@btraut/browser-bridge 0.10.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.
package/CHANGELOG.md CHANGED
@@ -6,12 +6,34 @@ The format is based on "Keep a Changelog", and this project adheres to Semantic
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.11.1] - 2026-02-16
10
+
11
+ ### Fixed
12
+
13
+ - Extension: dedicated agent windows now bootstrap with an extension-owned `agent-tab.html` page so the tab consistently shows the `Browser Bridge` title and robot favicon (instead of blank/new-tab styling).
14
+
15
+ ## [0.11.0] - 2026-02-16
16
+
17
+ ### Changed
18
+
19
+ - Runtime routing now defaults to single-instance mode on `127.0.0.1:3210`; deterministic per-worktree ports are used only in explicit isolated mode.
20
+ - Core startup now probes fallback ports only in isolated mode and preserves existing runtime metadata fields (including `extension_id`) when persisting host/port updates.
21
+ - `browser-bridge dev activate` is now explicitly an isolated-worktree workflow command and persists `isolated_mode: true` in runtime metadata.
22
+
23
+ ### Fixed
24
+
25
+ - Eliminated normal-workflow extension disconnects caused by hidden default port drift between Core/CLI and extension routing.
26
+
9
27
  ## [0.10.0] - 2026-02-15
10
28
 
11
29
  ### Added
12
30
 
13
31
  - CLI: support `-v` as a short alias for `--version`, with the value resolved from the installed package metadata.
14
32
 
33
+ ### Fixed
34
+
35
+ - README: switch the header image to an absolute GitHub URL so it renders correctly on npm package pages.
36
+
15
37
  ## [0.9.0] - 2026-02-15
16
38
 
17
39
  ### Fixed
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- <img src="docs/assets/readme-header.png" alt="Browser Bridge header graphic" width="720" />
1
+ <img src="https://raw.githubusercontent.com/btraut/browser-bridge/main/docs/assets/readme-header.png" alt="Browser Bridge header graphic" width="720" />
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@btraut/browser-bridge.svg)](https://www.npmjs.com/package/@btraut/browser-bridge) [![npm downloads](https://img.shields.io/npm/dm/@btraut/browser-bridge.svg)](https://www.npmjs.com/package/@btraut/browser-bridge) [![CI](https://github.com/btraut/browser-bridge/actions/workflows/ci.yml/badge.svg)](https://github.com/btraut/browser-bridge/actions/workflows/ci.yml) [![License](https://img.shields.io/github/license/btraut/browser-bridge.svg)](LICENSE)
4
4
 
@@ -260,9 +260,23 @@ claude mcp add --transport stdio browser-bridge \
260
260
 
261
261
  </details>
262
262
 
263
- ## 🔁 Multi-Worktree Dev Loop
263
+ ## Default Runtime (Normal Usage)
264
264
 
265
- Use this loop any time you switch worktrees.
265
+ For normal usage, Browser Bridge is zero-setup:
266
+
267
+ - Core and CLI default to `127.0.0.1:3210`.
268
+ - The extension also defaults to `3210`.
269
+ - You do not need `dev activate` unless you intentionally opt into isolated worktree routing.
270
+
271
+ Optional status check:
272
+
273
+ ```bash
274
+ browser-bridge dev info --json
275
+ ```
276
+
277
+ ## 🔁 Isolated Multi-Worktree Dev Loop (Advanced)
278
+
279
+ Use this loop when you intentionally run multiple worktree instances in parallel.
266
280
 
267
281
  1. Resolve runtime for the current worktree:
268
282
 
@@ -272,7 +286,7 @@ browser-bridge dev info --json
272
286
 
273
287
  Use the `port`, `worktreeId`, `metadataPath`, and `logDir` from output.
274
288
 
275
- 2. Activate extension routing for this worktree (required for extension-driving tasks):
289
+ 2. Activate isolated extension routing for this worktree:
276
290
 
277
291
  ```bash
278
292
  browser-bridge dev activate --extension-id <id>
@@ -295,7 +309,7 @@ tail -n 80 .context/logs/browser-bridge/core.jsonl
295
309
  tail -n 80 .context/logs/browser-bridge/mcp-adapter.jsonl
296
310
  ```
297
311
 
298
- - Do not assume port `3210` across worktrees: Default port is deterministic per worktree and may differ. Always check `browser-bridge dev info` (or pass explicit `--port` / `BROWSER_BRIDGE_CORE_PORT`).
312
+ - Default mode port is `3210`. In isolated mode, port is worktree-specific. Use `browser-bridge dev info` if you are unsure (or pass explicit `--port` / `BROWSER_BRIDGE_CORE_PORT`).
299
313
 
300
314
  ## 🩺 Diagnostics
301
315
 
package/dist/api.js CHANGED
@@ -103,6 +103,8 @@ var ENV_CORE_HOST = "BROWSER_BRIDGE_CORE_HOST";
103
103
  var ENV_VISION_HOST = "BROWSER_VISION_CORE_HOST";
104
104
  var ENV_CORE_PORT = "BROWSER_BRIDGE_CORE_PORT";
105
105
  var ENV_VISION_PORT = "BROWSER_VISION_CORE_PORT";
106
+ var ENV_ISOLATED_MODE = "BROWSER_BRIDGE_ISOLATED_MODE";
107
+ var ENV_VISION_ISOLATED_MODE = "BROWSER_VISION_ISOLATED_MODE";
106
108
  var RUNTIME_METADATA_RELATIVE_PATH = ".context/browser-bridge/dev.json";
107
109
  var DEFAULT_LOG_DIRECTORY_RELATIVE_PATH = ".context/logs/browser-bridge";
108
110
  var resolveCwd = (cwd) => (0, import_node_path.resolve)(cwd ?? process.cwd());
@@ -119,6 +121,22 @@ var normalizeHost = (value) => {
119
121
  const trimmed = value.trim();
120
122
  return trimmed.length > 0 ? trimmed : void 0;
121
123
  };
124
+ var parseBoolean = (value) => {
125
+ if (typeof value === "boolean") {
126
+ return value;
127
+ }
128
+ if (typeof value !== "string") {
129
+ return void 0;
130
+ }
131
+ const normalized = value.trim().toLowerCase();
132
+ if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
133
+ return true;
134
+ }
135
+ if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
136
+ return false;
137
+ }
138
+ return void 0;
139
+ };
122
140
  var parsePort = (value, label, invalidPolicy) => {
123
141
  if (value === void 0 || value === null) {
124
142
  return void 0;
@@ -202,6 +220,13 @@ var resolveEnvPortRaw = (env) => {
202
220
  }
203
221
  return env[ENV_VISION_PORT];
204
222
  };
223
+ var resolveEnvIsolatedMode = (env) => {
224
+ const bridge = parseBoolean(env[ENV_ISOLATED_MODE]);
225
+ if (bridge !== void 0) {
226
+ return bridge;
227
+ }
228
+ return parseBoolean(env[ENV_VISION_ISOLATED_MODE]);
229
+ };
205
230
  var sanitizeMetadata = (raw) => {
206
231
  if (!raw || typeof raw !== "object") {
207
232
  return null;
@@ -212,8 +237,9 @@ var sanitizeMetadata = (raw) => {
212
237
  const gitRoot = normalizeHost(candidate.git_root);
213
238
  const worktreeId = normalizeHost(candidate.worktree_id);
214
239
  const extensionId = normalizeHost(candidate.extension_id);
240
+ const isolatedMode = parseBoolean(candidate.isolated_mode);
215
241
  const updatedAt = normalizeHost(candidate.updated_at);
216
- if (!host && port === void 0 && !gitRoot && !worktreeId && !extensionId && !updatedAt) {
242
+ if (!host && port === void 0 && !gitRoot && !worktreeId && !extensionId && isolatedMode === void 0 && !updatedAt) {
217
243
  return null;
218
244
  }
219
245
  return {
@@ -222,6 +248,7 @@ var sanitizeMetadata = (raw) => {
222
248
  git_root: gitRoot,
223
249
  worktree_id: worktreeId,
224
250
  extension_id: extensionId,
251
+ isolated_mode: isolatedMode,
225
252
  updated_at: updatedAt
226
253
  };
227
254
  };
@@ -367,6 +394,11 @@ var resolveCoreRuntime = (options = {}) => {
367
394
  options.strictEnvPort ? "throw" : "ignore"
368
395
  );
369
396
  const metadataPort = parsePort(metadata?.port, "port", "ignore");
397
+ const optionIsolatedMode = options.isolatedMode;
398
+ const envIsolatedMode = resolveEnvIsolatedMode(env);
399
+ const metadataIsolatedMode = metadata?.isolated_mode;
400
+ const isolatedMode = optionIsolatedMode ?? envIsolatedMode ?? metadataIsolatedMode ?? false;
401
+ const isolatedModeSource = optionIsolatedMode !== void 0 ? "option" : envIsolatedMode !== void 0 ? "env" : metadataIsolatedMode !== void 0 ? "metadata" : "default";
370
402
  let port;
371
403
  let portSource;
372
404
  if (optionPort !== void 0) {
@@ -375,12 +407,15 @@ var resolveCoreRuntime = (options = {}) => {
375
407
  } else if (envPort !== void 0) {
376
408
  port = envPort;
377
409
  portSource = "env";
378
- } else if (metadataPort !== void 0) {
410
+ } else if (metadataPort !== void 0 && isolatedMode) {
379
411
  port = metadataPort;
380
412
  portSource = "metadata";
381
- } else {
413
+ } else if (isolatedMode) {
382
414
  port = deterministicPort;
383
415
  portSource = "deterministic";
416
+ } else {
417
+ port = LEGACY_DEFAULT_PORT;
418
+ portSource = "default";
384
419
  }
385
420
  return {
386
421
  host,
@@ -391,7 +426,9 @@ var resolveCoreRuntime = (options = {}) => {
391
426
  metadata,
392
427
  gitRoot,
393
428
  worktreeId: resolveWorktreeId({ cwd: resolvedCwd, gitRoot }),
394
- deterministicPort
429
+ deterministicPort,
430
+ isolatedMode,
431
+ isolatedModeSource
395
432
  };
396
433
  };
397
434
 
@@ -5086,6 +5123,26 @@ var createCoreServer = (options = {}) => {
5086
5123
  };
5087
5124
  };
5088
5125
  var CORE_PORT_PROBE_ATTEMPTS = 20;
5126
+ var buildRuntimeMetadataForPersist = (runtime, resolvedPort) => ({
5127
+ ...runtime.metadata ?? {},
5128
+ host: runtime.host,
5129
+ port: resolvedPort,
5130
+ git_root: runtime.gitRoot ?? runtime.metadata?.git_root,
5131
+ worktree_id: runtime.worktreeId ?? runtime.metadata?.worktree_id,
5132
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
5133
+ });
5134
+ var resolveProbePortsForRuntime = (runtime) => {
5135
+ if (!runtime.isolatedMode) {
5136
+ return [runtime.port];
5137
+ }
5138
+ if (runtime.portSource === "metadata" || runtime.portSource === "deterministic") {
5139
+ return createBoundedPortProbeSequence(
5140
+ runtime.port,
5141
+ CORE_PORT_PROBE_ATTEMPTS
5142
+ );
5143
+ }
5144
+ return [runtime.port];
5145
+ };
5089
5146
  var resolveSessionTtlMs = () => {
5090
5147
  const env = process.env.BROWSER_BRIDGE_SESSION_TTL_MS || process.env.BROWSER_VISION_SESSION_TTL_MS;
5091
5148
  if (env) {
@@ -5175,7 +5232,7 @@ var startCoreServer = async (options = {}) => {
5175
5232
  registry: options.registry,
5176
5233
  logger
5177
5234
  });
5178
- const probePorts = runtime.portSource === "metadata" || runtime.portSource === "deterministic" ? createBoundedPortProbeSequence(runtime.port, CORE_PORT_PROBE_ATTEMPTS) : [runtime.port];
5235
+ const probePorts = resolveProbePortsForRuntime(runtime);
5179
5236
  let lastAddressInUseError;
5180
5237
  for (const candidatePort of probePorts) {
5181
5238
  const listenStart = process.hrtime.bigint();
@@ -5198,13 +5255,7 @@ var startCoreServer = async (options = {}) => {
5198
5255
  });
5199
5256
  try {
5200
5257
  writeRuntimeMetadata(
5201
- {
5202
- host: runtime.host,
5203
- port: resolvedPort,
5204
- git_root: runtime.gitRoot ?? void 0,
5205
- worktree_id: runtime.worktreeId ?? void 0,
5206
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
5207
- },
5258
+ buildRuntimeMetadataForPersist(runtime, resolvedPort),
5208
5259
  { metadataPath: runtime.metadataPath }
5209
5260
  );
5210
5261
  logger.info("core.runtime_metadata.persisted", {