cdp-tunnel 2.7.7 → 2.7.9

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.
@@ -142,10 +142,57 @@ importScripts('features/automation-badge.js');
142
142
  State.removeTabIdToClientId(tabId);
143
143
  });
144
144
 
145
+ if (chrome.tabGroups) {
146
+ chrome.tabGroups.onRemoved.addListener(function(group) {
147
+ if (!group) return;
148
+ var removedGroupId = group.id;
149
+ Logger.info('[TabGroups] Group removed:', removedGroupId);
150
+
151
+ var clients = State.getCDPClients() || [];
152
+ for (var i = 0; i < clients.length; i++) {
153
+ var clientId = clients[i].id;
154
+ if (State.getGroupIdForClient(clientId) === removedGroupId) {
155
+ Logger.info('[TabGroups] Clearing cached groupId for client:', clientId);
156
+ State.setGroupIdForClient(clientId, null);
157
+
158
+ var attached = State.getAttachedTabIds();
159
+ attached.forEach(function(tid) {
160
+ if (State.getClientIdByTabId(tid) === clientId && !State.isPreExistingTab(tid)) {
161
+ Logger.info('[TabGroups] Re-grouping tab', tid, 'for client:', clientId);
162
+ SpecialHandler.addTabToAutomationGroup(tid, clientId);
163
+ }
164
+ });
165
+ break;
166
+ }
167
+ }
168
+ });
169
+ }
170
+
145
171
  chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
146
172
  if (changeInfo.status === 'complete' && State.isTabAttached(tabId)) {
147
173
  // 不再注入自动化标识,改为通过标签分组区分
148
174
  }
175
+
176
+ if (changeInfo.groupId !== undefined && changeInfo.groupId === -1) {
177
+ if (State.isTabAttached(tabId) && !State.isPreExistingTab(tabId)) {
178
+ var clientId = State.getClientIdByTabId(tabId);
179
+ if (clientId) {
180
+ var cachedGroupId = State.getGroupIdForClient(clientId);
181
+ if (cachedGroupId) {
182
+ Logger.info('[Tabs] Tab', tabId, 'left group, re-adding to cached group:', cachedGroupId);
183
+ chrome.tabs.group({ tabIds: tabId, groupId: cachedGroupId }, function() {
184
+ if (chrome.runtime.lastError) {
185
+ Logger.warn('[Tabs] Failed to re-add tab to group:', chrome.runtime.lastError.message);
186
+ SpecialHandler.addTabToAutomationGroup(tabId, clientId);
187
+ }
188
+ });
189
+ } else {
190
+ Logger.info('[Tabs] Tab', tabId, 'left group, no cached groupId — delegating to addTabToAutomationGroup');
191
+ SpecialHandler.addTabToAutomationGroup(tabId, clientId);
192
+ }
193
+ }
194
+ }
195
+ }
149
196
  });
150
197
 
151
198
  chrome.tabs.onCreated.addListener(function(tab) {
@@ -165,8 +165,13 @@ var SpecialHandler = (function() {
165
165
  var prev = _groupQueue.get(key) || Promise.resolve();
166
166
 
167
167
  var next = prev.then(function() {
168
- return new Promise(function(resolve) {
168
+ return new Promise(function(resolve, reject) {
169
+ var timeoutId = setTimeout(function() {
170
+ reject(new Error('addTabToAutomationGroup timeout after 10s'));
171
+ }, 10000);
172
+
169
173
  _addTabToAutomationGroupInner(tabId, clientId, function(success) {
174
+ clearTimeout(timeoutId);
170
175
  resolve(success);
171
176
  });
172
177
  });
@@ -227,12 +232,40 @@ var SpecialHandler = (function() {
227
232
  if (callback) callback(false);
228
233
  return;
229
234
  }
235
+ var cachedGroupId = State.getGroupIdForClient(clientId);
236
+ if (cachedGroupId) {
237
+ Logger.info('[TabGroup] Using cached groupId:', cachedGroupId, 'for client:', clientId);
238
+ chrome.tabs.group({ tabIds: tabId, groupId: cachedGroupId }, function(result) {
239
+ if (!chrome.runtime.lastError) {
240
+ updateTabGroupName(clientId);
241
+ Logger.info('[TabGroup] Tab', tabId, 'added to cached group:', cachedGroupId);
242
+ if (callback) callback(true);
243
+ return;
244
+ }
245
+ Logger.warn('[TabGroup] Cached groupId', cachedGroupId, 'failed:', chrome.runtime.lastError.message, '— falling back to query');
246
+ doGroupQuery(tabId, clientId, baseName, retries, callback);
247
+ });
248
+ return;
249
+ }
250
+ doGroupQuery(tabId, clientId, baseName, retries, callback);
251
+ }
252
+
253
+ function doGroupQuery(tabId, clientId, baseName, retries, callback) {
230
254
  chrome.tabGroups.query({}, function(allGroups) {
231
255
  if (chrome.runtime.lastError) {
232
256
  Logger.error('[TabGroup] tabGroups.query failed:', chrome.runtime.lastError.message);
233
257
  EventBuilder.send('CDPTunnel.debug', { source: 'doGroup', phase: 'query', error: chrome.runtime.lastError.message });
234
258
  }
235
- Logger.info('[TabGroup] query result: ' + (allGroups ? allGroups.length : 'null') + ' groups');
259
+ if (!allGroups) {
260
+ Logger.error('[TabGroup] tabGroups.query returned null');
261
+ if (retries < 3) {
262
+ setTimeout(function() { doGroup(tabId, clientId, baseName, retries + 1, callback); }, 500);
263
+ } else {
264
+ if (callback) callback(false);
265
+ }
266
+ return;
267
+ }
268
+ Logger.info('[TabGroup] query result: ' + allGroups.length + ' groups');
236
269
  var existing = CDPUtils.findGroupByName(allGroups, baseName);
237
270
  if (existing) {
238
271
  Logger.info('[TabGroup] Found existing group:', existing.id, 'title:', existing.title);
@@ -267,7 +300,7 @@ var SpecialHandler = (function() {
267
300
  }
268
301
  Logger.info('[TabGroup] chrome.tabs.group returned groupId:', groupId);
269
302
  EventBuilder.send('CDPTunnel.debug', { source: 'doGroup', phase: 'groupCreated', tabId: tabId, groupId: groupId });
270
- if (groupId) {
303
+ if (groupId) {
271
304
  if (chrome.tabGroups) {
272
305
  chrome.tabGroups.update(groupId, {
273
306
  title: baseName,
@@ -197,7 +197,7 @@ var WebSocketManager = (function() {
197
197
  Logger.info('[WS] Client connected, resuming event forwarding');
198
198
  State.setHasConnectedClient(true);
199
199
  State.addCDPClient(message.clientId, message.clientId);
200
- startGroupMonitor();
200
+ createGroupForClient(message.clientId);
201
201
  broadcastStateUpdate();
202
202
  break;
203
203
 
@@ -221,7 +221,6 @@ var WebSocketManager = (function() {
221
221
  State.removeCDPClient(discClientId);
222
222
  if (State.getCDPClients().length === 0) {
223
223
  State.setHasConnectedClient(false);
224
- stopGroupMonitor();
225
224
  }
226
225
  broadcastStateUpdate();
227
226
  });
@@ -231,11 +230,6 @@ var WebSocketManager = (function() {
231
230
  Logger.info('[WS] Received client list:', message.clients);
232
231
  State.setCDPClients(message.clients || []);
233
232
  State.setHasConnectedClient((message.clients || []).length > 0);
234
- if ((message.clients || []).length > 0) {
235
- startGroupMonitor();
236
- } else {
237
- stopGroupMonitor();
238
- }
239
233
  broadcastStateUpdate();
240
234
  break;
241
235
 
@@ -459,64 +453,40 @@ var WebSocketManager = (function() {
459
453
  });
460
454
  }
461
455
 
462
- var _groupMonitorTimer = null;
463
-
464
- function startGroupMonitor() {
465
- Logger.info('[Monitor] Starting group monitor...');
466
- if (_groupMonitorTimer) clearInterval(_groupMonitorTimer);
467
- _groupMonitorTimer = setInterval(function() {
468
- var attached = State.getAttachedTabIds();
469
- Logger.info('[Monitor] Checking ' + attached.length + ' attached tabs for grouping...');
470
- attached.forEach(function(tabId) {
471
- var clientId = State.getClientIdByTabId(tabId);
472
- if (!clientId) {
473
- Logger.warn('[Monitor] Tab', tabId, 'has no clientId mapping, cannot group');
474
- return;
475
- }
476
- if (State.isPreExistingTab(tabId)) {
477
- Logger.info('[Monitor] Tab', tabId, 'is pre-existing, skipping');
456
+ function createGroupForClient(clientId) {
457
+ if (!clientId || !chrome.tabGroups) return;
458
+
459
+ var existingGroupId = State.getGroupIdForClient(clientId);
460
+ if (existingGroupId) {
461
+ Logger.info('[WS] Group already cached for client:', clientId, 'groupId:', existingGroupId);
462
+ return;
463
+ }
464
+
465
+ var baseName = CDPUtils.getGroupBaseName(clientId);
466
+ chrome.tabs.query({ currentWindow: true }, function(tabs) {
467
+ if (!tabs || tabs.length === 0) {
468
+ Logger.warn('[WS] No tabs found for group creation');
469
+ return;
470
+ }
471
+ var windowId = tabs[0].windowId;
472
+ chrome.tabs.group({ createProperties: { windowId: windowId } }, function(groupId) {
473
+ if (chrome.runtime.lastError) {
474
+ Logger.warn('[WS] Failed to create group on connect:', chrome.runtime.lastError.message);
478
475
  return;
479
476
  }
480
- chrome.tabs.get(tabId, function(tab) {
481
- if (chrome.runtime.lastError || !tab) {
482
- Logger.error('[Monitor] Tab', tabId, 'not found:', chrome.runtime.lastError?.message);
483
- return;
484
- }
485
- var groupId = State.getGroupIdForClient(clientId);
486
- Logger.info('[Monitor] Tab', tabId, 'groupId=' + (tab.groupId > -1 ? tab.groupId : 'none'), 'expectedGroup=' + (groupId > -1 ? groupId : 'none'), 'clientId=' + (clientId || 'none'));
487
- if (tab.groupId > -1) return;
488
- Logger.info('[Monitor] Tab', tabId, 'escaped! Forcing regroup for client:', clientId);
489
- if (groupId) {
490
- chrome.tabs.group({ tabIds: tabId, groupId: groupId }, function() {
491
- Logger.info('[Monitor] Re-added tab', tabId, 'to existing group:', groupId);
492
- });
493
- } else {
494
- var baseName = CDPUtils.getGroupBaseName(clientId);
495
- chrome.tabs.group({ tabIds: tabId }, function(newGroupId) {
496
- if (chrome.runtime.lastError || !newGroupId) {
497
- Logger.error('[Monitor] Failed to create group for tab', tabId, ':', chrome.runtime.lastError?.message);
498
- return;
499
- }
500
- chrome.tabGroups.update(newGroupId, {
501
- title: baseName,
502
- color: CDPUtils.getGroupColorForClient(clientId),
503
- collapsed: true
504
- }, function() {
505
- State.setGroupIdForClient(clientId, newGroupId);
506
- Logger.info('[Monitor] Created new group', newGroupId, 'for escaped tab', tabId);
507
- });
508
- });
477
+ chrome.tabGroups.update(groupId, {
478
+ title: baseName,
479
+ color: CDPUtils.getGroupColorForClient(clientId),
480
+ collapsed: true
481
+ }, function() {
482
+ if (chrome.runtime.lastError) {
483
+ Logger.warn('[WS] Failed to set group title:', chrome.runtime.lastError.message);
509
484
  }
510
485
  });
486
+ State.setGroupIdForClient(clientId, groupId);
487
+ Logger.info('[WS] Created group for client:', clientId, 'groupId:', groupId, 'title:', baseName);
511
488
  });
512
- }, 5000);
513
- }
514
-
515
- function stopGroupMonitor() {
516
- if (_groupMonitorTimer) {
517
- clearInterval(_groupMonitorTimer);
518
- _groupMonitorTimer = null;
519
- }
489
+ });
520
490
  }
521
491
 
522
492
  function handleServerRestart() {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "CDP Bridge",
4
- "version": "2.7.7",
4
+ "version": "2.7.9",
5
5
  "description": "Chrome DevTools Protocol Bridge for Playwright/Puppeteer automation",
6
6
  "permissions": [
7
7
  "debugger",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdp-tunnel",
3
- "version": "2.7.7",
3
+ "version": "2.7.9",
4
4
  "description": "Bridge Chrome's debugger API to WebSocket — control your existing browser with Playwright/Puppeteer via CDP",
5
5
  "main": "server/proxy-server.js",
6
6
  "bin": "./cli/index.js",