From cb60f2a59677c6248717ecb234e9ca4f5943668e Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Wed, 1 Apr 2026 17:25:41 +0700 Subject: [PATCH] Fix Windows default shell for terminal creation --- packages/server/src/terminal/terminal.test.ts | 13 ++++++++++++ packages/server/src/terminal/terminal.ts | 21 +++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/server/src/terminal/terminal.test.ts b/packages/server/src/terminal/terminal.test.ts index 828ac66af..834cc1597 100644 --- a/packages/server/src/terminal/terminal.test.ts +++ b/packages/server/src/terminal/terminal.test.ts @@ -2,6 +2,7 @@ import { describe, it, expect, afterEach } from "vitest"; import { createTerminal, ensureNodePtySpawnHelperExecutableForCurrentPlatform, + resolveDefaultTerminalShell, type TerminalSession, } from "./terminal.js"; import { chmodSync, mkdtempSync, mkdirSync, rmSync, statSync, writeFileSync } from "node:fs"; @@ -111,6 +112,18 @@ describe("Terminal", () => { expect(statSync(helperPath).mode & 0o111).toBe(0o111); }); + it("uses cmd.exe-compatible default shell on Windows", () => { + expect(resolveDefaultTerminalShell({ platform: "win32", env: {} })).toBe( + "C:\\Windows\\System32\\cmd.exe", + ); + expect( + resolveDefaultTerminalShell({ + platform: "win32", + env: { ComSpec: "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" }, + }), + ).toBe("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"); + }); + it("creates a terminal session with an id, name, and cwd", async () => { const session = trackSession( await createTerminal({ diff --git a/packages/server/src/terminal/terminal.ts b/packages/server/src/terminal/terminal.ts index b6b80b302..60d9c7ef7 100644 --- a/packages/server/src/terminal/terminal.ts +++ b/packages/server/src/terminal/terminal.ts @@ -119,6 +119,22 @@ export function ensureNodePtySpawnHelperExecutableForCurrentPlatform( } } +export function resolveDefaultTerminalShell( + options: { + platform?: NodeJS.Platform; + env?: NodeJS.ProcessEnv; + } = {}, +): string { + const platform = options.platform ?? process.platform; + const env = options.env ?? process.env; + + if (platform === "win32") { + return env.ComSpec || env.COMSPEC || "C:\\Windows\\System32\\cmd.exe"; + } + + return env.SHELL || "/bin/sh"; +} + function extractCell(terminal: TerminalType, row: number, col: number): TerminalCell { const buffer = terminal.buffer.active; const line = buffer.getLine(row); @@ -299,12 +315,13 @@ export function captureTerminalLines( export async function createTerminal(options: CreateTerminalOptions): Promise { const { cwd, - shell = process.env.SHELL || "/bin/sh", + shell, env = {}, rows = 24, cols = 80, name = "Terminal", } = options; + const resolvedShell = shell ?? resolveDefaultTerminalShell(); const id = randomUUID(); const listeners = new Set<(msg: ServerMessage) => void>(); @@ -324,7 +341,7 @@ export async function createTerminal(options: CreateTerminalOptions): Promise