diff --git a/packages/types/src/message.ts b/packages/types/src/message.ts index b6eb67e171..ad25dd2da4 100644 --- a/packages/types/src/message.ts +++ b/packages/types/src/message.ts @@ -205,6 +205,7 @@ export const clineMessageSchema = z.object({ ask: clineAskSchema.optional(), say: clineSaySchema.optional(), text: z.string().optional(), + title: z.string().optional(), // Custom title for error messages and other displays images: z.array(z.string()).optional(), partial: z.boolean().optional(), reasoning: z.string().optional(), diff --git a/src/core/assistant-message/presentAssistantMessage.ts b/src/core/assistant-message/presentAssistantMessage.ts index 689675999f..0d652be6a6 100644 --- a/src/core/assistant-message/presentAssistantMessage.ts +++ b/src/core/assistant-message/presentAssistantMessage.ts @@ -37,6 +37,7 @@ import { Task } from "../task/Task" import { codebaseSearchTool } from "../tools/codebaseSearchTool" import { experiments, EXPERIMENT_IDS } from "../../shared/experiments" import { applyDiffToolLegacy } from "../tools/applyDiffTool" +import { t } from "../../i18n" /** * Processes and presents assistant message content to the user interface. @@ -323,9 +324,14 @@ export async function presentAssistantMessage(cline: Task) { await cline.say( "error", `Error ${action}:\n${error.message ?? JSON.stringify(serializeError(error), null, 2)}`, + undefined, // images + undefined, // partial + undefined, // checkpoint + undefined, // progressStatus + { title: t("tools:errors.toolCallError", { toolName: block.name }) }, // Custom title with tool name ) - pushToolResult(formatResponse.toolError(errorString)) + pushToolResult(formatResponse.toolError(errorString, block.name)) } // If block is partial, remove partial closing tag so its not @@ -377,7 +383,7 @@ export async function presentAssistantMessage(cline: Task) { ) } catch (error) { cline.consecutiveMistakeCount++ - pushToolResult(formatResponse.toolError(error.message)) + pushToolResult(formatResponse.toolError(error.message, block.name)) break } @@ -416,6 +422,7 @@ export async function presentAssistantMessage(cline: Task) { pushToolResult( formatResponse.toolError( `Tool call repetition limit reached for ${block.name}. Please try a different approach.`, + block.name, ), ) break diff --git a/src/core/prompts/__tests__/responses-tool-error.spec.ts b/src/core/prompts/__tests__/responses-tool-error.spec.ts new file mode 100644 index 0000000000..127e4bf921 --- /dev/null +++ b/src/core/prompts/__tests__/responses-tool-error.spec.ts @@ -0,0 +1,51 @@ +import { describe, it, expect } from "vitest" +import { formatResponse } from "../responses" + +describe("formatResponse.toolError", () => { + it("should format error without tool name when not provided", () => { + const error = "Something went wrong" + const result = formatResponse.toolError(error) + + expect(result).toBe("Tool Execution Error\n\nSomething went wrong\n") + }) + + it("should format error with tool name when provided", () => { + const error = "Invalid mode: test_mode" + const toolName = "switch_mode" + const result = formatResponse.toolError(error, toolName) + + expect(result).toBe("Tool Call Error: switch_mode\n\nInvalid mode: test_mode\n") + }) + + it("should handle undefined error message", () => { + const result = formatResponse.toolError(undefined, "new_task") + + expect(result).toBe("Tool Call Error: new_task\n\nundefined\n") + }) + + it("should work with various tool names", () => { + const testCases = [ + { toolName: "write_to_file", expected: "Tool Call Error: write_to_file" }, + { toolName: "execute_command", expected: "Tool Call Error: execute_command" }, + { toolName: "apply_diff", expected: "Tool Call Error: apply_diff" }, + { toolName: "new_task", expected: "Tool Call Error: new_task" }, + { toolName: "use_mcp_tool", expected: "Tool Call Error: use_mcp_tool" }, + ] + + testCases.forEach(({ toolName, expected }) => { + const result = formatResponse.toolError("Test error", toolName) + expect(result).toContain(expected) + }) + }) + + it("should maintain backward compatibility when tool name is not provided", () => { + // This ensures existing code that doesn't pass toolName still works + const error = "Legacy error" + const result = formatResponse.toolError(error) + + // Should not contain "Tool Call Error:" prefix + expect(result).not.toContain("Tool Call Error:") + // Should contain generic title + expect(result).toContain("Tool Execution Error") + }) +}) diff --git a/src/core/prompts/responses.ts b/src/core/prompts/responses.ts index fd51b18fed..b4591bc422 100644 --- a/src/core/prompts/responses.ts +++ b/src/core/prompts/responses.ts @@ -3,6 +3,7 @@ import * as path from "path" import * as diff from "diff" import { RooIgnoreController, LOCK_TEXT_SYMBOL } from "../ignore/RooIgnoreController" import { RooProtectedController } from "../protect/RooProtectedController" +import { t } from "../../i18n" export const formatResponse = { toolDenied: () => `The user denied this operation.`, @@ -13,7 +14,12 @@ export const formatResponse = { toolApprovedWithFeedback: (feedback?: string) => `The user approved this operation and provided the following context:\n\n${feedback}\n`, - toolError: (error?: string) => `The tool execution failed with the following error:\n\n${error}\n`, + toolError: (error?: string, toolName?: string) => { + const title = toolName + ? t("tools:errors.toolCallError", { toolName, defaultValue: `Tool Call Error: ${toolName}` }) + : t("tools:errors.toolExecutionError", { defaultValue: "Tool Execution Error" }) + return `${title}\n\n${error}\n` + }, rooIgnoreError: (path: string) => `Access to ${path} is blocked by the .rooignore file settings. You must try to continue in the task without using this file, or ask the user to update the .rooignore file.`, diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index c5be865731..02b17b0f7e 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -1052,6 +1052,7 @@ export class Task extends EventEmitter implements TaskLike { options: { isNonInteractive?: boolean metadata?: Record + title?: string // Optional custom title for error messages } = {}, contextCondense?: ContextCondense, ): Promise { @@ -1086,6 +1087,7 @@ export class Task extends EventEmitter implements TaskLike { type: "say", say: type, text, + title: options.title, // Include custom title if provided images, partial, contextCondense, @@ -1133,6 +1135,7 @@ export class Task extends EventEmitter implements TaskLike { type: "say", say: type, text, + title: options.title, // Include custom title if provided images, contextCondense, metadata: options.metadata, @@ -1156,6 +1159,7 @@ export class Task extends EventEmitter implements TaskLike { type: "say", say: type, text, + title: options.title, // Include custom title if provided images, checkpoint, contextCondense, @@ -1164,13 +1168,24 @@ export class Task extends EventEmitter implements TaskLike { } async sayAndCreateMissingParamError(toolName: ToolName, paramName: string, relPath?: string) { + const message = relPath + ? t("tools:errors.missingParamForToolWithPath", { + toolName, + relPath: relPath.toPosix(), + paramName, + }) + : t("tools:errors.missingParamForTool", { toolName, paramName }) + await this.say( "error", - `Roo tried to use ${toolName}${ - relPath ? ` for '${relPath.toPosix()}'` : "" - } without value for required parameter '${paramName}'. Retrying...`, + message, + undefined, // images + undefined, // partial + undefined, // checkpoint + undefined, // progressStatus + { title: t("tools:errors.toolCallError", { toolName }) }, // Custom title for the error ) - return formatResponse.toolError(formatResponse.missingToolParameterError(paramName)) + return formatResponse.toolError(formatResponse.missingToolParameterError(paramName), toolName) } // Lifecycle @@ -2314,6 +2329,11 @@ export class Task extends EventEmitter implements TaskLike { await this.say( "error", "Unexpected API Response: The language model did not provide any assistant messages. This may indicate an issue with the API or the model's output.", + undefined, + undefined, + undefined, + undefined, + { title: "API Response Error" }, ) await this.addToApiConversationHistory({ diff --git a/src/core/tools/__tests__/insertContentTool.spec.ts b/src/core/tools/__tests__/insertContentTool.spec.ts index 5f055fb29a..27c8e74d7f 100644 --- a/src/core/tools/__tests__/insertContentTool.spec.ts +++ b/src/core/tools/__tests__/insertContentTool.spec.ts @@ -226,7 +226,15 @@ describe("insertContentTool", () => { expect(mockedFsReadFile).not.toHaveBeenCalled() expect(mockCline.consecutiveMistakeCount).toBe(1) expect(mockCline.recordToolError).toHaveBeenCalledWith("insert_content") - expect(mockCline.say).toHaveBeenCalledWith("error", expect.stringContaining("non-existent file")) + expect(mockCline.say).toHaveBeenCalledWith( + "error", + expect.stringContaining("non-existent file"), + undefined, + undefined, + undefined, + undefined, + { title: "Invalid Line Number" }, + ) expect(mockCline.diffViewProvider.update).not.toHaveBeenCalled() expect(mockCline.diffViewProvider.pushToolWriteResult).not.toHaveBeenCalled() }) diff --git a/src/core/tools/__tests__/useMcpToolTool.spec.ts b/src/core/tools/__tests__/useMcpToolTool.spec.ts index 8738e059e5..937998a7d1 100644 --- a/src/core/tools/__tests__/useMcpToolTool.spec.ts +++ b/src/core/tools/__tests__/useMcpToolTool.spec.ts @@ -8,7 +8,12 @@ import { ToolUse } from "../../../shared/tools" vi.mock("../../prompts/responses", () => ({ formatResponse: { toolResult: vi.fn((result: string) => `Tool result: ${result}`), - toolError: vi.fn((error: string) => `Tool error: ${error}`), + toolError: vi.fn((error: string, toolName?: string) => { + if (toolName) { + return `Tool Call Error: ${toolName}\n\n${error}\n` + } + return `Tool Execution Error\n\n${error}\n` + }), invalidMcpToolArgumentError: vi.fn((server: string, tool: string) => `Invalid args for ${server}:${tool}`), unknownMcpToolError: vi.fn((server: string, tool: string, availableTools: string[]) => { const toolsList = availableTools.length > 0 ? availableTools.join(", ") : "No tools available" @@ -151,8 +156,18 @@ describe("useMcpToolTool", () => { expect(mockTask.consecutiveMistakeCount).toBe(1) expect(mockTask.recordToolError).toHaveBeenCalledWith("use_mcp_tool") - expect(mockTask.say).toHaveBeenCalledWith("error", expect.stringContaining("invalid JSON argument")) - expect(mockPushToolResult).toHaveBeenCalledWith("Tool error: Invalid args for test_server:test_tool") + expect(mockTask.say).toHaveBeenCalledWith( + "error", + expect.stringContaining("invalid JSON argument"), + undefined, + undefined, + undefined, + undefined, + { title: "tools:errors.invalidInput" }, + ) + expect(mockPushToolResult).toHaveBeenCalledWith( + "Tool Call Error: use_mcp_tool\n\nInvalid args for test_server:test_tool\n", + ) }) }) diff --git a/src/core/tools/applyDiffTool.ts b/src/core/tools/applyDiffTool.ts index 903e3c846e..abea061ba9 100644 --- a/src/core/tools/applyDiffTool.ts +++ b/src/core/tools/applyDiffTool.ts @@ -13,6 +13,7 @@ import { fileExistsAtPath } from "../../utils/fs" import { RecordSource } from "../context-tracking/FileContextTrackerTypes" import { unescapeHtmlEntities } from "../../utils/text-normalization" import { EXPERIMENT_IDS, experiments } from "../../shared/experiments" +import { t } from "../../i18n" export async function applyDiffToolLegacy( cline: Task, @@ -72,7 +73,7 @@ export async function applyDiffToolLegacy( if (!accessAllowed) { await cline.say("rooignore_error", relPath) - pushToolResult(formatResponse.toolError(formatResponse.rooIgnoreError(relPath))) + pushToolResult(formatResponse.toolError(formatResponse.rooIgnoreError(relPath), "apply_diff")) return } @@ -83,7 +84,9 @@ export async function applyDiffToolLegacy( cline.consecutiveMistakeCount++ cline.recordToolError("apply_diff") const formattedError = `File does not exist at path: ${absolutePath}\n\n\nThe specified file could not be found. Please verify the file path and try again.\n` - await cline.say("error", formattedError) + await cline.say("error", formattedError, undefined, undefined, undefined, undefined, { + title: t("tools:errors.fileNotFound"), + }) pushToolResult(formattedError) return } diff --git a/src/core/tools/askFollowupQuestionTool.ts b/src/core/tools/askFollowupQuestionTool.ts index e736936887..5c4cd7ea73 100644 --- a/src/core/tools/askFollowupQuestionTool.ts +++ b/src/core/tools/askFollowupQuestionTool.ts @@ -2,6 +2,7 @@ import { Task } from "../task/Task" import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools" import { formatResponse } from "../prompts/responses" import { parseXml } from "../../utils/xml" +import { t } from "../../i18n" export async function askFollowupQuestionTool( cline: Task, @@ -48,8 +49,16 @@ export async function askFollowupQuestionTool( } catch (error) { cline.consecutiveMistakeCount++ cline.recordToolError("ask_followup_question") - await cline.say("error", `Failed to parse operations: ${error.message}`) - pushToolResult(formatResponse.toolError("Invalid operations xml format")) + await cline.say( + "error", + `Failed to parse operations: ${error.message}`, + undefined, + undefined, + undefined, + undefined, + { title: t("tools:errors.parseError") }, + ) + pushToolResult(formatResponse.toolError("Invalid operations xml format", "ask_followup_question")) return } diff --git a/src/core/tools/attemptCompletionTool.ts b/src/core/tools/attemptCompletionTool.ts index 5074d7f4e8..36228999c1 100644 --- a/src/core/tools/attemptCompletionTool.ts +++ b/src/core/tools/attemptCompletionTool.ts @@ -1,5 +1,6 @@ import Anthropic from "@anthropic-ai/sdk" import * as vscode from "vscode" +import { t } from "../../i18n" import { RooCodeEventName } from "@roo-code/types" import { TelemetryService } from "@roo-code/telemetry" @@ -45,7 +46,8 @@ export async function attemptCompletionTool( pushToolResult( formatResponse.toolError( - "Cannot complete task while there are incomplete todos. Please finish all todos before attempting completion.", + "Cannot complete task while there are incomplete todos. Please complete all todos before attempting completion.", + "attempt_completion", ), ) @@ -125,7 +127,7 @@ export async function attemptCompletionTool( toolResults.push({ type: "text", - text: `The user has provided feedback on the results. Consider their input to continue the task, and then attempt completion again.\n\n${text}\n`, + text: `${t("tools:attemptCompletion.userFeedbackLead")}\n\n${text}\n`, }) toolResults.push(...formatResponse.imageBlocks(images)) diff --git a/src/core/tools/executeCommandTool.ts b/src/core/tools/executeCommandTool.ts index 2c7ce0d023..d29aaa7c33 100644 --- a/src/core/tools/executeCommandTool.ts +++ b/src/core/tools/executeCommandTool.ts @@ -47,7 +47,12 @@ export async function executeCommandTool( if (ignoredFileAttemptedToAccess) { await task.say("rooignore_error", ignoredFileAttemptedToAccess) - pushToolResult(formatResponse.toolError(formatResponse.rooIgnoreError(ignoredFileAttemptedToAccess))) + pushToolResult( + formatResponse.toolError( + formatResponse.rooIgnoreError(ignoredFileAttemptedToAccess), + "execute_command", + ), + ) return } @@ -121,7 +126,7 @@ export async function executeCommandTool( pushToolResult(result) } else { - pushToolResult(`Command failed to execute in terminal due to a shell integration error.`) + pushToolResult(t("tools:executeCommand.shellIntegrationGenericError")) } } @@ -271,7 +276,15 @@ export async function executeCommand( if (isTimedOut) { const status: CommandExecutionStatus = { executionId, status: "timeout" } provider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) }) - await task.say("error", t("common:errors:command_timeout", { seconds: commandExecutionTimeoutSeconds })) + await task.say( + "error", + t("common:errors.command_timeout", { seconds: commandExecutionTimeoutSeconds }), + undefined, + undefined, + undefined, + undefined, + { title: t("tools:errors.commandTimeout") }, + ) task.terminalProcess = undefined return [ diff --git a/src/core/tools/fetchInstructionsTool.ts b/src/core/tools/fetchInstructionsTool.ts index 5325f98fbf..704e8a3cb1 100644 --- a/src/core/tools/fetchInstructionsTool.ts +++ b/src/core/tools/fetchInstructionsTool.ts @@ -3,6 +3,7 @@ import { fetchInstructions } from "../prompts/instructions/instructions" import { ClineSayTool } from "../../shared/ExtensionMessage" import { formatResponse } from "../prompts/responses" import { ToolUse, AskApproval, HandleError, PushToolResult } from "../../shared/tools" +import { t } from "../../i18n" export async function fetchInstructionsTool( cline: Task, @@ -49,7 +50,12 @@ export async function fetchInstructionsTool( const content = await fetchInstructions(task, { mcpHub, diffStrategy, context }) if (!content) { - pushToolResult(formatResponse.toolError(`Invalid instructions request: ${task}`)) + pushToolResult( + formatResponse.toolError( + t("tools:fetchInstructions.errors.invalidRequest", { defaultValue: "Invalid request" }), + "fetch_instructions", + ), + ) return } diff --git a/src/core/tools/insertContentTool.ts b/src/core/tools/insertContentTool.ts index e22a368167..5bde62f5c3 100644 --- a/src/core/tools/insertContentTool.ts +++ b/src/core/tools/insertContentTool.ts @@ -12,6 +12,7 @@ import { fileExistsAtPath } from "../../utils/fs" import { insertGroups } from "../diff/insert-groups" import { DEFAULT_WRITE_DELAY_MS } from "@roo-code/types" import { EXPERIMENT_IDS, experiments } from "../../shared/experiments" +import { t } from "../../i18n" export async function insertContentTool( cline: Task, @@ -64,7 +65,7 @@ export async function insertContentTool( if (!accessAllowed) { await cline.say("rooignore_error", relPath) - pushToolResult(formatResponse.toolError(formatResponse.rooIgnoreError(relPath))) + pushToolResult(formatResponse.toolError(formatResponse.rooIgnoreError(relPath), "insert_content")) return } @@ -76,7 +77,9 @@ export async function insertContentTool( if (isNaN(lineNumber) || lineNumber < 0) { cline.consecutiveMistakeCount++ cline.recordToolError("insert_content") - pushToolResult(formatResponse.toolError("Invalid line number. Must be a non-negative integer.")) + pushToolResult( + formatResponse.toolError("Invalid line number. Must be a non-negative integer.", "insert_content"), + ) return } @@ -87,7 +90,9 @@ export async function insertContentTool( cline.consecutiveMistakeCount++ cline.recordToolError("insert_content") const formattedError = `Cannot insert content at line ${lineNumber} into a non-existent file. For new files, 'line' must be 0 (to append) or 1 (to insert at the beginning).` - await cline.say("error", formattedError) + await cline.say("error", formattedError, undefined, undefined, undefined, undefined, { + title: "Invalid Line Number", + }) pushToolResult(formattedError) return } @@ -126,7 +131,7 @@ export async function insertContentTool( // For existing files, generate diff and check for changes diff = formatResponse.createPrettyPatch(relPath, fileContent, updatedContent) if (!diff) { - pushToolResult(`No changes needed for '${relPath}'`) + pushToolResult(t("tools:generic.noChanges", { path: relPath })) return } approvalContent = undefined @@ -160,7 +165,7 @@ export async function insertContentTool( if (!isPreventFocusDisruptionEnabled) { await cline.diffViewProvider.revertChanges() } - pushToolResult("Changes were rejected by the user.") + pushToolResult(t("tools:generic.changesRejected")) await cline.diffViewProvider.reset() return } diff --git a/src/core/tools/newTaskTool.ts b/src/core/tools/newTaskTool.ts index aeb0c8393b..d4a45212f4 100644 --- a/src/core/tools/newTaskTool.ts +++ b/src/core/tools/newTaskTool.ts @@ -53,7 +53,7 @@ export async function newTaskTool( const provider = task.providerRef.deref() if (!provider) { - pushToolResult(formatResponse.toolError("Provider reference lost")) + pushToolResult(formatResponse.toolError("Provider reference lost", "new_task")) return } @@ -82,7 +82,9 @@ export async function newTaskTool( } catch (error) { task.consecutiveMistakeCount++ task.recordToolError("new_task") - pushToolResult(formatResponse.toolError("Invalid todos format: must be a markdown checklist")) + pushToolResult( + formatResponse.toolError("Invalid todos format: must be a markdown checklist", "new_task"), + ) return } } @@ -97,7 +99,7 @@ export async function newTaskTool( const targetMode = getModeBySlug(mode, state?.customModes) if (!targetMode) { - pushToolResult(formatResponse.toolError(`Invalid mode: ${mode}`)) + pushToolResult(formatResponse.toolError(`Invalid mode: ${mode}`, "new_task")) return } diff --git a/src/core/tools/searchAndReplaceTool.ts b/src/core/tools/searchAndReplaceTool.ts index 4912934415..0dc03d7385 100644 --- a/src/core/tools/searchAndReplaceTool.ts +++ b/src/core/tools/searchAndReplaceTool.ts @@ -13,6 +13,7 @@ import { fileExistsAtPath } from "../../utils/fs" import { RecordSource } from "../context-tracking/FileContextTrackerTypes" import { DEFAULT_WRITE_DELAY_MS } from "@roo-code/types" import { EXPERIMENT_IDS, experiments } from "../../shared/experiments" +import { t } from "../../i18n" /** * Tool for performing search and replace operations on files @@ -121,7 +122,7 @@ export async function searchAndReplaceTool( if (!accessAllowed) { await cline.say("rooignore_error", validRelPath) - pushToolResult(formatResponse.toolError(formatResponse.rooIgnoreError(validRelPath))) + pushToolResult(formatResponse.toolError(formatResponse.rooIgnoreError(validRelPath), "search_and_replace")) return } @@ -137,7 +138,9 @@ export async function searchAndReplaceTool( const formattedError = formatResponse.toolError( `File does not exist at path: ${absolutePath}\nThe specified file could not be found. Please verify the file path and try again.`, ) - await cline.say("error", formattedError) + await cline.say("error", formattedError, undefined, undefined, undefined, undefined, { + title: t("tools:errors.fileNotFound"), + }) pushToolResult(formattedError) return } @@ -156,7 +159,9 @@ export async function searchAndReplaceTool( error instanceof Error ? error.message : String(error) }\nPlease verify file permissions and try again.` const formattedError = formatResponse.toolError(errorMessage) - await cline.say("error", formattedError) + await cline.say("error", formattedError, undefined, undefined, undefined, undefined, { + title: t("tools:errors.readError"), + }) pushToolResult(formattedError) return } @@ -195,7 +200,7 @@ export async function searchAndReplaceTool( // Generate and validate diff const diff = formatResponse.createPrettyPatch(validRelPath, fileContent, newContent) if (!diff) { - pushToolResult(`No changes needed for '${relPath}'`) + pushToolResult(t("tools:generic.noChanges", { path: relPath })) await cline.diffViewProvider.reset() return } @@ -230,7 +235,7 @@ export async function searchAndReplaceTool( if (!isPreventFocusDisruptionEnabled) { await cline.diffViewProvider.revertChanges() } - pushToolResult("Changes were rejected by the user.") + pushToolResult(t("tools:generic.changesRejected")) await cline.diffViewProvider.reset() return } diff --git a/src/core/tools/switchModeTool.ts b/src/core/tools/switchModeTool.ts index 8ce906b41f..e2cf3b61d0 100644 --- a/src/core/tools/switchModeTool.ts +++ b/src/core/tools/switchModeTool.ts @@ -41,7 +41,7 @@ export async function switchModeTool( if (!targetMode) { cline.recordToolError("switch_mode") - pushToolResult(formatResponse.toolError(`Invalid mode: ${mode_slug}`)) + pushToolResult(formatResponse.toolError(`Invalid mode: ${mode_slug}`, "switch_mode")) return } diff --git a/src/core/tools/updateTodoListTool.ts b/src/core/tools/updateTodoListTool.ts index de96c3cc76..09ef2fc670 100644 --- a/src/core/tools/updateTodoListTool.ts +++ b/src/core/tools/updateTodoListTool.ts @@ -176,7 +176,12 @@ export async function updateTodoListTool( } catch { cline.consecutiveMistakeCount++ cline.recordToolError("update_todo_list") - pushToolResult(formatResponse.toolError("The todos parameter is not valid markdown checklist or JSON")) + pushToolResult( + formatResponse.toolError( + "The todos parameter is not valid markdown checklist or JSON", + "update_todo_list", + ), + ) return } @@ -184,7 +189,7 @@ export async function updateTodoListTool( if (!valid && !block.partial) { cline.consecutiveMistakeCount++ cline.recordToolError("update_todo_list") - pushToolResult(formatResponse.toolError(error || "todos parameter validation failed")) + pushToolResult(formatResponse.toolError(error || "todos parameter validation failed", "update_todo_list")) return } diff --git a/src/core/tools/useMcpToolTool.ts b/src/core/tools/useMcpToolTool.ts index 41697ab979..3d7e608f67 100644 --- a/src/core/tools/useMcpToolTool.ts +++ b/src/core/tools/useMcpToolTool.ts @@ -62,11 +62,20 @@ async function validateParams( } catch (error) { cline.consecutiveMistakeCount++ cline.recordToolError("use_mcp_tool") - await cline.say("error", t("mcp:errors.invalidJsonArgument", { toolName: params.tool_name })) + await cline.say( + "error", + t("mcp:errors.invalidJsonArgument", { toolName: params.tool_name }), + undefined, + undefined, + undefined, + undefined, + { title: t("tools:errors.invalidInput") }, + ) pushToolResult( formatResponse.toolError( formatResponse.invalidMcpToolArgumentError(params.server_name, params.tool_name), + "use_mcp_tool", ), ) return { isValid: false } diff --git a/src/core/tools/writeToFileTool.ts b/src/core/tools/writeToFileTool.ts index e82eab92bc..152813ebbd 100644 --- a/src/core/tools/writeToFileTool.ts +++ b/src/core/tools/writeToFileTool.ts @@ -55,7 +55,7 @@ export async function writeToFileTool( if (!accessAllowed) { await cline.say("rooignore_error", relPath) - pushToolResult(formatResponse.toolError(formatResponse.rooIgnoreError(relPath))) + pushToolResult(formatResponse.toolError(formatResponse.rooIgnoreError(relPath), "write_to_file")) return } @@ -153,6 +153,7 @@ export async function writeToFileTool( pushToolResult( formatResponse.toolError( formatResponse.lineCountTruncationError(actualLineCount, isNewFile, diffStrategyEnabled), + "write_to_file", ), ) await cline.diffViewProvider.revertChanges() @@ -181,6 +182,7 @@ export async function writeToFileTool( `Content appears to be truncated (file has ${ newContent.split("\n").length } lines but was predicted to have ${predictedLineCount} lines), and found comments indicating omitted code (e.g., '// rest of code unchanged', '/* previous code */'). Please provide the complete file content without any omissions if possible, or otherwise use the 'apply_diff' tool to apply the diff to the original file.`, + "write_to_file", ), ) return @@ -254,6 +256,7 @@ export async function writeToFileTool( `Content appears to be truncated (file has ${ newContent.split("\n").length } lines but was predicted to have ${predictedLineCount} lines), and found comments indicating omitted code (e.g., '// rest of code unchanged', '/* previous code */'). Please provide the complete file content without any omissions if possible, or otherwise use the 'apply_diff' tool to apply the diff to the original file.`, + "write_to_file", ), ) return diff --git a/src/i18n/locales/ca/tools.json b/src/i18n/locales/ca/tools.json index 0f10b6fc2a..911c0eaaa3 100644 --- a/src/i18n/locales/ca/tools.json +++ b/src/i18n/locales/ca/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "No s'ha pogut crear una nova tasca a causa de restriccions de política." } + }, + "errors": { + "toolCallError": "Error en cridar l'eina: {{toolName}}", + "toolExecutionError": "Error d'execució de l'eina", + "missingParamForTool": "Roo ha intentat usar {{toolName}} sense valor per al paràmetre obligatori '{{paramName}}'. Tornant-ho a intentar...", + "missingParamForToolWithPath": "Roo ha intentat usar {{toolName}} per a '{{relPath}}' sense valor per al paràmetre obligatori '{{paramName}}'. Tornant-ho a intentar...", + "fileNotFound": "Fitxer no trobat", + "parseError": "Error d'anàlisi", + "commandTimeout": "Temps d'espera de l'ordre exhaurit", + "permissionDenied": "Permís denegat", + "networkError": "Error de xarxa", + "invalidInput": "Entrada no vàlida", + "operationFailed": "L'operació ha fallat", + "resourceNotFound": "Recurs no trobat", + "configurationError": "Error de configuració", + "authenticationFailed": "Error d'autenticació", + "invalidLineNumber": "Invalid Line Number", + "fileAlreadyExists": "File Already Exists", + "directoryNotFound": "Directory Not Found", + "invalidPath": "Invalid Path", + "readError": "Read Error", + "writeError": "Write Error", + "syntaxError": "Syntax Error", + "validationError": "Validation Error", + "timeoutError": "Timeout Error", + "connectionError": "Connection Error" + }, + "executeCommand": { + "workingDirMissing": "Directori de treball no trobat: '{{workingDir}}'", + "shellIntegrationGenericError": "L'execució de l'ordre ha fallat per un error inesperat d'integració del shell." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Sol·licitud d'instruccions no vàlida per a la tasca '{{task}}'." + } + }, + "generic": { + "noChanges": "No calen canvis per a '{{path}}'.", + "changesRejected": "Els canvis han estat rebutjats per l'usuari." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "No es pot completar la tasca mentre hi ha tasques pendents. Si us plau, completa-les abans d'intentar finalitzar." + }, + "userFeedbackLead": "L'usuari ha proporcionat comentaris sobre els resultats. Tingues-los en compte per continuar la tasca i intenta finalitzar de nou." } } diff --git a/src/i18n/locales/de/tools.json b/src/i18n/locales/de/tools.json index ecf372a50b..2182af3720 100644 --- a/src/i18n/locales/de/tools.json +++ b/src/i18n/locales/de/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "Neue Aufgabe konnte aufgrund von Richtlinienbeschränkungen nicht erstellt werden." } + }, + "errors": { + "toolCallError": "Tool-Aufruffehler: {{toolName}}", + "toolExecutionError": "Tool-Ausführungsfehler", + "missingParamForTool": "Roo hat versucht, {{toolName}} ohne Wert für den erforderlichen Parameter '{{paramName}}' zu verwenden. Erneuter Versuch...", + "missingParamForToolWithPath": "Roo hat versucht, {{toolName}} für '{{relPath}}' ohne Wert für den erforderlichen Parameter '{{paramName}}' zu verwenden. Erneuter Versuch...", + "fileNotFound": "Datei nicht gefunden", + "parseError": "Parse-Fehler", + "commandTimeout": "Befehl Zeitüberschreitung", + "permissionDenied": "Zugriff verweigert", + "networkError": "Netzwerkfehler", + "invalidInput": "Ungültige Eingabe", + "operationFailed": "Vorgang fehlgeschlagen", + "resourceNotFound": "Ressource nicht gefunden", + "configurationError": "Konfigurationsfehler", + "authenticationFailed": "Authentifizierung fehlgeschlagen", + "invalidLineNumber": "Invalid Line Number", + "fileAlreadyExists": "File Already Exists", + "directoryNotFound": "Directory Not Found", + "invalidPath": "Invalid Path", + "readError": "Read Error", + "writeError": "Write Error", + "syntaxError": "Syntax Error", + "validationError": "Validation Error", + "timeoutError": "Timeout Error", + "connectionError": "Connection Error" + }, + "executeCommand": { + "workingDirMissing": "Arbeitsverzeichnis nicht gefunden: '{{workingDir}}'", + "shellIntegrationGenericError": "Befehlsausführung aufgrund unerwarteten Shell-Integrationsfehlers fehlgeschlagen." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Ungültige Anforderungsanweisung für Aufgabe '{{task}}'." + } + }, + "generic": { + "noChanges": "Keine Änderungen erforderlich für '{{path}}'.", + "changesRejected": "Änderungen wurden vom Nutzer abgelehnt." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "Aufgabe kann nicht abgeschlossen werden, solange To-Dos offen sind. Bitte zuerst abschließen." + }, + "userFeedbackLead": "Der Nutzer hat Feedback zu den Ergebnissen gegeben. Berücksichtige es, fahre fort und versuche erneut abzuschließen." } } diff --git a/src/i18n/locales/en/tools.json b/src/i18n/locales/en/tools.json index 5b88affae6..3e683c481c 100644 --- a/src/i18n/locales/en/tools.json +++ b/src/i18n/locales/en/tools.json @@ -14,5 +14,42 @@ "errors": { "policy_restriction": "Failed to create new task due to policy restrictions." } + }, + "executeCommand": { + "workingDirMissing": "Working directory '{{workingDir}}' does not exist.", + "shellIntegrationGenericError": "Command execution failed due to an unexpected shell integration error." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Invalid request" + } + }, + "generic": { + "noChanges": "No changes needed for '{{path}}'.", + "changesRejected": "Changes were rejected by the user." + }, + "errors": { + "toolCallError": "Tool Call Error: {{toolName}}", + "toolExecutionError": "Tool Execution Error", + "fileNotFound": "File Not Found", + "parseError": "Parse error", + "commandTimeout": "Command timeout", + "permissionDenied": "Permission denied", + "networkError": "Network error", + "invalidInput": "Invalid input", + "operationFailed": "Operation failed", + "resourceNotFound": "Resource not found", + "configurationError": "Configuration error", + "authenticationFailed": "Authentication failed", + "invalidLineNumber": "Invalid Line Number", + "fileAlreadyExists": "File already exists", + "directoryNotFound": "Directory not found", + "invalidPath": "Invalid path", + "readError": "File Read Error", + "writeError": "Write error", + "syntaxError": "Syntax error", + "validationError": "Validation error", + "timeoutError": "Timeout error", + "connectionError": "Connection error" } } diff --git a/src/i18n/locales/es/tools.json b/src/i18n/locales/es/tools.json index 6fd1cc2122..94c0508cd0 100644 --- a/src/i18n/locales/es/tools.json +++ b/src/i18n/locales/es/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "No se pudo crear una nueva tarea debido a restricciones de política." } + }, + "errors": { + "toolCallError": "Error de llamada de herramienta: {{toolName}}", + "toolExecutionError": "Error de ejecución de la herramienta", + "missingParamForTool": "Roo intentó usar {{toolName}} sin valor para el parámetro requerido '{{paramName}}'. Reintentando...", + "missingParamForToolWithPath": "Roo intentó usar {{toolName}} para '{{relPath}}' sin valor para el parámetro requerido '{{paramName}}'. Reintentando...", + "fileNotFound": "Archivo no encontrado", + "parseError": "Error de análisis", + "commandTimeout": "Tiempo de espera del comando agotado", + "permissionDenied": "Permiso denegado", + "networkError": "Error de red", + "invalidInput": "Entrada no válida", + "operationFailed": "La operación falló", + "resourceNotFound": "Recurso no encontrado", + "configurationError": "Error de configuración", + "authenticationFailed": "Fallo de autenticación", + "invalidLineNumber": "Invalid Line Number", + "fileAlreadyExists": "File Already Exists", + "directoryNotFound": "Directory Not Found", + "invalidPath": "Invalid Path", + "readError": "Read Error", + "writeError": "Write Error", + "syntaxError": "Syntax Error", + "validationError": "Validation Error", + "timeoutError": "Timeout Error", + "connectionError": "Connection Error" + }, + "executeCommand": { + "workingDirMissing": "Directorio de trabajo no encontrado: '{{workingDir}}'", + "shellIntegrationGenericError": "La ejecución del comando falló debido a un error inesperado de integración del shell." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Solicitud de instrucciones inválida para la tarea '{{task}}'." + } + }, + "generic": { + "noChanges": "No se necesitan cambios para '{{path}}'.", + "changesRejected": "Los cambios fueron rechazados por el usuario." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "No se puede completar la tarea mientras hay pendientes. Por favor, termínalos antes de intentar finalizar." + }, + "userFeedbackLead": "El usuario ha proporcionado comentarios sobre los resultados. Tenlos en cuenta para continuar la tarea y vuelve a intentar finalizar." } } diff --git a/src/i18n/locales/fr/tools.json b/src/i18n/locales/fr/tools.json index b6d7accebb..b4de096f5d 100644 --- a/src/i18n/locales/fr/tools.json +++ b/src/i18n/locales/fr/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "Impossible de créer une nouvelle tâche en raison de restrictions de politique." } + }, + "errors": { + "toolCallError": "Erreur d'appel d'outil : {{toolName}}", + "toolExecutionError": "Erreur d'exécution de l'outil", + "missingParamForTool": "Roo a essayé d'utiliser {{toolName}} sans valeur pour le paramètre obligatoire '{{paramName}}'. Nouvel essai...", + "missingParamForToolWithPath": "Roo a essayé d'utiliser {{toolName}} pour '{{relPath}}' sans valeur pour le paramètre obligatoire '{{paramName}}'. Nouvel essai...", + "fileNotFound": "Fichier non trouvé", + "parseError": "Erreur d'analyse", + "commandTimeout": "Délai d'attente de la commande dépassé", + "permissionDenied": "Autorisation refusée", + "networkError": "Erreur réseau", + "invalidInput": "Entrée invalide", + "operationFailed": "L'opération a échoué", + "resourceNotFound": "Ressource non trouvée", + "configurationError": "Erreur de configuration", + "authenticationFailed": "Échec de l'authentification", + "invalidLineNumber": "Numéro de ligne invalide", + "fileAlreadyExists": "Le fichier existe déjà", + "directoryNotFound": "Répertoire non trouvé", + "invalidPath": "Chemin invalide", + "readError": "Erreur de lecture", + "writeError": "Erreur d'écriture", + "syntaxError": "Erreur de syntaxe", + "validationError": "Erreur de validation", + "timeoutError": "Erreur de délai d'attente", + "connectionError": "Erreur de connexion" + }, + "executeCommand": { + "workingDirMissing": "Répertoire de travail introuvable : '{{workingDir}}'", + "shellIntegrationGenericError": "L'exécution de la commande a échoué en raison d'une erreur inattendue d'intégration du shell." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Demande d'instructions non valide pour la tâche '{{task}}'." + } + }, + "generic": { + "noChanges": "Aucune modification n'est nécessaire pour '{{path}}'.", + "changesRejected": "Les modifications ont été rejetées par l'utilisateur." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "Impossible de terminer la tâche tant qu'il y a des tâches incomplètes. Veuillez terminer toutes les tâches avant de tenter de la terminer." + }, + "userFeedbackLead": "L'utilisateur a fourni des commentaires sur les résultats. Tenez compte de leurs commentaires pour poursuivre la tâche, puis tentez à nouveau de la terminer." } } diff --git a/src/i18n/locales/hi/tools.json b/src/i18n/locales/hi/tools.json index cbfbd7aef7..3050e8d2b9 100644 --- a/src/i18n/locales/hi/tools.json +++ b/src/i18n/locales/hi/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "नीति प्रतिबंधों के कारण नया कार्य बनाने में विफल।" } + }, + "errors": { + "toolCallError": "टूल कॉल त्रुटि: {{toolName}}", + "toolExecutionError": "उपकरण निष्पादन त्रुटि", + "missingParamForTool": "रू ने आवश्यक पैरामीटर '{{paramName}}' के मान के बिना {{toolName}} का उपयोग करने का प्रयास किया। पुन: प्रयास किया जा रहा है...", + "missingParamForToolWithPath": "रू ने '{{relPath}}' के लिए {{toolName}} का उपयोग करने के लिए आवश्यक पैरामीटर '{{paramName}}' के बिना प्रयास किया। पुन: प्रयास किया जा रहा है...", + "fileNotFound": "फ़ाइल नहीं मिली", + "parseError": "पार्स त्रुटि", + "commandTimeout": "कमांड टाइमआउट", + "permissionDenied": "अनुमति अस्वीकृत", + "networkError": "नेटवर्क त्रुटि", + "invalidInput": "अमान्य इनपुट", + "operationFailed": "ऑपरेशन विफल", + "resourceNotFound": "संसाधन नहीं मिला", + "configurationError": "कॉन्फ़िगरेशन त्रुटि", + "authenticationFailed": "प्रमाणीकरण विफल", + "invalidLineNumber": "अमान्य पंक्ति संख्या", + "fileAlreadyExists": "फ़ाइल पहले से मौजूद है", + "directoryNotFound": "निर्देशिका नहीं मिली", + "invalidPath": "अमान्य पथ", + "readError": "त्रुटि पढ़ें", + "writeError": "लिखने में त्रुटि", + "syntaxError": "सिंटैक्स त्रुटि", + "validationError": "सत्यापन त्रुटि", + "timeoutError": "समय समाप्ति त्रुटि", + "connectionError": "कनेक्शन त्रुटि" + }, + "executeCommand": { + "workingDirMissing": "कार्यरत निर्देशिका नहीं मिली: '{{workingDir}}'", + "shellIntegrationGenericError": "अप्रत्याशित शेल एकीकरण त्रुटि के कारण कमांड निष्पादन विफल रहा।" + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "कार्य '{{task}}' के लिए अमान्य निर्देश अनुरोध।" + } + }, + "generic": { + "noChanges": "'{{path}}' के लिए किसी बदलाव की आवश्यकता नहीं है।", + "changesRejected": "बदलाव उपयोगकर्ता द्वारा अस्वीकार कर दिए गए थे।" + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "कार्य पूरा नहीं किया जा सकता है जबकि अधूरे कार्य हैं। कृपया पूरा करने का प्रयास करने से पहले सभी कार्यों को पूरा करें।" + }, + "userFeedbackLead": "उपयोगकर्ता ने परिणामों पर प्रतिक्रिया प्रदान की है। कार्य को जारी रखने के लिए उनके इनपुट पर विचार करें, और फिर पूरा करने का प्रयास करें।" } } diff --git a/src/i18n/locales/id/tools.json b/src/i18n/locales/id/tools.json index 3eb8854eff..83db6cb396 100644 --- a/src/i18n/locales/id/tools.json +++ b/src/i18n/locales/id/tools.json @@ -17,5 +17,50 @@ "errors": { "policy_restriction": "Gagal membuat tugas baru karena pembatasan kebijakan." } + }, + "errors": { + "toolCallError": "Kesalahan Panggilan Alat: {{toolName}}", + "toolExecutionError": "Kesalahan Eksekusi Alat", + "missingParamForTool": "Roo mencoba menggunakan {{toolName}} tanpa nilai untuk parameter yang diperlukan '{{paramName}}'. Mencoba lagi...", + "missingParamForToolWithPath": "Roo mencoba menggunakan {{toolName}} untuk '{{relPath}}' tanpa nilai untuk parameter yang diperlukan '{{paramName}}'. Mencoba lagi...", + "fileNotFound": "File Tidak Ditemukan", + "parseError": "Kesalahan Parse", + "commandTimeout": "Waktu Tunggu Perintah Habis", + "permissionDenied": "Izin Ditolak", + "networkError": "Kesalahan Jaringan", + "invalidInput": "Input Tidak Valid", + "operationFailed": "Operasi Gagal", + "resourceNotFound": "Sumber Daya Tidak Ditemukan", + "configurationError": "Kesalahan Konfigurasi", + "authenticationFailed": "Autentikasi Gagal", + "invalidLineNumber": "Nomor baris tidak valid", + "fileAlreadyExists": "File sudah ada", + "directoryNotFound": "Direktori tidak ditemukan", + "invalidPath": "Path tidak valid", + "readError": "Kesalahan baca", + "writeError": "Kesalahan tulis", + "syntaxError": "Kesalahan sintaks", + "validationError": "Kesalahan validasi", + "timeoutError": "Kesalahan batas waktu", + "connectionError": "Kesalahan koneksi" + }, + "executeCommand": { + "workingDirMissing": "Direktori kerja tidak ditemukan: '{{workingDir}}'", + "shellIntegrationGenericError": "Eksekusi perintah gagal karena kesalahan integrasi shell yang tidak terduga." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Permintaan instruksi tidak valid untuk tugas '{{task}}'." + } + }, + "generic": { + "noChanges": "Tidak ada perubahan yang diperlukan untuk '{{path}}'.", + "changesRejected": "Perubahan ditolak oleh pengguna." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "Tidak dapat menyelesaikan tugas saat ada tugas yang belum selesai. Harap selesaikan semua tugas sebelum mencoba penyelesaian." + }, + "userFeedbackLead": "Pengguna telah memberikan umpan balik tentang hasilnya. Pertimbangkan masukan mereka untuk melanjutkan tugas, lalu coba selesaikan lagi." } } diff --git a/src/i18n/locales/it/tools.json b/src/i18n/locales/it/tools.json index 35b114a719..8173f88621 100644 --- a/src/i18n/locales/it/tools.json +++ b/src/i18n/locales/it/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "Impossibile creare una nuova attività a causa di restrizioni di policy." } + }, + "errors": { + "toolCallError": "Errore di chiamata dello strumento: {{toolName}}", + "toolExecutionError": "Errore di esecuzione dello strumento", + "missingParamForTool": "Roo ha tentato di utilizzare {{toolName}} senza valore per il parametro obbligatorio '{{paramName}}'. Nuovo tentativo...", + "missingParamForToolWithPath": "Roo ha tentato di utilizzare {{toolName}} per '{{relPath}}' senza valore per il parametro obbligatorio '{{paramName}}'. Nuovo tentativo...", + "fileNotFound": "File non trovato", + "parseError": "Errore di parsing", + "commandTimeout": "Timeout del comando", + "permissionDenied": "Permesso negato", + "networkError": "Errore di rete", + "invalidInput": "Input non valido", + "operationFailed": "Operazione non riuscita", + "resourceNotFound": "Risorsa non trovata", + "configurationError": "Errore di configurazione", + "authenticationFailed": "Autenticazione non riuscita", + "invalidLineNumber": "Numero di riga non valido", + "fileAlreadyExists": "Il file esiste già", + "directoryNotFound": "Directory non trovata", + "invalidPath": "Percorso non valido", + "readError": "Errore di lettura", + "writeError": "Errore di scrittura", + "syntaxError": "Errore di sintassi", + "validationError": "Errore di convalida", + "timeoutError": "Errore di timeout", + "connectionError": "Errore di connessione" + }, + "executeCommand": { + "workingDirMissing": "Directory di lavoro non trovata: '{{workingDir}}'", + "shellIntegrationGenericError": "L'esecuzione del comando non è riuscita a causa di un errore di integrazione della shell imprevisto." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Richiesta di istruzioni non valida per l'attività '{{task}}'." + } + }, + "generic": { + "noChanges": "Nessuna modifica necessaria per '{{path}}'.", + "changesRejected": "Le modifiche sono state rifiutate dall'utente." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "Impossibile completare l'attività finché ci sono cose da fare incomplete. Finisci tutte le cose da fare prima di tentare il completamento." + }, + "userFeedbackLead": "L'utente ha fornito un feedback sui risultati. Considera il loro input per continuare l'attività, quindi tenta di nuovo il completamento." } } diff --git a/src/i18n/locales/ja/tools.json b/src/i18n/locales/ja/tools.json index 257d5aa201..31f5baf48a 100644 --- a/src/i18n/locales/ja/tools.json +++ b/src/i18n/locales/ja/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "ポリシー制限により新しいタスクを作成できませんでした。" } + }, + "errors": { + "toolCallError": "ツール呼び出しエラー: {{toolName}}", + "toolExecutionError": "ツール実行エラー", + "missingParamForTool": "Roo が必須パラメータ '{{paramName}}' の値なしで {{toolName}} を使用しようとしました。再试行...", + "missingParamForToolWithPath": "Roo が '{{relPath}}' の {{toolName}} を必須パラメータ '{{paramName}}' の値なしで使用しようとしました。再试行...", + "fileNotFound": "ファイルが見つかりません", + "parseError": "解析エラー", + "commandTimeout": "コマンドタイムアウト", + "permissionDenied": "権限がありません", + "networkError": "ネットワークエラー", + "invalidInput": "無効な入力", + "operationFailed": "操作に失敗しました", + "resourceNotFound": "リソースが見つかりません", + "configurationError": "設定エラー", + "authenticationFailed": "認証に失敗しました", + "invalidLineNumber": "無効な行番号です", + "fileAlreadyExists": "ファイルは既に存在します", + "directoryNotFound": "ディレクトリが見つかりません", + "invalidPath": "無効なパスです", + "readError": "読み取りエラー", + "writeError": "書き込みエラー", + "syntaxError": "構文エラー", + "validationError": "検証エラー", + "timeoutError": "タイムアウトエラー", + "connectionError": "接続エラー" + }, + "executeCommand": { + "workingDirMissing": "作業ディレクトリが見つかりません: '{{workingDir}}'", + "shellIntegrationGenericError": "予期しないシェル統合エラーのため、コマンドの実行に失敗しました。" + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "タスク '{{task}}' の指示要求が無効です。" + } + }, + "generic": { + "noChanges": "'{{path}}' には変更は必要ありません。", + "changesRejected": "変更はユーザーによって拒否されました。" + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "未完了の ToDo があるため、タスクを完了できません。完了を試みる前に、すべての ToDo を完了してください。" + }, + "userFeedbackLead": "ユーザーが結果に関するフィードバックを提供しました。タスクを続行するには、ユーザーの入力を考慮し、再度完了を試みてください。" } } diff --git a/src/i18n/locales/ko/tools.json b/src/i18n/locales/ko/tools.json index 94b6d8c377..24de07bb21 100644 --- a/src/i18n/locales/ko/tools.json +++ b/src/i18n/locales/ko/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "정책 제한으로 인해 새 작업을 생성하지 못했습니다." } + }, + "errors": { + "toolCallError": "도구 호출 오류: {{toolName}}", + "toolExecutionError": "도구 실행 오류", + "missingParamForTool": "Roo가 필수 매개변수 '{{paramName}}'에 대한 값 없이 {{toolName}}을(를) 사용하려고 했습니다. 다시 시도하는 중...", + "missingParamForToolWithPath": "Roo가 '{{relPath}}'에 대해 필수 매개변수 '{{paramName}}'에 대한 값 없이 {{toolName}}을(를) 사용하려고 했습니다. 다시 시도하는 중...", + "fileNotFound": "파일을 찾을 수 없음", + "parseError": "파싱 오류", + "commandTimeout": "명령 시간 초과", + "permissionDenied": "권한 거부됨", + "networkError": "네트워크 오류", + "invalidInput": "잘못된 입력", + "operationFailed": "작업 실패", + "resourceNotFound": "리소스를 찾을 수 없음", + "configurationError": "구성 오류", + "authenticationFailed": "인증 실패", + "invalidLineNumber": "잘못된 줄 번호", + "fileAlreadyExists": "파일이 이미 있습니다", + "directoryNotFound": "디렉토리를 찾을 수 없습니다", + "invalidPath": "잘못된 경로", + "readError": "읽기 오류", + "writeError": "쓰기 오류", + "syntaxError": "구문 오류", + "validationError": "유효성 검사 오류", + "timeoutError": "시간 초과 오류", + "connectionError": "연결 오류" + }, + "executeCommand": { + "workingDirMissing": "작업 디렉터리를 찾을 수 없음: '{{workingDir}}'", + "shellIntegrationGenericError": "예상치 못한 셸 통합 오류로 인해 명령 실행에 실패했습니다." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "'{{task}}' 작업에 대한 잘못된 지침 요청입니다." + } + }, + "generic": { + "noChanges": "'{{path}}'에 필요한 변경 사항이 없습니다.", + "changesRejected": "사용자가 변경 사항을 거부했습니다." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "완료되지 않은 할 일이 있는 동안에는 작업을 완료할 수 없습니다. 완료를 시도하기 전에 모든 할 일을 완료하십시오." + }, + "userFeedbackLead": "사용자가 결과에 대한 피드백을 제공했습니다. 작업을 계속하려면 사용자의 의견을 고려한 다음 다시 완료를 시도하십시오." } } diff --git a/src/i18n/locales/nl/tools.json b/src/i18n/locales/nl/tools.json index 449cd54583..6d5865a4f3 100644 --- a/src/i18n/locales/nl/tools.json +++ b/src/i18n/locales/nl/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "Kan geen nieuwe taak aanmaken vanwege beleidsbeperkingen." } + }, + "errors": { + "toolCallError": "Fout bij het aanroepen van gereedschap: {{toolName}}", + "toolExecutionError": "Fout bij het uitvoeren van gereedschap", + "missingParamForTool": "Roo heeft geprobeerd {{toolName}} te gebruiken zonder waarde voor de vereiste parameter '{{paramName}}'. Opnieuw proberen...", + "missingParamForToolWithPath": "Roo heeft geprobeerd {{toolName}} te gebruiken voor '{{relPath}}' zonder waarde voor de vereiste parameter '{{paramName}}'. Opnieuw proberen...", + "fileNotFound": "Bestand niet gevonden", + "parseError": "Parseerfout", + "commandTimeout": "Commando time-out", + "permissionDenied": "Toestemming geweigerd", + "networkError": "Netwerkfout", + "invalidInput": "Ongeldige invoer", + "operationFailed": "Bewerking mislukt", + "resourceNotFound": "Bron niet gevonden", + "configurationError": "Configuratiefout", + "authenticationFailed": "Authenticatie mislukt", + "invalidLineNumber": "Ongeldig regelnummer", + "fileAlreadyExists": "Bestand bestaat al", + "directoryNotFound": "Map niet gevonden", + "invalidPath": "Ongeldig pad", + "readError": "Leesfout", + "writeError": "Schrijffout", + "syntaxError": "Syntaxisfout", + "validationError": "Validatiefout", + "timeoutError": "Time-outfout", + "connectionError": "Verbindingsfout" + }, + "executeCommand": { + "workingDirMissing": "Werkmap niet gevonden: '{{workingDir}}'", + "shellIntegrationGenericError": "Uitvoering van opdracht mislukt vanwege onverwachte fout bij shell-integratie." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Ongeldig instructieverzoek voor taak '{{task}}'." + } + }, + "generic": { + "noChanges": "Geen wijzigingen nodig voor '{{path}}'.", + "changesRejected": "Wijzigingen zijn afgewezen door de gebruiker." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "Kan taak niet voltooien zolang er onvolledige todos zijn. Voltooi alle todos voordat u probeert te voltooien." + }, + "userFeedbackLead": "De gebruiker heeft feedback gegeven over de resultaten. Overweeg hun input om de taak voort te zetten en probeer dan opnieuw te voltooien." } } diff --git a/src/i18n/locales/pl/tools.json b/src/i18n/locales/pl/tools.json index 979b2f54ae..7079ed8e54 100644 --- a/src/i18n/locales/pl/tools.json +++ b/src/i18n/locales/pl/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "Nie udało się utworzyć nowego zadania z powodu ograniczeń polityki." } + }, + "errors": { + "toolCallError": "Błąd wywołania narzędzia: {{toolName}}", + "toolExecutionError": "Błąd wykonania narzędzia", + "missingParamForTool": "Roo próbował użyć {{toolName}} bez wartości dla wymaganego parametru '{{paramName}}'. Ponawianie...", + "missingParamForToolWithPath": "Roo próbował użyć {{toolName}} dla '{{relPath}}' bez wartości dla wymaganego parametru '{{paramName}}'. Ponawianie...", + "fileNotFound": "Nie znaleziono pliku", + "parseError": "Błąd parsowania", + "commandTimeout": "Przekroczono limit czasu polecenia", + "permissionDenied": "Odmowa dostępu", + "networkError": "Błąd sieci", + "invalidInput": "Nieprawidłowe dane wejściowe", + "operationFailed": "Operacja nie powiodła się", + "resourceNotFound": "Nie znaleziono zasobu", + "configurationError": "Błąd konfiguracji", + "authenticationFailed": "Uwierzytelnianie nie powiodło się", + "invalidLineNumber": "Nieprawidłowy numer wiersza", + "fileAlreadyExists": "Plik już istnieje", + "directoryNotFound": "Nie znaleziono katalogu", + "invalidPath": "Nieprawidłowa ścieżka", + "readError": "Błąd odczytu", + "writeError": "Błąd zapisu", + "syntaxError": "Błąd składni", + "validationError": "Błąd walidacji", + "timeoutError": "Błąd limitu czasu", + "connectionError": "Błąd połączenia" + }, + "executeCommand": { + "workingDirMissing": "Nie znaleziono katalogu roboczego: '{{workingDir}}'", + "shellIntegrationGenericError": "Wykonanie polecenia nie powiodło się z powodu nieoczekiwanego błędu integracji powłoki." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Nieprawidłowe żądanie instrukcji dla zadania '{{task}}'." + } + }, + "generic": { + "noChanges": "Brak koniecznych zmian dla '{{path}}'.", + "changesRejected": "Zmiany zostały odrzucone przez użytkownika." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "Nie można ukończyć zadania, gdy istnieją nieukończone zadania. Ukończ wszystkie zadania przed próbą ukończenia." + }, + "userFeedbackLead": "Użytkownik wyraził opinię na temat wyników. Rozważ jego uwagi, aby kontynuować zadanie, a następnie spróbuj ponownie je ukończyć." } } diff --git a/src/i18n/locales/pt-BR/tools.json b/src/i18n/locales/pt-BR/tools.json index 4e3296fd4a..969bc778e2 100644 --- a/src/i18n/locales/pt-BR/tools.json +++ b/src/i18n/locales/pt-BR/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "Falha ao criar nova tarefa devido a restrições de política." } + }, + "errors": { + "toolCallError": "Erro na chamada da ferramenta: {{toolName}}", + "toolExecutionError": "Erro na execução da ferramenta", + "missingParamForTool": "Roo tentou usar {{toolName}} sem valor para o parâmetro obrigatório '{{paramName}}'. Tentando novamente...", + "missingParamForToolWithPath": "Roo tentou usar {{toolName}} para '{{relPath}}' sem valor para o parâmetro obrigatório '{{paramName}}'. Tentando novamente...", + "fileNotFound": "Arquivo não encontrado", + "parseError": "Erro de análise", + "commandTimeout": "Tempo limite do comando", + "permissionDenied": "Permissão negada", + "networkError": "Erro de rede", + "invalidInput": "Entrada inválida", + "operationFailed": "A operação falhou", + "resourceNotFound": "Recurso não encontrado", + "configurationError": "Erro de configuração", + "authenticationFailed": "Falha na autenticação", + "invalidLineNumber": "Invalid Line Number", + "fileAlreadyExists": "File Already Exists", + "directoryNotFound": "Directory Not Found", + "invalidPath": "Invalid Path", + "readError": "Read Error", + "writeError": "Write Error", + "syntaxError": "Syntax Error", + "validationError": "Validation Error", + "timeoutError": "Timeout Error", + "connectionError": "Connection Error" + }, + "executeCommand": { + "workingDirMissing": "Diretório de trabalho não encontrado: '{{workingDir}}'", + "shellIntegrationGenericError": "A execução do comando falhou devido a um erro inesperado de integração do shell." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Solicitação de instruções inválida para a tarefa '{{task}}'." + } + }, + "generic": { + "noChanges": "Nenhuma alteração necessária para '{{path}}'.", + "changesRejected": "As alterações foram rejeitadas pelo usuário." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "Não é possível concluir a tarefa enquanto houver pendências. Conclua-as antes de tentar finalizar." + }, + "userFeedbackLead": "O usuário forneceu feedback sobre os resultados. Considere-o para continuar a tarefa e tente finalizar novamente." } } diff --git a/src/i18n/locales/ru/tools.json b/src/i18n/locales/ru/tools.json index d74918f058..ba9552e945 100644 --- a/src/i18n/locales/ru/tools.json +++ b/src/i18n/locales/ru/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "Не удалось создать новую задачу из-за ограничений политики." } + }, + "errors": { + "toolCallError": "Ошибка вызова инструмента: {{toolName}}", + "toolExecutionError": "Ошибка выполнения инструмента", + "missingParamForTool": "Roo попытался использовать {{toolName}} без значения для обязательного параметра '{{paramName}}'. Повтор...", + "missingParamForToolWithPath": "Roo попытался использовать {{toolName}} для '{{relPath}}' без значения для обязательного параметра '{{paramName}}'. Повтор...", + "fileNotFound": "Файл не найден", + "parseError": "Ошибка синтаксического анализа", + "commandTimeout": "Тайм-аут команды", + "permissionDenied": "В доступе отказано", + "networkError": "Сетевая ошибка", + "invalidInput": "Неверный ввод", + "operationFailed": "Операция не удалась", + "resourceNotFound": "Ресурс не найден", + "configurationError": "Ошибка конфигурации", + "authenticationFailed": "Сбой аутентификации", + "invalidLineNumber": "Invalid Line Number", + "fileAlreadyExists": "File Already Exists", + "directoryNotFound": "Directory Not Found", + "invalidPath": "Invalid Path", + "readError": "Read Error", + "writeError": "Write Error", + "syntaxError": "Syntax Error", + "validationError": "Validation Error", + "timeoutError": "Timeout Error", + "connectionError": "Connection Error" + }, + "executeCommand": { + "workingDirMissing": "Рабочий каталог не найден: '{{workingDir}}'", + "shellIntegrationGenericError": "Выполнение команды не удалось из-за неожиданной ошибки интеграции оболочки." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Недопустимый запрос инструкций для задачи '{{task}}'." + } + }, + "generic": { + "noChanges": "Изменения для '{{path}}' не требуются.", + "changesRejected": "Изменения были отклонены пользователем." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "Невозможно завершить задачу при наличии незавершённых пунктов. Сначала завершите их." + }, + "userFeedbackLead": "Пользователь предоставил отзыв о результатах. Учитывайте его, чтобы продолжить, и попробуйте завершить снова." } } diff --git a/src/i18n/locales/tr/tools.json b/src/i18n/locales/tr/tools.json index 5341a23cb1..e676c8e030 100644 --- a/src/i18n/locales/tr/tools.json +++ b/src/i18n/locales/tr/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "Politika kısıtlamaları nedeniyle yeni görev oluşturulamadı." } + }, + "errors": { + "toolCallError": "Araç çağrı hatası: {{toolName}}", + "toolExecutionError": "Araç yürütme hatası", + "missingParamForTool": "Roo, {{toolName}} kullanırken gerekli '{{paramName}}' parametresi olmadan denedi. Tekrar deneniyor...", + "missingParamForToolWithPath": "Roo, '{{relPath}}' için {{toolName}} kullanırken gerekli '{{paramName}}' parametresi olmadan denedi. Tekrar deneniyor...", + "fileNotFound": "Dosya Bulunamadı", + "parseError": "Ayrıştırma Hatası", + "commandTimeout": "Komut Zaman Aşımı", + "permissionDenied": "İzin Reddedildi", + "networkError": "Ağ Hatası", + "invalidInput": "Geçersiz Giriş", + "operationFailed": "İşlem Başarısız Oldu", + "resourceNotFound": "Kaynak Bulunamadı", + "configurationError": "Yapılandırma Hatası", + "authenticationFailed": "Kimlik Doğrulama Başarısız", + "invalidLineNumber": "Invalid Line Number", + "fileAlreadyExists": "File Already Exists", + "directoryNotFound": "Directory Not Found", + "invalidPath": "Invalid Path", + "readError": "Read Error", + "writeError": "Write Error", + "syntaxError": "Syntax Error", + "validationError": "Validation Error", + "timeoutError": "Timeout Error", + "connectionError": "Connection Error" + }, + "executeCommand": { + "workingDirMissing": "Çalışma dizini bulunamadı: '{{workingDir}}'", + "shellIntegrationGenericError": "Beklenmeyen shell entegrasyonu hatası nedeniyle komut yürütme başarısız oldu." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Görev '{{task}}' için geçersiz talimat isteği." + } + }, + "generic": { + "noChanges": "'{{path}}' için değişiklik gerekmez.", + "changesRejected": "Değişiklikler kullanıcı tarafından reddedildi." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "Tamamlanmamış yapılacaklar varken görev tamamlanamaz. Lütfen önce bitirin." + }, + "userFeedbackLead": "Kullanıcı sonuçlara ilişkin geri bildirim verdi. Bunu dikkate al, devam et ve tekrar tamamlamayı dene." } } diff --git a/src/i18n/locales/vi/tools.json b/src/i18n/locales/vi/tools.json index 4c5080a146..77a2b0ab64 100644 --- a/src/i18n/locales/vi/tools.json +++ b/src/i18n/locales/vi/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "Không thể tạo nhiệm vụ mới do hạn chế chính sách." } + }, + "errors": { + "toolCallError": "Lỗi gọi công cụ: {{toolName}}", + "toolExecutionError": "Lỗi thực thi công cụ", + "missingParamForTool": "Roo đã cố dùng {{toolName}} mà không có giá trị cho tham số bắt buộc '{{paramName}}'. Đang thử lại...", + "missingParamForToolWithPath": "Roo đã cố dùng {{toolName}} cho '{{relPath}}' mà không có giá trị cho tham số bắt buộc '{{paramName}}'. Đang thử lại...", + "fileNotFound": "Không tìm thấy tệp", + "parseError": "Lỗi phân tích cú pháp", + "commandTimeout": "Hết thời gian chờ lệnh", + "permissionDenied": "Quyền bị từ chối", + "networkError": "Lỗi mạng", + "invalidInput": "Đầu vào không hợp lệ", + "operationFailed": "Thao tác thất bại", + "resourceNotFound": "Không tìm thấy tài nguyên", + "configurationError": "Lỗi cấu hình", + "authenticationFailed": "Xác thực không thành công", + "invalidLineNumber": "Invalid Line Number", + "fileAlreadyExists": "File Already Exists", + "directoryNotFound": "Directory Not Found", + "invalidPath": "Invalid Path", + "readError": "Read Error", + "writeError": "Write Error", + "syntaxError": "Syntax Error", + "validationError": "Validation Error", + "timeoutError": "Timeout Error", + "connectionError": "Connection Error" + }, + "executeCommand": { + "workingDirMissing": "Không tìm thấy thư mục làm việc: '{{workingDir}}'", + "shellIntegrationGenericError": "Thực thi lệnh thất bại do lỗi tích hợp shell bất ngờ." + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "Yêu cầu hướng dẫn không hợp lệ cho nhiệm vụ '{{task}}'." + } + }, + "generic": { + "noChanges": "Không cần thay đổi cho '{{path}}'.", + "changesRejected": "Thay đổi đã bị người dùng từ chối." + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "Không thể hoàn thành nhiệm vụ khi vẫn còn mục cần làm. Vui lòng hoàn tất trước." + }, + "userFeedbackLead": "Người dùng đã cung cấp phản hồi về kết quả. Hãy cân nhắc phản hồi để tiếp tục và thử hoàn thành lại." } } diff --git a/src/i18n/locales/zh-CN/tools.json b/src/i18n/locales/zh-CN/tools.json index c0c93d8436..226c02a01f 100644 --- a/src/i18n/locales/zh-CN/tools.json +++ b/src/i18n/locales/zh-CN/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "由于策略限制,无法创建新任务。" } + }, + "errors": { + "toolCallError": "工具调用错误: {{toolName}}", + "toolExecutionError": "工具执行错误", + "missingParamForTool": "Roo 尝试使用 {{toolName}} 时缺少必填参数 '{{paramName}}' 的值。正在重试...", + "missingParamForToolWithPath": "Roo 在处理 '{{relPath}}' 使用 {{toolName}} 时缺少必填参数 '{{paramName}}' 的值。正在重试...", + "fileNotFound": "文件未找到", + "parseError": "解析错误", + "commandTimeout": "命令超时", + "permissionDenied": "权限被拒绝", + "networkError": "网络错误", + "invalidInput": "无效输入", + "operationFailed": "操作失败", + "resourceNotFound": "资源未找到", + "configurationError": "配置错误", + "authenticationFailed": "认证失败", + "invalidLineNumber": "Invalid Line Number", + "fileAlreadyExists": "File Already Exists", + "directoryNotFound": "Directory Not Found", + "invalidPath": "Invalid Path", + "readError": "Read Error", + "writeError": "Write Error", + "syntaxError": "Syntax Error", + "validationError": "Validation Error", + "timeoutError": "Timeout Error", + "connectionError": "Connection Error" + }, + "executeCommand": { + "workingDirMissing": "未找到工作目录: '{{workingDir}}'", + "shellIntegrationGenericError": "由于意外的终端 shell 集成错误,命令执行失败。" + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "针对任务 '{{task}}' 的指令请求无效。" + } + }, + "generic": { + "noChanges": "无需更改 '{{path}}'。", + "changesRejected": "更改已被用户拒绝。" + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "存在未完成的待办事项,无法完成任务。请完成后再尝试提交。" + }, + "userFeedbackLead": "用户已对结果提供反馈。请根据反馈继续任务,然后再次尝试完成。" } } diff --git a/src/i18n/locales/zh-TW/tools.json b/src/i18n/locales/zh-TW/tools.json index b736448c20..ff31b5ae75 100644 --- a/src/i18n/locales/zh-TW/tools.json +++ b/src/i18n/locales/zh-TW/tools.json @@ -14,5 +14,50 @@ "errors": { "policy_restriction": "由於政策限制,無法建立新工作。" } + }, + "errors": { + "toolCallError": "工具呼叫錯誤:{{toolName}}", + "toolExecutionError": "工具執行錯誤", + "missingParamForTool": "Roo 嘗試使用 {{toolName}} 時缺少必要參數「{{paramName}}」的值。正在重試...", + "missingParamForToolWithPath": "Roo 在處理「{{relPath}}」使用 {{toolName}} 時缺少必要參數「{{paramName}}」的值。正在重試...", + "fileNotFound": "找不到檔案", + "parseError": "解析錯誤", + "commandTimeout": "指令逾時", + "permissionDenied": "權限遭拒", + "networkError": "網路錯誤", + "invalidInput": "無效輸入", + "operationFailed": "操作失敗", + "resourceNotFound": "找不到資源", + "configurationError": "設定錯誤", + "authenticationFailed": "驗證失敗", + "invalidLineNumber": "Invalid Line Number", + "fileAlreadyExists": "File Already Exists", + "directoryNotFound": "Directory Not Found", + "invalidPath": "Invalid Path", + "readError": "Read Error", + "writeError": "Write Error", + "syntaxError": "Syntax Error", + "validationError": "Validation Error", + "timeoutError": "Timeout Error", + "connectionError": "Connection Error" + }, + "executeCommand": { + "workingDirMissing": "找不到工作目錄:'{{workingDir}}'", + "shellIntegrationGenericError": "由於意外的終端 Shell 整合錯誤,指令執行失敗。" + }, + "fetchInstructions": { + "errors": { + "invalidRequest": "針對工作「{{task}}」的指令請求無效。" + } + }, + "generic": { + "noChanges": "「{{path}}」無需變更。", + "changesRejected": "變更已被使用者拒絕。" + }, + "attemptCompletion": { + "errors": { + "incompleteTodos": "仍有未完成的待辦事項,無法完成工作。請完成後再嘗試提交。" + }, + "userFeedbackLead": "使用者已對結果提供回饋。請根據回饋繼續工作,然後再次嘗試完成。" } } diff --git a/src/services/glob/list-files.ts b/src/services/glob/list-files.ts index 5366bbb84b..d7249762f5 100644 --- a/src/services/glob/list-files.ts +++ b/src/services/glob/list-files.ts @@ -47,13 +47,16 @@ export async function listFiles(dirPath: string, recursive: boolean, limit: numb const rgPath = await getRipgrepPath() if (!recursive) { - // For non-recursive, use the existing approach + // For non-recursive, include top-level files plus top-level symlinked files const files = await listFilesWithRipgrep(rgPath, dirPath, false, limit) + const symlinkFiles = await listTopLevelSymlinkFiles(dirPath) + const mergedFiles = [...files, ...symlinkFiles] + const ignoreInstance = await createIgnoreInstance(dirPath) - // Calculate remaining limit for directories - const remainingLimit = Math.max(0, limit - files.length) + // Calculate remaining limit for directories after accounting for files + const remainingLimit = Math.max(0, limit - mergedFiles.length) const directories = await listFilteredDirectories(dirPath, false, ignoreInstance, remainingLimit) - return formatAndCombineResults(files, directories, limit) + return formatAndCombineResults(mergedFiles, directories, limit) } // For recursive mode, use the original approach but ensure first-level directories are included @@ -212,12 +215,43 @@ async function listFilesWithRipgrep( const absolutePath = path.resolve(dirPath) return relativePaths.map((relativePath) => path.resolve(absolutePath, relativePath)) } +/** + * List top-level symlinked files in a directory (non-recursive). + * We include the symlink path itself if it points to a file, or if it's a broken link. + */ +async function listTopLevelSymlinkFiles(dirPath: string): Promise { + const absolutePath = path.resolve(dirPath) + try { + const entries = await fs.promises.readdir(absolutePath, { withFileTypes: true }) + const results: string[] = [] + for (const entry of entries) { + if (entry.isSymbolicLink()) { + const symlinkPath = path.join(absolutePath, entry.name) + try { + // stat follows the symlink + const targetStat = await fs.promises.stat(symlinkPath) + if (targetStat.isFile()) { + results.push(symlinkPath) + } + } catch { + // Broken symlink - still surface the symlink path so it is visible to the user + results.push(symlinkPath) + } + } + } + return results + } catch { + return [] + } +} /** * Build appropriate ripgrep arguments based on whether we're doing a recursive search */ function buildRipgrepArgs(dirPath: string, recursive: boolean): string[] { // Base arguments to list files + // Always include --follow to satisfy symlink traversal expectations in unit tests. + // We additionally surface top-level symlinked files in non-recursive mode via listTopLevelSymlinkFiles(). const args = ["--files", "--hidden", "--follow"] if (recursive) { diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 7b3107a2be..44fb90f0fd 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -2,7 +2,7 @@ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from " import { useSize } from "react-use" import { useTranslation, Trans } from "react-i18next" import deepEqual from "fast-deep-equal" -import { VSCodeBadge, VSCodeButton } from "@vscode/webview-ui-toolkit/react" +import { VSCodeBadge } from "@vscode/webview-ui-toolkit/react" import type { ClineMessage, FollowUpData, SuggestionItem } from "@roo-code/types" import { Mode } from "@roo/modes" @@ -11,7 +11,6 @@ import { ClineApiReqInfo, ClineAskUseMcpServer, ClineSayTool } from "@roo/Extens import { COMMAND_OUTPUT_STRING } from "@roo/combineCommandSequences" import { safeJsonParse } from "@roo/safeJsonParse" -import { useCopyToClipboard } from "@src/utils/clipboard" import { useExtensionState } from "@src/context/ExtensionStateContext" import { findMatchingResourceOrTemplate } from "@src/utils/mcp" import { vscode } from "@src/utils/vscode" @@ -22,7 +21,6 @@ import { Button } from "@src/components/ui" import { ToolUseBlock, ToolUseBlockHeader } from "../common/ToolUseBlock" import UpdateTodoListToolBlock from "./UpdateTodoListToolBlock" import CodeAccordian from "../common/CodeAccordian" -import CodeBlock from "../common/CodeBlock" import MarkdownBlock from "../common/MarkdownBlock" import { ReasoningBlock } from "./ReasoningBlock" import Thumbnails from "../common/Thumbnails" @@ -47,6 +45,7 @@ import { McpExecution } from "./McpExecution" import { ChatTextArea } from "./ChatTextArea" import { MAX_IMAGES_PER_MESSAGE } from "./ChatView" import { useSelectedModel } from "../ui/hooks/useSelectedModel" +import { CollapsibleErrorSection } from "./CollapsibleErrorSection" interface ChatRowProps { message: ClineMessage @@ -120,12 +119,11 @@ export const ChatRowContent = ({ const { info: model } = useSelectedModel(apiConfiguration) const [reasoningCollapsed, setReasoningCollapsed] = useState(true) const [isDiffErrorExpanded, setIsDiffErrorExpanded] = useState(false) - const [showCopySuccess, setShowCopySuccess] = useState(false) const [isEditing, setIsEditing] = useState(false) const [editedContent, setEditedContent] = useState("") const [editMode, setEditMode] = useState(mode || "code") const [editImages, setEditImages] = useState([]) - const { copyWithFeedback } = useCopyToClipboard() + const [isErrorExpanded, setIsErrorExpanded] = useState(false) // Default collapsed like diff_error // Handle message events for image selection during edit mode useEffect(() => { @@ -211,13 +209,6 @@ export const ChatRowContent = ({ const [icon, title] = useMemo(() => { switch (type) { - case "error": - return [ - , - {t("chat:error")}, - ] case "mistake_limit_reached": return [ -
-
+
+
{t("chat:subtasks.newTaskContent")}
-
+
@@ -817,31 +789,12 @@ export const ChatRowContent = ({ {toolIcon("check-all")} {t("chat:subtasks.wantsToFinish")}
-
-
+
+
{t("chat:subtasks.completionContent")}
-
+
@@ -959,125 +912,23 @@ export const ChatRowContent = ({ switch (message.say) { case "diff_error": return ( -
-
-
setIsDiffErrorExpanded(!isDiffErrorExpanded)}> -
- - {t("chat:diffError.title")} -
-
- { - e.stopPropagation() - - // Call copyWithFeedback and handle the Promise - copyWithFeedback(message.text || "").then((success) => { - if (success) { - // Show checkmark - setShowCopySuccess(true) - - // Reset after a brief delay - setTimeout(() => { - setShowCopySuccess(false) - }, 1000) - } - }) - }}> - - - -
-
- {isDiffErrorExpanded && ( -
- -
- )} -
-
+ setIsDiffErrorExpanded(!isDiffErrorExpanded)} + /> ) case "subtask_result": return (
-
-
+
+
{t("chat:subtasks.resultContent")}
-
+
@@ -1134,7 +985,7 @@ export const ChatRowContent = ({ - troubleshooting guide + {t("chat:powershell.troubleshootingGuide")} . @@ -1243,16 +1094,16 @@ export const ChatRowContent = ({
) case "error": + // Detect language based on content - check if it contains XML-like error tags + const errorLanguage = message.text?.includes("") ? "xml" : "text" return ( - <> - {title && ( -
- {icon} - {title} -
- )} -

{message.text}

- + setIsErrorExpanded(!isErrorExpanded)} + /> ) case "completion_result": return ( @@ -1308,7 +1159,7 @@ export const ChatRowContent = ({ if (parsed && !parsed?.content) { console.error("Invalid codebaseSearch content structure:", parsed.content) - return
Error displaying search results.
+ return
{t("chat:codebaseSearch.errorDisplayingResults")}
} const { results = [] } = parsed?.content || {} diff --git a/webview-ui/src/components/chat/CollapsibleErrorSection.tsx b/webview-ui/src/components/chat/CollapsibleErrorSection.tsx new file mode 100644 index 0000000000..3ff5af524c --- /dev/null +++ b/webview-ui/src/components/chat/CollapsibleErrorSection.tsx @@ -0,0 +1,73 @@ +import React from "react" +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" +import CodeBlock from "../common/CodeBlock" +import { useCopyToClipboard } from "@src/utils/clipboard" + +interface CollapsibleErrorSectionProps { + title: string + content: string | null | undefined + language?: string + isExpanded: boolean + onToggleExpand: () => void +} + +export const CollapsibleErrorSection: React.FC = ({ + title, + content, + language = "xml", + isExpanded, + onToggleExpand, +}) => { + const [showCopySuccess, setShowCopySuccess] = React.useState(false) + const { copyWithFeedback } = useCopyToClipboard() + + const handleCopy = async (e: React.MouseEvent) => { + e.stopPropagation() + const success = await copyWithFeedback(content || "") + if (success) { + setShowCopySuccess(true) + setTimeout(() => setShowCopySuccess(false), 1000) + } + } + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault() + onToggleExpand() + } + } + + return ( +
+
+
+ + {title} +
+
+ + + + +
+
+ {isExpanded && ( +
+ +
+ )} +
+ ) +} diff --git a/webview-ui/src/components/chat/__tests__/ChatRow.spec.tsx b/webview-ui/src/components/chat/__tests__/ChatRow.spec.tsx new file mode 100644 index 0000000000..469fc13f50 --- /dev/null +++ b/webview-ui/src/components/chat/__tests__/ChatRow.spec.tsx @@ -0,0 +1,460 @@ +// npx vitest run src/components/chat/__tests__/ChatRow.spec.tsx + +import { render as rtlRender, screen, fireEvent, waitFor } from "@testing-library/react" +import { QueryClient, QueryClientProvider } from "@tanstack/react-query" +import { describe, it, expect, vi, beforeEach } from "vitest" +import { ChatRowContent } from "../ChatRow" +import type { ClineMessage } from "@roo-code/types" + +const render = (ui: any) => rtlRender({ui}) + +// Mock the clipboard utility +const mockCopyWithFeedback = vi.fn().mockResolvedValue(true) +vi.mock("@src/utils/clipboard", () => ({ + useCopyToClipboard: () => ({ + copyWithFeedback: mockCopyWithFeedback, + }), +})) + +// Mock the extension state context +vi.mock("@src/context/ExtensionStateContext", () => ({ + useExtensionState: () => ({ + mcpServers: [], + alwaysAllowMcp: false, + currentCheckpoint: null, + mode: "code", + }), +})) + +// Mock the translation hook +vi.mock("react-i18next", () => ({ + useTranslation: () => ({ + t: (key: string) => { + const translations: Record = { + "chat:error": "Error", + "chat:diffError.title": "Edit Unsuccessful", + } + return translations[key] || key + }, + }), + Trans: ({ children }: { children: React.ReactNode }) => <>{children}, + initReactI18next: { + type: "3rdParty", + init: () => {}, + }, +})) + +// Mock vscode API +vi.mock("@src/utils/vscode", () => ({ + vscode: { + postMessage: vi.fn(), + }, +})) + +// Mock CodeBlock component to avoid Tooltip issues +vi.mock("../../common/CodeBlock", () => ({ + default: ({ source }: { source: string }) =>
{source}
, +})) + +describe("ChatRow Error Display", () => { + const mockOnToggleExpand = vi.fn() + const mockOnSuggestionClick = vi.fn() + const mockOnBatchFileResponse = vi.fn() + const mockOnFollowUpUnmount = vi.fn() + + const baseProps = { + isExpanded: false, + isLast: false, + isStreaming: false, + onToggleExpand: mockOnToggleExpand, + onSuggestionClick: mockOnSuggestionClick, + onBatchFileResponse: mockOnBatchFileResponse, + onFollowUpUnmount: mockOnFollowUpUnmount, + isFollowUpAnswered: false, + editable: false, + } + + beforeEach(() => { + vi.clearAllMocks() + }) + + describe("Error Message Display", () => { + it("should render error message with collapsible section", () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "This is an error message", + } + + render() + + // Check that warning icon is present (matching diff_error style) + const warningIcon = document.querySelector(".codicon-warning") + expect(warningIcon).toBeTruthy() + + // Check that error title is present + expect(screen.getByText("Error")).toBeTruthy() + + // Check that error text is NOT visible by default (collapsed) + expect(screen.queryByText("This is an error message")).toBeFalsy() + + // Check that chevron-down icon is present (collapsed state) + const chevronDown = document.querySelector(".codicon-chevron-down") + expect(chevronDown).toBeTruthy() + + // Check that copy button is present + const copyButton = document.querySelector(".codicon-copy") + expect(copyButton).toBeTruthy() + }) + + it("should toggle error message visibility when clicked", () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "This is a collapsible error", + } + + render() + + // Initially collapsed - chevron should be down + let chevron = document.querySelector(".codicon-chevron-down") + expect(chevron).toBeTruthy() + expect(screen.queryByText("This is a collapsible error")).toBeFalsy() + + // Click to expand + const header = screen.getByText("Error").closest("div")?.parentElement + if (header) { + fireEvent.click(header) + } + + // After expand - chevron should be up and text visible + chevron = document.querySelector(".codicon-chevron-up") + expect(chevron).toBeTruthy() + + // The text is now in a CodeBlock (pre element) due to matching diff_error + const codeBlock = document.querySelector("pre") + expect(codeBlock?.textContent).toBe("This is a collapsible error") + + // Click to collapse again + if (header) { + fireEvent.click(header) + } + + // Should be collapsed again + chevron = document.querySelector(".codicon-chevron-down") + expect(chevron).toBeTruthy() + expect(document.querySelector("pre")).toBeFalsy() + }) + + it("should handle copy button click for error messages", async () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "Error to copy", + } + + render() + + // Find and click copy button (VSCodeButton component) + const copyIcon = document.querySelector(".codicon-copy") + expect(copyIcon).toBeTruthy() + + // Click on the VSCodeButton which contains the copy icon + const vscodeButton = copyIcon?.closest("vscode-button") + expect(vscodeButton).toBeTruthy() + + if (vscodeButton) { + fireEvent.click(vscodeButton) + } + + // Verify copy function was called with correct text + await waitFor(() => { + expect(mockCopyWithFeedback).toHaveBeenCalledWith("Error to copy") + }) + }) + + it("should show check icon after successful copy", async () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "Error to copy with feedback", + } + + render() + + // Initially should show copy icon + const copyIcon = document.querySelector(".codicon-copy") + expect(copyIcon).toBeTruthy() + + // Click copy button (VSCodeButton component) + const vscodeButton = copyIcon?.closest("vscode-button") + if (vscodeButton) { + fireEvent.click(vscodeButton) + } + + // Should show check icon after successful copy + await waitFor(() => { + const checkIcon = document.querySelector(".codicon-check") + expect(checkIcon).toBeTruthy() + }) + }) + + it("should handle empty error text gracefully", () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "", + } + + render() + + // Should still render the collapsible structure + expect(screen.getByText("Error")).toBeTruthy() + const copyButton = document.querySelector(".codicon-copy") + expect(copyButton).toBeTruthy() + }) + + it("should handle null error text gracefully", () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: null as any, + } + + render() + + // Should still render the collapsible structure + expect(screen.getByText("Error")).toBeTruthy() + const copyButton = document.querySelector(".codicon-copy") + expect(copyButton).toBeTruthy() + }) + + it("should use warning icon with warning color", () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "Styled error message", + } + + render() + + // Check that warning icon is present with warning color class + const warningIcon = document.querySelector(".codicon-warning") + expect(warningIcon).toBeTruthy() + // Check that the warning icon has the correct Tailwind class + expect(warningIcon?.classList.contains("text-vscode-editorWarning-foreground")).toBeTruthy() + }) + + it("should display custom title when provided", () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "This is a custom error", + title: "File Not Found", + } + + render() + + // Custom title should be visible + expect(screen.getByText("File Not Found")).toBeTruthy() + // Default "Error" title should not be visible + expect(screen.queryByText("Error")).toBeFalsy() + }) + + it("should fall back to default 'Error' title when custom title is not provided", () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "This is a default error", + // No title field provided + } + + render() + + // Default "Error" title should be visible + expect(screen.getByText("Error")).toBeTruthy() + }) + + it("should handle empty custom title by falling back to default", () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "Error with empty title", + title: "", // Empty title + } + + render() + + // Should fall back to default "Error" title + expect(screen.getByText("Error")).toBeTruthy() + }) + + it("should display custom title with special characters correctly", () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "Special character error", + title: "Error: File 'test.ts' not found!", + } + + render() + + // Custom title with special characters should be visible + expect(screen.getByText("Error: File 'test.ts' not found!")).toBeTruthy() + }) + }) + + describe("Diff Error Display", () => { + it("should render diff_error with collapsible section", () => { + const diffErrorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "diff_error", + text: "Diff application failed", + } + + render() + + // Check that warning icon is present + const warningIcon = document.querySelector(".codicon-warning") + expect(warningIcon).toBeTruthy() + + // Check that diff error title is present + expect(screen.getByText("Edit Unsuccessful")).toBeTruthy() + + // Check that copy button is present + const copyButton = document.querySelector(".codicon-copy") + expect(copyButton).toBeTruthy() + + // Should be collapsed by default for diff_error + const chevronDown = document.querySelector(".codicon-chevron-down") + expect(chevronDown).toBeTruthy() + }) + + it("should toggle diff_error visibility when clicked", () => { + const diffErrorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "diff_error", + text: "Diff content", + } + + render() + + // Initially collapsed + let chevron = document.querySelector(".codicon-chevron-down") + expect(chevron).toBeTruthy() + + // Click to expand + const header = screen.getByText("Edit Unsuccessful").closest("div")?.parentElement + if (header) { + fireEvent.click(header) + } + + // Should be expanded + chevron = document.querySelector(".codicon-chevron-up") + expect(chevron).toBeTruthy() + }) + }) + + describe("Consistency Between Error Types", () => { + it("should have similar structure for error and diff_error", () => { + const errorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "Regular error", + } + + const { container: errorContainer } = render() + + // Both should have collapsible structure + const errorChevron = errorContainer.querySelector(".codicon-chevron-up, .codicon-chevron-down") + expect(errorChevron).toBeTruthy() + + // Both should have copy button + const errorCopyButton = errorContainer.querySelector(".codicon-copy") + expect(errorCopyButton).toBeTruthy() + + // Clean up + errorContainer.remove() + + const diffErrorMessage: ClineMessage = { + ts: Date.now(), + type: "say", + say: "diff_error", + text: "Diff error", + } + + const { container: diffErrorContainer } = render( + , + ) + + const diffErrorChevron = diffErrorContainer.querySelector(".codicon-chevron-up, .codicon-chevron-down") + expect(diffErrorChevron).toBeTruthy() + + const diffErrorCopyButton = diffErrorContainer.querySelector(".codicon-copy") + expect(diffErrorCopyButton).toBeTruthy() + }) + + it("should handle multi-line error messages", () => { + const multiLineError: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "Line 1\nLine 2\nLine 3\nLine 4", + } + + render() + + // Should render as collapsible + const chevron = document.querySelector(".codicon-chevron-up, .codicon-chevron-down") + expect(chevron).toBeTruthy() + + // Should have copy button + const copyButton = document.querySelector(".codicon-copy") + expect(copyButton).toBeTruthy() + + // Click to expand + const header = screen.getByText("Error").closest("div")?.parentElement + if (header) { + fireEvent.click(header) + } + + // Text should be visible when expanded (in CodeBlock/pre element) + const codeBlock = document.querySelector("pre") + expect(codeBlock).toBeTruthy() + expect(codeBlock?.textContent).toBe("Line 1\nLine 2\nLine 3\nLine 4") + }) + + it("should handle very long single-line error messages", () => { + const longError: ClineMessage = { + ts: Date.now(), + type: "say", + say: "error", + text: "A".repeat(300), // 300 character error + } + + render() + + // Should render as collapsible + const chevron = document.querySelector(".codicon-chevron-up, .codicon-chevron-down") + expect(chevron).toBeTruthy() + + // Should have copy button + const copyButton = document.querySelector(".codicon-copy") + expect(copyButton).toBeTruthy() + }) + }) +}) diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 1d20be0c40..ddcb1506f3 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "Tasca completada", "powershell": { - "issues": "Sembla que estàs tenint problemes amb Windows PowerShell, si us plau consulta aquesta documentació per a més informació." + "issues": "Sembla que estàs tenint problemes amb Windows PowerShell, si us plau consulta aquesta documentació per a més informació.", + "troubleshootingGuide": "guia de resolució de problemes" }, "autoApprove": { "title": "Aprovació automàtica:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo vol cercar a la base de codi {{query}} a {{path}}:", "didSearch_one": "S'ha trobat 1 resultat", "didSearch_other": "S'han trobat {{count}} resultats", - "resultTooltip": "Puntuació de similitud: {{score}} (fes clic per obrir el fitxer)" + "resultTooltip": "Puntuació de similitud: {{score}} (fes clic per obrir el fitxer)", + "errorDisplayingResults": "Error en mostrar els resultats de la cerca." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index 82f1c77fbf..d5b96b563d 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "Aufgabe abgeschlossen", "powershell": { - "issues": "Es scheint, dass du Probleme mit Windows PowerShell hast, bitte sieh dir dies an" + "issues": "Es scheint, dass du Probleme mit Windows PowerShell hast, bitte sieh dir dies an", + "troubleshootingGuide": "Troubleshooting-Guide" }, "autoApprove": { "title": "Automatische Genehmigung:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo möchte den Codebase nach {{query}} in {{path}} durchsuchen:", "didSearch_one": "1 Ergebnis gefunden", "didSearch_other": "{{count}} Ergebnisse gefunden", - "resultTooltip": "Ähnlichkeitswert: {{score}} (klicken zum Öffnen der Datei)" + "resultTooltip": "Ähnlichkeitswert: {{score}} (klicken zum Öffnen der Datei)", + "errorDisplayingResults": "Fehler beim Anzeigen der Suchergebnisse." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index 72eacc5c58..b78e88ad5c 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -216,7 +216,8 @@ "wantsToSearchWithPath": "Roo wants to search the codebase for {{query}} in {{path}}:", "didSearch_one": "Found 1 result", "didSearch_other": "Found {{count}} results", - "resultTooltip": "Similarity score: {{score}} (click to open file)" + "resultTooltip": "Similarity score: {{score}} (click to open file)", + "errorDisplayingResults": "Error displaying search results." }, "commandOutput": "Command Output", "commandExecution": { @@ -266,7 +267,8 @@ }, "troubleMessage": "Roo is having trouble...", "powershell": { - "issues": "It seems like you're having Windows PowerShell issues, please see this" + "issues": "It seems like you're having Windows PowerShell issues, please see this", + "troubleshootingGuide": "troubleshooting guide" }, "autoApprove": { "title": "Auto-approve:", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index e63731b095..e0e75cc3e2 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "Tarea completada", "powershell": { - "issues": "Parece que estás teniendo problemas con Windows PowerShell, por favor consulta esta" + "issues": "Parece que estás teniendo problemas con Windows PowerShell, por favor consulta esta", + "troubleshootingGuide": "guía de solución de problemas" }, "autoApprove": { "title": "Auto-aprobar:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo quiere buscar en la base de código {{query}} en {{path}}:", "didSearch_one": "Se encontró 1 resultado", "didSearch_other": "Se encontraron {{count}} resultados", - "resultTooltip": "Puntuación de similitud: {{score}} (haz clic para abrir el archivo)" + "resultTooltip": "Puntuación de similitud: {{score}} (haz clic para abrir el archivo)", + "errorDisplayingResults": "Error al mostrar los resultados de la búsqueda." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 2575489787..439590b1aa 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "Tâche terminée", "powershell": { - "issues": "Il semble que vous rencontriez des problèmes avec Windows PowerShell, veuillez consulter ce" + "issues": "Il semble que vous rencontriez des problèmes avec Windows PowerShell, veuillez consulter ce", + "troubleshootingGuide": "guide de dépannage" }, "autoApprove": { "title": "Auto-approbation :", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo veut rechercher dans la base de code {{query}} dans {{path}} :", "didSearch_one": "1 résultat trouvé", "didSearch_other": "{{count}} résultats trouvés", - "resultTooltip": "Score de similarité : {{score}} (cliquer pour ouvrir le fichier)" + "resultTooltip": "Score de similarité : {{score}} (cliquer pour ouvrir le fichier)", + "errorDisplayingResults": "Erreur lors de l’affichage des résultats de recherche." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 28fc26fcaf..c35dd11c31 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "कार्य पूरा हुआ", "powershell": { - "issues": "ऐसा लगता है कि आपको Windows PowerShell के साथ समस्याएँ हो रही हैं, कृपया इसे देखें" + "issues": "ऐसा लगता है कि आपको Windows PowerShell के साथ समस्याएँ हो रही हैं, कृपया इसे देखें", + "troubleshootingGuide": "ट्रबलशूटिंग गाइड" }, "autoApprove": { "title": "स्वत:-स्वीकृति:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo {{path}} में कोडबेस में {{query}} खोजना चाहता है:", "didSearch_one": "1 परिणाम मिला", "didSearch_other": "{{count}} परिणाम मिले", - "resultTooltip": "समानता स्कोर: {{score}} (फ़ाइल खोलने के लिए क्लिक करें)" + "resultTooltip": "समानता स्कोर: {{score}} (फ़ाइल खोलने के लिए क्लिक करें)", + "errorDisplayingResults": "खोज परिणाम दिखाने में त्रुटि।" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index 0425a02b8f..5a498a2716 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -219,7 +219,8 @@ "wantsToSearchWithPath": "Roo ingin mencari codebase untuk {{query}} di {{path}}:", "didSearch_one": "Ditemukan 1 hasil", "didSearch_other": "Ditemukan {{count}} hasil", - "resultTooltip": "Skor kemiripan: {{score}} (klik untuk membuka file)" + "resultTooltip": "Skor kemiripan: {{score}} (klik untuk membuka file)", + "errorDisplayingResults": "Galat menampilkan hasil pencarian." }, "commandOutput": "Output Perintah", "commandExecution": { @@ -269,7 +270,8 @@ }, "troubleMessage": "Roo mengalami masalah...", "powershell": { - "issues": "Sepertinya kamu mengalami masalah Windows PowerShell, silakan lihat ini" + "issues": "Sepertinya kamu mengalami masalah Windows PowerShell, silakan lihat ini", + "troubleshootingGuide": "panduan pemecahan masalah" }, "autoApprove": { "title": "Auto-approve:", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index 4dd1270e34..8e08844843 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "Attività completata", "powershell": { - "issues": "Sembra che tu stia avendo problemi con Windows PowerShell, consulta questa" + "issues": "Sembra che tu stia avendo problemi con Windows PowerShell, consulta questa", + "troubleshootingGuide": "guida alla risoluzione dei problemi" }, "autoApprove": { "title": "Auto-approvazione:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo vuole cercare nella base di codice {{query}} in {{path}}:", "didSearch_one": "Trovato 1 risultato", "didSearch_other": "Trovati {{count}} risultati", - "resultTooltip": "Punteggio di somiglianza: {{score}} (clicca per aprire il file)" + "resultTooltip": "Punteggio di somiglianza: {{score}} (clicca per aprire il file)", + "errorDisplayingResults": "Errore durante la visualizzazione dei risultati di ricerca." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 9a5d47fec8..5da0832852 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "タスク完了", "powershell": { - "issues": "Windows PowerShellに問題があるようです。こちらを参照してください" + "issues": "Windows PowerShellに問題があるようです。こちらを参照してください", + "troubleshootingGuide": "トラブルシューティングガイド" }, "autoApprove": { "title": "自動承認:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Rooは {{path}} 内のコードベースで {{query}} を検索したい:", "didSearch_one": "1件の結果が見つかりました", "didSearch_other": "{{count}}件の結果が見つかりました", - "resultTooltip": "類似度スコア: {{score}} (クリックしてファイルを開く)" + "resultTooltip": "類似度スコア: {{score}} (クリックしてファイルを開く)", + "errorDisplayingResults": "検索結果の表示中にエラーが発生しました。" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index aaf29243b7..11418012e7 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "작업 완료", "powershell": { - "issues": "Windows PowerShell에 문제가 있는 것 같습니다. 다음을 참조하세요" + "issues": "Windows PowerShell에 문제가 있는 것 같습니다. 다음을 참조하세요", + "troubleshootingGuide": "문제 해결 가이드" }, "autoApprove": { "title": "자동 승인:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo가 {{path}}에서 {{query}}을(를) 검색하고 싶어합니다:", "didSearch_one": "1개의 결과를 찾았습니다", "didSearch_other": "{{count}}개의 결과를 찾았습니다", - "resultTooltip": "유사도 점수: {{score}} (클릭하여 파일 열기)" + "resultTooltip": "유사도 점수: {{score}} (클릭하여 파일 열기)", + "errorDisplayingResults": "검색 결과 표시 중 오류가 발생했습니다." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index c6d52fa92e..fd2acc7fa8 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -242,7 +242,8 @@ }, "troubleMessage": "Roo ondervindt problemen...", "powershell": { - "issues": "Het lijkt erop dat je problemen hebt met Windows PowerShell, zie deze" + "issues": "Het lijkt erop dat je problemen hebt met Windows PowerShell, zie deze", + "troubleshootingGuide": "probleemoplossingsgids" }, "autoApprove": { "title": "Automatisch goedkeuren:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo wil de codebase doorzoeken op {{query}} in {{path}}:", "didSearch_one": "1 resultaat gevonden", "didSearch_other": "{{count}} resultaten gevonden", - "resultTooltip": "Gelijkenisscore: {{score}} (klik om bestand te openen)" + "resultTooltip": "Gelijkenisscore: {{score}} (klik om bestand te openen)", + "errorDisplayingResults": "Fout bij het weergeven van zoekresultaten." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index 2028cb705b..e4eb2cc5f2 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "Zadanie zakończone", "powershell": { - "issues": "Wygląda na to, że masz problemy z Windows PowerShell, proszę zapoznaj się z tym" + "issues": "Wygląda na to, że masz problemy z Windows PowerShell, proszę zapoznaj się z tym", + "troubleshootingGuide": "poradnik rozwiązywania problemów" }, "autoApprove": { "title": "Automatyczne zatwierdzanie:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo chce przeszukać bazę kodu w poszukiwaniu {{query}} w {{path}}:", "didSearch_one": "Znaleziono 1 wynik", "didSearch_other": "Znaleziono {{count}} wyników", - "resultTooltip": "Wynik podobieństwa: {{score}} (kliknij, aby otworzyć plik)" + "resultTooltip": "Wynik podobieństwa: {{score}} (kliknij, aby otworzyć plik)", + "errorDisplayingResults": "Błąd podczas wyświetlania wyników wyszukiwania." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index 6ee23ca627..b53605feab 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "Tarefa concluída", "powershell": { - "issues": "Parece que você está tendo problemas com o Windows PowerShell, por favor veja este" + "issues": "Parece que você está tendo problemas com o Windows PowerShell, por favor veja este", + "troubleshootingGuide": "guia de solução de problemas" }, "autoApprove": { "title": "Aprovação automática:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo quer pesquisar na base de código por {{query}} em {{path}}:", "didSearch_one": "Encontrado 1 resultado", "didSearch_other": "Encontrados {{count}} resultados", - "resultTooltip": "Pontuação de similaridade: {{score}} (clique para abrir o arquivo)" + "resultTooltip": "Pontuação de similaridade: {{score}} (clique para abrir o arquivo)", + "errorDisplayingResults": "Erro ao exibir os resultados da pesquisa." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index 6cafe6bac9..758c519768 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -242,7 +242,8 @@ }, "troubleMessage": "У Roo возникли проблемы...", "powershell": { - "issues": "Похоже, у вас проблемы с Windows PowerShell, пожалуйста, ознакомьтесь с этим" + "issues": "Похоже, у вас проблемы с Windows PowerShell, пожалуйста, ознакомьтесь с этим", + "troubleshootingGuide": "руководство по устранению неполадок" }, "autoApprove": { "title": "Автоодобрение:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo хочет выполнить поиск в кодовой базе по {{query}} в {{path}}:", "didSearch_one": "Найден 1 результат", "didSearch_other": "Найдено {{count}} результатов", - "resultTooltip": "Оценка схожести: {{score}} (нажмите, чтобы открыть файл)" + "resultTooltip": "Оценка схожести: {{score}} (нажмите, чтобы открыть файл)", + "errorDisplayingResults": "Ошибка при отображении результатов поиска." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index 867acfbc9f..e2d3e8fae9 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "Görev Tamamlandı", "powershell": { - "issues": "Windows PowerShell ile ilgili sorunlar yaşıyor gibi görünüyorsunuz, lütfen şu konuya bakın" + "issues": "Windows PowerShell ile ilgili sorunlar yaşıyor gibi görünüyorsunuz, lütfen şu konuya bakın", + "troubleshootingGuide": "sorun giderme kılavuzu" }, "autoApprove": { "title": "Otomatik-onay:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo {{path}} içinde kod tabanında {{query}} aramak istiyor:", "didSearch_one": "1 sonuç bulundu", "didSearch_other": "{{count}} sonuç bulundu", - "resultTooltip": "Benzerlik puanı: {{score}} (dosyayı açmak için tıklayın)" + "resultTooltip": "Benzerlik puanı: {{score}} (dosyayı açmak için tıklayın)", + "errorDisplayingResults": "Arama sonuçları görüntülenirken hata oluştu." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index ef8e951aac..fe5996dc5e 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "Nhiệm vụ hoàn thành", "powershell": { - "issues": "Có vẻ như bạn đang gặp vấn đề với Windows PowerShell, vui lòng xem" + "issues": "Có vẻ như bạn đang gặp vấn đề với Windows PowerShell, vui lòng xem", + "troubleshootingGuide": "hướng dẫn khắc phục sự cố" }, "autoApprove": { "title": "Tự động phê duyệt:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo muốn tìm kiếm trong cơ sở mã cho {{query}} trong {{path}}:", "didSearch_one": "Đã tìm thấy 1 kết quả", "didSearch_other": "Đã tìm thấy {{count}} kết quả", - "resultTooltip": "Điểm tương tự: {{score}} (nhấp để mở tệp)" + "resultTooltip": "Điểm tương tự: {{score}} (nhấp để mở tệp)", + "errorDisplayingResults": "Lỗi khi hiển thị kết quả tìm kiếm." }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index 1e430200a1..6f9b97e712 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -242,7 +242,8 @@ }, "taskCompleted": "任务完成", "powershell": { - "issues": "看起来您遇到了Windows PowerShell问题,请参阅此" + "issues": "看起来您遇到了Windows PowerShell问题,请参阅此", + "troubleshootingGuide": "疑难解答指南" }, "autoApprove": { "title": "自动批准:", @@ -338,7 +339,8 @@ "wantsToSearchWithPath": "Roo 需要在 {{path}} 中搜索: {{query}}", "didSearch_one": "找到 1 个结果", "didSearch_other": "找到 {{count}} 个结果", - "resultTooltip": "相似度评分: {{score}} (点击打开文件)" + "resultTooltip": "相似度评分: {{score}} (点击打开文件)", + "errorDisplayingResults": "显示搜索结果时出错。" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index f5183d65a9..983de77566 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -216,7 +216,8 @@ "wantsToSearchWithPath": "Roo 想要在 {{path}} 中搜尋程式碼庫:{{query}}", "didSearch_one": "找到 1 個結果", "didSearch_other": "找到 {{count}} 個結果", - "resultTooltip": "相似度評分:{{score}} (點選開啟檔案)" + "resultTooltip": "相似度評分:{{score}} (點選開啟檔案)", + "errorDisplayingResults": "顯示搜尋結果時發生錯誤。" }, "commandOutput": "命令輸出", "commandExecution": { @@ -266,7 +267,8 @@ }, "troubleMessage": "Roo 遇到問題...", "powershell": { - "issues": "您似乎遇到了 Windows PowerShell 的問題,請參閱此說明文件" + "issues": "您似乎遇到了 Windows PowerShell 的問題,請參閱此說明文件", + "troubleshootingGuide": "疑難排解指南" }, "autoApprove": { "title": "自動核准:",