chrome-bridge-mcp 1.30.0 → 1.30.1

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.
@@ -25,6 +25,7 @@
25
25
  max: 0,
26
26
  items: [],
27
27
  blobs: new Map(),
28
+ names: new Map(),
28
29
  seq: 0,
29
30
  };
30
31
  Object.defineProperty(window, '__cbCapture', { value: st, configurable: true });
@@ -65,6 +66,16 @@
65
66
  return url;
66
67
  };
67
68
 
69
+ // a[download] su un URL http(s): lo scarica Chrome, e il service worker lo
70
+ // annulla a onCreated, quando Chrome non ha ancora scelto il nome. Qui si
71
+ // segna il nome dell'attributo, che il service worker chiede per quell'URL.
72
+ const noteName = (a) => {
73
+ if (st.armed && a instanceof HTMLAnchorElement && a.hasAttribute('download') && /^https?:/i.test(a.href || '')) {
74
+ const n = a.getAttribute('download');
75
+ if (n) st.names.set(a.href, n);
76
+ }
77
+ };
78
+
68
79
  const capturable = (a) => a instanceof HTMLAnchorElement && a.hasAttribute('download') && /^(blob|data):/i.test(a.href || '');
69
80
  const take = (a) => fromUrl(a.href, a.getAttribute('download') || '', a.href.startsWith('data:') ? 'data_url' : 'blob');
70
81
 
@@ -74,6 +85,7 @@
74
85
  window.addEventListener('click', (e) => {
75
86
  if (!st.armed || e.defaultPrevented || handled.has(e)) return;
76
87
  const a = e.composedPath().find((n) => n instanceof HTMLAnchorElement);
88
+ noteName(a);
77
89
  if (!capturable(a)) return;
78
90
  handled.add(e);
79
91
  e.preventDefault();
@@ -87,7 +99,10 @@
87
99
  // quelli della pagina, annulla l'azione nativa se la pagina non l'ha fatto.
88
100
  const origClick = HTMLAnchorElement.prototype.click;
89
101
  HTMLAnchorElement.prototype.click = function click() {
90
- if (!st.armed || !capturable(this)) return origClick.apply(this, arguments);
102
+ if (!st.armed || !capturable(this)) {
103
+ noteName(this);
104
+ return origClick.apply(this, arguments);
105
+ }
91
106
  const ev = new MouseEvent('click', { bubbles: true, cancelable: true, composed: true, view: window });
92
107
  let wanted = false;
93
108
  const last = (e) => {
@@ -202,5 +217,5 @@
202
217
  };
203
218
  st.drop = (id) => { st.items = st.items.filter((x) => x.id !== id); };
204
219
  st.arm = (max) => { st.armed = true; st.max = max; };
205
- st.disarm = () => { st.armed = false; st.items = []; st.blobs.clear(); };
220
+ st.disarm = () => { st.armed = false; st.items = []; st.blobs.clear(); st.names.clear(); };
206
221
  })();
@@ -3,7 +3,10 @@
3
3
  * del server (server/capture.js, che decide il nome sul disco).
4
4
  *
5
5
  * Ordine: filename* di Content-Disposition (RFC 5987, UTF-8 percent-encoded),
6
- * filename, il nome che Chrome aveva già scelto, l'ultimo segmento dell'URL.
6
+ * filename, l'attributo download dell'ancora cliccata (come in Chrome, dopo
7
+ * Content-Disposition), il nome che Chrome aveva già scelto, l'ultimo segmento
8
+ * dell'URL. A onCreated Chrome di solito non ha ancora scelto il nome: senza
9
+ * l'attributo, <a href="/" download="x.html"> arrivava come download.html.
7
10
  */
8
11
  export function dispositionName(header) {
9
12
  const h = String(header || '');
@@ -27,6 +30,6 @@ export function nameFromUrl(url) {
27
30
  }
28
31
  }
29
32
 
30
- export function downloadName({ disposition, chromeName, url }) {
31
- return dispositionName(disposition) || String(chromeName || '').split(/[\\/]/).pop() || nameFromUrl(url) || '';
33
+ export function downloadName({ disposition, chromeName, pageName, url }) {
34
+ return dispositionName(disposition) || String(pageName || '') || String(chromeName || '').split(/[\\/]/).pop() || nameFromUrl(url) || '';
32
35
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Chrome Bridge for Claude Code",
4
- "version": "1.30.0",
4
+ "version": "1.30.1",
5
5
  "description": "Bridge your browser to Claude Code: 67 token-efficient web-dev automation tools over a local WebSocket. ChromeOS included.",
6
6
  "homepage_url": "https://github.com/frsorrentino/chrome-bridge",
7
7
  "minimum_chrome_version": "135",
@@ -5112,7 +5112,16 @@ async function captureDownload(item) {
5112
5112
  const res = await fetch(url, { credentials: 'include', redirect: 'follow' });
5113
5113
  const declared = Number(res.headers.get('content-length') || 0);
5114
5114
  entry.mime = res.headers.get('content-type') || entry.mime;
5115
- entry.name = downloadName({ disposition: res.headers.get('content-disposition'), chromeName: item.filename, url: res.url || url });
5115
+ let pageName = '';
5116
+ try {
5117
+ const probes = await chrome.scripting.executeScript({
5118
+ target: { tabId, allFrames: true }, world: 'MAIN',
5119
+ func: (u) => window.__cbCapture?.names.get(u) ?? '',
5120
+ args: [item.url],
5121
+ });
5122
+ pageName = probes.map((r) => r.result).find(Boolean) || '';
5123
+ } catch {}
5124
+ entry.name = downloadName({ disposition: res.headers.get('content-disposition'), chromeName: item.filename, pageName, url: res.url || url });
5116
5125
  if (!res.ok) throw new Error(`refetch answered HTTP ${res.status} (a POST download or a one-time link cannot be fetched again)`);
5117
5126
  if (declared > max) {
5118
5127
  try { await res.body?.cancel(); } catch {}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "chrome-bridge-mcp",
3
3
  "mcpName": "io.github.frsorrentino/chrome-bridge",
4
- "version": "1.30.0",
4
+ "version": "1.30.1",
5
5
  "type": "module",
6
6
  "description": "Chrome Bridge by frsorrentino: MCP server that lets Claude Code borrow a tab from your own logged-in Chrome and hand it back — logins, 2FA and CAPTCHAs stay with you (handoff). 67 tools; 2.8-4.3× cheaper and up to 9.3× fewer turns than Claude in Chrome, measured; ChromeOS included.",
7
7
  "main": "server/index.js",
@@ -100,7 +100,7 @@ export const MessageType = Object.freeze({
100
100
  });
101
101
 
102
102
  // Versione
103
- export const VERSION = '1.30.0';
103
+ export const VERSION = '1.30.1';
104
104
 
105
105
  // Configurazione
106
106
  export const DEFAULT_PORT = 8765;