ornold-mcp 1.0.1 → 1.0.3
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/cli.js +926 -159
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -463,6 +463,8 @@ __export(multi_browser_exports, {
|
|
|
463
463
|
MultiBrowserExecutor: () => MultiBrowserExecutor
|
|
464
464
|
});
|
|
465
465
|
import * as playwright from "patchright";
|
|
466
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
467
|
+
import { join as join2, extname } from "node:path";
|
|
466
468
|
var MultiBrowserExecutor;
|
|
467
469
|
var init_multi_browser = __esm({
|
|
468
470
|
"src/executor/multi-browser.ts"() {
|
|
@@ -484,6 +486,8 @@ var init_multi_browser = __esm({
|
|
|
484
486
|
lastMousePosition = /* @__PURE__ */ new Map();
|
|
485
487
|
// Per-browser human profiles for varied timing
|
|
486
488
|
profiles = /* @__PURE__ */ new Map();
|
|
489
|
+
// Snapshot refs map back to selectors for flow-agent style browser tools
|
|
490
|
+
snapshotRefs = /* @__PURE__ */ new Map();
|
|
487
491
|
// Console messages collected per browser (since connect time)
|
|
488
492
|
consoleMessages = /* @__PURE__ */ new Map();
|
|
489
493
|
// Network requests collected per browser (since connect time)
|
|
@@ -644,6 +648,7 @@ var init_multi_browser = __esm({
|
|
|
644
648
|
};
|
|
645
649
|
this.browsers.set(endpoint.id, connected);
|
|
646
650
|
console.error(`[Executor] Successfully stored ${endpoint.id} in browsers map. Total browsers: ${this.browsers.size}`);
|
|
651
|
+
this.snapshotRefs.set(endpoint.id, /* @__PURE__ */ new Map());
|
|
647
652
|
const consoleLog = [];
|
|
648
653
|
this.consoleMessages.set(endpoint.id, consoleLog);
|
|
649
654
|
page.on("console", (msg) => {
|
|
@@ -668,6 +673,7 @@ var init_multi_browser = __esm({
|
|
|
668
673
|
this.browsers.delete(endpoint.id);
|
|
669
674
|
this.consoleMessages.delete(endpoint.id);
|
|
670
675
|
this.networkRequests.delete(endpoint.id);
|
|
676
|
+
this.snapshotRefs.delete(endpoint.id);
|
|
671
677
|
setTimeout(async () => {
|
|
672
678
|
if (!this.browsers.has(endpoint.id)) {
|
|
673
679
|
console.error(`[Executor] Attempting auto-reconnect for ${endpoint.id}...`);
|
|
@@ -701,6 +707,7 @@ var init_multi_browser = __esm({
|
|
|
701
707
|
this.browsers.delete(browserId);
|
|
702
708
|
this.consoleMessages.delete(browserId);
|
|
703
709
|
this.networkRequests.delete(browserId);
|
|
710
|
+
this.snapshotRefs.delete(browserId);
|
|
704
711
|
}
|
|
705
712
|
async disconnectAll() {
|
|
706
713
|
const ids = Array.from(this.browsers.keys());
|
|
@@ -940,6 +947,60 @@ var init_multi_browser = __esm({
|
|
|
940
947
|
if (!browser) throw new Error(`Browser ${browserId} not found`);
|
|
941
948
|
return browser.page;
|
|
942
949
|
}
|
|
950
|
+
resolveSelector(target, browserId) {
|
|
951
|
+
if (typeof target === "string") return target;
|
|
952
|
+
if (target.selector) return target.selector;
|
|
953
|
+
if (target.ref) {
|
|
954
|
+
const selector = this.snapshotRefs.get(browserId)?.get(String(target.ref));
|
|
955
|
+
if (selector) return selector;
|
|
956
|
+
throw new Error(`Unknown ref "${target.ref}" for browser ${browserId}. Call browser_parallel_snapshot first.`);
|
|
957
|
+
}
|
|
958
|
+
throw new Error("Either selector or ref is required");
|
|
959
|
+
}
|
|
960
|
+
isTruthyFieldValue(value) {
|
|
961
|
+
return ["true", "1", "yes", "on", "checked"].includes(value.trim().toLowerCase());
|
|
962
|
+
}
|
|
963
|
+
async waitForDomStable(page, stableMs, timeoutMs) {
|
|
964
|
+
const startedAt = Date.now();
|
|
965
|
+
let lastSignature = "";
|
|
966
|
+
let stableSince = 0;
|
|
967
|
+
const pollInterval = Math.min(250, Math.max(75, Math.floor(stableMs / 3) || 100));
|
|
968
|
+
while (Date.now() - startedAt <= timeoutMs) {
|
|
969
|
+
const signature = await page.evaluate(() => JSON.stringify({
|
|
970
|
+
readyState: document.readyState,
|
|
971
|
+
nodeCount: document.querySelectorAll("*").length,
|
|
972
|
+
textLength: document.body?.innerText.length ?? 0,
|
|
973
|
+
scrollHeight: document.documentElement?.scrollHeight ?? 0,
|
|
974
|
+
scrollWidth: document.documentElement?.scrollWidth ?? 0
|
|
975
|
+
}));
|
|
976
|
+
if (signature === lastSignature) {
|
|
977
|
+
if (!stableSince) stableSince = Date.now();
|
|
978
|
+
if (Date.now() - stableSince >= stableMs) return;
|
|
979
|
+
} else {
|
|
980
|
+
lastSignature = signature;
|
|
981
|
+
stableSince = 0;
|
|
982
|
+
}
|
|
983
|
+
await page.waitForTimeout(pollInterval);
|
|
984
|
+
}
|
|
985
|
+
throw new Error(`DOM did not become stable within ${timeoutMs}ms`);
|
|
986
|
+
}
|
|
987
|
+
getMimeType(fileName) {
|
|
988
|
+
const ext = extname(fileName).toLowerCase();
|
|
989
|
+
const types = {
|
|
990
|
+
".txt": "text/plain",
|
|
991
|
+
".json": "application/json",
|
|
992
|
+
".csv": "text/csv",
|
|
993
|
+
".pdf": "application/pdf",
|
|
994
|
+
".png": "image/png",
|
|
995
|
+
".jpg": "image/jpeg",
|
|
996
|
+
".jpeg": "image/jpeg",
|
|
997
|
+
".gif": "image/gif",
|
|
998
|
+
".webp": "image/webp",
|
|
999
|
+
".svg": "image/svg+xml",
|
|
1000
|
+
".zip": "application/zip"
|
|
1001
|
+
};
|
|
1002
|
+
return types[ext] || "application/octet-stream";
|
|
1003
|
+
}
|
|
943
1004
|
// ==================== PARALLEL EXECUTION ====================
|
|
944
1005
|
/**
|
|
945
1006
|
* Get the appropriate limiter based on operation type
|
|
@@ -1249,11 +1310,20 @@ var init_multi_browser = __esm({
|
|
|
1249
1310
|
}
|
|
1250
1311
|
return results;
|
|
1251
1312
|
}, !!options.compact);
|
|
1252
|
-
|
|
1313
|
+
const refMap = /* @__PURE__ */ new Map();
|
|
1314
|
+
let nextRef = 1;
|
|
1315
|
+
const elementsWithRefs = elements.map((element) => {
|
|
1316
|
+
if (!element.selector) return element;
|
|
1317
|
+
const ref = String(nextRef++);
|
|
1318
|
+
refMap.set(ref, element.selector);
|
|
1319
|
+
return { ...element, ref };
|
|
1320
|
+
});
|
|
1321
|
+
this.snapshotRefs.set(browserId, refMap);
|
|
1322
|
+
let snapshot = this.formatSnapshot(elementsWithRefs, !!options.compact);
|
|
1253
1323
|
if (snapshot.length > MAX_SNAPSHOT_SIZE) {
|
|
1254
1324
|
snapshot = snapshot.substring(0, MAX_SNAPSHOT_SIZE) + `
|
|
1255
1325
|
|
|
1256
|
-
... [TRUNCATED: ${
|
|
1326
|
+
... [TRUNCATED: ${elementsWithRefs.length} elements total, showing first ${MAX_SNAPSHOT_SIZE} chars]`;
|
|
1257
1327
|
}
|
|
1258
1328
|
return {
|
|
1259
1329
|
browserId,
|
|
@@ -1285,6 +1355,7 @@ var init_multi_browser = __esm({
|
|
|
1285
1355
|
let line = `- ${el.tag}`;
|
|
1286
1356
|
if (el.type) line += `[type=${el.type}]`;
|
|
1287
1357
|
if (el.disabled) line += " (disabled)";
|
|
1358
|
+
if (el.ref) line += ` [ref=${el.ref}]`;
|
|
1288
1359
|
line += ` \u2192 ${el.selector}`;
|
|
1289
1360
|
const details = [];
|
|
1290
1361
|
if (el.placeholder) details.push(`placeholder="${el.placeholder}"`);
|
|
@@ -1341,30 +1412,32 @@ var init_multi_browser = __esm({
|
|
|
1341
1412
|
this.lastMousePosition.set(browserId, pos);
|
|
1342
1413
|
}
|
|
1343
1414
|
// ==================== REF-BASED INTERACTION (human-like) ====================
|
|
1344
|
-
async parallelClick(
|
|
1415
|
+
async parallelClick(target, browserIds) {
|
|
1345
1416
|
return this.executeParallel(browserIds, async (page, browserId) => {
|
|
1346
1417
|
const profile = this.getProfile(browserId);
|
|
1418
|
+
const selector = this.resolveSelector(target, browserId);
|
|
1347
1419
|
const locator = page.locator(selector);
|
|
1348
1420
|
await locator.waitFor({ state: "visible", timeout: 5e3 });
|
|
1349
1421
|
await ensureCursor(page);
|
|
1350
1422
|
await preActionDelay(profile);
|
|
1351
|
-
const { target } = await getClickTarget(page, locator);
|
|
1423
|
+
const { target: clickTarget } = await getClickTarget(page, locator);
|
|
1352
1424
|
const fromPos = this.getMousePos(browserId);
|
|
1353
|
-
await humanClick(page,
|
|
1354
|
-
this.setMousePos(browserId,
|
|
1425
|
+
await humanClick(page, clickTarget, fromPos, profile);
|
|
1426
|
+
this.setMousePos(browserId, clickTarget);
|
|
1355
1427
|
});
|
|
1356
1428
|
}
|
|
1357
|
-
async parallelFill(
|
|
1429
|
+
async parallelFill(target, text, browserIds) {
|
|
1358
1430
|
return this.executeParallel(browserIds, async (page, browserId) => {
|
|
1359
1431
|
const profile = this.getProfile(browserId);
|
|
1432
|
+
const selector = this.resolveSelector(target, browserId);
|
|
1360
1433
|
const locator = page.locator(selector);
|
|
1361
1434
|
await locator.waitFor({ state: "visible", timeout: 5e3 });
|
|
1362
1435
|
await ensureCursor(page);
|
|
1363
1436
|
await preActionDelay(profile);
|
|
1364
|
-
const { target } = await getClickTarget(page, locator);
|
|
1437
|
+
const { target: clickTarget } = await getClickTarget(page, locator);
|
|
1365
1438
|
const fromPos = this.getMousePos(browserId);
|
|
1366
|
-
await humanClick(page,
|
|
1367
|
-
this.setMousePos(browserId,
|
|
1439
|
+
await humanClick(page, clickTarget, fromPos, profile);
|
|
1440
|
+
this.setMousePos(browserId, clickTarget);
|
|
1368
1441
|
await humanDelay(80, 200);
|
|
1369
1442
|
await page.keyboard.press("Meta+a");
|
|
1370
1443
|
await humanDelay(30, 80);
|
|
@@ -1374,20 +1447,21 @@ var init_multi_browser = __esm({
|
|
|
1374
1447
|
return `filled "${text}"`;
|
|
1375
1448
|
});
|
|
1376
1449
|
}
|
|
1377
|
-
async parallelFillMulti(
|
|
1450
|
+
async parallelFillMulti(target, texts) {
|
|
1378
1451
|
const browserIds = Object.keys(texts);
|
|
1379
1452
|
return this.executeParallel(browserIds, async (page, browserId) => {
|
|
1380
1453
|
const text = texts[browserId];
|
|
1381
1454
|
if (!text) throw new Error(`No text provided for browser ${browserId}`);
|
|
1382
1455
|
const profile = this.getProfile(browserId);
|
|
1456
|
+
const selector = this.resolveSelector(target, browserId);
|
|
1383
1457
|
const locator = page.locator(selector);
|
|
1384
1458
|
await locator.waitFor({ state: "visible", timeout: 5e3 });
|
|
1385
1459
|
await ensureCursor(page);
|
|
1386
1460
|
await preActionDelay(profile);
|
|
1387
|
-
const { target } = await getClickTarget(page, locator);
|
|
1461
|
+
const { target: clickTarget } = await getClickTarget(page, locator);
|
|
1388
1462
|
const fromPos = this.getMousePos(browserId);
|
|
1389
|
-
await humanClick(page,
|
|
1390
|
-
this.setMousePos(browserId,
|
|
1463
|
+
await humanClick(page, clickTarget, fromPos, profile);
|
|
1464
|
+
this.setMousePos(browserId, clickTarget);
|
|
1391
1465
|
await humanDelay(80, 200);
|
|
1392
1466
|
await page.keyboard.press("Meta+a");
|
|
1393
1467
|
await humanDelay(30, 80);
|
|
@@ -1396,44 +1470,47 @@ var init_multi_browser = __esm({
|
|
|
1396
1470
|
await humanTypeText(page, text, profile);
|
|
1397
1471
|
});
|
|
1398
1472
|
}
|
|
1399
|
-
async parallelType(
|
|
1473
|
+
async parallelType(target, text, browserIds) {
|
|
1400
1474
|
return this.executeParallel(browserIds, async (page, browserId) => {
|
|
1401
1475
|
const profile = this.getProfile(browserId);
|
|
1476
|
+
const selector = this.resolveSelector(target, browserId);
|
|
1402
1477
|
const locator = page.locator(selector);
|
|
1403
1478
|
await locator.waitFor({ state: "visible", timeout: 5e3 });
|
|
1404
1479
|
await ensureCursor(page);
|
|
1405
|
-
const { target } = await getClickTarget(page, locator);
|
|
1480
|
+
const { target: clickTarget } = await getClickTarget(page, locator);
|
|
1406
1481
|
const fromPos = this.getMousePos(browserId);
|
|
1407
|
-
await humanClick(page,
|
|
1408
|
-
this.setMousePos(browserId,
|
|
1482
|
+
await humanClick(page, clickTarget, fromPos, profile);
|
|
1483
|
+
this.setMousePos(browserId, clickTarget);
|
|
1409
1484
|
await humanDelay(50, 150);
|
|
1410
1485
|
await humanTypeText(page, text, profile);
|
|
1411
1486
|
});
|
|
1412
1487
|
}
|
|
1413
|
-
async parallelHover(
|
|
1488
|
+
async parallelHover(target, browserIds) {
|
|
1414
1489
|
return this.executeParallel(browserIds, async (page, browserId) => {
|
|
1415
1490
|
const profile = this.getProfile(browserId);
|
|
1491
|
+
const selector = this.resolveSelector(target, browserId);
|
|
1416
1492
|
const locator = page.locator(selector);
|
|
1417
1493
|
await locator.waitFor({ state: "visible", timeout: 5e3 });
|
|
1418
1494
|
await ensureCursor(page);
|
|
1419
1495
|
await preActionDelay(profile);
|
|
1420
|
-
const { target } = await getClickTarget(page, locator);
|
|
1496
|
+
const { target: hoverTarget } = await getClickTarget(page, locator);
|
|
1421
1497
|
const fromPos = this.getMousePos(browserId);
|
|
1422
|
-
await humanMouseMove(page, fromPos,
|
|
1423
|
-
this.setMousePos(browserId,
|
|
1498
|
+
await humanMouseMove(page, fromPos, hoverTarget, profile);
|
|
1499
|
+
this.setMousePos(browserId, hoverTarget);
|
|
1424
1500
|
});
|
|
1425
1501
|
}
|
|
1426
|
-
async parallelSelectOption(
|
|
1502
|
+
async parallelSelectOption(target, values, browserIds) {
|
|
1427
1503
|
return this.executeParallel(browserIds, async (page, browserId) => {
|
|
1428
1504
|
const profile = this.getProfile(browserId);
|
|
1505
|
+
const selector = this.resolveSelector(target, browserId);
|
|
1429
1506
|
const locator = page.locator(selector);
|
|
1430
1507
|
await locator.waitFor({ state: "visible", timeout: 5e3 });
|
|
1431
1508
|
await ensureCursor(page);
|
|
1432
1509
|
await preActionDelay(profile);
|
|
1433
|
-
const { target } = await getClickTarget(page, locator);
|
|
1510
|
+
const { target: clickTarget } = await getClickTarget(page, locator);
|
|
1434
1511
|
const fromPos = this.getMousePos(browserId);
|
|
1435
|
-
await humanClick(page,
|
|
1436
|
-
this.setMousePos(browserId,
|
|
1512
|
+
await humanClick(page, clickTarget, fromPos, profile);
|
|
1513
|
+
this.setMousePos(browserId, clickTarget);
|
|
1437
1514
|
await humanDelay(200, 500);
|
|
1438
1515
|
return await locator.selectOption(values);
|
|
1439
1516
|
});
|
|
@@ -1571,8 +1648,9 @@ var init_multi_browser = __esm({
|
|
|
1571
1648
|
// ==================== WAITING ====================
|
|
1572
1649
|
async parallelWaitFor(options, browserIds) {
|
|
1573
1650
|
const waitTimeMs = options.time ? options.time * 1e3 : 0;
|
|
1574
|
-
const textTimeout = 3e4;
|
|
1575
|
-
const
|
|
1651
|
+
const textTimeout = options.timeoutMs ?? 3e4;
|
|
1652
|
+
const domStableTimeout = options.timeoutMs ?? Math.max(options.domStableMs ?? 0, 5e3);
|
|
1653
|
+
const timeout = waitTimeMs + Math.max(textTimeout, domStableTimeout) + 5e3;
|
|
1576
1654
|
return this.executeParallel(browserIds, async (page) => {
|
|
1577
1655
|
if (options.time) {
|
|
1578
1656
|
await page.waitForTimeout(options.time * 1e3);
|
|
@@ -1583,6 +1661,9 @@ var init_multi_browser = __esm({
|
|
|
1583
1661
|
if (options.textGone) {
|
|
1584
1662
|
await page.getByText(options.textGone).waitFor({ state: "hidden", timeout: textTimeout });
|
|
1585
1663
|
}
|
|
1664
|
+
if (options.domStableMs) {
|
|
1665
|
+
await this.waitForDomStable(page, options.domStableMs, domStableTimeout);
|
|
1666
|
+
}
|
|
1586
1667
|
}, { timeout });
|
|
1587
1668
|
}
|
|
1588
1669
|
// ==================== FILE OPERATIONS (downloads, uploads, drag&drop) ====================
|
|
@@ -1636,62 +1717,39 @@ var init_multi_browser = __esm({
|
|
|
1636
1717
|
async listProjectFiles() {
|
|
1637
1718
|
const dir = await this.getProjectFilesDir();
|
|
1638
1719
|
if (!dir) return [];
|
|
1639
|
-
const ids = this.getBrowserIds();
|
|
1640
|
-
if (ids.length === 0) return [];
|
|
1641
|
-
const browser = this.browsers.get(ids[0]);
|
|
1642
|
-
if (!browser) return [];
|
|
1643
1720
|
try {
|
|
1644
|
-
const
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
const dir = ${JSON.stringify(dir)};
|
|
1653
|
-
if (!fs.existsSync(dir)) return JSON.stringify([]);
|
|
1654
|
-
const files = fs.readdirSync(dir).filter(f => !f.startsWith('.'));
|
|
1655
|
-
return JSON.stringify(files.map(f => {
|
|
1656
|
-
const stat = fs.statSync(path.join(dir, f));
|
|
1657
|
-
return { name: f, size: stat.size, modified: stat.mtimeMs };
|
|
1658
|
-
}));
|
|
1659
|
-
} catch(e) { return JSON.stringify({ error: e.message }); }
|
|
1660
|
-
})()
|
|
1661
|
-
`,
|
|
1662
|
-
returnByValue: true
|
|
1663
|
-
});
|
|
1664
|
-
const value = result.result?.value;
|
|
1665
|
-
if (typeof value === "string") {
|
|
1666
|
-
return JSON.parse(value);
|
|
1667
|
-
}
|
|
1668
|
-
} finally {
|
|
1669
|
-
await cdp.detach().catch(() => {
|
|
1670
|
-
});
|
|
1671
|
-
}
|
|
1721
|
+
const files = await readdir(dir);
|
|
1722
|
+
const items = await Promise.all(
|
|
1723
|
+
files.filter((file) => !file.startsWith(".")).map(async (file) => {
|
|
1724
|
+
const fileStat = await stat(join2(dir, file));
|
|
1725
|
+
return { name: file, size: fileStat.size, modified: fileStat.mtimeMs };
|
|
1726
|
+
})
|
|
1727
|
+
);
|
|
1728
|
+
return items;
|
|
1672
1729
|
} catch {
|
|
1673
1730
|
}
|
|
1674
1731
|
return [];
|
|
1675
1732
|
}
|
|
1676
1733
|
/** Upload a file from project directory via filechooser (selector-based) */
|
|
1677
|
-
async parallelUploadFile(
|
|
1734
|
+
async parallelUploadFile(target, fileName, browserIds) {
|
|
1678
1735
|
const dir = await this.getProjectFilesDir();
|
|
1679
1736
|
if (!dir) {
|
|
1680
1737
|
throw new Error("Project files directory not available");
|
|
1681
1738
|
}
|
|
1682
1739
|
return this.executeParallel(browserIds, async (page, browserId) => {
|
|
1683
1740
|
const profile = this.getProfile(browserId);
|
|
1741
|
+
const selector = this.resolveSelector(target, browserId);
|
|
1684
1742
|
const locator = page.locator(selector);
|
|
1685
1743
|
await locator.waitFor({ state: "visible", timeout: 5e3 });
|
|
1686
1744
|
await ensureCursor(page);
|
|
1687
1745
|
await preActionDelay(profile);
|
|
1688
1746
|
const fileChooserPromise = page.waitForEvent("filechooser", { timeout: 1e4 });
|
|
1689
|
-
const { target } = await getClickTarget(page, locator);
|
|
1747
|
+
const { target: clickTarget } = await getClickTarget(page, locator);
|
|
1690
1748
|
const fromPos = this.getMousePos(browserId);
|
|
1691
|
-
await humanClick(page,
|
|
1692
|
-
this.setMousePos(browserId,
|
|
1749
|
+
await humanClick(page, clickTarget, fromPos, profile);
|
|
1750
|
+
this.setMousePos(browserId, clickTarget);
|
|
1693
1751
|
const fileChooser = await fileChooserPromise;
|
|
1694
|
-
const filePath =
|
|
1752
|
+
const filePath = join2(dir, fileName);
|
|
1695
1753
|
await fileChooser.setFiles(filePath);
|
|
1696
1754
|
return `Uploaded "${fileName}" from ${dir}`;
|
|
1697
1755
|
}, { timeout: 15e3 });
|
|
@@ -1702,29 +1760,56 @@ var init_multi_browser = __esm({
|
|
|
1702
1760
|
const profile = this.getProfile(browserId);
|
|
1703
1761
|
const filled = [];
|
|
1704
1762
|
for (const field of fields) {
|
|
1705
|
-
const
|
|
1763
|
+
const selector = this.resolveSelector(field, browserId);
|
|
1764
|
+
const locator = page.locator(selector);
|
|
1706
1765
|
await locator.waitFor({ state: "visible", timeout: 5e3 });
|
|
1707
1766
|
await ensureCursor(page);
|
|
1708
1767
|
await preActionDelay(profile);
|
|
1709
|
-
|
|
1768
|
+
if (field.type === "checkbox") {
|
|
1769
|
+
if (this.isTruthyFieldValue(field.value)) {
|
|
1770
|
+
await locator.check();
|
|
1771
|
+
} else {
|
|
1772
|
+
await locator.uncheck();
|
|
1773
|
+
}
|
|
1774
|
+
filled.push(`${selector}=${field.value}`);
|
|
1775
|
+
continue;
|
|
1776
|
+
}
|
|
1777
|
+
if (field.type === "radio") {
|
|
1778
|
+
await locator.check();
|
|
1779
|
+
filled.push(`${selector}=${field.value}`);
|
|
1780
|
+
continue;
|
|
1781
|
+
}
|
|
1782
|
+
if (field.type === "combobox") {
|
|
1783
|
+
const { target: clickTarget2 } = await getClickTarget(page, locator);
|
|
1784
|
+
const fromPos2 = this.getMousePos(browserId);
|
|
1785
|
+
await humanClick(page, clickTarget2, fromPos2, profile);
|
|
1786
|
+
this.setMousePos(browserId, clickTarget2);
|
|
1787
|
+
await humanDelay(120, 240);
|
|
1788
|
+
await locator.selectOption(field.value);
|
|
1789
|
+
filled.push(`${selector}="${field.value}"`);
|
|
1790
|
+
continue;
|
|
1791
|
+
}
|
|
1792
|
+
const { target: clickTarget } = await getClickTarget(page, locator);
|
|
1710
1793
|
const fromPos = this.getMousePos(browserId);
|
|
1711
|
-
await humanClick(page,
|
|
1712
|
-
this.setMousePos(browserId,
|
|
1794
|
+
await humanClick(page, clickTarget, fromPos, profile);
|
|
1795
|
+
this.setMousePos(browserId, clickTarget);
|
|
1713
1796
|
await humanDelay(80, 200);
|
|
1714
1797
|
await page.keyboard.press("Meta+a");
|
|
1715
1798
|
await humanDelay(30, 80);
|
|
1716
1799
|
await page.keyboard.press("Backspace");
|
|
1717
1800
|
await humanDelay(50, 150);
|
|
1718
1801
|
await humanTypeText(page, field.value, profile);
|
|
1719
|
-
filled.push(`${
|
|
1802
|
+
filled.push(`${selector}="${field.value}"`);
|
|
1720
1803
|
}
|
|
1721
1804
|
return `Filled ${filled.length} fields: ${filled.join(", ")}`;
|
|
1722
1805
|
}, { timeout: fields.length * 5e3 + 5e3 });
|
|
1723
1806
|
}
|
|
1724
1807
|
// ==================== ELEMENT DRAG & DROP ====================
|
|
1725
|
-
async parallelDrag(
|
|
1808
|
+
async parallelDrag(startTarget, endTarget, browserIds) {
|
|
1726
1809
|
return this.executeParallel(browserIds, async (page, browserId) => {
|
|
1727
1810
|
const profile = this.getProfile(browserId);
|
|
1811
|
+
const startSelector = this.resolveSelector(startTarget, browserId);
|
|
1812
|
+
const endSelector = this.resolveSelector(endTarget, browserId);
|
|
1728
1813
|
const startLocator = page.locator(startSelector);
|
|
1729
1814
|
const endLocator = page.locator(endSelector);
|
|
1730
1815
|
await startLocator.waitFor({ state: "visible", timeout: 5e3 });
|
|
@@ -1890,35 +1975,37 @@ var init_multi_browser = __esm({
|
|
|
1890
1975
|
};
|
|
1891
1976
|
}
|
|
1892
1977
|
/** Drag and drop a file onto a dropzone (selector-based) */
|
|
1893
|
-
async parallelDragDropFile(
|
|
1978
|
+
async parallelDragDropFile(target, fileName, browserIds) {
|
|
1894
1979
|
const dir = await this.getProjectFilesDir();
|
|
1895
1980
|
if (!dir) {
|
|
1896
1981
|
throw new Error("Project files directory not available");
|
|
1897
1982
|
}
|
|
1898
1983
|
return this.executeParallel(browserIds, async (page, browserId) => {
|
|
1899
1984
|
const profile = this.getProfile(browserId);
|
|
1985
|
+
const selector = this.resolveSelector(target, browserId);
|
|
1900
1986
|
const locator = page.locator(selector);
|
|
1901
1987
|
await locator.waitFor({ state: "visible", timeout: 5e3 });
|
|
1902
1988
|
await ensureCursor(page);
|
|
1903
1989
|
await preActionDelay(profile);
|
|
1904
|
-
const { target } = await getClickTarget(page, locator);
|
|
1990
|
+
const { target: dropTarget } = await getClickTarget(page, locator);
|
|
1905
1991
|
const fromPos = this.getMousePos(browserId);
|
|
1906
|
-
await humanMouseMove(page, fromPos,
|
|
1907
|
-
this.setMousePos(browserId,
|
|
1908
|
-
const filePath =
|
|
1909
|
-
|
|
1992
|
+
await humanMouseMove(page, fromPos, dropTarget, profile);
|
|
1993
|
+
this.setMousePos(browserId, dropTarget);
|
|
1994
|
+
const filePath = join2(dir, fileName);
|
|
1995
|
+
const fileBytes = Array.from(await readFile(filePath));
|
|
1996
|
+
const mimeType = this.getMimeType(fileName);
|
|
1997
|
+
await page.evaluate(async ({
|
|
1998
|
+
x,
|
|
1999
|
+
y,
|
|
2000
|
+
fileName: fileName2,
|
|
2001
|
+
mimeType: mimeType2,
|
|
2002
|
+
fileBytes: fileBytes2
|
|
2003
|
+
}) => {
|
|
1910
2004
|
const dropzone = document.elementFromPoint(x, y);
|
|
1911
2005
|
if (!dropzone) throw new Error("No element at drop coordinates");
|
|
1912
2006
|
const dataTransfer = new DataTransfer();
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
const blob = await resp.blob();
|
|
1916
|
-
const file = new File([blob], fileName2, { type: blob.type });
|
|
1917
|
-
dataTransfer.items.add(file);
|
|
1918
|
-
} catch {
|
|
1919
|
-
const file = new File([""], fileName2);
|
|
1920
|
-
dataTransfer.items.add(file);
|
|
1921
|
-
}
|
|
2007
|
+
const file = new File([new Uint8Array(fileBytes2)], fileName2, { type: mimeType2 });
|
|
2008
|
+
dataTransfer.items.add(file);
|
|
1922
2009
|
const events = ["dragenter", "dragover", "drop"];
|
|
1923
2010
|
for (const eventType of events) {
|
|
1924
2011
|
const event = new DragEvent(eventType, {
|
|
@@ -1929,7 +2016,7 @@ var init_multi_browser = __esm({
|
|
|
1929
2016
|
dropzone.dispatchEvent(event);
|
|
1930
2017
|
await new Promise((r) => setTimeout(r, 50));
|
|
1931
2018
|
}
|
|
1932
|
-
}, { x:
|
|
2019
|
+
}, { x: dropTarget.x, y: dropTarget.y, fileName, mimeType, fileBytes });
|
|
1933
2020
|
return `Dropped "${fileName}" onto element`;
|
|
1934
2021
|
}, { timeout: 15e3 });
|
|
1935
2022
|
}
|
|
@@ -1948,10 +2035,39 @@ var getArg = (name) => {
|
|
|
1948
2035
|
const i = args.indexOf(`--${name}`);
|
|
1949
2036
|
return i >= 0 ? args[i + 1] : void 0;
|
|
1950
2037
|
};
|
|
2038
|
+
var getArgAny = (...names) => names.map((name) => getArg(name)).find((value) => value !== void 0);
|
|
2039
|
+
var getEnvAny = (...names) => names.map((name) => process.env[name]).find((value) => value !== void 0 && value !== "");
|
|
2040
|
+
function getOptionalPort(argNames, envNames) {
|
|
2041
|
+
const raw = getArgAny(...Array.isArray(argNames) ? argNames : [argNames]) ?? getEnvAny(...Array.isArray(envNames) ? envNames : [envNames]);
|
|
2042
|
+
if (raw === void 0 || raw === "") return void 0;
|
|
2043
|
+
const port = Number.parseInt(raw, 10);
|
|
2044
|
+
if (!Number.isFinite(port) || port <= 0) {
|
|
2045
|
+
const flagName = Array.isArray(argNames) ? argNames[0] : argNames;
|
|
2046
|
+
console.error(`[ornold] Invalid --${flagName}: ${raw}`);
|
|
2047
|
+
process.exit(1);
|
|
2048
|
+
}
|
|
2049
|
+
return port;
|
|
2050
|
+
}
|
|
2051
|
+
function getOptionalString(argNames, envNames) {
|
|
2052
|
+
const raw = getArgAny(...Array.isArray(argNames) ? argNames : [argNames]) ?? getEnvAny(...Array.isArray(envNames) ? envNames : [envNames]);
|
|
2053
|
+
if (raw === void 0) return void 0;
|
|
2054
|
+
const value = raw.trim();
|
|
2055
|
+
return value === "" ? void 0 : value;
|
|
2056
|
+
}
|
|
1951
2057
|
var TOKEN = getArg("token") || process.env.ORNOLD_TOKEN || "";
|
|
1952
2058
|
var SERVER_URL = getArg("server") || process.env.ORNOLD_SERVER || "wss://ornold-mcp.fly.dev/bridge";
|
|
1953
|
-
var LINKEN_PORT =
|
|
1954
|
-
var
|
|
2059
|
+
var LINKEN_PORT = getOptionalPort("linken-port", "LINKEN_PORT");
|
|
2060
|
+
var WADEX_PORT = getOptionalPort("wadex-port", "WADEX_PORT");
|
|
2061
|
+
var DOLPHIN_PORT = getOptionalPort("dolphin-port", "DOLPHIN_PORT");
|
|
2062
|
+
var DOLPHIN_API_TOKEN = getOptionalString("dolphin-token", "DOLPHIN_API_TOKEN");
|
|
2063
|
+
var VISION_PORT = getOptionalPort(["vision-port", "vision-local-port"], ["VISION_PORT", "VISION_LOCAL_PORT"]);
|
|
2064
|
+
var VISION_TOKEN = getOptionalString(["vision-token", "vision-x-token"], ["VISION_TOKEN", "VISION_X_TOKEN"]);
|
|
2065
|
+
var ENABLED_VENDORS = [
|
|
2066
|
+
...LINKEN_PORT !== void 0 ? ["linken"] : [],
|
|
2067
|
+
...WADEX_PORT !== void 0 ? ["wadex"] : [],
|
|
2068
|
+
...DOLPHIN_PORT !== void 0 || DOLPHIN_API_TOKEN !== void 0 ? ["dolphin"] : [],
|
|
2069
|
+
...VISION_TOKEN !== void 0 ? ["vision"] : []
|
|
2070
|
+
];
|
|
1955
2071
|
function getPackageVersion() {
|
|
1956
2072
|
try {
|
|
1957
2073
|
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
@@ -2050,46 +2166,190 @@ async function getExecutor() {
|
|
|
2050
2166
|
}
|
|
2051
2167
|
return executor;
|
|
2052
2168
|
}
|
|
2169
|
+
function getSelectorTarget(params) {
|
|
2170
|
+
const selector = typeof params.selector === "string" ? params.selector : void 0;
|
|
2171
|
+
const ref = typeof params.ref === "string" || typeof params.ref === "number" ? String(params.ref) : void 0;
|
|
2172
|
+
if (!selector && !ref) {
|
|
2173
|
+
throw new Error("Either selector or ref is required");
|
|
2174
|
+
}
|
|
2175
|
+
return selector ? { selector } : { ref };
|
|
2176
|
+
}
|
|
2177
|
+
function appendQueryValue(params, key, value) {
|
|
2178
|
+
if (value === void 0 || value === null) return;
|
|
2179
|
+
if (Array.isArray(value)) {
|
|
2180
|
+
for (const item of value) appendQueryValue(params, key, item);
|
|
2181
|
+
return;
|
|
2182
|
+
}
|
|
2183
|
+
if (typeof value === "object") {
|
|
2184
|
+
params.append(key, JSON.stringify(value));
|
|
2185
|
+
return;
|
|
2186
|
+
}
|
|
2187
|
+
params.append(key, String(value));
|
|
2188
|
+
}
|
|
2189
|
+
function withQuery(path2, query) {
|
|
2190
|
+
if (!query) return path2;
|
|
2191
|
+
const params = new URLSearchParams();
|
|
2192
|
+
for (const [key, value] of Object.entries(query)) {
|
|
2193
|
+
appendQueryValue(params, key, value);
|
|
2194
|
+
}
|
|
2195
|
+
const search = params.toString();
|
|
2196
|
+
return search ? `${path2}?${search}` : path2;
|
|
2197
|
+
}
|
|
2198
|
+
async function runVendorRequest(vendor, params) {
|
|
2199
|
+
const target = params.target === "local" ? "local" : "cloud";
|
|
2200
|
+
const path2 = typeof params.path === "string" ? params.path : "/";
|
|
2201
|
+
const method = typeof params.method === "string" ? params.method : "GET";
|
|
2202
|
+
const query = params.query && typeof params.query === "object" ? params.query : void 0;
|
|
2203
|
+
let url;
|
|
2204
|
+
const headers = {};
|
|
2205
|
+
if (vendor === "dolphin") {
|
|
2206
|
+
if (target === "cloud") {
|
|
2207
|
+
if (!DOLPHIN_API_TOKEN) {
|
|
2208
|
+
return { content: "DOLPHIN_API_TOKEN is not configured on this machine.", isError: true };
|
|
2209
|
+
}
|
|
2210
|
+
url = `https://dolphin-anty-api.com${withQuery(path2, query)}`;
|
|
2211
|
+
headers.Authorization = `Bearer ${DOLPHIN_API_TOKEN}`;
|
|
2212
|
+
} else {
|
|
2213
|
+
if (DOLPHIN_PORT === void 0) {
|
|
2214
|
+
return { content: "Dolphin local port is not configured on this machine.", isError: true };
|
|
2215
|
+
}
|
|
2216
|
+
url = `http://127.0.0.1:${DOLPHIN_PORT}${withQuery(path2, query)}`;
|
|
2217
|
+
}
|
|
2218
|
+
} else {
|
|
2219
|
+
if (!VISION_TOKEN) {
|
|
2220
|
+
return { content: "VISION_TOKEN is not configured on this machine.", isError: true };
|
|
2221
|
+
}
|
|
2222
|
+
headers["X-Token"] = VISION_TOKEN;
|
|
2223
|
+
if (target === "cloud") {
|
|
2224
|
+
url = `https://v1.empr.cloud/api/v1${withQuery(path2, query)}`;
|
|
2225
|
+
} else {
|
|
2226
|
+
if (VISION_PORT === void 0) {
|
|
2227
|
+
return { content: "Vision local port is not configured on this machine.", isError: true };
|
|
2228
|
+
}
|
|
2229
|
+
url = `http://127.0.0.1:${VISION_PORT}${withQuery(path2, query)}`;
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
if (params.body !== void 0) {
|
|
2233
|
+
headers["Content-Type"] = "application/json";
|
|
2234
|
+
}
|
|
2235
|
+
const resp = await fetch(url, {
|
|
2236
|
+
method,
|
|
2237
|
+
headers,
|
|
2238
|
+
body: params.body !== void 0 ? JSON.stringify(params.body) : void 0,
|
|
2239
|
+
signal: AbortSignal.timeout(3e4)
|
|
2240
|
+
});
|
|
2241
|
+
const data = await resp.text();
|
|
2242
|
+
try {
|
|
2243
|
+
return { content: JSON.stringify(JSON.parse(data)), isError: !resp.ok };
|
|
2244
|
+
} catch {
|
|
2245
|
+
return { content: data, isError: !resp.ok };
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2053
2248
|
async function handleExecuteCommand(msg) {
|
|
2054
2249
|
const { command, params } = msg;
|
|
2055
2250
|
try {
|
|
2056
2251
|
switch (command) {
|
|
2057
2252
|
// CDP commands — executed via local Patchright
|
|
2253
|
+
case "cdp_status": {
|
|
2254
|
+
const exec = await getExecutor();
|
|
2255
|
+
await exec.ensureBrowsersLoaded();
|
|
2256
|
+
const status = await exec.getDetailedStatus({ checkContent: !!params.checkContent });
|
|
2257
|
+
return { content: JSON.stringify(status), isError: false };
|
|
2258
|
+
}
|
|
2259
|
+
case "cdp_tabs": {
|
|
2260
|
+
const exec = await getExecutor();
|
|
2261
|
+
const r = await exec.parallelTabs(params.action, { index: params.index, url: params.url }, params.browserIds);
|
|
2262
|
+
return { content: formatResult(r), isError: false };
|
|
2263
|
+
}
|
|
2058
2264
|
case "cdp_navigate": {
|
|
2059
2265
|
const exec = await getExecutor();
|
|
2060
2266
|
const r = await exec.parallelNavigate(params.url, params.browserIds);
|
|
2061
2267
|
return { content: formatResult(r), isError: false };
|
|
2062
2268
|
}
|
|
2269
|
+
case "cdp_navigate_multi": {
|
|
2270
|
+
const exec = await getExecutor();
|
|
2271
|
+
const r = await exec.parallelNavigateMulti(params.targets);
|
|
2272
|
+
return { content: formatResult(r), isError: false };
|
|
2273
|
+
}
|
|
2063
2274
|
case "cdp_click": {
|
|
2064
2275
|
const exec = await getExecutor();
|
|
2065
|
-
const r = await exec.parallelClick(params
|
|
2276
|
+
const r = await exec.parallelClick(getSelectorTarget(params), params.browserIds);
|
|
2066
2277
|
return { content: formatResult(r), isError: false };
|
|
2067
2278
|
}
|
|
2068
2279
|
case "cdp_type": {
|
|
2069
2280
|
const exec = await getExecutor();
|
|
2070
|
-
const r = await exec.parallelType(params
|
|
2281
|
+
const r = await exec.parallelType(getSelectorTarget(params), params.text, params.browserIds);
|
|
2071
2282
|
return { content: formatResult(r), isError: false };
|
|
2072
2283
|
}
|
|
2073
2284
|
case "cdp_fill": {
|
|
2074
2285
|
const exec = await getExecutor();
|
|
2075
|
-
const
|
|
2286
|
+
const target = getSelectorTarget(params);
|
|
2287
|
+
const r = params.texts ? await exec.parallelFillMulti(target, params.texts) : await exec.parallelFill(target, params.text, params.browserIds);
|
|
2288
|
+
return { content: formatResult(r), isError: false };
|
|
2289
|
+
}
|
|
2290
|
+
case "cdp_fill_multi": {
|
|
2291
|
+
const exec = await getExecutor();
|
|
2292
|
+
const r = await exec.parallelFillMulti(getSelectorTarget(params), params.texts);
|
|
2293
|
+
return { content: formatResult(r), isError: false };
|
|
2294
|
+
}
|
|
2295
|
+
case "cdp_fill_form": {
|
|
2296
|
+
const exec = await getExecutor();
|
|
2297
|
+
const r = await exec.parallelFillForm(params.fields, params.browserIds);
|
|
2298
|
+
return { content: formatResult(r), isError: false };
|
|
2299
|
+
}
|
|
2300
|
+
case "cdp_drag": {
|
|
2301
|
+
const exec = await getExecutor();
|
|
2302
|
+
const r = await exec.parallelDrag(
|
|
2303
|
+
{
|
|
2304
|
+
selector: typeof params.startSelector === "string" ? params.startSelector : void 0,
|
|
2305
|
+
ref: typeof params.startRef === "string" || typeof params.startRef === "number" ? String(params.startRef) : void 0
|
|
2306
|
+
},
|
|
2307
|
+
{
|
|
2308
|
+
selector: typeof params.endSelector === "string" ? params.endSelector : void 0,
|
|
2309
|
+
ref: typeof params.endRef === "string" || typeof params.endRef === "number" ? String(params.endRef) : void 0
|
|
2310
|
+
},
|
|
2311
|
+
params.browserIds
|
|
2312
|
+
);
|
|
2076
2313
|
return { content: formatResult(r), isError: false };
|
|
2077
2314
|
}
|
|
2078
2315
|
case "cdp_snapshot": {
|
|
2079
2316
|
const exec = await getExecutor();
|
|
2080
2317
|
const r = await exec.parallelSnapshot(params.browserIds, { compact: params.compact });
|
|
2081
|
-
|
|
2318
|
+
const parts = (r.results || []).map((item) => {
|
|
2319
|
+
if (!item.success) return `[${item.browserId}] ERROR: ${item.error || "unknown"}`;
|
|
2320
|
+
const result = item.result || {};
|
|
2321
|
+
return `### ${item.browserId}
|
|
2322
|
+
URL: ${result.url || ""}
|
|
2323
|
+
Title: ${result.title || ""}
|
|
2324
|
+
${result.snapshot || ""}`;
|
|
2325
|
+
});
|
|
2326
|
+
return { content: parts.join("\n\n") || "OK", isError: false };
|
|
2082
2327
|
}
|
|
2083
2328
|
case "cdp_screenshot": {
|
|
2084
2329
|
const exec = await getExecutor();
|
|
2085
|
-
const r = await exec.parallelScreenshot(params.browserIds);
|
|
2086
|
-
|
|
2330
|
+
const r = await exec.parallelScreenshot(params.browserIds, { fullPage: params.fullPage });
|
|
2331
|
+
const lines = (r.results || []).map((item) => {
|
|
2332
|
+
if (!item.success) return `[${item.browserId}] ERROR: ${item.error || "unknown"}`;
|
|
2333
|
+
const image = Buffer.isBuffer(item.result) ? item.result.toString("base64") : Buffer.from(item.result || []).toString("base64");
|
|
2334
|
+
return `[${item.browserId}] ${image}`;
|
|
2335
|
+
});
|
|
2336
|
+
return { content: lines.join("\n") || "OK", isError: false };
|
|
2087
2337
|
}
|
|
2088
2338
|
case "cdp_evaluate": {
|
|
2089
2339
|
const exec = await getExecutor();
|
|
2090
2340
|
const r = await exec.parallelEvaluate(params.script, params.browserIds);
|
|
2091
2341
|
return { content: formatResult(r), isError: false };
|
|
2092
2342
|
}
|
|
2343
|
+
case "cdp_run_code": {
|
|
2344
|
+
const exec = await getExecutor();
|
|
2345
|
+
const r = await exec.parallelRunCode(params.code, params.browserIds);
|
|
2346
|
+
return { content: formatResult(r), isError: false };
|
|
2347
|
+
}
|
|
2348
|
+
case "cdp_run_code_with_vars": {
|
|
2349
|
+
const exec = await getExecutor();
|
|
2350
|
+
const r = await exec.parallelRunCodeWithVariables(params.codeTemplate, params.variables);
|
|
2351
|
+
return { content: formatResult(r), isError: false };
|
|
2352
|
+
}
|
|
2093
2353
|
case "cdp_press_key": {
|
|
2094
2354
|
const exec = await getExecutor();
|
|
2095
2355
|
const r = await exec.parallelPressKey(params.key, params.browserIds);
|
|
@@ -2097,12 +2357,12 @@ async function handleExecuteCommand(msg) {
|
|
|
2097
2357
|
}
|
|
2098
2358
|
case "cdp_select_option": {
|
|
2099
2359
|
const exec = await getExecutor();
|
|
2100
|
-
const r = await exec.parallelSelectOption(params
|
|
2360
|
+
const r = await exec.parallelSelectOption(getSelectorTarget(params), params.values, params.browserIds);
|
|
2101
2361
|
return { content: formatResult(r), isError: false };
|
|
2102
2362
|
}
|
|
2103
2363
|
case "cdp_hover": {
|
|
2104
2364
|
const exec = await getExecutor();
|
|
2105
|
-
const r = await exec.parallelHover(params
|
|
2365
|
+
const r = await exec.parallelHover(getSelectorTarget(params), params.browserIds);
|
|
2106
2366
|
return { content: formatResult(r), isError: false };
|
|
2107
2367
|
}
|
|
2108
2368
|
case "cdp_go_back": {
|
|
@@ -2110,6 +2370,11 @@ async function handleExecuteCommand(msg) {
|
|
|
2110
2370
|
const r = await exec.parallelGoBack(params.browserIds);
|
|
2111
2371
|
return { content: formatResult(r), isError: false };
|
|
2112
2372
|
}
|
|
2373
|
+
case "cdp_go_forward": {
|
|
2374
|
+
const exec = await getExecutor();
|
|
2375
|
+
const r = await exec.parallelGoForward(params.browserIds);
|
|
2376
|
+
return { content: formatResult(r), isError: false };
|
|
2377
|
+
}
|
|
2113
2378
|
case "cdp_reload": {
|
|
2114
2379
|
const exec = await getExecutor();
|
|
2115
2380
|
const r = await exec.parallelReload(params.browserIds);
|
|
@@ -2120,11 +2385,75 @@ async function handleExecuteCommand(msg) {
|
|
|
2120
2385
|
const opts = {};
|
|
2121
2386
|
if (params.time) opts.time = params.time;
|
|
2122
2387
|
if (params.text) opts.text = params.text;
|
|
2388
|
+
if (params.textGone) opts.textGone = params.textGone;
|
|
2389
|
+
if (params.domStableMs) opts.domStableMs = params.domStableMs;
|
|
2390
|
+
if (params.timeoutMs) opts.timeoutMs = params.timeoutMs;
|
|
2123
2391
|
const r = await exec.parallelWaitFor(opts, params.browserIds);
|
|
2124
2392
|
return { content: formatResult(r), isError: false };
|
|
2125
2393
|
}
|
|
2394
|
+
case "cdp_handle_dialog": {
|
|
2395
|
+
const exec = await getExecutor();
|
|
2396
|
+
const r = await exec.parallelHandleDialog(!!params.accept, params.promptText, params.browserIds);
|
|
2397
|
+
return { content: formatResult(r), isError: false };
|
|
2398
|
+
}
|
|
2399
|
+
case "cdp_console_messages": {
|
|
2400
|
+
const exec = await getExecutor();
|
|
2401
|
+
const r = await exec.parallelConsoleMessages(!!params.onlyErrors, params.browserIds);
|
|
2402
|
+
return { content: formatResult(r), isError: false };
|
|
2403
|
+
}
|
|
2404
|
+
case "cdp_network_requests": {
|
|
2405
|
+
const exec = await getExecutor();
|
|
2406
|
+
const r = await exec.parallelNetworkRequests(params.browserIds);
|
|
2407
|
+
return { content: formatResult(r), isError: false };
|
|
2408
|
+
}
|
|
2409
|
+
case "cdp_click_normalized_box": {
|
|
2410
|
+
const exec = await getExecutor();
|
|
2411
|
+
const r = await exec.parallelClickNormalizedBox(params.box, params.browserIds);
|
|
2412
|
+
return { content: formatResult(r), isError: false };
|
|
2413
|
+
}
|
|
2414
|
+
case "cdp_setup_downloads": {
|
|
2415
|
+
const exec = await getExecutor();
|
|
2416
|
+
const r = await exec.setupDownloads(params.browserIds);
|
|
2417
|
+
return { content: formatResult(r), isError: false };
|
|
2418
|
+
}
|
|
2419
|
+
case "cdp_list_downloads": {
|
|
2420
|
+
const exec = await getExecutor();
|
|
2421
|
+
const files = await exec.listProjectFiles();
|
|
2422
|
+
return { content: JSON.stringify(files), isError: false };
|
|
2423
|
+
}
|
|
2424
|
+
case "cdp_upload_file": {
|
|
2425
|
+
const exec = await getExecutor();
|
|
2426
|
+
const r = await exec.parallelUploadFile(getSelectorTarget(params), params.fileName, params.browserIds);
|
|
2427
|
+
return { content: formatResult(r), isError: false };
|
|
2428
|
+
}
|
|
2429
|
+
case "cdp_drag_drop_file": {
|
|
2430
|
+
const exec = await getExecutor();
|
|
2431
|
+
const r = await exec.parallelDragDropFile(getSelectorTarget(params), params.fileName, params.browserIds);
|
|
2432
|
+
return { content: formatResult(r), isError: false };
|
|
2433
|
+
}
|
|
2434
|
+
case "cdp_vision_capture": {
|
|
2435
|
+
const exec = await getExecutor();
|
|
2436
|
+
await exec.ensureBrowsersLoaded();
|
|
2437
|
+
const statuses = await exec.listBrowsers();
|
|
2438
|
+
const statusMap = new Map(statuses.map((browser) => [browser.id, browser]));
|
|
2439
|
+
const screenshotResult = await exec.parallelScreenshot(params.browserIds, {
|
|
2440
|
+
format: "jpeg",
|
|
2441
|
+
quality: 70
|
|
2442
|
+
});
|
|
2443
|
+
const captures = (screenshotResult.results || []).filter((item) => item.success && item.result !== void 0).map((item) => ({
|
|
2444
|
+
browserId: item.browserId,
|
|
2445
|
+
url: statusMap.get(item.browserId)?.url || "",
|
|
2446
|
+
screenshot: Buffer.isBuffer(item.result) ? item.result.toString("base64") : Buffer.from(item.result || []).toString("base64")
|
|
2447
|
+
}));
|
|
2448
|
+
const errors = (screenshotResult.results || []).filter((item) => !item.success).map((item) => ({
|
|
2449
|
+
browserId: item.browserId,
|
|
2450
|
+
error: item.error || "unknown"
|
|
2451
|
+
}));
|
|
2452
|
+
return { content: JSON.stringify({ captures, errors }), isError: captures.length === 0 };
|
|
2453
|
+
}
|
|
2126
2454
|
case "cdp_list_browsers": {
|
|
2127
2455
|
const exec = await getExecutor();
|
|
2456
|
+
await exec.ensureBrowsersLoaded();
|
|
2128
2457
|
const browsers = await exec.listBrowsers();
|
|
2129
2458
|
return { content: browsers.length === 0 ? "No browsers connected" : browsers.map((b) => `${b.id} ${b.connected ? "OK" : "DISCONNECTED"} ${b.url || ""}`).join("\n"), isError: false };
|
|
2130
2459
|
}
|
|
@@ -2174,6 +2503,10 @@ async function handleExecuteCommand(msg) {
|
|
|
2174
2503
|
return { content: data, isError: !resp.ok };
|
|
2175
2504
|
}
|
|
2176
2505
|
}
|
|
2506
|
+
case "dolphin_request":
|
|
2507
|
+
return await runVendorRequest("dolphin", params);
|
|
2508
|
+
case "vision_request":
|
|
2509
|
+
return await runVendorRequest("vision", params);
|
|
2177
2510
|
default:
|
|
2178
2511
|
return { content: `Unknown command: ${command}`, isError: true };
|
|
2179
2512
|
}
|
|
@@ -2200,121 +2533,555 @@ async function toolHandler(tool, args2) {
|
|
|
2200
2533
|
const result = await callServer(tool, args2);
|
|
2201
2534
|
return textResult(result.content, result.isError);
|
|
2202
2535
|
}
|
|
2536
|
+
var sphereStatusArg = z.enum(["stopped", "running", "imported", "warmup", "automationRunning"]).optional();
|
|
2537
|
+
var sphereProxyTypeArg = z.enum(["notSet", "socks5", "http", "ssh", "liveSocks5", "liveHttp", "direct", "tor", "localhost", "freeProxy"]);
|
|
2538
|
+
var visionFolderIconArg = z.enum([
|
|
2539
|
+
"Cloud",
|
|
2540
|
+
"Google",
|
|
2541
|
+
"Facebook",
|
|
2542
|
+
"TikTok",
|
|
2543
|
+
"Amazon",
|
|
2544
|
+
"Bitcoin",
|
|
2545
|
+
"Meta",
|
|
2546
|
+
"PayPal",
|
|
2547
|
+
"Discord",
|
|
2548
|
+
"Twitter",
|
|
2549
|
+
"Vkontakte",
|
|
2550
|
+
"Youtube",
|
|
2551
|
+
"Tinder",
|
|
2552
|
+
"Onlyfans",
|
|
2553
|
+
"Threads"
|
|
2554
|
+
]);
|
|
2555
|
+
var visionFolderColorArg = z.enum([
|
|
2556
|
+
"#FFC1073D",
|
|
2557
|
+
"#C8E4FFCD",
|
|
2558
|
+
"#3366FF3D",
|
|
2559
|
+
"#54D62C3D",
|
|
2560
|
+
"#FF48423D",
|
|
2561
|
+
"#919EAB3D"
|
|
2562
|
+
]);
|
|
2563
|
+
var visionPlatformArg = z.enum(["macos", "windows", "linux"]);
|
|
2564
|
+
var visionProfilePlatformArg = z.enum(["Windows", "MacOS", "Linux", "windows", "macos", "linux"]);
|
|
2565
|
+
var visionBrowserArg = z.enum(["Chrome", "chrome"]);
|
|
2566
|
+
var visionProxyTypeArg = z.enum(["HTTP", "SOCKS4", "SOCKS5", "SSH", "http", "socks4", "socks5", "ssh"]);
|
|
2567
|
+
function registerSphereTools(server, prefix, label) {
|
|
2568
|
+
server.tool(`${prefix}_get_instances`, `Get list of ${label} sessions`, {
|
|
2569
|
+
status: sphereStatusArg,
|
|
2570
|
+
proxy_info: z.boolean().optional()
|
|
2571
|
+
}, (args2) => toolHandler(`${prefix}_get_instances`, args2));
|
|
2572
|
+
server.tool(`${prefix}_create_quick_sessions`, `Create ${label} sessions`, {
|
|
2573
|
+
count: z.number().optional()
|
|
2574
|
+
}, (args2) => toolHandler(`${prefix}_create_quick_sessions`, args2));
|
|
2575
|
+
server.tool(`${prefix}_start_instances`, `Start ${label} browser sessions`, {
|
|
2576
|
+
uuids: z.array(z.string()),
|
|
2577
|
+
headless: z.boolean().optional(),
|
|
2578
|
+
debug_port: z.number().optional(),
|
|
2579
|
+
_scope: z.string().optional()
|
|
2580
|
+
}, (args2) => toolHandler(`${prefix}_start_instances`, args2));
|
|
2581
|
+
server.tool(`${prefix}_stop_instances`, `Stop ${label} sessions`, {
|
|
2582
|
+
uuids: z.array(z.string())
|
|
2583
|
+
}, (args2) => toolHandler(`${prefix}_stop_instances`, args2));
|
|
2584
|
+
server.tool(`${prefix}_session_info`, `Get ${label} session details`, {
|
|
2585
|
+
uuid: z.string()
|
|
2586
|
+
}, (args2) => toolHandler(`${prefix}_session_info`, args2));
|
|
2587
|
+
server.tool(`${prefix}_force_stop`, `Force stop ${label} session`, {
|
|
2588
|
+
uuid: z.string()
|
|
2589
|
+
}, (args2) => toolHandler(`${prefix}_force_stop`, args2));
|
|
2590
|
+
server.tool(`${prefix}_delete_sessions`, `Delete ${label} sessions`, {
|
|
2591
|
+
uuid: z.string().optional(),
|
|
2592
|
+
uuids: z.array(z.string()).optional()
|
|
2593
|
+
}, (args2) => toolHandler(`${prefix}_delete_sessions`, args2));
|
|
2594
|
+
server.tool(`${prefix}_unlock_stopped_sessions`, `Unlock stopped ${label} sessions`, {}, () => toolHandler(`${prefix}_unlock_stopped_sessions`, {}));
|
|
2595
|
+
server.tool(`${prefix}_set_session_name`, `Rename ${label} session`, {
|
|
2596
|
+
uuid: z.string(),
|
|
2597
|
+
name: z.string()
|
|
2598
|
+
}, (args2) => toolHandler(`${prefix}_set_session_name`, args2));
|
|
2599
|
+
server.tool(`${prefix}_set_connection`, `Set proxy for ${label} session`, {
|
|
2600
|
+
uuid: z.string(),
|
|
2601
|
+
type: sphereProxyTypeArg,
|
|
2602
|
+
ip: z.string().optional(),
|
|
2603
|
+
port: z.number().optional(),
|
|
2604
|
+
login: z.string().optional(),
|
|
2605
|
+
password: z.string().optional()
|
|
2606
|
+
}, (args2) => toolHandler(`${prefix}_set_connection`, args2));
|
|
2607
|
+
server.tool(`${prefix}_check_connection`, `Check proxy for ${label} session`, {
|
|
2608
|
+
uuid: z.string()
|
|
2609
|
+
}, (args2) => toolHandler(`${prefix}_check_connection`, args2));
|
|
2610
|
+
server.tool(`${prefix}_set_geo`, `Set ${label} geolocation`, {
|
|
2611
|
+
uuid: z.string(),
|
|
2612
|
+
timezone: z.string().optional(),
|
|
2613
|
+
language: z.string().optional(),
|
|
2614
|
+
latitude: z.number().optional(),
|
|
2615
|
+
longitude: z.number().optional()
|
|
2616
|
+
}, (args2) => toolHandler(`${prefix}_set_geo`, args2));
|
|
2617
|
+
server.tool(`${prefix}_set_useragent`, `Set ${label} user agent`, {
|
|
2618
|
+
uuid: z.string(),
|
|
2619
|
+
useragent: z.string()
|
|
2620
|
+
}, (args2) => toolHandler(`${prefix}_set_useragent`, args2));
|
|
2621
|
+
server.tool(`${prefix}_import_cookies`, `Import cookies into ${label} session`, {
|
|
2622
|
+
uuid: z.string(),
|
|
2623
|
+
file_path: z.string().optional(),
|
|
2624
|
+
json: z.string().optional()
|
|
2625
|
+
}, (args2) => toolHandler(`${prefix}_import_cookies`, args2));
|
|
2626
|
+
server.tool(`${prefix}_export_cookies`, `Export cookies from ${label} sessions`, {
|
|
2627
|
+
uuids: z.array(z.string()),
|
|
2628
|
+
folder_path: z.string()
|
|
2629
|
+
}, (args2) => toolHandler(`${prefix}_export_cookies`, args2));
|
|
2630
|
+
server.tool(`${prefix}_start_warmup`, `Start ${label} session warmup`, {
|
|
2631
|
+
uuid: z.string(),
|
|
2632
|
+
url_count: z.number().optional(),
|
|
2633
|
+
time_per_url: z.number().optional(),
|
|
2634
|
+
view_depth: z.number().optional(),
|
|
2635
|
+
urls: z.array(z.string()).optional()
|
|
2636
|
+
}, (args2) => toolHandler(`${prefix}_start_warmup`, args2));
|
|
2637
|
+
server.tool(`${prefix}_get_providers`, `List ${label} providers`, {}, () => toolHandler(`${prefix}_get_providers`, {}));
|
|
2638
|
+
server.tool(`${prefix}_set_active_provider`, `Set active ${label} provider`, {
|
|
2639
|
+
uuid: z.string()
|
|
2640
|
+
}, (args2) => toolHandler(`${prefix}_set_active_provider`, args2));
|
|
2641
|
+
server.tool(`${prefix}_delete_provider`, `Delete ${label} provider`, {
|
|
2642
|
+
uuid: z.string()
|
|
2643
|
+
}, (args2) => toolHandler(`${prefix}_delete_provider`, args2));
|
|
2644
|
+
server.tool(`${prefix}_get_desktops`, `List ${label} desktops`, {}, () => toolHandler(`${prefix}_get_desktops`, {}));
|
|
2645
|
+
server.tool(`${prefix}_create_desktop`, `Create ${label} desktop`, {
|
|
2646
|
+
name: z.string(),
|
|
2647
|
+
team_uuid: z.string().optional()
|
|
2648
|
+
}, (args2) => toolHandler(`${prefix}_create_desktop`, args2));
|
|
2649
|
+
server.tool(`${prefix}_set_active_desktop`, `Set active ${label} desktop`, {
|
|
2650
|
+
uuid: z.string()
|
|
2651
|
+
}, (args2) => toolHandler(`${prefix}_set_active_desktop`, args2));
|
|
2652
|
+
server.tool(`${prefix}_delete_desktop`, `Delete ${label} desktop`, {
|
|
2653
|
+
uuid: z.string()
|
|
2654
|
+
}, (args2) => toolHandler(`${prefix}_delete_desktop`, args2));
|
|
2655
|
+
server.tool(`${prefix}_optimize_storage`, `Optimize ${label} storage`, {}, () => toolHandler(`${prefix}_optimize_storage`, {}));
|
|
2656
|
+
}
|
|
2657
|
+
function registerDolphinTools(server) {
|
|
2658
|
+
if (DOLPHIN_API_TOKEN !== void 0) {
|
|
2659
|
+
server.tool("dolphin_get_profiles", "Get list of Dolphin Anty browser profiles", {
|
|
2660
|
+
limit: z.number().optional(),
|
|
2661
|
+
page: z.number().optional(),
|
|
2662
|
+
query: z.string().optional(),
|
|
2663
|
+
tags: z.array(z.string()).optional(),
|
|
2664
|
+
statuses: z.array(z.number()).optional(),
|
|
2665
|
+
mainWebsites: z.array(z.string()).optional()
|
|
2666
|
+
}, (args2) => toolHandler("dolphin_get_profiles", args2));
|
|
2667
|
+
}
|
|
2668
|
+
if (DOLPHIN_PORT !== void 0) {
|
|
2669
|
+
server.tool("dolphin_start_profile", "Start a Dolphin Anty browser profile", {
|
|
2670
|
+
profile_id: z.number(),
|
|
2671
|
+
headless: z.boolean().optional(),
|
|
2672
|
+
_scope: z.string().optional()
|
|
2673
|
+
}, (args2) => toolHandler("dolphin_start_profile", args2));
|
|
2674
|
+
server.tool("dolphin_stop_profile", "Stop a running Dolphin Anty browser profile", {
|
|
2675
|
+
profile_id: z.number()
|
|
2676
|
+
}, (args2) => toolHandler("dolphin_stop_profile", args2));
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
function registerVisionTools(server) {
|
|
2680
|
+
if (VISION_TOKEN === void 0) {
|
|
2681
|
+
return;
|
|
2682
|
+
}
|
|
2683
|
+
server.tool("vision_get_folders", "Get Vision Browser folders via Cloud API", {}, () => toolHandler("vision_get_folders", {}));
|
|
2684
|
+
server.tool("vision_create_folder", "Create a Vision Browser folder via Cloud API", {
|
|
2685
|
+
folder_name: z.string(),
|
|
2686
|
+
folder_icon: visionFolderIconArg,
|
|
2687
|
+
folder_color: visionFolderColorArg
|
|
2688
|
+
}, (args2) => toolHandler("vision_create_folder", args2));
|
|
2689
|
+
server.tool("vision_update_folder", "Update a Vision Browser folder via Cloud API", {
|
|
2690
|
+
folder_id: z.string(),
|
|
2691
|
+
folder_name: z.string().optional(),
|
|
2692
|
+
folder_icon: visionFolderIconArg.optional(),
|
|
2693
|
+
folder_color: visionFolderColorArg.optional()
|
|
2694
|
+
}, (args2) => toolHandler("vision_update_folder", args2));
|
|
2695
|
+
server.tool("vision_delete_folder", "Delete a Vision Browser folder via Cloud API", {
|
|
2696
|
+
folder_id: z.string()
|
|
2697
|
+
}, (args2) => toolHandler("vision_delete_folder", args2));
|
|
2698
|
+
server.tool("vision_get_profiles", "Get Vision Browser profiles from a specific folder via Cloud API", {
|
|
2699
|
+
folder_id: z.string(),
|
|
2700
|
+
name: z.string().optional(),
|
|
2701
|
+
pn: z.number().optional(),
|
|
2702
|
+
ps: z.number().optional()
|
|
2703
|
+
}, (args2) => toolHandler("vision_get_profiles", args2));
|
|
2704
|
+
server.tool("vision_get_profile", "Get a specific Vision Browser profile via Cloud API", {
|
|
2705
|
+
folder_id: z.string(),
|
|
2706
|
+
profile_id: z.string()
|
|
2707
|
+
}, (args2) => toolHandler("vision_get_profile", args2));
|
|
2708
|
+
server.tool("vision_get_fingerprint", "Get a Vision Browser fingerprint via Cloud API", {
|
|
2709
|
+
platform: visionPlatformArg,
|
|
2710
|
+
version: z.number().optional()
|
|
2711
|
+
}, (args2) => toolHandler("vision_get_fingerprint", args2));
|
|
2712
|
+
server.tool("vision_import_cookies", "Import cookies into a Vision Browser profile via Cloud API", {
|
|
2713
|
+
folder_id: z.string(),
|
|
2714
|
+
profile_id: z.string(),
|
|
2715
|
+
cookies: z.array(z.object({
|
|
2716
|
+
name: z.string(),
|
|
2717
|
+
value: z.string(),
|
|
2718
|
+
path: z.string(),
|
|
2719
|
+
domain: z.string(),
|
|
2720
|
+
expires: z.number().optional()
|
|
2721
|
+
}).passthrough())
|
|
2722
|
+
}, (args2) => toolHandler("vision_import_cookies", args2));
|
|
2723
|
+
server.tool("vision_get_cookies", "Get cookies from a Vision Browser profile via Cloud API", {
|
|
2724
|
+
folder_id: z.string(),
|
|
2725
|
+
profile_id: z.string()
|
|
2726
|
+
}, (args2) => toolHandler("vision_get_cookies", args2));
|
|
2727
|
+
server.tool("vision_create_profile", "Create a Vision Browser profile via Cloud API", {
|
|
2728
|
+
folder_id: z.string(),
|
|
2729
|
+
profile_name: z.string(),
|
|
2730
|
+
profile_notes: z.string().nullable().optional(),
|
|
2731
|
+
profile_tags: z.array(z.string()).optional(),
|
|
2732
|
+
new_profile_tags: z.array(z.string()).optional(),
|
|
2733
|
+
proxy_id: z.string().nullable().optional(),
|
|
2734
|
+
profile_status: z.array(z.string()).nullable().optional(),
|
|
2735
|
+
platform: visionProfilePlatformArg,
|
|
2736
|
+
browser: visionBrowserArg,
|
|
2737
|
+
fingerprint: z.object({
|
|
2738
|
+
webrtc_pref: z.unknown(),
|
|
2739
|
+
webgl_pref: z.unknown(),
|
|
2740
|
+
canvas_pref: z.unknown(),
|
|
2741
|
+
ports_protection: z.array(z.number())
|
|
2742
|
+
}).passthrough()
|
|
2743
|
+
}, (args2) => toolHandler("vision_create_profile", args2));
|
|
2744
|
+
server.tool("vision_update_profile", "Update a Vision Browser profile via Cloud API", {
|
|
2745
|
+
folder_id: z.string(),
|
|
2746
|
+
profile_id: z.string(),
|
|
2747
|
+
profile_name: z.string().optional(),
|
|
2748
|
+
profile_notes: z.string().optional(),
|
|
2749
|
+
profile_tags: z.array(z.string()).optional(),
|
|
2750
|
+
new_profile_tags: z.array(z.string()).optional(),
|
|
2751
|
+
profile_status: z.string().nullable().optional(),
|
|
2752
|
+
pinned: z.boolean().optional(),
|
|
2753
|
+
proxy_id: z.union([z.string(), z.object({ id: z.string() })]).optional()
|
|
2754
|
+
}, (args2) => toolHandler("vision_update_profile", args2));
|
|
2755
|
+
server.tool("vision_delete_profile", "Delete a Vision Browser profile via Cloud API", {
|
|
2756
|
+
folder_id: z.string(),
|
|
2757
|
+
profile_id: z.string()
|
|
2758
|
+
}, (args2) => toolHandler("vision_delete_profile", args2));
|
|
2759
|
+
server.tool("vision_get_proxies", "Get Vision Browser proxies from a specific folder via Cloud API", {
|
|
2760
|
+
folder_id: z.string()
|
|
2761
|
+
}, (args2) => toolHandler("vision_get_proxies", args2));
|
|
2762
|
+
server.tool("vision_create_proxies", "Create Vision Browser proxies inside a folder via Cloud API", {
|
|
2763
|
+
folder_id: z.string(),
|
|
2764
|
+
proxies: z.array(z.object({
|
|
2765
|
+
proxy_name: z.string(),
|
|
2766
|
+
proxy_type: visionProxyTypeArg,
|
|
2767
|
+
proxy_ip: z.string(),
|
|
2768
|
+
proxy_port: z.number(),
|
|
2769
|
+
proxy_username: z.string().optional(),
|
|
2770
|
+
proxy_password: z.string().optional(),
|
|
2771
|
+
update_url: z.string().optional(),
|
|
2772
|
+
proxy_geo: z.record(z.unknown()).optional()
|
|
2773
|
+
}).passthrough())
|
|
2774
|
+
}, (args2) => toolHandler("vision_create_proxies", args2));
|
|
2775
|
+
server.tool("vision_update_proxy", "Update a Vision Browser proxy via Cloud API", {
|
|
2776
|
+
folder_id: z.string(),
|
|
2777
|
+
proxy_id: z.string(),
|
|
2778
|
+
proxy_name: z.string(),
|
|
2779
|
+
proxy_type: visionProxyTypeArg,
|
|
2780
|
+
proxy_ip: z.string(),
|
|
2781
|
+
proxy_port: z.number(),
|
|
2782
|
+
proxy_username: z.string().optional(),
|
|
2783
|
+
proxy_password: z.string().optional(),
|
|
2784
|
+
update_url: z.string().optional(),
|
|
2785
|
+
proxy_geo: z.record(z.unknown()).optional()
|
|
2786
|
+
}, (args2) => toolHandler("vision_update_proxy", args2));
|
|
2787
|
+
server.tool("vision_delete_proxies", "Delete Vision Browser proxies inside a folder via Cloud API", {
|
|
2788
|
+
folder_id: z.string(),
|
|
2789
|
+
proxy_ids: z.array(z.string())
|
|
2790
|
+
}, (args2) => toolHandler("vision_delete_proxies", args2));
|
|
2791
|
+
server.tool("vision_get_statuses", "Get Vision Browser statuses from a specific folder via Cloud API", {
|
|
2792
|
+
folder_id: z.string()
|
|
2793
|
+
}, (args2) => toolHandler("vision_get_statuses", args2));
|
|
2794
|
+
server.tool("vision_get_tags", "Get Vision Browser tags from a specific folder via Cloud API", {
|
|
2795
|
+
folder_id: z.string()
|
|
2796
|
+
}, (args2) => toolHandler("vision_get_tags", args2));
|
|
2797
|
+
server.tool("vision_create_tags", "Create Vision Browser tags inside a folder via Cloud API", {
|
|
2798
|
+
folder_id: z.string(),
|
|
2799
|
+
tags: z.array(z.string())
|
|
2800
|
+
}, (args2) => toolHandler("vision_create_tags", args2));
|
|
2801
|
+
server.tool("vision_update_tag", "Update a Vision Browser tag via Cloud API", {
|
|
2802
|
+
folder_id: z.string(),
|
|
2803
|
+
tag_id: z.string(),
|
|
2804
|
+
name: z.string()
|
|
2805
|
+
}, (args2) => toolHandler("vision_update_tag", args2));
|
|
2806
|
+
server.tool("vision_delete_tags", "Delete Vision Browser tags via Cloud API", {
|
|
2807
|
+
folder_id: z.string(),
|
|
2808
|
+
tag_ids: z.array(z.string())
|
|
2809
|
+
}, (args2) => toolHandler("vision_delete_tags", args2));
|
|
2810
|
+
server.tool("vision_create_statuses", "Create Vision Browser statuses via Cloud API", {
|
|
2811
|
+
folder_id: z.string(),
|
|
2812
|
+
statuses: z.array(z.tuple([z.string(), z.string()]))
|
|
2813
|
+
}, (args2) => toolHandler("vision_create_statuses", args2));
|
|
2814
|
+
server.tool("vision_update_status", "Update a Vision Browser status via Cloud API", {
|
|
2815
|
+
folder_id: z.string(),
|
|
2816
|
+
status_id: z.string(),
|
|
2817
|
+
name: z.string(),
|
|
2818
|
+
color: z.string()
|
|
2819
|
+
}, (args2) => toolHandler("vision_update_status", args2));
|
|
2820
|
+
server.tool("vision_delete_statuses", "Delete Vision Browser statuses via Cloud API", {
|
|
2821
|
+
folder_id: z.string(),
|
|
2822
|
+
status_ids: z.array(z.string())
|
|
2823
|
+
}, (args2) => toolHandler("vision_delete_statuses", args2));
|
|
2824
|
+
if (VISION_PORT !== void 0) {
|
|
2825
|
+
server.tool("vision_get_languages", "Get available Vision Browser languages from the local API", {}, () => toolHandler("vision_get_languages", {}));
|
|
2826
|
+
server.tool("vision_get_timezones", "Get available Vision Browser timezones from the local API", {}, () => toolHandler("vision_get_timezones", {}));
|
|
2827
|
+
server.tool("vision_get_renderers", "Get available Vision Browser renderers from the local API", {
|
|
2828
|
+
os: visionPlatformArg,
|
|
2829
|
+
version: z.number().optional()
|
|
2830
|
+
}, (args2) => toolHandler("vision_get_renderers", args2));
|
|
2831
|
+
}
|
|
2832
|
+
}
|
|
2833
|
+
var browserIdsArg = z.array(z.string()).optional();
|
|
2834
|
+
var browserScopeArg = z.string().optional();
|
|
2835
|
+
var browserRefArg = z.union([z.string(), z.number()]).optional();
|
|
2836
|
+
var browserTargetArgs = {
|
|
2837
|
+
element: z.string().optional(),
|
|
2838
|
+
ref: browserRefArg,
|
|
2839
|
+
selector: z.string().optional(),
|
|
2840
|
+
browserIds: browserIdsArg,
|
|
2841
|
+
_scope: browserScopeArg
|
|
2842
|
+
};
|
|
2203
2843
|
function createServer() {
|
|
2204
2844
|
const server = new McpServer({ name: "ornold-browser", version: CLIENT_VERSION });
|
|
2205
2845
|
server.tool("browser_list", "List connected browsers", {}, () => toolHandler("browser_list", {}));
|
|
2846
|
+
server.tool("browser_status", "Check browser sync and responsiveness", {
|
|
2847
|
+
checkContent: z.boolean().optional(),
|
|
2848
|
+
_scope: browserScopeArg
|
|
2849
|
+
}, (args2) => toolHandler("browser_status", args2));
|
|
2850
|
+
server.tool("browser_parallel_tabs", "Manage browser tabs in parallel", {
|
|
2851
|
+
action: z.enum(["list", "new", "close", "select"]),
|
|
2852
|
+
index: z.number().optional(),
|
|
2853
|
+
url: z.string().optional(),
|
|
2854
|
+
browserIds: browserIdsArg,
|
|
2855
|
+
_scope: browserScopeArg
|
|
2856
|
+
}, (args2) => toolHandler("browser_parallel_tabs", args2));
|
|
2206
2857
|
server.tool("browser_parallel_snapshot", "Get page snapshot with [ref=N] markers", {
|
|
2207
2858
|
compact: z.boolean().optional(),
|
|
2208
|
-
browserIds:
|
|
2859
|
+
browserIds: browserIdsArg,
|
|
2860
|
+
_scope: browserScopeArg
|
|
2209
2861
|
}, (args2) => toolHandler("browser_parallel_snapshot", args2));
|
|
2210
2862
|
server.tool("browser_parallel_navigate", "Navigate to URL", {
|
|
2211
2863
|
url: z.string(),
|
|
2212
|
-
browserIds:
|
|
2864
|
+
browserIds: browserIdsArg,
|
|
2865
|
+
_scope: browserScopeArg
|
|
2213
2866
|
}, (args2) => toolHandler("browser_parallel_navigate", args2));
|
|
2867
|
+
server.tool("browser_parallel_navigate_multi", "Navigate each browser to a different URL", {
|
|
2868
|
+
targets: z.array(z.object({
|
|
2869
|
+
browserId: z.string(),
|
|
2870
|
+
url: z.string()
|
|
2871
|
+
})),
|
|
2872
|
+
_scope: browserScopeArg
|
|
2873
|
+
}, (args2) => toolHandler("browser_parallel_navigate_multi", args2));
|
|
2214
2874
|
server.tool("browser_parallel_click", "Click element", {
|
|
2215
|
-
|
|
2216
|
-
browserIds: z.array(z.string()).optional()
|
|
2875
|
+
...browserTargetArgs
|
|
2217
2876
|
}, (args2) => toolHandler("browser_parallel_click", args2));
|
|
2218
2877
|
server.tool("browser_parallel_type", "Type text into element", {
|
|
2219
|
-
|
|
2220
|
-
text: z.string()
|
|
2221
|
-
browserIds: z.array(z.string()).optional()
|
|
2878
|
+
...browserTargetArgs,
|
|
2879
|
+
text: z.string()
|
|
2222
2880
|
}, (args2) => toolHandler("browser_parallel_type", args2));
|
|
2223
2881
|
server.tool("browser_parallel_fill", "Fill input (clear + type)", {
|
|
2224
|
-
|
|
2225
|
-
text: z.string(),
|
|
2226
|
-
|
|
2882
|
+
...browserTargetArgs,
|
|
2883
|
+
text: z.string().optional(),
|
|
2884
|
+
texts: z.record(z.string()).optional()
|
|
2227
2885
|
}, (args2) => toolHandler("browser_parallel_fill", args2));
|
|
2886
|
+
server.tool("browser_parallel_fill_multi", "Fill input with per-browser values", {
|
|
2887
|
+
...browserTargetArgs,
|
|
2888
|
+
texts: z.record(z.string())
|
|
2889
|
+
}, (args2) => toolHandler("browser_parallel_fill_multi", args2));
|
|
2890
|
+
server.tool("browser_parallel_fill_form", "Fill multiple form fields sequentially", {
|
|
2891
|
+
fields: z.array(z.object({
|
|
2892
|
+
element: z.string().optional(),
|
|
2893
|
+
ref: browserRefArg,
|
|
2894
|
+
selector: z.string().optional(),
|
|
2895
|
+
value: z.string(),
|
|
2896
|
+
type: z.enum(["textbox", "checkbox", "radio", "combobox"]).optional()
|
|
2897
|
+
})),
|
|
2898
|
+
browserIds: browserIdsArg,
|
|
2899
|
+
_scope: browserScopeArg
|
|
2900
|
+
}, (args2) => toolHandler("browser_parallel_fill_form", args2));
|
|
2901
|
+
server.tool("browser_parallel_drag", "Drag from one element to another", {
|
|
2902
|
+
startElement: z.string().optional(),
|
|
2903
|
+
startRef: browserRefArg,
|
|
2904
|
+
startSelector: z.string().optional(),
|
|
2905
|
+
endElement: z.string().optional(),
|
|
2906
|
+
endRef: browserRefArg,
|
|
2907
|
+
endSelector: z.string().optional(),
|
|
2908
|
+
browserIds: browserIdsArg,
|
|
2909
|
+
_scope: browserScopeArg
|
|
2910
|
+
}, (args2) => toolHandler("browser_parallel_drag", args2));
|
|
2228
2911
|
server.tool("browser_parallel_press_key", "Press keyboard key", {
|
|
2229
2912
|
key: z.string(),
|
|
2230
|
-
browserIds:
|
|
2913
|
+
browserIds: browserIdsArg,
|
|
2914
|
+
_scope: browserScopeArg
|
|
2231
2915
|
}, (args2) => toolHandler("browser_parallel_press_key", args2));
|
|
2232
2916
|
server.tool("browser_parallel_select_option", "Select dropdown option", {
|
|
2233
|
-
|
|
2234
|
-
values: z.array(z.string())
|
|
2235
|
-
browserIds: z.array(z.string()).optional()
|
|
2917
|
+
...browserTargetArgs,
|
|
2918
|
+
values: z.array(z.string())
|
|
2236
2919
|
}, (args2) => toolHandler("browser_parallel_select_option", args2));
|
|
2237
2920
|
server.tool("browser_parallel_wait_for", "Wait for condition", {
|
|
2238
2921
|
time: z.number().optional(),
|
|
2239
2922
|
text: z.string().optional(),
|
|
2240
|
-
|
|
2923
|
+
textGone: z.string().optional(),
|
|
2924
|
+
domStableMs: z.number().optional(),
|
|
2925
|
+
timeoutMs: z.number().optional(),
|
|
2926
|
+
browserIds: browserIdsArg,
|
|
2927
|
+
_scope: browserScopeArg
|
|
2241
2928
|
}, (args2) => toolHandler("browser_parallel_wait_for", args2));
|
|
2242
2929
|
server.tool("browser_parallel_screenshot", "Take screenshot", {
|
|
2243
|
-
|
|
2930
|
+
fullPage: z.boolean().optional(),
|
|
2931
|
+
browserIds: browserIdsArg,
|
|
2932
|
+
_scope: browserScopeArg
|
|
2244
2933
|
}, (args2) => toolHandler("browser_parallel_screenshot", args2));
|
|
2245
2934
|
server.tool("browser_parallel_evaluate", "Run JavaScript in page", {
|
|
2246
2935
|
script: z.string(),
|
|
2247
|
-
browserIds:
|
|
2936
|
+
browserIds: browserIdsArg,
|
|
2937
|
+
_scope: browserScopeArg
|
|
2248
2938
|
}, (args2) => toolHandler("browser_parallel_evaluate", args2));
|
|
2939
|
+
server.tool("browser_parallel_run_code", "Run JavaScript code in page context", {
|
|
2940
|
+
code: z.string(),
|
|
2941
|
+
browserIds: browserIdsArg,
|
|
2942
|
+
_scope: browserScopeArg
|
|
2943
|
+
}, (args2) => toolHandler("browser_parallel_run_code", args2));
|
|
2944
|
+
server.tool("browser_parallel_run_code_with_vars", "Run templated JavaScript code with per-browser variables", {
|
|
2945
|
+
codeTemplate: z.string(),
|
|
2946
|
+
variables: z.record(z.record(z.string())),
|
|
2947
|
+
_scope: browserScopeArg
|
|
2948
|
+
}, (args2) => toolHandler("browser_parallel_run_code_with_vars", args2));
|
|
2249
2949
|
server.tool("browser_parallel_hover", "Hover over element", {
|
|
2250
|
-
|
|
2251
|
-
browserIds: z.array(z.string()).optional()
|
|
2950
|
+
...browserTargetArgs
|
|
2252
2951
|
}, (args2) => toolHandler("browser_parallel_hover", args2));
|
|
2253
2952
|
server.tool("browser_parallel_go_back", "Go back", {
|
|
2254
|
-
browserIds:
|
|
2953
|
+
browserIds: browserIdsArg,
|
|
2954
|
+
_scope: browserScopeArg
|
|
2255
2955
|
}, (args2) => toolHandler("browser_parallel_go_back", args2));
|
|
2956
|
+
server.tool("browser_parallel_go_forward", "Go forward", {
|
|
2957
|
+
browserIds: browserIdsArg,
|
|
2958
|
+
_scope: browserScopeArg
|
|
2959
|
+
}, (args2) => toolHandler("browser_parallel_go_forward", args2));
|
|
2256
2960
|
server.tool("browser_parallel_reload", "Reload page", {
|
|
2257
|
-
browserIds:
|
|
2961
|
+
browserIds: browserIdsArg,
|
|
2962
|
+
_scope: browserScopeArg
|
|
2258
2963
|
}, (args2) => toolHandler("browser_parallel_reload", args2));
|
|
2259
|
-
server.tool("
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
}, (args2) => toolHandler("
|
|
2284
|
-
server.tool("
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
server.tool("
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2964
|
+
server.tool("browser_parallel_handle_dialog", "Handle JavaScript dialogs", {
|
|
2965
|
+
accept: z.boolean(),
|
|
2966
|
+
promptText: z.string().optional(),
|
|
2967
|
+
browserIds: browserIdsArg,
|
|
2968
|
+
_scope: browserScopeArg
|
|
2969
|
+
}, (args2) => toolHandler("browser_parallel_handle_dialog", args2));
|
|
2970
|
+
server.tool("browser_parallel_console_messages", "Get console messages", {
|
|
2971
|
+
onlyErrors: z.boolean().optional(),
|
|
2972
|
+
browserIds: browserIdsArg,
|
|
2973
|
+
_scope: browserScopeArg
|
|
2974
|
+
}, (args2) => toolHandler("browser_parallel_console_messages", args2));
|
|
2975
|
+
server.tool("browser_parallel_network_requests", "Get network requests", {
|
|
2976
|
+
browserIds: browserIdsArg,
|
|
2977
|
+
_scope: browserScopeArg
|
|
2978
|
+
}, (args2) => toolHandler("browser_parallel_network_requests", args2));
|
|
2979
|
+
server.tool("browser_parallel_vision_analyze_grouped", "Analyze grouped browser screenshots with OmniParser via Ornold server", {
|
|
2980
|
+
similarityThreshold: z.number().optional(),
|
|
2981
|
+
browserIds: browserIdsArg,
|
|
2982
|
+
_scope: browserScopeArg
|
|
2983
|
+
}, (args2) => toolHandler("browser_parallel_vision_analyze_grouped", args2));
|
|
2984
|
+
server.tool("browser_parallel_click_normalized_box", "Click normalized viewport box center", {
|
|
2985
|
+
box: z.tuple([z.number(), z.number(), z.number(), z.number()]),
|
|
2986
|
+
browserIds: browserIdsArg,
|
|
2987
|
+
_scope: browserScopeArg
|
|
2988
|
+
}, (args2) => toolHandler("browser_parallel_click_normalized_box", args2));
|
|
2989
|
+
server.tool("browser_setup_downloads", "Enable browser downloads to project files directory", {
|
|
2990
|
+
browserIds: browserIdsArg,
|
|
2991
|
+
_scope: browserScopeArg
|
|
2992
|
+
}, (args2) => toolHandler("browser_setup_downloads", args2));
|
|
2993
|
+
server.tool("browser_list_downloads", "List files in project files directory", {}, () => toolHandler("browser_list_downloads", {}));
|
|
2994
|
+
server.tool("browser_parallel_upload_file", "Upload a file to an input element", {
|
|
2995
|
+
...browserTargetArgs,
|
|
2996
|
+
fileName: z.string()
|
|
2997
|
+
}, (args2) => toolHandler("browser_parallel_upload_file", args2));
|
|
2998
|
+
server.tool("browser_parallel_drag_drop_file", "Drag and drop a file onto an element", {
|
|
2999
|
+
...browserTargetArgs,
|
|
3000
|
+
fileName: z.string()
|
|
3001
|
+
}, (args2) => toolHandler("browser_parallel_drag_drop_file", args2));
|
|
3002
|
+
server.tool("browser_search_macros", "Search saved browser macros", {
|
|
3003
|
+
name: z.string(),
|
|
3004
|
+
_scope: browserScopeArg
|
|
3005
|
+
}, (args2) => toolHandler("browser_search_macros", args2));
|
|
3006
|
+
server.tool("browser_run_recorded_flow", "Run saved browser macro by ID", {
|
|
3007
|
+
macroId: z.string(),
|
|
3008
|
+
browserIds: browserIdsArg,
|
|
3009
|
+
_scope: browserScopeArg
|
|
3010
|
+
}, (args2) => toolHandler("browser_run_recorded_flow", args2));
|
|
3011
|
+
if (LINKEN_PORT !== void 0) registerSphereTools(server, "linken", "Linken Sphere");
|
|
3012
|
+
if (WADEX_PORT !== void 0) registerSphereTools(server, "wadex", "Wade X");
|
|
3013
|
+
if (DOLPHIN_PORT !== void 0 || DOLPHIN_API_TOKEN !== void 0) registerDolphinTools(server);
|
|
3014
|
+
if (VISION_TOKEN !== void 0) registerVisionTools(server);
|
|
3015
|
+
server.tool("browser_detect_captcha", "Detect captcha on page", {
|
|
3016
|
+
browserIds: browserIdsArg,
|
|
3017
|
+
_scope: browserScopeArg
|
|
3018
|
+
}, (args2) => toolHandler("browser_detect_captcha", args2));
|
|
3019
|
+
server.tool("browser_solve_press_hold", "Solve press-and-hold captcha", {
|
|
3020
|
+
browserIds: browserIdsArg,
|
|
3021
|
+
maxAttempts: z.number().optional(),
|
|
3022
|
+
holdMs: z.number().optional(),
|
|
3023
|
+
_scope: browserScopeArg
|
|
3024
|
+
}, (args2) => toolHandler("browser_solve_press_hold", args2));
|
|
3025
|
+
server.tool("browser_detect_press_hold", "Detect press-and-hold captcha", {
|
|
3026
|
+
browserIds: browserIdsArg,
|
|
3027
|
+
_scope: browserScopeArg
|
|
3028
|
+
}, (args2) => toolHandler("browser_detect_press_hold", args2));
|
|
3029
|
+
server.tool("browser_solve_captcha", "Solve captcha (reCAPTCHA/hCaptcha)", {
|
|
3030
|
+
browserIds: browserIdsArg,
|
|
3031
|
+
timeout: z.number().optional(),
|
|
3032
|
+
autoSubmit: z.boolean().optional(),
|
|
3033
|
+
_scope: browserScopeArg
|
|
3034
|
+
}, (args2) => toolHandler("browser_solve_captcha", args2));
|
|
3035
|
+
server.tool("browser_captcha_balance", "Check 2captcha balance", {}, () => toolHandler("browser_captcha_balance", {}));
|
|
2294
3036
|
server.tool("captcha_detect", "Detect captcha on page", {
|
|
2295
|
-
browserIds:
|
|
3037
|
+
browserIds: browserIdsArg
|
|
2296
3038
|
}, (args2) => toolHandler("captcha_detect", args2));
|
|
2297
3039
|
server.tool("captcha_solve_press_hold", "Solve press-and-hold captcha", {
|
|
2298
|
-
browserIds:
|
|
3040
|
+
browserIds: browserIdsArg
|
|
2299
3041
|
}, (args2) => toolHandler("captcha_solve_press_hold", args2));
|
|
2300
3042
|
server.tool("captcha_solve", "Solve captcha (reCAPTCHA/hCaptcha)", {
|
|
2301
|
-
browserIds:
|
|
3043
|
+
browserIds: browserIdsArg
|
|
2302
3044
|
}, (args2) => toolHandler("captcha_solve", args2));
|
|
2303
3045
|
return server;
|
|
2304
3046
|
}
|
|
2305
3047
|
async function main() {
|
|
2306
3048
|
await connectServer();
|
|
2307
|
-
|
|
3049
|
+
if (ENABLED_VENDORS.length === 0) {
|
|
3050
|
+
console.error("[ornold] No antidetect vendors configured. Only browser_* and captcha_* tools will be available.");
|
|
3051
|
+
}
|
|
3052
|
+
for (const [name, port, path2, headers] of [
|
|
3053
|
+
["linken", LINKEN_PORT, "/sessions", void 0],
|
|
3054
|
+
["wadex", WADEX_PORT, "/sessions", void 0],
|
|
3055
|
+
["dolphin", DOLPHIN_PORT, "/v1.0/browser_profiles", void 0],
|
|
3056
|
+
["vision", VISION_PORT, "/variations/language", VISION_TOKEN ? { "X-Token": VISION_TOKEN } : void 0]
|
|
3057
|
+
]) {
|
|
3058
|
+
if (port === void 0) continue;
|
|
2308
3059
|
try {
|
|
2309
|
-
const resp = await fetch(`http://127.0.0.1:${port}
|
|
3060
|
+
const resp = await fetch(`http://127.0.0.1:${port}${path2}`, { headers, signal: AbortSignal.timeout(2e3) });
|
|
2310
3061
|
if (resp.ok) console.error(`[ornold] ${name}: detected on port ${port}`);
|
|
2311
3062
|
} catch {
|
|
2312
3063
|
}
|
|
2313
3064
|
}
|
|
3065
|
+
if (DOLPHIN_API_TOKEN !== void 0) {
|
|
3066
|
+
console.error("[ornold] dolphin: cloud token configured");
|
|
3067
|
+
}
|
|
3068
|
+
if (VISION_TOKEN !== void 0) {
|
|
3069
|
+
console.error(`[ornold] vision: cloud token configured${VISION_PORT !== void 0 ? `, local port ${VISION_PORT}` : ""}`);
|
|
3070
|
+
}
|
|
2314
3071
|
ws?.send(JSON.stringify({
|
|
2315
3072
|
type: "bridge_hello",
|
|
2316
3073
|
hostname: (await import("os")).hostname(),
|
|
2317
|
-
config: {
|
|
3074
|
+
config: {
|
|
3075
|
+
enabledVendors: ENABLED_VENDORS,
|
|
3076
|
+
...LINKEN_PORT !== void 0 ? { linkenPort: LINKEN_PORT } : {},
|
|
3077
|
+
...WADEX_PORT !== void 0 ? { wadexPort: WADEX_PORT } : {},
|
|
3078
|
+
...DOLPHIN_PORT !== void 0 ? { dolphinPort: DOLPHIN_PORT } : {},
|
|
3079
|
+
...VISION_PORT !== void 0 ? { visionPort: VISION_PORT } : {},
|
|
3080
|
+
dolphinCloud: DOLPHIN_API_TOKEN !== void 0,
|
|
3081
|
+
dolphinLocal: DOLPHIN_PORT !== void 0,
|
|
3082
|
+
visionCloud: VISION_TOKEN !== void 0,
|
|
3083
|
+
visionLocal: VISION_TOKEN !== void 0 && VISION_PORT !== void 0
|
|
3084
|
+
}
|
|
2318
3085
|
}));
|
|
2319
3086
|
const server = createServer();
|
|
2320
3087
|
const transport = new StdioServerTransport();
|