/* Custom mode creator page — users define their own modes */ import { useState, useEffect } from "react"; import { useNavigate } from "react-router"; import { MODES, type ModeDef } from "#/types/mode"; const STORAGE_KEY = "wren-custom-modes"; interface CustomMode { id: string; label: string; shortLabel: string; description: string; icon: string; systemPrompt: string; suggestOn: string[]; color?: string; } function loadCustomModes(): CustomMode[] { try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]"); } catch { return []; } } function saveCustomModes(modes: CustomMode[]) { localStorage.setItem(STORAGE_KEY, JSON.stringify(modes)); } const ICON_OPTIONS = [ { value: "wrench", label: "Wrench", svg: "M14.7 6.3a1 1 0 000 1.4l1.6 1.6a1 1 0 001.4 0l3.77-3.77a6 6 0 01-7.94 7.94l-6.91 6.91a2.12 2.12 0 01-3-3l6.91-6.91a6 6 0 017.94-7.94l-3.76 3.76z", }, { value: "zap", label: "Zap", svg: "M13 2L3 14h9l-1 8 10-12h-9l1-8z" }, { value: "search", label: "Search", svg: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z", }, { value: "star", label: "Star", svg: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z", }, { value: "shield", label: "Shield", svg: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z", }, { value: "hash", label: "Hash", svg: "M4 9h16M4 15h16M10 3L8 21M16 3l-2 18" }, { value: "layers", label: "Layers", svg: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5", }, { value: "terminal", label: "Terminal", svg: "M4 17l6-6-6-6M12 19h8" }, ]; export default function ModesPage() { const navigate = useNavigate(); const [customModes, setCustomModes] = useState([]); const [showForm, setShowForm] = useState(false); const [editingId, setEditingId] = useState(null); /* Form state */ const [formLabel, setFormLabel] = useState(""); const [formShortLabel, setFormShortLabel] = useState(""); const [formDescription, setFormDescription] = useState(""); const [formIcon, setFormIcon] = useState("wrench"); const [formSystemPrompt, setFormSystemPrompt] = useState(""); const [formSuggestOn, setFormSuggestOn] = useState(""); const [formColor, setFormColor] = useState("#E86C4A"); const [formError, setFormError] = useState(null); useEffect(() => { setCustomModes(loadCustomModes()); }, []); function resetForm() { setFormLabel(""); setFormShortLabel(""); setFormDescription(""); setFormIcon("wrench"); setFormSystemPrompt(""); setFormSuggestOn(""); setFormColor("#E86C4A"); setFormError(null); setEditingId(null); } function handleEdit(mode: CustomMode) { setFormLabel(mode.label); setFormShortLabel(mode.shortLabel); setFormDescription(mode.description); setFormIcon(mode.icon); setFormSystemPrompt(mode.systemPrompt); setFormSuggestOn(mode.suggestOn.join(", ")); setFormColor(mode.color || "#E86C4A"); setEditingId(mode.id); setShowForm(true); } function handleSave() { if (!formLabel.trim()) { setFormError("Label is required"); return; } if (!formShortLabel.trim()) { setFormShortLabel(formLabel.trim()); } const id = editingId || `custom-${Date.now()}`; const mode: CustomMode = { id, label: formLabel.trim(), shortLabel: formShortLabel.trim() || formLabel.trim(), description: formDescription.trim(), icon: formIcon, systemPrompt: formSystemPrompt.trim(), suggestOn: formSuggestOn .split(",") .map((s) => s.trim()) .filter(Boolean), color: formColor, }; const existing = loadCustomModes(); if (editingId) { const idx = existing.findIndex((m) => m.id === editingId); if (idx >= 0) existing[idx] = mode; else existing.push(mode); } else { existing.push(mode); } saveCustomModes(existing); setCustomModes(existing); setShowForm(false); resetForm(); } function handleDelete(id: string) { const filtered = customModes.filter((m) => m.id !== id); saveCustomModes(filtered); setCustomModes(filtered); } function handleDuplicate(mode: CustomMode) { const newMode = { ...mode, id: `custom-${Date.now()}`, label: `${mode.label} (Copy)`, }; const existing = loadCustomModes(); existing.push(newMode); saveCustomModes(existing); setCustomModes(existing); } return (
{/* Header */}

Modes

Create and manage custom agent modes for different workflows

{/* Built-in modes */}

Built-in Modes

{MODES.filter((m) => m.enabledByDefault).map((mode) => ( ))}
{/* Custom modes */}

Custom Modes {customModes.length > 0 && `(${customModes.length})`}

{customModes.length === 0 && !showForm && (

No custom modes yet. Create one to extend Wren's capabilities.

)}
{customModes.map((mode) => (
o.value === mode.icon)?.svg || ICON_OPTIONS[0].svg } />
{mode.label} custom

{mode.description}

))}
{/* Create/Edit form */} {showForm && (

{editingId ? "Edit Mode" : "Create Custom Mode"}

Define keywords, system prompt, and behavior for this mode.

{/* Label */}
setFormLabel(e.target.value)} placeholder="e.g. Security Audit" className="w-full rounded-lg px-3 py-2 text-sm outline-none transition-all" style={{ background: "var(--claude-canvas)", border: "1px solid var(--border-strong)", color: "var(--text-primary)", }} />
{/* Short label */}
setFormShortLabel(e.target.value)} placeholder="e.g. Audit" className="w-full rounded-lg px-3 py-2 text-sm outline-none transition-all" style={{ background: "var(--claude-canvas)", border: "1px solid var(--border-strong)", color: "var(--text-primary)", }} />
{/* Description */}
setFormDescription(e.target.value)} placeholder="What this mode does..." className="w-full rounded-lg px-3 py-2 text-sm outline-none transition-all" style={{ background: "var(--claude-canvas)", border: "1px solid var(--border-strong)", color: "var(--text-primary)", }} />
{/* Icon + Color row */}
{ICON_OPTIONS.map((opt) => ( ))}
setFormColor(e.target.value)} className="h-8 w-8 rounded-lg cursor-pointer border-none" style={{ background: "transparent" }} /> {formColor}
{/* Suggest-on keywords */}
setFormSuggestOn(e.target.value)} placeholder="e.g. security, audit, vuln" className="w-full rounded-lg px-3 py-2 text-sm outline-none transition-all" style={{ background: "var(--claude-canvas)", border: "1px solid var(--border-strong)", color: "var(--text-primary)", }} />
{/* System prompt */}