@btraut/browser-bridge 0.13.1 → 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/CHANGELOG.md +31 -0
- package/README.md +28 -37
- package/dist/api.js +1013 -626
- package/dist/api.js.map +4 -4
- package/dist/index.js +323 -308
- package/dist/index.js.map +4 -4
- package/extension/dist/background.js +1016 -675
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/content.js +470 -76
- package/extension/dist/content.js.map +4 -4
- package/extension/dist/options-ui.js +2 -113
- package/extension/dist/options-ui.js.map +2 -2
- package/extension/manifest.json +2 -2
- package/package.json +1 -1
- package/skills/browser-bridge/SKILL.md +9 -0
- package/skills/browser-bridge/skill.json +1 -1
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
|
|
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 (!
|
|
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
|
|
349
|
-
const
|
|
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
|
|
358
|
-
const
|
|
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
|
|
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"
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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("
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
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
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
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
|
|
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 ??
|
|
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
|
|
3212
|
-
|
|
3213
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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,
|
|
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, "
|
|
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;
|