@opencode/browse 0.0.6-dev.20 → 0.0.6-dev.21

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.
@@ -1,3 +1,7 @@
1
+ import {
2
+ opencodeBrowserVersion2,
3
+ opencodeBrowserBuildId2
4
+ } from "./main-ek76h9k1.mjs";
1
5
  import {
2
6
  dataRoot,
3
7
  oldStoreMarker,
@@ -13,7 +17,9 @@ import {
13
17
  storedMode,
14
18
  setStoredMode,
15
19
  autoUpdateStatus,
16
- createAutoUpdater,
20
+ createAutoUpdater
21
+ } from "./main-0m569gdn.mjs";
22
+ import {
17
23
  extensionProtocolVersion,
18
24
  minExtensionProtocolVersion,
19
25
  checkoutReloadPrefix,
@@ -25,7 +31,7 @@ import {
25
31
  isExtensionResponse,
26
32
  isExtensionEvent,
27
33
  isJsonObject
28
- } from "./main-ma25hhqh.mjs";
34
+ } from "./main-3gthmkzw.mjs";
29
35
  import {
30
36
  isNodeError,
31
37
  isUnsupportedDirectorySyncError,
@@ -36,7 +42,7 @@ import {
36
42
  relayToken,
37
43
  secretsEqual,
38
44
  ensurePrivateDirectory
39
- } from "./main-20ahaz2q.mjs";
45
+ } from "./main-7qs0mwvc.mjs";
40
46
  import {
41
47
  ExecuteRequest,
42
48
  SessionAdoptRequest,
@@ -86,8 +92,10 @@ import {
86
92
  isRestrictedTarget2,
87
93
  isRestrictedUrl2,
88
94
  dataUrlDocument2
89
- } from "./main-0nta0a2z.mjs";
95
+ } from "./main-qm2keaeb.mjs";
90
96
  import {
97
+ relayHostname,
98
+ isLocalPeer,
91
99
  context,
92
100
  pendingPairingCodeKeys,
93
101
  consumePairingCode,
@@ -105,10 +113,8 @@ import {
105
113
  sessionProof,
106
114
  wrapToken,
107
115
  installedDevExtension,
108
- syncDevExtension,
109
- relayHostname,
110
- isLocalPeer
111
- } from "./main-hywb9qbv.mjs";
116
+ syncDevExtension
117
+ } from "./main-6bjnpchg.mjs";
112
118
  import {
113
119
  SettingsInputError,
114
120
  parseSettingChanges,
@@ -146,20 +152,16 @@ import {
146
152
  checkNavigationUrl,
147
153
  readSecret,
148
154
  secretText
149
- } from "./main-yd1d7qr1.mjs";
150
- import {
151
- opencodeBrowserVersion2,
152
- opencodeBrowserBuildId2
153
- } from "./main-arx3pfyn.mjs";
155
+ } from "./main-yq58hnwq.mjs";
154
156
  import {
155
157
  defaultJournalBaseDir,
156
158
  makeJournalEntry,
157
159
  appendJournalEntry,
158
160
  startJournalRetention
159
- } from "./main-42qfr69q.mjs";
161
+ } from "./main-ybvatjk0.mjs";
160
162
  import {
161
163
  createUpdateWatcher2
162
- } from "./main-3rsfghef.mjs";
164
+ } from "./main-33kf3cfr.mjs";
163
165
 
164
166
  // src/relay.ts
165
167
  import crypto10 from "node:crypto";
@@ -270,7 +272,7 @@ class ExtensionRpc {
270
272
  return Effect.void;
271
273
  }
272
274
  if (!socket || socket.readyState !== WebSocket.OPEN || !this.acceptsEvents) {
273
- resume(Effect.fail(new Error("Browse extension is not connected")));
275
+ resume(Effect.fail(new Error("browse extension is not connected")));
274
276
  return Effect.void;
275
277
  }
276
278
  const id = this.nextRequestId++;
@@ -1604,7 +1606,7 @@ import { chromium, errors } from "patchright-core";
1604
1606
 
1605
1607
  // src/snapshot/aria-snapshot.ts
1606
1608
  import { selectors } from "patchright-core";
1607
- var redactionCleanupErrorMessage = "Browse could not confirm ARIA snapshot value-redaction cleanup";
1609
+ var redactionCleanupErrorMessage = "browse could not confirm ARIA snapshot value-redaction cleanup";
1608
1610
  var redactionSelectorSource = `({
1609
1611
  query(root, body) {
1610
1612
  const separator = body.indexOf("_")
@@ -2307,7 +2309,7 @@ function assertExecuteFilePath(target, operation) {
2307
2309
  const resolved = realTarget(target);
2308
2310
  const data = realTarget(dataRoot());
2309
2311
  if (isInside(resolved, data)) {
2310
- throw new ExecuteFileAccessError(`${operation}: ${target} is inside Browse's data directory, which execute code cannot access`);
2312
+ throw new ExecuteFileAccessError(`${operation}: ${target} is inside browse's data directory, which execute code cannot access`);
2311
2313
  }
2312
2314
  if (!roots.some((root) => isInside(resolved, root))) {
2313
2315
  throw new ExecuteFileAccessError(`${operation}: ${target} is outside the execute file roots ${describeRoots()}. Set ${allowNodeEnvironmentVariable}=1 for unrestricted file access.`);
@@ -2690,7 +2692,15 @@ var stopPromiseHook;
2690
2692
  function trackPromisesOf(realm) {
2691
2693
  const previous = activeRealm;
2692
2694
  activeRealm = realm;
2693
- if (!stopPromiseHook && !process.versions.bun) {
2695
+ if (process.versions.bun) {
2696
+ const entered = { realm, at: Date.now() };
2697
+ lastRealm = entered;
2698
+ return () => {
2699
+ activeRealm = previous;
2700
+ entered.at = Date.now();
2701
+ };
2702
+ }
2703
+ if (!stopPromiseHook) {
2694
2704
  stopPromiseHook = v8.promiseHooks.createHook({ init(promise) {
2695
2705
  if (activeRealm)
2696
2706
  promiseRealms.set(promise, activeRealm);
@@ -2704,8 +2714,23 @@ function trackPromisesOf(realm) {
2704
2714
  }
2705
2715
  };
2706
2716
  }
2717
+ var realmsByPromisePrototype = new WeakMap;
2718
+ var lastRealm;
2719
+ var lastRealmWindowMs = 1000;
2720
+ function registerRealmPromisePrototype(prototype, realm) {
2721
+ if (process.versions.bun)
2722
+ realmsByPromisePrototype.set(prototype, realm);
2723
+ }
2724
+ function bunRejectionRealm(promise) {
2725
+ const byPrototype = realmsByPromisePrototype.get(Object.getPrototypeOf(promise));
2726
+ if (byPrototype)
2727
+ return byPrototype;
2728
+ if (!lastRealm || lastRealm.realm.isStopped)
2729
+ return;
2730
+ return activeRealm === lastRealm.realm || Date.now() - lastRealm.at <= lastRealmWindowMs ? lastRealm.realm : undefined;
2731
+ }
2707
2732
  function handleExecuteRealmRejection(promise) {
2708
- const realm = promiseRealms.get(promise);
2733
+ const realm = promiseRealms.get(promise) ?? (process.versions.bun ? bunRejectionRealm(promise) : undefined);
2709
2734
  if (!realm)
2710
2735
  return false;
2711
2736
  realm.dispose(new Error("Unhandled execute rejection; JavaScript state will reset before the next execute"));
@@ -2864,6 +2889,7 @@ class ExecuteRealm {
2864
2889
  this.sandboxFunctionPrototype = sandboxIntrinsics.Function.prototype;
2865
2890
  this.sandboxArrayPrototype = sandboxIntrinsics.Array.prototype;
2866
2891
  this.SandboxPromise = sandboxIntrinsics.Promise;
2892
+ registerRealmPromisePrototype(this.SandboxPromise.prototype, this);
2867
2893
  this.SandboxError = sandboxIntrinsics.Error;
2868
2894
  this.sandboxAwait = new vm3.Script("(async (value, resolve, reject) => { try { resolve(await value) } catch (error) { reject(error) } })").runInContext(this.context);
2869
2895
  this.state = Object.create(this.sandboxObjectPrototype);
@@ -3752,7 +3778,7 @@ function selectTarget({
3752
3778
  if (matches.length === 0) {
3753
3779
  throw new TargetSelectionError({
3754
3780
  reason: "not-found",
3755
- message: `No existing attached page URL includes ${selection.urlIncludes}. Target selectors do not navigate or open pages: use page.goto() in the session page, or attach the intended user tab with the Browse toolbar first.`
3781
+ message: `No existing attached page URL includes ${selection.urlIncludes}. Target selectors do not navigate or open pages: use page.goto() in the session page, or attach the intended user tab with the browse toolbar first.`
3756
3782
  });
3757
3783
  }
3758
3784
  if (matches.length > 1) {
@@ -3780,7 +3806,7 @@ function selectTarget({
3780
3806
  if (targets.length === 0) {
3781
3807
  throw new TargetSelectionError({
3782
3808
  reason: "not-found",
3783
- message: "No attached pages available. Attach the intended user tab with the Browse toolbar first."
3809
+ message: "No attached pages available. Attach the intended user tab with the browse toolbar first."
3784
3810
  });
3785
3811
  }
3786
3812
  if (targets.length > 1) {
@@ -3844,7 +3870,7 @@ var timedOut = Symbol("timed-out");
3844
3870
  var defaultPageClosedWarning = "The session default page was closed; created a new page. References to the old page in state are stale.";
3845
3871
  var defaultPageRecoveredWarning = "The session default page was unresponsive; created a new page. References to the old page in state are stale.";
3846
3872
  var defaultPageCrashedWarning = "The session default page target crashed; checking it before the next execute.";
3847
- var defaultPageRepairedWarning = "The session default page stopped answering automation; Browse reconnected and re-resolved the same tab. References to the old page in state are stale.";
3873
+ var defaultPageRepairedWarning = "The session default page stopped answering automation; browse reconnected and re-resolved the same tab. References to the old page in state are stale.";
3848
3874
  var protectedExtensionUiWarning = "Chromium blocked protected extension UI, possibly a password manager. Ask the user to finish or dismiss it in the browser, then retry.";
3849
3875
  var protectedExtensionUiDiagnostic = "target/cross-extension-page";
3850
3876
  var syntheticInputWarning = "fillInput/fillInputs set the value with synthetic input events (isTrusted: false, no key presses), which pages and bot protection can tell apart from typing. Prefer locator.fill() or locator.pressSequentially().";
@@ -4000,7 +4026,7 @@ async function finishHandoff(options) {
4000
4026
  const kind = runtimeFailureKind(error);
4001
4027
  if (kind !== "context-destroyed" && kind !== "context-missing")
4002
4028
  throw error;
4003
- throw new Error(`Handoff resolved (${options.message}), but the page execution context did not become available within ${contextTimeoutMs}ms: ${error instanceof Error ? error.message : String(error)}. The tab was kept; run a short follow-up execute so Browse can re-check it.`, { cause: error });
4029
+ throw new Error(`Handoff resolved (${options.message}), but the page execution context did not become available within ${contextTimeoutMs}ms: ${error instanceof Error ? error.message : String(error)}. The tab was kept; run a short follow-up execute so browse can re-check it.`, { cause: error });
4004
4030
  }
4005
4031
  }
4006
4032
  function isSessionPageConnected(options) {
@@ -4353,7 +4379,7 @@ ${wrapCode(code)}
4353
4379
  import { Effect as Effect6 } from "effect";
4354
4380
 
4355
4381
  // src/execute/guards.ts
4356
- var downloadCapabilityErrorMessage = "Downloads are unavailable in Browse extension-backed tabs: Chromium blocks Browser.setDownloadBehavior and Page.setDownloadBehavior through chrome.debugger, so Playwright cannot retain an artifact for download.saveAs(). Fetch the response in the page and save the returned bytes with files.write() when the site exposes them.";
4382
+ var downloadCapabilityErrorMessage = "Downloads are unavailable in browse extension-backed tabs: Chromium blocks Browser.setDownloadBehavior and Page.setDownloadBehavior through chrome.debugger, so Playwright cannot retain an artifact for download.saveAs(). Fetch the response in the page and save the returned bytes with files.write() when the site exposes them.";
4357
4383
  var downloadGuardedPages = new WeakSet;
4358
4384
  var downloadGuardedContexts = new WeakSet;
4359
4385
  var viewportZoomGuardedPages = new WeakSet;
@@ -8565,7 +8591,7 @@ function buildSandboxGlobals(deps) {
8565
8591
  const requestHandoff = deps.requestHandoff;
8566
8592
  const handoff = async (message, options) => {
8567
8593
  if (!requestHandoff) {
8568
- throw new Error("handoff is not available in this sandbox; it requires a relay-backed Browse session");
8594
+ throw new Error("handoff is not available in this sandbox; it requires a relay-backed browse session");
8569
8595
  }
8570
8596
  const handoffMessage = message?.trim() || defaultHandoffMessage;
8571
8597
  const timeoutMs = options?.timeoutMs ?? defaultHandoffTimeoutMs;
@@ -9618,7 +9644,7 @@ function finishCapture(active, options, secrets, profileOptions) {
9618
9644
  yield* writeArtifact(options.outputPath, {
9619
9645
  log: {
9620
9646
  version: "1.2",
9621
- creator: { name: "Browse", version: "1" },
9647
+ creator: { name: "browse", version: "1" },
9622
9648
  entries: protectedEntries.map(toHarEntry)
9623
9649
  }
9624
9650
  });
@@ -11386,7 +11412,7 @@ class FlightRecorderRelay {
11386
11412
  }
11387
11413
  async start(options) {
11388
11414
  if (!this.options.isExtensionConnected())
11389
- throw new Error("Browse extension is not connected");
11415
+ throw new Error("browse extension is not connected");
11390
11416
  if (this.isActiveTab(options.tabId))
11391
11417
  throw new Error("Flight recorder already active for this tab");
11392
11418
  if (this.options.isTabRecording?.(options.tabId))
@@ -12134,7 +12160,7 @@ class SessionAdmission {
12134
12160
  }
12135
12161
  assertAdmission() {
12136
12162
  if (this.admission !== "open") {
12137
- throw sessionError("inactive", this.admission === "closed" ? "Browse sessions are closing" : "Browse sessions are draining");
12163
+ throw sessionError("inactive", this.admission === "closed" ? "browse sessions are closing" : "browse sessions are draining");
12138
12164
  }
12139
12165
  }
12140
12166
  assertStableIdentity(id) {
@@ -12213,13 +12239,13 @@ class SessionAdmission {
12213
12239
  }
12214
12240
  });
12215
12241
  this.persistenceTail.catch((error) => {
12216
- console.error("Failed to persist Browse sessions", error);
12242
+ console.error("Failed to persist browse sessions", error);
12217
12243
  });
12218
12244
  }
12219
12245
  flushPersistence() {
12220
12246
  return Effect16.tryPromise({
12221
12247
  try: () => this.persistenceTail,
12222
- catch: (cause) => cause instanceof Error ? cause : new Error("Persist Browse sessions", { cause })
12248
+ catch: (cause) => cause instanceof Error ? cause : new Error("Persist browse sessions", { cause })
12223
12249
  });
12224
12250
  }
12225
12251
  commitPersistence(rollback) {
@@ -13626,7 +13652,7 @@ class RecordingRelay {
13626
13652
  return { success: false, error: "Recording frameRate must be an integer from 1 to 60" };
13627
13653
  }
13628
13654
  if (!this.options.isExtensionConnected()) {
13629
- return { success: false, error: "Browse extension is not connected" };
13655
+ return { success: false, error: "browse extension is not connected" };
13630
13656
  }
13631
13657
  if (this.activeRecordings.has(options.tabId) || this.startingRecordings.has(options.tabId)) {
13632
13658
  return { success: false, error: "Recording already in progress for this tab" };
@@ -13659,7 +13685,7 @@ class RecordingRelay {
13659
13685
  }
13660
13686
  async stopRecording(options) {
13661
13687
  if (!this.options.isExtensionConnected()) {
13662
- return { success: false, error: "Browse extension is not connected" };
13688
+ return { success: false, error: "browse extension is not connected" };
13663
13689
  }
13664
13690
  const recording = this.findRecording(options);
13665
13691
  if (!recording) {
@@ -13777,7 +13803,7 @@ class RecordingRelay {
13777
13803
  if (!this.options.isExtensionConnected()) {
13778
13804
  recording.resolveStop?.({ success: false, error: "Recording was cancelled" });
13779
13805
  await this.cleanupRecording(recording.tabId);
13780
- return { success: false, error: "Browse extension is not connected" };
13806
+ return { success: false, error: "browse extension is not connected" };
13781
13807
  }
13782
13808
  const result = this.options.sendToExtension({ method: "recording.cancel", params: { tabId: recording.tabId } }).then(parseCancelResult, (error) => ({ success: false, error: error instanceof Error ? error.message : String(error) })).then((result) => {
13783
13809
  recording.resolveStop?.({ success: false, error: "Recording was cancelled" });
@@ -14362,7 +14388,7 @@ function handleCliRequest(options) {
14362
14388
  const available = yield* options.sessions.targetsForAdoption(requestedSessionId, allTargets);
14363
14389
  const byTab = request.tabId === undefined ? undefined : allTargets.find((target) => target.tabId === request.tabId);
14364
14390
  if (request.tabId !== undefined && !byTab)
14365
- throw new Error(`Tab ${request.tabId} is not available to agents. Ask the user to click the Browse toolbar button on that tab.`);
14391
+ throw new Error(`Tab ${request.tabId} is not available to agents. Ask the user to click the browse toolbar button on that tab.`);
14366
14392
  if (byTab && !available.includes(byTab))
14367
14393
  return yield* new HttpRouteError2({ status: 400, code: "invalid-request", message: `Tab ${byTab.tabId} belongs to another browser. Start a new session for that browser.` });
14368
14394
  const candidates = byTab ? [byTab] : request.targetSelection ? available : (() => {
@@ -14432,7 +14458,7 @@ function createHttpRequestHandler(options) {
14432
14458
  const requestUrl = new URL(request.url ?? "/", `http://${formatHostForUrl2(options.host)}:${options.port}`);
14433
14459
  const pathname = requestUrl.pathname.replace(/\/$/, "") || "/";
14434
14460
  if (pathname !== "/" && pathname !== "/version" && !hasRelayToken(request, options.authToken)) {
14435
- sendJson2(response, { error: "Missing or invalid Browse relay token", code: "unauthorized" }, 401);
14461
+ sendJson2(response, { error: "Missing or invalid browse relay token", code: "unauthorized" }, 401);
14436
14462
  return;
14437
14463
  }
14438
14464
  const observational = request.method === "GET" || pathname === "/network/status" || pathname === "/auth/status";
@@ -15216,7 +15242,7 @@ function guardStorageAccess(context) {
15216
15242
  return null;
15217
15243
  const everyOrigin = storageMethodsForAllOrigins.get(context.method);
15218
15244
  if (everyOrigin) {
15219
- return `Browse blocked ${context.method}: ${everyOrigin}. Set ${allowAllStorageEnvironmentVariable}=1 on the relay to allow it.`;
15245
+ return `browse blocked ${context.method}: ${everyOrigin}. Set ${allowAllStorageEnvironmentVariable}=1 on the relay to allow it.`;
15220
15246
  }
15221
15247
  if (storageMethodsWithoutOrigin.has(context.method))
15222
15248
  return null;
@@ -15228,7 +15254,7 @@ function guardStorageAccess(context) {
15228
15254
  });
15229
15255
  if (outside === undefined)
15230
15256
  return null;
15231
- 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.`;
15257
+ 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.`;
15232
15258
  }
15233
15259
  var restrictedNavigationSchemes = new Set([
15234
15260
  "file:",
@@ -15261,7 +15287,7 @@ function guardNavigation(context) {
15261
15287
  if (scheme === "file:" && allowsFileUrls())
15262
15288
  return null;
15263
15289
  const hint = scheme === "file:" ? ` Set ${allowFileUrlsEnvironmentVariable}=1 on the relay to allow file: URLs.` : "";
15264
- return `Browse blocked ${context.method} to a ${scheme} URL: agents can't open browser-internal pages, other extensions, DevTools or local files.${hint}`;
15290
+ return `browse blocked ${context.method} to a ${scheme} URL: agents can't open browser-internal pages, other extensions, DevTools or local files.${hint}`;
15265
15291
  }
15266
15292
  function pageHosts(urls) {
15267
15293
  const hosts = [];
@@ -15300,7 +15326,7 @@ function guardCookieWrite(context) {
15300
15326
  for (const cookie of cookies) {
15301
15327
  const domain = cookieDomainOf(cookie);
15302
15328
  if (!domain || !hosts.some((host) => cookieAppliesToHost(domain, host))) {
15303
- 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.`;
15329
+ 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.`;
15304
15330
  }
15305
15331
  }
15306
15332
  return null;
@@ -15308,13 +15334,13 @@ function guardCookieWrite(context) {
15308
15334
  function guardCdpMethod(context) {
15309
15335
  const reason = alwaysBlocked.get(context.method);
15310
15336
  if (reason) {
15311
- return `Browse blocked ${context.method}: ${reason}. This command is always blocked by the relay.`;
15337
+ return `browse blocked ${context.method}: ${reason}. This command is always blocked by the relay.`;
15312
15338
  }
15313
15339
  if (context.method.startsWith("WebAuthn.")) {
15314
- return `Browse blocked ${context.method}: agents can't drive WebAuthn or add virtual authenticators. Passkey sign-ins in agent tabs use the logins the user granted in Deadbolt. This command is always blocked by the relay.`;
15340
+ return `browse blocked ${context.method}: agents can't drive WebAuthn or add virtual authenticators. Passkey sign-ins in agent tabs use the logins the user granted in Deadbolt. This command is always blocked by the relay.`;
15315
15341
  }
15316
15342
  if (context.method === "Page.bringToFront" && !allowsForeground()) {
15317
- return "Browse blocked Page.bringToFront: it raises the user's browser window over their work. Use handoff() when the user needs to act in the tab, or set OPENCODE_BROWSER_ALLOW_FOREGROUND=1 on the relay to allow it.";
15343
+ return "browse blocked Page.bringToFront: it raises the user's browser window over their work. Use handoff() when the user needs to act in the tab, or set OPENCODE_BROWSER_ALLOW_FOREGROUND=1 on the relay to allow it.";
15318
15344
  }
15319
15345
  if ((context.method === "Storage.setCookies" || context.method === "Network.setCookies" || context.method === "Network.setCookie") && !allowsAllCookies()) {
15320
15346
  const rejection = guardCookieWrite(context);
@@ -15334,7 +15360,7 @@ function guardCdpMethod(context) {
15334
15360
  const hosts = pageHosts(context.pageUrls?.() ?? []);
15335
15361
  const host = typeof url === "string" ? pageHosts([url])[0] : undefined;
15336
15362
  if (host === undefined || !hosts.includes(host)) {
15337
- 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.`;
15363
+ 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.`;
15338
15364
  }
15339
15365
  }
15340
15366
  if (context.readOnly && readOnlyBlockedPrefixes.some((prefix) => context.method.startsWith(prefix))) {
@@ -15923,11 +15949,11 @@ function createExtensionCommands(options) {
15923
15949
  if (tabId !== undefined) {
15924
15950
  const owner = browsers.browserTab(tabId);
15925
15951
  if (!owner)
15926
- return Effect26.fail(new Error("Browse extension is not connected"));
15952
+ return Effect26.fail(new Error("browse extension is not connected"));
15927
15953
  return sendToBrowser(owner.link, { ...command, params: { ...command.params, tabId: owner.tabId } });
15928
15954
  }
15929
15955
  const target = link ?? browsers.defaultLink();
15930
- return target ? sendToBrowser(target, command) : Effect26.fail(new Error("Browse extension is not connected"));
15956
+ return target ? sendToBrowser(target, command) : Effect26.fail(new Error("browse extension is not connected"));
15931
15957
  };
15932
15958
  const sendExtensionBestEffort = (command, link) => {
15933
15959
  Effect26.runPromise(Effect26.ignore(sendToExtension(command, link))).catch(() => {});
@@ -15940,13 +15966,13 @@ function createExtensionCommands(options) {
15940
15966
  const sendToEach = (command) => Effect26.gen(function* () {
15941
15967
  const links = browsers.list().filter((link) => link.rpc.connected);
15942
15968
  if (links.length === 0)
15943
- return yield* Effect26.fail(new Error("Browse extension is not connected"));
15969
+ return yield* Effect26.fail(new Error("browse extension is not connected"));
15944
15970
  const results = yield* Effect26.forEach(links, (link) => Effect26.result(sendToBrowser(link, command)), { concurrency: "unbounded" });
15945
15971
  const succeeded = results.find(Result2.isSuccess);
15946
15972
  if (succeeded)
15947
15973
  return succeeded.success;
15948
15974
  const failed = results.find(Result2.isFailure);
15949
- return yield* Effect26.fail(failed?.failure ?? new Error("Browse extension is not connected"));
15975
+ return yield* Effect26.fail(failed?.failure ?? new Error("browse extension is not connected"));
15950
15976
  });
15951
15977
  return { sendToExtension, sendExtensionBestEffort, sendToEveryBrowser, sendToEach };
15952
15978
  }
@@ -16551,7 +16577,7 @@ class ExtensionHandshake {
16551
16577
  const rejected = link ? undefined : this.rejectedProtocol();
16552
16578
  const recent = Date.now() - 65000;
16553
16579
  const pairingState = browsers.connected ? "connected" : rejected ? "incompatible" : this.lastRefused > recent ? "refused" : this.lastUnpaired > recent ? "unpaired" : this.hasPairedBrowser ? "paired-offline" : "not-seen";
16554
- const nextStep = pairingState === "connected" ? undefined : pairingState === "incompatible" ? this.mismatchAdvice(rejected?.version) : pairingState === "refused" || pairingState === "unpaired" ? `${pairingState === "refused" ? "Browse refused the pairing attempt" : "Browse is installed but not paired"}. Run \`${cliCommand("install")}\` again to pair it, or run \`${cliCommand("pair")}\` and enter the new code in Browse's Options.` : pairingState === "paired-offline" ? "Open the browser profile already paired with Browse and enable the extension; it reconnects automatically." : `No browser has contacted this relay yet. If Browse is installed, open that browser and run \`${cliCommand("install")}\` to pair it. Otherwise ${storeId ? `add Browse from ${storeUrl(storeId)}` : `follow the extension steps in \`${installCommand()}\``}.`;
16580
+ const nextStep = pairingState === "connected" ? undefined : pairingState === "incompatible" ? this.mismatchAdvice(rejected?.version) : pairingState === "refused" || pairingState === "unpaired" ? `${pairingState === "refused" ? "browse refused the pairing attempt" : "browse is installed but not paired"}. Run \`${cliCommand("install")}\` again to pair it, or run \`${cliCommand("pair")}\` and enter the new code in browse's Options.` : pairingState === "paired-offline" ? "Open the browser profile already paired with browse and enable the extension; it reconnects automatically." : `No browser has contacted this relay yet. If browse is installed, open that browser and run \`${cliCommand("install")}\` to pair it. Otherwise ${storeId ? `add browse from ${storeUrl(storeId)}` : `follow the extension steps in \`${installCommand()}\``}.`;
16555
16581
  return {
16556
16582
  connected: browsers.connected,
16557
16583
  pairingState,
@@ -16710,7 +16736,7 @@ class ExtensionHandshake {
16710
16736
  this.legacyExtensionReloaded = true;
16711
16737
  socket.send(JSON.stringify({ id: 0, method: "runtime.reload" }));
16712
16738
  }
16713
- socket.close(4005, "Pairing required: update Browse");
16739
+ socket.close(4005, "Pairing required: update browse");
16714
16740
  return;
16715
16741
  }
16716
16742
  if (!/^[A-Za-z0-9_-]{22,128}$/.test(extensionNonce)) {
@@ -16743,7 +16769,7 @@ class ExtensionHandshake {
16743
16769
  if (mode === "old") {
16744
16770
  const code = legacyPairingCode();
16745
16771
  if (code === undefined)
16746
- return refuse("old extension, no shared code", "Pairing failed: update Browse, then pair it with the code `pair` prints");
16772
+ return refuse("old extension, no shared code", "Pairing failed: update browse, then pair it with the code `pair` prints");
16747
16773
  socket.send(JSON.stringify({ method: "auth.challenge", params: { nonce: relayNonce, proof: legacyPairingProof(code, "relay", port, relayNonce, extensionNonce), protocol } }));
16748
16774
  return { ...base, expected: legacyPairingProof(code, "extension", port, extensionNonce, relayNonce) };
16749
16775
  }
@@ -17036,9 +17062,9 @@ function createRelaySettingsSync(options) {
17036
17062
  const extensionSettings = (method, values) => Effect29.gen(function* () {
17037
17063
  if (!browsers.connected) {
17038
17064
  const rejected = handshake.rejectedProtocol();
17039
- return yield* Effect29.fail(new Error(rejected ? handshake.mismatchAdvice(rejected.version) : "The Browse extension isn't connected, so its settings can't be read or changed. Ask the user to open the browser with the extension; its options page shows whether it's connected."));
17065
+ return yield* Effect29.fail(new Error(rejected ? handshake.mismatchAdvice(rejected.version) : "The browse extension isn't connected, so its settings can't be read or changed. Ask the user to open the browser with the extension; its options page shows whether it's connected."));
17040
17066
  }
17041
- const result = yield* sendToExtension({ method, ...values ? { params: { values } } : {} }).pipe(Effect29.mapError((error) => /Invalid extension command/.test(error.message) ? new Error(`The connected Browse extension is too old to read or change settings from here. Update browse (\`${installCommand()}\`) and reload the extension, or change them on its options page.`) : error));
17067
+ const result = yield* sendToExtension({ method, ...values ? { params: { values } } : {} }).pipe(Effect29.mapError((error) => /Invalid extension command/.test(error.message) ? new Error(`The connected browse extension is too old to read or change settings from here. Update browse (\`${installCommand()}\`) and reload the extension, or change them on its options page.`) : error));
17042
17068
  return settingsFromExtension(result);
17043
17069
  });
17044
17070
  const settingOverrides = () => {
@@ -17106,9 +17132,9 @@ function createRelaySettingsSync(options) {
17106
17132
 
17107
17133
  // src/relay/tab-presentation.ts
17108
17134
  import { Effect as Effect30 } from "effect";
17109
- var attachedBadge = { text: "ON", color: "#7c3aed", title: "Detach from Browse" };
17110
- var executingBadge = { text: "RUN", color: "#f59e0b", title: "Browse is running a script. Click to stop it and take this tab back." };
17111
- var waitingBadge = (message) => ({ text: "WAIT", color: "#2563eb", title: `Browse is waiting for you: ${message} Click here when you're done.` });
17135
+ var attachedBadge = { text: "ON", color: "#7c3aed", title: "Detach from browse" };
17136
+ var executingBadge = { text: "RUN", color: "#f59e0b", title: "browse is running a script. Click to stop it and take this tab back." };
17137
+ var waitingBadge = (message) => ({ text: "WAIT", color: "#2563eb", title: `browse is waiting for you: ${message} Click here when you're done.` });
17112
17138
  function createTabPresentation(options) {
17113
17139
  const {
17114
17140
  registry,
@@ -17322,7 +17348,7 @@ function createTabPresentation(options) {
17322
17348
  }
17323
17349
  if (action === "stop-execution" && sessionId) {
17324
17350
  relayLog("execute.stopped", { tabId, session: sessionId, from: "toolbar" });
17325
- sessions.stopExecution(sessionId, `The user took tab ${tabId} back (Browse toolbar button) while this script ran, so it was stopped. Don't use that tab again unless the user lends it back; ask the user how to continue.`);
17351
+ sessions.stopExecution(sessionId, `The user took tab ${tabId} back (browse toolbar button) while this script ran, so it was stopped. Don't use that tab again unless the user lends it back; ask the user how to continue.`);
17326
17352
  }
17327
17353
  }
17328
17354
  Effect30.runPromise(toggleTab(tabId)).catch((error) => {
@@ -17402,7 +17428,7 @@ function createRelayTransportServers(deps) {
17402
17428
  }
17403
17429
  if (!isReady()) {
17404
17430
  response.writeHead(503, { "content-type": "application/json; charset=utf-8", "retry-after": "1" });
17405
- response.end(JSON.stringify({ error: "Browse relay is starting", code: "relay-starting" }));
17431
+ response.end(JSON.stringify({ error: "browse relay is starting", code: "relay-starting" }));
17406
17432
  return;
17407
17433
  }
17408
17434
  const started = performance.now();
@@ -17424,7 +17450,7 @@ function createRelayTransportServers(deps) {
17424
17450
  const websocketServer = new WebSocketServer({ noServer: true, maxPayload: 256 * 1024 * 1024 });
17425
17451
  httpServer.on("upgrade", (request, socket, head) => {
17426
17452
  if (!isReady()) {
17427
- sendUpgradeError({ socket, status: 404, message: "Browse relay is starting" });
17453
+ sendUpgradeError({ socket, status: 404, message: "browse relay is starting" });
17428
17454
  return;
17429
17455
  }
17430
17456
  const requestUrl = new URL(request.url ?? "/", endpointUrl);
@@ -17455,7 +17481,7 @@ function createRelayTransportServers(deps) {
17455
17481
  return;
17456
17482
  }
17457
17483
  if (!hasRelayToken(request, authToken) && !secretsEqual(authToken, requestUrl.searchParams.get(relayTokenQueryParam) ?? undefined)) {
17458
- sendUpgradeError({ socket, status: 401, message: "Missing or invalid Browse relay token" });
17484
+ sendUpgradeError({ socket, status: 401, message: "Missing or invalid browse relay token" });
17459
17485
  return;
17460
17486
  }
17461
17487
  if (requestUrl.pathname.startsWith("/devtools/browser/")) {
@@ -17847,7 +17873,7 @@ class SessionCatalog {
17847
17873
  } catch (error) {
17848
17874
  if (isNodeError(error) && error.code === "ENOENT")
17849
17875
  return [];
17850
- throw new Error(`Could not read Browse session catalog at ${this.filePath}`, { cause: error });
17876
+ throw new Error(`Could not read browse session catalog at ${this.filePath}`, { cause: error });
17851
17877
  }
17852
17878
  try {
17853
17879
  const sessions = Schema13.decodeUnknownSync(Catalog)(JSON.parse(text)).sessions;
@@ -17857,7 +17883,7 @@ class SessionCatalog {
17857
17883
  return sessions;
17858
17884
  } catch (error) {
17859
17885
  const detail = error instanceof Error && error.message ? `: ${error.message}` : "";
17860
- throw new Error(`Could not decode Browse session catalog at ${this.filePath}${detail}`, { cause: error });
17886
+ throw new Error(`Could not decode browse session catalog at ${this.filePath}${detail}`, { cause: error });
17861
17887
  }
17862
17888
  }
17863
17889
  async save(sessions) {
@@ -17893,7 +17919,7 @@ class SessionCatalog {
17893
17919
  try {
17894
17920
  await fs14.rm(temporaryPath, { force: true });
17895
17921
  } catch {}
17896
- throw new Error(`Could not write Browse session catalog at ${this.filePath}`, { cause: error });
17922
+ throw new Error(`Could not write browse session catalog at ${this.filePath}`, { cause: error });
17897
17923
  }
17898
17924
  }
17899
17925
  }
@@ -17950,7 +17976,7 @@ class SessionNavigationGuard {
17950
17976
  if (decision.allowed)
17951
17977
  return;
17952
17978
  this.dependencies.log("allowlist.refused", { session: options.sessionId, method: options.method, reason: decision.reason });
17953
- return `Browse blocked ${options.method}: session ${options.sessionId} has a domain allowlist and ${decision.reason}. Ask the user before widening it (session_allowlist / \`session allow\`).`;
17979
+ return `browse blocked ${options.method}: session ${options.sessionId} has a domain allowlist and ${decision.reason}. Ask the user before widening it (session_allowlist / \`session allow\`).`;
17954
17980
  }
17955
17981
  popupAttached(target) {
17956
17982
  if (!this.enforced(target))
@@ -17998,7 +18024,7 @@ class SessionNavigationGuard {
17998
18024
  if (decision.allowed)
17999
18025
  return;
18000
18026
  this.dependencies.send(target.tabId, "Page.stopLoading", {}).catch(() => {});
18001
- this.addWarning(sessionId, `Domain allowlist: a tab of session ${sessionId} started to navigate to ${shortUrl(url)}, but ${decision.reason}; Browse stopped it. Ask the user before widening the allowlist.`);
18027
+ this.addWarning(sessionId, `Domain allowlist: a tab of session ${sessionId} started to navigate to ${shortUrl(url)}, but ${decision.reason}; browse stopped it. Ask the user before widening the allowlist.`);
18002
18028
  this.dependencies.log("allowlist.stopped", { tabId: target.tabId, session: sessionId, method, reason: decision.reason });
18003
18029
  }
18004
18030
  enforced(target) {
@@ -18024,7 +18050,7 @@ class SessionNavigationGuard {
18024
18050
  const shownUrl = shortUrl(url);
18025
18051
  const popup = this.freshPopups.has(target.tabId) && target.owner === "relay";
18026
18052
  const action = popup ? "closed the popup" : "sent the tab back to about:blank";
18027
- this.addWarning(sessionId, `Domain allowlist: a tab of session ${sessionId} went to ${shownUrl}, but ${reason}; Browse ${action}. Ask the user before widening the allowlist.`);
18053
+ this.addWarning(sessionId, `Domain allowlist: a tab of session ${sessionId} went to ${shownUrl}, but ${reason}; browse ${action}. Ask the user before widening the allowlist.`);
18028
18054
  this.dependencies.log("allowlist.violation", { tabId: target.tabId, session: sessionId, url: shownUrl, popup });
18029
18055
  if (popup) {
18030
18056
  this.freshPopups.delete(target.tabId);
@@ -18441,7 +18467,7 @@ var makeRelay = Effect34.fnUntraced(function* (options = {}) {
18441
18467
  }
18442
18468
  const existing = sessionId ? registry.listRootTargets().find((target) => target.opencodeBrowserSessionId === sessionId && target.owner === "relay") : undefined;
18443
18469
  const link = (existing && browsers.browserTab(existing.tabId)?.link) ?? browsers.defaultLink();
18444
- return link ? Effect34.succeed(link) : Effect34.fail(new Error("Browse extension is not connected"));
18470
+ return link ? Effect34.succeed(link) : Effect34.fail(new Error("browse extension is not connected"));
18445
18471
  });
18446
18472
  const createAndAttachTab = Effect34.fnUntraced(function* (createOptions) {
18447
18473
  const link = yield* sessionBrowser(createOptions.opencodeBrowserSessionId);
@@ -18685,11 +18711,11 @@ var makeRelay = Effect34.fnUntraced(function* (options = {}) {
18685
18711
  await sessionCatalog.save(restored);
18686
18712
  return restored;
18687
18713
  },
18688
- catch: (cause) => cause instanceof Error ? cause : new Error("Load Browse session catalog", { cause })
18714
+ catch: (cause) => cause instanceof Error ? cause : new Error("Load browse session catalog", { cause })
18689
18715
  });
18690
18716
  yield* Effect34.try({
18691
18717
  try: () => sessions.restore(restoredSessions),
18692
- catch: (cause) => cause instanceof Error ? cause : new Error("Restore Browse sessions", { cause })
18718
+ catch: (cause) => cause instanceof Error ? cause : new Error("Restore browse sessions", { cause })
18693
18719
  });
18694
18720
  catalogWritesEnabled = true;
18695
18721
  if (managed) {
@@ -1,3 +1,4 @@
1
+ import"./main-ek76h9k1.mjs";
1
2
  import {
2
3
  cliCommand,
3
4
  installCommand,
@@ -16,15 +17,15 @@ import {
16
17
  installVersion,
17
18
  pruneVersions,
18
19
  switchVersion
19
- } from "./main-ma25hhqh.mjs";
20
+ } from "./main-0m569gdn.mjs";
21
+ import"./main-3gthmkzw.mjs";
20
22
  import {
21
23
  Service,
22
24
  layerFetch,
23
25
  restartRelay,
24
26
  startManagedRelay
25
- } from "./main-0nta0a2z.mjs";
26
- import"./main-20ahaz2q.mjs";
27
- import"./main-arx3pfyn.mjs";
27
+ } from "./main-qm2keaeb.mjs";
28
+ import"./main-7qs0mwvc.mjs";
28
29
 
29
30
  // src/update/runtime-update.ts
30
31
  import { Effect } from "effect";
@@ -68,7 +69,7 @@ function npmOnly(command) {
68
69
  const runtime = npmRuntime();
69
70
  if (runtime)
70
71
  return runtime;
71
- log(`\`${command}\` is for npm installs (\`${installCommand()}\`); this one isn't.`);
72
+ log(`\`${command}\` is for installs that update themselves (\`${installCommand()}\`); this one isn't.`);
72
73
  process.exitCode = 1;
73
74
  return;
74
75
  }