@opencode/browse 0.0.6-dev.17 → 0.0.6-dev.18

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.
@@ -8,7 +8,7 @@ import {
8
8
  devExtension,
9
9
  installCommand,
10
10
  autoUpdateStatus
11
- } from "./main-g5mke6rn.mjs";
11
+ } from "./main-ha5bnd77.mjs";
12
12
  import {
13
13
  defaultPort2,
14
14
  isValidSessionId2,
@@ -27,11 +27,17 @@ import {
27
27
  ensureExtensionConnected,
28
28
  stoppedRelayStatus,
29
29
  statusCollections
30
- } from "./main-3qpkwaa7.mjs";
30
+ } from "./main-jjny7bmm.mjs";
31
+ import"./main-9y22cffn.mjs";
31
32
  import {
32
33
  opencodeBrowserVersion2,
33
34
  opencodeBrowserBuildId2
34
- } from "./main-y7c1atbf.mjs";
35
+ } from "./main-ppz7sv9s.mjs";
36
+ import {
37
+ defaultJournalBaseDir,
38
+ readJournalEntries,
39
+ formatJournalEntry
40
+ } from "./main-d7rbre73.mjs";
35
41
  import {
36
42
  addSecret,
37
43
  listSecrets,
@@ -43,18 +49,12 @@ import {
43
49
  unpair,
44
50
  settingKeys,
45
51
  formatSettings
46
- } from "./main-e4stqtf2.mjs";
47
- import {
48
- defaultJournalBaseDir,
49
- readJournalEntries,
50
- formatJournalEntry
51
- } from "./main-kvmxefp1.mjs";
52
+ } from "./main-fkhwazsm.mjs";
52
53
  import {
53
54
  updateJson2,
54
55
  formatUpdateNotice2,
55
56
  updateNotice2
56
- } from "./main-4p2p9eey.mjs";
57
- import"./main-4bht27ry.mjs";
57
+ } from "./main-w5sta7hq.mjs";
58
58
 
59
59
  // src/cli.ts
60
60
  import { NodeRuntime, NodeServices } from "@effect/platform-node";
@@ -211,10 +211,9 @@ var createDoctorReport = Effect2.fn("Doctor.createReport")(function* (options) {
211
211
  }
212
212
  })));
213
213
  const fileExists = (relativePath) => fs.exists(path.join(options.packageRoot, relativePath)).pipe(Effect2.orElseSucceed(() => false));
214
- const [packageResult, distCliExists, distMcpExists, currentResult] = yield* Effect2.all([
214
+ const [packageResult, distCliExists, currentResult] = yield* Effect2.all([
215
215
  probe(readPackageInfo),
216
216
  fileExists("dist/cli.mjs"),
217
- fileExists("dist/cli.mjs"),
218
217
  probe(store.read)
219
218
  ]);
220
219
  const expectedExtensionVersion = packageResult.ok ? { ok: true, value: extensionManifestVersion(packageResult.value.version) } : packageResult;
@@ -248,7 +247,7 @@ var createDoctorReport = Effect2.fn("Doctor.createReport")(function* (options) {
248
247
  return session.connected && session.id !== current;
249
248
  });
250
249
  const artifacts = [
251
- { path: "dist/cli.mjs", exists: distCliExists && distMcpExists }
250
+ { path: "dist/cli.mjs", exists: distCliExists }
252
251
  ];
253
252
  const checks = buildDoctorChecks({
254
253
  packageResult,
@@ -811,7 +810,7 @@ function errorJsonEnvelope(error) {
811
810
  return { ok: false, isError: true, text: message, value: null, valueUnavailable: true, error: errorValue, logs: [], warnings: [] };
812
811
  }
813
812
  var serve = Command.make("serve", {}, Effect3.fn("Cli.serve")(function* () {
814
- const [{ startRelay }, { parseAdditionalExtensionOrigins }] = yield* Effect3.promise(() => Promise.all([import("./relay-ns525pms.mjs"), import("./relay-helpers-pjcbxs7p.mjs")]));
813
+ const [{ startRelay }, { parseAdditionalExtensionOrigins }] = yield* Effect3.promise(() => Promise.all([import("./relay-zs96tkfm.mjs"), import("./relay-helpers-6a2vvzx9.mjs")]));
815
814
  const port = yield* portConfig;
816
815
  const additionalExtensionOrigins = parseAdditionalExtensionOrigins(yield* extensionOriginsConfig);
817
816
  yield* Effect3.scoped(Effect3.gen(function* () {
@@ -1681,7 +1680,7 @@ var settingsSet = Command.make("set", {
1681
1680
  })).pipe(Command.withDescription("Change settings (validated strictly; the extension's options page updates live)"));
1682
1681
  var settings = Command.make("settings").pipe(Command.withDescription("Read or change the user's settings (the extension's options page). Security switches are environment-only"), Command.withSubcommands([settingsGet, settingsSet]));
1683
1682
  var mcp = Command.make("mcp", {}, Effect3.fn("Cli.mcp")(function* () {
1684
- const { runMcpServer } = yield* Effect3.promise(() => import("./mcp-2smdsn8z.mjs"));
1683
+ const { runMcpServer } = yield* Effect3.promise(() => import("./mcp-qh25n9s0.mjs"));
1685
1684
  yield* runMcpServer;
1686
1685
  })).pipe(Command.withDescription("Run the Browse MCP server over stdio"));
1687
1686
  var opencodeBrowser = Command.make("opencode-browser").pipe(Command.withDescription("Control the user's existing browser through the Browse extension"), Command.withSubcommands([serve, relay, execute, session, tabs, settings, status, network, secrets, deadbolt, recording, flightRecorder, journal, doctor, skill, mcp]));
package/dist/cli.mjs CHANGED
@@ -2,26 +2,26 @@
2
2
 
3
3
  // src/main.ts
4
4
  import path from "node:path";
5
- var embeddedVersion = "0.0.6-dev.17";
5
+ var embeddedVersion = "0.0.6-dev.18";
6
6
  var setupCommands = new Set(["install", "uninstall", "extension", "pair", "rollback", "set"]);
7
7
  var command = process.argv[2];
8
8
  var invokedAs = path.basename(process.argv[1] ?? "");
9
9
  if (command === "--version" || command === "-v") {
10
- const opencodeBrowserVersion = embeddedVersion ?? (await import("./version-wrebjhy7.mjs")).opencodeBrowserVersion;
10
+ const opencodeBrowserVersion = embeddedVersion ?? (await import("./version-6g6gtnra.mjs")).opencodeBrowserVersion;
11
11
  process.stdout.write(`${opencodeBrowserVersion}
12
12
  `);
13
- } else if (invokedAs === "opencode-browser-mcp") {
13
+ } else if (invokedAs === "opencode-browser-mcp" || command === "mcp" && process.argv.length === 3) {
14
14
  const { NodeRuntime } = await import("@effect/platform-node");
15
- const { runMcpServer } = await import("./mcp-2smdsn8z.mjs");
15
+ const { runMcpServer } = await import("./mcp-qh25n9s0.mjs");
16
16
  runMcpServer.pipe(NodeRuntime.runMain);
17
17
  } else if (command === "runtime-install" || command === "runtime-switch") {
18
- const { runRuntimeInstall, runRuntimeSwitch } = await import("./runtime-update-0mddkfy5.mjs");
18
+ const { runRuntimeInstall, runRuntimeSwitch } = await import("./runtime-update-8wte78jj.mjs");
19
19
  await (command === "runtime-install" ? runRuntimeInstall : runRuntimeSwitch)(process.argv.slice(3));
20
20
  } else if (command === "update") {
21
- const { runUpdateCommand } = await import("./update-cyy1grjj.mjs");
21
+ const { runUpdateCommand } = await import("./update-st5c8grg.mjs");
22
22
  await runUpdateCommand(process.argv.slice(3));
23
23
  } else if (command && setupCommands.has(command)) {
24
- const { runSetup } = await import("./setup-f2qjnvre.mjs");
24
+ const { runSetup } = await import("./setup-cqjdfcy0.mjs");
25
25
  await runSetup(command, process.argv.slice(3));
26
26
  } else {
27
27
  if (!command || command === "--help" || command === "-h") {
@@ -55,9 +55,9 @@ if (command === "--version" || command === "-v") {
55
55
  `);
56
56
  }
57
57
  if (command === "status" && !process.argv.includes("--json")) {
58
- const { printSetupStatus } = await import("./setup-f2qjnvre.mjs");
58
+ const { printSetupStatus } = await import("./setup-cqjdfcy0.mjs");
59
59
  printSetupStatus();
60
60
  }
61
- const { runCli } = await import("./cli-b4sbkefj.mjs");
61
+ const { runCli } = await import("./cli-z00ttket.mjs");
62
62
  runCli();
63
63
  }
@@ -1,11 +1,11 @@
1
1
  import {
2
- ensurePrivateDirectory
3
- } from "./main-4bht27ry.mjs";
2
+ writePrivateJsonFileSync
3
+ } from "./main-9y22cffn.mjs";
4
4
  import {
5
5
  dataRoot,
6
6
  devExtensionUrl,
7
7
  devExtensionFolder
8
- } from "./main-g5mke6rn.mjs";
8
+ } from "./main-ha5bnd77.mjs";
9
9
 
10
10
  // src/browser-pairing.ts
11
11
  import crypto from "node:crypto";
@@ -45,7 +45,7 @@ function writePendingCodes(root, pending) {
45
45
  fs.rmSync(pairingCodesPath(root), { force: true });
46
46
  return;
47
47
  }
48
- writePrivateJson(pairingCodesPath(root), pending);
48
+ writePrivateJsonFileSync(pairingCodesPath(root), pending, { ensureParent: true });
49
49
  }
50
50
  function mintPairingCode(root = dataRoot(), options = {}) {
51
51
  const now = options.now ?? Date.now();
@@ -71,7 +71,7 @@ function recordPairingFailure(root = dataRoot(), now = Date.now()) {
71
71
  return exhausted && pending.codes.length > 0;
72
72
  }
73
73
  function writeExtensionPairing(extensionDirectory, code) {
74
- writePrivateJson(path.join(extensionDirectory, extensionPairingFileName), { code });
74
+ writePrivateJsonFileSync(path.join(extensionDirectory, extensionPairingFileName), { code });
75
75
  }
76
76
  function readBrowserPairings(root = dataRoot()) {
77
77
  try {
@@ -84,8 +84,7 @@ function readBrowserPairings(root = dataRoot()) {
84
84
  }
85
85
  }
86
86
  function writeBrowserPairings(root, pairings) {
87
- ensurePrivateDirectory(root);
88
- writePrivateJson(browserTokensPath(root), pairings);
87
+ writePrivateJsonFileSync(browserTokensPath(root), pairings, { ensureParent: true });
89
88
  }
90
89
  function browserToken(key, root = dataRoot()) {
91
90
  return readBrowserPairings(root)[key]?.token;
@@ -155,12 +154,6 @@ function wrapToken(sessionKey, token) {
155
154
  const mask = crypto.createHmac("sha256", sessionKey).update(`${context}|wrap`).digest();
156
155
  return Buffer.from(Buffer.from(token, "base64url").map((byte, index) => byte ^ mask[index])).toString("base64url");
157
156
  }
158
- function writePrivateJson(file, value) {
159
- const temporary = `${file}.${process.pid}.${crypto.randomUUID()}.tmp`;
160
- fs.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}
161
- `, { mode: 384 });
162
- fs.renameSync(temporary, file);
163
- }
164
157
 
165
158
  // src/dev-extension.ts
166
159
  import { createHash } from "node:crypto";
@@ -299,12 +292,7 @@ function readRelayConfig(root = dataRoot()) {
299
292
  }
300
293
  }
301
294
  function writeRelayConfig(config, root = dataRoot()) {
302
- fs2.mkdirSync(root, { recursive: true, mode: 448 });
303
- const file = relayConfigPath(root);
304
- const temporary = `${file}.${process.pid}.tmp`;
305
- fs2.writeFileSync(temporary, `${JSON.stringify(config, null, 2)}
306
- `, { mode: 384 });
307
- fs2.renameSync(temporary, file);
295
+ writePrivateJsonFileSync(relayConfigPath(root), config, { ensureParent: true });
308
296
  }
309
297
  var relayHostname = (root = dataRoot()) => readRelayConfig(root).hostname ?? "127.0.0.1";
310
298
  function isLocalPeer(socket) {
@@ -0,0 +1,130 @@
1
+ import {
2
+ dataRoot
3
+ } from "./main-ha5bnd77.mjs";
4
+
5
+ // src/relay-secrets.ts
6
+ import crypto2 from "node:crypto";
7
+ import fs2 from "node:fs";
8
+ import path2 from "node:path";
9
+
10
+ // src/fs-durability.ts
11
+ import { Predicate } from "effect";
12
+ import crypto from "node:crypto";
13
+ import fsSync from "node:fs";
14
+ import fs from "node:fs/promises";
15
+ import path from "node:path";
16
+ var unsupportedDirectorySyncCodes = new Set(["EPERM", "EINVAL", "ENOTSUP"]);
17
+ function isNodeError(error) {
18
+ return error instanceof Error && "code" in error;
19
+ }
20
+ function isUnsupportedDirectorySyncError(error) {
21
+ return isNodeError(error) && Predicate.isString(error.code) && unsupportedDirectorySyncCodes.has(error.code);
22
+ }
23
+ async function writeJsonFileAtomically(filePath, value, options = {}) {
24
+ const directory = path.dirname(filePath);
25
+ await fs.mkdir(directory, {
26
+ recursive: true,
27
+ ...options.dirMode === undefined ? {} : { mode: options.dirMode }
28
+ });
29
+ if (options.dirMode !== undefined) {
30
+ await fs.chmod(directory, options.dirMode);
31
+ }
32
+ const temporaryPath = `${filePath}.${process.pid}.${crypto.randomUUID()}.tmp`;
33
+ let renamed = false;
34
+ try {
35
+ await fs.writeFile(temporaryPath, `${JSON.stringify(value, null, 2)}
36
+ `, { mode: 384 });
37
+ await fs.rename(temporaryPath, filePath);
38
+ renamed = true;
39
+ await fs.chmod(filePath, 384);
40
+ } finally {
41
+ if (!renamed)
42
+ await fs.rm(temporaryPath, { force: true }).catch(() => {});
43
+ }
44
+ }
45
+ function ensurePrivateDirectorySync(directory) {
46
+ fsSync.mkdirSync(directory, { recursive: true, mode: 448 });
47
+ if (process.platform !== "win32")
48
+ fsSync.chmodSync(directory, 448);
49
+ }
50
+ function writePrivateJsonFileSync(filePath, value, options = {}) {
51
+ if (options.ensureParent)
52
+ ensurePrivateDirectorySync(path.dirname(filePath));
53
+ const temporaryPath = `${filePath}.${process.pid}.${crypto.randomUUID()}.tmp`;
54
+ let renamed = false;
55
+ try {
56
+ fsSync.writeFileSync(temporaryPath, `${JSON.stringify(value, null, 2)}
57
+ `, { mode: 384 });
58
+ fsSync.renameSync(temporaryPath, filePath);
59
+ renamed = true;
60
+ if (process.platform !== "win32")
61
+ fsSync.chmodSync(filePath, 384);
62
+ } finally {
63
+ if (!renamed)
64
+ fsSync.rmSync(temporaryPath, { force: true });
65
+ }
66
+ }
67
+
68
+ // src/relay-secrets.ts
69
+ var relayTokenQueryParam = "opencodeBrowserToken";
70
+ var tokenPattern = /^[A-Za-z0-9_-]{43}$/;
71
+ function relayTokenPath(root = dataRoot()) {
72
+ return path2.join(root, "relay-token");
73
+ }
74
+ function relayToken(root = dataRoot()) {
75
+ return readOrCreateSecret(relayTokenPath(root), () => crypto2.randomBytes(32).toString("base64url"), (value) => tokenPattern.test(value));
76
+ }
77
+ function relayAuthorization(root = dataRoot()) {
78
+ return `Bearer ${relayToken(root)}`;
79
+ }
80
+ function secretsEqual(expected, actual) {
81
+ if (actual === undefined)
82
+ return false;
83
+ const a = crypto2.createHash("sha256").update(expected).digest();
84
+ const b = crypto2.createHash("sha256").update(actual).digest();
85
+ return crypto2.timingSafeEqual(a, b) && expected.length === actual.length;
86
+ }
87
+ function readOrCreateSecret(file, generate, valid) {
88
+ const existing = readSecret(file);
89
+ if (existing !== undefined && valid(existing))
90
+ return existing;
91
+ ensurePrivateDirectory(path2.dirname(file));
92
+ const temporary = `${file}.${process.pid}.${crypto2.randomUUID()}.tmp`;
93
+ fs2.writeFileSync(temporary, `${generate()}
94
+ `, { mode: 384 });
95
+ try {
96
+ if (existing === undefined) {
97
+ try {
98
+ fs2.linkSync(temporary, file);
99
+ } catch (error) {
100
+ if (error.code !== "EEXIST")
101
+ throw error;
102
+ }
103
+ } else {
104
+ fs2.renameSync(temporary, file);
105
+ }
106
+ } finally {
107
+ fs2.rmSync(temporary, { force: true });
108
+ }
109
+ const created = readSecret(file);
110
+ if (created === undefined || !valid(created))
111
+ throw new Error(`Could not create ${file}`);
112
+ return created;
113
+ }
114
+ function readSecret(file) {
115
+ try {
116
+ const stat = fs2.statSync(file);
117
+ if (process.platform !== "win32" && (stat.mode & 63) !== 0)
118
+ fs2.chmodSync(file, 384);
119
+ return fs2.readFileSync(file, "utf8").trim();
120
+ } catch (error) {
121
+ if (error.code === "ENOENT")
122
+ return;
123
+ throw error;
124
+ }
125
+ }
126
+ function ensurePrivateDirectory(directory = dataRoot()) {
127
+ ensurePrivateDirectorySync(directory);
128
+ }
129
+
130
+ export { isNodeError, isUnsupportedDirectorySyncError, writeJsonFileAtomically, ensurePrivateDirectorySync, writePrivateJsonFileSync, relayTokenQueryParam, relayToken, relayAuthorization, secretsEqual, ensurePrivateDirectory };
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  isNodeError
3
- } from "./main-e4stqtf2.mjs";
3
+ } from "./main-9y22cffn.mjs";
4
4
  import {
5
5
  dataRoot
6
- } from "./main-g5mke6rn.mjs";
6
+ } from "./main-ha5bnd77.mjs";
7
7
  import {
8
8
  isValidSessionId2
9
- } from "./main-3qpkwaa7.mjs";
9
+ } from "./main-jjny7bmm.mjs";
10
10
 
11
11
  // src/session-journal.ts
12
12
  import fs from "node:fs";
@@ -1,19 +1,23 @@
1
+ import {
2
+ isNodeError,
3
+ writeJsonFileAtomically
4
+ } from "./main-9y22cffn.mjs";
1
5
  import {
2
6
  dataRoot,
3
7
  cliCommand
4
- } from "./main-g5mke6rn.mjs";
8
+ } from "./main-ha5bnd77.mjs";
5
9
 
6
10
  // src/site-secrets.ts
7
- import crypto2 from "node:crypto";
8
- import fs3 from "node:fs/promises";
9
- import path3 from "node:path";
11
+ import crypto from "node:crypto";
12
+ import fs2 from "node:fs/promises";
13
+ import path2 from "node:path";
10
14
  import { Effect as Effect2, Schema as Schema2 } from "effect";
11
15
 
12
16
  // src/auth-profile.ts
13
17
  import { Effect, Schema, Semaphore } from "effect";
14
18
  import { spawn } from "node:child_process";
15
- import fs2 from "node:fs/promises";
16
- import path2 from "node:path";
19
+ import fs from "node:fs/promises";
20
+ import path from "node:path";
17
21
 
18
22
  // src/child-process.ts
19
23
  async function terminateChildProcess(options) {
@@ -45,43 +49,8 @@ function signalChildProcess(child, signal) {
45
49
  child.kill(signal);
46
50
  }
47
51
 
48
- // src/fs-durability.ts
49
- import { Predicate } from "effect";
50
- import crypto from "node:crypto";
51
- import fs from "node:fs/promises";
52
- import path from "node:path";
53
- var unsupportedDirectorySyncCodes = new Set(["EPERM", "EINVAL", "ENOTSUP"]);
54
- function isNodeError(error) {
55
- return error instanceof Error && "code" in error;
56
- }
57
- function isUnsupportedDirectorySyncError(error) {
58
- return isNodeError(error) && Predicate.isString(error.code) && unsupportedDirectorySyncCodes.has(error.code);
59
- }
60
- async function writeJsonFileAtomically(filePath, value, options = {}) {
61
- const directory = path.dirname(filePath);
62
- await fs.mkdir(directory, {
63
- recursive: true,
64
- ...options.dirMode === undefined ? {} : { mode: options.dirMode }
65
- });
66
- if (options.dirMode !== undefined) {
67
- await fs.chmod(directory, options.dirMode);
68
- }
69
- const temporaryPath = `${filePath}.${process.pid}.${crypto.randomUUID()}.tmp`;
70
- let renamed = false;
71
- try {
72
- await fs.writeFile(temporaryPath, `${JSON.stringify(value, null, 2)}
73
- `, { mode: 384 });
74
- await fs.rename(temporaryPath, filePath);
75
- renamed = true;
76
- await fs.chmod(filePath, 384);
77
- } finally {
78
- if (!renamed)
79
- await fs.rm(temporaryPath, { force: true }).catch(() => {});
80
- }
81
- }
82
-
83
52
  // src/network-redaction.ts
84
- import { Predicate as Predicate2 } from "effect";
53
+ import { Predicate } from "effect";
85
54
  var secretNamePattern = /auth(?:orization)?|cookie|credential|csrf|xsrf|token|secret|session|password|passwd|pwd|passcode|otp|(?:^|[-_.])code(?:$|[-_.])|(?:api|access|refresh)[-_.]?key|signature|(?:^|[-_.])sig(?:$|[-_.])/i;
86
55
  var oneTimeFieldPattern = /pass(?:word|wd|code|phrase)|(?:^|[-_.])pwd(?:$|[-_.])|otp|totp|(?:^|[-_.])(?:mfa_?|2fa_?|verification_?|auth_?)?code(?:$|[-_.])|(?:^|[-_.])pin(?:$|[-_.])/i;
87
56
  var referencePattern = String.raw`BC_(?:SECRET|REDACTED)_\d+`;
@@ -188,7 +157,7 @@ class SecretCollector {
188
157
  return redactKnownValue(value, this.redactionSlots());
189
158
  }
190
159
  redactExactValue(value, minimumLength) {
191
- if (!Predicate2.isString(value) && !Predicate2.isNumber(value) && !Predicate2.isBoolean(value))
160
+ if (!Predicate.isString(value) && !Predicate.isNumber(value) && !Predicate.isBoolean(value))
192
161
  return value;
193
162
  const serialized = String(value);
194
163
  if (serialized.length < minimumLength)
@@ -279,7 +248,7 @@ class SecretCollector {
279
248
  if (Array.isArray(value)) {
280
249
  return value.map((item, index) => this.protectJson(item, location, [...path, String(index)], inSecret));
281
250
  }
282
- if (Predicate2.isObject(value)) {
251
+ if (Predicate.isObject(value)) {
283
252
  return Object.fromEntries(Object.entries(value).map(([key, item]) => [
284
253
  key,
285
254
  this.protectJson(item, location, [...path, key], inSecret || secretNamePattern.test(key))
@@ -473,15 +442,15 @@ function redactKnownValues(text, slots) {
473
442
  return [...slots].sort((left, right) => right.value.length - left.value.length).reduce((output, slot) => replaceOutsideReferences(output, slot.value, `\${${slot.ref}}`), text);
474
443
  }
475
444
  function redactKnownValue(value, slots) {
476
- if (Predicate2.isString(value))
445
+ if (Predicate.isString(value))
477
446
  return redactKnownValues(value, slots);
478
- if (Predicate2.isNumber(value) || Predicate2.isBoolean(value)) {
447
+ if (Predicate.isNumber(value) || Predicate.isBoolean(value)) {
479
448
  const slot = slots.find((candidate) => candidate.value === String(value));
480
449
  return slot ? `\${${slot.ref}}` : value;
481
450
  }
482
451
  if (Array.isArray(value))
483
452
  return value.map((item) => redactKnownValue(item, slots));
484
- if (!Predicate2.isObject(value))
453
+ if (!Predicate.isObject(value))
485
454
  return value;
486
455
  return Object.fromEntries(Object.entries(value).map(([key, item]) => [
487
456
  key,
@@ -491,7 +460,7 @@ function redactKnownValue(value, slots) {
491
460
  function redactSecretValue(value) {
492
461
  if (Array.isArray(value))
493
462
  return value.map(redactSecretValue);
494
- if (Predicate2.isObject(value)) {
463
+ if (Predicate.isObject(value)) {
495
464
  return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, redactSecretValue(item)]));
496
465
  }
497
466
  return value === null || value === "" ? value : "[REDACTED]";
@@ -516,7 +485,7 @@ function jwtExpiration(value) {
516
485
  return;
517
486
  try {
518
487
  const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
519
- return Predicate2.isNumber(payload.exp) ? new Date(payload.exp * 1000).toISOString() : undefined;
488
+ return Predicate.isNumber(payload.exp) ? new Date(payload.exp * 1000).toISOString() : undefined;
520
489
  } catch {
521
490
  return;
522
491
  }
@@ -550,7 +519,7 @@ class AuthProfileError extends Schema.TaggedError()("AuthProfile.Error", {
550
519
  cause: Schema.optionalKey(Schema.Defect())
551
520
  }) {
552
521
  }
553
- var defaultBaseDir = () => path2.join(dataRoot(), "secrets");
522
+ var defaultBaseDir = () => path.join(dataRoot(), "secrets");
554
523
  var writeLock = Semaphore.makeUnsafe(1);
555
524
  var profileLockTimeoutMs = 30000;
556
525
  var staleProfileLockMs = 60000;
@@ -559,7 +528,7 @@ var maximumTimeoutMs = 2147483647;
559
528
  var read = Effect.fn("AuthProfile.read")(function* (name, options = {}) {
560
529
  const filePath = yield* profilePath(options.baseDir ?? defaultBaseDir(), name);
561
530
  const text = yield* Effect.tryPromise({
562
- try: () => fs2.readFile(filePath, "utf8"),
531
+ try: () => fs.readFile(filePath, "utf8"),
563
532
  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 })
564
533
  });
565
534
  return yield* Schema.decodeUnknownEffect(StoredAuthProfile)(yield* Effect.try({
@@ -577,12 +546,12 @@ function withLock(name, options, effect) {
577
546
  const lockPath = `${filePath}.lock`;
578
547
  yield* Effect.tryPromise({
579
548
  try: async () => {
580
- await fs2.mkdir(baseDir, { recursive: true, mode: 448 });
581
- await fs2.chmod(baseDir, 448);
549
+ await fs.mkdir(baseDir, { recursive: true, mode: 448 });
550
+ await fs.chmod(baseDir, 448);
582
551
  const deadline = Date.now() + profileLockTimeoutMs;
583
552
  while (true) {
584
553
  try {
585
- const handle = await fs2.open(lockPath, "wx", 384);
554
+ const handle = await fs.open(lockPath, "wx", 384);
586
555
  let written = false;
587
556
  try {
588
557
  await handle.writeFile(`${process.pid}
@@ -591,17 +560,17 @@ function withLock(name, options, effect) {
591
560
  } finally {
592
561
  await handle.close();
593
562
  if (!written)
594
- await fs2.unlink(lockPath).catch(() => {});
563
+ await fs.unlink(lockPath).catch(() => {});
595
564
  }
596
565
  return;
597
566
  } catch (cause) {
598
567
  if (!isNodeError(cause) || cause.code !== "EEXIST")
599
568
  throw cause;
600
- const stat = await fs2.stat(lockPath).catch(() => {
569
+ const stat = await fs.stat(lockPath).catch(() => {
601
570
  return;
602
571
  });
603
572
  if (stat && Date.now() - stat.mtimeMs > staleProfileLockMs) {
604
- await fs2.unlink(lockPath).catch(() => {});
573
+ await fs.unlink(lockPath).catch(() => {});
605
574
  continue;
606
575
  }
607
576
  if (Date.now() >= deadline)
@@ -615,7 +584,7 @@ function withLock(name, options, effect) {
615
584
  return lockPath;
616
585
  });
617
586
  return Effect.acquireUseRelease(acquire, () => effect, (lockPath) => Effect.tryPromise({
618
- try: () => fs2.unlink(lockPath).catch(() => {}).then(() => {}),
587
+ try: () => fs.unlink(lockPath).catch(() => {}).then(() => {}),
619
588
  catch: (cause) => new AuthProfileError({ message: `Could not release auth profile lock: ${name}`, operation: "lock", reason: "write-failed", cause })
620
589
  }));
621
590
  }
@@ -701,7 +670,7 @@ function summary(profile) {
701
670
  };
702
671
  }
703
672
  function profilePath(baseDir, name) {
704
- return /^[a-z0-9][a-z0-9._-]{0,63}$/i.test(name) ? Effect.succeed(path2.join(baseDir, `${name}.json`)) : Effect.fail(new AuthProfileError({ message: `Invalid auth profile name: ${name}`, operation: "path", reason: "invalid-name" }));
673
+ return /^[a-z0-9][a-z0-9._-]{0,63}$/i.test(name) ? Effect.succeed(path.join(baseDir, `${name}.json`)) : Effect.fail(new AuthProfileError({ message: `Invalid auth profile name: ${name}`, operation: "path", reason: "invalid-name" }));
705
674
  }
706
675
  function sameSlots(left, right) {
707
676
  return JSON.stringify(left) === JSON.stringify(right);
@@ -1018,10 +987,10 @@ class SiteSecretError extends Schema2.TaggedError()("SiteSecret.Error", {
1018
987
  cause: Schema2.optionalKey(Schema2.Defect())
1019
988
  }) {
1020
989
  }
1021
- var defaultSiteSecretsDir = () => path3.join(dataRoot(), "site-secrets");
990
+ var defaultSiteSecretsDir = () => path2.join(dataRoot(), "site-secrets");
1022
991
  var namePattern = /^[a-z0-9][a-z0-9._-]{0,63}$/i;
1023
992
  function secretPath(baseDir, name) {
1024
- return namePattern.test(name) ? Effect2.succeed(path3.join(baseDir, `${name}.json`)) : Effect2.fail(new SiteSecretError({ message: `Invalid secret name: ${name} (letters, digits, ".", "_" and "-", up to 64)`, reason: "invalid-name" }));
993
+ return namePattern.test(name) ? Effect2.succeed(path2.join(baseDir, `${name}.json`)) : Effect2.fail(new SiteSecretError({ message: `Invalid secret name: ${name} (letters, digits, ".", "_" and "-", up to 64)`, reason: "invalid-name" }));
1025
994
  }
1026
995
  function summary2(secret) {
1027
996
  return { name: secret.name, kind: secret.kind, allowedOrigins: [...secret.allowedOrigins], createdAt: secret.createdAt, updatedAt: secret.updatedAt };
@@ -1029,7 +998,7 @@ function summary2(secret) {
1029
998
  var readSecret = Effect2.fn("SiteSecrets.read")(function* (name, options = {}) {
1030
999
  const filePath = yield* secretPath(options.baseDir ?? defaultSiteSecretsDir(), name);
1031
1000
  const text = yield* Effect2.tryPromise({
1032
- try: () => fs3.readFile(filePath, "utf8"),
1001
+ try: () => fs2.readFile(filePath, "utf8"),
1033
1002
  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 })
1034
1003
  });
1035
1004
  return yield* Effect2.try({
@@ -1071,7 +1040,7 @@ var addSecret = Effect2.fn("SiteSecrets.add")(function* (options) {
1071
1040
  var listSecrets = Effect2.fn("SiteSecrets.list")(function* (options = {}) {
1072
1041
  const baseDir = options.baseDir ?? defaultSiteSecretsDir();
1073
1042
  const names = yield* Effect2.tryPromise({
1074
- try: () => fs3.readdir(baseDir).catch((cause) => isNodeError(cause) && cause.code === "ENOENT" ? [] : Promise.reject(cause)),
1043
+ try: () => fs2.readdir(baseDir).catch((cause) => isNodeError(cause) && cause.code === "ENOENT" ? [] : Promise.reject(cause)),
1075
1044
  catch: (cause) => new SiteSecretError({ message: "Could not list secrets", reason: "read-failed", cause })
1076
1045
  });
1077
1046
  const secrets = [];
@@ -1086,7 +1055,7 @@ var removeSecret = Effect2.fn("SiteSecrets.remove")(function* (name, options = {
1086
1055
  const baseDir = options.baseDir ?? defaultSiteSecretsDir();
1087
1056
  const filePath = yield* secretPath(baseDir, name);
1088
1057
  return yield* withLock(name, { baseDir }, Effect2.tryPromise({
1089
- try: () => fs3.rm(filePath).then(() => true, (cause) => isNodeError(cause) && cause.code === "ENOENT" ? false : Promise.reject(cause)),
1058
+ try: () => fs2.rm(filePath).then(() => true, (cause) => isNodeError(cause) && cause.code === "ENOENT" ? false : Promise.reject(cause)),
1090
1059
  catch: (cause) => new SiteSecretError({ message: `Could not remove secret ${name}`, reason: "write-failed", cause })
1091
1060
  })).pipe(Effect2.mapError((error) => error instanceof SiteSecretError ? error : new SiteSecretError({ message: error.message, reason: "write-failed", cause: error })));
1092
1061
  });
@@ -1128,7 +1097,7 @@ function totpCode(seed, now = Date.now()) {
1128
1097
  const { key, digits, period, algorithm } = totpParameters(seed);
1129
1098
  const counter = Buffer.alloc(8);
1130
1099
  counter.writeBigUInt64BE(BigInt(Math.floor(now / 1000 / period)));
1131
- const hmac = crypto2.createHmac(algorithm, key).update(counter).digest();
1100
+ const hmac = crypto.createHmac(algorithm, key).update(counter).digest();
1132
1101
  const offset = hmac[hmac.length - 1] & 15;
1133
1102
  const binary = (hmac.readUInt32BE(offset) & 2147483647) % 10 ** digits;
1134
1103
  return String(binary).padStart(digits, "0");
@@ -1139,11 +1108,11 @@ function secretText(secret) {
1139
1108
 
1140
1109
  // src/deadbolt.ts
1141
1110
  import { spawn as spawn2, spawnSync } from "node:child_process";
1142
- import crypto3 from "node:crypto";
1143
- import fs4 from "node:fs";
1111
+ import crypto2 from "node:crypto";
1112
+ import fs3 from "node:fs";
1144
1113
  import net2 from "node:net";
1145
1114
  import os from "node:os";
1146
- import path4 from "node:path";
1115
+ import path3 from "node:path";
1147
1116
  class DeadboltError extends Error {
1148
1117
  name = "DeadboltError";
1149
1118
  code;
@@ -1156,16 +1125,16 @@ class DeadboltError extends Error {
1156
1125
  }
1157
1126
  var clientFileName = "deadbolt-client.json";
1158
1127
  function clientFilePath(root = dataRoot()) {
1159
- return path4.join(root, clientFileName);
1128
+ return path3.join(root, clientFileName);
1160
1129
  }
1161
1130
  function readClientFile(root = dataRoot()) {
1162
1131
  let text;
1163
1132
  try {
1164
1133
  const file = clientFilePath(root);
1165
- const stat = fs4.statSync(file);
1134
+ const stat = fs3.statSync(file);
1166
1135
  if (process.platform !== "win32" && (stat.mode & 63) !== 0)
1167
- fs4.chmodSync(file, 384);
1168
- text = fs4.readFileSync(file, "utf8");
1136
+ fs3.chmodSync(file, 384);
1137
+ text = fs3.readFileSync(file, "utf8");
1169
1138
  } catch {
1170
1139
  return;
1171
1140
  }
@@ -1193,9 +1162,9 @@ async function saveClient(client, root = dataRoot()) {
1193
1162
  }
1194
1163
  function removeClient(root = dataRoot()) {
1195
1164
  const file = clientFilePath(root);
1196
- if (!fs4.existsSync(file))
1165
+ if (!fs3.existsSync(file))
1197
1166
  return false;
1198
- fs4.rmSync(file, { force: true });
1167
+ fs3.rmSync(file, { force: true });
1199
1168
  return true;
1200
1169
  }
1201
1170
  function computedSocketPath(env = process.env) {
@@ -1204,13 +1173,13 @@ function computedSocketPath(env = process.env) {
1204
1173
  const suffix = deadboltHome ? `-${blake3Hex(Buffer.from(deadboltHome, "utf8")).slice(0, 8)}` : "";
1205
1174
  const uid = typeof process.getuid === "function" ? process.getuid() : 0;
1206
1175
  const runtime = nonEmpty("XDG_RUNTIME_DIR") ?? userRuntimeDir(uid);
1207
- const directory = runtime ? path4.join(runtime, `deadbolt${suffix}`) : path4.join(nonEmpty("TMPDIR") ?? os.tmpdir(), `deadbolt${suffix}-${uid}`);
1208
- return path4.join(directory, "agent.sock");
1176
+ const directory = runtime ? path3.join(runtime, `deadbolt${suffix}`) : path3.join(nonEmpty("TMPDIR") ?? os.tmpdir(), `deadbolt${suffix}-${uid}`);
1177
+ return path3.join(directory, "agent.sock");
1209
1178
  }
1210
1179
  function userRuntimeDir(uid) {
1211
1180
  const directory = `/run/user/${uid}`;
1212
1181
  try {
1213
- const stat = fs4.statSync(directory);
1182
+ const stat = fs3.statSync(directory);
1214
1183
  return stat.isDirectory() && stat.uid === uid ? directory : undefined;
1215
1184
  } catch {
1216
1185
  return;
@@ -1519,7 +1488,7 @@ function isBase64Url(value, maxLength = 8192) {
1519
1488
  return typeof value === "string" && value.length <= maxLength && /^[A-Za-z0-9_-]*$/.test(value);
1520
1489
  }
1521
1490
  function randomName(prefix) {
1522
- return `${prefix}${crypto3.randomBytes(12).toString("hex")}`;
1491
+ return `${prefix}${crypto2.randomBytes(12).toString("hex")}`;
1523
1492
  }
1524
1493
  var blake3Iv = [1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225];
1525
1494
  var blake3Permutation = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8];
@@ -1695,4 +1664,4 @@ function formatSettings(settings) {
1695
1664
  });
1696
1665
  }
1697
1666
 
1698
- export { terminateChildProcess, isNodeError, isUnsupportedDirectorySyncError, writeJsonFileAtomically, SecretCollector, looksLikeTokenSegment, AuthProfileError, read, readOptional, withLock, write, status, run, OriginPatternError, parseOriginPatterns, normalizeOriginPatterns, isPrivateAddress, explicitlyAllowsHost, checkUrl, checkNavigationUrl, readSecret, addSecret, listSecrets, removeSecret, secretText, DeadboltError, readClient, socketPath, connect, parseDeadboltName, originOnSite, pickLogin, originsFromPatterns, listLogins, pickPasskey, pair, unpair, isBase64Url, randomName, settingKeys, settingSpecs, securityVariables, SettingsInputError, parseSettingChanges, settingsFromExtension, settingsToExtension, describeSettings, describeChanges, formatSettings };
1667
+ export { terminateChildProcess, SecretCollector, looksLikeTokenSegment, AuthProfileError, read, readOptional, withLock, write, status, run, OriginPatternError, parseOriginPatterns, normalizeOriginPatterns, isPrivateAddress, explicitlyAllowsHost, checkUrl, checkNavigationUrl, readSecret, addSecret, listSecrets, removeSecret, secretText, DeadboltError, readClient, socketPath, connect, parseDeadboltName, originOnSite, pickLogin, originsFromPatterns, listLogins, pickPasskey, pair, unpair, isBase64Url, randomName, settingKeys, settingSpecs, securityVariables, SettingsInputError, parseSettingChanges, settingsFromExtension, settingsToExtension, describeSettings, describeChanges, formatSettings };
@@ -147,7 +147,7 @@ function storeConfig(env = process.env, baked = { id: "mfnicocicmmlkpjnaffgihfjh
147
147
  return id ? { id } : {};
148
148
  }
149
149
  var RELEASE_SERVICE = "https://anoma.ly/release";
150
- function devExtension(baked = { file: "browse-extension-0.0.6-dev.17.zip", sha256: "8bf258faf0bd4ea3e14dc6fa69efc1c553b8490f22bc7883e9016673521169d3", size: 38398 }) {
150
+ function devExtension(baked = { file: "browse-extension-0.0.6-dev.18.zip", sha256: "2f8f69b9022f9835f564f96ccc5fd07c48ad78e95488eeb2a83f253d8fafbb49", size: 38413 }) {
151
151
  return baked && /^[0-9a-f]{64}$/.test(baked.sha256) && /^[\w.-]+\.zip$/.test(baked.file) ? baked : undefined;
152
152
  }
153
153
  var devExtensionUrl = (extension, env = process.env) => `${(env.OPENCODE_BROWSER_RELEASE_SERVICE || RELEASE_SERVICE).replace(/\/+$/, "")}/browse/files/${extension.sha256}/${extension.file}`;
@@ -728,4 +728,4 @@ function spawnRuntimeChild(layout, entry, args, onExit, env = process.env) {
728
728
  }
729
729
  }
730
730
 
731
- export { extensionProtocolVersion, minExtensionProtocolVersion, unpackedExtensionId, unpackedReloadAdvice, checkoutReloadPrefix, extensionReconnectAlarmPeriodMs, extensionProtocolCompatibility, extensionProtocolSkew, extensionProtocolAdvice, makePageStatus, parseJsonObject, isCdpRequest, isExtensionResponse, isExtensionEvent, isJsonObject, dataRoot, oldStoreMarker, fromCheckout, checkoutRoot, cliCommand, storeConfig, devExtension, devExtensionUrl, devExtensionFolder, storeUrl, installCommand, autoUpdateModes, runtimeLayout, versionEntry, channelOf, UPDATE_VERSION, compareVersions, readCurrent, writeCurrent, readState, updateState, npmRuntime, autoUpdateOverride, storedMode, setStoredMode, autoUpdateStatus, describeAutoUpdate, registryUrl, fetchPublished, installVersion, pruneVersions, switchVersion, createAutoUpdater };
731
+ export { extensionProtocolVersion, minExtensionProtocolVersion, unpackedExtensionId, unpackedReloadAdvice, checkoutReloadPrefix, extensionReconnectAlarmPeriodMs, extensionProtocolCompatibility, extensionProtocolSkew, extensionProtocolAdvice, makePageStatus, parseJsonObject, isCdpRequest, isExtensionResponse, isExtensionEvent, isJsonObject, dataRoot, oldStoreMarker, fromCheckout, checkoutRoot, cliCommand, storeConfig, devExtension, devExtensionUrl, devExtensionFolder, storeUrl, installCommand, autoUpdateModes, runtimeLayout, versionEntry, channelOf, UPDATE_VERSION, compareVersions, readCurrent, writeCurrent, updateState, npmRuntime, autoUpdateOverride, storedMode, effectiveMode, setStoredMode, autoUpdateStatus, describeAutoUpdate, registryUrl, fetchPublished, installVersion, pruneVersions, switchVersion, createAutoUpdater };
@@ -6,13 +6,13 @@ import {
6
6
  cliCommand,
7
7
  installCommand,
8
8
  npmRuntime
9
- } from "./main-g5mke6rn.mjs";
10
- import {
11
- opencodeBrowserBuildId2
12
- } from "./main-y7c1atbf.mjs";
9
+ } from "./main-ha5bnd77.mjs";
13
10
  import {
14
11
  relayAuthorization
15
- } from "./main-4bht27ry.mjs";
12
+ } from "./main-9y22cffn.mjs";
13
+ import {
14
+ opencodeBrowserBuildId2
15
+ } from "./main-ppz7sv9s.mjs";
16
16
 
17
17
  // src/relay-helpers.ts
18
18
  import crypto from "node:crypto";
@@ -1408,7 +1408,7 @@ function managedRelayLaunch(entrypoint = loadedCliEntrypoint, executable = proce
1408
1408
  }
1409
1409
  function managedRelayEntrypoint(entrypoint) {
1410
1410
  const name = path.basename(entrypoint);
1411
- if (name === "mcp-main.ts" || name === "index.ts" || name === "opencode-browser-client.ts" || name === "cli.ts")
1411
+ if (name === "index.ts" || name === "opencode-browser-client.ts" || name === "cli.ts")
1412
1412
  return path.join(path.dirname(entrypoint), "main.ts");
1413
1413
  return entrypoint;
1414
1414
  }
@@ -0,0 +1,4 @@
1
+ // src/version.ts
2
+ var opencodeBrowserVersion2 = "0.0.6-dev.18";
3
+ var opencodeBrowserBuildId2 = "2026-11-04T14:16:07.180Z";
4
+ export { opencodeBrowserVersion2, opencodeBrowserBuildId2 };
@@ -6,7 +6,7 @@ import {
6
6
  compareVersions,
7
7
  npmRuntime,
8
8
  autoUpdateStatus
9
- } from "./main-g5mke6rn.mjs";
9
+ } from "./main-ha5bnd77.mjs";
10
10
 
11
11
  // src/update.ts
12
12
  import { execFile, spawnSync } from "node:child_process";
@@ -312,7 +312,7 @@ function runUpdate(args, deps) {
312
312
  async function runUpdateCommand2(args) {
313
313
  const log = (line) => process.stdout.write(line + `
314
314
  `);
315
- const { runNpmUpdate } = await import("./runtime-update-0mddkfy5.mjs");
315
+ const { runNpmUpdate } = await import("./runtime-update-8wte78jj.mjs");
316
316
  if (await runNpmUpdate(args))
317
317
  return;
318
318
  if (args.includes("--check")) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  autoUpdateStatus
3
- } from "./main-g5mke6rn.mjs";
3
+ } from "./main-ha5bnd77.mjs";
4
4
  import {
5
5
  parseTargetSelection2,
6
6
  getObject2,
@@ -10,22 +10,22 @@ import {
10
10
  relayBuildProblem,
11
11
  ensureRelay,
12
12
  ensureExtensionConnected
13
- } from "./main-3qpkwaa7.mjs";
13
+ } from "./main-jjny7bmm.mjs";
14
+ import"./main-9y22cffn.mjs";
14
15
  import {
15
16
  opencodeBrowserVersion2
16
- } from "./main-y7c1atbf.mjs";
17
+ } from "./main-ppz7sv9s.mjs";
17
18
  import {
18
19
  listSecrets,
19
20
  readClient,
20
21
  settingKeys,
21
22
  settingSpecs,
22
23
  securityVariables
23
- } from "./main-e4stqtf2.mjs";
24
+ } from "./main-fkhwazsm.mjs";
24
25
  import {
25
26
  updateJson2,
26
27
  createUpdateWatcher2
27
- } from "./main-4p2p9eey.mjs";
28
- import"./main-4bht27ry.mjs";
28
+ } from "./main-w5sta7hq.mjs";
29
29
 
30
30
  // src/mcp.ts
31
31
  import { NodeStdio } from "@effect/platform-node";
@@ -31,7 +31,7 @@ import {
31
31
  isRestrictedTarget2,
32
32
  isRestrictedUrl2,
33
33
  dataUrlDocument2
34
- } from "./main-3qpkwaa7.mjs";
34
+ } from "./main-jjny7bmm.mjs";
35
35
  export {
36
36
  HttpRouteError2 as HttpRouteError,
37
37
  chromeExtensionOriginForPath2 as chromeExtensionOriginForPath,
@@ -25,7 +25,7 @@ import {
25
25
  setStoredMode,
26
26
  autoUpdateStatus,
27
27
  createAutoUpdater
28
- } from "./main-g5mke6rn.mjs";
28
+ } from "./main-ha5bnd77.mjs";
29
29
  import {
30
30
  ExecuteRequest,
31
31
  SessionAdoptRequest,
@@ -75,7 +75,18 @@ import {
75
75
  isRestrictedTarget2,
76
76
  isRestrictedUrl2,
77
77
  dataUrlDocument2
78
- } from "./main-3qpkwaa7.mjs";
78
+ } from "./main-jjny7bmm.mjs";
79
+ import {
80
+ isNodeError,
81
+ isUnsupportedDirectorySyncError,
82
+ writeJsonFileAtomically,
83
+ ensurePrivateDirectorySync,
84
+ writePrivateJsonFileSync,
85
+ relayTokenQueryParam,
86
+ relayToken,
87
+ secretsEqual,
88
+ ensurePrivateDirectory
89
+ } from "./main-9y22cffn.mjs";
79
90
  import {
80
91
  context,
81
92
  pendingPairingCodeKeys,
@@ -97,12 +108,9 @@ import {
97
108
  syncDevExtension,
98
109
  relayHostname,
99
110
  isLocalPeer
100
- } from "./main-zwe0c783.mjs";
111
+ } from "./main-0egy8naa.mjs";
101
112
  import {
102
113
  terminateChildProcess,
103
- isNodeError,
104
- isUnsupportedDirectorySyncError,
105
- writeJsonFileAtomically,
106
114
  SecretCollector,
107
115
  looksLikeTokenSegment,
108
116
  AuthProfileError,
@@ -138,26 +146,20 @@ import {
138
146
  settingsToExtension,
139
147
  describeSettings,
140
148
  describeChanges
141
- } from "./main-e4stqtf2.mjs";
149
+ } from "./main-fkhwazsm.mjs";
142
150
  import {
143
151
  opencodeBrowserVersion2,
144
152
  opencodeBrowserBuildId2
145
- } from "./main-y7c1atbf.mjs";
153
+ } from "./main-ppz7sv9s.mjs";
146
154
  import {
147
155
  defaultJournalBaseDir,
148
156
  makeJournalEntry,
149
157
  appendJournalEntry,
150
158
  startJournalRetention
151
- } from "./main-kvmxefp1.mjs";
159
+ } from "./main-d7rbre73.mjs";
152
160
  import {
153
161
  createUpdateWatcher2
154
- } from "./main-4p2p9eey.mjs";
155
- import {
156
- relayTokenQueryParam,
157
- relayToken,
158
- secretsEqual,
159
- ensurePrivateDirectory
160
- } from "./main-4bht27ry.mjs";
162
+ } from "./main-w5sta7hq.mjs";
161
163
 
162
164
  // src/relay.ts
163
165
  import http4 from "node:http";
@@ -858,9 +860,7 @@ function managedRelayLogPath(home = os.homedir()) {
858
860
  function appendManagedRelayProcessLog(message, home = os.homedir()) {
859
861
  try {
860
862
  const logPath = managedRelayLogPath(home);
861
- const directory = path.dirname(logPath);
862
- fs.mkdirSync(directory, { recursive: true, mode: 448 });
863
- fs.chmodSync(directory, 448);
863
+ ensurePrivateDirectorySync(path.dirname(logPath));
864
864
  const entry = `${new Date().toISOString()} ${message.slice(0, maxEntryCharacters)}
865
865
  `;
866
866
  const stat = fs.statSync(logPath, { throwIfNoEntry: false });
@@ -1341,23 +1341,19 @@ class BrowserLinks {
1341
1341
  id = `${base}-${n}`;
1342
1342
  known[key] = { id, name };
1343
1343
  try {
1344
- fs2.mkdirSync(path2.dirname(this.file), { recursive: true, mode: 448 });
1345
- fs2.writeFileSync(this.file, `${JSON.stringify(known, null, 2)}
1346
- `, { mode: 384 });
1344
+ writePrivateJsonFileSync(this.file, known, { ensureParent: true });
1347
1345
  } catch {}
1348
1346
  return id;
1349
1347
  }
1350
1348
  connect(options) {
1351
1349
  const replaced = this.links.get(options.key);
1352
- if (replaced) {
1350
+ if (replaced)
1353
1351
  this.disconnect(replaced.socket);
1354
- replaced.rpc.rejectPending(new Error("Extension replaced"));
1355
- }
1356
1352
  const link = {
1357
1353
  key: options.key,
1358
1354
  id: this.identify(options.key, options.name),
1359
1355
  name: options.name,
1360
- rpc: this.options.rpc?.() ?? new ExtensionRpc,
1356
+ rpc: new ExtensionRpc,
1361
1357
  socket: options.socket,
1362
1358
  generation: ++this.generation,
1363
1359
  connectedAt: Date.now(),
@@ -1538,7 +1534,7 @@ class CdpRouter {
1538
1534
  clientSessionId,
1539
1535
  targetOwnerSessionId: target.opencodeBrowserSessionId,
1540
1536
  targetOwner: target.owner,
1541
- clientHasOwnedTarget: clientSessionId !== undefined && this.registry.listRootTargets().some((candidate) => candidate.opencodeBrowserSessionId === clientSessionId)
1537
+ clientHasOwnedTarget: clientSessionId !== undefined && target.opencodeBrowserSessionId === undefined && target.owner !== "user" && this.registry.listRootTargets().some((candidate) => candidate.opencodeBrowserSessionId === clientSessionId)
1542
1538
  });
1543
1539
  }
1544
1540
  canSeeTab(client, tabId) {
@@ -7141,7 +7137,7 @@ async function waitForProgress(page, field, timeoutMs) {
7141
7137
  return false;
7142
7138
  }
7143
7139
  async function clearSecretInputs(frames, fields = []) {
7144
- const clearScript = (nodes) => {
7140
+ const clearScript = () => {
7145
7141
  const own = (element) => {
7146
7142
  const input = element;
7147
7143
  if (!(input instanceof HTMLInputElement) || !input.value)
@@ -7154,7 +7150,7 @@ async function clearSecretInputs(frames, fields = []) {
7154
7150
  input.dispatchEvent(new Event("input", { bubbles: true }));
7155
7151
  input.dispatchEvent(new Event("change", { bubbles: true }));
7156
7152
  };
7157
- const all = [...nodes];
7153
+ const all = [];
7158
7154
  const walk = (root) => {
7159
7155
  for (const element of Array.from(root.querySelectorAll("input"))) {
7160
7156
  const input = element;
@@ -7182,7 +7178,7 @@ async function clearSecretInputs(frames, fields = []) {
7182
7178
  for (const frame of new Set(frames)) {
7183
7179
  if (frame.isDetached())
7184
7180
  continue;
7185
- await frame.evaluate(clearScript, []).catch(() => {});
7181
+ await frame.evaluate(clearScript).catch(() => {});
7186
7182
  }
7187
7183
  }
7188
7184
  async function submit(read, field) {
@@ -7470,10 +7466,8 @@ var probeSelectors = [
7470
7466
  "#challenge-running",
7471
7467
  "#challenge-stage",
7472
7468
  "#cf-challenge-running",
7473
- "#cf-please-wait",
7474
7469
  ".cf-turnstile",
7475
7470
  "#cf-error-details",
7476
- "#cf-wrapper .cf-error-type",
7477
7471
  "#sec-if-cpt-container",
7478
7472
  "#sec-cpt-if",
7479
7473
  "#sec-text-if",
@@ -13416,8 +13410,7 @@ var RelayLifecycleEvent = Schema8.TaggedUnion({
13416
13410
  });
13417
13411
  function appendRelayLifecycleEvent(filePath, event) {
13418
13412
  const directory = path9.dirname(filePath);
13419
- fs8.mkdirSync(directory, { recursive: true, mode: 448 });
13420
- fs8.chmodSync(directory, 448);
13413
+ ensurePrivateDirectorySync(directory);
13421
13414
  const entry = `${JSON.stringify({ ...Schema8.encodeSync(RelayLifecycleEvent)(event), timestamp: new Date().toISOString() })}
13422
13415
  `;
13423
13416
  const file = fs8.openSync(filePath, "a+", 384);
@@ -13466,15 +13459,21 @@ class RelayShutdown {
13466
13459
  get stopping() {
13467
13460
  return State.$is("Stopping")(this.state) || State.$is("Closing")(this.state);
13468
13461
  }
13469
- close() {
13462
+ drainAndSettle() {
13470
13463
  const control = this;
13471
13464
  return Effect9.gen(function* () {
13472
- control.state = State.Closing();
13473
13465
  yield* Effect9.all([control.options.drain, control.idle.await], { concurrency: "unbounded" });
13474
13466
  yield* control.idle.await;
13475
13467
  yield* control.options.settle;
13476
13468
  });
13477
13469
  }
13470
+ close() {
13471
+ const control = this;
13472
+ return Effect9.gen(function* () {
13473
+ control.state = State.Closing();
13474
+ yield* control.drainAndSettle();
13475
+ });
13476
+ }
13478
13477
  track(effect) {
13479
13478
  const control = this;
13480
13479
  return Effect9.acquireUseRelease(Effect9.suspend(() => {
@@ -13516,9 +13515,7 @@ class RelayShutdown {
13516
13515
  const busy = control.options.busy();
13517
13516
  if (busy)
13518
13517
  return yield* control.busyError(busy);
13519
- yield* Effect9.all([control.options.drain, control.idle.await], { concurrency: "unbounded" });
13520
- yield* control.idle.await;
13521
- yield* control.options.settle;
13518
+ yield* control.drainAndSettle();
13522
13519
  const remaining = control.options.busy();
13523
13520
  if (remaining)
13524
13521
  return yield* control.busyError(remaining);
@@ -14295,7 +14292,7 @@ function guardStorageAccess(context) {
14295
14292
  });
14296
14293
  if (outside === undefined)
14297
14294
  return null;
14298
- return `Browse blocked ${context.method}: site storage can only be used for the hosts of this session's attached pages (${hosts.length > 0 ? hosts.join(", ") : "none"}), not ${outside}. Set ${allowAllStorageEnvironmentVariable}=1 on the relay to allow it.`;
14295
+ return `Browse blocked ${context.method}: site storage can only be used for the hosts of this session's attached pages (${formatAllowedHosts(hosts)}), not ${outside}. Set ${allowAllStorageEnvironmentVariable}=1 on the relay to allow it.`;
14299
14296
  }
14300
14297
  var restrictedNavigationSchemes = new Set([
14301
14298
  "file:",
@@ -14358,13 +14355,16 @@ function cookieDomainOf(cookie) {
14358
14355
  }
14359
14356
  return typeof domain === "string" ? domain : undefined;
14360
14357
  }
14358
+ function formatAllowedHosts(hosts) {
14359
+ return hosts.length > 0 ? hosts.join(", ") : "none";
14360
+ }
14361
14361
  function guardCookieWrite(context) {
14362
14362
  const cookies = context.method === "Network.setCookie" ? [context.params] : Array.isArray(context.params?.cookies) ? context.params.cookies : [];
14363
14363
  const hosts = pageHosts(context.pageUrls?.() ?? []);
14364
14364
  for (const cookie of cookies) {
14365
14365
  const domain = cookieDomainOf(cookie);
14366
14366
  if (!domain || !hosts.some((host) => cookieAppliesToHost(domain, host))) {
14367
- return `Browse blocked ${context.method}: cookies can only be set for the hosts of this session's attached pages (${hosts.length > 0 ? hosts.join(", ") : "none"}), not ${domain ?? "a cookie without a domain or url"}. Set ${allowAllCookiesEnvironmentVariable}=1 on the relay to allow it.`;
14367
+ return `Browse blocked ${context.method}: cookies can only be set for the hosts of this session's attached pages (${formatAllowedHosts(hosts)}), not ${domain ?? "a cookie without a domain or url"}. Set ${allowAllCookiesEnvironmentVariable}=1 on the relay to allow it.`;
14368
14368
  }
14369
14369
  }
14370
14370
  return null;
@@ -14398,7 +14398,7 @@ function guardCdpMethod(context) {
14398
14398
  const hosts = pageHosts(context.pageUrls?.() ?? []);
14399
14399
  const host = typeof url === "string" ? pageHosts([url])[0] : undefined;
14400
14400
  if (host === undefined || !hosts.includes(host)) {
14401
- return `Browse blocked Network.loadNetworkResource: it loads URLs with the user's credentials outside the page's same-origin policy, so only the hosts of this session's attached pages (${hosts.length > 0 ? hosts.join(", ") : "none"}) are allowed. Set ${allowAllStorageEnvironmentVariable}=1 on the relay to allow it.`;
14401
+ return `Browse blocked Network.loadNetworkResource: it loads URLs with the user's credentials outside the page's same-origin policy, so only the hosts of this session's attached pages (${formatAllowedHosts(hosts)}) are allowed. Set ${allowAllStorageEnvironmentVariable}=1 on the relay to allow it.`;
14402
14402
  }
14403
14403
  }
14404
14404
  if (context.readOnly && readOnlyBlockedPrefixes.some((prefix) => context.method.startsWith(prefix))) {
@@ -8,24 +8,23 @@ import {
8
8
  compareVersions,
9
9
  readCurrent,
10
10
  writeCurrent,
11
- readState,
12
11
  updateState,
13
12
  npmRuntime,
14
- autoUpdateOverride,
13
+ effectiveMode,
15
14
  registryUrl,
16
15
  fetchPublished,
17
16
  installVersion,
18
17
  pruneVersions,
19
18
  switchVersion
20
- } from "./main-g5mke6rn.mjs";
19
+ } from "./main-ha5bnd77.mjs";
21
20
  import {
22
21
  Service,
23
22
  layerFetch,
24
23
  restartRelay,
25
24
  startManagedRelay
26
- } from "./main-3qpkwaa7.mjs";
27
- import"./main-y7c1atbf.mjs";
28
- import"./main-4bht27ry.mjs";
25
+ } from "./main-jjny7bmm.mjs";
26
+ import"./main-9y22cffn.mjs";
27
+ import"./main-ppz7sv9s.mjs";
29
28
 
30
29
  // src/runtime-update.ts
31
30
  import { Effect } from "effect";
@@ -129,7 +128,7 @@ async function runNpmUpdate(args, layout) {
129
128
  const current = readCurrent(lay);
130
129
  const refused = await switchTo(lay, published.version, { previous: current.version, force: args.includes("--force") });
131
130
  if (refused) {
132
- const automatic = (autoUpdateOverride() ?? readState(lay).mode ?? "on") === "on";
131
+ const automatic = effectiveMode(lay) === "on";
133
132
  log(`! Installed ${published.version}, but the relay didn't restart (${refused}).`);
134
133
  log(automatic ? " It switches to the new version by itself once no agent is using the browser." : ` When no agent is using the browser, run \`${cliCommand("update")}\` again.`);
135
134
  return true;
@@ -21,7 +21,10 @@ import {
21
21
  installVersion,
22
22
  pruneVersions,
23
23
  switchVersion
24
- } from "./main-g5mke6rn.mjs";
24
+ } from "./main-ha5bnd77.mjs";
25
+ import {
26
+ relayAuthorization
27
+ } from "./main-9y22cffn.mjs";
25
28
  import {
26
29
  pairingCodeTtlMs,
27
30
  bundledPairingCodeTtlMs,
@@ -38,13 +41,10 @@ import {
38
41
  parseHostname,
39
42
  readRelayConfig,
40
43
  writeRelayConfig
41
- } from "./main-zwe0c783.mjs";
44
+ } from "./main-0egy8naa.mjs";
42
45
  import {
43
46
  opencodeBrowserVersion2
44
- } from "./main-y7c1atbf.mjs";
45
- import {
46
- relayAuthorization
47
- } from "./main-4bht27ry.mjs";
47
+ } from "./main-ppz7sv9s.mjs";
48
48
  import { createRequire } from "node:module";
49
49
  var __create = Object.create;
50
50
  var __getProtoOf = Object.getPrototypeOf;
@@ -11310,7 +11310,7 @@ async function runSetup(command, args) {
11310
11310
  if (command === "set")
11311
11311
  return set(args);
11312
11312
  if (command === "rollback") {
11313
- const { runRollback } = await import("./runtime-update-0mddkfy5.mjs");
11313
+ const { runRollback } = await import("./runtime-update-8wte78jj.mjs");
11314
11314
  return runRollback(args);
11315
11315
  }
11316
11316
  }
@@ -4,8 +4,8 @@ import {
4
4
  updateNotice2,
5
5
  createUpdateWatcher2,
6
6
  runUpdateCommand2
7
- } from "./main-4p2p9eey.mjs";
8
- import"./main-g5mke6rn.mjs";
7
+ } from "./main-w5sta7hq.mjs";
8
+ import"./main-ha5bnd77.mjs";
9
9
  export {
10
10
  createUpdateWatcher2 as createUpdateWatcher,
11
11
  formatUpdateNotice2 as formatUpdateNotice,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  opencodeBrowserVersion2,
3
3
  opencodeBrowserBuildId2
4
- } from "./main-y7c1atbf.mjs";
4
+ } from "./main-ppz7sv9s.mjs";
5
5
  export {
6
6
  opencodeBrowserBuildId2 as opencodeBrowserBuildId,
7
7
  opencodeBrowserVersion2 as opencodeBrowserVersion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencode/browse",
3
- "version": "0.0.6-dev.17",
3
+ "version": "0.0.6-dev.18",
4
4
  "description": "Browse: connect the extension to opencode, and drive your browser from any agent (CLI, MCP, Playwright).",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,72 +0,0 @@
1
- import {
2
- dataRoot
3
- } from "./main-g5mke6rn.mjs";
4
-
5
- // src/relay-secrets.ts
6
- import crypto from "node:crypto";
7
- import fs from "node:fs";
8
- import path from "node:path";
9
- var relayTokenQueryParam = "opencodeBrowserToken";
10
- var tokenPattern = /^[A-Za-z0-9_-]{43}$/;
11
- function relayTokenPath(root = dataRoot()) {
12
- return path.join(root, "relay-token");
13
- }
14
- function relayToken(root = dataRoot()) {
15
- return readOrCreateSecret(relayTokenPath(root), () => crypto.randomBytes(32).toString("base64url"), (value) => tokenPattern.test(value));
16
- }
17
- function relayAuthorization(root = dataRoot()) {
18
- return `Bearer ${relayToken(root)}`;
19
- }
20
- function secretsEqual(expected, actual) {
21
- if (actual === undefined)
22
- return false;
23
- const a = crypto.createHash("sha256").update(expected).digest();
24
- const b = crypto.createHash("sha256").update(actual).digest();
25
- return crypto.timingSafeEqual(a, b) && expected.length === actual.length;
26
- }
27
- function readOrCreateSecret(file, generate, valid) {
28
- const existing = readSecret(file);
29
- if (existing !== undefined && valid(existing))
30
- return existing;
31
- ensurePrivateDirectory(path.dirname(file));
32
- const temporary = `${file}.${process.pid}.${crypto.randomUUID()}.tmp`;
33
- fs.writeFileSync(temporary, `${generate()}
34
- `, { mode: 384 });
35
- try {
36
- if (existing === undefined) {
37
- try {
38
- fs.linkSync(temporary, file);
39
- } catch (error) {
40
- if (error.code !== "EEXIST")
41
- throw error;
42
- }
43
- } else {
44
- fs.renameSync(temporary, file);
45
- }
46
- } finally {
47
- fs.rmSync(temporary, { force: true });
48
- }
49
- const created = readSecret(file);
50
- if (created === undefined || !valid(created))
51
- throw new Error(`Could not create ${file}`);
52
- return created;
53
- }
54
- function readSecret(file) {
55
- try {
56
- const stat = fs.statSync(file);
57
- if (process.platform !== "win32" && (stat.mode & 63) !== 0)
58
- fs.chmodSync(file, 384);
59
- return fs.readFileSync(file, "utf8").trim();
60
- } catch (error) {
61
- if (error.code === "ENOENT")
62
- return;
63
- throw error;
64
- }
65
- }
66
- function ensurePrivateDirectory(directory = dataRoot()) {
67
- fs.mkdirSync(directory, { recursive: true, mode: 448 });
68
- if (process.platform !== "win32")
69
- fs.chmodSync(directory, 448);
70
- }
71
-
72
- export { relayTokenQueryParam, relayToken, relayAuthorization, secretsEqual, ensurePrivateDirectory };
@@ -1,4 +0,0 @@
1
- // src/version.ts
2
- var opencodeBrowserVersion2 = "0.0.6-dev.17";
3
- var opencodeBrowserBuildId2 = "2026-11-03T15:29:35.727Z";
4
- export { opencodeBrowserVersion2, opencodeBrowserBuildId2 };