cdp-tunnel 2.7.8 → 2.7.10

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
  });
@@ -251,7 +256,16 @@ var SpecialHandler = (function() {
251
256
  Logger.error('[TabGroup] tabGroups.query failed:', chrome.runtime.lastError.message);
252
257
  EventBuilder.send('CDPTunnel.debug', { source: 'doGroup', phase: 'query', error: chrome.runtime.lastError.message });
253
258
  }
254
- 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');
255
269
  var existing = CDPUtils.findGroupByName(allGroups, baseName);
256
270
  if (existing) {
257
271
  Logger.info('[TabGroup] Found existing group:', existing.id, 'title:', existing.title);
@@ -3,6 +3,7 @@ var WebSocketManager = (function() {
3
3
  var _isSending = false;
4
4
  var _maxQueueSize = 100;
5
5
  var _bufferThreshold = 512 * 1024;
6
+ var _groupCreationPending = new Set();
6
7
 
7
8
  function connect() {
8
9
  var ws = State.getWs();
@@ -197,13 +198,14 @@ var WebSocketManager = (function() {
197
198
  Logger.info('[WS] Client connected, resuming event forwarding');
198
199
  State.setHasConnectedClient(true);
199
200
  State.addCDPClient(message.clientId, message.clientId);
200
- startGroupMonitor();
201
+ createGroupForClient(message.clientId);
201
202
  broadcastStateUpdate();
202
203
  break;
203
204
 
204
205
  case 'client-disconnected':
205
206
  Logger.info('[WS] Client disconnected:', message.clientId);
206
207
  var discClientId = message.clientId;
208
+ _groupCreationPending.delete(discClientId);
207
209
  closeTabGroupByClientId(discClientId).then(function() {
208
210
  return new Promise(function(resolve) {
209
211
  closeTabsByClientId(discClientId, resolve);
@@ -221,7 +223,6 @@ var WebSocketManager = (function() {
221
223
  State.removeCDPClient(discClientId);
222
224
  if (State.getCDPClients().length === 0) {
223
225
  State.setHasConnectedClient(false);
224
- stopGroupMonitor();
225
226
  }
226
227
  broadcastStateUpdate();
227
228
  });
@@ -231,11 +232,6 @@ var WebSocketManager = (function() {
231
232
  Logger.info('[WS] Received client list:', message.clients);
232
233
  State.setCDPClients(message.clients || []);
233
234
  State.setHasConnectedClient((message.clients || []).length > 0);
234
- if ((message.clients || []).length > 0) {
235
- startGroupMonitor();
236
- } else {
237
- stopGroupMonitor();
238
- }
239
235
  broadcastStateUpdate();
240
236
  break;
241
237
 
@@ -459,57 +455,50 @@ var WebSocketManager = (function() {
459
455
  });
460
456
  }
461
457
 
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');
458
+ function createGroupForClient(clientId) {
459
+ if (!clientId || !chrome.tabGroups) return;
460
+
461
+ if (_groupCreationPending.has(clientId)) {
462
+ Logger.info('[WS] Group creation already pending for client:', clientId);
463
+ return;
464
+ }
465
+
466
+ var existingGroupId = State.getGroupIdForClient(clientId);
467
+ if (existingGroupId) {
468
+ Logger.info('[WS] Group already cached for client:', clientId, 'groupId:', existingGroupId);
469
+ return;
470
+ }
471
+
472
+ _groupCreationPending.add(clientId);
473
+
474
+ var baseName = CDPUtils.getGroupBaseName(clientId);
475
+ chrome.tabs.query({ currentWindow: true }, function(tabs) {
476
+ if (!tabs || tabs.length === 0) {
477
+ Logger.warn('[WS] No tabs found for group creation');
478
+ _groupCreationPending.delete(clientId);
479
+ return;
480
+ }
481
+ var windowId = tabs[0].windowId;
482
+ chrome.tabs.group({ createProperties: { windowId: windowId } }, function(groupId) {
483
+ if (chrome.runtime.lastError) {
484
+ Logger.warn('[WS] Failed to create group on connect:', chrome.runtime.lastError.message);
485
+ _groupCreationPending.delete(clientId);
478
486
  return;
479
487
  }
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
- if (chrome.runtime.lastError) {
492
- Logger.error('[Monitor] Failed to re-add tab', tabId, 'to group', groupId, ':', chrome.runtime.lastError?.message);
493
- State.removeGroupForClient(clientId);
494
- SpecialHandler.addTabToAutomationGroup(tabId, clientId);
495
- } else {
496
- Logger.info('[Monitor] Re-added tab', tabId, 'to existing group:', groupId);
497
- }
498
- });
499
- } else {
500
- Logger.info('[Monitor] No cached groupId for client', clientId, '— delegating to addTabToAutomationGroup for tab', tabId);
501
- SpecialHandler.addTabToAutomationGroup(tabId, clientId);
488
+ _groupCreationPending.delete(clientId);
489
+ chrome.tabGroups.update(groupId, {
490
+ title: baseName,
491
+ color: CDPUtils.getGroupColorForClient(clientId),
492
+ collapsed: true
493
+ }, function() {
494
+ if (chrome.runtime.lastError) {
495
+ Logger.warn('[WS] Failed to set group title:', chrome.runtime.lastError.message);
502
496
  }
503
497
  });
498
+ State.setGroupIdForClient(clientId, groupId);
499
+ Logger.info('[WS] Created group for client:', clientId, 'groupId:', groupId, 'title:', baseName);
504
500
  });
505
- }, 5000);
506
- }
507
-
508
- function stopGroupMonitor() {
509
- if (_groupMonitorTimer) {
510
- clearInterval(_groupMonitorTimer);
511
- _groupMonitorTimer = null;
512
- }
501
+ });
513
502
  }
514
503
 
515
504
  function handleServerRestart() {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "CDP Bridge",
4
- "version": "2.7.8",
4
+ "version": "2.7.10",
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.8",
3
+ "version": "2.7.10",
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",