import { VSCodeButton, VSCodeCheckbox, VSCodeLink, VSCodeTextArea, VSCodeTextField } from "@vscode/webview-ui-toolkit/react" import { memo, useEffect, useState } from "react" import { useExtensionState } from "../../context/ExtensionStateContext" import { validateApiConfiguration, validateModelId } from "../../utils/validate" import { vscode } from "../../utils/vscode" import ApiOptions from "./ApiOptions" import McpEnabledToggle from "../mcp/McpEnabledToggle" import ApiConfigManager from "./ApiConfigManager" import { Mode } from "../../../../src/shared/modes" const IS_DEV = false // FIXME: use flags when packaging type SettingsViewProps = { onDone: () => void } const SettingsView = ({ onDone }: SettingsViewProps) => { const { apiConfiguration, version, customInstructions, setCustomInstructions, alwaysAllowReadOnly, setAlwaysAllowReadOnly, alwaysAllowWrite, setAlwaysAllowWrite, alwaysAllowExecute, setAlwaysAllowExecute, alwaysAllowBrowser, setAlwaysAllowBrowser, alwaysAllowMcp, setAlwaysAllowMcp, soundEnabled, setSoundEnabled, soundVolume, setSoundVolume, diffEnabled, setDiffEnabled, browserViewportSize, setBrowserViewportSize, openRouterModels, glamaModels, setAllowedCommands, allowedCommands, fuzzyMatchThreshold, setFuzzyMatchThreshold, preferredLanguage, setPreferredLanguage, writeDelayMs, setWriteDelayMs, screenshotQuality, setScreenshotQuality, terminalOutputLineLimit, setTerminalOutputLineLimit, mcpEnabled, alwaysApproveResubmit, setAlwaysApproveResubmit, requestDelaySeconds, setRequestDelaySeconds, currentApiConfigName, listApiConfigMeta, mode, setMode, experimentalDiffStrategy, setExperimentalDiffStrategy, } = useExtensionState() const [apiErrorMessage, setApiErrorMessage] = useState(undefined) const [modelIdErrorMessage, setModelIdErrorMessage] = useState(undefined) const [commandInput, setCommandInput] = useState("") const handleSubmit = () => { const apiValidationResult = validateApiConfiguration(apiConfiguration) const modelIdValidationResult = validateModelId(apiConfiguration, glamaModels, openRouterModels) setApiErrorMessage(apiValidationResult) setModelIdErrorMessage(modelIdValidationResult) if (!apiValidationResult && !modelIdValidationResult) { vscode.postMessage({ type: "apiConfiguration", apiConfiguration }) vscode.postMessage({ type: "customInstructions", text: customInstructions }) vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly }) vscode.postMessage({ type: "alwaysAllowWrite", bool: alwaysAllowWrite }) vscode.postMessage({ type: "alwaysAllowExecute", bool: alwaysAllowExecute }) vscode.postMessage({ type: "alwaysAllowBrowser", bool: alwaysAllowBrowser }) vscode.postMessage({ type: "alwaysAllowMcp", bool: alwaysAllowMcp }) vscode.postMessage({ type: "allowedCommands", commands: allowedCommands ?? [] }) vscode.postMessage({ type: "soundEnabled", bool: soundEnabled }) vscode.postMessage({ type: "soundVolume", value: soundVolume }) vscode.postMessage({ type: "diffEnabled", bool: diffEnabled }) vscode.postMessage({ type: "browserViewportSize", text: browserViewportSize }) vscode.postMessage({ type: "fuzzyMatchThreshold", value: fuzzyMatchThreshold ?? 1.0 }) vscode.postMessage({ type: "preferredLanguage", text: preferredLanguage }) vscode.postMessage({ type: "writeDelayMs", value: writeDelayMs }) vscode.postMessage({ type: "screenshotQuality", value: screenshotQuality ?? 75 }) vscode.postMessage({ type: "terminalOutputLineLimit", value: terminalOutputLineLimit ?? 500 }) vscode.postMessage({ type: "mcpEnabled", bool: mcpEnabled }) vscode.postMessage({ type: "alwaysApproveResubmit", bool: alwaysApproveResubmit }) vscode.postMessage({ type: "requestDelaySeconds", value: requestDelaySeconds }) vscode.postMessage({ type: "currentApiConfigName", text: currentApiConfigName }) vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration }) vscode.postMessage({ type: "mode", text: mode }) vscode.postMessage({ type: "experimentalDiffStrategy", bool: experimentalDiffStrategy }) onDone() } } useEffect(() => { setApiErrorMessage(undefined) setModelIdErrorMessage(undefined) }, [apiConfiguration]) // Initial validation on mount useEffect(() => { const apiValidationResult = validateApiConfiguration(apiConfiguration) const modelIdValidationResult = validateModelId(apiConfiguration, glamaModels, openRouterModels) setApiErrorMessage(apiValidationResult) setModelIdErrorMessage(modelIdValidationResult) }, [apiConfiguration, glamaModels, openRouterModels]) const handleResetState = () => { vscode.postMessage({ type: "resetState" }) } const handleAddCommand = () => { const currentCommands = allowedCommands ?? [] if (commandInput && !currentCommands.includes(commandInput)) { const newCommands = [...currentCommands, commandInput] setAllowedCommands(newCommands) setCommandInput("") vscode.postMessage({ type: "allowedCommands", commands: newCommands }) } } return (

Settings

Done

Provider Settings

{ vscode.postMessage({ type: "loadApiConfiguration", text: configName }) }} onDeleteConfig={(configName: string) => { vscode.postMessage({ type: "deleteApiConfiguration", text: configName }) }} onRenameConfig={(oldName: string, newName: string) => { vscode.postMessage({ type: "renameApiConfiguration", values: { oldName, newName }, apiConfiguration }) }} onUpsertConfig={(configName: string) => { vscode.postMessage({ type: "upsertApiConfiguration", text: configName, apiConfiguration }) }} />

Agent Settings

Select the mode that best fits your needs. Code mode focuses on implementation details, Architect mode on high-level design, and Ask mode on asking questions about the codebase.

Select the language that Cline should use for communication.

Custom Instructions setCustomInstructions(e.target?.value ?? "")} />

These instructions are added to the end of the system prompt sent with every request. Custom instructions set in .clinerules in the working directory are also included. For mode-specific instructions, use the Prompts tab in the top menu.

Terminal output limit setTerminalOutputLineLimit(parseInt(e.target.value))} style={{ flexGrow: 1, accentColor: 'var(--vscode-button-background)', height: '2px' }} /> {terminalOutputLineLimit ?? 500}

Maximum number of lines to include in terminal output when executing commands. When exceeded lines will be removed from the middle, saving tokens.

{ setDiffEnabled(e.target.checked) if (!e.target.checked) { // Reset experimental strategy when diffs are disabled setExperimentalDiffStrategy(false) } }}> Enable editing through diffs

When enabled, Cline will be able to edit files more quickly and will automatically reject truncated full-file writes. Works best with the latest Claude 3.5 Sonnet model.

{diffEnabled && (
⚠️ setExperimentalDiffStrategy(e.target.checked)}> Use experimental unified diff strategy

Enable the experimental unified diff strategy. This strategy might reduce the number of retries caused by model errors but may cause unexpected behavior or incorrect edits. Only enable if you understand the risks and are willing to carefully review all changes.

Match precision { setFuzzyMatchThreshold(parseFloat(e.target.value)); }} style={{ flexGrow: 1, accentColor: 'var(--vscode-button-background)', height: '2px' }} /> {Math.round((fuzzyMatchThreshold || 1) * 100)}%

This slider controls how precisely code sections must match when applying diffs. Lower values allow more flexible matching but increase the risk of incorrect replacements. Use values below 100% with extreme caution.

)}
setAlwaysAllowReadOnly(e.target.checked)}> Always approve read-only operations

When enabled, Cline will automatically view directory contents and read files without requiring you to click the Approve button.

⚠️ High-Risk Auto-Approve Settings

The following settings allow Cline to automatically perform potentially dangerous operations without requiring approval. Enable these settings only if you fully trust the AI and understand the associated security risks.

setAlwaysAllowWrite(e.target.checked)}> Always approve write operations

Automatically create and edit files without requiring approval

{alwaysAllowWrite && (
setWriteDelayMs(parseInt(e.target.value))} style={{ flex: 1, accentColor: 'var(--vscode-button-background)', height: '2px' }} /> {writeDelayMs}ms

Delay after writes to allow diagnostics to detect potential problems

)}
setAlwaysAllowBrowser(e.target.checked)}> Always approve browser actions

Automatically perform browser actions without requiring approval
Note: Only applies when the model supports computer use

setAlwaysApproveResubmit(e.target.checked)}> Always retry failed API requests

Automatically retry failed API requests when server returns an error response

{alwaysApproveResubmit && (
setRequestDelaySeconds(parseInt(e.target.value))} style={{ flex: 1, accentColor: 'var(--vscode-button-background)', height: '2px' }} /> {requestDelaySeconds}s

Delay before retrying the request

)}
setAlwaysAllowMcp(e.target.checked)}> Always approve MCP tools

Enable auto-approval of individual MCP tools in the MCP Servers view (requires both this setting and the tool's individual "Always allow" checkbox)

setAlwaysAllowExecute(e.target.checked)}> Always approve allowed execute operations

Automatically execute allowed terminal commands without requiring approval

{alwaysAllowExecute && (
Allowed Auto-Execute Commands

Command prefixes that can be auto-executed when "Always approve execute operations" is enabled.

setCommandInput(e.target.value)} onKeyDown={(e: any) => { if (e.key === 'Enter') { e.preventDefault() handleAddCommand() } }} placeholder="Enter command prefix (e.g., 'git ')" style={{ flexGrow: 1 }} /> Add
{(allowedCommands ?? []).map((cmd, index) => (
{cmd} { const newCommands = (allowedCommands ?? []).filter((_, i) => i !== index) setAllowedCommands(newCommands) vscode.postMessage({ type: "allowedCommands", commands: newCommands }) }} >
))}
)}

Browser Settings

Select the viewport size for browser interactions. This affects how websites are displayed and interacted with.

Screenshot quality setScreenshotQuality(parseInt(e.target.value))} style={{ flexGrow: 1, accentColor: 'var(--vscode-button-background)', height: '2px' }} /> {screenshotQuality ?? 75}%

Adjust the WebP quality of browser screenshots. Higher values provide clearer screenshots but increase token usage.

Notification Settings

setSoundEnabled(e.target.checked)}> Enable sound effects

When enabled, Cline will play sound effects for notifications and events.

{soundEnabled && (
Volume setSoundVolume(parseFloat(e.target.value))} style={{ flexGrow: 1, accentColor: 'var(--vscode-button-background)', height: '2px' }} aria-label="Volume" /> {((soundVolume ?? 0.5) * 100).toFixed(0)}%
)}
{IS_DEV && ( <>
Debug
Reset State

This will reset all global state and secret storage in the extension.

)}

If you have any questions or feedback, feel free to open an issue at{" "} github.com/RooVetGit/Roo-Cline or join {" "} reddit.com/r/roocline

v{version}

) } export default memo(SettingsView)