@xbrowser/cli 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  resolveLaunchOpts,
26
26
  saveSessionDiskMeta,
27
27
  setActivePage
28
- } from "./chunk-MNFOCOL6.js";
28
+ } from "./chunk-TLOHV3FP.js";
29
29
  import "./chunk-TNEN6VQ2.js";
30
30
  import {
31
31
  forwardCommandLog,
@@ -187,7 +187,7 @@ var version = pkg.version;
187
187
  // src/executor.ts
188
188
  import {
189
189
  ok as ok25,
190
- fail as fail7,
190
+ fail as fail8,
191
191
  isCommandResult,
192
192
  CompositeStorage as CompositeStorage2,
193
193
  TipCollector as TipCollector2,
@@ -263,7 +263,7 @@ function createStubContext(pluginName) {
263
263
 
264
264
  // src/commands/navigation.ts
265
265
  import { z } from "zod";
266
- import { ok } from "@dyyz1993/xcli-core";
266
+ import { ok, fail } from "@dyyz1993/xcli-core";
267
267
 
268
268
  // src/commands/command-registry.ts
269
269
  var registry = /* @__PURE__ */ new Map();
@@ -352,13 +352,19 @@ var gotoCommand = registerCommand({
352
352
  if (/^[\w-]+(\.[\w-]+)+/.test(url) || url.startsWith("localhost")) {
353
353
  url = "https://" + url;
354
354
  } else {
355
- throw new Error(`Invalid URL: "${url}". Expected http(s)://, file://, about:, data:, or a domain name.`);
355
+ return fail(`Invalid URL: "${url}". Expected http(s)://, file://, about:, data:, or a domain name.`);
356
356
  }
357
357
  }
358
- const response = await ctx.page.goto(url, {
359
- waitUntil: p.waitUntil || "domcontentloaded",
360
- ...p.timeout ? { timeout: p.timeout } : {}
361
- });
358
+ let response;
359
+ try {
360
+ response = await ctx.page.goto(url, {
361
+ waitUntil: p.waitUntil || "domcontentloaded",
362
+ ...p.timeout ? { timeout: p.timeout } : {}
363
+ });
364
+ } catch (err) {
365
+ const msg = err instanceof Error ? err.message : String(err);
366
+ return fail(`Navigation failed: ${msg}`);
367
+ }
362
368
  const ssr = await detectSsr(ctx.page);
363
369
  return ok({ url, status: response?.status(), ...ssr ? { ssr } : {} });
364
370
  }
@@ -673,6 +679,22 @@ var checkCommand = registerCommand({
673
679
  return ok2({ selector: p.selector });
674
680
  }
675
681
  });
682
+ var uncheckCommand = registerCommand({
683
+ name: "uncheck",
684
+ description: "Uncheck checkbox or radio",
685
+ scope: "element",
686
+ selectorParams: ["selector"],
687
+ parameters: z2.object({
688
+ selector: z2.string()
689
+ }),
690
+ result: z2.object({
691
+ selector: z2.string()
692
+ }),
693
+ handler: async (p, ctx) => {
694
+ await ctx.page.uncheck(p.selector, { timeout: 1e4 });
695
+ return ok2({ selector: p.selector });
696
+ }
697
+ });
676
698
  var hoverCommand = registerCommand({
677
699
  name: "hover",
678
700
  description: "Hover over element",
@@ -1214,7 +1236,7 @@ var setViewportCommand = registerCommand({
1214
1236
 
1215
1237
  // src/commands/frame.ts
1216
1238
  import { z as z12 } from "zod";
1217
- import { ok as ok12, fail } from "@dyyz1993/xcli-core";
1239
+ import { ok as ok12, fail as fail2 } from "@dyyz1993/xcli-core";
1218
1240
  var framesCommand = registerCommand({
1219
1241
  name: "frames",
1220
1242
  description: "List all frames in the current page",
@@ -1227,7 +1249,9 @@ var framesCommand = registerCommand({
1227
1249
  }))
1228
1250
  }),
1229
1251
  handler: async (_p, ctx) => {
1230
- const frameList = ctx.page.frames().map((frame, index) => ({
1252
+ const discover = ctx.page.discoverFrames;
1253
+ const rawFrames = discover ? await discover.call(ctx.page) : ctx.page.frames();
1254
+ const frameList = rawFrames.map((frame, index) => ({
1231
1255
  index,
1232
1256
  name: frame.name(),
1233
1257
  url: frame.url()
@@ -1249,17 +1273,18 @@ var frameCommand = registerCommand({
1249
1273
  error: z12.string().optional()
1250
1274
  }),
1251
1275
  handler: async (p, ctx) => {
1252
- const allFrames = ctx.page.frames();
1276
+ const discover = ctx.page.discoverFrames;
1277
+ const rawFrames = discover ? await discover.call(ctx.page) : ctx.page.frames();
1253
1278
  let targetFrame;
1254
1279
  if (p.index !== void 0) {
1255
- targetFrame = allFrames[p.index];
1280
+ targetFrame = rawFrames[p.index];
1256
1281
  } else if (p.name !== void 0) {
1257
- targetFrame = allFrames.find((f) => f.name() === p.name);
1282
+ targetFrame = rawFrames.find((f) => f.name() === p.name);
1258
1283
  } else {
1259
- return fail("Must provide index or name");
1284
+ return fail2("Must provide index or name");
1260
1285
  }
1261
1286
  if (!targetFrame) {
1262
- return fail("Frame not found");
1287
+ return fail2("Frame not found");
1263
1288
  }
1264
1289
  return ok12({
1265
1290
  name: targetFrame.name(),
@@ -1905,7 +1930,7 @@ var actionsCommand = registerCommand({
1905
1930
 
1906
1931
  // src/commands/scrape.ts
1907
1932
  import { z as z15 } from "zod";
1908
- import { ok as ok15, fail as fail2 } from "@dyyz1993/xcli-core";
1933
+ import { ok as ok15, fail as fail3 } from "@dyyz1993/xcli-core";
1909
1934
 
1910
1935
  // src/lib/html-to-markdown.ts
1911
1936
  import * as cheerio from "cheerio";
@@ -2421,7 +2446,7 @@ var scrapeCommand = registerCommand({
2421
2446
  }
2422
2447
  }
2423
2448
  }
2424
- return fail2(`Scrape failed after ${maxAttempts} attempt(s): ${lastError?.message ?? "unknown error"}`);
2449
+ return fail3(`Scrape failed after ${maxAttempts} attempt(s): ${lastError?.message ?? "unknown error"}`);
2425
2450
  } finally {
2426
2451
  await closeEphemeralContext(context);
2427
2452
  }
@@ -3485,7 +3510,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
3485
3510
 
3486
3511
  // src/commands/network.ts
3487
3512
  import { z as z19 } from "zod";
3488
- import { ok as ok19, fail as fail3 } from "@dyyz1993/xcli-core";
3513
+ import { ok as ok19, fail as fail4 } from "@dyyz1993/xcli-core";
3489
3514
  function extractPath2(url) {
3490
3515
  try {
3491
3516
  const u = new URL(url);
@@ -3650,7 +3675,7 @@ var networkCommand = registerCommand({
3650
3675
  };
3651
3676
  if (p.listen) {
3652
3677
  const page2 = ctx.page;
3653
- if (!page2) return fail3("No active page. Use --cdp to connect first.");
3678
+ if (!page2) return fail4("No active page. Use --cdp to connect first.");
3654
3679
  const captures = [];
3655
3680
  const consoleMessages = [];
3656
3681
  const wsCaptures = [];
@@ -4030,7 +4055,7 @@ var ENGINE_KEY_ENUM = z20.enum(ALL_ENGINE_KEYS);
4030
4055
 
4031
4056
  // src/commands/snapshot.ts
4032
4057
  import { z as z21 } from "zod";
4033
- import { ok as ok20, fail as fail4, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
4058
+ import { ok as ok20, fail as fail5, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
4034
4059
 
4035
4060
  // src/runtime/ref-store.ts
4036
4061
  var sessions = /* @__PURE__ */ new Map();
@@ -4986,7 +5011,7 @@ var snapshotCommand = registerCommand({
4986
5011
  persistSemantics(url, aria);
4987
5012
  return ok20({ url, title, aria, text, dom }, normalizeTips3(tips));
4988
5013
  }
4989
- return fail4(`Unknown snapshot type: ${p.type}`);
5014
+ return fail5(`Unknown snapshot type: ${p.type}`);
4990
5015
  }
4991
5016
  });
4992
5017
  function persistSemantics(url, aria) {
@@ -5155,7 +5180,7 @@ var waitForCommand = registerCommand({
5155
5180
 
5156
5181
  // src/commands/tab.ts
5157
5182
  import { z as z23 } from "zod";
5158
- import { ok as ok22, fail as fail5 } from "@dyyz1993/xcli-core";
5183
+ import { ok as ok22, fail as fail6 } from "@dyyz1993/xcli-core";
5159
5184
  var TabParams = z23.object({
5160
5185
  subcommand: z23.enum(["list", "new", "close", "switch"]),
5161
5186
  url: z23.string().optional(),
@@ -5182,7 +5207,7 @@ var tabCommand = registerCommand({
5182
5207
  case "switch":
5183
5208
  return handleSwitch(p, pages, ctx);
5184
5209
  default:
5185
- return fail5(`Unknown subcommand: ${p.subcommand}`);
5210
+ return fail6(`Unknown subcommand: ${p.subcommand}`);
5186
5211
  }
5187
5212
  }
5188
5213
  });
@@ -5239,11 +5264,11 @@ async function handleNew(p, _pages, ctx) {
5239
5264
  }
5240
5265
  async function handleClose(p, pages, ctx) {
5241
5266
  if (pages.length <= 1) {
5242
- return fail5("Cannot close the last remaining tab");
5267
+ return fail6("Cannot close the last remaining tab");
5243
5268
  }
5244
5269
  const closeIndex = p.index ?? pages.indexOf(ctx.page);
5245
5270
  if (closeIndex < 0 || closeIndex >= pages.length) {
5246
- return fail5(`Invalid tab index: ${closeIndex}. Valid range: 0-${pages.length - 1}`);
5271
+ return fail6(`Invalid tab index: ${closeIndex}. Valid range: 0-${pages.length - 1}`);
5247
5272
  }
5248
5273
  const pageToClose = pages[closeIndex];
5249
5274
  const isActivePage = pageToClose === ctx.page;
@@ -5266,10 +5291,10 @@ async function handleClose(p, pages, ctx) {
5266
5291
  }
5267
5292
  async function handleSwitch(p, pages, ctx) {
5268
5293
  if (p.index === void 0) {
5269
- return fail5("Parameter --index is required for switch subcommand");
5294
+ return fail6("Parameter --index is required for switch subcommand");
5270
5295
  }
5271
5296
  if (p.index < 0 || p.index >= pages.length) {
5272
- return fail5(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
5297
+ return fail6(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
5273
5298
  }
5274
5299
  const targetPage = pages[p.index];
5275
5300
  await targetPage.bringToFront().catch(() => {
@@ -5515,7 +5540,7 @@ registerCommandDefinition("addinitscript", ["script"]);
5515
5540
 
5516
5541
  // src/commands/find.ts
5517
5542
  import { z as z25 } from "zod";
5518
- import { ok as ok24, fail as fail6, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
5543
+ import { ok as ok24, fail as fail7, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
5519
5544
  var actionSchema2 = z25.enum(["click", "fill", "type", "select", "hover", "check"]);
5520
5545
  var findCommand = registerCommand({
5521
5546
  name: "find",
@@ -5556,7 +5581,7 @@ var findCommand = registerCommand({
5556
5581
  });
5557
5582
  const count = await locator.count();
5558
5583
  if (count === 0) {
5559
- return fail6(`No element found with ${p.strategy}="${p.value}"`);
5584
+ return fail7(`No element found with ${p.strategy}="${p.value}"`);
5560
5585
  }
5561
5586
  const tips = [];
5562
5587
  const target = selectTarget(locator, p.strategy);
@@ -5568,15 +5593,15 @@ var findCommand = registerCommand({
5568
5593
  await target.click({ timeout: p.timeout, force: true });
5569
5594
  return okWithTips({ matched: count, selector, action: "click" }, tips);
5570
5595
  } else if (actionName === "fill") {
5571
- if (actionValue === void 0) return fail6("find fill requires a value");
5596
+ if (actionValue === void 0) return fail7("find fill requires a value");
5572
5597
  await target.fill(actionValue, { timeout: p.timeout, force: true });
5573
5598
  return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
5574
5599
  } else if (actionName === "type") {
5575
- if (actionValue === void 0) return fail6("find type requires a value");
5600
+ if (actionValue === void 0) return fail7("find type requires a value");
5576
5601
  await target.type(actionValue, { delay: 10, timeout: p.timeout });
5577
5602
  return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
5578
5603
  } else if (actionName === "select") {
5579
- if (actionValue === void 0) return fail6("find select requires a value");
5604
+ if (actionValue === void 0) return fail7("find select requires a value");
5580
5605
  await target.selectOption(actionValue);
5581
5606
  return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
5582
5607
  } else if (actionName === "hover") {
@@ -7000,7 +7025,7 @@ async function guardCheck(commandName) {
7000
7025
  }
7001
7026
  }
7002
7027
  function errorResult(message) {
7003
- return { ...fail7(message), duration: 0 };
7028
+ return { ...fail8(message), duration: 0 };
7004
7029
  }
7005
7030
  function tipsToMessages(tips) {
7006
7031
  if (!tips || tips.length === 0) return [];
@@ -7033,7 +7058,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7033
7058
  }
7034
7059
  let targetPageOverride = null;
7035
7060
  if (_target && extraOpts?.cdpEndpoint) {
7036
- const { findTargetPage } = await import("./browser-PZX7PO23.js");
7061
+ const { findTargetPage } = await import("./browser-VKZVOOVV.js");
7037
7062
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7038
7063
  if (!targetPageOverride) {
7039
7064
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -7237,7 +7262,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7237
7262
  duration,
7238
7263
  timestamp: start
7239
7264
  });
7240
- return { ...fail7(errorMessage), duration };
7265
+ return { ...fail8(errorMessage), duration };
7241
7266
  } finally {
7242
7267
  }
7243
7268
  }
@@ -7278,7 +7303,7 @@ async function executeChain(input, options) {
7278
7303
  results.push({
7279
7304
  command: cmdName,
7280
7305
  raw: cmdStr,
7281
- ...fail7(`Plugin "${cmdName}" requires a sub-command`),
7306
+ ...fail8(`Plugin "${cmdName}" requires a sub-command`),
7282
7307
  duration: 0
7283
7308
  });
7284
7309
  if (type === "and") {
@@ -7297,7 +7322,7 @@ async function executeChain(input, options) {
7297
7322
  results.push({
7298
7323
  command: cmdName,
7299
7324
  raw: cmdStr,
7300
- ...fail7(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
7325
+ ...fail8(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
7301
7326
  duration: 0
7302
7327
  });
7303
7328
  if (type === "and") {
@@ -7429,7 +7454,7 @@ async function executeChain(input, options) {
7429
7454
  results.push({
7430
7455
  command: `${cmdName} ${subCommand}`,
7431
7456
  raw: cmdStr,
7432
- ...fail7(errorMessage),
7457
+ ...fail8(errorMessage),
7433
7458
  duration: duration2
7434
7459
  });
7435
7460
  if (type === "and") {
@@ -7501,7 +7526,7 @@ async function executeChain(input, options) {
7501
7526
  }
7502
7527
  }
7503
7528
  function isChainInput(input) {
7504
- return /\s&&\s|\s;\s|\s,\s|\s\+\s|\s->\s/.test(input);
7529
+ return /\s&&\s|\|\|\s|\s;\s|\s,\s|\s\+\s|\s->\s/.test(input);
7505
7530
  }
7506
7531
 
7507
7532
  // src/session/session-client.ts
@@ -9973,6 +9998,17 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
9973
9998
  };
9974
9999
  break;
9975
10000
  }
10001
+ case "tab": {
10002
+ const tabSub = args[0];
10003
+ const validSubs = ["list", "new", "close", "switch"];
10004
+ cmdName = "tab";
10005
+ params = {
10006
+ subcommand: validSubs.includes(tabSub) ? tabSub : options.subcommand,
10007
+ url: args[1] || options.url,
10008
+ index: options.index ? Number(options.index) : void 0
10009
+ };
10010
+ break;
10011
+ }
9976
10012
  default:
9977
10013
  cmdName = command;
9978
10014
  params = { ...options };
@@ -10795,6 +10831,7 @@ async function handleConvert(args, _mode) {
10795
10831
  const { generateJSScript, generatePythonScript, generateBashScript } = await import("./convert-LB3GJTLR.js");
10796
10832
  const content = fs3.readFileSync(filePath, "utf-8");
10797
10833
  const recording = yaml.parse(content);
10834
+ if (recording.actions && !recording.events) recording.events = recording.actions;
10798
10835
  const ext = path3.extname(outputPath).toLowerCase();
10799
10836
  let script;
10800
10837
  if (ext === ".py") {
@@ -10806,7 +10843,7 @@ async function handleConvert(args, _mode) {
10806
10843
  }
10807
10844
  fs3.writeFileSync(outputPath, script);
10808
10845
  fs3.chmodSync(outputPath, 493);
10809
- const eventCount = (recording.events || []).length;
10846
+ const eventCount = (recording.events || recording.actions || []).length;
10810
10847
  console.log(`Converted ${filePath} -> ${outputPath}`);
10811
10848
  console.log(` Events: ${eventCount}, Start URL: ${recording.startUrl}`);
10812
10849
  console.log(` Run: ${ext === ".py" ? "python" : ext === ".sh" ? "./" : "node"} ${outputPath}`);
@@ -10817,7 +10854,7 @@ async function handleExtract(args, _mode) {
10817
10854
  console.error("Usage: xbrowser extract <recording.yaml>");
10818
10855
  process.exit(1);
10819
10856
  }
10820
- const { extractAndSave, printExtractSummary } = await import("./extract-BSYBM4MR.js");
10857
+ const { extractAndSave, printExtractSummary } = await import("./extract-O46CC533.js");
10821
10858
  const { summary, outputPath } = extractAndSave(filePath);
10822
10859
  printExtractSummary(summary);
10823
10860
  console.log(`
@@ -10830,7 +10867,7 @@ async function handleFilter(args, _mode, options) {
10830
10867
  console.error("Usage: xbrowser filter <input.yaml> <output.yaml> [--exclude type1,type2]");
10831
10868
  process.exit(1);
10832
10869
  }
10833
- const { filterRecording, parseExcludeTypes } = await import("./filter-EDTFGLS5.js");
10870
+ const { filterRecording, parseExcludeTypes } = await import("./filter-TAAYMSYI.js");
10834
10871
  const excludeArgs = args.slice(2).concat(
10835
10872
  Object.entries(options || {}).flatMap(
10836
10873
  ([k, v]) => k.startsWith("exclude") ? [`--${k}${typeof v === "string" ? "=" + v : ""}`] : []
@@ -12285,7 +12322,7 @@ function extractCdpFromArgv(argv) {
12285
12322
  return process.env.XBROWSER_CDP;
12286
12323
  }
12287
12324
  async function handleStdinMode(stdinCommands, argv) {
12288
- const chain = stdinCommands.join(" && ");
12325
+ const chain = stdinCommands.join(" ; ");
12289
12326
  const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
12290
12327
  const sessionName = argv ? extractSessionNameFromArgv(argv) : "default";
12291
12328
  const chainResult = await executeChain(chain, { fileMode: true, cdpEndpoint, sessionName });
@@ -12548,6 +12585,13 @@ async function routeCommand(argvIn, stdinCommands) {
12548
12585
  for (const step of chainResult.steps) {
12549
12586
  if (step.success) {
12550
12587
  console.log(`[OK] ${step.raw}`);
12588
+ if (step.data && typeof step.data === "object") {
12589
+ const d = step.data;
12590
+ for (const [k, v] of Object.entries(d)) {
12591
+ if (k !== "ok" && k !== "success")
12592
+ console.log(` ${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`);
12593
+ }
12594
+ }
12551
12595
  if (step.tips?.length) {
12552
12596
  for (const tip of step.tips) {
12553
12597
  console.log(` \u{1F4A1} ${tip}`);
@@ -12557,6 +12601,9 @@ async function routeCommand(argvIn, stdinCommands) {
12557
12601
  console.error(`[FAIL] ${step.raw}: ${step.message}`);
12558
12602
  }
12559
12603
  }
12604
+ if (chainResult.stoppedReason) {
12605
+ console.error(`Stopped: ${chainResult.stoppedReason}`);
12606
+ }
12560
12607
  if (!chainResult.success) throw new Error("Command failed");
12561
12608
  return;
12562
12609
  }
@@ -12949,7 +12996,7 @@ async function main() {
12949
12996
  const command = process.argv[2];
12950
12997
  const isLongRunning = command === "preview" || command === "serve";
12951
12998
  if (!isLongRunning) {
12952
- const { ensureProcessCanExit } = await import("./browser-PZX7PO23.js");
12999
+ const { ensureProcessCanExit } = await import("./browser-VKZVOOVV.js");
12953
13000
  await ensureProcessCanExit().catch(() => {
12954
13001
  });
12955
13002
  process.exit(exitCode);