ghost-bridge 0.7.1 → 0.9.0
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 +32 -1
- package/dist/cli.js +266 -140
- package/dist/server.js +288 -69
- package/extension/background.js +692 -224
- package/extension/manifest.json +3 -2
- package/extension/offscreen.js +211 -29
- package/extension/popup.html +72 -54
- package/extension/popup.js +72 -42
- package/package.json +4 -4
package/dist/server.js
CHANGED
|
@@ -28523,6 +28523,7 @@ import net from "net";
|
|
|
28523
28523
|
import fs2 from "fs";
|
|
28524
28524
|
import os from "os";
|
|
28525
28525
|
import path2 from "path";
|
|
28526
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
28526
28527
|
|
|
28527
28528
|
// lib/version.js
|
|
28528
28529
|
import fs from "fs";
|
|
@@ -28541,15 +28542,43 @@ var WS_TOKEN = process.env.GHOST_BRIDGE_TOKEN || DEFAULT_WS_TOKEN;
|
|
|
28541
28542
|
var RESPONSE_TIMEOUT = 8e3;
|
|
28542
28543
|
var PORT_INFO_FILE = path2.join(os.tmpdir(), "ghost-bridge-port.json");
|
|
28543
28544
|
var SERVER_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
28545
|
+
var SERVER_ENTRY_PATH = fileURLToPath2(import.meta.url);
|
|
28544
28546
|
var chromeConnection = null;
|
|
28545
28547
|
var activeConnection = null;
|
|
28546
28548
|
var actualPort = BASE_PORT;
|
|
28547
28549
|
var isMainInstance = false;
|
|
28548
28550
|
var pendingRequests = /* @__PURE__ */ new Map();
|
|
28549
28551
|
var mcpClients = /* @__PURE__ */ new Set();
|
|
28552
|
+
var mcpClientSeq = 0;
|
|
28553
|
+
var LOCAL_CLIENT_ID = "local";
|
|
28550
28554
|
function log(msg) {
|
|
28551
28555
|
console.error(`[ghost-bridge] ${msg}`);
|
|
28552
28556
|
}
|
|
28557
|
+
function buildIdentityPayload() {
|
|
28558
|
+
return {
|
|
28559
|
+
type: "identity",
|
|
28560
|
+
service: "ghost-bridge",
|
|
28561
|
+
token: WS_TOKEN,
|
|
28562
|
+
pid: process.pid,
|
|
28563
|
+
port: actualPort,
|
|
28564
|
+
version: GHOST_BRIDGE_VERSION,
|
|
28565
|
+
serverPath: SERVER_ENTRY_PATH,
|
|
28566
|
+
startedAt: SERVER_STARTED_AT,
|
|
28567
|
+
capabilities: ["heartbeat"]
|
|
28568
|
+
};
|
|
28569
|
+
}
|
|
28570
|
+
function getServiceMismatch(probe) {
|
|
28571
|
+
if (!probe || probe.service !== "ghost-bridge") return null;
|
|
28572
|
+
if (!probe.version) return "\u65E7\u670D\u52A1\u7F3A\u5C11\u7248\u672C\u5143\u6570\u636E";
|
|
28573
|
+
if (probe.version !== GHOST_BRIDGE_VERSION) {
|
|
28574
|
+
return `\u7248\u672C\u4E0D\u4E00\u81F4\uFF08\u65E7: ${probe.version}, \u65B0: ${GHOST_BRIDGE_VERSION}\uFF09`;
|
|
28575
|
+
}
|
|
28576
|
+
if (!probe.serverPath) return "\u65E7\u670D\u52A1\u7F3A\u5C11\u8DEF\u5F84\u5143\u6570\u636E";
|
|
28577
|
+
if (path2.resolve(probe.serverPath) !== path2.resolve(SERVER_ENTRY_PATH)) {
|
|
28578
|
+
return `\u8DEF\u5F84\u4E0D\u4E00\u81F4\uFF08\u65E7: ${probe.serverPath}, \u65B0: ${SERVER_ENTRY_PATH}\uFF09`;
|
|
28579
|
+
}
|
|
28580
|
+
return null;
|
|
28581
|
+
}
|
|
28553
28582
|
function isProcessRunning(pid) {
|
|
28554
28583
|
try {
|
|
28555
28584
|
process.kill(pid, 0);
|
|
@@ -28628,11 +28657,11 @@ async function waitForPortAvailable(port, timeoutMs = 5e3) {
|
|
|
28628
28657
|
}
|
|
28629
28658
|
return isPortAvailable(port);
|
|
28630
28659
|
}
|
|
28631
|
-
async function stopExistingService(pid, port) {
|
|
28660
|
+
async function stopExistingService(pid, port, reason = "\u9700\u8981\u7531\u65B0\u5B9E\u4F8B\u63A5\u7BA1") {
|
|
28632
28661
|
if (!pid || pid === process.pid) {
|
|
28633
28662
|
return false;
|
|
28634
28663
|
}
|
|
28635
|
-
log(`\u68C0\u6D4B\u5230\u65E7\u5B9E\u4F8B
|
|
28664
|
+
log(`\u68C0\u6D4B\u5230\u65E7\u5B9E\u4F8B\u9700\u8981\u66FF\u6362\uFF1A${reason}\uFF0C\u51C6\u5907\u505C\u6B62\u65E7\u5B9E\u4F8B (PID: ${pid})`);
|
|
28636
28665
|
try {
|
|
28637
28666
|
process.kill(pid, "SIGTERM");
|
|
28638
28667
|
} catch (e) {
|
|
@@ -28686,13 +28715,18 @@ async function initWebSocketService() {
|
|
|
28686
28715
|
const probe = await probeExistingService(existing.port);
|
|
28687
28716
|
if (probe?.service === "ghost-bridge") {
|
|
28688
28717
|
if (probe.token === WS_TOKEN) {
|
|
28689
|
-
|
|
28690
|
-
|
|
28691
|
-
|
|
28692
|
-
|
|
28718
|
+
const mismatch = getServiceMismatch(probe);
|
|
28719
|
+
if (!mismatch) {
|
|
28720
|
+
actualPort = existing.port;
|
|
28721
|
+
isMainInstance = false;
|
|
28722
|
+
log(`\u2705 \u590D\u7528\u73B0\u6709\u670D\u52A1\uFF0C\u7AEF\u53E3 ${actualPort}`);
|
|
28723
|
+
return null;
|
|
28724
|
+
}
|
|
28725
|
+
await stopExistingService(Number(probe.pid) || existing.pid, existing.port, mismatch);
|
|
28726
|
+
} else {
|
|
28727
|
+
const oldPid = Number(probe.pid) || existing.pid;
|
|
28728
|
+
await stopExistingService(oldPid, existing.port, "token \u4E0D\u4E00\u81F4");
|
|
28693
28729
|
}
|
|
28694
|
-
const oldPid = Number(probe.pid) || existing.pid;
|
|
28695
|
-
await stopExistingService(oldPid, existing.port);
|
|
28696
28730
|
} else {
|
|
28697
28731
|
log(`\u274C \u73B0\u6709\u670D\u52A1\u9A8C\u8BC1\u5931\u8D25\uFF0C\u542F\u52A8\u65B0\u670D\u52A1...`);
|
|
28698
28732
|
try {
|
|
@@ -28705,12 +28739,17 @@ async function initWebSocketService() {
|
|
|
28705
28739
|
const probe = await probeExistingService(BASE_PORT);
|
|
28706
28740
|
if (probe?.service === "ghost-bridge") {
|
|
28707
28741
|
if (probe.token === WS_TOKEN) {
|
|
28708
|
-
|
|
28709
|
-
|
|
28710
|
-
|
|
28711
|
-
|
|
28742
|
+
const mismatch = getServiceMismatch(probe);
|
|
28743
|
+
if (!mismatch) {
|
|
28744
|
+
actualPort = BASE_PORT;
|
|
28745
|
+
isMainInstance = false;
|
|
28746
|
+
log(`\u2705 \u590D\u7528\u56FA\u5B9A\u7AEF\u53E3\u4E0A\u7684\u73B0\u6709\u670D\u52A1\uFF0C\u7AEF\u53E3 ${actualPort}`);
|
|
28747
|
+
return null;
|
|
28748
|
+
}
|
|
28749
|
+
await stopExistingService(Number(probe.pid), BASE_PORT, mismatch);
|
|
28750
|
+
} else {
|
|
28751
|
+
await stopExistingService(Number(probe.pid), BASE_PORT, "token \u4E0D\u4E00\u81F4");
|
|
28712
28752
|
}
|
|
28713
|
-
await stopExistingService(Number(probe.pid), BASE_PORT);
|
|
28714
28753
|
}
|
|
28715
28754
|
if (!await isPortAvailable(BASE_PORT)) {
|
|
28716
28755
|
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`);
|
|
@@ -28724,6 +28763,8 @@ async function initWebSocketService() {
|
|
|
28724
28763
|
port: actualPort,
|
|
28725
28764
|
wsUrl: `ws://localhost:${actualPort}`,
|
|
28726
28765
|
pid: process.pid,
|
|
28766
|
+
version: GHOST_BRIDGE_VERSION,
|
|
28767
|
+
serverPath: SERVER_ENTRY_PATH,
|
|
28727
28768
|
startedAt: SERVER_STARTED_AT
|
|
28728
28769
|
}, null, 2)
|
|
28729
28770
|
);
|
|
@@ -28731,20 +28772,19 @@ async function initWebSocketService() {
|
|
|
28731
28772
|
return wss2;
|
|
28732
28773
|
}
|
|
28733
28774
|
var wss = await initWebSocketService();
|
|
28775
|
+
var wsPingInterval = null;
|
|
28776
|
+
var WS_PING_INTERVAL_MS = 3e4;
|
|
28734
28777
|
if (wss) {
|
|
28735
28778
|
wss.on("connection", (ws, req) => {
|
|
28779
|
+
ws.isAlive = true;
|
|
28780
|
+
ws.on("pong", () => {
|
|
28781
|
+
ws.isAlive = true;
|
|
28782
|
+
});
|
|
28736
28783
|
const url2 = new URL(req.url || "/", "http://localhost");
|
|
28737
28784
|
const token = url2.searchParams.get("token") || "";
|
|
28738
28785
|
const role = url2.searchParams.get("role") || "";
|
|
28739
28786
|
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
|
-
}));
|
|
28787
|
+
ws.send(JSON.stringify(buildIdentityPayload()));
|
|
28748
28788
|
ws.close(1e3, "Probe complete");
|
|
28749
28789
|
return;
|
|
28750
28790
|
}
|
|
@@ -28755,9 +28795,11 @@ if (wss) {
|
|
|
28755
28795
|
}
|
|
28756
28796
|
log(`\u8FDE\u63A5\u9A8C\u8BC1\u901A\u8FC7 (token: ${token})`);
|
|
28757
28797
|
if (role === "mcp-client") {
|
|
28758
|
-
|
|
28798
|
+
const clientId = `c${++mcpClientSeq}`;
|
|
28799
|
+
ws.ghostClientId = clientId;
|
|
28800
|
+
log(`\u{1F4E1} MCP \u5BA2\u6237\u7AEF\u5DF2\u8FDE\u63A5 (${clientId})`);
|
|
28759
28801
|
mcpClients.add(ws);
|
|
28760
|
-
ws.send(JSON.stringify(
|
|
28802
|
+
ws.send(JSON.stringify(buildIdentityPayload()));
|
|
28761
28803
|
ws.on("message", (data) => {
|
|
28762
28804
|
try {
|
|
28763
28805
|
const msg = JSON.parse(data.toString());
|
|
@@ -28767,7 +28809,11 @@ if (wss) {
|
|
|
28767
28809
|
result: {
|
|
28768
28810
|
chromeConnected: !!chromeConnection,
|
|
28769
28811
|
mcpClientsCount: mcpClients.size,
|
|
28770
|
-
port: actualPort
|
|
28812
|
+
port: actualPort,
|
|
28813
|
+
version: GHOST_BRIDGE_VERSION,
|
|
28814
|
+
serverPath: SERVER_ENTRY_PATH,
|
|
28815
|
+
pid: process.pid,
|
|
28816
|
+
startedAt: SERVER_STARTED_AT
|
|
28771
28817
|
}
|
|
28772
28818
|
}));
|
|
28773
28819
|
return;
|
|
@@ -28779,15 +28825,26 @@ if (wss) {
|
|
|
28779
28825
|
return;
|
|
28780
28826
|
}
|
|
28781
28827
|
if (msg.id) {
|
|
28782
|
-
|
|
28828
|
+
const wireId = `${clientId}:${msg.id}`;
|
|
28829
|
+
pendingRequests.set(wireId, { source: ws, originalId: msg.id });
|
|
28830
|
+
chromeConnection.send(JSON.stringify({
|
|
28831
|
+
id: wireId,
|
|
28832
|
+
command: msg.command,
|
|
28833
|
+
params: msg.params,
|
|
28834
|
+
clientId,
|
|
28835
|
+
...WS_TOKEN ? { token: WS_TOKEN } : {}
|
|
28836
|
+
}));
|
|
28837
|
+
} else {
|
|
28838
|
+
chromeConnection.send(data);
|
|
28783
28839
|
}
|
|
28784
|
-
chromeConnection.send(data);
|
|
28785
28840
|
} catch {
|
|
28786
28841
|
}
|
|
28787
28842
|
});
|
|
28788
28843
|
ws.on("close", () => {
|
|
28789
|
-
log(
|
|
28844
|
+
log(`\u{1F4E1} MCP \u5BA2\u6237\u7AEF\u5DF2\u65AD\u5F00 (${ws.ghostClientId})`);
|
|
28790
28845
|
mcpClients.delete(ws);
|
|
28846
|
+
askChrome("_clientDisconnected", { clientId: ws.ghostClientId }, { timeoutMs: 3e3 }).catch(() => {
|
|
28847
|
+
});
|
|
28791
28848
|
});
|
|
28792
28849
|
} else {
|
|
28793
28850
|
if (chromeConnection && chromeConnection !== ws && chromeConnection.readyState === import_websocket.default.OPEN) {
|
|
@@ -28801,15 +28858,21 @@ if (wss) {
|
|
|
28801
28858
|
log("\u{1F310} Chrome \u6269\u5C55\u5DF2\u8FDE\u63A5");
|
|
28802
28859
|
chromeConnection = ws;
|
|
28803
28860
|
activeConnection = ws;
|
|
28804
|
-
ws.send(JSON.stringify(
|
|
28861
|
+
ws.send(JSON.stringify(buildIdentityPayload()));
|
|
28805
28862
|
ws.on("message", (data) => {
|
|
28806
28863
|
try {
|
|
28807
28864
|
const msg = JSON.parse(data.toString());
|
|
28865
|
+
if (msg.type === "heartbeat") {
|
|
28866
|
+
ws.send(JSON.stringify({ type: "heartbeat_ack", ts: msg.ts || Date.now() }));
|
|
28867
|
+
return;
|
|
28868
|
+
}
|
|
28808
28869
|
if (msg.id && pendingRequests.has(msg.id)) {
|
|
28809
28870
|
const pending = pendingRequests.get(msg.id);
|
|
28810
|
-
if (pending.source
|
|
28871
|
+
if (pending.source) {
|
|
28811
28872
|
pendingRequests.delete(msg.id);
|
|
28812
|
-
pending.source.
|
|
28873
|
+
if (pending.source.readyState === import_websocket.default.OPEN) {
|
|
28874
|
+
pending.source.send(JSON.stringify({ ...msg, id: pending.originalId }));
|
|
28875
|
+
}
|
|
28813
28876
|
return;
|
|
28814
28877
|
}
|
|
28815
28878
|
}
|
|
@@ -28817,14 +28880,38 @@ if (wss) {
|
|
|
28817
28880
|
}
|
|
28818
28881
|
handleIncoming(data);
|
|
28819
28882
|
});
|
|
28820
|
-
ws.on("close", () => {
|
|
28821
|
-
|
|
28883
|
+
ws.on("close", (code, reason) => {
|
|
28884
|
+
const reasonText = reason ? reason.toString() : "";
|
|
28885
|
+
log(`\u{1F310} Chrome \u8FDE\u63A5\u5DF2\u5173\u95ED (code=${code}${reasonText ? ` reason="${reasonText}"` : ""})`);
|
|
28886
|
+
if (chromeConnection !== ws) {
|
|
28887
|
+
log("\u5FFD\u7565\u65E7 Chrome \u8FDE\u63A5\u7684\u5173\u95ED\u4E8B\u4EF6");
|
|
28888
|
+
return;
|
|
28889
|
+
}
|
|
28822
28890
|
chromeConnection = null;
|
|
28823
|
-
activeConnection
|
|
28891
|
+
if (activeConnection === ws) {
|
|
28892
|
+
activeConnection = null;
|
|
28893
|
+
}
|
|
28824
28894
|
failAllPending("Chrome \u8FDE\u63A5\u65AD\u5F00");
|
|
28825
28895
|
});
|
|
28896
|
+
ws.on("error", (err) => {
|
|
28897
|
+
log(`\u{1F310} Chrome \u8FDE\u63A5\u9519\u8BEF: ${err.message}`);
|
|
28898
|
+
});
|
|
28826
28899
|
}
|
|
28827
28900
|
});
|
|
28901
|
+
wsPingInterval = setInterval(() => {
|
|
28902
|
+
for (const client of wss.clients) {
|
|
28903
|
+
if (client.isAlive === false) {
|
|
28904
|
+
log("\u{1F310} \u5FC3\u8DF3\u8D85\u65F6\uFF0C\u4E3B\u52A8\u65AD\u5F00\u6B7B\u8FDE\u63A5");
|
|
28905
|
+
client.terminate();
|
|
28906
|
+
continue;
|
|
28907
|
+
}
|
|
28908
|
+
client.isAlive = false;
|
|
28909
|
+
try {
|
|
28910
|
+
client.ping();
|
|
28911
|
+
} catch {
|
|
28912
|
+
}
|
|
28913
|
+
}
|
|
28914
|
+
}, WS_PING_INTERVAL_MS);
|
|
28828
28915
|
} else {
|
|
28829
28916
|
log(`\u{1F4E1} \u4F5C\u4E3A\u5BA2\u6237\u7AEF\u8FDE\u63A5\u5230\u4E3B\u5B9E\u4F8B (\u7AEF\u53E3 ${actualPort})...`);
|
|
28830
28917
|
connectToMainInstance();
|
|
@@ -28935,7 +29022,7 @@ async function askMainInstance(command, params = {}) {
|
|
|
28935
29022
|
async function askChrome(command, params = {}, options = {}) {
|
|
28936
29023
|
if (!activeConnection) throw new Error("Chrome \u672A\u8FDE\u63A5\uFF0C\u8BF7\u786E\u8BA4\u6D4F\u89C8\u5668\u5F00\u542F\u4E14\u6269\u5C55\u5DF2\u542F\u7528");
|
|
28937
29024
|
const id = crypto.randomUUID();
|
|
28938
|
-
const payload = { id, command, params };
|
|
29025
|
+
const payload = { id, command, params, clientId: LOCAL_CLIENT_ID };
|
|
28939
29026
|
if (WS_TOKEN) payload.token = WS_TOKEN;
|
|
28940
29027
|
const timeoutMs = options.timeoutMs || RESPONSE_TIMEOUT;
|
|
28941
29028
|
return new Promise((resolve, reject) => {
|
|
@@ -28956,6 +29043,10 @@ async function askChrome(command, params = {}, options = {}) {
|
|
|
28956
29043
|
function jsonText(data) {
|
|
28957
29044
|
return typeof data === "string" ? data : JSON.stringify(data);
|
|
28958
29045
|
}
|
|
29046
|
+
var TARGET_ARG = {
|
|
29047
|
+
type: "string",
|
|
29048
|
+
description: "\u547D\u540D\u6D4F\u89C8\u5668\u76EE\u6807\uFF0C\u5982 cases/app\u3002\u5148\u7528 bind_tab \u7ED1\u5B9A\uFF1B\u4E0D\u6307\u5B9A\u5219\u4F7F\u7528\u9ED8\u8BA4 focused/pinned \u76EE\u6807\u3002\u7ED1\u5B9A\u4E0E pin \u5747\u6309\u4F1A\u8BDD\u9694\u79BB"
|
|
29049
|
+
};
|
|
28959
29050
|
function buildSnippet(source, line, column, { beautifyEnabled = true, contextLines = 20 } = {}) {
|
|
28960
29051
|
const result = {};
|
|
28961
29052
|
if (!source) {
|
|
@@ -29003,6 +29094,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29003
29094
|
inputSchema: {
|
|
29004
29095
|
type: "object",
|
|
29005
29096
|
properties: {
|
|
29097
|
+
target: TARGET_ARG,
|
|
29006
29098
|
selector: {
|
|
29007
29099
|
type: "string",
|
|
29008
29100
|
description: "CSS \u9009\u62E9\u5668\uFF0C\u9650\u5B9A\u5206\u6790\u8303\u56F4\u3002\u4E0D\u6307\u5B9A\u5219\u5206\u6790\u6574\u4E2A\u9875\u9762"
|
|
@@ -29023,12 +29115,75 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29023
29115
|
description: "\u83B7\u53D6 ghost-bridge \u670D\u52A1\u5668\u72B6\u6001\uFF0C\u5305\u62EC\u5F53\u524D WebSocket \u7AEF\u53E3\u3001\u8FDE\u63A5\u72B6\u6001\u7B49",
|
|
29024
29116
|
inputSchema: { type: "object", properties: {} }
|
|
29025
29117
|
},
|
|
29118
|
+
{
|
|
29119
|
+
name: "list_tabs",
|
|
29120
|
+
description: "\u5217\u51FA\u5F53\u524D Chrome \u6807\u7B7E\u9875\uFF0C\u5E76\u8FD4\u56DE Ghost Bridge \u5F53\u524D\u76EE\u6807\u6A21\u5F0F\u4E0E\u76EE\u6807\u6807\u7B7E\u9875\u3002",
|
|
29121
|
+
inputSchema: { type: "object", properties: {} }
|
|
29122
|
+
},
|
|
29123
|
+
{
|
|
29124
|
+
name: "bind_tab",
|
|
29125
|
+
description: "\u6309 tabId\u3001URL \u7247\u6BB5\u6216\u6807\u9898\u7247\u6BB5\u628A Chrome \u6807\u7B7E\u9875\u7ED1\u5B9A\u4E3A\u547D\u540D target\uFF0C\u4F8B\u5982 cases \u6216 app\u3002target \u547D\u540D\u7A7A\u95F4\u6309 MCP \u4F1A\u8BDD\u9694\u79BB\uFF1A\u591A\u4E2A Agent / \u540C\u4E00 Agent \u7684\u591A\u4E2A\u4F1A\u8BDD\u5404\u81EA\u7ED1\u5B9A\u7684 target\uFF08\u542B\u540C\u540D\uFF09\u4E92\u4E0D\u5E72\u6270\u3002",
|
|
29126
|
+
inputSchema: {
|
|
29127
|
+
type: "object",
|
|
29128
|
+
properties: {
|
|
29129
|
+
name: { type: "string", description: "target \u540D\u79F0\uFF0C\u5982 cases/app\u3002\u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u548C\u8FDE\u5B57\u7B26" },
|
|
29130
|
+
tabId: { type: "number", description: "Chrome \u6807\u7B7E\u9875 ID\uFF0C\u4F18\u5148\u4F7F\u7528" },
|
|
29131
|
+
urlContains: { type: "string", description: "URL \u7247\u6BB5\u3002\u672A\u63D0\u4F9B tabId \u65F6\u6309\u5B83\u5339\u914D" },
|
|
29132
|
+
titleContains: { type: "string", description: "\u6807\u9898\u7247\u6BB5\u3002\u53EF\u4E0E urlContains \u540C\u65F6\u4F7F\u7528" }
|
|
29133
|
+
},
|
|
29134
|
+
required: ["name"]
|
|
29135
|
+
}
|
|
29136
|
+
},
|
|
29137
|
+
{
|
|
29138
|
+
name: "unbind_tab",
|
|
29139
|
+
description: "\u89E3\u7ED1\u4E00\u4E2A\u547D\u540D target\u3002\u82E5\u8BE5 tab \u6CA1\u6709\u5176\u4ED6 target \u5F15\u7528\uFF0C\u4F1A\u91CA\u653E\u5BF9\u5E94 debugger session\u3002",
|
|
29140
|
+
inputSchema: {
|
|
29141
|
+
type: "object",
|
|
29142
|
+
properties: {
|
|
29143
|
+
name: { type: "string", description: "\u8981\u89E3\u7ED1\u7684 target \u540D\u79F0" }
|
|
29144
|
+
},
|
|
29145
|
+
required: ["name"]
|
|
29146
|
+
}
|
|
29147
|
+
},
|
|
29148
|
+
{
|
|
29149
|
+
name: "list_targets",
|
|
29150
|
+
description: "\u67E5\u770B\u5F53\u524D\u5DF2\u7ED1\u5B9A\u7684\u547D\u540D targets\uFF0C\u4EE5\u53CA\u9ED8\u8BA4 focused/pinned \u76EE\u6807\u72B6\u6001\u3002",
|
|
29151
|
+
inputSchema: { type: "object", properties: {} }
|
|
29152
|
+
},
|
|
29153
|
+
{
|
|
29154
|
+
name: "get_target_tab",
|
|
29155
|
+
description: "\u67E5\u770B Ghost Bridge \u5F53\u524D\u64CD\u4F5C\u76EE\u6807\u3002\u76EE\u6807\u6A21\u5F0F\u4E3A focused \u65F6\u8DDF\u968F\u5F53\u524D\u805A\u7126\u6807\u7B7E\u9875\uFF1Bpinned \u65F6\u9501\u5B9A\u6307\u5B9A\u6807\u7B7E\u9875\u3002",
|
|
29156
|
+
inputSchema: { type: "object", properties: {} }
|
|
29157
|
+
},
|
|
29158
|
+
{
|
|
29159
|
+
name: "pin_current_tab",
|
|
29160
|
+
description: "\u9501\u5B9A\u5F53\u524D\u805A\u7126\u7684 Chrome \u6807\u7B7E\u9875\u3002\u9501\u5B9A\u540E\u7528\u6237\u5207\u6362\u5230\u5176\u4ED6\u9875\u9762\u4E5F\u4E0D\u4F1A\u6539\u53D8 Ghost Bridge \u7684\u64CD\u4F5C\u76EE\u6807\u3002",
|
|
29161
|
+
inputSchema: { type: "object", properties: {} }
|
|
29162
|
+
},
|
|
29163
|
+
{
|
|
29164
|
+
name: "pin_tab",
|
|
29165
|
+
description: "\u6309 tabId\u3001URL \u7247\u6BB5\u6216\u6807\u9898\u7247\u6BB5\u9501\u5B9A Chrome \u6807\u7B7E\u9875\u3002pin \u72B6\u6001\u6309 MCP \u4F1A\u8BDD\u9694\u79BB\uFF1A\u591A\u4E2A Agent / \u591A\u4E2A\u4F1A\u8BDD\u5404\u81EA pin \u7684\u9875\u9762\u4E92\u4E0D\u8986\u76D6\u3002",
|
|
29166
|
+
inputSchema: {
|
|
29167
|
+
type: "object",
|
|
29168
|
+
properties: {
|
|
29169
|
+
tabId: { type: "number", description: "Chrome \u6807\u7B7E\u9875 ID\uFF0C\u4F18\u5148\u4F7F\u7528" },
|
|
29170
|
+
urlContains: { type: "string", description: "URL \u7247\u6BB5\u3002\u672A\u63D0\u4F9B tabId \u65F6\u6309\u5B83\u5339\u914D" },
|
|
29171
|
+
titleContains: { type: "string", description: "\u6807\u9898\u7247\u6BB5\u3002\u53EF\u4E0E urlContains \u540C\u65F6\u4F7F\u7528" }
|
|
29172
|
+
}
|
|
29173
|
+
}
|
|
29174
|
+
},
|
|
29175
|
+
{
|
|
29176
|
+
name: "unpin_tab",
|
|
29177
|
+
description: "\u89E3\u9664\u9501\u5B9A\uFF0C\u6062\u590D\u8DDF\u968F\u5F53\u524D\u805A\u7126\u6807\u7B7E\u9875\u3002",
|
|
29178
|
+
inputSchema: { type: "object", properties: {} }
|
|
29179
|
+
},
|
|
29026
29180
|
{
|
|
29027
29181
|
name: "get_last_error",
|
|
29028
|
-
description: "\u83B7\u53D6\
|
|
29182
|
+
description: "\u83B7\u53D6\u76EE\u6807\u6807\u7B7E\u9875\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",
|
|
29029
29183
|
inputSchema: {
|
|
29030
29184
|
type: "object",
|
|
29031
29185
|
properties: {
|
|
29186
|
+
target: TARGET_ARG,
|
|
29032
29187
|
severity: {
|
|
29033
29188
|
type: "string",
|
|
29034
29189
|
enum: ["error", "warn", "info", "all"],
|
|
@@ -29043,10 +29198,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29043
29198
|
},
|
|
29044
29199
|
{
|
|
29045
29200
|
name: "get_script_source",
|
|
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",
|
|
29201
|
+
description: "\u6293\u53D6\u76EE\u6807\u6807\u7B7E\u9875\u7684\u811A\u672C\u6E90\u7801\u7247\u6BB5\uFF0C\u652F\u6301\u6309 URL \u7247\u6BB5\u7B5B\u9009\u548C\u53EF\u9009 beautify\u3002",
|
|
29047
29202
|
inputSchema: {
|
|
29048
29203
|
type: "object",
|
|
29049
29204
|
properties: {
|
|
29205
|
+
target: TARGET_ARG,
|
|
29050
29206
|
scriptUrlContains: { type: "string" },
|
|
29051
29207
|
line: { type: "number" },
|
|
29052
29208
|
column: { type: "number" },
|
|
@@ -29061,16 +29217,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29061
29217
|
inputSchema: {
|
|
29062
29218
|
type: "object",
|
|
29063
29219
|
properties: {
|
|
29220
|
+
target: TARGET_ARG,
|
|
29064
29221
|
durationMs: { type: "number", description: "\u9ED8\u8BA4 1500ms" }
|
|
29065
29222
|
}
|
|
29066
29223
|
}
|
|
29067
29224
|
},
|
|
29068
29225
|
{
|
|
29069
29226
|
name: "find_by_string",
|
|
29070
|
-
description: "\u5728\
|
|
29227
|
+
description: "\u5728\u76EE\u6807\u6807\u7B7E\u9875\u811A\u672C\u5185\u6309\u5B57\u7B26\u4E32\u641C\u7D22\uFF0C\u8FD4\u56DE\u5339\u914D\u4E0A\u4E0B\u6587\u3002",
|
|
29071
29228
|
inputSchema: {
|
|
29072
29229
|
type: "object",
|
|
29073
29230
|
properties: {
|
|
29231
|
+
target: TARGET_ARG,
|
|
29074
29232
|
query: { type: "string" },
|
|
29075
29233
|
scriptUrlContains: { type: "string" },
|
|
29076
29234
|
maxMatches: { type: "number" }
|
|
@@ -29081,23 +29239,24 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29081
29239
|
{
|
|
29082
29240
|
name: "symbolic_hints",
|
|
29083
29241
|
description: "\u6536\u96C6\u9875\u9762\u7684\u8D44\u6E90\u3001\u5168\u5C40\u7B26\u53F7\u4E0E UA/URL \u7EBF\u7D22\uFF0C\u5E2E\u52A9\u63A8\u65AD\u7248\u672C\u4E0E\u6A21\u5757\u5F52\u5C5E",
|
|
29084
|
-
inputSchema: { type: "object", properties: {} }
|
|
29242
|
+
inputSchema: { type: "object", properties: { target: TARGET_ARG } }
|
|
29085
29243
|
},
|
|
29086
29244
|
{
|
|
29087
29245
|
name: "eval_script",
|
|
29088
|
-
description: "\u5728\
|
|
29246
|
+
description: "\u5728\u76EE\u6807\u6807\u7B7E\u9875\u6267\u884C\u53EA\u8BFB JS \u8868\u8FBE\u5F0F\uFF08\u8C28\u614E\u4F7F\u7528\uFF09",
|
|
29089
29247
|
inputSchema: {
|
|
29090
29248
|
type: "object",
|
|
29091
|
-
properties: { code: { type: "string" } },
|
|
29249
|
+
properties: { target: TARGET_ARG, code: { type: "string" } },
|
|
29092
29250
|
required: ["code"]
|
|
29093
29251
|
}
|
|
29094
29252
|
},
|
|
29095
29253
|
{
|
|
29096
29254
|
name: "list_network_requests",
|
|
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",
|
|
29255
|
+
description: "\u5217\u51FA\u76EE\u6807\u6807\u7B7E\u9875\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",
|
|
29098
29256
|
inputSchema: {
|
|
29099
29257
|
type: "object",
|
|
29100
29258
|
properties: {
|
|
29259
|
+
target: TARGET_ARG,
|
|
29101
29260
|
filter: { type: "string", description: "URL \u5173\u952E\u8BCD\u8FC7\u6EE4" },
|
|
29102
29261
|
method: { type: "string", description: "\u8BF7\u6C42\u65B9\u6CD5\uFF1AGET/POST/PUT/DELETE \u7B49" },
|
|
29103
29262
|
status: { type: "string", description: "\u72B6\u6001\uFF1Asuccess/error/failed/pending" },
|
|
@@ -29117,6 +29276,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29117
29276
|
inputSchema: {
|
|
29118
29277
|
type: "object",
|
|
29119
29278
|
properties: {
|
|
29279
|
+
target: TARGET_ARG,
|
|
29120
29280
|
requestId: { type: "string", description: "\u8BF7\u6C42 ID\uFF08\u4ECE list_network_requests \u83B7\u53D6\uFF09" },
|
|
29121
29281
|
includeBody: { type: "boolean", description: "\u662F\u5426\u5305\u542B\u54CD\u5E94\u4F53\uFF0C\u9ED8\u8BA4 false" }
|
|
29122
29282
|
},
|
|
@@ -29126,7 +29286,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29126
29286
|
{
|
|
29127
29287
|
name: "clear_network_requests",
|
|
29128
29288
|
description: "\u6E05\u7A7A\u5DF2\u6355\u83B7\u7684\u7F51\u7EDC\u8BF7\u6C42\u8BB0\u5F55",
|
|
29129
|
-
inputSchema: { type: "object", properties: {} }
|
|
29289
|
+
inputSchema: { type: "object", properties: { target: TARGET_ARG } }
|
|
29130
29290
|
},
|
|
29131
29291
|
{
|
|
29132
29292
|
name: "perf_metrics",
|
|
@@ -29134,6 +29294,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29134
29294
|
inputSchema: {
|
|
29135
29295
|
type: "object",
|
|
29136
29296
|
properties: {
|
|
29297
|
+
target: TARGET_ARG,
|
|
29137
29298
|
includeTimings: {
|
|
29138
29299
|
type: "boolean",
|
|
29139
29300
|
description: "\u662F\u5426\u5305\u542B Navigation Timing \u548C Web Vitals\uFF0C\u9ED8\u8BA4 true"
|
|
@@ -29147,10 +29308,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29147
29308
|
},
|
|
29148
29309
|
{
|
|
29149
29310
|
name: "capture_screenshot",
|
|
29150
|
-
description: "\u622A\u53D6\
|
|
29311
|
+
description: "\u622A\u53D6\u76EE\u6807\u6807\u7B7E\u9875\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",
|
|
29151
29312
|
inputSchema: {
|
|
29152
29313
|
type: "object",
|
|
29153
29314
|
properties: {
|
|
29315
|
+
target: TARGET_ARG,
|
|
29154
29316
|
format: {
|
|
29155
29317
|
type: "string",
|
|
29156
29318
|
enum: ["png", "jpeg"],
|
|
@@ -29179,10 +29341,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29179
29341
|
},
|
|
29180
29342
|
{
|
|
29181
29343
|
name: "get_page_content",
|
|
29182
|
-
description: "\u63D0\u53D6\
|
|
29344
|
+
description: "\u63D0\u53D6\u76EE\u6807\u6807\u7B7E\u9875\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",
|
|
29183
29345
|
inputSchema: {
|
|
29184
29346
|
type: "object",
|
|
29185
29347
|
properties: {
|
|
29348
|
+
target: TARGET_ARG,
|
|
29186
29349
|
mode: {
|
|
29187
29350
|
type: "string",
|
|
29188
29351
|
enum: ["text", "html", "structured"],
|
|
@@ -29209,6 +29372,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29209
29372
|
inputSchema: {
|
|
29210
29373
|
type: "object",
|
|
29211
29374
|
properties: {
|
|
29375
|
+
target: TARGET_ARG,
|
|
29212
29376
|
selector: {
|
|
29213
29377
|
type: "string",
|
|
29214
29378
|
description: "CSS \u9009\u62E9\u5668\uFF0C\u9650\u5B9A\u626B\u63CF\u8303\u56F4\u3002\u4E0D\u6307\u5B9A\u5219\u626B\u63CF\u6574\u4E2A\u9875\u9762"
|
|
@@ -29230,6 +29394,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
29230
29394
|
inputSchema: {
|
|
29231
29395
|
type: "object",
|
|
29232
29396
|
properties: {
|
|
29397
|
+
target: TARGET_ARG,
|
|
29233
29398
|
ref: {
|
|
29234
29399
|
type: "string",
|
|
29235
29400
|
description: "\u76EE\u6807\u5143\u7D20\u7684 ref \u6807\u8BC6\uFF0C\u5982 'e1'\u3001'e5'\uFF08\u4ECE get_interactive_snapshot \u83B7\u53D6\uFF09"
|
|
@@ -29270,8 +29435,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
29270
29435
|
const args = request.params.arguments || {};
|
|
29271
29436
|
try {
|
|
29272
29437
|
if (name === "inspect_page") {
|
|
29273
|
-
const { selector, includeInteractive = true, maxElements = 30 } = args;
|
|
29438
|
+
const { target, selector, includeInteractive = true, maxElements = 30 } = args;
|
|
29274
29439
|
const snapshot = await askChrome("inspectPageSnapshot", {
|
|
29440
|
+
target,
|
|
29275
29441
|
selector,
|
|
29276
29442
|
includeInteractive,
|
|
29277
29443
|
maxElements
|
|
@@ -29305,13 +29471,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
29305
29471
|
};
|
|
29306
29472
|
}
|
|
29307
29473
|
if (name === "get_server_info") {
|
|
29308
|
-
let chromeOk, clientsCount;
|
|
29474
|
+
let chromeOk, clientsCount, mainStatus;
|
|
29309
29475
|
if (isMainInstance) {
|
|
29310
29476
|
chromeOk = !!chromeConnection;
|
|
29311
29477
|
clientsCount = mcpClients.size;
|
|
29478
|
+
mainStatus = {
|
|
29479
|
+
pid: process.pid,
|
|
29480
|
+
version: GHOST_BRIDGE_VERSION,
|
|
29481
|
+
serverPath: SERVER_ENTRY_PATH,
|
|
29482
|
+
startedAt: SERVER_STARTED_AT
|
|
29483
|
+
};
|
|
29312
29484
|
} else {
|
|
29313
29485
|
try {
|
|
29314
|
-
|
|
29486
|
+
mainStatus = await askMainInstance("_getMainStatus");
|
|
29315
29487
|
chromeOk = mainStatus.chromeConnected;
|
|
29316
29488
|
clientsCount = mainStatus.mcpClientsCount;
|
|
29317
29489
|
} catch {
|
|
@@ -29330,6 +29502,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
29330
29502
|
wsPort: actualPort,
|
|
29331
29503
|
wsUrl: `ws://localhost:${actualPort}`,
|
|
29332
29504
|
pid: process.pid,
|
|
29505
|
+
serverPath: SERVER_ENTRY_PATH,
|
|
29506
|
+
mainPid: mainStatus?.pid,
|
|
29507
|
+
mainVersion: mainStatus?.version,
|
|
29508
|
+
mainServerPath: mainStatus?.serverPath,
|
|
29509
|
+
mainStartedAt: mainStatus?.startedAt,
|
|
29333
29510
|
chromeConnected: chromeOk,
|
|
29334
29511
|
mcpClientsCount: clientsCount,
|
|
29335
29512
|
portInfoFile: PORT_INFO_FILE,
|
|
@@ -29339,13 +29516,49 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
29339
29516
|
]
|
|
29340
29517
|
};
|
|
29341
29518
|
}
|
|
29519
|
+
if (name === "list_tabs") {
|
|
29520
|
+
const res = await askChrome("listTabs");
|
|
29521
|
+
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29522
|
+
}
|
|
29523
|
+
if (name === "bind_tab") {
|
|
29524
|
+
const { name: targetName, tabId, urlContains, titleContains } = args;
|
|
29525
|
+
const res = await askChrome("bindTab", { name: targetName, tabId, urlContains, titleContains }, { timeoutMs: 1e4 });
|
|
29526
|
+
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29527
|
+
}
|
|
29528
|
+
if (name === "unbind_tab") {
|
|
29529
|
+
const { name: targetName } = args;
|
|
29530
|
+
const res = await askChrome("unbindTab", { name: targetName }, { timeoutMs: 1e4 });
|
|
29531
|
+
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29532
|
+
}
|
|
29533
|
+
if (name === "list_targets") {
|
|
29534
|
+
const res = await askChrome("listTargets");
|
|
29535
|
+
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29536
|
+
}
|
|
29537
|
+
if (name === "get_target_tab") {
|
|
29538
|
+
const res = await askChrome("getTargetTab");
|
|
29539
|
+
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29540
|
+
}
|
|
29541
|
+
if (name === "pin_current_tab") {
|
|
29542
|
+
const res = await askChrome("pinCurrentTab", {}, { timeoutMs: 1e4 });
|
|
29543
|
+
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29544
|
+
}
|
|
29545
|
+
if (name === "pin_tab") {
|
|
29546
|
+
const { tabId, urlContains, titleContains } = args;
|
|
29547
|
+
const res = await askChrome("pinTab", { tabId, urlContains, titleContains }, { timeoutMs: 1e4 });
|
|
29548
|
+
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29549
|
+
}
|
|
29550
|
+
if (name === "unpin_tab") {
|
|
29551
|
+
const res = await askChrome("unpinTab", {}, { timeoutMs: 1e4 });
|
|
29552
|
+
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29553
|
+
}
|
|
29342
29554
|
if (name === "get_last_error") {
|
|
29343
|
-
const { severity = "error", limit = 20 } = args;
|
|
29344
|
-
const data = await askChrome("getLastError", { severity, limit });
|
|
29555
|
+
const { target, severity = "error", limit = 20 } = args;
|
|
29556
|
+
const data = await askChrome("getLastError", { target, severity, limit });
|
|
29345
29557
|
return { content: [{ type: "text", text: jsonText(data) }] };
|
|
29346
29558
|
}
|
|
29347
29559
|
if (name === "get_script_source") {
|
|
29348
29560
|
const {
|
|
29561
|
+
target,
|
|
29349
29562
|
scriptUrlContains,
|
|
29350
29563
|
line,
|
|
29351
29564
|
column,
|
|
@@ -29354,6 +29567,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
29354
29567
|
} = args;
|
|
29355
29568
|
const res = await askChrome("getScriptSource", {
|
|
29356
29569
|
scriptUrlContains,
|
|
29570
|
+
target,
|
|
29357
29571
|
line,
|
|
29358
29572
|
column
|
|
29359
29573
|
});
|
|
@@ -29380,45 +29594,46 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
29380
29594
|
};
|
|
29381
29595
|
}
|
|
29382
29596
|
if (name === "coverage_snapshot") {
|
|
29597
|
+
const { target } = args;
|
|
29383
29598
|
const durationMs = args.durationMs || 1500;
|
|
29384
|
-
const res = await askChrome("coverageSnapshot", { durationMs }, { timeoutMs: durationMs + 4e3 });
|
|
29599
|
+
const res = await askChrome("coverageSnapshot", { target, durationMs }, { timeoutMs: durationMs + 4e3 });
|
|
29385
29600
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29386
29601
|
}
|
|
29387
29602
|
if (name === "find_by_string") {
|
|
29388
|
-
const { query, scriptUrlContains, maxMatches = 5 } = args;
|
|
29389
|
-
const res = await askChrome("findByString", { query, scriptUrlContains, maxMatches });
|
|
29603
|
+
const { target, query, scriptUrlContains, maxMatches = 5 } = args;
|
|
29604
|
+
const res = await askChrome("findByString", { target, query, scriptUrlContains, maxMatches });
|
|
29390
29605
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29391
29606
|
}
|
|
29392
29607
|
if (name === "symbolic_hints") {
|
|
29393
|
-
const res = await askChrome("symbolicHints");
|
|
29608
|
+
const res = await askChrome("symbolicHints", { target: args.target });
|
|
29394
29609
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29395
29610
|
}
|
|
29396
29611
|
if (name === "eval_script") {
|
|
29397
|
-
const res = await askChrome("eval", { code: args.code });
|
|
29612
|
+
const res = await askChrome("eval", { target: args.target, code: args.code });
|
|
29398
29613
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29399
29614
|
}
|
|
29400
29615
|
if (name === "list_network_requests") {
|
|
29401
|
-
const { filter, method, status, resourceType, limit, priorityMode = "debug" } = args;
|
|
29402
|
-
const res = await askChrome("listNetworkRequests", { filter, method, status, resourceType, limit, priorityMode });
|
|
29616
|
+
const { target, filter, method, status, resourceType, limit, priorityMode = "debug" } = args;
|
|
29617
|
+
const res = await askChrome("listNetworkRequests", { target, filter, method, status, resourceType, limit, priorityMode });
|
|
29403
29618
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29404
29619
|
}
|
|
29405
29620
|
if (name === "get_network_detail") {
|
|
29406
|
-
const { requestId, includeBody } = args;
|
|
29407
|
-
const res = await askChrome("getNetworkDetail", { requestId, includeBody });
|
|
29621
|
+
const { target, requestId, includeBody } = args;
|
|
29622
|
+
const res = await askChrome("getNetworkDetail", { target, requestId, includeBody });
|
|
29408
29623
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29409
29624
|
}
|
|
29410
29625
|
if (name === "clear_network_requests") {
|
|
29411
|
-
const res = await askChrome("clearNetworkRequests");
|
|
29626
|
+
const res = await askChrome("clearNetworkRequests", { target: args.target });
|
|
29412
29627
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29413
29628
|
}
|
|
29414
29629
|
if (name === "perf_metrics") {
|
|
29415
|
-
const { includeTimings, includeResources } = args;
|
|
29416
|
-
const res = await askChrome("perfMetrics", { includeTimings, includeResources });
|
|
29630
|
+
const { target, includeTimings, includeResources } = args;
|
|
29631
|
+
const res = await askChrome("perfMetrics", { target, includeTimings, includeResources });
|
|
29417
29632
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29418
29633
|
}
|
|
29419
29634
|
if (name === "capture_screenshot") {
|
|
29420
|
-
const { format, quality, fullPage, clip } = args;
|
|
29421
|
-
const res = await askChrome("captureScreenshot", { format, quality, fullPage, clip }, { timeoutMs: 15e3 });
|
|
29635
|
+
const { target, format, quality, fullPage, clip } = args;
|
|
29636
|
+
const res = await askChrome("captureScreenshot", { target, format, quality, fullPage, clip }, { timeoutMs: 15e3 });
|
|
29422
29637
|
const contents = [];
|
|
29423
29638
|
if (res.imageData) {
|
|
29424
29639
|
contents.push({
|
|
@@ -29442,7 +29657,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
29442
29657
|
return { content: contents };
|
|
29443
29658
|
}
|
|
29444
29659
|
if (name === "get_page_content") {
|
|
29445
|
-
const { mode = "text", selector, maxLength = 5e4, includeMetadata = true } = args;
|
|
29660
|
+
const { target, mode = "text", selector, maxLength = 5e4, includeMetadata = true } = args;
|
|
29446
29661
|
const validModes = ["text", "html", "structured"];
|
|
29447
29662
|
if (mode && !validModes.includes(mode)) {
|
|
29448
29663
|
return {
|
|
@@ -29452,17 +29667,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
29452
29667
|
}]
|
|
29453
29668
|
};
|
|
29454
29669
|
}
|
|
29455
|
-
const res = await askChrome("getPageContent", { mode, selector, maxLength, includeMetadata });
|
|
29670
|
+
const res = await askChrome("getPageContent", { target, mode, selector, maxLength, includeMetadata });
|
|
29456
29671
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29457
29672
|
}
|
|
29458
29673
|
if (name === "get_interactive_snapshot") {
|
|
29459
|
-
const { selector, includeText, maxElements } = args;
|
|
29460
|
-
const res = await askChrome("getInteractiveSnapshot", { selector, includeText, maxElements });
|
|
29674
|
+
const { target, selector, includeText, maxElements } = args;
|
|
29675
|
+
const res = await askChrome("getInteractiveSnapshot", { target, selector, includeText, maxElements });
|
|
29461
29676
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29462
29677
|
}
|
|
29463
29678
|
if (name === "dispatch_action") {
|
|
29464
|
-
const { ref, action, value, key, deltaX, deltaY, waitMs } = args;
|
|
29465
|
-
const res = await askChrome("dispatchAction", { ref, action, value, key, deltaX, deltaY, waitMs }, { timeoutMs: 1e4 });
|
|
29679
|
+
const { target, ref, action, value, key, deltaX, deltaY, waitMs } = args;
|
|
29680
|
+
const res = await askChrome("dispatchAction", { target, ref, action, value, key, deltaX, deltaY, waitMs }, { timeoutMs: 1e4 });
|
|
29466
29681
|
return { content: [{ type: "text", text: jsonText(res) }] };
|
|
29467
29682
|
}
|
|
29468
29683
|
return { content: [{ type: "text", text: `\u672A\u77E5\u5DE5\u5177\uFF1A${name}` }] };
|
|
@@ -29513,6 +29728,10 @@ function cleanup() {
|
|
|
29513
29728
|
} catch (e) {
|
|
29514
29729
|
log(`\u6E05\u7406\u7AEF\u53E3\u4FE1\u606F\u6587\u4EF6\u5931\u8D25: ${e.message}`);
|
|
29515
29730
|
}
|
|
29731
|
+
if (wsPingInterval) {
|
|
29732
|
+
clearInterval(wsPingInterval);
|
|
29733
|
+
wsPingInterval = null;
|
|
29734
|
+
}
|
|
29516
29735
|
if (wss) {
|
|
29517
29736
|
wss.close(() => {
|
|
29518
29737
|
log("\u{1F50C} WebSocket \u670D\u52A1\u5668\u5DF2\u5173\u95ED");
|