From 5b4ee752ad71f5487ad33f9bc51bd6f9a7e6d2f0 Mon Sep 17 00:00:00 2001 From: MarcoDotIO Date: Wed, 4 Nov 2026 11:25:44 -0500 Subject: [PATCH 1/2] fix(server): terminals start a $SHELL whose path contains a space The terminal took only the text before the first space of $SHELL, so a shell at a path like `/Users/Jane Doe/.local/bin/fish` failed to spawn and the terminal quietly fell back to zsh. Only text from the first flag (`bash -l`) is dropped now. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/terminal/Manager.test.ts | 14 ++++++++++++++ apps/server/src/terminal/Manager.ts | 6 +++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/server/src/terminal/Manager.test.ts b/apps/server/src/terminal/Manager.test.ts index 7accdb958372f..d1cc86a7fc7a0 100644 --- a/apps/server/src/terminal/Manager.test.ts +++ b/apps/server/src/terminal/Manager.test.ts @@ -1558,6 +1558,20 @@ it.layer( }), ); + it.effect("starts a $SHELL whose path contains a space", () => + Effect.gen(function* () { + const { manager, ptyAdapter } = yield* createManager(5, { + env: { SHELL: "/Users/Jane Doe/.local/bin/fish" }, + }).pipe(Effect.provide(layerWithHostPlatform("darwin"))); + + yield* manager.open(openInput()); + + expect(ptyAdapter.spawnInputs.map((input) => input.shell)).toEqual([ + "/Users/Jane Doe/.local/bin/fish", + ]); + }), + ); + it.effect( "writes completion syntax for the fallback shell instead of the configured fish shell", () => diff --git a/apps/server/src/terminal/Manager.ts b/apps/server/src/terminal/Manager.ts index 6a661db4e09d6..e685d605d3a74 100644 --- a/apps/server/src/terminal/Manager.ts +++ b/apps/server/src/terminal/Manager.ts @@ -527,9 +527,9 @@ function normalizeShellCommand( return trimmed; } - const firstToken = trimmed.split(/\s+/g)[0]?.trim(); - if (!firstToken) return null; - return firstToken.replace(/^['"]|['"]$/g, ""); + // A shell path can contain spaces, so only text from the first flag (`bash -l`) is dropped. + const command = trimmed.split(/\s+(?=-)/)[0]?.replace(/^['"]|['"]$/g, ""); + return command || null; } function basenameForPlatform(command: string, platform: NodeJS.Platform): string { From 984aa1e412df8c04802c706e03befb27b47d07e1 Mon Sep 17 00:00:00 2001 From: MarcoDotIO Date: Wed, 4 Nov 2026 11:36:56 -0500 Subject: [PATCH 2/2] fix(server): a quoted $SHELL path keeps a " -" inside it Co-Authored-By: Claude Opus 5.5 --- apps/server/src/terminal/Manager.test.ts | 12 ++++++++++++ apps/server/src/terminal/Manager.ts | 6 ++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/server/src/terminal/Manager.test.ts b/apps/server/src/terminal/Manager.test.ts index d1cc86a7fc7a0..c15e8f8936319 100644 --- a/apps/server/src/terminal/Manager.test.ts +++ b/apps/server/src/terminal/Manager.test.ts @@ -1572,6 +1572,18 @@ it.layer( }), ); + it.effect("starts a quoted $SHELL whose path contains a space and a dash", () => + Effect.gen(function* () { + const { manager, ptyAdapter } = yield* createManager(5, { + env: { SHELL: '"/opt/my -shell/fish" -l' }, + }).pipe(Effect.provide(layerWithHostPlatform("darwin"))); + + yield* manager.open(openInput()); + + expect(ptyAdapter.spawnInputs.map((input) => input.shell)).toEqual(["/opt/my -shell/fish"]); + }), + ); + it.effect( "writes completion syntax for the fallback shell instead of the configured fish shell", () => diff --git a/apps/server/src/terminal/Manager.ts b/apps/server/src/terminal/Manager.ts index e685d605d3a74..7fd43676f3350 100644 --- a/apps/server/src/terminal/Manager.ts +++ b/apps/server/src/terminal/Manager.ts @@ -527,8 +527,10 @@ function normalizeShellCommand( return trimmed; } - // A shell path can contain spaces, so only text from the first flag (`bash -l`) is dropped. - const command = trimmed.split(/\s+(?=-)/)[0]?.replace(/^['"]|['"]$/g, ""); + // A shell path can contain spaces, so only text from the first flag (`bash -l`) is dropped, + // and a quoted path is kept whole even when it contains " -". + const quoted = /^(['"])(.*?)\1(?:\s|$)/.exec(trimmed); + const command = quoted ? quoted[2] : trimmed.split(/\s+(?=-)/)[0]?.replace(/^['"]|['"]$/g, ""); return command || null; }