@rely-ai/caliber 0.5.0 → 0.5.2

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/bin.js +59 -36
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -4628,8 +4628,7 @@ function getInstalledSkills() {
4628
4628
  return installed;
4629
4629
  }
4630
4630
  async function searchSkillsSh(technologies) {
4631
- const results = [];
4632
- const seen = /* @__PURE__ */ new Set();
4631
+ const bestBySlug = /* @__PURE__ */ new Map();
4633
4632
  for (const tech of technologies) {
4634
4633
  try {
4635
4634
  const resp = await fetch(`https://skills.sh/api/search?q=${encodeURIComponent(tech)}&limit=10`, {
@@ -4639,23 +4638,24 @@ async function searchSkillsSh(technologies) {
4639
4638
  const data = await resp.json();
4640
4639
  if (!data.skills?.length) continue;
4641
4640
  for (const skill of data.skills) {
4642
- if (seen.has(skill.skillId)) continue;
4643
- seen.add(skill.skillId);
4644
- results.push({
4641
+ const existing = bestBySlug.get(skill.skillId);
4642
+ if (existing && existing.installs >= (skill.installs ?? 0)) continue;
4643
+ bestBySlug.set(skill.skillId, {
4645
4644
  name: skill.name,
4646
4645
  slug: skill.skillId,
4647
4646
  source_url: skill.source ? `https://github.com/${skill.source}` : "",
4648
4647
  score: 0,
4649
4648
  reason: skill.description || "",
4650
4649
  detected_technology: tech,
4651
- item_type: "skill"
4650
+ item_type: "skill",
4651
+ installs: skill.installs ?? 0
4652
4652
  });
4653
4653
  }
4654
4654
  } catch {
4655
4655
  continue;
4656
4656
  }
4657
4657
  }
4658
- return results;
4658
+ return Array.from(bestBySlug.values());
4659
4659
  }
4660
4660
  async function searchTessl(technologies) {
4661
4661
  const results = [];
@@ -4736,8 +4736,9 @@ async function searchAllProviders(technologies, platform) {
4736
4736
  const combined = [];
4737
4737
  for (const batch of results) {
4738
4738
  for (const result of batch) {
4739
- if (seen.has(result.slug)) continue;
4740
- seen.add(result.slug);
4739
+ const key = result.name.toLowerCase().replace(/[-_]/g, "");
4740
+ if (seen.has(key)) continue;
4741
+ seen.add(key);
4741
4742
  combined.push(result);
4742
4743
  }
4743
4744
  }
@@ -4934,9 +4935,24 @@ async function recommendCommand(options) {
4934
4935
  } else {
4935
4936
  results = newCandidates.slice(0, 20);
4936
4937
  }
4937
- const selected = await interactiveSelect(results);
4938
+ const fetchSpinner = ora4("Verifying skill availability...").start();
4939
+ const contentMap = /* @__PURE__ */ new Map();
4940
+ await Promise.all(results.map(async (rec) => {
4941
+ const content = await fetchSkillContent(rec);
4942
+ if (content) contentMap.set(rec.slug, content);
4943
+ }));
4944
+ const available = results.filter((r) => contentMap.has(r.slug));
4945
+ if (!available.length) {
4946
+ fetchSpinner.fail("No installable skills found \u2014 content could not be fetched.");
4947
+ return;
4948
+ }
4949
+ const unavailableCount = results.length - available.length;
4950
+ fetchSpinner.succeed(
4951
+ `${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ? chalk8.dim(` (${unavailableCount} unavailable)`) : "")
4952
+ );
4953
+ const selected = await interactiveSelect(available);
4938
4954
  if (selected?.length) {
4939
- await installSkills(selected, platforms);
4955
+ await installSkills(selected, platforms, contentMap);
4940
4956
  }
4941
4957
  }
4942
4958
  async function interactiveSelect(recs) {
@@ -5039,38 +5055,48 @@ async function interactiveSelect(recs) {
5039
5055
  });
5040
5056
  }
5041
5057
  async function fetchSkillContent(rec) {
5042
- try {
5043
- const resp = await fetch(`https://skills.sh/api/skills/${rec.slug}`, {
5044
- signal: AbortSignal.timeout(1e4)
5045
- });
5046
- if (resp.ok) {
5047
- const data = await resp.json();
5048
- const content = data.content || data.text;
5049
- if (content) return content;
5050
- }
5051
- } catch {
5052
- }
5053
- if (rec.source_url) {
5058
+ if (!rec.source_url) return null;
5059
+ const repoPath = rec.source_url.replace("https://github.com/", "");
5060
+ const candidates = [
5061
+ `https://raw.githubusercontent.com/${repoPath}/HEAD/skills/${rec.slug}/SKILL.md`,
5062
+ `https://raw.githubusercontent.com/${repoPath}/HEAD/${rec.slug}/SKILL.md`,
5063
+ `https://raw.githubusercontent.com/${repoPath}/HEAD/.claude/skills/${rec.slug}/SKILL.md`
5064
+ ];
5065
+ for (const url of candidates) {
5054
5066
  try {
5055
- const repoPath = rec.source_url.replace("https://github.com/", "");
5056
- const url = `https://raw.githubusercontent.com/${repoPath}/HEAD/skills/${rec.slug}/SKILL.md`;
5057
5067
  const resp = await fetch(url, { signal: AbortSignal.timeout(1e4) });
5058
- if (resp.ok) return await resp.text();
5068
+ if (resp.ok) {
5069
+ const text = await resp.text();
5070
+ if (text.length > 20) return text;
5071
+ }
5059
5072
  } catch {
5060
5073
  }
5061
5074
  }
5075
+ try {
5076
+ const resp = await fetch(
5077
+ `https://api.github.com/repos/${repoPath}/git/trees/HEAD?recursive=1`,
5078
+ { signal: AbortSignal.timeout(1e4) }
5079
+ );
5080
+ if (resp.ok) {
5081
+ const tree = await resp.json();
5082
+ const needle = `${rec.slug}/SKILL.md`;
5083
+ const match = tree.tree?.find((f) => f.path.endsWith(needle));
5084
+ if (match) {
5085
+ const rawUrl = `https://raw.githubusercontent.com/${repoPath}/HEAD/${match.path}`;
5086
+ const contentResp = await fetch(rawUrl, { signal: AbortSignal.timeout(1e4) });
5087
+ if (contentResp.ok) return await contentResp.text();
5088
+ }
5089
+ }
5090
+ } catch {
5091
+ }
5062
5092
  return null;
5063
5093
  }
5064
- async function installSkills(recs, platforms) {
5094
+ async function installSkills(recs, platforms, contentMap) {
5065
5095
  const spinner = ora4(`Installing ${recs.length} skill${recs.length > 1 ? "s" : ""}...`).start();
5066
5096
  const installed = [];
5067
- const warnings = [];
5068
5097
  for (const rec of recs) {
5069
- const content = await fetchSkillContent(rec);
5070
- if (!content) {
5071
- warnings.push(`No content available for ${rec.name}`);
5072
- continue;
5073
- }
5098
+ const content = contentMap.get(rec.slug);
5099
+ if (!content) continue;
5074
5100
  for (const platform of platforms) {
5075
5101
  const skillPath = getSkillPath(platform, rec.slug);
5076
5102
  const fullPath = join8(process.cwd(), skillPath);
@@ -5087,9 +5113,6 @@ async function installSkills(recs, platforms) {
5087
5113
  } else {
5088
5114
  spinner.fail("No skills were installed");
5089
5115
  }
5090
- for (const w of warnings) {
5091
- console.log(chalk8.yellow(` \u26A0 ${w}`));
5092
- }
5093
5116
  console.log("");
5094
5117
  }
5095
5118
  function printRecommendations(recs) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Analyze your codebase and generate optimized AI agent configs (CLAUDE.md, .cursorrules, skills) — no API key needed",
5
5
  "type": "module",
6
6
  "bin": {