@xbrowser/cli 1.4.4 → 1.4.6

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,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-4W54GEMV.js";
24
- import "./chunk-IDJ5NILK.js";
23
+ } from "./chunk-NQSFETTQ.js";
24
+ import "./chunk-2RHJEYWU.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-KFQGP6VL.js";
@@ -20,7 +20,7 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-CFPPWKVO.js";
23
+ } from "./chunk-RGS6ECTH.js";
24
24
  import "./chunk-TNEN6VQ2.js";
25
25
  import "./chunk-GDKLH7ZY.js";
26
26
  import "./chunk-KFQGP6VL.js";
@@ -20,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-X3FKWJV4.js";
24
- import "./chunk-IDJ5NILK.js";
23
+ } from "./chunk-LYVU6SD3.js";
24
+ import "./chunk-2RHJEYWU.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-ABXMBNQ6.js";
@@ -1165,23 +1165,17 @@ var XBPageImpl = class _XBPageImpl {
1165
1165
  headers: () => headers
1166
1166
  };
1167
1167
  }
1168
- async goBack(opts = {}) {
1168
+ async goBack(_opts = {}) {
1169
+ const prevUrl = await this.evaluate("location.href").catch(() => "");
1169
1170
  await this.evaluate("() => history.back()");
1170
- await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 5e3).catch(() => {
1171
- });
1172
- try {
1173
- this._url = await this.evaluate("location.href");
1174
- } catch {
1175
- }
1171
+ await this.waitForTimeout(2e3);
1172
+ this._url = await this.evaluate("location.href").catch(() => prevUrl);
1176
1173
  }
1177
- async goForward(opts = {}) {
1174
+ async goForward(_opts = {}) {
1175
+ const prevUrl = await this.evaluate("location.href").catch(() => "");
1178
1176
  await this.evaluate("() => history.forward()");
1179
- await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 5e3).catch(() => {
1180
- });
1181
- try {
1182
- this._url = await this.evaluate("location.href");
1183
- } catch {
1184
- }
1177
+ await this.waitForTimeout(2e3);
1178
+ this._url = await this.evaluate("location.href").catch(() => prevUrl);
1185
1179
  }
1186
1180
  async reload(opts = {}) {
1187
1181
  this._loadState = { loadFired: false, domContentFired: false, networkIdle: false };
@@ -14,7 +14,7 @@ import {
14
14
  scrollIntoView,
15
15
  waitForActionable,
16
16
  waitForNetworkIdle
17
- } from "./chunk-IDJ5NILK.js";
17
+ } from "./chunk-2RHJEYWU.js";
18
18
  import {
19
19
  connectToCDP,
20
20
  findChrome,
@@ -1164,23 +1164,17 @@ var XBPageImpl = class _XBPageImpl {
1164
1164
  headers: () => headers
1165
1165
  };
1166
1166
  }
1167
- async goBack(opts = {}) {
1167
+ async goBack(_opts = {}) {
1168
+ const prevUrl = await this.evaluate("location.href").catch(() => "");
1168
1169
  await this.evaluate("() => history.back()");
1169
- await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 5e3).catch(() => {
1170
- });
1171
- try {
1172
- this._url = await this.evaluate("location.href");
1173
- } catch {
1174
- }
1170
+ await this.waitForTimeout(2e3);
1171
+ this._url = await this.evaluate("location.href").catch(() => prevUrl);
1175
1172
  }
1176
- async goForward(opts = {}) {
1173
+ async goForward(_opts = {}) {
1174
+ const prevUrl = await this.evaluate("location.href").catch(() => "");
1177
1175
  await this.evaluate("() => history.forward()");
1178
- await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 5e3).catch(() => {
1179
- });
1180
- try {
1181
- this._url = await this.evaluate("location.href");
1182
- } catch {
1183
- }
1176
+ await this.waitForTimeout(2e3);
1177
+ this._url = await this.evaluate("location.href").catch(() => prevUrl);
1184
1178
  }
1185
1179
  async reload(opts = {}) {
1186
1180
  this._loadState = { loadFired: false, domContentFired: false, networkIdle: false };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-IDJ5NILK.js";
3
+ } from "./chunk-2RHJEYWU.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -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;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-IDJ5NILK.js";
3
+ } from "./chunk-2RHJEYWU.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -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;
@@ -1170,23 +1170,17 @@ var XBPageImpl = class _XBPageImpl {
1170
1170
  headers: () => headers
1171
1171
  };
1172
1172
  }
1173
- async goBack(opts = {}) {
1173
+ async goBack(_opts = {}) {
1174
+ const prevUrl = await this.evaluate("location.href").catch(() => "");
1174
1175
  await this.evaluate("() => history.back()");
1175
- await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 5e3).catch(() => {
1176
- });
1177
- try {
1178
- this._url = await this.evaluate("location.href");
1179
- } catch {
1180
- }
1176
+ await this.waitForTimeout(2e3);
1177
+ this._url = await this.evaluate("location.href").catch(() => prevUrl);
1181
1178
  }
1182
- async goForward(opts = {}) {
1179
+ async goForward(_opts = {}) {
1180
+ const prevUrl = await this.evaluate("location.href").catch(() => "");
1183
1181
  await this.evaluate("() => history.forward()");
1184
- await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 5e3).catch(() => {
1185
- });
1186
- try {
1187
- this._url = await this.evaluate("location.href");
1188
- } catch {
1189
- }
1182
+ await this.waitForTimeout(2e3);
1183
+ this._url = await this.evaluate("location.href").catch(() => prevUrl);
1190
1184
  }
1191
1185
  async reload(opts = {}) {
1192
1186
  this._loadState = { loadFired: false, domContentFired: false, networkIdle: false };
@@ -4274,21 +4268,27 @@ async function fetchNoProxy(url) {
4274
4268
  }
4275
4269
  async function resolveCDPEndpoint(raw) {
4276
4270
  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
4271
+ const ports = [9222, 9221, 9223, 9224];
4272
+ for (const port of ports) {
4273
+ try {
4274
+ const httpResp = await fetchNoProxy(`http://localhost:${port}/json/version`);
4275
+ if (httpResp.ok) {
4276
+ const data = await httpResp.json();
4277
+ if (data.webSocketDebuggerUrl) {
4278
+ return data.webSocketDebuggerUrl;
4279
+ }
4280
+ }
4281
+ } catch {
4282
+ }
4283
+ }
4284
+ throw new Error(
4285
+ `Could not auto-discover CDP endpoint. Tried ports: ${ports.join(", ")}.
4286
+ \u53EF\u80FD\u539F\u56E0\uFF1A\u6CA1\u6709 Chrome \u4EE5 --remote-debugging-port \u542F\u52A8\u3002
4281
4287
  \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
4288
+ 1. \u542F\u52A8 Chrome: google-chrome --remote-debugging-port=9222
4289
+ 2. \u6216\u7528 cdp-tunnel: npx cdp-tunnel setup
4284
4290
  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;
4291
+ );
4292
4292
  }
4293
4293
  if (/^\d+$/.test(raw)) {
4294
4294
  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-RGS6ECTH.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({
@@ -5460,12 +5466,12 @@ registerCommandDefinition("health", []);
5460
5466
  registerCommandDefinition("scrape", ["url"]);
5461
5467
  registerCommandDefinition("structure", []);
5462
5468
  registerCommandDefinition("get-cookies", []);
5463
- registerCommandDefinition("set-cookie", []);
5469
+ registerCommandDefinition("set-cookie", ["name", "value"]);
5464
5470
  registerCommandDefinition("clear-cookies", []);
5465
5471
  registerCommandDefinition("get-local-storage", []);
5466
- registerCommandDefinition("set-local-storage", []);
5472
+ registerCommandDefinition("set-local-storage", ["key", "value"]);
5467
5473
  registerCommandDefinition("clear-local-storage", []);
5468
- registerCommandDefinition("set-viewport", []);
5474
+ registerCommandDefinition("set-viewport", ["width", "height"]);
5469
5475
  registerCommandDefinition("frames", []);
5470
5476
  registerCommandDefinition("frame", ["selector"]);
5471
5477
  registerCommandDefinition("actions", ["url"]);
@@ -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-SOML2EWR.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.`);
@@ -10034,6 +10040,24 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
10034
10040
  timeout: args[0] ? Number(args[0]) : options.timeout ? Number(options.timeout) : 1e3
10035
10041
  };
10036
10042
  break;
10043
+ case "set-cookie":
10044
+ cmdName = "set-cookie";
10045
+ params = {
10046
+ name: options.name || args[0],
10047
+ value: (options.value || options.v) ?? args[1],
10048
+ domain: options.domain,
10049
+ path: options.path,
10050
+ httpOnly: options.httpOnly ? Boolean(options.httpOnly) : void 0,
10051
+ secure: options.secure ? Boolean(options.secure) : void 0
10052
+ };
10053
+ break;
10054
+ case "set-local-storage":
10055
+ cmdName = "set-local-storage";
10056
+ params = {
10057
+ key: options.key || args[0],
10058
+ value: (options.value || options.v) ?? args[1]
10059
+ };
10060
+ break;
10037
10061
  default:
10038
10062
  cmdName = command;
10039
10063
  params = { ...options };
@@ -11846,18 +11870,6 @@ function printChainResult(chainResult) {
11846
11870
  console.error(`Stopped: ${chainResult.stoppedReason}`);
11847
11871
  }
11848
11872
  }
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
11873
 
11862
11874
  // src/server/http-server.ts
11863
11875
  import { createServer } from "http";
@@ -12386,10 +12398,10 @@ function extractSessionNameFromArgv(argv) {
12386
12398
  async function handleEvalMode(argv) {
12387
12399
  const evalCommands = parseEvalFlags(argv);
12388
12400
  if (evalCommands.length === 0) return;
12389
- const chain = evalCommands.join(" && ");
12401
+ const chain = evalCommands.join(" ; ");
12390
12402
  const cdpEndpoint = extractCdpFromArgv(argv);
12391
12403
  const chainResult = await executeChain(chain, { cdpEndpoint });
12392
- printChainResultBrief(chainResult);
12404
+ printChainResult(chainResult);
12393
12405
  if (!chainResult.success) throw new Error("Command failed");
12394
12406
  }
12395
12407
  async function handleChainInput(input, argv) {
@@ -12433,12 +12445,8 @@ async function routeCommand(argvIn, stdinCommands) {
12433
12445
  const possibleCmd = argv[0].substring(0, spaceIdx);
12434
12446
  if (/^[a-zA-Z][\w-]*$/.test(possibleCmd)) {
12435
12447
  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
- }
12448
+ const remainderParts = remainder.split(/\s+/).filter(Boolean);
12449
+ argv = [possibleCmd, ...remainderParts, ...argv.slice(1)];
12442
12450
  }
12443
12451
  }
12444
12452
  } catch (e) {
@@ -13049,7 +13057,7 @@ async function main() {
13049
13057
  const command = process.argv[2];
13050
13058
  const isLongRunning = command === "preview" || command === "serve";
13051
13059
  if (!isLongRunning) {
13052
- const { ensureProcessCanExit } = await import("./browser-DS24BWJW.js");
13060
+ const { ensureProcessCanExit } = await import("./browser-SOML2EWR.js");
13053
13061
  await ensureProcessCanExit().catch(() => {
13054
13062
  });
13055
13063
  process.exit(exitCode);
@@ -21,8 +21,8 @@ import {
21
21
  resolveLaunchOpts,
22
22
  saveSessionDiskMeta,
23
23
  setActivePage
24
- } from "./chunk-4W54GEMV.js";
25
- import "./chunk-IDJ5NILK.js";
24
+ } from "./chunk-NQSFETTQ.js";
25
+ import "./chunk-2RHJEYWU.js";
26
26
  import "./chunk-TNEN6VQ2.js";
27
27
  import {
28
28
  getPluginLoader
@@ -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({
@@ -5421,12 +5427,12 @@ registerCommandDefinition("health", []);
5421
5427
  registerCommandDefinition("scrape", ["url"]);
5422
5428
  registerCommandDefinition("structure", []);
5423
5429
  registerCommandDefinition("get-cookies", []);
5424
- registerCommandDefinition("set-cookie", []);
5430
+ registerCommandDefinition("set-cookie", ["name", "value"]);
5425
5431
  registerCommandDefinition("clear-cookies", []);
5426
5432
  registerCommandDefinition("get-local-storage", []);
5427
- registerCommandDefinition("set-local-storage", []);
5433
+ registerCommandDefinition("set-local-storage", ["key", "value"]);
5428
5434
  registerCommandDefinition("clear-local-storage", []);
5429
- registerCommandDefinition("set-viewport", []);
5435
+ registerCommandDefinition("set-viewport", ["width", "height"]);
5430
5436
  registerCommandDefinition("frames", []);
5431
5437
  registerCommandDefinition("frame", ["selector"]);
5432
5438
  registerCommandDefinition("actions", ["url"]);
@@ -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-2OK26HBS.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.`);
@@ -8324,7 +8330,7 @@ function createRPCHandler() {
8324
8330
  const isNewFormat = Array.isArray(parsed.actions);
8325
8331
  if (isNewFormat) {
8326
8332
  try {
8327
- const { SessionReplayer } = await import("./session-replayer-F4ORJMCL.js");
8333
+ const { SessionReplayer } = await import("./session-replayer-YIGRIIDD.js");
8328
8334
  const replayer = new SessionReplayer({
8329
8335
  page: session.page,
8330
8336
  stepDelay: slowMo * 500,
package/dist/index.js CHANGED
@@ -81,8 +81,8 @@ import {
81
81
  resolveLaunchOpts,
82
82
  saveSessionDiskMeta,
83
83
  setActivePage
84
- } from "./chunk-X3FKWJV4.js";
85
- import "./chunk-IDJ5NILK.js";
84
+ } from "./chunk-LYVU6SD3.js";
85
+ import "./chunk-2RHJEYWU.js";
86
86
  import "./chunk-TNEN6VQ2.js";
87
87
  import {
88
88
  errMsg
@@ -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({
@@ -5777,12 +5783,12 @@ registerCommandDefinition("health", []);
5777
5783
  registerCommandDefinition("scrape", ["url"]);
5778
5784
  registerCommandDefinition("structure", []);
5779
5785
  registerCommandDefinition("get-cookies", []);
5780
- registerCommandDefinition("set-cookie", []);
5786
+ registerCommandDefinition("set-cookie", ["name", "value"]);
5781
5787
  registerCommandDefinition("clear-cookies", []);
5782
5788
  registerCommandDefinition("get-local-storage", []);
5783
- registerCommandDefinition("set-local-storage", []);
5789
+ registerCommandDefinition("set-local-storage", ["key", "value"]);
5784
5790
  registerCommandDefinition("clear-local-storage", []);
5785
- registerCommandDefinition("set-viewport", []);
5791
+ registerCommandDefinition("set-viewport", ["width", "height"]);
5786
5792
  registerCommandDefinition("frames", []);
5787
5793
  registerCommandDefinition("frame", ["selector"]);
5788
5794
  registerCommandDefinition("actions", ["url"]);
@@ -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-ZTTS2SVT.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.`);
@@ -10374,6 +10380,24 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
10374
10380
  timeout: args[0] ? Number(args[0]) : options.timeout ? Number(options.timeout) : 1e3
10375
10381
  };
10376
10382
  break;
10383
+ case "set-cookie":
10384
+ cmdName = "set-cookie";
10385
+ params = {
10386
+ name: options.name || args[0],
10387
+ value: (options.value || options.v) ?? args[1],
10388
+ domain: options.domain,
10389
+ path: options.path,
10390
+ httpOnly: options.httpOnly ? Boolean(options.httpOnly) : void 0,
10391
+ secure: options.secure ? Boolean(options.secure) : void 0
10392
+ };
10393
+ break;
10394
+ case "set-local-storage":
10395
+ cmdName = "set-local-storage";
10396
+ params = {
10397
+ key: options.key || args[0],
10398
+ value: (options.value || options.v) ?? args[1]
10399
+ };
10400
+ break;
10377
10401
  default:
10378
10402
  cmdName = command;
10379
10403
  params = { ...options };
@@ -12186,18 +12210,6 @@ function printChainResult(chainResult) {
12186
12210
  console.error(`Stopped: ${chainResult.stoppedReason}`);
12187
12211
  }
12188
12212
  }
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
12213
 
12202
12214
  // src/server/http-server.ts
12203
12215
  import { createServer } from "http";
@@ -12726,10 +12738,10 @@ function extractSessionNameFromArgv(argv) {
12726
12738
  async function handleEvalMode(argv) {
12727
12739
  const evalCommands = parseEvalFlags(argv);
12728
12740
  if (evalCommands.length === 0) return;
12729
- const chain = evalCommands.join(" && ");
12741
+ const chain = evalCommands.join(" ; ");
12730
12742
  const cdpEndpoint = extractCdpFromArgv(argv);
12731
12743
  const chainResult = await executeChain(chain, { cdpEndpoint });
12732
- printChainResultBrief(chainResult);
12744
+ printChainResult(chainResult);
12733
12745
  if (!chainResult.success) throw new Error("Command failed");
12734
12746
  }
12735
12747
  async function handleChainInput(input, argv) {
@@ -12773,12 +12785,8 @@ async function routeCommand(argvIn, stdinCommands) {
12773
12785
  const possibleCmd = argv[0].substring(0, spaceIdx);
12774
12786
  if (/^[a-zA-Z][\w-]*$/.test(possibleCmd)) {
12775
12787
  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
- }
12788
+ const remainderParts = remainder.split(/\s+/).filter(Boolean);
12789
+ argv = [possibleCmd, ...remainderParts, ...argv.slice(1)];
12782
12790
  }
12783
12791
  }
12784
12792
  } catch (e) {
@@ -16176,7 +16184,7 @@ var DataCollector = class {
16176
16184
  return results;
16177
16185
  }
16178
16186
  async createBrowserContext() {
16179
- const { launch } = await import("./cdp-driver-VRXHK6P6.js");
16187
+ const { launch } = await import("./cdp-driver-UGO45HXR.js");
16180
16188
  const { browser } = await launch({
16181
16189
  headless: true,
16182
16190
  args: ["--no-sandbox", "--disable-setuid-sandbox"]
@@ -31,7 +31,7 @@ var SessionReplayer = class {
31
31
  if (this.opts.page) {
32
32
  this.page = this.opts.page;
33
33
  } else if (this.opts.cdpUrl) {
34
- const { launch } = await import("./cdp-driver-VRXHK6P6.js");
34
+ const { launch } = await import("./cdp-driver-UGO45HXR.js");
35
35
  const { browser } = await launch({ cdpEndpoint: this.opts.cdpUrl });
36
36
  let contexts = browser.contexts();
37
37
  for (let i = 0; i < 10 && contexts.length === 0; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xbrowser/cli",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
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": {