@@ -30,6 +30,7 @@ import {
3030} from "../integrations/misc/extract-text"
3131import { countFileLines } from "../integrations/misc/line-counter"
3232import { fetchInstructionsTool } from "./tools/fetchInstructionsTool"
33+ import { readFileTool } from "./tools/readFileTool"
3334import { ExitCodeDetails } from "../integrations/terminal/TerminalProcess"
3435import { Terminal } from "../integrations/terminal/Terminal"
3536import { TerminalRegistry } from "../integrations/terminal/TerminalRegistry"
@@ -82,9 +83,7 @@ import { insertGroups } from "./diff/insert-groups"
8283import { telemetryService } from "../services/telemetry/TelemetryService"
8384import { validateToolUse , isToolAllowedForMode , ToolName } from "./mode-validator"
8485import { parseXml } from "../utils/xml"
85- import { readLines } from "../integrations/misc/read-lines"
8686import { getWorkspacePath } from "../utils/path"
87- import { isBinaryFile } from "isbinaryfile"
8887
8988export type ToolResponse = string | Array < Anthropic . TextBlockParam | Anthropic . ImageBlockParam >
9089type UserContent = Array < Anthropic . Messages . ContentBlockParam >
@@ -2256,151 +2255,8 @@ export class Cline extends EventEmitter<ClineEvents> {
22562255 }
22572256
22582257 case "read_file" : {
2259- const relPath : string | undefined = block . params . path
2260- const startLineStr : string | undefined = block . params . start_line
2261- const endLineStr : string | undefined = block . params . end_line
2262-
2263- // Get the full path and determine if it's outside the workspace
2264- const fullPath = relPath ? path . resolve ( this . cwd , removeClosingTag ( "path" , relPath ) ) : ""
2265- const isOutsideWorkspace = isPathOutsideWorkspace ( fullPath )
2266-
2267- const sharedMessageProps : ClineSayTool = {
2268- tool : "readFile" ,
2269- path : getReadablePath ( this . cwd , removeClosingTag ( "path" , relPath ) ) ,
2270- isOutsideWorkspace,
2271- }
2272- try {
2273- if ( block . partial ) {
2274- const partialMessage = JSON . stringify ( {
2275- ...sharedMessageProps ,
2276- content : undefined ,
2277- } satisfies ClineSayTool )
2278- await this . ask ( "tool" , partialMessage , block . partial ) . catch ( ( ) => { } )
2279- break
2280- } else {
2281- if ( ! relPath ) {
2282- this . consecutiveMistakeCount ++
2283- pushToolResult ( await this . sayAndCreateMissingParamError ( "read_file" , "path" ) )
2284- break
2285- }
2286-
2287- // Check if we're doing a line range read
2288- let isRangeRead = false
2289- let startLine : number | undefined = undefined
2290- let endLine : number | undefined = undefined
2291-
2292- // Check if we have either range parameter
2293- if ( startLineStr || endLineStr ) {
2294- isRangeRead = true
2295- }
2296-
2297- // Parse start_line if provided
2298- if ( startLineStr ) {
2299- startLine = parseInt ( startLineStr )
2300- if ( isNaN ( startLine ) ) {
2301- // Invalid start_line
2302- this . consecutiveMistakeCount ++
2303- await this . say ( "error" , `Failed to parse start_line: ${ startLineStr } ` )
2304- pushToolResult ( formatResponse . toolError ( "Invalid start_line value" ) )
2305- break
2306- }
2307- startLine -= 1 // Convert to 0-based index
2308- }
2309-
2310- // Parse end_line if provided
2311- if ( endLineStr ) {
2312- endLine = parseInt ( endLineStr )
2313-
2314- if ( isNaN ( endLine ) ) {
2315- // Invalid end_line
2316- this . consecutiveMistakeCount ++
2317- await this . say ( "error" , `Failed to parse end_line: ${ endLineStr } ` )
2318- pushToolResult ( formatResponse . toolError ( "Invalid end_line value" ) )
2319- break
2320- }
2321-
2322- // Convert to 0-based index
2323- endLine -= 1
2324- }
2325-
2326- const accessAllowed = this . rooIgnoreController ?. validateAccess ( relPath )
2327- if ( ! accessAllowed ) {
2328- await this . say ( "rooignore_error" , relPath )
2329- pushToolResult ( formatResponse . toolError ( formatResponse . rooIgnoreError ( relPath ) ) )
2330-
2331- break
2332- }
2333-
2334- this . consecutiveMistakeCount = 0
2335- const absolutePath = path . resolve ( this . cwd , relPath )
2336- const completeMessage = JSON . stringify ( {
2337- ...sharedMessageProps ,
2338- content : absolutePath ,
2339- } satisfies ClineSayTool )
2340-
2341- const didApprove = await askApproval ( "tool" , completeMessage )
2342- if ( ! didApprove ) {
2343- break
2344- }
2345-
2346- // Get the maxReadFileLine setting
2347- const { maxReadFileLine = 500 } = ( await this . providerRef . deref ( ) ?. getState ( ) ) ?? { }
2348-
2349- // Count total lines in the file
2350- let totalLines = 0
2351- try {
2352- totalLines = await countFileLines ( absolutePath )
2353- } catch ( error ) {
2354- console . error ( `Error counting lines in file ${ absolutePath } :` , error )
2355- }
2356-
2357- // now execute the tool like normal
2358- let content : string
2359- let isFileTruncated = false
2360- let sourceCodeDef = ""
2361-
2362- const isBinary = await isBinaryFile ( absolutePath ) . catch ( ( ) => false )
2363-
2364- if ( isRangeRead ) {
2365- if ( startLine === undefined ) {
2366- content = addLineNumbers ( await readLines ( absolutePath , endLine , startLine ) )
2367- } else {
2368- content = addLineNumbers (
2369- await readLines ( absolutePath , endLine , startLine ) ,
2370- startLine + 1 ,
2371- )
2372- }
2373- } else if ( ! isBinary && maxReadFileLine >= 0 && totalLines > maxReadFileLine ) {
2374- // If file is too large, only read the first maxReadFileLine lines
2375- isFileTruncated = true
2376-
2377- const res = await Promise . all ( [
2378- maxReadFileLine > 0 ? readLines ( absolutePath , maxReadFileLine - 1 , 0 ) : "" ,
2379- parseSourceCodeDefinitionsForFile ( absolutePath , this . rooIgnoreController ) ,
2380- ] )
2381-
2382- content = res [ 0 ] . length > 0 ? addLineNumbers ( res [ 0 ] ) : ""
2383- const result = res [ 1 ]
2384- if ( result ) {
2385- sourceCodeDef = `\n\n${ result } `
2386- }
2387- } else {
2388- // Read entire file
2389- content = await extractTextFromFile ( absolutePath )
2390- }
2391-
2392- // Add truncation notice if applicable
2393- if ( isFileTruncated ) {
2394- content += `\n\n[Showing only ${ maxReadFileLine } of ${ totalLines } total lines. Use start_line and end_line if you need to read more]${ sourceCodeDef } `
2395- }
2396-
2397- pushToolResult ( content )
2398- break
2399- }
2400- } catch ( error ) {
2401- await handleError ( "reading file" , error )
2402- break
2403- }
2258+ readFileTool ( this , block , askApproval , handleError , pushToolResult , removeClosingTag )
2259+ break
24042260 }
24052261
24062262 case "fetch_instructions" : {
0 commit comments