ghost-bridge 0.6.2 → 0.7.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.
package/README.md CHANGED
@@ -18,17 +18,6 @@ Most browser-capable AI tools start a separate browser. Ghost Bridge connects AI
18
18
  - Click, type, scroll, and submit forms on the current page
19
19
  - Share one Chrome transport across multiple MCP clients
20
20
 
21
- ## What's New in 0.6.1
22
-
23
- - `list_network_requests` and `get_network_detail` now summarize `data:` URLs and oversized URLs so inline images and long query strings do not overwhelm model context
24
-
25
- ## What's New in 0.6.0
26
-
27
- - `inspect_page` now collects structured page data and interactive elements in one browser-side snapshot, reducing duplicate DOM scans and cutting one round-trip from the hot path
28
- - `capture_screenshot` now defaults to JPEG for better transfer efficiency: visible viewport screenshots default to `quality: 80`, and `fullPage` screenshots default to `quality: 70`
29
- - Use `format: "png"` when you need high-fidelity text rendering, 1px lines, icon edges, transparency, or pixel-level UI inspection
30
- - Attachment and request cleanup paths are more robust under concurrent usage and multi-client reconnect scenarios
31
-
32
21
  ## Quick Start
33
22
 
34
23
  ### 1. Install
@@ -107,7 +96,7 @@ Typical prompts:
107
96
  | `dispatch_action` | Click, fill, press, scroll, hover, select |
108
97
  | `list_network_requests` | Inspect captured network traffic |
109
98
  | `get_network_detail` | Read one request in detail |
110
- | `get_last_error` | Inspect recent errors and exceptions |
99
+ | `get_last_error` | Inspect recent console, exception, and network error events |
111
100
  | `get_script_source` | Extract page scripts |
112
101
  | `find_by_string` | Search within bundled script content |
113
102
  | `coverage_snapshot` | Identify active scripts quickly |
package/dist/cli.js CHANGED
@@ -5505,14 +5505,14 @@ function getJsonClientDefinition(name, configPath, options = {}) {
5505
5505
  function getClientDefinitions() {
5506
5506
  const homeDir = getHomeDir();
5507
5507
  const claudeDir = path2.join(homeDir, ".claude");
5508
- const claudeSettingsPath = path2.join(claudeDir, "settings.json");
5509
5508
  const claudeLegacyPath = path2.join(homeDir, ".claude.json");
5510
5509
  const cursorDir = path2.join(homeDir, ".cursor");
5511
5510
  const antigravityDir = path2.join(homeDir, ".gemini", "antigravity");
5511
+ const hasClaudeLegacy = import_fs_extra.default.existsSync(claudeLegacyPath);
5512
5512
  return [
5513
- getJsonClientDefinition("Claude Code", import_fs_extra.default.existsSync(claudeSettingsPath) ? claudeSettingsPath : claudeLegacyPath, {
5514
- shouldCreate: true,
5515
- isAvailable: () => import_fs_extra.default.existsSync(claudeDir) || import_fs_extra.default.existsSync(claudeLegacyPath)
5513
+ getJsonClientDefinition("Claude Code (~/.claude.json)", claudeLegacyPath, {
5514
+ shouldCreate: hasClaudeLegacy || import_fs_extra.default.existsSync(claudeDir),
5515
+ isAvailable: () => hasClaudeLegacy || import_fs_extra.default.existsSync(claudeDir)
5516
5516
  }),
5517
5517
  {
5518
5518
  name: "Codex",
package/dist/server.js CHANGED
@@ -28536,14 +28536,11 @@ var GHOST_BRIDGE_VERSION = packageJson.version;
28536
28536
 
28537
28537
  // src/server.js
28538
28538
  var BASE_PORT = Number(process.env.GHOST_BRIDGE_PORT || 33333);
28539
- function getMonthlyToken() {
28540
- const now = /* @__PURE__ */ new Date();
28541
- const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1, 0, 0, 0, 0);
28542
- return String(firstDayOfMonth.getTime());
28543
- }
28544
- var WS_TOKEN = process.env.GHOST_BRIDGE_TOKEN || getMonthlyToken();
28539
+ var DEFAULT_WS_TOKEN = "ghost-bridge-local";
28540
+ var WS_TOKEN = process.env.GHOST_BRIDGE_TOKEN || DEFAULT_WS_TOKEN;
28545
28541
  var RESPONSE_TIMEOUT = 8e3;
28546
28542
  var PORT_INFO_FILE = path2.join(os.tmpdir(), "ghost-bridge-port.json");
28543
+ var SERVER_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
28547
28544
  var chromeConnection = null;
28548
28545
  var activeConnection = null;
28549
28546
  var actualPort = BASE_PORT;
@@ -28580,35 +28577,87 @@ function getExistingService() {
28580
28577
  return null;
28581
28578
  }
28582
28579
  }
28583
- function verifyExistingService(port) {
28580
+ function probeExistingService(port) {
28584
28581
  return new Promise((resolve) => {
28585
28582
  const url2 = new URL(`ws://localhost:${port}`);
28586
- if (WS_TOKEN) url2.searchParams.set("token", WS_TOKEN);
28583
+ url2.searchParams.set("role", "probe");
28587
28584
  const ws = new import_websocket.default(url2.toString());
28585
+ let settled = false;
28586
+ const finish = (result) => {
28587
+ if (settled) return;
28588
+ settled = true;
28589
+ clearTimeout(timeout);
28590
+ try {
28591
+ if (ws.readyState === import_websocket.default.CONNECTING || ws.readyState === import_websocket.default.OPEN) {
28592
+ ws.close();
28593
+ }
28594
+ } catch {
28595
+ }
28596
+ resolve(result);
28597
+ };
28588
28598
  const timeout = setTimeout(() => {
28589
- ws.close();
28590
- resolve(false);
28599
+ finish(null);
28591
28600
  }, 2e3);
28592
28601
  ws.on("message", (data) => {
28593
28602
  try {
28594
28603
  const msg = JSON.parse(data.toString());
28595
28604
  if (msg.type === "identity" && msg.service === "ghost-bridge") {
28596
- clearTimeout(timeout);
28597
- ws.close();
28598
- resolve(true);
28605
+ finish(msg);
28599
28606
  }
28600
28607
  } catch {
28601
28608
  }
28602
28609
  });
28603
28610
  ws.on("error", () => {
28604
- clearTimeout(timeout);
28605
- resolve(false);
28611
+ finish(null);
28606
28612
  });
28607
28613
  ws.on("close", () => {
28608
- clearTimeout(timeout);
28614
+ finish(null);
28609
28615
  });
28610
28616
  });
28611
28617
  }
28618
+ function sleep(ms) {
28619
+ return new Promise((resolve) => setTimeout(resolve, ms));
28620
+ }
28621
+ async function waitForPortAvailable(port, timeoutMs = 5e3) {
28622
+ const deadline = Date.now() + timeoutMs;
28623
+ while (Date.now() < deadline) {
28624
+ if (await isPortAvailable(port)) {
28625
+ return true;
28626
+ }
28627
+ await sleep(100);
28628
+ }
28629
+ return isPortAvailable(port);
28630
+ }
28631
+ async function stopExistingService(pid, port) {
28632
+ if (!pid || pid === process.pid) {
28633
+ return false;
28634
+ }
28635
+ log(`\u68C0\u6D4B\u5230\u65E7\u5B9E\u4F8B token \u4E0D\u4E00\u81F4\uFF0C\u51C6\u5907\u505C\u6B62\u65E7\u5B9E\u4F8B (PID: ${pid})`);
28636
+ try {
28637
+ process.kill(pid, "SIGTERM");
28638
+ } catch (e) {
28639
+ if (e.code === "ESRCH") {
28640
+ log(`\u65E7\u5B9E\u4F8B PID ${pid} \u5DF2\u4E0D\u5B58\u5728`);
28641
+ return true;
28642
+ }
28643
+ throw e;
28644
+ }
28645
+ const released = await waitForPortAvailable(port, 5e3);
28646
+ if (!released) {
28647
+ throw new Error(`\u65E7\u5B9E\u4F8B (PID: ${pid}) \u672A\u5728\u9884\u671F\u65F6\u95F4\u5185\u91CA\u653E\u7AEF\u53E3 ${port}`);
28648
+ }
28649
+ if (fs2.existsSync(PORT_INFO_FILE)) {
28650
+ try {
28651
+ const info = JSON.parse(fs2.readFileSync(PORT_INFO_FILE, "utf-8"));
28652
+ if (info.pid === pid) {
28653
+ fs2.unlinkSync(PORT_INFO_FILE);
28654
+ }
28655
+ } catch {
28656
+ }
28657
+ }
28658
+ log(`\u2705 \u65E7\u5B9E\u4F8B\u5DF2\u9000\u51FA\uFF0C\u7AEF\u53E3 ${port} \u53EF\u7531\u65B0\u5B9E\u4F8B\u63A5\u7BA1`);
28659
+ return true;
28660
+ }
28612
28661
  function isPortAvailable(port) {
28613
28662
  return new Promise((resolve) => {
28614
28663
  const server2 = net.createServer();
@@ -28634,12 +28683,16 @@ async function initWebSocketService() {
28634
28683
  const existing = getExistingService();
28635
28684
  if (existing) {
28636
28685
  log(`\u68C0\u6D4B\u5230\u73B0\u6709\u670D\u52A1 (PID: ${existing.pid}, \u7AEF\u53E3: ${existing.port})\uFF0C\u9A8C\u8BC1\u4E2D...`);
28637
- const valid = await verifyExistingService(existing.port);
28638
- if (valid) {
28639
- actualPort = existing.port;
28640
- isMainInstance = false;
28641
- log(`\u2705 \u590D\u7528\u73B0\u6709\u670D\u52A1\uFF0C\u7AEF\u53E3 ${actualPort}`);
28642
- return null;
28686
+ const probe = await probeExistingService(existing.port);
28687
+ if (probe?.service === "ghost-bridge") {
28688
+ if (probe.token === WS_TOKEN) {
28689
+ actualPort = existing.port;
28690
+ isMainInstance = false;
28691
+ log(`\u2705 \u590D\u7528\u73B0\u6709\u670D\u52A1\uFF0C\u7AEF\u53E3 ${actualPort}`);
28692
+ return null;
28693
+ }
28694
+ const oldPid = Number(probe.pid) || existing.pid;
28695
+ await stopExistingService(oldPid, existing.port);
28643
28696
  } else {
28644
28697
  log(`\u274C \u73B0\u6709\u670D\u52A1\u9A8C\u8BC1\u5931\u8D25\uFF0C\u542F\u52A8\u65B0\u670D\u52A1...`);
28645
28698
  try {
@@ -28649,14 +28702,19 @@ async function initWebSocketService() {
28649
28702
  }
28650
28703
  }
28651
28704
  if (!await isPortAvailable(BASE_PORT)) {
28652
- const valid = await verifyExistingService(BASE_PORT);
28653
- if (valid) {
28654
- actualPort = BASE_PORT;
28655
- isMainInstance = false;
28656
- log(`\u2705 \u590D\u7528\u56FA\u5B9A\u7AEF\u53E3\u4E0A\u7684\u73B0\u6709\u670D\u52A1\uFF0C\u7AEF\u53E3 ${actualPort}`);
28657
- return null;
28705
+ const probe = await probeExistingService(BASE_PORT);
28706
+ if (probe?.service === "ghost-bridge") {
28707
+ if (probe.token === WS_TOKEN) {
28708
+ actualPort = BASE_PORT;
28709
+ isMainInstance = false;
28710
+ log(`\u2705 \u590D\u7528\u56FA\u5B9A\u7AEF\u53E3\u4E0A\u7684\u73B0\u6709\u670D\u52A1\uFF0C\u7AEF\u53E3 ${actualPort}`);
28711
+ return null;
28712
+ }
28713
+ await stopExistingService(Number(probe.pid), BASE_PORT);
28714
+ }
28715
+ if (!await isPortAvailable(BASE_PORT)) {
28716
+ throw new Error(`\u56FA\u5B9A\u7AEF\u53E3 ${BASE_PORT} \u5DF2\u88AB\u5176\u4ED6\u8FDB\u7A0B\u5360\u7528\uFF0C\u8BF7\u91CA\u653E\u8BE5\u7AEF\u53E3\u6216\u901A\u8FC7 GHOST_BRIDGE_PORT \u6307\u5B9A\u5176\u4ED6\u7AEF\u53E3`);
28658
28717
  }
28659
- throw new Error(`\u56FA\u5B9A\u7AEF\u53E3 ${BASE_PORT} \u5DF2\u88AB\u5176\u4ED6\u8FDB\u7A0B\u5360\u7528\uFF0C\u8BF7\u91CA\u653E\u8BE5\u7AEF\u53E3\u6216\u901A\u8FC7 GHOST_BRIDGE_PORT \u6307\u5B9A\u5176\u4ED6\u7AEF\u53E3`);
28660
28718
  }
28661
28719
  const wss2 = await startWebSocketServer();
28662
28720
  isMainInstance = true;
@@ -28666,7 +28724,7 @@ async function initWebSocketService() {
28666
28724
  port: actualPort,
28667
28725
  wsUrl: `ws://localhost:${actualPort}`,
28668
28726
  pid: process.pid,
28669
- startedAt: (/* @__PURE__ */ new Date()).toISOString()
28727
+ startedAt: SERVER_STARTED_AT
28670
28728
  }, null, 2)
28671
28729
  );
28672
28730
  log(`\u{1F4DD} \u7AEF\u53E3\u4FE1\u606F\u5DF2\u5199\u5165: ${PORT_INFO_FILE}`);
@@ -28678,6 +28736,18 @@ if (wss) {
28678
28736
  const url2 = new URL(req.url || "/", "http://localhost");
28679
28737
  const token = url2.searchParams.get("token") || "";
28680
28738
  const role = url2.searchParams.get("role") || "";
28739
+ if (role === "probe") {
28740
+ ws.send(JSON.stringify({
28741
+ type: "identity",
28742
+ service: "ghost-bridge",
28743
+ token: WS_TOKEN,
28744
+ pid: process.pid,
28745
+ port: actualPort,
28746
+ startedAt: SERVER_STARTED_AT
28747
+ }));
28748
+ ws.close(1e3, "Probe complete");
28749
+ return;
28750
+ }
28681
28751
  if (WS_TOKEN && token !== WS_TOKEN) {
28682
28752
  log(`\u62D2\u7EDD\u8FDE\u63A5\uFF1Atoken \u4E0D\u5339\u914D (\u6536\u5230: ${token}, \u671F\u671B: ${WS_TOKEN})`);
28683
28753
  ws.close(1008, "Bad token");
@@ -28929,7 +28999,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
28929
28999
  tools: [
28930
29000
  {
28931
29001
  name: "inspect_page",
28932
- description: "\u3010\u9875\u9762\u5206\u6790\u5165\u53E3\u3011\u5F53\u7528\u6237\u8981\u6C42\u5206\u6790\u5F53\u524D\u9875\u9762/\u7F51\u7AD9/\u7F51\u9875\u3001\u7406\u89E3\u9875\u9762\u7ED3\u6784\u3001\u5FEB\u901F\u67E5\u770B\u5F53\u524D\u6807\u7B7E\u5185\u5BB9\u65F6\uFF0C\u4F18\u5148\u4F7F\u7528\u6B64\u5DE5\u5177\u3002\u65E0\u9700\u7528\u6237\u663E\u5F0F\u63D0\u5230 ghost-bridge\u3002\u9ED8\u8BA4\u8FD4\u56DE\u9875\u9762\u5143\u6570\u636E\u3001\u7ED3\u6784\u5316\u5185\u5BB9\u6458\u8981\u548C\u53EF\u4EA4\u4E92\u5143\u7D20\u6982\u89C8\uFF0C\u9002\u5408\u4F5C\u4E3A\u540E\u7EED\u622A\u56FE\u3001\u4EA4\u4E92\u3001\u7F51\u7EDC\u6392\u67E5\u524D\u7684\u7B2C\u4E00\u6B65\u3002",
29002
+ description: "\u9875\u9762\u5206\u6790\u5165\u53E3\u3002\u8FD4\u56DE\u9875\u9762\u5143\u6570\u636E\u3001\u7ED3\u6784\u5316\u6458\u8981\u548C\u53EF\u4EA4\u4E92\u5143\u7D20\u6982\u89C8\uFF0C\u9002\u5408\u5148\u5FEB\u901F\u4E86\u89E3\u5F53\u524D\u9875\u9762\u3002",
28933
29003
  inputSchema: {
28934
29004
  type: "object",
28935
29005
  properties: {
@@ -28955,7 +29025,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
28955
29025
  },
28956
29026
  {
28957
29027
  name: "get_last_error",
28958
- description: "\u83B7\u53D6\u5F53\u524D\u6807\u7B7E\u6700\u8FD1\u7684\u5F02\u5E38/\u62A5\u9519\u5806\u6808\u4E0E\u5143\u6570\u636E\uFF08\u65E0 sourcemap \u53CB\u597D\uFF09\u3002\u9ED8\u8BA4\u53EA\u8FD4\u56DE error \u7EA7\u522B\u7684\u6700\u8FD1 20 \u6761\u3002",
29028
+ description: "\u83B7\u53D6\u5F53\u524D\u6807\u7B7E\u6700\u8FD1\u7684\u63A7\u5236\u53F0\u3001\u5F02\u5E38\u548C\u7F51\u7EDC\u9519\u8BEF\u4E8B\u4EF6\u3002\u9ED8\u8BA4\u53EA\u8FD4\u56DE error\uFF1B\u5982\u9700\u67E5\u770B console.log / console.warn\uFF0C\u8BF7\u4F20 severity=info / warn / all\u3002",
28959
29029
  inputSchema: {
28960
29030
  type: "object",
28961
29031
  properties: {
@@ -28973,7 +29043,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
28973
29043
  },
28974
29044
  {
28975
29045
  name: "get_script_source",
28976
- description: "\u6293\u53D6\u76EE\u6807\u811A\u672C\u6E90\u7801\uFF08\u538B\u7F29\u7248\uFF09\uFF0C\u8FD4\u56DE\u5B9A\u4F4D\u7247\u6BB5\u4E0E\u53EF\u9009 beautify\uFF0C\u652F\u6301\u6309 URL \u7247\u6BB5\u7B5B\u9009",
29046
+ description: "\u6293\u53D6\u76EE\u6807\u811A\u672C\u6E90\u7801\u7247\u6BB5\uFF0C\u652F\u6301\u6309 URL \u7247\u6BB5\u7B5B\u9009\u548C\u53EF\u9009 beautify\u3002",
28977
29047
  inputSchema: {
28978
29048
  type: "object",
28979
29049
  properties: {
@@ -28997,7 +29067,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
28997
29067
  },
28998
29068
  {
28999
29069
  name: "find_by_string",
29000
- description: "\u5728\u5F53\u524D\u9875\u9762\u811A\u672C\u5185\u6309\u5B57\u7B26\u4E32\u641C\u7D22\uFF0C\u8FD4\u56DE\u5339\u914D\u7684\u4E0A\u4E0B\u6587\u7247\u6BB5\uFF08\u7528\u4E8E\u538B\u7F29\u4EE3\u7801\u5B9A\u4F4D\uFF09",
29070
+ description: "\u5728\u5F53\u524D\u9875\u9762\u811A\u672C\u5185\u6309\u5B57\u7B26\u4E32\u641C\u7D22\uFF0C\u8FD4\u56DE\u5339\u914D\u4E0A\u4E0B\u6587\u3002",
29001
29071
  inputSchema: {
29002
29072
  type: "object",
29003
29073
  properties: {
@@ -29024,7 +29094,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29024
29094
  },
29025
29095
  {
29026
29096
  name: "list_network_requests",
29027
- description: "\u5217\u51FA\u6355\u83B7\u7684\u7F51\u7EDC\u8BF7\u6C42\uFF0C\u652F\u6301\u6309 URL\u3001\u65B9\u6CD5\u3001\u72B6\u6001\u3001\u7C7B\u578B\u8FC7\u6EE4\u3002\u9ED8\u8BA4\u6309\u6392\u969C\u4F18\u5148\u7EA7\u6392\u5E8F\uFF1A\u5931\u8D25\u8BF7\u6C42\u3001\u8FDB\u884C\u4E2D\u8BF7\u6C42\u3001XHR/Fetch \u4F1A\u4F18\u5148\u5C55\u793A\u3002\u4E3A\u907F\u514D\u4E0A\u4E0B\u6587\u81A8\u80C0\uFF0Cdata URL \u548C\u8D85\u957F URL \u4F1A\u81EA\u52A8\u6458\u8981\u5316\u3002",
29097
+ description: "\u5217\u51FA\u6355\u83B7\u7684\u7F51\u7EDC\u8BF7\u6C42\uFF0C\u652F\u6301\u6309 URL\u3001\u65B9\u6CD5\u3001\u72B6\u6001\u548C\u7C7B\u578B\u8FC7\u6EE4\u3002\u9ED8\u8BA4\u6309\u6392\u969C\u4F18\u5148\u7EA7\u6392\u5E8F\uFF1Bdata URL \u548C\u8D85\u957F URL \u4F1A\u81EA\u52A8\u6458\u8981\u5316\u3002",
29028
29098
  inputSchema: {
29029
29099
  type: "object",
29030
29100
  properties: {
@@ -29043,7 +29113,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29043
29113
  },
29044
29114
  {
29045
29115
  name: "get_network_detail",
29046
- description: "\u83B7\u53D6\u5355\u4E2A\u7F51\u7EDC\u8BF7\u6C42\u7684\u8BE6\u7EC6\u4FE1\u606F\uFF0C\u5305\u62EC\u8BF7\u6C42\u5934\u3001\u54CD\u5E94\u5934\uFF0C\u53EF\u9009\u83B7\u53D6\u54CD\u5E94\u4F53\u3002\u4E3A\u907F\u514D\u4E0A\u4E0B\u6587\u81A8\u80C0\uFF0Cdata URL \u548C\u8D85\u957F URL \u4F1A\u81EA\u52A8\u6458\u8981\u5316\u3002",
29116
+ description: "\u83B7\u53D6\u5355\u4E2A\u7F51\u7EDC\u8BF7\u6C42\u8BE6\u60C5\uFF0C\u5305\u62EC\u8BF7\u6C42\u5934\u3001\u54CD\u5E94\u5934\u548C\u53EF\u9009\u54CD\u5E94\u4F53\uFF1B\u8D85\u957F URL \u4F1A\u81EA\u52A8\u6458\u8981\u5316\u3002",
29047
29117
  inputSchema: {
29048
29118
  type: "object",
29049
29119
  properties: {
@@ -29060,7 +29130,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29060
29130
  },
29061
29131
  {
29062
29132
  name: "perf_metrics",
29063
- description: "\u83B7\u53D6\u9875\u9762\u6027\u80FD\u6307\u6807\uFF1A\u5305\u542B\u5F15\u64CE\u7EA7\u6307\u6807\uFF08JS\u5806\u5185\u5B58\u3001DOM\u8282\u70B9\u6570\u3001Layout\u6B21\u6570\u3001\u811A\u672C\u6267\u884C\u65F6\u95F4\uFF09\u3001Web Vitals\uFF08FCP\u3001TTFB\u3001DOMContentLoaded\u3001Long Tasks\uFF09\u548C\u8D44\u6E90\u52A0\u8F7D\u6458\u8981\u3002\u7528\u4E8E\u8BCA\u65AD\u9875\u9762\u5361\u987F\u3001\u5185\u5B58\u5360\u7528\u8FC7\u9AD8\u3001\u52A0\u8F7D\u7F13\u6162\u7B49\u6027\u80FD\u95EE\u9898\u3002",
29133
+ description: "\u83B7\u53D6\u9875\u9762\u6027\u80FD\u6307\u6807\uFF0C\u5305\u62EC\u5F15\u64CE\u7EA7\u6307\u6807\u3001Web Vitals \u548C\u8D44\u6E90\u52A0\u8F7D\u6458\u8981\u3002",
29064
29134
  inputSchema: {
29065
29135
  type: "object",
29066
29136
  properties: {
@@ -29077,7 +29147,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29077
29147
  },
29078
29148
  {
29079
29149
  name: "capture_screenshot",
29080
- description: "\u3010\u63A8\u8350\u7528\u4E8E\u89C6\u89C9\u5206\u6790\u3011\u622A\u53D6\u5F53\u524D\u9875\u9762\u7684\u622A\u56FE\uFF0C\u8FD4\u56DE base64 \u56FE\u7247\u3002\u9002\u7528\u4E8E\uFF1A1) \u67E5\u770B\u9875\u9762\u5B9E\u9645\u89C6\u89C9\u6548\u679C 2) \u6392\u67E5 UI/\u6837\u5F0F/\u5E03\u5C40/\u989C\u8272\u95EE\u9898 3) \u9A8C\u8BC1\u9875\u9762\u6E32\u67D3 4) \u5206\u6790\u5143\u7D20\u4F4D\u7F6E\u548C\u95F4\u8DDD 5) \u67E5\u770B\u56FE\u7247/\u56FE\u6807\u7B49\u89C6\u89C9\u5185\u5BB9\u3002\u5F53\u7528\u6237\u8BF4\u201C\u770B\u770B\u8FD9\u4E2A\u9875\u9762\u957F\u4EC0\u4E48\u6837\u201D\u201C\u5E2E\u6211\u5206\u6790\u754C\u9762/\u5E03\u5C40/\u6837\u5F0F\u201D\u65F6\uFF0C\u5E94\u4F18\u5148\u4F7F\u7528\u6B64\u5DE5\u5177\uFF0C\u65E0\u9700\u7528\u6237\u663E\u5F0F\u63D0\u5230 ghost-bridge\u3002\u5F53\u9700\u8981\u770B\u5230\u9875\u9762\u300C\u957F\u4EC0\u4E48\u6837\u300D\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177\u3002\u9ED8\u8BA4\u4F18\u5148\u4F7F\u7528\u66F4\u7701\u4F20\u8F93\u7684 JPEG\uFF1A\u666E\u901A\u622A\u56FE\u9ED8\u8BA4 quality 80\uFF0C\u5B8C\u6574\u957F\u622A\u56FE\u9ED8\u8BA4 quality 70\u3002\u5F53\u9700\u8981\u68C0\u67E5\u6587\u5B57\u6E05\u6670\u5EA6\u30011px \u7EC6\u7EBF\u3001\u56FE\u6807\u8FB9\u7F18\u3001\u900F\u660E\u80CC\u666F\u6216\u50CF\u7D20\u7EA7\u7EC6\u8282\u65F6\uFF0C\u5E94\u4F18\u5148\u4F7F\u7528 PNG\u3002\u5982\u4EC5\u9700\u6587\u672C/\u94FE\u63A5\u7B49\u4FE1\u606F\uFF0C\u5EFA\u8BAE\u4F7F\u7528\u66F4\u5FEB\u7684 get_page_content\u3002",
29150
+ description: "\u622A\u53D6\u5F53\u524D\u9875\u9762\u622A\u56FE\uFF0C\u9002\u5408\u770B\u9875\u9762\u5B9E\u9645\u89C6\u89C9\u6548\u679C\u3001UI \u6837\u5F0F\u548C\u5E03\u5C40\u3002\u9ED8\u8BA4\u4F18\u5148\u4F7F\u7528 JPEG\uFF1B\u9700\u8981\u6587\u5B57\u3001\u7EC6\u7EBF\u6216\u900F\u660E\u80CC\u666F\u7EC6\u8282\u65F6\u6539\u7528 PNG\u3002",
29081
29151
  inputSchema: {
29082
29152
  type: "object",
29083
29153
  properties: {
@@ -29109,7 +29179,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29109
29179
  },
29110
29180
  {
29111
29181
  name: "get_page_content",
29112
- description: "\u3010\u63A8\u8350\u7528\u4E8E\u5FEB\u901F\u83B7\u53D6\u9875\u9762\u5185\u5BB9\u3011\u63D0\u53D6\u5F53\u524D\u9875\u9762\u7684\u6587\u672C\u3001HTML \u6216\u7ED3\u6784\u5316\u6570\u636E\u3002\u6BD4 capture_screenshot \u66F4\u5FEB\u66F4\u8F7B\u91CF\uFF0C\u9002\u7528\u4E8E\uFF1A1) \u83B7\u53D6\u9875\u9762\u6587\u5B57\u5185\u5BB9 2) \u63D0\u53D6\u94FE\u63A5/\u6309\u94AE/\u8868\u5355\u7B49\u5143\u7D20 3) \u5206\u6790 DOM \u7ED3\u6784 4) \u83B7\u53D6\u9875\u9762\u5143\u6570\u636E\uFF08title/description\uFF09\u3002\u5F53\u7528\u6237\u8BF4\u201C\u5206\u6790\u8FD9\u4E2A\u9875\u9762/\u7F51\u7AD9\u201D\u201C\u770B\u770B\u9875\u9762\u91CC\u6709\u4EC0\u4E48\u5185\u5BB9\u201D\u4E14\u4E0D\u5F3A\u8C03\u89C6\u89C9\u6548\u679C\u65F6\uFF0C\u4F18\u5148\u4F7F\u7528\u6B64\u5DE5\u5177\uFF0C\u65E0\u9700\u7528\u6237\u663E\u5F0F\u63D0\u5230 ghost-bridge\u3002\u5F53\u9700\u8981\u6587\u672C\u4FE1\u606F\u800C\u975E\u89C6\u89C9\u6548\u679C\u65F6\uFF0C\u4F18\u5148\u4F7F\u7528\u6B64\u5DE5\u5177\u3002\u6CE8\u610F\uFF1A\u4E0D\u652F\u6301 iframe \u5185\u5BB9\uFF0C\u4E0D\u53CD\u6620 CSS \u6837\u5F0F\u3002",
29182
+ description: "\u63D0\u53D6\u5F53\u524D\u9875\u9762\u7684\u6587\u672C\u3001HTML \u6216\u7ED3\u6784\u5316\u6570\u636E\u3002\u6BD4\u622A\u56FE\u66F4\u8F7B\u91CF\uFF0C\u9002\u5408\u5148\u770B\u6587\u5B57\u3001DOM \u7ED3\u6784\u548C\u9875\u9762\u5143\u6570\u636E\uFF1B\u4E0D\u53CD\u6620 CSS\uFF0C\u4E5F\u4E0D\u542B iframe \u5185\u5BB9\u3002",
29113
29183
  inputSchema: {
29114
29184
  type: "object",
29115
29185
  properties: {
@@ -29135,7 +29205,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29135
29205
  },
29136
29206
  {
29137
29207
  name: "get_interactive_snapshot",
29138
- description: "\u3010\u64CD\u4F5C\u9875\u9762\u524D\u5FC5\u987B\u5148\u8C03\u7528\u3011\u626B\u63CF\u5F53\u524D\u9875\u9762\u6240\u6709\u53EF\u89C1\u7684\u53EF\u4EA4\u4E92\u5143\u7D20\uFF08\u6309\u94AE/\u94FE\u63A5/\u8F93\u5165\u6846/\u4E0B\u62C9\u6846\u7B49\uFF09\uFF0C\u8FD4\u56DE\u5E26\u6709 ref \u77ED\u6807\u8BC6\uFF08\u5982 e1, e2, e3\uFF09\u7684\u7CBE\u7B80\u5217\u8868\uFF0C\u5305\u542B\u5143\u7D20\u7C7B\u578B\u3001\u6587\u672C\u548C\u4F4D\u7F6E\u3002Token \u6781\u7701\uFF08\u901A\u5E38 < 1000 tokens\uFF09\uFF0C\u4E13\u4E3A AI \u64CD\u4F5C\u9875\u9762\u800C\u8BBE\u8BA1\u3002\u5F53\u7528\u6237\u8981\u6C42\u70B9\u51FB\u3001\u8F93\u5165\u3001\u767B\u5F55\u3001\u63D0\u4EA4\u8868\u5355\u3001\u6253\u5F00\u83DC\u5355\u7B49\u64CD\u4F5C\u65F6\uFF0C\u5E94\u4E3B\u52A8\u4F7F\u7528\u6B64\u5DE5\u5177\u5F00\u59CB\u5B9A\u4F4D\u5143\u7D20\uFF0C\u65E0\u9700\u7528\u6237\u663E\u5F0F\u63D0\u5230 ghost-bridge\u3002\u83B7\u53D6\u540E\u53EF\u901A\u8FC7 dispatch_action \u5DE5\u5177\u4F7F\u7528 ref \u6807\u8BC6\u6765\u70B9\u51FB\u3001\u586B\u5199\u3001\u6309\u952E\u7B49\u3002\u652F\u6301 Shadow DOM \u7A7F\u900F\u3002\n\u26A0\uFE0F \u4EC5\u7528\u4E8E\u4EA4\u4E92\u64CD\u4F5C\u524D\u7684\u5143\u7D20\u5B9A\u4F4D\u3002\u5982\u9700\u6392\u67E5 UI/CSS \u5E03\u5C40\u95EE\u9898\uFF0C\u8BF7\u4F7F\u7528 capture_screenshot \u6216 get_page_content\u3002",
29208
+ description: "\u626B\u63CF\u5F53\u524D\u9875\u9762\u53EF\u89C1\u7684\u53EF\u4EA4\u4E92\u5143\u7D20\uFF0C\u8FD4\u56DE\u5E26 ref \u7684\u7CBE\u7B80\u5217\u8868\uFF0C\u4F9B\u540E\u7EED dispatch_action \u4F7F\u7528\u3002\u652F\u6301 Shadow DOM\uFF1B\u4EC5\u7528\u4E8E\u4EA4\u4E92\u5B9A\u4F4D\u3002",
29139
29209
  inputSchema: {
29140
29210
  type: "object",
29141
29211
  properties: {
@@ -29156,7 +29226,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29156
29226
  },
29157
29227
  {
29158
29228
  name: "dispatch_action",
29159
- description: "\u3010\u64CD\u4F5C\u9875\u9762\u5143\u7D20\u3011\u5BF9 get_interactive_snapshot \u8FD4\u56DE\u7684\u5143\u7D20\u6267\u884C\u52A8\u4F5C\u3002\u901A\u8FC7 ref \u6807\u8BC6\uFF08\u5982 e1, e5\uFF09\u7CBE\u51C6\u5B9A\u4F4D\u5143\u7D20\uFF0C\u4F7F\u7528 CDP \u7269\u7406\u7EA7\u6A21\u62DF\u6267\u884C\u64CD\u4F5C\uFF0C\u517C\u5BB9\u6240\u6709\u524D\u7AEF\u6846\u67B6\uFF08React/Vue/Angular\uFF09\uFF0C\u6210\u529F\u7387\u6781\u9AD8\u3002\n\u5F53\u7528\u6237\u660E\u786E\u5E0C\u671B\u5728\u9875\u9762\u4E0A\u6267\u884C\u70B9\u51FB\u3001\u8F93\u5165\u3001\u56DE\u8F66\u3001\u6EDA\u52A8\u3001\u9009\u62E9\u7B49\u64CD\u4F5C\u65F6\uFF0C\u5E94\u7ED3\u5408 get_interactive_snapshot \u4E3B\u52A8\u4F7F\u7528\u6B64\u5DE5\u5177\uFF0C\u65E0\u9700\u7528\u6237\u663E\u5F0F\u63D0\u5230 ghost-bridge\u3002\n\u652F\u6301\u7684\u52A8\u4F5C\uFF1Aclick\uFF08\u70B9\u51FB\uFF09\u3001fill\uFF08\u586B\u5199\u8F93\u5165\u6846\uFF09\u3001press\uFF08\u6309\u952E\u5982 Enter\uFF09\u3001scroll\uFF08\u6EDA\u52A8\uFF09\u3001select\uFF08\u4E0B\u62C9\u9009\u62E9\uFF09\u3001hover\uFF08\u60AC\u505C\uFF09\u3001focus\uFF08\u805A\u7126\uFF09\u3002\n\u26A0\uFE0F \u4F7F\u7528\u524D\u5FC5\u987B\u5148\u8C03\u7528 get_interactive_snapshot \u83B7\u53D6\u5143\u7D20\u5217\u8868\u3002\u64CD\u4F5C\u540E\u5EFA\u8BAE\u7528 capture_screenshot \u6216\u518D\u6B21 get_interactive_snapshot \u9A8C\u8BC1\u7ED3\u679C\u3002",
29229
+ description: "\u5BF9 get_interactive_snapshot \u8FD4\u56DE\u7684\u5143\u7D20\u6267\u884C\u70B9\u51FB\u3001\u8F93\u5165\u3001\u6309\u952E\u3001\u6EDA\u52A8\u3001\u9009\u62E9\u3001\u60AC\u505C\u6216\u805A\u7126\u3002\u26A0\uFE0F \u4F7F\u7528\u524D\u5FC5\u987B\u5148\u8C03\u7528 get_interactive_snapshot \u83B7\u53D6 ref\uFF1B\u64CD\u4F5C\u540E\u5EFA\u8BAE\u518D\u9A8C\u8BC1\u9875\u9762\u72B6\u6001\u3002",
29160
29230
  inputSchema: {
29161
29231
  type: "object",
29162
29232
  properties: {