@xbrowser/cli 1.8.6 → 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/cli.js +36 -28
- package/dist/daemon-main.js +36 -28
- package/dist/index.js +36 -28
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -182,7 +182,7 @@ function asZodSchema(value) {
|
|
|
182
182
|
// src/executor.ts
|
|
183
183
|
import {
|
|
184
184
|
ok as ok25,
|
|
185
|
-
fail as
|
|
185
|
+
fail as fail9,
|
|
186
186
|
isCommandResult,
|
|
187
187
|
CompositeStorage as CompositeStorage2,
|
|
188
188
|
TipCollector as TipCollector2,
|
|
@@ -2316,7 +2316,7 @@ var scrapeCommand = registerCommand({
|
|
|
2316
2316
|
scope: "project",
|
|
2317
2317
|
selectorParams: ["selector"],
|
|
2318
2318
|
parameters: z15.object({
|
|
2319
|
-
url: z15.string(),
|
|
2319
|
+
url: z15.string().optional(),
|
|
2320
2320
|
selector: z15.string().optional(),
|
|
2321
2321
|
timeout: z15.number().default(3e4),
|
|
2322
2322
|
format: z15.enum(["markdown", "html", "text"]).default("markdown"),
|
|
@@ -2329,10 +2329,14 @@ var scrapeCommand = registerCommand({
|
|
|
2329
2329
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
2330
2330
|
const maxAttempts = p.retries + 1;
|
|
2331
2331
|
try {
|
|
2332
|
+
const targetUrl = p.url || page.url();
|
|
2333
|
+
if (!targetUrl || targetUrl === "about:blank") {
|
|
2334
|
+
return fail3("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2335
|
+
}
|
|
2332
2336
|
let lastError;
|
|
2333
2337
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2334
2338
|
try {
|
|
2335
|
-
await page.goto(
|
|
2339
|
+
await page.goto(targetUrl, { waitUntil: "commit", timeout: p.timeout });
|
|
2336
2340
|
await page.waitForSelector("body", { timeout: p.timeout }).catch(() => {
|
|
2337
2341
|
});
|
|
2338
2342
|
await page.waitForLoadState("networkidle", Math.min(p.timeout, 8e3)).catch(() => {
|
|
@@ -2393,7 +2397,7 @@ var scrapeCommand = registerCommand({
|
|
|
2393
2397
|
return { url: location.href, title: document.title, navigation, tables, forms: forms.slice(0, 20), links: links.slice(0, 30), mainText };
|
|
2394
2398
|
});
|
|
2395
2399
|
try {
|
|
2396
|
-
persistFromScrape(
|
|
2400
|
+
persistFromScrape(targetUrl, structured);
|
|
2397
2401
|
} catch {
|
|
2398
2402
|
}
|
|
2399
2403
|
if (p.mode === "smart") {
|
|
@@ -2494,7 +2498,7 @@ var scrapeCommand = registerCommand({
|
|
|
2494
2498
|
|
|
2495
2499
|
// src/commands/map.ts
|
|
2496
2500
|
import { z as z16 } from "zod";
|
|
2497
|
-
import { ok as ok16 } from "@dyyz1993/xcli-core";
|
|
2501
|
+
import { ok as ok16, fail as fail4 } from "@dyyz1993/xcli-core";
|
|
2498
2502
|
|
|
2499
2503
|
// src/utils/url.ts
|
|
2500
2504
|
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -2730,7 +2734,7 @@ var mapCommand = registerCommand({
|
|
|
2730
2734
|
description: "Discover all URLs on a website via sitemap and page link extraction",
|
|
2731
2735
|
scope: "project",
|
|
2732
2736
|
parameters: z16.object({
|
|
2733
|
-
url: z16.string(),
|
|
2737
|
+
url: z16.string().optional(),
|
|
2734
2738
|
search: z16.string().optional(),
|
|
2735
2739
|
sitemap: z16.enum(["include", "only"]).optional(),
|
|
2736
2740
|
includeSubdomains: z16.boolean().optional(),
|
|
@@ -2741,7 +2745,11 @@ var mapCommand = registerCommand({
|
|
|
2741
2745
|
handler: async (p, ctx) => {
|
|
2742
2746
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
2743
2747
|
try {
|
|
2744
|
-
const
|
|
2748
|
+
const targetUrl = p.url || page.url();
|
|
2749
|
+
if (!targetUrl || targetUrl === "about:blank") {
|
|
2750
|
+
return fail4("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2751
|
+
}
|
|
2752
|
+
const links = await discoverUrls(page, targetUrl, {
|
|
2745
2753
|
sitemap: p.sitemap,
|
|
2746
2754
|
includeSubdomains: p.includeSubdomains,
|
|
2747
2755
|
allowExternalLinks: p.allowExternalLinks,
|
|
@@ -3584,7 +3592,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
3584
3592
|
|
|
3585
3593
|
// src/commands/network.ts
|
|
3586
3594
|
import { z as z19 } from "zod";
|
|
3587
|
-
import { ok as ok19, fail as
|
|
3595
|
+
import { ok as ok19, fail as fail5 } from "@dyyz1993/xcli-core";
|
|
3588
3596
|
function extractPath2(url) {
|
|
3589
3597
|
try {
|
|
3590
3598
|
const u = new URL(url);
|
|
@@ -3749,7 +3757,7 @@ var networkCommand = registerCommand({
|
|
|
3749
3757
|
};
|
|
3750
3758
|
if (p.listen) {
|
|
3751
3759
|
const page2 = ctx.page;
|
|
3752
|
-
if (!page2) return
|
|
3760
|
+
if (!page2) return fail5("No active page. Use --cdp to connect first.");
|
|
3753
3761
|
const captures = [];
|
|
3754
3762
|
const consoleMessages = [];
|
|
3755
3763
|
const wsCaptures = [];
|
|
@@ -4129,7 +4137,7 @@ var ENGINE_KEY_ENUM = z20.enum(ALL_ENGINE_KEYS);
|
|
|
4129
4137
|
|
|
4130
4138
|
// src/commands/snapshot.ts
|
|
4131
4139
|
import { z as z21 } from "zod";
|
|
4132
|
-
import { ok as ok20, fail as
|
|
4140
|
+
import { ok as ok20, fail as fail6, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
|
|
4133
4141
|
|
|
4134
4142
|
// src/runtime/ref-store.ts
|
|
4135
4143
|
var sessions = /* @__PURE__ */ new Map();
|
|
@@ -5100,7 +5108,7 @@ var snapshotCommand = registerCommand({
|
|
|
5100
5108
|
persistSemantics(url, aria);
|
|
5101
5109
|
return ok20({ url, title, aria, text, dom }, normalizeTips3(tips));
|
|
5102
5110
|
}
|
|
5103
|
-
return
|
|
5111
|
+
return fail6(`Unknown snapshot type: ${p.type}`);
|
|
5104
5112
|
}
|
|
5105
5113
|
});
|
|
5106
5114
|
function persistSemantics(url, aria) {
|
|
@@ -5269,7 +5277,7 @@ var waitForCommand = registerCommand({
|
|
|
5269
5277
|
|
|
5270
5278
|
// src/commands/tab.ts
|
|
5271
5279
|
import { z as z23 } from "zod";
|
|
5272
|
-
import { ok as ok22, fail as
|
|
5280
|
+
import { ok as ok22, fail as fail7 } from "@dyyz1993/xcli-core";
|
|
5273
5281
|
var TabParams = z23.object({
|
|
5274
5282
|
subcommand: z23.enum(["list", "new", "close", "switch"]),
|
|
5275
5283
|
url: z23.string().optional(),
|
|
@@ -5286,7 +5294,7 @@ var tabCommand = registerCommand({
|
|
|
5286
5294
|
}),
|
|
5287
5295
|
handler: async (p, ctx) => {
|
|
5288
5296
|
if (!ctx.browserContext) {
|
|
5289
|
-
return
|
|
5297
|
+
return fail7("No browser context available. Use --cdp to connect to a browser first.");
|
|
5290
5298
|
}
|
|
5291
5299
|
const pages = ctx.browserContext.pages();
|
|
5292
5300
|
switch (p.subcommand) {
|
|
@@ -5299,7 +5307,7 @@ var tabCommand = registerCommand({
|
|
|
5299
5307
|
case "switch":
|
|
5300
5308
|
return handleSwitch(p, pages, ctx);
|
|
5301
5309
|
default:
|
|
5302
|
-
return
|
|
5310
|
+
return fail7(`Unknown subcommand: ${p.subcommand}`);
|
|
5303
5311
|
}
|
|
5304
5312
|
}
|
|
5305
5313
|
});
|
|
@@ -5356,11 +5364,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5356
5364
|
}
|
|
5357
5365
|
async function handleClose(p, pages, ctx) {
|
|
5358
5366
|
if (pages.length <= 1) {
|
|
5359
|
-
return
|
|
5367
|
+
return fail7("Cannot close the last remaining tab");
|
|
5360
5368
|
}
|
|
5361
5369
|
const closeIndex = p.index ?? pages.indexOf(ctx.page);
|
|
5362
5370
|
if (closeIndex < 0 || closeIndex >= pages.length) {
|
|
5363
|
-
return
|
|
5371
|
+
return fail7(`Invalid tab index: ${closeIndex}. Valid range: 0-${pages.length - 1}`);
|
|
5364
5372
|
}
|
|
5365
5373
|
const pageToClose = pages[closeIndex];
|
|
5366
5374
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5383,10 +5391,10 @@ async function handleClose(p, pages, ctx) {
|
|
|
5383
5391
|
}
|
|
5384
5392
|
async function handleSwitch(p, pages, ctx) {
|
|
5385
5393
|
if (p.index === void 0) {
|
|
5386
|
-
return
|
|
5394
|
+
return fail7("Parameter --index is required for switch subcommand");
|
|
5387
5395
|
}
|
|
5388
5396
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5389
|
-
return
|
|
5397
|
+
return fail7(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5390
5398
|
}
|
|
5391
5399
|
const targetPage = pages[p.index];
|
|
5392
5400
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -5638,7 +5646,7 @@ registerCommandDefinition("addinitscript", ["script"]);
|
|
|
5638
5646
|
|
|
5639
5647
|
// src/commands/find.ts
|
|
5640
5648
|
import { z as z25 } from "zod";
|
|
5641
|
-
import { ok as ok24, fail as
|
|
5649
|
+
import { ok as ok24, fail as fail8, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
5642
5650
|
var actionSchema2 = z25.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
5643
5651
|
var findCommand = registerCommand({
|
|
5644
5652
|
name: "find",
|
|
@@ -5679,7 +5687,7 @@ var findCommand = registerCommand({
|
|
|
5679
5687
|
});
|
|
5680
5688
|
const count = await locator.count();
|
|
5681
5689
|
if (count === 0) {
|
|
5682
|
-
return
|
|
5690
|
+
return fail8(`No element found with ${p.strategy}="${p.value}"`);
|
|
5683
5691
|
}
|
|
5684
5692
|
const tips = [];
|
|
5685
5693
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -5691,15 +5699,15 @@ var findCommand = registerCommand({
|
|
|
5691
5699
|
await target.click({ timeout: p.timeout, force: true });
|
|
5692
5700
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
5693
5701
|
} else if (actionName === "fill") {
|
|
5694
|
-
if (actionValue === void 0) return
|
|
5702
|
+
if (actionValue === void 0) return fail8("find fill requires a value");
|
|
5695
5703
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
5696
5704
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
5697
5705
|
} else if (actionName === "type") {
|
|
5698
|
-
if (actionValue === void 0) return
|
|
5706
|
+
if (actionValue === void 0) return fail8("find type requires a value");
|
|
5699
5707
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
5700
5708
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
5701
5709
|
} else if (actionName === "select") {
|
|
5702
|
-
if (actionValue === void 0) return
|
|
5710
|
+
if (actionValue === void 0) return fail8("find select requires a value");
|
|
5703
5711
|
await target.selectOption(actionValue);
|
|
5704
5712
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
5705
5713
|
} else if (actionName === "hover") {
|
|
@@ -7135,7 +7143,7 @@ async function guardCheck(commandName) {
|
|
|
7135
7143
|
}
|
|
7136
7144
|
}
|
|
7137
7145
|
function errorResult(message) {
|
|
7138
|
-
return { ...
|
|
7146
|
+
return { ...fail9(message), duration: 0 };
|
|
7139
7147
|
}
|
|
7140
7148
|
function tipsToMessages(tips) {
|
|
7141
7149
|
if (!tips || tips.length === 0) return [];
|
|
@@ -7436,7 +7444,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7436
7444
|
duration,
|
|
7437
7445
|
timestamp: start
|
|
7438
7446
|
});
|
|
7439
|
-
return { ...
|
|
7447
|
+
return { ...fail9(errorMessage), duration };
|
|
7440
7448
|
} finally {
|
|
7441
7449
|
}
|
|
7442
7450
|
}
|
|
@@ -7477,7 +7485,7 @@ async function executeChain(input, options) {
|
|
|
7477
7485
|
results.push({
|
|
7478
7486
|
command: cmdName,
|
|
7479
7487
|
raw: cmdStr,
|
|
7480
|
-
...
|
|
7488
|
+
...fail9(`Plugin "${cmdName}" requires a sub-command`),
|
|
7481
7489
|
duration: 0
|
|
7482
7490
|
});
|
|
7483
7491
|
if (type === "and") {
|
|
@@ -7496,7 +7504,7 @@ async function executeChain(input, options) {
|
|
|
7496
7504
|
results.push({
|
|
7497
7505
|
command: cmdName,
|
|
7498
7506
|
raw: cmdStr,
|
|
7499
|
-
...
|
|
7507
|
+
...fail9(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
7500
7508
|
duration: 0
|
|
7501
7509
|
});
|
|
7502
7510
|
if (type === "and") {
|
|
@@ -7628,7 +7636,7 @@ async function executeChain(input, options) {
|
|
|
7628
7636
|
results.push({
|
|
7629
7637
|
command: `${cmdName} ${subCommand}`,
|
|
7630
7638
|
raw: cmdStr,
|
|
7631
|
-
...
|
|
7639
|
+
...fail9(errorMessage),
|
|
7632
7640
|
duration: duration2
|
|
7633
7641
|
});
|
|
7634
7642
|
if (type === "and") {
|
package/dist/daemon-main.js
CHANGED
|
@@ -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 [];
|
|
@@ -6973,7 +6981,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6973
6981
|
duration,
|
|
6974
6982
|
timestamp: start
|
|
6975
6983
|
});
|
|
6976
|
-
return { ...
|
|
6984
|
+
return { ...fail9(errorMessage), duration };
|
|
6977
6985
|
} finally {
|
|
6978
6986
|
}
|
|
6979
6987
|
}
|
|
@@ -7014,7 +7022,7 @@ async function executeChain(input, options) {
|
|
|
7014
7022
|
results.push({
|
|
7015
7023
|
command: cmdName,
|
|
7016
7024
|
raw: cmdStr,
|
|
7017
|
-
...
|
|
7025
|
+
...fail9(`Plugin "${cmdName}" requires a sub-command`),
|
|
7018
7026
|
duration: 0
|
|
7019
7027
|
});
|
|
7020
7028
|
if (type === "and") {
|
|
@@ -7033,7 +7041,7 @@ async function executeChain(input, options) {
|
|
|
7033
7041
|
results.push({
|
|
7034
7042
|
command: cmdName,
|
|
7035
7043
|
raw: cmdStr,
|
|
7036
|
-
...
|
|
7044
|
+
...fail9(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
7037
7045
|
duration: 0
|
|
7038
7046
|
});
|
|
7039
7047
|
if (type === "and") {
|
|
@@ -7165,7 +7173,7 @@ async function executeChain(input, options) {
|
|
|
7165
7173
|
results.push({
|
|
7166
7174
|
command: `${cmdName} ${subCommand}`,
|
|
7167
7175
|
raw: cmdStr,
|
|
7168
|
-
...
|
|
7176
|
+
...fail9(errorMessage),
|
|
7169
7177
|
duration: duration2
|
|
7170
7178
|
});
|
|
7171
7179
|
if (type === "and") {
|
package/dist/index.js
CHANGED
|
@@ -109,7 +109,7 @@ import {
|
|
|
109
109
|
// src/executor.ts
|
|
110
110
|
import {
|
|
111
111
|
ok as ok25,
|
|
112
|
-
fail as
|
|
112
|
+
fail as fail9,
|
|
113
113
|
isCommandResult,
|
|
114
114
|
CompositeStorage as CompositeStorage2,
|
|
115
115
|
TipCollector as TipCollector2,
|
|
@@ -2356,7 +2356,7 @@ var scrapeCommand = registerCommand({
|
|
|
2356
2356
|
scope: "project",
|
|
2357
2357
|
selectorParams: ["selector"],
|
|
2358
2358
|
parameters: z15.object({
|
|
2359
|
-
url: z15.string(),
|
|
2359
|
+
url: z15.string().optional(),
|
|
2360
2360
|
selector: z15.string().optional(),
|
|
2361
2361
|
timeout: z15.number().default(3e4),
|
|
2362
2362
|
format: z15.enum(["markdown", "html", "text"]).default("markdown"),
|
|
@@ -2369,10 +2369,14 @@ var scrapeCommand = registerCommand({
|
|
|
2369
2369
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
2370
2370
|
const maxAttempts = p.retries + 1;
|
|
2371
2371
|
try {
|
|
2372
|
+
const targetUrl = p.url || page.url();
|
|
2373
|
+
if (!targetUrl || targetUrl === "about:blank") {
|
|
2374
|
+
return fail3("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2375
|
+
}
|
|
2372
2376
|
let lastError;
|
|
2373
2377
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2374
2378
|
try {
|
|
2375
|
-
await page.goto(
|
|
2379
|
+
await page.goto(targetUrl, { waitUntil: "commit", timeout: p.timeout });
|
|
2376
2380
|
await page.waitForSelector("body", { timeout: p.timeout }).catch(() => {
|
|
2377
2381
|
});
|
|
2378
2382
|
await page.waitForLoadState("networkidle", Math.min(p.timeout, 8e3)).catch(() => {
|
|
@@ -2433,7 +2437,7 @@ var scrapeCommand = registerCommand({
|
|
|
2433
2437
|
return { url: location.href, title: document.title, navigation, tables, forms: forms.slice(0, 20), links: links.slice(0, 30), mainText };
|
|
2434
2438
|
});
|
|
2435
2439
|
try {
|
|
2436
|
-
persistFromScrape(
|
|
2440
|
+
persistFromScrape(targetUrl, structured);
|
|
2437
2441
|
} catch {
|
|
2438
2442
|
}
|
|
2439
2443
|
if (p.mode === "smart") {
|
|
@@ -2534,7 +2538,7 @@ var scrapeCommand = registerCommand({
|
|
|
2534
2538
|
|
|
2535
2539
|
// src/commands/map.ts
|
|
2536
2540
|
import { z as z16 } from "zod";
|
|
2537
|
-
import { ok as ok16 } from "@dyyz1993/xcli-core";
|
|
2541
|
+
import { ok as ok16, fail as fail4 } from "@dyyz1993/xcli-core";
|
|
2538
2542
|
|
|
2539
2543
|
// src/utils/url.ts
|
|
2540
2544
|
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -2770,7 +2774,7 @@ var mapCommand = registerCommand({
|
|
|
2770
2774
|
description: "Discover all URLs on a website via sitemap and page link extraction",
|
|
2771
2775
|
scope: "project",
|
|
2772
2776
|
parameters: z16.object({
|
|
2773
|
-
url: z16.string(),
|
|
2777
|
+
url: z16.string().optional(),
|
|
2774
2778
|
search: z16.string().optional(),
|
|
2775
2779
|
sitemap: z16.enum(["include", "only"]).optional(),
|
|
2776
2780
|
includeSubdomains: z16.boolean().optional(),
|
|
@@ -2781,7 +2785,11 @@ var mapCommand = registerCommand({
|
|
|
2781
2785
|
handler: async (p, ctx) => {
|
|
2782
2786
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
2783
2787
|
try {
|
|
2784
|
-
const
|
|
2788
|
+
const targetUrl = p.url || page.url();
|
|
2789
|
+
if (!targetUrl || targetUrl === "about:blank") {
|
|
2790
|
+
return fail4("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2791
|
+
}
|
|
2792
|
+
const links = await discoverUrls(page, targetUrl, {
|
|
2785
2793
|
sitemap: p.sitemap,
|
|
2786
2794
|
includeSubdomains: p.includeSubdomains,
|
|
2787
2795
|
allowExternalLinks: p.allowExternalLinks,
|
|
@@ -3624,7 +3632,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
3624
3632
|
|
|
3625
3633
|
// src/commands/network.ts
|
|
3626
3634
|
import { z as z19 } from "zod";
|
|
3627
|
-
import { ok as ok19, fail as
|
|
3635
|
+
import { ok as ok19, fail as fail5 } from "@dyyz1993/xcli-core";
|
|
3628
3636
|
function extractPath2(url) {
|
|
3629
3637
|
try {
|
|
3630
3638
|
const u = new URL(url);
|
|
@@ -3789,7 +3797,7 @@ var networkCommand = registerCommand({
|
|
|
3789
3797
|
};
|
|
3790
3798
|
if (p.listen) {
|
|
3791
3799
|
const page2 = ctx.page;
|
|
3792
|
-
if (!page2) return
|
|
3800
|
+
if (!page2) return fail5("No active page. Use --cdp to connect first.");
|
|
3793
3801
|
const captures = [];
|
|
3794
3802
|
const consoleMessages = [];
|
|
3795
3803
|
const wsCaptures = [];
|
|
@@ -4446,7 +4454,7 @@ function parseMarkdownResults(rawText) {
|
|
|
4446
4454
|
|
|
4447
4455
|
// src/commands/snapshot.ts
|
|
4448
4456
|
import { z as z21 } from "zod";
|
|
4449
|
-
import { ok as ok20, fail as
|
|
4457
|
+
import { ok as ok20, fail as fail6, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
|
|
4450
4458
|
|
|
4451
4459
|
// src/runtime/ref-store.ts
|
|
4452
4460
|
var sessions = /* @__PURE__ */ new Map();
|
|
@@ -5417,7 +5425,7 @@ var snapshotCommand = registerCommand({
|
|
|
5417
5425
|
persistSemantics(url, aria);
|
|
5418
5426
|
return ok20({ url, title, aria, text, dom }, normalizeTips3(tips));
|
|
5419
5427
|
}
|
|
5420
|
-
return
|
|
5428
|
+
return fail6(`Unknown snapshot type: ${p.type}`);
|
|
5421
5429
|
}
|
|
5422
5430
|
});
|
|
5423
5431
|
function persistSemantics(url, aria) {
|
|
@@ -5586,7 +5594,7 @@ var waitForCommand = registerCommand({
|
|
|
5586
5594
|
|
|
5587
5595
|
// src/commands/tab.ts
|
|
5588
5596
|
import { z as z23 } from "zod";
|
|
5589
|
-
import { ok as ok22, fail as
|
|
5597
|
+
import { ok as ok22, fail as fail7 } from "@dyyz1993/xcli-core";
|
|
5590
5598
|
var TabParams = z23.object({
|
|
5591
5599
|
subcommand: z23.enum(["list", "new", "close", "switch"]),
|
|
5592
5600
|
url: z23.string().optional(),
|
|
@@ -5603,7 +5611,7 @@ var tabCommand = registerCommand({
|
|
|
5603
5611
|
}),
|
|
5604
5612
|
handler: async (p, ctx) => {
|
|
5605
5613
|
if (!ctx.browserContext) {
|
|
5606
|
-
return
|
|
5614
|
+
return fail7("No browser context available. Use --cdp to connect to a browser first.");
|
|
5607
5615
|
}
|
|
5608
5616
|
const pages = ctx.browserContext.pages();
|
|
5609
5617
|
switch (p.subcommand) {
|
|
@@ -5616,7 +5624,7 @@ var tabCommand = registerCommand({
|
|
|
5616
5624
|
case "switch":
|
|
5617
5625
|
return handleSwitch(p, pages, ctx);
|
|
5618
5626
|
default:
|
|
5619
|
-
return
|
|
5627
|
+
return fail7(`Unknown subcommand: ${p.subcommand}`);
|
|
5620
5628
|
}
|
|
5621
5629
|
}
|
|
5622
5630
|
});
|
|
@@ -5673,11 +5681,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5673
5681
|
}
|
|
5674
5682
|
async function handleClose(p, pages, ctx) {
|
|
5675
5683
|
if (pages.length <= 1) {
|
|
5676
|
-
return
|
|
5684
|
+
return fail7("Cannot close the last remaining tab");
|
|
5677
5685
|
}
|
|
5678
5686
|
const closeIndex = p.index ?? pages.indexOf(ctx.page);
|
|
5679
5687
|
if (closeIndex < 0 || closeIndex >= pages.length) {
|
|
5680
|
-
return
|
|
5688
|
+
return fail7(`Invalid tab index: ${closeIndex}. Valid range: 0-${pages.length - 1}`);
|
|
5681
5689
|
}
|
|
5682
5690
|
const pageToClose = pages[closeIndex];
|
|
5683
5691
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5700,10 +5708,10 @@ async function handleClose(p, pages, ctx) {
|
|
|
5700
5708
|
}
|
|
5701
5709
|
async function handleSwitch(p, pages, ctx) {
|
|
5702
5710
|
if (p.index === void 0) {
|
|
5703
|
-
return
|
|
5711
|
+
return fail7("Parameter --index is required for switch subcommand");
|
|
5704
5712
|
}
|
|
5705
5713
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5706
|
-
return
|
|
5714
|
+
return fail7(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5707
5715
|
}
|
|
5708
5716
|
const targetPage = pages[p.index];
|
|
5709
5717
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -5955,7 +5963,7 @@ registerCommandDefinition("addinitscript", ["script"]);
|
|
|
5955
5963
|
|
|
5956
5964
|
// src/commands/find.ts
|
|
5957
5965
|
import { z as z25 } from "zod";
|
|
5958
|
-
import { ok as ok24, fail as
|
|
5966
|
+
import { ok as ok24, fail as fail8, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
5959
5967
|
var actionSchema2 = z25.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
5960
5968
|
var findCommand = registerCommand({
|
|
5961
5969
|
name: "find",
|
|
@@ -5996,7 +6004,7 @@ var findCommand = registerCommand({
|
|
|
5996
6004
|
});
|
|
5997
6005
|
const count = await locator.count();
|
|
5998
6006
|
if (count === 0) {
|
|
5999
|
-
return
|
|
6007
|
+
return fail8(`No element found with ${p.strategy}="${p.value}"`);
|
|
6000
6008
|
}
|
|
6001
6009
|
const tips = [];
|
|
6002
6010
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6008,15 +6016,15 @@ var findCommand = registerCommand({
|
|
|
6008
6016
|
await target.click({ timeout: p.timeout, force: true });
|
|
6009
6017
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6010
6018
|
} else if (actionName === "fill") {
|
|
6011
|
-
if (actionValue === void 0) return
|
|
6019
|
+
if (actionValue === void 0) return fail8("find fill requires a value");
|
|
6012
6020
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6013
6021
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6014
6022
|
} else if (actionName === "type") {
|
|
6015
|
-
if (actionValue === void 0) return
|
|
6023
|
+
if (actionValue === void 0) return fail8("find type requires a value");
|
|
6016
6024
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6017
6025
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6018
6026
|
} else if (actionName === "select") {
|
|
6019
|
-
if (actionValue === void 0) return
|
|
6027
|
+
if (actionValue === void 0) return fail8("find select requires a value");
|
|
6020
6028
|
await target.selectOption(actionValue);
|
|
6021
6029
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6022
6030
|
} else if (actionName === "hover") {
|
|
@@ -7452,7 +7460,7 @@ async function guardCheck(commandName) {
|
|
|
7452
7460
|
}
|
|
7453
7461
|
}
|
|
7454
7462
|
function errorResult(message) {
|
|
7455
|
-
return { ...
|
|
7463
|
+
return { ...fail9(message), duration: 0 };
|
|
7456
7464
|
}
|
|
7457
7465
|
function tipsToMessages(tips) {
|
|
7458
7466
|
if (!tips || tips.length === 0) return [];
|
|
@@ -7756,7 +7764,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7756
7764
|
duration,
|
|
7757
7765
|
timestamp: start
|
|
7758
7766
|
});
|
|
7759
|
-
return { ...
|
|
7767
|
+
return { ...fail9(errorMessage), duration };
|
|
7760
7768
|
} finally {
|
|
7761
7769
|
}
|
|
7762
7770
|
}
|
|
@@ -7797,7 +7805,7 @@ async function executeChain(input, options) {
|
|
|
7797
7805
|
results.push({
|
|
7798
7806
|
command: cmdName,
|
|
7799
7807
|
raw: cmdStr,
|
|
7800
|
-
...
|
|
7808
|
+
...fail9(`Plugin "${cmdName}" requires a sub-command`),
|
|
7801
7809
|
duration: 0
|
|
7802
7810
|
});
|
|
7803
7811
|
if (type === "and") {
|
|
@@ -7816,7 +7824,7 @@ async function executeChain(input, options) {
|
|
|
7816
7824
|
results.push({
|
|
7817
7825
|
command: cmdName,
|
|
7818
7826
|
raw: cmdStr,
|
|
7819
|
-
...
|
|
7827
|
+
...fail9(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
7820
7828
|
duration: 0
|
|
7821
7829
|
});
|
|
7822
7830
|
if (type === "and") {
|
|
@@ -7948,7 +7956,7 @@ async function executeChain(input, options) {
|
|
|
7948
7956
|
results.push({
|
|
7949
7957
|
command: `${cmdName} ${subCommand}`,
|
|
7950
7958
|
raw: cmdStr,
|
|
7951
|
-
...
|
|
7959
|
+
...fail9(errorMessage),
|
|
7952
7960
|
duration: duration2
|
|
7953
7961
|
});
|
|
7954
7962
|
if (type === "and") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.7",
|
|
4
4
|
"description": "Browser automation CLI for web scraping, headless browsing, SEO analysis, and AI agent workflows. A command-line alternative to Playwright, Puppeteer, and Selenium.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|