|
1 | 1 | import fs from "node:fs"; |
| 2 | +import { isLikelyBinary } from "../../scan/index.js"; |
2 | 3 | import { MAX_FILE_BYTES } from "../constants.js"; |
3 | 4 | import type { ReadFilesPayload, ToolResult } from "../types.js"; |
4 | 5 | import { safePath } from "./shared.js"; |
@@ -42,23 +43,39 @@ async function readSingleFile( |
42 | 43 | if (!stat.isFile()) { |
43 | 44 | return null; |
44 | 45 | } |
45 | | - if (stat.size <= maxBytes) { |
46 | | - return await fs.promises.readFile(absPath, "utf-8"); |
47 | | - } |
| 46 | + const buffer = |
| 47 | + stat.size <= maxBytes |
| 48 | + ? await fs.promises.readFile(absPath) |
| 49 | + : await readFilePrefix(absPath, maxBytes); |
48 | 50 |
|
49 | | - const handle = await fs.promises.open(absPath, "r"); |
50 | | - try { |
51 | | - const buffer = Buffer.alloc(maxBytes); |
52 | | - await handle.read(buffer, 0, maxBytes, 0); |
53 | | - return buffer.toString("utf-8"); |
54 | | - } finally { |
55 | | - await handle.close(); |
| 51 | + // Repository listings can contain executables, archives, images, and |
| 52 | + // other binary artifacts. Never decode those bytes into a prompt string: |
| 53 | + // replacement characters and JSON escaping can turn a bounded file read |
| 54 | + // into a much larger workflow payload with no useful project context. |
| 55 | + if (isLikelyBinary(buffer)) { |
| 56 | + return null; |
56 | 57 | } |
| 58 | + |
| 59 | + return buffer.toString("utf-8"); |
57 | 60 | } catch { |
58 | 61 | return null; |
59 | 62 | } |
60 | 63 | } |
61 | 64 |
|
| 65 | +async function readFilePrefix( |
| 66 | + absPath: string, |
| 67 | + maxBytes: number |
| 68 | +): Promise<Buffer> { |
| 69 | + const handle = await fs.promises.open(absPath, "r"); |
| 70 | + try { |
| 71 | + const buffer = Buffer.alloc(maxBytes); |
| 72 | + const { bytesRead } = await handle.read(buffer, 0, maxBytes, 0); |
| 73 | + return buffer.subarray(0, bytesRead); |
| 74 | + } finally { |
| 75 | + await handle.close(); |
| 76 | + } |
| 77 | +} |
| 78 | + |
62 | 79 | /** |
63 | 80 | * Tool definition for batched file reads. |
64 | 81 | */ |
|
0 commit comments