diff --git a/apps/server/src/terminal/Manager.test.ts b/apps/server/src/terminal/Manager.test.ts index 60cbd0dc52729..5677e841d18cf 100644 --- a/apps/server/src/terminal/Manager.test.ts +++ b/apps/server/src/terminal/Manager.test.ts @@ -1946,6 +1946,32 @@ 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("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 3f1b63255cbb3..799354d5e2e25 100644 --- a/apps/server/src/terminal/Manager.ts +++ b/apps/server/src/terminal/Manager.ts @@ -539,9 +539,11 @@ 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, + // 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; } function basenameForPlatform(command: string, platform: NodeJS.Platform): string {