fix: properly implement UTF-8 support for Windows terminals

- Add LANG and LC_ALL environment variables for UTF-8 encoding
- Prepend 'chcp 65001' command on Windows to set code page to UTF-8
- Handle both PowerShell and CMD syntax for code page switching
- Remove incorrect CHCP environment variable approach
- Update tests to reflect the corrected implementation

This properly fixes non-ASCII characters (Cyrillic, Chinese, Hindi, etc.)
being displayed as '?' or diamond symbols in terminal output on Windows.

Fixes #8530
This commit is contained in:
Roo Code 2025-10-06 13:09:33 +00:00
parent f30e88e9a9
commit 1781e3f58d
3 changed files with 16 additions and 46 deletions

View file

@ -165,11 +165,6 @@ export class Terminal extends BaseTerminal {
LC_ALL: "en_US.UTF-8",
}
// On Windows, set the code page to UTF-8 (65001) for proper Unicode support
if (process.platform === "win32") {
env.CHCP = "65001"
}
// Set Oh My Zsh shell integration if enabled
if (Terminal.getTerminalZshOhMy()) {
env.ITERM_SHELL_INTEGRATION_INSTALLED = "Yes"

View file

@ -114,9 +114,21 @@ export class TerminalProcess extends BaseTerminalProcess {
(defaultWindowsShellProfile === null ||
(defaultWindowsShellProfile as string)?.toLowerCase().includes("powershell"))
if (isPowerShell) {
let commandToExecute = command
let commandToExecute = command
// On Windows, prepend chcp 65001 to set UTF-8 code page for proper Unicode support
// This fixes issues with non-ASCII characters being displayed as "?" or diamond symbols
if (process.platform === "win32") {
if (isPowerShell) {
// PowerShell syntax: use semicolon to chain commands and redirect output to null
commandToExecute = `chcp 65001 > $null ; ${command}`
} else {
// CMD syntax: use && to chain commands and redirect output to nul
commandToExecute = `chcp 65001 > nul && ${command}`
}
}
if (isPowerShell) {
// Only add the PowerShell counter workaround if enabled
if (Terminal.getPowershellCounter()) {
commandToExecute += ` ; "(Roo/PS Workaround: ${this.terminal.cmdCounter++})" > $null`
@ -126,12 +138,10 @@ export class TerminalProcess extends BaseTerminalProcess {
if (Terminal.getCommandDelay() > 0) {
commandToExecute += ` ; start-sleep -milliseconds ${Terminal.getCommandDelay()}`
}
terminal.shellIntegration.executeCommand(commandToExecute)
} else {
terminal.shellIntegration.executeCommand(command)
}
terminal.shellIntegration.executeCommand(commandToExecute)
this.isHot = true
// Wait for stream to be available

View file

@ -126,40 +126,5 @@ describe("TerminalRegistry", () => {
Terminal.setTerminalZshP10k(false)
}
})
it("adds CHCP=65001 on Windows for UTF-8 support", () => {
// Mock platform as Windows
const originalPlatform = process.platform
Object.defineProperty(process, "platform", {
value: "win32",
writable: true,
configurable: true,
})
try {
TerminalRegistry.createTerminal("/test/path", "vscode")
expect(mockCreateTerminal).toHaveBeenCalledWith({
cwd: "/test/path",
name: "Roo Code",
iconPath: expect.any(Object),
env: {
PAGER: "",
VTE_VERSION: "0",
PROMPT_EOL_MARK: "",
LANG: "en_US.UTF-8",
LC_ALL: "en_US.UTF-8",
CHCP: "65001",
},
})
} finally {
// Restore original platform
Object.defineProperty(process, "platform", {
value: originalPlatform,
writable: true,
configurable: true,
})
}
})
})
})