diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index a38a6a41..9786c376 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -8,7 +8,7 @@ "name": "claudeclaw", "source": "./", "description": "Cron-like daemon that runs Claude prompts on a schedule", - "version": "1.0.41", + "version": "1.0.42", "keywords": [ "cron", "heartbeat", diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index e2be5931..b0891029 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,5 +1,5 @@ { "name": "claudeclaw", - "version": "1.0.41", + "version": "1.0.42", "description": "Cron-like daemon that runs Claude prompts on a schedule" } diff --git a/skills/install-skill/search.mjs b/skills/install-skill/search.mjs index 53fa4c1a..c6270558 100644 --- a/skills/install-skill/search.mjs +++ b/skills/install-skill/search.mjs @@ -1,6 +1,10 @@ // Search skills.sh and return JSON results // Usage: node search.mjs // Works with Node 18+, Bun, Deno +// +// Uses the skills.sh search API. The old approach (scraping embedded JSON +// out of the homepage HTML) broke when skills.sh moved to a Next.js app +// that loads results client-side. const query = process.argv[2]; if (!query) { @@ -9,33 +13,21 @@ if (!query) { } try { - const res = await fetch(`https://skills.sh/?q=${encodeURIComponent(query)}`); - const html = await res.text(); - - const skills = []; - const esc = `\\\\?"`; // matches both \" and " - const pattern = new RegExp( - `\\{${esc}source${esc}:${esc}([^"\\\\]+)${esc},${esc}skillId${esc}:${esc}([^"\\\\]+)${esc},${esc}name${esc}:${esc}([^"\\\\]+)${esc},${esc}installs${esc}:(\\d+)\\}`, - "g" + const res = await fetch( + `https://www.skills.sh/api/search?q=${encodeURIComponent(query)}` ); - let match; - while ((match = pattern.exec(html)) !== null) { - skills.push({ - source: match[1], - id: match[2], - name: match[3], - installs: parseInt(match[4]), - }); - } + if (!res.ok) throw new Error(`skills.sh API returned HTTP ${res.status}`); + const data = await res.json(); - const q = query.toLowerCase(); - let filtered = skills.filter( - (s) => s.name.toLowerCase().includes(q) || s.source.toLowerCase().includes(q) - ); - if (filtered.length === 0) filtered = skills.slice(0, 20); + const skills = (data.skills ?? []).map((s) => ({ + source: s.source, + id: s.skillId, + name: s.name, + installs: s.installs ?? 0, + })); - filtered.sort((a, b) => b.installs - a.installs); - console.log(JSON.stringify(filtered.slice(0, 15), null, 2)); + skills.sort((a, b) => b.installs - a.installs); + console.log(JSON.stringify(skills.slice(0, 15), null, 2)); } catch (e) { console.log(JSON.stringify({ error: e.message })); process.exit(1);