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))
|
|
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,
|
|
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
|
}
|
package/extension/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Chrome Bridge for Claude Code",
|
|
4
|
-
"version": "1.30.
|
|
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
|
-
|
|
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.
|
|
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",
|