@xbrowser/cli 1.1.1 → 1.2.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/README.md +5 -3
- package/dist/{browser-BX4HZOUT.js → browser-CWI6BXYK.js} +2 -2
- package/dist/{browser-5FR3B57B.js → browser-JP2LFPR2.js} +2 -2
- package/dist/{browser-CFHOD5GY.js → browser-PZX7PO23.js} +1 -1
- package/dist/{cdp-driver-E4I3AEJK.js → cdp-driver-RPUNQBGM.js} +124 -54
- package/dist/{cdp-driver-LKNM6OQI.js → cdp-driver-S5STYUZZ.js} +1 -1
- package/dist/{chunk-MWBVZWXA.js → chunk-6V57JME6.js} +7 -7
- package/dist/{chunk-ISOSRTTV.js → chunk-MNFOCOL6.js} +130 -60
- package/dist/{chunk-IX4JY6OO.js → chunk-QFROODUU.js} +124 -54
- package/dist/{chunk-GOKTOYWM.js → chunk-SLQR57XZ.js} +7 -7
- package/dist/cli.js +139 -23
- package/dist/daemon-main.js +67 -6
- package/dist/index.js +140 -24
- package/dist/{session-replayer-YWMSSZWC.js → session-replayer-IXLSCF5U.js} +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
resolveLaunchOpts,
|
|
26
26
|
saveSessionDiskMeta,
|
|
27
27
|
setActivePage
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-MNFOCOL6.js";
|
|
29
29
|
import "./chunk-TNEN6VQ2.js";
|
|
30
30
|
import {
|
|
31
31
|
forwardCommandLog,
|
|
@@ -800,6 +800,21 @@ var waitForSelectorDef = {
|
|
|
800
800
|
}
|
|
801
801
|
};
|
|
802
802
|
var waitCommand = registerCommand({ name: "wait", selectorParams: ["selector"], ...waitForSelectorDef });
|
|
803
|
+
var waitForTimeoutCommand = registerCommand({
|
|
804
|
+
name: "waitForTimeout",
|
|
805
|
+
description: "Wait for a specified number of milliseconds",
|
|
806
|
+
scope: "project",
|
|
807
|
+
parameters: z4.object({
|
|
808
|
+
timeout: z4.number().describe("Milliseconds to wait").default(1e3)
|
|
809
|
+
}),
|
|
810
|
+
result: z4.object({
|
|
811
|
+
waited: z4.number()
|
|
812
|
+
}),
|
|
813
|
+
handler: async (p) => {
|
|
814
|
+
await new Promise((r) => setTimeout(r, p.timeout));
|
|
815
|
+
return ok4({ waited: p.timeout });
|
|
816
|
+
}
|
|
817
|
+
});
|
|
803
818
|
|
|
804
819
|
// src/commands/scroll.ts
|
|
805
820
|
import { z as z5 } from "zod";
|
|
@@ -1665,7 +1680,7 @@ var healthCheckCommand = registerCommand({
|
|
|
1665
1680
|
issues.push({
|
|
1666
1681
|
severity: "error",
|
|
1667
1682
|
category: "links",
|
|
1668
|
-
message: `Broken link (fetch error): ${href} \u2014 ${
|
|
1683
|
+
message: `Broken link (fetch error): ${href} \u2014 ${(err instanceof Error ? err.message : String(err)) || "unknown"}`
|
|
1669
1684
|
});
|
|
1670
1685
|
}
|
|
1671
1686
|
}
|
|
@@ -2341,9 +2356,53 @@ var scrapeCommand = registerCommand({
|
|
|
2341
2356
|
}
|
|
2342
2357
|
let content;
|
|
2343
2358
|
switch (p.format) {
|
|
2344
|
-
case "markdown":
|
|
2359
|
+
case "markdown": {
|
|
2360
|
+
const tablesMd = await page.evaluate(() => {
|
|
2361
|
+
const tableSelectors = [
|
|
2362
|
+
"table",
|
|
2363
|
+
'[role="table"]',
|
|
2364
|
+
'[role="grid"]',
|
|
2365
|
+
'[class*="el-table"]',
|
|
2366
|
+
// Element UI
|
|
2367
|
+
'[class*="ant-table"]',
|
|
2368
|
+
// Ant Design
|
|
2369
|
+
'[class*="MuiTable"]',
|
|
2370
|
+
// Material UI
|
|
2371
|
+
'[class*="table"]'
|
|
2372
|
+
// Generic table-like
|
|
2373
|
+
].join(",");
|
|
2374
|
+
const tables = document.querySelectorAll(tableSelectors);
|
|
2375
|
+
if (tables.length === 0) return "";
|
|
2376
|
+
return Array.from(tables).map((table) => {
|
|
2377
|
+
const rows = table.querySelectorAll('tr, [role="row"], [class*="row"]');
|
|
2378
|
+
if (rows.length === 0) return "";
|
|
2379
|
+
const mdRows = Array.from(rows).map((row) => {
|
|
2380
|
+
const cells = row.querySelectorAll('th, td, [role="columnheader"], [role="cell"], [class*="cell"], [class*="col"]');
|
|
2381
|
+
return "| " + Array.from(cells).map((c) => {
|
|
2382
|
+
const cellText = c.innerText?.trim().replace(/\n/g, " ") || "";
|
|
2383
|
+
return cellText.replace(/\|/g, "\\|") || "";
|
|
2384
|
+
}).join(" | ") + " |";
|
|
2385
|
+
}).join("\n");
|
|
2386
|
+
const headerRow = rows[0];
|
|
2387
|
+
const headerCells = headerRow.querySelectorAll('th, [role="columnheader"], [class*="header"]');
|
|
2388
|
+
const hasHeader = headerCells.length > 0;
|
|
2389
|
+
if (hasHeader && mdRows) {
|
|
2390
|
+
const headerCount = headerCells.length;
|
|
2391
|
+
const sep = "| " + Array(headerCount).fill("---").join(" | ") + " |";
|
|
2392
|
+
return mdRows.split("\n").map((line, i) => {
|
|
2393
|
+
if (i === 0) return line + "\n" + sep;
|
|
2394
|
+
return line;
|
|
2395
|
+
}).join("\n");
|
|
2396
|
+
}
|
|
2397
|
+
return mdRows;
|
|
2398
|
+
}).join("\n\n");
|
|
2399
|
+
});
|
|
2345
2400
|
content = htmlToMarkdown(html, { onlyMainContent: p.onlyMainContent });
|
|
2401
|
+
if (tablesMd) {
|
|
2402
|
+
content = tablesMd + "\n\n" + content;
|
|
2403
|
+
}
|
|
2346
2404
|
break;
|
|
2405
|
+
}
|
|
2347
2406
|
case "html":
|
|
2348
2407
|
content = html;
|
|
2349
2408
|
break;
|
|
@@ -5283,6 +5342,7 @@ function parseCommandChain(input, options) {
|
|
|
5283
5342
|
continue;
|
|
5284
5343
|
}
|
|
5285
5344
|
if (char === ";") {
|
|
5345
|
+
lastOperator = "sequence";
|
|
5286
5346
|
flushPipeline();
|
|
5287
5347
|
continue;
|
|
5288
5348
|
}
|
|
@@ -5337,6 +5397,7 @@ registerCommandDefinition("uncheck", ["selector"]);
|
|
|
5337
5397
|
registerCommandDefinition("hover", ["selector"]);
|
|
5338
5398
|
registerCommandDefinition("dblclick", ["selector"]);
|
|
5339
5399
|
registerCommandDefinition("wait", ["selector"]);
|
|
5400
|
+
registerCommandDefinition("waitForTimeout", ["timeout"]);
|
|
5340
5401
|
registerCommandDefinition("screenshot", []);
|
|
5341
5402
|
registerCommandDefinition("eval", ["expression"]);
|
|
5342
5403
|
registerCommandDefinition("scroll", ["direction"]);
|
|
@@ -6969,7 +7030,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6969
7030
|
}
|
|
6970
7031
|
let targetPageOverride = null;
|
|
6971
7032
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6972
|
-
const { findTargetPage } = await import("./browser-
|
|
7033
|
+
const { findTargetPage } = await import("./browser-PZX7PO23.js");
|
|
6973
7034
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6974
7035
|
if (!targetPageOverride) {
|
|
6975
7036
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -9477,7 +9538,17 @@ var SELECTOR_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
9477
9538
|
"dblclick",
|
|
9478
9539
|
"wait"
|
|
9479
9540
|
]);
|
|
9541
|
+
var CAMEL_TO_KEBAB = {
|
|
9542
|
+
getCookies: "get-cookies",
|
|
9543
|
+
setCookie: "set-cookie",
|
|
9544
|
+
clearCookies: "clear-cookies",
|
|
9545
|
+
getLocalStorage: "get-local-storage",
|
|
9546
|
+
setLocalStorage: "set-local-storage",
|
|
9547
|
+
clearLocalStorage: "clear-local-storage",
|
|
9548
|
+
setViewport: "set-viewport"
|
|
9549
|
+
};
|
|
9480
9550
|
async function handleBrowserCommand(command, args, options, sessionName, mode, cdpEndpoint) {
|
|
9551
|
+
command = CAMEL_TO_KEBAB[command] || command;
|
|
9481
9552
|
if (args.includes("--help") || args.includes("-h") || options.help || options.h) {
|
|
9482
9553
|
const cmdDef = getCommand(command);
|
|
9483
9554
|
if (cmdDef) {
|
|
@@ -9594,7 +9665,8 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9594
9665
|
if (!args[0]) outputError(`Usage: xbrowser ${command} <url>`);
|
|
9595
9666
|
cmdName = "goto";
|
|
9596
9667
|
params = {
|
|
9597
|
-
|
|
9668
|
+
// Don't prefix if URL already has a scheme (http, file, about, data, etc.)
|
|
9669
|
+
url: /^(https?|wss?|file|about|data|chrome|blob):/i.test(args[0]) ? args[0] : /^[\w-]+(\.[\w-]+)+/.test(args[0]) || args[0].startsWith("localhost") ? "https://" + args[0] : args[0],
|
|
9598
9670
|
waitUntil: options.waitUntil,
|
|
9599
9671
|
...options.timeout ? { timeout: Number(options.timeout) } : {}
|
|
9600
9672
|
};
|
|
@@ -9606,7 +9678,7 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9606
9678
|
type: options.type,
|
|
9607
9679
|
selector: options.selector || options.s,
|
|
9608
9680
|
base64: !!options.base64,
|
|
9609
|
-
output: options.output || options.o
|
|
9681
|
+
output: options.output || options.o || args[0]
|
|
9610
9682
|
};
|
|
9611
9683
|
break;
|
|
9612
9684
|
case "eval":
|
|
@@ -9652,11 +9724,12 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9652
9724
|
break;
|
|
9653
9725
|
}
|
|
9654
9726
|
case "mouse": {
|
|
9655
|
-
const
|
|
9656
|
-
const
|
|
9657
|
-
const
|
|
9658
|
-
const
|
|
9659
|
-
|
|
9727
|
+
const flatArgs = args.flatMap((a) => a.split(/\s+/).filter(Boolean));
|
|
9728
|
+
const action = options.action || flatArgs.find((a) => ["move", "click", "dblclick", "down", "up"].includes(a));
|
|
9729
|
+
const actionIdx = action ? flatArgs.indexOf(action) : -1;
|
|
9730
|
+
const x = options.x !== void 0 ? Number(options.x) : actionIdx >= 0 && flatArgs[actionIdx + 1] ? Number(flatArgs[actionIdx + 1]) : void 0;
|
|
9731
|
+
const y = options.y !== void 0 ? Number(options.y) : actionIdx >= 0 && flatArgs[actionIdx + 2] ? Number(flatArgs[actionIdx + 2]) : void 0;
|
|
9732
|
+
if (!action || x === void 0 || y === void 0 || isNaN(x) || isNaN(y)) {
|
|
9660
9733
|
outputError("Usage: xbrowser mouse <move|click|dblclick> <x> <y>\n xbrowser mouse --action <action> --x <x> --y <y>");
|
|
9661
9734
|
}
|
|
9662
9735
|
cmdName = "mouse";
|
|
@@ -9842,6 +9915,7 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9842
9915
|
outputResult(result.data, mode);
|
|
9843
9916
|
console.error(`
|
|
9844
9917
|
\u26A0\uFE0F ${hint}`);
|
|
9918
|
+
process.exit(1);
|
|
9845
9919
|
} else {
|
|
9846
9920
|
outputResult(result.data, mode);
|
|
9847
9921
|
}
|
|
@@ -9936,11 +10010,6 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
9936
10010
|
}
|
|
9937
10011
|
|
|
9938
10012
|
// src/cli/plugin-routes.ts
|
|
9939
|
-
var pluginLoader3 = null;
|
|
9940
|
-
function getPluginLoader2() {
|
|
9941
|
-
if (!pluginLoader3) pluginLoader3 = new XBrowserPluginLoader();
|
|
9942
|
-
return pluginLoader3;
|
|
9943
|
-
}
|
|
9944
10013
|
async function buildRuntimePluginInfo() {
|
|
9945
10014
|
const loader = await getPluginLoader();
|
|
9946
10015
|
const sites = loader.getCore().loader.getSites();
|
|
@@ -10198,6 +10267,10 @@ async function handlePlugin(args, options, mode) {
|
|
|
10198
10267
|
} else {
|
|
10199
10268
|
result = await installer.installWithMarketplaceFallback(source, installOpts);
|
|
10200
10269
|
}
|
|
10270
|
+
try {
|
|
10271
|
+
await (await getPluginLoader()).reloadPlugin(result.name);
|
|
10272
|
+
} catch {
|
|
10273
|
+
}
|
|
10201
10274
|
outputResult(
|
|
10202
10275
|
{ ok: true, name: result.name, source: result.source, path: result.path },
|
|
10203
10276
|
mode
|
|
@@ -10213,6 +10286,11 @@ async function handlePlugin(args, options, mode) {
|
|
|
10213
10286
|
outputError(`Plugin "${name}" is not installed. Use 'xbrowser plugin list' to see installed plugins.`);
|
|
10214
10287
|
}
|
|
10215
10288
|
await installer.uninstall(name);
|
|
10289
|
+
try {
|
|
10290
|
+
const loader = await getPluginLoader();
|
|
10291
|
+
await loader.reloadPlugin(name);
|
|
10292
|
+
} catch {
|
|
10293
|
+
}
|
|
10216
10294
|
outputResult({ ok: true, name }, mode);
|
|
10217
10295
|
break;
|
|
10218
10296
|
}
|
|
@@ -10266,7 +10344,7 @@ Total: ${enrichedPlugins.length} plugins`);
|
|
|
10266
10344
|
case "reload": {
|
|
10267
10345
|
const name = subArgs[0];
|
|
10268
10346
|
if (!name) outputError("Usage: xbrowser plugin reload <name>");
|
|
10269
|
-
await
|
|
10347
|
+
(await getPluginLoader()).reloadPlugin(name);
|
|
10270
10348
|
outputResult({ ok: true, name }, mode);
|
|
10271
10349
|
break;
|
|
10272
10350
|
}
|
|
@@ -10650,15 +10728,20 @@ async function handleExtract(args, _mode) {
|
|
|
10650
10728
|
console.log(`
|
|
10651
10729
|
Saved LLM summary: ${outputPath}`);
|
|
10652
10730
|
}
|
|
10653
|
-
async function handleFilter(args, _mode) {
|
|
10731
|
+
async function handleFilter(args, _mode, options) {
|
|
10654
10732
|
const filePath = args[0];
|
|
10655
10733
|
const outputPath = args[1];
|
|
10656
10734
|
if (!filePath || !outputPath) {
|
|
10657
|
-
console.error("Usage: xbrowser filter <input.yaml> <output.yaml> [--exclude
|
|
10735
|
+
console.error("Usage: xbrowser filter <input.yaml> <output.yaml> [--exclude type1,type2]");
|
|
10658
10736
|
process.exit(1);
|
|
10659
10737
|
}
|
|
10660
10738
|
const { filterRecording, parseExcludeTypes } = await import("./filter-EDTFGLS5.js");
|
|
10661
|
-
const
|
|
10739
|
+
const excludeArgs = args.slice(2).concat(
|
|
10740
|
+
Object.entries(options || {}).flatMap(
|
|
10741
|
+
([k, v]) => k.startsWith("exclude") ? [`--${k}${typeof v === "string" ? "=" + v : ""}`] : []
|
|
10742
|
+
)
|
|
10743
|
+
);
|
|
10744
|
+
const excludeTypes = parseExcludeTypes(excludeArgs);
|
|
10662
10745
|
const result = filterRecording(filePath, outputPath, excludeTypes);
|
|
10663
10746
|
console.log(`Filtered ${filePath} -> ${outputPath}`);
|
|
10664
10747
|
console.log(` Original: ${result.originalCount}, After: ${result.filteredCount}, Removed: ${result.removed} (${result.percentage}%)`);
|
|
@@ -12109,10 +12192,18 @@ function extractCdpFromArgv(argv) {
|
|
|
12109
12192
|
async function handleStdinMode(stdinCommands, argv) {
|
|
12110
12193
|
const chain = stdinCommands.join(" && ");
|
|
12111
12194
|
const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
|
|
12112
|
-
const
|
|
12195
|
+
const sessionName = argv ? extractSessionNameFromArgv(argv) : "default";
|
|
12196
|
+
const chainResult = await executeChain(chain, { fileMode: true, cdpEndpoint, sessionName });
|
|
12113
12197
|
printChainResult(chainResult);
|
|
12114
12198
|
if (!chainResult.success) throw new Error("Command failed");
|
|
12115
12199
|
}
|
|
12200
|
+
function extractSessionNameFromArgv(argv) {
|
|
12201
|
+
for (let i = 0; i < argv.length; i++) {
|
|
12202
|
+
if (argv[i] === "--session" && argv[i + 1]) return argv[i + 1];
|
|
12203
|
+
if (typeof argv[i] === "string" && argv[i].startsWith("--session=")) return argv[i].slice(10);
|
|
12204
|
+
}
|
|
12205
|
+
return process.env.XBROWSER_SESSION || "default";
|
|
12206
|
+
}
|
|
12116
12207
|
async function handleEvalMode(argv) {
|
|
12117
12208
|
const evalCommands = parseEvalFlags(argv);
|
|
12118
12209
|
if (evalCommands.length === 0) return;
|
|
@@ -12252,6 +12343,31 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12252
12343
|
}
|
|
12253
12344
|
return;
|
|
12254
12345
|
}
|
|
12346
|
+
const SUBCOMMAND_HELP = {
|
|
12347
|
+
session: "session open|close|kill|list [--session <name>] [--cdp <endpoint>]",
|
|
12348
|
+
plugin: "plugin install|uninstall|list|reload|schema|search|info <name>",
|
|
12349
|
+
record: "record start|stop|status [--url <url>] [--name <flow>]",
|
|
12350
|
+
daemon: "daemon status [--port <port>]",
|
|
12351
|
+
replay: "replay <file> [--slow-mo <ms>] [--stop-on-error]",
|
|
12352
|
+
create: "create <name> [--template static|dynamic|login|api]",
|
|
12353
|
+
run: "run <file>",
|
|
12354
|
+
serve: "serve [--port <port>] [--token <token>]",
|
|
12355
|
+
remote: "remote <url> [command] [--token <token>]",
|
|
12356
|
+
convert: "convert <file> [--to js|py|sh]",
|
|
12357
|
+
extract: "extract <file> [--format json|yaml]",
|
|
12358
|
+
filter: "filter <file> [--include <type>] [--exclude <type>]",
|
|
12359
|
+
test: "test <name> [--cdp <endpoint>]",
|
|
12360
|
+
viewer: "viewer [--session <name>]",
|
|
12361
|
+
kill: "kill [--all]",
|
|
12362
|
+
net: "net [--cdp <endpoint>]"
|
|
12363
|
+
};
|
|
12364
|
+
const subHelp = SUBCOMMAND_HELP[command];
|
|
12365
|
+
if (subHelp) {
|
|
12366
|
+
console.log(`
|
|
12367
|
+
Usage: xbrowser ${subHelp}
|
|
12368
|
+
`);
|
|
12369
|
+
return;
|
|
12370
|
+
}
|
|
12255
12371
|
showMainHelp();
|
|
12256
12372
|
return;
|
|
12257
12373
|
}
|
|
@@ -12289,7 +12405,7 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12289
12405
|
await handleExtract(cmdArgs, mode);
|
|
12290
12406
|
break;
|
|
12291
12407
|
case "filter":
|
|
12292
|
-
await handleFilter(cmdArgs, mode);
|
|
12408
|
+
await handleFilter(cmdArgs, mode, options);
|
|
12293
12409
|
break;
|
|
12294
12410
|
case "run":
|
|
12295
12411
|
if (!cmdArgs[0]) {
|
|
@@ -12738,7 +12854,7 @@ async function main() {
|
|
|
12738
12854
|
const command = process.argv[2];
|
|
12739
12855
|
const isLongRunning = command === "preview" || command === "serve";
|
|
12740
12856
|
if (!isLongRunning) {
|
|
12741
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
12857
|
+
const { ensureProcessCanExit } = await import("./browser-PZX7PO23.js");
|
|
12742
12858
|
await ensureProcessCanExit().catch(() => {
|
|
12743
12859
|
});
|
|
12744
12860
|
process.exit(exitCode);
|
package/dist/daemon-main.js
CHANGED
|
@@ -21,8 +21,8 @@ import {
|
|
|
21
21
|
resolveLaunchOpts,
|
|
22
22
|
saveSessionDiskMeta,
|
|
23
23
|
setActivePage
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-SLQR57XZ.js";
|
|
25
|
+
import "./chunk-QFROODUU.js";
|
|
26
26
|
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import {
|
|
28
28
|
getDaemonConfig,
|
|
@@ -758,6 +758,21 @@ var waitForSelectorDef = {
|
|
|
758
758
|
}
|
|
759
759
|
};
|
|
760
760
|
var waitCommand = registerCommand({ name: "wait", selectorParams: ["selector"], ...waitForSelectorDef });
|
|
761
|
+
var waitForTimeoutCommand = registerCommand({
|
|
762
|
+
name: "waitForTimeout",
|
|
763
|
+
description: "Wait for a specified number of milliseconds",
|
|
764
|
+
scope: "project",
|
|
765
|
+
parameters: z4.object({
|
|
766
|
+
timeout: z4.number().describe("Milliseconds to wait").default(1e3)
|
|
767
|
+
}),
|
|
768
|
+
result: z4.object({
|
|
769
|
+
waited: z4.number()
|
|
770
|
+
}),
|
|
771
|
+
handler: async (p) => {
|
|
772
|
+
await new Promise((r) => setTimeout(r, p.timeout));
|
|
773
|
+
return ok4({ waited: p.timeout });
|
|
774
|
+
}
|
|
775
|
+
});
|
|
761
776
|
|
|
762
777
|
// src/commands/scroll.ts
|
|
763
778
|
import { z as z5 } from "zod";
|
|
@@ -1623,7 +1638,7 @@ var healthCheckCommand = registerCommand({
|
|
|
1623
1638
|
issues.push({
|
|
1624
1639
|
severity: "error",
|
|
1625
1640
|
category: "links",
|
|
1626
|
-
message: `Broken link (fetch error): ${href} \u2014 ${
|
|
1641
|
+
message: `Broken link (fetch error): ${href} \u2014 ${(err instanceof Error ? err.message : String(err)) || "unknown"}`
|
|
1627
1642
|
});
|
|
1628
1643
|
}
|
|
1629
1644
|
}
|
|
@@ -2299,9 +2314,53 @@ var scrapeCommand = registerCommand({
|
|
|
2299
2314
|
}
|
|
2300
2315
|
let content;
|
|
2301
2316
|
switch (p.format) {
|
|
2302
|
-
case "markdown":
|
|
2317
|
+
case "markdown": {
|
|
2318
|
+
const tablesMd = await page.evaluate(() => {
|
|
2319
|
+
const tableSelectors = [
|
|
2320
|
+
"table",
|
|
2321
|
+
'[role="table"]',
|
|
2322
|
+
'[role="grid"]',
|
|
2323
|
+
'[class*="el-table"]',
|
|
2324
|
+
// Element UI
|
|
2325
|
+
'[class*="ant-table"]',
|
|
2326
|
+
// Ant Design
|
|
2327
|
+
'[class*="MuiTable"]',
|
|
2328
|
+
// Material UI
|
|
2329
|
+
'[class*="table"]'
|
|
2330
|
+
// Generic table-like
|
|
2331
|
+
].join(",");
|
|
2332
|
+
const tables = document.querySelectorAll(tableSelectors);
|
|
2333
|
+
if (tables.length === 0) return "";
|
|
2334
|
+
return Array.from(tables).map((table) => {
|
|
2335
|
+
const rows = table.querySelectorAll('tr, [role="row"], [class*="row"]');
|
|
2336
|
+
if (rows.length === 0) return "";
|
|
2337
|
+
const mdRows = Array.from(rows).map((row) => {
|
|
2338
|
+
const cells = row.querySelectorAll('th, td, [role="columnheader"], [role="cell"], [class*="cell"], [class*="col"]');
|
|
2339
|
+
return "| " + Array.from(cells).map((c) => {
|
|
2340
|
+
const cellText = c.innerText?.trim().replace(/\n/g, " ") || "";
|
|
2341
|
+
return cellText.replace(/\|/g, "\\|") || "";
|
|
2342
|
+
}).join(" | ") + " |";
|
|
2343
|
+
}).join("\n");
|
|
2344
|
+
const headerRow = rows[0];
|
|
2345
|
+
const headerCells = headerRow.querySelectorAll('th, [role="columnheader"], [class*="header"]');
|
|
2346
|
+
const hasHeader = headerCells.length > 0;
|
|
2347
|
+
if (hasHeader && mdRows) {
|
|
2348
|
+
const headerCount = headerCells.length;
|
|
2349
|
+
const sep = "| " + Array(headerCount).fill("---").join(" | ") + " |";
|
|
2350
|
+
return mdRows.split("\n").map((line, i) => {
|
|
2351
|
+
if (i === 0) return line + "\n" + sep;
|
|
2352
|
+
return line;
|
|
2353
|
+
}).join("\n");
|
|
2354
|
+
}
|
|
2355
|
+
return mdRows;
|
|
2356
|
+
}).join("\n\n");
|
|
2357
|
+
});
|
|
2303
2358
|
content = htmlToMarkdown(html, { onlyMainContent: p.onlyMainContent });
|
|
2359
|
+
if (tablesMd) {
|
|
2360
|
+
content = tablesMd + "\n\n" + content;
|
|
2361
|
+
}
|
|
2304
2362
|
break;
|
|
2363
|
+
}
|
|
2305
2364
|
case "html":
|
|
2306
2365
|
content = html;
|
|
2307
2366
|
break;
|
|
@@ -5241,6 +5300,7 @@ function parseCommandChain(input, options) {
|
|
|
5241
5300
|
continue;
|
|
5242
5301
|
}
|
|
5243
5302
|
if (char === ";") {
|
|
5303
|
+
lastOperator = "sequence";
|
|
5244
5304
|
flushPipeline();
|
|
5245
5305
|
continue;
|
|
5246
5306
|
}
|
|
@@ -5295,6 +5355,7 @@ registerCommandDefinition("uncheck", ["selector"]);
|
|
|
5295
5355
|
registerCommandDefinition("hover", ["selector"]);
|
|
5296
5356
|
registerCommandDefinition("dblclick", ["selector"]);
|
|
5297
5357
|
registerCommandDefinition("wait", ["selector"]);
|
|
5358
|
+
registerCommandDefinition("waitForTimeout", ["timeout"]);
|
|
5298
5359
|
registerCommandDefinition("screenshot", []);
|
|
5299
5360
|
registerCommandDefinition("eval", ["expression"]);
|
|
5300
5361
|
registerCommandDefinition("scroll", ["direction"]);
|
|
@@ -6927,7 +6988,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6927
6988
|
}
|
|
6928
6989
|
let targetPageOverride = null;
|
|
6929
6990
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6930
|
-
const { findTargetPage } = await import("./browser-
|
|
6991
|
+
const { findTargetPage } = await import("./browser-CWI6BXYK.js");
|
|
6931
6992
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6932
6993
|
if (!targetPageOverride) {
|
|
6933
6994
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -8611,7 +8672,7 @@ function createRPCHandler() {
|
|
|
8611
8672
|
const isNewFormat = Array.isArray(parsed.actions);
|
|
8612
8673
|
if (isNewFormat) {
|
|
8613
8674
|
try {
|
|
8614
|
-
const { SessionReplayer } = await import("./session-replayer-
|
|
8675
|
+
const { SessionReplayer } = await import("./session-replayer-IXLSCF5U.js");
|
|
8615
8676
|
const replayer = new SessionReplayer({
|
|
8616
8677
|
page: session.page,
|
|
8617
8678
|
stepDelay: slowMo * 500,
|