@bitkyc08/opencodex 2.75.0 → 2.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/README.md +6 -1
  2. package/bin/ocx.mjs +12 -1
  3. package/gui/dist/assets/App-CddorHdA.js +51 -0
  4. package/gui/dist/assets/App-DMudtISW.css +1 -0
  5. package/gui/dist/assets/{Tray-CGAD2AGk.js → Tray-DjNwwrWS.js} +1 -1
  6. package/gui/dist/assets/index-Btze1I3T.css +1 -0
  7. package/gui/dist/assets/index-CvnY7E6i.js +86 -0
  8. package/gui/dist/assets/quota-summary-B_AWpHfP.js +1 -0
  9. package/gui/dist/index.html +2 -2
  10. package/gui/dist/provider-icons/opengateway.svg +12 -0
  11. package/package.json +1 -1
  12. package/src/adapters/anthropic/account-metadata.ts +17 -0
  13. package/src/adapters/anthropic/client-identity.ts +69 -0
  14. package/src/adapters/anthropic/passthrough.ts +23 -4
  15. package/src/adapters/anthropic.ts +18 -1
  16. package/src/adapters/command-code-project-context.ts +7 -11
  17. package/src/adapters/devin/cloud-direct/tool-schema.ts +12 -48
  18. package/src/adapters/kiro-retry.ts +23 -8
  19. package/src/adapters/openai-chat/messages.ts +1 -1
  20. package/src/adapters/registry.ts +8 -1
  21. package/src/adapters/zed.ts +377 -0
  22. package/src/bridge/sse.ts +4 -2
  23. package/src/chatgpt/app-server-shim/app-server-rewrite.ts +45 -0
  24. package/src/chatgpt/app-server-shim/bundle-trust.ts +77 -0
  25. package/src/chatgpt/app-server-shim/filter.ts +157 -0
  26. package/src/chatgpt/app-server-shim/gate-rewrite.ts +99 -0
  27. package/src/chatgpt/app-server-shim/launcher.ts +91 -0
  28. package/src/claude/desktop-3p-startup.ts +62 -0
  29. package/src/claude/desktop-3p.ts +5 -0
  30. package/src/claude/first-party-settings.ts +14 -0
  31. package/src/claude/intercept/cli-catalog.ts +150 -0
  32. package/src/claude/intercept/cli-picker.ts +82 -0
  33. package/src/claude/intercept/listener.ts +21 -6
  34. package/src/claude/intercept/picker-bootstrap.ts +23 -5
  35. package/src/claude/intercept/picker-models.ts +57 -13
  36. package/src/claude/intercept/runtime.ts +30 -2
  37. package/src/claude/intercept/settings.ts +3 -0
  38. package/src/cli/agent.ts +172 -0
  39. package/src/cli/alias.ts +2 -1
  40. package/src/cli/capabilities-command.ts +3 -2
  41. package/src/cli/capabilities.ts +87 -0
  42. package/src/cli/chatgpt-command.ts +140 -0
  43. package/src/cli/combo.ts +144 -19
  44. package/src/cli/config-command.ts +3 -1
  45. package/src/cli/dispatch.ts +10 -1
  46. package/src/cli/help.ts +1 -0
  47. package/src/cli/index.ts +5 -24
  48. package/src/cli/init.ts +16 -2
  49. package/src/cli/integrations.ts +13 -0
  50. package/src/cli/internal-command.ts +12 -5
  51. package/src/cli/observe.ts +6 -1
  52. package/src/cli/registry.ts +6 -0
  53. package/src/cli/route-policy.ts +3 -1
  54. package/src/cli/runtime-api.ts +5 -2
  55. package/src/cli/status-oauth.ts +5 -0
  56. package/src/cli/status.ts +8 -1
  57. package/src/cli/stop-approval.ts +55 -16
  58. package/src/cli/stop-report.ts +5 -0
  59. package/src/clients/lazycodex.ts +48 -0
  60. package/src/clients/omo-role-models.ts +111 -0
  61. package/src/codex/account-credit-use.ts +99 -0
  62. package/src/codex/account-lifecycle.ts +2 -0
  63. package/src/codex/agent-role-models.ts +171 -0
  64. package/src/codex/auth-api/account-list.ts +10 -3
  65. package/src/codex/auth-api/routes.ts +34 -0
  66. package/src/codex/auth-context.ts +52 -11
  67. package/src/codex/catalog/discovered-natives.ts +11 -1
  68. package/src/codex/catalog/gather-capture.ts +6 -1
  69. package/src/codex/catalog/model-hints.ts +9 -1
  70. package/src/codex/catalog/provider-models.ts +60 -0
  71. package/src/codex/catalog/routed-gather.ts +30 -5
  72. package/src/codex/convergence-types.ts +2 -1
  73. package/src/codex/main-account-external-usage.ts +62 -0
  74. package/src/codex/main-account-hard-lock.ts +24 -13
  75. package/src/codex/native-profile-processes.ts +53 -16
  76. package/src/codex/prompt-layers/toml-edit.ts +1 -1
  77. package/src/codex/quota-types.ts +3 -7
  78. package/src/codex/quota.ts +19 -4
  79. package/src/codex/role-auto-assign.ts +159 -0
  80. package/src/codex/role-sizing-limits.ts +2 -0
  81. package/src/codex/role-sizing.ts +216 -0
  82. package/src/codex/routing/selection.ts +36 -0
  83. package/src/codex/routing/thread-affinity.ts +2 -0
  84. package/src/codex/routing.ts +4 -4
  85. package/src/codex/subagent-model-fallback.ts +82 -26
  86. package/src/codex/subagent-selectable-models.ts +32 -0
  87. package/src/combos/index.ts +18 -0
  88. package/src/combos/jev-decision-contract.ts +20 -0
  89. package/src/combos/jev-dispatch.ts +18 -0
  90. package/src/combos/jev-model-backend.ts +127 -0
  91. package/src/combos/jev.ts +249 -33
  92. package/src/combos/types.ts +125 -2
  93. package/src/config/diagnostics.ts +18 -0
  94. package/src/config/macos-system-proxy.ts +72 -15
  95. package/src/config/owner-registry.ts +13 -4
  96. package/src/config/process-state.ts +17 -8
  97. package/src/config/proxy-env.ts +35 -5
  98. package/src/config/schema/config-schema.ts +30 -1
  99. package/src/config/schema/leaf-validators.ts +4 -0
  100. package/src/config/serving-runtimes.ts +95 -1
  101. package/src/generated/compatibility-version.json +336 -156
  102. package/src/lib/errors.ts +7 -7
  103. package/src/lib/jsonc.ts +13 -0
  104. package/src/lib/local-chat-completion.ts +144 -0
  105. package/src/lib/provider-outbound.ts +87 -1
  106. package/src/lib/provider-runtime-fetch.ts +23 -0
  107. package/src/lib/provider-tls-profile.ts +221 -0
  108. package/src/lib/request-execution-budget.ts +16 -6
  109. package/src/lib/spend-reservation-ledger.ts +54 -20
  110. package/src/lib/sse-decoder.ts +20 -17
  111. package/src/lib/synced-state-location.ts +96 -0
  112. package/src/lib/winsw.ts +14 -5
  113. package/src/oauth/anthropic-account-refusal.ts +53 -4
  114. package/src/oauth/anthropic-model-quota.ts +83 -0
  115. package/src/oauth/anthropic-rate-limit-policy.ts +37 -0
  116. package/src/oauth/anthropic-routing.ts +112 -58
  117. package/src/oauth/health.ts +39 -3
  118. package/src/oauth/index.ts +14 -0
  119. package/src/oauth/kiro-account-load.ts +10 -0
  120. package/src/oauth/zed.ts +134 -0
  121. package/src/providers/model-discovery.ts +19 -8
  122. package/src/providers/model-rename-fields.ts +1 -0
  123. package/src/providers/provider-id-rewrite.ts +9 -2
  124. package/src/providers/quota/account-cache.ts +29 -7
  125. package/src/providers/quota/anthropic-cooldown-recovery.ts +18 -0
  126. package/src/providers/quota/anthropic-family-headers.ts +25 -0
  127. package/src/providers/quota/vendor-probes-oauth.ts +5 -1
  128. package/src/providers/quota-types.ts +4 -0
  129. package/src/providers/registry/entries-core.ts +18 -0
  130. package/src/providers/registry/entries-extended.ts +55 -0
  131. package/src/providers/registry/types.ts +3 -0
  132. package/src/providers/xai-fast-model.ts +12 -4
  133. package/src/providers/zed.ts +598 -0
  134. package/src/responses/state/snapshot-select.ts +22 -9
  135. package/src/responses/state.ts +2 -3
  136. package/src/router.ts +9 -0
  137. package/src/server/anthropic-rate-limit-headers.ts +7 -0
  138. package/src/server/auth-cors.ts +7 -0
  139. package/src/server/chat-completions.ts +9 -4
  140. package/src/server/claude-messages.ts +59 -21
  141. package/src/server/index/claude-intercept-lifecycle.ts +71 -25
  142. package/src/server/index/optional-listeners.ts +4 -0
  143. package/src/server/index/spend-ledger-lifecycle.ts +4 -0
  144. package/src/server/management/agent-settings-routes.ts +74 -37
  145. package/src/server/management/claude-desktop-picker-routes.ts +7 -0
  146. package/src/server/management/claude-intercept-routes.ts +35 -0
  147. package/src/server/management/codex-agent-role-routes.ts +122 -0
  148. package/src/server/management/codex-role-auto-assign.ts +208 -0
  149. package/src/server/management/combo-routes.ts +62 -5
  150. package/src/server/management/config-routes.ts +35 -3
  151. package/src/server/management/context.ts +4 -1
  152. package/src/server/management/decision-discovery.ts +74 -0
  153. package/src/server/management/decision-model-validation.ts +80 -0
  154. package/src/server/management/decision-routes.ts +160 -0
  155. package/src/server/management/native-integration-routes.ts +16 -0
  156. package/src/server/management/provider-routes.ts +30 -34
  157. package/src/server/management/route-registry.ts +12 -0
  158. package/src/server/management/sibling-guard.ts +1 -0
  159. package/src/server/management/zed-provider-probe.ts +38 -0
  160. package/src/server/management-api.ts +12 -1
  161. package/src/server/messages-native-oauth.ts +7 -2
  162. package/src/server/messages-native.ts +7 -3
  163. package/src/server/relay.ts +3 -1
  164. package/src/server/request-log.ts +2 -0
  165. package/src/server/responses/adapter-continuation.ts +3 -3
  166. package/src/server/responses/adapter-dispatch.ts +18 -3
  167. package/src/server/responses/compact.ts +14 -1
  168. package/src/server/responses/core-auth.ts +2 -0
  169. package/src/server/responses/core-combo.ts +67 -11
  170. package/src/server/responses/core-normalize.ts +21 -1
  171. package/src/server/responses/core-options.ts +11 -1
  172. package/src/server/responses/core.ts +5 -3
  173. package/src/server/responses/fetch-helpers.ts +6 -3
  174. package/src/server/responses/jev-model-invoke.ts +190 -0
  175. package/src/server/responses/passthrough-delivery.ts +16 -0
  176. package/src/server/responses/policy-fallback.ts +55 -3
  177. package/src/server/responses/policy-request-scope.ts +80 -0
  178. package/src/server/responses/request-prepare.ts +70 -18
  179. package/src/server/responses/request-transport.ts +54 -23
  180. package/src/server/responses/run-turn-execution.ts +1 -0
  181. package/src/server/responses/sidecar-execution.ts +9 -3
  182. package/src/server/responses-hosted-image-display.ts +225 -0
  183. package/src/service/managing-cli.ts +34 -4
  184. package/src/service/systemd-env.ts +75 -0
  185. package/src/service/windows-guarded-manager.ts +60 -19
  186. package/src/service/windows-scheduler.ts +22 -3
  187. package/src/service/windows-taskxml.ts +32 -10
  188. package/src/service-manager-probe.ts +72 -19
  189. package/src/types/config.ts +31 -1
  190. package/src/types/provider.ts +2 -0
  191. package/src/types/request.ts +2 -0
  192. package/src/update/index.ts +39 -6
  193. package/src/update/job.ts +63 -63
  194. package/src/update/npm-cache-preflight.d.mts +33 -1
  195. package/src/update/npm-cache-preflight.mjs +131 -18
  196. package/src/update/ownership-transaction.ts +19 -1
  197. package/src/update/restart-ownership.ts +80 -6
  198. package/src/update/transactional-install.d.mts +2 -0
  199. package/src/update/transactional-install.mjs +6 -1
  200. package/src/usage/jev-stats.ts +28 -1
  201. package/src/usage/log.ts +1 -1
  202. package/src/vision/anthropic-describe.ts +5 -3
  203. package/src/vision/index.ts +1 -0
  204. package/src/vision/plan.ts +2 -1
  205. package/src/vision/routed-describe.ts +29 -121
  206. package/src/web-search/alpha-search.ts +3 -3
  207. package/src/web-search/anthropic-executor.ts +6 -4
  208. package/src/web-search/index.ts +1 -1
  209. package/src/web-search/loop.ts +3 -3
  210. package/src/web-search/passthrough-bridge.ts +2 -1
  211. package/src/web-search/run-turn-loop.ts +1 -1
  212. package/src/web-search/sidecar-providers.ts +2 -1
  213. package/gui/dist/assets/App-ia4U0ufY.css +0 -1
  214. package/gui/dist/assets/App-xm0zGNOe.js +0 -51
  215. package/gui/dist/assets/index-DBT3Q31Y.css +0 -1
  216. package/gui/dist/assets/index-D_RGAT6Q.js +0 -86
  217. package/gui/dist/assets/quota-summary-CUFq48t-.js +0 -1
@@ -19,18 +19,13 @@
19
19
  * admission secret in a forwardable header is a forwarding hazard). Loopback
20
20
  * binds require no token at all (resolveApiAuth admits loopback).
21
21
  *
22
- * Destination (#4236): the unauthenticated loopback listener when one is
23
- * enabled, otherwise the BIND address — the former roadmap-170 limitation
24
- * ("a bindHost where 127.0.0.1 does not answer cannot reach its own
25
- * loopback") is closed by resolving through `localInferenceDestination`
26
- * rather than composing 127.0.0.1 by hand.
22
+ * Destination (#4236) and transport: postLocalChatCompletion in
23
+ * src/lib/local-chat-completion.ts, which resolves the unauthenticated
24
+ * loopback listener when one is enabled and otherwise the BIND address.
27
25
  */
28
26
  import type { OcxConfig } from "../types";
29
- import { localAdmissionToken, localInferenceDestination } from "../lib/local-destinations";
30
- import { signalWithTimeout, cancelBodyOnAbort } from "../lib/abort";
31
- import { redactSecretString } from "../lib/redact";
32
- import { sidecarEnter } from "../lib/sidecar-tracker";
33
- import { configuredPort } from "../server/auth-cors";
27
+ import { localAdmissionToken } from "../lib/local-destinations";
28
+ import { localChatCompletionBaseUrl, postLocalChatCompletion } from "../lib/local-chat-completion";
34
29
  import type { DescribeOutcome, VisionSettings } from "./describe";
35
30
 
36
31
  export const VISION_DESCRIBE_TERMINAL_HEADER = "x-opencodex-vision-describe";
@@ -77,28 +72,7 @@ export function routedDescribeAdmissionToken(config: Pick<OcxConfig, "apiKeys">)
77
72
  export function routedDescribeBaseUrl(
78
73
  config: Pick<OcxConfig, "port" | "hostname" | "unauthenticatedLoopbackListener">,
79
74
  ): string {
80
- return routedDescribeDestination(config).origin;
81
- }
82
-
83
- /**
84
- * The local destination this self-fetch dials, and whether it needs a credential.
85
- *
86
- * This is a local client like any other: the unauthenticated loopback listener when one is
87
- * enabled, otherwise the bind address — on a tailnet-bound hub there is no loopback socket at
88
- * all (#4236). The helper sends the OpenAI chat wire, which that listener now admits.
89
- */
90
- function routedDescribeDestination(
91
- config: Pick<OcxConfig, "port" | "hostname" | "unauthenticatedLoopbackListener">,
92
- ) {
93
- // config.port can be 0 (ephemeral bind, tests) or stale after a live port override; the
94
- // server records its ACTUAL bound port via setCorsOrigin at startup, so prefer that when
95
- // config carries no positive port. `configuredPort()` is itself `0` when `_corsOrigin` has no
96
- // explicit port (a default-port origin), so the literal default has to backstop it or the
97
- // composed URL names port 0 and the self-fetch cannot connect.
98
- const port = config.port && config.port > 0
99
- ? config.port
100
- : Number(configuredPort()) || 10_100;
101
- return localInferenceDestination(config, port);
75
+ return localChatCompletionBaseUrl(config);
102
76
  }
103
77
 
104
78
  export async function describeImageRouted(
@@ -114,93 +88,27 @@ export async function describeImageRouted(
114
88
  const invalid = validateImageUrl(imageUrl);
115
89
  if (invalid) return { text: "", error: invalid };
116
90
 
117
- const headers: Record<string, string> = {
118
- "Content-Type": "application/json",
119
- [VISION_DESCRIBE_TERMINAL_HEADER]: "1",
120
- };
121
- const admission = routedDescribeAdmissionToken(config);
122
- if (admission) headers["x-opencodex-api-key"] = admission;
123
- // A bind that demands admission with no resolvable credential would return 401 with a body
124
- // the caller reports as a describe failure; naming the cause once is the difference between
125
- // "vision is broken" and a fixable configuration note.
126
- if (!admission && !baseUrlOverride && routedDescribeDestination(config).requiresAdmissionToken) {
127
- console.warn(
128
- "[vision] routed describe has no opencodex data-plane credential for "
129
- + `${routedDescribeBaseUrl(config)} — the self-fetch will be refused.`,
130
- );
131
- }
132
-
133
- const requestBody = {
134
- model: routedModel,
135
- stream: false,
136
- messages: [
137
- { role: "system", content: DESCRIBE_INSTRUCTION },
138
- {
139
- role: "user",
140
- content: [
141
- ...(contextText ? [{ type: "text", text: `User's request context: ${contextText}` }] : []),
142
- { type: "image_url", image_url: { url: imageUrl } },
143
- ],
144
- },
145
- ],
146
- };
147
-
148
- const linkedSignal = signalWithTimeout(settings.timeoutMs, abortSignal);
149
- const sidecarExit = sidecarEnter("vision");
150
- const t0 = Date.now();
151
- try {
152
- const res = await fetch(`${baseUrlOverride ?? routedDescribeBaseUrl(config)}/v1/chat/completions`, {
153
- method: "POST",
154
- headers,
155
- body: JSON.stringify(requestBody),
156
- signal: linkedSignal.signal,
157
- redirect: "manual",
158
- });
159
- const detachBodyGuard = cancelBodyOnAbort(res.body, linkedSignal.signal);
160
- try {
161
- const raw = await res.text();
162
- if (raw.length > MAX_ROUTED_RESPONSE_BYTES) {
163
- return { text: "", error: "routed describe response exceeded byte bound" };
164
- }
165
- if (!res.ok) {
166
- return { text: "", error: `routed describe HTTP ${res.status}: ${redactSecretString(raw.slice(0, 200))}` };
167
- }
168
- let payload: unknown;
169
- try { payload = JSON.parse(raw); } catch {
170
- return { text: "", error: "routed describe returned non-JSON" };
171
- }
172
- const content = extractChatContent(payload);
173
- if (!content) return { text: "", error: "routed describe returned no text" };
174
- return { text: content };
175
- } finally {
176
- detachBodyGuard();
177
- }
178
- } catch (e) {
179
- const kind = e instanceof Error && e.name === "TimeoutError" ? "timeout" : "connect_error";
180
- console.warn(`[vision] routed describe ${kind} (${Date.now() - t0}ms)`);
181
- return { text: "", error: redactSecretString(e instanceof Error ? e.message : String(e)) };
182
- } finally {
183
- sidecarExit();
184
- linkedSignal.cleanup();
185
- }
186
- }
187
-
188
- function extractChatContent(payload: unknown): string | undefined {
189
- if (!payload || typeof payload !== "object") return undefined;
190
- const choices = (payload as { choices?: unknown }).choices;
191
- if (!Array.isArray(choices) || choices.length === 0) return undefined;
192
- const message = (choices[0] as { message?: unknown })?.message;
193
- if (!message || typeof message !== "object") return undefined;
194
- const content = (message as { content?: unknown }).content;
195
- if (typeof content === "string" && content.trim().length > 0) return content;
196
- // Some adapters emit content parts; join text parts.
197
- if (Array.isArray(content)) {
198
- const joined = content
199
- .map(part => (part && typeof part === "object" && typeof (part as { text?: unknown }).text === "string"
200
- ? (part as { text: string }).text
201
- : ""))
202
- .join("");
203
- if (joined.trim().length > 0) return joined;
204
- }
205
- return undefined;
91
+ return postLocalChatCompletion({
92
+ config,
93
+ label: "routed describe",
94
+ logTag: "vision",
95
+ timeoutMs: settings.timeoutMs,
96
+ maxResponseBytes: MAX_ROUTED_RESPONSE_BYTES,
97
+ headers: { [VISION_DESCRIBE_TERMINAL_HEADER]: "1" },
98
+ abortSignal,
99
+ baseUrlOverride,
100
+ body: {
101
+ model: routedModel,
102
+ messages: [
103
+ { role: "system", content: DESCRIBE_INSTRUCTION },
104
+ {
105
+ role: "user",
106
+ content: [
107
+ ...(contextText ? [{ type: "text", text: `User's request context: ${contextText}` }] : []),
108
+ { type: "image_url", image_url: { url: imageUrl } },
109
+ ],
110
+ },
111
+ ],
112
+ },
113
+ });
206
114
  }
@@ -62,7 +62,7 @@ const DEFAULT_BACKEND_MODELS = {
62
62
  export type AlphaSearchSidecarBackend = keyof typeof DEFAULT_BACKEND_MODELS;
63
63
 
64
64
  type ResolvedAlphaSearchSidecar =
65
- | { backend: "anthropic"; providerName: string; provider: OcxProviderConfig }
65
+ | { backend: "anthropic"; providerName: string; provider: OcxProviderConfig; config: OcxConfig }
66
66
  | { backend: "xai"; providerName: string; provider: OcxProviderConfig }
67
67
  | { backend: "gemini"; providerName: string; provider: OcxProviderConfig }
68
68
  | { backend: "exa"; apiKey: string };
@@ -103,7 +103,7 @@ export function resolveAlphaSearchSidecar(config: OcxConfig): AlphaSearchSidecar
103
103
  case "anthropic": {
104
104
  const found = findAnthropicSidecarProvider(config);
105
105
  return found
106
- ? { status: "ready", sidecar: { backend, providerName: found.providerName, provider: found.provider } }
106
+ ? { status: "ready", sidecar: { backend, providerName: found.providerName, provider: found.provider, config } }
107
107
  : { status: "missing-credential", backend };
108
108
  }
109
109
  case "xai": {
@@ -188,7 +188,7 @@ async function runAlphaSearchQuery(
188
188
  ): Promise<SidecarOutcome> {
189
189
  switch (resolved.backend) {
190
190
  case "anthropic":
191
- return runAnthropicWebSearch(query, resolved.providerName, resolved.provider, settings, signal);
191
+ return runAnthropicWebSearch(query, resolved.providerName, resolved.provider, settings, signal, config);
192
192
  case "xai":
193
193
  return runXaiWebSearch(
194
194
  query,
@@ -1,5 +1,6 @@
1
- import type { OcxProviderConfig } from "../types";
2
- import { getValidAccessToken, publicOAuthAuthenticationErrorMessage } from "../oauth";
1
+ import type { OcxConfig, OcxProviderConfig } from "../types";
2
+ import { publicOAuthAuthenticationErrorMessage } from "../oauth";
3
+ import { getAnthropicSidecarAccessToken } from "../oauth/anthropic-routing";
3
4
  import { ANTHROPIC_OAUTH_BETA, CLAUDE_CODE_SYSTEM_INSTRUCTION } from "../oauth/anthropic";
4
5
  import { sidecarThinkingOff } from "../adapters/anthropic-model-contract";
5
6
  import { CLAUDE_CODE_HEADERS, claudeCodeSessionId } from "../adapters/client-fingerprint";
@@ -153,7 +154,7 @@ export async function parseAnthropicSidecarSSE(res: Response): Promise<SidecarOu
153
154
 
154
155
  /**
155
156
  * Execute ONE web search via a Claude sidecar through the STORED anthropic OAuth credential — the
156
- * Anthropic-backed analog of runWebSearch. Authenticates with getValidAccessToken (refresh handled)
157
+ * Anthropic-backed analog of runWebSearch. Resolves the helper model's permitted account (refresh handled)
157
158
  * and reproduces the Claude Code OAuth fingerprint (identity system block first, oauth beta, client
158
159
  * headers, stable session id) so the request is first-party-shaped. Never throws — returns `{error}`
159
160
  * so the caller injects a graceful tool result.
@@ -164,12 +165,13 @@ export async function runAnthropicWebSearch(
164
165
  provider: OcxProviderConfig,
165
166
  settings: SidecarSettings,
166
167
  abortSignal?: AbortSignal,
168
+ config?: OcxConfig,
167
169
  ): Promise<SidecarOutcome> {
168
170
  const base = provider.baseUrl.replace(/\/v1\/?$/, "");
169
171
  const url = `${base}/v1/messages`;
170
172
  let token: string;
171
173
  try {
172
- token = await getValidAccessToken(providerName);
174
+ token = await getAnthropicSidecarAccessToken(providerName, settings.model, config);
173
175
  } catch (e) {
174
176
  return { text: "", sources: [], error: `anthropic sidecar auth failed: ${publicOAuthAuthenticationErrorMessage(e)}` };
175
177
  }
@@ -170,7 +170,7 @@ export function planWebSearch(
170
170
  // resolveSidecarBackend's explicit-or-openai contract.
171
171
  const auth = resolveSidecarAuth(config);
172
172
  const anthropicSidecar = auth.isAnthropicAuth && auth.anthropicProviderName && auth.anthropicProvider
173
- ? { providerName: auth.anthropicProviderName, provider: auth.anthropicProvider }
173
+ ? { providerName: auth.anthropicProviderName, provider: auth.anthropicProvider, config }
174
174
  : undefined;
175
175
  const backend = resolveSidecarBackend(cfg.backend);
176
176
  const maxSearches = cfg.maxSearchesPerTurn ?? DEFAULT_MAX_SEARCHES;
@@ -1,5 +1,5 @@
1
1
  import type { AdapterRequest, IncomingMeta, ProviderAdapter } from "../adapters/base";
2
- import type { AdapterEvent, OcxMessage, OcxParsedRequest, OcxProviderConfig, OcxProviderOpaqueToolCallMetadata, OcxThinkingContent, OcxUsage, RateLimitRetryPolicy } from "../types";
2
+ import type { AdapterEvent, OcxConfig, OcxMessage, OcxParsedRequest, OcxProviderConfig, OcxProviderOpaqueToolCallMetadata, OcxThinkingContent, OcxUsage, RateLimitRetryPolicy } from "../types";
3
3
  import { namespacedToolName, toolChoiceToolPredicate } from "../types";
4
4
  import { cloneProviderOpaqueToolCallMetadata } from "../responses/provider-opaque-metadata";
5
5
  import type { AttemptRecoveryKind } from "../usage/log";
@@ -282,7 +282,7 @@ export interface WebSearchLoopDeps {
282
282
  /** Required for the openai backend; unused (and typically undefined) for the anthropic backend. */
283
283
  forwardProvider?: OcxProviderConfig;
284
284
  /** Required for the anthropic backend: the stored-OAuth provider that runs web_search_20250305. */
285
- anthropicSidecar?: { providerName: string; provider: OcxProviderConfig };
285
+ anthropicSidecar?: { providerName: string; provider: OcxProviderConfig; config: OcxConfig };
286
286
  /** Required for the xai backend: the stored Grok OAuth provider (L7). */
287
287
  xaiSidecar?: { providerName: string; provider: OcxProviderConfig };
288
288
  /** Required for the gemini backend: the stored Antigravity CCA provider (L8). */
@@ -743,7 +743,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
743
743
  // signal would otherwise look like an ordinary degradable failure).
744
744
  try {
745
745
  if (backend === "anthropic" && anthropicSidecar) {
746
- outcome = await runAnthropicWebSearch(query, anthropicSidecar.providerName, anthropicSidecar.provider, settings, signal);
746
+ outcome = await runAnthropicWebSearch(query, anthropicSidecar.providerName, anthropicSidecar.provider, settings, signal, anthropicSidecar.config);
747
747
  } else if (backend === "xai") {
748
748
  // L7: stored Grok OAuth to the pinned api.x.ai Responses endpoint; same
749
749
  // never-throws contract and no Codex/OpenAI pool outcome recording (F5 parity).
@@ -232,7 +232,7 @@ export function resolveOllamaWebSearchEndpoint(
232
232
  /** Credentials that may run a non-Ollama passthrough-bridge search. The key never rides the plan. */
233
233
  export interface PassthroughWebSearchBridgeAuth {
234
234
  openAiSidecar?: ResolvedOpenAiForwardSidecar;
235
- anthropic?: { providerName: string; provider: OcxProviderConfig };
235
+ anthropic?: { providerName: string; provider: OcxProviderConfig; config: OcxConfig };
236
236
  xai?: { providerName: string; provider: OcxProviderConfig };
237
237
  gemini?: { providerName: string; provider: OcxProviderConfig };
238
238
  exaApiKey?: string;
@@ -967,6 +967,7 @@ export function createPassthroughWebSearchBridgeExecutor(
967
967
  anthropic.provider,
968
968
  settings,
969
969
  querySignal,
970
+ anthropic.config,
970
971
  );
971
972
  }
972
973
  case "xai": {
@@ -262,7 +262,7 @@ export async function* runTurnWebSearchLoop(
262
262
  switch (plan.backend) {
263
263
  case "anthropic":
264
264
  return plan.anthropicSidecar
265
- ? await runAnthropicWebSearch(query, plan.anthropicSidecar.providerName, plan.anthropicSidecar.provider, plan.settings, signal)
265
+ ? await runAnthropicWebSearch(query, plan.anthropicSidecar.providerName, plan.anthropicSidecar.provider, plan.settings, signal, plan.anthropicSidecar.config)
266
266
  : { text: "", sources: [], error: "anthropic backend selected without a resolved sidecar provider" };
267
267
  case "xai":
268
268
  return plan.xaiSidecar
@@ -35,6 +35,7 @@ export function resolveSidecarBackend(
35
35
  export interface AnthropicSidecarProvider {
36
36
  providerName: string;
37
37
  provider: OcxProviderConfig;
38
+ config: OcxConfig;
38
39
  }
39
40
 
40
41
  /**
@@ -48,7 +49,7 @@ export interface AnthropicSidecarProvider {
48
49
  export function findAnthropicSidecarProvider(config: OcxConfig): AnthropicSidecarProvider | undefined {
49
50
  const auth = resolveSidecarAuth(config);
50
51
  if (!auth.isAnthropicAuth || !auth.anthropicProviderName || !auth.anthropicProvider) return undefined;
51
- return { providerName: auth.anthropicProviderName, provider: auth.anthropicProvider };
52
+ return { providerName: auth.anthropicProviderName, provider: auth.anthropicProvider, config };
52
53
  }
53
54
 
54
55
  /**
@@ -1 +0,0 @@
1
- .codex-account-controls{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:12px;min-width:0;display:flex}.codex-account-auto-switch{flex:none;align-items:center;gap:7px;min-width:0;display:flex}.codex-account-auto-switch-label{font-size:var(--text-label);color:var(--muted);font-weight:var(--weight-medium);white-space:nowrap}.codex-account-auto-switch-input-wrap{align-items:stretch;display:inline-flex;position:relative}.codex-account-auto-switch-input{width:76px;height:30px;font-size:var(--text-label);text-align:right;padding:4px 38px 4px 8px}.codex-account-auto-switch-unit{color:var(--muted);font-size:var(--text-label);pointer-events:none;position:absolute;top:50%;right:25px;transform:translateY(-50%)}.codex-account-auto-switch-input-wrap .ocx-stepper{width:22px}.codex-account-auto-switch-toggle{transform-origin:50%;margin-inline:-3px;transform:scale(.8)}.quota-row--codex-credits .quota-val{white-space:nowrap}.quota-compact:has(>.quota-row--codex-credits){grid-template-columns:minmax(34px,max-content) max-content minmax(34px,max-content) minmax(38px,max-content) minmax(58px,1fr) minmax(30px,max-content);column-gap:8px}.quota-compact:has(>.quota-row--codex-credits)>*{grid-column:1/-1}.quota-compact:has(>.quota-row--codex-credits)>.quota-row:not(.quota-row--credits){grid-template-columns:subgrid}.codex-auth-credits-toggle{align-items:center;gap:var(--space-2);white-space:nowrap;display:inline-flex}.codex-auth-credits-toggle__label{font-size:var(--text-label);color:var(--muted)}.kiro-device-dialog{max-width:var(--prose-measure);border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--surface);width:100%;color:var(--text);padding:var(--space-6)}.kiro-device-dialog::backdrop{background:var(--glass-rail)}.kiro-login-choices{gap:var(--space-2);margin-block:var(--space-4);display:grid}.kiro-login-choices .btn{min-height:var(--control-touch);justify-content:flex-start}.kiro-device-code{align-items:center;gap:var(--space-3);margin-block:var(--space-4);flex-wrap:wrap;display:flex}.kiro-device-code-value{font-family:var(--font-code);font-size:var(--text-title);font-weight:var(--weight-semibold);letter-spacing:var(--tracking-wide)}.kiro-device-destination{overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.kiro-device-actions{justify-content:flex-end;gap:var(--space-2);margin-top:var(--space-4);display:flex}.remote-link-page{gap:var(--space-4);display:grid}.remote-link-page .page-head{align-items:flex-start}.remote-link-page .page-sub{max-width:var(--prose-measure);margin:0}.remote-link-panel{gap:var(--space-4);display:grid}.remote-link-off-preview{min-height:260px;position:relative;overflow:hidden}.remote-link-off-preview:after{content:"";pointer-events:none;-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);background:color-mix(in srgb, var(--bg) 24%, transparent);position:absolute;inset:0}.remote-link-preview-content{gap:var(--space-3);filter:grayscale();opacity:.64;-webkit-user-select:none;user-select:none;display:grid}.remote-link-preview-row{justify-content:space-between;align-items:center;gap:var(--space-3);padding:var(--space-3);border:1px solid var(--border-soft);border-radius:var(--radius-sm);background:var(--raised);display:flex}.remote-link-preview-lines{gap:var(--space-2);width:min(55%,300px);display:grid}.remote-link-preview-lines span{border-radius:var(--radius-pill);background:var(--border);height:8px;display:block}.remote-link-switch-row{z-index:1;justify-content:space-between;align-items:center;gap:var(--space-4);display:flex;position:relative}.remote-link-switch{width:var(--control-touch);height:var(--control-md);border:1px solid var(--border);border-radius:var(--radius-pill);background:var(--toggle-off-bg);cursor:pointer;padding:3px}.remote-link-switch:after{content:"";background:var(--toggle-dot-color);width:24px;height:24px;transition:transform var(--motion-fast) ease;border-radius:50%;display:block}.remote-link-switch[aria-checked=true]{background:var(--toggle-on-bg)}.remote-link-switch[aria-checked=true]:after{transform:translate(16px)}.remote-link-switch:focus-visible,.remote-link-role-card:focus-visible,.remote-link-sheet button:focus-visible,.remote-link-row button:focus-visible{outline:2px solid var(--accent-ring);outline-offset:2px}.remote-link-role-grid{gap:var(--space-3);grid-template-columns:repeat(2,minmax(0,1fr));display:grid}.remote-link-role-card{min-height:132px;padding:var(--space-4);border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--raised);color:var(--text);text-align:left;cursor:pointer}.remote-link-role-card:hover{background:var(--raised-hover)}.remote-link-role-card[aria-disabled=true]{color:var(--muted);cursor:not-allowed;opacity:.72}.remote-link-role-card[aria-disabled=true]:hover{background:var(--raised)}.remote-link-role-card[aria-checked=true]{border-color:var(--text);box-shadow:0 0 0 1px var(--text)}.remote-link-role-card strong,.remote-link-role-card span{display:block}.remote-link-role-card span{margin-top:var(--space-2);color:var(--muted);font-size:var(--text-label)}.remote-link-toolbar{justify-content:space-between;align-items:center;gap:var(--space-3);display:flex}.remote-link-status{align-items:center;gap:var(--space-2);color:var(--muted);font-size:var(--text-label);display:inline-flex}.remote-link-status:before{content:"";background:var(--faint);border-radius:50%;flex:none;width:8px;height:8px}.remote-link-status[data-state=connected]:before{background:var(--green)}.remote-link-status[data-state=reconnecting]:before{background:var(--amber)}.remote-link-status[data-state=failed]:before{background:var(--red)}.remote-link-status[data-state=connecting]:before{background:var(--amber)}.remote-link-children{gap:var(--space-2);display:grid}.remote-link-row{gap:var(--space-3);padding:var(--space-3);border:1px solid var(--border-soft);border-radius:var(--radius-sm);background:var(--raised);grid-template-columns:minmax(0,1fr) auto;align-items:center;display:grid}.remote-link-row-main{gap:var(--space-2);min-width:0;display:grid}.remote-link-row-meta{gap:var(--space-3);color:var(--muted);font-size:var(--text-caption);flex-wrap:wrap;display:flex}.remote-link-row .btn{min-height:var(--control-touch)}.remote-link-error{color:var(--red)}.remote-link-hint{margin-top:var(--space-1);color:var(--muted);font-size:var(--text-label);overflow-wrap:anywhere;display:block}.remote-link-info{color:var(--muted);font-size:var(--text-label)}.remote-link-restart{gap:var(--space-2);padding:var(--space-4);border:1px solid var(--border-soft);border-radius:var(--radius-sm);background:var(--raised);display:grid}.remote-link-restart p{color:var(--muted);margin:0}.remote-link-fingerprint{padding:var(--space-3);overflow-wrap:anywhere;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--raised);font-family:var(--font-code);font-size:var(--text-label);margin:0}.remote-link-workspace-card{justify-content:space-between;align-items:center;gap:var(--space-4);display:flex}.remote-link-workspace-card p{margin:var(--space-1) 0 0;color:var(--muted);font-size:var(--text-label)}.remote-link-sheet{width:min(620px, calc(100vw - var(--space-4)));max-height:min(760px, calc(100dvh - var(--space-4)));padding:var(--space-6);border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--bg);color:var(--text);box-shadow:var(--shadow);margin:auto;overflow:auto}.remote-link-sheet::backdrop{background:color-mix(in srgb, var(--text) 24%, transparent)}.remote-link-sheet-head{justify-content:space-between;align-items:flex-start;gap:var(--space-3);display:flex}.remote-link-sheet-head h3{font-size:var(--text-title);margin:0}.remote-link-sheet-body{gap:var(--space-4);margin-top:var(--space-5);display:grid}.remote-link-candidates{gap:var(--space-2);display:grid}.remote-link-candidate{justify-content:space-between;align-items:center;gap:var(--space-3);min-height:var(--control-touch);padding:var(--space-2) var(--space-3);border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--raised);color:var(--text);cursor:pointer;text-align:left;display:flex}.remote-link-candidate:hover{background:var(--raised-hover)}.remote-link-form{gap:var(--space-2);display:grid}.remote-link-form .field-label{margin-bottom:0}.remote-link-sheet-actions{justify-content:flex-end;gap:var(--space-2);flex-wrap:wrap;display:flex}.remote-link-confirm-dialog{width:min(460px, calc(100vw - var(--space-4)));padding:var(--space-5);border:1px solid var(--border);border-radius:var(--radius);background:var(--bg);color:var(--text);box-shadow:var(--shadow);margin:auto}.remote-link-confirm-dialog::backdrop{background:color-mix(in srgb, var(--text) 24%, transparent)}.remote-link-confirm-dialog h3{font-size:var(--text-subtitle);margin:0}.remote-link-confirm-dialog p{color:var(--muted)}@media (width<=620px){.remote-link-role-grid{grid-template-columns:1fr}.remote-link-workspace-card,.remote-link-switch-row{flex-direction:column;align-items:stretch}.remote-link-switch{align-self:flex-start}.remote-link-sheet{width:calc(100vw - var(--space-2));border-radius:var(--radius-lg) var(--radius-lg) 0 0;max-height:88dvh;margin:auto auto 0}}@media (prefers-reduced-motion:reduce){.remote-link-page *,.remote-link-page :before,.remote-link-page :after{scroll-behavior:auto!important;transition:none!important;animation:none!important}}.quota-summary-bar{z-index:var(--z-sticky);border-bottom:1px solid var(--border);background:var(--bg);min-height:34px;font-size:var(--text-label);align-items:center;gap:12px;padding:4px 16px;display:flex;position:sticky;top:0}.quota-summary-scroller{flex:1;align-items:center;gap:2px;min-width:0;display:flex}.quota-summary-list{overscroll-behavior-x:contain;scrollbar-width:none;flex-wrap:nowrap;flex:auto;align-items:center;gap:4px;min-width:0;margin:0;padding:3px;list-style:none;display:flex;overflow:auto hidden}.quota-summary-list::-webkit-scrollbar{display:none}.quota-summary-item{flex:none}.quota-summary-scroll{border:1px solid var(--border);background:var(--surface);width:22px;height:22px;color:var(--text);font:inherit;cursor:pointer;border-radius:999px;flex:none;place-items:center;padding:0;font-weight:600;line-height:1;display:inline-grid}.quota-summary-scroll:hover:not([aria-disabled=true]){background:var(--bg)}.quota-summary-scroll[aria-disabled=true]{color:var(--muted);opacity:.45;cursor:default}.quota-summary-scroll:focus-visible{outline:2px solid var(--text);outline-offset:1px}.quota-summary-chip{color:var(--text);font:inherit;white-space:nowrap;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:999px;align-items:center;gap:6px;padding:3px 8px;text-decoration:none;display:inline-flex}.quota-summary-chip:hover,.quota-summary-chip--open{border-color:var(--border)}.quota-summary-chip:focus-visible{outline:2px solid var(--text);outline-offset:1px}.quota-summary-name{color:var(--muted)}.quota-summary-pct{font-variant-numeric:tabular-nums;font-weight:600}.quota-summary-flag{width:14px;height:14px;color:var(--bg);font-size:var(--text-micro);border-radius:50%;place-items:center;font-weight:700;display:inline-grid}.quota-summary-item--warn .quota-summary-chip{background:var(--amber-soft)}.quota-summary-item--warn .quota-summary-pct{color:var(--amber)}.quota-summary-item--warn .quota-summary-flag{background:var(--amber)}.quota-summary-item--critical .quota-summary-chip{border-color:var(--red);background:var(--red-soft)}.quota-summary-item--critical .quota-summary-pct{color:var(--red)}.quota-summary-item--critical .quota-summary-flag{background:var(--red)}.quota-summary-popover{top:calc(var(--qs-pop-top,0) * 1px);left:calc(var(--qs-pop-left,0) * 1px);z-index:var(--z-popover);border:1px solid var(--border);background:var(--surface);border-radius:8px;min-width:260px;max-width:calc(100% - 16px);padding:10px 12px;position:fixed;box-shadow:0 8px 24px #00000024}.quota-summary-popover:before{content:"";left:calc(var(--qs-bridge-left,0) * 1px - 1px);right:calc(var(--qs-bridge-right,0) * 1px - 1px);height:calc((var(--qs-pop-gap,4) + 1) * 1px);position:absolute;bottom:100%}.quota-summary-popover-head{justify-content:space-between;align-items:center;gap:12px;margin-bottom:6px;display:flex}.quota-summary-badge{font-size:var(--text-caption);border-radius:999px;padding:1px 6px}.quota-summary-badge--warn{color:var(--amber);background:var(--amber-soft)}.quota-summary-badge--critical{color:var(--red);background:var(--red-soft)}.quota-summary-table{border-collapse:collapse;width:100%}.quota-summary-table th,.quota-summary-table td{text-align:left;white-space:nowrap;padding:3px 0;font-weight:400}.quota-summary-table td.quota-summary-row-pct{font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap;padding:3px 12px;font-weight:600}.quota-summary-row-reset{color:var(--muted);white-space:nowrap}.quota-summary-table th[scope=row]{white-space:normal;overflow-wrap:anywhere}.quota-summary-row--warn .quota-summary-row-pct{color:var(--amber)}.quota-summary-row--critical .quota-summary-row-pct{color:var(--red)}.quota-summary-popover-foot{color:var(--muted);font-size:var(--text-caption);flex-wrap:wrap;justify-content:space-between;gap:4px 12px;margin-top:6px;display:flex}.quota-summary-updated{color:var(--muted);font-size:var(--text-caption);white-space:nowrap;flex-shrink:0}.quota-summary-popover-link{color:var(--text);text-underline-offset:2px;text-decoration:underline}.quota-summary-popover-link:focus-visible{outline:2px solid var(--text);outline-offset:1px}.quota-summary-updated--stale{color:var(--amber)}.main:has(>.quota-summary-bar):has(>.main-inner--combos .combos-workspace-shell){flex-direction:column;height:100dvh;display:flex}.main:has(>.quota-summary-bar)>.main-inner.main-inner--combos:has(.combos-workspace-shell){flex:auto;height:auto;min-height:0}@media (width<=760px){.quota-summary-bar{padding:4px 10px;position:static}.quota-summary-popover{top:calc(var(--qs-pop-top,0) * 1px);min-width:0;left:8px;right:8px}.main:has(>.quota-summary-bar):has(>.main-inner--combos .combos-workspace-shell){height:100%;min-height:0}}.app{--titlebar-h:40px;--tl-inset:80px;--chrome-clear:52px}.app--macos{--chrome-clear:124px;--sidebar-column:max(232px, calc(var(--tl-inset) + 52px))}.sidebar-top{z-index:calc(var(--z-overlay,30) + 1);width:232px;height:var(--titlebar-h,40px);border-bottom:1px solid var(--border);background:var(--glass-rail);-webkit-backdrop-filter:var(--glass-blur);-webkit-user-select:none;user-select:none;align-items:center;padding:0 10px 0 14px;display:flex;position:fixed;top:0;left:0}.app--macos .sidebar-top{width:var(--sidebar-column);padding-left:var(--tl-inset,80px)}.sidebar{padding-top:calc(var(--titlebar-h,40px) + 18px)}.sidebar-collapse{border-radius:var(--radius-sm);width:28px;height:28px;color:var(--muted);cursor:pointer;transition:background var(--motion-fast), color var(--motion-fast);background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.sidebar-collapse:hover{background:var(--accent-soft);color:var(--text)}.sidebar-collapse:focus-visible{outline:2px solid var(--accent-ring);outline-offset:2px}.sidebar-collapse svg{width:18px;height:18px}.main-top{z-index:var(--z-sticky);height:var(--titlebar-h,40px);background:var(--bg);border-bottom:1px solid var(--border);-webkit-user-select:none;user-select:none;align-items:stretch;display:flex;position:sticky;top:0}.main-top>.quota-summary-bar{border-bottom:none;flex:auto;min-width:0;min-height:0;padding:0 16px;position:static}.main:has(>.main-top):has(>.main-inner--combos .combos-workspace-shell){flex-direction:column;height:100dvh;display:flex}.main:has(>.main-top)>.main-inner.main-inner--combos:has(.combos-workspace-shell){flex:auto;height:auto;min-height:0}@media (width>=761px){.app{transition:grid-template-columns .16s}.app--macos.app--reduced-zoom{transition:none}.app--macos:not(.app--nav-collapsed){grid-template-columns:var(--sidebar-column) minmax(0, 1fr)}.app.app--nav-collapsed{grid-template-columns:0 1fr}.app--nav-collapsed .sidebar{display:none}.app--nav-collapsed .main{grid-column:2}.app--nav-collapsed .sidebar-top{-webkit-backdrop-filter:none;background:0 0;border-bottom:none;width:auto;margin:0;padding:0 12px}.app--macos.app--nav-collapsed .sidebar-top{padding-left:var(--tl-inset,80px)}.app--nav-collapsed .main-top,.app--nav-collapsed .main>.quota-summary-bar{padding-left:var(--chrome-clear,52px)}}@media (width<=760px){.sidebar-top{display:none}.main-top{z-index:auto;position:static}.main:has(>.main-top):has(>.main-inner--combos .combos-workspace-shell){height:100%;min-height:0}.app--macos .mobile-topbar{padding-left:var(--tl-inset,80px)}.app--macos .sidebar.open{padding-top:calc(var(--titlebar-h,40px) + 18px)}}@media (width<=320px){.app--macos .mobile-topbar{flex-wrap:wrap}.app--macos .mobile-topbar-actions{width:calc(100% + var(--tl-inset,80px));margin-left:calc(-1 * var(--tl-inset,80px));justify-content:flex-end}}