Matt Rubens 9 mesi fa
parent
commit
28e745124a
48 ha cambiato i file con 152 aggiunte e 159 eliminazioni
  1. 2 2
      .roomodes
  2. 27 3
      src/core/prompts/__tests__/__snapshots__/system.test.ts.snap
  3. 3 1
      src/core/prompts/sections/custom-instructions.ts
  4. 0 1
      src/core/prompts/sections/rules.ts
  5. 5 16
      src/core/prompts/system.ts
  6. 1 3
      src/core/prompts/tools/index.ts
  7. 2 0
      webview-ui/.gitignore
  8. 23 3
      webview-ui/package-lock.json
  9. 0 1
      webview-ui/package.json
  10. 79 71
      webview-ui/src/components/prompts/PromptsView.tsx
  11. 10 4
      webview-ui/src/i18n/TranslationContext.tsx
  12. 0 0
      webview-ui/src/i18n/locales/ar/.gitkeep
  13. 0 3
      webview-ui/src/i18n/locales/ar/chat.json
  14. 0 0
      webview-ui/src/i18n/locales/ca/.gitkeep
  15. 0 3
      webview-ui/src/i18n/locales/ca/chat.json
  16. 0 0
      webview-ui/src/i18n/locales/cs/.gitkeep
  17. 0 3
      webview-ui/src/i18n/locales/cs/chat.json
  18. 0 0
      webview-ui/src/i18n/locales/de/.gitkeep
  19. 0 3
      webview-ui/src/i18n/locales/de/chat.json
  20. 0 0
      webview-ui/src/i18n/locales/en/.gitkeep
  21. 0 0
      webview-ui/src/i18n/locales/es/.gitkeep
  22. 0 3
      webview-ui/src/i18n/locales/es/chat.json
  23. 0 0
      webview-ui/src/i18n/locales/fr/.gitkeep
  24. 0 3
      webview-ui/src/i18n/locales/fr/chat.json
  25. 0 0
      webview-ui/src/i18n/locales/hi/.gitkeep
  26. 0 3
      webview-ui/src/i18n/locales/hi/chat.json
  27. 0 0
      webview-ui/src/i18n/locales/hu/.gitkeep
  28. 0 3
      webview-ui/src/i18n/locales/hu/chat.json
  29. 0 0
      webview-ui/src/i18n/locales/it/.gitkeep
  30. 0 3
      webview-ui/src/i18n/locales/it/chat.json
  31. 0 0
      webview-ui/src/i18n/locales/ja/.gitkeep
  32. 0 3
      webview-ui/src/i18n/locales/ja/chat.json
  33. 0 0
      webview-ui/src/i18n/locales/ko/.gitkeep
  34. 0 3
      webview-ui/src/i18n/locales/ko/chat.json
  35. 0 0
      webview-ui/src/i18n/locales/pl/.gitkeep
  36. 0 3
      webview-ui/src/i18n/locales/pl/chat.json
  37. 0 0
      webview-ui/src/i18n/locales/pt-BR/.gitkeep
  38. 0 3
      webview-ui/src/i18n/locales/pt-br/chat.json
  39. 0 0
      webview-ui/src/i18n/locales/pt/.gitkeep
  40. 0 3
      webview-ui/src/i18n/locales/pt/chat.json
  41. 0 0
      webview-ui/src/i18n/locales/ru/.gitkeep
  42. 0 3
      webview-ui/src/i18n/locales/ru/chat.json
  43. 0 0
      webview-ui/src/i18n/locales/tr/.gitkeep
  44. 0 3
      webview-ui/src/i18n/locales/tr/chat.json
  45. 0 0
      webview-ui/src/i18n/locales/zh-CN/.gitkeep
  46. 0 0
      webview-ui/src/i18n/locales/zh-TW/.gitkeep
  47. 0 3
      webview-ui/src/i18n/locales/zh-cn/chat.json
  48. 0 3
      webview-ui/src/i18n/locales/zh-tw/chat.json

+ 2 - 2
.roomodes

@@ -1,8 +1,8 @@
 {
   "customModes": [
     {
-      "slug": "translator",
-      "name": "Translator",
+      "slug": "translate",
+      "name": "Translate",
       "roleDefinition": "You are Roo, a linguistic specialist focused on translating and managing localization files. Your responsibility is to help maintain and update translation files for the application, ensuring consistency and accuracy across all language resources.",
       "groups": [
         "read",

+ 27 - 3
src/core/prompts/__tests__/__snapshots__/system.test.ts.snap

@@ -132,12 +132,14 @@ Example: Requesting to write to frontend-config.json
 </write_to_file>
 
 ## execute_command
-Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/path
+Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Prefer relative commands and paths that avoid location sensitivity for terminal consistency, e.g: \`touch ./testdata/example.file\`, \`dir ./examples/model1/data/yaml\`, or \`go test ./cmd/front --config ./cmd/front/config.yml\`. If directed by the user, you may open a terminal in a different directory by using the \`cwd\` parameter.
 Parameters:
 - command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
+- cwd: (optional) The working directory to execute the command in (default: /test/path)
 Usage:
 <execute_command>
 <command>Your command here</command>
+<cwd>Working directory path (optional)</cwd>
 </execute_command>
 
 Example: Requesting to execute npm run dev
@@ -145,6 +147,12 @@ Example: Requesting to execute npm run dev
 <command>npm run dev</command>
 </execute_command>
 
+Example: Requesting to execute ls in a specific directory if directed
+<execute_command>
+<command>ls -la</command>
+<cwd>/home/user/projects</cwd>
+</execute_command>
+
 ## ask_followup_question
 Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
 Parameters:
@@ -543,12 +551,14 @@ Example: Replace all occurrences of "old" with "new" using regex
 </search_and_replace>
 
 ## execute_command
-Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/path
+Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Prefer relative commands and paths that avoid location sensitivity for terminal consistency, e.g: \`touch ./testdata/example.file\`, \`dir ./examples/model1/data/yaml\`, or \`go test ./cmd/front --config ./cmd/front/config.yml\`. If directed by the user, you may open a terminal in a different directory by using the \`cwd\` parameter.
 Parameters:
 - command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
+- cwd: (optional) The working directory to execute the command in (default: /test/path)
 Usage:
 <execute_command>
 <command>Your command here</command>
+<cwd>Working directory path (optional)</cwd>
 </execute_command>
 
 Example: Requesting to execute npm run dev
@@ -556,6 +566,12 @@ Example: Requesting to execute npm run dev
 <command>npm run dev</command>
 </execute_command>
 
+Example: Requesting to execute ls in a specific directory if directed
+<execute_command>
+<command>ls -la</command>
+<cwd>/home/user/projects</cwd>
+</execute_command>
+
 ## ask_followup_question
 Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
 Parameters:
@@ -923,12 +939,14 @@ Example: Replace all occurrences of "old" with "new" using regex
 </search_and_replace>
 
 ## execute_command
-Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/path
+Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Prefer relative commands and paths that avoid location sensitivity for terminal consistency, e.g: \`touch ./testdata/example.file\`, \`dir ./examples/model1/data/yaml\`, or \`go test ./cmd/front --config ./cmd/front/config.yml\`. If directed by the user, you may open a terminal in a different directory by using the \`cwd\` parameter.
 Parameters:
 - command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
+- cwd: (optional) The working directory to execute the command in (default: /test/path)
 Usage:
 <execute_command>
 <command>Your command here</command>
+<cwd>Working directory path (optional)</cwd>
 </execute_command>
 
 Example: Requesting to execute npm run dev
@@ -936,6 +954,12 @@ Example: Requesting to execute npm run dev
 <command>npm run dev</command>
 </execute_command>
 
+Example: Requesting to execute ls in a specific directory if directed
+<execute_command>
+<command>ls -la</command>
+<cwd>/home/user/projects</cwd>
+</execute_command>
+
 ## ask_followup_question
 Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
 Parameters:

+ 3 - 1
src/core/prompts/sections/custom-instructions.ts

@@ -47,7 +47,9 @@ export async function addCustomInstructions(
 
 	// Add language preference if provided
 	if (options.language) {
-		sections.push(`Language Preference:\nYou should always speak and think in the "${options.language}" language.`)
+		sections.push(
+			`Language Preference:\nYou should always speak and think in the "${options.language}" language unless the user gives you instructions below to do otherwise.`,
+		)
 	}
 
 	// Add global instructions first

+ 0 - 1
src/core/prompts/sections/rules.ts

@@ -16,7 +16,6 @@ function getEditingInstructions(diffStrategy?: DiffStrategy, experiments?: Recor
 	} else {
 		availableTools.push("write_to_file (for creating new files or complete file rewrites)")
 	}
-
 	if (experiments?.["insert_content"]) {
 		availableTools.push("insert_content (for adding lines to existing files)")
 	}

+ 5 - 16
src/core/prompts/system.ts

@@ -39,7 +39,7 @@ async function generatePrompt(
 	customModeConfigs?: ModeConfig[],
 	globalCustomInstructions?: string,
 	diffEnabled?: boolean,
-	experiments?: Record<string, boolean> | boolean | undefined,
+	experiments?: Record<string, boolean>,
 	enableMcpServerCreation?: boolean,
 	rooIgnoreInstructions?: string,
 ): Promise<string> {
@@ -61,12 +61,6 @@ async function generatePrompt(
 			: Promise.resolve(""),
 	])
 
-	// Convert experiments to an object if it's a boolean
-	const experimentSettings =
-		typeof experiments === "boolean"
-			? {} // Empty object if experiments is just a boolean
-			: (experiments ?? {})
-
 	const basePrompt = `${roleDefinition}
 
 ${getSharedToolUseSection()}
@@ -79,7 +73,7 @@ ${getToolDescriptionsForMode(
 	browserViewportSize,
 	mcpHub,
 	customModeConfigs,
-	experimentSettings,
+	experiments,
 )}
 
 ${getToolUseGuidelinesSection()}
@@ -90,7 +84,7 @@ ${getCapabilitiesSection(cwd, supportsComputerUse, mcpHub, effectiveDiffStrategy
 
 ${modesSection}
 
-${getRulesSection(cwd, supportsComputerUse, effectiveDiffStrategy, experimentSettings)}
+${getRulesSection(cwd, supportsComputerUse, effectiveDiffStrategy, experiments)}
 
 ${getSystemInfoSection(cwd, mode, customModeConfigs)}
 
@@ -113,7 +107,7 @@ export const SYSTEM_PROMPT = async (
 	customModes?: ModeConfig[],
 	globalCustomInstructions?: string,
 	diffEnabled?: boolean,
-	experiments?: Record<string, boolean> | boolean | undefined,
+	experiments?: Record<string, boolean>,
 	enableMcpServerCreation?: boolean,
 	rooIgnoreInstructions?: string,
 ): Promise<string> => {
@@ -157,11 +151,6 @@ ${customInstructions}`
 
 	// If diff is disabled, don't pass the diffStrategy
 	const effectiveDiffStrategy = diffEnabled ? diffStrategy : undefined
-	// Convert experiments to an object if it's a boolean
-	const experimentSettings =
-		typeof experiments === "boolean"
-			? {} // Empty object if experiments is just a boolean
-			: (experiments ?? {})
 
 	return generatePrompt(
 		context,
@@ -175,7 +164,7 @@ ${customInstructions}`
 		customModes,
 		globalCustomInstructions,
 		diffEnabled,
-		experimentSettings,
+		experiments,
 		enableMcpServerCreation,
 		rooIgnoreInstructions,
 	)

+ 1 - 3
src/core/prompts/tools/index.ts

@@ -61,15 +61,13 @@ export function getToolDescriptionsForMode(
 
 	const tools = new Set<string>()
 
-	const experimentSettings = experiments ?? {}
-
 	// Add tools from mode's groups
 	config.groups.forEach((groupEntry) => {
 		const groupName = getGroupName(groupEntry)
 		const toolGroup = TOOL_GROUPS[groupName]
 		if (toolGroup) {
 			toolGroup.tools.forEach((tool) => {
-				if (isToolAllowedForMode(tool as ToolName, mode, customModes ?? [], experimentSettings)) {
+				if (isToolAllowedForMode(tool as ToolName, mode, customModes ?? [], experiments ?? {})) {
 					tools.add(tool)
 				}
 			})

+ 2 - 0
webview-ui/.gitignore

@@ -23,3 +23,5 @@ yarn-debug.log*
 yarn-error.log*
 
 *storybook.log
+
+tsconfig.tsbuildinfo

+ 23 - 3
webview-ui/package-lock.json

@@ -21,7 +21,6 @@
 				"@radix-ui/react-slot": "^1.1.2",
 				"@radix-ui/react-tooltip": "^1.1.8",
 				"@tailwindcss/vite": "^4.0.0",
-				"@testing-library/dom": "^10.4.0",
 				"@vscode/webview-ui-toolkit": "^1.4.0",
 				"class-variance-authority": "^0.7.1",
 				"clsx": "^2.1.1",
@@ -131,6 +130,7 @@
 			"version": "7.26.2",
 			"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
 			"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
+			"dev": true,
 			"license": "MIT",
 			"dependencies": {
 				"@babel/helper-validator-identifier": "^7.25.9",
@@ -448,6 +448,7 @@
 			"version": "7.25.9",
 			"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
 			"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
+			"dev": true,
 			"license": "MIT",
 			"engines": {
 				"node": ">=6.9.0"
@@ -6536,6 +6537,8 @@
 			"version": "10.4.0",
 			"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
 			"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
+			"dev": true,
+			"peer": true,
 			"dependencies": {
 				"@babel/code-frame": "^7.10.4",
 				"@babel/runtime": "^7.12.5",
@@ -6645,7 +6648,9 @@
 		"node_modules/@types/aria-query": {
 			"version": "5.0.4",
 			"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
-			"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="
+			"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
+			"dev": true,
+			"peer": true
 		},
 		"node_modules/@types/babel__core": {
 			"version": "7.20.5",
@@ -7781,6 +7786,7 @@
 			"version": "5.0.1",
 			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
 			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+			"dev": true,
 			"license": "MIT",
 			"engines": {
 				"node": ">=8"
@@ -7790,6 +7796,7 @@
 			"version": "4.3.0",
 			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
 			"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+			"dev": true,
 			"license": "MIT",
 			"dependencies": {
 				"color-convert": "^2.0.1"
@@ -7838,6 +7845,7 @@
 			"version": "5.3.0",
 			"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
 			"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
+			"dev": true,
 			"license": "Apache-2.0",
 			"dependencies": {
 				"dequal": "^2.0.3"
@@ -8533,6 +8541,7 @@
 			"version": "4.1.2",
 			"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
 			"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+			"dev": true,
 			"license": "MIT",
 			"dependencies": {
 				"ansi-styles": "^4.1.0",
@@ -9132,6 +9141,7 @@
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
 			"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+			"dev": true,
 			"license": "MIT",
 			"dependencies": {
 				"color-name": "~1.1.4"
@@ -9144,6 +9154,7 @@
 			"version": "1.1.4",
 			"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
 			"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+			"dev": true,
 			"license": "MIT"
 		},
 		"node_modules/combined-stream": {
@@ -10180,7 +10191,9 @@
 		"node_modules/dom-accessibility-api": {
 			"version": "0.5.16",
 			"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
-			"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="
+			"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
+			"dev": true,
+			"peer": true
 		},
 		"node_modules/domexception": {
 			"version": "4.0.0",
@@ -12427,6 +12440,7 @@
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
 			"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+			"dev": true,
 			"license": "MIT",
 			"engines": {
 				"node": ">=8"
@@ -15403,6 +15417,8 @@
 			"version": "1.5.0",
 			"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
 			"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
+			"dev": true,
+			"peer": true,
 			"bin": {
 				"lz-string": "bin/bin.js"
 			}
@@ -18266,6 +18282,7 @@
 			"version": "27.5.1",
 			"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
 			"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
+			"dev": true,
 			"license": "MIT",
 			"dependencies": {
 				"ansi-regex": "^5.0.1",
@@ -18280,6 +18297,7 @@
 			"version": "5.2.0",
 			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
 			"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+			"dev": true,
 			"license": "MIT",
 			"engines": {
 				"node": ">=10"
@@ -18525,6 +18543,7 @@
 			"version": "17.0.2",
 			"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
 			"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
+			"dev": true,
 			"license": "MIT"
 		},
 		"node_modules/react-markdown": {
@@ -20466,6 +20485,7 @@
 			"version": "7.2.0",
 			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
 			"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+			"dev": true,
 			"license": "MIT",
 			"dependencies": {
 				"has-flag": "^4.0.0"

+ 0 - 1
webview-ui/package.json

@@ -28,7 +28,6 @@
 		"@radix-ui/react-slot": "^1.1.2",
 		"@radix-ui/react-tooltip": "^1.1.8",
 		"@tailwindcss/vite": "^4.0.0",
-		"@testing-library/dom": "^10.4.0",
 		"@vscode/webview-ui-toolkit": "^1.4.0",
 		"class-variance-authority": "^0.7.1",
 		"clsx": "^2.1.1",

+ 79 - 71
webview-ui/src/components/prompts/PromptsView.tsx

@@ -30,6 +30,7 @@ import {
 import { TOOL_GROUPS, GROUP_DISPLAY_NAMES, ToolGroup } from "../../../../src/shared/tool-groups"
 import { vscode } from "../../utils/vscode"
 import { Tab, TabContent, TabHeader } from "../common/Tab"
+import i18next from "i18next"
 
 // Get all available groups that should show in prompts view
 const availableGroups = (Object.keys(TOOL_GROUPS) as ToolGroup[]).filter((group) => !TOOL_GROUPS[group].alwaysAvailable)
@@ -409,49 +410,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 			</TabHeader>
 
 			<TabContent>
-				<div className="pb-5 border-b border-vscode-input-border">
-					<div className="font-bold mb-1">Custom Instructions for All Modes</div>
-					<div className="text-sm text-vscode-descriptionForeground mb-2">
-						These instructions apply to all modes. They provide a base set of behaviors that can be enhanced
-						by mode-specific instructions below.
-					</div>
-					<VSCodeTextArea
-						value={customInstructions ?? ""}
-						onChange={(e) => {
-							const value =
-								(e as CustomEvent)?.detail?.target?.value ||
-								((e as any).target as HTMLTextAreaElement).value
-							setCustomInstructions(value || undefined)
-							vscode.postMessage({
-								type: "customInstructions",
-								text: value.trim() || undefined,
-							})
-						}}
-						rows={4}
-						resize="vertical"
-						className="w-full"
-						data-testid="global-custom-instructions-textarea"
-					/>
-					<div className="text-xs text-vscode-descriptionForeground mt-1.5 mb-10">
-						Instructions can also be loaded from{" "}
-						<span
-							className="text-vscode-textLink-foreground cursor-pointer underline"
-							onClick={() =>
-								vscode.postMessage({
-									type: "openFile",
-									text: "./.clinerules",
-									values: {
-										create: true,
-										content: "",
-									},
-								})
-							}>
-							.clinerules
-						</span>{" "}
-						in your workspace.
-					</div>
-				</div>
-				<div className="mt-5">
+				<div>
 					<div onClick={(e) => e.stopPropagation()} className="flex justify-between items-center mb-3">
 						<h3 className="text-vscode-foreground m-0">Modes</h3>
 						<div className="flex gap-2">
@@ -882,8 +841,37 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 						</VSCodeButton>
 					</div>
 
+					{/*
+						NOTE: This setting is placed in PromptsView rather than SettingsView since it
+						directly affects the functionality related to modes and custom mode creation,
+						which are managed in this component. This is an intentional deviation from
+						the standard pattern described in cline_docs/settings.md.
+					*/}
+					<div className="mt-12">
+						<VSCodeCheckbox
+							checked={enableCustomModeCreation ?? true}
+							onChange={(e: any) => {
+								// Just update the local state through React context
+								// The React context will update the global state
+								setEnableCustomModeCreation(e.target.checked)
+							}}>
+							<span style={{ fontWeight: "500" }}>Enable Custom Mode Creation Through Prompts</span>
+						</VSCodeCheckbox>
+						<p
+							style={{
+								fontSize: "12px",
+								marginTop: "5px",
+								color: "var(--vscode-descriptionForeground)",
+							}}>
+							When enabled, Roo allows you to create custom modes using prompts like ‘Make me a custom
+							mode that…’. Disabling this reduces your system prompt by about 700 tokens when this feature
+							isn’t needed. When disabled you can still manually create custom modes using the + button
+							above or by editing the related config JSON.
+						</p>
+					</div>
+
 					{/* Custom System Prompt Disclosure */}
-					<div className="mb-3 mt-12">
+					<div className="mt-12">
 						<button
 							onClick={() => setIsSystemPromptDisclosureOpen(!isSystemPromptDisclosureOpen)}
 							className="flex items-center text-xs text-vscode-foreground hover:text-vscode-textLink-foreground focus:outline-none"
@@ -920,34 +908,54 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 							</div>
 						)}
 					</div>
+				</div>
 
-					{/*
-			NOTE: This setting is placed in PromptsView rather than SettingsView since it
-			directly affects the functionality related to modes and custom mode creation,
-			which are managed in this component. This is an intentional deviation from
-			the standard pattern described in cline_docs/settings.md.
-	*/}
-					<div className="mb-4 mt-4">
-						<VSCodeCheckbox
-							checked={enableCustomModeCreation ?? true}
-							onChange={(e: any) => {
-								// Just update the local state through React context
-								// The React context will update the global state
-								setEnableCustomModeCreation(e.target.checked)
-							}}>
-							<span style={{ fontWeight: "500" }}>Enable Custom Mode Creation Through Prompts</span>
-						</VSCodeCheckbox>
-						<p
-							style={{
-								fontSize: "12px",
-								marginTop: "5px",
-								color: "var(--vscode-descriptionForeground)",
-							}}>
-							When enabled, Roo allows you to create custom modes using prompts like ‘Make me a custom
-							mode that…’. Disabling this reduces your system prompt by about 700 tokens when this feature
-							isn’t needed. When disabled you can still manually create custom modes using the + button
-							above or by editing the related config JSON.
-						</p>
+				<div className="pb-5 border-b border-vscode-input-border">
+					<h3 style={{ color: "var(--vscode-foreground)", marginBottom: "12px" }}>
+						Custom Instructions for All Modes
+					</h3>
+
+					<div className="text-sm text-vscode-descriptionForeground mb-2">
+						These instructions apply to all modes. They provide a base set of behaviors that can be enhanced
+						by mode-specific instructions below.
+						<br />
+						If you would like Roo to think and speak in a different language than your editor display
+						language ({i18next.language}), you can specify it here.
+					</div>
+					<VSCodeTextArea
+						value={customInstructions ?? ""}
+						onChange={(e) => {
+							const value =
+								(e as CustomEvent)?.detail?.target?.value ||
+								((e as any).target as HTMLTextAreaElement).value
+							setCustomInstructions(value || undefined)
+							vscode.postMessage({
+								type: "customInstructions",
+								text: value.trim() || undefined,
+							})
+						}}
+						rows={4}
+						resize="vertical"
+						className="w-full"
+						data-testid="global-custom-instructions-textarea"
+					/>
+					<div className="text-xs text-vscode-descriptionForeground mt-1.5 mb-10">
+						Instructions can also be loaded from{" "}
+						<span
+							className="text-vscode-textLink-foreground cursor-pointer underline"
+							onClick={() =>
+								vscode.postMessage({
+									type: "openFile",
+									text: "./.clinerules",
+									values: {
+										create: true,
+										content: "",
+									},
+								})
+							}>
+							.clinerules
+						</span>{" "}
+						in your workspace.
 					</div>
 				</div>
 

+ 10 - 4
webview-ui/src/i18n/TranslationContext.tsx

@@ -1,4 +1,4 @@
-import React, { createContext, useContext, ReactNode, useEffect } from "react"
+import React, { createContext, useContext, ReactNode, useEffect, useCallback } from "react"
 import { useTranslation } from "react-i18next"
 import i18next, { loadTranslations } from "./setup"
 import { useExtensionState } from "@/context/ExtensionStateContext"
@@ -32,12 +32,18 @@ export const TranslationProvider: React.FC<{ children: ReactNode }> = ({ childre
 		i18n.changeLanguage(extensionState.language)
 	}, [i18n, extensionState.language])
 
+	// Memoize the translation function to prevent unnecessary re-renders
+	const translate = useCallback(
+		(key: string, options?: Record<string, any>) => {
+			return i18n.t(key, options)
+		},
+		[i18n],
+	)
+
 	return (
 		<TranslationContext.Provider
 			value={{
-				t: (key: string, options?: Record<string, any>) => {
-					return i18n.t(key, options)
-				},
+				t: translate,
 				i18n,
 			}}>
 			{children}

+ 0 - 0
webview-ui/src/i18n/locales/ar/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/ar/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "ماذا يمكن أن يفعل Roo من أجلك؟"
-}

+ 0 - 0
webview-ui/src/i18n/locales/ca/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/ca/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Què pot fer Roo per tu?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/cs/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/cs/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Co pro vás může Roo udělat?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/de/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/de/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Was kann Roo für dich tun?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/en/.gitkeep


+ 0 - 0
webview-ui/src/i18n/locales/es/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/es/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "¿Qué puedo hacer por ti?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/fr/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/fr/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Que peut faire Roo pour vous ?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/hi/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/hi/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Roo आपके लिए क्या कर सकता है?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/hu/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/hu/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Mit tehet érted a Roo?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/it/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/it/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Cosa può fare Roo per te?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/ja/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/ja/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Rooは何をお手伝いできますか?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/ko/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/ko/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Roo가 당신을 위해 무엇을 할 수 있을까요?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/pl/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/pl/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Co Roo może dla Ciebie zrobić?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/pt-BR/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/pt-br/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "O que o Roo pode fazer por você?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/pt/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/pt/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "O que o Roo pode fazer por si?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/ru/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/ru/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Что Roo может сделать для вас?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/tr/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/tr/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Roo sizin için ne yapabilir?"
-}

+ 0 - 0
webview-ui/src/i18n/locales/zh-CN/.gitkeep


+ 0 - 0
webview-ui/src/i18n/locales/zh-TW/.gitkeep


+ 0 - 3
webview-ui/src/i18n/locales/zh-cn/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Roo能为您做什么?"
-}

+ 0 - 3
webview-ui/src/i18n/locales/zh-tw/chat.json

@@ -1,3 +0,0 @@
-{
-	"greeting": "Roo能為您做什麼?"
-}