@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/anti-bot-MCVM6IFB.js +9 -0
- package/dist/chunk-7ZDWM6T2.js +145 -0
- package/dist/chunk-DPJNCMLC.js +246 -0
- package/dist/chunk-IIM5GOD7.js +93 -0
- package/dist/cli.js +80 -373
- package/dist/daemon-main.js +21 -389
- package/dist/human-interaction-HJTXFVQS.js +312 -0
- package/dist/human-interaction-OU7LZ6OZ.js +434 -0
- package/dist/index.d.ts +32 -1
- package/dist/index.js +55 -285
- package/package.json +1 -1
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/
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
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
|
|
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
|
|
8090
|
-
import { tmpdir
|
|
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 =
|
|
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 =
|
|
7872
|
+
const tarballPath = join7(tmpDir, `${name}.tgz`);
|
|
8167
7873
|
await downloadToFile(tarballUrl, tarballPath);
|
|
8168
|
-
const extractDir =
|
|
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
|
|
8204
|
-
import { tmpdir as
|
|
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 =
|
|
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
|
|
8246
|
-
import { tmpdir as
|
|
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 =
|
|
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 =
|
|
7966
|
+
const tarballPath = join9(tmpDir, fileName);
|
|
8261
7967
|
await downloadToFile2(url, tarballPath);
|
|
8262
|
-
const extractDir =
|
|
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
|
|
8305
|
-
import { tmpdir as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
8124
|
+
const tarballPath = join10(tmpDir, `${slug}.tar.gz`);
|
|
8419
8125
|
writeFileSync9(tarballPath, buffer);
|
|
8420
8126
|
try {
|
|
8421
|
-
const extractDir =
|
|
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(
|
|
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(
|
|
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
|
|
10421
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 ||
|
|
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(
|
|
11354
|
-
writeFileSync12(
|
|
11059
|
+
mkdirSync10(join13(finalOutputDir), { recursive: true });
|
|
11060
|
+
writeFileSync12(join13(finalOutputDir, "index.ts"), pluginCode, "utf-8");
|
|
11355
11061
|
if (knowledgeMd) {
|
|
11356
|
-
writeFileSync12(
|
|
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({
|