@intentius/chant 0.101.0 → 0.104.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/checks.d.ts.map +1 -1
- package/dist/attrref.d.ts.map +1 -1
- package/dist/audit/core.d.ts +2 -0
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/nginx.d.ts.map +1 -1
- package/dist/audit/prior-art.d.ts +48 -0
- package/dist/audit/prior-art.d.ts.map +1 -1
- package/dist/behaviour-kinds.d.ts.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/change-set.d.ts +232 -0
- package/dist/change-set.d.ts.map +1 -0
- package/dist/cli/commands/audit.d.ts +7 -0
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/carve-emit.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +16 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts +8 -0
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +9 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
- package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/change-set.d.ts +11 -0
- package/dist/cli/handlers/change-set.d.ts.map +1 -0
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.d.ts +33 -0
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +16 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/pr.d.ts +31 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -0
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/lsp/server.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/tools/build.d.ts.map +1 -1
- package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
- package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
- package/dist/cli/mcp/tools/import.d.ts.map +1 -1
- package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
- package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
- package/dist/cli/mcp/tools/search.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +4 -3
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +74 -3
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/naming.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.d.ts +67 -3
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/components/auto-release.d.ts +16 -0
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability.d.ts +53 -0
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/changed-files.d.ts +31 -0
- package/dist/components/changed-files.d.ts.map +1 -0
- package/dist/components/cli-support.d.ts +9 -1
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +24 -0
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/deploy-units.d.ts.map +1 -1
- package/dist/components/driver.d.ts +13 -0
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out-output.d.ts +6 -0
- package/dist/components/fan-out-output.d.ts.map +1 -1
- package/dist/components/fan-out-record.d.ts +41 -0
- package/dist/components/fan-out-record.d.ts.map +1 -0
- package/dist/components/fan-out-run.d.ts +65 -0
- package/dist/components/fan-out-run.d.ts.map +1 -1
- package/dist/components/fan-out-support.d.ts +2 -0
- package/dist/components/fan-out-support.d.ts.map +1 -1
- package/dist/components/fan-out.d.ts +6 -0
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/gated-wave-pipeline.d.ts +50 -0
- package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/layers.d.ts +25 -0
- package/dist/components/layers.d.ts.map +1 -0
- package/dist/components/pr-pipeline.d.ts +61 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -0
- package/dist/components/pr-run.d.ts +119 -0
- package/dist/components/pr-run.d.ts.map +1 -0
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/verbs/process-runner.d.ts.map +1 -1
- package/dist/components/verbs/r2-sync.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/shell.d.ts.map +1 -1
- package/dist/components/verbs/sign.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts.map +1 -1
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
- package/dist/components/verbs/wrangler.d.ts.map +1 -1
- package/dist/components/wave-plan.d.ts +49 -0
- package/dist/components/wave-plan.d.ts.map +1 -0
- package/dist/composite.d.ts.map +1 -1
- package/dist/config.d.ts +19 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/declarable.d.ts +16 -0
- package/dist/declarable.d.ts.map +1 -1
- package/dist/discovery/cache.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +15 -5
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +16 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
- package/dist/discovery/specifier-resolve.d.ts +37 -0
- package/dist/discovery/specifier-resolve.d.ts.map +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/fold/fold.d.ts +3 -1
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/gated-waves.d.ts +147 -0
- package/dist/gated-waves.d.ts.map +1 -0
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-layout.d.ts.map +1 -1
- package/dist/import/base-parser.d.ts.map +1 -1
- package/dist/import/embedded.d.ts +7 -0
- package/dist/import/embedded.d.ts.map +1 -1
- package/dist/import/parser-options.d.ts +14 -0
- package/dist/import/parser-options.d.ts.map +1 -0
- package/dist/import/parser.d.ts +17 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts.map +1 -1
- package/dist/lexicon-output.d.ts.map +1 -1
- package/dist/lexicon-schema.d.ts +3 -3
- package/dist/lexicon.d.ts +103 -3
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/assert-live.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +22 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +46 -1
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/member-ledger.d.ts.map +1 -1
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/scenario.d.ts.map +1 -1
- package/dist/lifecycle/status.d.ts.map +1 -1
- package/dist/lifecycle/work-lease.d.ts +61 -2
- package/dist/lifecycle/work-lease.d.ts.map +1 -1
- package/dist/lint/config.d.ts +8 -8
- package/dist/lint/engine.d.ts +6 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +18 -0
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +137 -11
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/apply.d.ts +79 -9
- package/dist/op/activities/apply.d.ts.map +1 -1
- package/dist/op/activities/change-set.d.ts +62 -0
- package/dist/op/activities/change-set.d.ts.map +1 -0
- package/dist/op/activities/decide.d.ts +2 -0
- package/dist/op/activities/decide.d.ts.map +1 -1
- package/dist/op/activities/factory.d.ts +137 -0
- package/dist/op/activities/factory.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +5 -1
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +1 -1
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts.map +1 -1
- package/dist/op/activity-profiles.d.ts.map +1 -1
- package/dist/op/builders.d.ts +11 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +12 -5
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
- package/dist/op/decide-backend.d.ts +5 -1
- package/dist/op/decide-backend.d.ts.map +1 -1
- package/dist/op/decide-read-inputs.d.ts +4 -2
- package/dist/op/decide-read-inputs.d.ts.map +1 -1
- package/dist/op/emulator-lifecycle.d.ts +21 -2
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/factory.d.ts +83 -0
- package/dist/op/factory.d.ts.map +1 -0
- package/dist/op/gate-approval.d.ts +5 -1
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-wait.d.ts.map +1 -1
- package/dist/op/gate.d.ts +19 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/index.d.ts +6 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +6 -0
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +2 -0
- package/dist/op/op-ir.d.ts.map +1 -1
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/run-context.d.ts +39 -0
- package/dist/op/run-context.d.ts.map +1 -0
- package/dist/op/run-live.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/source-archive.d.ts.map +1 -1
- package/dist/op/steward-beside.d.ts.map +1 -1
- package/dist/op/steward-points.d.ts.map +1 -1
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/types.d.ts +16 -3
- package/dist/op/types.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts +24 -4
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/plan-summary.d.ts +207 -0
- package/dist/plan-summary.d.ts.map +1 -0
- package/dist/pr-forge.d.ts +105 -0
- package/dist/pr-forge.d.ts.map +1 -0
- package/dist/pr-loop.d.ts +178 -0
- package/dist/pr-loop.d.ts.map +1 -0
- package/dist/project-root.d.ts.map +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/pseudo-parameter.d.ts.map +1 -1
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/secret-materialization.d.ts.map +1 -1
- package/dist/telemetry-attribution.d.ts +31 -0
- package/dist/telemetry-attribution.d.ts.map +1 -1
- package/dist/terraform/emit-source.d.ts.map +1 -1
- package/dist/terraform/hcl2json.d.ts +45 -0
- package/dist/terraform/hcl2json.d.ts.map +1 -0
- package/dist/terraform/parse.d.ts +4 -40
- package/dist/terraform/parse.d.ts.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
- package/dist/workspace/agent-cli.d.ts +5 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -1
- package/dist/workspace/box-cli.d.ts +12 -0
- package/dist/workspace/box-cli.d.ts.map +1 -0
- package/dist/workspace/box-factory.d.ts +97 -0
- package/dist/workspace/box-factory.d.ts.map +1 -0
- package/dist/workspace/box-listing.d.ts +85 -0
- package/dist/workspace/box-listing.d.ts.map +1 -0
- package/dist/workspace/box-publish.d.ts +147 -0
- package/dist/workspace/box-publish.d.ts.map +1 -0
- package/dist/workspace/broker-protocol.d.ts +190 -0
- package/dist/workspace/broker-protocol.d.ts.map +1 -0
- package/dist/workspace/changes.d.ts.map +1 -1
- package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
- package/dist/workspace/checks/boxes.d.ts.map +1 -1
- package/dist/workspace/checks.d.ts +5 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +10 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/composites.d.ts +2 -2
- package/dist/workspace/composites.d.ts.map +1 -1
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
- package/dist/workspace/conformance/broker.d.ts +202 -0
- package/dist/workspace/conformance/broker.d.ts.map +1 -0
- package/dist/workspace/conformance/index.d.ts +68 -6
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +19 -3
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +462 -0
- package/dist/workspace/conformance/writer.d.ts.map +1 -0
- package/dist/workspace/decide.d.ts +126 -12
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/decision-points.schema.json +11 -4
- package/dist/workspace/declaration.d.ts +156 -4
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +383 -5
- package/dist/workspace/environments.d.ts +36 -10
- package/dist/workspace/environments.d.ts.map +1 -1
- package/dist/workspace/factory-rules.d.ts +180 -0
- package/dist/workspace/factory-rules.d.ts.map +1 -0
- package/dist/workspace/generated-files.d.ts.map +1 -1
- package/dist/workspace/graph-cache.d.ts.map +1 -1
- package/dist/workspace/graph-cli.d.ts +2 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/identity.d.ts +111 -0
- package/dist/workspace/identity.d.ts.map +1 -0
- package/dist/workspace/init.d.ts +21 -0
- package/dist/workspace/init.d.ts.map +1 -1
- package/dist/workspace/intent-cli.d.ts +7 -4
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +36 -2
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +249 -8
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/json-edit.d.ts +24 -0
- package/dist/workspace/json-edit.d.ts.map +1 -0
- package/dist/workspace/jsonc.d.ts +11 -0
- package/dist/workspace/jsonc.d.ts.map +1 -1
- package/dist/workspace/kinds.d.ts +66 -4
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/lexicon-symbols.d.ts +29 -0
- package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
- package/dist/workspace/lineage-hash-index.d.ts.map +1 -1
- package/dist/workspace/lineage-lock.d.ts +2 -2
- package/dist/workspace/lineage-lock.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.d.ts +31 -2
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/point-answer.schema.json +42 -2
- package/dist/workspace/points-cli.d.ts +10 -3
- package/dist/workspace/points-cli.d.ts.map +1 -1
- package/dist/workspace/points.d.ts +66 -5
- package/dist/workspace/points.d.ts.map +1 -1
- package/dist/workspace/principal-classes.d.ts +114 -0
- package/dist/workspace/principal-classes.d.ts.map +1 -0
- package/dist/workspace/reason-codes.d.ts +53 -4
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/record-assets.d.ts.map +1 -1
- package/dist/workspace/record-sessions.d.ts +5 -7
- package/dist/workspace/record-sessions.d.ts.map +1 -1
- package/dist/workspace/records-checkout.d.ts +54 -0
- package/dist/workspace/records-checkout.d.ts.map +1 -0
- package/dist/workspace/records-cli.d.ts +34 -1
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +7 -3
- package/dist/workspace/records-close.d.ts.map +1 -1
- package/dist/workspace/records-since.d.ts.map +1 -1
- package/dist/workspace/records-write.d.ts +68 -7
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +43 -9
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/runs-cli.d.ts +296 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -0
- package/dist/workspace/runs.d.ts +544 -0
- package/dist/workspace/runs.d.ts.map +1 -0
- package/dist/workspace/session-kinds.d.ts +1 -1
- package/dist/workspace/session-kinds.d.ts.map +1 -1
- package/dist/workspace/source-block.d.ts +1 -1
- package/dist/workspace/source-block.d.ts.map +1 -1
- package/dist/workspace/squash.d.ts +80 -0
- package/dist/workspace/squash.d.ts.map +1 -0
- package/dist/workspace/status-gates.d.ts +17 -3
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +64 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +63 -0
- package/dist/workspace/symbols.d.ts.map +1 -0
- package/dist/workspace/trailer-joins.d.ts +46 -0
- package/dist/workspace/trailer-joins.d.ts.map +1 -0
- package/dist/workspace/trailers.d.ts +89 -0
- package/dist/workspace/trailers.d.ts.map +1 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -1
- package/dist/workspace/trust/rotation.d.ts.map +1 -1
- package/dist/workspace/trust/run-commits.d.ts +46 -0
- package/dist/workspace/trust/run-commits.d.ts.map +1 -0
- package/dist/workspace/trust/run-statement.d.ts +128 -0
- package/dist/workspace/trust/run-statement.d.ts.map +1 -0
- package/dist/workspace/trust/seal.d.ts +38 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/test-repo.d.ts.map +1 -1
- package/dist/workspace/trust/verify-cli.d.ts +1 -1
- package/dist/workspace/trust/verify.d.ts +16 -2
- package/dist/workspace/trust/verify.d.ts.map +1 -1
- package/dist/workspace/wip-cli.d.ts +21 -0
- package/dist/workspace/wip-cli.d.ts.map +1 -0
- package/dist/workspace/wip.d.ts +268 -0
- package/dist/workspace/wip.d.ts.map +1 -0
- package/dist/workspace/work-cli.d.ts +39 -3
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-evidence.d.ts +1 -1
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work-size.d.ts +55 -0
- package/dist/workspace/work-size.d.ts.map +1 -0
- package/dist/workspace/work.d.ts +26 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/dist/workspace/workspace-kinds.schema.json +122 -0
- package/dist/workspace/workspace-principals.schema.json +60 -0
- package/dist/workspace/write-lock-cli.d.ts +60 -0
- package/dist/workspace/write-lock-cli.d.ts.map +1 -0
- package/dist/workspace/write-lock.d.ts +152 -0
- package/dist/workspace/write-lock.d.ts.map +1 -0
- package/dist/workspace/write-scope.d.ts +83 -19
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/yaml.d.ts +21 -39
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +7 -2
- package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
- package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
- package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
- package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
- package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
- package/src/__fixtures__/change-set/warden.plan.json +44 -0
- package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
- package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
- package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
- package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
- package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
- package/src/audit/core.test.ts +15 -0
- package/src/audit/core.ts +8 -2
- package/src/audit/discover.test.ts +11 -0
- package/src/audit/discover.ts +7 -2
- package/src/audit/prior-art.ts +15 -0
- package/src/change-set-bundle.test.ts +57 -0
- package/src/change-set.test.ts +215 -0
- package/src/change-set.ts +445 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
- package/src/cli/commands/audit-opt-in.test.ts +54 -0
- package/src/cli/commands/audit.ts +29 -2
- package/src/cli/commands/build.test.ts +19 -0
- package/src/cli/commands/build.ts +3 -2
- package/src/cli/commands/carve-emit-state.test.ts +4 -0
- package/src/cli/commands/carve-emit.ts +5 -19
- package/src/cli/commands/check-lexicon.test.ts +62 -1
- package/src/cli/commands/check-lexicon.ts +36 -6
- package/src/cli/commands/import-live.test.ts +18 -0
- package/src/cli/commands/import-parser-options.test.ts +133 -0
- package/src/cli/commands/import.ts +21 -3
- package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
- package/src/cli/commands/init.test.ts +8 -1
- package/src/cli/commands/init.ts +23 -8
- package/src/cli/commands/lint.test.ts +37 -0
- package/src/cli/commands/onboard.test.ts +53 -3
- package/src/cli/commands/onboard.ts +52 -4
- package/src/cli/commands/pinned-upgrade.ts +73 -33
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
- package/src/cli/handlers/build.ts +13 -1
- package/src/cli/handlers/change-set.test.ts +56 -0
- package/src/cli/handlers/change-set.ts +44 -0
- package/src/cli/handlers/components.ts +2 -2
- package/src/cli/handlers/dev.ts +8 -6
- package/src/cli/handlers/fan-out.test.ts +221 -2
- package/src/cli/handlers/fan-out.ts +165 -75
- package/src/cli/handlers/graph.ts +3 -0
- package/src/cli/handlers/lifecycle.test.ts +67 -0
- package/src/cli/handlers/lifecycle.ts +6 -5
- package/src/cli/handlers/misc.ts +2 -0
- package/src/cli/handlers/operator.test.ts +21 -0
- package/src/cli/handlers/operator.ts +121 -6
- package/src/cli/handlers/pr.ts +373 -0
- package/src/cli/handlers/run.test.ts +111 -0
- package/src/cli/handlers/run.ts +86 -24
- package/src/cli/handlers/scenario.ts +2 -2
- package/src/cli/main.test.ts +21 -0
- package/src/cli/main.ts +246 -30
- package/src/cli/mcp/never-over-mcp.test.ts +101 -0
- package/src/cli/mcp/op-tools.ts +24 -2
- package/src/cli/mcp/workspace-tools.test.ts +5 -2
- package/src/cli/mcp/workspace-tools.ts +62 -7
- package/src/cli/registry.ts +74 -3
- package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
- package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
- package/src/codegen/pinned-upgrade.test.ts +104 -0
- package/src/codegen/pinned-upgrade.ts +250 -56
- package/src/codegen/testdata/postgres-tags.json +242 -0
- package/src/components/auto-release.ts +1 -1
- package/src/components/capability.ts +55 -0
- package/src/components/changed-files.ts +66 -0
- package/src/components/cli-support.ts +28 -5
- package/src/components/component.schema.json +17 -0
- package/src/components/component.ts +25 -0
- package/src/components/deploy-units.ts +3 -0
- package/src/components/driver.test.ts +52 -0
- package/src/components/driver.ts +31 -13
- package/src/components/fan-out-output.ts +42 -1
- package/src/components/fan-out-record.ts +69 -0
- package/src/components/fan-out-run.test.ts +17 -0
- package/src/components/fan-out-run.ts +304 -1
- package/src/components/fan-out-support.ts +3 -0
- package/src/components/fan-out-waves.test.ts +375 -0
- package/src/components/fan-out.ts +18 -17
- package/src/components/gated-wave-pipeline.ts +82 -0
- package/src/components/index.ts +1 -0
- package/src/components/layers.ts +30 -0
- package/src/components/pr-pipeline.ts +91 -0
- package/src/components/pr-run.test.ts +205 -0
- package/src/components/pr-run.ts +280 -0
- package/src/components/promote.ts +5 -0
- package/src/components/verbs/shell.test.ts +11 -0
- package/src/components/verbs/shell.ts +7 -3
- package/src/components/wave-plan.ts +124 -0
- package/src/config.test.ts +21 -0
- package/src/config.ts +15 -0
- package/src/declarable.test.ts +21 -0
- package/src/declarable.ts +19 -0
- package/src/discovery/fold-composite.test.ts +41 -5
- package/src/discovery/fold-import.test.ts +129 -0
- package/src/discovery/fold-import.ts +643 -131
- package/src/discovery/fold-package-composite.test.ts +264 -0
- package/src/discovery/fold-specifiers.test.ts +191 -0
- package/src/discovery/param-deps.test.ts +66 -1
- package/src/discovery/param-deps.ts +45 -0
- package/src/discovery/sandbox/bundle.ts +1 -1
- package/src/discovery/specifier-resolve.ts +344 -0
- package/src/fold/fold.test.ts +39 -1
- package/src/fold/fold.ts +83 -9
- package/src/fold-provenance.test.ts +140 -0
- package/src/gated-waves-bundle.test.ts +62 -0
- package/src/gated-waves.test.ts +118 -0
- package/src/gated-waves.ts +240 -0
- package/src/graph-ir.test.ts +83 -0
- package/src/graph-ir.ts +29 -0
- package/src/import/embedded.test.ts +20 -0
- package/src/import/embedded.ts +13 -0
- package/src/import/parser-options.ts +46 -0
- package/src/import/parser.ts +20 -0
- package/src/index.ts +1 -0
- package/src/lexicon.ts +106 -3
- package/src/lifecycle/gate-ledger.ts +23 -0
- package/src/lifecycle/git.ts +102 -16
- package/src/lifecycle/observe.test.ts +18 -0
- package/src/lifecycle/observe.ts +6 -4
- package/src/lifecycle/snapshot.ts +2 -2
- package/src/lifecycle/work-lease.test.ts +1 -1
- package/src/lifecycle/work-lease.ts +93 -2
- package/src/lint/engine.test.ts +55 -0
- package/src/lint/engine.ts +30 -4
- package/src/lint/output-docs.test.ts +59 -56
- package/src/lint/post-synth.test.ts +19 -0
- package/src/lint/post-synth.ts +19 -1
- package/src/meta/declared-imports.test.ts +1 -1
- package/src/op/activities/activity-contracts.ts +84 -0
- package/src/op/activities/apply.test.ts +189 -5
- package/src/op/activities/apply.ts +230 -8
- package/src/op/activities/change-set.ts +114 -0
- package/src/op/activities/decide.ts +3 -0
- package/src/op/activities/factory.ts +675 -0
- package/src/op/activities/index.ts +9 -0
- package/src/op/activities/lexicon-upgrade.test.ts +160 -6
- package/src/op/activities/lexicon-upgrade.ts +154 -51
- package/src/op/activity-contract.test.ts +21 -1
- package/src/op/activity-contract.ts +19 -9
- package/src/op/builders.ts +23 -0
- package/src/op/composites/apply-op.ts +12 -5
- package/src/op/composites/composites.test.ts +30 -3
- package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
- package/src/op/composites/lexicon-upgrade-op.ts +29 -8
- package/src/op/decide-backend.ts +5 -1
- package/src/op/decide-read-inputs.ts +33 -5
- package/src/op/emulator-lifecycle.test.ts +23 -0
- package/src/op/emulator-lifecycle.ts +52 -14
- package/src/op/factory.e2e.test.ts +232 -0
- package/src/op/factory.ts +118 -0
- package/src/op/gate-approval.test.ts +74 -0
- package/src/op/gate-approval.ts +5 -1
- package/src/op/gate.ts +31 -5
- package/src/op/index.ts +11 -1
- package/src/op/local-executor.test.ts +15 -0
- package/src/op/local-executor.ts +40 -12
- package/src/op/local-output.ts +1 -1
- package/src/op/op-ir.test.ts +9 -0
- package/src/op/op-ir.ts +4 -0
- package/src/op/op-verb-class.ts +3 -0
- package/src/op/operator.ts +4 -0
- package/src/op/run-context.test.ts +141 -0
- package/src/op/run-context.ts +51 -0
- package/src/op/runtimes/local.test.ts +14 -0
- package/src/op/runtimes/local.ts +2 -0
- package/src/op/steward-beside.ts +2 -0
- package/src/op/types.ts +16 -3
- package/src/op/work-lease-run.test.ts +47 -0
- package/src/op/work-lease-run.ts +76 -11
- package/src/plan-summary.test.ts +263 -0
- package/src/plan-summary.ts +845 -0
- package/src/pr-forge.test.ts +237 -0
- package/src/pr-forge.ts +332 -0
- package/src/pr-loop-bundle.test.ts +46 -0
- package/src/pr-loop.test.ts +171 -0
- package/src/pr-loop.ts +324 -0
- package/src/provenance.ts +35 -0
- package/src/telemetry-attribution.test.ts +23 -1
- package/src/telemetry-attribution.ts +51 -0
- package/src/terraform/hcl2json.test.ts +21 -0
- package/src/terraform/hcl2json.ts +81 -0
- package/src/terraform/parse.ts +11 -74
- package/src/workspace/agent-cli.ts +7 -3
- package/src/workspace/agent.schema.json +22 -0
- package/src/workspace/app-kind.test.ts +196 -0
- package/src/workspace/box-cli.ts +113 -0
- package/src/workspace/box-factory.test.ts +323 -0
- package/src/workspace/box-factory.ts +136 -0
- package/src/workspace/box-listing-write.schema.json +204 -0
- package/src/workspace/box-listing.test.ts +234 -0
- package/src/workspace/box-listing.ts +324 -0
- package/src/workspace/box-publish.schema.json +498 -0
- package/src/workspace/box-publish.test.ts +204 -0
- package/src/workspace/box-publish.ts +420 -0
- package/src/workspace/box-ship.test.ts +96 -0
- package/src/workspace/broker-protocol.schema.json +186 -0
- package/src/workspace/broker-protocol.test.ts +122 -0
- package/src/workspace/broker-protocol.ts +317 -0
- package/src/workspace/builder-tiers.test.ts +146 -0
- package/src/workspace/change-set.schema.json +460 -0
- package/src/workspace/changes.schema.json +12 -20
- package/src/workspace/changes.ts +4 -1
- package/src/workspace/chant-migrations.e2e.test.ts +17 -5
- package/src/workspace/checks/boxes.test.ts +5 -0
- package/src/workspace/checks.ts +39 -8
- package/src/workspace/component-environments.test.ts +105 -0
- package/src/workspace/compose-graph.ts +7 -0
- package/src/workspace/composites.schema.json +23 -4
- package/src/workspace/composites.test.ts +8 -8
- package/src/workspace/composites.ts +13 -2
- package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
- package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
- package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
- package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
- package/src/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
- package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
- package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
- package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
- package/src/workspace/conformance/broker.test.ts +122 -0
- package/src/workspace/conformance/broker.ts +792 -0
- package/src/workspace/conformance/conformance.e2e.test.ts +36 -3
- package/src/workspace/conformance/index.mjs +51 -3
- package/src/workspace/conformance/index.ts +107 -15
- package/src/workspace/conformance/vitest.ts +76 -2
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +177 -0
- package/src/workspace/conformance/writer.test.ts +186 -0
- package/src/workspace/conformance/writer.ts +1191 -0
- package/src/workspace/decide.test.ts +208 -4
- package/src/workspace/decide.ts +433 -73
- package/src/workspace/decision-points.schema.json +11 -4
- package/src/workspace/declaration.schema.json +383 -5
- package/src/workspace/declaration.ts +315 -10
- package/src/workspace/environments.ts +66 -14
- package/src/workspace/factory-rules.test.ts +62 -0
- package/src/workspace/factory-rules.ts +218 -0
- package/src/workspace/graph-cli.ts +6 -3
- package/src/workspace/graph.schema.json +314 -0
- package/src/workspace/identity.test.ts +219 -0
- package/src/workspace/identity.ts +186 -0
- package/src/workspace/init.ts +82 -2
- package/src/workspace/intent-cli.ts +84 -13
- package/src/workspace/intent-patch-id.test.ts +162 -0
- package/src/workspace/intent-record.schema.json +336 -1
- package/src/workspace/intent-record.ts +96 -16
- package/src/workspace/intent-reviews.test.ts +76 -0
- package/src/workspace/intent-squash.test.ts +213 -0
- package/src/workspace/intent-why.test.ts +274 -0
- package/src/workspace/intent.schema.json +950 -9
- package/src/workspace/intent.test.ts +11 -2
- package/src/workspace/intent.ts +722 -65
- package/src/workspace/json-edit.test.ts +121 -0
- package/src/workspace/json-edit.ts +142 -0
- package/src/workspace/jsonc.ts +20 -0
- package/src/workspace/kinds.ts +201 -39
- package/src/workspace/lexicon-symbols.test.ts +148 -0
- package/src/workspace/lexicon-symbols.ts +125 -0
- package/src/workspace/lineage-upgrade.test.ts +63 -0
- package/src/workspace/lineage-upgrade.ts +146 -5
- package/src/workspace/plan-summary.schema.json +155 -0
- package/src/workspace/point-answer.schema.json +42 -2
- package/src/workspace/points-cli.ts +42 -16
- package/src/workspace/points-write.schema.json +163 -4
- package/src/workspace/points.schema.json +157 -2
- package/src/workspace/points.test.ts +13 -1
- package/src/workspace/points.ts +118 -12
- package/src/workspace/pr-report.schema.json +95 -0
- package/src/workspace/principal-classes.test.ts +175 -0
- package/src/workspace/principal-classes.ts +307 -0
- package/src/workspace/profiles.test.ts +159 -0
- package/src/workspace/read-contract.test.ts +2 -2
- package/src/workspace/reason-codes.test.ts +23 -3
- package/src/workspace/reason-codes.ts +61 -4
- package/src/workspace/record-sessions.ts +9 -8
- package/src/workspace/records-amend.schema.json +80 -0
- package/src/workspace/records-checkout.ts +106 -0
- package/src/workspace/records-cli.ts +123 -17
- package/src/workspace/records-close.schema.json +79 -0
- package/src/workspace/records-close.ts +31 -7
- package/src/workspace/records-concurrent.e2e.test.ts +135 -0
- package/src/workspace/records-concurrent.test.ts +145 -0
- package/src/workspace/records-formats.test.ts +46 -10
- package/src/workspace/records-new.schema.json +9 -0
- package/src/workspace/records-review.schema.json +80 -0
- package/src/workspace/records-sessions-write.test.ts +69 -0
- package/src/workspace/records-sessions.test.ts +22 -0
- package/src/workspace/records-uncommitted.test.ts +171 -0
- package/src/workspace/records-write.ts +219 -30
- package/src/workspace/records.schema.json +88 -1
- package/src/workspace/records.ts +76 -8
- package/src/workspace/reference-kinds/app/package.json +10 -0
- package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
- package/src/workspace/run-statement.schema.json +622 -0
- package/src/workspace/runs-cli.ts +710 -0
- package/src/workspace/runs-statement.test.ts +239 -0
- package/src/workspace/runs-write.schema.json +994 -0
- package/src/workspace/runs.schema.json +1257 -0
- package/src/workspace/runs.test.ts +281 -0
- package/src/workspace/runs.ts +970 -0
- package/src/workspace/session-kinds.ts +3 -3
- package/src/workspace/squash.ts +198 -0
- package/src/workspace/status-contract.test.ts +10 -2
- package/src/workspace/status-gates.ts +25 -9
- package/src/workspace/status.schema.json +252 -4
- package/src/workspace/status.ts +110 -1
- package/src/workspace/symbols.ts +191 -0
- package/src/workspace/trailer-joins.test.ts +171 -0
- package/src/workspace/trailer-joins.ts +82 -0
- package/src/workspace/trailers.ts +148 -0
- package/src/workspace/trust/run-commits.ts +115 -0
- package/src/workspace/trust/run-statement.ts +226 -0
- package/src/workspace/trust/seal.ts +58 -1
- package/src/workspace/trust/verify-cli.ts +6 -5
- package/src/workspace/trust/verify.ts +39 -6
- package/src/workspace/wip-cli.ts +97 -0
- package/src/workspace/wip-write.schema.json +504 -0
- package/src/workspace/wip.schema.json +334 -0
- package/src/workspace/wip.test.ts +294 -0
- package/src/workspace/wip.ts +753 -0
- package/src/workspace/work-cli.e2e.test.ts +28 -1
- package/src/workspace/work-cli.ts +136 -8
- package/src/workspace/work-evidence.schema.json +5 -0
- package/src/workspace/work-history.schema.json +73 -1
- package/src/workspace/work-history.test.ts +48 -5
- package/src/workspace/work-kind-fields.test.ts +154 -0
- package/src/workspace/work-lease.schema.json +14 -1
- package/src/workspace/work-size.test.ts +77 -0
- package/src/workspace/work-size.ts +93 -0
- package/src/workspace/work.ts +82 -0
- package/src/workspace/workspace-kinds.schema.json +122 -0
- package/src/workspace/workspace-principals.schema.json +60 -0
- package/src/workspace/write-lock-cli.ts +131 -0
- package/src/workspace/write-lock.schema.json +172 -0
- package/src/workspace/write-lock.test.ts +189 -0
- package/src/workspace/write-lock.ts +474 -0
- package/src/workspace/write-scope.test.ts +144 -3
- package/src/workspace/write-scope.ts +192 -45
- package/src/yaml.test.ts +111 -1
- package/src/yaml.ts +141 -549
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/chant/schemas/workspace/principals/v1/workspace-principals.schema.json",
|
|
4
|
+
"title": "workspace-principals.json",
|
|
5
|
+
"description": "Principal classes a plugin supplies (#2524 D5, #3080, ws-079). A package publishes this file as data at its ./workspace-principals subpath, beside ./workspace-kinds. chant reads it with the file system and never imports the package. A class is a name for the principals holding one role in the trust policy at base; the declaration's writeScope may then give it an entry.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "classes"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "An editor hint. chant ignores it."
|
|
12
|
+
},
|
|
13
|
+
"$comment": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "A note for people. chant ignores it."
|
|
16
|
+
},
|
|
17
|
+
"schema": {
|
|
18
|
+
"const": 1,
|
|
19
|
+
"description": "The principal classes format version."
|
|
20
|
+
},
|
|
21
|
+
"classes": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"minItems": 1,
|
|
24
|
+
"items": {
|
|
25
|
+
"$ref": "#/$defs/class"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"patternProperties": {
|
|
30
|
+
"^x-": true
|
|
31
|
+
},
|
|
32
|
+
"additionalProperties": false,
|
|
33
|
+
"$defs": {
|
|
34
|
+
"class": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"required": ["name", "description", "role"],
|
|
37
|
+
"properties": {
|
|
38
|
+
"name": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"pattern": "^(?!x-)[a-z][a-z0-9-]{0,39}$",
|
|
41
|
+
"description": "The class's name, as a key of the declaration's writeScope names it. human, agent, runner and service are the core classes and can't be supplied."
|
|
42
|
+
},
|
|
43
|
+
"description": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"minLength": 1,
|
|
46
|
+
"description": "One line saying who is in the class, for listings and error messages."
|
|
47
|
+
},
|
|
48
|
+
"role": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
51
|
+
"description": "The role whose grant in the trust policy at base (.chant/trust.json roles) puts a principal in this class. The agent, runner and service roles belong to the core classes and can't be named here. One role puts a principal in one class."
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"patternProperties": {
|
|
55
|
+
"^x-": true
|
|
56
|
+
},
|
|
57
|
+
"additionalProperties": false
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant workspace lock` (#3173, ws-089): the working tree's write lock
|
|
3
|
+
* (`write-lock.ts`), seen and held from outside chant.
|
|
4
|
+
*
|
|
5
|
+
* - `lock` prints who holds it now, or that nobody does.
|
|
6
|
+
* - `lock acquire --holder <name> [--ttl <duration>]` takes it for a batch of
|
|
7
|
+
* writes across several chant calls, waiting for it as a write does, and
|
|
8
|
+
* prints the token. Each chant write of the batch runs with
|
|
9
|
+
* `CHANT_WRITE_LOCK=<token>` and goes ahead without waiting; every other
|
|
10
|
+
* writer waits. The lock lasts until it is released or the ttl passes
|
|
11
|
+
* (default 60s, at most 10m), after which any writer may break it.
|
|
12
|
+
* - `lock release --token <token>` gives it back.
|
|
13
|
+
*
|
|
14
|
+
* Each prints one JSON document (`write-lock.schema.json`); a refusal exits 1.
|
|
15
|
+
* The token is printed only to the caller that took the lock: `lock` never
|
|
16
|
+
* prints it, so holding the lock can't be taken over by reading who holds it.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { CommandContext } from "../cli/registry";
|
|
20
|
+
import { parseDuration } from "../op/duration";
|
|
21
|
+
import { readerVersion } from "./declaration";
|
|
22
|
+
import {
|
|
23
|
+
acquireBatchLock,
|
|
24
|
+
DEFAULT_BATCH_TTL_MS,
|
|
25
|
+
MAX_BATCH_TTL_MS,
|
|
26
|
+
releaseLock,
|
|
27
|
+
writeLockHolder,
|
|
28
|
+
writeLockPath,
|
|
29
|
+
WriteLockError,
|
|
30
|
+
type WriteLockHolder,
|
|
31
|
+
} from "./write-lock";
|
|
32
|
+
import { AGENT_ENV } from "./write-scope";
|
|
33
|
+
|
|
34
|
+
export const WRITE_LOCK_CONTRACT_VERSION = 1;
|
|
35
|
+
export const WRITE_LOCK_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/write-lock/v1/write-lock.schema.json";
|
|
36
|
+
|
|
37
|
+
/** Why a lock command did nothing. Closed. */
|
|
38
|
+
export const WRITE_LOCK_ERROR_CODES = ["write-usage-invalid", "write-lock-timeout", "write-lock-not-held"] as const;
|
|
39
|
+
export type WriteLockErrorCode = (typeof WRITE_LOCK_ERROR_CODES)[number];
|
|
40
|
+
|
|
41
|
+
/** A holder as the documents show it: everything but the token. */
|
|
42
|
+
export type HolderView = Omit<WriteLockHolder, "token">;
|
|
43
|
+
|
|
44
|
+
export type WriteLockDocument =
|
|
45
|
+
| {
|
|
46
|
+
$schema: string;
|
|
47
|
+
contract: number;
|
|
48
|
+
chant: string;
|
|
49
|
+
verb: "status" | "acquire" | "release";
|
|
50
|
+
/** The lock directory. */
|
|
51
|
+
path: string;
|
|
52
|
+
/** Who holds the lock after the command: the batch for acquire, null after release. */
|
|
53
|
+
holder: HolderView | null;
|
|
54
|
+
/** acquire only: the token each write of the batch runs with, as CHANT_WRITE_LOCK. */
|
|
55
|
+
token?: string;
|
|
56
|
+
}
|
|
57
|
+
| { $schema: string; contract: number; chant: string; verb: "status" | "acquire" | "release"; error: { code: WriteLockErrorCode; message: string }; holder: HolderView | null };
|
|
58
|
+
|
|
59
|
+
const USAGE = "chant workspace lock [acquire --holder <name> [--ttl <duration>] | release --token <token>] [--json]";
|
|
60
|
+
|
|
61
|
+
function view(h: WriteLockHolder | null): HolderView | null {
|
|
62
|
+
if (h === null) return null;
|
|
63
|
+
const { token: _token, ...rest } = h;
|
|
64
|
+
return rest;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Run one lock command and build its document. */
|
|
68
|
+
export async function workspaceLock(req: { cwd: string; verb: string | undefined; holder?: string; ttl?: string; token?: string; agent?: string }): Promise<WriteLockDocument> {
|
|
69
|
+
const verb = req.verb === undefined || req.verb === "status" ? "status" : req.verb === "acquire" || req.verb === "release" ? req.verb : null;
|
|
70
|
+
const head = { $schema: WRITE_LOCK_SCHEMA_ID, contract: WRITE_LOCK_CONTRACT_VERSION, chant: readerVersion() };
|
|
71
|
+
const fail = (v: "status" | "acquire" | "release", code: WriteLockErrorCode, message: string, holder: WriteLockHolder | null = null): WriteLockDocument => ({
|
|
72
|
+
...head,
|
|
73
|
+
verb: v,
|
|
74
|
+
error: { code, message: code === "write-usage-invalid" ? `${message}\n${USAGE}` : message },
|
|
75
|
+
holder: view(holder),
|
|
76
|
+
});
|
|
77
|
+
if (verb === null) return fail("status", "write-usage-invalid", `lock takes acquire or release, or nothing to say who holds it, not ${req.verb}`);
|
|
78
|
+
if (verb === "status") {
|
|
79
|
+
if (req.holder !== undefined || req.ttl !== undefined || req.token !== undefined) return fail(verb, "write-usage-invalid", "lock with no verb only says who holds the lock, and takes no --holder, --ttl or --token");
|
|
80
|
+
const { path, holder } = writeLockHolder(req.cwd);
|
|
81
|
+
return { ...head, verb, path, holder: view(holder) };
|
|
82
|
+
}
|
|
83
|
+
if (verb === "acquire") {
|
|
84
|
+
if (!req.holder) return fail(verb, "write-usage-invalid", "lock acquire needs --holder <name>: who holds the lock, as the other writers waiting on it are told");
|
|
85
|
+
if (req.token !== undefined) return fail(verb, "write-usage-invalid", "lock acquire hands out a token, and takes none");
|
|
86
|
+
let ttlMs = DEFAULT_BATCH_TTL_MS;
|
|
87
|
+
if (req.ttl !== undefined) {
|
|
88
|
+
const ms = /^\d+$/.test(req.ttl) ? Number(req.ttl) * 1000 : parseDurationOrNull(req.ttl);
|
|
89
|
+
if (ms === null || ms <= 0 || ms > MAX_BATCH_TTL_MS) return fail(verb, "write-usage-invalid", `--ttl takes a duration up to ${MAX_BATCH_TTL_MS / 60_000}m, such as 90s or 5m, not ${JSON.stringify(req.ttl)}`);
|
|
90
|
+
ttlMs = ms;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const { path, holder } = await acquireBatchLock(req.cwd, { verb: "batch", by: req.holder, agent: req.agent ?? null }, ttlMs);
|
|
94
|
+
return { ...head, verb, path, holder: view(holder), token: holder.token };
|
|
95
|
+
} catch (err) {
|
|
96
|
+
if (err instanceof WriteLockError) return fail(verb, err.code, err.message, err.holder);
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (!req.token) return fail(verb, "write-usage-invalid", "lock release needs --token <token>, as lock acquire printed it");
|
|
101
|
+
if (req.holder !== undefined || req.ttl !== undefined) return fail(verb, "write-usage-invalid", "lock release takes only --token");
|
|
102
|
+
const path = writeLockPath(req.cwd);
|
|
103
|
+
if (!releaseLock(path, req.token)) {
|
|
104
|
+
const { holder } = writeLockHolder(req.cwd);
|
|
105
|
+
return fail(verb, "write-lock-not-held", `the token given does not hold the write lock (${holder ? "another writer holds it" : "nobody holds it"}): it was released already, or it expired`, holder);
|
|
106
|
+
}
|
|
107
|
+
return { ...head, verb, path, holder: null };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function parseDurationOrNull(raw: string): number | null {
|
|
111
|
+
try {
|
|
112
|
+
return parseDuration(raw);
|
|
113
|
+
} catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** `chant workspace lock [acquire|release]`. Prints one JSON document; exits 1 on a refusal. */
|
|
119
|
+
export async function runWorkspaceLock(ctx: CommandContext): Promise<number> {
|
|
120
|
+
const { args } = ctx;
|
|
121
|
+
const doc = await workspaceLock({
|
|
122
|
+
cwd: process.cwd(),
|
|
123
|
+
verb: args.extraPositional,
|
|
124
|
+
holder: args.holder,
|
|
125
|
+
ttl: args.ttl,
|
|
126
|
+
token: args.token,
|
|
127
|
+
agent: process.env[AGENT_ENV] || undefined,
|
|
128
|
+
});
|
|
129
|
+
console.log(JSON.stringify(doc, null, 2));
|
|
130
|
+
return "error" in doc ? 1 : 0;
|
|
131
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/chant/schemas/workspace/write-lock/v1/write-lock.schema.json",
|
|
4
|
+
"title": "chant workspace lock output",
|
|
5
|
+
"description": "What `chant workspace lock [acquire --holder <name> [--ttl <duration>] | release --token <token>]` prints (#3173, ws-089): who holds the working tree's write lock, the token of a batch that took it, or the reason the command did nothing. Every chant write to the working tree (records new, amend, review and close, points ask and answer, box listing set) holds this lock from its first read to its last write. A batch holds it across chant calls: each call runs with CHANT_WRITE_LOCK=<token> and goes ahead without waiting while the token holds it. Readers ignore fields they do not know; a field is only ever added within a version. The error codes are a closed list, each in the one closed list of `reason-codes.ts`.",
|
|
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
|
+
"verb",
|
|
23
|
+
"path",
|
|
24
|
+
"holder"
|
|
25
|
+
],
|
|
26
|
+
"properties": {
|
|
27
|
+
"$schema": {
|
|
28
|
+
"const": "https://intentius.io/chant/schemas/workspace/write-lock/v1/write-lock.schema.json"
|
|
29
|
+
},
|
|
30
|
+
"contract": {
|
|
31
|
+
"const": 1
|
|
32
|
+
},
|
|
33
|
+
"chant": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "The chant version that printed it."
|
|
36
|
+
},
|
|
37
|
+
"verb": {
|
|
38
|
+
"enum": [
|
|
39
|
+
"status",
|
|
40
|
+
"acquire",
|
|
41
|
+
"release"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"path": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "The lock directory: chant-write.lock in the working tree's git directory, or a directory under the system's temporary directory outside git."
|
|
47
|
+
},
|
|
48
|
+
"holder": {
|
|
49
|
+
"$ref": "#/$defs/holder"
|
|
50
|
+
},
|
|
51
|
+
"token": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"pattern": "^[0-9a-f]{32}$",
|
|
54
|
+
"description": "acquire only: the token each write of the batch runs with, as CHANT_WRITE_LOCK, and lock release takes. Never printed by status."
|
|
55
|
+
},
|
|
56
|
+
"error": false
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"failure": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"description": "Nothing was done. Exit code 1.",
|
|
62
|
+
"required": [
|
|
63
|
+
"$schema",
|
|
64
|
+
"contract",
|
|
65
|
+
"chant",
|
|
66
|
+
"verb",
|
|
67
|
+
"error",
|
|
68
|
+
"holder"
|
|
69
|
+
],
|
|
70
|
+
"properties": {
|
|
71
|
+
"$schema": {
|
|
72
|
+
"const": "https://intentius.io/chant/schemas/workspace/write-lock/v1/write-lock.schema.json"
|
|
73
|
+
},
|
|
74
|
+
"contract": {
|
|
75
|
+
"const": 1
|
|
76
|
+
},
|
|
77
|
+
"chant": {
|
|
78
|
+
"type": "string"
|
|
79
|
+
},
|
|
80
|
+
"verb": {
|
|
81
|
+
"enum": [
|
|
82
|
+
"status",
|
|
83
|
+
"acquire",
|
|
84
|
+
"release"
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
"error": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"required": [
|
|
90
|
+
"code",
|
|
91
|
+
"message"
|
|
92
|
+
],
|
|
93
|
+
"properties": {
|
|
94
|
+
"code": {
|
|
95
|
+
"enum": [
|
|
96
|
+
"write-usage-invalid",
|
|
97
|
+
"write-lock-timeout",
|
|
98
|
+
"write-lock-not-held"
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
"message": {
|
|
102
|
+
"type": "string"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"holder": {
|
|
107
|
+
"$ref": "#/$defs/holder"
|
|
108
|
+
},
|
|
109
|
+
"token": false
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"holder": {
|
|
113
|
+
"description": "Who holds the lock: everything owner.json in the lock directory says but the token.",
|
|
114
|
+
"oneOf": [
|
|
115
|
+
{
|
|
116
|
+
"type": "null"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"type": "object",
|
|
120
|
+
"required": [
|
|
121
|
+
"pid",
|
|
122
|
+
"host",
|
|
123
|
+
"verb",
|
|
124
|
+
"by",
|
|
125
|
+
"agent",
|
|
126
|
+
"acquiredAt",
|
|
127
|
+
"expiresAt"
|
|
128
|
+
],
|
|
129
|
+
"properties": {
|
|
130
|
+
"pid": {
|
|
131
|
+
"type": [
|
|
132
|
+
"integer",
|
|
133
|
+
"null"
|
|
134
|
+
],
|
|
135
|
+
"description": "The process holding it, or null for a batch held across chant calls."
|
|
136
|
+
},
|
|
137
|
+
"host": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"description": "The host the holder runs on."
|
|
140
|
+
},
|
|
141
|
+
"verb": {
|
|
142
|
+
"type": "string",
|
|
143
|
+
"description": "What holds it: a write command, such as records amend, or batch."
|
|
144
|
+
},
|
|
145
|
+
"by": {
|
|
146
|
+
"type": [
|
|
147
|
+
"string",
|
|
148
|
+
"null"
|
|
149
|
+
],
|
|
150
|
+
"description": "Who the write or batch names: --by, or lock acquire's --holder."
|
|
151
|
+
},
|
|
152
|
+
"agent": {
|
|
153
|
+
"type": [
|
|
154
|
+
"string",
|
|
155
|
+
"null"
|
|
156
|
+
],
|
|
157
|
+
"description": "The agent session (CHANT_AGENT), or null."
|
|
158
|
+
},
|
|
159
|
+
"acquiredAt": {
|
|
160
|
+
"type": "string",
|
|
161
|
+
"description": "When it was taken, as an ISO 8601 time."
|
|
162
|
+
},
|
|
163
|
+
"expiresAt": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"description": "When any writer may break it, as an ISO 8601 time."
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The working tree's write lock and write journal (#3173, ws-089): where the
|
|
3
|
+
* lock lives, that writes in one process and across a batch serialise, that a
|
|
4
|
+
* dead or expired holder is broken, that a waiter is refused naming the
|
|
5
|
+
* holder, and that the journal names a record's last writer only while the
|
|
6
|
+
* file holds what that write left.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { hostname, tmpdir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { afterAll, afterEach, describe, expect, test } from "vitest";
|
|
13
|
+
import { cleanScratch, contract, git, repo, scratchDir } from "./__fixtures__/contract-repo";
|
|
14
|
+
import writeLockSchema from "./write-lock.schema.json";
|
|
15
|
+
import { workspaceLock } from "./write-lock-cli";
|
|
16
|
+
import {
|
|
17
|
+
gitDirOf,
|
|
18
|
+
lastWriteReader,
|
|
19
|
+
noteWrites,
|
|
20
|
+
WRITE_LOCK_ENV,
|
|
21
|
+
WRITE_LOCK_WAIT_ENV,
|
|
22
|
+
withWriteLock,
|
|
23
|
+
withWriteLockSync,
|
|
24
|
+
WriteLockError,
|
|
25
|
+
writeLockHolder,
|
|
26
|
+
writeLockPath,
|
|
27
|
+
} from "./write-lock";
|
|
28
|
+
|
|
29
|
+
afterAll(cleanScratch);
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
delete process.env[WRITE_LOCK_ENV];
|
|
32
|
+
delete process.env[WRITE_LOCK_WAIT_ENV];
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
|
36
|
+
const lockDoc = contract(writeLockSchema);
|
|
37
|
+
|
|
38
|
+
/** Put a lock in place as another process would have left it. */
|
|
39
|
+
function plant(start: string, over: Record<string, unknown>): string {
|
|
40
|
+
const lock = writeLockPath(start);
|
|
41
|
+
mkdirSync(lock);
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
writeFileSync(
|
|
44
|
+
join(lock, "owner.json"),
|
|
45
|
+
JSON.stringify({ token: "f".repeat(32), pid: process.pid, host: hostname(), verb: "records amend", by: "alice", agent: null, acquiredAt: new Date(now).toISOString(), expiresAt: new Date(now + 60_000).toISOString(), ...over }),
|
|
46
|
+
);
|
|
47
|
+
return lock;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
describe("where the lock lives", () => {
|
|
51
|
+
test("in the working tree's git directory, the linked worktree's own for a worktree, and under tmp outside git", () => {
|
|
52
|
+
const root = repo({ "a.txt": "a\n" }, true);
|
|
53
|
+
expect(gitDirOf(root)).toBe(join(root, ".git"));
|
|
54
|
+
expect(writeLockPath(join(root))).toBe(join(root, ".git", "chant-write.lock"));
|
|
55
|
+
const wt = join(scratchDir(), "wt");
|
|
56
|
+
git(root, "worktree", "add", "-q", wt);
|
|
57
|
+
expect(writeLockPath(wt)).toBe(join(root, ".git", "worktrees", "wt", "chant-write.lock"));
|
|
58
|
+
const bare = scratchDir();
|
|
59
|
+
expect(writeLockPath(bare).startsWith(tmpdir())).toBe(true);
|
|
60
|
+
expect(writeLockPath(bare)).toMatch(/chant-write-[0-9a-f]{16}\.lock$/);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("withWriteLock", () => {
|
|
65
|
+
test("serialises two writes this process runs at once, and lets a write inside a write through", async () => {
|
|
66
|
+
const root = repo({});
|
|
67
|
+
const order: string[] = [];
|
|
68
|
+
const one = withWriteLock(root, { verb: "records amend", by: "alice" }, false, async () => {
|
|
69
|
+
order.push("one in");
|
|
70
|
+
expect(writeLockHolder(root).holder).toMatchObject({ verb: "records amend", by: "alice", pid: process.pid });
|
|
71
|
+
// Re-entrant: work evidence amends inside its own write.
|
|
72
|
+
await withWriteLock(root, { verb: "records amend" }, false, async () => void order.push("nested"));
|
|
73
|
+
await sleep(80);
|
|
74
|
+
order.push("one out");
|
|
75
|
+
});
|
|
76
|
+
await sleep(10);
|
|
77
|
+
const two = withWriteLock(root, { verb: "records amend", by: "bob" }, false, async () => void order.push("two"));
|
|
78
|
+
await Promise.all([one, two]);
|
|
79
|
+
expect(order).toEqual(["one in", "nested", "one out", "two"]);
|
|
80
|
+
expect(existsSync(writeLockPath(root))).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("a dry run takes no lock", async () => {
|
|
84
|
+
const root = repo({});
|
|
85
|
+
plant(root, {});
|
|
86
|
+
expect(await withWriteLock(root, { verb: "records amend" }, true, async () => "ran")).toBe("ran");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("a waiter is refused with write-lock-timeout naming the holder, and the lock is released after a failure", async () => {
|
|
90
|
+
const root = repo({});
|
|
91
|
+
plant(root, {});
|
|
92
|
+
process.env[WRITE_LOCK_WAIT_ENV] = "100";
|
|
93
|
+
const err = await withWriteLock(root, { verb: "records review" }, false, async () => "no").catch((e: unknown) => e);
|
|
94
|
+
expect(err).toBeInstanceOf(WriteLockError);
|
|
95
|
+
expect((err as WriteLockError).code).toBe("write-lock-timeout");
|
|
96
|
+
expect((err as WriteLockError).message).toMatch(/records amend \(alice\)/);
|
|
97
|
+
expect((err as WriteLockError).holder?.by).toBe("alice");
|
|
98
|
+
|
|
99
|
+
const other = repo({});
|
|
100
|
+
await expect(withWriteLock(other, { verb: "records new" }, false, async () => { throw new Error("boom"); })).rejects.toThrow("boom");
|
|
101
|
+
expect(existsSync(writeLockPath(other))).toBe(false);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("breaks a lock whose process has exited, or that has expired", async () => {
|
|
105
|
+
const dead = repo({});
|
|
106
|
+
plant(dead, { pid: 2 ** 22 + 12345 });
|
|
107
|
+
expect(await withWriteLock(dead, { verb: "records amend" }, false, async () => "took it")).toBe("took it");
|
|
108
|
+
const expired = repo({});
|
|
109
|
+
plant(expired, { pid: null, verb: "batch", expiresAt: new Date(Date.now() - 1000).toISOString() });
|
|
110
|
+
expect(await withWriteLock(expired, { verb: "records amend" }, false, async () => "took it")).toBe("took it");
|
|
111
|
+
expect(writeLockHolder(expired).holder).toBeNull();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("the sync form refuses at once while this process's own async write holds the lock", async () => {
|
|
115
|
+
const root = repo({});
|
|
116
|
+
let inner: unknown;
|
|
117
|
+
const outer = withWriteLock(root, { verb: "records amend" }, false, async () => {
|
|
118
|
+
await sleep(30);
|
|
119
|
+
});
|
|
120
|
+
await sleep(5);
|
|
121
|
+
try {
|
|
122
|
+
withWriteLockSync(root, { verb: "box listing set" }, false, () => "no");
|
|
123
|
+
} catch (e) {
|
|
124
|
+
inner = e;
|
|
125
|
+
}
|
|
126
|
+
await outer;
|
|
127
|
+
expect((inner as WriteLockError).code).toBe("write-lock-timeout");
|
|
128
|
+
expect(withWriteLockSync(root, { verb: "box listing set" }, false, () => "yes")).toBe("yes");
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe("a batch held across chant calls (lock acquire)", () => {
|
|
133
|
+
test("its token lets each write through while others wait, and a released token is refused", async () => {
|
|
134
|
+
const root = repo({});
|
|
135
|
+
const acquired = await workspaceLock({ cwd: root, verb: "acquire", holder: "hud:alice", ttl: "30s" });
|
|
136
|
+
lockDoc.expectValid(acquired);
|
|
137
|
+
if ("error" in acquired) throw new Error(acquired.error.message);
|
|
138
|
+
expect(acquired.holder).toMatchObject({ verb: "batch", by: "hud:alice", pid: null });
|
|
139
|
+
expect(acquired.token).toMatch(/^[0-9a-f]{32}$/);
|
|
140
|
+
|
|
141
|
+
const status = await workspaceLock({ cwd: root, verb: undefined });
|
|
142
|
+
lockDoc.expectValid(status);
|
|
143
|
+
expect(status).not.toHaveProperty("token");
|
|
144
|
+
expect(status.holder).toMatchObject({ by: "hud:alice" });
|
|
145
|
+
|
|
146
|
+
// Another writer, without the token, waits and is refused.
|
|
147
|
+
process.env[WRITE_LOCK_WAIT_ENV] = "60";
|
|
148
|
+
await expect(withWriteLock(root, { verb: "records amend" }, false, async () => "no")).rejects.toMatchObject({ code: "write-lock-timeout" });
|
|
149
|
+
// The batch's own writes go ahead.
|
|
150
|
+
process.env[WRITE_LOCK_ENV] = acquired.token!;
|
|
151
|
+
expect(await withWriteLock(root, { verb: "records amend" }, false, async () => "batch write")).toBe("batch write");
|
|
152
|
+
expect(writeLockHolder(root).holder?.verb).toBe("batch");
|
|
153
|
+
|
|
154
|
+
const released = await workspaceLock({ cwd: root, verb: "release", token: acquired.token });
|
|
155
|
+
lockDoc.expectValid(released);
|
|
156
|
+
expect(released).toMatchObject({ verb: "release", holder: null });
|
|
157
|
+
await expect(withWriteLock(root, { verb: "records amend" }, false, async () => "no")).rejects.toMatchObject({ code: "write-lock-not-held" });
|
|
158
|
+
const again = await workspaceLock({ cwd: root, verb: "release", token: acquired.token });
|
|
159
|
+
lockDoc.expectValid(again);
|
|
160
|
+
expect(again).toMatchObject({ error: { code: "write-lock-not-held" } });
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("usage is refused with write-usage-invalid", async () => {
|
|
164
|
+
const root = repo({});
|
|
165
|
+
for (const req of [{ verb: "acquire" }, { verb: "acquire", holder: "x", ttl: "1h" }, { verb: "release" }, { verb: "steal" }, { verb: undefined, token: "x" }]) {
|
|
166
|
+
const doc = await workspaceLock({ cwd: root, ...req });
|
|
167
|
+
lockDoc.expectValid(doc);
|
|
168
|
+
expect(doc).toMatchObject({ error: { code: "write-usage-invalid" } });
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe("the write journal", () => {
|
|
174
|
+
test("names the last chant write of a file while the file holds the text it left", () => {
|
|
175
|
+
const root = repo({});
|
|
176
|
+
noteWrites(root, [{ path: "decisions/ws-001.md", text: "one\n" }], { verb: "records amend", by: null, agent: "app-agent" });
|
|
177
|
+
const read = lastWriteReader(root);
|
|
178
|
+
expect(read("decisions/ws-001.md", "one\n")).toMatchObject({ verb: "records amend", by: null, agent: "app-agent" });
|
|
179
|
+
expect(read("decisions/ws-001.md", "edited by hand\n")).toBeNull();
|
|
180
|
+
expect(read("decisions/ws-002.md", "one\n")).toBeNull();
|
|
181
|
+
expect(JSON.parse(readFileSync(join(root, ".git", "chant-writes.json"), "utf-8")).version).toBe(1);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("is not kept outside git", () => {
|
|
185
|
+
const bare = scratchDir();
|
|
186
|
+
noteWrites(bare, [{ path: "a.md", text: "a" }], { verb: "records new" });
|
|
187
|
+
expect(lastWriteReader(bare)("a.md", "a")).toBeNull();
|
|
188
|
+
});
|
|
189
|
+
});
|