Reviewed GitHub issue and related code files.
UnderstandIdentified root cause in line counting due to prepended newline.
UnderstandProposed and implemented fix for visual line counting.
BuildCommitted and pushed fix.
EditDisplayed file contents on user request.
VerifyAnalyze GitHub issue(s): https://github.com/badlogic/pi-mono/issues/921
For each issue:
Read the issue in full, including all comments and linked issues/PRs.
For bugs:
For feature requests:
Do NOT implement unless explicitly asked. Analyze and propose only.
Let me search for the relevant code handling the "ctrl+o to expand" functionality:
Let me read the visual-truncate.ts file which calculates the skippedCount:
Now I understand the bug. Let me analyze:
The bug is in tool-execution.ts in the renderBashContent() method (lines ~300-325).
// Line ~302const textContent = `\n${styledOutput}`;The code prepends a newline (\n) to the output for spacing purposes. This newline gets counted as a visual line during truncation.
Example with 5-line output:
output = "line1\nline2\nline3\nline4\nline5" (5 lines)textContent = "\nline1\nline2\nline3\nline4\nline5" (leading \n added)["", "line1", "line2", "line3", "line4", "line5"] = 6 visual linesBASH_PREVIEW_LINES = 5skippedCount = 6 - 5 = 1When no truncation occurs (line ~320):
return cachedLines;But when truncation occurs (line ~314-316):
return ["", hint, ...cachedLines];The truncated path adds a blank line ("") before the hint, but the non-truncated path doesn't add this spacing. This causes inconsistent visual spacing between collapsed and expanded states.
File: packages/coding-agent/src/modes/interactive/components/tool-execution.ts
Change 1 (line ~302): Remove the leading \n from textContent:
// Before:const textContent = `\n${styledOutput}`;
// After:const textContent = styledOutput;Change 2 (line ~320): Add blank line for consistent spacing:
// Before:return cachedLines;
// After:return ["", ...cachedLines];This ensures:
terrible analysis
Let me re-read the code more carefully.
Let me trace through more carefully with a concrete example:
With 5 lines of output:
output = "line1\nline2\nline3\nline4\nline5"textContent = "\nline1\nline2\nline3\nline4\nline5" (line 370 adds leading \n)truncateToVisualLines renders this and gets 6 visual lines: ["", "line1", "line2", "line3", "line4", "line5"]BASH_PREVIEW_LINES = 5cachedLines = ["line1", "line2", "line3", "line4", "line5"] (last 5)skippedCount = 1["", hint, ...cachedLines] showing "1 earlier lines" messageThe bug: The leading \n on line 370 is a formatting spacer, not content. It gets counted as a "hidden line", causing the off-by-one error.
With 7 lines: 8 visual lines (1 empty + 7 content), skips 3, reports "3 earlier lines" when only 2 actual content lines are hidden.
File: packages/coding-agent/src/modes/interactive/components/tool-execution.ts
Line 370: Change:
const textContent = `\n${styledOutput}`;to:
const textContent = styledOutput;Line 390: Change:
return cachedLines;to:
return ["", ...cachedLines];This removes the spacer from the truncation calculation while preserving the visual spacing in both truncated and non-truncated cases.
fix it
Now let me update the changelog:
+371 // Note: Don't include leading \n in truncation - it's just spacing, not content +372 const textContent = styledOutput;
why this assignment? and comment? do we still need this?
You're right, it's pointless. Just use styledOutput directly:
Done.
commit and push
Done. Committed and pushed 3235926e.
do a cat lines.txt
100 lines, line1 through line100.
// Line ~302const textContent = `\n${styledOutput}`;return cachedLines;return ["", hint, ...cachedLines];// Before:const textContent = `\n${styledOutput}`;
// After:const textContent = styledOutput;// Before:return cachedLines;
// After:return ["", ...cachedLines];const textContent = `\n${styledOutput}`;const textContent = styledOutput;return cachedLines;return ["", ...cachedLines];