chrome-ai-bridge 2.3.4 → 2.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -92,7 +92,13 @@ export class RelayServer extends EventEmitter {
|
|
|
92
92
|
ws.on('message', (data) => {
|
|
93
93
|
this.handleMessage(data.toString());
|
|
94
94
|
});
|
|
95
|
+
// Guard: only update state if this socket is still the current one.
|
|
96
|
+
// Prevents a stale socket's close event from corrupting a newer connection.
|
|
95
97
|
ws.on('close', () => {
|
|
98
|
+
if (this.ws !== ws) {
|
|
99
|
+
debugLog('[RelayServer] Stale socket closed (ignored — already replaced)');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
96
102
|
debugLog('[RelayServer] Extension disconnected');
|
|
97
103
|
this.stopKeepAlive();
|
|
98
104
|
this.rejectPendingRequests(new Error('RELAY_DISCONNECTED: Extension socket closed before request completion'));
|
|
@@ -330,10 +336,18 @@ export class RelayServer extends EventEmitter {
|
|
|
330
336
|
* Stop server
|
|
331
337
|
*/
|
|
332
338
|
async stop() {
|
|
339
|
+
this.stopKeepAlive();
|
|
333
340
|
if (this.ws) {
|
|
334
|
-
|
|
341
|
+
try {
|
|
342
|
+
this.ws.close();
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
// ignore close errors
|
|
346
|
+
}
|
|
335
347
|
this.ws = null;
|
|
336
348
|
}
|
|
349
|
+
this.ready = false;
|
|
350
|
+
this.tabId = null;
|
|
337
351
|
this.rejectPendingRequests(new Error('RELAY_STOPPED: Relay stopped before request completion'));
|
|
338
352
|
if (this.discoveryServer) {
|
|
339
353
|
this.discoveryServer.close();
|
|
@@ -343,6 +357,7 @@ export class RelayServer extends EventEmitter {
|
|
|
343
357
|
if (this.wss) {
|
|
344
358
|
return new Promise((resolve) => {
|
|
345
359
|
this.wss.close(() => {
|
|
360
|
+
this.wss = null;
|
|
346
361
|
debugLog('[RelayServer] Server stopped');
|
|
347
362
|
resolve();
|
|
348
363
|
});
|
|
@@ -166,22 +166,52 @@ async function rotateHistoryIfNeeded() {
|
|
|
166
166
|
}
|
|
167
167
|
/**
|
|
168
168
|
* キャッシュされたGeminiクライアントをクリア(リトライ用)
|
|
169
|
+
* @deprecated Use resetConnection('gemini') instead
|
|
169
170
|
*/
|
|
170
|
-
export function clearGeminiClient() {
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
export async function clearGeminiClient() {
|
|
172
|
+
await resetConnection('gemini');
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 指定 kind の接続を協調的にクリーンアップする。
|
|
176
|
+
* RelayServer・CdpClient・SessionManager・CDP リスナーを一括リセット。
|
|
177
|
+
* 接続失敗時のリトライ前に呼ぶことで「スティッキーな障害状態」を防ぐ。
|
|
178
|
+
*/
|
|
179
|
+
export async function resetConnection(kind) {
|
|
180
|
+
const label = kind === 'chatgpt' ? 'ChatGPT' : 'Gemini';
|
|
181
|
+
console.error(`[fast-cdp] resetConnection(${kind}) — coordinated cleanup start`);
|
|
182
|
+
// 1. CdpClient: all CDP event listeners removed
|
|
183
|
+
const client = getClientFromAgent(kind);
|
|
173
184
|
if (client) {
|
|
174
|
-
|
|
185
|
+
try {
|
|
186
|
+
client.removeAllCdpListeners();
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// ignore
|
|
190
|
+
}
|
|
191
|
+
console.error(`[${label}] CdpClient listeners removed`);
|
|
175
192
|
}
|
|
193
|
+
// 2. RelayServer: stop + reference clear (await to ensure port is released)
|
|
194
|
+
const relay = getRelayFromAgent(kind);
|
|
176
195
|
if (relay) {
|
|
177
196
|
try {
|
|
178
|
-
relay.stop();
|
|
197
|
+
await relay.stop();
|
|
179
198
|
}
|
|
180
199
|
catch {
|
|
181
200
|
// ignore stop errors
|
|
182
201
|
}
|
|
202
|
+
console.error(`[${label}] RelayServer stopped`);
|
|
183
203
|
}
|
|
184
|
-
|
|
204
|
+
// 3. Agent connection reference clear
|
|
205
|
+
setClientForAgent(kind, null, null);
|
|
206
|
+
console.error(`[${label}] Agent connection references cleared`);
|
|
207
|
+
// 4. Session info clear (await to prevent write race on retry)
|
|
208
|
+
try {
|
|
209
|
+
await clearAgentSession(kind);
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
// ignore session clear errors
|
|
213
|
+
}
|
|
214
|
+
console.error(`[fast-cdp] resetConnection(${kind}) — cleanup complete`);
|
|
185
215
|
}
|
|
186
216
|
/**
|
|
187
217
|
* 全接続をクリーンアップ(プロセス終了時用)
|
|
@@ -367,7 +397,9 @@ async function createConnection(kind) {
|
|
|
367
397
|
logWarn('fast-chat', `${kind} existing tab not found`, {
|
|
368
398
|
error: error instanceof Error ? error.message : String(error),
|
|
369
399
|
});
|
|
370
|
-
console.error(`[fast-cdp] ${kind} existing tab not found,
|
|
400
|
+
console.error(`[fast-cdp] ${kind} existing tab not found, resetting before new tab`);
|
|
401
|
+
// 再利用失敗 → stale 参照をクリアしてから新規タブへ
|
|
402
|
+
await resetConnection(kind);
|
|
371
403
|
}
|
|
372
404
|
}
|
|
373
405
|
// 新しいタブを作成
|
|
@@ -422,7 +454,9 @@ async function createConnection(kind) {
|
|
|
422
454
|
});
|
|
423
455
|
console.error(`[fast-cdp] ${kind} new tab attempt ${attempt + 1} failed:`, lastError.message);
|
|
424
456
|
if (attempt < 1) {
|
|
425
|
-
|
|
457
|
+
// リトライ前に協調クリーンアップして stale 状態を排除
|
|
458
|
+
console.error(`[fast-cdp] Resetting ${kind} connection before retry...`);
|
|
459
|
+
await resetConnection(kind);
|
|
426
460
|
await new Promise(r => setTimeout(r, 1000));
|
|
427
461
|
}
|
|
428
462
|
}
|
|
@@ -446,22 +480,10 @@ export async function getClient(kind) {
|
|
|
446
480
|
console.error(`[fast-cdp] Reusing healthy ${kind} connection`);
|
|
447
481
|
return existing;
|
|
448
482
|
}
|
|
449
|
-
// 接続が切れている →
|
|
483
|
+
// 接続が切れている → 協調クリーンアップして再接続
|
|
450
484
|
logConnectionState(kind, 'reconnecting');
|
|
451
|
-
console.error(`[fast-cdp] ${kind} connection lost,
|
|
452
|
-
|
|
453
|
-
const oldRelay = getRelayFromAgent(kind);
|
|
454
|
-
if (oldRelay) {
|
|
455
|
-
logInfo('fast-chat', `Stopping stale ${kind} RelayServer`);
|
|
456
|
-
console.error(`[fast-cdp] Stopping stale ${kind} RelayServer`);
|
|
457
|
-
await oldRelay.stop().catch((err) => {
|
|
458
|
-
logWarn('fast-chat', `Failed to stop stale ${kind} RelayServer`, {
|
|
459
|
-
error: err instanceof Error ? err.message : String(err),
|
|
460
|
-
});
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
// キャッシュをクリア
|
|
464
|
-
setClientForAgent(kind, null, null);
|
|
485
|
+
console.error(`[fast-cdp] ${kind} connection lost, performing coordinated reset...`);
|
|
486
|
+
await resetConnection(kind);
|
|
465
487
|
}
|
|
466
488
|
// 新しい接続を作成
|
|
467
489
|
return await createConnection(kind);
|
|
@@ -2205,9 +2227,8 @@ async function askGeminiFastInternal(question, debug) {
|
|
|
2205
2227
|
const stuckCheckResult = await checkGeminiStuckState(client);
|
|
2206
2228
|
if (stuckCheckResult.isStuck) {
|
|
2207
2229
|
console.error(`[Gemini] Existing chat appears stuck (stop button detected for ${stuckCheckResult.waitedMs}ms). Clearing session and retrying.`);
|
|
2208
|
-
//
|
|
2209
|
-
await
|
|
2210
|
-
clearGeminiClient();
|
|
2230
|
+
// 協調クリーンアップ(RelayServer + Client + Session を一括リセット)
|
|
2231
|
+
await resetConnection('gemini');
|
|
2211
2232
|
// エラーを投げて、呼び出し元でリトライを促す
|
|
2212
2233
|
throw new Error('GEMINI_STUCK_EXISTING_CHAT: Previous chat appears stuck (stop button visible). Session cleared, please retry.');
|
|
2213
2234
|
}
|
|
@@ -2475,9 +2496,8 @@ async function askGeminiFastInternal(question, debug) {
|
|
|
2475
2496
|
// 30秒以上停止ボタンが検出され続けている場合、セッションをクリアして新規チャットに切り替え
|
|
2476
2497
|
if (stopButtonConsecutiveCount >= forceNewChatThreshold) {
|
|
2477
2498
|
console.error(`[Gemini] Stop button detected for ${forceNewChatThreshold * 0.5}s - clearing session and forcing new chat`);
|
|
2478
|
-
//
|
|
2479
|
-
await
|
|
2480
|
-
clearGeminiClient();
|
|
2499
|
+
// 協調クリーンアップ(RelayServer + Client + Session を一括リセット)
|
|
2500
|
+
await resetConnection('gemini');
|
|
2481
2501
|
// エラーを投げて再試行を促す
|
|
2482
2502
|
throw new Error('GEMINI_STUCK_STOP_BUTTON: Previous response appears stuck. Session cleared, please retry.');
|
|
2483
2503
|
}
|
package/package.json
CHANGED