@mearl/native-host 2.4.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agentbay-browser.d.ts +136 -0
- package/dist/browser-inventory.d.ts +2 -1
- package/dist/cdp-backend/cdp-session.d.ts +10 -4
- package/dist/cdp-backend/client.d.ts +8 -21
- package/dist/cdp-backend/cookie-transfer.d.ts +5 -0
- package/dist/index.js +825 -351
- package/dist/managed-browser.d.ts +6 -0
- package/package.json +9 -4
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@ function uninstallNativeHostArtifacts(options = {}, dependencies = {}) {
|
|
|
46
46
|
writeLine(line);
|
|
47
47
|
};
|
|
48
48
|
try {
|
|
49
|
-
const
|
|
49
|
+
const existsSync5 = dependencies.existsSync ?? fs11.existsSync;
|
|
50
50
|
const platform = dependencies.platform ?? process.platform;
|
|
51
51
|
const hostDir = dependencies.hostDir ?? resolveNativeHostDirectory({
|
|
52
52
|
env: dependencies.env,
|
|
@@ -62,7 +62,7 @@ function uninstallNativeHostArtifacts(options = {}, dependencies = {}) {
|
|
|
62
62
|
path12.join(hostDir, `${hostName}-launcher.${launcherExtension}`)
|
|
63
63
|
];
|
|
64
64
|
for (const artifact of artifacts) {
|
|
65
|
-
if (!
|
|
65
|
+
if (!existsSync5(artifact))
|
|
66
66
|
continue;
|
|
67
67
|
unlinkSync(artifact);
|
|
68
68
|
log2(`✅ Removed: ${artifact}`);
|
|
@@ -98,7 +98,7 @@ import fs12 from "node:fs";
|
|
|
98
98
|
import path13 from "node:path";
|
|
99
99
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
100
100
|
import { createRequire } from "node:module";
|
|
101
|
-
import { fileURLToPath as
|
|
101
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
102
102
|
function resolveHostDir() {
|
|
103
103
|
return resolveNativeHostDirectory();
|
|
104
104
|
}
|
|
@@ -306,7 +306,7 @@ var init_install = __esm({
|
|
|
306
306
|
"use strict";
|
|
307
307
|
init_nativeHost();
|
|
308
308
|
DEFAULT_EXTENSION_ID = "aoehhjnofngknnjefamjbplchbolghkm";
|
|
309
|
-
__filename =
|
|
309
|
+
__filename = fileURLToPath3(import.meta.url);
|
|
310
310
|
__dirname = path13.dirname(__filename);
|
|
311
311
|
ALL_MODES = ["skills", "mcp"];
|
|
312
312
|
}
|
|
@@ -315,17 +315,16 @@ var init_install = __esm({
|
|
|
315
315
|
// src/index.ts
|
|
316
316
|
import net from "node:net";
|
|
317
317
|
import fs13 from "node:fs";
|
|
318
|
-
import
|
|
318
|
+
import http4 from "node:http";
|
|
319
319
|
import os7 from "node:os";
|
|
320
320
|
import path14 from "node:path";
|
|
321
|
-
import { fileURLToPath as
|
|
321
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
322
322
|
|
|
323
323
|
// src/cdp-backend/cdp-session.ts
|
|
324
|
-
import
|
|
324
|
+
import http2 from "node:http";
|
|
325
325
|
|
|
326
326
|
// src/cdp-backend/client.ts
|
|
327
|
-
import
|
|
328
|
-
import crypto2 from "node:crypto";
|
|
327
|
+
import WebSocket from "ws";
|
|
329
328
|
var CdpChildSession = class {
|
|
330
329
|
constructor(parent, sessionId) {
|
|
331
330
|
this.parent = parent;
|
|
@@ -344,199 +343,89 @@ var CdpChildSession = class {
|
|
|
344
343
|
}
|
|
345
344
|
};
|
|
346
345
|
var CdpClient = class _CdpClient {
|
|
347
|
-
socket
|
|
348
|
-
|
|
346
|
+
constructor(socket) {
|
|
347
|
+
this.socket = socket;
|
|
348
|
+
socket.on("message", (data) => this.consumeMessage(data));
|
|
349
|
+
socket.on("close", () => this.handleClosed());
|
|
350
|
+
socket.on("error", () => this.handleClosed());
|
|
351
|
+
}
|
|
349
352
|
nextId = 1;
|
|
350
353
|
pending = /* @__PURE__ */ new Map();
|
|
351
354
|
eventHandlers = /* @__PURE__ */ new Map();
|
|
352
|
-
/** sessionId → method → callbacks (for multiplexed page sessions) */
|
|
353
355
|
sessionEventHandlers = /* @__PURE__ */ new Map();
|
|
354
356
|
_closed = false;
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
for (const [id, pending] of this.pending) {
|
|
364
|
-
clearTimeout(pending.timer);
|
|
365
|
-
pending.reject(new Error("CDP connection closed"));
|
|
366
|
-
this.pending.delete(id);
|
|
357
|
+
static connect(wsUrl) {
|
|
358
|
+
return new Promise((resolve2, reject) => {
|
|
359
|
+
let url2;
|
|
360
|
+
try {
|
|
361
|
+
url2 = new URL(wsUrl);
|
|
362
|
+
} catch {
|
|
363
|
+
reject(new Error("Invalid CDP WebSocket URL"));
|
|
364
|
+
return;
|
|
367
365
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
366
|
+
if (url2.protocol !== "ws:" && url2.protocol !== "wss:") {
|
|
367
|
+
reject(new Error(`Unsupported CDP WebSocket protocol: ${url2.protocol}`));
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const socket = new WebSocket(url2, {
|
|
371
|
+
handshakeTimeout: 5e3,
|
|
372
|
+
maxPayload: 64 * 1024 * 1024,
|
|
373
|
+
perMessageDeflate: false
|
|
374
|
+
});
|
|
375
|
+
let settled = false;
|
|
376
|
+
const fail = (error48) => {
|
|
377
|
+
if (settled) return;
|
|
378
|
+
settled = true;
|
|
379
|
+
socket.terminate();
|
|
380
|
+
reject(error48);
|
|
381
|
+
};
|
|
382
|
+
socket.once("open", () => {
|
|
383
|
+
if (settled) return;
|
|
384
|
+
settled = true;
|
|
385
|
+
resolve2(new _CdpClient(socket));
|
|
386
|
+
});
|
|
387
|
+
socket.once("error", fail);
|
|
388
|
+
socket.once("unexpected-response", (_request, response) => {
|
|
389
|
+
response.resume();
|
|
390
|
+
fail(new Error(`CDP WebSocket upgrade failed with status ${response.statusCode ?? 0}`));
|
|
391
|
+
});
|
|
371
392
|
});
|
|
372
393
|
}
|
|
373
|
-
/** Create a child session client that routes through this connection via sessionId. */
|
|
374
394
|
createChildSession(sessionId) {
|
|
375
395
|
return new CdpChildSession(this, sessionId);
|
|
376
396
|
}
|
|
377
|
-
/** Send a command within a specific CDP session (multiplexed on this connection). */
|
|
378
397
|
sendCommandInSession(sessionId, method, params, timeoutMs = 3e4) {
|
|
379
|
-
return
|
|
380
|
-
if (this._closed) {
|
|
381
|
-
reject(new Error("CDP client is closed"));
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
const id = this.nextId++;
|
|
385
|
-
const timer = setTimeout(() => {
|
|
386
|
-
this.pending.delete(id);
|
|
387
|
-
reject(new Error(`CDP command timeout: ${method}`));
|
|
388
|
-
}, timeoutMs);
|
|
389
|
-
this.pending.set(id, { resolve, reject, timer, sessionId });
|
|
390
|
-
this.sendText(JSON.stringify({ id, method, params: params ?? {}, sessionId }));
|
|
391
|
-
});
|
|
398
|
+
return this.sendRequest(method, params, timeoutMs, sessionId);
|
|
392
399
|
}
|
|
393
|
-
/** Subscribe to events from a specific CDP session. */
|
|
394
400
|
onSession(sessionId, method, callback) {
|
|
395
401
|
if (!this.sessionEventHandlers.has(sessionId)) {
|
|
396
402
|
this.sessionEventHandlers.set(sessionId, /* @__PURE__ */ new Map());
|
|
397
403
|
}
|
|
398
404
|
const sessionMap = this.sessionEventHandlers.get(sessionId);
|
|
399
|
-
if (!sessionMap.has(method))
|
|
400
|
-
sessionMap.set(method, /* @__PURE__ */ new Set());
|
|
401
|
-
}
|
|
405
|
+
if (!sessionMap.has(method)) sessionMap.set(method, /* @__PURE__ */ new Set());
|
|
402
406
|
sessionMap.get(method).add(callback);
|
|
403
407
|
return () => sessionMap.get(method)?.delete(callback);
|
|
404
408
|
}
|
|
405
|
-
|
|
406
|
-
return
|
|
407
|
-
const url2 = new URL(wsUrl);
|
|
408
|
-
const port = parseInt(url2.port || "9222", 10);
|
|
409
|
-
const key = crypto2.randomBytes(16).toString("base64");
|
|
410
|
-
const expectedAccept = crypto2.createHash("sha1").update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest("base64");
|
|
411
|
-
const req = http.request({
|
|
412
|
-
host: url2.hostname,
|
|
413
|
-
port,
|
|
414
|
-
path: url2.pathname,
|
|
415
|
-
headers: {
|
|
416
|
-
Connection: "Upgrade",
|
|
417
|
-
Upgrade: "websocket",
|
|
418
|
-
"Sec-WebSocket-Key": key,
|
|
419
|
-
"Sec-WebSocket-Version": "13",
|
|
420
|
-
Host: url2.host
|
|
421
|
-
// No Origin header — Chrome allows connections without Origin,
|
|
422
|
-
// but rejects any Origin not in --remote-allow-origins allowlist.
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
let settled = false;
|
|
426
|
-
const fail = (err) => {
|
|
427
|
-
if (settled) return;
|
|
428
|
-
settled = true;
|
|
429
|
-
reject(err);
|
|
430
|
-
};
|
|
431
|
-
req.on("upgrade", (res, socket, head) => {
|
|
432
|
-
if (settled) return;
|
|
433
|
-
if (res.statusCode !== 101) {
|
|
434
|
-
settled = true;
|
|
435
|
-
socket.destroy();
|
|
436
|
-
reject(new Error(`WebSocket upgrade failed with status ${res.statusCode}`));
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
const acceptHeader = res.headers["sec-websocket-accept"];
|
|
440
|
-
if (acceptHeader !== expectedAccept) {
|
|
441
|
-
settled = true;
|
|
442
|
-
socket.destroy();
|
|
443
|
-
reject(new Error("WebSocket handshake key mismatch"));
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
settled = true;
|
|
447
|
-
const client2 = new _CdpClient(socket);
|
|
448
|
-
if (head && head.length > 0) {
|
|
449
|
-
client2.buffer = Buffer.concat([client2.buffer, head]);
|
|
450
|
-
client2.consumeFrames();
|
|
451
|
-
}
|
|
452
|
-
resolve(client2);
|
|
453
|
-
});
|
|
454
|
-
req.on("error", fail);
|
|
455
|
-
req.setTimeout(5e3, () => {
|
|
456
|
-
req.destroy();
|
|
457
|
-
fail(new Error("CDP WebSocket connect timeout"));
|
|
458
|
-
});
|
|
459
|
-
req.end();
|
|
460
|
-
});
|
|
409
|
+
sendCommand(method, params, timeoutMs = 3e4) {
|
|
410
|
+
return this.sendRequest(method, params, timeoutMs);
|
|
461
411
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
const masked = (byte1 & 128) !== 0;
|
|
467
|
-
let payloadLen = byte1 & 127;
|
|
468
|
-
let headerLen = 2;
|
|
469
|
-
if (payloadLen === 126) {
|
|
470
|
-
if (this.buffer.length < 4) return;
|
|
471
|
-
payloadLen = this.buffer.readUInt16BE(2);
|
|
472
|
-
headerLen = 4;
|
|
473
|
-
} else if (payloadLen === 127) {
|
|
474
|
-
if (this.buffer.length < 10) return;
|
|
475
|
-
payloadLen = Number(this.buffer.readBigUInt64BE(2));
|
|
476
|
-
headerLen = 10;
|
|
477
|
-
}
|
|
478
|
-
if (masked) headerLen += 4;
|
|
479
|
-
if (this.buffer.length < headerLen + payloadLen) return;
|
|
480
|
-
const opcode = this.buffer[0] & 15;
|
|
481
|
-
let payload;
|
|
482
|
-
if (masked) {
|
|
483
|
-
const maskKey = this.buffer.subarray(headerLen - 4, headerLen);
|
|
484
|
-
payload = Buffer.from(
|
|
485
|
-
this.buffer.subarray(headerLen, headerLen + payloadLen).map((b, i) => b ^ maskKey[i % 4])
|
|
486
|
-
);
|
|
487
|
-
} else {
|
|
488
|
-
payload = this.buffer.subarray(headerLen, headerLen + payloadLen);
|
|
489
|
-
}
|
|
490
|
-
this.buffer = this.buffer.subarray(headerLen + payloadLen);
|
|
491
|
-
if (opcode === 1 || opcode === 2) {
|
|
492
|
-
try {
|
|
493
|
-
const msg = JSON.parse(payload.toString("utf-8"));
|
|
494
|
-
this.handleMessage(msg);
|
|
495
|
-
} catch {
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
412
|
+
on(method, callback) {
|
|
413
|
+
if (!this.eventHandlers.has(method)) this.eventHandlers.set(method, /* @__PURE__ */ new Set());
|
|
414
|
+
this.eventHandlers.get(method).add(callback);
|
|
415
|
+
return () => this.eventHandlers.get(method)?.delete(callback);
|
|
499
416
|
}
|
|
500
|
-
|
|
501
|
-
if (
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
this.pending.delete(msg.id);
|
|
506
|
-
if (msg.error) {
|
|
507
|
-
pending.reject(new Error(msg.error.message ?? JSON.stringify(msg.error)));
|
|
508
|
-
} else {
|
|
509
|
-
pending.resolve(msg.result ?? {});
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
} else if (msg.method) {
|
|
513
|
-
if (msg.sessionId) {
|
|
514
|
-
const sessionMap = this.sessionEventHandlers.get(msg.sessionId);
|
|
515
|
-
const handlers = sessionMap?.get(msg.method);
|
|
516
|
-
if (handlers) {
|
|
517
|
-
for (const cb of handlers) {
|
|
518
|
-
try {
|
|
519
|
-
cb(msg.params);
|
|
520
|
-
} catch {
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
} else {
|
|
525
|
-
const handlers = this.eventHandlers.get(msg.method);
|
|
526
|
-
if (handlers) {
|
|
527
|
-
for (const cb of handlers) {
|
|
528
|
-
try {
|
|
529
|
-
cb(msg.params);
|
|
530
|
-
} catch {
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
417
|
+
close() {
|
|
418
|
+
if (this._closed) return;
|
|
419
|
+
this._closed = true;
|
|
420
|
+
this.socket.terminate();
|
|
421
|
+
this.rejectPending("CDP connection closed");
|
|
536
422
|
}
|
|
537
|
-
|
|
538
|
-
return
|
|
539
|
-
|
|
423
|
+
get closed() {
|
|
424
|
+
return this._closed;
|
|
425
|
+
}
|
|
426
|
+
sendRequest(method, params, timeoutMs, sessionId) {
|
|
427
|
+
return new Promise((resolve2, reject) => {
|
|
428
|
+
if (this._closed || this.socket.readyState !== WebSocket.OPEN) {
|
|
540
429
|
reject(new Error("CDP client is closed"));
|
|
541
430
|
return;
|
|
542
431
|
}
|
|
@@ -545,51 +434,61 @@ var CdpClient = class _CdpClient {
|
|
|
545
434
|
this.pending.delete(id);
|
|
546
435
|
reject(new Error(`CDP command timeout: ${method}`));
|
|
547
436
|
}, timeoutMs);
|
|
548
|
-
this.pending.set(id, { resolve, reject, timer });
|
|
549
|
-
this.
|
|
437
|
+
this.pending.set(id, { resolve: resolve2, reject, timer, sessionId });
|
|
438
|
+
this.socket.send(
|
|
439
|
+
JSON.stringify({ id, method, params: params ?? {}, ...sessionId ? { sessionId } : {} }),
|
|
440
|
+
(error48) => {
|
|
441
|
+
if (!error48) return;
|
|
442
|
+
const pending = this.pending.get(id);
|
|
443
|
+
if (!pending) return;
|
|
444
|
+
clearTimeout(pending.timer);
|
|
445
|
+
this.pending.delete(id);
|
|
446
|
+
pending.reject(error48);
|
|
447
|
+
}
|
|
448
|
+
);
|
|
550
449
|
});
|
|
551
450
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
451
|
+
consumeMessage(data) {
|
|
452
|
+
try {
|
|
453
|
+
const text = Array.isArray(data) ? Buffer.concat(data).toString("utf8") : Buffer.isBuffer(data) ? data.toString("utf8") : Buffer.from(data).toString("utf8");
|
|
454
|
+
this.handleMessage(JSON.parse(text));
|
|
455
|
+
} catch {
|
|
555
456
|
}
|
|
556
|
-
this.eventHandlers.get(method).add(callback);
|
|
557
|
-
return () => this.eventHandlers.get(method)?.delete(callback);
|
|
558
457
|
}
|
|
559
|
-
|
|
560
|
-
if (
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
header = Buffer.alloc(8);
|
|
572
|
-
header[0] = 129;
|
|
573
|
-
header[1] = 128 | 126;
|
|
574
|
-
header.writeUInt16BE(payload.length, 2);
|
|
575
|
-
maskKey.copy(header, 4);
|
|
576
|
-
} else {
|
|
577
|
-
header = Buffer.alloc(14);
|
|
578
|
-
header[0] = 129;
|
|
579
|
-
header[1] = 128 | 127;
|
|
580
|
-
header.writeBigUInt64BE(BigInt(payload.length), 2);
|
|
581
|
-
maskKey.copy(header, 10);
|
|
458
|
+
handleMessage(msg) {
|
|
459
|
+
if (msg.id !== void 0) {
|
|
460
|
+
const pending = this.pending.get(msg.id);
|
|
461
|
+
if (!pending) return;
|
|
462
|
+
clearTimeout(pending.timer);
|
|
463
|
+
this.pending.delete(msg.id);
|
|
464
|
+
if (msg.error) {
|
|
465
|
+
pending.reject(new Error(msg.error.message ?? JSON.stringify(msg.error)));
|
|
466
|
+
} else {
|
|
467
|
+
pending.resolve(msg.result ?? {});
|
|
468
|
+
}
|
|
469
|
+
return;
|
|
582
470
|
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
471
|
+
if (!msg.method) return;
|
|
472
|
+
const handlers = msg.sessionId ? this.sessionEventHandlers.get(msg.sessionId)?.get(msg.method) : this.eventHandlers.get(msg.method);
|
|
473
|
+
if (!handlers) return;
|
|
474
|
+
for (const callback of handlers) {
|
|
475
|
+
try {
|
|
476
|
+
callback(msg.params);
|
|
477
|
+
} catch {
|
|
478
|
+
}
|
|
589
479
|
}
|
|
590
480
|
}
|
|
591
|
-
|
|
592
|
-
|
|
481
|
+
handleClosed() {
|
|
482
|
+
if (this._closed) return;
|
|
483
|
+
this._closed = true;
|
|
484
|
+
this.rejectPending("CDP connection closed");
|
|
485
|
+
}
|
|
486
|
+
rejectPending(message) {
|
|
487
|
+
for (const [id, pending] of this.pending) {
|
|
488
|
+
clearTimeout(pending.timer);
|
|
489
|
+
pending.reject(new Error(message));
|
|
490
|
+
this.pending.delete(id);
|
|
491
|
+
}
|
|
593
492
|
}
|
|
594
493
|
};
|
|
595
494
|
|
|
@@ -3056,7 +2955,7 @@ function installPageObserverInPage(maxBatches = 50) {
|
|
|
3056
2955
|
});
|
|
3057
2956
|
state.waitSince = (checkpoint, checkpointFocus, quietMs, firstChangeTimeoutMs, timeoutMs) => {
|
|
3058
2957
|
const startedAt = performance.now();
|
|
3059
|
-
return new Promise((
|
|
2958
|
+
return new Promise((resolve2) => {
|
|
3060
2959
|
let completed = false;
|
|
3061
2960
|
let quietTimer;
|
|
3062
2961
|
let firstChangeTimer;
|
|
@@ -3121,7 +3020,7 @@ function installPageObserverInPage(maxBatches = 50) {
|
|
|
3121
3020
|
if (structuralMutationCount > 0 && unclassifiedStructuralMutationCount > 0) {
|
|
3122
3021
|
snapshotReasons.push("unclassified-structure");
|
|
3123
3022
|
}
|
|
3124
|
-
|
|
3023
|
+
resolve2({
|
|
3125
3024
|
mode: "delta",
|
|
3126
3025
|
scope: "main-document",
|
|
3127
3026
|
checkpoint,
|
|
@@ -3360,14 +3259,14 @@ function createNavigationSettlementTracker(options) {
|
|
|
3360
3259
|
return Promise.resolve(true);
|
|
3361
3260
|
if (timeoutMs <= 0 || disposed)
|
|
3362
3261
|
return Promise.resolve(false);
|
|
3363
|
-
return new Promise((
|
|
3262
|
+
return new Promise((resolve2) => {
|
|
3364
3263
|
const initialDeadline = performance.now() + timeoutMs;
|
|
3365
3264
|
const hardDeadline = initialDeadline + 4e3;
|
|
3366
3265
|
let timer;
|
|
3367
3266
|
const waiter = (didStart) => {
|
|
3368
3267
|
clearTimeout(timer);
|
|
3369
3268
|
startWaiters.delete(waiter);
|
|
3370
|
-
|
|
3269
|
+
resolve2(didStart);
|
|
3371
3270
|
};
|
|
3372
3271
|
const check2 = () => {
|
|
3373
3272
|
if (started) {
|
|
@@ -3389,26 +3288,26 @@ function createNavigationSettlementTracker(options) {
|
|
|
3389
3288
|
const waitForResult = (timeoutMs) => {
|
|
3390
3289
|
if (completed)
|
|
3391
3290
|
return Promise.resolve(completed);
|
|
3392
|
-
return new Promise((
|
|
3291
|
+
return new Promise((resolve2) => {
|
|
3393
3292
|
const waiter = (result) => {
|
|
3394
3293
|
clearTimeout(timer);
|
|
3395
3294
|
resultWaiters.delete(waiter);
|
|
3396
|
-
|
|
3295
|
+
resolve2(result);
|
|
3397
3296
|
};
|
|
3398
3297
|
const timer = setTimeout(() => {
|
|
3399
3298
|
resultWaiters.delete(waiter);
|
|
3400
3299
|
finish(documentComplete, false, "timeout");
|
|
3401
3300
|
if (completed)
|
|
3402
|
-
|
|
3301
|
+
resolve2(completed);
|
|
3403
3302
|
}, timeoutMs);
|
|
3404
3303
|
resultWaiters.add(waiter);
|
|
3405
3304
|
});
|
|
3406
3305
|
};
|
|
3407
3306
|
const waitForNetworkIdle = (timeoutMs) => {
|
|
3408
3307
|
const waitStartedAt = performance.now();
|
|
3409
|
-
return new Promise((
|
|
3308
|
+
return new Promise((resolve2) => {
|
|
3410
3309
|
const finishWait = (ready, settledBy) => {
|
|
3411
|
-
|
|
3310
|
+
resolve2({
|
|
3412
3311
|
ready,
|
|
3413
3312
|
settledBy,
|
|
3414
3313
|
pendingRequests: pendingRequests2.size,
|
|
@@ -4848,7 +4747,7 @@ async function setupBufferListeners(client2, buffers) {
|
|
|
4848
4747
|
|
|
4849
4748
|
// src/cdp-backend/discover.ts
|
|
4850
4749
|
import fs from "node:fs";
|
|
4851
|
-
import
|
|
4750
|
+
import http from "node:http";
|
|
4852
4751
|
import os from "node:os";
|
|
4853
4752
|
import path from "node:path";
|
|
4854
4753
|
function chromeUserDataDir() {
|
|
@@ -4876,13 +4775,13 @@ function readDevToolsActivePort(userDataDir = chromeUserDataDir()) {
|
|
|
4876
4775
|
}
|
|
4877
4776
|
}
|
|
4878
4777
|
async function discoverTargets(port = 9222) {
|
|
4879
|
-
return new Promise((
|
|
4880
|
-
const req =
|
|
4778
|
+
return new Promise((resolve2, reject) => {
|
|
4779
|
+
const req = http.get(`http://localhost:${port}/json`, (res) => {
|
|
4881
4780
|
let data = "";
|
|
4882
4781
|
res.on("data", (chunk) => data += chunk);
|
|
4883
4782
|
res.on("end", () => {
|
|
4884
4783
|
try {
|
|
4885
|
-
|
|
4784
|
+
resolve2(JSON.parse(data));
|
|
4886
4785
|
} catch (e) {
|
|
4887
4786
|
reject(new Error(`Failed to parse CDP targets: ${e}`));
|
|
4888
4787
|
}
|
|
@@ -4909,6 +4808,8 @@ async function isCdpAvailable(port = 9222, userDataDir) {
|
|
|
4909
4808
|
var CdpSession = class {
|
|
4910
4809
|
port;
|
|
4911
4810
|
userDataDir;
|
|
4811
|
+
endpointUrl;
|
|
4812
|
+
endpointResolver;
|
|
4912
4813
|
browserClient = null;
|
|
4913
4814
|
pageSessions = /* @__PURE__ */ new Map();
|
|
4914
4815
|
// targetId → PageSession
|
|
@@ -4922,6 +4823,8 @@ var CdpSession = class {
|
|
|
4922
4823
|
}
|
|
4923
4824
|
this.port = options.port ?? 9222;
|
|
4924
4825
|
this.userDataDir = options.userDataDir;
|
|
4826
|
+
this.endpointUrl = options.endpointUrl;
|
|
4827
|
+
this.endpointResolver = options.endpointResolver;
|
|
4925
4828
|
}
|
|
4926
4829
|
// ── Browser-level ──────────────────────────────────────────────────────────
|
|
4927
4830
|
async getBrowserClient() {
|
|
@@ -4999,7 +4902,13 @@ var CdpSession = class {
|
|
|
4999
4902
|
5e3
|
|
5000
4903
|
);
|
|
5001
4904
|
client2 = browser.createChildSession(sessionId);
|
|
5002
|
-
} catch {
|
|
4905
|
+
} catch (error48) {
|
|
4906
|
+
if (this.isRemote()) {
|
|
4907
|
+
throw new Error(
|
|
4908
|
+
`Failed to attach to remote CDP target ${target.id}: ${error48 instanceof Error ? error48.message : String(error48)}`,
|
|
4909
|
+
{ cause: error48 }
|
|
4910
|
+
);
|
|
4911
|
+
}
|
|
5003
4912
|
client2 = await CdpClient.connect(target.webSocketDebuggerUrl);
|
|
5004
4913
|
}
|
|
5005
4914
|
let tabId;
|
|
@@ -5029,6 +4938,7 @@ var CdpSession = class {
|
|
|
5029
4938
|
return session;
|
|
5030
4939
|
}
|
|
5031
4940
|
async findTargetById(targetId) {
|
|
4941
|
+
if (this.isRemote()) return this.findTargetByIdViaCdp(targetId);
|
|
5032
4942
|
try {
|
|
5033
4943
|
const targets = await discoverTargets(this.effectivePort());
|
|
5034
4944
|
return targets.find((t) => t.id === targetId && t.webSocketDebuggerUrl) ?? null;
|
|
@@ -5037,6 +4947,7 @@ var CdpSession = class {
|
|
|
5037
4947
|
}
|
|
5038
4948
|
}
|
|
5039
4949
|
async findDefaultPageTarget() {
|
|
4950
|
+
if (this.isRemote()) return this.findDefaultPageTargetViaCdp();
|
|
5040
4951
|
try {
|
|
5041
4952
|
const targets = await discoverTargets(this.effectivePort());
|
|
5042
4953
|
return targets.find(
|
|
@@ -5056,6 +4967,14 @@ var CdpSession = class {
|
|
|
5056
4967
|
* Priority: DevToolsActivePort file → HTTP /json/version
|
|
5057
4968
|
*/
|
|
5058
4969
|
async resolveBrowserWsUrl() {
|
|
4970
|
+
const configuredEndpoint = this.endpointResolver ? await this.endpointResolver() : this.endpointUrl;
|
|
4971
|
+
if (configuredEndpoint) {
|
|
4972
|
+
const url2 = new URL(configuredEndpoint);
|
|
4973
|
+
if (url2.protocol !== "ws:" && url2.protocol !== "wss:") {
|
|
4974
|
+
throw new Error(`Unsupported CDP endpoint protocol: ${url2.protocol}`);
|
|
4975
|
+
}
|
|
4976
|
+
return url2.toString();
|
|
4977
|
+
}
|
|
5059
4978
|
const fileInfo = readDevToolsActivePort(this.userDataDir);
|
|
5060
4979
|
if (fileInfo) {
|
|
5061
4980
|
return `ws://localhost:${fileInfo.port}${fileInfo.browserWsPath}`;
|
|
@@ -5075,6 +4994,9 @@ var CdpSession = class {
|
|
|
5075
4994
|
const port = this.effectivePort();
|
|
5076
4995
|
return `ws://localhost:${port}/devtools/page/${targetId}`;
|
|
5077
4996
|
}
|
|
4997
|
+
isRemote() {
|
|
4998
|
+
return Boolean(this.endpointUrl || this.endpointResolver);
|
|
4999
|
+
}
|
|
5078
5000
|
async findTargetByIdViaCdp(targetId) {
|
|
5079
5001
|
try {
|
|
5080
5002
|
const browser = await this.getBrowserClient();
|
|
@@ -5114,13 +5036,13 @@ var CdpSession = class {
|
|
|
5114
5036
|
}
|
|
5115
5037
|
}
|
|
5116
5038
|
fetchVersionInfo() {
|
|
5117
|
-
return new Promise((
|
|
5118
|
-
const req =
|
|
5039
|
+
return new Promise((resolve2, reject) => {
|
|
5040
|
+
const req = http2.get(`http://localhost:${this.port}/json/version`, (res) => {
|
|
5119
5041
|
let data = "";
|
|
5120
5042
|
res.on("data", (chunk) => data += chunk);
|
|
5121
5043
|
res.on("end", () => {
|
|
5122
5044
|
try {
|
|
5123
|
-
|
|
5045
|
+
resolve2(JSON.parse(data));
|
|
5124
5046
|
} catch (e) {
|
|
5125
5047
|
reject(new Error(`Failed to parse CDP version info: ${e}`));
|
|
5126
5048
|
}
|
|
@@ -5829,15 +5751,15 @@ async function releaseCdpControl(session) {
|
|
|
5829
5751
|
|
|
5830
5752
|
// src/cdp-backend/cdp-utils.ts
|
|
5831
5753
|
import https from "node:https";
|
|
5832
|
-
import
|
|
5754
|
+
import http3 from "node:http";
|
|
5833
5755
|
var TYPE_INTO_ELEMENT_SRC = typeIntoElement.toString();
|
|
5834
5756
|
var CLICK_ELEMENT_VIA_JS_SRC = clickElementViaJS.toString();
|
|
5835
5757
|
var GET_CLICK_COORDS_FROM_NODE_SRC = getClickCoordsFromNode.toString();
|
|
5836
5758
|
function nodeFetch(urlStr, options = {}) {
|
|
5837
|
-
return new Promise((
|
|
5759
|
+
return new Promise((resolve2, reject) => {
|
|
5838
5760
|
const url2 = new URL(urlStr);
|
|
5839
5761
|
const isHttps = url2.protocol === "https:";
|
|
5840
|
-
const lib = isHttps ? https :
|
|
5762
|
+
const lib = isHttps ? https : http3;
|
|
5841
5763
|
const { method = "GET", headers = {}, body, timeoutMs = 3e4 } = options;
|
|
5842
5764
|
const req = lib.request(
|
|
5843
5765
|
{
|
|
@@ -5857,7 +5779,7 @@ function nodeFetch(urlStr, options = {}) {
|
|
|
5857
5779
|
res.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
5858
5780
|
res.on("end", () => {
|
|
5859
5781
|
const bodyBuffer = Buffer.concat(chunks);
|
|
5860
|
-
|
|
5782
|
+
resolve2({
|
|
5861
5783
|
status: res.statusCode ?? 0,
|
|
5862
5784
|
statusText: res.statusMessage ?? "",
|
|
5863
5785
|
headers: responseHeaders,
|
|
@@ -5914,7 +5836,7 @@ ${value}\r
|
|
|
5914
5836
|
return { contentType: `multipart/form-data; boundary=${boundary}`, body };
|
|
5915
5837
|
}
|
|
5916
5838
|
async function waitForPageLoad(session, timeoutMs) {
|
|
5917
|
-
return new Promise((
|
|
5839
|
+
return new Promise((resolve2, reject) => {
|
|
5918
5840
|
let settled = false;
|
|
5919
5841
|
let removeLoadListener = () => {
|
|
5920
5842
|
};
|
|
@@ -5924,7 +5846,7 @@ async function waitForPageLoad(session, timeoutMs) {
|
|
|
5924
5846
|
clearTimeout(timer);
|
|
5925
5847
|
removeLoadListener();
|
|
5926
5848
|
if (error48) reject(error48);
|
|
5927
|
-
else
|
|
5849
|
+
else resolve2();
|
|
5928
5850
|
};
|
|
5929
5851
|
const timer = setTimeout(() => {
|
|
5930
5852
|
finish(new Error(`Page load timeout after ${timeoutMs}ms`));
|
|
@@ -7017,12 +6939,12 @@ function resolveCloudConnectorCommand() {
|
|
|
7017
6939
|
};
|
|
7018
6940
|
}
|
|
7019
6941
|
function startCloudConnector(serverUrl) {
|
|
7020
|
-
return new Promise((
|
|
6942
|
+
return new Promise((resolve2) => {
|
|
7021
6943
|
const existingPid = findLiveConnector(serverUrl);
|
|
7022
6944
|
if (existingPid) {
|
|
7023
6945
|
logFn(`Reusing existing cloud connector for ${serverUrl} (pid=${existingPid})`);
|
|
7024
6946
|
const entry = registerConnector(serverUrl, existingPid);
|
|
7025
|
-
|
|
6947
|
+
resolve2({
|
|
7026
6948
|
success: true,
|
|
7027
6949
|
pid: existingPid,
|
|
7028
6950
|
...entry.connectorId ? { connectorId: entry.connectorId } : {},
|
|
@@ -7055,14 +6977,14 @@ function startCloudConnector(serverUrl) {
|
|
|
7055
6977
|
clearTimeout(startupTimer);
|
|
7056
6978
|
if (ok && child.pid) {
|
|
7057
6979
|
const entry = registerConnector(serverUrl, child.pid, child);
|
|
7058
|
-
|
|
6980
|
+
resolve2({
|
|
7059
6981
|
success: true,
|
|
7060
6982
|
pid: child.pid,
|
|
7061
6983
|
...entry.connectorId ? { connectorId: entry.connectorId } : {},
|
|
7062
6984
|
...entry.name ? { name: entry.name } : {}
|
|
7063
6985
|
});
|
|
7064
6986
|
} else {
|
|
7065
|
-
|
|
6987
|
+
resolve2({ success: false, error: result.error || "Failed to spawn cloud connector" });
|
|
7066
6988
|
}
|
|
7067
6989
|
};
|
|
7068
6990
|
child.once("error", (error48) => {
|
|
@@ -7674,7 +7596,7 @@ async function cdpWaitForTracknick(session, options = {}) {
|
|
|
7674
7596
|
latest = await cdpGetTracknick(session);
|
|
7675
7597
|
if (expected && latest === expected) return latest;
|
|
7676
7598
|
if (!expected && latest && latest !== previous) return latest;
|
|
7677
|
-
await new Promise((
|
|
7599
|
+
await new Promise((resolve2) => setTimeout(resolve2, 500));
|
|
7678
7600
|
}
|
|
7679
7601
|
return latest || await cdpGetTracknick(session);
|
|
7680
7602
|
}
|
|
@@ -7684,7 +7606,7 @@ async function cdpOpenAndCloseTarget(cdpSession2, url2) {
|
|
|
7684
7606
|
url: url2,
|
|
7685
7607
|
background: true
|
|
7686
7608
|
});
|
|
7687
|
-
await new Promise((
|
|
7609
|
+
await new Promise((resolve2) => setTimeout(resolve2, 3500));
|
|
7688
7610
|
await browser.sendCommand("Target.closeTarget", { targetId }).catch(() => {
|
|
7689
7611
|
});
|
|
7690
7612
|
}
|
|
@@ -8434,7 +8356,7 @@ async function cdpPageWait(session, data) {
|
|
|
8434
8356
|
const options = resolvePageWaitInput(data);
|
|
8435
8357
|
const startedAt = Date.now();
|
|
8436
8358
|
if (options.mode === "time") {
|
|
8437
|
-
await new Promise((
|
|
8359
|
+
await new Promise((resolve2) => setTimeout(resolve2, options.time));
|
|
8438
8360
|
return { success: true, waited: true, elapsed: options.time, mode: options.mode };
|
|
8439
8361
|
}
|
|
8440
8362
|
const expression = options.mode === "selector" ? `!!document.querySelector(${JSON.stringify(options.selector)})` : options.condition;
|
|
@@ -8459,7 +8381,7 @@ async function cdpPageWait(session, data) {
|
|
|
8459
8381
|
value
|
|
8460
8382
|
};
|
|
8461
8383
|
}
|
|
8462
|
-
await new Promise((
|
|
8384
|
+
await new Promise((resolve2) => setTimeout(resolve2, options.interval));
|
|
8463
8385
|
}
|
|
8464
8386
|
if (options.mode === "selector") {
|
|
8465
8387
|
throw new Error(
|
|
@@ -8530,7 +8452,7 @@ async function waitForHistoryIndex(session, targetIndex, timeoutMs) {
|
|
|
8530
8452
|
}
|
|
8531
8453
|
} catch {
|
|
8532
8454
|
}
|
|
8533
|
-
await new Promise((
|
|
8455
|
+
await new Promise((resolve2) => setTimeout(resolve2, 50));
|
|
8534
8456
|
}
|
|
8535
8457
|
throw new Error(`Page history navigation timeout after ${timeoutMs}ms`);
|
|
8536
8458
|
}
|
|
@@ -8678,7 +8600,7 @@ async function readCurrentUrl(session, action) {
|
|
|
8678
8600
|
return url2;
|
|
8679
8601
|
}
|
|
8680
8602
|
function reloadPageAndWait(session, timeoutMs) {
|
|
8681
|
-
return new Promise((
|
|
8603
|
+
return new Promise((resolve2, reject) => {
|
|
8682
8604
|
let settled = false;
|
|
8683
8605
|
let removeListener = () => {
|
|
8684
8606
|
};
|
|
@@ -8688,7 +8610,7 @@ function reloadPageAndWait(session, timeoutMs) {
|
|
|
8688
8610
|
clearTimeout(timer);
|
|
8689
8611
|
removeListener();
|
|
8690
8612
|
if (error48) reject(error48);
|
|
8691
|
-
else
|
|
8613
|
+
else resolve2();
|
|
8692
8614
|
};
|
|
8693
8615
|
const timer = setTimeout(() => {
|
|
8694
8616
|
finish(new Error(`Page load timeout after ${timeoutMs}ms`));
|
|
@@ -9137,6 +9059,10 @@ async function cdpExportCookies(session, domains) {
|
|
|
9137
9059
|
async function cdpImportCookies(session, cookies) {
|
|
9138
9060
|
if (cookies.length === 0) return 0;
|
|
9139
9061
|
const browser = await session.getBrowserClient();
|
|
9062
|
+
return cdpImportCookiesWithClient(browser, cookies);
|
|
9063
|
+
}
|
|
9064
|
+
async function cdpImportCookiesWithClient(browser, cookies) {
|
|
9065
|
+
if (cookies.length === 0) return 0;
|
|
9140
9066
|
await browser.sendCommand("Storage.setCookies", { cookies });
|
|
9141
9067
|
return cookies.length;
|
|
9142
9068
|
}
|
|
@@ -9263,6 +9189,7 @@ function browserSummary(record2, running) {
|
|
|
9263
9189
|
return {
|
|
9264
9190
|
browserId: record2.browserId,
|
|
9265
9191
|
name: record2.name,
|
|
9192
|
+
provider: "local",
|
|
9266
9193
|
headless: record2.headless,
|
|
9267
9194
|
persistent: record2.persistent,
|
|
9268
9195
|
cdpPort: record2.cdpPort,
|
|
@@ -9329,12 +9256,15 @@ function findManagedRecord(selector) {
|
|
|
9329
9256
|
({ record: record2 }) => record2.browserId.toLowerCase() === normalized || record2.name.toLowerCase() === normalized
|
|
9330
9257
|
)?.record ?? null;
|
|
9331
9258
|
}
|
|
9259
|
+
function hasManagedBrowser(selector) {
|
|
9260
|
+
return findManagedRecord(selector) !== null;
|
|
9261
|
+
}
|
|
9332
9262
|
async function waitForActivePort(userDataDir) {
|
|
9333
9263
|
const deadline = Date.now() + LAUNCH_TIMEOUT_MS;
|
|
9334
9264
|
while (Date.now() < deadline) {
|
|
9335
9265
|
const info = readDevToolsActivePort(userDataDir);
|
|
9336
9266
|
if (info) return info.port;
|
|
9337
|
-
await new Promise((
|
|
9267
|
+
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
9338
9268
|
}
|
|
9339
9269
|
throw new Error(`Chrome did not expose a CDP port within ${LAUNCH_TIMEOUT_MS}ms`);
|
|
9340
9270
|
}
|
|
@@ -9344,7 +9274,7 @@ async function waitForBrowserRegistration(browserId, expectedPid) {
|
|
|
9344
9274
|
while (Date.now() < deadline) {
|
|
9345
9275
|
const record2 = readRecord(file2);
|
|
9346
9276
|
if (record2?.pid === expectedPid && isAlive(expectedPid)) return;
|
|
9347
|
-
await new Promise((
|
|
9277
|
+
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
9348
9278
|
}
|
|
9349
9279
|
throw new Error(`Managed browser ${browserId} did not register within ${LAUNCH_TIMEOUT_MS}ms`);
|
|
9350
9280
|
}
|
|
@@ -9366,7 +9296,7 @@ async function stopProcess(pid, commandMarker) {
|
|
|
9366
9296
|
signalProcess(pid, "SIGTERM", commandMarker);
|
|
9367
9297
|
const deadline = Date.now() + 3e3;
|
|
9368
9298
|
while (Date.now() < deadline && isManagedProcess(pid, commandMarker)) {
|
|
9369
|
-
await new Promise((
|
|
9299
|
+
await new Promise((resolve2) => setTimeout(resolve2, 50));
|
|
9370
9300
|
}
|
|
9371
9301
|
if (isManagedProcess(pid, commandMarker)) signalProcess(pid, "SIGKILL", commandMarker);
|
|
9372
9302
|
}
|
|
@@ -9435,6 +9365,9 @@ function acquireLaunchLock(browserId) {
|
|
|
9435
9365
|
};
|
|
9436
9366
|
}
|
|
9437
9367
|
async function launchManagedBrowser(input, deps) {
|
|
9368
|
+
if (input.imageId !== void 0) {
|
|
9369
|
+
throw new Error("imageId is only supported by the AgentBay browser provider");
|
|
9370
|
+
}
|
|
9438
9371
|
const name = validateName(input.name);
|
|
9439
9372
|
const browserId = managedBrowserId(name);
|
|
9440
9373
|
validateTdbankSelector(input);
|
|
@@ -9470,9 +9403,9 @@ async function launchManagedBrowser(input, deps) {
|
|
|
9470
9403
|
stdio: ["ignore", "ignore", logFd],
|
|
9471
9404
|
windowsHide: headless
|
|
9472
9405
|
});
|
|
9473
|
-
await new Promise((
|
|
9406
|
+
await new Promise((resolve2, reject) => {
|
|
9474
9407
|
chrome.once("error", reject);
|
|
9475
|
-
chrome.once("spawn",
|
|
9408
|
+
chrome.once("spawn", resolve2);
|
|
9476
9409
|
});
|
|
9477
9410
|
chromePid = chrome.pid ?? 0;
|
|
9478
9411
|
if (!chromePid) throw new Error("Chrome launched without a process id");
|
|
@@ -9511,9 +9444,9 @@ async function launchManagedBrowser(input, deps) {
|
|
|
9511
9444
|
],
|
|
9512
9445
|
{ detached: true, stdio: "ignore", windowsHide: true }
|
|
9513
9446
|
);
|
|
9514
|
-
await new Promise((
|
|
9447
|
+
await new Promise((resolve2, reject) => {
|
|
9515
9448
|
host.once("error", reject);
|
|
9516
|
-
host.once("spawn",
|
|
9449
|
+
host.once("spawn", resolve2);
|
|
9517
9450
|
});
|
|
9518
9451
|
hostPid = host.pid ?? 0;
|
|
9519
9452
|
if (!hostPid) throw new Error("Native host launched without a process id");
|
|
@@ -9566,6 +9499,450 @@ async function closeManagedBrowser(selector, options = {}) {
|
|
|
9566
9499
|
return { browserId: record2.browserId, closed: true, profileDeleted: deleteProfile };
|
|
9567
9500
|
}
|
|
9568
9501
|
|
|
9502
|
+
// src/agentbay-browser.ts
|
|
9503
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
9504
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
9505
|
+
import { homedir as homedir2 } from "node:os";
|
|
9506
|
+
import { dirname as dirname3, join as join4, parse, resolve } from "node:path";
|
|
9507
|
+
import { fileURLToPath } from "node:url";
|
|
9508
|
+
var AGENTBAY_BROWSERS_SUBDIR = "agentbay-browsers";
|
|
9509
|
+
var DEFAULT_AGENTBAY_IMAGE_ID = "imgc-0aae4rgl8kvagdv1j";
|
|
9510
|
+
var sdkPromise = null;
|
|
9511
|
+
async function loadSdk() {
|
|
9512
|
+
sdkPromise ??= import("wuying-agentbay-sdk").then((sdk) => {
|
|
9513
|
+
sdk.setupLogger({ level: "ERROR", enableConsole: false });
|
|
9514
|
+
return sdk;
|
|
9515
|
+
});
|
|
9516
|
+
return sdkPromise;
|
|
9517
|
+
}
|
|
9518
|
+
async function createClient(apiKey) {
|
|
9519
|
+
const { AgentBay } = await loadSdk();
|
|
9520
|
+
return new AgentBay({ apiKey });
|
|
9521
|
+
}
|
|
9522
|
+
function agentBayBrowserId(name) {
|
|
9523
|
+
return `managed:agentbay:${name.toLocaleLowerCase("en-US")}`;
|
|
9524
|
+
}
|
|
9525
|
+
function envValue(text, key) {
|
|
9526
|
+
for (const line of text.split(/\r?\n/)) {
|
|
9527
|
+
const match = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/.exec(line);
|
|
9528
|
+
if (!match || match[1] !== key) continue;
|
|
9529
|
+
let value = (match[2] ?? "").trim();
|
|
9530
|
+
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
9531
|
+
value = value.slice(1, -1);
|
|
9532
|
+
} else {
|
|
9533
|
+
value = value.replace(/\s+#.*$/, "").trim();
|
|
9534
|
+
}
|
|
9535
|
+
return value || void 0;
|
|
9536
|
+
}
|
|
9537
|
+
return void 0;
|
|
9538
|
+
}
|
|
9539
|
+
function envFilesUpward(start) {
|
|
9540
|
+
const files = [];
|
|
9541
|
+
let current = resolve(start);
|
|
9542
|
+
while (true) {
|
|
9543
|
+
files.push(join4(current, ".env"));
|
|
9544
|
+
const parent = dirname3(current);
|
|
9545
|
+
if (parent === current || current === parse(current).root) break;
|
|
9546
|
+
current = parent;
|
|
9547
|
+
}
|
|
9548
|
+
return files;
|
|
9549
|
+
}
|
|
9550
|
+
function resolveAgentBayApiKey() {
|
|
9551
|
+
const inherited = process.env.AGENTBAY_KEY?.trim() || process.env.AGENTBAY_API_KEY?.trim();
|
|
9552
|
+
if (inherited) return inherited;
|
|
9553
|
+
const moduleDir = dirname3(fileURLToPath(import.meta.url));
|
|
9554
|
+
const candidates = [
|
|
9555
|
+
...process.env.MEARL_ENV_FILE ? [resolve(process.env.MEARL_ENV_FILE)] : [],
|
|
9556
|
+
...envFilesUpward(process.cwd()),
|
|
9557
|
+
...envFilesUpward(moduleDir),
|
|
9558
|
+
join4(homedir2(), ".mearl", ".env")
|
|
9559
|
+
];
|
|
9560
|
+
for (const file2 of new Set(candidates)) {
|
|
9561
|
+
if (!existsSync4(file2)) continue;
|
|
9562
|
+
try {
|
|
9563
|
+
const text = readFileSync4(file2, "utf8");
|
|
9564
|
+
const value = envValue(text, "AGENTBAY_KEY") ?? envValue(text, "AGENTBAY_API_KEY");
|
|
9565
|
+
if (value) return value;
|
|
9566
|
+
} catch {
|
|
9567
|
+
}
|
|
9568
|
+
}
|
|
9569
|
+
throw new Error(
|
|
9570
|
+
"AgentBay API key not found. Set AGENTBAY_KEY in the environment, project .env, or ~/.mearl/.env."
|
|
9571
|
+
);
|
|
9572
|
+
}
|
|
9573
|
+
function validateAgentBayInput(input) {
|
|
9574
|
+
if (input.headless === true) {
|
|
9575
|
+
throw new Error("headless=true is not supported by the AgentBay browser provider");
|
|
9576
|
+
}
|
|
9577
|
+
if (input.executablePath) {
|
|
9578
|
+
throw new Error("executablePath is only supported by the local browser provider");
|
|
9579
|
+
}
|
|
9580
|
+
if (input.accountId !== void 0 || input.havanaId !== void 0 || input.site !== void 0 || typeof input.query === "string" && input.query.trim()) {
|
|
9581
|
+
throw new Error("TDBank login parameters are only supported by the local browser provider");
|
|
9582
|
+
}
|
|
9583
|
+
}
|
|
9584
|
+
function resolveAgentBayImageId(value) {
|
|
9585
|
+
if (value === void 0) return DEFAULT_AGENTBAY_IMAGE_ID;
|
|
9586
|
+
const imageId = typeof value === "string" ? value.trim() : "";
|
|
9587
|
+
if (!imageId || imageId.length > 128 || !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(imageId)) {
|
|
9588
|
+
throw new Error("imageId must be a valid AgentBay image alias or image ID");
|
|
9589
|
+
}
|
|
9590
|
+
return imageId;
|
|
9591
|
+
}
|
|
9592
|
+
function agentBayContextName(browserId) {
|
|
9593
|
+
return `mearl-browser-${hashKey(browserId)}`;
|
|
9594
|
+
}
|
|
9595
|
+
function normalizeDesktopUserAgent(value) {
|
|
9596
|
+
const userAgent = typeof value === "string" ? value.trim() : "";
|
|
9597
|
+
if (!userAgent) throw new Error("Could not determine the control browser user agent");
|
|
9598
|
+
return userAgent.replace(/\bHeadlessChrome\//g, "Chrome/");
|
|
9599
|
+
}
|
|
9600
|
+
function normalizeAgentBayAccessUrl(value) {
|
|
9601
|
+
const candidate = typeof value === "string" ? value.trim() : "";
|
|
9602
|
+
if (!candidate) return void 0;
|
|
9603
|
+
try {
|
|
9604
|
+
const url2 = new URL(candidate);
|
|
9605
|
+
return url2.protocol === "https:" || url2.protocol === "http:" ? url2.toString() : void 0;
|
|
9606
|
+
} catch {
|
|
9607
|
+
return void 0;
|
|
9608
|
+
}
|
|
9609
|
+
}
|
|
9610
|
+
function browserSummary2(record2, running) {
|
|
9611
|
+
const accessUrl = normalizeAgentBayAccessUrl(record2.accessUrl);
|
|
9612
|
+
return {
|
|
9613
|
+
browserId: record2.browserId,
|
|
9614
|
+
name: record2.name,
|
|
9615
|
+
provider: "agentbay",
|
|
9616
|
+
headless: false,
|
|
9617
|
+
persistent: record2.persistent === true,
|
|
9618
|
+
agentbaySessionId: record2.sessionId,
|
|
9619
|
+
...record2.imageId ? { agentbayImageId: record2.imageId } : {},
|
|
9620
|
+
...record2.contextId ? { agentbayContextId: record2.contextId } : {},
|
|
9621
|
+
...record2.contextName ? { agentbayContextName: record2.contextName } : {},
|
|
9622
|
+
...accessUrl ? { agentbayAccessUrl: accessUrl } : {},
|
|
9623
|
+
createdAt: record2.createdAt,
|
|
9624
|
+
...record2.copiedCookies ? { copiedCookies: record2.copiedCookies } : {},
|
|
9625
|
+
running
|
|
9626
|
+
};
|
|
9627
|
+
}
|
|
9628
|
+
function listRecords2() {
|
|
9629
|
+
const records = [];
|
|
9630
|
+
for (const file2 of listRecordFiles(keyedDir(AGENTBAY_BROWSERS_SUBDIR))) {
|
|
9631
|
+
const record2 = readRecord(file2);
|
|
9632
|
+
if (!record2) {
|
|
9633
|
+
removeRecord(file2);
|
|
9634
|
+
continue;
|
|
9635
|
+
}
|
|
9636
|
+
const running = isManagedProcess(record2.pid, `--browser-id ${record2.browserId}`);
|
|
9637
|
+
if (!running) removeRecord(keyedConfigFile("browsers", record2.browserId));
|
|
9638
|
+
records.push({ record: record2, running });
|
|
9639
|
+
}
|
|
9640
|
+
return records;
|
|
9641
|
+
}
|
|
9642
|
+
function findRecord(selector) {
|
|
9643
|
+
const normalized = selector.trim().toLowerCase();
|
|
9644
|
+
return listRecords2().find(
|
|
9645
|
+
({ record: record2 }) => record2.browserId.toLowerCase() === normalized || record2.name.toLowerCase() === normalized
|
|
9646
|
+
)?.record ?? null;
|
|
9647
|
+
}
|
|
9648
|
+
function hasAgentBayBrowser(selector) {
|
|
9649
|
+
return findRecord(selector) !== null;
|
|
9650
|
+
}
|
|
9651
|
+
function listAgentBayBrowsers() {
|
|
9652
|
+
return listRecords2().map(({ record: record2, running }) => browserSummary2(record2, running));
|
|
9653
|
+
}
|
|
9654
|
+
async function requireSession(sessionId, apiKey) {
|
|
9655
|
+
const agentBay = await createClient(apiKey);
|
|
9656
|
+
return requireSessionFromClient(agentBay, sessionId);
|
|
9657
|
+
}
|
|
9658
|
+
async function requireSessionFromClient(agentBay, sessionId) {
|
|
9659
|
+
const result = await agentBay.get(sessionId);
|
|
9660
|
+
if (!result.success || !result.session) {
|
|
9661
|
+
throw new Error(result.errorMessage || `AgentBay session not found: ${sessionId}`);
|
|
9662
|
+
}
|
|
9663
|
+
return result.session;
|
|
9664
|
+
}
|
|
9665
|
+
async function resolvePersistentContext(agentBay, browserId) {
|
|
9666
|
+
if (!agentBay.context) {
|
|
9667
|
+
throw new Error("The installed AgentBay SDK does not support persistent browser contexts");
|
|
9668
|
+
}
|
|
9669
|
+
const name = agentBayContextName(browserId);
|
|
9670
|
+
const result = await agentBay.context.get(name, true);
|
|
9671
|
+
if (!result.success || !result.context?.id) {
|
|
9672
|
+
throw new Error(result.errorMessage || `Failed to create AgentBay browser context: ${name}`);
|
|
9673
|
+
}
|
|
9674
|
+
return { id: result.context.id, name: result.context.name || name };
|
|
9675
|
+
}
|
|
9676
|
+
async function resolveAgentBayEndpoint(sessionId) {
|
|
9677
|
+
const apiKey = resolveAgentBayApiKey();
|
|
9678
|
+
const { AgentBay, GetCdpLinkRequest } = await loadSdk();
|
|
9679
|
+
const agentBay = new AgentBay({ apiKey });
|
|
9680
|
+
const response = await agentBay.client.getCdpLink(
|
|
9681
|
+
new GetCdpLinkRequest({ authorization: `Bearer ${apiKey}`, sessionId })
|
|
9682
|
+
);
|
|
9683
|
+
const endpoint = response.body?.success ? response.body.data?.url : void 0;
|
|
9684
|
+
if (!endpoint) {
|
|
9685
|
+
throw new Error(response.body?.message || `Failed to get AgentBay CDP link: ${sessionId}`);
|
|
9686
|
+
}
|
|
9687
|
+
const url2 = new URL(endpoint);
|
|
9688
|
+
if (url2.protocol !== "ws:" && url2.protocol !== "wss:") {
|
|
9689
|
+
throw new Error(`AgentBay returned an unsupported CDP endpoint: ${url2.protocol}`);
|
|
9690
|
+
}
|
|
9691
|
+
return url2.toString();
|
|
9692
|
+
}
|
|
9693
|
+
async function keepAgentBaySessionAlive(sessionId) {
|
|
9694
|
+
const session = await requireSession(sessionId, resolveAgentBayApiKey());
|
|
9695
|
+
const result = await session.keepAlive();
|
|
9696
|
+
if (result.success === false) throw new Error(result.errorMessage || "AgentBay keepalive failed");
|
|
9697
|
+
}
|
|
9698
|
+
async function initializeAgentBayBrowserSession(session, input, cookies, options = {}) {
|
|
9699
|
+
const initialized = await session.browser.initializeAsync(
|
|
9700
|
+
options.userAgent ? { userAgent: options.userAgent } : {}
|
|
9701
|
+
);
|
|
9702
|
+
if (!initialized) throw new Error("AgentBay browser initialization failed");
|
|
9703
|
+
const endpoint = await session.browser.getEndpointUrl();
|
|
9704
|
+
const cdp = await (options.connectCdp ?? ((url2) => CdpClient.connect(url2)))(endpoint);
|
|
9705
|
+
try {
|
|
9706
|
+
await cdp.sendCommand("Browser.getVersion", {}, 1e4);
|
|
9707
|
+
const copiedCookieCount = await cdpImportCookiesWithClient(cdp, cookies);
|
|
9708
|
+
if (input.url) {
|
|
9709
|
+
await cdp.sendCommand("Target.createTarget", { url: input.url, background: false });
|
|
9710
|
+
}
|
|
9711
|
+
return copiedCookieCount;
|
|
9712
|
+
} finally {
|
|
9713
|
+
cdp.close();
|
|
9714
|
+
}
|
|
9715
|
+
}
|
|
9716
|
+
async function launchAgentBayBrowser(input, deps) {
|
|
9717
|
+
const name = validateName(input.name);
|
|
9718
|
+
const browserId = agentBayBrowserId(name);
|
|
9719
|
+
validateAgentBayInput(input);
|
|
9720
|
+
const imageId = resolveAgentBayImageId(input.imageId);
|
|
9721
|
+
const persistent = input.persistent === true;
|
|
9722
|
+
const userAgentMode = resolveUserAgentMode(input.userAgentMode);
|
|
9723
|
+
const copyCookieDomains = input.copyCookieDomains === void 0 ? [] : normalizeCookieDomains(input.copyCookieDomains);
|
|
9724
|
+
const apiKey = (deps.resolveApiKey ?? resolveAgentBayApiKey)();
|
|
9725
|
+
const releaseLock = acquireLaunchLock(browserId);
|
|
9726
|
+
const persistBrowserRecord = deps.persistBrowserRecord ?? ((record2) => writeRecord(keyedConfigFile(AGENTBAY_BROWSERS_SUBDIR, record2.browserId), record2));
|
|
9727
|
+
let session = null;
|
|
9728
|
+
let context;
|
|
9729
|
+
let hostPid = 0;
|
|
9730
|
+
let recordWritten = false;
|
|
9731
|
+
try {
|
|
9732
|
+
if (findRecord(browserId)) throw new Error(`AgentBay browser already exists: ${browserId}`);
|
|
9733
|
+
const [cookies, userAgent] = await Promise.all([
|
|
9734
|
+
copyCookieDomains.length > 0 ? deps.exportCookies(copyCookieDomains) : Promise.resolve([]),
|
|
9735
|
+
userAgentMode === "desktop" ? deps.getBrowserUserAgent().then(normalizeDesktopUserAgent) : Promise.resolve(void 0)
|
|
9736
|
+
]);
|
|
9737
|
+
const agentBay = await (deps.createAgentBayClient ?? createClient)(apiKey);
|
|
9738
|
+
context = persistent ? await resolvePersistentContext(agentBay, browserId) : void 0;
|
|
9739
|
+
const created = await agentBay.create({
|
|
9740
|
+
imageId,
|
|
9741
|
+
framework: "mearl",
|
|
9742
|
+
...context ? {
|
|
9743
|
+
browserContext: {
|
|
9744
|
+
contextId: context.id,
|
|
9745
|
+
autoUpload: true,
|
|
9746
|
+
syncMode: "standard"
|
|
9747
|
+
}
|
|
9748
|
+
} : {}
|
|
9749
|
+
});
|
|
9750
|
+
if (!created.success || !created.session) {
|
|
9751
|
+
throw new Error(created.errorMessage || "AgentBay session creation failed");
|
|
9752
|
+
}
|
|
9753
|
+
session = created.session;
|
|
9754
|
+
const copiedCookieCount = await initializeAgentBayBrowserSession(session, input, cookies, {
|
|
9755
|
+
userAgent
|
|
9756
|
+
});
|
|
9757
|
+
const host = spawn4(
|
|
9758
|
+
process.execPath,
|
|
9759
|
+
[
|
|
9760
|
+
deps.nativeHostScript,
|
|
9761
|
+
"--daemon",
|
|
9762
|
+
"--agentbay-session-id",
|
|
9763
|
+
session.sessionId,
|
|
9764
|
+
"--browser-id",
|
|
9765
|
+
browserId,
|
|
9766
|
+
"--browser-name",
|
|
9767
|
+
name
|
|
9768
|
+
],
|
|
9769
|
+
{
|
|
9770
|
+
detached: true,
|
|
9771
|
+
stdio: "ignore",
|
|
9772
|
+
windowsHide: true
|
|
9773
|
+
}
|
|
9774
|
+
);
|
|
9775
|
+
await new Promise((resolveSpawn, rejectSpawn) => {
|
|
9776
|
+
host.once("error", rejectSpawn);
|
|
9777
|
+
host.once("spawn", resolveSpawn);
|
|
9778
|
+
});
|
|
9779
|
+
hostPid = host.pid ?? 0;
|
|
9780
|
+
if (!hostPid) throw new Error("AgentBay native host launched without a process id");
|
|
9781
|
+
host.unref();
|
|
9782
|
+
const accessUrl = normalizeAgentBayAccessUrl(session.resourceUrl);
|
|
9783
|
+
const record2 = {
|
|
9784
|
+
pid: hostPid,
|
|
9785
|
+
browserId,
|
|
9786
|
+
name,
|
|
9787
|
+
sessionId: session.sessionId,
|
|
9788
|
+
imageId,
|
|
9789
|
+
persistent,
|
|
9790
|
+
...context ? { contextId: context.id, contextName: context.name } : {},
|
|
9791
|
+
...accessUrl ? { accessUrl } : {},
|
|
9792
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9793
|
+
...copyCookieDomains.length > 0 ? { copiedCookies: { domains: copyCookieDomains, count: copiedCookieCount } } : {}
|
|
9794
|
+
};
|
|
9795
|
+
persistBrowserRecord(record2);
|
|
9796
|
+
recordWritten = true;
|
|
9797
|
+
await waitForBrowserRegistration(browserId, hostPid);
|
|
9798
|
+
deps.log(`AgentBay browser launched: ${browserId}, host=${hostPid}`);
|
|
9799
|
+
return browserSummary2(record2, true);
|
|
9800
|
+
} catch (error48) {
|
|
9801
|
+
if (hostPid) await stopProcess(hostPid, `--browser-id ${browserId}`);
|
|
9802
|
+
if (recordWritten) {
|
|
9803
|
+
removeRecord(keyedConfigFile(AGENTBAY_BROWSERS_SUBDIR, browserId));
|
|
9804
|
+
removeRecord(keyedConfigFile("browsers", browserId));
|
|
9805
|
+
}
|
|
9806
|
+
if (session) {
|
|
9807
|
+
let cleanupError;
|
|
9808
|
+
try {
|
|
9809
|
+
const deleted = await session.delete(false);
|
|
9810
|
+
if (!deleted.success) {
|
|
9811
|
+
cleanupError = new Error(deleted.errorMessage || "AgentBay session deletion failed");
|
|
9812
|
+
}
|
|
9813
|
+
} catch (deleteError) {
|
|
9814
|
+
cleanupError = deleteError;
|
|
9815
|
+
}
|
|
9816
|
+
if (cleanupError) {
|
|
9817
|
+
const accessUrl = normalizeAgentBayAccessUrl(session.resourceUrl);
|
|
9818
|
+
const recoveryRecord = {
|
|
9819
|
+
pid: hostPid,
|
|
9820
|
+
browserId,
|
|
9821
|
+
name,
|
|
9822
|
+
sessionId: session.sessionId,
|
|
9823
|
+
imageId,
|
|
9824
|
+
persistent,
|
|
9825
|
+
...context ? { contextId: context.id, contextName: context.name } : {},
|
|
9826
|
+
...accessUrl ? { accessUrl } : {},
|
|
9827
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9828
|
+
};
|
|
9829
|
+
let recoverySaved = false;
|
|
9830
|
+
let recoveryError;
|
|
9831
|
+
try {
|
|
9832
|
+
persistBrowserRecord(recoveryRecord);
|
|
9833
|
+
recoverySaved = true;
|
|
9834
|
+
} catch (writeError) {
|
|
9835
|
+
recoveryError = writeError;
|
|
9836
|
+
}
|
|
9837
|
+
deps.log(
|
|
9838
|
+
`AgentBay launch cleanup failed for ${session.sessionId}:`,
|
|
9839
|
+
cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
9840
|
+
);
|
|
9841
|
+
if (recoveryError) {
|
|
9842
|
+
deps.log(
|
|
9843
|
+
`AgentBay recovery metadata could not be saved for ${session.sessionId}:`,
|
|
9844
|
+
recoveryError instanceof Error ? recoveryError.message : String(recoveryError)
|
|
9845
|
+
);
|
|
9846
|
+
}
|
|
9847
|
+
throw new AggregateError(
|
|
9848
|
+
recoveryError ? [error48, cleanupError, recoveryError] : [error48, cleanupError],
|
|
9849
|
+
`${error48 instanceof Error ? error48.message : String(error48)}; ` + (recoverySaved ? "AgentBay session cleanup failed and recovery metadata was retained for browser_close" : `AgentBay session cleanup failed; session ${session.sessionId} may require manual deletion`),
|
|
9850
|
+
{ cause: error48 }
|
|
9851
|
+
);
|
|
9852
|
+
}
|
|
9853
|
+
}
|
|
9854
|
+
throw error48;
|
|
9855
|
+
} finally {
|
|
9856
|
+
releaseLock();
|
|
9857
|
+
}
|
|
9858
|
+
}
|
|
9859
|
+
function isMissingSessionError(error48) {
|
|
9860
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
9861
|
+
return /not[ -]?found|does not exist|already deleted|invalid session/i.test(message);
|
|
9862
|
+
}
|
|
9863
|
+
async function releaseAgentBayBrowserResources(record2, agentBay, options = {}) {
|
|
9864
|
+
const deleteContext = record2.persistent === true && options.deleteProfile === true;
|
|
9865
|
+
const syncContext = record2.persistent === true && !deleteContext;
|
|
9866
|
+
let contextSynced = Boolean(record2.contextSyncedAt);
|
|
9867
|
+
let session;
|
|
9868
|
+
try {
|
|
9869
|
+
session = await requireSessionFromClient(agentBay, record2.sessionId);
|
|
9870
|
+
} catch (error48) {
|
|
9871
|
+
if (!isMissingSessionError(error48)) throw error48;
|
|
9872
|
+
}
|
|
9873
|
+
if (session) {
|
|
9874
|
+
if (syncContext && !contextSynced) {
|
|
9875
|
+
if (!session.callMcpTool) {
|
|
9876
|
+
throw new Error("The installed AgentBay SDK cannot stop the browser before context sync");
|
|
9877
|
+
}
|
|
9878
|
+
const stopped = await session.callMcpTool("stopChrome", {}, false);
|
|
9879
|
+
if (stopped.success === false) {
|
|
9880
|
+
throw new Error(stopped.errorMessage || "AgentBay browser shutdown failed");
|
|
9881
|
+
}
|
|
9882
|
+
if (!session.context) {
|
|
9883
|
+
throw new Error("The installed AgentBay SDK cannot synchronize browser context state");
|
|
9884
|
+
}
|
|
9885
|
+
const synced = await session.context.sync();
|
|
9886
|
+
if (!synced.success) {
|
|
9887
|
+
throw new Error(synced.errorMessage || "AgentBay browser context sync failed");
|
|
9888
|
+
}
|
|
9889
|
+
contextSynced = true;
|
|
9890
|
+
record2.contextSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9891
|
+
options.persistRecord?.(record2);
|
|
9892
|
+
}
|
|
9893
|
+
try {
|
|
9894
|
+
const result = await session.delete(false);
|
|
9895
|
+
if (!result.success) {
|
|
9896
|
+
throw new Error(result.errorMessage || "AgentBay session deletion failed");
|
|
9897
|
+
}
|
|
9898
|
+
} catch (error48) {
|
|
9899
|
+
if (!isMissingSessionError(error48)) throw error48;
|
|
9900
|
+
}
|
|
9901
|
+
}
|
|
9902
|
+
if (deleteContext) {
|
|
9903
|
+
if (!record2.contextId || !record2.contextName || !agentBay.context) {
|
|
9904
|
+
throw new Error("AgentBay browser context metadata is unavailable for profile deletion");
|
|
9905
|
+
}
|
|
9906
|
+
const result = await agentBay.context.delete({
|
|
9907
|
+
id: record2.contextId,
|
|
9908
|
+
name: record2.contextName
|
|
9909
|
+
});
|
|
9910
|
+
if (!result.success) throw new Error(result.errorMessage || "AgentBay context deletion failed");
|
|
9911
|
+
}
|
|
9912
|
+
return {
|
|
9913
|
+
sessionDeleted: true,
|
|
9914
|
+
...syncContext ? { contextSynced } : {},
|
|
9915
|
+
...deleteContext ? { contextDeleted: true } : {}
|
|
9916
|
+
};
|
|
9917
|
+
}
|
|
9918
|
+
async function closeAgentBayBrowser(selector, options = {}) {
|
|
9919
|
+
const record2 = findRecord(selector);
|
|
9920
|
+
if (!record2) throw new Error(`AgentBay browser not found: ${selector}`);
|
|
9921
|
+
const agentBay = await createClient(resolveAgentBayApiKey());
|
|
9922
|
+
const released = await releaseAgentBayBrowserResources(record2, agentBay, {
|
|
9923
|
+
...options,
|
|
9924
|
+
persistRecord: (updatedRecord) => writeRecord(
|
|
9925
|
+
keyedConfigFile(AGENTBAY_BROWSERS_SUBDIR, updatedRecord.browserId),
|
|
9926
|
+
updatedRecord
|
|
9927
|
+
)
|
|
9928
|
+
});
|
|
9929
|
+
const closingOwnHost = record2.pid === process.pid;
|
|
9930
|
+
if (!closingOwnHost) await stopProcess(record2.pid, `--browser-id ${record2.browserId}`);
|
|
9931
|
+
removeRecord(keyedConfigFile(AGENTBAY_BROWSERS_SUBDIR, record2.browserId));
|
|
9932
|
+
removeRecord(keyedConfigFile("browsers", record2.browserId));
|
|
9933
|
+
if (closingOwnHost) {
|
|
9934
|
+
const timer = setTimeout(() => process.kill(process.pid, "SIGTERM"), 250);
|
|
9935
|
+
timer.unref();
|
|
9936
|
+
}
|
|
9937
|
+
return {
|
|
9938
|
+
browserId: record2.browserId,
|
|
9939
|
+
provider: "agentbay",
|
|
9940
|
+
closed: true,
|
|
9941
|
+
...released,
|
|
9942
|
+
...record2.persistent === true ? { profileDeleted: options.deleteProfile === true } : { profileDeleted: true }
|
|
9943
|
+
};
|
|
9944
|
+
}
|
|
9945
|
+
|
|
9569
9946
|
// src/browser-registry.ts
|
|
9570
9947
|
var BROWSERS_SUBDIR = "browsers";
|
|
9571
9948
|
var STALE_RECORD_TTL_MS = 5 * 6e4;
|
|
@@ -9715,10 +10092,16 @@ function mergeBrowserInventory(connected, managed) {
|
|
|
9715
10092
|
...connectionFields(record2),
|
|
9716
10093
|
headless: managedBrowser.headless,
|
|
9717
10094
|
persistent: managedBrowser.persistent,
|
|
9718
|
-
|
|
10095
|
+
provider: managedBrowser.provider,
|
|
10096
|
+
..."cdpPort" in managedBrowser ? { cdpPort: managedBrowser.cdpPort } : {},
|
|
10097
|
+
..."agentbaySessionId" in managedBrowser ? { agentbaySessionId: managedBrowser.agentbaySessionId } : {},
|
|
10098
|
+
..."agentbayImageId" in managedBrowser && managedBrowser.agentbayImageId ? { agentbayImageId: managedBrowser.agentbayImageId } : {},
|
|
10099
|
+
..."agentbayContextId" in managedBrowser && managedBrowser.agentbayContextId ? { agentbayContextId: managedBrowser.agentbayContextId } : {},
|
|
10100
|
+
..."agentbayContextName" in managedBrowser && managedBrowser.agentbayContextName ? { agentbayContextName: managedBrowser.agentbayContextName } : {},
|
|
10101
|
+
..."agentbayAccessUrl" in managedBrowser && managedBrowser.agentbayAccessUrl ? { agentbayAccessUrl: managedBrowser.agentbayAccessUrl } : {},
|
|
9719
10102
|
createdAt: managedBrowser.createdAt,
|
|
9720
|
-
account: managedBrowser.account,
|
|
9721
|
-
copiedCookies: managedBrowser.copiedCookies
|
|
10103
|
+
..."account" in managedBrowser ? { account: managedBrowser.account } : {},
|
|
10104
|
+
..."copiedCookies" in managedBrowser ? { copiedCookies: managedBrowser.copiedCookies } : {}
|
|
9722
10105
|
};
|
|
9723
10106
|
});
|
|
9724
10107
|
const disconnected = [...managedById.values()].sort((a, b) => b.createdAt.localeCompare(a.createdAt)).map((browser) => ({
|
|
@@ -9728,10 +10111,16 @@ function mergeBrowserInventory(connected, managed) {
|
|
|
9728
10111
|
status: browser.running ? "running_disconnected" : "stopped",
|
|
9729
10112
|
headless: browser.headless,
|
|
9730
10113
|
persistent: browser.persistent,
|
|
9731
|
-
|
|
10114
|
+
provider: browser.provider,
|
|
10115
|
+
..."cdpPort" in browser ? { cdpPort: browser.cdpPort } : {},
|
|
10116
|
+
..."agentbaySessionId" in browser ? { agentbaySessionId: browser.agentbaySessionId } : {},
|
|
10117
|
+
..."agentbayImageId" in browser && browser.agentbayImageId ? { agentbayImageId: browser.agentbayImageId } : {},
|
|
10118
|
+
..."agentbayContextId" in browser && browser.agentbayContextId ? { agentbayContextId: browser.agentbayContextId } : {},
|
|
10119
|
+
..."agentbayContextName" in browser && browser.agentbayContextName ? { agentbayContextName: browser.agentbayContextName } : {},
|
|
10120
|
+
..."agentbayAccessUrl" in browser && browser.agentbayAccessUrl ? { agentbayAccessUrl: browser.agentbayAccessUrl } : {},
|
|
9732
10121
|
createdAt: browser.createdAt,
|
|
9733
|
-
account: browser.account,
|
|
9734
|
-
copiedCookies: browser.copiedCookies
|
|
10122
|
+
..."account" in browser ? { account: browser.account } : {},
|
|
10123
|
+
..."copiedCookies" in browser ? { copiedCookies: browser.copiedCookies } : {}
|
|
9735
10124
|
}));
|
|
9736
10125
|
browsers.push(...disconnected);
|
|
9737
10126
|
return {
|
|
@@ -9741,7 +10130,7 @@ function mergeBrowserInventory(connected, managed) {
|
|
|
9741
10130
|
};
|
|
9742
10131
|
}
|
|
9743
10132
|
function listBrowserInventory() {
|
|
9744
|
-
const managed = listManagedBrowsers();
|
|
10133
|
+
const managed = [...listManagedBrowsers(), ...listAgentBayBrowsers()];
|
|
9745
10134
|
return mergeBrowserInventory(listRegisteredBrowsers(), managed);
|
|
9746
10135
|
}
|
|
9747
10136
|
|
|
@@ -9752,7 +10141,7 @@ import os2 from "node:os";
|
|
|
9752
10141
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
9753
10142
|
|
|
9754
10143
|
// src/version.ts
|
|
9755
|
-
var NATIVE_HOST_VERSION = true ? "2.
|
|
10144
|
+
var NATIVE_HOST_VERSION = true ? "2.5.1" : "unknown";
|
|
9756
10145
|
|
|
9757
10146
|
// src/analytics.ts
|
|
9758
10147
|
var MEASUREMENT_ID = "G-W84LJDZ6PH";
|
|
@@ -9936,14 +10325,14 @@ function selectedPath(stdout) {
|
|
|
9936
10325
|
const value = stdout.replace(/[\r\n]+$/, "");
|
|
9937
10326
|
return value || null;
|
|
9938
10327
|
}
|
|
9939
|
-
var runDirectoryPickerCommand = (command, args) => new Promise((
|
|
10328
|
+
var runDirectoryPickerCommand = (command, args) => new Promise((resolve2, reject) => {
|
|
9940
10329
|
execFile(command, args, { encoding: "utf8", windowsHide: true }, (error48, stdout) => {
|
|
9941
10330
|
if (!error48) {
|
|
9942
|
-
|
|
10331
|
+
resolve2(selectedPath(stdout));
|
|
9943
10332
|
return;
|
|
9944
10333
|
}
|
|
9945
10334
|
if (error48.code === 1) {
|
|
9946
|
-
|
|
10335
|
+
resolve2(null);
|
|
9947
10336
|
return;
|
|
9948
10337
|
}
|
|
9949
10338
|
reject(error48);
|
|
@@ -10614,17 +11003,17 @@ var AgentChatManager = class {
|
|
|
10614
11003
|
// src/agent/codex-provider.ts
|
|
10615
11004
|
import os3 from "node:os";
|
|
10616
11005
|
import readline from "node:readline";
|
|
10617
|
-
import { spawn as
|
|
11006
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
10618
11007
|
|
|
10619
11008
|
// src/agent/executable-resolver.ts
|
|
10620
11009
|
import fs6 from "node:fs";
|
|
10621
|
-
import { spawn as
|
|
11010
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
10622
11011
|
import path7 from "node:path";
|
|
10623
11012
|
|
|
10624
11013
|
// ../setup/dist/process.js
|
|
10625
11014
|
import fs5 from "node:fs";
|
|
10626
11015
|
import path6 from "node:path";
|
|
10627
|
-
import { spawn as
|
|
11016
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
10628
11017
|
var MAX_CAPTURE_LENGTH = 1e6;
|
|
10629
11018
|
function isExecutable(filePath, platform = process.platform) {
|
|
10630
11019
|
try {
|
|
@@ -10686,7 +11075,7 @@ function prependPathDirectory(directory, env = process.env) {
|
|
|
10686
11075
|
function findExecutable(name, options = {}) {
|
|
10687
11076
|
const env = options.env ?? process.env;
|
|
10688
11077
|
const platform = options.platform ?? process.platform;
|
|
10689
|
-
const
|
|
11078
|
+
const existsSync5 = options.existsSync ?? ((candidate) => isExecutable(candidate, platform));
|
|
10690
11079
|
const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH";
|
|
10691
11080
|
const directories = [
|
|
10692
11081
|
...options.extraDirectories ?? [],
|
|
@@ -10695,16 +11084,16 @@ function findExecutable(name, options = {}) {
|
|
|
10695
11084
|
for (const directory of directories) {
|
|
10696
11085
|
for (const executableName of executableNames(name, platform)) {
|
|
10697
11086
|
const candidate = path6.join(directory, executableName);
|
|
10698
|
-
if (
|
|
11087
|
+
if (existsSync5(candidate))
|
|
10699
11088
|
return candidate;
|
|
10700
11089
|
}
|
|
10701
11090
|
}
|
|
10702
11091
|
return null;
|
|
10703
11092
|
}
|
|
10704
|
-
var runCommand = (command, args, options = {}) => new Promise((
|
|
11093
|
+
var runCommand = (command, args, options = {}) => new Promise((resolve2, reject) => {
|
|
10705
11094
|
const capture = options.capture === true;
|
|
10706
11095
|
const launch = resolveSpawnCommand(command, args);
|
|
10707
|
-
const child =
|
|
11096
|
+
const child = spawn5(launch.command, launch.args, {
|
|
10708
11097
|
cwd: options.cwd,
|
|
10709
11098
|
env: options.env,
|
|
10710
11099
|
stdio: capture ? ["ignore", "pipe", "pipe"] : "inherit",
|
|
@@ -10723,7 +11112,7 @@ var runCommand = (command, args, options = {}) => new Promise((resolve, reject)
|
|
|
10723
11112
|
if (error48)
|
|
10724
11113
|
reject(error48);
|
|
10725
11114
|
else
|
|
10726
|
-
|
|
11115
|
+
resolve2({ code, stdout, stderr });
|
|
10727
11116
|
};
|
|
10728
11117
|
const timer = options.timeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
10729
11118
|
child.kill("SIGTERM");
|
|
@@ -10845,11 +11234,11 @@ function executableFileCandidates(candidates) {
|
|
|
10845
11234
|
return executableCandidates;
|
|
10846
11235
|
}
|
|
10847
11236
|
function probeAgentExecutable(executable, options) {
|
|
10848
|
-
return new Promise((
|
|
11237
|
+
return new Promise((resolve2) => {
|
|
10849
11238
|
let settled = false;
|
|
10850
11239
|
let stderr = "";
|
|
10851
11240
|
const launch = resolveSpawnCommand(executable, options.args);
|
|
10852
|
-
const child =
|
|
11241
|
+
const child = spawn6(launch.command, launch.args, {
|
|
10853
11242
|
stdio: ["ignore", "ignore", "pipe"],
|
|
10854
11243
|
windowsHide: true,
|
|
10855
11244
|
env: prependNodePath()
|
|
@@ -10858,7 +11247,7 @@ function probeAgentExecutable(executable, options) {
|
|
|
10858
11247
|
if (settled) return;
|
|
10859
11248
|
settled = true;
|
|
10860
11249
|
clearTimeout(timer);
|
|
10861
|
-
|
|
11250
|
+
resolve2(error48);
|
|
10862
11251
|
};
|
|
10863
11252
|
const timer = setTimeout(() => {
|
|
10864
11253
|
child.kill("SIGTERM");
|
|
@@ -10989,13 +11378,13 @@ function externalOpenCommand(url2, platform = process.platform) {
|
|
|
10989
11378
|
}
|
|
10990
11379
|
function openExternalUrl(url2) {
|
|
10991
11380
|
const { command, args } = externalOpenCommand(url2);
|
|
10992
|
-
return new Promise((
|
|
10993
|
-
const child =
|
|
11381
|
+
return new Promise((resolve2, reject) => {
|
|
11382
|
+
const child = spawn7(command, args, { stdio: "ignore", windowsHide: true });
|
|
10994
11383
|
child.once("error", (error48) => {
|
|
10995
11384
|
reject(new Error(`Unable to open Codex App: ${error48.message}`));
|
|
10996
11385
|
});
|
|
10997
11386
|
child.once("close", (code) => {
|
|
10998
|
-
if (code === 0)
|
|
11387
|
+
if (code === 0) resolve2();
|
|
10999
11388
|
else reject(new Error("Unable to open Codex App. Make sure it is installed."));
|
|
11000
11389
|
});
|
|
11001
11390
|
});
|
|
@@ -11162,7 +11551,7 @@ var CodexAgentProvider = class {
|
|
|
11162
11551
|
url: `data:${image.mimeType};base64,${image.data}`
|
|
11163
11552
|
}))
|
|
11164
11553
|
],
|
|
11165
|
-
summary: "
|
|
11554
|
+
summary: "detailed"
|
|
11166
11555
|
});
|
|
11167
11556
|
const turnId = result?.turn?.id;
|
|
11168
11557
|
if (typeof turnId !== "string" || !turnId) {
|
|
@@ -11224,7 +11613,7 @@ var CodexAgentProvider = class {
|
|
|
11224
11613
|
const launch = resolveSpawnCommand(executable, ["app-server", "--listen", "stdio://"]);
|
|
11225
11614
|
const childEnv = prependNodePath();
|
|
11226
11615
|
if (this.mearlSocketPath) childEnv.MEARL_SOCKET_PATH = this.mearlSocketPath;
|
|
11227
|
-
const child =
|
|
11616
|
+
const child = spawn7(launch.command, launch.args, {
|
|
11228
11617
|
stdio: ["pipe", "pipe", "pipe"],
|
|
11229
11618
|
windowsHide: true,
|
|
11230
11619
|
env: childEnv
|
|
@@ -11316,12 +11705,12 @@ var CodexAgentProvider = class {
|
|
|
11316
11705
|
}
|
|
11317
11706
|
request(method, params) {
|
|
11318
11707
|
const id = this.nextRequestId++;
|
|
11319
|
-
return new Promise((
|
|
11708
|
+
return new Promise((resolve2, reject) => {
|
|
11320
11709
|
const timer = setTimeout(() => {
|
|
11321
11710
|
this.pendingRequests.delete(id);
|
|
11322
11711
|
reject(new Error(`Codex request timed out: ${method}`));
|
|
11323
11712
|
}, REQUEST_TIMEOUT_MS);
|
|
11324
|
-
this.pendingRequests.set(id, { resolve, reject, timer });
|
|
11713
|
+
this.pendingRequests.set(id, { resolve: resolve2, reject, timer });
|
|
11325
11714
|
try {
|
|
11326
11715
|
this.write({ id, method, params });
|
|
11327
11716
|
} catch (error48) {
|
|
@@ -11395,7 +11784,7 @@ var CodexAgentProvider = class {
|
|
|
11395
11784
|
import fs7 from "node:fs";
|
|
11396
11785
|
import os4 from "node:os";
|
|
11397
11786
|
import path8 from "node:path";
|
|
11398
|
-
import { spawn as
|
|
11787
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
11399
11788
|
import { Readable, Writable } from "node:stream";
|
|
11400
11789
|
|
|
11401
11790
|
// ../../node_modules/.pnpm/@agentclientprotocol+sdk@1.2.1_zod@4.3.6/node_modules/@agentclientprotocol/sdk/dist/schema/index.js
|
|
@@ -11631,7 +12020,7 @@ __export(external_exports, {
|
|
|
11631
12020
|
object: () => object,
|
|
11632
12021
|
optional: () => optional,
|
|
11633
12022
|
overwrite: () => _overwrite,
|
|
11634
|
-
parse: () =>
|
|
12023
|
+
parse: () => parse3,
|
|
11635
12024
|
parseAsync: () => parseAsync2,
|
|
11636
12025
|
partialRecord: () => partialRecord,
|
|
11637
12026
|
pipe: () => pipe,
|
|
@@ -11950,7 +12339,7 @@ __export(core_exports2, {
|
|
|
11950
12339
|
isValidJWT: () => isValidJWT,
|
|
11951
12340
|
locales: () => locales_exports,
|
|
11952
12341
|
meta: () => meta,
|
|
11953
|
-
parse: () =>
|
|
12342
|
+
parse: () => parse2,
|
|
11954
12343
|
parseAsync: () => parseAsync,
|
|
11955
12344
|
prettifyError: () => prettifyError,
|
|
11956
12345
|
process: () => process2,
|
|
@@ -12873,7 +13262,7 @@ var _parse = (_Err) => (schema, value, _ctx, _params) => {
|
|
|
12873
13262
|
}
|
|
12874
13263
|
return result.value;
|
|
12875
13264
|
};
|
|
12876
|
-
var
|
|
13265
|
+
var parse2 = /* @__PURE__ */ _parse($ZodRealError);
|
|
12877
13266
|
var _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
|
|
12878
13267
|
const ctx = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
|
12879
13268
|
let result = schema._zod.run({ value, issues: [] }, ctx);
|
|
@@ -15546,10 +15935,10 @@ var $ZodFunction = /* @__PURE__ */ $constructor("$ZodFunction", (inst, def) => {
|
|
|
15546
15935
|
throw new Error("implement() must be called with a function");
|
|
15547
15936
|
}
|
|
15548
15937
|
return function(...args) {
|
|
15549
|
-
const parsedArgs = inst._def.input ?
|
|
15938
|
+
const parsedArgs = inst._def.input ? parse2(inst._def.input, args) : args;
|
|
15550
15939
|
const result = Reflect.apply(func, this, parsedArgs);
|
|
15551
15940
|
if (inst._def.output) {
|
|
15552
|
-
return
|
|
15941
|
+
return parse2(inst._def.output, result);
|
|
15553
15942
|
}
|
|
15554
15943
|
return result;
|
|
15555
15944
|
};
|
|
@@ -23598,7 +23987,7 @@ var ZodRealError = $constructor("ZodError", initializer2, {
|
|
|
23598
23987
|
});
|
|
23599
23988
|
|
|
23600
23989
|
// ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/parse.js
|
|
23601
|
-
var
|
|
23990
|
+
var parse3 = /* @__PURE__ */ _parse(ZodRealError);
|
|
23602
23991
|
var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
23603
23992
|
var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
23604
23993
|
var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
|
|
@@ -23641,7 +24030,7 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
23641
24030
|
reg.add(inst, meta3);
|
|
23642
24031
|
return inst;
|
|
23643
24032
|
});
|
|
23644
|
-
inst.parse = (data, params) =>
|
|
24033
|
+
inst.parse = (data, params) => parse3(inst, data, params, { callee: inst.parse });
|
|
23645
24034
|
inst.safeParse = (data, params) => safeParse2(inst, data, params);
|
|
23646
24035
|
inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
|
|
23647
24036
|
inst.safeParseAsync = async (data, params) => safeParseAsync2(inst, data, params);
|
|
@@ -27200,12 +27589,12 @@ var Connection = class {
|
|
|
27200
27589
|
const id = this.nextRequestId++;
|
|
27201
27590
|
let cancel = () => {
|
|
27202
27591
|
};
|
|
27203
|
-
const responsePromise = new Promise((
|
|
27592
|
+
const responsePromise = new Promise((resolve2, reject) => {
|
|
27204
27593
|
const pendingResponse = {
|
|
27205
27594
|
resolve: (response) => {
|
|
27206
27595
|
try {
|
|
27207
27596
|
const value = mapResponse ? mapResponse(response) : response;
|
|
27208
|
-
|
|
27597
|
+
resolve2(value);
|
|
27209
27598
|
} catch (error48) {
|
|
27210
27599
|
reject(error48);
|
|
27211
27600
|
}
|
|
@@ -27283,8 +27672,8 @@ var Connection = class {
|
|
|
27283
27672
|
initialize(stream, handlers) {
|
|
27284
27673
|
this.stream = stream;
|
|
27285
27674
|
this.staticHandlers = handlers;
|
|
27286
|
-
this.closedPromise = new Promise((
|
|
27287
|
-
this.abortController.signal.addEventListener("abort", () =>
|
|
27675
|
+
this.closedPromise = new Promise((resolve2) => {
|
|
27676
|
+
this.abortController.signal.addEventListener("abort", () => resolve2());
|
|
27288
27677
|
});
|
|
27289
27678
|
void this.receive();
|
|
27290
27679
|
}
|
|
@@ -27509,13 +27898,13 @@ var ConnectionBuilder = class {
|
|
|
27509
27898
|
/**
|
|
27510
27899
|
* Adds a typed request handler for one method.
|
|
27511
27900
|
*/
|
|
27512
|
-
onReceiveRequest(method,
|
|
27901
|
+
onReceiveRequest(method, parse4, handler) {
|
|
27513
27902
|
return this.withHandler({
|
|
27514
27903
|
handleMessage: async (message, cx) => {
|
|
27515
27904
|
if (message.kind !== "request" || message.method !== method) {
|
|
27516
27905
|
return Handled.no(message);
|
|
27517
27906
|
}
|
|
27518
|
-
const request =
|
|
27907
|
+
const request = parse4(message.params);
|
|
27519
27908
|
return await handler(request, message.responder, cx) ?? Handled.yes();
|
|
27520
27909
|
},
|
|
27521
27910
|
describe: () => `${this.connectionName ?? "request"}:${method}`
|
|
@@ -27524,13 +27913,13 @@ var ConnectionBuilder = class {
|
|
|
27524
27913
|
/**
|
|
27525
27914
|
* Adds a typed notification handler for one method.
|
|
27526
27915
|
*/
|
|
27527
|
-
onReceiveNotification(method,
|
|
27916
|
+
onReceiveNotification(method, parse4, handler) {
|
|
27528
27917
|
return this.withHandler({
|
|
27529
27918
|
handleMessage: async (message, cx) => {
|
|
27530
27919
|
if (message.kind !== "notification" || message.method !== method) {
|
|
27531
27920
|
return Handled.no(message);
|
|
27532
27921
|
}
|
|
27533
|
-
const notification =
|
|
27922
|
+
const notification = parse4(message.params);
|
|
27534
27923
|
return await handler(notification, cx) ?? Handled.yes();
|
|
27535
27924
|
},
|
|
27536
27925
|
describe: () => `${this.connectionName ?? "notification"}:${method}`
|
|
@@ -28072,8 +28461,8 @@ var AsyncQueue = class {
|
|
|
28072
28461
|
if (this.failed) {
|
|
28073
28462
|
return Promise.reject(this.failure);
|
|
28074
28463
|
}
|
|
28075
|
-
return new Promise((
|
|
28076
|
-
this.waiters.push({ resolve, reject });
|
|
28464
|
+
return new Promise((resolve2, reject) => {
|
|
28465
|
+
this.waiters.push({ resolve: resolve2, reject });
|
|
28077
28466
|
});
|
|
28078
28467
|
}
|
|
28079
28468
|
};
|
|
@@ -29184,7 +29573,7 @@ ${message}` : message;
|
|
|
29184
29573
|
}
|
|
29185
29574
|
const { executable } = resolution;
|
|
29186
29575
|
const launch = resolveSpawnCommand(executable, ["--acp"]);
|
|
29187
|
-
const child =
|
|
29576
|
+
const child = spawn8(launch.command, launch.args, {
|
|
29188
29577
|
stdio: ["pipe", "pipe", "pipe"],
|
|
29189
29578
|
windowsHide: true,
|
|
29190
29579
|
env: prependNodePath()
|
|
@@ -29452,10 +29841,10 @@ ${message}` : message;
|
|
|
29452
29841
|
if (requestId === null) {
|
|
29453
29842
|
return Promise.resolve({ outcome: { outcome: "cancelled" } });
|
|
29454
29843
|
}
|
|
29455
|
-
return new Promise((
|
|
29844
|
+
return new Promise((resolve2) => {
|
|
29456
29845
|
this.pendingPermissions.set(requestId, {
|
|
29457
29846
|
providerSessionId: request.sessionId,
|
|
29458
|
-
resolve
|
|
29847
|
+
resolve: resolve2
|
|
29459
29848
|
});
|
|
29460
29849
|
this.emit({
|
|
29461
29850
|
providerSessionId: request.sessionId,
|
|
@@ -29502,7 +29891,7 @@ ${message}` : message;
|
|
|
29502
29891
|
}
|
|
29503
29892
|
}
|
|
29504
29893
|
withTimeout(promise2, operation) {
|
|
29505
|
-
return new Promise((
|
|
29894
|
+
return new Promise((resolve2, reject) => {
|
|
29506
29895
|
const timer = setTimeout(
|
|
29507
29896
|
() => reject(new Error(`${operation} timed out`)),
|
|
29508
29897
|
REQUEST_TIMEOUT_MS2
|
|
@@ -29510,7 +29899,7 @@ ${message}` : message;
|
|
|
29510
29899
|
promise2.then(
|
|
29511
29900
|
(result) => {
|
|
29512
29901
|
clearTimeout(timer);
|
|
29513
|
-
|
|
29902
|
+
resolve2(result);
|
|
29514
29903
|
},
|
|
29515
29904
|
(error48) => {
|
|
29516
29905
|
clearTimeout(timer);
|
|
@@ -29529,9 +29918,9 @@ ${message}` : message;
|
|
|
29529
29918
|
});
|
|
29530
29919
|
}
|
|
29531
29920
|
runSkillsList(executable, cwd) {
|
|
29532
|
-
return new Promise((
|
|
29921
|
+
return new Promise((resolve2, reject) => {
|
|
29533
29922
|
const launch = resolveSpawnCommand(executable, ["skill", "list", "--all"]);
|
|
29534
|
-
const child =
|
|
29923
|
+
const child = spawn8(launch.command, launch.args, {
|
|
29535
29924
|
cwd,
|
|
29536
29925
|
stdio: ["ignore", "pipe", "pipe"],
|
|
29537
29926
|
windowsHide: true,
|
|
@@ -29545,7 +29934,7 @@ ${message}` : message;
|
|
|
29545
29934
|
settled = true;
|
|
29546
29935
|
clearTimeout(timer);
|
|
29547
29936
|
if (error48) reject(error48);
|
|
29548
|
-
else
|
|
29937
|
+
else resolve2(stdout);
|
|
29549
29938
|
};
|
|
29550
29939
|
const timer = setTimeout(() => {
|
|
29551
29940
|
child.kill("SIGTERM");
|
|
@@ -29580,12 +29969,12 @@ ${message}` : message;
|
|
|
29580
29969
|
import fs8 from "node:fs";
|
|
29581
29970
|
import os5 from "node:os";
|
|
29582
29971
|
import path9 from "node:path";
|
|
29583
|
-
import { spawn as
|
|
29972
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
29584
29973
|
var COMMAND_TIMEOUT_MS = 12e4;
|
|
29585
29974
|
var MAX_OUTPUT_LENGTH = 1e6;
|
|
29586
29975
|
var ANSI_ESCAPE_PATTERN = new RegExp(String.raw`\u001B\[[0-?]*[ -/]*[@-~]`, "g");
|
|
29587
|
-
function existingExecutable(candidates,
|
|
29588
|
-
return candidates.find((candidate) => candidate &&
|
|
29976
|
+
function existingExecutable(candidates, existsSync5) {
|
|
29977
|
+
return candidates.find((candidate) => candidate && existsSync5(candidate)) ?? null;
|
|
29589
29978
|
}
|
|
29590
29979
|
function stripAnsi(value) {
|
|
29591
29980
|
return value.replace(ANSI_ESCAPE_PATTERN, "");
|
|
@@ -29594,7 +29983,7 @@ function resolveAliSkillsExecutable(options = {}) {
|
|
|
29594
29983
|
const env = options.env ?? process.env;
|
|
29595
29984
|
const home = (options.homedir ?? os5.homedir)();
|
|
29596
29985
|
const platform = options.platform ?? process.platform;
|
|
29597
|
-
const
|
|
29986
|
+
const existsSync5 = options.existsSync ?? ((candidate) => isExecutable(candidate, platform));
|
|
29598
29987
|
const processExecPath = options.processExecPath ?? process.execPath;
|
|
29599
29988
|
const readdirSync2 = options.readdirSync ?? fs8.readdirSync;
|
|
29600
29989
|
const names = executableNames("ali-skills", platform);
|
|
@@ -29616,11 +30005,11 @@ function resolveAliSkillsExecutable(options = {}) {
|
|
|
29616
30005
|
...platform === "win32" ? [] : ["/opt/homebrew/bin/ali-skills", "/usr/local/bin/ali-skills", "/usr/bin/ali-skills"],
|
|
29617
30006
|
...pathCandidates
|
|
29618
30007
|
];
|
|
29619
|
-
return existingExecutable(candidates,
|
|
30008
|
+
return existingExecutable(candidates, existsSync5);
|
|
29620
30009
|
}
|
|
29621
|
-
var runAliSkillsCli = (executable, args, cwd) => new Promise((
|
|
30010
|
+
var runAliSkillsCli = (executable, args, cwd) => new Promise((resolve2, reject) => {
|
|
29622
30011
|
const launch = resolveSpawnCommand(executable, args);
|
|
29623
|
-
const child =
|
|
30012
|
+
const child = spawn9(launch.command, launch.args, {
|
|
29624
30013
|
cwd,
|
|
29625
30014
|
env: prependNodePath(prependCommandPath(executable)),
|
|
29626
30015
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -29638,7 +30027,7 @@ var runAliSkillsCli = (executable, args, cwd) => new Promise((resolve, reject) =
|
|
|
29638
30027
|
if (error48)
|
|
29639
30028
|
reject(error48);
|
|
29640
30029
|
else
|
|
29641
|
-
|
|
30030
|
+
resolve2({ stdout, stderr });
|
|
29642
30031
|
};
|
|
29643
30032
|
const timer = setTimeout(() => {
|
|
29644
30033
|
child.kill("SIGTERM");
|
|
@@ -29826,7 +30215,7 @@ function createExtensionRequestMessage(id, action, data, trustedInternal = false
|
|
|
29826
30215
|
// src/host-updater.ts
|
|
29827
30216
|
import fs10 from "node:fs";
|
|
29828
30217
|
import path11 from "node:path";
|
|
29829
|
-
import { fileURLToPath } from "node:url";
|
|
30218
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
29830
30219
|
|
|
29831
30220
|
// ../setup/dist/packageManager.js
|
|
29832
30221
|
import fs9 from "node:fs";
|
|
@@ -29834,8 +30223,8 @@ import path10 from "node:path";
|
|
|
29834
30223
|
function normalizePath(filePath) {
|
|
29835
30224
|
return filePath.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
29836
30225
|
}
|
|
29837
|
-
function firstExisting(candidates,
|
|
29838
|
-
return candidates.find((candidate) =>
|
|
30226
|
+
function firstExisting(candidates, existsSync5) {
|
|
30227
|
+
return candidates.find((candidate) => existsSync5(candidate));
|
|
29839
30228
|
}
|
|
29840
30229
|
function fallbackCommand(name, platform) {
|
|
29841
30230
|
if (platform !== "win32")
|
|
@@ -29847,7 +30236,7 @@ function fallbackCommand(name, platform) {
|
|
|
29847
30236
|
function resolvePackageManagerInstallation(packageRoot, packageName, options = {}) {
|
|
29848
30237
|
const env = options.env ?? process.env;
|
|
29849
30238
|
const platform = options.platform ?? process.platform;
|
|
29850
|
-
const
|
|
30239
|
+
const existsSync5 = options.existsSync ?? ((candidate) => isExecutable(candidate, platform));
|
|
29851
30240
|
const processExecPath = options.processExecPath ?? process.execPath;
|
|
29852
30241
|
const normalizedRoot = normalizePath(path10.resolve(packageRoot));
|
|
29853
30242
|
const lowerRoot = normalizedRoot.toLowerCase();
|
|
@@ -29858,13 +30247,13 @@ function resolvePackageManagerInstallation(packageRoot, packageName, options = {
|
|
|
29858
30247
|
const command = firstExisting([
|
|
29859
30248
|
...executableNames("pnpm", platform).map((name) => path10.join(pnpmHome, name)),
|
|
29860
30249
|
...executableNames("pnpm", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
|
|
29861
|
-
],
|
|
30250
|
+
], existsSync5) ?? fallbackCommand("pnpm", platform);
|
|
29862
30251
|
return { manager: "pnpm", command, binDirectory: pnpmHome };
|
|
29863
30252
|
}
|
|
29864
30253
|
const bunMarker = `/.bun/install/global/node_modules/${lowerPackageName}`;
|
|
29865
30254
|
if (lowerRoot.endsWith(bunMarker)) {
|
|
29866
30255
|
const bunHome = normalizedRoot.slice(0, lowerRoot.indexOf("/.bun/"));
|
|
29867
|
-
const command = firstExisting(executableNames("bun", platform).map((name) => path10.join(bunHome, ".bun", "bin", name)),
|
|
30256
|
+
const command = firstExisting(executableNames("bun", platform).map((name) => path10.join(bunHome, ".bun", "bin", name)), existsSync5) ?? fallbackCommand("bun", platform);
|
|
29868
30257
|
return {
|
|
29869
30258
|
manager: "bun",
|
|
29870
30259
|
command,
|
|
@@ -29883,12 +30272,12 @@ function resolvePackageManagerInstallation(packageRoot, packageName, options = {
|
|
|
29883
30272
|
const command = firstExisting([
|
|
29884
30273
|
...executableNames("yarn", platform).map((name) => path10.join(binDirectory, name)),
|
|
29885
30274
|
...executableNames("yarn", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
|
|
29886
|
-
],
|
|
30275
|
+
], existsSync5) ?? findExecutable("yarn", { env, existsSync: existsSync5, platform }) ?? fallbackCommand("yarn", platform);
|
|
29887
30276
|
return { manager: "yarn", command, binDirectory };
|
|
29888
30277
|
}
|
|
29889
30278
|
if (lowerRoot.includes("/.volta/tools/image/packages/") && lowerRoot.endsWith(`/lib/node_modules/${lowerPackageName}`)) {
|
|
29890
30279
|
const voltaHome = normalizedRoot.slice(0, lowerRoot.indexOf("/.volta/"));
|
|
29891
|
-
const command = firstExisting(executableNames("volta", platform).map((name) => path10.join(voltaHome, ".volta", "bin", name)),
|
|
30280
|
+
const command = firstExisting(executableNames("volta", platform).map((name) => path10.join(voltaHome, ".volta", "bin", name)), existsSync5) ?? fallbackCommand("volta", platform);
|
|
29892
30281
|
return {
|
|
29893
30282
|
manager: "volta",
|
|
29894
30283
|
command,
|
|
@@ -29901,7 +30290,7 @@ function resolvePackageManagerInstallation(packageRoot, packageName, options = {
|
|
|
29901
30290
|
const command = firstExisting([
|
|
29902
30291
|
...executableNames("npm", platform).map((name) => path10.join(prefix, "bin", name)),
|
|
29903
30292
|
...executableNames("npm", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
|
|
29904
|
-
],
|
|
30293
|
+
], existsSync5) ?? fallbackCommand("npm", platform);
|
|
29905
30294
|
return { manager: "npm", command, binDirectory: path10.join(prefix, "bin") };
|
|
29906
30295
|
}
|
|
29907
30296
|
if (platform === "win32" && env.APPDATA) {
|
|
@@ -29911,7 +30300,7 @@ function resolvePackageManagerInstallation(packageRoot, packageName, options = {
|
|
|
29911
30300
|
const command = firstExisting([
|
|
29912
30301
|
...executableNames("npm", platform).map((name) => path10.join(binDirectory, name)),
|
|
29913
30302
|
...executableNames("npm", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
|
|
29914
|
-
],
|
|
30303
|
+
], existsSync5) ?? fallbackCommand("npm", platform);
|
|
29915
30304
|
return { manager: "npm", command, binDirectory };
|
|
29916
30305
|
}
|
|
29917
30306
|
}
|
|
@@ -30002,7 +30391,7 @@ var NativeHostUpdateFailure = class extends Error {
|
|
|
30002
30391
|
}
|
|
30003
30392
|
};
|
|
30004
30393
|
function wait(delayMs) {
|
|
30005
|
-
return new Promise((
|
|
30394
|
+
return new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
30006
30395
|
}
|
|
30007
30396
|
function readLockState(lockPath) {
|
|
30008
30397
|
try {
|
|
@@ -30115,7 +30504,7 @@ function currentNativeHostPackageRoot(entryPath) {
|
|
|
30115
30504
|
return null;
|
|
30116
30505
|
}
|
|
30117
30506
|
function currentPackageManagerInstallation(environment, nodePath, platform) {
|
|
30118
|
-
const packageRoot = currentNativeHostPackageRoot(
|
|
30507
|
+
const packageRoot = currentNativeHostPackageRoot(fileURLToPath2(import.meta.url));
|
|
30119
30508
|
if (!packageRoot) return null;
|
|
30120
30509
|
return resolvePackageManagerInstallation(packageRoot, "@mearl/native-host", {
|
|
30121
30510
|
env: environment,
|
|
@@ -30245,6 +30634,7 @@ function positivePort(value, fallback) {
|
|
|
30245
30634
|
}
|
|
30246
30635
|
var CDP_PORT = positivePort(cliOption("--cdp-port"), 9222);
|
|
30247
30636
|
var CDP_USER_DATA_DIR = cliOption("--cdp-user-data-dir");
|
|
30637
|
+
var AGENTBAY_SESSION_ID = cliOption("--agentbay-session-id");
|
|
30248
30638
|
var CDP_BROWSER_ID = cliOption("--browser-id") ?? "cdp";
|
|
30249
30639
|
var CDP_BROWSER_NAME = cliOption("--browser-name") ?? "CDP";
|
|
30250
30640
|
if (cliArg === "--init" || cliArg === "--uninstall") {
|
|
@@ -30271,6 +30661,7 @@ Options:
|
|
|
30271
30661
|
--daemon Start as standalone CDP daemon (no extension needed)
|
|
30272
30662
|
--cdp-port <port> CDP port for daemon mode (default 9222)
|
|
30273
30663
|
--cdp-user-data-dir <dir> Read DevToolsActivePort from this Chrome profile
|
|
30664
|
+
--agentbay-session-id <id> Connect to an AgentBay browser session over CDP
|
|
30274
30665
|
--browser-id <id> Registry id for this CDP browser
|
|
30275
30666
|
--browser-name <name> Human-readable registry name
|
|
30276
30667
|
--version, -v Show version
|
|
@@ -30314,28 +30705,53 @@ function extractChromeVersion(input) {
|
|
|
30314
30705
|
const parts = match[1].split(".");
|
|
30315
30706
|
return parts.slice(0, 3).join(".");
|
|
30316
30707
|
}
|
|
30317
|
-
function fetchCdpBrowserVersion() {
|
|
30708
|
+
async function fetchCdpBrowserVersion() {
|
|
30709
|
+
if (AGENTBAY_SESSION_ID) {
|
|
30710
|
+
try {
|
|
30711
|
+
const browser = await getCdpSession().getBrowserClient();
|
|
30712
|
+
const result = await browser.sendCommand("Browser.getVersion", {}, 5e3);
|
|
30713
|
+
return result.product ?? null;
|
|
30714
|
+
} catch {
|
|
30715
|
+
return null;
|
|
30716
|
+
}
|
|
30717
|
+
}
|
|
30318
30718
|
const port = readDevToolsActivePort(CDP_USER_DATA_DIR)?.port ?? CDP_PORT;
|
|
30319
|
-
return new Promise((
|
|
30320
|
-
const req =
|
|
30719
|
+
return new Promise((resolve2) => {
|
|
30720
|
+
const req = http4.get(`http://localhost:${port}/json/version`, (res) => {
|
|
30321
30721
|
let data = "";
|
|
30322
30722
|
res.on("data", (chunk) => data += chunk);
|
|
30323
30723
|
res.on("end", () => {
|
|
30324
30724
|
try {
|
|
30325
30725
|
const info = JSON.parse(data);
|
|
30326
|
-
|
|
30726
|
+
resolve2(info.Browser ?? null);
|
|
30327
30727
|
} catch {
|
|
30328
|
-
|
|
30728
|
+
resolve2(null);
|
|
30329
30729
|
}
|
|
30330
30730
|
});
|
|
30331
30731
|
});
|
|
30332
|
-
req.on("error", () =>
|
|
30732
|
+
req.on("error", () => resolve2(null));
|
|
30333
30733
|
req.setTimeout(2e3, () => {
|
|
30334
30734
|
req.destroy();
|
|
30335
|
-
|
|
30735
|
+
resolve2(null);
|
|
30336
30736
|
});
|
|
30337
30737
|
});
|
|
30338
30738
|
}
|
|
30739
|
+
async function getCurrentBrowserUserAgent() {
|
|
30740
|
+
if (extensionVersion !== null) {
|
|
30741
|
+
try {
|
|
30742
|
+
const result = await sendRequestToExtension("get_browser_info", {}, 3e3);
|
|
30743
|
+
if (result.userAgent?.trim()) return result.userAgent;
|
|
30744
|
+
} catch {
|
|
30745
|
+
}
|
|
30746
|
+
}
|
|
30747
|
+
try {
|
|
30748
|
+
const browser = await getCdpSession().getBrowserClient();
|
|
30749
|
+
const result = await browser.sendCommand("Browser.getVersion", {}, 5e3);
|
|
30750
|
+
if (result.userAgent?.trim()) return result.userAgent;
|
|
30751
|
+
} catch {
|
|
30752
|
+
}
|
|
30753
|
+
throw new Error("Could not determine the control browser user agent for userAgentMode=desktop");
|
|
30754
|
+
}
|
|
30339
30755
|
async function collectVersions() {
|
|
30340
30756
|
const info = {
|
|
30341
30757
|
nativeHost: NATIVE_HOST_VERSION,
|
|
@@ -30387,7 +30803,9 @@ function scheduleInventoryExit() {
|
|
|
30387
30803
|
var cdpSession = null;
|
|
30388
30804
|
function getCdpSession() {
|
|
30389
30805
|
if (!cdpSession) {
|
|
30390
|
-
cdpSession = new CdpSession({
|
|
30806
|
+
cdpSession = AGENTBAY_SESSION_ID ? new CdpSession({
|
|
30807
|
+
endpointResolver: () => resolveAgentBayEndpoint(AGENTBAY_SESSION_ID)
|
|
30808
|
+
}) : new CdpSession({ port: CDP_PORT, userDataDir: CDP_USER_DATA_DIR });
|
|
30391
30809
|
}
|
|
30392
30810
|
return cdpSession;
|
|
30393
30811
|
}
|
|
@@ -30591,12 +31009,12 @@ function setupNativeMessageInput() {
|
|
|
30591
31009
|
}
|
|
30592
31010
|
function sendRequestToExtension(action, data, timeoutMs, trustedInternal = false, controlSource = "local") {
|
|
30593
31011
|
const id = `${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
30594
|
-
return new Promise((
|
|
31012
|
+
return new Promise((resolve2, reject) => {
|
|
30595
31013
|
const timer = setTimeout(() => {
|
|
30596
31014
|
pendingRequests.delete(id);
|
|
30597
31015
|
reject(new Error(`Request timeout after ${timeoutMs}ms`));
|
|
30598
31016
|
}, timeoutMs);
|
|
30599
|
-
pendingRequests.set(id, { resolve, reject, timer });
|
|
31017
|
+
pendingRequests.set(id, { resolve: resolve2, reject, timer });
|
|
30600
31018
|
sendToExtension(
|
|
30601
31019
|
createExtensionRequestMessage(id, action, data, trustedInternal, controlSource)
|
|
30602
31020
|
);
|
|
@@ -30706,7 +31124,14 @@ async function handleSocketLine(socket, line) {
|
|
|
30706
31124
|
try {
|
|
30707
31125
|
const selector = String(data?.browser ?? data?.browserId ?? data?.name ?? "").trim();
|
|
30708
31126
|
if (!selector) throw new Error("browser is required");
|
|
30709
|
-
const
|
|
31127
|
+
const localExists = hasManagedBrowser(selector);
|
|
31128
|
+
const agentBayExists = hasAgentBayBrowser(selector);
|
|
31129
|
+
if (localExists && agentBayExists) {
|
|
31130
|
+
throw new Error(
|
|
31131
|
+
`Managed browser name is ambiguous: ${selector}. Use the full browserId from browser_list.`
|
|
31132
|
+
);
|
|
31133
|
+
}
|
|
31134
|
+
const result = agentBayExists ? await closeAgentBayBrowser(selector, { deleteProfile: data?.deleteProfile }) : await closeManagedBrowser(selector, { deleteProfile: data?.deleteProfile });
|
|
30710
31135
|
socket.write(JSON.stringify({ id, success: true, data: result }) + "\n");
|
|
30711
31136
|
} catch (error48) {
|
|
30712
31137
|
socket.write(
|
|
@@ -30798,7 +31223,6 @@ async function handleSocketLine(socket, line) {
|
|
|
30798
31223
|
}
|
|
30799
31224
|
if (action === "browser_launch") {
|
|
30800
31225
|
try {
|
|
30801
|
-
const prepareTdbankSso = extensionVersion !== null ? (payload) => sendRequestToExtension("__tdbank_prepare_sso", payload, 2e4, true) : (payload) => cdpPrepareTdbankSso(getCdpSession(), payload);
|
|
30802
31226
|
const exportCookies = extensionVersion !== null ? async (domains) => {
|
|
30803
31227
|
const result2 = await sendRequestToExtension(
|
|
30804
31228
|
"__export_cookies",
|
|
@@ -30808,8 +31232,34 @@ async function handleSocketLine(socket, line) {
|
|
|
30808
31232
|
);
|
|
30809
31233
|
return result2.cookies ?? [];
|
|
30810
31234
|
} : (domains) => cdpExportCookies(getCdpSession(), domains);
|
|
31235
|
+
if (data?.provider === "agentbay") {
|
|
31236
|
+
const name2 = typeof data?.name === "string" ? data.name.trim() : "";
|
|
31237
|
+
if (name2 && hasManagedBrowser(name2)) {
|
|
31238
|
+
throw new Error(
|
|
31239
|
+
`Managed browser name is already used by the local provider: ${name2}. Choose a unique name.`
|
|
31240
|
+
);
|
|
31241
|
+
}
|
|
31242
|
+
const result2 = await launchAgentBayBrowser(data, {
|
|
31243
|
+
nativeHostScript: fileURLToPath4(import.meta.url),
|
|
31244
|
+
exportCookies,
|
|
31245
|
+
getBrowserUserAgent: getCurrentBrowserUserAgent,
|
|
31246
|
+
log
|
|
31247
|
+
});
|
|
31248
|
+
socket.write(JSON.stringify({ id, success: true, data: result2 }) + "\n");
|
|
31249
|
+
return;
|
|
31250
|
+
}
|
|
31251
|
+
if (data?.provider !== void 0 && data.provider !== "local") {
|
|
31252
|
+
throw new Error('provider must be "local" or "agentbay"');
|
|
31253
|
+
}
|
|
31254
|
+
const name = typeof data?.name === "string" ? data.name.trim() : "";
|
|
31255
|
+
if (name && hasAgentBayBrowser(name)) {
|
|
31256
|
+
throw new Error(
|
|
31257
|
+
`Managed browser name is already used by the AgentBay provider: ${name}. Choose a unique name.`
|
|
31258
|
+
);
|
|
31259
|
+
}
|
|
31260
|
+
const prepareTdbankSso = extensionVersion !== null ? (payload) => sendRequestToExtension("__tdbank_prepare_sso", payload, 2e4, true) : (payload) => cdpPrepareTdbankSso(getCdpSession(), payload);
|
|
30811
31261
|
const result = await launchManagedBrowser(data, {
|
|
30812
|
-
nativeHostScript:
|
|
31262
|
+
nativeHostScript: fileURLToPath4(import.meta.url),
|
|
30813
31263
|
prepareTdbankSso,
|
|
30814
31264
|
exportCookies,
|
|
30815
31265
|
log
|
|
@@ -30901,8 +31351,21 @@ async function handleViaCdp(action, data, _timeoutMs, controlSource) {
|
|
|
30901
31351
|
`${action} requires the Mearl browser extension. Install it from https://chromewebstore.google.com/detail/mearl/aoehhjnofngknnjefamjbplchbolghkm`
|
|
30902
31352
|
);
|
|
30903
31353
|
}
|
|
30904
|
-
|
|
31354
|
+
if (AGENTBAY_SESSION_ID && action === "page_upload") {
|
|
31355
|
+
throw new Error(
|
|
31356
|
+
"page_upload is not available for AgentBay CDP sessions because file paths resolve on the remote browser host."
|
|
31357
|
+
);
|
|
31358
|
+
}
|
|
31359
|
+
const available = AGENTBAY_SESSION_ID ? await getCdpSession().getBrowserClient().then(
|
|
31360
|
+
() => true,
|
|
31361
|
+
() => false
|
|
31362
|
+
) : await isCdpAvailable(CDP_PORT, CDP_USER_DATA_DIR);
|
|
30905
31363
|
if (!available) {
|
|
31364
|
+
if (AGENTBAY_SESSION_ID) {
|
|
31365
|
+
throw new Error(
|
|
31366
|
+
`AgentBay CDP endpoint is not available for session ${AGENTBAY_SESSION_ID}. Check the session status and AgentBay plan permissions.`
|
|
31367
|
+
);
|
|
31368
|
+
}
|
|
30906
31369
|
throw new Error(
|
|
30907
31370
|
`Chrome DevTools remote debugging is not available on port ${CDP_PORT}. Enable it via chrome://inspect/#remote-debugging (Chrome 145+) or install the Mearl extension.`
|
|
30908
31371
|
);
|
|
@@ -30937,16 +31400,16 @@ function onSocketConnection(socket) {
|
|
|
30937
31400
|
});
|
|
30938
31401
|
}
|
|
30939
31402
|
function isPathAlive(socketPath) {
|
|
30940
|
-
return new Promise((
|
|
31403
|
+
return new Promise((resolve2) => {
|
|
30941
31404
|
if (process.platform !== "win32" && !fs13.existsSync(socketPath)) {
|
|
30942
|
-
|
|
31405
|
+
resolve2(false);
|
|
30943
31406
|
return;
|
|
30944
31407
|
}
|
|
30945
31408
|
const client2 = net.createConnection(socketPath);
|
|
30946
31409
|
const done = (alive) => {
|
|
30947
31410
|
client2.removeAllListeners();
|
|
30948
31411
|
client2.destroy();
|
|
30949
|
-
|
|
31412
|
+
resolve2(alive);
|
|
30950
31413
|
};
|
|
30951
31414
|
const timer = setTimeout(() => done(false), 500);
|
|
30952
31415
|
client2.on("connect", () => {
|
|
@@ -30960,7 +31423,7 @@ function isPathAlive(socketPath) {
|
|
|
30960
31423
|
});
|
|
30961
31424
|
}
|
|
30962
31425
|
function listenOn(socketPath) {
|
|
30963
|
-
return new Promise((
|
|
31426
|
+
return new Promise((resolve2, reject) => {
|
|
30964
31427
|
if (process.platform !== "win32" && fs13.existsSync(socketPath)) {
|
|
30965
31428
|
try {
|
|
30966
31429
|
fs13.unlinkSync(socketPath);
|
|
@@ -30986,7 +31449,7 @@ function listenOn(socketPath) {
|
|
|
30986
31449
|
server.removeListener("error", reject);
|
|
30987
31450
|
server.on("error", (error48) => log("socket server error:", String(error48)));
|
|
30988
31451
|
log(`listening on ${socketPath}`);
|
|
30989
|
-
|
|
31452
|
+
resolve2(server);
|
|
30990
31453
|
});
|
|
30991
31454
|
});
|
|
30992
31455
|
}
|
|
@@ -31087,6 +31550,17 @@ async function main() {
|
|
|
31087
31550
|
lastFocusedAt: CDP_BROWSER_ID.startsWith("managed:") ? 0 : void 0
|
|
31088
31551
|
});
|
|
31089
31552
|
}
|
|
31553
|
+
if (AGENTBAY_SESSION_ID) {
|
|
31554
|
+
const keepAliveTimer = setInterval(() => {
|
|
31555
|
+
keepAgentBaySessionAlive(AGENTBAY_SESSION_ID).catch((error48) => {
|
|
31556
|
+
log(
|
|
31557
|
+
`AgentBay keepalive failed for ${AGENTBAY_SESSION_ID}:`,
|
|
31558
|
+
error48 instanceof Error ? error48.message : String(error48)
|
|
31559
|
+
);
|
|
31560
|
+
});
|
|
31561
|
+
}, 6e4);
|
|
31562
|
+
keepAliveTimer.unref();
|
|
31563
|
+
}
|
|
31090
31564
|
process.on("SIGINT", () => cleanupAndExit(0));
|
|
31091
31565
|
process.on("SIGTERM", () => cleanupAndExit(0));
|
|
31092
31566
|
process.on("uncaughtException", (error48) => {
|