skills 1.4.9 → 1.5.1
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 +77 -56
- package/dist/cli.mjs +255 -122
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
The CLI for the open agent skills ecosystem.
|
|
4
4
|
|
|
5
5
|
<!-- agent-list:start -->
|
|
6
|
+
|
|
6
7
|
Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [41 more](#available-agents).
|
|
8
|
+
|
|
7
9
|
<!-- agent-list:end -->
|
|
8
10
|
|
|
9
11
|
## Install a Skill
|
|
@@ -92,14 +94,13 @@ When installing interactively, you can choose:
|
|
|
92
94
|
|
|
93
95
|
## Other Commands
|
|
94
96
|
|
|
95
|
-
| Command | Description
|
|
96
|
-
| ---------------------------- |
|
|
97
|
-
| `npx skills list` | List installed skills (alias: `ls`)
|
|
98
|
-
| `npx skills find [query]` | Search for skills interactively or by keyword
|
|
99
|
-
| `npx skills remove [skills]` | Remove installed skills from agents
|
|
100
|
-
| `npx skills
|
|
101
|
-
| `npx skills
|
|
102
|
-
| `npx skills init [name]` | Create a new SKILL.md template |
|
|
97
|
+
| Command | Description |
|
|
98
|
+
| ---------------------------- | --------------------------------------------- |
|
|
99
|
+
| `npx skills list` | List installed skills (alias: `ls`) |
|
|
100
|
+
| `npx skills find [query]` | Search for skills interactively or by keyword |
|
|
101
|
+
| `npx skills remove [skills]` | Remove installed skills from agents |
|
|
102
|
+
| `npx skills update [skills]` | Update installed skills to latest versions |
|
|
103
|
+
| `npx skills init [name]` | Create a new SKILL.md template |
|
|
103
104
|
|
|
104
105
|
### `skills list`
|
|
105
106
|
|
|
@@ -128,16 +129,33 @@ npx skills find
|
|
|
128
129
|
npx skills find typescript
|
|
129
130
|
```
|
|
130
131
|
|
|
131
|
-
### `skills
|
|
132
|
+
### `skills update`
|
|
132
133
|
|
|
133
134
|
```bash
|
|
134
|
-
#
|
|
135
|
-
npx skills check
|
|
136
|
-
|
|
137
|
-
# Update all skills to latest versions
|
|
135
|
+
# Update all skills (interactive scope prompt)
|
|
138
136
|
npx skills update
|
|
137
|
+
|
|
138
|
+
# Update a single skill by name
|
|
139
|
+
npx skills update my-skill
|
|
140
|
+
|
|
141
|
+
# Update multiple specific skills
|
|
142
|
+
npx skills update frontend-design web-design-guidelines
|
|
143
|
+
|
|
144
|
+
# Update only global or project skills
|
|
145
|
+
npx skills update -g
|
|
146
|
+
npx skills update -p
|
|
147
|
+
|
|
148
|
+
# Non-interactive (auto-detects scope: project if in a project, else global)
|
|
149
|
+
npx skills update -y
|
|
139
150
|
```
|
|
140
151
|
|
|
152
|
+
| Option | Description |
|
|
153
|
+
| --------------- | ------------------------------------------------------------------------- |
|
|
154
|
+
| `-g, --global` | Only update global skills |
|
|
155
|
+
| `-p, --project` | Only update project skills |
|
|
156
|
+
| `-y, --yes` | Skip scope prompt (auto-detect: project if in a project dir, else global) |
|
|
157
|
+
| `[skills...]` | Update specific skills by name instead of all |
|
|
158
|
+
|
|
141
159
|
### `skills init`
|
|
142
160
|
|
|
143
161
|
```bash
|
|
@@ -207,49 +225,51 @@ Discover skills at **[skills.sh](https://skills.sh)**
|
|
|
207
225
|
Skills can be installed to any of these agents:
|
|
208
226
|
|
|
209
227
|
<!-- supported-agents:start -->
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
|
213
|
-
|
|
|
214
|
-
|
|
|
215
|
-
|
|
|
216
|
-
|
|
|
217
|
-
|
|
|
218
|
-
|
|
|
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
|
-
| Trae
|
|
248
|
-
|
|
|
249
|
-
|
|
|
250
|
-
|
|
|
251
|
-
|
|
|
252
|
-
|
|
|
228
|
+
|
|
229
|
+
| Agent | `--agent` | Project Path | Global Path |
|
|
230
|
+
| ------------------------------------- | ---------------------------------------- | ---------------------- | ------------------------------- |
|
|
231
|
+
| Amp, Kimi Code CLI, Replit, Universal | `amp`, `kimi-cli`, `replit`, `universal` | `.agents/skills/` | `~/.config/agents/skills/` |
|
|
232
|
+
| Antigravity | `antigravity` | `.agents/skills/` | `~/.gemini/antigravity/skills/` |
|
|
233
|
+
| Augment | `augment` | `.augment/skills/` | `~/.augment/skills/` |
|
|
234
|
+
| IBM Bob | `bob` | `.bob/skills/` | `~/.bob/skills/` |
|
|
235
|
+
| Claude Code | `claude-code` | `.claude/skills/` | `~/.claude/skills/` |
|
|
236
|
+
| OpenClaw | `openclaw` | `skills/` | `~/.openclaw/skills/` |
|
|
237
|
+
| Cline, Warp | `cline`, `warp` | `.agents/skills/` | `~/.agents/skills/` |
|
|
238
|
+
| CodeBuddy | `codebuddy` | `.codebuddy/skills/` | `~/.codebuddy/skills/` |
|
|
239
|
+
| Codex | `codex` | `.agents/skills/` | `~/.codex/skills/` |
|
|
240
|
+
| Command Code | `command-code` | `.commandcode/skills/` | `~/.commandcode/skills/` |
|
|
241
|
+
| Continue | `continue` | `.continue/skills/` | `~/.continue/skills/` |
|
|
242
|
+
| Cortex Code | `cortex` | `.cortex/skills/` | `~/.snowflake/cortex/skills/` |
|
|
243
|
+
| Crush | `crush` | `.crush/skills/` | `~/.config/crush/skills/` |
|
|
244
|
+
| Cursor | `cursor` | `.agents/skills/` | `~/.cursor/skills/` |
|
|
245
|
+
| Deep Agents | `deepagents` | `.agents/skills/` | `~/.deepagents/agent/skills/` |
|
|
246
|
+
| Droid | `droid` | `.factory/skills/` | `~/.factory/skills/` |
|
|
247
|
+
| Firebender | `firebender` | `.agents/skills/` | `~/.firebender/skills/` |
|
|
248
|
+
| Gemini CLI | `gemini-cli` | `.agents/skills/` | `~/.gemini/skills/` |
|
|
249
|
+
| GitHub Copilot | `github-copilot` | `.agents/skills/` | `~/.copilot/skills/` |
|
|
250
|
+
| Goose | `goose` | `.goose/skills/` | `~/.config/goose/skills/` |
|
|
251
|
+
| Junie | `junie` | `.junie/skills/` | `~/.junie/skills/` |
|
|
252
|
+
| iFlow CLI | `iflow-cli` | `.iflow/skills/` | `~/.iflow/skills/` |
|
|
253
|
+
| Kilo Code | `kilo` | `.kilocode/skills/` | `~/.kilocode/skills/` |
|
|
254
|
+
| Kiro CLI | `kiro-cli` | `.kiro/skills/` | `~/.kiro/skills/` |
|
|
255
|
+
| Kode | `kode` | `.kode/skills/` | `~/.kode/skills/` |
|
|
256
|
+
| MCPJam | `mcpjam` | `.mcpjam/skills/` | `~/.mcpjam/skills/` |
|
|
257
|
+
| Mistral Vibe | `mistral-vibe` | `.vibe/skills/` | `~/.vibe/skills/` |
|
|
258
|
+
| Mux | `mux` | `.mux/skills/` | `~/.mux/skills/` |
|
|
259
|
+
| OpenCode | `opencode` | `.agents/skills/` | `~/.config/opencode/skills/` |
|
|
260
|
+
| OpenHands | `openhands` | `.openhands/skills/` | `~/.openhands/skills/` |
|
|
261
|
+
| Pi | `pi` | `.pi/skills/` | `~/.pi/agent/skills/` |
|
|
262
|
+
| Qoder | `qoder` | `.qoder/skills/` | `~/.qoder/skills/` |
|
|
263
|
+
| Qwen Code | `qwen-code` | `.qwen/skills/` | `~/.qwen/skills/` |
|
|
264
|
+
| Roo Code | `roo` | `.roo/skills/` | `~/.roo/skills/` |
|
|
265
|
+
| Trae | `trae` | `.trae/skills/` | `~/.trae/skills/` |
|
|
266
|
+
| Trae CN | `trae-cn` | `.trae/skills/` | `~/.trae-cn/skills/` |
|
|
267
|
+
| Windsurf | `windsurf` | `.windsurf/skills/` | `~/.codeium/windsurf/skills/` |
|
|
268
|
+
| Zencoder | `zencoder` | `.zencoder/skills/` | `~/.zencoder/skills/` |
|
|
269
|
+
| Neovate | `neovate` | `.neovate/skills/` | `~/.neovate/skills/` |
|
|
270
|
+
| Pochi | `pochi` | `.pochi/skills/` | `~/.pochi/skills/` |
|
|
271
|
+
| AdaL | `adal` | `.adal/skills/` | `~/.adal/skills/` |
|
|
272
|
+
|
|
253
273
|
<!-- supported-agents:end -->
|
|
254
274
|
|
|
255
275
|
> [!NOTE]
|
|
@@ -314,6 +334,7 @@ metadata:
|
|
|
314
334
|
The CLI searches for skills in these locations within a repository:
|
|
315
335
|
|
|
316
336
|
<!-- skill-discovery:start -->
|
|
337
|
+
|
|
317
338
|
- Root directory (if it contains `SKILL.md`)
|
|
318
339
|
- `skills/`
|
|
319
340
|
- `skills/.curated/`
|
package/dist/cli.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import "./_chunks/libs/@kwsites/promise-deferred.mjs";
|
|
|
7
7
|
import { t as esm_default } from "./_chunks/libs/simple-git.mjs";
|
|
8
8
|
import { t as xdgConfig } from "./_chunks/libs/xdg-basedir.mjs";
|
|
9
9
|
import { execSync, spawnSync } from "child_process";
|
|
10
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
|
|
11
11
|
import { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "path";
|
|
12
12
|
import { homedir, platform, tmpdir } from "os";
|
|
13
13
|
import { fileURLToPath } from "url";
|
|
@@ -402,7 +402,8 @@ async function cloneRepo(url, ref) {
|
|
|
402
402
|
timeout: { block: CLONE_TIMEOUT_MS },
|
|
403
403
|
env: {
|
|
404
404
|
...process.env,
|
|
405
|
-
GIT_TERMINAL_PROMPT: "0"
|
|
405
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
406
|
+
GIT_LFS_SKIP_SMUDGE: "1"
|
|
406
407
|
}
|
|
407
408
|
});
|
|
408
409
|
const cloneOptions = ref ? [
|
|
@@ -2164,7 +2165,7 @@ async function tryBlobInstall(ownerRepo, options = {}) {
|
|
|
2164
2165
|
tree
|
|
2165
2166
|
};
|
|
2166
2167
|
}
|
|
2167
|
-
var version$1 = "1.
|
|
2168
|
+
var version$1 = "1.5.1";
|
|
2168
2169
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
2169
2170
|
async function isSourcePrivate(source) {
|
|
2170
2171
|
const ownerRepo = parseOwnerRepo(source);
|
|
@@ -4111,6 +4112,9 @@ function buildUpdateInstallSource(entry) {
|
|
|
4111
4112
|
if (entry.ref) installSource = `${installSource}#${entry.ref}`;
|
|
4112
4113
|
return installSource;
|
|
4113
4114
|
}
|
|
4115
|
+
function buildLocalUpdateSource(entry) {
|
|
4116
|
+
return formatSourceInput(entry.source, entry.ref);
|
|
4117
|
+
}
|
|
4114
4118
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
4115
4119
|
function getVersion() {
|
|
4116
4120
|
try {
|
|
@@ -4158,8 +4162,7 @@ function showBanner() {
|
|
|
4158
4162
|
console.log(` ${DIM}$${RESET} ${TEXT}npx skills list${RESET} ${DIM}List installed skills${RESET}`);
|
|
4159
4163
|
console.log(` ${DIM}$${RESET} ${TEXT}npx skills find ${DIM}[query]${RESET} ${DIM}Search for skills${RESET}`);
|
|
4160
4164
|
console.log();
|
|
4161
|
-
console.log(` ${DIM}$${RESET} ${TEXT}npx skills
|
|
4162
|
-
console.log(` ${DIM}$${RESET} ${TEXT}npx skills update${RESET} ${DIM}Update all skills${RESET}`);
|
|
4165
|
+
console.log(` ${DIM}$${RESET} ${TEXT}npx skills update${RESET} ${DIM}Update installed skills${RESET}`);
|
|
4163
4166
|
console.log();
|
|
4164
4167
|
console.log(` ${DIM}$${RESET} ${TEXT}npx skills experimental_install${RESET} ${DIM}Restore from skills-lock.json${RESET}`);
|
|
4165
4168
|
console.log(` ${DIM}$${RESET} ${TEXT}npx skills init ${DIM}[name]${RESET} ${DIM}Create a new skill${RESET}`);
|
|
@@ -4183,8 +4186,12 @@ ${BOLD}Manage Skills:${RESET}
|
|
|
4183
4186
|
find [query] Search for skills interactively
|
|
4184
4187
|
|
|
4185
4188
|
${BOLD}Updates:${RESET}
|
|
4186
|
-
|
|
4187
|
-
|
|
4189
|
+
update [skills...] Update skills to latest versions (alias: upgrade)
|
|
4190
|
+
|
|
4191
|
+
${BOLD}Update Options:${RESET}
|
|
4192
|
+
-g, --global Update global skills only
|
|
4193
|
+
-p, --project Update project skills only
|
|
4194
|
+
-y, --yes Skip scope prompt (auto-detect: project if in a project, else global)
|
|
4188
4195
|
|
|
4189
4196
|
${BOLD}Project:${RESET}
|
|
4190
4197
|
experimental_install Restore skills from skills-lock.json
|
|
@@ -4235,8 +4242,9 @@ ${BOLD}Examples:${RESET}
|
|
|
4235
4242
|
${DIM}$${RESET} skills ls --json ${DIM}# JSON output${RESET}
|
|
4236
4243
|
${DIM}$${RESET} skills find ${DIM}# interactive search${RESET}
|
|
4237
4244
|
${DIM}$${RESET} skills find typescript ${DIM}# search by keyword${RESET}
|
|
4238
|
-
${DIM}$${RESET} skills check
|
|
4239
4245
|
${DIM}$${RESET} skills update
|
|
4246
|
+
${DIM}$${RESET} skills update my-skill ${DIM}# update a single skill${RESET}
|
|
4247
|
+
${DIM}$${RESET} skills update -g ${DIM}# update global skills only${RESET}
|
|
4240
4248
|
${DIM}$${RESET} skills experimental_install ${DIM}# restore from skills-lock.json${RESET}
|
|
4241
4249
|
${DIM}$${RESET} skills init my-skill
|
|
4242
4250
|
${DIM}$${RESET} skills experimental_sync ${DIM}# sync from node_modules${RESET}
|
|
@@ -4351,127 +4359,144 @@ function readSkillLock() {
|
|
|
4351
4359
|
};
|
|
4352
4360
|
}
|
|
4353
4361
|
}
|
|
4362
|
+
function parseUpdateOptions(args) {
|
|
4363
|
+
const options = {};
|
|
4364
|
+
const positional = [];
|
|
4365
|
+
for (const arg of args) if (arg === "-g" || arg === "--global") options.global = true;
|
|
4366
|
+
else if (arg === "-p" || arg === "--project") options.project = true;
|
|
4367
|
+
else if (arg === "-y" || arg === "--yes") options.yes = true;
|
|
4368
|
+
else if (!arg.startsWith("-")) positional.push(arg);
|
|
4369
|
+
if (positional.length > 0) options.skills = positional;
|
|
4370
|
+
return options;
|
|
4371
|
+
}
|
|
4372
|
+
function hasProjectSkills(cwd) {
|
|
4373
|
+
const dir = cwd || process.cwd();
|
|
4374
|
+
if (existsSync(join(dir, "skills-lock.json"))) return true;
|
|
4375
|
+
const skillsDir = join(dir, ".agents", "skills");
|
|
4376
|
+
try {
|
|
4377
|
+
const entries = readdirSync(skillsDir, { withFileTypes: true });
|
|
4378
|
+
for (const entry of entries) if (entry.isDirectory()) {
|
|
4379
|
+
if (existsSync(join(skillsDir, entry.name, "SKILL.md"))) return true;
|
|
4380
|
+
}
|
|
4381
|
+
} catch {}
|
|
4382
|
+
return false;
|
|
4383
|
+
}
|
|
4384
|
+
async function resolveUpdateScope(options) {
|
|
4385
|
+
if (options.skills && options.skills.length > 0) {
|
|
4386
|
+
if (options.global) return "global";
|
|
4387
|
+
if (options.project) return "project";
|
|
4388
|
+
return "both";
|
|
4389
|
+
}
|
|
4390
|
+
if (options.global && options.project) return "both";
|
|
4391
|
+
if (options.global) return "global";
|
|
4392
|
+
if (options.project) return "project";
|
|
4393
|
+
if (options.yes || !process.stdin.isTTY) return hasProjectSkills() ? "project" : "global";
|
|
4394
|
+
const scope = await ve({
|
|
4395
|
+
message: "Update scope",
|
|
4396
|
+
options: [
|
|
4397
|
+
{
|
|
4398
|
+
value: "project",
|
|
4399
|
+
label: "Project",
|
|
4400
|
+
hint: "Update skills in current directory"
|
|
4401
|
+
},
|
|
4402
|
+
{
|
|
4403
|
+
value: "global",
|
|
4404
|
+
label: "Global",
|
|
4405
|
+
hint: "Update skills in home directory"
|
|
4406
|
+
},
|
|
4407
|
+
{
|
|
4408
|
+
value: "both",
|
|
4409
|
+
label: "Both",
|
|
4410
|
+
hint: "Update all skills"
|
|
4411
|
+
}
|
|
4412
|
+
]
|
|
4413
|
+
});
|
|
4414
|
+
if (pD(scope)) {
|
|
4415
|
+
xe("Cancelled");
|
|
4416
|
+
process.exit(0);
|
|
4417
|
+
}
|
|
4418
|
+
return scope;
|
|
4419
|
+
}
|
|
4420
|
+
function matchesSkillFilter(name, filter) {
|
|
4421
|
+
if (!filter || filter.length === 0) return true;
|
|
4422
|
+
const lower = name.toLowerCase();
|
|
4423
|
+
return filter.some((f) => f.toLowerCase() === lower);
|
|
4424
|
+
}
|
|
4354
4425
|
function getSkipReason(entry) {
|
|
4355
4426
|
if (entry.sourceType === "local") return "Local path";
|
|
4356
|
-
if (entry.sourceType === "git") return "Git URL
|
|
4357
|
-
if (
|
|
4427
|
+
if (entry.sourceType === "git") return "Git URL";
|
|
4428
|
+
if (entry.sourceType === "well-known") return "Well-known skill";
|
|
4429
|
+
if (!entry.skillFolderHash) return "Private or deleted repo";
|
|
4358
4430
|
if (!entry.skillPath) return "No skill path recorded";
|
|
4359
4431
|
return "No version tracking";
|
|
4360
4432
|
}
|
|
4433
|
+
function getInstallSource(skill) {
|
|
4434
|
+
let url = skill.sourceUrl;
|
|
4435
|
+
if (skill.sourceType === "well-known") {
|
|
4436
|
+
const idx = url.indexOf("/.well-known/");
|
|
4437
|
+
if (idx !== -1) url = url.slice(0, idx);
|
|
4438
|
+
}
|
|
4439
|
+
return formatSourceInput(url, skill.ref);
|
|
4440
|
+
}
|
|
4361
4441
|
function printSkippedSkills(skipped) {
|
|
4362
4442
|
if (skipped.length === 0) return;
|
|
4363
4443
|
console.log();
|
|
4364
4444
|
console.log(`${DIM}${skipped.length} skill(s) cannot be checked automatically:${RESET}`);
|
|
4445
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
4365
4446
|
for (const skill of skipped) {
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
}
|
|
4380
|
-
const token = getGitHubToken();
|
|
4381
|
-
const skillsBySource = /* @__PURE__ */ new Map();
|
|
4382
|
-
const skipped = [];
|
|
4383
|
-
for (const skillName of skillNames) {
|
|
4384
|
-
const entry = lock.skills[skillName];
|
|
4385
|
-
if (!entry) continue;
|
|
4386
|
-
if (!entry.skillFolderHash || !entry.skillPath) {
|
|
4387
|
-
skipped.push({
|
|
4388
|
-
name: skillName,
|
|
4389
|
-
reason: getSkipReason(entry),
|
|
4390
|
-
sourceUrl: entry.sourceUrl,
|
|
4391
|
-
ref: entry.ref
|
|
4392
|
-
});
|
|
4393
|
-
continue;
|
|
4447
|
+
const source = getInstallSource(skill);
|
|
4448
|
+
const existing = grouped.get(source) || [];
|
|
4449
|
+
existing.push(skill);
|
|
4450
|
+
grouped.set(source, existing);
|
|
4451
|
+
}
|
|
4452
|
+
for (const [source, skills] of grouped) {
|
|
4453
|
+
if (skills.length === 1) {
|
|
4454
|
+
const skill = skills[0];
|
|
4455
|
+
console.log(` ${TEXT}•${RESET} ${skill.name} ${DIM}(${skill.reason})${RESET}`);
|
|
4456
|
+
} else {
|
|
4457
|
+
const reason = skills[0].reason;
|
|
4458
|
+
const names = skills.map((s) => s.name).join(", ");
|
|
4459
|
+
console.log(` ${TEXT}•${RESET} ${names} ${DIM}(${reason})${RESET}`);
|
|
4394
4460
|
}
|
|
4395
|
-
|
|
4396
|
-
existing.push({
|
|
4397
|
-
name: skillName,
|
|
4398
|
-
entry
|
|
4399
|
-
});
|
|
4400
|
-
skillsBySource.set(entry.source, existing);
|
|
4401
|
-
}
|
|
4402
|
-
const totalSkills = skillNames.length - skipped.length;
|
|
4403
|
-
if (totalSkills === 0) {
|
|
4404
|
-
console.log(`${DIM}No GitHub skills to check.${RESET}`);
|
|
4405
|
-
printSkippedSkills(skipped);
|
|
4406
|
-
return;
|
|
4461
|
+
console.log(` ${DIM}To update: ${TEXT}npx skills add ${source} -g -y${RESET}`);
|
|
4407
4462
|
}
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
const
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
if (!
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
source,
|
|
4417
|
-
error: "Could not fetch from GitHub"
|
|
4418
|
-
});
|
|
4419
|
-
continue;
|
|
4420
|
-
}
|
|
4421
|
-
if (latestHash !== entry.skillFolderHash) updates.push({
|
|
4422
|
-
name,
|
|
4423
|
-
source
|
|
4424
|
-
});
|
|
4425
|
-
} catch (err) {
|
|
4426
|
-
errors.push({
|
|
4463
|
+
}
|
|
4464
|
+
async function getProjectSkillsForUpdate(skillFilter) {
|
|
4465
|
+
const localLock = await readLocalLock();
|
|
4466
|
+
const skills = [];
|
|
4467
|
+
for (const [name, entry] of Object.entries(localLock.skills)) {
|
|
4468
|
+
if (!matchesSkillFilter(name, skillFilter)) continue;
|
|
4469
|
+
if (entry.sourceType === "node_modules" || entry.sourceType === "local") continue;
|
|
4470
|
+
skills.push({
|
|
4427
4471
|
name,
|
|
4428
|
-
source,
|
|
4429
|
-
|
|
4472
|
+
source: entry.source,
|
|
4473
|
+
entry
|
|
4430
4474
|
});
|
|
4431
4475
|
}
|
|
4432
|
-
|
|
4433
|
-
if (updates.length === 0) console.log(`${TEXT}✓ All skills are up to date${RESET}`);
|
|
4434
|
-
else {
|
|
4435
|
-
console.log(`${TEXT}${updates.length} update(s) available:${RESET}`);
|
|
4436
|
-
console.log();
|
|
4437
|
-
for (const update of updates) {
|
|
4438
|
-
console.log(` ${TEXT}↑${RESET} ${update.name}`);
|
|
4439
|
-
console.log(` ${DIM}source: ${update.source}${RESET}`);
|
|
4440
|
-
}
|
|
4441
|
-
console.log();
|
|
4442
|
-
console.log(`${DIM}Run${RESET} ${TEXT}npx skills update${RESET} ${DIM}to update all skills${RESET}`);
|
|
4443
|
-
}
|
|
4444
|
-
if (errors.length > 0) {
|
|
4445
|
-
console.log();
|
|
4446
|
-
console.log(`${DIM}Could not check ${errors.length} skill(s) (may need reinstall)${RESET}`);
|
|
4447
|
-
console.log();
|
|
4448
|
-
for (const error of errors) {
|
|
4449
|
-
console.log(` ${DIM}✗${RESET} ${error.name}`);
|
|
4450
|
-
console.log(` ${DIM}source: ${error.source}${RESET}`);
|
|
4451
|
-
}
|
|
4452
|
-
}
|
|
4453
|
-
printSkippedSkills(skipped);
|
|
4454
|
-
track({
|
|
4455
|
-
event: "check",
|
|
4456
|
-
skillCount: String(totalSkills),
|
|
4457
|
-
updatesAvailable: String(updates.length)
|
|
4458
|
-
});
|
|
4459
|
-
console.log();
|
|
4476
|
+
return skills;
|
|
4460
4477
|
}
|
|
4461
|
-
async function
|
|
4462
|
-
console.log(`${TEXT}Checking for skill updates...${RESET}`);
|
|
4463
|
-
console.log();
|
|
4478
|
+
async function updateGlobalSkills(skillFilter) {
|
|
4464
4479
|
const lock = readSkillLock();
|
|
4465
4480
|
const skillNames = Object.keys(lock.skills);
|
|
4481
|
+
let successCount = 0;
|
|
4482
|
+
let failCount = 0;
|
|
4466
4483
|
if (skillNames.length === 0) {
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4484
|
+
if (!skillFilter) {
|
|
4485
|
+
console.log(`${DIM}No global skills tracked in lock file.${RESET}`);
|
|
4486
|
+
console.log(`${DIM}Install skills with${RESET} ${TEXT}npx skills add <package> -g${RESET}`);
|
|
4487
|
+
}
|
|
4488
|
+
return {
|
|
4489
|
+
successCount,
|
|
4490
|
+
failCount,
|
|
4491
|
+
checkedCount: 0
|
|
4492
|
+
};
|
|
4470
4493
|
}
|
|
4471
4494
|
const token = getGitHubToken();
|
|
4472
4495
|
const updates = [];
|
|
4473
4496
|
const skipped = [];
|
|
4497
|
+
const checkable = [];
|
|
4474
4498
|
for (const skillName of skillNames) {
|
|
4499
|
+
if (!matchesSkillFilter(skillName, skillFilter)) continue;
|
|
4475
4500
|
const entry = lock.skills[skillName];
|
|
4476
4501
|
if (!entry) continue;
|
|
4477
4502
|
if (!entry.skillFolderHash || !entry.skillPath) {
|
|
@@ -4479,10 +4504,19 @@ async function runUpdate() {
|
|
|
4479
4504
|
name: skillName,
|
|
4480
4505
|
reason: getSkipReason(entry),
|
|
4481
4506
|
sourceUrl: entry.sourceUrl,
|
|
4507
|
+
sourceType: entry.sourceType,
|
|
4482
4508
|
ref: entry.ref
|
|
4483
4509
|
});
|
|
4484
4510
|
continue;
|
|
4485
4511
|
}
|
|
4512
|
+
checkable.push({
|
|
4513
|
+
name: skillName,
|
|
4514
|
+
entry
|
|
4515
|
+
});
|
|
4516
|
+
}
|
|
4517
|
+
for (let i = 0; i < checkable.length; i++) {
|
|
4518
|
+
const { name: skillName, entry } = checkable[i];
|
|
4519
|
+
process.stdout.write(`\r${DIM}Checking global skill ${i + 1}/${checkable.length}: ${skillName}${RESET}\x1b[K`);
|
|
4486
4520
|
try {
|
|
4487
4521
|
const latestHash = await fetchSkillFolderHash(entry.source, entry.skillPath, token, entry.ref);
|
|
4488
4522
|
if (latestHash && latestHash !== entry.skillFolderHash) updates.push({
|
|
@@ -4492,20 +4526,34 @@ async function runUpdate() {
|
|
|
4492
4526
|
});
|
|
4493
4527
|
} catch {}
|
|
4494
4528
|
}
|
|
4495
|
-
if (
|
|
4496
|
-
|
|
4529
|
+
if (checkable.length > 0) process.stdout.write("\r\x1B[K");
|
|
4530
|
+
const checkedCount = checkable.length + skipped.length;
|
|
4531
|
+
if (checkable.length === 0 && skipped.length === 0) {
|
|
4532
|
+
if (!skillFilter) console.log(`${DIM}No global skills to check.${RESET}`);
|
|
4533
|
+
return {
|
|
4534
|
+
successCount,
|
|
4535
|
+
failCount,
|
|
4536
|
+
checkedCount: 0
|
|
4537
|
+
};
|
|
4538
|
+
}
|
|
4539
|
+
if (checkable.length === 0 && skipped.length > 0) {
|
|
4497
4540
|
printSkippedSkills(skipped);
|
|
4498
|
-
return
|
|
4541
|
+
return {
|
|
4542
|
+
successCount,
|
|
4543
|
+
failCount,
|
|
4544
|
+
checkedCount
|
|
4545
|
+
};
|
|
4499
4546
|
}
|
|
4500
4547
|
if (updates.length === 0) {
|
|
4501
|
-
console.log(`${TEXT}✓ All skills are up to date${RESET}`);
|
|
4502
|
-
|
|
4503
|
-
|
|
4548
|
+
console.log(`${TEXT}✓ All global skills are up to date${RESET}`);
|
|
4549
|
+
return {
|
|
4550
|
+
successCount,
|
|
4551
|
+
failCount,
|
|
4552
|
+
checkedCount
|
|
4553
|
+
};
|
|
4504
4554
|
}
|
|
4505
|
-
console.log(`${TEXT}Found ${updates.length} update(s)${RESET}`);
|
|
4555
|
+
console.log(`${TEXT}Found ${updates.length} global update(s)${RESET}`);
|
|
4506
4556
|
console.log();
|
|
4507
|
-
let successCount = 0;
|
|
4508
|
-
let failCount = 0;
|
|
4509
4557
|
for (const update of updates) {
|
|
4510
4558
|
console.log(`${TEXT}Updating ${update.name}...${RESET}`);
|
|
4511
4559
|
const installUrl = buildUpdateInstallSource(update.entry);
|
|
@@ -4537,14 +4585,101 @@ async function runUpdate() {
|
|
|
4537
4585
|
console.log(` ${DIM}✗ Failed to update ${update.name}${RESET}`);
|
|
4538
4586
|
}
|
|
4539
4587
|
}
|
|
4588
|
+
printSkippedSkills(skipped);
|
|
4589
|
+
return {
|
|
4590
|
+
successCount,
|
|
4591
|
+
failCount,
|
|
4592
|
+
checkedCount
|
|
4593
|
+
};
|
|
4594
|
+
}
|
|
4595
|
+
async function updateProjectSkills(skillFilter) {
|
|
4596
|
+
const projectSkills = await getProjectSkillsForUpdate(skillFilter);
|
|
4597
|
+
let successCount = 0;
|
|
4598
|
+
let failCount = 0;
|
|
4599
|
+
if (projectSkills.length === 0) {
|
|
4600
|
+
if (!skillFilter) {
|
|
4601
|
+
console.log(`${DIM}No project skills to update.${RESET}`);
|
|
4602
|
+
console.log(`${DIM}Install project skills with${RESET} ${TEXT}npx skills add <package>${RESET}`);
|
|
4603
|
+
}
|
|
4604
|
+
return {
|
|
4605
|
+
successCount,
|
|
4606
|
+
failCount,
|
|
4607
|
+
foundCount: 0
|
|
4608
|
+
};
|
|
4609
|
+
}
|
|
4610
|
+
console.log(`${TEXT}Refreshing ${projectSkills.length} project skill(s)...${RESET}`);
|
|
4611
|
+
console.log();
|
|
4612
|
+
for (const skill of projectSkills) {
|
|
4613
|
+
console.log(`${TEXT}Updating ${skill.name}...${RESET}`);
|
|
4614
|
+
const installUrl = buildLocalUpdateSource(skill.entry);
|
|
4615
|
+
const cliEntry = join(__dirname, "..", "bin", "cli.mjs");
|
|
4616
|
+
if (!existsSync(cliEntry)) {
|
|
4617
|
+
failCount++;
|
|
4618
|
+
console.log(` ${DIM}✗ Failed to update ${skill.name}: CLI entrypoint not found at ${cliEntry}${RESET}`);
|
|
4619
|
+
continue;
|
|
4620
|
+
}
|
|
4621
|
+
if (spawnSync(process.execPath, [
|
|
4622
|
+
cliEntry,
|
|
4623
|
+
"add",
|
|
4624
|
+
installUrl,
|
|
4625
|
+
"-y"
|
|
4626
|
+
], {
|
|
4627
|
+
stdio: [
|
|
4628
|
+
"inherit",
|
|
4629
|
+
"pipe",
|
|
4630
|
+
"pipe"
|
|
4631
|
+
],
|
|
4632
|
+
encoding: "utf-8",
|
|
4633
|
+
shell: process.platform === "win32"
|
|
4634
|
+
}).status === 0) {
|
|
4635
|
+
successCount++;
|
|
4636
|
+
console.log(` ${TEXT}✓${RESET} Updated ${skill.name}`);
|
|
4637
|
+
} else {
|
|
4638
|
+
failCount++;
|
|
4639
|
+
console.log(` ${DIM}✗ Failed to update ${skill.name}${RESET}`);
|
|
4640
|
+
}
|
|
4641
|
+
}
|
|
4642
|
+
return {
|
|
4643
|
+
successCount,
|
|
4644
|
+
failCount,
|
|
4645
|
+
foundCount: projectSkills.length
|
|
4646
|
+
};
|
|
4647
|
+
}
|
|
4648
|
+
async function runUpdate(args = []) {
|
|
4649
|
+
const options = parseUpdateOptions(args);
|
|
4650
|
+
const scope = await resolveUpdateScope(options);
|
|
4651
|
+
if (options.skills) console.log(`${TEXT}Updating ${options.skills.join(", ")}...${RESET}`);
|
|
4652
|
+
else console.log(`${TEXT}Checking for skill updates...${RESET}`);
|
|
4540
4653
|
console.log();
|
|
4541
|
-
|
|
4542
|
-
|
|
4654
|
+
let totalSuccess = 0;
|
|
4655
|
+
let totalFail = 0;
|
|
4656
|
+
let totalFound = 0;
|
|
4657
|
+
if (scope === "global" || scope === "both") {
|
|
4658
|
+
if (scope === "both" && !options.skills) console.log(`${BOLD}Global Skills${RESET}`);
|
|
4659
|
+
const { successCount, failCount, checkedCount } = await updateGlobalSkills(options.skills);
|
|
4660
|
+
totalSuccess += successCount;
|
|
4661
|
+
totalFail += failCount;
|
|
4662
|
+
totalFound += checkedCount;
|
|
4663
|
+
if (scope === "both" && !options.skills) console.log();
|
|
4664
|
+
}
|
|
4665
|
+
if (scope === "project" || scope === "both") {
|
|
4666
|
+
if (scope === "both" && !options.skills) console.log(`${BOLD}Project Skills${RESET}`);
|
|
4667
|
+
const { successCount, failCount, foundCount } = await updateProjectSkills(options.skills);
|
|
4668
|
+
totalSuccess += successCount;
|
|
4669
|
+
totalFail += failCount;
|
|
4670
|
+
totalFound += foundCount;
|
|
4671
|
+
}
|
|
4672
|
+
if (options.skills && totalFound === 0) console.log(`${DIM}No installed skills found matching: ${options.skills.join(", ")}${RESET}`);
|
|
4673
|
+
console.log();
|
|
4674
|
+
if (totalSuccess > 0) console.log(`${TEXT}✓ Updated ${totalSuccess} skill(s)${RESET}`);
|
|
4675
|
+
if (totalFail > 0) console.log(`${DIM}Failed to update ${totalFail} skill(s)${RESET}`);
|
|
4676
|
+
if (totalSuccess === 0 && totalFail === 0) {}
|
|
4543
4677
|
track({
|
|
4544
4678
|
event: "update",
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4679
|
+
scope,
|
|
4680
|
+
skillCount: String(totalSuccess + totalFail),
|
|
4681
|
+
successCount: String(totalSuccess),
|
|
4682
|
+
failCount: String(totalFail)
|
|
4548
4683
|
});
|
|
4549
4684
|
console.log();
|
|
4550
4685
|
}
|
|
@@ -4604,11 +4739,9 @@ async function main() {
|
|
|
4604
4739
|
await runList(restArgs);
|
|
4605
4740
|
break;
|
|
4606
4741
|
case "check":
|
|
4607
|
-
runCheck(restArgs);
|
|
4608
|
-
break;
|
|
4609
4742
|
case "update":
|
|
4610
4743
|
case "upgrade":
|
|
4611
|
-
runUpdate();
|
|
4744
|
+
await runUpdate(restArgs);
|
|
4612
4745
|
break;
|
|
4613
4746
|
case "--help":
|
|
4614
4747
|
case "-h":
|