mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-08 18:57:43 +02:00
[eric] skills: the Add box resolves pasted README install commands (npx/pnpm/bunx, skills.sh URLs) through the parser that shipped without a client
This commit is contained in:
@@ -14,6 +14,8 @@ import { fetchSkills } from '@/shared/state/skillsSlice';
|
||||
import {
|
||||
fetchAllRegistrySkills,
|
||||
installCuratedSkill,
|
||||
INSTALL_COMMAND_RE,
|
||||
parseInstallCommand,
|
||||
searchCommunitySkills,
|
||||
CommunitySkill,
|
||||
RegistrySkill,
|
||||
@@ -73,7 +75,14 @@ const DirectorySkillsTab: React.FC<Props> = ({ onOpenInstalled }) => {
|
||||
const seq = ++searchSeq.current;
|
||||
setCommunityLoading(true);
|
||||
try {
|
||||
const res = await searchCommunitySkills(query.trim());
|
||||
// A pasted README install command ("npx skills add pdf-filler", a skills.sh URL) resolves to
|
||||
// its skill id server-side first, so the box accepts the grammar people actually copy (ENG-217).
|
||||
let effective = query.trim();
|
||||
if (INSTALL_COMMAND_RE.test(effective)) {
|
||||
const skillId = await parseInstallCommand(effective).catch(() => null);
|
||||
if (skillId) effective = skillId;
|
||||
}
|
||||
const res = await searchCommunitySkills(effective);
|
||||
if (seq === searchSeq.current) setCommunity(res);
|
||||
} catch {
|
||||
if (seq === searchSeq.current) setCommunity([]);
|
||||
@@ -95,7 +104,9 @@ const DirectorySkillsTab: React.FC<Props> = ({ onOpenInstalled }) => {
|
||||
}, [localSkills]);
|
||||
|
||||
const cards = useMemo((): SkillCardModel[] => {
|
||||
const q = query.trim().toLowerCase();
|
||||
// A pasted install command already resolved server-side into the community results; filtering
|
||||
// those hits against the raw paste string would hide the exact skill the user asked for.
|
||||
const q = INSTALL_COMMAND_RE.test(query.trim()) ? '' : query.trim().toLowerCase();
|
||||
// Join curated skills to their skills.sh twin (source anthropics/skills) so Anthropic cards get real install counts.
|
||||
const communityByName = new Map(community.map((cs) => [cs.name.trim().toLowerCase(), cs]));
|
||||
const out: SkillCardModel[] = [];
|
||||
|
||||
@@ -207,6 +207,20 @@ export interface InstallDisclosure {
|
||||
secret_findings: string[];
|
||||
}
|
||||
|
||||
// The grammar people copy out of READMEs; cheap local gate so plain searches never buy a round-trip.
|
||||
export const INSTALL_COMMAND_RE = /^(npx|npm|pnpm|bunx|yarn)\s|skills\.sh\//i;
|
||||
|
||||
export async function parseInstallCommand(command: string): Promise<string | null> {
|
||||
const res = await fetch(`${SKILL_REGISTRY_API}/parse-command`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ command }),
|
||||
});
|
||||
if (!res.ok) return null;
|
||||
const data = (await res.json()) as { skill_id: string | null };
|
||||
return data.skill_id ?? null;
|
||||
}
|
||||
|
||||
export async function searchCommunitySkills(q: string): Promise<CommunitySkill[]> {
|
||||
const params = new URLSearchParams({ q, limit: '30', source: 'community' });
|
||||
const res = await fetch(`${SKILL_REGISTRY_API}/search?${params}`);
|
||||
|
||||
Reference in New Issue
Block a user