skillhub 0.1.7 → 0.1.8
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 +81 -26
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -135,6 +135,7 @@ async function trackInstall(skillId, platform, method = "cli") {
|
|
|
135
135
|
|
|
136
136
|
// src/utils/github.ts
|
|
137
137
|
import { Octokit } from "@octokit/rest";
|
|
138
|
+
import https2 from "https";
|
|
138
139
|
var octokit = null;
|
|
139
140
|
function getOctokit() {
|
|
140
141
|
if (!octokit) {
|
|
@@ -149,25 +150,73 @@ function getOctokit() {
|
|
|
149
150
|
}
|
|
150
151
|
return octokit;
|
|
151
152
|
}
|
|
153
|
+
async function fetchRawFile(owner, repo, path3, branch) {
|
|
154
|
+
return new Promise((resolve, reject) => {
|
|
155
|
+
const url = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${path3}`;
|
|
156
|
+
https2.get(url, { timeout: 1e4 }, (res) => {
|
|
157
|
+
if (res.statusCode === 404) {
|
|
158
|
+
reject(new Error("File not found"));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (res.statusCode !== 200) {
|
|
162
|
+
reject(new Error(`HTTP ${res.statusCode}`));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
let data = "";
|
|
166
|
+
res.on("data", (chunk) => data += chunk);
|
|
167
|
+
res.on("end", () => resolve(data));
|
|
168
|
+
}).on("error", (err) => {
|
|
169
|
+
reject(err);
|
|
170
|
+
}).on("timeout", () => {
|
|
171
|
+
reject(new Error("Request timeout"));
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
}
|
|
152
175
|
async function fetchSkillContent(owner, repo, skillPath, branch = "main") {
|
|
153
176
|
const client = getOctokit();
|
|
154
177
|
const skillMdPath = skillPath ? `${skillPath}/SKILL.md` : "SKILL.md";
|
|
155
178
|
let skillMdResponse;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
179
|
+
let lastError;
|
|
180
|
+
const pathsToTry = [
|
|
181
|
+
skillMdPath,
|
|
182
|
+
// Common skill directories
|
|
183
|
+
...skillPath && !skillPath.startsWith("skills/") ? [`skills/${skillPath}/SKILL.md`] : [],
|
|
184
|
+
...skillPath && !skillPath.startsWith(".claude/") ? [`.claude/skills/${skillPath}/SKILL.md`] : [],
|
|
185
|
+
...skillPath && !skillPath.startsWith(".github/") ? [`.github/skills/${skillPath}/SKILL.md`] : []
|
|
186
|
+
];
|
|
187
|
+
for (const pathToTry of pathsToTry) {
|
|
188
|
+
try {
|
|
189
|
+
skillMdResponse = await client.repos.getContent({
|
|
190
|
+
owner,
|
|
191
|
+
repo,
|
|
192
|
+
path: pathToTry,
|
|
193
|
+
ref: branch
|
|
194
|
+
});
|
|
195
|
+
break;
|
|
196
|
+
} catch (error) {
|
|
197
|
+
lastError = error;
|
|
198
|
+
if (error.message?.includes("timeout") || error.message?.includes("network")) {
|
|
199
|
+
try {
|
|
200
|
+
const rawContent = await fetchRawFile(owner, repo, pathToTry, branch);
|
|
201
|
+
skillMdResponse = {
|
|
202
|
+
data: {
|
|
203
|
+
content: Buffer.from(rawContent).toString("base64"),
|
|
204
|
+
encoding: "base64"
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
break;
|
|
208
|
+
} catch (rawError) {
|
|
209
|
+
throw new Error(`GitHub API timeout. Try using --no-api flag or check your network connection.`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (error.status === 404) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
throw new Error(`Failed to fetch from GitHub: ${error.message}`);
|
|
169
216
|
}
|
|
170
|
-
|
|
217
|
+
}
|
|
218
|
+
if (!skillMdResponse) {
|
|
219
|
+
throw new Error(`SKILL.md not found at ${owner}/${repo} (tried ${pathsToTry.length} paths)`);
|
|
171
220
|
}
|
|
172
221
|
if (!("content" in skillMdResponse.data)) {
|
|
173
222
|
throw new Error("SKILL.md not found");
|
|
@@ -589,9 +638,11 @@ var pkg = require2("../package.json");
|
|
|
589
638
|
var VERSION = pkg.version;
|
|
590
639
|
var program = new Command();
|
|
591
640
|
program.name("skillhub").description("CLI for managing AI Agent skills").version(VERSION);
|
|
592
|
-
program.command("install <skill-id>").description("Install a skill from the registry").option("-p, --platform <platform>", "Target platform (claude, codex, copilot, cursor, windsurf)"
|
|
641
|
+
program.command("install <skill-id>").description("Install a skill from the registry").option("-p, --platform <platform>", "Target platform (claude, codex, copilot, cursor, windsurf)").option("--project", "Install in the current project instead of globally").option("-f, --force", "Overwrite existing skill").option("--no-api", "Skip API lookup and fetch directly from GitHub").action(async (skillId, options) => {
|
|
642
|
+
const userConfig = await loadConfig();
|
|
643
|
+
const platform = options.platform || userConfig.defaultPlatform || "claude";
|
|
593
644
|
await install(skillId, {
|
|
594
|
-
platform
|
|
645
|
+
platform,
|
|
595
646
|
project: options.project,
|
|
596
647
|
force: options.force,
|
|
597
648
|
noApi: !options.api
|
|
@@ -607,31 +658,35 @@ program.command("list").description("List installed skills").option("-p, --platf
|
|
|
607
658
|
program.command("config").description("Manage CLI configuration").option("--set <key=value>", "Set a configuration value").option("--get <key>", "Get a configuration value").option("--list", "List all configuration values").action(async (options) => {
|
|
608
659
|
await config(options);
|
|
609
660
|
});
|
|
610
|
-
program.command("uninstall <skill-name>").description("Uninstall a skill").option("-p, --platform <platform>", "Target platform"
|
|
661
|
+
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) => {
|
|
611
662
|
const fs3 = await import("fs-extra");
|
|
612
663
|
const { getSkillPath: getSkillPath2, isSkillInstalled: isSkillInstalled2 } = await import("./paths-BVI5WSHE.js");
|
|
613
|
-
const
|
|
664
|
+
const userConfig = await loadConfig();
|
|
665
|
+
const platform = options.platform || userConfig.defaultPlatform || "claude";
|
|
666
|
+
const installed = await isSkillInstalled2(platform, skillName, options.project);
|
|
614
667
|
if (!installed) {
|
|
615
668
|
console.log(chalk5.yellow(`Skill ${skillName} is not installed.`));
|
|
616
669
|
process.exit(1);
|
|
617
670
|
}
|
|
618
|
-
const skillPath = getSkillPath2(
|
|
671
|
+
const skillPath = getSkillPath2(platform, skillName, options.project);
|
|
619
672
|
await fs3.default.remove(skillPath);
|
|
620
673
|
console.log(chalk5.green(`Skill ${skillName} uninstalled successfully.`));
|
|
621
674
|
});
|
|
622
|
-
program.command("update [skill-name]").description("Update installed skills").option("-p, --platform <platform>", "Target platform"
|
|
675
|
+
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) => {
|
|
623
676
|
const fsExtra = await import("fs-extra");
|
|
624
677
|
const pathModule = await import("path");
|
|
625
678
|
const { getSkillsPath: getSkillsPath2, getSkillPath: getSkillPath2 } = await import("./paths-BVI5WSHE.js");
|
|
679
|
+
const userConfig = await loadConfig();
|
|
680
|
+
const platform = options.platform || userConfig.defaultPlatform || "claude";
|
|
626
681
|
const ALL_PLATFORMS2 = ["claude", "codex", "copilot", "cursor", "windsurf"];
|
|
627
682
|
if (options.all) {
|
|
628
683
|
console.log(chalk5.cyan("\nUpdating all installed skills...\n"));
|
|
629
|
-
const platforms = options.platform ? [
|
|
684
|
+
const platforms = options.platform ? [platform] : ALL_PLATFORMS2;
|
|
630
685
|
let updated = 0;
|
|
631
686
|
let failed = 0;
|
|
632
687
|
let skipped = 0;
|
|
633
|
-
for (const
|
|
634
|
-
const skillsPath = getSkillsPath2(
|
|
688
|
+
for (const p of platforms) {
|
|
689
|
+
const skillsPath = getSkillsPath2(p);
|
|
635
690
|
if (!await fsExtra.default.pathExists(skillsPath)) {
|
|
636
691
|
continue;
|
|
637
692
|
}
|
|
@@ -655,7 +710,7 @@ program.command("update [skill-name]").description("Update installed skills").op
|
|
|
655
710
|
}
|
|
656
711
|
console.log(chalk5.dim(` Updating ${entry.name}...`));
|
|
657
712
|
await install(skillId, {
|
|
658
|
-
platform,
|
|
713
|
+
platform: p,
|
|
659
714
|
force: true
|
|
660
715
|
});
|
|
661
716
|
updated++;
|
|
@@ -675,7 +730,7 @@ program.command("update [skill-name]").description("Update installed skills").op
|
|
|
675
730
|
console.log(chalk5.red("Please specify a skill name or use --all."));
|
|
676
731
|
process.exit(1);
|
|
677
732
|
}
|
|
678
|
-
const skillPath = getSkillPath2(
|
|
733
|
+
const skillPath = getSkillPath2(platform, skillName);
|
|
679
734
|
const metadataPath = pathModule.join(skillPath, ".skillhub.json");
|
|
680
735
|
if (!await fsExtra.default.pathExists(metadataPath)) {
|
|
681
736
|
console.log(chalk5.yellow(`Skill ${skillName} was not installed via CLI.`));
|
|
@@ -691,7 +746,7 @@ program.command("update [skill-name]").description("Update installed skills").op
|
|
|
691
746
|
}
|
|
692
747
|
console.log(chalk5.dim(`Updating ${skillName}...`));
|
|
693
748
|
await install(skillId, {
|
|
694
|
-
platform
|
|
749
|
+
platform,
|
|
695
750
|
force: true
|
|
696
751
|
});
|
|
697
752
|
} catch (error) {
|
package/package.json
CHANGED