skillhub 0.1.15 → 0.2.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.
|
@@ -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";
|
|
@@ -311,6 +313,108 @@ async function getDefaultBranch(owner, repo) {
|
|
|
311
313
|
return response.data.default_branch;
|
|
312
314
|
}
|
|
313
315
|
|
|
316
|
+
// src/utils/transform.ts
|
|
317
|
+
var WINDSURF_CHAR_LIMIT = 6e3;
|
|
318
|
+
var PLATFORM_FILE_CONFIGS = {
|
|
319
|
+
claude: {
|
|
320
|
+
getFileName: () => "SKILL.md",
|
|
321
|
+
keepOriginal: false,
|
|
322
|
+
transform: (raw) => ({ content: raw, warnings: [] })
|
|
323
|
+
},
|
|
324
|
+
codex: {
|
|
325
|
+
getFileName: () => "SKILL.md",
|
|
326
|
+
keepOriginal: false,
|
|
327
|
+
transform: (raw) => ({ content: raw, warnings: [] })
|
|
328
|
+
},
|
|
329
|
+
cursor: {
|
|
330
|
+
getFileName: (skillName) => `${skillName}.mdc`,
|
|
331
|
+
keepOriginal: true,
|
|
332
|
+
transform: transformForCursor
|
|
333
|
+
},
|
|
334
|
+
windsurf: {
|
|
335
|
+
getFileName: (skillName) => `${skillName}.md`,
|
|
336
|
+
keepOriginal: true,
|
|
337
|
+
transform: transformForWindsurf
|
|
338
|
+
},
|
|
339
|
+
copilot: {
|
|
340
|
+
getFileName: (skillName) => `${skillName}.instructions.md`,
|
|
341
|
+
keepOriginal: true,
|
|
342
|
+
transform: transformForCopilot
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
function getPlatformFileName(platform, skillName) {
|
|
346
|
+
return PLATFORM_FILE_CONFIGS[platform].getFileName(skillName);
|
|
347
|
+
}
|
|
348
|
+
function transformForPlatform(platform, rawSkillMd, parsed) {
|
|
349
|
+
return PLATFORM_FILE_CONFIGS[platform].transform(rawSkillMd, parsed);
|
|
350
|
+
}
|
|
351
|
+
function shouldKeepOriginal(platform) {
|
|
352
|
+
return PLATFORM_FILE_CONFIGS[platform].keepOriginal;
|
|
353
|
+
}
|
|
354
|
+
function transformForCursor(_raw, parsed) {
|
|
355
|
+
const warnings = [];
|
|
356
|
+
const mdcFields = [];
|
|
357
|
+
if (parsed.metadata.description) {
|
|
358
|
+
mdcFields.push(`description: ${parsed.metadata.description}`);
|
|
359
|
+
}
|
|
360
|
+
const filePatterns = parsed.metadata.triggers?.filePatterns;
|
|
361
|
+
if (filePatterns && filePatterns.length > 0) {
|
|
362
|
+
mdcFields.push(`globs: ${filePatterns.join(", ")}`);
|
|
363
|
+
mdcFields.push("alwaysApply: false");
|
|
364
|
+
} else {
|
|
365
|
+
mdcFields.push("alwaysApply: true");
|
|
366
|
+
}
|
|
367
|
+
const body = parsed.content.trim();
|
|
368
|
+
const mdcContent = `---
|
|
369
|
+
${mdcFields.join("\n")}
|
|
370
|
+
---
|
|
371
|
+
${body}
|
|
372
|
+
`;
|
|
373
|
+
return { content: mdcContent, warnings };
|
|
374
|
+
}
|
|
375
|
+
function transformForWindsurf(_raw, parsed) {
|
|
376
|
+
const warnings = [];
|
|
377
|
+
let body = parsed.content.trim();
|
|
378
|
+
if (!body.startsWith("# ")) {
|
|
379
|
+
body = `# ${parsed.metadata.name}
|
|
380
|
+
|
|
381
|
+
${body}`;
|
|
382
|
+
}
|
|
383
|
+
if (body.length > WINDSURF_CHAR_LIMIT) {
|
|
384
|
+
warnings.push(
|
|
385
|
+
`Content exceeds Windsurf's ${WINDSURF_CHAR_LIMIT} character limit (${body.length} chars). Truncating.`
|
|
386
|
+
);
|
|
387
|
+
body = truncateAtSectionBoundary(body, WINDSURF_CHAR_LIMIT);
|
|
388
|
+
}
|
|
389
|
+
return { content: body + "\n", warnings };
|
|
390
|
+
}
|
|
391
|
+
function transformForCopilot(_raw, parsed) {
|
|
392
|
+
let body = parsed.content.trim();
|
|
393
|
+
if (!body.startsWith("# ")) {
|
|
394
|
+
body = `# ${parsed.metadata.name}
|
|
395
|
+
|
|
396
|
+
${body}`;
|
|
397
|
+
}
|
|
398
|
+
return { content: body + "\n", warnings: [] };
|
|
399
|
+
}
|
|
400
|
+
function truncateAtSectionBoundary(content, limit) {
|
|
401
|
+
const notice = "\n\n<!-- Truncated by SkillHub: see SKILL.md for full content -->\n";
|
|
402
|
+
const maxLen = limit - notice.length;
|
|
403
|
+
if (content.length <= maxLen) return content;
|
|
404
|
+
const truncated = content.slice(0, maxLen);
|
|
405
|
+
const lastHeading = truncated.lastIndexOf("\n## ");
|
|
406
|
+
const lastH1 = truncated.lastIndexOf("\n# ");
|
|
407
|
+
const cutPoint = Math.max(lastHeading, lastH1);
|
|
408
|
+
if (cutPoint > 0) {
|
|
409
|
+
return truncated.slice(0, cutPoint) + notice;
|
|
410
|
+
}
|
|
411
|
+
const lastParagraph = truncated.lastIndexOf("\n\n");
|
|
412
|
+
if (lastParagraph > 0) {
|
|
413
|
+
return truncated.slice(0, lastParagraph) + notice;
|
|
414
|
+
}
|
|
415
|
+
return truncated + notice;
|
|
416
|
+
}
|
|
417
|
+
|
|
314
418
|
// src/commands/install.ts
|
|
315
419
|
async function install(skillId, options) {
|
|
316
420
|
const spinner = ora("Parsing skill ID...").start();
|
|
@@ -444,13 +548,34 @@ A different skill is already installed with the name "${actualName}":`));
|
|
|
444
548
|
}
|
|
445
549
|
spinner.text = "Installing skill...";
|
|
446
550
|
await fs.ensureDir(installPath);
|
|
447
|
-
|
|
551
|
+
const platformFileName = getPlatformFileName(options.platform, actualName);
|
|
552
|
+
const { content: transformedContent, warnings: transformWarnings } = transformForPlatform(options.platform, content.skillMd, parsed);
|
|
553
|
+
for (const warning of transformWarnings) {
|
|
554
|
+
console.log(chalk.yellow(` Warning: ${warning}`));
|
|
555
|
+
}
|
|
556
|
+
if (isFlatFilePlatform(options.platform)) {
|
|
557
|
+
const platformFilePath2 = getPlatformFilePath(
|
|
558
|
+
options.platform,
|
|
559
|
+
actualName,
|
|
560
|
+
platformFileName,
|
|
561
|
+
options.project
|
|
562
|
+
);
|
|
563
|
+
await fs.writeFile(platformFilePath2, transformedContent);
|
|
564
|
+
} else {
|
|
565
|
+
await fs.writeFile(path.join(installPath, platformFileName), transformedContent);
|
|
566
|
+
}
|
|
567
|
+
if (shouldKeepOriginal(options.platform)) {
|
|
568
|
+
await fs.writeFile(path.join(installPath, "SKILL.md"), content.skillMd);
|
|
569
|
+
}
|
|
448
570
|
const canonicalId = skillInfo?.id || skillId;
|
|
571
|
+
const platformFilePath = isFlatFilePlatform(options.platform) ? getPlatformFilePath(options.platform, actualName, platformFileName, options.project) : null;
|
|
449
572
|
await fs.writeJson(path.join(installPath, ".skillhub.json"), {
|
|
450
573
|
skillId: canonicalId,
|
|
451
574
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
452
575
|
platform: options.platform,
|
|
453
|
-
version: parsed.metadata.version || null
|
|
576
|
+
version: parsed.metadata.version || null,
|
|
577
|
+
platformFileName,
|
|
578
|
+
platformFilePath
|
|
454
579
|
});
|
|
455
580
|
if (content.scripts.length > 0) {
|
|
456
581
|
const scriptsDir = path.join(installPath, "scripts");
|
|
@@ -511,19 +636,16 @@ function getPlatformName(platform) {
|
|
|
511
636
|
function getPlatformSetupInstructions(platform, installPath) {
|
|
512
637
|
switch (platform) {
|
|
513
638
|
case "claude":
|
|
514
|
-
return chalk.dim(" Skills in
|
|
639
|
+
return chalk.dim(" Skills in .claude/skills/ are automatically discovered by Claude Code.");
|
|
515
640
|
case "codex":
|
|
516
641
|
return chalk.dim(` Reference this skill in your AGENTS.md:
|
|
517
642
|
@import ${installPath}/SKILL.md`);
|
|
518
643
|
case "copilot":
|
|
519
|
-
return chalk.dim(
|
|
520
|
-
@import ${installPath}/SKILL.md`);
|
|
644
|
+
return chalk.dim(" Instructions in .github/instructions/ are automatically loaded by GitHub Copilot.");
|
|
521
645
|
case "cursor":
|
|
522
|
-
return chalk.dim(
|
|
523
|
-
@import ${installPath}/SKILL.md`);
|
|
646
|
+
return chalk.dim(" Rules in .cursor/rules/ are automatically loaded by Cursor.");
|
|
524
647
|
case "windsurf":
|
|
525
|
-
return chalk.dim(
|
|
526
|
-
Path: ${installPath}/SKILL.md`);
|
|
648
|
+
return chalk.dim(" Rules in .windsurf/rules/ are automatically loaded by Windsurf.");
|
|
527
649
|
default:
|
|
528
650
|
return null;
|
|
529
651
|
}
|
|
@@ -737,18 +859,31 @@ async function getInstalledSkills(platform, project = false) {
|
|
|
737
859
|
}
|
|
738
860
|
const skillPath = path2.join(skillsPath, entry.name);
|
|
739
861
|
const skillMdPath = path2.join(skillPath, "SKILL.md");
|
|
740
|
-
|
|
862
|
+
const metadataPath = path2.join(skillPath, ".skillhub.json");
|
|
863
|
+
const hasSkillMd = await fs2.pathExists(skillMdPath);
|
|
864
|
+
const hasMetadata = await fs2.pathExists(metadataPath);
|
|
865
|
+
if (!hasSkillMd && !hasMetadata) {
|
|
741
866
|
continue;
|
|
742
867
|
}
|
|
743
868
|
try {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
869
|
+
if (hasSkillMd) {
|
|
870
|
+
const content = await fs2.readFile(skillMdPath, "utf-8");
|
|
871
|
+
const parsed = parseSkillMd2(content);
|
|
872
|
+
skills.push({
|
|
873
|
+
name: parsed.metadata.name || entry.name,
|
|
874
|
+
description: parsed.metadata.description,
|
|
875
|
+
version: parsed.metadata.version,
|
|
876
|
+
path: skillPath
|
|
877
|
+
});
|
|
878
|
+
} else if (hasMetadata) {
|
|
879
|
+
const metadata = await fs2.readJson(metadataPath);
|
|
880
|
+
skills.push({
|
|
881
|
+
name: entry.name,
|
|
882
|
+
description: void 0,
|
|
883
|
+
version: metadata.version || void 0,
|
|
884
|
+
path: skillPath
|
|
885
|
+
});
|
|
886
|
+
}
|
|
752
887
|
} catch {
|
|
753
888
|
skills.push({
|
|
754
889
|
name: entry.name,
|
|
@@ -849,7 +984,8 @@ program.command("config").description("Manage CLI configuration").option("--set
|
|
|
849
984
|
});
|
|
850
985
|
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
986
|
const fs3 = await import("fs-extra");
|
|
852
|
-
const
|
|
987
|
+
const pathModule = await import("path");
|
|
988
|
+
const { getSkillPath: getSkillPath2, isSkillInstalled: isSkillInstalled2 } = await import("./paths-PDIRF66F.js");
|
|
853
989
|
const userConfig = await loadConfig();
|
|
854
990
|
const platform = options.platform || userConfig.defaultPlatform || "claude";
|
|
855
991
|
const installed = await isSkillInstalled2(platform, skillName, options.project);
|
|
@@ -858,13 +994,23 @@ program.command("uninstall <skill-name>").description("Uninstall a skill").optio
|
|
|
858
994
|
process.exit(1);
|
|
859
995
|
}
|
|
860
996
|
const skillPath = getSkillPath2(platform, skillName, options.project);
|
|
997
|
+
const metadataPath = pathModule.join(skillPath, ".skillhub.json");
|
|
998
|
+
if (await fs3.default.pathExists(metadataPath)) {
|
|
999
|
+
try {
|
|
1000
|
+
const metadata = await fs3.default.readJson(metadataPath);
|
|
1001
|
+
if (metadata.platformFilePath) {
|
|
1002
|
+
await fs3.default.remove(metadata.platformFilePath);
|
|
1003
|
+
}
|
|
1004
|
+
} catch {
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
861
1007
|
await fs3.default.remove(skillPath);
|
|
862
1008
|
console.log(chalk5.green(`Skill ${skillName} uninstalled successfully.`));
|
|
863
1009
|
});
|
|
864
1010
|
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
1011
|
const fsExtra = await import("fs-extra");
|
|
866
1012
|
const pathModule = await import("path");
|
|
867
|
-
const { getSkillsPath: getSkillsPath2, getSkillPath: getSkillPath2 } = await import("./paths-
|
|
1013
|
+
const { getSkillsPath: getSkillsPath2, getSkillPath: getSkillPath2 } = await import("./paths-PDIRF66F.js");
|
|
868
1014
|
const userConfig = await loadConfig();
|
|
869
1015
|
const platform = options.platform || userConfig.defaultPlatform || "claude";
|
|
870
1016
|
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