import { useState } from 'react'; import { AlertTriangle, Plus, Shield, X } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { Button, Input } from '../../../../../../../shared/view/ui'; import type { CodexPermissionMode, GeminiPermissionMode } from '../../../../../types/types'; const COMMON_CLAUDE_TOOLS = [ 'Bash(git log:*)', 'Bash(git diff:*)', 'Bash(git status:*)', 'Write', 'Read', 'Edit', 'Glob', 'Grep', 'MultiEdit', 'Task', 'TodoWrite', 'TodoRead', 'WebFetch', 'WebSearch', ]; const COMMON_CURSOR_COMMANDS = [ 'Shell(ls)', 'Shell(mkdir)', 'Shell(cd)', 'Shell(cat)', 'Shell(echo)', 'Shell(git status)', 'Shell(git diff)', 'Shell(git log)', 'Shell(npm install)', 'Shell(npm run)', 'Shell(python)', 'Shell(node)', ]; const addUnique = (items: string[], value: string): string[] => { const normalizedValue = value.trim(); if (!normalizedValue || items.includes(normalizedValue)) { return items; } return [...items, normalizedValue]; }; const removeValue = (items: string[], value: string): string[] => ( items.filter((item) => item !== value) ); type ClaudePermissionsProps = { agent: 'claude'; skipPermissions: boolean; onSkipPermissionsChange: (value: boolean) => void; allowedTools: string[]; onAllowedToolsChange: (value: string[]) => void; disallowedTools: string[]; onDisallowedToolsChange: (value: string[]) => void; }; function ClaudePermissions({ skipPermissions, onSkipPermissionsChange, allowedTools, onAllowedToolsChange, disallowedTools, onDisallowedToolsChange, }: Omit) { const { t } = useTranslation('settings'); const [newAllowedTool, setNewAllowedTool] = useState(''); const [newDisallowedTool, setNewDisallowedTool] = useState(''); const handleAddAllowedTool = (tool: string) => { const updated = addUnique(allowedTools, tool); if (updated.length === allowedTools.length) { return; } onAllowedToolsChange(updated); setNewAllowedTool(''); }; const handleAddDisallowedTool = (tool: string) => { const updated = addUnique(disallowedTools, tool); if (updated.length === disallowedTools.length) { return; } onDisallowedToolsChange(updated); setNewDisallowedTool(''); }; return (

{t('permissions.title')}

{t('permissions.allowedTools.title')}

{t('permissions.allowedTools.description')}

setNewAllowedTool(event.target.value)} placeholder={t('permissions.allowedTools.placeholder')} onKeyDown={(event) => { if (event.key === 'Enter') { event.preventDefault(); handleAddAllowedTool(newAllowedTool); } }} className="h-10 flex-1" />

{t('permissions.allowedTools.quickAdd')}

{COMMON_CLAUDE_TOOLS.map((tool) => ( ))}
{allowedTools.map((tool) => (
{tool}
))} {allowedTools.length === 0 && (
{t('permissions.allowedTools.empty')}
)}

{t('permissions.blockedTools.title')}

{t('permissions.blockedTools.description')}

setNewDisallowedTool(event.target.value)} placeholder={t('permissions.blockedTools.placeholder')} onKeyDown={(event) => { if (event.key === 'Enter') { event.preventDefault(); handleAddDisallowedTool(newDisallowedTool); } }} className="h-10 flex-1" />
{disallowedTools.map((tool) => (
{tool}
))} {disallowedTools.length === 0 && (
{t('permissions.blockedTools.empty')}
)}

{t('permissions.toolExamples.title')}

  • "Bash(git log:*)" {t('permissions.toolExamples.bashGitLog')}
  • "Bash(git diff:*)" {t('permissions.toolExamples.bashGitDiff')}
  • "Write" {t('permissions.toolExamples.write')}
  • "Bash(rm:*)" {t('permissions.toolExamples.bashRm')}
); } type CursorPermissionsProps = { agent: 'cursor'; skipPermissions: boolean; onSkipPermissionsChange: (value: boolean) => void; allowedCommands: string[]; onAllowedCommandsChange: (value: string[]) => void; disallowedCommands: string[]; onDisallowedCommandsChange: (value: string[]) => void; }; function CursorPermissions({ skipPermissions, onSkipPermissionsChange, allowedCommands, onAllowedCommandsChange, disallowedCommands, onDisallowedCommandsChange, }: Omit) { const { t } = useTranslation('settings'); const [newAllowedCommand, setNewAllowedCommand] = useState(''); const [newDisallowedCommand, setNewDisallowedCommand] = useState(''); const handleAddAllowedCommand = (command: string) => { const updated = addUnique(allowedCommands, command); if (updated.length === allowedCommands.length) { return; } onAllowedCommandsChange(updated); setNewAllowedCommand(''); }; const handleAddDisallowedCommand = (command: string) => { const updated = addUnique(disallowedCommands, command); if (updated.length === disallowedCommands.length) { return; } onDisallowedCommandsChange(updated); setNewDisallowedCommand(''); }; return (

{t('permissions.title')}

{t('permissions.allowedCommands.title')}

{t('permissions.allowedCommands.description')}

setNewAllowedCommand(event.target.value)} placeholder={t('permissions.allowedCommands.placeholder')} onKeyDown={(event) => { if (event.key === 'Enter') { event.preventDefault(); handleAddAllowedCommand(newAllowedCommand); } }} className="h-10 flex-1" />

{t('permissions.allowedCommands.quickAdd')}

{COMMON_CURSOR_COMMANDS.map((command) => ( ))}
{allowedCommands.map((command) => (
{command}
))} {allowedCommands.length === 0 && (
{t('permissions.allowedCommands.empty')}
)}

{t('permissions.blockedCommands.title')}

{t('permissions.blockedCommands.description')}

setNewDisallowedCommand(event.target.value)} placeholder={t('permissions.blockedCommands.placeholder')} onKeyDown={(event) => { if (event.key === 'Enter') { event.preventDefault(); handleAddDisallowedCommand(newDisallowedCommand); } }} className="h-10 flex-1" />
{disallowedCommands.map((command) => (
{command}
))} {disallowedCommands.length === 0 && (
{t('permissions.blockedCommands.empty')}
)}

{t('permissions.shellExamples.title')}

  • "Shell(ls)" {t('permissions.shellExamples.ls')}
  • "Shell(git status)" {t('permissions.shellExamples.gitStatus')}
  • "Shell(npm install)" {t('permissions.shellExamples.npmInstall')}
  • "Shell(rm -rf)" {t('permissions.shellExamples.rmRf')}
); } type CodexPermissionsProps = { agent: 'codex'; permissionMode: CodexPermissionMode; onPermissionModeChange: (value: CodexPermissionMode) => void; }; function CodexPermissions({ permissionMode, onPermissionModeChange }: Omit) { const { t } = useTranslation('settings'); return (

{t('permissions.codex.permissionMode')}

{t('permissions.codex.description')}

onPermissionModeChange('default')} >
onPermissionModeChange('acceptEdits')} >
onPermissionModeChange('bypassPermissions')} >
{t('permissions.codex.technicalDetails')}

{t('permissions.codex.modes.default.title')}: {t('permissions.codex.technicalInfo.default')}

{t('permissions.codex.modes.acceptEdits.title')}: {t('permissions.codex.technicalInfo.acceptEdits')}

{t('permissions.codex.modes.bypassPermissions.title')}: {t('permissions.codex.technicalInfo.bypassPermissions')}

{t('permissions.codex.technicalInfo.overrideNote')}

); } type GeminiPermissionsProps = { agent: 'gemini'; permissionMode: GeminiPermissionMode; onPermissionModeChange: (value: GeminiPermissionMode) => void; }; // Gemini Permissions function GeminiPermissions({ permissionMode, onPermissionModeChange }: Omit) { const { t } = useTranslation(['settings', 'chat']); return (

{t('gemini.permissionMode')}

{t('gemini.description')}

{/* Default Mode */}
onPermissionModeChange('default')} >
{/* Auto Edit Mode */}
onPermissionModeChange('auto_edit')} >
{/* YOLO Mode */}
onPermissionModeChange('yolo')} >
); } type PermissionsContentProps = ClaudePermissionsProps | CursorPermissionsProps | CodexPermissionsProps | GeminiPermissionsProps; export default function PermissionsContent(props: PermissionsContentProps) { if (props.agent === 'claude') { return ; } if (props.agent === 'cursor') { return ; } if (props.agent === 'gemini') { return ; } return ; }