cdp-tunnel 2.1.0 → 2.1.2

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.
package/cli/index.js CHANGED
@@ -104,6 +104,9 @@ function checkChromeExtension() {
104
104
  }
105
105
 
106
106
  function getExtensionPath() {
107
+ if (process.env.CDP_TUNNEL_DEV_EXT) {
108
+ return process.env.CDP_TUNNEL_DEV_EXT;
109
+ }
107
110
  const cliDir = __dirname;
108
111
  return path.join(cliDir, '..', 'extension-new');
109
112
  }
@@ -181,6 +184,18 @@ function startServer(port, watchdog, autoRestart) {
181
184
  console.log(' 重启次数: ' + restartTimestamps.length + '/' + MAX_RESTARTS + ' (60秒内)');
182
185
  console.log('');
183
186
 
187
+ // Kill any leftover process occupying the port before restarting
188
+ try {
189
+ const result = execSync(`lsof -ti:${port} 2>/dev/null || true`).toString().trim();
190
+ if (result) {
191
+ const pids = result.split('\n').filter(p => p && parseInt(p) !== process.pid);
192
+ pids.forEach(p => { try { process.kill(parseInt(p), 'SIGKILL'); } catch {} });
193
+ if (pids.length > 0) {
194
+ log('gray', ' 已清理占用端口 ' + port + ' 的残留进程: ' + pids.join(', '));
195
+ }
196
+ }
197
+ } catch {}
198
+
184
199
  setTimeout(() => startServer(port, true, autoRestart), 3000);
185
200
  });
186
201
 
@@ -285,7 +285,7 @@ var State = (function() {
285
285
  }
286
286
 
287
287
  var cdpGroups = groups.filter(function(g) {
288
- return g.title && g.title.indexOf('CDP-') === 0;
288
+ return g.title && (g.title.indexOf('CDP-') === 0 || g.title.indexOf('CDP #') === 0);
289
289
  });
290
290
 
291
291
  if (cdpGroups.length === 0) {
@@ -316,6 +316,7 @@ var WebSocketManager = (function() {
316
316
 
317
317
  function closeTabsByClientId(clientId, resolve) {
318
318
  var attachedTabs = State.getAttachedTabIds();
319
+ var groupId = State.getGroupIdForClient(clientId);
319
320
  var tabsToClose = [];
320
321
 
321
322
  attachedTabs.forEach(function(tabId) {
@@ -329,10 +330,35 @@ var WebSocketManager = (function() {
329
330
  resolve();
330
331
  return;
331
332
  }
332
-
333
- Logger.info('[WS] Closing ' + tabsToClose.length + ' attached tabs for clientId:', clientId);
334
-
335
- tabsToClose.forEach(function(tabId) {
333
+
334
+ if (groupId) {
335
+ chrome.tabs.query({ groupId: groupId }, function(groupTabs) {
336
+ if (chrome.runtime.lastError || !groupTabs) {
337
+ resolve();
338
+ return;
339
+ }
340
+ var groupTabIds = new Set(groupTabs.map(function(t) { return t.id; }));
341
+ var safeToClose = tabsToClose.filter(function(tabId) {
342
+ return groupTabIds.has(tabId);
343
+ });
344
+ var unsafeCount = tabsToClose.length - safeToClose.length;
345
+ if (unsafeCount > 0) {
346
+ Logger.info('[WS] Protecting ' + unsafeCount + ' tabs outside group from deletion');
347
+ }
348
+ doCloseTabs(safeToClose, clientId, resolve);
349
+ });
350
+ } else {
351
+ doCloseTabs(tabsToClose, clientId, resolve);
352
+ }
353
+ }
354
+
355
+ function doCloseTabs(tabIds, clientId, resolve) {
356
+ if (tabIds.length === 0) {
357
+ resolve();
358
+ return;
359
+ }
360
+ Logger.info('[WS] Closing ' + tabIds.length + ' attached tabs for clientId:', clientId);
361
+ tabIds.forEach(function(tabId) {
336
362
  chrome.tabs.remove(tabId, function() {
337
363
  if (chrome.runtime.lastError) {
338
364
  Logger.info('[WS] Tab already closed:', tabId);
@@ -341,7 +367,6 @@ var WebSocketManager = (function() {
341
367
  chrome.debugger.detach({ tabId: tabId }).catch(function() {});
342
368
  State.removeAttachedTab(tabId);
343
369
  });
344
-
345
370
  resolve();
346
371
  }
347
372
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdp-tunnel",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
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",
@@ -22,6 +22,7 @@ const PORT = CONFIG.PORT;
22
22
  const CONFIG_DIR = path.join(os.homedir(), '.cdp-tunnel');
23
23
  const EXTENSION_STATE_FILE = path.join(CONFIG_DIR, 'extension-state.json');
24
24
  const PLUGIN_EVER_CONNECTED_FILE = path.join(CONFIG_DIR, 'plugin-ever-connected');
25
+ const SERVER_START_TIME = Date.now();
25
26
 
26
27
  let lastChromeRestartAttempt = 0;
27
28
  const CHROME_RESTART_COOLDOWN = CONFIG.CHROME_RESTART_COOLDOWN;
@@ -739,7 +740,7 @@ function handlePluginConnection(ws, clientInfo) {
739
740
  type: 'connected',
740
741
  role: 'plugin',
741
742
  id: id,
742
- fresh: true,
743
+ fresh: (Date.now() - SERVER_START_TIME) < 5000,
743
744
  timestamp: Date.now()
744
745
  }));
745
746
  }
@@ -1513,4 +1514,14 @@ process.on('SIGTERM', () => {
1513
1514
  process.exit(0);
1514
1515
  });
1515
1516
 
1517
+ server.on('error', (err) => {
1518
+ if (err.code === 'EADDRINUSE') {
1519
+ console.error(`[FATAL] Port ${PORT} is already in use. Is another cdp-tunnel running?`);
1520
+ console.error(` Run "cdp-tunnel stop" first, or kill the process on port ${PORT}.`);
1521
+ process.exit(2);
1522
+ }
1523
+ console.error('[FATAL] Server error:', err.message);
1524
+ process.exit(1);
1525
+ });
1526
+
1516
1527
  server.listen(PORT, '0.0.0.0');