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.
Files changed (2) hide show
  1. package/dist/index.js +81 -26
  2. 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
- try {
157
- skillMdResponse = await client.repos.getContent({
158
- owner,
159
- repo,
160
- path: skillMdPath,
161
- ref: branch
162
- });
163
- } catch (error) {
164
- if (error.status === 404) {
165
- throw new Error(`SKILL.md not found at ${owner}/${repo}/${skillMdPath}`);
166
- }
167
- if (error.message?.includes("timeout")) {
168
- throw new Error(`GitHub request timeout. Check your internet connection or try again later.`);
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
- throw new Error(`Failed to fetch from GitHub: ${error.message}`);
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)", "claude").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) => {
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: options.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", "claude").option("--project", "Uninstall from project instead of globally").action(async (skillName, options) => {
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 installed = await isSkillInstalled2(options.platform, skillName, options.project);
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(options.platform, skillName, options.project);
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", "claude").option("--all", "Update all installed skills").action(async (skillName, options) => {
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 ? [options.platform] : ALL_PLATFORMS2;
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 platform of platforms) {
634
- const skillsPath = getSkillsPath2(platform);
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(options.platform, skillName);
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: options.platform,
749
+ platform,
695
750
  force: true
696
751
  });
697
752
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillhub",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "CLI tool for managing AI Agent skills - search, install, and update skills for Claude, Codex, Copilot, and more",
5
5
  "author": "SkillHub Contributors",
6
6
  "license": "MIT",