@intentius/chant 0.91.0 → 0.94.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/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +6 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-plugins.d.ts +6 -6
- package/dist/cli/mcp/workspace-tools.d.ts +2 -1
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +12 -2
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/lexicon-module.d.ts +22 -0
- package/dist/lexicon-module.d.ts.map +1 -1
- package/dist/lifecycle/converge-ledger.d.ts +19 -0
- package/dist/lifecycle/converge-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.d.ts +2 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/symptoms.d.ts +51 -0
- package/dist/lifecycle/symptoms.d.ts.map +1 -1
- package/dist/lint/rules/index.d.ts +4 -2
- package/dist/lint/rules/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +14 -3
- package/dist/lint/rules/op/index.d.ts.map +1 -1
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -1
- package/dist/lint/rules/op/sys010-key-over-plain-http.d.ts +29 -0
- package/dist/lint/rules/op/sys010-key-over-plain-http.d.ts.map +1 -0
- package/dist/lint/rules/sys001-no-literal-key.d.ts +3 -0
- package/dist/lint/rules/sys001-no-literal-key.d.ts.map +1 -0
- package/dist/op/__fixtures__/decide-stub-backend.d.ts +53 -0
- package/dist/op/__fixtures__/decide-stub-backend.d.ts.map +1 -0
- package/dist/op/activities/activity-contracts.d.ts +201 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/apply.d.ts.map +1 -1
- package/dist/op/activities/change-coverage.d.ts +44 -0
- package/dist/op/activities/change-coverage.d.ts.map +1 -0
- package/dist/op/activities/converge.d.ts +24 -1
- package/dist/op/activities/converge.d.ts.map +1 -1
- package/dist/op/activities/decide.d.ts +107 -0
- package/dist/op/activities/decide.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +10 -0
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/shell.d.ts +32 -0
- package/dist/op/activities/shell.d.ts.map +1 -1
- package/dist/op/activities/source-release.d.ts +86 -0
- package/dist/op/activities/source-release.d.ts.map +1 -0
- package/dist/op/activities/source-rollback.d.ts +100 -0
- package/dist/op/activities/source-rollback.d.ts.map +1 -0
- package/dist/op/activities/work-evidence.d.ts +42 -0
- package/dist/op/activities/work-evidence.d.ts.map +1 -0
- package/dist/op/activity-contract.d.ts +1 -0
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-profiles.d.ts +16 -0
- package/dist/op/activity-profiles.d.ts.map +1 -1
- package/dist/op/builders.d.ts +84 -2
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/converge-op.d.ts +31 -4
- package/dist/op/composites/converge-op.d.ts.map +1 -1
- package/dist/op/decide-backend.d.ts +116 -0
- package/dist/op/decide-backend.d.ts.map +1 -0
- package/dist/op/decide-config.d.ts +120 -0
- package/dist/op/decide-config.d.ts.map +1 -0
- package/dist/op/decide-read-inputs.d.ts +40 -0
- package/dist/op/decide-read-inputs.d.ts.map +1 -0
- package/dist/op/gate-wait.d.ts +43 -0
- package/dist/op/gate-wait.d.ts.map +1 -0
- package/dist/op/gate.d.ts +5 -2
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/index.d.ts +11 -4
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +29 -4
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-output.d.ts +2 -0
- package/dist/op/local-output.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 +97 -1
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/runtime.d.ts +37 -5
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/source-archive.d.ts +63 -0
- package/dist/op/source-archive.d.ts.map +1 -0
- package/dist/op/steward-points.d.ts +136 -0
- package/dist/op/steward-points.d.ts.map +1 -0
- package/dist/op/steward-turn.d.ts +53 -0
- package/dist/op/steward-turn.d.ts.map +1 -0
- package/dist/op/steward.d.ts +22 -1
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/types.d.ts +7 -0
- package/dist/op/types.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts +1 -1
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts +100 -0
- package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -0
- package/dist/workspace/answers-ledger.d.ts +76 -0
- package/dist/workspace/answers-ledger.d.ts.map +1 -0
- package/dist/workspace/box-intent.d.ts +85 -0
- package/dist/workspace/box-intent.d.ts.map +1 -0
- package/dist/workspace/changes-cli.d.ts +16 -0
- package/dist/workspace/changes-cli.d.ts.map +1 -0
- package/dist/workspace/changes.d.ts +200 -0
- package/dist/workspace/changes.d.ts.map +1 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.d.ts +59 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.d.ts.map +1 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.d.ts +51 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.d.ts.map +1 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.d.ts +26 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.d.ts.map +1 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.d.ts +59 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.d.ts.map +1 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.d.ts +22 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.d.ts.map +1 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts +71 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -0
- package/dist/workspace/chant-migrations.d.ts +104 -0
- package/dist/workspace/chant-migrations.d.ts.map +1 -0
- package/dist/workspace/checks/boxes.d.ts +47 -1
- package/dist/workspace/checks/boxes.d.ts.map +1 -1
- package/dist/workspace/checks/diagrams.d.ts +31 -0
- package/dist/workspace/checks/diagrams.d.ts.map +1 -0
- package/dist/workspace/checks/records.d.ts +7 -0
- package/dist/workspace/checks/records.d.ts.map +1 -1
- package/dist/workspace/checks.d.ts +7 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +2 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/decide.d.ts +49 -4
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/decision-points.schema.json +3 -3
- package/dist/workspace/declaration.d.ts +58 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +119 -1
- package/dist/workspace/declared-kinds.d.ts +20 -0
- package/dist/workspace/declared-kinds.d.ts.map +1 -1
- package/dist/workspace/generated-files.d.ts +7 -0
- package/dist/workspace/generated-files.d.ts.map +1 -1
- package/dist/workspace/intent-joins.d.ts +5 -5
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/lineage-check.d.ts +3 -0
- package/dist/workspace/lineage-check.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.d.ts +6 -1
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/ls.d.ts +39 -1
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/point-answer.schema.json +95 -0
- package/dist/workspace/points-cli.d.ts +2 -0
- package/dist/workspace/points-cli.d.ts.map +1 -1
- package/dist/workspace/points.d.ts +4 -6
- package/dist/workspace/points.d.ts.map +1 -1
- package/dist/workspace/reason-codes.d.ts +16 -2
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/records-cli.d.ts +11 -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-write.d.ts +11 -5
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +34 -4
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/status-gates.d.ts +7 -2
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status-stewards.d.ts +65 -1
- package/dist/workspace/status-stewards.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +24 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/work-cli.d.ts +113 -2
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-evidence.d.ts +74 -0
- package/dist/workspace/work-evidence.d.ts.map +1 -0
- package/dist/workspace/work.d.ts +43 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/audit.test.ts +9 -1
- package/src/cli/commands/build.ts +3 -2
- package/src/cli/commands/lint.ts +7 -1
- package/src/cli/handlers/graph.test.ts +20 -0
- package/src/cli/handlers/graph.ts +16 -2
- package/src/cli/handlers/operator.ts +34 -2
- package/src/cli/handlers/run.test.ts +154 -2
- package/src/cli/handlers/run.ts +121 -2
- package/src/cli/main.test.ts +10 -0
- package/src/cli/main.ts +23 -3
- package/src/cli/mcp/workspace-plugins.ts +6 -6
- package/src/cli/mcp/workspace-tools.test.ts +35 -19
- package/src/cli/mcp/workspace-tools.ts +62 -4
- package/src/cli/plugins.ts +11 -3
- package/src/cli/registry.ts +12 -2
- package/src/cli/serve-mcp-workspace.test.ts +6 -6
- package/src/codegen/pinned-upgrade.ts +2 -1
- package/src/codegen/release-wiring.test.ts +49 -2
- package/src/components/capability-plugin-loader.ts +3 -3
- package/src/components/cli-support.ts +2 -2
- package/src/config.ts +11 -0
- package/src/lexicon-module.ts +56 -1
- package/src/lexicon-package.test.ts +96 -0
- package/src/lifecycle/converge-ledger.ts +20 -0
- package/src/lifecycle/run-ledger.ts +6 -0
- package/src/lifecycle/symptoms.ts +95 -0
- package/src/lint/rules/index.ts +6 -2
- package/src/lint/rules/op/index.ts +17 -4
- package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +23 -1
- package/src/lint/rules/op/ops014-converge-rule-refusals.ts +10 -6
- package/src/lint/rules/op/sys010-key-over-plain-http.test.ts +52 -0
- package/src/lint/rules/op/sys010-key-over-plain-http.ts +100 -0
- package/src/lint/rules/sys001-no-literal-key.test.ts +31 -0
- package/src/lint/rules/sys001-no-literal-key.ts +67 -0
- package/src/op/__fixtures__/decide-stub-backend.ts +143 -0
- package/src/op/activities/activity-contracts.ts +190 -1
- package/src/op/activities/apply.ts +7 -6
- package/src/op/activities/change-coverage.ts +60 -0
- package/src/op/activities/converge.test.ts +55 -1
- package/src/op/activities/converge.ts +208 -29
- package/src/op/activities/decide.live.test.ts +78 -0
- package/src/op/activities/decide.test.ts +308 -0
- package/src/op/activities/decide.ts +267 -0
- package/src/op/activities/index.ts +21 -0
- package/src/op/activities/shell.test.ts +91 -1
- package/src/op/activities/shell.ts +91 -2
- package/src/op/activities/source-release.test.ts +118 -0
- package/src/op/activities/source-release.ts +168 -0
- package/src/op/activities/source-rollback.test.ts +131 -0
- package/src/op/activities/source-rollback.ts +239 -0
- package/src/op/activities/work-evidence.ts +62 -0
- package/src/op/activity-contract-registry.test.ts +2 -0
- package/src/op/activity-contract-registry.ts +2 -2
- package/src/op/activity-contract.test.ts +12 -0
- package/src/op/activity-contract.ts +6 -1
- package/src/op/activity-profiles.ts +29 -0
- package/src/op/activity-registry.test.ts +1 -1
- package/src/op/activity-registry.ts +2 -2
- package/src/op/builders.ts +119 -5
- package/src/op/command-gate.test.ts +192 -0
- package/src/op/composites/converge-op.test.ts +27 -1
- package/src/op/composites/converge-op.ts +69 -15
- package/src/op/decide-backend.test.ts +44 -0
- package/src/op/decide-backend.ts +212 -0
- package/src/op/decide-config.test.ts +52 -0
- package/src/op/decide-config.ts +80 -0
- package/src/op/decide-read-inputs.ts +117 -0
- package/src/op/gate-approval.ts +2 -2
- package/src/op/gate-wait.ts +57 -0
- package/src/op/gate.ts +8 -3
- package/src/op/generate-pipeline.ts +2 -2
- package/src/op/index.ts +18 -3
- package/src/op/local-executor.ts +151 -15
- package/src/op/local-output.test.ts +33 -0
- package/src/op/local-output.ts +20 -2
- package/src/op/op-ir.test.ts +10 -0
- package/src/op/op-ir.ts +4 -0
- package/src/op/op-verb-class.ts +1 -0
- package/src/op/operator.ts +290 -11
- package/src/op/runtime.ts +31 -8
- package/src/op/runtimes/local.ts +3 -1
- package/src/op/source-archive.ts +161 -0
- package/src/op/steward-points.test.ts +364 -0
- package/src/op/steward-points.ts +194 -0
- package/src/op/steward-turn.ts +79 -0
- package/src/op/steward.test.ts +87 -3
- package/src/op/steward.ts +25 -1
- package/src/op/types.ts +7 -0
- package/src/op/work-lease-run.test.ts +20 -1
- package/src/op/work-lease-run.ts +2 -2
- package/src/workspace/__fixtures__/decide-workspace.ts +129 -0
- package/src/workspace/__fixtures__/studio-template-84c8b21.json +67 -0
- package/src/workspace/answers-ledger.ts +118 -0
- package/src/workspace/box-intent.test.ts +205 -0
- package/src/workspace/box-intent.ts +159 -0
- package/src/workspace/changes-cli.ts +56 -0
- package/src/workspace/changes.schema.json +472 -0
- package/src/workspace/changes.test.ts +315 -0
- package/src/workspace/changes.ts +512 -0
- package/src/workspace/chant-migrations/chud-lexicon-exit-fly-site.ts +234 -0
- package/src/workspace/chant-migrations/chud-lexicon-exit-live-names.ts +164 -0
- package/src/workspace/chant-migrations/chud-lexicon-exit-rollback.ts +223 -0
- package/src/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.ts +195 -0
- package/src/workspace/chant-migrations/chud-lexicon-exit-ship-policy.ts +108 -0
- package/src/workspace/chant-migrations/chud-lexicon-exit.ts +882 -0
- package/src/workspace/chant-migrations.e2e.test.ts +1089 -0
- package/src/workspace/chant-migrations.ts +169 -0
- package/src/workspace/check-contract.test.ts +4 -2
- package/src/workspace/check.schema.json +19 -5
- package/src/workspace/checks/boxes.test.ts +82 -2
- package/src/workspace/checks/boxes.ts +202 -1
- package/src/workspace/checks/diagrams.test.ts +134 -0
- package/src/workspace/checks/diagrams.ts +108 -0
- package/src/workspace/checks/records.ts +47 -0
- package/src/workspace/checks.ts +20 -2
- package/src/workspace/compose-graph.ts +2 -0
- package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +10 -0
- package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +26 -0
- package/src/workspace/conformance/index.ts +5 -0
- package/src/workspace/decide.test.ts +1 -1
- package/src/workspace/decide.ts +156 -23
- package/src/workspace/decision-points.schema.json +3 -3
- package/src/workspace/declaration.schema.json +119 -1
- package/src/workspace/declaration.test.ts +58 -0
- package/src/workspace/declaration.ts +112 -0
- package/src/workspace/declared-kinds.test.ts +31 -5
- package/src/workspace/declared-kinds.ts +46 -1
- package/src/workspace/generated-files.ts +14 -0
- package/src/workspace/graph-cli.ts +1 -1
- package/src/workspace/graph.schema.json +9 -1
- package/src/workspace/intent-joins.test.ts +5 -5
- package/src/workspace/intent-joins.ts +5 -5
- package/src/workspace/intent.schema.json +8 -2
- package/src/workspace/intent.ts +3 -10
- package/src/workspace/lineage-check.ts +16 -1
- package/src/workspace/lineage-upgrade-cli.ts +1 -1
- package/src/workspace/lineage-upgrade.test.ts +70 -0
- package/src/workspace/lineage-upgrade.ts +81 -10
- package/src/workspace/ls-contract.test.ts +57 -0
- package/src/workspace/ls.schema.json +46 -1
- package/src/workspace/ls.ts +62 -3
- package/src/workspace/points-cli.ts +17 -3
- package/src/workspace/points-write.schema.json +11 -1
- package/src/workspace/points.schema.json +51 -0
- package/src/workspace/points.test.ts +16 -15
- package/src/workspace/points.ts +5 -17
- package/src/workspace/read-contract.test.ts +9 -1
- package/src/workspace/reason-codes.test.ts +18 -8
- package/src/workspace/reason-codes.ts +21 -2
- package/src/workspace/records-amend.schema.json +2 -0
- package/src/workspace/records-cli.ts +27 -4
- package/src/workspace/records-close.schema.json +2 -0
- package/src/workspace/records-formats.test.ts +15 -15
- package/src/workspace/records-new.schema.json +2 -0
- package/src/workspace/records-review.schema.json +2 -0
- package/src/workspace/records-sessions-write.e2e.test.ts +77 -0
- package/src/workspace/records-sessions-write.test.ts +2 -34
- package/src/workspace/records-since.test.ts +8 -7
- package/src/workspace/records-write.e2e.test.ts +108 -0
- package/src/workspace/records-write.test.ts +32 -41
- package/src/workspace/records-write.ts +33 -15
- package/src/workspace/records.schema.json +36 -2
- package/src/workspace/records.test.ts +49 -4
- package/src/workspace/records.ts +109 -3
- package/src/workspace/status-contract.test.ts +14 -8
- package/src/workspace/status-gates.ts +9 -4
- package/src/workspace/status-stewards.ts +155 -5
- package/src/workspace/status.schema.json +129 -8
- package/src/workspace/status.ts +46 -1
- package/src/workspace/work-acceptance.test.ts +274 -0
- package/src/workspace/{work-cli.test.ts → work-cli.e2e.test.ts} +1 -1
- package/src/workspace/work-cli.ts +193 -10
- package/src/workspace/work-evidence.schema.json +212 -0
- package/src/workspace/work-evidence.ts +169 -0
- package/src/workspace/work-history.schema.json +349 -0
- package/src/workspace/work-history.test.ts +156 -0
- package/src/workspace/{work-readiness-chud.test.ts → work-readiness.test.ts} +30 -32
- package/src/workspace/work.test.ts +20 -2
- package/src/workspace/work.ts +100 -1
- /package/src/cli/{discovery-skip.test.ts → discovery-skip.e2e.test.ts} +0 -0
- /package/src/workspace/conformance/{conformance.test.ts → conformance.e2e.test.ts} +0 -0
- /package/src/workspace/{which-chant.test.ts → which-chant.e2e.test.ts} +0 -0
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* is a thin call into the code the CLI runs:
|
|
7
7
|
*
|
|
8
8
|
* - The reads (`workspace-ls`, `workspace-status`, `workspace-graph`,
|
|
9
|
-
* `workspace-
|
|
9
|
+
* `workspace-changes`, `workspace-records`, `workspace-points`,
|
|
10
|
+
* `workspace-work-history`) run `chant workspace <command>
|
|
10
11
|
* ... --json` with the chant this server runs as, in the server's
|
|
11
12
|
* directory, and return the
|
|
12
13
|
* document it printed, unchanged, with its reason codes (#2536). Running the
|
|
@@ -52,7 +53,7 @@ export interface WorkspaceToolsOptions {
|
|
|
52
53
|
|
|
53
54
|
const PROTOCOL =
|
|
54
55
|
"Records are proposals until they are reviewed: a new record opens proposed, and people decide it through reviews and amendments. " +
|
|
55
|
-
"by must name the person or agent that actually decided, as it is recorded as given.";
|
|
56
|
+
"by must name the person or agent that actually proposed or decided it, as it is recorded as given.";
|
|
56
57
|
|
|
57
58
|
const kindProp = {
|
|
58
59
|
type: "string",
|
|
@@ -105,10 +106,29 @@ export const workspaceReadTools: ToolDefinition[] = [
|
|
|
105
106
|
},
|
|
106
107
|
},
|
|
107
108
|
},
|
|
109
|
+
{
|
|
110
|
+
name: "workspace-changes",
|
|
111
|
+
description:
|
|
112
|
+
"The forward coverage check over a diff: chant workspace check --changes <range> --json (changes.schema.json, #2773). Each changed path with the current records whose constrains cover it, and a change-uncovered or change-out-of-scope finding for each gap, at the severity the declaration's changes block sets. Returns the document unchanged.",
|
|
113
|
+
inputSchema: {
|
|
114
|
+
type: "object",
|
|
115
|
+
properties: {
|
|
116
|
+
range: { type: "string", description: "The diff: <base>..<head>, <base>...<head> (from their merge base), or <base> alone, to HEAD (--changes)." },
|
|
117
|
+
work: { type: "string", description: "The id of the work item in hand, whose out_of_scope and whose decisions' out_of_scope apply (--work)." },
|
|
118
|
+
severity: { type: "string", enum: ["off", "warn", "fail"], description: "In place of the declaration's changes.severity (--severity)." },
|
|
119
|
+
kind: {
|
|
120
|
+
type: "array",
|
|
121
|
+
items: { type: "string" },
|
|
122
|
+
description: "Record kind files to read in place of the declared ones (--kind).",
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
required: ["range"],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
108
128
|
{
|
|
109
129
|
name: "workspace-records",
|
|
110
130
|
description:
|
|
111
|
-
"The records of a kind, validated, with supersession, provenance, quorum and warnings: chant workspace records --json (records.schema.json). With since, what changed since a revision or a review session (records-since.schema.json). Returns the document unchanged; with id, only that record is kept in records. " +
|
|
131
|
+
"The records of a kind, validated, with supersession, remediation, provenance, quorum and warnings: chant workspace records --json (records.schema.json). With since, what changed since a revision or a review session (records-since.schema.json). Returns the document unchanged; with id, only that record is kept in records. " +
|
|
112
132
|
PROTOCOL,
|
|
113
133
|
inputSchema: {
|
|
114
134
|
type: "object",
|
|
@@ -134,6 +154,19 @@ export const workspaceReadTools: ToolDefinition[] = [
|
|
|
134
154
|
},
|
|
135
155
|
},
|
|
136
156
|
},
|
|
157
|
+
{
|
|
158
|
+
name: "workspace-work-history",
|
|
159
|
+
description:
|
|
160
|
+
"One work item's lease history, from the lifecycle ledger of the member that owns its work kind: chant workspace work history <item> --json (work-history.schema.json, #2785). Each claim has its fencing token and holder and how it ended: released with an outcome, still held, or never released (expired, or lost to a later claim). Returns the document unchanged.",
|
|
161
|
+
inputSchema: {
|
|
162
|
+
type: "object",
|
|
163
|
+
properties: {
|
|
164
|
+
item: { type: "string", description: "The work item's id." },
|
|
165
|
+
kind: { type: "string", description: "The work kind file, when more than one declared work kind has the id (--kind)." },
|
|
166
|
+
},
|
|
167
|
+
required: ["item"],
|
|
168
|
+
},
|
|
169
|
+
},
|
|
137
170
|
];
|
|
138
171
|
|
|
139
172
|
export const workspaceWriteTools: ToolDefinition[] = [
|
|
@@ -148,7 +181,11 @@ export const workspaceWriteTools: ToolDefinition[] = [
|
|
|
148
181
|
kind: kindProp,
|
|
149
182
|
record: { type: "object", description: "The record's fields, as the kind's schema describes them. The id is allocated when left out." },
|
|
150
183
|
prefix: { type: "string", description: "The id prefix to allocate under, when the records use several (--prefix)." },
|
|
151
|
-
by: {
|
|
184
|
+
by: {
|
|
185
|
+
type: "string",
|
|
186
|
+
description:
|
|
187
|
+
"Who proposed it: written to the kind's proposedBy field, such as proposed_by, since a record opens proposed. Written to its decider field, such as decided_by, only when the record's fields open it straight into a later state. Required to sign.",
|
|
188
|
+
},
|
|
152
189
|
sign: signProp,
|
|
153
190
|
dryRun: dryRunProp,
|
|
154
191
|
},
|
|
@@ -281,6 +318,27 @@ export function readArgv(tool: string, params: Record<string, unknown>): string[
|
|
|
281
318
|
if (intent !== undefined) return ["workspace", "graph", "--intent", intent, ...kindArgs, ...atArgs, "--json"];
|
|
282
319
|
return ["workspace", "graph", ...kindArgs, ...atArgs, "--json"];
|
|
283
320
|
}
|
|
321
|
+
case "workspace-changes": {
|
|
322
|
+
const range = str(params, "range", true)!;
|
|
323
|
+
const work = str(params, "work");
|
|
324
|
+
const severity = str(params, "severity");
|
|
325
|
+
if (severity !== undefined && !["off", "warn", "fail"].includes(severity)) throw new ToolInputError("severity must be off, warn or fail");
|
|
326
|
+
return [
|
|
327
|
+
"workspace",
|
|
328
|
+
"check",
|
|
329
|
+
"--changes",
|
|
330
|
+
range,
|
|
331
|
+
...(work !== undefined ? ["--work", work] : []),
|
|
332
|
+
...(severity !== undefined ? ["--severity", severity] : []),
|
|
333
|
+
...kinds(params).flatMap((k) => ["--kind", k]),
|
|
334
|
+
"--json",
|
|
335
|
+
];
|
|
336
|
+
}
|
|
337
|
+
case "workspace-work-history": {
|
|
338
|
+
const item = str(params, "item", true)!;
|
|
339
|
+
const kind = str(params, "kind");
|
|
340
|
+
return ["workspace", "work", "history", item, ...(kind !== undefined ? ["--kind", kind] : []), "--json"];
|
|
341
|
+
}
|
|
284
342
|
case "workspace-points": {
|
|
285
343
|
const kind = str(params, "kind");
|
|
286
344
|
return ["workspace", "points", ...(bool(params, "open") ? ["--open"] : []), ...(kind !== undefined ? ["--kind", kind] : []), ...atArgs, "--json"];
|
package/src/cli/plugins.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { importLexiconModule, lexiconModulePath, lexiconNames, registerLexiconDeclarations } from "../lexicon-module";
|
|
1
|
+
import { importLexiconModule, importLexiconPackage, lexiconModulePath, lexiconNames, registerLexiconDeclarations, resolveFromProject } from "../lexicon-module";
|
|
2
2
|
import { readLexiconDeclarationsStatically, type StaticLexiconRead } from "../config-static";
|
|
3
3
|
export { unknownPathLexiconsNotice } from "../config-static";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
@@ -51,7 +51,7 @@ export async function loadPlugin(lexiconName: string): Promise<LexiconPlugin> {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const packageName = `@intentius/chant-lexicon-${lexiconName}`;
|
|
54
|
-
const mod = await
|
|
54
|
+
const mod = (await importLexiconPackage(packageName)) as Record<string, any>;
|
|
55
55
|
|
|
56
56
|
// Look for an explicit LexiconPlugin export
|
|
57
57
|
for (const value of Object.values(mod)) {
|
|
@@ -109,7 +109,15 @@ export function resolveLexiconVersions(lexiconNames: readonly string[]): Record<
|
|
|
109
109
|
if (lexiconModulePath(name) !== undefined) continue;
|
|
110
110
|
const packageName = `@intentius/chant-lexicon-${name}`;
|
|
111
111
|
try {
|
|
112
|
-
|
|
112
|
+
// chant#2845 — a lexicon chant's own install can't reach is resolved from the project.
|
|
113
|
+
let entry: string | undefined;
|
|
114
|
+
try {
|
|
115
|
+
entry = require_.resolve(packageName);
|
|
116
|
+
} catch (err) {
|
|
117
|
+
entry = resolveFromProject(packageName);
|
|
118
|
+
if (entry === undefined) throw err;
|
|
119
|
+
}
|
|
120
|
+
let dir = dirname(entry);
|
|
113
121
|
// Bounded walk — a resolved entry point is never deeply nested inside
|
|
114
122
|
// its own package, and an unbounded loop here would climb to `/`.
|
|
115
123
|
for (let depth = 0; depth < 10; depth++) {
|
package/src/cli/registry.ts
CHANGED
|
@@ -303,13 +303,23 @@ export interface ParsedArgs {
|
|
|
303
303
|
composites?: boolean;
|
|
304
304
|
/** `chant workspace graph --intent <path[:start-end]>` (#2651): the region the intent graph is over. */
|
|
305
305
|
intent?: string;
|
|
306
|
+
/** `chant workspace check --changes <base>..<head>` (#2773): the diff the forward coverage check maps to records. */
|
|
307
|
+
changes?: string;
|
|
308
|
+
/** `chant workspace check --changes ... --severity off|warn|fail` (#2773): in place of the declaration's `changes.severity`. */
|
|
309
|
+
severity?: string;
|
|
306
310
|
/** `chant workspace records --current` (#2546): leave out records a closed record supersedes. */
|
|
307
311
|
current?: boolean;
|
|
308
312
|
/** `chant workspace records amend <id> --set <file|->` (#2670): the JSON fields to set. */
|
|
309
313
|
set?: string;
|
|
310
314
|
/** `chant workspace records review <id> --verdict <v>` (#2670): agree, dissent or abstain. */
|
|
311
315
|
verdict?: string;
|
|
312
|
-
/**
|
|
316
|
+
/**
|
|
317
|
+
* `chant workspace records review <id> --by <principal>` (#2670): the
|
|
318
|
+
* reviewer, as the caller names them. Also `chant workspace records new
|
|
319
|
+
* --by <name>` (#2756): the record's proposer, or its decider when it
|
|
320
|
+
* opens straight into a later state; see {@link ChannelOptions.by} in
|
|
321
|
+
* `records-write.ts`.
|
|
322
|
+
*/
|
|
313
323
|
by?: string;
|
|
314
324
|
/**
|
|
315
325
|
* `chant workspace records review <id> --sign [<key file>]` (#2687): the key that seals the verdict, or true for git's user.signingkey.
|
|
@@ -436,7 +446,7 @@ export interface ParsedArgs {
|
|
|
436
446
|
steward?: string;
|
|
437
447
|
/** `chant workspace work claim|renew|release <id> --holder <name>` (#2732): who holds, or releases, the work lease. */
|
|
438
448
|
holder?: string;
|
|
439
|
-
/** `chant run <op> --work <id>` (#2748): the work item an Op with a work lease runs under. */
|
|
449
|
+
/** `chant run <op> --work <id>` (#2748): the work item an Op with a work lease runs under. `chant workspace check --changes --work <id>` (#2773): the work item in hand. */
|
|
440
450
|
work?: string;
|
|
441
451
|
/** `chant workspace work claim|renew <id> --ttl <seconds|duration>` (#2732): how long the lease lasts unless renewed. */
|
|
442
452
|
ttl?: string;
|
|
@@ -73,8 +73,8 @@ describe("chant serve mcp at a workspace root with no lexicon of its own (#2700)
|
|
|
73
73
|
expect(init.instructions).toContain("Member delivery (delivery/) declares docker.");
|
|
74
74
|
}, TIMEOUT);
|
|
75
75
|
|
|
76
|
-
test("a
|
|
77
|
-
const root = join(scratch, "
|
|
76
|
+
test("a lexiconless root, lexicons only in a member, serves core and the lexicons that load", () => {
|
|
77
|
+
const root = join(scratch, "lexiconless-shaped");
|
|
78
78
|
mkdirSync(join(root, ".git"), { recursive: true });
|
|
79
79
|
mkdirSync(join(root, "delivery"), { recursive: true });
|
|
80
80
|
mkdirSync(join(root, "app"), { recursive: true });
|
|
@@ -87,9 +87,9 @@ describe("chant serve mcp at a workspace root with no lexicon of its own (#2700)
|
|
|
87
87
|
],
|
|
88
88
|
pins: [],
|
|
89
89
|
}));
|
|
90
|
-
// `
|
|
91
|
-
//
|
|
92
|
-
writeFileSync(join(root, "delivery", "chant.config.ts"), 'export default { lexicons: ["docker", "
|
|
90
|
+
// `acme` names a lexicon package that isn't installed here: it is named
|
|
91
|
+
// as not loaded and the rest is served.
|
|
92
|
+
writeFileSync(join(root, "delivery", "chant.config.ts"), 'export default { lexicons: ["docker", "acme"] };\n');
|
|
93
93
|
writeFileSync(join(root, "app", "server.js"), "// not chant\n");
|
|
94
94
|
|
|
95
95
|
const { status, stderr, init, tools } = initializeAndList(root);
|
|
@@ -97,7 +97,7 @@ describe("chant serve mcp at a workspace root with no lexicon of its own (#2700)
|
|
|
97
97
|
for (const name of CORE_TOOLS) expect(tools).toContain(name);
|
|
98
98
|
expect(tools).toContain("docker:diff");
|
|
99
99
|
expect(init.instructions).toContain('workspace "t"');
|
|
100
|
-
expect(init.instructions).toContain("Lexicon
|
|
100
|
+
expect(init.instructions).toContain("Lexicon acme did not load");
|
|
101
101
|
expect(init.instructions).toContain("Lexicon tools and resources served: docker.");
|
|
102
102
|
}, TIMEOUT);
|
|
103
103
|
|
|
@@ -26,6 +26,7 @@ import { join } from "path";
|
|
|
26
26
|
import { regenLexicon, type RegenResult } from "./lexicon-regen";
|
|
27
27
|
import { fetchWithRetry } from "./fetch";
|
|
28
28
|
import { isLexiconPlugin, type UpstreamPin } from "../lexicon";
|
|
29
|
+
import { importLexiconPackage } from "../lexicon-module";
|
|
29
30
|
|
|
30
31
|
// ── Public types ──────────────────────────────────────────────────────
|
|
31
32
|
|
|
@@ -200,7 +201,7 @@ export function revertVersionBump(filePath: string, original: string): void {
|
|
|
200
201
|
export async function loadUpstreamPin(lexicon: LexiconId): Promise<UpstreamPin | null> {
|
|
201
202
|
let mod: Record<string, unknown>;
|
|
202
203
|
try {
|
|
203
|
-
mod = (await
|
|
204
|
+
mod = (await importLexiconPackage(`@intentius/chant-lexicon-${lexicon}`)) as Record<string, unknown>;
|
|
204
205
|
} catch {
|
|
205
206
|
return null;
|
|
206
207
|
}
|
|
@@ -171,7 +171,54 @@ describe("release wiring: preflight gates both recipes (#1255)", () => {
|
|
|
171
171
|
}
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* #2816 — main's HEAD is rarely green, so a release tags the newest green
|
|
178
|
+
* commit on main (or the one named) and merges the bump back into main.
|
|
179
|
+
* scripts/release-preflight.test.ts runs the mechanics; this pins the wiring.
|
|
180
|
+
*/
|
|
181
|
+
describe("release wiring: release the newest green commit (#2816)", () => {
|
|
182
|
+
it("both recipes tag the commit the preflight chose, not HEAD", () => {
|
|
183
|
+
for (const recipe of ["release", "release-lexicon"]) {
|
|
184
|
+
const body = recipeBody(recipe);
|
|
185
|
+
expect(body).toMatch(/sha=\$\(bash scripts\/release-preflight\.sh/);
|
|
186
|
+
expect(body).toMatch(/release_open "\$sha"/);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("both recipes merge the tag back into main instead of pushing HEAD", () => {
|
|
191
|
+
for (const recipe of ["release", "release-lexicon"]) {
|
|
192
|
+
const body = recipeBody(recipe);
|
|
193
|
+
expect(body).toMatch(/release_ship "\$tag"/);
|
|
194
|
+
expect(body).not.toMatch(/git push/);
|
|
195
|
+
expect(body.indexOf("git tag")).toBeLessThan(body.indexOf("release_ship"));
|
|
196
|
+
}
|
|
197
|
+
const lib = readFileSync(join(repoRoot, "scripts", "release-lib.sh"), "utf-8");
|
|
198
|
+
// main and the tag land together or not at all, and nothing is forced.
|
|
199
|
+
expect(lib).toMatch(/git push --quiet --atomic origin "HEAD:refs\/heads\/main" "refs\/tags\/\$tag"/);
|
|
200
|
+
expect(lib).not.toMatch(/git push[^\n]*(--force|\s-f\b)/);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("both recipes offer a dry run that stops before committing", () => {
|
|
204
|
+
for (const recipe of ["release", "release-lexicon"]) {
|
|
205
|
+
const body = recipeBody(recipe);
|
|
206
|
+
expect(body.indexOf("RELEASE_DRY_RUN")).toBeGreaterThan(-1);
|
|
207
|
+
expect(body.indexOf("RELEASE_DRY_RUN")).toBeLessThan(body.indexOf("git commit"));
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("the whole-repo floor reads main as well as the green commit", () => {
|
|
212
|
+
expect(recipeBody("release")).toMatch(/release_version_at "\$RELEASE_MAIN"/);
|
|
213
|
+
expect(recipeBody("release-lexicon")).toMatch(/release_version_at "\$RELEASE_MAIN"/);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("a push to main does not cancel main's chant run; PR runs still cancel", () => {
|
|
217
|
+
const workflow = readFileSync(join(repoRoot, ".github", "workflows", "chant.yml"), "utf-8");
|
|
218
|
+
const block = workflow.match(/^concurrency:\n((?:[ ]+.*\n)+)/m)?.[1] ?? "";
|
|
219
|
+
// One group per commit on main, so a later push neither cancels a running
|
|
220
|
+
// run nor replaces a queued one.
|
|
221
|
+
expect(block).toMatch(/group:.*github\.ref == 'refs\/heads\/main' && github\.sha \|\| github\.ref/);
|
|
222
|
+
expect(block).toMatch(/cancel-in-progress: \$\{\{ github\.ref != 'refs\/heads\/main' \}\}/);
|
|
176
223
|
});
|
|
177
224
|
});
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { CapabilityRegistry } from "./capability";
|
|
25
|
-
import { lexiconModulePath } from "../lexicon-module";
|
|
25
|
+
import { lexiconModulePath, importLexiconPackage } from "../lexicon-module";
|
|
26
26
|
import type { CapabilityPlugin } from "./capability-plugin";
|
|
27
27
|
import { isCapabilityPlugin } from "./capability-plugin";
|
|
28
28
|
import { starterCapabilityPlugin } from "./starter-plugin";
|
|
@@ -62,7 +62,7 @@ export async function loadCapabilityPlugin(name: string): Promise<CapabilityPlug
|
|
|
62
62
|
const packageName = `@intentius/chant-capability-${name}`;
|
|
63
63
|
let mod: Record<string, unknown>;
|
|
64
64
|
try {
|
|
65
|
-
mod = (await
|
|
65
|
+
mod = (await importLexiconPackage(packageName)) as Record<string, unknown>;
|
|
66
66
|
} catch (err) {
|
|
67
67
|
throw new Error(
|
|
68
68
|
`capability plugin package "${packageName}" could not be loaded: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -118,7 +118,7 @@ export async function loadCapabilityPluginFromLexicon(name: string): Promise<Cap
|
|
|
118
118
|
const packageName = lexiconModulePath(name) ?? `@intentius/chant-lexicon-${name}`;
|
|
119
119
|
let mod: Record<string, unknown>;
|
|
120
120
|
try {
|
|
121
|
-
mod = (await
|
|
121
|
+
mod = (await importLexiconPackage(packageName)) as Record<string, unknown>;
|
|
122
122
|
} catch {
|
|
123
123
|
return null; // lexicon not installed / not resolvable here — nothing to contribute.
|
|
124
124
|
}
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* executor, the CLI entrypoint the driver (#556) never had.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import { lexiconModulePath, lexiconNames } from "../lexicon-module";
|
|
25
|
+
import { lexiconModulePath, lexiconNames, importLexiconPackage } from "../lexicon-module";
|
|
26
26
|
import { discoverComponents } from "./discover";
|
|
27
27
|
import type { BuildParamProvenance } from "../provenance";
|
|
28
28
|
import { inferArchetype, projectToJson, type Archetype } from "./component";
|
|
@@ -244,7 +244,7 @@ export interface GenerateComponentsResult {
|
|
|
244
244
|
async function loadLexiconPlugin(name: string): Promise<LexiconPlugin | null> {
|
|
245
245
|
let mod: Record<string, unknown>;
|
|
246
246
|
try {
|
|
247
|
-
mod = (await
|
|
247
|
+
mod = (await importLexiconPackage(lexiconModulePath(name) ?? `@intentius/chant-lexicon-${name}`)) as Record<string, unknown>;
|
|
248
248
|
} catch {
|
|
249
249
|
return null;
|
|
250
250
|
}
|
package/src/config.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { BuildParamProvenance } from "./provenance";
|
|
|
11
11
|
import { findProjectConfig } from "./project-root";
|
|
12
12
|
import { evaluateProjectConfig } from "./config-sandbox";
|
|
13
13
|
import { lexiconNames, pathLexiconRoot, registerLexiconDeclarations, type LexiconDeclaration } from "./lexicon-module";
|
|
14
|
+
import { decideConfigSchema, type DecideConfig } from "./op/decide-config";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* One project-declared environment (chant #1166). Historically always a bare
|
|
@@ -194,6 +195,7 @@ export const ChantConfigSchema = z.object({
|
|
|
194
195
|
knowledge: z.object({
|
|
195
196
|
dir: z.string().min(1).optional(),
|
|
196
197
|
}).optional(),
|
|
198
|
+
decide: decideConfigSchema.optional(),
|
|
197
199
|
exclude: z.array(z.string().min(1)).optional(),
|
|
198
200
|
include: z.array(z.string().min(1)).optional(),
|
|
199
201
|
rootOnly: z.boolean().optional(),
|
|
@@ -449,6 +451,15 @@ export interface ChantConfig {
|
|
|
449
451
|
dir?: string;
|
|
450
452
|
};
|
|
451
453
|
|
|
454
|
+
/**
|
|
455
|
+
* The backends the `decide` Op activity calls (#2828): backend name, as a
|
|
456
|
+
* decision point's model decider names it, to `{ url, key?, timeoutMs? }`.
|
|
457
|
+
* A key is `{ env }` or a brokered capability, never a literal (SYS001). A
|
|
458
|
+
* `decide` step's own `backends` take the place of these. See
|
|
459
|
+
* `./op/decide-config.ts`.
|
|
460
|
+
*/
|
|
461
|
+
decide?: DecideConfig;
|
|
462
|
+
|
|
452
463
|
/**
|
|
453
464
|
* Globs, relative to the directory holding this config, naming files that
|
|
454
465
|
* source discovery must skip (#2519): `build`, `lint`, `list`, `explain`
|
package/src/lexicon-module.ts
CHANGED
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
* a project that names lexicons by package takes exactly the path it always did.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
import {
|
|
27
|
+
import { createRequire } from "node:module";
|
|
28
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
29
|
+
import { pathToFileURL } from "node:url";
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* One `lexicons` entry: a package-backed name, or a name plus the module that
|
|
@@ -213,3 +215,56 @@ export function lexiconPackagesToInstall(
|
|
|
213
215
|
): string[] {
|
|
214
216
|
return names.filter((name) => !paths.has(name)).map((name) => `@intentius/chant-lexicon-${name}`);
|
|
215
217
|
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* chant#2845 — the npm package a bare specifier names: `@scope/name` for a
|
|
221
|
+
* scoped one, else its first segment. `undefined` for a relative or absolute
|
|
222
|
+
* path, which is not a package.
|
|
223
|
+
*/
|
|
224
|
+
export function packageNameOf(spec: string): string | undefined {
|
|
225
|
+
if (spec.startsWith(".") || isAbsolute(spec) || spec.startsWith("file:")) return undefined;
|
|
226
|
+
const parts = spec.split("/");
|
|
227
|
+
return spec.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** True when `err` says the package `pkg` itself could not be found, not something it imports. */
|
|
231
|
+
function isPackageNotFound(err: unknown, pkg: string): boolean {
|
|
232
|
+
const code = (err as { code?: unknown } | null)?.code;
|
|
233
|
+
if (code !== "ERR_MODULE_NOT_FOUND" && code !== "MODULE_NOT_FOUND") return false;
|
|
234
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
235
|
+
return message.includes(`'${pkg}'`) || message.includes(`"${pkg}"`) || message.includes(`${pkg}/`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* chant#2845 — resolve `spec` (a lexicon package or one of its subpaths) from
|
|
240
|
+
* `fromDir` instead of from chant's own install, or `undefined` when the
|
|
241
|
+
* project doesn't have it either.
|
|
242
|
+
*/
|
|
243
|
+
export function resolveFromProject(spec: string, fromDir: string = process.cwd()): string | undefined {
|
|
244
|
+
try {
|
|
245
|
+
return createRequire(join(fromDir, "package.json")).resolve(spec);
|
|
246
|
+
} catch {
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* chant#2845 — import a lexicon package, or one of its subpaths, by its bare
|
|
253
|
+
* specifier. chant's own install is tried first, as a bare `import()` always
|
|
254
|
+
* did, so a lexicon chant can reach loads exactly as before. When the package
|
|
255
|
+
* isn't there, which is the case for a chant installed globally and a project
|
|
256
|
+
* that installs its lexicons in its own node_modules, it is resolved from
|
|
257
|
+
* `fromDir` (the project) and imported from there. Any other failure, and a
|
|
258
|
+
* package the project doesn't have either, rethrows the first error.
|
|
259
|
+
*/
|
|
260
|
+
export async function importLexiconPackage(spec: string, fromDir: string = process.cwd()): Promise<Record<string, unknown>> {
|
|
261
|
+
try {
|
|
262
|
+
return (await import(spec)) as Record<string, unknown>;
|
|
263
|
+
} catch (err) {
|
|
264
|
+
const pkg = packageNameOf(spec);
|
|
265
|
+
if (pkg === undefined || !isPackageNotFound(err, pkg)) throw err;
|
|
266
|
+
const resolved = resolveFromProject(spec, fromDir);
|
|
267
|
+
if (resolved === undefined) throw err;
|
|
268
|
+
return (await import(pathToFileURL(resolved).href)) as Record<string, unknown>;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chant#2845 — a lexicon the project installs in its own node_modules loads
|
|
3
|
+
* when chant's own install can't reach it (a global chant): the plugin, its
|
|
4
|
+
* op activities and its activity contracts, resolved from the working
|
|
5
|
+
* directory after the bare import from chant's location fails.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, test, expect, beforeAll, afterAll } from "vitest";
|
|
8
|
+
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { importLexiconPackage, packageNameOf, resolveFromProject } from "./lexicon-module";
|
|
12
|
+
import { loadActivities } from "./op/activity-registry";
|
|
13
|
+
import { loadActivityContracts } from "./op/activity-contract-registry";
|
|
14
|
+
import { resolveLexiconVersions } from "./cli/plugins";
|
|
15
|
+
|
|
16
|
+
const NAME = "zz2845";
|
|
17
|
+
const PKG = `@intentius/chant-lexicon-${NAME}`;
|
|
18
|
+
let project: string;
|
|
19
|
+
|
|
20
|
+
beforeAll(async () => {
|
|
21
|
+
project = await mkdtemp(join(tmpdir(), "chant-2845-"));
|
|
22
|
+
const dir = join(project, "node_modules", "@intentius", `chant-lexicon-${NAME}`);
|
|
23
|
+
await mkdir(join(dir, "op"), { recursive: true });
|
|
24
|
+
await writeFile(
|
|
25
|
+
join(dir, "package.json"),
|
|
26
|
+
JSON.stringify({
|
|
27
|
+
name: PKG,
|
|
28
|
+
version: "9.9.9",
|
|
29
|
+
type: "module",
|
|
30
|
+
exports: { ".": { default: "./index.js" }, "./op/activities": { default: "./op/activities.js" }, "./op/activity-contracts": { default: "./op/contracts.js" } },
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
await writeFile(join(dir, "index.js"), "export const marker = 'plugin';\n");
|
|
34
|
+
await writeFile(join(dir, "op", "activities.js"), "export async function zz2845Probe() { return { ok: true }; }\n");
|
|
35
|
+
// A contract is branded with a global symbol, so a plain object built here is one.
|
|
36
|
+
await writeFile(
|
|
37
|
+
join(dir, "op", "contracts.js"),
|
|
38
|
+
"export const zz2845ProbeContract = { [Symbol.for('chant.op.activityContract')]: true, name: 'zz2845Probe', args: {}, returns: {} };\n",
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterAll(async () => {
|
|
43
|
+
await rm(project, { recursive: true, force: true });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("importLexiconPackage (#2845)", () => {
|
|
47
|
+
test("a package chant can't reach is imported from the project", async () => {
|
|
48
|
+
await expect(import(PKG)).rejects.toThrow();
|
|
49
|
+
const mod = await importLexiconPackage(PKG, project);
|
|
50
|
+
expect(mod.marker).toBe("plugin");
|
|
51
|
+
const op = await importLexiconPackage(`${PKG}/op/activities`, project);
|
|
52
|
+
expect(typeof op.zz2845Probe).toBe("function");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("a package chant reaches loads from chant's install, whatever the directory", async () => {
|
|
56
|
+
const mod = await importLexiconPackage("zod", project);
|
|
57
|
+
expect(typeof mod.z).toBe("object");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("a package neither has fails with the bare import's own error", async () => {
|
|
61
|
+
await expect(importLexiconPackage("@intentius/chant-lexicon-nope-2845", project)).rejects.toThrow(/chant-lexicon-nope-2845/);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("a path is not looked up in the project", () => {
|
|
65
|
+
expect(packageNameOf("/abs/lexicon.ts")).toBeUndefined();
|
|
66
|
+
expect(packageNameOf("./lexicon.ts")).toBeUndefined();
|
|
67
|
+
expect(packageNameOf(`${PKG}/op/activities`)).toBe(PKG);
|
|
68
|
+
expect(resolveFromProject(PKG, project)).toMatch(/index\.js$/);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("the loaders take the project's lexicon (#2845)", () => {
|
|
73
|
+
const inProject = async <T>(fn: () => Promise<T> | T): Promise<T> => {
|
|
74
|
+
const cwd = process.cwd();
|
|
75
|
+
process.chdir(project);
|
|
76
|
+
try {
|
|
77
|
+
return await fn();
|
|
78
|
+
} finally {
|
|
79
|
+
process.chdir(cwd);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
test("loadActivities finds its op activities", async () => {
|
|
84
|
+
const activities = await inProject(() => loadActivities([NAME]));
|
|
85
|
+
expect(activities.has("zz2845Probe")).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("loadActivityContracts finds its contracts", async () => {
|
|
89
|
+
const contracts = await inProject(() => loadActivityContracts([NAME]));
|
|
90
|
+
expect(contracts.has("zz2845Probe")).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("resolveLexiconVersions reads its version", async () => {
|
|
94
|
+
expect(await inProject(() => resolveLexiconVersions([NAME]))).toEqual({ [NAME]: "9.9.9" });
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -66,6 +66,12 @@ export interface ConvergeRuleOutcome {
|
|
|
66
66
|
action: "ran" | "reported" | "skipped-budget" | "skipped-flap" | "gated";
|
|
67
67
|
/** The dispatched Op name, for `action: "ran"` or `"gated"`. */
|
|
68
68
|
op?: string;
|
|
69
|
+
/**
|
|
70
|
+
* The resource the rule fired for, on a tick of a ConvergeOp with an
|
|
71
|
+
* observer step (#2778), which evaluates its rules once per resource. The
|
|
72
|
+
* dispatched Op reads it from `CHANT_CONVERGE_RESOURCE`.
|
|
73
|
+
*/
|
|
74
|
+
resource?: string;
|
|
69
75
|
/** The gate's signal name, for `action: "gated"`. */
|
|
70
76
|
gateName?: string;
|
|
71
77
|
/**
|
|
@@ -131,6 +137,14 @@ export function componentVerdicts(rows: readonly ComponentStatusRow[]): Converge
|
|
|
131
137
|
}));
|
|
132
138
|
}
|
|
133
139
|
|
|
140
|
+
/** One resource an observer step reported on a tick (#2778). */
|
|
141
|
+
export interface ConvergeResourceVerdict {
|
|
142
|
+
name: string;
|
|
143
|
+
status: "in-sync" | "drifted" | "unknown";
|
|
144
|
+
/** The observer's reason, capped to one line. */
|
|
145
|
+
detail?: string;
|
|
146
|
+
}
|
|
147
|
+
|
|
134
148
|
/** One immutable converge-tick record. */
|
|
135
149
|
export interface ConvergeTickRecord {
|
|
136
150
|
/** Schema version, so an incompatible future shape is detected before being misread. */
|
|
@@ -168,6 +182,12 @@ export interface ConvergeTickRecord {
|
|
|
168
182
|
* records written before #2027 have none; absent is not "no components".
|
|
169
183
|
*/
|
|
170
184
|
components?: ConvergeComponentVerdict[];
|
|
185
|
+
/**
|
|
186
|
+
* What a ConvergeOp's observer step reported this tick (#2778), one entry
|
|
187
|
+
* per resource: in its place of `components` for resources no lexicon
|
|
188
|
+
* observes. Absent on a tick observed through a lexicon environment.
|
|
189
|
+
*/
|
|
190
|
+
resources?: ConvergeResourceVerdict[];
|
|
171
191
|
/** Aggregate counts backing the tick's one log line. */
|
|
172
192
|
summary: {
|
|
173
193
|
drifted: number;
|
|
@@ -85,6 +85,8 @@ export function buildRunRecord(
|
|
|
85
85
|
status: OpRunRecord["status"];
|
|
86
86
|
id?: string;
|
|
87
87
|
gate?: OpRunRecord["gate"];
|
|
88
|
+
point?: OpRunRecord["point"];
|
|
89
|
+
steward?: string;
|
|
88
90
|
},
|
|
89
91
|
): OpRunRecordInput {
|
|
90
92
|
const phases: OpRunPhaseRecord[] = [];
|
|
@@ -106,6 +108,8 @@ export function buildRunRecord(
|
|
|
106
108
|
...(record.approval ? { approval: record.approval } : {}),
|
|
107
109
|
...(record.error !== undefined ? { error: record.error } : {}),
|
|
108
110
|
...(record.refusal !== undefined ? { refusal: record.refusal } : {}),
|
|
111
|
+
...(record.point ? { point: record.point } : {}),
|
|
112
|
+
...(record.gate ? { gate: record.gate } : {}),
|
|
109
113
|
});
|
|
110
114
|
if (record.outcome) outcomes[record.outcome.name] = record.outcome.value;
|
|
111
115
|
}
|
|
@@ -122,6 +126,8 @@ export function buildRunRecord(
|
|
|
122
126
|
outcomes,
|
|
123
127
|
phases,
|
|
124
128
|
...(times.gate ? { gate: times.gate } : {}),
|
|
129
|
+
...(times.point ? { point: times.point } : {}),
|
|
130
|
+
...(times.steward ? { steward: times.steward } : {}),
|
|
125
131
|
};
|
|
126
132
|
}
|
|
127
133
|
|