@xbrowser/cli 1.8.5 → 1.8.7
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/{browser-NSSCH4MJ.js → browser-LW2MDJE4.js} +1 -1
- package/dist/{browser-PTELW3WS.js → browser-TLIDFFEG.js} +1 -1
- package/dist/{browser-PUAJ3AHG.js → browser-XPKM344Y.js} +1 -1
- package/dist/{chunk-7EOQV6ZW.js → chunk-CJJ564VK.js} +1 -1
- package/dist/{chunk-BALOM2HW.js → chunk-FL6DOSWV.js} +36 -8
- package/dist/{chunk-TAHJCCME.js → chunk-HXLMMSU3.js} +1 -1
- package/dist/{chunk-XU5WOJIV.js → chunk-RMYEHTLS.js} +36 -8
- package/dist/{chunk-U25ZKXBJ.js → chunk-SJLRCE6N.js} +1 -1
- package/dist/cli.js +213 -103
- package/dist/daemon-main.js +65 -32
- package/dist/index.d.ts +1 -0
- package/dist/index.js +212 -102
- package/dist/{session-recorder-H2WPBCSW.js → session-recorder-33UKWCIR.js} +1 -1
- package/dist/{session-recorder-CV5EJSDY.js → session-recorder-BMIJ3ZJM.js} +1 -1
- package/package.json +2 -2
package/dist/daemon-main.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-VEDJ5XSQ.js";
|
|
6
6
|
import {
|
|
7
7
|
SessionRecorder
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-FL6DOSWV.js";
|
|
9
9
|
import {
|
|
10
10
|
closeEphemeralContext,
|
|
11
11
|
closeSessionByName,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
resolveLaunchOpts,
|
|
22
22
|
saveSessionDiskMeta,
|
|
23
23
|
setActivePage
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-HXLMMSU3.js";
|
|
25
25
|
import "./chunk-VJNMAWPZ.js";
|
|
26
26
|
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import {
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
// src/executor.ts
|
|
56
56
|
import {
|
|
57
57
|
ok as ok25,
|
|
58
|
-
fail as
|
|
58
|
+
fail as fail9,
|
|
59
59
|
isCommandResult,
|
|
60
60
|
CompositeStorage as CompositeStorage2,
|
|
61
61
|
TipCollector as TipCollector2,
|
|
@@ -2283,7 +2283,7 @@ var scrapeCommand = registerCommand({
|
|
|
2283
2283
|
scope: "project",
|
|
2284
2284
|
selectorParams: ["selector"],
|
|
2285
2285
|
parameters: z15.object({
|
|
2286
|
-
url: z15.string(),
|
|
2286
|
+
url: z15.string().optional(),
|
|
2287
2287
|
selector: z15.string().optional(),
|
|
2288
2288
|
timeout: z15.number().default(3e4),
|
|
2289
2289
|
format: z15.enum(["markdown", "html", "text"]).default("markdown"),
|
|
@@ -2296,10 +2296,14 @@ var scrapeCommand = registerCommand({
|
|
|
2296
2296
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
2297
2297
|
const maxAttempts = p.retries + 1;
|
|
2298
2298
|
try {
|
|
2299
|
+
const targetUrl = p.url || page.url();
|
|
2300
|
+
if (!targetUrl || targetUrl === "about:blank") {
|
|
2301
|
+
return fail3("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2302
|
+
}
|
|
2299
2303
|
let lastError;
|
|
2300
2304
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2301
2305
|
try {
|
|
2302
|
-
await page.goto(
|
|
2306
|
+
await page.goto(targetUrl, { waitUntil: "commit", timeout: p.timeout });
|
|
2303
2307
|
await page.waitForSelector("body", { timeout: p.timeout }).catch(() => {
|
|
2304
2308
|
});
|
|
2305
2309
|
await page.waitForLoadState("networkidle", Math.min(p.timeout, 8e3)).catch(() => {
|
|
@@ -2360,7 +2364,7 @@ var scrapeCommand = registerCommand({
|
|
|
2360
2364
|
return { url: location.href, title: document.title, navigation, tables, forms: forms.slice(0, 20), links: links.slice(0, 30), mainText };
|
|
2361
2365
|
});
|
|
2362
2366
|
try {
|
|
2363
|
-
persistFromScrape(
|
|
2367
|
+
persistFromScrape(targetUrl, structured);
|
|
2364
2368
|
} catch {
|
|
2365
2369
|
}
|
|
2366
2370
|
if (p.mode === "smart") {
|
|
@@ -2461,7 +2465,7 @@ var scrapeCommand = registerCommand({
|
|
|
2461
2465
|
|
|
2462
2466
|
// src/commands/map.ts
|
|
2463
2467
|
import { z as z16 } from "zod";
|
|
2464
|
-
import { ok as ok16 } from "@dyyz1993/xcli-core";
|
|
2468
|
+
import { ok as ok16, fail as fail4 } from "@dyyz1993/xcli-core";
|
|
2465
2469
|
|
|
2466
2470
|
// src/utils/url.ts
|
|
2467
2471
|
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -2697,7 +2701,7 @@ var mapCommand = registerCommand({
|
|
|
2697
2701
|
description: "Discover all URLs on a website via sitemap and page link extraction",
|
|
2698
2702
|
scope: "project",
|
|
2699
2703
|
parameters: z16.object({
|
|
2700
|
-
url: z16.string(),
|
|
2704
|
+
url: z16.string().optional(),
|
|
2701
2705
|
search: z16.string().optional(),
|
|
2702
2706
|
sitemap: z16.enum(["include", "only"]).optional(),
|
|
2703
2707
|
includeSubdomains: z16.boolean().optional(),
|
|
@@ -2708,7 +2712,11 @@ var mapCommand = registerCommand({
|
|
|
2708
2712
|
handler: async (p, ctx) => {
|
|
2709
2713
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
2710
2714
|
try {
|
|
2711
|
-
const
|
|
2715
|
+
const targetUrl = p.url || page.url();
|
|
2716
|
+
if (!targetUrl || targetUrl === "about:blank") {
|
|
2717
|
+
return fail4("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2718
|
+
}
|
|
2719
|
+
const links = await discoverUrls(page, targetUrl, {
|
|
2712
2720
|
sitemap: p.sitemap,
|
|
2713
2721
|
includeSubdomains: p.includeSubdomains,
|
|
2714
2722
|
allowExternalLinks: p.allowExternalLinks,
|
|
@@ -3551,7 +3559,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
3551
3559
|
|
|
3552
3560
|
// src/commands/network.ts
|
|
3553
3561
|
import { z as z19 } from "zod";
|
|
3554
|
-
import { ok as ok19, fail as
|
|
3562
|
+
import { ok as ok19, fail as fail5 } from "@dyyz1993/xcli-core";
|
|
3555
3563
|
function extractPath2(url) {
|
|
3556
3564
|
try {
|
|
3557
3565
|
const u = new URL(url);
|
|
@@ -3716,7 +3724,7 @@ var networkCommand = registerCommand({
|
|
|
3716
3724
|
};
|
|
3717
3725
|
if (p.listen) {
|
|
3718
3726
|
const page2 = ctx.page;
|
|
3719
|
-
if (!page2) return
|
|
3727
|
+
if (!page2) return fail5("No active page. Use --cdp to connect first.");
|
|
3720
3728
|
const captures = [];
|
|
3721
3729
|
const consoleMessages = [];
|
|
3722
3730
|
const wsCaptures = [];
|
|
@@ -4096,7 +4104,7 @@ var ENGINE_KEY_ENUM = z20.enum(ALL_ENGINE_KEYS);
|
|
|
4096
4104
|
|
|
4097
4105
|
// src/commands/snapshot.ts
|
|
4098
4106
|
import { z as z21 } from "zod";
|
|
4099
|
-
import { ok as ok20, fail as
|
|
4107
|
+
import { ok as ok20, fail as fail6, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
|
|
4100
4108
|
|
|
4101
4109
|
// src/runtime/ref-store.ts
|
|
4102
4110
|
var sessions = /* @__PURE__ */ new Map();
|
|
@@ -5067,7 +5075,7 @@ var snapshotCommand = registerCommand({
|
|
|
5067
5075
|
persistSemantics(url, aria);
|
|
5068
5076
|
return ok20({ url, title, aria, text, dom }, normalizeTips3(tips));
|
|
5069
5077
|
}
|
|
5070
|
-
return
|
|
5078
|
+
return fail6(`Unknown snapshot type: ${p.type}`);
|
|
5071
5079
|
}
|
|
5072
5080
|
});
|
|
5073
5081
|
function persistSemantics(url, aria) {
|
|
@@ -5236,7 +5244,7 @@ var waitForCommand = registerCommand({
|
|
|
5236
5244
|
|
|
5237
5245
|
// src/commands/tab.ts
|
|
5238
5246
|
import { z as z23 } from "zod";
|
|
5239
|
-
import { ok as ok22, fail as
|
|
5247
|
+
import { ok as ok22, fail as fail7 } from "@dyyz1993/xcli-core";
|
|
5240
5248
|
var TabParams = z23.object({
|
|
5241
5249
|
subcommand: z23.enum(["list", "new", "close", "switch"]),
|
|
5242
5250
|
url: z23.string().optional(),
|
|
@@ -5253,7 +5261,7 @@ var tabCommand = registerCommand({
|
|
|
5253
5261
|
}),
|
|
5254
5262
|
handler: async (p, ctx) => {
|
|
5255
5263
|
if (!ctx.browserContext) {
|
|
5256
|
-
return
|
|
5264
|
+
return fail7("No browser context available. Use --cdp to connect to a browser first.");
|
|
5257
5265
|
}
|
|
5258
5266
|
const pages = ctx.browserContext.pages();
|
|
5259
5267
|
switch (p.subcommand) {
|
|
@@ -5266,7 +5274,7 @@ var tabCommand = registerCommand({
|
|
|
5266
5274
|
case "switch":
|
|
5267
5275
|
return handleSwitch(p, pages, ctx);
|
|
5268
5276
|
default:
|
|
5269
|
-
return
|
|
5277
|
+
return fail7(`Unknown subcommand: ${p.subcommand}`);
|
|
5270
5278
|
}
|
|
5271
5279
|
}
|
|
5272
5280
|
});
|
|
@@ -5323,11 +5331,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5323
5331
|
}
|
|
5324
5332
|
async function handleClose(p, pages, ctx) {
|
|
5325
5333
|
if (pages.length <= 1) {
|
|
5326
|
-
return
|
|
5334
|
+
return fail7("Cannot close the last remaining tab");
|
|
5327
5335
|
}
|
|
5328
5336
|
const closeIndex = p.index ?? pages.indexOf(ctx.page);
|
|
5329
5337
|
if (closeIndex < 0 || closeIndex >= pages.length) {
|
|
5330
|
-
return
|
|
5338
|
+
return fail7(`Invalid tab index: ${closeIndex}. Valid range: 0-${pages.length - 1}`);
|
|
5331
5339
|
}
|
|
5332
5340
|
const pageToClose = pages[closeIndex];
|
|
5333
5341
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5350,10 +5358,10 @@ async function handleClose(p, pages, ctx) {
|
|
|
5350
5358
|
}
|
|
5351
5359
|
async function handleSwitch(p, pages, ctx) {
|
|
5352
5360
|
if (p.index === void 0) {
|
|
5353
|
-
return
|
|
5361
|
+
return fail7("Parameter --index is required for switch subcommand");
|
|
5354
5362
|
}
|
|
5355
5363
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5356
|
-
return
|
|
5364
|
+
return fail7(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5357
5365
|
}
|
|
5358
5366
|
const targetPage = pages[p.index];
|
|
5359
5367
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -5605,7 +5613,7 @@ registerCommandDefinition("addinitscript", ["script"]);
|
|
|
5605
5613
|
|
|
5606
5614
|
// src/commands/find.ts
|
|
5607
5615
|
import { z as z25 } from "zod";
|
|
5608
|
-
import { ok as ok24, fail as
|
|
5616
|
+
import { ok as ok24, fail as fail8, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
5609
5617
|
var actionSchema2 = z25.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
5610
5618
|
var findCommand = registerCommand({
|
|
5611
5619
|
name: "find",
|
|
@@ -5646,7 +5654,7 @@ var findCommand = registerCommand({
|
|
|
5646
5654
|
});
|
|
5647
5655
|
const count = await locator.count();
|
|
5648
5656
|
if (count === 0) {
|
|
5649
|
-
return
|
|
5657
|
+
return fail8(`No element found with ${p.strategy}="${p.value}"`);
|
|
5650
5658
|
}
|
|
5651
5659
|
const tips = [];
|
|
5652
5660
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -5658,15 +5666,15 @@ var findCommand = registerCommand({
|
|
|
5658
5666
|
await target.click({ timeout: p.timeout, force: true });
|
|
5659
5667
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
5660
5668
|
} else if (actionName === "fill") {
|
|
5661
|
-
if (actionValue === void 0) return
|
|
5669
|
+
if (actionValue === void 0) return fail8("find fill requires a value");
|
|
5662
5670
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
5663
5671
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
5664
5672
|
} else if (actionName === "type") {
|
|
5665
|
-
if (actionValue === void 0) return
|
|
5673
|
+
if (actionValue === void 0) return fail8("find type requires a value");
|
|
5666
5674
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
5667
5675
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
5668
5676
|
} else if (actionName === "select") {
|
|
5669
|
-
if (actionValue === void 0) return
|
|
5677
|
+
if (actionValue === void 0) return fail8("find select requires a value");
|
|
5670
5678
|
await target.selectOption(actionValue);
|
|
5671
5679
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
5672
5680
|
} else if (actionName === "hover") {
|
|
@@ -6672,7 +6680,7 @@ async function guardCheck(commandName) {
|
|
|
6672
6680
|
}
|
|
6673
6681
|
}
|
|
6674
6682
|
function errorResult(message) {
|
|
6675
|
-
return { ...
|
|
6683
|
+
return { ...fail9(message), duration: 0 };
|
|
6676
6684
|
}
|
|
6677
6685
|
function tipsToMessages(tips) {
|
|
6678
6686
|
if (!tips || tips.length === 0) return [];
|
|
@@ -6742,9 +6750,14 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6742
6750
|
const { _target: _u, ...rest } = params;
|
|
6743
6751
|
params = rest;
|
|
6744
6752
|
}
|
|
6753
|
+
const _tabIndex = params._tabIndex;
|
|
6754
|
+
if (_tabIndex !== void 0) {
|
|
6755
|
+
const { _tabIndex: _u, ...rest } = params;
|
|
6756
|
+
params = rest;
|
|
6757
|
+
}
|
|
6745
6758
|
let targetPageOverride = null;
|
|
6746
6759
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6747
|
-
const { findTargetPage } = await import("./browser-
|
|
6760
|
+
const { findTargetPage } = await import("./browser-LW2MDJE4.js");
|
|
6748
6761
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6749
6762
|
if (!targetPageOverride) {
|
|
6750
6763
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -6816,6 +6829,16 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6816
6829
|
cliName: "xbrowser",
|
|
6817
6830
|
tips: new TipCollector2()
|
|
6818
6831
|
};
|
|
6832
|
+
if (_tabIndex !== void 0 && session?.context) {
|
|
6833
|
+
const pages = session.context.pages();
|
|
6834
|
+
if (_tabIndex >= 0 && _tabIndex < pages.length) {
|
|
6835
|
+
const targetPage = pages[_tabIndex];
|
|
6836
|
+
await targetPage.bringToFront().catch(() => {
|
|
6837
|
+
});
|
|
6838
|
+
setActivePage(session, targetPage);
|
|
6839
|
+
ctx.page = targetPage;
|
|
6840
|
+
}
|
|
6841
|
+
}
|
|
6819
6842
|
const start = Date.now();
|
|
6820
6843
|
if (session) {
|
|
6821
6844
|
streamCommandEvent(session.id, {
|
|
@@ -6844,7 +6867,17 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6844
6867
|
if (hooks.length > 0 && session?.page) {
|
|
6845
6868
|
await Promise.all(hooks.map((h) => h.onBeforeCommand?.({ page: session.page, command: commandName, params })));
|
|
6846
6869
|
}
|
|
6847
|
-
|
|
6870
|
+
let raw;
|
|
6871
|
+
const handlerPromise = command.handler(params, ctx);
|
|
6872
|
+
if (extraOpts?.timeout && extraOpts.timeout > 0) {
|
|
6873
|
+
const timeoutMs = extraOpts.timeout;
|
|
6874
|
+
const timeoutPromise = new Promise(
|
|
6875
|
+
(_, reject) => setTimeout(() => reject(new Error(`Command timed out after ${timeoutMs}ms`)), timeoutMs)
|
|
6876
|
+
);
|
|
6877
|
+
raw = await Promise.race([handlerPromise, timeoutPromise]);
|
|
6878
|
+
} else {
|
|
6879
|
+
raw = await handlerPromise;
|
|
6880
|
+
}
|
|
6848
6881
|
const end = Date.now();
|
|
6849
6882
|
const duration = end - start;
|
|
6850
6883
|
let hookOutputs;
|
|
@@ -6948,7 +6981,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6948
6981
|
duration,
|
|
6949
6982
|
timestamp: start
|
|
6950
6983
|
});
|
|
6951
|
-
return { ...
|
|
6984
|
+
return { ...fail9(errorMessage), duration };
|
|
6952
6985
|
} finally {
|
|
6953
6986
|
}
|
|
6954
6987
|
}
|
|
@@ -6989,7 +7022,7 @@ async function executeChain(input, options) {
|
|
|
6989
7022
|
results.push({
|
|
6990
7023
|
command: cmdName,
|
|
6991
7024
|
raw: cmdStr,
|
|
6992
|
-
...
|
|
7025
|
+
...fail9(`Plugin "${cmdName}" requires a sub-command`),
|
|
6993
7026
|
duration: 0
|
|
6994
7027
|
});
|
|
6995
7028
|
if (type === "and") {
|
|
@@ -7008,7 +7041,7 @@ async function executeChain(input, options) {
|
|
|
7008
7041
|
results.push({
|
|
7009
7042
|
command: cmdName,
|
|
7010
7043
|
raw: cmdStr,
|
|
7011
|
-
...
|
|
7044
|
+
...fail9(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
7012
7045
|
duration: 0
|
|
7013
7046
|
});
|
|
7014
7047
|
if (type === "and") {
|
|
@@ -7140,7 +7173,7 @@ async function executeChain(input, options) {
|
|
|
7140
7173
|
results.push({
|
|
7141
7174
|
command: `${cmdName} ${subCommand}`,
|
|
7142
7175
|
raw: cmdStr,
|
|
7143
|
-
...
|
|
7176
|
+
...fail9(errorMessage),
|
|
7144
7177
|
duration: duration2
|
|
7145
7178
|
});
|
|
7146
7179
|
if (type === "and") {
|
package/dist/index.d.ts
CHANGED
|
@@ -737,6 +737,7 @@ declare function setWSServer(server: WSServer | null): void;
|
|
|
737
737
|
declare function executeCommand(commandName: string, params: Record<string, unknown>, sessionName?: string, extraOpts?: {
|
|
738
738
|
cdpEndpoint?: string;
|
|
739
739
|
skipCleanup?: boolean;
|
|
740
|
+
timeout?: number;
|
|
740
741
|
}): Promise<ExecutionResult>;
|
|
741
742
|
/**
|
|
742
743
|
* Execute a chain of browser commands parsed from a string expression.
|