@intentius/chant 0.79.0 → 0.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +30 -0
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts +5 -0
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +13 -0
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/terraform-state.d.ts +13 -0
- package/dist/audit/terraform-state.d.ts.map +1 -1
- package/dist/cli/command-group.d.ts +6 -0
- package/dist/cli/command-group.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +44 -3
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +8 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/import-agents.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/update.d.ts +6 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/vendor.d.ts +5 -0
- package/dist/cli/commands/vendor.d.ts.map +1 -1
- package/dist/cli/conflict-check.d.ts +6 -0
- package/dist/cli/conflict-check.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/components.d.ts.map +1 -1
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/init.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 +7 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/promote.d.ts +20 -0
- package/dist/cli/handlers/promote.d.ts.map +1 -0
- package/dist/cli/handlers/run-generate.d.ts +39 -0
- package/dist/cli/handlers/run-generate.d.ts.map +1 -0
- package/dist/cli/handlers/run.d.ts +4 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/handlers/vendor.d.ts +8 -3
- package/dist/cli/handlers/vendor.d.ts.map +1 -1
- package/dist/cli/main.d.ts +12 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/plugins.d.ts +14 -0
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +46 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts +10 -0
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/cli-support.d.ts +3 -1
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/discover.d.ts.map +1 -1
- package/dist/components/driver.d.ts +16 -2
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out-support.d.ts.map +1 -1
- package/dist/components/gate-plan.d.ts +40 -0
- package/dist/components/gate-plan.d.ts.map +1 -0
- package/dist/components/pilots/alb-ecs.pilot.d.ts +7 -1
- package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -1
- package/dist/components/presets/ecs-fargate.d.ts +10 -4
- package/dist/components/presets/ecs-fargate.d.ts.map +1 -1
- package/dist/components/promote.d.ts +264 -0
- package/dist/components/promote.d.ts.map +1 -0
- package/dist/components/sandbox/driver.d.ts.map +1 -1
- package/dist/components/sandbox/run.d.ts.map +1 -1
- package/dist/components/verbs/build-archive.d.ts +22 -11
- package/dist/components/verbs/build-archive.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/config-static.d.ts +59 -0
- package/dist/config-static.d.ts.map +1 -0
- package/dist/config.d.ts +104 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/content-digest.d.ts +17 -0
- package/dist/content-digest.d.ts.map +1 -0
- package/dist/discovery/files.d.ts +48 -4
- package/dist/discovery/files.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +32 -1
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/discovery/sandbox/driver.d.ts +20 -0
- package/dist/discovery/sandbox/driver.d.ts.map +1 -1
- package/dist/discovery/sandbox/fork.d.ts +20 -0
- package/dist/discovery/sandbox/fork.d.ts.map +1 -1
- package/dist/discovery/walk.d.ts +119 -0
- package/dist/discovery/walk.d.ts.map +1 -0
- package/dist/graph-ir.d.ts +17 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/join-key.d.ts +31 -0
- package/dist/join-key.d.ts.map +1 -0
- package/dist/lexicon-module.d.ts +110 -0
- package/dist/lexicon-module.d.ts.map +1 -0
- package/dist/lexicon.d.ts +82 -1
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/build-ledger-store.d.ts.map +1 -1
- package/dist/lifecycle/digest.d.ts +5 -1
- package/dist/lifecycle/digest.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +20 -5
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +64 -0
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/lease.d.ts +8 -1
- package/dist/lifecycle/lease.d.ts.map +1 -1
- package/dist/lifecycle/legacy-digest.d.ts +59 -0
- package/dist/lifecycle/legacy-digest.d.ts.map +1 -0
- package/dist/lifecycle/member-ledger.d.ts +67 -0
- package/dist/lifecycle/member-ledger.d.ts.map +1 -0
- package/dist/lifecycle/plan-digest.d.ts +4 -3
- package/dist/lifecycle/plan-digest.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +42 -1
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/status.d.ts +90 -5
- package/dist/lifecycle/status.d.ts.map +1 -1
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +2 -3
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +32 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +2 -0
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/propose-upgrade.d.ts +75 -0
- package/dist/op/activities/propose-upgrade.d.ts.map +1 -0
- package/dist/op/activity-contract-registry.d.ts.map +1 -1
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-name.d.ts +7 -0
- package/dist/op/gate-name.d.ts.map +1 -1
- package/dist/op/gate-summary.d.ts +16 -0
- package/dist/op/gate-summary.d.ts.map +1 -1
- package/dist/op/gate.d.ts +16 -2
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/generate-pipeline.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/project-root.d.ts +26 -0
- package/dist/project-root.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.d.ts +37 -0
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -0
- package/dist/workspace/__fixtures__/two-member-workspace.d.ts +11 -0
- package/dist/workspace/__fixtures__/two-member-workspace.d.ts.map +1 -0
- package/dist/workspace/checks/generated.d.ts +156 -0
- package/dist/workspace/checks/generated.d.ts.map +1 -0
- package/dist/workspace/checks/ledgers.d.ts +78 -0
- package/dist/workspace/checks/ledgers.d.ts.map +1 -0
- package/dist/workspace/checks/links.d.ts +25 -0
- package/dist/workspace/checks/links.d.ts.map +1 -0
- package/dist/workspace/checks/pipelines.d.ts +76 -0
- package/dist/workspace/checks/pipelines.d.ts.map +1 -0
- package/dist/workspace/checks.d.ts +161 -0
- package/dist/workspace/checks.d.ts.map +1 -0
- package/dist/workspace/compose-graph.d.ts +115 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -0
- package/dist/workspace/compose-reports.d.ts +68 -0
- package/dist/workspace/compose-reports.d.ts.map +1 -0
- package/dist/workspace/declaration.d.ts +220 -0
- package/dist/workspace/declaration.d.ts.map +1 -0
- package/dist/workspace/declaration.schema.json +434 -0
- package/dist/workspace/generated-files.d.ts +65 -0
- package/dist/workspace/generated-files.d.ts.map +1 -0
- package/dist/workspace/glob.d.ts +13 -0
- package/dist/workspace/glob.d.ts.map +1 -0
- package/dist/workspace/graph-cli.d.ts +75 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -0
- package/dist/workspace/init.d.ts +96 -0
- package/dist/workspace/init.d.ts.map +1 -0
- package/dist/workspace/jsonc.d.ts +38 -0
- package/dist/workspace/jsonc.d.ts.map +1 -0
- package/dist/workspace/kinds.d.ts +192 -0
- package/dist/workspace/kinds.d.ts.map +1 -0
- package/dist/workspace/lineage-check.d.ts +84 -0
- package/dist/workspace/lineage-check.d.ts.map +1 -0
- package/dist/workspace/lineage-cli.d.ts +31 -0
- package/dist/workspace/lineage-cli.d.ts.map +1 -0
- package/dist/workspace/lineage-init.d.ts +101 -0
- package/dist/workspace/lineage-init.d.ts.map +1 -0
- package/dist/workspace/lineage-lock.d.ts +258 -0
- package/dist/workspace/lineage-lock.d.ts.map +1 -0
- package/dist/workspace/lineage-merge.d.ts +14 -0
- package/dist/workspace/lineage-merge.d.ts.map +1 -0
- package/dist/workspace/lineage-migrations.d.ts +178 -0
- package/dist/workspace/lineage-migrations.d.ts.map +1 -0
- package/dist/workspace/lineage-update.d.ts +59 -0
- package/dist/workspace/lineage-update.d.ts.map +1 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts +40 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -0
- package/dist/workspace/lineage-upgrade.d.ts +146 -0
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -0
- package/dist/workspace/lineage-vendor.d.ts +63 -0
- package/dist/workspace/lineage-vendor.d.ts.map +1 -0
- package/dist/workspace/lineage-version.d.ts +32 -0
- package/dist/workspace/lineage-version.d.ts.map +1 -0
- package/dist/workspace/links.d.ts +150 -0
- package/dist/workspace/links.d.ts.map +1 -0
- package/dist/workspace/ls.d.ts +99 -0
- package/dist/workspace/ls.d.ts.map +1 -0
- package/dist/workspace/member-commands.d.ts +139 -0
- package/dist/workspace/member-commands.d.ts.map +1 -0
- package/dist/workspace/member-handles.d.ts +54 -0
- package/dist/workspace/member-handles.d.ts.map +1 -0
- package/dist/workspace/member-pipeline.d.ts +143 -0
- package/dist/workspace/member-pipeline.d.ts.map +1 -0
- package/dist/workspace/member-run.d.ts +67 -0
- package/dist/workspace/member-run.d.ts.map +1 -0
- package/dist/workspace/reason-codes.d.ts +65 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -0
- package/dist/workspace/record-source.d.ts +22 -0
- package/dist/workspace/record-source.d.ts.map +1 -0
- package/dist/workspace/records-cli.d.ts +81 -0
- package/dist/workspace/records-cli.d.ts.map +1 -0
- package/dist/workspace/records.d.ts +118 -0
- package/dist/workspace/records.d.ts.map +1 -0
- package/dist/workspace/root-refusal.d.ts +53 -0
- package/dist/workspace/root-refusal.d.ts.map +1 -0
- package/dist/workspace/status.d.ts +150 -0
- package/dist/workspace/status.d.ts.map +1 -0
- package/dist/workspace/template-manifest.d.ts +90 -0
- package/dist/workspace/template-manifest.d.ts.map +1 -0
- package/dist/workspace/tree.d.ts +36 -0
- package/dist/workspace/tree.d.ts.map +1 -0
- package/dist/workspace/trust/attestor.d.ts +67 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -0
- package/dist/workspace/trust/policy.d.ts +111 -0
- package/dist/workspace/trust/policy.d.ts.map +1 -0
- package/dist/workspace/trust/provenance.d.ts +67 -0
- package/dist/workspace/trust/provenance.d.ts.map +1 -0
- package/dist/workspace/trust/ssh-commit.d.ts +43 -0
- package/dist/workspace/trust/ssh-commit.d.ts.map +1 -0
- package/dist/workspace/trust/test-repo.d.ts +42 -0
- package/dist/workspace/trust/test-repo.d.ts.map +1 -0
- package/dist/workspace/trust/verify-cli.d.ts +9 -0
- package/dist/workspace/trust/verify-cli.d.ts.map +1 -0
- package/dist/workspace/trust/verify.d.ts +66 -0
- package/dist/workspace/trust/verify.d.ts.map +1 -0
- package/dist/workspace/which-chant.d.ts +58 -0
- package/dist/workspace/which-chant.d.ts.map +1 -0
- package/dist/workspace/workspace-kinds.schema.json +133 -0
- package/package.json +4 -3
- package/src/audit/core.ts +13 -2
- package/src/audit/discover.ts +102 -36
- package/src/audit/report-html.ts +3 -1
- package/src/audit/report-model.ts +14 -1
- package/src/audit/terraform-state.test.ts +81 -1
- package/src/audit/terraform-state.ts +25 -0
- package/src/cli/command-group.ts +7 -0
- package/src/cli/commands/audit-truncation.test.ts +167 -0
- package/src/cli/commands/audit.ts +132 -29
- package/src/cli/commands/check-lexicon-examples.ts +2 -1
- package/src/cli/commands/check-lexicon.ts +24 -0
- package/src/cli/commands/doctor.test.ts +30 -0
- package/src/cli/commands/doctor.ts +21 -0
- package/src/cli/commands/import-agents.ts +15 -4
- package/src/cli/commands/init.ts +76 -25
- package/src/cli/commands/lint.test.ts +52 -1
- package/src/cli/commands/lint.ts +41 -71
- package/src/cli/commands/onboard.ts +15 -0
- package/src/cli/commands/update.ts +18 -5
- package/src/cli/commands/vendor.ts +11 -6
- package/src/cli/conflict-check.test.ts +18 -1
- package/src/cli/conflict-check.ts +13 -0
- package/src/cli/discovery-skip.test.ts +168 -0
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +38 -0
- package/src/cli/handlers/build-member.test.ts +127 -0
- package/src/cli/handlers/build.test.ts +11 -0
- package/src/cli/handlers/build.ts +35 -1
- package/src/cli/handlers/components.test.ts +127 -0
- package/src/cli/handlers/components.ts +70 -8
- package/src/cli/handlers/dev.ts +6 -1
- package/src/cli/handlers/fan-out.ts +9 -2
- package/src/cli/handlers/graph.test.ts +20 -0
- package/src/cli/handlers/graph.ts +4 -2
- package/src/cli/handlers/init.ts +54 -1
- package/src/cli/handlers/lifecycle.ts +2 -1
- package/src/cli/handlers/misc.ts +16 -0
- package/src/cli/handlers/operator.test.ts +68 -0
- package/src/cli/handlers/operator.ts +39 -10
- package/src/cli/handlers/promote.test.ts +377 -0
- package/src/cli/handlers/promote.ts +391 -0
- package/src/cli/handlers/run-generate-member.test.ts +83 -0
- package/src/cli/handlers/run-generate.test.ts +158 -0
- package/src/cli/handlers/run-generate.ts +168 -0
- package/src/cli/handlers/run.test.ts +47 -0
- package/src/cli/handlers/run.ts +41 -6
- package/src/cli/handlers/vendor.ts +147 -43
- package/src/cli/main.test.ts +137 -1
- package/src/cli/main.ts +290 -24
- package/src/cli/mcp/op-tools.ts +2 -1
- package/src/cli/path-lexicon-messages.test.ts +152 -0
- package/src/cli/plugins.ts +43 -5
- package/src/cli/registry.ts +46 -1
- package/src/cli/static-config-read.test.ts +208 -0
- package/src/codegen/fetch.test.ts +63 -1
- package/src/codegen/fetch.ts +30 -1
- package/src/components/__fixtures__/alb-ecs-service.json +0 -8
- package/src/components/capability-plugin-loader.ts +3 -1
- package/src/components/cli-support.ts +9 -3
- package/src/components/discover.test.ts +27 -57
- package/src/components/discover.ts +20 -51
- package/src/components/driver.test.ts +90 -12
- package/src/components/driver.ts +43 -5
- package/src/components/fan-out-support.ts +2 -1
- package/src/components/gate-plan.ts +53 -0
- package/src/components/pilots/README.md +1 -1
- package/src/components/pilots/alb-ecs.pilot.ts +7 -7
- package/src/components/presets/ecs-fargate.ts +10 -5
- package/src/components/promote.test.ts +645 -0
- package/src/components/promote.ts +641 -0
- package/src/components/sandbox/driver.ts +8 -8
- package/src/components/sandbox/run.ts +4 -1
- package/src/components/verbs/build-archive.ts +27 -21
- package/src/components/verbs/run-agent.ts +3 -5
- package/src/config-static.test.ts +136 -0
- package/src/config-static.ts +232 -0
- package/src/config.test.ts +40 -0
- package/src/config.ts +161 -11
- package/src/content-digest.test.ts +120 -0
- package/src/content-digest.ts +21 -0
- package/src/discovery/files.test.ts +127 -1
- package/src/discovery/files.ts +91 -59
- package/src/discovery/fold-import.ts +127 -9
- package/src/discovery/index.ts +1 -0
- package/src/discovery/sandbox/driver.ts +73 -35
- package/src/discovery/sandbox/fork-diagnostic.test.ts +136 -13
- package/src/discovery/sandbox/fork.ts +83 -43
- package/src/discovery/sandbox/path-lexicon-multifile.test.ts +285 -0
- package/src/discovery/sandbox/path-lexicon-parity.test.ts +162 -0
- package/src/discovery/walk.test.ts +263 -0
- package/src/discovery/walk.ts +334 -0
- package/src/effect-receipt.ts +2 -2
- package/src/graph-ir.ts +18 -1
- package/src/join-key.test.ts +25 -0
- package/src/join-key.ts +39 -0
- package/src/lexicon-module.test.ts +203 -0
- package/src/lexicon-module.ts +215 -0
- package/src/lexicon.ts +105 -1
- package/src/lifecycle/build-ledger-store.ts +13 -2
- package/src/lifecycle/digest.ts +9 -5
- package/src/lifecycle/gate-ledger.test.ts +20 -0
- package/src/lifecycle/gate-ledger.ts +28 -6
- package/src/lifecycle/git.test.ts +13 -1
- package/src/lifecycle/git.ts +221 -176
- package/src/lifecycle/lease.ts +25 -10
- package/src/lifecycle/legacy-digest.test.ts +206 -0
- package/src/lifecycle/legacy-digest.ts +103 -0
- package/src/lifecycle/member-ledger.test.ts +319 -0
- package/src/lifecycle/member-ledger.ts +145 -0
- package/src/lifecycle/plan-digest.ts +7 -7
- package/src/lifecycle/release-ledger.test.ts +20 -0
- package/src/lifecycle/release-ledger.ts +53 -3
- package/src/lifecycle/status.test.ts +151 -1
- package/src/lifecycle/status.ts +228 -7
- package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +2 -3
- package/src/op/activities/activity-contracts.ts +37 -0
- package/src/op/activities/index.ts +10 -0
- package/src/op/activities/propose-upgrade.ts +206 -0
- package/src/op/activity-contract-registry.ts +18 -4
- package/src/op/activity-registry.ts +26 -0
- package/src/op/discover.test.ts +14 -4
- package/src/op/discover.ts +19 -23
- package/src/op/gate-approval.ts +3 -1
- package/src/op/gate-name.ts +8 -0
- package/src/op/gate-summary.test.ts +14 -0
- package/src/op/gate-summary.ts +25 -2
- package/src/op/gate.ts +36 -7
- package/src/op/generate-pipeline.test.ts +14 -5
- package/src/op/generate-pipeline.ts +2 -1
- package/src/op/runtimes/local.ts +2 -1
- package/src/project-root.test.ts +66 -1
- package/src/project-root.ts +48 -0
- package/src/workspace/__fixtures__/contract-repo.ts +100 -0
- package/src/workspace/__fixtures__/two-member-workspace.ts +35 -0
- package/src/workspace/behold-kinds.test.ts +162 -0
- package/src/workspace/check-contract.test.ts +127 -0
- package/src/workspace/check.schema.json +347 -0
- package/src/workspace/checks/generated.test.ts +287 -0
- package/src/workspace/checks/generated.ts +475 -0
- package/src/workspace/checks/ledgers.test.ts +139 -0
- package/src/workspace/checks/ledgers.ts +246 -0
- package/src/workspace/checks/links.ts +183 -0
- package/src/workspace/checks/pipelines.test.ts +133 -0
- package/src/workspace/checks/pipelines.ts +225 -0
- package/src/workspace/checks-repo.test.ts +71 -0
- package/src/workspace/checks.test.ts +450 -0
- package/src/workspace/checks.ts +461 -0
- package/src/workspace/compose-graph.test.ts +146 -0
- package/src/workspace/compose-graph.ts +228 -0
- package/src/workspace/compose-reports.test.ts +109 -0
- package/src/workspace/compose-reports.ts +186 -0
- package/src/workspace/declaration.schema.json +434 -0
- package/src/workspace/declaration.test.ts +347 -0
- package/src/workspace/declaration.ts +623 -0
- package/src/workspace/generated-files.test.ts +114 -0
- package/src/workspace/generated-files.ts +94 -0
- package/src/workspace/glob.ts +49 -0
- package/src/workspace/graph-cli.ts +220 -0
- package/src/workspace/graph-contract.test.ts +204 -0
- package/src/workspace/graph.schema.json +662 -0
- package/src/workspace/init.test.ts +223 -0
- package/src/workspace/init.ts +585 -0
- package/src/workspace/jsonc.test.ts +65 -0
- package/src/workspace/jsonc.ts +231 -0
- package/src/workspace/kinds.test.ts +288 -0
- package/src/workspace/kinds.ts +506 -0
- package/src/workspace/lineage-check.ts +264 -0
- package/src/workspace/lineage-cli.ts +114 -0
- package/src/workspace/lineage-init.test.ts +231 -0
- package/src/workspace/lineage-init.ts +365 -0
- package/src/workspace/lineage-lock.test.ts +224 -0
- package/src/workspace/lineage-lock.ts +357 -0
- package/src/workspace/lineage-merge.ts +44 -0
- package/src/workspace/lineage-migrations.test.ts +178 -0
- package/src/workspace/lineage-migrations.ts +343 -0
- package/src/workspace/lineage-update.ts +160 -0
- package/src/workspace/lineage-upgrade-cli.ts +151 -0
- package/src/workspace/lineage-upgrade.test.ts +474 -0
- package/src/workspace/lineage-upgrade.ts +624 -0
- package/src/workspace/lineage-vendor.test.ts +126 -0
- package/src/workspace/lineage-vendor.ts +215 -0
- package/src/workspace/lineage-version.ts +127 -0
- package/src/workspace/links.test.ts +344 -0
- package/src/workspace/links.ts +331 -0
- package/src/workspace/ls-contract.test.ts +200 -0
- package/src/workspace/ls.schema.json +190 -0
- package/src/workspace/ls.ts +254 -0
- package/src/workspace/member-commands.e2e.test.ts +244 -0
- package/src/workspace/member-commands.test.ts +217 -0
- package/src/workspace/member-commands.ts +540 -0
- package/src/workspace/member-handles.test.ts +76 -0
- package/src/workspace/member-handles.ts +228 -0
- package/src/workspace/member-pipeline.test.ts +135 -0
- package/src/workspace/member-pipeline.ts +317 -0
- package/src/workspace/member-run.ts +146 -0
- package/src/workspace/read-contract.test.ts +129 -0
- package/src/workspace/reason-codes.test.ts +113 -0
- package/src/workspace/reason-codes.ts +81 -0
- package/src/workspace/record-source.ts +117 -0
- package/src/workspace/records-cli.ts +198 -0
- package/src/workspace/records-contract.test.ts +93 -0
- package/src/workspace/records.schema.json +150 -0
- package/src/workspace/records.test.ts +243 -0
- package/src/workspace/records.ts +384 -0
- package/src/workspace/root-refusal.ts +97 -0
- package/src/workspace/status-contract.test.ts +308 -0
- package/src/workspace/status.schema.json +210 -0
- package/src/workspace/status.ts +412 -0
- package/src/workspace/template-manifest.test.ts +79 -0
- package/src/workspace/template-manifest.ts +221 -0
- package/src/workspace/tree.ts +132 -0
- package/src/workspace/trust/attestor.ts +93 -0
- package/src/workspace/trust/policy.ts +306 -0
- package/src/workspace/trust/provenance.ts +181 -0
- package/src/workspace/trust/ssh-commit.ts +138 -0
- package/src/workspace/trust/test-repo.ts +138 -0
- package/src/workspace/trust/trust.test.ts +397 -0
- package/src/workspace/trust/verify-cli.ts +56 -0
- package/src/workspace/trust/verify.ts +194 -0
- package/src/workspace/which-chant.test.ts +117 -0
- package/src/workspace/which-chant.ts +151 -0
- package/src/workspace/workspace-kinds.schema.json +133 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
1
|
+
import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
2
|
import { lintCommand, isLintRule, loadPluginRules, LEXICON_RESOLUTION_RULE_ID, type LintOptions } from "./lint";
|
|
3
3
|
import { loadPlugins, resolveProjectLexicons } from "../plugins";
|
|
4
4
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
@@ -641,6 +641,57 @@ describe("lintCommand — git-ignored files are not linted", () => {
|
|
|
641
641
|
});
|
|
642
642
|
});
|
|
643
643
|
|
|
644
|
+
/**
|
|
645
|
+
* chant#2527: lint walks through the one discovery walk. A child project
|
|
646
|
+
* inside a project is a boundary, `include` re-admits it, and a scan root
|
|
647
|
+
* that is itself git-ignored is linted.
|
|
648
|
+
*/
|
|
649
|
+
describe("lintCommand — the converged discovery walk (#2527)", () => {
|
|
650
|
+
let testDir: string;
|
|
651
|
+
const EVL003 = `const t = { a: 1 };\nexport function g(k: string) { return t[k]; }\n`;
|
|
652
|
+
|
|
653
|
+
beforeEach(async () => {
|
|
654
|
+
testDir = join(tmpdir(), `chant-lint-2527-${Date.now()}-${Math.random()}`);
|
|
655
|
+
await mkdir(testDir, { recursive: true });
|
|
656
|
+
process.env.NO_COLOR = "1";
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
afterEach(async () => {
|
|
660
|
+
await rm(testDir, { recursive: true, force: true });
|
|
661
|
+
delete process.env.NO_COLOR;
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
async function childProject(config: Record<string, unknown>): Promise<void> {
|
|
665
|
+
await writeFile(join(testDir, "chant.config.json"), JSON.stringify({ knowledge: { dir: "knowledge" }, ...config }));
|
|
666
|
+
await writeFile(join(testDir, "index.ts"), `export const x = 1;\n`);
|
|
667
|
+
await mkdir(join(testDir, "stacks", "east"), { recursive: true });
|
|
668
|
+
await writeFile(join(testDir, "stacks", "east", "chant.config.ts"), `export default {};\n`);
|
|
669
|
+
await writeFile(join(testDir, "stacks", "east", "east.ts"), EVL003);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
test("a nested child project is not linted from the parent", async () => {
|
|
673
|
+
await childProject({});
|
|
674
|
+
const result = await lintCommand({ path: testDir, format: "stylish" });
|
|
675
|
+
expect(result.diagnostics.some((d) => d.file.includes("east.ts"))).toBe(false);
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
test("include re-admits the child project", async () => {
|
|
679
|
+
await childProject({ include: ["stacks/east"] });
|
|
680
|
+
const result = await lintCommand({ path: testDir, format: "stylish" });
|
|
681
|
+
expect(result.diagnostics.some((d) => d.file.includes("east.ts") && d.ruleId === "EVL003")).toBe(true);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
test("an ignored scan root is linted: ignore rules apply below the root only", async () => {
|
|
685
|
+
execFileSync("git", ["init", "-q"], { cwd: testDir });
|
|
686
|
+
await writeFile(join(testDir, ".gitignore"), "/carveout/\n");
|
|
687
|
+
await mkdir(join(testDir, "carveout", "src"), { recursive: true });
|
|
688
|
+
await writeFile(join(testDir, "carveout", "src", "main.ts"), EVL003);
|
|
689
|
+
|
|
690
|
+
const result = await lintCommand({ path: join(testDir, "carveout", "src"), format: "stylish" });
|
|
691
|
+
expect(result.diagnostics.some((d) => d.file.includes("main.ts") && d.ruleId === "EVL003")).toBe(true);
|
|
692
|
+
});
|
|
693
|
+
});
|
|
694
|
+
|
|
644
695
|
/**
|
|
645
696
|
* chant #2222 (epic #2215 sub-issue 7) — `chant lint` used to print "No
|
|
646
697
|
* problems found" and exit 0 on a project whose declared lexicon could not be
|
package/src/cli/commands/lint.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { resolve, join, relative } from "path";
|
|
2
2
|
import type { BuildParamProvenance } from "../../provenance";
|
|
3
|
-
import { readFileSync, writeFileSync, readdirSync
|
|
4
|
-
import { execFileSync } from "child_process";
|
|
3
|
+
import { readFileSync, writeFileSync, readdirSync } from "fs";
|
|
5
4
|
import { runLint, parseDisableComments } from "../../lint/engine";
|
|
6
5
|
import type { LintRule, LintDiagnostic, LintFix } from "../../lint/rule";
|
|
7
6
|
import type { IntrinsicDef, LexiconPlugin } from "../../lexicon";
|
|
@@ -19,14 +18,15 @@ import { runPostSynthChecks } from "../../lint/post-synth";
|
|
|
19
18
|
import { rule } from "../../lint/declarative";
|
|
20
19
|
import { watchDirectory, formatTimestamp, formatChangedFiles } from "../watch";
|
|
21
20
|
import { formatError, formatInfo } from "../format";
|
|
22
|
-
import {
|
|
21
|
+
import { hasDiscoveryMarkerSync, isSourceFileName } from "../../discovery/files";
|
|
22
|
+
import { walkDiscovery, workspaceMemberDirs } from "../../discovery/walk";
|
|
23
23
|
import { buildParamValues, resolveBuildParams } from "../../build-params";
|
|
24
24
|
import { setBuildParams } from "../../params";
|
|
25
25
|
import { isNoLexiconDetected } from "../../detectLexicon";
|
|
26
26
|
|
|
27
27
|
// Import config loader
|
|
28
28
|
import { loadConfig, resolveRulesForFile, resolveConfiguredSeverity, findProjectRoot } from "../../lint/config";
|
|
29
|
-
import { loadChantConfig, resolveKnowledgeDir } from "../../config";
|
|
29
|
+
import { loadChantConfig, resolveKnowledgeDir, resolveDiscoveryGlobs } from "../../config";
|
|
30
30
|
import { findProjectConfig } from "../../project-root";
|
|
31
31
|
import type { LintProjectConfig } from "../../lint/rule";
|
|
32
32
|
import { loadOkfBundle, type OkfBundle } from "../../okf-read";
|
|
@@ -141,7 +141,7 @@ function lexiconResolutionDiagnostic(projectRoot: string, error: Error): LintDia
|
|
|
141
141
|
*/
|
|
142
142
|
async function loadAllPluginRules(
|
|
143
143
|
projectPath: string,
|
|
144
|
-
): Promise<{ rules: Map<string, LintRule>; intrinsics: IntrinsicDef[]; lexiconError?: Error }> {
|
|
144
|
+
): Promise<{ rules: Map<string, LintRule>; intrinsics: IntrinsicDef[]; plugins: LexiconPlugin[]; lexiconError?: Error }> {
|
|
145
145
|
const rules = new Map<string, LintRule>();
|
|
146
146
|
|
|
147
147
|
// Load core COR/EVL rules directly
|
|
@@ -219,7 +219,7 @@ async function loadAllPluginRules(
|
|
|
219
219
|
rules.set(r.id, r);
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
return { rules, intrinsics, ...(lexiconError ? { lexiconError } : {}) };
|
|
222
|
+
return { rules, intrinsics, plugins, ...(lexiconError ? { lexiconError } : {}) };
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
/**
|
|
@@ -269,64 +269,26 @@ export interface LintResult {
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
/**
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
272
|
+
* Every TypeScript file `chant lint` reads under `dir`, through the one
|
|
273
|
+
* discovery walk (`../../discovery/walk.ts`, #2527): git-ignored paths
|
|
274
|
+
* (vendored trees and the like, which the project never wrote), dot-directories,
|
|
275
|
+
* `dist` and, inside a project, child projects are skipped, and so is what the
|
|
276
|
+
* project's `exclude` globs (#2519) name, unless `include` re-admits it. Test
|
|
277
|
+
* and spec files, chant-generated files and skip-marked files are left out.
|
|
278
|
+
* Symlinks are followed, as lint always did.
|
|
278
279
|
*/
|
|
279
|
-
function
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
});
|
|
292
|
-
const ignored = new Set(out.split(/\r?\n/).filter(Boolean));
|
|
293
|
-
return ignored.size === 0 ? files : files.filter((f) => !ignored.has(f));
|
|
294
|
-
} catch {
|
|
295
|
-
// No git, not a repo, or nothing ignored (exit 1) — keep every file.
|
|
296
|
-
return files;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Get all TypeScript files recursively, skipping git-ignored paths.
|
|
302
|
-
*/
|
|
303
|
-
function getTypeScriptFiles(dir: string): string[] {
|
|
304
|
-
const files: string[] = [];
|
|
305
|
-
|
|
306
|
-
function scan(currentDir: string): void {
|
|
307
|
-
const entries = readdirSync(currentDir);
|
|
308
|
-
|
|
309
|
-
for (const entry of entries) {
|
|
310
|
-
const fullPath = join(currentDir, entry);
|
|
311
|
-
const stat = statSync(fullPath);
|
|
312
|
-
|
|
313
|
-
if (stat.isDirectory()) {
|
|
314
|
-
if (entry !== "node_modules" && !entry.startsWith(".")) {
|
|
315
|
-
scan(fullPath);
|
|
316
|
-
}
|
|
317
|
-
} else if (entry.endsWith(".ts") && !entry.endsWith(".test.ts") && !entry.endsWith(".spec.ts")) {
|
|
318
|
-
// Skip chant-generated files (worker/workflow/activities bootstrap): they
|
|
319
|
-
// hold no authored source and use runtime patterns the EVL* rules forbid.
|
|
320
|
-
if (readFileSync(fullPath, "utf-8").slice(0, 256).includes(GENERATED_MARKER)) {
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
files.push(fullPath);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
scan(dir);
|
|
329
|
-
return filterGitIgnored(files, dir);
|
|
280
|
+
async function getTypeScriptFiles(dir: string): Promise<string[]> {
|
|
281
|
+
// A missing or non-directory path fails here, as lint's own walk always did;
|
|
282
|
+
// the shared walk skips an unreadable directory in silence.
|
|
283
|
+
readdirSync(dir);
|
|
284
|
+
return walkDiscovery({
|
|
285
|
+
walker: "lint",
|
|
286
|
+
root: dir,
|
|
287
|
+
globs: await resolveDiscoveryGlobs(dir),
|
|
288
|
+
excludeDirs: await workspaceMemberDirs(dir),
|
|
289
|
+
followSymlinks: true,
|
|
290
|
+
accept: (name, full) => isSourceFileName(name) && !hasDiscoveryMarkerSync(full),
|
|
291
|
+
});
|
|
330
292
|
}
|
|
331
293
|
|
|
332
294
|
/**
|
|
@@ -522,8 +484,10 @@ async function runComponentCheckDiagnostics(
|
|
|
522
484
|
*
|
|
523
485
|
* The project's configured lexicon NAMES are read, though (chant #2101), to
|
|
524
486
|
* resolve the activity contracts each one declares at
|
|
525
|
-
* `@intentius/chant-lexicon-<name>/op/activity-contracts
|
|
526
|
-
*
|
|
487
|
+
* `@intentius/chant-lexicon-<name>/op/activity-contracts`. The plugins
|
|
488
|
+
* `lintCommand` already loaded are passed in (chant #2520), so a plugin's
|
|
489
|
+
* `activityContracts()` member counts here as it does in `chant build`, and
|
|
490
|
+
* a lexicon declared by module path is covered. Without them a step calling a
|
|
527
491
|
* lexicon's activity is flagged for the absence of a contract that lexicon
|
|
528
492
|
* does declare, which is the whole point of OPS013 firing outside a build.
|
|
529
493
|
*
|
|
@@ -538,6 +502,7 @@ async function runOpCheckDiagnostics(
|
|
|
538
502
|
infraPath: string,
|
|
539
503
|
files: string[],
|
|
540
504
|
buildParams?: BuildParamProvenance[],
|
|
505
|
+
plugins: readonly LexiconPlugin[] = [],
|
|
541
506
|
): Promise<{ diagnostics: LintDiagnostic[]; suppressed: Array<LintDiagnostic & { reason?: string }> }> {
|
|
542
507
|
const config = loadConfig(findProjectRoot(infraPath));
|
|
543
508
|
const opFiles = files.filter((f) => f.endsWith(".op.ts"));
|
|
@@ -573,8 +538,13 @@ async function runOpCheckDiagnostics(
|
|
|
573
538
|
|
|
574
539
|
if (entities.size === 0) return { diagnostics: [], suppressed: [] };
|
|
575
540
|
|
|
576
|
-
|
|
577
|
-
|
|
541
|
+
// chant #2520 — hand over the loaded plugin objects when there are any, as
|
|
542
|
+
// `chant build` does, so a plugin's `activityContracts()` member is read
|
|
543
|
+
// here too. Names alone are the fallback when no plugin loaded.
|
|
544
|
+
const activityContracts =
|
|
545
|
+
plugins.length > 0
|
|
546
|
+
? await loadActivityContracts(plugins)
|
|
547
|
+
: await loadActivityContracts(await resolveProjectLexicons(infraPath).catch(() => [] as string[]));
|
|
578
548
|
|
|
579
549
|
const raw = runPostSynthChecks(
|
|
580
550
|
coreOpChecks(),
|
|
@@ -698,8 +668,8 @@ export async function lintCommand(options: LintOptions): Promise<LintResult> {
|
|
|
698
668
|
allRules = new Map([...allRules, ...pluginRules]);
|
|
699
669
|
}
|
|
700
670
|
|
|
701
|
-
// Get all TypeScript files
|
|
702
|
-
const files = getTypeScriptFiles(infraPath);
|
|
671
|
+
// Get all TypeScript files, through the one discovery walk (#2527)
|
|
672
|
+
const files = await getTypeScriptFiles(infraPath);
|
|
703
673
|
|
|
704
674
|
// Run lint — use per-file rules when overrides are present
|
|
705
675
|
let diagnostics: LintDiagnostic[];
|
|
@@ -736,7 +706,7 @@ export async function lintCommand(options: LintOptions): Promise<LintResult> {
|
|
|
736
706
|
// Run the OPS* Op-model post-synth checks (#2122) over every `*.op.ts`
|
|
737
707
|
// file under the lint target — see runOpCheckDiagnostics's doc for why
|
|
738
708
|
// this needs no lexicon or build to fire.
|
|
739
|
-
const opResult = await runOpCheckDiagnostics(infraPath, files, buildParams);
|
|
709
|
+
const opResult = await runOpCheckDiagnostics(infraPath, files, buildParams, loaded.plugins);
|
|
740
710
|
diagnostics.push(...opResult.diagnostics);
|
|
741
711
|
suppressed.push(...opResult.suppressed);
|
|
742
712
|
|
|
@@ -790,7 +760,7 @@ export async function lintCommand(options: LintOptions): Promise<LintResult> {
|
|
|
790
760
|
|
|
791
761
|
// OPS* checks have no `.fix` either; re-run for the same consistency
|
|
792
762
|
// reason as the COMP* re-run just above.
|
|
793
|
-
const postOpResult = await runOpCheckDiagnostics(infraPath, files, buildParams);
|
|
763
|
+
const postOpResult = await runOpCheckDiagnostics(infraPath, files, buildParams, loaded.plugins);
|
|
794
764
|
diagnostics.push(...postOpResult.diagnostics);
|
|
795
765
|
suppressed.push(...postOpResult.suppressed);
|
|
796
766
|
}
|
|
@@ -2,6 +2,7 @@ import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
|
2
2
|
import { join, dirname } from "path";
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
4
|
import { formatSuccess, formatError, formatWarning } from "../format";
|
|
5
|
+
import { lexiconModulePath, lexiconSourceLabel } from "../../lexicon-module";
|
|
5
6
|
|
|
6
7
|
export interface OnboardOptions {
|
|
7
8
|
name: string;
|
|
@@ -331,6 +332,20 @@ export function patchDockerfile(filePath: string, name: string): PatchResult {
|
|
|
331
332
|
* Execute the onboard command — patches monorepo infrastructure for a new lexicon.
|
|
332
333
|
*/
|
|
333
334
|
export function onboardCommand(options: OnboardOptions): OnboardResult {
|
|
335
|
+
// chant#2578 — onboard wires a lexicon package into the chant monorepo. A
|
|
336
|
+
// lexicon declared by path has no package, so there is nothing to wire and
|
|
337
|
+
// no install step to print; say where it loads from instead.
|
|
338
|
+
if (lexiconModulePath(options.name) !== undefined) {
|
|
339
|
+
return {
|
|
340
|
+
success: false,
|
|
341
|
+
patched: [],
|
|
342
|
+
skipped: [],
|
|
343
|
+
error:
|
|
344
|
+
`lexicon "${options.name}" is declared by path in chant.config.ts and loads from ${lexiconSourceLabel(options.name)}. ` +
|
|
345
|
+
"onboard adds a lexicon package to the chant monorepo, and a lexicon loaded by path has no package to add.",
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
334
349
|
const root = options.root ?? findRepoRoot();
|
|
335
350
|
const patched: string[] = [];
|
|
336
351
|
const skipped: string[] = [];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { lexiconModulePath, lexiconNames } from "../../lexicon-module";
|
|
1
2
|
import { existsSync, mkdirSync, writeFileSync, cpSync, readdirSync, statSync, readFileSync } from "fs";
|
|
2
|
-
import { join, resolve } from "path";
|
|
3
|
+
import { dirname, join, resolve } from "path";
|
|
3
4
|
import { createRequire } from "module";
|
|
4
5
|
import { formatSuccess, formatWarning, formatError } from "../format";
|
|
5
6
|
import { loadChantConfig } from "../../config";
|
|
@@ -28,6 +29,15 @@ export interface UpdateResult {
|
|
|
28
29
|
error?: string;
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Where `chant update` writes a lexicon skill, relative to the project. The
|
|
34
|
+
* workspace drift check (#2541) compares these files with what the skills
|
|
35
|
+
* render to, so both read the path from here.
|
|
36
|
+
*/
|
|
37
|
+
export function skillFilePath(skillName: string): string {
|
|
38
|
+
return `skills/${skillName}/SKILL.md`;
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
/**
|
|
32
42
|
* Copy directory contents recursively, filtering to .ts and .d.ts files
|
|
33
43
|
*/
|
|
@@ -105,7 +115,7 @@ export async function updateCommand(options: UpdateOptions): Promise<UpdateResul
|
|
|
105
115
|
|
|
106
116
|
// Load config to get lexicons
|
|
107
117
|
const { config } = await loadChantConfig(projectDir);
|
|
108
|
-
const lexicons = config.lexicons ?? [];
|
|
118
|
+
const lexicons = lexiconNames(config.lexicons ?? []);
|
|
109
119
|
|
|
110
120
|
if (lexicons.length === 0) {
|
|
111
121
|
return {
|
|
@@ -137,6 +147,9 @@ export async function updateCommand(options: UpdateOptions): Promise<UpdateResul
|
|
|
137
147
|
|
|
138
148
|
// Sync each lexicon
|
|
139
149
|
for (const lexicon of lexicons) {
|
|
150
|
+
// chant #2520 — a lexicon declared by module path is project source, with
|
|
151
|
+
// no package to copy types from.
|
|
152
|
+
if (lexiconModulePath(lexicon) !== undefined) continue;
|
|
140
153
|
const pkgName = `@intentius/chant-lexicon-${lexicon}`;
|
|
141
154
|
const pkgPath = resolvePackagePath(pkgName, projectDir);
|
|
142
155
|
|
|
@@ -166,9 +179,9 @@ export async function updateCommand(options: UpdateOptions): Promise<UpdateResul
|
|
|
166
179
|
const skills = plugin.skills();
|
|
167
180
|
if (skills.length > 0) {
|
|
168
181
|
for (const skill of skills) {
|
|
169
|
-
const
|
|
170
|
-
mkdirSync(
|
|
171
|
-
writeFileSync(
|
|
182
|
+
const file = join(projectDir, skillFilePath(skill.name));
|
|
183
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
184
|
+
writeFileSync(file, skill.content);
|
|
172
185
|
}
|
|
173
186
|
synced.push(`${plugin.name} skills (${skills.length})`);
|
|
174
187
|
}
|
|
@@ -76,7 +76,7 @@ export function contentHash(files: Map<string, Buffer>): string {
|
|
|
76
76
|
// ── Source resolution → a { relpath → bytes } file set ──────────────────────
|
|
77
77
|
|
|
78
78
|
/** Walk a local directory into a relpath→bytes map (or a single file). */
|
|
79
|
-
function readLocal(absPath: string): Map<string, Buffer> {
|
|
79
|
+
export function readLocal(absPath: string): Map<string, Buffer> {
|
|
80
80
|
const files = new Map<string, Buffer>();
|
|
81
81
|
const stat = statSync(absPath);
|
|
82
82
|
if (stat.isFile()) {
|
|
@@ -135,12 +135,17 @@ export function scopeArchiveFiles(
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
async function resolveSource(entry: VendorEntry, manifestDir: string): Promise<Map<string, Buffer>> {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
return resolveVendorSource(entry.source, manifestDir);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Resolve a vendor source (a local path, or an archive URL) to its file set. */
|
|
142
|
+
export async function resolveVendorSource(source: VendorEntry["source"], manifestDir: string): Promise<Map<string, Buffer>> {
|
|
143
|
+
if (source.type === "local") {
|
|
144
|
+
const abs = resolve(manifestDir, source.path);
|
|
145
|
+
if (!existsSync(abs)) throw new Error(`local source not found: ${source.path}`);
|
|
141
146
|
return readLocal(abs);
|
|
142
147
|
}
|
|
143
|
-
return readArchive(
|
|
148
|
+
return readArchive(source.url, source.subpath);
|
|
144
149
|
}
|
|
145
150
|
|
|
146
151
|
// ── File I/O ────────────────────────────────────────────────────────────────
|
|
@@ -154,7 +159,7 @@ function writeFiles(targetDir: string, files: Map<string, Buffer>): void {
|
|
|
154
159
|
}
|
|
155
160
|
}
|
|
156
161
|
|
|
157
|
-
function readTarget(targetDir: string): Map<string, Buffer> {
|
|
162
|
+
export function readTarget(targetDir: string): Map<string, Buffer> {
|
|
158
163
|
if (!existsSync(targetDir)) return new Map();
|
|
159
164
|
return readLocal(targetDir);
|
|
160
165
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, test, expect } from "vitest";
|
|
2
|
-
import { checkConflicts } from "./conflict-check";
|
|
2
|
+
import { checkConflicts, describeConflict } from "./conflict-check";
|
|
3
3
|
import type { LexiconPlugin, CommandGroup } from "../lexicon";
|
|
4
4
|
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -228,6 +228,23 @@ describe("checkConflicts", () => {
|
|
|
228
228
|
expect(report.conflicts).toEqual([{ type: "command-group-name", key: "build", plugins: ["rogue"] }]);
|
|
229
229
|
});
|
|
230
230
|
|
|
231
|
+
// #2529 — `workspace` is reserved ahead of core's own command, and the
|
|
232
|
+
// error says it is reserved rather than naming a second lexicon.
|
|
233
|
+
test("a command group named workspace is a hard conflict with a clear message", () => {
|
|
234
|
+
const plugins = [makePlugin("rogue", { commandGroup: { name: "workspace", description: "d", commands: [] } })];
|
|
235
|
+
const report = checkConflicts(plugins);
|
|
236
|
+
expect(report.conflicts).toEqual([{ type: "command-group-name", key: "workspace", plugins: ["rogue"] }]);
|
|
237
|
+
expect(describeConflict(report.conflicts[0])).toMatch(
|
|
238
|
+
/"workspace" is a reserved chant command name, so no lexicon can register a command group with it/,
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test("a conflict between two lexicons is described without the reserved-name note", () => {
|
|
243
|
+
expect(describeConflict({ type: "command-group-name", key: "kube", plugins: ["k8s", "fly"] })).toBe(
|
|
244
|
+
' command-group-name "kube" from: k8s, fly',
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
|
|
231
248
|
test("no conflict for a single lexicon's own, non-reserved command-group name", () => {
|
|
232
249
|
const plugins = [
|
|
233
250
|
makePlugin("k8s", { commandGroup: { name: "kube", description: "d", commands: [] } }),
|
|
@@ -108,3 +108,16 @@ export function checkConflicts(plugins: LexiconPlugin[]): ConflictReport {
|
|
|
108
108
|
|
|
109
109
|
return { conflicts, warnings };
|
|
110
110
|
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* One line of the load-time error for a conflict. A command-group name that
|
|
114
|
+
* core reserves says so and says what to do, since the lexicon author reading
|
|
115
|
+
* it may not know the word is core's (#2529).
|
|
116
|
+
*/
|
|
117
|
+
export function describeConflict(c: ConflictEntry): string {
|
|
118
|
+
const line = ` ${c.type} "${c.key}" from: ${c.plugins.join(", ")}`;
|
|
119
|
+
if (c.type === "command-group-name" && RESERVED_COMMAND_NAMES.has(c.key)) {
|
|
120
|
+
return `${line} — "${c.key}" is a reserved chant command name, so no lexicon can register a command group with it. Rename the group.`;
|
|
121
|
+
}
|
|
122
|
+
return line;
|
|
123
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { mkdir, writeFile, rm, symlink, realpath } from "node:fs/promises";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { join, dirname, resolve } from "node:path";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { SKIP_MARKER } from "../discovery/files";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* chant #2519 — a project keeps a runnable `.ts` script with top-level side
|
|
12
|
+
* effects next to its declarations, and whole-project commands neither import
|
|
13
|
+
* nor lint it once the project says so, with an `exclude` glob or the skip
|
|
14
|
+
* marker.
|
|
15
|
+
*
|
|
16
|
+
* The script is the one from the issue: it reads `process.argv` as an Op name
|
|
17
|
+
* and exits the process with code 2. Imported by discovery, it reads chant's
|
|
18
|
+
* own argv and ends the command, which is what the first test shows. It also
|
|
19
|
+
* writes a file, so "imported" is visible apart from the exit code, and it
|
|
20
|
+
* indexes `process.env` dynamically, which EVL003 flags, so "linted" is
|
|
21
|
+
* visible in lint output.
|
|
22
|
+
*
|
|
23
|
+
* End-to-end through the real CLI (`main.ts`, spawned as `bin/chant` spawns
|
|
24
|
+
* it): an in-process `build()` would be killed by the script's `process.exit`,
|
|
25
|
+
* and the point is that every command's own path honours the setting.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
const mainTsPath = resolve(thisDir, "main.ts");
|
|
30
|
+
const repoRoot = resolve(thisDir, "../../../..");
|
|
31
|
+
/** One CLI run can take a minute on a loaded CI runner, and a test makes up to three. */
|
|
32
|
+
const SPAWN_TIMEOUT = 150_000;
|
|
33
|
+
const TIMEOUT = 3 * SPAWN_TIMEOUT + 30_000;
|
|
34
|
+
|
|
35
|
+
describe("CLI end-to-end — discovery skips a side-effecting script (#2519)", () => {
|
|
36
|
+
let testDir: string;
|
|
37
|
+
let ranPath: string;
|
|
38
|
+
|
|
39
|
+
/** Write the project config; `extra` is spliced into the default export. */
|
|
40
|
+
async function writeConfig(extra: string): Promise<void> {
|
|
41
|
+
await writeFile(join(testDir, "chant.config.ts"), `export default { lexicons: ["k8s"]${extra} };\n`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The runner from the issue, optionally headed by `header`. */
|
|
45
|
+
async function writeRunner(header = ""): Promise<void> {
|
|
46
|
+
await writeFile(
|
|
47
|
+
join(testDir, "ops", "run.ts"),
|
|
48
|
+
[
|
|
49
|
+
header,
|
|
50
|
+
'import { writeFileSync } from "node:fs";',
|
|
51
|
+
"const op = process.argv[2];",
|
|
52
|
+
"const target = process.env[`OP_${op}`];",
|
|
53
|
+
`writeFileSync(${JSON.stringify(ranPath)}, String(op));`,
|
|
54
|
+
'console.error(`no op named "${op}"`, target ?? "");',
|
|
55
|
+
"process.exit(2);",
|
|
56
|
+
"",
|
|
57
|
+
].join("\n"),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
beforeEach(async () => {
|
|
62
|
+
testDir = await realpath(
|
|
63
|
+
await (async () => {
|
|
64
|
+
const dir = join(tmpdir(), `chant-discovery-skip-test-${Date.now()}-${Math.random()}`);
|
|
65
|
+
await mkdir(join(dir, "src"), { recursive: true });
|
|
66
|
+
await mkdir(join(dir, "ops"), { recursive: true });
|
|
67
|
+
return dir;
|
|
68
|
+
})(),
|
|
69
|
+
);
|
|
70
|
+
ranPath = join(testDir, "runner-ran.txt");
|
|
71
|
+
|
|
72
|
+
await mkdir(join(testDir, "node_modules", "@intentius"), { recursive: true });
|
|
73
|
+
await symlink(
|
|
74
|
+
join(repoRoot, "lexicons", "k8s"),
|
|
75
|
+
join(testDir, "node_modules", "@intentius", "chant-lexicon-k8s"),
|
|
76
|
+
"dir",
|
|
77
|
+
);
|
|
78
|
+
await writeFile(
|
|
79
|
+
join(testDir, "src", "infra.ts"),
|
|
80
|
+
[
|
|
81
|
+
'import { Namespace } from "@intentius/chant-lexicon-k8s";',
|
|
82
|
+
'export const ns = new Namespace({ metadata: { name: "discovery-skip" } });',
|
|
83
|
+
"",
|
|
84
|
+
].join("\n"),
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
afterEach(async () => {
|
|
89
|
+
await rm(testDir, { recursive: true, force: true });
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
function runCli(args: string[]): { status: number | null; stdout: string; stderr: string } {
|
|
93
|
+
const result = spawnSync("npx", ["tsx", mainTsPath, ...args], {
|
|
94
|
+
cwd: repoRoot,
|
|
95
|
+
encoding: "utf-8",
|
|
96
|
+
timeout: SPAWN_TIMEOUT,
|
|
97
|
+
});
|
|
98
|
+
return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
test("without exclude or the marker, the script runs under `chant build` and ends it", async () => {
|
|
102
|
+
await writeConfig("");
|
|
103
|
+
await writeRunner();
|
|
104
|
+
|
|
105
|
+
const { status, stderr } = runCli(["build", testDir]);
|
|
106
|
+
|
|
107
|
+
expect(status).toBe(2);
|
|
108
|
+
expect(stderr).toContain('no op named "build"');
|
|
109
|
+
expect(existsSync(ranPath)).toBe(true);
|
|
110
|
+
}, TIMEOUT);
|
|
111
|
+
|
|
112
|
+
test("an `exclude` glob keeps build and lint out of the script", async () => {
|
|
113
|
+
await writeConfig(', exclude: ["ops/**"]');
|
|
114
|
+
await writeRunner();
|
|
115
|
+
|
|
116
|
+
const build = runCli(["build", testDir]);
|
|
117
|
+
expect(build.stderr).not.toContain("no op named");
|
|
118
|
+
expect(build.status).toBe(0);
|
|
119
|
+
expect(build.stdout).toContain("name: discovery-skip");
|
|
120
|
+
|
|
121
|
+
const lint = runCli(["lint", testDir, "--format", "json"]);
|
|
122
|
+
expect(lint.status).toBe(0);
|
|
123
|
+
const diagnostics = JSON.parse(lint.stdout) as Array<{ file: string }>;
|
|
124
|
+
expect(diagnostics.some((d) => d.file.endsWith("infra.ts"))).toBe(true);
|
|
125
|
+
expect(diagnostics.filter((d) => d.file.includes("ops"))).toEqual([]);
|
|
126
|
+
|
|
127
|
+
expect(existsSync(ranPath), "the script was imported").toBe(false);
|
|
128
|
+
}, TIMEOUT);
|
|
129
|
+
|
|
130
|
+
test("an `exclude` glob keeps list and explain out of the script", async () => {
|
|
131
|
+
await writeConfig(', exclude: ["ops/**"]');
|
|
132
|
+
await writeRunner();
|
|
133
|
+
|
|
134
|
+
for (const command of ["list", "explain"]) {
|
|
135
|
+
const { status, stdout, stderr } = runCli([command, testDir]);
|
|
136
|
+
expect(stderr, command).not.toContain("no op named");
|
|
137
|
+
expect(status, command).toBe(0);
|
|
138
|
+
expect(stdout, command).toContain("ns");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
expect(existsSync(ranPath), "the script was imported").toBe(false);
|
|
142
|
+
}, TIMEOUT);
|
|
143
|
+
|
|
144
|
+
test("the skip marker keeps build and lint out of the script with no config change", async () => {
|
|
145
|
+
await writeConfig("");
|
|
146
|
+
await writeRunner(`// ${SKIP_MARKER}: a runner, not a declaration`);
|
|
147
|
+
|
|
148
|
+
const build = runCli(["build", testDir]);
|
|
149
|
+
expect(build.stderr).not.toContain("no op named");
|
|
150
|
+
expect(build.status).toBe(0);
|
|
151
|
+
|
|
152
|
+
const lint = runCli(["lint", testDir, "--format", "json"]);
|
|
153
|
+
expect(lint.status).toBe(0);
|
|
154
|
+
const diagnostics = JSON.parse(lint.stdout) as Array<{ file: string }>;
|
|
155
|
+
expect(diagnostics.filter((d) => d.file.includes("ops"))).toEqual([]);
|
|
156
|
+
|
|
157
|
+
expect(existsSync(ranPath), "the script was imported").toBe(false);
|
|
158
|
+
}, TIMEOUT);
|
|
159
|
+
|
|
160
|
+
test("the control: without exclude, `chant lint` lints the script", async () => {
|
|
161
|
+
await writeConfig("");
|
|
162
|
+
await writeRunner();
|
|
163
|
+
|
|
164
|
+
const lint = runCli(["lint", testDir, "--format", "json"]);
|
|
165
|
+
const diagnostics = JSON.parse(lint.stdout) as Array<{ file: string; ruleId: string }>;
|
|
166
|
+
expect(diagnostics.some((d) => d.file.endsWith(join("ops", "run.ts")) && d.ruleId === "EVL003")).toBe(true);
|
|
167
|
+
}, TIMEOUT);
|
|
168
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`a project outside any workspace (level 0) > the pipeline is the generator's output, unchanged 1`] = `
|
|
4
|
+
"name: chant-components-staging
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
workflow_dispatch: {}
|
|
8
|
+
|
|
9
|
+
env:
|
|
10
|
+
CHANT_ENV: staging
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
shared-alb:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
container: node:22-slim
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- run: chant run --components shared-alb --env staging --dump-outputs shared-alb.outputs.json
|
|
19
|
+
- name: Upload shared-alb outputs
|
|
20
|
+
uses: actions/upload-artifact@v4
|
|
21
|
+
with:
|
|
22
|
+
name: shared-alb-outputs
|
|
23
|
+
path: shared-alb.outputs.json
|
|
24
|
+
api:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
needs:
|
|
27
|
+
- shared-alb
|
|
28
|
+
container: node:22-slim
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
- name: Download shared-alb outputs
|
|
32
|
+
uses: actions/download-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
name: shared-alb-outputs
|
|
35
|
+
path: .
|
|
36
|
+
- run: chant run --components api --env staging --seed-outputs shared-alb.outputs.json
|
|
37
|
+
"
|
|
38
|
+
`;
|