(args, extras)
| 12 | export const MAX_CHAR_POSITION = 2147483647; |
| 13 | |
| 14 | export const readFileRangeImpl: ToolImpl = async (args, extras) => { |
| 15 | const filepath = getStringArg(args, "filepath"); |
| 16 | const startLine = getNumberArg(args, "startLine"); |
| 17 | const endLine = getNumberArg(args, "endLine"); |
| 18 | |
| 19 | // Validate that line numbers are positive integers |
| 20 | if (startLine < 1) { |
| 21 | throw new ContinueError( |
| 22 | ContinueErrorReason.InvalidLineNumber, |
| 23 | "startLine must be 1 or greater. Negative line numbers are not supported - use the terminal tool with 'tail' command for reading from file end.", |
| 24 | ); |
| 25 | } |
| 26 | if (endLine < 1) { |
| 27 | throw new ContinueError( |
| 28 | ContinueErrorReason.InvalidLineNumber, |
| 29 | "endLine must be 1 or greater. Negative line numbers are not supported - use the terminal tool with 'tail' command for reading from file end.", |
| 30 | ); |
| 31 | } |
| 32 | if (endLine < startLine) { |
| 33 | throw new ContinueError( |
| 34 | ContinueErrorReason.InvalidLineNumber, |
| 35 | `endLine (${endLine}) must be greater than or equal to startLine (${startLine})`, |
| 36 | ); |
| 37 | } |
| 38 | |
| 39 | // Resolve the path first to get the actual path for security check |
| 40 | const resolvedPath = await resolveInputPath(extras.ide, filepath); |
| 41 | if (!resolvedPath) { |
| 42 | throw new ContinueError( |
| 43 | ContinueErrorReason.FileNotFound, |
| 44 | `File "${filepath}" does not exist or is not accessible. You might want to check the path and try again.`, |
| 45 | ); |
| 46 | } |
| 47 | |
| 48 | // Security check on the resolved display path |
| 49 | throwIfFileIsSecurityConcern(resolvedPath.displayPath); |
| 50 | |
| 51 | // Use the IDE's readRangeInFile method with 0-based range (IDE expects 0-based internally) |
| 52 | const content = await extras.ide.readRangeInFile(resolvedPath.uri, { |
| 53 | start: { |
| 54 | line: startLine - 1, // Convert from 1-based to 0-based |
| 55 | character: 0, |
| 56 | }, |
| 57 | end: { |
| 58 | line: endLine - 1, // Convert from 1-based to 0-based |
| 59 | character: MAX_CHAR_POSITION, // Read to end of line |
| 60 | }, |
| 61 | }); |
| 62 | |
| 63 | await throwIfFileExceedsHalfOfContext( |
| 64 | resolvedPath.displayPath, |
| 65 | content, |
| 66 | extras.config.selectedModelByRole.chat, |
| 67 | ); |
| 68 | |
| 69 | const rangeDescription = `${resolvedPath.displayPath} (lines ${startLine}-${endLine})`; |
| 70 | |
| 71 | return [ |
no test coverage detected