@btraut/browser-bridge 0.13.2 → 0.14.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/dist/index.js CHANGED
@@ -38,14 +38,11 @@ var import_node_path2 = require("node:path");
38
38
  var import_node_fs = require("node:fs");
39
39
  var import_node_path = require("node:path");
40
40
  var DEFAULT_HOST = "127.0.0.1";
41
- var LEGACY_DEFAULT_PORT = 3210;
42
- var DETERMINISTIC_PORT_WINDOW = 2e3;
41
+ var DEFAULT_PORT = 3210;
43
42
  var ENV_CORE_HOST = "BROWSER_BRIDGE_CORE_HOST";
44
43
  var ENV_VISION_HOST = "BROWSER_VISION_CORE_HOST";
45
44
  var ENV_CORE_PORT = "BROWSER_BRIDGE_CORE_PORT";
46
45
  var ENV_VISION_PORT = "BROWSER_VISION_CORE_PORT";
47
- var ENV_ISOLATED_MODE = "BROWSER_BRIDGE_ISOLATED_MODE";
48
- var ENV_VISION_ISOLATED_MODE = "BROWSER_VISION_ISOLATED_MODE";
49
46
  var ENV_BRIDGE_CWD = "BROWSER_BRIDGE_CWD";
50
47
  var ENV_PROCESS_PWD = "PWD";
51
48
  var ENV_PROCESS_INIT_CWD = "INIT_CWD";
@@ -102,22 +99,6 @@ var normalizeHost = (value) => {
102
99
  const trimmed = value.trim();
103
100
  return trimmed.length > 0 ? trimmed : void 0;
104
101
  };
105
- var parseBoolean = (value) => {
106
- if (typeof value === "boolean") {
107
- return value;
108
- }
109
- if (typeof value !== "string") {
110
- return void 0;
111
- }
112
- const normalized = value.trim().toLowerCase();
113
- if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
114
- return true;
115
- }
116
- if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
117
- return false;
118
- }
119
- return void 0;
120
- };
121
102
  var parsePort = (value, label, invalidPolicy) => {
122
103
  if (value === void 0 || value === null) {
123
104
  return void 0;
@@ -134,60 +115,6 @@ var parsePort = (value, label, invalidPolicy) => {
134
115
  }
135
116
  return void 0;
136
117
  };
137
- var hashString = (value) => {
138
- let hash = 2166136261;
139
- for (let index = 0; index < value.length; index += 1) {
140
- hash ^= value.charCodeAt(index);
141
- hash = Math.imul(hash, 16777619);
142
- }
143
- return hash >>> 0;
144
- };
145
- var normalizePathForHash = (value) => value.replace(/\\/g, "/").toLowerCase();
146
- var sanitizeToken = (value) => value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
147
- var fallbackWorktreeId = (gitRoot) => {
148
- const hash = hashString(normalizePathForHash(gitRoot)).toString(16).padStart(8, "0");
149
- return `wt-${hash}`;
150
- };
151
- var extractWorktreeIdFromGitDir = (gitDir) => {
152
- const normalized = gitDir.replace(/\\/g, "/");
153
- const marker = "/.git/worktrees/";
154
- const markerIndex = normalized.lastIndexOf(marker);
155
- if (markerIndex < 0) {
156
- return null;
157
- }
158
- const remainder = normalized.slice(markerIndex + marker.length);
159
- const rawId = remainder.split("/")[0];
160
- if (!rawId) {
161
- return null;
162
- }
163
- const sanitized = sanitizeToken(rawId);
164
- return sanitized.length > 0 ? sanitized : null;
165
- };
166
- var readWorktreeGitDir = (gitRoot) => {
167
- const gitPath = (0, import_node_path.join)(gitRoot, ".git");
168
- try {
169
- const stats = (0, import_node_fs.statSync)(gitPath);
170
- if (stats.isDirectory()) {
171
- return gitPath;
172
- }
173
- if (!stats.isFile()) {
174
- return null;
175
- }
176
- } catch {
177
- return null;
178
- }
179
- try {
180
- const raw = (0, import_node_fs.readFileSync)(gitPath, "utf8");
181
- const match = raw.match(/^gitdir:\s*(.+)$/m);
182
- if (!match?.[1]) {
183
- return null;
184
- }
185
- const candidate = match[1].trim();
186
- return (0, import_node_path.isAbsolute)(candidate) ? candidate : (0, import_node_path.resolve)(gitRoot, candidate);
187
- } catch {
188
- return null;
189
- }
190
- };
191
118
  var resolveEnvHost = (env) => {
192
119
  const bridgeHost = normalizeHost(env[ENV_CORE_HOST]);
193
120
  if (bridgeHost) {
@@ -201,35 +128,18 @@ var resolveEnvPortRaw = (env) => {
201
128
  }
202
129
  return env[ENV_VISION_PORT];
203
130
  };
204
- var resolveEnvIsolatedMode = (env) => {
205
- const bridge = parseBoolean(env[ENV_ISOLATED_MODE]);
206
- if (bridge !== void 0) {
207
- return bridge;
208
- }
209
- return parseBoolean(env[ENV_VISION_ISOLATED_MODE]);
210
- };
211
131
  var sanitizeMetadata = (raw) => {
212
132
  if (!raw || typeof raw !== "object") {
213
133
  return null;
214
134
  }
215
135
  const candidate = raw;
216
- const host = normalizeHost(candidate.host);
217
- const port = parsePort(candidate.port, "port", "ignore");
218
- const gitRoot = normalizeHost(candidate.git_root);
219
- const worktreeId = normalizeHost(candidate.worktree_id);
220
136
  const extensionId = normalizeHost(candidate.extension_id);
221
- const isolatedMode = parseBoolean(candidate.isolated_mode);
222
137
  const updatedAt = normalizeHost(candidate.updated_at);
223
- if (!host && port === void 0 && !gitRoot && !worktreeId && !extensionId && isolatedMode === void 0 && !updatedAt) {
138
+ if (!extensionId && !updatedAt) {
224
139
  return null;
225
140
  }
226
141
  return {
227
- host,
228
- port,
229
- git_root: gitRoot,
230
- worktree_id: worktreeId,
231
142
  extension_id: extensionId,
232
- isolated_mode: isolatedMode,
233
143
  updated_at: updatedAt
234
144
  };
235
145
  };
@@ -246,32 +156,6 @@ var findGitRoot = (cwd) => {
246
156
  current = parent;
247
157
  }
248
158
  };
249
- var resolveWorktreeId = ({
250
- cwd,
251
- gitRoot
252
- } = {}) => {
253
- const resolvedGitRoot = gitRoot ?? findGitRoot(resolveCwd(cwd));
254
- if (!resolvedGitRoot) {
255
- return null;
256
- }
257
- const gitDir = readWorktreeGitDir(resolvedGitRoot);
258
- const parsedId = gitDir ? extractWorktreeIdFromGitDir(gitDir) : null;
259
- if (parsedId) {
260
- return parsedId;
261
- }
262
- return fallbackWorktreeId(resolvedGitRoot);
263
- };
264
- var resolveDeterministicCorePort = ({
265
- cwd,
266
- gitRoot
267
- } = {}) => {
268
- const resolvedGitRoot = gitRoot ?? findGitRoot(resolveCwd(cwd));
269
- if (!resolvedGitRoot) {
270
- return LEGACY_DEFAULT_PORT;
271
- }
272
- const seed = normalizePathForHash(resolvedGitRoot);
273
- return LEGACY_DEFAULT_PORT + hashString(seed) % DETERMINISTIC_PORT_WINDOW;
274
- };
275
159
  var resolveRuntimeMetadataPath = ({
276
160
  cwd,
277
161
  gitRoot,
@@ -318,17 +202,6 @@ var readRuntimeMetadata = ({
318
202
  return null;
319
203
  }
320
204
  };
321
- var writeRuntimeMetadata = (metadata, {
322
- cwd,
323
- gitRoot,
324
- metadataPath
325
- } = {}) => {
326
- const path9 = resolveRuntimeMetadataPath({ cwd, gitRoot, metadataPath });
327
- (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(path9), { recursive: true });
328
- (0, import_node_fs.writeFileSync)(path9, `${JSON.stringify(metadata, null, 2)}
329
- `, "utf8");
330
- return path9;
331
- };
332
205
  var resolveCoreRuntime = (options = {}) => {
333
206
  const env = options.env ?? process.env;
334
207
  const resolvedCwd = resolveCwd(options.cwd);
@@ -339,45 +212,18 @@ var resolveCoreRuntime = (options = {}) => {
339
212
  metadataPath: options.metadataPath
340
213
  });
341
214
  const metadata = options.metadata === void 0 ? readRuntimeMetadata({ metadataPath }) : sanitizeMetadata(options.metadata);
342
- const deterministicPort = resolveDeterministicCorePort({
343
- cwd: resolvedCwd,
344
- gitRoot
345
- });
346
215
  const optionHost = normalizeHost(options.host);
347
216
  const envHost = resolveEnvHost(env);
348
- const metadataHost = normalizeHost(metadata?.host);
349
- const host = optionHost ?? envHost ?? metadataHost ?? DEFAULT_HOST;
350
- const hostSource = optionHost ? "option" : envHost ? "env" : metadataHost ? "metadata" : "default";
217
+ const host = optionHost ?? envHost ?? DEFAULT_HOST;
218
+ const hostSource = optionHost ? "option" : envHost ? "env" : "default";
351
219
  const optionPort = parsePort(options.port, "port", "throw");
352
220
  const envPort = parsePort(
353
221
  resolveEnvPortRaw(env),
354
222
  "port",
355
223
  options.strictEnvPort ? "throw" : "ignore"
356
224
  );
357
- const metadataPort = parsePort(metadata?.port, "port", "ignore");
358
- const optionIsolatedMode = options.isolatedMode;
359
- const envIsolatedMode = resolveEnvIsolatedMode(env);
360
- const metadataIsolatedMode = metadata?.isolated_mode;
361
- const isolatedMode = optionIsolatedMode ?? envIsolatedMode ?? metadataIsolatedMode ?? false;
362
- const isolatedModeSource = optionIsolatedMode !== void 0 ? "option" : envIsolatedMode !== void 0 ? "env" : metadataIsolatedMode !== void 0 ? "metadata" : "default";
363
- let port;
364
- let portSource;
365
- if (optionPort !== void 0) {
366
- port = optionPort;
367
- portSource = "option";
368
- } else if (envPort !== void 0) {
369
- port = envPort;
370
- portSource = "env";
371
- } else if (metadataPort !== void 0 && isolatedMode) {
372
- port = metadataPort;
373
- portSource = "metadata";
374
- } else if (isolatedMode) {
375
- port = deterministicPort;
376
- portSource = "deterministic";
377
- } else {
378
- port = LEGACY_DEFAULT_PORT;
379
- portSource = "default";
380
- }
225
+ const port = optionPort ?? envPort ?? DEFAULT_PORT;
226
+ const portSource = optionPort !== void 0 ? "option" : envPort !== void 0 ? "env" : "default";
381
227
  return {
382
228
  host,
383
229
  port,
@@ -385,11 +231,7 @@ var resolveCoreRuntime = (options = {}) => {
385
231
  portSource,
386
232
  metadataPath,
387
233
  metadata,
388
- gitRoot,
389
- worktreeId: resolveWorktreeId({ cwd: resolvedCwd, gitRoot }),
390
- deterministicPort,
391
- isolatedMode,
392
- isolatedModeSource
234
+ gitRoot
393
235
  };
394
236
  };
395
237
 
@@ -808,7 +650,7 @@ var createCoreReadinessController = (options = {}) => {
808
650
  }
809
651
  if (portOccupied) {
810
652
  throw new Error(
811
- `Core daemon failed to start on ${runtime.host}:${runtime.port}. A process is already listening on this port but did not pass Browser Bridge health checks. Retry with --no-daemon to reuse it, or enable isolated mode (BROWSER_BRIDGE_ISOLATED_MODE=1) for per-worktree ports.`
653
+ `Core daemon failed to start on ${runtime.host}:${runtime.port}. A process is already listening on this port but did not pass Browser Bridge health checks. Retry with --no-daemon to reuse the existing process or stop whatever is already bound to that port.`
812
654
  );
813
655
  }
814
656
  throw new Error(
@@ -1002,9 +844,7 @@ var DiagnosticsRuntimeEndpointSchema = import_zod3.z.object({
1002
844
  port: import_zod3.z.number().finite().optional(),
1003
845
  base_url: import_zod3.z.string().optional(),
1004
846
  host_source: import_zod3.z.string().optional(),
1005
- port_source: import_zod3.z.string().optional(),
1006
- metadata_path: import_zod3.z.string().optional(),
1007
- isolated_mode: import_zod3.z.boolean().optional()
847
+ port_source: import_zod3.z.string().optional()
1008
848
  });
1009
849
  var DiagnosticsRuntimeProcessSchema = import_zod3.z.object({
1010
850
  component: import_zod3.z.enum(["cli", "mcp", "core"]).optional(),
@@ -1025,12 +865,13 @@ var DiagnosticsRuntimeContextSchema = import_zod3.z.object({
1025
865
  process: DiagnosticsRuntimeProcessSchema.optional()
1026
866
  }).optional(),
1027
867
  extension: import_zod3.z.object({
868
+ extension_id: import_zod3.z.string().optional(),
1028
869
  version: import_zod3.z.string().optional(),
1029
870
  protocol_version: import_zod3.z.string().optional(),
1030
871
  capability_negotiated: import_zod3.z.boolean().optional(),
1031
872
  capabilities: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.boolean()).optional(),
1032
873
  endpoint: DiagnosticsRuntimeEndpointSchema.optional(),
1033
- port_source: import_zod3.z.enum(["default", "storage"]).optional()
874
+ port_source: import_zod3.z.enum(["default"]).optional()
1034
875
  }).optional()
1035
876
  });
1036
877
  var DiagnosticReportSchema = import_zod3.z.object({
@@ -1105,7 +946,7 @@ var DriveNavigateInputSchema = import_zod3.z.object({
1105
946
  session_id: import_zod3.z.string().min(1).optional(),
1106
947
  url: import_zod3.z.string().min(1),
1107
948
  tab_id: import_zod3.z.number().finite().optional(),
1108
- wait: import_zod3.z.enum(["none", "domcontentloaded"]).default("domcontentloaded")
949
+ wait: import_zod3.z.enum(["none", "domcontentloaded", "networkidle"]).default("domcontentloaded")
1109
950
  });
1110
951
  var DriveNavigateOutputSchema = OpResultSchema.extend({
1111
952
  session_id: import_zod3.z.string().min(1)
@@ -1274,6 +1115,8 @@ var InspectConsistencySchema = import_zod3.z.enum(["best_effort", "quiesce"]);
1274
1115
  var TargetHintSchema = import_zod3.z.object({
1275
1116
  url: import_zod3.z.string().min(1).optional(),
1276
1117
  title: import_zod3.z.string().min(1).optional(),
1118
+ tab_id: import_zod3.z.number().finite().optional(),
1119
+ tabId: import_zod3.z.number().finite().optional(),
1277
1120
  last_active_at: import_zod3.z.string().optional(),
1278
1121
  lastActiveAt: import_zod3.z.string().optional()
1279
1122
  });
@@ -1468,6 +1311,7 @@ var HealthCheckOutputSchema = import_zod3.z.object({
1468
1311
  }).passthrough(),
1469
1312
  extension: import_zod3.z.object({
1470
1313
  connected: import_zod3.z.boolean(),
1314
+ extension_id: import_zod3.z.string().optional(),
1471
1315
  last_seen_at: import_zod3.z.string().min(1).optional()
1472
1316
  }).passthrough()
1473
1317
  }).passthrough();
@@ -1504,6 +1348,49 @@ var resolveTimeoutMs2 = (timeoutMs) => {
1504
1348
  };
1505
1349
  var normalizePath = (path9) => path9.startsWith("/") ? path9 : `/${path9}`;
1506
1350
  var durationMs = (startedAt) => Number((Number(process.hrtime.bigint() - startedAt) / 1e6).toFixed(3));
1351
+ var MAX_RESPONSE_PREVIEW_LENGTH = 200;
1352
+ var normalizeResponsePreview = (raw) => {
1353
+ const normalized = raw.replace(/\s+/g, " ").trim();
1354
+ if (normalized.length <= MAX_RESPONSE_PREVIEW_LENGTH) {
1355
+ return normalized;
1356
+ }
1357
+ return `${normalized.slice(0, MAX_RESPONSE_PREVIEW_LENGTH)}...`;
1358
+ };
1359
+ var getHeaderValue = (headers, name) => {
1360
+ if (!headers || typeof headers.get !== "function") {
1361
+ return void 0;
1362
+ }
1363
+ const value = headers.get(name);
1364
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1365
+ };
1366
+ var buildInvalidCoreResponseError = (options) => {
1367
+ const details = {
1368
+ base_url: options.baseUrl,
1369
+ path: options.path,
1370
+ status: options.status,
1371
+ reason: options.kind === "empty" ? "core_empty_response" : "core_invalid_json_response",
1372
+ next_step: "Verify Browser Bridge core is reachable on the expected host and port, then retry."
1373
+ };
1374
+ if (options.contentType) {
1375
+ details.content_type = options.contentType;
1376
+ }
1377
+ if (options.responseText && options.responseText.trim().length > 0) {
1378
+ details.response_preview = normalizeResponsePreview(options.responseText);
1379
+ }
1380
+ const message = options.kind === "empty" ? "Core returned an empty response." : options.contentType?.toLowerCase().includes("text/html") ? "Core returned HTML instead of JSON." : "Core returned an invalid JSON response.";
1381
+ return new CoreClientError({
1382
+ code: "UNAVAILABLE",
1383
+ message,
1384
+ retryable: true,
1385
+ retry: {
1386
+ retryable: true,
1387
+ reason: options.kind === "empty" ? "core_empty_response" : "core_invalid_json_response",
1388
+ retry_after_ms: 250,
1389
+ max_attempts: 1
1390
+ },
1391
+ details
1392
+ });
1393
+ };
1507
1394
  var createCoreClient = (options = {}) => {
1508
1395
  const logger = options.logger ?? createJsonlLogger({
1509
1396
  stream: "cli",
@@ -1617,6 +1504,7 @@ startCoreServer({ ${startOptions.join(
1617
1504
  });
1618
1505
  throw error;
1619
1506
  }
1507
+ const contentType = getHeaderValue(response.headers, "content-type");
1620
1508
  const raw = await response.text();
1621
1509
  if (!raw) {
1622
1510
  logger.warn("cli.core.request.empty_response", {
@@ -1624,9 +1512,16 @@ startCoreServer({ ${startOptions.join(
1624
1512
  path: requestPath,
1625
1513
  base_url: readiness.baseUrl,
1626
1514
  status: response.status,
1515
+ content_type: contentType,
1627
1516
  duration_ms: durationMs(startedAt)
1628
1517
  });
1629
- throw new Error(`Empty response from Core (${response.status}).`);
1518
+ throw buildInvalidCoreResponseError({
1519
+ kind: "empty",
1520
+ status: response.status,
1521
+ baseUrl: readiness.baseUrl,
1522
+ path: requestPath,
1523
+ contentType
1524
+ });
1630
1525
  }
1631
1526
  try {
1632
1527
  const parsed = JSON.parse(raw);
@@ -1639,16 +1534,24 @@ startCoreServer({ ${startOptions.join(
1639
1534
  });
1640
1535
  return parsed;
1641
1536
  } catch (error) {
1642
- const message = error instanceof Error ? error.message : "Unknown JSON parse error";
1643
1537
  logger.error("cli.core.request.invalid_json", {
1644
1538
  method,
1645
1539
  path: requestPath,
1646
1540
  base_url: readiness.baseUrl,
1647
1541
  status: response.status,
1542
+ content_type: contentType,
1543
+ response_preview: normalizeResponsePreview(raw),
1648
1544
  duration_ms: durationMs(startedAt),
1649
1545
  error
1650
1546
  });
1651
- throw new Error(`Failed to parse Core response: ${message}`);
1547
+ throw buildInvalidCoreResponseError({
1548
+ kind: "invalid_json",
1549
+ status: response.status,
1550
+ baseUrl: readiness.baseUrl,
1551
+ path: requestPath,
1552
+ contentType,
1553
+ responseText: raw
1554
+ });
1652
1555
  }
1653
1556
  } finally {
1654
1557
  clearTimeout(timeout);
@@ -1665,9 +1568,7 @@ startCoreServer({ ${startOptions.join(
1665
1568
  port: readiness.runtime.port,
1666
1569
  base_url: readiness.baseUrl,
1667
1570
  host_source: readiness.runtime.hostSource,
1668
- port_source: readiness.runtime.portSource,
1669
- metadata_path: readiness.runtime.metadataPath,
1670
- isolated_mode: readiness.runtime.isolatedMode
1571
+ port_source: readiness.runtime.portSource
1671
1572
  },
1672
1573
  process: {
1673
1574
  component: "cli",
@@ -1962,35 +1863,8 @@ var registerDiagnosticsCommands = (program2) => {
1962
1863
  });
1963
1864
  };
1964
1865
 
1965
- // packages/cli/src/open-path.ts
1966
- var import_node_child_process2 = require("node:child_process");
1967
- var openPath = async (target) => {
1968
- const platform = process.platform;
1969
- if (platform === "darwin") {
1970
- const child2 = (0, import_node_child_process2.spawn)("open", [target], { detached: true, stdio: "ignore" });
1971
- child2.unref();
1972
- return;
1973
- }
1974
- if (platform === "win32") {
1975
- const child2 = (0, import_node_child_process2.spawn)("cmd", ["/c", "start", "", target], {
1976
- detached: true,
1977
- stdio: "ignore"
1978
- });
1979
- child2.unref();
1980
- return;
1981
- }
1982
- const child = (0, import_node_child_process2.spawn)("xdg-open", [target], {
1983
- detached: true,
1984
- stdio: "ignore"
1985
- });
1986
- child.unref();
1987
- };
1988
-
1989
1866
  // packages/cli/src/commands/dev.ts
1990
1867
  var ENV_EXTENSION_ID = "BROWSER_BRIDGE_EXTENSION_ID";
1991
- var ACTIVATION_FLAG_PARAM = "bb_activate";
1992
- var ACTIVATION_PORT_PARAM = "corePort";
1993
- var ACTIVATION_WORKTREE_PARAM = "worktreeId";
1994
1868
  var normalizeToken = (value) => {
1995
1869
  if (typeof value !== "string") {
1996
1870
  return void 0;
@@ -2007,45 +1881,71 @@ var resolveActivationExtensionId = (options) => {
2007
1881
  if (envId) {
2008
1882
  return { extensionId: envId, source: "env" };
2009
1883
  }
2010
- const metadataId = normalizeToken(options.metadataExtensionId);
2011
- if (metadataId) {
2012
- return { extensionId: metadataId, source: "metadata" };
2013
- }
2014
1884
  return null;
2015
1885
  };
2016
- var buildActivationOptionsUrl = (options) => {
2017
- const search = new URLSearchParams();
2018
- search.set(ACTIVATION_FLAG_PARAM, "1");
2019
- search.set(ACTIVATION_PORT_PARAM, String(options.corePort));
2020
- if (options.worktreeId) {
2021
- search.set(ACTIVATION_WORKTREE_PARAM, options.worktreeId);
2022
- }
2023
- return `chrome-extension://${options.extensionId}/options.html?${search.toString()}`;
2024
- };
2025
- var buildPersistedRuntimeMetadata = (runtime, extensionId) => ({
2026
- ...runtime.metadata ?? {},
2027
- host: runtime.host,
2028
- port: runtime.port,
2029
- git_root: runtime.gitRoot ?? runtime.metadata?.git_root,
2030
- worktree_id: runtime.worktreeId ?? runtime.metadata?.worktree_id,
2031
- extension_id: extensionId,
2032
- isolated_mode: true,
2033
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
2034
- });
2035
- var resolveRuntimeForCommand = (options, overrides = {}) => {
1886
+ var resolveRuntimeForCommand = (options) => {
2036
1887
  const runtimeOptions = {
2037
1888
  host: options.host,
2038
1889
  port: options.port,
2039
1890
  strictEnvPort: true
2040
1891
  };
2041
- if (overrides.isolatedMode !== void 0) {
2042
- runtimeOptions.isolatedMode = overrides.isolatedMode;
2043
- }
2044
1892
  return resolveCoreRuntime(runtimeOptions);
2045
1893
  };
1894
+ var hasPassingCheck = (report, name) => report?.checks?.some((check) => check.name === name && check.ok) ?? false;
1895
+ var getReportedExtensionId = (report) => normalizeToken(report?.runtime?.extension?.extension_id);
1896
+ var inspectCapabilityReady = (report, expectedExtensionId) => {
1897
+ const reportedExtensionId = getReportedExtensionId(report);
1898
+ const extensionIdMatch = !expectedExtensionId || !reportedExtensionId || reportedExtensionId === expectedExtensionId;
1899
+ return extensionIdMatch && hasPassingCheck(report, "inspect.capability");
1900
+ };
1901
+ var readDiagnosticReport = async (runtime) => {
1902
+ const client = createCoreClient({
1903
+ host: runtime.host,
1904
+ port: runtime.port,
1905
+ ensureDaemon: true
1906
+ });
1907
+ const envelope2 = await client.post(
1908
+ "/diagnostics/doctor",
1909
+ {}
1910
+ );
1911
+ return envelope2.ok ? envelope2.result : void 0;
1912
+ };
1913
+ var buildInspectCapabilityError = (runtime, report, expectedExtension) => {
1914
+ const observedExtensionId = getReportedExtensionId(report);
1915
+ if (expectedExtension && observedExtensionId && observedExtensionId !== expectedExtension.extensionId) {
1916
+ return new CliError({
1917
+ code: "FAILED_PRECONDITION",
1918
+ message: "Inspect capability is available, but the connected extension does not match the requested extension id.",
1919
+ retryable: false,
1920
+ details: {
1921
+ host: runtime.host,
1922
+ port: runtime.port,
1923
+ expectedExtensionId: expectedExtension.extensionId,
1924
+ expectedExtensionIdSource: expectedExtension.source,
1925
+ observedExtensionId,
1926
+ next_step: "Clear the stale extension-id override or reload the intended Browser Bridge extension, then retry."
1927
+ }
1928
+ });
1929
+ }
1930
+ return new CliError({
1931
+ code: "FAILED_PRECONDITION",
1932
+ message: "Inspect capability is unavailable in a build where it should already be enabled.",
1933
+ retryable: true,
1934
+ details: {
1935
+ host: runtime.host,
1936
+ port: runtime.port,
1937
+ expectedExtensionId: expectedExtension?.extensionId,
1938
+ expectedExtensionIdSource: expectedExtension?.source,
1939
+ observedConnected: report?.extension?.connected ?? false,
1940
+ observedExtensionId,
1941
+ observedInspectCapability: hasPassingCheck(report, "inspect.capability"),
1942
+ next_step: "Restart the Browser Bridge core daemon, then reload or update the Browser Bridge extension and retry."
1943
+ }
1944
+ });
1945
+ };
2046
1946
  var registerDevCommands = (program2) => {
2047
1947
  const dev = program2.command("dev").description("Development commands");
2048
- dev.command("info").description("Print resolved runtime details for the current worktree").action(async (_options, command) => {
1948
+ dev.command("info").description("Print resolved runtime details for the current environment").action(async (_options, command) => {
2049
1949
  await runLocal(command, async (globalOptions) => {
2050
1950
  const runtime = resolveRuntimeForCommand(globalOptions);
2051
1951
  const logDir = resolveLogDirectory({ gitRoot: runtime.gitRoot });
@@ -2056,8 +1956,6 @@ var registerDevCommands = (program2) => {
2056
1956
  hostSource: runtime.hostSource,
2057
1957
  port: runtime.port,
2058
1958
  portSource: runtime.portSource,
2059
- deterministicPort: runtime.deterministicPort,
2060
- worktreeId: runtime.worktreeId,
2061
1959
  metadataPath: runtime.metadataPath,
2062
1960
  logDir,
2063
1961
  metadataSnapshot: runtime.metadata
@@ -2065,51 +1963,40 @@ var registerDevCommands = (program2) => {
2065
1963
  };
2066
1964
  });
2067
1965
  });
2068
- dev.command("activate").description(
2069
- "Enable isolated worktree routing and open extension options for activation"
2070
- ).option(
1966
+ dev.command("enable-inspect").description("Compatibility helper that verifies inspect capability").option(
2071
1967
  "--extension-id <id>",
2072
- "Chrome extension id to activate for isolated worktree routing"
1968
+ "Chrome extension id to verify against while checking inspect capability"
2073
1969
  ).action(async (options, command) => {
2074
1970
  await runLocal(command, async (globalOptions) => {
2075
- const runtime = resolveRuntimeForCommand(globalOptions, {
2076
- isolatedMode: true
2077
- });
2078
- const extension = resolveActivationExtensionId({
1971
+ const runtime = resolveRuntimeForCommand(globalOptions);
1972
+ let resolvedExtension = resolveActivationExtensionId({
2079
1973
  optionExtensionId: options.extensionId,
2080
- envExtensionId: process.env[ENV_EXTENSION_ID],
2081
- metadataExtensionId: runtime.metadata?.extension_id
1974
+ envExtensionId: process.env[ENV_EXTENSION_ID]
2082
1975
  });
2083
- if (!extension) {
2084
- throw new CliError({
2085
- code: "INVALID_ARGUMENT",
2086
- message: "Missing extension id. Provide --extension-id <id>, set BROWSER_BRIDGE_EXTENSION_ID, or persist extension_id in metadata by running dev activate with --extension-id once (only needed for isolated worktree routing).",
2087
- retryable: false,
2088
- details: {
2089
- metadataPath: runtime.metadataPath
2090
- }
2091
- });
1976
+ const report = await readDiagnosticReport(runtime);
1977
+ if (!resolvedExtension) {
1978
+ const reportedExtensionId = getReportedExtensionId(report);
1979
+ if (reportedExtensionId) {
1980
+ resolvedExtension = {
1981
+ extensionId: reportedExtensionId,
1982
+ source: "connected"
1983
+ };
1984
+ }
1985
+ }
1986
+ if (!inspectCapabilityReady(report, resolvedExtension?.extensionId)) {
1987
+ throw buildInspectCapabilityError(runtime, report, resolvedExtension);
2092
1988
  }
2093
- const metadataPath = writeRuntimeMetadata(
2094
- buildPersistedRuntimeMetadata(runtime, extension.extensionId),
2095
- { metadataPath: runtime.metadataPath }
2096
- );
2097
- const activationUrl = buildActivationOptionsUrl({
2098
- extensionId: extension.extensionId,
2099
- corePort: runtime.port,
2100
- worktreeId: runtime.worktreeId
2101
- });
2102
- await openPath(activationUrl);
2103
1989
  return {
2104
1990
  ok: true,
2105
1991
  result: {
2106
- extensionId: extension.extensionId,
2107
- extensionIdSource: extension.source,
2108
1992
  host: runtime.host,
2109
1993
  port: runtime.port,
2110
- isolatedMode: true,
2111
- metadataPath,
2112
- activationUrl
1994
+ inspectAlwaysEnabled: true,
1995
+ checkedWithDiagnostics: true,
1996
+ ...resolvedExtension ? {
1997
+ extensionId: resolvedExtension.extensionId,
1998
+ extensionIdSource: resolvedExtension.source
1999
+ } : {}
2113
2000
  }
2114
2001
  };
2115
2002
  });
@@ -2198,7 +2085,7 @@ var registerDriveCommands = (program2) => {
2198
2085
  drive.command("navigate").description("Navigate to a URL").option(
2199
2086
  "--session-id <id>",
2200
2087
  "Session identifier (auto-created when omitted)"
2201
- ).requiredOption("--url <url>", "URL to navigate to").option("--tab-id <id>", "Tab identifier (defaults to agent window/tab)").option("--wait <mode>", "Wait mode (none, domcontentloaded)").action(async (options, command) => {
2088
+ ).requiredOption("--url <url>", "URL to navigate to").option("--tab-id <id>", "Tab identifier (defaults to agent window/tab)").option("--wait <mode>", "Wait mode (none, domcontentloaded, networkidle)").action(async (options, command) => {
2202
2089
  await runCommand(command, (client) => {
2203
2090
  const payload = parseInput(DriveNavigateInputSchema, {
2204
2091
  ...options.sessionId ? { session_id: options.sessionId } : {},
@@ -2476,9 +2363,23 @@ var registerDriveCommands = (program2) => {
2476
2363
  };
2477
2364
 
2478
2365
  // packages/cli/src/commands/inspect.ts
2366
+ var parseNumber4 = (value) => {
2367
+ if (value === void 0 || value === null || value === "") {
2368
+ return void 0;
2369
+ }
2370
+ const parsed = Number(value);
2371
+ return Number.isFinite(parsed) ? parsed : Number.NaN;
2372
+ };
2373
+ var buildTargetHint = (options) => {
2374
+ const tabId = parseNumber4(options.tabId);
2375
+ if (tabId === void 0) {
2376
+ return void 0;
2377
+ }
2378
+ return { tab_id: tabId };
2379
+ };
2479
2380
  var registerInspectCommands = (program2) => {
2480
2381
  const inspect = program2.command("inspect").description("Inspect commands");
2481
- inspect.command("dom-snapshot").description("Fetch a DOM snapshot").requiredOption("--session-id <id>", "Session identifier").option("--format <format>", "Snapshot format (ax, html)").option("--consistency <mode>", "Consistency mode (best_effort, quiesce)").option("-i, --interactive", "Only include interactive elements").option("-c, --compact", "Remove empty/decorative nodes").option("--max-nodes <n>", "Limit AX snapshot to at most n nodes").option("-s, --selector <selector>", "Limit snapshot to selector").action(async (options, command) => {
2382
+ inspect.command("dom-snapshot").description("Fetch a DOM snapshot").requiredOption("--session-id <id>", "Session identifier").option("--format <format>", "Snapshot format (ax, html)").option("--consistency <mode>", "Consistency mode (best_effort, quiesce)").option("-i, --interactive", "Only include interactive elements").option("-c, --compact", "Remove empty/decorative nodes").option("--max-nodes <n>", "Limit AX snapshot to at most n nodes").option("-s, --selector <selector>", "Limit snapshot to selector").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
2482
2383
  await runCommand(command, (client) => {
2483
2384
  const payload = parseInput(InspectDomSnapshotInputSchema, {
2484
2385
  session_id: options.sessionId,
@@ -2487,7 +2388,8 @@ var registerInspectCommands = (program2) => {
2487
2388
  interactive: options.interactive,
2488
2389
  compact: options.compact,
2489
2390
  max_nodes: options.maxNodes,
2490
- selector: options.selector
2391
+ selector: options.selector,
2392
+ target: buildTargetHint(options)
2491
2393
  });
2492
2394
  return client.post("/inspect/dom_snapshot", payload);
2493
2395
  });
@@ -2500,7 +2402,7 @@ var registerInspectCommands = (program2) => {
2500
2402
  return client.post("/inspect/dom_diff", payload);
2501
2403
  });
2502
2404
  });
2503
- inspect.command("find").description("Find elements and return refs").requiredOption("--session-id <id>", "Session identifier").argument("<kind>", "Find kind (role, text, label)").argument("<value>", "Role name or text to match").option("--name <name>", "Accessible name to match (role only)").action(async (kind, value, options, command) => {
2405
+ inspect.command("find").description("Find elements and return refs").requiredOption("--session-id <id>", "Session identifier").argument("<kind>", "Find kind (role, text, label)").argument("<value>", "Role name or text to match").option("--name <name>", "Accessible name to match (role only)").option("--tab-id <id>", "Explicit tab identifier").action(async (kind, value, options, command) => {
2504
2406
  await runCommand(command, (client) => {
2505
2407
  const normalizedKind = String(kind ?? "").toLowerCase();
2506
2408
  let payload;
@@ -2509,19 +2411,22 @@ var registerInspectCommands = (program2) => {
2509
2411
  session_id: options.sessionId,
2510
2412
  kind: "role",
2511
2413
  role: value,
2512
- name: options.name
2414
+ name: options.name,
2415
+ target: buildTargetHint(options)
2513
2416
  };
2514
2417
  } else if (normalizedKind === "text") {
2515
2418
  payload = {
2516
2419
  session_id: options.sessionId,
2517
2420
  kind: "text",
2518
- text: value
2421
+ text: value,
2422
+ target: buildTargetHint(options)
2519
2423
  };
2520
2424
  } else if (normalizedKind === "label") {
2521
2425
  payload = {
2522
2426
  session_id: options.sessionId,
2523
2427
  kind: "label",
2524
- label: value
2428
+ label: value,
2429
+ target: buildTargetHint(options)
2525
2430
  };
2526
2431
  } else {
2527
2432
  throw new CliError({
@@ -2535,53 +2440,59 @@ var registerInspectCommands = (program2) => {
2535
2440
  return client.post("/inspect/find", parsed);
2536
2441
  });
2537
2442
  });
2538
- inspect.command("extract-content").description("Extract main content from the page").requiredOption("--session-id <id>", "Session identifier").option("--format <format>", "Output format (markdown, text, article_json)").option("--include-metadata", "Include article metadata").option("--no-include-metadata", "Exclude article metadata").action(async (options, command) => {
2443
+ inspect.command("extract-content").description("Extract main content from the page").requiredOption("--session-id <id>", "Session identifier").option("--format <format>", "Output format (markdown, text, article_json)").option("--include-metadata", "Include article metadata").option("--no-include-metadata", "Exclude article metadata").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
2539
2444
  await runCommand(command, (client) => {
2540
2445
  const payload = parseInput(InspectExtractContentInputSchema, {
2541
2446
  session_id: options.sessionId,
2542
2447
  format: options.format,
2543
- include_metadata: options.includeMetadata
2448
+ include_metadata: options.includeMetadata,
2449
+ target: buildTargetHint(options)
2544
2450
  });
2545
2451
  return client.post("/inspect/extract_content", payload);
2546
2452
  });
2547
2453
  });
2548
- inspect.command("page-state").description("Capture form, storage, and cookie state").requiredOption("--session-id <id>", "Session identifier").action(async (options, command) => {
2454
+ inspect.command("page-state").description("Capture form, storage, and cookie state").requiredOption("--session-id <id>", "Session identifier").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
2549
2455
  await runCommand(command, (client) => {
2550
2456
  const payload = parseInput(InspectPageStateInputSchema, {
2551
- session_id: options.sessionId
2457
+ session_id: options.sessionId,
2458
+ target: buildTargetHint(options)
2552
2459
  });
2553
2460
  return client.post("/inspect/page_state", payload);
2554
2461
  });
2555
2462
  });
2556
- inspect.command("console-list").description("Fetch console entries").requiredOption("--session-id <id>", "Session identifier").action(async (options, command) => {
2463
+ inspect.command("console-list").description("Fetch console entries").requiredOption("--session-id <id>", "Session identifier").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
2557
2464
  await runCommand(command, (client) => {
2558
2465
  const payload = parseInput(InspectConsoleListInputSchema, {
2559
- session_id: options.sessionId
2466
+ session_id: options.sessionId,
2467
+ target: buildTargetHint(options)
2560
2468
  });
2561
2469
  return client.post("/inspect/console_list", payload);
2562
2470
  });
2563
2471
  });
2564
- inspect.command("network-har").description("Fetch network HAR").requiredOption("--session-id <id>", "Session identifier").action(async (options, command) => {
2472
+ inspect.command("network-har").description("Fetch network HAR").requiredOption("--session-id <id>", "Session identifier").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
2565
2473
  await runCommand(command, (client) => {
2566
2474
  const payload = parseInput(InspectNetworkHarInputSchema, {
2567
- session_id: options.sessionId
2475
+ session_id: options.sessionId,
2476
+ target: buildTargetHint(options)
2568
2477
  });
2569
2478
  return client.post("/inspect/network_har", payload);
2570
2479
  });
2571
2480
  });
2572
- inspect.command("evaluate").description("Evaluate a JavaScript expression").requiredOption("--session-id <id>", "Session identifier").option("--expression <expr>", "Expression to evaluate").action(async (options, command) => {
2481
+ inspect.command("evaluate").description("Evaluate a JavaScript expression").requiredOption("--session-id <id>", "Session identifier").option("--expression <expr>", "Expression to evaluate").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
2573
2482
  await runCommand(command, (client) => {
2574
2483
  const payload = parseInput(InspectEvaluateInputSchema, {
2575
2484
  session_id: options.sessionId,
2576
- expression: options.expression
2485
+ expression: options.expression,
2486
+ target: buildTargetHint(options)
2577
2487
  });
2578
2488
  return client.post("/inspect/evaluate", payload);
2579
2489
  });
2580
2490
  });
2581
- inspect.command("performance-metrics").description("Fetch performance metrics").requiredOption("--session-id <id>", "Session identifier").action(async (options, command) => {
2491
+ inspect.command("performance-metrics").description("Fetch performance metrics").requiredOption("--session-id <id>", "Session identifier").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
2582
2492
  await runCommand(command, (client) => {
2583
2493
  const payload = parseInput(InspectPerformanceMetricsInputSchema, {
2584
- session_id: options.sessionId
2494
+ session_id: options.sessionId,
2495
+ target: buildTargetHint(options)
2585
2496
  });
2586
2497
  return client.post("/inspect/performance_metrics", payload);
2587
2498
  });
@@ -2589,7 +2500,7 @@ var registerInspectCommands = (program2) => {
2589
2500
  };
2590
2501
 
2591
2502
  // packages/mcp-adapter/src/core-client.ts
2592
- var import_node_child_process3 = require("node:child_process");
2503
+ var import_node_child_process2 = require("node:child_process");
2593
2504
  var import_node_path4 = require("node:path");
2594
2505
  var DEFAULT_TIMEOUT_MS3 = 3e4;
2595
2506
  var normalizePath2 = (path9) => path9.startsWith("/") ? path9 : `/${path9}`;
@@ -2618,7 +2529,7 @@ var createCoreClient2 = (options = {}) => {
2618
2529
  }).child({ scope: "core-client" });
2619
2530
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
2620
2531
  const fetchImpl = options.fetchImpl ?? fetch;
2621
- const spawnImpl = options.spawnImpl ?? import_node_child_process3.spawn;
2532
+ const spawnImpl = options.spawnImpl ?? import_node_child_process2.spawn;
2622
2533
  const ensureDaemon = options.ensureDaemon ?? false;
2623
2534
  const componentVersion = options.componentVersion ?? process.env.BROWSER_BRIDGE_VERSION ?? process.env.npm_package_version;
2624
2535
  const readiness = createCoreReadinessController({
@@ -2750,9 +2661,7 @@ startCoreServer({ ${startOptions.join(
2750
2661
  port: readiness.runtime.port,
2751
2662
  base_url: readiness.baseUrl,
2752
2663
  host_source: readiness.runtime.hostSource,
2753
- port_source: readiness.runtime.portSource,
2754
- metadata_path: readiness.runtime.metadataPath,
2755
- isolated_mode: readiness.runtime.isolatedMode
2664
+ port_source: readiness.runtime.portSource
2756
2665
  },
2757
2666
  process: {
2758
2667
  component: "mcp",
@@ -2798,6 +2707,70 @@ var toInternalErrorEnvelope = (error) => ({
2798
2707
  });
2799
2708
  var envelope = (schema) => successEnvelopeSchema(schema);
2800
2709
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2710
+ var readSessionId = (args) => {
2711
+ if (!isRecord(args)) {
2712
+ return void 0;
2713
+ }
2714
+ const sessionId = args.session_id;
2715
+ return typeof sessionId === "string" && sessionId.length > 0 ? sessionId : void 0;
2716
+ };
2717
+ var supportsSessionMigration = (corePath) => corePath.startsWith("/drive/") || corePath.startsWith("/inspect/") || corePath.startsWith("/artifacts/") || corePath === "/diagnostics/doctor";
2718
+ var isSessionNotFoundEnvelope = (envelopeResult) => {
2719
+ if (envelopeResult.ok) {
2720
+ return false;
2721
+ }
2722
+ const details = envelopeResult.error.details;
2723
+ return envelopeResult.error.code === "NOT_FOUND" && isRecord(details) && details.reason === "session_not_found";
2724
+ };
2725
+ var addSessionRecoveryHint = (envelopeResult) => {
2726
+ if (envelopeResult.ok) {
2727
+ return envelopeResult;
2728
+ }
2729
+ return {
2730
+ ok: false,
2731
+ error: {
2732
+ ...envelopeResult.error,
2733
+ details: {
2734
+ ...isRecord(envelopeResult.error.details) ? envelopeResult.error.details : {},
2735
+ recover_action: "session.create"
2736
+ }
2737
+ }
2738
+ };
2739
+ };
2740
+ var addSessionMigrationNotice = (envelopeResult, staleSessionId, replacementSessionId) => {
2741
+ if (envelopeResult.ok) {
2742
+ if (!isRecord(envelopeResult.result)) {
2743
+ return envelopeResult;
2744
+ }
2745
+ const warning = `Session ${staleSessionId} became stale after runtime switch; retried with ${replacementSessionId}.`;
2746
+ const existingWarnings = Array.isArray(envelopeResult.result.warnings) ? envelopeResult.result.warnings.filter(
2747
+ (item) => typeof item === "string"
2748
+ ) : [];
2749
+ return {
2750
+ ok: true,
2751
+ result: {
2752
+ ...envelopeResult.result,
2753
+ warnings: existingWarnings.includes(warning) ? existingWarnings : [...existingWarnings, warning],
2754
+ session_migration: {
2755
+ stale_session_id: staleSessionId,
2756
+ replacement_session_id: replacementSessionId
2757
+ }
2758
+ }
2759
+ };
2760
+ }
2761
+ return {
2762
+ ok: false,
2763
+ error: {
2764
+ ...envelopeResult.error,
2765
+ details: {
2766
+ ...isRecord(envelopeResult.error.details) ? envelopeResult.error.details : {},
2767
+ stale_session_id: staleSessionId,
2768
+ replacement_session_id: replacementSessionId,
2769
+ recover_action: "session.recover"
2770
+ }
2771
+ }
2772
+ };
2773
+ };
2801
2774
  var addDeprecatedAliasWarning2 = (envelopeResult, deprecationAlias) => {
2802
2775
  if (!deprecationAlias || !envelopeResult.ok || typeof envelopeResult.result !== "object" || !envelopeResult.result) {
2803
2776
  return envelopeResult;
@@ -3208,10 +3181,26 @@ var createToolHandler = (clientProvider, corePath, deprecationAlias, transformIn
3208
3181
  void _extra;
3209
3182
  try {
3210
3183
  const client = typeof clientProvider === "function" ? await clientProvider() : clientProvider;
3211
- const envelopeResult = await client.post(
3212
- corePath,
3213
- transformInput ? transformInput(args) : args
3214
- );
3184
+ const transformedArgs = transformInput ? transformInput(args) : args;
3185
+ const staleSessionId = readSessionId(transformedArgs);
3186
+ let envelopeResult = await client.post(corePath, transformedArgs);
3187
+ if (staleSessionId && supportsSessionMigration(corePath) && isSessionNotFoundEnvelope(envelopeResult) && isRecord(transformedArgs)) {
3188
+ const createdSession = await client.post("/session/create", {});
3189
+ if (createdSession.ok && isRecord(createdSession.result) && typeof createdSession.result.session_id === "string" && createdSession.result.session_id.length > 0) {
3190
+ const replacementSessionId = createdSession.result.session_id;
3191
+ const retryArgs = {
3192
+ ...transformedArgs,
3193
+ session_id: replacementSessionId
3194
+ };
3195
+ envelopeResult = addSessionMigrationNotice(
3196
+ await client.post(corePath, retryArgs),
3197
+ staleSessionId,
3198
+ replacementSessionId
3199
+ );
3200
+ } else {
3201
+ envelopeResult = addSessionRecoveryHint(envelopeResult);
3202
+ }
3203
+ }
3215
3204
  return toToolResult(
3216
3205
  addDeprecatedAliasWarning2(envelopeResult, deprecationAlias)
3217
3206
  );
@@ -3357,7 +3346,7 @@ var DEFAULT_HTTP_PATH = "/mcp";
3357
3346
  var ENV_MCP_EAGER = "BROWSER_BRIDGE_MCP_EAGER";
3358
3347
  var ENV_LEGACY_MCP_EAGER = "BROWSER_VISION_MCP_EAGER";
3359
3348
  var durationMs4 = (startedAt) => Number((Number(process.hrtime.bigint() - startedAt) / 1e6).toFixed(3));
3360
- var parseBoolean2 = (value) => {
3349
+ var parseBoolean = (value) => {
3361
3350
  if (value === void 0) {
3362
3351
  return void 0;
3363
3352
  }
@@ -3374,7 +3363,7 @@ var resolveEagerMode = (explicit) => {
3374
3363
  if (typeof explicit === "boolean") {
3375
3364
  return explicit;
3376
3365
  }
3377
- const envValue = parseBoolean2(process.env[ENV_MCP_EAGER]) ?? parseBoolean2(process.env[ENV_LEGACY_MCP_EAGER]);
3366
+ const envValue = parseBoolean(process.env[ENV_MCP_EAGER]) ?? parseBoolean(process.env[ENV_LEGACY_MCP_EAGER]);
3378
3367
  return envValue ?? false;
3379
3368
  };
3380
3369
  var toCoreClientOptions = (options, logger) => ({
@@ -3561,7 +3550,7 @@ var readJsonBody = async (req, maxBytes = 5 * 1024 * 1024) => {
3561
3550
  }
3562
3551
  return JSON.parse(raw);
3563
3552
  };
3564
- var getHeaderValue = (value) => {
3553
+ var getHeaderValue2 = (value) => {
3565
3554
  if (typeof value === "string") {
3566
3555
  return value;
3567
3556
  }
@@ -3627,7 +3616,7 @@ var startMcpHttpServer = async (options = {}) => {
3627
3616
  });
3628
3617
  return;
3629
3618
  }
3630
- const sessionId = getHeaderValue(req.headers["mcp-session-id"]);
3619
+ const sessionId = getHeaderValue2(req.headers["mcp-session-id"]);
3631
3620
  requestLogger.debug("mcp.http.request.session", {
3632
3621
  session_id: sessionId ?? null
3633
3622
  });
@@ -3786,7 +3775,7 @@ var checkboxPrompt = async (options) => {
3786
3775
  };
3787
3776
 
3788
3777
  // packages/cli/src/installer/mcp-install.ts
3789
- var import_node_child_process4 = require("node:child_process");
3778
+ var import_node_child_process3 = require("node:child_process");
3790
3779
 
3791
3780
  // packages/cli/src/installer/cursor-mcp.ts
3792
3781
  var import_promises2 = __toESM(require("node:fs/promises"));
@@ -3857,7 +3846,7 @@ var installCursorMcp = async (settingsPath) => {
3857
3846
  // packages/cli/src/installer/mcp-install.ts
3858
3847
  var runQuiet = async (cmd, args) => {
3859
3848
  await new Promise((resolve4, reject) => {
3860
- const child = (0, import_node_child_process4.spawn)(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
3849
+ const child = (0, import_node_child_process3.spawn)(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
3861
3850
  let stderr = "";
3862
3851
  child.stderr?.on("data", (chunk) => {
3863
3852
  stderr += String(chunk);
@@ -4026,11 +4015,6 @@ var import_express2 = __toESM(require("express"));
4026
4015
  // packages/core/src/routes/session.ts
4027
4016
  var import_express = require("express");
4028
4017
 
4029
- // packages/core/src/inspect/service.ts
4030
- var import_readability = require("@mozilla/readability");
4031
- var import_jsdom = require("jsdom");
4032
- var import_turndown = __toESM(require("turndown"));
4033
-
4034
4018
  // packages/core/src/artifacts.ts
4035
4019
  var import_promises3 = require("node:fs/promises");
4036
4020
  var import_node_os2 = __toESM(require("node:os"));
@@ -4063,6 +4047,11 @@ var DriveMutex = class {
4063
4047
  };
4064
4048
  var driveMutex = new DriveMutex();
4065
4049
 
4050
+ // packages/core/src/inspect/extract-content-policy.ts
4051
+ var import_readability = require("@mozilla/readability");
4052
+ var import_jsdom = require("jsdom");
4053
+ var import_turndown = __toESM(require("turndown"));
4054
+
4066
4055
  // packages/core/src/page-state-script.ts
4067
4056
  var PAGE_STATE_SCRIPT = [
4068
4057
  "(() => {",
@@ -4172,6 +4161,32 @@ var PROCESS_STARTED_AT = new Date(
4172
4161
  Date.now() - Math.floor(process.uptime() * 1e3)
4173
4162
  ).toISOString();
4174
4163
 
4164
+ // packages/cli/src/open-path.ts
4165
+ var import_node_child_process4 = require("node:child_process");
4166
+ var shouldOpenInChrome = (target) => /^chrome(?:-extension)?:\/\//.test(target);
4167
+ var openPath = async (target) => {
4168
+ const platform = process.platform;
4169
+ if (platform === "darwin") {
4170
+ const args = shouldOpenInChrome(target) ? ["-a", "Google Chrome", target] : [target];
4171
+ const child2 = (0, import_node_child_process4.spawn)("open", args, { detached: true, stdio: "ignore" });
4172
+ child2.unref();
4173
+ return;
4174
+ }
4175
+ if (platform === "win32") {
4176
+ const child2 = (0, import_node_child_process4.spawn)("cmd", ["/c", "start", "", target], {
4177
+ detached: true,
4178
+ stdio: "ignore"
4179
+ });
4180
+ child2.unref();
4181
+ return;
4182
+ }
4183
+ const child = (0, import_node_child_process4.spawn)("xdg-open", [target], {
4184
+ detached: true,
4185
+ stdio: "ignore"
4186
+ });
4187
+ child.unref();
4188
+ };
4189
+
4175
4190
  // packages/cli/src/commands/open-artifacts.ts
4176
4191
  var registerOpenArtifactsCommand = (program2) => {
4177
4192
  program2.command("open-artifacts").description("Open the artifact folder for a session").requiredOption("--session-id <id>", "Session identifier").action(async (options, command) => {
@@ -4331,7 +4346,7 @@ var resolveSkillSourceDir = async () => {
4331
4346
  } catch {
4332
4347
  }
4333
4348
  const repoRoot = import_node_path8.default.resolve(rootDir, "..", "..");
4334
- const docsSkill = import_node_path8.default.join(repoRoot, "docs", "skills", "browser-bridge");
4349
+ const docsSkill = import_node_path8.default.join(repoRoot, "skills", "browser-bridge");
4335
4350
  try {
4336
4351
  await import_promises4.default.stat(docsSkill);
4337
4352
  return docsSkill;