@xbrowser/cli 1.4.4 → 1.4.5
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 +1 -1
- package/dist/{browser-KBUORWR3.js → browser-2OALOLR2.js} +1 -1
- package/dist/{browser-DS24BWJW.js → browser-5CM4GUZU.js} +1 -1
- package/dist/{browser-YKJO3BOQ.js → browser-V3VHXQQF.js} +1 -1
- package/dist/{chunk-CFPPWKVO.js → chunk-NW3WE5JK.js} +19 -13
- package/dist/{chunk-4W54GEMV.js → chunk-SMRIC22G.js} +19 -13
- package/dist/{chunk-X3FKWJV4.js → chunk-Z6GGTJL5.js} +19 -13
- package/dist/cli.js +16 -26
- package/dist/daemon-main.js +11 -5
- package/dist/index.js +15 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# xbrowser
|
|
2
2
|
|
|
3
|
-
> **Browser automation CLI** for web scraping, headless browsing, SEO analysis, and AI agent workflows.
|
|
3
|
+
> **Browser automation CLI** for web scraping, headless browsing, SEO analysis, and AI agent workflows. 51 commands, 70+ plugins. A command-line alternative to Playwright, Puppeteer, and Selenium — **no code required**.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/dyyz1993/xbrowser/actions)
|
|
6
6
|
[](https://codecov.io/gh/dyyz1993/xbrowser)
|
|
@@ -4274,21 +4274,27 @@ async function fetchNoProxy(url) {
|
|
|
4274
4274
|
}
|
|
4275
4275
|
async function resolveCDPEndpoint(raw) {
|
|
4276
4276
|
if (raw === "auto") {
|
|
4277
|
-
const
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4277
|
+
const ports = [9222, 9221, 9223, 9224];
|
|
4278
|
+
for (const port of ports) {
|
|
4279
|
+
try {
|
|
4280
|
+
const httpResp = await fetchNoProxy(`http://localhost:${port}/json/version`);
|
|
4281
|
+
if (httpResp.ok) {
|
|
4282
|
+
const data = await httpResp.json();
|
|
4283
|
+
if (data.webSocketDebuggerUrl) {
|
|
4284
|
+
return data.webSocketDebuggerUrl;
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
} catch {
|
|
4288
|
+
}
|
|
4289
|
+
}
|
|
4290
|
+
throw new Error(
|
|
4291
|
+
`Could not auto-discover CDP endpoint. Tried ports: ${ports.join(", ")}.
|
|
4292
|
+
\u53EF\u80FD\u539F\u56E0\uFF1A\u6CA1\u6709 Chrome \u4EE5 --remote-debugging-port \u542F\u52A8\u3002
|
|
4281
4293
|
\u89E3\u51B3\u65B9\u6CD5\uFF1A
|
|
4282
|
-
1. \
|
|
4283
|
-
2. \
|
|
4294
|
+
1. \u542F\u52A8 Chrome: google-chrome --remote-debugging-port=9222
|
|
4295
|
+
2. \u6216\u7528 cdp-tunnel: npx cdp-tunnel setup
|
|
4284
4296
|
3. \u6216\u6307\u5B9A\u7AEF\u53E3: --cdp <port>`
|
|
4285
|
-
|
|
4286
|
-
}
|
|
4287
|
-
const data = await httpResp.json();
|
|
4288
|
-
if (!data.webSocketDebuggerUrl) {
|
|
4289
|
-
throw new Error("Could not auto-discover CDP endpoint from localhost:9222");
|
|
4290
|
-
}
|
|
4291
|
-
return data.webSocketDebuggerUrl;
|
|
4297
|
+
);
|
|
4292
4298
|
}
|
|
4293
4299
|
if (/^\d+$/.test(raw)) {
|
|
4294
4300
|
const port = raw;
|
|
@@ -1400,21 +1400,27 @@ async function fetchNoProxy(url) {
|
|
|
1400
1400
|
}
|
|
1401
1401
|
async function resolveCDPEndpoint(raw) {
|
|
1402
1402
|
if (raw === "auto") {
|
|
1403
|
-
const
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1403
|
+
const ports = [9222, 9221, 9223, 9224];
|
|
1404
|
+
for (const port of ports) {
|
|
1405
|
+
try {
|
|
1406
|
+
const httpResp = await fetchNoProxy(`http://localhost:${port}/json/version`);
|
|
1407
|
+
if (httpResp.ok) {
|
|
1408
|
+
const data = await httpResp.json();
|
|
1409
|
+
if (data.webSocketDebuggerUrl) {
|
|
1410
|
+
return data.webSocketDebuggerUrl;
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
} catch {
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
throw new Error(
|
|
1417
|
+
`Could not auto-discover CDP endpoint. Tried ports: ${ports.join(", ")}.
|
|
1418
|
+
\u53EF\u80FD\u539F\u56E0\uFF1A\u6CA1\u6709 Chrome \u4EE5 --remote-debugging-port \u542F\u52A8\u3002
|
|
1407
1419
|
\u89E3\u51B3\u65B9\u6CD5\uFF1A
|
|
1408
|
-
1. \
|
|
1409
|
-
2. \
|
|
1420
|
+
1. \u542F\u52A8 Chrome: google-chrome --remote-debugging-port=9222
|
|
1421
|
+
2. \u6216\u7528 cdp-tunnel: npx cdp-tunnel setup
|
|
1410
1422
|
3. \u6216\u6307\u5B9A\u7AEF\u53E3: --cdp <port>`
|
|
1411
|
-
|
|
1412
|
-
}
|
|
1413
|
-
const data = await httpResp.json();
|
|
1414
|
-
if (!data.webSocketDebuggerUrl) {
|
|
1415
|
-
throw new Error("Could not auto-discover CDP endpoint from localhost:9222");
|
|
1416
|
-
}
|
|
1417
|
-
return data.webSocketDebuggerUrl;
|
|
1423
|
+
);
|
|
1418
1424
|
}
|
|
1419
1425
|
if (/^\d+$/.test(raw)) {
|
|
1420
1426
|
const port = raw;
|
|
@@ -35,21 +35,27 @@ async function fetchNoProxy(url) {
|
|
|
35
35
|
}
|
|
36
36
|
async function resolveCDPEndpoint(raw) {
|
|
37
37
|
if (raw === "auto") {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
const ports = [9222, 9221, 9223, 9224];
|
|
39
|
+
for (const port of ports) {
|
|
40
|
+
try {
|
|
41
|
+
const httpResp = await fetchNoProxy(`http://localhost:${port}/json/version`);
|
|
42
|
+
if (httpResp.ok) {
|
|
43
|
+
const data = await httpResp.json();
|
|
44
|
+
if (data.webSocketDebuggerUrl) {
|
|
45
|
+
return data.webSocketDebuggerUrl;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
throw new Error(
|
|
52
|
+
`Could not auto-discover CDP endpoint. Tried ports: ${ports.join(", ")}.
|
|
53
|
+
\u53EF\u80FD\u539F\u56E0\uFF1A\u6CA1\u6709 Chrome \u4EE5 --remote-debugging-port \u542F\u52A8\u3002
|
|
42
54
|
\u89E3\u51B3\u65B9\u6CD5\uFF1A
|
|
43
|
-
1. \
|
|
44
|
-
2. \
|
|
55
|
+
1. \u542F\u52A8 Chrome: google-chrome --remote-debugging-port=9222
|
|
56
|
+
2. \u6216\u7528 cdp-tunnel: npx cdp-tunnel setup
|
|
45
57
|
3. \u6216\u6307\u5B9A\u7AEF\u53E3: --cdp <port>`
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
const data = await httpResp.json();
|
|
49
|
-
if (!data.webSocketDebuggerUrl) {
|
|
50
|
-
throw new Error("Could not auto-discover CDP endpoint from localhost:9222");
|
|
51
|
-
}
|
|
52
|
-
return data.webSocketDebuggerUrl;
|
|
58
|
+
);
|
|
53
59
|
}
|
|
54
60
|
if (/^\d+$/.test(raw)) {
|
|
55
61
|
const port = raw;
|
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-NW3WE5JK.js";
|
|
29
29
|
import "./chunk-TNEN6VQ2.js";
|
|
30
30
|
import {
|
|
31
31
|
forwardCommandLog,
|
|
@@ -397,8 +397,13 @@ var refreshCommand = registerCommand({
|
|
|
397
397
|
scope: "page",
|
|
398
398
|
result: z.object({ url: z.string() }),
|
|
399
399
|
handler: async (_p, ctx) => {
|
|
400
|
-
|
|
401
|
-
|
|
400
|
+
try {
|
|
401
|
+
await ctx.page.reload();
|
|
402
|
+
} catch (err) {
|
|
403
|
+
return fail(`Refresh failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
404
|
+
}
|
|
405
|
+
const url = await ctx.page.evaluate("location.href").catch(() => ctx.page.url());
|
|
406
|
+
return ok({ url });
|
|
402
407
|
}
|
|
403
408
|
});
|
|
404
409
|
var titleCommand = registerCommand({
|
|
@@ -417,7 +422,8 @@ var urlCommand = registerCommand({
|
|
|
417
422
|
scope: "page",
|
|
418
423
|
result: z.object({ url: z.string() }),
|
|
419
424
|
handler: async (_p, ctx) => {
|
|
420
|
-
|
|
425
|
+
const url = await ctx.page.evaluate("location.href").catch(() => ctx.page.url() || "about:blank");
|
|
426
|
+
return ok({ url });
|
|
421
427
|
}
|
|
422
428
|
});
|
|
423
429
|
registerCommand({
|
|
@@ -7077,7 +7083,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7077
7083
|
}
|
|
7078
7084
|
let targetPageOverride = null;
|
|
7079
7085
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7080
|
-
const { findTargetPage } = await import("./browser-
|
|
7086
|
+
const { findTargetPage } = await import("./browser-5CM4GUZU.js");
|
|
7081
7087
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7082
7088
|
if (!targetPageOverride) {
|
|
7083
7089
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -11846,18 +11852,6 @@ function printChainResult(chainResult) {
|
|
|
11846
11852
|
console.error(`Stopped: ${chainResult.stoppedReason}`);
|
|
11847
11853
|
}
|
|
11848
11854
|
}
|
|
11849
|
-
function printChainResultBrief(chainResult) {
|
|
11850
|
-
for (const step of chainResult.steps) {
|
|
11851
|
-
if (step.success) {
|
|
11852
|
-
console.log(`[OK] ${step.raw}`);
|
|
11853
|
-
} else {
|
|
11854
|
-
console.error(`[FAIL] ${step.raw}: ${step.message}`);
|
|
11855
|
-
}
|
|
11856
|
-
}
|
|
11857
|
-
if (chainResult.stoppedReason) {
|
|
11858
|
-
console.error(`Stopped: ${chainResult.stoppedReason}`);
|
|
11859
|
-
}
|
|
11860
|
-
}
|
|
11861
11855
|
|
|
11862
11856
|
// src/server/http-server.ts
|
|
11863
11857
|
import { createServer } from "http";
|
|
@@ -12386,10 +12380,10 @@ function extractSessionNameFromArgv(argv) {
|
|
|
12386
12380
|
async function handleEvalMode(argv) {
|
|
12387
12381
|
const evalCommands = parseEvalFlags(argv);
|
|
12388
12382
|
if (evalCommands.length === 0) return;
|
|
12389
|
-
const chain = evalCommands.join("
|
|
12383
|
+
const chain = evalCommands.join(" ; ");
|
|
12390
12384
|
const cdpEndpoint = extractCdpFromArgv(argv);
|
|
12391
12385
|
const chainResult = await executeChain(chain, { cdpEndpoint });
|
|
12392
|
-
|
|
12386
|
+
printChainResult(chainResult);
|
|
12393
12387
|
if (!chainResult.success) throw new Error("Command failed");
|
|
12394
12388
|
}
|
|
12395
12389
|
async function handleChainInput(input, argv) {
|
|
@@ -12433,12 +12427,8 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12433
12427
|
const possibleCmd = argv[0].substring(0, spaceIdx);
|
|
12434
12428
|
if (/^[a-zA-Z][\w-]*$/.test(possibleCmd)) {
|
|
12435
12429
|
const remainder = argv[0].substring(spaceIdx + 1);
|
|
12436
|
-
|
|
12437
|
-
|
|
12438
|
-
argv = [possibleCmd, ...remainderParts, ...argv.slice(1)];
|
|
12439
|
-
} else {
|
|
12440
|
-
argv = [possibleCmd, remainder, ...argv.slice(1)];
|
|
12441
|
-
}
|
|
12430
|
+
const remainderParts = remainder.split(/\s+/).filter(Boolean);
|
|
12431
|
+
argv = [possibleCmd, ...remainderParts, ...argv.slice(1)];
|
|
12442
12432
|
}
|
|
12443
12433
|
}
|
|
12444
12434
|
} catch (e) {
|
|
@@ -13049,7 +13039,7 @@ async function main() {
|
|
|
13049
13039
|
const command = process.argv[2];
|
|
13050
13040
|
const isLongRunning = command === "preview" || command === "serve";
|
|
13051
13041
|
if (!isLongRunning) {
|
|
13052
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
13042
|
+
const { ensureProcessCanExit } = await import("./browser-5CM4GUZU.js");
|
|
13053
13043
|
await ensureProcessCanExit().catch(() => {
|
|
13054
13044
|
});
|
|
13055
13045
|
process.exit(exitCode);
|
package/dist/daemon-main.js
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
resolveLaunchOpts,
|
|
22
22
|
saveSessionDiskMeta,
|
|
23
23
|
setActivePage
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-SMRIC22G.js";
|
|
25
25
|
import "./chunk-IDJ5NILK.js";
|
|
26
26
|
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import {
|
|
@@ -358,8 +358,13 @@ var refreshCommand = registerCommand({
|
|
|
358
358
|
scope: "page",
|
|
359
359
|
result: z.object({ url: z.string() }),
|
|
360
360
|
handler: async (_p, ctx) => {
|
|
361
|
-
|
|
362
|
-
|
|
361
|
+
try {
|
|
362
|
+
await ctx.page.reload();
|
|
363
|
+
} catch (err) {
|
|
364
|
+
return fail(`Refresh failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
365
|
+
}
|
|
366
|
+
const url = await ctx.page.evaluate("location.href").catch(() => ctx.page.url());
|
|
367
|
+
return ok({ url });
|
|
363
368
|
}
|
|
364
369
|
});
|
|
365
370
|
var titleCommand = registerCommand({
|
|
@@ -378,7 +383,8 @@ var urlCommand = registerCommand({
|
|
|
378
383
|
scope: "page",
|
|
379
384
|
result: z.object({ url: z.string() }),
|
|
380
385
|
handler: async (_p, ctx) => {
|
|
381
|
-
|
|
386
|
+
const url = await ctx.page.evaluate("location.href").catch(() => ctx.page.url() || "about:blank");
|
|
387
|
+
return ok({ url });
|
|
382
388
|
}
|
|
383
389
|
});
|
|
384
390
|
registerCommand({
|
|
@@ -6608,7 +6614,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6608
6614
|
}
|
|
6609
6615
|
let targetPageOverride = null;
|
|
6610
6616
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6611
|
-
const { findTargetPage } = await import("./browser-
|
|
6617
|
+
const { findTargetPage } = await import("./browser-V3VHXQQF.js");
|
|
6612
6618
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6613
6619
|
if (!targetPageOverride) {
|
|
6614
6620
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
package/dist/index.js
CHANGED
|
@@ -81,7 +81,7 @@ import {
|
|
|
81
81
|
resolveLaunchOpts,
|
|
82
82
|
saveSessionDiskMeta,
|
|
83
83
|
setActivePage
|
|
84
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-Z6GGTJL5.js";
|
|
85
85
|
import "./chunk-IDJ5NILK.js";
|
|
86
86
|
import "./chunk-TNEN6VQ2.js";
|
|
87
87
|
import {
|
|
@@ -437,8 +437,13 @@ var refreshCommand = registerCommand({
|
|
|
437
437
|
scope: "page",
|
|
438
438
|
result: z.object({ url: z.string() }),
|
|
439
439
|
handler: async (_p, ctx) => {
|
|
440
|
-
|
|
441
|
-
|
|
440
|
+
try {
|
|
441
|
+
await ctx.page.reload();
|
|
442
|
+
} catch (err) {
|
|
443
|
+
return fail(`Refresh failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
444
|
+
}
|
|
445
|
+
const url = await ctx.page.evaluate("location.href").catch(() => ctx.page.url());
|
|
446
|
+
return ok({ url });
|
|
442
447
|
}
|
|
443
448
|
});
|
|
444
449
|
var titleCommand = registerCommand({
|
|
@@ -457,7 +462,8 @@ var urlCommand = registerCommand({
|
|
|
457
462
|
scope: "page",
|
|
458
463
|
result: z.object({ url: z.string() }),
|
|
459
464
|
handler: async (_p, ctx) => {
|
|
460
|
-
|
|
465
|
+
const url = await ctx.page.evaluate("location.href").catch(() => ctx.page.url() || "about:blank");
|
|
466
|
+
return ok({ url });
|
|
461
467
|
}
|
|
462
468
|
});
|
|
463
469
|
registerCommand({
|
|
@@ -7397,7 +7403,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7397
7403
|
}
|
|
7398
7404
|
let targetPageOverride = null;
|
|
7399
7405
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7400
|
-
const { findTargetPage } = await import("./browser-
|
|
7406
|
+
const { findTargetPage } = await import("./browser-2OALOLR2.js");
|
|
7401
7407
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7402
7408
|
if (!targetPageOverride) {
|
|
7403
7409
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -12186,18 +12192,6 @@ function printChainResult(chainResult) {
|
|
|
12186
12192
|
console.error(`Stopped: ${chainResult.stoppedReason}`);
|
|
12187
12193
|
}
|
|
12188
12194
|
}
|
|
12189
|
-
function printChainResultBrief(chainResult) {
|
|
12190
|
-
for (const step of chainResult.steps) {
|
|
12191
|
-
if (step.success) {
|
|
12192
|
-
console.log(`[OK] ${step.raw}`);
|
|
12193
|
-
} else {
|
|
12194
|
-
console.error(`[FAIL] ${step.raw}: ${step.message}`);
|
|
12195
|
-
}
|
|
12196
|
-
}
|
|
12197
|
-
if (chainResult.stoppedReason) {
|
|
12198
|
-
console.error(`Stopped: ${chainResult.stoppedReason}`);
|
|
12199
|
-
}
|
|
12200
|
-
}
|
|
12201
12195
|
|
|
12202
12196
|
// src/server/http-server.ts
|
|
12203
12197
|
import { createServer } from "http";
|
|
@@ -12726,10 +12720,10 @@ function extractSessionNameFromArgv(argv) {
|
|
|
12726
12720
|
async function handleEvalMode(argv) {
|
|
12727
12721
|
const evalCommands = parseEvalFlags(argv);
|
|
12728
12722
|
if (evalCommands.length === 0) return;
|
|
12729
|
-
const chain = evalCommands.join("
|
|
12723
|
+
const chain = evalCommands.join(" ; ");
|
|
12730
12724
|
const cdpEndpoint = extractCdpFromArgv(argv);
|
|
12731
12725
|
const chainResult = await executeChain(chain, { cdpEndpoint });
|
|
12732
|
-
|
|
12726
|
+
printChainResult(chainResult);
|
|
12733
12727
|
if (!chainResult.success) throw new Error("Command failed");
|
|
12734
12728
|
}
|
|
12735
12729
|
async function handleChainInput(input, argv) {
|
|
@@ -12773,12 +12767,8 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12773
12767
|
const possibleCmd = argv[0].substring(0, spaceIdx);
|
|
12774
12768
|
if (/^[a-zA-Z][\w-]*$/.test(possibleCmd)) {
|
|
12775
12769
|
const remainder = argv[0].substring(spaceIdx + 1);
|
|
12776
|
-
|
|
12777
|
-
|
|
12778
|
-
argv = [possibleCmd, ...remainderParts, ...argv.slice(1)];
|
|
12779
|
-
} else {
|
|
12780
|
-
argv = [possibleCmd, remainder, ...argv.slice(1)];
|
|
12781
|
-
}
|
|
12770
|
+
const remainderParts = remainder.split(/\s+/).filter(Boolean);
|
|
12771
|
+
argv = [possibleCmd, ...remainderParts, ...argv.slice(1)];
|
|
12782
12772
|
}
|
|
12783
12773
|
}
|
|
12784
12774
|
} catch (e) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.5",
|
|
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": {
|