anygate 0.6.0 → 0.6.2

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.
@@ -13,11 +13,11 @@ import {
13
13
  VERSION,
14
14
  VERTEX_ANTHROPIC_NPM,
15
15
  classifyModelFormat
16
- } from "./chunk-QLHVQYQN.js";
16
+ } from "./chunk-S5WL3M5G.js";
17
17
  import {
18
18
  getTemplateById,
19
19
  listAddableTemplates
20
- } from "./chunk-VGM6EBG4.js";
20
+ } from "./chunk-4N4RDHGZ.js";
21
21
 
22
22
  // src/apps/shared/ui.ts
23
23
  import pc from "picocolors";
@@ -156,13 +156,19 @@ async function pollOpenAiDeviceCodeToken(deviceData, opts) {
156
156
  }).toString()
157
157
  });
158
158
  if (!tokenResponse.ok) {
159
- throw new Error(`OpenAI token exchange failed (${tokenResponse.status})`);
159
+ const detail = await tokenResponse.text().catch(() => "");
160
+ throw new Error(
161
+ `OpenAI token exchange failed (${tokenResponse.status})${detail.trim() ? `: ${detail.replace(/\s+/g, " ").trim().slice(0, 200)}` : ""}`
162
+ );
160
163
  }
161
164
  const tokens = await tokenResponse.json();
162
165
  return { tokens, accountId: extractOpenAiAccountId(tokens) };
163
166
  }
164
167
  if (response.status !== 403 && response.status !== 404) {
165
- throw new Error(`OpenAI device authorization failed (${response.status})`);
168
+ const detail = await response.text().catch(() => "");
169
+ throw new Error(
170
+ `OpenAI device authorization failed (${response.status})${detail.trim() ? `: ${detail.replace(/\s+/g, " ").trim().slice(0, 200)}` : ""}`
171
+ );
166
172
  }
167
173
  await sleep(
168
174
  Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, Math.max(0, deadline - now()))
@@ -2548,6 +2554,7 @@ function loadPreferences() {
2548
2554
  antigravityCliFavoriteModels: config.antigravityCliFavoriteModels,
2549
2555
  antigravityCliFavoritesHintShown: config.antigravityCliFavoritesHintShown,
2550
2556
  appPathOverrides: config.appPathOverrides,
2557
+ launchPresets: config.launchPresets,
2551
2558
  recentLaunchFolders: config.recentLaunchFolders,
2552
2559
  server: config.server
2553
2560
  };
@@ -2577,6 +2584,19 @@ function savePreferences(prefs) {
2577
2584
  config.recentLaunchFolders = prefs.recentLaunchFolders;
2578
2585
  writeConfig(config);
2579
2586
  }
2587
+ var MAX_LAUNCH_PRESETS = 50;
2588
+ function loadLaunchPresets() {
2589
+ const presets = readConfig().launchPresets;
2590
+ return Array.isArray(presets) ? presets : [];
2591
+ }
2592
+ function saveLaunchPresets(presets) {
2593
+ const config = readConfig();
2594
+ const next = presets.slice(0, MAX_LAUNCH_PRESETS);
2595
+ if (next.length === 0) delete config.launchPresets;
2596
+ else config.launchPresets = next;
2597
+ writeConfig(config);
2598
+ return next;
2599
+ }
2580
2600
  function getAppPathOverride(appId) {
2581
2601
  const value = loadPreferences().appPathOverrides?.[appId];
2582
2602
  return typeof value === "string" && value.trim() ? value : void 0;
@@ -2801,6 +2821,14 @@ var PROVIDER_DEFAULTS = {
2801
2821
  "xai-oauth": 131072,
2802
2822
  "openai-oauth": 128e3
2803
2823
  };
2824
+ var SERVER_CONFIGURED_CONTEXT_PROVIDERS = /* @__PURE__ */ new Set(["ollama", "lmstudio"]);
2825
+ var OLLAMA_DEFAULT_CONTEXT_LENGTH = 4096;
2826
+ function serverConfiguredContextWindow(providerId) {
2827
+ if (!SERVER_CONFIGURED_CONTEXT_PROVIDERS.has(providerId)) return void 0;
2828
+ const fromEnv = Number(process.env.OLLAMA_CONTEXT_LENGTH?.trim());
2829
+ if (Number.isFinite(fromEnv) && fromEnv > 0) return fromEnv;
2830
+ return PROVIDER_DEFAULTS[providerId] ?? OLLAMA_DEFAULT_CONTEXT_LENGTH;
2831
+ }
2804
2832
  var parsedCache;
2805
2833
  var cacheIndex;
2806
2834
  var heuristicCache = /* @__PURE__ */ new Map();
@@ -2885,6 +2913,10 @@ function contextWindowFromHeuristics(modelId) {
2885
2913
  return DEFAULT_CONTEXT_WINDOW;
2886
2914
  }
2887
2915
  function lookupContextWindow(modelId, providerId) {
2916
+ if (providerId) {
2917
+ const fromServer = serverConfiguredContextWindow(providerId);
2918
+ if (fromServer) return fromServer;
2919
+ }
2888
2920
  const fromCache = getCacheIndex().get(modelId);
2889
2921
  if (fromCache) return fromCache;
2890
2922
  const fromModelsDev = getModelsDevIndex().get(modelId);
@@ -2904,7 +2936,7 @@ function resolveContextWindow(modelId, explicit, providerId) {
2904
2936
  // src/auth/github.ts
2905
2937
  var CLIENT_ID2 = "Iv1.b507a08c87ecfe98";
2906
2938
  var DEVICE_CODE_URL = "https://github.com/login/device/code";
2907
- var TOKEN_URL = "https://github.com/login/auth/access_token";
2939
+ var TOKEN_URL = "https://github.com/login/oauth/access_token";
2908
2940
  var COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
2909
2941
  var SCOPE = "copilot";
2910
2942
  var DEVICE_CODE_DEFAULT_INTERVAL_MS = 5e3;
@@ -2989,8 +3021,20 @@ async function pollGithubDeviceCodeToken(device, opts) {
2989
3021
  grant_type: "urn:ietf:params:oauth:grant-type:device_code"
2990
3022
  }).toString()
2991
3023
  });
2992
- const body = await response.json().catch(() => ({}));
3024
+ const raw = await response.text().catch(() => "");
3025
+ let body = {};
3026
+ try {
3027
+ if (raw.trim().startsWith("{")) body = JSON.parse(raw);
3028
+ } catch {
3029
+ }
2993
3030
  const error = body["error"];
3031
+ if (!error && !body["access_token"]) {
3032
+ if (!raw.trim().startsWith("{")) {
3033
+ throw new Error(
3034
+ `GitHub device authorization got a non-JSON response (HTTP ${response.status}) from ${TOKEN_URL}${raw.trim() ? `: ${raw.replace(/\s+/g, " ").trim().slice(0, 200)}` : ""}`
3035
+ );
3036
+ }
3037
+ }
2994
3038
  if (!error && body["access_token"]) {
2995
3039
  const ghuToken = body["access_token"];
2996
3040
  const copilot = await exchangeForCopilotToken(ghuToken);
@@ -3087,7 +3131,14 @@ async function pollXaiDeviceCodeToken(device, opts) {
3087
3131
  }).toString()
3088
3132
  });
3089
3133
  if (response.ok) return response.json();
3090
- const body = await response.json().catch(() => ({}));
3134
+ const raw = await response.text().catch(() => "");
3135
+ let body = {};
3136
+ try {
3137
+ if (raw.trim().startsWith("{")) {
3138
+ body = JSON.parse(raw);
3139
+ }
3140
+ } catch {
3141
+ }
3091
3142
  const remaining = Math.max(0, deadline - now());
3092
3143
  if (body.error === "authorization_pending") {
3093
3144
  await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS3, remaining));
@@ -3098,7 +3149,16 @@ async function pollXaiDeviceCodeToken(device, opts) {
3098
3149
  await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS3, remaining));
3099
3150
  continue;
3100
3151
  }
3101
- throw new Error(`xAI device authorization failed${body.error ? `: ${body.error}` : ""}`);
3152
+ if (body.error === "expired_token") {
3153
+ throw new Error("xAI device code expired \u2014 run anygate providers auth xai again");
3154
+ }
3155
+ if (body.error) {
3156
+ const detail = body.error_description ? ` \u2014 ${body.error_description}` : "";
3157
+ throw new Error(`xAI device authorization failed: ${body.error}${detail}`);
3158
+ }
3159
+ throw new Error(
3160
+ `xAI device authorization failed (HTTP ${response.status})${raw.trim() ? `: ${raw.replace(/\s+/g, " ").trim().slice(0, 200)}` : ""}`
3161
+ );
3102
3162
  }
3103
3163
  throw new Error("xAI device authorization timed out");
3104
3164
  }
@@ -3808,6 +3868,7 @@ function buildChildEnv(baseUrl, model, apiKey, proxyPort, contextWindow, enableG
3808
3868
  }
3809
3869
  env["ANTHROPIC_BASE_URL"] = proxyPort ? `http://127.0.0.1:${proxyPort}` : baseUrl;
3810
3870
  env["ANTHROPIC_API_KEY"] = apiKey;
3871
+ env["ANTHROPIC_AUTH_TOKEN"] = apiKey;
3811
3872
  const bareModel = stripOneMContextSuffix(model);
3812
3873
  env["ANTHROPIC_MODEL"] = claudeCodeClientModelId(model, contextWindow);
3813
3874
  env["CLAUDE_CODE_MAX_CONTEXT_TOKENS"] = String(resolveContextWindow(bareModel, contextWindow));
@@ -4993,7 +5054,7 @@ function parseModelList(body, npm, providerId) {
4993
5054
  const freeStatus = classifyFreeStatus({
4994
5055
  model: { cost, isFree: row.isFree }
4995
5056
  });
4996
- const contextWindow = row.context_length ?? row.contextWindow ?? row.context_window ?? resolveContextWindow(id);
5057
+ const contextWindow = row.context_length ?? row.contextWindow ?? row.context_window ?? resolveContextWindow(id, void 0, providerId);
4997
5058
  models.push({
4998
5059
  id,
4999
5060
  name: normalizeGoogleDisplayName(row.name, id),
@@ -5034,7 +5095,7 @@ async function fetchTemplateModels(template, apiKey, baseUrlOverride, extraHeade
5034
5095
  upstreamModelId: sm.id,
5035
5096
  family,
5036
5097
  brand: deriveBrand(family),
5037
- contextWindow: resolveContextWindow(sm.id),
5098
+ contextWindow: resolveContextWindow(sm.id, void 0, template.id),
5038
5099
  modelFormat: modelFormatForNpm(template.npm),
5039
5100
  npm: template.npm
5040
5101
  };
@@ -7194,16 +7255,51 @@ async function generateAnthropicResponse(model, params, modelId, options) {
7194
7255
  }
7195
7256
 
7196
7257
  // src/storage/analytics.ts
7197
- import { appendFileSync, openSync as openSync3, writeSync as writeSync3, closeSync as closeSync3, readFileSync as readFileSync11, existsSync as existsSync8 } from "fs";
7198
- import { join as join8 } from "path";
7258
+ import {
7259
+ appendFileSync,
7260
+ openSync as openSync3,
7261
+ writeSync as writeSync3,
7262
+ closeSync as closeSync3,
7263
+ readFileSync as readFileSync11,
7264
+ existsSync as existsSync8,
7265
+ mkdirSync as mkdirSync8
7266
+ } from "fs";
7267
+ import { join as join8, dirname as dirname5 } from "path";
7268
+
7269
+ // src/services/event-bus.ts
7270
+ var listeners = /* @__PURE__ */ new Set();
7271
+ function subscribeToAppEvents(listener) {
7272
+ listeners.add(listener);
7273
+ return () => {
7274
+ listeners.delete(listener);
7275
+ };
7276
+ }
7277
+ function emitAppEvent(event) {
7278
+ for (const listener of listeners) {
7279
+ try {
7280
+ listener(event);
7281
+ } catch {
7282
+ }
7283
+ }
7284
+ }
7285
+
7286
+ // src/storage/analytics.ts
7199
7287
  var ANALYTICS_FILE = "analytics.jsonl";
7200
7288
  function normalizeModelKey(modelId) {
7201
7289
  return modelId.toLowerCase().replace(/\//g, ":").replace(/\s*\([^)]*\)\s*$/g, "").replace(/\s+/g, " ").trim();
7202
7290
  }
7291
+ function normalizeAppKey(app) {
7292
+ const key = app.trim().toLowerCase().replace(/\s+/g, "-");
7293
+ return key || "unknown";
7294
+ }
7203
7295
  function analyticsPath() {
7204
7296
  return join8(getAppHome(), ANALYTICS_FILE);
7205
7297
  }
7206
7298
  function appendAtomic(path, line) {
7299
+ try {
7300
+ mkdirSync8(dirname5(path), { recursive: true, mode: 448 });
7301
+ } catch {
7302
+ }
7207
7303
  try {
7208
7304
  const fd = openSync3(path, "a", 384);
7209
7305
  try {
@@ -7233,6 +7329,18 @@ function recordUsage(event) {
7233
7329
  if (event.npm) clean.npm = event.npm;
7234
7330
  if (event.providerId) clean.providerId = event.providerId;
7235
7331
  appendAtomic(analyticsPath(), JSON.stringify(clean));
7332
+ try {
7333
+ emitAppEvent({
7334
+ type: "usage",
7335
+ app: clean.app,
7336
+ modelId: clean.modelId,
7337
+ ...clean.providerId ? { providerId: clean.providerId } : {},
7338
+ inputTokens: clean.inputTokens,
7339
+ outputTokens: clean.outputTokens,
7340
+ ts: clean.ts
7341
+ });
7342
+ } catch {
7343
+ }
7236
7344
  }
7237
7345
  function readAnalyticsLog() {
7238
7346
  const path = analyticsPath();
@@ -7293,11 +7401,22 @@ function aggregateAnalytics(range) {
7293
7401
  const modelMap = /* @__PURE__ */ new Map();
7294
7402
  let totalTokens = 0;
7295
7403
  let messages = 0;
7404
+ let totalInputTokens = 0;
7405
+ let totalOutputTokens = 0;
7406
+ const appMap = /* @__PURE__ */ new Map();
7296
7407
  for (const e of events) {
7297
7408
  const day = dayKey(e.ts);
7298
7409
  const tok = e.inputTokens + e.outputTokens;
7299
7410
  totalTokens += tok;
7411
+ totalInputTokens += e.inputTokens;
7412
+ totalOutputTokens += e.outputTokens;
7300
7413
  messages += 1;
7414
+ const appKey = normalizeAppKey(e.app || "unknown");
7415
+ const a = appMap.get(appKey) ?? { inputTokens: 0, outputTokens: 0, messages: 0 };
7416
+ a.inputTokens += e.inputTokens;
7417
+ a.outputTokens += e.outputTokens;
7418
+ a.messages += 1;
7419
+ appMap.set(appKey, a);
7301
7420
  eventsByDay.set(day, (eventsByDay.get(day) ?? 0) + 1);
7302
7421
  tokensByDay.set(day, (tokensByDay.get(day) ?? 0) + tok);
7303
7422
  activeDaySet.add(day);
@@ -7366,14 +7485,14 @@ function aggregateAnalytics(range) {
7366
7485
  }
7367
7486
  const models = [...modelMap.entries()].map(([, m], idx) => {
7368
7487
  const share = totalTokens > 0 ? (m.inputTokens + m.outputTokens) / totalTokens : 0;
7369
- const apps = [...m.apps];
7488
+ const apps2 = [...m.apps];
7370
7489
  return {
7371
7490
  provider: m.provider,
7372
7491
  model: m.model,
7373
7492
  tier: "",
7374
7493
  // source tier isn't tracked in the log; UI shows it from catalog elsewhere
7375
- app: apps[0] ?? m.app,
7376
- apps,
7494
+ app: apps2[0] ?? m.app,
7495
+ apps: apps2,
7377
7496
  inputTokens: m.inputTokens,
7378
7497
  outputTokens: m.outputTokens,
7379
7498
  share,
@@ -7382,19 +7501,31 @@ function aggregateAnalytics(range) {
7382
7501
  });
7383
7502
  models.sort((a, b) => b.share - a.share);
7384
7503
  const favoriteModel = models.length > 0 ? `${models[0].provider}: ${models[0].model}` : "";
7504
+ const apps = [...appMap.entries()].map(([app, a], idx) => ({
7505
+ app,
7506
+ inputTokens: a.inputTokens,
7507
+ outputTokens: a.outputTokens,
7508
+ messages: a.messages,
7509
+ share: totalTokens > 0 ? (a.inputTokens + a.outputTokens) / totalTokens : 0,
7510
+ color: MODEL_PALETTE[idx % MODEL_PALETTE.length]
7511
+ })).sort((x, y) => y.share - x.share);
7385
7512
  return {
7386
7513
  range,
7387
7514
  sessions: activeDaySet.size,
7388
7515
  messages,
7389
7516
  totalTokens,
7517
+ inputTokens: totalInputTokens,
7518
+ outputTokens: totalOutputTokens,
7390
7519
  activeDays: activeDaySet.size,
7391
7520
  currentStreakDays: currentStreak,
7392
7521
  longestStreakDays: longestStreak,
7393
7522
  peakHour,
7523
+ hourly: hourCounts,
7394
7524
  favoriteModel,
7395
7525
  heatmap,
7396
7526
  dailyTokens,
7397
- models
7527
+ models,
7528
+ apps
7398
7529
  };
7399
7530
  }
7400
7531
 
@@ -7461,8 +7592,9 @@ function lookupRoute(byAlias, id) {
7461
7592
  }
7462
7593
  return void 0;
7463
7594
  }
7464
- function startProxyCatalog(routes, defaultAliasId, debug = false) {
7595
+ function startProxyCatalog(routes, defaultAliasId, debug = false, opts) {
7465
7596
  const proxyToken = randomUUID5();
7597
+ const defaultApp = opts?.app;
7466
7598
  silenceSdkWarnings();
7467
7599
  if (routes.length === 0) {
7468
7600
  return Promise.reject(new Error("Proxy catalog requires at least one route"));
@@ -7654,7 +7786,7 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
7654
7786
  modelId: route.realModelId,
7655
7787
  npm: route.npm,
7656
7788
  providerId: route.providerId,
7657
- app: route.app ?? "gateway",
7789
+ app: route.app ?? defaultApp ?? "gateway",
7658
7790
  inputTokens: usage.inputTokens,
7659
7791
  outputTokens: usage.outputTokens
7660
7792
  });
@@ -7672,7 +7804,7 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
7672
7804
  modelId: route.realModelId,
7673
7805
  npm: route.npm,
7674
7806
  providerId: route.providerId,
7675
- app: route.app ?? "gateway",
7807
+ app: route.app ?? defaultApp ?? "gateway",
7676
7808
  inputTokens: u?.inputTokens ?? 0,
7677
7809
  outputTokens: u?.outputTokens ?? 0
7678
7810
  });
@@ -7763,7 +7895,7 @@ data: ${JSON.stringify({ type: "error", error: { type: errorType, message } })}
7763
7895
  ts: (/* @__PURE__ */ new Date()).toISOString(),
7764
7896
  modelId: route.realModelId,
7765
7897
  providerId: route.providerId,
7766
- app: route.app ?? "Antigravity",
7898
+ app: route.app ?? defaultApp ?? "Antigravity",
7767
7899
  inputTokens: usage.inputTokens,
7768
7900
  outputTokens: usage.outputTokens
7769
7901
  });
@@ -7832,6 +7964,7 @@ function startProxy(completionsUrl, modelId, debug = false, contextWindow, sdk,
7832
7964
  interleavedReasoningField: sdk?.interleavedReasoningField,
7833
7965
  useResponsesLite: sdk?.useResponsesLite,
7834
7966
  preferWebSockets: sdk?.preferWebSockets,
7967
+ headers: sdk?.headers,
7835
7968
  app: sdk?.app
7836
7969
  }
7837
7970
  ],
@@ -8018,7 +8151,7 @@ function cachedModelToLocal(cached, provider) {
8018
8151
  brand: cached.brand ?? deriveBrand(cached.family ?? ""),
8019
8152
  modelFormat: "cloud-code",
8020
8153
  upstreamModelId: cached.upstreamModelId ?? cached.id,
8021
- contextWindow: cached.contextWindow ?? resolveContextWindow(id2),
8154
+ contextWindow: cached.contextWindow ?? resolveContextWindow(id2, void 0, provider.id),
8022
8155
  isFree: isFreeStatus(freeStatus),
8023
8156
  freeStatus,
8024
8157
  reasoning: cached.reasoning,
@@ -8050,7 +8183,7 @@ function cachedModelToLocal(cached, provider) {
8050
8183
  cost: cached.cost,
8051
8184
  isFree: isFreeStatus(freeStatus),
8052
8185
  freeStatus,
8053
- contextWindow: cached.contextWindow ?? resolveContextWindow(id),
8186
+ contextWindow: cached.contextWindow ?? resolveContextWindow(id, void 0, provider.id),
8054
8187
  supportedParameters: cached.supportedParameters,
8055
8188
  reasoning: cached.reasoning ?? modelsDev?.reasoning,
8056
8189
  interleavedReasoningField: cached.interleavedReasoningField ?? modelsDev?.interleaved?.field,
@@ -8062,6 +8195,11 @@ function providerAllowsAnonymousFreeModels(provider) {
8062
8195
  const template = getTemplateById(provider.templateId) ?? getTemplateById(provider.id);
8063
8196
  return template?.anonymousFreeModels === true;
8064
8197
  }
8198
+ function providerAllowsMissingKey(provider) {
8199
+ if (provider.authType === "none") return true;
8200
+ const template = getTemplateById(provider.templateId) ?? getTemplateById(provider.id);
8201
+ return template?.apiKeyOptional === true;
8202
+ }
8065
8203
  function materializeOne(provider, resolveCredential, agent) {
8066
8204
  if (!provider.enabled) return null;
8067
8205
  if (!isValidProviderId(provider.id)) return null;
@@ -8082,7 +8220,7 @@ function materializeOne(provider, resolveCredential, agent) {
8082
8220
  models.push(model);
8083
8221
  }
8084
8222
  if (models.length === 0) return null;
8085
- if (!apiKey.trim() && !anonymousFreeOnly) return null;
8223
+ if (!apiKey.trim() && !anonymousFreeOnly && !providerAllowsMissingKey(provider)) return null;
8086
8224
  return {
8087
8225
  id: provider.id,
8088
8226
  name: provider.name,
@@ -8294,6 +8432,10 @@ function makeRouteResolver(localProviders) {
8294
8432
  return provider && model ? localModelToRoute(provider, model) ?? void 0 : void 0;
8295
8433
  };
8296
8434
  }
8435
+ function buildProviderAllModelRoutes(provider, startingRoute, resolveRoute2, max = MAX_MODEL_CATALOG) {
8436
+ const tail = provider.models.map((model) => resolveRoute2(provider.id, model.id)).filter((route) => route !== void 0).filter((route) => route.aliasId !== startingRoute.aliasId);
8437
+ return dedupeByKey([startingRoute, ...tail], (route) => route.aliasId, max);
8438
+ }
8297
8439
  function buildCatalogRoutes(startingRoute, favorites, resolveRoute2, max = MAX_MODEL_CATALOG) {
8298
8440
  const droppedFavorites = [];
8299
8441
  const tail = favorites.map((fav) => {
@@ -8651,9 +8793,9 @@ async function addCustomEndpointProvider(input) {
8651
8793
 
8652
8794
  // src/registry/storage/builtins.ts
8653
8795
  import { readFileSync as readFileSync12 } from "fs";
8654
- import { join as join9, dirname as dirname5 } from "path";
8796
+ import { join as join9, dirname as dirname6 } from "path";
8655
8797
  import { fileURLToPath } from "url";
8656
- var __dirname = dirname5(fileURLToPath(import.meta.url));
8798
+ var __dirname = dirname6(fileURLToPath(import.meta.url));
8657
8799
  var PROVIDERS_DIR = join9(__dirname, "..", "data", "providers");
8658
8800
  function loadBuiltinProviderSync(id) {
8659
8801
  try {
@@ -9892,12 +10034,22 @@ function oauthDisplayName(registryId, fallbackName) {
9892
10034
  if (registryId === "xai-oauth") return "xAI (SuperGrok)";
9893
10035
  return fallbackName;
9894
10036
  }
10037
+ function resolveOAuthTemplate(providerId) {
10038
+ const stripped = providerId.replace(/-oauth$/, "") || providerId;
10039
+ const strippedTemplate = getTemplateById(stripped);
10040
+ if (strippedTemplate) return { templateId: stripped, template: strippedTemplate };
10041
+ const exact = getTemplateById(providerId);
10042
+ if (exact) return { templateId: providerId, template: exact };
10043
+ const registryId = toOAuthRegistryId(providerId);
10044
+ const viaRegistryId = getTemplateById(registryId);
10045
+ if (viaRegistryId) return { templateId: registryId, template: viaRegistryId };
10046
+ return { templateId: stripped, template: void 0 };
10047
+ }
9895
10048
  async function upsertOAuthProvider(providerId, cred) {
9896
10049
  const registryId = toOAuthRegistryId(providerId);
9897
- const templateId = providerId.replace(/-oauth$/, "") || providerId;
10050
+ const { templateId, template } = resolveOAuthTemplate(providerId);
9898
10051
  const registry = loadRegistry();
9899
10052
  const authRef = oauthAuthRef(registryId);
9900
- const template = getTemplateById(templateId);
9901
10053
  let entry = registry.providers.find((pr) => pr.id === registryId);
9902
10054
  if (!entry) {
9903
10055
  const raw = await fetchRawOpencodeProviders();
@@ -10173,10 +10325,7 @@ function createVertexModelCatalog(models) {
10173
10325
  }
10174
10326
 
10175
10327
  // src/apps/codex/app-launch.ts
10176
- import { execSync as execSync4 } from "child_process";
10177
10328
  import { existsSync as existsSync14 } from "fs";
10178
- import { homedir as homedir8 } from "os";
10179
- import { join as join14 } from "path";
10180
10329
 
10181
10330
  // src/apps/shared/app-launcher.ts
10182
10331
  import { execSync as execSync3, spawn as spawn4 } from "child_process";
@@ -10442,6 +10591,24 @@ var CodexAppLauncher = class extends AppLauncher {
10442
10591
  return null;
10443
10592
  }
10444
10593
  }
10594
+ /**
10595
+ * Find a Microsoft Store (MSIX) install via Get-StartApps. Store installs have
10596
+ * no .exe at any fixed path, so the static winInstallBases search cannot see
10597
+ * them. Returns a version-independent shell:AppsFolder moniker, which
10598
+ * AppLauncher.openApp() launches via `cmd /c start`.
10599
+ */
10600
+ findWinAppExtra() {
10601
+ for (const name of this.winAppNames) {
10602
+ try {
10603
+ const appId = this.runPowerShell(
10604
+ `(Get-StartApps | Where-Object { $_.Name -eq '${name}' -or $_.Name -like '${name}*' } | Select-Object -First 1 -ExpandProperty AppID)`
10605
+ );
10606
+ if (appId) return `shell:AppsFolder\\${appId}`;
10607
+ } catch {
10608
+ }
10609
+ }
10610
+ return null;
10611
+ }
10445
10612
  winQuitGracefulCommand() {
10446
10613
  const nameFilter = this.winAppNames.map((name) => `'${name}'`).join(",");
10447
10614
  return `Get-Process ${nameFilter} -ErrorAction SilentlyContinue | Where-Object { $_.MainWindowHandle -ne 0 } | ForEach-Object { [void]$_.CloseMainWindow() }`;
@@ -10462,38 +10629,7 @@ function codexAppSupported() {
10462
10629
  }
10463
10630
  }
10464
10631
  function findCodexApp() {
10465
- if (process.platform === "darwin") {
10466
- for (const bundleName of launcher.darwinAppBundleNames) {
10467
- const paths = [`/Applications/${bundleName}`, join14(homedir8(), "Applications", bundleName)];
10468
- for (const path of paths) {
10469
- if (existsSync14(path)) return path;
10470
- }
10471
- }
10472
- try {
10473
- const out = execSync4(`mdfind "kMDItemCFBundleIdentifier == '${CODEX_BUNDLE_ID}'"`, {
10474
- encoding: "utf8",
10475
- stdio: ["pipe", "pipe", "pipe"]
10476
- }).trim();
10477
- const first = out.split("\n").map((l) => l.trim()).find(Boolean);
10478
- if (first && existsSync14(first)) return first;
10479
- } catch {
10480
- }
10481
- }
10482
- if (process.platform === "win32") {
10483
- const localAppData = process.env.LOCALAPPDATA ?? join14(homedir8(), "AppData", "Local");
10484
- for (const base of launcher.winInstallBases) {
10485
- for (const exe of launcher.winExeNames) {
10486
- const paths = [join14(localAppData, "Programs", base, exe), join14(localAppData, base, exe)];
10487
- for (const path of paths) {
10488
- try {
10489
- if (existsSync14(path)) return path;
10490
- } catch {
10491
- }
10492
- }
10493
- }
10494
- }
10495
- }
10496
- return null;
10632
+ return launcher.findApp();
10497
10633
  }
10498
10634
  function isCodexAppRunning() {
10499
10635
  return launcher.isRunning();
@@ -10987,7 +11123,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
10987
11123
  modelId: responseModelId,
10988
11124
  npm: model.npm,
10989
11125
  providerId: model.providerId,
10990
- app: "gateway",
11126
+ app: options.app ?? "gateway",
10991
11127
  inputTokens: usage.inputTokens,
10992
11128
  outputTokens: usage.outputTokens
10993
11129
  });
@@ -11003,7 +11139,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
11003
11139
  modelId: responseModelId,
11004
11140
  npm: model.npm,
11005
11141
  providerId: model.providerId,
11006
- app: "gateway",
11142
+ app: options.app ?? "gateway",
11007
11143
  inputTokens: anthropicResponse._usage?.inputTokens ?? 0,
11008
11144
  outputTokens: anthropicResponse._usage?.outputTokens ?? 0
11009
11145
  });
@@ -11089,7 +11225,7 @@ async function handleOpenAIChatCompletions(req, res, options, modelCache, plog)
11089
11225
  modelId: responseModelId,
11090
11226
  npm: model.npm ?? (model.modelFormat === "anthropic" ? "@ai-sdk/anthropic" : void 0),
11091
11227
  providerId: model.providerId,
11092
- app: "gateway",
11228
+ app: options.app ?? "gateway",
11093
11229
  inputTokens: usage.inputTokens,
11094
11230
  outputTokens: usage.outputTokens
11095
11231
  });
@@ -11105,7 +11241,7 @@ async function handleOpenAIChatCompletions(req, res, options, modelCache, plog)
11105
11241
  modelId: responseModelId,
11106
11242
  npm: model.npm ?? (model.modelFormat === "anthropic" ? "@ai-sdk/anthropic" : void 0),
11107
11243
  providerId: model.providerId,
11108
- app: "gateway",
11244
+ app: options.app ?? "gateway",
11109
11245
  inputTokens: usage.inputTokens,
11110
11246
  outputTokens: usage.outputTokens
11111
11247
  });
@@ -11239,10 +11375,7 @@ function summarizeServerProviders(models) {
11239
11375
  }
11240
11376
 
11241
11377
  // src/apps/claude/desktop-launch.ts
11242
- import { execSync as execSync5 } from "child_process";
11243
11378
  import { existsSync as existsSync15 } from "fs";
11244
- import { homedir as homedir9 } from "os";
11245
- import { join as join15 } from "path";
11246
11379
  var CLAUDE_BUNDLE_ID = "com.anthropic.claudefordesktop";
11247
11380
  var ClaudeAppLauncher = class extends AppLauncher {
11248
11381
  appName = "Claude Desktop";
@@ -11284,40 +11417,7 @@ function claudeAppSupported() {
11284
11417
  }
11285
11418
  }
11286
11419
  function findClaudeApp() {
11287
- const override = getAppPathOverride("claude-app");
11288
- if (override && existsSync15(override)) return override;
11289
- if (process.platform === "darwin") {
11290
- for (const bundleName of launcher2.darwinAppBundleNames) {
11291
- const paths = [`/Applications/${bundleName}`, join15(homedir9(), "Applications", bundleName)];
11292
- for (const path of paths) {
11293
- if (existsSync15(path)) return path;
11294
- }
11295
- }
11296
- try {
11297
- const out = execSync5(`mdfind "kMDItemCFBundleIdentifier == '${CLAUDE_BUNDLE_ID}'"`, {
11298
- encoding: "utf8",
11299
- stdio: ["pipe", "pipe", "pipe"]
11300
- }).trim();
11301
- const first = out.split("\n").map((l) => l.trim()).find(Boolean);
11302
- if (first && existsSync15(first)) return first;
11303
- } catch {
11304
- }
11305
- }
11306
- if (process.platform === "win32") {
11307
- const localAppData = process.env.LOCALAPPDATA ?? join15(homedir9(), "AppData", "Local");
11308
- for (const base of launcher2.winInstallBases) {
11309
- for (const exe of launcher2.winExeNames) {
11310
- const paths = [join15(localAppData, "Programs", base, exe), join15(localAppData, base, exe)];
11311
- for (const path of paths) {
11312
- try {
11313
- if (existsSync15(path)) return path;
11314
- } catch {
11315
- }
11316
- }
11317
- }
11318
- }
11319
- }
11320
- return null;
11420
+ return launcher2.findApp();
11321
11421
  }
11322
11422
  function isClaudeAppRunning() {
11323
11423
  return launcher2.isRunning();
@@ -12065,6 +12165,8 @@ export {
12065
12165
  resolveInputTypes,
12066
12166
  loadPreferences,
12067
12167
  savePreferences,
12168
+ loadLaunchPresets,
12169
+ saveLaunchPresets,
12068
12170
  getAppPathOverride,
12069
12171
  setAppPathOverride,
12070
12172
  recordLaunchFolder,
@@ -12142,11 +12244,14 @@ export {
12142
12244
  encodeToolUseId,
12143
12245
  serializeToolResultContent,
12144
12246
  translateRequest,
12247
+ subscribeToAppEvents,
12248
+ emitAppEvent,
12145
12249
  recordUsage,
12146
12250
  aggregateAnalytics,
12147
12251
  aliasModelId,
12148
12252
  startProxyCatalog,
12149
12253
  startProxy,
12254
+ dedupeByKey,
12150
12255
  routableModelsForTarget,
12151
12256
  providersForTarget,
12152
12257
  fetchProviderCatalog,
@@ -12156,6 +12261,7 @@ export {
12156
12261
  resolveProvidersForDisplay,
12157
12262
  localProvidersToServerModels,
12158
12263
  makeRouteResolver,
12264
+ buildProviderAllModelRoutes,
12159
12265
  buildCatalogRoutes,
12160
12266
  findBinaryOnPath,
12161
12267
  findClaudeBinary,
@@ -12209,4 +12315,4 @@ export {
12209
12315
  runServerCommand,
12210
12316
  favoriteProviderDisplayName
12211
12317
  };
12212
- //# sourceMappingURL=chunk-CRK6YGKY.js.map
12318
+ //# sourceMappingURL=chunk-EMBABL33.js.map