agentic-browser 1.0.2 → 1.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/AGENTS.md
CHANGED
|
@@ -59,8 +59,10 @@ AgenticBrowserCore → ControlApi → SessionManager → BrowserController (CDP)
|
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
1. `createAgenticBrowserCore()` builds AppContext + ChromeCdpBrowserController
|
|
62
|
-
2.
|
|
63
|
-
3.
|
|
62
|
+
2. `createSession` either launches a new Chrome (`browser.launch()`) or connects to existing one (`browser.connect(cdpUrl)`) based on config
|
|
63
|
+
3. Commands execute via CDP `Runtime.evaluate` on the browser page
|
|
64
|
+
4. Results are recorded as evidence, indexed per-domain for memory search
|
|
65
|
+
5. Connected sessions (pid=0) skip `process.kill` on terminate — the user's browser stays open
|
|
64
66
|
|
|
65
67
|
## Code Conventions
|
|
66
68
|
|
|
@@ -108,6 +110,8 @@ AgenticBrowserCore → ControlApi → SessionManager → BrowserController (CDP)
|
|
|
108
110
|
|
|
109
111
|
- `AGENTIC_BROWSER_LOG_DIR` — base dir for sessions/memory/events (default: `.agentic-browser`)
|
|
110
112
|
- `AGENTIC_BROWSER_CHROME_EXECUTABLE_PATH` — explicit Chrome path (auto-discovered if not set)
|
|
113
|
+
- `AGENTIC_BROWSER_CDP_URL` — connect to an already-running Chrome via CDP (e.g. `http://127.0.0.1:9222`)
|
|
114
|
+
- `AGENTIC_BROWSER_USER_PROFILE` — use real Chrome profile (`default`, `true`, or absolute path)
|
|
111
115
|
|
|
112
116
|
## MCP Server
|
|
113
117
|
|
package/README.md
CHANGED
|
@@ -37,12 +37,72 @@ npm run lint
|
|
|
37
37
|
npm test
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
## Connect to Existing Chrome / Use Your Profile
|
|
41
|
+
|
|
42
|
+
By default, agentic-browser launches a fresh Chrome instance with an isolated profile. You can instead **connect to an already-running Chrome** or **launch Chrome with your real profile** (bookmarks, cookies, extensions, saved passwords).
|
|
43
|
+
|
|
44
|
+
### Connect to a running Chrome
|
|
45
|
+
|
|
46
|
+
Start Chrome yourself with remote debugging enabled:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# macOS
|
|
50
|
+
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
|
|
51
|
+
|
|
52
|
+
# Linux
|
|
53
|
+
google-chrome --remote-debugging-port=9222
|
|
54
|
+
|
|
55
|
+
# Windows
|
|
56
|
+
chrome.exe --remote-debugging-port=9222
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Then connect agentic-browser to it:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
agentic-browser agent start --cdp-url http://127.0.0.1:9222
|
|
63
|
+
# or low-level:
|
|
64
|
+
agentic-browser session:start --cdp-url http://127.0.0.1:9222
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
When connected this way, stopping the session will **not** kill your Chrome process.
|
|
68
|
+
|
|
69
|
+
### Launch Chrome with your real profile
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Use your default Chrome profile
|
|
73
|
+
agentic-browser agent start --user-profile default
|
|
74
|
+
|
|
75
|
+
# Use a specific profile directory
|
|
76
|
+
agentic-browser agent start --user-profile /path/to/chrome/profile
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The default profile path is resolved per platform:
|
|
80
|
+
- **macOS:** `~/Library/Application Support/Google/Chrome`
|
|
81
|
+
- **Linux:** `~/.config/google-chrome`
|
|
82
|
+
- **Windows:** `%LOCALAPPDATA%\Google\Chrome\User Data`
|
|
83
|
+
|
|
84
|
+
### Environment variables
|
|
85
|
+
|
|
86
|
+
Both options can also be set via environment variables:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Connect to existing Chrome
|
|
90
|
+
export AGENTIC_BROWSER_CDP_URL=http://127.0.0.1:9222
|
|
91
|
+
|
|
92
|
+
# Use default Chrome profile (set to "default", "true", or an absolute path)
|
|
93
|
+
export AGENTIC_BROWSER_USER_PROFILE=default
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
CLI flags take precedence over environment variables.
|
|
97
|
+
|
|
40
98
|
## Agent Commands (Recommended for LLMs)
|
|
41
99
|
|
|
42
100
|
The `agent` subcommand manages session state, auto-restarts on disconnect, generates command IDs, and retries failed commands automatically:
|
|
43
101
|
|
|
44
102
|
```bash
|
|
45
103
|
agentic-browser agent start
|
|
104
|
+
agentic-browser agent start --cdp-url http://127.0.0.1:9222
|
|
105
|
+
agentic-browser agent start --user-profile default
|
|
46
106
|
agentic-browser agent status
|
|
47
107
|
agentic-browser agent run navigate '{"url":"https://example.com"}'
|
|
48
108
|
agentic-browser agent run interact '{"action":"click","selector":"#login"}'
|
|
@@ -120,6 +180,8 @@ For direct control without session state management:
|
|
|
120
180
|
|
|
121
181
|
```bash
|
|
122
182
|
agentic-browser session:start
|
|
183
|
+
agentic-browser session:start --cdp-url http://127.0.0.1:9222
|
|
184
|
+
agentic-browser session:start --user-profile default
|
|
123
185
|
```
|
|
124
186
|
|
|
125
187
|
### 2. Read Session Status
|
|
@@ -220,6 +282,31 @@ const memory = core.searchMemory({
|
|
|
220
282
|
await core.stopSession(session.sessionId);
|
|
221
283
|
```
|
|
222
284
|
|
|
285
|
+
### Connect to existing Chrome programmatically
|
|
286
|
+
|
|
287
|
+
```ts
|
|
288
|
+
import { createAgenticBrowserCore } from "agentic-browser";
|
|
289
|
+
|
|
290
|
+
// Connect to a Chrome instance running with --remote-debugging-port=9222
|
|
291
|
+
const core = createAgenticBrowserCore({
|
|
292
|
+
env: { ...process.env, AGENTIC_BROWSER_CDP_URL: "http://127.0.0.1:9222" },
|
|
293
|
+
});
|
|
294
|
+
const session = await core.startSession();
|
|
295
|
+
// session is now controlling the existing Chrome — stopping won't kill it
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Use default Chrome profile programmatically
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
import { createAgenticBrowserCore } from "agentic-browser";
|
|
302
|
+
|
|
303
|
+
const core = createAgenticBrowserCore({
|
|
304
|
+
env: { ...process.env, AGENTIC_BROWSER_USER_PROFILE: "default" },
|
|
305
|
+
});
|
|
306
|
+
const session = await core.startSession();
|
|
307
|
+
// Chrome launched with your real profile (cookies, bookmarks, extensions)
|
|
308
|
+
```
|
|
309
|
+
|
|
223
310
|
## Documentation
|
|
224
311
|
|
|
225
312
|
```bash
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { r as createCliRuntime } from "../runtime-B_7vsUma.mjs";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import crypto from "node:crypto";
|
|
@@ -242,7 +243,9 @@ async function main() {
|
|
|
242
243
|
const runtime = createCliRuntime();
|
|
243
244
|
const program = new Command();
|
|
244
245
|
program.name("agentic-browser").description("Agentic browser CLI");
|
|
245
|
-
program.command("session:start").action(async () => {
|
|
246
|
+
program.command("session:start").option("--cdp-url <url>", "connect to existing Chrome via CDP endpoint URL").option("--user-profile <path>", "use 'default' for system Chrome profile or an absolute path").action(async (options) => {
|
|
247
|
+
if (options.cdpUrl) runtime.context.config.cdpUrl = options.cdpUrl;
|
|
248
|
+
if (options.userProfile) runtime.context.config.userProfileDir = options.userProfile === "true" || options.userProfile === "default" ? "default" : options.userProfile;
|
|
246
249
|
const result = await runSessionStart(runtime, { browser: "chrome" });
|
|
247
250
|
console.log(JSON.stringify(result));
|
|
248
251
|
});
|
|
@@ -307,7 +310,9 @@ async function main() {
|
|
|
307
310
|
console.log(JSON.stringify(result));
|
|
308
311
|
});
|
|
309
312
|
const agent = program.command("agent").description("Stateful agent wrapper with session persistence and auto-retry");
|
|
310
|
-
agent.command("start").action(async () => {
|
|
313
|
+
agent.command("start").option("--cdp-url <url>", "connect to existing Chrome via CDP endpoint URL").option("--user-profile <path>", "use 'default' for system Chrome profile or an absolute path").action(async (options) => {
|
|
314
|
+
if (options.cdpUrl) runtime.context.config.cdpUrl = options.cdpUrl;
|
|
315
|
+
if (options.userProfile) runtime.context.config.userProfileDir = options.userProfile === "true" || options.userProfile === "default" ? "default" : options.userProfile;
|
|
311
316
|
const result = await agentStart(runtime);
|
|
312
317
|
console.log(JSON.stringify(result));
|
|
313
318
|
});
|
|
@@ -361,7 +366,7 @@ async function main() {
|
|
|
361
366
|
await startMcpServer();
|
|
362
367
|
});
|
|
363
368
|
program.command("setup").description("Configure agentic-browser as MCP server for your AI tool").action(async () => {
|
|
364
|
-
const { runSetup } = await import("../setup-
|
|
369
|
+
const { runSetup } = await import("../setup-COK-KCfv.mjs");
|
|
365
370
|
await runSetup();
|
|
366
371
|
});
|
|
367
372
|
await program.parseAsync(process.argv);
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { i as createMockAgenticBrowserCore, n as createAgenticBrowserCore, t as AgenticBrowserCore } from "./runtime-B_7vsUma.mjs";
|
|
2
3
|
|
|
3
4
|
export { AgenticBrowserCore, createAgenticBrowserCore, createMockAgenticBrowserCore };
|
package/dist/mcp/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { n as createAgenticBrowserCore } from "../runtime-B_7vsUma.mjs";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
import { spawn } from "node:child_process";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import net from "node:net";
|
|
5
|
+
import os from "node:os";
|
|
4
6
|
import path from "node:path";
|
|
5
7
|
import WebSocket, { WebSocketServer } from "ws";
|
|
6
8
|
import { URL as URL$1, fileURLToPath } from "node:url";
|
|
@@ -156,6 +158,13 @@ async function getFreePort() {
|
|
|
156
158
|
});
|
|
157
159
|
});
|
|
158
160
|
}
|
|
161
|
+
function resolveDefaultProfileDir() {
|
|
162
|
+
const platform = os.platform();
|
|
163
|
+
const home = os.homedir();
|
|
164
|
+
if (platform === "darwin") return path.join(home, "Library", "Application Support", "Google", "Chrome");
|
|
165
|
+
if (platform === "win32") return path.join(process.env.LOCALAPPDATA ?? path.join(home, "AppData", "Local"), "Google", "Chrome", "User Data");
|
|
166
|
+
return path.join(home, ".config", "google-chrome");
|
|
167
|
+
}
|
|
159
168
|
var ChromeCdpBrowserController = class {
|
|
160
169
|
connections = /* @__PURE__ */ new Map();
|
|
161
170
|
constructor(baseDir, connectionFactory = CdpConnection.connect) {
|
|
@@ -190,6 +199,19 @@ var ChromeCdpBrowserController = class {
|
|
|
190
199
|
closeConnection(targetWsUrl) {
|
|
191
200
|
this.dropConnection(targetWsUrl);
|
|
192
201
|
}
|
|
202
|
+
async connect(cdpUrl) {
|
|
203
|
+
const parsed = new URL(cdpUrl);
|
|
204
|
+
const port = Number.parseInt(parsed.port, 10);
|
|
205
|
+
if (!port) throw new Error(`Invalid CDP URL: could not extract port from ${cdpUrl}`);
|
|
206
|
+
await waitForDebugger(port);
|
|
207
|
+
const targetWsUrl = await createTarget(cdpUrl);
|
|
208
|
+
await evaluateExpression(targetWsUrl, "window.location.href");
|
|
209
|
+
return {
|
|
210
|
+
pid: 0,
|
|
211
|
+
cdpUrl,
|
|
212
|
+
targetWsUrl
|
|
213
|
+
};
|
|
214
|
+
}
|
|
193
215
|
async ensureEnabled(targetWsUrl) {
|
|
194
216
|
const cached = this.connections.get(targetWsUrl);
|
|
195
217
|
if (!cached) return;
|
|
@@ -202,10 +224,13 @@ var ChromeCdpBrowserController = class {
|
|
|
202
224
|
cached.enabled.runtime = true;
|
|
203
225
|
}
|
|
204
226
|
}
|
|
205
|
-
async launch(sessionId, explicitPath) {
|
|
227
|
+
async launch(sessionId, explicitPath, userProfileDir) {
|
|
206
228
|
const executablePath = discoverChrome(explicitPath);
|
|
207
229
|
const extension = loadControlExtension();
|
|
208
|
-
|
|
230
|
+
let profileDir;
|
|
231
|
+
if (userProfileDir === "default") profileDir = resolveDefaultProfileDir();
|
|
232
|
+
else if (userProfileDir) profileDir = userProfileDir;
|
|
233
|
+
else profileDir = path.join(this.baseDir, "profiles", sessionId);
|
|
209
234
|
fs.mkdirSync(profileDir, { recursive: true });
|
|
210
235
|
const launchAttempts = [
|
|
211
236
|
{
|
|
@@ -639,6 +664,7 @@ var ChromeCdpBrowserController = class {
|
|
|
639
664
|
}
|
|
640
665
|
}
|
|
641
666
|
terminate(pid) {
|
|
667
|
+
if (pid === 0) return;
|
|
642
668
|
try {
|
|
643
669
|
process.kill(pid, "SIGTERM");
|
|
644
670
|
} catch {}
|
|
@@ -661,6 +687,19 @@ var MockBrowserController = class {
|
|
|
661
687
|
targetWsUrl
|
|
662
688
|
};
|
|
663
689
|
}
|
|
690
|
+
async connect(cdpUrl) {
|
|
691
|
+
this.pages.set(cdpUrl, {
|
|
692
|
+
url: "about:blank",
|
|
693
|
+
title: "about:blank",
|
|
694
|
+
text: "",
|
|
695
|
+
html: "<html><body></body></html>"
|
|
696
|
+
});
|
|
697
|
+
return {
|
|
698
|
+
pid: 0,
|
|
699
|
+
cdpUrl,
|
|
700
|
+
targetWsUrl: cdpUrl
|
|
701
|
+
};
|
|
702
|
+
}
|
|
664
703
|
async navigate(cdpUrl, url) {
|
|
665
704
|
const page = this.pages.get(cdpUrl);
|
|
666
705
|
if (!page) throw new Error("mock page missing");
|
|
@@ -784,7 +823,7 @@ var SessionManager = class {
|
|
|
784
823
|
if (active && active.session.status !== "terminated") throw new Error("A managed session is already active");
|
|
785
824
|
const sessionId = crypto.randomUUID();
|
|
786
825
|
const token = this.ctx.tokenService.issue(sessionId);
|
|
787
|
-
const launched = await this.browser.launch(sessionId, this.ctx.config.browserExecutablePath);
|
|
826
|
+
const launched = this.ctx.config.cdpUrl ? await this.browser.connect(this.ctx.config.cdpUrl) : await this.browser.launch(sessionId, this.ctx.config.browserExecutablePath, this.ctx.config.userProfileDir);
|
|
788
827
|
const session = {
|
|
789
828
|
sessionId,
|
|
790
829
|
status: "ready",
|
|
@@ -1135,12 +1174,18 @@ function loadConfig(env = process.env) {
|
|
|
1135
1174
|
const commandTimeoutMs = Number.parseInt(env.AGENTIC_BROWSER_COMMAND_TIMEOUT_MS ?? `${DEFAULT_TIMEOUT_MS}`, 10);
|
|
1136
1175
|
if (Number.isNaN(wsPort) || wsPort <= 0) throw new Error("AGENTIC_BROWSER_WS_PORT must be a positive integer");
|
|
1137
1176
|
if (Number.isNaN(commandTimeoutMs) || commandTimeoutMs <= 0) throw new Error("AGENTIC_BROWSER_COMMAND_TIMEOUT_MS must be a positive integer");
|
|
1177
|
+
const userProfile = env.AGENTIC_BROWSER_USER_PROFILE;
|
|
1178
|
+
let userProfileDir;
|
|
1179
|
+
if (userProfile === "true" || userProfile === "default") userProfileDir = "default";
|
|
1180
|
+
else if (userProfile && path.isAbsolute(userProfile)) userProfileDir = userProfile;
|
|
1138
1181
|
return {
|
|
1139
1182
|
host: env.AGENTIC_BROWSER_HOST ?? "127.0.0.1",
|
|
1140
1183
|
wsPort,
|
|
1141
1184
|
commandTimeoutMs,
|
|
1142
1185
|
logDir: env.AGENTIC_BROWSER_LOG_DIR ?? path.resolve(process.cwd(), ".agentic-browser"),
|
|
1143
|
-
browserExecutablePath: env.AGENTIC_BROWSER_CHROME_PATH
|
|
1186
|
+
browserExecutablePath: env.AGENTIC_BROWSER_CHROME_PATH,
|
|
1187
|
+
cdpUrl: env.AGENTIC_BROWSER_CDP_URL,
|
|
1188
|
+
userProfileDir
|
|
1144
1189
|
};
|
|
1145
1190
|
}
|
|
1146
1191
|
|