browser-autopilot 0.1.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.
- package/README.md +251 -0
- package/dist/agent/history.d.ts +41 -0
- package/dist/agent/history.js +98 -0
- package/dist/agent/history.js.map +1 -0
- package/dist/agent/loop.d.ts +34 -0
- package/dist/agent/loop.js +278 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/run.d.ts +4 -0
- package/dist/agent/run.js +67 -0
- package/dist/agent/run.js.map +1 -0
- package/dist/agent/state.d.ts +37 -0
- package/dist/agent/state.js +82 -0
- package/dist/agent/state.js.map +1 -0
- package/dist/agent/tools.d.ts +414 -0
- package/dist/agent/tools.js +399 -0
- package/dist/agent/tools.js.map +1 -0
- package/dist/browser/cdp.d.ts +91 -0
- package/dist/browser/cdp.js +470 -0
- package/dist/browser/cdp.js.map +1 -0
- package/dist/browser/dom.d.ts +30 -0
- package/dist/browser/dom.js +79 -0
- package/dist/browser/dom.js.map +1 -0
- package/dist/browser/snapshot.d.ts +19 -0
- package/dist/browser/snapshot.js +70 -0
- package/dist/browser/snapshot.js.map +1 -0
- package/dist/captcha/solver.d.ts +20 -0
- package/dist/captcha/solver.js +101 -0
- package/dist/captcha/solver.js.map +1 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.js +44 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator.d.ts +33 -0
- package/dist/orchestrator.js +197 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/viewer/server.d.ts +14 -0
- package/dist/viewer/server.js +93 -0
- package/dist/viewer/server.js.map +1 -0
- package/dist/x11/agent.d.ts +34 -0
- package/dist/x11/agent.js +103 -0
- package/dist/x11/agent.js.map +1 -0
- package/dist/x11/chrome.d.ts +9 -0
- package/dist/x11/chrome.js +107 -0
- package/dist/x11/chrome.js.map +1 -0
- package/dist/x11/input.d.ts +13 -0
- package/dist/x11/input.js +75 -0
- package/dist/x11/input.js.map +1 -0
- package/dist/x11/login.d.ts +6 -0
- package/dist/x11/login.js +76 -0
- package/dist/x11/login.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM snapshot serialization for LLM consumption.
|
|
3
|
+
*
|
|
4
|
+
* Inspired by agent-browser's snapshot.ts — converts the accessibility tree
|
|
5
|
+
* into indexed text the LLM can reason about and reference elements by [ref=eN].
|
|
6
|
+
*/
|
|
7
|
+
const INTERACTIVE_ROLES = new Set([
|
|
8
|
+
"button", "link", "textbox", "searchbox", "combobox", "listbox",
|
|
9
|
+
"checkbox", "radio", "switch", "tab", "menuitem", "menuitemcheckbox",
|
|
10
|
+
"menuitemradio", "option", "slider", "spinbutton", "progressbar",
|
|
11
|
+
"scrollbar", "treeitem",
|
|
12
|
+
]);
|
|
13
|
+
const CONTENT_ROLES = new Set([
|
|
14
|
+
"heading", "paragraph", "blockquote", "code", "figure",
|
|
15
|
+
"img", "math", "table", "cell", "row", "list", "listitem",
|
|
16
|
+
"article", "main", "navigation", "banner", "contentinfo",
|
|
17
|
+
"complementary", "form", "region", "status", "alert", "dialog",
|
|
18
|
+
"tooltip", "log", "marquee", "timer",
|
|
19
|
+
]);
|
|
20
|
+
export function serializeAXNodes(nodes, opts = {}) {
|
|
21
|
+
const refs = new Map();
|
|
22
|
+
const lines = [];
|
|
23
|
+
let refCounter = 0;
|
|
24
|
+
for (const node of nodes) {
|
|
25
|
+
const role = node.role?.value ?? "";
|
|
26
|
+
const name = node.name?.value ?? "";
|
|
27
|
+
const value = node.value?.value ?? "";
|
|
28
|
+
if (!role || role === "none" || role === "generic" || role === "InlineTextBox")
|
|
29
|
+
continue;
|
|
30
|
+
if (opts.interactive && !INTERACTIVE_ROLES.has(role))
|
|
31
|
+
continue;
|
|
32
|
+
const isInteractive = INTERACTIVE_ROLES.has(role);
|
|
33
|
+
const isContent = CONTENT_ROLES.has(role);
|
|
34
|
+
if (!isInteractive && !isContent)
|
|
35
|
+
continue;
|
|
36
|
+
let ref = "";
|
|
37
|
+
if (isInteractive) {
|
|
38
|
+
refCounter++;
|
|
39
|
+
ref = `e${refCounter}`;
|
|
40
|
+
refs.set(ref, {
|
|
41
|
+
ref,
|
|
42
|
+
role,
|
|
43
|
+
name,
|
|
44
|
+
selector: buildSelector(role, name, node),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const parts = [role];
|
|
48
|
+
if (name)
|
|
49
|
+
parts.push(`"${name}"`);
|
|
50
|
+
if (value)
|
|
51
|
+
parts.push(`value="${value}"`);
|
|
52
|
+
if (ref)
|
|
53
|
+
parts.push(`[ref=${ref}]`);
|
|
54
|
+
lines.push(parts.join(" "));
|
|
55
|
+
}
|
|
56
|
+
return { text: lines.join("\n"), refs };
|
|
57
|
+
}
|
|
58
|
+
function buildSelector(role, name, node) {
|
|
59
|
+
if (role === "textbox" || role === "searchbox") {
|
|
60
|
+
return name ? `input[name="${name}"], input[placeholder="${name}"]` : "input";
|
|
61
|
+
}
|
|
62
|
+
if (role === "button") {
|
|
63
|
+
return name ? `button:has-text("${name}"), [role="button"]:has-text("${name}")` : "button";
|
|
64
|
+
}
|
|
65
|
+
if (role === "link") {
|
|
66
|
+
return name ? `a:has-text("${name}")` : "a";
|
|
67
|
+
}
|
|
68
|
+
return `[role="${role}"]`;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/browser/snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal captcha solver — Capsolver (primary), 2Captcha (fallback).
|
|
3
|
+
* Supports: reCAPTCHA v2/v3, hCaptcha, Cloudflare Turnstile, DataDome.
|
|
4
|
+
*/
|
|
5
|
+
interface SolveResult {
|
|
6
|
+
token?: string;
|
|
7
|
+
cookie?: string;
|
|
8
|
+
provider: string;
|
|
9
|
+
}
|
|
10
|
+
type CaptchaType = "recaptcha_v2" | "recaptcha_v3" | "hcaptcha" | "turnstile" | "datadome";
|
|
11
|
+
export declare function solve(opts: {
|
|
12
|
+
type: CaptchaType;
|
|
13
|
+
siteUrl: string;
|
|
14
|
+
siteKey?: string;
|
|
15
|
+
captchaUrl?: string;
|
|
16
|
+
userAgent?: string;
|
|
17
|
+
proxy?: string;
|
|
18
|
+
action?: string;
|
|
19
|
+
}): Promise<SolveResult>;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal captcha solver — Capsolver (primary), 2Captcha (fallback).
|
|
3
|
+
* Supports: reCAPTCHA v2/v3, hCaptcha, Cloudflare Turnstile, DataDome.
|
|
4
|
+
*/
|
|
5
|
+
import { config } from "../config.js";
|
|
6
|
+
// ── Capsolver ────────────────────────────────────────────────────────────────
|
|
7
|
+
async function capsolverSolve(task) {
|
|
8
|
+
const resp = await fetch("https://api.capsolver.com/createTask", {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers: { "Content-Type": "application/json" },
|
|
11
|
+
body: JSON.stringify({ clientKey: config.captcha.capsolverKey, task }),
|
|
12
|
+
});
|
|
13
|
+
const data = await resp.json();
|
|
14
|
+
if (data.errorId !== 0)
|
|
15
|
+
throw new Error(`capsolver: ${data.errorDescription}`);
|
|
16
|
+
const taskId = data.taskId;
|
|
17
|
+
for (let i = 0; i < 60; i++) {
|
|
18
|
+
await sleep(3000);
|
|
19
|
+
const r = await fetch("https://api.capsolver.com/getTaskResult", {
|
|
20
|
+
method: "POST",
|
|
21
|
+
headers: { "Content-Type": "application/json" },
|
|
22
|
+
body: JSON.stringify({ clientKey: config.captcha.capsolverKey, taskId }),
|
|
23
|
+
});
|
|
24
|
+
const result = await r.json();
|
|
25
|
+
if (result.status === "ready")
|
|
26
|
+
return result.solution;
|
|
27
|
+
}
|
|
28
|
+
throw new Error("capsolver timeout");
|
|
29
|
+
}
|
|
30
|
+
// ── 2Captcha ─────────────────────────────────────────────────────────────────
|
|
31
|
+
async function twoCaptchaSolve(task) {
|
|
32
|
+
const resp = await fetch("https://api.2captcha.com/createTask", {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: { "Content-Type": "application/json" },
|
|
35
|
+
body: JSON.stringify({ clientKey: config.captcha.twocaptchaKey, task }),
|
|
36
|
+
});
|
|
37
|
+
const data = await resp.json();
|
|
38
|
+
if (data.errorId !== 0)
|
|
39
|
+
throw new Error(`2captcha: ${JSON.stringify(data)}`);
|
|
40
|
+
const taskId = data.taskId;
|
|
41
|
+
for (let i = 0; i < 60; i++) {
|
|
42
|
+
await sleep(5000);
|
|
43
|
+
const r = await fetch("https://api.2captcha.com/getTaskResult", {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: { "Content-Type": "application/json" },
|
|
46
|
+
body: JSON.stringify({ clientKey: config.captcha.twocaptchaKey, taskId }),
|
|
47
|
+
});
|
|
48
|
+
const result = await r.json();
|
|
49
|
+
if (result.status === "ready")
|
|
50
|
+
return result.solution;
|
|
51
|
+
}
|
|
52
|
+
throw new Error("2captcha timeout");
|
|
53
|
+
}
|
|
54
|
+
const TASK_MAP = {
|
|
55
|
+
capsolver: {
|
|
56
|
+
recaptcha_v2: (o) => ({ type: "ReCaptchaV2TaskProxyLess", websiteURL: o.siteUrl, websiteKey: o.siteKey }),
|
|
57
|
+
recaptcha_v3: (o) => ({ type: "ReCaptchaV3TaskProxyLess", websiteURL: o.siteUrl, websiteKey: o.siteKey, pageAction: o.action ?? "verify" }),
|
|
58
|
+
hcaptcha: (o) => ({ type: "HCaptchaTaskProxyLess", websiteURL: o.siteUrl, websiteKey: o.siteKey }),
|
|
59
|
+
turnstile: (o) => ({ type: "AntiTurnstileTaskProxyLess", websiteURL: o.siteUrl, websiteKey: o.siteKey }),
|
|
60
|
+
datadome: (o) => ({ type: "DatadomeSliderTask", websiteURL: o.siteUrl, captchaUrl: o.captchaUrl, userAgent: o.userAgent, proxy: o.proxy }),
|
|
61
|
+
},
|
|
62
|
+
twocaptcha: {
|
|
63
|
+
recaptcha_v2: (o) => ({ type: "RecaptchaV2TaskProxyless", websiteURL: o.siteUrl, websiteKey: o.siteKey }),
|
|
64
|
+
recaptcha_v3: (o) => ({ type: "RecaptchaV3TaskProxyless", websiteURL: o.siteUrl, websiteKey: o.siteKey, pageAction: o.action ?? "verify" }),
|
|
65
|
+
hcaptcha: (o) => ({ type: "HCaptchaTaskProxyless", websiteURL: o.siteUrl, websiteKey: o.siteKey }),
|
|
66
|
+
turnstile: (o) => ({ type: "TurnstileTaskProxyless", websiteURL: o.siteUrl, websiteKey: o.siteKey }),
|
|
67
|
+
datadome: (o) => ({ type: "DataDomeSliderTask", websiteURL: o.siteUrl, captchaUrl: o.captchaUrl, userAgent: o.userAgent, proxyType: "http", proxyAddress: o.proxy }),
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
const SOLVERS = {
|
|
71
|
+
capsolver: capsolverSolve,
|
|
72
|
+
twocaptcha: twoCaptchaSolve,
|
|
73
|
+
};
|
|
74
|
+
export async function solve(opts) {
|
|
75
|
+
const providers = [
|
|
76
|
+
...(config.captcha.capsolverKey ? ["capsolver"] : []),
|
|
77
|
+
...(config.captcha.twocaptchaKey ? ["twocaptcha"] : []),
|
|
78
|
+
];
|
|
79
|
+
for (const provider of providers) {
|
|
80
|
+
const taskBuilder = TASK_MAP[provider]?.[opts.type];
|
|
81
|
+
if (!taskBuilder)
|
|
82
|
+
continue;
|
|
83
|
+
try {
|
|
84
|
+
const task = taskBuilder(opts);
|
|
85
|
+
const solution = await SOLVERS[provider](task);
|
|
86
|
+
return {
|
|
87
|
+
token: solution.gRecaptchaResponse ?? solution.token,
|
|
88
|
+
cookie: solution.cookie,
|
|
89
|
+
provider,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
console.log(` ${provider} failed: ${e.message}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
throw new Error(`All providers failed for ${opts.type}`);
|
|
97
|
+
}
|
|
98
|
+
function sleep(ms) {
|
|
99
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=solver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solver.js","sourceRoot":"","sources":["../../src/captcha/solver.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared configuration — single source of truth for all env vars.
|
|
3
|
+
*
|
|
4
|
+
* Platform-aware defaults:
|
|
5
|
+
* Docker/Linux: /data/ (container volume mount)
|
|
6
|
+
* macOS/local: ~/.browser-autopilot/
|
|
7
|
+
*/
|
|
8
|
+
export interface Credentials {
|
|
9
|
+
username: string;
|
|
10
|
+
password: string;
|
|
11
|
+
email: string;
|
|
12
|
+
totpKey: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ProxyConfig {
|
|
15
|
+
host: string;
|
|
16
|
+
port: string;
|
|
17
|
+
}
|
|
18
|
+
export interface BrowserConfig {
|
|
19
|
+
profileDir: string;
|
|
20
|
+
cdpPort: number;
|
|
21
|
+
dataDir: string;
|
|
22
|
+
}
|
|
23
|
+
export interface CaptchaConfig {
|
|
24
|
+
capsolverKey: string;
|
|
25
|
+
twocaptchaKey: string;
|
|
26
|
+
proxy: string;
|
|
27
|
+
}
|
|
28
|
+
export declare const config: {
|
|
29
|
+
isDocker: boolean;
|
|
30
|
+
credentials: Credentials;
|
|
31
|
+
proxy: ProxyConfig;
|
|
32
|
+
browser: BrowserConfig;
|
|
33
|
+
captcha: CaptchaConfig;
|
|
34
|
+
readonly cdpUrl: string;
|
|
35
|
+
readonly socks5Url: string;
|
|
36
|
+
};
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared configuration — single source of truth for all env vars.
|
|
3
|
+
*
|
|
4
|
+
* Platform-aware defaults:
|
|
5
|
+
* Docker/Linux: /data/ (container volume mount)
|
|
6
|
+
* macOS/local: ~/.browser-autopilot/
|
|
7
|
+
*/
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
const isDocker = process.env.DOCKER === "1" || process.env.container != null
|
|
11
|
+
|| (await import("fs")).existsSync("/.dockerenv");
|
|
12
|
+
const localBase = join(homedir(), ".browser-autopilot");
|
|
13
|
+
export const config = {
|
|
14
|
+
isDocker,
|
|
15
|
+
credentials: {
|
|
16
|
+
username: process.env.TWITTER_USER ?? "",
|
|
17
|
+
password: process.env.TWITTER_PASS ?? "",
|
|
18
|
+
email: process.env.TWITTER_EMAIL ?? "",
|
|
19
|
+
totpKey: process.env.TWITTER_TOTP_KEY ?? "",
|
|
20
|
+
},
|
|
21
|
+
proxy: {
|
|
22
|
+
host: process.env.PROXY_HOST ?? "127.0.0.1",
|
|
23
|
+
port: process.env.PROXY_PORT ?? "1080",
|
|
24
|
+
},
|
|
25
|
+
browser: {
|
|
26
|
+
profileDir: process.env.PROFILE_DIR
|
|
27
|
+
?? (isDocker ? "/data/browser_sessions" : join(localBase, "sessions")),
|
|
28
|
+
cdpPort: parseInt(process.env.CDP_PORT ?? "9222"),
|
|
29
|
+
dataDir: process.env.DATA_DIR
|
|
30
|
+
?? (isDocker ? "/data" : join(localBase, "data")),
|
|
31
|
+
},
|
|
32
|
+
captcha: {
|
|
33
|
+
capsolverKey: process.env.CAPSOLVER_KEY ?? "",
|
|
34
|
+
twocaptchaKey: process.env.TWOCAPTCHA_KEY ?? "",
|
|
35
|
+
proxy: process.env.CAPTCHA_PROXY ?? "",
|
|
36
|
+
},
|
|
37
|
+
get cdpUrl() {
|
|
38
|
+
return `http://127.0.0.1:${this.browser.cdpPort}`;
|
|
39
|
+
},
|
|
40
|
+
get socks5Url() {
|
|
41
|
+
return `socks5://${this.proxy.host}:${this.proxy.port}`;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI;OACxE,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAEnD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,oBAAoB,CAAC,CAAC;AA0BxD,MAAM,CAAC,MAAM,MAAM,GAAG;IACrB,QAAQ;IAER,WAAW,EAAE;QACZ,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE;QACxC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE;QACxC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE;QACtC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE;KAC5B;IAEhB,KAAK,EAAE;QACN,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,WAAW;QAC3C,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,MAAM;KACvB;IAEhB,OAAO,EAAE;QACR,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;eAC/B,CAAC,QAAQ,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACvE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,MAAM,CAAC;QACjD,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ;eACzB,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;KACjC;IAElB,OAAO,EAAE;QACR,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE;QAC7C,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE;QAC/C,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE;KACrB;IAElB,IAAI,MAAM;QACT,OAAO,oBAAoB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IACnD,CAAC;IAED,IAAI,SAAS;QACZ,OAAO,YAAY,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACzD,CAAC;CACD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encumbrance — Autonomous browser agent.
|
|
3
|
+
*
|
|
4
|
+
* Automatically picks the right mode:
|
|
5
|
+
* - Cached session? → straight to CDP agent
|
|
6
|
+
* - CDP login works? → use it (fast)
|
|
7
|
+
* - Bot detection? → fall back to X11 (stealth)
|
|
8
|
+
*/
|
|
9
|
+
export { X11Agent } from "./x11/agent.js";
|
|
10
|
+
export { CDPBrowser } from "./browser/cdp.js";
|
|
11
|
+
export { DOMIndexer, type IndexedElement } from "./browser/dom.js";
|
|
12
|
+
export { runAgent, type AgentOptions } from "./agent/loop.js";
|
|
13
|
+
export { createBrowserTools } from "./agent/tools.js";
|
|
14
|
+
export { AgentHistory, type StepRecord } from "./agent/history.js";
|
|
15
|
+
export { captureBrowserState, formatStateForLLM } from "./agent/state.js";
|
|
16
|
+
export { solve as solveCaptcha } from "./captcha/solver.js";
|
|
17
|
+
export { login } from "./x11/login.js";
|
|
18
|
+
export { orchestrate, type OrchestratorOptions, type OrchestratorResult } from "./orchestrator.js";
|
|
19
|
+
export { startViewer } from "./viewer/server.js";
|
|
20
|
+
export { config } from "./config.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encumbrance — Autonomous browser agent.
|
|
3
|
+
*
|
|
4
|
+
* Automatically picks the right mode:
|
|
5
|
+
* - Cached session? → straight to CDP agent
|
|
6
|
+
* - CDP login works? → use it (fast)
|
|
7
|
+
* - Bot detection? → fall back to X11 (stealth)
|
|
8
|
+
*/
|
|
9
|
+
// Library exports
|
|
10
|
+
export { X11Agent } from "./x11/agent.js";
|
|
11
|
+
export { CDPBrowser } from "./browser/cdp.js";
|
|
12
|
+
export { DOMIndexer } from "./browser/dom.js";
|
|
13
|
+
export { runAgent } from "./agent/loop.js";
|
|
14
|
+
export { createBrowserTools } from "./agent/tools.js";
|
|
15
|
+
export { AgentHistory } from "./agent/history.js";
|
|
16
|
+
export { captureBrowserState, formatStateForLLM } from "./agent/state.js";
|
|
17
|
+
export { solve as solveCaptcha } from "./captcha/solver.js";
|
|
18
|
+
export { login } from "./x11/login.js";
|
|
19
|
+
export { orchestrate } from "./orchestrator.js";
|
|
20
|
+
export { startViewer } from "./viewer/server.js";
|
|
21
|
+
export { config } from "./config.js";
|
|
22
|
+
// CLI entrypoint
|
|
23
|
+
import { orchestrate } from "./orchestrator.js";
|
|
24
|
+
import { config } from "./config.js";
|
|
25
|
+
async function main() {
|
|
26
|
+
const { result, success, loginMethod } = await orchestrate({
|
|
27
|
+
credentials: config.credentials,
|
|
28
|
+
loginUrl: process.env.LOGIN_URL ?? "https://x.com/login",
|
|
29
|
+
successUrlContains: process.env.SUCCESS_URL ?? "/home",
|
|
30
|
+
task: process.env.AGENT_TASK ?? "Navigate to the home page and describe what you see.",
|
|
31
|
+
maxSteps: parseInt(process.env.MAX_STEPS ?? "80"),
|
|
32
|
+
});
|
|
33
|
+
console.log("\n" + "=".repeat(50));
|
|
34
|
+
console.log(`Login: ${loginMethod}`);
|
|
35
|
+
console.log(`Success: ${success}`);
|
|
36
|
+
if (result)
|
|
37
|
+
console.log(`Result:\n${result}`);
|
|
38
|
+
console.log("=".repeat(50));
|
|
39
|
+
}
|
|
40
|
+
if (process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("index.js")) {
|
|
41
|
+
main().catch((e) => { console.error(e); process.exit(1); });
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,kBAAkB;AAClB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAuB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAqB,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAmB,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,KAAK,IAAI,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,WAAW,EAAqD,MAAM,mBAAmB,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,iBAAiB;AACjB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,KAAK,UAAU,IAAI;IAClB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,WAAW,CAAC;QAC1D,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,qBAAqB;QACxD,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO;QACtD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,sDAAsD;QACtF,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC;KACjD,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,UAAU,WAAW,EAAE,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;IACnC,IAAI,MAAM;QAAE,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,EAAE,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;IACpF,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator — automatically decides between CDP and X11 modes.
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. Launch Chrome with CDP port open (but no client attached)
|
|
6
|
+
* 2. Check if already logged in (cookies from previous run)
|
|
7
|
+
* 3. If logged in → skip to CDP agent
|
|
8
|
+
* 4. If not logged in → try CDP login first (fast, indexed DOM)
|
|
9
|
+
* 5. If CDP login fails (bot detection) → disconnect CDP, fall back to X11
|
|
10
|
+
* 6. After login → connect CDP agent for the actual task
|
|
11
|
+
*
|
|
12
|
+
* The user never needs to specify which mode to use.
|
|
13
|
+
*/
|
|
14
|
+
import { CDPBrowser } from "./browser/cdp.js";
|
|
15
|
+
import { type Credentials } from "./config.js";
|
|
16
|
+
interface OrchestratorOptions {
|
|
17
|
+
credentials: Credentials;
|
|
18
|
+
loginUrl: string;
|
|
19
|
+
successUrlContains: string;
|
|
20
|
+
task: string;
|
|
21
|
+
maxSteps?: number;
|
|
22
|
+
extraTools?: Record<string, any>;
|
|
23
|
+
loginPrompt?: string;
|
|
24
|
+
keepBrowser?: boolean;
|
|
25
|
+
}
|
|
26
|
+
interface OrchestratorResult {
|
|
27
|
+
result: string | null;
|
|
28
|
+
success: boolean;
|
|
29
|
+
loginMethod: "cached" | "cdp" | "x11" | "failed";
|
|
30
|
+
browser?: CDPBrowser;
|
|
31
|
+
}
|
|
32
|
+
export declare function orchestrate(opts: OrchestratorOptions): Promise<OrchestratorResult>;
|
|
33
|
+
export { type OrchestratorOptions, type OrchestratorResult };
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator — automatically decides between CDP and X11 modes.
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. Launch Chrome with CDP port open (but no client attached)
|
|
6
|
+
* 2. Check if already logged in (cookies from previous run)
|
|
7
|
+
* 3. If logged in → skip to CDP agent
|
|
8
|
+
* 4. If not logged in → try CDP login first (fast, indexed DOM)
|
|
9
|
+
* 5. If CDP login fails (bot detection) → disconnect CDP, fall back to X11
|
|
10
|
+
* 6. After login → connect CDP agent for the actual task
|
|
11
|
+
*
|
|
12
|
+
* The user never needs to specify which mode to use.
|
|
13
|
+
*/
|
|
14
|
+
import { CDPBrowser } from "./browser/cdp.js";
|
|
15
|
+
import { X11Agent } from "./x11/agent.js";
|
|
16
|
+
import * as chrome from "./x11/chrome.js";
|
|
17
|
+
import * as x11Input from "./x11/input.js";
|
|
18
|
+
import { runAgent } from "./agent/loop.js";
|
|
19
|
+
import { authenticator } from "otplib";
|
|
20
|
+
const BOT_DETECTION_SIGNALS = [
|
|
21
|
+
"could not log you in",
|
|
22
|
+
"something went wrong",
|
|
23
|
+
"try again later",
|
|
24
|
+
"unusual login activity",
|
|
25
|
+
"suspicious activity",
|
|
26
|
+
"verify you are human",
|
|
27
|
+
"captcha",
|
|
28
|
+
"challenge",
|
|
29
|
+
];
|
|
30
|
+
export async function orchestrate(opts) {
|
|
31
|
+
const { credentials, loginUrl, successUrlContains, task, maxSteps = 80, extraTools = {}, } = opts;
|
|
32
|
+
console.log("╔══════════════════════════════════════╗");
|
|
33
|
+
console.log("║ browser-autopilot orchestrator ║");
|
|
34
|
+
console.log("╚══════════════════════════════════════╝");
|
|
35
|
+
console.log(` user: ${credentials.username}`);
|
|
36
|
+
console.log(` login: ${loginUrl}`);
|
|
37
|
+
console.log(` success: URL contains "${successUrlContains}"`);
|
|
38
|
+
console.log();
|
|
39
|
+
// ── Step 1: Launch Chrome ────────────────────────────────────────────
|
|
40
|
+
const pid = chrome.launch(loginUrl, credentials.username);
|
|
41
|
+
console.log(`Chrome launched (pid=${pid})`);
|
|
42
|
+
// Wait for Chrome + page load
|
|
43
|
+
console.log("Waiting for Chrome...");
|
|
44
|
+
for (let i = 0; i < 30; i++) {
|
|
45
|
+
if (chrome.getPageUrls().length > 0)
|
|
46
|
+
break;
|
|
47
|
+
x11Input.sleep(1000);
|
|
48
|
+
}
|
|
49
|
+
x11Input.sleep(5000);
|
|
50
|
+
// ── Step 2: Check if already logged in ──────────────────────────────
|
|
51
|
+
if (chrome.pageUrlContains(successUrlContains)) {
|
|
52
|
+
console.log("✓ Already logged in (cached session)\n");
|
|
53
|
+
return await runCDPAgent(task, maxSteps, extraTools, "cached", opts.keepBrowser);
|
|
54
|
+
}
|
|
55
|
+
// ── Step 3: Try CDP login first ─────────────────────────────────────
|
|
56
|
+
console.log("Attempting CDP login...");
|
|
57
|
+
const cdpResult = await tryCDPLogin(credentials, loginUrl, successUrlContains);
|
|
58
|
+
if (cdpResult === "success") {
|
|
59
|
+
console.log("✓ CDP login succeeded\n");
|
|
60
|
+
return await runCDPAgent(task, maxSteps, extraTools, "cdp", opts.keepBrowser);
|
|
61
|
+
}
|
|
62
|
+
if (cdpResult === "bot_detected") {
|
|
63
|
+
console.log("⚠ Bot detection triggered — falling back to X11\n");
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
console.log("⚠ CDP login failed — falling back to X11\n");
|
|
67
|
+
}
|
|
68
|
+
// ── Step 4: Fall back to X11 login ──────────────────────────────────
|
|
69
|
+
// Kill Chrome and relaunch fresh (CDP tainted the session)
|
|
70
|
+
try {
|
|
71
|
+
process.kill(pid);
|
|
72
|
+
x11Input.sleep(2000);
|
|
73
|
+
}
|
|
74
|
+
catch { }
|
|
75
|
+
const freshPid = chrome.launch(loginUrl, credentials.username);
|
|
76
|
+
console.log(`Fresh Chrome launched (pid=${freshPid})`);
|
|
77
|
+
for (let i = 0; i < 30; i++) {
|
|
78
|
+
if (chrome.getPageUrls().length > 0)
|
|
79
|
+
break;
|
|
80
|
+
x11Input.sleep(1000);
|
|
81
|
+
}
|
|
82
|
+
x11Input.sleep(5000);
|
|
83
|
+
x11Input.focusWindow("Log in", "X", "x.com", "Twitter", "Google Chrome", "Sign in");
|
|
84
|
+
x11Input.sleep(2000);
|
|
85
|
+
const x11Success = await runX11Login(credentials, successUrlContains, opts.loginPrompt);
|
|
86
|
+
if (!x11Success) {
|
|
87
|
+
console.log("✗ X11 login also failed\n");
|
|
88
|
+
return { result: null, success: false, loginMethod: "failed" };
|
|
89
|
+
}
|
|
90
|
+
console.log("✓ X11 login succeeded\n");
|
|
91
|
+
return await runCDPAgent(task, maxSteps, extraTools, "x11", opts.keepBrowser);
|
|
92
|
+
}
|
|
93
|
+
// ── CDP login attempt ────────────────────────────────────────────────────────
|
|
94
|
+
async function tryCDPLogin(creds, loginUrl, successUrl) {
|
|
95
|
+
const browser = new CDPBrowser();
|
|
96
|
+
try {
|
|
97
|
+
await browser.connect();
|
|
98
|
+
// Navigate to login
|
|
99
|
+
await browser.navigate(loginUrl);
|
|
100
|
+
await browser.waitMs(3000);
|
|
101
|
+
// Check page text for bot detection signals
|
|
102
|
+
const text = await browser.getPageText();
|
|
103
|
+
const lowerText = text.toLowerCase();
|
|
104
|
+
if (BOT_DETECTION_SIGNALS.some((sig) => lowerText.includes(sig))) {
|
|
105
|
+
await browser.disconnect();
|
|
106
|
+
return "bot_detected";
|
|
107
|
+
}
|
|
108
|
+
// Try quick login via CDP
|
|
109
|
+
const loginTask = `
|
|
110
|
+
Login to this page with:
|
|
111
|
+
- Username: ${creds.username}
|
|
112
|
+
- Email: ${creds.email}
|
|
113
|
+
- Password: ${creds.password}
|
|
114
|
+
- For 2FA, call get_totp_code
|
|
115
|
+
|
|
116
|
+
After login, call done with "login complete".
|
|
117
|
+
If you see "could not log you in", "something went wrong", or any bot detection message, call done with "bot_detected".
|
|
118
|
+
`;
|
|
119
|
+
const { result } = await runAgent({
|
|
120
|
+
task: loginTask,
|
|
121
|
+
browser,
|
|
122
|
+
maxSteps: 15,
|
|
123
|
+
maxFailures: 3,
|
|
124
|
+
});
|
|
125
|
+
await browser.disconnect();
|
|
126
|
+
if (result?.includes("bot_detected"))
|
|
127
|
+
return "bot_detected";
|
|
128
|
+
if (chrome.pageUrlContains(successUrl))
|
|
129
|
+
return "success";
|
|
130
|
+
return "failed";
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
try {
|
|
134
|
+
await browser.disconnect();
|
|
135
|
+
}
|
|
136
|
+
catch { }
|
|
137
|
+
return "failed";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// ── X11 login ────────────────────────────────────────────────────────────────
|
|
141
|
+
async function runX11Login(creds, successUrl, customPrompt) {
|
|
142
|
+
const prompt = customPrompt ?? buildDefaultLoginPrompt(creds);
|
|
143
|
+
const agent = new X11Agent();
|
|
144
|
+
return agent.run({
|
|
145
|
+
systemPrompt: prompt,
|
|
146
|
+
successCheck: () => chrome.pageUrlContains(successUrl),
|
|
147
|
+
onAction: (type, value) => {
|
|
148
|
+
if (type === "inject" && value === "TOTP") {
|
|
149
|
+
const code = authenticator.generate(creds.totpKey);
|
|
150
|
+
console.log(` totp: ${code}`);
|
|
151
|
+
x11Input.typeText(code, 100);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function buildDefaultLoginPrompt(creds) {
|
|
157
|
+
return `You are controlling a Chrome browser via X11 keyboard input to log in.
|
|
158
|
+
You see screenshots of the browser. Based on what you see, tell me what action to take.
|
|
159
|
+
|
|
160
|
+
Credentials:
|
|
161
|
+
- Username: ${creds.username}
|
|
162
|
+
- Email: ${creds.email}
|
|
163
|
+
- Password: ${creds.password}
|
|
164
|
+
- For 2FA/TOTP: say ACTION: INJECT TOTP
|
|
165
|
+
|
|
166
|
+
RULES:
|
|
167
|
+
- Use ONLY keyboard. No clicking.
|
|
168
|
+
- If you see a login form, TYPE the username immediately, then KEY Return.
|
|
169
|
+
- If asked for email/phone verification, TYPE the email, then KEY Return.
|
|
170
|
+
- If you see a password field, TYPE the password, then KEY Return.
|
|
171
|
+
- For 2FA, use INJECT TOTP then KEY Return.
|
|
172
|
+
- NEVER wait more than 3 seconds. NEVER wait more than 2 times in a row.
|
|
173
|
+
|
|
174
|
+
Actions (ONE per message):
|
|
175
|
+
ACTION: TYPE text
|
|
176
|
+
ACTION: KEY keyname (Return, Tab, Escape)
|
|
177
|
+
ACTION: WAIT seconds (max 3)
|
|
178
|
+
ACTION: INJECT TOTP
|
|
179
|
+
ACTION: DONE (when logged in)
|
|
180
|
+
ACTION: FAILED reason`;
|
|
181
|
+
}
|
|
182
|
+
// ── CDP agent (post-login) ───────────────────────────────────────────────────
|
|
183
|
+
async function runCDPAgent(task, maxSteps, extraTools, loginMethod, keepBrowser = false) {
|
|
184
|
+
const browser = new CDPBrowser();
|
|
185
|
+
await browser.connect();
|
|
186
|
+
console.log("CDP connected\n");
|
|
187
|
+
const { result, success } = await runAgent({
|
|
188
|
+
task,
|
|
189
|
+
browser,
|
|
190
|
+
maxSteps,
|
|
191
|
+
extraTools,
|
|
192
|
+
});
|
|
193
|
+
if (!keepBrowser)
|
|
194
|
+
await browser.disconnect();
|
|
195
|
+
return { result, success, loginMethod, browser: keepBrowser ? browser : undefined };
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live browser viewer — streams the Xvfb display over WebSocket.
|
|
3
|
+
*
|
|
4
|
+
* Uses x11vnc + websockify to expose the virtual display as a
|
|
5
|
+
* noVNC-compatible stream. Open the URL in any browser to watch
|
|
6
|
+
* the agent work in real-time.
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* Xvfb (:99) → x11vnc (port 5900) → websockify (port 6080) → browser
|
|
10
|
+
*/
|
|
11
|
+
export declare function startViewer(): {
|
|
12
|
+
url: string;
|
|
13
|
+
stop: () => void;
|
|
14
|
+
};
|