@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
|
@@ -11,69 +11,162 @@
|
|
|
11
11
|
* When present, copies the pre-built directory tree to ~/.claude/plugins/
|
|
12
12
|
* and updates Claude's plugin registry files. When absent, falls back to
|
|
13
13
|
* copying dist/skills/ to ~/.claude/skills/.
|
|
14
|
+
*
|
|
15
|
+
* Every lane resolves what it installs from (staging an archive under $TMPDIR first),
|
|
16
|
+
* then calls {@link planInstall} and {@link executeInstall}: ONE plan of tree changes —
|
|
17
|
+
* the marketplace copy, each plugin's cache, each skill, everything `vat.replaces`
|
|
18
|
+
* removes — and the registry edit that agrees with it, applied as one transaction.
|
|
14
19
|
*/
|
|
15
|
-
import {
|
|
16
|
-
import
|
|
20
|
+
import { readdirSync } from 'node:fs';
|
|
21
|
+
import fs from 'node:fs/promises';
|
|
17
22
|
import { basename } from 'node:path';
|
|
18
23
|
import { readDeclaredSkillName } from '@vibe-agent-toolkit/agent-skills';
|
|
19
|
-
import { getClaudeUserPaths,
|
|
20
|
-
import {
|
|
21
|
-
import { direntKindFollowingSync, isPathAbsentError, isSingleFsSegment,
|
|
24
|
+
import { getClaudeUserPaths, linkDevSkills, PLUGIN_KEY_INVALID_CODE, planPackageInstall, requirePluginInstallNames, } from '@vibe-agent-toolkit/claude-marketplace';
|
|
25
|
+
import { buildReport, createRegistryIssue, toFindings } from '@vibe-agent-toolkit/schema';
|
|
26
|
+
import { applyTreePlan, classifyFsFault, copyTree, direntKindFollowingSync, everywhere, forEachInOrder, fsBoundary, isPathAbsentError, isSingleFsSegment, isTreeChangeResidue, isVatError, pathPresent, planTreeChanges, proveTreeReadable, requireConfirmedAbsent, safePath, TREE_DEST_NOT_OWNED_CODE, withFsFault, withFsFaultSync, } from '@vibe-agent-toolkit/utils';
|
|
27
|
+
import { ARCHIVE_LIMITS, extractArchive } from '@vibe-agent-toolkit/utils/archive';
|
|
22
28
|
import { safeExecSync } from '@vibe-agent-toolkit/utils/process';
|
|
23
|
-
import AdmZip from 'adm-zip';
|
|
24
29
|
import { Command } from 'commander';
|
|
25
|
-
import
|
|
26
|
-
import {
|
|
30
|
+
import { CommandRefusalError, refusalCodeOf } from '../../../utils/command-refusal.js';
|
|
31
|
+
import { endWithRefusal, endWithReport, leftoverIssue, NOTHING_FINISHED } from '../../../utils/document-writer.js';
|
|
32
|
+
import { extractSkillZip, inStaging, installLinks, installUnit, occupiedRefusal, skillCopyChange } from '../../../utils/install-plan.js';
|
|
27
33
|
import { createLogger } from '../../../utils/logger.js';
|
|
28
|
-
import {
|
|
34
|
+
import { requireInputPath } from '../../../utils/project-root-policy.js';
|
|
35
|
+
import { detectSource, downloadNpmPackage, isGlobalNpmInstall, readPackageJson, readPackageJsonVatMetadata, } from './helpers.js';
|
|
36
|
+
import { keptForSiblingFindings } from './kept-findings.js';
|
|
29
37
|
/** Relative path within a VAT npm package to its pre-built plugin structure. */
|
|
30
38
|
const PLUGIN_MARKETPLACES_SUBPATH = safePath.join('dist', '.claude', 'plugins', 'marketplaces');
|
|
31
|
-
|
|
39
|
+
/** `vat claude plugin install` has no `--strict`: a warning never fails it. */
|
|
40
|
+
const GATE = { strict: false };
|
|
41
|
+
/** One install source resolved per run — the `--npm-postinstall` lane included. */
|
|
42
|
+
const INSTALL_SOURCES = 1;
|
|
32
43
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
44
|
+
* Where the child `vat build`'s streams go. Its stdout is sent straight to
|
|
45
|
+
* this process's stderr (fd 2): this verb's stdout carries only its own
|
|
46
|
+
* report, and a PIPE would buffer the build's document under spawnSync's
|
|
47
|
+
* 1 MiB `maxBuffer` — a larger one kills the child with ENOBUFS.
|
|
48
|
+
*/
|
|
49
|
+
const BUILD_CHILD_STDIO = ['inherit', 2, 'inherit'];
|
|
50
|
+
/** A fresh run of `options`, nothing done yet. */
|
|
51
|
+
function newInstallRun(options, logger) {
|
|
52
|
+
return { options, logger, dryRun: options.dryRun === true, source: undefined, skills: [], issues: [], roots: { source: [], environment: [] } };
|
|
53
|
+
}
|
|
54
|
+
/** The classifier over the run's trees: a fault's side is decided by the path it names. */
|
|
55
|
+
function boundaryOf(run) {
|
|
56
|
+
return fsBoundary({ source: run.roots.source, environment: run.roots.environment }, { origin: 'content' });
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* One tree the run is about to copy ({@link installUnit}): a staged one as it is, one in the
|
|
60
|
+
* operator's own directory as its real path once no link in it leads outside it.
|
|
35
61
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
62
|
+
* @param dir - The tree: a skill, a marketplace or a plugin directory
|
|
63
|
+
* @param side - The side the lane resolved its package on
|
|
64
|
+
* @param what - What the tree is, for a refusal
|
|
39
65
|
*/
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
66
|
+
function unitOf(run, dir, side, what) {
|
|
67
|
+
// A lane that installs from the operator's directory names it before it plans anything.
|
|
68
|
+
const [root] = run.roots.source;
|
|
69
|
+
if (side !== 'environment' && root === undefined)
|
|
70
|
+
throw new Error('install lane planned a copy before naming its source directory');
|
|
71
|
+
return installUnit({ root: root ?? dir, side }, dir, what);
|
|
72
|
+
}
|
|
73
|
+
/** Name the source the run installs from. */
|
|
74
|
+
function setSource(run, label, type, symlink = false) {
|
|
75
|
+
run.source = { label, type, symlink };
|
|
76
|
+
}
|
|
77
|
+
/** The run as an outcome, or `undefined` before any lane named its source. */
|
|
78
|
+
function outcomeOf(run) {
|
|
79
|
+
if (run.source === undefined)
|
|
80
|
+
return undefined;
|
|
81
|
+
return { source: run.source.label, sourceType: run.source.type, symlink: run.source.symlink, skills: run.skills, issues: run.issues };
|
|
82
|
+
}
|
|
83
|
+
/** The report's `data` for an outcome. */
|
|
84
|
+
function installData(outcome, dryRun) {
|
|
85
|
+
return { source: outcome.source, sourceType: outcome.sourceType, dryRun, symlink: outcome.symlink, skills: outcome.skills };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* What finished before a refusal: every skill already installed, and every
|
|
89
|
+
* finding already made — or {@link NOTHING_FINISHED} when there is none.
|
|
90
|
+
*/
|
|
91
|
+
export function installFinished(outcome, dryRun) {
|
|
92
|
+
if (outcome === undefined || (outcome.skills.length === 0 && outcome.issues.length === 0))
|
|
93
|
+
return NOTHING_FINISHED;
|
|
94
|
+
return { examined: INSTALL_SOURCES, findings: toFindings(outcome.issues), data: installData(outcome, dryRun) };
|
|
95
|
+
}
|
|
96
|
+
/** A source FILE argument (a .zip, a .tgz): absent is the invocation's mistake, refused the input's. */
|
|
97
|
+
function assertSourceFile(path) {
|
|
98
|
+
requireInputPath(path, path, { origin: 'argument', message: `Path does not exist: ${path}` }, everywhere('source'));
|
|
99
|
+
}
|
|
100
|
+
/** The skills `--name` selects from a package's declared list; naming one it lacks is the invocation's mistake. */
|
|
101
|
+
function selectSkills(skills, name, packageName) {
|
|
102
|
+
if (name === undefined)
|
|
103
|
+
return [...skills];
|
|
104
|
+
const selected = skills.filter((skill) => skill === name);
|
|
105
|
+
if (selected.length === 0) {
|
|
106
|
+
throw new CommandRefusalError('USAGE_INVALID', `Skill "${name}" not found in package ${packageName}. Available: ${skills.join(', ')}`);
|
|
107
|
+
}
|
|
108
|
+
return selected;
|
|
46
109
|
}
|
|
47
110
|
/**
|
|
48
|
-
*
|
|
111
|
+
* List immediate subdirectory names inside a directory of the PACKAGE being
|
|
112
|
+
* installed, on `side` (the operator's tree, or VAT's staging when it was extracted
|
|
113
|
+
* there), following links. An empty array when the directory is absent — believed
|
|
114
|
+
* only when its parent's listing agrees; a directory the OS will not list (or an
|
|
115
|
+
* entry it will not stat) is a fault on `side`, naming it.
|
|
116
|
+
*
|
|
117
|
+
* Followed on purpose: a built plugin tree may hold a plugin or a skill AS a
|
|
118
|
+
* symlink, and `Dirent.isDirectory()` is false for a link.
|
|
119
|
+
*
|
|
120
|
+
* A tree-change leftover (`.<name>.vat-staged-*`, what a killed build leaves beside
|
|
121
|
+
* what it was replacing) is never one of them: it is not a marketplace, a plugin or a skill.
|
|
49
122
|
*/
|
|
50
|
-
|
|
123
|
+
function listSubdirectories(dir, side, within) {
|
|
124
|
+
const ctx = { side, action: 'list the package directory', path: dir };
|
|
125
|
+
let entries;
|
|
51
126
|
try {
|
|
52
|
-
|
|
53
|
-
marketplaceName: mpName,
|
|
54
|
-
pluginName,
|
|
55
|
-
pluginDir,
|
|
56
|
-
version,
|
|
57
|
-
source: { source: 'npm', package: packageName, version },
|
|
58
|
-
paths,
|
|
59
|
-
});
|
|
60
|
-
logger.info(` Registered plugin ${pluginName}@${mpName} in Claude plugin registry`);
|
|
127
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
61
128
|
}
|
|
62
129
|
catch (error) {
|
|
63
|
-
|
|
130
|
+
if (!isPathAbsentError(error))
|
|
131
|
+
throw classifyFsFault(error, ctx);
|
|
132
|
+
requireConfirmedAbsent(dir, error, { action: ctx.action, path: dir }, { follows: true, sideOf: everywhere(side) });
|
|
133
|
+
return [];
|
|
64
134
|
}
|
|
135
|
+
return withFsFaultSync(ctx, () => entries.filter((d) => !isTreeChangeResidue(d.name) && direntKindFollowingSync(dir, d, within) === 'directory').map((d) => d.name));
|
|
65
136
|
}
|
|
66
137
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
138
|
+
* Refuse, before anything under ~/.claude changes, a package whose plugin tree
|
|
139
|
+
* or `vat.replaces` names something that cannot be installed or removed: a
|
|
140
|
+
* plugin or marketplace directory, the package version, a replaced plugin, or a
|
|
141
|
+
* replaced flat skill that is not one path segment (or a dot-led version). Each
|
|
142
|
+
* came from the PACKAGE, so the refusal is the input's (`INPUT_UNREADABLE`), not
|
|
143
|
+
* the invocation's. (`vat.replaces`' SHAPE was already refused by `readPackageJson`.)
|
|
69
144
|
*/
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
145
|
+
function assertPackagePluginNames(marketplacesDir, marketplaceNames, packageJson, version, side, within) {
|
|
146
|
+
const check = (names, origin) => {
|
|
147
|
+
try {
|
|
148
|
+
requirePluginInstallNames({ ...names, version });
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (!isVatError(error, PLUGIN_KEY_INVALID_CODE))
|
|
152
|
+
throw error;
|
|
153
|
+
throw new CommandRefusalError('INPUT_UNREADABLE', `Package ${packageJson.name} cannot be installed, nothing was changed: ${error.message} (${origin}).`, { cause: error });
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
for (const skillName of packageJson.vat?.replaces?.flatSkills ?? []) {
|
|
157
|
+
if (!isSingleFsSegment(skillName)) {
|
|
158
|
+
throw new CommandRefusalError('INPUT_UNREADABLE', `Package ${packageJson.name} cannot be installed, nothing was changed: the legacy flat skill "${skillName}" it ` +
|
|
159
|
+
'replaces (package.json vat.replaces.flatSkills) must be a single path segment (no separators, not "." or "..").');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
for (const marketplaceName of marketplaceNames) {
|
|
163
|
+
for (const pluginName of listSubdirectories(safePath.join(marketplacesDir, marketplaceName, 'plugins'), side, within)) {
|
|
164
|
+
check({ marketplaceName, pluginName }, 'its built plugin tree and package.json version');
|
|
165
|
+
}
|
|
166
|
+
for (const pluginName of packageJson.vat?.replaces?.plugins ?? []) {
|
|
167
|
+
check({ marketplaceName, pluginName }, 'package.json vat.replaces.plugins');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
77
170
|
}
|
|
78
171
|
/**
|
|
79
172
|
* Convert a skill name to a filesystem-safe path segment.
|
|
@@ -95,7 +188,7 @@ function skillNameToFsPath(name) {
|
|
|
95
188
|
*/
|
|
96
189
|
export function assertSkillEntryName(name, origin) {
|
|
97
190
|
if (!isSingleFsSegment(name)) {
|
|
98
|
-
throw new
|
|
191
|
+
throw new CommandRefusalError('INPUT_UNREADABLE', `Refusing to install "${name}" (${origin}): a skill name must be a single path segment ` +
|
|
99
192
|
`(no separators, not "." or "..").`);
|
|
100
193
|
}
|
|
101
194
|
return name;
|
|
@@ -107,7 +200,7 @@ export function createPluginInstallCommand() {
|
|
|
107
200
|
.argument('[source]', 'Source to install from (npm:package, ZIP file, or directory path)')
|
|
108
201
|
.option('-s, --skills-dir <path>', 'Claude skills directory', getClaudeUserPaths().skillsDir)
|
|
109
202
|
.option('-n, --name <name>', 'Custom name for installed skill (default: auto-detect from source)')
|
|
110
|
-
.option('-f, --force', 'Overwrite existing skill
|
|
203
|
+
.option('-f, --force', 'Overwrite an existing skill, or a marketplace directory VAT did not install from this package', false)
|
|
111
204
|
.option('--dry-run', 'Preview installation without creating files', false)
|
|
112
205
|
.option('--npm-postinstall', 'Run as npm postinstall hook (internal use)', false)
|
|
113
206
|
.option('-d, --dev', 'Development mode: symlink skills from dist/skills/ (rebuilds reflected immediately)')
|
|
@@ -125,6 +218,29 @@ Description:
|
|
|
125
218
|
the pre-built directory tree is copied to ~/.claude/plugins/ (dumb copy).
|
|
126
219
|
Otherwise, falls back to copying dist/skills/ to ~/.claude/skills/.
|
|
127
220
|
|
|
221
|
+
A marketplace directory already at ~/.claude/plugins/marketplaces/<name> is
|
|
222
|
+
replaced only when VAT installed it from this same package (its .vat-marketplace
|
|
223
|
+
marker says so; for an install made by a VAT older than the marker, the
|
|
224
|
+
known_marketplaces.json entry naming this package does). Anything else there — a
|
|
225
|
+
marketplace Claude Code added, or one another package installed — is refused
|
|
226
|
+
with nothing changed; --force replaces it. So is a marketplace name whose
|
|
227
|
+
known_marketplaces.json entry another source registered, with no directory
|
|
228
|
+
(or an empty one) there.
|
|
229
|
+
|
|
230
|
+
Archives (.zip, .tgz, an npm tarball) are judged whole before anything is
|
|
231
|
+
written: one holding a symbolic or hard link, a device, a name that leaves the
|
|
232
|
+
archive (absolute, ".."), one name twice (or twice once letter case is
|
|
233
|
+
folded), or more than 50,000 entries / 256 MiB expanded is refused. A skill
|
|
234
|
+
ZIP holds SKILL.md at its top level, or exactly one top-level folder with
|
|
235
|
+
SKILL.md directly inside. A local directory may hold links, but only
|
|
236
|
+
relative ones to something that exists inside the plugin or skill being
|
|
237
|
+
installed, reached through no other link.
|
|
238
|
+
|
|
239
|
+
One transaction: the marketplace copy, each plugin's cache, each skill, the
|
|
240
|
+
registry files and everything vat.replaces removes change together, or not at
|
|
241
|
+
all. --dry-run prints the plan, one line per change ([dry-run] create|replace|
|
|
242
|
+
remove|keep|subsumed <what> <path>), and changes nothing.
|
|
243
|
+
|
|
128
244
|
Supported sources:
|
|
129
245
|
- npm package: npm:@scope/package-name
|
|
130
246
|
- Local ZIP file: ./path/to/skill.zip
|
|
@@ -132,15 +248,44 @@ Description:
|
|
|
132
248
|
- npm postinstall: --npm-postinstall (automatic during global install)
|
|
133
249
|
- Dev mode: --dev (symlinks from dist/skills/)
|
|
134
250
|
|
|
135
|
-
Output:
|
|
136
|
-
- status:
|
|
137
|
-
-
|
|
138
|
-
- sourceType: npm/local/zip/npm-postinstall
|
|
251
|
+
Output (YAML report on stdout):
|
|
252
|
+
- status: ok, findings (a warning below), or error when the run could not install
|
|
253
|
+
- examined: install sources resolved (1; a --npm-postinstall that skips is ok, skills: [])
|
|
254
|
+
- data.source / data.sourceType: what was installed from (npm/local/zip/tgz/dev/npm-postinstall)
|
|
255
|
+
- data.dryRun, data.symlink (true for --dev)
|
|
256
|
+
- data.skills[]: { name, installPath, sourcePath } — sourcePath is the --dev link target, else null
|
|
257
|
+
- findings: COMPONENT_DECLARED_BUT_MISSING (warning) for a --dev plugin skill whose build is missing;
|
|
258
|
+
TREE_CLEANUP_INCOMPLETE (warning), its link the path, when the install is complete but a
|
|
259
|
+
previous tree it replaced (left as .<name>.vat-staged-*.previous beside it) or its
|
|
260
|
+
$TMPDIR staging directory could not be removed;
|
|
261
|
+
PLUGIN_KEPT_SIBLING_UNEXAMINED (warning), its link the directory, for a plugin
|
|
262
|
+
vat.replaces kept because a directory it may be could not be examined
|
|
139
263
|
|
|
140
264
|
Exit Codes:
|
|
141
|
-
0 -
|
|
142
|
-
|
|
143
|
-
|
|
265
|
+
0 - Installed (a warning does not fail the run)
|
|
266
|
+
2 - The run could not install: a missing or unknown source, a skill that exists
|
|
267
|
+
without --force (an EMPTY directory there is replaced without it), a marketplace
|
|
268
|
+
directory VAT did not install from this package (without --force), an unknown
|
|
269
|
+
--target, a plain directory with no SKILL.md (USAGE_INVALID); --target claude.ai (NOT_IMPLEMENTED); an unreadable
|
|
270
|
+
source (a package directory it cannot list, or a named pipe, socket or
|
|
271
|
+
device in the package, refused unopened, included), a link in a local
|
|
272
|
+
directory that leads outside what is being installed, a .zip, .tgz or
|
|
273
|
+
npm tarball VAT does not accept (see Archives above; not an archive,
|
|
274
|
+
or an entry that does not inflate, included), a ZIP not laid out
|
|
275
|
+
as a skill ZIP, a registry file that is not JSON, a
|
|
276
|
+
package whose vat.replaces is not { plugins?: string[], flatSkills?: string[] },
|
|
277
|
+
whose plugin or marketplace directory, version, vat.replaces.plugins or
|
|
278
|
+
vat.replaces.flatSkills entry is not one path segment (or whose version
|
|
279
|
+
begins with ".") (INPUT_UNREADABLE); npm pack failing, a full $TMPDIR during
|
|
280
|
+
its download included (EXTERNAL_API_FAILED); --build whose vat build failed,
|
|
281
|
+
a staging copy under $TMPDIR it could not create or extract into (full,
|
|
282
|
+
read-only, out of descriptors), a destination under ~/.claude (or -s) it
|
|
283
|
+
cannot examine or write (RUN_INCOMPLETE). Every such refusal changes
|
|
284
|
+
nothing under ~/.claude. Only a tree vat.replaces removes that the OS will
|
|
285
|
+
not delete once the registry is written refuses after the install
|
|
286
|
+
(RUN_INCOMPLETE naming it), and then lists the installed skills. A plugin
|
|
287
|
+
vat.replaces names that is the just-installed plugin on disk (Old -> old on a
|
|
288
|
+
case-insensitive filesystem) loses only its registry entry.
|
|
144
289
|
|
|
145
290
|
Example:
|
|
146
291
|
$ vat claude plugin install --dev # Symlink all skills from cwd
|
|
@@ -150,370 +295,464 @@ Example:
|
|
|
150
295
|
`);
|
|
151
296
|
return command;
|
|
152
297
|
}
|
|
298
|
+
/**
|
|
299
|
+
* Build the report. Pure: no file system, no `process.exit`.
|
|
300
|
+
*
|
|
301
|
+
* @param outcome - What the install run did
|
|
302
|
+
* @param dryRun - Whether anything was actually written
|
|
303
|
+
* @param durationMs - How long the run took
|
|
304
|
+
*/
|
|
305
|
+
export function buildPluginInstallReport(outcome, dryRun, durationMs) {
|
|
306
|
+
return buildReport({
|
|
307
|
+
examined: INSTALL_SOURCES,
|
|
308
|
+
findings: toFindings(outcome.issues),
|
|
309
|
+
data: installData(outcome, dryRun),
|
|
310
|
+
gate: GATE,
|
|
311
|
+
durationMs,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
/** Refuse a `--target` this verb cannot install to. */
|
|
315
|
+
function assertInstallTarget(target) {
|
|
316
|
+
if (target === 'code')
|
|
317
|
+
return;
|
|
318
|
+
if (target === 'claude.ai') {
|
|
319
|
+
throw new CommandRefusalError('NOT_IMPLEMENTED', 'claude.ai org provisioning API not yet confirmed as public. Use the claude.ai admin console to upload a .zip manually, '
|
|
320
|
+
+ 'or vat claude org skills install for workspace-scoped skill management.');
|
|
321
|
+
}
|
|
322
|
+
throw new CommandRefusalError('USAGE_INVALID', `Unsupported --target "${target}": use code (default) or claude.ai.`);
|
|
323
|
+
}
|
|
324
|
+
/** Route the invocation to the lane that installs it. */
|
|
325
|
+
async function runInstall(source, run) {
|
|
326
|
+
const { options, logger } = run;
|
|
327
|
+
assertInstallTarget(options.target ?? 'code');
|
|
328
|
+
// --build implies --dev
|
|
329
|
+
if (options.build || options.dev) {
|
|
330
|
+
await handleDevInstall(run);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (options.npmPostinstall) {
|
|
334
|
+
await handleNpmPostinstall(run);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
// Regular install - source is required
|
|
338
|
+
if (!source) {
|
|
339
|
+
throw new CommandRefusalError('USAGE_INVALID', 'Source argument required. Use npm:package, ./dir, ./file.zip or ./file.tgz');
|
|
340
|
+
}
|
|
341
|
+
const sourceType = detectSource(source);
|
|
342
|
+
logger.debug(`Detected source type: ${sourceType}`);
|
|
343
|
+
switch (sourceType) {
|
|
344
|
+
case 'npm':
|
|
345
|
+
return handleNpmInstall(source, run);
|
|
346
|
+
case 'local':
|
|
347
|
+
return handleLocalInstall(source, run);
|
|
348
|
+
case 'zip':
|
|
349
|
+
return handleZipInstall(source, run);
|
|
350
|
+
case 'tgz':
|
|
351
|
+
return handleTgzInstall(source, run);
|
|
352
|
+
case 'npm-postinstall':
|
|
353
|
+
case 'dev':
|
|
354
|
+
// detectSource never returns these for a positional source: each is a flag.
|
|
355
|
+
throw new Error(`${sourceType} source type is handled by its own flag`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
/** The human half, on stderr; a run that placed no skill gets no check mark. */
|
|
359
|
+
function logInstallOutcome(outcome, dryRun, logger) {
|
|
360
|
+
const count = outcome.skills.length;
|
|
361
|
+
if (count === 0) {
|
|
362
|
+
logger.info(dryRun ? '\n⚠️ Dry-run: the source holds no skill to install' : '\n⚠️ Nothing installed: the source holds no skill');
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (outcome.symlink) {
|
|
366
|
+
logger.info(dryRun ? `\n✅ Dry-run complete: ${count} skill(s) would be symlinked` : `\n✅ Dev-installed ${count} skill(s) via symlink`);
|
|
367
|
+
if (!dryRun)
|
|
368
|
+
logger.info(` After rebuilding, run /reload-plugins in Claude Code`);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
if (dryRun) {
|
|
372
|
+
logger.info(`\n✅ Dry-run complete: ${count} skill(s) would be installed`);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
logger.info(`\n✅ Installed ${count} skill(s)`);
|
|
376
|
+
logger.info(`\n💡 Run 'vat claude plugin list' to verify installation`);
|
|
377
|
+
logger.info(` Restart Claude Code or run /reload-plugins to use the new skill`);
|
|
378
|
+
}
|
|
153
379
|
async function installCommand(source, options) {
|
|
154
380
|
const logger = createLogger(options.debug ? { debug: true } : {});
|
|
155
381
|
const startTime = Date.now();
|
|
382
|
+
const run = newInstallRun(options, logger);
|
|
383
|
+
const { dryRun } = run;
|
|
384
|
+
let outcome;
|
|
156
385
|
try {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
process.stdout.write(`status: not-available\n`);
|
|
163
|
-
process.stdout.write(`reason: "claude.ai org provisioning API not yet confirmed as public"\n`);
|
|
164
|
-
process.stdout.write(`requestedTarget: claude.ai\n`);
|
|
165
|
-
process.stdout.write(`guidance: "Use claude.ai admin console to upload a .zip manually, or use --target api.anthropic.com for workspace-scoped skill management"\n`);
|
|
166
|
-
process.exit(ExitCode.ERROR);
|
|
167
|
-
}
|
|
168
|
-
// Handle --build (implies --dev)
|
|
169
|
-
if (options.build) {
|
|
170
|
-
options.dev = true;
|
|
171
|
-
}
|
|
172
|
-
// Handle --dev flag
|
|
173
|
-
if (options.dev) {
|
|
174
|
-
await handleDevInstall(options, logger, startTime);
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
// Handle --npm-postinstall flag
|
|
178
|
-
if (options.npmPostinstall) {
|
|
179
|
-
await handleNpmPostinstall(options, logger, startTime);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
// Regular install - source is required
|
|
183
|
-
if (!source) {
|
|
184
|
-
throw new Error('Source argument required. Use npm:package, ./dir, or ./file.zip');
|
|
185
|
-
}
|
|
186
|
-
// Detect source type
|
|
187
|
-
const sourceType = detectSource(source);
|
|
188
|
-
logger.debug(`Detected source type: ${sourceType}`);
|
|
189
|
-
// Route to appropriate handler
|
|
190
|
-
switch (sourceType) {
|
|
191
|
-
case 'npm': {
|
|
192
|
-
await handleNpmInstall(source, options, logger, startTime);
|
|
193
|
-
break;
|
|
194
|
-
}
|
|
195
|
-
case 'local': {
|
|
196
|
-
await handleLocalInstall(source, options, logger, startTime);
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
case 'zip': {
|
|
200
|
-
await handleZipInstall(source, options, logger, startTime);
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
case 'tgz': {
|
|
204
|
-
await handleTgzInstall(source, options, logger, startTime);
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
case 'npm-postinstall': {
|
|
208
|
-
throw new Error('npm-postinstall source type should be handled by --npm-postinstall flag');
|
|
209
|
-
}
|
|
210
|
-
case 'dev': {
|
|
211
|
-
throw new Error('dev source type should be handled by --dev flag');
|
|
212
|
-
}
|
|
213
|
-
}
|
|
386
|
+
await runInstall(source, run);
|
|
387
|
+
outcome = outcomeOf(run);
|
|
388
|
+
// Every lane names its source before it can return; reaching here without one is a defect.
|
|
389
|
+
if (outcome === undefined)
|
|
390
|
+
throw new Error('install lane returned without naming its source');
|
|
214
391
|
}
|
|
215
392
|
catch (error) {
|
|
216
|
-
|
|
217
|
-
|
|
393
|
+
// A raw filesystem fault is classified by the path it names against the run's trees;
|
|
394
|
+
// anything already coded or classified passes through as it is.
|
|
395
|
+
const refusal = boundaryOf(run).classify(error, 'install the plugin', 'destination');
|
|
396
|
+
// Whatever installed before the refusal is still reported.
|
|
397
|
+
endWithRefusal('claude plugin install', refusalCodeOf(refusal), refusal, 'yaml', GATE, installFinished(outcomeOf(run), dryRun));
|
|
398
|
+
}
|
|
399
|
+
logInstallOutcome(outcome, dryRun, logger);
|
|
400
|
+
endWithReport('claude plugin install', buildPluginInstallReport(outcome, dryRun, Date.now() - startTime), 'yaml');
|
|
218
401
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
402
|
+
// --- the one plan -----------------------------------------------------------------------------
|
|
403
|
+
/** The input kind of a package's built plugin tree. */
|
|
404
|
+
const PLUGIN_TREE = 'plugin-tree';
|
|
405
|
+
/** One skill copied into the skills directory: absent build is the invocation's mistake. */
|
|
406
|
+
function skillCopy(run, side, skill) {
|
|
407
|
+
const { path: skillPath, name: skillName, within } = skill;
|
|
408
|
+
// The source declares a skill whose build is absent or unreadable: absent is the
|
|
409
|
+
// invocation's mistake, as for every path argument; unreadable is classified on its side —
|
|
410
|
+
// the operator's tree, or VAT's own staging an archive was extracted into.
|
|
411
|
+
if (!pathPresent(skillPath, { follow: within }, everywhere(side), 'confirmed')) {
|
|
412
|
+
throw new CommandRefusalError('USAGE_INVALID', `Skill "${skillName}" has no build to install. Path does not exist: ${skillPath}`);
|
|
413
|
+
}
|
|
414
|
+
const skillsDir = run.options.skillsDir ?? getClaudeUserPaths().skillsDir;
|
|
415
|
+
// The declared name is author-controlled (SKILL.md `name:`, package.json `vat.skills[]`) and
|
|
416
|
+
// `--force` replaces whatever is at this path.
|
|
417
|
+
const installPath = safePath.join(skillsDir, assertSkillEntryName(skillName, 'skill name'));
|
|
418
|
+
return {
|
|
419
|
+
change: skillCopyChange({ name: skillName, source: unitOf(run, skillPath, side, 'the skill directory'), dest: installPath }, side, run.options.force === true),
|
|
420
|
+
skill: { name: skillName, installPath, sourcePath: null },
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
function planSkills(run, side, skills) {
|
|
424
|
+
const copies = skills.map((skill) => skillCopy(run, side, skill));
|
|
425
|
+
return { changes: copies.map((copy) => copy.change), registry: null, replaced: [], skills: copies.map((copy) => copy.skill), issues: [] };
|
|
426
|
+
}
|
|
427
|
+
/** Entries of a plugin other than its skills: what `--dev` copies (it links each skill instead). */
|
|
428
|
+
const notSkills = (relative) => relative !== 'skills';
|
|
429
|
+
/** Entries of a marketplace other than its plugins: what `--dev` copies before building each plugin. */
|
|
430
|
+
const notPlugins = (relative) => relative !== 'plugins';
|
|
431
|
+
/** Entries of a marketplace other than a plugin's skills: what a `--dev` install reads of it. */
|
|
432
|
+
const notPluginSkills = (relative) => !/^plugins\/[^/]+\/skills$/.test(relative);
|
|
433
|
+
/** The `--dev` links of one plugin: each skill its tree declares and `dist/skills/` holds; each one it does not, a finding. */
|
|
434
|
+
function devPlugin(plugin, rootDir) {
|
|
435
|
+
const skillsDir = safePath.join(plugin.srcPluginDir, 'skills');
|
|
436
|
+
const result = { plugin, hasSkills: pathPresent(skillsDir, { follow: rootDir }, everywhere(plugin.side), 'confirmed'), links: [], skills: [], issues: [] };
|
|
437
|
+
for (const name of listSubdirectories(skillsDir, plugin.side, rootDir)) {
|
|
438
|
+
const target = safePath.resolve(rootDir, 'dist', 'skills', name);
|
|
439
|
+
if (!pathPresent(target, { follow: rootDir }, everywhere(plugin.side), 'confirmed')) {
|
|
440
|
+
result.issues.push(createRegistryIssue('COMPONENT_DECLARED_BUT_MISSING', `Plugin "${plugin.pluginName}" declares skill "${name}", but it is not built — it was not linked. Run vat build, then re-install.`, { location: safePath.relative(rootDir, target) }));
|
|
441
|
+
continue;
|
|
255
442
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
name,
|
|
259
|
-
installPath: safePath.join(skillsDir, name),
|
|
260
|
-
})), `npm:${packageName}`, 'npm', duration, logger, options.dryRun);
|
|
261
|
-
process.exit(ExitCode.OK);
|
|
262
|
-
}
|
|
263
|
-
finally {
|
|
264
|
-
await rm(tempDir, { recursive: true, force: true });
|
|
443
|
+
result.links.push({ name, target });
|
|
444
|
+
result.skills.push({ name: `${plugin.pluginName}:${name}`, installPath: safePath.join(plugin.destPluginDir, 'skills', name), sourcePath: target });
|
|
265
445
|
}
|
|
446
|
+
return result;
|
|
266
447
|
}
|
|
267
448
|
/**
|
|
268
|
-
*
|
|
449
|
+
* Fill `relative` under the staged directory (`''`: the directory itself) with one `--dev` plugin: its non-skill content copied, and a link per built
|
|
450
|
+
* skill to `dist/skills/<name>`, so a rebuild is picked up live.
|
|
269
451
|
*/
|
|
270
|
-
async function
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
452
|
+
async function writeDevPlugin(dev, staged, relative) {
|
|
453
|
+
await copyTree(dev.plugin.srcPluginDir, staged, relative, { links: installLinks(dev.plugin.side), side: dev.plugin.side, onto: 'fresh', filter: notSkills });
|
|
454
|
+
if (dev.hasSkills)
|
|
455
|
+
await linkDevSkills(relative === '' ? staged : safePath.join(staged, relative), dev.links);
|
|
456
|
+
}
|
|
457
|
+
/** The plugins one marketplace of the package ships, each as the tree its cache is copied from, with where it goes under `paths`. */
|
|
458
|
+
function pluginsOf(run, side, srcMpDir, marketplaceName, destMpDir, rootDir) {
|
|
459
|
+
return listSubdirectories(safePath.join(srcMpDir, 'plugins'), side, rootDir).map((pluginName) => ({
|
|
460
|
+
side,
|
|
461
|
+
marketplaceName,
|
|
462
|
+
pluginName,
|
|
463
|
+
// Its own unit: the cache holds this plugin alone, so a link from it into a sibling plugin would leave the copy.
|
|
464
|
+
srcPluginDir: unitOf(run, safePath.join(srcMpDir, 'plugins', pluginName), side, 'the plugin directory'),
|
|
465
|
+
destPluginDir: safePath.join(destMpDir, 'plugins', pluginName),
|
|
466
|
+
}));
|
|
467
|
+
}
|
|
468
|
+
/** One marketplace of a copy install: the package's tree copied whole, and each plugin's cache copied from it. */
|
|
469
|
+
function copiedMarketplace(marketplaceName, srcMpDir, plugins, side, rootDir) {
|
|
470
|
+
const skills = plugins.flatMap((plugin) => listSubdirectories(safePath.join(plugin.srcPluginDir, 'skills'), side, rootDir).map((name) => ({ name, installPath: safePath.join(plugin.destPluginDir, 'skills', name), sourcePath: null })));
|
|
471
|
+
return {
|
|
472
|
+
install: {
|
|
473
|
+
marketplaceName,
|
|
474
|
+
write: (staged) => copyTree(srcMpDir, staged, '', { links: installLinks(side), side, onto: 'fresh' }),
|
|
475
|
+
reads: [srcMpDir],
|
|
476
|
+
// A `write` fill, not a `copy`: the planner proves every `copy` source again, and the whole package was
|
|
477
|
+
// proven readable once already ({@link planPluginTree}). The holding check still sees it (`reads`).
|
|
478
|
+
plugins: plugins.map(({ pluginName, srcPluginDir }) => ({
|
|
479
|
+
pluginName,
|
|
480
|
+
cacheFill: { from: 'write', write: (staged) => copyTree(srcPluginDir, staged, '', { links: installLinks(side), side, onto: 'fresh' }), reads: [srcPluginDir] },
|
|
481
|
+
})),
|
|
482
|
+
},
|
|
483
|
+
skills,
|
|
484
|
+
issues: [],
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
/** One marketplace of a `--dev` install: its non-plugin content copied, each plugin built with links, the cache built the same way. */
|
|
488
|
+
function devMarketplace(marketplaceName, srcMpDir, plugins, rootDir, side) {
|
|
489
|
+
const linked = plugins.map((plugin) => devPlugin(plugin, rootDir));
|
|
490
|
+
return {
|
|
491
|
+
install: {
|
|
492
|
+
marketplaceName,
|
|
493
|
+
write: async (staged) => {
|
|
494
|
+
await copyTree(srcMpDir, staged, '', { links: installLinks(side), side, onto: 'fresh', filter: notPlugins });
|
|
495
|
+
// In order: each plugin is built into the one staged tree, and the first refusal stops the fill.
|
|
496
|
+
await forEachInOrder(linked, (dev) => writeDevPlugin(dev, staged, `plugins/${dev.plugin.pluginName}`));
|
|
497
|
+
},
|
|
498
|
+
reads: [srcMpDir],
|
|
499
|
+
plugins: linked.map((dev) => ({
|
|
500
|
+
pluginName: dev.plugin.pluginName,
|
|
501
|
+
cacheFill: { from: 'write', write: (staged) => writeDevPlugin(dev, staged, ''), reads: [dev.plugin.srcPluginDir] },
|
|
502
|
+
})),
|
|
503
|
+
},
|
|
504
|
+
skills: linked.flatMap((each) => each.skills),
|
|
505
|
+
issues: linked.flatMap((each) => each.issues),
|
|
506
|
+
};
|
|
309
507
|
}
|
|
310
508
|
/**
|
|
311
|
-
*
|
|
509
|
+
* Plan a plugin-tree install: every marketplace the package ships replaced whole (with
|
|
510
|
+
* VAT's marker), each plugin's cache, each `vat.replaces` plugin's cache and flat skill
|
|
511
|
+
* removed, and the registry edit — one plan. Every name is checked and the whole source
|
|
512
|
+
* proven readable before anything is decided. A marketplace directory already there is
|
|
513
|
+
* replaced only when VAT installed it from this very package, or under `force` (`--force`).
|
|
312
514
|
*/
|
|
313
|
-
async function
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
515
|
+
async function planPluginTree(run, input, mode) {
|
|
516
|
+
const { rootDir, packageJson, side } = input;
|
|
517
|
+
const force = run.options.force === true;
|
|
518
|
+
const marketplacesDir = safePath.join(rootDir, PLUGIN_MARKETPLACES_SUBPATH);
|
|
519
|
+
const paths = getClaudeUserPaths();
|
|
520
|
+
const version = packageJson.version ?? '0.0.0';
|
|
521
|
+
const marketplaceNames = listSubdirectories(marketplacesDir, side, rootDir);
|
|
522
|
+
assertPackagePluginNames(marketplacesDir, marketplaceNames, packageJson, version, side, rootDir);
|
|
523
|
+
// Each marketplace as the tree it is copied from, before anything reads it: one in the operator's
|
|
524
|
+
// own directory with a link leading out of it is the package's refusal (INPUT_UNREADABLE).
|
|
525
|
+
const marketplaces = marketplaceNames.map((mpName) => ({ mpName, srcMpDir: unitOf(run, safePath.join(marketplacesDir, mpName), side, 'the marketplace directory') }));
|
|
526
|
+
// Every file of the package, before anything changes — dry run or real: a file the
|
|
527
|
+
// install cannot read is the package's refusal (INPUT_UNREADABLE).
|
|
528
|
+
const proof = mode === 'dev' ? { links: installLinks(side), side, filter: notPluginSkills } : { links: installLinks(side), side };
|
|
529
|
+
// In order: the first unreadable entry named is the first marketplace's, deterministically.
|
|
530
|
+
await forEachInOrder(marketplaces, ({ srcMpDir }) => proveTreeReadable(srcMpDir, proof));
|
|
531
|
+
const built = marketplaces.map(({ mpName, srcMpDir }) => {
|
|
532
|
+
const plugins = pluginsOf(run, side, srcMpDir, mpName, safePath.join(paths.marketplacesDir, mpName), rootDir);
|
|
533
|
+
return mode === 'dev' ? devMarketplace(mpName, srcMpDir, plugins, rootDir, side) : copiedMarketplace(mpName, srcMpDir, plugins, side, rootDir);
|
|
534
|
+
});
|
|
535
|
+
const replaces = packageJson.vat?.replaces;
|
|
536
|
+
const shipped = new Set(built.flatMap(({ install }) => install.plugins.map(({ pluginName }) => `${pluginName}@${install.marketplaceName}`)));
|
|
537
|
+
const planned = planPackageInstall({
|
|
538
|
+
marketplaces: built.map((each) => each.install),
|
|
539
|
+
version,
|
|
540
|
+
source: { source: 'npm', package: packageJson.name, version },
|
|
541
|
+
replacedPluginKeys: marketplaceNames.flatMap((mp) => (replaces?.plugins ?? []).map((plugin) => `${plugin}@${mp}`)),
|
|
542
|
+
force,
|
|
543
|
+
paths,
|
|
544
|
+
});
|
|
545
|
+
const flatSkills = (replaces?.flatSkills ?? []).map((name) => ({
|
|
546
|
+
op: 'remove',
|
|
547
|
+
dest: safePath.join(paths.skillsDir, assertSkillEntryName(name, 'vat.replaces.flatSkills')),
|
|
548
|
+
// The package says it replaces this legacy install: whatever is there goes.
|
|
549
|
+
ownership: { kind: 'force' },
|
|
550
|
+
label: `legacy flat skill ${name}`,
|
|
551
|
+
}));
|
|
552
|
+
return {
|
|
553
|
+
changes: [...planned.changes, ...flatSkills],
|
|
554
|
+
registry: planned.registry,
|
|
555
|
+
replaced: planned.replaced.map((each) => ({ ...each, reinstalled: shipped.has(each.pluginKey) })),
|
|
556
|
+
skills: built.flatMap((each) => each.skills),
|
|
557
|
+
issues: built.flatMap((each) => each.issues),
|
|
558
|
+
};
|
|
329
559
|
}
|
|
330
560
|
/**
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
561
|
+
* Plan an install of `input`, with no side effect: the tree changes, the registry edit,
|
|
562
|
+
* and what the run reports once they are done. `mode` is `dev` only for a plugin tree
|
|
563
|
+
* whose skills are linked, not copied (`--dev`).
|
|
334
564
|
*/
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
const skillPath = safePath.join(extractedDir, 'dist', 'skills', skillNameToFsPath(skillName));
|
|
359
|
-
await installSkillFromPath(skillPath, skillName, options, logger);
|
|
565
|
+
function planInstall(run, input, mode) {
|
|
566
|
+
if (input.kind === PLUGIN_TREE)
|
|
567
|
+
return planPluginTree(run, input, mode);
|
|
568
|
+
// A skills lane plans synchronously; a refusal still rejects the returned promise.
|
|
569
|
+
return Promise.resolve().then(() => planSkills(run, input.side, input.kind === 'skills'
|
|
570
|
+
? input.skillNames.map((name) => ({ path: safePath.join(input.rootDir, 'dist', 'skills', skillNameToFsPath(name)), name, within: input.rootDir }))
|
|
571
|
+
// The skill directory IS the input (the operator's own, or VAT's staging of an archive): its own `within`.
|
|
572
|
+
: [{ path: input.skillPath, name: input.skillName, within: input.skillPath }]));
|
|
573
|
+
}
|
|
574
|
+
/** A package directory's plugin tree, as the input of {@link planInstall}. */
|
|
575
|
+
function pluginTree(side, rootDir, packageJson) {
|
|
576
|
+
return { kind: PLUGIN_TREE, side, rootDir, packageJson };
|
|
577
|
+
}
|
|
578
|
+
/** What the decided plan did with each replaced plugin: a warning per directory kept, and a finding per one kept for an unexaminable sibling. */
|
|
579
|
+
function replacedOutcome(run, planned, plan) {
|
|
580
|
+
const decided = planned.replaced.flatMap(({ pluginKey, index, reinstalled }) => {
|
|
581
|
+
const change = plan.changes[index];
|
|
582
|
+
return change === undefined ? [] : [{ pluginKey, change, reinstalled }];
|
|
583
|
+
});
|
|
584
|
+
for (const { pluginKey, change, reinstalled } of decided) {
|
|
585
|
+
// A key the package installs again stays registered: nothing to warn about.
|
|
586
|
+
if (change.action === 'keep' && change.existing !== 'absent' && !reinstalled) {
|
|
587
|
+
run.logger.warn(` Plugin "${pluginKey}" is removed from the registry, but ${change.change.dest} is kept (${change.reason ?? 'kept'})`);
|
|
360
588
|
}
|
|
361
|
-
const duration = Date.now() - startTime;
|
|
362
|
-
outputInstallSuccess(skillNames.map(name => ({ name, installPath: safePath.join(skillsDir, name) })), sourcePath, 'tgz', duration, logger, options.dryRun);
|
|
363
|
-
process.exit(ExitCode.OK);
|
|
364
|
-
}
|
|
365
|
-
finally {
|
|
366
|
-
await rm(tempDir, { recursive: true, force: true });
|
|
367
589
|
}
|
|
590
|
+
return keptForSiblingFindings(decided.flatMap(({ change }) => (change.action === 'keep' && change.unexaminedSibling !== undefined ? [{ path: change.change.dest, sibling: change.unexaminedSibling }] : [])));
|
|
591
|
+
}
|
|
592
|
+
/** Record what the run did: called once the transaction committed, or once a dry run is planned. */
|
|
593
|
+
function record(run, planned, findings) {
|
|
594
|
+
run.skills.push(...planned.skills);
|
|
595
|
+
run.issues.push(...planned.issues, ...findings);
|
|
368
596
|
}
|
|
369
597
|
/**
|
|
370
|
-
*
|
|
371
|
-
*
|
|
598
|
+
* Carry out a planned install as ONE transaction: every tree staged and swapped, then the
|
|
599
|
+
* registry written (`afterSwap`); a failure before the registry is written puts every tree
|
|
600
|
+
* and registry file back. Under `--dry-run` the plan's lines are printed and nothing changes.
|
|
601
|
+
* What the run installed is recorded the moment the registry is written, so a failure after
|
|
602
|
+
* that (a replaced tree the OS will not delete) reports it.
|
|
372
603
|
*/
|
|
373
|
-
async function
|
|
374
|
-
|
|
375
|
-
// refusal on the probe, or a failed removal, stays loud: this used to catch
|
|
376
|
-
// everything and recognise its own throw by the words in its message.
|
|
604
|
+
async function executeInstall(run, planned) {
|
|
605
|
+
let plan;
|
|
377
606
|
try {
|
|
378
|
-
|
|
607
|
+
plan = await planTreeChanges(planned.changes);
|
|
379
608
|
}
|
|
380
609
|
catch (error) {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
610
|
+
throw notOwnedRefusal(occupiedRefusal(error));
|
|
611
|
+
}
|
|
612
|
+
const findings = replacedOutcome(run, planned, plan);
|
|
613
|
+
const prefix = run.dryRun ? '[dry-run] ' : '';
|
|
614
|
+
for (const line of plan.describe())
|
|
615
|
+
run.logger.info(` ${prefix}${line}`);
|
|
616
|
+
if (run.dryRun) {
|
|
617
|
+
record(run, planned, findings);
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
const { warnings } = await applyTreePlan(plan, {
|
|
621
|
+
afterSwap: async () => {
|
|
622
|
+
await planned.registry?.apply();
|
|
623
|
+
record(run, planned, findings);
|
|
624
|
+
},
|
|
625
|
+
});
|
|
626
|
+
for (const { path, message } of warnings)
|
|
627
|
+
leftover(run, leftoverIssue(message, path));
|
|
628
|
+
}
|
|
629
|
+
/** A marketplace directory VAT cannot prove it installed from this package, as the invocation's refusal saying how to proceed; anything else as itself. */
|
|
630
|
+
function notOwnedRefusal(error) {
|
|
631
|
+
if (!isVatError(error, TREE_DEST_NOT_OWNED_CODE))
|
|
632
|
+
return error;
|
|
633
|
+
return new CommandRefusalError('USAGE_INVALID', `${error.message}. Nothing was changed. Uninstall what is there first — \`vat claude plugin uninstall <plugin>@<marketplace>\` when VAT installed it, Claude Code's /plugin when it did — or pass --force to replace it.`, { cause: error });
|
|
634
|
+
}
|
|
635
|
+
/** A leftover of a complete install, as a warning naming it. */
|
|
636
|
+
function leftover(run, issue) {
|
|
637
|
+
run.logger.warn(` ${issue.message}`);
|
|
638
|
+
run.issues.push(issue);
|
|
639
|
+
}
|
|
640
|
+
/** Plan and execute `input`: every lane's last step. */
|
|
641
|
+
async function install(run, input, mode) {
|
|
642
|
+
await executeInstall(run, await planInstall(run, input, mode));
|
|
643
|
+
}
|
|
644
|
+
/** Run `work` in a fresh `$TMPDIR` staging directory (VAT's own: `environment`), disposed of after: see {@link inStaging}. */
|
|
645
|
+
function stagedIn(run, prefix, work) {
|
|
646
|
+
return inStaging(prefix, async (dir) => {
|
|
647
|
+
run.roots.environment.push(dir);
|
|
648
|
+
await work(dir);
|
|
649
|
+
}, (issue) => leftover(run, issue));
|
|
392
650
|
}
|
|
651
|
+
// --- the lanes --------------------------------------------------------------------------------
|
|
393
652
|
/**
|
|
394
|
-
*
|
|
395
|
-
*
|
|
653
|
+
* The package at `rootDir`, as `readPackageJson` is told of it: its side, and what the user named —
|
|
654
|
+
* the directory itself, or, where `rootDir` is VAT's staging (`environment`: a staging directory
|
|
655
|
+
* under $TMPDIR names nothing they have), the archive or npm spec the run was given.
|
|
396
656
|
*/
|
|
397
|
-
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
catch (error) {
|
|
411
|
-
// ⚠️ POSIX-only in practice: `handleDevInstall` throws on win32 before
|
|
412
|
-
// this call chain begins, so Windows-specific handling here would be dead
|
|
413
|
-
// code — an earlier revision added exactly that. Making `--dev` work on
|
|
414
|
-
// Windows means changing that guard (a junction needs no elevation), not
|
|
415
|
-
// this catch. Not falling back to a copy either — dev mode exists so a
|
|
416
|
-
// rebuild is picked up live, and a copy would quietly stop that.
|
|
417
|
-
//
|
|
418
|
-
// ⚠️ This throws mid-loop, after `devInstallMarketplace` already removed
|
|
419
|
-
// the previous marketplace directory and `devInstallPlugin` copied the
|
|
420
|
-
// non-skill content. Earlier skills are linked, later ones are not, and
|
|
421
|
-
// `registerPlugin` never runs — so the tree is on disk but unregistered.
|
|
422
|
-
// Recoverable by re-running, which starts over.
|
|
423
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
424
|
-
throw new Error(`Could not symlink ${skillFsName} to ${destSkillPath}: ${detail}\n` +
|
|
425
|
-
'Check that the destination directory is writable. This install is now ' +
|
|
426
|
-
'incomplete — re-run the same command to start over.');
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
logger.info(` Symlinked: ${safePath.relative(cwd, destSkillPath)} → ${srcSkillPath}`);
|
|
430
|
-
return {
|
|
431
|
-
name: `${pluginName}:${skillFsName}`,
|
|
432
|
-
installPath: destSkillPath,
|
|
433
|
-
sourcePath: srcSkillPath,
|
|
434
|
-
};
|
|
657
|
+
function packageOf(run, rootDir, side) {
|
|
658
|
+
const named = side === 'environment' && run.source !== undefined ? `The package ${run.source.label}` : `The package directory ${rootDir}`;
|
|
659
|
+
return { side, label: named };
|
|
660
|
+
}
|
|
661
|
+
/** A package directory's install: its plugin tree, or (none, or `--user-install-without-plugin`) its declared skills. */
|
|
662
|
+
async function installPackageDir(run, rootDir, side) {
|
|
663
|
+
if (run.options.userInstallWithoutPlugin !== true && pathPresent(safePath.join(rootDir, PLUGIN_MARKETPLACES_SUBPATH), { follow: rootDir }, everywhere(side), 'confirmed')) {
|
|
664
|
+
run.logger.info(' Plugin detected — installing via Claude plugin system');
|
|
665
|
+
await install(run, pluginTree(side, rootDir, await readPackageJson(rootDir, packageOf(run, rootDir, side))), 'copy');
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
const { packageJson, skills } = await readPackageJsonVatMetadata(rootDir, packageOf(run, rootDir, side));
|
|
669
|
+
await install(run, { kind: 'skills', side, rootDir, skillNames: selectSkills(skills, run.options.name, packageJson.name) }, 'copy');
|
|
435
670
|
}
|
|
436
671
|
/**
|
|
437
|
-
*
|
|
672
|
+
* Handle npm package installation
|
|
438
673
|
*/
|
|
439
|
-
async function
|
|
440
|
-
const
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
await
|
|
448
|
-
}
|
|
449
|
-
// Followed: a skill directory that is itself a link is still a skill to link.
|
|
450
|
-
const skillEntries = readdirSync(srcSkillsDir, { withFileTypes: true })
|
|
451
|
-
.filter(d => direntKindFollowingSync(srcSkillsDir, d) === 'directory');
|
|
452
|
-
for (const skillEntry of skillEntries) {
|
|
453
|
-
const result = await symlinkDevSkill(skillEntry.name, destSkillsDir, cwd, pluginName, options, logger);
|
|
454
|
-
if (result) {
|
|
455
|
-
installed.push(result);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
return installed;
|
|
674
|
+
async function handleNpmInstall(source, run) {
|
|
675
|
+
const { logger } = run;
|
|
676
|
+
const packageName = source.startsWith('npm:') ? source.slice(4) : source;
|
|
677
|
+
setSource(run, `npm:${packageName}`, 'npm');
|
|
678
|
+
logger.info(`📥 Installing skill from npm: ${packageName}`);
|
|
679
|
+
await stagedIn(run, 'vat-install-npm-', async (tempDir) => {
|
|
680
|
+
logger.info(' Downloading package...');
|
|
681
|
+
const extractedPath = await downloadNpmPackage(packageName, tempDir);
|
|
682
|
+
await installPackageDir(run, extractedPath, 'environment');
|
|
683
|
+
});
|
|
459
684
|
}
|
|
460
685
|
/**
|
|
461
|
-
*
|
|
686
|
+
* Handle local directory installation
|
|
462
687
|
*/
|
|
463
|
-
async function
|
|
464
|
-
const {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
688
|
+
async function handleLocalInstall(source, run) {
|
|
689
|
+
const { options, logger } = run;
|
|
690
|
+
const sourcePath = safePath.resolve(source); // The operator's own argument: every probe beneath it passes it as `within`.
|
|
691
|
+
setSource(run, `local:${sourcePath}`, 'local');
|
|
692
|
+
run.roots.source.push(sourcePath);
|
|
693
|
+
logger.info(`📥 Installing skill from directory: ${sourcePath}`);
|
|
694
|
+
// A package: its pre-built plugin tree, or each skill its vat.skills declares.
|
|
695
|
+
const marketplacesDir = safePath.join(sourcePath, PLUGIN_MARKETPLACES_SUBPATH);
|
|
696
|
+
if ((!options.userInstallWithoutPlugin && pathPresent(marketplacesDir, { follow: sourcePath }, everywhere('source'), 'confirmed')) || pathPresent(safePath.join(sourcePath, 'package.json'), { follow: sourcePath }, everywhere('source'), 'confirmed')) {
|
|
697
|
+
await installPackageDir(run, sourcePath, 'source');
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
// Plain skill directory: it must hold a SKILL.md, or any directory would
|
|
701
|
+
// install as a skill. A source that names nothing keeps its own refusal below.
|
|
702
|
+
if (pathPresent(sourcePath, { follow: sourcePath }, everywhere('source'), 'confirmed') && !pathPresent(safePath.join(sourcePath, 'SKILL.md'), { follow: sourcePath }, everywhere('source'), 'confirmed')) {
|
|
703
|
+
throw new CommandRefusalError('USAGE_INVALID', `No SKILL.md found at the root of: ${sourcePath}`);
|
|
704
|
+
}
|
|
705
|
+
// The package.json branch above installs each skill under its declared name;
|
|
706
|
+
// do the same here rather than under whatever the source directory is called.
|
|
707
|
+
const skillName = options.name ??
|
|
708
|
+
readDeclaredSkillName(safePath.join(sourcePath, 'SKILL.md')) ??
|
|
709
|
+
basename(sourcePath);
|
|
710
|
+
await install(run, { kind: 'skill-dir', side: 'source', skillPath: sourcePath, skillName }, 'copy');
|
|
482
711
|
}
|
|
483
712
|
/**
|
|
484
|
-
*
|
|
713
|
+
* Handle ZIP file installation
|
|
485
714
|
*/
|
|
486
|
-
async function
|
|
487
|
-
const
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
//
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
715
|
+
async function handleZipInstall(source, run) {
|
|
716
|
+
const { options, logger } = run;
|
|
717
|
+
const sourcePath = safePath.resolve(source);
|
|
718
|
+
setSource(run, sourcePath, 'zip');
|
|
719
|
+
run.roots.source.push(sourcePath);
|
|
720
|
+
logger.info(`📥 Installing skill from ZIP: ${sourcePath}`);
|
|
721
|
+
assertSourceFile(sourcePath);
|
|
722
|
+
// Extracted to staging first, through the one archive primitive: an archive it refuses — an
|
|
723
|
+
// entry that does not inflate, a link, two entries one name — is refused with nothing under
|
|
724
|
+
// ~/.claude changed.
|
|
725
|
+
await stagedIn(run, 'vat-install-zip-', async (tempDir) => {
|
|
726
|
+
logger.info(' Extracting ZIP...');
|
|
727
|
+
const extracted = safePath.join(tempDir, 'skill');
|
|
728
|
+
await withFsFault({ side: 'environment', action: 'create the staging directory', path: extracted }, () => fs.mkdir(extracted));
|
|
729
|
+
// The one extraction of a skill ZIP, shared with `vat skills install` and the org upload: the
|
|
730
|
+
// skill is at the top level or in the single top-level folder, installed under the name its SKILL.md declares.
|
|
731
|
+
const skillPath = await extractSkillZip(sourcePath, extracted);
|
|
732
|
+
const skillName = options.name ?? readDeclaredSkillName(safePath.join(skillPath, 'SKILL.md')) ?? basename(sourcePath, '.zip');
|
|
733
|
+
await install(run, { kind: 'skill-dir', side: 'environment', skillPath, skillName }, 'copy');
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Handle npm tarball (.tgz / .tar.gz) installation.
|
|
738
|
+
* npm pack format: all package files are under a `package/` subdirectory in the tarball.
|
|
739
|
+
* Extracts to a temp directory then installs the plugin tree, or the declared skills.
|
|
740
|
+
*/
|
|
741
|
+
async function handleTgzInstall(source, run) {
|
|
742
|
+
const { logger } = run;
|
|
743
|
+
const sourcePath = safePath.resolve(source);
|
|
744
|
+
setSource(run, sourcePath, 'tgz');
|
|
745
|
+
run.roots.source.push(sourcePath);
|
|
746
|
+
logger.info(`📥 Installing skill from tarball: ${sourcePath}`);
|
|
747
|
+
assertSourceFile(sourcePath);
|
|
748
|
+
await stagedIn(run, 'vat-install-tgz-', async (tempDir) => {
|
|
749
|
+
logger.info(' Extracting tarball...');
|
|
750
|
+
// One entry at a time: when the extraction throws, nothing is still being written under the staging.
|
|
751
|
+
await extractArchive({ file: sourcePath, side: 'source' }, tempDir, { format: 'tar', limits: ARCHIVE_LIMITS });
|
|
752
|
+
// npm pack tarballs extract under package/ subdirectory
|
|
753
|
+
const packageDir = safePath.join(tempDir, 'package');
|
|
754
|
+
await installPackageDir(run, pathPresent(packageDir, { follow: tempDir }, everywhere('environment'), 'confirmed') ? packageDir : tempDir, 'environment');
|
|
755
|
+
});
|
|
517
756
|
}
|
|
518
757
|
/**
|
|
519
758
|
* Handle development mode installation via plugin tree (symlinks).
|
|
@@ -522,292 +761,113 @@ async function devInstallMarketplace(mpName, srcMpDir, packageInfo, cwd, options
|
|
|
522
761
|
* - Copies non-skill content (.claude-plugin/ dirs) to ~/.claude/plugins/
|
|
523
762
|
* - For each skill directory under plugins/{plugin}/skills/{name}/, creates a
|
|
524
763
|
* symlink to the corresponding dist/skills/{name}/ directory
|
|
525
|
-
* - Registers each plugin in the Claude plugin registry
|
|
764
|
+
* - Registers each plugin in the Claude plugin registry
|
|
526
765
|
*
|
|
527
|
-
*
|
|
766
|
+
* Each marketplace is ONE replace, built whole in staging and swapped in: the installed
|
|
767
|
+
* marketplace is never deleted first. Skills appear in Claude Code as {plugin}:{skill}.
|
|
528
768
|
*/
|
|
529
|
-
async function handleDevInstall(
|
|
769
|
+
async function handleDevInstall(run) {
|
|
770
|
+
const { options, logger } = run;
|
|
530
771
|
if (process.platform === 'win32') {
|
|
531
|
-
throw new
|
|
772
|
+
throw new CommandRefusalError('NOT_IMPLEMENTED', '--dev (symlink) not supported on Windows.\n' +
|
|
532
773
|
'Use copy mode (omit --dev) or WSL for development.');
|
|
533
774
|
}
|
|
534
775
|
// --cwd only applies to --dev mode; other paths (npm postinstall, etc.) use process.cwd()
|
|
535
|
-
const cwd = options.cwd ? safePath.resolve(options.cwd) : process.cwd();
|
|
776
|
+
const cwd = options.cwd ? safePath.resolve(options.cwd) : process.cwd(); // The operator's own: every probe beneath it passes it as `within`.
|
|
777
|
+
run.roots.source.push(cwd);
|
|
536
778
|
if (options.build) {
|
|
537
779
|
runBuild(cwd, logger);
|
|
538
780
|
}
|
|
539
781
|
// Check for pre-built plugin tree
|
|
540
782
|
const marketplacesDir = safePath.join(cwd, PLUGIN_MARKETPLACES_SUBPATH);
|
|
541
|
-
if (!
|
|
542
|
-
throw new
|
|
783
|
+
if (!pathPresent(marketplacesDir, { follow: cwd }, everywhere('source'), 'confirmed')) {
|
|
784
|
+
throw new CommandRefusalError('USAGE_INVALID', `Plugin tree not found at ${marketplacesDir}\n` +
|
|
543
785
|
`Run: vat build first (builds the plugin tree)`);
|
|
544
786
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
const packageJson = JSON.parse(pkgRaw);
|
|
787
|
+
const packageJson = await readPackageJson(cwd, packageOf(run, cwd, 'source'));
|
|
788
|
+
setSource(run, packageJson.name, 'dev', true);
|
|
548
789
|
logger.info(`📥 Dev-installing plugin tree from ${packageJson.name}`);
|
|
549
|
-
|
|
550
|
-
const installed = [];
|
|
551
|
-
// Remove old plugins/flat skills this package replaces, before installing
|
|
552
|
-
if (packageJson.vat?.replaces) {
|
|
553
|
-
const paths = getClaudeUserPaths();
|
|
554
|
-
const marketplaceNames = listSubdirectories(marketplacesDir);
|
|
555
|
-
await executeReplaces(packageJson.vat.replaces, marketplaceNames, paths, options.dryRun ?? false, logger);
|
|
556
|
-
}
|
|
557
|
-
for (const mpName of listSubdirectories(marketplacesDir)) {
|
|
558
|
-
const srcMpDir = safePath.join(marketplacesDir, mpName);
|
|
559
|
-
const results = await devInstallMarketplace(mpName, srcMpDir, packageInfo, cwd, options, logger);
|
|
560
|
-
installed.push(...results);
|
|
561
|
-
}
|
|
562
|
-
const duration = Date.now() - startTime;
|
|
563
|
-
outputDevSuccess(installed, packageJson.name, duration, logger, options.dryRun);
|
|
564
|
-
process.exit(ExitCode.OK);
|
|
790
|
+
await install(run, pluginTree('source', cwd, packageJson), 'dev');
|
|
565
791
|
}
|
|
566
792
|
/**
|
|
567
|
-
* Shell out to vat build (skills + claude plugin tree)
|
|
793
|
+
* Shell out to `vat build` (skills + claude plugin tree) in `cwd`.
|
|
794
|
+
*
|
|
795
|
+
* Its stdout goes to this process's stderr ({@link BUILD_CHILD_STDIO}), never
|
|
796
|
+
* through a buffered pipe. A build that exits non-zero, or one that cannot be
|
|
797
|
+
* started, stops the install before anything is installed: `RUN_INCOMPLETE`.
|
|
798
|
+
*
|
|
799
|
+
* @throws A `RUN_INCOMPLETE` {@link CommandRefusalError}
|
|
568
800
|
*/
|
|
569
|
-
function runBuild(cwd, logger) {
|
|
801
|
+
export function runBuild(cwd, logger) {
|
|
570
802
|
logger.info('🔨 Building first (skills + plugin tree)...');
|
|
571
803
|
const binPath = safePath.resolve(safePath.join(import.meta.dirname, '../../../../bin/vat.js'));
|
|
572
|
-
|
|
573
|
-
cwd,
|
|
574
|
-
|
|
575
|
-
|
|
804
|
+
try {
|
|
805
|
+
safeExecSync(process.execPath, [binPath, 'build'], { cwd, stdio: BUILD_CHILD_STDIO });
|
|
806
|
+
}
|
|
807
|
+
catch (error) {
|
|
808
|
+
const why = isVatError(error, 'COMMAND_EXECUTION')
|
|
809
|
+
? 'vat build failed — its output above says why'
|
|
810
|
+
: `vat build could not be run: ${String(error)}`;
|
|
811
|
+
throw new CommandRefusalError('RUN_INCOMPLETE', `${why} (in ${cwd}), so nothing was installed.`, { cause: error });
|
|
812
|
+
}
|
|
576
813
|
logger.info('');
|
|
577
814
|
}
|
|
578
815
|
/**
|
|
579
816
|
* Handle npm postinstall hook
|
|
580
817
|
*/
|
|
581
|
-
async function handleNpmPostinstall(
|
|
818
|
+
async function handleNpmPostinstall(run) {
|
|
819
|
+
const { options, logger } = run;
|
|
582
820
|
logger.info(`📥 Running npm postinstall hook`);
|
|
821
|
+
// The postinstall lane resolves its source (the package directory) whether or
|
|
822
|
+
// not it installs: a skip is an answer, `ok` with no skills — never a failure
|
|
823
|
+
// inside `npm install -g`.
|
|
824
|
+
const cwd = process.cwd(); // The package npm runs us in: every probe beneath it passes it as `within`.
|
|
825
|
+
setSource(run, cwd, 'npm-postinstall');
|
|
826
|
+
run.roots.source.push(cwd);
|
|
583
827
|
if (!isGlobalNpmInstall()) {
|
|
584
828
|
logger.info(' Skipping: Not a global npm install');
|
|
585
|
-
|
|
829
|
+
return;
|
|
586
830
|
}
|
|
587
|
-
const cwd = process.cwd();
|
|
588
|
-
// Check for pre-built plugin tree (dist/.claude/plugins/marketplaces/)
|
|
589
|
-
const marketplacesDir = safePath.join(cwd, PLUGIN_MARKETPLACES_SUBPATH);
|
|
590
|
-
const hasPluginTree = existsSync(marketplacesDir);
|
|
591
831
|
if (!options.userInstallWithoutPlugin) {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
logger.info(` Package: ${packageJson.name}@${packageJson.version ?? 'unknown'}`);
|
|
596
|
-
logger.info(` Plugin tree detected — copying to ~/.claude/plugins/`);
|
|
597
|
-
const installedSkills = await copyPluginTree(marketplacesDir, packageJson, logger, options.dryRun);
|
|
598
|
-
const duration = Date.now() - startTime;
|
|
599
|
-
logger.info(`✅ Installed plugin from ${packageJson.name} (${installedSkills.length} skill(s))`);
|
|
600
|
-
logger.info(` Duration: ${duration}ms`);
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
832
|
+
// Check for pre-built plugin tree (dist/.claude/plugins/marketplaces/)
|
|
833
|
+
const marketplacesDir = safePath.join(cwd, PLUGIN_MARKETPLACES_SUBPATH);
|
|
834
|
+
if (!pathPresent(marketplacesDir, { follow: cwd }, everywhere('source'), 'confirmed')) {
|
|
603
835
|
logger.info(` No plugin tree found at dist/.claude/plugins/marketplaces/`);
|
|
604
836
|
logger.info(` Run 'vat build' to generate plugin artifacts before publishing.`);
|
|
605
837
|
logger.info(` Skipping install — no skills registered.`);
|
|
838
|
+
return;
|
|
606
839
|
}
|
|
607
|
-
|
|
840
|
+
const packageJson = await readPackageJson(cwd, packageOf(run, cwd, 'source'));
|
|
841
|
+
logger.info(` Package: ${packageJson.name}@${packageJson.version ?? 'unknown'}`);
|
|
842
|
+
logger.info(` Plugin tree detected — copying to ~/.claude/plugins/`);
|
|
843
|
+
await install(run, pluginTree('source', cwd, packageJson), 'copy');
|
|
844
|
+
return;
|
|
608
845
|
}
|
|
609
846
|
// --user-install-without-plugin: install skills directly to ~/.claude/skills/
|
|
610
|
-
const { packageJson, skills } = await readPackageJsonVatMetadata(cwd);
|
|
611
|
-
logger.info(` Package: ${packageJson.name}@${packageJson.version}`);
|
|
847
|
+
const { packageJson, skills } = await readPackageJsonVatMetadata(cwd, packageOf(run, cwd, 'source'));
|
|
848
|
+
logger.info(` Package: ${packageJson.name}@${packageJson.version ?? 'unknown'}`);
|
|
612
849
|
logger.info(` Skills found: ${skills.length}`);
|
|
613
|
-
|
|
614
|
-
const skillPath = safePath.join(cwd, 'dist', 'skills', skillNameToFsPath(skillName));
|
|
615
|
-
await installSkillFromPath(skillPath, skillName, options, logger);
|
|
616
|
-
}
|
|
617
|
-
const duration = Date.now() - startTime;
|
|
618
|
-
logger.info(`✅ Installed ${skills.length} skill(s) from ${packageJson.name}`);
|
|
619
|
-
logger.info(` Duration: ${duration}ms`);
|
|
620
|
-
process.exit(ExitCode.OK);
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Execute vat.replaces cleanup before installing the new plugin.
|
|
624
|
-
*
|
|
625
|
-
* Removes old plugin registrations and legacy flat-skill installs that this
|
|
626
|
-
* package now supersedes. Runs before the new plugin is copied/symlinked so
|
|
627
|
-
* Claude Code never sees stale duplicate entries.
|
|
628
|
-
*
|
|
629
|
-
* Idempotent — uninstallPlugin handles "not found" gracefully.
|
|
630
|
-
*/
|
|
631
|
-
export async function removeFlatSkill(skillPath, logger) {
|
|
632
|
-
logger.info(` Removing legacy flat skill: ${toForwardSlash(skillPath)}`);
|
|
633
|
-
await rm(skillPath, { recursive: true, force: true });
|
|
634
|
-
}
|
|
635
|
-
export function logFlatSkillRemoval(skillPath, logger) {
|
|
636
|
-
logger.info(` [dry-run] Would remove legacy flat skill: ${toForwardSlash(skillPath)}`);
|
|
637
|
-
}
|
|
638
|
-
export async function removeOldPlugins(oldPlugins, marketplaceNames, paths, dryRun, logger) {
|
|
639
|
-
for (const mp of marketplaceNames) {
|
|
640
|
-
for (const oldPlugin of oldPlugins ?? []) {
|
|
641
|
-
const pluginKey = `${oldPlugin}@${mp}`;
|
|
642
|
-
if (dryRun) {
|
|
643
|
-
logger.info(` [dry-run] Would uninstall old plugin: ${pluginKey}`);
|
|
644
|
-
}
|
|
645
|
-
else {
|
|
646
|
-
logger.info(` Removing old plugin: ${pluginKey}`);
|
|
647
|
-
await uninstallPlugin({ pluginKey, paths, dryRun: false });
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
export async function executeReplaces(replaces, marketplaceNames, paths, dryRun, logger) {
|
|
653
|
-
// Remove old plugin entries from all marketplaces this package ships into
|
|
654
|
-
await removeOldPlugins(replaces.plugins, marketplaceNames, paths, dryRun, logger);
|
|
655
|
-
// Remove legacy flat-skill installs from ~/.claude/skills/<name>
|
|
656
|
-
for (const skillName of replaces.flatSkills ?? []) {
|
|
657
|
-
// The entry comes from the INSTALLED package's package.json, and this is
|
|
658
|
-
// an `rm -rf` with no flag in front of it: `"../victim"` used to remove a
|
|
659
|
-
// sibling of the skills dir (with the default paths, `"../.."` is $HOME).
|
|
660
|
-
const skillPath = safePath.join(paths.skillsDir, assertSkillEntryName(skillName, 'vat.replaces.flatSkills'));
|
|
661
|
-
let pathExists = false;
|
|
662
|
-
try {
|
|
663
|
-
lstatSync(skillPath); // throws if path itself doesn't exist (doesn't follow symlinks)
|
|
664
|
-
pathExists = true;
|
|
665
|
-
}
|
|
666
|
-
catch (error) {
|
|
667
|
-
// Path doesn't exist — nothing to remove. One the OS refuses to examine
|
|
668
|
-
// is not "nothing to remove": the legacy install is still there and a
|
|
669
|
-
// silent skip leaves it beside its replacement.
|
|
670
|
-
if (!isPathAbsentError(error))
|
|
671
|
-
throw error;
|
|
672
|
-
}
|
|
673
|
-
if (pathExists) {
|
|
674
|
-
if (dryRun) {
|
|
675
|
-
logFlatSkillRemoval(skillPath, logger);
|
|
676
|
-
}
|
|
677
|
-
else {
|
|
678
|
-
await removeFlatSkill(skillPath, logger);
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
/**
|
|
684
|
-
* Copy pre-built plugin tree to ~/.claude/plugins/ and update registry.
|
|
685
|
-
*
|
|
686
|
-
* This is a "dumb copy" — the dist/.claude/plugins/marketplaces/ tree mirrors
|
|
687
|
-
* the target ~/.claude/plugins/marketplaces/ structure exactly. No path rewriting,
|
|
688
|
-
* no assembly, no skill resolution. Just recursive copy + registry update.
|
|
689
|
-
*/
|
|
690
|
-
async function copyPluginTree(marketplacesDir, packageJson, logger, dryRun) {
|
|
691
|
-
const paths = getClaudeUserPaths();
|
|
692
|
-
const version = packageJson.version ?? '0.0.0';
|
|
693
|
-
const marketplaceNames = listSubdirectories(marketplacesDir);
|
|
694
|
-
const installedSkills = [];
|
|
695
|
-
// Remove any old plugins/flat skills this package replaces, before installing
|
|
696
|
-
if (packageJson.vat?.replaces) {
|
|
697
|
-
await executeReplaces(packageJson.vat.replaces, marketplaceNames, paths, dryRun ?? false, logger);
|
|
698
|
-
}
|
|
699
|
-
for (const mpName of marketplaceNames) {
|
|
700
|
-
const srcMpDir = safePath.join(marketplacesDir, mpName);
|
|
701
|
-
const destMpDir = safePath.join(paths.marketplacesDir, mpName);
|
|
702
|
-
// Replace the marketplace directory entirely so skills removed from the
|
|
703
|
-
// package do not persist in the user's Claude installation.
|
|
704
|
-
logger.info(` Copying marketplace: ${mpName} → ${destMpDir}`);
|
|
705
|
-
await rm(destMpDir, { recursive: true, force: true });
|
|
706
|
-
await mkdir(destMpDir, { recursive: true });
|
|
707
|
-
cpSync(srcMpDir, destMpDir, { recursive: true, force: true });
|
|
708
|
-
// Register each plugin and collect installed skill names
|
|
709
|
-
for (const pluginName of listSubdirectories(safePath.join(srcMpDir, 'plugins'))) {
|
|
710
|
-
const pluginDir = safePath.join(destMpDir, 'plugins', pluginName);
|
|
711
|
-
await registerPlugin(mpName, pluginName, pluginDir, version, packageJson.name, paths, logger);
|
|
712
|
-
const skillNames = listSubdirectories(safePath.join(srcMpDir, 'plugins', pluginName, 'skills'));
|
|
713
|
-
for (const skillName of skillNames) {
|
|
714
|
-
installedSkills.push({
|
|
715
|
-
name: skillName,
|
|
716
|
-
installPath: safePath.join(destMpDir, 'plugins', pluginName, 'skills', skillName),
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
return installedSkills;
|
|
722
|
-
}
|
|
723
|
-
/**
|
|
724
|
-
* Prepare plugins directory and check for conflicts
|
|
725
|
-
*/
|
|
726
|
-
async function prepareInstallation(skillName, options) {
|
|
727
|
-
const skillsDir = options.skillsDir ?? getClaudeUserPaths().skillsDir;
|
|
728
|
-
// The declared name is author-controlled (SKILL.md `name:`, package.json
|
|
729
|
-
// `vat.skills[]`) and `--force` turns this path into an `rm -rf`.
|
|
730
|
-
const installPath = safePath.join(skillsDir, assertSkillEntryName(skillName, 'skill name'));
|
|
731
|
-
let exists = false;
|
|
732
|
-
try {
|
|
733
|
-
lstatSync(installPath);
|
|
734
|
-
exists = true;
|
|
735
|
-
}
|
|
736
|
-
catch (error) {
|
|
737
|
-
// Does not exist. A refusal is not that: it used to read as "free", and
|
|
738
|
-
// the extraction that followed then met the same refusal without a name.
|
|
739
|
-
if (!isPathAbsentError(error))
|
|
740
|
-
throw error;
|
|
741
|
-
}
|
|
742
|
-
if (exists && !options.force) {
|
|
743
|
-
throw new Error(`Skill already exists at ${installPath}. Use --force to overwrite.`);
|
|
744
|
-
}
|
|
745
|
-
if (exists && options.force && !options.dryRun) {
|
|
746
|
-
await rm(installPath, { recursive: true, force: true });
|
|
747
|
-
}
|
|
748
|
-
if (!options.dryRun) {
|
|
749
|
-
await mkdir(skillsDir, { recursive: true });
|
|
750
|
-
}
|
|
751
|
-
return { skillsDir, installPath };
|
|
752
|
-
}
|
|
753
|
-
/**
|
|
754
|
-
* Install skill from a path to plugins directory
|
|
755
|
-
*/
|
|
756
|
-
async function installSkillFromPath(skillPath, skillName, options, logger) {
|
|
757
|
-
if (!existsSync(skillPath)) {
|
|
758
|
-
throw new Error(`Skill path not found: ${skillPath}`);
|
|
759
|
-
}
|
|
760
|
-
const { installPath } = await prepareInstallation(skillName, options);
|
|
761
|
-
if (!options.dryRun) {
|
|
762
|
-
logger.info(` Installing ${skillName}...`);
|
|
763
|
-
cpSync(skillPath, installPath, { recursive: true, force: true });
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
/**
|
|
767
|
-
* Output success YAML for dev install
|
|
768
|
-
*/
|
|
769
|
-
function outputDevSuccess(installed, packageName, duration, logger, dryRun) {
|
|
770
|
-
writeYamlHeader(dryRun);
|
|
771
|
-
process.stdout.write(`sourceType: dev\n`);
|
|
772
|
-
process.stdout.write(`package: "${packageName}"\n`);
|
|
773
|
-
process.stdout.write(`skillsInstalled: ${installed.length}\n`);
|
|
774
|
-
process.stdout.write(`symlink: true\n`);
|
|
775
|
-
process.stdout.write(`skills:\n`);
|
|
776
|
-
for (const skill of installed) {
|
|
777
|
-
process.stdout.write(` - name: ${skill.name}\n`);
|
|
778
|
-
process.stdout.write(` installPath: ${skill.installPath}\n`);
|
|
779
|
-
process.stdout.write(` sourcePath: ${skill.sourcePath}\n`);
|
|
780
|
-
}
|
|
781
|
-
process.stdout.write(`duration: ${duration}ms\n`);
|
|
782
|
-
if (dryRun) {
|
|
783
|
-
logger.info(`\n✅ Dry-run complete: ${installed.length} skill(s) would be symlinked`);
|
|
784
|
-
}
|
|
785
|
-
else {
|
|
786
|
-
logger.info(`\n✅ Dev-installed ${installed.length} skill(s) via symlink`);
|
|
787
|
-
logger.info(` After rebuilding, run /reload-plugins in Claude Code`);
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
/**
|
|
791
|
-
* Output success YAML for install
|
|
792
|
-
*/
|
|
793
|
-
function outputInstallSuccess(skills, source, sourceType, duration, logger, dryRun) {
|
|
794
|
-
writeYamlHeader(dryRun);
|
|
795
|
-
process.stdout.write(`source: ${source}\n`);
|
|
796
|
-
process.stdout.write(`sourceType: ${sourceType}\n`);
|
|
797
|
-
process.stdout.write(`skillsInstalled: ${skills.length}\n`);
|
|
798
|
-
process.stdout.write(`skills:\n`);
|
|
799
|
-
for (const skill of skills) {
|
|
800
|
-
process.stdout.write(` - name: ${skill.name}\n`);
|
|
801
|
-
process.stdout.write(` installPath: ${skill.installPath}\n`);
|
|
802
|
-
}
|
|
803
|
-
process.stdout.write(`duration: ${duration}ms\n`);
|
|
804
|
-
if (dryRun) {
|
|
805
|
-
logger.info(`\n✅ Dry-run complete: ${skills.length} skill(s) would be installed`);
|
|
806
|
-
}
|
|
807
|
-
else {
|
|
808
|
-
logger.info(`\n✅ Installed ${skills.length} skill(s)`);
|
|
809
|
-
logger.info(`\n💡 Run 'vat claude plugin list' to verify installation`);
|
|
810
|
-
logger.info(` Restart Claude Code or run /reload-plugins to use the new skill`);
|
|
811
|
-
}
|
|
850
|
+
await install(run, { kind: 'skills', side: 'source', rootDir: cwd, skillNames: skills }, 'copy');
|
|
812
851
|
}
|
|
852
|
+
/** Test-facing seam: the pure decisions of this module, reached by its unit tests. */
|
|
853
|
+
export const __internal = {
|
|
854
|
+
assertInstallTarget,
|
|
855
|
+
assertPackagePluginNames,
|
|
856
|
+
boundaryOf,
|
|
857
|
+
executeInstall,
|
|
858
|
+
leftover,
|
|
859
|
+
logInstallOutcome,
|
|
860
|
+
newInstallRun,
|
|
861
|
+
notPlugins,
|
|
862
|
+
notPluginSkills,
|
|
863
|
+
notSkills,
|
|
864
|
+
outcomeOf,
|
|
865
|
+
planInstall,
|
|
866
|
+
record,
|
|
867
|
+
replacedOutcome,
|
|
868
|
+
selectSkills,
|
|
869
|
+
setSource,
|
|
870
|
+
skillNameToFsPath,
|
|
871
|
+
stagedIn,
|
|
872
|
+
};
|
|
813
873
|
//# sourceMappingURL=install.js.map
|