diff --git a/browse/src/browser-manager.ts b/browse/src/browser-manager.ts index 63d78358..51c7348d 100644 --- a/browse/src/browser-manager.ts +++ b/browse/src/browser-manager.ts @@ -72,6 +72,11 @@ export class BrowserManager { private connectionMode: 'launched' | 'headed' = 'launched'; private intentionalDisconnect = false; + // Called when the headed browser disconnects without intentional teardown + // (user closed the window). Wired up by server.ts to run full cleanup + // (sidebar-agent, state file, profile locks) before exiting with code 2. + public onDisconnect: (() => void) | null = null; + getConnectionMode(): 'launched' | 'headed' { return this.connectionMode; } // ─── Watch Mode Methods ───────────────────────────────── @@ -467,13 +472,20 @@ export class BrowserManager { await this.newTab(); } - // Browser disconnect handler — exit code 2 distinguishes from crashes (1) + // Browser disconnect handler — exit code 2 distinguishes from crashes (1). + // Calls onDisconnect() to trigger full shutdown (kill sidebar-agent, save + // session, clean profile locks + state file) before exit. Falls back to + // direct process.exit(2) if no callback is wired up. if (this.browser) { this.browser.on('disconnected', () => { if (this.intentionalDisconnect) return; console.error('[browse] Real browser disconnected (user closed or crashed).'); console.error('[browse] Run `$B connect` to reconnect.'); - process.exit(2); + if (this.onDisconnect) { + this.onDisconnect(); + } else { + process.exit(2); + } }); } diff --git a/browse/src/server.ts b/browse/src/server.ts index 4982a62c..81548c1b 100644 --- a/browse/src/server.ts +++ b/browse/src/server.ts @@ -805,6 +805,10 @@ function emitInspectorEvent(event: any): void { // ─── Server ──────────────────────────────────────────────────── const browserManager = new BrowserManager(); +// When the user closes the headed browser window, run full cleanup +// (kill sidebar-agent, save session, remove profile locks, delete state file) +// before exiting with code 2. Exit code 2 distinguishes user-close from crashes (1). +browserManager.onDisconnect = () => shutdown(2); let isShuttingDown = false; // Test if a port is available by binding and immediately releasing. @@ -1192,7 +1196,7 @@ async function handleCommand(body: any, tokenInfo?: TokenInfo | null): Promise