ultimate-playwright-mcp 0.1.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/LICENSE +26 -0
- package/README.md +286 -0
- package/dist/browser/cdp.d.ts +37 -0
- package/dist/browser/cdp.d.ts.map +1 -0
- package/dist/browser/cdp.helpers.d.ts +13 -0
- package/dist/browser/cdp.helpers.d.ts.map +1 -0
- package/dist/browser/cdp.helpers.js +38 -0
- package/dist/browser/cdp.helpers.js.map +1 -0
- package/dist/browser/cdp.js +77 -0
- package/dist/browser/cdp.js.map +1 -0
- package/dist/browser/chrome-tab-groups.d.ts +93 -0
- package/dist/browser/chrome-tab-groups.d.ts.map +1 -0
- package/dist/browser/chrome-tab-groups.js +458 -0
- package/dist/browser/chrome-tab-groups.js.map +1 -0
- package/dist/browser/chrome.d.ts +11 -0
- package/dist/browser/chrome.d.ts.map +1 -0
- package/dist/browser/chrome.js +74 -0
- package/dist/browser/chrome.js.map +1 -0
- package/dist/browser/pw-role-snapshot.d.ts +41 -0
- package/dist/browser/pw-role-snapshot.d.ts.map +1 -0
- package/dist/browser/pw-role-snapshot.js +346 -0
- package/dist/browser/pw-role-snapshot.js.map +1 -0
- package/dist/browser/pw-session.d.ts +145 -0
- package/dist/browser/pw-session.d.ts.map +1 -0
- package/dist/browser/pw-session.js +468 -0
- package/dist/browser/pw-session.js.map +1 -0
- package/dist/browser/pw-tools-activity.d.ts +27 -0
- package/dist/browser/pw-tools-activity.d.ts.map +1 -0
- package/dist/browser/pw-tools-activity.js +52 -0
- package/dist/browser/pw-tools-activity.js.map +1 -0
- package/dist/browser/pw-tools-downloads.d.ts +40 -0
- package/dist/browser/pw-tools-downloads.d.ts.map +1 -0
- package/dist/browser/pw-tools-downloads.js +191 -0
- package/dist/browser/pw-tools-downloads.js.map +1 -0
- package/dist/browser/pw-tools-interactions.d.ts +122 -0
- package/dist/browser/pw-tools-interactions.d.ts.map +1 -0
- package/dist/browser/pw-tools-interactions.js +434 -0
- package/dist/browser/pw-tools-interactions.js.map +1 -0
- package/dist/browser/pw-tools-responses.d.ts +19 -0
- package/dist/browser/pw-tools-responses.d.ts.map +1 -0
- package/dist/browser/pw-tools-responses.js +98 -0
- package/dist/browser/pw-tools-responses.js.map +1 -0
- package/dist/browser/pw-tools-shared.d.ts +12 -0
- package/dist/browser/pw-tools-shared.d.ts.map +1 -0
- package/dist/browser/pw-tools-shared.js +55 -0
- package/dist/browser/pw-tools-shared.js.map +1 -0
- package/dist/browser/pw-tools-snapshot.d.ts +70 -0
- package/dist/browser/pw-tools-snapshot.d.ts.map +1 -0
- package/dist/browser/pw-tools-snapshot.js +151 -0
- package/dist/browser/pw-tools-snapshot.js.map +1 -0
- package/dist/browser/pw-tools-state.d.ts +52 -0
- package/dist/browser/pw-tools-state.d.ts.map +1 -0
- package/dist/browser/pw-tools-state.js +159 -0
- package/dist/browser/pw-tools-state.js.map +1 -0
- package/dist/browser/pw-tools-storage.d.ts +53 -0
- package/dist/browser/pw-tools-storage.d.ts.map +1 -0
- package/dist/browser/pw-tools-storage.js +81 -0
- package/dist/browser/pw-tools-storage.js.map +1 -0
- package/dist/browser/pw-tools-trace.d.ts +18 -0
- package/dist/browser/pw-tools-trace.d.ts.map +1 -0
- package/dist/browser/pw-tools-trace.js +31 -0
- package/dist/browser/pw-tools-trace.js.map +1 -0
- package/dist/browser/tab-groups.d.ts +94 -0
- package/dist/browser/tab-groups.d.ts.map +1 -0
- package/dist/browser/tab-groups.js +303 -0
- package/dist/browser/tab-groups.js.map +1 -0
- package/dist/browser/target-id.d.ts +20 -0
- package/dist/browser/target-id.d.ts.map +1 -0
- package/dist/browser/target-id.js +29 -0
- package/dist/browser/target-id.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +35 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +32 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/chrome-daemon.d.ts +7 -0
- package/dist/daemon/chrome-daemon.d.ts.map +1 -0
- package/dist/daemon/chrome-daemon.js +264 -0
- package/dist/daemon/chrome-daemon.js.map +1 -0
- package/dist/daemon/cli.d.ts +6 -0
- package/dist/daemon/cli.d.ts.map +1 -0
- package/dist/daemon/cli.js +110 -0
- package/dist/daemon/cli.js.map +1 -0
- package/dist/daemon/manager.d.ts +22 -0
- package/dist/daemon/manager.d.ts.map +1 -0
- package/dist/daemon/manager.js +89 -0
- package/dist/daemon/manager.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +41 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +122 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/actions.d.ts +6 -0
- package/dist/mcp/tools/actions.d.ts.map +1 -0
- package/dist/mcp/tools/actions.js +214 -0
- package/dist/mcp/tools/actions.js.map +1 -0
- package/dist/mcp/tools/navigate.d.ts +6 -0
- package/dist/mcp/tools/navigate.d.ts.map +1 -0
- package/dist/mcp/tools/navigate.js +31 -0
- package/dist/mcp/tools/navigate.js.map +1 -0
- package/dist/mcp/tools/snapshot.d.ts +6 -0
- package/dist/mcp/tools/snapshot.d.ts.map +1 -0
- package/dist/mcp/tools/snapshot.js +26 -0
- package/dist/mcp/tools/snapshot.js.map +1 -0
- package/dist/mcp/tools/tab-group.d.ts +9 -0
- package/dist/mcp/tools/tab-group.d.ts.map +1 -0
- package/dist/mcp/tools/tab-group.js +173 -0
- package/dist/mcp/tools/tab-group.js.map +1 -0
- package/dist/mcp/tools/tabs.d.ts +6 -0
- package/dist/mcp/tools/tabs.d.ts.map +1 -0
- package/dist/mcp/tools/tabs.js +209 -0
- package/dist/mcp/tools/tabs.js.map +1 -0
- package/dist/utils/command-format.d.ts +6 -0
- package/dist/utils/command-format.d.ts.map +1 -0
- package/dist/utils/command-format.js +8 -0
- package/dist/utils/command-format.js.map +1 -0
- package/dist/utils/errors.d.ts +6 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +22 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/extension-installer.d.ts +16 -0
- package/dist/utils/extension-installer.d.ts.map +1 -0
- package/dist/utils/extension-installer.js +134 -0
- package/dist/utils/extension-installer.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome visual tab groups via the companion extension.
|
|
3
|
+
*
|
|
4
|
+
* Connects to the "UltimatePW Tab Grouper" extension's service worker
|
|
5
|
+
* via CDP and calls its global helpers (groupTabs, ungroupTabs, etc.)
|
|
6
|
+
* to manage native Chrome tab groups with titles and colors.
|
|
7
|
+
*
|
|
8
|
+
* Falls back gracefully — if the extension isn't loaded, visual grouping
|
|
9
|
+
* is simply skipped and a warning is returned.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
12
|
+
import { resolve as resolvePath } from "node:path";
|
|
13
|
+
import WebSocket from "ws";
|
|
14
|
+
import { getHeadersWithAuth } from "./cdp.helpers.js";
|
|
15
|
+
import { getExtensionId as getStoredExtensionId, setExtensionId as storeExtensionId } from "./tab-groups.js";
|
|
16
|
+
// ── Find the extension service worker ──────────────────────────────────────
|
|
17
|
+
let cachedSwUrl = null;
|
|
18
|
+
let cachedCdpBase = null;
|
|
19
|
+
/** Cached extension ID so we can wake it when dormant */
|
|
20
|
+
let cachedExtensionId = null;
|
|
21
|
+
/**
|
|
22
|
+
* Compute a Chrome unpacked extension ID from its absolute directory path.
|
|
23
|
+
* Chrome uses SHA-256 of the path, maps each nibble to a-p.
|
|
24
|
+
*/
|
|
25
|
+
export function computeExtensionId(extensionPath) {
|
|
26
|
+
const abs = resolvePath(extensionPath);
|
|
27
|
+
const hash = createHash("sha256").update(abs).digest();
|
|
28
|
+
let id = "";
|
|
29
|
+
for (let i = 0; i < 16; i++) {
|
|
30
|
+
const byte = hash[i];
|
|
31
|
+
id += String.fromCharCode(97 + (byte >> 4));
|
|
32
|
+
id += String.fromCharCode(97 + (byte & 0xf));
|
|
33
|
+
}
|
|
34
|
+
return id;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Pre-seed the extension ID from a known path. Call this during server init
|
|
38
|
+
* so the wake mechanism works even before the first probe succeeds.
|
|
39
|
+
*/
|
|
40
|
+
export function seedExtensionIdFromPath(extensionPath) {
|
|
41
|
+
const id = computeExtensionId(extensionPath);
|
|
42
|
+
cachedExtensionId = id;
|
|
43
|
+
storeExtensionId(id);
|
|
44
|
+
}
|
|
45
|
+
async function findExtensionServiceWorker(cdpUrl) {
|
|
46
|
+
const baseUrl = cdpUrl
|
|
47
|
+
.replace(/\/+$/, "")
|
|
48
|
+
.replace(/^ws:/, "http:")
|
|
49
|
+
.replace(/\/cdp$/, "");
|
|
50
|
+
// Use cached result if same CDP base
|
|
51
|
+
if (cachedSwUrl && cachedCdpBase === baseUrl) {
|
|
52
|
+
// Verify it's still alive
|
|
53
|
+
try {
|
|
54
|
+
const resp = await fetch(`${baseUrl}/json/list`, {
|
|
55
|
+
signal: AbortSignal.timeout(2000),
|
|
56
|
+
headers: getHeadersWithAuth(`${baseUrl}/json/list`),
|
|
57
|
+
});
|
|
58
|
+
if (resp.ok) {
|
|
59
|
+
const targets = (await resp.json());
|
|
60
|
+
if (targets.some((t) => t.webSocketDebuggerUrl === cachedSwUrl)) {
|
|
61
|
+
return cachedSwUrl;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Cache miss
|
|
67
|
+
}
|
|
68
|
+
cachedSwUrl = null;
|
|
69
|
+
cachedCdpBase = null;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const resp = await fetch(`${baseUrl}/json/list`, {
|
|
73
|
+
signal: AbortSignal.timeout(3000),
|
|
74
|
+
headers: getHeadersWithAuth(`${baseUrl}/json/list`),
|
|
75
|
+
});
|
|
76
|
+
if (!resp.ok)
|
|
77
|
+
return null;
|
|
78
|
+
const targets = (await resp.json());
|
|
79
|
+
// Find our companion extension's service worker by probing each
|
|
80
|
+
// extension SW for the `groupTabs` global we define.
|
|
81
|
+
const candidates = targets.filter((t) => t.type === "service_worker" &&
|
|
82
|
+
t.url.startsWith("chrome-extension://") &&
|
|
83
|
+
t.webSocketDebuggerUrl);
|
|
84
|
+
for (const candidate of candidates) {
|
|
85
|
+
try {
|
|
86
|
+
const hasGroupTabs = await probeForGroupTabs(candidate.webSocketDebuggerUrl);
|
|
87
|
+
if (hasGroupTabs) {
|
|
88
|
+
cachedSwUrl = candidate.webSocketDebuggerUrl;
|
|
89
|
+
cachedCdpBase = baseUrl;
|
|
90
|
+
// Extract and persist the extension ID from URL
|
|
91
|
+
const extIdMatch = candidate.url.match(/chrome-extension:\/\/([a-z]+)\//);
|
|
92
|
+
if (extIdMatch) {
|
|
93
|
+
cachedExtensionId = extIdMatch[1];
|
|
94
|
+
storeExtensionId(cachedExtensionId);
|
|
95
|
+
}
|
|
96
|
+
return cachedSwUrl;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// This SW doesn't have our function, or it's dormant — skip
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// If we have a cached or persisted extension ID, try to wake the dormant SW
|
|
104
|
+
// by sending it a message from any available extension SW
|
|
105
|
+
const extId = cachedExtensionId || getStoredExtensionId();
|
|
106
|
+
if (extId) {
|
|
107
|
+
cachedExtensionId = extId;
|
|
108
|
+
// Use ALL extension SWs (not just candidates) as potential senders
|
|
109
|
+
const allSWs = targets.filter((t) => t.type === "service_worker" && t.webSocketDebuggerUrl);
|
|
110
|
+
const woke = await wakeExtension(baseUrl, extId, allSWs);
|
|
111
|
+
if (woke) {
|
|
112
|
+
// Re-scan after wake
|
|
113
|
+
const resp2 = await fetch(`${baseUrl}/json/list`, {
|
|
114
|
+
signal: AbortSignal.timeout(3000),
|
|
115
|
+
headers: getHeadersWithAuth(`${baseUrl}/json/list`),
|
|
116
|
+
});
|
|
117
|
+
if (resp2.ok) {
|
|
118
|
+
const refreshed = (await resp2.json());
|
|
119
|
+
for (const candidate of refreshed.filter((t) => t.type === "service_worker" && t.url.startsWith("chrome-extension://"))) {
|
|
120
|
+
try {
|
|
121
|
+
const hasGroupTabs = await probeForGroupTabs(candidate.webSocketDebuggerUrl);
|
|
122
|
+
if (hasGroupTabs) {
|
|
123
|
+
cachedSwUrl = candidate.webSocketDebuggerUrl;
|
|
124
|
+
cachedCdpBase = baseUrl;
|
|
125
|
+
// Persist the extension ID
|
|
126
|
+
const m = candidate.url.match(/chrome-extension:\/\/([a-z]+)\//);
|
|
127
|
+
if (m) {
|
|
128
|
+
cachedExtensionId = m[1];
|
|
129
|
+
storeExtensionId(m[1]);
|
|
130
|
+
}
|
|
131
|
+
return cachedSwUrl;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// skip
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// ── Wake a dormant extension service worker ────────────────────────────────
|
|
148
|
+
/**
|
|
149
|
+
* Wake a dormant MV3 extension by sending it a message from another extension's
|
|
150
|
+
* service worker. Chrome re-starts the target SW to deliver the message.
|
|
151
|
+
*/
|
|
152
|
+
async function wakeExtension(_cdpBaseUrl, extensionId, availableSWs) {
|
|
153
|
+
// Find any OTHER extension SW that's alive to send the wake message from
|
|
154
|
+
const sender = availableSWs.find((t) => t.webSocketDebuggerUrl && !t.url.includes(extensionId));
|
|
155
|
+
if (!sender)
|
|
156
|
+
return false;
|
|
157
|
+
try {
|
|
158
|
+
const result = await new Promise((resolve) => {
|
|
159
|
+
const timer = setTimeout(() => {
|
|
160
|
+
sock.close();
|
|
161
|
+
resolve(false);
|
|
162
|
+
}, 5000);
|
|
163
|
+
const sock = new WebSocket(sender.webSocketDebuggerUrl);
|
|
164
|
+
sock.on("error", () => {
|
|
165
|
+
clearTimeout(timer);
|
|
166
|
+
resolve(false);
|
|
167
|
+
});
|
|
168
|
+
sock.on("open", () => {
|
|
169
|
+
sock.send(JSON.stringify({
|
|
170
|
+
id: 1,
|
|
171
|
+
method: "Runtime.evaluate",
|
|
172
|
+
params: {
|
|
173
|
+
expression: `chrome.runtime.sendMessage("${extensionId}", {type:"wake"}).then(() => true).catch(() => true)`,
|
|
174
|
+
awaitPromise: true,
|
|
175
|
+
returnByValue: true,
|
|
176
|
+
},
|
|
177
|
+
}));
|
|
178
|
+
});
|
|
179
|
+
sock.on("message", (data) => {
|
|
180
|
+
const msg = JSON.parse(data.toString());
|
|
181
|
+
if (msg.id === 1) {
|
|
182
|
+
clearTimeout(timer);
|
|
183
|
+
sock.close();
|
|
184
|
+
resolve(true);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
if (result) {
|
|
189
|
+
// Give the SW a moment to start up
|
|
190
|
+
await new Promise((r) => setTimeout(r, 2500));
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// ── Probe a service worker for our extension ───────────────────────────────
|
|
199
|
+
async function probeForGroupTabs(wsUrl) {
|
|
200
|
+
return new Promise((resolve, reject) => {
|
|
201
|
+
const timer = setTimeout(() => {
|
|
202
|
+
sock.close();
|
|
203
|
+
reject(new Error("probe timeout"));
|
|
204
|
+
}, 3000);
|
|
205
|
+
const sock = new WebSocket(wsUrl);
|
|
206
|
+
sock.on("error", (err) => {
|
|
207
|
+
clearTimeout(timer);
|
|
208
|
+
reject(err);
|
|
209
|
+
});
|
|
210
|
+
sock.on("open", () => {
|
|
211
|
+
sock.send(JSON.stringify({
|
|
212
|
+
id: 1,
|
|
213
|
+
method: "Runtime.evaluate",
|
|
214
|
+
params: {
|
|
215
|
+
expression: "typeof groupTabs === 'function'",
|
|
216
|
+
returnByValue: true,
|
|
217
|
+
},
|
|
218
|
+
}));
|
|
219
|
+
});
|
|
220
|
+
sock.on("message", (data) => {
|
|
221
|
+
let msg;
|
|
222
|
+
try {
|
|
223
|
+
msg = JSON.parse(data.toString());
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (msg.id !== 1)
|
|
229
|
+
return;
|
|
230
|
+
clearTimeout(timer);
|
|
231
|
+
sock.close();
|
|
232
|
+
resolve(msg.result?.result?.value === true);
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
// ── Evaluate JS on the extension service worker ────────────────────────────
|
|
237
|
+
async function evalOnExtension(cdpUrl, expression, timeout = 10_000) {
|
|
238
|
+
const wsUrl = await findExtensionServiceWorker(cdpUrl);
|
|
239
|
+
if (!wsUrl) {
|
|
240
|
+
throw new ExtensionNotFoundError();
|
|
241
|
+
}
|
|
242
|
+
return new Promise((resolve, reject) => {
|
|
243
|
+
const timer = setTimeout(() => {
|
|
244
|
+
sock.close();
|
|
245
|
+
reject(new Error("CDP evaluation timed out"));
|
|
246
|
+
}, timeout);
|
|
247
|
+
const sock = new WebSocket(wsUrl);
|
|
248
|
+
sock.on("error", (err) => {
|
|
249
|
+
clearTimeout(timer);
|
|
250
|
+
reject(err);
|
|
251
|
+
});
|
|
252
|
+
sock.on("open", () => {
|
|
253
|
+
sock.send(JSON.stringify({
|
|
254
|
+
id: 1,
|
|
255
|
+
method: "Runtime.evaluate",
|
|
256
|
+
params: {
|
|
257
|
+
expression,
|
|
258
|
+
awaitPromise: true,
|
|
259
|
+
returnByValue: true,
|
|
260
|
+
},
|
|
261
|
+
}));
|
|
262
|
+
});
|
|
263
|
+
sock.on("message", (data) => {
|
|
264
|
+
let msg;
|
|
265
|
+
try {
|
|
266
|
+
msg = JSON.parse(data.toString());
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (msg.id !== 1)
|
|
272
|
+
return;
|
|
273
|
+
clearTimeout(timer);
|
|
274
|
+
sock.close();
|
|
275
|
+
if (msg.error) {
|
|
276
|
+
reject(new Error(`CDP error: ${msg.error.message}`));
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const result = msg.result?.result;
|
|
280
|
+
const exception = msg.result?.exceptionDetails;
|
|
281
|
+
if (exception) {
|
|
282
|
+
const detail = exception.exception?.description || exception.text || "Unknown error";
|
|
283
|
+
reject(new Error(`Extension error: ${detail}`));
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (result?.subtype === "error") {
|
|
287
|
+
reject(new Error(`Extension error: ${result.description || "Unknown"}`));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
resolve(result?.value);
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
// ── Custom error for missing extension ─────────────────────────────────────
|
|
295
|
+
export class ExtensionNotFoundError extends Error {
|
|
296
|
+
constructor() {
|
|
297
|
+
super(`Tab Grouper extension not found. Visual tab groups require the companion extension.\n` +
|
|
298
|
+
`Load it with: --chrome-extensions extensions/tab-grouper`);
|
|
299
|
+
this.name = "ExtensionNotFoundError";
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
303
|
+
/**
|
|
304
|
+
* Check whether the companion extension is available.
|
|
305
|
+
*/
|
|
306
|
+
/**
|
|
307
|
+
* Warm up: discover and cache the extension ID while the SW is still alive
|
|
308
|
+
* (should be called soon after Chrome starts). Best-effort, non-blocking.
|
|
309
|
+
*/
|
|
310
|
+
export async function warmupTabGrouper(cdpUrl) {
|
|
311
|
+
try {
|
|
312
|
+
await findExtensionServiceWorker(cdpUrl);
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
// Best-effort
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
export async function isTabGrouperAvailable(cdpUrl) {
|
|
319
|
+
const wsUrl = await findExtensionServiceWorker(cdpUrl);
|
|
320
|
+
return wsUrl !== null;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Get the Chrome tab ID for a given URL + title combo.
|
|
324
|
+
* We need this to bridge CDP targetId → Chrome tab ID.
|
|
325
|
+
*/
|
|
326
|
+
export async function getChromeTabId(cdpUrl, targetUrl, targetTitle) {
|
|
327
|
+
try {
|
|
328
|
+
const tabs = (await evalOnExtension(cdpUrl, `queryTabs()`));
|
|
329
|
+
// Match by URL (most reliable)
|
|
330
|
+
const urlMatches = tabs.filter((t) => t.url === targetUrl);
|
|
331
|
+
if (urlMatches.length === 1)
|
|
332
|
+
return urlMatches[0].id;
|
|
333
|
+
// If multiple URL matches, narrow by title
|
|
334
|
+
if (urlMatches.length > 1 && targetTitle) {
|
|
335
|
+
const titleMatch = urlMatches.find((t) => t.title === targetTitle);
|
|
336
|
+
if (titleMatch)
|
|
337
|
+
return titleMatch.id;
|
|
338
|
+
}
|
|
339
|
+
return urlMatches[0]?.id ?? null;
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Map CDP targetIds to Chrome tab IDs by correlating URL/title.
|
|
347
|
+
* Returns a map of targetId → chromeTabId.
|
|
348
|
+
*/
|
|
349
|
+
export async function mapTargetIdsToChromeTabIds(cdpUrl, targets) {
|
|
350
|
+
const result = new Map();
|
|
351
|
+
let chromeTabs;
|
|
352
|
+
try {
|
|
353
|
+
chromeTabs = (await evalOnExtension(cdpUrl, `queryTabs()`));
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
// Build URL → chrome tabs index
|
|
359
|
+
const byUrl = new Map();
|
|
360
|
+
for (const ct of chromeTabs) {
|
|
361
|
+
const list = byUrl.get(ct.url) || [];
|
|
362
|
+
list.push({ id: ct.id, title: ct.title });
|
|
363
|
+
byUrl.set(ct.url, list);
|
|
364
|
+
}
|
|
365
|
+
for (const target of targets) {
|
|
366
|
+
const candidates = byUrl.get(target.url);
|
|
367
|
+
if (!candidates?.length)
|
|
368
|
+
continue;
|
|
369
|
+
if (candidates.length === 1) {
|
|
370
|
+
result.set(target.targetId, candidates[0].id);
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
// Multiple tabs with same URL, try title match
|
|
374
|
+
const titleMatch = candidates.find((c) => c.title === target.title);
|
|
375
|
+
if (titleMatch) {
|
|
376
|
+
result.set(target.targetId, titleMatch.id);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Group Chrome tabs visually with a title and color.
|
|
384
|
+
* @param chromeTabIds - Chrome internal tab IDs (not CDP targetIds)
|
|
385
|
+
* @param title - Group title
|
|
386
|
+
* @param color - grey|blue|red|yellow|green|pink|purple|cyan
|
|
387
|
+
* @param existingGroupId - If provided, add to an existing Chrome group
|
|
388
|
+
* @returns Chrome's groupId
|
|
389
|
+
*/
|
|
390
|
+
export async function groupTabsVisually(cdpUrl, chromeTabIds, title, color, existingGroupId) {
|
|
391
|
+
const existingArg = existingGroupId !== undefined ? `, ${existingGroupId}` : "";
|
|
392
|
+
const result = (await evalOnExtension(cdpUrl, `groupTabs([${chromeTabIds.join(",")}], ${JSON.stringify(title)}, ${JSON.stringify(color)}${existingArg})`));
|
|
393
|
+
return result;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Remove tabs from their Chrome visual group.
|
|
397
|
+
*/
|
|
398
|
+
export async function ungroupTabsVisually(cdpUrl, chromeTabIds) {
|
|
399
|
+
await evalOnExtension(cdpUrl, `ungroupTabs([${chromeTabIds.join(",")}])`);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Update a Chrome visual group's title/color/collapsed state.
|
|
403
|
+
*/
|
|
404
|
+
export async function updateVisualGroup(cdpUrl, chromeGroupId, updates) {
|
|
405
|
+
await evalOnExtension(cdpUrl, `updateTabGroup(${chromeGroupId}, ${JSON.stringify(updates)})`);
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* List all Chrome visual tab groups.
|
|
409
|
+
*/
|
|
410
|
+
export async function listVisualTabGroups(cdpUrl) {
|
|
411
|
+
return (await evalOnExtension(cdpUrl, `listTabGroups()`));
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Create a tab via the extension (gives us the Chrome tab ID directly).
|
|
415
|
+
* This avoids the unreliable URL-based mapping from CDP targetIds.
|
|
416
|
+
* Returns both the Chrome tabId and the CDP targetId.
|
|
417
|
+
*/
|
|
418
|
+
export async function createTabViaExtension(cdpUrl, url) {
|
|
419
|
+
// Snapshot existing CDP targets BEFORE creating the tab
|
|
420
|
+
const beforeResp = await fetch(`${cdpUrl}/json/list`, {
|
|
421
|
+
signal: AbortSignal.timeout(3000),
|
|
422
|
+
headers: getHeadersWithAuth(`${cdpUrl}/json/list`),
|
|
423
|
+
});
|
|
424
|
+
const beforeTargets = beforeResp.ok
|
|
425
|
+
? (await beforeResp.json())
|
|
426
|
+
: [];
|
|
427
|
+
const beforeIds = new Set(beforeTargets.map((t) => t.id));
|
|
428
|
+
// Create the tab via extension
|
|
429
|
+
const result = (await evalOnExtension(cdpUrl, `createTab(${JSON.stringify(url)})`));
|
|
430
|
+
// Poll for the NEW CDP target (one that wasn't in the before snapshot)
|
|
431
|
+
let targetId = null;
|
|
432
|
+
for (let attempt = 0; attempt < 20; attempt++) {
|
|
433
|
+
const resp = await fetch(`${cdpUrl}/json/list`, {
|
|
434
|
+
signal: AbortSignal.timeout(3000),
|
|
435
|
+
headers: getHeadersWithAuth(`${cdpUrl}/json/list`),
|
|
436
|
+
});
|
|
437
|
+
if (resp.ok) {
|
|
438
|
+
const targets = (await resp.json());
|
|
439
|
+
const newTarget = targets.find((t) => t.type === "page" && !beforeIds.has(t.id));
|
|
440
|
+
if (newTarget) {
|
|
441
|
+
targetId = newTarget.id;
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
446
|
+
}
|
|
447
|
+
if (!targetId) {
|
|
448
|
+
throw new Error(`Created Chrome tab ${result.tabId} but could not find new CDP target`);
|
|
449
|
+
}
|
|
450
|
+
return { chromeTabId: result.tabId, targetId, url: result.url };
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Close a tab via the extension using its Chrome tab ID.
|
|
454
|
+
*/
|
|
455
|
+
export async function closeTabViaExtension(cdpUrl, chromeTabId) {
|
|
456
|
+
await evalOnExtension(cdpUrl, `closeTab(${chromeTabId})`);
|
|
457
|
+
}
|
|
458
|
+
//# sourceMappingURL=chrome-tab-groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chrome-tab-groups.js","sourceRoot":"","sources":["../../src/browser/chrome-tab-groups.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracted from OpenClaw (https://github.com/openclaw/openclaw)
|
|
3
|
+
* Original: src/browser/chrome.ts
|
|
4
|
+
* License: MIT
|
|
5
|
+
*
|
|
6
|
+
* Modified for ultimate-playwright-mcp:
|
|
7
|
+
* - Removed Chrome launcher (we use CDP to existing Chrome)
|
|
8
|
+
* - Kept only getChromeWebSocketUrl for CDP connection
|
|
9
|
+
*/
|
|
10
|
+
export declare function getChromeWebSocketUrl(cdpUrl: string, timeoutMs?: number): Promise<string | null>;
|
|
11
|
+
//# sourceMappingURL=chrome.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../src/browser/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsEH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,SAAS,SAAM,GACd,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracted from OpenClaw (https://github.com/openclaw/openclaw)
|
|
3
|
+
* Original: src/browser/chrome.ts
|
|
4
|
+
* License: MIT
|
|
5
|
+
*
|
|
6
|
+
* Modified for ultimate-playwright-mcp:
|
|
7
|
+
* - Removed Chrome launcher (we use CDP to existing Chrome)
|
|
8
|
+
* - Kept only getChromeWebSocketUrl for CDP connection
|
|
9
|
+
*/
|
|
10
|
+
import { getHeadersWithAuth, isLoopbackHost } from "./cdp.helpers.js";
|
|
11
|
+
function appendCdpPath(cdpUrl, path) {
|
|
12
|
+
const url = new URL(cdpUrl);
|
|
13
|
+
const basePath = url.pathname.replace(/\/$/, "");
|
|
14
|
+
const suffix = path.startsWith("/") ? path : `/${path}`;
|
|
15
|
+
url.pathname = `${basePath}${suffix}`;
|
|
16
|
+
return url.toString();
|
|
17
|
+
}
|
|
18
|
+
function normalizeCdpWsUrl(wsUrl, cdpUrl) {
|
|
19
|
+
const ws = new URL(wsUrl);
|
|
20
|
+
const cdp = new URL(cdpUrl);
|
|
21
|
+
// If WebSocket URL is loopback but CDP URL isn't, use CDP URL's host
|
|
22
|
+
if (isLoopbackHost(ws.hostname) && !isLoopbackHost(cdp.hostname)) {
|
|
23
|
+
ws.hostname = cdp.hostname;
|
|
24
|
+
const cdpPort = cdp.port || (cdp.protocol === "https:" ? "443" : "80");
|
|
25
|
+
if (cdpPort) {
|
|
26
|
+
ws.port = cdpPort;
|
|
27
|
+
}
|
|
28
|
+
ws.protocol = cdp.protocol === "https:" ? "wss:" : "ws:";
|
|
29
|
+
}
|
|
30
|
+
// Upgrade to wss if CDP is https
|
|
31
|
+
if (cdp.protocol === "https:" && ws.protocol === "ws:") {
|
|
32
|
+
ws.protocol = "wss:";
|
|
33
|
+
}
|
|
34
|
+
// Copy auth from CDP URL if WebSocket URL doesn't have it
|
|
35
|
+
if (!ws.username && !ws.password && (cdp.username || cdp.password)) {
|
|
36
|
+
ws.username = cdp.username;
|
|
37
|
+
ws.password = cdp.password;
|
|
38
|
+
}
|
|
39
|
+
return ws.toString();
|
|
40
|
+
}
|
|
41
|
+
async function fetchChromeVersion(cdpUrl, timeoutMs = 500) {
|
|
42
|
+
const ctrl = new AbortController();
|
|
43
|
+
const t = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
44
|
+
try {
|
|
45
|
+
const versionUrl = appendCdpPath(cdpUrl, "/json/version");
|
|
46
|
+
const res = await fetch(versionUrl, {
|
|
47
|
+
signal: ctrl.signal,
|
|
48
|
+
headers: getHeadersWithAuth(versionUrl),
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const data = (await res.json());
|
|
54
|
+
if (!data || typeof data !== "object") {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return data;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
clearTimeout(t);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export async function getChromeWebSocketUrl(cdpUrl, timeoutMs = 500) {
|
|
67
|
+
const version = await fetchChromeVersion(cdpUrl, timeoutMs);
|
|
68
|
+
const wsUrl = String(version?.webSocketDebuggerUrl ?? "").trim();
|
|
69
|
+
if (!wsUrl) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return normalizeCdpWsUrl(wsUrl, cdpUrl);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=chrome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../src/browser/chrome.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracted from OpenClaw (https://github.com/openclaw/openclaw)
|
|
3
|
+
* Original: src/browser/pw-role-snapshot.ts
|
|
4
|
+
* License: MIT
|
|
5
|
+
*/
|
|
6
|
+
export type RoleRef = {
|
|
7
|
+
role: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
/** Index used only when role+name duplicates exist. */
|
|
10
|
+
nth?: number;
|
|
11
|
+
};
|
|
12
|
+
export type RoleRefMap = Record<string, RoleRef>;
|
|
13
|
+
export type RoleSnapshotStats = {
|
|
14
|
+
lines: number;
|
|
15
|
+
chars: number;
|
|
16
|
+
refs: number;
|
|
17
|
+
interactive: number;
|
|
18
|
+
};
|
|
19
|
+
export type RoleSnapshotOptions = {
|
|
20
|
+
/** Only include interactive elements (buttons, links, inputs, etc.). */
|
|
21
|
+
interactive?: boolean;
|
|
22
|
+
/** Maximum depth to include (0 = root only). */
|
|
23
|
+
maxDepth?: number;
|
|
24
|
+
/** Remove unnamed structural elements and empty branches. */
|
|
25
|
+
compact?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare function getRoleSnapshotStats(snapshot: string, refs: RoleRefMap): RoleSnapshotStats;
|
|
28
|
+
export declare function parseRoleRef(raw: string): string | null;
|
|
29
|
+
export declare function buildRoleSnapshotFromAriaSnapshot(ariaSnapshot: string, options?: RoleSnapshotOptions): {
|
|
30
|
+
snapshot: string;
|
|
31
|
+
refs: RoleRefMap;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Build a role snapshot from Playwright's AI snapshot output while preserving Playwright's own
|
|
35
|
+
* aria-ref ids (e.g. ref=e13). This makes the refs self-resolving across calls.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildRoleSnapshotFromAiSnapshot(aiSnapshot: string, options?: RoleSnapshotOptions): {
|
|
38
|
+
snapshot: string;
|
|
39
|
+
refs: RoleRefMap;
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=pw-role-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pw-role-snapshot.d.ts","sourceRoot":"","sources":["../../src/browser/pw-role-snapshot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,wEAAwE;IACxE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAwDF,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,iBAAiB,CAQ1F;AA4JD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWvD;AAED,wBAAgB,iCAAiC,CAC/C,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,mBAAwB,GAChC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CA+ExC;AAOD;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,mBAAwB,GAChC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CA0ExC"}
|