@accomplish_ai/agent-core 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -0
- package/dist/common/constants.d.ts +1 -1
- package/dist/common/constants.d.ts.map +1 -1
- package/dist/common/constants.js +1 -1
- package/dist/common/constants.js.map +1 -1
- package/dist/common/types/index.d.ts +14 -10
- package/dist/common/types/index.d.ts.map +1 -1
- package/dist/common/types/index.js +4 -10
- package/dist/common/types/index.js.map +1 -1
- package/dist/common/utils/index.d.ts +3 -3
- package/dist/common/utils/index.d.ts.map +1 -1
- package/dist/common/utils/index.js +3 -3
- package/dist/common/utils/index.js.map +1 -1
- package/dist/factories/speech.d.ts.map +1 -1
- package/dist/factories/speech.js.map +1 -1
- package/dist/index.d.ts +1 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -20
- package/dist/index.js.map +1 -1
- package/dist/internal/classes/SecureStorage.d.ts.map +1 -1
- package/dist/internal/classes/SecureStorage.js +3 -0
- package/dist/internal/classes/SecureStorage.js.map +1 -1
- package/dist/internal/classes/TaskManager.d.ts +3 -2
- package/dist/internal/classes/TaskManager.d.ts.map +1 -1
- package/dist/internal/classes/TaskManager.js +34 -1
- package/dist/internal/classes/TaskManager.js.map +1 -1
- package/dist/storage/index.d.ts +4 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +4 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/types/log-writer.d.ts +2 -15
- package/dist/types/log-writer.d.ts.map +1 -1
- package/dist/types/skills-manager.d.ts +13 -0
- package/dist/types/skills-manager.d.ts.map +1 -1
- package/dist/types/speech.d.ts +3 -2
- package/dist/types/speech.d.ts.map +1 -1
- package/dist/types/storage.d.ts +70 -0
- package/dist/types/storage.d.ts.map +1 -1
- package/dist/types/task-manager.d.ts +13 -3
- package/dist/types/task-manager.d.ts.map +1 -1
- package/dist/types.d.ts +0 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/index.d.ts +16 -13
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +13 -13
- package/dist/utils/index.js.map +1 -1
- package/mcp-tools/dev-browser/server.cjs +144 -0
- package/package.json +16 -3
- package/mcp-tools/ask-user-question/src/index.ts +0 -183
- package/mcp-tools/ask-user-question/tsconfig.json +0 -12
- package/mcp-tools/complete-task/src/index.ts +0 -92
- package/mcp-tools/dev-browser/src/index.ts +0 -290
- package/mcp-tools/dev-browser/src/relay.ts +0 -652
- package/mcp-tools/dev-browser/src/types.ts +0 -31
- package/mcp-tools/dev-browser/tsconfig.json +0 -36
- package/mcp-tools/dev-browser-mcp/src/index.ts +0 -3940
- package/mcp-tools/dev-browser-mcp/src/snapshot/compactor.test.ts +0 -86
- package/mcp-tools/dev-browser-mcp/src/snapshot/compactor.ts +0 -31
- package/mcp-tools/dev-browser-mcp/src/snapshot/differ.test.ts +0 -178
- package/mcp-tools/dev-browser-mcp/src/snapshot/differ.ts +0 -167
- package/mcp-tools/dev-browser-mcp/src/snapshot/index.ts +0 -19
- package/mcp-tools/dev-browser-mcp/src/snapshot/manager.test.ts +0 -247
- package/mcp-tools/dev-browser-mcp/src/snapshot/manager.ts +0 -131
- package/mcp-tools/dev-browser-mcp/src/snapshot/parser.test.ts +0 -94
- package/mcp-tools/dev-browser-mcp/src/snapshot/parser.ts +0 -81
- package/mcp-tools/dev-browser-mcp/src/snapshot/priority.test.ts +0 -104
- package/mcp-tools/dev-browser-mcp/src/snapshot/priority.ts +0 -84
- package/mcp-tools/dev-browser-mcp/src/snapshot/tokens.test.ts +0 -64
- package/mcp-tools/dev-browser-mcp/src/snapshot/tokens.ts +0 -36
- package/mcp-tools/dev-browser-mcp/src/snapshot/types.ts +0 -89
- package/mcp-tools/dev-browser-mcp/tsconfig.json +0 -15
- package/mcp-tools/file-permission/src/index.ts +0 -125
- package/mcp-tools/file-permission/tsconfig.json +0 -17
- package/mcp-tools/report-checkpoint/src/index.ts +0 -127
- package/mcp-tools/report-checkpoint/tsconfig.json +0 -12
- package/mcp-tools/report-thought/src/index.ts +0 -109
- package/mcp-tools/report-thought/tsconfig.json +0 -12
- package/mcp-tools/start-task/src/index.ts +0 -86
|
@@ -1,652 +0,0 @@
|
|
|
1
|
-
import { Hono } from "hono";
|
|
2
|
-
import { serve } from "@hono/node-server";
|
|
3
|
-
import { createNodeWebSocket } from "@hono/node-ws";
|
|
4
|
-
import type { WSContext } from "hono/ws";
|
|
5
|
-
|
|
6
|
-
export interface RelayOptions {
|
|
7
|
-
port?: number;
|
|
8
|
-
host?: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface RelayServer {
|
|
12
|
-
wsEndpoint: string;
|
|
13
|
-
port: number;
|
|
14
|
-
stop(): Promise<void>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface TargetInfo {
|
|
18
|
-
targetId: string;
|
|
19
|
-
type: string;
|
|
20
|
-
title: string;
|
|
21
|
-
url: string;
|
|
22
|
-
attached: boolean;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface ConnectedTarget {
|
|
26
|
-
sessionId: string;
|
|
27
|
-
targetId: string;
|
|
28
|
-
targetInfo: TargetInfo;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface PlaywrightClient {
|
|
32
|
-
id: string;
|
|
33
|
-
ws: WSContext;
|
|
34
|
-
knownTargets: Set<string>;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
interface ExtensionCommandMessage {
|
|
38
|
-
id: number;
|
|
39
|
-
method: "forwardCDPCommand";
|
|
40
|
-
params: {
|
|
41
|
-
method: string;
|
|
42
|
-
params?: Record<string, unknown>;
|
|
43
|
-
sessionId?: string;
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface ExtensionResponseMessage {
|
|
48
|
-
id: number;
|
|
49
|
-
result?: unknown;
|
|
50
|
-
error?: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
interface ExtensionEventMessage {
|
|
54
|
-
method: "forwardCDPEvent";
|
|
55
|
-
params: {
|
|
56
|
-
method: string;
|
|
57
|
-
params?: Record<string, unknown>;
|
|
58
|
-
sessionId?: string;
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
type ExtensionMessage =
|
|
63
|
-
| ExtensionResponseMessage
|
|
64
|
-
| ExtensionEventMessage
|
|
65
|
-
| { method: "log"; params: { level: string; args: string[] } };
|
|
66
|
-
|
|
67
|
-
interface CDPCommand {
|
|
68
|
-
id: number;
|
|
69
|
-
method: string;
|
|
70
|
-
params?: Record<string, unknown>;
|
|
71
|
-
sessionId?: string;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
interface CDPResponse {
|
|
75
|
-
id: number;
|
|
76
|
-
sessionId?: string;
|
|
77
|
-
result?: unknown;
|
|
78
|
-
error?: { message: string };
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
interface CDPEvent {
|
|
82
|
-
method: string;
|
|
83
|
-
sessionId?: string;
|
|
84
|
-
params?: Record<string, unknown>;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export async function serveRelay(options: RelayOptions = {}): Promise<RelayServer> {
|
|
88
|
-
const port = options.port ?? 9224;
|
|
89
|
-
const host = options.host ?? "127.0.0.1";
|
|
90
|
-
|
|
91
|
-
const connectedTargets = new Map<string, ConnectedTarget>();
|
|
92
|
-
const namedPages = new Map<string, string>();
|
|
93
|
-
const playwrightClients = new Map<string, PlaywrightClient>();
|
|
94
|
-
let extensionWs: WSContext | null = null;
|
|
95
|
-
|
|
96
|
-
const extensionPendingRequests = new Map<
|
|
97
|
-
number,
|
|
98
|
-
{
|
|
99
|
-
resolve: (result: unknown) => void;
|
|
100
|
-
reject: (error: Error) => void;
|
|
101
|
-
}
|
|
102
|
-
>();
|
|
103
|
-
let extensionMessageId = 0;
|
|
104
|
-
|
|
105
|
-
function log(...args: unknown[]) {
|
|
106
|
-
console.log("[relay]", ...args);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function sendToPlaywright(message: CDPResponse | CDPEvent, clientId?: string) {
|
|
110
|
-
const messageStr = JSON.stringify(message);
|
|
111
|
-
|
|
112
|
-
if (clientId) {
|
|
113
|
-
const client = playwrightClients.get(clientId);
|
|
114
|
-
if (client) {
|
|
115
|
-
client.ws.send(messageStr);
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
for (const client of playwrightClients.values()) {
|
|
119
|
-
client.ws.send(messageStr);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function sendAttachedToTarget(
|
|
125
|
-
target: ConnectedTarget,
|
|
126
|
-
clientId?: string,
|
|
127
|
-
waitingForDebugger = false
|
|
128
|
-
) {
|
|
129
|
-
const event: CDPEvent = {
|
|
130
|
-
method: "Target.attachedToTarget",
|
|
131
|
-
params: {
|
|
132
|
-
sessionId: target.sessionId,
|
|
133
|
-
targetInfo: { ...target.targetInfo, attached: true },
|
|
134
|
-
waitingForDebugger,
|
|
135
|
-
},
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
if (clientId) {
|
|
139
|
-
const client = playwrightClients.get(clientId);
|
|
140
|
-
if (client && !client.knownTargets.has(target.targetId)) {
|
|
141
|
-
client.knownTargets.add(target.targetId);
|
|
142
|
-
client.ws.send(JSON.stringify(event));
|
|
143
|
-
}
|
|
144
|
-
} else {
|
|
145
|
-
for (const client of playwrightClients.values()) {
|
|
146
|
-
if (!client.knownTargets.has(target.targetId)) {
|
|
147
|
-
client.knownTargets.add(target.targetId);
|
|
148
|
-
client.ws.send(JSON.stringify(event));
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
async function sendToExtension({
|
|
155
|
-
method,
|
|
156
|
-
params,
|
|
157
|
-
timeout = 30000,
|
|
158
|
-
}: {
|
|
159
|
-
method: string;
|
|
160
|
-
params?: Record<string, unknown>;
|
|
161
|
-
timeout?: number;
|
|
162
|
-
}): Promise<unknown> {
|
|
163
|
-
if (!extensionWs) {
|
|
164
|
-
throw new Error("Extension not connected");
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const id = ++extensionMessageId;
|
|
168
|
-
const message = { id, method, params };
|
|
169
|
-
|
|
170
|
-
extensionWs.send(JSON.stringify(message));
|
|
171
|
-
|
|
172
|
-
return new Promise((resolve, reject) => {
|
|
173
|
-
const timeoutId = setTimeout(() => {
|
|
174
|
-
extensionPendingRequests.delete(id);
|
|
175
|
-
reject(new Error(`Extension request timeout after ${timeout}ms: ${method}`));
|
|
176
|
-
}, timeout);
|
|
177
|
-
|
|
178
|
-
extensionPendingRequests.set(id, {
|
|
179
|
-
resolve: (result) => {
|
|
180
|
-
clearTimeout(timeoutId);
|
|
181
|
-
resolve(result);
|
|
182
|
-
},
|
|
183
|
-
reject: (error) => {
|
|
184
|
-
clearTimeout(timeoutId);
|
|
185
|
-
reject(error);
|
|
186
|
-
},
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async function routeCdpCommand({
|
|
192
|
-
method,
|
|
193
|
-
params,
|
|
194
|
-
sessionId,
|
|
195
|
-
}: {
|
|
196
|
-
method: string;
|
|
197
|
-
params?: Record<string, unknown>;
|
|
198
|
-
sessionId?: string;
|
|
199
|
-
}): Promise<unknown> {
|
|
200
|
-
switch (method) {
|
|
201
|
-
case "Browser.getVersion":
|
|
202
|
-
return {
|
|
203
|
-
protocolVersion: "1.3",
|
|
204
|
-
product: "Chrome/Extension-Bridge",
|
|
205
|
-
revision: "1.0.0",
|
|
206
|
-
userAgent: "dev-browser-relay/1.0.0",
|
|
207
|
-
jsVersion: "V8",
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
case "Browser.setDownloadBehavior":
|
|
211
|
-
return {};
|
|
212
|
-
|
|
213
|
-
case "Target.setAutoAttach":
|
|
214
|
-
if (sessionId) break;
|
|
215
|
-
return {};
|
|
216
|
-
|
|
217
|
-
case "Target.setDiscoverTargets":
|
|
218
|
-
return {};
|
|
219
|
-
|
|
220
|
-
case "Target.attachToBrowserTarget":
|
|
221
|
-
return { sessionId: "browser" };
|
|
222
|
-
|
|
223
|
-
case "Target.detachFromTarget":
|
|
224
|
-
if (sessionId === "browser" || params?.sessionId === "browser") {
|
|
225
|
-
return {};
|
|
226
|
-
}
|
|
227
|
-
break;
|
|
228
|
-
|
|
229
|
-
case "Target.attachToTarget": {
|
|
230
|
-
const targetId = params?.targetId as string;
|
|
231
|
-
if (!targetId) {
|
|
232
|
-
throw new Error("targetId is required for Target.attachToTarget");
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
for (const target of connectedTargets.values()) {
|
|
236
|
-
if (target.targetId === targetId) {
|
|
237
|
-
return { sessionId: target.sessionId };
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
throw new Error(`Target ${targetId} not found in connected targets`);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
case "Target.getTargetInfo": {
|
|
245
|
-
const targetId = params?.targetId as string;
|
|
246
|
-
|
|
247
|
-
if (targetId) {
|
|
248
|
-
for (const target of connectedTargets.values()) {
|
|
249
|
-
if (target.targetId === targetId) {
|
|
250
|
-
return { targetInfo: target.targetInfo };
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (sessionId) {
|
|
256
|
-
const target = connectedTargets.get(sessionId);
|
|
257
|
-
if (target) {
|
|
258
|
-
return { targetInfo: target.targetInfo };
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const firstTarget = Array.from(connectedTargets.values())[0];
|
|
263
|
-
return { targetInfo: firstTarget?.targetInfo };
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
case "Target.getTargets":
|
|
267
|
-
return {
|
|
268
|
-
targetInfos: Array.from(connectedTargets.values()).map((t) => ({
|
|
269
|
-
...t.targetInfo,
|
|
270
|
-
attached: true,
|
|
271
|
-
})),
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
case "Target.createTarget":
|
|
275
|
-
case "Target.closeTarget":
|
|
276
|
-
return await sendToExtension({
|
|
277
|
-
method: "forwardCDPCommand",
|
|
278
|
-
params: { method, params },
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return await sendToExtension({
|
|
283
|
-
method: "forwardCDPCommand",
|
|
284
|
-
params: { sessionId, method, params },
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const app = new Hono();
|
|
289
|
-
const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });
|
|
290
|
-
|
|
291
|
-
app.get("/", (c) => {
|
|
292
|
-
return c.json({
|
|
293
|
-
wsEndpoint: `ws://${host}:${port}/cdp`,
|
|
294
|
-
extensionConnected: extensionWs !== null,
|
|
295
|
-
mode: "extension",
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
app.get("/pages", (c) => {
|
|
300
|
-
return c.json({
|
|
301
|
-
pages: Array.from(namedPages.keys()),
|
|
302
|
-
});
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
app.post("/pages", async (c) => {
|
|
306
|
-
const body = await c.req.json();
|
|
307
|
-
const name = body.name as string;
|
|
308
|
-
|
|
309
|
-
if (!name) {
|
|
310
|
-
return c.json({ error: "name is required" }, 400);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const existingSessionId = namedPages.get(name);
|
|
314
|
-
if (existingSessionId) {
|
|
315
|
-
const target = connectedTargets.get(existingSessionId);
|
|
316
|
-
if (target) {
|
|
317
|
-
await sendToExtension({
|
|
318
|
-
method: "forwardCDPCommand",
|
|
319
|
-
params: {
|
|
320
|
-
method: "Target.activateTarget",
|
|
321
|
-
params: { targetId: target.targetId },
|
|
322
|
-
},
|
|
323
|
-
});
|
|
324
|
-
return c.json({
|
|
325
|
-
wsEndpoint: `ws://${host}:${port}/cdp`,
|
|
326
|
-
name,
|
|
327
|
-
targetId: target.targetId,
|
|
328
|
-
url: target.targetInfo.url,
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
namedPages.delete(name);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
if (!extensionWs) {
|
|
335
|
-
return c.json({ error: "Extension not connected" }, 503);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
try {
|
|
339
|
-
const result = (await sendToExtension({
|
|
340
|
-
method: "forwardCDPCommand",
|
|
341
|
-
params: { method: "Target.createTarget", params: { url: "about:blank" } },
|
|
342
|
-
})) as { targetId: string };
|
|
343
|
-
|
|
344
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
345
|
-
|
|
346
|
-
for (const [sessionId, target] of connectedTargets) {
|
|
347
|
-
if (target.targetId === result.targetId) {
|
|
348
|
-
namedPages.set(name, sessionId);
|
|
349
|
-
await sendToExtension({
|
|
350
|
-
method: "forwardCDPCommand",
|
|
351
|
-
params: {
|
|
352
|
-
method: "Target.activateTarget",
|
|
353
|
-
params: { targetId: target.targetId },
|
|
354
|
-
},
|
|
355
|
-
});
|
|
356
|
-
return c.json({
|
|
357
|
-
wsEndpoint: `ws://${host}:${port}/cdp`,
|
|
358
|
-
name,
|
|
359
|
-
targetId: target.targetId,
|
|
360
|
-
url: target.targetInfo.url,
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
throw new Error("Target created but not found in registry");
|
|
366
|
-
} catch (err) {
|
|
367
|
-
log("Error creating tab:", err);
|
|
368
|
-
return c.json({ error: (err as Error).message }, 500);
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
app.delete("/pages/:name", (c) => {
|
|
373
|
-
const name = c.req.param("name");
|
|
374
|
-
const deleted = namedPages.delete(name);
|
|
375
|
-
return c.json({ success: deleted });
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
app.get(
|
|
379
|
-
"/cdp/:clientId?",
|
|
380
|
-
upgradeWebSocket((c) => {
|
|
381
|
-
const clientId =
|
|
382
|
-
c.req.param("clientId") || `client-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
383
|
-
|
|
384
|
-
return {
|
|
385
|
-
onOpen(_event, ws) {
|
|
386
|
-
if (playwrightClients.has(clientId)) {
|
|
387
|
-
log(`Rejecting duplicate client ID: ${clientId}`);
|
|
388
|
-
ws.close(1000, "Client ID already connected");
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
playwrightClients.set(clientId, { id: clientId, ws, knownTargets: new Set() });
|
|
393
|
-
log(`Playwright client connected: ${clientId}`);
|
|
394
|
-
},
|
|
395
|
-
|
|
396
|
-
async onMessage(event, _ws) {
|
|
397
|
-
let message: CDPCommand;
|
|
398
|
-
|
|
399
|
-
try {
|
|
400
|
-
message = JSON.parse(event.data.toString());
|
|
401
|
-
} catch {
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
const { id, sessionId, method, params } = message;
|
|
406
|
-
|
|
407
|
-
if (!extensionWs) {
|
|
408
|
-
sendToPlaywright(
|
|
409
|
-
{
|
|
410
|
-
id,
|
|
411
|
-
sessionId,
|
|
412
|
-
error: { message: "Extension not connected" },
|
|
413
|
-
},
|
|
414
|
-
clientId
|
|
415
|
-
);
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
try {
|
|
420
|
-
const result = await routeCdpCommand({ method, params, sessionId });
|
|
421
|
-
|
|
422
|
-
if (method === "Target.setAutoAttach" && !sessionId) {
|
|
423
|
-
for (const target of connectedTargets.values()) {
|
|
424
|
-
sendAttachedToTarget(target, clientId);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
if (
|
|
429
|
-
method === "Target.setDiscoverTargets" &&
|
|
430
|
-
(params as { discover?: boolean })?.discover
|
|
431
|
-
) {
|
|
432
|
-
for (const target of connectedTargets.values()) {
|
|
433
|
-
sendToPlaywright(
|
|
434
|
-
{
|
|
435
|
-
method: "Target.targetCreated",
|
|
436
|
-
params: {
|
|
437
|
-
targetInfo: { ...target.targetInfo, attached: true },
|
|
438
|
-
},
|
|
439
|
-
},
|
|
440
|
-
clientId
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
if (
|
|
446
|
-
method === "Target.attachToTarget" &&
|
|
447
|
-
(result as { sessionId?: string })?.sessionId
|
|
448
|
-
) {
|
|
449
|
-
const targetId = params?.targetId as string;
|
|
450
|
-
const target = Array.from(connectedTargets.values()).find(
|
|
451
|
-
(t) => t.targetId === targetId
|
|
452
|
-
);
|
|
453
|
-
if (target) {
|
|
454
|
-
sendAttachedToTarget(target, clientId);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
sendToPlaywright({ id, sessionId, result }, clientId);
|
|
459
|
-
} catch (e) {
|
|
460
|
-
log("Error handling CDP command:", method, e);
|
|
461
|
-
sendToPlaywright(
|
|
462
|
-
{
|
|
463
|
-
id,
|
|
464
|
-
sessionId,
|
|
465
|
-
error: { message: (e as Error).message },
|
|
466
|
-
},
|
|
467
|
-
clientId
|
|
468
|
-
);
|
|
469
|
-
}
|
|
470
|
-
},
|
|
471
|
-
|
|
472
|
-
onClose() {
|
|
473
|
-
playwrightClients.delete(clientId);
|
|
474
|
-
log(`Playwright client disconnected: ${clientId}`);
|
|
475
|
-
},
|
|
476
|
-
|
|
477
|
-
onError(event) {
|
|
478
|
-
log(`Playwright WebSocket error [${clientId}]:`, event);
|
|
479
|
-
},
|
|
480
|
-
};
|
|
481
|
-
})
|
|
482
|
-
);
|
|
483
|
-
|
|
484
|
-
app.get(
|
|
485
|
-
"/extension",
|
|
486
|
-
upgradeWebSocket(() => {
|
|
487
|
-
return {
|
|
488
|
-
onOpen(_event, ws) {
|
|
489
|
-
if (extensionWs) {
|
|
490
|
-
log("Closing existing extension connection");
|
|
491
|
-
extensionWs.close(4001, "Extension Replaced");
|
|
492
|
-
|
|
493
|
-
connectedTargets.clear();
|
|
494
|
-
namedPages.clear();
|
|
495
|
-
for (const pending of extensionPendingRequests.values()) {
|
|
496
|
-
pending.reject(new Error("Extension connection replaced"));
|
|
497
|
-
}
|
|
498
|
-
extensionPendingRequests.clear();
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
extensionWs = ws;
|
|
502
|
-
log("Extension connected");
|
|
503
|
-
},
|
|
504
|
-
|
|
505
|
-
async onMessage(event, ws) {
|
|
506
|
-
let message: ExtensionMessage;
|
|
507
|
-
|
|
508
|
-
try {
|
|
509
|
-
message = JSON.parse(event.data.toString());
|
|
510
|
-
} catch {
|
|
511
|
-
ws.close(1000, "Invalid JSON");
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if ("id" in message && typeof message.id === "number") {
|
|
516
|
-
const pending = extensionPendingRequests.get(message.id);
|
|
517
|
-
if (!pending) {
|
|
518
|
-
log("Unexpected response with id:", message.id);
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
extensionPendingRequests.delete(message.id);
|
|
523
|
-
|
|
524
|
-
if ((message as ExtensionResponseMessage).error) {
|
|
525
|
-
pending.reject(new Error((message as ExtensionResponseMessage).error));
|
|
526
|
-
} else {
|
|
527
|
-
pending.resolve((message as ExtensionResponseMessage).result);
|
|
528
|
-
}
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
if ("method" in message && message.method === "log") {
|
|
533
|
-
const { level, args } = message.params;
|
|
534
|
-
console.log(`[extension:${level}]`, ...args);
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if ("method" in message && message.method === "forwardCDPEvent") {
|
|
539
|
-
const eventMsg = message as ExtensionEventMessage;
|
|
540
|
-
const { method, params, sessionId } = eventMsg.params;
|
|
541
|
-
|
|
542
|
-
if (method === "Target.attachedToTarget") {
|
|
543
|
-
const targetParams = params as {
|
|
544
|
-
sessionId: string;
|
|
545
|
-
targetInfo: TargetInfo;
|
|
546
|
-
};
|
|
547
|
-
|
|
548
|
-
const target: ConnectedTarget = {
|
|
549
|
-
sessionId: targetParams.sessionId,
|
|
550
|
-
targetId: targetParams.targetInfo.targetId,
|
|
551
|
-
targetInfo: targetParams.targetInfo,
|
|
552
|
-
};
|
|
553
|
-
connectedTargets.set(targetParams.sessionId, target);
|
|
554
|
-
|
|
555
|
-
log(`Target attached: ${targetParams.targetInfo.url} (${targetParams.sessionId})`);
|
|
556
|
-
|
|
557
|
-
sendAttachedToTarget(target);
|
|
558
|
-
} else if (method === "Target.detachedFromTarget") {
|
|
559
|
-
const detachParams = params as { sessionId: string };
|
|
560
|
-
connectedTargets.delete(detachParams.sessionId);
|
|
561
|
-
|
|
562
|
-
for (const [name, sid] of namedPages) {
|
|
563
|
-
if (sid === detachParams.sessionId) {
|
|
564
|
-
namedPages.delete(name);
|
|
565
|
-
break;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
log(`Target detached: ${detachParams.sessionId}`);
|
|
570
|
-
|
|
571
|
-
sendToPlaywright({
|
|
572
|
-
method: "Target.detachedFromTarget",
|
|
573
|
-
params: detachParams,
|
|
574
|
-
});
|
|
575
|
-
} else if (method === "Target.targetInfoChanged") {
|
|
576
|
-
const infoParams = params as { targetInfo: TargetInfo };
|
|
577
|
-
for (const target of connectedTargets.values()) {
|
|
578
|
-
if (target.targetId === infoParams.targetInfo.targetId) {
|
|
579
|
-
target.targetInfo = infoParams.targetInfo;
|
|
580
|
-
break;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
sendToPlaywright({
|
|
585
|
-
method: "Target.targetInfoChanged",
|
|
586
|
-
params: infoParams,
|
|
587
|
-
});
|
|
588
|
-
} else {
|
|
589
|
-
sendToPlaywright({
|
|
590
|
-
sessionId,
|
|
591
|
-
method,
|
|
592
|
-
params,
|
|
593
|
-
});
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
},
|
|
597
|
-
|
|
598
|
-
onClose(_event, ws) {
|
|
599
|
-
if (extensionWs && extensionWs !== ws) {
|
|
600
|
-
log("Old extension connection closed");
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
log("Extension disconnected");
|
|
605
|
-
|
|
606
|
-
for (const pending of extensionPendingRequests.values()) {
|
|
607
|
-
pending.reject(new Error("Extension connection closed"));
|
|
608
|
-
}
|
|
609
|
-
extensionPendingRequests.clear();
|
|
610
|
-
|
|
611
|
-
extensionWs = null;
|
|
612
|
-
connectedTargets.clear();
|
|
613
|
-
namedPages.clear();
|
|
614
|
-
|
|
615
|
-
for (const client of playwrightClients.values()) {
|
|
616
|
-
client.ws.close(1000, "Extension disconnected");
|
|
617
|
-
}
|
|
618
|
-
playwrightClients.clear();
|
|
619
|
-
},
|
|
620
|
-
|
|
621
|
-
onError(event) {
|
|
622
|
-
log("Extension WebSocket error:", event);
|
|
623
|
-
},
|
|
624
|
-
};
|
|
625
|
-
})
|
|
626
|
-
);
|
|
627
|
-
|
|
628
|
-
const server = serve({ fetch: app.fetch, port, hostname: host });
|
|
629
|
-
injectWebSocket(server);
|
|
630
|
-
|
|
631
|
-
const wsEndpoint = `ws://${host}:${port}/cdp`;
|
|
632
|
-
|
|
633
|
-
log("CDP relay server started");
|
|
634
|
-
log(` HTTP: http://${host}:${port}`);
|
|
635
|
-
log(` CDP endpoint: ${wsEndpoint}`);
|
|
636
|
-
log(` Extension endpoint: ws://${host}:${port}/extension`);
|
|
637
|
-
log("");
|
|
638
|
-
log("Waiting for extension to connect...");
|
|
639
|
-
|
|
640
|
-
return {
|
|
641
|
-
wsEndpoint,
|
|
642
|
-
port,
|
|
643
|
-
async stop() {
|
|
644
|
-
for (const client of playwrightClients.values()) {
|
|
645
|
-
client.ws.close(1000, "Server stopped");
|
|
646
|
-
}
|
|
647
|
-
playwrightClients.clear();
|
|
648
|
-
extensionWs?.close(1000, "Server stopped");
|
|
649
|
-
server.close();
|
|
650
|
-
},
|
|
651
|
-
};
|
|
652
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export interface ServeOptions {
|
|
2
|
-
port?: number;
|
|
3
|
-
headless?: boolean;
|
|
4
|
-
cdpPort?: number;
|
|
5
|
-
profileDir?: string;
|
|
6
|
-
useSystemChrome?: boolean;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface ViewportSize {
|
|
10
|
-
width: number;
|
|
11
|
-
height: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface GetPageRequest {
|
|
15
|
-
name: string;
|
|
16
|
-
viewport?: ViewportSize;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface GetPageResponse {
|
|
20
|
-
wsEndpoint: string;
|
|
21
|
-
name: string;
|
|
22
|
-
targetId: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface ListPagesResponse {
|
|
26
|
-
pages: string[];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface ServerInfoResponse {
|
|
30
|
-
wsEndpoint: string;
|
|
31
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
// Environment setup & latest features
|
|
4
|
-
"lib": ["ESNext"],
|
|
5
|
-
"target": "ESNext",
|
|
6
|
-
"module": "Preserve",
|
|
7
|
-
"moduleDetection": "force",
|
|
8
|
-
"jsx": "react-jsx",
|
|
9
|
-
"allowJs": true,
|
|
10
|
-
|
|
11
|
-
// Bundler mode
|
|
12
|
-
"moduleResolution": "bundler",
|
|
13
|
-
"allowImportingTsExtensions": true,
|
|
14
|
-
"verbatimModuleSyntax": true,
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
|
|
17
|
-
// Path aliases
|
|
18
|
-
"baseUrl": ".",
|
|
19
|
-
"paths": {
|
|
20
|
-
"@/*": ["./src/*"]
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
// Best practices
|
|
24
|
-
"strict": true,
|
|
25
|
-
"skipLibCheck": true,
|
|
26
|
-
"noFallthroughCasesInSwitch": true,
|
|
27
|
-
"noUncheckedIndexedAccess": true,
|
|
28
|
-
"noImplicitOverride": true,
|
|
29
|
-
|
|
30
|
-
// Some stricter flags (disabled by default)
|
|
31
|
-
"noUnusedLocals": false,
|
|
32
|
-
"noUnusedParameters": false,
|
|
33
|
-
"noPropertyAccessFromIndexSignature": false
|
|
34
|
-
},
|
|
35
|
-
"include": ["src/**/*", "scripts/**/*"]
|
|
36
|
-
}
|