@xbrowser/cli 1.2.2 → 1.3.1

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/index.js CHANGED
@@ -49,11 +49,11 @@ import {
49
49
  extractAndSave,
50
50
  extractRecording,
51
51
  printExtractSummary
52
- } from "./chunk-L53IDAWK.js";
52
+ } from "./chunk-MJFYLKGL.js";
53
53
  import {
54
54
  filterRecording,
55
55
  parseExcludeTypes
56
- } from "./chunk-AT4PHAJY.js";
56
+ } from "./chunk-GJAV3QGG.js";
57
57
  import {
58
58
  SessionRecorder
59
59
  } from "./chunk-ACFE6PKF.js";
@@ -81,8 +81,8 @@ import {
81
81
  resolveLaunchOpts,
82
82
  saveSessionDiskMeta,
83
83
  setActivePage
84
- } from "./chunk-6V57JME6.js";
85
- import "./chunk-QFROODUU.js";
84
+ } from "./chunk-UZQYMXR5.js";
85
+ import "./chunk-N4PIGZDG.js";
86
86
  import "./chunk-TNEN6VQ2.js";
87
87
  import {
88
88
  errMsg
@@ -114,7 +114,7 @@ var version = pkg.version;
114
114
  // src/executor.ts
115
115
  import {
116
116
  ok as ok25,
117
- fail as fail7,
117
+ fail as fail8,
118
118
  isCommandResult,
119
119
  CompositeStorage as CompositeStorage2,
120
120
  TipCollector as TipCollector2,
@@ -300,7 +300,7 @@ function createStubContext(pluginName) {
300
300
 
301
301
  // src/commands/navigation.ts
302
302
  import { z } from "zod";
303
- import { ok } from "@dyyz1993/xcli-core";
303
+ import { ok, fail } from "@dyyz1993/xcli-core";
304
304
 
305
305
  // src/commands/command-registry.ts
306
306
  var registry = /* @__PURE__ */ new Map();
@@ -392,13 +392,19 @@ var gotoCommand = registerCommand({
392
392
  if (/^[\w-]+(\.[\w-]+)+/.test(url) || url.startsWith("localhost")) {
393
393
  url = "https://" + url;
394
394
  } else {
395
- throw new Error(`Invalid URL: "${url}". Expected http(s)://, file://, about:, data:, or a domain name.`);
395
+ return fail(`Invalid URL: "${url}". Expected http(s)://, file://, about:, data:, or a domain name.`);
396
396
  }
397
397
  }
398
- const response = await ctx.page.goto(url, {
399
- waitUntil: p.waitUntil || "domcontentloaded",
400
- ...p.timeout ? { timeout: p.timeout } : {}
401
- });
398
+ let response;
399
+ try {
400
+ response = await ctx.page.goto(url, {
401
+ waitUntil: p.waitUntil || "domcontentloaded",
402
+ ...p.timeout ? { timeout: p.timeout } : {}
403
+ });
404
+ } catch (err) {
405
+ const msg = err instanceof Error ? err.message : String(err);
406
+ return fail(`Navigation failed: ${msg}`);
407
+ }
402
408
  const ssr = await detectSsr(ctx.page);
403
409
  return ok({ url, status: response?.status(), ...ssr ? { ssr } : {} });
404
410
  }
@@ -713,6 +719,22 @@ var checkCommand = registerCommand({
713
719
  return ok2({ selector: p.selector });
714
720
  }
715
721
  });
722
+ var uncheckCommand = registerCommand({
723
+ name: "uncheck",
724
+ description: "Uncheck checkbox or radio",
725
+ scope: "element",
726
+ selectorParams: ["selector"],
727
+ parameters: z2.object({
728
+ selector: z2.string()
729
+ }),
730
+ result: z2.object({
731
+ selector: z2.string()
732
+ }),
733
+ handler: async (p, ctx) => {
734
+ await ctx.page.uncheck(p.selector, { timeout: 1e4 });
735
+ return ok2({ selector: p.selector });
736
+ }
737
+ });
716
738
  var hoverCommand = registerCommand({
717
739
  name: "hover",
718
740
  description: "Hover over element",
@@ -1254,7 +1276,7 @@ var setViewportCommand = registerCommand({
1254
1276
 
1255
1277
  // src/commands/frame.ts
1256
1278
  import { z as z12 } from "zod";
1257
- import { ok as ok12, fail } from "@dyyz1993/xcli-core";
1279
+ import { ok as ok12, fail as fail2 } from "@dyyz1993/xcli-core";
1258
1280
  var framesCommand = registerCommand({
1259
1281
  name: "frames",
1260
1282
  description: "List all frames in the current page",
@@ -1267,7 +1289,9 @@ var framesCommand = registerCommand({
1267
1289
  }))
1268
1290
  }),
1269
1291
  handler: async (_p, ctx) => {
1270
- const frameList = ctx.page.frames().map((frame, index) => ({
1292
+ const discover = ctx.page.discoverFrames;
1293
+ const rawFrames = discover ? await discover.call(ctx.page) : ctx.page.frames();
1294
+ const frameList = rawFrames.map((frame, index) => ({
1271
1295
  index,
1272
1296
  name: frame.name(),
1273
1297
  url: frame.url()
@@ -1289,17 +1313,18 @@ var frameCommand = registerCommand({
1289
1313
  error: z12.string().optional()
1290
1314
  }),
1291
1315
  handler: async (p, ctx) => {
1292
- const allFrames = ctx.page.frames();
1316
+ const discover = ctx.page.discoverFrames;
1317
+ const rawFrames = discover ? await discover.call(ctx.page) : ctx.page.frames();
1293
1318
  let targetFrame;
1294
1319
  if (p.index !== void 0) {
1295
- targetFrame = allFrames[p.index];
1320
+ targetFrame = rawFrames[p.index];
1296
1321
  } else if (p.name !== void 0) {
1297
- targetFrame = allFrames.find((f) => f.name() === p.name);
1322
+ targetFrame = rawFrames.find((f) => f.name() === p.name);
1298
1323
  } else {
1299
- return fail("Must provide index or name");
1324
+ return fail2("Must provide index or name");
1300
1325
  }
1301
1326
  if (!targetFrame) {
1302
- return fail("Frame not found");
1327
+ return fail2("Frame not found");
1303
1328
  }
1304
1329
  return ok12({
1305
1330
  name: targetFrame.name(),
@@ -1945,7 +1970,7 @@ var actionsCommand = registerCommand({
1945
1970
 
1946
1971
  // src/commands/scrape.ts
1947
1972
  import { z as z15 } from "zod";
1948
- import { ok as ok15, fail as fail2 } from "@dyyz1993/xcli-core";
1973
+ import { ok as ok15, fail as fail3 } from "@dyyz1993/xcli-core";
1949
1974
 
1950
1975
  // src/lib/html-to-markdown.ts
1951
1976
  import * as cheerio from "cheerio";
@@ -2461,7 +2486,7 @@ var scrapeCommand = registerCommand({
2461
2486
  }
2462
2487
  }
2463
2488
  }
2464
- return fail2(`Scrape failed after ${maxAttempts} attempt(s): ${lastError?.message ?? "unknown error"}`);
2489
+ return fail3(`Scrape failed after ${maxAttempts} attempt(s): ${lastError?.message ?? "unknown error"}`);
2465
2490
  } finally {
2466
2491
  await closeEphemeralContext(context);
2467
2492
  }
@@ -3525,7 +3550,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
3525
3550
 
3526
3551
  // src/commands/network.ts
3527
3552
  import { z as z19 } from "zod";
3528
- import { ok as ok19, fail as fail3 } from "@dyyz1993/xcli-core";
3553
+ import { ok as ok19, fail as fail4 } from "@dyyz1993/xcli-core";
3529
3554
  function extractPath2(url) {
3530
3555
  try {
3531
3556
  const u = new URL(url);
@@ -3690,7 +3715,7 @@ var networkCommand = registerCommand({
3690
3715
  };
3691
3716
  if (p.listen) {
3692
3717
  const page2 = ctx.page;
3693
- if (!page2) return fail3("No active page. Use --cdp to connect first.");
3718
+ if (!page2) return fail4("No active page. Use --cdp to connect first.");
3694
3719
  const captures = [];
3695
3720
  const consoleMessages = [];
3696
3721
  const wsCaptures = [];
@@ -4347,7 +4372,7 @@ function parseMarkdownResults(rawText) {
4347
4372
 
4348
4373
  // src/commands/snapshot.ts
4349
4374
  import { z as z21 } from "zod";
4350
- import { ok as ok20, fail as fail4, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
4375
+ import { ok as ok20, fail as fail5, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
4351
4376
 
4352
4377
  // src/runtime/ref-store.ts
4353
4378
  var sessions = /* @__PURE__ */ new Map();
@@ -5303,7 +5328,7 @@ var snapshotCommand = registerCommand({
5303
5328
  persistSemantics(url, aria);
5304
5329
  return ok20({ url, title, aria, text, dom }, normalizeTips3(tips));
5305
5330
  }
5306
- return fail4(`Unknown snapshot type: ${p.type}`);
5331
+ return fail5(`Unknown snapshot type: ${p.type}`);
5307
5332
  }
5308
5333
  });
5309
5334
  function persistSemantics(url, aria) {
@@ -5472,7 +5497,7 @@ var waitForCommand = registerCommand({
5472
5497
 
5473
5498
  // src/commands/tab.ts
5474
5499
  import { z as z23 } from "zod";
5475
- import { ok as ok22, fail as fail5 } from "@dyyz1993/xcli-core";
5500
+ import { ok as ok22, fail as fail6 } from "@dyyz1993/xcli-core";
5476
5501
  var TabParams = z23.object({
5477
5502
  subcommand: z23.enum(["list", "new", "close", "switch"]),
5478
5503
  url: z23.string().optional(),
@@ -5499,7 +5524,7 @@ var tabCommand = registerCommand({
5499
5524
  case "switch":
5500
5525
  return handleSwitch(p, pages, ctx);
5501
5526
  default:
5502
- return fail5(`Unknown subcommand: ${p.subcommand}`);
5527
+ return fail6(`Unknown subcommand: ${p.subcommand}`);
5503
5528
  }
5504
5529
  }
5505
5530
  });
@@ -5556,11 +5581,11 @@ async function handleNew(p, _pages, ctx) {
5556
5581
  }
5557
5582
  async function handleClose(p, pages, ctx) {
5558
5583
  if (pages.length <= 1) {
5559
- return fail5("Cannot close the last remaining tab");
5584
+ return fail6("Cannot close the last remaining tab");
5560
5585
  }
5561
5586
  const closeIndex = p.index ?? pages.indexOf(ctx.page);
5562
5587
  if (closeIndex < 0 || closeIndex >= pages.length) {
5563
- return fail5(`Invalid tab index: ${closeIndex}. Valid range: 0-${pages.length - 1}`);
5588
+ return fail6(`Invalid tab index: ${closeIndex}. Valid range: 0-${pages.length - 1}`);
5564
5589
  }
5565
5590
  const pageToClose = pages[closeIndex];
5566
5591
  const isActivePage = pageToClose === ctx.page;
@@ -5583,10 +5608,10 @@ async function handleClose(p, pages, ctx) {
5583
5608
  }
5584
5609
  async function handleSwitch(p, pages, ctx) {
5585
5610
  if (p.index === void 0) {
5586
- return fail5("Parameter --index is required for switch subcommand");
5611
+ return fail6("Parameter --index is required for switch subcommand");
5587
5612
  }
5588
5613
  if (p.index < 0 || p.index >= pages.length) {
5589
- return fail5(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
5614
+ return fail6(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
5590
5615
  }
5591
5616
  const targetPage = pages[p.index];
5592
5617
  await targetPage.bringToFront().catch(() => {
@@ -5832,7 +5857,7 @@ registerCommandDefinition("addinitscript", ["script"]);
5832
5857
 
5833
5858
  // src/commands/find.ts
5834
5859
  import { z as z25 } from "zod";
5835
- import { ok as ok24, fail as fail6, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
5860
+ import { ok as ok24, fail as fail7, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
5836
5861
  var actionSchema2 = z25.enum(["click", "fill", "type", "select", "hover", "check"]);
5837
5862
  var findCommand = registerCommand({
5838
5863
  name: "find",
@@ -5873,7 +5898,7 @@ var findCommand = registerCommand({
5873
5898
  });
5874
5899
  const count = await locator.count();
5875
5900
  if (count === 0) {
5876
- return fail6(`No element found with ${p.strategy}="${p.value}"`);
5901
+ return fail7(`No element found with ${p.strategy}="${p.value}"`);
5877
5902
  }
5878
5903
  const tips = [];
5879
5904
  const target = selectTarget(locator, p.strategy);
@@ -5885,15 +5910,15 @@ var findCommand = registerCommand({
5885
5910
  await target.click({ timeout: p.timeout, force: true });
5886
5911
  return okWithTips({ matched: count, selector, action: "click" }, tips);
5887
5912
  } else if (actionName === "fill") {
5888
- if (actionValue === void 0) return fail6("find fill requires a value");
5913
+ if (actionValue === void 0) return fail7("find fill requires a value");
5889
5914
  await target.fill(actionValue, { timeout: p.timeout, force: true });
5890
5915
  return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
5891
5916
  } else if (actionName === "type") {
5892
- if (actionValue === void 0) return fail6("find type requires a value");
5917
+ if (actionValue === void 0) return fail7("find type requires a value");
5893
5918
  await target.type(actionValue, { delay: 10, timeout: p.timeout });
5894
5919
  return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
5895
5920
  } else if (actionName === "select") {
5896
- if (actionValue === void 0) return fail6("find select requires a value");
5921
+ if (actionValue === void 0) return fail7("find select requires a value");
5897
5922
  await target.selectOption(actionValue);
5898
5923
  return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
5899
5924
  } else if (actionName === "hover") {
@@ -6648,8 +6673,10 @@ var XBrowserPluginLoader = class {
6648
6673
  const instance = await this.loadPlugin(indexPath, entry.name);
6649
6674
  loaded.push(instance);
6650
6675
  } catch (err) {
6651
- if (process.env.XBROWSER_DEBUG) {
6652
- console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${err instanceof Error ? err.message : String(err)}`);
6676
+ const errMsg2 = err instanceof Error ? err.message : String(err);
6677
+ console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${errMsg2}`);
6678
+ if (errMsg2.includes("Cannot find module") && errMsg2.includes("shared/")) {
6679
+ console.warn(` \u{1F4A1} This plugin needs shared/ dependencies. Try: xbrowser plugin install shared`);
6653
6680
  }
6654
6681
  }
6655
6682
  }
@@ -7315,7 +7342,7 @@ async function guardCheck(commandName) {
7315
7342
  }
7316
7343
  }
7317
7344
  function errorResult(message) {
7318
- return { ...fail7(message), duration: 0 };
7345
+ return { ...fail8(message), duration: 0 };
7319
7346
  }
7320
7347
  function tipsToMessages(tips) {
7321
7348
  if (!tips || tips.length === 0) return [];
@@ -7351,7 +7378,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7351
7378
  }
7352
7379
  let targetPageOverride = null;
7353
7380
  if (_target && extraOpts?.cdpEndpoint) {
7354
- const { findTargetPage } = await import("./browser-JP2LFPR2.js");
7381
+ const { findTargetPage } = await import("./browser-WMQRPYXX.js");
7355
7382
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7356
7383
  if (!targetPageOverride) {
7357
7384
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -7555,7 +7582,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7555
7582
  duration,
7556
7583
  timestamp: start
7557
7584
  });
7558
- return { ...fail7(errorMessage), duration };
7585
+ return { ...fail8(errorMessage), duration };
7559
7586
  } finally {
7560
7587
  }
7561
7588
  }
@@ -7596,7 +7623,7 @@ async function executeChain(input, options) {
7596
7623
  results.push({
7597
7624
  command: cmdName,
7598
7625
  raw: cmdStr,
7599
- ...fail7(`Plugin "${cmdName}" requires a sub-command`),
7626
+ ...fail8(`Plugin "${cmdName}" requires a sub-command`),
7600
7627
  duration: 0
7601
7628
  });
7602
7629
  if (type === "and") {
@@ -7615,7 +7642,7 @@ async function executeChain(input, options) {
7615
7642
  results.push({
7616
7643
  command: cmdName,
7617
7644
  raw: cmdStr,
7618
- ...fail7(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
7645
+ ...fail8(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
7619
7646
  duration: 0
7620
7647
  });
7621
7648
  if (type === "and") {
@@ -7747,7 +7774,7 @@ async function executeChain(input, options) {
7747
7774
  results.push({
7748
7775
  command: `${cmdName} ${subCommand}`,
7749
7776
  raw: cmdStr,
7750
- ...fail7(errorMessage),
7777
+ ...fail8(errorMessage),
7751
7778
  duration: duration2
7752
7779
  });
7753
7780
  if (type === "and") {
@@ -7819,7 +7846,7 @@ async function executeChain(input, options) {
7819
7846
  }
7820
7847
  }
7821
7848
  function isChainInput(input) {
7822
- return /\s&&\s|\s;\s|\s,\s|\s\+\s|\s->\s/.test(input);
7849
+ return /\s&&\s|\|\|\s|\s;\s|\s,\s|\s\+\s|\s->\s/.test(input);
7823
7850
  }
7824
7851
 
7825
7852
  // src/context.ts
@@ -8069,9 +8096,12 @@ import {
8069
8096
  existsSync as existsSync10,
8070
8097
  readdirSync as readdirSync2,
8071
8098
  mkdirSync as mkdirSync8,
8072
- rmSync as rmSync6
8099
+ rmSync as rmSync6,
8100
+ copyFileSync,
8101
+ cpSync as cpSync6,
8102
+ readFileSync as readFileSync8
8073
8103
  } from "fs";
8074
- import { resolve as resolve8, basename as basename2 } from "path";
8104
+ import { resolve as resolve8, basename as basename2, dirname as dirname3 } from "path";
8075
8105
  import { homedir as homedir7 } from "os";
8076
8106
 
8077
8107
  // src/plugin/install-sources/local.ts
@@ -8564,28 +8594,103 @@ var PluginInstaller = class {
8564
8594
  switch (type) {
8565
8595
  case "local":
8566
8596
  return await installFromLocal(source, name, targetDir).then((r) => {
8597
+ this.fixSharedDeps(targetDir);
8567
8598
  ensurePluginDependencies(this.pluginsDir);
8568
8599
  return r;
8569
8600
  });
8570
8601
  case "npm":
8571
8602
  return await installFromNpm(resolvedSource, name, targetDir).then((r) => {
8603
+ this.fixSharedDeps(targetDir);
8572
8604
  ensurePluginDependencies(this.pluginsDir);
8573
8605
  return r;
8574
8606
  });
8575
8607
  case "git":
8576
8608
  return await installFromGit(source, name, targetDir).then((r) => {
8609
+ this.fixSharedDeps(targetDir);
8577
8610
  ensurePluginDependencies(this.pluginsDir);
8578
8611
  return r;
8579
8612
  });
8580
8613
  case "url":
8581
8614
  return await installFromUrl(source, name, targetDir).then((r) => {
8615
+ this.fixSharedDeps(targetDir);
8582
8616
  ensurePluginDependencies(this.pluginsDir);
8583
8617
  return r;
8584
8618
  });
8585
8619
  }
8586
8620
  }
8621
+ /**
8622
+ * Fix missing `../shared/` dependencies after installation.
8623
+ *
8624
+ * Some marketplace/npm packages import from `../shared/` (e.g. ssr-detect.js,
8625
+ * ai-chat-base.ts) but the `shared/` directory is not included in the package.
8626
+ * This method scans the installed plugin's index.ts for such imports and
8627
+ * copies the missing files from the local repository's `.xcli/plugins/shared/`
8628
+ * directory (if available).
8629
+ */
8630
+ fixSharedDeps(pluginDir) {
8631
+ const indexPath = resolve8(pluginDir, "index.ts");
8632
+ if (!existsSync10(indexPath)) return;
8633
+ let content;
8634
+ try {
8635
+ content = readFileSync8(indexPath, "utf8");
8636
+ } catch {
8637
+ return;
8638
+ }
8639
+ const sharedImportRegex = /from\s+['"]\.\.\/shared\/([^'"]+)['"]/g;
8640
+ const missingFiles = [];
8641
+ let match;
8642
+ while ((match = sharedImportRegex.exec(content)) !== null) {
8643
+ missingFiles.push(match[1]);
8644
+ }
8645
+ if (missingFiles.length === 0) return;
8646
+ const sharedDir = resolve8(pluginDir, "..", "shared");
8647
+ const toCopy = [];
8648
+ for (const file of missingFiles) {
8649
+ const targetPath = resolve8(sharedDir, file);
8650
+ if (!existsSync10(targetPath)) {
8651
+ toCopy.push(file);
8652
+ }
8653
+ }
8654
+ if (toCopy.length === 0) return;
8655
+ const repoSharedDirs = [
8656
+ resolve8(process.cwd(), ".xcli/plugins/shared"),
8657
+ resolve8(homedir7(), ".xbrowser/plugins/shared")
8658
+ ];
8659
+ let sourceSharedDir = null;
8660
+ for (const dir of repoSharedDirs) {
8661
+ if (existsSync10(dir)) {
8662
+ sourceSharedDir = dir;
8663
+ break;
8664
+ }
8665
+ }
8666
+ if (!sourceSharedDir) {
8667
+ console.warn(`\u26A0\uFE0F Plugin "${basename2(pluginDir)}" imports shared files but they are missing: ${toCopy.join(", ")}`);
8668
+ console.warn(` To fix: install the "shared" plugin or copy .xcli/plugins/shared/ to ~/.xbrowser/plugins/shared/`);
8669
+ return;
8670
+ }
8671
+ mkdirSync8(sharedDir, { recursive: true });
8672
+ for (const file of toCopy) {
8673
+ const src = resolve8(sourceSharedDir, file);
8674
+ const dst = resolve8(sharedDir, file);
8675
+ if (existsSync10(src)) {
8676
+ try {
8677
+ cpSync6(dirname3(src), dirname3(dst), { recursive: true });
8678
+ console.log(`\u2705 Copied shared/${file} for plugin "${basename2(pluginDir)}"`);
8679
+ } catch {
8680
+ try {
8681
+ copyFileSync(src, dst);
8682
+ console.log(`\u2705 Copied shared/${file} for plugin "${basename2(pluginDir)}"`);
8683
+ } catch {
8684
+ console.warn(`\u26A0\uFE0F Could not copy shared/${file}`);
8685
+ }
8686
+ }
8687
+ }
8688
+ }
8689
+ }
8587
8690
  async installFromMarketplace(slug, options) {
8588
8691
  const result = await installFromMarketplace(this.pluginsDir, slug, options);
8692
+ const targetDir = resolve8(this.pluginsDir, result.name);
8693
+ this.fixSharedDeps(targetDir);
8589
8694
  ensurePluginDependencies(this.pluginsDir);
8590
8695
  return result;
8591
8696
  }
@@ -10233,6 +10338,17 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
10233
10338
  };
10234
10339
  break;
10235
10340
  }
10341
+ case "tab": {
10342
+ const tabSub = args[0];
10343
+ const validSubs = ["list", "new", "close", "switch"];
10344
+ cmdName = "tab";
10345
+ params = {
10346
+ subcommand: validSubs.includes(tabSub) ? tabSub : options.subcommand,
10347
+ url: args[1] || options.url,
10348
+ index: options.index ? Number(options.index) : void 0
10349
+ };
10350
+ break;
10351
+ }
10236
10352
  default:
10237
10353
  cmdName = command;
10238
10354
  params = { ...options };
@@ -11055,6 +11171,7 @@ async function handleConvert(args, _mode) {
11055
11171
  const { generateJSScript: generateJSScript2, generatePythonScript: generatePythonScript2, generateBashScript: generateBashScript2 } = await import("./convert-R3XXYKC6.js");
11056
11172
  const content = fs6.readFileSync(filePath, "utf-8");
11057
11173
  const recording = yaml3.parse(content);
11174
+ if (recording.actions && !recording.events) recording.events = recording.actions;
11058
11175
  const ext = path5.extname(outputPath).toLowerCase();
11059
11176
  let script;
11060
11177
  if (ext === ".py") {
@@ -11066,7 +11183,7 @@ async function handleConvert(args, _mode) {
11066
11183
  }
11067
11184
  fs6.writeFileSync(outputPath, script);
11068
11185
  fs6.chmodSync(outputPath, 493);
11069
- const eventCount = (recording.events || []).length;
11186
+ const eventCount = (recording.events || recording.actions || []).length;
11070
11187
  console.log(`Converted ${filePath} -> ${outputPath}`);
11071
11188
  console.log(` Events: ${eventCount}, Start URL: ${recording.startUrl}`);
11072
11189
  console.log(` Run: ${ext === ".py" ? "python" : ext === ".sh" ? "./" : "node"} ${outputPath}`);
@@ -11077,7 +11194,7 @@ async function handleExtract(args, _mode) {
11077
11194
  console.error("Usage: xbrowser extract <recording.yaml>");
11078
11195
  process.exit(1);
11079
11196
  }
11080
- const { extractAndSave: extractAndSave2, printExtractSummary: printExtractSummary2 } = await import("./extract-2ZFW2MX7.js");
11197
+ const { extractAndSave: extractAndSave2, printExtractSummary: printExtractSummary2 } = await import("./extract-RM62AJXW.js");
11081
11198
  const { summary, outputPath } = extractAndSave2(filePath);
11082
11199
  printExtractSummary2(summary);
11083
11200
  console.log(`
@@ -11090,7 +11207,7 @@ async function handleFilter(args, _mode, options) {
11090
11207
  console.error("Usage: xbrowser filter <input.yaml> <output.yaml> [--exclude type1,type2]");
11091
11208
  process.exit(1);
11092
11209
  }
11093
- const { filterRecording: filterRecording2, parseExcludeTypes: parseExcludeTypes2 } = await import("./filter-3JQWBM5F.js");
11210
+ const { filterRecording: filterRecording2, parseExcludeTypes: parseExcludeTypes2 } = await import("./filter-K6FGRJQU.js");
11094
11211
  const excludeArgs = args.slice(2).concat(
11095
11212
  Object.entries(options || {}).flatMap(
11096
11213
  ([k, v]) => k.startsWith("exclude") ? [`--${k}${typeof v === "string" ? "=" + v : ""}`] : []
@@ -11653,7 +11770,7 @@ async function handleNetCommand(args, options, mode, sessionName) {
11653
11770
 
11654
11771
  // src/cli/test-routes.ts
11655
11772
  import { execSync as execSync3 } from "child_process";
11656
- import { readFileSync as readFileSync8 } from "fs";
11773
+ import { readFileSync as readFileSync9 } from "fs";
11657
11774
  import { resolve as resolve9 } from "path";
11658
11775
  function findPluginPath(plugin) {
11659
11776
  const candidates = [
@@ -11662,7 +11779,7 @@ function findPluginPath(plugin) {
11662
11779
  ];
11663
11780
  for (const p of candidates) {
11664
11781
  try {
11665
- readFileSync8(p, "utf-8");
11782
+ readFileSync9(p, "utf-8");
11666
11783
  return p;
11667
11784
  } catch {
11668
11785
  }
@@ -11673,7 +11790,7 @@ function extractSchema(plugin, command) {
11673
11790
  const pluginPath = findPluginPath(plugin);
11674
11791
  let src;
11675
11792
  try {
11676
- src = readFileSync8(pluginPath, "utf-8");
11793
+ src = readFileSync9(pluginPath, "utf-8");
11677
11794
  } catch {
11678
11795
  return null;
11679
11796
  }
@@ -12545,7 +12662,7 @@ function extractCdpFromArgv(argv) {
12545
12662
  return process.env.XBROWSER_CDP;
12546
12663
  }
12547
12664
  async function handleStdinMode(stdinCommands, argv) {
12548
- const chain = stdinCommands.join(" && ");
12665
+ const chain = stdinCommands.join(" ; ");
12549
12666
  const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
12550
12667
  const sessionName = argv ? extractSessionNameFromArgv(argv) : "default";
12551
12668
  const chainResult = await executeChain(chain, { fileMode: true, cdpEndpoint, sessionName });
@@ -12808,6 +12925,13 @@ async function routeCommand(argvIn, stdinCommands) {
12808
12925
  for (const step of chainResult.steps) {
12809
12926
  if (step.success) {
12810
12927
  console.log(`[OK] ${step.raw}`);
12928
+ if (step.data && typeof step.data === "object") {
12929
+ const d = step.data;
12930
+ for (const [k, v] of Object.entries(d)) {
12931
+ if (k !== "ok" && k !== "success")
12932
+ console.log(` ${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`);
12933
+ }
12934
+ }
12811
12935
  if (step.tips?.length) {
12812
12936
  for (const tip of step.tips) {
12813
12937
  console.log(` \u{1F4A1} ${tip}`);
@@ -12817,6 +12941,9 @@ async function routeCommand(argvIn, stdinCommands) {
12817
12941
  console.error(`[FAIL] ${step.raw}: ${step.message}`);
12818
12942
  }
12819
12943
  }
12944
+ if (chainResult.stoppedReason) {
12945
+ console.error(`Stopped: ${chainResult.stoppedReason}`);
12946
+ }
12820
12947
  if (!chainResult.success) throw new Error("Command failed");
12821
12948
  return;
12822
12949
  }
@@ -14451,10 +14578,10 @@ var FileDownloadHandler = class {
14451
14578
  async handle(ctx) {
14452
14579
  const msg = ctx.message;
14453
14580
  try {
14454
- const { readFileSync: readFileSync10 } = await import("fs");
14581
+ const { readFileSync: readFileSync11 } = await import("fs");
14455
14582
  const { resolve: resolve10, basename: basename3 } = await import("path");
14456
14583
  const targetPath = resolve10(msg.path);
14457
- const data = readFileSync10(targetPath);
14584
+ const data = readFileSync11(targetPath);
14458
14585
  const base64 = data.toString("base64");
14459
14586
  const ext = targetPath.split(".").pop()?.toLowerCase() || "";
14460
14587
  const mimeMap = {
@@ -15996,7 +16123,7 @@ var DataCollector = class {
15996
16123
  return results;
15997
16124
  }
15998
16125
  async createBrowserContext() {
15999
- const { launch } = await import("./cdp-driver-S5STYUZZ.js");
16126
+ const { launch } = await import("./cdp-driver-72HOBP4C.js");
16000
16127
  const { browser } = await launch({
16001
16128
  headless: true,
16002
16129
  args: ["--no-sandbox", "--disable-setuid-sandbox"]
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getPluginLoader,
3
3
  resetPluginLoader
4
- } from "./chunk-PHBK3TRN.js";
4
+ } from "./chunk-2QQDTXDL.js";
5
5
  import "./chunk-KFQGP6VL.js";
6
6
  export {
7
7
  getPluginLoader,
@@ -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-S5STYUZZ.js");
34
+ const { launch } = await import("./cdp-driver-72HOBP4C.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.2.2",
3
+ "version": "1.3.1",
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": {