@opencode/browse 0.0.6-dev.25 → 0.0.6-dev.28

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.
@@ -2,15 +2,15 @@ import {
2
2
  parseTargetSelection2,
3
3
  getObject2,
4
4
  getString2
5
- } from "./main-7pxrvrp0.mjs";
5
+ } from "./main-8h1nwn45.mjs";
6
6
  import {
7
7
  isNodeError,
8
8
  writeJsonFileAtomically
9
- } from "./main-tf22ynec.mjs";
9
+ } from "./main-x8w3s3rv.mjs";
10
10
  import {
11
11
  dataRoot,
12
12
  cliCommand
13
- } from "./main-hh2mneh8.mjs";
13
+ } from "./main-8ncff5jp.mjs";
14
14
 
15
15
  // src/relay/user-settings.ts
16
16
  var settingKeys = ["window", "grouping", "idleMinutes", "cursor", "humanInput", "handoffNotifications", "autoUpdate"];
@@ -306,452 +306,17 @@ function toolResult(options) {
306
306
  });
307
307
  }
308
308
 
309
- // src/auth/deadbolt.ts
310
- import { spawn, spawnSync } from "node:child_process";
311
- import crypto from "node:crypto";
312
- import fs from "node:fs";
313
- import net from "node:net";
314
- import os from "node:os";
315
- import path from "node:path";
316
- class DeadboltError extends Error {
317
- name = "DeadboltError";
318
- code;
319
- detail;
320
- constructor(code, message, detail = {}) {
321
- super(message);
322
- this.code = code;
323
- this.detail = detail;
324
- }
325
- }
326
- var clientFileName = "deadbolt-client.json";
327
- function clientFilePath(root = dataRoot()) {
328
- return path.join(root, clientFileName);
329
- }
330
- function readClientFile(root = dataRoot()) {
331
- let text;
332
- try {
333
- const file = clientFilePath(root);
334
- const stat = fs.statSync(file);
335
- if (process.platform !== "win32" && (stat.mode & 63) !== 0)
336
- fs.chmodSync(file, 384);
337
- text = fs.readFileSync(file, "utf8");
338
- } catch {
339
- return;
340
- }
341
- try {
342
- const value = JSON.parse(text);
343
- if (typeof value.id !== "string" || !value.id || typeof value.token !== "string" || !value.token)
344
- return;
345
- return {
346
- version: 1,
347
- id: value.id,
348
- token: value.token,
349
- connectedAt: typeof value.connectedAt === "string" ? value.connectedAt : ""
350
- };
351
- } catch {
352
- return;
353
- }
354
- }
355
- function readClient(root = dataRoot()) {
356
- const file = readClientFile(root);
357
- return file ? { id: file.id, token: file.token } : undefined;
358
- }
359
- async function saveClient(client, root = dataRoot()) {
360
- const value = { version: 1, id: client.id, token: client.token, connectedAt: new Date().toISOString() };
361
- await writeJsonFileAtomically(clientFilePath(root), value, { dirMode: 448 });
362
- }
363
- function removeClient(root = dataRoot()) {
364
- const file = clientFilePath(root);
365
- if (!fs.existsSync(file))
366
- return false;
367
- fs.rmSync(file, { force: true });
368
- return true;
369
- }
370
- function computedSocketPath(env = process.env) {
371
- const nonEmpty = (name) => env[name] ? env[name] : undefined;
372
- const deadboltHome = nonEmpty("DEADBOLT_HOME");
373
- const suffix = deadboltHome ? `-${blake3Hex(Buffer.from(deadboltHome, "utf8")).slice(0, 8)}` : "";
374
- const uid = typeof process.getuid === "function" ? process.getuid() : 0;
375
- const runtime = nonEmpty("XDG_RUNTIME_DIR") ?? userRuntimeDir(uid);
376
- const directory = runtime ? path.join(runtime, `deadbolt${suffix}`) : path.join(nonEmpty("TMPDIR") ?? os.tmpdir(), `deadbolt${suffix}-${uid}`);
377
- return path.join(directory, "agent.sock");
378
- }
379
- function userRuntimeDir(uid) {
380
- const directory = `/run/user/${uid}`;
381
- try {
382
- const stat = fs.statSync(directory);
383
- return stat.isDirectory() && stat.uid === uid ? directory : undefined;
384
- } catch {
385
- return;
386
- }
387
- }
388
- function socketPath(options = {}) {
389
- const env = options.env ?? process.env;
390
- return env.OPENCODE_BROWSER_DEADBOLT_SOCKET || computedSocketPath(env);
391
- }
392
- var requestTimeoutMs = 15000;
393
- var maxReplyBytes = 4 * 1024 * 1024;
394
- function errorCode(code) {
395
- const normalized = typeof code === "string" ? code.replace(/-/g, "_") : "";
396
- switch (normalized) {
397
- case "locked":
398
- case "not_granted":
399
- case "forbidden":
400
- case "rate_limited":
401
- case "domain_mismatch":
402
- case "not_found":
403
- case "choose_passkey":
404
- return normalized;
405
- case "not_initialized":
406
- return "locked";
407
- default:
408
- return "failed";
409
- }
410
- }
411
- var errorHints = {
412
- locked: "Deadbolt is locked, so agent sign-ins are paused until the user unlocks it.",
413
- forbidden: "Deadbolt doesn't know this browse install (its client was removed or revoked). Ask the user to run `opencode-browser deadbolt connect`.",
414
- rate_limited: "Deadbolt is rate-limiting this client; wait before trying again."
415
- };
416
- function rawRequest(socket, request, timeoutMs = requestTimeoutMs) {
417
- return new Promise((resolve, reject) => {
418
- const connection = net.createConnection(socket);
419
- let buffer = "";
420
- let settled = false;
421
- const finish = (error, value) => {
422
- if (settled)
423
- return;
424
- settled = true;
425
- clearTimeout(timer);
426
- connection.destroy();
427
- if (error)
428
- reject(error);
429
- else
430
- resolve(value);
431
- };
432
- const timer = setTimeout(() => finish(new DeadboltError("unavailable", `Deadbolt did not answer ${String(request.cmd)} within ${timeoutMs} ms`)), timeoutMs);
433
- connection.setEncoding("utf8");
434
- connection.on("connect", () => connection.write(`${JSON.stringify(request)}
435
- `));
436
- connection.on("error", (cause) => {
437
- const missing = cause.code === "ENOENT" || cause.code === "ECONNREFUSED";
438
- finish(new DeadboltError("unavailable", missing ? "Deadbolt isn't running (no agent socket). Ask the user to start or unlock Deadbolt." : `Could not reach Deadbolt: ${cause.message}`));
439
- });
440
- connection.on("data", (chunk) => {
441
- buffer += chunk;
442
- if (buffer.length > maxReplyBytes)
443
- return finish(new DeadboltError("failed", "Deadbolt's reply was too large"));
444
- let newline;
445
- while ((newline = buffer.indexOf(`
446
- `)) !== -1) {
447
- const line = buffer.slice(0, newline).trim();
448
- buffer = buffer.slice(newline + 1);
449
- if (!line)
450
- continue;
451
- let message;
452
- try {
453
- message = JSON.parse(line);
454
- } catch {
455
- return finish(new DeadboltError("failed", "Deadbolt sent a reply that isn't JSON"));
456
- }
457
- if (message.type === "ok")
458
- return finish(undefined, message.reply ?? {});
459
- if (message.type === "error") {
460
- const code = errorCode(message.code);
461
- const text = typeof message.message === "string" ? message.message : String(message.code);
462
- const detail = message.grant ?? {};
463
- const choices = passkeyList(message.choices ?? message.passkeys);
464
- return finish(new DeadboltError(code, errorHints[code] ? `${text.replace(/[\s.]*$/, ".")} ${errorHints[code]}` : text, {
465
- ...typeof detail.site === "string" ? { site: detail.site } : {},
466
- ...typeof detail.login === "string" ? { login: detail.login } : {},
467
- ...choices.length > 0 ? { choices } : {}
468
- }));
469
- }
470
- }
471
- });
472
- connection.on("end", () => finish(new DeadboltError("failed", "Deadbolt closed the connection without a reply")));
473
- });
474
- }
475
- var str = (value) => typeof value === "string" ? value : undefined;
476
- function passkeyList(value) {
477
- if (!Array.isArray(value))
478
- return [];
479
- return value.filter((entry) => entry !== null && typeof entry === "object").map((entry) => {
480
- const username = str(entry.username);
481
- const displayName = str(entry.display_name) ?? str(entry.displayName);
482
- return { ref: entry.ref ?? entry.login, ...username ? { username } : {}, ...displayName ? { displayName } : {}, granted: entry.granted !== false };
483
- });
484
- }
485
- function toLogin(raw) {
486
- const signIn = raw.sign_in;
487
- const fields = Array.isArray(raw.fields) ? raw.fields.filter((field) => typeof field === "string") : undefined;
488
- const username = str(raw.username);
489
- return {
490
- ref: raw.ref ?? raw.login,
491
- title: str(raw.title) ?? "",
492
- ...username ? { username } : {},
493
- hasPassword: raw.has_password === true,
494
- hasTotp: raw.has_totp === true || raw.has_otp === true,
495
- hasPasskey: raw.has_passkey === true,
496
- granted: fields !== undefined && fields.length > 0 || raw.passkeys === true,
497
- passkeys: raw.passkeys === true,
498
- ...fields ? { fields } : {},
499
- ...signIn && typeof signIn.provider === "string" ? { signIn: { provider: signIn.provider, ...str(signIn.account) ? { account: str(signIn.account) } : {} } } : {}
500
- };
501
- }
502
- function connect(options = {}) {
503
- const client = options.client ?? readClient(options.root);
504
- if (!client) {
505
- throw new DeadboltError("not_connected", "browse isn't connected to Deadbolt. Ask the user to run `opencode-browser deadbolt connect` and to allow the logins agents may use with `deadbolt agents allow <site>`.");
506
- }
507
- const socket = options.socket ?? socketPath();
508
- let protocol;
509
- const version = async () => {
510
- if (protocol === undefined) {
511
- const status = await rawRequest(socket, { v: 0, cmd: "status" });
512
- protocol = typeof status.protocol === "number" ? status.protocol : 0;
513
- }
514
- return protocol;
515
- };
516
- const send = async (cmd, fields) => rawRequest(socket, { v: await version(), cmd, client: { id: client.id, token: client.token }, ...fields });
517
- const site = async (origin) => {
518
- const reply = await send("agent-logins", { origin });
519
- const raw = (Array.isArray(reply.logins) ? reply.logins : []).filter((login) => login !== null && typeof login === "object");
520
- const logins = raw.map(toLogin);
521
- let passkeys = passkeyList(reply.passkeys);
522
- if (!Array.isArray(reply.passkeys)) {
523
- passkeys = logins.filter((login) => login.hasPasskey).map((login) => ({ ref: login.ref, ...login.username ? { username: login.username } : {}, granted: login.passkeys }));
524
- }
525
- return { logins, passkeys };
526
- };
527
- return {
528
- socket,
529
- client,
530
- status: async () => {
531
- const status = await rawRequest(socket, { v: 0, cmd: "status" });
532
- protocol = typeof status.protocol === "number" ? status.protocol : 0;
533
- return { protocol, unlocked: status.unlocked === true, ...str(status.version) ? { version: str(status.version) } : {} };
534
- },
535
- logins: async (origin) => (await site(origin)).logins,
536
- site: (origin) => site(origin),
537
- fill: async (origin, login, want) => {
538
- const reply = await send("agent-fill", { origin, login: login.ref, want: [...want] });
539
- const values = reply.values ?? reply;
540
- return {
541
- ...str(values.username) !== undefined ? { username: str(values.username) } : {},
542
- ...str(values.password) !== undefined ? { password: str(values.password) } : {},
543
- ...str(values.totp) !== undefined ? { totp: str(values.totp) } : {}
544
- };
545
- },
546
- passkeyGet: async (request) => {
547
- const reply = await send("agent-passkey-get", {
548
- origin: request.origin,
549
- ...request.rpId ? { rp_id: request.rpId } : {},
550
- challenge: request.challenge,
551
- allow_credentials: [...request.allowCredentials],
552
- user_verification: request.userVerification,
553
- ...request.login !== undefined ? { login: request.login } : {}
554
- });
555
- if (reply.reply === "choose-passkey") {
556
- throw new DeadboltError("choose_passkey", "Several passkeys could sign in here; name one by its username.", { choices: passkeyList(reply.choices ?? reply.passkeys) });
557
- }
558
- const credentialId = str(reply.credential_id);
559
- const clientDataJson = str(reply.client_data_json);
560
- const authenticatorData = str(reply.authenticator_data);
561
- const signature = str(reply.signature);
562
- if (!credentialId || !clientDataJson || !authenticatorData || !signature)
563
- throw new DeadboltError("failed", "Deadbolt's passkey assertion is incomplete");
564
- return { credentialId, clientDataJson, authenticatorData, signature, ...str(reply.user_handle) ? { userHandle: str(reply.user_handle) } : {} };
565
- }
566
- };
567
- }
568
- var deadboltNamePrefix = "deadbolt:";
569
- function parseDeadboltName(name) {
570
- if (!name.startsWith(deadboltNamePrefix))
571
- return;
572
- const rest = name.slice(deadboltNamePrefix.length).trim();
573
- const origin = /^https?:\/\/[^/]+/i.exec(rest);
574
- const site = origin ? origin[0] : rest.split("/")[0];
575
- const username = rest.slice(site.length + 1);
576
- if (!site)
577
- return;
578
- return { site: site.toLowerCase(), ...username ? { username } : {} };
579
- }
580
- function originOnSite(origin, site) {
581
- let url;
582
- try {
583
- url = new URL(origin);
584
- } catch {
585
- return false;
586
- }
587
- if (/^https?:\/\//i.test(site)) {
588
- try {
589
- return new URL(site).origin === url.origin;
590
- } catch {
591
- return false;
592
- }
593
- }
594
- const host = url.hostname.toLowerCase();
595
- const bare = site.replace(/^\*\./, "").replace(/:\d+$/, "").toLowerCase();
596
- const local = host === "localhost" || host === "127.0.0.1" || host === "[::1]" || host.endsWith(".localhost");
597
- if (url.protocol !== "https:" && !(url.protocol === "http:" && local))
598
- return false;
599
- return host === bare || host.endsWith(`.${bare}`);
600
- }
601
- function pickLogin(logins, site, username, field) {
602
- const granted = logins.filter((login) => login.granted && (field === undefined || login.fields === undefined || login.fields.includes(field)));
603
- const candidates = username === undefined ? granted : granted.filter((login) => login.username?.toLowerCase() === username.toLowerCase());
604
- if (candidates.length === 1)
605
- return candidates[0];
606
- if (candidates.length === 0) {
607
- throw new DeadboltError("not_granted", username === undefined ? `No Deadbolt login is granted to browse for ${site}${field ? ` (${field})` : ""}. Ask the user to allow one with \`deadbolt agents allow ${site}\`.` : `No Deadbolt login for ${username} is granted to browse for ${site}${field ? ` (${field})` : ""}. Ask the user to allow it with \`deadbolt agents allow ${site} --login ${username}\`.`, { site, ...username ? { login: username } : {} });
608
- }
609
- throw new DeadboltError("failed", `Several Deadbolt logins are granted for ${site}; name one: deadbolt:${site}/<username> (${candidates.map((login) => login.username ?? login.title).join(", ")})`);
610
- }
611
- function originsFromPatterns(patterns) {
612
- const origins = new Set;
613
- for (const pattern of patterns) {
614
- const scheme = /^(https?):\/\//i.exec(pattern)?.[1]?.toLowerCase() ?? "https";
615
- const host = pattern.replace(/^https?:\/\//i, "").replace(/^\*\./, "").replace(/\/$/, "");
616
- try {
617
- origins.add(new URL(`${scheme}://${host}`).origin);
618
- } catch {}
619
- }
620
- return [...origins];
621
- }
622
- async function listLogins(origins, connection) {
623
- let deadbolt;
624
- try {
625
- deadbolt = connection ?? connect();
626
- } catch (error) {
627
- return { connected: false, logins: [], passkeys: [], error: { code: error instanceof DeadboltError ? error.code : "failed", message: error instanceof Error ? error.message : String(error) } };
628
- }
629
- const logins = [];
630
- const passkeys = [];
631
- for (const origin of origins.slice(0, 20)) {
632
- try {
633
- const found = await deadbolt.site(origin);
634
- for (const { ref: _ref, ...login } of found.logins)
635
- logins.push({ ...login, origin });
636
- for (const { ref: _ref, ...passkey } of found.passkeys)
637
- passkeys.push({ ...passkey, origin });
638
- } catch (error) {
639
- if (error instanceof DeadboltError && (error.code === "domain_mismatch" || error.code === "not_found" || error.code === "not_granted"))
640
- continue;
641
- return { connected: true, logins, passkeys, error: { code: error instanceof DeadboltError ? error.code : "failed", message: error instanceof Error ? error.message : String(error) } };
642
- }
643
- }
644
- return { connected: true, logins, passkeys };
645
- }
646
- function pickPasskey(passkeys, username) {
647
- const wanted = username.toLowerCase();
648
- const granted = passkeys.filter((passkey) => passkey.granted);
649
- return granted.find((passkey) => passkey.username?.toLowerCase() === wanted) ?? granted.find((passkey) => passkey.displayName?.toLowerCase() === wanted);
650
- }
651
- async function pair(options = {}) {
652
- const command = options.command ?? (process.env.OPENCODE_BROWSER_DEADBOLT_CLI || "deadbolt");
653
- const stdout = await new Promise((resolve, reject) => {
654
- const child = spawn(command, ["agents", "add-client", options.name ?? "browse", "--json"], { stdio: ["inherit", "pipe", "inherit"] });
655
- let output = "";
656
- child.stdout.setEncoding("utf8");
657
- child.stdout.on("data", (chunk) => {
658
- output += chunk;
659
- });
660
- child.on("error", (cause) => reject(new DeadboltError("unavailable", cause.code === "ENOENT" ? `${command} isn't installed or on PATH. Install Deadbolt first.` : `Could not run ${command}: ${cause.message}`)));
661
- child.on("close", (code) => code === 0 ? resolve(output) : reject(new DeadboltError("failed", `deadbolt agents add-client exited with status ${code}`)));
662
- });
663
- let parsed;
664
- try {
665
- const line = stdout.trim().split(`
666
- `).filter(Boolean).at(-1) ?? "";
667
- parsed = JSON.parse(line);
668
- } catch {
669
- throw new DeadboltError("failed", "deadbolt agents add-client --json didn't print a client");
670
- }
671
- const client = parsed.client ?? parsed;
672
- const id = str(client.id);
673
- const token = str(client.token) ?? str(parsed.token);
674
- if (!id || !token)
675
- throw new DeadboltError("failed", "deadbolt agents add-client --json printed no id and token");
676
- await saveClient({ id, token }, options.root);
677
- return { id };
678
- }
679
- function unpair(options = {}) {
680
- const client = readClient(options.root);
681
- if (!client)
682
- return { removed: false, revoked: false };
683
- const command = options.command ?? (process.env.OPENCODE_BROWSER_DEADBOLT_CLI || "deadbolt");
684
- const result = spawnSync(command, ["agents", "remove-client", client.id], { stdio: ["inherit", "ignore", "inherit"], timeout: 120000 });
685
- return { removed: removeClient(options.root), revoked: result.status === 0 };
686
- }
687
- function isBase64Url(value, maxLength = 8192) {
688
- return typeof value === "string" && value.length <= maxLength && /^[A-Za-z0-9_-]*$/.test(value);
689
- }
690
- function randomName(prefix) {
691
- return `${prefix}${crypto.randomBytes(12).toString("hex")}`;
692
- }
693
- var blake3Iv = [1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225];
694
- var blake3Permutation = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8];
695
- function blake3Compress(cv, block, blockLength, flags) {
696
- const s = new Uint32Array([...cv, blake3Iv[0], blake3Iv[1], blake3Iv[2], blake3Iv[3], 0, 0, blockLength, flags]);
697
- let m = Uint32Array.from(block);
698
- const rotr = (x, n) => x >>> n | x << 32 - n;
699
- const g = (a, b, c, d, x, y) => {
700
- s[a] = s[a] + s[b] + x;
701
- s[d] = rotr(s[d] ^ s[a], 16);
702
- s[c] = s[c] + s[d];
703
- s[b] = rotr(s[b] ^ s[c], 12);
704
- s[a] = s[a] + s[b] + y;
705
- s[d] = rotr(s[d] ^ s[a], 8);
706
- s[c] = s[c] + s[d];
707
- s[b] = rotr(s[b] ^ s[c], 7);
708
- };
709
- for (let round = 0;round < 7; round++) {
710
- g(0, 4, 8, 12, m[0], m[1]);
711
- g(1, 5, 9, 13, m[2], m[3]);
712
- g(2, 6, 10, 14, m[4], m[5]);
713
- g(3, 7, 11, 15, m[6], m[7]);
714
- g(0, 5, 10, 15, m[8], m[9]);
715
- g(1, 6, 11, 12, m[10], m[11]);
716
- g(2, 7, 8, 13, m[12], m[13]);
717
- g(3, 4, 9, 14, m[14], m[15]);
718
- if (round < 6)
719
- m = Uint32Array.from(blake3Permutation, (index) => m[index]);
720
- }
721
- return Array.from({ length: 8 }, (_, index) => (s[index] ^ s[index + 8]) >>> 0);
722
- }
723
- function blake3Hex(input) {
724
- if (input.length > 1024)
725
- throw new Error("blake3Hex handles inputs up to 1024 bytes (DEADBOLT_HOME is longer: set OPENCODE_BROWSER_DEADBOLT_SOCKET)");
726
- const blocks = Math.max(1, Math.ceil(input.length / 64));
727
- let cv = [...blake3Iv];
728
- for (let index = 0;index < blocks; index++) {
729
- const bytes = new Uint8Array(64);
730
- const chunk = input.subarray(index * 64, index * 64 + 64);
731
- bytes.set(chunk);
732
- const words = new Uint32Array(16);
733
- const view = new DataView(bytes.buffer);
734
- for (let word = 0;word < 16; word++)
735
- words[word] = view.getUint32(word * 4, true);
736
- const flags = (index === 0 ? 1 : 0) | (index === blocks - 1 ? 2 | 8 : 0);
737
- cv = blake3Compress(cv, words, chunk.length, flags);
738
- }
739
- const out = Buffer.alloc(32);
740
- cv.forEach((word, index) => out.writeUInt32LE(word, index * 4));
741
- return out.toString("hex");
742
- }
743
-
744
309
  // src/auth/site-secrets.ts
745
- import crypto2 from "node:crypto";
746
- import fs3 from "node:fs/promises";
747
- import path3 from "node:path";
310
+ import crypto from "node:crypto";
311
+ import fs2 from "node:fs/promises";
312
+ import path2 from "node:path";
748
313
  import { Effect as Effect3, Schema as Schema2 } from "effect";
749
314
 
750
315
  // src/auth/profile.ts
751
316
  import { Effect as Effect2, Schema, Semaphore } from "effect";
752
- import { spawn as spawn2 } from "node:child_process";
753
- import fs2 from "node:fs/promises";
754
- import path2 from "node:path";
317
+ import { spawn } from "node:child_process";
318
+ import fs from "node:fs/promises";
319
+ import path from "node:path";
755
320
 
756
321
  // src/update/child-process.ts
757
322
  async function terminateChildProcess(options) {
@@ -1253,7 +818,7 @@ class AuthProfileError extends Schema.TaggedError()("AuthProfile.Error", {
1253
818
  cause: Schema.optionalKey(Schema.Defect())
1254
819
  }) {
1255
820
  }
1256
- var defaultBaseDir = () => path2.join(dataRoot(), "secrets");
821
+ var defaultBaseDir = () => path.join(dataRoot(), "secrets");
1257
822
  var writeLock = Semaphore.makeUnsafe(1);
1258
823
  var profileLockTimeoutMs = 30000;
1259
824
  var staleProfileLockMs = 60000;
@@ -1262,7 +827,7 @@ var maximumTimeoutMs = 2147483647;
1262
827
  var read = Effect2.fn("AuthProfile.read")(function* (name, options = {}) {
1263
828
  const filePath = yield* profilePath(options.baseDir ?? defaultBaseDir(), name);
1264
829
  const text = yield* Effect2.tryPromise({
1265
- try: () => fs2.readFile(filePath, "utf8"),
830
+ try: () => fs.readFile(filePath, "utf8"),
1266
831
  catch: (cause) => isNodeError(cause) && cause.code === "ENOENT" ? new AuthProfileError({ message: `Auth profile not found: ${name}`, operation: "read", reason: "not-found", cause }) : new AuthProfileError({ message: `Could not read auth profile: ${name}`, operation: "read", reason: "read-failed", cause })
1267
832
  });
1268
833
  return yield* Schema.decodeUnknownEffect(StoredAuthProfile)(yield* Effect2.try({
@@ -1280,12 +845,12 @@ function withLock(name, options, effect) {
1280
845
  const lockPath = `${filePath}.lock`;
1281
846
  yield* Effect2.tryPromise({
1282
847
  try: async () => {
1283
- await fs2.mkdir(baseDir, { recursive: true, mode: 448 });
1284
- await fs2.chmod(baseDir, 448);
848
+ await fs.mkdir(baseDir, { recursive: true, mode: 448 });
849
+ await fs.chmod(baseDir, 448);
1285
850
  const deadline = Date.now() + profileLockTimeoutMs;
1286
851
  while (true) {
1287
852
  try {
1288
- const handle = await fs2.open(lockPath, "wx", 384);
853
+ const handle = await fs.open(lockPath, "wx", 384);
1289
854
  let written = false;
1290
855
  try {
1291
856
  await handle.writeFile(`${process.pid}
@@ -1294,17 +859,17 @@ function withLock(name, options, effect) {
1294
859
  } finally {
1295
860
  await handle.close();
1296
861
  if (!written)
1297
- await fs2.unlink(lockPath).catch(() => {});
862
+ await fs.unlink(lockPath).catch(() => {});
1298
863
  }
1299
864
  return;
1300
865
  } catch (cause) {
1301
866
  if (!isNodeError(cause) || cause.code !== "EEXIST")
1302
867
  throw cause;
1303
- const stat = await fs2.stat(lockPath).catch(() => {
868
+ const stat = await fs.stat(lockPath).catch(() => {
1304
869
  return;
1305
870
  });
1306
871
  if (stat && Date.now() - stat.mtimeMs > staleProfileLockMs) {
1307
- await fs2.unlink(lockPath).catch(() => {});
872
+ await fs.unlink(lockPath).catch(() => {});
1308
873
  continue;
1309
874
  }
1310
875
  if (Date.now() >= deadline)
@@ -1318,7 +883,7 @@ function withLock(name, options, effect) {
1318
883
  return lockPath;
1319
884
  });
1320
885
  return Effect2.acquireUseRelease(acquire, () => effect, (lockPath) => Effect2.tryPromise({
1321
- try: () => fs2.unlink(lockPath).catch(() => {}).then(() => {}),
886
+ try: () => fs.unlink(lockPath).catch(() => {}).then(() => {}),
1322
887
  catch: (cause) => new AuthProfileError({ message: `Could not release auth profile lock: ${name}`, operation: "lock", reason: "write-failed", cause })
1323
888
  }));
1324
889
  }
@@ -1405,7 +970,7 @@ function summary(profile) {
1405
970
  }
1406
971
  var profileNamePattern = /^[a-z0-9][a-z0-9._-]{0,63}$/i;
1407
972
  function profilePath(baseDir, name) {
1408
- return profileNamePattern.test(name) ? Effect2.succeed(path2.join(baseDir, `${name}.json`)) : Effect2.fail(new AuthProfileError({ message: `Invalid auth profile name: ${name}`, operation: "path", reason: "invalid-name" }));
973
+ return profileNamePattern.test(name) ? Effect2.succeed(path.join(baseDir, `${name}.json`)) : Effect2.fail(new AuthProfileError({ message: `Invalid auth profile name: ${name}`, operation: "path", reason: "invalid-name" }));
1409
974
  }
1410
975
  function sameSlots(left, right) {
1411
976
  return JSON.stringify(left) === JSON.stringify(right);
@@ -1438,7 +1003,7 @@ function redactOutput(text, slots, maxBytes) {
1438
1003
  }
1439
1004
  function runChild(options) {
1440
1005
  return Effect2.callback((resume) => {
1441
- const child = spawn2(options.command, [...options.args], {
1006
+ const child = spawn(options.command, [...options.args], {
1442
1007
  ...options.cwd ? { cwd: options.cwd } : {},
1443
1008
  env: childEnvironment(options.env),
1444
1009
  detached: process.platform !== "win32",
@@ -1511,7 +1076,7 @@ function childEnvironment(profile) {
1511
1076
 
1512
1077
  // src/auth/domain-policy.ts
1513
1078
  import dns from "node:dns/promises";
1514
- import net2 from "node:net";
1079
+ import net from "node:net";
1515
1080
 
1516
1081
  class OriginPatternError extends Error {
1517
1082
  name = "OriginPatternError";
@@ -1547,7 +1112,7 @@ function parseOriginPattern(raw) {
1547
1112
  throw new OriginPatternError(`Origin pattern ${JSON.stringify(raw)} must be a host or origin`);
1548
1113
  }
1549
1114
  const host = unbracket(parsed.hostname.toLowerCase());
1550
- if (wildcard && net2.isIP(host))
1115
+ if (wildcard && net.isIP(host))
1551
1116
  throw new OriginPatternError(`Origin pattern ${JSON.stringify(raw)}: wildcards don't apply to IP addresses`);
1552
1117
  if (wildcard && !host.includes("."))
1553
1118
  throw new OriginPatternError(`Origin pattern ${JSON.stringify(raw)}: "*." needs a domain with a dot, like *.example.com`);
@@ -1592,14 +1157,14 @@ var privateIpv4Ranges = [
1592
1157
  ];
1593
1158
  function isPrivateAddress(address) {
1594
1159
  const ip = unbracket(address.toLowerCase()).replace(/%.*$/, "");
1595
- if (net2.isIPv4(ip)) {
1160
+ if (net.isIPv4(ip)) {
1596
1161
  const value = ipv4ToNumber(ip);
1597
1162
  return privateIpv4Ranges.some(([base, bits]) => {
1598
1163
  const mask = bits === 0 ? 0 : 4294967295 << 32 - bits >>> 0;
1599
1164
  return (value & mask) >>> 0 === (ipv4ToNumber(base) & mask) >>> 0;
1600
1165
  });
1601
1166
  }
1602
- if (net2.isIPv6(ip)) {
1167
+ if (net.isIPv6(ip)) {
1603
1168
  if (ip === "::" || ip === "::1")
1604
1169
  return true;
1605
1170
  const mapped = /^(?:0*:)*:?ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(ip) ?? /^::(\d+\.\d+\.\d+\.\d+)$/.exec(ip);
@@ -1625,7 +1190,7 @@ function isLocalhostName(host) {
1625
1190
  }
1626
1191
  function isPrivateHost(host) {
1627
1192
  const bare = unbracket(host.toLowerCase());
1628
- return isLocalhostName(bare) || net2.isIP(bare) !== 0 && isPrivateAddress(bare);
1193
+ return isLocalhostName(bare) || net.isIP(bare) !== 0 && isPrivateAddress(bare);
1629
1194
  }
1630
1195
  function defaultPort(protocol) {
1631
1196
  return protocol === "https:" ? "443" : "80";
@@ -1676,7 +1241,7 @@ function checkUrl(rawUrl, rules, options = {}) {
1676
1241
  }
1677
1242
  async function resolvesToPrivateAddress(host, timeoutMs = 2000) {
1678
1243
  const bare = unbracket(host);
1679
- if (net2.isIP(bare) || isLocalhostName(bare))
1244
+ if (net.isIP(bare) || isLocalhostName(bare))
1680
1245
  return isPrivateHost(bare) ? bare : undefined;
1681
1246
  let timer;
1682
1247
  try {
@@ -1722,9 +1287,9 @@ class SiteSecretError extends Schema2.TaggedError()("SiteSecret.Error", {
1722
1287
  cause: Schema2.optionalKey(Schema2.Defect())
1723
1288
  }) {
1724
1289
  }
1725
- var defaultSiteSecretsDir = () => path3.join(dataRoot(), "site-secrets");
1290
+ var defaultSiteSecretsDir = () => path2.join(dataRoot(), "site-secrets");
1726
1291
  function secretPath(baseDir, name) {
1727
- return profileNamePattern.test(name) ? Effect3.succeed(path3.join(baseDir, `${name}.json`)) : Effect3.fail(new SiteSecretError({ message: `Invalid secret name: ${name} (letters, digits, ".", "_" and "-", up to 64)`, reason: "invalid-name" }));
1292
+ return profileNamePattern.test(name) ? Effect3.succeed(path2.join(baseDir, `${name}.json`)) : Effect3.fail(new SiteSecretError({ message: `Invalid secret name: ${name} (letters, digits, ".", "_" and "-", up to 64)`, reason: "invalid-name" }));
1728
1293
  }
1729
1294
  function summary2(secret) {
1730
1295
  return { name: secret.name, kind: secret.kind, allowedOrigins: [...secret.allowedOrigins], createdAt: secret.createdAt, updatedAt: secret.updatedAt };
@@ -1732,7 +1297,7 @@ function summary2(secret) {
1732
1297
  var readSecret = Effect3.fn("SiteSecrets.read")(function* (name, options = {}) {
1733
1298
  const filePath = yield* secretPath(options.baseDir ?? defaultSiteSecretsDir(), name);
1734
1299
  const text = yield* Effect3.tryPromise({
1735
- try: () => fs3.readFile(filePath, "utf8"),
1300
+ try: () => fs2.readFile(filePath, "utf8"),
1736
1301
  catch: (cause) => isNodeError(cause) && cause.code === "ENOENT" ? new SiteSecretError({ message: `Secret not found: ${name}. Ask the user to add it with \`opencode-browser secrets add ${name} --origin <origin>\`.`, reason: "not-found" }) : new SiteSecretError({ message: `Could not read secret ${name}`, reason: "read-failed", cause })
1737
1302
  });
1738
1303
  return yield* Effect3.try({
@@ -1774,7 +1339,7 @@ var addSecret = Effect3.fn("SiteSecrets.add")(function* (options) {
1774
1339
  var listSecrets = Effect3.fn("SiteSecrets.list")(function* (options = {}) {
1775
1340
  const baseDir = options.baseDir ?? defaultSiteSecretsDir();
1776
1341
  const names = yield* Effect3.tryPromise({
1777
- try: () => fs3.readdir(baseDir).catch((cause) => isNodeError(cause) && cause.code === "ENOENT" ? [] : Promise.reject(cause)),
1342
+ try: () => fs2.readdir(baseDir).catch((cause) => isNodeError(cause) && cause.code === "ENOENT" ? [] : Promise.reject(cause)),
1778
1343
  catch: (cause) => new SiteSecretError({ message: "Could not list secrets", reason: "read-failed", cause })
1779
1344
  });
1780
1345
  const secrets = [];
@@ -1789,7 +1354,7 @@ var removeSecret = Effect3.fn("SiteSecrets.remove")(function* (name, options = {
1789
1354
  const baseDir = options.baseDir ?? defaultSiteSecretsDir();
1790
1355
  const filePath = yield* secretPath(baseDir, name);
1791
1356
  return yield* withLock(name, { baseDir }, Effect3.tryPromise({
1792
- try: () => fs3.rm(filePath).then(() => true, (cause) => isNodeError(cause) && cause.code === "ENOENT" ? false : Promise.reject(cause)),
1357
+ try: () => fs2.rm(filePath).then(() => true, (cause) => isNodeError(cause) && cause.code === "ENOENT" ? false : Promise.reject(cause)),
1793
1358
  catch: (cause) => new SiteSecretError({ message: `Could not remove secret ${name}`, reason: "write-failed", cause })
1794
1359
  })).pipe(Effect3.mapError((error) => error instanceof SiteSecretError ? error : new SiteSecretError({ message: error.message, reason: "write-failed", cause: error })));
1795
1360
  });
@@ -1831,7 +1396,7 @@ function totpCode(seed, now = Date.now()) {
1831
1396
  const { key, digits, period, algorithm } = totpParameters(seed);
1832
1397
  const counter = Buffer.alloc(8);
1833
1398
  counter.writeBigUInt64BE(BigInt(Math.floor(now / 1000 / period)));
1834
- const hmac = crypto2.createHmac(algorithm, key).update(counter).digest();
1399
+ const hmac = crypto.createHmac(algorithm, key).update(counter).digest();
1835
1400
  const offset = hmac[hmac.length - 1] & 15;
1836
1401
  const binary = (hmac.readUInt32BE(offset) & 2147483647) % 10 ** digits;
1837
1402
  return String(binary).padStart(digits, "0");
@@ -1840,4 +1405,4 @@ function secretText(secret) {
1840
1405
  return secret.kind === "totp" ? totpCode(secret.value) : secret.value;
1841
1406
  }
1842
1407
 
1843
- export { settingKeys, settingSpecs, securityVariables, SettingsInputError, parseSettingChanges, settingsFromExtension, settingsToExtension, describeSettings, describeChanges, formatSettings, browsersNote2, mcpUpdateNote2, objectSchema, emptyInputSchema, sessionSchemaProperty, sessionAliasSchemaProperty, sessionOnlyInputSchema, ensureSessionExists, parseExecuteArguments, parseAdoptArguments, requiredStringField, optionalStringField, optionalBooleanField, optionalPositiveIntegerField, optionalStringArrayField, requireObject, toolResultForValue2, mcpErrorMessage2, toolResult, DeadboltError, readClient, socketPath, connect, parseDeadboltName, originOnSite, pickLogin, originsFromPatterns, listLogins, pickPasskey, pair, unpair, isBase64Url, randomName, terminateChildProcess, SecretCollector, looksLikeTokenSegment, AuthProfileError, read, readOptional, withLock, write, status, run, OriginPatternError, parseOriginPatterns, normalizeOriginPatterns, isPrivateAddress, explicitlyAllowsHost, checkUrl, checkNavigationUrl, readSecret, addSecret, listSecrets, removeSecret, secretText };
1408
+ export { settingKeys, settingSpecs, securityVariables, SettingsInputError, parseSettingChanges, settingsFromExtension, settingsToExtension, describeSettings, describeChanges, formatSettings, browsersNote2, mcpUpdateNote2, objectSchema, emptyInputSchema, sessionSchemaProperty, sessionAliasSchemaProperty, sessionOnlyInputSchema, ensureSessionExists, parseExecuteArguments, parseAdoptArguments, requiredStringField, optionalStringField, optionalBooleanField, optionalPositiveIntegerField, optionalStringArrayField, requireObject, toolResultForValue2, mcpErrorMessage2, toolResult, terminateChildProcess, SecretCollector, looksLikeTokenSegment, AuthProfileError, read, readOptional, withLock, write, status, run, OriginPatternError, parseOriginPatterns, normalizeOriginPatterns, isPrivateAddress, explicitlyAllowsHost, checkUrl, checkNavigationUrl, readSecret, addSecret, listSecrets, removeSecret, secretText };