@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 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. 50 commands, 20+ plugins. A command-line alternative to Playwright, Puppeteer, and Selenium — **no code required**.
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
  [![CI Status](https://github.com/dyyz1993/xbrowser/workflows/CI/badge.svg)](https://github.com/dyyz1993/xbrowser/actions)
6
6
  [![codecov](https://codecov.io/gh/dyyz1993/xbrowser/branch/master/graph/badge.svg)](https://codecov.io/gh/dyyz1993/xbrowser)
@@ -20,7 +20,7 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-X3FKWJV4.js";
23
+ } from "./chunk-Z6GGTJL5.js";
24
24
  import "./chunk-IDJ5NILK.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
@@ -20,7 +20,7 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-CFPPWKVO.js";
23
+ } from "./chunk-NW3WE5JK.js";
24
24
  import "./chunk-TNEN6VQ2.js";
25
25
  import "./chunk-GDKLH7ZY.js";
26
26
  import "./chunk-KFQGP6VL.js";
@@ -20,7 +20,7 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-4W54GEMV.js";
23
+ } from "./chunk-SMRIC22G.js";
24
24
  import "./chunk-IDJ5NILK.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
@@ -4274,21 +4274,27 @@ async function fetchNoProxy(url) {
4274
4274
  }
4275
4275
  async function resolveCDPEndpoint(raw) {
4276
4276
  if (raw === "auto") {
4277
- const httpResp = await fetchNoProxy("http://localhost:9222/json/version");
4278
- if (!httpResp.ok) {
4279
- throw new Error(
4280
- `CDP port 9222 responded with ${httpResp.status} ${httpResp.statusText}. \u53EF\u80FD\u539F\u56E0\uFF1A9222 \u88AB\u50F5\u6B7B\u7684 Chrome \u5360\u7528\uFF0C\u6216\u6CA1\u6709 Chrome \u4EE5 --remote-debugging-port \u542F\u52A8\u3002
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. \u6740\u6389\u6B8B\u7559 Chrome: pkill -f "remote-debugging-port"
4283
- 2. \u91CD\u542F Chrome: npx cdp-tunnel setup
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 httpResp = await fetchNoProxy("http://localhost:9222/json/version");
1404
- if (!httpResp.ok) {
1405
- throw new Error(
1406
- `CDP port 9222 responded with ${httpResp.status} ${httpResp.statusText}. \u53EF\u80FD\u539F\u56E0\uFF1A9222 \u88AB\u50F5\u6B7B\u7684 Chrome \u5360\u7528\uFF0C\u6216\u6CA1\u6709 Chrome \u4EE5 --remote-debugging-port \u542F\u52A8\u3002
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. \u6740\u6389\u6B8B\u7559 Chrome: pkill -f "remote-debugging-port"
1409
- 2. \u91CD\u542F Chrome: npx cdp-tunnel setup
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 httpResp = await fetchNoProxy("http://localhost:9222/json/version");
39
- if (!httpResp.ok) {
40
- throw new Error(
41
- `CDP port 9222 responded with ${httpResp.status} ${httpResp.statusText}. \u53EF\u80FD\u539F\u56E0\uFF1A9222 \u88AB\u50F5\u6B7B\u7684 Chrome \u5360\u7528\uFF0C\u6216\u6CA1\u6709 Chrome \u4EE5 --remote-debugging-port \u542F\u52A8\u3002
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. \u6740\u6389\u6B8B\u7559 Chrome: pkill -f "remote-debugging-port"
44
- 2. \u91CD\u542F Chrome: npx cdp-tunnel setup
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-CFPPWKVO.js";
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
- await ctx.page.reload();
401
- return ok({ url: ctx.page.url() });
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
- return ok({ url: ctx.page.url() || "about:blank" });
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-DS24BWJW.js");
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
- printChainResultBrief(chainResult);
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
- if (remainder.includes("--")) {
12437
- const remainderParts = remainder.split(/\s+/).filter(Boolean);
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-DS24BWJW.js");
13042
+ const { ensureProcessCanExit } = await import("./browser-5CM4GUZU.js");
13053
13043
  await ensureProcessCanExit().catch(() => {
13054
13044
  });
13055
13045
  process.exit(exitCode);
@@ -21,7 +21,7 @@ import {
21
21
  resolveLaunchOpts,
22
22
  saveSessionDiskMeta,
23
23
  setActivePage
24
- } from "./chunk-4W54GEMV.js";
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
- await ctx.page.reload();
362
- return ok({ url: ctx.page.url() });
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
- return ok({ url: ctx.page.url() || "about:blank" });
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-YKJO3BOQ.js");
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-X3FKWJV4.js";
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
- await ctx.page.reload();
441
- return ok({ url: ctx.page.url() });
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
- return ok({ url: ctx.page.url() || "about:blank" });
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-KBUORWR3.js");
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
- printChainResultBrief(chainResult);
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
- if (remainder.includes("--")) {
12777
- const remainderParts = remainder.split(/\s+/).filter(Boolean);
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.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": {