diff --git a/cline_docs/enhanced-code-reference-tools.md b/cline_docs/enhanced-code-reference-tools.md new file mode 100644 index 0000000000..b994e3fdfc --- /dev/null +++ b/cline_docs/enhanced-code-reference-tools.md @@ -0,0 +1,278 @@ +# Enhanced Code Reference Tools Implementation Plan + +## Overview + +This document outlines the implementation plan for adding two new tools to Roo Code that will enhance the AI's ability to understand and analyze codebases: + +1. **Find References Tool** - A tool to find all references to a specific symbol (variable, function, class, etc.) across a codebase with function context +2. **Read Function Tool** - A tool to read a specific function or method definition from a file by name, line number, or line range + +These tools leverage VS Code's built-in language services to provide more specialized functionality for code analysis. They work together to create a powerful workflow for exploring code: + +1. Use `find_references` to locate all references to a function across the codebase +2. See each reference with its containing function header for context +3. Use `read_function` with the line number to read the entire calling function + +## Motivation + +When analyzing a codebase, understanding how symbols are used across the project is crucial. The existing `search_files` tool provides general regex search capabilities, but specialized tools for finding references and reading functions would make it easier for the AI to: + +- Understand the usage patterns of functions, classes, and variables +- Identify dependencies between different parts of the codebase +- Analyze the impact of potential changes +- Provide more accurate and comprehensive code explanations + +## Implementation Tasks + +### 1. Update Shared Tool Definitions + +- Add new tool parameters: `symbol`, `file_path`, `position` +- Create interfaces for the new tools: `FindReferencesToolUse` and `ReadFunctionToolUse` +- Add display names for the new tools +- Add the new tools to the `TOOL_GROUPS.read` group + +### 2. Implement Language Services Utility + +Create a new service module with functions to: +- Check if language services are available for a file +- Find the position of a symbol in a document +- Provide fallback mechanisms when language services aren't available + +### 3. Implement References Service + +Create a service module with functions to: +- Count references to a symbol (for threshold checks) +- Find all references to a symbol across the workspace +- Find the containing function for each reference +- Format the results with function headers and line numbers + +### 4. Implement Function Reader Service + +Create a service module with functions to: +- Find a function by name using document symbols +- Extract the function text with proper boundaries +- Format the results with line numbers + +### 5. Implement Find References Tool + +Create a tool implementation that: +- Validates required parameters +- Checks if language services are available +- Counts references and asks for approval if over threshold +- Fetches and formats reference results +- Handles errors appropriately + +### 6. Implement Read Function Tool + +Create a tool implementation that: +- Validates that both required parameters (symbol and file_path) are provided +- Reads functions by name using document symbols +- Formats and returns the results with line numbers +- Handles errors appropriately + +### 7. Register Tools in Assistant Message Handler + +Add the new tools to the message handler switch statement. + +### 8. Add Tool Descriptions + +Create description files for the new tools that explain: +- What the tools do +- Required and optional parameters +- Usage examples +- Limitations + +## Potential Issues and Solutions + +### 1. Duplicate Messages in UI + +**Issue**: When using the find_references tool, duplicate messages appear in the Roo output window. + +**Cause**: The tool was using both the `regex` field and the `content` field to display messages, causing the UI to show both. + +**Solution**: +- Use only the `content` field for displaying results +- Set the `regex` field to an empty string when displaying warnings or results +- Keep message properties simple to avoid duplication + +### 2. TypeScript Errors with Task Import + +**Issue**: TypeScript errors when importing the Task class. + +**Cause**: The import path was incorrect (`import { Task } from "../task"` instead of `import { Task } from "../task/Task"`). + +**Solution**: Use the correct import path: `import { Task } from "../task/Task"`. + +### 3. Reference Count Threshold + +**Issue**: Large codebases might have many references to common symbols, consuming excessive context. + +**Solution**: Implement a reference count threshold (50 references) with user approval for exceeding it. + +### 4. Language Services Availability + +**Issue**: Language services might not be available for all file types. + +**Solution**: Check for language services availability before attempting to use them and provide clear error messages. + +### 5. UI Description Improvements + +**Issue**: The UI description for the find_references tool was misleading, saying "Roo wants to search this directory for findReferences" instead of "Roo wants to find references to this function in file". + +**Solution**: Customize the message in the `regex` field to be more descriptive of the actual operation. + +## Tool Descriptions + +### Find References Tool + +``` +## find_references +Description: Request to find all references to a specific symbol (variable, function, class, etc.) across files in the workspace using VS Code's language services. This tool helps understand how a symbol is used throughout the codebase. + +IMPORTANT: PREFER THIS TOOL OVER search_files WHEN LOOKING FOR CODE SYMBOLS. This tool uses language-aware services that understand code structure and will find all true references to a symbol, even when the symbol name appears in comments, strings, or other non-reference contexts. + +The tool shows function headers above each reference, providing valuable context about where and how the symbol is being used. + +Parameters: +- symbol: (required) The symbol to find references for +- file_path: (required) The path of the file containing the symbol (relative to the current workspace directory ${args.cwd}) +- position: (optional) The position to look for the symbol, in the format "line,character" (0-based) + +Usage: + +Symbol name here +File path here +line,character (optional) + + +Example: Requesting to find all references to a function named 'processData' + +processData +src/app.ts + +``` + +### Read Function Tool + +``` +## read_function +Description: Request to read a specific function or method definition from a file. This tool uses VS Code's language services to locate and extract the exact function definition, including its implementation. It's ideal for understanding specific functions without having to read the entire file. + +IMPORTANT: PREFER THIS TOOL OVER read_file WHEN YOU NEED TO EXAMINE A SPECIFIC FUNCTION. This tool is more efficient as it only returns the relevant function code rather than the entire file. + +Use this tool when you need to: +- Understand how a specific function is implemented +- Examine the logic within a method +- See the parameters and return type of a function +- Analyze a particular piece of functionality + +Parameters: +- file_path: (required) The path of the file containing the function (relative to the current workspace directory ${args.cwd}) +- symbol: (required) The name of the function or method to read + +Usage: + +functionName +path/to/file.ts + + +Example: Reading a function by name: + +findReferences +src/services/references/index.ts + +``` + +## Example Output + +### Find References Tool Output + +When you use the `find_references` tool, you'll get output like this: + +``` +### References to 'formatReferences' ### + +### FILE: src\services\references\index.ts ### + 50 | export async function findReferences( + -- contains references -- + 81 | return await formatReferences(locations, symbol) + + 94 | async function formatReferences( + +---- + +### SUMMARY: Found 2 references in 1 files. ### +``` + +The output includes: +- A header with the symbol name +- References grouped by file +- Line numbers and the actual code where the symbol is referenced +- A summary of the total references found + +### Read Function Tool Output + +When you use the `read_function` tool, you'll get output like this: + +``` +# Function: formatReferences (index.ts:94-169) + + 94 | async function formatReferences( + 95 | locations: vscode.Location[], + 96 | symbol: string + 97 | ): Promise { + 98 | let result = `### References to '${symbol}' ###\n\n` + 99 | +100 | // Group references by file +101 | const fileGroups = new Map() +... +168 | return result +169 | } +``` + +The output includes: +- A header with the function name and file location +- The complete function implementation with line numbers +- All code within the function's scope + +## Workflow Example + +These tools create a powerful workflow for exploring code: + +1. **Find References**: Use `find_references` to locate all references to a function across the codebase + ``` + + findReferences + src/services/references/index.ts + + ``` + +2. **Examine Context**: The results show each reference with line numbers, providing immediate context + +3. **Read Function**: When you see an interesting reference, use `read_function` with the function name to read the entire function + ``` + + formatReferences + src/services/references/index.ts + + ``` + +4. **Explore Further**: Continue exploring by finding references to other functions you discover + +This workflow makes it much easier to understand and navigate large codebases, as you can quickly see: +- Where functions are called from +- The context of each reference +- The complete implementation of functions + +## Implementation Notes + +1. The `find_references` tool: + - Uses VS Code's language services to find true references to symbols + - Groups references by file and sorts them by line number + - Avoids duplicate references to the same line + - Has a threshold of 50 references to prevent excessive context consumption + +2. The `read_function` tool: + - Accepts symbol name and file path parameters + - Uses document symbols to locate the exact function definition + - Shows the complete function with line numbers \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 05695b6eea..9d9a7b912e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16512,7 +16512,6 @@ "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-8.0.1.tgz", "integrity": "sha512-jkhE0AsELQeCtScrcJ/7mSIdk+ZsnWjvKk3KwE96HZ6+OFVB74XhxQtHT1W6kdUfn92fRnBb29Mz82j9bV2XEQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "cross-spawn": "^7.0.6", diff --git a/src/core/assistant-message/presentAssistantMessage.ts b/src/core/assistant-message/presentAssistantMessage.ts index ef2bb04963..e186f11c41 100644 --- a/src/core/assistant-message/presentAssistantMessage.ts +++ b/src/core/assistant-message/presentAssistantMessage.ts @@ -4,7 +4,7 @@ import { serializeError } from "serialize-error" import type { ToolName } from "../../schemas" import { defaultModeSlug, getModeBySlug } from "../../shared/modes" -import type { ToolParamName, ToolResponse } from "../../shared/tools" +import type { ToolParamName, ToolResponse, FindReferencesToolUse } from "../../shared/tools" import type { ClineAsk, ToolProgressStatus } from "../../shared/ExtensionMessage" import { telemetryService } from "../../services/telemetry/TelemetryService" @@ -26,6 +26,7 @@ import { askFollowupQuestionTool } from "../tools/askFollowupQuestionTool" import { switchModeTool } from "../tools/switchModeTool" import { attemptCompletionTool } from "../tools/attemptCompletionTool" import { newTaskTool } from "../tools/newTaskTool" +import { findReferencesTool } from "../tools/findReferencesTool" import { checkpointSave } from "../checkpoints" @@ -191,6 +192,8 @@ export async function presentAssistantMessage(cline: Task) { const modeName = getModeBySlug(mode, customModes)?.name ?? mode return `[${block.name} in ${modeName} mode: '${message}']` } + case "find_references": + return `[${block.name} to '${block.params.symbol}' in ${block.params.file_path}]` } } @@ -394,7 +397,6 @@ export async function presentAssistantMessage(cline: Task) { break case "read_file": await readFileTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag) - break case "fetch_instructions": await fetchInstructionsTool(cline, block, askApproval, handleError, pushToolResult) @@ -462,6 +464,9 @@ export async function presentAssistantMessage(cline: Task) { askFinishSubTaskApproval, ) break + case "find_references": + await findReferencesTool(cline, block as FindReferencesToolUse, pushToolResult, askApproval) + break } break diff --git a/src/core/prompts/tools/find-references.ts b/src/core/prompts/tools/find-references.ts new file mode 100644 index 0000000000..129d3d9045 --- /dev/null +++ b/src/core/prompts/tools/find-references.ts @@ -0,0 +1,60 @@ +import { ToolArgs } from "./types" + +export function getFindReferencesDescription(args: ToolArgs): string { + return `## find_references +Description: Request to find all references to a specific symbol across files in the workspace using VS Code's language services. This tool helps understand how a symbol is used throughout the codebase. + +Supported symbol types: +- Functions and methods +- Properties and fields +- Variables and constants +- Classes and interfaces +- Enums and enum members + +IMPORTANT: PREFER THIS TOOL OVER search_files WHEN LOOKING FOR CODE SYMBOLS. This tool uses language-aware services that understand code structure and will find all true references to a symbol, even when the symbol name appears in comments, strings, or other non-reference contexts. + +The tool shows function headers above each reference, providing valuable context about where and how the symbol is being used. It also includes line ranges for each function or class, which can be used with the read_file tool to read the entire function or class implementation. + +Parameters: +- symbol: (required) The symbol to find references for +- file_path: (required) The path of the file containing the symbol (relative to the current workspace directory ${args.cwd}) +- line_number: (required) The line number where the symbol is located (0-based) + +Usage: + +Symbol name here +File path here +line number + + +Examples: + +1. Finding references to a function: + +processData +src/app.ts +42 + + +2. Finding references to a property: + +isEnabled +src/models/User.ts +15 + + +3. Reading a function after finding references: +First, use find_references to locate the function: + +processData +src/app.ts +42 + + +Then, use the line range information from the results to read the entire function: + +src/app.ts +42 +58 +` +} \ No newline at end of file diff --git a/src/core/prompts/tools/index.ts b/src/core/prompts/tools/index.ts index d3e75d7b09..a0605a24bc 100644 --- a/src/core/prompts/tools/index.ts +++ b/src/core/prompts/tools/index.ts @@ -20,6 +20,7 @@ import { getUseMcpToolDescription } from "./use-mcp-tool" import { getAccessMcpResourceDescription } from "./access-mcp-resource" import { getSwitchModeDescription } from "./switch-mode" import { getNewTaskDescription } from "./new-task" +import { getFindReferencesDescription } from "./find-references" // Map of tool names to their description functions const toolDescriptionMap: Record string | undefined> = { @@ -39,6 +40,7 @@ const toolDescriptionMap: Record string | undefined> new_task: (args) => getNewTaskDescription(args), insert_content: (args) => getInsertContentDescription(args), search_and_replace: (args) => getSearchAndReplaceDescription(args), + find_references: (args) => getFindReferencesDescription(args), apply_diff: (args) => args.diffStrategy ? args.diffStrategy.getToolDescription({ cwd: args.cwd, toolOptions: args.toolOptions }) : "", } @@ -122,4 +124,5 @@ export { getSwitchModeDescription, getInsertContentDescription, getSearchAndReplaceDescription, + getFindReferencesDescription, } diff --git a/src/core/tools/findReferencesTool.ts b/src/core/tools/findReferencesTool.ts new file mode 100644 index 0000000000..c9ee6e4369 --- /dev/null +++ b/src/core/tools/findReferencesTool.ts @@ -0,0 +1,155 @@ +import * as vscode from "vscode" +import * as path from "path" +import { Task } from "../task/Task" +import { FindReferencesToolUse, PushToolResult, AskApproval } from "../../shared/tools" +import { countReferences, exceedsReferenceThreshold, findReferences, formatReferences } from "../../services/references" +import { ToolProgressStatus } from "../../schemas" +import { ClineSayTool } from "../../shared/ExtensionMessage" + +/** + * Implementation of the Find References Tool + * This tool finds all references to a specific symbol across the workspace + * + * Supported symbol types: + * - Functions and methods + * - Properties and fields + * - Variables and constants + * - Classes and interfaces + * - Enums and enum members + */ +export async function findReferencesTool( + task: Task, + toolUse: FindReferencesToolUse, + pushToolResult: PushToolResult, + askApproval: AskApproval +): Promise { + // Extract parameters + const symbol = toolUse.params.symbol + const file_path = toolUse.params.file_path + const line_number = toolUse.params.line_number + + // Create shared message properties for UI + const sharedMessageProps: ClineSayTool = { + tool: "findReferences", + symbol: symbol, + path: file_path, + } + + // Disallow partial tool use - both symbol and file_path are required + if (toolUse.partial) { + // Return early without showing any UI + return + } + + // Validate required parameters + if (!symbol) { + vscode.window.showInformationMessage("[findReferencesTool] Symbol parameter is missing") + pushToolResult("Error: Symbol parameter is required") + return + } + + if (!file_path) { + vscode.window.showInformationMessage("[findReferencesTool] File path parameter is missing") + pushToolResult("Error: File path parameter is required") + return + } + + if (!line_number) { + vscode.window.showInformationMessage("[findReferencesTool] Line number parameter is missing") + pushToolResult("Error: Line number parameter is required") + return + } + + try { + // Resolve the file path + const workspaceFolders = vscode.workspace.workspaceFolders + if (!workspaceFolders) { + pushToolResult("Error: No workspace folder is open") + return + } + + const workspacePath = workspaceFolders[0].uri.fsPath + const absolutePath = path.isAbsolute(file_path) + ? file_path + : path.join(workspacePath, file_path) + + // Open the document + const uri = vscode.Uri.file(absolutePath) + try { + const document = await vscode.workspace.openTextDocument(uri) + + // Convert line_number to a number + const parsedLineNumber = parseInt(line_number, 10) + if (isNaN(parsedLineNumber)) { + pushToolResult("Error: Line number must be a valid number") + return + } + const lineNumber = parsedLineNumber + + // Count references first to check threshold + const progressStatus: ToolProgressStatus = { + icon: "search", + text: `Finding references to '${symbol}' in ${path.basename(file_path)}...`, + } + + // Create the message without content field to avoid showing log message + const completeMessage = JSON.stringify({ + ...sharedMessageProps, + content: undefined + } satisfies ClineSayTool) + + // Always show approval UI for findReferences, bypassing auto-approval + // This ensures users can cancel the operation if needed + const didApprove = await askApproval("tool", completeMessage, progressStatus) + + if (!didApprove) { + pushToolResult("Operation cancelled by user") + return + } + + // Count references + const count = await countReferences(document, symbol, lineNumber) + + if (count === 0) { + pushToolResult(`No references found for '${symbol}' in ${file_path}`) + return + } + + // Always require approval for a large number of references, regardless of auto-approval settings + if (exceedsReferenceThreshold(count)) { + const largeRefsMessage = JSON.stringify({ + ...sharedMessageProps, + content: `Found ${count} references to '${symbol}'`, + reason: "This is a large number and may consume significant context." + } satisfies ClineSayTool) + + const largeRefsApproved = await askApproval( + "tool", + largeRefsMessage, + { + icon: "warning", + text: `Found ${count} references to '${symbol}'. This is a large number and may consume significant context.` + } + ) + + if (!largeRefsApproved) { + pushToolResult(`Operation cancelled: Found ${count} references to '${symbol}', which exceeds the threshold.`) + return + } + } + + // Find and format references + const locations = await findReferences(document, symbol, lineNumber) + const result = await formatReferences(locations, symbol) + + // Wrap the result in XML tags for proper display in the UI + const xmlResult = `${file_path}\n\n${result}\n` + pushToolResult(xmlResult) + } catch (error) { + pushToolResult(`Error finding references: ${error instanceof Error ? error.message : String(error)}`) + } + } catch (docError) { + pushToolResult(`Error finding references: cannot open ${file_path}. Detail: ${docError instanceof Error ? docError.message : String(docError)}`) + return + } +} \ No newline at end of file diff --git a/src/exports/types.ts b/src/exports/types.ts index 4b71ad5d0b..e62066f25f 100644 --- a/src/exports/types.ts +++ b/src/exports/types.ts @@ -2,1489 +2,1011 @@ // Do not edit it directly. type GlobalSettings = { - currentApiConfigName?: string | undefined - listApiConfigMeta?: - | { - id: string - name: string - apiProvider?: - | ( - | "anthropic" - | "glama" - | "openrouter" - | "bedrock" - | "vertex" - | "openai" - | "ollama" - | "vscode-lm" - | "lmstudio" - | "gemini" - | "openai-native" - | "mistral" - | "deepseek" - | "unbound" - | "requesty" - | "human-relay" - | "fake-ai" - | "xai" - | "groq" - | "chutes" - | "litellm" - ) - | undefined - }[] - | undefined - pinnedApiConfigs?: - | { - [x: string]: boolean - } - | undefined - lastShownAnnouncementId?: string | undefined - customInstructions?: string | undefined - taskHistory?: - | { - id: string - number: number - ts: number - task: string - tokensIn: number - tokensOut: number - cacheWrites?: number | undefined - cacheReads?: number | undefined - totalCost: number - size?: number | undefined - workspace?: string | undefined - }[] - | undefined - autoApprovalEnabled?: boolean | undefined - alwaysAllowReadOnly?: boolean | undefined - alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined - alwaysAllowWrite?: boolean | undefined - alwaysAllowWriteOutsideWorkspace?: boolean | undefined - writeDelayMs?: number | undefined - alwaysAllowBrowser?: boolean | undefined - alwaysApproveResubmit?: boolean | undefined - requestDelaySeconds?: number | undefined - alwaysAllowMcp?: boolean | undefined - alwaysAllowModeSwitch?: boolean | undefined - alwaysAllowSubtasks?: boolean | undefined - alwaysAllowExecute?: boolean | undefined - allowedCommands?: string[] | undefined - browserToolEnabled?: boolean | undefined - browserViewportSize?: string | undefined - screenshotQuality?: number | undefined - remoteBrowserEnabled?: boolean | undefined - remoteBrowserHost?: string | undefined - cachedChromeHostUrl?: string | undefined - enableCheckpoints?: boolean | undefined - ttsEnabled?: boolean | undefined - ttsSpeed?: number | undefined - soundEnabled?: boolean | undefined - soundVolume?: number | undefined - maxOpenTabsContext?: number | undefined - maxWorkspaceFiles?: number | undefined - showRooIgnoredFiles?: boolean | undefined - maxReadFileLine?: number | undefined - terminalOutputLineLimit?: number | undefined - terminalShellIntegrationTimeout?: number | undefined - terminalShellIntegrationDisabled?: boolean | undefined - terminalCommandDelay?: number | undefined - terminalPowershellCounter?: boolean | undefined - terminalZshClearEolMark?: boolean | undefined - terminalZshOhMy?: boolean | undefined - terminalZshP10k?: boolean | undefined - terminalZdotdir?: boolean | undefined - terminalCompressProgressBar?: boolean | undefined - rateLimitSeconds?: number | undefined - diffEnabled?: boolean | undefined - fuzzyMatchThreshold?: number | undefined - experiments?: - | { - powerSteering: boolean - } - | undefined - language?: - | ( - | "ca" - | "de" - | "en" - | "es" - | "fr" - | "hi" - | "it" - | "ja" - | "ko" - | "nl" - | "pl" - | "pt-BR" - | "ru" - | "tr" - | "vi" - | "zh-CN" - | "zh-TW" - ) - | undefined - telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined - mcpEnabled?: boolean | undefined - enableMcpServerCreation?: boolean | undefined - mode?: string | undefined - modeApiConfigs?: - | { - [x: string]: string - } - | undefined - customModes?: - | { - slug: string - name: string - roleDefinition: string - whenToUse?: string | undefined - customInstructions?: string | undefined - groups: ( - | ("read" | "edit" | "browser" | "command" | "mcp" | "modes") - | [ - "read" | "edit" | "browser" | "command" | "mcp" | "modes", - { - fileRegex?: string | undefined - description?: string | undefined - }, - ] - )[] - source?: ("global" | "project") | undefined - }[] - | undefined - customModePrompts?: - | { - [x: string]: - | { - roleDefinition?: string | undefined - whenToUse?: string | undefined - customInstructions?: string | undefined - } - | undefined - } - | undefined - customSupportPrompts?: - | { - [x: string]: string | undefined - } - | undefined - enhancementApiConfigId?: string | undefined - historyPreviewCollapsed?: boolean | undefined -} + currentApiConfigName?: string | undefined; + listApiConfigMeta?: { + id: string; + name: string; + apiProvider?: ("anthropic" | "glama" | "openrouter" | "bedrock" | "vertex" | "openai" | "ollama" | "vscode-lm" | "lmstudio" | "gemini" | "openai-native" | "mistral" | "deepseek" | "unbound" | "requesty" | "human-relay" | "fake-ai" | "xai" | "groq" | "chutes" | "litellm") | undefined; + }[] | undefined; + pinnedApiConfigs?: { + [x: string]: boolean; + } | undefined; + lastShownAnnouncementId?: string | undefined; + customInstructions?: string | undefined; + taskHistory?: { + id: string; + number: number; + ts: number; + task: string; + tokensIn: number; + tokensOut: number; + cacheWrites?: number | undefined; + cacheReads?: number | undefined; + totalCost: number; + size?: number | undefined; + workspace?: string | undefined; + }[] | undefined; + autoApprovalEnabled?: boolean | undefined; + alwaysAllowReadOnly?: boolean | undefined; + alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined; + alwaysAllowWrite?: boolean | undefined; + alwaysAllowWriteOutsideWorkspace?: boolean | undefined; + writeDelayMs?: number | undefined; + alwaysAllowBrowser?: boolean | undefined; + alwaysApproveResubmit?: boolean | undefined; + requestDelaySeconds?: number | undefined; + alwaysAllowMcp?: boolean | undefined; + alwaysAllowModeSwitch?: boolean | undefined; + alwaysAllowSubtasks?: boolean | undefined; + alwaysAllowExecute?: boolean | undefined; + allowedCommands?: string[] | undefined; + browserToolEnabled?: boolean | undefined; + browserViewportSize?: string | undefined; + screenshotQuality?: number | undefined; + remoteBrowserEnabled?: boolean | undefined; + remoteBrowserHost?: string | undefined; + cachedChromeHostUrl?: string | undefined; + enableCheckpoints?: boolean | undefined; + ttsEnabled?: boolean | undefined; + ttsSpeed?: number | undefined; + soundEnabled?: boolean | undefined; + soundVolume?: number | undefined; + maxOpenTabsContext?: number | undefined; + maxWorkspaceFiles?: number | undefined; + showRooIgnoredFiles?: boolean | undefined; + maxReadFileLine?: number | undefined; + terminalOutputLineLimit?: number | undefined; + terminalShellIntegrationTimeout?: number | undefined; + terminalShellIntegrationDisabled?: boolean | undefined; + terminalCommandDelay?: number | undefined; + terminalPowershellCounter?: boolean | undefined; + terminalZshClearEolMark?: boolean | undefined; + terminalZshOhMy?: boolean | undefined; + terminalZshP10k?: boolean | undefined; + terminalZdotdir?: boolean | undefined; + terminalCompressProgressBar?: boolean | undefined; + rateLimitSeconds?: number | undefined; + diffEnabled?: boolean | undefined; + fuzzyMatchThreshold?: number | undefined; + experiments?: { + powerSteering: boolean; + } | undefined; + language?: ("ca" | "de" | "en" | "es" | "fr" | "hi" | "it" | "ja" | "ko" | "nl" | "pl" | "pt-BR" | "ru" | "tr" | "vi" | "zh-CN" | "zh-TW") | undefined; + telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined; + mcpEnabled?: boolean | undefined; + enableMcpServerCreation?: boolean | undefined; + mode?: string | undefined; + modeApiConfigs?: { + [x: string]: string; + } | undefined; + customModes?: { + slug: string; + name: string; + roleDefinition: string; + whenToUse?: string | undefined; + customInstructions?: string | undefined; + groups: (("read" | "edit" | "browser" | "command" | "mcp" | "modes") | [ + "read" | "edit" | "browser" | "command" | "mcp" | "modes", + { + fileRegex?: string | undefined; + description?: string | undefined; + } + ])[]; + source?: ("global" | "project") | undefined; + }[] | undefined; + customModePrompts?: { + [x: string]: { + roleDefinition?: string | undefined; + whenToUse?: string | undefined; + customInstructions?: string | undefined; + } | undefined; + } | undefined; + customSupportPrompts?: { + [x: string]: string | undefined; + } | undefined; + enhancementApiConfigId?: string | undefined; + historyPreviewCollapsed?: boolean | undefined; +}; export type { GlobalSettings } type ProviderSettings = { - apiProvider?: - | ( - | "anthropic" - | "glama" - | "openrouter" - | "bedrock" - | "vertex" - | "openai" - | "ollama" - | "vscode-lm" - | "lmstudio" - | "gemini" - | "openai-native" - | "mistral" - | "deepseek" - | "unbound" - | "requesty" - | "human-relay" - | "fake-ai" - | "xai" - | "groq" - | "chutes" - | "litellm" - ) - | undefined - includeMaxTokens?: boolean | undefined - reasoningEffort?: ("low" | "medium" | "high") | undefined - diffEnabled?: boolean | undefined - fuzzyMatchThreshold?: number | undefined - modelTemperature?: (number | null) | undefined - rateLimitSeconds?: number | undefined - modelMaxTokens?: number | undefined - modelMaxThinkingTokens?: number | undefined - apiModelId?: string | undefined - apiKey?: string | undefined - anthropicBaseUrl?: string | undefined - anthropicUseAuthToken?: boolean | undefined - glamaModelId?: string | undefined - glamaApiKey?: string | undefined - openRouterApiKey?: string | undefined - openRouterModelId?: string | undefined - openRouterBaseUrl?: string | undefined - openRouterSpecificProvider?: string | undefined - openRouterUseMiddleOutTransform?: boolean | undefined - awsAccessKey?: string | undefined - awsSecretKey?: string | undefined - awsSessionToken?: string | undefined - awsRegion?: string | undefined - awsUseCrossRegionInference?: boolean | undefined - awsUsePromptCache?: boolean | undefined - awsProfile?: string | undefined - awsUseProfile?: boolean | undefined - awsCustomArn?: string | undefined - vertexKeyFile?: string | undefined - vertexJsonCredentials?: string | undefined - vertexProjectId?: string | undefined - vertexRegion?: string | undefined - openAiBaseUrl?: string | undefined - openAiApiKey?: string | undefined - openAiLegacyFormat?: boolean | undefined - openAiR1FormatEnabled?: boolean | undefined - openAiModelId?: string | undefined - openAiCustomModelInfo?: - | ({ - maxTokens?: (number | null) | undefined - maxThinkingTokens?: (number | null) | undefined - contextWindow: number - supportsImages?: boolean | undefined - supportsComputerUse?: boolean | undefined - supportsPromptCache: boolean - inputPrice?: number | undefined - outputPrice?: number | undefined - cacheWritesPrice?: number | undefined - cacheReadsPrice?: number | undefined - description?: string | undefined - reasoningEffort?: ("low" | "medium" | "high") | undefined - thinking?: boolean | undefined - minTokensPerCachePoint?: number | undefined - maxCachePoints?: number | undefined - cachableFields?: string[] | undefined - tiers?: - | { - contextWindow: number - inputPrice?: number | undefined - outputPrice?: number | undefined - cacheWritesPrice?: number | undefined - cacheReadsPrice?: number | undefined - }[] - | undefined - } | null) - | undefined - openAiUseAzure?: boolean | undefined - azureApiVersion?: string | undefined - openAiStreamingEnabled?: boolean | undefined - enableReasoningEffort?: boolean | undefined - openAiHostHeader?: string | undefined - openAiHeaders?: - | { - [x: string]: string - } - | undefined - ollamaModelId?: string | undefined - ollamaBaseUrl?: string | undefined - vsCodeLmModelSelector?: - | { - vendor?: string | undefined - family?: string | undefined - version?: string | undefined - id?: string | undefined - } - | undefined - lmStudioModelId?: string | undefined - lmStudioBaseUrl?: string | undefined - lmStudioDraftModelId?: string | undefined - lmStudioSpeculativeDecodingEnabled?: boolean | undefined - geminiApiKey?: string | undefined - googleGeminiBaseUrl?: string | undefined - openAiNativeApiKey?: string | undefined - openAiNativeBaseUrl?: string | undefined - mistralApiKey?: string | undefined - mistralCodestralUrl?: string | undefined - deepSeekBaseUrl?: string | undefined - deepSeekApiKey?: string | undefined - unboundApiKey?: string | undefined - unboundModelId?: string | undefined - requestyApiKey?: string | undefined - requestyModelId?: string | undefined - fakeAi?: unknown | undefined - xaiApiKey?: string | undefined - groqApiKey?: string | undefined - chutesApiKey?: string | undefined - litellmBaseUrl?: string | undefined - litellmApiKey?: string | undefined - litellmModelId?: string | undefined -} + apiProvider?: ("anthropic" | "glama" | "openrouter" | "bedrock" | "vertex" | "openai" | "ollama" | "vscode-lm" | "lmstudio" | "gemini" | "openai-native" | "mistral" | "deepseek" | "unbound" | "requesty" | "human-relay" | "fake-ai" | "xai" | "groq" | "chutes" | "litellm") | undefined; + includeMaxTokens?: boolean | undefined; + reasoningEffort?: ("low" | "medium" | "high") | undefined; + diffEnabled?: boolean | undefined; + fuzzyMatchThreshold?: number | undefined; + modelTemperature?: (number | null) | undefined; + rateLimitSeconds?: number | undefined; + modelMaxTokens?: number | undefined; + modelMaxThinkingTokens?: number | undefined; + apiModelId?: string | undefined; + apiKey?: string | undefined; + anthropicBaseUrl?: string | undefined; + anthropicUseAuthToken?: boolean | undefined; + glamaModelId?: string | undefined; + glamaApiKey?: string | undefined; + openRouterApiKey?: string | undefined; + openRouterModelId?: string | undefined; + openRouterBaseUrl?: string | undefined; + openRouterSpecificProvider?: string | undefined; + openRouterUseMiddleOutTransform?: boolean | undefined; + awsAccessKey?: string | undefined; + awsSecretKey?: string | undefined; + awsSessionToken?: string | undefined; + awsRegion?: string | undefined; + awsUseCrossRegionInference?: boolean | undefined; + awsUsePromptCache?: boolean | undefined; + awsProfile?: string | undefined; + awsUseProfile?: boolean | undefined; + awsCustomArn?: string | undefined; + vertexKeyFile?: string | undefined; + vertexJsonCredentials?: string | undefined; + vertexProjectId?: string | undefined; + vertexRegion?: string | undefined; + openAiBaseUrl?: string | undefined; + openAiApiKey?: string | undefined; + openAiLegacyFormat?: boolean | undefined; + openAiR1FormatEnabled?: boolean | undefined; + openAiModelId?: string | undefined; + openAiCustomModelInfo?: ({ + maxTokens?: (number | null) | undefined; + maxThinkingTokens?: (number | null) | undefined; + contextWindow: number; + supportsImages?: boolean | undefined; + supportsComputerUse?: boolean | undefined; + supportsPromptCache: boolean; + inputPrice?: number | undefined; + outputPrice?: number | undefined; + cacheWritesPrice?: number | undefined; + cacheReadsPrice?: number | undefined; + description?: string | undefined; + reasoningEffort?: ("low" | "medium" | "high") | undefined; + thinking?: boolean | undefined; + minTokensPerCachePoint?: number | undefined; + maxCachePoints?: number | undefined; + cachableFields?: string[] | undefined; + tiers?: { + contextWindow: number; + inputPrice?: number | undefined; + outputPrice?: number | undefined; + cacheWritesPrice?: number | undefined; + cacheReadsPrice?: number | undefined; + }[] | undefined; + } | null) | undefined; + openAiUseAzure?: boolean | undefined; + azureApiVersion?: string | undefined; + openAiStreamingEnabled?: boolean | undefined; + enableReasoningEffort?: boolean | undefined; + openAiHostHeader?: string | undefined; + openAiHeaders?: { + [x: string]: string; + } | undefined; + ollamaModelId?: string | undefined; + ollamaBaseUrl?: string | undefined; + vsCodeLmModelSelector?: { + vendor?: string | undefined; + family?: string | undefined; + version?: string | undefined; + id?: string | undefined; + } | undefined; + lmStudioModelId?: string | undefined; + lmStudioBaseUrl?: string | undefined; + lmStudioDraftModelId?: string | undefined; + lmStudioSpeculativeDecodingEnabled?: boolean | undefined; + geminiApiKey?: string | undefined; + googleGeminiBaseUrl?: string | undefined; + openAiNativeApiKey?: string | undefined; + openAiNativeBaseUrl?: string | undefined; + mistralApiKey?: string | undefined; + mistralCodestralUrl?: string | undefined; + deepSeekBaseUrl?: string | undefined; + deepSeekApiKey?: string | undefined; + unboundApiKey?: string | undefined; + unboundModelId?: string | undefined; + requestyApiKey?: string | undefined; + requestyModelId?: string | undefined; + fakeAi?: unknown | undefined; + xaiApiKey?: string | undefined; + groqApiKey?: string | undefined; + chutesApiKey?: string | undefined; + litellmBaseUrl?: string | undefined; + litellmApiKey?: string | undefined; + litellmModelId?: string | undefined; +}; export type { ProviderSettings } type ProviderSettingsEntry = { - id: string - name: string - apiProvider?: - | ( - | "anthropic" - | "glama" - | "openrouter" - | "bedrock" - | "vertex" - | "openai" - | "ollama" - | "vscode-lm" - | "lmstudio" - | "gemini" - | "openai-native" - | "mistral" - | "deepseek" - | "unbound" - | "requesty" - | "human-relay" - | "fake-ai" - | "xai" - | "groq" - | "chutes" - | "litellm" - ) - | undefined -} + id: string; + name: string; + apiProvider?: ("anthropic" | "glama" | "openrouter" | "bedrock" | "vertex" | "openai" | "ollama" | "vscode-lm" | "lmstudio" | "gemini" | "openai-native" | "mistral" | "deepseek" | "unbound" | "requesty" | "human-relay" | "fake-ai" | "xai" | "groq" | "chutes" | "litellm") | undefined; +}; export type { ProviderSettingsEntry } type ClineMessage = { - ts: number - type: "ask" | "say" - ask?: - | ( - | "followup" - | "command" - | "command_output" - | "completion_result" - | "tool" - | "api_req_failed" - | "resume_task" - | "resume_completed_task" - | "mistake_limit_reached" - | "browser_action_launch" - | "use_mcp_server" - ) - | undefined - say?: - | ( - | "error" - | "api_req_started" - | "api_req_finished" - | "api_req_retried" - | "api_req_retry_delayed" - | "api_req_deleted" - | "text" - | "reasoning" - | "completion_result" - | "user_feedback" - | "user_feedback_diff" - | "command_output" - | "shell_integration_warning" - | "browser_action" - | "browser_action_result" - | "mcp_server_request_started" - | "mcp_server_response" - | "subtask_result" - | "checkpoint_saved" - | "rooignore_error" - | "diff_error" - ) - | undefined - text?: string | undefined - images?: string[] | undefined - partial?: boolean | undefined - reasoning?: string | undefined - conversationHistoryIndex?: number | undefined - checkpoint?: - | { - [x: string]: unknown - } - | undefined - progressStatus?: - | { - icon?: string | undefined - text?: string | undefined - } - | undefined -} + ts: number; + type: "ask" | "say"; + ask?: ("followup" | "command" | "command_output" | "completion_result" | "tool" | "api_req_failed" | "resume_task" | "resume_completed_task" | "mistake_limit_reached" | "browser_action_launch" | "use_mcp_server") | undefined; + say?: ("error" | "api_req_started" | "api_req_finished" | "api_req_retried" | "api_req_retry_delayed" | "api_req_deleted" | "text" | "reasoning" | "completion_result" | "user_feedback" | "user_feedback_diff" | "command_output" | "shell_integration_warning" | "browser_action" | "browser_action_result" | "mcp_server_request_started" | "mcp_server_response" | "subtask_result" | "checkpoint_saved" | "rooignore_error" | "diff_error") | undefined; + text?: string | undefined; + images?: string[] | undefined; + partial?: boolean | undefined; + reasoning?: string | undefined; + conversationHistoryIndex?: number | undefined; + checkpoint?: { + [x: string]: unknown; + } | undefined; + progressStatus?: { + icon?: string | undefined; + text?: string | undefined; + } | undefined; +}; export type { ClineMessage } type TokenUsage = { - totalTokensIn: number - totalTokensOut: number - totalCacheWrites?: number | undefined - totalCacheReads?: number | undefined - totalCost: number - contextTokens: number -} + totalTokensIn: number; + totalTokensOut: number; + totalCacheWrites?: number | undefined; + totalCacheReads?: number | undefined; + totalCost: number; + contextTokens: number; +}; export type { TokenUsage } type RooCodeEvents = { - message: [ - { - taskId: string - action: "created" | "updated" - message: { - ts: number - type: "ask" | "say" - ask?: - | ( - | "followup" - | "command" - | "command_output" - | "completion_result" - | "tool" - | "api_req_failed" - | "resume_task" - | "resume_completed_task" - | "mistake_limit_reached" - | "browser_action_launch" - | "use_mcp_server" - ) - | undefined - say?: - | ( - | "error" - | "api_req_started" - | "api_req_finished" - | "api_req_retried" - | "api_req_retry_delayed" - | "api_req_deleted" - | "text" - | "reasoning" - | "completion_result" - | "user_feedback" - | "user_feedback_diff" - | "command_output" - | "shell_integration_warning" - | "browser_action" - | "browser_action_result" - | "mcp_server_request_started" - | "mcp_server_response" - | "subtask_result" - | "checkpoint_saved" - | "rooignore_error" - | "diff_error" - ) - | undefined - text?: string | undefined - images?: string[] | undefined - partial?: boolean | undefined - reasoning?: string | undefined - conversationHistoryIndex?: number | undefined - checkpoint?: - | { - [x: string]: unknown - } - | undefined - progressStatus?: - | { - icon?: string | undefined - text?: string | undefined - } - | undefined - } - }, - ] - taskCreated: [string] - taskStarted: [string] - taskModeSwitched: [string, string] - taskPaused: [string] - taskUnpaused: [string] - taskAskResponded: [string] - taskAborted: [string] - taskSpawned: [string, string] - taskCompleted: [ - string, - { - totalTokensIn: number - totalTokensOut: number - totalCacheWrites?: number | undefined - totalCacheReads?: number | undefined - totalCost: number - contextTokens: number - }, - { - [x: string]: { - attempts: number - failures: number - } - }, - ] - taskTokenUsageUpdated: [ - string, - { - totalTokensIn: number - totalTokensOut: number - totalCacheWrites?: number | undefined - totalCacheReads?: number | undefined - totalCost: number - contextTokens: number - }, - ] - taskToolFailed: [ - string, - ( - | "execute_command" - | "read_file" - | "write_to_file" - | "apply_diff" - | "insert_content" - | "search_and_replace" - | "search_files" - | "list_files" - | "list_code_definition_names" - | "browser_action" - | "use_mcp_tool" - | "access_mcp_resource" - | "ask_followup_question" - | "attempt_completion" - | "switch_mode" - | "new_task" - | "fetch_instructions" - ), - string, - ] -} + message: [ + { + taskId: string; + action: "created" | "updated"; + message: { + ts: number; + type: "ask" | "say"; + ask?: ("followup" | "command" | "command_output" | "completion_result" | "tool" | "api_req_failed" | "resume_task" | "resume_completed_task" | "mistake_limit_reached" | "browser_action_launch" | "use_mcp_server") | undefined; + say?: ("error" | "api_req_started" | "api_req_finished" | "api_req_retried" | "api_req_retry_delayed" | "api_req_deleted" | "text" | "reasoning" | "completion_result" | "user_feedback" | "user_feedback_diff" | "command_output" | "shell_integration_warning" | "browser_action" | "browser_action_result" | "mcp_server_request_started" | "mcp_server_response" | "subtask_result" | "checkpoint_saved" | "rooignore_error" | "diff_error") | undefined; + text?: string | undefined; + images?: string[] | undefined; + partial?: boolean | undefined; + reasoning?: string | undefined; + conversationHistoryIndex?: number | undefined; + checkpoint?: { + [x: string]: unknown; + } | undefined; + progressStatus?: { + icon?: string | undefined; + text?: string | undefined; + } | undefined; + }; + } + ]; + taskCreated: [ + string + ]; + taskStarted: [ + string + ]; + taskModeSwitched: [ + string, + string + ]; + taskPaused: [ + string + ]; + taskUnpaused: [ + string + ]; + taskAskResponded: [ + string + ]; + taskAborted: [ + string + ]; + taskSpawned: [ + string, + string + ]; + taskCompleted: [ + string, + { + totalTokensIn: number; + totalTokensOut: number; + totalCacheWrites?: number | undefined; + totalCacheReads?: number | undefined; + totalCost: number; + contextTokens: number; + }, + { + [x: string]: { + attempts: number; + failures: number; + }; + } + ]; + taskTokenUsageUpdated: [ + string, + { + totalTokensIn: number; + totalTokensOut: number; + totalCacheWrites?: number | undefined; + totalCacheReads?: number | undefined; + totalCost: number; + contextTokens: number; + } + ]; + taskToolFailed: [ + string, + "execute_command" | "read_file" | "write_to_file" | "apply_diff" | "insert_content" | "search_and_replace" | "search_files" | "list_files" | "list_code_definition_names" | "browser_action" | "use_mcp_tool" | "access_mcp_resource" | "ask_followup_question" | "attempt_completion" | "switch_mode" | "new_task" | "fetch_instructions" | "find_references" | "read_function", + string + ]; +}; export type { RooCodeEvents } -type IpcMessage = - | { - type: "Ack" - origin: "server" - data: { - clientId: string - pid: number - ppid: number - } - } - | { - type: "TaskCommand" - origin: "client" - clientId: string - data: - | { - commandName: "StartNewTask" - data: { - configuration: { - apiProvider?: - | ( - | "anthropic" - | "glama" - | "openrouter" - | "bedrock" - | "vertex" - | "openai" - | "ollama" - | "vscode-lm" - | "lmstudio" - | "gemini" - | "openai-native" - | "mistral" - | "deepseek" - | "unbound" - | "requesty" - | "human-relay" - | "fake-ai" - | "xai" - | "groq" - | "chutes" - | "litellm" - ) - | undefined - includeMaxTokens?: boolean | undefined - reasoningEffort?: ("low" | "medium" | "high") | undefined - diffEnabled?: boolean | undefined - fuzzyMatchThreshold?: number | undefined - modelTemperature?: (number | null) | undefined - rateLimitSeconds?: number | undefined - modelMaxTokens?: number | undefined - modelMaxThinkingTokens?: number | undefined - apiModelId?: string | undefined - apiKey?: string | undefined - anthropicBaseUrl?: string | undefined - anthropicUseAuthToken?: boolean | undefined - glamaModelId?: string | undefined - glamaApiKey?: string | undefined - openRouterApiKey?: string | undefined - openRouterModelId?: string | undefined - openRouterBaseUrl?: string | undefined - openRouterSpecificProvider?: string | undefined - openRouterUseMiddleOutTransform?: boolean | undefined - awsAccessKey?: string | undefined - awsSecretKey?: string | undefined - awsSessionToken?: string | undefined - awsRegion?: string | undefined - awsUseCrossRegionInference?: boolean | undefined - awsUsePromptCache?: boolean | undefined - awsProfile?: string | undefined - awsUseProfile?: boolean | undefined - awsCustomArn?: string | undefined - vertexKeyFile?: string | undefined - vertexJsonCredentials?: string | undefined - vertexProjectId?: string | undefined - vertexRegion?: string | undefined - openAiBaseUrl?: string | undefined - openAiApiKey?: string | undefined - openAiLegacyFormat?: boolean | undefined - openAiR1FormatEnabled?: boolean | undefined - openAiModelId?: string | undefined - openAiCustomModelInfo?: - | ({ - maxTokens?: (number | null) | undefined - maxThinkingTokens?: (number | null) | undefined - contextWindow: number - supportsImages?: boolean | undefined - supportsComputerUse?: boolean | undefined - supportsPromptCache: boolean - inputPrice?: number | undefined - outputPrice?: number | undefined - cacheWritesPrice?: number | undefined - cacheReadsPrice?: number | undefined - description?: string | undefined - reasoningEffort?: ("low" | "medium" | "high") | undefined - thinking?: boolean | undefined - minTokensPerCachePoint?: number | undefined - maxCachePoints?: number | undefined - cachableFields?: string[] | undefined - tiers?: - | { - contextWindow: number - inputPrice?: number | undefined - outputPrice?: number | undefined - cacheWritesPrice?: number | undefined - cacheReadsPrice?: number | undefined - }[] - | undefined - } | null) - | undefined - openAiUseAzure?: boolean | undefined - azureApiVersion?: string | undefined - openAiStreamingEnabled?: boolean | undefined - enableReasoningEffort?: boolean | undefined - openAiHostHeader?: string | undefined - openAiHeaders?: - | { - [x: string]: string - } - | undefined - ollamaModelId?: string | undefined - ollamaBaseUrl?: string | undefined - vsCodeLmModelSelector?: - | { - vendor?: string | undefined - family?: string | undefined - version?: string | undefined - id?: string | undefined - } - | undefined - lmStudioModelId?: string | undefined - lmStudioBaseUrl?: string | undefined - lmStudioDraftModelId?: string | undefined - lmStudioSpeculativeDecodingEnabled?: boolean | undefined - geminiApiKey?: string | undefined - googleGeminiBaseUrl?: string | undefined - openAiNativeApiKey?: string | undefined - openAiNativeBaseUrl?: string | undefined - mistralApiKey?: string | undefined - mistralCodestralUrl?: string | undefined - deepSeekBaseUrl?: string | undefined - deepSeekApiKey?: string | undefined - unboundApiKey?: string | undefined - unboundModelId?: string | undefined - requestyApiKey?: string | undefined - requestyModelId?: string | undefined - fakeAi?: unknown | undefined - xaiApiKey?: string | undefined - groqApiKey?: string | undefined - chutesApiKey?: string | undefined - litellmBaseUrl?: string | undefined - litellmApiKey?: string | undefined - litellmModelId?: string | undefined - currentApiConfigName?: string | undefined - listApiConfigMeta?: - | { - id: string - name: string - apiProvider?: - | ( - | "anthropic" - | "glama" - | "openrouter" - | "bedrock" - | "vertex" - | "openai" - | "ollama" - | "vscode-lm" - | "lmstudio" - | "gemini" - | "openai-native" - | "mistral" - | "deepseek" - | "unbound" - | "requesty" - | "human-relay" - | "fake-ai" - | "xai" - | "groq" - | "chutes" - | "litellm" - ) - | undefined - }[] - | undefined - pinnedApiConfigs?: - | { - [x: string]: boolean - } - | undefined - lastShownAnnouncementId?: string | undefined - customInstructions?: string | undefined - taskHistory?: - | { - id: string - number: number - ts: number - task: string - tokensIn: number - tokensOut: number - cacheWrites?: number | undefined - cacheReads?: number | undefined - totalCost: number - size?: number | undefined - workspace?: string | undefined - }[] - | undefined - autoApprovalEnabled?: boolean | undefined - alwaysAllowReadOnly?: boolean | undefined - alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined - alwaysAllowWrite?: boolean | undefined - alwaysAllowWriteOutsideWorkspace?: boolean | undefined - writeDelayMs?: number | undefined - alwaysAllowBrowser?: boolean | undefined - alwaysApproveResubmit?: boolean | undefined - requestDelaySeconds?: number | undefined - alwaysAllowMcp?: boolean | undefined - alwaysAllowModeSwitch?: boolean | undefined - alwaysAllowSubtasks?: boolean | undefined - alwaysAllowExecute?: boolean | undefined - allowedCommands?: string[] | undefined - browserToolEnabled?: boolean | undefined - browserViewportSize?: string | undefined - screenshotQuality?: number | undefined - remoteBrowserEnabled?: boolean | undefined - remoteBrowserHost?: string | undefined - cachedChromeHostUrl?: string | undefined - enableCheckpoints?: boolean | undefined - ttsEnabled?: boolean | undefined - ttsSpeed?: number | undefined - soundEnabled?: boolean | undefined - soundVolume?: number | undefined - maxOpenTabsContext?: number | undefined - maxWorkspaceFiles?: number | undefined - showRooIgnoredFiles?: boolean | undefined - maxReadFileLine?: number | undefined - terminalOutputLineLimit?: number | undefined - terminalShellIntegrationTimeout?: number | undefined - terminalShellIntegrationDisabled?: boolean | undefined - terminalCommandDelay?: number | undefined - terminalPowershellCounter?: boolean | undefined - terminalZshClearEolMark?: boolean | undefined - terminalZshOhMy?: boolean | undefined - terminalZshP10k?: boolean | undefined - terminalZdotdir?: boolean | undefined - terminalCompressProgressBar?: boolean | undefined - experiments?: - | { - powerSteering: boolean - } - | undefined - language?: - | ( - | "ca" - | "de" - | "en" - | "es" - | "fr" - | "hi" - | "it" - | "ja" - | "ko" - | "nl" - | "pl" - | "pt-BR" - | "ru" - | "tr" - | "vi" - | "zh-CN" - | "zh-TW" - ) - | undefined - telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined - mcpEnabled?: boolean | undefined - enableMcpServerCreation?: boolean | undefined - mode?: string | undefined - modeApiConfigs?: - | { - [x: string]: string - } - | undefined - customModes?: - | { - slug: string - name: string - roleDefinition: string - whenToUse?: string | undefined - customInstructions?: string | undefined - groups: ( - | ("read" | "edit" | "browser" | "command" | "mcp" | "modes") - | [ - "read" | "edit" | "browser" | "command" | "mcp" | "modes", - { - fileRegex?: string | undefined - description?: string | undefined - }, - ] - )[] - source?: ("global" | "project") | undefined - }[] - | undefined - customModePrompts?: - | { - [x: string]: - | { - roleDefinition?: string | undefined - whenToUse?: string | undefined - customInstructions?: string | undefined - } - | undefined - } - | undefined - customSupportPrompts?: - | { - [x: string]: string | undefined - } - | undefined - enhancementApiConfigId?: string | undefined - historyPreviewCollapsed?: boolean | undefined - } - text: string - images?: string[] | undefined - newTab?: boolean | undefined - } - } - | { - commandName: "CancelTask" - data: string - } - | { - commandName: "CloseTask" - data: string - } - } - | { - type: "TaskEvent" - origin: "server" - relayClientId?: string | undefined - data: - | { - eventName: "message" - payload: [ - { - taskId: string - action: "created" | "updated" - message: { - ts: number - type: "ask" | "say" - ask?: - | ( - | "followup" - | "command" - | "command_output" - | "completion_result" - | "tool" - | "api_req_failed" - | "resume_task" - | "resume_completed_task" - | "mistake_limit_reached" - | "browser_action_launch" - | "use_mcp_server" - ) - | undefined - say?: - | ( - | "error" - | "api_req_started" - | "api_req_finished" - | "api_req_retried" - | "api_req_retry_delayed" - | "api_req_deleted" - | "text" - | "reasoning" - | "completion_result" - | "user_feedback" - | "user_feedback_diff" - | "command_output" - | "shell_integration_warning" - | "browser_action" - | "browser_action_result" - | "mcp_server_request_started" - | "mcp_server_response" - | "subtask_result" - | "checkpoint_saved" - | "rooignore_error" - | "diff_error" - ) - | undefined - text?: string | undefined - images?: string[] | undefined - partial?: boolean | undefined - reasoning?: string | undefined - conversationHistoryIndex?: number | undefined - checkpoint?: - | { - [x: string]: unknown - } - | undefined - progressStatus?: - | { - icon?: string | undefined - text?: string | undefined - } - | undefined - } - }, - ] - } - | { - eventName: "taskCreated" - payload: [string] - } - | { - eventName: "taskStarted" - payload: [string] - } - | { - eventName: "taskModeSwitched" - payload: [string, string] - } - | { - eventName: "taskPaused" - payload: [string] - } - | { - eventName: "taskUnpaused" - payload: [string] - } - | { - eventName: "taskAskResponded" - payload: [string] - } - | { - eventName: "taskAborted" - payload: [string] - } - | { - eventName: "taskSpawned" - payload: [string, string] - } - | { - eventName: "taskCompleted" - payload: [ - string, - { - totalTokensIn: number - totalTokensOut: number - totalCacheWrites?: number | undefined - totalCacheReads?: number | undefined - totalCost: number - contextTokens: number - }, - { - [x: string]: { - attempts: number - failures: number - } - }, - ] - } - | { - eventName: "taskTokenUsageUpdated" - payload: [ - string, - { - totalTokensIn: number - totalTokensOut: number - totalCacheWrites?: number | undefined - totalCacheReads?: number | undefined - totalCost: number - contextTokens: number - }, - ] - } - } +type IpcMessage = { + type: "Ack"; + origin: "server"; + data: { + clientId: string; + pid: number; + ppid: number; + }; +} | { + type: "TaskCommand"; + origin: "client"; + clientId: string; + data: { + commandName: "StartNewTask"; + data: { + configuration: { + apiProvider?: ("anthropic" | "glama" | "openrouter" | "bedrock" | "vertex" | "openai" | "ollama" | "vscode-lm" | "lmstudio" | "gemini" | "openai-native" | "mistral" | "deepseek" | "unbound" | "requesty" | "human-relay" | "fake-ai" | "xai" | "groq" | "chutes" | "litellm") | undefined; + includeMaxTokens?: boolean | undefined; + reasoningEffort?: ("low" | "medium" | "high") | undefined; + diffEnabled?: boolean | undefined; + fuzzyMatchThreshold?: number | undefined; + modelTemperature?: (number | null) | undefined; + rateLimitSeconds?: number | undefined; + modelMaxTokens?: number | undefined; + modelMaxThinkingTokens?: number | undefined; + apiModelId?: string | undefined; + apiKey?: string | undefined; + anthropicBaseUrl?: string | undefined; + anthropicUseAuthToken?: boolean | undefined; + glamaModelId?: string | undefined; + glamaApiKey?: string | undefined; + openRouterApiKey?: string | undefined; + openRouterModelId?: string | undefined; + openRouterBaseUrl?: string | undefined; + openRouterSpecificProvider?: string | undefined; + openRouterUseMiddleOutTransform?: boolean | undefined; + awsAccessKey?: string | undefined; + awsSecretKey?: string | undefined; + awsSessionToken?: string | undefined; + awsRegion?: string | undefined; + awsUseCrossRegionInference?: boolean | undefined; + awsUsePromptCache?: boolean | undefined; + awsProfile?: string | undefined; + awsUseProfile?: boolean | undefined; + awsCustomArn?: string | undefined; + vertexKeyFile?: string | undefined; + vertexJsonCredentials?: string | undefined; + vertexProjectId?: string | undefined; + vertexRegion?: string | undefined; + openAiBaseUrl?: string | undefined; + openAiApiKey?: string | undefined; + openAiLegacyFormat?: boolean | undefined; + openAiR1FormatEnabled?: boolean | undefined; + openAiModelId?: string | undefined; + openAiCustomModelInfo?: ({ + maxTokens?: (number | null) | undefined; + maxThinkingTokens?: (number | null) | undefined; + contextWindow: number; + supportsImages?: boolean | undefined; + supportsComputerUse?: boolean | undefined; + supportsPromptCache: boolean; + inputPrice?: number | undefined; + outputPrice?: number | undefined; + cacheWritesPrice?: number | undefined; + cacheReadsPrice?: number | undefined; + description?: string | undefined; + reasoningEffort?: ("low" | "medium" | "high") | undefined; + thinking?: boolean | undefined; + minTokensPerCachePoint?: number | undefined; + maxCachePoints?: number | undefined; + cachableFields?: string[] | undefined; + tiers?: { + contextWindow: number; + inputPrice?: number | undefined; + outputPrice?: number | undefined; + cacheWritesPrice?: number | undefined; + cacheReadsPrice?: number | undefined; + }[] | undefined; + } | null) | undefined; + openAiUseAzure?: boolean | undefined; + azureApiVersion?: string | undefined; + openAiStreamingEnabled?: boolean | undefined; + enableReasoningEffort?: boolean | undefined; + openAiHostHeader?: string | undefined; + openAiHeaders?: { + [x: string]: string; + } | undefined; + ollamaModelId?: string | undefined; + ollamaBaseUrl?: string | undefined; + vsCodeLmModelSelector?: { + vendor?: string | undefined; + family?: string | undefined; + version?: string | undefined; + id?: string | undefined; + } | undefined; + lmStudioModelId?: string | undefined; + lmStudioBaseUrl?: string | undefined; + lmStudioDraftModelId?: string | undefined; + lmStudioSpeculativeDecodingEnabled?: boolean | undefined; + geminiApiKey?: string | undefined; + googleGeminiBaseUrl?: string | undefined; + openAiNativeApiKey?: string | undefined; + openAiNativeBaseUrl?: string | undefined; + mistralApiKey?: string | undefined; + mistralCodestralUrl?: string | undefined; + deepSeekBaseUrl?: string | undefined; + deepSeekApiKey?: string | undefined; + unboundApiKey?: string | undefined; + unboundModelId?: string | undefined; + requestyApiKey?: string | undefined; + requestyModelId?: string | undefined; + fakeAi?: unknown | undefined; + xaiApiKey?: string | undefined; + groqApiKey?: string | undefined; + chutesApiKey?: string | undefined; + litellmBaseUrl?: string | undefined; + litellmApiKey?: string | undefined; + litellmModelId?: string | undefined; + currentApiConfigName?: string | undefined; + listApiConfigMeta?: { + id: string; + name: string; + apiProvider?: ("anthropic" | "glama" | "openrouter" | "bedrock" | "vertex" | "openai" | "ollama" | "vscode-lm" | "lmstudio" | "gemini" | "openai-native" | "mistral" | "deepseek" | "unbound" | "requesty" | "human-relay" | "fake-ai" | "xai" | "groq" | "chutes" | "litellm") | undefined; + }[] | undefined; + pinnedApiConfigs?: { + [x: string]: boolean; + } | undefined; + lastShownAnnouncementId?: string | undefined; + customInstructions?: string | undefined; + taskHistory?: { + id: string; + number: number; + ts: number; + task: string; + tokensIn: number; + tokensOut: number; + cacheWrites?: number | undefined; + cacheReads?: number | undefined; + totalCost: number; + size?: number | undefined; + workspace?: string | undefined; + }[] | undefined; + autoApprovalEnabled?: boolean | undefined; + alwaysAllowReadOnly?: boolean | undefined; + alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined; + alwaysAllowWrite?: boolean | undefined; + alwaysAllowWriteOutsideWorkspace?: boolean | undefined; + writeDelayMs?: number | undefined; + alwaysAllowBrowser?: boolean | undefined; + alwaysApproveResubmit?: boolean | undefined; + requestDelaySeconds?: number | undefined; + alwaysAllowMcp?: boolean | undefined; + alwaysAllowModeSwitch?: boolean | undefined; + alwaysAllowSubtasks?: boolean | undefined; + alwaysAllowExecute?: boolean | undefined; + allowedCommands?: string[] | undefined; + browserToolEnabled?: boolean | undefined; + browserViewportSize?: string | undefined; + screenshotQuality?: number | undefined; + remoteBrowserEnabled?: boolean | undefined; + remoteBrowserHost?: string | undefined; + cachedChromeHostUrl?: string | undefined; + enableCheckpoints?: boolean | undefined; + ttsEnabled?: boolean | undefined; + ttsSpeed?: number | undefined; + soundEnabled?: boolean | undefined; + soundVolume?: number | undefined; + maxOpenTabsContext?: number | undefined; + maxWorkspaceFiles?: number | undefined; + showRooIgnoredFiles?: boolean | undefined; + maxReadFileLine?: number | undefined; + terminalOutputLineLimit?: number | undefined; + terminalShellIntegrationTimeout?: number | undefined; + terminalShellIntegrationDisabled?: boolean | undefined; + terminalCommandDelay?: number | undefined; + terminalPowershellCounter?: boolean | undefined; + terminalZshClearEolMark?: boolean | undefined; + terminalZshOhMy?: boolean | undefined; + terminalZshP10k?: boolean | undefined; + terminalZdotdir?: boolean | undefined; + terminalCompressProgressBar?: boolean | undefined; + experiments?: { + powerSteering: boolean; + } | undefined; + language?: ("ca" | "de" | "en" | "es" | "fr" | "hi" | "it" | "ja" | "ko" | "nl" | "pl" | "pt-BR" | "ru" | "tr" | "vi" | "zh-CN" | "zh-TW") | undefined; + telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined; + mcpEnabled?: boolean | undefined; + enableMcpServerCreation?: boolean | undefined; + mode?: string | undefined; + modeApiConfigs?: { + [x: string]: string; + } | undefined; + customModes?: { + slug: string; + name: string; + roleDefinition: string; + whenToUse?: string | undefined; + customInstructions?: string | undefined; + groups: (("read" | "edit" | "browser" | "command" | "mcp" | "modes") | [ + "read" | "edit" | "browser" | "command" | "mcp" | "modes", + { + fileRegex?: string | undefined; + description?: string | undefined; + } + ])[]; + source?: ("global" | "project") | undefined; + }[] | undefined; + customModePrompts?: { + [x: string]: { + roleDefinition?: string | undefined; + whenToUse?: string | undefined; + customInstructions?: string | undefined; + } | undefined; + } | undefined; + customSupportPrompts?: { + [x: string]: string | undefined; + } | undefined; + enhancementApiConfigId?: string | undefined; + historyPreviewCollapsed?: boolean | undefined; + }; + text: string; + images?: string[] | undefined; + newTab?: boolean | undefined; + }; + } | { + commandName: "CancelTask"; + data: string; + } | { + commandName: "CloseTask"; + data: string; + }; +} | { + type: "TaskEvent"; + origin: "server"; + relayClientId?: string | undefined; + data: { + eventName: "message"; + payload: [ + { + taskId: string; + action: "created" | "updated"; + message: { + ts: number; + type: "ask" | "say"; + ask?: ("followup" | "command" | "command_output" | "completion_result" | "tool" | "api_req_failed" | "resume_task" | "resume_completed_task" | "mistake_limit_reached" | "browser_action_launch" | "use_mcp_server") | undefined; + say?: ("error" | "api_req_started" | "api_req_finished" | "api_req_retried" | "api_req_retry_delayed" | "api_req_deleted" | "text" | "reasoning" | "completion_result" | "user_feedback" | "user_feedback_diff" | "command_output" | "shell_integration_warning" | "browser_action" | "browser_action_result" | "mcp_server_request_started" | "mcp_server_response" | "subtask_result" | "checkpoint_saved" | "rooignore_error" | "diff_error") | undefined; + text?: string | undefined; + images?: string[] | undefined; + partial?: boolean | undefined; + reasoning?: string | undefined; + conversationHistoryIndex?: number | undefined; + checkpoint?: { + [x: string]: unknown; + } | undefined; + progressStatus?: { + icon?: string | undefined; + text?: string | undefined; + } | undefined; + }; + } + ]; + } | { + eventName: "taskCreated"; + payload: [ + string + ]; + } | { + eventName: "taskStarted"; + payload: [ + string + ]; + } | { + eventName: "taskModeSwitched"; + payload: [ + string, + string + ]; + } | { + eventName: "taskPaused"; + payload: [ + string + ]; + } | { + eventName: "taskUnpaused"; + payload: [ + string + ]; + } | { + eventName: "taskAskResponded"; + payload: [ + string + ]; + } | { + eventName: "taskAborted"; + payload: [ + string + ]; + } | { + eventName: "taskSpawned"; + payload: [ + string, + string + ]; + } | { + eventName: "taskCompleted"; + payload: [ + string, + { + totalTokensIn: number; + totalTokensOut: number; + totalCacheWrites?: number | undefined; + totalCacheReads?: number | undefined; + totalCost: number; + contextTokens: number; + }, + { + [x: string]: { + attempts: number; + failures: number; + }; + } + ]; + } | { + eventName: "taskTokenUsageUpdated"; + payload: [ + string, + { + totalTokensIn: number; + totalTokensOut: number; + totalCacheWrites?: number | undefined; + totalCacheReads?: number | undefined; + totalCost: number; + contextTokens: number; + } + ]; + }; +}; export type { IpcMessage } -type TaskCommand = - | { - commandName: "StartNewTask" - data: { - configuration: { - apiProvider?: - | ( - | "anthropic" - | "glama" - | "openrouter" - | "bedrock" - | "vertex" - | "openai" - | "ollama" - | "vscode-lm" - | "lmstudio" - | "gemini" - | "openai-native" - | "mistral" - | "deepseek" - | "unbound" - | "requesty" - | "human-relay" - | "fake-ai" - | "xai" - | "groq" - | "chutes" - | "litellm" - ) - | undefined - includeMaxTokens?: boolean | undefined - reasoningEffort?: ("low" | "medium" | "high") | undefined - diffEnabled?: boolean | undefined - fuzzyMatchThreshold?: number | undefined - modelTemperature?: (number | null) | undefined - rateLimitSeconds?: number | undefined - modelMaxTokens?: number | undefined - modelMaxThinkingTokens?: number | undefined - apiModelId?: string | undefined - apiKey?: string | undefined - anthropicBaseUrl?: string | undefined - anthropicUseAuthToken?: boolean | undefined - glamaModelId?: string | undefined - glamaApiKey?: string | undefined - openRouterApiKey?: string | undefined - openRouterModelId?: string | undefined - openRouterBaseUrl?: string | undefined - openRouterSpecificProvider?: string | undefined - openRouterUseMiddleOutTransform?: boolean | undefined - awsAccessKey?: string | undefined - awsSecretKey?: string | undefined - awsSessionToken?: string | undefined - awsRegion?: string | undefined - awsUseCrossRegionInference?: boolean | undefined - awsUsePromptCache?: boolean | undefined - awsProfile?: string | undefined - awsUseProfile?: boolean | undefined - awsCustomArn?: string | undefined - vertexKeyFile?: string | undefined - vertexJsonCredentials?: string | undefined - vertexProjectId?: string | undefined - vertexRegion?: string | undefined - openAiBaseUrl?: string | undefined - openAiApiKey?: string | undefined - openAiLegacyFormat?: boolean | undefined - openAiR1FormatEnabled?: boolean | undefined - openAiModelId?: string | undefined - openAiCustomModelInfo?: - | ({ - maxTokens?: (number | null) | undefined - maxThinkingTokens?: (number | null) | undefined - contextWindow: number - supportsImages?: boolean | undefined - supportsComputerUse?: boolean | undefined - supportsPromptCache: boolean - inputPrice?: number | undefined - outputPrice?: number | undefined - cacheWritesPrice?: number | undefined - cacheReadsPrice?: number | undefined - description?: string | undefined - reasoningEffort?: ("low" | "medium" | "high") | undefined - thinking?: boolean | undefined - minTokensPerCachePoint?: number | undefined - maxCachePoints?: number | undefined - cachableFields?: string[] | undefined - tiers?: - | { - contextWindow: number - inputPrice?: number | undefined - outputPrice?: number | undefined - cacheWritesPrice?: number | undefined - cacheReadsPrice?: number | undefined - }[] - | undefined - } | null) - | undefined - openAiUseAzure?: boolean | undefined - azureApiVersion?: string | undefined - openAiStreamingEnabled?: boolean | undefined - enableReasoningEffort?: boolean | undefined - openAiHostHeader?: string | undefined - openAiHeaders?: - | { - [x: string]: string - } - | undefined - ollamaModelId?: string | undefined - ollamaBaseUrl?: string | undefined - vsCodeLmModelSelector?: - | { - vendor?: string | undefined - family?: string | undefined - version?: string | undefined - id?: string | undefined - } - | undefined - lmStudioModelId?: string | undefined - lmStudioBaseUrl?: string | undefined - lmStudioDraftModelId?: string | undefined - lmStudioSpeculativeDecodingEnabled?: boolean | undefined - geminiApiKey?: string | undefined - googleGeminiBaseUrl?: string | undefined - openAiNativeApiKey?: string | undefined - openAiNativeBaseUrl?: string | undefined - mistralApiKey?: string | undefined - mistralCodestralUrl?: string | undefined - deepSeekBaseUrl?: string | undefined - deepSeekApiKey?: string | undefined - unboundApiKey?: string | undefined - unboundModelId?: string | undefined - requestyApiKey?: string | undefined - requestyModelId?: string | undefined - fakeAi?: unknown | undefined - xaiApiKey?: string | undefined - groqApiKey?: string | undefined - chutesApiKey?: string | undefined - litellmBaseUrl?: string | undefined - litellmApiKey?: string | undefined - litellmModelId?: string | undefined - currentApiConfigName?: string | undefined - listApiConfigMeta?: - | { - id: string - name: string - apiProvider?: - | ( - | "anthropic" - | "glama" - | "openrouter" - | "bedrock" - | "vertex" - | "openai" - | "ollama" - | "vscode-lm" - | "lmstudio" - | "gemini" - | "openai-native" - | "mistral" - | "deepseek" - | "unbound" - | "requesty" - | "human-relay" - | "fake-ai" - | "xai" - | "groq" - | "chutes" - | "litellm" - ) - | undefined - }[] - | undefined - pinnedApiConfigs?: - | { - [x: string]: boolean - } - | undefined - lastShownAnnouncementId?: string | undefined - customInstructions?: string | undefined - taskHistory?: - | { - id: string - number: number - ts: number - task: string - tokensIn: number - tokensOut: number - cacheWrites?: number | undefined - cacheReads?: number | undefined - totalCost: number - size?: number | undefined - workspace?: string | undefined - }[] - | undefined - autoApprovalEnabled?: boolean | undefined - alwaysAllowReadOnly?: boolean | undefined - alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined - alwaysAllowWrite?: boolean | undefined - alwaysAllowWriteOutsideWorkspace?: boolean | undefined - writeDelayMs?: number | undefined - alwaysAllowBrowser?: boolean | undefined - alwaysApproveResubmit?: boolean | undefined - requestDelaySeconds?: number | undefined - alwaysAllowMcp?: boolean | undefined - alwaysAllowModeSwitch?: boolean | undefined - alwaysAllowSubtasks?: boolean | undefined - alwaysAllowExecute?: boolean | undefined - allowedCommands?: string[] | undefined - browserToolEnabled?: boolean | undefined - browserViewportSize?: string | undefined - screenshotQuality?: number | undefined - remoteBrowserEnabled?: boolean | undefined - remoteBrowserHost?: string | undefined - cachedChromeHostUrl?: string | undefined - enableCheckpoints?: boolean | undefined - ttsEnabled?: boolean | undefined - ttsSpeed?: number | undefined - soundEnabled?: boolean | undefined - soundVolume?: number | undefined - maxOpenTabsContext?: number | undefined - maxWorkspaceFiles?: number | undefined - showRooIgnoredFiles?: boolean | undefined - maxReadFileLine?: number | undefined - terminalOutputLineLimit?: number | undefined - terminalShellIntegrationTimeout?: number | undefined - terminalShellIntegrationDisabled?: boolean | undefined - terminalCommandDelay?: number | undefined - terminalPowershellCounter?: boolean | undefined - terminalZshClearEolMark?: boolean | undefined - terminalZshOhMy?: boolean | undefined - terminalZshP10k?: boolean | undefined - terminalZdotdir?: boolean | undefined - terminalCompressProgressBar?: boolean | undefined - experiments?: - | { - powerSteering: boolean - } - | undefined - language?: - | ( - | "ca" - | "de" - | "en" - | "es" - | "fr" - | "hi" - | "it" - | "ja" - | "ko" - | "nl" - | "pl" - | "pt-BR" - | "ru" - | "tr" - | "vi" - | "zh-CN" - | "zh-TW" - ) - | undefined - telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined - mcpEnabled?: boolean | undefined - enableMcpServerCreation?: boolean | undefined - mode?: string | undefined - modeApiConfigs?: - | { - [x: string]: string - } - | undefined - customModes?: - | { - slug: string - name: string - roleDefinition: string - whenToUse?: string | undefined - customInstructions?: string | undefined - groups: ( - | ("read" | "edit" | "browser" | "command" | "mcp" | "modes") - | [ - "read" | "edit" | "browser" | "command" | "mcp" | "modes", - { - fileRegex?: string | undefined - description?: string | undefined - }, - ] - )[] - source?: ("global" | "project") | undefined - }[] - | undefined - customModePrompts?: - | { - [x: string]: - | { - roleDefinition?: string | undefined - whenToUse?: string | undefined - customInstructions?: string | undefined - } - | undefined - } - | undefined - customSupportPrompts?: - | { - [x: string]: string | undefined - } - | undefined - enhancementApiConfigId?: string | undefined - historyPreviewCollapsed?: boolean | undefined - } - text: string - images?: string[] | undefined - newTab?: boolean | undefined - } - } - | { - commandName: "CancelTask" - data: string - } - | { - commandName: "CloseTask" - data: string - } +type TaskCommand = { + commandName: "StartNewTask"; + data: { + configuration: { + apiProvider?: ("anthropic" | "glama" | "openrouter" | "bedrock" | "vertex" | "openai" | "ollama" | "vscode-lm" | "lmstudio" | "gemini" | "openai-native" | "mistral" | "deepseek" | "unbound" | "requesty" | "human-relay" | "fake-ai" | "xai" | "groq" | "chutes" | "litellm") | undefined; + includeMaxTokens?: boolean | undefined; + reasoningEffort?: ("low" | "medium" | "high") | undefined; + diffEnabled?: boolean | undefined; + fuzzyMatchThreshold?: number | undefined; + modelTemperature?: (number | null) | undefined; + rateLimitSeconds?: number | undefined; + modelMaxTokens?: number | undefined; + modelMaxThinkingTokens?: number | undefined; + apiModelId?: string | undefined; + apiKey?: string | undefined; + anthropicBaseUrl?: string | undefined; + anthropicUseAuthToken?: boolean | undefined; + glamaModelId?: string | undefined; + glamaApiKey?: string | undefined; + openRouterApiKey?: string | undefined; + openRouterModelId?: string | undefined; + openRouterBaseUrl?: string | undefined; + openRouterSpecificProvider?: string | undefined; + openRouterUseMiddleOutTransform?: boolean | undefined; + awsAccessKey?: string | undefined; + awsSecretKey?: string | undefined; + awsSessionToken?: string | undefined; + awsRegion?: string | undefined; + awsUseCrossRegionInference?: boolean | undefined; + awsUsePromptCache?: boolean | undefined; + awsProfile?: string | undefined; + awsUseProfile?: boolean | undefined; + awsCustomArn?: string | undefined; + vertexKeyFile?: string | undefined; + vertexJsonCredentials?: string | undefined; + vertexProjectId?: string | undefined; + vertexRegion?: string | undefined; + openAiBaseUrl?: string | undefined; + openAiApiKey?: string | undefined; + openAiLegacyFormat?: boolean | undefined; + openAiR1FormatEnabled?: boolean | undefined; + openAiModelId?: string | undefined; + openAiCustomModelInfo?: ({ + maxTokens?: (number | null) | undefined; + maxThinkingTokens?: (number | null) | undefined; + contextWindow: number; + supportsImages?: boolean | undefined; + supportsComputerUse?: boolean | undefined; + supportsPromptCache: boolean; + inputPrice?: number | undefined; + outputPrice?: number | undefined; + cacheWritesPrice?: number | undefined; + cacheReadsPrice?: number | undefined; + description?: string | undefined; + reasoningEffort?: ("low" | "medium" | "high") | undefined; + thinking?: boolean | undefined; + minTokensPerCachePoint?: number | undefined; + maxCachePoints?: number | undefined; + cachableFields?: string[] | undefined; + tiers?: { + contextWindow: number; + inputPrice?: number | undefined; + outputPrice?: number | undefined; + cacheWritesPrice?: number | undefined; + cacheReadsPrice?: number | undefined; + }[] | undefined; + } | null) | undefined; + openAiUseAzure?: boolean | undefined; + azureApiVersion?: string | undefined; + openAiStreamingEnabled?: boolean | undefined; + enableReasoningEffort?: boolean | undefined; + openAiHostHeader?: string | undefined; + openAiHeaders?: { + [x: string]: string; + } | undefined; + ollamaModelId?: string | undefined; + ollamaBaseUrl?: string | undefined; + vsCodeLmModelSelector?: { + vendor?: string | undefined; + family?: string | undefined; + version?: string | undefined; + id?: string | undefined; + } | undefined; + lmStudioModelId?: string | undefined; + lmStudioBaseUrl?: string | undefined; + lmStudioDraftModelId?: string | undefined; + lmStudioSpeculativeDecodingEnabled?: boolean | undefined; + geminiApiKey?: string | undefined; + googleGeminiBaseUrl?: string | undefined; + openAiNativeApiKey?: string | undefined; + openAiNativeBaseUrl?: string | undefined; + mistralApiKey?: string | undefined; + mistralCodestralUrl?: string | undefined; + deepSeekBaseUrl?: string | undefined; + deepSeekApiKey?: string | undefined; + unboundApiKey?: string | undefined; + unboundModelId?: string | undefined; + requestyApiKey?: string | undefined; + requestyModelId?: string | undefined; + fakeAi?: unknown | undefined; + xaiApiKey?: string | undefined; + groqApiKey?: string | undefined; + chutesApiKey?: string | undefined; + litellmBaseUrl?: string | undefined; + litellmApiKey?: string | undefined; + litellmModelId?: string | undefined; + currentApiConfigName?: string | undefined; + listApiConfigMeta?: { + id: string; + name: string; + apiProvider?: ("anthropic" | "glama" | "openrouter" | "bedrock" | "vertex" | "openai" | "ollama" | "vscode-lm" | "lmstudio" | "gemini" | "openai-native" | "mistral" | "deepseek" | "unbound" | "requesty" | "human-relay" | "fake-ai" | "xai" | "groq" | "chutes" | "litellm") | undefined; + }[] | undefined; + pinnedApiConfigs?: { + [x: string]: boolean; + } | undefined; + lastShownAnnouncementId?: string | undefined; + customInstructions?: string | undefined; + taskHistory?: { + id: string; + number: number; + ts: number; + task: string; + tokensIn: number; + tokensOut: number; + cacheWrites?: number | undefined; + cacheReads?: number | undefined; + totalCost: number; + size?: number | undefined; + workspace?: string | undefined; + }[] | undefined; + autoApprovalEnabled?: boolean | undefined; + alwaysAllowReadOnly?: boolean | undefined; + alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined; + alwaysAllowWrite?: boolean | undefined; + alwaysAllowWriteOutsideWorkspace?: boolean | undefined; + writeDelayMs?: number | undefined; + alwaysAllowBrowser?: boolean | undefined; + alwaysApproveResubmit?: boolean | undefined; + requestDelaySeconds?: number | undefined; + alwaysAllowMcp?: boolean | undefined; + alwaysAllowModeSwitch?: boolean | undefined; + alwaysAllowSubtasks?: boolean | undefined; + alwaysAllowExecute?: boolean | undefined; + allowedCommands?: string[] | undefined; + browserToolEnabled?: boolean | undefined; + browserViewportSize?: string | undefined; + screenshotQuality?: number | undefined; + remoteBrowserEnabled?: boolean | undefined; + remoteBrowserHost?: string | undefined; + cachedChromeHostUrl?: string | undefined; + enableCheckpoints?: boolean | undefined; + ttsEnabled?: boolean | undefined; + ttsSpeed?: number | undefined; + soundEnabled?: boolean | undefined; + soundVolume?: number | undefined; + maxOpenTabsContext?: number | undefined; + maxWorkspaceFiles?: number | undefined; + showRooIgnoredFiles?: boolean | undefined; + maxReadFileLine?: number | undefined; + terminalOutputLineLimit?: number | undefined; + terminalShellIntegrationTimeout?: number | undefined; + terminalShellIntegrationDisabled?: boolean | undefined; + terminalCommandDelay?: number | undefined; + terminalPowershellCounter?: boolean | undefined; + terminalZshClearEolMark?: boolean | undefined; + terminalZshOhMy?: boolean | undefined; + terminalZshP10k?: boolean | undefined; + terminalZdotdir?: boolean | undefined; + terminalCompressProgressBar?: boolean | undefined; + experiments?: { + powerSteering: boolean; + } | undefined; + language?: ("ca" | "de" | "en" | "es" | "fr" | "hi" | "it" | "ja" | "ko" | "nl" | "pl" | "pt-BR" | "ru" | "tr" | "vi" | "zh-CN" | "zh-TW") | undefined; + telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined; + mcpEnabled?: boolean | undefined; + enableMcpServerCreation?: boolean | undefined; + mode?: string | undefined; + modeApiConfigs?: { + [x: string]: string; + } | undefined; + customModes?: { + slug: string; + name: string; + roleDefinition: string; + whenToUse?: string | undefined; + customInstructions?: string | undefined; + groups: (("read" | "edit" | "browser" | "command" | "mcp" | "modes") | [ + "read" | "edit" | "browser" | "command" | "mcp" | "modes", + { + fileRegex?: string | undefined; + description?: string | undefined; + } + ])[]; + source?: ("global" | "project") | undefined; + }[] | undefined; + customModePrompts?: { + [x: string]: { + roleDefinition?: string | undefined; + whenToUse?: string | undefined; + customInstructions?: string | undefined; + } | undefined; + } | undefined; + customSupportPrompts?: { + [x: string]: string | undefined; + } | undefined; + enhancementApiConfigId?: string | undefined; + historyPreviewCollapsed?: boolean | undefined; + }; + text: string; + images?: string[] | undefined; + newTab?: boolean | undefined; + }; +} | { + commandName: "CancelTask"; + data: string; +} | { + commandName: "CloseTask"; + data: string; +}; export type { TaskCommand } -type TaskEvent = - | { - eventName: "message" - payload: [ - { - taskId: string - action: "created" | "updated" - message: { - ts: number - type: "ask" | "say" - ask?: - | ( - | "followup" - | "command" - | "command_output" - | "completion_result" - | "tool" - | "api_req_failed" - | "resume_task" - | "resume_completed_task" - | "mistake_limit_reached" - | "browser_action_launch" - | "use_mcp_server" - ) - | undefined - say?: - | ( - | "error" - | "api_req_started" - | "api_req_finished" - | "api_req_retried" - | "api_req_retry_delayed" - | "api_req_deleted" - | "text" - | "reasoning" - | "completion_result" - | "user_feedback" - | "user_feedback_diff" - | "command_output" - | "shell_integration_warning" - | "browser_action" - | "browser_action_result" - | "mcp_server_request_started" - | "mcp_server_response" - | "subtask_result" - | "checkpoint_saved" - | "rooignore_error" - | "diff_error" - ) - | undefined - text?: string | undefined - images?: string[] | undefined - partial?: boolean | undefined - reasoning?: string | undefined - conversationHistoryIndex?: number | undefined - checkpoint?: - | { - [x: string]: unknown - } - | undefined - progressStatus?: - | { - icon?: string | undefined - text?: string | undefined - } - | undefined - } - }, - ] - } - | { - eventName: "taskCreated" - payload: [string] - } - | { - eventName: "taskStarted" - payload: [string] - } - | { - eventName: "taskModeSwitched" - payload: [string, string] - } - | { - eventName: "taskPaused" - payload: [string] - } - | { - eventName: "taskUnpaused" - payload: [string] - } - | { - eventName: "taskAskResponded" - payload: [string] - } - | { - eventName: "taskAborted" - payload: [string] - } - | { - eventName: "taskSpawned" - payload: [string, string] - } - | { - eventName: "taskCompleted" - payload: [ - string, - { - totalTokensIn: number - totalTokensOut: number - totalCacheWrites?: number | undefined - totalCacheReads?: number | undefined - totalCost: number - contextTokens: number - }, - { - [x: string]: { - attempts: number - failures: number - } - }, - ] - } - | { - eventName: "taskTokenUsageUpdated" - payload: [ - string, - { - totalTokensIn: number - totalTokensOut: number - totalCacheWrites?: number | undefined - totalCacheReads?: number | undefined - totalCost: number - contextTokens: number - }, - ] - } +type TaskEvent = { + eventName: "message"; + payload: [ + { + taskId: string; + action: "created" | "updated"; + message: { + ts: number; + type: "ask" | "say"; + ask?: ("followup" | "command" | "command_output" | "completion_result" | "tool" | "api_req_failed" | "resume_task" | "resume_completed_task" | "mistake_limit_reached" | "browser_action_launch" | "use_mcp_server") | undefined; + say?: ("error" | "api_req_started" | "api_req_finished" | "api_req_retried" | "api_req_retry_delayed" | "api_req_deleted" | "text" | "reasoning" | "completion_result" | "user_feedback" | "user_feedback_diff" | "command_output" | "shell_integration_warning" | "browser_action" | "browser_action_result" | "mcp_server_request_started" | "mcp_server_response" | "subtask_result" | "checkpoint_saved" | "rooignore_error" | "diff_error") | undefined; + text?: string | undefined; + images?: string[] | undefined; + partial?: boolean | undefined; + reasoning?: string | undefined; + conversationHistoryIndex?: number | undefined; + checkpoint?: { + [x: string]: unknown; + } | undefined; + progressStatus?: { + icon?: string | undefined; + text?: string | undefined; + } | undefined; + }; + } + ]; +} | { + eventName: "taskCreated"; + payload: [ + string + ]; +} | { + eventName: "taskStarted"; + payload: [ + string + ]; +} | { + eventName: "taskModeSwitched"; + payload: [ + string, + string + ]; +} | { + eventName: "taskPaused"; + payload: [ + string + ]; +} | { + eventName: "taskUnpaused"; + payload: [ + string + ]; +} | { + eventName: "taskAskResponded"; + payload: [ + string + ]; +} | { + eventName: "taskAborted"; + payload: [ + string + ]; +} | { + eventName: "taskSpawned"; + payload: [ + string, + string + ]; +} | { + eventName: "taskCompleted"; + payload: [ + string, + { + totalTokensIn: number; + totalTokensOut: number; + totalCacheWrites?: number | undefined; + totalCacheReads?: number | undefined; + totalCost: number; + contextTokens: number; + }, + { + [x: string]: { + attempts: number; + failures: number; + }; + } + ]; +} | { + eventName: "taskTokenUsageUpdated"; + payload: [ + string, + { + totalTokensIn: number; + totalTokensOut: number; + totalCacheWrites?: number | undefined; + totalCacheReads?: number | undefined; + totalCost: number; + contextTokens: number; + } + ]; +}; -export type { TaskEvent } +export type { TaskEvent } \ No newline at end of file diff --git a/src/schemas/index.ts b/src/schemas/index.ts index 70ea39f624..c8cfe9b770 100644 --- a/src/schemas/index.ts +++ b/src/schemas/index.ts @@ -1002,6 +1002,7 @@ export const toolNames = [ "switch_mode", "new_task", "fetch_instructions", + "find_references", ] as const export const toolNamesSchema = z.enum(toolNames) diff --git a/src/services/language-services/index.ts b/src/services/language-services/index.ts new file mode 100644 index 0000000000..aaa0bd2bec --- /dev/null +++ b/src/services/language-services/index.ts @@ -0,0 +1,417 @@ +import * as vscode from "vscode" + +// Create a dedicated output channel for debugging C# references +const debugChannel = vscode.window.createOutputChannel("C# References Debug - Language Services"); + +/** + * Log a debug message to the output channel + * @param message The message to log + */ +function debugLog(message: string): void { + const timestamp = new Date().toISOString(); + debugChannel.appendLine(`[${timestamp}] [LanguageServices] ${message}`); + // Also log to console for terminal visibility + console.log(`[C# References Debug] [LanguageServices] ${message}`); +} + +/** + * Check if language services are available for a file + * @param document The document to check + * @returns True if language services are available + */ +export async function hasLanguageServices(document: vscode.TextDocument): Promise { + debugLog(`Checking language services for ${document.uri.fsPath} (language: ${document.languageId})`) + try { + // Try to get document symbols as a test for language services + const symbols = await vscode.commands.executeCommand( + "vscode.executeDocumentSymbolProvider", + document.uri + ) + const hasServices = symbols !== undefined && symbols.length > 0 + debugLog(`Language services ${hasServices ? 'available' : 'not available'} for ${document.uri.fsPath}`) + if (hasServices && symbols) { + debugLog(`Found ${symbols.length} top-level symbols`) + } + return hasServices + } catch (error) { + debugLog(`ERROR checking language services: ${error instanceof Error ? error.message : String(error)}`) + return false + } +} + +/** + * Find the position of a symbol in a document + * @param document The document to search + * @param symbolName The name of the symbol to find + * @param position Optional position to start searching from + * @returns The position of the symbol or undefined if not found + */ +export async function findSymbolPosition( + document: vscode.TextDocument, + symbolName: string, + position?: vscode.Position +): Promise { + debugLog(`Finding position for symbol '${symbolName}' in ${document.uri.fsPath}`) + debugLog(`Document language: ${document.languageId}`) + + // If position is provided, use it + if (position) { + debugLog(`Using provided position: line ${position.line}, character ${position.character}`) + return position + } + + // Try to find the symbol in the document + try { + debugLog(`Executing document symbol provider for ${document.uri.fsPath}`) + const symbols = await vscode.commands.executeCommand( + "vscode.executeDocumentSymbolProvider", + document.uri + ) + + if (!symbols || symbols.length === 0) { + debugLog(`No symbols found in ${document.uri.fsPath}`) + debugLog(`Falling back to text search for '${symbolName}'`) + + // Fallback: Try to find the symbol in the text + for (let i = 0; i < document.lineCount; i++) { + const line = document.lineAt(i).text + const index = line.indexOf(symbolName) + if (index >= 0) { + const pos = new vscode.Position(i, index) + debugLog(`Found symbol '${symbolName}' via text search at line ${i}, character ${index}`) + return pos + } + } + + debugLog(`Symbol '${symbolName}' not found via text search either`) + return undefined + } + + // Recursively search for the symbol + const findSymbol = (symbols: vscode.DocumentSymbol[]): vscode.Position | undefined => { + for (const symbol of symbols) { + // Match only by exact name + if (symbol.name === symbolName) { + debugLog(`Found exact matching symbol: ${symbol.name} at line ${symbol.range.start.line}, character ${symbol.range.start.character}`) + + // Use selectionRange instead of range for more precise positioning + // selectionRange typically points to just the name of the symbol + debugLog(`Using selectionRange: line ${symbol.selectionRange.start.line}, character ${symbol.selectionRange.start.character}`) + return symbol.selectionRange.start + } + + if (symbol.children.length > 0) { + const childResult = findSymbol(symbol.children) + if (childResult) { + return childResult + } + } + } + return undefined + } + + const position = findSymbol(symbols) + + if (position) { + debugLog(`Found symbol position at line ${position.line}, character ${position.character}`) + + // Log detailed information about the found symbol + try { + // Find the actual symbol in the document symbols + const findSymbolDetails = (symbols: vscode.DocumentSymbol[]): vscode.DocumentSymbol | undefined => { + for (const symbol of symbols) { + if (symbol.name === symbolName) { + return symbol; + } + if (symbol.children.length > 0) { + const childResult = findSymbolDetails(symbol.children); + if (childResult) { + return childResult; + } + } + } + return undefined; + }; + + const symbolDetails = findSymbolDetails(symbols); + + if (symbolDetails) { + debugLog(`SYMBOL DETAILS:`); + debugLog(` Name: ${symbolDetails.name}`); + debugLog(` Kind: ${vscode.SymbolKind[symbolDetails.kind]}`); + debugLog(` Range: lines ${symbolDetails.range.start.line}-${symbolDetails.range.end.line}, chars ${symbolDetails.range.start.character}-${symbolDetails.range.end.character}`); + debugLog(` Selection Range: lines ${symbolDetails.selectionRange.start.line}-${symbolDetails.selectionRange.end.line}, chars ${symbolDetails.selectionRange.start.character}-${symbolDetails.selectionRange.end.character}`); + + // Log the full text of the symbol if it spans multiple lines + if (symbolDetails.range.start.line !== symbolDetails.range.end.line) { + debugLog(` Multi-line symbol content:`); + for (let i = symbolDetails.range.start.line; i <= symbolDetails.range.end.line; i++) { + debugLog(` ${i}: ${document.lineAt(i).text}`); + } + } else { + const lineText = document.lineAt(symbolDetails.range.start.line).text; + debugLog(` Symbol content: "${lineText.substring(symbolDetails.range.start.character, symbolDetails.range.end.character)}"`); + } + } + } catch (e) { + debugLog(`Error getting symbol details: ${e}`); + } + } else { + debugLog(`Symbol '${symbolName}' not found in document symbols`) + } + + // Show the output channel to make sure logs are visible + debugChannel.show(true); + + return position + } catch (error) { + debugLog(`ERROR finding symbol position: ${error instanceof Error ? error.message : String(error)}`) + if (error instanceof Error && error.stack) { + debugLog(`Stack trace: ${error.stack}`) + } + // Show the output channel on error to make sure logs are visible + debugChannel.show(true); + return undefined + } +} + +/** + * Get the containing function for a position in a document + * @param document The document to search + * @param position The position to find the containing function for + * @returns The function symbol or undefined if not found + */ +export async function getContainingFunction( + document: vscode.TextDocument, + position: vscode.Position +): Promise { + try { + const symbols = await vscode.commands.executeCommand( + "vscode.executeDocumentSymbolProvider", + document.uri + ) + + if (!symbols || symbols.length === 0) { + return undefined + } + + // Recursively search for a function that contains the position + const findContainingFunction = (symbols: vscode.DocumentSymbol[]): vscode.DocumentSymbol | undefined => { + for (const symbol of symbols) { + // Check if this symbol contains the position and is a function/method + if ( + symbol.range.contains(position) && + (symbol.kind === vscode.SymbolKind.Function || + symbol.kind === vscode.SymbolKind.Method || + symbol.kind === vscode.SymbolKind.Constructor) + ) { + // Create a modified symbol with the selectionRange as the range + // This focuses on the function name rather than the entire function block + const adjustedSymbol = { + ...symbol, + range: symbol.selectionRange + }; + return adjustedSymbol; + } + + // Check children + if (symbol.children.length > 0) { + const childResult = findContainingFunction(symbol.children) + if (childResult) { + return childResult + } + } + } + return undefined + } + + const functionSymbol = findContainingFunction(symbols) + return functionSymbol + } catch (error) { + return undefined + } +} + +/** + * Find a function by name in a document + * @param document The document to search + * @param functionName The name of the function to find + * @returns The function symbol or undefined if not found + */ +export async function findFunctionsByName( + document: vscode.TextDocument, + functionName: string +): Promise { + debugLog(`Finding function '${functionName}' in ${document.uri.fsPath}`) + + try { + const symbols = await vscode.commands.executeCommand( + "vscode.executeDocumentSymbolProvider", + document.uri + ) + + if (!symbols || symbols.length === 0) { + return undefined + } + + // Recursively search for all matching functions (to handle overloads) + const matchingFunctions: vscode.DocumentSymbol[] = [] + + const findFunctions = (symbols: vscode.DocumentSymbol[]): void => { + for (const symbol of symbols) { + // Match only by exact name + const isMatch = symbol.name === functionName + + if ( + isMatch && + (symbol.kind === vscode.SymbolKind.Function || + symbol.kind === vscode.SymbolKind.Method || + symbol.kind === vscode.SymbolKind.Constructor) + ) { + matchingFunctions.push(symbol) + } + + // Continue searching in children even if we found a match + if (symbol.children.length > 0) { + findFunctions(symbol.children) + } + } + } + + findFunctions(symbols) + + // Log the number of matching functions found + if (matchingFunctions.length > 0) { + debugLog(`Found ${matchingFunctions.length} matching function(s) named '${functionName}'`) + + // Log details of each matching function + matchingFunctions.forEach((func, index) => { + debugLog(`Match #${index + 1}: line ${func.range.start.line}, character ${func.range.start.character}`) + }) + + return matchingFunctions + } + + return undefined + } catch (error) { + return undefined + } +} + +/** + * Find a symbol by name in a document + * @param document The document to search + * @param symbolName The name of the symbol to find + * @returns The symbol or undefined if not found + */ +export async function findSymbolsByName( + document: vscode.TextDocument, + symbolName: string +): Promise { + debugLog(`Finding symbol '${symbolName}' in ${document.uri.fsPath}`) + + try { + const symbols = await vscode.commands.executeCommand( + "vscode.executeDocumentSymbolProvider", + document.uri + ) + + if (!symbols || symbols.length === 0) { + return undefined + } + + // Recursively search for all matching symbols + const matchingSymbols: vscode.DocumentSymbol[] = [] + + const findSymbols = (symbols: vscode.DocumentSymbol[]): void => { + for (const symbol of symbols) { + // Match only by exact name + const isMatch = symbol.name === symbolName + + if (isMatch) { + matchingSymbols.push(symbol) + } + + // Continue searching in children even if we found a match + if (symbol.children.length > 0) { + findSymbols(symbol.children) + } + } + } + + findSymbols(symbols) + + // Log the number of matching symbols found + if (matchingSymbols.length > 0) { + debugLog(`Found ${matchingSymbols.length} matching symbol(s) named '${symbolName}'`) + + // Log details of each matching symbol + matchingSymbols.forEach((sym, index) => { + debugLog(`Match #${index + 1}: ${vscode.SymbolKind[sym.kind]}, line ${sym.range.start.line}, character ${sym.range.start.character}`) + }) + + return matchingSymbols + } + + return undefined + } catch (error) { + return undefined + } +} + +/** + * Get the containing symbol for a position in a document + * @param document The document to search + * @param position The position to find the containing symbol for + * @param symbolKinds The kinds of symbols to look for (defaults to all kinds) + * @returns The symbol or undefined if not found + */ +export async function getContainingSymbol( + document: vscode.TextDocument, + position: vscode.Position, + symbolKinds?: vscode.SymbolKind[] +): Promise { + try { + const symbols = await vscode.commands.executeCommand( + "vscode.executeDocumentSymbolProvider", + document.uri + ) + + if (!symbols || symbols.length === 0) { + return undefined + } + + // Recursively search for a symbol that contains the position + const findContainingSymbol = (symbols: vscode.DocumentSymbol[]): vscode.DocumentSymbol | undefined => { + for (const symbol of symbols) { + // Check if this symbol contains the position and matches the requested kinds + if ( + symbol.range.contains(position) && + (!symbolKinds || symbolKinds.includes(symbol.kind)) + ) { + // Create a modified symbol with the selectionRange as the range + // This focuses on the symbol name rather than the entire block + const adjustedSymbol = { + ...symbol, + range: symbol.selectionRange + }; + return adjustedSymbol; + } + + // Check children + if (symbol.children.length > 0) { + const childResult = findContainingSymbol(symbol.children) + if (childResult) { + return childResult + } + } + } + return undefined + } + + const foundSymbol = findContainingSymbol(symbols) + return foundSymbol + } catch (error) { + return undefined + } +} \ No newline at end of file diff --git a/src/services/references/index.ts b/src/services/references/index.ts new file mode 100644 index 0000000000..3f67992a12 --- /dev/null +++ b/src/services/references/index.ts @@ -0,0 +1,449 @@ +import * as vscode from "vscode" +import { getContainingFunction, findSymbolPosition, getContainingSymbol } from "../language-services" + +// Create a dedicated output channel for debugging C# references +const debugChannel = vscode.window.createOutputChannel("C# References Debug"); + +/** + * Log a debug message to the output channel + * @param message The message to log + */ +function debugLog(message: string): void { + const timestamp = new Date().toISOString(); + debugChannel.appendLine(`[${timestamp}] ${message}`); + // Also log to console for terminal visibility + console.log(`[C# References Debug] ${message}`); +} + +// Maximum number of references to return without asking for approval +const MAX_REFERENCES_THRESHOLD = 50 + +/** + * Count the number of references to a symbol + * @param document The document containing the symbol + * @param symbolName The name of the symbol to find references for + * @param position Optional position of the symbol + * @returns The number of references + */ +export async function countReferences( + document: vscode.TextDocument, + symbolName: string, + lineNumber?: number +): Promise { + debugLog(`Starting search for '${symbolName}' in ${document.uri.fsPath}`) + debugLog(`Document language: ${document.languageId}`) + + // If line number is provided, create a position at that line + let symbolPosition: vscode.Position | undefined + if (lineNumber !== undefined) { + // Find the position of the symbol on the specified line + const line = document.lineAt(lineNumber).text + const charPos = line.indexOf(symbolName) + if (charPos >= 0) { + symbolPosition = new vscode.Position(lineNumber, charPos) + debugLog(`Using provided line number ${lineNumber}, found symbol at character ${charPos}`) + } else { + debugLog(`Symbol '${symbolName}' not found on line ${lineNumber}`) + } + } + + // If we don't have a position yet, try to find it + symbolPosition = symbolPosition || await findSymbolPosition(document, symbolName) + + if (!symbolPosition) { + debugLog(`Symbol position not found for '${symbolName}' in ${document.uri.fsPath}`) + return 0 + } + + debugLog(`Found symbol position at line ${symbolPosition.line}, character ${symbolPosition.character}`) + + try { + debugLog(`Executing reference provider for ${document.uri.fsPath}`) + + const locations = await vscode.commands.executeCommand( + "vscode.executeReferenceProvider", + document.uri, + symbolPosition + ) + + const count = locations?.length || 0 + debugLog(`Found ${count} references for '${symbolName}'`) + return count + } catch (error) { + debugLog(`ERROR finding references: ${error instanceof Error ? error.message : String(error)}`) + if (error instanceof Error && error.stack) { + debugLog(`Stack trace: ${error.stack}`) + } + return 0 + } +} + +/** + * Find all references to a symbol + * @param document The document containing the symbol + * @param symbolName The name of the symbol to find references for + * @param position Optional position of the symbol + * @returns An array of locations where the symbol is referenced + */ +export async function findReferences( + document: vscode.TextDocument, + symbolName: string, + lineNumber?: number +): Promise { + debugLog(`Starting search for '${symbolName}' in ${document.uri.fsPath}`) + debugLog(`Document language: ${document.languageId}`) + + // Find all matching symbols (to handle overloads) + const symbols = await vscode.commands.executeCommand( + "vscode.executeDocumentSymbolProvider", + document.uri + ) + + if (!symbols || symbols.length === 0) { + debugLog(`No symbols found in ${document.uri.fsPath}`) + return [] + } + + // Find all matching symbols with the given name + const matchingSymbols: vscode.DocumentSymbol[] = [] + + const findMatchingSymbols = (symbols: vscode.DocumentSymbol[]): void => { + for (const symbol of symbols) { + if (symbol.name === symbolName && + (symbol.kind === vscode.SymbolKind.Function || + symbol.kind === vscode.SymbolKind.Method || + symbol.kind === vscode.SymbolKind.Constructor || + symbol.kind === vscode.SymbolKind.Property || + symbol.kind === vscode.SymbolKind.Field || + symbol.kind === vscode.SymbolKind.Variable || + symbol.kind === vscode.SymbolKind.Constant || + symbol.kind === vscode.SymbolKind.Class || + symbol.kind === vscode.SymbolKind.Interface || + symbol.kind === vscode.SymbolKind.Enum || + symbol.kind === vscode.SymbolKind.EnumMember)) { + matchingSymbols.push(symbol) + } + + if (symbol.children.length > 0) { + findMatchingSymbols(symbol.children) + } + } + } + + findMatchingSymbols(symbols) + + // If we found matching symbols, log them + if (matchingSymbols.length > 0) { + debugLog(`Found ${matchingSymbols.length} matching symbol(s) named '${symbolName}'`) + + // If line number is provided, filter to the symbol at that line + if (lineNumber !== undefined) { + const symbolsAtLine = matchingSymbols.filter(s => + s.range.start.line <= lineNumber && s.range.end.line >= lineNumber) + + if (symbolsAtLine.length > 0) { + debugLog(`Found ${symbolsAtLine.length} symbol(s) at line ${lineNumber}`) + matchingSymbols.length = 0 // Clear the array + matchingSymbols.push(...symbolsAtLine) + } + } + } else { + debugLog(`No matching symbols found for '${symbolName}'`) + return [] + } + + // Get references for all matching symbols + const allLocations: vscode.Location[] = [] + + for (const symbol of matchingSymbols) { + const symbolPosition = symbol.selectionRange.start + + debugLog(`Finding references for symbol at line ${symbolPosition.line}, character ${symbolPosition.character}`) + + try { + debugLog(`Executing reference provider for '${symbolName}' at position ${symbolPosition.line},${symbolPosition.character}`) + + const locations = await vscode.commands.executeCommand( + "vscode.executeReferenceProvider", + document.uri, + symbolPosition + ) + + if (locations && locations.length > 0) { + debugLog(`Found ${locations.length} references for symbol at line ${symbolPosition.line}`) + allLocations.push(...locations) + } + } catch (error) { + debugLog(`ERROR finding references for symbol at line ${symbolPosition.line}: ${error instanceof Error ? error.message : String(error)}`) + } + } + + // Remove duplicates (same file and position) + const uniqueLocations: vscode.Location[] = [] + const seen = new Set() + + for (const location of allLocations) { + const key = `${location.uri.fsPath}:${location.range.start.line}:${location.range.start.character}` + if (!seen.has(key)) { + seen.add(key) + uniqueLocations.push(location) + } + } + + const count = uniqueLocations.length + + if (count === 0) { + debugLog(`No references found for '${symbolName}'`) + } else { + debugLog(`Found ${count} unique references for '${symbolName}' across ${matchingSymbols.length} overloads`) + + // Log the first few references for debugging + const maxToLog = Math.min(count, 5) + for (let i = 0; i < maxToLog; i++) { + const loc = uniqueLocations[i] + debugLog(`Reference ${i+1}: ${loc.uri.fsPath}:${loc.range.start.line},${loc.range.start.character}`) + } + } + + // Show the output channel to make sure logs are visible + debugChannel.show(true); + + return uniqueLocations +} + +/** + * Check if the number of references exceeds the threshold + * @param count The number of references + * @returns True if the count exceeds the threshold + */ +export function exceedsReferenceThreshold(count: number): boolean { + return count > MAX_REFERENCES_THRESHOLD +} + +/** + * Format references with function context + * @param locations The locations of the references + * @param symbol The symbol being referenced + * @returns A formatted string with the references + */ +async function formatReferences( + locations: vscode.Location[], + symbol: string +): Promise { + let result = `# References to '${symbol}'\n\n` + + // Group references by file + const fileGroups = new Map() + + for (const location of locations) { + const filePath = location.uri.fsPath + if (!fileGroups.has(filePath)) { + fileGroups.set(filePath, []) + } + fileGroups.get(filePath)!.push(location) + } + + // Process each file + for (const [filePath, locations] of fileGroups.entries()) { + // Sort locations by line number + locations.sort((a, b) => a.range.start.line - b.range.start.line) + + // Get workspace-relative path for display + const workspaceFolders = vscode.workspace.workspaceFolders + let displayPath = filePath + + if (workspaceFolders && workspaceFolders.length > 0) { + const workspacePath = workspaceFolders[0].uri.fsPath + // Try to make the path relative to the workspace + if (filePath.startsWith(workspacePath)) { + displayPath = filePath.substring(workspacePath.length) + // Remove leading slash or backslash + if (displayPath.startsWith('/') || displayPath.startsWith('\\')) { + displayPath = displayPath.substring(1) + } + } + } + + result += `## File: ${displayPath}\n\n` + + try { + // Process each location + const document = await vscode.workspace.openTextDocument(vscode.Uri.file(filePath)) + + // Group references by containing function or class + const functionGroups = new Map }>() + const classGroups = new Map }>() + const standaloneReferences: Array<{ line: number, text: string }> = [] + + for (const location of locations) { + const line = location.range.start.line + const lineText = document.lineAt(line).text.trim() + + // Try to get the containing function or class + try { + // First try to get containing function + const functionSymbol = await getContainingFunction(document, location.range.start) + + if (functionSymbol) { + // Group by function + const functionHeaderLine = functionSymbol.range.start.line + const functionHeader = document.lineAt(functionHeaderLine).text + + if (!functionGroups.has(functionHeaderLine)) { + functionGroups.set(functionHeaderLine, { + header: functionHeader, + references: [] + }) + } + + // Only add if it's not the function declaration itself + if (functionHeaderLine !== line) { + functionGroups.get(functionHeaderLine)!.references.push({ + line: line, + text: lineText + }) + } else { + // It's the function declaration itself + if (!functionGroups.has(functionHeaderLine)) { + functionGroups.set(functionHeaderLine, { + header: functionHeader, + references: [] + }) + } + } + } else { + // Try to get containing class or other symbol + const classSymbol = await getContainingSymbol( + document, + location.range.start, + [ + vscode.SymbolKind.Class, + vscode.SymbolKind.Interface, + vscode.SymbolKind.Enum, + vscode.SymbolKind.Struct + ] + ) + + if (classSymbol) { + // Group by class + const classHeaderLine = classSymbol.range.start.line + const classHeader = document.lineAt(classHeaderLine).text + + if (!classGroups.has(classHeaderLine)) { + classGroups.set(classHeaderLine, { + header: classHeader, + references: [] + }) + } + + // Only add if it's not the class declaration itself + if (classHeaderLine !== line) { + classGroups.get(classHeaderLine)!.references.push({ + line: line, + text: lineText + }) + } else { + // It's the class declaration itself + if (!classGroups.has(classHeaderLine)) { + classGroups.set(classHeaderLine, { + header: classHeader, + references: [] + }) + } + } + } else { + // No containing function or class, add to standalone references + standaloneReferences.push({ + line: line, + text: lineText + }) + } + } + } catch (error) { + // Add to standalone references if we can't get the containing function + standaloneReferences.push({ + line: line, + text: lineText + }) + } + } + + // Output function groups + for (const [functionLine, group] of functionGroups.entries()) { + // Get the full function range + const functionSymbol = await getContainingFunction(document, new vscode.Position(functionLine, 0)) + const functionStartLine = functionSymbol ? functionSymbol.range.start.line + 1 : functionLine + 1 + const functionEndLine = functionSymbol ? functionSymbol.range.end.line + 1 : functionLine + 1 + + result += `### ${group.header.trim()} (lines ${functionStartLine}-${functionEndLine})\n` + + // Add references within this function + if (group.references.length > 0) { + for (const ref of group.references) { + result += `Line ${ref.line + 1}: \`${ref.text}\`\n` + } + } else { + // This is a direct reference to the function/method itself + result += `*Function declaration*\n` + } + + // Add a note about how to read the full function + result += `\n*To read this function:* Use \`read_file\` with \`${functionStartLine}\` and \`${functionEndLine}\`\n\n` + } + + // Output class groups + for (const [classLine, group] of classGroups.entries()) { + // Get the full class range + const classSymbol = await getContainingSymbol( + document, + new vscode.Position(classLine, 0), + [ + vscode.SymbolKind.Class, + vscode.SymbolKind.Interface, + vscode.SymbolKind.Enum, + vscode.SymbolKind.Struct + ] + ) + const classStartLine = classSymbol ? classSymbol.range.start.line + 1 : classLine + 1 + const classEndLine = classSymbol ? classSymbol.range.end.line + 1 : classLine + 1 + + result += `### ${group.header.trim()} (lines ${classStartLine}-${classEndLine})\n` + + // Add references within this class + if (group.references.length > 0) { + for (const ref of group.references) { + result += `Line ${ref.line + 1}: \`${ref.text}\`\n` + } + } else { + // This is a direct reference to the class itself + result += `*Class declaration*\n` + } + + // Add a note about how to read the full class + result += `\n*To read this class:* Use \`read_file\` with \`${classStartLine}\` and \`${classEndLine}\`\n\n` + } + + // Output standalone references + if (standaloneReferences.length > 0) { + result += "### Other references\n" + for (const ref of standaloneReferences) { + result += `Line ${ref.line + 1}: \`${ref.text}\`\n` + } + result += "\n" + } + } catch (error) { + result += `Error processing file\n\n` + } + + result += "---\n\n" + } + + // Add summary + const totalFiles = fileGroups.size + const totalReferences = locations.length + result += `**Summary**: Found ${totalReferences} references in ${totalFiles} files.` + + return result +} + +export { formatReferences } \ No newline at end of file diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 6330556024..0ceabf4a4f 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -224,6 +224,8 @@ export interface ClineSayTool { | "finishTask" | "searchAndReplace" | "insertContent" + | "findReferences" + | "readFunction" path?: string diff?: string content?: string @@ -239,6 +241,7 @@ export interface ClineSayTool { startLine?: number endLine?: number lineNumber?: number + symbol?: string } // Must keep in sync with system prompt. diff --git a/src/shared/tools.ts b/src/shared/tools.ts index 1a6eb84ad7..edd8f81516 100644 --- a/src/shared/tools.ts +++ b/src/shared/tools.ts @@ -63,6 +63,9 @@ export const toolParamNames = [ "ignore_case", "start_line", "end_line", + "symbol", + "file_path", + "line_number", ] as const export type ToolParamName = (typeof toolParamNames)[number] @@ -116,6 +119,11 @@ export interface ListCodeDefinitionNamesToolUse extends ToolUse { params: Partial, "path">> } +export interface FindReferencesToolUse extends ToolUse { + name: "find_references" + params: Partial, "symbol" | "file_path" | "line_number">> +} + export interface BrowserActionToolUse extends ToolUse { name: "browser_action" params: Partial, "action" | "url" | "coordinate" | "text" | "size">> @@ -181,6 +189,7 @@ export const TOOL_DISPLAY_NAMES: Record = { new_task: "create new task", insert_content: "insert content", search_and_replace: "search and replace", + find_references: "find references", } as const export type { ToolGroup } @@ -188,7 +197,7 @@ export type { ToolGroup } // Define available tool groups. export const TOOL_GROUPS: Record = { read: { - tools: ["read_file", "fetch_instructions", "search_files", "list_files", "list_code_definition_names"], + tools: ["read_file", "fetch_instructions", "search_files", "list_files", "list_code_definition_names", "find_references"], }, edit: { tools: ["apply_diff", "write_to_file", "insert_content", "search_and_replace"], diff --git a/webview-ui/package-lock.json b/webview-ui/package-lock.json index 81105d26a2..b8c9962a4e 100644 --- a/webview-ui/package-lock.json +++ b/webview-ui/package-lock.json @@ -50,6 +50,7 @@ "remove-markdown": "^0.6.0", "shell-quote": "^1.8.2", "shiki": "^3.2.1", + "source-map": "^0.7.4", "styled-components": "^6.1.13", "tailwind-merge": "^2.6.0", "tailwindcss": "^4.0.0", @@ -9373,6 +9374,14 @@ "node": ">=8.0.0" } }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/css.escape": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", @@ -10607,6 +10616,16 @@ "source-map": "~0.6.1" } }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/eslint": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", @@ -13700,6 +13719,15 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/istanbul-reports": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", @@ -19023,6 +19051,15 @@ "node": ">= 4" } }, + "node_modules/recast/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -20043,12 +20080,11 @@ } }, "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, "node_modules/source-map-js": { @@ -20071,6 +20107,15 @@ "source-map": "^0.6.0" } }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/space-separated-tokens": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 8912a5d80e..27e0626bc6 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -619,6 +619,105 @@ export const ChatRowContent = ({ ) + case "findReferences": + // Parse XML content if available + const findReferencesContent = tool.content && typeof tool.content === 'string' && tool.content.includes('') + ? tool.content.match(/([\s\S]*?)<\/references>/)?.[1]?.trim() + : tool.content; + + return ( + <> +
+ {toolIcon("references")} + + {message.type === "ask" ? ( + {tool.symbol} }} + values={{ symbol: tool.symbol }} + /> + ) : ( + {tool.symbol} }} + values={{ symbol: tool.symbol }} + /> + )} + +
+ + vscode.postMessage({ type: "openFile", text: tool.path })}> + {tool.path?.startsWith(".") && .} + + {removeLeadingNonAlphanumeric(tool.path ?? "") + "\u200E"} + +
+ +
+
+ {findReferencesContent && ( + + )} + + ) + case "readFunction": + // Parse XML content if available + const readFunctionContent = tool.content && typeof tool.content === 'string' && tool.content.includes('') + ? tool.content.match(/([\s\S]*?)<\/functions>/)?.[1]?.trim() + : tool.content; + + return ( + <> +
+ {toolIcon("symbol-method")} + + {message.type === "ask" ? ( + {tool.symbol} }} + values={{ symbol: tool.symbol }} + /> + ) : ( + {tool.symbol} }} + values={{ symbol: tool.symbol }} + /> + )} + +
+ + vscode.postMessage({ type: "openFile", text: tool.path })}> + {tool.path?.startsWith(".") && .} + + {removeLeadingNonAlphanumeric(tool.path ?? "") + "\u200E"} + +
+ +
+
+ {readFunctionContent && ( + + )} + + ) default: return null } diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 90cdd14753..f1925aa7ce 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -678,6 +678,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction{{regex}}:", "didSearch": "Roo searched this directory for {{regex}}:" }, + "codeOperations": { + "wantsToFindReferences": "Roo wants to find references to {{symbol}}:", + "didFindReferences": "Roo found references to {{symbol}}:", + "wantsToReadFunction": "Roo wants to read the function {{symbol}}:", + "didReadFunction": "Roo read the function {{symbol}}:" + }, "commandOutput": "Command Output", "response": "Response", "arguments": "Arguments",