'use client'; import React, { useEffect, useState, useRef } from 'react'; import { Puzzle, Upload, Download, Trash2, RefreshCw, Loader2, AlertCircle, X, } from 'lucide-react'; import { listSkills, deleteSkill, uploadSkill, downloadSkill } from '@/lib/api'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import type { Skill } from '@/types'; export default function SkillsPage() { const [skills, setSkills] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [showUpload, setShowUpload] = useState(false); const [deleting, setDeleting] = useState(null); const loadSkills = async () => { setLoading(true); setError(null); try { const data = await listSkills(); setSkills(Array.isArray(data) ? data : []); } catch (err: any) { setError(err.message || '加载技能失败'); } finally { setLoading(false); } }; useEffect(() => { loadSkills(); }, []); const handleDelete = async (name: string) => { setDeleting(name); }; const confirmDelete = async (name: string) => { try { await deleteSkill(name); setDeleting(null); loadSkills(); } catch (err: any) { setError(err.message || '删除技能失败'); setDeleting(null); } }; const handleUploadDone = () => { setShowUpload(false); loadSkills(); }; if (loading) { return (
); } return (

技能

{error && (
{error}
)} {/* Upload Dialog */} {showUpload && ( setShowUpload(false)} onError={(msg) => setError(msg)} /> )} {/* Delete Confirmation */} {deleting && (

确定删除技能 {deleting} 吗?此操作不可撤销。

)} {/* Skills Table */} {skills.length === 0 ? (

暂无技能

上传一个技能 zip 包即可开始使用。

) : ( 名称 描述 来源 状态 操作 {skills.map((skill) => ( {skill.name} {skill.description} {skill.source === 'builtin' ? ( 内置 ) : ( 工作区 )} {skill.available ? ( 可用 ) : ( 不可用 )}
{skill.source === 'workspace' && ( )}
))}
)}
); } function UploadSkillForm({ onDone, onCancel, onError, }: { onDone: () => void; onCancel: () => void; onError: (msg: string) => void; }) { const [uploading, setUploading] = useState(false); const fileRef = useRef(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const file = fileRef.current?.files?.[0]; if (!file) return; setUploading(true); try { await uploadSkill(file); onDone(); } catch (err: any) { onError(err.message || '上传失败'); } finally { setUploading(false); } }; return (
上传技能

压缩包中必须包含 `SKILL.md` 文件

); }