import { useEffect, useMemo, useState } from "react"; import { BookOpenCheck, Search, Sparkles } from "lucide-react"; type Skill = { name: string; description: string; source: "Pi" | "Agents" | "Codex"; }; const sourceLabel: Record = { Pi: "Pi", Agents: "本地 Agents", Codex: "Codex", }; export function SkillsPage() { const [skills, setSkills] = useState([]); const [query, setQuery] = useState(""); const [loading, setLoading] = useState(true); const [error, setError] = useState(false); useEffect(() => { fetch("/api/pi/skills") .then((res) => { if (!res.ok) throw new Error("Unable to load skills"); return res.json() as Promise<{ skills?: Skill[] }>; }) .then((data) => setSkills(data.skills ?? [])) .catch(() => setError(true)) .finally(() => setLoading(false)); }, []); const visibleSkills = useMemo(() => { const keyword = query.trim().toLocaleLowerCase(); if (!keyword) return skills; return skills.filter((skill) => `${skill.name} ${skill.description} ${skill.source}`.toLocaleLowerCase().includes(keyword)); }, [query, skills]); return (

LOCAL CAPABILITIES

Skills

已发现 {skills.length} 个本地能力包,可在对话中按需调用。

{loading ?

正在读取本地 Skills…

: error ?

无法读取本地 Skills。

: visibleSkills.length === 0 ?

没有匹配的 Skills。

: (
{visibleSkills.map((skill) =>

{skill.name}

{sourceLabel[skill.source]}

{skill.description}

)}
)}
); }