chrome-bridge-mcp 1.30.4 → 1.30.6

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Chrome Bridge for Claude Code",
4
- "version": "1.30.2",
4
+ "version": "1.30.5",
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",
@@ -4821,10 +4821,25 @@ async function cmdDragAndDrop({ source_selector, target_selector, mode = 'html5'
4821
4821
  const results = await chrome.scripting.executeScript({
4822
4822
  target: scriptTarget(tabId, frame_id),
4823
4823
  func: async (srcSel, tgtSel, dndMode) => {
4824
- const src = document.querySelector(srcSel);
4825
- if (!src) throw new Error(`Source element not found: ${srcSel}`);
4826
- const tgt = document.querySelector(tgtSel);
4827
- if (!tgt) throw new Error(`Target element not found: ${tgtSel}`);
4824
+ function deepQuery(sel) {
4825
+ if (!sel.includes('>>>')) return document.querySelector(sel);
4826
+ const parts = sel.split('>>>').map((s) => s.trim());
4827
+ let ctx = document;
4828
+ for (let i = 0; i < parts.length; i++) {
4829
+ const found = ctx.querySelector(parts[i]);
4830
+ if (!found) return null;
4831
+ if (i === parts.length - 1) return found;
4832
+ if (!found.shadowRoot) return null;
4833
+ ctx = found.shadowRoot;
4834
+ }
4835
+ return null;
4836
+ }
4837
+ // Un throw qui arrivava come result undefined e diventava {dragged:false}:
4838
+ // un selettore ">>>" (SyntaxError per querySelector) falliva in silenzio.
4839
+ const src = deepQuery(srcSel);
4840
+ if (!src) return { missing: 'Source', selector: srcSel };
4841
+ const tgt = deepQuery(tgtSel);
4842
+ if (!tgt) return { missing: 'Target', selector: tgtSel };
4828
4843
  src.scrollIntoView({ block: 'center', behavior: 'instant' });
4829
4844
  const sr = src.getBoundingClientRect();
4830
4845
  const tr = tgt.getBoundingClientRect();
@@ -4867,7 +4882,9 @@ async function cmdDragAndDrop({ source_selector, target_selector, mode = 'html5'
4867
4882
  args: [source_selector, target_selector, mode],
4868
4883
  world: 'MAIN',
4869
4884
  });
4870
- return results?.[0]?.result ?? { dragged: false };
4885
+ const out = elementOutcome(results, source_selector);
4886
+ if (out.missing) throw new Error(`${out.missing} element not found: ${out.selector} (no element matches; check it with query_dom)`);
4887
+ return out;
4871
4888
  }
4872
4889
 
4873
4890
  // --- clipboard ---
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",
4
+ "version": "1.30.6",
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",
@@ -4,6 +4,10 @@
4
4
 
5
5
  import { randomBytes } from 'node:crypto';
6
6
 
7
+ // Pagina dell'estensione sul Chrome Web Store: la ricerca dello store la trova
8
+ // di rado, quindi chi dice «estensione non connessa» dà il link diretto.
9
+ export const EXTENSION_STORE_URL = 'https://chromewebstore.google.com/detail/chrome-bridge-for-claude/bioknpaeahidbelaljjohjofiloeodmb';
10
+
7
11
  // Tipi di messaggi WebSocket
8
12
  export const MessageType = Object.freeze({
9
13
  // Comandi (server → extension)
@@ -100,7 +104,7 @@ export const MessageType = Object.freeze({
100
104
  });
101
105
 
102
106
  // Versione
103
- export const VERSION = '1.30.4';
107
+ export const VERSION = '1.30.6';
104
108
 
105
109
  // Configurazione
106
110
  export const DEFAULT_PORT = 8765;
package/server/tools.js CHANGED
@@ -13,7 +13,7 @@ import { parse as parseHtml } from 'node-html-parser';
13
13
  import { z } from 'zod';
14
14
  import { runAssert } from './assertions.js';
15
15
  import { ensureStubServer, addStub, clearStubs, listStubs, stubHost } from './stub-server.js';
16
- import { MessageType, VERSION } from './protocol.js';
16
+ import { MessageType, VERSION, EXTENSION_STORE_URL } from './protocol.js';
17
17
  import { checkLinksBatch } from './link-checker.js';
18
18
  import { toHar } from './har.js';
19
19
  import { decodeTrackingRequests, trackingLines } from './trackers.js';
@@ -839,7 +839,7 @@ export function registerTools(server, wsManager, caps = 'all', options = {}) {
839
839
  server.tool(
840
840
  'get_status',
841
841
  'Status of the bridge itself, not of a page: call it when a tool you expect is missing or browser commands fail '
842
- + '(connected=false: the extension is not reachable). Also reports mode (primary/relay), host, port, server and '
842
+ + '(connected=false: the extension is not reachable, extension_install gives its Chrome Web Store link). Also reports mode (primary/relay), host, port, server and '
843
843
  + 'extension versions, js_evaluation (false under --no-js), write_root, read_root, session_tab_id (the implicit tab), '
844
844
  + 'owned_tabs (created by this session), uptime_sec. caps_active and caps_available: a missing tool lives in an inactive cap. '
845
845
  + 'enable is the only change it makes: it switches caps on for this session, no restart, and lists the tools added. Optional caps: '
@@ -869,6 +869,8 @@ export function registerTools(server, wsManager, caps = 'all', options = {}) {
869
869
  type: 'text',
870
870
  text: jsonText({
871
871
  connected: wsManager.isConnected(),
872
+ // Senza estensione l'agente ha il link da dare all'utente.
873
+ ...(!wsManager.isConnected() && { extension_install: EXTENSION_STORE_URL }),
872
874
  mode: wsManager.mode,
873
875
  host: wsManager.host,
874
876
  port: wsManager.port,
@@ -14,7 +14,7 @@
14
14
  */
15
15
 
16
16
  import WebSocket, { WebSocketServer } from 'ws';
17
- import { DEFAULT_PORT, PING_INTERVAL_MS, IDENT_TIMEOUT_MS, PENDING_RELAY_TTL_MS, getTimeout, createCommand, MessageType, VERSION } from './protocol.js';
17
+ import { DEFAULT_PORT, PING_INTERVAL_MS, IDENT_TIMEOUT_MS, PENDING_RELAY_TTL_MS, getTimeout, createCommand, MessageType, VERSION, EXTENSION_STORE_URL } from './protocol.js';
18
18
 
19
19
  /** Quanto tenere in vita l'attesa di risposta per un comando arrivato da un relay. */
20
20
  export function relayExpiry(msg) {
@@ -134,7 +134,7 @@ export class WSManager {
134
134
  `Chrome extension not connected (server ${this.mode} on ${this.host}:${this.port}`
135
135
  + `${this.mode === 'relay' ? ', reached through another chrome-bridge instance' : ''}`
136
136
  + `, waited ${Math.round(this.connectWaitMs / 1000)}s)`
137
- + ` — ${this.notConnectedHint || 'open Chrome, check the chrome-bridge extension is enabled and its port matches'}`,
137
+ + ` — ${this.notConnectedHint || `open Chrome, check the chrome-bridge extension is enabled and its port matches (not installed yet: ${EXTENSION_STORE_URL})`}`,
138
138
  );
139
139
  }
140
140
  return this._send(type, params);
@@ -454,7 +454,7 @@ export class WSManager {
454
454
  ws.send(JSON.stringify({
455
455
  id: msg.id,
456
456
  type: MessageType.ERROR,
457
- error: 'Chrome extension not connected',
457
+ error: `Chrome extension not connected — install or enable it: ${EXTENSION_STORE_URL}`,
458
458
  }));
459
459
  return;
460
460
  }