diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index bdd36c0f..00000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(grep \"\\\\.tsx$\")", - "Bash(awk '{print $NF}')", - "Bash(xargs -I {} basename {})" - ] - } -} diff --git a/.gitignore b/.gitignore index ed4d3dea..043f2941 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,20 @@ -# Workspace/editor -.vscode/ -frontend-web/.vscode/ - -# Local runtime logs and pid files -.runtime/ +# Workspace/editor +.vscode/ +frontend-web/.vscode/ + +# Claude Code local-only settings (per-user permissions, not shared) +.claude/settings.local.json + +# Local runtime logs and pid files +.runtime/ # Frontend local/runtime artifacts -frontend-web/.env -frontend-web/node_modules/ -frontend-web/.pnpm-store/ -frontend-web/tsconfig.tsbuildinfo -frontend-web/vite-dev.log -frontend-web/vite-dev.err.log +frontend-web/.env +frontend-web/node_modules/ +frontend-web/.pnpm-store/ +frontend-web/tsconfig.tsbuildinfo +frontend-web/vite-dev.log +frontend-web/vite-dev.err.log # Frontend local packages/archives/docs (non-source) frontend-web/pnpm-lock.yaml @@ -52,11 +55,11 @@ offline-backend-20260512/config.yaml offline-backend-20260512/config.yaml.example offline-backend-20260512/data/ offline-backend-20260512/deerflow-backend-offline-image-20260505.tar -offline-backend-20260512/extensions_config.json -offline-backend-20260512/skills/ -offline-backend-20260512/wheelhouse/ -offline-backend-20260512/backend/.deer-flow/data/*.db -offline-backend-20260512/backend/.deer-flow/data/*.db-* -offline-backend-20260512/start_backend.sh -offline-backend-20260512/stop_backend.sh -offline-backend-20260512/check_backend.sh +offline-backend-20260512/extensions_config.json +offline-backend-20260512/skills/ +offline-backend-20260512/wheelhouse/ +offline-backend-20260512/backend/.deer-flow/data/*.db +offline-backend-20260512/backend/.deer-flow/data/*.db-* +offline-backend-20260512/start_backend.sh +offline-backend-20260512/stop_backend.sh +offline-backend-20260512/check_backend.sh diff --git a/frontend-web/src/components/workspace/agents/agent-card.tsx b/frontend-web/src/components/workspace/agents/agent-card.tsx index 42b4a1e5..cc136d61 100644 --- a/frontend-web/src/components/workspace/agents/agent-card.tsx +++ b/frontend-web/src/components/workspace/agents/agent-card.tsx @@ -1,406 +1,418 @@ -"use client"; - -import { - BotIcon, - EyeIcon, - EyeOffIcon, - MessageSquareIcon, - SquarePenIcon, - Trash2Icon, -} from "lucide-react"; -import { useRouter } from "next/navigation"; -import { useEffect, useMemo, useState } from "react"; -import { toast } from "sonner"; - -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { Switch } from "@/components/ui/switch"; -import { Textarea } from "@/components/ui/textarea"; -import { useDeleteAgent, useUpdateAgent } from "@/core/agents"; -import type { Agent } from "@/core/agents"; -import { getStoredAuth } from "@/core/auth"; -import { useI18n } from "@/core/i18n/hooks"; -import { useSkills } from "@/core/skills/hooks"; - -interface AgentCardProps { - agent: Agent; -} - -export function AgentCard({ agent }: AgentCardProps) { - const { t } = useI18n(); - const router = useRouter(); - const deleteAgent = useDeleteAgent(); - const updateAgent = useUpdateAgent(); - const { skills, isLoading: isSkillsLoading } = useSkills(); - const [deleteOpen, setDeleteOpen] = useState(false); - const [editOpen, setEditOpen] = useState(false); - const [editName, setEditName] = useState(agent.name); - const [editDescription, setEditDescription] = useState(agent.description ?? ""); - const [editSoul, setEditSoul] = useState(agent.soul ?? ""); - const [editPublished, setEditPublished] = useState(agent.published); - const [selectedSkills, setSelectedSkills] = useState( - agent.skills ?? [], - ); - - const currentUserId = useMemo(() => getStoredAuth()?.user_id ?? null, []); - const isBuiltin = agent.builtin; - const isOwned = - !isBuiltin && agent.user_id !== null && agent.user_id === currentUserId; - const isFromOthers = !isBuiltin && !isOwned; - - useEffect(() => { - if (!editOpen) { - return; - } - setEditName(agent.name); - setEditDescription(agent.description ?? ""); - setEditSoul(agent.soul ?? ""); - setEditPublished(agent.published); - setSelectedSkills(agent.skills ?? []); - }, [ - agent.description, - agent.name, - agent.published, - agent.skills, - agent.soul, - editOpen, - ]); - - function handleChat() { - router.push(`/page/workspace/agents/${agent.id}/chats/new`); - } - - async function handleDelete() { - try { - await deleteAgent.mutateAsync(agent.id); - toast.success(t.agents.deleteSuccess); - setDeleteOpen(false); - } catch (err) { - toast.error(err instanceof Error ? err.message : String(err)); - } - } - - async function handleSaveEdit() { - const trimmedName = editName.trim(); - if (!trimmedName) { - toast.error(t.agents.nameStepInvalidError ?? "名称不能为空"); - return; - } - try { - await updateAgent.mutateAsync({ - id: agent.id, - request: { - name: trimmedName, - description: editDescription, - soul: editSoul, - published: editPublished, - skills: selectedSkills, - }, - }); - toast.success("智能体已更新"); - setEditOpen(false); - } catch (err) { - toast.error(err instanceof Error ? err.message : String(err)); - } - } - - async function handleTogglePublished() { - try { - await updateAgent.mutateAsync({ - id: agent.id, - request: { published: !agent.published }, - }); - toast.success(agent.published ? "已取消发布" : "已发布"); - } catch (err) { - toast.error(err instanceof Error ? err.message : String(err)); - } - } - - function toggleSkill(skillName: string) { - setSelectedSkills((prev) => { - if (prev.includes(skillName)) { - return prev.filter((name) => name !== skillName); - } - return [...prev, skillName]; - }); - } - - const enabledSkills = skills.filter((skill) => skill.enabled); - - return ( - <> - - -
-
-
- -
-
- - {agent.name} - - {agent.model && ( - - {agent.model} - - )} -
-
-
- {isBuiltin && ( - - 内置 - - )} - {isOwned && ( - - 我的 - - )} - {isFromOthers && ( - - 来自他人 - - )} - {isOwned && agent.published && ( - - 已发布 - - )} -
-
- {agent.description && ( - - {agent.description} - - )} -
- - {(agent.tool_groups?.length ?? agent.skills?.length ?? 0) > 0 && ( - -
- {agent.tool_groups?.map((group) => ( - - {group} - - ))} - {agent.skills?.map((skill) => ( - - {skill} - - ))} -
-
- )} - - - - {isOwned && ( -
- - - -
- )} -
-
- - - - - 编辑智能体:{agent.name} - - 可以修改名称、描述、技能白名单、SOUL 内容与发布状态。 - - -
-
- - setEditName(e.target.value)} - placeholder="输入智能体名称(允许中文)" - /> -
-
- -