From 612f8b6d7ba70b80f9e96ea2842d87b51aa4bf30 Mon Sep 17 00:00:00 2001 From: sorlros Date: Mon, 18 May 2026 14:28:01 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(tui):=20exec=20=EC=99=84=EB=A3=8C=20?= =?UTF-8?q?=EB=A7=88=EC=BB=A4=20lookahead=208/10=ED=96=89=20=E2=86=92=2050?= =?UTF-8?q?=ED=96=89=EC=9C=BC=EB=A1=9C=20=ED=99=95=EC=9E=A5=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=EC=9E=A5=EB=AC=B8=20=EC=9D=91=EB=8B=B5=20freeze=20?= =?UTF-8?q?=ED=95=B4=EC=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- src/cli/tui/panels/embedded-terminal.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli/tui/panels/embedded-terminal.ts b/src/cli/tui/panels/embedded-terminal.ts index 5ade8bd..7a1d633 100644 --- a/src/cli/tui/panels/embedded-terminal.ts +++ b/src/cli/tui/panels/embedded-terminal.ts @@ -915,7 +915,7 @@ const buildCompactRenderableLines = ( } let statusIndex = -1; - for (let lookahead = 2; lookahead < Math.min(rows.length - index, 8); lookahead += 1) { + for (let lookahead = 2; lookahead < Math.min(rows.length - index, 50); lookahead += 1) { const candidate = rows[index + lookahead]; if (candidate !== undefined && isCommandStatusLine(candidate.plainText)) { commandBlock.push(candidate); @@ -1263,7 +1263,7 @@ export class EmbeddedTerminalPane { } let statusLine: string | null = null; - for (let lookahead = index + 2; lookahead < Math.min(rows.length, index + 10); lookahead += 1) { + for (let lookahead = index + 2; lookahead < Math.min(rows.length, index + 50); lookahead += 1) { const candidate = rows[lookahead]?.plainText ?? ""; if (isCommandStatusLine(candidate)) { statusLine = candidate; @@ -1375,7 +1375,7 @@ export class EmbeddedTerminalPane { } let hasStatusLine = false; - for (let lookahead = index + 2; lookahead < Math.min(rows.length, index + 8); lookahead += 1) { + for (let lookahead = index + 2; lookahead < Math.min(rows.length, index + 50); lookahead += 1) { if (isCommandStatusLine(rows[lookahead]?.plainText ?? "")) { hasStatusLine = true; break; From e9ed078fbd4f5776e69f3dba5c650a8743df41a9 Mon Sep 17 00:00:00 2001 From: sorlros Date: Mon, 18 May 2026 15:15:36 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix(tui):=20alternate=20screen=20=EC=A2=85?= =?UTF-8?q?=EB=A3=8C=20=EC=8B=9C=20=EB=82=B4=EC=9A=A9=EC=9D=84=20scrollbac?= =?UTF-8?q?k=EC=97=90=20flush=ED=95=98=EC=97=AC=20codex=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit codex exec가 자신의 TUI에 alternate screen buffer(\x1b[?1049h)를 사용하여 출력하는 경우, 프로세스 종료 시 \x1b[?1049l로 복귀하면 alternate screen 내용이 버려지고 빈 main screen만 남아 사용자가 응답을 볼 수 없던 문제를 수정. alternate screen 종료 처리 시 비어있지 않은 행을 scrollback에 push한 뒤 main screen을 복원하도록 변경. Co-Authored-By: Claude Sonnet 4.6 --- src/cli/tui/terminal-emulator.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/cli/tui/terminal-emulator.ts b/src/cli/tui/terminal-emulator.ts index 04c0810..396139a 100644 --- a/src/cli/tui/terminal-emulator.ts +++ b/src/cli/tui/terminal-emulator.ts @@ -710,6 +710,17 @@ export class TerminalEmulatorBuffer { } if (sequence === "\u001b[?1049l") { + // Flush non-blank alternate screen rows to scrollback so codex's TUI + // output survives the screen switch (otherwise the content is discarded). + const altRows = this.alternateScreenBuffer; + let lastNonBlank = altRows.length - 1; + while (lastNonBlank >= 0 && altRows[lastNonBlank]!.every((cell) => cell.char.length === 0)) { + lastNonBlank -= 1; + } + for (let i = 0; i <= lastNonBlank; i += 1) { + this.pushScrollback(altRows[i]!); + } + this.alternateScreen = false; if (this.savedMainState) { this.mainScreen = this.savedMainState.screen.map((row) => cloneRow(row, this.columns));