@btraut/browser-bridge 0.13.2 → 0.15.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 +51 -0
- package/README.md +53 -37
- package/dist/api.js +1792 -678
- package/dist/api.js.map +4 -4
- package/dist/index.js +666 -417
- package/dist/index.js.map +4 -4
- package/extension/dist/background.js +1484 -693
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/content.js +534 -77
- 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/dist/permissions-request-ui.js +111 -0
- package/extension/dist/permissions-request-ui.js.map +7 -0
- package/extension/manifest.json +3 -3
- package/package.json +1 -1
- package/skills/browser-bridge/SKILL.md +18 -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(
|
|
@@ -821,9 +663,10 @@ var createCoreReadinessController = (options = {}) => {
|
|
|
821
663
|
return;
|
|
822
664
|
}
|
|
823
665
|
if (!ensurePromise) {
|
|
824
|
-
ensurePromise =
|
|
666
|
+
ensurePromise = (async () => {
|
|
667
|
+
await ensureCoreRunning();
|
|
668
|
+
})().finally(() => {
|
|
825
669
|
ensurePromise = null;
|
|
826
|
-
throw error;
|
|
827
670
|
});
|
|
828
671
|
}
|
|
829
672
|
await ensurePromise;
|
|
@@ -1002,9 +845,7 @@ var DiagnosticsRuntimeEndpointSchema = import_zod3.z.object({
|
|
|
1002
845
|
port: import_zod3.z.number().finite().optional(),
|
|
1003
846
|
base_url: import_zod3.z.string().optional(),
|
|
1004
847
|
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()
|
|
848
|
+
port_source: import_zod3.z.string().optional()
|
|
1008
849
|
});
|
|
1009
850
|
var DiagnosticsRuntimeProcessSchema = import_zod3.z.object({
|
|
1010
851
|
component: import_zod3.z.enum(["cli", "mcp", "core"]).optional(),
|
|
@@ -1025,12 +866,13 @@ var DiagnosticsRuntimeContextSchema = import_zod3.z.object({
|
|
|
1025
866
|
process: DiagnosticsRuntimeProcessSchema.optional()
|
|
1026
867
|
}).optional(),
|
|
1027
868
|
extension: import_zod3.z.object({
|
|
869
|
+
extension_id: import_zod3.z.string().optional(),
|
|
1028
870
|
version: import_zod3.z.string().optional(),
|
|
1029
871
|
protocol_version: import_zod3.z.string().optional(),
|
|
1030
872
|
capability_negotiated: import_zod3.z.boolean().optional(),
|
|
1031
873
|
capabilities: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.boolean()).optional(),
|
|
1032
874
|
endpoint: DiagnosticsRuntimeEndpointSchema.optional(),
|
|
1033
|
-
port_source: import_zod3.z.enum(["default"
|
|
875
|
+
port_source: import_zod3.z.enum(["default"]).optional()
|
|
1034
876
|
}).optional()
|
|
1035
877
|
});
|
|
1036
878
|
var DiagnosticReportSchema = import_zod3.z.object({
|
|
@@ -1097,6 +939,63 @@ var SessionCloseInputSchema = SessionIdSchema;
|
|
|
1097
939
|
var SessionCloseOutputSchema = import_zod3.z.object({
|
|
1098
940
|
ok: import_zod3.z.boolean()
|
|
1099
941
|
});
|
|
942
|
+
var PermissionsModeSchema = import_zod3.z.enum(["granular", "bypass"]);
|
|
943
|
+
var PermissionsRequestSourceSchema = import_zod3.z.enum(["cli", "mcp", "api"]);
|
|
944
|
+
var PermissionsPendingRequestKindSchema = import_zod3.z.enum([
|
|
945
|
+
"allow_site",
|
|
946
|
+
"revoke_site",
|
|
947
|
+
"set_mode"
|
|
948
|
+
]);
|
|
949
|
+
var PermissionsPendingRequestStatusSchema = import_zod3.z.enum([
|
|
950
|
+
"pending",
|
|
951
|
+
"approved",
|
|
952
|
+
"denied",
|
|
953
|
+
"timed_out"
|
|
954
|
+
]);
|
|
955
|
+
var PermissionsSiteEntrySchema = import_zod3.z.object({
|
|
956
|
+
site: import_zod3.z.string().min(1),
|
|
957
|
+
created_at: import_zod3.z.string().datetime(),
|
|
958
|
+
last_used_at: import_zod3.z.string().datetime()
|
|
959
|
+
});
|
|
960
|
+
var PermissionsListInputSchema = import_zod3.z.object({}).strict().default({});
|
|
961
|
+
var PermissionsListOutputSchema = import_zod3.z.object({
|
|
962
|
+
sites: import_zod3.z.array(PermissionsSiteEntrySchema)
|
|
963
|
+
});
|
|
964
|
+
var PermissionsGetModeInputSchema = import_zod3.z.object({}).strict().default({});
|
|
965
|
+
var PermissionsGetModeOutputSchema = import_zod3.z.object({
|
|
966
|
+
mode: PermissionsModeSchema
|
|
967
|
+
});
|
|
968
|
+
var PermissionsPendingRequestSchema = import_zod3.z.object({
|
|
969
|
+
request_id: import_zod3.z.string().min(1),
|
|
970
|
+
kind: PermissionsPendingRequestKindSchema,
|
|
971
|
+
status: PermissionsPendingRequestStatusSchema,
|
|
972
|
+
requested_at: import_zod3.z.string().datetime(),
|
|
973
|
+
site: import_zod3.z.string().min(1).optional(),
|
|
974
|
+
mode: PermissionsModeSchema.optional(),
|
|
975
|
+
source: PermissionsRequestSourceSchema.optional(),
|
|
976
|
+
warning: import_zod3.z.string().optional(),
|
|
977
|
+
message: import_zod3.z.string().optional()
|
|
978
|
+
});
|
|
979
|
+
var PermissionsListPendingRequestsInputSchema = import_zod3.z.object({}).strict().default({});
|
|
980
|
+
var PermissionsListPendingRequestsOutputSchema = import_zod3.z.object({
|
|
981
|
+
requests: import_zod3.z.array(PermissionsPendingRequestSchema)
|
|
982
|
+
});
|
|
983
|
+
var PermissionsRequestAllowSiteInputSchema = import_zod3.z.object({
|
|
984
|
+
site: import_zod3.z.string().min(1),
|
|
985
|
+
timeout_ms: import_zod3.z.number().int().positive().max(3e5).optional(),
|
|
986
|
+
source: PermissionsRequestSourceSchema.optional()
|
|
987
|
+
});
|
|
988
|
+
var PermissionsRequestRevokeSiteInputSchema = import_zod3.z.object({
|
|
989
|
+
site: import_zod3.z.string().min(1),
|
|
990
|
+
timeout_ms: import_zod3.z.number().int().positive().max(3e5).optional(),
|
|
991
|
+
source: PermissionsRequestSourceSchema.optional()
|
|
992
|
+
});
|
|
993
|
+
var PermissionsRequestSetModeInputSchema = import_zod3.z.object({
|
|
994
|
+
mode: PermissionsModeSchema,
|
|
995
|
+
timeout_ms: import_zod3.z.number().int().positive().max(3e5).optional(),
|
|
996
|
+
source: PermissionsRequestSourceSchema.optional()
|
|
997
|
+
});
|
|
998
|
+
var PermissionsRequestOutputSchema = PermissionsPendingRequestSchema;
|
|
1100
999
|
var DriveWaitConditionSchema = import_zod3.z.object({
|
|
1101
1000
|
kind: import_zod3.z.enum(["locator_visible", "text_present", "url_matches"]),
|
|
1102
1001
|
value: import_zod3.z.string().min(1)
|
|
@@ -1105,7 +1004,7 @@ var DriveNavigateInputSchema = import_zod3.z.object({
|
|
|
1105
1004
|
session_id: import_zod3.z.string().min(1).optional(),
|
|
1106
1005
|
url: import_zod3.z.string().min(1),
|
|
1107
1006
|
tab_id: import_zod3.z.number().finite().optional(),
|
|
1108
|
-
wait: import_zod3.z.enum(["none", "domcontentloaded"]).default("domcontentloaded")
|
|
1007
|
+
wait: import_zod3.z.enum(["none", "domcontentloaded", "networkidle"]).default("domcontentloaded")
|
|
1109
1008
|
});
|
|
1110
1009
|
var DriveNavigateOutputSchema = OpResultSchema.extend({
|
|
1111
1010
|
session_id: import_zod3.z.string().min(1)
|
|
@@ -1274,6 +1173,8 @@ var InspectConsistencySchema = import_zod3.z.enum(["best_effort", "quiesce"]);
|
|
|
1274
1173
|
var TargetHintSchema = import_zod3.z.object({
|
|
1275
1174
|
url: import_zod3.z.string().min(1).optional(),
|
|
1276
1175
|
title: import_zod3.z.string().min(1).optional(),
|
|
1176
|
+
tab_id: import_zod3.z.number().finite().optional(),
|
|
1177
|
+
tabId: import_zod3.z.number().finite().optional(),
|
|
1277
1178
|
last_active_at: import_zod3.z.string().optional(),
|
|
1278
1179
|
lastActiveAt: import_zod3.z.string().optional()
|
|
1279
1180
|
});
|
|
@@ -1281,6 +1182,12 @@ var FormFieldInfoSchema = import_zod3.z.object({
|
|
|
1281
1182
|
name: import_zod3.z.string(),
|
|
1282
1183
|
type: import_zod3.z.string(),
|
|
1283
1184
|
value: import_zod3.z.string(),
|
|
1185
|
+
selector: import_zod3.z.string().optional(),
|
|
1186
|
+
label: import_zod3.z.string().optional(),
|
|
1187
|
+
placeholder: import_zod3.z.string().optional(),
|
|
1188
|
+
checked: import_zod3.z.boolean().optional(),
|
|
1189
|
+
disabled: import_zod3.z.boolean().optional(),
|
|
1190
|
+
visible: import_zod3.z.boolean().optional(),
|
|
1284
1191
|
options: import_zod3.z.array(import_zod3.z.string()).optional()
|
|
1285
1192
|
});
|
|
1286
1193
|
var FormInfoSchema = import_zod3.z.object({
|
|
@@ -1293,7 +1200,31 @@ var StorageEntrySchema = import_zod3.z.object({
|
|
|
1293
1200
|
key: import_zod3.z.string(),
|
|
1294
1201
|
value: import_zod3.z.string()
|
|
1295
1202
|
});
|
|
1203
|
+
var FocusedElementSchema = import_zod3.z.object({
|
|
1204
|
+
selector: import_zod3.z.string().optional(),
|
|
1205
|
+
name: import_zod3.z.string().optional(),
|
|
1206
|
+
label: import_zod3.z.string().optional(),
|
|
1207
|
+
role: import_zod3.z.string().optional(),
|
|
1208
|
+
type: import_zod3.z.string().optional(),
|
|
1209
|
+
text: import_zod3.z.string().optional()
|
|
1210
|
+
});
|
|
1211
|
+
var PageActionSchema = import_zod3.z.object({
|
|
1212
|
+
selector: import_zod3.z.string(),
|
|
1213
|
+
role: import_zod3.z.string(),
|
|
1214
|
+
name: import_zod3.z.string()
|
|
1215
|
+
});
|
|
1216
|
+
var StorageSummarySchema = import_zod3.z.object({
|
|
1217
|
+
localStorageCount: import_zod3.z.number().int().nonnegative(),
|
|
1218
|
+
sessionStorageCount: import_zod3.z.number().int().nonnegative(),
|
|
1219
|
+
cookieCount: import_zod3.z.number().int().nonnegative()
|
|
1220
|
+
});
|
|
1296
1221
|
var PageStateSchema = import_zod3.z.object({
|
|
1222
|
+
url: import_zod3.z.string().optional(),
|
|
1223
|
+
title: import_zod3.z.string().optional(),
|
|
1224
|
+
readyState: import_zod3.z.string().optional(),
|
|
1225
|
+
focused: FocusedElementSchema.optional(),
|
|
1226
|
+
primaryActions: import_zod3.z.array(PageActionSchema).optional(),
|
|
1227
|
+
storageSummary: StorageSummarySchema.optional(),
|
|
1297
1228
|
forms: import_zod3.z.array(FormInfoSchema),
|
|
1298
1229
|
localStorage: import_zod3.z.array(StorageEntrySchema),
|
|
1299
1230
|
sessionStorage: import_zod3.z.array(StorageEntrySchema),
|
|
@@ -1356,6 +1287,7 @@ var InspectFindOutputSchema = import_zod3.z.object({
|
|
|
1356
1287
|
warnings: import_zod3.z.array(import_zod3.z.string()).optional()
|
|
1357
1288
|
});
|
|
1358
1289
|
var InspectPageStateInputSchema = SessionIdSchema.extend({
|
|
1290
|
+
include_values: import_zod3.z.boolean().default(false),
|
|
1359
1291
|
target: TargetHintSchema.optional()
|
|
1360
1292
|
});
|
|
1361
1293
|
var InspectPageStateOutputSchema = PageStateSchema;
|
|
@@ -1366,6 +1298,7 @@ var InspectExtractContentFormatSchema = import_zod3.z.enum([
|
|
|
1366
1298
|
]);
|
|
1367
1299
|
var InspectExtractContentInputSchema = SessionIdSchema.extend({
|
|
1368
1300
|
format: InspectExtractContentFormatSchema.default("markdown"),
|
|
1301
|
+
consistency: InspectConsistencySchema.default("quiesce"),
|
|
1369
1302
|
include_metadata: import_zod3.z.boolean().default(true),
|
|
1370
1303
|
target: TargetHintSchema.optional()
|
|
1371
1304
|
});
|
|
@@ -1378,6 +1311,7 @@ var InspectExtractContentOutputSchema = import_zod3.z.object({
|
|
|
1378
1311
|
warnings: import_zod3.z.array(import_zod3.z.string()).optional()
|
|
1379
1312
|
});
|
|
1380
1313
|
var InspectConsoleListInputSchema = SessionIdSchema.extend({
|
|
1314
|
+
since: import_zod3.z.string().optional(),
|
|
1381
1315
|
target: TargetHintSchema.optional()
|
|
1382
1316
|
});
|
|
1383
1317
|
var ConsoleSourceLocationSchema = import_zod3.z.object({
|
|
@@ -1468,6 +1402,7 @@ var HealthCheckOutputSchema = import_zod3.z.object({
|
|
|
1468
1402
|
}).passthrough(),
|
|
1469
1403
|
extension: import_zod3.z.object({
|
|
1470
1404
|
connected: import_zod3.z.boolean(),
|
|
1405
|
+
extension_id: import_zod3.z.string().optional(),
|
|
1471
1406
|
last_seen_at: import_zod3.z.string().min(1).optional()
|
|
1472
1407
|
}).passthrough()
|
|
1473
1408
|
}).passthrough();
|
|
@@ -1482,6 +1417,7 @@ var import_zod4 = require("zod");
|
|
|
1482
1417
|
|
|
1483
1418
|
// packages/cli/src/core-client.ts
|
|
1484
1419
|
var import_node_child_process = require("node:child_process");
|
|
1420
|
+
var import_node_fs3 = require("node:fs");
|
|
1485
1421
|
var import_node_path3 = require("node:path");
|
|
1486
1422
|
var CoreClientError = class extends Error {
|
|
1487
1423
|
constructor(info) {
|
|
@@ -1504,6 +1440,50 @@ var resolveTimeoutMs2 = (timeoutMs) => {
|
|
|
1504
1440
|
};
|
|
1505
1441
|
var normalizePath = (path9) => path9.startsWith("/") ? path9 : `/${path9}`;
|
|
1506
1442
|
var durationMs = (startedAt) => Number((Number(process.hrtime.bigint() - startedAt) / 1e6).toFixed(3));
|
|
1443
|
+
var MAX_RESPONSE_PREVIEW_LENGTH = 200;
|
|
1444
|
+
var STALE_DAEMON_GRACE_MS = 1e3;
|
|
1445
|
+
var normalizeResponsePreview = (raw) => {
|
|
1446
|
+
const normalized = raw.replace(/\s+/g, " ").trim();
|
|
1447
|
+
if (normalized.length <= MAX_RESPONSE_PREVIEW_LENGTH) {
|
|
1448
|
+
return normalized;
|
|
1449
|
+
}
|
|
1450
|
+
return `${normalized.slice(0, MAX_RESPONSE_PREVIEW_LENGTH)}...`;
|
|
1451
|
+
};
|
|
1452
|
+
var getHeaderValue = (headers, name) => {
|
|
1453
|
+
if (!headers || typeof headers.get !== "function") {
|
|
1454
|
+
return void 0;
|
|
1455
|
+
}
|
|
1456
|
+
const value = headers.get(name);
|
|
1457
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
1458
|
+
};
|
|
1459
|
+
var buildInvalidCoreResponseError = (options) => {
|
|
1460
|
+
const details = {
|
|
1461
|
+
base_url: options.baseUrl,
|
|
1462
|
+
path: options.path,
|
|
1463
|
+
status: options.status,
|
|
1464
|
+
reason: options.kind === "empty" ? "core_empty_response" : "core_invalid_json_response",
|
|
1465
|
+
next_step: "Verify Browser Bridge core is reachable on the expected host and port, then retry."
|
|
1466
|
+
};
|
|
1467
|
+
if (options.contentType) {
|
|
1468
|
+
details.content_type = options.contentType;
|
|
1469
|
+
}
|
|
1470
|
+
if (options.responseText && options.responseText.trim().length > 0) {
|
|
1471
|
+
details.response_preview = normalizeResponsePreview(options.responseText);
|
|
1472
|
+
}
|
|
1473
|
+
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.";
|
|
1474
|
+
return new CoreClientError({
|
|
1475
|
+
code: "UNAVAILABLE",
|
|
1476
|
+
message,
|
|
1477
|
+
retryable: true,
|
|
1478
|
+
retry: {
|
|
1479
|
+
retryable: true,
|
|
1480
|
+
reason: options.kind === "empty" ? "core_empty_response" : "core_invalid_json_response",
|
|
1481
|
+
retry_after_ms: 250,
|
|
1482
|
+
max_attempts: 1
|
|
1483
|
+
},
|
|
1484
|
+
details
|
|
1485
|
+
});
|
|
1486
|
+
};
|
|
1507
1487
|
var createCoreClient = (options = {}) => {
|
|
1508
1488
|
const logger = options.logger ?? createJsonlLogger({
|
|
1509
1489
|
stream: "cli",
|
|
@@ -1513,6 +1493,15 @@ var createCoreClient = (options = {}) => {
|
|
|
1513
1493
|
const spawnImpl = options.spawnImpl ?? import_node_child_process.spawn;
|
|
1514
1494
|
const timeoutMs = resolveTimeoutMs2(options.timeoutMs);
|
|
1515
1495
|
const componentVersion = process.env.BROWSER_BRIDGE_VERSION ?? process.env.npm_package_version;
|
|
1496
|
+
const coreEntry = (0, import_node_path3.resolve)(__dirname, "api.js");
|
|
1497
|
+
const currentBuildTimeMs = options.currentBuildTimeMs ?? (() => {
|
|
1498
|
+
try {
|
|
1499
|
+
return (0, import_node_fs3.statSync)(coreEntry).mtimeMs;
|
|
1500
|
+
} catch {
|
|
1501
|
+
return void 0;
|
|
1502
|
+
}
|
|
1503
|
+
})();
|
|
1504
|
+
const killProcess = options.killProcess ?? ((pid) => process.kill(pid));
|
|
1516
1505
|
const readiness = createCoreReadinessController({
|
|
1517
1506
|
host: options.host,
|
|
1518
1507
|
port: options.port,
|
|
@@ -1524,7 +1513,7 @@ var createCoreClient = (options = {}) => {
|
|
|
1524
1513
|
logger,
|
|
1525
1514
|
logPrefix: "cli.core",
|
|
1526
1515
|
spawnDaemon: (runtime) => {
|
|
1527
|
-
const
|
|
1516
|
+
const coreEntry2 = (0, import_node_path3.resolve)(__dirname, "api.js");
|
|
1528
1517
|
const startOptions = [];
|
|
1529
1518
|
if (runtime.hostSource === "option" || runtime.hostSource === "env") {
|
|
1530
1519
|
startOptions.push(`host: ${JSON.stringify(runtime.host)}`);
|
|
@@ -1533,7 +1522,7 @@ var createCoreClient = (options = {}) => {
|
|
|
1533
1522
|
startOptions.push(`port: ${runtime.port}`);
|
|
1534
1523
|
}
|
|
1535
1524
|
const script = `const { startCoreServer } = require(${JSON.stringify(
|
|
1536
|
-
|
|
1525
|
+
coreEntry2
|
|
1537
1526
|
)});
|
|
1538
1527
|
startCoreServer({ ${startOptions.join(
|
|
1539
1528
|
", "
|
|
@@ -1617,6 +1606,7 @@ startCoreServer({ ${startOptions.join(
|
|
|
1617
1606
|
});
|
|
1618
1607
|
throw error;
|
|
1619
1608
|
}
|
|
1609
|
+
const contentType = getHeaderValue(response.headers, "content-type");
|
|
1620
1610
|
const raw = await response.text();
|
|
1621
1611
|
if (!raw) {
|
|
1622
1612
|
logger.warn("cli.core.request.empty_response", {
|
|
@@ -1624,9 +1614,16 @@ startCoreServer({ ${startOptions.join(
|
|
|
1624
1614
|
path: requestPath,
|
|
1625
1615
|
base_url: readiness.baseUrl,
|
|
1626
1616
|
status: response.status,
|
|
1617
|
+
content_type: contentType,
|
|
1627
1618
|
duration_ms: durationMs(startedAt)
|
|
1628
1619
|
});
|
|
1629
|
-
throw
|
|
1620
|
+
throw buildInvalidCoreResponseError({
|
|
1621
|
+
kind: "empty",
|
|
1622
|
+
status: response.status,
|
|
1623
|
+
baseUrl: readiness.baseUrl,
|
|
1624
|
+
path: requestPath,
|
|
1625
|
+
contentType
|
|
1626
|
+
});
|
|
1630
1627
|
}
|
|
1631
1628
|
try {
|
|
1632
1629
|
const parsed = JSON.parse(raw);
|
|
@@ -1639,23 +1636,83 @@ startCoreServer({ ${startOptions.join(
|
|
|
1639
1636
|
});
|
|
1640
1637
|
return parsed;
|
|
1641
1638
|
} catch (error) {
|
|
1642
|
-
const message = error instanceof Error ? error.message : "Unknown JSON parse error";
|
|
1643
1639
|
logger.error("cli.core.request.invalid_json", {
|
|
1644
1640
|
method,
|
|
1645
1641
|
path: requestPath,
|
|
1646
1642
|
base_url: readiness.baseUrl,
|
|
1647
1643
|
status: response.status,
|
|
1644
|
+
content_type: contentType,
|
|
1645
|
+
response_preview: normalizeResponsePreview(raw),
|
|
1648
1646
|
duration_ms: durationMs(startedAt),
|
|
1649
1647
|
error
|
|
1650
1648
|
});
|
|
1651
|
-
throw
|
|
1649
|
+
throw buildInvalidCoreResponseError({
|
|
1650
|
+
kind: "invalid_json",
|
|
1651
|
+
status: response.status,
|
|
1652
|
+
baseUrl: readiness.baseUrl,
|
|
1653
|
+
path: requestPath,
|
|
1654
|
+
contentType,
|
|
1655
|
+
responseText: raw
|
|
1656
|
+
});
|
|
1652
1657
|
}
|
|
1653
1658
|
} finally {
|
|
1654
1659
|
clearTimeout(timeout);
|
|
1655
1660
|
}
|
|
1656
1661
|
};
|
|
1657
|
-
const
|
|
1662
|
+
const maybeRestartStaleDaemon = async () => {
|
|
1663
|
+
if (currentBuildTimeMs === void 0) {
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
let payload;
|
|
1667
|
+
try {
|
|
1668
|
+
payload = await requestJson(
|
|
1669
|
+
"POST",
|
|
1670
|
+
"/health/check",
|
|
1671
|
+
{}
|
|
1672
|
+
);
|
|
1673
|
+
} catch {
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
if (!payload.ok || !payload.result?.started_at) {
|
|
1677
|
+
return;
|
|
1678
|
+
}
|
|
1679
|
+
const startedAtMs = Date.parse(payload.result.started_at);
|
|
1680
|
+
if (!Number.isFinite(startedAtMs)) {
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
if (startedAtMs + STALE_DAEMON_GRACE_MS >= currentBuildTimeMs) {
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1686
|
+
const pidValue = payload.result.pid;
|
|
1687
|
+
if (!Number.isInteger(pidValue) || pidValue === process.pid) {
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1690
|
+
const pid = pidValue;
|
|
1691
|
+
logger.warn("cli.core.ensure_ready.stale_daemon", {
|
|
1692
|
+
base_url: readiness.baseUrl,
|
|
1693
|
+
pid,
|
|
1694
|
+
started_at: payload.result.started_at,
|
|
1695
|
+
current_build_time_ms: currentBuildTimeMs
|
|
1696
|
+
});
|
|
1697
|
+
try {
|
|
1698
|
+
killProcess(pid);
|
|
1699
|
+
} catch (error) {
|
|
1700
|
+
logger.warn("cli.core.ensure_ready.stale_daemon_kill_failed", {
|
|
1701
|
+
base_url: readiness.baseUrl,
|
|
1702
|
+
pid,
|
|
1703
|
+
error
|
|
1704
|
+
});
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1707
|
+
await new Promise((resolve4) => setTimeout(resolve4, 150));
|
|
1658
1708
|
await readiness.ensureReady();
|
|
1709
|
+
};
|
|
1710
|
+
const ensureReady = async () => {
|
|
1711
|
+
await readiness.ensureReady();
|
|
1712
|
+
await maybeRestartStaleDaemon();
|
|
1713
|
+
};
|
|
1714
|
+
const post = async (path9, body) => {
|
|
1715
|
+
await ensureReady();
|
|
1659
1716
|
readiness.refreshRuntime();
|
|
1660
1717
|
const payload = path9 === "/diagnostics/doctor" && (!body || typeof body === "object" && !Array.isArray(body)) ? {
|
|
1661
1718
|
...body && typeof body === "object" ? body : {},
|
|
@@ -1665,9 +1722,7 @@ startCoreServer({ ${startOptions.join(
|
|
|
1665
1722
|
port: readiness.runtime.port,
|
|
1666
1723
|
base_url: readiness.baseUrl,
|
|
1667
1724
|
host_source: readiness.runtime.hostSource,
|
|
1668
|
-
port_source: readiness.runtime.portSource
|
|
1669
|
-
metadata_path: readiness.runtime.metadataPath,
|
|
1670
|
-
isolated_mode: readiness.runtime.isolatedMode
|
|
1725
|
+
port_source: readiness.runtime.portSource
|
|
1671
1726
|
},
|
|
1672
1727
|
process: {
|
|
1673
1728
|
component: "cli",
|
|
@@ -1685,7 +1740,7 @@ startCoreServer({ ${startOptions.join(
|
|
|
1685
1740
|
get baseUrl() {
|
|
1686
1741
|
return readiness.baseUrl;
|
|
1687
1742
|
},
|
|
1688
|
-
ensureReady
|
|
1743
|
+
ensureReady,
|
|
1689
1744
|
post
|
|
1690
1745
|
};
|
|
1691
1746
|
};
|
|
@@ -1962,35 +2017,9 @@ var registerDiagnosticsCommands = (program2) => {
|
|
|
1962
2017
|
});
|
|
1963
2018
|
};
|
|
1964
2019
|
|
|
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
2020
|
// packages/cli/src/commands/dev.ts
|
|
1990
2021
|
var ENV_EXTENSION_ID = "BROWSER_BRIDGE_EXTENSION_ID";
|
|
1991
|
-
var
|
|
1992
|
-
var ACTIVATION_PORT_PARAM = "corePort";
|
|
1993
|
-
var ACTIVATION_WORKTREE_PARAM = "worktreeId";
|
|
2022
|
+
var INSPECT_PROBE_RETRY_DELAYS_MS = [150, 300, 600];
|
|
1994
2023
|
var normalizeToken = (value) => {
|
|
1995
2024
|
if (typeof value !== "string") {
|
|
1996
2025
|
return void 0;
|
|
@@ -2007,45 +2036,102 @@ var resolveActivationExtensionId = (options) => {
|
|
|
2007
2036
|
if (envId) {
|
|
2008
2037
|
return { extensionId: envId, source: "env" };
|
|
2009
2038
|
}
|
|
2010
|
-
const metadataId = normalizeToken(options.metadataExtensionId);
|
|
2011
|
-
if (metadataId) {
|
|
2012
|
-
return { extensionId: metadataId, source: "metadata" };
|
|
2013
|
-
}
|
|
2014
2039
|
return null;
|
|
2015
2040
|
};
|
|
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 = {}) => {
|
|
2041
|
+
var resolveRuntimeForCommand = (options) => {
|
|
2036
2042
|
const runtimeOptions = {
|
|
2037
2043
|
host: options.host,
|
|
2038
2044
|
port: options.port,
|
|
2039
2045
|
strictEnvPort: true
|
|
2040
2046
|
};
|
|
2041
|
-
if (overrides.isolatedMode !== void 0) {
|
|
2042
|
-
runtimeOptions.isolatedMode = overrides.isolatedMode;
|
|
2043
|
-
}
|
|
2044
2047
|
return resolveCoreRuntime(runtimeOptions);
|
|
2045
2048
|
};
|
|
2049
|
+
var hasPassingCheck = (report, name) => report?.checks?.some((check) => check.name === name && check.ok) ?? false;
|
|
2050
|
+
var getReportedExtensionId = (report) => normalizeToken(report?.runtime?.extension?.extension_id);
|
|
2051
|
+
var inspectCapabilityReady = (report, expectedExtensionId) => {
|
|
2052
|
+
const reportedExtensionId = getReportedExtensionId(report);
|
|
2053
|
+
const extensionIdMatch = !expectedExtensionId || !reportedExtensionId || reportedExtensionId === expectedExtensionId;
|
|
2054
|
+
return extensionIdMatch && hasPassingCheck(report, "inspect.capability");
|
|
2055
|
+
};
|
|
2056
|
+
var sleep = async (ms) => {
|
|
2057
|
+
await new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
2058
|
+
};
|
|
2059
|
+
var shouldRetryInspectProbe = (report, expectedExtensionId) => {
|
|
2060
|
+
if (inspectCapabilityReady(report, expectedExtensionId)) {
|
|
2061
|
+
return false;
|
|
2062
|
+
}
|
|
2063
|
+
const observedExtensionId = getReportedExtensionId(report);
|
|
2064
|
+
if (expectedExtensionId && observedExtensionId && observedExtensionId !== expectedExtensionId) {
|
|
2065
|
+
return false;
|
|
2066
|
+
}
|
|
2067
|
+
const extensionConnected = report?.extension?.connected ?? false;
|
|
2068
|
+
const capabilityNegotiated = report?.runtime?.extension?.capability_negotiated === true || hasPassingCheck(report, "runtime.extension.capability_negotiated");
|
|
2069
|
+
return !extensionConnected || !capabilityNegotiated;
|
|
2070
|
+
};
|
|
2071
|
+
var readDiagnosticReport = async (runtime) => {
|
|
2072
|
+
const client = createCoreClient({
|
|
2073
|
+
host: runtime.host,
|
|
2074
|
+
port: runtime.port,
|
|
2075
|
+
ensureDaemon: true
|
|
2076
|
+
});
|
|
2077
|
+
const envelope2 = await client.post(
|
|
2078
|
+
"/diagnostics/doctor",
|
|
2079
|
+
{}
|
|
2080
|
+
);
|
|
2081
|
+
return envelope2.ok ? envelope2.result : void 0;
|
|
2082
|
+
};
|
|
2083
|
+
var readDiagnosticReportWithRetry = async (runtime, expectedExtensionId) => {
|
|
2084
|
+
let report;
|
|
2085
|
+
for (let attempt = 0; attempt <= INSPECT_PROBE_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
2086
|
+
if (attempt > 0) {
|
|
2087
|
+
const delayMs = INSPECT_PROBE_RETRY_DELAYS_MS[attempt - 1] ?? 0;
|
|
2088
|
+
if (delayMs > 0) {
|
|
2089
|
+
await sleep(delayMs);
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
report = await readDiagnosticReport(runtime);
|
|
2093
|
+
if (!shouldRetryInspectProbe(report, expectedExtensionId)) {
|
|
2094
|
+
return report;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
return report;
|
|
2098
|
+
};
|
|
2099
|
+
var buildInspectCapabilityError = (runtime, report, expectedExtension) => {
|
|
2100
|
+
const observedExtensionId = getReportedExtensionId(report);
|
|
2101
|
+
if (expectedExtension && observedExtensionId && observedExtensionId !== expectedExtension.extensionId) {
|
|
2102
|
+
return new CliError({
|
|
2103
|
+
code: "FAILED_PRECONDITION",
|
|
2104
|
+
message: "Inspect capability is available, but the connected extension does not match the requested extension id.",
|
|
2105
|
+
retryable: false,
|
|
2106
|
+
details: {
|
|
2107
|
+
host: runtime.host,
|
|
2108
|
+
port: runtime.port,
|
|
2109
|
+
expectedExtensionId: expectedExtension.extensionId,
|
|
2110
|
+
expectedExtensionIdSource: expectedExtension.source,
|
|
2111
|
+
observedExtensionId,
|
|
2112
|
+
next_step: "Clear the stale extension-id override or reload the intended Browser Bridge extension, then retry."
|
|
2113
|
+
}
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
return new CliError({
|
|
2117
|
+
code: "FAILED_PRECONDITION",
|
|
2118
|
+
message: "Inspect capability is unavailable in a build where it should already be enabled.",
|
|
2119
|
+
retryable: true,
|
|
2120
|
+
details: {
|
|
2121
|
+
host: runtime.host,
|
|
2122
|
+
port: runtime.port,
|
|
2123
|
+
expectedExtensionId: expectedExtension?.extensionId,
|
|
2124
|
+
expectedExtensionIdSource: expectedExtension?.source,
|
|
2125
|
+
observedConnected: report?.extension?.connected ?? false,
|
|
2126
|
+
observedExtensionId,
|
|
2127
|
+
observedInspectCapability: hasPassingCheck(report, "inspect.capability"),
|
|
2128
|
+
next_step: "Restart the Browser Bridge core daemon, then reload or update the Browser Bridge extension and retry."
|
|
2129
|
+
}
|
|
2130
|
+
});
|
|
2131
|
+
};
|
|
2046
2132
|
var registerDevCommands = (program2) => {
|
|
2047
2133
|
const dev = program2.command("dev").description("Development commands");
|
|
2048
|
-
dev.command("info").description("Print resolved runtime details for the current
|
|
2134
|
+
dev.command("info").description("Print resolved runtime details for the current environment").action(async (_options, command) => {
|
|
2049
2135
|
await runLocal(command, async (globalOptions) => {
|
|
2050
2136
|
const runtime = resolveRuntimeForCommand(globalOptions);
|
|
2051
2137
|
const logDir = resolveLogDirectory({ gitRoot: runtime.gitRoot });
|
|
@@ -2056,8 +2142,6 @@ var registerDevCommands = (program2) => {
|
|
|
2056
2142
|
hostSource: runtime.hostSource,
|
|
2057
2143
|
port: runtime.port,
|
|
2058
2144
|
portSource: runtime.portSource,
|
|
2059
|
-
deterministicPort: runtime.deterministicPort,
|
|
2060
|
-
worktreeId: runtime.worktreeId,
|
|
2061
2145
|
metadataPath: runtime.metadataPath,
|
|
2062
2146
|
logDir,
|
|
2063
2147
|
metadataSnapshot: runtime.metadata
|
|
@@ -2065,51 +2149,43 @@ var registerDevCommands = (program2) => {
|
|
|
2065
2149
|
};
|
|
2066
2150
|
});
|
|
2067
2151
|
});
|
|
2068
|
-
dev.command("
|
|
2069
|
-
"Enable isolated worktree routing and open extension options for activation"
|
|
2070
|
-
).option(
|
|
2152
|
+
dev.command("enable-inspect").description("Compatibility helper that verifies inspect capability").option(
|
|
2071
2153
|
"--extension-id <id>",
|
|
2072
|
-
"Chrome extension id to
|
|
2154
|
+
"Chrome extension id to verify against while checking inspect capability"
|
|
2073
2155
|
).action(async (options, command) => {
|
|
2074
2156
|
await runLocal(command, async (globalOptions) => {
|
|
2075
|
-
const runtime = resolveRuntimeForCommand(globalOptions
|
|
2076
|
-
|
|
2077
|
-
});
|
|
2078
|
-
const extension = resolveActivationExtensionId({
|
|
2157
|
+
const runtime = resolveRuntimeForCommand(globalOptions);
|
|
2158
|
+
let resolvedExtension = resolveActivationExtensionId({
|
|
2079
2159
|
optionExtensionId: options.extensionId,
|
|
2080
|
-
envExtensionId: process.env[ENV_EXTENSION_ID]
|
|
2081
|
-
metadataExtensionId: runtime.metadata?.extension_id
|
|
2160
|
+
envExtensionId: process.env[ENV_EXTENSION_ID]
|
|
2082
2161
|
});
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
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
|
-
});
|
|
2092
|
-
}
|
|
2093
|
-
const metadataPath = writeRuntimeMetadata(
|
|
2094
|
-
buildPersistedRuntimeMetadata(runtime, extension.extensionId),
|
|
2095
|
-
{ metadataPath: runtime.metadataPath }
|
|
2162
|
+
const report = await readDiagnosticReportWithRetry(
|
|
2163
|
+
runtime,
|
|
2164
|
+
resolvedExtension?.extensionId
|
|
2096
2165
|
);
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2166
|
+
if (!resolvedExtension) {
|
|
2167
|
+
const reportedExtensionId = getReportedExtensionId(report);
|
|
2168
|
+
if (reportedExtensionId) {
|
|
2169
|
+
resolvedExtension = {
|
|
2170
|
+
extensionId: reportedExtensionId,
|
|
2171
|
+
source: "connected"
|
|
2172
|
+
};
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
if (!inspectCapabilityReady(report, resolvedExtension?.extensionId)) {
|
|
2176
|
+
throw buildInspectCapabilityError(runtime, report, resolvedExtension);
|
|
2177
|
+
}
|
|
2103
2178
|
return {
|
|
2104
2179
|
ok: true,
|
|
2105
2180
|
result: {
|
|
2106
|
-
extensionId: extension.extensionId,
|
|
2107
|
-
extensionIdSource: extension.source,
|
|
2108
2181
|
host: runtime.host,
|
|
2109
2182
|
port: runtime.port,
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2183
|
+
inspectAlwaysEnabled: true,
|
|
2184
|
+
checkedWithDiagnostics: true,
|
|
2185
|
+
...resolvedExtension ? {
|
|
2186
|
+
extensionId: resolvedExtension.extensionId,
|
|
2187
|
+
extensionIdSource: resolvedExtension.source
|
|
2188
|
+
} : {}
|
|
2113
2189
|
}
|
|
2114
2190
|
};
|
|
2115
2191
|
});
|
|
@@ -2198,7 +2274,7 @@ var registerDriveCommands = (program2) => {
|
|
|
2198
2274
|
drive.command("navigate").description("Navigate to a URL").option(
|
|
2199
2275
|
"--session-id <id>",
|
|
2200
2276
|
"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) => {
|
|
2277
|
+
).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
2278
|
await runCommand(command, (client) => {
|
|
2203
2279
|
const payload = parseInput(DriveNavigateInputSchema, {
|
|
2204
2280
|
...options.sessionId ? { session_id: options.sessionId } : {},
|
|
@@ -2476,9 +2552,23 @@ var registerDriveCommands = (program2) => {
|
|
|
2476
2552
|
};
|
|
2477
2553
|
|
|
2478
2554
|
// packages/cli/src/commands/inspect.ts
|
|
2555
|
+
var parseNumber4 = (value) => {
|
|
2556
|
+
if (value === void 0 || value === null || value === "") {
|
|
2557
|
+
return void 0;
|
|
2558
|
+
}
|
|
2559
|
+
const parsed = Number(value);
|
|
2560
|
+
return Number.isFinite(parsed) ? parsed : Number.NaN;
|
|
2561
|
+
};
|
|
2562
|
+
var buildTargetHint = (options) => {
|
|
2563
|
+
const tabId = parseNumber4(options.tabId);
|
|
2564
|
+
if (tabId === void 0) {
|
|
2565
|
+
return void 0;
|
|
2566
|
+
}
|
|
2567
|
+
return { tab_id: tabId };
|
|
2568
|
+
};
|
|
2479
2569
|
var registerInspectCommands = (program2) => {
|
|
2480
2570
|
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) => {
|
|
2571
|
+
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
2572
|
await runCommand(command, (client) => {
|
|
2483
2573
|
const payload = parseInput(InspectDomSnapshotInputSchema, {
|
|
2484
2574
|
session_id: options.sessionId,
|
|
@@ -2487,7 +2577,8 @@ var registerInspectCommands = (program2) => {
|
|
|
2487
2577
|
interactive: options.interactive,
|
|
2488
2578
|
compact: options.compact,
|
|
2489
2579
|
max_nodes: options.maxNodes,
|
|
2490
|
-
selector: options.selector
|
|
2580
|
+
selector: options.selector,
|
|
2581
|
+
target: buildTargetHint(options)
|
|
2491
2582
|
});
|
|
2492
2583
|
return client.post("/inspect/dom_snapshot", payload);
|
|
2493
2584
|
});
|
|
@@ -2500,7 +2591,7 @@ var registerInspectCommands = (program2) => {
|
|
|
2500
2591
|
return client.post("/inspect/dom_diff", payload);
|
|
2501
2592
|
});
|
|
2502
2593
|
});
|
|
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) => {
|
|
2594
|
+
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
2595
|
await runCommand(command, (client) => {
|
|
2505
2596
|
const normalizedKind = String(kind ?? "").toLowerCase();
|
|
2506
2597
|
let payload;
|
|
@@ -2509,19 +2600,22 @@ var registerInspectCommands = (program2) => {
|
|
|
2509
2600
|
session_id: options.sessionId,
|
|
2510
2601
|
kind: "role",
|
|
2511
2602
|
role: value,
|
|
2512
|
-
name: options.name
|
|
2603
|
+
name: options.name,
|
|
2604
|
+
target: buildTargetHint(options)
|
|
2513
2605
|
};
|
|
2514
2606
|
} else if (normalizedKind === "text") {
|
|
2515
2607
|
payload = {
|
|
2516
2608
|
session_id: options.sessionId,
|
|
2517
2609
|
kind: "text",
|
|
2518
|
-
text: value
|
|
2610
|
+
text: value,
|
|
2611
|
+
target: buildTargetHint(options)
|
|
2519
2612
|
};
|
|
2520
2613
|
} else if (normalizedKind === "label") {
|
|
2521
2614
|
payload = {
|
|
2522
2615
|
session_id: options.sessionId,
|
|
2523
2616
|
kind: "label",
|
|
2524
|
-
label: value
|
|
2617
|
+
label: value,
|
|
2618
|
+
target: buildTargetHint(options)
|
|
2525
2619
|
};
|
|
2526
2620
|
} else {
|
|
2527
2621
|
throw new CliError({
|
|
@@ -2535,53 +2629,65 @@ var registerInspectCommands = (program2) => {
|
|
|
2535
2629
|
return client.post("/inspect/find", parsed);
|
|
2536
2630
|
});
|
|
2537
2631
|
});
|
|
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(
|
|
2632
|
+
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(
|
|
2633
|
+
"--consistency <mode>",
|
|
2634
|
+
"Capture consistency (best_effort, quiesce)"
|
|
2635
|
+
).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
2636
|
await runCommand(command, (client) => {
|
|
2540
2637
|
const payload = parseInput(InspectExtractContentInputSchema, {
|
|
2541
2638
|
session_id: options.sessionId,
|
|
2542
2639
|
format: options.format,
|
|
2543
|
-
|
|
2640
|
+
consistency: options.consistency,
|
|
2641
|
+
include_metadata: options.includeMetadata,
|
|
2642
|
+
target: buildTargetHint(options)
|
|
2544
2643
|
});
|
|
2545
2644
|
return client.post("/inspect/extract_content", payload);
|
|
2546
2645
|
});
|
|
2547
2646
|
});
|
|
2548
|
-
inspect.command("page-state").description("Capture form, storage, and cookie state").requiredOption("--session-id <id>", "Session identifier").action(async (options, command) => {
|
|
2647
|
+
inspect.command("page-state").description("Capture form, storage, and cookie state").requiredOption("--session-id <id>", "Session identifier").option("--include-values", "Include captured values instead of redacting").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
|
|
2549
2648
|
await runCommand(command, (client) => {
|
|
2550
2649
|
const payload = parseInput(InspectPageStateInputSchema, {
|
|
2551
|
-
session_id: options.sessionId
|
|
2650
|
+
session_id: options.sessionId,
|
|
2651
|
+
include_values: options.includeValues,
|
|
2652
|
+
target: buildTargetHint(options)
|
|
2552
2653
|
});
|
|
2553
2654
|
return client.post("/inspect/page_state", payload);
|
|
2554
2655
|
});
|
|
2555
2656
|
});
|
|
2556
|
-
inspect.command("console-list").description("Fetch console entries").requiredOption("--session-id <id>", "Session identifier").action(async (options, command) => {
|
|
2657
|
+
inspect.command("console-list").description("Fetch console entries").requiredOption("--session-id <id>", "Session identifier").option("--since <iso>", "Only include entries at or after this timestamp").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
|
|
2557
2658
|
await runCommand(command, (client) => {
|
|
2558
2659
|
const payload = parseInput(InspectConsoleListInputSchema, {
|
|
2559
|
-
session_id: options.sessionId
|
|
2660
|
+
session_id: options.sessionId,
|
|
2661
|
+
since: options.since,
|
|
2662
|
+
target: buildTargetHint(options)
|
|
2560
2663
|
});
|
|
2561
2664
|
return client.post("/inspect/console_list", payload);
|
|
2562
2665
|
});
|
|
2563
2666
|
});
|
|
2564
|
-
inspect.command("network-har").description("Fetch network HAR").requiredOption("--session-id <id>", "Session identifier").action(async (options, command) => {
|
|
2667
|
+
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
2668
|
await runCommand(command, (client) => {
|
|
2566
2669
|
const payload = parseInput(InspectNetworkHarInputSchema, {
|
|
2567
|
-
session_id: options.sessionId
|
|
2670
|
+
session_id: options.sessionId,
|
|
2671
|
+
target: buildTargetHint(options)
|
|
2568
2672
|
});
|
|
2569
2673
|
return client.post("/inspect/network_har", payload);
|
|
2570
2674
|
});
|
|
2571
2675
|
});
|
|
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) => {
|
|
2676
|
+
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
2677
|
await runCommand(command, (client) => {
|
|
2574
2678
|
const payload = parseInput(InspectEvaluateInputSchema, {
|
|
2575
2679
|
session_id: options.sessionId,
|
|
2576
|
-
expression: options.expression
|
|
2680
|
+
expression: options.expression,
|
|
2681
|
+
target: buildTargetHint(options)
|
|
2577
2682
|
});
|
|
2578
2683
|
return client.post("/inspect/evaluate", payload);
|
|
2579
2684
|
});
|
|
2580
2685
|
});
|
|
2581
|
-
inspect.command("performance-metrics").description("Fetch performance metrics").requiredOption("--session-id <id>", "Session identifier").action(async (options, command) => {
|
|
2686
|
+
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
2687
|
await runCommand(command, (client) => {
|
|
2583
2688
|
const payload = parseInput(InspectPerformanceMetricsInputSchema, {
|
|
2584
|
-
session_id: options.sessionId
|
|
2689
|
+
session_id: options.sessionId,
|
|
2690
|
+
target: buildTargetHint(options)
|
|
2585
2691
|
});
|
|
2586
2692
|
return client.post("/inspect/performance_metrics", payload);
|
|
2587
2693
|
});
|
|
@@ -2589,7 +2695,7 @@ var registerInspectCommands = (program2) => {
|
|
|
2589
2695
|
};
|
|
2590
2696
|
|
|
2591
2697
|
// packages/mcp-adapter/src/core-client.ts
|
|
2592
|
-
var
|
|
2698
|
+
var import_node_child_process2 = require("node:child_process");
|
|
2593
2699
|
var import_node_path4 = require("node:path");
|
|
2594
2700
|
var DEFAULT_TIMEOUT_MS3 = 3e4;
|
|
2595
2701
|
var normalizePath2 = (path9) => path9.startsWith("/") ? path9 : `/${path9}`;
|
|
@@ -2618,7 +2724,7 @@ var createCoreClient2 = (options = {}) => {
|
|
|
2618
2724
|
}).child({ scope: "core-client" });
|
|
2619
2725
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
|
|
2620
2726
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
2621
|
-
const spawnImpl = options.spawnImpl ??
|
|
2727
|
+
const spawnImpl = options.spawnImpl ?? import_node_child_process2.spawn;
|
|
2622
2728
|
const ensureDaemon = options.ensureDaemon ?? false;
|
|
2623
2729
|
const componentVersion = options.componentVersion ?? process.env.BROWSER_BRIDGE_VERSION ?? process.env.npm_package_version;
|
|
2624
2730
|
const readiness = createCoreReadinessController({
|
|
@@ -2750,9 +2856,7 @@ startCoreServer({ ${startOptions.join(
|
|
|
2750
2856
|
port: readiness.runtime.port,
|
|
2751
2857
|
base_url: readiness.baseUrl,
|
|
2752
2858
|
host_source: readiness.runtime.hostSource,
|
|
2753
|
-
port_source: readiness.runtime.portSource
|
|
2754
|
-
metadata_path: readiness.runtime.metadataPath,
|
|
2755
|
-
isolated_mode: readiness.runtime.isolatedMode
|
|
2859
|
+
port_source: readiness.runtime.portSource
|
|
2756
2860
|
},
|
|
2757
2861
|
process: {
|
|
2758
2862
|
component: "mcp",
|
|
@@ -2798,6 +2902,74 @@ var toInternalErrorEnvelope = (error) => ({
|
|
|
2798
2902
|
});
|
|
2799
2903
|
var envelope = (schema) => successEnvelopeSchema(schema);
|
|
2800
2904
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2905
|
+
var readSessionId = (args) => {
|
|
2906
|
+
if (!isRecord(args)) {
|
|
2907
|
+
return void 0;
|
|
2908
|
+
}
|
|
2909
|
+
const sessionId = args.session_id;
|
|
2910
|
+
return typeof sessionId === "string" && sessionId.length > 0 ? sessionId : void 0;
|
|
2911
|
+
};
|
|
2912
|
+
var withPermissionsSource = (source) => (args) => isRecord(args) ? {
|
|
2913
|
+
...args,
|
|
2914
|
+
source
|
|
2915
|
+
} : args;
|
|
2916
|
+
var supportsSessionMigration = (corePath) => corePath.startsWith("/drive/") || corePath.startsWith("/inspect/") || corePath.startsWith("/artifacts/") || corePath === "/diagnostics/doctor";
|
|
2917
|
+
var isSessionNotFoundEnvelope = (envelopeResult) => {
|
|
2918
|
+
if (envelopeResult.ok) {
|
|
2919
|
+
return false;
|
|
2920
|
+
}
|
|
2921
|
+
const details = envelopeResult.error.details;
|
|
2922
|
+
return envelopeResult.error.code === "NOT_FOUND" && isRecord(details) && details.reason === "session_not_found";
|
|
2923
|
+
};
|
|
2924
|
+
var addSessionRecoveryHint = (envelopeResult) => {
|
|
2925
|
+
if (envelopeResult.ok) {
|
|
2926
|
+
return envelopeResult;
|
|
2927
|
+
}
|
|
2928
|
+
return {
|
|
2929
|
+
ok: false,
|
|
2930
|
+
error: {
|
|
2931
|
+
...envelopeResult.error,
|
|
2932
|
+
details: {
|
|
2933
|
+
...isRecord(envelopeResult.error.details) ? envelopeResult.error.details : {},
|
|
2934
|
+
recover_action: "session.create"
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
};
|
|
2938
|
+
};
|
|
2939
|
+
var addSessionMigrationNotice = (envelopeResult, staleSessionId, replacementSessionId) => {
|
|
2940
|
+
if (envelopeResult.ok) {
|
|
2941
|
+
if (!isRecord(envelopeResult.result)) {
|
|
2942
|
+
return envelopeResult;
|
|
2943
|
+
}
|
|
2944
|
+
const warning = `Session ${staleSessionId} became stale after runtime switch; retried with ${replacementSessionId}.`;
|
|
2945
|
+
const existingWarnings = Array.isArray(envelopeResult.result.warnings) ? envelopeResult.result.warnings.filter(
|
|
2946
|
+
(item) => typeof item === "string"
|
|
2947
|
+
) : [];
|
|
2948
|
+
return {
|
|
2949
|
+
ok: true,
|
|
2950
|
+
result: {
|
|
2951
|
+
...envelopeResult.result,
|
|
2952
|
+
warnings: existingWarnings.includes(warning) ? existingWarnings : [...existingWarnings, warning],
|
|
2953
|
+
session_migration: {
|
|
2954
|
+
stale_session_id: staleSessionId,
|
|
2955
|
+
replacement_session_id: replacementSessionId
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
2960
|
+
return {
|
|
2961
|
+
ok: false,
|
|
2962
|
+
error: {
|
|
2963
|
+
...envelopeResult.error,
|
|
2964
|
+
details: {
|
|
2965
|
+
...isRecord(envelopeResult.error.details) ? envelopeResult.error.details : {},
|
|
2966
|
+
stale_session_id: staleSessionId,
|
|
2967
|
+
replacement_session_id: replacementSessionId,
|
|
2968
|
+
recover_action: "session.recover"
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
};
|
|
2972
|
+
};
|
|
2801
2973
|
var addDeprecatedAliasWarning2 = (envelopeResult, deprecationAlias) => {
|
|
2802
2974
|
if (!deprecationAlias || !envelopeResult.ok || typeof envelopeResult.result !== "object" || !envelopeResult.result) {
|
|
2803
2975
|
return envelopeResult;
|
|
@@ -2854,6 +3026,69 @@ var TOOL_DEFINITIONS = [
|
|
|
2854
3026
|
corePath: "/session/close"
|
|
2855
3027
|
}
|
|
2856
3028
|
},
|
|
3029
|
+
{
|
|
3030
|
+
name: "permissions.list",
|
|
3031
|
+
config: {
|
|
3032
|
+
title: "Permissions List",
|
|
3033
|
+
description: "List allowlisted Browser Bridge sites.",
|
|
3034
|
+
inputSchema: PermissionsListInputSchema,
|
|
3035
|
+
outputSchema: envelope(PermissionsListOutputSchema),
|
|
3036
|
+
corePath: "/permissions/list"
|
|
3037
|
+
}
|
|
3038
|
+
},
|
|
3039
|
+
{
|
|
3040
|
+
name: "permissions.get_mode",
|
|
3041
|
+
config: {
|
|
3042
|
+
title: "Permissions Get Mode",
|
|
3043
|
+
description: "Read the current Browser Bridge permissions mode.",
|
|
3044
|
+
inputSchema: PermissionsGetModeInputSchema,
|
|
3045
|
+
outputSchema: envelope(PermissionsGetModeOutputSchema),
|
|
3046
|
+
corePath: "/permissions/get_mode"
|
|
3047
|
+
}
|
|
3048
|
+
},
|
|
3049
|
+
{
|
|
3050
|
+
name: "permissions.list_pending_requests",
|
|
3051
|
+
config: {
|
|
3052
|
+
title: "Permissions List Pending Requests",
|
|
3053
|
+
description: "List pending external Browser Bridge permission-change requests.",
|
|
3054
|
+
inputSchema: PermissionsListPendingRequestsInputSchema,
|
|
3055
|
+
outputSchema: envelope(PermissionsListPendingRequestsOutputSchema),
|
|
3056
|
+
corePath: "/permissions/list_pending_requests"
|
|
3057
|
+
}
|
|
3058
|
+
},
|
|
3059
|
+
{
|
|
3060
|
+
name: "permissions.request_allow_site",
|
|
3061
|
+
config: {
|
|
3062
|
+
title: "Permissions Request Allow Site",
|
|
3063
|
+
description: "Request allowlisting a site. A human must approve the change in Chrome before it applies.",
|
|
3064
|
+
inputSchema: PermissionsRequestAllowSiteInputSchema,
|
|
3065
|
+
outputSchema: envelope(PermissionsRequestOutputSchema),
|
|
3066
|
+
corePath: "/permissions/request_allow_site",
|
|
3067
|
+
transformInput: withPermissionsSource("mcp")
|
|
3068
|
+
}
|
|
3069
|
+
},
|
|
3070
|
+
{
|
|
3071
|
+
name: "permissions.request_revoke_site",
|
|
3072
|
+
config: {
|
|
3073
|
+
title: "Permissions Request Revoke Site",
|
|
3074
|
+
description: "Request revoking a site from the allowlist. A human must approve the change in Chrome before it applies.",
|
|
3075
|
+
inputSchema: PermissionsRequestRevokeSiteInputSchema,
|
|
3076
|
+
outputSchema: envelope(PermissionsRequestOutputSchema),
|
|
3077
|
+
corePath: "/permissions/request_revoke_site",
|
|
3078
|
+
transformInput: withPermissionsSource("mcp")
|
|
3079
|
+
}
|
|
3080
|
+
},
|
|
3081
|
+
{
|
|
3082
|
+
name: "permissions.request_set_mode",
|
|
3083
|
+
config: {
|
|
3084
|
+
title: "Permissions Request Set Mode",
|
|
3085
|
+
description: "Request changing Browser Bridge permission mode. A human must approve the change in Chrome before it applies.",
|
|
3086
|
+
inputSchema: PermissionsRequestSetModeInputSchema,
|
|
3087
|
+
outputSchema: envelope(PermissionsRequestOutputSchema),
|
|
3088
|
+
corePath: "/permissions/request_set_mode",
|
|
3089
|
+
transformInput: withPermissionsSource("mcp")
|
|
3090
|
+
}
|
|
3091
|
+
},
|
|
2857
3092
|
{
|
|
2858
3093
|
name: "drive.navigate",
|
|
2859
3094
|
config: {
|
|
@@ -3208,10 +3443,26 @@ var createToolHandler = (clientProvider, corePath, deprecationAlias, transformIn
|
|
|
3208
3443
|
void _extra;
|
|
3209
3444
|
try {
|
|
3210
3445
|
const client = typeof clientProvider === "function" ? await clientProvider() : clientProvider;
|
|
3211
|
-
const
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
)
|
|
3446
|
+
const transformedArgs = transformInput ? transformInput(args) : args;
|
|
3447
|
+
const staleSessionId = readSessionId(transformedArgs);
|
|
3448
|
+
let envelopeResult = await client.post(corePath, transformedArgs);
|
|
3449
|
+
if (staleSessionId && supportsSessionMigration(corePath) && isSessionNotFoundEnvelope(envelopeResult) && isRecord(transformedArgs)) {
|
|
3450
|
+
const createdSession = await client.post("/session/create", {});
|
|
3451
|
+
if (createdSession.ok && isRecord(createdSession.result) && typeof createdSession.result.session_id === "string" && createdSession.result.session_id.length > 0) {
|
|
3452
|
+
const replacementSessionId = createdSession.result.session_id;
|
|
3453
|
+
const retryArgs = {
|
|
3454
|
+
...transformedArgs,
|
|
3455
|
+
session_id: replacementSessionId
|
|
3456
|
+
};
|
|
3457
|
+
envelopeResult = addSessionMigrationNotice(
|
|
3458
|
+
await client.post(corePath, retryArgs),
|
|
3459
|
+
staleSessionId,
|
|
3460
|
+
replacementSessionId
|
|
3461
|
+
);
|
|
3462
|
+
} else {
|
|
3463
|
+
envelopeResult = addSessionRecoveryHint(envelopeResult);
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3215
3466
|
return toToolResult(
|
|
3216
3467
|
addDeprecatedAliasWarning2(envelopeResult, deprecationAlias)
|
|
3217
3468
|
);
|
|
@@ -3357,7 +3608,7 @@ var DEFAULT_HTTP_PATH = "/mcp";
|
|
|
3357
3608
|
var ENV_MCP_EAGER = "BROWSER_BRIDGE_MCP_EAGER";
|
|
3358
3609
|
var ENV_LEGACY_MCP_EAGER = "BROWSER_VISION_MCP_EAGER";
|
|
3359
3610
|
var durationMs4 = (startedAt) => Number((Number(process.hrtime.bigint() - startedAt) / 1e6).toFixed(3));
|
|
3360
|
-
var
|
|
3611
|
+
var parseBoolean = (value) => {
|
|
3361
3612
|
if (value === void 0) {
|
|
3362
3613
|
return void 0;
|
|
3363
3614
|
}
|
|
@@ -3374,7 +3625,7 @@ var resolveEagerMode = (explicit) => {
|
|
|
3374
3625
|
if (typeof explicit === "boolean") {
|
|
3375
3626
|
return explicit;
|
|
3376
3627
|
}
|
|
3377
|
-
const envValue =
|
|
3628
|
+
const envValue = parseBoolean(process.env[ENV_MCP_EAGER]) ?? parseBoolean(process.env[ENV_LEGACY_MCP_EAGER]);
|
|
3378
3629
|
return envValue ?? false;
|
|
3379
3630
|
};
|
|
3380
3631
|
var toCoreClientOptions = (options, logger) => ({
|
|
@@ -3561,7 +3812,7 @@ var readJsonBody = async (req, maxBytes = 5 * 1024 * 1024) => {
|
|
|
3561
3812
|
}
|
|
3562
3813
|
return JSON.parse(raw);
|
|
3563
3814
|
};
|
|
3564
|
-
var
|
|
3815
|
+
var getHeaderValue2 = (value) => {
|
|
3565
3816
|
if (typeof value === "string") {
|
|
3566
3817
|
return value;
|
|
3567
3818
|
}
|
|
@@ -3627,7 +3878,7 @@ var startMcpHttpServer = async (options = {}) => {
|
|
|
3627
3878
|
});
|
|
3628
3879
|
return;
|
|
3629
3880
|
}
|
|
3630
|
-
const sessionId =
|
|
3881
|
+
const sessionId = getHeaderValue2(req.headers["mcp-session-id"]);
|
|
3631
3882
|
requestLogger.debug("mcp.http.request.session", {
|
|
3632
3883
|
session_id: sessionId ?? null
|
|
3633
3884
|
});
|
|
@@ -3786,7 +4037,7 @@ var checkboxPrompt = async (options) => {
|
|
|
3786
4037
|
};
|
|
3787
4038
|
|
|
3788
4039
|
// packages/cli/src/installer/mcp-install.ts
|
|
3789
|
-
var
|
|
4040
|
+
var import_node_child_process3 = require("node:child_process");
|
|
3790
4041
|
|
|
3791
4042
|
// packages/cli/src/installer/cursor-mcp.ts
|
|
3792
4043
|
var import_promises2 = __toESM(require("node:fs/promises"));
|
|
@@ -3857,7 +4108,7 @@ var installCursorMcp = async (settingsPath) => {
|
|
|
3857
4108
|
// packages/cli/src/installer/mcp-install.ts
|
|
3858
4109
|
var runQuiet = async (cmd, args) => {
|
|
3859
4110
|
await new Promise((resolve4, reject) => {
|
|
3860
|
-
const child = (0,
|
|
4111
|
+
const child = (0, import_node_child_process3.spawn)(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
3861
4112
|
let stderr = "";
|
|
3862
4113
|
child.stderr?.on("data", (chunk) => {
|
|
3863
4114
|
stderr += String(chunk);
|
|
@@ -4026,11 +4277,6 @@ var import_express2 = __toESM(require("express"));
|
|
|
4026
4277
|
// packages/core/src/routes/session.ts
|
|
4027
4278
|
var import_express = require("express");
|
|
4028
4279
|
|
|
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
4280
|
// packages/core/src/artifacts.ts
|
|
4035
4281
|
var import_promises3 = require("node:fs/promises");
|
|
4036
4282
|
var import_node_os2 = __toESM(require("node:os"));
|
|
@@ -4063,106 +4309,10 @@ var DriveMutex = class {
|
|
|
4063
4309
|
};
|
|
4064
4310
|
var driveMutex = new DriveMutex();
|
|
4065
4311
|
|
|
4066
|
-
// packages/core/src/
|
|
4067
|
-
var
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
" if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {",
|
|
4071
|
-
" return CSS.escape(value);",
|
|
4072
|
-
" }",
|
|
4073
|
-
` return String(value).replace(/["'\\\\]/g, '\\\\$&');`,
|
|
4074
|
-
" };",
|
|
4075
|
-
" const truncate = (value, max) => {",
|
|
4076
|
-
" const text = String(value ?? '');",
|
|
4077
|
-
" return text.length > max ? text.slice(0, max) : text;",
|
|
4078
|
-
" };",
|
|
4079
|
-
" const selectorFor = (element) => {",
|
|
4080
|
-
" if (element.id) {",
|
|
4081
|
-
" return `#${escape(element.id)}`;",
|
|
4082
|
-
" }",
|
|
4083
|
-
" const name = element.getAttribute('name');",
|
|
4084
|
-
" if (name) {",
|
|
4085
|
-
' return `${element.tagName.toLowerCase()}[name="${escape(name)}"]`;',
|
|
4086
|
-
" }",
|
|
4087
|
-
" const parts = [];",
|
|
4088
|
-
" let node = element;",
|
|
4089
|
-
" while (node && node.nodeType === 1 && parts.length < 4) {",
|
|
4090
|
-
" let part = node.tagName.toLowerCase();",
|
|
4091
|
-
" const parent = node.parentElement;",
|
|
4092
|
-
" if (parent) {",
|
|
4093
|
-
" const siblings = Array.from(parent.children).filter(",
|
|
4094
|
-
" (child) => child.tagName === node.tagName",
|
|
4095
|
-
" );",
|
|
4096
|
-
" if (siblings.length > 1) {",
|
|
4097
|
-
" part += `:nth-of-type(${siblings.indexOf(node) + 1})`;",
|
|
4098
|
-
" }",
|
|
4099
|
-
" }",
|
|
4100
|
-
" parts.unshift(part);",
|
|
4101
|
-
" node = parent;",
|
|
4102
|
-
" }",
|
|
4103
|
-
" return parts.join('>');",
|
|
4104
|
-
" };",
|
|
4105
|
-
" const readStorage = (storage, limit) => {",
|
|
4106
|
-
" try {",
|
|
4107
|
-
" return Object.keys(storage)",
|
|
4108
|
-
" .slice(0, limit)",
|
|
4109
|
-
" .map((key) => ({",
|
|
4110
|
-
" key,",
|
|
4111
|
-
" value: truncate(storage.getItem(key), 500),",
|
|
4112
|
-
" }));",
|
|
4113
|
-
" } catch {",
|
|
4114
|
-
" return [];",
|
|
4115
|
-
" }",
|
|
4116
|
-
" };",
|
|
4117
|
-
" const forms = Array.from(document.querySelectorAll('form')).map((form) => {",
|
|
4118
|
-
" const fields = Array.from(form.elements)",
|
|
4119
|
-
" .filter((element) => element && element.tagName)",
|
|
4120
|
-
" .map((element) => {",
|
|
4121
|
-
" const tag = element.tagName.toLowerCase();",
|
|
4122
|
-
" const type = 'type' in element && element.type ? element.type : tag;",
|
|
4123
|
-
" const name = element.name || element.getAttribute('name') || element.id || '';",
|
|
4124
|
-
" let value = '';",
|
|
4125
|
-
" let options;",
|
|
4126
|
-
" if (tag === 'select') {",
|
|
4127
|
-
" const select = element;",
|
|
4128
|
-
" value = select.value ?? '';",
|
|
4129
|
-
" options = Array.from(select.options).map((option) => option.text);",
|
|
4130
|
-
" } else if (tag === 'input' && element.type === 'password') {",
|
|
4131
|
-
" value = '[redacted]';",
|
|
4132
|
-
" } else if (tag === 'input' || tag === 'textarea') {",
|
|
4133
|
-
" value = element.value ?? '';",
|
|
4134
|
-
" } else if (element.isContentEditable) {",
|
|
4135
|
-
" value = element.textContent ?? '';",
|
|
4136
|
-
" } else if ('value' in element) {",
|
|
4137
|
-
" value = element.value ?? '';",
|
|
4138
|
-
" }",
|
|
4139
|
-
" return {",
|
|
4140
|
-
" name,",
|
|
4141
|
-
" type,",
|
|
4142
|
-
" value: truncate(value, 500),",
|
|
4143
|
-
" ...(options ? { options } : {}),",
|
|
4144
|
-
" };",
|
|
4145
|
-
" });",
|
|
4146
|
-
" return {",
|
|
4147
|
-
" selector: selectorFor(form),",
|
|
4148
|
-
" action: form.getAttribute('action') || undefined,",
|
|
4149
|
-
" method: form.getAttribute('method') || undefined,",
|
|
4150
|
-
" fields,",
|
|
4151
|
-
" };",
|
|
4152
|
-
" });",
|
|
4153
|
-
" const localStorage = readStorage(window.localStorage, 100);",
|
|
4154
|
-
" const sessionStorage = readStorage(window.sessionStorage, 100);",
|
|
4155
|
-
" const cookies = (document.cookie ? document.cookie.split(';') : [])",
|
|
4156
|
-
" .map((entry) => entry.trim())",
|
|
4157
|
-
" .filter((entry) => entry.length > 0)",
|
|
4158
|
-
" .slice(0, 50)",
|
|
4159
|
-
" .map((entry) => {",
|
|
4160
|
-
" const [key, ...rest] = entry.split('=');",
|
|
4161
|
-
" return { key, value: truncate(rest.join('='), 500) };",
|
|
4162
|
-
" });",
|
|
4163
|
-
" return { forms, localStorage, sessionStorage, cookies };",
|
|
4164
|
-
"})()"
|
|
4165
|
-
].join("\n");
|
|
4312
|
+
// packages/core/src/inspect/extract-content-policy.ts
|
|
4313
|
+
var import_readability = require("@mozilla/readability");
|
|
4314
|
+
var import_jsdom = require("jsdom");
|
|
4315
|
+
var import_turndown = __toESM(require("turndown"));
|
|
4166
4316
|
|
|
4167
4317
|
// packages/core/src/diagnostics.ts
|
|
4168
4318
|
var STALE_ERROR_THRESHOLD_MS = 2 * 60 * 1e3;
|
|
@@ -4172,6 +4322,32 @@ var PROCESS_STARTED_AT = new Date(
|
|
|
4172
4322
|
Date.now() - Math.floor(process.uptime() * 1e3)
|
|
4173
4323
|
).toISOString();
|
|
4174
4324
|
|
|
4325
|
+
// packages/cli/src/open-path.ts
|
|
4326
|
+
var import_node_child_process4 = require("node:child_process");
|
|
4327
|
+
var shouldOpenInChrome = (target) => /^chrome(?:-extension)?:\/\//.test(target);
|
|
4328
|
+
var openPath = async (target) => {
|
|
4329
|
+
const platform = process.platform;
|
|
4330
|
+
if (platform === "darwin") {
|
|
4331
|
+
const args = shouldOpenInChrome(target) ? ["-a", "Google Chrome", target] : [target];
|
|
4332
|
+
const child2 = (0, import_node_child_process4.spawn)("open", args, { detached: true, stdio: "ignore" });
|
|
4333
|
+
child2.unref();
|
|
4334
|
+
return;
|
|
4335
|
+
}
|
|
4336
|
+
if (platform === "win32") {
|
|
4337
|
+
const child2 = (0, import_node_child_process4.spawn)("cmd", ["/c", "start", "", target], {
|
|
4338
|
+
detached: true,
|
|
4339
|
+
stdio: "ignore"
|
|
4340
|
+
});
|
|
4341
|
+
child2.unref();
|
|
4342
|
+
return;
|
|
4343
|
+
}
|
|
4344
|
+
const child = (0, import_node_child_process4.spawn)("xdg-open", [target], {
|
|
4345
|
+
detached: true,
|
|
4346
|
+
stdio: "ignore"
|
|
4347
|
+
});
|
|
4348
|
+
child.unref();
|
|
4349
|
+
};
|
|
4350
|
+
|
|
4175
4351
|
// packages/cli/src/commands/open-artifacts.ts
|
|
4176
4352
|
var registerOpenArtifactsCommand = (program2) => {
|
|
4177
4353
|
program2.command("open-artifacts").description("Open the artifact folder for a session").requiredOption("--session-id <id>", "Session identifier").action(async (options, command) => {
|
|
@@ -4186,6 +4362,78 @@ var registerOpenArtifactsCommand = (program2) => {
|
|
|
4186
4362
|
});
|
|
4187
4363
|
};
|
|
4188
4364
|
|
|
4365
|
+
// packages/cli/src/commands/permissions.ts
|
|
4366
|
+
var parseNumber5 = (value) => {
|
|
4367
|
+
if (value === void 0 || value === null || value === "") {
|
|
4368
|
+
return void 0;
|
|
4369
|
+
}
|
|
4370
|
+
const parsed = Number(value);
|
|
4371
|
+
return Number.isFinite(parsed) ? parsed : Number.NaN;
|
|
4372
|
+
};
|
|
4373
|
+
var registerPermissionsCommands = (program2) => {
|
|
4374
|
+
const permissions = program2.command("permissions").description("Manage Browser Bridge permissions");
|
|
4375
|
+
permissions.command("list").description("List allowlisted sites").action(async (_options, command) => {
|
|
4376
|
+
await runCommand(command, (client) => {
|
|
4377
|
+
const payload = parseInput(PermissionsListInputSchema, {});
|
|
4378
|
+
return client.post("/permissions/list", payload);
|
|
4379
|
+
});
|
|
4380
|
+
});
|
|
4381
|
+
permissions.command("mode").description("Show the current permissions mode").action(async (_options, command) => {
|
|
4382
|
+
await runCommand(command, (client) => {
|
|
4383
|
+
const payload = parseInput(PermissionsGetModeInputSchema, {});
|
|
4384
|
+
return client.post("/permissions/get_mode", payload);
|
|
4385
|
+
});
|
|
4386
|
+
});
|
|
4387
|
+
permissions.command("pending").description("List pending external permission-change requests").action(async (_options, command) => {
|
|
4388
|
+
await runCommand(command, (client) => {
|
|
4389
|
+
const payload = parseInput(
|
|
4390
|
+
PermissionsListPendingRequestsInputSchema,
|
|
4391
|
+
{}
|
|
4392
|
+
);
|
|
4393
|
+
return client.post("/permissions/list_pending_requests", payload);
|
|
4394
|
+
});
|
|
4395
|
+
});
|
|
4396
|
+
permissions.command("allow-site").description("Request allowlisting a site").requiredOption("--site <site>", "Site hostname[:port] to allowlist").option(
|
|
4397
|
+
"--timeout-ms <ms>",
|
|
4398
|
+
"How long to wait for approval before returning"
|
|
4399
|
+
).action(async (options, command) => {
|
|
4400
|
+
await runCommand(command, (client) => {
|
|
4401
|
+
const payload = parseInput(PermissionsRequestAllowSiteInputSchema, {
|
|
4402
|
+
site: options.site,
|
|
4403
|
+
timeout_ms: parseNumber5(options.timeoutMs),
|
|
4404
|
+
source: "cli"
|
|
4405
|
+
});
|
|
4406
|
+
return client.post("/permissions/request_allow_site", payload);
|
|
4407
|
+
});
|
|
4408
|
+
});
|
|
4409
|
+
permissions.command("revoke-site").description("Request revoking a site from the allowlist").requiredOption("--site <site>", "Site hostname[:port] to revoke").option(
|
|
4410
|
+
"--timeout-ms <ms>",
|
|
4411
|
+
"How long to wait for approval before returning"
|
|
4412
|
+
).action(async (options, command) => {
|
|
4413
|
+
await runCommand(command, (client) => {
|
|
4414
|
+
const payload = parseInput(PermissionsRequestRevokeSiteInputSchema, {
|
|
4415
|
+
site: options.site,
|
|
4416
|
+
timeout_ms: parseNumber5(options.timeoutMs),
|
|
4417
|
+
source: "cli"
|
|
4418
|
+
});
|
|
4419
|
+
return client.post("/permissions/request_revoke_site", payload);
|
|
4420
|
+
});
|
|
4421
|
+
});
|
|
4422
|
+
permissions.command("set-mode").description("Request changing the permissions mode").requiredOption("--mode <mode>", "Mode to request (granular or bypass)").option(
|
|
4423
|
+
"--timeout-ms <ms>",
|
|
4424
|
+
"How long to wait for approval before returning"
|
|
4425
|
+
).action(async (options, command) => {
|
|
4426
|
+
await runCommand(command, (client) => {
|
|
4427
|
+
const payload = parseInput(PermissionsRequestSetModeInputSchema, {
|
|
4428
|
+
mode: options.mode,
|
|
4429
|
+
timeout_ms: parseNumber5(options.timeoutMs),
|
|
4430
|
+
source: "cli"
|
|
4431
|
+
});
|
|
4432
|
+
return client.post("/permissions/request_set_mode", payload);
|
|
4433
|
+
});
|
|
4434
|
+
});
|
|
4435
|
+
};
|
|
4436
|
+
|
|
4189
4437
|
// packages/cli/src/commands/session.ts
|
|
4190
4438
|
var registerSessionCommands = (program2) => {
|
|
4191
4439
|
const session = program2.command("session").description("Manage Core sessions");
|
|
@@ -4331,14 +4579,14 @@ var resolveSkillSourceDir = async () => {
|
|
|
4331
4579
|
} catch {
|
|
4332
4580
|
}
|
|
4333
4581
|
const repoRoot = import_node_path8.default.resolve(rootDir, "..", "..");
|
|
4334
|
-
const
|
|
4582
|
+
const repoSkill = import_node_path8.default.join(repoRoot, ".agents", "skills", "browser-bridge");
|
|
4335
4583
|
try {
|
|
4336
|
-
await import_promises4.default.stat(
|
|
4337
|
-
return
|
|
4584
|
+
await import_promises4.default.stat(repoSkill);
|
|
4585
|
+
return repoSkill;
|
|
4338
4586
|
} catch {
|
|
4339
4587
|
}
|
|
4340
4588
|
throw new Error(
|
|
4341
|
-
`Unable to locate packaged skill. Expected ${packaged} (npm install) or ${
|
|
4589
|
+
`Unable to locate packaged skill. Expected ${packaged} (npm install) or ${repoSkill} (repo dev).`
|
|
4342
4590
|
);
|
|
4343
4591
|
};
|
|
4344
4592
|
|
|
@@ -4635,6 +4883,7 @@ var main = async () => {
|
|
|
4635
4883
|
"Output Browser Bridge CLI version"
|
|
4636
4884
|
).option("--host <host>", "Core host (default: 127.0.0.1)").option("--port <port>", "Core port (default: 3210)").option("--json", "Output JSON").option("--no-daemon", "Disable auto-starting Core");
|
|
4637
4885
|
registerSessionCommands(program);
|
|
4886
|
+
registerPermissionsCommands(program);
|
|
4638
4887
|
registerDriveCommands(program);
|
|
4639
4888
|
registerInspectCommands(program);
|
|
4640
4889
|
registerArtifactsCommands(program);
|