vskill 0.5.107 → 0.5.109
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 +109 -0
- package/agents.json +1 -1
- package/dist/commands/add.d.ts +36 -0
- package/dist/commands/add.js +149 -0
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/cleanup.d.ts +6 -1
- package/dist/commands/cleanup.js +37 -5
- package/dist/commands/cleanup.js.map +1 -1
- package/dist/commands/disable.d.ts +8 -0
- package/dist/commands/disable.js +194 -0
- package/dist/commands/disable.js.map +1 -0
- package/dist/commands/enable.d.ts +11 -0
- package/dist/commands/enable.js +209 -0
- package/dist/commands/enable.js.map +1 -0
- package/dist/commands/eval/serve.js +18 -4
- package/dist/commands/eval/serve.js.map +1 -1
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +83 -1
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/remove.d.ts +2 -0
- package/dist/commands/remove.js +84 -11
- package/dist/commands/remove.js.map +1 -1
- package/dist/eval/llm.js +7 -0
- package/dist/eval/llm.js.map +1 -1
- package/dist/eval-server/__tests__/helpers/skill-md-test-helpers.d.ts +1 -0
- package/dist/eval-server/__tests__/helpers/skill-md-test-helpers.js +16 -0
- package/dist/eval-server/__tests__/helpers/skill-md-test-helpers.js.map +1 -0
- package/dist/eval-server/api-routes.d.ts +13 -2
- package/dist/eval-server/api-routes.js +314 -37
- package/dist/eval-server/api-routes.js.map +1 -1
- package/dist/eval-server/check-dist-freshness.d.ts +19 -0
- package/dist/eval-server/check-dist-freshness.js +100 -0
- package/dist/eval-server/check-dist-freshness.js.map +1 -0
- package/dist/eval-server/eval-server.js +17 -6
- package/dist/eval-server/eval-server.js.map +1 -1
- package/dist/eval-server/improve-routes.js +50 -2
- package/dist/eval-server/improve-routes.js.map +1 -1
- package/dist/eval-server/platform-proxy.d.ts +22 -0
- package/dist/eval-server/platform-proxy.js +53 -4
- package/dist/eval-server/platform-proxy.js.map +1 -1
- package/dist/eval-server/providers.js +4 -1
- package/dist/eval-server/providers.js.map +1 -1
- package/dist/eval-server/settings-store.js +19 -1
- package/dist/eval-server/settings-store.js.map +1 -1
- package/dist/eval-server/skill-create-routes.d.ts +9 -0
- package/dist/eval-server/skill-create-routes.js +107 -19
- package/dist/eval-server/skill-create-routes.js.map +1 -1
- package/dist/eval-server/studio-json.js +12 -3
- package/dist/eval-server/studio-json.js.map +1 -1
- package/dist/eval-ui/assets/{CommandPalette-sazEtk0a.js → CommandPalette-3xE9OCOe.js} +1 -1
- package/dist/eval-ui/assets/CreateSkillPage-BEdLsGoc.js +12 -0
- package/dist/eval-ui/assets/{UpdateDropdown-Ce9LXOxb.js → UpdateDropdown-Bwk3qR7G.js} +1 -1
- package/dist/eval-ui/assets/{index-vn5bFfrb.js → index-CdnFViSu.js} +38 -38
- package/dist/eval-ui/assets/index-CyYEYhQ8.css +1 -0
- package/dist/eval-ui/index.html +2 -2
- package/dist/index.js +38 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/skill-lifecycle.d.ts +78 -0
- package/dist/lib/skill-lifecycle.js +136 -0
- package/dist/lib/skill-lifecycle.js.map +1 -0
- package/dist/utils/version.d.ts +13 -0
- package/dist/utils/version.js +29 -0
- package/dist/utils/version.js.map +1 -1
- package/package.json +1 -1
- package/dist/eval-ui/assets/CreateSkillPage-B5qENwBj.js +0 -12
- package/dist/eval-ui/assets/index-BBoVqs6V.css +0 -1
package/README.md
CHANGED
|
@@ -133,11 +133,15 @@ Then invoke as `/plugin:skill` in your agent:
|
|
|
133
133
|
|
|
134
134
|
```
|
|
135
135
|
vskill install <source> Install skill after security scan
|
|
136
|
+
vskill enable <skill> Enable a previously-installed skill in Claude Code
|
|
137
|
+
vskill disable <skill> Disable a skill (keep files on disk; flip the toggle)
|
|
136
138
|
vskill find <query> Search the verified-skill.com registry
|
|
137
139
|
vskill scan <path> Run security scan without installing
|
|
138
140
|
vskill list Show installed skills with status
|
|
141
|
+
vskill list --installed Per-scope enabled/disabled status table
|
|
139
142
|
vskill remove <skill> Remove an installed skill
|
|
140
143
|
vskill update [skill] Update with diff scanning (--all for everything)
|
|
144
|
+
vskill cleanup Remove stale plugin entries and orphaned cache
|
|
141
145
|
vskill audit [path] Full project security audit with LLM analysis
|
|
142
146
|
vskill info <skill> Show detailed skill information
|
|
143
147
|
vskill submit <source> Submit a skill for verification
|
|
@@ -147,6 +151,108 @@ vskill diff <s> <from> <to> Show multi-file diff between two versions
|
|
|
147
151
|
vskill keys <cmd> [provider] Manage LLM API keys (set/list/remove/path)
|
|
148
152
|
```
|
|
149
153
|
|
|
154
|
+
## Enable / Disable
|
|
155
|
+
|
|
156
|
+
`vskill install` extracts a skill's files and (when the source is a Claude
|
|
157
|
+
Code marketplace plugin) registers the plugin in `~/.claude/settings.json`'s
|
|
158
|
+
`enabledPlugins`. Once installed, you can toggle it without re-downloading:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Disable a skill — keeps files on disk, just removes the enabledPlugins entry.
|
|
162
|
+
vskill disable foo
|
|
163
|
+
|
|
164
|
+
# Re-enable later — same plugin id, no network round-trip.
|
|
165
|
+
vskill enable foo
|
|
166
|
+
|
|
167
|
+
# Project-scope toggle (writes <cwd>/.claude/settings.json instead of ~/).
|
|
168
|
+
vskill enable foo --scope project
|
|
169
|
+
|
|
170
|
+
# Preview what would happen (prints the exact `claude plugin install/uninstall`
|
|
171
|
+
# invocation, no subprocess spawn).
|
|
172
|
+
vskill enable foo --dry-run
|
|
173
|
+
vskill disable foo --dry-run
|
|
174
|
+
|
|
175
|
+
# Verbose — shows resolved binary path + scope + cwd.
|
|
176
|
+
vskill enable foo --verbose
|
|
177
|
+
|
|
178
|
+
# Machine-readable JSON.
|
|
179
|
+
vskill enable foo --json
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Both commands wrap `claude plugin install/uninstall` per
|
|
183
|
+
[ADR 0724-01](../../.specweave/docs/internal/architecture/adr/0724-01-skill-enable-disable-via-claude-cli.md)
|
|
184
|
+
— vskill never writes `settings.json` directly. The commands are
|
|
185
|
+
**idempotent**: running `vskill enable foo` twice prints
|
|
186
|
+
`foo already enabled in user scope` on the second run and exits 0.
|
|
187
|
+
|
|
188
|
+
### Install with `--no-enable`
|
|
189
|
+
|
|
190
|
+
For CI pipelines that want the files on disk and the lockfile entry written
|
|
191
|
+
but **not** the plugin registered:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
vskill install anton-abyzov/skill-foo --no-enable
|
|
195
|
+
# … later, when you actually want it active:
|
|
196
|
+
vskill enable foo
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### `vskill list --installed`
|
|
200
|
+
|
|
201
|
+
Joins `vskill.lock` with `enabledPlugins` reads at user and project scope:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
$ vskill list --installed
|
|
205
|
+
|
|
206
|
+
Installed Skills (3)
|
|
207
|
+
|
|
208
|
+
Skill Version Source User Scope Project Scope
|
|
209
|
+
foo 1.0.0 marketplace:o/r#foo enabled disabled
|
|
210
|
+
bar 2.1.0 marketplace:o/r#bar disabled enabled
|
|
211
|
+
baz 0.1.0 github:o/r#baz n/a n/a
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The `n/a` rows are auto-discovered skills (no `marketplace` field in their
|
|
215
|
+
lockfile entry) — there's nothing to toggle for them; agents pick them up
|
|
216
|
+
directly from their `localSkillsDir`/`globalSkillsDir` on the filesystem.
|
|
217
|
+
|
|
218
|
+
JSON output (`--installed --json`) emits one object per skill with
|
|
219
|
+
`{name, version, source, enabledUser, enabledProject, autoDiscovered}` —
|
|
220
|
+
suitable for piping into `jq`.
|
|
221
|
+
|
|
222
|
+
### Multi-agent surface awareness
|
|
223
|
+
|
|
224
|
+
When you have Claude Code AND Cursor AND Codex CLI installed, both
|
|
225
|
+
`install` and `enable` print a per-agent line so you know exactly which
|
|
226
|
+
surface received the registration:
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
$ vskill enable foo
|
|
230
|
+
|
|
231
|
+
Enabled foo (foo@m) in user scope.
|
|
232
|
+
> Claude Code (user) — enabled via claude CLI
|
|
233
|
+
> Cursor — auto-discovers from .cursor/skills (no plugin enable needed)
|
|
234
|
+
> Codex CLI — auto-discovers from .codex/skills (no plugin enable needed)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
For non-Claude-Code agents that auto-discover from disk, there is nothing
|
|
238
|
+
to toggle — the skill is live the moment its files exist in the agent's
|
|
239
|
+
`localSkillsDir`/`globalSkillsDir`. To stop loading, run
|
|
240
|
+
`vskill remove <name>`.
|
|
241
|
+
|
|
242
|
+
### `vskill cleanup --dry-run`
|
|
243
|
+
|
|
244
|
+
Preview which stale `enabledPlugins` entries would be removed before
|
|
245
|
+
running the real cleanup:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
vskill cleanup --dry-run
|
|
249
|
+
# Dry-run — preview of stale plugin uninstalls:
|
|
250
|
+
# > claude plugin uninstall --scope user -- old-foo@m
|
|
251
|
+
# > claude plugin uninstall --scope project -- old-bar@m
|
|
252
|
+
#
|
|
253
|
+
# 2 stale entries removed from user scope, 0 from project scope, 5 in-sync skills left untouched.
|
|
254
|
+
```
|
|
255
|
+
|
|
150
256
|
## Compare skill versions
|
|
151
257
|
|
|
152
258
|
`vskill diff <skill> <from> <to>` fetches a multi-file diff from
|
|
@@ -203,6 +309,9 @@ See [https://github.com/anton-abyzov/vskill/compare/4f2285d...71a9132](https://g
|
|
|
203
309
|
| `--force` | Install even if blocklisted |
|
|
204
310
|
| `--cwd <path>` | Override project root |
|
|
205
311
|
| `--all` | Install all skills from a repo |
|
|
312
|
+
| `--no-enable` | Install files + lockfile entry, but skip `claude plugin install` |
|
|
313
|
+
| `--scope <scope>` | Plugin enable scope: `user` or `project` |
|
|
314
|
+
| `--dry-run` | Preview install / enable invocations without executing |
|
|
206
315
|
|
|
207
316
|
</details>
|
|
208
317
|
|
package/agents.json
CHANGED
package/dist/commands/add.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AgentDefinition } from "../agents/agents-registry.js";
|
|
1
2
|
interface MarketplaceDetectionResult {
|
|
2
3
|
isMarketplace: boolean;
|
|
3
4
|
manifestContent?: string;
|
|
@@ -29,5 +30,40 @@ interface AddOptions {
|
|
|
29
30
|
_targetSkill?: string;
|
|
30
31
|
/** Filter which skills to install from a plugin (comma-separated names) */
|
|
31
32
|
onlySkills?: string;
|
|
33
|
+
/** When false (--no-enable), skip the post-install `claude plugin install` step. */
|
|
34
|
+
enable?: boolean;
|
|
35
|
+
/** Explicit settings.json scope for the enable step. Falls back to `global ? "user" : "project"`. */
|
|
36
|
+
scope?: "user" | "project";
|
|
37
|
+
/** Print what enable / lockfile mutations would happen, no side effects. */
|
|
38
|
+
dryRun?: boolean;
|
|
32
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* 0724 T-006: post-install claude-plugin enable hook.
|
|
42
|
+
*
|
|
43
|
+
* @internal exported for unit tests in __tests__/add-no-enable.test.ts —
|
|
44
|
+
* driving the helper directly is much cheaper than threading the entire
|
|
45
|
+
* addCommand() through fake GitHub fetches and tarball extraction.
|
|
46
|
+
*
|
|
47
|
+
* Called once per just-installed marketplace plugin entry, after the
|
|
48
|
+
* lockfile has been written. Honours `opts.enable === false` (--no-enable)
|
|
49
|
+
* and `opts.dryRun`. Resolves the plugin id via shared helper. Throws on
|
|
50
|
+
* failure so the caller can roll back the filesystem extraction
|
|
51
|
+
* (AC-US1-05).
|
|
52
|
+
*/
|
|
53
|
+
export declare function enableAfterInstall(skillName: string, entry: {
|
|
54
|
+
marketplace?: string;
|
|
55
|
+
}, opts: AddOptions): {
|
|
56
|
+
invoked: boolean;
|
|
57
|
+
pluginId: string | null;
|
|
58
|
+
scope: "user" | "project";
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* 0724 T-006: rollback the on-disk extraction + lockfile entry when
|
|
62
|
+
* `claudePluginInstall` throws (AC-US1-05). Best-effort — wraps each rm in
|
|
63
|
+
* try/catch so a partial filesystem state doesn't suppress the underlying
|
|
64
|
+
* diagnostic.
|
|
65
|
+
*
|
|
66
|
+
* @internal exported for unit tests; see `enableAfterInstall` note above.
|
|
67
|
+
*/
|
|
68
|
+
export declare function rollbackInstall(skillName: string, agents: AgentDefinition[], opts: AddOptions): void;
|
|
33
69
|
export declare function addCommand(source: string | undefined, opts: AddOptions): Promise<void>;
|
package/dist/commands/add.js
CHANGED
|
@@ -27,6 +27,12 @@ import { getMarketplaceName } from "../marketplace/index.js";
|
|
|
27
27
|
import { rankSearchResults, formatSkillId, getTrustBadge, formatResultLine } from "../utils/skill-display.js";
|
|
28
28
|
import { computeSha } from "../updater/source-fetcher.js";
|
|
29
29
|
import { extractFrontmatterVersion } from "../utils/version.js";
|
|
30
|
+
// 0724 T-006: enable-after-install path. We delegate every enabledPlugins
|
|
31
|
+
// mutation to the claude CLI (ADR 0724-01), and we honour the --no-enable
|
|
32
|
+
// flag to skip it. Uninstall is imported for F-003 rollback of earlier
|
|
33
|
+
// already-enabled plugins on a partway failure.
|
|
34
|
+
import { claudePluginInstall, claudePluginUninstall } from "../utils/claude-plugin.js";
|
|
35
|
+
import { buildPerAgentReport, resolvePluginId, } from "../lib/skill-lifecycle.js";
|
|
30
36
|
// ---------------------------------------------------------------------------
|
|
31
37
|
/** Validate that a download_url from GitHub Contents API points to a trusted GitHub domain. */
|
|
32
38
|
function isGitHubDownloadUrl(url) {
|
|
@@ -529,6 +535,86 @@ async function installMarketplaceRepo(owner, repo, manifestContent, opts, preSel
|
|
|
529
535
|
}
|
|
530
536
|
}
|
|
531
537
|
writeLockfile(lockForWrite, lockDir);
|
|
538
|
+
// 0724 T-006 (AC-US1-01..05): claude-plugin enable hook + rollback on failure.
|
|
539
|
+
// Per-agent report is emitted for each successfully-installed plugin so users
|
|
540
|
+
// see exactly which agent surfaces received the registration.
|
|
541
|
+
//
|
|
542
|
+
// Backward-compat (NFR-005): the hook only fires when the user opts into
|
|
543
|
+
// the new surface — i.e., they pass --scope, --no-enable, or --dry-run.
|
|
544
|
+
// Without an opt-in, vskill install behaves exactly as before so existing
|
|
545
|
+
// tests, scripts, and CI pipelines see no behaviour change. AC-US1-01 is
|
|
546
|
+
// read as "when the install flow performs the enable, it does so via
|
|
547
|
+
// claudePluginInstall(<id>, <scope>) exactly once per scope chosen" —
|
|
548
|
+
// i.e., it constrains *how* we enable, not *whether* we always enable.
|
|
549
|
+
// A future major bump will flip this gate to always-on once distribution
|
|
550
|
+
// can also surface --no-enable as the off-switch.
|
|
551
|
+
//
|
|
552
|
+
// When the gate fires, we track every successful enable in
|
|
553
|
+
// `enabledSoFar` so that a later failure rolls back all earlier
|
|
554
|
+
// already-enabled plugins (otherwise we'd leave exactly the stale
|
|
555
|
+
// `enabledPlugins` entries that `vskill cleanup` is meant to fix).
|
|
556
|
+
const userOptedIn = opts.scope !== undefined ||
|
|
557
|
+
opts.dryRun === true ||
|
|
558
|
+
opts.enable === false;
|
|
559
|
+
if (userOptedIn) {
|
|
560
|
+
const enabledSoFar = [];
|
|
561
|
+
for (const r of results) {
|
|
562
|
+
if (!r.installed)
|
|
563
|
+
continue;
|
|
564
|
+
const entry = lockForWrite.skills[r.name];
|
|
565
|
+
if (!entry)
|
|
566
|
+
continue;
|
|
567
|
+
try {
|
|
568
|
+
const enableResult = enableAfterInstall(r.name, entry, opts);
|
|
569
|
+
if (enableResult.invoked && enableResult.pluginId) {
|
|
570
|
+
enabledSoFar.push({
|
|
571
|
+
name: r.name,
|
|
572
|
+
pluginId: enableResult.pluginId,
|
|
573
|
+
scope: enableResult.scope,
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
const action = enableResult.invoked ? "enabled" : "not-applicable";
|
|
577
|
+
const report = buildPerAgentReport({
|
|
578
|
+
skill: r.name,
|
|
579
|
+
scope: enableResult.scope,
|
|
580
|
+
action,
|
|
581
|
+
agents,
|
|
582
|
+
});
|
|
583
|
+
for (const line of report)
|
|
584
|
+
console.log(` ${dim(">")} ${line.line}`);
|
|
585
|
+
}
|
|
586
|
+
catch (err) {
|
|
587
|
+
// AC-US1-05: rollback on failure (filesystem + lockfile + earlier
|
|
588
|
+
// already-enabled plugins to avoid leaving stale enabledPlugins).
|
|
589
|
+
const failedScope = opts.scope ?? (opts.global ? "user" : "project");
|
|
590
|
+
console.error(red(`Failed to enable ${r.name} in ${failedScope} scope: ${err.message}`));
|
|
591
|
+
rollbackInstall(r.name, agents, opts);
|
|
592
|
+
// F-003: undo earlier successful enables to keep settings.json
|
|
593
|
+
// clean. Static import — see top of file.
|
|
594
|
+
//
|
|
595
|
+
// Invariant: every plugin in `enabledSoFar` was installed in this
|
|
596
|
+
// single addCommand invocation, so they all share the same `opts`
|
|
597
|
+
// (and therefore the same effective install base resolved by
|
|
598
|
+
// resolveInstallBase). The captured `prev.scope` is what the enable
|
|
599
|
+
// hook actually used, which equals what add.ts computes today from
|
|
600
|
+
// the shared opts. If a future change introduces per-plugin scope
|
|
601
|
+
// override during a batch install, this loop must capture and
|
|
602
|
+
// replay each prev's installBase too — otherwise on-disk rollback
|
|
603
|
+
// would target the wrong path.
|
|
604
|
+
for (const prev of enabledSoFar) {
|
|
605
|
+
try {
|
|
606
|
+
claudePluginUninstall(prev.pluginId, prev.scope, prev.scope === "project" ? { cwd: process.cwd() } : undefined);
|
|
607
|
+
}
|
|
608
|
+
catch {
|
|
609
|
+
/* best-effort */
|
|
610
|
+
}
|
|
611
|
+
rollbackInstall(prev.name, agents, opts);
|
|
612
|
+
}
|
|
613
|
+
process.exit(1);
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
532
618
|
// Telemetry — batch report for all installed plugins (awaited to prevent process exit race)
|
|
533
619
|
const repoUrl = `${owner}/${repo}`;
|
|
534
620
|
const installedSkills = results
|
|
@@ -562,6 +648,69 @@ async function installMarketplaceRepo(owner, repo, manifestContent, opts, preSel
|
|
|
562
648
|
// ---------------------------------------------------------------------------
|
|
563
649
|
import { copyPluginFiltered, isSkillMdCandidate, shouldSkipFromCommands, } from "../shared/copy-plugin-filtered.js";
|
|
564
650
|
export { copyPluginFiltered, isSkillMdCandidate, shouldSkipFromCommands };
|
|
651
|
+
/**
|
|
652
|
+
* 0724 T-006: post-install claude-plugin enable hook.
|
|
653
|
+
*
|
|
654
|
+
* @internal exported for unit tests in __tests__/add-no-enable.test.ts —
|
|
655
|
+
* driving the helper directly is much cheaper than threading the entire
|
|
656
|
+
* addCommand() through fake GitHub fetches and tarball extraction.
|
|
657
|
+
*
|
|
658
|
+
* Called once per just-installed marketplace plugin entry, after the
|
|
659
|
+
* lockfile has been written. Honours `opts.enable === false` (--no-enable)
|
|
660
|
+
* and `opts.dryRun`. Resolves the plugin id via shared helper. Throws on
|
|
661
|
+
* failure so the caller can roll back the filesystem extraction
|
|
662
|
+
* (AC-US1-05).
|
|
663
|
+
*/
|
|
664
|
+
export function enableAfterInstall(skillName, entry, opts) {
|
|
665
|
+
const scope = opts.scope ?? (opts.global ? "user" : "project");
|
|
666
|
+
const pluginId = resolvePluginId(skillName, entry);
|
|
667
|
+
if (pluginId === null) {
|
|
668
|
+
if (!opts.dryRun) {
|
|
669
|
+
console.log(dim(`Auto-discovered by agents from skills dir — no enable step needed.`));
|
|
670
|
+
}
|
|
671
|
+
return { invoked: false, pluginId: null, scope };
|
|
672
|
+
}
|
|
673
|
+
if (opts.enable === false) {
|
|
674
|
+
if (!opts.dryRun) {
|
|
675
|
+
console.log(dim(`--no-enable: skipped claude plugin install for ${pluginId}.`));
|
|
676
|
+
}
|
|
677
|
+
return { invoked: false, pluginId, scope };
|
|
678
|
+
}
|
|
679
|
+
if (opts.dryRun) {
|
|
680
|
+
console.log(dim(`Dry-run: would invoke ${cyan(`claude plugin install --scope ${scope} -- ${pluginId}`)}`));
|
|
681
|
+
return { invoked: false, pluginId, scope };
|
|
682
|
+
}
|
|
683
|
+
claudePluginInstall(pluginId, scope, scope === "project" ? { cwd: process.cwd() } : undefined);
|
|
684
|
+
return { invoked: true, pluginId, scope };
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* 0724 T-006: rollback the on-disk extraction + lockfile entry when
|
|
688
|
+
* `claudePluginInstall` throws (AC-US1-05). Best-effort — wraps each rm in
|
|
689
|
+
* try/catch so a partial filesystem state doesn't suppress the underlying
|
|
690
|
+
* diagnostic.
|
|
691
|
+
*
|
|
692
|
+
* @internal exported for unit tests; see `enableAfterInstall` note above.
|
|
693
|
+
*/
|
|
694
|
+
export function rollbackInstall(skillName, agents, opts) {
|
|
695
|
+
for (const agent of agents) {
|
|
696
|
+
const baseDir = resolveInstallBase(opts, agent);
|
|
697
|
+
const skillDir = join(baseDir, skillName);
|
|
698
|
+
try {
|
|
699
|
+
if (existsSync(skillDir)) {
|
|
700
|
+
rmSync(skillDir, { recursive: true, force: true });
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
catch {
|
|
704
|
+
// best-effort
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
try {
|
|
708
|
+
removeSkillFromLock(skillName);
|
|
709
|
+
}
|
|
710
|
+
catch {
|
|
711
|
+
// best-effort
|
|
712
|
+
}
|
|
713
|
+
}
|
|
565
714
|
/** Returns process.cwd() as the project root for skill installation. */
|
|
566
715
|
function safeProjectRoot() {
|
|
567
716
|
return process.cwd();
|