From 2609ec706e59ce5b95223f46077cac05345a5b6b Mon Sep 17 00:00:00 2001 From: Roo Code Date: Tue, 9 Sep 2025 03:20:30 +0000 Subject: [PATCH] fix: handle Windows cmd encoding for ipconfig and other commands - Set UTF-8 code page (65001) for Windows cmd before executing commands - Add proper UTF-8 encoding for PowerShell commands - Handle encoding fallback for Windows terminal output - Fix garbled output issue when running ipconfig through cmd Fixes #7803 --- .../terminal/ExecaTerminalProcess.ts | 26 ++++++++++++++++--- src/integrations/terminal/Terminal.ts | 8 ++++++ src/integrations/terminal/TerminalProcess.ts | 12 +++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/integrations/terminal/ExecaTerminalProcess.ts b/src/integrations/terminal/ExecaTerminalProcess.ts index 2f8ebfa7a8..52d013b404 100644 --- a/src/integrations/terminal/ExecaTerminalProcess.ts +++ b/src/integrations/terminal/ExecaTerminalProcess.ts @@ -38,17 +38,25 @@ export class ExecaTerminalProcess extends BaseTerminalProcess { try { this.isHot = true + // On Windows, wrap the command with chcp to ensure UTF-8 output + let actualCommand = command + if (process.platform === "win32") { + // Set code page to UTF-8 (65001) before running the command + // and restore it afterwards to avoid affecting other programs + actualCommand = `chcp 65001 >nul 2>&1 && ${command}` + } + this.subprocess = execa({ shell: true, cwd: this.terminal.getCurrentWorkingDirectory(), all: true, env: { ...process.env, - // Ensure UTF-8 encoding for Ruby, CocoaPods, etc. + // Ensure UTF-8 encoding for Ruby, CocoaPods, etc. (Unix-like systems) LANG: "en_US.UTF-8", LC_ALL: "en_US.UTF-8", }, - })`${command}` + })`${actualCommand}` this.pid = this.subprocess.pid @@ -74,9 +82,21 @@ export class ExecaTerminalProcess extends BaseTerminalProcess { const rawStream = this.subprocess.iterable({ from: "all", preserveNewlines: true }) // Wrap the stream to ensure all chunks are strings (execa can return Uint8Array) + // On Windows, we need to handle potential encoding issues const stream = (async function* () { for await (const chunk of rawStream) { - yield typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk) + if (typeof chunk === "string") { + yield chunk + } else { + // For Windows cmd output, try to decode with UTF-8 first + // If that fails, fall back to Windows-1252 (common Windows encoding) + try { + yield new TextDecoder("utf-8", { fatal: true }).decode(chunk) + } catch { + // Fallback to Windows-1252 if UTF-8 decoding fails + yield new TextDecoder("windows-1252", { fatal: false }).decode(chunk) + } + } } })() diff --git a/src/integrations/terminal/Terminal.ts b/src/integrations/terminal/Terminal.ts index 8bf2072f3d..7a18a8626c 100644 --- a/src/integrations/terminal/Terminal.ts +++ b/src/integrations/terminal/Terminal.ts @@ -159,6 +159,14 @@ export class Terminal extends BaseTerminal { VTE_VERSION: "0", } + // On Windows, set the console output code page to UTF-8 + // This helps with proper encoding of command outputs like ipconfig + if (process.platform === "win32") { + env.PYTHONIOENCODING = "utf-8" + // Note: We can't set CHCP directly here as it's a command, not an env var + // The actual chcp command will be handled in the terminal execution + } + // Set Oh My Zsh shell integration if enabled if (Terminal.getTerminalZshOhMy()) { env.ITERM_SHELL_INTEGRATION_INSTALLED = "Yes" diff --git a/src/integrations/terminal/TerminalProcess.ts b/src/integrations/terminal/TerminalProcess.ts index eb0424fe8d..f2a7bd5fe3 100644 --- a/src/integrations/terminal/TerminalProcess.ts +++ b/src/integrations/terminal/TerminalProcess.ts @@ -114,9 +114,17 @@ export class TerminalProcess extends BaseTerminalProcess { (defaultWindowsShellProfile === null || (defaultWindowsShellProfile as string)?.toLowerCase().includes("powershell")) + const isCmd = + process.platform === "win32" && + defaultWindowsShellProfile !== null && + (defaultWindowsShellProfile as string)?.toLowerCase().includes("cmd") + if (isPowerShell) { let commandToExecute = command + // Set UTF-8 encoding for PowerShell + commandToExecute = `[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; ${commandToExecute}` + // Only add the PowerShell counter workaround if enabled if (Terminal.getPowershellCounter()) { commandToExecute += ` ; "(Roo/PS Workaround: ${this.terminal.cmdCounter++})" > $null` @@ -127,6 +135,10 @@ export class TerminalProcess extends BaseTerminalProcess { commandToExecute += ` ; start-sleep -milliseconds ${Terminal.getCommandDelay()}` } + terminal.shellIntegration.executeCommand(commandToExecute) + } else if (isCmd) { + // For Windows cmd, set code page to UTF-8 before executing the command + const commandToExecute = `chcp 65001 >nul 2>&1 && ${command}` terminal.shellIntegration.executeCommand(commandToExecute) } else { terminal.shellIntegration.executeCommand(command)