@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
|
@@ -1781,37 +1781,109 @@ var uaCommand = registerCommand({
|
|
|
1781
1781
|
}
|
|
1782
1782
|
});
|
|
1783
1783
|
|
|
1784
|
-
// src/commands/
|
|
1784
|
+
// src/commands/preflight.ts
|
|
1785
1785
|
import { z as z11 } from "zod";
|
|
1786
1786
|
import { ok as ok11, fail as fail4 } from "@dyyz1993/xcli-core";
|
|
1787
|
+
var preflightCommand = registerCommand({
|
|
1788
|
+
name: "preflight",
|
|
1789
|
+
description: "Pre-flight anti-bot gate: open local detection page and verify stealth posture before any automation task",
|
|
1790
|
+
scope: "page",
|
|
1791
|
+
parameters: z11.object({
|
|
1792
|
+
strict: z11.boolean().optional().describe("\u5931\u8D25\u65F6\u4EE5\u975E\u96F6\u9000\u51FA\u7801\u7ED3\u675F\uFF08\u94FE\u5F0F/CI \u95E8\u7981\u7528\uFF09"),
|
|
1793
|
+
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")
|
|
1794
|
+
}),
|
|
1795
|
+
result: z11.object({
|
|
1796
|
+
gate: z11.enum(["pass", "fail"]),
|
|
1797
|
+
failed: z11.array(z11.string()),
|
|
1798
|
+
headless: z11.boolean()
|
|
1799
|
+
}),
|
|
1800
|
+
handler: async (p, ctx) => {
|
|
1801
|
+
const page = ctx.page;
|
|
1802
|
+
const tips = [];
|
|
1803
|
+
const ua = await page.evaluate("navigator.userAgent").catch(() => "");
|
|
1804
|
+
const outerW = await page.evaluate("window.outerWidth").catch(() => 0);
|
|
1805
|
+
const headless = /headless/i.test(ua) || outerW === 0;
|
|
1806
|
+
const publishMode = p.publish || process.env.XBROWSER_NO_HEADLESS_PUBLISH === "1";
|
|
1807
|
+
if (publishMode && headless) {
|
|
1808
|
+
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");
|
|
1809
|
+
tips.push(' \u6709\u5934 Chrome: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --user-data-dir=~/.xbrowser/chrome-profile-headed --remote-debugging-port=9222');
|
|
1810
|
+
tips.push(" \u7136\u540E\u52A0 --cdp http://localhost:9222");
|
|
1811
|
+
return fail4("PREFLIGHT-FAIL: headless \u4E0D\u5141\u8BB8\u7528\u4E8E\u53D1\u5E03\u7C7B\u4EFB\u52A1\uFF08\u7528 --cdp \u63A5\u6709\u5934 Chrome\uFF09", tips);
|
|
1812
|
+
}
|
|
1813
|
+
let pageUrl = null;
|
|
1814
|
+
try {
|
|
1815
|
+
const { fileURLToPath } = await import("url");
|
|
1816
|
+
const { join: join9, dirname: dirname4 } = await import("path");
|
|
1817
|
+
const { existsSync: existsSync7 } = await import("fs");
|
|
1818
|
+
const here = typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url);
|
|
1819
|
+
const candidates = [
|
|
1820
|
+
join9(dirname4(here), "..", "assets", "preflight.html"),
|
|
1821
|
+
join9(process.cwd(), "assets", "preflight.html")
|
|
1822
|
+
];
|
|
1823
|
+
pageUrl = candidates.find((c) => existsSync7(c)) || null;
|
|
1824
|
+
} catch {
|
|
1825
|
+
}
|
|
1826
|
+
if (pageUrl) {
|
|
1827
|
+
await page.goto("file://" + pageUrl, { waitUntil: "domcontentloaded", timeout: 15e3 });
|
|
1828
|
+
} else {
|
|
1829
|
+
await page.goto("about:blank");
|
|
1830
|
+
await page.evaluate(`(function(){
|
|
1831
|
+
var fails=[];
|
|
1832
|
+
if(navigator.webdriver!==false)fails.push('webdriver');
|
|
1833
|
+
if(/headless/i.test(navigator.userAgent))fails.push('ua-no-headless');
|
|
1834
|
+
window.__pf=fails.join(',');
|
|
1835
|
+
document.title=fails.length?'PREFLIGHT-FAIL':'PREFLIGHT-PASS';
|
|
1836
|
+
})()`);
|
|
1837
|
+
}
|
|
1838
|
+
await page.waitForTimeout(1200);
|
|
1839
|
+
const result = await page.evaluate(`(function(){
|
|
1840
|
+
var out=document.getElementById('out');
|
|
1841
|
+
return { title: document.title, fails: out ? (out.getAttribute('data-fails')||'') : (window.__pf||'') };
|
|
1842
|
+
})()`).catch(() => ({ title: "PREFLIGHT-FAIL", fails: "evaluate-error" }));
|
|
1843
|
+
const passed = result.title === "PREFLIGHT-PASS";
|
|
1844
|
+
const failed = result.fails ? result.fails.split(",").filter(Boolean) : [];
|
|
1845
|
+
tips.push(`headless=${headless}${publishMode ? "\uFF08publish \u95E8\u7981\u5F00\u542F\uFF09" : ""}`);
|
|
1846
|
+
if (passed) {
|
|
1847
|
+
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");
|
|
1848
|
+
return ok11({ gate: "pass", failed: [], headless }, tips);
|
|
1849
|
+
}
|
|
1850
|
+
tips.push(`\u5931\u8D25\u9879: ${failed.join(", ") || result.title}`);
|
|
1851
|
+
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");
|
|
1852
|
+
return fail4(`PREFLIGHT-FAIL: ${failed.join(", ") || result.title}`, tips);
|
|
1853
|
+
}
|
|
1854
|
+
});
|
|
1855
|
+
|
|
1856
|
+
// src/commands/storage.ts
|
|
1857
|
+
import { z as z12 } from "zod";
|
|
1858
|
+
import { ok as ok12, fail as fail5 } from "@dyyz1993/xcli-core";
|
|
1787
1859
|
var getCookiesCommand = registerCommand({
|
|
1788
1860
|
name: "get-cookies",
|
|
1789
1861
|
description: "Get all cookies for the current page",
|
|
1790
1862
|
scope: "page",
|
|
1791
|
-
result:
|
|
1792
|
-
cookies:
|
|
1863
|
+
result: z12.object({
|
|
1864
|
+
cookies: z12.array(z12.record(z12.unknown()))
|
|
1793
1865
|
}),
|
|
1794
1866
|
handler: async (_p, ctx) => {
|
|
1795
1867
|
const cookies = await ctx.browserContext.cookies();
|
|
1796
|
-
return
|
|
1868
|
+
return ok12({ cookies });
|
|
1797
1869
|
}
|
|
1798
1870
|
});
|
|
1799
1871
|
var setCookieCommand = registerCommand({
|
|
1800
1872
|
name: "set-cookie",
|
|
1801
1873
|
description: "Set a cookie",
|
|
1802
1874
|
scope: "page",
|
|
1803
|
-
parameters:
|
|
1804
|
-
name:
|
|
1805
|
-
value:
|
|
1806
|
-
domain:
|
|
1807
|
-
path:
|
|
1808
|
-
url:
|
|
1809
|
-
expires:
|
|
1810
|
-
httpOnly:
|
|
1811
|
-
secure:
|
|
1812
|
-
sameSite:
|
|
1875
|
+
parameters: z12.object({
|
|
1876
|
+
name: z12.coerce.string(),
|
|
1877
|
+
value: z12.coerce.string(),
|
|
1878
|
+
domain: z12.coerce.string().optional(),
|
|
1879
|
+
path: z12.coerce.string().optional(),
|
|
1880
|
+
url: z12.string().optional().describe("Cookie URL (alternative to domain)"),
|
|
1881
|
+
expires: z12.number().optional(),
|
|
1882
|
+
httpOnly: z12.boolean().optional(),
|
|
1883
|
+
secure: z12.boolean().optional(),
|
|
1884
|
+
sameSite: z12.enum(["Strict", "Lax", "None"]).optional()
|
|
1813
1885
|
}),
|
|
1814
|
-
result:
|
|
1886
|
+
result: z12.object({ name: z12.string() }),
|
|
1815
1887
|
handler: async (p, ctx) => {
|
|
1816
1888
|
const cookie = { ...p };
|
|
1817
1889
|
if (!cookie.domain && !cookie.url) {
|
|
@@ -1826,38 +1898,38 @@ var setCookieCommand = registerCommand({
|
|
|
1826
1898
|
}
|
|
1827
1899
|
}
|
|
1828
1900
|
if (!cookie.domain && !cookie.url) {
|
|
1829
|
-
return
|
|
1901
|
+
return fail5("set-cookie requires --domain or --url, or a non-blank page URL to infer from");
|
|
1830
1902
|
}
|
|
1831
1903
|
await ctx.browserContext.addCookies([cookie]);
|
|
1832
|
-
return
|
|
1904
|
+
return ok12({ name: p.name });
|
|
1833
1905
|
}
|
|
1834
1906
|
});
|
|
1835
1907
|
var clearCookiesCommand = registerCommand({
|
|
1836
1908
|
name: "clear-cookies",
|
|
1837
1909
|
description: "Clear all cookies",
|
|
1838
1910
|
scope: "page",
|
|
1839
|
-
result:
|
|
1911
|
+
result: z12.object({ cleared: z12.boolean() }),
|
|
1840
1912
|
handler: async (_p, ctx) => {
|
|
1841
1913
|
await ctx.browserContext.clearCookies();
|
|
1842
|
-
return
|
|
1914
|
+
return ok12({ cleared: true });
|
|
1843
1915
|
}
|
|
1844
1916
|
});
|
|
1845
1917
|
var getLocalStorageCommand = registerCommand({
|
|
1846
1918
|
name: "get-local-storage",
|
|
1847
1919
|
description: "Get localStorage entries",
|
|
1848
1920
|
scope: "page",
|
|
1849
|
-
parameters:
|
|
1850
|
-
key:
|
|
1921
|
+
parameters: z12.object({
|
|
1922
|
+
key: z12.string().optional()
|
|
1851
1923
|
}),
|
|
1852
|
-
result:
|
|
1853
|
-
|
|
1854
|
-
|
|
1924
|
+
result: z12.union([
|
|
1925
|
+
z12.object({ key: z12.string(), value: z12.string().nullable() }),
|
|
1926
|
+
z12.object({ data: z12.record(z12.string()) })
|
|
1855
1927
|
]),
|
|
1856
1928
|
handler: async (p, ctx) => {
|
|
1857
1929
|
try {
|
|
1858
1930
|
if (p.key) {
|
|
1859
1931
|
const value = await ctx.page.evaluate((k) => localStorage.getItem(k), p.key);
|
|
1860
|
-
return
|
|
1932
|
+
return ok12({ key: p.key, value });
|
|
1861
1933
|
}
|
|
1862
1934
|
const data = await ctx.page.evaluate(() => {
|
|
1863
1935
|
const entries = {};
|
|
@@ -1867,9 +1939,9 @@ var getLocalStorageCommand = registerCommand({
|
|
|
1867
1939
|
}
|
|
1868
1940
|
return entries;
|
|
1869
1941
|
});
|
|
1870
|
-
return
|
|
1942
|
+
return ok12({ data });
|
|
1871
1943
|
} catch (e) {
|
|
1872
|
-
return
|
|
1944
|
+
return fail5(`localStorage not accessible on this page: ${e instanceof Error ? e.message : String(e)}`);
|
|
1873
1945
|
}
|
|
1874
1946
|
}
|
|
1875
1947
|
});
|
|
@@ -1877,11 +1949,11 @@ var setLocalStorageCommand = registerCommand({
|
|
|
1877
1949
|
name: "set-local-storage",
|
|
1878
1950
|
description: "Set a localStorage entry",
|
|
1879
1951
|
scope: "page",
|
|
1880
|
-
parameters:
|
|
1881
|
-
key:
|
|
1882
|
-
value:
|
|
1952
|
+
parameters: z12.object({
|
|
1953
|
+
key: z12.string(),
|
|
1954
|
+
value: z12.string()
|
|
1883
1955
|
}),
|
|
1884
|
-
result:
|
|
1956
|
+
result: z12.object({ key: z12.string() }),
|
|
1885
1957
|
handler: async (p, ctx) => {
|
|
1886
1958
|
try {
|
|
1887
1959
|
await ctx.page.evaluate(
|
|
@@ -1890,9 +1962,9 @@ var setLocalStorageCommand = registerCommand({
|
|
|
1890
1962
|
},
|
|
1891
1963
|
{ key: p.key, value: p.value }
|
|
1892
1964
|
);
|
|
1893
|
-
return
|
|
1965
|
+
return ok12({ key: p.key });
|
|
1894
1966
|
} catch (e) {
|
|
1895
|
-
return
|
|
1967
|
+
return fail5(`localStorage not accessible on this page: ${e instanceof Error ? e.message : String(e)}`);
|
|
1896
1968
|
}
|
|
1897
1969
|
}
|
|
1898
1970
|
});
|
|
@@ -1900,20 +1972,20 @@ var clearLocalStorageCommand = registerCommand({
|
|
|
1900
1972
|
name: "clear-local-storage",
|
|
1901
1973
|
description: "Clear all localStorage entries",
|
|
1902
1974
|
scope: "page",
|
|
1903
|
-
result:
|
|
1975
|
+
result: z12.object({ cleared: z12.boolean() }),
|
|
1904
1976
|
handler: async (_p, ctx) => {
|
|
1905
1977
|
try {
|
|
1906
1978
|
await ctx.page.evaluate(() => localStorage.clear());
|
|
1907
|
-
return
|
|
1979
|
+
return ok12({ cleared: true });
|
|
1908
1980
|
} catch (e) {
|
|
1909
|
-
return
|
|
1981
|
+
return fail5(`localStorage not accessible on this page: ${e instanceof Error ? e.message : String(e)}`);
|
|
1910
1982
|
}
|
|
1911
1983
|
}
|
|
1912
1984
|
});
|
|
1913
1985
|
|
|
1914
1986
|
// src/commands/screenshot.ts
|
|
1915
|
-
import { z as
|
|
1916
|
-
import { ok as
|
|
1987
|
+
import { z as z13 } from "zod";
|
|
1988
|
+
import { ok as ok13, fail as fail6 } from "@dyyz1993/xcli-core";
|
|
1917
1989
|
import { writeFileSync, mkdirSync } from "fs";
|
|
1918
1990
|
import { dirname, join as join3 } from "path";
|
|
1919
1991
|
function ensureScreenshotsDir() {
|
|
@@ -1940,23 +2012,23 @@ var screenshotCommand = registerCommand({
|
|
|
1940
2012
|
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>)",
|
|
1941
2013
|
scope: "page",
|
|
1942
2014
|
selectorParams: ["selector"],
|
|
1943
|
-
parameters:
|
|
1944
|
-
selector:
|
|
1945
|
-
type:
|
|
1946
|
-
fullPage:
|
|
1947
|
-
output:
|
|
1948
|
-
base64:
|
|
2015
|
+
parameters: z13.object({
|
|
2016
|
+
selector: z13.string().optional(),
|
|
2017
|
+
type: z13.enum(["png", "jpeg"]).optional(),
|
|
2018
|
+
fullPage: z13.boolean().optional(),
|
|
2019
|
+
output: z13.string().optional(),
|
|
2020
|
+
base64: z13.boolean().optional().describe("Return base64 data instead of file path")
|
|
1949
2021
|
}),
|
|
1950
|
-
result:
|
|
1951
|
-
|
|
1952
|
-
data:
|
|
1953
|
-
format:
|
|
1954
|
-
size:
|
|
2022
|
+
result: z13.union([
|
|
2023
|
+
z13.object({
|
|
2024
|
+
data: z13.string(),
|
|
2025
|
+
format: z13.string(),
|
|
2026
|
+
size: z13.number()
|
|
1955
2027
|
}),
|
|
1956
|
-
|
|
1957
|
-
output:
|
|
1958
|
-
format:
|
|
1959
|
-
size:
|
|
2028
|
+
z13.object({
|
|
2029
|
+
output: z13.string(),
|
|
2030
|
+
format: z13.string(),
|
|
2031
|
+
size: z13.number()
|
|
1960
2032
|
})
|
|
1961
2033
|
]),
|
|
1962
2034
|
handler: async (p, ctx) => {
|
|
@@ -1974,21 +2046,21 @@ var screenshotCommand = registerCommand({
|
|
|
1974
2046
|
if (p.output) {
|
|
1975
2047
|
const dirErr = ensureParentDir(p.output);
|
|
1976
2048
|
if (dirErr) {
|
|
1977
|
-
return
|
|
2049
|
+
return fail6(`Cannot create directory for --output "${p.output}": ${dirErr}`);
|
|
1978
2050
|
}
|
|
1979
2051
|
try {
|
|
1980
2052
|
writeFileSync(p.output, buffer, "binary");
|
|
1981
2053
|
} catch (err) {
|
|
1982
|
-
return
|
|
2054
|
+
return fail6(`Failed to write screenshot to "${p.output}": ${err instanceof Error ? err.message : String(err)}`);
|
|
1983
2055
|
}
|
|
1984
|
-
return
|
|
2056
|
+
return ok13({
|
|
1985
2057
|
output: p.output,
|
|
1986
2058
|
format,
|
|
1987
2059
|
size: buffer.length
|
|
1988
2060
|
});
|
|
1989
2061
|
}
|
|
1990
2062
|
if (p.base64) {
|
|
1991
|
-
return
|
|
2063
|
+
return ok13({
|
|
1992
2064
|
data: buffer.toString("base64"),
|
|
1993
2065
|
format,
|
|
1994
2066
|
size: buffer.length
|
|
@@ -1997,7 +2069,7 @@ var screenshotCommand = registerCommand({
|
|
|
1997
2069
|
ensureScreenshotsDir();
|
|
1998
2070
|
const screenshotPath = generateScreenshotPath(format);
|
|
1999
2071
|
writeFileSync(screenshotPath, buffer, "binary");
|
|
2000
|
-
return
|
|
2072
|
+
return ok13({
|
|
2001
2073
|
output: screenshotPath,
|
|
2002
2074
|
format,
|
|
2003
2075
|
size: buffer.length
|
|
@@ -2006,19 +2078,19 @@ var screenshotCommand = registerCommand({
|
|
|
2006
2078
|
});
|
|
2007
2079
|
|
|
2008
2080
|
// src/commands/structure.ts
|
|
2009
|
-
import { z as
|
|
2010
|
-
import { ok as
|
|
2081
|
+
import { z as z14 } from "zod";
|
|
2082
|
+
import { ok as ok14 } from "@dyyz1993/xcli-core";
|
|
2011
2083
|
var structureCommand = registerCommand({
|
|
2012
2084
|
name: "structure",
|
|
2013
2085
|
description: "Get the DOM structure of the page or an element",
|
|
2014
2086
|
scope: "page",
|
|
2015
2087
|
selectorParams: ["selector"],
|
|
2016
|
-
parameters:
|
|
2017
|
-
selector:
|
|
2018
|
-
depth:
|
|
2088
|
+
parameters: z14.object({
|
|
2089
|
+
selector: z14.string().optional(),
|
|
2090
|
+
depth: z14.number().optional()
|
|
2019
2091
|
}),
|
|
2020
|
-
result:
|
|
2021
|
-
structure:
|
|
2092
|
+
result: z14.object({
|
|
2093
|
+
structure: z14.record(z14.unknown())
|
|
2022
2094
|
}),
|
|
2023
2095
|
handler: async (p, ctx) => {
|
|
2024
2096
|
const structure = await ctx.page.evaluate(
|
|
@@ -2050,30 +2122,30 @@ var structureCommand = registerCommand({
|
|
|
2050
2122
|
},
|
|
2051
2123
|
{ sel: p.selector || "body", maxDepth: p.depth || 5 }
|
|
2052
2124
|
);
|
|
2053
|
-
return
|
|
2125
|
+
return ok14({ structure });
|
|
2054
2126
|
}
|
|
2055
2127
|
});
|
|
2056
2128
|
|
|
2057
2129
|
// src/commands/viewport.ts
|
|
2058
|
-
import { z as
|
|
2059
|
-
import { ok as
|
|
2130
|
+
import { z as z15 } from "zod";
|
|
2131
|
+
import { ok as ok15 } from "@dyyz1993/xcli-core";
|
|
2060
2132
|
var setViewportCommand = registerCommand({
|
|
2061
2133
|
name: "set-viewport",
|
|
2062
2134
|
description: "Set the viewport size and properties",
|
|
2063
2135
|
scope: "browser",
|
|
2064
|
-
parameters:
|
|
2065
|
-
width:
|
|
2066
|
-
height:
|
|
2067
|
-
deviceScaleFactor:
|
|
2068
|
-
isMobile:
|
|
2069
|
-
hasTouch:
|
|
2136
|
+
parameters: z15.object({
|
|
2137
|
+
width: z15.coerce.number(),
|
|
2138
|
+
height: z15.coerce.number(),
|
|
2139
|
+
deviceScaleFactor: z15.coerce.number().optional(),
|
|
2140
|
+
isMobile: z15.boolean().optional(),
|
|
2141
|
+
hasTouch: z15.boolean().optional()
|
|
2070
2142
|
}),
|
|
2071
|
-
result:
|
|
2072
|
-
width:
|
|
2073
|
-
height:
|
|
2074
|
-
deviceScaleFactor:
|
|
2075
|
-
isMobile:
|
|
2076
|
-
hasTouch:
|
|
2143
|
+
result: z15.object({
|
|
2144
|
+
width: z15.number(),
|
|
2145
|
+
height: z15.number(),
|
|
2146
|
+
deviceScaleFactor: z15.number().optional(),
|
|
2147
|
+
isMobile: z15.boolean().optional(),
|
|
2148
|
+
hasTouch: z15.boolean().optional()
|
|
2077
2149
|
}),
|
|
2078
2150
|
handler: async (p, ctx) => {
|
|
2079
2151
|
const viewport = ctx.page.viewportSize();
|
|
@@ -2086,7 +2158,7 @@ var setViewportCommand = registerCommand({
|
|
|
2086
2158
|
...p.isMobile !== void 0 && { isMobile: p.isMobile },
|
|
2087
2159
|
...p.hasTouch !== void 0 && { hasTouch: p.hasTouch }
|
|
2088
2160
|
});
|
|
2089
|
-
return
|
|
2161
|
+
return ok15({
|
|
2090
2162
|
width,
|
|
2091
2163
|
height,
|
|
2092
2164
|
...p.deviceScaleFactor !== void 0 && { deviceScaleFactor: p.deviceScaleFactor },
|
|
@@ -2097,17 +2169,17 @@ var setViewportCommand = registerCommand({
|
|
|
2097
2169
|
});
|
|
2098
2170
|
|
|
2099
2171
|
// src/commands/frame.ts
|
|
2100
|
-
import { z as
|
|
2101
|
-
import { ok as
|
|
2172
|
+
import { z as z16 } from "zod";
|
|
2173
|
+
import { ok as ok16, fail as fail7 } from "@dyyz1993/xcli-core";
|
|
2102
2174
|
var framesCommand = registerCommand({
|
|
2103
2175
|
name: "frames",
|
|
2104
2176
|
description: "List all frames in the current page",
|
|
2105
2177
|
scope: "page",
|
|
2106
|
-
result:
|
|
2107
|
-
frames:
|
|
2108
|
-
index:
|
|
2109
|
-
name:
|
|
2110
|
-
url:
|
|
2178
|
+
result: z16.object({
|
|
2179
|
+
frames: z16.array(z16.object({
|
|
2180
|
+
index: z16.number(),
|
|
2181
|
+
name: z16.string().nullable(),
|
|
2182
|
+
url: z16.string()
|
|
2111
2183
|
}))
|
|
2112
2184
|
}),
|
|
2113
2185
|
handler: async (_p, ctx) => {
|
|
@@ -2118,21 +2190,21 @@ var framesCommand = registerCommand({
|
|
|
2118
2190
|
name: frame.name(),
|
|
2119
2191
|
url: frame.url()
|
|
2120
2192
|
}));
|
|
2121
|
-
return
|
|
2193
|
+
return ok16({ frames: frameList });
|
|
2122
2194
|
}
|
|
2123
2195
|
});
|
|
2124
2196
|
var frameCommand = registerCommand({
|
|
2125
2197
|
name: "frame",
|
|
2126
2198
|
description: "Get frame info by index or name",
|
|
2127
2199
|
scope: "page",
|
|
2128
|
-
parameters:
|
|
2129
|
-
index:
|
|
2130
|
-
name:
|
|
2200
|
+
parameters: z16.object({
|
|
2201
|
+
index: z16.number().int().min(0).optional(),
|
|
2202
|
+
name: z16.string().optional()
|
|
2131
2203
|
}),
|
|
2132
|
-
result:
|
|
2133
|
-
name:
|
|
2134
|
-
url:
|
|
2135
|
-
error:
|
|
2204
|
+
result: z16.object({
|
|
2205
|
+
name: z16.string().nullable(),
|
|
2206
|
+
url: z16.string(),
|
|
2207
|
+
error: z16.string().optional()
|
|
2136
2208
|
}),
|
|
2137
2209
|
handler: async (p, ctx) => {
|
|
2138
2210
|
const discover = ctx.page.discoverFrames;
|
|
@@ -2143,12 +2215,12 @@ var frameCommand = registerCommand({
|
|
|
2143
2215
|
} else if (p.name !== void 0) {
|
|
2144
2216
|
targetFrame = rawFrames.find((f) => f.name() === p.name);
|
|
2145
2217
|
} else {
|
|
2146
|
-
return
|
|
2218
|
+
return fail7("Must provide index or name");
|
|
2147
2219
|
}
|
|
2148
2220
|
if (!targetFrame) {
|
|
2149
|
-
return
|
|
2221
|
+
return fail7("Frame not found");
|
|
2150
2222
|
}
|
|
2151
|
-
return
|
|
2223
|
+
return ok16({
|
|
2152
2224
|
name: targetFrame.name(),
|
|
2153
2225
|
url: targetFrame.url()
|
|
2154
2226
|
});
|
|
@@ -2156,27 +2228,27 @@ var frameCommand = registerCommand({
|
|
|
2156
2228
|
});
|
|
2157
2229
|
|
|
2158
2230
|
// src/commands/ui-debug.ts
|
|
2159
|
-
import { z as
|
|
2160
|
-
import { ok as
|
|
2231
|
+
import { z as z17 } from "zod";
|
|
2232
|
+
import { ok as ok17 } from "@dyyz1993/xcli-core";
|
|
2161
2233
|
var consoleCheckCommand = registerCommand({
|
|
2162
2234
|
name: "console",
|
|
2163
2235
|
description: "Collect and analyze browser console messages (errors, warnings, logs)",
|
|
2164
2236
|
scope: "page",
|
|
2165
|
-
parameters:
|
|
2166
|
-
url:
|
|
2167
|
-
duration:
|
|
2168
|
-
filter:
|
|
2169
|
-
includeStackTraces:
|
|
2237
|
+
parameters: z17.object({
|
|
2238
|
+
url: z17.string().optional().describe("URL to navigate first (optional, uses current page if omitted)"),
|
|
2239
|
+
duration: z17.number().optional().default(5e3).describe("How long to collect messages (ms)"),
|
|
2240
|
+
filter: z17.enum(["all", "error", "warning", "info", "log"]).optional().default("all"),
|
|
2241
|
+
includeStackTraces: z17.boolean().optional().default(true)
|
|
2170
2242
|
}),
|
|
2171
|
-
result:
|
|
2172
|
-
url:
|
|
2173
|
-
duration:
|
|
2174
|
-
total:
|
|
2175
|
-
errors:
|
|
2176
|
-
warnings:
|
|
2177
|
-
messages:
|
|
2178
|
-
summary:
|
|
2179
|
-
passed:
|
|
2243
|
+
result: z17.object({
|
|
2244
|
+
url: z17.string(),
|
|
2245
|
+
duration: z17.number(),
|
|
2246
|
+
total: z17.number(),
|
|
2247
|
+
errors: z17.number(),
|
|
2248
|
+
warnings: z17.number(),
|
|
2249
|
+
messages: z17.array(z17.record(z17.unknown())),
|
|
2250
|
+
summary: z17.string(),
|
|
2251
|
+
passed: z17.boolean()
|
|
2180
2252
|
}),
|
|
2181
2253
|
handler: async (p, ctx) => {
|
|
2182
2254
|
const { page } = ctx;
|
|
@@ -2258,7 +2330,7 @@ ${a.stack || ""}`;
|
|
|
2258
2330
|
const filtered = p.filter === "all" ? messages : messages.filter((m) => m.type === p.filter);
|
|
2259
2331
|
const errorCount = messages.filter((m) => m.type === "error").length;
|
|
2260
2332
|
const warnCount = messages.filter((m) => m.type === "warning").length;
|
|
2261
|
-
return
|
|
2333
|
+
return ok17({
|
|
2262
2334
|
url: page.url(),
|
|
2263
2335
|
duration: p.duration,
|
|
2264
2336
|
total: messages.length,
|
|
@@ -2274,23 +2346,23 @@ var networkCheckCommand = registerCommand({
|
|
|
2274
2346
|
name: "net-debug",
|
|
2275
2347
|
description: "Monitor and analyze network requests \u2014 capture failed requests, slow responses, status codes",
|
|
2276
2348
|
scope: "page",
|
|
2277
|
-
parameters:
|
|
2278
|
-
url:
|
|
2279
|
-
duration:
|
|
2280
|
-
filter:
|
|
2281
|
-
slowThreshold:
|
|
2349
|
+
parameters: z17.object({
|
|
2350
|
+
url: z17.string().optional().describe("URL to navigate first"),
|
|
2351
|
+
duration: z17.number().optional().default(5e3).describe("How long to monitor (ms)"),
|
|
2352
|
+
filter: z17.enum(["all", "failed", "slow", "error", "xhr", "fetch", "document", "stylesheet", "script", "image"]).optional().default("all"),
|
|
2353
|
+
slowThreshold: z17.number().optional().default(3e3).describe('Threshold for "slow" requests (ms)')
|
|
2282
2354
|
}),
|
|
2283
|
-
result:
|
|
2284
|
-
url:
|
|
2285
|
-
duration:
|
|
2286
|
-
totalRequests:
|
|
2287
|
-
failedRequests:
|
|
2288
|
-
slowRequests:
|
|
2289
|
-
errorRequests:
|
|
2290
|
-
totalSizeKB:
|
|
2291
|
-
requests:
|
|
2292
|
-
summary:
|
|
2293
|
-
passed:
|
|
2355
|
+
result: z17.object({
|
|
2356
|
+
url: z17.string(),
|
|
2357
|
+
duration: z17.number(),
|
|
2358
|
+
totalRequests: z17.number(),
|
|
2359
|
+
failedRequests: z17.number(),
|
|
2360
|
+
slowRequests: z17.number(),
|
|
2361
|
+
errorRequests: z17.number(),
|
|
2362
|
+
totalSizeKB: z17.number(),
|
|
2363
|
+
requests: z17.array(z17.record(z17.unknown())),
|
|
2364
|
+
summary: z17.string(),
|
|
2365
|
+
passed: z17.boolean()
|
|
2294
2366
|
}),
|
|
2295
2367
|
handler: async (p, ctx) => {
|
|
2296
2368
|
const { page } = ctx;
|
|
@@ -2372,7 +2444,7 @@ var networkCheckCommand = registerCommand({
|
|
|
2372
2444
|
const slowCount = requests.filter((r) => r.duration >= p.slowThreshold).length;
|
|
2373
2445
|
const errorCount = requests.filter((r) => r.error).length;
|
|
2374
2446
|
const totalSize = requests.reduce((sum, r) => sum + r.size, 0);
|
|
2375
|
-
return
|
|
2447
|
+
return ok17({
|
|
2376
2448
|
url: page.url(),
|
|
2377
2449
|
duration: p.duration,
|
|
2378
2450
|
totalRequests: requests.length,
|
|
@@ -2394,17 +2466,17 @@ var perfCheckCommand = registerCommand({
|
|
|
2394
2466
|
name: "perf",
|
|
2395
2467
|
description: "Audit page performance metrics \u2014 load time, FCP, LCP, CLS, TTFB, resource sizes",
|
|
2396
2468
|
scope: "page",
|
|
2397
|
-
parameters:
|
|
2398
|
-
url:
|
|
2399
|
-
iterations:
|
|
2469
|
+
parameters: z17.object({
|
|
2470
|
+
url: z17.string().optional().describe("URL to navigate (uses current page if omitted)"),
|
|
2471
|
+
iterations: z17.number().optional().default(1).describe("Number of iterations to average")
|
|
2400
2472
|
}),
|
|
2401
|
-
result:
|
|
2402
|
-
url:
|
|
2403
|
-
iterations:
|
|
2404
|
-
metrics:
|
|
2405
|
-
allIterations:
|
|
2406
|
-
passed:
|
|
2407
|
-
summary:
|
|
2473
|
+
result: z17.object({
|
|
2474
|
+
url: z17.string(),
|
|
2475
|
+
iterations: z17.number(),
|
|
2476
|
+
metrics: z17.record(z17.unknown()),
|
|
2477
|
+
allIterations: z17.array(z17.record(z17.unknown())).optional(),
|
|
2478
|
+
passed: z17.boolean(),
|
|
2479
|
+
summary: z17.string()
|
|
2408
2480
|
}),
|
|
2409
2481
|
handler: async (p, ctx) => {
|
|
2410
2482
|
const { page } = ctx;
|
|
@@ -2466,7 +2538,7 @@ var perfCheckCommand = registerCommand({
|
|
|
2466
2538
|
if (resourceStats) avg.resourceStats = resourceStats;
|
|
2467
2539
|
return avg;
|
|
2468
2540
|
})();
|
|
2469
|
-
return
|
|
2541
|
+
return ok17({
|
|
2470
2542
|
url: page.url(),
|
|
2471
2543
|
iterations: p.iterations,
|
|
2472
2544
|
metrics: avgMetrics,
|
|
@@ -2480,23 +2552,23 @@ var healthCheckCommand = registerCommand({
|
|
|
2480
2552
|
name: "health",
|
|
2481
2553
|
description: "Comprehensive page health check \u2014 broken links, missing images, console errors, SEO issues",
|
|
2482
2554
|
scope: "page",
|
|
2483
|
-
parameters:
|
|
2484
|
-
url:
|
|
2485
|
-
checkLinks:
|
|
2486
|
-
checkImages:
|
|
2487
|
-
checkMeta:
|
|
2488
|
-
maxLinks:
|
|
2555
|
+
parameters: z17.object({
|
|
2556
|
+
url: z17.string().optional().describe("URL to check"),
|
|
2557
|
+
checkLinks: z17.boolean().optional().default(true).describe("Check for broken links"),
|
|
2558
|
+
checkImages: z17.boolean().optional().default(true).describe("Check for missing/broken images"),
|
|
2559
|
+
checkMeta: z17.boolean().optional().default(true).describe("Check SEO meta tags"),
|
|
2560
|
+
maxLinks: z17.number().optional().default(50).describe("Max links to check")
|
|
2489
2561
|
}),
|
|
2490
|
-
result:
|
|
2491
|
-
url:
|
|
2492
|
-
title:
|
|
2493
|
-
passed:
|
|
2494
|
-
totalIssues:
|
|
2495
|
-
errors:
|
|
2496
|
-
warnings:
|
|
2497
|
-
info:
|
|
2498
|
-
issues:
|
|
2499
|
-
summary:
|
|
2562
|
+
result: z17.object({
|
|
2563
|
+
url: z17.string(),
|
|
2564
|
+
title: z17.string(),
|
|
2565
|
+
passed: z17.boolean(),
|
|
2566
|
+
totalIssues: z17.number(),
|
|
2567
|
+
errors: z17.number(),
|
|
2568
|
+
warnings: z17.number(),
|
|
2569
|
+
info: z17.number(),
|
|
2570
|
+
issues: z17.array(z17.record(z17.unknown())),
|
|
2571
|
+
summary: z17.string()
|
|
2500
2572
|
}),
|
|
2501
2573
|
handler: async (p, ctx) => {
|
|
2502
2574
|
const { page } = ctx;
|
|
@@ -2583,7 +2655,7 @@ var healthCheckCommand = registerCommand({
|
|
|
2583
2655
|
}, { checkLinks: p.checkLinks, checkImages: p.checkImages, checkMeta: p.checkMeta, maxLinks: p.maxLinks });
|
|
2584
2656
|
const errors = result.issues.filter((i) => i.severity === "error").length;
|
|
2585
2657
|
const warnings = result.issues.filter((i) => i.severity === "warning").length;
|
|
2586
|
-
return
|
|
2658
|
+
return ok17({
|
|
2587
2659
|
url: result.url,
|
|
2588
2660
|
title: result.title,
|
|
2589
2661
|
passed: errors === 0,
|
|
@@ -2598,8 +2670,8 @@ var healthCheckCommand = registerCommand({
|
|
|
2598
2670
|
});
|
|
2599
2671
|
|
|
2600
2672
|
// src/commands/actions.ts
|
|
2601
|
-
import { z as
|
|
2602
|
-
import { ok as
|
|
2673
|
+
import { z as z18 } from "zod";
|
|
2674
|
+
import { ok as ok18 } from "@dyyz1993/xcli-core";
|
|
2603
2675
|
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
2604
2676
|
import { join as join4 } from "path";
|
|
2605
2677
|
function ensureScreenshotsDir2() {
|
|
@@ -2611,53 +2683,53 @@ function generateScreenshotPath2(format) {
|
|
|
2611
2683
|
const ext = format === "jpeg" ? "jpg" : "png";
|
|
2612
2684
|
return join4(resolveScreenshotsDir(), `screenshot-${timestamp}-${random}.${ext}`);
|
|
2613
2685
|
}
|
|
2614
|
-
var waitActionSchema =
|
|
2615
|
-
type:
|
|
2616
|
-
milliseconds:
|
|
2617
|
-
selector:
|
|
2686
|
+
var waitActionSchema = z18.object({
|
|
2687
|
+
type: z18.literal("wait"),
|
|
2688
|
+
milliseconds: z18.number().positive().optional(),
|
|
2689
|
+
selector: z18.string().optional()
|
|
2618
2690
|
}).refine(
|
|
2619
2691
|
(d) => (d.milliseconds !== void 0 || d.selector !== void 0) && !(d.milliseconds !== void 0 && d.selector !== void 0),
|
|
2620
2692
|
{ message: "Either 'milliseconds' or 'selector' must be provided, but not both." }
|
|
2621
2693
|
);
|
|
2622
|
-
var clickActionSchema =
|
|
2623
|
-
type:
|
|
2624
|
-
selector:
|
|
2625
|
-
all:
|
|
2694
|
+
var clickActionSchema = z18.object({
|
|
2695
|
+
type: z18.literal("click"),
|
|
2696
|
+
selector: z18.string(),
|
|
2697
|
+
all: z18.boolean().optional()
|
|
2626
2698
|
});
|
|
2627
|
-
var screenshotActionSchema =
|
|
2628
|
-
type:
|
|
2629
|
-
fullPage:
|
|
2630
|
-
quality:
|
|
2631
|
-
viewport:
|
|
2632
|
-
base64:
|
|
2699
|
+
var screenshotActionSchema = z18.object({
|
|
2700
|
+
type: z18.literal("screenshot"),
|
|
2701
|
+
fullPage: z18.boolean().optional(),
|
|
2702
|
+
quality: z18.number().min(1).max(100).optional(),
|
|
2703
|
+
viewport: z18.object({ width: z18.number().int().positive(), height: z18.number().int().positive() }).optional(),
|
|
2704
|
+
base64: z18.boolean().optional().describe("Return base64 data instead of file path")
|
|
2633
2705
|
});
|
|
2634
|
-
var writeActionSchema =
|
|
2635
|
-
type:
|
|
2636
|
-
text:
|
|
2706
|
+
var writeActionSchema = z18.object({
|
|
2707
|
+
type: z18.literal("write"),
|
|
2708
|
+
text: z18.string()
|
|
2637
2709
|
});
|
|
2638
|
-
var pressActionSchema =
|
|
2639
|
-
type:
|
|
2640
|
-
key:
|
|
2710
|
+
var pressActionSchema = z18.object({
|
|
2711
|
+
type: z18.literal("press"),
|
|
2712
|
+
key: z18.string()
|
|
2641
2713
|
});
|
|
2642
|
-
var scrollActionSchema =
|
|
2643
|
-
type:
|
|
2644
|
-
direction:
|
|
2645
|
-
selector:
|
|
2714
|
+
var scrollActionSchema = z18.object({
|
|
2715
|
+
type: z18.literal("scroll"),
|
|
2716
|
+
direction: z18.enum(["up", "down"]).optional(),
|
|
2717
|
+
selector: z18.string().optional()
|
|
2646
2718
|
});
|
|
2647
|
-
var scrapeActionSchema =
|
|
2648
|
-
type:
|
|
2719
|
+
var scrapeActionSchema = z18.object({
|
|
2720
|
+
type: z18.literal("scrape")
|
|
2649
2721
|
});
|
|
2650
|
-
var executeJavascriptActionSchema =
|
|
2651
|
-
type:
|
|
2652
|
-
script:
|
|
2722
|
+
var executeJavascriptActionSchema = z18.object({
|
|
2723
|
+
type: z18.literal("executeJavascript"),
|
|
2724
|
+
script: z18.string()
|
|
2653
2725
|
});
|
|
2654
|
-
var pdfActionSchema =
|
|
2655
|
-
type:
|
|
2656
|
-
landscape:
|
|
2657
|
-
scale:
|
|
2658
|
-
format:
|
|
2726
|
+
var pdfActionSchema = z18.object({
|
|
2727
|
+
type: z18.literal("pdf"),
|
|
2728
|
+
landscape: z18.boolean().optional(),
|
|
2729
|
+
scale: z18.number().optional(),
|
|
2730
|
+
format: z18.enum(["A0", "A1", "A2", "A3", "A4", "A5", "A6", "Letter", "Legal", "Tabloid", "Ledger"]).optional()
|
|
2659
2731
|
});
|
|
2660
|
-
var actionSchema =
|
|
2732
|
+
var actionSchema = z18.union([
|
|
2661
2733
|
waitActionSchema,
|
|
2662
2734
|
clickActionSchema,
|
|
2663
2735
|
screenshotActionSchema,
|
|
@@ -2748,11 +2820,11 @@ var actionsCommand = registerCommand({
|
|
|
2748
2820
|
name: "actions",
|
|
2749
2821
|
description: "Execute a sequence of actions (wait, click, scroll, screenshot, fill, etc.)",
|
|
2750
2822
|
scope: "page",
|
|
2751
|
-
parameters:
|
|
2752
|
-
url:
|
|
2753
|
-
actions:
|
|
2754
|
-
output:
|
|
2755
|
-
timeout:
|
|
2823
|
+
parameters: z18.object({
|
|
2824
|
+
url: z18.string().describe("Starting URL"),
|
|
2825
|
+
actions: z18.array(actionSchema).max(MAX_ACTIONS).describe("Array of actions (max 50)"),
|
|
2826
|
+
output: z18.enum(["text", "json"]).default("json").describe("Output format: text or json"),
|
|
2827
|
+
timeout: z18.number().default(60).describe("Overall timeout in seconds (default: 60)")
|
|
2756
2828
|
}),
|
|
2757
2829
|
handler: async (p, ctx) => {
|
|
2758
2830
|
await ctx.page.goto(p.url, { waitUntil: "domcontentloaded" });
|
|
@@ -2772,14 +2844,14 @@ var actionsCommand = registerCommand({
|
|
|
2772
2844
|
const finalUrl = ctx.page.url();
|
|
2773
2845
|
const timedOut = results.length < p.actions.length;
|
|
2774
2846
|
if (p.output === "text") {
|
|
2775
|
-
return
|
|
2847
|
+
return ok18({
|
|
2776
2848
|
title,
|
|
2777
2849
|
url: finalUrl,
|
|
2778
2850
|
actions: results.map((r) => JSON.stringify(r)).join("\n"),
|
|
2779
2851
|
...timedOut ? { warning: `Timed out after ${p.timeout}s, completed ${results.length}/${p.actions.length} actions` } : {}
|
|
2780
2852
|
});
|
|
2781
2853
|
}
|
|
2782
|
-
return
|
|
2854
|
+
return ok18({
|
|
2783
2855
|
title,
|
|
2784
2856
|
url: finalUrl,
|
|
2785
2857
|
results,
|
|
@@ -2789,8 +2861,8 @@ var actionsCommand = registerCommand({
|
|
|
2789
2861
|
});
|
|
2790
2862
|
|
|
2791
2863
|
// src/commands/scrape.ts
|
|
2792
|
-
import { z as
|
|
2793
|
-
import { ok as
|
|
2864
|
+
import { z as z19 } from "zod";
|
|
2865
|
+
import { ok as ok19, fail as fail8 } from "@dyyz1993/xcli-core";
|
|
2794
2866
|
|
|
2795
2867
|
// src/lib/html-to-markdown.ts
|
|
2796
2868
|
import * as cheerio from "cheerio";
|
|
@@ -3175,15 +3247,15 @@ var scrapeCommand = registerCommand({
|
|
|
3175
3247
|
description: "Scrape a page and convert to Markdown (with JS rendering)",
|
|
3176
3248
|
scope: "project",
|
|
3177
3249
|
selectorParams: ["selector"],
|
|
3178
|
-
parameters:
|
|
3179
|
-
url:
|
|
3180
|
-
selector:
|
|
3181
|
-
timeout:
|
|
3182
|
-
format:
|
|
3183
|
-
onlyMainContent:
|
|
3184
|
-
retries:
|
|
3185
|
-
waitAfterLoad:
|
|
3186
|
-
mode:
|
|
3250
|
+
parameters: z19.object({
|
|
3251
|
+
url: z19.string().optional(),
|
|
3252
|
+
selector: z19.string().optional(),
|
|
3253
|
+
timeout: z19.number().default(3e4),
|
|
3254
|
+
format: z19.enum(["markdown", "html", "text"]).default("markdown"),
|
|
3255
|
+
onlyMainContent: z19.boolean().default(true),
|
|
3256
|
+
retries: z19.number().int().min(0).max(5).optional().default(2).describe("\u91CD\u8BD5\u6B21\u6570\uFF08\u9ED8\u8BA4 2\uFF09"),
|
|
3257
|
+
waitAfterLoad: z19.number().int().optional().default(0).describe("\u9875\u9762\u52A0\u8F7D\u540E\u989D\u5916\u7B49\u5F85\u6BEB\u79D2"),
|
|
3258
|
+
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")
|
|
3187
3259
|
}),
|
|
3188
3260
|
handler: async (p, ctx) => {
|
|
3189
3261
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
@@ -3191,7 +3263,7 @@ var scrapeCommand = registerCommand({
|
|
|
3191
3263
|
try {
|
|
3192
3264
|
const targetUrl = p.url || page.url();
|
|
3193
3265
|
if (!targetUrl || targetUrl === "about:blank") {
|
|
3194
|
-
return
|
|
3266
|
+
return fail8("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
3195
3267
|
}
|
|
3196
3268
|
let lastError;
|
|
3197
3269
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
@@ -3261,7 +3333,7 @@ var scrapeCommand = registerCommand({
|
|
|
3261
3333
|
} catch {
|
|
3262
3334
|
}
|
|
3263
3335
|
if (p.mode === "smart") {
|
|
3264
|
-
return
|
|
3336
|
+
return ok19(structured);
|
|
3265
3337
|
}
|
|
3266
3338
|
if (p.mode === "compact") {
|
|
3267
3339
|
const compactData = structured.tables.length > 0 ? structured.tables.map((t) => ({
|
|
@@ -3274,9 +3346,9 @@ var scrapeCommand = registerCommand({
|
|
|
3274
3346
|
return compact;
|
|
3275
3347
|
})
|
|
3276
3348
|
})) : structured.mainText?.substring(0, 500);
|
|
3277
|
-
return
|
|
3349
|
+
return ok19({ url: structured.url, title: structured.title, data: compactData });
|
|
3278
3350
|
}
|
|
3279
|
-
return
|
|
3351
|
+
return ok19(structured);
|
|
3280
3352
|
}
|
|
3281
3353
|
let content;
|
|
3282
3354
|
switch (p.format) {
|
|
@@ -3335,7 +3407,7 @@ var scrapeCommand = registerCommand({
|
|
|
3335
3407
|
content = await page.innerText("body");
|
|
3336
3408
|
break;
|
|
3337
3409
|
}
|
|
3338
|
-
return
|
|
3410
|
+
return ok19({ content, title, url: finalUrl });
|
|
3339
3411
|
} catch (err) {
|
|
3340
3412
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
3341
3413
|
if (attempt < maxAttempts) {
|
|
@@ -3345,20 +3417,20 @@ var scrapeCommand = registerCommand({
|
|
|
3345
3417
|
}
|
|
3346
3418
|
}
|
|
3347
3419
|
}
|
|
3348
|
-
return
|
|
3420
|
+
return fail8(`Scrape failed after ${maxAttempts} attempt(s): ${lastError?.message ?? "unknown error"}`);
|
|
3349
3421
|
} finally {
|
|
3350
3422
|
await closeEphemeralContext(context);
|
|
3351
3423
|
}
|
|
3352
3424
|
},
|
|
3353
|
-
result:
|
|
3354
|
-
url:
|
|
3355
|
-
title:
|
|
3425
|
+
result: z19.object({
|
|
3426
|
+
url: z19.string(),
|
|
3427
|
+
title: z19.string()
|
|
3356
3428
|
}).passthrough()
|
|
3357
3429
|
});
|
|
3358
3430
|
|
|
3359
3431
|
// src/commands/map.ts
|
|
3360
|
-
import { z as
|
|
3361
|
-
import { ok as
|
|
3432
|
+
import { z as z20 } from "zod";
|
|
3433
|
+
import { ok as ok20, fail as fail9 } from "@dyyz1993/xcli-core";
|
|
3362
3434
|
|
|
3363
3435
|
// src/utils/url.ts
|
|
3364
3436
|
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -3593,21 +3665,21 @@ var mapCommand = registerCommand({
|
|
|
3593
3665
|
name: "map",
|
|
3594
3666
|
description: "Discover all URLs on a website via sitemap and page link extraction",
|
|
3595
3667
|
scope: "project",
|
|
3596
|
-
parameters:
|
|
3597
|
-
url:
|
|
3598
|
-
search:
|
|
3599
|
-
sitemap:
|
|
3600
|
-
includeSubdomains:
|
|
3601
|
-
allowExternalLinks:
|
|
3602
|
-
limit:
|
|
3603
|
-
verbose:
|
|
3668
|
+
parameters: z20.object({
|
|
3669
|
+
url: z20.string().optional(),
|
|
3670
|
+
search: z20.string().optional(),
|
|
3671
|
+
sitemap: z20.enum(["include", "only"]).optional(),
|
|
3672
|
+
includeSubdomains: z20.boolean().optional(),
|
|
3673
|
+
allowExternalLinks: z20.boolean().optional().describe("Include links to external domains"),
|
|
3674
|
+
limit: z20.number().optional(),
|
|
3675
|
+
verbose: z20.boolean().default(false).describe("Show progress feedback")
|
|
3604
3676
|
}),
|
|
3605
3677
|
handler: async (p, ctx) => {
|
|
3606
3678
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
3607
3679
|
try {
|
|
3608
3680
|
const targetUrl = p.url || page.url();
|
|
3609
3681
|
if (!targetUrl || targetUrl === "about:blank") {
|
|
3610
|
-
return
|
|
3682
|
+
return fail9("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
3611
3683
|
}
|
|
3612
3684
|
const links = await discoverUrls(page, targetUrl, {
|
|
3613
3685
|
sitemap: p.sitemap,
|
|
@@ -3618,7 +3690,7 @@ var mapCommand = registerCommand({
|
|
|
3618
3690
|
verbose: p.verbose
|
|
3619
3691
|
});
|
|
3620
3692
|
const linkObjects = links.map((url) => ({ url }));
|
|
3621
|
-
return
|
|
3693
|
+
return ok20({
|
|
3622
3694
|
links: linkObjects,
|
|
3623
3695
|
success: true
|
|
3624
3696
|
});
|
|
@@ -3626,15 +3698,15 @@ var mapCommand = registerCommand({
|
|
|
3626
3698
|
await closeEphemeralContext(context);
|
|
3627
3699
|
}
|
|
3628
3700
|
},
|
|
3629
|
-
result:
|
|
3630
|
-
links:
|
|
3631
|
-
success:
|
|
3701
|
+
result: z20.object({
|
|
3702
|
+
links: z20.array(z20.object({ url: z20.string() })),
|
|
3703
|
+
success: z20.boolean()
|
|
3632
3704
|
})
|
|
3633
3705
|
});
|
|
3634
3706
|
|
|
3635
3707
|
// src/commands/crawl.ts
|
|
3636
|
-
import { z as
|
|
3637
|
-
import { ok as
|
|
3708
|
+
import { z as z21 } from "zod";
|
|
3709
|
+
import { ok as ok21 } from "@dyyz1993/xcli-core";
|
|
3638
3710
|
function stripHashAnchorQuery(url) {
|
|
3639
3711
|
try {
|
|
3640
3712
|
const parsed = new URL(url);
|
|
@@ -3811,21 +3883,21 @@ var crawlCommand = registerCommand({
|
|
|
3811
3883
|
name: "crawl",
|
|
3812
3884
|
description: "Crawl a website and extract content from all pages",
|
|
3813
3885
|
scope: "project",
|
|
3814
|
-
parameters:
|
|
3815
|
-
url:
|
|
3816
|
-
limit:
|
|
3817
|
-
maxDepth:
|
|
3818
|
-
includePaths:
|
|
3819
|
-
excludePaths:
|
|
3820
|
-
allowSubdomains:
|
|
3821
|
-
allowExternalLinks:
|
|
3822
|
-
allowBackwardCrawling:
|
|
3823
|
-
enableSpa:
|
|
3824
|
-
format:
|
|
3825
|
-
onlyMainContent:
|
|
3826
|
-
concurrency:
|
|
3827
|
-
retries:
|
|
3828
|
-
verbose:
|
|
3886
|
+
parameters: z21.object({
|
|
3887
|
+
url: z21.string(),
|
|
3888
|
+
limit: z21.number().default(10),
|
|
3889
|
+
maxDepth: z21.number().default(3),
|
|
3890
|
+
includePaths: z21.array(z21.string()).optional(),
|
|
3891
|
+
excludePaths: z21.array(z21.string()).optional(),
|
|
3892
|
+
allowSubdomains: z21.boolean().default(false),
|
|
3893
|
+
allowExternalLinks: z21.boolean().default(false),
|
|
3894
|
+
allowBackwardCrawling: z21.boolean().default(false),
|
|
3895
|
+
enableSpa: z21.boolean().default(true).describe("Disable to skip SPA route detection"),
|
|
3896
|
+
format: z21.enum(["markdown", "html"]).default("markdown"),
|
|
3897
|
+
onlyMainContent: z21.boolean().default(true),
|
|
3898
|
+
concurrency: z21.number().default(3),
|
|
3899
|
+
retries: z21.number().default(2),
|
|
3900
|
+
verbose: z21.boolean().default(false)
|
|
3829
3901
|
}),
|
|
3830
3902
|
handler: async (p, ctx) => {
|
|
3831
3903
|
const startUrl = new URL(p.url);
|
|
@@ -3964,7 +4036,7 @@ var crawlCommand = registerCommand({
|
|
|
3964
4036
|
if (errorPages.length > 0) {
|
|
3965
4037
|
response.errors = errorPages;
|
|
3966
4038
|
}
|
|
3967
|
-
return
|
|
4039
|
+
return ok21(response);
|
|
3968
4040
|
} finally {
|
|
3969
4041
|
for (const ctx2 of contexts) {
|
|
3970
4042
|
await ctx2.close().catch(() => {
|
|
@@ -3974,15 +4046,15 @@ var crawlCommand = registerCommand({
|
|
|
3974
4046
|
} catch (err) {
|
|
3975
4047
|
const message = err instanceof Error ? err.message : String(err);
|
|
3976
4048
|
const successPages = results.filter((r) => !isPageError(r));
|
|
3977
|
-
return
|
|
4049
|
+
return ok21({ pages: successPages, total: successPages.length, success: false, error: message });
|
|
3978
4050
|
}
|
|
3979
4051
|
}
|
|
3980
4052
|
});
|
|
3981
4053
|
|
|
3982
4054
|
// src/commands/search.ts
|
|
3983
|
-
import { z as
|
|
4055
|
+
import { z as z22 } from "zod";
|
|
3984
4056
|
import * as cheerio2 from "cheerio";
|
|
3985
|
-
import { ok as
|
|
4057
|
+
import { ok as ok22 } from "@dyyz1993/xcli-core";
|
|
3986
4058
|
function getRecencyParams(recency) {
|
|
3987
4059
|
const now = Math.floor(Date.now() / 1e3);
|
|
3988
4060
|
switch (recency) {
|
|
@@ -4316,16 +4388,16 @@ var searchCommand = registerCommand({
|
|
|
4316
4388
|
name: "search",
|
|
4317
4389
|
description: "Search the web and extract results with engine fallback",
|
|
4318
4390
|
scope: "project",
|
|
4319
|
-
parameters:
|
|
4320
|
-
query:
|
|
4321
|
-
engine:
|
|
4322
|
-
limit:
|
|
4323
|
-
full:
|
|
4324
|
-
format:
|
|
4325
|
-
timeout:
|
|
4326
|
-
recency:
|
|
4327
|
-
fallback:
|
|
4328
|
-
site:
|
|
4391
|
+
parameters: z22.object({
|
|
4392
|
+
query: z22.string(),
|
|
4393
|
+
engine: z22.string().optional(),
|
|
4394
|
+
limit: z22.number().default(10),
|
|
4395
|
+
full: z22.boolean().default(false),
|
|
4396
|
+
format: z22.enum(["markdown", "json", "text"]).default("markdown"),
|
|
4397
|
+
timeout: z22.number().default(15e3),
|
|
4398
|
+
recency: z22.enum(["hour", "day", "week", "month", "year"]).optional().describe("Filter by time: hour/day/week/month/year"),
|
|
4399
|
+
fallback: z22.boolean().default(false).describe("Sequential engine fallback instead of parallel"),
|
|
4400
|
+
site: z22.string().optional().describe("Limit results to a specific site (e.g. github.com, v2ex.com)")
|
|
4329
4401
|
}),
|
|
4330
4402
|
handler: async (p, ctx) => {
|
|
4331
4403
|
const { context } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
@@ -4431,7 +4503,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
4431
4503
|
lines.push(`> ${r.snippet}`);
|
|
4432
4504
|
lines.push("");
|
|
4433
4505
|
}
|
|
4434
|
-
return
|
|
4506
|
+
return ok22({ ...searchResult, content: lines.join("\n") });
|
|
4435
4507
|
}
|
|
4436
4508
|
if (p.format === "text") {
|
|
4437
4509
|
const lines = [`Search: ${searchResult.query} (Engine: ${searchResult.engine}, Total: ${searchResult.total})`, ""];
|
|
@@ -4441,9 +4513,9 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
4441
4513
|
lines.push(` ${r.snippet}`);
|
|
4442
4514
|
lines.push("");
|
|
4443
4515
|
}
|
|
4444
|
-
return
|
|
4516
|
+
return ok22({ ...searchResult, content: lines.join("\n") });
|
|
4445
4517
|
}
|
|
4446
|
-
return
|
|
4518
|
+
return ok22(searchResult);
|
|
4447
4519
|
} finally {
|
|
4448
4520
|
await closeEphemeralContext(context);
|
|
4449
4521
|
}
|
|
@@ -4451,8 +4523,8 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
4451
4523
|
});
|
|
4452
4524
|
|
|
4453
4525
|
// src/commands/network.ts
|
|
4454
|
-
import { z as
|
|
4455
|
-
import { ok as
|
|
4526
|
+
import { z as z23 } from "zod";
|
|
4527
|
+
import { ok as ok23, fail as fail10 } from "@dyyz1993/xcli-core";
|
|
4456
4528
|
function extractPath2(url) {
|
|
4457
4529
|
try {
|
|
4458
4530
|
const u = new URL(url);
|
|
@@ -4550,19 +4622,19 @@ var networkCommand = registerCommand({
|
|
|
4550
4622
|
name: "network",
|
|
4551
4623
|
description: "Capture and filter network responses from a URL",
|
|
4552
4624
|
scope: "project",
|
|
4553
|
-
parameters:
|
|
4554
|
-
url:
|
|
4555
|
-
filter:
|
|
4556
|
-
match:
|
|
4557
|
-
search:
|
|
4558
|
-
console:
|
|
4559
|
-
timeout:
|
|
4560
|
-
wait:
|
|
4561
|
-
limit:
|
|
4562
|
-
format:
|
|
4563
|
-
ws:
|
|
4564
|
-
listen:
|
|
4565
|
-
duration:
|
|
4625
|
+
parameters: z23.object({
|
|
4626
|
+
url: z23.string(),
|
|
4627
|
+
filter: z23.string().optional(),
|
|
4628
|
+
match: z23.string().optional(),
|
|
4629
|
+
search: z23.string().optional().describe("Search within all captured response bodies"),
|
|
4630
|
+
console: z23.boolean().default(false),
|
|
4631
|
+
timeout: z23.number().default(3e4),
|
|
4632
|
+
wait: z23.number().default(3e3),
|
|
4633
|
+
limit: z23.number().default(50),
|
|
4634
|
+
format: z23.enum(["summary", "json"]).default("summary"),
|
|
4635
|
+
ws: z23.boolean().optional().default(false).describe("Only show WebSocket messages"),
|
|
4636
|
+
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"),
|
|
4637
|
+
duration: z23.number().int().optional().default(15e3).describe("\u76D1\u542C\u6A21\u5F0F\u7B49\u5F85\u65F6\u957F\uFF08\u6BEB\u79D2\uFF0C\u9ED8\u8BA4 15000\uFF09")
|
|
4566
4638
|
}),
|
|
4567
4639
|
handler: async (p, ctx) => {
|
|
4568
4640
|
const startTime = Date.now();
|
|
@@ -4617,7 +4689,7 @@ var networkCommand = registerCommand({
|
|
|
4617
4689
|
};
|
|
4618
4690
|
if (p.listen) {
|
|
4619
4691
|
const page2 = ctx.page;
|
|
4620
|
-
if (!page2) return
|
|
4692
|
+
if (!page2) return fail10("No active page. Use --cdp to connect first.");
|
|
4621
4693
|
const captures = [];
|
|
4622
4694
|
const consoleMessages = [];
|
|
4623
4695
|
const wsCaptures = [];
|
|
@@ -4644,7 +4716,7 @@ var networkCommand = registerCommand({
|
|
|
4644
4716
|
page2.off("response", handler);
|
|
4645
4717
|
const duration = Date.now() - startTime;
|
|
4646
4718
|
if (p.ws && wsCaptures.length > 0) {
|
|
4647
|
-
return
|
|
4719
|
+
return ok23({
|
|
4648
4720
|
url: "[listen mode]",
|
|
4649
4721
|
duration,
|
|
4650
4722
|
total: captures.length,
|
|
@@ -4658,9 +4730,9 @@ var networkCommand = registerCommand({
|
|
|
4658
4730
|
});
|
|
4659
4731
|
}
|
|
4660
4732
|
if (p.format === "json") {
|
|
4661
|
-
return
|
|
4733
|
+
return ok23(buildJsonOutput("[listen mode]", captures, consoleMessages, captures.length, wsCaptures));
|
|
4662
4734
|
}
|
|
4663
|
-
return
|
|
4735
|
+
return ok23(buildSummaryOutput("[listen mode]", duration, captures, consoleMessages, captures.length, wsCaptures));
|
|
4664
4736
|
}
|
|
4665
4737
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
4666
4738
|
try {
|
|
@@ -4715,7 +4787,7 @@ var networkCommand = registerCommand({
|
|
|
4715
4787
|
}
|
|
4716
4788
|
const duration = Date.now() - startTime;
|
|
4717
4789
|
if (p.ws && wsCaptures.length > 0) {
|
|
4718
|
-
return
|
|
4790
|
+
return ok23({
|
|
4719
4791
|
url: p.url,
|
|
4720
4792
|
duration,
|
|
4721
4793
|
total: captures.length,
|
|
@@ -4729,9 +4801,9 @@ var networkCommand = registerCommand({
|
|
|
4729
4801
|
});
|
|
4730
4802
|
}
|
|
4731
4803
|
if (p.format === "json") {
|
|
4732
|
-
return
|
|
4804
|
+
return ok23(buildJsonOutput(p.url, results, consoleMessages, totalCount, wsCaptures, searchResults));
|
|
4733
4805
|
}
|
|
4734
|
-
return
|
|
4806
|
+
return ok23(buildSummaryOutput(p.url, duration, results, consoleMessages, totalCount, wsCaptures));
|
|
4735
4807
|
} finally {
|
|
4736
4808
|
await closeEphemeralContext(context);
|
|
4737
4809
|
}
|
|
@@ -4739,7 +4811,7 @@ var networkCommand = registerCommand({
|
|
|
4739
4811
|
});
|
|
4740
4812
|
|
|
4741
4813
|
// src/commands/ai-search-engines.ts
|
|
4742
|
-
import { z as
|
|
4814
|
+
import { z as z24 } from "zod";
|
|
4743
4815
|
var ENGINE_CONFIGS = {
|
|
4744
4816
|
deepseek: {
|
|
4745
4817
|
key: "deepseek",
|
|
@@ -4993,7 +5065,7 @@ var ENGINE_CONFIGS = {
|
|
|
4993
5065
|
}
|
|
4994
5066
|
};
|
|
4995
5067
|
var ALL_ENGINE_KEYS = Object.keys(ENGINE_CONFIGS);
|
|
4996
|
-
var ENGINE_KEY_ENUM =
|
|
5068
|
+
var ENGINE_KEY_ENUM = z24.enum(ALL_ENGINE_KEYS);
|
|
4997
5069
|
function getEngineConfig(key) {
|
|
4998
5070
|
return ENGINE_CONFIGS[key];
|
|
4999
5071
|
}
|
|
@@ -5273,8 +5345,8 @@ function parseMarkdownResults(rawText) {
|
|
|
5273
5345
|
}
|
|
5274
5346
|
|
|
5275
5347
|
// src/commands/snapshot.ts
|
|
5276
|
-
import { z as
|
|
5277
|
-
import { ok as
|
|
5348
|
+
import { z as z25 } from "zod";
|
|
5349
|
+
import { ok as ok24, fail as fail11, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
|
|
5278
5350
|
|
|
5279
5351
|
// src/utils/resolve-selector.ts
|
|
5280
5352
|
function buildElementSelector(el) {
|
|
@@ -5755,24 +5827,24 @@ var snapshotCommand = registerCommand({
|
|
|
5755
5827
|
description: "Capture a quick page state snapshot \u2014 aria tree, visible text, or DOM summary",
|
|
5756
5828
|
scope: "page",
|
|
5757
5829
|
selectorParams: ["selector"],
|
|
5758
|
-
parameters:
|
|
5759
|
-
type:
|
|
5760
|
-
selector:
|
|
5761
|
-
depth:
|
|
5762
|
-
interactive:
|
|
5763
|
-
interactiveOnly:
|
|
5764
|
-
i:
|
|
5765
|
-
compact:
|
|
5766
|
-
c:
|
|
5767
|
-
selectors:
|
|
5768
|
-
all:
|
|
5830
|
+
parameters: z25.object({
|
|
5831
|
+
type: z25.enum(["aria", "text", "dom", "all"]).default("aria").describe("Snapshot type: aria (accessibility tree), text (visible text), dom (element summary), all (combined)"),
|
|
5832
|
+
selector: z25.string().optional().describe("Scope to a specific element"),
|
|
5833
|
+
depth: z25.number().optional().default(6).describe("Max depth for DOM/aria tree"),
|
|
5834
|
+
interactive: z25.boolean().optional().default(false).describe("Return interactive agent refs only"),
|
|
5835
|
+
interactiveOnly: z25.boolean().optional().default(false).describe("Alias for interactive"),
|
|
5836
|
+
i: z25.boolean().optional().default(false).describe("Short alias for interactive"),
|
|
5837
|
+
compact: z25.boolean().optional().default(false).describe("Include compact xbrowser style snapshot text"),
|
|
5838
|
+
c: z25.boolean().optional().default(false).describe("Short alias for compact"),
|
|
5839
|
+
selectors: z25.boolean().optional().default(false).describe("Include ref to CSS selector map"),
|
|
5840
|
+
all: z25.boolean().optional().default(false).describe("Include hidden interactive targets when using interactive snapshot")
|
|
5769
5841
|
}),
|
|
5770
|
-
result:
|
|
5771
|
-
url:
|
|
5772
|
-
title:
|
|
5773
|
-
aria:
|
|
5774
|
-
text:
|
|
5775
|
-
dom:
|
|
5842
|
+
result: z25.object({
|
|
5843
|
+
url: z25.string(),
|
|
5844
|
+
title: z25.string(),
|
|
5845
|
+
aria: z25.string().optional(),
|
|
5846
|
+
text: z25.string().optional(),
|
|
5847
|
+
dom: z25.record(z25.unknown()).optional()
|
|
5776
5848
|
}),
|
|
5777
5849
|
handler: async (p, ctx) => {
|
|
5778
5850
|
const page = ctx.page;
|
|
@@ -5786,7 +5858,7 @@ var snapshotCommand = registerCommand({
|
|
|
5786
5858
|
if (p.compact || p.c || p.interactive || p.interactiveOnly || p.i) {
|
|
5787
5859
|
observation.compact = formatObservationCompact(observation, { selectors: p.selectors });
|
|
5788
5860
|
}
|
|
5789
|
-
return
|
|
5861
|
+
return ok24(observation, normalizeTips3([
|
|
5790
5862
|
`refs refreshed for ${observation.targets.length} targets; use click @e1 or fill @e2 "text"`
|
|
5791
5863
|
]));
|
|
5792
5864
|
}
|
|
@@ -5794,15 +5866,15 @@ var snapshotCommand = registerCommand({
|
|
|
5794
5866
|
const aria = await captureAriaSnapshot(page, p.selector, p.depth);
|
|
5795
5867
|
const tips = await buildRefTips(page, aria);
|
|
5796
5868
|
persistSemantics(url, aria);
|
|
5797
|
-
return
|
|
5869
|
+
return ok24({ url, title, aria }, normalizeTips3(tips));
|
|
5798
5870
|
}
|
|
5799
5871
|
if (p.type === "text") {
|
|
5800
5872
|
const text = await captureTextSnapshot(page, p.selector);
|
|
5801
|
-
return
|
|
5873
|
+
return ok24({ url, title, text });
|
|
5802
5874
|
}
|
|
5803
5875
|
if (p.type === "dom") {
|
|
5804
5876
|
const dom = await captureDomSnapshot(page, p.selector, p.depth ?? 6);
|
|
5805
|
-
return
|
|
5877
|
+
return ok24({ url, title, dom });
|
|
5806
5878
|
}
|
|
5807
5879
|
if (p.type === "all") {
|
|
5808
5880
|
const [aria, text, dom] = await Promise.all([
|
|
@@ -5812,9 +5884,9 @@ var snapshotCommand = registerCommand({
|
|
|
5812
5884
|
]);
|
|
5813
5885
|
const tips = await buildRefTips(page, aria);
|
|
5814
5886
|
persistSemantics(url, aria);
|
|
5815
|
-
return
|
|
5887
|
+
return ok24({ url, title, aria, text, dom }, normalizeTips3(tips));
|
|
5816
5888
|
}
|
|
5817
|
-
return
|
|
5889
|
+
return fail11(`Unknown snapshot type: ${p.type}`);
|
|
5818
5890
|
}
|
|
5819
5891
|
});
|
|
5820
5892
|
function persistSemantics(url, aria) {
|
|
@@ -5891,22 +5963,22 @@ async function captureDomSnapshot(page, selector, maxDepth) {
|
|
|
5891
5963
|
}
|
|
5892
5964
|
|
|
5893
5965
|
// src/commands/agent.ts
|
|
5894
|
-
import { z as
|
|
5895
|
-
import { ok as
|
|
5966
|
+
import { z as z26 } from "zod";
|
|
5967
|
+
import { ok as ok25, normalizeTips as normalizeTips4 } from "@dyyz1993/xcli-core";
|
|
5896
5968
|
var observeCommand = registerCommand({
|
|
5897
5969
|
name: "observe",
|
|
5898
5970
|
description: "Observe the current page as structured agent targets with session refs",
|
|
5899
5971
|
scope: "page",
|
|
5900
|
-
parameters:
|
|
5901
|
-
includeHidden:
|
|
5902
|
-
limit:
|
|
5903
|
-
compact:
|
|
5904
|
-
selectors:
|
|
5972
|
+
parameters: z26.object({
|
|
5973
|
+
includeHidden: z26.boolean().optional().default(false).describe("Include hidden elements in the target list"),
|
|
5974
|
+
limit: z26.number().int().positive().max(300).optional().default(80).describe("Maximum number of targets to return"),
|
|
5975
|
+
compact: z26.boolean().optional().default(false).describe("Include compact xbrowser style snapshot text"),
|
|
5976
|
+
selectors: z26.boolean().optional().default(false).describe("Include ref to stable CSS selector map")
|
|
5905
5977
|
}),
|
|
5906
|
-
result:
|
|
5907
|
-
targets:
|
|
5908
|
-
selectors:
|
|
5909
|
-
compact:
|
|
5978
|
+
result: z26.object({
|
|
5979
|
+
targets: z26.array(z26.record(z26.unknown())),
|
|
5980
|
+
selectors: z26.record(z26.unknown()).optional(),
|
|
5981
|
+
compact: z26.string().optional()
|
|
5910
5982
|
}).passthrough(),
|
|
5911
5983
|
handler: async (p, ctx) => {
|
|
5912
5984
|
const observation = await observePage(ctx.page, ctx.sessionId, {
|
|
@@ -5915,7 +5987,7 @@ var observeCommand = registerCommand({
|
|
|
5915
5987
|
});
|
|
5916
5988
|
if (p.selectors) observation.selectors = buildSelectorMap(observation);
|
|
5917
5989
|
if (p.compact) observation.compact = formatObservationCompact(observation, { selectors: p.selectors });
|
|
5918
|
-
return
|
|
5990
|
+
return ok25(observation, normalizeTips4([
|
|
5919
5991
|
`refs refreshed for ${observation.targets.length} targets; use act --ref @e1 --action click or click @e1`
|
|
5920
5992
|
]));
|
|
5921
5993
|
}
|
|
@@ -5925,14 +5997,14 @@ var actCommand = registerCommand({
|
|
|
5925
5997
|
description: "Perform an agent action using an observe ref or explicit selector",
|
|
5926
5998
|
scope: "element",
|
|
5927
5999
|
selectorParams: ["selector"],
|
|
5928
|
-
parameters:
|
|
5929
|
-
action:
|
|
5930
|
-
ref:
|
|
5931
|
-
selector:
|
|
5932
|
-
value:
|
|
5933
|
-
key:
|
|
5934
|
-
force:
|
|
5935
|
-
timeout:
|
|
6000
|
+
parameters: z26.object({
|
|
6001
|
+
action: z26.enum(["click", "fill", "type", "press", "select", "check", "hover"]).default("click"),
|
|
6002
|
+
ref: z26.string().optional().describe("Session-scoped ref returned by observe, such as e1"),
|
|
6003
|
+
selector: z26.string().optional().describe("CSS selector fallback when no ref is available"),
|
|
6004
|
+
value: z26.string().optional().describe("Value for fill/type/select"),
|
|
6005
|
+
key: z26.string().optional().describe("Key for press"),
|
|
6006
|
+
force: z26.boolean().optional().default(false).describe("Bypass actionability checks"),
|
|
6007
|
+
timeout: z26.number().optional().default(1e4).describe("Playwright action timeout in milliseconds")
|
|
5936
6008
|
}).refine((p) => !!p.ref || !!p.selector, {
|
|
5937
6009
|
message: "Either ref or selector is required"
|
|
5938
6010
|
}),
|
|
@@ -5946,7 +6018,7 @@ var actCommand = registerCommand({
|
|
|
5946
6018
|
tips: normalizeTips4(result.stale ? ["run observe again to refresh refs"] : [])
|
|
5947
6019
|
};
|
|
5948
6020
|
}
|
|
5949
|
-
return
|
|
6021
|
+
return ok25(result, normalizeTips4(result.stale ? ["ref screen hash changed; run observe if the next action is uncertain"] : []));
|
|
5950
6022
|
}
|
|
5951
6023
|
});
|
|
5952
6024
|
var waitForCommand = registerCommand({
|
|
@@ -5954,16 +6026,16 @@ var waitForCommand = registerCommand({
|
|
|
5954
6026
|
description: "Wait for agent predicates such as text, URL, load state, selector state, or screen hash changes",
|
|
5955
6027
|
scope: "page",
|
|
5956
6028
|
selectorParams: ["selector"],
|
|
5957
|
-
parameters:
|
|
5958
|
-
selector:
|
|
5959
|
-
state:
|
|
5960
|
-
text:
|
|
5961
|
-
url:
|
|
5962
|
-
load:
|
|
5963
|
-
fn:
|
|
5964
|
-
screenHashChanged:
|
|
5965
|
-
timeout:
|
|
5966
|
-
pollInterval:
|
|
6029
|
+
parameters: z26.object({
|
|
6030
|
+
selector: z26.string().optional().describe("CSS selector or observe ref to wait for"),
|
|
6031
|
+
state: z26.enum(["attached", "detached", "visible", "hidden"]).optional().default("visible"),
|
|
6032
|
+
text: z26.string().optional().describe("Visible text to wait for"),
|
|
6033
|
+
url: z26.string().optional().describe("URL substring or glob pattern to wait for"),
|
|
6034
|
+
load: z26.enum(["load", "domcontentloaded", "networkidle"]).optional().describe("Load state to wait for"),
|
|
6035
|
+
fn: z26.string().optional().describe("JavaScript predicate to wait for"),
|
|
6036
|
+
screenHashChanged: z26.string().optional().describe("Previous screenHash from observe"),
|
|
6037
|
+
timeout: z26.number().optional().default(3e4),
|
|
6038
|
+
pollInterval: z26.number().optional().default(200)
|
|
5967
6039
|
}).refine((p) => [p.selector, p.text, p.url, p.load, p.fn, p.screenHashChanged].filter(Boolean).length === 1, {
|
|
5968
6040
|
message: "Provide exactly one wait predicate: selector, text, url, load, fn, or screenHashChanged"
|
|
5969
6041
|
}),
|
|
@@ -5977,30 +6049,30 @@ var waitForCommand = registerCommand({
|
|
|
5977
6049
|
tips: []
|
|
5978
6050
|
};
|
|
5979
6051
|
}
|
|
5980
|
-
return
|
|
6052
|
+
return ok25(result);
|
|
5981
6053
|
}
|
|
5982
6054
|
});
|
|
5983
6055
|
|
|
5984
6056
|
// src/commands/tab.ts
|
|
5985
|
-
import { z as
|
|
5986
|
-
import { ok as
|
|
5987
|
-
var TabParams =
|
|
5988
|
-
subcommand:
|
|
5989
|
-
url:
|
|
5990
|
-
index:
|
|
6057
|
+
import { z as z27 } from "zod";
|
|
6058
|
+
import { ok as ok26, fail as fail12 } from "@dyyz1993/xcli-core";
|
|
6059
|
+
var TabParams = z27.object({
|
|
6060
|
+
subcommand: z27.enum(["list", "new", "close", "switch"]),
|
|
6061
|
+
url: z27.string().optional(),
|
|
6062
|
+
index: z27.number().int().min(0).optional()
|
|
5991
6063
|
});
|
|
5992
6064
|
var tabCommand = registerCommand({
|
|
5993
6065
|
name: "tab",
|
|
5994
6066
|
description: "Manage browser tabs: list, new, close, switch",
|
|
5995
6067
|
scope: "page",
|
|
5996
6068
|
parameters: TabParams,
|
|
5997
|
-
result:
|
|
5998
|
-
success:
|
|
5999
|
-
data:
|
|
6069
|
+
result: z27.object({
|
|
6070
|
+
success: z27.boolean(),
|
|
6071
|
+
data: z27.unknown()
|
|
6000
6072
|
}),
|
|
6001
6073
|
handler: async (p, ctx) => {
|
|
6002
6074
|
if (!ctx.browserContext) {
|
|
6003
|
-
return
|
|
6075
|
+
return fail12("No browser context available. Use --cdp to connect to a browser first.");
|
|
6004
6076
|
}
|
|
6005
6077
|
const pages = ctx.browserContext.pages();
|
|
6006
6078
|
switch (p.subcommand) {
|
|
@@ -6013,7 +6085,7 @@ var tabCommand = registerCommand({
|
|
|
6013
6085
|
case "switch":
|
|
6014
6086
|
return handleSwitch(p, pages, ctx);
|
|
6015
6087
|
default:
|
|
6016
|
-
return
|
|
6088
|
+
return fail12(`Unknown subcommand: ${p.subcommand}`);
|
|
6017
6089
|
}
|
|
6018
6090
|
}
|
|
6019
6091
|
});
|
|
@@ -6028,7 +6100,7 @@ async function handleList(pages, ctx) {
|
|
|
6028
6100
|
if (isActive) activeIndex = i;
|
|
6029
6101
|
tabs.push({ index: i, url, title, active: isActive });
|
|
6030
6102
|
}
|
|
6031
|
-
return
|
|
6103
|
+
return ok26({ tabs, total: tabs.length, activeIndex });
|
|
6032
6104
|
}
|
|
6033
6105
|
async function handleNew(p, _pages, ctx) {
|
|
6034
6106
|
const newPage = await ctx.browserContext.newPage();
|
|
@@ -6056,7 +6128,7 @@ async function handleNew(p, _pages, ctx) {
|
|
|
6056
6128
|
const title = await newPage.title().catch(() => "");
|
|
6057
6129
|
const allPages = ctx.browserContext.pages();
|
|
6058
6130
|
const newIndex = allPages.indexOf(newPage);
|
|
6059
|
-
return
|
|
6131
|
+
return ok26({
|
|
6060
6132
|
index: newIndex >= 0 ? newIndex : allPages.length - 1,
|
|
6061
6133
|
url: newPage.url(),
|
|
6062
6134
|
title,
|
|
@@ -6067,11 +6139,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
6067
6139
|
async function handleClose(p, ctx) {
|
|
6068
6140
|
const currentPages = ctx.browserContext.pages();
|
|
6069
6141
|
if (currentPages.length <= 1) {
|
|
6070
|
-
return
|
|
6142
|
+
return fail12("Cannot close the last remaining tab");
|
|
6071
6143
|
}
|
|
6072
6144
|
const closeIndex = p.index ?? currentPages.findIndex((pg) => pg === ctx.page);
|
|
6073
6145
|
if (closeIndex < 0 || closeIndex >= currentPages.length) {
|
|
6074
|
-
return
|
|
6146
|
+
return fail12(`Invalid tab index: ${closeIndex}. Valid range: 0-${currentPages.length - 1}`);
|
|
6075
6147
|
}
|
|
6076
6148
|
const pageToClose = currentPages[closeIndex];
|
|
6077
6149
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -6086,7 +6158,7 @@ async function handleClose(p, ctx) {
|
|
|
6086
6158
|
}
|
|
6087
6159
|
ctx.page = newActivePage;
|
|
6088
6160
|
}
|
|
6089
|
-
return
|
|
6161
|
+
return ok26({
|
|
6090
6162
|
closedIndex: closeIndex,
|
|
6091
6163
|
total: remainingPages.length,
|
|
6092
6164
|
activeIndex: isActivePage ? closeIndex < remainingPages.length ? closeIndex : remainingPages.length - 1 : remainingPages.findIndex((pg) => pg === ctx.page)
|
|
@@ -6094,10 +6166,10 @@ async function handleClose(p, ctx) {
|
|
|
6094
6166
|
}
|
|
6095
6167
|
async function handleSwitch(p, pages, ctx) {
|
|
6096
6168
|
if (p.index === void 0) {
|
|
6097
|
-
return
|
|
6169
|
+
return fail12("Parameter --index is required for switch subcommand");
|
|
6098
6170
|
}
|
|
6099
6171
|
if (p.index < 0 || p.index >= pages.length) {
|
|
6100
|
-
return
|
|
6172
|
+
return fail12(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
6101
6173
|
}
|
|
6102
6174
|
const targetPage = pages[p.index];
|
|
6103
6175
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -6119,7 +6191,7 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6119
6191
|
}
|
|
6120
6192
|
ctx.page = targetPage;
|
|
6121
6193
|
const title = await targetPage.title().catch(() => "");
|
|
6122
|
-
return
|
|
6194
|
+
return ok26({
|
|
6123
6195
|
index: p.index,
|
|
6124
6196
|
url: targetPage.url(),
|
|
6125
6197
|
title,
|
|
@@ -6128,17 +6200,17 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6128
6200
|
}
|
|
6129
6201
|
|
|
6130
6202
|
// src/commands/addinitscript.ts
|
|
6131
|
-
import { z as
|
|
6132
|
-
import { ok as
|
|
6203
|
+
import { z as z28 } from "zod";
|
|
6204
|
+
import { ok as ok27 } from "@dyyz1993/xcli-core";
|
|
6133
6205
|
import { readFileSync as readFileSync4 } from "fs";
|
|
6134
|
-
var InitScriptParams =
|
|
6135
|
-
script:
|
|
6136
|
-
file:
|
|
6137
|
-
stdin:
|
|
6138
|
-
name:
|
|
6139
|
-
list:
|
|
6140
|
-
remove:
|
|
6141
|
-
base64:
|
|
6206
|
+
var InitScriptParams = z28.object({
|
|
6207
|
+
script: z28.string().optional(),
|
|
6208
|
+
file: z28.string().optional(),
|
|
6209
|
+
stdin: z28.boolean().optional(),
|
|
6210
|
+
name: z28.string().optional(),
|
|
6211
|
+
list: z28.boolean().optional(),
|
|
6212
|
+
remove: z28.union([z28.string(), z28.boolean()]).optional(),
|
|
6213
|
+
base64: z28.string().optional()
|
|
6142
6214
|
});
|
|
6143
6215
|
var registeredScripts = /* @__PURE__ */ new Map();
|
|
6144
6216
|
function resolveScriptContent(params) {
|
|
@@ -6172,14 +6244,14 @@ var addInitScriptCommand = registerCommand({
|
|
|
6172
6244
|
description: "Add an initialization script that runs on every page load",
|
|
6173
6245
|
scope: "page",
|
|
6174
6246
|
parameters: InitScriptParams,
|
|
6175
|
-
result:
|
|
6176
|
-
scripts:
|
|
6177
|
-
removed:
|
|
6178
|
-
existed:
|
|
6179
|
-
error:
|
|
6180
|
-
registered:
|
|
6181
|
-
hint:
|
|
6182
|
-
executedImmediately:
|
|
6247
|
+
result: z28.object({
|
|
6248
|
+
scripts: z28.array(z28.object({ name: z28.string(), size: z28.number(), preview: z28.string() })).optional(),
|
|
6249
|
+
removed: z28.string().optional(),
|
|
6250
|
+
existed: z28.boolean().optional(),
|
|
6251
|
+
error: z28.string().optional(),
|
|
6252
|
+
registered: z28.string().optional(),
|
|
6253
|
+
hint: z28.string().optional(),
|
|
6254
|
+
executedImmediately: z28.boolean().optional()
|
|
6183
6255
|
}).passthrough(),
|
|
6184
6256
|
handler: async (params, ctx) => {
|
|
6185
6257
|
if (params.list) {
|
|
@@ -6188,20 +6260,20 @@ var addInitScriptCommand = registerCommand({
|
|
|
6188
6260
|
size: content2.length,
|
|
6189
6261
|
preview: content2.slice(0, 80)
|
|
6190
6262
|
}));
|
|
6191
|
-
return
|
|
6263
|
+
return ok27({ scripts });
|
|
6192
6264
|
}
|
|
6193
6265
|
if (params.remove && typeof params.remove === "string") {
|
|
6194
6266
|
const existed = registeredScripts.delete(params.remove);
|
|
6195
|
-
return
|
|
6267
|
+
return ok27({ removed: params.remove, existed });
|
|
6196
6268
|
}
|
|
6197
6269
|
const removeTarget = (typeof params.remove === "string" ? params.remove : null) || (params.name && !resolveScriptContent(params) ? params.name : null);
|
|
6198
6270
|
if (removeTarget && !resolveScriptContent(params)) {
|
|
6199
6271
|
const existed = registeredScripts.delete(removeTarget);
|
|
6200
|
-
return
|
|
6272
|
+
return ok27({ removed: removeTarget, existed });
|
|
6201
6273
|
}
|
|
6202
6274
|
let content = params.stdin ? await readStdin() : resolveScriptContent(params);
|
|
6203
6275
|
if (!content) {
|
|
6204
|
-
return
|
|
6276
|
+
return ok27({ error: "No script content provided. Use --script, --file, --stdin, or --base64" });
|
|
6205
6277
|
}
|
|
6206
6278
|
const scriptName = params.name ?? `script-${Date.now()}`;
|
|
6207
6279
|
registeredScripts.set(scriptName, content);
|
|
@@ -6209,45 +6281,45 @@ var addInitScriptCommand = registerCommand({
|
|
|
6209
6281
|
try {
|
|
6210
6282
|
await ctx.page.evaluate(content);
|
|
6211
6283
|
} catch {
|
|
6212
|
-
return
|
|
6284
|
+
return ok27({
|
|
6213
6285
|
registered: scriptName,
|
|
6214
6286
|
hint: "Script registered for future page loads; immediate execution skipped (page may not be ready)"
|
|
6215
6287
|
});
|
|
6216
6288
|
}
|
|
6217
|
-
return
|
|
6289
|
+
return ok27({ registered: scriptName, executedImmediately: true });
|
|
6218
6290
|
}
|
|
6219
6291
|
});
|
|
6220
6292
|
registerCommandDefinition("addinitscript", ["script"]);
|
|
6221
6293
|
|
|
6222
6294
|
// src/commands/find.ts
|
|
6223
|
-
import { z as
|
|
6224
|
-
import { ok as
|
|
6225
|
-
var actionSchema2 =
|
|
6295
|
+
import { z as z29 } from "zod";
|
|
6296
|
+
import { ok as ok28, fail as fail13, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
6297
|
+
var actionSchema2 = z29.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
6226
6298
|
var findCommand = registerCommand({
|
|
6227
6299
|
name: "find",
|
|
6228
6300
|
description: "Find elements by semantic strategy (text/role/label/placeholder/testid) and optionally perform an action",
|
|
6229
6301
|
scope: "page",
|
|
6230
|
-
parameters:
|
|
6231
|
-
strategy:
|
|
6232
|
-
value:
|
|
6233
|
-
name:
|
|
6234
|
-
exact:
|
|
6235
|
-
operation:
|
|
6302
|
+
parameters: z29.object({
|
|
6303
|
+
strategy: z29.enum(["text", "role", "label", "placeholder", "testid", "alt", "title", "first", "last", "nth"]),
|
|
6304
|
+
value: z29.string(),
|
|
6305
|
+
name: z29.string().optional(),
|
|
6306
|
+
exact: z29.boolean().optional().default(false),
|
|
6307
|
+
operation: z29.string().optional().describe('Trailing operation syntax, e.g. click, fill "text", type "text"'),
|
|
6236
6308
|
action: actionSchema2.optional().describe("Action to perform when not using trailing operation syntax"),
|
|
6237
|
-
actionValue:
|
|
6238
|
-
index:
|
|
6239
|
-
click:
|
|
6240
|
-
fill:
|
|
6241
|
-
type:
|
|
6242
|
-
select:
|
|
6243
|
-
hover:
|
|
6244
|
-
check:
|
|
6245
|
-
timeout:
|
|
6309
|
+
actionValue: z29.string().optional().describe("Value for fill/type/select when using action"),
|
|
6310
|
+
index: z29.number().int().optional().describe("Index for nth strategy"),
|
|
6311
|
+
click: z29.boolean().optional().default(false),
|
|
6312
|
+
fill: z29.string().optional(),
|
|
6313
|
+
type: z29.string().optional(),
|
|
6314
|
+
select: z29.string().optional(),
|
|
6315
|
+
hover: z29.boolean().optional().default(false),
|
|
6316
|
+
check: z29.boolean().optional().default(false),
|
|
6317
|
+
timeout: z29.number().optional().default(1e4)
|
|
6246
6318
|
}),
|
|
6247
|
-
result:
|
|
6248
|
-
matched:
|
|
6249
|
-
selector:
|
|
6250
|
-
action:
|
|
6319
|
+
result: z29.object({
|
|
6320
|
+
matched: z29.number(),
|
|
6321
|
+
selector: z29.string(),
|
|
6322
|
+
action: z29.string().optional()
|
|
6251
6323
|
}),
|
|
6252
6324
|
handler: async (p, ctx) => {
|
|
6253
6325
|
const page = ctx.page;
|
|
@@ -6262,7 +6334,7 @@ var findCommand = registerCommand({
|
|
|
6262
6334
|
});
|
|
6263
6335
|
const count = await locator.count();
|
|
6264
6336
|
if (count === 0) {
|
|
6265
|
-
return
|
|
6337
|
+
return fail13(`No element found with ${p.strategy}="${p.value}"`);
|
|
6266
6338
|
}
|
|
6267
6339
|
const tips = [];
|
|
6268
6340
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6274,15 +6346,15 @@ var findCommand = registerCommand({
|
|
|
6274
6346
|
await target.click({ timeout: p.timeout, force: true });
|
|
6275
6347
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6276
6348
|
} else if (actionName === "fill") {
|
|
6277
|
-
if (actionValue === void 0) return
|
|
6349
|
+
if (actionValue === void 0) return fail13("find fill requires a value");
|
|
6278
6350
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6279
6351
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6280
6352
|
} else if (actionName === "type") {
|
|
6281
|
-
if (actionValue === void 0) return
|
|
6353
|
+
if (actionValue === void 0) return fail13("find type requires a value");
|
|
6282
6354
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6283
6355
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6284
6356
|
} else if (actionName === "select") {
|
|
6285
|
-
if (actionValue === void 0) return
|
|
6357
|
+
if (actionValue === void 0) return fail13("find select requires a value");
|
|
6286
6358
|
await target.selectOption(actionValue);
|
|
6287
6359
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6288
6360
|
} else if (actionName === "hover") {
|
|
@@ -6296,7 +6368,7 @@ var findCommand = registerCommand({
|
|
|
6296
6368
|
}
|
|
6297
6369
|
});
|
|
6298
6370
|
function okWithTips(data, tips) {
|
|
6299
|
-
const result =
|
|
6371
|
+
const result = ok28(data);
|
|
6300
6372
|
if (tips.length > 0) result.tips = normalizeTips5(tips);
|
|
6301
6373
|
return result;
|
|
6302
6374
|
}
|
|
@@ -6395,8 +6467,8 @@ function describeSelector(strategy, value, name) {
|
|
|
6395
6467
|
}
|
|
6396
6468
|
|
|
6397
6469
|
// src/commands/visual-tag.ts
|
|
6398
|
-
import { z as
|
|
6399
|
-
import { ok as
|
|
6470
|
+
import { z as z30 } from "zod";
|
|
6471
|
+
import { ok as ok29, fail as fail14 } from "@dyyz1993/xcli-core";
|
|
6400
6472
|
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6401
6473
|
var TAG_SCRIPT = `
|
|
6402
6474
|
(function() {
|
|
@@ -6487,49 +6559,49 @@ var visualTagCommand = registerCommand({
|
|
|
6487
6559
|
name: "visual-tag",
|
|
6488
6560
|
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",
|
|
6489
6561
|
scope: "page",
|
|
6490
|
-
parameters:
|
|
6491
|
-
action:
|
|
6492
|
-
id:
|
|
6562
|
+
parameters: z30.object({
|
|
6563
|
+
action: z30.enum(["tag", "lookup", "clear", "list"]),
|
|
6564
|
+
id: z30.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6493
6565
|
}),
|
|
6494
|
-
result:
|
|
6495
|
-
action:
|
|
6496
|
-
tagged:
|
|
6497
|
-
id:
|
|
6498
|
-
element:
|
|
6566
|
+
result: z30.object({
|
|
6567
|
+
action: z30.string(),
|
|
6568
|
+
tagged: z30.number().optional(),
|
|
6569
|
+
id: z30.string().optional(),
|
|
6570
|
+
element: z30.record(z30.unknown()).optional()
|
|
6499
6571
|
}),
|
|
6500
6572
|
handler: async (p, ctx) => {
|
|
6501
6573
|
switch (p.action) {
|
|
6502
6574
|
case "tag": {
|
|
6503
6575
|
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6504
6576
|
const parsed = JSON.parse(result);
|
|
6505
|
-
return
|
|
6577
|
+
return ok29({ action: "tag", tagged: parsed.tagged });
|
|
6506
6578
|
}
|
|
6507
6579
|
case "lookup": {
|
|
6508
|
-
if (!p.id) return
|
|
6580
|
+
if (!p.id) return fail14("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6509
6581
|
const result = await ctx.page.evaluate(
|
|
6510
6582
|
`(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'}); })()`
|
|
6511
6583
|
);
|
|
6512
6584
|
const parsed = JSON.parse(result);
|
|
6513
|
-
if (parsed.err) return
|
|
6514
|
-
return
|
|
6585
|
+
if (parsed.err) return fail14(`ID ${p.id}: ${parsed.err}`);
|
|
6586
|
+
return ok29({ action: "lookup", id: p.id, element: parsed });
|
|
6515
6587
|
}
|
|
6516
6588
|
case "list": {
|
|
6517
6589
|
const result = await ctx.page.evaluate(
|
|
6518
6590
|
`(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); })()`
|
|
6519
6591
|
);
|
|
6520
|
-
return
|
|
6592
|
+
return ok29({ action: "list", element: JSON.parse(result) });
|
|
6521
6593
|
}
|
|
6522
6594
|
case "clear": {
|
|
6523
6595
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6524
|
-
return
|
|
6596
|
+
return ok29({ action: "clear" });
|
|
6525
6597
|
}
|
|
6526
6598
|
}
|
|
6527
6599
|
}
|
|
6528
6600
|
});
|
|
6529
6601
|
|
|
6530
6602
|
// src/commands/visual-tag-v2.ts
|
|
6531
|
-
import { z as
|
|
6532
|
-
import { ok as
|
|
6603
|
+
import { z as z31 } from "zod";
|
|
6604
|
+
import { ok as ok30, fail as fail15 } from "@dyyz1993/xcli-core";
|
|
6533
6605
|
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6534
6606
|
var TAG_V2_SCRIPT = `
|
|
6535
6607
|
(function() {
|
|
@@ -6876,45 +6948,45 @@ var visualTagV2Command = registerCommand({
|
|
|
6876
6948
|
name: "visual-tag-v2",
|
|
6877
6949
|
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",
|
|
6878
6950
|
scope: "page",
|
|
6879
|
-
parameters:
|
|
6880
|
-
action:
|
|
6881
|
-
id:
|
|
6882
|
-
query:
|
|
6883
|
-
type:
|
|
6884
|
-
"interact-action":
|
|
6885
|
-
value:
|
|
6951
|
+
parameters: z31.object({
|
|
6952
|
+
action: z31.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
6953
|
+
id: z31.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
6954
|
+
query: z31.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
6955
|
+
type: z31.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
6956
|
+
"interact-action": z31.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
6957
|
+
value: z31.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6886
6958
|
}),
|
|
6887
|
-
result:
|
|
6888
|
-
action:
|
|
6889
|
-
total:
|
|
6890
|
-
byType:
|
|
6891
|
-
element:
|
|
6959
|
+
result: z31.object({
|
|
6960
|
+
action: z31.string(),
|
|
6961
|
+
total: z31.number().optional(),
|
|
6962
|
+
byType: z31.record(z31.number()).optional(),
|
|
6963
|
+
element: z31.record(z31.unknown()).optional()
|
|
6892
6964
|
}),
|
|
6893
6965
|
handler: async (p, ctx) => {
|
|
6894
6966
|
switch (p.action) {
|
|
6895
6967
|
case "tag": {
|
|
6896
6968
|
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6897
6969
|
const parsed = JSON.parse(result);
|
|
6898
|
-
return
|
|
6970
|
+
return ok30({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6899
6971
|
}
|
|
6900
6972
|
case "lookup": {
|
|
6901
|
-
if (!p.id) return
|
|
6973
|
+
if (!p.id) return fail15("lookup \u9700\u8981 --id");
|
|
6902
6974
|
const result = await ctx.page.evaluate(
|
|
6903
6975
|
`(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'})})()`
|
|
6904
6976
|
);
|
|
6905
6977
|
const parsed = JSON.parse(result);
|
|
6906
|
-
if (parsed.err) return
|
|
6907
|
-
return
|
|
6978
|
+
if (parsed.err) return fail15(`ID ${p.id}: ${parsed.err}`);
|
|
6979
|
+
return ok30({ action: "lookup", id: p.id, element: parsed });
|
|
6908
6980
|
}
|
|
6909
6981
|
case "by-type": {
|
|
6910
6982
|
const result = await ctx.page.evaluate(
|
|
6911
6983
|
`(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)})()`
|
|
6912
6984
|
);
|
|
6913
|
-
return
|
|
6985
|
+
return ok30({ action: "by-type", element: JSON.parse(result) });
|
|
6914
6986
|
}
|
|
6915
6987
|
case "find": {
|
|
6916
6988
|
const query = p.query;
|
|
6917
|
-
if (!query) return
|
|
6989
|
+
if (!query) return fail15('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6918
6990
|
const result = await ctx.page.evaluate(
|
|
6919
6991
|
`(function(){
|
|
6920
6992
|
var map = window.__xbTagSerializable;
|
|
@@ -6956,21 +7028,21 @@ var visualTagV2Command = registerCommand({
|
|
|
6956
7028
|
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
6957
7029
|
})()`
|
|
6958
7030
|
);
|
|
6959
|
-
return
|
|
7031
|
+
return ok30({ action: "find", query, element: JSON.parse(result) });
|
|
6960
7032
|
}
|
|
6961
7033
|
case "stats": {
|
|
6962
7034
|
const result = await ctx.page.evaluate(
|
|
6963
7035
|
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
6964
7036
|
);
|
|
6965
|
-
return
|
|
7037
|
+
return ok30({ action: "stats", element: JSON.parse(result) });
|
|
6966
7038
|
}
|
|
6967
7039
|
case "interact": {
|
|
6968
7040
|
const query = p.query;
|
|
6969
7041
|
const pAny = p;
|
|
6970
7042
|
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
6971
7043
|
const value = pAny.value;
|
|
6972
|
-
if (!query) return
|
|
6973
|
-
if (!action) return
|
|
7044
|
+
if (!query) return fail15("interact \u9700\u8981 --query \u53C2\u6570");
|
|
7045
|
+
if (!action) return fail15("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
6974
7046
|
const findResult = await ctx.page.evaluate(
|
|
6975
7047
|
`(function(){
|
|
6976
7048
|
var map = window.__xbTagSerializable;
|
|
@@ -7000,11 +7072,11 @@ var visualTagV2Command = registerCommand({
|
|
|
7000
7072
|
})()`
|
|
7001
7073
|
);
|
|
7002
7074
|
const parsed = JSON.parse(findResult);
|
|
7003
|
-
if (parsed.err) return
|
|
7004
|
-
if (!parsed.total || !parsed.results?.length) return
|
|
7075
|
+
if (parsed.err) return fail15(parsed.err);
|
|
7076
|
+
if (!parsed.total || !parsed.results?.length) return fail15(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
7005
7077
|
const target = parsed.results[0];
|
|
7006
7078
|
if (action === "read") {
|
|
7007
|
-
return
|
|
7079
|
+
return ok30({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
7008
7080
|
}
|
|
7009
7081
|
if (action === "click") {
|
|
7010
7082
|
const el = await ctx.page.evaluate(
|
|
@@ -7017,12 +7089,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7017
7089
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7018
7090
|
})()`
|
|
7019
7091
|
);
|
|
7020
|
-
if (!el) return
|
|
7092
|
+
if (!el) return fail15(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7021
7093
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7022
|
-
return
|
|
7094
|
+
return ok30({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
7023
7095
|
}
|
|
7024
7096
|
if (action === "fill") {
|
|
7025
|
-
if (!value) return
|
|
7097
|
+
if (!value) return fail15("fill \u9700\u8981 --value \u53C2\u6570");
|
|
7026
7098
|
const el = await ctx.page.evaluate(
|
|
7027
7099
|
`(function(){
|
|
7028
7100
|
var map = window.__xbTagMap;
|
|
@@ -7033,12 +7105,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7033
7105
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7034
7106
|
})()`
|
|
7035
7107
|
);
|
|
7036
|
-
if (!el) return
|
|
7108
|
+
if (!el) return fail15(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7037
7109
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7038
7110
|
await ctx.page.keyboard.type(value, { stealth: true });
|
|
7039
|
-
return
|
|
7111
|
+
return ok30({ action: "interact", query, target, result: { filled: true, value } });
|
|
7040
7112
|
}
|
|
7041
|
-
return
|
|
7113
|
+
return fail15(`\u672A\u77E5 action: ${action}`);
|
|
7042
7114
|
}
|
|
7043
7115
|
case "export": {
|
|
7044
7116
|
const result = await ctx.page.evaluate(
|
|
@@ -7086,12 +7158,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7086
7158
|
})()`
|
|
7087
7159
|
);
|
|
7088
7160
|
const parsed = JSON.parse(result);
|
|
7089
|
-
if (parsed.err) return
|
|
7090
|
-
return
|
|
7161
|
+
if (parsed.err) return fail15(String(parsed.err));
|
|
7162
|
+
return ok30({ action: "export", element: parsed });
|
|
7091
7163
|
}
|
|
7092
7164
|
case "clear": {
|
|
7093
7165
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7094
|
-
return
|
|
7166
|
+
return ok30({ action: "clear" });
|
|
7095
7167
|
}
|
|
7096
7168
|
}
|
|
7097
7169
|
}
|
|
@@ -7617,8 +7689,8 @@ function classifyFailure(message) {
|
|
|
7617
7689
|
|
|
7618
7690
|
// src/executor.ts
|
|
7619
7691
|
import {
|
|
7620
|
-
ok as
|
|
7621
|
-
fail as
|
|
7692
|
+
ok as ok31,
|
|
7693
|
+
fail as fail16,
|
|
7622
7694
|
isCommandResult,
|
|
7623
7695
|
CompositeStorage as CompositeStorage2,
|
|
7624
7696
|
TipCollector as TipCollector2,
|
|
@@ -8484,7 +8556,7 @@ async function guardCheck(commandName) {
|
|
|
8484
8556
|
}
|
|
8485
8557
|
}
|
|
8486
8558
|
function errorResult(message) {
|
|
8487
|
-
return { ...
|
|
8559
|
+
return { ...fail16(message), duration: 0 };
|
|
8488
8560
|
}
|
|
8489
8561
|
function tipsToMessages(tips) {
|
|
8490
8562
|
if (!tips || tips.length === 0) return [];
|
|
@@ -8760,7 +8832,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8760
8832
|
timestamp: start
|
|
8761
8833
|
});
|
|
8762
8834
|
if (isSuccess) {
|
|
8763
|
-
return { ...
|
|
8835
|
+
return { ...ok31(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8764
8836
|
}
|
|
8765
8837
|
const fc = classifyFailure(raw.message);
|
|
8766
8838
|
return {
|
|
@@ -8783,7 +8855,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8783
8855
|
duration,
|
|
8784
8856
|
timestamp: start
|
|
8785
8857
|
});
|
|
8786
|
-
return { ...
|
|
8858
|
+
return { ...ok31(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8787
8859
|
} catch (err) {
|
|
8788
8860
|
const end = Date.now();
|
|
8789
8861
|
const duration = end - start;
|
|
@@ -8828,7 +8900,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8828
8900
|
duration,
|
|
8829
8901
|
timestamp: start
|
|
8830
8902
|
});
|
|
8831
|
-
return { ...
|
|
8903
|
+
return { ...fail16(errorMessage), duration };
|
|
8832
8904
|
} finally {
|
|
8833
8905
|
}
|
|
8834
8906
|
}
|
|
@@ -8873,7 +8945,7 @@ async function executeChain(input, options) {
|
|
|
8873
8945
|
results.push({
|
|
8874
8946
|
command: cmdName,
|
|
8875
8947
|
raw: cmdStr,
|
|
8876
|
-
...
|
|
8948
|
+
...fail16(`Plugin "${cmdName}" requires a sub-command`),
|
|
8877
8949
|
duration: 0
|
|
8878
8950
|
});
|
|
8879
8951
|
if (type === "and") {
|
|
@@ -8892,7 +8964,7 @@ async function executeChain(input, options) {
|
|
|
8892
8964
|
results.push({
|
|
8893
8965
|
command: cmdName,
|
|
8894
8966
|
raw: cmdStr,
|
|
8895
|
-
...
|
|
8967
|
+
...fail16(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
8896
8968
|
duration: 0
|
|
8897
8969
|
});
|
|
8898
8970
|
if (type === "and") {
|
|
@@ -9004,7 +9076,7 @@ async function executeChain(input, options) {
|
|
|
9004
9076
|
results.push({
|
|
9005
9077
|
command: `${cmdName} ${subCommand}`,
|
|
9006
9078
|
raw: cmdStr,
|
|
9007
|
-
...
|
|
9079
|
+
...ok31(data),
|
|
9008
9080
|
duration: duration2,
|
|
9009
9081
|
...hookOutputs ? { hookOutputs } : {}
|
|
9010
9082
|
});
|
|
@@ -9032,7 +9104,7 @@ async function executeChain(input, options) {
|
|
|
9032
9104
|
results.push({
|
|
9033
9105
|
command: `${cmdName} ${subCommand}`,
|
|
9034
9106
|
raw: cmdStr,
|
|
9035
|
-
...
|
|
9107
|
+
...fail16(errorMessage),
|
|
9036
9108
|
duration: duration2
|
|
9037
9109
|
});
|
|
9038
9110
|
if (type === "and") {
|