pi-browser-use 0.11.0 → 0.11.1

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.
Files changed (55) hide show
  1. package/dist/annotate.d.ts +0 -14
  2. package/dist/annotate.js +0 -14
  3. package/dist/artifacts.d.ts +0 -2
  4. package/dist/artifacts.js +0 -2
  5. package/dist/auth-verifiers.d.ts +0 -29
  6. package/dist/auth-verifiers.js +0 -31
  7. package/dist/chrome-launcher.d.ts +0 -59
  8. package/dist/chrome-launcher.js +0 -54
  9. package/dist/client.d.ts +0 -4
  10. package/dist/client.js +0 -17
  11. package/dist/config.d.ts +0 -25
  12. package/dist/config.js +0 -23
  13. package/dist/doctor.d.ts +0 -8
  14. package/dist/doctor.js +0 -5
  15. package/dist/existing-flow.d.ts +0 -31
  16. package/dist/existing-flow.js +0 -29
  17. package/dist/focus-policy.d.ts +0 -13
  18. package/dist/focus-policy.js +0 -13
  19. package/dist/index.d.ts +0 -1
  20. package/dist/index.js +0 -1
  21. package/dist/mcp-server.d.ts +0 -2
  22. package/dist/mcp-server.js +0 -10
  23. package/dist/named-profile.d.ts +0 -36
  24. package/dist/named-profile.js +0 -37
  25. package/dist/persistent-backend.d.ts +2 -56
  26. package/dist/persistent-backend.js +30 -65
  27. package/dist/persistent-store.d.ts +0 -24
  28. package/dist/persistent-store.js +0 -24
  29. package/dist/profile-lock.d.ts +0 -21
  30. package/dist/profile-lock.js +0 -27
  31. package/dist/profile.d.ts +0 -10
  32. package/dist/profile.js +0 -14
  33. package/dist/runtime.d.ts +0 -3
  34. package/dist/runtime.js +3 -92
  35. package/dist/session-manager.d.ts +0 -48
  36. package/dist/session-manager.js +0 -46
  37. package/dist/session.d.ts +0 -42
  38. package/dist/session.js +0 -18
  39. package/dist/settings.d.ts +0 -5
  40. package/dist/settings.js +0 -5
  41. package/dist/setup-flow.d.ts +0 -41
  42. package/dist/setup-flow.js +0 -37
  43. package/dist/shared-backend.d.ts +0 -30
  44. package/dist/shared-backend.js +0 -31
  45. package/dist/tab-bridge.d.ts +0 -27
  46. package/dist/tab-bridge.js +0 -27
  47. package/dist/tool-augment.d.ts +0 -9
  48. package/dist/tool-augment.js +0 -14
  49. package/dist/vision.d.ts +0 -17
  50. package/dist/vision.js +0 -17
  51. package/docs/performance.md +2 -0
  52. package/extension/README.md +2 -0
  53. package/extension/background.js +4 -9
  54. package/package.json +1 -1
  55. package/plugin.json +1 -1
@@ -1,27 +1,3 @@
1
- /**
2
- * Pi-owned Persistent Chrome backend (spec sections 2 and 4).
3
- *
4
- * Normal automation launches Chrome directly with the Pi profile and an
5
- * ephemeral loopback remote-debugging port, then MCP attaches via
6
- * `--browser-url` — instead of asking MCP/Puppeteer to create the browser:
7
- *
8
- * ```text
9
- * Google Chrome --user-data-dir="<pi-profile>"
10
- * --remote-debugging-port=<ephemeral> [--headless]
11
- * ↕
12
- * chrome-devtools-mcp --browser-url=http://127.0.0.1:<port>
13
- * ```
14
- *
15
- * Invariants:
16
- * - one Chrome process <-> one persistent profile (profile lock held for the
17
- * whole backend lifetime, acquired on start, released on stop);
18
- * - dynamically allocated localhost port, never hardcoded 9222;
19
- * - clean shutdown (SIGTERM, then SIGKILL) before any relaunch, so headed and
20
- * headless instances never overlap on the same user-data-dir.
21
- *
22
- * The launcher and MCP-client factory are injectable so the lifecycle is
23
- * unit-testable without a real Chrome.
24
- */
25
1
  import { findManagedChromePids, launchChrome, } from './chrome-launcher.js';
26
2
  import { execFileSync } from 'node:child_process';
27
3
  import { ensureNamedProfile, PI_PROFILE_NAME } from './named-profile.js';
@@ -46,7 +22,6 @@ export class PersistentBackend {
46
22
  this.attachClient = options.attachClient;
47
23
  this.sessionId = options.sessionId ?? newSessionId();
48
24
  }
49
- /** True when this session owns the Chrome process (may restart it). */
50
25
  get owned() {
51
26
  return this.sharedAdvert === undefined;
52
27
  }
@@ -64,15 +39,34 @@ export class PersistentBackend {
64
39
  attached() {
65
40
  return this.client;
66
41
  }
67
- /** OS pid of the owned Chrome process, for explicit user-facing fronting. */
68
42
  pid() {
69
43
  return this.chrome?.pid;
70
44
  }
71
- /**
72
- * Kill leftover Pi-managed Chromes on this profile (crashed sessions).
73
- * Only processes carrying our managed flags; skips our own pid and
74
- * manually opened windows. Injectable runner for tests.
75
- */
45
+ onChromeExit(chrome) {
46
+ if (this.chrome !== chrome)
47
+ return;
48
+ this.chrome = undefined;
49
+ const lock = this.lock;
50
+ this.lock = undefined;
51
+ try {
52
+ lock?.release();
53
+ }
54
+ catch {
55
+ }
56
+ withdrawAdvert(this.profileDir(), this.sessionId);
57
+ const client = this.client;
58
+ this.client = undefined;
59
+ if (client)
60
+ void client.close().catch(() => { });
61
+ }
62
+ watchChrome(chrome) {
63
+ try {
64
+ void chrome.waitForExit().then(() => this.onChromeExit(chrome), () => this.onChromeExit(chrome));
65
+ }
66
+ catch {
67
+ this.onChromeExit(chrome);
68
+ }
69
+ }
76
70
  reapOrphans(profileDir, runner) {
77
71
  const run = runner ?? {
78
72
  ps: () => {
@@ -88,7 +82,6 @@ export class PersistentBackend {
88
82
  process.kill(pid, 'SIGTERM');
89
83
  }
90
84
  catch {
91
- // Already gone; the endpoint check below confirms.
92
85
  }
93
86
  },
94
87
  };
@@ -106,17 +99,13 @@ export class PersistentBackend {
106
99
  reaped.push(pid);
107
100
  }
108
101
  catch {
109
- // One stubborn process must not block the launch.
110
102
  }
111
103
  }
112
104
  return reaped;
113
105
  }
114
- /**
115
- * Start Pi-owned Chrome and prepare the MCP attach config. When an
116
- * `attachClient` factory was injected, the client is created here;
117
- * otherwise the caller builds its DevToolsClient from `attachConfig()`.
118
- */
119
106
  async start(signal) {
107
+ if (this.chrome?.exited)
108
+ this.onChromeExit(this.chrome);
120
109
  if (this.running())
121
110
  return this.attachConfig();
122
111
  if (signal?.aborted)
@@ -126,8 +115,6 @@ export class PersistentBackend {
126
115
  this.lock = this.acquireLock(profileDir);
127
116
  }
128
117
  catch (error) {
129
- // A live peer owns Chrome: share it instead of failing. No lock, no
130
- // kill rights — this session only borrows pages.
131
118
  if (error instanceof ProfileLockedError) {
132
119
  const advert = readLiveAdvert(profileDir);
133
120
  if (advert) {
@@ -141,20 +128,14 @@ export class PersistentBackend {
141
128
  throw error;
142
129
  }
143
130
  try {
144
- // Self-healing: reap Pi-managed orphans from crashed sessions before
145
- // launching (same user-data-dir + debugging flags, never our pid,
146
- // never a manually opened window). Best effort, never fatal.
147
131
  const reaped = this.reapOrphans(profileDir);
148
132
  if (reaped.length > 0) {
149
133
  await new Promise((resolve) => setTimeout(resolve, 2000));
150
134
  }
151
135
  prepareBrowserProfile({ ...this.options.config, userDataDir: profileDir });
152
- // Pin the named Pi profile; migrate legacy layouts once, under lock.
153
136
  ensureNamedProfile(profileDir);
154
- // Explicit headed wins; otherwise infer from config (headless:false
155
- // means headed) so direct construction can't silently go headless.
156
137
  const headed = this.options.headed ?? this.options.config.headless === false;
157
- this.chrome = await this.launch({
138
+ const chrome = await this.launch({
158
139
  userDataDir: profileDir,
159
140
  profileDirectory: PI_PROFILE_NAME,
160
141
  headless: !headed,
@@ -162,6 +143,8 @@ export class PersistentBackend {
162
143
  executablePath: this.options.config.executablePath,
163
144
  signal,
164
145
  });
146
+ this.chrome = chrome;
147
+ this.watchChrome(chrome);
165
148
  }
166
149
  catch (error) {
167
150
  this.lock.release();
@@ -184,7 +167,6 @@ export class PersistentBackend {
184
167
  this.client = this.attachClient(attach);
185
168
  return attach;
186
169
  }
187
- /** Effective browser URL: owned Chrome or the shared peer's. */
188
170
  effectiveBrowserUrl() {
189
171
  if (this.chrome)
190
172
  return this.chrome.browserUrl;
@@ -192,11 +174,6 @@ export class PersistentBackend {
192
174
  return this.sharedAdvert.browserUrl;
193
175
  throw new Error('Persistent backend is not running.');
194
176
  }
195
- /**
196
- * MCP attach config: same session options, but pointed at Pi-owned Chrome
197
- * (or the shared peer's). `userDataDir`/`isolated` are stripped — MCP
198
- * must attach, not launch.
199
- */
200
177
  attachConfig() {
201
178
  const browserUrl = this.effectiveBrowserUrl();
202
179
  const { userDataDir: _userDataDir, isolated: _isolated, executablePath: _executablePath, channel: _channel, chromeArgs: _chromeArgs, ...rest } = this.options.config;
@@ -205,8 +182,6 @@ export class PersistentBackend {
205
182
  void _executablePath;
206
183
  void _channel;
207
184
  void _chromeArgs;
208
- // We already launched Chrome with these options. Upstream rejects an
209
- // executable/channel combined with browserUrl; attach must not relaunch.
210
185
  return { ...rest, browserUrl, isolated: false };
211
186
  }
212
187
  running() {
@@ -214,11 +189,6 @@ export class PersistentBackend {
214
189
  return true;
215
190
  return this.chrome !== undefined && !this.chrome.exited;
216
191
  }
217
- /**
218
- * Clean shutdown. Owned: close client, quit Chrome, release lock,
219
- * withdraw advert. Shared: close only our own MCP client — never touch
220
- * the peer's browser.
221
- */
222
192
  async stop() {
223
193
  const errors = [];
224
194
  if (this.client) {
@@ -262,7 +232,6 @@ export class PersistentBackend {
262
232
  .join('; ')}`);
263
233
  }
264
234
  }
265
- /** Restart into the other visibility (headless <-> headed fallback). */
266
235
  async restart(headed, signal) {
267
236
  if (this.sharedAdvert) {
268
237
  throw new Error('Cannot restart a shared peer backend (owned by another live session). ' +
@@ -273,10 +242,6 @@ export class PersistentBackend {
273
242
  return this.start(signal);
274
243
  }
275
244
  }
276
- /**
277
- * Persistent mode self-launches Pi-owned Chrome (§4) unless the legacy
278
- * escape hatch is set (MCP launches Chrome itself, pre-Phase-2 behavior).
279
- */
280
245
  export function shouldSelfLaunch(config) {
281
246
  if (process.env['PI_BROWSER_USE_LEGACY_PERSISTENT'] === '1')
282
247
  return false;
@@ -1,35 +1,11 @@
1
- /**
2
- * Durable Persistent-mode metadata (spec section 2).
3
- *
4
- * Only durable state is persisted: initialization flag, profile path, last
5
- * working launch mode, and last bootstrap timestamp. Passwords, cookies,
6
- * tokens, or copied browser credentials must never be stored here — Chrome
7
- * owns those inside its profile directory.
8
- *
9
- * Default location is a sibling of the profile directory:
10
- * `<profileDir>.meta.json` (e.g. `~/.pi/browser-profile.meta.json`), so a
11
- * profile move/rename never orphans its metadata.
12
- */
13
1
  import type { PersistentBrowserMetadata, SiteBrowserPreference } from './session.js';
14
2
  export declare function metadataPathFor(profileDir?: string): string;
15
3
  export declare function defaultMetadata(profileDir?: string): PersistentBrowserMetadata;
16
- /** Load metadata; returns uninitialized defaults when absent or corrupt. */
17
4
  export declare function loadPersistentMetadata(profileDir?: string): PersistentBrowserMetadata;
18
- /** Atomically persist metadata (write-then-rename via temp file). */
19
5
  export declare function savePersistentMetadata(meta: PersistentBrowserMetadata): void;
20
- /** Record a completed bootstrap: initialized now, timestamped. */
21
6
  export declare function markBootstrapped(profileDir?: string, at?: string): PersistentBrowserMetadata;
22
- /** Record which launch mode last automated successfully. */
23
7
  export declare function markAutomationResult(profileDir: string, mode: 'headless' | 'headed'): PersistentBrowserMetadata;
24
- /**
25
- * Per-origin headed-background preferences (spec section 8). Stored beside
26
- * the metadata file (`<profileDir>.sites.json`); origins only, never
27
- * credentials. A site pinned here starts headed-background instead of
28
- * globally downgrading Persistent because one site rejects headless.
29
- */
30
8
  export declare function sitePreferencesPathFor(profileDir?: string): string;
31
- /** Load per-origin preferences; empty when absent or corrupt. */
32
9
  export declare function loadSitePreferences(profileDir?: string): SiteBrowserPreference[];
33
- /** Persist per-origin preferences. */
34
10
  export declare function saveSitePreferences(profileDir: string, preferences: SiteBrowserPreference[]): void;
35
11
  //# sourceMappingURL=persistent-store.d.ts.map
@@ -1,15 +1,3 @@
1
- /**
2
- * Durable Persistent-mode metadata (spec section 2).
3
- *
4
- * Only durable state is persisted: initialization flag, profile path, last
5
- * working launch mode, and last bootstrap timestamp. Passwords, cookies,
6
- * tokens, or copied browser credentials must never be stored here — Chrome
7
- * owns those inside its profile directory.
8
- *
9
- * Default location is a sibling of the profile directory:
10
- * `<profileDir>.meta.json` (e.g. `~/.pi/browser-profile.meta.json`), so a
11
- * profile move/rename never orphans its metadata.
12
- */
13
1
  import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
14
2
  import { dirname } from 'node:path';
15
3
  import { DEFAULT_PROFILE_DIR } from './config.js';
@@ -19,7 +7,6 @@ export function metadataPathFor(profileDir = DEFAULT_PROFILE_DIR) {
19
7
  export function defaultMetadata(profileDir = DEFAULT_PROFILE_DIR) {
20
8
  return { initialized: false, profilePath: profileDir };
21
9
  }
22
- /** Load metadata; returns uninitialized defaults when absent or corrupt. */
23
10
  export function loadPersistentMetadata(profileDir = DEFAULT_PROFILE_DIR) {
24
11
  const path = metadataPathFor(profileDir);
25
12
  try {
@@ -37,13 +24,11 @@ export function loadPersistentMetadata(profileDir = DEFAULT_PROFILE_DIR) {
37
24
  return defaultMetadata(profileDir);
38
25
  }
39
26
  }
40
- /** Atomically persist metadata (write-then-rename via temp file). */
41
27
  export function savePersistentMetadata(meta) {
42
28
  const path = metadataPathFor(meta.profilePath);
43
29
  mkdirSync(dirname(path), { recursive: true });
44
30
  writeFileSync(path, `${JSON.stringify(meta, null, 2)}\n`, 'utf8');
45
31
  }
46
- /** Record a completed bootstrap: initialized now, timestamped. */
47
32
  export function markBootstrapped(profileDir = DEFAULT_PROFILE_DIR, at = new Date().toISOString()) {
48
33
  const meta = {
49
34
  ...loadPersistentMetadata(profileDir),
@@ -54,7 +39,6 @@ export function markBootstrapped(profileDir = DEFAULT_PROFILE_DIR, at = new Date
54
39
  savePersistentMetadata(meta);
55
40
  return meta;
56
41
  }
57
- /** Record which launch mode last automated successfully. */
58
42
  export function markAutomationResult(profileDir, mode) {
59
43
  const meta = {
60
44
  ...loadPersistentMetadata(profileDir),
@@ -64,16 +48,9 @@ export function markAutomationResult(profileDir, mode) {
64
48
  savePersistentMetadata(meta);
65
49
  return meta;
66
50
  }
67
- /**
68
- * Per-origin headed-background preferences (spec section 8). Stored beside
69
- * the metadata file (`<profileDir>.sites.json`); origins only, never
70
- * credentials. A site pinned here starts headed-background instead of
71
- * globally downgrading Persistent because one site rejects headless.
72
- */
73
51
  export function sitePreferencesPathFor(profileDir = DEFAULT_PROFILE_DIR) {
74
52
  return `${profileDir}.sites.json`;
75
53
  }
76
- /** Load per-origin preferences; empty when absent or corrupt. */
77
54
  export function loadSitePreferences(profileDir = DEFAULT_PROFILE_DIR) {
78
55
  try {
79
56
  const raw = JSON.parse(readFileSync(sitePreferencesPathFor(profileDir), 'utf8'));
@@ -89,7 +66,6 @@ export function loadSitePreferences(profileDir = DEFAULT_PROFILE_DIR) {
89
66
  return [];
90
67
  }
91
68
  }
92
- /** Persist per-origin preferences. */
93
69
  export function saveSitePreferences(profileDir, preferences) {
94
70
  const path = sitePreferencesPathFor(profileDir);
95
71
  mkdirSync(dirname(path), { recursive: true });
@@ -1,17 +1,3 @@
1
- /**
2
- * Single-process guard for a Chrome user-data directory (spec section 4).
3
- *
4
- * Chrome corrupts state when two processes share one user-data-dir, so every
5
- * Pi-owned launch/shutdown path must hold this lock:
6
- *
7
- * ```text
8
- * one Chrome process <-> one persistent profile
9
- * ```
10
- *
11
- * Implemented as a sibling `<profileDir>.lock` file holding `{ pid,
12
- * createdAt }`. Stale locks (dead pid or age beyond `staleMs`) are reclaimed;
13
- * live locks throw {@link ProfileLockedError}.
14
- */
15
1
  export declare class ProfileLockedError extends Error {
16
2
  readonly profileDir: string;
17
3
  readonly holderPid?: number;
@@ -25,16 +11,9 @@ export interface ProfileLockHandle {
25
11
  }
26
12
  export declare function lockPathFor(profileDir: string): string;
27
13
  export interface AcquireLockOptions {
28
- /** Locks older than this with a dead holder are reclaimed. Default 5 min. */
29
14
  staleMs?: number;
30
15
  }
31
- /**
32
- * Acquire the exclusive lock for `profileDir`. Throws ProfileLockedError when
33
- * a live Chrome (or another Pi process) holds it.
34
- */
35
16
  export declare function acquireProfileLock(profileDir: string, options?: AcquireLockOptions): ProfileLockHandle;
36
- /** True when a live holder currently owns the profile lock. */
37
17
  export declare function isProfileLocked(profileDir: string): boolean;
38
- /** Run `fn` while holding the profile lock, always releasing afterwards. */
39
18
  export declare function withProfileLock<T>(profileDir: string, fn: (lock: ProfileLockHandle) => Promise<T>, options?: AcquireLockOptions): Promise<T>;
40
19
  //# sourceMappingURL=profile-lock.d.ts.map
@@ -1,17 +1,3 @@
1
- /**
2
- * Single-process guard for a Chrome user-data directory (spec section 4).
3
- *
4
- * Chrome corrupts state when two processes share one user-data-dir, so every
5
- * Pi-owned launch/shutdown path must hold this lock:
6
- *
7
- * ```text
8
- * one Chrome process <-> one persistent profile
9
- * ```
10
- *
11
- * Implemented as a sibling `<profileDir>.lock` file holding `{ pid,
12
- * createdAt }`. Stale locks (dead pid or age beyond `staleMs`) are reclaimed;
13
- * live locks throw {@link ProfileLockedError}.
14
- */
15
1
  import { closeSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
16
2
  import { dirname } from 'node:path';
17
3
  export class ProfileLockedError extends Error {
@@ -77,24 +63,17 @@ function tryCreateLockFile(lockPath) {
77
63
  closeSync(fd);
78
64
  }
79
65
  catch {
80
- // Best effort; the lock content is already written.
81
66
  }
82
67
  }
83
68
  }
84
69
  }
85
- /**
86
- * Acquire the exclusive lock for `profileDir`. Throws ProfileLockedError when
87
- * a live Chrome (or another Pi process) holds it.
88
- */
89
70
  export function acquireProfileLock(profileDir, options) {
90
71
  const staleMs = options?.staleMs ?? 5 * 60 * 1000;
91
72
  const lockPath = lockPathFor(profileDir);
92
- // Ensure the parent exists so the sibling lock file can be created.
93
73
  try {
94
74
  mkdirSync(dirname(lockPath), { recursive: true });
95
75
  }
96
76
  catch {
97
- // Parent creation failure surfaces on lock creation below.
98
77
  }
99
78
  if (tryCreateLockFile(lockPath)) {
100
79
  return makeHandle(profileDir, lockPath);
@@ -108,7 +87,6 @@ export function acquireProfileLock(profileDir, options) {
108
87
  rmSync(lockPath, { force: true });
109
88
  }
110
89
  catch {
111
- // Fall through to the error below if removal failed.
112
90
  }
113
91
  if (tryCreateLockFile(lockPath)) {
114
92
  return makeHandle(profileDir, lockPath);
@@ -129,19 +107,15 @@ function makeHandle(profileDir, lockPath) {
129
107
  rmSync(lockPath, { force: true });
130
108
  }
131
109
  catch {
132
- // Lock files are best-effort on shutdown.
133
110
  }
134
111
  },
135
112
  };
136
113
  return handle;
137
114
  }
138
- /** True when a live holder currently owns the profile lock. */
139
115
  export function isProfileLocked(profileDir) {
140
116
  const lockPath = lockPathFor(profileDir);
141
117
  const holderPid = readLockPid(lockPath);
142
118
  if (holderPid === undefined) {
143
- // Unparseable/missing lock file: treat a present file as locked to stay
144
- // safe, absent as unlocked.
145
119
  try {
146
120
  readFileSync(lockPath);
147
121
  return true;
@@ -152,7 +126,6 @@ export function isProfileLocked(profileDir) {
152
126
  }
153
127
  return isPidAlive(holderPid);
154
128
  }
155
- /** Run `fn` while holding the profile lock, always releasing afterwards. */
156
129
  export async function withProfileLock(profileDir, fn, options) {
157
130
  const lock = acquireProfileLock(profileDir, options);
158
131
  try {
package/dist/profile.d.ts CHANGED
@@ -1,13 +1,3 @@
1
1
  import { type BrowserUseConfig } from './config.js';
2
- /**
3
- * Guard the browser profile before launch. A default profile that exists but
4
- * cannot be read/written (typically root-owned after running under sudo) is
5
- * moved aside so Chrome starts fresh instead of showing a "can't read your
6
- * preferences" dialog on every launch. An explicit custom userDataDir in the
7
- * same state fails fast with a remediation hint instead of silently
8
- * discarding the user's data. Persistent launches additionally pin the named
9
- * `pi-browser-use` profile (one-time legacy migration, refuses while an
10
- * external Chrome holds the root).
11
- */
12
2
  export declare function prepareBrowserProfile(config: BrowserUseConfig): void;
13
3
  //# sourceMappingURL=profile.d.ts.map
package/dist/profile.js CHANGED
@@ -20,21 +20,9 @@ function isUnusableDir(path) {
20
20
  return false;
21
21
  }
22
22
  catch (error) {
23
- // A missing directory is fine (Chrome creates it); anything else means
24
- // the profile cannot be used.
25
23
  return error.code !== 'ENOENT';
26
24
  }
27
25
  }
28
- /**
29
- * Guard the browser profile before launch. A default profile that exists but
30
- * cannot be read/written (typically root-owned after running under sudo) is
31
- * moved aside so Chrome starts fresh instead of showing a "can't read your
32
- * preferences" dialog on every launch. An explicit custom userDataDir in the
33
- * same state fails fast with a remediation hint instead of silently
34
- * discarding the user's data. Persistent launches additionally pin the named
35
- * `pi-browser-use` profile (one-time legacy migration, refuses while an
36
- * external Chrome holds the root).
37
- */
38
26
  export function prepareBrowserProfile(config) {
39
27
  if (config.browserUrl || config.wsEndpoint || config.autoConnect)
40
28
  return;
@@ -58,8 +46,6 @@ export function prepareBrowserProfile(config) {
58
46
  `Fix ownership with: sudo chown -R $(id -un):$(id -gn) ${JSON.stringify(dir)}`);
59
47
  }
60
48
  }
61
- // Pin the named Pi profile for persistent launches (fresh migrations
62
- // happen here, under no running Chrome by construction of the callers).
63
49
  if (config.sessionMode === 'persistent') {
64
50
  ensureNamedProfile(dir);
65
51
  }
package/dist/runtime.d.ts CHANGED
@@ -11,7 +11,6 @@ type UpstreamResult = {
11
11
  }>;
12
12
  isError?: boolean;
13
13
  };
14
- /** Host-independent tool contract; Pi and MCP adapt only at their boundaries. */
15
14
  export type VisionCaller = Parameters<typeof handleAnalyzeScreenshot>[1];
16
15
  export interface BrowserToolContext {
17
16
  callVision?: VisionCaller;
@@ -30,12 +29,10 @@ export interface BrowserRuntimeOptions {
30
29
  defaultProfileDir?: string;
31
30
  artifactDir?: string;
32
31
  visionEnabled?: boolean;
33
- /** Discover tools without launching Chrome. Native Pi keeps eager startup. */
34
32
  lazyBrowser?: boolean;
35
33
  createClient?: (config: BrowserUseConfig) => BrowserClient;
36
34
  createBackend?: (options: PersistentBackendOptions) => BrowserBackend;
37
35
  }
38
- /** Shared browser lifecycle, policy, tools, and ownership. No Pi host is required. */
39
36
  export declare function createBrowserRuntime(options?: BrowserRuntimeOptions): {
40
37
  start: () => Promise<BrowserToolDefinition[]>;
41
38
  stop: () => Promise<void>;