vskill 0.5.44 → 0.5.46

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.
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Skill Studio</title>
7
- <script type="module" crossorigin src="/assets/index-CsWzYuTb.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-B5TJCTjp.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-CGNHEtf7.css">
9
9
  </head>
10
10
  <body>
@@ -32,3 +32,19 @@ export declare function migrateStaleSkillFiles(skillsDir: string): MigrationResu
32
32
  * Also recurses one level into namespace directories (e.g., sw/).
33
33
  */
34
34
  export declare function ensureSkillMdNaming(skillsDir: string): NamingResult;
35
+ /**
36
+ * Remove stale double-nested skill directories left by pre-fix installations.
37
+ *
38
+ * Before the double-nesting fix (ec19dde, 2026-03-18), installing a plugin
39
+ * whose single skill shared its name would create:
40
+ * {skillsDir}/{name}/{name}/SKILL.md (incorrect)
41
+ * instead of:
42
+ * {skillsDir}/{name}/SKILL.md (correct)
43
+ *
44
+ * When called AFTER writing the correct SKILL.md, this function detects and
45
+ * removes the stale nested directory.
46
+ *
47
+ * @param skillDir The directory that should contain SKILL.md directly,
48
+ * e.g. `~/.claude/skills/nanobanana/`
49
+ */
50
+ export declare function cleanStaleNesting(skillDir: string): void;
@@ -1,7 +1,7 @@
1
1
  // ---------------------------------------------------------------------------
2
2
  // Migrate stale flat .md skill files to {name}/SKILL.md subdirectory structure
3
3
  // ---------------------------------------------------------------------------
4
- import { readdirSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, existsSync, lstatSync, } from "node:fs";
4
+ import { readdirSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, rmSync, existsSync, lstatSync, } from "node:fs";
5
5
  import { join, basename } from "node:path";
6
6
  import { ensureFrontmatter } from "./frontmatter.js";
7
7
  /**
@@ -164,6 +164,37 @@ function enforceSkillMdInDir(dir, result) {
164
164
  }
165
165
  }
166
166
  }
167
+ /**
168
+ * Remove stale double-nested skill directories left by pre-fix installations.
169
+ *
170
+ * Before the double-nesting fix (ec19dde, 2026-03-18), installing a plugin
171
+ * whose single skill shared its name would create:
172
+ * {skillsDir}/{name}/{name}/SKILL.md (incorrect)
173
+ * instead of:
174
+ * {skillsDir}/{name}/SKILL.md (correct)
175
+ *
176
+ * When called AFTER writing the correct SKILL.md, this function detects and
177
+ * removes the stale nested directory.
178
+ *
179
+ * @param skillDir The directory that should contain SKILL.md directly,
180
+ * e.g. `~/.claude/skills/nanobanana/`
181
+ */
182
+ export function cleanStaleNesting(skillDir) {
183
+ const name = basename(skillDir);
184
+ const nested = join(skillDir, name);
185
+ try {
186
+ const stat = lstatSync(nested);
187
+ if (!stat.isDirectory() || stat.isSymbolicLink())
188
+ return;
189
+ // Only remove the nested dir when the parent already has the correct SKILL.md
190
+ if (existsSync(join(skillDir, "SKILL.md"))) {
191
+ rmSync(nested, { recursive: true, force: true });
192
+ }
193
+ }
194
+ catch {
195
+ // Nested dir doesn't exist — nothing to clean
196
+ }
197
+ }
167
198
  /**
168
199
  * Migrate stale flat .md files within a single directory level.
169
200
  */
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/installer/migrate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/installer/migrate.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,12 @@
1
1
  export interface ProviderResult {
2
2
  provider: string;
3
- status: string;
4
- verdict: string | null;
3
+ status: "PASS" | "FAIL" | "PENDING" | "TIMED_OUT";
4
+ verdict: "PASS" | "FAIL" | "CONCERNS" | "PENDING" | null;
5
5
  criticalCount: number;
6
6
  }
7
7
  export interface PlatformSecurityResult {
8
8
  hasCritical: boolean;
9
- overallVerdict: string;
9
+ overallVerdict: "PASS" | "FAIL" | "PENDING" | "TIMED_OUT" | "CERTIFIED";
10
10
  providers: ProviderResult[];
11
11
  reportUrl: string;
12
12
  }
@@ -2,6 +2,20 @@
2
2
  // Platform security check — queries external SAST scan results (best-effort)
3
3
  // ---------------------------------------------------------------------------
4
4
  const BASE_URL = "https://verified-skill.com";
5
+ // ---------------------------------------------------------------------------
6
+ // Runtime validation helpers
7
+ // ---------------------------------------------------------------------------
8
+ const VALID_STATUSES = new Set(["PASS", "FAIL", "PENDING", "TIMED_OUT"]);
9
+ const VALID_VERDICTS = new Set(["PASS", "FAIL", "CONCERNS", "PENDING"]);
10
+ const VALID_OVERALL = new Set(["PASS", "FAIL", "PENDING", "TIMED_OUT", "CERTIFIED"]);
11
+ function validateEnum(value, allowed, fallback) {
12
+ const upper = value.toUpperCase();
13
+ return allowed.has(upper) ? upper : fallback;
14
+ }
15
+ function safeNumber(value, fallback) {
16
+ const n = Number(value ?? fallback);
17
+ return isNaN(n) ? fallback : n;
18
+ }
5
19
  /**
6
20
  * Check external SAST scan results from the platform API.
7
21
  * Returns null on any network/API error (best-effort, non-fatal).
@@ -9,25 +23,32 @@ const BASE_URL = "https://verified-skill.com";
9
23
  export async function checkPlatformSecurity(skillName) {
10
24
  try {
11
25
  const url = `${BASE_URL}/api/v1/skills/${skillName.split("/").map(encodeURIComponent).join("/")}/security`;
12
- const res = await fetch(url);
13
- if (!res.ok)
26
+ const res = await fetch(url, { signal: AbortSignal.timeout(10_000) });
27
+ if (!res.ok) {
28
+ console.warn(`[platform-security] HTTP ${res.status} for ${skillName}`);
14
29
  return null;
30
+ }
15
31
  const data = (await res.json());
16
32
  const providers = (data.providers || []).map((p) => ({
17
33
  provider: String(p.provider || ""),
18
- status: String(p.status || "PENDING"),
19
- verdict: p.verdict ?? null,
20
- criticalCount: Number(p.criticalCount ?? 0),
34
+ status: validateEnum(String(p.status || "PENDING"), VALID_STATUSES, "PENDING"),
35
+ verdict: p.verdict == null ? null : validateEnum(String(p.verdict), VALID_VERDICTS, "PENDING"),
36
+ criticalCount: safeNumber(p.criticalCount, 0),
21
37
  }));
38
+ // Empty providers = no scan data available — report as PENDING, not all-clear
39
+ const overallVerdict = providers.length === 0
40
+ ? "PENDING"
41
+ : validateEnum(String(data.overallVerdict || "PENDING"), VALID_OVERALL, "PENDING");
22
42
  const hasCritical = providers.some((p) => p.status === "FAIL" && p.criticalCount > 0);
23
43
  return {
24
44
  hasCritical,
25
- overallVerdict: String(data.overallVerdict || "PENDING"),
45
+ overallVerdict,
26
46
  providers,
27
47
  reportUrl: String(data.reportUrl || ""),
28
48
  };
29
49
  }
30
- catch {
50
+ catch (err) {
51
+ console.warn(`[platform-security] check failed for ${skillName}:`, err instanceof Error ? err.message : String(err));
31
52
  return null;
32
53
  }
33
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"platform-security.js","sourceRoot":"","sources":["../../src/security/platform-security.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAE9E,MAAM,QAAQ,GAAG,4BAA4B,CAAC;AAgB9C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,SAAiB;IAEjB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,GAAG,QAAQ,kBAAkB,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;QAC3G,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QAE7B,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAEzB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAS7B,CAAC;QAEF,MAAM,SAAS,GAAqB,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACrE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC;YAClC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC;YACrC,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,IAAI;YAC1B,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC;SAC5C,CAAC,CAAC,CAAC;QAEJ,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,aAAa,GAAG,CAAC,CAClD,CAAC;QAEF,OAAO;YACL,WAAW;YACX,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,cAAc,IAAI,SAAS,CAAC;YACxD,SAAS;YACT,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;SACxC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"platform-security.js","sourceRoot":"","sources":["../../src/security/platform-security.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAE9E,MAAM,QAAQ,GAAG,4BAA4B,CAAC;AAgB9C,8EAA8E;AAC9E,6BAA6B;AAC7B,8EAA8E;AAE9E,MAAM,cAAc,GAAG,IAAI,GAAG,CAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;AACnG,MAAM,cAAc,GAAG,IAAI,GAAG,CAAyC,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;AAChH,MAAM,aAAa,GAAG,IAAI,GAAG,CAA2C,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;AAE/H,SAAS,YAAY,CAAmB,KAAa,EAAE,OAAe,EAAE,QAAW;IACjF,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAO,CAAC;IACvC,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC/C,CAAC;AAED,SAAS,UAAU,CAAC,KAAc,EAAE,QAAgB;IAClD,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC;IACpC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,SAAiB;IAEjB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,GAAG,QAAQ,kBAAkB,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;QAC3G,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAEtE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,4BAA4B,GAAG,CAAC,MAAM,QAAQ,SAAS,EAAE,CAAC,CAAC;YACxE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAS7B,CAAC;QAEF,MAAM,SAAS,GAAqB,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACrE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC;YAClC,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC,EAAE,cAAc,EAAE,SAAS,CAAC;YAC9E,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,SAAS,CAAC;YAC9F,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC;SAC9C,CAAC,CAAC,CAAC;QAEJ,8EAA8E;QAC9E,MAAM,cAAc,GAAG,SAAS,CAAC,MAAM,KAAK,CAAC;YAC3C,CAAC,CAAC,SAAkB;YACpB,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,IAAI,SAAS,CAAC,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;QAErF,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,aAAa,GAAG,CAAC,CAClD,CAAC;QAEF,OAAO;YACL,WAAW;YACX,cAAc;YACd,SAAS;YACT,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;SACxC,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,wCAAwC,SAAS,GAAG,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACrH,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -1,2 +1,2 @@
1
1
  export type { SettingsOptions } from "./settings.js";
2
- export { enablePlugin, disablePlugin, removePlugin, isPluginEnabled, listEnabledPlugins, purgeStalePlugins, } from "./settings.js";
2
+ export { isPluginEnabled, listEnabledPlugins, purgeStalePlugins, } from "./settings.js";
@@ -1,2 +1,2 @@
1
- export { enablePlugin, disablePlugin, removePlugin, isPluginEnabled, listEnabledPlugins, purgeStalePlugins, } from "./settings.js";
1
+ export { isPluginEnabled, listEnabledPlugins, purgeStalePlugins, } from "./settings.js";
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/settings/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/settings/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,eAAe,CAAC"}
@@ -2,18 +2,6 @@ export interface SettingsOptions {
2
2
  scope: "user" | "project";
3
3
  projectDir?: string;
4
4
  }
5
- /**
6
- * Enable a plugin in settings.json.
7
- */
8
- export declare function enablePlugin(pluginId: string, opts: SettingsOptions): void;
9
- /**
10
- * Disable a plugin in settings.json (set to false).
11
- */
12
- export declare function disablePlugin(pluginId: string, opts: SettingsOptions): void;
13
- /**
14
- * Remove a plugin entry entirely from settings.json (vs. setting to false).
15
- */
16
- export declare function removePlugin(pluginId: string, opts: SettingsOptions): void;
17
5
  /**
18
6
  * Check if a plugin is enabled in settings.json.
19
7
  */
@@ -23,15 +11,15 @@ export declare function isPluginEnabled(pluginId: string, opts: SettingsOptions)
23
11
  */
24
12
  export declare function listEnabledPlugins(opts: SettingsOptions): string[];
25
13
  /**
26
- * Remove enabledPlugins entries not backed by a lockfile entry.
14
+ * Identify enabledPlugins entries not backed by a lockfile entry.
27
15
  *
28
16
  * Plugin IDs use `<skillName>@<marketplace>` format.
29
17
  * A plugin is stale when no lockfile skill matches by name AND marketplace.
30
18
  *
31
- * Designed for `vskill init` (pre-launch)runs BEFORE Claude Code
32
- * loads its in-memory settings cache, preventing ghost re-writes.
19
+ * Returns the list of stale plugin IDs callers are responsible for
20
+ * uninstalling them via `claudePluginUninstall()`.
33
21
  *
34
- * @returns Array of purged plugin IDs
22
+ * @returns Array of stale plugin IDs
35
23
  */
36
24
  export declare function purgeStalePlugins(opts: SettingsOptions, lockfileSkills: Record<string, {
37
25
  marketplace?: string;
@@ -1,8 +1,13 @@
1
1
  // ---------------------------------------------------------------------------
2
- // Claude Code settings.json management
2
+ // Claude Code settings.json — READ-ONLY access
3
+ //
4
+ // This module only reads settings.json. All writes must go through the
5
+ // claude CLI (claude plugin install/uninstall). Direct filesystem writes
6
+ // to settings.json bypass Claude Code's atomicity guarantees and can cause
7
+ // race conditions when Claude Code holds the file in memory.
3
8
  // ---------------------------------------------------------------------------
4
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
5
- import { join, dirname } from "node:path";
9
+ import { readFileSync, existsSync } from "node:fs";
10
+ import { join } from "node:path";
6
11
  import { homedir } from "node:os";
7
12
  /**
8
13
  * Resolves the path to settings.json based on scope.
@@ -30,49 +35,6 @@ function readSettings(opts) {
30
35
  return {};
31
36
  }
32
37
  }
33
- /**
34
- * Writes settings.json, creating parent directories if needed.
35
- */
36
- function writeSettings(settings, opts) {
37
- const p = settingsPath(opts);
38
- const dir = dirname(p);
39
- if (!existsSync(dir)) {
40
- mkdirSync(dir, { recursive: true });
41
- }
42
- writeFileSync(p, JSON.stringify(settings, null, 2) + "\n", "utf-8");
43
- }
44
- /**
45
- * Enable a plugin in settings.json.
46
- */
47
- export function enablePlugin(pluginId, opts) {
48
- const settings = readSettings(opts);
49
- if (!settings.enabledPlugins) {
50
- settings.enabledPlugins = {};
51
- }
52
- settings.enabledPlugins[pluginId] = true;
53
- writeSettings(settings, opts);
54
- }
55
- /**
56
- * Disable a plugin in settings.json (set to false).
57
- */
58
- export function disablePlugin(pluginId, opts) {
59
- const settings = readSettings(opts);
60
- if (!settings.enabledPlugins) {
61
- settings.enabledPlugins = {};
62
- }
63
- settings.enabledPlugins[pluginId] = false;
64
- writeSettings(settings, opts);
65
- }
66
- /**
67
- * Remove a plugin entry entirely from settings.json (vs. setting to false).
68
- */
69
- export function removePlugin(pluginId, opts) {
70
- const settings = readSettings(opts);
71
- if (settings.enabledPlugins) {
72
- delete settings.enabledPlugins[pluginId];
73
- }
74
- writeSettings(settings, opts);
75
- }
76
38
  /**
77
39
  * Check if a plugin is enabled in settings.json.
78
40
  */
@@ -92,21 +54,21 @@ export function listEnabledPlugins(opts) {
92
54
  .map(([k]) => k);
93
55
  }
94
56
  /**
95
- * Remove enabledPlugins entries not backed by a lockfile entry.
57
+ * Identify enabledPlugins entries not backed by a lockfile entry.
96
58
  *
97
59
  * Plugin IDs use `<skillName>@<marketplace>` format.
98
60
  * A plugin is stale when no lockfile skill matches by name AND marketplace.
99
61
  *
100
- * Designed for `vskill init` (pre-launch)runs BEFORE Claude Code
101
- * loads its in-memory settings cache, preventing ghost re-writes.
62
+ * Returns the list of stale plugin IDs callers are responsible for
63
+ * uninstalling them via `claudePluginUninstall()`.
102
64
  *
103
- * @returns Array of purged plugin IDs
65
+ * @returns Array of stale plugin IDs
104
66
  */
105
67
  export function purgeStalePlugins(opts, lockfileSkills) {
106
68
  const settings = readSettings(opts);
107
69
  if (!settings.enabledPlugins)
108
70
  return [];
109
- const purged = [];
71
+ const stale = [];
110
72
  for (const pluginId of Object.keys(settings.enabledPlugins)) {
111
73
  const atIdx = pluginId.lastIndexOf("@");
112
74
  if (atIdx === -1)
@@ -115,13 +77,9 @@ export function purgeStalePlugins(opts, lockfileSkills) {
115
77
  const marketplace = pluginId.slice(atIdx + 1);
116
78
  const lockEntry = lockfileSkills[skillName];
117
79
  if (!lockEntry || lockEntry.marketplace !== marketplace) {
118
- purged.push(pluginId);
119
- delete settings.enabledPlugins[pluginId];
80
+ stale.push(pluginId);
120
81
  }
121
82
  }
122
- if (purged.length > 0) {
123
- writeSettings(settings, opts);
124
- }
125
- return purged;
83
+ return stale;
126
84
  }
127
85
  //# sourceMappingURL=settings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/settings/settings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/settings/settings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Uninstall a marketplace plugin via the claude CLI.
3
+ *
4
+ * Delegates to: claude plugin uninstall --scope <scope> -- <pluginId>
5
+ *
6
+ * This is the only sanctioned way to remove entries from settings.json's
7
+ * enabledPlugins field and the associated plugin cache.
8
+ *
9
+ * **Note**: `scope: "project"` operates on the project in `process.cwd()`.
10
+ * Callers must ensure they are in the correct working directory, or pass
11
+ * a `cwd` option to override.
12
+ *
13
+ * @throws if the claude binary is not found — callers should wrap in try/catch
14
+ * when the plugin may not have been installed via the claude CLI
15
+ */
16
+ export declare function claudePluginUninstall(pluginId: string, scope?: "user" | "project" | "local", opts?: {
17
+ cwd?: string;
18
+ }): void;
@@ -0,0 +1,28 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Claude CLI plugin management delegation
3
+ //
4
+ // All mutations to ~/.claude/settings.json (enabledPlugins) and the plugin
5
+ // cache must go through the claude CLI, never via direct filesystem writes.
6
+ // ---------------------------------------------------------------------------
7
+ import { execFileSync } from "node:child_process";
8
+ import { resolveCliBinary } from "./resolve-binary.js";
9
+ /**
10
+ * Uninstall a marketplace plugin via the claude CLI.
11
+ *
12
+ * Delegates to: claude plugin uninstall --scope <scope> -- <pluginId>
13
+ *
14
+ * This is the only sanctioned way to remove entries from settings.json's
15
+ * enabledPlugins field and the associated plugin cache.
16
+ *
17
+ * **Note**: `scope: "project"` operates on the project in `process.cwd()`.
18
+ * Callers must ensure they are in the correct working directory, or pass
19
+ * a `cwd` option to override.
20
+ *
21
+ * @throws if the claude binary is not found — callers should wrap in try/catch
22
+ * when the plugin may not have been installed via the claude CLI
23
+ */
24
+ export function claudePluginUninstall(pluginId, scope = "user", opts) {
25
+ const claude = resolveCliBinary("claude");
26
+ execFileSync(claude, ["plugin", "uninstall", "--scope", scope, "--", pluginId], { stdio: "pipe", ...(opts?.cwd ? { cwd: opts.cwd } : {}) });
27
+ }
28
+ //# sourceMappingURL=claude-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-plugin.js","sourceRoot":"","sources":["../../src/utils/claude-plugin.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0CAA0C;AAC1C,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,8EAA8E;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,QAAsC,MAAM,EAC5C,IAAuB;IAEvB,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC1C,YAAY,CACV,MAAM,EACN,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,EACzD,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAC3D,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vskill",
3
- "version": "0.5.44",
3
+ "version": "0.5.46",
4
4
  "type": "module",
5
5
  "description": "Secure multi-platform AI skill installer — scan before you install",
6
6
  "bin": {
@@ -46,12 +46,13 @@ if (remaining.length > 0) {
46
46
  console.log("Or manually delete the directories listed above.\n");
47
47
  }
48
48
 
49
- // Clean plugin cache if it exists
50
- const cacheDir = path.join(home, ".claude", "plugins", "cache");
49
+ // Clean only the vskill-owned marketplace subdirectory from the plugin cache.
50
+ // Never delete the entire cache — other tools may share ~/.claude/plugins/cache/.
51
+ const vskillCacheDir = path.join(home, ".claude", "plugins", "cache", "specweave");
51
52
  try {
52
- if (fs.existsSync(cacheDir)) {
53
- fs.rmSync(cacheDir, { recursive: true, force: true });
54
- console.log("vskill: Cleaned plugin cache at " + cacheDir);
53
+ if (fs.existsSync(vskillCacheDir)) {
54
+ fs.rmSync(vskillCacheDir, { recursive: true, force: true });
55
+ console.log("vskill: Cleaned plugin cache at " + vskillCacheDir);
55
56
  }
56
57
  } catch {
57
58
  // Ignore cleanup errors