From e54d409af314278ce4dff558bf40e70cad89d8e3 Mon Sep 17 00:00:00 2001 From: Omar Alaaeldein Date: Fri, 3 Jul 2026 05:40:16 -0400 Subject: [PATCH] fix: strip all ANSI escape seqs in terminal command output When sudo (or other interactive programs) run via run_terminal_command, they can emit cursor-movement, scroll-region, alternate-screen and other VT/ANSI control sequences that bleed into the TUI and corrupt the display (garbage characters, broken scrolling). Changes: - Switch stripColors -> stripAnsi so ALL escape sequences are removed from captured stdout/stderr, not just SGR color codes (\x1B[...m). - Strip bare \r characters that sudo uses to erase its password-prompt line after credentials are accepted. - Set SUDO_PROMPT to a plain ASCII string so sudo never emits decorated (colored/formatted) prompts to /dev/tty. - Default TERM=dumb (when not overridden by the caller) so child programs like git, less, and man suppress their own color/cursor output. --- sdk/src/tools/run-terminal-command.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sdk/src/tools/run-terminal-command.ts b/sdk/src/tools/run-terminal-command.ts index d313137a61..55d46e6e0e 100644 --- a/sdk/src/tools/run-terminal-command.ts +++ b/sdk/src/tools/run-terminal-command.ts @@ -6,7 +6,7 @@ import * as path from 'path' import type { ChildProcess } from 'child_process' import { - stripColors, + stripAnsi, truncateStringWithMessage, } from '../../../common/src/util/string' import { getSystemProcessEnv } from '../env' @@ -175,6 +175,14 @@ export function runTerminalCommand({ const processEnv = { ...getSystemProcessEnv(), ...(env ?? {}), + // Use a plain-text sudo prompt so sudo doesn't emit ANSI color/cursor + // sequences when asking for a password. Without this, sudo writes + // decorated prompts to /dev/tty that can bleed into the TUI. + SUDO_PROMPT: '[sudo] password: ', + // Signal to child programs that this is a dumb non-interactive terminal + // so they suppress color output and cursor-movement sequences. + // (Only set if the caller hasn't explicitly overridden it.) + ...((env ?? {}).TERM === undefined && { TERM: 'dumb' }), } as NodeJS.ProcessEnv if (signal?.aborted) { @@ -241,7 +249,12 @@ export function runTerminalCommand({ const truncateOutput = (str: string) => truncateStringWithMessage({ - str: stripColors(str), + // Strip all ANSI/VT escape sequences (not just color codes) so that + // cursor-movement, scroll-region, alternate-screen and other control + // sequences emitted by sudo and interactive programs don't bleed into + // the TUI and corrupt its scroll state or render garbage characters. + // Also normalise bare \r that sudo uses to overwrite its prompt line. + str: stripAnsi(str).replace(/\r/g, ''), maxLength: COMMAND_OUTPUT_LIMIT, remove: 'MIDDLE', })