statusLine: multi-line output truncated to single terminal width by cli-truncate
Summary
Multi-line statusLine output is rendered inside a single <Text wrap="truncate"> component. The bundled cli-truncate (BXq) measures the total stringWidth across all lines (treating \n as width-0) and truncates the entire concatenated string to fit within terminal columns. This means Row 1 consumes most of the character budget, Row 2 gets a few characters, and Row 3 disappears entirely.
Steps to reproduce
- Configure a
statusLinecommand that outputs 3 lines, each ~80-110 visible characters:
``bash``
printf "Row1 with emoji and ANSI colours (%s chars)\n" "..."
printf "Row2 with prompt text\n"
printf "Row3 with insight text\n"
- Use a terminal width of ~120-200 columns
- Observe that Row 2 is aggressively truncated with
…(Unicode ellipsis) and Row 3 is missing
Expected behaviour
Each row should be independently truncated to the terminal width. A 3-row status line with rows of 80-110 chars should display all 3 rows, each clipped independently if needed.
Actual behaviour
All rows are concatenated into one string, stringWidth sums the visible width across all lines (~250+ chars), which exceeds the terminal width (~120-200), and cli-truncate slices the entire string from the end. Row 1 (~110 chars) consumes the budget, Row 2 gets ~5-10 chars + …, Row 3 is lost.
Screenshot showing the issue (Row 2 truncated to "I ju…", Row 3 gone):
Root cause (traced through v2.1.81 binary)
Rendering component (RR$):
// All rows passed as one string into a single <Text>
return createElement(Box, {paddingX: Z, gap: 2},
O ? createElement(Text, {dimColor: true, wrap: "truncate"},
createElement(J4, null, O) // O = "Row1\nRow2\nRow3"
) : null
)
stdout processing (Wiq):
// Joins rows back into a single newline-delimited string
let H = A.stdout.trim().split('\n').flatMap((j) => j.trim() || []).join('\n');
Truncation (BXq / cli-truncate):
let width = stringWidth(input); // sums ALL lines: 111 + 51 + 84 = 246
if (width <= columns) return input; // 246 > 120 → truncate
return sliceAnsi(input, 0, columns - 1) + '…'; // slices across line boundaries
stringWidth treats \n as width-0 and sums character widths across all lines. cli-truncate was designed for single-line strings and has no multi-line awareness.
Suggested fix
Split the statusLine output into separate <Text> elements per line:
// Instead of one <Text> for everything:
return createElement(Box, {paddingX: Z, gap: 2, flexDirection: "column"},
O ? O.split('\n').map((line, i) =>
createElement(Text, {key: i, dimColor: true, wrap: "truncate"},
createElement(J4, null, line)
)
) : null
)
This way each row gets independently truncated to the terminal width, which is the expected behaviour for multi-line status output.
Environment
- Claude Code v2.1.81
- macOS (Darwin, Apple M1 Max)
- Ghostty terminal (confirmed not the source of truncation)
- Bun runtime (uses
Bun.stringWidth)
This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗