From d6aab9fcaf7592dc148b942e4edbc0b2c14a3267 Mon Sep 17 00:00:00 2001 From: Hannes Rudolph Date: Tue, 27 Jan 2026 18:17:40 -0700 Subject: [PATCH] fix: display search pattern and match count in read_command_output UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using search mode, the UI now shows the search pattern and match count instead of the misleading byte range (0 B - totalSize). - Added searchPattern and matchCount fields to ClineSayTool type - Updated ReadCommandOutputTool to return match count from search operations - Updated ChatRow to display 'search: "pattern" • N matches' for search mode --- src/core/tools/ReadCommandOutputTool.ts | 14 ++++++++++---- webview-ui/src/components/chat/ChatRow.tsx | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/core/tools/ReadCommandOutputTool.ts b/src/core/tools/ReadCommandOutputTool.ts index 9ae4a377ef..9d3bbd35dd 100644 --- a/src/core/tools/ReadCommandOutputTool.ts +++ b/src/core/tools/ReadCommandOutputTool.ts @@ -161,10 +161,13 @@ export class ReadCommandOutputTool extends BaseTool<"read_command_output"> { let result: string let readStart = 0 let readEnd = 0 + let matchCount: number | undefined if (search) { // Search mode: filter lines matching the pattern - result = await this.searchInArtifact(artifactPath, search, totalSize, limit) + const searchResult = await this.searchInArtifact(artifactPath, search, totalSize, limit) + result = searchResult.content + matchCount = searchResult.matchCount // For search, we're scanning the whole file readStart = 0 readEnd = totalSize @@ -184,6 +187,7 @@ export class ReadCommandOutputTool extends BaseTool<"read_command_output"> { readStart, readEnd, totalBytes: totalSize, + ...(search && { searchPattern: search, matchCount }), }), ) @@ -292,7 +296,7 @@ export class ReadCommandOutputTool extends BaseTool<"read_command_output"> { pattern: string, totalSize: number, limit: number, - ): Promise { + ): Promise<{ content: string; matchCount: number }> { const CHUNK_SIZE = 64 * 1024 // 64KB chunks for bounded memory // Create case-insensitive regex for search @@ -368,23 +372,25 @@ export class ReadCommandOutputTool extends BaseTool<"read_command_output"> { const artifactId = path.basename(artifactPath) if (matches.length === 0) { - return [ + const content = [ `[Command Output: ${artifactId}] (search: "${pattern}")`, `Total size: ${this.formatBytes(totalSize)}`, "", "No matches found for the search pattern.", ].join("\n") + return { content, matchCount: 0 } } // Format matches with line numbers const matchedLines = matches.map((m) => `${String(m.lineNumber).padStart(5)} | ${m.content}`).join("\n") - return [ + const content = [ `[Command Output: ${artifactId}] (search: "${pattern}")`, `Total matches: ${matches.length} | Showing first ${matches.length}`, "", matchedLines, ].join("\n") + return { content, matchCount: matches.length } } /** diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index c79dd11a86..4c205a4a1b 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -1470,6 +1470,7 @@ export const ChatRowContent = ({ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` return `${(bytes / (1024 * 1024)).toFixed(1)} MB` } + // Determine if this is a search operation const isSearch = sayTool.searchPattern !== undefined