skillhub 0.2.5 → 0.2.7

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 +44 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3516,6 +3516,12 @@ var VALID_PLATFORMS = ["claude", "codex", "copilot", "cursor", "windsurf"];
3516
3516
  var NAME_PATTERN = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/;
3517
3517
  var MAX_DESCRIPTION_LENGTH = 1024;
3518
3518
  var MAX_NAME_LENGTH = 64;
3519
+ function sanitizeUtf8(input) {
3520
+ let result = input.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, "");
3521
+ result = Buffer.from(result, "utf8").toString("utf8");
3522
+ result = result.replace(/[\uD800-\uDFFF]/g, "");
3523
+ return result;
3524
+ }
3519
3525
  var INSTRUCTION_FILE_PATTERNS = [
3520
3526
  {
3521
3527
  format: "skill.md",
@@ -3600,8 +3606,8 @@ function parseSkillMd(content) {
3600
3606
  validateTriggers(frontmatter.triggers, warnings);
3601
3607
  }
3602
3608
  const metadata = {
3603
- name: String(frontmatter.name || ""),
3604
- description: String(frontmatter.description || ""),
3609
+ name: sanitizeUtf8(String(frontmatter.name || "")),
3610
+ description: sanitizeUtf8(String(frontmatter.description || "")),
3605
3611
  version: frontmatter.version ? String(frontmatter.version) : void 0,
3606
3612
  license: frontmatter.license ? String(frontmatter.license) : void 0,
3607
3613
  author: frontmatter.author ? String(frontmatter.author) : void 0,
@@ -3784,8 +3790,8 @@ function parseGenericInstructionFile(content, format, repoMeta) {
3784
3790
  const derivedDescription = frontmatter.description || repoMeta.description || extractFirstParagraph(body) || `${FORMAT_LABELS[format]} from ${repoMeta.owner}/${repoMeta.name}`;
3785
3791
  const inferredPlatform = pattern?.inferredPlatform || "claude";
3786
3792
  const metadata = {
3787
- name: derivedName,
3788
- description: derivedDescription.slice(0, MAX_DESCRIPTION_LENGTH),
3793
+ name: sanitizeUtf8(derivedName),
3794
+ description: sanitizeUtf8(derivedDescription.slice(0, MAX_DESCRIPTION_LENGTH)),
3789
3795
  version: frontmatter.version ? String(frontmatter.version) : void 0,
3790
3796
  license: frontmatter.license ? String(frontmatter.license) : void 0,
3791
3797
  author: frontmatter.author ? String(frontmatter.author) : repoMeta.owner,
@@ -3828,6 +3834,21 @@ function extractFirstParagraph(content) {
3828
3834
  }
3829
3835
  return null;
3830
3836
  }
3837
+ var TAG_KEYS = [
3838
+ "RATIONALE",
3839
+ "USE-CASES",
3840
+ "AUDIENCE",
3841
+ "COMPLEMENTS",
3842
+ "SEO-EN",
3843
+ "BUNDLE-FIT",
3844
+ "FRAMEWORK-LOCK",
3845
+ "CONTRIBUTING-REPO",
3846
+ "MATURITY",
3847
+ "COMPLEXITY",
3848
+ "DEPENDENCIES",
3849
+ "PLATFORM"
3850
+ ];
3851
+ var TAG_REGEX = new RegExp(`(${TAG_KEYS.join("|")}):\\s*`, "g");
3831
3852
 
3832
3853
  // src/utils/api.ts
3833
3854
  import https from "https";
@@ -4298,7 +4319,8 @@ async function install(skillId, options2) {
4298
4319
  try {
4299
4320
  skillInfo = await getSkill(skillId);
4300
4321
  if (skillInfo) {
4301
- spinner.succeed(`Found in registry: ${skillInfo.name}`);
4322
+ const reviewBadge = skillInfo.aiScore && skillInfo.reviewStatus === "ai-reviewed" ? chalk.dim(` | AI: ${skillInfo.aiScore}/100`) : skillInfo.reviewStatus === "verified" ? chalk.green(` | AI: ${skillInfo.aiScore}/100 \u2713`) : "";
4323
+ spinner.succeed(`Found in registry: ${skillInfo.name}${reviewBadge}`);
4302
4324
  spinner.start("Preparing installation...");
4303
4325
  }
4304
4326
  } catch (error) {
@@ -4344,6 +4366,12 @@ async function install(skillId, options2) {
4344
4366
  spinner.text = "Downloading skill files...";
4345
4367
  const cachedFiles = await getSkillFiles(skillInfo.id);
4346
4368
  if (cachedFiles && cachedFiles.files.length > 0) {
4369
+ if (cachedFiles.isStale) {
4370
+ spinner.warn(chalk.yellow(
4371
+ "This skill may have been removed from its GitHub repository.\n Files were served from the SkillHub cache and may be outdated."
4372
+ ));
4373
+ spinner.start("Installing from cached files...");
4374
+ }
4347
4375
  if (cachedFiles.sourceFormat) {
4348
4376
  sourceFormat = cachedFiles.sourceFormat;
4349
4377
  }
@@ -4573,7 +4601,7 @@ async function search(query, options2) {
4573
4601
  try {
4574
4602
  const limit = parseInt(options2.limit || "10");
4575
4603
  const page = parseInt(options2.page || "1");
4576
- const sort = options2.sort || "downloads";
4604
+ const sort = options2.sort || "recommended";
4577
4605
  const result = await searchSkills(query, {
4578
4606
  platform: options2.platform,
4579
4607
  limit,
@@ -4586,7 +4614,7 @@ async function search(query, options2) {
4586
4614
  console.log(chalk2.dim("Try a different search term or check the spelling."));
4587
4615
  return;
4588
4616
  }
4589
- const sortLabel = { downloads: "downloads", stars: "GitHub stars", rating: "rating", recent: "recently updated" }[sort] || sort;
4617
+ const sortLabel = { recommended: "recommended", downloads: "downloads", stars: "GitHub stars", rating: "rating", recent: "recently updated", aiScore: "AI score" }[sort] || sort;
4590
4618
  console.log(chalk2.bold(`Found ${result.pagination.total} skills (sorted by ${sortLabel}):
4591
4619
  `));
4592
4620
  console.log(
@@ -4610,6 +4638,12 @@ async function search(query, options2) {
4610
4638
  ` ${chalk2.yellow("\u2605")} ${skill.rating.toFixed(1)} ${chalk2.dim(`(${skill.ratingCount} ratings)`)}`
4611
4639
  );
4612
4640
  }
4641
+ if (skill.aiScore && skill.reviewStatus && skill.reviewStatus !== "unreviewed" && skill.reviewStatus !== "auto-scored") {
4642
+ const scoreColor = skill.aiScore >= 75 ? chalk2.green : skill.aiScore >= 50 ? chalk2.yellow : chalk2.dim;
4643
+ console.log(
4644
+ ` ${chalk2.magenta("AI")} ${scoreColor(String(skill.aiScore))} ${chalk2.dim(`(${skill.reviewStatus})`)}`
4645
+ );
4646
+ }
4613
4647
  console.log(chalk2.dim("\u2500".repeat(80)));
4614
4648
  }
4615
4649
  console.log();
@@ -4620,8 +4654,8 @@ async function search(query, options2) {
4620
4654
  chalk2.dim(`Page ${page} of ${totalPages}. Use ${chalk2.white(`--page ${page + 1}`)} for next page.`)
4621
4655
  );
4622
4656
  }
4623
- if (sort === "downloads") {
4624
- console.log(chalk2.dim(`Sort options: ${chalk2.white("--sort stars|rating|recent")}`));
4657
+ if (sort === "recommended") {
4658
+ console.log(chalk2.dim(`Sort options: ${chalk2.white("--sort downloads|stars|rating|recent|aiScore")}`));
4625
4659
  }
4626
4660
  } catch (error) {
4627
4661
  spinner.fail("Search failed");
@@ -4855,7 +4889,7 @@ program.command("install <skill-id>").description("Install a skill from the regi
4855
4889
  // Commander converts --no-api to api: false
4856
4890
  });
4857
4891
  });
4858
- program.command("search <query>").description("Search for skills in the registry").option("-p, --platform <platform>", "Filter by platform").option("-s, --sort <sort>", "Sort by: downloads, stars, rating, recent", "downloads").option("-l, --limit <number>", "Number of results", "10").option("--page <number>", "Page number", "1").action(async (query, options2) => {
4892
+ program.command("search <query>").description("Search for skills in the registry").option("-p, --platform <platform>", "Filter by platform").option("-s, --sort <sort>", "Sort by: recommended, downloads, stars, rating, recent, aiScore", "recommended").option("-l, --limit <number>", "Number of results", "10").option("--page <number>", "Page number", "1").action(async (query, options2) => {
4859
4893
  await search(query, options2);
4860
4894
  });
4861
4895
  program.command("list").description("List installed skills").option("-p, --platform <platform>", "Filter by platform").option("--project", "List skills in the current project").option("--all", "List both global and project skills").action(async (options2) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillhub",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
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",