diff --git a/src/context.ts b/src/context.ts index 1e2fa3c0..cd267faa 100644 --- a/src/context.ts +++ b/src/context.ts @@ -17,10 +17,14 @@ export class Context { return this._ws; } - set ws(ws: WebSocket) { + set ws(ws: WebSocket | undefined) { this._ws = ws; } + clearWs() { + this._ws = undefined; + } + hasWs(): boolean { return !!this._ws; } @@ -48,5 +52,6 @@ export class Context { return; } await this._ws.close(); + this._ws = undefined; } } diff --git a/src/server.ts b/src/server.ts index 7c118f0e..fa0d7312 100644 --- a/src/server.ts +++ b/src/server.ts @@ -35,9 +35,27 @@ export async function createServerWithTools(options: Options): Promise { wss.on("connection", (websocket) => { // Close any existing connections if (context.hasWs()) { - context.ws.close(); + try { + context.ws.close(); + } catch {} } context.ws = websocket; + + // Ping heartbeat to keep Chrome MV3 background service worker alive + const pingInterval = setInterval(() => { + if (websocket.readyState === websocket.OPEN) { + websocket.ping(); + } else { + clearInterval(pingInterval); + } + }, 5000); + + websocket.on("close", () => { + clearInterval(pingInterval); + if (context.hasWs() && context.ws === websocket) { + context.clearWs(); + } + }); }); server.setRequestHandler(ListToolsRequestSchema, async () => { @@ -82,8 +100,9 @@ export async function createServerWithTools(options: Options): Promise { return { contents }; }); + const originalClose = server.close.bind(server); server.close = async () => { - await server.close(); + await originalClose(); await wss.close(); await context.close(); }; diff --git a/src/utils/port.ts b/src/utils/port.ts index 0e388dfe..c8966c0d 100644 --- a/src/utils/port.ts +++ b/src/utils/port.ts @@ -16,12 +16,15 @@ export function killProcessOnPort(port: number) { try { if (process.platform === "win32") { execSync( - `FOR /F "tokens=5" %a in ('netstat -ano ^| findstr :${port}') do taskkill /F /PID %a`, + `FOR /F "tokens=5" %a in ('netstat -ano ^| findstr :${port}') do taskkill /F /PID %a 2>nul`, + { stdio: "ignore" }, ); } else { - execSync(`lsof -ti:${port} | xargs kill -9`); + execSync(`lsof -ti:${port} | xargs kill -9 2>/dev/null`, { + stdio: "ignore", + }); } - } catch (error) { - console.error(`Failed to kill process on port ${port}:`, error); + } catch { + // Port might not be in use, ignore expected exit code } }