cdp-tunnel 2.9.1 → 2.9.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.
@@ -338,6 +338,15 @@ importScripts('features/automation-badge.js');
338
338
  });
339
339
  });
340
340
 
341
+ function getCdpAddress(wsUrl, mode) {
342
+ var match = (wsUrl || '').match(/:\/\/([^\/]+):(\d+)/);
343
+ if (!match) return '';
344
+ var host = match[1];
345
+ var port = parseInt(match[2], 10);
346
+ if (mode === 'takeover') port += 1;
347
+ return 'http://' + host + ':' + port;
348
+ }
349
+
341
350
  chrome.runtime.onInstalled.addListener(function(details) {
342
351
  Logger.info('[Runtime] Extension installed/updated:', details.reason);
343
352
  State.persist(null, false);
@@ -466,7 +475,8 @@ importScripts('features/automation-badge.js');
466
475
  status = 'error';
467
476
  }
468
477
  }
469
- return { id: conn.id, tag: conn.tag, url: conn.url, mode: conn.mode || 'create', status: status, attachedCount: attachedCount };
478
+ var cdpAddress = getCdpAddress(conn.url, conn.mode || 'create');
479
+ return { id: conn.id, tag: conn.tag, url: conn.url, mode: conn.mode || 'create', status: status, attachedCount: attachedCount, cdpAddress: cdpAddress };
470
480
  });
471
481
  sendResponse({ connections: list });
472
482
  });
@@ -283,6 +283,37 @@
283
283
  font-family: 'Monaco', 'Menlo', monospace;
284
284
  }
285
285
 
286
+ .conn-config-cdp {
287
+ font-size: 11px;
288
+ color: #374151;
289
+ font-family: 'Monaco', 'Menlo', monospace;
290
+ margin-top: 2px;
291
+ display: flex;
292
+ align-items: center;
293
+ gap: 4px;
294
+ }
295
+
296
+ .conn-config-cdp .cdp-addr {
297
+ color: #2563eb;
298
+ font-weight: 600;
299
+ cursor: pointer;
300
+ }
301
+
302
+ .conn-config-cdp .btn-copy-cdp {
303
+ border: none;
304
+ background: transparent;
305
+ cursor: pointer;
306
+ font-size: 12px;
307
+ padding: 0 4px;
308
+ opacity: 0.5;
309
+ transition: opacity 0.2s;
310
+ line-height: 1;
311
+ }
312
+
313
+ .conn-config-cdp .btn-copy-cdp:hover {
314
+ opacity: 1;
315
+ }
316
+
286
317
  .conn-config-item .btn-delete {
287
318
  padding: 4px 10px;
288
319
  border: none;
@@ -95,13 +95,15 @@
95
95
  connections.forEach(function(conn) {
96
96
  var statusClass = getStatusClass(conn.id, conn.enabled);
97
97
  var isActive = conn.enabled && statusClass === 'connected';
98
+ var cdpAddr = getCdpAddress(conn.url, conn.mode);
98
99
  html +=
99
100
  '<div class="conn-config-item' + (isActive ? ' active' : '') + '" data-id="' + conn.id + '">' +
100
101
  '<input type="checkbox" class="conn-toggle" data-id="' + conn.id + '"' + (conn.enabled ? ' checked' : '') + ' title="启用/禁用">' +
101
102
  '<span class="status-dot ' + statusClass + '" title="' + statusClass + '"></span>' +
102
103
  '<div class="conn-config-info">' +
103
104
  '<div class="conn-config-tag">' + (conn.mode === 'takeover' ? '🔗 ' : '🆕 ') + escapeHtml(conn.tag) + '</div>' +
104
- '<div class="conn-config-url" title="' + escapeAttr(conn.url) + '">' + escapeHtml(conn.url) + '</div>' +
105
+ '<div class="conn-config-url" title="' + escapeAttr(conn.url) + '">WS: ' + escapeHtml(conn.url) + '</div>' +
106
+ (cdpAddr ? '<div class="conn-config-cdp">CDP: <span class="cdp-addr" data-cdp="' + escapeAttr(cdpAddr) + '">' + escapeHtml(cdpAddr) + '</span> <button class="btn-copy-cdp" data-cdp="' + escapeAttr(cdpAddr) + '" title="复制 CDP 地址">📋</button></div>' : '') +
105
107
  '</div>' +
106
108
  '<button class="btn-delete" data-id="' + conn.id + '" title="删除">删除</button>' +
107
109
  '</div>';
@@ -297,6 +299,15 @@
297
299
  return (s || '').replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
298
300
  }
299
301
 
302
+ function getCdpAddress(wsUrl, mode) {
303
+ var match = (wsUrl || '').match(/:\/\/([^\/]+):(\d+)/);
304
+ if (!match) return '';
305
+ var host = match[1];
306
+ var port = parseInt(match[2], 10);
307
+ if (mode === 'takeover') port += 1;
308
+ return 'http://' + host + ':' + port;
309
+ }
310
+
300
311
  function init() {
301
312
  if (typeof chrome !== 'undefined' && chrome.storage) {
302
313
  chrome.storage.local.get(['autoMute'], function(result) {
@@ -365,6 +376,17 @@
365
376
  });
366
377
 
367
378
  elements.connConfigList.addEventListener('click', function(e) {
379
+ var copyBtn = e.target.closest('.btn-copy-cdp');
380
+ if (copyBtn) {
381
+ var addr = copyBtn.dataset.cdp;
382
+ if (addr) {
383
+ navigator.clipboard.writeText(addr).then(function() {
384
+ showToast('已复制: ' + addr);
385
+ });
386
+ }
387
+ return;
388
+ }
389
+
368
390
  var toggleEl = e.target.closest('.conn-toggle');
369
391
  if (toggleEl) {
370
392
  var connId = toggleEl.dataset.id;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "CDP Bridge",
4
- "version": "2.9.1",
4
+ "version": "2.9.2",
5
5
  "description": "Chrome DevTools Protocol Bridge for Playwright/Puppeteer automation",
6
6
  "permissions": [
7
7
  "debugger",
@@ -23,6 +23,12 @@ body { width: 320px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
23
23
  .conn-tag { font-weight: 600; font-size: 13px; color: #e0e0e0; }
24
24
  .conn-url { color: #888; font-size: 11px; font-family: 'SF Mono', Menlo, monospace; word-break: break-all; margin-top: 3px; line-height: 1.4; }
25
25
 
26
+ .conn-cdp { color: #4a9eff; font-size: 11px; font-family: 'SF Mono', Menlo, monospace; margin-top: 2px; display: flex; align-items: center; gap: 2px; }
27
+ .conn-cdp-label { color: #888; }
28
+ .conn-cdp-value { font-weight: 600; }
29
+ .conn-cdp-copy { background: none; border: none; cursor: pointer; font-size: 11px; padding: 0 2px; opacity: 0.5; transition: opacity 0.15s; }
30
+ .conn-cdp-copy:hover { opacity: 1; }
31
+
26
32
  .empty-hint { text-align: center; padding: 16px 10px; color: #777; font-size: 12px; }
27
33
 
28
34
  .stats-row { display: flex; gap: 16px; padding: 8px 0; font-size: 12px; color: #aaa; }
@@ -14,6 +14,15 @@
14
14
  });
15
15
  }
16
16
 
17
+ function getCdpAddress(wsUrl, mode) {
18
+ var match = (wsUrl || '').match(/:\/\/([^\/]+):(\d+)/);
19
+ if (!match) return '';
20
+ var host = match[1];
21
+ var port = parseInt(match[2], 10);
22
+ if (mode === 'takeover') port += 1;
23
+ return 'http://' + host + ':' + port;
24
+ }
25
+
17
26
  function renderConnectionList(connections) {
18
27
  connectionList.innerHTML = '';
19
28
 
@@ -43,10 +52,42 @@
43
52
 
44
53
  var url = document.createElement('div');
45
54
  url.className = 'conn-url';
46
- url.textContent = conn.url;
55
+ url.textContent = 'WS: ' + conn.url;
47
56
 
48
57
  item.appendChild(header);
49
58
  item.appendChild(url);
59
+
60
+ var cdpAddr = conn.cdpAddress || getCdpAddress(conn.url, conn.mode);
61
+ if (cdpAddr) {
62
+ var cdpRow = document.createElement('div');
63
+ cdpRow.className = 'conn-cdp';
64
+
65
+ var cdpLabel = document.createElement('span');
66
+ cdpLabel.className = 'conn-cdp-label';
67
+ cdpLabel.textContent = 'CDP: ';
68
+
69
+ var cdpValue = document.createElement('span');
70
+ cdpValue.className = 'conn-cdp-value';
71
+ cdpValue.textContent = cdpAddr;
72
+
73
+ var copyBtn = document.createElement('button');
74
+ copyBtn.className = 'conn-cdp-copy';
75
+ copyBtn.textContent = '📋';
76
+ copyBtn.title = '复制';
77
+ copyBtn.addEventListener('click', function(ev) {
78
+ ev.stopPropagation();
79
+ navigator.clipboard.writeText(cdpAddr).then(function() {
80
+ copyBtn.textContent = '✓';
81
+ setTimeout(function() { copyBtn.textContent = '📋'; }, 1200);
82
+ });
83
+ });
84
+
85
+ cdpRow.appendChild(cdpLabel);
86
+ cdpRow.appendChild(cdpValue);
87
+ cdpRow.appendChild(copyBtn);
88
+ item.appendChild(cdpRow);
89
+ }
90
+
50
91
  connectionList.appendChild(item);
51
92
  });
52
93
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdp-tunnel",
3
- "version": "2.9.1",
3
+ "version": "2.9.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",