skills 1.4.3 → 1.4.5
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 +2 -2
- package/dist/cli.mjs +127 -31
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The CLI for the open agent skills ecosystem.
|
|
4
4
|
|
|
5
5
|
<!-- agent-list:start -->
|
|
6
|
-
Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [
|
|
6
|
+
Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [38 more](#available-agents).
|
|
7
7
|
<!-- agent-list:end -->
|
|
8
8
|
|
|
9
9
|
## Install a Skill
|
|
@@ -214,7 +214,7 @@ Skills can be installed to any of these agents:
|
|
|
214
214
|
| Augment | `augment` | `.augment/skills/` | `~/.augment/skills/` |
|
|
215
215
|
| Claude Code | `claude-code` | `.claude/skills/` | `~/.claude/skills/` |
|
|
216
216
|
| OpenClaw | `openclaw` | `skills/` | `~/.openclaw/skills/` |
|
|
217
|
-
| Cline | `cline` | `.agents/skills/` | `~/.agents/skills/` |
|
|
217
|
+
| Cline, Warp | `cline`, `warp` | `.agents/skills/` | `~/.agents/skills/` |
|
|
218
218
|
| CodeBuddy | `codebuddy` | `.codebuddy/skills/` | `~/.codebuddy/skills/` |
|
|
219
219
|
| Codex | `codex` | `.agents/skills/` | `~/.codex/skills/` |
|
|
220
220
|
| Command Code | `command-code` | `.commandcode/skills/` | `~/.commandcode/skills/` |
|
package/dist/cli.mjs
CHANGED
|
@@ -21,6 +21,13 @@ import { access, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpat
|
|
|
21
21
|
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
22
22
|
function getOwnerRepo(parsed) {
|
|
23
23
|
if (parsed.type === "local") return null;
|
|
24
|
+
const sshMatch = parsed.url.match(/^git@[^:]+:(.+)$/);
|
|
25
|
+
if (sshMatch) {
|
|
26
|
+
let path = sshMatch[1];
|
|
27
|
+
path = path.replace(/\.git$/, "");
|
|
28
|
+
if (path.includes("/")) return path;
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
24
31
|
if (!parsed.url.startsWith("http://") && !parsed.url.startsWith("https://")) return null;
|
|
25
32
|
try {
|
|
26
33
|
let path = new URL(parsed.url).pathname.slice(1);
|
|
@@ -46,6 +53,11 @@ async function isRepoPrivate(owner, repo) {
|
|
|
46
53
|
return null;
|
|
47
54
|
}
|
|
48
55
|
}
|
|
56
|
+
function sanitizeSubpath(subpath) {
|
|
57
|
+
const segments = subpath.replace(/\\/g, "/").split("/");
|
|
58
|
+
for (const segment of segments) if (segment === "..") throw new Error(`Unsafe subpath: "${subpath}" contains path traversal segments. Subpaths must not contain ".." components.`);
|
|
59
|
+
return subpath;
|
|
60
|
+
}
|
|
49
61
|
function isLocalPath(input) {
|
|
50
62
|
return isAbsolute(input) || input.startsWith("./") || input.startsWith("../") || input === "." || input === ".." || /^[a-zA-Z]:[/\\]/.test(input);
|
|
51
63
|
}
|
|
@@ -53,6 +65,10 @@ const SOURCE_ALIASES = { "coinbase/agentWallet": "coinbase/agentic-wallet-skills
|
|
|
53
65
|
function parseSource(input) {
|
|
54
66
|
const alias = SOURCE_ALIASES[input];
|
|
55
67
|
if (alias) input = alias;
|
|
68
|
+
const githubPrefixMatch = input.match(/^github:(.+)$/);
|
|
69
|
+
if (githubPrefixMatch) return parseSource(githubPrefixMatch[1]);
|
|
70
|
+
const gitlabPrefixMatch = input.match(/^gitlab:(.+)$/);
|
|
71
|
+
if (gitlabPrefixMatch) return parseSource(`https://gitlab.com/${gitlabPrefixMatch[1]}`);
|
|
56
72
|
if (isLocalPath(input)) {
|
|
57
73
|
const resolvedPath = resolve(input);
|
|
58
74
|
return {
|
|
@@ -68,7 +84,7 @@ function parseSource(input) {
|
|
|
68
84
|
type: "github",
|
|
69
85
|
url: `https://github.com/${owner}/${repo}.git`,
|
|
70
86
|
ref,
|
|
71
|
-
subpath
|
|
87
|
+
subpath: subpath ? sanitizeSubpath(subpath) : subpath
|
|
72
88
|
};
|
|
73
89
|
}
|
|
74
90
|
const githubTreeMatch = input.match(/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)$/);
|
|
@@ -95,7 +111,7 @@ function parseSource(input) {
|
|
|
95
111
|
type: "gitlab",
|
|
96
112
|
url: `${protocol}://${hostname}/${repoPath.replace(/\.git$/, "")}.git`,
|
|
97
113
|
ref,
|
|
98
|
-
subpath
|
|
114
|
+
subpath: subpath ? sanitizeSubpath(subpath) : subpath
|
|
99
115
|
};
|
|
100
116
|
}
|
|
101
117
|
const gitlabTreeMatch = input.match(/^(https?):\/\/([^/]+)\/(.+?)\/-\/tree\/([^/]+)$/);
|
|
@@ -130,7 +146,7 @@ function parseSource(input) {
|
|
|
130
146
|
return {
|
|
131
147
|
type: "github",
|
|
132
148
|
url: `https://github.com/${owner}/${repo}.git`,
|
|
133
|
-
subpath
|
|
149
|
+
subpath: subpath ? sanitizeSubpath(subpath) : subpath
|
|
134
150
|
};
|
|
135
151
|
}
|
|
136
152
|
if (isWellKnownUrl(input)) return {
|
|
@@ -486,9 +502,15 @@ async function findSkillDirs(dir, depth = 0, maxDepth = 5) {
|
|
|
486
502
|
return [];
|
|
487
503
|
}
|
|
488
504
|
}
|
|
505
|
+
function isSubpathSafe(basePath, subpath) {
|
|
506
|
+
const normalizedBase = normalize(resolve(basePath));
|
|
507
|
+
const normalizedTarget = normalize(resolve(join(basePath, subpath)));
|
|
508
|
+
return normalizedTarget.startsWith(normalizedBase + sep) || normalizedTarget === normalizedBase;
|
|
509
|
+
}
|
|
489
510
|
async function discoverSkills(basePath, subpath, options) {
|
|
490
511
|
const skills = [];
|
|
491
512
|
const seenNames = /* @__PURE__ */ new Set();
|
|
513
|
+
if (subpath && !isSubpathSafe(basePath, subpath)) throw new Error(`Invalid subpath: "${subpath}" resolves outside the repository directory. Subpath must not contain ".." segments that escape the base path.`);
|
|
492
514
|
const searchPath = subpath ? join(basePath, subpath) : basePath;
|
|
493
515
|
const pluginGroupings = await getPluginGroupings(searchPath);
|
|
494
516
|
const enhanceSkill = (skill) => {
|
|
@@ -902,6 +924,15 @@ const agents = {
|
|
|
902
924
|
return existsSync(join(home, ".trae-cn"));
|
|
903
925
|
}
|
|
904
926
|
},
|
|
927
|
+
warp: {
|
|
928
|
+
name: "warp",
|
|
929
|
+
displayName: "Warp",
|
|
930
|
+
skillsDir: ".agents/skills",
|
|
931
|
+
globalSkillsDir: join(home, ".agents/skills"),
|
|
932
|
+
detectInstalled: async () => {
|
|
933
|
+
return existsSync(join(home, ".warp"));
|
|
934
|
+
}
|
|
935
|
+
},
|
|
905
936
|
windsurf: {
|
|
906
937
|
name: "windsurf",
|
|
907
938
|
displayName: "Windsurf",
|
|
@@ -1114,10 +1145,14 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
1114
1145
|
}
|
|
1115
1146
|
}
|
|
1116
1147
|
const EXCLUDE_FILES = new Set(["metadata.json"]);
|
|
1117
|
-
const EXCLUDE_DIRS = new Set([
|
|
1148
|
+
const EXCLUDE_DIRS = new Set([
|
|
1149
|
+
".git",
|
|
1150
|
+
"__pycache__",
|
|
1151
|
+
"__pypackages__"
|
|
1152
|
+
]);
|
|
1118
1153
|
const isExcluded = (name, isDirectory = false) => {
|
|
1119
1154
|
if (EXCLUDE_FILES.has(name)) return true;
|
|
1120
|
-
if (name.startsWith("
|
|
1155
|
+
if (name.startsWith(".")) return true;
|
|
1121
1156
|
if (isDirectory && EXCLUDE_DIRS.has(name)) return true;
|
|
1122
1157
|
return false;
|
|
1123
1158
|
};
|
|
@@ -1128,10 +1163,15 @@ async function copyDirectory(src, dest) {
|
|
|
1128
1163
|
const srcPath = join(src, entry.name);
|
|
1129
1164
|
const destPath = join(dest, entry.name);
|
|
1130
1165
|
if (entry.isDirectory()) await copyDirectory(srcPath, destPath);
|
|
1131
|
-
else
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1166
|
+
else try {
|
|
1167
|
+
await cp(srcPath, destPath, {
|
|
1168
|
+
dereference: true,
|
|
1169
|
+
recursive: true
|
|
1170
|
+
});
|
|
1171
|
+
} catch (err) {
|
|
1172
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT" && entry.isSymbolicLink()) console.warn(`Skipping broken symlink: ${srcPath}`);
|
|
1173
|
+
else throw err;
|
|
1174
|
+
}
|
|
1135
1175
|
}));
|
|
1136
1176
|
}
|
|
1137
1177
|
async function isSkillInstalled(skillName, agentType, options = {}) {
|
|
@@ -1579,6 +1619,8 @@ const AGENTS_DIR$1 = ".agents";
|
|
|
1579
1619
|
const LOCK_FILE$1 = ".skill-lock.json";
|
|
1580
1620
|
const CURRENT_VERSION$1 = 3;
|
|
1581
1621
|
function getSkillLockPath$1() {
|
|
1622
|
+
const xdgStateHome = process.env.XDG_STATE_HOME;
|
|
1623
|
+
if (xdgStateHome) return join(xdgStateHome, "skills", LOCK_FILE$1);
|
|
1582
1624
|
return join(homedir(), AGENTS_DIR$1, LOCK_FILE$1);
|
|
1583
1625
|
}
|
|
1584
1626
|
async function readSkillLock$1() {
|
|
@@ -1751,7 +1793,7 @@ function createEmptyLocalLock() {
|
|
|
1751
1793
|
skills: {}
|
|
1752
1794
|
};
|
|
1753
1795
|
}
|
|
1754
|
-
var version$1 = "1.4.
|
|
1796
|
+
var version$1 = "1.4.5";
|
|
1755
1797
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
1756
1798
|
async function isSourcePrivate(source) {
|
|
1757
1799
|
const ownerRepo = parseOwnerRepo(source);
|
|
@@ -2048,7 +2090,8 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2048
2090
|
installGlobally = scope;
|
|
2049
2091
|
}
|
|
2050
2092
|
let installMode = options.copy ? "copy" : "symlink";
|
|
2051
|
-
|
|
2093
|
+
const uniqueDirs = new Set(targetAgents.map((a) => agents[a].skillsDir));
|
|
2094
|
+
if (!options.copy && !options.yes && uniqueDirs.size > 1) {
|
|
2052
2095
|
const modeChoice = await ve({
|
|
2053
2096
|
message: "Installation method",
|
|
2054
2097
|
options: [{
|
|
@@ -2066,7 +2109,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2066
2109
|
process.exit(0);
|
|
2067
2110
|
}
|
|
2068
2111
|
installMode = modeChoice;
|
|
2069
|
-
}
|
|
2112
|
+
} else if (uniqueDirs.size <= 1) installMode = "copy";
|
|
2070
2113
|
const cwd = process.cwd();
|
|
2071
2114
|
const summaryLines = [];
|
|
2072
2115
|
targetAgents.map((a) => agents[a].displayName);
|
|
@@ -2440,7 +2483,8 @@ async function runAdd(args, options = {}) {
|
|
|
2440
2483
|
installGlobally = scope;
|
|
2441
2484
|
}
|
|
2442
2485
|
let installMode = options.copy ? "copy" : "symlink";
|
|
2443
|
-
|
|
2486
|
+
const uniqueDirs = new Set(targetAgents.map((a) => agents[a].skillsDir));
|
|
2487
|
+
if (!options.copy && !options.yes && uniqueDirs.size > 1) {
|
|
2444
2488
|
const modeChoice = await ve({
|
|
2445
2489
|
message: "Installation method",
|
|
2446
2490
|
options: [{
|
|
@@ -2459,7 +2503,7 @@ async function runAdd(args, options = {}) {
|
|
|
2459
2503
|
process.exit(0);
|
|
2460
2504
|
}
|
|
2461
2505
|
installMode = modeChoice;
|
|
2462
|
-
}
|
|
2506
|
+
} else if (uniqueDirs.size <= 1) installMode = "copy";
|
|
2463
2507
|
const cwd = process.cwd();
|
|
2464
2508
|
const summaryLines = [];
|
|
2465
2509
|
targetAgents.map((a) => agents[a].displayName);
|
|
@@ -2552,6 +2596,7 @@ async function runAdd(args, options = {}) {
|
|
|
2552
2596
|
skillFiles[skill.name] = relativePath;
|
|
2553
2597
|
}
|
|
2554
2598
|
const normalizedSource = getOwnerRepo(parsed);
|
|
2599
|
+
const lockSource = parsed.url.startsWith("git@") ? parsed.url : normalizedSource;
|
|
2555
2600
|
if (normalizedSource) {
|
|
2556
2601
|
const ownerRepo = parseOwnerRepo(normalizedSource);
|
|
2557
2602
|
if (ownerRepo) {
|
|
@@ -2580,11 +2625,11 @@ async function runAdd(args, options = {}) {
|
|
|
2580
2625
|
let skillFolderHash = "";
|
|
2581
2626
|
const skillPathValue = skillFiles[skill.name];
|
|
2582
2627
|
if (parsed.type === "github" && skillPathValue) {
|
|
2583
|
-
const hash = await fetchSkillFolderHash(normalizedSource, skillPathValue);
|
|
2628
|
+
const hash = await fetchSkillFolderHash(normalizedSource, skillPathValue, getGitHubToken());
|
|
2584
2629
|
if (hash) skillFolderHash = hash;
|
|
2585
2630
|
}
|
|
2586
2631
|
await addSkillToLock(skill.name, {
|
|
2587
|
-
source: normalizedSource,
|
|
2632
|
+
source: lockSource || normalizedSource,
|
|
2588
2633
|
sourceType: parsed.type,
|
|
2589
2634
|
sourceUrl: parsed.url,
|
|
2590
2635
|
skillPath: skillPathValue,
|
|
@@ -2601,7 +2646,7 @@ async function runAdd(args, options = {}) {
|
|
|
2601
2646
|
if (successfulSkillNames.has(skillDisplayName)) try {
|
|
2602
2647
|
const computedHash = await computeSkillFolderHash(skill.path);
|
|
2603
2648
|
await addSkillToLocalLock(skill.name, {
|
|
2604
|
-
source:
|
|
2649
|
+
source: lockSource || parsed.url,
|
|
2605
2650
|
sourceType: parsed.type,
|
|
2606
2651
|
computedHash
|
|
2607
2652
|
}, cwd);
|
|
@@ -2790,7 +2835,7 @@ async function searchSkillsAPI(query) {
|
|
|
2790
2835
|
slug: skill.id,
|
|
2791
2836
|
source: skill.source || "",
|
|
2792
2837
|
installs: skill.installs
|
|
2793
|
-
}));
|
|
2838
|
+
})).sort((a, b) => (b.installs || 0) - (a.installs || 0));
|
|
2794
2839
|
} catch {
|
|
2795
2840
|
return [];
|
|
2796
2841
|
}
|
|
@@ -3346,6 +3391,7 @@ function parseListOptions(args) {
|
|
|
3346
3391
|
for (let i = 0; i < args.length; i++) {
|
|
3347
3392
|
const arg = args[i];
|
|
3348
3393
|
if (arg === "-g" || arg === "--global") options.global = true;
|
|
3394
|
+
else if (arg === "--json") options.json = true;
|
|
3349
3395
|
else if (arg === "-a" || arg === "--agent") {
|
|
3350
3396
|
options.agent = options.agent || [];
|
|
3351
3397
|
while (i + 1 < args.length && !args[i + 1].startsWith("-")) options.agent.push(args[++i]);
|
|
@@ -3371,10 +3417,24 @@ async function runList(args) {
|
|
|
3371
3417
|
global: scope,
|
|
3372
3418
|
agentFilter
|
|
3373
3419
|
});
|
|
3420
|
+
if (options.json) {
|
|
3421
|
+
const jsonOutput = installedSkills.map((skill) => ({
|
|
3422
|
+
name: skill.name,
|
|
3423
|
+
path: skill.canonicalPath,
|
|
3424
|
+
scope: skill.scope,
|
|
3425
|
+
agents: skill.agents.map((a) => agents[a].displayName)
|
|
3426
|
+
}));
|
|
3427
|
+
console.log(JSON.stringify(jsonOutput, null, 2));
|
|
3428
|
+
return;
|
|
3429
|
+
}
|
|
3374
3430
|
const lockedSkills = await getAllLockedSkills();
|
|
3375
3431
|
const cwd = process.cwd();
|
|
3376
3432
|
const scopeLabel = scope ? "Global" : "Project";
|
|
3377
3433
|
if (installedSkills.length === 0) {
|
|
3434
|
+
if (options.json) {
|
|
3435
|
+
console.log("[]");
|
|
3436
|
+
return;
|
|
3437
|
+
}
|
|
3378
3438
|
console.log(`${DIM$1}No ${scopeLabel.toLowerCase()} skills found.${RESET$1}`);
|
|
3379
3439
|
if (scope) console.log(`${DIM$1}Try listing project skills without -g${RESET$1}`);
|
|
3380
3440
|
else console.log(`${DIM$1}Try listing global skills with -g${RESET$1}`);
|
|
@@ -3713,6 +3773,7 @@ ${BOLD}Experimental Sync Options:${RESET}
|
|
|
3713
3773
|
${BOLD}List Options:${RESET}
|
|
3714
3774
|
-g, --global List global skills (default: project)
|
|
3715
3775
|
-a, --agent <agents> Filter by specific agents
|
|
3776
|
+
--json Output as JSON (machine-readable, no ANSI codes)
|
|
3716
3777
|
|
|
3717
3778
|
${BOLD}Options:${RESET}
|
|
3718
3779
|
--help, -h Show this help message
|
|
@@ -3729,6 +3790,7 @@ ${BOLD}Examples:${RESET}
|
|
|
3729
3790
|
${DIM}$${RESET} skills list ${DIM}# list project skills${RESET}
|
|
3730
3791
|
${DIM}$${RESET} skills ls -g ${DIM}# list global skills${RESET}
|
|
3731
3792
|
${DIM}$${RESET} skills ls -a claude-code ${DIM}# filter by agent${RESET}
|
|
3793
|
+
${DIM}$${RESET} skills ls --json ${DIM}# JSON output${RESET}
|
|
3732
3794
|
${DIM}$${RESET} skills find ${DIM}# interactive search${RESET}
|
|
3733
3795
|
${DIM}$${RESET} skills find typescript ${DIM}# search by keyword${RESET}
|
|
3734
3796
|
${DIM}$${RESET} skills check
|
|
@@ -3822,6 +3884,8 @@ const AGENTS_DIR = ".agents";
|
|
|
3822
3884
|
const LOCK_FILE = ".skill-lock.json";
|
|
3823
3885
|
const CURRENT_LOCK_VERSION = 3;
|
|
3824
3886
|
function getSkillLockPath() {
|
|
3887
|
+
const xdgStateHome = process.env.XDG_STATE_HOME;
|
|
3888
|
+
if (xdgStateHome) return join(xdgStateHome, "skills", LOCK_FILE);
|
|
3825
3889
|
return join(homedir(), AGENTS_DIR, LOCK_FILE);
|
|
3826
3890
|
}
|
|
3827
3891
|
function readSkillLock() {
|
|
@@ -3845,6 +3909,22 @@ function readSkillLock() {
|
|
|
3845
3909
|
};
|
|
3846
3910
|
}
|
|
3847
3911
|
}
|
|
3912
|
+
function getSkipReason(entry) {
|
|
3913
|
+
if (entry.sourceType === "local") return "Local path";
|
|
3914
|
+
if (entry.sourceType === "git") return "Git URL (hash tracking not supported)";
|
|
3915
|
+
if (!entry.skillFolderHash) return "No version hash available";
|
|
3916
|
+
if (!entry.skillPath) return "No skill path recorded";
|
|
3917
|
+
return "No version tracking";
|
|
3918
|
+
}
|
|
3919
|
+
function printSkippedSkills(skipped) {
|
|
3920
|
+
if (skipped.length === 0) return;
|
|
3921
|
+
console.log();
|
|
3922
|
+
console.log(`${DIM}${skipped.length} skill(s) cannot be checked automatically:${RESET}`);
|
|
3923
|
+
for (const skill of skipped) {
|
|
3924
|
+
console.log(` ${TEXT}•${RESET} ${skill.name} ${DIM}(${skill.reason})${RESET}`);
|
|
3925
|
+
console.log(` ${DIM}To update: ${TEXT}npx skills add ${skill.sourceUrl} -g -y${RESET}`);
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3848
3928
|
async function runCheck(args = []) {
|
|
3849
3929
|
console.log(`${TEXT}Checking for skill updates...${RESET}`);
|
|
3850
3930
|
console.log();
|
|
@@ -3857,12 +3937,16 @@ async function runCheck(args = []) {
|
|
|
3857
3937
|
}
|
|
3858
3938
|
const token = getGitHubToken();
|
|
3859
3939
|
const skillsBySource = /* @__PURE__ */ new Map();
|
|
3860
|
-
|
|
3940
|
+
const skipped = [];
|
|
3861
3941
|
for (const skillName of skillNames) {
|
|
3862
3942
|
const entry = lock.skills[skillName];
|
|
3863
3943
|
if (!entry) continue;
|
|
3864
|
-
if (
|
|
3865
|
-
|
|
3944
|
+
if (!entry.skillFolderHash || !entry.skillPath) {
|
|
3945
|
+
skipped.push({
|
|
3946
|
+
name: skillName,
|
|
3947
|
+
reason: getSkipReason(entry),
|
|
3948
|
+
sourceUrl: entry.sourceUrl
|
|
3949
|
+
});
|
|
3866
3950
|
continue;
|
|
3867
3951
|
}
|
|
3868
3952
|
const existing = skillsBySource.get(entry.source) || [];
|
|
@@ -3872,9 +3956,10 @@ async function runCheck(args = []) {
|
|
|
3872
3956
|
});
|
|
3873
3957
|
skillsBySource.set(entry.source, existing);
|
|
3874
3958
|
}
|
|
3875
|
-
const totalSkills = skillNames.length -
|
|
3959
|
+
const totalSkills = skillNames.length - skipped.length;
|
|
3876
3960
|
if (totalSkills === 0) {
|
|
3877
3961
|
console.log(`${DIM}No GitHub skills to check.${RESET}`);
|
|
3962
|
+
printSkippedSkills(skipped);
|
|
3878
3963
|
return;
|
|
3879
3964
|
}
|
|
3880
3965
|
console.log(`${DIM}Checking ${totalSkills} skill(s) for updates...${RESET}`);
|
|
@@ -3917,6 +4002,7 @@ async function runCheck(args = []) {
|
|
|
3917
4002
|
console.log();
|
|
3918
4003
|
console.log(`${DIM}Could not check ${errors.length} skill(s) (may need reinstall)${RESET}`);
|
|
3919
4004
|
}
|
|
4005
|
+
printSkippedSkills(skipped);
|
|
3920
4006
|
track({
|
|
3921
4007
|
event: "check",
|
|
3922
4008
|
skillCount: String(totalSkills),
|
|
@@ -3936,12 +4022,18 @@ async function runUpdate() {
|
|
|
3936
4022
|
}
|
|
3937
4023
|
const token = getGitHubToken();
|
|
3938
4024
|
const updates = [];
|
|
3939
|
-
|
|
4025
|
+
const skipped = [];
|
|
3940
4026
|
for (const skillName of skillNames) {
|
|
3941
4027
|
const entry = lock.skills[skillName];
|
|
3942
4028
|
if (!entry) continue;
|
|
3943
|
-
if (
|
|
3944
|
-
|
|
4029
|
+
if (!entry.skillFolderHash || !entry.skillPath) {
|
|
4030
|
+
skipped.push({
|
|
4031
|
+
name: skillName,
|
|
4032
|
+
reason: getSkipReason(entry),
|
|
4033
|
+
sourceUrl: entry.sourceUrl
|
|
4034
|
+
});
|
|
4035
|
+
continue;
|
|
4036
|
+
}
|
|
3945
4037
|
try {
|
|
3946
4038
|
const latestHash = await fetchSkillFolderHash(entry.source, entry.skillPath, token);
|
|
3947
4039
|
if (latestHash && latestHash !== entry.skillFolderHash) updates.push({
|
|
@@ -3951,8 +4043,9 @@ async function runUpdate() {
|
|
|
3951
4043
|
});
|
|
3952
4044
|
} catch {}
|
|
3953
4045
|
}
|
|
3954
|
-
if (
|
|
4046
|
+
if (skillNames.length - skipped.length === 0) {
|
|
3955
4047
|
console.log(`${DIM}No skills to check.${RESET}`);
|
|
4048
|
+
printSkippedSkills(skipped);
|
|
3956
4049
|
return;
|
|
3957
4050
|
}
|
|
3958
4051
|
if (updates.length === 0) {
|
|
@@ -3982,11 +4075,14 @@ async function runUpdate() {
|
|
|
3982
4075
|
installUrl,
|
|
3983
4076
|
"-g",
|
|
3984
4077
|
"-y"
|
|
3985
|
-
], {
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
4078
|
+
], {
|
|
4079
|
+
stdio: [
|
|
4080
|
+
"inherit",
|
|
4081
|
+
"pipe",
|
|
4082
|
+
"pipe"
|
|
4083
|
+
],
|
|
4084
|
+
shell: process.platform === "win32"
|
|
4085
|
+
}).status === 0) {
|
|
3990
4086
|
successCount++;
|
|
3991
4087
|
console.log(` ${TEXT}✓${RESET} Updated ${update.name}`);
|
|
3992
4088
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skills",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.5",
|
|
4
4
|
"description": "The open agent skills ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
"roo",
|
|
72
72
|
"trae",
|
|
73
73
|
"trae-cn",
|
|
74
|
+
"warp",
|
|
74
75
|
"windsurf",
|
|
75
76
|
"zencoder",
|
|
76
77
|
"neovate",
|