From 741b57ed061c767ed25777f39b9fe826aaa1bcbc Mon Sep 17 00:00:00 2001 From: Gal Zahavi <38544478+galz10@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:21:23 -0700 Subject: [PATCH] fix(core): Use shell for spawn on Windows (#9995) --- packages/cli/src/gemini.test.tsx | 26 ++++++++++++++----- .../src/validateNonInterActiveAuth.test.ts | 1 + packages/core/src/ide/ide-installer.test.ts | 19 +++++++++++++- packages/core/src/ide/ide-installer.ts | 2 +- packages/core/src/utils/editor.test.ts | 1 + packages/core/src/utils/editor.ts | 1 + 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/gemini.test.tsx b/packages/cli/src/gemini.test.tsx index 4d6b894393..a0de0d6165 100644 --- a/packages/cli/src/gemini.test.tsx +++ b/packages/cli/src/gemini.test.tsx @@ -32,13 +32,25 @@ class MockProcessExitError extends Error { } // Mock dependencies -vi.mock('./config/settings.js', async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - loadSettings: vi.fn(), - }; -}); +vi.mock('./config/settings.js', () => ({ + loadSettings: vi.fn().mockReturnValue({ + merged: { + advanced: {}, + security: { auth: {} }, + ui: {}, + }, + setValue: vi.fn(), + forScope: () => ({ settings: {}, originalSettings: {}, path: '' }), + errors: [], + }), + migrateDeprecatedSettings: vi.fn(), + SettingScope: { + User: 'user', + Workspace: 'workspace', + System: 'system', + SystemDefaults: 'system-defaults', + }, +})); vi.mock('./config/config.js', () => ({ loadCliConfig: vi.fn().mockResolvedValue({ diff --git a/packages/cli/src/validateNonInterActiveAuth.test.ts b/packages/cli/src/validateNonInterActiveAuth.test.ts index 9f3159c88a..e4f9d961f5 100644 --- a/packages/cli/src/validateNonInterActiveAuth.test.ts +++ b/packages/cli/src/validateNonInterActiveAuth.test.ts @@ -31,6 +31,7 @@ describe('validateNonInterActiveAuth', () => { processExitSpy = vi.spyOn(process, 'exit').mockImplementation((code) => { throw new Error(`process.exit(${code}) called`); }); + vi.spyOn(auth, 'validateAuthMethod').mockReturnValue(null); refreshAuthMock = vi.fn().mockResolvedValue('refreshed'); mockSettings = { system: { path: '', settings: {} }, diff --git a/packages/core/src/ide/ide-installer.test.ts b/packages/core/src/ide/ide-installer.test.ts index dd29bb85e2..ff2afce27f 100644 --- a/packages/core/src/ide/ide-installer.test.ts +++ b/packages/core/src/ide/ide-installer.test.ts @@ -119,7 +119,24 @@ describe('ide-installer', () => { 'google.gemini-cli-vscode-ide-companion', '--force', ], - { stdio: 'pipe' }, + { stdio: 'pipe', shell: false }, + ); + }); + + it('installs the extension using code cli on windows', async () => { + const { installer } = setup({ + platform: 'win32', + execSync: () => 'C:\\Program Files\\Microsoft VS Code\\bin\\code.cmd', + }); + await installer.install(); + expect(child_process.spawnSync).toHaveBeenCalledWith( + 'C:\\Program Files\\Microsoft VS Code\\bin\\code.cmd', + [ + '--install-extension', + 'google.gemini-cli-vscode-ide-companion', + '--force', + ], + { stdio: 'pipe', shell: true }, ); }); diff --git a/packages/core/src/ide/ide-installer.ts b/packages/core/src/ide/ide-installer.ts index 554b87a987..62d5382b4c 100644 --- a/packages/core/src/ide/ide-installer.ts +++ b/packages/core/src/ide/ide-installer.ts @@ -125,7 +125,7 @@ class VsCodeInstaller implements IdeInstaller { 'google.gemini-cli-vscode-ide-companion', '--force', ], - { stdio: 'pipe' }, + { stdio: 'pipe', shell: this.platform === 'win32' }, ); if (result.status !== 0) { diff --git a/packages/core/src/utils/editor.test.ts b/packages/core/src/utils/editor.test.ts index db72124047..acc9e1a1a9 100644 --- a/packages/core/src/utils/editor.test.ts +++ b/packages/core/src/utils/editor.test.ts @@ -339,6 +339,7 @@ describe('editor utils', () => { diffCommand.args, { stdio: 'inherit', + shell: process.platform === 'win32', }, ); expect(mockSpawnOn).toHaveBeenCalledWith('close', expect.any(Function)); diff --git a/packages/core/src/utils/editor.ts b/packages/core/src/utils/editor.ts index 8b507926a0..1023abe4a0 100644 --- a/packages/core/src/utils/editor.ts +++ b/packages/core/src/utils/editor.ts @@ -195,6 +195,7 @@ export async function openDiff( return new Promise((resolve, reject) => { const childProcess = spawn(diffCommand.command, diffCommand.args, { stdio: 'inherit', + shell: process.platform === 'win32', }); childProcess.on('close', (code) => {