skpm-cli 1.4.7 → 1.5.0
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 +81 -57
- package/dist/cli.mjs +337 -66
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,37 +1,60 @@
|
|
|
1
|
-
#
|
|
1
|
+
# skpm
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The Skill Package Manager for AI agents. Fork of [vercel-labs/skills](https://github.com/vercel-labs/skills) with **dependency graph resolution**.
|
|
4
4
|
|
|
5
5
|
<!-- agent-list:start -->
|
|
6
|
-
Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [40 more](#
|
|
6
|
+
Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [40 more](#supported-agents).
|
|
7
7
|
<!-- agent-list:end -->
|
|
8
8
|
|
|
9
|
+
## What's different from `skills`?
|
|
10
|
+
|
|
11
|
+
- **`dependsOn`** — Skills declare dependencies in SKILL.md frontmatter. `skpm add` recursively installs the full tree.
|
|
12
|
+
- **`postInstall`** — Skills can declare setup commands (CLI installs, config). Printed with y/n prompt before execution.
|
|
13
|
+
- **`--trust-scripts`** — Auto-accept postInstall commands (for CI/CD).
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm i -g skpm-cli # global install (recommended)
|
|
19
|
+
skpm add owner/repo@skill -g
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or use without installing:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx skpm-cli add owner/repo@skill -g
|
|
26
|
+
```
|
|
27
|
+
|
|
9
28
|
## Install a Skill
|
|
10
29
|
|
|
11
30
|
```bash
|
|
12
|
-
|
|
31
|
+
skpm add jonmumm/skills@swarm -g
|
|
32
|
+
# → automatically installs grill-me, mutation-testing, tdd
|
|
13
33
|
```
|
|
14
34
|
|
|
15
35
|
### Source Formats
|
|
16
36
|
|
|
17
37
|
```bash
|
|
18
38
|
# GitHub shorthand (owner/repo)
|
|
19
|
-
|
|
39
|
+
skpm add jonmumm/skills
|
|
40
|
+
|
|
41
|
+
# Install a specific skill with auto-resolved dependencies
|
|
42
|
+
skpm add jonmumm/skills@swarm
|
|
20
43
|
|
|
21
44
|
# Full GitHub URL
|
|
22
|
-
|
|
45
|
+
skpm add https://github.com/jonmumm/skills
|
|
23
46
|
|
|
24
47
|
# Direct path to a skill in a repo
|
|
25
|
-
|
|
48
|
+
skpm add https://github.com/jonmumm/skills/tree/main/skills/tdd
|
|
26
49
|
|
|
27
50
|
# GitLab URL
|
|
28
|
-
|
|
51
|
+
skpm add https://gitlab.com/org/repo
|
|
29
52
|
|
|
30
53
|
# Any git URL
|
|
31
|
-
|
|
54
|
+
skpm add git@github.com:owner/repo.git
|
|
32
55
|
|
|
33
56
|
# Local path
|
|
34
|
-
|
|
57
|
+
skpm add ./my-local-skills
|
|
35
58
|
```
|
|
36
59
|
|
|
37
60
|
### Options
|
|
@@ -49,29 +72,26 @@ npx skills add ./my-local-skills
|
|
|
49
72
|
### Examples
|
|
50
73
|
|
|
51
74
|
```bash
|
|
75
|
+
# Install a skill (dependencies auto-resolved)
|
|
76
|
+
skpm add jonmumm/skills@swarm -g
|
|
77
|
+
|
|
52
78
|
# List skills in a repository
|
|
53
|
-
|
|
79
|
+
skpm add jonmumm/skills --list
|
|
54
80
|
|
|
55
81
|
# Install specific skills
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
# Install a skill with spaces in the name (must be quoted)
|
|
59
|
-
npx skills add owner/repo --skill "Convex Best Practices"
|
|
82
|
+
skpm add jonmumm/skills --skill swarm --skill tdd
|
|
60
83
|
|
|
61
84
|
# Install to specific agents
|
|
62
|
-
|
|
85
|
+
skpm add jonmumm/skills -a claude-code -a opencode
|
|
63
86
|
|
|
64
87
|
# Non-interactive installation (CI/CD friendly)
|
|
65
|
-
|
|
88
|
+
skpm add jonmumm/skills --skill swarm -g -a claude-code -y
|
|
66
89
|
|
|
67
90
|
# Install all skills from a repo to all agents
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
# Install all skills to specific agents
|
|
71
|
-
npx skills add vercel-labs/agent-skills --skill '*' -a claude-code
|
|
91
|
+
skpm add jonmumm/skills --all
|
|
72
92
|
|
|
73
|
-
#
|
|
74
|
-
|
|
93
|
+
# Auto-accept postInstall commands (CI/CD)
|
|
94
|
+
skpm add jonmumm/skills@swarm -g -y --trust-scripts
|
|
75
95
|
```
|
|
76
96
|
|
|
77
97
|
### Installation Scope
|
|
@@ -94,12 +114,12 @@ When installing interactively, you can choose:
|
|
|
94
114
|
|
|
95
115
|
| Command | Description |
|
|
96
116
|
| ---------------------------- | ---------------------------------------------- |
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
117
|
+
| `skpm list` | List installed skills (alias: `ls`) |
|
|
118
|
+
| `skpm find [query]` | Search for skills interactively or by keyword |
|
|
119
|
+
| `skpm remove [skills]` | Remove installed skills from agents |
|
|
120
|
+
| `skpm check` | Check for available skill updates |
|
|
121
|
+
| `skpm update` | Update all installed skills to latest versions |
|
|
122
|
+
| `skpm init [name]` | Create a new SKILL.md template |
|
|
103
123
|
|
|
104
124
|
### `skills list`
|
|
105
125
|
|
|
@@ -107,13 +127,13 @@ List all installed skills. Similar to `npm ls`.
|
|
|
107
127
|
|
|
108
128
|
```bash
|
|
109
129
|
# List all installed skills (project and global)
|
|
110
|
-
|
|
130
|
+
skpm list
|
|
111
131
|
|
|
112
132
|
# List only global skills
|
|
113
|
-
|
|
133
|
+
skpm ls -g
|
|
114
134
|
|
|
115
135
|
# Filter by specific agents
|
|
116
|
-
|
|
136
|
+
skpm ls -a claude-code -a cursor
|
|
117
137
|
```
|
|
118
138
|
|
|
119
139
|
### `skills find`
|
|
@@ -122,30 +142,30 @@ Search for skills interactively or by keyword.
|
|
|
122
142
|
|
|
123
143
|
```bash
|
|
124
144
|
# Interactive search (fzf-style)
|
|
125
|
-
|
|
145
|
+
skpm find
|
|
126
146
|
|
|
127
147
|
# Search by keyword
|
|
128
|
-
|
|
148
|
+
skpm find typescript
|
|
129
149
|
```
|
|
130
150
|
|
|
131
151
|
### `skills check` / `skills update`
|
|
132
152
|
|
|
133
153
|
```bash
|
|
134
154
|
# Check if any installed skills have updates
|
|
135
|
-
|
|
155
|
+
skpm check
|
|
136
156
|
|
|
137
157
|
# Update all skills to latest versions
|
|
138
|
-
|
|
158
|
+
skpm update
|
|
139
159
|
```
|
|
140
160
|
|
|
141
161
|
### `skills init`
|
|
142
162
|
|
|
143
163
|
```bash
|
|
144
164
|
# Create SKILL.md in current directory
|
|
145
|
-
|
|
165
|
+
skpm init
|
|
146
166
|
|
|
147
167
|
# Create a new skill in a subdirectory
|
|
148
|
-
|
|
168
|
+
skpm init my-skill
|
|
149
169
|
```
|
|
150
170
|
|
|
151
171
|
### `skills remove`
|
|
@@ -154,31 +174,31 @@ Remove installed skills from agents.
|
|
|
154
174
|
|
|
155
175
|
```bash
|
|
156
176
|
# Remove interactively (select from installed skills)
|
|
157
|
-
|
|
177
|
+
skpm remove
|
|
158
178
|
|
|
159
179
|
# Remove specific skill by name
|
|
160
|
-
|
|
180
|
+
skpm remove web-design-guidelines
|
|
161
181
|
|
|
162
182
|
# Remove multiple skills
|
|
163
|
-
|
|
183
|
+
skpm remove frontend-design web-design-guidelines
|
|
164
184
|
|
|
165
185
|
# Remove from global scope
|
|
166
|
-
|
|
186
|
+
skpm remove --global web-design-guidelines
|
|
167
187
|
|
|
168
188
|
# Remove from specific agents only
|
|
169
|
-
|
|
189
|
+
skpm remove --agent claude-code cursor my-skill
|
|
170
190
|
|
|
171
191
|
# Remove all installed skills without confirmation
|
|
172
|
-
|
|
192
|
+
skpm remove --all
|
|
173
193
|
|
|
174
194
|
# Remove all skills from a specific agent
|
|
175
|
-
|
|
195
|
+
skpm remove --skill '*' -a cursor
|
|
176
196
|
|
|
177
197
|
# Remove a specific skill from all agents
|
|
178
|
-
|
|
198
|
+
skpm remove my-skill --agent '*'
|
|
179
199
|
|
|
180
200
|
# Use 'rm' alias
|
|
181
|
-
|
|
201
|
+
skpm rm my-skill
|
|
182
202
|
```
|
|
183
203
|
|
|
184
204
|
| Option | Description |
|
|
@@ -200,7 +220,7 @@ Skills let agents perform specialized tasks like:
|
|
|
200
220
|
- Creating PRs following your team's conventions
|
|
201
221
|
- Integrating with external tools (Linear, Notion, etc.)
|
|
202
222
|
|
|
203
|
-
Discover skills at **[
|
|
223
|
+
Discover skills at **[skpm.sh](https://skpm.sh)**
|
|
204
224
|
|
|
205
225
|
## Supported Agents
|
|
206
226
|
|
|
@@ -295,16 +315,19 @@ Describe the scenarios where this skill should be used.
|
|
|
295
315
|
|
|
296
316
|
### Optional Fields
|
|
297
317
|
|
|
298
|
-
- `
|
|
299
|
-
|
|
300
|
-
|
|
318
|
+
- `dependsOn`: Array of skill dependencies in `owner/repo@skill-name` format. Resolved recursively on install.
|
|
319
|
+
- `postInstall`: Array of shell commands to run after installation. Printed with y/n prompt (or auto-accepted with `--trust-scripts`).
|
|
320
|
+
- `metadata.internal`: Set to `true` to hide the skill from normal discovery.
|
|
301
321
|
|
|
302
322
|
```markdown
|
|
303
323
|
---
|
|
304
|
-
name: my-
|
|
305
|
-
description:
|
|
306
|
-
|
|
307
|
-
|
|
324
|
+
name: my-skill
|
|
325
|
+
description: My skill that depends on others
|
|
326
|
+
dependsOn:
|
|
327
|
+
- jonmumm/skills@grill-me
|
|
328
|
+
- mattpocock/skills@tdd
|
|
329
|
+
postInstall:
|
|
330
|
+
- "which linear || pnpm i -g @linear/cli"
|
|
308
331
|
---
|
|
309
332
|
```
|
|
310
333
|
|
|
@@ -410,7 +433,7 @@ Ensure you have write access to the target directory.
|
|
|
410
433
|
|
|
411
434
|
```bash
|
|
412
435
|
# Install internal skills
|
|
413
|
-
INSTALL_INTERNAL_SKILLS=1
|
|
436
|
+
INSTALL_INTERNAL_SKILLS=1 skpm add owner/repo --list
|
|
414
437
|
```
|
|
415
438
|
|
|
416
439
|
## Telemetry
|
|
@@ -422,7 +445,7 @@ Telemetry is automatically disabled in CI environments.
|
|
|
422
445
|
## Related Links
|
|
423
446
|
|
|
424
447
|
- [Agent Skills Specification](https://agentskills.io)
|
|
425
|
-
- [Skills Directory](https://
|
|
448
|
+
- [Skills Directory](https://skpm.sh)
|
|
426
449
|
- [Amp Skills Documentation](https://ampcode.com/manual#agent-skills)
|
|
427
450
|
- [Antigravity Skills Documentation](https://antigravity.google/docs/skills)
|
|
428
451
|
- [Factory AI / Droid Skills Documentation](https://docs.factory.ai/cli/configuration/skills)
|
|
@@ -449,6 +472,7 @@ Telemetry is automatically disabled in CI environments.
|
|
|
449
472
|
- [Replit Skills Documentation](https://docs.replit.com/replitai/skills)
|
|
450
473
|
- [Roo Code Skills Documentation](https://docs.roocode.com/features/skills)
|
|
451
474
|
- [Trae Skills Documentation](https://docs.trae.ai/ide/skills)
|
|
475
|
+
- [skpm CLI](https://github.com/skpm-sh/cli)
|
|
452
476
|
- [Vercel Agent Skills Repository](https://github.com/vercel-labs/agent-skills)
|
|
453
477
|
|
|
454
478
|
## License
|
package/dist/cli.mjs
CHANGED
|
@@ -1900,7 +1900,7 @@ function createEmptyLocalLock() {
|
|
|
1900
1900
|
skills: {}
|
|
1901
1901
|
};
|
|
1902
1902
|
}
|
|
1903
|
-
var version$1 = "1.
|
|
1903
|
+
var version$1 = "1.5.0";
|
|
1904
1904
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
1905
1905
|
async function isSourcePrivate(source) {
|
|
1906
1906
|
const ownerRepo = parseOwnerRepo(source);
|
|
@@ -2363,7 +2363,7 @@ async function runAdd(args, options = {}) {
|
|
|
2363
2363
|
console.log(` ${import_picocolors.default.cyan("npx skpm-cli add")} ${import_picocolors.default.yellow("<source>")} ${import_picocolors.default.dim("[options]")}`);
|
|
2364
2364
|
console.log();
|
|
2365
2365
|
console.log(import_picocolors.default.dim(" Example:"));
|
|
2366
|
-
console.log(` ${import_picocolors.default.cyan("npx skpm-cli add")} ${import_picocolors.default.yellow("
|
|
2366
|
+
console.log(` ${import_picocolors.default.cyan("npx skpm-cli add")} ${import_picocolors.default.yellow("owner/repo")}`);
|
|
2367
2367
|
console.log();
|
|
2368
2368
|
process.exit(1);
|
|
2369
2369
|
}
|
|
@@ -2824,37 +2824,86 @@ async function runAdd(args, options = {}) {
|
|
|
2824
2824
|
for (const r of failed) M.message(` ${import_picocolors.default.red("✗")} ${r.skill} → ${r.agent}: ${import_picocolors.default.dim(r.error)}`);
|
|
2825
2825
|
}
|
|
2826
2826
|
const allPostInstallCommands = [];
|
|
2827
|
+
const depFailures = [];
|
|
2828
|
+
const sharedResolved = /* @__PURE__ */ new Set();
|
|
2829
|
+
const depCloneCache = /* @__PURE__ */ new Map();
|
|
2830
|
+
const depTempDirs = /* @__PURE__ */ new Set();
|
|
2831
|
+
if (tempDir && normalizedSource) depCloneCache.set(parsed.url, tempDir);
|
|
2827
2832
|
for (const skill of selectedSkills) {
|
|
2828
2833
|
if (skill.postInstall.length > 0) allPostInstallCommands.push(...skill.postInstall);
|
|
2829
2834
|
if (skill.dependsOn.length > 0) {
|
|
2830
2835
|
M.info(import_picocolors.default.dim(`Resolving dependencies for ${skill.name}...`));
|
|
2831
|
-
const depResult = await resolveDependencies(skill, async (
|
|
2832
|
-
const depSource = skillName ? `${
|
|
2836
|
+
const depResult = await resolveDependencies(skill, async (depSourceStr, skillName) => {
|
|
2837
|
+
const depSource = skillName ? `${depSourceStr}@${skillName}` : depSourceStr;
|
|
2833
2838
|
M.step(import_picocolors.default.dim(` Installing dependency: ${depSource}`));
|
|
2834
|
-
const
|
|
2835
|
-
let
|
|
2839
|
+
const depParsed = parseSource(depSourceStr);
|
|
2840
|
+
let depDir;
|
|
2836
2841
|
try {
|
|
2837
|
-
if (
|
|
2838
|
-
else
|
|
2839
|
-
|
|
2842
|
+
if (depParsed.type === "local") depDir = depParsed.localPath;
|
|
2843
|
+
else {
|
|
2844
|
+
const cacheKey = depParsed.url;
|
|
2845
|
+
if (depCloneCache.has(cacheKey)) depDir = depCloneCache.get(cacheKey);
|
|
2846
|
+
else {
|
|
2847
|
+
depDir = await cloneRepo(depParsed.url, depParsed.ref);
|
|
2848
|
+
depCloneCache.set(cacheKey, depDir);
|
|
2849
|
+
depTempDirs.add(depDir);
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
const depSkills = await discoverSkills(depDir, depParsed.subpath, { includeInternal: true });
|
|
2840
2853
|
const targetSkills = skillName ? depSkills.filter((s) => s.name.toLowerCase() === skillName.toLowerCase()) : depSkills;
|
|
2841
2854
|
if (targetSkills.length === 0) {
|
|
2842
2855
|
M.warn(import_picocolors.default.yellow(` Dependency skill not found: ${depSource}`));
|
|
2843
2856
|
return [];
|
|
2844
2857
|
}
|
|
2845
|
-
for (const depSkill of targetSkills)
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2858
|
+
for (const depSkill of targetSkills) {
|
|
2859
|
+
for (const agent of targetAgents) {
|
|
2860
|
+
const depInstallResult = await installSkillForAgent(depSkill, agent, {
|
|
2861
|
+
global: installGlobally,
|
|
2862
|
+
mode: installMode
|
|
2863
|
+
});
|
|
2864
|
+
if (!depInstallResult.success) depFailures.push({
|
|
2865
|
+
skill: depSkill.name,
|
|
2866
|
+
agent: agents[agent].displayName,
|
|
2867
|
+
error: depInstallResult.error
|
|
2868
|
+
});
|
|
2869
|
+
}
|
|
2870
|
+
if (installGlobally) try {
|
|
2871
|
+
const depNormalizedSource = getOwnerRepo(depParsed);
|
|
2872
|
+
let depSkillPath;
|
|
2873
|
+
if (depDir && depSkill.path.startsWith(depDir + sep)) depSkillPath = depSkill.path.slice(depDir.length + 1).split(sep).join("/") + "/SKILL.md";
|
|
2874
|
+
else if (depDir && depSkill.path === depDir) depSkillPath = "SKILL.md";
|
|
2875
|
+
let depFolderHash = "";
|
|
2876
|
+
if (depParsed.type === "github" && depSkillPath && depNormalizedSource) {
|
|
2877
|
+
const token = getGitHubToken();
|
|
2878
|
+
const hash = await fetchSkillFolderHash(depNormalizedSource, depSkillPath, token);
|
|
2879
|
+
if (hash) depFolderHash = hash;
|
|
2880
|
+
}
|
|
2881
|
+
const depLockSource = depParsed.url.startsWith("git@") ? depParsed.url : depNormalizedSource || depParsed.url;
|
|
2882
|
+
await addSkillToLock(depSkill.name, {
|
|
2883
|
+
source: depLockSource,
|
|
2884
|
+
sourceType: depParsed.type,
|
|
2885
|
+
sourceUrl: depParsed.url,
|
|
2886
|
+
skillPath: depSkillPath,
|
|
2887
|
+
skillFolderHash: depFolderHash,
|
|
2888
|
+
pluginName: depSkill.pluginName
|
|
2889
|
+
});
|
|
2890
|
+
} catch {}
|
|
2891
|
+
}
|
|
2849
2892
|
return targetSkills;
|
|
2850
|
-
}
|
|
2851
|
-
|
|
2893
|
+
} catch (err) {
|
|
2894
|
+
throw err;
|
|
2852
2895
|
}
|
|
2853
|
-
}, (warning) => M.warn(import_picocolors.default.yellow(warning)));
|
|
2896
|
+
}, (warning) => M.warn(import_picocolors.default.yellow(warning)), sharedResolved);
|
|
2854
2897
|
allPostInstallCommands.push(...depResult.postInstallCommands);
|
|
2855
2898
|
if (depResult.errors.length > 0) for (const err of depResult.errors) M.warn(import_picocolors.default.yellow(`Dependency ${err.ref}: ${err.error}`));
|
|
2856
2899
|
}
|
|
2857
2900
|
}
|
|
2901
|
+
for (const dir of depTempDirs) await cleanupTempDir(dir).catch(() => {});
|
|
2902
|
+
if (depFailures.length > 0) {
|
|
2903
|
+
console.log();
|
|
2904
|
+
M.error(import_picocolors.default.red(`Failed to install ${depFailures.length} dependency(ies)`));
|
|
2905
|
+
for (const f of depFailures) M.message(` ${import_picocolors.default.red("✗")} ${f.skill} → ${f.agent}${f.error ? `: ${import_picocolors.default.dim(f.error)}` : ""}`);
|
|
2906
|
+
}
|
|
2858
2907
|
if (allPostInstallCommands.length > 0) {
|
|
2859
2908
|
console.log();
|
|
2860
2909
|
M.info("Post-install commands required:");
|
|
@@ -2912,7 +2961,7 @@ async function promptForFindSkills(options, targetAgents) {
|
|
|
2912
2961
|
console.log();
|
|
2913
2962
|
M.step("Installing find-skills skill...");
|
|
2914
2963
|
try {
|
|
2915
|
-
await runAdd(["
|
|
2964
|
+
await runAdd(["skpm-sh/skills"], {
|
|
2916
2965
|
skill: ["find-skills"],
|
|
2917
2966
|
global: true,
|
|
2918
2967
|
yes: true,
|
|
@@ -2920,11 +2969,11 @@ async function promptForFindSkills(options, targetAgents) {
|
|
|
2920
2969
|
});
|
|
2921
2970
|
} catch {
|
|
2922
2971
|
M.warn("Failed to install find-skills. You can try again with:");
|
|
2923
|
-
M.message(import_picocolors.default.dim(" npx skpm-cli add
|
|
2972
|
+
M.message(import_picocolors.default.dim(" npx skpm-cli add skpm-sh/skills@find-skills -g -y --all"));
|
|
2924
2973
|
}
|
|
2925
2974
|
} else {
|
|
2926
2975
|
await dismissPrompt("findSkillsPrompt");
|
|
2927
|
-
M.message(import_picocolors.default.dim("You can install it later with: npx skpm-cli add
|
|
2976
|
+
M.message(import_picocolors.default.dim("You can install it later with: npx skpm-cli add skpm-sh/skills@find-skills"));
|
|
2928
2977
|
}
|
|
2929
2978
|
} catch {}
|
|
2930
2979
|
}
|
|
@@ -2967,10 +3016,10 @@ function parseAddOptions(args) {
|
|
|
2967
3016
|
options
|
|
2968
3017
|
};
|
|
2969
3018
|
}
|
|
2970
|
-
const RESET$
|
|
2971
|
-
const BOLD$
|
|
2972
|
-
const DIM$
|
|
2973
|
-
const TEXT$
|
|
3019
|
+
const RESET$4 = "\x1B[0m";
|
|
3020
|
+
const BOLD$4 = "\x1B[1m";
|
|
3021
|
+
const DIM$4 = "\x1B[38;5;102m";
|
|
3022
|
+
const TEXT$3 = "\x1B[38;5;145m";
|
|
2974
3023
|
const CYAN$1 = "\x1B[36m";
|
|
2975
3024
|
const SEARCH_API_BASE = process.env.SKPM_API_URL || "https://skpm.sh";
|
|
2976
3025
|
function formatInstalls(count) {
|
|
@@ -3014,28 +3063,28 @@ async function runSearchPrompt(initialQuery = "") {
|
|
|
3014
3063
|
if (lastRenderedLines > 0) process.stdout.write(MOVE_UP(lastRenderedLines) + MOVE_TO_COL(1));
|
|
3015
3064
|
process.stdout.write(CLEAR_DOWN);
|
|
3016
3065
|
const lines = [];
|
|
3017
|
-
const cursor = `${BOLD$
|
|
3018
|
-
lines.push(`${TEXT$
|
|
3066
|
+
const cursor = `${BOLD$4}_${RESET$4}`;
|
|
3067
|
+
lines.push(`${TEXT$3}Search skills:${RESET$4} ${query}${cursor}`);
|
|
3019
3068
|
lines.push("");
|
|
3020
|
-
if (!query || query.length < 2) lines.push(`${DIM$
|
|
3021
|
-
else if (results.length === 0 && loading) lines.push(`${DIM$
|
|
3022
|
-
else if (results.length === 0) lines.push(`${DIM$
|
|
3069
|
+
if (!query || query.length < 2) lines.push(`${DIM$4}Start typing to search (min 2 chars)${RESET$4}`);
|
|
3070
|
+
else if (results.length === 0 && loading) lines.push(`${DIM$4}Searching...${RESET$4}`);
|
|
3071
|
+
else if (results.length === 0) lines.push(`${DIM$4}No skills found${RESET$4}`);
|
|
3023
3072
|
else {
|
|
3024
3073
|
const visible = results.slice(0, 8);
|
|
3025
3074
|
for (let i = 0; i < visible.length; i++) {
|
|
3026
3075
|
const skill = visible[i];
|
|
3027
3076
|
const isSelected = i === selectedIndex;
|
|
3028
|
-
const arrow = isSelected ? `${BOLD$
|
|
3029
|
-
const name = isSelected ? `${BOLD$
|
|
3030
|
-
const source = skill.source ? ` ${DIM$
|
|
3077
|
+
const arrow = isSelected ? `${BOLD$4}>${RESET$4}` : " ";
|
|
3078
|
+
const name = isSelected ? `${BOLD$4}${skill.name}${RESET$4}` : `${TEXT$3}${skill.name}${RESET$4}`;
|
|
3079
|
+
const source = skill.source ? ` ${DIM$4}${skill.source}${RESET$4}` : "";
|
|
3031
3080
|
const installs = formatInstalls(skill.installs);
|
|
3032
|
-
const installsBadge = installs ? ` ${CYAN$1}${installs}${RESET$
|
|
3033
|
-
const loadingIndicator = loading && i === 0 ? ` ${DIM$
|
|
3081
|
+
const installsBadge = installs ? ` ${CYAN$1}${installs}${RESET$4}` : "";
|
|
3082
|
+
const loadingIndicator = loading && i === 0 ? ` ${DIM$4}...${RESET$4}` : "";
|
|
3034
3083
|
lines.push(` ${arrow} ${name}${source}${installsBadge}${loadingIndicator}`);
|
|
3035
3084
|
}
|
|
3036
3085
|
}
|
|
3037
3086
|
lines.push("");
|
|
3038
|
-
lines.push(`${DIM$
|
|
3087
|
+
lines.push(`${DIM$4}up/down navigate | enter select | esc cancel${RESET$4}`);
|
|
3039
3088
|
for (const line of lines) process.stdout.write(line + "\n");
|
|
3040
3089
|
lastRenderedLines = lines.length;
|
|
3041
3090
|
}
|
|
@@ -3131,9 +3180,9 @@ async function isRepoPublic(owner, repo) {
|
|
|
3131
3180
|
async function runFind(args) {
|
|
3132
3181
|
const query = args.join(" ");
|
|
3133
3182
|
const isNonInteractive = !process.stdin.isTTY;
|
|
3134
|
-
const agentTip = `${DIM$
|
|
3135
|
-
${DIM$
|
|
3136
|
-
${DIM$
|
|
3183
|
+
const agentTip = `${DIM$4}Tip: if running in a coding agent, follow these steps:${RESET$4}
|
|
3184
|
+
${DIM$4} 1) npx skpm-cli find [query]${RESET$4}
|
|
3185
|
+
${DIM$4} 2) npx skpm-cli add <owner/repo@skill>${RESET$4}`;
|
|
3137
3186
|
if (query) {
|
|
3138
3187
|
const results = await searchSkillsAPI(query);
|
|
3139
3188
|
track({
|
|
@@ -3142,16 +3191,16 @@ ${DIM$2} 2) npx skpm-cli add <owner/repo@skill>${RESET$2}`;
|
|
|
3142
3191
|
resultCount: String(results.length)
|
|
3143
3192
|
});
|
|
3144
3193
|
if (results.length === 0) {
|
|
3145
|
-
console.log(`${DIM$
|
|
3194
|
+
console.log(`${DIM$4}No skills found for "${query}"${RESET$4}`);
|
|
3146
3195
|
return;
|
|
3147
3196
|
}
|
|
3148
|
-
console.log(`${DIM$
|
|
3197
|
+
console.log(`${DIM$4}Install with${RESET$4} npx skpm-cli add <owner/repo@skill>`);
|
|
3149
3198
|
console.log();
|
|
3150
3199
|
for (const skill of results.slice(0, 6)) {
|
|
3151
3200
|
const pkg = skill.source || skill.slug;
|
|
3152
3201
|
const installs = formatInstalls(skill.installs);
|
|
3153
|
-
console.log(`${TEXT$
|
|
3154
|
-
console.log(`${DIM$
|
|
3202
|
+
console.log(`${TEXT$3}${pkg}@${skill.name}${RESET$4}${installs ? ` ${CYAN$1}${installs}${RESET$4}` : ""}`);
|
|
3203
|
+
console.log(`${DIM$4}└ https://skpm.sh/${skill.slug}${RESET$4}`);
|
|
3155
3204
|
console.log();
|
|
3156
3205
|
}
|
|
3157
3206
|
return;
|
|
@@ -3168,14 +3217,14 @@ ${DIM$2} 2) npx skpm-cli add <owner/repo@skill>${RESET$2}`;
|
|
|
3168
3217
|
interactive: "1"
|
|
3169
3218
|
});
|
|
3170
3219
|
if (!selected) {
|
|
3171
|
-
console.log(`${DIM$
|
|
3220
|
+
console.log(`${DIM$4}Search cancelled${RESET$4}`);
|
|
3172
3221
|
console.log();
|
|
3173
3222
|
return;
|
|
3174
3223
|
}
|
|
3175
3224
|
const pkg = selected.source || selected.slug;
|
|
3176
3225
|
const skillName = selected.name;
|
|
3177
3226
|
console.log();
|
|
3178
|
-
console.log(`${TEXT$
|
|
3227
|
+
console.log(`${TEXT$3}Installing ${BOLD$4}${skillName}${RESET$4} from ${DIM$4}${pkg}${RESET$4}...`);
|
|
3179
3228
|
console.log();
|
|
3180
3229
|
const { source, options } = parseAddOptions([
|
|
3181
3230
|
pkg,
|
|
@@ -3185,8 +3234,8 @@ ${DIM$2} 2) npx skpm-cli add <owner/repo@skill>${RESET$2}`;
|
|
|
3185
3234
|
await runAdd(source, options);
|
|
3186
3235
|
console.log();
|
|
3187
3236
|
const info = getOwnerRepoFromString(pkg);
|
|
3188
|
-
if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$
|
|
3189
|
-
else console.log(`${DIM$
|
|
3237
|
+
if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$4}View the skill at${RESET$4} ${TEXT$3}https://skpm.sh/${selected.slug}${RESET$4}`);
|
|
3238
|
+
else console.log(`${DIM$4}Discover more skills at${RESET$4} ${TEXT$3}https://skpm.sh${RESET$4}`);
|
|
3190
3239
|
console.log();
|
|
3191
3240
|
}
|
|
3192
3241
|
const isCancelled = (value) => typeof value === "symbol";
|
|
@@ -3523,9 +3572,9 @@ async function runInstallFromLock(args) {
|
|
|
3523
3572
|
}
|
|
3524
3573
|
}
|
|
3525
3574
|
}
|
|
3526
|
-
const RESET$
|
|
3527
|
-
const BOLD$
|
|
3528
|
-
const DIM$
|
|
3575
|
+
const RESET$3 = "\x1B[0m";
|
|
3576
|
+
const BOLD$3 = "\x1B[1m";
|
|
3577
|
+
const DIM$3 = "\x1B[38;5;102m";
|
|
3529
3578
|
const CYAN = "\x1B[36m";
|
|
3530
3579
|
const YELLOW = "\x1B[33m";
|
|
3531
3580
|
function shortenPath(fullPath, cwd) {
|
|
@@ -3561,8 +3610,8 @@ async function runList(args) {
|
|
|
3561
3610
|
const validAgents = Object.keys(agents);
|
|
3562
3611
|
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
3563
3612
|
if (invalidAgents.length > 0) {
|
|
3564
|
-
console.log(`${YELLOW}Invalid agents: ${invalidAgents.join(", ")}${RESET$
|
|
3565
|
-
console.log(`${DIM$
|
|
3613
|
+
console.log(`${YELLOW}Invalid agents: ${invalidAgents.join(", ")}${RESET$3}`);
|
|
3614
|
+
console.log(`${DIM$3}Valid agents: ${validAgents.join(", ")}${RESET$3}`);
|
|
3566
3615
|
process.exit(1);
|
|
3567
3616
|
}
|
|
3568
3617
|
agentFilter = options.agent;
|
|
@@ -3589,20 +3638,20 @@ async function runList(args) {
|
|
|
3589
3638
|
console.log("[]");
|
|
3590
3639
|
return;
|
|
3591
3640
|
}
|
|
3592
|
-
console.log(`${DIM$
|
|
3593
|
-
if (scope) console.log(`${DIM$
|
|
3594
|
-
else console.log(`${DIM$
|
|
3641
|
+
console.log(`${DIM$3}No ${scopeLabel.toLowerCase()} skills found.${RESET$3}`);
|
|
3642
|
+
if (scope) console.log(`${DIM$3}Try listing project skills without -g${RESET$3}`);
|
|
3643
|
+
else console.log(`${DIM$3}Try listing global skills with -g${RESET$3}`);
|
|
3595
3644
|
return;
|
|
3596
3645
|
}
|
|
3597
3646
|
function printSkill(skill, indent = false) {
|
|
3598
3647
|
const prefix = indent ? " " : "";
|
|
3599
3648
|
const shortPath = shortenPath(skill.canonicalPath, cwd);
|
|
3600
3649
|
const agentNames = skill.agents.map((a) => agents[a].displayName);
|
|
3601
|
-
const agentInfo = skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW}not linked${RESET$
|
|
3602
|
-
console.log(`${prefix}${CYAN}${skill.name}${RESET$
|
|
3603
|
-
console.log(`${prefix} ${DIM$
|
|
3650
|
+
const agentInfo = skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW}not linked${RESET$3}`;
|
|
3651
|
+
console.log(`${prefix}${CYAN}${skill.name}${RESET$3} ${DIM$3}${shortPath}${RESET$3}`);
|
|
3652
|
+
console.log(`${prefix} ${DIM$3}Agents:${RESET$3} ${agentInfo}`);
|
|
3604
3653
|
}
|
|
3605
|
-
console.log(`${BOLD$
|
|
3654
|
+
console.log(`${BOLD$3}${scopeLabel} Skills${RESET$3}`);
|
|
3606
3655
|
console.log();
|
|
3607
3656
|
const groupedSkills = {};
|
|
3608
3657
|
const ungroupedSkills = [];
|
|
@@ -3618,13 +3667,13 @@ async function runList(args) {
|
|
|
3618
3667
|
const sortedGroups = Object.keys(groupedSkills).sort();
|
|
3619
3668
|
for (const group of sortedGroups) {
|
|
3620
3669
|
const title = group.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3621
|
-
console.log(`${BOLD$
|
|
3670
|
+
console.log(`${BOLD$3}${title}${RESET$3}`);
|
|
3622
3671
|
const skills = groupedSkills[group];
|
|
3623
3672
|
if (skills) for (const skill of skills) printSkill(skill, true);
|
|
3624
3673
|
console.log();
|
|
3625
3674
|
}
|
|
3626
3675
|
if (ungroupedSkills.length > 0) {
|
|
3627
|
-
console.log(`${BOLD$
|
|
3676
|
+
console.log(`${BOLD$3}General${RESET$3}`);
|
|
3628
3677
|
for (const skill of ungroupedSkills) printSkill(skill, true);
|
|
3629
3678
|
console.log();
|
|
3630
3679
|
}
|
|
@@ -3823,6 +3872,218 @@ function parseRemoveOptions(args) {
|
|
|
3823
3872
|
options
|
|
3824
3873
|
};
|
|
3825
3874
|
}
|
|
3875
|
+
const RESET$2 = "\x1B[0m";
|
|
3876
|
+
const BOLD$2 = "\x1B[1m";
|
|
3877
|
+
const DIM$2 = "\x1B[38;5;102m";
|
|
3878
|
+
const TEXT$2 = "\x1B[38;5;145m";
|
|
3879
|
+
async function buildDependencyTree(skill, resolving, cloneCache, tempDirs) {
|
|
3880
|
+
const nodes = [];
|
|
3881
|
+
for (const depRef of skill.dependsOn) {
|
|
3882
|
+
if (resolving.has(depRef)) {
|
|
3883
|
+
nodes.push({
|
|
3884
|
+
name: `${depRef} (circular)`,
|
|
3885
|
+
ref: depRef,
|
|
3886
|
+
children: []
|
|
3887
|
+
});
|
|
3888
|
+
continue;
|
|
3889
|
+
}
|
|
3890
|
+
const parsed = parseDependencyRef(depRef);
|
|
3891
|
+
if (!parsed) {
|
|
3892
|
+
nodes.push({
|
|
3893
|
+
name: `${depRef} (invalid ref)`,
|
|
3894
|
+
ref: depRef,
|
|
3895
|
+
children: []
|
|
3896
|
+
});
|
|
3897
|
+
continue;
|
|
3898
|
+
}
|
|
3899
|
+
resolving.add(depRef);
|
|
3900
|
+
try {
|
|
3901
|
+
const parsedSource = parseSource(parsed.source);
|
|
3902
|
+
let depDir;
|
|
3903
|
+
const cacheKey = parsedSource.url;
|
|
3904
|
+
if (cloneCache.has(cacheKey)) depDir = cloneCache.get(cacheKey);
|
|
3905
|
+
else if (parsedSource.type === "local") depDir = parsedSource.localPath;
|
|
3906
|
+
else {
|
|
3907
|
+
depDir = await cloneRepo(parsedSource.url, parsedSource.ref);
|
|
3908
|
+
tempDirs.add(depDir);
|
|
3909
|
+
cloneCache.set(cacheKey, depDir);
|
|
3910
|
+
}
|
|
3911
|
+
const depSkills = await discoverSkills(depDir, parsedSource.subpath, { includeInternal: true });
|
|
3912
|
+
const targetSkills = parsed.skillName ? depSkills.filter((s) => s.name.toLowerCase() === parsed.skillName.toLowerCase()) : depSkills;
|
|
3913
|
+
for (const depSkill of targetSkills) {
|
|
3914
|
+
const children = await buildDependencyTree(depSkill, resolving, cloneCache, tempDirs);
|
|
3915
|
+
nodes.push({
|
|
3916
|
+
name: depRef,
|
|
3917
|
+
ref: depRef,
|
|
3918
|
+
children
|
|
3919
|
+
});
|
|
3920
|
+
}
|
|
3921
|
+
if (targetSkills.length === 0) nodes.push({
|
|
3922
|
+
name: `${depRef} (not found)`,
|
|
3923
|
+
ref: depRef,
|
|
3924
|
+
children: []
|
|
3925
|
+
});
|
|
3926
|
+
} catch (err) {
|
|
3927
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3928
|
+
nodes.push({
|
|
3929
|
+
name: `${depRef} (error: ${msg})`,
|
|
3930
|
+
ref: depRef,
|
|
3931
|
+
children: []
|
|
3932
|
+
});
|
|
3933
|
+
}
|
|
3934
|
+
}
|
|
3935
|
+
return nodes;
|
|
3936
|
+
}
|
|
3937
|
+
function printTree(nodes, prefix = "") {
|
|
3938
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
3939
|
+
const node = nodes[i];
|
|
3940
|
+
const isLast = i === nodes.length - 1;
|
|
3941
|
+
const connector = isLast ? "└── " : "├── ";
|
|
3942
|
+
const childPrefix = isLast ? " " : "│ ";
|
|
3943
|
+
console.log(`${prefix}${connector}${TEXT$2}${node.name}${RESET$2}`);
|
|
3944
|
+
if (node.children.length > 0) printTree(node.children, prefix + childPrefix);
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
async function runDeps(args) {
|
|
3948
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
3949
|
+
console.log(`
|
|
3950
|
+
${BOLD$2}Usage:${RESET$2} skpm deps <package>
|
|
3951
|
+
|
|
3952
|
+
${BOLD$2}Description:${RESET$2}
|
|
3953
|
+
Show the dependency tree for a skill without installing it.
|
|
3954
|
+
|
|
3955
|
+
${BOLD$2}Arguments:${RESET$2}
|
|
3956
|
+
package Skill reference (e.g., owner/repo@skill-name)
|
|
3957
|
+
|
|
3958
|
+
${BOLD$2}Examples:${RESET$2}
|
|
3959
|
+
${DIM$2}$${RESET$2} skpm deps jonmumm/skills@swarm
|
|
3960
|
+
${DIM$2}$${RESET$2} skpm deps owner/repo@skill-name
|
|
3961
|
+
`);
|
|
3962
|
+
return;
|
|
3963
|
+
}
|
|
3964
|
+
const source = args[0];
|
|
3965
|
+
if (!source) {
|
|
3966
|
+
console.log(`${RESET$2}Missing required argument: package`);
|
|
3967
|
+
console.log(`${DIM$2}Usage: skpm deps <package>${RESET$2}`);
|
|
3968
|
+
process.exit(1);
|
|
3969
|
+
}
|
|
3970
|
+
const tempDirs = /* @__PURE__ */ new Set();
|
|
3971
|
+
const cloneCache = /* @__PURE__ */ new Map();
|
|
3972
|
+
try {
|
|
3973
|
+
const parsed = parseSource(source);
|
|
3974
|
+
let skillsDir;
|
|
3975
|
+
if (parsed.type === "local") skillsDir = parsed.localPath;
|
|
3976
|
+
else {
|
|
3977
|
+
console.log(`${DIM$2}Cloning repository...${RESET$2}`);
|
|
3978
|
+
skillsDir = await cloneRepo(parsed.url, parsed.ref);
|
|
3979
|
+
tempDirs.add(skillsDir);
|
|
3980
|
+
cloneCache.set(parsed.url, skillsDir);
|
|
3981
|
+
}
|
|
3982
|
+
const skills = await discoverSkills(skillsDir, parsed.subpath, { includeInternal: true });
|
|
3983
|
+
const targetSkills = parsed.skillFilter ? skills.filter((s) => s.name.toLowerCase() === parsed.skillFilter.toLowerCase()) : skills;
|
|
3984
|
+
if (targetSkills.length === 0) {
|
|
3985
|
+
console.log(`No skills found matching: ${source}`);
|
|
3986
|
+
process.exit(1);
|
|
3987
|
+
}
|
|
3988
|
+
for (const skill of targetSkills) {
|
|
3989
|
+
console.log(`${BOLD$2}${skill.name}${RESET$2}`);
|
|
3990
|
+
if (skill.dependsOn.length === 0) {
|
|
3991
|
+
console.log(`${DIM$2} (no dependencies)${RESET$2}`);
|
|
3992
|
+
continue;
|
|
3993
|
+
}
|
|
3994
|
+
printTree(await buildDependencyTree(skill, /* @__PURE__ */ new Set(), cloneCache, tempDirs));
|
|
3995
|
+
}
|
|
3996
|
+
} finally {
|
|
3997
|
+
for (const dir of tempDirs) await cleanupTempDir(dir).catch(() => {});
|
|
3998
|
+
}
|
|
3999
|
+
}
|
|
4000
|
+
const RESET$1 = "\x1B[0m";
|
|
4001
|
+
const BOLD$1 = "\x1B[1m";
|
|
4002
|
+
const DIM$1 = "\x1B[38;5;102m";
|
|
4003
|
+
const TEXT$1 = "\x1B[38;5;145m";
|
|
4004
|
+
function parseRunScriptsOptions(args) {
|
|
4005
|
+
const options = {};
|
|
4006
|
+
let skillName;
|
|
4007
|
+
for (const arg of args) if (arg === "--trust-scripts") options.trustScripts = true;
|
|
4008
|
+
else if (!arg.startsWith("-")) skillName = arg;
|
|
4009
|
+
return {
|
|
4010
|
+
skillName,
|
|
4011
|
+
options
|
|
4012
|
+
};
|
|
4013
|
+
}
|
|
4014
|
+
async function runRunScripts(args) {
|
|
4015
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
4016
|
+
console.log(`
|
|
4017
|
+
${BOLD$1}Usage:${RESET$1} skpm run-scripts <skill-name> [options]
|
|
4018
|
+
|
|
4019
|
+
${BOLD$1}Description:${RESET$1}
|
|
4020
|
+
Execute postInstall commands for an already-installed skill.
|
|
4021
|
+
|
|
4022
|
+
${BOLD$1}Arguments:${RESET$1}
|
|
4023
|
+
skill-name Name of the installed skill
|
|
4024
|
+
|
|
4025
|
+
${BOLD$1}Options:${RESET$1}
|
|
4026
|
+
--trust-scripts Auto-accept without prompting
|
|
4027
|
+
|
|
4028
|
+
${BOLD$1}Examples:${RESET$1}
|
|
4029
|
+
${DIM$1}$${RESET$1} skpm run-scripts swarm
|
|
4030
|
+
${DIM$1}$${RESET$1} skpm run-scripts swarm --trust-scripts
|
|
4031
|
+
`);
|
|
4032
|
+
return;
|
|
4033
|
+
}
|
|
4034
|
+
const { skillName, options } = parseRunScriptsOptions(args);
|
|
4035
|
+
if (!skillName) {
|
|
4036
|
+
console.log(`Missing required argument: skill-name`);
|
|
4037
|
+
console.log(`${DIM$1}Usage: skpm run-scripts <skill-name>${RESET$1}`);
|
|
4038
|
+
process.exit(1);
|
|
4039
|
+
}
|
|
4040
|
+
const skillMdPath = join(join(homedir(), ".agents", "skills", skillName), "SKILL.md");
|
|
4041
|
+
if (!existsSync(skillMdPath)) {
|
|
4042
|
+
console.log(`Skill not found: ${skillName}`);
|
|
4043
|
+
console.log(`${DIM$1}Expected at: ${skillMdPath}${RESET$1}`);
|
|
4044
|
+
process.exit(1);
|
|
4045
|
+
}
|
|
4046
|
+
const skill = await parseSkillMd(skillMdPath, { includeInternal: true });
|
|
4047
|
+
if (!skill) {
|
|
4048
|
+
console.log(`Failed to parse SKILL.md for: ${skillName}`);
|
|
4049
|
+
process.exit(1);
|
|
4050
|
+
}
|
|
4051
|
+
if (skill.postInstall.length === 0) {
|
|
4052
|
+
console.log(`${TEXT$1}No postInstall commands defined for ${skillName}${RESET$1}`);
|
|
4053
|
+
return;
|
|
4054
|
+
}
|
|
4055
|
+
console.log(`${TEXT$1}Post-install commands for ${BOLD$1}${skillName}${RESET$1}${TEXT$1}:${RESET$1}`);
|
|
4056
|
+
console.log(formatPostInstallCommands(skill.postInstall));
|
|
4057
|
+
console.log();
|
|
4058
|
+
let shouldRun = options.trustScripts === true;
|
|
4059
|
+
if (!shouldRun) {
|
|
4060
|
+
const rl = readline.createInterface({
|
|
4061
|
+
input: process.stdin,
|
|
4062
|
+
output: process.stdout
|
|
4063
|
+
});
|
|
4064
|
+
const answer = await new Promise((resolve) => {
|
|
4065
|
+
rl.question("Run these commands? [y/N] ", (ans) => {
|
|
4066
|
+
rl.close();
|
|
4067
|
+
resolve(ans);
|
|
4068
|
+
});
|
|
4069
|
+
});
|
|
4070
|
+
shouldRun = answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
4071
|
+
}
|
|
4072
|
+
if (shouldRun) {
|
|
4073
|
+
const result = await executePostInstallCommands(skill.postInstall, (cmd) => {
|
|
4074
|
+
console.log(`${DIM$1}$ ${cmd}${RESET$1}`);
|
|
4075
|
+
execSync(cmd, { stdio: "inherit" });
|
|
4076
|
+
});
|
|
4077
|
+
if (result.failed.length > 0) {
|
|
4078
|
+
for (const f of result.failed) {
|
|
4079
|
+
console.log(`${RESET$1}Command failed: ${f.command}`);
|
|
4080
|
+
console.log(`${DIM$1}${f.error}${RESET$1}`);
|
|
4081
|
+
}
|
|
4082
|
+
process.exit(1);
|
|
4083
|
+
}
|
|
4084
|
+
console.log(`${TEXT$1}All commands completed successfully${RESET$1}`);
|
|
4085
|
+
} else console.log(`${DIM$1}Skipped.${RESET$1}`);
|
|
4086
|
+
}
|
|
3826
4087
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
3827
4088
|
function getVersion() {
|
|
3828
4089
|
try {
|
|
@@ -3877,7 +4138,7 @@ function showBanner() {
|
|
|
3877
4138
|
console.log(` ${DIM}$${RESET} ${TEXT}skpm init ${DIM}[name]${RESET} ${DIM}Create a new skill${RESET}`);
|
|
3878
4139
|
console.log(` ${DIM}$${RESET} ${TEXT}skpm experimental_sync${RESET} ${DIM}Sync skills from node_modules${RESET}`);
|
|
3879
4140
|
console.log();
|
|
3880
|
-
console.log(`${DIM}try:${RESET} skpm add
|
|
4141
|
+
console.log(`${DIM}try:${RESET} skpm add jonmumm/skills`);
|
|
3881
4142
|
console.log();
|
|
3882
4143
|
console.log(`Discover more skills at ${TEXT}https://skpm.sh/${RESET}`);
|
|
3883
4144
|
console.log();
|
|
@@ -3888,8 +4149,8 @@ ${BOLD}Usage:${RESET} skpm <command> [options]
|
|
|
3888
4149
|
|
|
3889
4150
|
${BOLD}Manage Skills:${RESET}
|
|
3890
4151
|
add <package> Add a skill package (alias: a)
|
|
3891
|
-
e.g.
|
|
3892
|
-
https://github.com/
|
|
4152
|
+
e.g. owner/repo
|
|
4153
|
+
https://github.com/owner/repo
|
|
3893
4154
|
remove [skills] Remove installed skills
|
|
3894
4155
|
list, ls List installed skills
|
|
3895
4156
|
find [query] Search for skills interactively
|
|
@@ -3898,6 +4159,10 @@ ${BOLD}Updates:${RESET}
|
|
|
3898
4159
|
check Check for available skill updates
|
|
3899
4160
|
update Update all skills to latest versions
|
|
3900
4161
|
|
|
4162
|
+
${BOLD}Inspect:${RESET}
|
|
4163
|
+
deps <package> Show dependency tree for a skill
|
|
4164
|
+
run-scripts <name> Execute postInstall for an installed skill
|
|
4165
|
+
|
|
3901
4166
|
${BOLD}Project:${RESET}
|
|
3902
4167
|
experimental_install Restore skills from skills-lock.json
|
|
3903
4168
|
init [name] Initialize a skill (creates <name>/SKILL.md or ./SKILL.md)
|
|
@@ -3935,10 +4200,10 @@ ${BOLD}Options:${RESET}
|
|
|
3935
4200
|
--version, -v Show version number
|
|
3936
4201
|
|
|
3937
4202
|
${BOLD}Examples:${RESET}
|
|
3938
|
-
${DIM}$${RESET} skpm add
|
|
3939
|
-
${DIM}$${RESET} skpm add
|
|
3940
|
-
${DIM}$${RESET} skpm add
|
|
3941
|
-
${DIM}$${RESET} skpm add
|
|
4203
|
+
${DIM}$${RESET} skpm add jonmumm/skills
|
|
4204
|
+
${DIM}$${RESET} skpm add jonmumm/skills -g
|
|
4205
|
+
${DIM}$${RESET} skpm add jonmumm/skills --agent claude-code cursor
|
|
4206
|
+
${DIM}$${RESET} skpm add jonmumm/skills --skill swarm tdd
|
|
3942
4207
|
${DIM}$${RESET} skpm remove ${DIM}# interactive remove${RESET}
|
|
3943
4208
|
${DIM}$${RESET} skpm remove web-design ${DIM}# remove by name${RESET}
|
|
3944
4209
|
${DIM}$${RESET} skpm rm --global frontend-design
|
|
@@ -4318,6 +4583,12 @@ async function main() {
|
|
|
4318
4583
|
await runSync(restArgs, syncOptions);
|
|
4319
4584
|
break;
|
|
4320
4585
|
}
|
|
4586
|
+
case "deps":
|
|
4587
|
+
await runDeps(restArgs);
|
|
4588
|
+
break;
|
|
4589
|
+
case "run-scripts":
|
|
4590
|
+
await runRunScripts(restArgs);
|
|
4591
|
+
break;
|
|
4321
4592
|
case "list":
|
|
4322
4593
|
case "ls":
|
|
4323
4594
|
await runList(restArgs);
|