import React from 'react' import { Box, color, Link, Text, useTheme, Pane, Tab, Tabs, useTabHeaderFocus } from '@anthropic/ink' import { useKeybindings } from '../../keybindings/useKeybinding.js' import type { CommandResultDisplay } from '../../types/command.js' import type { SandboxDependencyCheck } from '../../utils/sandbox/sandbox-adapter.js' import { SandboxManager } from '../../utils/sandbox/sandbox-adapter.js' import { getSettings_DEPRECATED } from '../../utils/settings/settings.js' import { Select } from '../CustomSelect/select.js' import { SandboxConfigTab } from './SandboxConfigTab.js' import { SandboxDependenciesTab } from './SandboxDependenciesTab.js' import { SandboxOverridesTab } from './SandboxOverridesTab.js' type Props = { onComplete: ( result?: string, options?: { display?: CommandResultDisplay }, ) => void depCheck: SandboxDependencyCheck } type SandboxMode = 'auto-allow' | 'regular' | 'disabled' export function SandboxSettings({ onComplete, depCheck, }: Props): React.ReactNode { const [theme] = useTheme() const currentEnabled = SandboxManager.isSandboxingEnabled() const currentAutoAllow = SandboxManager.isAutoAllowBashIfSandboxedEnabled() const hasWarnings = depCheck.warnings.length > 0 const settings = getSettings_DEPRECATED() const allowAllUnixSockets = settings.sandbox?.network?.allowAllUnixSockets // Show warning if seccomp missing AND user hasn't allowed all unix sockets const showSocketWarning = hasWarnings && !allowAllUnixSockets // Determine current mode const getCurrentMode = (): SandboxMode => { if (!currentEnabled) return 'disabled' if (currentAutoAllow) return 'auto-allow' return 'regular' } const currentMode = getCurrentMode() const currentIndicator = color('success', theme)(`(current)`) const options = [ { label: currentMode === 'auto-allow' ? `Sandbox BashTool, with auto-allow ${currentIndicator}` : 'Sandbox BashTool, with auto-allow', value: 'auto-allow', }, { label: currentMode === 'regular' ? `Sandbox BashTool, with regular permissions ${currentIndicator}` : 'Sandbox BashTool, with regular permissions', value: 'regular', }, { label: currentMode === 'disabled' ? `No Sandbox ${currentIndicator}` : 'No Sandbox', value: 'disabled', }, ] async function handleSelect(value: string) { const mode = value as SandboxMode switch (mode) { case 'auto-allow': await SandboxManager.setSandboxSettings({ enabled: true, autoAllowBashIfSandboxed: true, }) onComplete('✓ Sandbox enabled with auto-allow for bash commands') break case 'regular': await SandboxManager.setSandboxSettings({ enabled: true, autoAllowBashIfSandboxed: false, }) onComplete('✓ Sandbox enabled with regular bash permissions') break case 'disabled': await SandboxManager.setSandboxSettings({ enabled: false, autoAllowBashIfSandboxed: false, }) onComplete('○ Sandbox disabled') break } } useKeybindings( { 'confirm:no': () => onComplete(undefined, { display: 'skip' }), }, { context: 'Settings' }, ) const modeTab = ( ) const overridesTab = ( ) const configTab = ( ) const hasErrors = depCheck.errors.length > 0 // If required deps missing, only show Dependencies tab // If only optional deps missing, show all tabs const tabs = hasErrors ? [ , ] : [ modeTab, ...(hasWarnings ? [ , ] : []), overridesTab, configTab, ] return ( {tabs} ) } function SandboxModeTab({ showSocketWarning, options, onSelect, onComplete, }: { showSocketWarning: boolean options: Array<{ label: string; value: string }> onSelect: (value: string) => void onComplete: Props['onComplete'] }): React.ReactNode { const { headerFocused, focusHeader } = useTabHeaderFocus() return ( {showSocketWarning && ( Cannot block unix domain sockets (see Dependencies tab) )} Configure Mode: