@vibe-agent-toolkit/cli 0.2.0-rc.11 → 0.2.0-rc.12
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 +3 -3
- package/dist/bin/supervise-cli.d.ts +45 -0
- package/dist/bin/supervise-cli.d.ts.map +1 -0
- package/dist/bin/supervise-cli.js +83 -0
- package/dist/bin/supervise-cli.js.map +1 -0
- package/dist/bin/vat +95 -43
- package/dist/bin/vat.d.ts +15 -4
- package/dist/bin/vat.d.ts.map +1 -1
- package/dist/bin/vat.js +95 -43
- package/dist/bin/vat.js.map +1 -1
- package/dist/bin.js +21 -29
- package/dist/bin.js.map +1 -1
- package/dist/command-tree.d.ts +45 -0
- package/dist/command-tree.d.ts.map +1 -0
- package/dist/command-tree.js +60 -0
- package/dist/command-tree.js.map +1 -0
- package/dist/commands/agent/build-schema.d.ts +100 -0
- package/dist/commands/agent/build-schema.d.ts.map +1 -0
- package/dist/commands/agent/build-schema.js +32 -0
- package/dist/commands/agent/build-schema.js.map +1 -0
- package/dist/commands/agent/build.d.ts +1 -0
- package/dist/commands/agent/build.d.ts.map +1 -1
- package/dist/commands/agent/build.js +63 -33
- package/dist/commands/agent/build.js.map +1 -1
- package/dist/commands/agent/import-schema.d.ts +75 -0
- package/dist/commands/agent/import-schema.d.ts.map +1 -0
- package/dist/commands/agent/import-schema.js +25 -0
- package/dist/commands/agent/import-schema.js.map +1 -0
- package/dist/commands/agent/import.d.ts.map +1 -1
- package/dist/commands/agent/import.js +33 -27
- package/dist/commands/agent/import.js.map +1 -1
- package/dist/commands/agent/index.d.ts.map +1 -1
- package/dist/commands/agent/index.js +132 -37
- package/dist/commands/agent/index.js.map +1 -1
- package/dist/commands/agent/install-path.d.ts.map +1 -1
- package/dist/commands/agent/install-path.js +2 -1
- package/dist/commands/agent/install-path.js.map +1 -1
- package/dist/commands/agent/install-schema.d.ts +89 -0
- package/dist/commands/agent/install-schema.d.ts.map +1 -0
- package/dist/commands/agent/install-schema.js +29 -0
- package/dist/commands/agent/install-schema.js.map +1 -0
- package/dist/commands/agent/install.d.ts +7 -1
- package/dist/commands/agent/install.d.ts.map +1 -1
- package/dist/commands/agent/install.js +78 -108
- package/dist/commands/agent/install.js.map +1 -1
- package/dist/commands/agent/installed-schema.d.ts +140 -0
- package/dist/commands/agent/installed-schema.d.ts.map +1 -0
- package/dist/commands/agent/installed-schema.js +36 -0
- package/dist/commands/agent/installed-schema.js.map +1 -0
- package/dist/commands/agent/installed.d.ts +1 -1
- package/dist/commands/agent/installed.d.ts.map +1 -1
- package/dist/commands/agent/installed.js +104 -75
- package/dist/commands/agent/installed.js.map +1 -1
- package/dist/commands/agent/list-schema.d.ts +128 -0
- package/dist/commands/agent/list-schema.d.ts.map +1 -0
- package/dist/commands/agent/list-schema.js +34 -0
- package/dist/commands/agent/list-schema.js.map +1 -0
- package/dist/commands/agent/list.d.ts +4 -3
- package/dist/commands/agent/list.d.ts.map +1 -1
- package/dist/commands/agent/list.js +50 -37
- package/dist/commands/agent/list.js.map +1 -1
- package/dist/commands/agent/run.d.ts +3 -0
- package/dist/commands/agent/run.d.ts.map +1 -1
- package/dist/commands/agent/run.js +8 -3
- package/dist/commands/agent/run.js.map +1 -1
- package/dist/commands/agent/uninstall-schema.d.ts +89 -0
- package/dist/commands/agent/uninstall-schema.d.ts.map +1 -0
- package/dist/commands/agent/uninstall-schema.js +29 -0
- package/dist/commands/agent/uninstall-schema.js.map +1 -0
- package/dist/commands/agent/uninstall.d.ts +5 -1
- package/dist/commands/agent/uninstall.d.ts.map +1 -1
- package/dist/commands/agent/uninstall.js +50 -38
- package/dist/commands/agent/uninstall.js.map +1 -1
- package/dist/commands/agent/validate-schema.d.ts +129 -0
- package/dist/commands/agent/validate-schema.d.ts.map +1 -0
- package/dist/commands/agent/validate-schema.js +35 -0
- package/dist/commands/agent/validate-schema.js.map +1 -0
- package/dist/commands/agent/validate.d.ts +6 -0
- package/dist/commands/agent/validate.d.ts.map +1 -1
- package/dist/commands/agent/validate.js +64 -36
- package/dist/commands/agent/validate.js.map +1 -1
- package/dist/commands/ard/emit-schema.d.ts +108 -0
- package/dist/commands/ard/emit-schema.d.ts.map +1 -0
- package/dist/commands/ard/emit-schema.js +37 -0
- package/dist/commands/ard/emit-schema.js.map +1 -0
- package/dist/commands/ard/emit.d.ts +21 -65
- package/dist/commands/ard/emit.d.ts.map +1 -1
- package/dist/commands/ard/emit.js +68 -74
- package/dist/commands/ard/emit.js.map +1 -1
- package/dist/commands/ard/index.d.ts.map +1 -1
- package/dist/commands/ard/index.js +14 -11
- package/dist/commands/ard/index.js.map +1 -1
- package/dist/commands/audit/compat-lane-findings.d.ts +65 -0
- package/dist/commands/audit/compat-lane-findings.d.ts.map +1 -0
- package/dist/commands/audit/compat-lane-findings.js +72 -0
- package/dist/commands/audit/compat-lane-findings.js.map +1 -0
- package/dist/commands/audit/distributed-tree.d.ts +2 -2
- package/dist/commands/audit/distributed-tree.d.ts.map +1 -1
- package/dist/commands/audit/distributed-tree.js +23 -12
- package/dist/commands/audit/distributed-tree.js.map +1 -1
- package/dist/commands/audit/git-url-clone.d.ts +15 -7
- package/dist/commands/audit/git-url-clone.d.ts.map +1 -1
- package/dist/commands/audit/git-url-clone.js +85 -42
- package/dist/commands/audit/git-url-clone.js.map +1 -1
- package/dist/commands/audit/hierarchical-output.d.ts +28 -4
- package/dist/commands/audit/hierarchical-output.d.ts.map +1 -1
- package/dist/commands/audit/hierarchical-output.js +44 -27
- package/dist/commands/audit/hierarchical-output.js.map +1 -1
- package/dist/commands/audit/scan-population.d.ts.map +1 -1
- package/dist/commands/audit/scan-population.js +2 -1
- package/dist/commands/audit/scan-population.js.map +1 -1
- package/dist/commands/audit-schema.d.ts +1247 -0
- package/dist/commands/audit-schema.d.ts.map +1 -0
- package/dist/commands/audit-schema.js +139 -0
- package/dist/commands/audit-schema.js.map +1 -0
- package/dist/commands/audit-settings-schema.d.ts +417 -0
- package/dist/commands/audit-settings-schema.d.ts.map +1 -0
- package/dist/commands/audit-settings-schema.js +77 -0
- package/dist/commands/audit-settings-schema.js.map +1 -0
- package/dist/commands/audit-settings.d.ts +28 -9
- package/dist/commands/audit-settings.d.ts.map +1 -1
- package/dist/commands/audit-settings.js +215 -151
- package/dist/commands/audit-settings.js.map +1 -1
- package/dist/commands/audit.d.ts +72 -33
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +405 -411
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/build.d.ts +61 -4
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +176 -190
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/cache/clear-schema.d.ts +111 -0
- package/dist/commands/cache/clear-schema.d.ts.map +1 -0
- package/dist/commands/cache/clear-schema.js +37 -0
- package/dist/commands/cache/clear-schema.js.map +1 -0
- package/dist/commands/cache/clear.d.ts +28 -26
- package/dist/commands/cache/clear.d.ts.map +1 -1
- package/dist/commands/cache/clear.js +108 -103
- 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 +13 -7
- package/dist/commands/cache/index.js.map +1 -1
- package/dist/commands/claude/claude-config.d.ts +23 -6
- package/dist/commands/claude/claude-config.d.ts.map +1 -1
- package/dist/commands/claude/claude-config.js +29 -15
- package/dist/commands/claude/claude-config.js.map +1 -1
- package/dist/commands/claude/context.d.ts +55 -2
- package/dist/commands/claude/context.d.ts.map +1 -1
- package/dist/commands/claude/context.js +74 -50
- package/dist/commands/claude/context.js.map +1 -1
- package/dist/commands/claude/marketplace/changelog-utils.js +2 -2
- package/dist/commands/claude/marketplace/changelog-utils.js.map +1 -1
- package/dist/commands/claude/marketplace/git-publish.d.ts +14 -1
- package/dist/commands/claude/marketplace/git-publish.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/git-publish.js +135 -68
- package/dist/commands/claude/marketplace/git-publish.js.map +1 -1
- package/dist/commands/claude/marketplace/license-utils.d.ts +3 -5
- package/dist/commands/claude/marketplace/license-utils.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/license-utils.js +16 -7
- package/dist/commands/claude/marketplace/license-utils.js.map +1 -1
- package/dist/commands/claude/marketplace/publish-schema.d.ts +137 -0
- package/dist/commands/claude/marketplace/publish-schema.d.ts.map +1 -0
- package/dist/commands/claude/marketplace/publish-schema.js +32 -0
- package/dist/commands/claude/marketplace/publish-schema.js.map +1 -0
- package/dist/commands/claude/marketplace/publish-tree.d.ts +6 -0
- package/dist/commands/claude/marketplace/publish-tree.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/publish-tree.js +75 -17
- package/dist/commands/claude/marketplace/publish-tree.js.map +1 -1
- package/dist/commands/claude/marketplace/publish.d.ts +27 -0
- package/dist/commands/claude/marketplace/publish.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/publish.js +84 -50
- package/dist/commands/claude/marketplace/publish.js.map +1 -1
- package/dist/commands/claude/marketplace/validate-schema.d.ts +362 -0
- package/dist/commands/claude/marketplace/validate-schema.d.ts.map +1 -0
- package/dist/commands/claude/marketplace/validate-schema.js +67 -0
- package/dist/commands/claude/marketplace/validate-schema.js.map +1 -0
- package/dist/commands/claude/marketplace/validate.d.ts +40 -53
- package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/validate.js +358 -214
- package/dist/commands/claude/marketplace/validate.js.map +1 -1
- package/dist/commands/claude/org/api-keys.d.ts +3 -0
- package/dist/commands/claude/org/api-keys.d.ts.map +1 -1
- package/dist/commands/claude/org/api-keys.js +4 -5
- package/dist/commands/claude/org/api-keys.js.map +1 -1
- package/dist/commands/claude/org/code-analytics.js +1 -1
- package/dist/commands/claude/org/code-analytics.js.map +1 -1
- package/dist/commands/claude/org/cost.d.ts.map +1 -1
- package/dist/commands/claude/org/cost.js +11 -33
- package/dist/commands/claude/org/cost.js.map +1 -1
- package/dist/commands/claude/org/helpers.d.ts +40 -27
- package/dist/commands/claude/org/helpers.d.ts.map +1 -1
- package/dist/commands/claude/org/helpers.js +61 -66
- package/dist/commands/claude/org/helpers.js.map +1 -1
- package/dist/commands/claude/org/index.d.ts.map +1 -1
- package/dist/commands/claude/org/index.js +10 -4
- package/dist/commands/claude/org/index.js.map +1 -1
- package/dist/commands/claude/org/info.d.ts.map +1 -1
- package/dist/commands/claude/org/info.js +2 -3
- package/dist/commands/claude/org/info.js.map +1 -1
- package/dist/commands/claude/org/invites.d.ts +3 -0
- package/dist/commands/claude/org/invites.d.ts.map +1 -1
- package/dist/commands/claude/org/invites.js +5 -7
- package/dist/commands/claude/org/invites.js.map +1 -1
- package/dist/commands/claude/org/skills.d.ts +76 -21
- package/dist/commands/claude/org/skills.d.ts.map +1 -1
- package/dist/commands/claude/org/skills.js +273 -246
- package/dist/commands/claude/org/skills.js.map +1 -1
- package/dist/commands/claude/org/stubs-schema.d.ts +56 -0
- package/dist/commands/claude/org/stubs-schema.d.ts.map +1 -0
- package/dist/commands/claude/org/stubs-schema.js +23 -0
- package/dist/commands/claude/org/stubs-schema.js.map +1 -0
- package/dist/commands/claude/org/stubs.d.ts +8 -3
- package/dist/commands/claude/org/stubs.d.ts.map +1 -1
- package/dist/commands/claude/org/stubs.js +9 -9
- package/dist/commands/claude/org/stubs.js.map +1 -1
- package/dist/commands/claude/org/usage.d.ts.map +1 -1
- package/dist/commands/claude/org/usage.js +1 -2
- package/dist/commands/claude/org/usage.js.map +1 -1
- package/dist/commands/claude/org/users.d.ts +3 -0
- package/dist/commands/claude/org/users.d.ts.map +1 -1
- package/dist/commands/claude/org/users.js +6 -8
- package/dist/commands/claude/org/users.js.map +1 -1
- package/dist/commands/claude/org/workspaces.d.ts +3 -0
- package/dist/commands/claude/org/workspaces.d.ts.map +1 -1
- package/dist/commands/claude/org/workspaces.js +10 -15
- package/dist/commands/claude/org/workspaces.js.map +1 -1
- package/dist/commands/claude/plugin/build-schema.d.ts +642 -0
- package/dist/commands/claude/plugin/build-schema.d.ts.map +1 -0
- package/dist/commands/claude/plugin/build-schema.js +51 -0
- package/dist/commands/claude/plugin/build-schema.js.map +1 -0
- package/dist/commands/claude/plugin/build.d.ts +220 -45
- package/dist/commands/claude/plugin/build.d.ts.map +1 -1
- package/dist/commands/claude/plugin/build.js +466 -249
- package/dist/commands/claude/plugin/build.js.map +1 -1
- package/dist/commands/claude/plugin/helpers.d.ts +186 -24
- package/dist/commands/claude/plugin/helpers.d.ts.map +1 -1
- package/dist/commands/claude/plugin/helpers.js +110 -68
- package/dist/commands/claude/plugin/helpers.js.map +1 -1
- package/dist/commands/claude/plugin/install-schema.d.ts +144 -0
- package/dist/commands/claude/plugin/install-schema.d.ts.map +1 -0
- package/dist/commands/claude/plugin/install-schema.js +36 -0
- package/dist/commands/claude/plugin/install-schema.js.map +1 -0
- package/dist/commands/claude/plugin/install.d.ts +191 -11
- package/dist/commands/claude/plugin/install.d.ts.map +1 -1
- package/dist/commands/claude/plugin/install.js +688 -628
- package/dist/commands/claude/plugin/install.js.map +1 -1
- package/dist/commands/claude/plugin/kept-findings.d.ts +19 -0
- package/dist/commands/claude/plugin/kept-findings.d.ts.map +1 -0
- package/dist/commands/claude/plugin/kept-findings.js +24 -0
- package/dist/commands/claude/plugin/kept-findings.js.map +1 -0
- package/dist/commands/claude/plugin/list-schema.d.ts +223 -0
- package/dist/commands/claude/plugin/list-schema.d.ts.map +1 -0
- package/dist/commands/claude/plugin/list-schema.js +34 -0
- package/dist/commands/claude/plugin/list-schema.js.map +1 -0
- package/dist/commands/claude/plugin/list.d.ts +18 -0
- package/dist/commands/claude/plugin/list.d.ts.map +1 -1
- package/dist/commands/claude/plugin/list.js +53 -45
- package/dist/commands/claude/plugin/list.js.map +1 -1
- package/dist/commands/claude/plugin/npm-pack.d.ts +15 -0
- package/dist/commands/claude/plugin/npm-pack.d.ts.map +1 -0
- package/dist/commands/claude/plugin/npm-pack.js +39 -0
- package/dist/commands/claude/plugin/npm-pack.js.map +1 -0
- package/dist/commands/claude/plugin/plugin-changelog.d.ts +5 -1
- package/dist/commands/claude/plugin/plugin-changelog.d.ts.map +1 -1
- package/dist/commands/claude/plugin/plugin-changelog.js +9 -5
- package/dist/commands/claude/plugin/plugin-changelog.js.map +1 -1
- package/dist/commands/claude/plugin/plugin-files.d.ts +21 -2
- package/dist/commands/claude/plugin/plugin-files.d.ts.map +1 -1
- package/dist/commands/claude/plugin/plugin-files.js +65 -32
- package/dist/commands/claude/plugin/plugin-files.js.map +1 -1
- package/dist/commands/claude/plugin/plugin-validators.d.ts +13 -0
- package/dist/commands/claude/plugin/plugin-validators.d.ts.map +1 -1
- package/dist/commands/claude/plugin/plugin-validators.js +64 -16
- package/dist/commands/claude/plugin/plugin-validators.js.map +1 -1
- package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
- package/dist/commands/claude/plugin/tree-copy.js +63 -37
- package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
- package/dist/commands/claude/plugin/uninstall-schema.d.ts +112 -0
- package/dist/commands/claude/plugin/uninstall-schema.d.ts.map +1 -0
- package/dist/commands/claude/plugin/uninstall-schema.js +28 -0
- package/dist/commands/claude/plugin/uninstall-schema.js.map +1 -0
- package/dist/commands/claude/plugin/uninstall.d.ts +57 -0
- package/dist/commands/claude/plugin/uninstall.d.ts.map +1 -1
- package/dist/commands/claude/plugin/uninstall.js +176 -64
- package/dist/commands/claude/plugin/uninstall.js.map +1 -1
- package/dist/commands/consistency-check.d.ts.map +1 -1
- package/dist/commands/consistency-check.js +8 -6
- package/dist/commands/consistency-check.js.map +1 -1
- package/dist/commands/corpus/index.d.ts.map +1 -1
- package/dist/commands/corpus/index.js +26 -10
- package/dist/commands/corpus/index.js.map +1 -1
- package/dist/commands/corpus/report.d.ts +34 -16
- package/dist/commands/corpus/report.d.ts.map +1 -1
- package/dist/commands/corpus/report.js +36 -18
- package/dist/commands/corpus/report.js.map +1 -1
- package/dist/commands/corpus/runner.d.ts +25 -20
- package/dist/commands/corpus/runner.d.ts.map +1 -1
- package/dist/commands/corpus/runner.js +123 -67
- package/dist/commands/corpus/runner.js.map +1 -1
- package/dist/commands/corpus/scan-schema.d.ts +127 -0
- package/dist/commands/corpus/scan-schema.d.ts.map +1 -0
- package/dist/commands/corpus/scan-schema.js +31 -0
- package/dist/commands/corpus/scan-schema.js.map +1 -0
- package/dist/commands/corpus/scan.d.ts +31 -0
- package/dist/commands/corpus/scan.d.ts.map +1 -1
- package/dist/commands/corpus/scan.js +124 -50
- package/dist/commands/corpus/scan.js.map +1 -1
- package/dist/commands/corpus/seed.d.ts +11 -8
- package/dist/commands/corpus/seed.d.ts.map +1 -1
- package/dist/commands/corpus/seed.js +29 -11
- package/dist/commands/corpus/seed.js.map +1 -1
- package/dist/commands/doctor-render.d.ts +52 -0
- package/dist/commands/doctor-render.d.ts.map +1 -0
- package/dist/commands/doctor-render.js +110 -0
- package/dist/commands/doctor-render.js.map +1 -0
- package/dist/commands/doctor-schema.d.ts +191 -0
- package/dist/commands/doctor-schema.d.ts.map +1 -0
- package/dist/commands/doctor-schema.js +44 -0
- package/dist/commands/doctor-schema.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -62
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +126 -165
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/inventory-schema.d.ts +7297 -0
- package/dist/commands/inventory-schema.d.ts.map +1 -0
- package/dist/commands/inventory-schema.js +28 -0
- package/dist/commands/inventory-schema.js.map +1 -0
- package/dist/commands/inventory.d.ts +1 -1
- package/dist/commands/inventory.d.ts.map +1 -1
- package/dist/commands/inventory.js +89 -41
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/mcp/index.d.ts.map +1 -1
- package/dist/commands/mcp/index.js +15 -0
- package/dist/commands/mcp/index.js.map +1 -1
- package/dist/commands/mcp/list-collections-schema.d.ts +101 -0
- package/dist/commands/mcp/list-collections-schema.d.ts.map +1 -0
- package/dist/commands/mcp/list-collections-schema.js +22 -0
- package/dist/commands/mcp/list-collections-schema.js.map +1 -0
- package/dist/commands/mcp/list-collections.d.ts +1 -1
- package/dist/commands/mcp/list-collections.d.ts.map +1 -1
- package/dist/commands/mcp/list-collections.js +19 -17
- package/dist/commands/mcp/list-collections.js.map +1 -1
- package/dist/commands/mcp/serve.d.ts +5 -0
- package/dist/commands/mcp/serve.d.ts.map +1 -1
- package/dist/commands/mcp/serve.js +29 -15
- 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 +6 -5
- package/dist/commands/okf/index.js.map +1 -1
- package/dist/commands/okf/validate-schema.d.ts +171 -0
- package/dist/commands/okf/validate-schema.d.ts.map +1 -0
- package/dist/commands/okf/validate-schema.js +44 -0
- package/dist/commands/okf/validate-schema.js.map +1 -0
- package/dist/commands/okf/validate.d.ts +16 -149
- package/dist/commands/okf/validate.d.ts.map +1 -1
- package/dist/commands/okf/validate.js +64 -62
- package/dist/commands/okf/validate.js.map +1 -1
- package/dist/commands/orchestrator-schema.d.ts +419 -0
- package/dist/commands/orchestrator-schema.d.ts.map +1 -0
- package/dist/commands/orchestrator-schema.js +91 -0
- package/dist/commands/orchestrator-schema.js.map +1 -0
- package/dist/commands/phase-utils.d.ts +188 -220
- package/dist/commands/phase-utils.d.ts.map +1 -1
- package/dist/commands/phase-utils.js +210 -258
- package/dist/commands/phase-utils.js.map +1 -1
- package/dist/commands/positional-args.d.ts +13 -11
- package/dist/commands/positional-args.d.ts.map +1 -1
- package/dist/commands/positional-args.js +16 -15
- package/dist/commands/positional-args.js.map +1 -1
- package/dist/commands/rag/admin-schema.d.ts +152 -0
- package/dist/commands/rag/admin-schema.d.ts.map +1 -0
- package/dist/commands/rag/admin-schema.js +31 -0
- package/dist/commands/rag/admin-schema.js.map +1 -0
- package/dist/commands/rag/clear-command.d.ts.map +1 -1
- package/dist/commands/rag/clear-command.js +30 -15
- package/dist/commands/rag/clear-command.js.map +1 -1
- package/dist/commands/rag/command-helpers.d.ts +31 -7
- package/dist/commands/rag/command-helpers.d.ts.map +1 -1
- package/dist/commands/rag/command-helpers.js +41 -21
- package/dist/commands/rag/command-helpers.js.map +1 -1
- package/dist/commands/rag/index-command.d.ts +37 -48
- package/dist/commands/rag/index-command.d.ts.map +1 -1
- package/dist/commands/rag/index-command.js +80 -65
- package/dist/commands/rag/index-command.js.map +1 -1
- package/dist/commands/rag/index-schema.d.ts +107 -0
- package/dist/commands/rag/index-schema.d.ts.map +1 -0
- package/dist/commands/rag/index-schema.js +34 -0
- package/dist/commands/rag/index-schema.js.map +1 -0
- package/dist/commands/rag/index.d.ts.map +1 -1
- package/dist/commands/rag/index.js +88 -41
- package/dist/commands/rag/index.js.map +1 -1
- package/dist/commands/rag/query-command.d.ts +18 -4
- package/dist/commands/rag/query-command.d.ts.map +1 -1
- package/dist/commands/rag/query-command.js +42 -27
- package/dist/commands/rag/query-command.js.map +1 -1
- package/dist/commands/rag/query-schema.d.ts +363 -0
- package/dist/commands/rag/query-schema.d.ts.map +1 -0
- package/dist/commands/rag/query-schema.js +59 -0
- package/dist/commands/rag/query-schema.js.map +1 -0
- package/dist/commands/rag/stats-command.d.ts.map +1 -1
- package/dist/commands/rag/stats-command.js +19 -18
- package/dist/commands/rag/stats-command.js.map +1 -1
- package/dist/commands/resources/check-progress.d.ts +64 -11
- package/dist/commands/resources/check-progress.d.ts.map +1 -1
- package/dist/commands/resources/check-progress.js +77 -4
- package/dist/commands/resources/check-progress.js.map +1 -1
- package/dist/commands/resources/check-schema.d.ts +335 -0
- package/dist/commands/resources/check-schema.d.ts.map +1 -0
- package/dist/commands/resources/check-schema.js +104 -0
- package/dist/commands/resources/check-schema.js.map +1 -0
- package/dist/commands/resources/check-supervisor.d.ts +315 -71
- package/dist/commands/resources/check-supervisor.d.ts.map +1 -1
- package/dist/commands/resources/check-supervisor.js +493 -107
- package/dist/commands/resources/check-supervisor.js.map +1 -1
- package/dist/commands/resources/check.d.ts +56 -249
- package/dist/commands/resources/check.d.ts.map +1 -1
- package/dist/commands/resources/check.js +416 -276
- 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 +165 -91
- package/dist/commands/resources/index.js.map +1 -1
- package/dist/commands/resources/query-schema.d.ts +188 -0
- package/dist/commands/resources/query-schema.d.ts.map +1 -0
- package/dist/commands/resources/query-schema.js +48 -0
- package/dist/commands/resources/query-schema.js.map +1 -0
- package/dist/commands/resources/query.d.ts +17 -12
- package/dist/commands/resources/query.d.ts.map +1 -1
- package/dist/commands/resources/query.js +60 -48
- package/dist/commands/resources/query.js.map +1 -1
- package/dist/commands/resources/scan-schema.d.ts +195 -0
- package/dist/commands/resources/scan-schema.d.ts.map +1 -0
- package/dist/commands/resources/scan-schema.js +53 -0
- package/dist/commands/resources/scan-schema.js.map +1 -0
- package/dist/commands/resources/scan.d.ts +26 -3
- package/dist/commands/resources/scan.d.ts.map +1 -1
- package/dist/commands/resources/scan.js +51 -53
- package/dist/commands/resources/scan.js.map +1 -1
- package/dist/commands/resources/validate-schema.d.ts +326 -0
- package/dist/commands/resources/validate-schema.d.ts.map +1 -0
- package/dist/commands/resources/validate-schema.js +60 -0
- package/dist/commands/resources/validate-schema.js.map +1 -0
- package/dist/commands/resources/validate.d.ts +45 -169
- package/dist/commands/resources/validate.d.ts.map +1 -1
- package/dist/commands/resources/validate.js +221 -485
- package/dist/commands/resources/validate.js.map +1 -1
- package/dist/commands/skill/review-checklist.d.ts.map +1 -1
- package/dist/commands/skill/review-checklist.js +0 -1
- package/dist/commands/skill/review-checklist.js.map +1 -1
- package/dist/commands/skill/review-schema.d.ts +278 -0
- package/dist/commands/skill/review-schema.d.ts.map +1 -0
- package/dist/commands/skill/review-schema.js +46 -0
- package/dist/commands/skill/review-schema.js.map +1 -0
- package/dist/commands/skill/review.d.ts +8 -234
- package/dist/commands/skill/review.d.ts.map +1 -1
- package/dist/commands/skill/review.js +54 -78
- package/dist/commands/skill/review.js.map +1 -1
- package/dist/commands/skill/test/auth-flags.d.ts +3 -0
- package/dist/commands/skill/test/auth-flags.d.ts.map +1 -1
- package/dist/commands/skill/test/auth-flags.js +6 -2
- package/dist/commands/skill/test/auth-flags.js.map +1 -1
- package/dist/commands/skill/test/configure-schema.d.ts +67 -0
- package/dist/commands/skill/test/configure-schema.d.ts.map +1 -0
- package/dist/commands/skill/test/configure-schema.js +27 -0
- package/dist/commands/skill/test/configure-schema.js.map +1 -0
- package/dist/commands/skill/test/configure.d.ts +12 -5
- package/dist/commands/skill/test/configure.d.ts.map +1 -1
- package/dist/commands/skill/test/configure.js +101 -31
- package/dist/commands/skill/test/configure.js.map +1 -1
- package/dist/commands/skill/test/run-schema.d.ts +107 -0
- package/dist/commands/skill/test/run-schema.d.ts.map +1 -0
- package/dist/commands/skill/test/run-schema.js +36 -0
- package/dist/commands/skill/test/run-schema.js.map +1 -0
- package/dist/commands/skill/test/run.d.ts +3 -2
- package/dist/commands/skill/test/run.d.ts.map +1 -1
- package/dist/commands/skill/test/run.js +316 -155
- package/dist/commands/skill/test/run.js.map +1 -1
- package/dist/commands/skills/build-schema.d.ts +199 -0
- package/dist/commands/skills/build-schema.d.ts.map +1 -0
- package/dist/commands/skills/build-schema.js +55 -0
- package/dist/commands/skills/build-schema.js.map +1 -0
- package/dist/commands/skills/build.d.ts +95 -298
- package/dist/commands/skills/build.d.ts.map +1 -1
- package/dist/commands/skills/build.js +415 -818
- package/dist/commands/skills/build.js.map +1 -1
- package/dist/commands/skills/command-helpers.d.ts +5 -11
- package/dist/commands/skills/command-helpers.d.ts.map +1 -1
- package/dist/commands/skills/command-helpers.js +7 -17
- package/dist/commands/skills/command-helpers.js.map +1 -1
- package/dist/commands/skills/index.js +12 -6
- package/dist/commands/skills/index.js.map +1 -1
- package/dist/commands/skills/install-schema.d.ts +153 -0
- package/dist/commands/skills/install-schema.d.ts.map +1 -0
- package/dist/commands/skills/install-schema.js +44 -0
- package/dist/commands/skills/install-schema.js.map +1 -0
- package/dist/commands/skills/install.d.ts +76 -8
- package/dist/commands/skills/install.d.ts.map +1 -1
- package/dist/commands/skills/install.js +230 -194
- package/dist/commands/skills/install.js.map +1 -1
- package/dist/commands/skills/list-schema.d.ts +145 -0
- package/dist/commands/skills/list-schema.d.ts.map +1 -0
- package/dist/commands/skills/list-schema.js +37 -0
- package/dist/commands/skills/list-schema.js.map +1 -0
- package/dist/commands/skills/list.d.ts +39 -8
- package/dist/commands/skills/list.d.ts.map +1 -1
- package/dist/commands/skills/list.js +110 -122
- package/dist/commands/skills/list.js.map +1 -1
- package/dist/commands/skills/package-schema.d.ts +98 -0
- package/dist/commands/skills/package-schema.d.ts.map +1 -0
- package/dist/commands/skills/package-schema.js +32 -0
- package/dist/commands/skills/package-schema.js.map +1 -0
- package/dist/commands/skills/package.d.ts +85 -14
- package/dist/commands/skills/package.d.ts.map +1 -1
- package/dist/commands/skills/package.js +288 -207
- package/dist/commands/skills/package.js.map +1 -1
- package/dist/commands/skills/scope-guard.d.ts +27 -20
- package/dist/commands/skills/scope-guard.d.ts.map +1 -1
- package/dist/commands/skills/scope-guard.js +43 -32
- package/dist/commands/skills/scope-guard.js.map +1 -1
- package/dist/commands/skills/skill-discovery.d.ts +1 -1
- package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
- package/dist/commands/skills/skill-discovery.js +40 -19
- package/dist/commands/skills/skill-discovery.js.map +1 -1
- package/dist/commands/skills/source-resolvers.d.ts +58 -8
- package/dist/commands/skills/source-resolvers.d.ts.map +1 -1
- package/dist/commands/skills/source-resolvers.js +113 -38
- package/dist/commands/skills/source-resolvers.js.map +1 -1
- package/dist/commands/skills/validate-command.d.ts.map +1 -1
- package/dist/commands/skills/validate-command.js +31 -51
- package/dist/commands/skills/validate-command.js.map +1 -1
- package/dist/commands/skills/validate-schema.d.ts +199 -0
- package/dist/commands/skills/validate-schema.d.ts.map +1 -0
- package/dist/commands/skills/validate-schema.js +44 -0
- package/dist/commands/skills/validate-schema.js.map +1 -0
- package/dist/commands/skills/validate.d.ts +100 -136
- package/dist/commands/skills/validate.d.ts.map +1 -1
- package/dist/commands/skills/validate.js +257 -343
- package/dist/commands/skills/validate.js.map +1 -1
- package/dist/commands/validate.d.ts +17 -5
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +139 -94
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/verify.d.ts +121 -110
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +230 -294
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/report-schemas.d.ts +12398 -35
- package/dist/report-schemas.d.ts.map +1 -1
- package/dist/report-schemas.js +624 -66
- package/dist/report-schemas.js.map +1 -1
- package/dist/skill-resolution/packaging-config.js +2 -2
- package/dist/skill-resolution/packaging-config.js.map +1 -1
- package/dist/skill-resolution/resolve-skill-reference.d.ts.map +1 -1
- package/dist/skill-resolution/resolve-skill-reference.js +20 -13
- package/dist/skill-resolution/resolve-skill-reference.js.map +1 -1
- package/dist/utils/agent-discovery.d.ts +34 -1
- package/dist/utils/agent-discovery.d.ts.map +1 -1
- package/dist/utils/agent-discovery.js +80 -38
- package/dist/utils/agent-discovery.js.map +1 -1
- package/dist/utils/claude-context-lens.d.ts +13 -6
- package/dist/utils/claude-context-lens.d.ts.map +1 -1
- package/dist/utils/claude-context-lens.js +11 -12
- package/dist/utils/claude-context-lens.js.map +1 -1
- package/dist/utils/command-error-codes.d.ts +12 -0
- package/dist/utils/command-error-codes.d.ts.map +1 -0
- package/dist/utils/command-error-codes.js +12 -0
- package/dist/utils/command-error-codes.js.map +1 -0
- package/dist/utils/command-refusal.d.ts +58 -0
- package/dist/utils/command-refusal.d.ts.map +1 -0
- package/dist/utils/command-refusal.js +170 -0
- package/dist/utils/command-refusal.js.map +1 -0
- package/dist/utils/commander-ending.d.ts +40 -0
- package/dist/utils/commander-ending.d.ts.map +1 -0
- package/dist/utils/commander-ending.js +42 -0
- package/dist/utils/commander-ending.js.map +1 -0
- package/dist/utils/config-loader.d.ts +13 -8
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +84 -45
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/corpus-target.d.ts +1 -1
- package/dist/utils/corpus-target.d.ts.map +1 -1
- package/dist/utils/corpus-target.js +6 -4
- package/dist/utils/corpus-target.js.map +1 -1
- package/dist/utils/debug-diagnostics.d.ts +18 -0
- package/dist/utils/debug-diagnostics.d.ts.map +1 -0
- package/dist/utils/debug-diagnostics.js +23 -0
- package/dist/utils/debug-diagnostics.js.map +1 -0
- package/dist/utils/document-writer.d.ts +191 -0
- package/dist/utils/document-writer.d.ts.map +1 -0
- package/dist/utils/document-writer.js +319 -0
- package/dist/utils/document-writer.js.map +1 -0
- package/dist/utils/help-loader.d.ts +2 -2
- package/dist/utils/help-loader.js +2 -2
- package/dist/utils/install-plan.d.ts +99 -0
- package/dist/utils/install-plan.d.ts.map +1 -0
- package/dist/utils/install-plan.js +146 -0
- package/dist/utils/install-plan.js.map +1 -0
- package/dist/utils/issue-anchor.d.ts +1 -1
- package/dist/utils/issue-anchor.d.ts.map +1 -1
- package/dist/utils/issue-anchor.js.map +1 -1
- package/dist/utils/issue-rendering.d.ts +8 -3
- package/dist/utils/issue-rendering.d.ts.map +1 -1
- package/dist/utils/issue-rendering.js +4 -0
- package/dist/utils/issue-rendering.js.map +1 -1
- package/dist/utils/lens-population.d.ts +20 -0
- package/dist/utils/lens-population.d.ts.map +1 -0
- package/dist/utils/lens-population.js +15 -0
- package/dist/utils/lens-population.js.map +1 -0
- package/dist/utils/marketplace-io.d.ts +63 -0
- package/dist/utils/marketplace-io.d.ts.map +1 -0
- package/dist/utils/marketplace-io.js +63 -0
- package/dist/utils/marketplace-io.js.map +1 -0
- package/dist/utils/operator-notices.d.ts +97 -0
- package/dist/utils/operator-notices.d.ts.map +1 -0
- package/dist/utils/operator-notices.js +115 -0
- package/dist/utils/operator-notices.js.map +1 -0
- package/dist/utils/optional-backend.d.ts +18 -15
- package/dist/utils/optional-backend.d.ts.map +1 -1
- package/dist/utils/optional-backend.js +22 -33
- package/dist/utils/optional-backend.js.map +1 -1
- package/dist/utils/output.d.ts +5 -43
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +8 -63
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/package-json.d.ts +3 -4
- package/dist/utils/package-json.d.ts.map +1 -1
- package/dist/utils/package-json.js +8 -8
- package/dist/utils/package-json.js.map +1 -1
- package/dist/utils/population-wiring.d.ts +31 -38
- package/dist/utils/population-wiring.d.ts.map +1 -1
- package/dist/utils/population-wiring.js +38 -32
- package/dist/utils/population-wiring.js.map +1 -1
- package/dist/utils/project-root-policy.d.ts +74 -1
- package/dist/utils/project-root-policy.d.ts.map +1 -1
- package/dist/utils/project-root-policy.js +146 -8
- package/dist/utils/project-root-policy.js.map +1 -1
- package/dist/utils/projection-lenses.d.ts +25 -7
- package/dist/utils/projection-lenses.d.ts.map +1 -1
- package/dist/utils/projection-lenses.js +20 -6
- package/dist/utils/projection-lenses.js.map +1 -1
- package/dist/utils/projection-query.d.ts +17 -10
- package/dist/utils/projection-query.d.ts.map +1 -1
- package/dist/utils/projection-query.js +47 -28
- package/dist/utils/projection-query.js.map +1 -1
- package/dist/utils/projection-store.d.ts +2 -2
- package/dist/utils/projection-store.d.ts.map +1 -1
- package/dist/utils/projection-store.js +74 -45
- package/dist/utils/projection-store.js.map +1 -1
- package/dist/utils/rag-database.d.ts +61 -0
- package/dist/utils/rag-database.d.ts.map +1 -0
- package/dist/utils/rag-database.js +178 -0
- package/dist/utils/rag-database.js.map +1 -0
- package/dist/utils/relation-limits.d.ts +7 -2
- package/dist/utils/relation-limits.d.ts.map +1 -1
- package/dist/utils/relation-limits.js +6 -1
- package/dist/utils/relation-limits.js.map +1 -1
- package/dist/utils/relativize-paths.d.ts +23 -0
- package/dist/utils/relativize-paths.d.ts.map +1 -1
- package/dist/utils/relativize-paths.js +32 -1
- package/dist/utils/relativize-paths.js.map +1 -1
- package/dist/utils/resource-loader.d.ts +76 -32
- package/dist/utils/resource-loader.d.ts.map +1 -1
- package/dist/utils/resource-loader.js +132 -66
- package/dist/utils/resource-loader.js.map +1 -1
- package/dist/utils/run-integrity.d.ts +64 -31
- package/dist/utils/run-integrity.d.ts.map +1 -1
- package/dist/utils/run-integrity.js +76 -35
- package/dist/utils/run-integrity.js.map +1 -1
- package/dist/utils/scope-locations.d.ts +7 -5
- package/dist/utils/scope-locations.d.ts.map +1 -1
- package/dist/utils/scope-locations.js +37 -12
- package/dist/utils/scope-locations.js.map +1 -1
- package/dist/utils/staging-dir.d.ts +7 -0
- package/dist/utils/staging-dir.d.ts.map +1 -0
- package/dist/utils/staging-dir.js +12 -0
- package/dist/utils/staging-dir.js.map +1 -0
- package/dist/utils/url-redact.d.ts +9 -0
- package/dist/utils/url-redact.d.ts.map +1 -1
- package/dist/utils/url-redact.js +13 -0
- package/dist/utils/url-redact.js.map +1 -1
- package/dist/utils/user-context-scanner.d.ts +3 -2
- package/dist/utils/user-context-scanner.d.ts.map +1 -1
- package/dist/utils/user-context-scanner.js +24 -4
- 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 +8 -14
- 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 +3 -3
- package/dist/utils/vat-bin-path.js.map +1 -1
- package/dist/utils/verdict-helpers.d.ts.map +1 -1
- package/dist/utils/verdict-helpers.js +5 -5
- package/dist/utils/verdict-helpers.js.map +1 -1
- package/docs/agent.md +347 -2
- package/docs/audit.md +312 -89
- package/docs/doctor.md +65 -19
- package/docs/index.md +571 -20
- package/docs/mcp.md +64 -12
- package/docs/rag.md +176 -48
- package/docs/resources.md +257 -71
- package/docs/skill-test.md +148 -19
- package/docs/skills.md +459 -174
- package/package.json +16 -19
- package/schemas/agent-build.json +268 -0
- package/schemas/agent-import.json +252 -0
- package/schemas/agent-install.json +260 -0
- package/schemas/agent-installed.json +287 -0
- package/schemas/agent-list.json +279 -0
- package/schemas/agent-uninstall.json +260 -0
- package/schemas/agent-validate.json +279 -0
- package/schemas/ard-emit.json +224 -106
- package/schemas/audit-settings.json +472 -0
- package/schemas/audit.json +635 -0
- package/schemas/cache-clear.json +273 -0
- package/schemas/claude-marketplace-publish.json +286 -0
- package/schemas/claude-marketplace-validate.json +352 -0
- package/schemas/claude-org-not-implemented.json +239 -0
- package/schemas/claude-plugin-build.json +446 -0
- package/schemas/claude-plugin-install.json +291 -0
- package/schemas/claude-plugin-list.json +326 -0
- package/schemas/claude-plugin-uninstall.json +272 -0
- package/schemas/corpus-audit.json +635 -0
- package/schemas/corpus-scan.json +293 -0
- package/schemas/doctor.json +299 -0
- package/schemas/inventory.json +982 -0
- package/schemas/mcp-list-collections.json +268 -0
- package/schemas/okf-validate.json +224 -106
- package/schemas/orchestrator.json +299 -0
- package/schemas/rag-clear.json +253 -0
- package/schemas/rag-index.json +273 -0
- package/schemas/rag-query.json +365 -0
- package/schemas/rag-stats.json +269 -0
- package/schemas/resources-check.json +242 -108
- package/schemas/resources-query.json +333 -0
- package/schemas/resources-scan.json +321 -0
- package/schemas/resources-validate.json +332 -0
- package/schemas/skill-review.json +224 -106
- package/schemas/skill-test-configure.json +256 -0
- package/schemas/skill-test-run.json +296 -0
- package/schemas/skills-build.json +325 -0
- package/schemas/skills-install.json +287 -0
- package/schemas/skills-list.json +283 -0
- package/schemas/skills-package.json +270 -0
- package/schemas/skills-validate.json +285 -0
- package/dist/commands/skills/shared.d.ts +0 -29
- package/dist/commands/skills/shared.d.ts.map +0 -1
- package/dist/commands/skills/shared.js +0 -33
- package/dist/commands/skills/shared.js.map +0 -1
- package/dist/utils/command-error.d.ts +0 -194
- package/dist/utils/command-error.d.ts.map +0 -1
- package/dist/utils/command-error.js +0 -237
- package/dist/utils/command-error.js.map +0 -1
package/dist/commands/audit.js
CHANGED
|
@@ -3,32 +3,33 @@
|
|
|
3
3
|
* Top-level command: vat audit [path]
|
|
4
4
|
*/
|
|
5
5
|
import * as fs from 'node:fs';
|
|
6
|
-
import { existsSync as fsExistsSync } from 'node:fs';
|
|
7
6
|
import { basename } from 'node:path';
|
|
8
|
-
import { conventionalSuiteProbe, crawlAndResolveRegistry, detectDeclaredButMissing, detectMarketplacePluginSourceMissing, resetPackagingRegistryCache, detectPresentButUndeclared, detectReferenceTargetMissing, detectResourceFormat, enumerateSurfaces, materializeIssue, validate, validateMarketplace, validateSkill, validateSkillForPackaging, } from '@vibe-agent-toolkit/agent-skills';
|
|
7
|
+
import { conventionalSuiteProbe, crawlAndResolveRegistry, detectDeclaredButMissing, detectMarketplacePluginSourceMissing, resetPackagingRegistryCache, detectPresentButUndeclared, detectReferenceTargetMissing, describeIssues, detectResourceFormat, enumerateSurfaces, materializeIssue, validate, validateMarketplace, validateSkill, validateSkillForPackaging, } from '@vibe-agent-toolkit/agent-skills';
|
|
9
8
|
import { analyzeCompatibility, checkSettingsCompatibility, detectSkillClaudePluginNameMismatch, crawlSkillLinkRegistry, extractClaudeMarketplaceInventory, extractClaudePluginInventory, getClaudeUserPaths, readEffectiveSettings, validatePlugin, } from '@vibe-agent-toolkit/claude-marketplace';
|
|
10
9
|
import { detectFormat } from '@vibe-agent-toolkit/discovery';
|
|
11
10
|
import { listingRefusalRemedy } from '@vibe-agent-toolkit/resources';
|
|
12
|
-
import {
|
|
13
|
-
import { findProjectRoot,
|
|
11
|
+
import { buildReport, countBySeverity, exitCodeForReport, summarizeIssues, toFindings, withAddedFindings, } from '@vibe-agent-toolkit/schema';
|
|
12
|
+
import { everywhere, findProjectRoot, followedKind, followedKindSync, forEachInOrder, fsFaultOf, isPathAbsentError, issueLocation, mapInOrder, pathPresent, relativeEscapesRoot, resetProjectRootCaches, safePath, toForwardSlash, } from '@vibe-agent-toolkit/utils';
|
|
14
13
|
import { DirectoryListingRefusedError } from '@vibe-agent-toolkit/utils/crawl';
|
|
15
14
|
import { gitFindRoot, isGitUrl, parseGitUrl, } from '@vibe-agent-toolkit/utils/git';
|
|
16
15
|
import { Command } from 'commander';
|
|
17
16
|
import { resetSkillDiscoveryCache, resolveProjectDeclaredEvalSuites, resolveSkillPackagingConfig, stripValidationAllowForDisplay, } from '../skill-resolution/packaging-config.js';
|
|
18
|
-
import {
|
|
17
|
+
import { CommandRefusalError, errorMessageOf, refusalCodeOf } from '../utils/command-refusal.js';
|
|
19
18
|
import { ConfigLoadError, loadConfig, resetLoadedConfigCache, } from '../utils/config-loader.js';
|
|
20
|
-
import {
|
|
19
|
+
import { endWithRefusal, leftoverIssueOf, NOTHING_FINISHED, writeDocument } from '../utils/document-writer.js';
|
|
20
|
+
import { countCollapsedFindings, formatCollapsedFindingsHint, formatIssueLines, formatSeverityBreakdown, issuesToRenderAtVerbosity, } from '../utils/issue-rendering.js';
|
|
21
21
|
import { resolveIssueSeverity } from '../utils/issue-severity.js';
|
|
22
22
|
import { createLogger } from '../utils/logger.js';
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
23
|
+
import { classifyInputFault, readInputFile, unlistableDirectoryRefusal } from '../utils/project-root-policy.js';
|
|
24
|
+
import { relativizePath } from '../utils/relativize-paths.js';
|
|
25
|
+
import { RUN_INTEGRITY_CODE } from '../utils/run-integrity.js';
|
|
26
26
|
import { mergeSkillPackagingConfig } from '../utils/skill-packaging-config.js';
|
|
27
27
|
import { renderSkillQualityFooter } from '../utils/skill-quality-footer.js';
|
|
28
28
|
import { computeConfigVerdicts } from '../utils/verdict-helpers.js';
|
|
29
|
+
import { compatLaneIssues } from './audit/compat-lane-findings.js';
|
|
29
30
|
import { crawlOwnsSubtree, distributedTreeFindings, getOrCreateGitTracker, gitTrackerForProjectRoot, isWithin, resetGitTrackerCache, } from './audit/distributed-tree.js';
|
|
30
31
|
import { withClonedRepo } from './audit/git-url-clone.js';
|
|
31
|
-
import { buildHierarchicalOutput } from './audit/hierarchical-output.js';
|
|
32
|
+
import { addMisconfigurationIssues, buildHierarchicalOutput } from './audit/hierarchical-output.js';
|
|
32
33
|
import { renderProvenanceHeader, rewritePathsInResults, } from './audit/provenance.js';
|
|
33
34
|
import { enumerateAuditPopulation, resolveProjectExcludes, VAT_CONFIG_FILENAME, } from './audit/scan-population.js';
|
|
34
35
|
import { createAuditSettingsCommand } from './audit-settings.js';
|
|
@@ -55,12 +56,13 @@ const RESOURCE_TYPE_CLAUDE_PLUGIN = 'claude-plugin';
|
|
|
55
56
|
*/
|
|
56
57
|
async function buildVATProjectContext(scanRoot, logger, locationRoot) {
|
|
57
58
|
const configPath = safePath.join(scanRoot, VAT_CONFIG_FILENAME);
|
|
58
|
-
|
|
59
|
+
// A probe the OS refuses is the config's source fault, never "no config here".
|
|
60
|
+
if (!pathPresent(configPath, { follow: scanRoot }, everywhere('source'), 'probe')) {
|
|
59
61
|
return null;
|
|
60
62
|
}
|
|
61
63
|
let config;
|
|
62
64
|
try {
|
|
63
|
-
config = loadConfig(scanRoot);
|
|
65
|
+
config = loadConfig(scanRoot, 'source');
|
|
64
66
|
}
|
|
65
67
|
catch (error) {
|
|
66
68
|
logger.debug(`Config-aware audit: skipping invalid config in ${scanRoot}: ${String(error)}`);
|
|
@@ -96,23 +98,17 @@ async function buildVATProjectContext(scanRoot, logger, locationRoot) {
|
|
|
96
98
|
}
|
|
97
99
|
return { skillConfigs };
|
|
98
100
|
}
|
|
99
|
-
/**
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* The one-line human summary of a severity distribution.
|
|
109
|
-
*
|
|
110
|
-
* Every result that carries findings renders its counts the same way, so a reader
|
|
111
|
-
* comparing two entries is comparing the same sentence.
|
|
112
|
-
*/
|
|
113
|
-
function formatCountsSummary(counts) {
|
|
114
|
-
return `${counts.errors} errors, ${counts.warnings} warnings, ${counts.info} info`;
|
|
101
|
+
/** A file carries an error-severity finding — the `filesWithErrors` bucket. */
|
|
102
|
+
function hasErrors(result) {
|
|
103
|
+
return countBySeverity(result.issues).errors > 0;
|
|
104
|
+
}
|
|
105
|
+
/** A file's worst actionable finding is a warning — the `filesWithWarnings` bucket. */
|
|
106
|
+
function hasOnlyWarnings(result) {
|
|
107
|
+
const { errors, warnings } = countBySeverity(result.issues);
|
|
108
|
+
return errors === 0 && warnings > 0;
|
|
115
109
|
}
|
|
110
|
+
/** `vat audit` has no `--strict`: warnings never move its exit code. */
|
|
111
|
+
const AUDIT_GATE = { strict: false };
|
|
116
112
|
/**
|
|
117
113
|
* Append findings to a result and re-derive everything that describes them.
|
|
118
114
|
*
|
|
@@ -124,17 +120,25 @@ function formatCountsSummary(counts) {
|
|
|
124
120
|
*
|
|
125
121
|
* Mutates in place, because the audit pipeline hands these results around by
|
|
126
122
|
* reference and there is no single place a rebuilt copy could be swapped in.
|
|
123
|
+
* The sentence comes from the same `describeIssues` the producer used, so the
|
|
124
|
+
* re-derived one is exactly what the producer says for the grown list — never a
|
|
125
|
+
* second wording, and never a stale "Valid plugin" beside a warning.
|
|
127
126
|
*/
|
|
128
127
|
function appendIssues(result, issues) {
|
|
129
128
|
if (issues.length === 0) {
|
|
130
129
|
return;
|
|
131
130
|
}
|
|
132
131
|
result.issues.push(...issues);
|
|
133
|
-
|
|
134
|
-
result.status = calculateValidationStatus(result.issues);
|
|
135
|
-
result.issueCounts = counts;
|
|
136
|
-
result.summary = formatCountsSummary(counts);
|
|
132
|
+
Object.assign(result, describeIssues(result.issues, result.type));
|
|
137
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Convert PackagingValidationResult to ValidationResult for consistent audit output.
|
|
136
|
+
* In audit mode, we merge allErrors (which includes both errors and warnings after
|
|
137
|
+
* severity resolution but WITHOUT allow suppression) into the standard issues array.
|
|
138
|
+
*
|
|
139
|
+
* Compat verdicts (COMPAT_TARGET_*) are computed from the result's observations
|
|
140
|
+
* and the config-level targets, then merged into the issue list.
|
|
141
|
+
*/
|
|
138
142
|
function packagingResultToValidationResult(skillPath, result, configTargets, locationRoot) {
|
|
139
143
|
// allErrors contains all emitted issues (errors + warnings) after severity resolution
|
|
140
144
|
// but without allow suppression — exactly what audit wants. Verdicts are
|
|
@@ -143,14 +147,11 @@ function packagingResultToValidationResult(skillPath, result, configTargets, loc
|
|
|
143
147
|
const issues = verdictIssues.length > 0
|
|
144
148
|
? [...result.allErrors, ...verdictIssues]
|
|
145
149
|
: result.allErrors;
|
|
146
|
-
const issueCounts = countBySeverity(issues);
|
|
147
150
|
const out = {
|
|
148
151
|
path: skillPath,
|
|
149
152
|
type: RESOURCE_TYPE_AGENT_SKILL,
|
|
150
|
-
|
|
151
|
-
summary: formatCountsSummary(issueCounts),
|
|
153
|
+
...describeIssues(issues, RESOURCE_TYPE_AGENT_SKILL),
|
|
152
154
|
issues,
|
|
153
|
-
issueCounts,
|
|
154
155
|
metadata: {
|
|
155
156
|
lineCount: result.metadata.skillLines,
|
|
156
157
|
name: result.skillName,
|
|
@@ -196,7 +197,7 @@ function packagingResultToValidationResult(skillPath, result, configTargets, loc
|
|
|
196
197
|
*
|
|
197
198
|
* ⚠️ The filesystem question IS asked, and the answer changes what the operator
|
|
198
199
|
* is told. `config-loader.ts` preserves `cause` specifically so callers can ask
|
|
199
|
-
* `
|
|
200
|
+
* `fsFaultOf` and "decide whether to degrade or abort"; catching
|
|
200
201
|
* `ConfigLoadError` unconditionally never asked at all, so a `chmod 000` config
|
|
201
202
|
* and a typo produced the same sentence — and a permissions problem is not a
|
|
202
203
|
* broken config.
|
|
@@ -317,7 +318,7 @@ function recordUnloadableConfig(err, logger, locationRoot) {
|
|
|
317
318
|
// different actions from the operator: `chmod`/ownership on one side, an edit
|
|
318
319
|
// to the file on the other. Collapsing them into one sentence was the whole
|
|
319
320
|
// cost of never asking.
|
|
320
|
-
const why =
|
|
321
|
+
const why = fsFaultOf(err) === undefined ? 'unloadable' : 'unreadable';
|
|
321
322
|
logger.warn(`Ignoring ${why} config at ${configPath}; skills it governs are validated`
|
|
322
323
|
+ ` config-free: ${err.message}`);
|
|
323
324
|
}
|
|
@@ -340,7 +341,7 @@ function recordUnloadableConfig(err, logger, locationRoot) {
|
|
|
340
341
|
function degradingDiscovery(configRoot, logger, locationRoot) {
|
|
341
342
|
return {
|
|
342
343
|
degrade: (refusal) => {
|
|
343
|
-
recordRefusedDiscovery(new DirectoryListingRefusedError(refusal, { root: configRoot, remedy: SKILLS_INCLUDE_REMEDY }), configRoot, logger, locationRoot);
|
|
344
|
+
recordRefusedDiscovery(new DirectoryListingRefusedError(refusal, { root: configRoot, remedy: SKILLS_INCLUDE_REMEDY, side: 'source' }), configRoot, logger, locationRoot);
|
|
344
345
|
},
|
|
345
346
|
};
|
|
346
347
|
}
|
|
@@ -372,7 +373,7 @@ function degradingDiscovery(configRoot, logger, locationRoot) {
|
|
|
372
373
|
function degradingRegistry(projectRoot, logger, locationRoot) {
|
|
373
374
|
return {
|
|
374
375
|
degrade: (refusal) => {
|
|
375
|
-
const err = new DirectoryListingRefusedError(refusal, { root: projectRoot, remedy: listingRefusalRemedy(projectRoot) });
|
|
376
|
+
const err = new DirectoryListingRefusedError(refusal, { root: projectRoot, remedy: listingRefusalRemedy(projectRoot), side: 'source' });
|
|
376
377
|
recordRefusedListing(err, logger, locationRoot, () => `The link graph under ${projectRoot} skipped an unreadable directory; every document beneath it`
|
|
377
378
|
+ ` is missing from this audit's link and reference checks: ${err.message}`);
|
|
378
379
|
},
|
|
@@ -469,8 +470,10 @@ async function validateSingleSkill(skillPath, options, logger, locationRoot, cra
|
|
|
469
470
|
// makes when this registry does not cover the skill: one ruling, both crawls.
|
|
470
471
|
const unreadable = degradingRegistry(projectRoot, logger, locationRoot);
|
|
471
472
|
const sharedCtx = {
|
|
472
|
-
registry: await crawlAndResolveRegistry(projectRoot, { unreadable }),
|
|
473
|
+
registry: await crawlAndResolveRegistry(projectRoot, { outputs: [], unreadable }),
|
|
473
474
|
unreadable,
|
|
475
|
+
// An audit only reads the trees it scans.
|
|
476
|
+
outputs: [],
|
|
474
477
|
locationRoot,
|
|
475
478
|
projectSkills: await resolveProjectDeclaredEvalSuites(skillPath, degradingDiscovery(projectRoot, logger, locationRoot)),
|
|
476
479
|
// The RUN's probe, not this call's — see {@link runSuiteProbe}. This lane
|
|
@@ -486,7 +489,8 @@ async function validateSingleSkill(skillPath, options, logger, locationRoot, cra
|
|
|
486
489
|
return configAware;
|
|
487
490
|
}
|
|
488
491
|
// Fallback: basic validation. Severity is applied by `applySeverityFilter`.
|
|
489
|
-
|
|
492
|
+
// The audited skill is the verb's input.
|
|
493
|
+
const validateOptions = { skillPath, locationRoot, validation: {}, side: 'source' };
|
|
490
494
|
if (options.warnUnreferencedFiles) {
|
|
491
495
|
validateOptions.checkUnreferencedFiles = true;
|
|
492
496
|
}
|
|
@@ -533,13 +537,13 @@ function collect(value, previous) {
|
|
|
533
537
|
* Create audit command
|
|
534
538
|
* Top-level command: vat audit [path]
|
|
535
539
|
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
* `FINDINGS` when
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
540
|
+
* Publishes the report envelope through the one writer, and ends on the code
|
|
541
|
+
* the written document derives — the rule every report verb shares: `OK` when
|
|
542
|
+
* no finding is at error severity, `FINDINGS` when one is (a run that audited
|
|
543
|
+
* zero files carries the writer's `RESOURCE_CHECK_BROKEN`), `ERROR` only when
|
|
544
|
+
* the audit did not finish (`status: error`, with the refusal in `error.code`).
|
|
545
|
+
* Warnings never move the exit code — audit has no `--strict`;
|
|
546
|
+
* `validation.severity` is the dial that decides what counts.
|
|
543
547
|
*/
|
|
544
548
|
export function createAuditCommand() {
|
|
545
549
|
const audit = new Command('audit');
|
|
@@ -607,12 +611,19 @@ Description:
|
|
|
607
611
|
(See packages/cli/docs/audit.md for details.)
|
|
608
612
|
|
|
609
613
|
Output:
|
|
610
|
-
The
|
|
611
|
-
|
|
614
|
+
The report envelope every report verb publishes (YAML on stdout):
|
|
615
|
+
- status: ok (no findings) | findings (at least one) | error (did not finish)
|
|
616
|
+
- examined: files read; summary: findings by severity; gate: { strict: false }
|
|
617
|
+
- findings: every finding, each with the file to open as 'location'
|
|
618
|
+
- data.root: the scan root every path is relative to (null for a git URL,
|
|
619
|
+
whose data.provenance names the source instead)
|
|
620
|
+
- data.counts: filesPassed / filesWithWarnings / filesWithErrors /
|
|
621
|
+
pathsUnreadable; data.files: one row per file (status, summary,
|
|
622
|
+
compatibility, settings); data.hierarchical: the --user grouping
|
|
623
|
+
- error: { code, message } when status is error
|
|
612
624
|
|
|
613
|
-
A run that audited ZERO files is
|
|
614
|
-
non-overridable RESOURCE_CHECK_BROKEN
|
|
615
|
-
about the run, so it is not a files[] row), and exit 1.
|
|
625
|
+
A run that audited ZERO files is not a pass: the report carries one
|
|
626
|
+
non-overridable RESOURCE_CHECK_BROKEN finding and ends on exit 1.
|
|
616
627
|
|
|
617
628
|
Validation Behavior:
|
|
618
629
|
Audit surfaces all validation issues for inspection.
|
|
@@ -620,9 +631,8 @@ Validation Behavior:
|
|
|
620
631
|
- NEVER applies validation.allow (allowed codes are always shown)
|
|
621
632
|
- Respects validation.severity: a code set to 'ignore' is hidden; warnings
|
|
622
633
|
and errors are both reported, each at its configured severity
|
|
623
|
-
- ALWAYS exits 0 for validation results (never gates on errors)
|
|
624
634
|
|
|
625
|
-
For gated validation
|
|
635
|
+
For gated validation that honours validation.allow, use: vat skills validate
|
|
626
636
|
For the full list of codes and severity defaults, see: docs/validation-codes.md
|
|
627
637
|
|
|
628
638
|
Default: Validates SKILL.md and all transitively linked markdown files
|
|
@@ -640,7 +650,10 @@ Validation Checks:
|
|
|
640
650
|
Warnings (should fix):
|
|
641
651
|
- Skill exceeds recommended length (>5000 lines)
|
|
642
652
|
- With --compat: a declared target cannot or may not run the skill
|
|
643
|
-
(COMPAT_TARGET_INCOMPATIBLE, COMPAT_TARGET_NEEDS_REVIEW)
|
|
653
|
+
(COMPAT_TARGET_INCOMPATIBLE, COMPAT_TARGET_NEEDS_REVIEW); a plugin or a
|
|
654
|
+
path the analysis could not look at (COMPAT_NOT_CHECKED)
|
|
655
|
+
- With --compat --settings: something the plugin declares that the settings
|
|
656
|
+
block (SETTINGS_POLICY_CONFLICT)
|
|
644
657
|
- Unreferenced files detected (with --warn-unreferenced-files)
|
|
645
658
|
|
|
646
659
|
Info (observations):
|
|
@@ -679,20 +692,23 @@ Config-Aware Validation:
|
|
|
679
692
|
skills.config.<name>.validation... that one skill
|
|
680
693
|
|
|
681
694
|
Exit Codes:
|
|
682
|
-
0 - The audit
|
|
695
|
+
0 - The audit finished and no finding is at error severity (warnings and
|
|
683
696
|
informational findings are in the report, not the exit code).
|
|
684
|
-
1 - The audit
|
|
685
|
-
|
|
686
|
-
the scan could not read, or a governing config that cannot be
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
that
|
|
695
|
-
|
|
697
|
+
1 - The audit finished with at least one error-severity finding
|
|
698
|
+
('status: findings'), including zero files audited. A path inside the
|
|
699
|
+
tree the scan could not read, or a governing config that cannot be
|
|
700
|
+
loaded, is SCAN_PATH_UNREADABLE (warning): the run is degraded, not
|
|
701
|
+
failed, and the refused path is counted in data.counts.pathsUnreadable,
|
|
702
|
+
never in 'examined'.
|
|
703
|
+
2 - The audit did not finish ('status: error', the reason in error.code):
|
|
704
|
+
USAGE_INVALID for a path that does not exist, a file no audit lane
|
|
705
|
+
recognises, a git URL that does not parse, --user with no Claude
|
|
706
|
+
config dir, --settings without --compat or together with --user, or a
|
|
707
|
+
--settings file that does not exist; INPUT_UNREADABLE for a root
|
|
708
|
+
directory the OS will not list, a git URL that would not clone, or a
|
|
709
|
+
settings file (named or auto-discovered) the OS refuses, that does not
|
|
710
|
+
parse, or that fails the settings schema; INTERNAL_ERROR for a defect
|
|
711
|
+
in VAT.
|
|
696
712
|
|
|
697
713
|
Examples:
|
|
698
714
|
$ vat audit ./plugins/ # Audit recursively (default)
|
|
@@ -739,23 +755,22 @@ export function userScanTargets(candidates, recursive) {
|
|
|
739
755
|
}
|
|
740
756
|
/**
|
|
741
757
|
* Handle --user audit: scans ~/.claude/plugins, ~/.claude/skills, ~/.claude/marketplaces
|
|
742
|
-
* and
|
|
758
|
+
* and publishes the report with its `data.hierarchical` view. Calls process.exit() when done.
|
|
743
759
|
*/
|
|
744
760
|
async function auditUserDirectories(recursive, options, startTime, logger) {
|
|
745
761
|
const { claudeDir, pluginsDir, skillsDir, marketplacesDir } = getClaudeUserPaths();
|
|
746
762
|
// --user scans three sibling directories; they share ONE enclosing Claude
|
|
747
763
|
// config dir, so that is the run's single stated root.
|
|
748
764
|
const scanRoot = safePath.resolve(claudeDir);
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
const
|
|
765
|
+
// Each install root is the operator's own configuration (`CLAUDE_CONFIG_DIR`/`HOME`), so it is
|
|
766
|
+
// its own `within`; a probe the OS refuses is that root's source fault, never "not installed".
|
|
767
|
+
const userRootPresent = (dir) => pathPresent(dir, { follow: dir }, everywhere('source'), 'probe');
|
|
768
|
+
const pluginsDirExists = userRootPresent(pluginsDir);
|
|
769
|
+
const skillsDirExists = userRootPresent(skillsDir);
|
|
770
|
+
const marketplacesDirExists = userRootPresent(marketplacesDir);
|
|
752
771
|
if (!pluginsDirExists && !skillsDirExists && !marketplacesDirExists) {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
logger.error(` Skills: ${skillsDir}`);
|
|
756
|
-
logger.error(` Marketplaces: ${marketplacesDir}`);
|
|
757
|
-
logger.error('Claude plugins/skills/marketplaces have not been installed yet.');
|
|
758
|
-
process.exit(ExitCode.ERROR);
|
|
772
|
+
throw new CommandRefusalError('USAGE_INVALID', `No user-level Claude directories found (plugins: ${pluginsDir}, skills: ${skillsDir}, marketplaces: ${marketplacesDir}). `
|
|
773
|
+
+ 'Claude plugins, skills and marketplaces have not been installed yet — set CLAUDE_CONFIG_DIR to the config dir to audit.');
|
|
759
774
|
}
|
|
760
775
|
const scanned = [];
|
|
761
776
|
// The roots that exist, minus any one another already covers — see
|
|
@@ -765,27 +780,36 @@ async function auditUserDirectories(recursive, options, startTime, logger) {
|
|
|
765
780
|
...(skillsDirExists ? [skillsDir] : []),
|
|
766
781
|
...(marketplacesDirExists ? [marketplacesDir] : []),
|
|
767
782
|
];
|
|
768
|
-
|
|
783
|
+
// In order: the targets share the population cache and the logger.
|
|
784
|
+
await forEachInOrder(userScanTargets(present, recursive), async (target) => {
|
|
769
785
|
logger.debug(`Auditing user-level resources at: ${target}`);
|
|
770
786
|
scanned.push(...await getValidationResults(target, recursive, options, logger, scanRoot));
|
|
771
|
-
}
|
|
787
|
+
});
|
|
772
788
|
// The `--user` report is assembled here rather than by `buildAuditReport`, so
|
|
773
789
|
// it needs its own append or the config findings would reach stderr and not the
|
|
774
|
-
// document — see the same call in `buildAuditReport`.
|
|
775
|
-
|
|
790
|
+
// document — see the same call in `buildAuditReport`. The misconfiguration
|
|
791
|
+
// findings join the RESULTS, not only the hierarchy, so the envelope counts them.
|
|
792
|
+
const results = addMisconfigurationIssues(withDegradedConfigFindings(scanned), scanRoot);
|
|
776
793
|
// Run compatibility analysis if --compat flag is set
|
|
777
794
|
const compatMap = options.compat
|
|
778
|
-
? await runCompatAnalysis(results, logger, scanRoot) // --settings
|
|
795
|
+
? await runCompatAnalysis(results, logger, scanRoot) // --settings is refused under --user
|
|
779
796
|
: undefined;
|
|
780
797
|
const verbose = options.verbose ?? false;
|
|
781
798
|
const skillResults = results.filter((r) => SKILL_RESULT_TYPES.has(r.type));
|
|
782
799
|
const hierarchical = buildHierarchicalOutput(skillResults, verbose, scanRoot);
|
|
783
|
-
const
|
|
784
|
-
|
|
800
|
+
const report = buildAuditDocument(results, {
|
|
801
|
+
root: scanRoot,
|
|
802
|
+
compatMap,
|
|
803
|
+
verbose,
|
|
804
|
+
hierarchical,
|
|
805
|
+
durationMs: Date.now() - startTime,
|
|
806
|
+
});
|
|
807
|
+
const written = writeDocument('audit', report, 'yaml');
|
|
785
808
|
if (verbose) {
|
|
786
809
|
renderVerboseEvidence(results, scanRoot, logger);
|
|
787
810
|
}
|
|
788
|
-
logHierarchicalSummary(results,
|
|
811
|
+
logHierarchicalSummary({ results, written, data: report.data, root: scanRoot, verbose }, logger);
|
|
812
|
+
process.exit(exitCodeForReport(written));
|
|
789
813
|
}
|
|
790
814
|
/** Skill resource types that can have per-skill validation config. */
|
|
791
815
|
const SKILL_RESULT_TYPES = new Set([RESOURCE_TYPE_AGENT_SKILL, 'vat-agent']);
|
|
@@ -809,7 +833,8 @@ const SKILL_RESULT_TYPES = new Set([RESOURCE_TYPE_AGENT_SKILL, 'vat-agent']);
|
|
|
809
833
|
*/
|
|
810
834
|
export function deriveScanRoot(targetPath) {
|
|
811
835
|
const resolved = safePath.resolve(targetPath);
|
|
812
|
-
|
|
836
|
+
// The operator's own target: its own `within`.
|
|
837
|
+
const isDirectory = followedKindSync(resolved, resolved) === 'directory';
|
|
813
838
|
return isDirectory ? resolved : safePath.resolve(resolved, '..');
|
|
814
839
|
}
|
|
815
840
|
/**
|
|
@@ -841,15 +866,12 @@ function deriveConfigRoot(targetPath) {
|
|
|
841
866
|
* Build the recalculated status and summary after issues have been filtered.
|
|
842
867
|
*/
|
|
843
868
|
function buildFilteredResult(result, filteredIssues) {
|
|
844
|
-
const counts = countBySeverity(filteredIssues);
|
|
845
869
|
return {
|
|
846
870
|
...result,
|
|
847
|
-
|
|
848
|
-
// Spreading `result` carried the PRE-filter `issueCounts` forward, so a
|
|
871
|
+
// Spreading `result` carried the PRE-filter counts forward, so a
|
|
849
872
|
// `severity: ignore` config left the counts describing findings the report
|
|
850
873
|
// no longer contained. The counts are re-derived, never inherited.
|
|
851
|
-
|
|
852
|
-
summary: formatCountsSummary(counts),
|
|
874
|
+
...describeIssues(filteredIssues, result.type),
|
|
853
875
|
issues: filteredIssues,
|
|
854
876
|
};
|
|
855
877
|
}
|
|
@@ -970,29 +992,57 @@ function isEmptiedUnreadablePathResult(result) {
|
|
|
970
992
|
&& result.metadata === undefined;
|
|
971
993
|
}
|
|
972
994
|
/**
|
|
973
|
-
*
|
|
974
|
-
*
|
|
995
|
+
* Refuse a `--settings` the run would otherwise ignore, before any scan or clone.
|
|
996
|
+
*
|
|
997
|
+
* Every arm used to be a stderr line and exit 0: without `--compat` a warning
|
|
998
|
+
* and no settings check; under `--user` nothing at all; and a named file that
|
|
999
|
+
* is absent read as "no settings", so `--compat --settings /typo.json` printed
|
|
1000
|
+
* `findings: []` for a check that never compared anything. The sibling verb
|
|
1001
|
+
* `audit settings --file <missing>` refuses the same path.
|
|
1002
|
+
*
|
|
1003
|
+
* @throws {CommandRefusalError} `USAGE_INVALID` for a flag the run cannot honour
|
|
1004
|
+
* or a named file that is absent; `INPUT_UNREADABLE` for one the OS refuses
|
|
975
1005
|
*/
|
|
976
|
-
|
|
977
|
-
if (
|
|
978
|
-
return
|
|
1006
|
+
function refuseUnusableSettingsFlag(options) {
|
|
1007
|
+
if (options.settings === undefined || options.settings === false)
|
|
1008
|
+
return;
|
|
979
1009
|
if (!options.compat) {
|
|
980
|
-
|
|
981
|
-
|
|
1010
|
+
throw new CommandRefusalError('USAGE_INVALID', '--settings requires --compat: the settings check runs inside the compatibility analysis. Add --compat, or drop --settings.');
|
|
1011
|
+
}
|
|
1012
|
+
if (options.user) {
|
|
1013
|
+
throw new CommandRefusalError('USAGE_INVALID', '--settings is not supported with --user. Audit the plugin directory with --compat --settings instead, or drop --settings.');
|
|
982
1014
|
}
|
|
1015
|
+
if (typeof options.settings !== 'string')
|
|
1016
|
+
return;
|
|
1017
|
+
readInputFile(safePath.resolve(options.settings), { origin: 'argument', message: `Path does not exist: ${safePath.resolve(options.settings)}` });
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* The EffectiveSettings `--settings` asks the compat analysis to check against.
|
|
1021
|
+
* Called only under `--compat`; {@link refuseUnusableSettingsFlag} has already
|
|
1022
|
+
* refused every combination the run cannot honour.
|
|
1023
|
+
*
|
|
1024
|
+
* @throws {CommandRefusalError} `INPUT_UNREADABLE` when a settings file (named
|
|
1025
|
+
* or auto-discovered) the OS refuses, does not parse, or fails its schema — the check cannot run, and a warning beside
|
|
1026
|
+
* an unchecked report was how it used to pass silently
|
|
1027
|
+
*/
|
|
1028
|
+
async function resolveEffectiveSettings(options, scanPath) {
|
|
1029
|
+
if (!options.settings)
|
|
1030
|
+
return undefined;
|
|
983
1031
|
const settingsFile = typeof options.settings === 'string' ? options.settings : undefined;
|
|
984
1032
|
try {
|
|
985
1033
|
return await readEffectiveSettings({ settingsFile, projectDir: scanPath });
|
|
986
1034
|
}
|
|
987
|
-
catch (
|
|
988
|
-
|
|
989
|
-
return undefined;
|
|
1035
|
+
catch (error) {
|
|
1036
|
+
throw new CommandRefusalError('INPUT_UNREADABLE', `Claude settings could not be loaded for --settings: ${errorMessageOf(error)}`, { cause: error });
|
|
990
1037
|
}
|
|
991
1038
|
}
|
|
992
1039
|
/**
|
|
993
|
-
* Run the audit pipeline at `scanPath` and assemble the report
|
|
994
|
-
*
|
|
995
|
-
* (`root`) and every `path`/`location` beneath it is relative to that root.
|
|
1040
|
+
* Run the audit pipeline at `scanPath` and assemble the report, without
|
|
1041
|
+
* writing anything. The report states its coordinate system once
|
|
1042
|
+
* (`data.root`) and every `path`/`location` beneath it is relative to that root.
|
|
1043
|
+
*
|
|
1044
|
+
* The zero-files refusal is NOT here: the writer adds it from the registry's
|
|
1045
|
+
* denominator on the way out, as it does for every report verb.
|
|
996
1046
|
*
|
|
997
1047
|
* @internal Exported for integration testing only — not part of the public CLI API.
|
|
998
1048
|
*/
|
|
@@ -1026,7 +1076,7 @@ export async function buildAuditReport(scanPath, options, startTime, logger) {
|
|
|
1026
1076
|
// only show more than the adopter asked for, never less.
|
|
1027
1077
|
let config;
|
|
1028
1078
|
try {
|
|
1029
|
-
config = loadConfig(deriveConfigRoot(scanPath));
|
|
1079
|
+
config = loadConfig(deriveConfigRoot(scanPath), 'source');
|
|
1030
1080
|
}
|
|
1031
1081
|
catch (err) {
|
|
1032
1082
|
// `warn`, not `debug`. Falling back to no config is the safe direction — it
|
|
@@ -1040,60 +1090,95 @@ export async function buildAuditReport(scanPath, options, startTime, logger) {
|
|
|
1040
1090
|
// Apply severity filtering: hide codes whose effective severity is 'ignore'.
|
|
1041
1091
|
// Allow is deliberately NOT applied — audit shows every finding.
|
|
1042
1092
|
const results = applySeverityFilter(rawResults, config);
|
|
1043
|
-
const effectiveSettings = await resolveEffectiveSettings(options, scanPath, logger);
|
|
1044
1093
|
// Run compatibility analysis if --compat flag is set
|
|
1045
1094
|
const compatMap = options.compat
|
|
1046
|
-
? await runCompatAnalysis(results, logger, scanRoot,
|
|
1095
|
+
? await runCompatAnalysis(results, logger, scanRoot, await resolveEffectiveSettings(options, scanPath), vatContextForCompat)
|
|
1047
1096
|
: undefined;
|
|
1048
1097
|
const verbose = options.verbose ?? false;
|
|
1049
1098
|
return {
|
|
1050
1099
|
results,
|
|
1051
|
-
|
|
1100
|
+
report: buildAuditDocument(results, {
|
|
1101
|
+
root: scanRoot,
|
|
1102
|
+
compatMap,
|
|
1103
|
+
verbose,
|
|
1104
|
+
hierarchical: null,
|
|
1105
|
+
durationMs: Date.now() - startTime,
|
|
1106
|
+
}),
|
|
1052
1107
|
};
|
|
1053
1108
|
}
|
|
1054
|
-
/**
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1109
|
+
/**
|
|
1110
|
+
* A URL audit's report: its run root is a random tempdir — not reproducible and
|
|
1111
|
+
* useless to a reader — so `data.root` is `null`, `data.provenance` states the
|
|
1112
|
+
* base instead (url @ ref @ commit), and any string still spelling the tempdir
|
|
1113
|
+
* is rewritten relative to the clone.
|
|
1114
|
+
*/
|
|
1115
|
+
export function urlAuditReport(report, provenance, tempRoot) {
|
|
1116
|
+
const rewritten = rewritePathsInResults(report, tempRoot);
|
|
1117
|
+
return { ...rewritten, data: { ...rewritten.data, root: null, provenance } };
|
|
1059
1118
|
}
|
|
1060
|
-
|
|
1119
|
+
/**
|
|
1120
|
+
* Audit `scanPath` and build the report, without publishing it: a URL audit publishes it only
|
|
1121
|
+
* once its clone is disposed of, so a clone left behind is a warning IN the document.
|
|
1122
|
+
*/
|
|
1123
|
+
async function buildAuditAtPath(scanPath, options, overrides = {}) {
|
|
1061
1124
|
const logger = createLogger(options.debug ? { debug: true } : {});
|
|
1062
1125
|
const startTime = Date.now();
|
|
1063
1126
|
const verbose = options.verbose ?? false;
|
|
1064
|
-
const { results,
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1127
|
+
const { results, report } = await buildAuditReport(scanPath, options, startTime, logger);
|
|
1128
|
+
const scanRoot = deriveScanRoot(scanPath);
|
|
1129
|
+
if (overrides.provenance !== undefined) {
|
|
1130
|
+
// The human half of the provenance: the machine half is `data.provenance`.
|
|
1131
|
+
logger.info(renderProvenanceHeader(overrides.provenance).trimEnd());
|
|
1132
|
+
}
|
|
1133
|
+
const published = overrides.provenance === undefined || overrides.tempRoot === undefined
|
|
1134
|
+
? report
|
|
1135
|
+
: urlAuditReport(report, overrides.provenance, overrides.tempRoot);
|
|
1136
|
+
return { results, report: published, scanRoot, logger, verbose, startTime };
|
|
1137
|
+
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Publish a built audit, with `added` findings the run learned of after building it.
|
|
1140
|
+
*
|
|
1141
|
+
* @returns What was published. The caller exits with the code it calls for.
|
|
1142
|
+
*/
|
|
1143
|
+
function publishAudit(built, added) {
|
|
1144
|
+
const { results, scanRoot, logger, verbose } = built;
|
|
1145
|
+
const report = withAddedFindings(built.report, added);
|
|
1146
|
+
const written = writeDocument('audit', report, 'yaml');
|
|
1074
1147
|
if (verbose) {
|
|
1075
|
-
renderVerboseEvidence(results,
|
|
1148
|
+
renderVerboseEvidence(results, scanRoot, logger);
|
|
1076
1149
|
}
|
|
1077
|
-
handleAuditResults(results,
|
|
1078
|
-
logger.debug(`Audit complete in ${Date.now() - startTime}ms`);
|
|
1150
|
+
handleAuditResults({ results, written, data: report.data, root: scanRoot, verbose }, logger);
|
|
1151
|
+
logger.debug(`Audit complete in ${Date.now() - built.startTime}ms`);
|
|
1152
|
+
return written;
|
|
1079
1153
|
}
|
|
1080
1154
|
async function runUrlAudit(rawInput, options) {
|
|
1081
|
-
|
|
1082
|
-
|
|
1155
|
+
let parsed;
|
|
1156
|
+
try {
|
|
1157
|
+
parsed = parseGitUrl(rawInput);
|
|
1158
|
+
}
|
|
1159
|
+
catch (error) {
|
|
1160
|
+
// The argument is the operator's, and it does not name a source.
|
|
1161
|
+
throw new CommandRefusalError('USAGE_INVALID', errorMessageOf(error), { cause: error });
|
|
1162
|
+
}
|
|
1163
|
+
const { value: built, leftover } = await withClonedRepo(parsed, { keepTempForDebug: options.debug === true }, ({ targetDir, tempdir, provenance }) => {
|
|
1083
1164
|
// Re-enter the audit pipeline against the cloned target. Strip --user
|
|
1084
1165
|
// (it doesn't apply to URL audits).
|
|
1085
1166
|
const innerOptions = { ...options, user: false };
|
|
1086
|
-
|
|
1167
|
+
return buildAuditAtPath(targetDir, innerOptions, {
|
|
1087
1168
|
provenance,
|
|
1088
1169
|
tempRoot: tempdir,
|
|
1089
1170
|
});
|
|
1090
1171
|
});
|
|
1172
|
+
// Only now, the clone disposed of: one it left behind is a warning in the document.
|
|
1173
|
+
const written = publishAudit(built, leftover === undefined ? [] : toFindings([leftoverIssueOf(leftover)]));
|
|
1174
|
+
process.exit(exitCodeForReport(written));
|
|
1091
1175
|
}
|
|
1092
1176
|
export async function auditCommand(targetPath, options) {
|
|
1093
1177
|
const logger = createLogger(options.debug ? { debug: true } : {});
|
|
1094
1178
|
const startTime = Date.now();
|
|
1095
1179
|
resetAuditCaches();
|
|
1096
1180
|
try {
|
|
1181
|
+
refuseUnusableSettingsFlag(options);
|
|
1097
1182
|
// A local path always wins. `isGitUrl` accepts bare `owner/repo` GitHub
|
|
1098
1183
|
// shorthand, which is indistinguishable from an ordinary two-segment
|
|
1099
1184
|
// relative path (`plugins/arc`, `docs/guides`, `packages/cli`). Asking
|
|
@@ -1101,7 +1186,9 @@ export async function auditCommand(targetPath, options) {
|
|
|
1101
1186
|
// cloned https://github.com/<that>.git instead, reaching out to the
|
|
1102
1187
|
// network with a name derived from the caller's own directory layout.
|
|
1103
1188
|
// Shorthand is a fallback for arguments that name nothing on disk.
|
|
1104
|
-
|
|
1189
|
+
// The operator's own argument: its own `within`. A probe the OS refuses is its source fault,
|
|
1190
|
+
// never "names nothing on disk" — that would send a local path to the network.
|
|
1191
|
+
if (targetPath !== undefined && !pathPresent(targetPath, { follow: targetPath }, everywhere('source'), 'probe') && isGitUrl(targetPath)) {
|
|
1105
1192
|
await runUrlAudit(targetPath, options);
|
|
1106
1193
|
return;
|
|
1107
1194
|
}
|
|
@@ -1112,19 +1199,14 @@ export async function auditCommand(targetPath, options) {
|
|
|
1112
1199
|
return;
|
|
1113
1200
|
}
|
|
1114
1201
|
const scanPath = targetPath ? safePath.resolve(targetPath) : process.cwd();
|
|
1115
|
-
const unusable = await
|
|
1116
|
-
if (unusable !== undefined)
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
return handleExpectedFailure(unusable, ExitCode.ERROR, startTime);
|
|
1120
|
-
}
|
|
1121
|
-
await runAuditAtPath(scanPath, options);
|
|
1202
|
+
const unusable = await unusableRootRefusal(scanPath);
|
|
1203
|
+
if (unusable !== undefined)
|
|
1204
|
+
throw unusable;
|
|
1205
|
+
process.exit(exitCodeForReport(publishAudit(await buildAuditAtPath(scanPath, options), [])));
|
|
1122
1206
|
}
|
|
1123
1207
|
catch (error) {
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
// operator has to search for did not match what they typed.
|
|
1127
|
-
handleCommandError(error, logger, startTime, 'Audit');
|
|
1208
|
+
logger.debug(`Audit did not finish after ${Date.now() - startTime}ms`);
|
|
1209
|
+
endWithRefusal('audit', refusalCodeOf(error), error, 'yaml', AUDIT_GATE, NOTHING_FINISHED);
|
|
1128
1210
|
}
|
|
1129
1211
|
}
|
|
1130
1212
|
/**
|
|
@@ -1132,9 +1214,9 @@ export async function auditCommand(targetPath, options) {
|
|
|
1132
1214
|
* may start.
|
|
1133
1215
|
*
|
|
1134
1216
|
* The exit-code contract every verb shares: a path that does not exist, or a
|
|
1135
|
-
* file no audit lane recognises, is the INVOCATION's mistake — `
|
|
1136
|
-
* (2) before any scan, the same ending `vat resources validate` and
|
|
1137
|
-
* review` give the same argument. Until this check the audit ran anyway and
|
|
1217
|
+
* file no audit lane recognises, is the INVOCATION's mistake — a `USAGE_INVALID`
|
|
1218
|
+
* refusal (exit 2) before any scan, the same ending `vat resources validate` and
|
|
1219
|
+
* `vat skill review` give the same argument. Until this check the audit ran anyway and
|
|
1138
1220
|
* published `UNKNOWN_FORMAT` as a finding at exit 1 with `filesScanned: 1`: a
|
|
1139
1221
|
* typo in a CI step read as "the tree failed its gate", and the denominator
|
|
1140
1222
|
* counted a file that was never there.
|
|
@@ -1144,54 +1226,37 @@ export async function auditCommand(targetPath, options) {
|
|
|
1144
1226
|
* zero-files refusal at exit 1 — while `vat resources validate`, `check`,
|
|
1145
1227
|
* `query` and `scan` all end the same argument at exit 2. One outcome, two
|
|
1146
1228
|
* codes. Nothing under an unlistable root can be examined, so the audit could
|
|
1147
|
-
* not do its job:
|
|
1229
|
+
* not do its job: an `INPUT_UNREADABLE` refusal, exit 2 like a missing path.
|
|
1148
1230
|
*
|
|
1149
1231
|
* ONLY the root. A sub-path inside a readable tree is never the invocation's
|
|
1150
1232
|
* fault and stays a finding. Pinned by the `audit → error` rows of
|
|
1151
|
-
* `exit-codes.system.test.ts` and the
|
|
1152
|
-
* `exit-code-matrix.system.test.ts`.
|
|
1233
|
+
* `exit-codes.system.test.ts` and the `audit` row of
|
|
1234
|
+
* `exit-code-matrix-path-unlistable.system.test.ts`.
|
|
1153
1235
|
*/
|
|
1154
|
-
async function
|
|
1236
|
+
async function unusableRootRefusal(scanPath) {
|
|
1155
1237
|
let isDirectory;
|
|
1156
1238
|
try {
|
|
1157
1239
|
isDirectory = fs.lstatSync(scanPath).isDirectory();
|
|
1158
1240
|
}
|
|
1159
1241
|
catch (error) {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
return
|
|
1242
|
+
// Absent is the invocation's mistake; any other error (an `EACCES` parent) is
|
|
1243
|
+
// the input's refusal — never a scan that starts anyway.
|
|
1244
|
+
return classifyInputFault(scanPath, error, { origin: 'argument', message: `Path does not exist: ${scanPath}` });
|
|
1163
1245
|
}
|
|
1164
1246
|
if (isDirectory)
|
|
1165
|
-
return
|
|
1247
|
+
return unlistableDirectoryRefusal(scanPath);
|
|
1166
1248
|
if (detectFormat(scanPath) === RESOURCE_TYPE_AGENT_SKILL)
|
|
1167
1249
|
return undefined;
|
|
1168
1250
|
if ((await detectResourceFormat(scanPath)).type !== 'unknown')
|
|
1169
1251
|
return undefined;
|
|
1170
|
-
return `Path is not a resource this command can audit (a SKILL.md, a plugin or marketplace directory, or a Claude registry file): ${scanPath}
|
|
1171
|
-
}
|
|
1172
|
-
/**
|
|
1173
|
-
* Why a root DIRECTORY cannot be audited, or `undefined` when it can be listed.
|
|
1174
|
-
*
|
|
1175
|
-
* @param scanPath - The root the operator named, known to be a directory
|
|
1176
|
-
* @returns The refusal, or undefined
|
|
1177
|
-
*/
|
|
1178
|
-
function unlistableRootReason(scanPath) {
|
|
1179
|
-
try {
|
|
1180
|
-
// A probe, not a listing: the crawl owns enumeration, this only asks whether it can start.
|
|
1181
|
-
fs.accessSync(scanPath, fs.constants.R_OK | fs.constants.X_OK);
|
|
1182
|
-
return undefined;
|
|
1183
|
-
}
|
|
1184
|
-
catch (error) {
|
|
1185
|
-
const code = error.code ?? 'unknown error';
|
|
1186
|
-
return `Path cannot be read (${code}): ${scanPath}`;
|
|
1187
|
-
}
|
|
1252
|
+
return new CommandRefusalError('USAGE_INVALID', `Path is not a resource this command can audit (a SKILL.md, a plugin or marketplace directory, or a Claude registry file): ${scanPath}`);
|
|
1188
1253
|
}
|
|
1189
1254
|
/**
|
|
1190
1255
|
* Dispatch a single surface to the matching validator. Keeps the multi-surface
|
|
1191
1256
|
* branch of {@link getValidationResults} focused so cognitive complexity stays
|
|
1192
1257
|
* within the ESLint budget.
|
|
1193
1258
|
*/
|
|
1194
|
-
|
|
1259
|
+
function validateSurface(surface, options, logger, locationRoot) {
|
|
1195
1260
|
if (surface.type === RESOURCE_TYPE_AGENT_SKILL) {
|
|
1196
1261
|
// No crawl: this arm only runs for a MULTI-surface root, which in practice is
|
|
1197
1262
|
// skill-claude-plugin (SKILL.md beside .claude-plugin/plugin.json). The plugin
|
|
@@ -1208,13 +1273,10 @@ async function validateSurface(surface, options, logger, locationRoot) {
|
|
|
1208
1273
|
* Validate every surface enumerated at a directory root (used when
|
|
1209
1274
|
* `enumerateSurfaces` returns more than one — e.g., skill-claude-plugin).
|
|
1210
1275
|
*/
|
|
1211
|
-
|
|
1276
|
+
function validateMultipleSurfaces(surfaces, scanPath, options, logger, locationRoot) {
|
|
1212
1277
|
logger.debug(`Detected ${surfaces.length.toString()} surfaces at ${scanPath}: ${surfaces.map((s) => s.type).join(', ')}`);
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
results.push(await validateSurface(surface, options, logger, locationRoot));
|
|
1216
|
-
}
|
|
1217
|
-
return results;
|
|
1278
|
+
// In order: the surfaces share the population cache and the logger.
|
|
1279
|
+
return mapInOrder(surfaces, (surface) => validateSurface(surface, options, logger, locationRoot));
|
|
1218
1280
|
}
|
|
1219
1281
|
/**
|
|
1220
1282
|
* Additive inventory-detector pass — runs the pure-function detectors
|
|
@@ -1258,18 +1320,19 @@ async function recurseIntoMarketplacePlugins(marketplaceInv, recursive, options,
|
|
|
1258
1320
|
const marketplaceRoot = safePath.resolve(marketplaceInv.path);
|
|
1259
1321
|
const seen = new Set([marketplaceRoot]);
|
|
1260
1322
|
const results = [];
|
|
1261
|
-
|
|
1323
|
+
// In order: the `seen` dedupe must see each plugin before the next one starts.
|
|
1324
|
+
await forEachInOrder(marketplaceInv.discovered.plugins, async (plugin) => {
|
|
1262
1325
|
const pluginPath = safePath.resolve(plugin.path);
|
|
1263
1326
|
if (seen.has(pluginPath)) {
|
|
1264
1327
|
logger.debug(` Skipping marketplace-recurse into already-visited path: ${pluginPath}`);
|
|
1265
|
-
|
|
1328
|
+
return;
|
|
1266
1329
|
}
|
|
1267
1330
|
seen.add(pluginPath);
|
|
1268
1331
|
logger.debug(` Recursing into marketplace path-source plugin: ${pluginPath}`);
|
|
1269
1332
|
// Same run root — recursing into a co-located plugin must NOT re-anchor.
|
|
1270
1333
|
const pluginResults = await getValidationResults(pluginPath, recursive, options, logger, locationRoot);
|
|
1271
1334
|
results.push(...pluginResults);
|
|
1272
|
-
}
|
|
1335
|
+
});
|
|
1273
1336
|
return results;
|
|
1274
1337
|
}
|
|
1275
1338
|
/**
|
|
@@ -1333,7 +1396,7 @@ function appendInventoryParseErrors(result, inv, locationRoot) {
|
|
|
1333
1396
|
refusalsFiled.add(location);
|
|
1334
1397
|
parseIssues.push(materializeIssue('SCAN_PATH_UNREADABLE', { location, detail: `${location}: ${message}` }));
|
|
1335
1398
|
}
|
|
1336
|
-
// Status was hand-set to 'error' here while
|
|
1399
|
+
// Status was hand-set to 'error' here while the counts and description kept
|
|
1337
1400
|
// describing the pre-append list. One appender derives all three.
|
|
1338
1401
|
appendIssues(result, parseIssues);
|
|
1339
1402
|
}
|
|
@@ -1376,7 +1439,7 @@ export async function getValidationResults(scanPath, recursive, options, logger,
|
|
|
1376
1439
|
catch (error) {
|
|
1377
1440
|
// Only the filesystem refusing the subject degrades; a defect in a validator
|
|
1378
1441
|
// must still fail loudly rather than be reported as a permissions problem.
|
|
1379
|
-
if (
|
|
1442
|
+
if (fsFaultOf(error) === undefined)
|
|
1380
1443
|
throw error;
|
|
1381
1444
|
logger.debug(`Unreadable audit subject: ${scanPath}`);
|
|
1382
1445
|
return [unreadablePathResult(scanPath, error, locationRoot)];
|
|
@@ -1450,13 +1513,10 @@ function withoutHostedRefusals(result, hosted) {
|
|
|
1450
1513
|
return [];
|
|
1451
1514
|
if (issues.length === result.issues.length)
|
|
1452
1515
|
return [result];
|
|
1453
|
-
const issueCounts = countBySeverity(issues);
|
|
1454
1516
|
return [{
|
|
1455
1517
|
...result,
|
|
1456
|
-
|
|
1457
|
-
summary: formatCountsSummary(issueCounts),
|
|
1518
|
+
...describeIssues(issues, result.type),
|
|
1458
1519
|
issues,
|
|
1459
|
-
issueCounts,
|
|
1460
1520
|
}];
|
|
1461
1521
|
}
|
|
1462
1522
|
async function validateAuditSubject(scanPath, recursive, options, logger, locationRoot) {
|
|
@@ -1523,7 +1583,7 @@ async function validateAuditSubject(scanPath, recursive, options, logger, locati
|
|
|
1523
1583
|
return [result];
|
|
1524
1584
|
}
|
|
1525
1585
|
// If unknown format, check if it's a directory we can scan
|
|
1526
|
-
if (await isScannableDirectory(scanPath)) {
|
|
1586
|
+
if (await isScannableDirectory(scanPath, locationRoot)) {
|
|
1527
1587
|
logger.debug('Scanning directory for resources');
|
|
1528
1588
|
// The project's `resources.exclude` is applied by the scan context,
|
|
1529
1589
|
// on the project-root basis its globs were written against — NOT
|
|
@@ -1551,10 +1611,10 @@ async function validateAuditSubject(scanPath, recursive, options, logger, locati
|
|
|
1551
1611
|
* `validate()` then reported the directory as an unknown resource format. A
|
|
1552
1612
|
* scan that examined nothing was reported as a directory that was nothing.
|
|
1553
1613
|
*/
|
|
1554
|
-
async function isScannableDirectory(scanPath) {
|
|
1555
|
-
const fsp = await import('node:fs/promises');
|
|
1614
|
+
async function isScannableDirectory(scanPath, locationRoot) {
|
|
1556
1615
|
try {
|
|
1557
|
-
|
|
1616
|
+
// `scanPath` is crawled beneath the run's scan root: its links are read before the kernel follows them.
|
|
1617
|
+
return (await followedKind(scanPath, locationRoot)) === 'directory';
|
|
1558
1618
|
}
|
|
1559
1619
|
catch (error) {
|
|
1560
1620
|
if (isPathAbsentError(error))
|
|
@@ -1574,11 +1634,12 @@ async function isScannableDirectory(scanPath) {
|
|
|
1574
1634
|
async function validatePluginSkillsViaInventory(scanPath, options, logger, locationRoot, excludeSkillPaths = new Set()) {
|
|
1575
1635
|
const inv = await pluginInventoryAt(scanPath);
|
|
1576
1636
|
const results = [];
|
|
1577
|
-
|
|
1637
|
+
// In order: the skills share the population cache and the logger.
|
|
1638
|
+
await forEachInOrder(inv.discovered.skills, async (skill) => {
|
|
1578
1639
|
const resolvedPath = safePath.resolve(skill.files.skillMd);
|
|
1579
1640
|
if (excludeSkillPaths.has(resolvedPath)) {
|
|
1580
1641
|
logger.debug(` Skipping already-validated skill (inventory): ${skill.files.skillMd}`);
|
|
1581
|
-
|
|
1642
|
+
return;
|
|
1582
1643
|
}
|
|
1583
1644
|
logger.debug(` Validating plugin-bundled skill (inventory): ${skill.files.skillMd}`);
|
|
1584
1645
|
// Guarded PER SKILL, not left to the boundary. The boundary guard answers at
|
|
@@ -1596,12 +1657,12 @@ async function validatePluginSkillsViaInventory(scanPath, options, logger, locat
|
|
|
1596
1657
|
results.push(await validateSingleSkill(skill.files.skillMd, options, logger, locationRoot, false));
|
|
1597
1658
|
}
|
|
1598
1659
|
catch (error) {
|
|
1599
|
-
if (
|
|
1660
|
+
if (fsFaultOf(error) === undefined)
|
|
1600
1661
|
throw error;
|
|
1601
1662
|
logger.debug(` Unreadable plugin-bundled skill: ${skill.files.skillMd}`);
|
|
1602
1663
|
results.push(unreadablePathResult(skill.files.skillMd, error, locationRoot));
|
|
1603
1664
|
}
|
|
1604
|
-
}
|
|
1665
|
+
});
|
|
1605
1666
|
return results;
|
|
1606
1667
|
}
|
|
1607
1668
|
/**
|
|
@@ -1667,9 +1728,10 @@ function withRelativePath(message, absolutePath, locationRoot) {
|
|
|
1667
1728
|
*/
|
|
1668
1729
|
export async function runCompatAnalysis(results, logger, locationRoot, effectiveSettings, vatContext = null) {
|
|
1669
1730
|
const compatMap = new Map();
|
|
1670
|
-
|
|
1731
|
+
// In order: each plugin's explanations go to the logger as it is analyzed.
|
|
1732
|
+
await forEachInOrder(results, async (result) => {
|
|
1671
1733
|
if (result.type !== RESOURCE_TYPE_CLAUDE_PLUGIN)
|
|
1672
|
-
|
|
1734
|
+
return;
|
|
1673
1735
|
const entry = {
|
|
1674
1736
|
compat: await analyzeOrExplain(result.path, locationRoot, vatContext, logger),
|
|
1675
1737
|
};
|
|
@@ -1677,9 +1739,31 @@ export async function runCompatAnalysis(results, logger, locationRoot, effective
|
|
|
1677
1739
|
entry.settings = await settingsVerdict(result.path, effectiveSettings, locationRoot, logger);
|
|
1678
1740
|
}
|
|
1679
1741
|
compatMap.set(result.path, entry);
|
|
1680
|
-
}
|
|
1742
|
+
});
|
|
1743
|
+
fileLaneFindings(results, compatMap, locationRoot);
|
|
1681
1744
|
return compatMap;
|
|
1682
1745
|
}
|
|
1746
|
+
/**
|
|
1747
|
+
* File what the lanes found, and what they could not look at, as findings on each plugin's own
|
|
1748
|
+
* result — so the envelope's status, the row's status and the file counts say what the
|
|
1749
|
+
* `compatibility:` and `settings:` blocks say. A path whose refusal the document already carries
|
|
1750
|
+
* (by its code: `compatLaneIssues` decides which) is not filed a second time.
|
|
1751
|
+
*/
|
|
1752
|
+
function fileLaneFindings(results, compatMap, locationRoot) {
|
|
1753
|
+
const locationOf = (absolutePath) => issueLocation(absolutePath, locationRoot) || '.';
|
|
1754
|
+
const filed = results.flatMap((result) => result.issues.map((issue) => ({ code: issue.code, location: issue.location ?? locationOf(result.path) })));
|
|
1755
|
+
for (const result of results) {
|
|
1756
|
+
const entry = compatMap.get(result.path);
|
|
1757
|
+
if (entry === undefined)
|
|
1758
|
+
continue;
|
|
1759
|
+
const issues = compatLaneIssues(locationOf(result.path), {
|
|
1760
|
+
compatibility: entry.compat,
|
|
1761
|
+
...(entry.settings !== undefined && { settings: renderSettingsBlock(entry.settings, locationRoot) }),
|
|
1762
|
+
}, filed);
|
|
1763
|
+
appendIssues(result, issues);
|
|
1764
|
+
filed.push(...issues.map((issue) => ({ code: issue.code, location: issue.location ?? locationOf(result.path) })));
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1683
1767
|
/**
|
|
1684
1768
|
* The analyzer's result for one plugin, or — when it threw — the reason, said
|
|
1685
1769
|
* on stderr and carried into the document. Compat analysis is best-effort:
|
|
@@ -1767,45 +1851,65 @@ function applyCompatMap(results, compatMap, locationRoot) {
|
|
|
1767
1851
|
return results;
|
|
1768
1852
|
}
|
|
1769
1853
|
/**
|
|
1770
|
-
*
|
|
1771
|
-
*
|
|
1772
|
-
* (even as `[]`) would clutter terse YAML; we omit the key entirely.
|
|
1854
|
+
* `compatibility.evidence` is published only under `--verbose`. Producing the
|
|
1855
|
+
* field at all (even as `[]`) would clutter terse YAML; the key is omitted.
|
|
1773
1856
|
*/
|
|
1774
1857
|
function stripCompatEvidence(compat) {
|
|
1775
1858
|
const out = { ...compat };
|
|
1776
1859
|
delete out['evidence'];
|
|
1777
1860
|
return out;
|
|
1778
1861
|
}
|
|
1779
|
-
function applyVerboseFilter(results, verbose) {
|
|
1780
|
-
if (verbose)
|
|
1781
|
-
return results;
|
|
1782
|
-
return results.map(r => {
|
|
1783
|
-
const stripped = { ...r };
|
|
1784
|
-
delete stripped['evidence'];
|
|
1785
|
-
if (r.compatibility !== undefined) {
|
|
1786
|
-
stripped['compatibility'] = stripCompatEvidence(r.compatibility);
|
|
1787
|
-
}
|
|
1788
|
-
return stripped;
|
|
1789
|
-
});
|
|
1790
|
-
}
|
|
1791
1862
|
/**
|
|
1792
|
-
*
|
|
1793
|
-
*
|
|
1794
|
-
*
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1863
|
+
* A result's row. `status` and `summary` are re-derived from its FINAL issue
|
|
1864
|
+
* list here — a producer that appended findings after publishing its counts
|
|
1865
|
+
* cannot leave the row describing the list as it was.
|
|
1866
|
+
*/
|
|
1867
|
+
function fileRow(result, root, verbose) {
|
|
1868
|
+
const row = { path: relativizePath(result.path, root), type: result.type, ...summarizeIssues(result.issues) };
|
|
1869
|
+
if (result.compatibility !== undefined)
|
|
1870
|
+
row.compatibility = verbose ? result.compatibility : stripCompatEvidence(result.compatibility);
|
|
1871
|
+
if (result.settings !== undefined)
|
|
1872
|
+
row.settings = result.settings;
|
|
1873
|
+
return row;
|
|
1874
|
+
}
|
|
1875
|
+
/**
|
|
1876
|
+
* Every file's findings, flattened, each naming the file to open. A finding a
|
|
1877
|
+
* validator published without a `location` inherits its file's row path, so a
|
|
1878
|
+
* consumer never has to join a finding back to the row it came from.
|
|
1879
|
+
*/
|
|
1880
|
+
function auditFindings(results, root) {
|
|
1881
|
+
return toFindings(results.flatMap((result) => result.issues.map((issue) => issue.location === undefined ? { ...issue, location: relativizePath(result.path, root) } : issue)));
|
|
1882
|
+
}
|
|
1883
|
+
/**
|
|
1884
|
+
* Assemble the report envelope from the per-file results.
|
|
1885
|
+
*
|
|
1886
|
+
* ONE builder for the directory lane, the `--user` lane and the corpus scan's
|
|
1887
|
+
* per-plugin document, so none of them can publish a status or a count the
|
|
1888
|
+
* others would not. `examined` is the files READ — a refused path is counted
|
|
1889
|
+
* in `data.counts.pathsUnreadable` and nowhere else — and the writer turns a
|
|
1890
|
+
* zero into the run's `RESOURCE_CHECK_BROKEN` finding.
|
|
1891
|
+
*
|
|
1892
|
+
* @param results - One result per audited file or refused path
|
|
1893
|
+
* @param context - The root, the compat lanes' output and the `--user` view
|
|
1894
|
+
* @returns The report, before the writer's run-integrity pass
|
|
1895
|
+
*/
|
|
1896
|
+
export function buildAuditDocument(results, context) {
|
|
1897
|
+
const { root, compatMap, verbose, hierarchical, durationMs } = context;
|
|
1898
|
+
const { examined, counts } = countFilesByStatus(results);
|
|
1899
|
+
return buildReport({
|
|
1900
|
+
examined,
|
|
1901
|
+
findings: auditFindings(results, root),
|
|
1902
|
+
data: {
|
|
1903
|
+
// Stated once, and the only absolute path in the document.
|
|
1904
|
+
root,
|
|
1905
|
+
provenance: null,
|
|
1906
|
+
counts,
|
|
1907
|
+
files: applyCompatMap([...results], compatMap, root).map((result) => fileRow(result, root, verbose)),
|
|
1908
|
+
hierarchical,
|
|
1909
|
+
},
|
|
1910
|
+
gate: AUDIT_GATE,
|
|
1911
|
+
durationMs,
|
|
1912
|
+
});
|
|
1809
1913
|
}
|
|
1810
1914
|
/**
|
|
1811
1915
|
* Maps a CAPABILITY_* observation code to the family of pattern IDs whose
|
|
@@ -1903,21 +2007,22 @@ function renderVerboseEvidence(results, root, logger) {
|
|
|
1903
2007
|
}
|
|
1904
2008
|
}
|
|
1905
2009
|
/**
|
|
1906
|
-
* The stderr half of
|
|
1907
|
-
* document says. The
|
|
1908
|
-
*
|
|
1909
|
-
*
|
|
1910
|
-
*
|
|
1911
|
-
*
|
|
2010
|
+
* The stderr half of the run-level refusal, so the human channel says what the
|
|
2011
|
+
* document says. The writer derives it (the registry's denominator for `audit`
|
|
2012
|
+
* is files); this only RENDERS the finding the WRITTEN report carries. Both
|
|
2013
|
+
* stderr lanes call it first, because "Audit successful: 0 file(s) passed"
|
|
2014
|
+
* over a refused run is the exact disagreement the refusal exists to end
|
|
2015
|
+
* (invariant 6 of `run-integrity.ts`).
|
|
1912
2016
|
*
|
|
1913
2017
|
* @returns Whether a refusal was rendered, so the caller skips its verdict line
|
|
1914
2018
|
*/
|
|
1915
|
-
function logRunIntegrity(
|
|
1916
|
-
|
|
2019
|
+
function logRunIntegrity(written, logger) {
|
|
2020
|
+
const refusals = written.findings.filter((finding) => finding.code === RUN_INTEGRITY_CODE);
|
|
2021
|
+
if (refusals.length === 0)
|
|
1917
2022
|
return false;
|
|
1918
|
-
logger.error(
|
|
1919
|
-
for (const
|
|
1920
|
-
for (const line of formatIssueLines(
|
|
2023
|
+
logger.error(`Audit is not a verdict: it audited ${written.examined} files`);
|
|
2024
|
+
for (const refusal of refusals) {
|
|
2025
|
+
for (const line of formatIssueLines(refusal, ' '))
|
|
1921
2026
|
logger.error(line);
|
|
1922
2027
|
}
|
|
1923
2028
|
return true;
|
|
@@ -1957,36 +2062,34 @@ function logSettingsTotals(files, logger) {
|
|
|
1957
2062
|
logger.error(`⚠ ${compatUnchecked} path(s) the compatibility analysis could not read — see 'compatibility.unchecked' in YAML output`);
|
|
1958
2063
|
}
|
|
1959
2064
|
}
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
if (refused) {
|
|
2065
|
+
/**
|
|
2066
|
+
* The human channel for the directory lane, read off the WRITTEN report — the
|
|
2067
|
+
* file counts, and the findings of the files that carry an actionable one. The
|
|
2068
|
+
* exit code is not decided here: the caller ends on `exitCodeForReport`.
|
|
2069
|
+
*/
|
|
2070
|
+
function handleAuditResults({ results, written, data, root, verbose }, logger) {
|
|
2071
|
+
const { filesWithErrors: errorCount, filesWithWarnings: warningCount, filesPassed: successCount, } = data.counts;
|
|
2072
|
+
logSettingsTotals(data.files, logger);
|
|
2073
|
+
if (logRunIntegrity(written, logger)) {
|
|
1970
2074
|
// Rendered above; there is no file verdict to print over zero files.
|
|
1971
2075
|
}
|
|
1972
2076
|
else if (errorCount > 0) {
|
|
1973
2077
|
logger.error(`Audit found ${errorCount} file(s) with errors`);
|
|
1974
|
-
logFindingsForStatus(results,
|
|
2078
|
+
logFindingsForStatus(results, hasErrors, root, logger.error.bind(logger), verbose);
|
|
1975
2079
|
}
|
|
1976
2080
|
else if (warningCount > 0) {
|
|
1977
2081
|
logger.info(`Audit passed with warnings: ${warningCount} file(s)`);
|
|
1978
|
-
logFindingsForStatus(results,
|
|
2082
|
+
logFindingsForStatus(results, hasOnlyWarnings, root, logger.info.bind(logger), verbose);
|
|
1979
2083
|
}
|
|
1980
2084
|
else {
|
|
1981
|
-
// `
|
|
1982
|
-
//
|
|
2085
|
+
// `ok` over info findings still means "nothing actionable", NOT "nothing
|
|
2086
|
+
// to see" — name them or the YAML and the stderr line disagree.
|
|
1983
2087
|
const withFindings = countResultsWithFindings(results);
|
|
1984
2088
|
logger.info(withFindings > 0
|
|
1985
2089
|
? `Audit successful: ${successCount} file(s) passed (${withFindings} with informational findings)`
|
|
1986
2090
|
: `Audit successful: ${successCount} file(s) passed`);
|
|
1987
2091
|
}
|
|
1988
2092
|
renderAuditFooter(results, logger);
|
|
1989
|
-
process.exit(refused || errorCount > 0 ? ExitCode.FINDINGS : ExitCode.OK);
|
|
1990
2093
|
}
|
|
1991
2094
|
/**
|
|
1992
2095
|
* Render the skill-quality checklist footer when audit results contain
|
|
@@ -2039,7 +2142,7 @@ function renderAuditFooter(results, logger) {
|
|
|
2039
2142
|
* cannot answer the question.
|
|
2040
2143
|
*
|
|
2041
2144
|
* Pure: takes results, returns lines. It reads `issues` and never rewrites it,
|
|
2042
|
-
* because `
|
|
2145
|
+
* because `buildAuditAtPath` builds the YAML document from the very same array.
|
|
2043
2146
|
*
|
|
2044
2147
|
* @internal Exported for unit testing only — not part of the public CLI API.
|
|
2045
2148
|
*/
|
|
@@ -2075,8 +2178,8 @@ export function formatAuditFindingsLines(results, root, verbose) {
|
|
|
2075
2178
|
* The banner counts FILES and the blocks below count FINDINGS; both are needed,
|
|
2076
2179
|
* and `logFn` picks the channel the calling branch already established.
|
|
2077
2180
|
*/
|
|
2078
|
-
function logFindingsForStatus(results,
|
|
2079
|
-
const selected = results.filter(
|
|
2181
|
+
function logFindingsForStatus(results, inBucket, root, logFn, verbose) {
|
|
2182
|
+
const selected = results.filter(inBucket);
|
|
2080
2183
|
for (const line of formatAuditFindingsLines(selected, root, verbose)) {
|
|
2081
2184
|
logFn(line);
|
|
2082
2185
|
}
|
|
@@ -2158,15 +2261,16 @@ async function handleFileEntry(entry, fullPath, options, logger, scanCtx) {
|
|
|
2158
2261
|
const skillDir = safePath.resolve(fullPath, '..');
|
|
2159
2262
|
const unreadable = degradingRegistry(findProjectRoot(skillDir) ?? skillDir, logger, locationRoot);
|
|
2160
2263
|
const sharedCtx = scanCtx.gitTracker === null
|
|
2161
|
-
? { locationRoot, projectSkills, suiteProbe, unreadable }
|
|
2162
|
-
: { gitTracker: scanCtx.gitTracker, locationRoot, projectSkills, suiteProbe, unreadable };
|
|
2264
|
+
? { locationRoot, projectSkills, suiteProbe, unreadable, outputs: [] }
|
|
2265
|
+
: { gitTracker: scanCtx.gitTracker, locationRoot, projectSkills, suiteProbe, unreadable, outputs: [] };
|
|
2163
2266
|
const packagingResult = await validateSkillForPackaging(fullPath, skillConfig, 'source', sharedCtx);
|
|
2164
2267
|
const configAware = packagingResultToValidationResult(fullPath, packagingResult, skillConfig.targets, locationRoot);
|
|
2165
2268
|
await appendDistributedTreeFindings(configAware, fullPath, locationRoot, ownsOwnCrawl(scanCtx, fullPath));
|
|
2166
2269
|
return configAware;
|
|
2167
2270
|
}
|
|
2168
2271
|
// Wild mode: basic validation. Severity is applied by `applySeverityFilter`.
|
|
2169
|
-
|
|
2272
|
+
// The audited skill is the verb's input.
|
|
2273
|
+
const validateOptions = { skillPath: fullPath, locationRoot, validation: {}, side: 'source' };
|
|
2170
2274
|
if (options.warnUnreferencedFiles) {
|
|
2171
2275
|
validateOptions.checkUnreferencedFiles = true;
|
|
2172
2276
|
}
|
|
@@ -2203,7 +2307,7 @@ async function validatePluginDirectory(dir, logger, locationRoot) {
|
|
|
2203
2307
|
*/
|
|
2204
2308
|
const inventoryRegistryCache = new Map();
|
|
2205
2309
|
/** Build (once per run, per root) the registry the plugin inventory link walk needs. */
|
|
2206
|
-
|
|
2310
|
+
function getOrCreateInventoryRegistry(projectRoot) {
|
|
2207
2311
|
const cached = inventoryRegistryCache.get(projectRoot);
|
|
2208
2312
|
if (cached !== undefined) {
|
|
2209
2313
|
return cached;
|
|
@@ -2239,7 +2343,7 @@ async function getOrCreateInventoryRegistry(projectRoot) {
|
|
|
2239
2343
|
* case to encode here. This is the call site that carried all 786 measured
|
|
2240
2344
|
* `git check-ignore` spawns.
|
|
2241
2345
|
*/
|
|
2242
|
-
|
|
2346
|
+
function pluginInventoryAt(dir) {
|
|
2243
2347
|
const projectRoot = findProjectRoot(dir);
|
|
2244
2348
|
return extractClaudePluginInventory(dir, {
|
|
2245
2349
|
...(projectRoot === null
|
|
@@ -2304,11 +2408,11 @@ async function resolveScanContext(dirPath, locationRoot, logger) {
|
|
|
2304
2408
|
* is no longer the ONLY thing the run says — the code, the location and the fix
|
|
2305
2409
|
* come from the registry.
|
|
2306
2410
|
*
|
|
2307
|
-
* This result is a `files[]` row but NOT a
|
|
2411
|
+
* This result is a `data.files[]` row but NOT a file read: `countFilesByStatus`
|
|
2308
2412
|
* recognises it ({@link isUnreadablePathResult}) and reports it under
|
|
2309
|
-
* `
|
|
2310
|
-
* root the OS refused therefore
|
|
2311
|
-
* refusal, instead of `
|
|
2413
|
+
* `data.counts.pathsUnreadable`, outside `examined` and the status counts. A
|
|
2414
|
+
* root the OS refused therefore examines zero files and ends on the zero-files
|
|
2415
|
+
* refusal, instead of `examined: 1` over a path nothing read.
|
|
2312
2416
|
*/
|
|
2313
2417
|
function unreadablePathResult(dirPath, error, locationRoot) {
|
|
2314
2418
|
// `issueLocation` is `path.relative`, so it answers `''` when the subject IS the
|
|
@@ -2329,14 +2433,11 @@ function unreadablePathResult(dirPath, error, locationRoot) {
|
|
|
2329
2433
|
detail: `${location}: ${reason}`,
|
|
2330
2434
|
}),
|
|
2331
2435
|
];
|
|
2332
|
-
const issueCounts = countBySeverity(issues);
|
|
2333
2436
|
return {
|
|
2334
2437
|
path: dirPath,
|
|
2335
2438
|
type: 'unknown',
|
|
2336
|
-
|
|
2337
|
-
summary: formatCountsSummary(issueCounts),
|
|
2439
|
+
...describeIssues(issues, 'unknown'),
|
|
2338
2440
|
issues,
|
|
2339
|
-
issueCounts,
|
|
2340
2441
|
};
|
|
2341
2442
|
}
|
|
2342
2443
|
/**
|
|
@@ -2366,7 +2467,7 @@ async function validateScanSubject(subject, options, logger, scanCtx, claims) {
|
|
|
2366
2467
|
}
|
|
2367
2468
|
const subjectCtx = { ...scanCtx, crawledRoot: claims.owner(subject.path) };
|
|
2368
2469
|
const result = await handleFileEntry({ name: basename(subject.path) }, subject.path, options, logger, subjectCtx);
|
|
2369
|
-
if (subject.kind === 'skill' && ownsOwnCrawl(subjectCtx, subject.path) && await crawlOwnsSubtree(subject.path)) {
|
|
2470
|
+
if (subject.kind === 'skill' && ownsOwnCrawl(subjectCtx, subject.path) && await crawlOwnsSubtree(subject.path, locationRoot)) {
|
|
2370
2471
|
claims.claim(subject.dir);
|
|
2371
2472
|
}
|
|
2372
2473
|
return result === null ? [] : [result];
|
|
@@ -2376,7 +2477,7 @@ async function validateScanSubject(subject, options, logger, scanCtx, claims) {
|
|
|
2376
2477
|
// turning a genuine VAT bug into a `warning` about the file it happened on is
|
|
2377
2478
|
// the same "detector silently disables itself" shape this guard exists to
|
|
2378
2479
|
// prevent — it would make the tool quietest exactly when it is most wrong.
|
|
2379
|
-
if (
|
|
2480
|
+
if (fsFaultOf(error) === undefined)
|
|
2380
2481
|
throw error;
|
|
2381
2482
|
const path = subject.kind === 'plugin' ? subject.dir : subject.path;
|
|
2382
2483
|
logger.debug(`Unreadable entry: ${path}`);
|
|
@@ -2427,29 +2528,16 @@ async function scanDirectory(dirPath, recursive, options, logger, scanCtx) {
|
|
|
2427
2528
|
}
|
|
2428
2529
|
const results = population.refusals.map((refusal) => {
|
|
2429
2530
|
logger.debug(`Unreadable directory: ${refusal.directory}`);
|
|
2430
|
-
const err = new DirectoryListingRefusedError(refusal, { root: dirPath, remedy: scanRefusalRemedy() });
|
|
2531
|
+
const err = new DirectoryListingRefusedError(refusal, { root: dirPath, remedy: scanRefusalRemedy(), side: 'source' });
|
|
2431
2532
|
return unreadablePathResult(refusal.directory, err, scanCtx.locationRoot);
|
|
2432
2533
|
});
|
|
2433
2534
|
const claims = new SubtreeClaims();
|
|
2434
|
-
|
|
2535
|
+
// In order: `claims` resolves each subtree against the subjects before it.
|
|
2536
|
+
await forEachInOrder(population.subjects, async (subject) => {
|
|
2435
2537
|
results.push(...await validateScanSubject(subject, options, logger, scanCtx, claims));
|
|
2436
|
-
}
|
|
2538
|
+
});
|
|
2437
2539
|
return results;
|
|
2438
2540
|
}
|
|
2439
|
-
/**
|
|
2440
|
-
* Calculate overall status from validation results
|
|
2441
|
-
*/
|
|
2442
|
-
function calculateOverallStatus(results) {
|
|
2443
|
-
const errorCount = results.filter((r) => r.status === 'error').length;
|
|
2444
|
-
const warningCount = results.filter((r) => r.status === 'warning').length;
|
|
2445
|
-
if (errorCount > 0) {
|
|
2446
|
-
return 'error';
|
|
2447
|
-
}
|
|
2448
|
-
if (warningCount > 0) {
|
|
2449
|
-
return 'warning';
|
|
2450
|
-
}
|
|
2451
|
-
return 'success';
|
|
2452
|
-
}
|
|
2453
2541
|
/**
|
|
2454
2542
|
* How many results carry at least one finding.
|
|
2455
2543
|
*
|
|
@@ -2473,147 +2561,53 @@ function isUnreadablePathResult(result) {
|
|
|
2473
2561
|
&& result.issues.every((issue) => issue.code === 'SCAN_PATH_UNREADABLE');
|
|
2474
2562
|
}
|
|
2475
2563
|
/**
|
|
2476
|
-
* Count files by their
|
|
2564
|
+
* Count files by their worst actionable severity, and the files read.
|
|
2477
2565
|
*
|
|
2478
2566
|
* A refused path is NOT a scanned file. It used to be counted as one, which
|
|
2479
2567
|
* made the zero-files refusal unreachable for exactly the tree it exists for:
|
|
2480
|
-
* `chmod 000` on the whole root gave
|
|
2481
|
-
*
|
|
2482
|
-
*
|
|
2568
|
+
* `chmod 000` on the whole root gave one file scanned, none passed, a warning
|
|
2569
|
+
* status and exit 0 — nothing read, gate green. Kept out of every status count
|
|
2570
|
+
* too, or `filesWithWarnings` would exceed the files read.
|
|
2483
2571
|
*/
|
|
2484
2572
|
function countFilesByStatus(results) {
|
|
2485
2573
|
const scanned = results.filter((r) => !isUnreadablePathResult(r));
|
|
2574
|
+
const withErrors = scanned.filter(hasErrors).length;
|
|
2575
|
+
const withWarnings = scanned.filter(hasOnlyWarnings).length;
|
|
2486
2576
|
return {
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
}
|
|
2494
|
-
/**
|
|
2495
|
-
* Build base summary structure (used by both flat and hierarchical), together
|
|
2496
|
-
* with the entries the document will publish.
|
|
2497
|
-
*
|
|
2498
|
-
* `issueCounts` is named exactly as it is on every individual file entry, and
|
|
2499
|
-
* means the same thing at both levels: findings, by severity. `summary` only ever
|
|
2500
|
-
* counts files.
|
|
2501
|
-
*
|
|
2502
|
-
* The header total and every per-file total come from ONE traversal of the
|
|
2503
|
-
* final issue set, and the entries carrying those per-file totals are returned
|
|
2504
|
-
* from the same pass. Before that, the header was derived from the issue
|
|
2505
|
-
* records while each file's `issueCounts` was whatever its producer had
|
|
2506
|
-
* published — and a producer that appends findings after publishing (or never
|
|
2507
|
-
* sets the counts at all: `validatePlugin` writes `status` and `summary` but
|
|
2508
|
-
* not `issueCounts`) left the two disagreeing inside one document. A real
|
|
2509
|
-
* `vat audit --user` run said 55/422/504 in the header over per-file counts
|
|
2510
|
-
* summing to 55/360/405, with 91 of 614 entries declaring `{0,0,0}` above the
|
|
2511
|
-
* findings they listed. Re-deriving here means the header and the sum are the
|
|
2512
|
-
* same arithmetic on the same array, so they cannot drift again no matter what
|
|
2513
|
-
* a producer forgets.
|
|
2514
|
-
*
|
|
2515
|
-
* `linkedFiles[].issues` are deliberately NOT added: every linked finding is
|
|
2516
|
-
* also present in its owner's `issues`, so the nested list is a VIEW of records
|
|
2517
|
-
* already counted, not extra records. `audit-report-coherence.integration.test.ts`
|
|
2518
|
-
* pins that subset relation, because counting once is only correct while it holds.
|
|
2519
|
-
*
|
|
2520
|
-
* 🚨 **Zero files audited is an ERROR, not "an empty tree audits cleanly".**
|
|
2521
|
-
* `calculateOverallStatus([])` is `success`, so an existing directory holding
|
|
2522
|
-
* nothing auditable — moved plugins, a wrong subdirectory, an excluded tree, a
|
|
2523
|
-
* tree of files no lane recognises — published `status: success` beside
|
|
2524
|
-
* `filesScanned: 0`, and this command's own documentation tells CI to gate on
|
|
2525
|
-
* that `status`. Derived HERE, in the one builder both the directory lane
|
|
2526
|
-
* (`calculateSummary`) and the `--user` lane (`calculateHierarchicalSummary`)
|
|
2527
|
-
* pass through, so neither can publish a clean status over a zero denominator.
|
|
2528
|
-
* Through the shared mechanism in `run-integrity.ts`: one non-overridable
|
|
2529
|
-
* `RESOURCE_CHECK_BROKEN` at `error`, published under a top-level `issues` —
|
|
2530
|
-
* the claim is about the RUN, so it is not a `files[]` row and does not count
|
|
2531
|
-
* toward `filesScanned` — and counted in the header `issueCounts`, so the
|
|
2532
|
-
* identity becomes `issueCounts === Σ files[].issueCounts + Σ issues`.
|
|
2533
|
-
*
|
|
2534
|
-
* The exit code is NOT touched by this: `status` describes the findings and the
|
|
2535
|
-
* exit code describes whether the run completed, and this run completed. See
|
|
2536
|
-
* {@link createAuditCommand}.
|
|
2537
|
-
*/
|
|
2538
|
-
function buildBaseSummary(results, startTime) {
|
|
2539
|
-
const issueCounts = { errors: 0, warnings: 0, info: 0 };
|
|
2540
|
-
const entries = results.map((result) => {
|
|
2541
|
-
const counts = countBySeverity(result.issues);
|
|
2542
|
-
issueCounts.errors += counts.errors;
|
|
2543
|
-
issueCounts.warnings += counts.warnings;
|
|
2544
|
-
issueCounts.info += counts.info;
|
|
2545
|
-
return { ...result, issueCounts: counts };
|
|
2546
|
-
});
|
|
2547
|
-
const summary = countFilesByStatus(entries);
|
|
2548
|
-
// The denominator is files READ: a tree whose every path was refused audited
|
|
2549
|
-
// nothing, and says so through the same refusal as an empty tree.
|
|
2550
|
-
const runIssues = nothingCheckedFinding(summary.filesScanned, entries.flatMap((entry) => entry.issues), () => 'The audit ran over 0 files, so this report is not a verdict: a tree with nothing'
|
|
2551
|
-
+ ' to audit produces the same counts as a clean one. The path resolved to a tree'
|
|
2552
|
-
+ ' holding no auditable file — usually a wrong subdirectory, plugins or skills that'
|
|
2553
|
-
+ ' have moved, an excluded tree, files no audit lane recognises, or `--no-recursive`'
|
|
2554
|
-
+ ' over a tree whose resources sit deeper. Point the command at the plugin,'
|
|
2555
|
-
+ ' marketplace, registry or SKILL.md tree it should read.');
|
|
2556
|
-
return {
|
|
2557
|
-
entries,
|
|
2558
|
-
// Every run-integrity finding is `error` by construction (invariant 2 of
|
|
2559
|
-
// `run-integrity.ts`), so a non-empty refusal IS the status; otherwise the
|
|
2560
|
-
// files decide it, as before.
|
|
2561
|
-
status: runIssues.length > 0 ? 'error' : calculateOverallStatus(entries),
|
|
2562
|
-
summary,
|
|
2563
|
-
issueCounts: sumSeverityCounts([issueCounts, countBySeverity(runIssues)]),
|
|
2564
|
-
...(runIssues.length === 0 ? {} : { issues: [...runIssues] }),
|
|
2565
|
-
duration: `${Date.now() - startTime}ms`,
|
|
2566
|
-
};
|
|
2567
|
-
}
|
|
2568
|
-
/**
|
|
2569
|
-
* Calculate summary for hierarchical output
|
|
2570
|
-
*/
|
|
2571
|
-
function calculateHierarchicalSummary(results, hierarchical, startTime, compatMap, verbose, root) {
|
|
2572
|
-
const { entries, ...base } = buildBaseSummary(results, startTime);
|
|
2573
|
-
const withCompat = applyCompatMap(entries, compatMap, root);
|
|
2574
|
-
return {
|
|
2575
|
-
root,
|
|
2576
|
-
...base,
|
|
2577
|
-
summary: {
|
|
2578
|
-
...base.summary,
|
|
2579
|
-
marketplaces: hierarchical.marketplaces.length,
|
|
2580
|
-
cachedPlugins: hierarchical.cachedPlugins.length,
|
|
2581
|
-
standalonePlugins: hierarchical.standalonePlugins.length,
|
|
2582
|
-
standaloneSkills: hierarchical.standaloneSkills.length,
|
|
2577
|
+
examined: scanned.length,
|
|
2578
|
+
counts: {
|
|
2579
|
+
filesPassed: scanned.length - withErrors - withWarnings,
|
|
2580
|
+
filesWithWarnings: withWarnings,
|
|
2581
|
+
filesWithErrors: withErrors,
|
|
2582
|
+
pathsUnreadable: results.length - scanned.length,
|
|
2583
2583
|
},
|
|
2584
|
-
files: relativizePathEntries(applyVerboseFilter(withCompat, verbose), root, NESTED_PATH_CARRIERS),
|
|
2585
|
-
hierarchical,
|
|
2586
2584
|
};
|
|
2587
2585
|
}
|
|
2588
2586
|
/**
|
|
2589
|
-
*
|
|
2587
|
+
* The human channel for the `--user` lane, read off the WRITTEN report. The
|
|
2588
|
+
* exit code is not decided here: the caller ends on `exitCodeForReport`.
|
|
2590
2589
|
*/
|
|
2591
|
-
function logHierarchicalSummary(results,
|
|
2592
|
-
const
|
|
2590
|
+
function logHierarchicalSummary({ results, written, data }, logger) {
|
|
2591
|
+
const { filesWithErrors, filesWithWarnings } = data.counts;
|
|
2593
2592
|
const skillsWithIssues = countResultsWithFindings(results);
|
|
2594
2593
|
const totalSkills = results.length;
|
|
2595
|
-
|
|
2596
|
-
const refused = logRunIntegrity(runIssues, logger);
|
|
2597
|
-
if (refused) {
|
|
2594
|
+
if (logRunIntegrity(written, logger)) {
|
|
2598
2595
|
// Rendered above; there is no skill verdict to print over zero skills.
|
|
2599
2596
|
}
|
|
2600
|
-
else if (
|
|
2601
|
-
|
|
2602
|
-
logger.error(`Audit found ${errorCount} skill(s) with errors (${totalSkills} scanned, ${skillsWithIssues} with issues)`);
|
|
2597
|
+
else if (filesWithErrors > 0) {
|
|
2598
|
+
logger.error(`Audit found ${filesWithErrors} skill(s) with errors (${totalSkills} scanned, ${skillsWithIssues} with issues)`);
|
|
2603
2599
|
}
|
|
2604
|
-
else if (
|
|
2605
|
-
|
|
2606
|
-
logger.info(`Audit passed with warnings: ${warningCount} skill(s) (${totalSkills} scanned, ${skillsWithIssues} with issues)`);
|
|
2600
|
+
else if (filesWithWarnings > 0) {
|
|
2601
|
+
logger.info(`Audit passed with warnings: ${filesWithWarnings} skill(s) (${totalSkills} scanned, ${skillsWithIssues} with issues)`);
|
|
2607
2602
|
}
|
|
2608
2603
|
else if (skillsWithIssues > 0) {
|
|
2609
|
-
//
|
|
2610
|
-
//
|
|
2604
|
+
// Nothing actionable is NOT "nothing to see". Saying only "N passed" over
|
|
2605
|
+
// a pile of info findings is how they stayed invisible.
|
|
2611
2606
|
logger.info(`Audit successful: ${totalSkills} skill(s) passed (${skillsWithIssues} with informational findings)`);
|
|
2612
2607
|
}
|
|
2613
2608
|
else {
|
|
2614
2609
|
logger.info(`Audit successful: ${totalSkills} skill(s) passed`);
|
|
2615
2610
|
}
|
|
2616
2611
|
renderAuditFooter(results, logger);
|
|
2617
|
-
process.exit(refused || status === 'error' ? ExitCode.FINDINGS : ExitCode.OK);
|
|
2618
2612
|
}
|
|
2619
2613
|
//# sourceMappingURL=audit.js.map
|