diff --git a/src/utils/browser/chrome-reuse.ts b/src/utils/browser/chrome-reuse.ts index eacefe8b..976c39ef 100644 --- a/src/utils/browser/chrome-reuse.ts +++ b/src/utils/browser/chrome-reuse.ts @@ -49,18 +49,7 @@ export function resolveDefaultChromeUserDataDir( } export function resolveConfiguredBrowserProfileDir(profileDir?: string): string | undefined { - if (profileDir?.trim()) { - return expandPath(profileDir); - } - - try { - const defaultUserDataDir = resolveDefaultChromeUserDataDir(); - return fs.existsSync(path.join(defaultUserDataDir, DEVTOOLS_ACTIVE_PORT_FILE)) - ? defaultUserDataDir - : undefined; - } catch { - return undefined; - } + return profileDir?.trim() ? expandPath(profileDir) : undefined; } export async function resolveBrowserRuntimeEnv( diff --git a/tests/unit/targets/default-profile-browser-launch.test.ts b/tests/unit/targets/default-profile-browser-launch.test.ts index 1f42f749..2ee938a3 100644 --- a/tests/unit/targets/default-profile-browser-launch.test.ts +++ b/tests/unit/targets/default-profile-browser-launch.test.ts @@ -151,6 +151,40 @@ exit 0 await expect(waitForMockDevtoolsPort(delayedPortFile, 500)).resolves.toBe('43123'); }); + it('ignores stale default Chrome DevTools metadata unless browser reuse is explicitly configured', () => { + if (process.platform === 'win32') return; + + const defaultChromeDir = path.join( + tmpHome, + 'Library', + 'Application Support', + 'Google', + 'Chrome' + ); + fs.mkdirSync(defaultChromeDir, { recursive: true }); + fs.writeFileSync( + path.join(defaultChromeDir, 'DevToolsActivePort'), + '9222\n/devtools/browser/stale-default', + 'utf8' + ); + + const result = runCcs(['default', 'smoke'], { + ...baseEnv, + HOME: tmpHome, + USERPROFILE: tmpHome, + }); + + expect(result.status).toBe(0); + expect(result.stderr).not.toContain('Chrome DevTools endpoint is unreachable'); + + const launchedArgs = fs.readFileSync(claudeArgsLogPath, 'utf8'); + expect(launchedArgs).not.toContain(BROWSER_PROMPT_SNIPPET); + + const launchedEnv = fs.readFileSync(claudeEnvLogPath, 'utf8'); + expect(launchedEnv).not.toContain('9222'); + expect(launchedEnv).not.toContain('devtools/browser/stale-default'); + }); + it('passes browser runtime env through default Claude launches when reuse is configured', async () => { if (process.platform === 'win32') return; diff --git a/tests/unit/utils/browser/chrome-reuse.test.ts b/tests/unit/utils/browser/chrome-reuse.test.ts index e0b8ac8a..f9b90c5c 100644 --- a/tests/unit/utils/browser/chrome-reuse.test.ts +++ b/tests/unit/utils/browser/chrome-reuse.test.ts @@ -3,12 +3,15 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { + resolveConfiguredBrowserProfileDir, resolveBrowserRuntimeEnv, resolveDefaultChromeUserDataDir, } from '../../../../src/utils/browser/chrome-reuse'; describe('chrome reuse resolver', () => { + const originalHome = process.env.HOME; const originalLocalAppData = process.env.LOCALAPPDATA; + const originalUserProfile = process.env.USERPROFILE; let tempDirs: string[] = []; let servers: Array<{ stop: () => void }> = []; @@ -96,6 +99,18 @@ describe('chrome reuse resolver', () => { } else { process.env.LOCALAPPDATA = originalLocalAppData; } + + if (originalHome === undefined) { + delete process.env.HOME; + } else { + process.env.HOME = originalHome; + } + + if (originalUserProfile === undefined) { + delete process.env.USERPROFILE; + } else { + process.env.USERPROFILE = originalUserProfile; + } }); it('uses explicit profile-dir before the default path and resolves the websocket target', async () => { @@ -122,6 +137,23 @@ describe('chrome reuse resolver', () => { expect(fs.existsSync(path.join(defaultProfileDir, 'DevToolsActivePort'))).toBe(false); }); + it('only enables browser reuse for an explicitly configured profile directory', () => { + const isolatedHome = createTempDir('ccs-chrome-config-home-'); + const defaultProfileDir = path.join( + isolatedHome, + 'Library', + 'Application Support', + 'Google', + 'Chrome' + ); + writeDevToolsActivePort(defaultProfileDir, '9222\n/devtools/browser/stale-default'); + process.env.HOME = isolatedHome; + process.env.USERPROFILE = isolatedHome; + + expect(resolveConfiguredBrowserProfileDir()).toBeUndefined(); + expect(resolveConfiguredBrowserProfileDir(defaultProfileDir)).toBe(defaultProfileDir); + }); + it('uses an explicit devtools port override when metadata is missing', async () => { const profileDir = createTempDir('ccs-chrome-explicit-port-'); const server = await startDevToolsServer({