import { useEffect, useRef, useState } from 'react'; import { api } from '../api'; import { useDebounced } from '../useDebounce'; import type { CapabilityResult } from '../types'; const TYPES = ['all', 'skill', 'agent', 'command', 'rule', 'flow', 'behavior', 'hook', 'template', 'tool', 'addon', 'framework', 'extension', 'plugin', 'provider', 'document']; // Tenor-style capability search — modeled on fortemi-react's SearchBar + SearchResults // (debounced input, Ctrl/⌘-K focus, card grid with rank + snippet + trigger tags), // wired to the AIWG registry via the Bridge (read-only catalog data; never execution). export function CapabilitySearch({ onPick, autoFocus, compact, refreshTick = 0 }: { onPick: (c: CapabilityResult) => void; autoFocus?: boolean; compact?: boolean; refreshTick?: number; }) { const [q, setQ] = useState(''); const [type, setType] = useState('all'); const [results, setResults] = useState(null); const [err, setErr] = useState(''); const debounced = useDebounced(q, 300); const inputRef = useRef(null); useEffect(() => { if (autoFocus) inputRef.current?.focus(); }, [autoFocus]); useEffect(() => { const onKey = (e: KeyboardEvent) => { if ((e.ctrlKey || e.metaKey) && e.key === 'k') { e.preventDefault(); inputRef.current?.focus(); } }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, []); useEffect(() => { const term = debounced.trim(); if (!term) { setResults(null); return; } let live = true; api<{ results: CapabilityResult[] }>(`/api/capabilities?q=${encodeURIComponent(term)}&type=${encodeURIComponent(type)}&limit=12`) .then((d) => { if (live) { setResults(d.results); setErr(''); } }) .catch((e) => { if (live) setErr((e as Error).message); }); return () => { live = false; }; }, [debounced, type, refreshTick]); return (
setQ(e.target.value)} placeholder="Search capabilities… (Ctrl/⌘-K)" aria-label="Search capabilities" style={{ minWidth: compact ? 220 : 300 }} />
{err &&

{err}

} {results === null ?

Type to search every indexed capability and artifact type.

: !results.length ?

No matches.

: (
{results.map((r) => ( ))}
)}
); }