@xbrowser/cli 1.15.0 → 1.16.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,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-K5E4CWRV.js";
24
- import "./chunk-NTTFKS6T.js";
23
+ } from "./chunk-7V3B7VPX.js";
24
+ import "./chunk-A5HJ6IRE.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-A6LPGFAL.js";
@@ -20,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-XQ4KOZ37.js";
24
- import "./chunk-UXDGEDT7.js";
23
+ } from "./chunk-GWQ5NTVE.js";
24
+ import "./chunk-LTBNQERK.js";
25
25
  import "./chunk-3FWLW7FS.js";
26
26
  import "./chunk-TNEN6VQ2.js";
27
27
  import "./chunk-GDKLH7ZY.js";
@@ -20,7 +20,7 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-HFP4QCZL.js";
23
+ } from "./chunk-5EYOEB4R.js";
24
24
  import "./chunk-TNEN6VQ2.js";
25
25
  import "./chunk-GDKLH7ZY.js";
26
26
  import "./chunk-KFQGP6VL.js";
@@ -701,6 +701,26 @@ var XBKeyboardImpl = class {
701
701
  ...mapping.keyCode ? { windowsVirtualKeyCode: mapping.keyCode } : {}
702
702
  });
703
703
  }
704
+ /**
705
+ * Shortcut combo press (modifier+key) with explicit per-event modifiers
706
+ * bitmask — plain down(mod)+press(key) inserts the raw character because
707
+ * CDP modifiers are per-event fields, not session state (d56: Meta,v
708
+ * typed a literal 'v'). keyDown type carries the default action so the
709
+ * browser's shortcut dispatcher sees the combo (e.g. native paste).
710
+ */
711
+ async pressCombo(key, modifier) {
712
+ const MODBIT = { Alt: 1, Control: 2, Meta: 4, Shift: 8 };
713
+ const m = resolveKeyMapping(modifier);
714
+ const k = resolveKeyMapping(key);
715
+ const bits = MODBIT[modifier] ?? 0;
716
+ await this.dispatchKeyEvent({ type: "rawKeyDown", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: bits });
717
+ await this.dispatchKeyEvent({ type: "keyDown", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
718
+ if (process.env.XBROWSER_STEALTH !== "off") {
719
+ await sleep2(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
720
+ }
721
+ await this.dispatchKeyEvent({ type: "keyUp", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
722
+ await this.dispatchKeyEvent({ type: "keyUp", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: 0 });
723
+ }
704
724
  async dispatchKeyEvent(params) {
705
725
  await this.conn.send("Input.dispatchKeyEvent", params, this.sessionId);
706
726
  }
@@ -1084,6 +1104,18 @@ var XBLocatorImpl = class _XBLocatorImpl {
1084
1104
  await waitForActionable(this.page, this.selector, opts);
1085
1105
  await scrollIntoView(this.page, this.selector);
1086
1106
  await this.click({ ...opts });
1107
+ if (process.env.XBROWSER_STEALTH !== "off" && value.length >= 40 && process.env.XBROWSER_FILL_TYPE !== "type") {
1108
+ try {
1109
+ const { pasteViaClipboard, syntheticPaste } = await import("./clipboard-XRP54ENE.js");
1110
+ await pasteViaClipboard(this.page, value);
1111
+ const got = await this.page.evaluate(
1112
+ `(function(){ const el = ${this._q(this.selector)}; return el ? (el.value || '') : ''; })()`
1113
+ );
1114
+ if (got === value) return;
1115
+ if (await syntheticPaste(this.page, this._q(this.selector), value)) return;
1116
+ } catch {
1117
+ }
1118
+ }
1087
1119
  await this.page.keyboard.type(value, { stealth: true });
1088
1120
  return;
1089
1121
  await this.page.evaluate(`
@@ -14,7 +14,7 @@ import {
14
14
  scrollIntoView,
15
15
  waitForActionable,
16
16
  waitForNetworkIdle
17
- } from "./chunk-UXDGEDT7.js";
17
+ } from "./chunk-LTBNQERK.js";
18
18
  import "./chunk-3FWLW7FS.js";
19
19
  import {
20
20
  connectToCDP,
@@ -14,7 +14,7 @@ import {
14
14
  scrollIntoView,
15
15
  waitForActionable,
16
16
  waitForNetworkIdle
17
- } from "./chunk-NTTFKS6T.js";
17
+ } from "./chunk-A5HJ6IRE.js";
18
18
  import {
19
19
  connectToCDP,
20
20
  findChrome,
@@ -714,6 +714,26 @@ var XBKeyboardImpl = class {
714
714
  ...mapping.keyCode ? { windowsVirtualKeyCode: mapping.keyCode } : {}
715
715
  });
716
716
  }
717
+ /**
718
+ * Shortcut combo press (modifier+key) with explicit per-event modifiers
719
+ * bitmask — plain down(mod)+press(key) inserts the raw character because
720
+ * CDP modifiers are per-event fields, not session state (d56: Meta,v
721
+ * typed a literal 'v'). keyDown type carries the default action so the
722
+ * browser's shortcut dispatcher sees the combo (e.g. native paste).
723
+ */
724
+ async pressCombo(key, modifier) {
725
+ const MODBIT = { Alt: 1, Control: 2, Meta: 4, Shift: 8 };
726
+ const m = resolveKeyMapping(modifier);
727
+ const k = resolveKeyMapping(key);
728
+ const bits = MODBIT[modifier] ?? 0;
729
+ await this.dispatchKeyEvent({ type: "rawKeyDown", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: bits });
730
+ await this.dispatchKeyEvent({ type: "keyDown", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
731
+ if (process.env.XBROWSER_STEALTH !== "off") {
732
+ await sleep3(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
733
+ }
734
+ await this.dispatchKeyEvent({ type: "keyUp", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
735
+ await this.dispatchKeyEvent({ type: "keyUp", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: 0 });
736
+ }
717
737
  async dispatchKeyEvent(params) {
718
738
  await this.conn.send("Input.dispatchKeyEvent", params, this.sessionId);
719
739
  }
@@ -1097,6 +1117,18 @@ var XBLocatorImpl = class _XBLocatorImpl {
1097
1117
  await waitForActionable(this.page, this.selector, opts);
1098
1118
  await scrollIntoView(this.page, this.selector);
1099
1119
  await this.click({ ...opts });
1120
+ if (process.env.XBROWSER_STEALTH !== "off" && value.length >= 40 && process.env.XBROWSER_FILL_TYPE !== "type") {
1121
+ try {
1122
+ const { pasteViaClipboard, syntheticPaste } = await import("./clipboard-BOL2GP2E.js");
1123
+ await pasteViaClipboard(this.page, value);
1124
+ const got = await this.page.evaluate(
1125
+ `(function(){ const el = ${this._q(this.selector)}; return el ? (el.value || '') : ''; })()`
1126
+ );
1127
+ if (got === value) return;
1128
+ if (await syntheticPaste(this.page, this._q(this.selector), value)) return;
1129
+ } catch {
1130
+ }
1131
+ }
1100
1132
  await this.page.keyboard.type(value, { stealth: true });
1101
1133
  return;
1102
1134
  await this.page.evaluate(`
@@ -5363,16 +5395,14 @@ process.on("exit", () => {
5363
5395
  async function getCDPTargets2(cdpEndpoint) {
5364
5396
  try {
5365
5397
  const ep = String(cdpEndpoint);
5366
- let host = "localhost";
5367
- let port = "9222";
5398
+ let url = "http://localhost:9222/json/list";
5368
5399
  if (ep.startsWith("http://") || ep.startsWith("https://")) {
5369
5400
  const u = new URL(ep);
5370
- host = u.hostname;
5371
- port = u.port || "9222";
5401
+ u.pathname = (u.pathname.replace(/\/+$/, "") || "") + "/json/list";
5402
+ url = u.toString();
5372
5403
  } else if (/^\d+$/.test(ep)) {
5373
- port = ep;
5404
+ url = `http://localhost:${ep}/json/list`;
5374
5405
  }
5375
- const url = `http://${host}:${port}/json/list`;
5376
5406
  const resp = await fetch(url);
5377
5407
  return await resp.json();
5378
5408
  } catch {
@@ -5857,6 +5887,10 @@ async function createSession(name, url, options) {
5857
5887
  }
5858
5888
  }
5859
5889
  page = targetPage;
5890
+ if (isCDP) {
5891
+ await Promise.resolve(targetPage.bringToFront?.()).catch(() => {
5892
+ });
5893
+ }
5860
5894
  } else {
5861
5895
  context = await b.newContext({ viewport: { width: 1920, height: 1080 } });
5862
5896
  page = await context.newPage();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-NTTFKS6T.js";
3
+ } from "./chunk-A5HJ6IRE.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -161,16 +161,14 @@ process.on("exit", () => {
161
161
  async function getCDPTargets(cdpEndpoint) {
162
162
  try {
163
163
  const ep = String(cdpEndpoint);
164
- let host = "localhost";
165
- let port = "9222";
164
+ let url = "http://localhost:9222/json/list";
166
165
  if (ep.startsWith("http://") || ep.startsWith("https://")) {
167
166
  const u = new URL(ep);
168
- host = u.hostname;
169
- port = u.port || "9222";
167
+ u.pathname = (u.pathname.replace(/\/+$/, "") || "") + "/json/list";
168
+ url = u.toString();
170
169
  } else if (/^\d+$/.test(ep)) {
171
- port = ep;
170
+ url = `http://localhost:${ep}/json/list`;
172
171
  }
173
- const url = `http://${host}:${port}/json/list`;
174
172
  const resp = await fetch(url);
175
173
  return await resp.json();
176
174
  } catch {
@@ -655,6 +653,10 @@ async function createSession(name, url, options) {
655
653
  }
656
654
  }
657
655
  page = targetPage;
656
+ if (isCDP) {
657
+ await Promise.resolve(targetPage.bringToFront?.()).catch(() => {
658
+ });
659
+ }
658
660
  } else {
659
661
  context = await b.newContext({ viewport: { width: 1920, height: 1080 } });
660
662
  page = await context.newPage();
@@ -711,6 +711,26 @@ var XBKeyboardImpl = class {
711
711
  ...mapping.keyCode ? { windowsVirtualKeyCode: mapping.keyCode } : {}
712
712
  });
713
713
  }
714
+ /**
715
+ * Shortcut combo press (modifier+key) with explicit per-event modifiers
716
+ * bitmask — plain down(mod)+press(key) inserts the raw character because
717
+ * CDP modifiers are per-event fields, not session state (d56: Meta,v
718
+ * typed a literal 'v'). keyDown type carries the default action so the
719
+ * browser's shortcut dispatcher sees the combo (e.g. native paste).
720
+ */
721
+ async pressCombo(key, modifier) {
722
+ const MODBIT = { Alt: 1, Control: 2, Meta: 4, Shift: 8 };
723
+ const m = resolveKeyMapping(modifier);
724
+ const k = resolveKeyMapping(key);
725
+ const bits = MODBIT[modifier] ?? 0;
726
+ await this.dispatchKeyEvent({ type: "rawKeyDown", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: bits });
727
+ await this.dispatchKeyEvent({ type: "keyDown", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
728
+ if (process.env.XBROWSER_STEALTH !== "off") {
729
+ await sleep3(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
730
+ }
731
+ await this.dispatchKeyEvent({ type: "keyUp", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
732
+ await this.dispatchKeyEvent({ type: "keyUp", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: 0 });
733
+ }
714
734
  async dispatchKeyEvent(params) {
715
735
  await this.conn.send("Input.dispatchKeyEvent", params, this.sessionId);
716
736
  }
@@ -1094,6 +1114,18 @@ var XBLocatorImpl = class _XBLocatorImpl {
1094
1114
  await waitForActionable(this.page, this.selector, opts);
1095
1115
  await scrollIntoView(this.page, this.selector);
1096
1116
  await this.click({ ...opts });
1117
+ if (process.env.XBROWSER_STEALTH !== "off" && value.length >= 40 && process.env.XBROWSER_FILL_TYPE !== "type") {
1118
+ try {
1119
+ const { pasteViaClipboard, syntheticPaste } = await import("./clipboard-BOL2GP2E.js");
1120
+ await pasteViaClipboard(this.page, value);
1121
+ const got = await this.page.evaluate(
1122
+ `(function(){ const el = ${this._q(this.selector)}; return el ? (el.value || '') : ''; })()`
1123
+ );
1124
+ if (got === value) return;
1125
+ if (await syntheticPaste(this.page, this._q(this.selector), value)) return;
1126
+ } catch {
1127
+ }
1128
+ }
1097
1129
  await this.page.keyboard.type(value, { stealth: true });
1098
1130
  return;
1099
1131
  await this.page.evaluate(`
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createRuleEngine,
3
3
  launch
4
- } from "./chunk-UXDGEDT7.js";
4
+ } from "./chunk-LTBNQERK.js";
5
5
  import {
6
6
  errMsg
7
7
  } from "./chunk-GDKLH7ZY.js";
@@ -588,16 +588,14 @@ process.on("exit", () => {
588
588
  async function getCDPTargets(cdpEndpoint) {
589
589
  try {
590
590
  const ep = String(cdpEndpoint);
591
- let host = "localhost";
592
- let port = "9222";
591
+ let url = "http://localhost:9222/json/list";
593
592
  if (ep.startsWith("http://") || ep.startsWith("https://")) {
594
593
  const u = new URL(ep);
595
- host = u.hostname;
596
- port = u.port || "9222";
594
+ u.pathname = (u.pathname.replace(/\/+$/, "") || "") + "/json/list";
595
+ url = u.toString();
597
596
  } else if (/^\d+$/.test(ep)) {
598
- port = ep;
597
+ url = `http://localhost:${ep}/json/list`;
599
598
  }
600
- const url = `http://${host}:${port}/json/list`;
601
599
  const resp = await fetch(url);
602
600
  return await resp.json();
603
601
  } catch {
@@ -1082,6 +1080,10 @@ async function createSession(name, url, options) {
1082
1080
  }
1083
1081
  }
1084
1082
  page = targetPage;
1083
+ if (isCDP) {
1084
+ await Promise.resolve(targetPage.bringToFront?.()).catch(() => {
1085
+ });
1086
+ }
1085
1087
  } else {
1086
1088
  context = await b.newContext({ viewport: { width: 1920, height: 1080 } });
1087
1089
  page = await context.newPage();
@@ -712,6 +712,26 @@ var XBKeyboardImpl = class {
712
712
  ...mapping.keyCode ? { windowsVirtualKeyCode: mapping.keyCode } : {}
713
713
  });
714
714
  }
715
+ /**
716
+ * Shortcut combo press (modifier+key) with explicit per-event modifiers
717
+ * bitmask — plain down(mod)+press(key) inserts the raw character because
718
+ * CDP modifiers are per-event fields, not session state (d56: Meta,v
719
+ * typed a literal 'v'). keyDown type carries the default action so the
720
+ * browser's shortcut dispatcher sees the combo (e.g. native paste).
721
+ */
722
+ async pressCombo(key, modifier) {
723
+ const MODBIT = { Alt: 1, Control: 2, Meta: 4, Shift: 8 };
724
+ const m = resolveKeyMapping(modifier);
725
+ const k = resolveKeyMapping(key);
726
+ const bits = MODBIT[modifier] ?? 0;
727
+ await this.dispatchKeyEvent({ type: "rawKeyDown", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: bits });
728
+ await this.dispatchKeyEvent({ type: "keyDown", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
729
+ if (process.env.XBROWSER_STEALTH !== "off") {
730
+ await sleep3(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
731
+ }
732
+ await this.dispatchKeyEvent({ type: "keyUp", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
733
+ await this.dispatchKeyEvent({ type: "keyUp", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: 0 });
734
+ }
715
735
  async dispatchKeyEvent(params) {
716
736
  await this.conn.send("Input.dispatchKeyEvent", params, this.sessionId);
717
737
  }
@@ -993,6 +1013,18 @@ var XBLocatorImpl = class _XBLocatorImpl {
993
1013
  await waitForActionable(this.page, this.selector, opts);
994
1014
  await scrollIntoView(this.page, this.selector);
995
1015
  await this.click({ ...opts });
1016
+ if (process.env.XBROWSER_STEALTH !== "off" && value.length >= 40 && process.env.XBROWSER_FILL_TYPE !== "type") {
1017
+ try {
1018
+ const { pasteViaClipboard, syntheticPaste } = await import("./clipboard-BOL2GP2E.js");
1019
+ await pasteViaClipboard(this.page, value);
1020
+ const got = await this.page.evaluate(
1021
+ `(function(){ const el = ${this._q(this.selector)}; return el ? (el.value || '') : ''; })()`
1022
+ );
1023
+ if (got === value) return;
1024
+ if (await syntheticPaste(this.page, this._q(this.selector), value)) return;
1025
+ } catch {
1026
+ }
1027
+ }
996
1028
  await this.page.keyboard.type(value, { stealth: true });
997
1029
  return;
998
1030
  await this.page.evaluate(`
package/dist/cli.js CHANGED
@@ -26,6 +26,16 @@ import {
26
26
  import {
27
27
  buildViewerUrl
28
28
  } from "./chunk-3OD76SUE.js";
29
+ import {
30
+ NPM_REGISTRY_URL,
31
+ NPM_SCOPE,
32
+ getConfigValue,
33
+ getMarketplaceUrl,
34
+ loadConfig,
35
+ resolveNpmPackageWithFallback,
36
+ resolveScreenshotsDir,
37
+ setConfigValue
38
+ } from "./chunk-ZTHE5RBZ.js";
29
39
  import {
30
40
  getDaemonConfig,
31
41
  getDaemonProcessStatus,
@@ -62,7 +72,7 @@ import {
62
72
  setActivePage,
63
73
  sleep,
64
74
  wheelDelta
65
- } from "./chunk-HFP4QCZL.js";
75
+ } from "./chunk-5EYOEB4R.js";
66
76
  import "./chunk-TNEN6VQ2.js";
67
77
  import {
68
78
  errMsg
@@ -71,16 +81,6 @@ import {
71
81
  detectAntiBot,
72
82
  formatDetectionMessage
73
83
  } from "./chunk-JKVUFP3G.js";
74
- import {
75
- NPM_REGISTRY_URL,
76
- NPM_SCOPE,
77
- getConfigValue,
78
- getMarketplaceUrl,
79
- loadConfig,
80
- resolveNpmPackageWithFallback,
81
- resolveScreenshotsDir,
82
- setConfigValue
83
- } from "./chunk-ZTHE5RBZ.js";
84
84
  import "./chunk-KFQGP6VL.js";
85
85
 
86
86
  // src/router.ts
@@ -7542,7 +7542,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7542
7542
  }
7543
7543
  let targetPageOverride = null;
7544
7544
  if (_target && extraOpts?.cdpEndpoint) {
7545
- const { findTargetPage } = await import("./browser-JNT2I73V.js");
7545
+ const { findTargetPage } = await import("./browser-KT4FOWBO.js");
7546
7546
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7547
7547
  if (!targetPageOverride) {
7548
7548
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -7756,7 +7756,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7756
7756
  const errorMessage = errMsg(err);
7757
7757
  if (session?.page && process.env.XBROWSER_RECOVERY && !extraOpts?._recoveryAttempted) {
7758
7758
  try {
7759
- const { attemptRecovery } = await import("./recovery-FTZGV6VY.js");
7759
+ const { attemptRecovery } = await import("./recovery-NXC35EQN.js");
7760
7760
  const recovery = await attemptRecovery(
7761
7761
  session.page,
7762
7762
  sessionName,
@@ -13717,7 +13717,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
13717
13717
  const targetPage = pages[cmdTabIndex];
13718
13718
  await targetPage.bringToFront().catch(() => {
13719
13719
  });
13720
- const { setActivePage: setActivePage2 } = await import("./browser-JNT2I73V.js");
13720
+ const { setActivePage: setActivePage2 } = await import("./browser-KT4FOWBO.js");
13721
13721
  setActivePage2(session, targetPage);
13722
13722
  }
13723
13723
  }
@@ -13993,7 +13993,7 @@ async function main() {
13993
13993
  const command = process.argv[2];
13994
13994
  const isLongRunning = command === "preview" || command === "serve";
13995
13995
  if (!isLongRunning) {
13996
- const { ensureProcessCanExit } = await import("./browser-JNT2I73V.js");
13996
+ const { ensureProcessCanExit } = await import("./browser-KT4FOWBO.js");
13997
13997
  await ensureProcessCanExit().catch(() => {
13998
13998
  });
13999
13999
  process.exit(process.exitCode || exitCode);
@@ -0,0 +1,58 @@
1
+ import "./chunk-KFQGP6VL.js";
2
+
3
+ // src/utils/clipboard.ts
4
+ import { exec, execSync } from "child_process";
5
+ function writeClipboard(text) {
6
+ const plat = process.platform;
7
+ if (plat === "darwin") {
8
+ const p = exec("pbcopy");
9
+ if (!p.stdin) throw new Error("pbcopy stdin unavailable");
10
+ p.stdin.write(text);
11
+ p.stdin.end();
12
+ execSync("sleep 0.05");
13
+ } else if (plat === "linux") {
14
+ execSync("command -v xclip >/dev/null 2>&1 && echo ok", { stdio: "ignore" });
15
+ const p = exec("xclip -selection clipboard -in");
16
+ if (!p.stdin) throw new Error("xclip stdin unavailable");
17
+ p.stdin.write(text);
18
+ p.stdin.end();
19
+ execSync("sleep 0.05");
20
+ } else if (plat === "win32") {
21
+ const p = exec("clip");
22
+ if (!p.stdin) throw new Error("clip stdin unavailable");
23
+ p.stdin.write(text);
24
+ p.stdin.end();
25
+ execSync("timeout /t 1 /nobreak >nul");
26
+ } else {
27
+ throw new Error(`Unsupported platform for clipboard: ${plat}`);
28
+ }
29
+ }
30
+ async function pasteViaClipboard(page, text) {
31
+ writeClipboard(text);
32
+ const kb = page.keyboard;
33
+ const mod = process.platform === "darwin" ? "Meta" : "Control";
34
+ await kb.pressCombo("v", mod);
35
+ await new Promise((r) => setTimeout(r, 150));
36
+ }
37
+ async function syntheticPaste(page, selector, text) {
38
+ const result = await page.evaluate(`
39
+ (function() {
40
+ const el = ${"{SELECTOR}"};
41
+ if (!el) return false;
42
+ el.focus();
43
+ if (el.value) { el.select(); document.execCommand('delete'); }
44
+ try {
45
+ const dt = new DataTransfer();
46
+ dt.setData('text/plain', ${JSON.stringify(text)});
47
+ el.dispatchEvent(new ClipboardEvent('paste', { clipboardData: dt, bubbles: true, cancelable: true }));
48
+ } catch (e) { /* ClipboardEvent ctor guard */ }
49
+ const ok = document.execCommand('insertText', false, ${JSON.stringify(text)});
50
+ return ok === true && (el.value || '') === ${JSON.stringify(text)};
51
+ })()
52
+ `.replace("{SELECTOR}", selector));
53
+ return result === true;
54
+ }
55
+ export {
56
+ pasteViaClipboard,
57
+ syntheticPaste
58
+ };
@@ -0,0 +1,58 @@
1
+ import "./chunk-3RG5ZIWI.js";
2
+
3
+ // src/utils/clipboard.ts
4
+ import { exec, execSync } from "child_process";
5
+ function writeClipboard(text) {
6
+ const plat = process.platform;
7
+ if (plat === "darwin") {
8
+ const p = exec("pbcopy");
9
+ if (!p.stdin) throw new Error("pbcopy stdin unavailable");
10
+ p.stdin.write(text);
11
+ p.stdin.end();
12
+ execSync("sleep 0.05");
13
+ } else if (plat === "linux") {
14
+ execSync("command -v xclip >/dev/null 2>&1 && echo ok", { stdio: "ignore" });
15
+ const p = exec("xclip -selection clipboard -in");
16
+ if (!p.stdin) throw new Error("xclip stdin unavailable");
17
+ p.stdin.write(text);
18
+ p.stdin.end();
19
+ execSync("sleep 0.05");
20
+ } else if (plat === "win32") {
21
+ const p = exec("clip");
22
+ if (!p.stdin) throw new Error("clip stdin unavailable");
23
+ p.stdin.write(text);
24
+ p.stdin.end();
25
+ execSync("timeout /t 1 /nobreak >nul");
26
+ } else {
27
+ throw new Error(`Unsupported platform for clipboard: ${plat}`);
28
+ }
29
+ }
30
+ async function pasteViaClipboard(page, text) {
31
+ writeClipboard(text);
32
+ const kb = page.keyboard;
33
+ const mod = process.platform === "darwin" ? "Meta" : "Control";
34
+ await kb.pressCombo("v", mod);
35
+ await new Promise((r) => setTimeout(r, 150));
36
+ }
37
+ async function syntheticPaste(page, selector, text) {
38
+ const result = await page.evaluate(`
39
+ (function() {
40
+ const el = ${"{SELECTOR}"};
41
+ if (!el) return false;
42
+ el.focus();
43
+ if (el.value) { el.select(); document.execCommand('delete'); }
44
+ try {
45
+ const dt = new DataTransfer();
46
+ dt.setData('text/plain', ${JSON.stringify(text)});
47
+ el.dispatchEvent(new ClipboardEvent('paste', { clipboardData: dt, bubbles: true, cancelable: true }));
48
+ } catch (e) { /* ClipboardEvent ctor guard */ }
49
+ const ok = document.execCommand('insertText', false, ${JSON.stringify(text)});
50
+ return ok === true && (el.value || '') === ${JSON.stringify(text)};
51
+ })()
52
+ `.replace("{SELECTOR}", selector));
53
+ return result === true;
54
+ }
55
+ export {
56
+ pasteViaClipboard,
57
+ syntheticPaste
58
+ };
@@ -7,6 +7,10 @@ import {
7
7
  import {
8
8
  buildViewerUrl
9
9
  } from "./chunk-TZPKFUBT.js";
10
+ import {
11
+ ScreencastCapturer,
12
+ resolveScreenshotsDir
13
+ } from "./chunk-HBMEFSTB.js";
10
14
  import "./chunk-CG3D3CHY.js";
11
15
  import {
12
16
  commandLogStore,
@@ -30,13 +34,13 @@ import {
30
34
  resolveLaunchOpts,
31
35
  saveSessionDiskMeta,
32
36
  setActivePage
33
- } from "./chunk-XQ4KOZ37.js";
37
+ } from "./chunk-GWQ5NTVE.js";
34
38
  import {
35
39
  createRuleEngine,
36
40
  rand,
37
41
  sleep,
38
42
  wheelDelta
39
- } from "./chunk-UXDGEDT7.js";
43
+ } from "./chunk-LTBNQERK.js";
40
44
  import {
41
45
  queryJS
42
46
  } from "./chunk-3FWLW7FS.js";
@@ -48,10 +52,6 @@ import {
48
52
  detectAntiBot,
49
53
  formatDetectionMessage
50
54
  } from "./chunk-JKVUFP3G.js";
51
- import {
52
- ScreencastCapturer,
53
- resolveScreenshotsDir
54
- } from "./chunk-HBMEFSTB.js";
55
55
  import "./chunk-KFQGP6VL.js";
56
56
 
57
57
  // src/daemon/daemon-main.ts
@@ -7060,7 +7060,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7060
7060
  }
7061
7061
  let targetPageOverride = null;
7062
7062
  if (_target && extraOpts?.cdpEndpoint) {
7063
- const { findTargetPage } = await import("./browser-YYMKZWTU.js");
7063
+ const { findTargetPage } = await import("./browser-AOVQTGJ7.js");
7064
7064
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7065
7065
  if (!targetPageOverride) {
7066
7066
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -7274,7 +7274,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7274
7274
  const errorMessage = errMsg(err);
7275
7275
  if (session?.page && process.env.XBROWSER_RECOVERY && !extraOpts?._recoveryAttempted) {
7276
7276
  try {
7277
- const { attemptRecovery } = await import("./recovery-Z3RDZENA.js");
7277
+ const { attemptRecovery } = await import("./recovery-MDWAVXE4.js");
7278
7278
  const recovery = await attemptRecovery(
7279
7279
  session.page,
7280
7280
  sessionName,
@@ -8314,7 +8314,7 @@ function createRPCHandler() {
8314
8314
  return result;
8315
8315
  } catch (err) {
8316
8316
  const errorMessage = errMsg(err);
8317
- const { attemptRecovery } = await import("./recovery-Z3RDZENA.js");
8317
+ const { attemptRecovery } = await import("./recovery-MDWAVXE4.js");
8318
8318
  const recovery = await attemptRecovery(
8319
8319
  session?.page,
8320
8320
  sessionName,
@@ -8879,7 +8879,7 @@ function createRPCHandler() {
8879
8879
  if (isNewFormat) {
8880
8880
  try {
8881
8881
  const replayErrors = [];
8882
- const { SessionReplayer } = await import("./session-replayer-DKHXF3DZ.js");
8882
+ const { SessionReplayer } = await import("./session-replayer-MJH5W7BB.js");
8883
8883
  const replayer = new SessionReplayer({
8884
8884
  page: session.page,
8885
8885
  stepDelay: slowMo * 500,
package/dist/index.d.ts CHANGED
@@ -318,6 +318,8 @@ interface XBKeyboard {
318
318
  }): Promise<void>;
319
319
  /** Navigation key with CDP 'keyDown' type (carries browser default actions) */
320
320
  pressNav(key: string): Promise<void>;
321
+ /** Shortcut combo (modifier+key) with explicit per-event modifiers bitmask */
322
+ pressCombo(key: string, modifier: 'Meta' | 'Control' | 'Alt' | 'Shift'): Promise<void>;
321
323
  down(key: string): Promise<void>;
322
324
  up(key: string): Promise<void>;
323
325
  type(text: string, opts?: {
package/dist/index.js CHANGED
@@ -1,3 +1,24 @@
1
+ import {
2
+ filterRecording,
3
+ parseExcludeTypes
4
+ } from "./chunk-ANVL2ID2.js";
5
+ import {
6
+ closeAllSessions,
7
+ closeEphemeralContext,
8
+ closeSessionByName,
9
+ createEphemeralContext,
10
+ createSession,
11
+ destroyBrowser,
12
+ findOrRestoreSession,
13
+ findSession,
14
+ getAllSessions,
15
+ getBrowser,
16
+ getSessionById,
17
+ resetForTesting,
18
+ resolveLaunchOpts,
19
+ saveSessionDiskMeta,
20
+ setActivePage
21
+ } from "./chunk-7V3B7VPX.js";
1
22
  import {
2
23
  detectAntiBot,
3
24
  formatDetectionMessage
@@ -61,43 +82,11 @@ import {
61
82
  extractRecording,
62
83
  printExtractSummary
63
84
  } from "./chunk-X46HDAOT.js";
64
- import {
65
- filterRecording,
66
- parseExcludeTypes
67
- } from "./chunk-ANVL2ID2.js";
68
- import {
69
- SessionRecorder
70
- } from "./chunk-NODRQGOK.js";
71
- import {
72
- addKnownIssue,
73
- getKnowledgePath,
74
- init_site_knowledge,
75
- listSiteKnowledge,
76
- readSiteKnowledge,
77
- readSiteKnowledgeMarkdown
78
- } from "./chunk-OZKD3W4X.js";
79
- import {
80
- closeAllSessions,
81
- closeEphemeralContext,
82
- closeSessionByName,
83
- createEphemeralContext,
84
- createSession,
85
- destroyBrowser,
86
- findOrRestoreSession,
87
- findSession,
88
- getAllSessions,
89
- getBrowser,
90
- getSessionById,
91
- resetForTesting,
92
- resolveLaunchOpts,
93
- saveSessionDiskMeta,
94
- setActivePage
95
- } from "./chunk-K5E4CWRV.js";
96
85
  import {
97
86
  rand,
98
87
  sleep,
99
88
  wheelDelta
100
- } from "./chunk-NTTFKS6T.js";
89
+ } from "./chunk-A5HJ6IRE.js";
101
90
  import "./chunk-TNEN6VQ2.js";
102
91
  import {
103
92
  errMsg
@@ -118,6 +107,17 @@ import {
118
107
  networkAnomalyRule,
119
108
  pageLifecycleRule
120
109
  } from "./chunk-H2A5JUK5.js";
110
+ import {
111
+ SessionRecorder
112
+ } from "./chunk-NODRQGOK.js";
113
+ import {
114
+ addKnownIssue,
115
+ getKnowledgePath,
116
+ init_site_knowledge,
117
+ listSiteKnowledge,
118
+ readSiteKnowledge,
119
+ readSiteKnowledgeMarkdown
120
+ } from "./chunk-OZKD3W4X.js";
121
121
  import {
122
122
  __require
123
123
  } from "./chunk-KFQGP6VL.js";
@@ -7893,7 +7893,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7893
7893
  }
7894
7894
  let targetPageOverride = null;
7895
7895
  if (_target && extraOpts?.cdpEndpoint) {
7896
- const { findTargetPage } = await import("./browser-4FKHBUBJ.js");
7896
+ const { findTargetPage } = await import("./browser-3KTEVTMU.js");
7897
7897
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7898
7898
  if (!targetPageOverride) {
7899
7899
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -14106,7 +14106,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
14106
14106
  const targetPage = pages[cmdTabIndex];
14107
14107
  await targetPage.bringToFront().catch(() => {
14108
14108
  });
14109
- const { setActivePage: setActivePage2 } = await import("./browser-4FKHBUBJ.js");
14109
+ const { setActivePage: setActivePage2 } = await import("./browser-3KTEVTMU.js");
14110
14110
  setActivePage2(session, targetPage);
14111
14111
  }
14112
14112
  }
@@ -17279,7 +17279,7 @@ var DataCollector = class {
17279
17279
  return results;
17280
17280
  }
17281
17281
  async createBrowserContext() {
17282
- const { launch } = await import("./cdp-driver-QX72T7SU.js");
17282
+ const { launch } = await import("./cdp-driver-OC37OT4B.js");
17283
17283
  const { browser } = await launch({
17284
17284
  headless: true,
17285
17285
  args: ["--no-sandbox", "--disable-setuid-sandbox"]
@@ -34,7 +34,7 @@ var SessionReplayer = class {
34
34
  if (this.opts.page) {
35
35
  this.page = this.opts.page;
36
36
  } else if (this.opts.cdpUrl) {
37
- const { launch } = await import("./cdp-driver-7RW4NY2X.js");
37
+ const { launch } = await import("./cdp-driver-DKNLIA6B.js");
38
38
  const { browser } = await launch({ cdpEndpoint: this.opts.cdpUrl });
39
39
  let contexts = browser.contexts();
40
40
  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.15.0",
3
+ "version": "1.16.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": {
@@ -1,11 +1,11 @@
1
- import {
2
- buildViewerUrl
3
- } from "./chunk-TZPKFUBT.js";
4
- import "./chunk-CG3D3CHY.js";
5
1
  import {
6
2
  HumanInteractionManager
7
3
  } from "./chunk-OMU63E6J.js";
4
+ import {
5
+ buildViewerUrl
6
+ } from "./chunk-TZPKFUBT.js";
8
7
  import "./chunk-HBMEFSTB.js";
8
+ import "./chunk-CG3D3CHY.js";
9
9
  import "./chunk-KFQGP6VL.js";
10
10
 
11
11
  // src/recovery.ts
@@ -1,11 +1,11 @@
1
- import {
2
- buildViewerUrl
3
- } from "./chunk-3OD76SUE.js";
4
- import "./chunk-Q2DFJQGS.js";
5
1
  import {
6
2
  HumanInteractionManager
7
3
  } from "./chunk-TEXCXIBW.js";
4
+ import {
5
+ buildViewerUrl
6
+ } from "./chunk-3OD76SUE.js";
8
7
  import "./chunk-ZTHE5RBZ.js";
8
+ import "./chunk-Q2DFJQGS.js";
9
9
  import "./chunk-KFQGP6VL.js";
10
10
 
11
11
  // src/recovery.ts