"use client"; import { useState, useMemo, useCallback, useEffect } from "react"; import { useAppStore, AIProfile, AgentModel, ThinkingLevel, ModelProvider, } from "@/store/app-store"; import { Button } from "@/components/ui/button"; import { HotkeyButton } from "@/components/ui/hotkey-button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { cn, modelSupportsThinking } from "@/lib/utils"; import { useKeyboardShortcuts, useKeyboardShortcutsConfig, KeyboardShortcut, } from "@/hooks/use-keyboard-shortcuts"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { UserCircle, Plus, Pencil, Trash2, Brain, Zap, Scale, Cpu, Rocket, Sparkles, GripVertical, Lock, Check, RefreshCw, } from "lucide-react"; import { toast } from "sonner"; import { DndContext, DragEndEvent, PointerSensor, useSensor, useSensors, closestCenter, } from "@dnd-kit/core"; import { SortableContext, useSortable, verticalListSortingStrategy, } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; // Icon mapping for profiles const PROFILE_ICONS: Record< string, React.ComponentType<{ className?: string }> > = { Brain, Zap, Scale, Cpu, Rocket, Sparkles, }; // Available icons for selection const ICON_OPTIONS = [ { name: "Brain", icon: Brain }, { name: "Zap", icon: Zap }, { name: "Scale", icon: Scale }, { name: "Cpu", icon: Cpu }, { name: "Rocket", icon: Rocket }, { name: "Sparkles", icon: Sparkles }, ]; // Model options for the form const CLAUDE_MODELS: { id: AgentModel; label: string }[] = [ { id: "haiku", label: "Claude Haiku" }, { id: "sonnet", label: "Claude Sonnet" }, { id: "opus", label: "Claude Opus" }, ]; const THINKING_LEVELS: { id: ThinkingLevel; label: string }[] = [ { id: "none", label: "None" }, { id: "low", label: "Low" }, { id: "medium", label: "Medium" }, { id: "high", label: "High" }, { id: "ultrathink", label: "Ultrathink" }, ]; // Helper to determine provider from model function getProviderFromModel(model: AgentModel): ModelProvider { return "claude"; } // Sortable Profile Card Component function SortableProfileCard({ profile, onEdit, onDelete, }: { profile: AIProfile; onEdit: () => void; onDelete: () => void; }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id: profile.id }); const style = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.5 : 1, }; const IconComponent = profile.icon ? PROFILE_ICONS[profile.icon] : Brain; return (
{/* Drag Handle */} {/* Icon */}
{IconComponent && ( )}
{/* Content */}

{profile.name}

{profile.isBuiltIn && ( Built-in )}

{profile.description}

{profile.model} {profile.thinkingLevel !== "none" && ( {profile.thinkingLevel} )}
{/* Actions */} {!profile.isBuiltIn && (
)}
); } // Profile Form Component function ProfileForm({ profile, onSave, onCancel, isEditing, hotkeyActive, }: { profile: Partial; onSave: (profile: Omit) => void; onCancel: () => void; isEditing: boolean; hotkeyActive: boolean; }) { const [formData, setFormData] = useState({ name: profile.name || "", description: profile.description || "", model: profile.model || ("opus" as AgentModel), thinkingLevel: profile.thinkingLevel || ("none" as ThinkingLevel), icon: profile.icon || "Brain", }); const provider = getProviderFromModel(formData.model); const supportsThinking = modelSupportsThinking(formData.model); const handleModelChange = (model: AgentModel) => { setFormData({ ...formData, model, }); }; const handleSubmit = () => { if (!formData.name.trim()) { toast.error("Please enter a profile name"); return; } onSave({ name: formData.name.trim(), description: formData.description.trim(), model: formData.model, thinkingLevel: supportsThinking ? formData.thinkingLevel : "none", provider, isBuiltIn: false, icon: formData.icon, }); }; return (
{/* Name */}
setFormData({ ...formData, name: e.target.value })} placeholder="e.g., Heavy Task, Quick Fix" data-testid="profile-name-input" />
{/* Description */}