skillhub 0.1.16 → 0.2.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.
|
@@ -12,18 +12,29 @@ var PLATFORM_PATHS = {
|
|
|
12
12
|
project: ".codex/skills"
|
|
13
13
|
},
|
|
14
14
|
copilot: {
|
|
15
|
-
user: ".github/
|
|
16
|
-
project: ".github/
|
|
15
|
+
user: ".github/instructions",
|
|
16
|
+
project: ".github/instructions"
|
|
17
17
|
},
|
|
18
18
|
cursor: {
|
|
19
|
-
user: ".cursor/
|
|
20
|
-
project: ".cursor/
|
|
19
|
+
user: ".cursor/rules",
|
|
20
|
+
project: ".cursor/rules"
|
|
21
21
|
},
|
|
22
22
|
windsurf: {
|
|
23
|
-
user: ".windsurf/
|
|
24
|
-
project: ".windsurf/
|
|
23
|
+
user: ".windsurf/rules",
|
|
24
|
+
project: ".windsurf/rules"
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
+
var FLAT_FILE_PLATFORMS = ["cursor", "windsurf", "copilot"];
|
|
28
|
+
function isFlatFilePlatform(platform) {
|
|
29
|
+
return FLAT_FILE_PLATFORMS.includes(platform);
|
|
30
|
+
}
|
|
31
|
+
function getPlatformFilePath(platform, skillName, fileName, project = false) {
|
|
32
|
+
const basePath = getSkillsPath(platform, project);
|
|
33
|
+
if (isFlatFilePlatform(platform)) {
|
|
34
|
+
return path.join(basePath, fileName);
|
|
35
|
+
}
|
|
36
|
+
return path.join(basePath, skillName, fileName);
|
|
37
|
+
}
|
|
27
38
|
function getSkillsPath(platform, project = false) {
|
|
28
39
|
const home = os.homedir();
|
|
29
40
|
const cwd = process.cwd();
|
|
@@ -77,6 +88,8 @@ async function saveConfig(config) {
|
|
|
77
88
|
}
|
|
78
89
|
|
|
79
90
|
export {
|
|
91
|
+
isFlatFilePlatform,
|
|
92
|
+
getPlatformFilePath,
|
|
80
93
|
getSkillsPath,
|
|
81
94
|
getSkillPath,
|
|
82
95
|
ensureSkillsDir,
|
package/dist/index.js
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ensureSkillsDir,
|
|
4
4
|
getConfigPath,
|
|
5
|
+
getPlatformFilePath,
|
|
5
6
|
getSkillPath,
|
|
6
7
|
getSkillsPath,
|
|
8
|
+
isFlatFilePlatform,
|
|
7
9
|
isSkillInstalled,
|
|
8
10
|
loadConfig,
|
|
9
11
|
saveConfig
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SLCBZBS3.js";
|
|
11
13
|
|
|
12
14
|
// src/index.ts
|
|
13
15
|
import { Command } from "commander";
|
|
@@ -19,7 +21,7 @@ import fs from "fs-extra";
|
|
|
19
21
|
import * as path from "path";
|
|
20
22
|
import chalk from "chalk";
|
|
21
23
|
import ora from "ora";
|
|
22
|
-
import { parseSkillMd } from "skillhub-core";
|
|
24
|
+
import { parseSkillMd, parseGenericInstructionFile, INSTRUCTION_FILE_PATTERNS as INSTRUCTION_FILE_PATTERNS2 } from "skillhub-core";
|
|
23
25
|
|
|
24
26
|
// src/utils/api.ts
|
|
25
27
|
import https from "https";
|
|
@@ -154,6 +156,7 @@ async function getSkillFiles(id) {
|
|
|
154
156
|
|
|
155
157
|
// src/utils/github.ts
|
|
156
158
|
import { Octokit } from "@octokit/rest";
|
|
159
|
+
import { INSTRUCTION_FILE_PATTERNS } from "skillhub-core";
|
|
157
160
|
import https2 from "https";
|
|
158
161
|
var octokit = null;
|
|
159
162
|
function getOctokit() {
|
|
@@ -191,17 +194,34 @@ async function fetchRawFile(owner, repo, path3, branch) {
|
|
|
191
194
|
});
|
|
192
195
|
});
|
|
193
196
|
}
|
|
194
|
-
|
|
197
|
+
function getInstructionFilename(sourceFormat) {
|
|
198
|
+
const pattern = INSTRUCTION_FILE_PATTERNS.find((p) => p.format === sourceFormat);
|
|
199
|
+
return pattern?.filename || "SKILL.md";
|
|
200
|
+
}
|
|
201
|
+
async function fetchSkillContent(owner, repo, skillPath, branch = "main", sourceFormat = "skill.md") {
|
|
195
202
|
const client = getOctokit();
|
|
196
|
-
const
|
|
203
|
+
const filename = getInstructionFilename(sourceFormat);
|
|
204
|
+
const isStandalone = sourceFormat !== "skill.md";
|
|
205
|
+
const basePath = skillPath ? `${skillPath}/${filename}` : filename;
|
|
197
206
|
let skillMdResponse;
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
207
|
+
let pathsToTry;
|
|
208
|
+
if (sourceFormat === "cursorrules" || sourceFormat === "windsurfrules") {
|
|
209
|
+
pathsToTry = [filename];
|
|
210
|
+
} else if (sourceFormat === "copilot-instructions") {
|
|
211
|
+
pathsToTry = [`.github/${filename}`];
|
|
212
|
+
} else if (sourceFormat === "agents.md") {
|
|
213
|
+
pathsToTry = [basePath];
|
|
214
|
+
if (skillPath) {
|
|
215
|
+
pathsToTry.push(filename);
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
pathsToTry = [
|
|
219
|
+
basePath,
|
|
220
|
+
...skillPath && !skillPath.startsWith("skills/") ? [`skills/${skillPath}/SKILL.md`] : [],
|
|
221
|
+
...skillPath && !skillPath.startsWith(".claude/") ? [`.claude/skills/${skillPath}/SKILL.md`] : [],
|
|
222
|
+
...skillPath && !skillPath.startsWith(".github/") ? [`.github/skills/${skillPath}/SKILL.md`] : []
|
|
223
|
+
];
|
|
224
|
+
}
|
|
205
225
|
for (const pathToTry of pathsToTry) {
|
|
206
226
|
try {
|
|
207
227
|
skillMdResponse = await client.repos.getContent({
|
|
@@ -233,12 +253,20 @@ async function fetchSkillContent(owner, repo, skillPath, branch = "main") {
|
|
|
233
253
|
}
|
|
234
254
|
}
|
|
235
255
|
if (!skillMdResponse) {
|
|
236
|
-
throw new Error(
|
|
256
|
+
throw new Error(`${filename} not found at ${owner}/${repo} (tried ${pathsToTry.length} paths)`);
|
|
237
257
|
}
|
|
238
258
|
if (!("content" in skillMdResponse.data)) {
|
|
239
|
-
throw new Error(
|
|
259
|
+
throw new Error(`${filename} not found`);
|
|
240
260
|
}
|
|
241
261
|
const skillMd = Buffer.from(skillMdResponse.data.content, "base64").toString("utf-8");
|
|
262
|
+
if (isStandalone) {
|
|
263
|
+
return {
|
|
264
|
+
skillMd,
|
|
265
|
+
scripts: [],
|
|
266
|
+
references: [],
|
|
267
|
+
assets: []
|
|
268
|
+
};
|
|
269
|
+
}
|
|
242
270
|
const scripts = [];
|
|
243
271
|
try {
|
|
244
272
|
const scriptsPath = skillPath ? `${skillPath}/scripts` : "scripts";
|
|
@@ -311,6 +339,108 @@ async function getDefaultBranch(owner, repo) {
|
|
|
311
339
|
return response.data.default_branch;
|
|
312
340
|
}
|
|
313
341
|
|
|
342
|
+
// src/utils/transform.ts
|
|
343
|
+
var WINDSURF_CHAR_LIMIT = 6e3;
|
|
344
|
+
var PLATFORM_FILE_CONFIGS = {
|
|
345
|
+
claude: {
|
|
346
|
+
getFileName: () => "SKILL.md",
|
|
347
|
+
keepOriginal: false,
|
|
348
|
+
transform: (raw) => ({ content: raw, warnings: [] })
|
|
349
|
+
},
|
|
350
|
+
codex: {
|
|
351
|
+
getFileName: () => "SKILL.md",
|
|
352
|
+
keepOriginal: false,
|
|
353
|
+
transform: (raw) => ({ content: raw, warnings: [] })
|
|
354
|
+
},
|
|
355
|
+
cursor: {
|
|
356
|
+
getFileName: (skillName) => `${skillName}.mdc`,
|
|
357
|
+
keepOriginal: true,
|
|
358
|
+
transform: transformForCursor
|
|
359
|
+
},
|
|
360
|
+
windsurf: {
|
|
361
|
+
getFileName: (skillName) => `${skillName}.md`,
|
|
362
|
+
keepOriginal: true,
|
|
363
|
+
transform: transformForWindsurf
|
|
364
|
+
},
|
|
365
|
+
copilot: {
|
|
366
|
+
getFileName: (skillName) => `${skillName}.instructions.md`,
|
|
367
|
+
keepOriginal: true,
|
|
368
|
+
transform: transformForCopilot
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
function getPlatformFileName(platform, skillName) {
|
|
372
|
+
return PLATFORM_FILE_CONFIGS[platform].getFileName(skillName);
|
|
373
|
+
}
|
|
374
|
+
function transformForPlatform(platform, rawSkillMd, parsed) {
|
|
375
|
+
return PLATFORM_FILE_CONFIGS[platform].transform(rawSkillMd, parsed);
|
|
376
|
+
}
|
|
377
|
+
function shouldKeepOriginal(platform) {
|
|
378
|
+
return PLATFORM_FILE_CONFIGS[platform].keepOriginal;
|
|
379
|
+
}
|
|
380
|
+
function transformForCursor(_raw, parsed) {
|
|
381
|
+
const warnings = [];
|
|
382
|
+
const mdcFields = [];
|
|
383
|
+
if (parsed.metadata.description) {
|
|
384
|
+
mdcFields.push(`description: ${parsed.metadata.description}`);
|
|
385
|
+
}
|
|
386
|
+
const filePatterns = parsed.metadata.triggers?.filePatterns;
|
|
387
|
+
if (filePatterns && filePatterns.length > 0) {
|
|
388
|
+
mdcFields.push(`globs: ${filePatterns.join(", ")}`);
|
|
389
|
+
mdcFields.push("alwaysApply: false");
|
|
390
|
+
} else {
|
|
391
|
+
mdcFields.push("alwaysApply: true");
|
|
392
|
+
}
|
|
393
|
+
const body = parsed.content.trim();
|
|
394
|
+
const mdcContent = `---
|
|
395
|
+
${mdcFields.join("\n")}
|
|
396
|
+
---
|
|
397
|
+
${body}
|
|
398
|
+
`;
|
|
399
|
+
return { content: mdcContent, warnings };
|
|
400
|
+
}
|
|
401
|
+
function transformForWindsurf(_raw, parsed) {
|
|
402
|
+
const warnings = [];
|
|
403
|
+
let body = parsed.content.trim();
|
|
404
|
+
if (!body.startsWith("# ")) {
|
|
405
|
+
body = `# ${parsed.metadata.name}
|
|
406
|
+
|
|
407
|
+
${body}`;
|
|
408
|
+
}
|
|
409
|
+
if (body.length > WINDSURF_CHAR_LIMIT) {
|
|
410
|
+
warnings.push(
|
|
411
|
+
`Content exceeds Windsurf's ${WINDSURF_CHAR_LIMIT} character limit (${body.length} chars). Truncating.`
|
|
412
|
+
);
|
|
413
|
+
body = truncateAtSectionBoundary(body, WINDSURF_CHAR_LIMIT);
|
|
414
|
+
}
|
|
415
|
+
return { content: body + "\n", warnings };
|
|
416
|
+
}
|
|
417
|
+
function transformForCopilot(_raw, parsed) {
|
|
418
|
+
let body = parsed.content.trim();
|
|
419
|
+
if (!body.startsWith("# ")) {
|
|
420
|
+
body = `# ${parsed.metadata.name}
|
|
421
|
+
|
|
422
|
+
${body}`;
|
|
423
|
+
}
|
|
424
|
+
return { content: body + "\n", warnings: [] };
|
|
425
|
+
}
|
|
426
|
+
function truncateAtSectionBoundary(content, limit) {
|
|
427
|
+
const notice = "\n\n<!-- Truncated by SkillHub: see SKILL.md for full content -->\n";
|
|
428
|
+
const maxLen = limit - notice.length;
|
|
429
|
+
if (content.length <= maxLen) return content;
|
|
430
|
+
const truncated = content.slice(0, maxLen);
|
|
431
|
+
const lastHeading = truncated.lastIndexOf("\n## ");
|
|
432
|
+
const lastH1 = truncated.lastIndexOf("\n# ");
|
|
433
|
+
const cutPoint = Math.max(lastHeading, lastH1);
|
|
434
|
+
if (cutPoint > 0) {
|
|
435
|
+
return truncated.slice(0, cutPoint) + notice;
|
|
436
|
+
}
|
|
437
|
+
const lastParagraph = truncated.lastIndexOf("\n\n");
|
|
438
|
+
if (lastParagraph > 0) {
|
|
439
|
+
return truncated.slice(0, lastParagraph) + notice;
|
|
440
|
+
}
|
|
441
|
+
return truncated + notice;
|
|
442
|
+
}
|
|
443
|
+
|
|
314
444
|
// src/commands/install.ts
|
|
315
445
|
async function install(skillId, options) {
|
|
316
446
|
const spinner = ora("Parsing skill ID...").start();
|
|
@@ -340,10 +470,12 @@ async function install(skillId, options) {
|
|
|
340
470
|
}
|
|
341
471
|
let skillName;
|
|
342
472
|
let branch = "main";
|
|
473
|
+
let sourceFormat = "skill.md";
|
|
343
474
|
if (skillInfo) {
|
|
344
475
|
skillName = skillInfo.name;
|
|
345
476
|
skillPath = skillInfo.skillPath;
|
|
346
477
|
branch = skillInfo.branch || "main";
|
|
478
|
+
sourceFormat = skillInfo.sourceFormat || "skill.md";
|
|
347
479
|
spinner.text = `Found skill: ${chalk.cyan(skillName)}`;
|
|
348
480
|
} else {
|
|
349
481
|
spinner.text = "Skill not in registry, fetching from GitHub...";
|
|
@@ -372,7 +504,10 @@ async function install(skillId, options) {
|
|
|
372
504
|
spinner.text = "Downloading skill files...";
|
|
373
505
|
const cachedFiles = await getSkillFiles(skillInfo.id);
|
|
374
506
|
if (cachedFiles && cachedFiles.files.length > 0) {
|
|
375
|
-
|
|
507
|
+
if (cachedFiles.sourceFormat) {
|
|
508
|
+
sourceFormat = cachedFiles.sourceFormat;
|
|
509
|
+
}
|
|
510
|
+
content = convertCachedFilesToSkillContent(cachedFiles, sourceFormat);
|
|
376
511
|
spinner.text = cachedFiles.fromCache ? `Using cached files (${cachedFiles.files.length} files)` : `Downloaded ${cachedFiles.files.length} files via API`;
|
|
377
512
|
}
|
|
378
513
|
} catch {
|
|
@@ -386,7 +521,7 @@ async function install(skillId, options) {
|
|
|
386
521
|
spinner.text = `Downloading from GitHub: ${owner}/${repo}/${skillPath || ""}...`;
|
|
387
522
|
}
|
|
388
523
|
try {
|
|
389
|
-
content = await fetchSkillContent(owner, repo, skillPath, branch);
|
|
524
|
+
content = await fetchSkillContent(owner, repo, skillPath, branch, sourceFormat);
|
|
390
525
|
spinner.text = `Downloaded ${content.scripts.length} scripts, ${content.references.length} references`;
|
|
391
526
|
} catch (error) {
|
|
392
527
|
spinner.fail("Failed to download skill files");
|
|
@@ -408,7 +543,11 @@ async function install(skillId, options) {
|
|
|
408
543
|
spinner.fail("Failed to download skill content");
|
|
409
544
|
process.exit(1);
|
|
410
545
|
}
|
|
411
|
-
const parsed = parseSkillMd(content.skillMd)
|
|
546
|
+
const parsed = sourceFormat === "skill.md" ? parseSkillMd(content.skillMd) : parseGenericInstructionFile(content.skillMd, sourceFormat, {
|
|
547
|
+
name: skillName,
|
|
548
|
+
description: skillInfo?.description || null,
|
|
549
|
+
owner
|
|
550
|
+
});
|
|
412
551
|
if (!parsed.validation.isValid) {
|
|
413
552
|
spinner.warn("Skill has validation issues:");
|
|
414
553
|
for (const error of parsed.validation.errors) {
|
|
@@ -444,13 +583,34 @@ A different skill is already installed with the name "${actualName}":`));
|
|
|
444
583
|
}
|
|
445
584
|
spinner.text = "Installing skill...";
|
|
446
585
|
await fs.ensureDir(installPath);
|
|
447
|
-
|
|
586
|
+
const platformFileName = getPlatformFileName(options.platform, actualName);
|
|
587
|
+
const { content: transformedContent, warnings: transformWarnings } = transformForPlatform(options.platform, content.skillMd, parsed);
|
|
588
|
+
for (const warning of transformWarnings) {
|
|
589
|
+
console.log(chalk.yellow(` Warning: ${warning}`));
|
|
590
|
+
}
|
|
591
|
+
if (isFlatFilePlatform(options.platform)) {
|
|
592
|
+
const platformFilePath2 = getPlatformFilePath(
|
|
593
|
+
options.platform,
|
|
594
|
+
actualName,
|
|
595
|
+
platformFileName,
|
|
596
|
+
options.project
|
|
597
|
+
);
|
|
598
|
+
await fs.writeFile(platformFilePath2, transformedContent);
|
|
599
|
+
} else {
|
|
600
|
+
await fs.writeFile(path.join(installPath, platformFileName), transformedContent);
|
|
601
|
+
}
|
|
602
|
+
if (shouldKeepOriginal(options.platform)) {
|
|
603
|
+
await fs.writeFile(path.join(installPath, "SKILL.md"), content.skillMd);
|
|
604
|
+
}
|
|
448
605
|
const canonicalId = skillInfo?.id || skillId;
|
|
606
|
+
const platformFilePath = isFlatFilePlatform(options.platform) ? getPlatformFilePath(options.platform, actualName, platformFileName, options.project) : null;
|
|
449
607
|
await fs.writeJson(path.join(installPath, ".skillhub.json"), {
|
|
450
608
|
skillId: canonicalId,
|
|
451
609
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
452
610
|
platform: options.platform,
|
|
453
|
-
version: parsed.metadata.version || null
|
|
611
|
+
version: parsed.metadata.version || null,
|
|
612
|
+
platformFileName,
|
|
613
|
+
platformFilePath
|
|
454
614
|
});
|
|
455
615
|
if (content.scripts.length > 0) {
|
|
456
616
|
const scriptsDir = path.join(installPath, "scripts");
|
|
@@ -511,30 +671,30 @@ function getPlatformName(platform) {
|
|
|
511
671
|
function getPlatformSetupInstructions(platform, installPath) {
|
|
512
672
|
switch (platform) {
|
|
513
673
|
case "claude":
|
|
514
|
-
return chalk.dim(" Skills in
|
|
674
|
+
return chalk.dim(" Skills in .claude/skills/ are automatically discovered by Claude Code.");
|
|
515
675
|
case "codex":
|
|
516
676
|
return chalk.dim(` Reference this skill in your AGENTS.md:
|
|
517
677
|
@import ${installPath}/SKILL.md`);
|
|
518
678
|
case "copilot":
|
|
519
|
-
return chalk.dim(
|
|
520
|
-
@import ${installPath}/SKILL.md`);
|
|
679
|
+
return chalk.dim(" Instructions in .github/instructions/ are automatically loaded by GitHub Copilot.");
|
|
521
680
|
case "cursor":
|
|
522
|
-
return chalk.dim(
|
|
523
|
-
@import ${installPath}/SKILL.md`);
|
|
681
|
+
return chalk.dim(" Rules in .cursor/rules/ are automatically loaded by Cursor.");
|
|
524
682
|
case "windsurf":
|
|
525
|
-
return chalk.dim(
|
|
526
|
-
Path: ${installPath}/SKILL.md`);
|
|
683
|
+
return chalk.dim(" Rules in .windsurf/rules/ are automatically loaded by Windsurf.");
|
|
527
684
|
default:
|
|
528
685
|
return null;
|
|
529
686
|
}
|
|
530
687
|
}
|
|
531
|
-
|
|
688
|
+
var MAIN_FILE_NAMES = INSTRUCTION_FILE_PATTERNS2.map((p) => p.filename);
|
|
689
|
+
function convertCachedFilesToSkillContent(response, sourceFormat = "skill.md") {
|
|
532
690
|
let skillMd = "";
|
|
533
691
|
const scripts = [];
|
|
534
692
|
const references = [];
|
|
693
|
+
const expectedPattern = INSTRUCTION_FILE_PATTERNS2.find((p) => p.format === sourceFormat);
|
|
694
|
+
const expectedFilename = expectedPattern?.filename || "SKILL.md";
|
|
535
695
|
for (const file of response.files) {
|
|
536
696
|
if (!file.content) continue;
|
|
537
|
-
if (file.name ===
|
|
697
|
+
if (!skillMd && (file.name === expectedFilename || MAIN_FILE_NAMES.includes(file.name)) && file.path === file.name) {
|
|
538
698
|
skillMd = file.content;
|
|
539
699
|
continue;
|
|
540
700
|
}
|
|
@@ -737,18 +897,31 @@ async function getInstalledSkills(platform, project = false) {
|
|
|
737
897
|
}
|
|
738
898
|
const skillPath = path2.join(skillsPath, entry.name);
|
|
739
899
|
const skillMdPath = path2.join(skillPath, "SKILL.md");
|
|
740
|
-
|
|
900
|
+
const metadataPath = path2.join(skillPath, ".skillhub.json");
|
|
901
|
+
const hasSkillMd = await fs2.pathExists(skillMdPath);
|
|
902
|
+
const hasMetadata = await fs2.pathExists(metadataPath);
|
|
903
|
+
if (!hasSkillMd && !hasMetadata) {
|
|
741
904
|
continue;
|
|
742
905
|
}
|
|
743
906
|
try {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
907
|
+
if (hasSkillMd) {
|
|
908
|
+
const content = await fs2.readFile(skillMdPath, "utf-8");
|
|
909
|
+
const parsed = parseSkillMd2(content);
|
|
910
|
+
skills.push({
|
|
911
|
+
name: parsed.metadata.name || entry.name,
|
|
912
|
+
description: parsed.metadata.description,
|
|
913
|
+
version: parsed.metadata.version,
|
|
914
|
+
path: skillPath
|
|
915
|
+
});
|
|
916
|
+
} else if (hasMetadata) {
|
|
917
|
+
const metadata = await fs2.readJson(metadataPath);
|
|
918
|
+
skills.push({
|
|
919
|
+
name: entry.name,
|
|
920
|
+
description: void 0,
|
|
921
|
+
version: metadata.version || void 0,
|
|
922
|
+
path: skillPath
|
|
923
|
+
});
|
|
924
|
+
}
|
|
752
925
|
} catch {
|
|
753
926
|
skills.push({
|
|
754
927
|
name: entry.name,
|
|
@@ -849,7 +1022,8 @@ program.command("config").description("Manage CLI configuration").option("--set
|
|
|
849
1022
|
});
|
|
850
1023
|
program.command("uninstall <skill-name>").description("Uninstall a skill").option("-p, --platform <platform>", "Target platform").option("--project", "Uninstall from project instead of globally").action(async (skillName, options) => {
|
|
851
1024
|
const fs3 = await import("fs-extra");
|
|
852
|
-
const
|
|
1025
|
+
const pathModule = await import("path");
|
|
1026
|
+
const { getSkillPath: getSkillPath2, isSkillInstalled: isSkillInstalled2 } = await import("./paths-PDIRF66F.js");
|
|
853
1027
|
const userConfig = await loadConfig();
|
|
854
1028
|
const platform = options.platform || userConfig.defaultPlatform || "claude";
|
|
855
1029
|
const installed = await isSkillInstalled2(platform, skillName, options.project);
|
|
@@ -858,13 +1032,23 @@ program.command("uninstall <skill-name>").description("Uninstall a skill").optio
|
|
|
858
1032
|
process.exit(1);
|
|
859
1033
|
}
|
|
860
1034
|
const skillPath = getSkillPath2(platform, skillName, options.project);
|
|
1035
|
+
const metadataPath = pathModule.join(skillPath, ".skillhub.json");
|
|
1036
|
+
if (await fs3.default.pathExists(metadataPath)) {
|
|
1037
|
+
try {
|
|
1038
|
+
const metadata = await fs3.default.readJson(metadataPath);
|
|
1039
|
+
if (metadata.platformFilePath) {
|
|
1040
|
+
await fs3.default.remove(metadata.platformFilePath);
|
|
1041
|
+
}
|
|
1042
|
+
} catch {
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
861
1045
|
await fs3.default.remove(skillPath);
|
|
862
1046
|
console.log(chalk5.green(`Skill ${skillName} uninstalled successfully.`));
|
|
863
1047
|
});
|
|
864
1048
|
program.command("update [skill-name]").description("Update installed skills").option("-p, --platform <platform>", "Target platform").option("--all", "Update all installed skills").action(async (skillName, options) => {
|
|
865
1049
|
const fsExtra = await import("fs-extra");
|
|
866
1050
|
const pathModule = await import("path");
|
|
867
|
-
const { getSkillsPath: getSkillsPath2, getSkillPath: getSkillPath2 } = await import("./paths-
|
|
1051
|
+
const { getSkillsPath: getSkillsPath2, getSkillPath: getSkillPath2 } = await import("./paths-PDIRF66F.js");
|
|
868
1052
|
const userConfig = await loadConfig();
|
|
869
1053
|
const platform = options.platform || userConfig.defaultPlatform || "claude";
|
|
870
1054
|
const ALL_PLATFORMS2 = ["claude", "codex", "copilot", "cursor", "windsurf"];
|
|
@@ -2,18 +2,22 @@ import {
|
|
|
2
2
|
detectPlatform,
|
|
3
3
|
ensureSkillsDir,
|
|
4
4
|
getConfigPath,
|
|
5
|
+
getPlatformFilePath,
|
|
5
6
|
getSkillPath,
|
|
6
7
|
getSkillsPath,
|
|
8
|
+
isFlatFilePlatform,
|
|
7
9
|
isSkillInstalled,
|
|
8
10
|
loadConfig,
|
|
9
11
|
saveConfig
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SLCBZBS3.js";
|
|
11
13
|
export {
|
|
12
14
|
detectPlatform,
|
|
13
15
|
ensureSkillsDir,
|
|
14
16
|
getConfigPath,
|
|
17
|
+
getPlatformFilePath,
|
|
15
18
|
getSkillPath,
|
|
16
19
|
getSkillsPath,
|
|
20
|
+
isFlatFilePlatform,
|
|
17
21
|
isSkillInstalled,
|
|
18
22
|
loadConfig,
|
|
19
23
|
saveConfig
|
package/package.json
CHANGED