@xbrowser/cli 1.1.2 → 1.2.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-XVZ6NKRJ.js";
28
+ } from "./chunk-MNFOCOL6.js";
29
29
  import "./chunk-TNEN6VQ2.js";
30
30
  import {
31
31
  forwardCommandLog,
@@ -800,6 +800,21 @@ var waitForSelectorDef = {
800
800
  }
801
801
  };
802
802
  var waitCommand = registerCommand({ name: "wait", selectorParams: ["selector"], ...waitForSelectorDef });
803
+ var waitForTimeoutCommand = registerCommand({
804
+ name: "waitForTimeout",
805
+ description: "Wait for a specified number of milliseconds",
806
+ scope: "project",
807
+ parameters: z4.object({
808
+ timeout: z4.number().describe("Milliseconds to wait").default(1e3)
809
+ }),
810
+ result: z4.object({
811
+ waited: z4.number()
812
+ }),
813
+ handler: async (p) => {
814
+ await new Promise((r) => setTimeout(r, p.timeout));
815
+ return ok4({ waited: p.timeout });
816
+ }
817
+ });
803
818
 
804
819
  // src/commands/scroll.ts
805
820
  import { z as z5 } from "zod";
@@ -1665,7 +1680,7 @@ var healthCheckCommand = registerCommand({
1665
1680
  issues.push({
1666
1681
  severity: "error",
1667
1682
  category: "links",
1668
- message: `Broken link (fetch error): ${href} \u2014 ${errMsg(err) || "unknown"}`
1683
+ message: `Broken link (fetch error): ${href} \u2014 ${(err instanceof Error ? err.message : String(err)) || "unknown"}`
1669
1684
  });
1670
1685
  }
1671
1686
  }
@@ -2341,9 +2356,54 @@ var scrapeCommand = registerCommand({
2341
2356
  }
2342
2357
  let content;
2343
2358
  switch (p.format) {
2344
- case "markdown":
2359
+ case "markdown": {
2360
+ const tablesMd = await page.evaluate(() => {
2361
+ document.querySelectorAll(
2362
+ '.el-table__fixed, .el-table__fixed-right, [class*="fixed-left"], [class*="fixed-right"], .ant-table-fixed-left, .ant-table-fixed-right'
2363
+ ).forEach((el) => el.remove());
2364
+ document.querySelectorAll("table").forEach((t) => {
2365
+ if (t.closest(".el-table__fixed, .el-table__fixed-right")) t.remove();
2366
+ });
2367
+ const tables = document.querySelectorAll("table");
2368
+ if (tables.length === 0) {
2369
+ const altTables = document.querySelectorAll(
2370
+ '[role="table"], [role="grid"], .el-table__body, .ant-table-tbody'
2371
+ );
2372
+ if (altTables.length === 0) return "";
2373
+ return Array.from(altTables).map((table) => {
2374
+ return extractRowsFromContainer(table);
2375
+ }).filter((md) => md).join("\n\n");
2376
+ }
2377
+ return Array.from(tables).map((table) => {
2378
+ return extractRowsFromContainer(table);
2379
+ }).filter((md) => md).join("\n\n");
2380
+ function extractRowsFromContainer(container) {
2381
+ const rows = container.querySelectorAll(':scope > tr, :scope > thead > tr, :scope > tbody > tr, :scope > tfoot > tr, [role="row"]');
2382
+ if (rows.length === 0) return "";
2383
+ const mdRows = Array.from(rows).map((row) => {
2384
+ const cells = row.querySelectorAll(':scope > th, :scope > td, :scope > [role="columnheader"], :scope > [role="cell"]');
2385
+ if (cells.length === 0) return "";
2386
+ return "| " + Array.from(cells).map((c) => {
2387
+ const cellText = c.innerText?.trim().replace(/\n/g, " ") || "";
2388
+ return cellText.replace(/\|/g, "\\|") || "";
2389
+ }).join(" | ") + " |";
2390
+ }).filter((r) => r);
2391
+ if (mdRows.length === 0) return "";
2392
+ const headerRow = rows[0];
2393
+ const headerCells = headerRow.querySelectorAll(':scope > th, :scope > [role="columnheader"]');
2394
+ if (headerCells.length > 0) {
2395
+ const sep = "| " + Array(headerCells.length).fill("---").join(" | ") + " |";
2396
+ return mdRows[0] + "\n" + sep + "\n" + mdRows.slice(1).join("\n");
2397
+ }
2398
+ return mdRows.join("\n");
2399
+ }
2400
+ });
2345
2401
  content = htmlToMarkdown(html, { onlyMainContent: p.onlyMainContent });
2402
+ if (tablesMd) {
2403
+ content = tablesMd + "\n\n" + content;
2404
+ }
2346
2405
  break;
2406
+ }
2347
2407
  case "html":
2348
2408
  content = html;
2349
2409
  break;
@@ -5283,6 +5343,7 @@ function parseCommandChain(input, options) {
5283
5343
  continue;
5284
5344
  }
5285
5345
  if (char === ";") {
5346
+ lastOperator = "sequence";
5286
5347
  flushPipeline();
5287
5348
  continue;
5288
5349
  }
@@ -5337,6 +5398,7 @@ registerCommandDefinition("uncheck", ["selector"]);
5337
5398
  registerCommandDefinition("hover", ["selector"]);
5338
5399
  registerCommandDefinition("dblclick", ["selector"]);
5339
5400
  registerCommandDefinition("wait", ["selector"]);
5401
+ registerCommandDefinition("waitForTimeout", ["timeout"]);
5340
5402
  registerCommandDefinition("screenshot", []);
5341
5403
  registerCommandDefinition("eval", ["expression"]);
5342
5404
  registerCommandDefinition("scroll", ["direction"]);
@@ -6969,7 +7031,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6969
7031
  }
6970
7032
  let targetPageOverride = null;
6971
7033
  if (_target && extraOpts?.cdpEndpoint) {
6972
- const { findTargetPage } = await import("./browser-DZVIVKOA.js");
7034
+ const { findTargetPage } = await import("./browser-PZX7PO23.js");
6973
7035
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
6974
7036
  if (!targetPageOverride) {
6975
7037
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -9477,7 +9539,17 @@ var SELECTOR_COMMANDS = /* @__PURE__ */ new Set([
9477
9539
  "dblclick",
9478
9540
  "wait"
9479
9541
  ]);
9542
+ var CAMEL_TO_KEBAB = {
9543
+ getCookies: "get-cookies",
9544
+ setCookie: "set-cookie",
9545
+ clearCookies: "clear-cookies",
9546
+ getLocalStorage: "get-local-storage",
9547
+ setLocalStorage: "set-local-storage",
9548
+ clearLocalStorage: "clear-local-storage",
9549
+ setViewport: "set-viewport"
9550
+ };
9480
9551
  async function handleBrowserCommand(command, args, options, sessionName, mode, cdpEndpoint) {
9552
+ command = CAMEL_TO_KEBAB[command] || command;
9481
9553
  if (args.includes("--help") || args.includes("-h") || options.help || options.h) {
9482
9554
  const cmdDef = getCommand(command);
9483
9555
  if (cmdDef) {
@@ -9607,7 +9679,7 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
9607
9679
  type: options.type,
9608
9680
  selector: options.selector || options.s,
9609
9681
  base64: !!options.base64,
9610
- output: options.output || options.o
9682
+ output: options.output || options.o || args[0]
9611
9683
  };
9612
9684
  break;
9613
9685
  case "eval":
@@ -9844,6 +9916,7 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
9844
9916
  outputResult(result.data, mode);
9845
9917
  console.error(`
9846
9918
  \u26A0\uFE0F ${hint}`);
9919
+ process.exit(1);
9847
9920
  } else {
9848
9921
  outputResult(result.data, mode);
9849
9922
  }
@@ -9938,11 +10011,6 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
9938
10011
  }
9939
10012
 
9940
10013
  // src/cli/plugin-routes.ts
9941
- var pluginLoader3 = null;
9942
- function getPluginLoader2() {
9943
- if (!pluginLoader3) pluginLoader3 = new XBrowserPluginLoader();
9944
- return pluginLoader3;
9945
- }
9946
10014
  async function buildRuntimePluginInfo() {
9947
10015
  const loader = await getPluginLoader();
9948
10016
  const sites = loader.getCore().loader.getSites();
@@ -10200,6 +10268,10 @@ async function handlePlugin(args, options, mode) {
10200
10268
  } else {
10201
10269
  result = await installer.installWithMarketplaceFallback(source, installOpts);
10202
10270
  }
10271
+ try {
10272
+ await (await getPluginLoader()).reloadPlugin(result.name);
10273
+ } catch {
10274
+ }
10203
10275
  outputResult(
10204
10276
  { ok: true, name: result.name, source: result.source, path: result.path },
10205
10277
  mode
@@ -10215,6 +10287,11 @@ async function handlePlugin(args, options, mode) {
10215
10287
  outputError(`Plugin "${name}" is not installed. Use 'xbrowser plugin list' to see installed plugins.`);
10216
10288
  }
10217
10289
  await installer.uninstall(name);
10290
+ try {
10291
+ const loader = await getPluginLoader();
10292
+ await loader.reloadPlugin(name);
10293
+ } catch {
10294
+ }
10218
10295
  outputResult({ ok: true, name }, mode);
10219
10296
  break;
10220
10297
  }
@@ -10268,7 +10345,7 @@ Total: ${enrichedPlugins.length} plugins`);
10268
10345
  case "reload": {
10269
10346
  const name = subArgs[0];
10270
10347
  if (!name) outputError("Usage: xbrowser plugin reload <name>");
10271
- await getPluginLoader2().reloadPlugin(name);
10348
+ (await getPluginLoader()).reloadPlugin(name);
10272
10349
  outputResult({ ok: true, name }, mode);
10273
10350
  break;
10274
10351
  }
@@ -12116,10 +12193,18 @@ function extractCdpFromArgv(argv) {
12116
12193
  async function handleStdinMode(stdinCommands, argv) {
12117
12194
  const chain = stdinCommands.join(" && ");
12118
12195
  const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
12119
- const chainResult = await executeChain(chain, { fileMode: true, cdpEndpoint });
12196
+ const sessionName = argv ? extractSessionNameFromArgv(argv) : "default";
12197
+ const chainResult = await executeChain(chain, { fileMode: true, cdpEndpoint, sessionName });
12120
12198
  printChainResult(chainResult);
12121
12199
  if (!chainResult.success) throw new Error("Command failed");
12122
12200
  }
12201
+ function extractSessionNameFromArgv(argv) {
12202
+ for (let i = 0; i < argv.length; i++) {
12203
+ if (argv[i] === "--session" && argv[i + 1]) return argv[i + 1];
12204
+ if (typeof argv[i] === "string" && argv[i].startsWith("--session=")) return argv[i].slice(10);
12205
+ }
12206
+ return process.env.XBROWSER_SESSION || "default";
12207
+ }
12123
12208
  async function handleEvalMode(argv) {
12124
12209
  const evalCommands = parseEvalFlags(argv);
12125
12210
  if (evalCommands.length === 0) return;
@@ -12259,6 +12344,31 @@ async function routeCommand(argvIn, stdinCommands) {
12259
12344
  }
12260
12345
  return;
12261
12346
  }
12347
+ const SUBCOMMAND_HELP = {
12348
+ session: "session open|close|kill|list [--session <name>] [--cdp <endpoint>]",
12349
+ plugin: "plugin install|uninstall|list|reload|schema|search|info <name>",
12350
+ record: "record start|stop|status [--url <url>] [--name <flow>]",
12351
+ daemon: "daemon status [--port <port>]",
12352
+ replay: "replay <file> [--slow-mo <ms>] [--stop-on-error]",
12353
+ create: "create <name> [--template static|dynamic|login|api]",
12354
+ run: "run <file>",
12355
+ serve: "serve [--port <port>] [--token <token>]",
12356
+ remote: "remote <url> [command] [--token <token>]",
12357
+ convert: "convert <file> [--to js|py|sh]",
12358
+ extract: "extract <file> [--format json|yaml]",
12359
+ filter: "filter <file> [--include <type>] [--exclude <type>]",
12360
+ test: "test <name> [--cdp <endpoint>]",
12361
+ viewer: "viewer [--session <name>]",
12362
+ kill: "kill [--all]",
12363
+ net: "net [--cdp <endpoint>]"
12364
+ };
12365
+ const subHelp = SUBCOMMAND_HELP[command];
12366
+ if (subHelp) {
12367
+ console.log(`
12368
+ Usage: xbrowser ${subHelp}
12369
+ `);
12370
+ return;
12371
+ }
12262
12372
  showMainHelp();
12263
12373
  return;
12264
12374
  }
@@ -12745,7 +12855,7 @@ async function main() {
12745
12855
  const command = process.argv[2];
12746
12856
  const isLongRunning = command === "preview" || command === "serve";
12747
12857
  if (!isLongRunning) {
12748
- const { ensureProcessCanExit } = await import("./browser-DZVIVKOA.js");
12858
+ const { ensureProcessCanExit } = await import("./browser-PZX7PO23.js");
12749
12859
  await ensureProcessCanExit().catch(() => {
12750
12860
  });
12751
12861
  process.exit(exitCode);
@@ -21,8 +21,8 @@ import {
21
21
  resolveLaunchOpts,
22
22
  saveSessionDiskMeta,
23
23
  setActivePage
24
- } from "./chunk-NDAMCPIJ.js";
25
- import "./chunk-E5WWMKXB.js";
24
+ } from "./chunk-SLQR57XZ.js";
25
+ import "./chunk-QFROODUU.js";
26
26
  import "./chunk-TNEN6VQ2.js";
27
27
  import {
28
28
  getDaemonConfig,
@@ -758,6 +758,21 @@ var waitForSelectorDef = {
758
758
  }
759
759
  };
760
760
  var waitCommand = registerCommand({ name: "wait", selectorParams: ["selector"], ...waitForSelectorDef });
761
+ var waitForTimeoutCommand = registerCommand({
762
+ name: "waitForTimeout",
763
+ description: "Wait for a specified number of milliseconds",
764
+ scope: "project",
765
+ parameters: z4.object({
766
+ timeout: z4.number().describe("Milliseconds to wait").default(1e3)
767
+ }),
768
+ result: z4.object({
769
+ waited: z4.number()
770
+ }),
771
+ handler: async (p) => {
772
+ await new Promise((r) => setTimeout(r, p.timeout));
773
+ return ok4({ waited: p.timeout });
774
+ }
775
+ });
761
776
 
762
777
  // src/commands/scroll.ts
763
778
  import { z as z5 } from "zod";
@@ -1623,7 +1638,7 @@ var healthCheckCommand = registerCommand({
1623
1638
  issues.push({
1624
1639
  severity: "error",
1625
1640
  category: "links",
1626
- message: `Broken link (fetch error): ${href} \u2014 ${errMsg(err) || "unknown"}`
1641
+ message: `Broken link (fetch error): ${href} \u2014 ${(err instanceof Error ? err.message : String(err)) || "unknown"}`
1627
1642
  });
1628
1643
  }
1629
1644
  }
@@ -2299,9 +2314,54 @@ var scrapeCommand = registerCommand({
2299
2314
  }
2300
2315
  let content;
2301
2316
  switch (p.format) {
2302
- case "markdown":
2317
+ case "markdown": {
2318
+ const tablesMd = await page.evaluate(() => {
2319
+ document.querySelectorAll(
2320
+ '.el-table__fixed, .el-table__fixed-right, [class*="fixed-left"], [class*="fixed-right"], .ant-table-fixed-left, .ant-table-fixed-right'
2321
+ ).forEach((el) => el.remove());
2322
+ document.querySelectorAll("table").forEach((t) => {
2323
+ if (t.closest(".el-table__fixed, .el-table__fixed-right")) t.remove();
2324
+ });
2325
+ const tables = document.querySelectorAll("table");
2326
+ if (tables.length === 0) {
2327
+ const altTables = document.querySelectorAll(
2328
+ '[role="table"], [role="grid"], .el-table__body, .ant-table-tbody'
2329
+ );
2330
+ if (altTables.length === 0) return "";
2331
+ return Array.from(altTables).map((table) => {
2332
+ return extractRowsFromContainer(table);
2333
+ }).filter((md) => md).join("\n\n");
2334
+ }
2335
+ return Array.from(tables).map((table) => {
2336
+ return extractRowsFromContainer(table);
2337
+ }).filter((md) => md).join("\n\n");
2338
+ function extractRowsFromContainer(container) {
2339
+ const rows = container.querySelectorAll(':scope > tr, :scope > thead > tr, :scope > tbody > tr, :scope > tfoot > tr, [role="row"]');
2340
+ if (rows.length === 0) return "";
2341
+ const mdRows = Array.from(rows).map((row) => {
2342
+ const cells = row.querySelectorAll(':scope > th, :scope > td, :scope > [role="columnheader"], :scope > [role="cell"]');
2343
+ if (cells.length === 0) return "";
2344
+ return "| " + Array.from(cells).map((c) => {
2345
+ const cellText = c.innerText?.trim().replace(/\n/g, " ") || "";
2346
+ return cellText.replace(/\|/g, "\\|") || "";
2347
+ }).join(" | ") + " |";
2348
+ }).filter((r) => r);
2349
+ if (mdRows.length === 0) return "";
2350
+ const headerRow = rows[0];
2351
+ const headerCells = headerRow.querySelectorAll(':scope > th, :scope > [role="columnheader"]');
2352
+ if (headerCells.length > 0) {
2353
+ const sep = "| " + Array(headerCells.length).fill("---").join(" | ") + " |";
2354
+ return mdRows[0] + "\n" + sep + "\n" + mdRows.slice(1).join("\n");
2355
+ }
2356
+ return mdRows.join("\n");
2357
+ }
2358
+ });
2303
2359
  content = htmlToMarkdown(html, { onlyMainContent: p.onlyMainContent });
2360
+ if (tablesMd) {
2361
+ content = tablesMd + "\n\n" + content;
2362
+ }
2304
2363
  break;
2364
+ }
2305
2365
  case "html":
2306
2366
  content = html;
2307
2367
  break;
@@ -5241,6 +5301,7 @@ function parseCommandChain(input, options) {
5241
5301
  continue;
5242
5302
  }
5243
5303
  if (char === ";") {
5304
+ lastOperator = "sequence";
5244
5305
  flushPipeline();
5245
5306
  continue;
5246
5307
  }
@@ -5295,6 +5356,7 @@ registerCommandDefinition("uncheck", ["selector"]);
5295
5356
  registerCommandDefinition("hover", ["selector"]);
5296
5357
  registerCommandDefinition("dblclick", ["selector"]);
5297
5358
  registerCommandDefinition("wait", ["selector"]);
5359
+ registerCommandDefinition("waitForTimeout", ["timeout"]);
5298
5360
  registerCommandDefinition("screenshot", []);
5299
5361
  registerCommandDefinition("eval", ["expression"]);
5300
5362
  registerCommandDefinition("scroll", ["direction"]);
@@ -6927,7 +6989,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6927
6989
  }
6928
6990
  let targetPageOverride = null;
6929
6991
  if (_target && extraOpts?.cdpEndpoint) {
6930
- const { findTargetPage } = await import("./browser-ZF4EJ3SK.js");
6992
+ const { findTargetPage } = await import("./browser-CWI6BXYK.js");
6931
6993
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
6932
6994
  if (!targetPageOverride) {
6933
6995
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -8611,7 +8673,7 @@ function createRPCHandler() {
8611
8673
  const isNewFormat = Array.isArray(parsed.actions);
8612
8674
  if (isNewFormat) {
8613
8675
  try {
8614
- const { SessionReplayer } = await import("./session-replayer-UHITXIOZ.js");
8676
+ const { SessionReplayer } = await import("./session-replayer-IXLSCF5U.js");
8615
8677
  const replayer = new SessionReplayer({
8616
8678
  page: session.page,
8617
8679
  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-OH7CB2P6.js";
85
- import "./chunk-E5WWMKXB.js";
84
+ } from "./chunk-6V57JME6.js";
85
+ import "./chunk-QFROODUU.js";
86
86
  import "./chunk-TNEN6VQ2.js";
87
87
  import {
88
88
  errMsg
@@ -840,6 +840,21 @@ var waitForSelectorDef = {
840
840
  }
841
841
  };
842
842
  var waitCommand = registerCommand({ name: "wait", selectorParams: ["selector"], ...waitForSelectorDef });
843
+ var waitForTimeoutCommand = registerCommand({
844
+ name: "waitForTimeout",
845
+ description: "Wait for a specified number of milliseconds",
846
+ scope: "project",
847
+ parameters: z4.object({
848
+ timeout: z4.number().describe("Milliseconds to wait").default(1e3)
849
+ }),
850
+ result: z4.object({
851
+ waited: z4.number()
852
+ }),
853
+ handler: async (p) => {
854
+ await new Promise((r) => setTimeout(r, p.timeout));
855
+ return ok4({ waited: p.timeout });
856
+ }
857
+ });
843
858
 
844
859
  // src/commands/scroll.ts
845
860
  import { z as z5 } from "zod";
@@ -1705,7 +1720,7 @@ var healthCheckCommand = registerCommand({
1705
1720
  issues.push({
1706
1721
  severity: "error",
1707
1722
  category: "links",
1708
- message: `Broken link (fetch error): ${href} \u2014 ${errMsg(err) || "unknown"}`
1723
+ message: `Broken link (fetch error): ${href} \u2014 ${(err instanceof Error ? err.message : String(err)) || "unknown"}`
1709
1724
  });
1710
1725
  }
1711
1726
  }
@@ -2381,9 +2396,54 @@ var scrapeCommand = registerCommand({
2381
2396
  }
2382
2397
  let content;
2383
2398
  switch (p.format) {
2384
- case "markdown":
2399
+ case "markdown": {
2400
+ const tablesMd = await page.evaluate(() => {
2401
+ document.querySelectorAll(
2402
+ '.el-table__fixed, .el-table__fixed-right, [class*="fixed-left"], [class*="fixed-right"], .ant-table-fixed-left, .ant-table-fixed-right'
2403
+ ).forEach((el) => el.remove());
2404
+ document.querySelectorAll("table").forEach((t) => {
2405
+ if (t.closest(".el-table__fixed, .el-table__fixed-right")) t.remove();
2406
+ });
2407
+ const tables = document.querySelectorAll("table");
2408
+ if (tables.length === 0) {
2409
+ const altTables = document.querySelectorAll(
2410
+ '[role="table"], [role="grid"], .el-table__body, .ant-table-tbody'
2411
+ );
2412
+ if (altTables.length === 0) return "";
2413
+ return Array.from(altTables).map((table) => {
2414
+ return extractRowsFromContainer(table);
2415
+ }).filter((md) => md).join("\n\n");
2416
+ }
2417
+ return Array.from(tables).map((table) => {
2418
+ return extractRowsFromContainer(table);
2419
+ }).filter((md) => md).join("\n\n");
2420
+ function extractRowsFromContainer(container) {
2421
+ const rows = container.querySelectorAll(':scope > tr, :scope > thead > tr, :scope > tbody > tr, :scope > tfoot > tr, [role="row"]');
2422
+ if (rows.length === 0) return "";
2423
+ const mdRows = Array.from(rows).map((row) => {
2424
+ const cells = row.querySelectorAll(':scope > th, :scope > td, :scope > [role="columnheader"], :scope > [role="cell"]');
2425
+ if (cells.length === 0) return "";
2426
+ return "| " + Array.from(cells).map((c) => {
2427
+ const cellText = c.innerText?.trim().replace(/\n/g, " ") || "";
2428
+ return cellText.replace(/\|/g, "\\|") || "";
2429
+ }).join(" | ") + " |";
2430
+ }).filter((r) => r);
2431
+ if (mdRows.length === 0) return "";
2432
+ const headerRow = rows[0];
2433
+ const headerCells = headerRow.querySelectorAll(':scope > th, :scope > [role="columnheader"]');
2434
+ if (headerCells.length > 0) {
2435
+ const sep = "| " + Array(headerCells.length).fill("---").join(" | ") + " |";
2436
+ return mdRows[0] + "\n" + sep + "\n" + mdRows.slice(1).join("\n");
2437
+ }
2438
+ return mdRows.join("\n");
2439
+ }
2440
+ });
2385
2441
  content = htmlToMarkdown(html, { onlyMainContent: p.onlyMainContent });
2442
+ if (tablesMd) {
2443
+ content = tablesMd + "\n\n" + content;
2444
+ }
2386
2445
  break;
2446
+ }
2387
2447
  case "html":
2388
2448
  content = html;
2389
2449
  break;
@@ -5600,6 +5660,7 @@ function parseCommandChain(input, options) {
5600
5660
  continue;
5601
5661
  }
5602
5662
  if (char === ";") {
5663
+ lastOperator = "sequence";
5603
5664
  flushPipeline();
5604
5665
  continue;
5605
5666
  }
@@ -5654,6 +5715,7 @@ registerCommandDefinition("uncheck", ["selector"]);
5654
5715
  registerCommandDefinition("hover", ["selector"]);
5655
5716
  registerCommandDefinition("dblclick", ["selector"]);
5656
5717
  registerCommandDefinition("wait", ["selector"]);
5718
+ registerCommandDefinition("waitForTimeout", ["timeout"]);
5657
5719
  registerCommandDefinition("screenshot", []);
5658
5720
  registerCommandDefinition("eval", ["expression"]);
5659
5721
  registerCommandDefinition("scroll", ["direction"]);
@@ -7289,7 +7351,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7289
7351
  }
7290
7352
  let targetPageOverride = null;
7291
7353
  if (_target && extraOpts?.cdpEndpoint) {
7292
- const { findTargetPage } = await import("./browser-H55TWH2I.js");
7354
+ const { findTargetPage } = await import("./browser-JP2LFPR2.js");
7293
7355
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7294
7356
  if (!targetPageOverride) {
7295
7357
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -9817,7 +9879,17 @@ var SELECTOR_COMMANDS = /* @__PURE__ */ new Set([
9817
9879
  "dblclick",
9818
9880
  "wait"
9819
9881
  ]);
9882
+ var CAMEL_TO_KEBAB = {
9883
+ getCookies: "get-cookies",
9884
+ setCookie: "set-cookie",
9885
+ clearCookies: "clear-cookies",
9886
+ getLocalStorage: "get-local-storage",
9887
+ setLocalStorage: "set-local-storage",
9888
+ clearLocalStorage: "clear-local-storage",
9889
+ setViewport: "set-viewport"
9890
+ };
9820
9891
  async function handleBrowserCommand(command, args, options, sessionName, mode, cdpEndpoint) {
9892
+ command = CAMEL_TO_KEBAB[command] || command;
9821
9893
  if (args.includes("--help") || args.includes("-h") || options.help || options.h) {
9822
9894
  const cmdDef = getCommand(command);
9823
9895
  if (cmdDef) {
@@ -9947,7 +10019,7 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
9947
10019
  type: options.type,
9948
10020
  selector: options.selector || options.s,
9949
10021
  base64: !!options.base64,
9950
- output: options.output || options.o
10022
+ output: options.output || options.o || args[0]
9951
10023
  };
9952
10024
  break;
9953
10025
  case "eval":
@@ -10184,6 +10256,7 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
10184
10256
  outputResult(result.data, mode);
10185
10257
  console.error(`
10186
10258
  \u26A0\uFE0F ${hint}`);
10259
+ process.exit(1);
10187
10260
  } else {
10188
10261
  outputResult(result.data, mode);
10189
10262
  }
@@ -10278,11 +10351,6 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
10278
10351
  }
10279
10352
 
10280
10353
  // src/cli/plugin-routes.ts
10281
- var pluginLoader3 = null;
10282
- function getPluginLoader2() {
10283
- if (!pluginLoader3) pluginLoader3 = new XBrowserPluginLoader();
10284
- return pluginLoader3;
10285
- }
10286
10354
  async function buildRuntimePluginInfo() {
10287
10355
  const loader = await getPluginLoader();
10288
10356
  const sites = loader.getCore().loader.getSites();
@@ -10540,6 +10608,10 @@ async function handlePlugin(args, options, mode) {
10540
10608
  } else {
10541
10609
  result = await installer.installWithMarketplaceFallback(source, installOpts);
10542
10610
  }
10611
+ try {
10612
+ await (await getPluginLoader()).reloadPlugin(result.name);
10613
+ } catch {
10614
+ }
10543
10615
  outputResult(
10544
10616
  { ok: true, name: result.name, source: result.source, path: result.path },
10545
10617
  mode
@@ -10555,6 +10627,11 @@ async function handlePlugin(args, options, mode) {
10555
10627
  outputError(`Plugin "${name}" is not installed. Use 'xbrowser plugin list' to see installed plugins.`);
10556
10628
  }
10557
10629
  await installer.uninstall(name);
10630
+ try {
10631
+ const loader = await getPluginLoader();
10632
+ await loader.reloadPlugin(name);
10633
+ } catch {
10634
+ }
10558
10635
  outputResult({ ok: true, name }, mode);
10559
10636
  break;
10560
10637
  }
@@ -10608,7 +10685,7 @@ Total: ${enrichedPlugins.length} plugins`);
10608
10685
  case "reload": {
10609
10686
  const name = subArgs[0];
10610
10687
  if (!name) outputError("Usage: xbrowser plugin reload <name>");
10611
- await getPluginLoader2().reloadPlugin(name);
10688
+ (await getPluginLoader()).reloadPlugin(name);
10612
10689
  outputResult({ ok: true, name }, mode);
10613
10690
  break;
10614
10691
  }
@@ -12456,10 +12533,18 @@ function extractCdpFromArgv(argv) {
12456
12533
  async function handleStdinMode(stdinCommands, argv) {
12457
12534
  const chain = stdinCommands.join(" && ");
12458
12535
  const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
12459
- const chainResult = await executeChain(chain, { fileMode: true, cdpEndpoint });
12536
+ const sessionName = argv ? extractSessionNameFromArgv(argv) : "default";
12537
+ const chainResult = await executeChain(chain, { fileMode: true, cdpEndpoint, sessionName });
12460
12538
  printChainResult(chainResult);
12461
12539
  if (!chainResult.success) throw new Error("Command failed");
12462
12540
  }
12541
+ function extractSessionNameFromArgv(argv) {
12542
+ for (let i = 0; i < argv.length; i++) {
12543
+ if (argv[i] === "--session" && argv[i + 1]) return argv[i + 1];
12544
+ if (typeof argv[i] === "string" && argv[i].startsWith("--session=")) return argv[i].slice(10);
12545
+ }
12546
+ return process.env.XBROWSER_SESSION || "default";
12547
+ }
12463
12548
  async function handleEvalMode(argv) {
12464
12549
  const evalCommands = parseEvalFlags(argv);
12465
12550
  if (evalCommands.length === 0) return;
@@ -12599,6 +12684,31 @@ async function routeCommand(argvIn, stdinCommands) {
12599
12684
  }
12600
12685
  return;
12601
12686
  }
12687
+ const SUBCOMMAND_HELP = {
12688
+ session: "session open|close|kill|list [--session <name>] [--cdp <endpoint>]",
12689
+ plugin: "plugin install|uninstall|list|reload|schema|search|info <name>",
12690
+ record: "record start|stop|status [--url <url>] [--name <flow>]",
12691
+ daemon: "daemon status [--port <port>]",
12692
+ replay: "replay <file> [--slow-mo <ms>] [--stop-on-error]",
12693
+ create: "create <name> [--template static|dynamic|login|api]",
12694
+ run: "run <file>",
12695
+ serve: "serve [--port <port>] [--token <token>]",
12696
+ remote: "remote <url> [command] [--token <token>]",
12697
+ convert: "convert <file> [--to js|py|sh]",
12698
+ extract: "extract <file> [--format json|yaml]",
12699
+ filter: "filter <file> [--include <type>] [--exclude <type>]",
12700
+ test: "test <name> [--cdp <endpoint>]",
12701
+ viewer: "viewer [--session <name>]",
12702
+ kill: "kill [--all]",
12703
+ net: "net [--cdp <endpoint>]"
12704
+ };
12705
+ const subHelp = SUBCOMMAND_HELP[command];
12706
+ if (subHelp) {
12707
+ console.log(`
12708
+ Usage: xbrowser ${subHelp}
12709
+ `);
12710
+ return;
12711
+ }
12602
12712
  showMainHelp();
12603
12713
  return;
12604
12714
  }
@@ -15872,7 +15982,7 @@ var DataCollector = class {
15872
15982
  return results;
15873
15983
  }
15874
15984
  async createBrowserContext() {
15875
- const { launch } = await import("./cdp-driver-WWQBRTPF.js");
15985
+ const { launch } = await import("./cdp-driver-S5STYUZZ.js");
15876
15986
  const { browser } = await launch({
15877
15987
  headless: true,
15878
15988
  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-WWQBRTPF.js");
34
+ const { launch } = await import("./cdp-driver-S5STYUZZ.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.1.2",
3
+ "version": "1.2.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": {
@@ -96,7 +96,7 @@
96
96
  "sharp": "^0.34.5",
97
97
  "turndown": "^7.2.4",
98
98
  "turndown-plugin-gfm": "^1.0.2",
99
- "ws": "^8.20.0",
99
+ "ws": "^8.21.0",
100
100
  "yaml": "^2.8.4",
101
101
  "zod": "^3.24.0"
102
102
  },