@vibe-agent-toolkit/cli 0.2.0-rc.7 → 0.2.0-rc.9
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/README.md +0 -1
- package/dist/bin/vat +34 -19
- package/dist/bin/vat.js +34 -19
- package/dist/bin/vat.js.map +1 -1
- package/dist/bin.js +5 -2
- package/dist/bin.js.map +1 -1
- package/dist/commands/agent/build.d.ts.map +1 -1
- package/dist/commands/agent/build.js +2 -1
- package/dist/commands/agent/build.js.map +1 -1
- package/dist/commands/agent/import.d.ts.map +1 -1
- package/dist/commands/agent/import.js +3 -2
- package/dist/commands/agent/import.js.map +1 -1
- package/dist/commands/agent/install-path.d.ts +36 -0
- package/dist/commands/agent/install-path.d.ts.map +1 -0
- package/dist/commands/agent/install-path.js +44 -0
- package/dist/commands/agent/install-path.js.map +1 -0
- package/dist/commands/agent/install.d.ts.map +1 -1
- package/dist/commands/agent/install.js +22 -10
- package/dist/commands/agent/install.js.map +1 -1
- package/dist/commands/agent/installed.d.ts.map +1 -1
- package/dist/commands/agent/installed.js +22 -12
- package/dist/commands/agent/installed.js.map +1 -1
- package/dist/commands/agent/list.d.ts.map +1 -1
- package/dist/commands/agent/list.js +2 -1
- package/dist/commands/agent/list.js.map +1 -1
- package/dist/commands/agent/run.d.ts.map +1 -1
- package/dist/commands/agent/run.js +2 -1
- package/dist/commands/agent/run.js.map +1 -1
- package/dist/commands/agent/uninstall.d.ts.map +1 -1
- package/dist/commands/agent/uninstall.js +13 -6
- package/dist/commands/agent/uninstall.js.map +1 -1
- package/dist/commands/agent/validate.d.ts.map +1 -1
- package/dist/commands/agent/validate.js +3 -2
- package/dist/commands/agent/validate.js.map +1 -1
- package/dist/commands/ard/emit.d.ts +72 -23
- package/dist/commands/ard/emit.d.ts.map +1 -1
- package/dist/commands/ard/emit.js +109 -56
- package/dist/commands/ard/emit.js.map +1 -1
- package/dist/commands/ard/index.d.ts +1 -1
- package/dist/commands/ard/index.d.ts.map +1 -1
- package/dist/commands/ard/index.js +4 -3
- package/dist/commands/ard/index.js.map +1 -1
- package/dist/commands/audit/distributed-tree.d.ts.map +1 -1
- package/dist/commands/audit/distributed-tree.js +9 -6
- package/dist/commands/audit/distributed-tree.js.map +1 -1
- package/dist/commands/audit/provenance.d.ts.map +1 -1
- package/dist/commands/audit/provenance.js +4 -3
- package/dist/commands/audit/provenance.js.map +1 -1
- package/dist/commands/audit/scan-population.d.ts +158 -0
- package/dist/commands/audit/scan-population.d.ts.map +1 -0
- package/dist/commands/audit/scan-population.js +292 -0
- package/dist/commands/audit/scan-population.js.map +1 -0
- package/dist/commands/audit-settings.d.ts.map +1 -1
- package/dist/commands/audit-settings.js +6 -5
- package/dist/commands/audit-settings.js.map +1 -1
- package/dist/commands/audit.d.ts +16 -14
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +304 -389
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +25 -24
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/cache/clear.d.ts +17 -3
- package/dist/commands/cache/clear.d.ts.map +1 -1
- package/dist/commands/cache/clear.js +34 -13
- package/dist/commands/cache/clear.js.map +1 -1
- package/dist/commands/cache/index.d.ts.map +1 -1
- package/dist/commands/cache/index.js +19 -10
- package/dist/commands/cache/index.js.map +1 -1
- package/dist/commands/claude/context.d.ts +2 -2
- package/dist/commands/claude/context.d.ts.map +1 -1
- package/dist/commands/claude/context.js +7 -6
- package/dist/commands/claude/context.js.map +1 -1
- package/dist/commands/claude/index.d.ts +12 -11
- package/dist/commands/claude/index.d.ts.map +1 -1
- package/dist/commands/claude/index.js +14 -16
- package/dist/commands/claude/index.js.map +1 -1
- package/dist/commands/claude/marketplace/changelog-utils.d.ts +1 -1
- package/dist/commands/claude/marketplace/changelog-utils.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/changelog-utils.js +1 -2
- package/dist/commands/claude/marketplace/changelog-utils.js.map +1 -1
- package/dist/commands/claude/marketplace/git-publish.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/git-publish.js +22 -12
- package/dist/commands/claude/marketplace/git-publish.js.map +1 -1
- package/dist/commands/claude/marketplace/license-utils.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/license-utils.js +0 -1
- package/dist/commands/claude/marketplace/license-utils.js.map +1 -1
- package/dist/commands/claude/marketplace/publish-tree.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/publish-tree.js +0 -6
- package/dist/commands/claude/marketplace/publish-tree.js.map +1 -1
- package/dist/commands/claude/marketplace/publish.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/publish.js +2 -1
- package/dist/commands/claude/marketplace/publish.js.map +1 -1
- package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/validate.js +26 -16
- package/dist/commands/claude/marketplace/validate.js.map +1 -1
- package/dist/commands/claude/org/api-keys.d.ts +0 -3
- package/dist/commands/claude/org/api-keys.d.ts.map +1 -1
- package/dist/commands/claude/org/api-keys.js +2 -1
- package/dist/commands/claude/org/api-keys.js.map +1 -1
- package/dist/commands/claude/org/helpers.d.ts +17 -22
- package/dist/commands/claude/org/helpers.d.ts.map +1 -1
- package/dist/commands/claude/org/helpers.js +6 -22
- package/dist/commands/claude/org/helpers.js.map +1 -1
- package/dist/commands/claude/org/invites.d.ts +0 -3
- package/dist/commands/claude/org/invites.d.ts.map +1 -1
- package/dist/commands/claude/org/invites.js +3 -2
- package/dist/commands/claude/org/invites.js.map +1 -1
- package/dist/commands/claude/org/skills.d.ts +19 -1
- package/dist/commands/claude/org/skills.d.ts.map +1 -1
- package/dist/commands/claude/org/skills.js +147 -111
- package/dist/commands/claude/org/skills.js.map +1 -1
- package/dist/commands/claude/org/users.d.ts +0 -3
- package/dist/commands/claude/org/users.d.ts.map +1 -1
- package/dist/commands/claude/org/users.js +3 -2
- package/dist/commands/claude/org/users.js.map +1 -1
- package/dist/commands/claude/org/workspaces.d.ts +0 -3
- package/dist/commands/claude/org/workspaces.d.ts.map +1 -1
- package/dist/commands/claude/org/workspaces.js +6 -5
- package/dist/commands/claude/org/workspaces.js.map +1 -1
- package/dist/commands/claude/plugin/build.d.ts.map +1 -1
- package/dist/commands/claude/plugin/build.js +23 -52
- package/dist/commands/claude/plugin/build.js.map +1 -1
- package/dist/commands/claude/plugin/helpers.d.ts.map +1 -1
- package/dist/commands/claude/plugin/helpers.js +0 -6
- package/dist/commands/claude/plugin/helpers.js.map +1 -1
- package/dist/commands/claude/plugin/install.d.ts +12 -0
- package/dist/commands/claude/plugin/install.d.ts.map +1 -1
- package/dist/commands/claude/plugin/install.js +71 -60
- package/dist/commands/claude/plugin/install.js.map +1 -1
- package/dist/commands/claude/plugin/list.d.ts.map +1 -1
- package/dist/commands/claude/plugin/list.js +3 -2
- package/dist/commands/claude/plugin/list.js.map +1 -1
- package/dist/commands/claude/plugin/plugin-changelog.d.ts.map +1 -1
- package/dist/commands/claude/plugin/plugin-changelog.js +0 -2
- package/dist/commands/claude/plugin/plugin-changelog.js.map +1 -1
- package/dist/commands/claude/plugin/plugin-files.d.ts.map +1 -1
- package/dist/commands/claude/plugin/plugin-files.js +3 -6
- package/dist/commands/claude/plugin/plugin-files.js.map +1 -1
- package/dist/commands/claude/plugin/plugin-validators.d.ts.map +1 -1
- package/dist/commands/claude/plugin/plugin-validators.js +3 -6
- package/dist/commands/claude/plugin/plugin-validators.js.map +1 -1
- package/dist/commands/claude/plugin/tree-copy.d.ts +2 -1
- package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
- package/dist/commands/claude/plugin/tree-copy.js +15 -14
- package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
- package/dist/commands/claude/plugin/uninstall.d.ts.map +1 -1
- package/dist/commands/claude/plugin/uninstall.js +4 -4
- package/dist/commands/claude/plugin/uninstall.js.map +1 -1
- package/dist/commands/consistency-check.d.ts +17 -15
- package/dist/commands/consistency-check.d.ts.map +1 -1
- package/dist/commands/consistency-check.js +149 -104
- package/dist/commands/consistency-check.js.map +1 -1
- package/dist/commands/corpus/report.d.ts.map +1 -1
- package/dist/commands/corpus/report.js +1 -2
- package/dist/commands/corpus/report.js.map +1 -1
- package/dist/commands/corpus/runner.d.ts.map +1 -1
- package/dist/commands/corpus/runner.js +2 -6
- package/dist/commands/corpus/runner.js.map +1 -1
- package/dist/commands/corpus/scan.d.ts.map +1 -1
- package/dist/commands/corpus/scan.js +2 -3
- package/dist/commands/corpus/scan.js.map +1 -1
- package/dist/commands/corpus/seed.d.ts +4 -4
- package/dist/commands/corpus/seed.d.ts.map +1 -1
- package/dist/commands/corpus/seed.js +1 -3
- package/dist/commands/corpus/seed.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +55 -37
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/inventory.d.ts.map +1 -1
- package/dist/commands/inventory.js +6 -7
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/mcp/list-collections.d.ts.map +1 -1
- package/dist/commands/mcp/list-collections.js +2 -1
- package/dist/commands/mcp/list-collections.js.map +1 -1
- package/dist/commands/mcp/serve.d.ts.map +1 -1
- package/dist/commands/mcp/serve.js +3 -2
- package/dist/commands/mcp/serve.js.map +1 -1
- package/dist/commands/okf/index.d.ts.map +1 -1
- package/dist/commands/okf/index.js +14 -2
- package/dist/commands/okf/index.js.map +1 -1
- package/dist/commands/okf/validate.d.ts +157 -48
- package/dist/commands/okf/validate.d.ts.map +1 -1
- package/dist/commands/okf/validate.js +109 -76
- package/dist/commands/okf/validate.js.map +1 -1
- package/dist/commands/phase-utils.d.ts +11 -10
- package/dist/commands/phase-utils.d.ts.map +1 -1
- package/dist/commands/phase-utils.js +30 -14
- package/dist/commands/phase-utils.js.map +1 -1
- package/dist/commands/positional-args.d.ts.map +1 -1
- package/dist/commands/positional-args.js +2 -1
- package/dist/commands/positional-args.js.map +1 -1
- package/dist/commands/rag/clear-command.d.ts.map +1 -1
- package/dist/commands/rag/clear-command.js +2 -1
- package/dist/commands/rag/clear-command.js.map +1 -1
- package/dist/commands/rag/index-command.d.ts.map +1 -1
- package/dist/commands/rag/index-command.js +4 -1
- package/dist/commands/rag/index-command.js.map +1 -1
- package/dist/commands/rag/query-command.d.ts.map +1 -1
- package/dist/commands/rag/query-command.js +2 -1
- package/dist/commands/rag/query-command.js.map +1 -1
- package/dist/commands/rag/stats-command.d.ts.map +1 -1
- package/dist/commands/rag/stats-command.js +2 -1
- package/dist/commands/rag/stats-command.js.map +1 -1
- package/dist/commands/resources/check-progress.d.ts +6 -0
- package/dist/commands/resources/check-progress.d.ts.map +1 -1
- package/dist/commands/resources/check-progress.js +15 -4
- package/dist/commands/resources/check-progress.js.map +1 -1
- package/dist/commands/resources/check-supervisor.d.ts.map +1 -1
- package/dist/commands/resources/check-supervisor.js +14 -7
- package/dist/commands/resources/check-supervisor.js.map +1 -1
- package/dist/commands/resources/check.d.ts +315 -205
- package/dist/commands/resources/check.d.ts.map +1 -1
- package/dist/commands/resources/check.js +368 -327
- package/dist/commands/resources/check.js.map +1 -1
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +159 -39
- package/dist/commands/resources/index.js.map +1 -1
- package/dist/commands/resources/query.d.ts +2 -2
- package/dist/commands/resources/query.d.ts.map +1 -1
- package/dist/commands/resources/query.js +24 -18
- package/dist/commands/resources/query.js.map +1 -1
- package/dist/commands/resources/scan.d.ts.map +1 -1
- package/dist/commands/resources/scan.js +4 -8
- package/dist/commands/resources/scan.js.map +1 -1
- package/dist/commands/resources/validate.d.ts +1 -1
- package/dist/commands/resources/validate.d.ts.map +1 -1
- package/dist/commands/resources/validate.js +0 -1
- package/dist/commands/resources/validate.js.map +1 -1
- package/dist/commands/skill/review-checklist.d.ts +3 -2
- package/dist/commands/skill/review-checklist.d.ts.map +1 -1
- package/dist/commands/skill/review-checklist.js +4 -2
- package/dist/commands/skill/review-checklist.js.map +1 -1
- package/dist/commands/skill/review.d.ts +247 -0
- package/dist/commands/skill/review.d.ts.map +1 -1
- package/dist/commands/skill/review.js +90 -60
- package/dist/commands/skill/review.js.map +1 -1
- package/dist/commands/skill/test/configure.d.ts.map +1 -1
- package/dist/commands/skill/test/configure.js +0 -1
- package/dist/commands/skill/test/configure.js.map +1 -1
- package/dist/commands/skill/test/run.d.ts +12 -6
- package/dist/commands/skill/test/run.d.ts.map +1 -1
- package/dist/commands/skill/test/run.js +120 -65
- package/dist/commands/skill/test/run.js.map +1 -1
- package/dist/commands/skills/build.d.ts +83 -3
- package/dist/commands/skills/build.d.ts.map +1 -1
- package/dist/commands/skills/build.js +162 -40
- package/dist/commands/skills/build.js.map +1 -1
- package/dist/commands/skills/install.d.ts +2 -1
- package/dist/commands/skills/install.d.ts.map +1 -1
- package/dist/commands/skills/install.js +20 -30
- package/dist/commands/skills/install.js.map +1 -1
- package/dist/commands/skills/list.d.ts.map +1 -1
- package/dist/commands/skills/list.js +14 -18
- package/dist/commands/skills/list.js.map +1 -1
- package/dist/commands/skills/package.d.ts +1 -1
- package/dist/commands/skills/package.d.ts.map +1 -1
- package/dist/commands/skills/package.js +6 -8
- package/dist/commands/skills/package.js.map +1 -1
- package/dist/commands/skills/scope-guard.d.ts.map +1 -1
- package/dist/commands/skills/scope-guard.js +2 -4
- package/dist/commands/skills/scope-guard.js.map +1 -1
- package/dist/commands/skills/shared.d.ts.map +1 -1
- package/dist/commands/skills/shared.js +2 -4
- package/dist/commands/skills/shared.js.map +1 -1
- package/dist/commands/skills/skill-discovery.d.ts +15 -13
- package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
- package/dist/commands/skills/skill-discovery.js +23 -5
- package/dist/commands/skills/skill-discovery.js.map +1 -1
- package/dist/commands/skills/source-resolvers.d.ts +15 -0
- package/dist/commands/skills/source-resolvers.d.ts.map +1 -1
- package/dist/commands/skills/source-resolvers.js +25 -4
- package/dist/commands/skills/source-resolvers.js.map +1 -1
- package/dist/commands/validate.d.ts +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +39 -14
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/verify.d.ts +17 -5
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +161 -104
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/report-schemas.d.ts +45 -0
- package/dist/report-schemas.d.ts.map +1 -0
- package/dist/report-schemas.js +100 -0
- package/dist/report-schemas.js.map +1 -0
- package/dist/skill-resolution/classify.js +2 -2
- package/dist/skill-resolution/classify.js.map +1 -1
- package/dist/skill-resolution/resolve-skill-reference.d.ts.map +1 -1
- package/dist/skill-resolution/resolve-skill-reference.js +50 -55
- package/dist/skill-resolution/resolve-skill-reference.js.map +1 -1
- package/dist/utils/agent-discovery.d.ts.map +1 -1
- package/dist/utils/agent-discovery.js +22 -11
- package/dist/utils/agent-discovery.js.map +1 -1
- package/dist/utils/agent-runner.d.ts.map +1 -1
- package/dist/utils/agent-runner.js +0 -1
- package/dist/utils/agent-runner.js.map +1 -1
- package/dist/utils/claude-context-lens.d.ts +34 -0
- package/dist/utils/claude-context-lens.d.ts.map +1 -0
- package/dist/utils/claude-context-lens.js +39 -0
- package/dist/utils/claude-context-lens.js.map +1 -0
- package/dist/utils/command-error.d.ts +63 -62
- package/dist/utils/command-error.d.ts.map +1 -1
- package/dist/utils/command-error.js +80 -76
- package/dist/utils/command-error.js.map +1 -1
- package/dist/utils/config-loader.d.ts +2 -1
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +3 -6
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/corpus-target.d.ts +5 -27
- package/dist/utils/corpus-target.d.ts.map +1 -1
- package/dist/utils/corpus-target.js +7 -33
- package/dist/utils/corpus-target.js.map +1 -1
- package/dist/utils/help-loader.d.ts.map +1 -1
- package/dist/utils/help-loader.js +0 -1
- package/dist/utils/help-loader.js.map +1 -1
- package/dist/utils/issue-rendering.d.ts +2 -2
- package/dist/utils/issue-rendering.js +2 -2
- package/dist/utils/optional-backend.d.ts.map +1 -1
- package/dist/utils/optional-backend.js +2 -1
- package/dist/utils/optional-backend.js.map +1 -1
- package/dist/utils/output.d.ts +9 -0
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +16 -0
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/package-json.d.ts +24 -0
- package/dist/utils/package-json.d.ts.map +1 -0
- package/dist/utils/package-json.js +49 -0
- package/dist/utils/package-json.js.map +1 -0
- package/dist/utils/project-root-policy.d.ts.map +1 -1
- package/dist/utils/project-root-policy.js +0 -2
- package/dist/utils/project-root-policy.js.map +1 -1
- package/dist/utils/projection-lenses.d.ts +98 -0
- package/dist/utils/projection-lenses.d.ts.map +1 -0
- package/dist/utils/projection-lenses.js +203 -0
- package/dist/utils/projection-lenses.js.map +1 -0
- package/dist/utils/projection-query.d.ts +38 -14
- package/dist/utils/projection-query.d.ts.map +1 -1
- package/dist/utils/projection-query.js +78 -17
- package/dist/utils/projection-query.js.map +1 -1
- package/dist/utils/projection-store.d.ts +61 -42
- package/dist/utils/projection-store.d.ts.map +1 -1
- package/dist/utils/projection-store.js +155 -59
- package/dist/utils/projection-store.js.map +1 -1
- package/dist/utils/relation-limits.d.ts +50 -0
- package/dist/utils/relation-limits.d.ts.map +1 -0
- package/dist/utils/relation-limits.js +50 -0
- package/dist/utils/relation-limits.js.map +1 -0
- package/dist/utils/resource-loader.js +2 -2
- package/dist/utils/resource-loader.js.map +1 -1
- package/dist/utils/skill-discovery.d.ts.map +1 -1
- package/dist/utils/skill-discovery.js +2 -1
- package/dist/utils/skill-discovery.js.map +1 -1
- package/dist/utils/skill-packaging-config.d.ts +63 -1
- package/dist/utils/skill-packaging-config.d.ts.map +1 -1
- package/dist/utils/skill-packaging-config.js +56 -1
- package/dist/utils/skill-packaging-config.js.map +1 -1
- package/dist/utils/url-redact.d.ts.map +1 -1
- package/dist/utils/url-redact.js +4 -6
- package/dist/utils/url-redact.js.map +1 -1
- package/dist/utils/user-context-scanner.d.ts.map +1 -1
- package/dist/utils/user-context-scanner.js +0 -2
- package/dist/utils/user-context-scanner.js.map +1 -1
- package/dist/utils/validate-help-files.d.ts.map +1 -1
- package/dist/utils/validate-help-files.js +3 -4
- package/dist/utils/validate-help-files.js.map +1 -1
- package/dist/utils/vat-bin-path.d.ts.map +1 -1
- package/dist/utils/vat-bin-path.js +0 -1
- package/dist/utils/vat-bin-path.js.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -3
- package/dist/version.js.map +1 -1
- package/docs/audit.md +44 -53
- package/docs/doctor.md +1 -0
- package/docs/index.md +18 -10
- package/docs/rag.md +0 -1
- package/docs/resources.md +0 -1
- package/docs/skill-test.md +10 -9
- package/docs/skills.md +6 -7
- package/package.json +23 -28
- package/schemas/ard-emit.json +149 -0
- package/schemas/okf-validate.json +170 -0
- package/schemas/resources-check.json +229 -0
- package/schemas/skill-review.json +230 -0
- package/dist/commands/claude/budget.d.ts +0 -170
- package/dist/commands/claude/budget.d.ts.map +0 -1
- package/dist/commands/claude/budget.js +0 -464
- package/dist/commands/claude/budget.js.map +0 -1
- package/dist/utils/context-budget-issues.d.ts +0 -108
- package/dist/utils/context-budget-issues.d.ts.map +0 -1
- package/dist/utils/context-budget-issues.js +0 -280
- package/dist/utils/context-budget-issues.js.map +0 -1
|
@@ -1,181 +1,134 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `vat resources check` — run the project's own
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* The same class one level further out, and the one that shipped. `checksRun` is
|
|
32
|
-
* the denominator of RULES; nothing counted the ROWS, so a repository whose
|
|
33
|
-
* enumeration came back empty — a broad `.gitignore`, a shallow or sparse CI
|
|
34
|
-
* checkout, a root that resolved somewhere else — ran every declared check over
|
|
35
|
-
* nothing and reported `status: success` on exit 0 with empty stderr. Population
|
|
36
|
-
* declines ignored members rather than flagging them, so the tables held no
|
|
37
|
-
* trace of it either.
|
|
38
|
-
*
|
|
39
|
-
* So the population's size is published (`membersEnumerated`), and a run whose
|
|
40
|
-
* checks executed over zero members is an ERROR under the same non-overridable
|
|
41
|
-
* code as a broken statement — see {@link emptyCorpusFinding}. A gate that
|
|
42
|
-
* asserts nothing over nothing has not passed.
|
|
43
|
-
*
|
|
44
|
-
* ## 🔑 An unknown `--check` name is a refusal, not an empty pass
|
|
45
|
-
*
|
|
46
|
-
* The same failure class one flag over: a filter that matched nothing ran nothing
|
|
47
|
-
* and exited 0. `requireDeclaredCheck` refuses it before the crawl, naming the
|
|
48
|
-
* declared set. A gate that cannot fail is worse than no gate.
|
|
49
|
-
*
|
|
50
|
-
* ## 🔑 NO checks at all is the same refusal, and the one that shipped longest
|
|
51
|
-
*
|
|
52
|
-
* A project with a valid config and no `checks:` block reported `status:
|
|
53
|
-
* success`, `checksRun: 0`, exit 0 — so DELETING the `checks:` block silently
|
|
54
|
-
* deleted the gate and nothing anywhere said so. A gate that checked nothing is
|
|
55
|
-
* indistinguishable from a gate that was removed, and the entire argument for
|
|
56
|
-
* having these gates is that you never let those two look alike. It is now a
|
|
57
|
-
* `RESOURCE_CHECK_BROKEN` error like the other three — see
|
|
58
|
-
* {@link noCheckRanFinding}, and `RUN_INTEGRITY_CODE` for why one code
|
|
59
|
-
* covers all four. Declaring no checks is a legitimate CHOICE; running a gate
|
|
60
|
-
* that can only pass is not, so the remedy is to take the command out of the
|
|
61
|
-
* pipeline.
|
|
62
|
-
*
|
|
63
|
-
* ## 🔑 SQL is the surface a user OPTED IN to, so no BUILT-IN check may be SQL
|
|
64
|
-
*
|
|
65
|
-
* Every check this verb runs is adopter-declared: {@link checkCommand} reads
|
|
66
|
-
* `config?.resources?.checks` and nothing else, and warns loudly when a project
|
|
67
|
-
* declares none. There are no built-ins, and the one way to end that quietly is
|
|
68
|
-
* to author the first one as SQL. A default-on rule written as a statement makes
|
|
69
|
-
* the engine, the projection and the population mandatory for everyone who
|
|
70
|
-
* inherits it, without anybody deciding that. So: **built-ins are TypeScript
|
|
71
|
-
* predicates over the projection's row model.** SQL stays the two places a user
|
|
72
|
-
* asked for it — this verb's declared checks, and `vat resources query`.
|
|
73
|
-
*
|
|
74
|
-
* ⚠️ The engine today is `node:sqlite`, built into Node, so the thing at stake is
|
|
75
|
-
* not an install — it is the POPULATION. On an ~11,700-member adopter tree
|
|
76
|
-
* building the projection is **>99.9%** of a check run (16.5 s cold, ~1.3 s from
|
|
77
|
-
* the store) against **0.0008–0.004 s** for the statements themselves; see
|
|
78
|
-
* `vat-knowledge-resources.md`, which carries that measurement. That is exactly
|
|
79
|
-
* the cost "What this does NOT do" below refuses to put on every adopter's
|
|
80
|
-
* pre-commit path, and a default-on SQL check would put it there without the
|
|
81
|
-
* decision. The INSTALL cost is deferred rather than gone: the open question
|
|
82
|
-
* about a columnar engine is a 108 MB platform binding on a published toolkit,
|
|
83
|
-
* and this invariant is what keeps that question still answerable either way.
|
|
84
|
-
*
|
|
85
|
-
* ## 🔑 The DEFAULT check set belongs to the pipeline, not to the config file
|
|
86
|
-
*
|
|
87
|
-
* A directory with no `vibe-agent-toolkit.config.yaml` must run exactly the same
|
|
88
|
-
* default-on checks as one with a config; config only ADDS to that set or
|
|
89
|
-
* OVERRIDES a severity in it. This is load-bearing rather than a convenience:
|
|
90
|
-
* *"'default-on error' is meaningless as a category if being default-on requires
|
|
91
|
-
* a config file to say so."*
|
|
92
|
-
*
|
|
93
|
-
* It is therefore a constraint on WHERE the defaults live in code, not only on
|
|
94
|
-
* what they are. They cannot be defaulted into the parsed config object, because
|
|
95
|
-
* an absent config is `undefined` and every default would vanish with it — for
|
|
96
|
-
* the project that never wrote one, which is the population the category exists
|
|
97
|
-
* for. The rest of VAT already behaves this way and is the shape to match:
|
|
98
|
-
* `vat audit` completes its entire scan first and reads config only to apply
|
|
99
|
-
* severity overrides, warning and CONTINUING when the file cannot be read; and
|
|
100
|
-
* `loadResourcesWithConfig` hands `vat resources validate` a registry whose
|
|
101
|
-
* built-in validators run whether `loadConfig` returned a config or nothing.
|
|
102
|
-
* This verb has no defaults yet, so the invariant is a rule for the first one —
|
|
103
|
-
* and the day it is written is the easiest day to break it.
|
|
104
|
-
*
|
|
105
|
-
* ## Keeping a TypeScript check and its SQL twin: two good reasons, one trap
|
|
106
|
-
*
|
|
107
|
-
* The proposal was "write the predicate twice, in TypeScript and in SQL, and run
|
|
108
|
-
* whichever is faster". Two thirds of it are worth having.
|
|
109
|
-
*
|
|
110
|
-
* ✅ **As documentation.** An SQL twin is executable documentation of the row
|
|
111
|
-
* model, and strictly better than prose about it: prose can describe a column
|
|
112
|
-
* that no longer exists and never say so, while a statement stops compiling —
|
|
113
|
-
* which this verb reports as `RESOURCE_CHECK_BROKEN` rather than as a skip.
|
|
114
|
-
*
|
|
115
|
-
* ✅ **As a differential oracle.** Run both over the frozen corpus and assert
|
|
116
|
-
* IDENTICAL findings. That is the only thing which makes a dual implementation
|
|
117
|
-
* better than a single one rather than worse: two implementations with no
|
|
118
|
-
* mandatory differential test are simply two places for one rule to be wrong.
|
|
119
|
-
* Apply it selectively, to genuinely relational checks — done by default, every
|
|
120
|
-
* new rule costs three artifacts instead of one.
|
|
121
|
-
*
|
|
122
|
-
* ⛔ **As a runtime optimizer — rejected, on two INDEPENDENT grounds.** It would
|
|
123
|
-
* essentially never choose SQL: `buildResourceProjection` hands the rows back in
|
|
124
|
-
* memory before the ephemeral database exists at all, so the TypeScript arm is a
|
|
125
|
-
* for-loop over data already in hand, and the SQL arm's whole measured share of a
|
|
126
|
-
* run is the 0.0008–0.004 s above. A scheduler would be choosing between two
|
|
127
|
-
* arms of the 0.1%. And it reintroduces the dependency through the back door: an
|
|
128
|
-
* optimizer that MAY choose SQL means SQL MAY be needed at check time, which for
|
|
129
|
-
* anyone shipping the thing is the same as needed. **Optionality is not a
|
|
130
|
-
* property you can keep while also letting a scheduler reach for the optional
|
|
131
|
-
* thing.**
|
|
132
|
-
*
|
|
133
|
-
* ## 🔑 Adopter SQL runs UNSANDBOXED on purpose — and contributed SQL is not adopter SQL
|
|
134
|
-
*
|
|
135
|
-
* What a statement may BE is gated hard, and documented where it is enforced:
|
|
136
|
-
* `assertIsQuery` and `detachForeignSchemas` in
|
|
137
|
-
* `packages/projection-sqlite/src/store.ts` refuse `ATTACH` and `PRAGMA`, with
|
|
138
|
-
* the measured cross-repository leak that motivated both, and CHANGELOG.md's
|
|
139
|
-
* `--budget` entry carries why nothing inside this process can interrupt a
|
|
140
|
-
* runaway statement. Read those; do not restate them here.
|
|
141
|
-
*
|
|
142
|
-
* What is written down nowhere else is that everything PAST those gates is
|
|
143
|
-
* unsandboxed deliberately. A `.sql` file the adopter points their own config at
|
|
144
|
-
* is adopter code, at the same trust boundary as their eslint config: they wrote
|
|
145
|
-
* it or they chose to inherit it, and VAT is not the thing standing between a
|
|
146
|
-
* project and its own repository.
|
|
147
|
-
*
|
|
148
|
-
* 🚨 That reasoning covers exactly ONE trust domain, and the rule scoping it is
|
|
149
|
-
* the other half: **contributed SQL is a reviewed EXAMPLE, never an
|
|
150
|
-
* auto-executed check.** A contribution channel is third-party text, and a
|
|
151
|
-
* statement arriving through one has none of the "they chose it" the paragraph
|
|
152
|
-
* above rests on. Ship it as documentation an adopter copies into their own
|
|
153
|
-
* `resources.checks` deliberately. One paragraph must not be stretched to cover
|
|
154
|
-
* both domains.
|
|
155
|
-
*
|
|
156
|
-
* ## What this does NOT do
|
|
157
|
-
*
|
|
158
|
-
* It does not fold into `vat resources validate`. That command is on every
|
|
159
|
-
* adopter's pre-commit path, and adding a store-backed population to it is a
|
|
160
|
-
* cost and a risk that deserves its own decision with its own evidence. Wiring
|
|
161
|
-
* this into CI is one line in a workflow; making it unavoidable is not this
|
|
162
|
-
* change's call to make.
|
|
2
|
+
* `vat resources check` — run the project's own assertions over its resource
|
|
3
|
+
* projection, as a gate.
|
|
4
|
+
*
|
|
5
|
+
* The invariants this file implements are written down once, in
|
|
6
|
+
* `docs/architecture/cli.md` under "`vat resources check [path]`". Read that
|
|
7
|
+
* before changing anything here; the headlines, so a reader knows when to:
|
|
8
|
+
*
|
|
9
|
+
* - 🔑 **Four ways to check nothing are all refusals**, at error severity under
|
|
10
|
+
* the non-overridable `RESOURCE_CHECK_BROKEN`: a statement that will not run
|
|
11
|
+
* (the `catch` in `runUnits`), a corpus that enumerated empty
|
|
12
|
+
* ({@link emptyCorpusFinding}), a `--check` name nothing declares
|
|
13
|
+
* (`requireKnownCheck`), and not one check executed at all
|
|
14
|
+
* ({@link noCheckRanFinding}, derived in {@link buildCheckOutputData} so an
|
|
15
|
+
* emptied `BUILTIN_CHECKS` cannot publish a clean document).
|
|
16
|
+
* - ⚠️ That last one does NOT make the step always able to fail: the only
|
|
17
|
+
* built-in ships at `info`. Do not invent a second refusal for it — that
|
|
18
|
+
* would refuse the no-config run the default set exists to serve.
|
|
19
|
+
* - 🔑 **No built-in check may be SQL.** {@link checkCommand} reads
|
|
20
|
+
* `config?.resources?.checks` and nothing else for statements; built-ins are
|
|
21
|
+
* TypeScript predicates over the row model, and a built-in's `sqlTwin` is
|
|
22
|
+
* documentation an adopter copies, never executed here.
|
|
23
|
+
* - 🔑 **The default set belongs to the pipeline, not the config file.**
|
|
24
|
+
* `BUILTIN_CHECKS` reaches {@link runProjectChecks} as a REQUIRED `builtins`
|
|
25
|
+
* argument via {@link runOutcome}; nothing on that path reads `config`.
|
|
26
|
+
* - 🚨 **Adopter SQL runs unsandboxed on purpose, and contributed SQL is not
|
|
27
|
+
* adopter SQL** — a contributed statement ships as a reviewed example.
|
|
28
|
+
* - ⛔ A TypeScript/SQL twin is documentation and a differential oracle, never
|
|
29
|
+
* a runtime optimizer to schedule between.
|
|
163
30
|
*/
|
|
164
31
|
import { performance } from 'node:perf_hooks';
|
|
165
|
-
import { issuesFromCheckRows } from '@vibe-agent-toolkit/resources';
|
|
166
|
-
import {
|
|
32
|
+
import { bindBuiltinChecks, BUILTIN_CHECK_NAMES, issuesFromCheckRows, LIMIT_DIRECTIONS, } from '@vibe-agent-toolkit/resources';
|
|
33
|
+
import { buildReport, CUSTOM_CHECK_CODE_PREFIX, ExitCode, isCustomCheckCode, reportSchema, toFindings, } from '@vibe-agent-toolkit/schema';
|
|
167
34
|
import { safePath } from '@vibe-agent-toolkit/utils';
|
|
168
|
-
import {
|
|
35
|
+
import { z } from 'zod';
|
|
36
|
+
import { handleReportCommandError } from '../../utils/command-error.js';
|
|
169
37
|
import { loadConfigCached } from '../../utils/config-loader.js';
|
|
170
38
|
import { formatDurationSecs } from '../../utils/duration.js';
|
|
171
39
|
import { resolveIssueSeverity } from '../../utils/issue-severity.js';
|
|
172
40
|
import { createLogger } from '../../utils/logger.js';
|
|
173
|
-
import {
|
|
41
|
+
import { writeStdoutSync, writeStructuredOutput } from '../../utils/output.js';
|
|
174
42
|
import { assertDirectoryArgument, projectRootOrLoudCwd, projectRootOrNull } from '../../utils/project-root-policy.js';
|
|
175
43
|
import { withQueriedProjection, } from '../../utils/projection-query.js';
|
|
44
|
+
import { relationBoundsFor } from '../../utils/relation-limits.js';
|
|
176
45
|
import { nothingCheckedFinding, runIntegrityFinding } from '../../utils/run-integrity.js';
|
|
177
46
|
import { createProgressWriter, parseProgressLog, unitInFlight, } from './check-progress.js';
|
|
178
47
|
import { parseBudgetSeconds, requireSupervisableFlags, runsInThisProcess, superviseCheck, withProgressLog, } from './check-supervisor.js';
|
|
48
|
+
/** What one rule cost, as the document publishes it. */
|
|
49
|
+
const PublishedCheckCostSchema = z.object({
|
|
50
|
+
name: z.string(),
|
|
51
|
+
/** Three significant figures, so a 0.4 ms rule serializes as 0.0004 rather than a zero that reads as "not measured". */
|
|
52
|
+
durationSecs: z.number().nonnegative(),
|
|
53
|
+
/** Rows the statement returned. ABSENT, never 0, when the statement did not complete. */
|
|
54
|
+
rows: z.number().int().nonnegative().optional(),
|
|
55
|
+
broken: z.literal(true).optional(),
|
|
56
|
+
/** Present and `true` only for a rule VAT supplied — see {@link CheckCost.builtin}. */
|
|
57
|
+
builtin: z.literal(true).optional(),
|
|
58
|
+
}).strict();
|
|
59
|
+
/**
|
|
60
|
+
* The published copy of {@link relationBoundsFor}'s answer.
|
|
61
|
+
*
|
|
62
|
+
* The registry lists are `readonly` and this document is handed to a serializer,
|
|
63
|
+
* so the arrays are copied rather than referenced — the same rule
|
|
64
|
+
* `lensesEvaluated` follows one field above: a published document owns no
|
|
65
|
+
* reference into the run's own state.
|
|
66
|
+
*
|
|
67
|
+
* @param lensesEvaluated - The lenses this run evaluated
|
|
68
|
+
* @returns The bounds keys to spread, or nothing
|
|
69
|
+
*/
|
|
70
|
+
function structuredBounds(lensesEvaluated) {
|
|
71
|
+
const bounds = relationBoundsFor(lensesEvaluated);
|
|
72
|
+
if (bounds.boundsStatement === undefined || bounds.limits === undefined)
|
|
73
|
+
return {};
|
|
74
|
+
return { boundsStatement: bounds.boundsStatement, limits: bounds.limits.map((limit) => ({ ...limit })) };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A signed bound on what the derived rows settle, as `@vibe-agent-toolkit/resources`
|
|
78
|
+
* states it.
|
|
79
|
+
*
|
|
80
|
+
* ⛔ The direction vocabulary is IMPORTED, never respelled: `LIMIT_DIRECTIONS`
|
|
81
|
+
* is the one list, tied to `StatedLimit['direction']` by `satisfies`, so a
|
|
82
|
+
* fifth direction cannot leave this schema quietly rejecting it.
|
|
83
|
+
*/
|
|
84
|
+
const StatedLimitSchema = z.object({
|
|
85
|
+
id: z.string(),
|
|
86
|
+
direction: z.enum(LIMIT_DIRECTIONS),
|
|
87
|
+
statement: z.string(),
|
|
88
|
+
}).strict();
|
|
89
|
+
/**
|
|
90
|
+
* What the check run reports beyond its findings.
|
|
91
|
+
*
|
|
92
|
+
* The envelope's `examined` is `membersEnumerated` — what the rules ran
|
|
93
|
+
* AGAINST. `checksRun` is the other denominator, the number of RULES, and both
|
|
94
|
+
* are needed: zero findings is the pass condition and either number at zero
|
|
95
|
+
* makes that pass vacuous.
|
|
96
|
+
*/
|
|
97
|
+
export const CheckDataSchema = z.object({
|
|
98
|
+
root: z.string(),
|
|
99
|
+
/** Whether the projection was derived this run or read from the store. */
|
|
100
|
+
population: z.enum(['derived', 'store']),
|
|
101
|
+
/** What the population cost — charged to no check, see `CheckCost`. */
|
|
102
|
+
populationSecs: z.number().nonnegative(),
|
|
103
|
+
/** What evaluating the lenses cost, paid before the first statement ran. */
|
|
104
|
+
lensSecs: z.number().nonnegative(),
|
|
105
|
+
/**
|
|
106
|
+
* Which lenses that covers — the derived relations this run's checks could
|
|
107
|
+
* actually read. 🔑 An empty list says "no check asked for a derived relation"
|
|
108
|
+
* rather than "a lens stopped running"; without it `lensSecs: 0` is the same
|
|
109
|
+
* document either way, and a gate whose rules silently read empty relations is
|
|
110
|
+
* a gate that cannot fail.
|
|
111
|
+
*/
|
|
112
|
+
lensesEvaluated: z.array(z.string()),
|
|
113
|
+
/**
|
|
114
|
+
* The prose frame {@link CheckDataSchema.limits} is read under. Present
|
|
115
|
+
* exactly when a lens with stated bounds was evaluated.
|
|
116
|
+
*/
|
|
117
|
+
boundsStatement: z.string().optional(),
|
|
118
|
+
/**
|
|
119
|
+
* What the derived rows this run could read do NOT settle — signed and
|
|
120
|
+
* directional, the same list `vat claude context` publishes beside its own
|
|
121
|
+
* answer. Absent when no bounded lens ran: an empty list would claim nothing
|
|
122
|
+
* bounds the answer, which is stronger than "the answer holds no such row".
|
|
123
|
+
*/
|
|
124
|
+
limits: z.array(StatedLimitSchema).optional(),
|
|
125
|
+
/** The number of rules that EXECUTED. Derived from `checks`, never carried beside it. */
|
|
126
|
+
checksRun: z.number().int().nonnegative(),
|
|
127
|
+
/** What each rule cost, directly under the denominator it is the breakdown of. */
|
|
128
|
+
checks: z.array(PublishedCheckCostSchema),
|
|
129
|
+
}).strict();
|
|
130
|
+
/** The document this command publishes. */
|
|
131
|
+
export const CHECK_REPORT_SCHEMA = reportSchema(CheckDataSchema);
|
|
179
132
|
/**
|
|
180
133
|
* The refusal for a run in which NO check executed.
|
|
181
134
|
*
|
|
@@ -209,22 +162,28 @@ import { parseBudgetSeconds, requireSupervisableFlags, runsInThisProcess, superv
|
|
|
209
162
|
* stand-down matters here for an interrupted run, which recovers zero costs when
|
|
210
163
|
* the kill landed before the first statement finished and already carries
|
|
211
164
|
* {@link interruptedRunFinding}, the more specific of the two claims. A `--check`
|
|
212
|
-
* filter that matched nothing is refused earlier by {@link
|
|
165
|
+
* filter that matched nothing is refused earlier by {@link requireKnownCheck},
|
|
213
166
|
* and must stay refused even if that guard is ever widened.
|
|
214
167
|
*
|
|
168
|
+
* 🔑 **An absent `checks:` block does not empty the denominator** — the built-in
|
|
169
|
+
* set is in the pipeline, so reaching zero here means not even a default ran and
|
|
170
|
+
* the remedy is not "declare some checks". The guard stays because it is the
|
|
171
|
+
* mechanism-level guarantee that `checksRun: 0` can never be published clean,
|
|
172
|
+
* whatever empties it.
|
|
173
|
+
*
|
|
215
174
|
* @param costs - One record per check that EXECUTED; its length is `checksRun`
|
|
216
175
|
* @param issues - What the run already found, so an existing run-integrity
|
|
217
176
|
* report is not duplicated
|
|
218
177
|
* @returns The finding, or nothing when at least one check ran
|
|
219
178
|
*/
|
|
220
179
|
function noCheckRanFinding(costs, issues) {
|
|
221
|
-
return nothingCheckedFinding(costs.length, issues, () => 'No check ran, so this document is not a verdict: a gate that checked nothing'
|
|
180
|
+
return nothingCheckedFinding(costs.length, issues, () => 'No check ran at all, so this document is not a verdict: a gate that checked nothing'
|
|
222
181
|
+ ' produces the same report as a gate that was removed, and this run cannot tell'
|
|
223
182
|
+ ' you which happened.'
|
|
224
|
-
+ '
|
|
225
|
-
+ '
|
|
226
|
-
+ '
|
|
227
|
-
+ '
|
|
183
|
+
+ ' This is not an absent `resources.checks` block — VAT\'s own built-in checks run'
|
|
184
|
+
+ ' whether or not a project declares any, so reaching zero means not even those'
|
|
185
|
+
+ ' executed. Re-run with --debug and report it; if the run was filtered, check that'
|
|
186
|
+
+ ' --check named a rule this build still ships.');
|
|
228
187
|
}
|
|
229
188
|
/**
|
|
230
189
|
* Build the check report.
|
|
@@ -241,7 +200,7 @@ function noCheckRanFinding(costs, issues) {
|
|
|
241
200
|
* account for it cannot disagree.
|
|
242
201
|
*
|
|
243
202
|
* 🚨 `populationSecs` and the per-check `durationSecs` do not overlap and do not
|
|
244
|
-
* sum to `
|
|
203
|
+
* sum to `durationMs`. The population is paid once and shared by every check;
|
|
245
204
|
* see {@link CheckCost} for why it is charged to none of them.
|
|
246
205
|
*
|
|
247
206
|
* 🔑 A denominator of zero is refused HERE rather than published — see
|
|
@@ -249,77 +208,76 @@ function noCheckRanFinding(costs, issues) {
|
|
|
249
208
|
* passes through, so deriving the refusal in it is what makes "checked nothing,
|
|
250
209
|
* status clean" unrepresentable rather than merely unwritten.
|
|
251
210
|
*
|
|
211
|
+
* 🪤 The findings are NOT run through `relativizePathEntries`. Every other
|
|
212
|
+
* payload builder re-bases here because its producer keeps absolute paths
|
|
213
|
+
* internally; these arrive project-relative instead, and re-basing an
|
|
214
|
+
* already-relative path would resolve it against the wrong base and silently
|
|
215
|
+
* corrupt it. The guarantee is `locationOf` in `sql-checks.ts` — the one place
|
|
216
|
+
* a projection column becomes a finding's `location`, and which refuses an
|
|
217
|
+
* absolute or backslashed value there. Nothing on this path parses findings
|
|
218
|
+
* through the schema at runtime, and do not "fix" that by parsing at this
|
|
219
|
+
* boundary: it would convert a slip in `locationOf` from "this finding loses
|
|
220
|
+
* its anchor" into "the whole run throws", which is strictly worse for a gate.
|
|
221
|
+
*
|
|
252
222
|
* @param input - The findings and the provenance of the run behind them
|
|
253
223
|
* @returns The document to serialize
|
|
254
224
|
*/
|
|
255
225
|
export function buildCheckOutputData(input) {
|
|
256
226
|
const issues = [...noCheckRanFinding(input.costs, input.issues), ...input.issues];
|
|
257
|
-
return {
|
|
258
|
-
status: calculateValidationStatus(issues),
|
|
259
|
-
root: input.root,
|
|
260
|
-
population: input.population,
|
|
261
|
-
// Beside the origin, because a `population: store` a reader cannot price is
|
|
262
|
-
// a label taken on faith. Charged to no check — see {@link CheckCost}.
|
|
263
|
-
populationSecs: formatDurationSecs(input.populationMs),
|
|
264
|
-
// Published here too, and not only by `query`, because this verb pays it
|
|
265
|
-
// identically — the lens is evaluated before the first statement runs. A
|
|
266
|
-
// document that priced the population but not the lens would attribute the
|
|
267
|
-
// lens's cost to whichever rule the reader happened to be looking at, which
|
|
268
|
-
// is the same defect `populationSecs` exists to prevent.
|
|
269
|
-
lensSecs: formatDurationSecs(input.lensMs),
|
|
270
|
-
// The denominator. See above: without it an empty findings list is
|
|
271
|
-
// ambiguous. Derived from `checks`, never carried beside it.
|
|
272
|
-
checksRun: input.costs.length,
|
|
227
|
+
return buildReport({
|
|
273
228
|
// The OTHER denominator, and the one whose absence shipped a green gate over
|
|
274
229
|
// an empty repository. `checksRun` counts rules; this counts what they ran
|
|
275
|
-
// against.
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
230
|
+
// against.
|
|
231
|
+
examined: input.membersEnumerated,
|
|
232
|
+
findings: toFindings(issues),
|
|
233
|
+
durationMs: input.durationMs,
|
|
234
|
+
data: {
|
|
235
|
+
root: input.root,
|
|
236
|
+
population: input.population,
|
|
237
|
+
// Beside the origin, because a `population: store` a reader cannot price is
|
|
238
|
+
// a label taken on faith. Charged to no check — see {@link CheckCost}.
|
|
239
|
+
populationSecs: formatDurationSecs(input.populationMs),
|
|
240
|
+
// Published here too, and not only by `query`, because this verb pays it
|
|
241
|
+
// identically — the lens is evaluated before the first statement runs. A
|
|
242
|
+
// document that priced the population but not the lens would attribute the
|
|
243
|
+
// lens's cost to whichever rule the reader happened to be looking at, which
|
|
244
|
+
// is the same defect `populationSecs` exists to prevent.
|
|
245
|
+
lensSecs: formatDurationSecs(input.lensMs),
|
|
246
|
+
// What that number covers — see `CheckDataSchema.lensesEvaluated`. Copied
|
|
247
|
+
// into a plain array so the published document owns no reference into the
|
|
248
|
+
// run's own state.
|
|
249
|
+
lensesEvaluated: [...input.lensesEvaluated],
|
|
250
|
+
// The bounds of the rows those lenses produced, stated ONCE and only when
|
|
251
|
+
// a bounded lens ran. This is the verb an adopter makes GATE, so it is the
|
|
252
|
+
// one that most owes them — `utils/relation-limits.ts` carries why.
|
|
253
|
+
// Copied out of the readonly registry lists: the published document owns
|
|
254
|
+
// no reference into module state a later render could mutate.
|
|
255
|
+
...structuredBounds(input.lensesEvaluated),
|
|
256
|
+
// The denominator of rules. Derived from `checks`, never carried beside it.
|
|
257
|
+
checksRun: input.costs.length,
|
|
258
|
+
// What each rule cost, directly under the denominator it is a breakdown
|
|
259
|
+
// of. A SQL surface is an unbounded cost — a project can declare a
|
|
260
|
+
// statement that scans every row of every table — and a single total
|
|
261
|
+
// attributes nothing: ten seconds is one expensive rule, a slow
|
|
262
|
+
// population, or forty cheap rules, and only this list tells them apart.
|
|
263
|
+
//
|
|
264
|
+
// 🪤 `rows` and `broken` are spread conditionally rather than defaulted.
|
|
265
|
+
// `rows: 0` on a statement that never returned would read as a clean pass,
|
|
266
|
+
// which is the exact confusion `RESOURCE_CHECK_BROKEN` exists to prevent —
|
|
267
|
+
// so a check that threw publishes no row count at all.
|
|
268
|
+
checks: input.costs.map((cost) => ({
|
|
269
|
+
name: cost.name,
|
|
270
|
+
// Three significant figures, so a 0.4 ms rule serializes as 0.0004 rather
|
|
271
|
+
// than rounding to a zero that reads as "not measured".
|
|
272
|
+
durationSecs: formatDurationSecs(cost.durationMs),
|
|
273
|
+
...(cost.rows === undefined ? {} : { rows: cost.rows }),
|
|
274
|
+
...(cost.broken === undefined ? {} : { broken: cost.broken }),
|
|
275
|
+
// Absent, never `false`, on a declared rule — so the key's presence is
|
|
276
|
+
// the whole claim and a reader never has to tell `false` from unset.
|
|
277
|
+
...(cost.builtin === undefined ? {} : { builtin: cost.builtin }),
|
|
278
|
+
})),
|
|
279
|
+
},
|
|
280
|
+
});
|
|
323
281
|
}
|
|
324
282
|
/**
|
|
325
283
|
* Run a thunk between two readings of the clock, and report both.
|
|
@@ -380,7 +338,7 @@ function timed(now, run) {
|
|
|
380
338
|
*
|
|
381
339
|
* 🪤 Only `ask` reaches this. Turning the selected rows INTO findings is not a
|
|
382
340
|
* statement failure, and reporting it as one told the operator a working rule
|
|
383
|
-
* was broken — see the append in {@link
|
|
341
|
+
* was broken — see the append in {@link runUnits}.
|
|
384
342
|
*
|
|
385
343
|
* @param name - The check's key in `resources.checks`
|
|
386
344
|
* @param error - Whatever the statement threw
|
|
@@ -391,48 +349,85 @@ function brokenCheckFinding(name, error) {
|
|
|
391
349
|
+ (error instanceof Error ? error.message : String(error)));
|
|
392
350
|
}
|
|
393
351
|
/**
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
* ## What the clock measures, and what it must not
|
|
397
|
-
*
|
|
398
|
-
* The span is `ask(check.sql)` and nothing else — structurally, because it is
|
|
399
|
-
* the thunk handed to {@link timed}, which exists for that reason and documents
|
|
400
|
-
* the mutation that proved an inline stopwatch unguardable. Everything before
|
|
401
|
-
* the loop — the git tracker, `buildResourceProjection`, loading the ephemeral
|
|
402
|
-
* database — is paid ONCE for all of them and reaches the document as
|
|
403
|
-
* `populationSecs`; see {@link CheckCost} for why charging it here would be a
|
|
404
|
-
* lie in N places.
|
|
405
|
-
*
|
|
406
|
-
* ⚠️ `performance.now()`, never `Date.now()`. A rule over a small projection is
|
|
407
|
-
* routinely sub-millisecond, and a millisecond-granularity clock reports every
|
|
408
|
-
* one of them as `0` — which reads as "not measured" and makes the whole
|
|
409
|
-
* attribution worthless exactly where it is cheapest to get right.
|
|
410
|
-
*
|
|
411
|
-
* 🪤 Exactly one cost record per executed check, on both paths, because
|
|
412
|
-
* `checksRun` is this list's length. The record is filed before the rows become
|
|
413
|
-
* findings, so nothing between the two can leave a check unpriced.
|
|
414
|
-
*
|
|
415
|
-
* ## 🚨 Why the loop announces itself before it can be stopped
|
|
416
|
-
*
|
|
417
|
-
* {@link ProgressSink} is told a check is about to run, and told again when it
|
|
418
|
-
* is priced. That ordering is not decoration: this verb runs adopter-authored
|
|
419
|
-
* SQL unattended, an accidental cross join or an unterminated `WITH RECURSIVE`
|
|
420
|
-
* runs forever, and NOTHING in-process can interrupt it — the query is
|
|
421
|
-
* synchronous, it holds the event loop, and `node:sqlite` exposes no interrupt.
|
|
422
|
-
* The supervisor's only lever is an external `SIGKILL`, which publishes nothing
|
|
423
|
-
* of the killed process's memory. So the name of the rule that hangs has to be
|
|
424
|
-
* on disk BEFORE it is entered, or it is not recoverable at all.
|
|
352
|
+
* One declared statement, as a unit.
|
|
425
353
|
*
|
|
354
|
+
* @param name - The check's key in `resources.checks`
|
|
355
|
+
* @param check - Its declaration
|
|
356
|
+
* @param ask - Runs one statement against the populated projection
|
|
357
|
+
* @returns The runnable unit
|
|
358
|
+
*/
|
|
359
|
+
function sqlCheckUnit(name, check, ask) {
|
|
360
|
+
return {
|
|
361
|
+
name,
|
|
362
|
+
select: () => {
|
|
363
|
+
const rows = ask(check.sql);
|
|
364
|
+
return { rows: rows.length, report: () => issuesFromCheckRows(name, check, rows) };
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* One built-in predicate, as a unit.
|
|
370
|
+
*
|
|
371
|
+
* 🪤 Its `rows` is the finding count, and that is the same quantity a statement
|
|
372
|
+
* reports: one finding per violating row. There is no conversion step to leave
|
|
373
|
+
* outside the clock, so the whole predicate is timed.
|
|
374
|
+
*
|
|
375
|
+
* @param builtin - The built-in, already bound to this run's projection
|
|
376
|
+
* @returns The runnable unit
|
|
377
|
+
*/
|
|
378
|
+
function builtinCheckUnit(builtin) {
|
|
379
|
+
return {
|
|
380
|
+
name: builtin.name,
|
|
381
|
+
builtin: true,
|
|
382
|
+
select: () => {
|
|
383
|
+
const issues = builtin.run();
|
|
384
|
+
return { rows: issues.length, report: () => issues };
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Every check this run will attempt, in the order it will attempt them.
|
|
390
|
+
*
|
|
391
|
+
* 🔑 **Built-ins FIRST, and never interleaved with the declared ones**, so the
|
|
392
|
+
* document's `checks[]` opens with the same rules in the same order for every
|
|
393
|
+
* project and a reader comparing two runs compares like with like.
|
|
394
|
+
*
|
|
395
|
+
* 🪤 A project MAY declare a check whose key equals a built-in's name. Both run,
|
|
396
|
+
* both are priced, `builtin` on the cost record tells them apart, and
|
|
397
|
+
* `--check <name>` selects both. Not refused: a new config error is a breaking
|
|
398
|
+
* change and nothing about the collision is unsafe.
|
|
399
|
+
*
|
|
400
|
+
* @param builtins - The default set, bound to this run's projection
|
|
426
401
|
* @param checks - The project's `resources.checks`
|
|
427
|
-
* @param only - A single check key to run, or undefined for all of them
|
|
428
402
|
* @param ask - Runs one statement against the populated projection
|
|
403
|
+
* @returns The units, built-ins first
|
|
404
|
+
*/
|
|
405
|
+
function checkUnits(builtins, checks, ask) {
|
|
406
|
+
return [
|
|
407
|
+
...builtins.map((builtin) => builtinCheckUnit(builtin)),
|
|
408
|
+
...Object.entries(checks).map(([name, check]) => sqlCheckUnit(name, check, ask)),
|
|
409
|
+
];
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Run every unit, collect its findings, and price it.
|
|
413
|
+
*
|
|
414
|
+
* 🚨 **The timed span is `unit.select()` and nothing else** — structurally,
|
|
415
|
+
* because it is the thunk handed to {@link timed}. 🚨 **And the loop announces a
|
|
416
|
+
* check BEFORE it can be stopped**, because a runaway statement can only be
|
|
417
|
+
* ended by an external `SIGKILL` that publishes nothing of the killed process's
|
|
418
|
+
* memory. Both, with the clock-granularity and one-record-per-check rules they
|
|
419
|
+
* rest on: `docs/architecture/cli.md`, "The population is charged to NOBODY" and
|
|
420
|
+
* "Why the loop announces a check before it can be stopped".
|
|
421
|
+
*
|
|
422
|
+
* @param units - Every check this run will attempt, built-ins first
|
|
423
|
+
* @param only - A single check name to run, or undefined for all of them
|
|
429
424
|
* @param now - The clock, in milliseconds; injected so a test can assert an
|
|
430
425
|
* exact duration rather than a range that passes on a timer that never started
|
|
431
426
|
* @param onProgress - Told what is about to run and what it cost, or undefined
|
|
432
427
|
* when nothing is watching (the in-process lane, and `--budget 0`)
|
|
433
428
|
* @returns The findings, and one cost record per check that ran
|
|
434
429
|
*/
|
|
435
|
-
function
|
|
430
|
+
function runUnits(units, only, now, onProgress) {
|
|
436
431
|
const issues = [];
|
|
437
432
|
const costs = [];
|
|
438
433
|
/** File the cost with the observer as well as with the caller — one place. */
|
|
@@ -440,23 +435,28 @@ function runChecks(checks, only, ask, now, onProgress) {
|
|
|
440
435
|
costs.push(cost);
|
|
441
436
|
onProgress?.({ kind: 'check', ...cost });
|
|
442
437
|
};
|
|
443
|
-
for (const
|
|
438
|
+
for (const unit of units) {
|
|
439
|
+
const { name } = unit;
|
|
444
440
|
if (only !== undefined && name !== only)
|
|
445
441
|
continue;
|
|
442
|
+
// Spread onto every cost record this unit files, so the two arms below
|
|
443
|
+
// cannot disagree about which set the rule came from.
|
|
444
|
+
const origin = unit.builtin === undefined ? {} : { builtin: unit.builtin };
|
|
446
445
|
// 🪤 BEFORE `timed`, and not one line later. `ask` is where a runaway
|
|
447
446
|
// statement never returns from, so an announcement below it is filed by
|
|
448
447
|
// every check except the one whose name the operator needs.
|
|
449
448
|
onProgress?.({ kind: 'start', name });
|
|
450
|
-
const outcome = timed(now,
|
|
449
|
+
const outcome = timed(now, unit.select);
|
|
451
450
|
if (!outcome.ok) {
|
|
452
|
-
// Priced up to the throw, and with NO row count: a
|
|
451
|
+
// Priced up to the throw, and with NO row count: a check that did not
|
|
453
452
|
// complete selected nothing, and `rows: 0` would say it selected nothing
|
|
454
|
-
// and passed.
|
|
455
|
-
|
|
453
|
+
// and passed. A built-in reaches this arm too — a defect in VAT's own
|
|
454
|
+
// predicate must fail the gate rather than vanish.
|
|
455
|
+
price({ name, durationMs: outcome.durationMs, broken: true, ...origin });
|
|
456
456
|
issues.push(brokenCheckFinding(name, outcome.error));
|
|
457
457
|
continue;
|
|
458
458
|
}
|
|
459
|
-
price({ name, durationMs: outcome.durationMs, rows: outcome.value.
|
|
459
|
+
price({ name, durationMs: outcome.durationMs, rows: outcome.value.rows, ...origin });
|
|
460
460
|
// 🪤 Appended one at a time, NEVER `issues.push(...findings)`. A spread
|
|
461
461
|
// becomes an ARGUMENT LIST, which throws `RangeError: Maximum call stack
|
|
462
462
|
// size exceeded` past roughly 125,000 elements on the main thread — and a
|
|
@@ -466,44 +466,49 @@ function runChecks(checks, only, ask, now, onProgress) {
|
|
|
466
466
|
// the throw landed in the arm above: a rule that ran perfectly was reported
|
|
467
467
|
// as one that "could not run, so it is asserting nothing". A loop does not
|
|
468
468
|
// put the argument limit in play at all.
|
|
469
|
-
for (const issue of
|
|
469
|
+
for (const issue of outcome.value.report())
|
|
470
470
|
issues.push(issue);
|
|
471
471
|
}
|
|
472
472
|
return { issues, costs };
|
|
473
473
|
}
|
|
474
474
|
/**
|
|
475
|
-
* Refuse a `--check` name
|
|
475
|
+
* Refuse a `--check` name that names neither a built-in nor a declared check.
|
|
476
476
|
*
|
|
477
|
-
* 🔑 **An unknown name
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
* That is not a hypothetical typo: `vat resources check --check orphan-skills`
|
|
485
|
-
* is the example in this command's own help text. Rename or delete that check
|
|
486
|
-
* and the CI step keeps passing forever while asserting nothing.
|
|
477
|
+
* 🔑 **An unknown name is otherwise a silent green.** With nothing comparing the
|
|
478
|
+
* flag against the known names, `--check nope` filters every check away, runs
|
|
479
|
+
* none, and exits 0 with `checksRun: 0` and `issues: []` on empty stderr — and
|
|
480
|
+
* the "no checks are declared" warning does not fire, because it asks whether
|
|
481
|
+
* the `checks` MAP is empty, never whether the FILTER matched anything. Not a
|
|
482
|
+
* hypothetical typo: rename or delete a check and the CI step keeps passing
|
|
483
|
+
* forever while asserting nothing.
|
|
487
484
|
*
|
|
488
485
|
* Thrown rather than reported as a finding, because it is an OPERATOR error and
|
|
489
486
|
* not a content violation — the two have different exit codes in this command's
|
|
490
487
|
* contract (2 versus 1) and different audiences. Thrown before the projection is
|
|
491
488
|
* populated, so a mistyped flag costs no crawl.
|
|
492
489
|
*
|
|
490
|
+
* 🔑 **A built-in is nameable here exactly like a declared one.** A guard that
|
|
491
|
+
* only knew the config would refuse the very rules that run when there is no
|
|
492
|
+
* config at all. The refusal names both sets.
|
|
493
|
+
*
|
|
494
|
+
* @param builtinNames - The default set's names — {@link BUILTIN_CHECK_NAMES} in
|
|
495
|
+
* production, and passed in rather than imported here so a test can prove the
|
|
496
|
+
* guard rather than restate the constant
|
|
493
497
|
* @param checks - The project's `resources.checks`
|
|
494
498
|
* @param only - The `--check` value, or undefined
|
|
495
|
-
* @throws When `only` names no
|
|
499
|
+
* @throws When `only` names no check this run would attempt
|
|
496
500
|
*/
|
|
497
|
-
export function
|
|
501
|
+
export function requireKnownCheck(builtinNames, checks, only) {
|
|
498
502
|
// 🪤 `Object.hasOwn`, not `only in checks`. `in` walks the prototype chain, so
|
|
499
503
|
// `--check toString` would have looked declared, matched nothing, and restored
|
|
500
504
|
// the exact silent green this guard closes.
|
|
501
|
-
if (only === undefined || Object.hasOwn(checks, only))
|
|
505
|
+
if (only === undefined || builtinNames.includes(only) || Object.hasOwn(checks, only))
|
|
502
506
|
return;
|
|
503
507
|
const declared = Object.keys(checks);
|
|
504
|
-
throw new Error(`No check named "${only}"
|
|
508
|
+
throw new Error(`No check named "${only}" exists. `
|
|
509
|
+
+ `Built in: ${builtinNames.join(', ')}. `
|
|
505
510
|
+ (declared.length === 0
|
|
506
|
-
? 'This project declares none — add them under `resources.checks` in'
|
|
511
|
+
? 'This project declares none of its own — add them under `resources.checks` in'
|
|
507
512
|
+ ' vibe-agent-toolkit.config.yaml.'
|
|
508
513
|
: `Declared under \`resources.checks\`: ${declared.join(', ')}.`));
|
|
509
514
|
}
|
|
@@ -511,7 +516,7 @@ export function requireDeclaredCheck(checks, only) {
|
|
|
511
516
|
* Name every `CUSTOM:` severity override that overrides nothing.
|
|
512
517
|
*
|
|
513
518
|
* 🔑 **The same silent-green shape as an unknown `--check` name, one surface
|
|
514
|
-
* over.** {@link
|
|
519
|
+
* over.** {@link requireKnownCheck} refuses `--check nope` because a filter
|
|
515
520
|
* that matched nothing ran nothing and exited 0. A `validation.severity` entry
|
|
516
521
|
* keyed `CUSTOM:<name>` for a check that is not declared is the mirror image: it
|
|
517
522
|
* parses (the schema validates the KEY's shape and cannot see
|
|
@@ -544,7 +549,7 @@ export function requireDeclaredCheck(checks, only) {
|
|
|
544
549
|
export function warnUndeclaredOverrides(checks, validation, logger) {
|
|
545
550
|
const stale = Object.keys(validation?.severity ?? {})
|
|
546
551
|
.filter((code) => isCustomCheckCode(code))
|
|
547
|
-
// 🪤 `Object.hasOwn`, not `in` — same reason {@link
|
|
552
|
+
// 🪤 `Object.hasOwn`, not `in` — same reason {@link requireKnownCheck}
|
|
548
553
|
// uses it: `in` walks the prototype chain, so an override keyed
|
|
549
554
|
// `CUSTOM:toString` would look declared and stay silent.
|
|
550
555
|
.filter((code) => !Object.hasOwn(checks, code.slice(CUSTOM_CHECK_CODE_PREFIX.length)));
|
|
@@ -967,7 +972,7 @@ function noPopulationMessage(ending) {
|
|
|
967
972
|
* honest value — and inventing `membersEnumerated: 0` would be worse than a
|
|
968
973
|
* blank, because that value already MEANS "this gate ran over an empty corpus",
|
|
969
974
|
* which is a different and wrong claim. The throw becomes an operator error
|
|
970
|
-
* (exit 2) through the same `
|
|
975
|
+
* (exit 2) through the same `handleReportCommandError` path everything else here uses.
|
|
971
976
|
*
|
|
972
977
|
* @param options - The wreckage
|
|
973
978
|
* @param options.entries - What `parseProgressLog` recovered
|
|
@@ -988,6 +993,7 @@ export function buildInterruptedCheckInput(options) {
|
|
|
988
993
|
population: population.population,
|
|
989
994
|
populationMs: population.populationMs,
|
|
990
995
|
lensMs: population.lensMs,
|
|
996
|
+
lensesEvaluated: population.lensesEvaluated,
|
|
991
997
|
membersEnumerated: population.membersEnumerated,
|
|
992
998
|
issues: [interruptedRunFinding(unitInFlight(entries), ending)],
|
|
993
999
|
// 🪤 Rebuilt field by field rather than passed through. The log's check
|
|
@@ -1000,12 +1006,19 @@ export function buildInterruptedCheckInput(options) {
|
|
|
1000
1006
|
durationMs: entry.durationMs,
|
|
1001
1007
|
...(entry.rows === undefined ? {} : { rows: entry.rows }),
|
|
1002
1008
|
...(entry.broken === undefined ? {} : { broken: entry.broken }),
|
|
1009
|
+
...(entry.builtin === undefined ? {} : { builtin: entry.builtin }),
|
|
1003
1010
|
})),
|
|
1004
1011
|
};
|
|
1005
1012
|
}
|
|
1006
1013
|
/**
|
|
1007
|
-
* Run
|
|
1008
|
-
* verb's logic, with
|
|
1014
|
+
* Run this project's checks — VAT's default set plus whatever the project
|
|
1015
|
+
* declared — and resolve their severities: the whole of this verb's logic, with
|
|
1016
|
+
* the database taken out.
|
|
1017
|
+
*
|
|
1018
|
+
* 🔑 **`builtins` is a required argument beside `checks`, never a default inside
|
|
1019
|
+
* this function.** That is what makes "the default set belongs to the pipeline,
|
|
1020
|
+
* not to the config file" a property of the signature — nobody can get the
|
|
1021
|
+
* defaults by omitting an argument or lose them by supplying no config.
|
|
1009
1022
|
*
|
|
1010
1023
|
* Exported and pure so the loop is provable without a spawn. It was not: every
|
|
1011
1024
|
* spawned case declared ONE check (the `--check` case declares two and filters
|
|
@@ -1018,8 +1031,11 @@ export function buildInterruptedCheckInput(options) {
|
|
|
1018
1031
|
* trust.
|
|
1019
1032
|
*
|
|
1020
1033
|
* @param options - The run
|
|
1034
|
+
* @param options.builtins - The default set, already bound to this run's
|
|
1035
|
+
* projection. Required, and `[]` is a deliberate statement rather than an
|
|
1036
|
+
* omission
|
|
1021
1037
|
* @param options.checks - The declared checks
|
|
1022
|
-
* @param options.only - A single check
|
|
1038
|
+
* @param options.only - A single check name, or undefined for all
|
|
1023
1039
|
* @param options.ask - Runs one statement against the populated projection
|
|
1024
1040
|
* @param options.validation - The project's severity overrides, or undefined
|
|
1025
1041
|
* @param options.membersEnumerated - How many members the population enumerated.
|
|
@@ -1034,9 +1050,9 @@ export function buildInterruptedCheckInput(options) {
|
|
|
1034
1050
|
* unit case run with nobody watching
|
|
1035
1051
|
* @returns The resolved findings, and one cost record per check that ran
|
|
1036
1052
|
*/
|
|
1037
|
-
export function
|
|
1053
|
+
export function runProjectChecks(options) {
|
|
1038
1054
|
const now = options.now ?? (() => performance.now());
|
|
1039
|
-
const { issues, costs } =
|
|
1055
|
+
const { issues, costs } = runUnits(checkUnits(options.builtins, options.checks, options.ask), options.only, now, options.onProgress);
|
|
1040
1056
|
// 🚨 HERE, and this line moved to get here. `checks-complete` buys the phase
|
|
1041
1057
|
// after the last statement a fresh watchdog window, and three places
|
|
1042
1058
|
// documented that phase as "resolving severities and serialising". It was
|
|
@@ -1047,7 +1063,7 @@ export function runDeclaredChecks(options) {
|
|
|
1047
1063
|
// which is the useful direction: the alternative was to weaken three docs.
|
|
1048
1064
|
//
|
|
1049
1065
|
// ⚠️ It does NOT cover the last check's row-to-issue conversion, which
|
|
1050
|
-
// `
|
|
1066
|
+
// `runUnits` does after filing that check's cost — see {@link inFlightPhrase}
|
|
1051
1067
|
// for why the `idle` sentence still has to hedge for that window.
|
|
1052
1068
|
options.onProgress?.({ kind: 'checks-complete' });
|
|
1053
1069
|
// The run-integrity report leads. An aggregate check selects a row whatever
|
|
@@ -1064,6 +1080,12 @@ export function runDeclaredChecks(options) {
|
|
|
1064
1080
|
// It reaches a check's VIOLATIONS only. `RESOURCE_CHECK_BROKEN` is not an
|
|
1065
1081
|
// overridable code, so the news that a check stopped checking survives every
|
|
1066
1082
|
// override an adopter can write about the check itself.
|
|
1083
|
+
//
|
|
1084
|
+
// 🔑 A BUILT-IN's findings pass through the identical call, under their
|
|
1085
|
+
// ordinary registry code: `severity: { CLAUDE_RULE_GLOB_INERT: ignore }`
|
|
1086
|
+
// silences the default exactly as it silences any other code VAT emits, with
|
|
1087
|
+
// no `CUSTOM:` spelling and no second override surface. That the two lanes
|
|
1088
|
+
// share this one line is the reason there is nothing to keep in step.
|
|
1067
1089
|
issues: resolveIssueSeverity(reported, options.validation),
|
|
1068
1090
|
costs,
|
|
1069
1091
|
};
|
|
@@ -1079,12 +1101,7 @@ export function runDeclaredChecks(options) {
|
|
|
1079
1101
|
* @param format - `json`, or anything else for YAML
|
|
1080
1102
|
*/
|
|
1081
1103
|
function emitCheckDocument(payload, format) {
|
|
1082
|
-
|
|
1083
|
-
writeJsonOutput(payload);
|
|
1084
|
-
}
|
|
1085
|
-
else {
|
|
1086
|
-
writeYamlOutput(payload);
|
|
1087
|
-
}
|
|
1104
|
+
writeStructuredOutput(payload, format);
|
|
1088
1105
|
}
|
|
1089
1106
|
/**
|
|
1090
1107
|
* The child's argv — this very command, plus the hidden flag that stops it
|
|
@@ -1227,26 +1244,31 @@ export async function checkCommand(pathArg, options) {
|
|
|
1227
1244
|
process.exit(ending.code);
|
|
1228
1245
|
}
|
|
1229
1246
|
emitCheckDocument(ending.payload, options.format);
|
|
1230
|
-
// ⛔ Never
|
|
1231
|
-
// its own memory — must not look like a pass.
|
|
1232
|
-
|
|
1247
|
+
// ⛔ Never OK. A run that did not finish — killed by the watchdog OR dead of
|
|
1248
|
+
// its own memory — must not look like a pass. FINDINGS, because the
|
|
1249
|
+
// document it just published says `status: findings` with the killed
|
|
1250
|
+
// check named as one: the checks that completed are kept, and the exit
|
|
1251
|
+
// code follows the document, as everywhere else.
|
|
1252
|
+
process.exit(ExitCode.FINDINGS);
|
|
1233
1253
|
}
|
|
1234
1254
|
const projectRoot = projectRootOrLoudCwd(pathArg ?? process.cwd(), logger);
|
|
1235
1255
|
const config = loadConfigCached(projectRoot);
|
|
1236
1256
|
const checks = config?.resources?.checks;
|
|
1237
1257
|
if (checks === undefined || Object.keys(checks).length === 0) {
|
|
1238
|
-
// 🪤 Stderr only, and it decides NOTHING
|
|
1239
|
-
//
|
|
1240
|
-
//
|
|
1241
|
-
// the
|
|
1242
|
-
//
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
+ ' vibe-agent-toolkit.config.yaml;
|
|
1246
|
-
+ ' statement selecting the rows that VIOLATE it.'
|
|
1258
|
+
// 🪤 Stderr only, and it decides NOTHING — the document is what the exit
|
|
1259
|
+
// code is computed from and what CI parses. ⚠️ It does not stand beside a
|
|
1260
|
+
// refusal: the built-in set runs here, so this run DID assert something.
|
|
1261
|
+
// What the operator needs to know is that the project is relying entirely
|
|
1262
|
+
// on VAT's defaults, which is what a deleted `checks:` block looks like.
|
|
1263
|
+
logger.warn(`No checks of this project's own are declared, so this run asserted only VAT's`
|
|
1264
|
+
+ ` built-in set (${BUILTIN_CHECK_NAMES.join(', ')}).`
|
|
1265
|
+
+ ' Add your own under `resources.checks` in vibe-agent-toolkit.config.yaml;'
|
|
1266
|
+
+ ' each is a description plus one SQL statement selecting the rows that VIOLATE it.'
|
|
1267
|
+
+ ' `vat resources check --help` prints the SQL each built-in is equivalent to,'
|
|
1268
|
+
+ ' as a starting point.');
|
|
1247
1269
|
}
|
|
1248
1270
|
// Before the crawl: a mistyped flag is an operator error and pays nothing.
|
|
1249
|
-
|
|
1271
|
+
requireKnownCheck(BUILTIN_CHECK_NAMES, checks ?? {}, options.check);
|
|
1250
1272
|
// Also before the crawl, and for the same reason: an override that overrides
|
|
1251
1273
|
// nothing is knowable from the config alone, and the operator should read it
|
|
1252
1274
|
// beside the other config news rather than after a full population.
|
|
@@ -1267,10 +1289,10 @@ export async function checkCommand(pathArg, options) {
|
|
|
1267
1289
|
durationMs: Date.now() - startTime,
|
|
1268
1290
|
});
|
|
1269
1291
|
emitCheckDocument(payload, options.format);
|
|
1270
|
-
process.exit(payload
|
|
1292
|
+
process.exit(payload.summary.errors > 0 ? ExitCode.FINDINGS : ExitCode.OK);
|
|
1271
1293
|
}
|
|
1272
1294
|
catch (error) {
|
|
1273
|
-
|
|
1295
|
+
handleReportCommandError(error, logger, startTime, 'Check', options.format);
|
|
1274
1296
|
}
|
|
1275
1297
|
}
|
|
1276
1298
|
/**
|
|
@@ -1298,7 +1320,13 @@ async function runOutcome(options) {
|
|
|
1298
1320
|
// bare throw, and the finding exists precisely so a renamed column cannot end a
|
|
1299
1321
|
// gate quietly. The population is the price of an honest report, and it is
|
|
1300
1322
|
// charged once for every check rather than per broken one.
|
|
1301
|
-
|
|
1323
|
+
// 🔑 `statements` IS passed, and it is a different question from `preflight`:
|
|
1324
|
+
// it only decides which derived relations are evaluated. Every declared
|
|
1325
|
+
// statement goes in, including one `--check` narrows away — the lens is per
|
|
1326
|
+
// RUN, and narrowing it would make `--check foo` and a full run disagree about
|
|
1327
|
+
// which relations exist.
|
|
1328
|
+
const statements = Object.values(checks).map((check) => check.sql);
|
|
1329
|
+
return withQueriedProjection({ root, logger, statements }, (ask, provenance, extent, projection) => {
|
|
1302
1330
|
// 🔑 Emitted HERE, inside the callback, because this is the one place where
|
|
1303
1331
|
// the provenance and the extent are both exactly in hand — and emitted the
|
|
1304
1332
|
// INSTANT population completes, because its arrival is what tells a
|
|
@@ -1310,14 +1338,27 @@ async function runOutcome(options) {
|
|
|
1310
1338
|
population: provenance.population,
|
|
1311
1339
|
populationMs: provenance.populationMs,
|
|
1312
1340
|
lensMs: provenance.lensMs,
|
|
1341
|
+
lensesEvaluated: [...provenance.lensesEvaluated],
|
|
1313
1342
|
membersEnumerated: extent.membersEnumerated,
|
|
1314
1343
|
});
|
|
1315
1344
|
// 🪤 `checks-complete` is NOT emitted here. It used to be, and that put
|
|
1316
|
-
// `resolveIssueSeverity` — which runs inside `
|
|
1345
|
+
// `resolveIssueSeverity` — which runs inside `runProjectChecks` — on the
|
|
1317
1346
|
// wrong side of the line, still charged to the last check's budget window
|
|
1318
1347
|
// while three separate docs said otherwise. It is emitted by
|
|
1319
|
-
// `
|
|
1320
|
-
|
|
1348
|
+
// `runProjectChecks` itself now, the instant the last statement is done.
|
|
1349
|
+
//
|
|
1350
|
+
// 🔑 The DEFAULT SET enters HERE, from a module constant bound to the
|
|
1351
|
+
// projection — never from `config`, which this line does not read. That is
|
|
1352
|
+
// the placement the "defaults belong to the pipeline" invariant is about.
|
|
1353
|
+
const ran = runProjectChecks({
|
|
1354
|
+
builtins: bindBuiltinChecks(projection),
|
|
1355
|
+
checks,
|
|
1356
|
+
only,
|
|
1357
|
+
ask,
|
|
1358
|
+
validation,
|
|
1359
|
+
...extent,
|
|
1360
|
+
onProgress,
|
|
1361
|
+
});
|
|
1321
1362
|
return { ...ran, ...provenance, ...extent };
|
|
1322
1363
|
});
|
|
1323
1364
|
}
|