@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/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") {
@@ -6331,8 +6356,10 @@ var XBrowserPluginLoader = class {
6331
6356
  const instance = await this.loadPlugin(indexPath, entry.name);
6332
6357
  loaded.push(instance);
6333
6358
  } catch (err) {
6334
- if (process.env.XBROWSER_DEBUG) {
6335
- console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${err instanceof Error ? err.message : String(err)}`);
6359
+ const errMsg2 = err instanceof Error ? err.message : String(err);
6360
+ console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${errMsg2}`);
6361
+ if (errMsg2.includes("Cannot find module") && errMsg2.includes("shared/")) {
6362
+ console.warn(` \u{1F4A1} This plugin needs shared/ dependencies. Try: xbrowser plugin install shared`);
6336
6363
  }
6337
6364
  }
6338
6365
  }
@@ -6998,7 +7025,7 @@ async function guardCheck(commandName) {
6998
7025
  }
6999
7026
  }
7000
7027
  function errorResult(message) {
7001
- return { ...fail7(message), duration: 0 };
7028
+ return { ...fail8(message), duration: 0 };
7002
7029
  }
7003
7030
  function tipsToMessages(tips) {
7004
7031
  if (!tips || tips.length === 0) return [];
@@ -7031,7 +7058,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7031
7058
  }
7032
7059
  let targetPageOverride = null;
7033
7060
  if (_target && extraOpts?.cdpEndpoint) {
7034
- const { findTargetPage } = await import("./browser-PZX7PO23.js");
7061
+ const { findTargetPage } = await import("./browser-VKZVOOVV.js");
7035
7062
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7036
7063
  if (!targetPageOverride) {
7037
7064
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -7235,7 +7262,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7235
7262
  duration,
7236
7263
  timestamp: start
7237
7264
  });
7238
- return { ...fail7(errorMessage), duration };
7265
+ return { ...fail8(errorMessage), duration };
7239
7266
  } finally {
7240
7267
  }
7241
7268
  }
@@ -7276,7 +7303,7 @@ async function executeChain(input, options) {
7276
7303
  results.push({
7277
7304
  command: cmdName,
7278
7305
  raw: cmdStr,
7279
- ...fail7(`Plugin "${cmdName}" requires a sub-command`),
7306
+ ...fail8(`Plugin "${cmdName}" requires a sub-command`),
7280
7307
  duration: 0
7281
7308
  });
7282
7309
  if (type === "and") {
@@ -7295,7 +7322,7 @@ async function executeChain(input, options) {
7295
7322
  results.push({
7296
7323
  command: cmdName,
7297
7324
  raw: cmdStr,
7298
- ...fail7(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
7325
+ ...fail8(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
7299
7326
  duration: 0
7300
7327
  });
7301
7328
  if (type === "and") {
@@ -7427,7 +7454,7 @@ async function executeChain(input, options) {
7427
7454
  results.push({
7428
7455
  command: `${cmdName} ${subCommand}`,
7429
7456
  raw: cmdStr,
7430
- ...fail7(errorMessage),
7457
+ ...fail8(errorMessage),
7431
7458
  duration: duration2
7432
7459
  });
7433
7460
  if (type === "and") {
@@ -7499,7 +7526,7 @@ async function executeChain(input, options) {
7499
7526
  }
7500
7527
  }
7501
7528
  function isChainInput(input) {
7502
- 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);
7503
7530
  }
7504
7531
 
7505
7532
  // src/session/session-client.ts
@@ -7734,9 +7761,12 @@ import {
7734
7761
  existsSync as existsSync10,
7735
7762
  readdirSync as readdirSync2,
7736
7763
  mkdirSync as mkdirSync8,
7737
- rmSync as rmSync6
7764
+ rmSync as rmSync6,
7765
+ copyFileSync,
7766
+ cpSync as cpSync6,
7767
+ readFileSync as readFileSync8
7738
7768
  } from "fs";
7739
- import { resolve as resolve8, basename as basename2 } from "path";
7769
+ import { resolve as resolve8, basename as basename2, dirname as dirname3 } from "path";
7740
7770
  import { homedir as homedir8 } from "os";
7741
7771
 
7742
7772
  // src/plugin/install-sources/local.ts
@@ -8229,28 +8259,103 @@ var PluginInstaller = class {
8229
8259
  switch (type) {
8230
8260
  case "local":
8231
8261
  return await installFromLocal(source, name, targetDir).then((r) => {
8262
+ this.fixSharedDeps(targetDir);
8232
8263
  ensurePluginDependencies(this.pluginsDir);
8233
8264
  return r;
8234
8265
  });
8235
8266
  case "npm":
8236
8267
  return await installFromNpm(resolvedSource, name, targetDir).then((r) => {
8268
+ this.fixSharedDeps(targetDir);
8237
8269
  ensurePluginDependencies(this.pluginsDir);
8238
8270
  return r;
8239
8271
  });
8240
8272
  case "git":
8241
8273
  return await installFromGit(source, name, targetDir).then((r) => {
8274
+ this.fixSharedDeps(targetDir);
8242
8275
  ensurePluginDependencies(this.pluginsDir);
8243
8276
  return r;
8244
8277
  });
8245
8278
  case "url":
8246
8279
  return await installFromUrl(source, name, targetDir).then((r) => {
8280
+ this.fixSharedDeps(targetDir);
8247
8281
  ensurePluginDependencies(this.pluginsDir);
8248
8282
  return r;
8249
8283
  });
8250
8284
  }
8251
8285
  }
8286
+ /**
8287
+ * Fix missing `../shared/` dependencies after installation.
8288
+ *
8289
+ * Some marketplace/npm packages import from `../shared/` (e.g. ssr-detect.js,
8290
+ * ai-chat-base.ts) but the `shared/` directory is not included in the package.
8291
+ * This method scans the installed plugin's index.ts for such imports and
8292
+ * copies the missing files from the local repository's `.xcli/plugins/shared/`
8293
+ * directory (if available).
8294
+ */
8295
+ fixSharedDeps(pluginDir) {
8296
+ const indexPath = resolve8(pluginDir, "index.ts");
8297
+ if (!existsSync10(indexPath)) return;
8298
+ let content;
8299
+ try {
8300
+ content = readFileSync8(indexPath, "utf8");
8301
+ } catch {
8302
+ return;
8303
+ }
8304
+ const sharedImportRegex = /from\s+['"]\.\.\/shared\/([^'"]+)['"]/g;
8305
+ const missingFiles = [];
8306
+ let match;
8307
+ while ((match = sharedImportRegex.exec(content)) !== null) {
8308
+ missingFiles.push(match[1]);
8309
+ }
8310
+ if (missingFiles.length === 0) return;
8311
+ const sharedDir = resolve8(pluginDir, "..", "shared");
8312
+ const toCopy = [];
8313
+ for (const file of missingFiles) {
8314
+ const targetPath = resolve8(sharedDir, file);
8315
+ if (!existsSync10(targetPath)) {
8316
+ toCopy.push(file);
8317
+ }
8318
+ }
8319
+ if (toCopy.length === 0) return;
8320
+ const repoSharedDirs = [
8321
+ resolve8(process.cwd(), ".xcli/plugins/shared"),
8322
+ resolve8(homedir8(), ".xbrowser/plugins/shared")
8323
+ ];
8324
+ let sourceSharedDir = null;
8325
+ for (const dir of repoSharedDirs) {
8326
+ if (existsSync10(dir)) {
8327
+ sourceSharedDir = dir;
8328
+ break;
8329
+ }
8330
+ }
8331
+ if (!sourceSharedDir) {
8332
+ console.warn(`\u26A0\uFE0F Plugin "${basename2(pluginDir)}" imports shared files but they are missing: ${toCopy.join(", ")}`);
8333
+ console.warn(` To fix: install the "shared" plugin or copy .xcli/plugins/shared/ to ~/.xbrowser/plugins/shared/`);
8334
+ return;
8335
+ }
8336
+ mkdirSync8(sharedDir, { recursive: true });
8337
+ for (const file of toCopy) {
8338
+ const src = resolve8(sourceSharedDir, file);
8339
+ const dst = resolve8(sharedDir, file);
8340
+ if (existsSync10(src)) {
8341
+ try {
8342
+ cpSync6(dirname3(src), dirname3(dst), { recursive: true });
8343
+ console.log(`\u2705 Copied shared/${file} for plugin "${basename2(pluginDir)}"`);
8344
+ } catch {
8345
+ try {
8346
+ copyFileSync(src, dst);
8347
+ console.log(`\u2705 Copied shared/${file} for plugin "${basename2(pluginDir)}"`);
8348
+ } catch {
8349
+ console.warn(`\u26A0\uFE0F Could not copy shared/${file}`);
8350
+ }
8351
+ }
8352
+ }
8353
+ }
8354
+ }
8252
8355
  async installFromMarketplace(slug, options) {
8253
8356
  const result = await installFromMarketplace(this.pluginsDir, slug, options);
8357
+ const targetDir = resolve8(this.pluginsDir, result.name);
8358
+ this.fixSharedDeps(targetDir);
8254
8359
  ensurePluginDependencies(this.pluginsDir);
8255
8360
  return result;
8256
8361
  }
@@ -9893,6 +9998,17 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
9893
9998
  };
9894
9999
  break;
9895
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
+ }
9896
10012
  default:
9897
10013
  cmdName = command;
9898
10014
  params = { ...options };
@@ -10715,6 +10831,7 @@ async function handleConvert(args, _mode) {
10715
10831
  const { generateJSScript, generatePythonScript, generateBashScript } = await import("./convert-LB3GJTLR.js");
10716
10832
  const content = fs3.readFileSync(filePath, "utf-8");
10717
10833
  const recording = yaml.parse(content);
10834
+ if (recording.actions && !recording.events) recording.events = recording.actions;
10718
10835
  const ext = path3.extname(outputPath).toLowerCase();
10719
10836
  let script;
10720
10837
  if (ext === ".py") {
@@ -10726,7 +10843,7 @@ async function handleConvert(args, _mode) {
10726
10843
  }
10727
10844
  fs3.writeFileSync(outputPath, script);
10728
10845
  fs3.chmodSync(outputPath, 493);
10729
- const eventCount = (recording.events || []).length;
10846
+ const eventCount = (recording.events || recording.actions || []).length;
10730
10847
  console.log(`Converted ${filePath} -> ${outputPath}`);
10731
10848
  console.log(` Events: ${eventCount}, Start URL: ${recording.startUrl}`);
10732
10849
  console.log(` Run: ${ext === ".py" ? "python" : ext === ".sh" ? "./" : "node"} ${outputPath}`);
@@ -10737,7 +10854,7 @@ async function handleExtract(args, _mode) {
10737
10854
  console.error("Usage: xbrowser extract <recording.yaml>");
10738
10855
  process.exit(1);
10739
10856
  }
10740
- const { extractAndSave, printExtractSummary } = await import("./extract-BSYBM4MR.js");
10857
+ const { extractAndSave, printExtractSummary } = await import("./extract-O46CC533.js");
10741
10858
  const { summary, outputPath } = extractAndSave(filePath);
10742
10859
  printExtractSummary(summary);
10743
10860
  console.log(`
@@ -10750,7 +10867,7 @@ async function handleFilter(args, _mode, options) {
10750
10867
  console.error("Usage: xbrowser filter <input.yaml> <output.yaml> [--exclude type1,type2]");
10751
10868
  process.exit(1);
10752
10869
  }
10753
- const { filterRecording, parseExcludeTypes } = await import("./filter-EDTFGLS5.js");
10870
+ const { filterRecording, parseExcludeTypes } = await import("./filter-TAAYMSYI.js");
10754
10871
  const excludeArgs = args.slice(2).concat(
10755
10872
  Object.entries(options || {}).flatMap(
10756
10873
  ([k, v]) => k.startsWith("exclude") ? [`--${k}${typeof v === "string" ? "=" + v : ""}`] : []
@@ -11313,7 +11430,7 @@ async function handleNetCommand(args, options, mode, sessionName) {
11313
11430
 
11314
11431
  // src/cli/test-routes.ts
11315
11432
  import { execSync as execSync3 } from "child_process";
11316
- import { readFileSync as readFileSync8 } from "fs";
11433
+ import { readFileSync as readFileSync9 } from "fs";
11317
11434
  import { resolve as resolve9 } from "path";
11318
11435
  function findPluginPath(plugin) {
11319
11436
  const candidates = [
@@ -11322,7 +11439,7 @@ function findPluginPath(plugin) {
11322
11439
  ];
11323
11440
  for (const p of candidates) {
11324
11441
  try {
11325
- readFileSync8(p, "utf-8");
11442
+ readFileSync9(p, "utf-8");
11326
11443
  return p;
11327
11444
  } catch {
11328
11445
  }
@@ -11333,7 +11450,7 @@ function extractSchema(plugin, command) {
11333
11450
  const pluginPath = findPluginPath(plugin);
11334
11451
  let src;
11335
11452
  try {
11336
- src = readFileSync8(pluginPath, "utf-8");
11453
+ src = readFileSync9(pluginPath, "utf-8");
11337
11454
  } catch {
11338
11455
  return null;
11339
11456
  }
@@ -12205,7 +12322,7 @@ function extractCdpFromArgv(argv) {
12205
12322
  return process.env.XBROWSER_CDP;
12206
12323
  }
12207
12324
  async function handleStdinMode(stdinCommands, argv) {
12208
- const chain = stdinCommands.join(" && ");
12325
+ const chain = stdinCommands.join(" ; ");
12209
12326
  const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
12210
12327
  const sessionName = argv ? extractSessionNameFromArgv(argv) : "default";
12211
12328
  const chainResult = await executeChain(chain, { fileMode: true, cdpEndpoint, sessionName });
@@ -12468,6 +12585,13 @@ async function routeCommand(argvIn, stdinCommands) {
12468
12585
  for (const step of chainResult.steps) {
12469
12586
  if (step.success) {
12470
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
+ }
12471
12595
  if (step.tips?.length) {
12472
12596
  for (const tip of step.tips) {
12473
12597
  console.log(` \u{1F4A1} ${tip}`);
@@ -12477,6 +12601,9 @@ async function routeCommand(argvIn, stdinCommands) {
12477
12601
  console.error(`[FAIL] ${step.raw}: ${step.message}`);
12478
12602
  }
12479
12603
  }
12604
+ if (chainResult.stoppedReason) {
12605
+ console.error(`Stopped: ${chainResult.stoppedReason}`);
12606
+ }
12480
12607
  if (!chainResult.success) throw new Error("Command failed");
12481
12608
  return;
12482
12609
  }
@@ -12869,7 +12996,7 @@ async function main() {
12869
12996
  const command = process.argv[2];
12870
12997
  const isLongRunning = command === "preview" || command === "serve";
12871
12998
  if (!isLongRunning) {
12872
- const { ensureProcessCanExit } = await import("./browser-PZX7PO23.js");
12999
+ const { ensureProcessCanExit } = await import("./browser-VKZVOOVV.js");
12873
13000
  await ensureProcessCanExit().catch(() => {
12874
13001
  });
12875
13002
  process.exit(exitCode);