clearcote 0.6.0 → 0.8.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 CHANGED
@@ -81,6 +81,61 @@ const context = await launchPersistentContext("./profile-7423", {
81
81
  });
82
82
  ```
83
83
 
84
+ ### AI agent (OpenRouter)
85
+
86
+ Drive a page with an **in-browser AI agent** — it perceives the live page, asks an LLM what to do,
87
+ and executes the steps as real, trusted input through Chrome's Actor framework. Defaults to
88
+ [OpenRouter](https://openrouter.ai); switch models with a single slug.
89
+
90
+ ```ts
91
+ import { launchAgent, runAgentTask } from "clearcote";
92
+
93
+ const ctx = await launchAgent({
94
+ agentLlmKey: process.env.OPENROUTER_API_KEY, // turns the agent on
95
+ agentModel: "openai/gpt-4o-mini", // any provider/model slug
96
+ });
97
+ const page = ctx.pages()[0] ?? (await ctx.newPage());
98
+ await page.goto("https://example.com");
99
+
100
+ const result = await runAgentTask(page, "Click the 'More information...' link.", { maxSteps: 8 });
101
+ console.log(result.success, result.finalText, result.steps);
102
+ await ctx.close();
103
+ ```
104
+
105
+ - `agentLlmKey` is all you need — the engine auto-enables Chrome's Actor framework (no extra flags).
106
+ - `agentLlmUrl` points at any OpenAI-compatible endpoint (default OpenRouter); `agentToolMode` is `"tools"` (function-calling) or `"json"`.
107
+ - Override the model per task: `runAgentTask(page, goal, { model: "anthropic/claude-3.5-sonnet" })`.
108
+ - The agent needs a **regular profile** — use `launchAgent` / `launchPersistentContext`, not the incognito `launch()`.
109
+
110
+ ### Capture or import a profile
111
+
112
+ Make Clearcote present a **real machine's** identity instead of the synthetic seed-derived one. Pass
113
+ a captured fingerprint as `fingerprintProfile` — a file path, a plain object, or a JSON string (the
114
+ SDK gzip+base64-encodes it for the engine):
115
+
116
+ ```ts
117
+ const browser = await launch({
118
+ fingerprint: "seed-1", // still the farbling root / fallback for absent fields
119
+ fingerprintProfile: "profile.json", // a real machine's captured identity
120
+ });
121
+ ```
122
+
123
+ Get a profile two ways:
124
+
125
+ - **Capture** from a donor Chrome — open
126
+ [`tools/fingerprint-collect/collect.html`](../../tools/fingerprint-collect/README.md) and click
127
+ Capture, or paste `collect.js` + `snippet.js` in DevTools. Either downloads the JSON.
128
+ - **Convert** the open-source [chrome-fingerprints](https://github.com/Vinyzu/chrome-fingerprints)
129
+ dataset: `pip install chrome-fingerprints && python tools/fingerprint-collect/convert_dataset.py
130
+ --out ./profiles --count 100`.
131
+
132
+ **Override / fallback semantics:** fields present in the profile **override** the `fingerprint`
133
+ seed-derived persona; **absent** fields **fall back** to the seed, so partial profiles stay
134
+ coherent. The SDK also derives `acceptLanguage` from the profile's `navigator.languages` when you
135
+ don't set `acceptLanguage` explicitly. See the
136
+ [collector README](../../tools/fingerprint-collect/README.md) for the full schema and what each
137
+ field drives.
138
+
84
139
  ## Fingerprint options
85
140
 
86
141
  All optional. Anything not listed here is passed straight through to Playwright
@@ -102,6 +157,7 @@ All optional. Anything not listed here is passed straight through to Playwright
102
157
  | `webrtcIp` | `--webrtc-ip` | WebRTC IP to report. The engine **fabricates** the `srflx` candidate at this IP and sends **no real STUN** from the host, so the real IP never leaks (not merely relabeled). |
103
158
  | `disableGpuFingerprint` | `--disable-gpu-fingerprint` | Turn off GPU/WebGL spoofing. |
104
159
  | `geoip` | _(directive)_ | `true` → resolve the proxy's exit-IP geo and auto-fill timezone/acceptLanguage/location/**webrtcIp**. |
160
+ | `fingerprintProfile` | `--fingerprint-profile` | A real machine's captured fingerprint (file path / object / JSON string; the SDK gzip+base64-encodes it). Fields present override the seed-derived persona; absent fields fall back to `fingerprint`. |
105
161
 
106
162
  ## API
107
163
 
@@ -0,0 +1,68 @@
1
+ import type { Page } from "playwright-core";
2
+ /** OpenAI-compatible chat-completions endpoints. OpenRouter is the default so you can switch between
3
+ * any provider/model with a single `agentModel` slug. */
4
+ export declare const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
5
+ export interface AgentOptions {
6
+ /**
7
+ * Base URL of an OpenAI-compatible chat-completions API. Defaults to OpenRouter
8
+ * (`https://openrouter.ai/api/v1`) when `agentLlmKey` is set. Point it at any OpenAI-compatible
9
+ * gateway (a local model server, Azure OpenAI, etc.) to use a different backend.
10
+ */
11
+ agentLlmUrl?: string;
12
+ /**
13
+ * API key (sent as a Bearer token) for the LLM endpoint — e.g. an OpenRouter key. **Setting this
14
+ * turns the in-browser AI agent on** (and makes the engine auto-enable Chrome's Actor framework).
15
+ */
16
+ agentLlmKey?: string;
17
+ /**
18
+ * Model slug, e.g. `"openai/gpt-4o-mini"`, `"anthropic/claude-3.5-sonnet"`, `"google/gemini-2.0-flash-001"`
19
+ * — any model your provider exposes (OpenRouter routes by `provider/model`). Switching models =
20
+ * switching this one value. Override per task via `runAgentTask(page, goal, { model })`.
21
+ */
22
+ agentModel?: string;
23
+ /**
24
+ * How the agent gets actions from the model: `"tools"` (OpenAI function-calling) or `"json"`
25
+ * (a plain JSON reply). Defaults to the engine default; use `"json"` for models without reliable
26
+ * tool-calling.
27
+ */
28
+ agentToolMode?: "tools" | "json" | (string & {});
29
+ }
30
+ export declare const AGENT_KEYS: (keyof AgentOptions)[];
31
+ /** Split an options object into its agent half and the remaining (Playwright/other) half. */
32
+ export declare function splitAgentOptions<T extends AgentOptions>(options: T): {
33
+ agent: AgentOptions;
34
+ rest: Omit<T, keyof AgentOptions>;
35
+ };
36
+ /** Build the Chromium switches for the AI agent. Returns `[]` (agent off) unless a key or URL is set. */
37
+ export declare function agentArgs(o: AgentOptions): string[];
38
+ export interface AgentTaskOptions {
39
+ /** Hard cap on observe→think→act iterations before the agent stops (default: engine default, ~20). */
40
+ maxSteps?: number;
41
+ /** Override the launch-time `agentModel` for just this task (any OpenRouter slug). */
42
+ model?: string;
43
+ /** Optional JSON plan/hint string passed verbatim to the agent's planner. */
44
+ planJson?: string;
45
+ }
46
+ /** One recorded step of the agent loop (shape mirrors the engine's step journal). */
47
+ export interface AgentStep {
48
+ action?: string;
49
+ status?: string;
50
+ [k: string]: unknown;
51
+ }
52
+ export interface AgentTaskResult {
53
+ /** Whether the agent reported the goal as completed (vs. hitting the step limit or erroring). */
54
+ success: boolean;
55
+ /** The agent's final message (completion summary, or an error description). */
56
+ finalText: string;
57
+ /** Parsed per-step journal (clicks/types/scrolls/navigations and their outcomes). */
58
+ steps: AgentStep[];
59
+ /** The raw `stepsJson` string as returned by the engine (in case `steps` failed to parse). */
60
+ stepsJson: string;
61
+ }
62
+ /**
63
+ * Run an autonomous AI-agent task against `page`: the engine perceives the page, asks the LLM
64
+ * (OpenRouter by default) what to do, and executes the actions until the goal is met or `maxSteps`
65
+ * is reached. The browser must have been launched with `agentLlmKey` (and optionally `agentModel`).
66
+ */
67
+ export declare function runAgentTask(page: Page, goal: string, opts?: AgentTaskOptions): Promise<AgentTaskResult>;
68
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C;yDACyD;AACzD,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAElE,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;CAClD;AAED,eAAO,MAAM,UAAU,EAAE,CAAC,MAAM,YAAY,CAAC,EAK5C,CAAC;AAEF,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,YAAY,EACtD,OAAO,EAAE,CAAC,GACT;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,YAAY,CAAC,CAAA;CAAE,CAW5D;AAED,yGAAyG;AACzG,wBAAgB,SAAS,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,EAAE,CAQnD;AAED,MAAM,WAAW,gBAAgB;IAC/B,sGAAsG;IACtG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qFAAqF;AACrF,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,iGAAiG;IACjG,OAAO,EAAE,OAAO,CAAC;IACjB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,8FAA8F;IAC9F,SAAS,EAAE,MAAM,CAAC;CACnB;AAQD;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,gBAAqB,GAC1B,OAAO,CAAC,eAAe,CAAC,CA8B1B"}
package/dist/agent.js ADDED
@@ -0,0 +1,105 @@
1
+ // In-browser AI agent (OpenRouter / any OpenAI-compatible endpoint).
2
+ //
3
+ // import { launchAgent, runAgentTask } from "clearcote";
4
+ // const ctx = await launchAgent({
5
+ // agentLlmKey: process.env.OPENROUTER_API_KEY, // turns the agent on
6
+ // agentModel: "openai/gpt-4o-mini", // any OpenRouter model slug
7
+ // });
8
+ // const page = ctx.pages()[0] ?? (await ctx.newPage());
9
+ // await page.goto("https://example.com");
10
+ // const result = await runAgentTask(page, "Click the 'More information...' link.", { maxSteps: 8 });
11
+ // console.log(result.success, result.finalText, result.steps);
12
+ //
13
+ // The agent runs *inside* the browser process: it perceives the live page, asks the LLM what to do,
14
+ // and drives real (trusted) input through Chrome's Actor framework. Setting `agentLlmKey` (or
15
+ // `agentLlmUrl`) is all that's needed — the engine auto-enables the Actor framework whenever
16
+ // `--agent-llm-url` is present, so no `--enable-features`/`--disable-actor-safety-checks` flags are
17
+ // required. Requires a Clearcote binary that exposes `Browser.agentRunTask`.
18
+ //
19
+ // IMPORTANT — the agent needs a REGULAR profile. Chrome's Actor framework only attaches to a normal
20
+ // (persistent) profile, not an incognito one, so drive the agent from `launchAgent()` or
21
+ // `launchPersistentContext()`. Plain `launch()` returns an incognito browser where the agent can't
22
+ // attach the tab ("Actor service unavailable" / "could not attach tab to task").
23
+ /** OpenAI-compatible chat-completions endpoints. OpenRouter is the default so you can switch between
24
+ * any provider/model with a single `agentModel` slug. */
25
+ export const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
26
+ export const AGENT_KEYS = [
27
+ "agentLlmUrl",
28
+ "agentLlmKey",
29
+ "agentModel",
30
+ "agentToolMode",
31
+ ];
32
+ /** Split an options object into its agent half and the remaining (Playwright/other) half. */
33
+ export function splitAgentOptions(options) {
34
+ const agent = {};
35
+ const rest = {};
36
+ for (const [k, v] of Object.entries(options)) {
37
+ if (AGENT_KEYS.includes(k)) {
38
+ agent[k] = v;
39
+ }
40
+ else {
41
+ rest[k] = v;
42
+ }
43
+ }
44
+ return { agent, rest: rest };
45
+ }
46
+ /** Build the Chromium switches for the AI agent. Returns `[]` (agent off) unless a key or URL is set. */
47
+ export function agentArgs(o) {
48
+ const args = [];
49
+ if (o.agentLlmKey == null && o.agentLlmUrl == null)
50
+ return args;
51
+ args.push(`--agent-llm-url=${o.agentLlmUrl ?? OPENROUTER_BASE_URL}`);
52
+ if (o.agentLlmKey != null)
53
+ args.push(`--agent-llm-key=${o.agentLlmKey}`);
54
+ if (o.agentModel != null)
55
+ args.push(`--agent-model=${o.agentModel}`);
56
+ if (o.agentToolMode != null)
57
+ args.push(`--agent-tool-mode=${o.agentToolMode}`);
58
+ return args;
59
+ }
60
+ async function pageTargetId(page) {
61
+ const s = await page.context().newCDPSession(page);
62
+ const info = await s.send("Target.getTargetInfo");
63
+ return info.targetInfo.targetId;
64
+ }
65
+ /**
66
+ * Run an autonomous AI-agent task against `page`: the engine perceives the page, asks the LLM
67
+ * (OpenRouter by default) what to do, and executes the actions until the goal is met or `maxSteps`
68
+ * is reached. The browser must have been launched with `agentLlmKey` (and optionally `agentModel`).
69
+ */
70
+ export async function runAgentTask(page, goal, opts = {}) {
71
+ const browser = page.context().browser();
72
+ if (!browser)
73
+ throw new Error("runAgentTask: page is not attached to a Browser");
74
+ const session = await browser.newBrowserCDPSession();
75
+ const params = { targetId: await pageTargetId(page), goal };
76
+ if (opts.maxSteps != null)
77
+ params.maxSteps = opts.maxSteps;
78
+ if (opts.model != null)
79
+ params.model = opts.model;
80
+ if (opts.planJson != null)
81
+ params.planJson = opts.planJson;
82
+ let res;
83
+ try {
84
+ res = await session.send("Browser.agentRunTask", params);
85
+ }
86
+ catch (e) {
87
+ throw new Error("Browser.agentRunTask failed — make sure this is a Clearcote build with the AI agent and that " +
88
+ "the browser was launched with agentLlmKey/agentLlmUrl set. Underlying error: " +
89
+ e.message);
90
+ }
91
+ let steps = [];
92
+ try {
93
+ steps = JSON.parse(res.stepsJson || "[]");
94
+ }
95
+ catch {
96
+ /* leave steps = [] */
97
+ }
98
+ return {
99
+ success: !!res.success,
100
+ finalText: res.finalText ?? "",
101
+ steps,
102
+ stepsJson: res.stepsJson ?? "[]",
103
+ };
104
+ }
105
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare function main(argv?: string[]): Promise<void>;
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAsbA,wBAAsB,IAAI,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBhF"}
package/dist/cli.js ADDED
@@ -0,0 +1,425 @@
1
+ #!/usr/bin/env node
2
+ // clearcote-agent — a terminal wrapper around Clearcote's in-browser AI agent.
3
+ //
4
+ // Launches a REGULAR-profile Clearcote (anti-detect Chromium), points it at OpenRouter, and runs
5
+ // natural-language goals on a page via the SDK. The agent perceives the page, asks an LLM, and acts
6
+ // via Chrome's Actor framework.
7
+ //
8
+ // clearcote-agent --goal "Click the 'More information...' link" --url https://example.com
9
+ // clearcote-agent -i --url https://example.com # interactive REPL
10
+ //
11
+ // The agent only works in a regular/persistent profile, so this always uses launchAgent() (never the
12
+ // incognito launch()). Logins/cookies persist in --profile so you can sign in once and reuse it.
13
+ import { parseArgs } from "node:util";
14
+ import * as readline from "node:readline";
15
+ import { mkdirSync } from "node:fs";
16
+ import { homedir } from "node:os";
17
+ import { join } from "node:path";
18
+ import { launchAgent, runAgentTask } from "./index.js";
19
+ const USAGE = `clearcote-agent — run natural-language goals on a page via Clearcote's in-browser AI agent.
20
+
21
+ USAGE
22
+ clearcote-agent --goal <text> [--url <url>] [options] one-shot
23
+ clearcote-agent -i|--interactive [--url <url>] [options] interactive REPL
24
+
25
+ OPTIONS
26
+ --goal <text> the task (required in one-shot; optional in REPL)
27
+ --url <url> starting page (default: about:blank)
28
+ -i, --interactive REPL mode (always headed + persistent)
29
+ --model <slug> OpenRouter provider/model slug (default: openai/gpt-4o)
30
+ --key <k> OpenRouter API key (env OPENROUTER_API_KEY or CLEARCOTE_AGENT_KEY)
31
+ --llm-url <url> OpenAI-compatible base URL (default: OpenRouter)
32
+ --tool-mode <m> "tools" | "json"
33
+ --max-steps <n> max agent steps (default: 20)
34
+ --profile <dir> persistent profile dir (default: ~/.clearcote/agent-profile)
35
+ --headless run headless (default: headed; ignored in REPL)
36
+ --executable <path> path to Clearcote chrome.exe (else auto-download / CLEARCOTE_BINARY)
37
+ --fingerprint <seed> anti-detect fingerprint seed
38
+ --proxy <url> proxy, e.g. http://user:pass@host:port
39
+ --timezone <tz> IANA timezone, e.g. America/New_York
40
+ --json one-shot only: print the raw result object as JSON (logs to stderr)
41
+ -h, --help show this help
42
+
43
+ REPL COMMANDS
44
+ :goto <url> navigate the current page
45
+ :url print the current URL
46
+ :model <slug> change the model for subsequent goals
47
+ :steps <n> change max-steps
48
+ :help list commands
49
+ :quit, :exit close and exit (Ctrl-D also quits)
50
+ <anything> run as a goal against the current page`;
51
+ /** Friendly, expected-condition error — no stack trace, custom exit code. */
52
+ class UsageError extends Error {
53
+ code;
54
+ constructor(message, code = 2) {
55
+ super(message);
56
+ this.code = code;
57
+ this.name = "UsageError";
58
+ }
59
+ }
60
+ /** Log to stderr (results go to stdout). */
61
+ function log(msg) {
62
+ process.stderr.write(msg + "\n");
63
+ }
64
+ /** Parse a proxy URL into a Playwright proxy descriptor, splitting credentials out of the userinfo. */
65
+ function parseProxy(raw) {
66
+ let u;
67
+ try {
68
+ u = new URL(raw);
69
+ }
70
+ catch {
71
+ throw new UsageError(`Invalid --proxy URL: ${raw}`);
72
+ }
73
+ const proxy = { server: `${u.protocol}//${u.host}` };
74
+ if (u.username)
75
+ proxy.username = decodeURIComponent(u.username);
76
+ if (u.password)
77
+ proxy.password = decodeURIComponent(u.password);
78
+ return proxy;
79
+ }
80
+ /** Validate a starting URL (about:blank or anything URL-parseable). A bare host like "example.com"
81
+ * is upgraded to https:// so users don't have to type the scheme. Returns the normalized URL. */
82
+ function validateUrl(raw) {
83
+ if (raw === "about:blank")
84
+ return raw;
85
+ try {
86
+ new URL(raw);
87
+ return raw;
88
+ }
89
+ catch {
90
+ try {
91
+ const upgraded = "https://" + raw;
92
+ new URL(upgraded);
93
+ return upgraded;
94
+ }
95
+ catch {
96
+ throw new UsageError(`Invalid --url: ${raw}`);
97
+ }
98
+ }
99
+ }
100
+ /** Parse a positive-integer step count. */
101
+ function parseMaxSteps(raw) {
102
+ const n = Number(raw);
103
+ if (!Number.isInteger(n) || n <= 0) {
104
+ throw new UsageError(`Invalid --max-steps (expected a positive integer): ${raw}`);
105
+ }
106
+ return n;
107
+ }
108
+ /** Render a result to stdout in human form (header already printed by caller). */
109
+ function printResult(result, currentUrl) {
110
+ process.stdout.write((result.success ? "OK" : "FAIL") + "\n");
111
+ if (result.finalText)
112
+ process.stdout.write(result.finalText + "\n");
113
+ if (result.steps.length) {
114
+ process.stdout.write("\nsteps:\n");
115
+ result.steps.forEach((step, i) => {
116
+ const action = step.action ?? "(step)";
117
+ const status = step.status != null ? ` [${step.status}]` : "";
118
+ const fields = [];
119
+ for (const [k, v] of Object.entries(step)) {
120
+ if (k === "action" || k === "status")
121
+ continue;
122
+ if (v == null)
123
+ continue;
124
+ const s = typeof v === "string" ? v : JSON.stringify(v);
125
+ fields.push(`${k}=${s.length > 80 ? s.slice(0, 77) + "..." : s}`);
126
+ }
127
+ const detail = fields.length ? ` ${fields.join(" ")}` : "";
128
+ process.stdout.write(` ${i + 1}. ${action}${detail}${status}\n`);
129
+ });
130
+ }
131
+ process.stdout.write(`\nurl: ${currentUrl}\n`);
132
+ }
133
+ /** Parse + validate process argv into a normalized Cli config. Throws UsageError on bad input. */
134
+ function parseCli(argv) {
135
+ const config = {
136
+ args: argv,
137
+ allowPositionals: false,
138
+ strict: true,
139
+ options: {
140
+ goal: { type: "string" },
141
+ url: { type: "string" },
142
+ interactive: { type: "boolean", short: "i" },
143
+ model: { type: "string" },
144
+ key: { type: "string" },
145
+ "llm-url": { type: "string" },
146
+ "tool-mode": { type: "string" },
147
+ "max-steps": { type: "string" },
148
+ profile: { type: "string" },
149
+ headless: { type: "boolean" },
150
+ executable: { type: "string" },
151
+ fingerprint: { type: "string" },
152
+ proxy: { type: "string" },
153
+ timezone: { type: "string" },
154
+ json: { type: "boolean" },
155
+ help: { type: "boolean", short: "h" },
156
+ },
157
+ };
158
+ let values;
159
+ try {
160
+ ({ values } = parseArgs(config));
161
+ }
162
+ catch (e) {
163
+ throw new UsageError(e.message);
164
+ }
165
+ if (values.help)
166
+ return { cli: {}, help: true };
167
+ const key = values.key ??
168
+ process.env.OPENROUTER_API_KEY ??
169
+ process.env.CLEARCOTE_AGENT_KEY;
170
+ if (!key) {
171
+ throw new UsageError("No OpenRouter API key. Pass --key <k>, or set OPENROUTER_API_KEY or CLEARCOTE_AGENT_KEY.");
172
+ }
173
+ const interactive = !!values.interactive;
174
+ const goal = values.goal;
175
+ if (!interactive && (goal == null || goal.trim() === "")) {
176
+ throw new UsageError("Missing --goal. Provide a task with --goal <text>, or use -i for the REPL.");
177
+ }
178
+ const url = validateUrl(values.url ?? "about:blank");
179
+ const maxSteps = values["max-steps"] != null ? parseMaxSteps(values["max-steps"]) : 20;
180
+ const proxy = values.proxy != null ? parseProxy(values.proxy) : undefined;
181
+ let headless = !!values.headless;
182
+ if (interactive && headless) {
183
+ log("warning: --headless is ignored in interactive mode (REPL is always headed).");
184
+ headless = false;
185
+ }
186
+ const profile = values.profile ?? join(homedir(), ".clearcote", "agent-profile");
187
+ return {
188
+ cli: {
189
+ goal,
190
+ url,
191
+ interactive,
192
+ model: values.model ?? "openai/gpt-4o",
193
+ key,
194
+ llmUrl: values["llm-url"],
195
+ toolMode: values["tool-mode"],
196
+ maxSteps,
197
+ profile,
198
+ headless,
199
+ executable: values.executable,
200
+ fingerprint: values.fingerprint,
201
+ proxy,
202
+ timezone: values.timezone,
203
+ json: !!values.json,
204
+ },
205
+ help: false,
206
+ };
207
+ }
208
+ /** Build the launchAgent options from the parsed config. */
209
+ function launchOptions(cli) {
210
+ mkdirSync(cli.profile, { recursive: true });
211
+ return {
212
+ userDataDir: cli.profile,
213
+ agentLlmKey: cli.key,
214
+ agentLlmUrl: cli.llmUrl,
215
+ agentModel: cli.model,
216
+ agentToolMode: cli.toolMode,
217
+ headless: cli.headless,
218
+ proxy: cli.proxy,
219
+ fingerprint: cli.fingerprint,
220
+ timezone: cli.timezone,
221
+ executablePath: cli.executable,
222
+ };
223
+ }
224
+ /** Resolve the page to drive (reuse the first open page, else create one). */
225
+ async function currentPage(ctx) {
226
+ return ctx.pages()[0] ?? (await ctx.newPage());
227
+ }
228
+ /** One-shot: launch -> goto -> run goal -> print -> close. Returns the process exit code. */
229
+ async function runOneShot(cli) {
230
+ log(`launching Clearcote (profile: ${cli.profile})...`);
231
+ const ctx = await launchAgent(launchOptions(cli));
232
+ try {
233
+ const page = await currentPage(ctx);
234
+ if (cli.url !== "about:blank") {
235
+ log(`navigating to ${cli.url}...`);
236
+ await page.goto(cli.url);
237
+ }
238
+ if (!cli.json)
239
+ process.stdout.write(`goal: ${cli.goal}\n`);
240
+ log(`running (${cli.model}, up to ${cli.maxSteps} steps)...`);
241
+ const result = await runAgentTask(page, cli.goal, {
242
+ model: cli.model,
243
+ maxSteps: cli.maxSteps,
244
+ });
245
+ const finalUrl = page.url();
246
+ if (cli.json) {
247
+ process.stdout.write(JSON.stringify({ ...result, url: finalUrl }, null, 2) + "\n");
248
+ }
249
+ else {
250
+ printResult(result, finalUrl);
251
+ }
252
+ return result.success ? 0 : 1;
253
+ }
254
+ finally {
255
+ await ctx.close();
256
+ }
257
+ }
258
+ /** Interactive REPL: persistent headed session; each non-':' line is a goal on the current page. */
259
+ async function runRepl(cli) {
260
+ log(`launching Clearcote (profile: ${cli.profile})...`);
261
+ const ctx = await launchAgent(launchOptions(cli));
262
+ let page = await currentPage(ctx);
263
+ if (cli.url !== "about:blank") {
264
+ log(`navigating to ${cli.url}...`);
265
+ await page.goto(cli.url);
266
+ }
267
+ let model = cli.model;
268
+ let maxSteps = cli.maxSteps;
269
+ log("interactive mode. Type a goal, or :help for commands. Ctrl-D to quit.");
270
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: "agent> " });
271
+ const replHelp = [
272
+ "commands:",
273
+ " :goto <url> navigate the current page",
274
+ " :url print the current URL",
275
+ " :model <slug> change the model for subsequent goals",
276
+ " :steps <n> change max-steps",
277
+ " :help this help",
278
+ " :quit, :exit close and exit",
279
+ " <anything> run as a goal against the current page",
280
+ ].join("\n");
281
+ return await new Promise((resolve) => {
282
+ let closing = false;
283
+ const finish = () => {
284
+ if (closing)
285
+ return;
286
+ closing = true;
287
+ rl.close();
288
+ ctx
289
+ .close()
290
+ .catch((e) => log(`warning: closing browser failed: ${e.message}`))
291
+ .finally(() => resolve(0));
292
+ };
293
+ // Process one input line (a ':' command or a goal); resolves when it fully settles.
294
+ const processLine = async (line) => {
295
+ if (line.startsWith(":")) {
296
+ const sp = line.indexOf(" ");
297
+ const cmd = (sp === -1 ? line : line.slice(0, sp)).toLowerCase();
298
+ const arg = sp === -1 ? "" : line.slice(sp + 1).trim();
299
+ switch (cmd) {
300
+ case ":quit":
301
+ case ":exit":
302
+ finish();
303
+ return;
304
+ case ":help":
305
+ log(replHelp);
306
+ break;
307
+ case ":url":
308
+ process.stdout.write(page.url() + "\n");
309
+ break;
310
+ case ":goto": {
311
+ if (!arg) {
312
+ log("usage: :goto <url>");
313
+ break;
314
+ }
315
+ let target;
316
+ try {
317
+ target = validateUrl(arg);
318
+ }
319
+ catch (e) {
320
+ log(e.message);
321
+ break;
322
+ }
323
+ try {
324
+ await page.goto(target);
325
+ process.stdout.write(page.url() + "\n");
326
+ }
327
+ catch (e) {
328
+ log(`navigation failed: ${e.message}`);
329
+ }
330
+ break;
331
+ }
332
+ case ":model":
333
+ if (!arg) {
334
+ log(`model: ${model}`);
335
+ break;
336
+ }
337
+ model = arg;
338
+ log(`model set to ${model}`);
339
+ break;
340
+ case ":steps":
341
+ if (!arg) {
342
+ log(`max-steps: ${maxSteps}`);
343
+ break;
344
+ }
345
+ try {
346
+ maxSteps = parseMaxSteps(arg);
347
+ log(`max-steps set to ${maxSteps}`);
348
+ }
349
+ catch (e) {
350
+ log(e.message);
351
+ }
352
+ break;
353
+ default:
354
+ log(`unknown command: ${cmd} (try :help)`);
355
+ }
356
+ return;
357
+ }
358
+ // A goal line.
359
+ process.stdout.write(`goal: ${line}\n`);
360
+ log(`running (${model}, up to ${maxSteps} steps)...`);
361
+ // Re-resolve the page in case the previous one was closed.
362
+ page = await currentPage(ctx);
363
+ const result = await runAgentTask(page, line, { model, maxSteps });
364
+ printResult(result, page.url());
365
+ };
366
+ // Serialize input: pause stdin while a goal/command runs so a second Enter can't start a
367
+ // concurrent goal against the shared page; resume + re-prompt once it settles.
368
+ const pump = (line) => {
369
+ rl.pause();
370
+ processLine(line)
371
+ .catch((e) => log(`error: ${e.message}`))
372
+ .finally(() => {
373
+ if (!closing) {
374
+ rl.resume();
375
+ rl.prompt();
376
+ }
377
+ });
378
+ };
379
+ // If a --goal was passed alongside -i, run it as the first goal before the prompt loop.
380
+ const initial = cli.goal?.trim();
381
+ if (initial) {
382
+ pump(initial);
383
+ }
384
+ else {
385
+ rl.prompt();
386
+ }
387
+ rl.on("line", (raw) => {
388
+ const line = raw.trim();
389
+ if (line === "") {
390
+ rl.prompt();
391
+ return;
392
+ }
393
+ pump(line);
394
+ });
395
+ rl.on("close", finish);
396
+ });
397
+ }
398
+ export async function main(argv = process.argv.slice(2)) {
399
+ let cli;
400
+ try {
401
+ const parsed = parseCli(argv);
402
+ if (parsed.help) {
403
+ process.stdout.write(USAGE + "\n");
404
+ return;
405
+ }
406
+ cli = parsed.cli;
407
+ }
408
+ catch (e) {
409
+ if (e instanceof UsageError) {
410
+ log(e.message);
411
+ process.exitCode = e.code;
412
+ return;
413
+ }
414
+ throw e;
415
+ }
416
+ try {
417
+ process.exitCode = cli.interactive ? await runRepl(cli) : await runOneShot(cli);
418
+ }
419
+ catch (e) {
420
+ log(`error: ${e.message}`);
421
+ process.exitCode = 1;
422
+ }
423
+ }
424
+ main();
425
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -31,7 +31,20 @@ export interface FingerprintOptions {
31
31
  acceptLanguage?: string;
32
32
  /** WebRTC egress IP to report (typically your proxy's public IP). */
33
33
  webrtcIp?: string;
34
- /** Turn OFF GPU/WebGL fingerprint spoofing (advertise the real backend). */
34
+ /**
35
+ * Present the machine's **real GPU** instead of a spoofed one. WebGL `UNMASKED_VENDOR`/`RENDERER`,
36
+ * the `getParameter` table, and the canvas/WebGL render all report the genuine host backend. This
37
+ * is the most coherent setting against strict browser-tampering classifiers: the GPU string and
38
+ * the actually-rendered pixels match, so there is no GPU spoof to catch (the same reason a stock
39
+ * browser passes). Composes with `fingerprintProfile` — the profile still supplies
40
+ * screen/fonts/audio/hardware, but the **real host GPU is kept** instead of the profile's GPU
41
+ * (which the host cannot actually render, and would otherwise be a string-vs-render mismatch).
42
+ * Pair with `fingerprintNoise: false` so the canvas/WebGL readback isn't perturbed either.
43
+ *
44
+ * Trade-off: every persona on one physical machine then shares the same canvas/WebGL identity, so
45
+ * a tracker can link them by GPU hash. Best for single-identity / one-persona-per-host use; for
46
+ * multi-account-on-one-machine, keep this off and instead match the profile's GPU to the host.
47
+ */
35
48
  disableGpuFingerprint?: boolean;
36
49
  /**
37
50
  * Set `false` to turn OFF the per-eTLD+1 farbling NOISE (canvas/WebGL/audio/client-rects), so
@@ -40,6 +53,19 @@ export interface FingerprintOptions {
40
53
  * stay on. Default (unset/`true`) keeps the noise.
41
54
  */
42
55
  fingerprintNoise?: boolean;
56
+ /**
57
+ * Import a real captured fingerprint so the browser presents *that machine's* identity instead
58
+ * of the synthetic seed-derived one. Accepts a path to a `.json` profile, a profile object, or a
59
+ * JSON string (capture one with `tools/fingerprint-collect`). Fields present in the profile
60
+ * override the seed-derived persona; absent fields fall back to the seed, so partial profiles
61
+ * stay coherent.
62
+ */
63
+ fingerprintProfile?: string | Record<string, unknown>;
64
+ /**
65
+ * `navigator.storage.estimate().quota` in **megabytes**. A tiny/ephemeral quota reads as a test
66
+ * machine or incognito; set a realistic on-disk value (e.g. `250000` for ~244 GB).
67
+ */
68
+ storageQuota?: number;
43
69
  }
44
70
  /** Split an options object into its fingerprint half and the remaining (Playwright) half. */
45
71
  export declare function splitFingerprintOptions<T extends FingerprintOptions>(options: T): {
@@ -50,6 +76,13 @@ export declare function splitFingerprintOptions<T extends FingerprintOptions>(op
50
76
  * tag list with NO `;q=` weights or spaces (Chromium adds the q-weights to the header itself; a
51
77
  * `;` in the switch value trips a DCHECK and crashes the renderer). */
52
78
  export declare function cleanAcceptLanguage(v: string): string;
79
+ /** Encode a captured clearcote-profile for the `--fingerprint-profile` switch. `value` may be a
80
+ * path to a `.json` file, a profile object, or a JSON string. gzip+base64 keeps the full capture
81
+ * (~40 KB) within Chromium's command-line length limit (gzip ~6x); the engine gunzips + parses it. */
82
+ export declare function encodeProfile(value: string | Record<string, unknown>): string;
83
+ /** Best-effort: derive an Accept-Language from an imported profile's navigator.languages
84
+ * (path / object / JSON string), so an imported identity keeps the donor's language order. */
85
+ export declare function profileAcceptLanguage(value: string | Record<string, unknown>): string | undefined;
53
86
  /** Build the Chromium switches for a set of fingerprint options. */
54
87
  export declare function fingerprintArgs(o: FingerprintOptions): string[];
55
88
  //# sourceMappingURL=fingerprint.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IACzC,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oCAAoC;IACpC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAChE,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAmBD,6FAA6F;AAC7F,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,kBAAkB,EAClE,OAAO,EAAE,CAAC,GACT;IAAE,WAAW,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,kBAAkB,CAAC,CAAA;CAAE,CAW9E;AAED;;uEAEuE;AACvE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAMrD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,EAAE,CA4B/D"}
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IACzC,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oCAAoC;IACpC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAChE,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;;OAaG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAqBD,6FAA6F;AAC7F,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,kBAAkB,EAClE,OAAO,EAAE,CAAC,GACT;IAAE,WAAW,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,kBAAkB,CAAC,CAAA;CAAE,CAW9E;AAED;;uEAEuE;AACvE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAMrD;AAED;;sGAEsG;AACtG,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAU7E;AAED;8FAC8F;AAC9F,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAajG;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAiD/D"}
@@ -1,5 +1,7 @@
1
1
  // Maps the SDK's fingerprint options to the Clearcote Chromium command-line switches.
2
2
  // Switch names mirror components/ungoogled/ungoogled_switches.cc (see patches/000-fingerprint-switches.patch).
3
+ import { gzipSync } from "node:zlib";
4
+ import { existsSync, readFileSync } from "node:fs";
3
5
  const FINGERPRINT_KEYS = [
4
6
  "fingerprint",
5
7
  "platform",
@@ -15,6 +17,8 @@ const FINGERPRINT_KEYS = [
15
17
  "webrtcIp",
16
18
  "disableGpuFingerprint",
17
19
  "fingerprintNoise",
20
+ "fingerprintProfile",
21
+ "storageQuota",
18
22
  ];
19
23
  /** Split an options object into its fingerprint half and the remaining (Playwright) half. */
20
24
  export function splitFingerprintOptions(options) {
@@ -40,6 +44,43 @@ export function cleanAcceptLanguage(v) {
40
44
  .filter(Boolean)
41
45
  .join(",");
42
46
  }
47
+ /** Encode a captured clearcote-profile for the `--fingerprint-profile` switch. `value` may be a
48
+ * path to a `.json` file, a profile object, or a JSON string. gzip+base64 keeps the full capture
49
+ * (~40 KB) within Chromium's command-line length limit (gzip ~6x); the engine gunzips + parses it. */
50
+ export function encodeProfile(value) {
51
+ let raw;
52
+ if (typeof value === "object") {
53
+ raw = Buffer.from(JSON.stringify(value));
54
+ }
55
+ else if (existsSync(value)) {
56
+ raw = readFileSync(value);
57
+ }
58
+ else {
59
+ raw = Buffer.from(value); // assume a JSON string
60
+ }
61
+ return gzipSync(raw, { level: 9 }).toString("base64");
62
+ }
63
+ /** Best-effort: derive an Accept-Language from an imported profile's navigator.languages
64
+ * (path / object / JSON string), so an imported identity keeps the donor's language order. */
65
+ export function profileAcceptLanguage(value) {
66
+ let obj;
67
+ try {
68
+ if (typeof value === "object")
69
+ obj = value;
70
+ else if (existsSync(value))
71
+ obj = JSON.parse(readFileSync(value, "utf8"));
72
+ else
73
+ obj = JSON.parse(value);
74
+ }
75
+ catch {
76
+ return undefined;
77
+ }
78
+ const nav = obj?.navigator;
79
+ const langs = nav?.languages;
80
+ if (Array.isArray(langs) && langs.length)
81
+ return langs.map(String).join(",");
82
+ return undefined;
83
+ }
43
84
  /** Build the Chromium switches for a set of fingerprint options. */
44
85
  export function fingerprintArgs(o) {
45
86
  const args = [];
@@ -60,9 +101,25 @@ export function fingerprintArgs(o) {
60
101
  set("fingerprint-gpu-renderer", o.gpuRenderer);
61
102
  set("fingerprint-hardware-concurrency", o.hardwareConcurrency);
62
103
  set("fingerprint-location", o.location);
104
+ set("fingerprint-storage-quota", o.storageQuota);
63
105
  set("timezone", o.timezone);
64
- if (o.acceptLanguage)
65
- args.push(`--accept-lang=${cleanAcceptLanguage(String(o.acceptLanguage))}`);
106
+ // Always send a coherent Accept-Language. Without --accept-lang Chromium falls back to the
107
+ // build/OS locale, which can leak a language that mismatches the proxy's country/timezone
108
+ // (e.g. en-GB on a US IP) — a geo-inconsistency tell. Prefer an explicit value, then an imported
109
+ // profile's languages, then en-US,en (the common Chrome default; set acceptLanguage or geoip to
110
+ // match the proxy region).
111
+ const acceptLanguage = o.acceptLanguage ||
112
+ (o.fingerprintProfile ? profileAcceptLanguage(o.fingerprintProfile) : undefined) ||
113
+ "en-US,en";
114
+ const cleanLang = cleanAcceptLanguage(String(acceptLanguage));
115
+ args.push(`--accept-lang=${cleanLang}`);
116
+ // Also pin the UI/ICU locale to the PRIMARY Accept-Language tag, so Intl.DateTimeFormat /
117
+ // NumberFormat / Collator (main thread AND workers) resolve to the same locale as
118
+ // navigator.language. Without --lang, Chromium falls back to the build/OS locale (e.g. en-GB on an
119
+ // en-US persona) — a locale-incoherence tell auditors flag (navigator.language=en-US but Intl=en-GB).
120
+ const primaryLang = cleanLang.split(",")[0];
121
+ if (primaryLang)
122
+ args.push(`--lang=${primaryLang}`);
66
123
  set("webrtc-ip", o.webrtcIp);
67
124
  if (o.disableGpuFingerprint)
68
125
  args.push("--disable-gpu-fingerprint");
@@ -71,6 +128,11 @@ export function fingerprintArgs(o) {
71
128
  // Identity spoofs (UA/screen/GPU/persona) stay on. Default keeps the noise.
72
129
  if (o.fingerprintNoise === false)
73
130
  args.push("--disable-fingerprint-noise");
131
+ // fingerprintProfile imports a real captured fingerprint (path/object/JSON) — see
132
+ // tools/fingerprint-collect. Its fields override the seed-derived persona; absent fields fall
133
+ // back to the seed, so partial profiles stay coherent.
134
+ if (o.fingerprintProfile)
135
+ args.push(`--fingerprint-profile=${encodeProfile(o.fingerprintProfile)}`);
74
136
  return args;
75
137
  }
76
138
  //# sourceMappingURL=fingerprint.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,21 +2,23 @@ import type { Browser, BrowserContext, BrowserContextOptions, LaunchOptions as P
2
2
  import { type DownloadOptions } from "./download.js";
3
3
  import { type FingerprintOptions } from "./fingerprint.js";
4
4
  import { type HumanizeOptions } from "./humanize.js";
5
+ import { type AgentOptions } from "./agent.js";
5
6
  export type { FingerprintOptions } from "./fingerprint.js";
6
7
  export type { DownloadOptions } from "./download.js";
7
8
  export { resolveGeo, type Geo } from "./geoip.js";
8
9
  export type { HumanizeOptions } from "./humanize.js";
10
+ export { runAgentTask, agentArgs, OPENROUTER_BASE_URL, type AgentOptions, type AgentTaskOptions, type AgentTaskResult, type AgentStep, } from "./agent.js";
9
11
  export { RELEASE } from "./release.js";
10
12
  /** When true (and a proxy is set), resolve the proxy's exit-IP geo and auto-fill any unset
11
13
  * `timezone` + `acceptLanguage` (+ `location`) so they match the proxy region. */
12
14
  interface GeoipOption {
13
15
  geoip?: boolean;
14
16
  }
15
- /** Options for {@link launch}: Playwright launch options + Clearcote fingerprint + download options. */
16
- export interface LaunchOptions extends PlaywrightLaunchOptions, FingerprintOptions, GeoipOption, HumanizeOptions, DownloadOptions {
17
+ /** Options for {@link launch}: Playwright launch options + Clearcote fingerprint + agent + download options. */
18
+ export interface LaunchOptions extends PlaywrightLaunchOptions, FingerprintOptions, AgentOptions, GeoipOption, HumanizeOptions, DownloadOptions {
17
19
  }
18
20
  /** Options for {@link launchPersistentContext}. */
19
- export interface PersistentContextOptions extends PlaywrightLaunchOptions, BrowserContextOptions, FingerprintOptions, GeoipOption, HumanizeOptions, DownloadOptions {
21
+ export interface PersistentContextOptions extends PlaywrightLaunchOptions, BrowserContextOptions, FingerprintOptions, AgentOptions, GeoipOption, HumanizeOptions, DownloadOptions {
20
22
  }
21
23
  /**
22
24
  * Resolve the Clearcote chrome.exe path, downloading + verifying it if needed.
@@ -34,11 +36,37 @@ export declare function launch(options?: LaunchOptions): Promise<Browser>;
34
36
  * {@link BrowserContext} (cookies, storage, etc. persist in `userDataDir`).
35
37
  */
36
38
  export declare function launchPersistentContext(userDataDir: string, options?: PersistentContextOptions): Promise<BrowserContext>;
39
+ /** Options for {@link launchAgent}: persistent-context options + an optional `userDataDir`. */
40
+ export interface LaunchAgentOptions extends PersistentContextOptions {
41
+ /** Profile directory to persist (cookies/storage/logins). Defaults to a fresh temp dir. */
42
+ userDataDir?: string;
43
+ }
44
+ /**
45
+ * Launch Clearcote ready for the in-browser AI agent and return a Playwright {@link BrowserContext}.
46
+ *
47
+ * The agent drives Chrome's Actor framework, which only attaches to a **regular profile** — not
48
+ * incognito — so this uses a *persistent* context (a fresh temp `userDataDir` unless you pass one).
49
+ * Set `agentLlmKey` (+ optional `agentModel`), then drive a page with {@link runAgentTask}:
50
+ *
51
+ * ```ts
52
+ * const ctx = await launchAgent({ agentLlmKey: process.env.OPENROUTER_API_KEY, agentModel: "openai/gpt-4o-mini" });
53
+ * const page = ctx.pages()[0] ?? (await ctx.newPage());
54
+ * await page.goto("https://example.com");
55
+ * const result = await runAgentTask(page, "Click the 'More information...' link.");
56
+ * ```
57
+ *
58
+ * Use this (or {@link launchPersistentContext}) for the agent — plain {@link launch} is incognito,
59
+ * where the Actor framework can't attach the tab.
60
+ */
61
+ export declare function launchAgent(options?: LaunchAgentOptions): Promise<BrowserContext>;
62
+ import { runAgentTask } from "./agent.js";
37
63
  declare const _default: {
38
64
  launch: typeof launch;
39
65
  launchPersistentContext: typeof launchPersistentContext;
66
+ launchAgent: typeof launchAgent;
40
67
  executablePath: typeof executablePath;
41
68
  download: typeof download;
69
+ runAgentTask: typeof runAgentTask;
42
70
  RELEASE: import("./release.js").ReleaseInfo;
43
71
  };
44
72
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,qBAAqB,EACrB,aAAa,IAAI,uBAAuB,EACzC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAA4C,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAErG,OAAO,EAA6C,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhG,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;kFACkF;AAClF,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wGAAwG;AACxG,MAAM,WAAW,aAAc,SAAQ,uBAAuB,EAAE,kBAAkB,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe;CAAG;AAEpI,mDAAmD;AACnD,MAAM,WAAW,wBACf,SAAQ,uBAAuB,EAC7B,qBAAqB,EACrB,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,eAAe;CAAG;AAwBtB;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,eAAoB,GAC1D,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED,iGAAiG;AACjG,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAE7E;AAED,yEAAyE;AACzE,wBAAsB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAa1E;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,cAAc,CAAC,CAazB;;;;;;;;AAED,wBAAsF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,qBAAqB,EACrB,aAAa,IAAI,uBAAuB,EACzC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAA4C,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAErG,OAAO,EAA6C,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAChG,OAAO,EAAgC,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG7E,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EACL,YAAY,EACZ,SAAS,EACT,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,SAAS,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;kFACkF;AAClF,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,gHAAgH;AAChH,MAAM,WAAW,aAAc,SAAQ,uBAAuB,EAAE,kBAAkB,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe;CAAG;AAElJ,mDAAmD;AACnD,MAAM,WAAW,wBACf,SAAQ,uBAAuB,EAC7B,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,eAAe;CAAG;AAwBtB;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,eAAoB,GAC1D,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED,iGAAiG;AACjG,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAE7E;AAED,yEAAyE;AACzE,wBAAsB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAc1E;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,cAAc,CAAC,CAczB;AAED,+FAA+F;AAC/F,MAAM,WAAW,kBAAmB,SAAQ,wBAAwB;IAClE,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,cAAc,CAAC,CAI3F;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;;;;;;;;;;AAC1C,wBAAiH"}
package/dist/index.js CHANGED
@@ -10,12 +10,17 @@
10
10
  // (headless, proxy, args, timeout, ...) passes through; the fingerprint options below are added
11
11
  // as engine switches.
12
12
  import { chromium } from "playwright-core";
13
+ import { mkdtempSync } from "node:fs";
14
+ import { tmpdir } from "node:os";
15
+ import { join } from "node:path";
13
16
  import { ensureBinary } from "./download.js";
14
17
  import { fingerprintArgs, splitFingerprintOptions } from "./fingerprint.js";
15
18
  import { resolveGeo } from "./geoip.js";
16
19
  import { installHumanize, installHumanizeOnContext } from "./humanize.js";
20
+ import { agentArgs, splitAgentOptions } from "./agent.js";
17
21
  import { RELEASE } from "./release.js";
18
22
  export { resolveGeo } from "./geoip.js";
23
+ export { runAgentTask, agentArgs, OPENROUTER_BASE_URL, } from "./agent.js";
19
24
  export { RELEASE } from "./release.js";
20
25
  /** Fill unset timezone/acceptLanguage/location/webrtcIp on `fp` from the proxy's exit-IP geo. */
21
26
  async function applyGeoip(fp, proxy) {
@@ -58,7 +63,8 @@ export async function download(options = {}) {
58
63
  /** Launch Clearcote and return a standard Playwright {@link Browser}. */
59
64
  export async function launch(options = {}) {
60
65
  const { executablePath: exeOption, args, geoip, humanize, showCursor, autoUpdate, cacheDir, quiet, ...rest } = options;
61
- const { fingerprint, rest: pwOptions } = splitFingerprintOptions(rest);
66
+ const { fingerprint, rest: afterFp } = splitFingerprintOptions(rest);
67
+ const { agent, rest: pwOptions } = splitAgentOptions(afterFp);
62
68
  if (geoip)
63
69
  await applyGeoip(fingerprint, pwOptions.proxy);
64
70
  const exe = await executablePath({ executablePath: exeOption, autoUpdate, cacheDir, quiet });
@@ -66,7 +72,7 @@ export async function launch(options = {}) {
66
72
  const browser = await chromium.launch({
67
73
  ...pwOptions,
68
74
  executablePath: exe,
69
- args: [...fingerprintArgs(fingerprint), ...(args ?? [])],
75
+ args: [...fingerprintArgs(fingerprint), ...agentArgs(agent), ...(args ?? [])],
70
76
  });
71
77
  installHumanize(browser, { humanize, showCursor });
72
78
  return browser;
@@ -77,7 +83,8 @@ export async function launch(options = {}) {
77
83
  */
78
84
  export async function launchPersistentContext(userDataDir, options = {}) {
79
85
  const { executablePath: exeOption, args, geoip, humanize, showCursor, autoUpdate, cacheDir, quiet, ...rest } = options;
80
- const { fingerprint, rest: pwOptions } = splitFingerprintOptions(rest);
86
+ const { fingerprint, rest: afterFp } = splitFingerprintOptions(rest);
87
+ const { agent, rest: pwOptions } = splitAgentOptions(afterFp);
81
88
  if (geoip)
82
89
  await applyGeoip(fingerprint, pwOptions.proxy);
83
90
  const exe = await executablePath({ executablePath: exeOption, autoUpdate, cacheDir, quiet });
@@ -85,10 +92,33 @@ export async function launchPersistentContext(userDataDir, options = {}) {
85
92
  const context = await chromium.launchPersistentContext(userDataDir, {
86
93
  ...pwOptions,
87
94
  executablePath: exe,
88
- args: [...fingerprintArgs(fingerprint), ...(args ?? [])],
95
+ args: [...fingerprintArgs(fingerprint), ...agentArgs(agent), ...(args ?? [])],
89
96
  });
90
97
  installHumanizeOnContext(context, { humanize, showCursor });
91
98
  return context;
92
99
  }
93
- export default { launch, launchPersistentContext, executablePath, download, RELEASE };
100
+ /**
101
+ * Launch Clearcote ready for the in-browser AI agent and return a Playwright {@link BrowserContext}.
102
+ *
103
+ * The agent drives Chrome's Actor framework, which only attaches to a **regular profile** — not
104
+ * incognito — so this uses a *persistent* context (a fresh temp `userDataDir` unless you pass one).
105
+ * Set `agentLlmKey` (+ optional `agentModel`), then drive a page with {@link runAgentTask}:
106
+ *
107
+ * ```ts
108
+ * const ctx = await launchAgent({ agentLlmKey: process.env.OPENROUTER_API_KEY, agentModel: "openai/gpt-4o-mini" });
109
+ * const page = ctx.pages()[0] ?? (await ctx.newPage());
110
+ * await page.goto("https://example.com");
111
+ * const result = await runAgentTask(page, "Click the 'More information...' link.");
112
+ * ```
113
+ *
114
+ * Use this (or {@link launchPersistentContext}) for the agent — plain {@link launch} is incognito,
115
+ * where the Actor framework can't attach the tab.
116
+ */
117
+ export async function launchAgent(options = {}) {
118
+ const { userDataDir, ...rest } = options;
119
+ const dir = userDataDir ?? mkdtempSync(join(tmpdir(), "clearcote-agent-"));
120
+ return launchPersistentContext(dir, rest);
121
+ }
122
+ import { runAgentTask } from "./agent.js";
123
+ export default { launch, launchPersistentContext, launchAgent, executablePath, download, runAgentTask, RELEASE };
94
124
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,wCAAwC;AACxC,oFAAoF;AACpF,0CAA0C;AAC1C,iEAAiE;AACjE,EAAE;AACF,4FAA4F;AAC5F,gGAAgG;AAChG,gGAAgG;AAChG,sBAAsB;AAEtB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAO3C,OAAO,EAAE,YAAY,EAAwB,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAA2B,MAAM,kBAAkB,CAAC;AACrG,OAAO,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAwB,MAAM,eAAe,CAAC;AAChG,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAIvC,OAAO,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAoBvC,iGAAiG;AACjG,KAAK,UAAU,UAAU,CAAC,EAAsB,EAAE,KAAc;IAC9D,MAAM,GAAG,GAAe,MAAM,UAAU,CAAC,KAA8E,CAAC,CAAC;IACzH,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,QAAQ,IAAI,IAAI;QAAE,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IACpE,IAAI,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,cAAc,IAAI,IAAI;QAAE,EAAE,CAAC,cAAc,GAAG,GAAG,CAAC,cAAc,CAAC;IAC5F,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,QAAQ,IAAI,IAAI;QAAE,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IACpE,2FAA2F;IAC3F,iEAAiE;IACjE,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,QAAQ,IAAI,IAAI;QAAE,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAW;IACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,aAAa,OAAO,CAAC,OAAO,2DAA2D,OAAO,CAAC,QAAQ,MAAM;YAC3G,kEAAkE;YAClE,8DAA8D,GAAG,GAAG,CACvE,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAAyD,EAAE;IAE3D,IAAI,OAAO,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,cAAc,CAAC;IAC1D,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACtE,OAAO,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;AAC5G,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,UAA2B,EAAE;IAC1D,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAAyB,EAAE;IACtD,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACvH,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACvE,IAAI,KAAK;QAAE,MAAM,UAAU,CAAC,WAAW,EAAG,SAAqC,CAAC,KAAK,CAAC,CAAC;IACvF,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7F,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QACpC,GAAI,SAAqC;QACzC,cAAc,EAAE,GAAG;QACnB,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KACzD,CAAC,CAAC;IACH,eAAe,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IACnD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,WAAmB,EACnB,UAAoC,EAAE;IAEtC,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACvH,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACvE,IAAI,KAAK;QAAE,MAAM,UAAU,CAAC,WAAW,EAAG,SAAqC,CAAC,KAAK,CAAC,CAAC;IACvF,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7F,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,uBAAuB,CAAC,WAAW,EAAE;QAClE,GAAI,SAA6D;QACjE,cAAc,EAAE,GAAG;QACnB,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KACzD,CAAC,CAAC;IACH,wBAAwB,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAC5D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,eAAe,EAAE,MAAM,EAAE,uBAAuB,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/release.js CHANGED
@@ -4,13 +4,13 @@
4
4
  // this package, the hash check guarantees you run exactly the published, signed binary.
5
5
  // Published checksums + GPG signatures live on the release page.
6
6
  export const RELEASE = {
7
- tag: "v0.1.0-pre.7",
7
+ tag: "v0.1.0-pre.10",
8
8
  version: "149.0.7827.114",
9
9
  asset: "clearcote-149.0.7827.114-windows-x64.zip",
10
- url: "https://github.com/clearcotelabs/clearcote-browser/releases/download/v0.1.0-pre.7/clearcote-149.0.7827.114-windows-x64.zip",
11
- sha256: "85417dacb82d074a9f23ff326fb9837df3387e4c72b0c628c21d8d407d5f6f58",
10
+ url: "https://github.com/clearcotelabs/clearcote-browser/releases/download/v0.1.0-pre.10/clearcote-149.0.7827.114-windows-x64.zip",
11
+ sha256: "8e1f72cc32b3c2adcc64b6ef6be9d367c4a63b51c4a459a626b000126cb019af",
12
12
  exeSha256: "5743595256c89c6874804bf3315acce592fc7f1883760c8d380c010151a73b23",
13
- size: 242557010,
13
+ size: 242602257,
14
14
  os: "win32",
15
15
  };
16
16
  /** GitHub repo (owner/name) the releases come from — used by the opt-in auto-update resolver. */
@@ -1 +1 @@
1
- {"version":3,"file":"release.js","sourceRoot":"","sources":["../src/release.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,wFAAwF;AACxF,2FAA2F;AAC3F,wFAAwF;AACxF,iEAAiE;AAqBjE,MAAM,CAAC,MAAM,OAAO,GAAgB;IAClC,GAAG,EAAE,cAAc;IACnB,OAAO,EAAE,gBAAgB;IACzB,KAAK,EAAE,0CAA0C;IACjD,GAAG,EAAE,4HAA4H;IACjI,MAAM,EAAE,kEAAkE;IAC1E,SAAS,EAAE,kEAAkE;IAC7E,IAAI,EAAE,SAAS;IACf,EAAE,EAAE,OAAO;CACZ,CAAC;AAEF,iGAAiG;AACjG,MAAM,CAAC,MAAM,IAAI,GAAG,iCAAiC,CAAC;AAEtD;;;qFAGqF;AACrF,MAAM,CAAC,MAAM,eAAe,GAAG,0CAA0C,CAAC"}
1
+ {"version":3,"file":"release.js","sourceRoot":"","sources":["../src/release.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,wFAAwF;AACxF,2FAA2F;AAC3F,wFAAwF;AACxF,iEAAiE;AAqBjE,MAAM,CAAC,MAAM,OAAO,GAAgB;IAClC,GAAG,EAAE,eAAe;IACpB,OAAO,EAAE,gBAAgB;IACzB,KAAK,EAAE,0CAA0C;IACjD,GAAG,EAAE,6HAA6H;IAClI,MAAM,EAAE,kEAAkE;IAC1E,SAAS,EAAE,kEAAkE;IAC7E,IAAI,EAAE,SAAS;IACf,EAAE,EAAE,OAAO;CACZ,CAAC;AAEF,iGAAiG;AACjG,MAAM,CAAC,MAAM,IAAI,GAAG,iCAAiC,CAAC;AAEtD;;;qFAGqF;AACrF,MAAM,CAAC,MAAM,eAAe,GAAG,0CAA0C,CAAC"}
package/package.json CHANGED
@@ -1,58 +1,65 @@
1
- {
2
- "name": "clearcote",
3
- "version": "0.6.0",
4
- "description": "Playwright drop-in for the Clearcote anti-fingerprint Chromium build. launch() returns a standard Playwright Browser backed by the verified Clearcote binary, which is auto-downloaded and SHA-256 checked.",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
- }
13
- },
14
- "files": [
15
- "dist",
16
- "README.md"
17
- ],
18
- "engines": {
19
- "node": ">=18"
20
- },
21
- "scripts": {
22
- "build": "tsc -p tsconfig.json",
23
- "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
24
- "prepublishOnly": "npm run clean && npm run build"
25
- },
26
- "dependencies": {
27
- "extract-zip": "^2.0.1",
28
- "maxmind": "^4.3.0",
29
- "playwright-core": "^1.49.0"
30
- },
31
- "devDependencies": {
32
- "@types/node": "^22.0.0",
33
- "typescript": "^5.6.0"
34
- },
35
- "keywords": [
36
- "clearcote",
37
- "playwright",
38
- "puppeteer",
39
- "chromium",
40
- "anti-detect",
41
- "anti-fingerprint",
42
- "fingerprint",
43
- "farbling",
44
- "automation",
45
- "stealth",
46
- "ungoogled"
47
- ],
48
- "license": "BSD-3-Clause",
49
- "homepage": "https://github.com/clearcotelabs/clearcote-browser",
50
- "repository": {
51
- "type": "git",
52
- "url": "git+https://github.com/clearcotelabs/clearcote-browser.git",
53
- "directory": "sdk/node"
54
- },
55
- "bugs": {
56
- "url": "https://github.com/clearcotelabs/clearcote-browser/issues"
57
- }
58
- }
1
+ {
2
+ "name": "clearcote",
3
+ "version": "0.8.0",
4
+ "description": "Playwright drop-in for the Clearcote anti-fingerprint Chromium build. launch() returns a standard Playwright Browser backed by the verified Clearcote binary, which is auto-downloaded and SHA-256 checked.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "clearcote-agent": "./dist/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "engines": {
22
+ "node": ">=18"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc -p tsconfig.json",
26
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
27
+ "typecheck": "tsc -p tsconfig.json --noEmit",
28
+ "test": "vitest run",
29
+ "test:watch": "vitest",
30
+ "prepublishOnly": "npm run clean && npm run build"
31
+ },
32
+ "dependencies": {
33
+ "extract-zip": "^2.0.1",
34
+ "maxmind": "^4.3.0",
35
+ "playwright-core": "^1.49.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^22.0.0",
39
+ "typescript": "^5.6.0",
40
+ "vitest": "^2.1.9"
41
+ },
42
+ "keywords": [
43
+ "clearcote",
44
+ "playwright",
45
+ "puppeteer",
46
+ "chromium",
47
+ "anti-detect",
48
+ "anti-fingerprint",
49
+ "fingerprint",
50
+ "farbling",
51
+ "automation",
52
+ "stealth",
53
+ "ungoogled"
54
+ ],
55
+ "license": "BSD-3-Clause",
56
+ "homepage": "https://github.com/clearcotelabs/clearcote-browser",
57
+ "repository": {
58
+ "type": "git",
59
+ "url": "git+https://github.com/clearcotelabs/clearcote-browser.git",
60
+ "directory": "sdk/node"
61
+ },
62
+ "bugs": {
63
+ "url": "https://github.com/clearcotelabs/clearcote-browser/issues"
64
+ }
65
+ }