@xbrowser/cli 1.24.2 → 1.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-LTLMDKWG.js → chunk-I4WCDFZR.js} +559 -487
- package/dist/{chunk-SUHS2EWV.js → chunk-SGALUO4Z.js} +559 -487
- package/dist/cli.js +2 -2
- package/dist/daemon-main.js +562 -490
- package/dist/index.js +2 -2
- package/dist/{server-A5R4OIGX.js → server-22WXTWK3.js} +1 -1
- package/dist/{server-Y5VVPRC6.js → server-L7IV24YL.js} +1 -1
- package/package.json +1 -1
|
@@ -63,8 +63,8 @@ function classifyFailure(message) {
|
|
|
63
63
|
|
|
64
64
|
// src/executor.ts
|
|
65
65
|
import {
|
|
66
|
-
ok as
|
|
67
|
-
fail as
|
|
66
|
+
ok as ok31,
|
|
67
|
+
fail as fail16,
|
|
68
68
|
isCommandResult,
|
|
69
69
|
CompositeStorage as CompositeStorage2,
|
|
70
70
|
TipCollector as TipCollector2,
|
|
@@ -1426,37 +1426,109 @@ var uaCommand = registerCommand({
|
|
|
1426
1426
|
}
|
|
1427
1427
|
});
|
|
1428
1428
|
|
|
1429
|
-
// src/commands/
|
|
1429
|
+
// src/commands/preflight.ts
|
|
1430
1430
|
import { z as z11 } from "zod";
|
|
1431
1431
|
import { ok as ok11, fail as fail4 } from "@dyyz1993/xcli-core";
|
|
1432
|
+
var preflightCommand = registerCommand({
|
|
1433
|
+
name: "preflight",
|
|
1434
|
+
description: "Pre-flight anti-bot gate: open local detection page and verify stealth posture before any automation task",
|
|
1435
|
+
scope: "page",
|
|
1436
|
+
parameters: z11.object({
|
|
1437
|
+
strict: z11.boolean().optional().describe("\u5931\u8D25\u65F6\u4EE5\u975E\u96F6\u9000\u51FA\u7801\u7ED3\u675F\uFF08\u94FE\u5F0F/CI \u95E8\u7981\u7528\uFF09"),
|
|
1438
|
+
publish: z11.boolean().optional().describe("\u53D1\u5E03\u7C7B\u4EFB\u52A1\u95E8\u7981\uFF1Aheadless \u73AF\u5883\u76F4\u63A5\u5224\u5931\u8D25\uFF08\u9ED8\u8BA4\u7531 XBROWSER_NO_HEADLESS_PUBLISH \u63A7\u5236\uFF09")
|
|
1439
|
+
}),
|
|
1440
|
+
result: z11.object({
|
|
1441
|
+
gate: z11.enum(["pass", "fail"]),
|
|
1442
|
+
failed: z11.array(z11.string()),
|
|
1443
|
+
headless: z11.boolean()
|
|
1444
|
+
}),
|
|
1445
|
+
handler: async (p, ctx) => {
|
|
1446
|
+
const page = ctx.page;
|
|
1447
|
+
const tips = [];
|
|
1448
|
+
const ua = await page.evaluate("navigator.userAgent").catch(() => "");
|
|
1449
|
+
const outerW = await page.evaluate("window.outerWidth").catch(() => 0);
|
|
1450
|
+
const headless = /headless/i.test(ua) || outerW === 0;
|
|
1451
|
+
const publishMode = p.publish || process.env.XBROWSER_NO_HEADLESS_PUBLISH === "1";
|
|
1452
|
+
if (publishMode && headless) {
|
|
1453
|
+
tips.push("\u53D1\u5E03\u7C7B\u4EFB\u52A1\u7981\u7528 headless\uFF08\u98CE\u63A7\u7EA2\u7EBF\uFF09\uFF1A\u63A5\u6709\u5934\u771F\u6D4F\u89C8\u5668\u540E\u91CD\u8BD5");
|
|
1454
|
+
tips.push(' \u6709\u5934 Chrome: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --user-data-dir=~/.xbrowser/chrome-profile-headed --remote-debugging-port=9222');
|
|
1455
|
+
tips.push(" \u7136\u540E\u52A0 --cdp http://localhost:9222");
|
|
1456
|
+
return fail4("PREFLIGHT-FAIL: headless \u4E0D\u5141\u8BB8\u7528\u4E8E\u53D1\u5E03\u7C7B\u4EFB\u52A1\uFF08\u7528 --cdp \u63A5\u6709\u5934 Chrome\uFF09", tips);
|
|
1457
|
+
}
|
|
1458
|
+
let pageUrl = null;
|
|
1459
|
+
try {
|
|
1460
|
+
const { fileURLToPath } = await import("url");
|
|
1461
|
+
const { join: join9, dirname: dirname4 } = await import("path");
|
|
1462
|
+
const { existsSync: existsSync7 } = await import("fs");
|
|
1463
|
+
const here = typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url);
|
|
1464
|
+
const candidates = [
|
|
1465
|
+
join9(dirname4(here), "..", "assets", "preflight.html"),
|
|
1466
|
+
join9(process.cwd(), "assets", "preflight.html")
|
|
1467
|
+
];
|
|
1468
|
+
pageUrl = candidates.find((c) => existsSync7(c)) || null;
|
|
1469
|
+
} catch {
|
|
1470
|
+
}
|
|
1471
|
+
if (pageUrl) {
|
|
1472
|
+
await page.goto("file://" + pageUrl, { waitUntil: "domcontentloaded", timeout: 15e3 });
|
|
1473
|
+
} else {
|
|
1474
|
+
await page.goto("about:blank");
|
|
1475
|
+
await page.evaluate(`(function(){
|
|
1476
|
+
var fails=[];
|
|
1477
|
+
if(navigator.webdriver!==false)fails.push('webdriver');
|
|
1478
|
+
if(/headless/i.test(navigator.userAgent))fails.push('ua-no-headless');
|
|
1479
|
+
window.__pf=fails.join(',');
|
|
1480
|
+
document.title=fails.length?'PREFLIGHT-FAIL':'PREFLIGHT-PASS';
|
|
1481
|
+
})()`);
|
|
1482
|
+
}
|
|
1483
|
+
await page.waitForTimeout(1200);
|
|
1484
|
+
const result = await page.evaluate(`(function(){
|
|
1485
|
+
var out=document.getElementById('out');
|
|
1486
|
+
return { title: document.title, fails: out ? (out.getAttribute('data-fails')||'') : (window.__pf||'') };
|
|
1487
|
+
})()`).catch(() => ({ title: "PREFLIGHT-FAIL", fails: "evaluate-error" }));
|
|
1488
|
+
const passed = result.title === "PREFLIGHT-PASS";
|
|
1489
|
+
const failed = result.fails ? result.fails.split(",").filter(Boolean) : [];
|
|
1490
|
+
tips.push(`headless=${headless}${publishMode ? "\uFF08publish \u95E8\u7981\u5F00\u542F\uFF09" : ""}`);
|
|
1491
|
+
if (passed) {
|
|
1492
|
+
tips.push("\u9884\u68C0\u901A\u8FC7\uFF1A\u53CD\u722C\u59FF\u6001\u5168\u90E8\u65AD\u8A00\u7EFF\u706F\uFF0C\u53EF\u6267\u884C\u81EA\u52A8\u5316\u4EFB\u52A1");
|
|
1493
|
+
return ok11({ gate: "pass", failed: [], headless }, tips);
|
|
1494
|
+
}
|
|
1495
|
+
tips.push(`\u5931\u8D25\u9879: ${failed.join(", ") || result.title}`);
|
|
1496
|
+
tips.push("\u4FEE\u590D\u6307\u5F15: headless \u73AF\u5883\u63A5\u6709\u5934 Chrome\uFF08--cdp\uFF09\uFF1Bwebdriver \u6CC4\u6F0F\u68C0\u67E5 stealth \u57AB\u7247\uFF08XBROWSER_STEALTH \u4E0D\u4E3A off\uFF09");
|
|
1497
|
+
return fail4(`PREFLIGHT-FAIL: ${failed.join(", ") || result.title}`, tips);
|
|
1498
|
+
}
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
// src/commands/storage.ts
|
|
1502
|
+
import { z as z12 } from "zod";
|
|
1503
|
+
import { ok as ok12, fail as fail5 } from "@dyyz1993/xcli-core";
|
|
1432
1504
|
var getCookiesCommand = registerCommand({
|
|
1433
1505
|
name: "get-cookies",
|
|
1434
1506
|
description: "Get all cookies for the current page",
|
|
1435
1507
|
scope: "page",
|
|
1436
|
-
result:
|
|
1437
|
-
cookies:
|
|
1508
|
+
result: z12.object({
|
|
1509
|
+
cookies: z12.array(z12.record(z12.unknown()))
|
|
1438
1510
|
}),
|
|
1439
1511
|
handler: async (_p, ctx) => {
|
|
1440
1512
|
const cookies = await ctx.browserContext.cookies();
|
|
1441
|
-
return
|
|
1513
|
+
return ok12({ cookies });
|
|
1442
1514
|
}
|
|
1443
1515
|
});
|
|
1444
1516
|
var setCookieCommand = registerCommand({
|
|
1445
1517
|
name: "set-cookie",
|
|
1446
1518
|
description: "Set a cookie",
|
|
1447
1519
|
scope: "page",
|
|
1448
|
-
parameters:
|
|
1449
|
-
name:
|
|
1450
|
-
value:
|
|
1451
|
-
domain:
|
|
1452
|
-
path:
|
|
1453
|
-
url:
|
|
1454
|
-
expires:
|
|
1455
|
-
httpOnly:
|
|
1456
|
-
secure:
|
|
1457
|
-
sameSite:
|
|
1520
|
+
parameters: z12.object({
|
|
1521
|
+
name: z12.coerce.string(),
|
|
1522
|
+
value: z12.coerce.string(),
|
|
1523
|
+
domain: z12.coerce.string().optional(),
|
|
1524
|
+
path: z12.coerce.string().optional(),
|
|
1525
|
+
url: z12.string().optional().describe("Cookie URL (alternative to domain)"),
|
|
1526
|
+
expires: z12.number().optional(),
|
|
1527
|
+
httpOnly: z12.boolean().optional(),
|
|
1528
|
+
secure: z12.boolean().optional(),
|
|
1529
|
+
sameSite: z12.enum(["Strict", "Lax", "None"]).optional()
|
|
1458
1530
|
}),
|
|
1459
|
-
result:
|
|
1531
|
+
result: z12.object({ name: z12.string() }),
|
|
1460
1532
|
handler: async (p, ctx) => {
|
|
1461
1533
|
const cookie = { ...p };
|
|
1462
1534
|
if (!cookie.domain && !cookie.url) {
|
|
@@ -1471,38 +1543,38 @@ var setCookieCommand = registerCommand({
|
|
|
1471
1543
|
}
|
|
1472
1544
|
}
|
|
1473
1545
|
if (!cookie.domain && !cookie.url) {
|
|
1474
|
-
return
|
|
1546
|
+
return fail5("set-cookie requires --domain or --url, or a non-blank page URL to infer from");
|
|
1475
1547
|
}
|
|
1476
1548
|
await ctx.browserContext.addCookies([cookie]);
|
|
1477
|
-
return
|
|
1549
|
+
return ok12({ name: p.name });
|
|
1478
1550
|
}
|
|
1479
1551
|
});
|
|
1480
1552
|
var clearCookiesCommand = registerCommand({
|
|
1481
1553
|
name: "clear-cookies",
|
|
1482
1554
|
description: "Clear all cookies",
|
|
1483
1555
|
scope: "page",
|
|
1484
|
-
result:
|
|
1556
|
+
result: z12.object({ cleared: z12.boolean() }),
|
|
1485
1557
|
handler: async (_p, ctx) => {
|
|
1486
1558
|
await ctx.browserContext.clearCookies();
|
|
1487
|
-
return
|
|
1559
|
+
return ok12({ cleared: true });
|
|
1488
1560
|
}
|
|
1489
1561
|
});
|
|
1490
1562
|
var getLocalStorageCommand = registerCommand({
|
|
1491
1563
|
name: "get-local-storage",
|
|
1492
1564
|
description: "Get localStorage entries",
|
|
1493
1565
|
scope: "page",
|
|
1494
|
-
parameters:
|
|
1495
|
-
key:
|
|
1566
|
+
parameters: z12.object({
|
|
1567
|
+
key: z12.string().optional()
|
|
1496
1568
|
}),
|
|
1497
|
-
result:
|
|
1498
|
-
|
|
1499
|
-
|
|
1569
|
+
result: z12.union([
|
|
1570
|
+
z12.object({ key: z12.string(), value: z12.string().nullable() }),
|
|
1571
|
+
z12.object({ data: z12.record(z12.string()) })
|
|
1500
1572
|
]),
|
|
1501
1573
|
handler: async (p, ctx) => {
|
|
1502
1574
|
try {
|
|
1503
1575
|
if (p.key) {
|
|
1504
1576
|
const value = await ctx.page.evaluate((k) => localStorage.getItem(k), p.key);
|
|
1505
|
-
return
|
|
1577
|
+
return ok12({ key: p.key, value });
|
|
1506
1578
|
}
|
|
1507
1579
|
const data = await ctx.page.evaluate(() => {
|
|
1508
1580
|
const entries = {};
|
|
@@ -1512,9 +1584,9 @@ var getLocalStorageCommand = registerCommand({
|
|
|
1512
1584
|
}
|
|
1513
1585
|
return entries;
|
|
1514
1586
|
});
|
|
1515
|
-
return
|
|
1587
|
+
return ok12({ data });
|
|
1516
1588
|
} catch (e) {
|
|
1517
|
-
return
|
|
1589
|
+
return fail5(`localStorage not accessible on this page: ${e instanceof Error ? e.message : String(e)}`);
|
|
1518
1590
|
}
|
|
1519
1591
|
}
|
|
1520
1592
|
});
|
|
@@ -1522,11 +1594,11 @@ var setLocalStorageCommand = registerCommand({
|
|
|
1522
1594
|
name: "set-local-storage",
|
|
1523
1595
|
description: "Set a localStorage entry",
|
|
1524
1596
|
scope: "page",
|
|
1525
|
-
parameters:
|
|
1526
|
-
key:
|
|
1527
|
-
value:
|
|
1597
|
+
parameters: z12.object({
|
|
1598
|
+
key: z12.string(),
|
|
1599
|
+
value: z12.string()
|
|
1528
1600
|
}),
|
|
1529
|
-
result:
|
|
1601
|
+
result: z12.object({ key: z12.string() }),
|
|
1530
1602
|
handler: async (p, ctx) => {
|
|
1531
1603
|
try {
|
|
1532
1604
|
await ctx.page.evaluate(
|
|
@@ -1535,9 +1607,9 @@ var setLocalStorageCommand = registerCommand({
|
|
|
1535
1607
|
},
|
|
1536
1608
|
{ key: p.key, value: p.value }
|
|
1537
1609
|
);
|
|
1538
|
-
return
|
|
1610
|
+
return ok12({ key: p.key });
|
|
1539
1611
|
} catch (e) {
|
|
1540
|
-
return
|
|
1612
|
+
return fail5(`localStorage not accessible on this page: ${e instanceof Error ? e.message : String(e)}`);
|
|
1541
1613
|
}
|
|
1542
1614
|
}
|
|
1543
1615
|
});
|
|
@@ -1545,20 +1617,20 @@ var clearLocalStorageCommand = registerCommand({
|
|
|
1545
1617
|
name: "clear-local-storage",
|
|
1546
1618
|
description: "Clear all localStorage entries",
|
|
1547
1619
|
scope: "page",
|
|
1548
|
-
result:
|
|
1620
|
+
result: z12.object({ cleared: z12.boolean() }),
|
|
1549
1621
|
handler: async (_p, ctx) => {
|
|
1550
1622
|
try {
|
|
1551
1623
|
await ctx.page.evaluate(() => localStorage.clear());
|
|
1552
|
-
return
|
|
1624
|
+
return ok12({ cleared: true });
|
|
1553
1625
|
} catch (e) {
|
|
1554
|
-
return
|
|
1626
|
+
return fail5(`localStorage not accessible on this page: ${e instanceof Error ? e.message : String(e)}`);
|
|
1555
1627
|
}
|
|
1556
1628
|
}
|
|
1557
1629
|
});
|
|
1558
1630
|
|
|
1559
1631
|
// src/commands/screenshot.ts
|
|
1560
|
-
import { z as
|
|
1561
|
-
import { ok as
|
|
1632
|
+
import { z as z13 } from "zod";
|
|
1633
|
+
import { ok as ok13, fail as fail6 } from "@dyyz1993/xcli-core";
|
|
1562
1634
|
import { writeFileSync, mkdirSync } from "fs";
|
|
1563
1635
|
import { dirname, join as join4 } from "path";
|
|
1564
1636
|
function ensureScreenshotsDir() {
|
|
@@ -1585,23 +1657,23 @@ var screenshotCommand = registerCommand({
|
|
|
1585
1657
|
description: "Take a screenshot of the page or element (auto-saved to the OS temp dir unless --output is given; persistent override: xbrowser config set screenshots.dir <path>)",
|
|
1586
1658
|
scope: "page",
|
|
1587
1659
|
selectorParams: ["selector"],
|
|
1588
|
-
parameters:
|
|
1589
|
-
selector:
|
|
1590
|
-
type:
|
|
1591
|
-
fullPage:
|
|
1592
|
-
output:
|
|
1593
|
-
base64:
|
|
1660
|
+
parameters: z13.object({
|
|
1661
|
+
selector: z13.string().optional(),
|
|
1662
|
+
type: z13.enum(["png", "jpeg"]).optional(),
|
|
1663
|
+
fullPage: z13.boolean().optional(),
|
|
1664
|
+
output: z13.string().optional(),
|
|
1665
|
+
base64: z13.boolean().optional().describe("Return base64 data instead of file path")
|
|
1594
1666
|
}),
|
|
1595
|
-
result:
|
|
1596
|
-
|
|
1597
|
-
data:
|
|
1598
|
-
format:
|
|
1599
|
-
size:
|
|
1667
|
+
result: z13.union([
|
|
1668
|
+
z13.object({
|
|
1669
|
+
data: z13.string(),
|
|
1670
|
+
format: z13.string(),
|
|
1671
|
+
size: z13.number()
|
|
1600
1672
|
}),
|
|
1601
|
-
|
|
1602
|
-
output:
|
|
1603
|
-
format:
|
|
1604
|
-
size:
|
|
1673
|
+
z13.object({
|
|
1674
|
+
output: z13.string(),
|
|
1675
|
+
format: z13.string(),
|
|
1676
|
+
size: z13.number()
|
|
1605
1677
|
})
|
|
1606
1678
|
]),
|
|
1607
1679
|
handler: async (p, ctx) => {
|
|
@@ -1619,21 +1691,21 @@ var screenshotCommand = registerCommand({
|
|
|
1619
1691
|
if (p.output) {
|
|
1620
1692
|
const dirErr = ensureParentDir(p.output);
|
|
1621
1693
|
if (dirErr) {
|
|
1622
|
-
return
|
|
1694
|
+
return fail6(`Cannot create directory for --output "${p.output}": ${dirErr}`);
|
|
1623
1695
|
}
|
|
1624
1696
|
try {
|
|
1625
1697
|
writeFileSync(p.output, buffer, "binary");
|
|
1626
1698
|
} catch (err) {
|
|
1627
|
-
return
|
|
1699
|
+
return fail6(`Failed to write screenshot to "${p.output}": ${err instanceof Error ? err.message : String(err)}`);
|
|
1628
1700
|
}
|
|
1629
|
-
return
|
|
1701
|
+
return ok13({
|
|
1630
1702
|
output: p.output,
|
|
1631
1703
|
format,
|
|
1632
1704
|
size: buffer.length
|
|
1633
1705
|
});
|
|
1634
1706
|
}
|
|
1635
1707
|
if (p.base64) {
|
|
1636
|
-
return
|
|
1708
|
+
return ok13({
|
|
1637
1709
|
data: buffer.toString("base64"),
|
|
1638
1710
|
format,
|
|
1639
1711
|
size: buffer.length
|
|
@@ -1642,7 +1714,7 @@ var screenshotCommand = registerCommand({
|
|
|
1642
1714
|
ensureScreenshotsDir();
|
|
1643
1715
|
const screenshotPath = generateScreenshotPath(format);
|
|
1644
1716
|
writeFileSync(screenshotPath, buffer, "binary");
|
|
1645
|
-
return
|
|
1717
|
+
return ok13({
|
|
1646
1718
|
output: screenshotPath,
|
|
1647
1719
|
format,
|
|
1648
1720
|
size: buffer.length
|
|
@@ -1651,19 +1723,19 @@ var screenshotCommand = registerCommand({
|
|
|
1651
1723
|
});
|
|
1652
1724
|
|
|
1653
1725
|
// src/commands/structure.ts
|
|
1654
|
-
import { z as
|
|
1655
|
-
import { ok as
|
|
1726
|
+
import { z as z14 } from "zod";
|
|
1727
|
+
import { ok as ok14 } from "@dyyz1993/xcli-core";
|
|
1656
1728
|
var structureCommand = registerCommand({
|
|
1657
1729
|
name: "structure",
|
|
1658
1730
|
description: "Get the DOM structure of the page or an element",
|
|
1659
1731
|
scope: "page",
|
|
1660
1732
|
selectorParams: ["selector"],
|
|
1661
|
-
parameters:
|
|
1662
|
-
selector:
|
|
1663
|
-
depth:
|
|
1733
|
+
parameters: z14.object({
|
|
1734
|
+
selector: z14.string().optional(),
|
|
1735
|
+
depth: z14.number().optional()
|
|
1664
1736
|
}),
|
|
1665
|
-
result:
|
|
1666
|
-
structure:
|
|
1737
|
+
result: z14.object({
|
|
1738
|
+
structure: z14.record(z14.unknown())
|
|
1667
1739
|
}),
|
|
1668
1740
|
handler: async (p, ctx) => {
|
|
1669
1741
|
const structure = await ctx.page.evaluate(
|
|
@@ -1695,30 +1767,30 @@ var structureCommand = registerCommand({
|
|
|
1695
1767
|
},
|
|
1696
1768
|
{ sel: p.selector || "body", maxDepth: p.depth || 5 }
|
|
1697
1769
|
);
|
|
1698
|
-
return
|
|
1770
|
+
return ok14({ structure });
|
|
1699
1771
|
}
|
|
1700
1772
|
});
|
|
1701
1773
|
|
|
1702
1774
|
// src/commands/viewport.ts
|
|
1703
|
-
import { z as
|
|
1704
|
-
import { ok as
|
|
1775
|
+
import { z as z15 } from "zod";
|
|
1776
|
+
import { ok as ok15 } from "@dyyz1993/xcli-core";
|
|
1705
1777
|
var setViewportCommand = registerCommand({
|
|
1706
1778
|
name: "set-viewport",
|
|
1707
1779
|
description: "Set the viewport size and properties",
|
|
1708
1780
|
scope: "browser",
|
|
1709
|
-
parameters:
|
|
1710
|
-
width:
|
|
1711
|
-
height:
|
|
1712
|
-
deviceScaleFactor:
|
|
1713
|
-
isMobile:
|
|
1714
|
-
hasTouch:
|
|
1781
|
+
parameters: z15.object({
|
|
1782
|
+
width: z15.coerce.number(),
|
|
1783
|
+
height: z15.coerce.number(),
|
|
1784
|
+
deviceScaleFactor: z15.coerce.number().optional(),
|
|
1785
|
+
isMobile: z15.boolean().optional(),
|
|
1786
|
+
hasTouch: z15.boolean().optional()
|
|
1715
1787
|
}),
|
|
1716
|
-
result:
|
|
1717
|
-
width:
|
|
1718
|
-
height:
|
|
1719
|
-
deviceScaleFactor:
|
|
1720
|
-
isMobile:
|
|
1721
|
-
hasTouch:
|
|
1788
|
+
result: z15.object({
|
|
1789
|
+
width: z15.number(),
|
|
1790
|
+
height: z15.number(),
|
|
1791
|
+
deviceScaleFactor: z15.number().optional(),
|
|
1792
|
+
isMobile: z15.boolean().optional(),
|
|
1793
|
+
hasTouch: z15.boolean().optional()
|
|
1722
1794
|
}),
|
|
1723
1795
|
handler: async (p, ctx) => {
|
|
1724
1796
|
const viewport = ctx.page.viewportSize();
|
|
@@ -1731,7 +1803,7 @@ var setViewportCommand = registerCommand({
|
|
|
1731
1803
|
...p.isMobile !== void 0 && { isMobile: p.isMobile },
|
|
1732
1804
|
...p.hasTouch !== void 0 && { hasTouch: p.hasTouch }
|
|
1733
1805
|
});
|
|
1734
|
-
return
|
|
1806
|
+
return ok15({
|
|
1735
1807
|
width,
|
|
1736
1808
|
height,
|
|
1737
1809
|
...p.deviceScaleFactor !== void 0 && { deviceScaleFactor: p.deviceScaleFactor },
|
|
@@ -1742,17 +1814,17 @@ var setViewportCommand = registerCommand({
|
|
|
1742
1814
|
});
|
|
1743
1815
|
|
|
1744
1816
|
// src/commands/frame.ts
|
|
1745
|
-
import { z as
|
|
1746
|
-
import { ok as
|
|
1817
|
+
import { z as z16 } from "zod";
|
|
1818
|
+
import { ok as ok16, fail as fail7 } from "@dyyz1993/xcli-core";
|
|
1747
1819
|
var framesCommand = registerCommand({
|
|
1748
1820
|
name: "frames",
|
|
1749
1821
|
description: "List all frames in the current page",
|
|
1750
1822
|
scope: "page",
|
|
1751
|
-
result:
|
|
1752
|
-
frames:
|
|
1753
|
-
index:
|
|
1754
|
-
name:
|
|
1755
|
-
url:
|
|
1823
|
+
result: z16.object({
|
|
1824
|
+
frames: z16.array(z16.object({
|
|
1825
|
+
index: z16.number(),
|
|
1826
|
+
name: z16.string().nullable(),
|
|
1827
|
+
url: z16.string()
|
|
1756
1828
|
}))
|
|
1757
1829
|
}),
|
|
1758
1830
|
handler: async (_p, ctx) => {
|
|
@@ -1763,21 +1835,21 @@ var framesCommand = registerCommand({
|
|
|
1763
1835
|
name: frame.name(),
|
|
1764
1836
|
url: frame.url()
|
|
1765
1837
|
}));
|
|
1766
|
-
return
|
|
1838
|
+
return ok16({ frames: frameList });
|
|
1767
1839
|
}
|
|
1768
1840
|
});
|
|
1769
1841
|
var frameCommand = registerCommand({
|
|
1770
1842
|
name: "frame",
|
|
1771
1843
|
description: "Get frame info by index or name",
|
|
1772
1844
|
scope: "page",
|
|
1773
|
-
parameters:
|
|
1774
|
-
index:
|
|
1775
|
-
name:
|
|
1845
|
+
parameters: z16.object({
|
|
1846
|
+
index: z16.number().int().min(0).optional(),
|
|
1847
|
+
name: z16.string().optional()
|
|
1776
1848
|
}),
|
|
1777
|
-
result:
|
|
1778
|
-
name:
|
|
1779
|
-
url:
|
|
1780
|
-
error:
|
|
1849
|
+
result: z16.object({
|
|
1850
|
+
name: z16.string().nullable(),
|
|
1851
|
+
url: z16.string(),
|
|
1852
|
+
error: z16.string().optional()
|
|
1781
1853
|
}),
|
|
1782
1854
|
handler: async (p, ctx) => {
|
|
1783
1855
|
const discover = ctx.page.discoverFrames;
|
|
@@ -1788,12 +1860,12 @@ var frameCommand = registerCommand({
|
|
|
1788
1860
|
} else if (p.name !== void 0) {
|
|
1789
1861
|
targetFrame = rawFrames.find((f) => f.name() === p.name);
|
|
1790
1862
|
} else {
|
|
1791
|
-
return
|
|
1863
|
+
return fail7("Must provide index or name");
|
|
1792
1864
|
}
|
|
1793
1865
|
if (!targetFrame) {
|
|
1794
|
-
return
|
|
1866
|
+
return fail7("Frame not found");
|
|
1795
1867
|
}
|
|
1796
|
-
return
|
|
1868
|
+
return ok16({
|
|
1797
1869
|
name: targetFrame.name(),
|
|
1798
1870
|
url: targetFrame.url()
|
|
1799
1871
|
});
|
|
@@ -1801,27 +1873,27 @@ var frameCommand = registerCommand({
|
|
|
1801
1873
|
});
|
|
1802
1874
|
|
|
1803
1875
|
// src/commands/ui-debug.ts
|
|
1804
|
-
import { z as
|
|
1805
|
-
import { ok as
|
|
1876
|
+
import { z as z17 } from "zod";
|
|
1877
|
+
import { ok as ok17 } from "@dyyz1993/xcli-core";
|
|
1806
1878
|
var consoleCheckCommand = registerCommand({
|
|
1807
1879
|
name: "console",
|
|
1808
1880
|
description: "Collect and analyze browser console messages (errors, warnings, logs)",
|
|
1809
1881
|
scope: "page",
|
|
1810
|
-
parameters:
|
|
1811
|
-
url:
|
|
1812
|
-
duration:
|
|
1813
|
-
filter:
|
|
1814
|
-
includeStackTraces:
|
|
1882
|
+
parameters: z17.object({
|
|
1883
|
+
url: z17.string().optional().describe("URL to navigate first (optional, uses current page if omitted)"),
|
|
1884
|
+
duration: z17.number().optional().default(5e3).describe("How long to collect messages (ms)"),
|
|
1885
|
+
filter: z17.enum(["all", "error", "warning", "info", "log"]).optional().default("all"),
|
|
1886
|
+
includeStackTraces: z17.boolean().optional().default(true)
|
|
1815
1887
|
}),
|
|
1816
|
-
result:
|
|
1817
|
-
url:
|
|
1818
|
-
duration:
|
|
1819
|
-
total:
|
|
1820
|
-
errors:
|
|
1821
|
-
warnings:
|
|
1822
|
-
messages:
|
|
1823
|
-
summary:
|
|
1824
|
-
passed:
|
|
1888
|
+
result: z17.object({
|
|
1889
|
+
url: z17.string(),
|
|
1890
|
+
duration: z17.number(),
|
|
1891
|
+
total: z17.number(),
|
|
1892
|
+
errors: z17.number(),
|
|
1893
|
+
warnings: z17.number(),
|
|
1894
|
+
messages: z17.array(z17.record(z17.unknown())),
|
|
1895
|
+
summary: z17.string(),
|
|
1896
|
+
passed: z17.boolean()
|
|
1825
1897
|
}),
|
|
1826
1898
|
handler: async (p, ctx) => {
|
|
1827
1899
|
const { page } = ctx;
|
|
@@ -1903,7 +1975,7 @@ ${a.stack || ""}`;
|
|
|
1903
1975
|
const filtered = p.filter === "all" ? messages : messages.filter((m) => m.type === p.filter);
|
|
1904
1976
|
const errorCount = messages.filter((m) => m.type === "error").length;
|
|
1905
1977
|
const warnCount = messages.filter((m) => m.type === "warning").length;
|
|
1906
|
-
return
|
|
1978
|
+
return ok17({
|
|
1907
1979
|
url: page.url(),
|
|
1908
1980
|
duration: p.duration,
|
|
1909
1981
|
total: messages.length,
|
|
@@ -1919,23 +1991,23 @@ var networkCheckCommand = registerCommand({
|
|
|
1919
1991
|
name: "net-debug",
|
|
1920
1992
|
description: "Monitor and analyze network requests \u2014 capture failed requests, slow responses, status codes",
|
|
1921
1993
|
scope: "page",
|
|
1922
|
-
parameters:
|
|
1923
|
-
url:
|
|
1924
|
-
duration:
|
|
1925
|
-
filter:
|
|
1926
|
-
slowThreshold:
|
|
1994
|
+
parameters: z17.object({
|
|
1995
|
+
url: z17.string().optional().describe("URL to navigate first"),
|
|
1996
|
+
duration: z17.number().optional().default(5e3).describe("How long to monitor (ms)"),
|
|
1997
|
+
filter: z17.enum(["all", "failed", "slow", "error", "xhr", "fetch", "document", "stylesheet", "script", "image"]).optional().default("all"),
|
|
1998
|
+
slowThreshold: z17.number().optional().default(3e3).describe('Threshold for "slow" requests (ms)')
|
|
1927
1999
|
}),
|
|
1928
|
-
result:
|
|
1929
|
-
url:
|
|
1930
|
-
duration:
|
|
1931
|
-
totalRequests:
|
|
1932
|
-
failedRequests:
|
|
1933
|
-
slowRequests:
|
|
1934
|
-
errorRequests:
|
|
1935
|
-
totalSizeKB:
|
|
1936
|
-
requests:
|
|
1937
|
-
summary:
|
|
1938
|
-
passed:
|
|
2000
|
+
result: z17.object({
|
|
2001
|
+
url: z17.string(),
|
|
2002
|
+
duration: z17.number(),
|
|
2003
|
+
totalRequests: z17.number(),
|
|
2004
|
+
failedRequests: z17.number(),
|
|
2005
|
+
slowRequests: z17.number(),
|
|
2006
|
+
errorRequests: z17.number(),
|
|
2007
|
+
totalSizeKB: z17.number(),
|
|
2008
|
+
requests: z17.array(z17.record(z17.unknown())),
|
|
2009
|
+
summary: z17.string(),
|
|
2010
|
+
passed: z17.boolean()
|
|
1939
2011
|
}),
|
|
1940
2012
|
handler: async (p, ctx) => {
|
|
1941
2013
|
const { page } = ctx;
|
|
@@ -2017,7 +2089,7 @@ var networkCheckCommand = registerCommand({
|
|
|
2017
2089
|
const slowCount = requests.filter((r) => r.duration >= p.slowThreshold).length;
|
|
2018
2090
|
const errorCount = requests.filter((r) => r.error).length;
|
|
2019
2091
|
const totalSize = requests.reduce((sum, r) => sum + r.size, 0);
|
|
2020
|
-
return
|
|
2092
|
+
return ok17({
|
|
2021
2093
|
url: page.url(),
|
|
2022
2094
|
duration: p.duration,
|
|
2023
2095
|
totalRequests: requests.length,
|
|
@@ -2039,17 +2111,17 @@ var perfCheckCommand = registerCommand({
|
|
|
2039
2111
|
name: "perf",
|
|
2040
2112
|
description: "Audit page performance metrics \u2014 load time, FCP, LCP, CLS, TTFB, resource sizes",
|
|
2041
2113
|
scope: "page",
|
|
2042
|
-
parameters:
|
|
2043
|
-
url:
|
|
2044
|
-
iterations:
|
|
2114
|
+
parameters: z17.object({
|
|
2115
|
+
url: z17.string().optional().describe("URL to navigate (uses current page if omitted)"),
|
|
2116
|
+
iterations: z17.number().optional().default(1).describe("Number of iterations to average")
|
|
2045
2117
|
}),
|
|
2046
|
-
result:
|
|
2047
|
-
url:
|
|
2048
|
-
iterations:
|
|
2049
|
-
metrics:
|
|
2050
|
-
allIterations:
|
|
2051
|
-
passed:
|
|
2052
|
-
summary:
|
|
2118
|
+
result: z17.object({
|
|
2119
|
+
url: z17.string(),
|
|
2120
|
+
iterations: z17.number(),
|
|
2121
|
+
metrics: z17.record(z17.unknown()),
|
|
2122
|
+
allIterations: z17.array(z17.record(z17.unknown())).optional(),
|
|
2123
|
+
passed: z17.boolean(),
|
|
2124
|
+
summary: z17.string()
|
|
2053
2125
|
}),
|
|
2054
2126
|
handler: async (p, ctx) => {
|
|
2055
2127
|
const { page } = ctx;
|
|
@@ -2111,7 +2183,7 @@ var perfCheckCommand = registerCommand({
|
|
|
2111
2183
|
if (resourceStats) avg.resourceStats = resourceStats;
|
|
2112
2184
|
return avg;
|
|
2113
2185
|
})();
|
|
2114
|
-
return
|
|
2186
|
+
return ok17({
|
|
2115
2187
|
url: page.url(),
|
|
2116
2188
|
iterations: p.iterations,
|
|
2117
2189
|
metrics: avgMetrics,
|
|
@@ -2125,23 +2197,23 @@ var healthCheckCommand = registerCommand({
|
|
|
2125
2197
|
name: "health",
|
|
2126
2198
|
description: "Comprehensive page health check \u2014 broken links, missing images, console errors, SEO issues",
|
|
2127
2199
|
scope: "page",
|
|
2128
|
-
parameters:
|
|
2129
|
-
url:
|
|
2130
|
-
checkLinks:
|
|
2131
|
-
checkImages:
|
|
2132
|
-
checkMeta:
|
|
2133
|
-
maxLinks:
|
|
2200
|
+
parameters: z17.object({
|
|
2201
|
+
url: z17.string().optional().describe("URL to check"),
|
|
2202
|
+
checkLinks: z17.boolean().optional().default(true).describe("Check for broken links"),
|
|
2203
|
+
checkImages: z17.boolean().optional().default(true).describe("Check for missing/broken images"),
|
|
2204
|
+
checkMeta: z17.boolean().optional().default(true).describe("Check SEO meta tags"),
|
|
2205
|
+
maxLinks: z17.number().optional().default(50).describe("Max links to check")
|
|
2134
2206
|
}),
|
|
2135
|
-
result:
|
|
2136
|
-
url:
|
|
2137
|
-
title:
|
|
2138
|
-
passed:
|
|
2139
|
-
totalIssues:
|
|
2140
|
-
errors:
|
|
2141
|
-
warnings:
|
|
2142
|
-
info:
|
|
2143
|
-
issues:
|
|
2144
|
-
summary:
|
|
2207
|
+
result: z17.object({
|
|
2208
|
+
url: z17.string(),
|
|
2209
|
+
title: z17.string(),
|
|
2210
|
+
passed: z17.boolean(),
|
|
2211
|
+
totalIssues: z17.number(),
|
|
2212
|
+
errors: z17.number(),
|
|
2213
|
+
warnings: z17.number(),
|
|
2214
|
+
info: z17.number(),
|
|
2215
|
+
issues: z17.array(z17.record(z17.unknown())),
|
|
2216
|
+
summary: z17.string()
|
|
2145
2217
|
}),
|
|
2146
2218
|
handler: async (p, ctx) => {
|
|
2147
2219
|
const { page } = ctx;
|
|
@@ -2228,7 +2300,7 @@ var healthCheckCommand = registerCommand({
|
|
|
2228
2300
|
}, { checkLinks: p.checkLinks, checkImages: p.checkImages, checkMeta: p.checkMeta, maxLinks: p.maxLinks });
|
|
2229
2301
|
const errors = result.issues.filter((i) => i.severity === "error").length;
|
|
2230
2302
|
const warnings = result.issues.filter((i) => i.severity === "warning").length;
|
|
2231
|
-
return
|
|
2303
|
+
return ok17({
|
|
2232
2304
|
url: result.url,
|
|
2233
2305
|
title: result.title,
|
|
2234
2306
|
passed: errors === 0,
|
|
@@ -2243,8 +2315,8 @@ var healthCheckCommand = registerCommand({
|
|
|
2243
2315
|
});
|
|
2244
2316
|
|
|
2245
2317
|
// src/commands/actions.ts
|
|
2246
|
-
import { z as
|
|
2247
|
-
import { ok as
|
|
2318
|
+
import { z as z18 } from "zod";
|
|
2319
|
+
import { ok as ok18 } from "@dyyz1993/xcli-core";
|
|
2248
2320
|
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
2249
2321
|
import { join as join5 } from "path";
|
|
2250
2322
|
function ensureScreenshotsDir2() {
|
|
@@ -2256,53 +2328,53 @@ function generateScreenshotPath2(format) {
|
|
|
2256
2328
|
const ext = format === "jpeg" ? "jpg" : "png";
|
|
2257
2329
|
return join5(resolveScreenshotsDir(), `screenshot-${timestamp}-${random}.${ext}`);
|
|
2258
2330
|
}
|
|
2259
|
-
var waitActionSchema =
|
|
2260
|
-
type:
|
|
2261
|
-
milliseconds:
|
|
2262
|
-
selector:
|
|
2331
|
+
var waitActionSchema = z18.object({
|
|
2332
|
+
type: z18.literal("wait"),
|
|
2333
|
+
milliseconds: z18.number().positive().optional(),
|
|
2334
|
+
selector: z18.string().optional()
|
|
2263
2335
|
}).refine(
|
|
2264
2336
|
(d) => (d.milliseconds !== void 0 || d.selector !== void 0) && !(d.milliseconds !== void 0 && d.selector !== void 0),
|
|
2265
2337
|
{ message: "Either 'milliseconds' or 'selector' must be provided, but not both." }
|
|
2266
2338
|
);
|
|
2267
|
-
var clickActionSchema =
|
|
2268
|
-
type:
|
|
2269
|
-
selector:
|
|
2270
|
-
all:
|
|
2339
|
+
var clickActionSchema = z18.object({
|
|
2340
|
+
type: z18.literal("click"),
|
|
2341
|
+
selector: z18.string(),
|
|
2342
|
+
all: z18.boolean().optional()
|
|
2271
2343
|
});
|
|
2272
|
-
var screenshotActionSchema =
|
|
2273
|
-
type:
|
|
2274
|
-
fullPage:
|
|
2275
|
-
quality:
|
|
2276
|
-
viewport:
|
|
2277
|
-
base64:
|
|
2344
|
+
var screenshotActionSchema = z18.object({
|
|
2345
|
+
type: z18.literal("screenshot"),
|
|
2346
|
+
fullPage: z18.boolean().optional(),
|
|
2347
|
+
quality: z18.number().min(1).max(100).optional(),
|
|
2348
|
+
viewport: z18.object({ width: z18.number().int().positive(), height: z18.number().int().positive() }).optional(),
|
|
2349
|
+
base64: z18.boolean().optional().describe("Return base64 data instead of file path")
|
|
2278
2350
|
});
|
|
2279
|
-
var writeActionSchema =
|
|
2280
|
-
type:
|
|
2281
|
-
text:
|
|
2351
|
+
var writeActionSchema = z18.object({
|
|
2352
|
+
type: z18.literal("write"),
|
|
2353
|
+
text: z18.string()
|
|
2282
2354
|
});
|
|
2283
|
-
var pressActionSchema =
|
|
2284
|
-
type:
|
|
2285
|
-
key:
|
|
2355
|
+
var pressActionSchema = z18.object({
|
|
2356
|
+
type: z18.literal("press"),
|
|
2357
|
+
key: z18.string()
|
|
2286
2358
|
});
|
|
2287
|
-
var scrollActionSchema =
|
|
2288
|
-
type:
|
|
2289
|
-
direction:
|
|
2290
|
-
selector:
|
|
2359
|
+
var scrollActionSchema = z18.object({
|
|
2360
|
+
type: z18.literal("scroll"),
|
|
2361
|
+
direction: z18.enum(["up", "down"]).optional(),
|
|
2362
|
+
selector: z18.string().optional()
|
|
2291
2363
|
});
|
|
2292
|
-
var scrapeActionSchema =
|
|
2293
|
-
type:
|
|
2364
|
+
var scrapeActionSchema = z18.object({
|
|
2365
|
+
type: z18.literal("scrape")
|
|
2294
2366
|
});
|
|
2295
|
-
var executeJavascriptActionSchema =
|
|
2296
|
-
type:
|
|
2297
|
-
script:
|
|
2367
|
+
var executeJavascriptActionSchema = z18.object({
|
|
2368
|
+
type: z18.literal("executeJavascript"),
|
|
2369
|
+
script: z18.string()
|
|
2298
2370
|
});
|
|
2299
|
-
var pdfActionSchema =
|
|
2300
|
-
type:
|
|
2301
|
-
landscape:
|
|
2302
|
-
scale:
|
|
2303
|
-
format:
|
|
2371
|
+
var pdfActionSchema = z18.object({
|
|
2372
|
+
type: z18.literal("pdf"),
|
|
2373
|
+
landscape: z18.boolean().optional(),
|
|
2374
|
+
scale: z18.number().optional(),
|
|
2375
|
+
format: z18.enum(["A0", "A1", "A2", "A3", "A4", "A5", "A6", "Letter", "Legal", "Tabloid", "Ledger"]).optional()
|
|
2304
2376
|
});
|
|
2305
|
-
var actionSchema =
|
|
2377
|
+
var actionSchema = z18.union([
|
|
2306
2378
|
waitActionSchema,
|
|
2307
2379
|
clickActionSchema,
|
|
2308
2380
|
screenshotActionSchema,
|
|
@@ -2393,11 +2465,11 @@ var actionsCommand = registerCommand({
|
|
|
2393
2465
|
name: "actions",
|
|
2394
2466
|
description: "Execute a sequence of actions (wait, click, scroll, screenshot, fill, etc.)",
|
|
2395
2467
|
scope: "page",
|
|
2396
|
-
parameters:
|
|
2397
|
-
url:
|
|
2398
|
-
actions:
|
|
2399
|
-
output:
|
|
2400
|
-
timeout:
|
|
2468
|
+
parameters: z18.object({
|
|
2469
|
+
url: z18.string().describe("Starting URL"),
|
|
2470
|
+
actions: z18.array(actionSchema).max(MAX_ACTIONS).describe("Array of actions (max 50)"),
|
|
2471
|
+
output: z18.enum(["text", "json"]).default("json").describe("Output format: text or json"),
|
|
2472
|
+
timeout: z18.number().default(60).describe("Overall timeout in seconds (default: 60)")
|
|
2401
2473
|
}),
|
|
2402
2474
|
handler: async (p, ctx) => {
|
|
2403
2475
|
await ctx.page.goto(p.url, { waitUntil: "domcontentloaded" });
|
|
@@ -2417,14 +2489,14 @@ var actionsCommand = registerCommand({
|
|
|
2417
2489
|
const finalUrl = ctx.page.url();
|
|
2418
2490
|
const timedOut = results.length < p.actions.length;
|
|
2419
2491
|
if (p.output === "text") {
|
|
2420
|
-
return
|
|
2492
|
+
return ok18({
|
|
2421
2493
|
title,
|
|
2422
2494
|
url: finalUrl,
|
|
2423
2495
|
actions: results.map((r) => JSON.stringify(r)).join("\n"),
|
|
2424
2496
|
...timedOut ? { warning: `Timed out after ${p.timeout}s, completed ${results.length}/${p.actions.length} actions` } : {}
|
|
2425
2497
|
});
|
|
2426
2498
|
}
|
|
2427
|
-
return
|
|
2499
|
+
return ok18({
|
|
2428
2500
|
title,
|
|
2429
2501
|
url: finalUrl,
|
|
2430
2502
|
results,
|
|
@@ -2434,8 +2506,8 @@ var actionsCommand = registerCommand({
|
|
|
2434
2506
|
});
|
|
2435
2507
|
|
|
2436
2508
|
// src/commands/scrape.ts
|
|
2437
|
-
import { z as
|
|
2438
|
-
import { ok as
|
|
2509
|
+
import { z as z19 } from "zod";
|
|
2510
|
+
import { ok as ok19, fail as fail8 } from "@dyyz1993/xcli-core";
|
|
2439
2511
|
|
|
2440
2512
|
// src/lib/html-to-markdown.ts
|
|
2441
2513
|
import * as cheerio from "cheerio";
|
|
@@ -2820,15 +2892,15 @@ var scrapeCommand = registerCommand({
|
|
|
2820
2892
|
description: "Scrape a page and convert to Markdown (with JS rendering)",
|
|
2821
2893
|
scope: "project",
|
|
2822
2894
|
selectorParams: ["selector"],
|
|
2823
|
-
parameters:
|
|
2824
|
-
url:
|
|
2825
|
-
selector:
|
|
2826
|
-
timeout:
|
|
2827
|
-
format:
|
|
2828
|
-
onlyMainContent:
|
|
2829
|
-
retries:
|
|
2830
|
-
waitAfterLoad:
|
|
2831
|
-
mode:
|
|
2895
|
+
parameters: z19.object({
|
|
2896
|
+
url: z19.string().optional(),
|
|
2897
|
+
selector: z19.string().optional(),
|
|
2898
|
+
timeout: z19.number().default(3e4),
|
|
2899
|
+
format: z19.enum(["markdown", "html", "text"]).default("markdown"),
|
|
2900
|
+
onlyMainContent: z19.boolean().default(true),
|
|
2901
|
+
retries: z19.number().int().min(0).max(5).optional().default(2).describe("\u91CD\u8BD5\u6B21\u6570\uFF08\u9ED8\u8BA4 2\uFF09"),
|
|
2902
|
+
waitAfterLoad: z19.number().int().optional().default(0).describe("\u9875\u9762\u52A0\u8F7D\u540E\u989D\u5916\u7B49\u5F85\u6BEB\u79D2"),
|
|
2903
|
+
mode: z19.enum(["raw", "clean", "compact", "smart"]).default("raw").describe("\u8F93\u51FA\u6A21\u5F0F\uFF1Araw\uFF08\u9ED8\u8BA4\uFF09/ clean\uFF08\u7ED3\u6784\u5316\uFF09/ compact\uFF08\u7CBE\u7B80\uFF09/ smart\uFF08\u7ED3\u6784\u5316\uFF0C\u7559\u7ED9 agent \u589E\u5F3A\uFF09")
|
|
2832
2904
|
}),
|
|
2833
2905
|
handler: async (p, ctx) => {
|
|
2834
2906
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
@@ -2836,7 +2908,7 @@ var scrapeCommand = registerCommand({
|
|
|
2836
2908
|
try {
|
|
2837
2909
|
const targetUrl = p.url || page.url();
|
|
2838
2910
|
if (!targetUrl || targetUrl === "about:blank") {
|
|
2839
|
-
return
|
|
2911
|
+
return fail8("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2840
2912
|
}
|
|
2841
2913
|
let lastError;
|
|
2842
2914
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
@@ -2906,7 +2978,7 @@ var scrapeCommand = registerCommand({
|
|
|
2906
2978
|
} catch {
|
|
2907
2979
|
}
|
|
2908
2980
|
if (p.mode === "smart") {
|
|
2909
|
-
return
|
|
2981
|
+
return ok19(structured);
|
|
2910
2982
|
}
|
|
2911
2983
|
if (p.mode === "compact") {
|
|
2912
2984
|
const compactData = structured.tables.length > 0 ? structured.tables.map((t) => ({
|
|
@@ -2919,9 +2991,9 @@ var scrapeCommand = registerCommand({
|
|
|
2919
2991
|
return compact;
|
|
2920
2992
|
})
|
|
2921
2993
|
})) : structured.mainText?.substring(0, 500);
|
|
2922
|
-
return
|
|
2994
|
+
return ok19({ url: structured.url, title: structured.title, data: compactData });
|
|
2923
2995
|
}
|
|
2924
|
-
return
|
|
2996
|
+
return ok19(structured);
|
|
2925
2997
|
}
|
|
2926
2998
|
let content;
|
|
2927
2999
|
switch (p.format) {
|
|
@@ -2980,7 +3052,7 @@ var scrapeCommand = registerCommand({
|
|
|
2980
3052
|
content = await page.innerText("body");
|
|
2981
3053
|
break;
|
|
2982
3054
|
}
|
|
2983
|
-
return
|
|
3055
|
+
return ok19({ content, title, url: finalUrl });
|
|
2984
3056
|
} catch (err) {
|
|
2985
3057
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
2986
3058
|
if (attempt < maxAttempts) {
|
|
@@ -2990,20 +3062,20 @@ var scrapeCommand = registerCommand({
|
|
|
2990
3062
|
}
|
|
2991
3063
|
}
|
|
2992
3064
|
}
|
|
2993
|
-
return
|
|
3065
|
+
return fail8(`Scrape failed after ${maxAttempts} attempt(s): ${lastError?.message ?? "unknown error"}`);
|
|
2994
3066
|
} finally {
|
|
2995
3067
|
await closeEphemeralContext(context);
|
|
2996
3068
|
}
|
|
2997
3069
|
},
|
|
2998
|
-
result:
|
|
2999
|
-
url:
|
|
3000
|
-
title:
|
|
3070
|
+
result: z19.object({
|
|
3071
|
+
url: z19.string(),
|
|
3072
|
+
title: z19.string()
|
|
3001
3073
|
}).passthrough()
|
|
3002
3074
|
});
|
|
3003
3075
|
|
|
3004
3076
|
// src/commands/map.ts
|
|
3005
|
-
import { z as
|
|
3006
|
-
import { ok as
|
|
3077
|
+
import { z as z20 } from "zod";
|
|
3078
|
+
import { ok as ok20, fail as fail9 } from "@dyyz1993/xcli-core";
|
|
3007
3079
|
|
|
3008
3080
|
// src/utils/url.ts
|
|
3009
3081
|
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -3238,21 +3310,21 @@ var mapCommand = registerCommand({
|
|
|
3238
3310
|
name: "map",
|
|
3239
3311
|
description: "Discover all URLs on a website via sitemap and page link extraction",
|
|
3240
3312
|
scope: "project",
|
|
3241
|
-
parameters:
|
|
3242
|
-
url:
|
|
3243
|
-
search:
|
|
3244
|
-
sitemap:
|
|
3245
|
-
includeSubdomains:
|
|
3246
|
-
allowExternalLinks:
|
|
3247
|
-
limit:
|
|
3248
|
-
verbose:
|
|
3313
|
+
parameters: z20.object({
|
|
3314
|
+
url: z20.string().optional(),
|
|
3315
|
+
search: z20.string().optional(),
|
|
3316
|
+
sitemap: z20.enum(["include", "only"]).optional(),
|
|
3317
|
+
includeSubdomains: z20.boolean().optional(),
|
|
3318
|
+
allowExternalLinks: z20.boolean().optional().describe("Include links to external domains"),
|
|
3319
|
+
limit: z20.number().optional(),
|
|
3320
|
+
verbose: z20.boolean().default(false).describe("Show progress feedback")
|
|
3249
3321
|
}),
|
|
3250
3322
|
handler: async (p, ctx) => {
|
|
3251
3323
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
3252
3324
|
try {
|
|
3253
3325
|
const targetUrl = p.url || page.url();
|
|
3254
3326
|
if (!targetUrl || targetUrl === "about:blank") {
|
|
3255
|
-
return
|
|
3327
|
+
return fail9("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
3256
3328
|
}
|
|
3257
3329
|
const links = await discoverUrls(page, targetUrl, {
|
|
3258
3330
|
sitemap: p.sitemap,
|
|
@@ -3263,7 +3335,7 @@ var mapCommand = registerCommand({
|
|
|
3263
3335
|
verbose: p.verbose
|
|
3264
3336
|
});
|
|
3265
3337
|
const linkObjects = links.map((url) => ({ url }));
|
|
3266
|
-
return
|
|
3338
|
+
return ok20({
|
|
3267
3339
|
links: linkObjects,
|
|
3268
3340
|
success: true
|
|
3269
3341
|
});
|
|
@@ -3271,15 +3343,15 @@ var mapCommand = registerCommand({
|
|
|
3271
3343
|
await closeEphemeralContext(context);
|
|
3272
3344
|
}
|
|
3273
3345
|
},
|
|
3274
|
-
result:
|
|
3275
|
-
links:
|
|
3276
|
-
success:
|
|
3346
|
+
result: z20.object({
|
|
3347
|
+
links: z20.array(z20.object({ url: z20.string() })),
|
|
3348
|
+
success: z20.boolean()
|
|
3277
3349
|
})
|
|
3278
3350
|
});
|
|
3279
3351
|
|
|
3280
3352
|
// src/commands/crawl.ts
|
|
3281
|
-
import { z as
|
|
3282
|
-
import { ok as
|
|
3353
|
+
import { z as z21 } from "zod";
|
|
3354
|
+
import { ok as ok21 } from "@dyyz1993/xcli-core";
|
|
3283
3355
|
function stripHashAnchorQuery(url) {
|
|
3284
3356
|
try {
|
|
3285
3357
|
const parsed = new URL(url);
|
|
@@ -3456,21 +3528,21 @@ var crawlCommand = registerCommand({
|
|
|
3456
3528
|
name: "crawl",
|
|
3457
3529
|
description: "Crawl a website and extract content from all pages",
|
|
3458
3530
|
scope: "project",
|
|
3459
|
-
parameters:
|
|
3460
|
-
url:
|
|
3461
|
-
limit:
|
|
3462
|
-
maxDepth:
|
|
3463
|
-
includePaths:
|
|
3464
|
-
excludePaths:
|
|
3465
|
-
allowSubdomains:
|
|
3466
|
-
allowExternalLinks:
|
|
3467
|
-
allowBackwardCrawling:
|
|
3468
|
-
enableSpa:
|
|
3469
|
-
format:
|
|
3470
|
-
onlyMainContent:
|
|
3471
|
-
concurrency:
|
|
3472
|
-
retries:
|
|
3473
|
-
verbose:
|
|
3531
|
+
parameters: z21.object({
|
|
3532
|
+
url: z21.string(),
|
|
3533
|
+
limit: z21.number().default(10),
|
|
3534
|
+
maxDepth: z21.number().default(3),
|
|
3535
|
+
includePaths: z21.array(z21.string()).optional(),
|
|
3536
|
+
excludePaths: z21.array(z21.string()).optional(),
|
|
3537
|
+
allowSubdomains: z21.boolean().default(false),
|
|
3538
|
+
allowExternalLinks: z21.boolean().default(false),
|
|
3539
|
+
allowBackwardCrawling: z21.boolean().default(false),
|
|
3540
|
+
enableSpa: z21.boolean().default(true).describe("Disable to skip SPA route detection"),
|
|
3541
|
+
format: z21.enum(["markdown", "html"]).default("markdown"),
|
|
3542
|
+
onlyMainContent: z21.boolean().default(true),
|
|
3543
|
+
concurrency: z21.number().default(3),
|
|
3544
|
+
retries: z21.number().default(2),
|
|
3545
|
+
verbose: z21.boolean().default(false)
|
|
3474
3546
|
}),
|
|
3475
3547
|
handler: async (p, ctx) => {
|
|
3476
3548
|
const startUrl = new URL(p.url);
|
|
@@ -3609,7 +3681,7 @@ var crawlCommand = registerCommand({
|
|
|
3609
3681
|
if (errorPages.length > 0) {
|
|
3610
3682
|
response.errors = errorPages;
|
|
3611
3683
|
}
|
|
3612
|
-
return
|
|
3684
|
+
return ok21(response);
|
|
3613
3685
|
} finally {
|
|
3614
3686
|
for (const ctx2 of contexts) {
|
|
3615
3687
|
await ctx2.close().catch(() => {
|
|
@@ -3619,15 +3691,15 @@ var crawlCommand = registerCommand({
|
|
|
3619
3691
|
} catch (err) {
|
|
3620
3692
|
const message = err instanceof Error ? err.message : String(err);
|
|
3621
3693
|
const successPages = results.filter((r) => !isPageError(r));
|
|
3622
|
-
return
|
|
3694
|
+
return ok21({ pages: successPages, total: successPages.length, success: false, error: message });
|
|
3623
3695
|
}
|
|
3624
3696
|
}
|
|
3625
3697
|
});
|
|
3626
3698
|
|
|
3627
3699
|
// src/commands/search.ts
|
|
3628
|
-
import { z as
|
|
3700
|
+
import { z as z22 } from "zod";
|
|
3629
3701
|
import * as cheerio2 from "cheerio";
|
|
3630
|
-
import { ok as
|
|
3702
|
+
import { ok as ok22 } from "@dyyz1993/xcli-core";
|
|
3631
3703
|
function getRecencyParams(recency) {
|
|
3632
3704
|
const now = Math.floor(Date.now() / 1e3);
|
|
3633
3705
|
switch (recency) {
|
|
@@ -3961,16 +4033,16 @@ var searchCommand = registerCommand({
|
|
|
3961
4033
|
name: "search",
|
|
3962
4034
|
description: "Search the web and extract results with engine fallback",
|
|
3963
4035
|
scope: "project",
|
|
3964
|
-
parameters:
|
|
3965
|
-
query:
|
|
3966
|
-
engine:
|
|
3967
|
-
limit:
|
|
3968
|
-
full:
|
|
3969
|
-
format:
|
|
3970
|
-
timeout:
|
|
3971
|
-
recency:
|
|
3972
|
-
fallback:
|
|
3973
|
-
site:
|
|
4036
|
+
parameters: z22.object({
|
|
4037
|
+
query: z22.string(),
|
|
4038
|
+
engine: z22.string().optional(),
|
|
4039
|
+
limit: z22.number().default(10),
|
|
4040
|
+
full: z22.boolean().default(false),
|
|
4041
|
+
format: z22.enum(["markdown", "json", "text"]).default("markdown"),
|
|
4042
|
+
timeout: z22.number().default(15e3),
|
|
4043
|
+
recency: z22.enum(["hour", "day", "week", "month", "year"]).optional().describe("Filter by time: hour/day/week/month/year"),
|
|
4044
|
+
fallback: z22.boolean().default(false).describe("Sequential engine fallback instead of parallel"),
|
|
4045
|
+
site: z22.string().optional().describe("Limit results to a specific site (e.g. github.com, v2ex.com)")
|
|
3974
4046
|
}),
|
|
3975
4047
|
handler: async (p, ctx) => {
|
|
3976
4048
|
const { context } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
@@ -4076,7 +4148,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
4076
4148
|
lines.push(`> ${r.snippet}`);
|
|
4077
4149
|
lines.push("");
|
|
4078
4150
|
}
|
|
4079
|
-
return
|
|
4151
|
+
return ok22({ ...searchResult, content: lines.join("\n") });
|
|
4080
4152
|
}
|
|
4081
4153
|
if (p.format === "text") {
|
|
4082
4154
|
const lines = [`Search: ${searchResult.query} (Engine: ${searchResult.engine}, Total: ${searchResult.total})`, ""];
|
|
@@ -4086,9 +4158,9 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
4086
4158
|
lines.push(` ${r.snippet}`);
|
|
4087
4159
|
lines.push("");
|
|
4088
4160
|
}
|
|
4089
|
-
return
|
|
4161
|
+
return ok22({ ...searchResult, content: lines.join("\n") });
|
|
4090
4162
|
}
|
|
4091
|
-
return
|
|
4163
|
+
return ok22(searchResult);
|
|
4092
4164
|
} finally {
|
|
4093
4165
|
await closeEphemeralContext(context);
|
|
4094
4166
|
}
|
|
@@ -4096,8 +4168,8 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
4096
4168
|
});
|
|
4097
4169
|
|
|
4098
4170
|
// src/commands/network.ts
|
|
4099
|
-
import { z as
|
|
4100
|
-
import { ok as
|
|
4171
|
+
import { z as z23 } from "zod";
|
|
4172
|
+
import { ok as ok23, fail as fail10 } from "@dyyz1993/xcli-core";
|
|
4101
4173
|
function extractPath2(url) {
|
|
4102
4174
|
try {
|
|
4103
4175
|
const u = new URL(url);
|
|
@@ -4195,19 +4267,19 @@ var networkCommand = registerCommand({
|
|
|
4195
4267
|
name: "network",
|
|
4196
4268
|
description: "Capture and filter network responses from a URL",
|
|
4197
4269
|
scope: "project",
|
|
4198
|
-
parameters:
|
|
4199
|
-
url:
|
|
4200
|
-
filter:
|
|
4201
|
-
match:
|
|
4202
|
-
search:
|
|
4203
|
-
console:
|
|
4204
|
-
timeout:
|
|
4205
|
-
wait:
|
|
4206
|
-
limit:
|
|
4207
|
-
format:
|
|
4208
|
-
ws:
|
|
4209
|
-
listen:
|
|
4210
|
-
duration:
|
|
4270
|
+
parameters: z23.object({
|
|
4271
|
+
url: z23.string(),
|
|
4272
|
+
filter: z23.string().optional(),
|
|
4273
|
+
match: z23.string().optional(),
|
|
4274
|
+
search: z23.string().optional().describe("Search within all captured response bodies"),
|
|
4275
|
+
console: z23.boolean().default(false),
|
|
4276
|
+
timeout: z23.number().default(3e4),
|
|
4277
|
+
wait: z23.number().default(3e3),
|
|
4278
|
+
limit: z23.number().default(50),
|
|
4279
|
+
format: z23.enum(["summary", "json"]).default("summary"),
|
|
4280
|
+
ws: z23.boolean().optional().default(false).describe("Only show WebSocket messages"),
|
|
4281
|
+
listen: z23.boolean().optional().default(false).describe("\u76D1\u542C\u6A21\u5F0F\uFF1A\u4F7F\u7528\u73B0\u6709 session \u7684 page\uFF0C\u7B49\u5F85\u6307\u5B9A\u65F6\u95F4\u6355\u83B7\u8BF7\u6C42"),
|
|
4282
|
+
duration: z23.number().int().optional().default(15e3).describe("\u76D1\u542C\u6A21\u5F0F\u7B49\u5F85\u65F6\u957F\uFF08\u6BEB\u79D2\uFF0C\u9ED8\u8BA4 15000\uFF09")
|
|
4211
4283
|
}),
|
|
4212
4284
|
handler: async (p, ctx) => {
|
|
4213
4285
|
const startTime = Date.now();
|
|
@@ -4262,7 +4334,7 @@ var networkCommand = registerCommand({
|
|
|
4262
4334
|
};
|
|
4263
4335
|
if (p.listen) {
|
|
4264
4336
|
const page2 = ctx.page;
|
|
4265
|
-
if (!page2) return
|
|
4337
|
+
if (!page2) return fail10("No active page. Use --cdp to connect first.");
|
|
4266
4338
|
const captures = [];
|
|
4267
4339
|
const consoleMessages = [];
|
|
4268
4340
|
const wsCaptures = [];
|
|
@@ -4289,7 +4361,7 @@ var networkCommand = registerCommand({
|
|
|
4289
4361
|
page2.off("response", handler);
|
|
4290
4362
|
const duration = Date.now() - startTime;
|
|
4291
4363
|
if (p.ws && wsCaptures.length > 0) {
|
|
4292
|
-
return
|
|
4364
|
+
return ok23({
|
|
4293
4365
|
url: "[listen mode]",
|
|
4294
4366
|
duration,
|
|
4295
4367
|
total: captures.length,
|
|
@@ -4303,9 +4375,9 @@ var networkCommand = registerCommand({
|
|
|
4303
4375
|
});
|
|
4304
4376
|
}
|
|
4305
4377
|
if (p.format === "json") {
|
|
4306
|
-
return
|
|
4378
|
+
return ok23(buildJsonOutput("[listen mode]", captures, consoleMessages, captures.length, wsCaptures));
|
|
4307
4379
|
}
|
|
4308
|
-
return
|
|
4380
|
+
return ok23(buildSummaryOutput("[listen mode]", duration, captures, consoleMessages, captures.length, wsCaptures));
|
|
4309
4381
|
}
|
|
4310
4382
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
4311
4383
|
try {
|
|
@@ -4360,7 +4432,7 @@ var networkCommand = registerCommand({
|
|
|
4360
4432
|
}
|
|
4361
4433
|
const duration = Date.now() - startTime;
|
|
4362
4434
|
if (p.ws && wsCaptures.length > 0) {
|
|
4363
|
-
return
|
|
4435
|
+
return ok23({
|
|
4364
4436
|
url: p.url,
|
|
4365
4437
|
duration,
|
|
4366
4438
|
total: captures.length,
|
|
@@ -4374,9 +4446,9 @@ var networkCommand = registerCommand({
|
|
|
4374
4446
|
});
|
|
4375
4447
|
}
|
|
4376
4448
|
if (p.format === "json") {
|
|
4377
|
-
return
|
|
4449
|
+
return ok23(buildJsonOutput(p.url, results, consoleMessages, totalCount, wsCaptures, searchResults));
|
|
4378
4450
|
}
|
|
4379
|
-
return
|
|
4451
|
+
return ok23(buildSummaryOutput(p.url, duration, results, consoleMessages, totalCount, wsCaptures));
|
|
4380
4452
|
} finally {
|
|
4381
4453
|
await closeEphemeralContext(context);
|
|
4382
4454
|
}
|
|
@@ -4384,7 +4456,7 @@ var networkCommand = registerCommand({
|
|
|
4384
4456
|
});
|
|
4385
4457
|
|
|
4386
4458
|
// src/commands/ai-search-engines.ts
|
|
4387
|
-
import { z as
|
|
4459
|
+
import { z as z24 } from "zod";
|
|
4388
4460
|
var ENGINE_CONFIGS = {
|
|
4389
4461
|
deepseek: {
|
|
4390
4462
|
key: "deepseek",
|
|
@@ -4638,11 +4710,11 @@ var ENGINE_CONFIGS = {
|
|
|
4638
4710
|
}
|
|
4639
4711
|
};
|
|
4640
4712
|
var ALL_ENGINE_KEYS = Object.keys(ENGINE_CONFIGS);
|
|
4641
|
-
var ENGINE_KEY_ENUM =
|
|
4713
|
+
var ENGINE_KEY_ENUM = z24.enum(ALL_ENGINE_KEYS);
|
|
4642
4714
|
|
|
4643
4715
|
// src/commands/snapshot.ts
|
|
4644
|
-
import { z as
|
|
4645
|
-
import { ok as
|
|
4716
|
+
import { z as z25 } from "zod";
|
|
4717
|
+
import { ok as ok24, fail as fail11, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
|
|
4646
4718
|
|
|
4647
4719
|
// src/runtime/ref-store.ts
|
|
4648
4720
|
var sessions = /* @__PURE__ */ new Map();
|
|
@@ -5554,24 +5626,24 @@ var snapshotCommand = registerCommand({
|
|
|
5554
5626
|
description: "Capture a quick page state snapshot \u2014 aria tree, visible text, or DOM summary",
|
|
5555
5627
|
scope: "page",
|
|
5556
5628
|
selectorParams: ["selector"],
|
|
5557
|
-
parameters:
|
|
5558
|
-
type:
|
|
5559
|
-
selector:
|
|
5560
|
-
depth:
|
|
5561
|
-
interactive:
|
|
5562
|
-
interactiveOnly:
|
|
5563
|
-
i:
|
|
5564
|
-
compact:
|
|
5565
|
-
c:
|
|
5566
|
-
selectors:
|
|
5567
|
-
all:
|
|
5629
|
+
parameters: z25.object({
|
|
5630
|
+
type: z25.enum(["aria", "text", "dom", "all"]).default("aria").describe("Snapshot type: aria (accessibility tree), text (visible text), dom (element summary), all (combined)"),
|
|
5631
|
+
selector: z25.string().optional().describe("Scope to a specific element"),
|
|
5632
|
+
depth: z25.number().optional().default(6).describe("Max depth for DOM/aria tree"),
|
|
5633
|
+
interactive: z25.boolean().optional().default(false).describe("Return interactive agent refs only"),
|
|
5634
|
+
interactiveOnly: z25.boolean().optional().default(false).describe("Alias for interactive"),
|
|
5635
|
+
i: z25.boolean().optional().default(false).describe("Short alias for interactive"),
|
|
5636
|
+
compact: z25.boolean().optional().default(false).describe("Include compact xbrowser style snapshot text"),
|
|
5637
|
+
c: z25.boolean().optional().default(false).describe("Short alias for compact"),
|
|
5638
|
+
selectors: z25.boolean().optional().default(false).describe("Include ref to CSS selector map"),
|
|
5639
|
+
all: z25.boolean().optional().default(false).describe("Include hidden interactive targets when using interactive snapshot")
|
|
5568
5640
|
}),
|
|
5569
|
-
result:
|
|
5570
|
-
url:
|
|
5571
|
-
title:
|
|
5572
|
-
aria:
|
|
5573
|
-
text:
|
|
5574
|
-
dom:
|
|
5641
|
+
result: z25.object({
|
|
5642
|
+
url: z25.string(),
|
|
5643
|
+
title: z25.string(),
|
|
5644
|
+
aria: z25.string().optional(),
|
|
5645
|
+
text: z25.string().optional(),
|
|
5646
|
+
dom: z25.record(z25.unknown()).optional()
|
|
5575
5647
|
}),
|
|
5576
5648
|
handler: async (p, ctx) => {
|
|
5577
5649
|
const page = ctx.page;
|
|
@@ -5585,7 +5657,7 @@ var snapshotCommand = registerCommand({
|
|
|
5585
5657
|
if (p.compact || p.c || p.interactive || p.interactiveOnly || p.i) {
|
|
5586
5658
|
observation.compact = formatObservationCompact(observation, { selectors: p.selectors });
|
|
5587
5659
|
}
|
|
5588
|
-
return
|
|
5660
|
+
return ok24(observation, normalizeTips3([
|
|
5589
5661
|
`refs refreshed for ${observation.targets.length} targets; use click @e1 or fill @e2 "text"`
|
|
5590
5662
|
]));
|
|
5591
5663
|
}
|
|
@@ -5593,15 +5665,15 @@ var snapshotCommand = registerCommand({
|
|
|
5593
5665
|
const aria = await captureAriaSnapshot(page, p.selector, p.depth);
|
|
5594
5666
|
const tips = await buildRefTips(page, aria);
|
|
5595
5667
|
persistSemantics(url, aria);
|
|
5596
|
-
return
|
|
5668
|
+
return ok24({ url, title, aria }, normalizeTips3(tips));
|
|
5597
5669
|
}
|
|
5598
5670
|
if (p.type === "text") {
|
|
5599
5671
|
const text = await captureTextSnapshot(page, p.selector);
|
|
5600
|
-
return
|
|
5672
|
+
return ok24({ url, title, text });
|
|
5601
5673
|
}
|
|
5602
5674
|
if (p.type === "dom") {
|
|
5603
5675
|
const dom = await captureDomSnapshot(page, p.selector, p.depth ?? 6);
|
|
5604
|
-
return
|
|
5676
|
+
return ok24({ url, title, dom });
|
|
5605
5677
|
}
|
|
5606
5678
|
if (p.type === "all") {
|
|
5607
5679
|
const [aria, text, dom] = await Promise.all([
|
|
@@ -5611,9 +5683,9 @@ var snapshotCommand = registerCommand({
|
|
|
5611
5683
|
]);
|
|
5612
5684
|
const tips = await buildRefTips(page, aria);
|
|
5613
5685
|
persistSemantics(url, aria);
|
|
5614
|
-
return
|
|
5686
|
+
return ok24({ url, title, aria, text, dom }, normalizeTips3(tips));
|
|
5615
5687
|
}
|
|
5616
|
-
return
|
|
5688
|
+
return fail11(`Unknown snapshot type: ${p.type}`);
|
|
5617
5689
|
}
|
|
5618
5690
|
});
|
|
5619
5691
|
function persistSemantics(url, aria) {
|
|
@@ -5690,22 +5762,22 @@ async function captureDomSnapshot(page, selector, maxDepth) {
|
|
|
5690
5762
|
}
|
|
5691
5763
|
|
|
5692
5764
|
// src/commands/agent.ts
|
|
5693
|
-
import { z as
|
|
5694
|
-
import { ok as
|
|
5765
|
+
import { z as z26 } from "zod";
|
|
5766
|
+
import { ok as ok25, normalizeTips as normalizeTips4 } from "@dyyz1993/xcli-core";
|
|
5695
5767
|
var observeCommand = registerCommand({
|
|
5696
5768
|
name: "observe",
|
|
5697
5769
|
description: "Observe the current page as structured agent targets with session refs",
|
|
5698
5770
|
scope: "page",
|
|
5699
|
-
parameters:
|
|
5700
|
-
includeHidden:
|
|
5701
|
-
limit:
|
|
5702
|
-
compact:
|
|
5703
|
-
selectors:
|
|
5771
|
+
parameters: z26.object({
|
|
5772
|
+
includeHidden: z26.boolean().optional().default(false).describe("Include hidden elements in the target list"),
|
|
5773
|
+
limit: z26.number().int().positive().max(300).optional().default(80).describe("Maximum number of targets to return"),
|
|
5774
|
+
compact: z26.boolean().optional().default(false).describe("Include compact xbrowser style snapshot text"),
|
|
5775
|
+
selectors: z26.boolean().optional().default(false).describe("Include ref to stable CSS selector map")
|
|
5704
5776
|
}),
|
|
5705
|
-
result:
|
|
5706
|
-
targets:
|
|
5707
|
-
selectors:
|
|
5708
|
-
compact:
|
|
5777
|
+
result: z26.object({
|
|
5778
|
+
targets: z26.array(z26.record(z26.unknown())),
|
|
5779
|
+
selectors: z26.record(z26.unknown()).optional(),
|
|
5780
|
+
compact: z26.string().optional()
|
|
5709
5781
|
}).passthrough(),
|
|
5710
5782
|
handler: async (p, ctx) => {
|
|
5711
5783
|
const observation = await observePage(ctx.page, ctx.sessionId, {
|
|
@@ -5714,7 +5786,7 @@ var observeCommand = registerCommand({
|
|
|
5714
5786
|
});
|
|
5715
5787
|
if (p.selectors) observation.selectors = buildSelectorMap(observation);
|
|
5716
5788
|
if (p.compact) observation.compact = formatObservationCompact(observation, { selectors: p.selectors });
|
|
5717
|
-
return
|
|
5789
|
+
return ok25(observation, normalizeTips4([
|
|
5718
5790
|
`refs refreshed for ${observation.targets.length} targets; use act --ref @e1 --action click or click @e1`
|
|
5719
5791
|
]));
|
|
5720
5792
|
}
|
|
@@ -5724,14 +5796,14 @@ var actCommand = registerCommand({
|
|
|
5724
5796
|
description: "Perform an agent action using an observe ref or explicit selector",
|
|
5725
5797
|
scope: "element",
|
|
5726
5798
|
selectorParams: ["selector"],
|
|
5727
|
-
parameters:
|
|
5728
|
-
action:
|
|
5729
|
-
ref:
|
|
5730
|
-
selector:
|
|
5731
|
-
value:
|
|
5732
|
-
key:
|
|
5733
|
-
force:
|
|
5734
|
-
timeout:
|
|
5799
|
+
parameters: z26.object({
|
|
5800
|
+
action: z26.enum(["click", "fill", "type", "press", "select", "check", "hover"]).default("click"),
|
|
5801
|
+
ref: z26.string().optional().describe("Session-scoped ref returned by observe, such as e1"),
|
|
5802
|
+
selector: z26.string().optional().describe("CSS selector fallback when no ref is available"),
|
|
5803
|
+
value: z26.string().optional().describe("Value for fill/type/select"),
|
|
5804
|
+
key: z26.string().optional().describe("Key for press"),
|
|
5805
|
+
force: z26.boolean().optional().default(false).describe("Bypass actionability checks"),
|
|
5806
|
+
timeout: z26.number().optional().default(1e4).describe("Playwright action timeout in milliseconds")
|
|
5735
5807
|
}).refine((p) => !!p.ref || !!p.selector, {
|
|
5736
5808
|
message: "Either ref or selector is required"
|
|
5737
5809
|
}),
|
|
@@ -5745,7 +5817,7 @@ var actCommand = registerCommand({
|
|
|
5745
5817
|
tips: normalizeTips4(result.stale ? ["run observe again to refresh refs"] : [])
|
|
5746
5818
|
};
|
|
5747
5819
|
}
|
|
5748
|
-
return
|
|
5820
|
+
return ok25(result, normalizeTips4(result.stale ? ["ref screen hash changed; run observe if the next action is uncertain"] : []));
|
|
5749
5821
|
}
|
|
5750
5822
|
});
|
|
5751
5823
|
var waitForCommand = registerCommand({
|
|
@@ -5753,16 +5825,16 @@ var waitForCommand = registerCommand({
|
|
|
5753
5825
|
description: "Wait for agent predicates such as text, URL, load state, selector state, or screen hash changes",
|
|
5754
5826
|
scope: "page",
|
|
5755
5827
|
selectorParams: ["selector"],
|
|
5756
|
-
parameters:
|
|
5757
|
-
selector:
|
|
5758
|
-
state:
|
|
5759
|
-
text:
|
|
5760
|
-
url:
|
|
5761
|
-
load:
|
|
5762
|
-
fn:
|
|
5763
|
-
screenHashChanged:
|
|
5764
|
-
timeout:
|
|
5765
|
-
pollInterval:
|
|
5828
|
+
parameters: z26.object({
|
|
5829
|
+
selector: z26.string().optional().describe("CSS selector or observe ref to wait for"),
|
|
5830
|
+
state: z26.enum(["attached", "detached", "visible", "hidden"]).optional().default("visible"),
|
|
5831
|
+
text: z26.string().optional().describe("Visible text to wait for"),
|
|
5832
|
+
url: z26.string().optional().describe("URL substring or glob pattern to wait for"),
|
|
5833
|
+
load: z26.enum(["load", "domcontentloaded", "networkidle"]).optional().describe("Load state to wait for"),
|
|
5834
|
+
fn: z26.string().optional().describe("JavaScript predicate to wait for"),
|
|
5835
|
+
screenHashChanged: z26.string().optional().describe("Previous screenHash from observe"),
|
|
5836
|
+
timeout: z26.number().optional().default(3e4),
|
|
5837
|
+
pollInterval: z26.number().optional().default(200)
|
|
5766
5838
|
}).refine((p) => [p.selector, p.text, p.url, p.load, p.fn, p.screenHashChanged].filter(Boolean).length === 1, {
|
|
5767
5839
|
message: "Provide exactly one wait predicate: selector, text, url, load, fn, or screenHashChanged"
|
|
5768
5840
|
}),
|
|
@@ -5776,30 +5848,30 @@ var waitForCommand = registerCommand({
|
|
|
5776
5848
|
tips: []
|
|
5777
5849
|
};
|
|
5778
5850
|
}
|
|
5779
|
-
return
|
|
5851
|
+
return ok25(result);
|
|
5780
5852
|
}
|
|
5781
5853
|
});
|
|
5782
5854
|
|
|
5783
5855
|
// src/commands/tab.ts
|
|
5784
|
-
import { z as
|
|
5785
|
-
import { ok as
|
|
5786
|
-
var TabParams =
|
|
5787
|
-
subcommand:
|
|
5788
|
-
url:
|
|
5789
|
-
index:
|
|
5856
|
+
import { z as z27 } from "zod";
|
|
5857
|
+
import { ok as ok26, fail as fail12 } from "@dyyz1993/xcli-core";
|
|
5858
|
+
var TabParams = z27.object({
|
|
5859
|
+
subcommand: z27.enum(["list", "new", "close", "switch"]),
|
|
5860
|
+
url: z27.string().optional(),
|
|
5861
|
+
index: z27.number().int().min(0).optional()
|
|
5790
5862
|
});
|
|
5791
5863
|
var tabCommand = registerCommand({
|
|
5792
5864
|
name: "tab",
|
|
5793
5865
|
description: "Manage browser tabs: list, new, close, switch",
|
|
5794
5866
|
scope: "page",
|
|
5795
5867
|
parameters: TabParams,
|
|
5796
|
-
result:
|
|
5797
|
-
success:
|
|
5798
|
-
data:
|
|
5868
|
+
result: z27.object({
|
|
5869
|
+
success: z27.boolean(),
|
|
5870
|
+
data: z27.unknown()
|
|
5799
5871
|
}),
|
|
5800
5872
|
handler: async (p, ctx) => {
|
|
5801
5873
|
if (!ctx.browserContext) {
|
|
5802
|
-
return
|
|
5874
|
+
return fail12("No browser context available. Use --cdp to connect to a browser first.");
|
|
5803
5875
|
}
|
|
5804
5876
|
const pages = ctx.browserContext.pages();
|
|
5805
5877
|
switch (p.subcommand) {
|
|
@@ -5812,7 +5884,7 @@ var tabCommand = registerCommand({
|
|
|
5812
5884
|
case "switch":
|
|
5813
5885
|
return handleSwitch(p, pages, ctx);
|
|
5814
5886
|
default:
|
|
5815
|
-
return
|
|
5887
|
+
return fail12(`Unknown subcommand: ${p.subcommand}`);
|
|
5816
5888
|
}
|
|
5817
5889
|
}
|
|
5818
5890
|
});
|
|
@@ -5827,7 +5899,7 @@ async function handleList(pages, ctx) {
|
|
|
5827
5899
|
if (isActive) activeIndex = i;
|
|
5828
5900
|
tabs.push({ index: i, url, title, active: isActive });
|
|
5829
5901
|
}
|
|
5830
|
-
return
|
|
5902
|
+
return ok26({ tabs, total: tabs.length, activeIndex });
|
|
5831
5903
|
}
|
|
5832
5904
|
async function handleNew(p, _pages, ctx) {
|
|
5833
5905
|
const newPage = await ctx.browserContext.newPage();
|
|
@@ -5855,7 +5927,7 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5855
5927
|
const title = await newPage.title().catch(() => "");
|
|
5856
5928
|
const allPages = ctx.browserContext.pages();
|
|
5857
5929
|
const newIndex = allPages.indexOf(newPage);
|
|
5858
|
-
return
|
|
5930
|
+
return ok26({
|
|
5859
5931
|
index: newIndex >= 0 ? newIndex : allPages.length - 1,
|
|
5860
5932
|
url: newPage.url(),
|
|
5861
5933
|
title,
|
|
@@ -5866,11 +5938,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5866
5938
|
async function handleClose(p, ctx) {
|
|
5867
5939
|
const currentPages = ctx.browserContext.pages();
|
|
5868
5940
|
if (currentPages.length <= 1) {
|
|
5869
|
-
return
|
|
5941
|
+
return fail12("Cannot close the last remaining tab");
|
|
5870
5942
|
}
|
|
5871
5943
|
const closeIndex = p.index ?? currentPages.findIndex((pg) => pg === ctx.page);
|
|
5872
5944
|
if (closeIndex < 0 || closeIndex >= currentPages.length) {
|
|
5873
|
-
return
|
|
5945
|
+
return fail12(`Invalid tab index: ${closeIndex}. Valid range: 0-${currentPages.length - 1}`);
|
|
5874
5946
|
}
|
|
5875
5947
|
const pageToClose = currentPages[closeIndex];
|
|
5876
5948
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5885,7 +5957,7 @@ async function handleClose(p, ctx) {
|
|
|
5885
5957
|
}
|
|
5886
5958
|
ctx.page = newActivePage;
|
|
5887
5959
|
}
|
|
5888
|
-
return
|
|
5960
|
+
return ok26({
|
|
5889
5961
|
closedIndex: closeIndex,
|
|
5890
5962
|
total: remainingPages.length,
|
|
5891
5963
|
activeIndex: isActivePage ? closeIndex < remainingPages.length ? closeIndex : remainingPages.length - 1 : remainingPages.findIndex((pg) => pg === ctx.page)
|
|
@@ -5893,10 +5965,10 @@ async function handleClose(p, ctx) {
|
|
|
5893
5965
|
}
|
|
5894
5966
|
async function handleSwitch(p, pages, ctx) {
|
|
5895
5967
|
if (p.index === void 0) {
|
|
5896
|
-
return
|
|
5968
|
+
return fail12("Parameter --index is required for switch subcommand");
|
|
5897
5969
|
}
|
|
5898
5970
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5899
|
-
return
|
|
5971
|
+
return fail12(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5900
5972
|
}
|
|
5901
5973
|
const targetPage = pages[p.index];
|
|
5902
5974
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -5918,7 +5990,7 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
5918
5990
|
}
|
|
5919
5991
|
ctx.page = targetPage;
|
|
5920
5992
|
const title = await targetPage.title().catch(() => "");
|
|
5921
|
-
return
|
|
5993
|
+
return ok26({
|
|
5922
5994
|
index: p.index,
|
|
5923
5995
|
url: targetPage.url(),
|
|
5924
5996
|
title,
|
|
@@ -5927,8 +5999,8 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
5927
5999
|
}
|
|
5928
6000
|
|
|
5929
6001
|
// src/commands/addinitscript.ts
|
|
5930
|
-
import { z as
|
|
5931
|
-
import { ok as
|
|
6002
|
+
import { z as z28 } from "zod";
|
|
6003
|
+
import { ok as ok27 } from "@dyyz1993/xcli-core";
|
|
5932
6004
|
import { readFileSync as readFileSync4 } from "fs";
|
|
5933
6005
|
|
|
5934
6006
|
// src/chain-parser.ts
|
|
@@ -6069,14 +6141,14 @@ registerCommandDefinition("tab", ["subcommand"]);
|
|
|
6069
6141
|
registerCommandDefinition("mouse", ["action", "x", "y"]);
|
|
6070
6142
|
|
|
6071
6143
|
// src/commands/addinitscript.ts
|
|
6072
|
-
var InitScriptParams =
|
|
6073
|
-
script:
|
|
6074
|
-
file:
|
|
6075
|
-
stdin:
|
|
6076
|
-
name:
|
|
6077
|
-
list:
|
|
6078
|
-
remove:
|
|
6079
|
-
base64:
|
|
6144
|
+
var InitScriptParams = z28.object({
|
|
6145
|
+
script: z28.string().optional(),
|
|
6146
|
+
file: z28.string().optional(),
|
|
6147
|
+
stdin: z28.boolean().optional(),
|
|
6148
|
+
name: z28.string().optional(),
|
|
6149
|
+
list: z28.boolean().optional(),
|
|
6150
|
+
remove: z28.union([z28.string(), z28.boolean()]).optional(),
|
|
6151
|
+
base64: z28.string().optional()
|
|
6080
6152
|
});
|
|
6081
6153
|
var registeredScripts = /* @__PURE__ */ new Map();
|
|
6082
6154
|
function resolveScriptContent(params) {
|
|
@@ -6110,14 +6182,14 @@ var addInitScriptCommand = registerCommand({
|
|
|
6110
6182
|
description: "Add an initialization script that runs on every page load",
|
|
6111
6183
|
scope: "page",
|
|
6112
6184
|
parameters: InitScriptParams,
|
|
6113
|
-
result:
|
|
6114
|
-
scripts:
|
|
6115
|
-
removed:
|
|
6116
|
-
existed:
|
|
6117
|
-
error:
|
|
6118
|
-
registered:
|
|
6119
|
-
hint:
|
|
6120
|
-
executedImmediately:
|
|
6185
|
+
result: z28.object({
|
|
6186
|
+
scripts: z28.array(z28.object({ name: z28.string(), size: z28.number(), preview: z28.string() })).optional(),
|
|
6187
|
+
removed: z28.string().optional(),
|
|
6188
|
+
existed: z28.boolean().optional(),
|
|
6189
|
+
error: z28.string().optional(),
|
|
6190
|
+
registered: z28.string().optional(),
|
|
6191
|
+
hint: z28.string().optional(),
|
|
6192
|
+
executedImmediately: z28.boolean().optional()
|
|
6121
6193
|
}).passthrough(),
|
|
6122
6194
|
handler: async (params, ctx) => {
|
|
6123
6195
|
if (params.list) {
|
|
@@ -6126,20 +6198,20 @@ var addInitScriptCommand = registerCommand({
|
|
|
6126
6198
|
size: content2.length,
|
|
6127
6199
|
preview: content2.slice(0, 80)
|
|
6128
6200
|
}));
|
|
6129
|
-
return
|
|
6201
|
+
return ok27({ scripts });
|
|
6130
6202
|
}
|
|
6131
6203
|
if (params.remove && typeof params.remove === "string") {
|
|
6132
6204
|
const existed = registeredScripts.delete(params.remove);
|
|
6133
|
-
return
|
|
6205
|
+
return ok27({ removed: params.remove, existed });
|
|
6134
6206
|
}
|
|
6135
6207
|
const removeTarget = (typeof params.remove === "string" ? params.remove : null) || (params.name && !resolveScriptContent(params) ? params.name : null);
|
|
6136
6208
|
if (removeTarget && !resolveScriptContent(params)) {
|
|
6137
6209
|
const existed = registeredScripts.delete(removeTarget);
|
|
6138
|
-
return
|
|
6210
|
+
return ok27({ removed: removeTarget, existed });
|
|
6139
6211
|
}
|
|
6140
6212
|
let content = params.stdin ? await readStdin() : resolveScriptContent(params);
|
|
6141
6213
|
if (!content) {
|
|
6142
|
-
return
|
|
6214
|
+
return ok27({ error: "No script content provided. Use --script, --file, --stdin, or --base64" });
|
|
6143
6215
|
}
|
|
6144
6216
|
const scriptName = params.name ?? `script-${Date.now()}`;
|
|
6145
6217
|
registeredScripts.set(scriptName, content);
|
|
@@ -6147,45 +6219,45 @@ var addInitScriptCommand = registerCommand({
|
|
|
6147
6219
|
try {
|
|
6148
6220
|
await ctx.page.evaluate(content);
|
|
6149
6221
|
} catch {
|
|
6150
|
-
return
|
|
6222
|
+
return ok27({
|
|
6151
6223
|
registered: scriptName,
|
|
6152
6224
|
hint: "Script registered for future page loads; immediate execution skipped (page may not be ready)"
|
|
6153
6225
|
});
|
|
6154
6226
|
}
|
|
6155
|
-
return
|
|
6227
|
+
return ok27({ registered: scriptName, executedImmediately: true });
|
|
6156
6228
|
}
|
|
6157
6229
|
});
|
|
6158
6230
|
registerCommandDefinition("addinitscript", ["script"]);
|
|
6159
6231
|
|
|
6160
6232
|
// src/commands/find.ts
|
|
6161
|
-
import { z as
|
|
6162
|
-
import { ok as
|
|
6163
|
-
var actionSchema2 =
|
|
6233
|
+
import { z as z29 } from "zod";
|
|
6234
|
+
import { ok as ok28, fail as fail13, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
6235
|
+
var actionSchema2 = z29.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
6164
6236
|
var findCommand = registerCommand({
|
|
6165
6237
|
name: "find",
|
|
6166
6238
|
description: "Find elements by semantic strategy (text/role/label/placeholder/testid) and optionally perform an action",
|
|
6167
6239
|
scope: "page",
|
|
6168
|
-
parameters:
|
|
6169
|
-
strategy:
|
|
6170
|
-
value:
|
|
6171
|
-
name:
|
|
6172
|
-
exact:
|
|
6173
|
-
operation:
|
|
6240
|
+
parameters: z29.object({
|
|
6241
|
+
strategy: z29.enum(["text", "role", "label", "placeholder", "testid", "alt", "title", "first", "last", "nth"]),
|
|
6242
|
+
value: z29.string(),
|
|
6243
|
+
name: z29.string().optional(),
|
|
6244
|
+
exact: z29.boolean().optional().default(false),
|
|
6245
|
+
operation: z29.string().optional().describe('Trailing operation syntax, e.g. click, fill "text", type "text"'),
|
|
6174
6246
|
action: actionSchema2.optional().describe("Action to perform when not using trailing operation syntax"),
|
|
6175
|
-
actionValue:
|
|
6176
|
-
index:
|
|
6177
|
-
click:
|
|
6178
|
-
fill:
|
|
6179
|
-
type:
|
|
6180
|
-
select:
|
|
6181
|
-
hover:
|
|
6182
|
-
check:
|
|
6183
|
-
timeout:
|
|
6247
|
+
actionValue: z29.string().optional().describe("Value for fill/type/select when using action"),
|
|
6248
|
+
index: z29.number().int().optional().describe("Index for nth strategy"),
|
|
6249
|
+
click: z29.boolean().optional().default(false),
|
|
6250
|
+
fill: z29.string().optional(),
|
|
6251
|
+
type: z29.string().optional(),
|
|
6252
|
+
select: z29.string().optional(),
|
|
6253
|
+
hover: z29.boolean().optional().default(false),
|
|
6254
|
+
check: z29.boolean().optional().default(false),
|
|
6255
|
+
timeout: z29.number().optional().default(1e4)
|
|
6184
6256
|
}),
|
|
6185
|
-
result:
|
|
6186
|
-
matched:
|
|
6187
|
-
selector:
|
|
6188
|
-
action:
|
|
6257
|
+
result: z29.object({
|
|
6258
|
+
matched: z29.number(),
|
|
6259
|
+
selector: z29.string(),
|
|
6260
|
+
action: z29.string().optional()
|
|
6189
6261
|
}),
|
|
6190
6262
|
handler: async (p, ctx) => {
|
|
6191
6263
|
const page = ctx.page;
|
|
@@ -6200,7 +6272,7 @@ var findCommand = registerCommand({
|
|
|
6200
6272
|
});
|
|
6201
6273
|
const count = await locator.count();
|
|
6202
6274
|
if (count === 0) {
|
|
6203
|
-
return
|
|
6275
|
+
return fail13(`No element found with ${p.strategy}="${p.value}"`);
|
|
6204
6276
|
}
|
|
6205
6277
|
const tips = [];
|
|
6206
6278
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6212,15 +6284,15 @@ var findCommand = registerCommand({
|
|
|
6212
6284
|
await target.click({ timeout: p.timeout, force: true });
|
|
6213
6285
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6214
6286
|
} else if (actionName === "fill") {
|
|
6215
|
-
if (actionValue === void 0) return
|
|
6287
|
+
if (actionValue === void 0) return fail13("find fill requires a value");
|
|
6216
6288
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6217
6289
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6218
6290
|
} else if (actionName === "type") {
|
|
6219
|
-
if (actionValue === void 0) return
|
|
6291
|
+
if (actionValue === void 0) return fail13("find type requires a value");
|
|
6220
6292
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6221
6293
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6222
6294
|
} else if (actionName === "select") {
|
|
6223
|
-
if (actionValue === void 0) return
|
|
6295
|
+
if (actionValue === void 0) return fail13("find select requires a value");
|
|
6224
6296
|
await target.selectOption(actionValue);
|
|
6225
6297
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6226
6298
|
} else if (actionName === "hover") {
|
|
@@ -6234,7 +6306,7 @@ var findCommand = registerCommand({
|
|
|
6234
6306
|
}
|
|
6235
6307
|
});
|
|
6236
6308
|
function okWithTips(data, tips) {
|
|
6237
|
-
const result =
|
|
6309
|
+
const result = ok28(data);
|
|
6238
6310
|
if (tips.length > 0) result.tips = normalizeTips5(tips);
|
|
6239
6311
|
return result;
|
|
6240
6312
|
}
|
|
@@ -6333,8 +6405,8 @@ function describeSelector(strategy, value, name) {
|
|
|
6333
6405
|
}
|
|
6334
6406
|
|
|
6335
6407
|
// src/commands/visual-tag.ts
|
|
6336
|
-
import { z as
|
|
6337
|
-
import { ok as
|
|
6408
|
+
import { z as z30 } from "zod";
|
|
6409
|
+
import { ok as ok29, fail as fail14 } from "@dyyz1993/xcli-core";
|
|
6338
6410
|
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6339
6411
|
var TAG_SCRIPT = `
|
|
6340
6412
|
(function() {
|
|
@@ -6425,49 +6497,49 @@ var visualTagCommand = registerCommand({
|
|
|
6425
6497
|
name: "visual-tag",
|
|
6426
6498
|
description: "\u5728\u9875\u9762\u4E0A\u7ED9\u53EF\u4EA4\u4E92\u5143\u7D20\u53E0\u52A0\u9632\u6DF7\u6DC6\u77ED ID \u6807\u7B7E\uFF08\u89C6\u89C9\u5B9A\u4F4D\u7528\uFF09",
|
|
6427
6499
|
scope: "page",
|
|
6428
|
-
parameters:
|
|
6429
|
-
action:
|
|
6430
|
-
id:
|
|
6500
|
+
parameters: z30.object({
|
|
6501
|
+
action: z30.enum(["tag", "lookup", "clear", "list"]),
|
|
6502
|
+
id: z30.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6431
6503
|
}),
|
|
6432
|
-
result:
|
|
6433
|
-
action:
|
|
6434
|
-
tagged:
|
|
6435
|
-
id:
|
|
6436
|
-
element:
|
|
6504
|
+
result: z30.object({
|
|
6505
|
+
action: z30.string(),
|
|
6506
|
+
tagged: z30.number().optional(),
|
|
6507
|
+
id: z30.string().optional(),
|
|
6508
|
+
element: z30.record(z30.unknown()).optional()
|
|
6437
6509
|
}),
|
|
6438
6510
|
handler: async (p, ctx) => {
|
|
6439
6511
|
switch (p.action) {
|
|
6440
6512
|
case "tag": {
|
|
6441
6513
|
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6442
6514
|
const parsed = JSON.parse(result);
|
|
6443
|
-
return
|
|
6515
|
+
return ok29({ action: "tag", tagged: parsed.tagged });
|
|
6444
6516
|
}
|
|
6445
6517
|
case "lookup": {
|
|
6446
|
-
if (!p.id) return
|
|
6518
|
+
if (!p.id) return fail14("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6447
6519
|
const result = await ctx.page.evaluate(
|
|
6448
6520
|
`(function() { var m = window.__xbTagMap; if (!m) return JSON.stringify({err:'no-map'}); var e = m[${JSON.stringify(p.id)}]; return e ? JSON.stringify(e) : JSON.stringify({err:'not-found'}); })()`
|
|
6449
6521
|
);
|
|
6450
6522
|
const parsed = JSON.parse(result);
|
|
6451
|
-
if (parsed.err) return
|
|
6452
|
-
return
|
|
6523
|
+
if (parsed.err) return fail14(`ID ${p.id}: ${parsed.err}`);
|
|
6524
|
+
return ok29({ action: "lookup", id: p.id, element: parsed });
|
|
6453
6525
|
}
|
|
6454
6526
|
case "list": {
|
|
6455
6527
|
const result = await ctx.page.evaluate(
|
|
6456
6528
|
`(function() { var m = window.__xbTagMap; if (!m) return '{}'; var out = {}; for (var k in m) { out[k] = m[k].text || m[k].tagName; } return JSON.stringify(out); })()`
|
|
6457
6529
|
);
|
|
6458
|
-
return
|
|
6530
|
+
return ok29({ action: "list", element: JSON.parse(result) });
|
|
6459
6531
|
}
|
|
6460
6532
|
case "clear": {
|
|
6461
6533
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6462
|
-
return
|
|
6534
|
+
return ok29({ action: "clear" });
|
|
6463
6535
|
}
|
|
6464
6536
|
}
|
|
6465
6537
|
}
|
|
6466
6538
|
});
|
|
6467
6539
|
|
|
6468
6540
|
// src/commands/visual-tag-v2.ts
|
|
6469
|
-
import { z as
|
|
6470
|
-
import { ok as
|
|
6541
|
+
import { z as z31 } from "zod";
|
|
6542
|
+
import { ok as ok30, fail as fail15 } from "@dyyz1993/xcli-core";
|
|
6471
6543
|
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6472
6544
|
var TAG_V2_SCRIPT = `
|
|
6473
6545
|
(function() {
|
|
@@ -6814,45 +6886,45 @@ var visualTagV2Command = registerCommand({
|
|
|
6814
6886
|
name: "visual-tag-v2",
|
|
6815
6887
|
description: "\u5206\u8272\u6807\u6CE8\u9875\u9762\u5143\u7D20\uFF08\u7EA2=\u53EF\u70B9\u51FB \u84DD=\u8F93\u5165 \u7EFF=\u56FE\u7247 \u9EC4=\u5217\u8868 \u7D2B=\u6570\u5B57 \u6A59=\u6587\u672C\uFF09",
|
|
6816
6888
|
scope: "page",
|
|
6817
|
-
parameters:
|
|
6818
|
-
action:
|
|
6819
|
-
id:
|
|
6820
|
-
query:
|
|
6821
|
-
type:
|
|
6822
|
-
"interact-action":
|
|
6823
|
-
value:
|
|
6889
|
+
parameters: z31.object({
|
|
6890
|
+
action: z31.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
6891
|
+
id: z31.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
6892
|
+
query: z31.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
6893
|
+
type: z31.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
6894
|
+
"interact-action": z31.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
6895
|
+
value: z31.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6824
6896
|
}),
|
|
6825
|
-
result:
|
|
6826
|
-
action:
|
|
6827
|
-
total:
|
|
6828
|
-
byType:
|
|
6829
|
-
element:
|
|
6897
|
+
result: z31.object({
|
|
6898
|
+
action: z31.string(),
|
|
6899
|
+
total: z31.number().optional(),
|
|
6900
|
+
byType: z31.record(z31.number()).optional(),
|
|
6901
|
+
element: z31.record(z31.unknown()).optional()
|
|
6830
6902
|
}),
|
|
6831
6903
|
handler: async (p, ctx) => {
|
|
6832
6904
|
switch (p.action) {
|
|
6833
6905
|
case "tag": {
|
|
6834
6906
|
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6835
6907
|
const parsed = JSON.parse(result);
|
|
6836
|
-
return
|
|
6908
|
+
return ok30({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6837
6909
|
}
|
|
6838
6910
|
case "lookup": {
|
|
6839
|
-
if (!p.id) return
|
|
6911
|
+
if (!p.id) return fail15("lookup \u9700\u8981 --id");
|
|
6840
6912
|
const result = await ctx.page.evaluate(
|
|
6841
6913
|
`(function(){var m=window.__xbTagMap;if(!m)return JSON.stringify({err:'no-map'});var e=m[${JSON.stringify(p.id)}];return e?JSON.stringify(e):JSON.stringify({err:'not-found'})})()`
|
|
6842
6914
|
);
|
|
6843
6915
|
const parsed = JSON.parse(result);
|
|
6844
|
-
if (parsed.err) return
|
|
6845
|
-
return
|
|
6916
|
+
if (parsed.err) return fail15(`ID ${p.id}: ${parsed.err}`);
|
|
6917
|
+
return ok30({ action: "lookup", id: p.id, element: parsed });
|
|
6846
6918
|
}
|
|
6847
6919
|
case "by-type": {
|
|
6848
6920
|
const result = await ctx.page.evaluate(
|
|
6849
6921
|
`(function(){var m=window.__xbTagMap;if(!m)return'{}';var out={};for(var k in m){if(!${JSON.stringify(p.type || "")}||m[k].type===${JSON.stringify(p.type || "")}){out[k]={type:m[k].type,text:m[k].text,num:m[k].num,label:m[k].formLabel}}}return JSON.stringify(out)})()`
|
|
6850
6922
|
);
|
|
6851
|
-
return
|
|
6923
|
+
return ok30({ action: "by-type", element: JSON.parse(result) });
|
|
6852
6924
|
}
|
|
6853
6925
|
case "find": {
|
|
6854
6926
|
const query = p.query;
|
|
6855
|
-
if (!query) return
|
|
6927
|
+
if (!query) return fail15('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6856
6928
|
const result = await ctx.page.evaluate(
|
|
6857
6929
|
`(function(){
|
|
6858
6930
|
var map = window.__xbTagSerializable;
|
|
@@ -6894,21 +6966,21 @@ var visualTagV2Command = registerCommand({
|
|
|
6894
6966
|
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
6895
6967
|
})()`
|
|
6896
6968
|
);
|
|
6897
|
-
return
|
|
6969
|
+
return ok30({ action: "find", query, element: JSON.parse(result) });
|
|
6898
6970
|
}
|
|
6899
6971
|
case "stats": {
|
|
6900
6972
|
const result = await ctx.page.evaluate(
|
|
6901
6973
|
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
6902
6974
|
);
|
|
6903
|
-
return
|
|
6975
|
+
return ok30({ action: "stats", element: JSON.parse(result) });
|
|
6904
6976
|
}
|
|
6905
6977
|
case "interact": {
|
|
6906
6978
|
const query = p.query;
|
|
6907
6979
|
const pAny = p;
|
|
6908
6980
|
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
6909
6981
|
const value = pAny.value;
|
|
6910
|
-
if (!query) return
|
|
6911
|
-
if (!action) return
|
|
6982
|
+
if (!query) return fail15("interact \u9700\u8981 --query \u53C2\u6570");
|
|
6983
|
+
if (!action) return fail15("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
6912
6984
|
const findResult = await ctx.page.evaluate(
|
|
6913
6985
|
`(function(){
|
|
6914
6986
|
var map = window.__xbTagSerializable;
|
|
@@ -6938,11 +7010,11 @@ var visualTagV2Command = registerCommand({
|
|
|
6938
7010
|
})()`
|
|
6939
7011
|
);
|
|
6940
7012
|
const parsed = JSON.parse(findResult);
|
|
6941
|
-
if (parsed.err) return
|
|
6942
|
-
if (!parsed.total || !parsed.results?.length) return
|
|
7013
|
+
if (parsed.err) return fail15(parsed.err);
|
|
7014
|
+
if (!parsed.total || !parsed.results?.length) return fail15(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
6943
7015
|
const target = parsed.results[0];
|
|
6944
7016
|
if (action === "read") {
|
|
6945
|
-
return
|
|
7017
|
+
return ok30({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
6946
7018
|
}
|
|
6947
7019
|
if (action === "click") {
|
|
6948
7020
|
const el = await ctx.page.evaluate(
|
|
@@ -6955,12 +7027,12 @@ var visualTagV2Command = registerCommand({
|
|
|
6955
7027
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
6956
7028
|
})()`
|
|
6957
7029
|
);
|
|
6958
|
-
if (!el) return
|
|
7030
|
+
if (!el) return fail15(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
6959
7031
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
6960
|
-
return
|
|
7032
|
+
return ok30({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
6961
7033
|
}
|
|
6962
7034
|
if (action === "fill") {
|
|
6963
|
-
if (!value) return
|
|
7035
|
+
if (!value) return fail15("fill \u9700\u8981 --value \u53C2\u6570");
|
|
6964
7036
|
const el = await ctx.page.evaluate(
|
|
6965
7037
|
`(function(){
|
|
6966
7038
|
var map = window.__xbTagMap;
|
|
@@ -6971,12 +7043,12 @@ var visualTagV2Command = registerCommand({
|
|
|
6971
7043
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
6972
7044
|
})()`
|
|
6973
7045
|
);
|
|
6974
|
-
if (!el) return
|
|
7046
|
+
if (!el) return fail15(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
6975
7047
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
6976
7048
|
await ctx.page.keyboard.type(value, { stealth: true });
|
|
6977
|
-
return
|
|
7049
|
+
return ok30({ action: "interact", query, target, result: { filled: true, value } });
|
|
6978
7050
|
}
|
|
6979
|
-
return
|
|
7051
|
+
return fail15(`\u672A\u77E5 action: ${action}`);
|
|
6980
7052
|
}
|
|
6981
7053
|
case "export": {
|
|
6982
7054
|
const result = await ctx.page.evaluate(
|
|
@@ -7024,12 +7096,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7024
7096
|
})()`
|
|
7025
7097
|
);
|
|
7026
7098
|
const parsed = JSON.parse(result);
|
|
7027
|
-
if (parsed.err) return
|
|
7028
|
-
return
|
|
7099
|
+
if (parsed.err) return fail15(String(parsed.err));
|
|
7100
|
+
return ok30({ action: "export", element: parsed });
|
|
7029
7101
|
}
|
|
7030
7102
|
case "clear": {
|
|
7031
7103
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7032
|
-
return
|
|
7104
|
+
return ok30({ action: "clear" });
|
|
7033
7105
|
}
|
|
7034
7106
|
}
|
|
7035
7107
|
}
|
|
@@ -8167,7 +8239,7 @@ async function guardCheck(commandName) {
|
|
|
8167
8239
|
}
|
|
8168
8240
|
}
|
|
8169
8241
|
function errorResult(message) {
|
|
8170
|
-
return { ...
|
|
8242
|
+
return { ...fail16(message), duration: 0 };
|
|
8171
8243
|
}
|
|
8172
8244
|
function tipsToMessages(tips) {
|
|
8173
8245
|
if (!tips || tips.length === 0) return [];
|
|
@@ -8440,7 +8512,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8440
8512
|
timestamp: start
|
|
8441
8513
|
});
|
|
8442
8514
|
if (isSuccess) {
|
|
8443
|
-
return { ...
|
|
8515
|
+
return { ...ok31(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8444
8516
|
}
|
|
8445
8517
|
const fc = classifyFailure(raw.message);
|
|
8446
8518
|
return {
|
|
@@ -8463,7 +8535,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8463
8535
|
duration,
|
|
8464
8536
|
timestamp: start
|
|
8465
8537
|
});
|
|
8466
|
-
return { ...
|
|
8538
|
+
return { ...ok31(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8467
8539
|
} catch (err) {
|
|
8468
8540
|
const end = Date.now();
|
|
8469
8541
|
const duration = end - start;
|
|
@@ -8508,7 +8580,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8508
8580
|
duration,
|
|
8509
8581
|
timestamp: start
|
|
8510
8582
|
});
|
|
8511
|
-
return { ...
|
|
8583
|
+
return { ...fail16(errorMessage), duration };
|
|
8512
8584
|
} finally {
|
|
8513
8585
|
}
|
|
8514
8586
|
}
|
|
@@ -8553,7 +8625,7 @@ async function executeChain(input, options) {
|
|
|
8553
8625
|
results.push({
|
|
8554
8626
|
command: cmdName,
|
|
8555
8627
|
raw: cmdStr,
|
|
8556
|
-
...
|
|
8628
|
+
...fail16(`Plugin "${cmdName}" requires a sub-command`),
|
|
8557
8629
|
duration: 0
|
|
8558
8630
|
});
|
|
8559
8631
|
if (type === "and") {
|
|
@@ -8572,7 +8644,7 @@ async function executeChain(input, options) {
|
|
|
8572
8644
|
results.push({
|
|
8573
8645
|
command: cmdName,
|
|
8574
8646
|
raw: cmdStr,
|
|
8575
|
-
...
|
|
8647
|
+
...fail16(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
8576
8648
|
duration: 0
|
|
8577
8649
|
});
|
|
8578
8650
|
if (type === "and") {
|
|
@@ -8684,7 +8756,7 @@ async function executeChain(input, options) {
|
|
|
8684
8756
|
results.push({
|
|
8685
8757
|
command: `${cmdName} ${subCommand}`,
|
|
8686
8758
|
raw: cmdStr,
|
|
8687
|
-
...
|
|
8759
|
+
...ok31(data),
|
|
8688
8760
|
duration: duration2,
|
|
8689
8761
|
...hookOutputs ? { hookOutputs } : {}
|
|
8690
8762
|
});
|
|
@@ -8712,7 +8784,7 @@ async function executeChain(input, options) {
|
|
|
8712
8784
|
results.push({
|
|
8713
8785
|
command: `${cmdName} ${subCommand}`,
|
|
8714
8786
|
raw: cmdStr,
|
|
8715
|
-
...
|
|
8787
|
+
...fail16(errorMessage),
|
|
8716
8788
|
duration: duration2
|
|
8717
8789
|
});
|
|
8718
8790
|
if (type === "and") {
|