@bud-fe/skills 0.0.1 → 0.0.3
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 +18 -9
- package/dist/cli.mjs +211 -87
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
# skills-x
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Forked from [vercel-labs/skills](https://github.com/vercel-labs/skills).
|
|
4
|
+
|
|
5
|
+
## Changes based on upstream
|
|
6
|
+
|
|
7
|
+
### ADDED
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
- `add-c` 命令:支持按名称从默认源的 `commands/` 目录安装 slash command 文件
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- `
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
-
|
|
11
|
+
### MODIFIED
|
|
12
|
+
|
|
13
|
+
- `add` 命令
|
|
14
|
+
- 支持在未提供源但携带标志(如 `--list` 和 `--all`)时,自动解析至默认源
|
|
15
|
+
- 将简单标识符(如 `code-review`)映射到默认源,而显式源(`owner/repo`、URL、本地路径)保持原有行为
|
|
16
|
+
- `find` 命令
|
|
17
|
+
- 无参数时默认从默认源搜索
|
|
18
|
+
- `-g` / `--global` 搜索 [skills.sh](https://skills.sh)(即原逻辑)
|
|
19
|
+
- `check` 和 `update`
|
|
20
|
+
- 支持非 GitHub 源(如 GitLab、通用 Git),采用基于内容的内容哈希(SHA-256)进行更新检测
|
|
14
21
|
|
|
15
22
|
---
|
|
16
23
|
|
|
24
|
+
The CLI for the open agent skills, commands ecosystem.
|
|
25
|
+
|
|
17
26
|
<!-- agent-list:start -->
|
|
18
27
|
|
|
19
28
|
Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and [37 more](#available-agents).
|
package/dist/cli.mjs
CHANGED
|
@@ -19,7 +19,7 @@ import { access, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpat
|
|
|
19
19
|
import * as readline from "readline";
|
|
20
20
|
import { Writable } from "stream";
|
|
21
21
|
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
22
|
-
var version$1 = "0.0.
|
|
22
|
+
var version$1 = "0.0.3";
|
|
23
23
|
const home = homedir();
|
|
24
24
|
const configHome = xdgConfig ?? join(home, ".config");
|
|
25
25
|
const codexHome = process.env.CODEX_HOME?.trim() || join(home, ".codex");
|
|
@@ -104,6 +104,8 @@ const agents = {
|
|
|
104
104
|
displayName: "Codex",
|
|
105
105
|
skillsDir: ".agents/skills",
|
|
106
106
|
globalSkillsDir: join(codexHome, "skills"),
|
|
107
|
+
commandsDir: ".codex/prompts",
|
|
108
|
+
globalCommandsDir: join(codexHome, "prompts"),
|
|
107
109
|
detectInstalled: async () => {
|
|
108
110
|
return existsSync(codexHome) || existsSync("/etc/codex");
|
|
109
111
|
}
|
|
@@ -2322,6 +2324,33 @@ async function selectAgentsInteractive(options) {
|
|
|
2322
2324
|
return selected;
|
|
2323
2325
|
}
|
|
2324
2326
|
setVersion(version$1);
|
|
2327
|
+
async function resolveGlobalLockHashData(params, deps = {
|
|
2328
|
+
fetchGitHubHash: fetchSkillFolderHash,
|
|
2329
|
+
computeFolderHash: computeSkillFolderHash
|
|
2330
|
+
}) {
|
|
2331
|
+
if (params.sourceType === "github") {
|
|
2332
|
+
let skillFolderHash = "";
|
|
2333
|
+
if (params.normalizedSource && params.skillPathValue) try {
|
|
2334
|
+
const hash = await deps.fetchGitHubHash(params.normalizedSource, params.skillPathValue);
|
|
2335
|
+
if (hash) skillFolderHash = hash;
|
|
2336
|
+
} catch {}
|
|
2337
|
+
return {
|
|
2338
|
+
skillFolderHash,
|
|
2339
|
+
hashMethod: "github-tree-sha"
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
if (params.sourceType === "git" || params.sourceType === "gitlab") {
|
|
2343
|
+
let skillFolderHash = "";
|
|
2344
|
+
if (params.installDir) try {
|
|
2345
|
+
skillFolderHash = await deps.computeFolderHash(params.installDir);
|
|
2346
|
+
} catch {}
|
|
2347
|
+
return {
|
|
2348
|
+
skillFolderHash,
|
|
2349
|
+
hashMethod: "content-sha256"
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
return { skillFolderHash: "" };
|
|
2353
|
+
}
|
|
2325
2354
|
async function handleRemoteSkill(source, url, options, spinner) {
|
|
2326
2355
|
const provider = findProvider(url);
|
|
2327
2356
|
if (!provider) {
|
|
@@ -2494,7 +2523,9 @@ async function handleRemoteSkill(source, url, options, spinner) {
|
|
|
2494
2523
|
});
|
|
2495
2524
|
if (successful.length > 0 && installGlobally) try {
|
|
2496
2525
|
let skillFolderHash = "";
|
|
2526
|
+
let hashMethod;
|
|
2497
2527
|
if (remoteSkill.providerId === "github") {
|
|
2528
|
+
hashMethod = "github-tree-sha";
|
|
2498
2529
|
const hash = await fetchSkillFolderHash(remoteSkill.sourceIdentifier, url);
|
|
2499
2530
|
if (hash) skillFolderHash = hash;
|
|
2500
2531
|
}
|
|
@@ -2502,7 +2533,8 @@ async function handleRemoteSkill(source, url, options, spinner) {
|
|
|
2502
2533
|
source: remoteSkill.sourceIdentifier,
|
|
2503
2534
|
sourceType: remoteSkill.providerId,
|
|
2504
2535
|
sourceUrl: url,
|
|
2505
|
-
skillFolderHash
|
|
2536
|
+
skillFolderHash,
|
|
2537
|
+
hashMethod
|
|
2506
2538
|
});
|
|
2507
2539
|
} catch {}
|
|
2508
2540
|
if (successful.length > 0 && !installGlobally) try {
|
|
@@ -3329,18 +3361,22 @@ async function runAdd(args, options = {}) {
|
|
|
3329
3361
|
for (const skill of selectedSkills) {
|
|
3330
3362
|
const skillDisplayName = getSkillDisplayName(skill);
|
|
3331
3363
|
if (successfulSkillNames.has(skillDisplayName)) try {
|
|
3332
|
-
let skillFolderHash = "";
|
|
3333
3364
|
const skillPathValue = skillFiles[skill.name];
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3365
|
+
const matchingResult = successful.find((r) => r.skill === skillDisplayName);
|
|
3366
|
+
const installDir = matchingResult?.canonicalPath || matchingResult?.path;
|
|
3367
|
+
const { skillFolderHash, hashMethod } = await resolveGlobalLockHashData({
|
|
3368
|
+
sourceType: parsed.type,
|
|
3369
|
+
normalizedSource,
|
|
3370
|
+
skillPathValue,
|
|
3371
|
+
installDir
|
|
3372
|
+
});
|
|
3338
3373
|
await addSkillToLock(skill.name, {
|
|
3339
3374
|
source: normalizedSource,
|
|
3340
3375
|
sourceType: parsed.type,
|
|
3341
3376
|
sourceUrl: parsed.url,
|
|
3342
3377
|
skillPath: skillPathValue,
|
|
3343
|
-
skillFolderHash
|
|
3378
|
+
skillFolderHash,
|
|
3379
|
+
hashMethod
|
|
3344
3380
|
});
|
|
3345
3381
|
} catch {}
|
|
3346
3382
|
}
|
|
@@ -3642,13 +3678,13 @@ async function runAddCommand(args, options = {}) {
|
|
|
3642
3678
|
const modeChoice = await ve({
|
|
3643
3679
|
message: "Installation method",
|
|
3644
3680
|
options: [{
|
|
3645
|
-
value: "symlink",
|
|
3646
|
-
label: "Symlink (Recommended)",
|
|
3647
|
-
hint: "Single source of truth, easy updates"
|
|
3648
|
-
}, {
|
|
3649
3681
|
value: "copy",
|
|
3650
3682
|
label: "Copy to all agents",
|
|
3651
3683
|
hint: "Independent copies for each agent"
|
|
3684
|
+
}, {
|
|
3685
|
+
value: "symlink",
|
|
3686
|
+
label: "Symlink (Cline, Kilo Code not supported)",
|
|
3687
|
+
hint: "Single source of truth, easy updates"
|
|
3652
3688
|
}]
|
|
3653
3689
|
});
|
|
3654
3690
|
if (pD(modeChoice)) {
|
|
@@ -4826,6 +4862,142 @@ function parseRemoveOptions(args) {
|
|
|
4826
4862
|
options
|
|
4827
4863
|
};
|
|
4828
4864
|
}
|
|
4865
|
+
const DEFAULT_DEPS = {
|
|
4866
|
+
fetchGitHubHash: fetchSkillFolderHash,
|
|
4867
|
+
cloneRepo,
|
|
4868
|
+
cleanupTempDir,
|
|
4869
|
+
computeFolderHash: computeSkillFolderHash,
|
|
4870
|
+
pathExists: existsSync
|
|
4871
|
+
};
|
|
4872
|
+
function normalizeSkillFolderPath(skillPath) {
|
|
4873
|
+
let folderPath = skillPath.replace(/\\/g, "/");
|
|
4874
|
+
if (folderPath.endsWith("/SKILL.md")) folderPath = folderPath.slice(0, -9);
|
|
4875
|
+
else if (folderPath.endsWith("SKILL.md")) folderPath = folderPath.slice(0, -8);
|
|
4876
|
+
if (folderPath.endsWith("/")) folderPath = folderPath.slice(0, -1);
|
|
4877
|
+
return folderPath;
|
|
4878
|
+
}
|
|
4879
|
+
function resolveHashMethod(entry) {
|
|
4880
|
+
if (entry.hashMethod === "github-tree-sha" || entry.hashMethod === "content-sha256") return entry.hashMethod;
|
|
4881
|
+
if (entry.sourceType === "github") return "github-tree-sha";
|
|
4882
|
+
if ((entry.sourceType === "git" || entry.sourceType === "gitlab") && !!entry.skillFolderHash) return "content-sha256";
|
|
4883
|
+
return null;
|
|
4884
|
+
}
|
|
4885
|
+
async function detectSkillUpdates(lock, options = {}) {
|
|
4886
|
+
const deps = {
|
|
4887
|
+
...DEFAULT_DEPS,
|
|
4888
|
+
...options.deps || {}
|
|
4889
|
+
};
|
|
4890
|
+
const githubSkillsBySource = /* @__PURE__ */ new Map();
|
|
4891
|
+
const contentSkillsBySourceUrl = /* @__PURE__ */ new Map();
|
|
4892
|
+
let skippedMissingMetadata = 0;
|
|
4893
|
+
for (const [name, entry] of Object.entries(lock.skills)) {
|
|
4894
|
+
const hashMethod = resolveHashMethod(entry);
|
|
4895
|
+
if (!hashMethod || !entry.skillPath || !entry.skillFolderHash) {
|
|
4896
|
+
skippedMissingMetadata++;
|
|
4897
|
+
continue;
|
|
4898
|
+
}
|
|
4899
|
+
if (hashMethod === "github-tree-sha") {
|
|
4900
|
+
const bucket = githubSkillsBySource.get(entry.source) || [];
|
|
4901
|
+
bucket.push({
|
|
4902
|
+
name,
|
|
4903
|
+
entry
|
|
4904
|
+
});
|
|
4905
|
+
githubSkillsBySource.set(entry.source, bucket);
|
|
4906
|
+
continue;
|
|
4907
|
+
}
|
|
4908
|
+
if (!entry.sourceUrl) {
|
|
4909
|
+
skippedMissingMetadata++;
|
|
4910
|
+
continue;
|
|
4911
|
+
}
|
|
4912
|
+
const bucket = contentSkillsBySourceUrl.get(entry.sourceUrl) || [];
|
|
4913
|
+
bucket.push({
|
|
4914
|
+
name,
|
|
4915
|
+
entry
|
|
4916
|
+
});
|
|
4917
|
+
contentSkillsBySourceUrl.set(entry.sourceUrl, bucket);
|
|
4918
|
+
}
|
|
4919
|
+
const updates = [];
|
|
4920
|
+
const errors = [];
|
|
4921
|
+
let checkedCount = 0;
|
|
4922
|
+
for (const [source, skills] of githubSkillsBySource) for (const { name, entry } of skills) {
|
|
4923
|
+
checkedCount++;
|
|
4924
|
+
try {
|
|
4925
|
+
const latestHash = await deps.fetchGitHubHash(source, entry.skillPath, options.githubToken);
|
|
4926
|
+
if (!latestHash) {
|
|
4927
|
+
errors.push({
|
|
4928
|
+
name,
|
|
4929
|
+
source,
|
|
4930
|
+
error: "Could not fetch from GitHub"
|
|
4931
|
+
});
|
|
4932
|
+
continue;
|
|
4933
|
+
}
|
|
4934
|
+
if (latestHash !== entry.skillFolderHash) updates.push({
|
|
4935
|
+
name,
|
|
4936
|
+
source,
|
|
4937
|
+
entry
|
|
4938
|
+
});
|
|
4939
|
+
} catch (err) {
|
|
4940
|
+
errors.push({
|
|
4941
|
+
name,
|
|
4942
|
+
source,
|
|
4943
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
4944
|
+
});
|
|
4945
|
+
}
|
|
4946
|
+
}
|
|
4947
|
+
for (const [sourceUrl, skills] of contentSkillsBySourceUrl) {
|
|
4948
|
+
let tempDir = null;
|
|
4949
|
+
try {
|
|
4950
|
+
tempDir = await deps.cloneRepo(sourceUrl);
|
|
4951
|
+
} catch (err) {
|
|
4952
|
+
const message = err instanceof Error ? err.message : "Failed to clone source repository";
|
|
4953
|
+
for (const { name, entry } of skills) {
|
|
4954
|
+
checkedCount++;
|
|
4955
|
+
errors.push({
|
|
4956
|
+
name,
|
|
4957
|
+
source: entry.source,
|
|
4958
|
+
error: message
|
|
4959
|
+
});
|
|
4960
|
+
}
|
|
4961
|
+
continue;
|
|
4962
|
+
}
|
|
4963
|
+
try {
|
|
4964
|
+
for (const { name, entry } of skills) {
|
|
4965
|
+
checkedCount++;
|
|
4966
|
+
try {
|
|
4967
|
+
const folderPath = normalizeSkillFolderPath(entry.skillPath);
|
|
4968
|
+
const targetDir = folderPath ? join(tempDir, folderPath) : tempDir;
|
|
4969
|
+
if (!deps.pathExists(targetDir)) {
|
|
4970
|
+
errors.push({
|
|
4971
|
+
name,
|
|
4972
|
+
source: entry.source,
|
|
4973
|
+
error: `Skill path not found: ${folderPath}`
|
|
4974
|
+
});
|
|
4975
|
+
continue;
|
|
4976
|
+
}
|
|
4977
|
+
if (await deps.computeFolderHash(targetDir) !== entry.skillFolderHash) updates.push({
|
|
4978
|
+
name,
|
|
4979
|
+
source: entry.source,
|
|
4980
|
+
entry
|
|
4981
|
+
});
|
|
4982
|
+
} catch (err) {
|
|
4983
|
+
errors.push({
|
|
4984
|
+
name,
|
|
4985
|
+
source: entry.source,
|
|
4986
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
4987
|
+
});
|
|
4988
|
+
}
|
|
4989
|
+
}
|
|
4990
|
+
} finally {
|
|
4991
|
+
await deps.cleanupTempDir(tempDir).catch(() => {});
|
|
4992
|
+
}
|
|
4993
|
+
}
|
|
4994
|
+
return {
|
|
4995
|
+
checkedCount,
|
|
4996
|
+
skippedMissingMetadata,
|
|
4997
|
+
updates,
|
|
4998
|
+
errors
|
|
4999
|
+
};
|
|
5000
|
+
}
|
|
4829
5001
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
4830
5002
|
function getVersion() {
|
|
4831
5003
|
try {
|
|
@@ -5080,58 +5252,21 @@ async function runCheck(args = []) {
|
|
|
5080
5252
|
console.log(`${TEXT}Checking for skill updates...${RESET}`);
|
|
5081
5253
|
console.log();
|
|
5082
5254
|
const lock = readSkillLock();
|
|
5083
|
-
|
|
5084
|
-
if (skillNames.length === 0) {
|
|
5255
|
+
if (Object.keys(lock.skills).length === 0) {
|
|
5085
5256
|
console.log(`${DIM}No skills tracked in lock file.${RESET}`);
|
|
5086
5257
|
console.log(`${DIM}Install skills with${RESET} ${TEXT}npx skills add <package>${RESET}`);
|
|
5087
5258
|
return;
|
|
5088
5259
|
}
|
|
5089
|
-
const
|
|
5090
|
-
const
|
|
5091
|
-
let skippedCount = 0;
|
|
5092
|
-
for (const skillName of skillNames) {
|
|
5093
|
-
const entry = lock.skills[skillName];
|
|
5094
|
-
if (!entry) continue;
|
|
5095
|
-
if (entry.sourceType !== "github" || !entry.skillFolderHash || !entry.skillPath) {
|
|
5096
|
-
skippedCount++;
|
|
5097
|
-
continue;
|
|
5098
|
-
}
|
|
5099
|
-
const existing = skillsBySource.get(entry.source) || [];
|
|
5100
|
-
existing.push({
|
|
5101
|
-
name: skillName,
|
|
5102
|
-
entry
|
|
5103
|
-
});
|
|
5104
|
-
skillsBySource.set(entry.source, existing);
|
|
5105
|
-
}
|
|
5106
|
-
const totalSkills = skillNames.length - skippedCount;
|
|
5260
|
+
const result = await detectSkillUpdates(lock, { githubToken: getGitHubToken() });
|
|
5261
|
+
const totalSkills = result.checkedCount;
|
|
5107
5262
|
if (totalSkills === 0) {
|
|
5108
|
-
console.log(`${DIM}No
|
|
5263
|
+
console.log(`${DIM}No skills with update metadata to check.${RESET}`);
|
|
5264
|
+
if (result.skippedMissingMetadata > 0) console.log(`${DIM}${result.skippedMissingMetadata} skill(s) are missing hash metadata (run${RESET} ${TEXT}npx skills add <source> -g${RESET} ${DIM}to reinstall and track updates).${RESET}`);
|
|
5109
5265
|
return;
|
|
5110
5266
|
}
|
|
5111
5267
|
console.log(`${DIM}Checking ${totalSkills} skill(s) for updates...${RESET}`);
|
|
5112
|
-
const updates =
|
|
5113
|
-
const errors =
|
|
5114
|
-
for (const [source, skills] of skillsBySource) for (const { name, entry } of skills) try {
|
|
5115
|
-
const latestHash = await fetchSkillFolderHash(source, entry.skillPath, token);
|
|
5116
|
-
if (!latestHash) {
|
|
5117
|
-
errors.push({
|
|
5118
|
-
name,
|
|
5119
|
-
source,
|
|
5120
|
-
error: "Could not fetch from GitHub"
|
|
5121
|
-
});
|
|
5122
|
-
continue;
|
|
5123
|
-
}
|
|
5124
|
-
if (latestHash !== entry.skillFolderHash) updates.push({
|
|
5125
|
-
name,
|
|
5126
|
-
source
|
|
5127
|
-
});
|
|
5128
|
-
} catch (err) {
|
|
5129
|
-
errors.push({
|
|
5130
|
-
name,
|
|
5131
|
-
source,
|
|
5132
|
-
error: err instanceof Error ? err.message : "Unknown error"
|
|
5133
|
-
});
|
|
5134
|
-
}
|
|
5268
|
+
const updates = result.updates;
|
|
5269
|
+
const errors = result.errors;
|
|
5135
5270
|
console.log();
|
|
5136
5271
|
if (updates.length === 0) console.log(`${TEXT}✓ All skills are up to date${RESET}`);
|
|
5137
5272
|
else {
|
|
@@ -5148,6 +5283,10 @@ async function runCheck(args = []) {
|
|
|
5148
5283
|
console.log();
|
|
5149
5284
|
console.log(`${DIM}Could not check ${errors.length} skill(s) (may need reinstall)${RESET}`);
|
|
5150
5285
|
}
|
|
5286
|
+
if (result.skippedMissingMetadata > 0) {
|
|
5287
|
+
console.log();
|
|
5288
|
+
console.log(`${DIM}Skipped ${result.skippedMissingMetadata} skill(s) missing hash metadata (reinstall to enable update tracking).${RESET}`);
|
|
5289
|
+
}
|
|
5151
5290
|
track({
|
|
5152
5291
|
event: "check",
|
|
5153
5292
|
skillCount: String(totalSkills),
|
|
@@ -5159,31 +5298,16 @@ async function runUpdate() {
|
|
|
5159
5298
|
console.log(`${TEXT}Checking for skill updates...${RESET}`);
|
|
5160
5299
|
console.log();
|
|
5161
5300
|
const lock = readSkillLock();
|
|
5162
|
-
|
|
5163
|
-
if (skillNames.length === 0) {
|
|
5301
|
+
if (Object.keys(lock.skills).length === 0) {
|
|
5164
5302
|
console.log(`${DIM}No skills tracked in lock file.${RESET}`);
|
|
5165
5303
|
console.log(`${DIM}Install skills with${RESET} ${TEXT}npx skills add <package>${RESET}`);
|
|
5166
5304
|
return;
|
|
5167
5305
|
}
|
|
5168
|
-
const
|
|
5169
|
-
const updates =
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
if (!entry) continue;
|
|
5174
|
-
if (entry.sourceType !== "github" || !entry.skillFolderHash || !entry.skillPath) continue;
|
|
5175
|
-
checkedCount++;
|
|
5176
|
-
try {
|
|
5177
|
-
const latestHash = await fetchSkillFolderHash(entry.source, entry.skillPath, token);
|
|
5178
|
-
if (latestHash && latestHash !== entry.skillFolderHash) updates.push({
|
|
5179
|
-
name: skillName,
|
|
5180
|
-
source: entry.source,
|
|
5181
|
-
entry
|
|
5182
|
-
});
|
|
5183
|
-
} catch {}
|
|
5184
|
-
}
|
|
5185
|
-
if (checkedCount === 0) {
|
|
5186
|
-
console.log(`${DIM}No skills to check.${RESET}`);
|
|
5306
|
+
const result = await detectSkillUpdates(lock, { githubToken: getGitHubToken() });
|
|
5307
|
+
const updates = result.updates;
|
|
5308
|
+
if (result.checkedCount === 0) {
|
|
5309
|
+
console.log(`${DIM}No skills with update metadata to check.${RESET}`);
|
|
5310
|
+
if (result.skippedMissingMetadata > 0) console.log(`${DIM}${result.skippedMissingMetadata} skill(s) are missing hash metadata (reinstall to enable update tracking).${RESET}`);
|
|
5187
5311
|
return;
|
|
5188
5312
|
}
|
|
5189
5313
|
if (updates.length === 0) {
|
|
@@ -5198,22 +5322,21 @@ async function runUpdate() {
|
|
|
5198
5322
|
for (const update of updates) {
|
|
5199
5323
|
console.log(`${TEXT}Updating ${update.name}...${RESET}`);
|
|
5200
5324
|
let installUrl = update.entry.sourceUrl;
|
|
5201
|
-
|
|
5325
|
+
const addArgs = [
|
|
5326
|
+
"-y",
|
|
5327
|
+
"skills",
|
|
5328
|
+
"add"
|
|
5329
|
+
];
|
|
5330
|
+
if (update.entry.sourceType === "github" && update.entry.skillPath) {
|
|
5202
5331
|
let skillFolder = update.entry.skillPath;
|
|
5203
5332
|
if (skillFolder.endsWith("/SKILL.md")) skillFolder = skillFolder.slice(0, -9);
|
|
5204
5333
|
else if (skillFolder.endsWith("SKILL.md")) skillFolder = skillFolder.slice(0, -8);
|
|
5205
5334
|
if (skillFolder.endsWith("/")) skillFolder = skillFolder.slice(0, -1);
|
|
5206
5335
|
installUrl = update.entry.sourceUrl.replace(/\.git$/, "").replace(/\/$/, "");
|
|
5207
5336
|
installUrl = `${installUrl}/tree/main/${skillFolder}`;
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
"skills",
|
|
5212
|
-
"add",
|
|
5213
|
-
installUrl,
|
|
5214
|
-
"-g",
|
|
5215
|
-
"-y"
|
|
5216
|
-
], { stdio: [
|
|
5337
|
+
addArgs.push(installUrl, "-g", "-y");
|
|
5338
|
+
} else addArgs.push(installUrl, "--skill", update.name, "-g", "-y");
|
|
5339
|
+
if (spawnSync("npx", addArgs, { stdio: [
|
|
5217
5340
|
"inherit",
|
|
5218
5341
|
"pipe",
|
|
5219
5342
|
"pipe"
|
|
@@ -5228,6 +5351,7 @@ async function runUpdate() {
|
|
|
5228
5351
|
console.log();
|
|
5229
5352
|
if (successCount > 0) console.log(`${TEXT}✓ Updated ${successCount} skill(s)${RESET}`);
|
|
5230
5353
|
if (failCount > 0) console.log(`${DIM}Failed to update ${failCount} skill(s)${RESET}`);
|
|
5354
|
+
if (result.skippedMissingMetadata > 0) console.log(`${DIM}Skipped ${result.skippedMissingMetadata} skill(s) missing hash metadata (reinstall to enable update tracking).${RESET}`);
|
|
5231
5355
|
track({
|
|
5232
5356
|
event: "update",
|
|
5233
5357
|
skillCount: String(updates.length),
|