@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
package/dist/daemon-main.js
CHANGED
|
@@ -102,8 +102,8 @@ function classifyFailure(message) {
|
|
|
102
102
|
|
|
103
103
|
// src/executor.ts
|
|
104
104
|
import {
|
|
105
|
-
ok as
|
|
106
|
-
fail as
|
|
105
|
+
ok as ok31,
|
|
106
|
+
fail as fail16,
|
|
107
107
|
isCommandResult,
|
|
108
108
|
CompositeStorage as CompositeStorage2,
|
|
109
109
|
TipCollector as TipCollector2,
|
|
@@ -1449,37 +1449,109 @@ var uaCommand = registerCommand({
|
|
|
1449
1449
|
}
|
|
1450
1450
|
});
|
|
1451
1451
|
|
|
1452
|
-
// src/commands/
|
|
1452
|
+
// src/commands/preflight.ts
|
|
1453
1453
|
import { z as z11 } from "zod";
|
|
1454
1454
|
import { ok as ok11, fail as fail4 } from "@dyyz1993/xcli-core";
|
|
1455
|
+
var preflightCommand = registerCommand({
|
|
1456
|
+
name: "preflight",
|
|
1457
|
+
description: "Pre-flight anti-bot gate: open local detection page and verify stealth posture before any automation task",
|
|
1458
|
+
scope: "page",
|
|
1459
|
+
parameters: z11.object({
|
|
1460
|
+
strict: z11.boolean().optional().describe("\u5931\u8D25\u65F6\u4EE5\u975E\u96F6\u9000\u51FA\u7801\u7ED3\u675F\uFF08\u94FE\u5F0F/CI \u95E8\u7981\u7528\uFF09"),
|
|
1461
|
+
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")
|
|
1462
|
+
}),
|
|
1463
|
+
result: z11.object({
|
|
1464
|
+
gate: z11.enum(["pass", "fail"]),
|
|
1465
|
+
failed: z11.array(z11.string()),
|
|
1466
|
+
headless: z11.boolean()
|
|
1467
|
+
}),
|
|
1468
|
+
handler: async (p, ctx) => {
|
|
1469
|
+
const page = ctx.page;
|
|
1470
|
+
const tips = [];
|
|
1471
|
+
const ua = await page.evaluate("navigator.userAgent").catch(() => "");
|
|
1472
|
+
const outerW = await page.evaluate("window.outerWidth").catch(() => 0);
|
|
1473
|
+
const headless = /headless/i.test(ua) || outerW === 0;
|
|
1474
|
+
const publishMode = p.publish || process.env.XBROWSER_NO_HEADLESS_PUBLISH === "1";
|
|
1475
|
+
if (publishMode && headless) {
|
|
1476
|
+
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");
|
|
1477
|
+
tips.push(' \u6709\u5934 Chrome: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --user-data-dir=~/.xbrowser/chrome-profile-headed --remote-debugging-port=9222');
|
|
1478
|
+
tips.push(" \u7136\u540E\u52A0 --cdp http://localhost:9222");
|
|
1479
|
+
return fail4("PREFLIGHT-FAIL: headless \u4E0D\u5141\u8BB8\u7528\u4E8E\u53D1\u5E03\u7C7B\u4EFB\u52A1\uFF08\u7528 --cdp \u63A5\u6709\u5934 Chrome\uFF09", tips);
|
|
1480
|
+
}
|
|
1481
|
+
let pageUrl = null;
|
|
1482
|
+
try {
|
|
1483
|
+
const { fileURLToPath } = await import("url");
|
|
1484
|
+
const { join: join10, dirname: dirname3 } = await import("path");
|
|
1485
|
+
const { existsSync: existsSync4 } = await import("fs");
|
|
1486
|
+
const here = typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url);
|
|
1487
|
+
const candidates = [
|
|
1488
|
+
join10(dirname3(here), "..", "assets", "preflight.html"),
|
|
1489
|
+
join10(process.cwd(), "assets", "preflight.html")
|
|
1490
|
+
];
|
|
1491
|
+
pageUrl = candidates.find((c) => existsSync4(c)) || null;
|
|
1492
|
+
} catch {
|
|
1493
|
+
}
|
|
1494
|
+
if (pageUrl) {
|
|
1495
|
+
await page.goto("file://" + pageUrl, { waitUntil: "domcontentloaded", timeout: 15e3 });
|
|
1496
|
+
} else {
|
|
1497
|
+
await page.goto("about:blank");
|
|
1498
|
+
await page.evaluate(`(function(){
|
|
1499
|
+
var fails=[];
|
|
1500
|
+
if(navigator.webdriver!==false)fails.push('webdriver');
|
|
1501
|
+
if(/headless/i.test(navigator.userAgent))fails.push('ua-no-headless');
|
|
1502
|
+
window.__pf=fails.join(',');
|
|
1503
|
+
document.title=fails.length?'PREFLIGHT-FAIL':'PREFLIGHT-PASS';
|
|
1504
|
+
})()`);
|
|
1505
|
+
}
|
|
1506
|
+
await page.waitForTimeout(1200);
|
|
1507
|
+
const result = await page.evaluate(`(function(){
|
|
1508
|
+
var out=document.getElementById('out');
|
|
1509
|
+
return { title: document.title, fails: out ? (out.getAttribute('data-fails')||'') : (window.__pf||'') };
|
|
1510
|
+
})()`).catch(() => ({ title: "PREFLIGHT-FAIL", fails: "evaluate-error" }));
|
|
1511
|
+
const passed = result.title === "PREFLIGHT-PASS";
|
|
1512
|
+
const failed = result.fails ? result.fails.split(",").filter(Boolean) : [];
|
|
1513
|
+
tips.push(`headless=${headless}${publishMode ? "\uFF08publish \u95E8\u7981\u5F00\u542F\uFF09" : ""}`);
|
|
1514
|
+
if (passed) {
|
|
1515
|
+
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");
|
|
1516
|
+
return ok11({ gate: "pass", failed: [], headless }, tips);
|
|
1517
|
+
}
|
|
1518
|
+
tips.push(`\u5931\u8D25\u9879: ${failed.join(", ") || result.title}`);
|
|
1519
|
+
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");
|
|
1520
|
+
return fail4(`PREFLIGHT-FAIL: ${failed.join(", ") || result.title}`, tips);
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
|
|
1524
|
+
// src/commands/storage.ts
|
|
1525
|
+
import { z as z12 } from "zod";
|
|
1526
|
+
import { ok as ok12, fail as fail5 } from "@dyyz1993/xcli-core";
|
|
1455
1527
|
var getCookiesCommand = registerCommand({
|
|
1456
1528
|
name: "get-cookies",
|
|
1457
1529
|
description: "Get all cookies for the current page",
|
|
1458
1530
|
scope: "page",
|
|
1459
|
-
result:
|
|
1460
|
-
cookies:
|
|
1531
|
+
result: z12.object({
|
|
1532
|
+
cookies: z12.array(z12.record(z12.unknown()))
|
|
1461
1533
|
}),
|
|
1462
1534
|
handler: async (_p, ctx) => {
|
|
1463
1535
|
const cookies = await ctx.browserContext.cookies();
|
|
1464
|
-
return
|
|
1536
|
+
return ok12({ cookies });
|
|
1465
1537
|
}
|
|
1466
1538
|
});
|
|
1467
1539
|
var setCookieCommand = registerCommand({
|
|
1468
1540
|
name: "set-cookie",
|
|
1469
1541
|
description: "Set a cookie",
|
|
1470
1542
|
scope: "page",
|
|
1471
|
-
parameters:
|
|
1472
|
-
name:
|
|
1473
|
-
value:
|
|
1474
|
-
domain:
|
|
1475
|
-
path:
|
|
1476
|
-
url:
|
|
1477
|
-
expires:
|
|
1478
|
-
httpOnly:
|
|
1479
|
-
secure:
|
|
1480
|
-
sameSite:
|
|
1543
|
+
parameters: z12.object({
|
|
1544
|
+
name: z12.coerce.string(),
|
|
1545
|
+
value: z12.coerce.string(),
|
|
1546
|
+
domain: z12.coerce.string().optional(),
|
|
1547
|
+
path: z12.coerce.string().optional(),
|
|
1548
|
+
url: z12.string().optional().describe("Cookie URL (alternative to domain)"),
|
|
1549
|
+
expires: z12.number().optional(),
|
|
1550
|
+
httpOnly: z12.boolean().optional(),
|
|
1551
|
+
secure: z12.boolean().optional(),
|
|
1552
|
+
sameSite: z12.enum(["Strict", "Lax", "None"]).optional()
|
|
1481
1553
|
}),
|
|
1482
|
-
result:
|
|
1554
|
+
result: z12.object({ name: z12.string() }),
|
|
1483
1555
|
handler: async (p, ctx) => {
|
|
1484
1556
|
const cookie = { ...p };
|
|
1485
1557
|
if (!cookie.domain && !cookie.url) {
|
|
@@ -1494,38 +1566,38 @@ var setCookieCommand = registerCommand({
|
|
|
1494
1566
|
}
|
|
1495
1567
|
}
|
|
1496
1568
|
if (!cookie.domain && !cookie.url) {
|
|
1497
|
-
return
|
|
1569
|
+
return fail5("set-cookie requires --domain or --url, or a non-blank page URL to infer from");
|
|
1498
1570
|
}
|
|
1499
1571
|
await ctx.browserContext.addCookies([cookie]);
|
|
1500
|
-
return
|
|
1572
|
+
return ok12({ name: p.name });
|
|
1501
1573
|
}
|
|
1502
1574
|
});
|
|
1503
1575
|
var clearCookiesCommand = registerCommand({
|
|
1504
1576
|
name: "clear-cookies",
|
|
1505
1577
|
description: "Clear all cookies",
|
|
1506
1578
|
scope: "page",
|
|
1507
|
-
result:
|
|
1579
|
+
result: z12.object({ cleared: z12.boolean() }),
|
|
1508
1580
|
handler: async (_p, ctx) => {
|
|
1509
1581
|
await ctx.browserContext.clearCookies();
|
|
1510
|
-
return
|
|
1582
|
+
return ok12({ cleared: true });
|
|
1511
1583
|
}
|
|
1512
1584
|
});
|
|
1513
1585
|
var getLocalStorageCommand = registerCommand({
|
|
1514
1586
|
name: "get-local-storage",
|
|
1515
1587
|
description: "Get localStorage entries",
|
|
1516
1588
|
scope: "page",
|
|
1517
|
-
parameters:
|
|
1518
|
-
key:
|
|
1589
|
+
parameters: z12.object({
|
|
1590
|
+
key: z12.string().optional()
|
|
1519
1591
|
}),
|
|
1520
|
-
result:
|
|
1521
|
-
|
|
1522
|
-
|
|
1592
|
+
result: z12.union([
|
|
1593
|
+
z12.object({ key: z12.string(), value: z12.string().nullable() }),
|
|
1594
|
+
z12.object({ data: z12.record(z12.string()) })
|
|
1523
1595
|
]),
|
|
1524
1596
|
handler: async (p, ctx) => {
|
|
1525
1597
|
try {
|
|
1526
1598
|
if (p.key) {
|
|
1527
1599
|
const value = await ctx.page.evaluate((k) => localStorage.getItem(k), p.key);
|
|
1528
|
-
return
|
|
1600
|
+
return ok12({ key: p.key, value });
|
|
1529
1601
|
}
|
|
1530
1602
|
const data = await ctx.page.evaluate(() => {
|
|
1531
1603
|
const entries = {};
|
|
@@ -1535,9 +1607,9 @@ var getLocalStorageCommand = registerCommand({
|
|
|
1535
1607
|
}
|
|
1536
1608
|
return entries;
|
|
1537
1609
|
});
|
|
1538
|
-
return
|
|
1610
|
+
return ok12({ data });
|
|
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,11 +1617,11 @@ var setLocalStorageCommand = registerCommand({
|
|
|
1545
1617
|
name: "set-local-storage",
|
|
1546
1618
|
description: "Set a localStorage entry",
|
|
1547
1619
|
scope: "page",
|
|
1548
|
-
parameters:
|
|
1549
|
-
key:
|
|
1550
|
-
value:
|
|
1620
|
+
parameters: z12.object({
|
|
1621
|
+
key: z12.string(),
|
|
1622
|
+
value: z12.string()
|
|
1551
1623
|
}),
|
|
1552
|
-
result:
|
|
1624
|
+
result: z12.object({ key: z12.string() }),
|
|
1553
1625
|
handler: async (p, ctx) => {
|
|
1554
1626
|
try {
|
|
1555
1627
|
await ctx.page.evaluate(
|
|
@@ -1558,9 +1630,9 @@ var setLocalStorageCommand = registerCommand({
|
|
|
1558
1630
|
},
|
|
1559
1631
|
{ key: p.key, value: p.value }
|
|
1560
1632
|
);
|
|
1561
|
-
return
|
|
1633
|
+
return ok12({ key: p.key });
|
|
1562
1634
|
} catch (e) {
|
|
1563
|
-
return
|
|
1635
|
+
return fail5(`localStorage not accessible on this page: ${e instanceof Error ? e.message : String(e)}`);
|
|
1564
1636
|
}
|
|
1565
1637
|
}
|
|
1566
1638
|
});
|
|
@@ -1568,20 +1640,20 @@ var clearLocalStorageCommand = registerCommand({
|
|
|
1568
1640
|
name: "clear-local-storage",
|
|
1569
1641
|
description: "Clear all localStorage entries",
|
|
1570
1642
|
scope: "page",
|
|
1571
|
-
result:
|
|
1643
|
+
result: z12.object({ cleared: z12.boolean() }),
|
|
1572
1644
|
handler: async (_p, ctx) => {
|
|
1573
1645
|
try {
|
|
1574
1646
|
await ctx.page.evaluate(() => localStorage.clear());
|
|
1575
|
-
return
|
|
1647
|
+
return ok12({ cleared: true });
|
|
1576
1648
|
} catch (e) {
|
|
1577
|
-
return
|
|
1649
|
+
return fail5(`localStorage not accessible on this page: ${e instanceof Error ? e.message : String(e)}`);
|
|
1578
1650
|
}
|
|
1579
1651
|
}
|
|
1580
1652
|
});
|
|
1581
1653
|
|
|
1582
1654
|
// src/commands/screenshot.ts
|
|
1583
|
-
import { z as
|
|
1584
|
-
import { ok as
|
|
1655
|
+
import { z as z13 } from "zod";
|
|
1656
|
+
import { ok as ok13, fail as fail6 } from "@dyyz1993/xcli-core";
|
|
1585
1657
|
import { writeFileSync, mkdirSync } from "fs";
|
|
1586
1658
|
import { dirname, join as join4 } from "path";
|
|
1587
1659
|
function ensureScreenshotsDir() {
|
|
@@ -1608,23 +1680,23 @@ var screenshotCommand = registerCommand({
|
|
|
1608
1680
|
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>)",
|
|
1609
1681
|
scope: "page",
|
|
1610
1682
|
selectorParams: ["selector"],
|
|
1611
|
-
parameters:
|
|
1612
|
-
selector:
|
|
1613
|
-
type:
|
|
1614
|
-
fullPage:
|
|
1615
|
-
output:
|
|
1616
|
-
base64:
|
|
1683
|
+
parameters: z13.object({
|
|
1684
|
+
selector: z13.string().optional(),
|
|
1685
|
+
type: z13.enum(["png", "jpeg"]).optional(),
|
|
1686
|
+
fullPage: z13.boolean().optional(),
|
|
1687
|
+
output: z13.string().optional(),
|
|
1688
|
+
base64: z13.boolean().optional().describe("Return base64 data instead of file path")
|
|
1617
1689
|
}),
|
|
1618
|
-
result:
|
|
1619
|
-
|
|
1620
|
-
data:
|
|
1621
|
-
format:
|
|
1622
|
-
size:
|
|
1690
|
+
result: z13.union([
|
|
1691
|
+
z13.object({
|
|
1692
|
+
data: z13.string(),
|
|
1693
|
+
format: z13.string(),
|
|
1694
|
+
size: z13.number()
|
|
1623
1695
|
}),
|
|
1624
|
-
|
|
1625
|
-
output:
|
|
1626
|
-
format:
|
|
1627
|
-
size:
|
|
1696
|
+
z13.object({
|
|
1697
|
+
output: z13.string(),
|
|
1698
|
+
format: z13.string(),
|
|
1699
|
+
size: z13.number()
|
|
1628
1700
|
})
|
|
1629
1701
|
]),
|
|
1630
1702
|
handler: async (p, ctx) => {
|
|
@@ -1642,21 +1714,21 @@ var screenshotCommand = registerCommand({
|
|
|
1642
1714
|
if (p.output) {
|
|
1643
1715
|
const dirErr = ensureParentDir(p.output);
|
|
1644
1716
|
if (dirErr) {
|
|
1645
|
-
return
|
|
1717
|
+
return fail6(`Cannot create directory for --output "${p.output}": ${dirErr}`);
|
|
1646
1718
|
}
|
|
1647
1719
|
try {
|
|
1648
1720
|
writeFileSync(p.output, buffer, "binary");
|
|
1649
1721
|
} catch (err) {
|
|
1650
|
-
return
|
|
1722
|
+
return fail6(`Failed to write screenshot to "${p.output}": ${err instanceof Error ? err.message : String(err)}`);
|
|
1651
1723
|
}
|
|
1652
|
-
return
|
|
1724
|
+
return ok13({
|
|
1653
1725
|
output: p.output,
|
|
1654
1726
|
format,
|
|
1655
1727
|
size: buffer.length
|
|
1656
1728
|
});
|
|
1657
1729
|
}
|
|
1658
1730
|
if (p.base64) {
|
|
1659
|
-
return
|
|
1731
|
+
return ok13({
|
|
1660
1732
|
data: buffer.toString("base64"),
|
|
1661
1733
|
format,
|
|
1662
1734
|
size: buffer.length
|
|
@@ -1665,7 +1737,7 @@ var screenshotCommand = registerCommand({
|
|
|
1665
1737
|
ensureScreenshotsDir();
|
|
1666
1738
|
const screenshotPath = generateScreenshotPath(format);
|
|
1667
1739
|
writeFileSync(screenshotPath, buffer, "binary");
|
|
1668
|
-
return
|
|
1740
|
+
return ok13({
|
|
1669
1741
|
output: screenshotPath,
|
|
1670
1742
|
format,
|
|
1671
1743
|
size: buffer.length
|
|
@@ -1674,19 +1746,19 @@ var screenshotCommand = registerCommand({
|
|
|
1674
1746
|
});
|
|
1675
1747
|
|
|
1676
1748
|
// src/commands/structure.ts
|
|
1677
|
-
import { z as
|
|
1678
|
-
import { ok as
|
|
1749
|
+
import { z as z14 } from "zod";
|
|
1750
|
+
import { ok as ok14 } from "@dyyz1993/xcli-core";
|
|
1679
1751
|
var structureCommand = registerCommand({
|
|
1680
1752
|
name: "structure",
|
|
1681
1753
|
description: "Get the DOM structure of the page or an element",
|
|
1682
1754
|
scope: "page",
|
|
1683
1755
|
selectorParams: ["selector"],
|
|
1684
|
-
parameters:
|
|
1685
|
-
selector:
|
|
1686
|
-
depth:
|
|
1756
|
+
parameters: z14.object({
|
|
1757
|
+
selector: z14.string().optional(),
|
|
1758
|
+
depth: z14.number().optional()
|
|
1687
1759
|
}),
|
|
1688
|
-
result:
|
|
1689
|
-
structure:
|
|
1760
|
+
result: z14.object({
|
|
1761
|
+
structure: z14.record(z14.unknown())
|
|
1690
1762
|
}),
|
|
1691
1763
|
handler: async (p, ctx) => {
|
|
1692
1764
|
const structure = await ctx.page.evaluate(
|
|
@@ -1718,30 +1790,30 @@ var structureCommand = registerCommand({
|
|
|
1718
1790
|
},
|
|
1719
1791
|
{ sel: p.selector || "body", maxDepth: p.depth || 5 }
|
|
1720
1792
|
);
|
|
1721
|
-
return
|
|
1793
|
+
return ok14({ structure });
|
|
1722
1794
|
}
|
|
1723
1795
|
});
|
|
1724
1796
|
|
|
1725
1797
|
// src/commands/viewport.ts
|
|
1726
|
-
import { z as
|
|
1727
|
-
import { ok as
|
|
1798
|
+
import { z as z15 } from "zod";
|
|
1799
|
+
import { ok as ok15 } from "@dyyz1993/xcli-core";
|
|
1728
1800
|
var setViewportCommand = registerCommand({
|
|
1729
1801
|
name: "set-viewport",
|
|
1730
1802
|
description: "Set the viewport size and properties",
|
|
1731
1803
|
scope: "browser",
|
|
1732
|
-
parameters:
|
|
1733
|
-
width:
|
|
1734
|
-
height:
|
|
1735
|
-
deviceScaleFactor:
|
|
1736
|
-
isMobile:
|
|
1737
|
-
hasTouch:
|
|
1804
|
+
parameters: z15.object({
|
|
1805
|
+
width: z15.coerce.number(),
|
|
1806
|
+
height: z15.coerce.number(),
|
|
1807
|
+
deviceScaleFactor: z15.coerce.number().optional(),
|
|
1808
|
+
isMobile: z15.boolean().optional(),
|
|
1809
|
+
hasTouch: z15.boolean().optional()
|
|
1738
1810
|
}),
|
|
1739
|
-
result:
|
|
1740
|
-
width:
|
|
1741
|
-
height:
|
|
1742
|
-
deviceScaleFactor:
|
|
1743
|
-
isMobile:
|
|
1744
|
-
hasTouch:
|
|
1811
|
+
result: z15.object({
|
|
1812
|
+
width: z15.number(),
|
|
1813
|
+
height: z15.number(),
|
|
1814
|
+
deviceScaleFactor: z15.number().optional(),
|
|
1815
|
+
isMobile: z15.boolean().optional(),
|
|
1816
|
+
hasTouch: z15.boolean().optional()
|
|
1745
1817
|
}),
|
|
1746
1818
|
handler: async (p, ctx) => {
|
|
1747
1819
|
const viewport = ctx.page.viewportSize();
|
|
@@ -1754,7 +1826,7 @@ var setViewportCommand = registerCommand({
|
|
|
1754
1826
|
...p.isMobile !== void 0 && { isMobile: p.isMobile },
|
|
1755
1827
|
...p.hasTouch !== void 0 && { hasTouch: p.hasTouch }
|
|
1756
1828
|
});
|
|
1757
|
-
return
|
|
1829
|
+
return ok15({
|
|
1758
1830
|
width,
|
|
1759
1831
|
height,
|
|
1760
1832
|
...p.deviceScaleFactor !== void 0 && { deviceScaleFactor: p.deviceScaleFactor },
|
|
@@ -1765,17 +1837,17 @@ var setViewportCommand = registerCommand({
|
|
|
1765
1837
|
});
|
|
1766
1838
|
|
|
1767
1839
|
// src/commands/frame.ts
|
|
1768
|
-
import { z as
|
|
1769
|
-
import { ok as
|
|
1840
|
+
import { z as z16 } from "zod";
|
|
1841
|
+
import { ok as ok16, fail as fail7 } from "@dyyz1993/xcli-core";
|
|
1770
1842
|
var framesCommand = registerCommand({
|
|
1771
1843
|
name: "frames",
|
|
1772
1844
|
description: "List all frames in the current page",
|
|
1773
1845
|
scope: "page",
|
|
1774
|
-
result:
|
|
1775
|
-
frames:
|
|
1776
|
-
index:
|
|
1777
|
-
name:
|
|
1778
|
-
url:
|
|
1846
|
+
result: z16.object({
|
|
1847
|
+
frames: z16.array(z16.object({
|
|
1848
|
+
index: z16.number(),
|
|
1849
|
+
name: z16.string().nullable(),
|
|
1850
|
+
url: z16.string()
|
|
1779
1851
|
}))
|
|
1780
1852
|
}),
|
|
1781
1853
|
handler: async (_p, ctx) => {
|
|
@@ -1786,21 +1858,21 @@ var framesCommand = registerCommand({
|
|
|
1786
1858
|
name: frame.name(),
|
|
1787
1859
|
url: frame.url()
|
|
1788
1860
|
}));
|
|
1789
|
-
return
|
|
1861
|
+
return ok16({ frames: frameList });
|
|
1790
1862
|
}
|
|
1791
1863
|
});
|
|
1792
1864
|
var frameCommand = registerCommand({
|
|
1793
1865
|
name: "frame",
|
|
1794
1866
|
description: "Get frame info by index or name",
|
|
1795
1867
|
scope: "page",
|
|
1796
|
-
parameters:
|
|
1797
|
-
index:
|
|
1798
|
-
name:
|
|
1868
|
+
parameters: z16.object({
|
|
1869
|
+
index: z16.number().int().min(0).optional(),
|
|
1870
|
+
name: z16.string().optional()
|
|
1799
1871
|
}),
|
|
1800
|
-
result:
|
|
1801
|
-
name:
|
|
1802
|
-
url:
|
|
1803
|
-
error:
|
|
1872
|
+
result: z16.object({
|
|
1873
|
+
name: z16.string().nullable(),
|
|
1874
|
+
url: z16.string(),
|
|
1875
|
+
error: z16.string().optional()
|
|
1804
1876
|
}),
|
|
1805
1877
|
handler: async (p, ctx) => {
|
|
1806
1878
|
const discover = ctx.page.discoverFrames;
|
|
@@ -1811,12 +1883,12 @@ var frameCommand = registerCommand({
|
|
|
1811
1883
|
} else if (p.name !== void 0) {
|
|
1812
1884
|
targetFrame = rawFrames.find((f) => f.name() === p.name);
|
|
1813
1885
|
} else {
|
|
1814
|
-
return
|
|
1886
|
+
return fail7("Must provide index or name");
|
|
1815
1887
|
}
|
|
1816
1888
|
if (!targetFrame) {
|
|
1817
|
-
return
|
|
1889
|
+
return fail7("Frame not found");
|
|
1818
1890
|
}
|
|
1819
|
-
return
|
|
1891
|
+
return ok16({
|
|
1820
1892
|
name: targetFrame.name(),
|
|
1821
1893
|
url: targetFrame.url()
|
|
1822
1894
|
});
|
|
@@ -1824,27 +1896,27 @@ var frameCommand = registerCommand({
|
|
|
1824
1896
|
});
|
|
1825
1897
|
|
|
1826
1898
|
// src/commands/ui-debug.ts
|
|
1827
|
-
import { z as
|
|
1828
|
-
import { ok as
|
|
1899
|
+
import { z as z17 } from "zod";
|
|
1900
|
+
import { ok as ok17 } from "@dyyz1993/xcli-core";
|
|
1829
1901
|
var consoleCheckCommand = registerCommand({
|
|
1830
1902
|
name: "console",
|
|
1831
1903
|
description: "Collect and analyze browser console messages (errors, warnings, logs)",
|
|
1832
1904
|
scope: "page",
|
|
1833
|
-
parameters:
|
|
1834
|
-
url:
|
|
1835
|
-
duration:
|
|
1836
|
-
filter:
|
|
1837
|
-
includeStackTraces:
|
|
1905
|
+
parameters: z17.object({
|
|
1906
|
+
url: z17.string().optional().describe("URL to navigate first (optional, uses current page if omitted)"),
|
|
1907
|
+
duration: z17.number().optional().default(5e3).describe("How long to collect messages (ms)"),
|
|
1908
|
+
filter: z17.enum(["all", "error", "warning", "info", "log"]).optional().default("all"),
|
|
1909
|
+
includeStackTraces: z17.boolean().optional().default(true)
|
|
1838
1910
|
}),
|
|
1839
|
-
result:
|
|
1840
|
-
url:
|
|
1841
|
-
duration:
|
|
1842
|
-
total:
|
|
1843
|
-
errors:
|
|
1844
|
-
warnings:
|
|
1845
|
-
messages:
|
|
1846
|
-
summary:
|
|
1847
|
-
passed:
|
|
1911
|
+
result: z17.object({
|
|
1912
|
+
url: z17.string(),
|
|
1913
|
+
duration: z17.number(),
|
|
1914
|
+
total: z17.number(),
|
|
1915
|
+
errors: z17.number(),
|
|
1916
|
+
warnings: z17.number(),
|
|
1917
|
+
messages: z17.array(z17.record(z17.unknown())),
|
|
1918
|
+
summary: z17.string(),
|
|
1919
|
+
passed: z17.boolean()
|
|
1848
1920
|
}),
|
|
1849
1921
|
handler: async (p, ctx) => {
|
|
1850
1922
|
const { page } = ctx;
|
|
@@ -1926,7 +1998,7 @@ ${a.stack || ""}`;
|
|
|
1926
1998
|
const filtered = p.filter === "all" ? messages : messages.filter((m) => m.type === p.filter);
|
|
1927
1999
|
const errorCount = messages.filter((m) => m.type === "error").length;
|
|
1928
2000
|
const warnCount = messages.filter((m) => m.type === "warning").length;
|
|
1929
|
-
return
|
|
2001
|
+
return ok17({
|
|
1930
2002
|
url: page.url(),
|
|
1931
2003
|
duration: p.duration,
|
|
1932
2004
|
total: messages.length,
|
|
@@ -1942,23 +2014,23 @@ var networkCheckCommand = registerCommand({
|
|
|
1942
2014
|
name: "net-debug",
|
|
1943
2015
|
description: "Monitor and analyze network requests \u2014 capture failed requests, slow responses, status codes",
|
|
1944
2016
|
scope: "page",
|
|
1945
|
-
parameters:
|
|
1946
|
-
url:
|
|
1947
|
-
duration:
|
|
1948
|
-
filter:
|
|
1949
|
-
slowThreshold:
|
|
2017
|
+
parameters: z17.object({
|
|
2018
|
+
url: z17.string().optional().describe("URL to navigate first"),
|
|
2019
|
+
duration: z17.number().optional().default(5e3).describe("How long to monitor (ms)"),
|
|
2020
|
+
filter: z17.enum(["all", "failed", "slow", "error", "xhr", "fetch", "document", "stylesheet", "script", "image"]).optional().default("all"),
|
|
2021
|
+
slowThreshold: z17.number().optional().default(3e3).describe('Threshold for "slow" requests (ms)')
|
|
1950
2022
|
}),
|
|
1951
|
-
result:
|
|
1952
|
-
url:
|
|
1953
|
-
duration:
|
|
1954
|
-
totalRequests:
|
|
1955
|
-
failedRequests:
|
|
1956
|
-
slowRequests:
|
|
1957
|
-
errorRequests:
|
|
1958
|
-
totalSizeKB:
|
|
1959
|
-
requests:
|
|
1960
|
-
summary:
|
|
1961
|
-
passed:
|
|
2023
|
+
result: z17.object({
|
|
2024
|
+
url: z17.string(),
|
|
2025
|
+
duration: z17.number(),
|
|
2026
|
+
totalRequests: z17.number(),
|
|
2027
|
+
failedRequests: z17.number(),
|
|
2028
|
+
slowRequests: z17.number(),
|
|
2029
|
+
errorRequests: z17.number(),
|
|
2030
|
+
totalSizeKB: z17.number(),
|
|
2031
|
+
requests: z17.array(z17.record(z17.unknown())),
|
|
2032
|
+
summary: z17.string(),
|
|
2033
|
+
passed: z17.boolean()
|
|
1962
2034
|
}),
|
|
1963
2035
|
handler: async (p, ctx) => {
|
|
1964
2036
|
const { page } = ctx;
|
|
@@ -2040,7 +2112,7 @@ var networkCheckCommand = registerCommand({
|
|
|
2040
2112
|
const slowCount = requests.filter((r) => r.duration >= p.slowThreshold).length;
|
|
2041
2113
|
const errorCount = requests.filter((r) => r.error).length;
|
|
2042
2114
|
const totalSize = requests.reduce((sum, r) => sum + r.size, 0);
|
|
2043
|
-
return
|
|
2115
|
+
return ok17({
|
|
2044
2116
|
url: page.url(),
|
|
2045
2117
|
duration: p.duration,
|
|
2046
2118
|
totalRequests: requests.length,
|
|
@@ -2062,17 +2134,17 @@ var perfCheckCommand = registerCommand({
|
|
|
2062
2134
|
name: "perf",
|
|
2063
2135
|
description: "Audit page performance metrics \u2014 load time, FCP, LCP, CLS, TTFB, resource sizes",
|
|
2064
2136
|
scope: "page",
|
|
2065
|
-
parameters:
|
|
2066
|
-
url:
|
|
2067
|
-
iterations:
|
|
2137
|
+
parameters: z17.object({
|
|
2138
|
+
url: z17.string().optional().describe("URL to navigate (uses current page if omitted)"),
|
|
2139
|
+
iterations: z17.number().optional().default(1).describe("Number of iterations to average")
|
|
2068
2140
|
}),
|
|
2069
|
-
result:
|
|
2070
|
-
url:
|
|
2071
|
-
iterations:
|
|
2072
|
-
metrics:
|
|
2073
|
-
allIterations:
|
|
2074
|
-
passed:
|
|
2075
|
-
summary:
|
|
2141
|
+
result: z17.object({
|
|
2142
|
+
url: z17.string(),
|
|
2143
|
+
iterations: z17.number(),
|
|
2144
|
+
metrics: z17.record(z17.unknown()),
|
|
2145
|
+
allIterations: z17.array(z17.record(z17.unknown())).optional(),
|
|
2146
|
+
passed: z17.boolean(),
|
|
2147
|
+
summary: z17.string()
|
|
2076
2148
|
}),
|
|
2077
2149
|
handler: async (p, ctx) => {
|
|
2078
2150
|
const { page } = ctx;
|
|
@@ -2134,7 +2206,7 @@ var perfCheckCommand = registerCommand({
|
|
|
2134
2206
|
if (resourceStats) avg.resourceStats = resourceStats;
|
|
2135
2207
|
return avg;
|
|
2136
2208
|
})();
|
|
2137
|
-
return
|
|
2209
|
+
return ok17({
|
|
2138
2210
|
url: page.url(),
|
|
2139
2211
|
iterations: p.iterations,
|
|
2140
2212
|
metrics: avgMetrics,
|
|
@@ -2148,23 +2220,23 @@ var healthCheckCommand = registerCommand({
|
|
|
2148
2220
|
name: "health",
|
|
2149
2221
|
description: "Comprehensive page health check \u2014 broken links, missing images, console errors, SEO issues",
|
|
2150
2222
|
scope: "page",
|
|
2151
|
-
parameters:
|
|
2152
|
-
url:
|
|
2153
|
-
checkLinks:
|
|
2154
|
-
checkImages:
|
|
2155
|
-
checkMeta:
|
|
2156
|
-
maxLinks:
|
|
2223
|
+
parameters: z17.object({
|
|
2224
|
+
url: z17.string().optional().describe("URL to check"),
|
|
2225
|
+
checkLinks: z17.boolean().optional().default(true).describe("Check for broken links"),
|
|
2226
|
+
checkImages: z17.boolean().optional().default(true).describe("Check for missing/broken images"),
|
|
2227
|
+
checkMeta: z17.boolean().optional().default(true).describe("Check SEO meta tags"),
|
|
2228
|
+
maxLinks: z17.number().optional().default(50).describe("Max links to check")
|
|
2157
2229
|
}),
|
|
2158
|
-
result:
|
|
2159
|
-
url:
|
|
2160
|
-
title:
|
|
2161
|
-
passed:
|
|
2162
|
-
totalIssues:
|
|
2163
|
-
errors:
|
|
2164
|
-
warnings:
|
|
2165
|
-
info:
|
|
2166
|
-
issues:
|
|
2167
|
-
summary:
|
|
2230
|
+
result: z17.object({
|
|
2231
|
+
url: z17.string(),
|
|
2232
|
+
title: z17.string(),
|
|
2233
|
+
passed: z17.boolean(),
|
|
2234
|
+
totalIssues: z17.number(),
|
|
2235
|
+
errors: z17.number(),
|
|
2236
|
+
warnings: z17.number(),
|
|
2237
|
+
info: z17.number(),
|
|
2238
|
+
issues: z17.array(z17.record(z17.unknown())),
|
|
2239
|
+
summary: z17.string()
|
|
2168
2240
|
}),
|
|
2169
2241
|
handler: async (p, ctx) => {
|
|
2170
2242
|
const { page } = ctx;
|
|
@@ -2251,7 +2323,7 @@ var healthCheckCommand = registerCommand({
|
|
|
2251
2323
|
}, { checkLinks: p.checkLinks, checkImages: p.checkImages, checkMeta: p.checkMeta, maxLinks: p.maxLinks });
|
|
2252
2324
|
const errors = result.issues.filter((i) => i.severity === "error").length;
|
|
2253
2325
|
const warnings = result.issues.filter((i) => i.severity === "warning").length;
|
|
2254
|
-
return
|
|
2326
|
+
return ok17({
|
|
2255
2327
|
url: result.url,
|
|
2256
2328
|
title: result.title,
|
|
2257
2329
|
passed: errors === 0,
|
|
@@ -2266,8 +2338,8 @@ var healthCheckCommand = registerCommand({
|
|
|
2266
2338
|
});
|
|
2267
2339
|
|
|
2268
2340
|
// src/commands/actions.ts
|
|
2269
|
-
import { z as
|
|
2270
|
-
import { ok as
|
|
2341
|
+
import { z as z18 } from "zod";
|
|
2342
|
+
import { ok as ok18 } from "@dyyz1993/xcli-core";
|
|
2271
2343
|
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
2272
2344
|
import { join as join5 } from "path";
|
|
2273
2345
|
function ensureScreenshotsDir2() {
|
|
@@ -2279,53 +2351,53 @@ function generateScreenshotPath2(format) {
|
|
|
2279
2351
|
const ext = format === "jpeg" ? "jpg" : "png";
|
|
2280
2352
|
return join5(resolveScreenshotsDir(), `screenshot-${timestamp}-${random}.${ext}`);
|
|
2281
2353
|
}
|
|
2282
|
-
var waitActionSchema =
|
|
2283
|
-
type:
|
|
2284
|
-
milliseconds:
|
|
2285
|
-
selector:
|
|
2354
|
+
var waitActionSchema = z18.object({
|
|
2355
|
+
type: z18.literal("wait"),
|
|
2356
|
+
milliseconds: z18.number().positive().optional(),
|
|
2357
|
+
selector: z18.string().optional()
|
|
2286
2358
|
}).refine(
|
|
2287
2359
|
(d) => (d.milliseconds !== void 0 || d.selector !== void 0) && !(d.milliseconds !== void 0 && d.selector !== void 0),
|
|
2288
2360
|
{ message: "Either 'milliseconds' or 'selector' must be provided, but not both." }
|
|
2289
2361
|
);
|
|
2290
|
-
var clickActionSchema =
|
|
2291
|
-
type:
|
|
2292
|
-
selector:
|
|
2293
|
-
all:
|
|
2362
|
+
var clickActionSchema = z18.object({
|
|
2363
|
+
type: z18.literal("click"),
|
|
2364
|
+
selector: z18.string(),
|
|
2365
|
+
all: z18.boolean().optional()
|
|
2294
2366
|
});
|
|
2295
|
-
var screenshotActionSchema =
|
|
2296
|
-
type:
|
|
2297
|
-
fullPage:
|
|
2298
|
-
quality:
|
|
2299
|
-
viewport:
|
|
2300
|
-
base64:
|
|
2367
|
+
var screenshotActionSchema = z18.object({
|
|
2368
|
+
type: z18.literal("screenshot"),
|
|
2369
|
+
fullPage: z18.boolean().optional(),
|
|
2370
|
+
quality: z18.number().min(1).max(100).optional(),
|
|
2371
|
+
viewport: z18.object({ width: z18.number().int().positive(), height: z18.number().int().positive() }).optional(),
|
|
2372
|
+
base64: z18.boolean().optional().describe("Return base64 data instead of file path")
|
|
2301
2373
|
});
|
|
2302
|
-
var writeActionSchema =
|
|
2303
|
-
type:
|
|
2304
|
-
text:
|
|
2374
|
+
var writeActionSchema = z18.object({
|
|
2375
|
+
type: z18.literal("write"),
|
|
2376
|
+
text: z18.string()
|
|
2305
2377
|
});
|
|
2306
|
-
var pressActionSchema =
|
|
2307
|
-
type:
|
|
2308
|
-
key:
|
|
2378
|
+
var pressActionSchema = z18.object({
|
|
2379
|
+
type: z18.literal("press"),
|
|
2380
|
+
key: z18.string()
|
|
2309
2381
|
});
|
|
2310
|
-
var scrollActionSchema =
|
|
2311
|
-
type:
|
|
2312
|
-
direction:
|
|
2313
|
-
selector:
|
|
2382
|
+
var scrollActionSchema = z18.object({
|
|
2383
|
+
type: z18.literal("scroll"),
|
|
2384
|
+
direction: z18.enum(["up", "down"]).optional(),
|
|
2385
|
+
selector: z18.string().optional()
|
|
2314
2386
|
});
|
|
2315
|
-
var scrapeActionSchema =
|
|
2316
|
-
type:
|
|
2387
|
+
var scrapeActionSchema = z18.object({
|
|
2388
|
+
type: z18.literal("scrape")
|
|
2317
2389
|
});
|
|
2318
|
-
var executeJavascriptActionSchema =
|
|
2319
|
-
type:
|
|
2320
|
-
script:
|
|
2390
|
+
var executeJavascriptActionSchema = z18.object({
|
|
2391
|
+
type: z18.literal("executeJavascript"),
|
|
2392
|
+
script: z18.string()
|
|
2321
2393
|
});
|
|
2322
|
-
var pdfActionSchema =
|
|
2323
|
-
type:
|
|
2324
|
-
landscape:
|
|
2325
|
-
scale:
|
|
2326
|
-
format:
|
|
2394
|
+
var pdfActionSchema = z18.object({
|
|
2395
|
+
type: z18.literal("pdf"),
|
|
2396
|
+
landscape: z18.boolean().optional(),
|
|
2397
|
+
scale: z18.number().optional(),
|
|
2398
|
+
format: z18.enum(["A0", "A1", "A2", "A3", "A4", "A5", "A6", "Letter", "Legal", "Tabloid", "Ledger"]).optional()
|
|
2327
2399
|
});
|
|
2328
|
-
var actionSchema =
|
|
2400
|
+
var actionSchema = z18.union([
|
|
2329
2401
|
waitActionSchema,
|
|
2330
2402
|
clickActionSchema,
|
|
2331
2403
|
screenshotActionSchema,
|
|
@@ -2416,11 +2488,11 @@ var actionsCommand = registerCommand({
|
|
|
2416
2488
|
name: "actions",
|
|
2417
2489
|
description: "Execute a sequence of actions (wait, click, scroll, screenshot, fill, etc.)",
|
|
2418
2490
|
scope: "page",
|
|
2419
|
-
parameters:
|
|
2420
|
-
url:
|
|
2421
|
-
actions:
|
|
2422
|
-
output:
|
|
2423
|
-
timeout:
|
|
2491
|
+
parameters: z18.object({
|
|
2492
|
+
url: z18.string().describe("Starting URL"),
|
|
2493
|
+
actions: z18.array(actionSchema).max(MAX_ACTIONS).describe("Array of actions (max 50)"),
|
|
2494
|
+
output: z18.enum(["text", "json"]).default("json").describe("Output format: text or json"),
|
|
2495
|
+
timeout: z18.number().default(60).describe("Overall timeout in seconds (default: 60)")
|
|
2424
2496
|
}),
|
|
2425
2497
|
handler: async (p, ctx) => {
|
|
2426
2498
|
await ctx.page.goto(p.url, { waitUntil: "domcontentloaded" });
|
|
@@ -2440,14 +2512,14 @@ var actionsCommand = registerCommand({
|
|
|
2440
2512
|
const finalUrl = ctx.page.url();
|
|
2441
2513
|
const timedOut = results.length < p.actions.length;
|
|
2442
2514
|
if (p.output === "text") {
|
|
2443
|
-
return
|
|
2515
|
+
return ok18({
|
|
2444
2516
|
title,
|
|
2445
2517
|
url: finalUrl,
|
|
2446
2518
|
actions: results.map((r) => JSON.stringify(r)).join("\n"),
|
|
2447
2519
|
...timedOut ? { warning: `Timed out after ${p.timeout}s, completed ${results.length}/${p.actions.length} actions` } : {}
|
|
2448
2520
|
});
|
|
2449
2521
|
}
|
|
2450
|
-
return
|
|
2522
|
+
return ok18({
|
|
2451
2523
|
title,
|
|
2452
2524
|
url: finalUrl,
|
|
2453
2525
|
results,
|
|
@@ -2457,8 +2529,8 @@ var actionsCommand = registerCommand({
|
|
|
2457
2529
|
});
|
|
2458
2530
|
|
|
2459
2531
|
// src/commands/scrape.ts
|
|
2460
|
-
import { z as
|
|
2461
|
-
import { ok as
|
|
2532
|
+
import { z as z19 } from "zod";
|
|
2533
|
+
import { ok as ok19, fail as fail8 } from "@dyyz1993/xcli-core";
|
|
2462
2534
|
|
|
2463
2535
|
// src/lib/html-to-markdown.ts
|
|
2464
2536
|
import * as cheerio from "cheerio";
|
|
@@ -2843,15 +2915,15 @@ var scrapeCommand = registerCommand({
|
|
|
2843
2915
|
description: "Scrape a page and convert to Markdown (with JS rendering)",
|
|
2844
2916
|
scope: "project",
|
|
2845
2917
|
selectorParams: ["selector"],
|
|
2846
|
-
parameters:
|
|
2847
|
-
url:
|
|
2848
|
-
selector:
|
|
2849
|
-
timeout:
|
|
2850
|
-
format:
|
|
2851
|
-
onlyMainContent:
|
|
2852
|
-
retries:
|
|
2853
|
-
waitAfterLoad:
|
|
2854
|
-
mode:
|
|
2918
|
+
parameters: z19.object({
|
|
2919
|
+
url: z19.string().optional(),
|
|
2920
|
+
selector: z19.string().optional(),
|
|
2921
|
+
timeout: z19.number().default(3e4),
|
|
2922
|
+
format: z19.enum(["markdown", "html", "text"]).default("markdown"),
|
|
2923
|
+
onlyMainContent: z19.boolean().default(true),
|
|
2924
|
+
retries: z19.number().int().min(0).max(5).optional().default(2).describe("\u91CD\u8BD5\u6B21\u6570\uFF08\u9ED8\u8BA4 2\uFF09"),
|
|
2925
|
+
waitAfterLoad: z19.number().int().optional().default(0).describe("\u9875\u9762\u52A0\u8F7D\u540E\u989D\u5916\u7B49\u5F85\u6BEB\u79D2"),
|
|
2926
|
+
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")
|
|
2855
2927
|
}),
|
|
2856
2928
|
handler: async (p, ctx) => {
|
|
2857
2929
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
@@ -2859,7 +2931,7 @@ var scrapeCommand = registerCommand({
|
|
|
2859
2931
|
try {
|
|
2860
2932
|
const targetUrl = p.url || page.url();
|
|
2861
2933
|
if (!targetUrl || targetUrl === "about:blank") {
|
|
2862
|
-
return
|
|
2934
|
+
return fail8("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2863
2935
|
}
|
|
2864
2936
|
let lastError;
|
|
2865
2937
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
@@ -2929,7 +3001,7 @@ var scrapeCommand = registerCommand({
|
|
|
2929
3001
|
} catch {
|
|
2930
3002
|
}
|
|
2931
3003
|
if (p.mode === "smart") {
|
|
2932
|
-
return
|
|
3004
|
+
return ok19(structured);
|
|
2933
3005
|
}
|
|
2934
3006
|
if (p.mode === "compact") {
|
|
2935
3007
|
const compactData = structured.tables.length > 0 ? structured.tables.map((t) => ({
|
|
@@ -2942,9 +3014,9 @@ var scrapeCommand = registerCommand({
|
|
|
2942
3014
|
return compact;
|
|
2943
3015
|
})
|
|
2944
3016
|
})) : structured.mainText?.substring(0, 500);
|
|
2945
|
-
return
|
|
3017
|
+
return ok19({ url: structured.url, title: structured.title, data: compactData });
|
|
2946
3018
|
}
|
|
2947
|
-
return
|
|
3019
|
+
return ok19(structured);
|
|
2948
3020
|
}
|
|
2949
3021
|
let content;
|
|
2950
3022
|
switch (p.format) {
|
|
@@ -3003,7 +3075,7 @@ var scrapeCommand = registerCommand({
|
|
|
3003
3075
|
content = await page.innerText("body");
|
|
3004
3076
|
break;
|
|
3005
3077
|
}
|
|
3006
|
-
return
|
|
3078
|
+
return ok19({ content, title, url: finalUrl });
|
|
3007
3079
|
} catch (err) {
|
|
3008
3080
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
3009
3081
|
if (attempt < maxAttempts) {
|
|
@@ -3013,20 +3085,20 @@ var scrapeCommand = registerCommand({
|
|
|
3013
3085
|
}
|
|
3014
3086
|
}
|
|
3015
3087
|
}
|
|
3016
|
-
return
|
|
3088
|
+
return fail8(`Scrape failed after ${maxAttempts} attempt(s): ${lastError?.message ?? "unknown error"}`);
|
|
3017
3089
|
} finally {
|
|
3018
3090
|
await closeEphemeralContext(context);
|
|
3019
3091
|
}
|
|
3020
3092
|
},
|
|
3021
|
-
result:
|
|
3022
|
-
url:
|
|
3023
|
-
title:
|
|
3093
|
+
result: z19.object({
|
|
3094
|
+
url: z19.string(),
|
|
3095
|
+
title: z19.string()
|
|
3024
3096
|
}).passthrough()
|
|
3025
3097
|
});
|
|
3026
3098
|
|
|
3027
3099
|
// src/commands/map.ts
|
|
3028
|
-
import { z as
|
|
3029
|
-
import { ok as
|
|
3100
|
+
import { z as z20 } from "zod";
|
|
3101
|
+
import { ok as ok20, fail as fail9 } from "@dyyz1993/xcli-core";
|
|
3030
3102
|
|
|
3031
3103
|
// src/utils/url.ts
|
|
3032
3104
|
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -3261,21 +3333,21 @@ var mapCommand = registerCommand({
|
|
|
3261
3333
|
name: "map",
|
|
3262
3334
|
description: "Discover all URLs on a website via sitemap and page link extraction",
|
|
3263
3335
|
scope: "project",
|
|
3264
|
-
parameters:
|
|
3265
|
-
url:
|
|
3266
|
-
search:
|
|
3267
|
-
sitemap:
|
|
3268
|
-
includeSubdomains:
|
|
3269
|
-
allowExternalLinks:
|
|
3270
|
-
limit:
|
|
3271
|
-
verbose:
|
|
3336
|
+
parameters: z20.object({
|
|
3337
|
+
url: z20.string().optional(),
|
|
3338
|
+
search: z20.string().optional(),
|
|
3339
|
+
sitemap: z20.enum(["include", "only"]).optional(),
|
|
3340
|
+
includeSubdomains: z20.boolean().optional(),
|
|
3341
|
+
allowExternalLinks: z20.boolean().optional().describe("Include links to external domains"),
|
|
3342
|
+
limit: z20.number().optional(),
|
|
3343
|
+
verbose: z20.boolean().default(false).describe("Show progress feedback")
|
|
3272
3344
|
}),
|
|
3273
3345
|
handler: async (p, ctx) => {
|
|
3274
3346
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
3275
3347
|
try {
|
|
3276
3348
|
const targetUrl = p.url || page.url();
|
|
3277
3349
|
if (!targetUrl || targetUrl === "about:blank") {
|
|
3278
|
-
return
|
|
3350
|
+
return fail9("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
3279
3351
|
}
|
|
3280
3352
|
const links = await discoverUrls(page, targetUrl, {
|
|
3281
3353
|
sitemap: p.sitemap,
|
|
@@ -3286,7 +3358,7 @@ var mapCommand = registerCommand({
|
|
|
3286
3358
|
verbose: p.verbose
|
|
3287
3359
|
});
|
|
3288
3360
|
const linkObjects = links.map((url) => ({ url }));
|
|
3289
|
-
return
|
|
3361
|
+
return ok20({
|
|
3290
3362
|
links: linkObjects,
|
|
3291
3363
|
success: true
|
|
3292
3364
|
});
|
|
@@ -3294,15 +3366,15 @@ var mapCommand = registerCommand({
|
|
|
3294
3366
|
await closeEphemeralContext(context);
|
|
3295
3367
|
}
|
|
3296
3368
|
},
|
|
3297
|
-
result:
|
|
3298
|
-
links:
|
|
3299
|
-
success:
|
|
3369
|
+
result: z20.object({
|
|
3370
|
+
links: z20.array(z20.object({ url: z20.string() })),
|
|
3371
|
+
success: z20.boolean()
|
|
3300
3372
|
})
|
|
3301
3373
|
});
|
|
3302
3374
|
|
|
3303
3375
|
// src/commands/crawl.ts
|
|
3304
|
-
import { z as
|
|
3305
|
-
import { ok as
|
|
3376
|
+
import { z as z21 } from "zod";
|
|
3377
|
+
import { ok as ok21 } from "@dyyz1993/xcli-core";
|
|
3306
3378
|
function stripHashAnchorQuery(url) {
|
|
3307
3379
|
try {
|
|
3308
3380
|
const parsed = new URL(url);
|
|
@@ -3479,21 +3551,21 @@ var crawlCommand = registerCommand({
|
|
|
3479
3551
|
name: "crawl",
|
|
3480
3552
|
description: "Crawl a website and extract content from all pages",
|
|
3481
3553
|
scope: "project",
|
|
3482
|
-
parameters:
|
|
3483
|
-
url:
|
|
3484
|
-
limit:
|
|
3485
|
-
maxDepth:
|
|
3486
|
-
includePaths:
|
|
3487
|
-
excludePaths:
|
|
3488
|
-
allowSubdomains:
|
|
3489
|
-
allowExternalLinks:
|
|
3490
|
-
allowBackwardCrawling:
|
|
3491
|
-
enableSpa:
|
|
3492
|
-
format:
|
|
3493
|
-
onlyMainContent:
|
|
3494
|
-
concurrency:
|
|
3495
|
-
retries:
|
|
3496
|
-
verbose:
|
|
3554
|
+
parameters: z21.object({
|
|
3555
|
+
url: z21.string(),
|
|
3556
|
+
limit: z21.number().default(10),
|
|
3557
|
+
maxDepth: z21.number().default(3),
|
|
3558
|
+
includePaths: z21.array(z21.string()).optional(),
|
|
3559
|
+
excludePaths: z21.array(z21.string()).optional(),
|
|
3560
|
+
allowSubdomains: z21.boolean().default(false),
|
|
3561
|
+
allowExternalLinks: z21.boolean().default(false),
|
|
3562
|
+
allowBackwardCrawling: z21.boolean().default(false),
|
|
3563
|
+
enableSpa: z21.boolean().default(true).describe("Disable to skip SPA route detection"),
|
|
3564
|
+
format: z21.enum(["markdown", "html"]).default("markdown"),
|
|
3565
|
+
onlyMainContent: z21.boolean().default(true),
|
|
3566
|
+
concurrency: z21.number().default(3),
|
|
3567
|
+
retries: z21.number().default(2),
|
|
3568
|
+
verbose: z21.boolean().default(false)
|
|
3497
3569
|
}),
|
|
3498
3570
|
handler: async (p, ctx) => {
|
|
3499
3571
|
const startUrl = new URL(p.url);
|
|
@@ -3632,7 +3704,7 @@ var crawlCommand = registerCommand({
|
|
|
3632
3704
|
if (errorPages.length > 0) {
|
|
3633
3705
|
response.errors = errorPages;
|
|
3634
3706
|
}
|
|
3635
|
-
return
|
|
3707
|
+
return ok21(response);
|
|
3636
3708
|
} finally {
|
|
3637
3709
|
for (const ctx2 of contexts) {
|
|
3638
3710
|
await ctx2.close().catch(() => {
|
|
@@ -3642,15 +3714,15 @@ var crawlCommand = registerCommand({
|
|
|
3642
3714
|
} catch (err) {
|
|
3643
3715
|
const message = err instanceof Error ? err.message : String(err);
|
|
3644
3716
|
const successPages = results.filter((r) => !isPageError(r));
|
|
3645
|
-
return
|
|
3717
|
+
return ok21({ pages: successPages, total: successPages.length, success: false, error: message });
|
|
3646
3718
|
}
|
|
3647
3719
|
}
|
|
3648
3720
|
});
|
|
3649
3721
|
|
|
3650
3722
|
// src/commands/search.ts
|
|
3651
|
-
import { z as
|
|
3723
|
+
import { z as z22 } from "zod";
|
|
3652
3724
|
import * as cheerio2 from "cheerio";
|
|
3653
|
-
import { ok as
|
|
3725
|
+
import { ok as ok22 } from "@dyyz1993/xcli-core";
|
|
3654
3726
|
function getRecencyParams(recency) {
|
|
3655
3727
|
const now = Math.floor(Date.now() / 1e3);
|
|
3656
3728
|
switch (recency) {
|
|
@@ -3984,16 +4056,16 @@ var searchCommand = registerCommand({
|
|
|
3984
4056
|
name: "search",
|
|
3985
4057
|
description: "Search the web and extract results with engine fallback",
|
|
3986
4058
|
scope: "project",
|
|
3987
|
-
parameters:
|
|
3988
|
-
query:
|
|
3989
|
-
engine:
|
|
3990
|
-
limit:
|
|
3991
|
-
full:
|
|
3992
|
-
format:
|
|
3993
|
-
timeout:
|
|
3994
|
-
recency:
|
|
3995
|
-
fallback:
|
|
3996
|
-
site:
|
|
4059
|
+
parameters: z22.object({
|
|
4060
|
+
query: z22.string(),
|
|
4061
|
+
engine: z22.string().optional(),
|
|
4062
|
+
limit: z22.number().default(10),
|
|
4063
|
+
full: z22.boolean().default(false),
|
|
4064
|
+
format: z22.enum(["markdown", "json", "text"]).default("markdown"),
|
|
4065
|
+
timeout: z22.number().default(15e3),
|
|
4066
|
+
recency: z22.enum(["hour", "day", "week", "month", "year"]).optional().describe("Filter by time: hour/day/week/month/year"),
|
|
4067
|
+
fallback: z22.boolean().default(false).describe("Sequential engine fallback instead of parallel"),
|
|
4068
|
+
site: z22.string().optional().describe("Limit results to a specific site (e.g. github.com, v2ex.com)")
|
|
3997
4069
|
}),
|
|
3998
4070
|
handler: async (p, ctx) => {
|
|
3999
4071
|
const { context } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
@@ -4099,7 +4171,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
4099
4171
|
lines.push(`> ${r.snippet}`);
|
|
4100
4172
|
lines.push("");
|
|
4101
4173
|
}
|
|
4102
|
-
return
|
|
4174
|
+
return ok22({ ...searchResult, content: lines.join("\n") });
|
|
4103
4175
|
}
|
|
4104
4176
|
if (p.format === "text") {
|
|
4105
4177
|
const lines = [`Search: ${searchResult.query} (Engine: ${searchResult.engine}, Total: ${searchResult.total})`, ""];
|
|
@@ -4109,9 +4181,9 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
4109
4181
|
lines.push(` ${r.snippet}`);
|
|
4110
4182
|
lines.push("");
|
|
4111
4183
|
}
|
|
4112
|
-
return
|
|
4184
|
+
return ok22({ ...searchResult, content: lines.join("\n") });
|
|
4113
4185
|
}
|
|
4114
|
-
return
|
|
4186
|
+
return ok22(searchResult);
|
|
4115
4187
|
} finally {
|
|
4116
4188
|
await closeEphemeralContext(context);
|
|
4117
4189
|
}
|
|
@@ -4119,8 +4191,8 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
4119
4191
|
});
|
|
4120
4192
|
|
|
4121
4193
|
// src/commands/network.ts
|
|
4122
|
-
import { z as
|
|
4123
|
-
import { ok as
|
|
4194
|
+
import { z as z23 } from "zod";
|
|
4195
|
+
import { ok as ok23, fail as fail10 } from "@dyyz1993/xcli-core";
|
|
4124
4196
|
function extractPath2(url) {
|
|
4125
4197
|
try {
|
|
4126
4198
|
const u = new URL(url);
|
|
@@ -4218,19 +4290,19 @@ var networkCommand = registerCommand({
|
|
|
4218
4290
|
name: "network",
|
|
4219
4291
|
description: "Capture and filter network responses from a URL",
|
|
4220
4292
|
scope: "project",
|
|
4221
|
-
parameters:
|
|
4222
|
-
url:
|
|
4223
|
-
filter:
|
|
4224
|
-
match:
|
|
4225
|
-
search:
|
|
4226
|
-
console:
|
|
4227
|
-
timeout:
|
|
4228
|
-
wait:
|
|
4229
|
-
limit:
|
|
4230
|
-
format:
|
|
4231
|
-
ws:
|
|
4232
|
-
listen:
|
|
4233
|
-
duration:
|
|
4293
|
+
parameters: z23.object({
|
|
4294
|
+
url: z23.string(),
|
|
4295
|
+
filter: z23.string().optional(),
|
|
4296
|
+
match: z23.string().optional(),
|
|
4297
|
+
search: z23.string().optional().describe("Search within all captured response bodies"),
|
|
4298
|
+
console: z23.boolean().default(false),
|
|
4299
|
+
timeout: z23.number().default(3e4),
|
|
4300
|
+
wait: z23.number().default(3e3),
|
|
4301
|
+
limit: z23.number().default(50),
|
|
4302
|
+
format: z23.enum(["summary", "json"]).default("summary"),
|
|
4303
|
+
ws: z23.boolean().optional().default(false).describe("Only show WebSocket messages"),
|
|
4304
|
+
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"),
|
|
4305
|
+
duration: z23.number().int().optional().default(15e3).describe("\u76D1\u542C\u6A21\u5F0F\u7B49\u5F85\u65F6\u957F\uFF08\u6BEB\u79D2\uFF0C\u9ED8\u8BA4 15000\uFF09")
|
|
4234
4306
|
}),
|
|
4235
4307
|
handler: async (p, ctx) => {
|
|
4236
4308
|
const startTime = Date.now();
|
|
@@ -4285,7 +4357,7 @@ var networkCommand = registerCommand({
|
|
|
4285
4357
|
};
|
|
4286
4358
|
if (p.listen) {
|
|
4287
4359
|
const page2 = ctx.page;
|
|
4288
|
-
if (!page2) return
|
|
4360
|
+
if (!page2) return fail10("No active page. Use --cdp to connect first.");
|
|
4289
4361
|
const captures = [];
|
|
4290
4362
|
const consoleMessages = [];
|
|
4291
4363
|
const wsCaptures = [];
|
|
@@ -4312,7 +4384,7 @@ var networkCommand = registerCommand({
|
|
|
4312
4384
|
page2.off("response", handler);
|
|
4313
4385
|
const duration = Date.now() - startTime;
|
|
4314
4386
|
if (p.ws && wsCaptures.length > 0) {
|
|
4315
|
-
return
|
|
4387
|
+
return ok23({
|
|
4316
4388
|
url: "[listen mode]",
|
|
4317
4389
|
duration,
|
|
4318
4390
|
total: captures.length,
|
|
@@ -4326,9 +4398,9 @@ var networkCommand = registerCommand({
|
|
|
4326
4398
|
});
|
|
4327
4399
|
}
|
|
4328
4400
|
if (p.format === "json") {
|
|
4329
|
-
return
|
|
4401
|
+
return ok23(buildJsonOutput("[listen mode]", captures, consoleMessages, captures.length, wsCaptures));
|
|
4330
4402
|
}
|
|
4331
|
-
return
|
|
4403
|
+
return ok23(buildSummaryOutput("[listen mode]", duration, captures, consoleMessages, captures.length, wsCaptures));
|
|
4332
4404
|
}
|
|
4333
4405
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
4334
4406
|
try {
|
|
@@ -4383,7 +4455,7 @@ var networkCommand = registerCommand({
|
|
|
4383
4455
|
}
|
|
4384
4456
|
const duration = Date.now() - startTime;
|
|
4385
4457
|
if (p.ws && wsCaptures.length > 0) {
|
|
4386
|
-
return
|
|
4458
|
+
return ok23({
|
|
4387
4459
|
url: p.url,
|
|
4388
4460
|
duration,
|
|
4389
4461
|
total: captures.length,
|
|
@@ -4397,9 +4469,9 @@ var networkCommand = registerCommand({
|
|
|
4397
4469
|
});
|
|
4398
4470
|
}
|
|
4399
4471
|
if (p.format === "json") {
|
|
4400
|
-
return
|
|
4472
|
+
return ok23(buildJsonOutput(p.url, results, consoleMessages, totalCount, wsCaptures, searchResults));
|
|
4401
4473
|
}
|
|
4402
|
-
return
|
|
4474
|
+
return ok23(buildSummaryOutput(p.url, duration, results, consoleMessages, totalCount, wsCaptures));
|
|
4403
4475
|
} finally {
|
|
4404
4476
|
await closeEphemeralContext(context);
|
|
4405
4477
|
}
|
|
@@ -4407,7 +4479,7 @@ var networkCommand = registerCommand({
|
|
|
4407
4479
|
});
|
|
4408
4480
|
|
|
4409
4481
|
// src/commands/ai-search-engines.ts
|
|
4410
|
-
import { z as
|
|
4482
|
+
import { z as z24 } from "zod";
|
|
4411
4483
|
var ENGINE_CONFIGS = {
|
|
4412
4484
|
deepseek: {
|
|
4413
4485
|
key: "deepseek",
|
|
@@ -4661,11 +4733,11 @@ var ENGINE_CONFIGS = {
|
|
|
4661
4733
|
}
|
|
4662
4734
|
};
|
|
4663
4735
|
var ALL_ENGINE_KEYS = Object.keys(ENGINE_CONFIGS);
|
|
4664
|
-
var ENGINE_KEY_ENUM =
|
|
4736
|
+
var ENGINE_KEY_ENUM = z24.enum(ALL_ENGINE_KEYS);
|
|
4665
4737
|
|
|
4666
4738
|
// src/commands/snapshot.ts
|
|
4667
|
-
import { z as
|
|
4668
|
-
import { ok as
|
|
4739
|
+
import { z as z25 } from "zod";
|
|
4740
|
+
import { ok as ok24, fail as fail11, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
|
|
4669
4741
|
|
|
4670
4742
|
// src/runtime/ref-store.ts
|
|
4671
4743
|
var sessions = /* @__PURE__ */ new Map();
|
|
@@ -5577,24 +5649,24 @@ var snapshotCommand = registerCommand({
|
|
|
5577
5649
|
description: "Capture a quick page state snapshot \u2014 aria tree, visible text, or DOM summary",
|
|
5578
5650
|
scope: "page",
|
|
5579
5651
|
selectorParams: ["selector"],
|
|
5580
|
-
parameters:
|
|
5581
|
-
type:
|
|
5582
|
-
selector:
|
|
5583
|
-
depth:
|
|
5584
|
-
interactive:
|
|
5585
|
-
interactiveOnly:
|
|
5586
|
-
i:
|
|
5587
|
-
compact:
|
|
5588
|
-
c:
|
|
5589
|
-
selectors:
|
|
5590
|
-
all:
|
|
5652
|
+
parameters: z25.object({
|
|
5653
|
+
type: z25.enum(["aria", "text", "dom", "all"]).default("aria").describe("Snapshot type: aria (accessibility tree), text (visible text), dom (element summary), all (combined)"),
|
|
5654
|
+
selector: z25.string().optional().describe("Scope to a specific element"),
|
|
5655
|
+
depth: z25.number().optional().default(6).describe("Max depth for DOM/aria tree"),
|
|
5656
|
+
interactive: z25.boolean().optional().default(false).describe("Return interactive agent refs only"),
|
|
5657
|
+
interactiveOnly: z25.boolean().optional().default(false).describe("Alias for interactive"),
|
|
5658
|
+
i: z25.boolean().optional().default(false).describe("Short alias for interactive"),
|
|
5659
|
+
compact: z25.boolean().optional().default(false).describe("Include compact xbrowser style snapshot text"),
|
|
5660
|
+
c: z25.boolean().optional().default(false).describe("Short alias for compact"),
|
|
5661
|
+
selectors: z25.boolean().optional().default(false).describe("Include ref to CSS selector map"),
|
|
5662
|
+
all: z25.boolean().optional().default(false).describe("Include hidden interactive targets when using interactive snapshot")
|
|
5591
5663
|
}),
|
|
5592
|
-
result:
|
|
5593
|
-
url:
|
|
5594
|
-
title:
|
|
5595
|
-
aria:
|
|
5596
|
-
text:
|
|
5597
|
-
dom:
|
|
5664
|
+
result: z25.object({
|
|
5665
|
+
url: z25.string(),
|
|
5666
|
+
title: z25.string(),
|
|
5667
|
+
aria: z25.string().optional(),
|
|
5668
|
+
text: z25.string().optional(),
|
|
5669
|
+
dom: z25.record(z25.unknown()).optional()
|
|
5598
5670
|
}),
|
|
5599
5671
|
handler: async (p, ctx) => {
|
|
5600
5672
|
const page = ctx.page;
|
|
@@ -5608,7 +5680,7 @@ var snapshotCommand = registerCommand({
|
|
|
5608
5680
|
if (p.compact || p.c || p.interactive || p.interactiveOnly || p.i) {
|
|
5609
5681
|
observation.compact = formatObservationCompact(observation, { selectors: p.selectors });
|
|
5610
5682
|
}
|
|
5611
|
-
return
|
|
5683
|
+
return ok24(observation, normalizeTips3([
|
|
5612
5684
|
`refs refreshed for ${observation.targets.length} targets; use click @e1 or fill @e2 "text"`
|
|
5613
5685
|
]));
|
|
5614
5686
|
}
|
|
@@ -5616,15 +5688,15 @@ var snapshotCommand = registerCommand({
|
|
|
5616
5688
|
const aria = await captureAriaSnapshot(page, p.selector, p.depth);
|
|
5617
5689
|
const tips = await buildRefTips(page, aria);
|
|
5618
5690
|
persistSemantics(url, aria);
|
|
5619
|
-
return
|
|
5691
|
+
return ok24({ url, title, aria }, normalizeTips3(tips));
|
|
5620
5692
|
}
|
|
5621
5693
|
if (p.type === "text") {
|
|
5622
5694
|
const text = await captureTextSnapshot(page, p.selector);
|
|
5623
|
-
return
|
|
5695
|
+
return ok24({ url, title, text });
|
|
5624
5696
|
}
|
|
5625
5697
|
if (p.type === "dom") {
|
|
5626
5698
|
const dom = await captureDomSnapshot(page, p.selector, p.depth ?? 6);
|
|
5627
|
-
return
|
|
5699
|
+
return ok24({ url, title, dom });
|
|
5628
5700
|
}
|
|
5629
5701
|
if (p.type === "all") {
|
|
5630
5702
|
const [aria, text, dom] = await Promise.all([
|
|
@@ -5634,9 +5706,9 @@ var snapshotCommand = registerCommand({
|
|
|
5634
5706
|
]);
|
|
5635
5707
|
const tips = await buildRefTips(page, aria);
|
|
5636
5708
|
persistSemantics(url, aria);
|
|
5637
|
-
return
|
|
5709
|
+
return ok24({ url, title, aria, text, dom }, normalizeTips3(tips));
|
|
5638
5710
|
}
|
|
5639
|
-
return
|
|
5711
|
+
return fail11(`Unknown snapshot type: ${p.type}`);
|
|
5640
5712
|
}
|
|
5641
5713
|
});
|
|
5642
5714
|
function persistSemantics(url, aria) {
|
|
@@ -5713,22 +5785,22 @@ async function captureDomSnapshot(page, selector, maxDepth) {
|
|
|
5713
5785
|
}
|
|
5714
5786
|
|
|
5715
5787
|
// src/commands/agent.ts
|
|
5716
|
-
import { z as
|
|
5717
|
-
import { ok as
|
|
5788
|
+
import { z as z26 } from "zod";
|
|
5789
|
+
import { ok as ok25, normalizeTips as normalizeTips4 } from "@dyyz1993/xcli-core";
|
|
5718
5790
|
var observeCommand = registerCommand({
|
|
5719
5791
|
name: "observe",
|
|
5720
5792
|
description: "Observe the current page as structured agent targets with session refs",
|
|
5721
5793
|
scope: "page",
|
|
5722
|
-
parameters:
|
|
5723
|
-
includeHidden:
|
|
5724
|
-
limit:
|
|
5725
|
-
compact:
|
|
5726
|
-
selectors:
|
|
5794
|
+
parameters: z26.object({
|
|
5795
|
+
includeHidden: z26.boolean().optional().default(false).describe("Include hidden elements in the target list"),
|
|
5796
|
+
limit: z26.number().int().positive().max(300).optional().default(80).describe("Maximum number of targets to return"),
|
|
5797
|
+
compact: z26.boolean().optional().default(false).describe("Include compact xbrowser style snapshot text"),
|
|
5798
|
+
selectors: z26.boolean().optional().default(false).describe("Include ref to stable CSS selector map")
|
|
5727
5799
|
}),
|
|
5728
|
-
result:
|
|
5729
|
-
targets:
|
|
5730
|
-
selectors:
|
|
5731
|
-
compact:
|
|
5800
|
+
result: z26.object({
|
|
5801
|
+
targets: z26.array(z26.record(z26.unknown())),
|
|
5802
|
+
selectors: z26.record(z26.unknown()).optional(),
|
|
5803
|
+
compact: z26.string().optional()
|
|
5732
5804
|
}).passthrough(),
|
|
5733
5805
|
handler: async (p, ctx) => {
|
|
5734
5806
|
const observation = await observePage(ctx.page, ctx.sessionId, {
|
|
@@ -5737,7 +5809,7 @@ var observeCommand = registerCommand({
|
|
|
5737
5809
|
});
|
|
5738
5810
|
if (p.selectors) observation.selectors = buildSelectorMap(observation);
|
|
5739
5811
|
if (p.compact) observation.compact = formatObservationCompact(observation, { selectors: p.selectors });
|
|
5740
|
-
return
|
|
5812
|
+
return ok25(observation, normalizeTips4([
|
|
5741
5813
|
`refs refreshed for ${observation.targets.length} targets; use act --ref @e1 --action click or click @e1`
|
|
5742
5814
|
]));
|
|
5743
5815
|
}
|
|
@@ -5747,14 +5819,14 @@ var actCommand = registerCommand({
|
|
|
5747
5819
|
description: "Perform an agent action using an observe ref or explicit selector",
|
|
5748
5820
|
scope: "element",
|
|
5749
5821
|
selectorParams: ["selector"],
|
|
5750
|
-
parameters:
|
|
5751
|
-
action:
|
|
5752
|
-
ref:
|
|
5753
|
-
selector:
|
|
5754
|
-
value:
|
|
5755
|
-
key:
|
|
5756
|
-
force:
|
|
5757
|
-
timeout:
|
|
5822
|
+
parameters: z26.object({
|
|
5823
|
+
action: z26.enum(["click", "fill", "type", "press", "select", "check", "hover"]).default("click"),
|
|
5824
|
+
ref: z26.string().optional().describe("Session-scoped ref returned by observe, such as e1"),
|
|
5825
|
+
selector: z26.string().optional().describe("CSS selector fallback when no ref is available"),
|
|
5826
|
+
value: z26.string().optional().describe("Value for fill/type/select"),
|
|
5827
|
+
key: z26.string().optional().describe("Key for press"),
|
|
5828
|
+
force: z26.boolean().optional().default(false).describe("Bypass actionability checks"),
|
|
5829
|
+
timeout: z26.number().optional().default(1e4).describe("Playwright action timeout in milliseconds")
|
|
5758
5830
|
}).refine((p) => !!p.ref || !!p.selector, {
|
|
5759
5831
|
message: "Either ref or selector is required"
|
|
5760
5832
|
}),
|
|
@@ -5768,7 +5840,7 @@ var actCommand = registerCommand({
|
|
|
5768
5840
|
tips: normalizeTips4(result.stale ? ["run observe again to refresh refs"] : [])
|
|
5769
5841
|
};
|
|
5770
5842
|
}
|
|
5771
|
-
return
|
|
5843
|
+
return ok25(result, normalizeTips4(result.stale ? ["ref screen hash changed; run observe if the next action is uncertain"] : []));
|
|
5772
5844
|
}
|
|
5773
5845
|
});
|
|
5774
5846
|
var waitForCommand = registerCommand({
|
|
@@ -5776,16 +5848,16 @@ var waitForCommand = registerCommand({
|
|
|
5776
5848
|
description: "Wait for agent predicates such as text, URL, load state, selector state, or screen hash changes",
|
|
5777
5849
|
scope: "page",
|
|
5778
5850
|
selectorParams: ["selector"],
|
|
5779
|
-
parameters:
|
|
5780
|
-
selector:
|
|
5781
|
-
state:
|
|
5782
|
-
text:
|
|
5783
|
-
url:
|
|
5784
|
-
load:
|
|
5785
|
-
fn:
|
|
5786
|
-
screenHashChanged:
|
|
5787
|
-
timeout:
|
|
5788
|
-
pollInterval:
|
|
5851
|
+
parameters: z26.object({
|
|
5852
|
+
selector: z26.string().optional().describe("CSS selector or observe ref to wait for"),
|
|
5853
|
+
state: z26.enum(["attached", "detached", "visible", "hidden"]).optional().default("visible"),
|
|
5854
|
+
text: z26.string().optional().describe("Visible text to wait for"),
|
|
5855
|
+
url: z26.string().optional().describe("URL substring or glob pattern to wait for"),
|
|
5856
|
+
load: z26.enum(["load", "domcontentloaded", "networkidle"]).optional().describe("Load state to wait for"),
|
|
5857
|
+
fn: z26.string().optional().describe("JavaScript predicate to wait for"),
|
|
5858
|
+
screenHashChanged: z26.string().optional().describe("Previous screenHash from observe"),
|
|
5859
|
+
timeout: z26.number().optional().default(3e4),
|
|
5860
|
+
pollInterval: z26.number().optional().default(200)
|
|
5789
5861
|
}).refine((p) => [p.selector, p.text, p.url, p.load, p.fn, p.screenHashChanged].filter(Boolean).length === 1, {
|
|
5790
5862
|
message: "Provide exactly one wait predicate: selector, text, url, load, fn, or screenHashChanged"
|
|
5791
5863
|
}),
|
|
@@ -5799,30 +5871,30 @@ var waitForCommand = registerCommand({
|
|
|
5799
5871
|
tips: []
|
|
5800
5872
|
};
|
|
5801
5873
|
}
|
|
5802
|
-
return
|
|
5874
|
+
return ok25(result);
|
|
5803
5875
|
}
|
|
5804
5876
|
});
|
|
5805
5877
|
|
|
5806
5878
|
// src/commands/tab.ts
|
|
5807
|
-
import { z as
|
|
5808
|
-
import { ok as
|
|
5809
|
-
var TabParams =
|
|
5810
|
-
subcommand:
|
|
5811
|
-
url:
|
|
5812
|
-
index:
|
|
5879
|
+
import { z as z27 } from "zod";
|
|
5880
|
+
import { ok as ok26, fail as fail12 } from "@dyyz1993/xcli-core";
|
|
5881
|
+
var TabParams = z27.object({
|
|
5882
|
+
subcommand: z27.enum(["list", "new", "close", "switch"]),
|
|
5883
|
+
url: z27.string().optional(),
|
|
5884
|
+
index: z27.number().int().min(0).optional()
|
|
5813
5885
|
});
|
|
5814
5886
|
var tabCommand = registerCommand({
|
|
5815
5887
|
name: "tab",
|
|
5816
5888
|
description: "Manage browser tabs: list, new, close, switch",
|
|
5817
5889
|
scope: "page",
|
|
5818
5890
|
parameters: TabParams,
|
|
5819
|
-
result:
|
|
5820
|
-
success:
|
|
5821
|
-
data:
|
|
5891
|
+
result: z27.object({
|
|
5892
|
+
success: z27.boolean(),
|
|
5893
|
+
data: z27.unknown()
|
|
5822
5894
|
}),
|
|
5823
5895
|
handler: async (p, ctx) => {
|
|
5824
5896
|
if (!ctx.browserContext) {
|
|
5825
|
-
return
|
|
5897
|
+
return fail12("No browser context available. Use --cdp to connect to a browser first.");
|
|
5826
5898
|
}
|
|
5827
5899
|
const pages = ctx.browserContext.pages();
|
|
5828
5900
|
switch (p.subcommand) {
|
|
@@ -5835,7 +5907,7 @@ var tabCommand = registerCommand({
|
|
|
5835
5907
|
case "switch":
|
|
5836
5908
|
return handleSwitch(p, pages, ctx);
|
|
5837
5909
|
default:
|
|
5838
|
-
return
|
|
5910
|
+
return fail12(`Unknown subcommand: ${p.subcommand}`);
|
|
5839
5911
|
}
|
|
5840
5912
|
}
|
|
5841
5913
|
});
|
|
@@ -5850,7 +5922,7 @@ async function handleList(pages, ctx) {
|
|
|
5850
5922
|
if (isActive) activeIndex = i;
|
|
5851
5923
|
tabs.push({ index: i, url, title, active: isActive });
|
|
5852
5924
|
}
|
|
5853
|
-
return
|
|
5925
|
+
return ok26({ tabs, total: tabs.length, activeIndex });
|
|
5854
5926
|
}
|
|
5855
5927
|
async function handleNew(p, _pages, ctx) {
|
|
5856
5928
|
const newPage = await ctx.browserContext.newPage();
|
|
@@ -5878,7 +5950,7 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5878
5950
|
const title = await newPage.title().catch(() => "");
|
|
5879
5951
|
const allPages = ctx.browserContext.pages();
|
|
5880
5952
|
const newIndex = allPages.indexOf(newPage);
|
|
5881
|
-
return
|
|
5953
|
+
return ok26({
|
|
5882
5954
|
index: newIndex >= 0 ? newIndex : allPages.length - 1,
|
|
5883
5955
|
url: newPage.url(),
|
|
5884
5956
|
title,
|
|
@@ -5889,11 +5961,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5889
5961
|
async function handleClose(p, ctx) {
|
|
5890
5962
|
const currentPages = ctx.browserContext.pages();
|
|
5891
5963
|
if (currentPages.length <= 1) {
|
|
5892
|
-
return
|
|
5964
|
+
return fail12("Cannot close the last remaining tab");
|
|
5893
5965
|
}
|
|
5894
5966
|
const closeIndex = p.index ?? currentPages.findIndex((pg) => pg === ctx.page);
|
|
5895
5967
|
if (closeIndex < 0 || closeIndex >= currentPages.length) {
|
|
5896
|
-
return
|
|
5968
|
+
return fail12(`Invalid tab index: ${closeIndex}. Valid range: 0-${currentPages.length - 1}`);
|
|
5897
5969
|
}
|
|
5898
5970
|
const pageToClose = currentPages[closeIndex];
|
|
5899
5971
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5908,7 +5980,7 @@ async function handleClose(p, ctx) {
|
|
|
5908
5980
|
}
|
|
5909
5981
|
ctx.page = newActivePage;
|
|
5910
5982
|
}
|
|
5911
|
-
return
|
|
5983
|
+
return ok26({
|
|
5912
5984
|
closedIndex: closeIndex,
|
|
5913
5985
|
total: remainingPages.length,
|
|
5914
5986
|
activeIndex: isActivePage ? closeIndex < remainingPages.length ? closeIndex : remainingPages.length - 1 : remainingPages.findIndex((pg) => pg === ctx.page)
|
|
@@ -5916,10 +5988,10 @@ async function handleClose(p, ctx) {
|
|
|
5916
5988
|
}
|
|
5917
5989
|
async function handleSwitch(p, pages, ctx) {
|
|
5918
5990
|
if (p.index === void 0) {
|
|
5919
|
-
return
|
|
5991
|
+
return fail12("Parameter --index is required for switch subcommand");
|
|
5920
5992
|
}
|
|
5921
5993
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5922
|
-
return
|
|
5994
|
+
return fail12(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5923
5995
|
}
|
|
5924
5996
|
const targetPage = pages[p.index];
|
|
5925
5997
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -5941,7 +6013,7 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
5941
6013
|
}
|
|
5942
6014
|
ctx.page = targetPage;
|
|
5943
6015
|
const title = await targetPage.title().catch(() => "");
|
|
5944
|
-
return
|
|
6016
|
+
return ok26({
|
|
5945
6017
|
index: p.index,
|
|
5946
6018
|
url: targetPage.url(),
|
|
5947
6019
|
title,
|
|
@@ -5950,8 +6022,8 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
5950
6022
|
}
|
|
5951
6023
|
|
|
5952
6024
|
// src/commands/addinitscript.ts
|
|
5953
|
-
import { z as
|
|
5954
|
-
import { ok as
|
|
6025
|
+
import { z as z28 } from "zod";
|
|
6026
|
+
import { ok as ok27 } from "@dyyz1993/xcli-core";
|
|
5955
6027
|
import { readFileSync as readFileSync4 } from "fs";
|
|
5956
6028
|
|
|
5957
6029
|
// src/chain-parser.ts
|
|
@@ -6092,14 +6164,14 @@ registerCommandDefinition("tab", ["subcommand"]);
|
|
|
6092
6164
|
registerCommandDefinition("mouse", ["action", "x", "y"]);
|
|
6093
6165
|
|
|
6094
6166
|
// src/commands/addinitscript.ts
|
|
6095
|
-
var InitScriptParams =
|
|
6096
|
-
script:
|
|
6097
|
-
file:
|
|
6098
|
-
stdin:
|
|
6099
|
-
name:
|
|
6100
|
-
list:
|
|
6101
|
-
remove:
|
|
6102
|
-
base64:
|
|
6167
|
+
var InitScriptParams = z28.object({
|
|
6168
|
+
script: z28.string().optional(),
|
|
6169
|
+
file: z28.string().optional(),
|
|
6170
|
+
stdin: z28.boolean().optional(),
|
|
6171
|
+
name: z28.string().optional(),
|
|
6172
|
+
list: z28.boolean().optional(),
|
|
6173
|
+
remove: z28.union([z28.string(), z28.boolean()]).optional(),
|
|
6174
|
+
base64: z28.string().optional()
|
|
6103
6175
|
});
|
|
6104
6176
|
var registeredScripts = /* @__PURE__ */ new Map();
|
|
6105
6177
|
function resolveScriptContent(params) {
|
|
@@ -6133,14 +6205,14 @@ var addInitScriptCommand = registerCommand({
|
|
|
6133
6205
|
description: "Add an initialization script that runs on every page load",
|
|
6134
6206
|
scope: "page",
|
|
6135
6207
|
parameters: InitScriptParams,
|
|
6136
|
-
result:
|
|
6137
|
-
scripts:
|
|
6138
|
-
removed:
|
|
6139
|
-
existed:
|
|
6140
|
-
error:
|
|
6141
|
-
registered:
|
|
6142
|
-
hint:
|
|
6143
|
-
executedImmediately:
|
|
6208
|
+
result: z28.object({
|
|
6209
|
+
scripts: z28.array(z28.object({ name: z28.string(), size: z28.number(), preview: z28.string() })).optional(),
|
|
6210
|
+
removed: z28.string().optional(),
|
|
6211
|
+
existed: z28.boolean().optional(),
|
|
6212
|
+
error: z28.string().optional(),
|
|
6213
|
+
registered: z28.string().optional(),
|
|
6214
|
+
hint: z28.string().optional(),
|
|
6215
|
+
executedImmediately: z28.boolean().optional()
|
|
6144
6216
|
}).passthrough(),
|
|
6145
6217
|
handler: async (params, ctx) => {
|
|
6146
6218
|
if (params.list) {
|
|
@@ -6149,20 +6221,20 @@ var addInitScriptCommand = registerCommand({
|
|
|
6149
6221
|
size: content2.length,
|
|
6150
6222
|
preview: content2.slice(0, 80)
|
|
6151
6223
|
}));
|
|
6152
|
-
return
|
|
6224
|
+
return ok27({ scripts });
|
|
6153
6225
|
}
|
|
6154
6226
|
if (params.remove && typeof params.remove === "string") {
|
|
6155
6227
|
const existed = registeredScripts.delete(params.remove);
|
|
6156
|
-
return
|
|
6228
|
+
return ok27({ removed: params.remove, existed });
|
|
6157
6229
|
}
|
|
6158
6230
|
const removeTarget = (typeof params.remove === "string" ? params.remove : null) || (params.name && !resolveScriptContent(params) ? params.name : null);
|
|
6159
6231
|
if (removeTarget && !resolveScriptContent(params)) {
|
|
6160
6232
|
const existed = registeredScripts.delete(removeTarget);
|
|
6161
|
-
return
|
|
6233
|
+
return ok27({ removed: removeTarget, existed });
|
|
6162
6234
|
}
|
|
6163
6235
|
let content = params.stdin ? await readStdin() : resolveScriptContent(params);
|
|
6164
6236
|
if (!content) {
|
|
6165
|
-
return
|
|
6237
|
+
return ok27({ error: "No script content provided. Use --script, --file, --stdin, or --base64" });
|
|
6166
6238
|
}
|
|
6167
6239
|
const scriptName = params.name ?? `script-${Date.now()}`;
|
|
6168
6240
|
registeredScripts.set(scriptName, content);
|
|
@@ -6170,45 +6242,45 @@ var addInitScriptCommand = registerCommand({
|
|
|
6170
6242
|
try {
|
|
6171
6243
|
await ctx.page.evaluate(content);
|
|
6172
6244
|
} catch {
|
|
6173
|
-
return
|
|
6245
|
+
return ok27({
|
|
6174
6246
|
registered: scriptName,
|
|
6175
6247
|
hint: "Script registered for future page loads; immediate execution skipped (page may not be ready)"
|
|
6176
6248
|
});
|
|
6177
6249
|
}
|
|
6178
|
-
return
|
|
6250
|
+
return ok27({ registered: scriptName, executedImmediately: true });
|
|
6179
6251
|
}
|
|
6180
6252
|
});
|
|
6181
6253
|
registerCommandDefinition("addinitscript", ["script"]);
|
|
6182
6254
|
|
|
6183
6255
|
// src/commands/find.ts
|
|
6184
|
-
import { z as
|
|
6185
|
-
import { ok as
|
|
6186
|
-
var actionSchema2 =
|
|
6256
|
+
import { z as z29 } from "zod";
|
|
6257
|
+
import { ok as ok28, fail as fail13, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
6258
|
+
var actionSchema2 = z29.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
6187
6259
|
var findCommand = registerCommand({
|
|
6188
6260
|
name: "find",
|
|
6189
6261
|
description: "Find elements by semantic strategy (text/role/label/placeholder/testid) and optionally perform an action",
|
|
6190
6262
|
scope: "page",
|
|
6191
|
-
parameters:
|
|
6192
|
-
strategy:
|
|
6193
|
-
value:
|
|
6194
|
-
name:
|
|
6195
|
-
exact:
|
|
6196
|
-
operation:
|
|
6263
|
+
parameters: z29.object({
|
|
6264
|
+
strategy: z29.enum(["text", "role", "label", "placeholder", "testid", "alt", "title", "first", "last", "nth"]),
|
|
6265
|
+
value: z29.string(),
|
|
6266
|
+
name: z29.string().optional(),
|
|
6267
|
+
exact: z29.boolean().optional().default(false),
|
|
6268
|
+
operation: z29.string().optional().describe('Trailing operation syntax, e.g. click, fill "text", type "text"'),
|
|
6197
6269
|
action: actionSchema2.optional().describe("Action to perform when not using trailing operation syntax"),
|
|
6198
|
-
actionValue:
|
|
6199
|
-
index:
|
|
6200
|
-
click:
|
|
6201
|
-
fill:
|
|
6202
|
-
type:
|
|
6203
|
-
select:
|
|
6204
|
-
hover:
|
|
6205
|
-
check:
|
|
6206
|
-
timeout:
|
|
6270
|
+
actionValue: z29.string().optional().describe("Value for fill/type/select when using action"),
|
|
6271
|
+
index: z29.number().int().optional().describe("Index for nth strategy"),
|
|
6272
|
+
click: z29.boolean().optional().default(false),
|
|
6273
|
+
fill: z29.string().optional(),
|
|
6274
|
+
type: z29.string().optional(),
|
|
6275
|
+
select: z29.string().optional(),
|
|
6276
|
+
hover: z29.boolean().optional().default(false),
|
|
6277
|
+
check: z29.boolean().optional().default(false),
|
|
6278
|
+
timeout: z29.number().optional().default(1e4)
|
|
6207
6279
|
}),
|
|
6208
|
-
result:
|
|
6209
|
-
matched:
|
|
6210
|
-
selector:
|
|
6211
|
-
action:
|
|
6280
|
+
result: z29.object({
|
|
6281
|
+
matched: z29.number(),
|
|
6282
|
+
selector: z29.string(),
|
|
6283
|
+
action: z29.string().optional()
|
|
6212
6284
|
}),
|
|
6213
6285
|
handler: async (p, ctx) => {
|
|
6214
6286
|
const page = ctx.page;
|
|
@@ -6223,7 +6295,7 @@ var findCommand = registerCommand({
|
|
|
6223
6295
|
});
|
|
6224
6296
|
const count = await locator.count();
|
|
6225
6297
|
if (count === 0) {
|
|
6226
|
-
return
|
|
6298
|
+
return fail13(`No element found with ${p.strategy}="${p.value}"`);
|
|
6227
6299
|
}
|
|
6228
6300
|
const tips = [];
|
|
6229
6301
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6235,15 +6307,15 @@ var findCommand = registerCommand({
|
|
|
6235
6307
|
await target.click({ timeout: p.timeout, force: true });
|
|
6236
6308
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6237
6309
|
} else if (actionName === "fill") {
|
|
6238
|
-
if (actionValue === void 0) return
|
|
6310
|
+
if (actionValue === void 0) return fail13("find fill requires a value");
|
|
6239
6311
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6240
6312
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6241
6313
|
} else if (actionName === "type") {
|
|
6242
|
-
if (actionValue === void 0) return
|
|
6314
|
+
if (actionValue === void 0) return fail13("find type requires a value");
|
|
6243
6315
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6244
6316
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6245
6317
|
} else if (actionName === "select") {
|
|
6246
|
-
if (actionValue === void 0) return
|
|
6318
|
+
if (actionValue === void 0) return fail13("find select requires a value");
|
|
6247
6319
|
await target.selectOption(actionValue);
|
|
6248
6320
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6249
6321
|
} else if (actionName === "hover") {
|
|
@@ -6257,7 +6329,7 @@ var findCommand = registerCommand({
|
|
|
6257
6329
|
}
|
|
6258
6330
|
});
|
|
6259
6331
|
function okWithTips(data, tips) {
|
|
6260
|
-
const result =
|
|
6332
|
+
const result = ok28(data);
|
|
6261
6333
|
if (tips.length > 0) result.tips = normalizeTips5(tips);
|
|
6262
6334
|
return result;
|
|
6263
6335
|
}
|
|
@@ -6356,8 +6428,8 @@ function describeSelector(strategy, value, name) {
|
|
|
6356
6428
|
}
|
|
6357
6429
|
|
|
6358
6430
|
// src/commands/visual-tag.ts
|
|
6359
|
-
import { z as
|
|
6360
|
-
import { ok as
|
|
6431
|
+
import { z as z30 } from "zod";
|
|
6432
|
+
import { ok as ok29, fail as fail14 } from "@dyyz1993/xcli-core";
|
|
6361
6433
|
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6362
6434
|
var TAG_SCRIPT = `
|
|
6363
6435
|
(function() {
|
|
@@ -6448,49 +6520,49 @@ var visualTagCommand = registerCommand({
|
|
|
6448
6520
|
name: "visual-tag",
|
|
6449
6521
|
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",
|
|
6450
6522
|
scope: "page",
|
|
6451
|
-
parameters:
|
|
6452
|
-
action:
|
|
6453
|
-
id:
|
|
6523
|
+
parameters: z30.object({
|
|
6524
|
+
action: z30.enum(["tag", "lookup", "clear", "list"]),
|
|
6525
|
+
id: z30.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6454
6526
|
}),
|
|
6455
|
-
result:
|
|
6456
|
-
action:
|
|
6457
|
-
tagged:
|
|
6458
|
-
id:
|
|
6459
|
-
element:
|
|
6527
|
+
result: z30.object({
|
|
6528
|
+
action: z30.string(),
|
|
6529
|
+
tagged: z30.number().optional(),
|
|
6530
|
+
id: z30.string().optional(),
|
|
6531
|
+
element: z30.record(z30.unknown()).optional()
|
|
6460
6532
|
}),
|
|
6461
6533
|
handler: async (p, ctx) => {
|
|
6462
6534
|
switch (p.action) {
|
|
6463
6535
|
case "tag": {
|
|
6464
6536
|
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6465
6537
|
const parsed = JSON.parse(result);
|
|
6466
|
-
return
|
|
6538
|
+
return ok29({ action: "tag", tagged: parsed.tagged });
|
|
6467
6539
|
}
|
|
6468
6540
|
case "lookup": {
|
|
6469
|
-
if (!p.id) return
|
|
6541
|
+
if (!p.id) return fail14("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6470
6542
|
const result = await ctx.page.evaluate(
|
|
6471
6543
|
`(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'}); })()`
|
|
6472
6544
|
);
|
|
6473
6545
|
const parsed = JSON.parse(result);
|
|
6474
|
-
if (parsed.err) return
|
|
6475
|
-
return
|
|
6546
|
+
if (parsed.err) return fail14(`ID ${p.id}: ${parsed.err}`);
|
|
6547
|
+
return ok29({ action: "lookup", id: p.id, element: parsed });
|
|
6476
6548
|
}
|
|
6477
6549
|
case "list": {
|
|
6478
6550
|
const result = await ctx.page.evaluate(
|
|
6479
6551
|
`(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); })()`
|
|
6480
6552
|
);
|
|
6481
|
-
return
|
|
6553
|
+
return ok29({ action: "list", element: JSON.parse(result) });
|
|
6482
6554
|
}
|
|
6483
6555
|
case "clear": {
|
|
6484
6556
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6485
|
-
return
|
|
6557
|
+
return ok29({ action: "clear" });
|
|
6486
6558
|
}
|
|
6487
6559
|
}
|
|
6488
6560
|
}
|
|
6489
6561
|
});
|
|
6490
6562
|
|
|
6491
6563
|
// src/commands/visual-tag-v2.ts
|
|
6492
|
-
import { z as
|
|
6493
|
-
import { ok as
|
|
6564
|
+
import { z as z31 } from "zod";
|
|
6565
|
+
import { ok as ok30, fail as fail15 } from "@dyyz1993/xcli-core";
|
|
6494
6566
|
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6495
6567
|
var TAG_V2_SCRIPT = `
|
|
6496
6568
|
(function() {
|
|
@@ -6837,45 +6909,45 @@ var visualTagV2Command = registerCommand({
|
|
|
6837
6909
|
name: "visual-tag-v2",
|
|
6838
6910
|
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",
|
|
6839
6911
|
scope: "page",
|
|
6840
|
-
parameters:
|
|
6841
|
-
action:
|
|
6842
|
-
id:
|
|
6843
|
-
query:
|
|
6844
|
-
type:
|
|
6845
|
-
"interact-action":
|
|
6846
|
-
value:
|
|
6912
|
+
parameters: z31.object({
|
|
6913
|
+
action: z31.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
6914
|
+
id: z31.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
6915
|
+
query: z31.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
6916
|
+
type: z31.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
6917
|
+
"interact-action": z31.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
6918
|
+
value: z31.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6847
6919
|
}),
|
|
6848
|
-
result:
|
|
6849
|
-
action:
|
|
6850
|
-
total:
|
|
6851
|
-
byType:
|
|
6852
|
-
element:
|
|
6920
|
+
result: z31.object({
|
|
6921
|
+
action: z31.string(),
|
|
6922
|
+
total: z31.number().optional(),
|
|
6923
|
+
byType: z31.record(z31.number()).optional(),
|
|
6924
|
+
element: z31.record(z31.unknown()).optional()
|
|
6853
6925
|
}),
|
|
6854
6926
|
handler: async (p, ctx) => {
|
|
6855
6927
|
switch (p.action) {
|
|
6856
6928
|
case "tag": {
|
|
6857
6929
|
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6858
6930
|
const parsed = JSON.parse(result);
|
|
6859
|
-
return
|
|
6931
|
+
return ok30({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6860
6932
|
}
|
|
6861
6933
|
case "lookup": {
|
|
6862
|
-
if (!p.id) return
|
|
6934
|
+
if (!p.id) return fail15("lookup \u9700\u8981 --id");
|
|
6863
6935
|
const result = await ctx.page.evaluate(
|
|
6864
6936
|
`(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'})})()`
|
|
6865
6937
|
);
|
|
6866
6938
|
const parsed = JSON.parse(result);
|
|
6867
|
-
if (parsed.err) return
|
|
6868
|
-
return
|
|
6939
|
+
if (parsed.err) return fail15(`ID ${p.id}: ${parsed.err}`);
|
|
6940
|
+
return ok30({ action: "lookup", id: p.id, element: parsed });
|
|
6869
6941
|
}
|
|
6870
6942
|
case "by-type": {
|
|
6871
6943
|
const result = await ctx.page.evaluate(
|
|
6872
6944
|
`(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)})()`
|
|
6873
6945
|
);
|
|
6874
|
-
return
|
|
6946
|
+
return ok30({ action: "by-type", element: JSON.parse(result) });
|
|
6875
6947
|
}
|
|
6876
6948
|
case "find": {
|
|
6877
6949
|
const query = p.query;
|
|
6878
|
-
if (!query) return
|
|
6950
|
+
if (!query) return fail15('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6879
6951
|
const result = await ctx.page.evaluate(
|
|
6880
6952
|
`(function(){
|
|
6881
6953
|
var map = window.__xbTagSerializable;
|
|
@@ -6917,21 +6989,21 @@ var visualTagV2Command = registerCommand({
|
|
|
6917
6989
|
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
6918
6990
|
})()`
|
|
6919
6991
|
);
|
|
6920
|
-
return
|
|
6992
|
+
return ok30({ action: "find", query, element: JSON.parse(result) });
|
|
6921
6993
|
}
|
|
6922
6994
|
case "stats": {
|
|
6923
6995
|
const result = await ctx.page.evaluate(
|
|
6924
6996
|
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
6925
6997
|
);
|
|
6926
|
-
return
|
|
6998
|
+
return ok30({ action: "stats", element: JSON.parse(result) });
|
|
6927
6999
|
}
|
|
6928
7000
|
case "interact": {
|
|
6929
7001
|
const query = p.query;
|
|
6930
7002
|
const pAny = p;
|
|
6931
7003
|
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
6932
7004
|
const value = pAny.value;
|
|
6933
|
-
if (!query) return
|
|
6934
|
-
if (!action) return
|
|
7005
|
+
if (!query) return fail15("interact \u9700\u8981 --query \u53C2\u6570");
|
|
7006
|
+
if (!action) return fail15("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
6935
7007
|
const findResult = await ctx.page.evaluate(
|
|
6936
7008
|
`(function(){
|
|
6937
7009
|
var map = window.__xbTagSerializable;
|
|
@@ -6961,11 +7033,11 @@ var visualTagV2Command = registerCommand({
|
|
|
6961
7033
|
})()`
|
|
6962
7034
|
);
|
|
6963
7035
|
const parsed = JSON.parse(findResult);
|
|
6964
|
-
if (parsed.err) return
|
|
6965
|
-
if (!parsed.total || !parsed.results?.length) return
|
|
7036
|
+
if (parsed.err) return fail15(parsed.err);
|
|
7037
|
+
if (!parsed.total || !parsed.results?.length) return fail15(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
6966
7038
|
const target = parsed.results[0];
|
|
6967
7039
|
if (action === "read") {
|
|
6968
|
-
return
|
|
7040
|
+
return ok30({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
6969
7041
|
}
|
|
6970
7042
|
if (action === "click") {
|
|
6971
7043
|
const el = await ctx.page.evaluate(
|
|
@@ -6978,12 +7050,12 @@ var visualTagV2Command = registerCommand({
|
|
|
6978
7050
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
6979
7051
|
})()`
|
|
6980
7052
|
);
|
|
6981
|
-
if (!el) return
|
|
7053
|
+
if (!el) return fail15(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
6982
7054
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
6983
|
-
return
|
|
7055
|
+
return ok30({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
6984
7056
|
}
|
|
6985
7057
|
if (action === "fill") {
|
|
6986
|
-
if (!value) return
|
|
7058
|
+
if (!value) return fail15("fill \u9700\u8981 --value \u53C2\u6570");
|
|
6987
7059
|
const el = await ctx.page.evaluate(
|
|
6988
7060
|
`(function(){
|
|
6989
7061
|
var map = window.__xbTagMap;
|
|
@@ -6994,12 +7066,12 @@ var visualTagV2Command = registerCommand({
|
|
|
6994
7066
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
6995
7067
|
})()`
|
|
6996
7068
|
);
|
|
6997
|
-
if (!el) return
|
|
7069
|
+
if (!el) return fail15(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
6998
7070
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
6999
7071
|
await ctx.page.keyboard.type(value, { stealth: true });
|
|
7000
|
-
return
|
|
7072
|
+
return ok30({ action: "interact", query, target, result: { filled: true, value } });
|
|
7001
7073
|
}
|
|
7002
|
-
return
|
|
7074
|
+
return fail15(`\u672A\u77E5 action: ${action}`);
|
|
7003
7075
|
}
|
|
7004
7076
|
case "export": {
|
|
7005
7077
|
const result = await ctx.page.evaluate(
|
|
@@ -7047,12 +7119,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7047
7119
|
})()`
|
|
7048
7120
|
);
|
|
7049
7121
|
const parsed = JSON.parse(result);
|
|
7050
|
-
if (parsed.err) return
|
|
7051
|
-
return
|
|
7122
|
+
if (parsed.err) return fail15(String(parsed.err));
|
|
7123
|
+
return ok30({ action: "export", element: parsed });
|
|
7052
7124
|
}
|
|
7053
7125
|
case "clear": {
|
|
7054
7126
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7055
|
-
return
|
|
7127
|
+
return ok30({ action: "clear" });
|
|
7056
7128
|
}
|
|
7057
7129
|
}
|
|
7058
7130
|
}
|
|
@@ -7722,7 +7794,7 @@ async function guardCheck(commandName) {
|
|
|
7722
7794
|
}
|
|
7723
7795
|
}
|
|
7724
7796
|
function errorResult(message) {
|
|
7725
|
-
return { ...
|
|
7797
|
+
return { ...fail16(message), duration: 0 };
|
|
7726
7798
|
}
|
|
7727
7799
|
function tipsToMessages(tips) {
|
|
7728
7800
|
if (!tips || tips.length === 0) return [];
|
|
@@ -7995,7 +8067,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7995
8067
|
timestamp: start
|
|
7996
8068
|
});
|
|
7997
8069
|
if (isSuccess) {
|
|
7998
|
-
return { ...
|
|
8070
|
+
return { ...ok31(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
7999
8071
|
}
|
|
8000
8072
|
const fc = classifyFailure(raw.message);
|
|
8001
8073
|
return {
|
|
@@ -8018,7 +8090,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8018
8090
|
duration,
|
|
8019
8091
|
timestamp: start
|
|
8020
8092
|
});
|
|
8021
|
-
return { ...
|
|
8093
|
+
return { ...ok31(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8022
8094
|
} catch (err) {
|
|
8023
8095
|
const end = Date.now();
|
|
8024
8096
|
const duration = end - start;
|
|
@@ -8063,7 +8135,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8063
8135
|
duration,
|
|
8064
8136
|
timestamp: start
|
|
8065
8137
|
});
|
|
8066
|
-
return { ...
|
|
8138
|
+
return { ...fail16(errorMessage), duration };
|
|
8067
8139
|
} finally {
|
|
8068
8140
|
}
|
|
8069
8141
|
}
|
|
@@ -8108,7 +8180,7 @@ async function executeChain(input, options) {
|
|
|
8108
8180
|
results.push({
|
|
8109
8181
|
command: cmdName,
|
|
8110
8182
|
raw: cmdStr,
|
|
8111
|
-
...
|
|
8183
|
+
...fail16(`Plugin "${cmdName}" requires a sub-command`),
|
|
8112
8184
|
duration: 0
|
|
8113
8185
|
});
|
|
8114
8186
|
if (type === "and") {
|
|
@@ -8127,7 +8199,7 @@ async function executeChain(input, options) {
|
|
|
8127
8199
|
results.push({
|
|
8128
8200
|
command: cmdName,
|
|
8129
8201
|
raw: cmdStr,
|
|
8130
|
-
...
|
|
8202
|
+
...fail16(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
8131
8203
|
duration: 0
|
|
8132
8204
|
});
|
|
8133
8205
|
if (type === "and") {
|
|
@@ -8239,7 +8311,7 @@ async function executeChain(input, options) {
|
|
|
8239
8311
|
results.push({
|
|
8240
8312
|
command: `${cmdName} ${subCommand}`,
|
|
8241
8313
|
raw: cmdStr,
|
|
8242
|
-
...
|
|
8314
|
+
...ok31(data),
|
|
8243
8315
|
duration: duration2,
|
|
8244
8316
|
...hookOutputs ? { hookOutputs } : {}
|
|
8245
8317
|
});
|
|
@@ -8267,7 +8339,7 @@ async function executeChain(input, options) {
|
|
|
8267
8339
|
results.push({
|
|
8268
8340
|
command: `${cmdName} ${subCommand}`,
|
|
8269
8341
|
raw: cmdStr,
|
|
8270
|
-
...
|
|
8342
|
+
...fail16(errorMessage),
|
|
8271
8343
|
duration: duration2
|
|
8272
8344
|
});
|
|
8273
8345
|
if (type === "and") {
|
|
@@ -9691,10 +9763,10 @@ function createRPCHandler() {
|
|
|
9691
9763
|
const errors = Array.isArray(input.errors) ? input.errors : [];
|
|
9692
9764
|
const eventsPlayed = typeof input.eventsPlayed === "number" ? input.eventsPlayed : 0;
|
|
9693
9765
|
const totalEvents = typeof input.totalEvents === "number" ? input.totalEvents : eventsPlayed + errors.length;
|
|
9694
|
-
const
|
|
9766
|
+
const ok32 = input.ok ?? errors.length === 0;
|
|
9695
9767
|
return {
|
|
9696
|
-
ok:
|
|
9697
|
-
success:
|
|
9768
|
+
ok: ok32,
|
|
9769
|
+
success: ok32,
|
|
9698
9770
|
duration: typeof input.duration === "number" ? input.duration : 0,
|
|
9699
9771
|
eventsPlayed,
|
|
9700
9772
|
totalEvents,
|