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. Commands execute via CDP `Runtime.evaluate` on the browser page
63
- 3. Results are recorded as evidence, indexed per-domain for memory search
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
@@ -1,4 +1,5 @@
1
- import { r as createCliRuntime } from "../runtime-C-oYEtN0.mjs";
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-CULSgM_M.mjs");
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
- import { i as createMockAgenticBrowserCore, n as createAgenticBrowserCore, t as AgenticBrowserCore } from "./runtime-C-oYEtN0.mjs";
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 };
@@ -1,4 +1,5 @@
1
- import { n as createAgenticBrowserCore } from "../runtime-C-oYEtN0.mjs";
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
- const profileDir = path.join(this.baseDir, "profiles", sessionId);
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
 
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env node
1
2
  import fs from "node:fs";
2
3
  import path from "node:path";
3
4
  import readline from "node:readline/promises";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-browser",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",