skillhub 0.1.3 → 0.1.5

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 +57 -15
  2. package/package.json +13 -3
package/dist/index.js CHANGED
@@ -111,7 +111,8 @@ async function searchSkills(query, options = {}) {
111
111
  return JSON.parse(response.data);
112
112
  }
113
113
  async function getSkill(id) {
114
- const response = await httpsRequest(`${API_BASE_URL}/skills/${encodeURIComponent(id)}`);
114
+ const encodedPath = id.split("/").map(encodeURIComponent).join("/");
115
+ const response = await httpsRequest(`${API_BASE_URL}/skills/${encodedPath}`);
115
116
  if (response.statusCode === 404) {
116
117
  return null;
117
118
  }
@@ -122,7 +123,8 @@ async function getSkill(id) {
122
123
  }
123
124
  async function trackInstall(skillId, platform, method = "cli") {
124
125
  try {
125
- await httpsRequest(`${API_BASE_URL}/skills/${encodeURIComponent(skillId)}/install`, {
126
+ const encodedPath = skillId.split("/").map(encodeURIComponent).join("/");
127
+ await httpsRequest(`${API_BASE_URL}/skills/${encodedPath}/install`, {
126
128
  method: "POST",
127
129
  headers: { "Content-Type": "application/json" },
128
130
  body: JSON.stringify({ platform, method })
@@ -138,7 +140,11 @@ function getOctokit() {
138
140
  if (!octokit) {
139
141
  octokit = new Octokit({
140
142
  auth: process.env.GITHUB_TOKEN,
141
- userAgent: "SkillHub-CLI/1.0"
143
+ userAgent: "SkillHub-CLI/1.0",
144
+ request: {
145
+ timeout: 3e4
146
+ // 30 second timeout
147
+ }
142
148
  });
143
149
  }
144
150
  return octokit;
@@ -146,12 +152,23 @@ function getOctokit() {
146
152
  async function fetchSkillContent(owner, repo, skillPath, branch = "main") {
147
153
  const client = getOctokit();
148
154
  const skillMdPath = skillPath ? `${skillPath}/SKILL.md` : "SKILL.md";
149
- const skillMdResponse = await client.repos.getContent({
150
- owner,
151
- repo,
152
- path: skillMdPath,
153
- ref: branch
154
- });
155
+ 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.`);
169
+ }
170
+ throw new Error(`Failed to fetch from GitHub: ${error.message}`);
171
+ }
155
172
  if (!("content" in skillMdResponse.data)) {
156
173
  throw new Error("SKILL.md not found");
157
174
  }
@@ -239,7 +256,13 @@ async function install(skillId, options) {
239
256
  }
240
257
  const [owner, repo, ...rest] = parts;
241
258
  const skillPath = rest.join("/");
242
- const skillInfo = await getSkill(skillId);
259
+ let skillInfo;
260
+ try {
261
+ skillInfo = await getSkill(skillId);
262
+ } catch (error) {
263
+ spinner.warn(`API error: ${error.message}`);
264
+ spinner.start("Falling back to direct GitHub fetch...");
265
+ }
243
266
  let skillName;
244
267
  let branch = "main";
245
268
  if (skillInfo) {
@@ -247,8 +270,13 @@ async function install(skillId, options) {
247
270
  spinner.text = `Found skill: ${chalk.cyan(skillName)}`;
248
271
  } else {
249
272
  spinner.text = "Skill not in registry, fetching from GitHub...";
250
- branch = await getDefaultBranch(owner, repo);
251
- skillName = skillPath || repo;
273
+ try {
274
+ branch = await getDefaultBranch(owner, repo);
275
+ skillName = skillPath || repo;
276
+ } catch (error) {
277
+ spinner.fail("Failed to connect to GitHub");
278
+ throw error;
279
+ }
252
280
  }
253
281
  const installed = await isSkillInstalled(options.platform, skillName, options.project);
254
282
  if (installed && !options.force) {
@@ -258,8 +286,22 @@ async function install(skillId, options) {
258
286
  process.exit(1);
259
287
  }
260
288
  await ensureSkillsDir(options.platform, options.project);
261
- spinner.text = "Downloading skill files...";
262
- const content = await fetchSkillContent(owner, repo, skillPath, branch);
289
+ spinner.text = `Downloading from ${owner}/${repo}/${skillPath || ""}...`;
290
+ let content;
291
+ try {
292
+ content = await fetchSkillContent(owner, repo, skillPath, branch);
293
+ spinner.text = `Downloaded ${content.scripts.length} scripts, ${content.references.length} references`;
294
+ } catch (error) {
295
+ spinner.fail("Failed to download skill files");
296
+ console.error(chalk.red(error.message));
297
+ console.log();
298
+ console.log(chalk.yellow("Troubleshooting tips:"));
299
+ console.log(chalk.dim(" 1. Check your internet connection"));
300
+ console.log(chalk.dim(" 2. If behind a proxy, configure HTTP_PROXY/HTTPS_PROXY environment variables"));
301
+ console.log(chalk.dim(" 3. Try again in a few minutes (GitHub API might be rate-limited)"));
302
+ console.log(chalk.dim(" 4. Set GITHUB_TOKEN environment variable for higher rate limits"));
303
+ process.exit(1);
304
+ }
263
305
  const parsed = parseSkillMd(content.skillMd);
264
306
  if (!parsed.validation.isValid) {
265
307
  spinner.warn("Skill has validation issues:");
@@ -357,7 +399,7 @@ async function search(query, options) {
357
399
  const verified = skill.isVerified ? chalk2.green("\u2713") : " ";
358
400
  const security = getSecurityBadge(skill.securityScore);
359
401
  console.log(
360
- `${verified} ${chalk2.cyan(skill.name.padEnd(25))} ${security} \u2B50 ${formatNumber(skill.githubStars).padStart(6)} \u2B07 ${formatNumber(skill.downloadCount).padStart(6)}`
402
+ `${verified} ${chalk2.cyan(skill.id.padEnd(40))} ${security} \u2B50 ${formatNumber(skill.githubStars).padStart(6)} \u2B07 ${formatNumber(skill.downloadCount).padStart(6)}`
361
403
  );
362
404
  console.log(
363
405
  ` ${chalk2.dim(skill.description.slice(0, 70))}${skill.description.length > 70 ? "..." : ""}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillhub",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
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",
@@ -14,7 +14,9 @@
14
14
  "bin": {
15
15
  "skillhub": "./dist/index.js"
16
16
  },
17
- "files": ["dist"],
17
+ "files": [
18
+ "dist"
19
+ ],
18
20
  "scripts": {
19
21
  "build": "tsup src/index.ts --format esm --target node20 --clean",
20
22
  "dev": "tsx src/index.ts",
@@ -45,5 +47,13 @@
45
47
  "engines": {
46
48
  "node": ">=18.0.0"
47
49
  },
48
- "keywords": ["ai", "agent", "skills", "cli", "claude", "codex", "copilot"]
50
+ "keywords": [
51
+ "ai",
52
+ "agent",
53
+ "skills",
54
+ "cli",
55
+ "claude",
56
+ "codex",
57
+ "copilot"
58
+ ]
49
59
  }