@intentius/chant 0.101.0 → 0.102.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/checks.d.ts.map +1 -1
- package/dist/attrref.d.ts.map +1 -1
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/nginx.d.ts.map +1 -1
- package/dist/audit/prior-art.d.ts +48 -0
- package/dist/audit/prior-art.d.ts.map +1 -1
- package/dist/behaviour-kinds.d.ts.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/cli/commands/carve-emit.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +16 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts +8 -0
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +9 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
- package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +9 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/lsp/server.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/tools/build.d.ts.map +1 -1
- package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
- package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
- package/dist/cli/mcp/tools/import.d.ts.map +1 -1
- package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
- package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
- package/dist/cli/mcp/tools/search.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +11 -2
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/naming.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.d.ts +67 -3
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/verbs/process-runner.d.ts.map +1 -1
- package/dist/components/verbs/r2-sync.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/sign.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts.map +1 -1
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
- package/dist/components/verbs/wrangler.d.ts.map +1 -1
- package/dist/composite.d.ts.map +1 -1
- package/dist/config.d.ts +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/graph-detail.d.ts.map +1 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-layout.d.ts.map +1 -1
- package/dist/import/base-parser.d.ts.map +1 -1
- package/dist/import/embedded.d.ts +7 -0
- package/dist/import/embedded.d.ts.map +1 -1
- package/dist/import/parser-options.d.ts +14 -0
- package/dist/import/parser-options.d.ts.map +1 -0
- package/dist/import/parser.d.ts +17 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts.map +1 -1
- package/dist/lexicon-output.d.ts.map +1 -1
- package/dist/lexicon-schema.d.ts +3 -3
- package/dist/lexicon.d.ts +55 -3
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/assert-live.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +15 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/member-ledger.d.ts.map +1 -1
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/plan-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/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +11 -11
- package/dist/op/activities/apply.d.ts +79 -9
- package/dist/op/activities/apply.d.ts.map +1 -1
- package/dist/op/activities/decide.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +1 -1
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +1 -1
- package/dist/op/activity-failure.d.ts.map +1 -1
- package/dist/op/activity-profiles.d.ts.map +1 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +12 -5
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
- package/dist/op/decide-backend.d.ts.map +1 -1
- package/dist/op/decide-read-inputs.d.ts.map +1 -1
- package/dist/op/emulator-lifecycle.d.ts +21 -2
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate-approval.d.ts +5 -1
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-wait.d.ts.map +1 -1
- package/dist/op/gate.d.ts +19 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/index.d.ts +2 -0
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +6 -0
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/run-context.d.ts +39 -0
- package/dist/op/run-context.d.ts.map +1 -0
- package/dist/op/run-live.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/source-archive.d.ts.map +1 -1
- package/dist/op/steward-beside.d.ts.map +1 -1
- package/dist/op/steward-points.d.ts.map +1 -1
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/types.d.ts +8 -3
- package/dist/op/types.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts +24 -4
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/project-root.d.ts.map +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/pseudo-parameter.d.ts.map +1 -1
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/secret-materialization.d.ts.map +1 -1
- package/dist/terraform/emit-source.d.ts.map +1 -1
- package/dist/terraform/parse.d.ts.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
- package/dist/workspace/agent-cli.d.ts +5 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -1
- package/dist/workspace/box-factory.d.ts +73 -0
- package/dist/workspace/box-factory.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/conformance/index.d.ts +67 -6
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +12 -3
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +368 -0
- package/dist/workspace/conformance/writer.d.ts.map +1 -0
- package/dist/workspace/decide.d.ts +1 -1
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/declaration.d.ts +91 -4
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +234 -5
- 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/intent-cli.d.ts +7 -4
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +8 -1
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +149 -5
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/kinds.d.ts +18 -4
- package/dist/workspace/kinds.d.ts.map +1 -1
- 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/links.d.ts.map +1 -1
- 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 +21 -1
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/record-assets.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 +27 -1
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +1 -1
- 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 +5 -4
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +15 -0
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/runs-cli.d.ts +164 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -0
- package/dist/workspace/runs.d.ts +423 -0
- package/dist/workspace/runs.d.ts.map +1 -0
- package/dist/workspace/source-block.d.ts +1 -1
- package/dist/workspace/source-block.d.ts.map +1 -1
- package/dist/workspace/status-gates.d.ts +15 -3
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +10 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +52 -0
- package/dist/workspace/symbols.d.ts.map +1 -0
- package/dist/workspace/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/seal.d.ts +33 -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/work-cli.d.ts +39 -3
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-evidence.d.ts +1 -1
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work.d.ts +26 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/dist/workspace/workspace-principals.schema.json +60 -0
- package/dist/workspace/write-scope.d.ts +79 -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 +2 -2
- package/src/audit/prior-art.ts +15 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
- 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/components.ts +2 -2
- package/src/cli/handlers/dev.ts +8 -6
- package/src/cli/handlers/lifecycle.test.ts +67 -0
- package/src/cli/handlers/lifecycle.ts +6 -5
- package/src/cli/handlers/misc.ts +2 -0
- package/src/cli/handlers/operator.ts +87 -3
- package/src/cli/handlers/run.test.ts +111 -0
- package/src/cli/handlers/run.ts +85 -24
- package/src/cli/handlers/scenario.ts +2 -2
- package/src/cli/main.test.ts +1 -0
- package/src/cli/main.ts +65 -11
- package/src/cli/mcp/workspace-tools.test.ts +5 -2
- package/src/cli/mcp/workspace-tools.ts +29 -2
- package/src/cli/registry.ts +11 -2
- 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/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/specifier-resolve.ts +344 -0
- package/src/fold/fold.test.ts +39 -1
- package/src/fold/fold.ts +83 -9
- package/src/fold-provenance.test.ts +140 -0
- package/src/graph-ir.test.ts +83 -0
- package/src/graph-ir.ts +29 -0
- package/src/import/embedded.test.ts +20 -0
- package/src/import/embedded.ts +13 -0
- package/src/import/parser-options.ts +46 -0
- package/src/import/parser.ts +20 -0
- package/src/lexicon.ts +55 -3
- package/src/lifecycle/gate-ledger.ts +16 -0
- 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/op/activities/apply.test.ts +189 -5
- package/src/op/activities/apply.ts +230 -8
- package/src/op/activities/index.ts +3 -0
- package/src/op/activities/lexicon-upgrade.test.ts +160 -6
- package/src/op/activities/lexicon-upgrade.ts +154 -51
- package/src/op/composites/apply-op.ts +12 -5
- package/src/op/composites/composites.test.ts +30 -3
- package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
- package/src/op/composites/lexicon-upgrade-op.ts +29 -8
- package/src/op/emulator-lifecycle.test.ts +23 -0
- package/src/op/emulator-lifecycle.ts +52 -14
- package/src/op/gate-approval.test.ts +74 -0
- package/src/op/gate-approval.ts +5 -1
- package/src/op/gate.ts +31 -5
- package/src/op/index.ts +2 -0
- package/src/op/local-executor.test.ts +15 -0
- package/src/op/local-executor.ts +40 -12
- package/src/op/local-output.ts +1 -1
- package/src/op/operator.ts +4 -0
- package/src/op/run-context.test.ts +141 -0
- package/src/op/run-context.ts +51 -0
- package/src/op/runtimes/local.test.ts +14 -0
- package/src/op/runtimes/local.ts +2 -0
- package/src/op/steward-beside.ts +2 -0
- package/src/op/types.ts +8 -3
- package/src/op/work-lease-run.test.ts +47 -0
- package/src/op/work-lease-run.ts +73 -11
- package/src/provenance.ts +35 -0
- package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
- package/src/workspace/agent-cli.ts +7 -3
- package/src/workspace/agent.schema.json +22 -0
- package/src/workspace/box-factory.test.ts +320 -0
- package/src/workspace/box-factory.ts +103 -0
- package/src/workspace/changes.schema.json +12 -20
- package/src/workspace/changes.ts +4 -1
- package/src/workspace/checks/boxes.test.ts +2 -0
- package/src/workspace/checks.ts +29 -5
- package/src/workspace/compose-graph.ts +7 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +27 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +95 -0
- package/src/workspace/conformance/__writer_fixture__/decisions/points.json +132 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +48 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +108 -0
- package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +578 -0
- package/src/workspace/conformance/conformance.e2e.test.ts +35 -3
- package/src/workspace/conformance/index.mjs +30 -3
- package/src/workspace/conformance/index.ts +103 -15
- package/src/workspace/conformance/vitest.ts +44 -2
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +131 -0
- package/src/workspace/conformance/writer.test.ts +156 -0
- package/src/workspace/conformance/writer.ts +880 -0
- package/src/workspace/decide.ts +7 -1
- package/src/workspace/declaration.schema.json +234 -5
- package/src/workspace/declaration.ts +174 -10
- package/src/workspace/graph-cli.ts +5 -2
- package/src/workspace/graph.schema.json +247 -0
- package/src/workspace/identity.test.ts +196 -0
- package/src/workspace/identity.ts +186 -0
- package/src/workspace/intent-cli.ts +64 -10
- package/src/workspace/intent-record.schema.json +208 -0
- package/src/workspace/intent-record.ts +35 -1
- package/src/workspace/intent-why.test.ts +274 -0
- package/src/workspace/intent.schema.json +718 -7
- package/src/workspace/intent.test.ts +11 -2
- package/src/workspace/intent.ts +495 -32
- package/src/workspace/kinds.ts +44 -37
- package/src/workspace/points-write.schema.json +1 -0
- package/src/workspace/principal-classes.test.ts +175 -0
- package/src/workspace/principal-classes.ts +307 -0
- package/src/workspace/reason-codes.test.ts +11 -3
- package/src/workspace/reason-codes.ts +24 -1
- package/src/workspace/records-amend.schema.json +2 -0
- package/src/workspace/records-checkout.ts +106 -0
- package/src/workspace/records-cli.ts +103 -11
- package/src/workspace/records-close.schema.json +1 -0
- package/src/workspace/records-new.schema.json +2 -0
- package/src/workspace/records-review.schema.json +2 -0
- package/src/workspace/records-uncommitted.test.ts +171 -0
- package/src/workspace/records-write.ts +28 -6
- package/src/workspace/records.schema.json +72 -1
- package/src/workspace/records.ts +27 -0
- package/src/workspace/runs-cli.ts +381 -0
- package/src/workspace/runs-write.schema.json +583 -0
- package/src/workspace/runs.schema.json +810 -0
- package/src/workspace/runs.test.ts +242 -0
- package/src/workspace/runs.ts +709 -0
- package/src/workspace/status-contract.test.ts +5 -0
- package/src/workspace/status-gates.ts +22 -8
- package/src/workspace/status.schema.json +127 -2
- package/src/workspace/status.ts +21 -1
- package/src/workspace/symbols.ts +180 -0
- package/src/workspace/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/seal.ts +52 -1
- package/src/workspace/work-cli.e2e.test.ts +28 -1
- package/src/workspace/work-cli.ts +133 -8
- package/src/workspace/work-evidence.schema.json +2 -0
- package/src/workspace/work-history.schema.json +73 -1
- package/src/workspace/work-history.test.ts +48 -5
- package/src/workspace/work-kind-fields.test.ts +154 -0
- package/src/workspace/work-lease.schema.json +14 -1
- package/src/workspace/work.ts +82 -0
- package/src/workspace/workspace-principals.schema.json +60 -0
- package/src/workspace/write-scope.test.ts +128 -2
- package/src/workspace/write-scope.ts +170 -45
- package/src/yaml.test.ts +111 -1
- package/src/yaml.ts +141 -549
package/src/workspace/decide.ts
CHANGED
|
@@ -68,6 +68,8 @@ import { AGENT_ROLE } from "./records-cli";
|
|
|
68
68
|
import type { SourceVia } from "./source-block";
|
|
69
69
|
import type { RecordSource } from "./record-source";
|
|
70
70
|
import { currentStewardTurn } from "../op/steward-turn";
|
|
71
|
+
import { IdentityError, refuseUnidentified } from "./identity";
|
|
72
|
+
import { scopeSource } from "./write-scope";
|
|
71
73
|
import { RefCASConflictError } from "../lifecycle/git";
|
|
72
74
|
import { readLedgerAnswers, refreshLedger, withLedgerAnswers, writeLedgerAnswer, type LedgerAnswers } from "./answers-ledger";
|
|
73
75
|
|
|
@@ -99,6 +101,8 @@ export const POINTS_WRITE_ERROR_CODES = [
|
|
|
99
101
|
"record-id-taken",
|
|
100
102
|
/** The answer was given during a steward's turn (#2749): a steward never answers a question, its own or another's. */
|
|
101
103
|
"answer-in-steward-turn",
|
|
104
|
+
/** An answerer is named by a bare name, and identity.attribution at base is identified (#3163). */
|
|
105
|
+
"principal-unidentified",
|
|
102
106
|
...RECORD_REASON_CODES,
|
|
103
107
|
] as const satisfies readonly ReasonCode[];
|
|
104
108
|
export type PointsWriteErrorCode = (typeof POINTS_WRITE_ERROR_CODES)[number];
|
|
@@ -256,7 +260,7 @@ export type PointsWriteDocument =
|
|
|
256
260
|
| { $schema: string; contract: number; verb: "ask" | "answer"; error: { code: PointsWriteErrorCode; message: string } };
|
|
257
261
|
|
|
258
262
|
function failure(verb: "ask" | "answer", err: unknown): PointsWriteDocument {
|
|
259
|
-
if (err instanceof PointsWriteError || err instanceof RecordWriteError || err instanceof RecordReadError) {
|
|
263
|
+
if (err instanceof PointsWriteError || err instanceof RecordWriteError || err instanceof RecordReadError || err instanceof IdentityError) {
|
|
260
264
|
return { $schema: POINTS_WRITE_SCHEMA_ID, contract: POINTS_WRITE_CONTRACT_VERSION, verb, error: { code: err.code as PointsWriteErrorCode, message: err.message } };
|
|
261
265
|
}
|
|
262
266
|
if (err instanceof WorkspaceReadError) {
|
|
@@ -611,6 +615,8 @@ export async function answerPoint(opts: AnswerPointOptions): Promise<PointsWrite
|
|
|
611
615
|
`this is the steward ${turn.steward}'s turn, and a steward never answers a decision point: a person answers ${opts.id} through hud or \`chant workspace points answer\` at a shell`,
|
|
612
616
|
);
|
|
613
617
|
}
|
|
618
|
+
// #3163: under identity.attribution "identified" at base, each answerer is a forge identity or a signer.
|
|
619
|
+
refuseUnidentified(scopeSource(opts.cwd), opts.by, "--by");
|
|
614
620
|
const kinds = await answerKindFiles(opts.cwd, opts.kind);
|
|
615
621
|
if (kinds.length === 0) throw new PointsWriteError("points-undeclared", "no record kind with an answers block is declared: name one with --kind, or declare one in chant.workspace.json");
|
|
616
622
|
let found:
|
|
@@ -104,12 +104,18 @@
|
|
|
104
104
|
},
|
|
105
105
|
"writeScope": {
|
|
106
106
|
"type": "object",
|
|
107
|
-
"
|
|
108
|
-
|
|
107
|
+
"propertyNames": {
|
|
108
|
+
"$ref": "#/$defs/className"
|
|
109
|
+
},
|
|
110
|
+
"additionalProperties": {
|
|
111
|
+
"$ref": "#/$defs/classScope",
|
|
112
|
+
"description": "A domain class a pinned package supplies at its ./workspace-principals subpath (#3080, ws-079): principals holding the role the class names in the trust policy at base, and none of the agent, runner and service roles. A key no pinned package supplies fails chant workspace check with WSP003, and a writer judged human is refused with write-scope-class-unknown, since it may be in that class. Added in schema 1 by chant 0.102.0, so a declaration that uses one sets minReader to 0.102.0 or newer."
|
|
113
|
+
},
|
|
114
|
+
"description": "Who may write what (#2524 D5, #2548, ws-067): for each principal class, the members whose files it may write and the record kinds it may write, with which verbs. A class is human, agent, runner or service, or a domain class a pinned package supplies (#3080). A class with no entry is not restricted. An agent is always bound to its session's member (agents); its entry can only narrow the record kinds and verbs. chant workspace records new, amend, review and close and the MCP record tools refuse a write outside the writer's scope with write-scope-member or write-scope-kind, and chant workspace check --changes reports each commit that writes outside its author's scope, read from the declaration and the trust policy at the range's base, and a write to a path the class's protected list covers with write-scope-protected (#3146). Added in schema 1 by chant 0.101.0, so a declaration that uses it sets minReader to 0.101.0 or newer.",
|
|
109
115
|
"properties": {
|
|
110
116
|
"human": {
|
|
111
117
|
"$ref": "#/$defs/classScope",
|
|
112
|
-
"description": "Principals holding none of the agent, runner and service roles in the trust policy at base."
|
|
118
|
+
"description": "Principals holding none of the agent, runner and service roles, and none of the roles a domain class names, in the trust policy at base."
|
|
113
119
|
},
|
|
114
120
|
"agent": {
|
|
115
121
|
"$ref": "#/$defs/agentScope",
|
|
@@ -131,6 +137,35 @@
|
|
|
131
137
|
"items": {
|
|
132
138
|
"$ref": "#/$defs/agent"
|
|
133
139
|
}
|
|
140
|
+
},
|
|
141
|
+
"identity": {
|
|
142
|
+
"type": "object",
|
|
143
|
+
"additionalProperties": false,
|
|
144
|
+
"description": "Who a person-attributed record or gate approval may name, and which gates need a signed approval (#3163, ws-080). Read from the declaration at base, like writeScope, so a change can't loosen its own rule. A person is named by a forge identity (github:<login>, gitlab:<login>, or <forge>@<host>:<login> for forgejo, gitea or a self-hosted github or gitlab) that the surface which signed them in maps their session to, or by a principal .chant/allowed_signers lists at base. chant never authenticates a person: a forge identity is recorded as the surface gives it, and only a seal verified against the signers at base attests it. Added in schema 1 by chant 0.102.0, so a declaration that uses it sets minReader to 0.102.0 or newer.",
|
|
145
|
+
"properties": {
|
|
146
|
+
"attribution": {
|
|
147
|
+
"enum": ["any", "identified"],
|
|
148
|
+
"description": "any (the default): a record's by, decided_by, reviewer or answerer and a gate approval's actor may be any name, such as a roster name. identified: each must be a forge identity, a principal the signers file at base lists, or a principal holding the agent, runner or service role at base or listed by a declared agent session; chant workspace records new and review, points answer and chant approve refuse any other name with principal-unidentified."
|
|
149
|
+
},
|
|
150
|
+
"gates": {
|
|
151
|
+
"type": "object",
|
|
152
|
+
"description": "Gates, by name, that pass only on a signed approval: chant approve --sign with a key the signers file at base lists for the approver. The rule applies to a gate of that name in every member, Op and component. An unsigned approval, or one whose signer is not in class, is recorded nowhere and never counts toward the gate.",
|
|
153
|
+
"propertyNames": {
|
|
154
|
+
"type": "string",
|
|
155
|
+
"minLength": 1
|
|
156
|
+
},
|
|
157
|
+
"additionalProperties": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"additionalProperties": false,
|
|
160
|
+
"properties": {
|
|
161
|
+
"class": {
|
|
162
|
+
"$ref": "#/$defs/className",
|
|
163
|
+
"description": "The principal class the signer must be in, read from the role grants at base (#3080, ws-079): human, runner, service, or a domain class a pinned package supplies. A class no pinned package supplies lets no approval through (fail closed). Absent: any signer the signers file lists."
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
134
169
|
}
|
|
135
170
|
},
|
|
136
171
|
"patternProperties": {
|
|
@@ -147,6 +182,11 @@
|
|
|
147
182
|
"type": "string",
|
|
148
183
|
"pattern": "^[a-z][a-z0-9-]{0,39}$"
|
|
149
184
|
},
|
|
185
|
+
"className": {
|
|
186
|
+
"type": "string",
|
|
187
|
+
"pattern": "^(?!x-)[a-z][a-z0-9-]{0,39}$",
|
|
188
|
+
"description": "A principal class: human, agent, runner, service, or a domain class a pinned package supplies (#3080)."
|
|
189
|
+
},
|
|
150
190
|
"version": {
|
|
151
191
|
"type": "string",
|
|
152
192
|
"pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?$"
|
|
@@ -444,7 +484,7 @@
|
|
|
444
484
|
},
|
|
445
485
|
"box": {
|
|
446
486
|
"type": "object",
|
|
447
|
-
"description": "The member is a box, or holds a box's declarations (#2726). A box holds no credential: each capability it needs outside itself is reached through a broker, a runtime such as a lobby or a door, which holds the credential and enforces the scope. chant workspace check fails when a file in the member's directory carries a literal secret (WSP121) and when a capability names no broker (WSP122). chant workspace status --json lists the capabilities, so a broker can read the scopes. Its host, slot, ports, state and cookies state the box's isolation (#2727): chant derives each value from the box's identity, its host, the member's name and its slot, and prints them in chant workspace status --json, so a runtime reads them instead of choosing its own. chant workspace check fails when two boxes on a host resolve to the same value (WSP123) and when a box hard-codes a machine path (WSP124). A member that builds the fountain lexicon's Box declares the callback token fountain gives its persistent sandbox as the capability fountain-callback, brokered by fountain, with scope owner, or chant workspace check fails (WSP125, #2780). Its intent names the decision record that says what the box is for (#2850): chant workspace status --json reports the record's state and answer, and chant workspace check fails when no decision record has the id (WSP126) and warns when the record constrains no member or path of this workspace (WSP127, #2857). Its services list what the box runs under its supervisor (#2880), which the fly lexicon observes, restarts and applies through sprite-env, and which chant workspace status --json prints. Added in schema 1 by chant 0.91.0, so a declaration that uses it sets minReader to 0.91.0 or newer.",
|
|
487
|
+
"description": "The member is a box, or holds a box's declarations (#2726). A box holds no credential: each capability it needs outside itself is reached through a broker, a runtime such as a lobby or a door, which holds the credential and enforces the scope. chant workspace check fails when a file in the member's directory carries a literal secret (WSP121) and when a capability names no broker (WSP122). chant workspace status --json lists the capabilities, so a broker can read the scopes. Its host, slot, ports, state and cookies state the box's isolation (#2727): chant derives each value from the box's identity, its host, the member's name and its slot, and prints them in chant workspace status --json, so a runtime reads them instead of choosing its own. chant workspace check fails when two boxes on a host resolve to the same value (WSP123) and when a box hard-codes a machine path (WSP124). A member that builds the fountain lexicon's Box declares the callback token fountain gives its persistent sandbox as the capability fountain-callback, brokered by fountain, with scope owner, or chant workspace check fails (WSP125, #2780). Its intent names the decision record that says what the box is for (#2850): chant workspace status --json reports the record's state and answer, and chant workspace check fails when no decision record has the id (WSP126) and warns when the record constrains no member or path of this workspace (WSP127, #2857). Its services list what the box runs under its supervisor (#2880), which the fly lexicon observes, restarts and applies through sprite-env, and which chant workspace status --json prints. Its factory declares what the box builds, how a build is checked, which member declares the builder agents and where a finished build is published (#3146, ws-077), and its listing what the box shows of itself (#3146). Added in schema 1 by chant 0.91.0, so a declaration that uses it sets minReader to 0.91.0 or newer.",
|
|
448
488
|
"properties": {
|
|
449
489
|
"intent": {
|
|
450
490
|
"type": "string",
|
|
@@ -458,6 +498,12 @@
|
|
|
458
498
|
"$ref": "#/$defs/boxService"
|
|
459
499
|
}
|
|
460
500
|
},
|
|
501
|
+
"factory": {
|
|
502
|
+
"$ref": "#/$defs/boxFactory"
|
|
503
|
+
},
|
|
504
|
+
"listing": {
|
|
505
|
+
"$ref": "#/$defs/boxListing"
|
|
506
|
+
},
|
|
461
507
|
"capabilities": {
|
|
462
508
|
"type": "array",
|
|
463
509
|
"description": "Each capability the box reaches outside itself, named once. None when omitted.",
|
|
@@ -530,6 +576,142 @@
|
|
|
530
576
|
},
|
|
531
577
|
"additionalProperties": false
|
|
532
578
|
},
|
|
579
|
+
"boxFactory": {
|
|
580
|
+
"type": "object",
|
|
581
|
+
"description": "What the box builds and how (#3146, ws-077), replacing studio's x-factory. Opt-in: a box block without it declares no factory, and nothing here is required of a workspace that doesn't build with agents (#3174). At most one box block in a declaration declares a factory. builds and builders name declared members, or the declaration can't be read (declaration-invalid). chant workspace status --json and chant workspace graph --json print it under the member's box. The factory need not build an app: builds may name any member kind, such as chant or terraform, and the check may be a plan, a lint or a conformance run. Added in schema 1 by chant 0.102.0, so a declaration that uses it sets minReader to 0.102.0 or newer.",
|
|
582
|
+
"required": [
|
|
583
|
+
"builds"
|
|
584
|
+
],
|
|
585
|
+
"properties": {
|
|
586
|
+
"builds": {
|
|
587
|
+
"type": "array",
|
|
588
|
+
"minItems": 1,
|
|
589
|
+
"uniqueItems": true,
|
|
590
|
+
"description": "The members the factory builds, each a declared member of any kind. A work item a person asks for here constrains member:<the first>.",
|
|
591
|
+
"items": {
|
|
592
|
+
"$ref": "#/$defs/name"
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
"check": {
|
|
596
|
+
"description": "The command whose exit code is a build's verdict, run from the workspace root after the work item's own checks: a command, or { run, kind } saying what it is. kind is test when omitted.",
|
|
597
|
+
"oneOf": [
|
|
598
|
+
{
|
|
599
|
+
"type": "string",
|
|
600
|
+
"minLength": 1
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
"type": "object",
|
|
604
|
+
"required": [
|
|
605
|
+
"run"
|
|
606
|
+
],
|
|
607
|
+
"properties": {
|
|
608
|
+
"run": {
|
|
609
|
+
"type": "string",
|
|
610
|
+
"minLength": 1,
|
|
611
|
+
"description": "The command, run from the workspace root."
|
|
612
|
+
},
|
|
613
|
+
"kind": {
|
|
614
|
+
"enum": [
|
|
615
|
+
"test",
|
|
616
|
+
"build",
|
|
617
|
+
"lint",
|
|
618
|
+
"plan",
|
|
619
|
+
"conformance"
|
|
620
|
+
],
|
|
621
|
+
"description": "What the command is: an app's tests, a build, a lint, a lifecycle plan or a conformance run. test when omitted."
|
|
622
|
+
}
|
|
623
|
+
},
|
|
624
|
+
"patternProperties": {
|
|
625
|
+
"^x-": true
|
|
626
|
+
},
|
|
627
|
+
"additionalProperties": false
|
|
628
|
+
}
|
|
629
|
+
]
|
|
630
|
+
},
|
|
631
|
+
"checks": {
|
|
632
|
+
"$ref": "#/$defs/path",
|
|
633
|
+
"description": "The directory, from the workspace root, where a work item's builder writes the check for its item. When omitted the orchestrator chooses, such as <the first member of builds>/checks."
|
|
634
|
+
},
|
|
635
|
+
"builders": {
|
|
636
|
+
"$ref": "#/$defs/name",
|
|
637
|
+
"description": "The member that declares the builder agents, such as the one whose agents/ holds them. Which agent builds at which tier is #3152; the tier vocabulary is the work kind's work.tier.tiers (#3147)."
|
|
638
|
+
},
|
|
639
|
+
"publish": {
|
|
640
|
+
"type": "object",
|
|
641
|
+
"description": "Where a finished build is published: its branch is pushed and a pull request opened against repo's base. The repo is the record, so an orchestrator reads this instead of being told the target in its environment.",
|
|
642
|
+
"required": [
|
|
643
|
+
"repo"
|
|
644
|
+
],
|
|
645
|
+
"properties": {
|
|
646
|
+
"forge": {
|
|
647
|
+
"enum": [
|
|
648
|
+
"github"
|
|
649
|
+
],
|
|
650
|
+
"description": "The forge repo is on. github when omitted."
|
|
651
|
+
},
|
|
652
|
+
"repo": {
|
|
653
|
+
"type": "string",
|
|
654
|
+
"pattern": "^[A-Za-z0-9][A-Za-z0-9-]{0,38}/[A-Za-z0-9._-]{1,100}$",
|
|
655
|
+
"description": "The repository the pull request is opened on, as owner/name."
|
|
656
|
+
},
|
|
657
|
+
"base": {
|
|
658
|
+
"type": "string",
|
|
659
|
+
"minLength": 1,
|
|
660
|
+
"description": "The branch the pull request targets. The repository's default branch when omitted."
|
|
661
|
+
},
|
|
662
|
+
"branchPrefix": {
|
|
663
|
+
"type": "string",
|
|
664
|
+
"minLength": 1,
|
|
665
|
+
"pattern": "^[A-Za-z0-9._/-]+$",
|
|
666
|
+
"description": "What the published branch's name starts with; the work item's id follows, as in box/ and then box/work-012. chant/work/ when omitted, the work lease's own branch."
|
|
667
|
+
},
|
|
668
|
+
"head": {
|
|
669
|
+
"type": "string",
|
|
670
|
+
"pattern": "^[A-Za-z0-9][A-Za-z0-9-]{0,38}/[A-Za-z0-9._-]{1,100}$",
|
|
671
|
+
"description": "The repository the branch is pushed to when it isn't repo, as owner/name: a fork, so the pull request comes from <head owner>:<branch>. A runtime that publishes for one contributor's fork supplies that per contributor instead (arugula-salad/studio#242); this names a fork the whole workspace publishes from."
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
"patternProperties": {
|
|
675
|
+
"^x-": true
|
|
676
|
+
},
|
|
677
|
+
"additionalProperties": false
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
"patternProperties": {
|
|
681
|
+
"^x-": true
|
|
682
|
+
},
|
|
683
|
+
"additionalProperties": false
|
|
684
|
+
},
|
|
685
|
+
"boxListing": {
|
|
686
|
+
"type": "object",
|
|
687
|
+
"description": "What the box shows of itself on a home site that lists boxes (#3146, #3154): whether it is listed, its title and one line, and a cover image kept as a file in the repo. A box's listing is configuration, so changing it is a reviewed change (ws-074). chant workspace status --json and chant workspace graph --json print it under the member's box, with the cover's sha256. Added in schema 1 by chant 0.102.0, so a declaration that uses it sets minReader to 0.102.0 or newer.",
|
|
688
|
+
"properties": {
|
|
689
|
+
"published": {
|
|
690
|
+
"type": "boolean",
|
|
691
|
+
"description": "Whether the box is listed. true when omitted: a box is listed unless its owner takes it out."
|
|
692
|
+
},
|
|
693
|
+
"title": {
|
|
694
|
+
"type": "string",
|
|
695
|
+
"maxLength": 60,
|
|
696
|
+
"pattern": "^[^\\u0000-\\u001f\\u007f-\\u009f]*$",
|
|
697
|
+
"description": "The box's title, one line of at most 60 characters. Empty when omitted, and a reader then shows a name of its own."
|
|
698
|
+
},
|
|
699
|
+
"line": {
|
|
700
|
+
"type": "string",
|
|
701
|
+
"maxLength": 140,
|
|
702
|
+
"pattern": "^[^\\u0000-\\u001f\\u007f-\\u009f]*$",
|
|
703
|
+
"description": "One line saying what the box is, at most 140 characters. Empty when omitted."
|
|
704
|
+
},
|
|
705
|
+
"cover": {
|
|
706
|
+
"$ref": "#/$defs/path",
|
|
707
|
+
"description": "A PNG, JPEG or WebP picture of the box, as a file from the workspace root. None when omitted."
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
"patternProperties": {
|
|
711
|
+
"^x-": true
|
|
712
|
+
},
|
|
713
|
+
"additionalProperties": false
|
|
714
|
+
},
|
|
533
715
|
"boxService": {
|
|
534
716
|
"type": "object",
|
|
535
717
|
"description": "A service a box runs under its supervisor (#2880).",
|
|
@@ -920,6 +1102,39 @@
|
|
|
920
1102
|
}
|
|
921
1103
|
}
|
|
922
1104
|
},
|
|
1105
|
+
"protectedPath": {
|
|
1106
|
+
"description": "A protected path: a glob from the workspace root, or { path, except } for a JSON file whose listed top-level keys may still change.",
|
|
1107
|
+
"oneOf": [
|
|
1108
|
+
{
|
|
1109
|
+
"$ref": "#/$defs/fileGlob"
|
|
1110
|
+
},
|
|
1111
|
+
{
|
|
1112
|
+
"type": "object",
|
|
1113
|
+
"required": [
|
|
1114
|
+
"path"
|
|
1115
|
+
],
|
|
1116
|
+
"properties": {
|
|
1117
|
+
"path": {
|
|
1118
|
+
"$ref": "#/$defs/fileGlob"
|
|
1119
|
+
},
|
|
1120
|
+
"except": {
|
|
1121
|
+
"type": "array",
|
|
1122
|
+
"minItems": 1,
|
|
1123
|
+
"uniqueItems": true,
|
|
1124
|
+
"description": "Top-level keys of the JSON file a write may change. A change anywhere else in the file, or to a file that doesn't parse as a JSON object before and after, is still outside the scope.",
|
|
1125
|
+
"items": {
|
|
1126
|
+
"type": "string",
|
|
1127
|
+
"minLength": 1
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
"patternProperties": {
|
|
1132
|
+
"^x-": true
|
|
1133
|
+
},
|
|
1134
|
+
"additionalProperties": false
|
|
1135
|
+
}
|
|
1136
|
+
]
|
|
1137
|
+
},
|
|
923
1138
|
"classScope": {
|
|
924
1139
|
"type": "object",
|
|
925
1140
|
"description": "A principal class's write scope.",
|
|
@@ -939,6 +1154,13 @@
|
|
|
939
1154
|
}
|
|
940
1155
|
]
|
|
941
1156
|
},
|
|
1157
|
+
"protected": {
|
|
1158
|
+
"type": "array",
|
|
1159
|
+
"description": "Paths the class may not write, even inside a member it may (#3146, ws-077): each a glob from the workspace root, or { path, except } for a JSON file the class may change only in the top-level keys except names. An entry protects the files it matches and everything under a directory it matches. A record file is judged by records, not here. Added in schema 1 by chant 0.102.0, so a declaration that uses it sets minReader to 0.102.0 or newer.",
|
|
1160
|
+
"items": {
|
|
1161
|
+
"$ref": "#/$defs/protectedPath"
|
|
1162
|
+
}
|
|
1163
|
+
},
|
|
942
1164
|
"records": {
|
|
943
1165
|
"$ref": "#/$defs/recordScope",
|
|
944
1166
|
"description": "The record kinds the class may write, and how. Without it, every kind in reach, with every verb. A kind a member declares is in reach when that member is; the workspace's own kinds always are."
|
|
@@ -951,8 +1173,15 @@
|
|
|
951
1173
|
},
|
|
952
1174
|
"agentScope": {
|
|
953
1175
|
"type": "object",
|
|
954
|
-
"description": "The agent class's write scope. Its members are always its session's one member, so only the record kinds can be set.",
|
|
1176
|
+
"description": "The agent class's write scope. Its members are always its session's one member, so only the record kinds and the protected paths can be set.",
|
|
955
1177
|
"properties": {
|
|
1178
|
+
"protected": {
|
|
1179
|
+
"type": "array",
|
|
1180
|
+
"description": "Paths the class may not write, even inside a member it may (#3146, ws-077): each a glob from the workspace root, or { path, except } for a JSON file the class may change only in the top-level keys except names. An entry protects the files it matches and everything under a directory it matches. A record file is judged by records, not here. Added in schema 1 by chant 0.102.0, so a declaration that uses it sets minReader to 0.102.0 or newer.",
|
|
1181
|
+
"items": {
|
|
1182
|
+
"$ref": "#/$defs/protectedPath"
|
|
1183
|
+
}
|
|
1184
|
+
},
|
|
956
1185
|
"records": {
|
|
957
1186
|
"$ref": "#/$defs/recordScope",
|
|
958
1187
|
"description": "The record kinds an agent may write, and how. Without it, every kind in reach of its member, with every verb."
|
|
@@ -107,9 +107,11 @@ export interface ChangesPolicy {
|
|
|
107
107
|
ignore: string[];
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
/** The core principal classes (#2524 D5). */
|
|
110
|
+
/** The core principal classes (#2524 D5). A pinned package may supply domain classes too (#3080, `principal-classes.ts`). */
|
|
111
111
|
export const PRINCIPAL_CLASSES = ["human", "agent", "runner", "service"] as const;
|
|
112
|
-
export type
|
|
112
|
+
export type CorePrincipalClass = (typeof PRINCIPAL_CLASSES)[number];
|
|
113
|
+
/** A class name: a core class, or a domain class a pinned package supplies (#3080). */
|
|
114
|
+
export type PrincipalClass = string;
|
|
113
115
|
|
|
114
116
|
/** How a record is written, as the records commands name it (#2548). */
|
|
115
117
|
export const WRITE_VERBS = ["new", "amend", "review", "close"] as const;
|
|
@@ -121,11 +123,46 @@ export interface ClassScope {
|
|
|
121
123
|
members: string[] | null;
|
|
122
124
|
/** Kind name to the verbs the class may write it with, or null for every kind in reach with every verb. */
|
|
123
125
|
records: Record<string, WriteVerb[]> | null;
|
|
126
|
+
/** Paths the class may not write even inside a member it may (#3146, ws-077), in file order. Empty when the entry lists none. */
|
|
127
|
+
protected: ProtectedPath[];
|
|
124
128
|
pointer: string;
|
|
125
129
|
}
|
|
126
130
|
|
|
127
|
-
/**
|
|
128
|
-
|
|
131
|
+
/**
|
|
132
|
+
* A protected path in a write scope (#3146, ws-077): a glob from the
|
|
133
|
+
* workspace root. It protects the files it matches and everything under a
|
|
134
|
+
* directory it matches. `except` names top-level keys of a JSON file a write
|
|
135
|
+
* may still change; empty when the entry allows none.
|
|
136
|
+
*/
|
|
137
|
+
export interface ProtectedPath {
|
|
138
|
+
path: string;
|
|
139
|
+
except: string[];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The declaration's `writeScope` block: an entry per restricted class, in
|
|
144
|
+
* file order. A class with no entry is not restricted. A key may name a
|
|
145
|
+
* domain class a pinned package supplies (#3080); whether one does is known
|
|
146
|
+
* only once the pins are read, so an unknown key is judged where the scope
|
|
147
|
+
* is applied, not here.
|
|
148
|
+
*/
|
|
149
|
+
export type WriteScope = Record<PrincipalClass, ClassScope>;
|
|
150
|
+
|
|
151
|
+
/** A gate the declaration's `identity.gates` names (#3163, ws-080): it passes only on a signed approval. */
|
|
152
|
+
export interface SignedGate {
|
|
153
|
+
gate: string;
|
|
154
|
+
/** The class the signer must be in, or null for any signer the signers file at base lists. */
|
|
155
|
+
class: PrincipalClass | null;
|
|
156
|
+
pointer: string;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** The declaration's `identity` block (#3163, ws-080), read at base. */
|
|
160
|
+
export interface IdentityPolicy {
|
|
161
|
+
/** `identified`: a person-attributed write must name a forge identity, a signer at base, or an agent, runner or service principal. */
|
|
162
|
+
attribution: "any" | "identified";
|
|
163
|
+
/** By gate name. */
|
|
164
|
+
gates: Record<string, SignedGate>;
|
|
165
|
+
}
|
|
129
166
|
|
|
130
167
|
/** An agent session the declaration names (#2524 D20, #2548): bound to one member. */
|
|
131
168
|
export interface AgentDeclaration {
|
|
@@ -254,10 +291,63 @@ export interface BoxDeclaration {
|
|
|
254
291
|
* `spriteApplyServices` read them with `box: true`.
|
|
255
292
|
*/
|
|
256
293
|
services: BoxService[];
|
|
294
|
+
/** What the box builds and how (#3146, ws-077), or null when the block declares no factory. */
|
|
295
|
+
factory: BoxFactory | null;
|
|
296
|
+
/** What the box shows of itself on a home site (#3146), or null when the block declares no listing. */
|
|
297
|
+
listing: BoxListing | null;
|
|
298
|
+
/** The block's JSON Pointer in the file, for messages. */
|
|
299
|
+
pointer: string;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** What a check command is (#3146). */
|
|
303
|
+
export const FACTORY_CHECK_KINDS = ["test", "build", "lint", "plan", "conformance"] as const;
|
|
304
|
+
export type FactoryCheckKind = (typeof FACTORY_CHECK_KINDS)[number];
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* A box's factory (#3146, ws-077): what it builds, how a build is checked,
|
|
308
|
+
* which member declares the builder agents and where a finished build is
|
|
309
|
+
* published. Defaults are filled in, so a reader never guesses one.
|
|
310
|
+
*/
|
|
311
|
+
export interface BoxFactory {
|
|
312
|
+
/** The members the factory builds, in file order; at least one. */
|
|
313
|
+
builds: string[];
|
|
314
|
+
/** The verdict command, run from the workspace root, or null when none is declared. */
|
|
315
|
+
check: { run: string; kind: FactoryCheckKind } | null;
|
|
316
|
+
/** Where a work item's builder writes its check, from the workspace root, or null for the orchestrator's choice. */
|
|
317
|
+
checks: string | null;
|
|
318
|
+
/** The member that declares the builder agents, or null when none is named. */
|
|
319
|
+
builders: string | null;
|
|
320
|
+
/** Where a finished build is published, or null when the factory doesn't publish past the box. */
|
|
321
|
+
publish: FactoryPublish | null;
|
|
257
322
|
/** The block's JSON Pointer in the file, for messages. */
|
|
258
323
|
pointer: string;
|
|
259
324
|
}
|
|
260
325
|
|
|
326
|
+
/** Where a finished build goes (#3146): its branch is pushed and a pull request opened against `repo`'s `base`. */
|
|
327
|
+
export interface FactoryPublish {
|
|
328
|
+
forge: "github";
|
|
329
|
+
/** owner/name. */
|
|
330
|
+
repo: string;
|
|
331
|
+
/** The branch the pull request targets, or null for the repository's default branch. */
|
|
332
|
+
base: string | null;
|
|
333
|
+
/** What the published branch's name starts with, before the work item's id. */
|
|
334
|
+
branchPrefix: string;
|
|
335
|
+
/** The repository the branch is pushed to when it isn't `repo` (a fork), as owner/name, or null. */
|
|
336
|
+
head: string | null;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** The branch prefix a publish target uses when it names none: the work lease's own branch. */
|
|
340
|
+
export const DEFAULT_PUBLISH_BRANCH_PREFIX = "chant/work/";
|
|
341
|
+
|
|
342
|
+
/** What a box shows of itself (#3146, #3154). */
|
|
343
|
+
export interface BoxListing {
|
|
344
|
+
published: boolean;
|
|
345
|
+
title: string;
|
|
346
|
+
line: string;
|
|
347
|
+
/** The cover image, from the workspace root, or null. */
|
|
348
|
+
cover: string | null;
|
|
349
|
+
}
|
|
350
|
+
|
|
261
351
|
/** A service a box runs under its supervisor (#2880). */
|
|
262
352
|
export interface BoxService {
|
|
263
353
|
/** Unique in the box. */
|
|
@@ -375,6 +465,8 @@ export interface Declaration {
|
|
|
375
465
|
writeScope: WriteScope | null;
|
|
376
466
|
/** The agent sessions, in file order (#2548). */
|
|
377
467
|
agents: AgentDeclaration[];
|
|
468
|
+
/** Who a person-attributed write may name, and which gates need a signed approval (#3163), or null when the declaration has no `identity` block. */
|
|
469
|
+
identity: IdentityPolicy | null;
|
|
378
470
|
/** The file, relative to the workspace root's tree (`chant.workspace.json` or `.jsonc`). */
|
|
379
471
|
file: string;
|
|
380
472
|
}
|
|
@@ -699,6 +791,9 @@ export function parseDeclaration(text: string, file: string, reader: string = re
|
|
|
699
791
|
const problem = m.box ? boxServicesProblem(m.name, m.box.services) : null;
|
|
700
792
|
if (problem) throw new WorkspaceReadError("declaration-invalid", problem.message, at(problem.pointer));
|
|
701
793
|
}
|
|
794
|
+
// One factory, building and naming declared members (#3146).
|
|
795
|
+
const factory = factoryProblem(members);
|
|
796
|
+
if (factory) throw new WorkspaceReadError("declaration-invalid", factory.message, at(factory.pointer));
|
|
702
797
|
|
|
703
798
|
// A diagram name is given once across the declaration (#2764): a reader keys diagrams by name.
|
|
704
799
|
const ownDiagrams = diagramsOf(obj.diagrams, null, "/diagrams");
|
|
@@ -738,21 +833,21 @@ export function parseDeclaration(text: string, file: string, reader: string = re
|
|
|
738
833
|
changes: changesOf(obj.changes as Record<string, unknown> | undefined),
|
|
739
834
|
writeScope,
|
|
740
835
|
agents,
|
|
836
|
+
identity: identityOf(obj.identity),
|
|
741
837
|
file,
|
|
742
838
|
};
|
|
743
839
|
}
|
|
744
840
|
|
|
745
841
|
/**
|
|
746
842
|
* The `writeScope` block, already validated, with the rule the schema can't
|
|
747
|
-
* say (#2548): a member it names is a declared member.
|
|
843
|
+
* say (#2548): a member it names is a declared member. Its keys are kept in
|
|
844
|
+
* file order: the core classes and any domain class (#3080).
|
|
748
845
|
*/
|
|
749
846
|
function writeScopeOf(raw: unknown, members: Member[], at: (pointer: string, key?: boolean) => ErrorLocation): WriteScope | null {
|
|
750
847
|
if (raw === undefined) return null;
|
|
751
|
-
const block = raw as
|
|
848
|
+
const block = raw as Record<PrincipalClass, { members?: "*" | string[]; records?: Record<string, WriteVerb[]>; protected?: (string | { path: string; except?: string[] })[] }>;
|
|
752
849
|
const out: WriteScope = {};
|
|
753
|
-
for (const cls of
|
|
754
|
-
const entry = block[cls];
|
|
755
|
-
if (entry === undefined) continue;
|
|
850
|
+
for (const [cls, entry] of Object.entries(block)) {
|
|
756
851
|
const pointer = `/writeScope/${cls}`;
|
|
757
852
|
const list = entry.members === undefined || entry.members === "*" ? null : [...entry.members];
|
|
758
853
|
for (const [i, name] of (list ?? []).entries()) {
|
|
@@ -765,7 +860,8 @@ function writeScopeOf(raw: unknown, members: Member[], at: (pointer: string, key
|
|
|
765
860
|
}
|
|
766
861
|
}
|
|
767
862
|
const records = entry.records === undefined ? null : Object.fromEntries(Object.entries(entry.records).map(([k, v]) => [k, [...v]]));
|
|
768
|
-
|
|
863
|
+
const guarded = (entry.protected ?? []).map((p) => (typeof p === "string" ? { path: p, except: [] } : { path: p.path, except: [...(p.except ?? [])] }));
|
|
864
|
+
out[cls] = { members: list, records, protected: guarded, pointer };
|
|
769
865
|
}
|
|
770
866
|
return out;
|
|
771
867
|
}
|
|
@@ -775,6 +871,17 @@ function writeScopeOf(raw: unknown, members: Member[], at: (pointer: string, key
|
|
|
775
871
|
* (#2548): names are unique, each names a declared member, and a principal
|
|
776
872
|
* is listed by one session at most.
|
|
777
873
|
*/
|
|
874
|
+
/** The `identity` block, already validated by the schema (#3163). */
|
|
875
|
+
function identityOf(raw: unknown): IdentityPolicy | null {
|
|
876
|
+
if (raw === undefined) return null;
|
|
877
|
+
const block = raw as { attribution?: "any" | "identified"; gates?: Record<string, { class?: string }> };
|
|
878
|
+
const gates: Record<string, SignedGate> = {};
|
|
879
|
+
for (const [gate, entry] of Object.entries(block.gates ?? {})) {
|
|
880
|
+
gates[gate] = { gate, class: entry.class ?? null, pointer: `/identity/gates/${gate.replace(/~/g, "~0").replace(/\//g, "~1")}` };
|
|
881
|
+
}
|
|
882
|
+
return { attribution: block.attribution ?? "any", gates };
|
|
883
|
+
}
|
|
884
|
+
|
|
778
885
|
function agentsOf(raw: unknown, members: Member[], at: (pointer: string, key?: boolean) => ErrorLocation): AgentDeclaration[] {
|
|
779
886
|
const agents = ((raw as { name: string; member: string; principals?: string[] }[] | undefined) ?? []).map((a, i) => ({
|
|
780
887
|
name: a.name,
|
|
@@ -856,7 +963,17 @@ function boxOf(raw: unknown, pointer: string): BoxDeclaration | null {
|
|
|
856
963
|
cookies?: string[];
|
|
857
964
|
intent?: string;
|
|
858
965
|
services?: { name: string; cmd: string; needs?: string[]; httpPort?: number; duration?: string; health?: string; optional?: boolean }[];
|
|
966
|
+
factory?: {
|
|
967
|
+
builds: string[];
|
|
968
|
+
check?: string | { run: string; kind?: FactoryCheckKind };
|
|
969
|
+
checks?: string;
|
|
970
|
+
builders?: string;
|
|
971
|
+
publish?: { forge?: "github"; repo: string; base?: string; branchPrefix?: string; head?: string };
|
|
972
|
+
};
|
|
973
|
+
listing?: { published?: boolean; title?: string; line?: string; cover?: string };
|
|
859
974
|
};
|
|
975
|
+
const f = b.factory;
|
|
976
|
+
const l = b.listing;
|
|
860
977
|
return {
|
|
861
978
|
capabilities: (b.capabilities ?? []).map((c, i) => ({ name: c.name, broker: c.broker ?? null, scope: [...(c.scope ?? [])], pointer: `${pointer}/capabilities/${i}` })),
|
|
862
979
|
// The schema requires host and slot together, and host for ports, state and cookies.
|
|
@@ -875,10 +992,57 @@ function boxOf(raw: unknown, pointer: string): BoxDeclaration | null {
|
|
|
875
992
|
optional: s.optional ?? false,
|
|
876
993
|
pointer: `${pointer}/services/${i}`,
|
|
877
994
|
})),
|
|
995
|
+
factory:
|
|
996
|
+
f === undefined
|
|
997
|
+
? null
|
|
998
|
+
: {
|
|
999
|
+
builds: [...f.builds],
|
|
1000
|
+
check: f.check === undefined ? null : typeof f.check === "string" ? { run: f.check, kind: "test" } : { run: f.check.run, kind: f.check.kind ?? "test" },
|
|
1001
|
+
checks: f.checks ?? null,
|
|
1002
|
+
builders: f.builders ?? null,
|
|
1003
|
+
publish:
|
|
1004
|
+
f.publish === undefined
|
|
1005
|
+
? null
|
|
1006
|
+
: {
|
|
1007
|
+
forge: f.publish.forge ?? "github",
|
|
1008
|
+
repo: f.publish.repo,
|
|
1009
|
+
base: f.publish.base ?? null,
|
|
1010
|
+
branchPrefix: f.publish.branchPrefix ?? DEFAULT_PUBLISH_BRANCH_PREFIX,
|
|
1011
|
+
head: f.publish.head ?? null,
|
|
1012
|
+
},
|
|
1013
|
+
pointer: `${pointer}/factory`,
|
|
1014
|
+
},
|
|
1015
|
+
listing: l === undefined ? null : { published: l.published ?? true, title: l.title ?? "", line: l.line ?? "", cover: l.cover ?? null },
|
|
878
1016
|
pointer,
|
|
879
1017
|
};
|
|
880
1018
|
}
|
|
881
1019
|
|
|
1020
|
+
/**
|
|
1021
|
+
* The rules the schema can't say about the factories (#3146, ws-077): at most
|
|
1022
|
+
* one box block declares one, and the members its builds and builders name
|
|
1023
|
+
* are declared members.
|
|
1024
|
+
*/
|
|
1025
|
+
function factoryProblem(members: readonly Member[]): { message: string; pointer: string } | null {
|
|
1026
|
+
const declaring = members.filter((m) => m.box?.factory);
|
|
1027
|
+
if (declaring.length > 1) {
|
|
1028
|
+
return {
|
|
1029
|
+
message: `members ${declaring[0].name} and ${declaring[1].name} both declare a factory in their box block; a workspace has one factory, so an orchestrator reads one`,
|
|
1030
|
+
pointer: declaring[1].box!.factory!.pointer,
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
const factory = declaring[0]?.box?.factory;
|
|
1034
|
+
if (!factory) return null;
|
|
1035
|
+
const known = () => members.map((m) => m.name).join(", ");
|
|
1036
|
+
const j = factory.builds.findIndex((name) => !members.some((m) => m.name === name));
|
|
1037
|
+
if (j >= 0) {
|
|
1038
|
+
return { message: `the factory builds ${JSON.stringify(factory.builds[j])}, which is not a declared member; declared members: ${known()}`, pointer: `${factory.pointer}/builds/${j}` };
|
|
1039
|
+
}
|
|
1040
|
+
if (factory.builders !== null && !members.some((m) => m.name === factory.builders)) {
|
|
1041
|
+
return { message: `the factory's builders names ${JSON.stringify(factory.builders)}, which is not a declared member; declared members: ${known()}`, pointer: `${factory.pointer}/builders` };
|
|
1042
|
+
}
|
|
1043
|
+
return null;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
882
1046
|
/**
|
|
883
1047
|
* The rules the schema can't say about a box's services (#2880), as a
|
|
884
1048
|
* message and the pointer to show, or null when they hold: each name is
|
|
@@ -30,6 +30,7 @@ import { tmpdir } from "node:os";
|
|
|
30
30
|
import { dirname, join, resolve } from "node:path";
|
|
31
31
|
import { formatError } from "../cli/format";
|
|
32
32
|
import type { CommandContext, ParsedArgs } from "../cli/registry";
|
|
33
|
+
import { graphBox, plantability, type Plantable } from "./box-factory";
|
|
33
34
|
import { composeWorkspaceGraph, readMemberIr, type ComposedMember, type ComposeInput, type WorkspaceGraph } from "./compose-graph";
|
|
34
35
|
import { openGraphCache, splitCached, storeReads, withoutUnits } from "./graph-cache";
|
|
35
36
|
import { readDeclaration, readerVersion, WORKSPACE_ERROR_CODES, WorkspaceReadError, type ErrorLocation } from "./declaration";
|
|
@@ -67,7 +68,7 @@ interface Head {
|
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
export type GraphDocument =
|
|
70
|
-
| (Head & { at: string | null } & WorkspaceGraph)
|
|
71
|
+
| (Head & { at: string | null; plantable: Plantable } & WorkspaceGraph)
|
|
71
72
|
| (Head & { error: { code: GraphErrorCode; message: string; location: ErrorLocation | null } });
|
|
72
73
|
|
|
73
74
|
export interface GraphQuery {
|
|
@@ -258,6 +259,8 @@ export async function workspaceGraph(query: GraphQuery): Promise<GraphResult> {
|
|
|
258
259
|
}
|
|
259
260
|
// Links (#2539) resolve against the declaration that was read, the revision's for --at, and the kinds installed now.
|
|
260
261
|
const graph = composeWorkspaceGraph({ name: declaration.name, root: located.root }, inputs, { declaration, kinds });
|
|
262
|
+
// The box's factory and listing (#3146), from the declaration read, so --at gives them at that revision.
|
|
263
|
+
for (const member of graph.members) member.box = graphBox(declaration.members.find((m) => m.name === member.name)?.box ?? null, located.tree);
|
|
261
264
|
// Nested workspaces (#2551, ws-071): read-only, through their own chant workspace graph.
|
|
262
265
|
const nestedFailed = await expandNested(graph, declaration.members, query, located.rootOnDisk, located.at);
|
|
263
266
|
let recordsFailed = false;
|
|
@@ -276,7 +279,7 @@ export async function workspaceGraph(query: GraphQuery): Promise<GraphResult> {
|
|
|
276
279
|
query.onStderr?.(`${formatError({ message: `--kind ${query.kind}: ${err.code}: ${err.message}`, hint: USAGE })}\n`);
|
|
277
280
|
}
|
|
278
281
|
}
|
|
279
|
-
return { doc: { ...head, at: located.at, ...graph }, failed: failed || recordsFailed || nestedFailed, ...(components ? { components } : {}) };
|
|
282
|
+
return { doc: { ...head, at: located.at, plantable: plantability(declaration), ...graph }, failed: failed || recordsFailed || nestedFailed, ...(components ? { components } : {}) };
|
|
280
283
|
} catch (err) {
|
|
281
284
|
if (!(err instanceof WorkspaceReadError)) throw err;
|
|
282
285
|
return { doc: { ...head, error: { code: err.code, message: err.message, location: err.location ?? null } }, failed: true };
|