chrome-bridge-mcp 1.31.0 → 1.31.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/extension/manifest.json +1 -1
- package/extension/webmcp-hook.js +5 -2
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/server/index.js +32 -2
- package/server/protocol.js +1 -1
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.31.
|
|
4
|
+
"version": "1.31.1",
|
|
5
5
|
"description": "Bridge your browser to Claude Code: 69 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",
|
package/extension/webmcp-hook.js
CHANGED
|
@@ -283,11 +283,14 @@
|
|
|
283
283
|
} else {
|
|
284
284
|
throw new Error('this WebMCP version has no executeTool and the tool was registered before chrome-bridge could see it');
|
|
285
285
|
}
|
|
286
|
-
|
|
286
|
+
let out = await Promise.race([run, timedOut]);
|
|
287
|
+
// executeTool di Chrome restituisce il risultato come stringa JSON.
|
|
288
|
+
if (typeof out === 'string') { try { out = JSON.parse(out); } catch {} }
|
|
287
289
|
settle(entry, t0, out);
|
|
288
290
|
return { status: 'ok', result: entry.output, ms: entry.ms };
|
|
289
291
|
} catch (err) {
|
|
290
|
-
|
|
292
|
+
// Chrome rifiuta con l'AbortError del segnale prima del nostro timer.
|
|
293
|
+
settle(entry, t0, undefined, ac.signal.aborted && !err?.timeout ? Object.assign(new Error(`timed out after ${timeout} ms`), { timeout: true }) : err);
|
|
291
294
|
return { status: entry.status, error: entry.error, ms: entry.ms };
|
|
292
295
|
} finally {
|
|
293
296
|
clearTimeout(timer);
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-bridge-mcp",
|
|
3
|
-
"version": "1.31.
|
|
3
|
+
"version": "1.31.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "chrome-bridge-mcp",
|
|
9
|
-
"version": "1.31.
|
|
9
|
+
"version": "1.31.2",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@jridgewell/trace-mapping": "^0.3.31",
|
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.31.
|
|
4
|
+
"version": "1.31.2",
|
|
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). 69 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",
|
package/server/index.js
CHANGED
|
@@ -44,6 +44,9 @@ function parseSecurity() {
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
const SHUTDOWN_DEADLINE_MS = 10000;
|
|
48
|
+
const PARENT_CHECK_MS = 1000;
|
|
49
|
+
|
|
47
50
|
function parseCaps() {
|
|
48
51
|
const i = process.argv.indexOf('--caps');
|
|
49
52
|
if (i !== -1 && process.argv[i + 1]) return process.argv[i + 1];
|
|
@@ -78,6 +81,9 @@ async function main() {
|
|
|
78
81
|
// segnale arrivano insieme.
|
|
79
82
|
let closing = null;
|
|
80
83
|
const shutdown = () => (closing ??= (async () => {
|
|
84
|
+
// Uno shutdown bloccato non deve tenere vivo il processo: dopo la
|
|
85
|
+
// scadenza, o al secondo segnale, si esce comunque.
|
|
86
|
+
setTimeout(forceExit, SHUTDOWN_DEADLINE_MS);
|
|
81
87
|
console.error('[chrome-bridge] Shutting down...');
|
|
82
88
|
// Il browser di --launch per primo: su Windows Claude Code chiude stdin e
|
|
83
89
|
// dopo 300 ms uccide l'albero dei processi (2.1.296). Le sue schede
|
|
@@ -91,14 +97,38 @@ async function main() {
|
|
|
91
97
|
try { await mcpServer.close(); } catch {}
|
|
92
98
|
process.exit(0);
|
|
93
99
|
})());
|
|
94
|
-
|
|
95
|
-
|
|
100
|
+
const forceExit = () => {
|
|
101
|
+
if (browser) { try { process.kill(browser.pid, 'SIGKILL'); } catch {} }
|
|
102
|
+
process.exit(1);
|
|
103
|
+
};
|
|
104
|
+
const onSignal = () => (closing ? forceExit() : shutdown());
|
|
105
|
+
process.on('SIGINT', onSignal);
|
|
106
|
+
process.on('SIGTERM', onSignal);
|
|
107
|
+
// Client sparito: stdout e stderr restano pipe senza lettore e ogni
|
|
108
|
+
// scrittura dà EPIPE. Senza questi ascoltatori l'errore arrivava a
|
|
109
|
+
// uncaughtException, che riscriveva su stderr: un ciclo di errori che non
|
|
110
|
+
// lasciava girare l'event loop, neanche per SIGTERM (28/10/2026: un server
|
|
111
|
+
// --launch orfano da 2 h al 46% di CPU, chiuso solo con SIGKILL).
|
|
112
|
+
process.stdout.on('error', shutdown);
|
|
113
|
+
process.stderr.on('error', shutdown);
|
|
96
114
|
// Su Windows SIGINT e SIGTERM non arrivano, e un client terminato di colpo
|
|
97
115
|
// non manda segnali: in entrambi i casi resta solo la fine di stdin. L'SDK
|
|
98
116
|
// non la ascolta, e il WebSocket teneva vivo il processo.
|
|
99
117
|
process.stdin.once('end', shutdown);
|
|
100
118
|
process.stdin.once('close', shutdown);
|
|
101
119
|
mcpServer.server.onclose = shutdown;
|
|
120
|
+
// Prima di mcpServer.connect() nessuno legge stdin e la sua fine non
|
|
121
|
+
// arriva; un client che muore durante l'avvio a freddo di Chrome lascia un
|
|
122
|
+
// orfano adottato da init (o da systemd, su Crostini). Il cambio di padre
|
|
123
|
+
// lo rivela anche quando stdin resta aperto in un altro processo.
|
|
124
|
+
if (LAUNCH) {
|
|
125
|
+
const parent = process.ppid;
|
|
126
|
+
const parentGone = () => {
|
|
127
|
+
if (process.ppid !== parent) return true;
|
|
128
|
+
try { process.kill(parent, 0); return false; } catch (e) { return e.code !== 'EPERM'; }
|
|
129
|
+
};
|
|
130
|
+
setInterval(() => { if (parentGone()) shutdown(); }, PARENT_CHECK_MS).unref();
|
|
131
|
+
}
|
|
102
132
|
process.on('uncaughtException', (err) => {
|
|
103
133
|
console.error('[chrome-bridge] Uncaught exception:', err);
|
|
104
134
|
shutdown().catch(() => process.exit(1));
|