Browse Source

Fix linter warning + run prettier on everything (#3581)

Chris Estreich 7 tháng trước cách đây
mục cha
commit
cd07b7faeb

+ 7 - 10
e2e/.vscode-test.mjs

@@ -2,18 +2,15 @@
  * See: https://code.visualstudio.com/api/working-with-extensions/testing-extension
  */
 
-import { defineConfig } from '@vscode/test-cli';
+import { defineConfig } from "@vscode/test-cli"
 
 export default defineConfig({
-	label: 'integrationTest',
-	files: 'out/suite/**/*.test.js',
-	workspaceFolder: '.',
+	label: "integrationTest",
+	files: "out/suite/**/*.test.js",
+	workspaceFolder: ".",
 	mocha: {
-		ui: 'tdd',
+		ui: "tdd",
 		timeout: 60000,
 	},
-	launchArgs: [
-		'--enable-proposed-api=RooVeterinaryInc.roo-cline',
-		'--disable-extensions'
-	]
-});
+	launchArgs: ["--enable-proposed-api=RooVeterinaryInc.roo-cline", "--disable-extensions"],
+})

+ 1 - 1
e2e/package.json

@@ -3,7 +3,7 @@
 	"version": "0.1.0",
 	"private": true,
 	"scripts": {
-		"lint": "eslint src/**/*.ts",
+		"lint": "eslint src/**/*.ts --max-warnings=0",
 		"check-types": "tsc --noEmit",
 		"test": "npm run build && npx dotenvx run -f .env.local -- node ./out/runTest.js",
 		"ci": "npm run vscode-test && npm run test",

+ 1 - 1
evals/.tool-versions

@@ -1,4 +1,4 @@
 python 3.13.2
 golang 1.24.2
-rust 1.86.0
+rust 1.85.1
 nodejs 20.18.1

+ 29 - 29
package.nls.nl.json

@@ -1,31 +1,31 @@
 {
-  "extension.displayName": "Roo Code (voorheen Roo Cline)",
-  "extension.description": "Een compleet ontwikkelteam van AI-agents in je editor.",
-  "views.contextMenu.label": "Roo Code",
-  "views.terminalMenu.label": "Roo Code",
-  "views.activitybar.title": "Roo Code",
-  "command.newTask.title": "Nieuwe Taak",
-  "command.mcpServers.title": "MCP Servers",
-  "command.prompts.title": "Prompts",
-  "command.history.title": "Geschiedenis",
-  "command.openInEditor.title": "Openen in Editor",
-  "command.settings.title": "Instellingen",
-  "command.documentation.title": "Documentatie",
-  "command.openInNewTab.title": "Openen in Nieuw Tabblad",
-  "command.explainCode.title": "Leg Code Uit",
-  "command.fixCode.title": "Repareer Code",
-  "command.improveCode.title": "Verbeter Code",
-  "command.addToContext.title": "Toevoegen aan Context",
-  "command.focusInput.title": "Focus op Invoerveld",
-  "command.setCustomStoragePath.title": "Aangepast Opslagpad Instellen",
-  "command.terminal.addToContext.title": "Terminalinhoud aan Context Toevoegen",
-  "command.terminal.fixCommand.title": "Repareer Dit Commando",
-  "command.terminal.explainCommand.title": "Leg Dit Commando Uit",
-  "command.acceptInput.title": "Invoer/Suggestie Accepteren",
-  "configuration.title": "Roo Code",
-  "commands.allowedCommands.description": "Commando's die automatisch kunnen worden uitgevoerd wanneer 'Altijd goedkeuren uitvoerbewerkingen' is ingeschakeld",
-  "settings.vsCodeLmModelSelector.description": "Instellingen voor VSCode Language Model API",
-  "settings.vsCodeLmModelSelector.vendor.description": "De leverancier van het taalmodel (bijv. copilot)",
-  "settings.vsCodeLmModelSelector.family.description": "De familie van het taalmodel (bijv. gpt-4)",
-  "settings.customStoragePath.description": "Aangepast opslagpad. Laat leeg om de standaardlocatie te gebruiken. Ondersteunt absolute paden (bijv. 'D:\\RooCodeStorage')"
+	"extension.displayName": "Roo Code (voorheen Roo Cline)",
+	"extension.description": "Een compleet ontwikkelteam van AI-agents in je editor.",
+	"views.contextMenu.label": "Roo Code",
+	"views.terminalMenu.label": "Roo Code",
+	"views.activitybar.title": "Roo Code",
+	"command.newTask.title": "Nieuwe Taak",
+	"command.mcpServers.title": "MCP Servers",
+	"command.prompts.title": "Prompts",
+	"command.history.title": "Geschiedenis",
+	"command.openInEditor.title": "Openen in Editor",
+	"command.settings.title": "Instellingen",
+	"command.documentation.title": "Documentatie",
+	"command.openInNewTab.title": "Openen in Nieuw Tabblad",
+	"command.explainCode.title": "Leg Code Uit",
+	"command.fixCode.title": "Repareer Code",
+	"command.improveCode.title": "Verbeter Code",
+	"command.addToContext.title": "Toevoegen aan Context",
+	"command.focusInput.title": "Focus op Invoerveld",
+	"command.setCustomStoragePath.title": "Aangepast Opslagpad Instellen",
+	"command.terminal.addToContext.title": "Terminalinhoud aan Context Toevoegen",
+	"command.terminal.fixCommand.title": "Repareer Dit Commando",
+	"command.terminal.explainCommand.title": "Leg Dit Commando Uit",
+	"command.acceptInput.title": "Invoer/Suggestie Accepteren",
+	"configuration.title": "Roo Code",
+	"commands.allowedCommands.description": "Commando's die automatisch kunnen worden uitgevoerd wanneer 'Altijd goedkeuren uitvoerbewerkingen' is ingeschakeld",
+	"settings.vsCodeLmModelSelector.description": "Instellingen voor VSCode Language Model API",
+	"settings.vsCodeLmModelSelector.vendor.description": "De leverancier van het taalmodel (bijv. copilot)",
+	"settings.vsCodeLmModelSelector.family.description": "De familie van het taalmodel (bijv. gpt-4)",
+	"settings.customStoragePath.description": "Aangepast opslagpad. Laat leeg om de standaardlocatie te gebruiken. Ondersteunt absolute paden (bijv. 'D:\\RooCodeStorage')"
 }

+ 3 - 2
scripts/generate-types.mts

@@ -21,12 +21,13 @@ async function main() {
 	fs.writeFileSync("src/exports/types.ts", types.join("\n\n"))
 
 	await $`npx tsup src/exports/interface.ts --dts-only -d out`
-	fs.writeFileSync("out/interface.d.ts", "src/exports/roo-code.d.ts")
+	fs.copyFileSync("out/interface.d.ts", "src/exports/roo-code.d.ts")
 
 	await $`npx prettier --write src/exports/types.ts src/exports/roo-code.d.ts`
 
 	if (fs.existsSync(path.join("..", "Roo-Code-Types"))) {
-		fs.copyFileSync("src/exports/roo-code.d.ts", path.join("..", "Roo-Code-Types", "index.d.ts"))
+		fs.copyFileSync("out/interface.js", path.join("..", "Roo-Code-Types", "src", "index.js"))
+		fs.copyFileSync("out/interface.d.ts", path.join("..", "Roo-Code-Types", "src", "index.d.ts"))
 	}
 }
 

+ 91 - 91
src/i18n/locales/nl/common.json

@@ -1,93 +1,93 @@
 {
-  "extension": {
-    "name": "Roo Code",
-    "description": "Een compleet ontwikkelteam van AI-agenten in je editor."
-  },
-  "number_format": {
-    "thousand_suffix": "k",
-    "million_suffix": "m",
-    "billion_suffix": "mrd"
-  },
-  "welcome": "Welkom, {{name}}! Je hebt {{count}} meldingen.",
-  "items": {
-    "zero": "Geen items",
-    "one": "Eén item",
-    "other": "{{count}} items"
-  },
-  "confirmation": {
-    "reset_state": "Weet je zeker dat je alle status en geheime opslag in de extensie wilt resetten? Dit kan niet ongedaan worden gemaakt.",
-    "delete_config_profile": "Weet je zeker dat je dit configuratieprofiel wilt verwijderen?",
-    "delete_custom_mode": "Weet je zeker dat je deze aangepaste modus wilt verwijderen?",
-    "delete_message": "Wat wil je verwijderen?",
-    "just_this_message": "Alleen dit bericht",
-    "this_and_subsequent": "Dit en alle volgende berichten"
-  },
-  "errors": {
-    "invalid_mcp_config": "Ongeldig project MCP-configuratieformaat",
-    "invalid_mcp_settings_format": "Ongeldig MCP-instellingen JSON-formaat. Zorg ervoor dat je instellingen het juiste JSON-formaat volgen.",
-    "invalid_mcp_settings_syntax": "Ongeldig MCP-instellingen JSON-formaat. Controleer je instellingenbestand op syntaxfouten.",
-    "invalid_mcp_settings_validation": "Ongeldig MCP-instellingenformaat: {{errorMessages}}",
-    "failed_initialize_project_mcp": "Initialiseren van project MCP-server mislukt: {{error}}",
-    "invalid_data_uri": "Ongeldig data-URI-formaat",
-    "checkpoint_timeout": "Time-out bij het herstellen van checkpoint.",
-    "checkpoint_failed": "Herstellen van checkpoint mislukt.",
-    "no_workspace": "Open eerst een projectmap",
-    "update_support_prompt": "Bijwerken van ondersteuningsprompt mislukt",
-    "reset_support_prompt": "Resetten van ondersteuningsprompt mislukt",
-    "enhance_prompt": "Verbeteren van prompt mislukt",
-    "get_system_prompt": "Ophalen van systeemprompt mislukt",
-    "search_commits": "Zoeken naar commits mislukt",
-    "save_api_config": "Opslaan van API-configuratie mislukt",
-    "create_api_config": "Aanmaken van API-configuratie mislukt",
-    "rename_api_config": "Hernoemen van API-configuratie mislukt",
-    "load_api_config": "Laden van API-configuratie mislukt",
-    "delete_api_config": "Verwijderen van API-configuratie mislukt",
-    "list_api_config": "Ophalen van lijst met API-configuraties mislukt",
-    "update_server_timeout": "Bijwerken van server-timeout mislukt",
-    "create_mcp_json": "Aanmaken of openen van .roo/mcp.json mislukt: {{error}}",
-    "hmr_not_running": "Lokale ontwikkelserver draait niet, HMR werkt niet. Voer 'npm run dev' uit voordat je de extensie start om HMR in te schakelen.",
-    "retrieve_current_mode": "Fout: ophalen van huidige modus uit status mislukt.",
-    "failed_delete_repo": "Verwijderen van gekoppelde schaduwrepository of branch mislukt: {{error}}",
-    "failed_remove_directory": "Verwijderen van taakmap mislukt: {{error}}",
-    "custom_storage_path_unusable": "Aangepast opslagpad \"{{path}}\" is onbruikbaar, standaardpad wordt gebruikt",
-    "cannot_access_path": "Kan pad {{path}} niet openen: {{error}}",
-    "failed_update_project_mcp": "Bijwerken van project MCP-servers mislukt"
-  },
-  "warnings": {
-    "no_terminal_content": "Geen terminalinhoud geselecteerd",
-    "missing_task_files": "De bestanden van deze taak ontbreken. Wil je deze uit de takenlijst verwijderen?"
-  },
-  "info": {
-    "no_changes": "Geen wijzigingen gevonden.",
-    "clipboard_copy": "Systeemprompt succesvol gekopieerd naar klembord",
-    "history_cleanup": "{{count}} taak/taken met ontbrekende bestanden uit geschiedenis verwijderd.",
-    "mcp_server_restarting": "{{serverName}} MCP-server wordt opnieuw gestart...",
-    "mcp_server_connected": "{{serverName}} MCP-server verbonden",
-    "mcp_server_deleted": "MCP-server verwijderd: {{serverName}}",
-    "mcp_server_not_found": "Server \"{{serverName}}\" niet gevonden in configuratie",
-    "custom_storage_path_set": "Aangepast opslagpad ingesteld: {{path}}",
-    "default_storage_path": "Terug naar standaard opslagpad",
-    "settings_imported": "Instellingen succesvol geïmporteerd."
-  },
-  "answers": {
-    "yes": "Ja",
-    "no": "Nee",
-    "cancel": "Annuleren",
-    "remove": "Verwijderen",
-    "keep": "Behouden"
-  },
-  "tasks": {
-    "canceled": "Taakfout: gestopt en geannuleerd door gebruiker.",
-    "deleted": "Taakfout: gestopt en verwijderd door gebruiker."
-  },
-  "storage": {
-    "prompt_custom_path": "Voer een aangepast opslagpad voor gespreksgeschiedenis in, laat leeg voor standaardlocatie",
-    "path_placeholder": "D:\\RooCodeStorage",
-    "enter_absolute_path": "Voer een absoluut pad in (bijv. D:\\RooCodeStorage of /home/user/storage)",
-    "enter_valid_path": "Voer een geldig pad in"
-  },
-  "input": {
-    "task_prompt": "Wat moet Roo doen?",
-    "task_placeholder": "Typ hier je taak"
-  }
+	"extension": {
+		"name": "Roo Code",
+		"description": "Een compleet ontwikkelteam van AI-agenten in je editor."
+	},
+	"number_format": {
+		"thousand_suffix": "k",
+		"million_suffix": "m",
+		"billion_suffix": "mrd"
+	},
+	"welcome": "Welkom, {{name}}! Je hebt {{count}} meldingen.",
+	"items": {
+		"zero": "Geen items",
+		"one": "Eén item",
+		"other": "{{count}} items"
+	},
+	"confirmation": {
+		"reset_state": "Weet je zeker dat je alle status en geheime opslag in de extensie wilt resetten? Dit kan niet ongedaan worden gemaakt.",
+		"delete_config_profile": "Weet je zeker dat je dit configuratieprofiel wilt verwijderen?",
+		"delete_custom_mode": "Weet je zeker dat je deze aangepaste modus wilt verwijderen?",
+		"delete_message": "Wat wil je verwijderen?",
+		"just_this_message": "Alleen dit bericht",
+		"this_and_subsequent": "Dit en alle volgende berichten"
+	},
+	"errors": {
+		"invalid_mcp_config": "Ongeldig project MCP-configuratieformaat",
+		"invalid_mcp_settings_format": "Ongeldig MCP-instellingen JSON-formaat. Zorg ervoor dat je instellingen het juiste JSON-formaat volgen.",
+		"invalid_mcp_settings_syntax": "Ongeldig MCP-instellingen JSON-formaat. Controleer je instellingenbestand op syntaxfouten.",
+		"invalid_mcp_settings_validation": "Ongeldig MCP-instellingenformaat: {{errorMessages}}",
+		"failed_initialize_project_mcp": "Initialiseren van project MCP-server mislukt: {{error}}",
+		"invalid_data_uri": "Ongeldig data-URI-formaat",
+		"checkpoint_timeout": "Time-out bij het herstellen van checkpoint.",
+		"checkpoint_failed": "Herstellen van checkpoint mislukt.",
+		"no_workspace": "Open eerst een projectmap",
+		"update_support_prompt": "Bijwerken van ondersteuningsprompt mislukt",
+		"reset_support_prompt": "Resetten van ondersteuningsprompt mislukt",
+		"enhance_prompt": "Verbeteren van prompt mislukt",
+		"get_system_prompt": "Ophalen van systeemprompt mislukt",
+		"search_commits": "Zoeken naar commits mislukt",
+		"save_api_config": "Opslaan van API-configuratie mislukt",
+		"create_api_config": "Aanmaken van API-configuratie mislukt",
+		"rename_api_config": "Hernoemen van API-configuratie mislukt",
+		"load_api_config": "Laden van API-configuratie mislukt",
+		"delete_api_config": "Verwijderen van API-configuratie mislukt",
+		"list_api_config": "Ophalen van lijst met API-configuraties mislukt",
+		"update_server_timeout": "Bijwerken van server-timeout mislukt",
+		"create_mcp_json": "Aanmaken of openen van .roo/mcp.json mislukt: {{error}}",
+		"hmr_not_running": "Lokale ontwikkelserver draait niet, HMR werkt niet. Voer 'npm run dev' uit voordat je de extensie start om HMR in te schakelen.",
+		"retrieve_current_mode": "Fout: ophalen van huidige modus uit status mislukt.",
+		"failed_delete_repo": "Verwijderen van gekoppelde schaduwrepository of branch mislukt: {{error}}",
+		"failed_remove_directory": "Verwijderen van taakmap mislukt: {{error}}",
+		"custom_storage_path_unusable": "Aangepast opslagpad \"{{path}}\" is onbruikbaar, standaardpad wordt gebruikt",
+		"cannot_access_path": "Kan pad {{path}} niet openen: {{error}}",
+		"failed_update_project_mcp": "Bijwerken van project MCP-servers mislukt"
+	},
+	"warnings": {
+		"no_terminal_content": "Geen terminalinhoud geselecteerd",
+		"missing_task_files": "De bestanden van deze taak ontbreken. Wil je deze uit de takenlijst verwijderen?"
+	},
+	"info": {
+		"no_changes": "Geen wijzigingen gevonden.",
+		"clipboard_copy": "Systeemprompt succesvol gekopieerd naar klembord",
+		"history_cleanup": "{{count}} taak/taken met ontbrekende bestanden uit geschiedenis verwijderd.",
+		"mcp_server_restarting": "{{serverName}} MCP-server wordt opnieuw gestart...",
+		"mcp_server_connected": "{{serverName}} MCP-server verbonden",
+		"mcp_server_deleted": "MCP-server verwijderd: {{serverName}}",
+		"mcp_server_not_found": "Server \"{{serverName}}\" niet gevonden in configuratie",
+		"custom_storage_path_set": "Aangepast opslagpad ingesteld: {{path}}",
+		"default_storage_path": "Terug naar standaard opslagpad",
+		"settings_imported": "Instellingen succesvol geïmporteerd."
+	},
+	"answers": {
+		"yes": "Ja",
+		"no": "Nee",
+		"cancel": "Annuleren",
+		"remove": "Verwijderen",
+		"keep": "Behouden"
+	},
+	"tasks": {
+		"canceled": "Taakfout: gestopt en geannuleerd door gebruiker.",
+		"deleted": "Taakfout: gestopt en verwijderd door gebruiker."
+	},
+	"storage": {
+		"prompt_custom_path": "Voer een aangepast opslagpad voor gespreksgeschiedenis in, laat leeg voor standaardlocatie",
+		"path_placeholder": "D:\\RooCodeStorage",
+		"enter_absolute_path": "Voer een absoluut pad in (bijv. D:\\RooCodeStorage of /home/user/storage)",
+		"enter_valid_path": "Voer een geldig pad in"
+	},
+	"input": {
+		"task_prompt": "Wat moet Roo doen?",
+		"task_placeholder": "Typ hier je taak"
+	}
 }

+ 11 - 11
webview-ui/index.html

@@ -1,12 +1,12 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Roo Code</title>
-  </head>
-  <body>
-    <div id="root"></div>
-    <script type="module" src="/src/index.tsx"></script>
-  </body>
-</html>
+	<head>
+		<meta charset="UTF-8" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<title>Roo Code</title>
+	</head>
+	<body>
+		<div id="root"></div>
+		<script type="module" src="/src/index.tsx"></script>
+	</body>
+</html>

+ 3 - 3
webview-ui/jest.config.cjs

@@ -12,14 +12,14 @@ module.exports = {
 		"^vscrui$": "<rootDir>/src/__mocks__/vscrui.ts",
 		"^@vscode/webview-ui-toolkit/react$": "<rootDir>/src/__mocks__/@vscode/webview-ui-toolkit/react.ts",
 		"^@/(.*)$": "<rootDir>/src/$1",
-		'^@roo/(.*)$': '<rootDir>/../src/$1',
-		'^@src/(.*)$': '<rootDir>/src/$1',		
+		"^@roo/(.*)$": "<rootDir>/../src/$1",
+		"^@src/(.*)$": "<rootDir>/src/$1",
 		"^src/i18n/setup$": "<rootDir>/src/__mocks__/i18n/setup.ts",
 		"^\\.\\./setup$": "<rootDir>/src/__mocks__/i18n/setup.ts",
 		"^\\./setup$": "<rootDir>/src/__mocks__/i18n/setup.ts",
 		"^src/i18n/TranslationContext$": "<rootDir>/src/__mocks__/i18n/TranslationContext.tsx",
 		"^\\.\\./TranslationContext$": "<rootDir>/src/__mocks__/i18n/TranslationContext.tsx",
-		"^\\./TranslationContext$": "<rootDir>/src/__mocks__/i18n/TranslationContext.tsx"
+		"^\\./TranslationContext$": "<rootDir>/src/__mocks__/i18n/TranslationContext.tsx",
 	},
 	reporters: [["jest-simple-dot-reporter", {}]],
 	transformIgnorePatterns: [

+ 1 - 1
webview-ui/package.json

@@ -4,7 +4,7 @@
 	"private": true,
 	"type": "module",
 	"scripts": {
-		"lint": "eslint src --ext .ts,.tsx",
+		"lint": "eslint src --ext .ts,.tsx --max-warnings=0",
 		"check-types": "tsc",
 		"test": "jest -w=40%",
 		"dev": "vite",

+ 0 - 158
webview-ui/src/__tests__/utils/command-validation.test.ts

@@ -1,158 +0,0 @@
-import { parseCommand, validateCommand } from "../../utils/command-validation"
-
-/**
- * Tests for the command-validation module
- *
- * These tests include a reproduction of a bug where the shell-quote library
- * used in parseCommand throws an error when parsing commands that contain
- * the Bash $RANDOM variable in array indexing expressions.
- *
- * Error: "Bad substitution: levels[$RANDOM"
- *
- * The issue occurs specifically with complex expressions like:
- * ${levels[$RANDOM % ${#levels[@]}]}
- */
-describe("command-validation", () => {
-	describe("parseCommand", () => {
-		it("should correctly parse simple commands", () => {
-			const result = parseCommand("echo hello")
-			expect(result).toEqual(["echo hello"])
-		})
-
-		it("should correctly parse commands with chaining operators", () => {
-			const result = parseCommand("echo hello && echo world")
-			expect(result).toEqual(["echo hello", "echo world"])
-		})
-
-		it("should correctly parse commands with quotes", () => {
-			const result = parseCommand('echo "hello world"')
-			expect(result).toEqual(['echo "hello world"'])
-		})
-
-		it("should correctly parse commands with redirections", () => {
-			const result = parseCommand("echo hello 2>&1")
-			expect(result).toEqual(["echo hello 2>&1"])
-		})
-
-		it("should correctly parse commands with subshells", () => {
-			const result = parseCommand("echo $(date)")
-			expect(result).toEqual(["echo", "date"])
-		})
-
-		it("should not throw an error when parsing commands with simple array indexing", () => {
-			// Simple array indexing works fine
-			const commandWithArrayIndex = "value=${array[$index]}"
-
-			expect(() => {
-				parseCommand(commandWithArrayIndex)
-			}).not.toThrow()
-		})
-
-		it("should not throw an error when parsing commands with $RANDOM in array index", () => {
-			// This test reproduces the specific bug reported in the error
-			const commandWithRandom = "level=${levels[$RANDOM % ${#levels[@]}]}"
-
-			expect(() => {
-				parseCommand(commandWithRandom)
-			}).not.toThrow()
-		})
-
-		it("should not throw an error with simple $RANDOM variable", () => {
-			// Simple $RANDOM usage works fine
-			const commandWithRandom = "echo $RANDOM"
-
-			expect(() => {
-				parseCommand(commandWithRandom)
-			}).not.toThrow()
-		})
-
-		it("should not throw an error with simple array indexing using $RANDOM", () => {
-			// Simple array indexing with $RANDOM works fine
-			const commandWithRandomIndex = "echo ${array[$RANDOM]}"
-
-			expect(() => {
-				parseCommand(commandWithRandomIndex)
-			}).not.toThrow()
-		})
-
-		it("should not throw an error with complex array indexing using $RANDOM and arithmetic", () => {
-			// This test reproduces the exact expression from the original error
-			const commandWithComplexRandom = "echo ${levels[$RANDOM % ${#levels[@]}]}"
-
-			expect(() => {
-				parseCommand(commandWithComplexRandom)
-			}).not.toThrow("Bad substitution")
-		})
-
-		it("should not throw an error when parsing the full log generator command", () => {
-			// This is the exact command from the original error message
-			const logGeneratorCommand = `while true; do \\
-  levels=(INFO WARN ERROR DEBUG); \\
-  msgs=("User logged in" "Connection timeout" "Processing request" "Cache miss" "Database query"); \\
-  level=\${levels[$RANDOM % \${#levels[@]}]}; \\
-  msg=\${msgs[$RANDOM % \${#msgs[@]}]}; \\
-  echo "\$(date '+%Y-%m-%d %H:%M:%S') [$level] $msg"; \\
-  sleep 1; \\
-done`
-
-			// This reproduces the original error
-			expect(() => {
-				parseCommand(logGeneratorCommand)
-			}).not.toThrow("Bad substitution: levels[$RANDOM")
-		})
-
-		it("should not throw an error when parsing just the problematic part", () => {
-			// This isolates just the part mentioned in the error message
-			const problematicPart = "level=${levels[$RANDOM"
-
-			expect(() => {
-				parseCommand(problematicPart)
-			}).not.toThrow("Bad substitution")
-		})
-	})
-
-	describe("validateCommand", () => {
-		it("should validate allowed commands", () => {
-			const result = validateCommand("echo hello", ["echo"])
-			expect(result).toBe(true)
-		})
-
-		it("should reject disallowed commands", () => {
-			const result = validateCommand("rm -rf /", ["echo", "ls"])
-			expect(result).toBe(false)
-		})
-
-		it("should not fail validation for commands with simple $RANDOM variable", () => {
-			const commandWithRandom = "echo $RANDOM"
-
-			expect(() => {
-				validateCommand(commandWithRandom, ["echo"])
-			}).not.toThrow()
-		})
-
-		it("should not fail validation for commands with simple array indexing using $RANDOM", () => {
-			const commandWithRandomIndex = "echo ${array[$RANDOM]}"
-
-			expect(() => {
-				validateCommand(commandWithRandomIndex, ["echo"])
-			}).not.toThrow()
-		})
-
-		it("should return false for the full log generator command due to subshell detection", () => {
-			// This is the exact command from the original error message
-			const logGeneratorCommand = `while true; do \\
-  levels=(INFO WARN ERROR DEBUG); \\
-  msgs=("User logged in" "Connection timeout" "Processing request" "Cache miss" "Database query"); \\
-  level=\${levels[$RANDOM % \${#levels[@]}]}; \\
-  msg=\${msgs[$RANDOM % \${#msgs[@]}]}; \\
-  echo "\$(date '+%Y-%m-%d %H:%M:%S') [$level] $msg"; \\
-  sleep 1; \\
-done`
-
-			// validateCommand should return false due to subshell detection
-			// without throwing an error
-			const result = validateCommand(logGeneratorCommand, ["while"])
-			expect(result).toBe(false)
-		})
-	})
-})

+ 2 - 1
webview-ui/src/components/settings/ModelInfoView.tsx

@@ -73,7 +73,8 @@ export const ModelInfoView = ({
 		),
 		apiProvider === "gemini" && (
 			<span className="italic">
-				{(selectedModelId === "gemini-2.5-pro-preview-03-25" || selectedModelId === "gemini-2.5-pro-preview-05-06")
+				{selectedModelId === "gemini-2.5-pro-preview-03-25" ||
+				selectedModelId === "gemini-2.5-pro-preview-05-06"
 					? t("settings:modelInfo.gemini.billingEstimate")
 					: t("settings:modelInfo.gemini.freeRequests", {
 							count: selectedModelId && selectedModelId.includes("flash") ? 15 : 2,

+ 249 - 249
webview-ui/src/i18n/locales/nl/chat.json

@@ -1,251 +1,251 @@
 {
-  "greeting": "Welkom bij Roo Code",
-  "task": {
-    "title": "Taak",
-    "seeMore": "Meer weergeven",
-    "seeLess": "Minder weergeven",
-    "tokens": "Tokens:",
-    "cache": "Cache:",
-    "apiCost": "API-kosten:",
-    "contextWindow": "Contextlengte:",
-    "closeAndStart": "Taak sluiten en een nieuwe starten",
-    "export": "Taakgeschiedenis exporteren",
-    "delete": "Taak verwijderen (Shift + Klik om bevestiging over te slaan)"
-  },
-  "unpin": "Losmaken",
-  "pin": "Vastmaken",
-  "retry": {
-    "title": "Opnieuw proberen",
-    "tooltip": "Probeer de bewerking opnieuw"
-  },
-  "startNewTask": {
-    "title": "Nieuwe taak starten",
-    "tooltip": "Begin een nieuwe taak"
-  },
-  "proceedAnyways": {
-    "title": "Toch doorgaan",
-    "tooltip": "Ga door terwijl het commando wordt uitgevoerd"
-  },
-  "save": {
-    "title": "Opslaan",
-    "tooltip": "Bestandswijzigingen opslaan"
-  },
-  "tokenProgress": {
-    "availableSpace": "Beschikbare ruimte: {{amount}} tokens",
-    "tokensUsed": "Gebruikte tokens: {{used}} van {{total}}",
-    "reservedForResponse": "Gereserveerd voor modelantwoord: {{amount}} tokens"
-  },
-  "reject": {
-    "title": "Weigeren",
-    "tooltip": "Deze actie weigeren"
-  },
-  "completeSubtaskAndReturn": "Subtaak voltooien en terugkeren",
-  "approve": {
-    "title": "Goedkeuren",
-    "tooltip": "Deze actie goedkeuren"
-  },
-  "runCommand": {
-    "title": "Commando uitvoeren",
-    "tooltip": "Voer dit commando uit"
-  },
-  "proceedWhileRunning": {
-    "title": "Doorgaan tijdens uitvoeren",
-    "tooltip": "Ga door ondanks waarschuwingen"
-  },
-  "killCommand": {
-    "title": "Commando stoppen",
-    "tooltip": "Huidig commando stoppen"
-  },
-  "resumeTask": {
-    "title": "Taak hervatten",
-    "tooltip": "Ga door met de huidige taak"
-  },
-  "terminate": {
-    "title": "Beëindigen",
-    "tooltip": "Beëindig de huidige taak"
-  },
-  "cancel": {
-    "title": "Annuleren",
-    "tooltip": "Annuleer de huidige bewerking"
-  },
-  "scrollToBottom": "Scroll naar onderaan de chat",
-  "about": "Genereer, refactor en debug code met AI-assistentie.<br />Bekijk onze <DocsLink>documentatie</DocsLink> voor meer informatie.",
-  "onboarding": "Je takenlijst in deze werkruimte is leeg.",
-  "rooTips": {
-    "boomerangTasks": {
-      "title": "Boomerang-taken",
-      "description": "Splits taken op in kleinere, beheersbare delen"
-    },
-    "stickyModels": {
-      "title": "Vastgezette modellen",
-      "description": "Elke modus onthoudt je laatst gebruikte model"
-    },
-    "tools": {
-      "title": "Tools",
-      "description": "Laat de AI problemen oplossen door te browsen, commando's uit te voeren en meer"
-    },
-    "customizableModes": {
-      "title": "Aanpasbare modi",
-      "description": "Gespecialiseerde persona's met hun eigen gedrag en toegewezen modellen"
-    }
-  },
-  "selectMode": "Selecteer modus voor interactie",
-  "selectApiConfig": "Selecteer API-configuratie",
-  "enhancePrompt": "Prompt verbeteren met extra context",
-  "enhancePromptDescription": "De knop 'Prompt verbeteren' helpt je prompt te verbeteren door extra context, verduidelijking of herformulering te bieden. Probeer hier een prompt te typen en klik opnieuw op de knop om te zien hoe het werkt.",
-  "addImages": "Afbeeldingen toevoegen aan bericht",
-  "sendMessage": "Bericht verzenden",
-  "typeMessage": "Typ een bericht...",
-  "typeTask": "Typ hier je taak...",
-  "addContext": "@ om context toe te voegen, / om van modus te wisselen",
-  "dragFiles": "houd shift ingedrukt om bestanden te slepen",
-  "dragFilesImages": "houd shift ingedrukt om bestanden/afbeeldingen te slepen",
-  "errorReadingFile": "Fout bij het lezen van bestand:",
-  "noValidImages": "Er zijn geen geldige afbeeldingen verwerkt",
-  "separator": "Scheidingsteken",
-  "edit": "Bewerken...",
-  "forNextMode": "voor volgende modus",
-  "apiRequest": {
-    "title": "API-verzoek",
-    "failed": "API-verzoek mislukt",
-    "streaming": "API-verzoek...",
-    "cancelled": "API-verzoek geannuleerd",
-    "streamingFailed": "API-streaming mislukt"
-  },
-  "checkpoint": {
-    "initial": "Initiële checkpoint",
-    "regular": "Checkpoint",
-    "initializingWarning": "Checkpoint wordt nog steeds geïnitialiseerd... Als dit te lang duurt, kun je checkpoints uitschakelen in de <settingsLink>instellingen</settingsLink> en je taak opnieuw starten.",
-    "menu": {
-      "viewDiff": "Bekijk verschil",
-      "restore": "Herstel checkpoint",
-      "restoreFiles": "Bestanden herstellen",
-      "restoreFilesDescription": "Herstelt de bestanden van je project naar een momentopname die op dit punt is gemaakt.",
-      "restoreFilesAndTask": "Bestanden & taak herstellen",
-      "confirm": "Bevestigen",
-      "cancel": "Annuleren",
-      "cannotUndo": "Deze actie kan niet ongedaan worden gemaakt.",
-      "restoreFilesAndTaskDescription": "Herstelt de bestanden van je project naar een momentopname die op dit punt is gemaakt en verwijdert alle berichten na dit punt."
-    },
-    "current": "Huidig"
-  },
-  "instructions": {
-    "wantsToFetch": "Roo wil gedetailleerde instructies ophalen om te helpen met de huidige taak"
-  },
-  "fileOperations": {
-    "wantsToRead": "Roo wil dit bestand lezen:",
-    "wantsToReadOutsideWorkspace": "Roo wil dit bestand buiten de werkruimte lezen:",
-    "didRead": "Roo heeft dit bestand gelezen:",
-    "wantsToEdit": "Roo wil dit bestand bewerken:",
-    "wantsToEditOutsideWorkspace": "Roo wil dit bestand buiten de werkruimte bewerken:",
-    "wantsToCreate": "Roo wil een nieuw bestand aanmaken:",
-    "wantsToSearchReplace": "Roo wil zoeken en vervangen in dit bestand:",
-    "didSearchReplace": "Roo heeft zoeken en vervangen uitgevoerd op dit bestand:",
-    "wantsToInsert": "Roo wil inhoud invoegen in dit bestand:",
-    "wantsToInsertWithLineNumber": "Roo wil inhoud invoegen in dit bestand op regel {{lineNumber}}:",
-    "wantsToInsertAtEnd": "Roo wil inhoud toevoegen aan het einde van dit bestand:"
-  },
-  "directoryOperations": {
-    "wantsToViewTopLevel": "Roo wil de bovenliggende bestanden in deze map bekijken:",
-    "didViewTopLevel": "Roo heeft de bovenliggende bestanden in deze map bekeken:",
-    "wantsToViewRecursive": "Roo wil alle bestanden in deze map recursief bekijken:",
-    "didViewRecursive": "Roo heeft alle bestanden in deze map recursief bekeken:",
-    "wantsToViewDefinitions": "Roo wil broncode-definitienamen bekijken die in deze map worden gebruikt:",
-    "didViewDefinitions": "Roo heeft broncode-definitienamen bekeken die in deze map worden gebruikt:",
-    "wantsToSearch": "Roo wil deze map doorzoeken op <code>{{regex}}</code>:",
-    "didSearch": "Roo heeft deze map doorzocht op <code>{{regex}}</code>:"
-  },
-  "commandOutput": "Commando-uitvoer",
-  "response": "Antwoord",
-  "arguments": "Argumenten",
-  "mcp": {
-    "wantsToUseTool": "Roo wil een tool gebruiken op de {{serverName}} MCP-server:",
-    "wantsToAccessResource": "Roo wil een bron benaderen op de {{serverName}} MCP-server:"
-  },
-  "modes": {
-    "wantsToSwitch": "Roo wil overschakelen naar {{mode}} modus",
-    "wantsToSwitchWithReason": "Roo wil overschakelen naar {{mode}} modus omdat: {{reason}}",
-    "didSwitch": "Roo is overgeschakeld naar {{mode}} modus",
-    "didSwitchWithReason": "Roo is overgeschakeld naar {{mode}} modus omdat: {{reason}}"
-  },
-  "subtasks": {
-    "wantsToCreate": "Roo wil een nieuwe subtaak aanmaken in {{mode}} modus:",
-    "wantsToFinish": "Roo wil deze subtaak voltooien",
-    "newTaskContent": "Subtaak-instructies",
-    "completionContent": "Subtaak voltooid",
-    "resultContent": "Subtaakresultaten",
-    "defaultResult": "Ga verder met de volgende taak.",
-    "completionInstructions": "Subtaak voltooid! Je kunt de resultaten bekijken en eventuele correcties of volgende stappen voorstellen. Als alles goed is, bevestig dan om het resultaat terug te sturen naar de hoofdtaak."
-  },
-  "questions": {
-    "hasQuestion": "Roo heeft een vraag:"
-  },
-  "taskCompleted": "Taak voltooid",
-  "error": "Fout",
-  "diffError": {
-    "title": "Bewerking mislukt"
-  },
-  "troubleMessage": "Roo ondervindt problemen...",
-  "powershell": {
-    "issues": "Het lijkt erop dat je problemen hebt met Windows PowerShell, zie deze"
-  },
-  "autoApprove": {
-    "title": "Automatisch goedkeuren:",
-    "none": "Geen",
-    "description": "Met automatisch goedkeuren kan Roo Code acties uitvoeren zonder om toestemming te vragen. Schakel dit alleen in voor acties die je volledig vertrouwt. Meer gedetailleerde configuratie beschikbaar in de <settingsLink>Instellingen</settingsLink>."
-  },
-  "announcement": {
-    "title": "🎉 Roo Code 3.16 uitgebracht",
-    "description": "Roo Code 3.16 brengt nieuwe functies en verbeteringen op basis van jouw feedback.",
-    "feature1": "<bold>Groq en Chutes API-providers</bold>: Ondersteuning toegevoegd voor Groq en Chutes API-providers (dank aan @shariqriazz!)",
-    "feature2": "<bold>Klikbare codeverwijzingen</bold>: Codeverwijzingen in modelantwoorden navigeren nu naar bronregels (dank aan @KJ7LNW!)",
-    "feature3": "<bold>MCP-stabiliteitsverbeteringen</bold>: Verschillende bugs opgelost om de stabiliteit van MCP-integraties te verbeteren",
-    "hideButton": "Aankondiging verbergen",
-    "detailsDiscussLinks": "Meer details en discussie in <discordLink>Discord</discordLink> en <redditLink>Reddit</redditLink> 🚀",
-    "whatsNew": "Wat is er nieuw"
-  },
-  "reasoning": {
-    "thinking": "Denkt na",
-    "seconds": "{{count}}s"
-  },
-  "followUpSuggest": {
-    "copyToInput": "Kopiëren naar invoer (zelfde als shift + klik)"
-  },
-  "browser": {
-    "rooWantsToUse": "Roo wil de browser gebruiken:",
-    "consoleLogs": "Console-logboeken",
-    "noNewLogs": "(Geen nieuwe logboeken)",
-    "screenshot": "Browserschermopname",
-    "cursor": "cursor",
-    "navigation": {
-      "step": "Stap {{current}} van {{total}}",
-      "previous": "Vorige",
-      "next": "Volgende"
-    },
-    "sessionStarted": "Browsersessie gestart",
-    "actions": {
-      "title": "Browse-actie: ",
-      "launch": "Browser starten op {{url}}",
-      "click": "Klik ({{coordinate}})",
-      "type": "Typ \"{{text}}\"",
-      "scrollDown": "Scroll naar beneden",
-      "scrollUp": "Scroll naar boven",
-      "close": "Browser sluiten"
-    }
-  },
-  "codeblock": {
-    "tooltips": {
-      "expand": "Codeblok uitvouwen",
-      "collapse": "Codeblok samenvouwen",
-      "enable_wrap": "Regelafbreking inschakelen",
-      "disable_wrap": "Regelafbreking uitschakelen",
-      "copy_code": "Code kopiëren"
-    }
-  },
-  "systemPromptWarning": "WAARSCHUWING: Aangepaste systeemprompt actief. Dit kan de functionaliteit ernstig verstoren en onvoorspelbaar gedrag veroorzaken.",
-  "shellIntegration": {
-    "title": "Waarschuwing commando-uitvoering",
-    "description": "Je commando wordt uitgevoerd zonder VSCode-terminal shell-integratie. Om deze waarschuwing te onderdrukken kun je shell-integratie uitschakelen in het gedeelte <strong>Terminal</strong> van de <settingsLink>Roo Code-instellingen</settingsLink> of de VSCode-terminalintegratie oplossen via de onderstaande link.",
-    "troubleshooting": "Klik hier voor shell-integratie documentatie."
-  }
+	"greeting": "Welkom bij Roo Code",
+	"task": {
+		"title": "Taak",
+		"seeMore": "Meer weergeven",
+		"seeLess": "Minder weergeven",
+		"tokens": "Tokens:",
+		"cache": "Cache:",
+		"apiCost": "API-kosten:",
+		"contextWindow": "Contextlengte:",
+		"closeAndStart": "Taak sluiten en een nieuwe starten",
+		"export": "Taakgeschiedenis exporteren",
+		"delete": "Taak verwijderen (Shift + Klik om bevestiging over te slaan)"
+	},
+	"unpin": "Losmaken",
+	"pin": "Vastmaken",
+	"retry": {
+		"title": "Opnieuw proberen",
+		"tooltip": "Probeer de bewerking opnieuw"
+	},
+	"startNewTask": {
+		"title": "Nieuwe taak starten",
+		"tooltip": "Begin een nieuwe taak"
+	},
+	"proceedAnyways": {
+		"title": "Toch doorgaan",
+		"tooltip": "Ga door terwijl het commando wordt uitgevoerd"
+	},
+	"save": {
+		"title": "Opslaan",
+		"tooltip": "Bestandswijzigingen opslaan"
+	},
+	"tokenProgress": {
+		"availableSpace": "Beschikbare ruimte: {{amount}} tokens",
+		"tokensUsed": "Gebruikte tokens: {{used}} van {{total}}",
+		"reservedForResponse": "Gereserveerd voor modelantwoord: {{amount}} tokens"
+	},
+	"reject": {
+		"title": "Weigeren",
+		"tooltip": "Deze actie weigeren"
+	},
+	"completeSubtaskAndReturn": "Subtaak voltooien en terugkeren",
+	"approve": {
+		"title": "Goedkeuren",
+		"tooltip": "Deze actie goedkeuren"
+	},
+	"runCommand": {
+		"title": "Commando uitvoeren",
+		"tooltip": "Voer dit commando uit"
+	},
+	"proceedWhileRunning": {
+		"title": "Doorgaan tijdens uitvoeren",
+		"tooltip": "Ga door ondanks waarschuwingen"
+	},
+	"killCommand": {
+		"title": "Commando stoppen",
+		"tooltip": "Huidig commando stoppen"
+	},
+	"resumeTask": {
+		"title": "Taak hervatten",
+		"tooltip": "Ga door met de huidige taak"
+	},
+	"terminate": {
+		"title": "Beëindigen",
+		"tooltip": "Beëindig de huidige taak"
+	},
+	"cancel": {
+		"title": "Annuleren",
+		"tooltip": "Annuleer de huidige bewerking"
+	},
+	"scrollToBottom": "Scroll naar onderaan de chat",
+	"about": "Genereer, refactor en debug code met AI-assistentie.<br />Bekijk onze <DocsLink>documentatie</DocsLink> voor meer informatie.",
+	"onboarding": "Je takenlijst in deze werkruimte is leeg.",
+	"rooTips": {
+		"boomerangTasks": {
+			"title": "Boomerang-taken",
+			"description": "Splits taken op in kleinere, beheersbare delen"
+		},
+		"stickyModels": {
+			"title": "Vastgezette modellen",
+			"description": "Elke modus onthoudt je laatst gebruikte model"
+		},
+		"tools": {
+			"title": "Tools",
+			"description": "Laat de AI problemen oplossen door te browsen, commando's uit te voeren en meer"
+		},
+		"customizableModes": {
+			"title": "Aanpasbare modi",
+			"description": "Gespecialiseerde persona's met hun eigen gedrag en toegewezen modellen"
+		}
+	},
+	"selectMode": "Selecteer modus voor interactie",
+	"selectApiConfig": "Selecteer API-configuratie",
+	"enhancePrompt": "Prompt verbeteren met extra context",
+	"enhancePromptDescription": "De knop 'Prompt verbeteren' helpt je prompt te verbeteren door extra context, verduidelijking of herformulering te bieden. Probeer hier een prompt te typen en klik opnieuw op de knop om te zien hoe het werkt.",
+	"addImages": "Afbeeldingen toevoegen aan bericht",
+	"sendMessage": "Bericht verzenden",
+	"typeMessage": "Typ een bericht...",
+	"typeTask": "Typ hier je taak...",
+	"addContext": "@ om context toe te voegen, / om van modus te wisselen",
+	"dragFiles": "houd shift ingedrukt om bestanden te slepen",
+	"dragFilesImages": "houd shift ingedrukt om bestanden/afbeeldingen te slepen",
+	"errorReadingFile": "Fout bij het lezen van bestand:",
+	"noValidImages": "Er zijn geen geldige afbeeldingen verwerkt",
+	"separator": "Scheidingsteken",
+	"edit": "Bewerken...",
+	"forNextMode": "voor volgende modus",
+	"apiRequest": {
+		"title": "API-verzoek",
+		"failed": "API-verzoek mislukt",
+		"streaming": "API-verzoek...",
+		"cancelled": "API-verzoek geannuleerd",
+		"streamingFailed": "API-streaming mislukt"
+	},
+	"checkpoint": {
+		"initial": "Initiële checkpoint",
+		"regular": "Checkpoint",
+		"initializingWarning": "Checkpoint wordt nog steeds geïnitialiseerd... Als dit te lang duurt, kun je checkpoints uitschakelen in de <settingsLink>instellingen</settingsLink> en je taak opnieuw starten.",
+		"menu": {
+			"viewDiff": "Bekijk verschil",
+			"restore": "Herstel checkpoint",
+			"restoreFiles": "Bestanden herstellen",
+			"restoreFilesDescription": "Herstelt de bestanden van je project naar een momentopname die op dit punt is gemaakt.",
+			"restoreFilesAndTask": "Bestanden & taak herstellen",
+			"confirm": "Bevestigen",
+			"cancel": "Annuleren",
+			"cannotUndo": "Deze actie kan niet ongedaan worden gemaakt.",
+			"restoreFilesAndTaskDescription": "Herstelt de bestanden van je project naar een momentopname die op dit punt is gemaakt en verwijdert alle berichten na dit punt."
+		},
+		"current": "Huidig"
+	},
+	"instructions": {
+		"wantsToFetch": "Roo wil gedetailleerde instructies ophalen om te helpen met de huidige taak"
+	},
+	"fileOperations": {
+		"wantsToRead": "Roo wil dit bestand lezen:",
+		"wantsToReadOutsideWorkspace": "Roo wil dit bestand buiten de werkruimte lezen:",
+		"didRead": "Roo heeft dit bestand gelezen:",
+		"wantsToEdit": "Roo wil dit bestand bewerken:",
+		"wantsToEditOutsideWorkspace": "Roo wil dit bestand buiten de werkruimte bewerken:",
+		"wantsToCreate": "Roo wil een nieuw bestand aanmaken:",
+		"wantsToSearchReplace": "Roo wil zoeken en vervangen in dit bestand:",
+		"didSearchReplace": "Roo heeft zoeken en vervangen uitgevoerd op dit bestand:",
+		"wantsToInsert": "Roo wil inhoud invoegen in dit bestand:",
+		"wantsToInsertWithLineNumber": "Roo wil inhoud invoegen in dit bestand op regel {{lineNumber}}:",
+		"wantsToInsertAtEnd": "Roo wil inhoud toevoegen aan het einde van dit bestand:"
+	},
+	"directoryOperations": {
+		"wantsToViewTopLevel": "Roo wil de bovenliggende bestanden in deze map bekijken:",
+		"didViewTopLevel": "Roo heeft de bovenliggende bestanden in deze map bekeken:",
+		"wantsToViewRecursive": "Roo wil alle bestanden in deze map recursief bekijken:",
+		"didViewRecursive": "Roo heeft alle bestanden in deze map recursief bekeken:",
+		"wantsToViewDefinitions": "Roo wil broncode-definitienamen bekijken die in deze map worden gebruikt:",
+		"didViewDefinitions": "Roo heeft broncode-definitienamen bekeken die in deze map worden gebruikt:",
+		"wantsToSearch": "Roo wil deze map doorzoeken op <code>{{regex}}</code>:",
+		"didSearch": "Roo heeft deze map doorzocht op <code>{{regex}}</code>:"
+	},
+	"commandOutput": "Commando-uitvoer",
+	"response": "Antwoord",
+	"arguments": "Argumenten",
+	"mcp": {
+		"wantsToUseTool": "Roo wil een tool gebruiken op de {{serverName}} MCP-server:",
+		"wantsToAccessResource": "Roo wil een bron benaderen op de {{serverName}} MCP-server:"
+	},
+	"modes": {
+		"wantsToSwitch": "Roo wil overschakelen naar {{mode}} modus",
+		"wantsToSwitchWithReason": "Roo wil overschakelen naar {{mode}} modus omdat: {{reason}}",
+		"didSwitch": "Roo is overgeschakeld naar {{mode}} modus",
+		"didSwitchWithReason": "Roo is overgeschakeld naar {{mode}} modus omdat: {{reason}}"
+	},
+	"subtasks": {
+		"wantsToCreate": "Roo wil een nieuwe subtaak aanmaken in {{mode}} modus:",
+		"wantsToFinish": "Roo wil deze subtaak voltooien",
+		"newTaskContent": "Subtaak-instructies",
+		"completionContent": "Subtaak voltooid",
+		"resultContent": "Subtaakresultaten",
+		"defaultResult": "Ga verder met de volgende taak.",
+		"completionInstructions": "Subtaak voltooid! Je kunt de resultaten bekijken en eventuele correcties of volgende stappen voorstellen. Als alles goed is, bevestig dan om het resultaat terug te sturen naar de hoofdtaak."
+	},
+	"questions": {
+		"hasQuestion": "Roo heeft een vraag:"
+	},
+	"taskCompleted": "Taak voltooid",
+	"error": "Fout",
+	"diffError": {
+		"title": "Bewerking mislukt"
+	},
+	"troubleMessage": "Roo ondervindt problemen...",
+	"powershell": {
+		"issues": "Het lijkt erop dat je problemen hebt met Windows PowerShell, zie deze"
+	},
+	"autoApprove": {
+		"title": "Automatisch goedkeuren:",
+		"none": "Geen",
+		"description": "Met automatisch goedkeuren kan Roo Code acties uitvoeren zonder om toestemming te vragen. Schakel dit alleen in voor acties die je volledig vertrouwt. Meer gedetailleerde configuratie beschikbaar in de <settingsLink>Instellingen</settingsLink>."
+	},
+	"announcement": {
+		"title": "🎉 Roo Code 3.16 uitgebracht",
+		"description": "Roo Code 3.16 brengt nieuwe functies en verbeteringen op basis van jouw feedback.",
+		"feature1": "<bold>Groq en Chutes API-providers</bold>: Ondersteuning toegevoegd voor Groq en Chutes API-providers (dank aan @shariqriazz!)",
+		"feature2": "<bold>Klikbare codeverwijzingen</bold>: Codeverwijzingen in modelantwoorden navigeren nu naar bronregels (dank aan @KJ7LNW!)",
+		"feature3": "<bold>MCP-stabiliteitsverbeteringen</bold>: Verschillende bugs opgelost om de stabiliteit van MCP-integraties te verbeteren",
+		"hideButton": "Aankondiging verbergen",
+		"detailsDiscussLinks": "Meer details en discussie in <discordLink>Discord</discordLink> en <redditLink>Reddit</redditLink> 🚀",
+		"whatsNew": "Wat is er nieuw"
+	},
+	"reasoning": {
+		"thinking": "Denkt na",
+		"seconds": "{{count}}s"
+	},
+	"followUpSuggest": {
+		"copyToInput": "Kopiëren naar invoer (zelfde als shift + klik)"
+	},
+	"browser": {
+		"rooWantsToUse": "Roo wil de browser gebruiken:",
+		"consoleLogs": "Console-logboeken",
+		"noNewLogs": "(Geen nieuwe logboeken)",
+		"screenshot": "Browserschermopname",
+		"cursor": "cursor",
+		"navigation": {
+			"step": "Stap {{current}} van {{total}}",
+			"previous": "Vorige",
+			"next": "Volgende"
+		},
+		"sessionStarted": "Browsersessie gestart",
+		"actions": {
+			"title": "Browse-actie: ",
+			"launch": "Browser starten op {{url}}",
+			"click": "Klik ({{coordinate}})",
+			"type": "Typ \"{{text}}\"",
+			"scrollDown": "Scroll naar beneden",
+			"scrollUp": "Scroll naar boven",
+			"close": "Browser sluiten"
+		}
+	},
+	"codeblock": {
+		"tooltips": {
+			"expand": "Codeblok uitvouwen",
+			"collapse": "Codeblok samenvouwen",
+			"enable_wrap": "Regelafbreking inschakelen",
+			"disable_wrap": "Regelafbreking uitschakelen",
+			"copy_code": "Code kopiëren"
+		}
+	},
+	"systemPromptWarning": "WAARSCHUWING: Aangepaste systeemprompt actief. Dit kan de functionaliteit ernstig verstoren en onvoorspelbaar gedrag veroorzaken.",
+	"shellIntegration": {
+		"title": "Waarschuwing commando-uitvoering",
+		"description": "Je commando wordt uitgevoerd zonder VSCode-terminal shell-integratie. Om deze waarschuwing te onderdrukken kun je shell-integratie uitschakelen in het gedeelte <strong>Terminal</strong> van de <settingsLink>Roo Code-instellingen</settingsLink> of de VSCode-terminalintegratie oplossen via de onderstaande link.",
+		"troubleshooting": "Klik hier voor shell-integratie documentatie."
+	}
 }

+ 12 - 12
webview-ui/src/i18n/locales/nl/common.json

@@ -1,14 +1,14 @@
 {
-  "number_format": {
-    "thousand_suffix": "k",
-    "million_suffix": "m",
-    "billion_suffix": "mrd"
-  },
-  "ui": {
-    "search_placeholder": "Zoeken..."
-  },
-  "mermaid": {
-    "loading": "Mermaid-diagram genereren...",
-    "render_error": "Kan diagram niet weergeven"
-  }
+	"number_format": {
+		"thousand_suffix": "k",
+		"million_suffix": "m",
+		"billion_suffix": "mrd"
+	},
+	"ui": {
+		"search_placeholder": "Zoeken..."
+	},
+	"mermaid": {
+		"loading": "Mermaid-diagram genereren...",
+		"render_error": "Kan diagram niet weergeven"
+	}
 }

+ 37 - 37
webview-ui/src/i18n/locales/nl/history.json

@@ -1,39 +1,39 @@
 {
-  "recentTasks": "Taken",
-  "viewAll": "Alle taken weergeven",
-  "tokens": "Tokens: ↑{{in}} ↓{{out}}",
-  "cache": "Cache: +{{writes}} → {{reads}}",
-  "apiCost": "API-kosten: ${{cost}}",
-  "history": "Geschiedenis",
-  "exitSelectionMode": "Selectiemodus verlaten",
-  "enterSelectionMode": "Selectiemodus starten",
-  "done": "Gereed",
-  "searchPlaceholder": "Geschiedenis doorzoeken...",
-  "newest": "Nieuwste",
-  "oldest": "Oudste",
-  "mostExpensive": "Duurste",
-  "mostTokens": "Meeste tokens",
-  "mostRelevant": "Meest relevant",
-  "deleteTaskTitle": "Taak verwijderen (Shift + Klik om bevestiging over te slaan)",
-  "tokensLabel": "Tokens:",
-  "cacheLabel": "Cache:",
-  "apiCostLabel": "API-kosten:",
-  "copyPrompt": "Prompt kopiëren",
-  "exportTask": "Taak exporteren",
-  "deleteTask": "Taak verwijderen",
-  "deleteTaskMessage": "Weet je zeker dat je deze taak wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.",
-  "cancel": "Annuleren",
-  "delete": "Verwijderen",
-  "exitSelection": "Selectie verlaten",
-  "selectionMode": "Selectiemodus",
-  "deselectAll": "Alles deselecteren",
-  "selectAll": "Alles selecteren",
-  "selectedItems": "Geselecteerd {{selected}}/{{total}} items",
-  "clearSelection": "Selectie wissen",
-  "deleteSelected": "Geselecteerde verwijderen",
-  "deleteTasks": "Taken verwijderen",
-  "confirmDeleteTasks": "Weet je zeker dat je {{count}} taken wilt verwijderen?",
-  "deleteTasksWarning": "Verwijderde taken kunnen niet worden hersteld. Zorg ervoor dat je wilt doorgaan.",
-  "deleteItems": "Verwijder {{count}} items",
-  "showAllWorkspaces": "Toon taken van alle werkruimtes"
+	"recentTasks": "Taken",
+	"viewAll": "Alle taken weergeven",
+	"tokens": "Tokens: ↑{{in}} ↓{{out}}",
+	"cache": "Cache: +{{writes}} → {{reads}}",
+	"apiCost": "API-kosten: ${{cost}}",
+	"history": "Geschiedenis",
+	"exitSelectionMode": "Selectiemodus verlaten",
+	"enterSelectionMode": "Selectiemodus starten",
+	"done": "Gereed",
+	"searchPlaceholder": "Geschiedenis doorzoeken...",
+	"newest": "Nieuwste",
+	"oldest": "Oudste",
+	"mostExpensive": "Duurste",
+	"mostTokens": "Meeste tokens",
+	"mostRelevant": "Meest relevant",
+	"deleteTaskTitle": "Taak verwijderen (Shift + Klik om bevestiging over te slaan)",
+	"tokensLabel": "Tokens:",
+	"cacheLabel": "Cache:",
+	"apiCostLabel": "API-kosten:",
+	"copyPrompt": "Prompt kopiëren",
+	"exportTask": "Taak exporteren",
+	"deleteTask": "Taak verwijderen",
+	"deleteTaskMessage": "Weet je zeker dat je deze taak wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.",
+	"cancel": "Annuleren",
+	"delete": "Verwijderen",
+	"exitSelection": "Selectie verlaten",
+	"selectionMode": "Selectiemodus",
+	"deselectAll": "Alles deselecteren",
+	"selectAll": "Alles selecteren",
+	"selectedItems": "Geselecteerd {{selected}}/{{total}} items",
+	"clearSelection": "Selectie wissen",
+	"deleteSelected": "Geselecteerde verwijderen",
+	"deleteTasks": "Taken verwijderen",
+	"confirmDeleteTasks": "Weet je zeker dat je {{count}} taken wilt verwijderen?",
+	"deleteTasksWarning": "Verwijderde taken kunnen niet worden hersteld. Zorg ervoor dat je wilt doorgaan.",
+	"deleteItems": "Verwijder {{count}} items",
+	"showAllWorkspaces": "Toon taken van alle werkruimtes"
 }

+ 11 - 11
webview-ui/src/i18n/locales/nl/humanRelay.json

@@ -1,13 +1,13 @@
 {
-  "dialogTitle": "Human Relay - Help alstublieft met kopiëren/plakken",
-  "dialogDescription": "Kopieer de volgende prompt naar de web-AI en plak het antwoord van de AI in het onderstaande invoerveld.",
-  "copiedToClipboard": "Gekopieerd naar klembord",
-  "aiResponse": {
-    "label": "Voer het antwoord van de AI in:",
-    "placeholder": "Plak hier het antwoord van de AI..."
-  },
-  "actions": {
-    "cancel": "Annuleren",
-    "submit": "Verzenden"
-  }
+	"dialogTitle": "Human Relay - Help alstublieft met kopiëren/plakken",
+	"dialogDescription": "Kopieer de volgende prompt naar de web-AI en plak het antwoord van de AI in het onderstaande invoerveld.",
+	"copiedToClipboard": "Gekopieerd naar klembord",
+	"aiResponse": {
+		"label": "Voer het antwoord van de AI in:",
+		"placeholder": "Plak hier het antwoord van de AI..."
+	},
+	"actions": {
+		"cancel": "Annuleren",
+		"submit": "Verzenden"
+	}
 }

+ 53 - 53
webview-ui/src/i18n/locales/nl/mcp.json

@@ -1,55 +1,55 @@
 {
-  "title": "MCP-servers",
-  "done": "Gereed",
-  "description": "Het <0>Model Context Protocol</0> maakt communicatie mogelijk met lokaal draaiende MCP-servers die extra tools en bronnen bieden om Roo's mogelijkheden uit te breiden. Je kunt <1>community-servers</1> gebruiken of Roo vragen om nieuwe tools te maken die specifiek zijn voor jouw workflow (bijv. 'voeg een tool toe die de nieuwste npm-documentatie ophaalt').",
-  "enableToggle": {
-    "title": "MCP-servers inschakelen",
-    "description": "Indien ingeschakeld, kan Roo communiceren met MCP-servers voor geavanceerde functionaliteit. Gebruik je geen MCP, dan kun je dit uitschakelen om het tokengebruik te verminderen."
-  },
-  "enableServerCreation": {
-    "title": "Aanmaken van MCP-server inschakelen",
-    "description": "Indien ingeschakeld, kan Roo je helpen nieuwe MCP-servers te maken via commando's zoals 'voeg een nieuwe tool toe aan...'. Heb je dit niet nodig, schakel het dan uit om het tokengebruik te verminderen."
-  },
-  "editGlobalMCP": "Globale MCP bewerken",
-  "editProjectMCP": "Project-MCP bewerken",
-  "tool": {
-    "alwaysAllow": "Altijd toestaan",
-    "parameters": "Parameters",
-    "noDescription": "Geen beschrijving"
-  },
-  "tabs": {
-    "tools": "Tools",
-    "resources": "Bronnen",
-    "errors": "Fouten"
-  },
-  "emptyState": {
-    "noTools": "Geen tools gevonden",
-    "noResources": "Geen bronnen gevonden",
-    "noLogs": "Geen logboeken gevonden",
-    "noErrors": "Geen fouten gevonden"
-  },
-  "networkTimeout": {
-    "label": "Netwerktime-out",
-    "description": "Maximale wachttijd op serverantwoorden",
-    "options": {
-      "15seconds": "15 seconden",
-      "30seconds": "30 seconden",
-      "1minute": "1 minuut",
-      "5minutes": "5 minuten",
-      "10minutes": "10 minuten",
-      "15minutes": "15 minuten",
-      "30minutes": "30 minuten",
-      "60minutes": "60 minuten"
-    }
-  },
-  "deleteDialog": {
-    "title": "MCP-server verwijderen",
-    "description": "Weet je zeker dat je de MCP-server '{{serverName}}' wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.",
-    "cancel": "Annuleren",
-    "delete": "Verwijderen"
-  },
-  "serverStatus": {
-    "retrying": "Opnieuw proberen...",
-    "retryConnection": "Verbinding opnieuw proberen"
-  }
+	"title": "MCP-servers",
+	"done": "Gereed",
+	"description": "Het <0>Model Context Protocol</0> maakt communicatie mogelijk met lokaal draaiende MCP-servers die extra tools en bronnen bieden om Roo's mogelijkheden uit te breiden. Je kunt <1>community-servers</1> gebruiken of Roo vragen om nieuwe tools te maken die specifiek zijn voor jouw workflow (bijv. 'voeg een tool toe die de nieuwste npm-documentatie ophaalt').",
+	"enableToggle": {
+		"title": "MCP-servers inschakelen",
+		"description": "Indien ingeschakeld, kan Roo communiceren met MCP-servers voor geavanceerde functionaliteit. Gebruik je geen MCP, dan kun je dit uitschakelen om het tokengebruik te verminderen."
+	},
+	"enableServerCreation": {
+		"title": "Aanmaken van MCP-server inschakelen",
+		"description": "Indien ingeschakeld, kan Roo je helpen nieuwe MCP-servers te maken via commando's zoals 'voeg een nieuwe tool toe aan...'. Heb je dit niet nodig, schakel het dan uit om het tokengebruik te verminderen."
+	},
+	"editGlobalMCP": "Globale MCP bewerken",
+	"editProjectMCP": "Project-MCP bewerken",
+	"tool": {
+		"alwaysAllow": "Altijd toestaan",
+		"parameters": "Parameters",
+		"noDescription": "Geen beschrijving"
+	},
+	"tabs": {
+		"tools": "Tools",
+		"resources": "Bronnen",
+		"errors": "Fouten"
+	},
+	"emptyState": {
+		"noTools": "Geen tools gevonden",
+		"noResources": "Geen bronnen gevonden",
+		"noLogs": "Geen logboeken gevonden",
+		"noErrors": "Geen fouten gevonden"
+	},
+	"networkTimeout": {
+		"label": "Netwerktime-out",
+		"description": "Maximale wachttijd op serverantwoorden",
+		"options": {
+			"15seconds": "15 seconden",
+			"30seconds": "30 seconden",
+			"1minute": "1 minuut",
+			"5minutes": "5 minuten",
+			"10minutes": "10 minuten",
+			"15minutes": "15 minuten",
+			"30minutes": "30 minuten",
+			"60minutes": "60 minuten"
+		}
+	},
+	"deleteDialog": {
+		"title": "MCP-server verwijderen",
+		"description": "Weet je zeker dat je de MCP-server '{{serverName}}' wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.",
+		"cancel": "Annuleren",
+		"delete": "Verwijderen"
+	},
+	"serverStatus": {
+		"retrying": "Opnieuw proberen...",
+		"retryConnection": "Verbinding opnieuw proberen"
+	}
 }

+ 147 - 147
webview-ui/src/i18n/locales/nl/prompts.json

@@ -1,149 +1,149 @@
 {
-  "title": "Prompts",
-  "done": "Gereed",
-  "modes": {
-    "title": "Modi",
-    "createNewMode": "Nieuwe modus aanmaken",
-    "editModesConfig": "Modusconfiguratie bewerken",
-    "editGlobalModes": "Globale modi bewerken",
-    "editProjectModes": "Projectmodi bewerken (.roomodes)",
-    "createModeHelpText": "Klik op + om een nieuwe aangepaste modus te maken, of vraag Roo in de chat om er een voor je te maken!",
-    "selectMode": "Modus zoeken"
-  },
-  "apiConfiguration": {
-    "title": "API-configuratie",
-    "select": "Selecteer welke API-configuratie voor deze modus gebruikt moet worden"
-  },
-  "tools": {
-    "title": "Beschikbare tools",
-    "builtInModesText": "Tools voor ingebouwde modi kunnen niet worden aangepast",
-    "editTools": "Tools bewerken",
-    "doneEditing": "Bewerken voltooid",
-    "allowedFiles": "Toegestane bestanden:",
-    "toolNames": {
-      "read": "Bestanden lezen",
-      "edit": "Bestanden bewerken",
-      "browser": "Browser gebruiken",
-      "command": "Commando's uitvoeren",
-      "mcp": "MCP gebruiken"
-    },
-    "noTools": "Geen"
-  },
-  "roleDefinition": {
-    "title": "Roldefinitie",
-    "resetToDefault": "Terugzetten naar standaard",
-    "description": "Definieer Roo's expertise en persoonlijkheid voor deze modus. Deze beschrijving bepaalt hoe Roo zich presenteert en taken benadert."
-  },
-  "customInstructions": {
-    "title": "Modusspecifieke instructies (optioneel)",
-    "resetToDefault": "Terugzetten naar standaard",
-    "description": "Voeg gedragsrichtlijnen toe die specifiek zijn voor de modus {{modeName}}.",
-    "loadFromFile": "Modusspecifieke instructies voor {{mode}} kunnen ook worden geladen uit de map <span>.roo/rules-{{slug}}/</span> in je werkruimte (.roorules-{{slug}} en .clinerules-{{slug}} zijn verouderd en werken binnenkort niet meer)."
-  },
-  "globalCustomInstructions": {
-    "title": "Aangepaste instructies voor alle modi",
-    "description": "Deze instructies gelden voor alle modi. Ze bieden een basisset aan gedragingen die kunnen worden uitgebreid met modusspecifieke instructies hieronder.\nWil je dat Roo in een andere taal denkt en spreekt dan de weergavetaal van je editor ({{language}}), dan kun je dat hier aangeven.",
-    "loadFromFile": "Instructies kunnen ook worden geladen uit de map <span>.roo/rules/</span> in je werkruimte (.roorules en .clinerules zijn verouderd en werken binnenkort niet meer)."
-  },
-  "systemPrompt": {
-    "preview": "Systeemprompt bekijken",
-    "copy": "Systeemprompt kopiëren naar klembord",
-    "title": "Systeemprompt ({{modeName}} modus)"
-  },
-  "supportPrompts": {
-    "title": "Ondersteuningsprompts",
-    "resetPrompt": "Reset {{promptType}} prompt naar standaard",
-    "prompt": "Prompt",
-    "enhance": {
-      "apiConfiguration": "API-configuratie",
-      "apiConfigDescription": "Je kunt een API-configuratie selecteren die altijd wordt gebruikt voor het verbeteren van prompts, of gewoon de huidige selectie gebruiken",
-      "useCurrentConfig": "Huidige API-configuratie gebruiken",
-      "testPromptPlaceholder": "Voer een prompt in om de verbetering te testen",
-      "previewButton": "Voorbeeld promptverbetering"
-    },
-    "types": {
-      "ENHANCE": {
-        "label": "Prompt verbeteren",
-        "description": "Gebruik promptverbetering om op maat gemaakte suggesties of verbeteringen voor je invoer te krijgen. Zo begrijpt Roo je intentie en krijg je de best mogelijke antwoorden. Beschikbaar via het ✨-icoon in de chat."
-      },
-      "EXPLAIN": {
-        "label": "Code uitleggen",
-        "description": "Krijg gedetailleerde uitleg over codefragmenten, functies of hele bestanden. Handig om complexe code te begrijpen of nieuwe patronen te leren. Beschikbaar via codeacties (lampje in de editor) en het contextmenu (rechtsklik op geselecteerde code)."
-      },
-      "FIX": {
-        "label": "Problemen oplossen",
-        "description": "Krijg hulp bij het identificeren en oplossen van bugs, fouten of codekwaliteitsproblemen. Biedt stapsgewijze begeleiding bij het oplossen van problemen. Beschikbaar via codeacties (lampje in de editor) en het contextmenu (rechtsklik op geselecteerde code)."
-      },
-      "IMPROVE": {
-        "label": "Code verbeteren",
-        "description": "Ontvang suggesties voor codeoptimalisatie, betere praktijken en architecturale verbeteringen met behoud van functionaliteit. Beschikbaar via codeacties (lampje in de editor) en het contextmenu (rechtsklik op geselecteerde code)."
-      },
-      "ADD_TO_CONTEXT": {
-        "label": "Aan context toevoegen",
-        "description": "Voeg context toe aan je huidige taak of gesprek. Handig voor extra informatie of verduidelijkingen. Beschikbaar via codeacties (lampje in de editor) en het contextmenu (rechtsklik op geselecteerde code)."
-      },
-      "TERMINAL_ADD_TO_CONTEXT": {
-        "label": "Terminalinhoud aan context toevoegen",
-        "description": "Voeg terminaluitvoer toe aan je huidige taak of gesprek. Handig voor commando-uitvoer of logboeken. Beschikbaar in het terminalcontextmenu (rechtsklik op geselecteerde terminalinhoud)."
-      },
-      "TERMINAL_FIX": {
-        "label": "Terminalcommando repareren",
-        "description": "Krijg hulp bij het repareren van terminalcommando's die zijn mislukt of verbetering nodig hebben. Beschikbaar in het terminalcontextmenu (rechtsklik op geselecteerde terminalinhoud)."
-      },
-      "TERMINAL_EXPLAIN": {
-        "label": "Terminalcommando uitleggen",
-        "description": "Krijg gedetailleerde uitleg over terminalcommando's en hun uitvoer. Beschikbaar in het terminalcontextmenu (rechtsklik op geselecteerde terminalinhoud)."
-      },
-      "NEW_TASK": {
-        "label": "Nieuwe taak starten",
-        "description": "Start een nieuwe taak met gebruikersinvoer. Beschikbaar via de Command Palette."
-      }
-    }
-  },
-  "advancedSystemPrompt": {
-    "title": "Geavanceerd: Systeemprompt overschrijven",
-    "description": "Je kunt de systeemprompt voor deze modus volledig vervangen (behalve de roldefinitie en aangepaste instructies) door een bestand aan te maken op <span>.roo/system-prompt-{{slug}}</span> in je werkruimte. Dit is een zeer geavanceerde functie die ingebouwde beveiligingen en consistentiecontroles omzeilt (vooral rond toolgebruik), dus wees voorzichtig!"
-  },
-  "createModeDialog": {
-    "title": "Nieuwe modus aanmaken",
-    "close": "Sluiten",
-    "name": {
-      "label": "Naam",
-      "placeholder": "Voer de naam van de modus in"
-    },
-    "slug": {
-      "label": "Slug",
-      "description": "De slug wordt gebruikt in URL's en bestandsnamen. Moet kleine letters, cijfers en koppeltekens bevatten."
-    },
-    "saveLocation": {
-      "label": "Opslaglocatie",
-      "description": "Kies waar je deze modus wilt opslaan. Projectspecifieke modi hebben voorrang op globale modi.",
-      "global": {
-        "label": "Globaal",
-        "description": "Beschikbaar in alle werkruimtes"
-      },
-      "project": {
-        "label": "Projectspecifiek (.roomodes)",
-        "description": "Alleen beschikbaar in deze werkruimte, heeft voorrang op globaal"
-      }
-    },
-    "roleDefinition": {
-      "label": "Roldefinitie",
-      "description": "Definieer Roo's expertise en persoonlijkheid voor deze modus."
-    },
-    "tools": {
-      "label": "Beschikbare tools",
-      "description": "Selecteer welke tools deze modus kan gebruiken."
-    },
-    "customInstructions": {
-      "label": "Aangepaste instructies (optioneel)",
-      "description": "Voeg gedragsrichtlijnen toe die specifiek zijn voor deze modus."
-    },
-    "buttons": {
-      "cancel": "Annuleren",
-      "create": "Modus aanmaken"
-    },
-    "deleteMode": "Modus verwijderen"
-  },
-  "allFiles": "alle bestanden"
+	"title": "Prompts",
+	"done": "Gereed",
+	"modes": {
+		"title": "Modi",
+		"createNewMode": "Nieuwe modus aanmaken",
+		"editModesConfig": "Modusconfiguratie bewerken",
+		"editGlobalModes": "Globale modi bewerken",
+		"editProjectModes": "Projectmodi bewerken (.roomodes)",
+		"createModeHelpText": "Klik op + om een nieuwe aangepaste modus te maken, of vraag Roo in de chat om er een voor je te maken!",
+		"selectMode": "Modus zoeken"
+	},
+	"apiConfiguration": {
+		"title": "API-configuratie",
+		"select": "Selecteer welke API-configuratie voor deze modus gebruikt moet worden"
+	},
+	"tools": {
+		"title": "Beschikbare tools",
+		"builtInModesText": "Tools voor ingebouwde modi kunnen niet worden aangepast",
+		"editTools": "Tools bewerken",
+		"doneEditing": "Bewerken voltooid",
+		"allowedFiles": "Toegestane bestanden:",
+		"toolNames": {
+			"read": "Bestanden lezen",
+			"edit": "Bestanden bewerken",
+			"browser": "Browser gebruiken",
+			"command": "Commando's uitvoeren",
+			"mcp": "MCP gebruiken"
+		},
+		"noTools": "Geen"
+	},
+	"roleDefinition": {
+		"title": "Roldefinitie",
+		"resetToDefault": "Terugzetten naar standaard",
+		"description": "Definieer Roo's expertise en persoonlijkheid voor deze modus. Deze beschrijving bepaalt hoe Roo zich presenteert en taken benadert."
+	},
+	"customInstructions": {
+		"title": "Modusspecifieke instructies (optioneel)",
+		"resetToDefault": "Terugzetten naar standaard",
+		"description": "Voeg gedragsrichtlijnen toe die specifiek zijn voor de modus {{modeName}}.",
+		"loadFromFile": "Modusspecifieke instructies voor {{mode}} kunnen ook worden geladen uit de map <span>.roo/rules-{{slug}}/</span> in je werkruimte (.roorules-{{slug}} en .clinerules-{{slug}} zijn verouderd en werken binnenkort niet meer)."
+	},
+	"globalCustomInstructions": {
+		"title": "Aangepaste instructies voor alle modi",
+		"description": "Deze instructies gelden voor alle modi. Ze bieden een basisset aan gedragingen die kunnen worden uitgebreid met modusspecifieke instructies hieronder.\nWil je dat Roo in een andere taal denkt en spreekt dan de weergavetaal van je editor ({{language}}), dan kun je dat hier aangeven.",
+		"loadFromFile": "Instructies kunnen ook worden geladen uit de map <span>.roo/rules/</span> in je werkruimte (.roorules en .clinerules zijn verouderd en werken binnenkort niet meer)."
+	},
+	"systemPrompt": {
+		"preview": "Systeemprompt bekijken",
+		"copy": "Systeemprompt kopiëren naar klembord",
+		"title": "Systeemprompt ({{modeName}} modus)"
+	},
+	"supportPrompts": {
+		"title": "Ondersteuningsprompts",
+		"resetPrompt": "Reset {{promptType}} prompt naar standaard",
+		"prompt": "Prompt",
+		"enhance": {
+			"apiConfiguration": "API-configuratie",
+			"apiConfigDescription": "Je kunt een API-configuratie selecteren die altijd wordt gebruikt voor het verbeteren van prompts, of gewoon de huidige selectie gebruiken",
+			"useCurrentConfig": "Huidige API-configuratie gebruiken",
+			"testPromptPlaceholder": "Voer een prompt in om de verbetering te testen",
+			"previewButton": "Voorbeeld promptverbetering"
+		},
+		"types": {
+			"ENHANCE": {
+				"label": "Prompt verbeteren",
+				"description": "Gebruik promptverbetering om op maat gemaakte suggesties of verbeteringen voor je invoer te krijgen. Zo begrijpt Roo je intentie en krijg je de best mogelijke antwoorden. Beschikbaar via het ✨-icoon in de chat."
+			},
+			"EXPLAIN": {
+				"label": "Code uitleggen",
+				"description": "Krijg gedetailleerde uitleg over codefragmenten, functies of hele bestanden. Handig om complexe code te begrijpen of nieuwe patronen te leren. Beschikbaar via codeacties (lampje in de editor) en het contextmenu (rechtsklik op geselecteerde code)."
+			},
+			"FIX": {
+				"label": "Problemen oplossen",
+				"description": "Krijg hulp bij het identificeren en oplossen van bugs, fouten of codekwaliteitsproblemen. Biedt stapsgewijze begeleiding bij het oplossen van problemen. Beschikbaar via codeacties (lampje in de editor) en het contextmenu (rechtsklik op geselecteerde code)."
+			},
+			"IMPROVE": {
+				"label": "Code verbeteren",
+				"description": "Ontvang suggesties voor codeoptimalisatie, betere praktijken en architecturale verbeteringen met behoud van functionaliteit. Beschikbaar via codeacties (lampje in de editor) en het contextmenu (rechtsklik op geselecteerde code)."
+			},
+			"ADD_TO_CONTEXT": {
+				"label": "Aan context toevoegen",
+				"description": "Voeg context toe aan je huidige taak of gesprek. Handig voor extra informatie of verduidelijkingen. Beschikbaar via codeacties (lampje in de editor) en het contextmenu (rechtsklik op geselecteerde code)."
+			},
+			"TERMINAL_ADD_TO_CONTEXT": {
+				"label": "Terminalinhoud aan context toevoegen",
+				"description": "Voeg terminaluitvoer toe aan je huidige taak of gesprek. Handig voor commando-uitvoer of logboeken. Beschikbaar in het terminalcontextmenu (rechtsklik op geselecteerde terminalinhoud)."
+			},
+			"TERMINAL_FIX": {
+				"label": "Terminalcommando repareren",
+				"description": "Krijg hulp bij het repareren van terminalcommando's die zijn mislukt of verbetering nodig hebben. Beschikbaar in het terminalcontextmenu (rechtsklik op geselecteerde terminalinhoud)."
+			},
+			"TERMINAL_EXPLAIN": {
+				"label": "Terminalcommando uitleggen",
+				"description": "Krijg gedetailleerde uitleg over terminalcommando's en hun uitvoer. Beschikbaar in het terminalcontextmenu (rechtsklik op geselecteerde terminalinhoud)."
+			},
+			"NEW_TASK": {
+				"label": "Nieuwe taak starten",
+				"description": "Start een nieuwe taak met gebruikersinvoer. Beschikbaar via de Command Palette."
+			}
+		}
+	},
+	"advancedSystemPrompt": {
+		"title": "Geavanceerd: Systeemprompt overschrijven",
+		"description": "Je kunt de systeemprompt voor deze modus volledig vervangen (behalve de roldefinitie en aangepaste instructies) door een bestand aan te maken op <span>.roo/system-prompt-{{slug}}</span> in je werkruimte. Dit is een zeer geavanceerde functie die ingebouwde beveiligingen en consistentiecontroles omzeilt (vooral rond toolgebruik), dus wees voorzichtig!"
+	},
+	"createModeDialog": {
+		"title": "Nieuwe modus aanmaken",
+		"close": "Sluiten",
+		"name": {
+			"label": "Naam",
+			"placeholder": "Voer de naam van de modus in"
+		},
+		"slug": {
+			"label": "Slug",
+			"description": "De slug wordt gebruikt in URL's en bestandsnamen. Moet kleine letters, cijfers en koppeltekens bevatten."
+		},
+		"saveLocation": {
+			"label": "Opslaglocatie",
+			"description": "Kies waar je deze modus wilt opslaan. Projectspecifieke modi hebben voorrang op globale modi.",
+			"global": {
+				"label": "Globaal",
+				"description": "Beschikbaar in alle werkruimtes"
+			},
+			"project": {
+				"label": "Projectspecifiek (.roomodes)",
+				"description": "Alleen beschikbaar in deze werkruimte, heeft voorrang op globaal"
+			}
+		},
+		"roleDefinition": {
+			"label": "Roldefinitie",
+			"description": "Definieer Roo's expertise en persoonlijkheid voor deze modus."
+		},
+		"tools": {
+			"label": "Beschikbare tools",
+			"description": "Selecteer welke tools deze modus kan gebruiken."
+		},
+		"customInstructions": {
+			"label": "Aangepaste instructies (optioneel)",
+			"description": "Voeg gedragsrichtlijnen toe die specifiek zijn voor deze modus."
+		},
+		"buttons": {
+			"cancel": "Annuleren",
+			"create": "Modus aanmaken"
+		},
+		"deleteMode": "Modus verwijderen"
+	},
+	"allFiles": "alle bestanden"
 }

+ 26 - 26
webview-ui/src/i18n/locales/nl/welcome.json

@@ -1,28 +1,28 @@
 {
-  "greeting": "Hoi, ik ben Roo!",
-  "introduction": "<strong>Roo Code is de toonaangevende autonome programmeeragent.</strong> Maak je klaar om te ontwerpen, coderen, debuggen en je productiviteit te verhogen als nooit tevoren. Om door te gaan, heeft Roo Code een API-sleutel nodig.",
-  "notice": "Om te beginnen heeft deze extensie een API-provider nodig.",
-  "start": "Aan de slag!",
-  "chooseProvider": "Kies een API-provider om te beginnen:",
-  "routers": {
-    "requesty": {
-      "description": "Jouw geoptimaliseerde LLM-router",
-      "incentive": "$1 gratis tegoed"
-    },
-    "openrouter": {
-      "description": "Een uniforme interface voor LLM's"
-    }
-  },
-  "startRouter": "Snelle setup via een router",
-  "startCustom": "Gebruik je eigen API-sleutel",
-  "telemetry": {
-    "title": "Help Roo Code verbeteren",
-    "anonymousTelemetry": "Stuur anonieme fout- en gebruiksgegevens om ons te helpen bugs op te lossen en de extensie te verbeteren. Er worden nooit code, prompts of persoonlijke gegevens verzonden.",
-    "changeSettings": "Je kunt dit altijd wijzigen onderaan de <settingsLink>instellingen</settingsLink>",
-    "settings": "instellingen",
-    "allow": "Toestaan",
-    "deny": "Weigeren"
-  },
-  "or": "of",
-  "importSettings": "Instellingen importeren"
+	"greeting": "Hoi, ik ben Roo!",
+	"introduction": "<strong>Roo Code is de toonaangevende autonome programmeeragent.</strong> Maak je klaar om te ontwerpen, coderen, debuggen en je productiviteit te verhogen als nooit tevoren. Om door te gaan, heeft Roo Code een API-sleutel nodig.",
+	"notice": "Om te beginnen heeft deze extensie een API-provider nodig.",
+	"start": "Aan de slag!",
+	"chooseProvider": "Kies een API-provider om te beginnen:",
+	"routers": {
+		"requesty": {
+			"description": "Jouw geoptimaliseerde LLM-router",
+			"incentive": "$1 gratis tegoed"
+		},
+		"openrouter": {
+			"description": "Een uniforme interface voor LLM's"
+		}
+	},
+	"startRouter": "Snelle setup via een router",
+	"startCustom": "Gebruik je eigen API-sleutel",
+	"telemetry": {
+		"title": "Help Roo Code verbeteren",
+		"anonymousTelemetry": "Stuur anonieme fout- en gebruiksgegevens om ons te helpen bugs op te lossen en de extensie te verbeteren. Er worden nooit code, prompts of persoonlijke gegevens verzonden.",
+		"changeSettings": "Je kunt dit altijd wijzigen onderaan de <settingsLink>instellingen</settingsLink>",
+		"settings": "instellingen",
+		"allow": "Toestaan",
+		"deny": "Weigeren"
+	},
+	"or": "of",
+	"importSettings": "Instellingen importeren"
 }

+ 1 - 1
webview-ui/src/stories/Welcome.mdx

@@ -1,4 +1,4 @@
-import { Meta } from "@storybook/blocks";
+import { Meta } from "@storybook/blocks"
 
 <Meta title="Welcome" />
 

+ 162 - 0
webview-ui/src/utils/__tests__/command-validation.test.ts

@@ -1,3 +1,8 @@
+/* eslint-disable no-useless-escape */
+/* eslint-disable no-template-curly-in-string */
+
+// npx jest src/utils/__tests__/command-validation.test.ts
+
 import { parseCommand, isAllowedSingleCommand, validateCommand } from "../command-validation"
 
 describe("Command Validation", () => {
@@ -119,3 +124,160 @@ describe("Command Validation", () => {
 		})
 	})
 })
+
+/**
+ * Tests for the command-validation module
+ *
+ * These tests include a reproduction of a bug where the shell-quote library
+ * used in parseCommand throws an error when parsing commands that contain
+ * the Bash $RANDOM variable in array indexing expressions.
+ *
+ * Error: "Bad substitution: levels[$RANDOM"
+ *
+ * The issue occurs specifically with complex expressions like:
+ * ${levels[$RANDOM % ${#levels[@]}]}
+ */
+describe("command-validation", () => {
+	describe("parseCommand", () => {
+		it("should correctly parse simple commands", () => {
+			const result = parseCommand("echo hello")
+			expect(result).toEqual(["echo hello"])
+		})
+
+		it("should correctly parse commands with chaining operators", () => {
+			const result = parseCommand("echo hello && echo world")
+			expect(result).toEqual(["echo hello", "echo world"])
+		})
+
+		it("should correctly parse commands with quotes", () => {
+			const result = parseCommand('echo "hello world"')
+			expect(result).toEqual(['echo "hello world"'])
+		})
+
+		it("should correctly parse commands with redirections", () => {
+			const result = parseCommand("echo hello 2>&1")
+			expect(result).toEqual(["echo hello 2>&1"])
+		})
+
+		it("should correctly parse commands with subshells", () => {
+			const result = parseCommand("echo $(date)")
+			expect(result).toEqual(["echo", "date"])
+		})
+
+		it("should not throw an error when parsing commands with simple array indexing", () => {
+			// Simple array indexing works fine
+			const commandWithArrayIndex = "value=${array[$index]}"
+
+			expect(() => {
+				parseCommand(commandWithArrayIndex)
+			}).not.toThrow()
+		})
+
+		it("should not throw an error when parsing commands with $RANDOM in array index", () => {
+			// This test reproduces the specific bug reported in the error
+			const commandWithRandom = "level=${levels[$RANDOM % ${#levels[@]}]}"
+
+			expect(() => {
+				parseCommand(commandWithRandom)
+			}).not.toThrow()
+		})
+
+		it("should not throw an error with simple $RANDOM variable", () => {
+			// Simple $RANDOM usage works fine
+			const commandWithRandom = "echo $RANDOM"
+
+			expect(() => {
+				parseCommand(commandWithRandom)
+			}).not.toThrow()
+		})
+
+		it("should not throw an error with simple array indexing using $RANDOM", () => {
+			// Simple array indexing with $RANDOM works fine
+			const commandWithRandomIndex = "echo ${array[$RANDOM]}"
+
+			expect(() => {
+				parseCommand(commandWithRandomIndex)
+			}).not.toThrow()
+		})
+
+		it("should not throw an error with complex array indexing using $RANDOM and arithmetic", () => {
+			// This test reproduces the exact expression from the original error
+			const commandWithComplexRandom = "echo ${levels[$RANDOM % ${#levels[@]}]}"
+
+			expect(() => {
+				parseCommand(commandWithComplexRandom)
+			}).not.toThrow("Bad substitution")
+		})
+
+		it("should not throw an error when parsing the full log generator command", () => {
+			// This is the exact command from the original error message
+			const logGeneratorCommand = `while true; do \\
+  levels=(INFO WARN ERROR DEBUG); \\
+  msgs=("User logged in" "Connection timeout" "Processing request" "Cache miss" "Database query"); \\
+  level=\${levels[$RANDOM % \${#levels[@]}]}; \\
+  msg=\${msgs[$RANDOM % \${#msgs[@]}]}; \\
+  echo "\$(date '+%Y-%m-%d %H:%M:%S') [$level] $msg"; \\
+  sleep 1; \\
+done`
+
+			// This reproduces the original error
+			expect(() => {
+				parseCommand(logGeneratorCommand)
+			}).not.toThrow("Bad substitution: levels[$RANDOM")
+		})
+
+		it("should not throw an error when parsing just the problematic part", () => {
+			// This isolates just the part mentioned in the error message
+			const problematicPart = "level=${levels[$RANDOM"
+
+			expect(() => {
+				parseCommand(problematicPart)
+			}).not.toThrow("Bad substitution")
+		})
+	})
+
+	describe("validateCommand", () => {
+		it("should validate allowed commands", () => {
+			const result = validateCommand("echo hello", ["echo"])
+			expect(result).toBe(true)
+		})
+
+		it("should reject disallowed commands", () => {
+			const result = validateCommand("rm -rf /", ["echo", "ls"])
+			expect(result).toBe(false)
+		})
+
+		it("should not fail validation for commands with simple $RANDOM variable", () => {
+			const commandWithRandom = "echo $RANDOM"
+
+			expect(() => {
+				validateCommand(commandWithRandom, ["echo"])
+			}).not.toThrow()
+		})
+
+		it("should not fail validation for commands with simple array indexing using $RANDOM", () => {
+			const commandWithRandomIndex = "echo ${array[$RANDOM]}"
+
+			expect(() => {
+				validateCommand(commandWithRandomIndex, ["echo"])
+			}).not.toThrow()
+		})
+
+		it("should return false for the full log generator command due to subshell detection", () => {
+			// This is the exact command from the original error message
+			const logGeneratorCommand = `while true; do \\
+  levels=(INFO WARN ERROR DEBUG); \\
+  msgs=("User logged in" "Connection timeout" "Processing request" "Cache miss" "Database query"); \\
+  level=\${levels[$RANDOM % \${#levels[@]}]}; \\
+  msg=\${msgs[$RANDOM % \${#msgs[@]}]}; \\
+  echo "\$(date '+%Y-%m-%d %H:%M:%S') [$level] $msg"; \\
+  sleep 1; \\
+done`
+
+			// validateCommand should return false due to subshell detection
+			// without throwing an error
+			const result = validateCommand(logGeneratorCommand, ["while"])
+			expect(result).toBe(false)
+		})
+	})
+})