import React, { useState, useEffect, useCallback, useRef } from "react" import { VSCodeCheckbox, VSCodeRadioGroup, VSCodeRadio, VSCodeTextArea, VSCodeLink, VSCodeTextField, } from "@vscode/webview-ui-toolkit/react" import { Trans } from "react-i18next" import { ChevronDown, X, Upload, Download } from "lucide-react" import { ModeConfig, GroupEntry, PromptComponent, ToolGroup, modeConfigSchema } from "@roo-code/types" import { Mode, getRoleDefinition, getWhenToUse, getDescription, getCustomInstructions, getAllModes, findModeBySlug as findCustomModeBySlug, defaultModeSlug, } from "@roo/modes" import { TOOL_GROUPS } from "@roo/tools" import { vscode } from "@src/utils/vscode" import { buildDocLink } from "@src/utils/docLinks" import { useAppTranslation } from "@src/i18n/TranslationContext" import { useExtensionState } from "@src/context/ExtensionStateContext" import { Section } from "@src/components/settings/Section" import { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Popover, PopoverContent, PopoverTrigger, Command, CommandInput, CommandList, CommandEmpty, CommandItem, CommandGroup, Input, StandardTooltip, } from "@src/components/ui" import { DeleteModeDialog } from "@src/components/modes/DeleteModeDialog" import { useEscapeKey } from "@src/hooks/useEscapeKey" // Get all available groups that should show in prompts view const availableGroups = (Object.keys(TOOL_GROUPS) as ToolGroup[]).filter((group) => !TOOL_GROUPS[group].alwaysAvailable) type ModeSource = "global" | "project" type ImportModeResult = { type: "importModeResult"; success: boolean; slug?: string; error?: string } // Helper to get group name regardless of format function getGroupName(group: GroupEntry): ToolGroup { return Array.isArray(group) ? group[0] : group } const ModesView = () => { const { t } = useAppTranslation() const { customModePrompts, listApiConfigMeta, currentApiConfigName, mode, customInstructions, setCustomInstructions, customModes, } = useExtensionState() // Use a local state to track the visually active mode // This prevents flickering when switching modes rapidly by: // 1. Updating the UI immediately when a mode is clicked // 2. Not syncing with the backend mode state (which would cause flickering) // 3. Still sending the mode change to the backend for persistence const [visualMode, setVisualMode] = useState(mode) // Build modes fresh each render so search reflects inline rename updates immediately const modes = getAllModes(customModes) const [isDialogOpen, setIsDialogOpen] = useState(false) const [selectedPromptContent, setSelectedPromptContent] = useState("") const [selectedPromptTitle, setSelectedPromptTitle] = useState("") const [isToolsEditMode, setIsToolsEditMode] = useState(false) const [showConfigMenu, setShowConfigMenu] = useState(false) const [isCreateModeDialogOpen, setIsCreateModeDialogOpen] = useState(false) const [isExporting, setIsExporting] = useState(false) const [isImporting, setIsImporting] = useState(false) const [showImportDialog, setShowImportDialog] = useState(false) const [importLevel, setImportLevel] = useState<"global" | "project">("project") const [hasRulesToExport, setHasRulesToExport] = useState>({}) const [showDeleteConfirm, setShowDeleteConfirm] = useState(false) const [modeToDelete, setModeToDelete] = useState<{ slug: string name: string source?: string rulesFolderPath?: string } | null>(null) // State for mode selection popover and search const [open, setOpen] = useState(false) const [searchValue, setSearchValue] = useState("") const searchInputRef = useRef(null) // removed unused local name state (replaced by inline rename UX) // Inline rename state for the mode dropdown row const [isRenamingMode, setIsRenamingMode] = useState(false) const [renameInputValue, setRenameInputValue] = useState("") const renameInputRef = useRef(null) // Optimistic rename map so search reflects new names immediately const [localRenames, setLocalRenames] = useState>({}) // Display list that overlays optimistic names const displayModes = (modes || []).map((m) => (localRenames[m.slug] ? { ...m, name: localRenames[m.slug] } : m)) // Direct update functions const updateAgentPrompt = useCallback( (mode: Mode, promptData: PromptComponent) => { const existingPrompt = customModePrompts?.[mode] as PromptComponent const updatedPrompt = { ...existingPrompt, ...promptData } // Only include properties that differ from defaults if (updatedPrompt.roleDefinition === getRoleDefinition(mode)) { delete updatedPrompt.roleDefinition } if (updatedPrompt.description === getDescription(mode)) { delete updatedPrompt.description } if (updatedPrompt.whenToUse === getWhenToUse(mode)) { delete updatedPrompt.whenToUse } vscode.postMessage({ type: "updatePrompt", promptMode: mode, customPrompt: updatedPrompt, }) }, [customModePrompts], ) const updateCustomMode = useCallback((slug: string, modeConfig: ModeConfig) => { const source = modeConfig.source || "global" vscode.postMessage({ type: "updateCustomMode", slug, modeConfig: { ...modeConfig, source, // Ensure source is set }, }) }, []) // Helper function to find a mode by slug const findModeBySlug = useCallback( (searchSlug: string, modes: readonly ModeConfig[] | undefined): ModeConfig | undefined => { return findCustomModeBySlug(searchSlug, modes) }, [], ) const switchMode = useCallback((slug: string) => { vscode.postMessage({ type: "mode", text: slug, }) }, []) // Handle mode switching with explicit state initialization const handleModeSwitch = useCallback( (modeConfig: ModeConfig) => { if (modeConfig.slug === visualMode) return // Prevent unnecessary updates // Immediately update visual state for instant feedback setVisualMode(modeConfig.slug) // Then send the mode change message to the backend switchMode(modeConfig.slug) // Exit tools edit mode when switching modes setIsToolsEditMode(false) }, [visualMode, switchMode], ) // Refs to track latest state/functions for message handler (which has no dependencies) const handleModeSwitchRef = useRef(handleModeSwitch) const customModesRef = useRef(customModes) const switchModeRef = useRef(switchMode) // Update refs when dependencies change useEffect(() => { handleModeSwitchRef.current = handleModeSwitch }, [handleModeSwitch]) useEffect(() => { customModesRef.current = customModes }, [customModes]) useEffect(() => { switchModeRef.current = switchMode }, [switchMode]) // Sync visualMode with backend mode changes to prevent desync useEffect(() => { setVisualMode(mode) }, [mode]) // Handler for popover open state change const onOpenChange = useCallback((open: boolean) => { setOpen(open) // Reset search when closing the popover if (!open) { setTimeout(() => setSearchValue(""), 100) } }, []) // Use the shared ESC key handler hook useEscapeKey(open, () => setOpen(false)) // Handler for clearing search input const onClearSearch = useCallback(() => { setSearchValue("") searchInputRef.current?.focus() }, []) // Focus rename input when entering rename mode useEffect(() => { if (isRenamingMode) { const id = setTimeout(() => renameInputRef.current?.focus(), 0) return () => clearTimeout(id) } }, [isRenamingMode]) const handleStartRenameMode = useCallback(() => { const customMode = findModeBySlug(visualMode, customModes) if (customMode) { setIsRenamingMode(true) setRenameInputValue(customMode.name) } }, [visualMode, customModes, findModeBySlug]) const handleCancelRenameMode = useCallback(() => { setIsRenamingMode(false) setRenameInputValue("") }, []) const handleSaveRenameMode = useCallback(() => { const customMode = findModeBySlug(visualMode, customModes) const trimmed = renameInputValue.trim() if (!customMode || !trimmed) { setIsRenamingMode(false) return } // Prevent duplicate names against other modes const nameTaken = modes.some( (m) => m.name.toLowerCase() === trimmed.toLowerCase() && m.slug !== customMode.slug, ) if (nameTaken) { // simple guard: do nothing if taken return } updateCustomMode(visualMode, { ...customMode, name: trimmed, source: customMode.source || "global", }) // Optimistically reflect rename in UI/search immediately setLocalRenames((prev) => ({ ...prev, [visualMode]: trimmed })) setIsRenamingMode(false) }, [visualMode, customModes, renameInputValue, modes, updateCustomMode, findModeBySlug]) // Helper function to get current mode's config const getCurrentMode = useCallback((): ModeConfig | undefined => { const findMode = (m: ModeConfig): boolean => m.slug === visualMode return customModes?.find(findMode) || modes.find(findMode) }, [visualMode, customModes, modes]) // Check if the current mode has rules to export const checkRulesDirectory = useCallback((slug: string) => { vscode.postMessage({ type: "checkRulesDirectory", slug: slug, }) }, []) // Check rules directory when mode changes useEffect(() => { const currentMode = getCurrentMode() if (currentMode?.slug && hasRulesToExport[currentMode.slug] === undefined) { checkRulesDirectory(currentMode.slug) } }, [getCurrentMode, checkRulesDirectory, hasRulesToExport]) // State for create mode dialog const [newModeName, setNewModeName] = useState("") const [newModeSlug, setNewModeSlug] = useState("") const [newModeDescription, setNewModeDescription] = useState("") const [newModeRoleDefinition, setNewModeRoleDefinition] = useState("") const [newModeWhenToUse, setNewModeWhenToUse] = useState("") const [newModeCustomInstructions, setNewModeCustomInstructions] = useState("") const [newModeGroups, setNewModeGroups] = useState(availableGroups) const [newModeSource, setNewModeSource] = useState("global") // Field-specific error states const [nameError, setNameError] = useState("") const [slugError, setSlugError] = useState("") const [descriptionError, setDescriptionError] = useState("") const [roleDefinitionError, setRoleDefinitionError] = useState("") const [groupsError, setGroupsError] = useState("") // Helper to reset form state const resetFormState = useCallback(() => { // Reset form fields setNewModeName("") setNewModeSlug("") setNewModeDescription("") setNewModeGroups(availableGroups) setNewModeRoleDefinition("") setNewModeWhenToUse("") setNewModeCustomInstructions("") setNewModeSource("global") // Reset error states setNameError("") setSlugError("") setDescriptionError("") setRoleDefinitionError("") setGroupsError("") }, []) // Reset form fields when dialog opens useEffect(() => { if (isCreateModeDialogOpen) { resetFormState() } }, [isCreateModeDialogOpen, resetFormState]) // Ensure import dialog defaults to "project" each open useEffect(() => { if (showImportDialog) { setImportLevel("project") } }, [showImportDialog]) // Helper function to generate a unique slug from a name const generateSlug = useCallback((name: string, attempt = 0): string => { const baseSlug = name .toLowerCase() .replace(/[^a-z0-9-]+/g, "-") .replace(/^-+|-+$/g, "") return attempt === 0 ? baseSlug : `${baseSlug}-${attempt}` }, []) // Handler for name changes const handleNameChange = useCallback( (name: string) => { setNewModeName(name) setNewModeSlug(generateSlug(name)) }, [generateSlug], ) const handleCreateMode = useCallback(() => { // Clear previous errors setNameError("") setSlugError("") setDescriptionError("") setRoleDefinitionError("") setGroupsError("") const source = newModeSource const newMode: ModeConfig = { slug: newModeSlug, name: newModeName, description: newModeDescription.trim() || undefined, roleDefinition: newModeRoleDefinition.trim(), whenToUse: newModeWhenToUse.trim() || undefined, customInstructions: newModeCustomInstructions.trim() || undefined, groups: newModeGroups, source, } // Validate the mode against the schema const result = modeConfigSchema.safeParse(newMode) if (!result.success) { // Map Zod errors to specific fields result.error.errors.forEach((error) => { const field = error.path[0] as string const message = error.message switch (field) { case "name": setNameError(message) break case "slug": setSlugError(message) break case "description": setDescriptionError(message) break case "roleDefinition": setRoleDefinitionError(message) break case "groups": setGroupsError(message) break } }) return } updateCustomMode(newModeSlug, newMode) // Immediately select the newly created mode in the UI setVisualMode(newModeSlug) switchMode(newModeSlug) setIsCreateModeDialogOpen(false) resetFormState() // eslint-disable-next-line react-hooks/exhaustive-deps }, [ newModeName, newModeSlug, newModeDescription, newModeRoleDefinition, newModeWhenToUse, // Add whenToUse dependency newModeCustomInstructions, newModeGroups, newModeSource, updateCustomMode, ]) const isNameOrSlugTaken = useCallback( (name: string, slug: string) => { return modes.some((m) => m.slug === slug || m.name === name) }, [modes], ) const openCreateModeDialog = useCallback(() => { const baseNamePrefix = "New Custom Mode" // Find unique name and slug let attempt = 0 let name = baseNamePrefix let slug = generateSlug(name) while (isNameOrSlugTaken(name, slug)) { attempt++ name = `${baseNamePrefix} ${attempt + 1}` slug = generateSlug(name) } setNewModeName(name) setNewModeSlug(slug) setIsCreateModeDialogOpen(true) }, [generateSlug, isNameOrSlugTaken]) // Handler for group checkbox changes const handleGroupChange = useCallback( (group: ToolGroup, isCustomMode: boolean, customMode: ModeConfig | undefined) => (e: Event | React.FormEvent) => { if (!isCustomMode) return // Prevent changes to built-in modes const target = (e as CustomEvent)?.detail?.target || (e.target as HTMLInputElement) const checked = target.checked const oldGroups = customMode?.groups || [] let newGroups: GroupEntry[] if (checked) { newGroups = [...oldGroups, group] } else { newGroups = oldGroups.filter((g) => getGroupName(g) !== group) } if (customMode) { const source = customMode.source || "global" updateCustomMode(customMode.slug, { ...customMode, groups: newGroups, source, }) } }, [updateCustomMode], ) // Handle clicks outside the config menu useEffect(() => { const handleClickOutside = () => { if (showConfigMenu) { setShowConfigMenu(false) } } document.addEventListener("click", handleClickOutside) return () => document.removeEventListener("click", handleClickOutside) }, [showConfigMenu]) // Use a ref to store the current modeToDelete value const modeToDeleteRef = useRef(modeToDelete) // Update the ref whenever modeToDelete changes useEffect(() => { modeToDeleteRef.current = modeToDelete }, [modeToDelete]) useEffect(() => { const handler = (event: MessageEvent) => { const message = event.data if (message.type === "systemPrompt") { if (message.text) { setSelectedPromptContent(message.text) setSelectedPromptTitle(`System Prompt (${message.mode} mode)`) setIsDialogOpen(true) } } else if (message.type === "exportModeResult") { setIsExporting(false) if (!message.success) { // Show error message console.error("Failed to export mode:", message.error) } } else if (message.type === "importModeResult") { setIsImporting(false) setShowImportDialog(false) if (message.success) { const { slug } = message as ImportModeResult if (slug) { // Try switching using the freshest mode list available const all = getAllModes(customModesRef.current) const importedMode = all.find((m) => m.slug === slug) if (importedMode) { handleModeSwitchRef.current(importedMode) } else { // Fallback: slug not yet in state (race condition) - select default mode setVisualMode(defaultModeSlug) switchModeRef.current?.(defaultModeSlug) } } } else { // Only log error if it's not a cancellation if (message.error !== "cancelled") { console.error("Failed to import mode:", message.error) } } // Note: Auto-select after import will be handled by PR #9003 } else if (message.type === "checkRulesDirectoryResult") { setHasRulesToExport((prev) => ({ ...prev, [message.slug]: message.hasContent, })) } else if (message.type === "deleteCustomModeCheck") { // Handle the check response // Use the ref to get the current modeToDelete value const currentModeToDelete = modeToDeleteRef.current if (message.slug && currentModeToDelete && currentModeToDelete.slug === message.slug) { setModeToDelete({ ...currentModeToDelete, rulesFolderPath: message.rulesFolderPath, }) setShowDeleteConfirm(true) } } } window.addEventListener("message", handler) return () => window.removeEventListener("message", handler) }, [checkRulesDirectory, switchMode]) const handleAgentReset = ( modeSlug: string, type: "roleDefinition" | "description" | "whenToUse" | "customInstructions", ) => { // Only reset for built-in modes const existingPrompt = customModePrompts?.[modeSlug] as PromptComponent const updatedPrompt = { ...existingPrompt } delete updatedPrompt[type] // Remove the field entirely to ensure it reloads from defaults vscode.postMessage({ type: "updatePrompt", promptMode: modeSlug, customPrompt: updatedPrompt, }) } return (
e.stopPropagation()} className="flex justify-between items-center mb-3">

{t("prompts:modes.title")}

{showConfigMenu && (
e.stopPropagation()} onMouseDown={(e) => e.stopPropagation()} className="absolute top-full right-0 w-[200px] mt-1 bg-vscode-editor-background border border-vscode-input-border rounded shadow-md z-[1000]">
{ e.preventDefault() // Prevent blur vscode.postMessage({ type: "openCustomModesSettings", }) setShowConfigMenu(false) }} onClick={(e) => e.preventDefault()}> {t("prompts:modes.editGlobalModes")}
{ e.preventDefault() // Prevent blur vscode.postMessage({ type: "openFile", text: "./.roomodes", values: { create: true, content: JSON.stringify({ customModes: [] }, null, 2), }, }) setShowConfigMenu(false) }} onClick={(e) => e.preventDefault()}> {t("prompts:modes.editProjectModes")}
)}
{isRenamingMode ? ( <> { const target = e as { target: { value: string } } setRenameInputValue(target.target.value) }} className="grow" placeholder={t("prompts:createModeDialog.name.placeholder")} /> ) : ( <>
{searchValue.length > 0 && (
)}
{searchValue && (
{t("prompts:modes.noMatchFound")}
)}
{displayModes .filter((modeConfig) => searchValue ? modeConfig.name .toLowerCase() .includes(searchValue.toLowerCase()) : true, ) .map((modeConfig) => ( { handleModeSwitch(modeConfig) setOpen(false) }} data-testid={`mode-option-${modeConfig.slug}`}>
{modeConfig.name} {modeConfig.slug}
))}
{/* New mode (+) moved here from the top bar */} {/* Edit (rename) mode - only enabled for custom modes */} {/* Delete mode - disabled for built-in modes */} {/* Export mode (kept here to the right of the dropdown) */} )}
{/* API Configuration - Moved Here */}
{t("prompts:apiConfiguration.title")}
{t("prompts:apiConfiguration.select")}
{/* Role Definition section */}
{t("prompts:roleDefinition.title")}
{!findModeBySlug(visualMode, customModes) && ( )}
{t("prompts:roleDefinition.description")}
{ const customMode = findModeBySlug(visualMode, customModes) const prompt = customModePrompts?.[visualMode] as PromptComponent return customMode?.roleDefinition ?? prompt?.roleDefinition ?? getRoleDefinition(visualMode) })()} onChange={(e) => { const value = (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value const customMode = findModeBySlug(visualMode, customModes) if (customMode) { // For custom modes, update the JSON file updateCustomMode(visualMode, { ...customMode, roleDefinition: value.trim() || "", source: customMode.source || "global", }) } else { // For built-in modes, update the prompts updateAgentPrompt(visualMode, { roleDefinition: value.trim() || undefined, }) } }} className="w-full" rows={5} data-testid={`${getCurrentMode()?.slug || "code"}-prompt-textarea`} />
{/* Description section */}
{t("prompts:description.title")}
{!findModeBySlug(visualMode, customModes) && ( )}
{t("prompts:description.description")}
{ const customMode = findModeBySlug(visualMode, customModes) const prompt = customModePrompts?.[visualMode] as PromptComponent return customMode?.description ?? prompt?.description ?? getDescription(visualMode) })()} onChange={(e) => { const value = (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value const customMode = findModeBySlug(visualMode, customModes) if (customMode) { // For custom modes, update the JSON file updateCustomMode(visualMode, { ...customMode, description: value.trim() || undefined, source: customMode.source || "global", }) } else { // For built-in modes, update the prompts updateAgentPrompt(visualMode, { description: value.trim() || undefined, }) } }} className="w-full" data-testid={`${getCurrentMode()?.slug || "code"}-description-textfield`} />
{/* When to Use section */}
{t("prompts:whenToUse.title")}
{!findModeBySlug(visualMode, customModes) && ( )}
{t("prompts:whenToUse.description")}
{ const customMode = findModeBySlug(visualMode, customModes) const prompt = customModePrompts?.[visualMode] as PromptComponent return customMode?.whenToUse ?? prompt?.whenToUse ?? getWhenToUse(visualMode) })()} onChange={(e) => { const value = (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value const customMode = findModeBySlug(visualMode, customModes) if (customMode) { // For custom modes, update the JSON file updateCustomMode(visualMode, { ...customMode, whenToUse: value.trim() || undefined, source: customMode.source || "global", }) } else { // For built-in modes, update the prompts updateAgentPrompt(visualMode, { whenToUse: value.trim() || undefined, }) } }} className="w-full" rows={4} data-testid={`${getCurrentMode()?.slug || "code"}-when-to-use-textarea`} />
{/* Mode settings */} <> {/* Show tools for all modes */}
{t("prompts:tools.title")}
{findModeBySlug(visualMode, customModes) && ( )}
{!findModeBySlug(visualMode, customModes) && (
{t("prompts:tools.builtInModesText")}
)} {isToolsEditMode && findModeBySlug(visualMode, customModes) ? (
{availableGroups.map((group) => { const currentMode = getCurrentMode() const isCustomMode = findModeBySlug(visualMode, customModes) const customMode = isCustomMode const isGroupEnabled = isCustomMode ? customMode?.groups?.some((g) => getGroupName(g) === group) : currentMode?.groups?.some((g) => getGroupName(g) === group) return ( {t(`prompts:tools.toolNames.${group}`)} {group === "edit" && (
{t("prompts:tools.allowedFiles")}{" "} {(() => { const currentMode = getCurrentMode() const editGroup = currentMode?.groups?.find( (g) => Array.isArray(g) && g[0] === "edit" && g[1]?.fileRegex, ) if (!Array.isArray(editGroup)) return t("prompts:allFiles") return editGroup[1].description || `/${editGroup[1].fileRegex}/` })()}
)}
) })}
) : (
{(() => { const currentMode = getCurrentMode() const enabledGroups = currentMode?.groups || [] // If there are no enabled groups, display translated "None" if (enabledGroups.length === 0) { return t("prompts:tools.noTools") } return enabledGroups .map((group) => { const groupName = getGroupName(group) const displayName = t(`prompts:tools.toolNames.${groupName}`) if (Array.isArray(group) && group[1]?.fileRegex) { const description = group[1].description || `/${group[1].fileRegex}/` return `${displayName} (${description})` } return displayName }) .join(", ") })()}
)}
{/* Role definition for both built-in and custom modes */}
{t("prompts:customInstructions.title")}
{!findModeBySlug(visualMode, customModes) && ( )}
{t("prompts:customInstructions.description", { modeName: getCurrentMode()?.name || "Code", })}
{ const customMode = findModeBySlug(visualMode, customModes) const prompt = customModePrompts?.[visualMode] as PromptComponent return ( customMode?.customInstructions ?? prompt?.customInstructions ?? getCustomInstructions(visualMode, customModes) ) })()} onChange={(e) => { const value = (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value const customMode = findModeBySlug(visualMode, customModes) if (customMode) { // For custom modes, update the JSON file updateCustomMode(visualMode, { ...customMode, // Preserve empty string; only treat null/undefined as unset customInstructions: value ?? undefined, source: customMode.source || "global", }) } else { // For built-in modes, update the prompts const existingPrompt = customModePrompts?.[visualMode] as PromptComponent updateAgentPrompt(visualMode, { ...existingPrompt, customInstructions: value.trim() || undefined, }) } }} rows={10} className="w-full" data-testid={`${getCurrentMode()?.slug || "code"}-custom-instructions-textarea`} />
{ const currentMode = getCurrentMode() if (!currentMode) return // Open or create an empty file vscode.postMessage({ type: "openFile", text: `./.roo/rules-${currentMode.slug}/rules.md`, values: { create: true, content: "", }, }) }} /> ), "0": ( ), }} />

{t("prompts:globalCustomInstructions.title")}

{ const value = (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value setCustomInstructions(value ?? undefined) vscode.postMessage({ type: "customInstructions", text: value ?? undefined, }) }} rows={4} className="w-full" data-testid="global-custom-instructions-textarea" />
vscode.postMessage({ type: "openFile", text: "./.roo/rules/rules.md", values: { create: true, content: "", }, }) } /> ), "0": ( ), }} />
{isCreateModeDialogOpen && (

{t("prompts:createModeDialog.title")}

{t("prompts:createModeDialog.name.label")}
{ handleNameChange(e.target.value) }} className="w-full" /> {nameError && (
{nameError}
)}
{t("prompts:createModeDialog.slug.label")}
{ setNewModeSlug(e.target.value) }} className="w-full" />
{t("prompts:createModeDialog.slug.description")}
{slugError && (
{slugError}
)}
{t("prompts:createModeDialog.saveLocation.label")}
{t("prompts:createModeDialog.saveLocation.description")}
) => { const target = ((e as CustomEvent)?.detail?.target || (e.target as HTMLInputElement)) as HTMLInputElement setNewModeSource(target.value as ModeSource) }}> {t("prompts:createModeDialog.saveLocation.global.label")}
{t("prompts:createModeDialog.saveLocation.global.description")}
{t("prompts:createModeDialog.saveLocation.project.label")}
{t("prompts:createModeDialog.saveLocation.project.description")}
{t("prompts:createModeDialog.roleDefinition.label")}
{t("prompts:createModeDialog.roleDefinition.description")}
{ setNewModeRoleDefinition((e.target as HTMLTextAreaElement).value) }} rows={4} className="w-full" /> {roleDefinitionError && (
{roleDefinitionError}
)}
{t("prompts:createModeDialog.description.label")}
{t("prompts:createModeDialog.description.description")}
{ setNewModeDescription((e.target as HTMLInputElement).value) }} className="w-full" /> {descriptionError && (
{descriptionError}
)}
{t("prompts:createModeDialog.whenToUse.label")}
{t("prompts:createModeDialog.whenToUse.description")}
{ setNewModeWhenToUse((e.target as HTMLTextAreaElement).value) }} rows={3} className="w-full" />
{t("prompts:createModeDialog.tools.label")}
{t("prompts:createModeDialog.tools.description")}
{availableGroups.map((group) => ( getGroupName(g) === group)} onChange={(e: Event | React.FormEvent) => { const target = (e as CustomEvent)?.detail?.target || (e.target as HTMLInputElement) const checked = target.checked if (checked) { setNewModeGroups([...newModeGroups, group]) } else { setNewModeGroups( newModeGroups.filter((g) => getGroupName(g) !== group), ) } }}> {t(`prompts:tools.toolNames.${group}`)} ))}
{groupsError && (
{groupsError}
)}
{t("prompts:createModeDialog.customInstructions.label")}
{t("prompts:createModeDialog.customInstructions.description")}
{ setNewModeCustomInstructions((e.target as HTMLTextAreaElement).value) }} rows={4} className="w-full" />
)} {isDialogOpen && (

{selectedPromptTitle || t("prompts:systemPrompt.title", { modeName: getCurrentMode()?.name || "Code", })}

								{selectedPromptContent}
							
)} {/* Import Mode Dialog */} {showImportDialog && (

{t("prompts:modes.importMode")}

{t("prompts:importMode.selectLevel")}

)} {/* Delete Mode Confirmation Dialog */} { if (modeToDelete) { vscode.postMessage({ type: "deleteCustomMode", slug: modeToDelete.slug, }) setShowDeleteConfirm(false) setModeToDelete(null) } }} />
) } export default ModesView