@xbrowser/cli 1.9.7 → 1.9.8

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,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-37SHZSUR.js";
24
- import "./chunk-VJNMAWPZ.js";
23
+ } from "./chunk-ENCEMM7Z.js";
24
+ import "./chunk-GM3HWQ5U.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-KFQGP6VL.js";
@@ -20,7 +20,7 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-74S7UUI2.js";
23
+ } from "./chunk-A4YHJW3Z.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-5JSOGINQ.js";
24
- import "./chunk-VJNMAWPZ.js";
23
+ } from "./chunk-PBDID7SE.js";
24
+ import "./chunk-GM3HWQ5U.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-ABXMBNQ6.js";
@@ -14,7 +14,7 @@ import {
14
14
  scrollIntoView,
15
15
  waitForActionable,
16
16
  waitForNetworkIdle
17
- } from "./chunk-VJNMAWPZ.js";
17
+ } from "./chunk-GM3HWQ5U.js";
18
18
  import {
19
19
  connectToCDP,
20
20
  findChrome,
@@ -1333,7 +1333,22 @@ Last error: ${lastError.message}` : "";
1333
1333
  return this._url;
1334
1334
  }
1335
1335
  async title() {
1336
- this._title = await this.evaluate("document.title");
1336
+ for (let i = 0; i < 20; i++) {
1337
+ try {
1338
+ this._title = await this.evaluate("document.title");
1339
+ if (this._title) return this._title;
1340
+ } catch {
1341
+ }
1342
+ await new Promise((r) => setTimeout(r, 50));
1343
+ }
1344
+ try {
1345
+ const info = await this._cdpSend("Target.getTargetInfo", { targetId: this._targetId });
1346
+ if (info?.title) {
1347
+ this._title = info.title;
1348
+ return this._title;
1349
+ }
1350
+ } catch {
1351
+ }
1337
1352
  return this._title;
1338
1353
  }
1339
1354
  async content() {
@@ -1338,7 +1338,22 @@ Last error: ${lastError.message}` : "";
1338
1338
  return this._url;
1339
1339
  }
1340
1340
  async title() {
1341
- this._title = await this.evaluate("document.title");
1341
+ for (let i = 0; i < 20; i++) {
1342
+ try {
1343
+ this._title = await this.evaluate("document.title");
1344
+ if (this._title) return this._title;
1345
+ } catch {
1346
+ }
1347
+ await new Promise((r) => setTimeout(r, 50));
1348
+ }
1349
+ try {
1350
+ const info = await this._cdpSend("Target.getTargetInfo", { targetId: this._targetId });
1351
+ if (info?.title) {
1352
+ this._title = info.title;
1353
+ return this._title;
1354
+ }
1355
+ } catch {
1356
+ }
1342
1357
  return this._title;
1343
1358
  }
1344
1359
  async content() {
@@ -4965,7 +4980,7 @@ async function closeSessionByName(name) {
4965
4980
  } catch {
4966
4981
  }
4967
4982
  try {
4968
- const { SessionRecorder } = await import("./session-recorder-RFOPX4SF.js");
4983
+ const { SessionRecorder } = await import("./session-recorder-AG6CH6EI.js");
4969
4984
  SessionRecorder.cleanup(session.name);
4970
4985
  } catch {
4971
4986
  }
@@ -2020,17 +2020,37 @@ var SessionRecorder = class _SessionRecorder {
2020
2020
  * selector or the screenshot fails (non-critical — never blocks recording).
2021
2021
  *
2022
2022
  * Only captures for: click, input, change, dblclick, and their CDP counterparts.
2023
+ *
2024
+ * Retry strategy (3 attempts, 3s each):
2025
+ * 1. element screenshot via locator
2026
+ * 2. retry element screenshot (element may have been animating/detached)
2027
+ * 3. fallback to viewport screenshot (so we always get *something*)
2023
2028
  */
2024
2029
  async captureElementScreenshot(page, action) {
2025
2030
  const keyTypes = ["click", "input", "change", "dblclick", "cdp-click", "cdp-fill", "filechooser"];
2026
2031
  if (!keyTypes.includes(action.type)) return;
2027
2032
  if (!action.element?.selector) return;
2033
+ const selector = action.element.selector;
2028
2034
  try {
2029
- const buffer = await page.locator(action.element.selector).first().screenshot({
2035
+ const buffer = await page.locator(selector).first().screenshot({
2030
2036
  type: "png",
2031
- timeout: 2e3
2037
+ timeout: 3e3
2032
2038
  });
2033
2039
  return buffer.toString("base64");
2040
+ } catch {
2041
+ }
2042
+ try {
2043
+ await page.waitForSelector(selector, { state: "visible", timeout: 2e3 });
2044
+ const buffer = await page.locator(selector).first().screenshot({
2045
+ type: "png",
2046
+ timeout: 3e3
2047
+ });
2048
+ return buffer.toString("base64");
2049
+ } catch {
2050
+ }
2051
+ try {
2052
+ const buffer = await page.screenshot({ type: "png", timeout: 3e3 });
2053
+ return buffer.toString("base64");
2034
2054
  } catch {
2035
2055
  return;
2036
2056
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-VJNMAWPZ.js";
3
+ } from "./chunk-GM3HWQ5U.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -2021,7 +2021,7 @@ async function closeSessionByName(name) {
2021
2021
  } catch {
2022
2022
  }
2023
2023
  try {
2024
- const { SessionRecorder } = await import("./session-recorder-7GXI42FO.js");
2024
+ const { SessionRecorder } = await import("./session-recorder-K3K63Q33.js");
2025
2025
  SessionRecorder.cleanup(session.name);
2026
2026
  } catch {
2027
2027
  }
@@ -1332,7 +1332,22 @@ Last error: ${lastError.message}` : "";
1332
1332
  return this._url;
1333
1333
  }
1334
1334
  async title() {
1335
- this._title = await this.evaluate("document.title");
1335
+ for (let i = 0; i < 20; i++) {
1336
+ try {
1337
+ this._title = await this.evaluate("document.title");
1338
+ if (this._title) return this._title;
1339
+ } catch {
1340
+ }
1341
+ await new Promise((r) => setTimeout(r, 50));
1342
+ }
1343
+ try {
1344
+ const info = await this._cdpSend("Target.getTargetInfo", { targetId: this._targetId });
1345
+ if (info?.title) {
1346
+ this._title = info.title;
1347
+ return this._title;
1348
+ }
1349
+ } catch {
1350
+ }
1336
1351
  return this._title;
1337
1352
  }
1338
1353
  async content() {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-VJNMAWPZ.js";
3
+ } from "./chunk-GM3HWQ5U.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -656,7 +656,7 @@ async function closeSessionByName(name) {
656
656
  } catch {
657
657
  }
658
658
  try {
659
- const { SessionRecorder } = await import("./session-recorder-RFOPX4SF.js");
659
+ const { SessionRecorder } = await import("./session-recorder-AG6CH6EI.js");
660
660
  SessionRecorder.cleanup(session.name);
661
661
  } catch {
662
662
  }
@@ -2417,17 +2417,37 @@ var SessionRecorder = class _SessionRecorder {
2417
2417
  * selector or the screenshot fails (non-critical — never blocks recording).
2418
2418
  *
2419
2419
  * Only captures for: click, input, change, dblclick, and their CDP counterparts.
2420
+ *
2421
+ * Retry strategy (3 attempts, 3s each):
2422
+ * 1. element screenshot via locator
2423
+ * 2. retry element screenshot (element may have been animating/detached)
2424
+ * 3. fallback to viewport screenshot (so we always get *something*)
2420
2425
  */
2421
2426
  async captureElementScreenshot(page, action) {
2422
2427
  const keyTypes = ["click", "input", "change", "dblclick", "cdp-click", "cdp-fill", "filechooser"];
2423
2428
  if (!keyTypes.includes(action.type)) return;
2424
2429
  if (!action.element?.selector) return;
2430
+ const selector = action.element.selector;
2425
2431
  try {
2426
- const buffer = await page.locator(action.element.selector).first().screenshot({
2432
+ const buffer = await page.locator(selector).first().screenshot({
2427
2433
  type: "png",
2428
- timeout: 2e3
2434
+ timeout: 3e3
2429
2435
  });
2430
2436
  return buffer.toString("base64");
2437
+ } catch {
2438
+ }
2439
+ try {
2440
+ await page.waitForSelector(selector, { state: "visible", timeout: 2e3 });
2441
+ const buffer = await page.locator(selector).first().screenshot({
2442
+ type: "png",
2443
+ timeout: 3e3
2444
+ });
2445
+ return buffer.toString("base64");
2446
+ } catch {
2447
+ }
2448
+ try {
2449
+ const buffer = await page.screenshot({ type: "png", timeout: 3e3 });
2450
+ return buffer.toString("base64");
2431
2451
  } catch {
2432
2452
  return;
2433
2453
  }
package/dist/cli.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  } from "./chunk-YAUG3NSI.js";
31
31
  import {
32
32
  SessionRecorder
33
- } from "./chunk-CH5ZQV64.js";
33
+ } from "./chunk-C3LIGO4V.js";
34
34
  import {
35
35
  addKnownIssue,
36
36
  getKnowledgePath,
@@ -54,7 +54,7 @@ import {
54
54
  resolveLaunchOpts,
55
55
  saveSessionDiskMeta,
56
56
  setActivePage
57
- } from "./chunk-74S7UUI2.js";
57
+ } from "./chunk-A4YHJW3Z.js";
58
58
  import "./chunk-TNEN6VQ2.js";
59
59
  import {
60
60
  errMsg
@@ -7058,7 +7058,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7058
7058
  }
7059
7059
  let targetPageOverride = null;
7060
7060
  if (_target && extraOpts?.cdpEndpoint) {
7061
- const { findTargetPage } = await import("./browser-JXIJF4VL.js");
7061
+ const { findTargetPage } = await import("./browser-GT4BMX6X.js");
7062
7062
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7063
7063
  if (!targetPageOverride) {
7064
7064
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -11117,7 +11117,7 @@ async function handleFilter(args, _mode, options) {
11117
11117
  }
11118
11118
  }
11119
11119
  async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
11120
- const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-RFOPX4SF.js");
11120
+ const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-AG6CH6EI.js");
11121
11121
  const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
11122
11122
  const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync12 } = await import("fs");
11123
11123
  const { join: join13 } = await import("path");
@@ -13094,7 +13094,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
13094
13094
  const targetPage = pages[cmdTabIndex];
13095
13095
  await targetPage.bringToFront().catch(() => {
13096
13096
  });
13097
- const { setActivePage: setActivePage2 } = await import("./browser-JXIJF4VL.js");
13097
+ const { setActivePage: setActivePage2 } = await import("./browser-GT4BMX6X.js");
13098
13098
  setActivePage2(session, targetPage);
13099
13099
  }
13100
13100
  }
@@ -13370,7 +13370,7 @@ async function main() {
13370
13370
  const command = process.argv[2];
13371
13371
  const isLongRunning = command === "preview" || command === "serve";
13372
13372
  if (!isLongRunning) {
13373
- const { ensureProcessCanExit } = await import("./browser-JXIJF4VL.js");
13373
+ const { ensureProcessCanExit } = await import("./browser-GT4BMX6X.js");
13374
13374
  await ensureProcessCanExit().catch(() => {
13375
13375
  });
13376
13376
  process.exit(process.exitCode || exitCode);
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-VEDJ5XSQ.js";
14
14
  import {
15
15
  SessionRecorder
16
- } from "./chunk-C4O73DQL.js";
16
+ } from "./chunk-VEWTHYDG.js";
17
17
  import {
18
18
  closeEphemeralContext,
19
19
  closeSessionByName,
@@ -29,8 +29,8 @@ import {
29
29
  resolveLaunchOpts,
30
30
  saveSessionDiskMeta,
31
31
  setActivePage
32
- } from "./chunk-37SHZSUR.js";
33
- import "./chunk-VJNMAWPZ.js";
32
+ } from "./chunk-ENCEMM7Z.js";
33
+ import "./chunk-GM3HWQ5U.js";
34
34
  import "./chunk-TNEN6VQ2.js";
35
35
  import {
36
36
  errMsg
@@ -6575,7 +6575,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6575
6575
  }
6576
6576
  let targetPageOverride = null;
6577
6577
  if (_target && extraOpts?.cdpEndpoint) {
6578
- const { findTargetPage } = await import("./browser-ALPLJNH2.js");
6578
+ const { findTargetPage } = await import("./browser-43YXUIML.js");
6579
6579
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
6580
6580
  if (!targetPageOverride) {
6581
6581
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -8167,7 +8167,7 @@ function createRPCHandler() {
8167
8167
  const sessionName = params.session || "default";
8168
8168
  const slowMo = params.slowMo || 1;
8169
8169
  if (!file) {
8170
- return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: "Missing file parameter" }] };
8170
+ return normalizeReplayResult({ ok: false, errors: [{ eventIndex: -1, error: "Missing file parameter" }] });
8171
8171
  }
8172
8172
  let rawContent;
8173
8173
  let parsed;
@@ -8180,55 +8180,54 @@ function createRPCHandler() {
8180
8180
  parsed = yaml2.parse(rawContent);
8181
8181
  }
8182
8182
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
8183
- return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: `File "${file}" does not contain a valid recording. Expected a JSON/YAML object with an "actions" or "events" array, got ${parsed === null ? "empty content" : typeof parsed}.` }] };
8183
+ return normalizeReplayResult({ ok: false, errors: [{ eventIndex: -1, error: `File "${file}" does not contain a valid recording. Expected a JSON/YAML object with an "actions" or "events" array, got ${parsed === null ? "empty content" : typeof parsed}.` }] });
8184
8184
  }
8185
8185
  } catch (e) {
8186
8186
  const msg = e instanceof Error ? e.message : String(e);
8187
- return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: `Failed to parse "${file}" as JSON or YAML: ${msg.split("\n")[0]}` }] };
8187
+ return normalizeReplayResult({ ok: false, errors: [{ eventIndex: -1, error: `Failed to parse "${file}" as JSON or YAML: ${msg.split("\n")[0]}` }] });
8188
8188
  }
8189
8189
  const session = findSession(sessionName);
8190
8190
  if (!session) {
8191
- return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: `Session not found: ${sessionName}. Open a browser first: xbrowser goto <url> --session ${sessionName}` }] };
8191
+ return normalizeReplayResult({ ok: false, errors: [{ eventIndex: -1, error: `Session not found: ${sessionName}. Open a browser first: xbrowser goto <url> --session ${sessionName}` }] });
8192
8192
  }
8193
8193
  if (!session.page) {
8194
- return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: "Session has no page: " + sessionName }] };
8194
+ return normalizeReplayResult({ ok: false, errors: [{ eventIndex: -1, error: "Session has no page: " + sessionName }] });
8195
8195
  }
8196
8196
  const isNewFormat = Array.isArray(parsed.actions);
8197
8197
  if (isNewFormat) {
8198
8198
  try {
8199
8199
  const replayErrors = [];
8200
- const { SessionReplayer } = await import("./session-replayer-3HEIJBJ2.js");
8200
+ const { SessionReplayer } = await import("./session-replayer-V4MP6M6I.js");
8201
8201
  const replayer = new SessionReplayer({
8202
8202
  page: session.page,
8203
8203
  stepDelay: slowMo * 500,
8204
8204
  onStep: (action, index, total) => {
8205
8205
  console.log(`[replay] Step ${index + 1}/${total}: ${action.type} ${action.element?.selector || action.url || ""}`);
8206
8206
  },
8207
- onError: (action, error) => {
8207
+ onError: (action, error, index) => {
8208
8208
  const msg = `[${action?.type || "unknown"}] ${error?.message || String(error)}`;
8209
8209
  console.error("[replay] Error at step:", msg);
8210
- replayErrors.push({ eventIndex: -1, error: msg });
8210
+ replayErrors.push({ eventIndex: index, error: msg });
8211
8211
  }
8212
8212
  });
8213
8213
  if (!Array.isArray(parsed.actions) || typeof parsed.startUrl !== "string") {
8214
- return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: "Invalid recording format: missing actions or startUrl" }] };
8214
+ return normalizeReplayResult({ ok: false, errors: [{ eventIndex: -1, error: "Invalid recording format: missing actions or startUrl" }] });
8215
8215
  }
8216
8216
  await replayer.load(parsed);
8217
8217
  const startTime = Date.now();
8218
8218
  const result2 = await replayer.run();
8219
8219
  const duration = Date.now() - startTime;
8220
- return {
8220
+ return normalizeReplayResult({
8221
8221
  ok: result2.failed === 0,
8222
- success: result2.failed === 0,
8223
8222
  duration,
8224
8223
  eventsPlayed: result2.success,
8225
8224
  totalEvents: result2.success + result2.failed + result2.skipped,
8226
8225
  errors: replayErrors
8227
- };
8226
+ });
8228
8227
  } catch (e) {
8229
8228
  const msg = e instanceof Error ? e.message : String(e);
8230
8229
  console.error("[replay] SessionReplayer error:", msg);
8231
- return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: "Replay failed: " + msg }] };
8230
+ return normalizeReplayResult({ ok: false, errors: [{ eventIndex: -1, error: "Replay failed: " + msg }] });
8232
8231
  }
8233
8232
  }
8234
8233
  const engine = PlaybackEngine.fromFile(session.page, file);
@@ -8242,7 +8241,21 @@ function createRPCHandler() {
8242
8241
  });
8243
8242
  }
8244
8243
  });
8245
- return { ok: result.success, ...result };
8244
+ return normalizeReplayResult({ ok: result.success, ...result });
8245
+ }
8246
+ function normalizeReplayResult(input) {
8247
+ const errors = Array.isArray(input.errors) ? input.errors : [];
8248
+ const eventsPlayed = typeof input.eventsPlayed === "number" ? input.eventsPlayed : 0;
8249
+ const totalEvents = typeof input.totalEvents === "number" ? input.totalEvents : eventsPlayed + errors.length;
8250
+ const ok26 = input.ok ?? errors.length === 0;
8251
+ return {
8252
+ ok: ok26,
8253
+ success: ok26,
8254
+ duration: typeof input.duration === "number" ? input.duration : 0,
8255
+ eventsPlayed,
8256
+ totalEvents,
8257
+ errors
8258
+ };
8246
8259
  }
8247
8260
  async function handleViewerCheckSelector(params) {
8248
8261
  const name = params.name || "default";
package/dist/index.d.ts CHANGED
@@ -1939,6 +1939,11 @@ declare class SessionRecorder {
1939
1939
  * selector or the screenshot fails (non-critical — never blocks recording).
1940
1940
  *
1941
1941
  * Only captures for: click, input, change, dblclick, and their CDP counterparts.
1942
+ *
1943
+ * Retry strategy (3 attempts, 3s each):
1944
+ * 1. element screenshot via locator
1945
+ * 2. retry element screenshot (element may have been animating/detached)
1946
+ * 3. fallback to viewport screenshot (so we always get *something*)
1942
1947
  */
1943
1948
  private captureElementScreenshot;
1944
1949
  /**
package/dist/index.js CHANGED
@@ -61,7 +61,7 @@ import {
61
61
  } from "./chunk-ANVL2ID2.js";
62
62
  import {
63
63
  SessionRecorder
64
- } from "./chunk-CH5ZQV64.js";
64
+ } from "./chunk-C3LIGO4V.js";
65
65
  import {
66
66
  addKnownIssue,
67
67
  getKnowledgePath,
@@ -86,8 +86,8 @@ import {
86
86
  resolveLaunchOpts,
87
87
  saveSessionDiskMeta,
88
88
  setActivePage
89
- } from "./chunk-5JSOGINQ.js";
90
- import "./chunk-VJNMAWPZ.js";
89
+ } from "./chunk-PBDID7SE.js";
90
+ import "./chunk-GM3HWQ5U.js";
91
91
  import "./chunk-TNEN6VQ2.js";
92
92
  import {
93
93
  errMsg
@@ -7406,7 +7406,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7406
7406
  }
7407
7407
  let targetPageOverride = null;
7408
7408
  if (_target && extraOpts?.cdpEndpoint) {
7409
- const { findTargetPage } = await import("./browser-ZPQP6VW7.js");
7409
+ const { findTargetPage } = await import("./browser-SJWPJFN7.js");
7410
7410
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7411
7411
  if (!targetPageOverride) {
7412
7412
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -11503,7 +11503,7 @@ async function handleFilter(args, _mode, options) {
11503
11503
  }
11504
11504
  }
11505
11505
  async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
11506
- const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-RFOPX4SF.js");
11506
+ const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-AG6CH6EI.js");
11507
11507
  const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
11508
11508
  const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync13 } = await import("fs");
11509
11509
  const { join: join14 } = await import("path");
@@ -13480,7 +13480,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
13480
13480
  const targetPage = pages[cmdTabIndex];
13481
13481
  await targetPage.bringToFront().catch(() => {
13482
13482
  });
13483
- const { setActivePage: setActivePage2 } = await import("./browser-ZPQP6VW7.js");
13483
+ const { setActivePage: setActivePage2 } = await import("./browser-SJWPJFN7.js");
13484
13484
  setActivePage2(session, targetPage);
13485
13485
  }
13486
13486
  }
@@ -16543,7 +16543,7 @@ var DataCollector = class {
16543
16543
  return results;
16544
16544
  }
16545
16545
  async createBrowserContext() {
16546
- const { launch } = await import("./cdp-driver-6EVYLHL2.js");
16546
+ const { launch } = await import("./cdp-driver-PUZLDSQU.js");
16547
16547
  const { browser } = await launch({
16548
16548
  headless: true,
16549
16549
  args: ["--no-sandbox", "--disable-setuid-sandbox"]
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SessionRecorder
3
- } from "./chunk-CH5ZQV64.js";
3
+ } from "./chunk-C3LIGO4V.js";
4
4
  import "./chunk-OZKD3W4X.js";
5
5
  import "./chunk-KFQGP6VL.js";
6
6
  export {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SessionRecorder
3
- } from "./chunk-C4O73DQL.js";
3
+ } from "./chunk-VEWTHYDG.js";
4
4
  import "./chunk-KFQGP6VL.js";
5
5
  export {
6
6
  SessionRecorder
@@ -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-6EVYLHL2.js");
34
+ const { launch } = await import("./cdp-driver-PUZLDSQU.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++) {
@@ -65,7 +65,7 @@ var SessionReplayer = class {
65
65
  success++;
66
66
  } catch (e) {
67
67
  const err = e instanceof Error ? e : new Error(String(e));
68
- this.opts.onError?.(action, err);
68
+ this.opts.onError?.(action, err, i);
69
69
  failed++;
70
70
  }
71
71
  if (i < actions.length - 1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xbrowser/cli",
3
- "version": "1.9.7",
3
+ "version": "1.9.8",
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": {