diff --git a/browse/src/cli.ts b/browse/src/cli.ts index 29409c4a..6e0d42f9 100644 --- a/browse/src/cli.ts +++ b/browse/src/cli.ts @@ -330,12 +330,21 @@ async function ensureServer(): Promise { return state; } + // BROWSE_NO_AUTOSTART: sidebar agent sets this so the child claude never + // spawns an invisible headless browser. If the headed server is down, + // fail fast with a clear error instead of silently starting a new one. + if (process.env.BROWSE_NO_AUTOSTART === '1') { + console.error('[browse] Server not available and BROWSE_NO_AUTOSTART is set.'); + console.error('[browse] The headed browser may have been closed. Run /open-gstack-browser to restart.'); + process.exit(1); + } + // Guard: never silently replace a headed server with a headless one. // Headed mode means a user-visible Chrome window is (or was) controlled. // Silently replacing it would be confusing — tell the user to reconnect. if (state && state.mode === 'headed' && isProcessAlive(state.pid)) { console.error(`[browse] Headed server running (PID ${state.pid}) but not responding.`); - console.error(`[browse] Run '$B connect' to restart.`); + console.error(`[browse] Run '/open-gstack-browser' to restart.`); process.exit(1); } diff --git a/browse/src/sidebar-agent.ts b/browse/src/sidebar-agent.ts index f0d62dcd..22f0f53b 100644 --- a/browse/src/sidebar-agent.ts +++ b/browse/src/sidebar-agent.ts @@ -242,9 +242,12 @@ async function askClaude(queueEntry: any): Promise { env: { ...process.env, BROWSE_STATE_FILE: stateFile || '', - // Connect to the existing headed browse server instead of launching a new one. - // Without this, the child claude starts a headless browser on a random port. + // Connect to the existing headed browse server, never start a new one. + // BROWSE_PORT tells the CLI which port to check. + // BROWSE_NO_AUTOSTART prevents spawning an invisible headless browser + // if the headed server is down — fail fast with a clear error instead. BROWSE_PORT: process.env.BROWSE_PORT || '34567', + BROWSE_NO_AUTOSTART: '1', // Pin this agent to its tab — prevents cross-tab interference // when multiple agents run simultaneously BROWSE_TAB: String(tid),