fix: truncate oversized TUI lines instead of crashing (#287)

Lines exceeding terminal width are now silently truncated at the render
boundary rather than throwing a fatal error that kills the session.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lex Christopherson 2026-03-13 16:50:58 -06:00
parent 60a3607ff7
commit 7664163c1f

View file

@ -8,7 +8,7 @@ import * as path from "node:path";
import { isKeyRelease, matchesKey } from "./keys.js";
import type { Terminal } from "./terminal.js";
import { getCapabilities, isImageLine, setCellDimensions } from "./terminal-image.js";
import { extractSegments, sliceByColumn, sliceWithWidth, visibleWidth } from "./utils.js";
import { extractSegments, sliceByColumn, sliceWithWidth, truncateToWidth, visibleWidth } from "./utils.js";
/**
* Component interface - all components must implement this
@ -1069,35 +1069,10 @@ export class TUI extends Container {
for (let i = firstChanged; i <= renderEnd; i++) {
if (i > firstChanged) buffer += "\r\n";
buffer += "\x1b[2K"; // Clear current line
const line = newLines[i];
let line = newLines[i];
const isImage = isImageLine(line);
if (!isImage && visibleWidth(line) > width) {
// Log all lines to crash file for debugging
const crashLogPath = path.join(os.homedir(), ".pi", "agent", "pi-crash.log");
const crashData = [
`Crash at ${new Date().toISOString()}`,
`Terminal width: ${width}`,
`Line ${i} visible width: ${visibleWidth(line)}`,
"",
"=== All rendered lines ===",
...newLines.map((l, idx) => `[${idx}] (w=${visibleWidth(l)}) ${l}`),
"",
].join("\n");
fs.mkdirSync(path.dirname(crashLogPath), { recursive: true });
fs.writeFileSync(crashLogPath, crashData);
// Clean up terminal state before throwing
this.stop();
const errorMsg = [
`Rendered line ${i} exceeds terminal width (${visibleWidth(line)} > ${width}).`,
"",
"This is likely caused by a custom TUI component not truncating its output.",
"Use visibleWidth() to measure and truncateToWidth() to truncate lines.",
"",
`Debug log written to: ${crashLogPath}`,
].join("\n");
throw new Error(errorMsg);
line = truncateToWidth(line, width);
}
buffer += line;
}