Просмотр исходного кода

Additional checkbox for auto-approving reads and writes outside of the workspace (#1965)

Matt Rubens 9 месяцев назад
Родитель
Сommit
1810efe496
28 измененных файлов с 598 добавлено и 43 удалено
  1. 12 0
      src/core/Cline.ts
  2. 14 0
      src/core/webview/ClineProvider.ts
  3. 2 0
      src/core/webview/__tests__/ClineProvider.test.ts
  4. 2 0
      src/exports/roo-code.d.ts
  5. 3 0
      src/shared/ExtensionMessage.ts
  6. 2 0
      src/shared/WebviewMessage.ts
  7. 2 0
      src/shared/globalState.ts
  8. 24 0
      src/utils/pathUtils.ts
  9. 51 13
      webview-ui/src/components/chat/ChatView.tsx
  10. 280 0
      webview-ui/src/components/chat/__tests__/ChatView.auto-approve.test.tsx
  11. 41 0
      webview-ui/src/components/settings/AutoApproveSettings.tsx
  12. 9 0
      webview-ui/src/components/settings/SettingsView.tsx
  13. 6 0
      webview-ui/src/context/ExtensionStateContext.tsx
  14. 10 2
      webview-ui/src/i18n/locales/ca/settings.json
  15. 10 2
      webview-ui/src/i18n/locales/de/settings.json
  16. 10 2
      webview-ui/src/i18n/locales/en/settings.json
  17. 10 2
      webview-ui/src/i18n/locales/es/settings.json
  18. 10 2
      webview-ui/src/i18n/locales/fr/settings.json
  19. 10 2
      webview-ui/src/i18n/locales/hi/settings.json
  20. 10 2
      webview-ui/src/i18n/locales/it/settings.json
  21. 10 2
      webview-ui/src/i18n/locales/ja/settings.json
  22. 10 2
      webview-ui/src/i18n/locales/ko/settings.json
  23. 10 2
      webview-ui/src/i18n/locales/pl/settings.json
  24. 10 2
      webview-ui/src/i18n/locales/pt-BR/settings.json
  25. 10 2
      webview-ui/src/i18n/locales/tr/settings.json
  26. 10 2
      webview-ui/src/i18n/locales/vi/settings.json
  27. 10 2
      webview-ui/src/i18n/locales/zh-CN/settings.json
  28. 10 2
      webview-ui/src/i18n/locales/zh-TW/settings.json

+ 12 - 0
src/core/Cline.ts

@@ -11,6 +11,7 @@ import pWaitFor from "p-wait-for"
 import getFolderSize from "get-folder-size"
 import getFolderSize from "get-folder-size"
 import { serializeError } from "serialize-error"
 import { serializeError } from "serialize-error"
 import * as vscode from "vscode"
 import * as vscode from "vscode"
+import { isPathOutsideWorkspace } from "../utils/pathUtils"
 
 
 import { TokenUsage } from "../exports/roo-code"
 import { TokenUsage } from "../exports/roo-code"
 import { ApiHandler, buildApiHandler } from "../api"
 import { ApiHandler, buildApiHandler } from "../api"
@@ -1606,9 +1607,14 @@ export class Cline extends EventEmitter<ClineEvents> {
 							}
 							}
 						}
 						}
 
 
+						// Determine if the path is outside the workspace
+						const fullPath = relPath ? path.resolve(this.cwd, removeClosingTag("path", relPath)) : ""
+						const isOutsideWorkspace = isPathOutsideWorkspace(fullPath)
+
 						const sharedMessageProps: ClineSayTool = {
 						const sharedMessageProps: ClineSayTool = {
 							tool: fileExists ? "editedExistingFile" : "newFileCreated",
 							tool: fileExists ? "editedExistingFile" : "newFileCreated",
 							path: getReadablePath(this.cwd, removeClosingTag("path", relPath)),
 							path: getReadablePath(this.cwd, removeClosingTag("path", relPath)),
+							isOutsideWorkspace,
 						}
 						}
 						try {
 						try {
 							if (block.partial) {
 							if (block.partial) {
@@ -2245,9 +2251,15 @@ export class Cline extends EventEmitter<ClineEvents> {
 						const relPath: string | undefined = block.params.path
 						const relPath: string | undefined = block.params.path
 						const startLineStr: string | undefined = block.params.start_line
 						const startLineStr: string | undefined = block.params.start_line
 						const endLineStr: string | undefined = block.params.end_line
 						const endLineStr: string | undefined = block.params.end_line
+
+						// Get the full path and determine if it's outside the workspace
+						const fullPath = relPath ? path.resolve(this.cwd, removeClosingTag("path", relPath)) : ""
+						const isOutsideWorkspace = isPathOutsideWorkspace(fullPath)
+
 						const sharedMessageProps: ClineSayTool = {
 						const sharedMessageProps: ClineSayTool = {
 							tool: "readFile",
 							tool: "readFile",
 							path: getReadablePath(this.cwd, removeClosingTag("path", relPath)),
 							path: getReadablePath(this.cwd, removeClosingTag("path", relPath)),
+							isOutsideWorkspace,
 						}
 						}
 						try {
 						try {
 							if (block.partial) {
 							if (block.partial) {

+ 14 - 0
src/core/webview/ClineProvider.ts

@@ -971,10 +971,18 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
 						await this.updateGlobalState("alwaysAllowReadOnly", message.bool ?? undefined)
 						await this.updateGlobalState("alwaysAllowReadOnly", message.bool ?? undefined)
 						await this.postStateToWebview()
 						await this.postStateToWebview()
 						break
 						break
+					case "alwaysAllowReadOnlyOutsideWorkspace":
+						await this.updateGlobalState("alwaysAllowReadOnlyOutsideWorkspace", message.bool ?? undefined)
+						await this.postStateToWebview()
+						break
 					case "alwaysAllowWrite":
 					case "alwaysAllowWrite":
 						await this.updateGlobalState("alwaysAllowWrite", message.bool ?? undefined)
 						await this.updateGlobalState("alwaysAllowWrite", message.bool ?? undefined)
 						await this.postStateToWebview()
 						await this.postStateToWebview()
 						break
 						break
+					case "alwaysAllowWriteOutsideWorkspace":
+						await this.updateGlobalState("alwaysAllowWriteOutsideWorkspace", message.bool ?? undefined)
+						await this.postStateToWebview()
+						break
 					case "alwaysAllowExecute":
 					case "alwaysAllowExecute":
 						await this.updateGlobalState("alwaysAllowExecute", message.bool ?? undefined)
 						await this.updateGlobalState("alwaysAllowExecute", message.bool ?? undefined)
 						await this.postStateToWebview()
 						await this.postStateToWebview()
@@ -2490,7 +2498,9 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
 			lastShownAnnouncementId,
 			lastShownAnnouncementId,
 			customInstructions,
 			customInstructions,
 			alwaysAllowReadOnly,
 			alwaysAllowReadOnly,
+			alwaysAllowReadOnlyOutsideWorkspace,
 			alwaysAllowWrite,
 			alwaysAllowWrite,
+			alwaysAllowWriteOutsideWorkspace,
 			alwaysAllowExecute,
 			alwaysAllowExecute,
 			alwaysAllowBrowser,
 			alwaysAllowBrowser,
 			alwaysAllowMcp,
 			alwaysAllowMcp,
@@ -2544,7 +2554,9 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
 			apiConfiguration,
 			apiConfiguration,
 			customInstructions,
 			customInstructions,
 			alwaysAllowReadOnly: alwaysAllowReadOnly ?? false,
 			alwaysAllowReadOnly: alwaysAllowReadOnly ?? false,
+			alwaysAllowReadOnlyOutsideWorkspace: alwaysAllowReadOnlyOutsideWorkspace ?? false,
 			alwaysAllowWrite: alwaysAllowWrite ?? false,
 			alwaysAllowWrite: alwaysAllowWrite ?? false,
+			alwaysAllowWriteOutsideWorkspace: alwaysAllowWriteOutsideWorkspace ?? false,
 			alwaysAllowExecute: alwaysAllowExecute ?? false,
 			alwaysAllowExecute: alwaysAllowExecute ?? false,
 			alwaysAllowBrowser: alwaysAllowBrowser ?? false,
 			alwaysAllowBrowser: alwaysAllowBrowser ?? false,
 			alwaysAllowMcp: alwaysAllowMcp ?? false,
 			alwaysAllowMcp: alwaysAllowMcp ?? false,
@@ -2707,7 +2719,9 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
 			lastShownAnnouncementId: stateValues.lastShownAnnouncementId,
 			lastShownAnnouncementId: stateValues.lastShownAnnouncementId,
 			customInstructions: stateValues.customInstructions,
 			customInstructions: stateValues.customInstructions,
 			alwaysAllowReadOnly: stateValues.alwaysAllowReadOnly ?? false,
 			alwaysAllowReadOnly: stateValues.alwaysAllowReadOnly ?? false,
+			alwaysAllowReadOnlyOutsideWorkspace: stateValues.alwaysAllowReadOnlyOutsideWorkspace ?? false,
 			alwaysAllowWrite: stateValues.alwaysAllowWrite ?? false,
 			alwaysAllowWrite: stateValues.alwaysAllowWrite ?? false,
+			alwaysAllowWriteOutsideWorkspace: stateValues.alwaysAllowWriteOutsideWorkspace ?? false,
 			alwaysAllowExecute: stateValues.alwaysAllowExecute ?? false,
 			alwaysAllowExecute: stateValues.alwaysAllowExecute ?? false,
 			alwaysAllowBrowser: stateValues.alwaysAllowBrowser ?? false,
 			alwaysAllowBrowser: stateValues.alwaysAllowBrowser ?? false,
 			alwaysAllowMcp: stateValues.alwaysAllowMcp ?? false,
 			alwaysAllowMcp: stateValues.alwaysAllowMcp ?? false,

+ 2 - 0
src/core/webview/__tests__/ClineProvider.test.ts

@@ -434,7 +434,9 @@ describe("ClineProvider", () => {
 			},
 			},
 			customInstructions: undefined,
 			customInstructions: undefined,
 			alwaysAllowReadOnly: false,
 			alwaysAllowReadOnly: false,
+			alwaysAllowReadOnlyOutsideWorkspace: false,
 			alwaysAllowWrite: false,
 			alwaysAllowWrite: false,
+			alwaysAllowWriteOutsideWorkspace: false,
 			alwaysAllowExecute: false,
 			alwaysAllowExecute: false,
 			alwaysAllowBrowser: false,
 			alwaysAllowBrowser: false,
 			alwaysAllowMcp: false,
 			alwaysAllowMcp: false,

+ 2 - 0
src/exports/roo-code.d.ts

@@ -182,7 +182,9 @@ export type GlobalStateKey =
 	| "lastShownAnnouncementId"
 	| "lastShownAnnouncementId"
 	| "customInstructions"
 	| "customInstructions"
 	| "alwaysAllowReadOnly"
 	| "alwaysAllowReadOnly"
+	| "alwaysAllowReadOnlyOutsideWorkspace"
 	| "alwaysAllowWrite"
 	| "alwaysAllowWrite"
+	| "alwaysAllowWriteOutsideWorkspace"
 	| "alwaysAllowExecute"
 	| "alwaysAllowExecute"
 	| "alwaysAllowBrowser"
 	| "alwaysAllowBrowser"
 	| "alwaysAllowMcp"
 	| "alwaysAllowMcp"

+ 3 - 0
src/shared/ExtensionMessage.ts

@@ -120,7 +120,9 @@ export interface ExtensionState {
 	customModePrompts?: CustomModePrompts
 	customModePrompts?: CustomModePrompts
 	customSupportPrompts?: CustomSupportPrompts
 	customSupportPrompts?: CustomSupportPrompts
 	alwaysAllowReadOnly?: boolean
 	alwaysAllowReadOnly?: boolean
+	alwaysAllowReadOnlyOutsideWorkspace?: boolean
 	alwaysAllowWrite?: boolean
 	alwaysAllowWrite?: boolean
+	alwaysAllowWriteOutsideWorkspace?: boolean
 	alwaysAllowExecute?: boolean
 	alwaysAllowExecute?: boolean
 	alwaysAllowBrowser?: boolean
 	alwaysAllowBrowser?: boolean
 	alwaysAllowMcp?: boolean
 	alwaysAllowMcp?: boolean
@@ -192,6 +194,7 @@ export interface ClineSayTool {
 	filePattern?: string
 	filePattern?: string
 	mode?: string
 	mode?: string
 	reason?: string
 	reason?: string
+	isOutsideWorkspace?: boolean
 }
 }
 
 
 // Must keep in sync with system prompt.
 // Must keep in sync with system prompt.

+ 2 - 0
src/shared/WebviewMessage.ts

@@ -22,7 +22,9 @@ export interface WebviewMessage {
 		| "customInstructions"
 		| "customInstructions"
 		| "allowedCommands"
 		| "allowedCommands"
 		| "alwaysAllowReadOnly"
 		| "alwaysAllowReadOnly"
+		| "alwaysAllowReadOnlyOutsideWorkspace"
 		| "alwaysAllowWrite"
 		| "alwaysAllowWrite"
+		| "alwaysAllowWriteOutsideWorkspace"
 		| "alwaysAllowExecute"
 		| "alwaysAllowExecute"
 		| "webviewDidLaunch"
 		| "webviewDidLaunch"
 		| "newTask"
 		| "newTask"

+ 2 - 0
src/shared/globalState.ts

@@ -49,7 +49,9 @@ export const GLOBAL_STATE_KEYS = [
 	"lastShownAnnouncementId",
 	"lastShownAnnouncementId",
 	"customInstructions",
 	"customInstructions",
 	"alwaysAllowReadOnly",
 	"alwaysAllowReadOnly",
+	"alwaysAllowReadOnlyOutsideWorkspace",
 	"alwaysAllowWrite",
 	"alwaysAllowWrite",
+	"alwaysAllowWriteOutsideWorkspace",
 	"alwaysAllowExecute",
 	"alwaysAllowExecute",
 	"alwaysAllowBrowser",
 	"alwaysAllowBrowser",
 	"alwaysAllowMcp",
 	"alwaysAllowMcp",

+ 24 - 0
src/utils/pathUtils.ts

@@ -0,0 +1,24 @@
+import * as vscode from "vscode"
+import * as path from "path"
+
+/**
+ * Checks if a file path is outside all workspace folders
+ * @param filePath The file path to check
+ * @returns true if the path is outside all workspace folders, false otherwise
+ */
+export function isPathOutsideWorkspace(filePath: string): boolean {
+	// If there are no workspace folders, consider everything outside workspace for safety
+	if (!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0) {
+		return true
+	}
+
+	// Normalize and resolve the path to handle .. and . components correctly
+	const absolutePath = path.resolve(filePath)
+
+	// Check if the path is within any workspace folder
+	return !vscode.workspace.workspaceFolders.some((folder) => {
+		const folderPath = folder.uri.fsPath
+		// Path is inside a workspace if it equals the workspace path or is a subfolder
+		return absolutePath === folderPath || absolutePath.startsWith(folderPath + path.sep)
+	})
+}

+ 51 - 13
webview-ui/src/components/chat/ChatView.tsx

@@ -55,7 +55,9 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
 		mcpServers,
 		mcpServers,
 		alwaysAllowBrowser,
 		alwaysAllowBrowser,
 		alwaysAllowReadOnly,
 		alwaysAllowReadOnly,
+		alwaysAllowReadOnlyOutsideWorkspace,
 		alwaysAllowWrite,
 		alwaysAllowWrite,
+		alwaysAllowWriteOutsideWorkspace,
 		alwaysAllowExecute,
 		alwaysAllowExecute,
 		alwaysAllowMcp,
 		alwaysAllowMcp,
 		allowedCommands,
 		allowedCommands,
@@ -649,26 +651,60 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
 		(message: ClineMessage | undefined) => {
 		(message: ClineMessage | undefined) => {
 			if (!autoApprovalEnabled || !message || message.type !== "ask") return false
 			if (!autoApprovalEnabled || !message || message.type !== "ask") return false
 
 
-			return (
-				(alwaysAllowBrowser && message.ask === "browser_action_launch") ||
-				(alwaysAllowReadOnly && message.ask === "tool" && isReadOnlyToolAction(message)) ||
-				(alwaysAllowWrite && message.ask === "tool" && isWriteToolAction(message)) ||
-				(alwaysAllowExecute && message.ask === "command" && isAllowedCommand(message)) ||
-				(alwaysAllowMcp && message.ask === "use_mcp_server" && isMcpToolAlwaysAllowed(message)) ||
-				(alwaysAllowModeSwitch &&
-					message.ask === "tool" &&
-					JSON.parse(message.text || "{}")?.tool === "switchMode") ||
-				(alwaysAllowSubtasks &&
-					message.ask === "tool" &&
-					["newTask", "finishTask"].includes(JSON.parse(message.text || "{}")?.tool))
-			)
+			if (message.ask === "browser_action_launch") {
+				return alwaysAllowBrowser
+			}
+
+			if (message.ask === "use_mcp_server") {
+				return alwaysAllowMcp && isMcpToolAlwaysAllowed(message)
+			}
+
+			if (message.ask === "command") {
+				return alwaysAllowExecute && isAllowedCommand(message)
+			}
+
+			// For read/write operations, check if it's outside workspace and if we have permission for that
+			if (message.ask === "tool") {
+				let tool: any = {}
+				try {
+					tool = JSON.parse(message.text || "{}")
+				} catch (error) {
+					console.error("Failed to parse tool:", error)
+				}
+
+				if (!tool) {
+					return false
+				}
+
+				if (tool?.tool === "switchMode") {
+					return alwaysAllowModeSwitch
+				}
+
+				if (["newTask", "finishTask"].includes(tool?.tool)) {
+					return alwaysAllowSubtasks
+				}
+
+				const isOutsideWorkspace = !!tool.isOutsideWorkspace
+
+				if (isReadOnlyToolAction(message)) {
+					return alwaysAllowReadOnly && (!isOutsideWorkspace || alwaysAllowReadOnlyOutsideWorkspace)
+				}
+
+				if (isWriteToolAction(message)) {
+					return alwaysAllowWrite && (!isOutsideWorkspace || alwaysAllowWriteOutsideWorkspace)
+				}
+			}
+
+			return false
 		},
 		},
 		[
 		[
 			autoApprovalEnabled,
 			autoApprovalEnabled,
 			alwaysAllowBrowser,
 			alwaysAllowBrowser,
 			alwaysAllowReadOnly,
 			alwaysAllowReadOnly,
+			alwaysAllowReadOnlyOutsideWorkspace,
 			isReadOnlyToolAction,
 			isReadOnlyToolAction,
 			alwaysAllowWrite,
 			alwaysAllowWrite,
+			alwaysAllowWriteOutsideWorkspace,
 			isWriteToolAction,
 			isWriteToolAction,
 			alwaysAllowExecute,
 			alwaysAllowExecute,
 			isAllowedCommand,
 			isAllowedCommand,
@@ -1047,7 +1083,9 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
 		handlePrimaryButtonClick,
 		handlePrimaryButtonClick,
 		alwaysAllowBrowser,
 		alwaysAllowBrowser,
 		alwaysAllowReadOnly,
 		alwaysAllowReadOnly,
+		alwaysAllowReadOnlyOutsideWorkspace,
 		alwaysAllowWrite,
 		alwaysAllowWrite,
+		alwaysAllowWriteOutsideWorkspace,
 		alwaysAllowExecute,
 		alwaysAllowExecute,
 		alwaysAllowMcp,
 		alwaysAllowMcp,
 		messages,
 		messages,

+ 280 - 0
webview-ui/src/components/chat/__tests__/ChatView.auto-approve.test.tsx

@@ -146,6 +146,156 @@ describe("ChatView - Auto Approval Tests", () => {
 		})
 		})
 	})
 	})
 
 
+	it("auto-approves outside workspace read operations when enabled", async () => {
+		render(
+			<ExtensionStateContextProvider>
+				<ChatView
+					isHidden={false}
+					showAnnouncement={false}
+					hideAnnouncement={() => {}}
+					showHistoryView={() => {}}
+				/>
+			</ExtensionStateContextProvider>,
+		)
+
+		// First hydrate state with initial task
+		mockPostMessage({
+			alwaysAllowReadOnly: true,
+			alwaysAllowReadOnlyOutsideWorkspace: true,
+			autoApprovalEnabled: true,
+			clineMessages: [
+				{
+					type: "say",
+					say: "task",
+					ts: Date.now() - 2000,
+					text: "Initial task",
+				},
+			],
+		})
+
+		// Then send the read tool ask message with an absolute path (outside workspace)
+		mockPostMessage({
+			alwaysAllowReadOnly: true,
+			alwaysAllowReadOnlyOutsideWorkspace: true,
+			autoApprovalEnabled: true,
+			clineMessages: [
+				{
+					type: "say",
+					say: "task",
+					ts: Date.now() - 2000,
+					text: "Initial task",
+				},
+				{
+					type: "ask",
+					ask: "tool",
+					ts: Date.now(),
+					text: JSON.stringify({
+						tool: "readFile",
+						path: "/absolute/path/test.txt",
+						// Use an absolute path that's clearly outside workspace
+					}),
+					partial: false,
+				},
+			],
+		})
+
+		// Also mock the filePaths for workspace detection
+		mockPostMessage({
+			alwaysAllowReadOnly: true,
+			alwaysAllowReadOnlyOutsideWorkspace: true,
+			autoApprovalEnabled: true,
+			filePaths: ["/workspace/root", "/another/workspace"],
+			clineMessages: [
+				{
+					type: "say",
+					say: "task",
+					ts: Date.now() - 2000,
+					text: "Initial task",
+				},
+				{
+					type: "ask",
+					ask: "tool",
+					ts: Date.now(),
+					text: JSON.stringify({
+						tool: "readFile",
+						path: "/absolute/path/test.txt",
+					}),
+					partial: false,
+				},
+			],
+		})
+
+		// Wait for the auto-approval message
+		await waitFor(() => {
+			expect(vscode.postMessage).toHaveBeenCalledWith({
+				type: "askResponse",
+				askResponse: "yesButtonClicked",
+			})
+		})
+	})
+
+	it("does not auto-approve outside workspace read operations without permission", async () => {
+		render(
+			<ExtensionStateContextProvider>
+				<ChatView
+					isHidden={false}
+					showAnnouncement={false}
+					hideAnnouncement={() => {}}
+					showHistoryView={() => {}}
+				/>
+			</ExtensionStateContextProvider>,
+		)
+
+		// First hydrate state with initial task
+		mockPostMessage({
+			alwaysAllowReadOnly: true,
+			alwaysAllowReadOnlyOutsideWorkspace: false, // No permission for outside workspace
+			autoApprovalEnabled: true,
+			filePaths: ["/workspace/root", "/another/workspace"], // Same workspace paths as before
+			clineMessages: [
+				{
+					type: "say",
+					say: "task",
+					ts: Date.now() - 2000,
+					text: "Initial task",
+				},
+			],
+		})
+
+		// Then send the read tool ask message with an absolute path (outside workspace)
+		mockPostMessage({
+			alwaysAllowReadOnly: true,
+			alwaysAllowReadOnlyOutsideWorkspace: false,
+			autoApprovalEnabled: true,
+			clineMessages: [
+				{
+					type: "say",
+					say: "task",
+					ts: Date.now() - 2000,
+					text: "Initial task",
+				},
+				{
+					type: "ask",
+					ask: "tool",
+					ts: Date.now(),
+					text: JSON.stringify({
+						tool: "readFile",
+						path: "/absolute/path/test.txt",
+						isOutsideWorkspace: true, // Explicitly indicate this is outside workspace
+					}),
+					partial: false,
+				},
+			],
+		})
+
+		// Wait a short time and verify no auto-approval message was sent
+		await new Promise((resolve) => setTimeout(resolve, 100))
+		expect(vscode.postMessage).not.toHaveBeenCalledWith({
+			type: "askResponse",
+			askResponse: "yesButtonClicked",
+		})
+	})
+
 	it("does not auto-approve when autoApprovalEnabled is false", async () => {
 	it("does not auto-approve when autoApprovalEnabled is false", async () => {
 		render(
 		render(
 			<ExtensionStateContextProvider>
 			<ExtensionStateContextProvider>
@@ -258,6 +408,136 @@ describe("ChatView - Auto Approval Tests", () => {
 		})
 		})
 	})
 	})
 
 
+	it("auto-approves outside workspace write operations when enabled", async () => {
+		render(
+			<ExtensionStateContextProvider>
+				<ChatView
+					isHidden={false}
+					showAnnouncement={false}
+					hideAnnouncement={() => {}}
+					showHistoryView={() => {}}
+				/>
+			</ExtensionStateContextProvider>,
+		)
+
+		// First hydrate state with initial task
+		mockPostMessage({
+			alwaysAllowWrite: true,
+			alwaysAllowWriteOutsideWorkspace: true,
+			autoApprovalEnabled: true,
+			writeDelayMs: 0, // Set to 0 for testing
+			filePaths: ["/workspace/root", "/another/workspace"], // Define workspace paths for testing
+			clineMessages: [
+				{
+					type: "say",
+					say: "task",
+					ts: Date.now() - 2000,
+					text: "Initial task",
+				},
+			],
+		})
+
+		// Then send the write tool ask message with an absolute path (outside workspace)
+		mockPostMessage({
+			alwaysAllowWrite: true,
+			alwaysAllowWriteOutsideWorkspace: true,
+			autoApprovalEnabled: true,
+			writeDelayMs: 0,
+			clineMessages: [
+				{
+					type: "say",
+					say: "task",
+					ts: Date.now() - 2000,
+					text: "Initial task",
+				},
+				{
+					type: "ask",
+					ask: "tool",
+					ts: Date.now(),
+					text: JSON.stringify({
+						tool: "editedExistingFile",
+						path: "/absolute/path/test.txt",
+						content: "Test content",
+					}),
+					partial: false,
+				},
+			],
+		})
+
+		// Wait for the auto-approval message
+		await waitFor(() => {
+			expect(vscode.postMessage).toHaveBeenCalledWith({
+				type: "askResponse",
+				askResponse: "yesButtonClicked",
+			})
+		})
+	})
+
+	it("does not auto-approve outside workspace write operations without permission", async () => {
+		render(
+			<ExtensionStateContextProvider>
+				<ChatView
+					isHidden={false}
+					showAnnouncement={false}
+					hideAnnouncement={() => {}}
+					showHistoryView={() => {}}
+				/>
+			</ExtensionStateContextProvider>,
+		)
+
+		// First hydrate state with initial task
+		mockPostMessage({
+			alwaysAllowWrite: true,
+			alwaysAllowWriteOutsideWorkspace: false, // No permission for outside workspace
+			autoApprovalEnabled: true,
+			writeDelayMs: 0,
+			filePaths: ["/workspace/root", "/another/workspace"], // Define workspace paths for testing
+			clineMessages: [
+				{
+					type: "say",
+					say: "task",
+					ts: Date.now() - 2000,
+					text: "Initial task",
+				},
+			],
+		})
+
+		// Then send the write tool ask message with an absolute path (outside workspace)
+		mockPostMessage({
+			alwaysAllowWrite: true,
+			alwaysAllowWriteOutsideWorkspace: false,
+			autoApprovalEnabled: true,
+			writeDelayMs: 0,
+			clineMessages: [
+				{
+					type: "say",
+					say: "task",
+					ts: Date.now() - 2000,
+					text: "Initial task",
+				},
+				{
+					type: "ask",
+					ask: "tool",
+					ts: Date.now(),
+					text: JSON.stringify({
+						tool: "editedExistingFile",
+						path: "/absolute/path/test.txt",
+						content: "Test content",
+						isOutsideWorkspace: true, // Explicitly indicate this is outside workspace
+					}),
+					partial: false,
+				},
+			],
+		})
+
+		// Wait a short time and verify no auto-approval message was sent
+		await new Promise((resolve) => setTimeout(resolve, 100))
+		expect(vscode.postMessage).not.toHaveBeenCalledWith({
+			type: "askResponse",
+			askResponse: "yesButtonClicked",
+		})
+	})
+
 	it("auto-approves browser actions when enabled", async () => {
 	it("auto-approves browser actions when enabled", async () => {
 		render(
 		render(
 			<ExtensionStateContextProvider>
 			<ExtensionStateContextProvider>

+ 41 - 0
webview-ui/src/components/settings/AutoApproveSettings.tsx

@@ -12,7 +12,9 @@ import { Section } from "./Section"
 
 
 type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
 type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
 	alwaysAllowReadOnly?: boolean
 	alwaysAllowReadOnly?: boolean
+	alwaysAllowReadOnlyOutsideWorkspace?: boolean
 	alwaysAllowWrite?: boolean
 	alwaysAllowWrite?: boolean
+	alwaysAllowWriteOutsideWorkspace?: boolean
 	writeDelayMs: number
 	writeDelayMs: number
 	alwaysAllowBrowser?: boolean
 	alwaysAllowBrowser?: boolean
 	alwaysApproveResubmit?: boolean
 	alwaysApproveResubmit?: boolean
@@ -24,7 +26,9 @@ type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
 	allowedCommands?: string[]
 	allowedCommands?: string[]
 	setCachedStateField: SetCachedStateField<
 	setCachedStateField: SetCachedStateField<
 		| "alwaysAllowReadOnly"
 		| "alwaysAllowReadOnly"
+		| "alwaysAllowReadOnlyOutsideWorkspace"
 		| "alwaysAllowWrite"
 		| "alwaysAllowWrite"
+		| "alwaysAllowWriteOutsideWorkspace"
 		| "writeDelayMs"
 		| "writeDelayMs"
 		| "alwaysAllowBrowser"
 		| "alwaysAllowBrowser"
 		| "alwaysApproveResubmit"
 		| "alwaysApproveResubmit"
@@ -39,7 +43,9 @@ type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
 
 
 export const AutoApproveSettings = ({
 export const AutoApproveSettings = ({
 	alwaysAllowReadOnly,
 	alwaysAllowReadOnly,
+	alwaysAllowReadOnlyOutsideWorkspace,
 	alwaysAllowWrite,
 	alwaysAllowWrite,
+	alwaysAllowWriteOutsideWorkspace,
 	writeDelayMs,
 	writeDelayMs,
 	alwaysAllowBrowser,
 	alwaysAllowBrowser,
 	alwaysApproveResubmit,
 	alwaysApproveResubmit,
@@ -88,6 +94,26 @@ export const AutoApproveSettings = ({
 					</div>
 					</div>
 				</div>
 				</div>
 
 
+				{alwaysAllowReadOnly && (
+					<div className="flex flex-col gap-3 pl-3 border-l-2 border-vscode-button-background">
+						<div>
+							<VSCodeCheckbox
+								checked={alwaysAllowReadOnlyOutsideWorkspace}
+								onChange={(e: any) =>
+									setCachedStateField("alwaysAllowReadOnlyOutsideWorkspace", e.target.checked)
+								}
+								data-testid="always-allow-readonly-outside-workspace-checkbox">
+								<span className="font-medium">
+									{t("settings:autoApprove.readOnly.outsideWorkspace.label")}
+								</span>
+							</VSCodeCheckbox>
+							<div className="text-vscode-descriptionForeground text-sm mt-1">
+								{t("settings:autoApprove.readOnly.outsideWorkspace.description")}
+							</div>
+						</div>
+					</div>
+				)}
+
 				<div>
 				<div>
 					<VSCodeCheckbox
 					<VSCodeCheckbox
 						checked={alwaysAllowWrite}
 						checked={alwaysAllowWrite}
@@ -102,6 +128,21 @@ export const AutoApproveSettings = ({
 
 
 				{alwaysAllowWrite && (
 				{alwaysAllowWrite && (
 					<div className="flex flex-col gap-3 pl-3 border-l-2 border-vscode-button-background">
 					<div className="flex flex-col gap-3 pl-3 border-l-2 border-vscode-button-background">
+						<div>
+							<VSCodeCheckbox
+								checked={alwaysAllowWriteOutsideWorkspace}
+								onChange={(e: any) =>
+									setCachedStateField("alwaysAllowWriteOutsideWorkspace", e.target.checked)
+								}
+								data-testid="always-allow-write-outside-workspace-checkbox">
+								<span className="font-medium">
+									{t("settings:autoApprove.write.outsideWorkspace.label")}
+								</span>
+							</VSCodeCheckbox>
+							<div className="text-vscode-descriptionForeground text-sm mt-1 mb-3">
+								{t("settings:autoApprove.write.outsideWorkspace.description")}
+							</div>
+						</div>
 						<div>
 						<div>
 							<div className="flex items-center gap-2">
 							<div className="flex items-center gap-2">
 								<Slider
 								<Slider

+ 9 - 0
webview-ui/src/components/settings/SettingsView.tsx

@@ -98,6 +98,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
 
 
 	const {
 	const {
 		alwaysAllowReadOnly,
 		alwaysAllowReadOnly,
+		alwaysAllowReadOnlyOutsideWorkspace,
 		allowedCommands,
 		allowedCommands,
 		language,
 		language,
 		alwaysAllowBrowser,
 		alwaysAllowBrowser,
@@ -106,6 +107,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
 		alwaysAllowModeSwitch,
 		alwaysAllowModeSwitch,
 		alwaysAllowSubtasks,
 		alwaysAllowSubtasks,
 		alwaysAllowWrite,
 		alwaysAllowWrite,
+		alwaysAllowWriteOutsideWorkspace,
 		alwaysApproveResubmit,
 		alwaysApproveResubmit,
 		browserToolEnabled,
 		browserToolEnabled,
 		browserViewportSize,
 		browserViewportSize,
@@ -207,7 +209,12 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
 		if (isSettingValid) {
 		if (isSettingValid) {
 			vscode.postMessage({ type: "language", text: language })
 			vscode.postMessage({ type: "language", text: language })
 			vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly })
 			vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly })
+			vscode.postMessage({
+				type: "alwaysAllowReadOnlyOutsideWorkspace",
+				bool: alwaysAllowReadOnlyOutsideWorkspace,
+			})
 			vscode.postMessage({ type: "alwaysAllowWrite", bool: alwaysAllowWrite })
 			vscode.postMessage({ type: "alwaysAllowWrite", bool: alwaysAllowWrite })
+			vscode.postMessage({ type: "alwaysAllowWriteOutsideWorkspace", bool: alwaysAllowWriteOutsideWorkspace })
 			vscode.postMessage({ type: "alwaysAllowExecute", bool: alwaysAllowExecute })
 			vscode.postMessage({ type: "alwaysAllowExecute", bool: alwaysAllowExecute })
 			vscode.postMessage({ type: "alwaysAllowBrowser", bool: alwaysAllowBrowser })
 			vscode.postMessage({ type: "alwaysAllowBrowser", bool: alwaysAllowBrowser })
 			vscode.postMessage({ type: "alwaysAllowMcp", bool: alwaysAllowMcp })
 			vscode.postMessage({ type: "alwaysAllowMcp", bool: alwaysAllowMcp })
@@ -403,7 +410,9 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
 				<div ref={autoApproveRef}>
 				<div ref={autoApproveRef}>
 					<AutoApproveSettings
 					<AutoApproveSettings
 						alwaysAllowReadOnly={alwaysAllowReadOnly}
 						alwaysAllowReadOnly={alwaysAllowReadOnly}
+						alwaysAllowReadOnlyOutsideWorkspace={alwaysAllowReadOnlyOutsideWorkspace}
 						alwaysAllowWrite={alwaysAllowWrite}
 						alwaysAllowWrite={alwaysAllowWrite}
+						alwaysAllowWriteOutsideWorkspace={alwaysAllowWriteOutsideWorkspace}
 						writeDelayMs={writeDelayMs}
 						writeDelayMs={writeDelayMs}
 						alwaysAllowBrowser={alwaysAllowBrowser}
 						alwaysAllowBrowser={alwaysAllowBrowser}
 						alwaysApproveResubmit={alwaysApproveResubmit}
 						alwaysApproveResubmit={alwaysApproveResubmit}

+ 6 - 0
webview-ui/src/context/ExtensionStateContext.tsx

@@ -23,7 +23,9 @@ export interface ExtensionStateContextType extends ExtensionState {
 	setApiConfiguration: (config: ApiConfiguration) => void
 	setApiConfiguration: (config: ApiConfiguration) => void
 	setCustomInstructions: (value?: string) => void
 	setCustomInstructions: (value?: string) => void
 	setAlwaysAllowReadOnly: (value: boolean) => void
 	setAlwaysAllowReadOnly: (value: boolean) => void
+	setAlwaysAllowReadOnlyOutsideWorkspace: (value: boolean) => void
 	setAlwaysAllowWrite: (value: boolean) => void
 	setAlwaysAllowWrite: (value: boolean) => void
+	setAlwaysAllowWriteOutsideWorkspace: (value: boolean) => void
 	setAlwaysAllowExecute: (value: boolean) => void
 	setAlwaysAllowExecute: (value: boolean) => void
 	setAlwaysAllowBrowser: (value: boolean) => void
 	setAlwaysAllowBrowser: (value: boolean) => void
 	setAlwaysAllowMcp: (value: boolean) => void
 	setAlwaysAllowMcp: (value: boolean) => void
@@ -259,7 +261,11 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
 			})),
 			})),
 		setCustomInstructions: (value) => setState((prevState) => ({ ...prevState, customInstructions: value })),
 		setCustomInstructions: (value) => setState((prevState) => ({ ...prevState, customInstructions: value })),
 		setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })),
 		setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })),
+		setAlwaysAllowReadOnlyOutsideWorkspace: (value) =>
+			setState((prevState) => ({ ...prevState, alwaysAllowReadOnlyOutsideWorkspace: value })),
 		setAlwaysAllowWrite: (value) => setState((prevState) => ({ ...prevState, alwaysAllowWrite: value })),
 		setAlwaysAllowWrite: (value) => setState((prevState) => ({ ...prevState, alwaysAllowWrite: value })),
+		setAlwaysAllowWriteOutsideWorkspace: (value) =>
+			setState((prevState) => ({ ...prevState, alwaysAllowWriteOutsideWorkspace: value })),
 		setAlwaysAllowExecute: (value) => setState((prevState) => ({ ...prevState, alwaysAllowExecute: value })),
 		setAlwaysAllowExecute: (value) => setState((prevState) => ({ ...prevState, alwaysAllowExecute: value })),
 		setAlwaysAllowBrowser: (value) => setState((prevState) => ({ ...prevState, alwaysAllowBrowser: value })),
 		setAlwaysAllowBrowser: (value) => setState((prevState) => ({ ...prevState, alwaysAllowBrowser: value })),
 		setAlwaysAllowMcp: (value) => setState((prevState) => ({ ...prevState, alwaysAllowMcp: value })),
 		setAlwaysAllowMcp: (value) => setState((prevState) => ({ ...prevState, alwaysAllowMcp: value })),

+ 10 - 2
webview-ui/src/i18n/locales/ca/settings.json

@@ -35,12 +35,20 @@
 		"description": "Permet que Roo realitzi operacions automàticament sense requerir aprovació. Activeu aquesta configuració només si confieu plenament en la IA i enteneu els riscos de seguretat associats.",
 		"description": "Permet que Roo realitzi operacions automàticament sense requerir aprovació. Activeu aquesta configuració només si confieu plenament en la IA i enteneu els riscos de seguretat associats.",
 		"readOnly": {
 		"readOnly": {
 			"label": "Aprovar sempre operacions de només lectura",
 			"label": "Aprovar sempre operacions de només lectura",
-			"description": "Quan està activat, Roo veurà automàticament el contingut del directori i llegirà fitxers sense que calgui fer clic al botó Aprovar."
+			"description": "Quan està activat, Roo veurà automàticament el contingut del directori i llegirà fitxers sense que calgui fer clic al botó Aprovar.",
+			"outsideWorkspace": {
+				"label": "Incloure fitxers fora de l'espai de treball",
+				"description": "Permetre a Roo llegir fitxers fora de l'espai de treball actual sense requerir aprovació."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "Aprovar sempre operacions d'escriptura",
 			"label": "Aprovar sempre operacions d'escriptura",
 			"description": "Crear i editar fitxers automàticament sense requerir aprovació",
 			"description": "Crear i editar fitxers automàticament sense requerir aprovació",
-			"delayLabel": "Retard després d'escriptura per permetre que els diagnòstics detectin possibles problemes"
+			"delayLabel": "Retard després d'escriptura per permetre que els diagnòstics detectin possibles problemes",
+			"outsideWorkspace": {
+				"label": "Incloure fitxers fora de l'espai de treball",
+				"description": "Permetre a Roo crear i editar fitxers fora de l'espai de treball actual sense requerir aprovació."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "Aprovar sempre accions del navegador",
 			"label": "Aprovar sempre accions del navegador",

+ 10 - 2
webview-ui/src/i18n/locales/de/settings.json

@@ -35,12 +35,20 @@
 		"description": "Erlaubt Roo, Operationen automatisch ohne Genehmigung durchzuführen. Aktiviere diese Einstellungen nur, wenn du der KI vollständig vertraust und die damit verbundenen Sicherheitsrisiken verstehst.",
 		"description": "Erlaubt Roo, Operationen automatisch ohne Genehmigung durchzuführen. Aktiviere diese Einstellungen nur, wenn du der KI vollständig vertraust und die damit verbundenen Sicherheitsrisiken verstehst.",
 		"readOnly": {
 		"readOnly": {
 			"label": "Schreibgeschützte Operationen immer genehmigen",
 			"label": "Schreibgeschützte Operationen immer genehmigen",
-			"description": "Wenn aktiviert, wird Roo automatisch Verzeichnisinhalte anzeigen und Dateien lesen, ohne dass du auf die Genehmigen-Schaltfläche klicken musst."
+			"description": "Wenn aktiviert, wird Roo automatisch Verzeichnisinhalte anzeigen und Dateien lesen, ohne dass du auf die Genehmigen-Schaltfläche klicken musst.",
+			"outsideWorkspace": {
+				"label": "Dateien außerhalb des Arbeitsbereichs einbeziehen",
+				"description": "Roo erlauben, Dateien außerhalb des aktuellen Arbeitsbereichs ohne Genehmigung zu lesen."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "Schreiboperationen immer genehmigen",
 			"label": "Schreiboperationen immer genehmigen",
 			"description": "Dateien automatisch erstellen und bearbeiten ohne Genehmigung",
 			"description": "Dateien automatisch erstellen und bearbeiten ohne Genehmigung",
-			"delayLabel": "Verzögerung nach Schreibvorgängen, damit Diagnosefunktionen potenzielle Probleme erkennen können"
+			"delayLabel": "Verzögerung nach Schreibvorgängen, damit Diagnosefunktionen potenzielle Probleme erkennen können",
+			"outsideWorkspace": {
+				"label": "Dateien außerhalb des Arbeitsbereichs einbeziehen",
+				"description": "Roo erlauben, Dateien außerhalb des aktuellen Arbeitsbereichs ohne Genehmigung zu erstellen und zu bearbeiten."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "Browser-Aktionen immer genehmigen",
 			"label": "Browser-Aktionen immer genehmigen",

+ 10 - 2
webview-ui/src/i18n/locales/en/settings.json

@@ -35,12 +35,20 @@
 		"description": "Allow Roo to automatically perform operations without requiring approval. Enable these settings only if you fully trust the AI and understand the associated security risks.",
 		"description": "Allow Roo to automatically perform operations without requiring approval. Enable these settings only if you fully trust the AI and understand the associated security risks.",
 		"readOnly": {
 		"readOnly": {
 			"label": "Always approve read-only operations",
 			"label": "Always approve read-only operations",
-			"description": "When enabled, Roo will automatically view directory contents and read files without requiring you to click the Approve button."
+			"description": "When enabled, Roo will automatically view directory contents and read files without requiring you to click the Approve button.",
+			"outsideWorkspace": {
+				"label": "Include files outside workspace",
+				"description": "Allow Roo to read files outside the current workspace without requiring approval."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "Always approve write operations",
 			"label": "Always approve write operations",
 			"description": "Automatically create and edit files without requiring approval",
 			"description": "Automatically create and edit files without requiring approval",
-			"delayLabel": "Delay after writes to allow diagnostics to detect potential problems"
+			"delayLabel": "Delay after writes to allow diagnostics to detect potential problems",
+			"outsideWorkspace": {
+				"label": "Include files outside workspace",
+				"description": "Allow Roo to create and edit files outside the current workspace without requiring approval."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "Always approve browser actions",
 			"label": "Always approve browser actions",

+ 10 - 2
webview-ui/src/i18n/locales/es/settings.json

@@ -35,12 +35,20 @@
 		"description": "Permitir que Roo realice operaciones automáticamente sin requerir aprobación. Habilite esta configuración solo si confía plenamente en la IA y comprende los riesgos de seguridad asociados.",
 		"description": "Permitir que Roo realice operaciones automáticamente sin requerir aprobación. Habilite esta configuración solo si confía plenamente en la IA y comprende los riesgos de seguridad asociados.",
 		"readOnly": {
 		"readOnly": {
 			"label": "Aprobar siempre operaciones de solo lectura",
 			"label": "Aprobar siempre operaciones de solo lectura",
-			"description": "Cuando está habilitado, Roo verá automáticamente el contenido del directorio y leerá archivos sin que necesite hacer clic en el botón Aprobar."
+			"description": "Cuando está habilitado, Roo verá automáticamente el contenido del directorio y leerá archivos sin que necesite hacer clic en el botón Aprobar.",
+			"outsideWorkspace": {
+				"label": "Incluir archivos fuera del espacio de trabajo",
+				"description": "Permitir a Roo leer archivos fuera del espacio de trabajo actual sin requerir aprobación."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "Aprobar siempre operaciones de escritura",
 			"label": "Aprobar siempre operaciones de escritura",
 			"description": "Crear y editar archivos automáticamente sin requerir aprobación",
 			"description": "Crear y editar archivos automáticamente sin requerir aprobación",
-			"delayLabel": "Retraso después de escritura para permitir que los diagnósticos detecten posibles problemas"
+			"delayLabel": "Retraso después de escritura para permitir que los diagnósticos detecten posibles problemas",
+			"outsideWorkspace": {
+				"label": "Incluir archivos fuera del espacio de trabajo",
+				"description": "Permitir a Roo crear y editar archivos fuera del espacio de trabajo actual sin requerir aprobación."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "Aprobar siempre acciones del navegador",
 			"label": "Aprobar siempre acciones del navegador",

+ 10 - 2
webview-ui/src/i18n/locales/fr/settings.json

@@ -35,12 +35,20 @@
 		"description": "Permettre à Roo d'effectuer automatiquement des opérations sans requérir d'approbation. Activez ces paramètres uniquement si vous faites entièrement confiance à l'IA et que vous comprenez les risques de sécurité associés.",
 		"description": "Permettre à Roo d'effectuer automatiquement des opérations sans requérir d'approbation. Activez ces paramètres uniquement si vous faites entièrement confiance à l'IA et que vous comprenez les risques de sécurité associés.",
 		"readOnly": {
 		"readOnly": {
 			"label": "Toujours approuver les opérations en lecture seule",
 			"label": "Toujours approuver les opérations en lecture seule",
-			"description": "Lorsque cette option est activée, Roo affichera automatiquement le contenu des répertoires et lira les fichiers sans que vous ayez à cliquer sur le bouton Approuver."
+			"description": "Lorsque cette option est activée, Roo affichera automatiquement le contenu des répertoires et lira les fichiers sans que vous ayez à cliquer sur le bouton Approuver.",
+			"outsideWorkspace": {
+				"label": "Inclure les fichiers en dehors de l'espace de travail",
+				"description": "Permettre à Roo de lire des fichiers en dehors de l'espace de travail actuel sans nécessiter d'approbation."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "Toujours approuver les opérations d'écriture",
 			"label": "Toujours approuver les opérations d'écriture",
 			"description": "Créer et modifier automatiquement des fichiers sans nécessiter d'approbation",
 			"description": "Créer et modifier automatiquement des fichiers sans nécessiter d'approbation",
-			"delayLabel": "Délai après les écritures pour permettre aux diagnostics de détecter les problèmes potentiels"
+			"delayLabel": "Délai après les écritures pour permettre aux diagnostics de détecter les problèmes potentiels",
+			"outsideWorkspace": {
+				"label": "Inclure les fichiers en dehors de l'espace de travail",
+				"description": "Permettre à Roo de créer et modifier des fichiers en dehors de l'espace de travail actuel sans nécessiter d'approbation."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "Toujours approuver les actions du navigateur",
 			"label": "Toujours approuver les actions du navigateur",

+ 10 - 2
webview-ui/src/i18n/locales/hi/settings.json

@@ -35,12 +35,20 @@
 		"description": "Roo को अनुमोदन की आवश्यकता के बिना स्वचालित रूप से ऑपरेशन करने की अनुमति दें। इन सेटिंग्स को केवल तभी सक्षम करें जब आप AI पर पूरी तरह से भरोसा करते हों और संबंधित सुरक्षा जोखिमों को समझते हों।",
 		"description": "Roo को अनुमोदन की आवश्यकता के बिना स्वचालित रूप से ऑपरेशन करने की अनुमति दें। इन सेटिंग्स को केवल तभी सक्षम करें जब आप AI पर पूरी तरह से भरोसा करते हों और संबंधित सुरक्षा जोखिमों को समझते हों।",
 		"readOnly": {
 		"readOnly": {
 			"label": "केवल पढ़ने वाले ऑपरेशन हमेशा अनुमोदित करें",
 			"label": "केवल पढ़ने वाले ऑपरेशन हमेशा अनुमोदित करें",
-			"description": "जब सक्षम होता है, तो Roo आपके अनुमोदित बटन पर क्लिक किए बिना स्वचालित रूप से निर्देशिका सामग्री देखेगा और फाइलें पढ़ेगा।"
+			"description": "जब सक्षम होता है, तो Roo आपके अनुमोदित बटन पर क्लिक किए बिना स्वचालित रूप से निर्देशिका सामग्री देखेगा और फाइलें पढ़ेगा।",
+			"outsideWorkspace": {
+				"label": "वर्कस्पेस के बाहर की फाइलें शामिल करें",
+				"description": "Roo को अनुमोदन की आवश्यकता के बिना वर्तमान वर्कस्पेस के बाहर की फाइलें पढ़ने की अनुमति दें।"
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "लिखने वाले ऑपरेशन हमेशा अनुमोदित करें",
 			"label": "लिखने वाले ऑपरेशन हमेशा अनुमोदित करें",
 			"description": "अनुमोदन की आवश्यकता के बिना स्वचालित रूप से फाइलें बनाएँ और संपादित करें",
 			"description": "अनुमोदन की आवश्यकता के बिना स्वचालित रूप से फाइलें बनाएँ और संपादित करें",
-			"delayLabel": "लिखने के बाद विलंब ताकि डायग्नोस्टिक संभावित समस्याओं का पता लगा सकें"
+			"delayLabel": "लिखने के बाद विलंब ताकि डायग्नोस्टिक संभावित समस्याओं का पता लगा सकें",
+			"outsideWorkspace": {
+				"label": "वर्कस्पेस के बाहर की फाइलें शामिल करें",
+				"description": "Roo को अनुमोदन की आवश्यकता के बिना वर्तमान वर्कस्पेस के बाहर फाइलें बनाने और संपादित करने की अनुमति दें।"
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "ब्राउज़र क्रियाएँ हमेशा अनुमोदित करें",
 			"label": "ब्राउज़र क्रियाएँ हमेशा अनुमोदित करें",

+ 10 - 2
webview-ui/src/i18n/locales/it/settings.json

@@ -35,12 +35,20 @@
 		"description": "Permetti a Roo di eseguire automaticamente operazioni senza richiedere approvazione. Abilita queste impostazioni solo se ti fidi completamente dell'IA e comprendi i rischi di sicurezza associati.",
 		"description": "Permetti a Roo di eseguire automaticamente operazioni senza richiedere approvazione. Abilita queste impostazioni solo se ti fidi completamente dell'IA e comprendi i rischi di sicurezza associati.",
 		"readOnly": {
 		"readOnly": {
 			"label": "Approva sempre operazioni di sola lettura",
 			"label": "Approva sempre operazioni di sola lettura",
-			"description": "Quando abilitato, Roo visualizzerà automaticamente i contenuti della directory e leggerà i file senza richiedere di cliccare sul pulsante Approva."
+			"description": "Quando abilitato, Roo visualizzerà automaticamente i contenuti della directory e leggerà i file senza richiedere di cliccare sul pulsante Approva.",
+			"outsideWorkspace": {
+				"label": "Includi file al di fuori dell'area di lavoro",
+				"description": "Permetti a Roo di leggere file al di fuori dell'area di lavoro attuale senza richiedere approvazione."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "Approva sempre operazioni di scrittura",
 			"label": "Approva sempre operazioni di scrittura",
 			"description": "Crea e modifica automaticamente i file senza richiedere approvazione",
 			"description": "Crea e modifica automaticamente i file senza richiedere approvazione",
-			"delayLabel": "Ritardo dopo le scritture per consentire alla diagnostica di rilevare potenziali problemi"
+			"delayLabel": "Ritardo dopo le scritture per consentire alla diagnostica di rilevare potenziali problemi",
+			"outsideWorkspace": {
+				"label": "Includi file al di fuori dell'area di lavoro",
+				"description": "Permetti a Roo di creare e modificare file al di fuori dell'area di lavoro attuale senza richiedere approvazione."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "Approva sempre azioni del browser",
 			"label": "Approva sempre azioni del browser",

+ 10 - 2
webview-ui/src/i18n/locales/ja/settings.json

@@ -35,12 +35,20 @@
 		"description": "Rooが承認なしで自動的に操作を実行できるようにします。AIを完全に信頼し、関連するセキュリティリスクを理解している場合にのみ、これらの設定を有効にしてください。",
 		"description": "Rooが承認なしで自動的に操作を実行できるようにします。AIを完全に信頼し、関連するセキュリティリスクを理解している場合にのみ、これらの設定を有効にしてください。",
 		"readOnly": {
 		"readOnly": {
 			"label": "読み取り専用操作を常に承認",
 			"label": "読み取り専用操作を常に承認",
-			"description": "有効にすると、Rooは承認ボタンをクリックすることなく、自動的にディレクトリの内容を表示してファイルを読み取ります。"
+			"description": "有効にすると、Rooは承認ボタンをクリックすることなく、自動的にディレクトリの内容を表示してファイルを読み取ります。",
+			"outsideWorkspace": {
+				"label": "ワークスペース外のファイルを含める",
+				"description": "Rooが承認なしで現在のワークスペース外のファイルを読み取ることを許可します。"
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "書き込み操作を常に承認",
 			"label": "書き込み操作を常に承認",
 			"description": "承認なしで自動的にファイルを作成・編集",
 			"description": "承認なしで自動的にファイルを作成・編集",
-			"delayLabel": "診断が潜在的な問題を検出できるよう、書き込み後に遅延を設ける"
+			"delayLabel": "診断が潜在的な問題を検出できるよう、書き込み後に遅延を設ける",
+			"outsideWorkspace": {
+				"label": "ワークスペース外のファイルを含める",
+				"description": "Rooが承認なしで現在のワークスペース外のファイルを作成・編集することを許可します。"
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "ブラウザアクションを常に承認",
 			"label": "ブラウザアクションを常に承認",

+ 10 - 2
webview-ui/src/i18n/locales/ko/settings.json

@@ -35,12 +35,20 @@
 		"description": "Roo가 승인 없이 자동으로 작업을 수행할 수 있도록 허용합니다. AI를 완전히 신뢰하고 관련 보안 위험을 이해하는 경우에만 이러한 설정을 활성화하세요.",
 		"description": "Roo가 승인 없이 자동으로 작업을 수행할 수 있도록 허용합니다. AI를 완전히 신뢰하고 관련 보안 위험을 이해하는 경우에만 이러한 설정을 활성화하세요.",
 		"readOnly": {
 		"readOnly": {
 			"label": "읽기 전용 작업 항상 승인",
 			"label": "읽기 전용 작업 항상 승인",
-			"description": "활성화되면 Roo는 승인 버튼을 클릭하지 않고도 자동으로 디렉토리 내용을 보고 파일을 읽습니다."
+			"description": "활성화되면 Roo는 승인 버튼을 클릭하지 않고도 자동으로 디렉토리 내용을 보고 파일을 읽습니다.",
+			"outsideWorkspace": {
+				"label": "워크스페이스 외부 파일 포함",
+				"description": "Roo가 승인 없이 현재 워크스페이스 외부의 파일을 읽을 수 있도록 허용합니다."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "쓰기 작업 항상 승인",
 			"label": "쓰기 작업 항상 승인",
 			"description": "승인 없이 자동으로 파일 생성 및 편집",
 			"description": "승인 없이 자동으로 파일 생성 및 편집",
-			"delayLabel": "진단이 잠재적 문제를 감지할 수 있도록 쓰기 후 지연"
+			"delayLabel": "진단이 잠재적 문제를 감지할 수 있도록 쓰기 후 지연",
+			"outsideWorkspace": {
+				"label": "워크스페이스 외부 파일 포함",
+				"description": "Roo가 승인 없이 현재 워크스페이스 외부의 파일을 생성하고 편집할 수 있도록 허용합니다."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "브라우저 작업 항상 승인",
 			"label": "브라우저 작업 항상 승인",

+ 10 - 2
webview-ui/src/i18n/locales/pl/settings.json

@@ -35,12 +35,20 @@
 		"description": "Pozwól Roo na automatyczne wykonywanie operacji bez wymagania zatwierdzenia. Włącz te ustawienia tylko jeśli w pełni ufasz AI i rozumiesz związane z tym zagrożenia bezpieczeństwa.",
 		"description": "Pozwól Roo na automatyczne wykonywanie operacji bez wymagania zatwierdzenia. Włącz te ustawienia tylko jeśli w pełni ufasz AI i rozumiesz związane z tym zagrożenia bezpieczeństwa.",
 		"readOnly": {
 		"readOnly": {
 			"label": "Zawsze zatwierdzaj operacje tylko do odczytu",
 			"label": "Zawsze zatwierdzaj operacje tylko do odczytu",
-			"description": "Gdy włączone, Roo automatycznie będzie wyświetlać zawartość katalogów i czytać pliki bez konieczności klikania przycisku Zatwierdź."
+			"description": "Gdy włączone, Roo automatycznie będzie wyświetlać zawartość katalogów i czytać pliki bez konieczności klikania przycisku Zatwierdź.",
+			"outsideWorkspace": {
+				"label": "Uwzględnij pliki poza obszarem roboczym",
+				"description": "Pozwól Roo na odczyt plików poza bieżącym obszarem roboczym bez konieczności zatwierdzania."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "Zawsze zatwierdzaj operacje zapisu",
 			"label": "Zawsze zatwierdzaj operacje zapisu",
 			"description": "Automatycznie twórz i edytuj pliki bez konieczności zatwierdzania",
 			"description": "Automatycznie twórz i edytuj pliki bez konieczności zatwierdzania",
-			"delayLabel": "Opóźnienie po zapisach, aby umożliwić diagnostyce wykrycie potencjalnych problemów"
+			"delayLabel": "Opóźnienie po zapisach, aby umożliwić diagnostyce wykrycie potencjalnych problemów",
+			"outsideWorkspace": {
+				"label": "Uwzględnij pliki poza obszarem roboczym",
+				"description": "Pozwól Roo na tworzenie i edycję plików poza bieżącym obszarem roboczym bez konieczności zatwierdzania."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "Zawsze zatwierdzaj akcje przeglądarki",
 			"label": "Zawsze zatwierdzaj akcje przeglądarki",

+ 10 - 2
webview-ui/src/i18n/locales/pt-BR/settings.json

@@ -35,12 +35,20 @@
 		"description": "Permitir que o Roo realize operações automaticamente sem exigir aprovação. Ative essas configurações apenas se confiar totalmente na IA e compreender os riscos de segurança associados.",
 		"description": "Permitir que o Roo realize operações automaticamente sem exigir aprovação. Ative essas configurações apenas se confiar totalmente na IA e compreender os riscos de segurança associados.",
 		"readOnly": {
 		"readOnly": {
 			"label": "Aprovar sempre operações somente de leitura",
 			"label": "Aprovar sempre operações somente de leitura",
-			"description": "Quando ativado, o Roo visualizará automaticamente o conteúdo do diretório e lerá arquivos sem que você precise clicar no botão Aprovar."
+			"description": "Quando ativado, o Roo visualizará automaticamente o conteúdo do diretório e lerá arquivos sem que você precise clicar no botão Aprovar.",
+			"outsideWorkspace": {
+				"label": "Incluir arquivos fora do espaço de trabalho",
+				"description": "Permitir que o Roo leia arquivos fora do espaço de trabalho atual sem exigir aprovação."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "Aprovar sempre operações de escrita",
 			"label": "Aprovar sempre operações de escrita",
 			"description": "Criar e editar arquivos automaticamente sem exigir aprovação",
 			"description": "Criar e editar arquivos automaticamente sem exigir aprovação",
-			"delayLabel": "Atraso após escritas para permitir que diagnósticos detectem problemas potenciais"
+			"delayLabel": "Atraso após escritas para permitir que diagnósticos detectem problemas potenciais",
+			"outsideWorkspace": {
+				"label": "Incluir arquivos fora do espaço de trabalho",
+				"description": "Permitir que o Roo crie e edite arquivos fora do espaço de trabalho atual sem exigir aprovação."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "Aprovar sempre ações do navegador",
 			"label": "Aprovar sempre ações do navegador",

+ 10 - 2
webview-ui/src/i18n/locales/tr/settings.json

@@ -35,12 +35,20 @@
 		"description": "Roo'nun onay gerektirmeden otomatik olarak işlemler gerçekleştirmesine izin verin. Bu ayarları yalnızca yapay zekaya tamamen güveniyorsanız ve ilgili güvenlik risklerini anlıyorsanız etkinleştirin.",
 		"description": "Roo'nun onay gerektirmeden otomatik olarak işlemler gerçekleştirmesine izin verin. Bu ayarları yalnızca yapay zekaya tamamen güveniyorsanız ve ilgili güvenlik risklerini anlıyorsanız etkinleştirin.",
 		"readOnly": {
 		"readOnly": {
 			"label": "Salt okunur işlemleri her zaman onayla",
 			"label": "Salt okunur işlemleri her zaman onayla",
-			"description": "Etkinleştirildiğinde, Roo otomatik olarak dizin içeriğini görüntüleyecek ve Onayla düğmesine tıklamanıza gerek kalmadan dosyaları okuyacaktır."
+			"description": "Etkinleştirildiğinde, Roo otomatik olarak dizin içeriğini görüntüleyecek ve Onayla düğmesine tıklamanıza gerek kalmadan dosyaları okuyacaktır.",
+			"outsideWorkspace": {
+				"label": "Çalışma alanı dışındaki dosyaları dahil et",
+				"description": "Roo'nun onay gerektirmeden mevcut çalışma alanı dışındaki dosyaları okumasına izin ver."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "Yazma işlemlerini her zaman onayla",
 			"label": "Yazma işlemlerini her zaman onayla",
 			"description": "Onay gerektirmeden otomatik olarak dosya oluştur ve düzenle",
 			"description": "Onay gerektirmeden otomatik olarak dosya oluştur ve düzenle",
-			"delayLabel": "Tanılamanın potansiyel sorunları tespit etmesine izin vermek için yazmalardan sonra gecikme"
+			"delayLabel": "Tanılamanın potansiyel sorunları tespit etmesine izin vermek için yazmalardan sonra gecikme",
+			"outsideWorkspace": {
+				"label": "Çalışma alanı dışındaki dosyaları dahil et",
+				"description": "Roo'nun onay gerektirmeden mevcut çalışma alanı dışında dosya oluşturmasına ve düzenlemesine izin ver."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "Tarayıcı eylemlerini her zaman onayla",
 			"label": "Tarayıcı eylemlerini her zaman onayla",

+ 10 - 2
webview-ui/src/i18n/locales/vi/settings.json

@@ -35,12 +35,20 @@
 		"description": "Cho phép Roo tự động thực hiện các hoạt động mà không cần phê duyệt. Chỉ bật những cài đặt này nếu bạn hoàn toàn tin tưởng AI và hiểu rõ các rủi ro bảo mật liên quan.",
 		"description": "Cho phép Roo tự động thực hiện các hoạt động mà không cần phê duyệt. Chỉ bật những cài đặt này nếu bạn hoàn toàn tin tưởng AI và hiểu rõ các rủi ro bảo mật liên quan.",
 		"readOnly": {
 		"readOnly": {
 			"label": "Luôn phê duyệt các hoạt động chỉ đọc",
 			"label": "Luôn phê duyệt các hoạt động chỉ đọc",
-			"description": "Khi được bật, Roo sẽ tự động xem nội dung thư mục và đọc tệp mà không yêu cầu bạn nhấp vào nút Phê duyệt."
+			"description": "Khi được bật, Roo sẽ tự động xem nội dung thư mục và đọc tệp mà không yêu cầu bạn nhấp vào nút Phê duyệt.",
+			"outsideWorkspace": {
+				"label": "Bao gồm các tệp ngoài không gian làm việc",
+				"description": "Cho phép Roo đọc các tệp bên ngoài không gian làm việc hiện tại mà không yêu cầu phê duyệt."
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "Luôn phê duyệt các hoạt động ghi",
 			"label": "Luôn phê duyệt các hoạt động ghi",
 			"description": "Tự động tạo và chỉnh sửa tệp mà không cần phê duyệt",
 			"description": "Tự động tạo và chỉnh sửa tệp mà không cần phê duyệt",
-			"delayLabel": "Trì hoãn sau khi ghi để cho phép chẩn đoán phát hiện các vấn đề tiềm ẩn"
+			"delayLabel": "Trì hoãn sau khi ghi để cho phép chẩn đoán phát hiện các vấn đề tiềm ẩn",
+			"outsideWorkspace": {
+				"label": "Bao gồm các tệp ngoài không gian làm việc",
+				"description": "Cho phép Roo tạo và chỉnh sửa các tệp bên ngoài không gian làm việc hiện tại mà không yêu cầu phê duyệt."
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "Luôn phê duyệt các hành động trình duyệt",
 			"label": "Luôn phê duyệt các hành động trình duyệt",

+ 10 - 2
webview-ui/src/i18n/locales/zh-CN/settings.json

@@ -35,12 +35,20 @@
 		"description": "允许 Roo 自动执行操作而无需批准。只有在您完全信任 AI 并了解相关安全风险的情况下才启用这些设置。",
 		"description": "允许 Roo 自动执行操作而无需批准。只有在您完全信任 AI 并了解相关安全风险的情况下才启用这些设置。",
 		"readOnly": {
 		"readOnly": {
 			"label": "始终批准只读操作",
 			"label": "始终批准只读操作",
-			"description": "启用后,Roo 将自动查看目录内容并读取文件,无需点击批准按钮。"
+			"description": "启用后,Roo 将自动查看目录内容并读取文件,无需点击批准按钮。",
+			"outsideWorkspace": {
+				"label": "包含工作区外的文件",
+				"description": "允许 Roo 读取当前工作区外的文件,无需批准。"
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "始终批准写入操作",
 			"label": "始终批准写入操作",
 			"description": "自动创建和编辑文件而无需批准",
 			"description": "自动创建和编辑文件而无需批准",
-			"delayLabel": "写入后延迟以允许诊断检测潜在问题"
+			"delayLabel": "写入后延迟以允许诊断检测潜在问题",
+			"outsideWorkspace": {
+				"label": "包含工作区外的文件",
+				"description": "允许 Roo 创建和编辑当前工作区外的文件,无需批准。"
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "始终批准浏览器操作",
 			"label": "始终批准浏览器操作",

+ 10 - 2
webview-ui/src/i18n/locales/zh-TW/settings.json

@@ -35,12 +35,20 @@
 		"description": "允許 Roo 無需批准即執行操作。僅在您完全信任 AI 並了解相關安全風險時啟用這些設定。",
 		"description": "允許 Roo 無需批准即執行操作。僅在您完全信任 AI 並了解相關安全風險時啟用這些設定。",
 		"readOnly": {
 		"readOnly": {
 			"label": "始終批准只讀操作",
 			"label": "始終批准只讀操作",
-			"description": "啟用後,Roo 將自動查看目錄內容和讀取文件,無需點擊批准按鈕。"
+			"description": "啟用後,Roo 將自動查看目錄內容和讀取文件,無需點擊批准按鈕。",
+			"outsideWorkspace": {
+				"label": "包含工作區外的檔案",
+				"description": "允許 Roo 讀取當前工作區外的檔案,無需批准。"
+			}
 		},
 		},
 		"write": {
 		"write": {
 			"label": "始終批准寫入操作",
 			"label": "始終批准寫入操作",
 			"description": "自動建立和編輯文件而無需批准",
 			"description": "自動建立和編輯文件而無需批准",
-			"delayLabel": "寫入後延遲以允許診斷檢測潛在問題"
+			"delayLabel": "寫入後延遲以允許診斷檢測潛在問題",
+			"outsideWorkspace": {
+				"label": "包含工作區外的檔案",
+				"description": "允許 Roo 在當前工作區外建立和編輯檔案,無需批准。"
+			}
 		},
 		},
 		"browser": {
 		"browser": {
 			"label": "始終批准瀏覽器操作",
 			"label": "始終批准瀏覽器操作",