@xbrowser/cli 1.4.7 → 1.5.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.
@@ -20,7 +20,7 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-RGS6ECTH.js";
23
+ } from "./chunk-H7R352A2.js";
24
24
  import "./chunk-TNEN6VQ2.js";
25
25
  import "./chunk-GDKLH7ZY.js";
26
26
  import "./chunk-KFQGP6VL.js";
@@ -20,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-NQSFETTQ.js";
24
- import "./chunk-2RHJEYWU.js";
23
+ } from "./chunk-WCM4FNUB.js";
24
+ import "./chunk-74QM55TC.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-KFQGP6VL.js";
@@ -20,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-LYVU6SD3.js";
24
- import "./chunk-2RHJEYWU.js";
23
+ } from "./chunk-MKEAO3XJ.js";
24
+ import "./chunk-74QM55TC.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-ABXMBNQ6.js";
@@ -303,6 +303,18 @@ function queryAllJS(selector) {
303
303
  async function waitForActionable(page, selector, opts = {}) {
304
304
  const timeout = opts.timeout ?? 3e4;
305
305
  if (opts.force) {
306
+ if (selector.startsWith("xpath=")) {
307
+ const rect2 = await page.evaluate(`
308
+ (function() {
309
+ const el = ${queryJS(selector)};
310
+ if (!el) return null;
311
+ const r = el.getBoundingClientRect();
312
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
313
+ })()
314
+ `);
315
+ if (!rect2) throw new Error(`Element not found: ${selector}`);
316
+ return { nodeId: 0, rect: rect2 };
317
+ }
306
318
  const nodeId = await page.querySelector(selector);
307
319
  if (!nodeId) throw new Error(`Element not found: ${selector}`);
308
320
  const rect = await page.getBoxModel(nodeId);
@@ -1165,17 +1177,43 @@ var XBPageImpl = class _XBPageImpl {
1165
1177
  headers: () => headers
1166
1178
  };
1167
1179
  }
1168
- async goBack(_opts = {}) {
1169
- const prevUrl = await this.evaluate("location.href").catch(() => "");
1180
+ async goBack(opts = {}) {
1181
+ try {
1182
+ const navHistory = await this.conn.send("Page.getNavigationHistory", void 0, this.sessionId);
1183
+ if (navHistory.currentIndex > 0) {
1184
+ const prevUrl = navHistory.entries[navHistory.currentIndex - 1]?.url;
1185
+ if (prevUrl && prevUrl !== "about:blank") {
1186
+ await this.conn.send("Page.navigate", { url: prevUrl }, this.sessionId);
1187
+ await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 1e4).catch(() => {
1188
+ });
1189
+ this._url = prevUrl;
1190
+ return;
1191
+ }
1192
+ }
1193
+ } catch {
1194
+ }
1170
1195
  await this.evaluate("() => history.back()");
1171
- await this.waitForTimeout(2e3);
1172
- this._url = await this.evaluate("location.href").catch(() => prevUrl);
1196
+ await this.waitForTimeout(3e3);
1197
+ this._url = await this.evaluate("location.href").catch(() => this._url);
1173
1198
  }
1174
- async goForward(_opts = {}) {
1175
- const prevUrl = await this.evaluate("location.href").catch(() => "");
1199
+ async goForward(opts = {}) {
1200
+ try {
1201
+ const navHistory = await this.conn.send("Page.getNavigationHistory", void 0, this.sessionId);
1202
+ if (navHistory.currentIndex < navHistory.entries.length - 1) {
1203
+ const nextUrl = navHistory.entries[navHistory.currentIndex + 1]?.url;
1204
+ if (nextUrl && nextUrl !== "about:blank") {
1205
+ await this.conn.send("Page.navigate", { url: nextUrl }, this.sessionId);
1206
+ await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 1e4).catch(() => {
1207
+ });
1208
+ this._url = nextUrl;
1209
+ return;
1210
+ }
1211
+ }
1212
+ } catch {
1213
+ }
1176
1214
  await this.evaluate("() => history.forward()");
1177
- await this.waitForTimeout(2e3);
1178
- this._url = await this.evaluate("location.href").catch(() => prevUrl);
1215
+ await this.waitForTimeout(3e3);
1216
+ this._url = await this.evaluate("location.href").catch(() => this._url);
1179
1217
  }
1180
1218
  async reload(opts = {}) {
1181
1219
  this._loadState = { loadFired: false, domContentFired: false, networkIdle: false };
@@ -1656,6 +1694,22 @@ Last error: ${lastError.message}` : "";
1656
1694
  // ── CDP helpers exposed for locator/element ─────────────────
1657
1695
  /** Query a single element, returns CDP nodeId or 0 if not found */
1658
1696
  async querySelector(selector) {
1697
+ if (selector.startsWith("xpath=")) {
1698
+ const found = await this.evaluate(`
1699
+ (() => { const el = ${queryJS(selector)}; return !!el; })()
1700
+ `).catch(() => false);
1701
+ if (!found) return 0;
1702
+ try {
1703
+ const search = await this.conn.send(
1704
+ "DOM.performSearch",
1705
+ { query: selector.slice(6) },
1706
+ this.sessionId
1707
+ );
1708
+ if (search.nodeId) return search.nodeId;
1709
+ } catch {
1710
+ }
1711
+ return 1;
1712
+ }
1659
1713
  const doc = await this.conn.send(
1660
1714
  "DOM.getDocument",
1661
1715
  { depth: 0 },
@@ -14,7 +14,7 @@ import {
14
14
  scrollIntoView,
15
15
  waitForActionable,
16
16
  waitForNetworkIdle
17
- } from "./chunk-2RHJEYWU.js";
17
+ } from "./chunk-74QM55TC.js";
18
18
  import {
19
19
  connectToCDP,
20
20
  findChrome,
@@ -302,6 +302,18 @@ function queryAllJS(selector) {
302
302
  async function waitForActionable(page, selector, opts = {}) {
303
303
  const timeout = opts.timeout ?? 3e4;
304
304
  if (opts.force) {
305
+ if (selector.startsWith("xpath=")) {
306
+ const rect2 = await page.evaluate(`
307
+ (function() {
308
+ const el = ${queryJS(selector)};
309
+ if (!el) return null;
310
+ const r = el.getBoundingClientRect();
311
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
312
+ })()
313
+ `);
314
+ if (!rect2) throw new Error(`Element not found: ${selector}`);
315
+ return { nodeId: 0, rect: rect2 };
316
+ }
305
317
  const nodeId = await page.querySelector(selector);
306
318
  if (!nodeId) throw new Error(`Element not found: ${selector}`);
307
319
  const rect = await page.getBoxModel(nodeId);
@@ -1164,17 +1176,43 @@ var XBPageImpl = class _XBPageImpl {
1164
1176
  headers: () => headers
1165
1177
  };
1166
1178
  }
1167
- async goBack(_opts = {}) {
1168
- const prevUrl = await this.evaluate("location.href").catch(() => "");
1179
+ async goBack(opts = {}) {
1180
+ try {
1181
+ const navHistory = await this.conn.send("Page.getNavigationHistory", void 0, this.sessionId);
1182
+ if (navHistory.currentIndex > 0) {
1183
+ const prevUrl = navHistory.entries[navHistory.currentIndex - 1]?.url;
1184
+ if (prevUrl && prevUrl !== "about:blank") {
1185
+ await this.conn.send("Page.navigate", { url: prevUrl }, this.sessionId);
1186
+ await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 1e4).catch(() => {
1187
+ });
1188
+ this._url = prevUrl;
1189
+ return;
1190
+ }
1191
+ }
1192
+ } catch {
1193
+ }
1169
1194
  await this.evaluate("() => history.back()");
1170
- await this.waitForTimeout(2e3);
1171
- this._url = await this.evaluate("location.href").catch(() => prevUrl);
1195
+ await this.waitForTimeout(3e3);
1196
+ this._url = await this.evaluate("location.href").catch(() => this._url);
1172
1197
  }
1173
- async goForward(_opts = {}) {
1174
- const prevUrl = await this.evaluate("location.href").catch(() => "");
1198
+ async goForward(opts = {}) {
1199
+ try {
1200
+ const navHistory = await this.conn.send("Page.getNavigationHistory", void 0, this.sessionId);
1201
+ if (navHistory.currentIndex < navHistory.entries.length - 1) {
1202
+ const nextUrl = navHistory.entries[navHistory.currentIndex + 1]?.url;
1203
+ if (nextUrl && nextUrl !== "about:blank") {
1204
+ await this.conn.send("Page.navigate", { url: nextUrl }, this.sessionId);
1205
+ await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 1e4).catch(() => {
1206
+ });
1207
+ this._url = nextUrl;
1208
+ return;
1209
+ }
1210
+ }
1211
+ } catch {
1212
+ }
1175
1213
  await this.evaluate("() => history.forward()");
1176
- await this.waitForTimeout(2e3);
1177
- this._url = await this.evaluate("location.href").catch(() => prevUrl);
1214
+ await this.waitForTimeout(3e3);
1215
+ this._url = await this.evaluate("location.href").catch(() => this._url);
1178
1216
  }
1179
1217
  async reload(opts = {}) {
1180
1218
  this._loadState = { loadFired: false, domContentFired: false, networkIdle: false };
@@ -1655,6 +1693,22 @@ Last error: ${lastError.message}` : "";
1655
1693
  // ── CDP helpers exposed for locator/element ─────────────────
1656
1694
  /** Query a single element, returns CDP nodeId or 0 if not found */
1657
1695
  async querySelector(selector) {
1696
+ if (selector.startsWith("xpath=")) {
1697
+ const found = await this.evaluate(`
1698
+ (() => { const el = ${queryJS(selector)}; return !!el; })()
1699
+ `).catch(() => false);
1700
+ if (!found) return 0;
1701
+ try {
1702
+ const search = await this.conn.send(
1703
+ "DOM.performSearch",
1704
+ { query: selector.slice(6) },
1705
+ this.sessionId
1706
+ );
1707
+ if (search.nodeId) return search.nodeId;
1708
+ } catch {
1709
+ }
1710
+ return 1;
1711
+ }
1658
1712
  const doc = await this.conn.send(
1659
1713
  "DOM.getDocument",
1660
1714
  { depth: 0 },
@@ -308,6 +308,18 @@ function queryAllJS(selector) {
308
308
  async function waitForActionable(page, selector, opts = {}) {
309
309
  const timeout = opts.timeout ?? 3e4;
310
310
  if (opts.force) {
311
+ if (selector.startsWith("xpath=")) {
312
+ const rect2 = await page.evaluate(`
313
+ (function() {
314
+ const el = ${queryJS(selector)};
315
+ if (!el) return null;
316
+ const r = el.getBoundingClientRect();
317
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
318
+ })()
319
+ `);
320
+ if (!rect2) throw new Error(`Element not found: ${selector}`);
321
+ return { nodeId: 0, rect: rect2 };
322
+ }
311
323
  const nodeId = await page.querySelector(selector);
312
324
  if (!nodeId) throw new Error(`Element not found: ${selector}`);
313
325
  const rect = await page.getBoxModel(nodeId);
@@ -1170,17 +1182,43 @@ var XBPageImpl = class _XBPageImpl {
1170
1182
  headers: () => headers
1171
1183
  };
1172
1184
  }
1173
- async goBack(_opts = {}) {
1174
- const prevUrl = await this.evaluate("location.href").catch(() => "");
1185
+ async goBack(opts = {}) {
1186
+ try {
1187
+ const navHistory = await this.conn.send("Page.getNavigationHistory", void 0, this.sessionId);
1188
+ if (navHistory.currentIndex > 0) {
1189
+ const prevUrl = navHistory.entries[navHistory.currentIndex - 1]?.url;
1190
+ if (prevUrl && prevUrl !== "about:blank") {
1191
+ await this.conn.send("Page.navigate", { url: prevUrl }, this.sessionId);
1192
+ await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 1e4).catch(() => {
1193
+ });
1194
+ this._url = prevUrl;
1195
+ return;
1196
+ }
1197
+ }
1198
+ } catch {
1199
+ }
1175
1200
  await this.evaluate("() => history.back()");
1176
- await this.waitForTimeout(2e3);
1177
- this._url = await this.evaluate("location.href").catch(() => prevUrl);
1201
+ await this.waitForTimeout(3e3);
1202
+ this._url = await this.evaluate("location.href").catch(() => this._url);
1178
1203
  }
1179
- async goForward(_opts = {}) {
1180
- const prevUrl = await this.evaluate("location.href").catch(() => "");
1204
+ async goForward(opts = {}) {
1205
+ try {
1206
+ const navHistory = await this.conn.send("Page.getNavigationHistory", void 0, this.sessionId);
1207
+ if (navHistory.currentIndex < navHistory.entries.length - 1) {
1208
+ const nextUrl = navHistory.entries[navHistory.currentIndex + 1]?.url;
1209
+ if (nextUrl && nextUrl !== "about:blank") {
1210
+ await this.conn.send("Page.navigate", { url: nextUrl }, this.sessionId);
1211
+ await this.waitForLoadState(opts.waitUntil ?? "domcontentloaded", opts.timeout ?? 1e4).catch(() => {
1212
+ });
1213
+ this._url = nextUrl;
1214
+ return;
1215
+ }
1216
+ }
1217
+ } catch {
1218
+ }
1181
1219
  await this.evaluate("() => history.forward()");
1182
- await this.waitForTimeout(2e3);
1183
- this._url = await this.evaluate("location.href").catch(() => prevUrl);
1220
+ await this.waitForTimeout(3e3);
1221
+ this._url = await this.evaluate("location.href").catch(() => this._url);
1184
1222
  }
1185
1223
  async reload(opts = {}) {
1186
1224
  this._loadState = { loadFired: false, domContentFired: false, networkIdle: false };
@@ -1661,6 +1699,22 @@ Last error: ${lastError.message}` : "";
1661
1699
  // ── CDP helpers exposed for locator/element ─────────────────
1662
1700
  /** Query a single element, returns CDP nodeId or 0 if not found */
1663
1701
  async querySelector(selector) {
1702
+ if (selector.startsWith("xpath=")) {
1703
+ const found = await this.evaluate(`
1704
+ (() => { const el = ${queryJS(selector)}; return !!el; })()
1705
+ `).catch(() => false);
1706
+ if (!found) return 0;
1707
+ try {
1708
+ const search = await this.conn.send(
1709
+ "DOM.performSearch",
1710
+ { query: selector.slice(6) },
1711
+ this.sessionId
1712
+ );
1713
+ if (search.nodeId) return search.nodeId;
1714
+ } catch {
1715
+ }
1716
+ return 1;
1717
+ }
1664
1718
  const doc = await this.conn.send(
1665
1719
  "DOM.getDocument",
1666
1720
  { depth: 0 },
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-2RHJEYWU.js";
3
+ } from "./chunk-74QM55TC.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-2RHJEYWU.js";
3
+ } from "./chunk-74QM55TC.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
package/dist/cli.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  resolveLaunchOpts,
26
26
  saveSessionDiskMeta,
27
27
  setActivePage
28
- } from "./chunk-RGS6ECTH.js";
28
+ } from "./chunk-H7R352A2.js";
29
29
  import "./chunk-TNEN6VQ2.js";
30
30
  import {
31
31
  forwardCommandLog,
@@ -1208,9 +1208,9 @@ var setViewportCommand = registerCommand({
1208
1208
  description: "Set the viewport size and properties",
1209
1209
  scope: "browser",
1210
1210
  parameters: z11.object({
1211
- width: z11.number(),
1212
- height: z11.number(),
1213
- deviceScaleFactor: z11.number().optional(),
1211
+ width: z11.coerce.number(),
1212
+ height: z11.coerce.number(),
1213
+ deviceScaleFactor: z11.coerce.number().optional(),
1214
1214
  isMobile: z11.boolean().optional(),
1215
1215
  hasTouch: z11.boolean().optional()
1216
1216
  }),
@@ -7083,7 +7083,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7083
7083
  }
7084
7084
  let targetPageOverride = null;
7085
7085
  if (_target && extraOpts?.cdpEndpoint) {
7086
- const { findTargetPage } = await import("./browser-SOML2EWR.js");
7086
+ const { findTargetPage } = await import("./browser-2FJ4OO4H.js");
7087
7087
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7088
7088
  if (!targetPageOverride) {
7089
7089
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -11744,8 +11744,13 @@ Commands:
11744
11744
  session close [--session <name>] Close session
11745
11745
  session list List sessions
11746
11746
  session kill [--session <name>] Kill session
11747
+
11747
11748
  goto <url> Navigate to URL
11748
11749
  open <url> Navigate to URL (alias for goto)
11750
+ back Go back in history
11751
+ forward Go forward in history
11752
+ refresh Reload page
11753
+
11749
11754
  click <selector> Click element (-s <sel>)
11750
11755
  fill <selector> <value> Fill input (-s <sel> -v <val>)
11751
11756
  type <selector> <text> Type text (-s <sel> -v <text>)
@@ -11755,21 +11760,61 @@ Commands:
11755
11760
  dblclick <selector> Double click (-s <sel>)
11756
11761
  check <selector> Check checkbox (-s <sel>)
11757
11762
  uncheck <selector> Uncheck checkbox (-s <sel>)
11758
- screenshot [--full-page] [--base64] Take screenshot (saves to ~/.xbrowser/screenshots/; use --base64 for inline data)
11763
+ mouse <action> <x> <y> Mouse move/click at coordinates
11764
+ scroll <direction> [--distance N] Scroll page
11765
+
11766
+ screenshot [--full-page] [--base64] Take screenshot
11759
11767
  eval <expression> Evaluate JS
11760
11768
  wait <selector> [--timeout <ms>] Wait for element (-s <sel>)
11761
- scroll <direction> [--distance N] Scroll page
11769
+ waitForTimeout <ms> Wait for milliseconds
11770
+ waitFor --text <t> Wait for text/url/selector predicate
11762
11771
  title Get page title
11763
11772
  url Get current URL
11764
11773
  html [--selector <sel>] Get HTML content
11765
11774
  text [--selector <sel>] Get text content
11775
+ find <strategy> <value> [--action click|fill|hover] Find element by text/role/label
11776
+
11777
+ set-viewport <width> <height> Set viewport size
11778
+ frames List all frames
11779
+ frame --index <n> Switch to frame
11780
+ tab list List browser tabs
11781
+ tab new <url> Open new tab
11782
+ tab close --index <n> Close tab
11783
+ tab switch --index <n> Switch to tab
11784
+
11785
+ get-cookies Get all cookies
11786
+ set-cookie <name> <value> Set cookie
11787
+ clear-cookies Clear cookies
11788
+ get-local-storage Get localStorage
11789
+ set-local-storage <key> <value> Set localStorage item
11790
+ clear-local-storage Clear localStorage
11791
+
11792
+ snapshot Get page snapshot with element refs
11793
+ observe AI agent: observe page state
11794
+ act AI agent: perform action
11795
+ actions <url> --action "..." Execute action sequence
11796
+
11797
+ console Get console messages
11798
+ net-debug Get network debug info
11799
+ perf Get performance metrics
11800
+ health Run page health check (SEO/links/errors)
11801
+ structure Get page DOM structure
11802
+ network <url> Capture network traffic
11803
+ addinitscript <script> Add init script
11804
+
11805
+ scrape <url> Scrape page to markdown
11806
+ crawl <url> Crawl website (multi-page)
11807
+ search "query" Search the web (--engine, --limit, --full)
11808
+ map <url> Discover all URLs on a website
11809
+
11766
11810
  convert <rec.yaml> <out.{js,py,sh}> Convert recording to script
11767
11811
  extract <rec.yaml> Extract LLM-ready summary
11768
11812
  filter <in.yaml> <out.yaml> Filter recording events
11769
- scrape <url> Scrape a page and convert to markdown
11770
- crawl <url> Crawl a website and extract content from multiple pages
11771
- search "query" Search the web and extract results (--engine, --limit, --full)
11772
- map <url> Discover all URLs on a website
11813
+ replay <file> Replay recording
11814
+ record start --url <url> Start recording
11815
+ record stop Stop recording
11816
+ record status Recording status
11817
+
11773
11818
  config <get|set|list> Manage config
11774
11819
  plugin search <query> Search for plugins
11775
11820
  plugin install <source> Install plugin
@@ -11777,16 +11822,12 @@ Commands:
11777
11822
  plugin list List plugins
11778
11823
  plugin reload <name> Reload plugin
11779
11824
  create <name> --template <type> Create plugin
11780
- serve [--port <port>] [--token <t>] Start HTTP server for remote access
11781
- remote <url> [command] [--token <t>] Execute command on remote server
11782
- record start --url <url> Start recording
11783
- record stop Stop recording
11784
- record status Recording status
11785
- replay <file> Replay recording
11825
+ serve [--port <port>] [--token <t>] Start HTTP server
11826
+ remote <url> [command] [--token <t>] Execute on remote server
11786
11827
  run <file> Execute commands from file
11787
- viewer [--name <n>] [--selector <sel>] Generate viewer URL
11828
+ viewer [--name <n>] Generate viewer URL
11788
11829
  help Show this help
11789
- --version, -v Show version
11830
+ --version Show version
11790
11831
  Plugin Commands:
11791
11832
  Installed plugins provide additional commands.
11792
11833
  Use 'xbrowser plugin list' to see installed plugins and their commands.
@@ -11832,7 +11873,7 @@ Global Flags:
11832
11873
  --session <name> Use specific session
11833
11874
  --cdp <endpoint> Connect via CDP (url, port, or 'auto')
11834
11875
  --help, -h Show help
11835
- `);
11876
+ `);
11836
11877
  }
11837
11878
 
11838
11879
  // src/cli/chain-output.ts
@@ -13059,7 +13100,7 @@ async function main() {
13059
13100
  const command = process.argv[2];
13060
13101
  const isLongRunning = command === "preview" || command === "serve";
13061
13102
  if (!isLongRunning) {
13062
- const { ensureProcessCanExit } = await import("./browser-SOML2EWR.js");
13103
+ const { ensureProcessCanExit } = await import("./browser-2FJ4OO4H.js");
13063
13104
  await ensureProcessCanExit().catch(() => {
13064
13105
  });
13065
13106
  process.exit(exitCode);
@@ -21,8 +21,8 @@ import {
21
21
  resolveLaunchOpts,
22
22
  saveSessionDiskMeta,
23
23
  setActivePage
24
- } from "./chunk-NQSFETTQ.js";
25
- import "./chunk-2RHJEYWU.js";
24
+ } from "./chunk-WCM4FNUB.js";
25
+ import "./chunk-74QM55TC.js";
26
26
  import "./chunk-TNEN6VQ2.js";
27
27
  import {
28
28
  getPluginLoader
@@ -1169,9 +1169,9 @@ var setViewportCommand = registerCommand({
1169
1169
  description: "Set the viewport size and properties",
1170
1170
  scope: "browser",
1171
1171
  parameters: z11.object({
1172
- width: z11.number(),
1173
- height: z11.number(),
1174
- deviceScaleFactor: z11.number().optional(),
1172
+ width: z11.coerce.number(),
1173
+ height: z11.coerce.number(),
1174
+ deviceScaleFactor: z11.coerce.number().optional(),
1175
1175
  isMobile: z11.boolean().optional(),
1176
1176
  hasTouch: z11.boolean().optional()
1177
1177
  }),
@@ -6614,7 +6614,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6614
6614
  }
6615
6615
  let targetPageOverride = null;
6616
6616
  if (_target && extraOpts?.cdpEndpoint) {
6617
- const { findTargetPage } = await import("./browser-2OK26HBS.js");
6617
+ const { findTargetPage } = await import("./browser-IS6DTR5Y.js");
6618
6618
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
6619
6619
  if (!targetPageOverride) {
6620
6620
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -8330,7 +8330,7 @@ function createRPCHandler() {
8330
8330
  const isNewFormat = Array.isArray(parsed.actions);
8331
8331
  if (isNewFormat) {
8332
8332
  try {
8333
- const { SessionReplayer } = await import("./session-replayer-YIGRIIDD.js");
8333
+ const { SessionReplayer } = await import("./session-replayer-SD2MWGP5.js");
8334
8334
  const replayer = new SessionReplayer({
8335
8335
  page: session.page,
8336
8336
  stepDelay: slowMo * 500,
package/dist/index.js CHANGED
@@ -81,8 +81,8 @@ import {
81
81
  resolveLaunchOpts,
82
82
  saveSessionDiskMeta,
83
83
  setActivePage
84
- } from "./chunk-LYVU6SD3.js";
85
- import "./chunk-2RHJEYWU.js";
84
+ } from "./chunk-MKEAO3XJ.js";
85
+ import "./chunk-74QM55TC.js";
86
86
  import "./chunk-TNEN6VQ2.js";
87
87
  import {
88
88
  errMsg
@@ -1248,9 +1248,9 @@ var setViewportCommand = registerCommand({
1248
1248
  description: "Set the viewport size and properties",
1249
1249
  scope: "browser",
1250
1250
  parameters: z11.object({
1251
- width: z11.number(),
1252
- height: z11.number(),
1253
- deviceScaleFactor: z11.number().optional(),
1251
+ width: z11.coerce.number(),
1252
+ height: z11.coerce.number(),
1253
+ deviceScaleFactor: z11.coerce.number().optional(),
1254
1254
  isMobile: z11.boolean().optional(),
1255
1255
  hasTouch: z11.boolean().optional()
1256
1256
  }),
@@ -7403,7 +7403,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7403
7403
  }
7404
7404
  let targetPageOverride = null;
7405
7405
  if (_target && extraOpts?.cdpEndpoint) {
7406
- const { findTargetPage } = await import("./browser-ZTTS2SVT.js");
7406
+ const { findTargetPage } = await import("./browser-ZFW2XADE.js");
7407
7407
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7408
7408
  if (!targetPageOverride) {
7409
7409
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -12084,8 +12084,13 @@ Commands:
12084
12084
  session close [--session <name>] Close session
12085
12085
  session list List sessions
12086
12086
  session kill [--session <name>] Kill session
12087
+
12087
12088
  goto <url> Navigate to URL
12088
12089
  open <url> Navigate to URL (alias for goto)
12090
+ back Go back in history
12091
+ forward Go forward in history
12092
+ refresh Reload page
12093
+
12089
12094
  click <selector> Click element (-s <sel>)
12090
12095
  fill <selector> <value> Fill input (-s <sel> -v <val>)
12091
12096
  type <selector> <text> Type text (-s <sel> -v <text>)
@@ -12095,21 +12100,61 @@ Commands:
12095
12100
  dblclick <selector> Double click (-s <sel>)
12096
12101
  check <selector> Check checkbox (-s <sel>)
12097
12102
  uncheck <selector> Uncheck checkbox (-s <sel>)
12098
- screenshot [--full-page] [--base64] Take screenshot (saves to ~/.xbrowser/screenshots/; use --base64 for inline data)
12103
+ mouse <action> <x> <y> Mouse move/click at coordinates
12104
+ scroll <direction> [--distance N] Scroll page
12105
+
12106
+ screenshot [--full-page] [--base64] Take screenshot
12099
12107
  eval <expression> Evaluate JS
12100
12108
  wait <selector> [--timeout <ms>] Wait for element (-s <sel>)
12101
- scroll <direction> [--distance N] Scroll page
12109
+ waitForTimeout <ms> Wait for milliseconds
12110
+ waitFor --text <t> Wait for text/url/selector predicate
12102
12111
  title Get page title
12103
12112
  url Get current URL
12104
12113
  html [--selector <sel>] Get HTML content
12105
12114
  text [--selector <sel>] Get text content
12115
+ find <strategy> <value> [--action click|fill|hover] Find element by text/role/label
12116
+
12117
+ set-viewport <width> <height> Set viewport size
12118
+ frames List all frames
12119
+ frame --index <n> Switch to frame
12120
+ tab list List browser tabs
12121
+ tab new <url> Open new tab
12122
+ tab close --index <n> Close tab
12123
+ tab switch --index <n> Switch to tab
12124
+
12125
+ get-cookies Get all cookies
12126
+ set-cookie <name> <value> Set cookie
12127
+ clear-cookies Clear cookies
12128
+ get-local-storage Get localStorage
12129
+ set-local-storage <key> <value> Set localStorage item
12130
+ clear-local-storage Clear localStorage
12131
+
12132
+ snapshot Get page snapshot with element refs
12133
+ observe AI agent: observe page state
12134
+ act AI agent: perform action
12135
+ actions <url> --action "..." Execute action sequence
12136
+
12137
+ console Get console messages
12138
+ net-debug Get network debug info
12139
+ perf Get performance metrics
12140
+ health Run page health check (SEO/links/errors)
12141
+ structure Get page DOM structure
12142
+ network <url> Capture network traffic
12143
+ addinitscript <script> Add init script
12144
+
12145
+ scrape <url> Scrape page to markdown
12146
+ crawl <url> Crawl website (multi-page)
12147
+ search "query" Search the web (--engine, --limit, --full)
12148
+ map <url> Discover all URLs on a website
12149
+
12106
12150
  convert <rec.yaml> <out.{js,py,sh}> Convert recording to script
12107
12151
  extract <rec.yaml> Extract LLM-ready summary
12108
12152
  filter <in.yaml> <out.yaml> Filter recording events
12109
- scrape <url> Scrape a page and convert to markdown
12110
- crawl <url> Crawl a website and extract content from multiple pages
12111
- search "query" Search the web and extract results (--engine, --limit, --full)
12112
- map <url> Discover all URLs on a website
12153
+ replay <file> Replay recording
12154
+ record start --url <url> Start recording
12155
+ record stop Stop recording
12156
+ record status Recording status
12157
+
12113
12158
  config <get|set|list> Manage config
12114
12159
  plugin search <query> Search for plugins
12115
12160
  plugin install <source> Install plugin
@@ -12117,16 +12162,12 @@ Commands:
12117
12162
  plugin list List plugins
12118
12163
  plugin reload <name> Reload plugin
12119
12164
  create <name> --template <type> Create plugin
12120
- serve [--port <port>] [--token <t>] Start HTTP server for remote access
12121
- remote <url> [command] [--token <t>] Execute command on remote server
12122
- record start --url <url> Start recording
12123
- record stop Stop recording
12124
- record status Recording status
12125
- replay <file> Replay recording
12165
+ serve [--port <port>] [--token <t>] Start HTTP server
12166
+ remote <url> [command] [--token <t>] Execute on remote server
12126
12167
  run <file> Execute commands from file
12127
- viewer [--name <n>] [--selector <sel>] Generate viewer URL
12168
+ viewer [--name <n>] Generate viewer URL
12128
12169
  help Show this help
12129
- --version, -v Show version
12170
+ --version Show version
12130
12171
  Plugin Commands:
12131
12172
  Installed plugins provide additional commands.
12132
12173
  Use 'xbrowser plugin list' to see installed plugins and their commands.
@@ -12172,7 +12213,7 @@ Global Flags:
12172
12213
  --session <name> Use specific session
12173
12214
  --cdp <endpoint> Connect via CDP (url, port, or 'auto')
12174
12215
  --help, -h Show help
12175
- `);
12216
+ `);
12176
12217
  }
12177
12218
 
12178
12219
  // src/cli/chain-output.ts
@@ -16186,7 +16227,7 @@ var DataCollector = class {
16186
16227
  return results;
16187
16228
  }
16188
16229
  async createBrowserContext() {
16189
- const { launch } = await import("./cdp-driver-UGO45HXR.js");
16230
+ const { launch } = await import("./cdp-driver-QHTXQRQ2.js");
16190
16231
  const { browser } = await launch({
16191
16232
  headless: true,
16192
16233
  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-UGO45HXR.js");
34
+ const { launch } = await import("./cdp-driver-QHTXQRQ2.js");
35
35
  const { browser } = await launch({ cdpEndpoint: this.opts.cdpUrl });
36
36
  let contexts = browser.contexts();
37
37
  for (let i = 0; i < 10 && contexts.length === 0; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xbrowser/cli",
3
- "version": "1.4.7",
3
+ "version": "1.5.0",
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": {