@xbrowser/cli 1.9.1 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,32 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- SessionRecorder
4
- } from "./chunk-YSCY52UJ.js";
5
- import {
6
- addKnownIssue,
7
- getKnowledgePath,
8
- init_site_knowledge,
9
- listSiteKnowledge,
10
- readSiteKnowledge,
11
- readSiteKnowledgeMarkdown
12
- } from "./chunk-OZKD3W4X.js";
13
- import {
14
- closeAllSessions,
15
- closeEphemeralContext,
16
- closeSessionByName,
17
- createEphemeralContext,
18
- createRuleEngine,
19
- createSession,
20
- findOrRestoreSession,
21
- findSession,
22
- getAllSessions,
23
- getBrowser,
24
- getSessionById,
25
- resolveLaunchOpts,
26
- saveSessionDiskMeta,
27
- setActivePage
28
- } from "./chunk-Z7WC4P2M.js";
29
- import "./chunk-TNEN6VQ2.js";
30
2
  import {
31
3
  forwardCommandLog,
32
4
  forwardNetworkAnalyze,
@@ -56,9 +28,50 @@ import {
56
28
  stopDaemonProcess,
57
29
  version
58
30
  } from "./chunk-53LRNYPG.js";
31
+ import {
32
+ SessionRecorder
33
+ } from "./chunk-YSCY52UJ.js";
34
+ import {
35
+ addKnownIssue,
36
+ getKnowledgePath,
37
+ init_site_knowledge,
38
+ listSiteKnowledge,
39
+ readSiteKnowledge,
40
+ readSiteKnowledgeMarkdown
41
+ } from "./chunk-OZKD3W4X.js";
42
+ import {
43
+ closeAllSessions,
44
+ closeEphemeralContext,
45
+ closeSessionByName,
46
+ createEphemeralContext,
47
+ createRuleEngine,
48
+ createSession,
49
+ findOrRestoreSession,
50
+ findSession,
51
+ getAllSessions,
52
+ getBrowser,
53
+ getSessionById,
54
+ resolveLaunchOpts,
55
+ saveSessionDiskMeta,
56
+ setActivePage
57
+ } from "./chunk-Z7WC4P2M.js";
58
+ import "./chunk-TNEN6VQ2.js";
59
59
  import {
60
60
  errMsg
61
61
  } from "./chunk-GDKLH7ZY.js";
62
+ import {
63
+ detectAntiBot,
64
+ formatDetectionMessage
65
+ } from "./chunk-DPJNCMLC.js";
66
+ import {
67
+ NPM_REGISTRY_URL,
68
+ NPM_SCOPE,
69
+ getConfigValue,
70
+ getMarketplaceUrl,
71
+ loadConfig,
72
+ resolveNpmPackageWithFallback,
73
+ setConfigValue
74
+ } from "./chunk-IIM5GOD7.js";
62
75
  import "./chunk-KFQGP6VL.js";
63
76
 
64
77
  // src/router.ts
@@ -5850,246 +5863,12 @@ function describeSelector(strategy, value, name) {
5850
5863
  }
5851
5864
  }
5852
5865
 
5853
- // src/anti-bot-detection.ts
5854
- var CAPTCHA_PATTERNS = [
5855
- { name: "reCAPTCHA", pattern: /recaptcha/i },
5856
- { name: "hCaptcha", pattern: /hcaptcha/i },
5857
- { name: "Turnstile", pattern: /turnstile/i },
5858
- { name: "Cloudflare", pattern: /cloudflare/i },
5859
- { name: "FunCaptcha", pattern: /funcaptcha/i },
5860
- { name: "AWS WAF", pattern: /aws.*challenge/i }
5861
- ];
5862
- var WARNING_TEXTS = [
5863
- { text: "detected as bot", severity: "high" },
5864
- { text: "suspicious activity", severity: "high" },
5865
- { text: "unusual traffic", severity: "high" },
5866
- { text: "please verify you are human", severity: "medium" },
5867
- { text: "access denied", severity: "high" },
5868
- { text: "blocked", severity: "high" },
5869
- { text: "rate limit", severity: "medium" },
5870
- { text: "too many requests", severity: "medium" },
5871
- { text: "\u9A8C\u8BC1", severity: "low" },
5872
- { text: "\u9A8C\u8BC1\u7801", severity: "low" }
5873
- ];
5874
- var BLOCKED_URL_PATTERNS = [
5875
- { name: "Cloudflare Challenge", pattern: /challenge-platform/i },
5876
- { name: "Cloudflare Captcha", pattern: /cf-challenge/i },
5877
- { name: "AWS WAF", pattern: /aws-waf/i },
5878
- { name: "Generic Captcha", pattern: /captcha/i }
5879
- ];
5880
- async function detectAntiBot(page, config = {}) {
5881
- const {
5882
- checkCaptcha = true,
5883
- checkWarning = true,
5884
- checkBlocked = true,
5885
- checkLogin = false,
5886
- checkWebdriver = true
5887
- } = config;
5888
- const result = {
5889
- detected: false
5866
+ // src/context.ts
5867
+ function attachDetectAntiBot(ctx) {
5868
+ ctx.detectAntiBot = async (page, config) => {
5869
+ const { detectAntiBot: detectAntiBot2 } = await import("./anti-bot-MCVM6IFB.js");
5870
+ return detectAntiBot2(page, config);
5890
5871
  };
5891
- if (checkCaptcha) {
5892
- const captchaResult = await detectCaptcha2(page);
5893
- if (captchaResult.detected) {
5894
- return captchaResult;
5895
- }
5896
- }
5897
- if (checkWarning) {
5898
- const warningResult = await detectWarningText(page);
5899
- if (warningResult.detected) {
5900
- return warningResult;
5901
- }
5902
- }
5903
- if (checkBlocked) {
5904
- const blockedResult = await detectBlockedPage(page);
5905
- if (blockedResult.detected) {
5906
- return blockedResult;
5907
- }
5908
- }
5909
- if (checkWebdriver) {
5910
- const webdriverResult = await detectWebdriverExposure(page);
5911
- if (webdriverResult.detected) {
5912
- return webdriverResult;
5913
- }
5914
- }
5915
- if (checkLogin) {
5916
- const loginResult = await detectLoginRequired(page);
5917
- if (loginResult.detected) {
5918
- return loginResult;
5919
- }
5920
- }
5921
- return result;
5922
- }
5923
- async function detectCaptcha2(page) {
5924
- try {
5925
- const iframes = await page.frames();
5926
- for (const iframe of iframes) {
5927
- const src = iframe.url();
5928
- for (const pattern of CAPTCHA_PATTERNS) {
5929
- if (pattern.pattern.test(src)) {
5930
- return {
5931
- detected: true,
5932
- type: "captcha",
5933
- severity: "high",
5934
- message: `Detected ${pattern.name} CAPTCHA (iframe: ${src})`,
5935
- selector: `iframe[src*="${pattern.name.toLowerCase()}"]`,
5936
- actionRequired: "manual"
5937
- };
5938
- }
5939
- }
5940
- }
5941
- const captchaSelectors = [
5942
- ".g-recaptcha",
5943
- "#captcha",
5944
- '[class*="captcha"]',
5945
- '[id*="captcha"]',
5946
- 'iframe[src*="recaptcha"]',
5947
- 'iframe[src*="hcaptcha"]',
5948
- 'iframe[src*="turnstile"]'
5949
- ];
5950
- for (const selector of captchaSelectors) {
5951
- const element = await page.$(selector).catch(() => null);
5952
- if (element) {
5953
- return {
5954
- detected: true,
5955
- type: "captcha",
5956
- severity: "high",
5957
- message: `CAPTCHA element found: ${selector}`,
5958
- selector,
5959
- actionRequired: "manual"
5960
- };
5961
- }
5962
- }
5963
- return { detected: false };
5964
- } catch {
5965
- return { detected: false };
5966
- }
5967
- }
5968
- async function detectWarningText(page) {
5969
- try {
5970
- const pageText = await page.textContent("body").catch(() => "") || "";
5971
- const lowerText = pageText.toLowerCase();
5972
- for (const { text, severity } of WARNING_TEXTS) {
5973
- if (lowerText.includes(text.toLowerCase())) {
5974
- return {
5975
- detected: true,
5976
- type: "warning",
5977
- severity,
5978
- message: `Anti-bot warning text found: "${text}"`,
5979
- actionRequired: severity === "high" ? "manual" : "retry"
5980
- };
5981
- }
5982
- }
5983
- return { detected: false };
5984
- } catch {
5985
- return { detected: false };
5986
- }
5987
- }
5988
- async function detectBlockedPage(page) {
5989
- try {
5990
- const url = page.url();
5991
- for (const { name, pattern } of BLOCKED_URL_PATTERNS) {
5992
- if (pattern.test(url)) {
5993
- return {
5994
- detected: true,
5995
- type: "blocked",
5996
- severity: "high",
5997
- message: `Blocked page detected: ${name} (${url})`,
5998
- actionRequired: "manual"
5999
- };
6000
- }
6001
- }
6002
- return { detected: false };
6003
- } catch {
6004
- return { detected: false };
6005
- }
6006
- }
6007
- async function detectWebdriverExposure(page) {
6008
- try {
6009
- const webdriver = await page.evaluate(() => {
6010
- return {
6011
- webdriver: navigator.webdriver,
6012
- webdriverScriptFn: !!window.__webdriver_script_fn,
6013
- webdriverEvaluate: !!window.__webdriver_evaluate,
6014
- chrome: !!window.chrome,
6015
- permissions: navigator.permissions
6016
- };
6017
- }).catch(() => null);
6018
- if (!webdriver) {
6019
- return { detected: false };
6020
- }
6021
- const issues = [];
6022
- if (webdriver.webdriver === true) {
6023
- issues.push("navigator.webdriver === true");
6024
- }
6025
- if (webdriver.webdriverScriptFn) {
6026
- issues.push("__webdriver_script_fn present");
6027
- }
6028
- if (webdriver.webdriverEvaluate) {
6029
- issues.push("__webdriver_evaluate present");
6030
- }
6031
- if (!webdriver.chrome) {
6032
- issues.push("window.chrome missing");
6033
- }
6034
- if (!webdriver.permissions) {
6035
- issues.push("navigator.permissions missing");
6036
- }
6037
- if (issues.length > 0) {
6038
- return {
6039
- detected: true,
6040
- type: "warning",
6041
- severity: "high",
6042
- message: `Automation markers exposed: ${issues.join(", ")}`,
6043
- actionRequired: "manual"
6044
- };
6045
- }
6046
- return { detected: false };
6047
- } catch {
6048
- return { detected: false };
6049
- }
6050
- }
6051
- async function detectLoginRequired(page) {
6052
- try {
6053
- const loginSelectors = [
6054
- 'a[href*="login"]',
6055
- 'a[href*="signin"]',
6056
- 'a[href*="sign-in"]',
6057
- 'button:has-text("Log in")',
6058
- 'button:has-text("Sign in")',
6059
- 'button:has-text("Login")',
6060
- 'button:has-text("\u767B\u5F55")'
6061
- ];
6062
- for (const selector of loginSelectors) {
6063
- const element = await page.$(selector).catch(() => null);
6064
- if (element) {
6065
- const rect = await element.boundingBox().catch(() => null);
6066
- if (rect && rect.y < 200) {
6067
- return {
6068
- detected: true,
6069
- type: "login",
6070
- severity: "medium",
6071
- message: "Login button detected in page header",
6072
- selector,
6073
- actionRequired: "manual"
6074
- };
6075
- }
6076
- }
6077
- }
6078
- return { detected: false };
6079
- } catch {
6080
- return { detected: false };
6081
- }
6082
- }
6083
- function formatDetectionMessage(result) {
6084
- if (!result.detected) {
6085
- return "\u2705 No anti-bot detection detected.";
6086
- }
6087
- const emoji = result.severity === "high" ? "\u{1F6A8}" : result.severity === "medium" ? "\u26A0\uFE0F" : "\u2139\uFE0F";
6088
- const action = result.actionRequired === "manual" ? "Please handle manually" : result.actionRequired === "retry" ? "Consider retrying with delay" : "Consider switching to a different session";
6089
- return `${emoji} Detection: ${result.message}
6090
- Type: ${result.type}
6091
- Severity: ${result.severity}
6092
- Action: ${action}`;
6093
5872
  }
6094
5873
 
6095
5874
  // src/plugin/loader.ts
@@ -7335,6 +7114,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7335
7114
  cliName: "xbrowser",
7336
7115
  tips: new TipCollector2()
7337
7116
  };
7117
+ attachDetectAntiBot(ctx);
7338
7118
  if (_tabIndex !== void 0 && session?.context) {
7339
7119
  const pages = session.context.pages();
7340
7120
  if (_tabIndex >= 0 && _tabIndex < pages.length) {
@@ -7864,80 +7644,6 @@ var sessionKillBuiltin = {
7864
7644
  }
7865
7645
  };
7866
7646
 
7867
- // src/config.ts
7868
- import { homedir as homedir7, tmpdir } from "os";
7869
- import { join as join7 } from "path";
7870
- import { loadConfig as coreLoadConfig, saveConfig as coreSaveConfig } from "@dyyz1993/xcli-core";
7871
- function getConfigSource() {
7872
- return { configDir: join7(homedir7() || tmpdir(), ".xbrowser") };
7873
- }
7874
- function loadConfig() {
7875
- return coreLoadConfig(getConfigSource());
7876
- }
7877
- function saveConfig(config) {
7878
- coreSaveConfig(getConfigSource(), config);
7879
- }
7880
- function getConfigValue(key) {
7881
- const parts = key.split(".");
7882
- let obj = loadConfig();
7883
- for (const part of parts) {
7884
- if (obj && typeof obj === "object") {
7885
- obj = obj[part];
7886
- } else {
7887
- return void 0;
7888
- }
7889
- }
7890
- return obj;
7891
- }
7892
- function setConfigValue(key, value) {
7893
- const config = loadConfig();
7894
- const parts = key.split(".");
7895
- let obj = config;
7896
- for (let i = 0; i < parts.length - 1; i++) {
7897
- if (!obj[parts[i]] || typeof obj[parts[i]] !== "object") {
7898
- obj[parts[i]] = {};
7899
- }
7900
- obj = obj[parts[i]];
7901
- }
7902
- obj[parts[parts.length - 1]] = value;
7903
- saveConfig(config);
7904
- }
7905
- var DEFAULT_MARKETPLACE_URL = "https://marketplace.xbrowser.dev";
7906
- var NPM_REGISTRY_URL = "https://registry.npmjs.org";
7907
- var NPM_SCOPE = "@xbrowser/";
7908
- function getMarketplaceUrl() {
7909
- return process.env.XBROWSER_MARKETPLACE_URL || getConfigValue("marketplaceUrl") || DEFAULT_MARKETPLACE_URL;
7910
- }
7911
- function resolveNpmPackageName(name) {
7912
- if (name.startsWith("@")) return name;
7913
- return `${NPM_SCOPE}${name}`;
7914
- }
7915
- var NPM_NAME_ALIASES = {
7916
- "1688": "alibaba-1688"
7917
- };
7918
- function generateNpmCandidates(name) {
7919
- if (name.startsWith("@")) return [name];
7920
- const resolved = NPM_NAME_ALIASES[name] ?? name;
7921
- return [
7922
- `${NPM_SCOPE}xbrowser-plugin-${resolved}`,
7923
- `${NPM_SCOPE}${resolved}`,
7924
- `xbrowser-plugin-${resolved}`
7925
- ];
7926
- }
7927
- async function resolveNpmPackageWithFallback(name) {
7928
- const candidates = generateNpmCandidates(name);
7929
- for (const candidate of candidates) {
7930
- try {
7931
- const encoded = encodeURIComponent(candidate);
7932
- const res = await fetch(`${NPM_REGISTRY_URL}/${encoded}`);
7933
- if (res.ok) return candidate;
7934
- } catch {
7935
- continue;
7936
- }
7937
- }
7938
- return resolveNpmPackageName(name);
7939
- }
7940
-
7941
7647
  // src/builtins/config.ts
7942
7648
  var configBuiltin = {
7943
7649
  name: "config",
@@ -8044,7 +7750,7 @@ import {
8044
7750
  writeFileSync as writeFileSync10
8045
7751
  } from "fs";
8046
7752
  import { resolve as resolve8, basename as basename2, dirname as dirname4 } from "path";
8047
- import { homedir as homedir8 } from "os";
7753
+ import { homedir as homedir7 } from "os";
8048
7754
 
8049
7755
  // src/plugin/install-sources/local.ts
8050
7756
  import { existsSync as existsSync5, cpSync, rmSync } from "fs";
@@ -8086,8 +7792,8 @@ async function installFromLocal(source, name, targetDir) {
8086
7792
 
8087
7793
  // src/plugin/install-sources/npm.ts
8088
7794
  import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync6, rmSync as rmSync2, cpSync as cpSync2 } from "fs";
8089
- import { resolve as resolve4, join as join8 } from "path";
8090
- import { tmpdir as tmpdir2 } from "os";
7795
+ import { resolve as resolve4, join as join7 } from "path";
7796
+ import { tmpdir } from "os";
8091
7797
  import {
8092
7798
  downloadToFile,
8093
7799
  extractTarGz,
@@ -8159,13 +7865,13 @@ async function installFromNpm(packageName, name, targetDir) {
8159
7865
  throw new Error(`No tarball URL for ${packageName}@${latestVersion}`);
8160
7866
  }
8161
7867
  const tarballUrl = versionMeta.dist.tarball;
8162
- const tmpDir = join8(tmpdir2(), `xbrowser-npm-${Date.now()}`);
7868
+ const tmpDir = join7(tmpdir(), `xbrowser-npm-${Date.now()}`);
8163
7869
  mkdirSync5(tmpDir, { recursive: true });
8164
7870
  let warnings = [];
8165
7871
  try {
8166
- const tarballPath = join8(tmpDir, `${name}.tgz`);
7872
+ const tarballPath = join7(tmpDir, `${name}.tgz`);
8167
7873
  await downloadToFile(tarballUrl, tarballPath);
8168
- const extractDir = join8(tmpDir, "extracted");
7874
+ const extractDir = join7(tmpDir, "extracted");
8169
7875
  extractTarGz(tarballPath, extractDir);
8170
7876
  flattenPackageRoot(extractDir);
8171
7877
  const verify = verifyPlugin2(extractDir, { metadataField: "xbrowser" });
@@ -8200,12 +7906,12 @@ async function installFromNpm(packageName, name, targetDir) {
8200
7906
 
8201
7907
  // src/plugin/install-sources/git.ts
8202
7908
  import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync7, rmSync as rmSync3, cpSync as cpSync3 } from "fs";
8203
- import { resolve as resolve5, join as join9 } from "path";
8204
- import { tmpdir as tmpdir3 } from "os";
7909
+ import { resolve as resolve5, join as join8 } from "path";
7910
+ import { tmpdir as tmpdir2 } from "os";
8205
7911
  import { execSync as execSync2 } from "child_process";
8206
7912
  import { verifyPlugin as verifyPlugin3, safeCleanup as safeCleanup3 } from "@dyyz1993/xcli-core";
8207
7913
  async function installFromGit(gitUrl, name, targetDir) {
8208
- const tmpDir = join9(tmpdir3(), `xbrowser-git-${Date.now()}`);
7914
+ const tmpDir = join8(tmpdir2(), `xbrowser-git-${Date.now()}`);
8209
7915
  let warnings = [];
8210
7916
  try {
8211
7917
  execSync2(`git clone --depth 1 "${gitUrl}" "${tmpDir}"`, { stdio: "pipe" });
@@ -8242,8 +7948,8 @@ async function installFromGit(gitUrl, name, targetDir) {
8242
7948
 
8243
7949
  // src/plugin/install-sources/url.ts
8244
7950
  import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync8, rmSync as rmSync4, cpSync as cpSync4 } from "fs";
8245
- import { resolve as resolve6, join as join10, basename } from "path";
8246
- import { tmpdir as tmpdir4 } from "os";
7951
+ import { resolve as resolve6, join as join9, basename } from "path";
7952
+ import { tmpdir as tmpdir3 } from "os";
8247
7953
  import {
8248
7954
  downloadToFile as downloadToFile2,
8249
7955
  extractTarGz as extractTarGz2,
@@ -8252,14 +7958,14 @@ import {
8252
7958
  safeCleanup as safeCleanup4
8253
7959
  } from "@dyyz1993/xcli-core";
8254
7960
  async function installFromUrl(url, name, targetDir) {
8255
- const tmpDir = join10(tmpdir4(), `xbrowser-url-${Date.now()}`);
7961
+ const tmpDir = join9(tmpdir3(), `xbrowser-url-${Date.now()}`);
8256
7962
  mkdirSync6(tmpDir, { recursive: true });
8257
7963
  let warnings = [];
8258
7964
  try {
8259
7965
  const fileName = basename(new URL(url).pathname) || "plugin.tar.gz";
8260
- const tarballPath = join10(tmpDir, fileName);
7966
+ const tarballPath = join9(tmpDir, fileName);
8261
7967
  await downloadToFile2(url, tarballPath);
8262
- const extractDir = join10(tmpDir, "extracted");
7968
+ const extractDir = join9(tmpDir, "extracted");
8263
7969
  extractTarGz2(tarballPath, extractDir);
8264
7970
  flattenPackageRoot2(extractDir);
8265
7971
  const verify = verifyPlugin4(extractDir, { metadataField: "xbrowser" });
@@ -8301,8 +8007,8 @@ import {
8301
8007
  rmSync as rmSync5,
8302
8008
  cpSync as cpSync5
8303
8009
  } from "fs";
8304
- import { resolve as resolve7, join as join11, dirname as dirname3 } from "path";
8305
- import { tmpdir as tmpdir5 } from "os";
8010
+ import { resolve as resolve7, join as join10, dirname as dirname3 } from "path";
8011
+ import { tmpdir as tmpdir4 } from "os";
8306
8012
  import { gunzipSync } from "zlib";
8307
8013
  import {
8308
8014
  downloadToFile as downloadToFile3,
@@ -8330,7 +8036,7 @@ async function installFromMarketplace(pluginsDir, slug, options) {
8330
8036
  throw new Error(`Plugin "${name}" already exists. Use --force to overwrite.`);
8331
8037
  }
8332
8038
  mkdirSync7(targetDir, { recursive: true });
8333
- const tmpDir = join11(tmpdir5(), `xbrowser-marketplace-${Date.now()}`);
8039
+ const tmpDir = join10(tmpdir4(), `xbrowser-marketplace-${Date.now()}`);
8334
8040
  mkdirSync7(tmpDir, { recursive: true });
8335
8041
  const realSlug = String(plugin.slug || slug);
8336
8042
  try {
@@ -8393,7 +8099,7 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
8393
8099
  }
8394
8100
  if (tarballRes.status === 302 || tarballRes.headers.get("location")) {
8395
8101
  const redirectUrl = tarballRes.headers.get("location");
8396
- const tarballPath = join11(tmpDir, `${slug}.tar.gz`);
8102
+ const tarballPath = join10(tmpDir, `${slug}.tar.gz`);
8397
8103
  await downloadToFile3(redirectUrl, tarballPath);
8398
8104
  const buffer = readFileSync7(tarballPath);
8399
8105
  const manifest = tryParseAsGzippedManifest(buffer);
@@ -8401,7 +8107,7 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
8401
8107
  extractManifestToDir(manifest, targetDir);
8402
8108
  return;
8403
8109
  }
8404
- const extractDir = join11(tmpDir, "extracted");
8110
+ const extractDir = join10(tmpDir, "extracted");
8405
8111
  extractTarGz3(tarballPath, extractDir);
8406
8112
  flattenPackageRoot3(extractDir);
8407
8113
  if (existsSync9(targetDir)) {
@@ -8415,10 +8121,10 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
8415
8121
  extractManifestToDir(manifest, targetDir);
8416
8122
  return;
8417
8123
  }
8418
- const tarballPath = join11(tmpDir, `${slug}.tar.gz`);
8124
+ const tarballPath = join10(tmpDir, `${slug}.tar.gz`);
8419
8125
  writeFileSync9(tarballPath, buffer);
8420
8126
  try {
8421
- const extractDir = join11(tmpDir, "extracted");
8127
+ const extractDir = join10(tmpDir, "extracted");
8422
8128
  extractTarGz3(tarballPath, extractDir);
8423
8129
  flattenPackageRoot3(extractDir);
8424
8130
  if (existsSync9(targetDir)) {
@@ -8511,7 +8217,7 @@ function ensureIndexFile(plugin, name, targetDir) {
8511
8217
  var PluginInstaller = class {
8512
8218
  pluginsDir;
8513
8219
  constructor(pluginsDir) {
8514
- this.pluginsDir = pluginsDir || resolve8(homedir8(), ".xbrowser/plugins");
8220
+ this.pluginsDir = pluginsDir || resolve8(homedir7(), ".xbrowser/plugins");
8515
8221
  }
8516
8222
  getPluginsDir() {
8517
8223
  return this.pluginsDir;
@@ -8596,7 +8302,7 @@ var PluginInstaller = class {
8596
8302
  if (toCopy.length === 0) return;
8597
8303
  const repoSharedDirs = [
8598
8304
  resolve8(process.cwd(), ".xcli/plugins/shared"),
8599
- resolve8(homedir8(), ".xbrowser/plugins/shared")
8305
+ resolve8(homedir7(), ".xbrowser/plugins/shared")
8600
8306
  ];
8601
8307
  let sourceSharedDir = null;
8602
8308
  for (const dir of repoSharedDirs) {
@@ -10417,15 +10123,15 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
10417
10123
  }
10418
10124
 
10419
10125
  // src/cli/session-routes.ts
10420
- import { homedir as homedir9 } from "os";
10421
- import { join as join13 } from "path";
10126
+ import { homedir as homedir8 } from "os";
10127
+ import { join as join12 } from "path";
10422
10128
  import { readdirSync as readdirSync3, rmSync as rmSync7 } from "fs";
10423
10129
  function cleanSessionFiles() {
10424
- const dir = join13(homedir9(), ".xbrowser", "sessions");
10130
+ const dir = join12(homedir8(), ".xbrowser", "sessions");
10425
10131
  let count = 0;
10426
10132
  try {
10427
10133
  for (const entry of readdirSync3(dir, { withFileTypes: true })) {
10428
- const p = join13(dir, entry.name);
10134
+ const p = join12(dir, entry.name);
10429
10135
  rmSync7(p, { recursive: true, force: true });
10430
10136
  count++;
10431
10137
  }
@@ -11334,7 +11040,7 @@ async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
11334
11040
  const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-KPU4YQAE.js");
11335
11041
  const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
11336
11042
  const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync12 } = await import("fs");
11337
- const { join: join14 } = await import("path");
11043
+ const { join: join13 } = await import("path");
11338
11044
  const data = SessionRecorder2.readData(sessionName);
11339
11045
  if (!data) {
11340
11046
  outputError(`No recording found for session "${sessionName}". Run \`xbrowser record stop --session ${sessionName}\` first.`);
@@ -11346,14 +11052,14 @@ async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
11346
11052
  } catch {
11347
11053
  }
11348
11054
  const finalPluginName = pluginName || domain.split(".")[0] || "my-site";
11349
- const finalOutputDir = outputDir || join14(process.cwd(), ".xcli", "plugins", finalPluginName);
11055
+ const finalOutputDir = outputDir || join13(process.cwd(), ".xcli", "plugins", finalPluginName);
11350
11056
  const knowledge = readSiteKnowledge2(domain);
11351
11057
  const knowledgeMd = knowledge ? toMarkdown(knowledge) : "";
11352
11058
  const pluginCode = generatePluginCode(finalPluginName, domain, data, knowledgeMd);
11353
- mkdirSync10(join14(finalOutputDir), { recursive: true });
11354
- writeFileSync12(join14(finalOutputDir, "index.ts"), pluginCode, "utf-8");
11059
+ mkdirSync10(join13(finalOutputDir), { recursive: true });
11060
+ writeFileSync12(join13(finalOutputDir, "index.ts"), pluginCode, "utf-8");
11355
11061
  if (knowledgeMd) {
11356
- writeFileSync12(join14(finalOutputDir, "SITE_KNOWLEDGE.md"), knowledgeMd, "utf-8");
11062
+ writeFileSync12(join13(finalOutputDir, "SITE_KNOWLEDGE.md"), knowledgeMd, "utf-8");
11357
11063
  }
11358
11064
  console.log("");
11359
11065
  console.log("=== Plugin Generated ===");
@@ -13334,6 +13040,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
13334
13040
  },
13335
13041
  tips: new TipCollector3()
13336
13042
  };
13043
+ attachDetectAntiBot(ctx);
13337
13044
  try {
13338
13045
  const cmdStart = Date.now();
13339
13046
  const loginGuard = await checkPluginLoginRequired({