skillhub 0.2.0 → 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.
- package/dist/index.js +55 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import fs from "fs-extra";
|
|
|
21
21
|
import * as path from "path";
|
|
22
22
|
import chalk from "chalk";
|
|
23
23
|
import ora from "ora";
|
|
24
|
-
import { parseSkillMd } from "skillhub-core";
|
|
24
|
+
import { parseSkillMd, parseGenericInstructionFile, INSTRUCTION_FILE_PATTERNS as INSTRUCTION_FILE_PATTERNS2 } from "skillhub-core";
|
|
25
25
|
|
|
26
26
|
// src/utils/api.ts
|
|
27
27
|
import https from "https";
|
|
@@ -156,6 +156,7 @@ async function getSkillFiles(id) {
|
|
|
156
156
|
|
|
157
157
|
// src/utils/github.ts
|
|
158
158
|
import { Octokit } from "@octokit/rest";
|
|
159
|
+
import { INSTRUCTION_FILE_PATTERNS } from "skillhub-core";
|
|
159
160
|
import https2 from "https";
|
|
160
161
|
var octokit = null;
|
|
161
162
|
function getOctokit() {
|
|
@@ -193,17 +194,34 @@ async function fetchRawFile(owner, repo, path3, branch) {
|
|
|
193
194
|
});
|
|
194
195
|
});
|
|
195
196
|
}
|
|
196
|
-
|
|
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") {
|
|
197
202
|
const client = getOctokit();
|
|
198
|
-
const
|
|
203
|
+
const filename = getInstructionFilename(sourceFormat);
|
|
204
|
+
const isStandalone = sourceFormat !== "skill.md";
|
|
205
|
+
const basePath = skillPath ? `${skillPath}/${filename}` : filename;
|
|
199
206
|
let skillMdResponse;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
+
}
|
|
207
225
|
for (const pathToTry of pathsToTry) {
|
|
208
226
|
try {
|
|
209
227
|
skillMdResponse = await client.repos.getContent({
|
|
@@ -235,12 +253,20 @@ async function fetchSkillContent(owner, repo, skillPath, branch = "main") {
|
|
|
235
253
|
}
|
|
236
254
|
}
|
|
237
255
|
if (!skillMdResponse) {
|
|
238
|
-
throw new Error(
|
|
256
|
+
throw new Error(`${filename} not found at ${owner}/${repo} (tried ${pathsToTry.length} paths)`);
|
|
239
257
|
}
|
|
240
258
|
if (!("content" in skillMdResponse.data)) {
|
|
241
|
-
throw new Error(
|
|
259
|
+
throw new Error(`${filename} not found`);
|
|
242
260
|
}
|
|
243
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
|
+
}
|
|
244
270
|
const scripts = [];
|
|
245
271
|
try {
|
|
246
272
|
const scriptsPath = skillPath ? `${skillPath}/scripts` : "scripts";
|
|
@@ -444,10 +470,12 @@ async function install(skillId, options) {
|
|
|
444
470
|
}
|
|
445
471
|
let skillName;
|
|
446
472
|
let branch = "main";
|
|
473
|
+
let sourceFormat = "skill.md";
|
|
447
474
|
if (skillInfo) {
|
|
448
475
|
skillName = skillInfo.name;
|
|
449
476
|
skillPath = skillInfo.skillPath;
|
|
450
477
|
branch = skillInfo.branch || "main";
|
|
478
|
+
sourceFormat = skillInfo.sourceFormat || "skill.md";
|
|
451
479
|
spinner.text = `Found skill: ${chalk.cyan(skillName)}`;
|
|
452
480
|
} else {
|
|
453
481
|
spinner.text = "Skill not in registry, fetching from GitHub...";
|
|
@@ -476,7 +504,10 @@ async function install(skillId, options) {
|
|
|
476
504
|
spinner.text = "Downloading skill files...";
|
|
477
505
|
const cachedFiles = await getSkillFiles(skillInfo.id);
|
|
478
506
|
if (cachedFiles && cachedFiles.files.length > 0) {
|
|
479
|
-
|
|
507
|
+
if (cachedFiles.sourceFormat) {
|
|
508
|
+
sourceFormat = cachedFiles.sourceFormat;
|
|
509
|
+
}
|
|
510
|
+
content = convertCachedFilesToSkillContent(cachedFiles, sourceFormat);
|
|
480
511
|
spinner.text = cachedFiles.fromCache ? `Using cached files (${cachedFiles.files.length} files)` : `Downloaded ${cachedFiles.files.length} files via API`;
|
|
481
512
|
}
|
|
482
513
|
} catch {
|
|
@@ -490,7 +521,7 @@ async function install(skillId, options) {
|
|
|
490
521
|
spinner.text = `Downloading from GitHub: ${owner}/${repo}/${skillPath || ""}...`;
|
|
491
522
|
}
|
|
492
523
|
try {
|
|
493
|
-
content = await fetchSkillContent(owner, repo, skillPath, branch);
|
|
524
|
+
content = await fetchSkillContent(owner, repo, skillPath, branch, sourceFormat);
|
|
494
525
|
spinner.text = `Downloaded ${content.scripts.length} scripts, ${content.references.length} references`;
|
|
495
526
|
} catch (error) {
|
|
496
527
|
spinner.fail("Failed to download skill files");
|
|
@@ -512,7 +543,11 @@ async function install(skillId, options) {
|
|
|
512
543
|
spinner.fail("Failed to download skill content");
|
|
513
544
|
process.exit(1);
|
|
514
545
|
}
|
|
515
|
-
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
|
+
});
|
|
516
551
|
if (!parsed.validation.isValid) {
|
|
517
552
|
spinner.warn("Skill has validation issues:");
|
|
518
553
|
for (const error of parsed.validation.errors) {
|
|
@@ -650,13 +685,16 @@ function getPlatformSetupInstructions(platform, installPath) {
|
|
|
650
685
|
return null;
|
|
651
686
|
}
|
|
652
687
|
}
|
|
653
|
-
|
|
688
|
+
var MAIN_FILE_NAMES = INSTRUCTION_FILE_PATTERNS2.map((p) => p.filename);
|
|
689
|
+
function convertCachedFilesToSkillContent(response, sourceFormat = "skill.md") {
|
|
654
690
|
let skillMd = "";
|
|
655
691
|
const scripts = [];
|
|
656
692
|
const references = [];
|
|
693
|
+
const expectedPattern = INSTRUCTION_FILE_PATTERNS2.find((p) => p.format === sourceFormat);
|
|
694
|
+
const expectedFilename = expectedPattern?.filename || "SKILL.md";
|
|
657
695
|
for (const file of response.files) {
|
|
658
696
|
if (!file.content) continue;
|
|
659
|
-
if (file.name ===
|
|
697
|
+
if (!skillMd && (file.name === expectedFilename || MAIN_FILE_NAMES.includes(file.name)) && file.path === file.name) {
|
|
660
698
|
skillMd = file.content;
|
|
661
699
|
continue;
|
|
662
700
|
}
|
package/package.json
CHANGED