abelworkflow 1.2.3 → 1.3.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.
Files changed (63) hide show
  1. package/README.md +26 -25
  2. package/extensions/gpt-responses-compat.ts +166 -27
  3. package/lib/cli/main.mjs +18 -86
  4. package/lib/cli/pi.mjs +43 -0
  5. package/lib/cli/prompts.mjs +3 -3
  6. package/lib/installer/assets.mjs +35 -31
  7. package/lib/installer/install.mjs +29 -9
  8. package/lib/installer/links.mjs +97 -84
  9. package/lib/paths.mjs +0 -2
  10. package/lib/providers/claude.mjs +14 -3
  11. package/lib/providers/codex.mjs +14 -9
  12. package/lib/providers/pi.mjs +61 -68
  13. package/lib/providers/skills.mjs +22 -22
  14. package/lib/providers/url.mjs +32 -1
  15. package/lib/templates/codex/agents/default.toml +16 -54
  16. package/lib/templates/codex/agents/explorer.toml +25 -52
  17. package/lib/templates/codex/agents/planner.toml +23 -77
  18. package/lib/templates/codex/agents/reviewer.toml +16 -62
  19. package/lib/templates/codex/agents/worker.toml +30 -64
  20. package/lib/templates/codex/config-base.toml +0 -6
  21. package/lib/templates/{workflow/gitignore.template → gitignore.template} +0 -3
  22. package/lib/tools/cli-installer.mjs +40 -12
  23. package/package.json +13 -18
  24. package/lib/templates/workflow/AGENTS.md +0 -50
  25. package/lib/templates/workflow/commands/abel-design.md +0 -175
  26. package/lib/templates/workflow/commands/abel-diagnose.md +0 -63
  27. package/lib/templates/workflow/commands/abel-implement.md +0 -170
  28. package/lib/templates/workflow/commands/abel-init.md +0 -25
  29. package/skills/dev-browser/SKILL.md +0 -281
  30. package/skills/dev-browser/dist/scripts/start.d.ts +0 -1
  31. package/skills/dev-browser/dist/scripts/start.js +0 -90
  32. package/skills/dev-browser/dist/src/client.d.ts +0 -92
  33. package/skills/dev-browser/dist/src/client.js +0 -310
  34. package/skills/dev-browser/dist/src/entrypoint.d.ts +0 -29
  35. package/skills/dev-browser/dist/src/entrypoint.js +0 -113
  36. package/skills/dev-browser/dist/src/index.d.ts +0 -3
  37. package/skills/dev-browser/dist/src/index.js +0 -1
  38. package/skills/dev-browser/dist/src/page-api.d.ts +0 -24
  39. package/skills/dev-browser/dist/src/page-api.js +0 -103
  40. package/skills/dev-browser/dist/src/relay.d.ts +0 -26
  41. package/skills/dev-browser/dist/src/relay.js +0 -567
  42. package/skills/dev-browser/dist/src/runtime.d.ts +0 -34
  43. package/skills/dev-browser/dist/src/runtime.js +0 -44
  44. package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts +0 -22
  45. package/skills/dev-browser/dist/src/snapshot/browser-script.js +0 -868
  46. package/skills/dev-browser/dist/src/snapshot/index.d.ts +0 -13
  47. package/skills/dev-browser/dist/src/snapshot/index.js +0 -13
  48. package/skills/dev-browser/dist/src/snapshot/inject.d.ts +0 -12
  49. package/skills/dev-browser/dist/src/snapshot/inject.js +0 -12
  50. package/skills/dev-browser/dist/src/standalone.d.ts +0 -31
  51. package/skills/dev-browser/dist/src/standalone.js +0 -173
  52. package/skills/dev-browser/dist/src/startup.d.ts +0 -46
  53. package/skills/dev-browser/dist/src/startup.js +0 -77
  54. package/skills/dev-browser/dist/src/target-registry.d.ts +0 -28
  55. package/skills/dev-browser/dist/src/target-registry.js +0 -134
  56. package/skills/dev-browser/dist/src/types.d.ts +0 -26
  57. package/skills/dev-browser/dist/src/types.js +0 -1
  58. package/skills/dev-browser/package-lock.json +0 -1545
  59. package/skills/dev-browser/package.json +0 -35
  60. package/skills/dev-browser/references/scraping.md +0 -144
  61. package/skills/git-commit/SKILL.md +0 -124
  62. package/skills/time/SKILL.md +0 -119
  63. package/skills/time/scripts/time_cli.py +0 -143
@@ -1,567 +0,0 @@
1
- import { serve } from "@hono/node-server";
2
- import { createNodeWebSocket } from "@hono/node-ws";
3
- import { Hono } from "hono";
4
- import { formatHttpUrl, formatWsUrl, normalizeLoopbackHost } from "./entrypoint.js";
5
- import { PageBackendError, createPageApi, } from "./page-api.js";
6
- import { createTargetRegistry, } from "./target-registry.js";
7
- export const WEBSOCKET_POLICY_VIOLATION_CODE = 1008;
8
- export const CDP_ORIGIN_POLICY_REASON = "CDP endpoint requires an originless client";
9
- export const EXTENSION_ORIGIN_POLICY_REASON = "Extension endpoint requires originless or chrome-extension client";
10
- export function isTrustedCdpOrigin(origin) {
11
- return origin === undefined;
12
- }
13
- export function isTrustedExtensionOrigin(origin) {
14
- if (origin === undefined)
15
- return true;
16
- try {
17
- const url = new URL(origin);
18
- return (url.protocol === "chrome-extension:" &&
19
- /^[a-p]{32}$/.test(url.hostname) &&
20
- (url.pathname === "" || url.pathname === "/") &&
21
- url.username === "" &&
22
- url.password === "" &&
23
- url.port === "" &&
24
- url.search === "" &&
25
- url.hash === "");
26
- }
27
- catch {
28
- return false;
29
- }
30
- }
31
- function isRecord(value) {
32
- return typeof value === "object" && value !== null && !Array.isArray(value);
33
- }
34
- function isCdpCommand(value) {
35
- return isRecord(value)
36
- && typeof value.id === "number"
37
- && Number.isFinite(value.id)
38
- && typeof value.method === "string"
39
- && (value.params === undefined || isRecord(value.params))
40
- && (value.sessionId === undefined || typeof value.sessionId === "string");
41
- }
42
- function isTargetInfo(value) {
43
- return isRecord(value)
44
- && typeof value.targetId === "string"
45
- && typeof value.type === "string"
46
- && typeof value.title === "string"
47
- && typeof value.url === "string"
48
- && typeof value.attached === "boolean";
49
- }
50
- function isExtensionEvent(value) {
51
- if (!isRecord(value) || value.method !== "forwardCDPEvent" || !isRecord(value.params)) {
52
- return false;
53
- }
54
- const event = value.params;
55
- if (typeof event.method !== "string"
56
- || (event.params !== undefined && !isRecord(event.params))
57
- || (event.sessionId !== undefined && typeof event.sessionId !== "string")) {
58
- return false;
59
- }
60
- if (event.method === "Target.attachedToTarget") {
61
- return isRecord(event.params)
62
- && typeof event.params.sessionId === "string"
63
- && isTargetInfo(event.params.targetInfo);
64
- }
65
- if (event.method === "Target.detachedFromTarget") {
66
- return isRecord(event.params) && typeof event.params.sessionId === "string";
67
- }
68
- if (event.method === "Target.targetInfoChanged") {
69
- return isRecord(event.params) && isTargetInfo(event.params.targetInfo);
70
- }
71
- return true;
72
- }
73
- export function createExtensionPageBackend({ registry, isConnected, sendCommand, timeoutMs, }) {
74
- const pending = new Map();
75
- async function create(name) {
76
- if (!isConnected())
77
- throw new PageBackendError(503, "extension not connected");
78
- const result = (await sendCommand("Target.createTarget", { url: "about:blank" }));
79
- if (typeof result?.targetId !== "string" || result.targetId.length === 0) {
80
- throw new PageBackendError(502, "extension returned an invalid targetId");
81
- }
82
- if (!isConnected()) {
83
- throw new PageBackendError(503, "extension connection closed");
84
- }
85
- let target;
86
- try {
87
- target = await registry.waitForAttach(result.targetId, timeoutMs);
88
- }
89
- catch (error) {
90
- if (error instanceof PageBackendError)
91
- throw error;
92
- const timeout = new PageBackendError(504, errorMessage(error));
93
- try {
94
- await sendCommand("Target.closeTarget", { targetId: result.targetId });
95
- }
96
- catch { }
97
- throw timeout;
98
- }
99
- registry.bindName(name, target.targetId);
100
- return { name, targetId: target.targetId };
101
- }
102
- return {
103
- async list() {
104
- return registry.list();
105
- },
106
- async getOrCreate(name, viewport) {
107
- if (viewport) {
108
- throw new PageBackendError(400, "viewport is not supported in extension mode");
109
- }
110
- const existing = registry.getByName(name);
111
- if (existing)
112
- return { name, targetId: existing.targetId };
113
- const inFlight = pending.get(name);
114
- if (inFlight)
115
- return inFlight;
116
- const creation = create(name);
117
- pending.set(name, creation);
118
- try {
119
- return await creation;
120
- }
121
- finally {
122
- if (pending.get(name) === creation)
123
- pending.delete(name);
124
- }
125
- },
126
- async close(name) {
127
- const target = registry.getByName(name);
128
- if (!target)
129
- return false;
130
- if (!isConnected())
131
- throw new PageBackendError(503, "extension not connected");
132
- const result = (await sendCommand("Target.closeTarget", {
133
- targetId: target.targetId,
134
- }));
135
- if (result?.success !== true) {
136
- throw new PageBackendError(502, `extension failed to close target ${target.targetId}`);
137
- }
138
- if (!isConnected()) {
139
- throw new PageBackendError(503, "extension connection closed");
140
- }
141
- try {
142
- await registry.waitForDetach(target.targetId, timeoutMs);
143
- }
144
- catch (error) {
145
- if (error instanceof PageBackendError)
146
- throw error;
147
- throw new PageBackendError(504, errorMessage(error));
148
- }
149
- return true;
150
- },
151
- };
152
- }
153
- export async function serveRelay(options = {}) {
154
- const requestedPort = options.port ?? 9222;
155
- const host = normalizeLoopbackHost(options.host ?? "127.0.0.1");
156
- if (!Number.isInteger(requestedPort) || requestedPort < 1 || requestedPort > 65535) {
157
- throw new Error(`Invalid port: ${requestedPort}. Must be between 1 and 65535`);
158
- }
159
- const targetTimeoutMs = options.targetTimeoutMs ?? 5000;
160
- const wsEndpoint = formatWsUrl(host, requestedPort, "/cdp");
161
- const registry = createTargetRegistry();
162
- const playwrightClients = new Map();
163
- const extensionPending = new Map();
164
- let extensionWs = null;
165
- let extensionMessageId = 0;
166
- let virtualSessionId = 0;
167
- function log(...args) {
168
- console.log("[relay]", ...args);
169
- }
170
- function isPlaywrightClientOwner(client) {
171
- return playwrightClients.get(client.id) === client;
172
- }
173
- function sendToPlaywright(message, client) {
174
- const encoded = JSON.stringify(message);
175
- if (client) {
176
- if (isPlaywrightClientOwner(client))
177
- client.ws.send(encoded);
178
- return;
179
- }
180
- for (const client of playwrightClients.values())
181
- client.ws.send(encoded);
182
- }
183
- function sendAttached(target, client) {
184
- const event = {
185
- method: "Target.attachedToTarget",
186
- params: {
187
- sessionId: target.sessionId,
188
- targetInfo: { ...target.targetInfo, attached: true },
189
- waitingForDebugger: false,
190
- },
191
- };
192
- const clients = client ? [client] : playwrightClients.values();
193
- for (const owner of clients) {
194
- if (!isPlaywrightClientOwner(owner) || owner.knownTargets.has(target.targetId))
195
- continue;
196
- owner.knownTargets.add(target.targetId);
197
- owner.ws.send(JSON.stringify(event));
198
- }
199
- }
200
- function createSessionAlias(client, physicalSessionId, parentSessionId) {
201
- let sessionId;
202
- do {
203
- sessionId = `dev-browser-virtual-${++virtualSessionId}`;
204
- } while (registry.getBySessionId(sessionId) || client.sessionAliases.has(sessionId));
205
- client.sessionAliases.set(sessionId, { physicalSessionId, parentSessionId });
206
- return sessionId;
207
- }
208
- function resolveSessionId(client, sessionId) {
209
- return sessionId
210
- ? (client.sessionAliases.get(sessionId)?.physicalSessionId ?? sessionId)
211
- : undefined;
212
- }
213
- function sendSessionEvent(method, params, sessionId) {
214
- for (const client of playwrightClients.values()) {
215
- client.ws.send(JSON.stringify({ method, params, sessionId }));
216
- if (!sessionId)
217
- continue;
218
- for (const [alias, binding] of client.sessionAliases) {
219
- if (binding.physicalSessionId !== sessionId)
220
- continue;
221
- client.ws.send(JSON.stringify({ method, params, sessionId: alias }));
222
- }
223
- }
224
- }
225
- function sendDetached(physicalSessionId, params, target) {
226
- const physicalParams = { ...params, sessionId: physicalSessionId };
227
- for (const client of playwrightClients.values()) {
228
- if (target)
229
- client.knownTargets.delete(target.targetId);
230
- client.ws.send(JSON.stringify({ method: "Target.detachedFromTarget", params: physicalParams }));
231
- for (const [alias, binding] of client.sessionAliases) {
232
- if (binding.physicalSessionId !== physicalSessionId)
233
- continue;
234
- client.sessionAliases.delete(alias);
235
- client.ws.send(JSON.stringify({
236
- method: "Target.detachedFromTarget",
237
- params: { ...params, sessionId: alias },
238
- sessionId: binding.parentSessionId,
239
- }));
240
- }
241
- }
242
- }
243
- function rejectExtensionPending(error) {
244
- for (const pending of extensionPending.values())
245
- pending.reject(error);
246
- extensionPending.clear();
247
- }
248
- function closePlaywrightClients(reason) {
249
- for (const client of playwrightClients.values())
250
- client.ws.close(1000, reason);
251
- playwrightClients.clear();
252
- }
253
- function disconnectExtension(error) {
254
- rejectExtensionPending(error);
255
- registry.disconnect(error);
256
- extensionWs = null;
257
- closePlaywrightClients(error.message);
258
- }
259
- function closeInvalidExtension(ws, code, reason) {
260
- if (extensionWs === ws) {
261
- disconnectExtension(new PageBackendError(502, reason));
262
- }
263
- ws.close(code, reason);
264
- }
265
- async function sendToExtension(method, params, timeoutMs = 30_000) {
266
- const ws = extensionWs;
267
- if (!ws)
268
- throw new PageBackendError(503, "extension not connected");
269
- const id = ++extensionMessageId;
270
- ws.send(JSON.stringify({ id, method, params }));
271
- return new Promise((resolve, reject) => {
272
- const timer = setTimeout(() => {
273
- extensionPending.delete(id);
274
- reject(new Error(`Extension request timeout after ${timeoutMs}ms: ${method}`));
275
- }, timeoutMs);
276
- extensionPending.set(id, {
277
- resolve: (result) => {
278
- clearTimeout(timer);
279
- resolve(result);
280
- },
281
- reject: (error) => {
282
- clearTimeout(timer);
283
- reject(error);
284
- },
285
- });
286
- });
287
- }
288
- const sendCdpCommand = (method, params) => sendToExtension("forwardCDPCommand", { method, params });
289
- const pageBackend = createExtensionPageBackend({
290
- registry,
291
- isConnected: () => extensionWs !== null,
292
- sendCommand: sendCdpCommand,
293
- timeoutMs: targetTimeoutMs,
294
- });
295
- async function routeCdpCommand(client, { method, params, sessionId }) {
296
- const physicalSessionId = resolveSessionId(client, sessionId);
297
- switch (method) {
298
- case "Browser.getVersion":
299
- return {
300
- protocolVersion: "1.3",
301
- product: "Chrome/Extension-Bridge",
302
- revision: "1.0.0",
303
- userAgent: "dev-browser-relay/1.0.0",
304
- jsVersion: "V8",
305
- };
306
- case "Browser.setDownloadBehavior":
307
- case "Target.setDiscoverTargets":
308
- return {};
309
- case "Target.setAutoAttach":
310
- if (!sessionId)
311
- return {};
312
- break;
313
- case "Target.attachToBrowserTarget":
314
- return { sessionId: "browser" };
315
- case "Target.detachFromTarget": {
316
- const detachedSessionId = params?.sessionId;
317
- if (typeof detachedSessionId === "string" && client.sessionAliases.delete(detachedSessionId)) {
318
- return {};
319
- }
320
- if (sessionId === "browser" || params?.sessionId === "browser")
321
- return {};
322
- break;
323
- }
324
- case "Target.attachToTarget": {
325
- const targetId = params?.targetId;
326
- if (typeof targetId !== "string")
327
- throw new Error("targetId is required");
328
- const target = registry.getByTargetId(targetId);
329
- if (!target)
330
- throw new Error(`Target ${targetId} not found`);
331
- return {
332
- sessionId: createSessionAlias(client, target.sessionId, sessionId),
333
- };
334
- }
335
- case "Target.getTargetInfo": {
336
- const targetId = params?.targetId;
337
- const target = typeof targetId === "string"
338
- ? registry.getByTargetId(targetId)
339
- : physicalSessionId
340
- ? registry.getBySessionId(physicalSessionId)
341
- : undefined;
342
- return { targetInfo: target?.targetInfo };
343
- }
344
- case "Target.getTargets":
345
- return {
346
- targetInfos: registry.targets().map(({ targetInfo }) => ({
347
- ...targetInfo,
348
- attached: true,
349
- })),
350
- };
351
- case "Target.createTarget":
352
- case "Target.closeTarget":
353
- return sendCdpCommand(method, params);
354
- }
355
- return sendToExtension("forwardCDPCommand", {
356
- sessionId: physicalSessionId,
357
- method,
358
- params,
359
- });
360
- }
361
- const app = new Hono();
362
- const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });
363
- app.get("/", (c) => c.json({
364
- wsEndpoint,
365
- extensionConnected: extensionWs !== null,
366
- mode: "extension",
367
- }));
368
- app.route("/", createPageApi({ backend: pageBackend, wsEndpoint }));
369
- app.get("/cdp/:clientId?", upgradeWebSocket((c) => {
370
- const clientId = c.req.param("clientId") ?? `client-${Date.now()}-${Math.random().toString(36).slice(2)}`;
371
- const trustedOrigin = isTrustedCdpOrigin(c.req.header("origin"));
372
- return {
373
- onOpen(_event, ws) {
374
- if (!trustedOrigin) {
375
- ws.close(WEBSOCKET_POLICY_VIOLATION_CODE, CDP_ORIGIN_POLICY_REASON);
376
- return;
377
- }
378
- if (playwrightClients.has(clientId)) {
379
- ws.close(1000, "Client ID already connected");
380
- return;
381
- }
382
- playwrightClients.set(clientId, {
383
- id: clientId,
384
- ws,
385
- knownTargets: new Set(),
386
- sessionAliases: new Map(),
387
- });
388
- },
389
- async onMessage(event, ws) {
390
- if (!trustedOrigin)
391
- return;
392
- let parsed;
393
- try {
394
- parsed = JSON.parse(event.data.toString());
395
- }
396
- catch {
397
- return;
398
- }
399
- if (!isCdpCommand(parsed))
400
- return;
401
- const command = parsed;
402
- const { id, method, params, sessionId } = command;
403
- const client = playwrightClients.get(clientId);
404
- if (!client || client.ws !== ws)
405
- return;
406
- if (!extensionWs) {
407
- sendToPlaywright({ id, sessionId, error: { message: "extension not connected" } }, client);
408
- return;
409
- }
410
- try {
411
- const result = await routeCdpCommand(client, { method, params, sessionId });
412
- if (method === "Target.setAutoAttach" && !sessionId) {
413
- for (const target of registry.targets())
414
- sendAttached(target, client);
415
- }
416
- if (method === "Target.setDiscoverTargets" && params?.discover === true) {
417
- for (const target of registry.targets()) {
418
- sendToPlaywright({
419
- method: "Target.targetCreated",
420
- params: { targetInfo: { ...target.targetInfo, attached: true } },
421
- }, client);
422
- }
423
- }
424
- if (method === "Target.attachToTarget") {
425
- const targetId = params?.targetId;
426
- if (typeof targetId === "string") {
427
- const target = registry.getByTargetId(targetId);
428
- if (target)
429
- sendAttached(target, client);
430
- }
431
- }
432
- sendToPlaywright({ id, sessionId, result }, client);
433
- }
434
- catch (error) {
435
- sendToPlaywright({ id, sessionId, error: { message: errorMessage(error) } }, client);
436
- }
437
- },
438
- onClose(_event, ws) {
439
- if (!trustedOrigin)
440
- return;
441
- const client = playwrightClients.get(clientId);
442
- if (client?.ws === ws)
443
- playwrightClients.delete(clientId);
444
- },
445
- };
446
- }));
447
- app.get("/extension", upgradeWebSocket((c) => {
448
- const trustedOrigin = isTrustedExtensionOrigin(c.req.header("origin"));
449
- return {
450
- onOpen(_event, ws) {
451
- if (!trustedOrigin) {
452
- ws.close(WEBSOCKET_POLICY_VIOLATION_CODE, EXTENSION_ORIGIN_POLICY_REASON);
453
- return;
454
- }
455
- if (extensionWs) {
456
- const old = extensionWs;
457
- disconnectExtension(new PageBackendError(503, "extension connection replaced"));
458
- old.close(4001, "Extension replaced");
459
- }
460
- extensionWs = ws;
461
- log("Extension connected");
462
- },
463
- onMessage(event, ws) {
464
- if (!trustedOrigin)
465
- return;
466
- if (extensionWs !== ws)
467
- return;
468
- let parsed;
469
- try {
470
- parsed = JSON.parse(event.data.toString());
471
- }
472
- catch {
473
- closeInvalidExtension(ws, 1000, "Invalid JSON");
474
- return;
475
- }
476
- if (!isRecord(parsed)) {
477
- closeInvalidExtension(ws, 1003, "Invalid extension message");
478
- return;
479
- }
480
- const message = parsed;
481
- if ("id" in message) {
482
- if (typeof message.id !== "number")
483
- return;
484
- const pending = extensionPending.get(message.id);
485
- if (!pending)
486
- return;
487
- extensionPending.delete(message.id);
488
- if (message.error)
489
- pending.reject(new PageBackendError(502, message.error));
490
- else
491
- pending.resolve(message.result);
492
- return;
493
- }
494
- if (message.method !== "forwardCDPEvent")
495
- return;
496
- if (!isExtensionEvent(parsed)) {
497
- closeInvalidExtension(ws, 1003, "Invalid extension message");
498
- return;
499
- }
500
- const { method, params, sessionId } = parsed.params;
501
- if (method === "Target.attachedToTarget") {
502
- const attached = params;
503
- const target = {
504
- sessionId: attached.sessionId,
505
- targetId: attached.targetInfo.targetId,
506
- targetInfo: attached.targetInfo,
507
- };
508
- registry.attach(target);
509
- sendAttached(target);
510
- return;
511
- }
512
- if (method === "Target.detachedFromTarget") {
513
- const detached = params;
514
- const target = registry.detach(detached.sessionId);
515
- sendDetached(detached.sessionId, detached, target);
516
- return;
517
- }
518
- if (method === "Target.targetInfoChanged") {
519
- const changed = params;
520
- registry.updateTargetInfo(changed.targetInfo);
521
- sendToPlaywright({ method, params: changed });
522
- return;
523
- }
524
- sendSessionEvent(method, params, sessionId);
525
- },
526
- onClose(_event, ws) {
527
- if (!trustedOrigin)
528
- return;
529
- if (extensionWs !== ws)
530
- return;
531
- log("Extension disconnected");
532
- disconnectExtension(new PageBackendError(503, "extension connection closed"));
533
- },
534
- };
535
- }));
536
- const server = serve({ fetch: app.fetch, port: requestedPort, hostname: host });
537
- injectWebSocket(server);
538
- await waitForListening(server);
539
- log(`HTTP: ${formatHttpUrl(host, requestedPort)}`);
540
- let stopped = false;
541
- return {
542
- wsEndpoint,
543
- port: requestedPort,
544
- async stop() {
545
- if (stopped)
546
- return;
547
- stopped = true;
548
- const ws = extensionWs;
549
- disconnectExtension(new PageBackendError(503, "relay server stopped"));
550
- ws?.close(1000, "Server stopped");
551
- await new Promise((resolve, reject) => {
552
- server.close((error) => (error ? reject(error) : resolve()));
553
- });
554
- },
555
- };
556
- }
557
- function waitForListening(server) {
558
- if (server.listening)
559
- return Promise.resolve();
560
- return new Promise((resolve, reject) => {
561
- server.once("listening", resolve);
562
- server.once("error", reject);
563
- });
564
- }
565
- function errorMessage(error) {
566
- return error instanceof Error ? error.message : String(error);
567
- }
@@ -1,34 +0,0 @@
1
- export interface TcpPortProbe {
2
- once(event: "error" | "listening", listener: () => void): this;
3
- listen(port: number, host: string): unknown;
4
- close(callback: () => void): unknown;
5
- }
6
- export type TcpPortProbeFactory = () => TcpPortProbe;
7
- export type PlaywrightChromiumExecutableName = "chromium" | "chromium-headless-shell";
8
- export interface ChromiumInstallCheckOptions {
9
- headless: boolean;
10
- findExecutable: (name: PlaywrightChromiumExecutableName) => {
11
- executablePath: () => string | undefined;
12
- } | undefined;
13
- exists: (path: string) => boolean;
14
- }
15
- export interface RuntimePackageLock {
16
- packages?: Record<string, {
17
- dependencies?: Record<string, string>;
18
- version?: string;
19
- }>;
20
- }
21
- export interface InvalidRuntimeDependenciesOptions {
22
- skillDir: string;
23
- lockedDependencies: Record<string, string>;
24
- readPackageVersion: (packageJsonPath: string) => string | undefined;
25
- }
26
- export declare function assertRuntimeDependenciesAvailable({ invalidDependencies, }: {
27
- invalidDependencies: string[];
28
- }): void;
29
- export declare function isTcpPortInUse(port: number, host?: string, createProbe?: TcpPortProbeFactory): Promise<boolean>;
30
- export declare function isPlaywrightChromiumInstalled({ headless, findExecutable, exists, }: ChromiumInstallCheckOptions): boolean;
31
- export declare function getLockedRuntimeDependencies(lockfile: RuntimePackageLock): Record<string, string>;
32
- export declare function getInvalidRuntimeDependencies({ skillDir, lockedDependencies, readPackageVersion, }: InvalidRuntimeDependenciesOptions): string[];
33
- export declare function resolveImportMetaDir(moduleUrl: string): string;
34
- export declare function resolveSkillDirFromEntrypoint(moduleUrl: string): string;
@@ -1,44 +0,0 @@
1
- import { createServer } from "node:net";
2
- import { basename, dirname, join } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- export function assertRuntimeDependenciesAvailable({ invalidDependencies, }) {
5
- if (invalidDependencies.length === 0)
6
- return;
7
- throw new Error(`Runtime dependencies missing or out of date: ${invalidDependencies.join(", ")}. ` +
8
- "From the dev-browser skill directory, run: npm ci --omit=dev");
9
- }
10
- export async function isTcpPortInUse(port, host = "127.0.0.1", createProbe = createServer) {
11
- return await new Promise((resolve) => {
12
- const server = createProbe();
13
- server.once("error", () => resolve(true));
14
- server.once("listening", () => server.close(() => resolve(false)));
15
- server.listen(port, host);
16
- });
17
- }
18
- export function isPlaywrightChromiumInstalled({ headless, findExecutable, exists, }) {
19
- const name = headless ? "chromium-headless-shell" : "chromium";
20
- const executablePath = findExecutable(name)?.executablePath();
21
- return typeof executablePath === "string" && executablePath.length > 0 && exists(executablePath);
22
- }
23
- export function getLockedRuntimeDependencies(lockfile) {
24
- const packages = lockfile.packages ?? {};
25
- return Object.fromEntries(Object.keys(packages[""]?.dependencies ?? {}).map((name) => {
26
- const version = packages[`node_modules/${name}`]?.version;
27
- if (!version)
28
- throw new Error(`Missing locked version for runtime dependency ${name}`);
29
- return [name, version];
30
- }));
31
- }
32
- export function getInvalidRuntimeDependencies({ skillDir, lockedDependencies, readPackageVersion, }) {
33
- return Object.entries(lockedDependencies).flatMap(([name, version]) => readPackageVersion(join(skillDir, "node_modules", ...name.split("/"), "package.json")) ===
34
- version
35
- ? []
36
- : [name]);
37
- }
38
- export function resolveImportMetaDir(moduleUrl) {
39
- return dirname(fileURLToPath(moduleUrl));
40
- }
41
- export function resolveSkillDirFromEntrypoint(moduleUrl) {
42
- const parentDir = dirname(resolveImportMetaDir(moduleUrl));
43
- return basename(parentDir) === "dist" ? dirname(parentDir) : parentDir;
44
- }
@@ -1,22 +0,0 @@
1
- /**
2
- * Browser-injectable snapshot script.
3
- *
4
- * This module provides the snapshot functionality as a string that can be
5
- * injected into the browser via page.addScriptTag() or page.evaluate().
6
- *
7
- * The approach is to read the compiled JavaScript at runtime and bundle it
8
- * into a single script that exposes window.__devBrowser_getAISnapshot() and
9
- * window.__devBrowser_selectSnapshotRef().
10
- */
11
- /**
12
- * Get the snapshot script that can be injected into the browser.
13
- * Returns a self-contained JavaScript string that:
14
- * 1. Defines all necessary functions (domUtils, roleUtils, yaml, ariaSnapshot)
15
- * 2. Exposes window.__devBrowser_getAISnapshot()
16
- * 3. Exposes window.__devBrowser_selectSnapshotRef()
17
- */
18
- export declare function getSnapshotScript(): string;
19
- /**
20
- * Clear the cached script (useful for development/testing)
21
- */
22
- export declare function clearSnapshotScriptCache(): void;