@xbrowser/cli 1.21.0 → 1.22.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.
Files changed (32) hide show
  1. package/README.md +1 -0
  2. package/dist/{browser-CNBSH53B.js → browser-BVRFSUXU.js} +3 -2
  3. package/dist/{browser-C2VEOJC2.js → browser-DSYUAE7H.js} +5 -4
  4. package/dist/{browser-VZOOFLAH.js → browser-Q67BJTI2.js} +4 -3
  5. package/dist/{cdp-driver-KFX4A6WR.js → cdp-driver-DC7EIUG5.js} +4 -3
  6. package/dist/{cdp-driver-7Z6ZAT5E.js → cdp-driver-T7D6H2RW.js} +335 -546
  7. package/dist/{cdp-driver-26LGCHXV.js → cdp-driver-WWO2UZDR.js} +3 -2
  8. package/dist/{chunk-Z5RTK4GW.js → chunk-2Q3GQRUP.js} +2 -2
  9. package/dist/{chunk-CLYZPSDR.js → chunk-4OU37CXP.js} +354 -576
  10. package/dist/{chunk-HWWG2ISJ.js → chunk-7OP2ISEY.js} +353 -575
  11. package/dist/{chunk-3FWLW7FS.js → chunk-A7NEA4PA.js} +39 -1
  12. package/dist/chunk-GYB5BOSP.js +602 -0
  13. package/dist/{chunk-ESJYANQO.js → chunk-IFKJO2UR.js} +360 -582
  14. package/dist/{chunk-NODRQGOK.js → chunk-IR6C24P7.js} +97 -0
  15. package/dist/{chunk-3KZ34AUC.js → chunk-MYH6FIBZ.js} +2 -1
  16. package/dist/{chunk-AVSTNODR.js → chunk-T4WTKBWI.js} +2 -2
  17. package/dist/{chunk-HBHOKZPN.js → chunk-V6KGBU5J.js} +97 -0
  18. package/dist/{chunk-IWVG4XYZ.js → chunk-VCVDILH6.js} +2 -1
  19. package/dist/cli.js +25 -13
  20. package/dist/daemon-main.js +20 -14
  21. package/dist/index.d.ts +37 -1
  22. package/dist/index.js +26 -15
  23. package/dist/keep-awake-M4KJS4B4.js +29 -0
  24. package/dist/{launcher-44STYRJC.js → launcher-IK2FKW6T.js} +1 -1
  25. package/dist/{launcher-EXJHHAUL.js → launcher-LUOMMGZC.js} +1 -1
  26. package/dist/{session-recorder-SLDBENVF.js → session-recorder-563ISSJK.js} +1 -1
  27. package/dist/{session-recorder-3BEVWHOK.js → session-recorder-GEZVQBKW.js} +1 -1
  28. package/dist/session-replayer-XM5L7LFD.js +927 -0
  29. package/dist/stealth-2AA2FSNN.js +29 -0
  30. package/dist/stealth-JOXGV34D.js +29 -0
  31. package/package.json +1 -1
  32. package/dist/session-replayer-EVD4HZBB.js +0 -413
@@ -478,6 +478,55 @@ var ACTION_SIGNAL_SCRIPT = `
478
478
  } catch(e) { /* skip */ }
479
479
  }
480
480
 
481
+ // Ordinal address (r6): ancestor form's ordinal among sibling forms + element's
482
+ // ordinal among same-tag direct children of that form. Direct children only \u2014
483
+ // nested elements have no stable single-level address.
484
+ var ordinal = null;
485
+ try {
486
+ var ordForm = el.closest ? el.closest('form') : null;
487
+ if (ordForm && el.parentElement === ordForm) {
488
+ var ordParent = ordForm.parentElement;
489
+ var formSibs = ordParent
490
+ ? Array.prototype.filter.call(ordParent.children, function(c) { return c.tagName === 'FORM'; })
491
+ : [ordForm];
492
+ var tagSibs = Array.prototype.filter.call(ordForm.children, function(c) { return c.tagName === el.tagName; });
493
+ ordinal = {
494
+ formNth: formSibs.indexOf(ordForm) + 1,
495
+ tagNth: tagSibs.indexOf(el) + 1,
496
+ };
497
+ }
498
+ } catch(e) { /* skip */ }
499
+
500
+ // Label text (r16): the <label> associated with the element (for= association or ancestor wrapper). In virtual list /
501
+ // form-row reordering scenarios, structural ordinals fail, but the label text moves in the same line as the
502
+ // control\u2014content moves, and the anchor follows the content.
503
+ var labelText = '';
504
+ try {
505
+ var lbl = null;
506
+ if (el.id) lbl = el.ownerDocument.querySelector('label[for="' + el.id + '"]');
507
+ if (!lbl && el.closest) lbl = el.closest('label');
508
+ if (lbl) labelText = (lbl.textContent || '').trim().substring(0, 40);
509
+ } catch(e) { /* skip */ }
510
+
511
+ // Element size (r25): rounded rect at record time \u2014 scoring signal for
512
+ // fingerprint disambiguation between same-fingerprint decoys.
513
+ var size = null;
514
+ try {
515
+ var szR = el.getBoundingClientRect();
516
+ if (szR.width > 0 || szR.height > 0) {
517
+ size = { w: Math.round(szR.width), h: Math.round(szR.height) };
518
+ }
519
+ } catch(e) { /* skip */ }
520
+
521
+ // Row text (r27): textContent of the closest table/list row. In virtual
522
+ // lists and sortable tables the row re-indexes \u2014 the row TEXT travels
523
+ // with the content, giving inputs a content anchor that survives reorder.
524
+ var rowText = '';
525
+ try {
526
+ var row = el.closest ? el.closest('tr,li') : null;
527
+ if (row) rowText = (row.textContent || '').trim().replace(/s+/g, ' ').substring(0, 40);
528
+ } catch(e) { /* skip */ }
529
+
481
530
  return {
482
531
  tag: tag,
483
532
  selector: selector,
@@ -491,6 +540,10 @@ var ACTION_SIGNAL_SCRIPT = `
491
540
  placeholder: el.getAttribute('placeholder') || undefined,
492
541
  ariaLabel: el.getAttribute('aria-label') || undefined,
493
542
  href: el.getAttribute('href') ? el.getAttribute('href').substring(0, 80) : undefined,
543
+ ordinal: ordinal || undefined,
544
+ labelText: labelText || undefined,
545
+ size: size || undefined,
546
+ rowText: rowText || undefined,
494
547
  };
495
548
  }
496
549
 
@@ -1128,6 +1181,50 @@ var ACTION_SIGNAL_SCRIPT = `
1128
1181
  __xb_drag_start_pos = { x: e.clientX, y: e.clientY };
1129
1182
  }, true);
1130
1183
  document.addEventListener('drop', function(e) {
1184
+ // sup-s5: OS \u6587\u4EF6\u62D6\u5165\u6355\u83B7\u2014\u2014Dropzone/Uppy \u7C7B\u4E0A\u4F20\u533A\u65E0 input[type=file]\uFF0C
1185
+ // change \u6355\u83B7\u591F\u4E0D\u7740\uFF1BdataTransfer.files \u7ECF FileReader \u5185\u8054\uFF08\u4E0E
1186
+ // filechooser \u540C\u6784\uFF09\uFF0C\u56DE\u653E\u7AEF 'drop' \u52A8\u4F5C\u7ECF dropFiles \u91CD\u653E\u3002
1187
+ try {
1188
+ var dropped = (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0)
1189
+ ? Array.prototype.slice.call(e.dataTransfer.files)
1190
+ : [];
1191
+ if (dropped.length > 0) {
1192
+ var zone = describe(resolveMeaningful(e));
1193
+ var names = dropped.map(function(f) { return f.name; });
1194
+ var readers = [];
1195
+ for (var i = 0; i < dropped.length; i++) {
1196
+ readers.push(new Promise(function(resolve) {
1197
+ var reader = new FileReader();
1198
+ reader.onload = function() { resolve(reader.result); };
1199
+ reader.onerror = function() { resolve(null); };
1200
+ reader.readAsDataURL(dropped[i]);
1201
+ }));
1202
+ }
1203
+ Promise.all(readers).then(function(contents) {
1204
+ var fileData = [];
1205
+ for (var j = 0; j < dropped.length; j++) {
1206
+ fileData.push({
1207
+ name: dropped[j].name,
1208
+ type: dropped[j].type,
1209
+ size: dropped[j].size,
1210
+ dataUrl: contents[j],
1211
+ });
1212
+ }
1213
+ pushAction('drop', {
1214
+ x: e.clientX,
1215
+ y: e.clientY,
1216
+ element: zone,
1217
+ value: names.join(', '),
1218
+ files: {
1219
+ names: names,
1220
+ count: dropped.length,
1221
+ isMultiple: dropped.length > 1,
1222
+ fileData: fileData,
1223
+ },
1224
+ });
1225
+ });
1226
+ }
1227
+ } catch(_) { /* capture must not break the drag path */ }
1131
1228
  if (__xb_drag_source && __xb_drag_start_pos) {
1132
1229
  pushAction('drag', {
1133
1230
  x: e.clientX,
@@ -93,10 +93,11 @@ async function launchChrome(options = {}) {
93
93
  "--no-sandbox",
94
94
  "--no-first-run",
95
95
  "--no-default-browser-check",
96
+ "--disable-session-crashed-bubble",
96
97
  "--disable-background-timer-throttling",
97
98
  "--disable-backgrounding-occluded-windows",
98
99
  "--disable-renderer-backgrounding",
99
- "--disable-features=Translate",
100
+ "--disable-features=Translate,PasswordLeakDetection",
100
101
  "--disable-popup-blocking"
101
102
  ];
102
103
  if (headless) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createRuleEngine,
3
3
  launch
4
- } from "./chunk-CLYZPSDR.js";
4
+ } from "./chunk-4OU37CXP.js";
5
5
  import {
6
6
  errMsg
7
7
  } from "./chunk-GDKLH7ZY.js";
@@ -1227,7 +1227,7 @@ async function closeSessionByName(name) {
1227
1227
  } catch {
1228
1228
  }
1229
1229
  try {
1230
- const { SessionRecorder } = await import("./session-recorder-3BEVWHOK.js");
1230
+ const { SessionRecorder } = await import("./session-recorder-GEZVQBKW.js");
1231
1231
  SessionRecorder.cleanup(session.name);
1232
1232
  } catch {
1233
1233
  }
@@ -875,6 +875,55 @@ var ACTION_SIGNAL_SCRIPT = `
875
875
  } catch(e) { /* skip */ }
876
876
  }
877
877
 
878
+ // Ordinal address (r6): ancestor form's ordinal among sibling forms + element's
879
+ // ordinal among same-tag direct children of that form. Direct children only \u2014
880
+ // nested elements have no stable single-level address.
881
+ var ordinal = null;
882
+ try {
883
+ var ordForm = el.closest ? el.closest('form') : null;
884
+ if (ordForm && el.parentElement === ordForm) {
885
+ var ordParent = ordForm.parentElement;
886
+ var formSibs = ordParent
887
+ ? Array.prototype.filter.call(ordParent.children, function(c) { return c.tagName === 'FORM'; })
888
+ : [ordForm];
889
+ var tagSibs = Array.prototype.filter.call(ordForm.children, function(c) { return c.tagName === el.tagName; });
890
+ ordinal = {
891
+ formNth: formSibs.indexOf(ordForm) + 1,
892
+ tagNth: tagSibs.indexOf(el) + 1,
893
+ };
894
+ }
895
+ } catch(e) { /* skip */ }
896
+
897
+ // Label text (r16): the <label> associated with the element (for= association or ancestor wrapper). In virtual list /
898
+ // form-row reordering scenarios, structural ordinals fail, but the label text moves in the same line as the
899
+ // control\u2014content moves, and the anchor follows the content.
900
+ var labelText = '';
901
+ try {
902
+ var lbl = null;
903
+ if (el.id) lbl = el.ownerDocument.querySelector('label[for="' + el.id + '"]');
904
+ if (!lbl && el.closest) lbl = el.closest('label');
905
+ if (lbl) labelText = (lbl.textContent || '').trim().substring(0, 40);
906
+ } catch(e) { /* skip */ }
907
+
908
+ // Element size (r25): rounded rect at record time \u2014 scoring signal for
909
+ // fingerprint disambiguation between same-fingerprint decoys.
910
+ var size = null;
911
+ try {
912
+ var szR = el.getBoundingClientRect();
913
+ if (szR.width > 0 || szR.height > 0) {
914
+ size = { w: Math.round(szR.width), h: Math.round(szR.height) };
915
+ }
916
+ } catch(e) { /* skip */ }
917
+
918
+ // Row text (r27): textContent of the closest table/list row. In virtual
919
+ // lists and sortable tables the row re-indexes \u2014 the row TEXT travels
920
+ // with the content, giving inputs a content anchor that survives reorder.
921
+ var rowText = '';
922
+ try {
923
+ var row = el.closest ? el.closest('tr,li') : null;
924
+ if (row) rowText = (row.textContent || '').trim().replace(/s+/g, ' ').substring(0, 40);
925
+ } catch(e) { /* skip */ }
926
+
878
927
  return {
879
928
  tag: tag,
880
929
  selector: selector,
@@ -888,6 +937,10 @@ var ACTION_SIGNAL_SCRIPT = `
888
937
  placeholder: el.getAttribute('placeholder') || undefined,
889
938
  ariaLabel: el.getAttribute('aria-label') || undefined,
890
939
  href: el.getAttribute('href') ? el.getAttribute('href').substring(0, 80) : undefined,
940
+ ordinal: ordinal || undefined,
941
+ labelText: labelText || undefined,
942
+ size: size || undefined,
943
+ rowText: rowText || undefined,
891
944
  };
892
945
  }
893
946
 
@@ -1525,6 +1578,50 @@ var ACTION_SIGNAL_SCRIPT = `
1525
1578
  __xb_drag_start_pos = { x: e.clientX, y: e.clientY };
1526
1579
  }, true);
1527
1580
  document.addEventListener('drop', function(e) {
1581
+ // sup-s5: OS \u6587\u4EF6\u62D6\u5165\u6355\u83B7\u2014\u2014Dropzone/Uppy \u7C7B\u4E0A\u4F20\u533A\u65E0 input[type=file]\uFF0C
1582
+ // change \u6355\u83B7\u591F\u4E0D\u7740\uFF1BdataTransfer.files \u7ECF FileReader \u5185\u8054\uFF08\u4E0E
1583
+ // filechooser \u540C\u6784\uFF09\uFF0C\u56DE\u653E\u7AEF 'drop' \u52A8\u4F5C\u7ECF dropFiles \u91CD\u653E\u3002
1584
+ try {
1585
+ var dropped = (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0)
1586
+ ? Array.prototype.slice.call(e.dataTransfer.files)
1587
+ : [];
1588
+ if (dropped.length > 0) {
1589
+ var zone = describe(resolveMeaningful(e));
1590
+ var names = dropped.map(function(f) { return f.name; });
1591
+ var readers = [];
1592
+ for (var i = 0; i < dropped.length; i++) {
1593
+ readers.push(new Promise(function(resolve) {
1594
+ var reader = new FileReader();
1595
+ reader.onload = function() { resolve(reader.result); };
1596
+ reader.onerror = function() { resolve(null); };
1597
+ reader.readAsDataURL(dropped[i]);
1598
+ }));
1599
+ }
1600
+ Promise.all(readers).then(function(contents) {
1601
+ var fileData = [];
1602
+ for (var j = 0; j < dropped.length; j++) {
1603
+ fileData.push({
1604
+ name: dropped[j].name,
1605
+ type: dropped[j].type,
1606
+ size: dropped[j].size,
1607
+ dataUrl: contents[j],
1608
+ });
1609
+ }
1610
+ pushAction('drop', {
1611
+ x: e.clientX,
1612
+ y: e.clientY,
1613
+ element: zone,
1614
+ value: names.join(', '),
1615
+ files: {
1616
+ names: names,
1617
+ count: dropped.length,
1618
+ isMultiple: dropped.length > 1,
1619
+ fileData: fileData,
1620
+ },
1621
+ });
1622
+ });
1623
+ }
1624
+ } catch(_) { /* capture must not break the drag path */ }
1528
1625
  if (__xb_drag_source && __xb_drag_start_pos) {
1529
1626
  pushAction('drag', {
1530
1627
  x: e.clientX,
@@ -97,10 +97,11 @@ async function launchChrome(options = {}) {
97
97
  "--no-sandbox",
98
98
  "--no-first-run",
99
99
  "--no-default-browser-check",
100
+ "--disable-session-crashed-bubble",
100
101
  "--disable-background-timer-throttling",
101
102
  "--disable-backgrounding-occluded-windows",
102
103
  "--disable-renderer-backgrounding",
103
- "--disable-features=Translate",
104
+ "--disable-features=Translate,PasswordLeakDetection",
104
105
  "--disable-popup-blocking"
105
106
  ];
106
107
  if (headless) {
package/dist/cli.js CHANGED
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ detectAntiBot,
4
+ formatDetectionMessage
5
+ } from "./chunk-JKVUFP3G.js";
2
6
  import {
3
7
  forwardCommandLog,
4
8
  forwardNetworkAnalyze,
@@ -45,7 +49,7 @@ import {
45
49
  } from "./chunk-Q2DFJQGS.js";
46
50
  import {
47
51
  SessionRecorder
48
- } from "./chunk-NODRQGOK.js";
52
+ } from "./chunk-IR6C24P7.js";
49
53
  import {
50
54
  addKnownIssue,
51
55
  getKnowledgePath,
@@ -66,21 +70,19 @@ import {
66
70
  getAllSessions,
67
71
  getBrowser,
68
72
  getSessionById,
69
- rand,
70
73
  resolveLaunchOpts,
71
74
  saveSessionDiskMeta,
72
- setActivePage,
75
+ setActivePage
76
+ } from "./chunk-IFKJO2UR.js";
77
+ import {
78
+ rand,
73
79
  sleep,
74
80
  wheelDelta
75
- } from "./chunk-ESJYANQO.js";
76
- import "./chunk-3KZ34AUC.js";
81
+ } from "./chunk-GYB5BOSP.js";
82
+ import "./chunk-MYH6FIBZ.js";
77
83
  import {
78
84
  errMsg
79
85
  } from "./chunk-GDKLH7ZY.js";
80
- import {
81
- detectAntiBot,
82
- formatDetectionMessage
83
- } from "./chunk-JKVUFP3G.js";
84
86
  import "./chunk-KFQGP6VL.js";
85
87
 
86
88
  // src/router.ts
@@ -8248,7 +8250,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
8248
8250
  }
8249
8251
  let targetPageOverride = null;
8250
8252
  if (_target && extraOpts?.cdpEndpoint) {
8251
- const { findTargetPage } = await import("./browser-CNBSH53B.js");
8253
+ const { findTargetPage } = await import("./browser-BVRFSUXU.js");
8252
8254
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
8253
8255
  if (!targetPageOverride) {
8254
8256
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -12292,6 +12294,16 @@ async function handleReplay(args, options, mode) {
12292
12294
  }
12293
12295
  return;
12294
12296
  }
12297
+ if (result.ok && mode !== "json" && mode !== "yaml") {
12298
+ const healed = typeof result.healed === "number" ? result.healed : 0;
12299
+ if (healed > 0) {
12300
+ console.log(`
12301
+ Self-healed ${healed} action(s):`);
12302
+ for (const d of result.healedDetails ?? []) {
12303
+ console.log(` - step ${d.index + 1}: ${d.strategy}`);
12304
+ }
12305
+ }
12306
+ }
12295
12307
  outputResult(result, mode);
12296
12308
  }
12297
12309
  async function handleConvert(args, _mode) {
@@ -12393,7 +12405,7 @@ async function handleFilter(args, _mode, options) {
12393
12405
  }
12394
12406
  }
12395
12407
  async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
12396
- const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-SLDBENVF.js");
12408
+ const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-563ISSJK.js");
12397
12409
  const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
12398
12410
  const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync12 } = await import("fs");
12399
12411
  const { join: join15 } = await import("path");
@@ -14433,7 +14445,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
14433
14445
  const targetPage = pages[cmdTabIndex];
14434
14446
  await targetPage.bringToFront().catch(() => {
14435
14447
  });
14436
- const { setActivePage: setActivePage2 } = await import("./browser-CNBSH53B.js");
14448
+ const { setActivePage: setActivePage2 } = await import("./browser-BVRFSUXU.js");
14437
14449
  setActivePage2(session, targetPage);
14438
14450
  }
14439
14451
  }
@@ -14709,7 +14721,7 @@ async function main() {
14709
14721
  const command = process.argv[2];
14710
14722
  const isLongRunning = command === "preview" || command === "serve";
14711
14723
  if (!isLongRunning) {
14712
- const { ensureProcessCanExit } = await import("./browser-CNBSH53B.js");
14724
+ const { ensureProcessCanExit } = await import("./browser-BVRFSUXU.js");
14713
14725
  await ensureProcessCanExit().catch(() => {
14714
14726
  });
14715
14727
  process.exit(process.exitCode || exitCode);
@@ -1,3 +1,7 @@
1
+ import {
2
+ detectAntiBot,
3
+ formatDetectionMessage
4
+ } from "./chunk-JKVUFP3G.js";
1
5
  import {
2
6
  getPluginLoader
3
7
  } from "./chunk-PIWNMC36.js";
@@ -19,7 +23,7 @@ import {
19
23
  } from "./chunk-VEDJ5XSQ.js";
20
24
  import {
21
25
  SessionRecorder
22
- } from "./chunk-HBHOKZPN.js";
26
+ } from "./chunk-V6KGBU5J.js";
23
27
  import {
24
28
  closeEphemeralContext,
25
29
  closeSessionByName,
@@ -34,24 +38,22 @@ import {
34
38
  resolveLaunchOpts,
35
39
  saveSessionDiskMeta,
36
40
  setActivePage
37
- } from "./chunk-AVSTNODR.js";
41
+ } from "./chunk-T4WTKBWI.js";
42
+ import {
43
+ createRuleEngine
44
+ } from "./chunk-4OU37CXP.js";
45
+ import {
46
+ queryJS
47
+ } from "./chunk-A7NEA4PA.js";
38
48
  import {
39
- createRuleEngine,
40
49
  rand,
41
50
  sleep,
42
51
  wheelDelta
43
- } from "./chunk-CLYZPSDR.js";
44
- import {
45
- queryJS
46
- } from "./chunk-3FWLW7FS.js";
47
- import "./chunk-3KZ34AUC.js";
52
+ } from "./chunk-GYB5BOSP.js";
53
+ import "./chunk-MYH6FIBZ.js";
48
54
  import {
49
55
  errMsg
50
56
  } from "./chunk-GDKLH7ZY.js";
51
- import {
52
- detectAntiBot,
53
- formatDetectionMessage
54
- } from "./chunk-JKVUFP3G.js";
55
57
  import "./chunk-KFQGP6VL.js";
56
58
 
57
59
  // src/daemon/daemon-main.ts
@@ -7766,7 +7768,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7766
7768
  }
7767
7769
  let targetPageOverride = null;
7768
7770
  if (_target && extraOpts?.cdpEndpoint) {
7769
- const { findTargetPage } = await import("./browser-C2VEOJC2.js");
7771
+ const { findTargetPage } = await import("./browser-DSYUAE7H.js");
7770
7772
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7771
7773
  if (!targetPageOverride) {
7772
7774
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -9588,7 +9590,7 @@ function createRPCHandler() {
9588
9590
  if (isNewFormat) {
9589
9591
  try {
9590
9592
  const replayErrors = [];
9591
- const { SessionReplayer } = await import("./session-replayer-EVD4HZBB.js");
9593
+ const { SessionReplayer } = await import("./session-replayer-XM5L7LFD.js");
9592
9594
  const replayer = new SessionReplayer({
9593
9595
  page: session.page,
9594
9596
  stepDelay: slowMo * 500,
@@ -9613,6 +9615,8 @@ function createRPCHandler() {
9613
9615
  duration,
9614
9616
  eventsPlayed: result2.success,
9615
9617
  totalEvents: result2.success + result2.failed + result2.skipped,
9618
+ healed: result2.healed,
9619
+ healedDetails: result2.healedDetails,
9616
9620
  errors: replayErrors
9617
9621
  });
9618
9622
  } catch (e) {
@@ -9645,6 +9649,8 @@ function createRPCHandler() {
9645
9649
  duration: typeof input.duration === "number" ? input.duration : 0,
9646
9650
  eventsPlayed,
9647
9651
  totalEvents,
9652
+ healed: typeof input.healed === "number" ? input.healed : 0,
9653
+ healedDetails: Array.isArray(input.healedDetails) ? input.healedDetails : [],
9648
9654
  errors
9649
9655
  };
9650
9656
  }
package/dist/index.d.ts CHANGED
@@ -137,6 +137,12 @@ interface XBContextOptions {
137
137
  ignoreHTTPSErrors?: boolean;
138
138
  /** S194: stealth 伪装配置(UA-CH 档案等)——经 context 传至 page 的注入层 */
139
139
  stealthConfig?: Partial<StealthConfig>;
140
+ /** sup-s9: HTTP Basic/Digest 凭证——Fetch.authRequired 自动 ProvideCredentials;
141
+ * 缺省 CancelAuth(快速失败,不弹认证框不挂起) */
142
+ httpCredentials?: {
143
+ username: string;
144
+ password: string;
145
+ };
140
146
  }
141
147
  interface XBContext {
142
148
  newPage(): Promise<XBPage>;
@@ -270,6 +276,8 @@ interface XBPage {
270
276
  width: number;
271
277
  height: number;
272
278
  }): Promise<void>;
279
+ /** env-E2: 缩放变异——deviceScaleFactor 切换(CSS 视口尺寸不变) */
280
+ setDeviceScaleFactor(dsf: number): Promise<void>;
273
281
  addInitScript(script: string): Promise<void>;
274
282
  /** 覆盖当前页会话的 User-Agent(Network.setUserAgentOverride,会话级持久) */
275
283
  setUserAgent(userAgent: string): Promise<void>;
@@ -286,6 +294,10 @@ interface XBPage {
286
294
  route(url: string | RegExp, handler: (route: XBRoute) => Promise<void> | void): Promise<void>;
287
295
  unroute(url: string | RegExp, handler?: (route: XBRoute) => Promise<void> | void): Promise<void>;
288
296
  setInputFiles(selector: string, files: XBFilePayload | XBFilePayload[]): Promise<void>;
297
+ /** sup-s4: Dropzone 拖拽上传模拟——DataTransfer+File 派发 dragenter/dragover/drop */
298
+ dropFiles(selector: string, payload: XBFilePayload): Promise<void>;
299
+ /** sup-s11: beforeunload 自动应答语义(accept=离开默认 / dismiss=留守) */
300
+ setBeforeUnloadBehavior(mode: 'accept' | 'dismiss'): void;
289
301
  dragAndDrop(source: string, target: string): Promise<void>;
290
302
  on(event: string, handler: Function): void;
291
303
  off(event: string, handler: Function): void;
@@ -1853,7 +1865,7 @@ interface HoverContext {
1853
1865
  }
1854
1866
  interface UserAction {
1855
1867
  id: number;
1856
- type: 'click' | 'input' | 'change' | 'keydown' | 'submit' | 'scroll' | 'navigation' | 'goto' | 'cdp-fill' | 'cdp-click' | 'cdp-eval' | 'filechooser' | 'dblclick' | 'contextmenu' | 'hover' | 'drag' | 'resize' | 'clipboard' | 'touch' | 'focus' | 'visibility' | 'popup_appear' | 'discovered_filters';
1868
+ type: 'click' | 'input' | 'change' | 'keydown' | 'submit' | 'scroll' | 'navigation' | 'goto' | 'cdp-fill' | 'cdp-click' | 'cdp-eval' | 'filechooser' | 'dblclick' | 'contextmenu' | 'hover' | 'drag' | 'resize' | 'clipboard' | 'touch' | 'focus' | 'visibility' | 'drop' | 'popup_appear' | 'discovered_filters';
1857
1869
  timestamp: number;
1858
1870
  url: string;
1859
1871
  pageTitle: string;
@@ -1877,6 +1889,24 @@ interface UserAction {
1877
1889
  placeholder?: string;
1878
1890
  ariaLabel?: string;
1879
1891
  href?: string;
1892
+ /** 结构地址(r6):祖先 form 在同级 form 中的序 + 元素在 form 内同 tag
1893
+ * 兄弟中的序(仅 form 直接子元素捕获)。布局位移后坐标失效时仍可定位。 */
1894
+ ordinal?: {
1895
+ formNth: number;
1896
+ tagNth: number;
1897
+ };
1898
+ /** 关联 label 的文本(r16):for= 关联或祖先 label 包裹。行重排/虚拟
1899
+ * 列表重建后结构序失效时的内容锚。 */
1900
+ labelText?: string;
1901
+ /** 元素尺寸(r25):录制时 rounded rect。同指纹诱饵消歧的评分信号
1902
+ * (仅加分不否决——响应式布局合法改变尺寸)。 */
1903
+ size?: {
1904
+ w: number;
1905
+ h: number;
1906
+ };
1907
+ /** 所在行文本(r27):closest('tr,li') 的 textContent 前 40 字符。
1908
+ * 表格/列表行重排后结构序失效时的内容锚(label 锚的行推广)。 */
1909
+ rowText?: string;
1880
1910
  };
1881
1911
  value?: string;
1882
1912
  key?: string;
@@ -2277,6 +2307,12 @@ interface PlaybackResult {
2277
2307
  event?: RecordedEvent;
2278
2308
  error: string;
2279
2309
  }>;
2310
+ /** r13: 自愈步数与明细(SessionReplayer 路径填充) */
2311
+ healed?: number;
2312
+ healedDetails?: Array<{
2313
+ index: number;
2314
+ strategy: string;
2315
+ }>;
2280
2316
  }
2281
2317
  /**
2282
2318
  * Engine for playing back a recorded browser session.
package/dist/index.js CHANGED
@@ -1,7 +1,15 @@
1
+ import {
2
+ extractAndSave,
3
+ extractRecording,
4
+ printExtractSummary
5
+ } from "./chunk-X46HDAOT.js";
1
6
  import {
2
7
  filterRecording,
3
8
  parseExcludeTypes
4
9
  } from "./chunk-ANVL2ID2.js";
10
+ import {
11
+ SessionRecorder
12
+ } from "./chunk-IR6C24P7.js";
5
13
  import {
6
14
  closeAllSessions,
7
15
  closeEphemeralContext,
@@ -18,7 +26,7 @@ import {
18
26
  resolveLaunchOpts,
19
27
  saveSessionDiskMeta,
20
28
  setActivePage
21
- } from "./chunk-Z5RTK4GW.js";
29
+ } from "./chunk-2Q3GQRUP.js";
22
30
  import {
23
31
  detectAntiBot,
24
32
  formatDetectionMessage
@@ -77,17 +85,13 @@ import {
77
85
  generateJSScript,
78
86
  generatePythonScript
79
87
  } from "./chunk-ETCO4SNK.js";
80
- import {
81
- extractAndSave,
82
- extractRecording,
83
- printExtractSummary
84
- } from "./chunk-X46HDAOT.js";
88
+ import "./chunk-7OP2ISEY.js";
85
89
  import {
86
90
  rand,
87
91
  sleep,
88
92
  wheelDelta
89
- } from "./chunk-HWWG2ISJ.js";
90
- import "./chunk-3KZ34AUC.js";
93
+ } from "./chunk-GYB5BOSP.js";
94
+ import "./chunk-MYH6FIBZ.js";
91
95
  import {
92
96
  errMsg
93
97
  } from "./chunk-GDKLH7ZY.js";
@@ -107,9 +111,6 @@ import {
107
111
  networkAnomalyRule,
108
112
  pageLifecycleRule
109
113
  } from "./chunk-75DNUI6M.js";
110
- import {
111
- SessionRecorder
112
- } from "./chunk-NODRQGOK.js";
113
114
  import {
114
115
  addKnownIssue,
115
116
  getKnowledgePath,
@@ -8599,7 +8600,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
8599
8600
  }
8600
8601
  let targetPageOverride = null;
8601
8602
  if (_target && extraOpts?.cdpEndpoint) {
8602
- const { findTargetPage } = await import("./browser-VZOOFLAH.js");
8603
+ const { findTargetPage } = await import("./browser-Q67BJTI2.js");
8603
8604
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
8604
8605
  if (!targetPageOverride) {
8605
8606
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -12681,6 +12682,16 @@ async function handleReplay(args, options, mode) {
12681
12682
  }
12682
12683
  return;
12683
12684
  }
12685
+ if (result.ok && mode !== "json" && mode !== "yaml") {
12686
+ const healed = typeof result.healed === "number" ? result.healed : 0;
12687
+ if (healed > 0) {
12688
+ console.log(`
12689
+ Self-healed ${healed} action(s):`);
12690
+ for (const d of result.healedDetails ?? []) {
12691
+ console.log(` - step ${d.index + 1}: ${d.strategy}`);
12692
+ }
12693
+ }
12694
+ }
12684
12695
  outputResult(result, mode);
12685
12696
  }
12686
12697
  async function handleConvert(args, _mode) {
@@ -12782,7 +12793,7 @@ async function handleFilter(args, _mode, options) {
12782
12793
  }
12783
12794
  }
12784
12795
  async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
12785
- const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-SLDBENVF.js");
12796
+ const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-563ISSJK.js");
12786
12797
  const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
12787
12798
  const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync13 } = await import("fs");
12788
12799
  const { join: join16 } = await import("path");
@@ -14822,7 +14833,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
14822
14833
  const targetPage = pages[cmdTabIndex];
14823
14834
  await targetPage.bringToFront().catch(() => {
14824
14835
  });
14825
- const { setActivePage: setActivePage2 } = await import("./browser-VZOOFLAH.js");
14836
+ const { setActivePage: setActivePage2 } = await import("./browser-Q67BJTI2.js");
14826
14837
  setActivePage2(session, targetPage);
14827
14838
  }
14828
14839
  }
@@ -17995,7 +18006,7 @@ var DataCollector = class {
17995
18006
  return results;
17996
18007
  }
17997
18008
  async createBrowserContext() {
17998
- const { launch } = await import("./cdp-driver-26LGCHXV.js");
18009
+ const { launch } = await import("./cdp-driver-WWO2UZDR.js");
17999
18010
  const { browser } = await launch({
18000
18011
  headless: true,
18001
18012
  args: ["--no-sandbox", "--disable-setuid-sandbox"]
@@ -0,0 +1,29 @@
1
+ import "./chunk-KFQGP6VL.js";
2
+
3
+ // src/utils/keep-awake.ts
4
+ import { spawn } from "child_process";
5
+ function startKeepAwake() {
6
+ if (process.platform !== "darwin") return { dispose: () => {
7
+ } };
8
+ try {
9
+ const child = spawn("caffeinate", ["-i", "-w", String(process.pid)], {
10
+ stdio: "ignore",
11
+ detached: false
12
+ });
13
+ return {
14
+ pid: child.pid,
15
+ dispose: () => {
16
+ try {
17
+ child.kill("SIGTERM");
18
+ } catch {
19
+ }
20
+ }
21
+ };
22
+ } catch {
23
+ return { dispose: () => {
24
+ } };
25
+ }
26
+ }
27
+ export {
28
+ startKeepAwake
29
+ };