diff --git a/apps/code/src/main/services/shell/service.test.ts b/apps/code/src/main/services/shell/service.test.ts index 929f8d91d..6cafe2b3f 100644 --- a/apps/code/src/main/services/shell/service.test.ts +++ b/apps/code/src/main/services/shell/service.test.ts @@ -185,6 +185,32 @@ describe("ShellService", () => { vi.clearAllMocks(); }); + it.each([ + [ + "interactive shell session", + () => service.create("session-1", "/home/user/project"), + ], + [ + "command session", + () => + service.createCommandSession({ + sessionId: "session-1", + command: "echo hello", + cwd: "/home/user/project", + }), + ], + ])("spawns %s with UTF-8 output decoding", async (_name, createSession) => { + await createSession(); + + expect(mockPty.spawn).toHaveBeenCalledWith( + expect.any(String), + expect.any(Array), + expect.objectContaining({ + encoding: "utf8", + }), + ); + }); + describe("create", () => { it("creates a new shell session", async () => { await service.create("session-1", "/home/user/project"); diff --git a/apps/code/src/main/services/shell/service.ts b/apps/code/src/main/services/shell/service.ts index 5e286311c..f82fec5da 100644 --- a/apps/code/src/main/services/shell/service.ts +++ b/apps/code/src/main/services/shell/service.ts @@ -22,6 +22,7 @@ declare module "node-pty" { } const log = logger.scope("shell"); +const PTY_ENCODING = "utf8"; export interface ShellSession { pty: pty.IPty; @@ -135,7 +136,7 @@ export class ShellService extends TypedEventEmitter { rows: 24, cwd: workingDir, env: buildShellEnv(mergedEnv), - encoding: null, + encoding: PTY_ENCODING, }); this.processTracking.register( @@ -215,7 +216,7 @@ export class ShellService extends TypedEventEmitter { rows: 24, cwd: workingDir, env: buildShellEnv(taskEnv), - encoding: null, + encoding: PTY_ENCODING, }); this.processTracking.register( diff --git a/apps/code/src/renderer/features/terminal/services/TerminalManager.ts b/apps/code/src/renderer/features/terminal/services/TerminalManager.ts index bd15de20c..007a80589 100644 --- a/apps/code/src/renderer/features/terminal/services/TerminalManager.ts +++ b/apps/code/src/renderer/features/terminal/services/TerminalManager.ts @@ -7,6 +7,8 @@ import { WebLinksAddon } from "@xterm/addon-web-links"; import { Terminal as XTerm } from "@xterm/xterm"; const log = logger.scope("terminal-manager"); +const TERMINAL_FONT_FAMILY = + 'var(--code-font-family, "Berkeley Mono", "JetBrains Mono", "Consolas", "Monaco", monospace)'; let parkingContainer: HTMLElement | null = null; @@ -161,7 +163,7 @@ class TerminalManagerImpl { const term = new XTerm({ cursorBlink: true, fontSize: 12, - fontFamily: "monospace", + fontFamily: TERMINAL_FONT_FAMILY, theme: getTerminalTheme(this.isDarkMode), cursorStyle: "block", cursorWidth: 8,