diff --git a/src/integrations/misc/__tests__/read-file-truncation.spec.ts b/src/integrations/misc/__tests__/read-file-truncation.spec.ts new file mode 100644 index 0000000000..e200fb91b0 --- /dev/null +++ b/src/integrations/misc/__tests__/read-file-truncation.spec.ts @@ -0,0 +1,64 @@ +import { promises as fs } from "fs" +import path from "path" +import { readIndentationBlock } from "../read-file-content" + +describe("readIndentationBlock truncation", () => { + const testDir = __dirname + + async function withTempFile(filename: string, content: string, testFn: (filepath: string) => Promise) { + const filepath = path.join(testDir, filename) + await fs.writeFile(filepath, content) + try { + await testFn(filepath) + } finally { + await fs.unlink(filepath) + } + } + + it("should NOT be truncated when block size equals limit and no content remains", async () => { + // Use indentation to ensure lines are treated as content block, not siblings + const content = " Line 1\n Line 2\n Line 3" + await withTempFile("truncation-exact-test.txt", content, async (filepath) => { + const result = await readIndentationBlock(filepath, 1, 3) + // Should get all 3 lines + expect(result.lineCount).toBe(3) + expect(result.metadata.truncatedByLimit).toBe(false) + }) + }) + + it("should be truncated when block size exceeds limit", async () => { + // Use indentation to ensure lines are treated as content block, not siblings + const content = " Line 1\n Line 2\n Line 3\n Line 4" + await withTempFile("truncation-exceeds-test.txt", content, async (filepath) => { + const result = await readIndentationBlock(filepath, 1, 3) + // Should get 3 lines + expect(result.lineCount).toBe(3) + expect(result.metadata.truncatedByLimit).toBe(true) + }) + }) + + it("should NOT be truncated when block ends naturally before limit (with maxLevels)", async () => { + // Block: lines 1-2 (indent 8). File has lines 3-4 (indent 0). Limit 10. + // maxLevels: 1 => minIndent = 8 - 4 = 4. + const content = " Line 1\n Line 2\nLine 3\nLine 4" + await withTempFile("truncation-natural-end-levels-test.txt", content, async (filepath) => { + const result = await readIndentationBlock(filepath, 1, 10, { + anchorLine: 1, + maxLevels: 1, + }) + // Should get 2 lines (Line 1, Line 2) + expect(result.lineCount).toBe(2) + expect(result.metadata.truncatedByLimit).toBe(false) + }) + }) + + it("should be truncated when block continues but limit reached", async () => { + // Block: lines 1-4. Limit 3. + const content = " Line 1\n Line 2\n Line 3\n Line 4" + await withTempFile("truncation-limit-reached-test.txt", content, async (filepath) => { + const result = await readIndentationBlock(filepath, 1, 3, { anchorLine: 1 }) + expect(result.lineCount).toBe(3) + expect(result.metadata.truncatedByLimit).toBe(true) + }) + }) +}) diff --git a/src/integrations/misc/read-file-content.ts b/src/integrations/misc/read-file-content.ts index 4eace8e5b7..88d752a0b3 100644 --- a/src/integrations/misc/read-file-content.ts +++ b/src/integrations/misc/read-file-content.ts @@ -241,6 +241,11 @@ async function collectFileLines(filePath: string): Promise { lineNumber++ records.push(createLineRecord(lineNumber, buffer)) } + console.log( + "collectFileLines records:", + records.length, + records.map((r) => r.raw), + ) resolve(records) }) }) @@ -506,8 +511,9 @@ export async function readIndentationBlock( let j = anchorIndex + 1 // downward cursor let iMinIndentCount = 0 let jMinIndentCount = 0 + let truncatedByLimit = false - while (out.length < finalLimit) { + while (out.length <= finalLimit) { let progressed = 0 // Expand upward @@ -530,12 +536,15 @@ export async function readIndentationBlock( } } - if (i >= 0) { - i-- + // Check if we've exceeded the limit + if (out.length > finalLimit) { + truncatedByLimit = true + out.shift() + break } - if (out.length >= finalLimit) { - break + if (i >= 0) { + i-- } } else { i = -1 // Stop upward expansion @@ -558,6 +567,13 @@ export async function readIndentationBlock( jMinIndentCount++ } + // Check if we've exceeded the limit + if (out.length > finalLimit) { + truncatedByLimit = true + out.pop() + break + } + if (j < records.length) { j++ } @@ -594,9 +610,6 @@ export async function readIndentationBlock( const totalLines = records.length const linesAfterEnd = totalLines - endLine - // Determine if truncated by limit (expansion stopped due to limit, not natural boundaries) - const truncatedByLimit = out.length >= finalLimit - return { content, lineCount: linesReturned,