claudish 7.30.0 → 7.31.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 (2) hide show
  1. package/dist/index.js +1034 -441
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -651,7 +651,7 @@ var init_onepassword_config = __esm(() => {
651
651
  });
652
652
 
653
653
  // src/version.ts
654
- var VERSION = "7.30.0";
654
+ var VERSION = "7.31.0";
655
655
 
656
656
  // src/logger.ts
657
657
  var exports_logger = {};
@@ -28218,6 +28218,25 @@ var init_provider_definitions = __esm(() => {
28218
28218
  isDirectApi: true,
28219
28219
  description: "Sakana Fugu Subscription (sc@)"
28220
28220
  },
28221
+ {
28222
+ name: "qwen-cloud",
28223
+ displayName: "Qwen Plan",
28224
+ transport: "anthropic",
28225
+ baseUrl: "https://token-plan.ap-southeast-1.maas.aliyuncs.com",
28226
+ baseUrlEnvVars: ["QWEN_CLOUD_PLAN_BASE_URL"],
28227
+ apiPath: "/apps/anthropic/v1/messages",
28228
+ apiKeyEnvVar: "QWEN_CLOUD_PLAN_API_KEY",
28229
+ apiKeyDescription: "Qwen Plan API Key",
28230
+ apiKeyUrl: "https://www.alibabacloud.com/help/en/model-studio/claude-code",
28231
+ authScheme: "bearer",
28232
+ shortcuts: ["qc"],
28233
+ shortestPrefix: "qc",
28234
+ legacyPrefixes: [{ prefix: "qc/", stripPrefix: true }],
28235
+ nativeModelPatterns: [{ pattern: /^qwen3\.\d/i }],
28236
+ modelDiscovery: { path: "/compatible-mode/v1/models", format: "openai-models-list" },
28237
+ isDirectApi: true,
28238
+ description: "Qwen Plan (qc@)"
28239
+ },
28221
28240
  {
28222
28241
  name: "qwen",
28223
28242
  displayName: "Qwen",
@@ -31500,6 +31519,7 @@ var init_routing_hints = __esm(() => {
31500
31519
  deepseek: { apiKeyEnvVar: "DEEPSEEK_API_KEY" },
31501
31520
  sakana: { apiKeyEnvVar: "SAKANA_API_KEY" },
31502
31521
  "sakana-subscription": { apiKeyEnvVar: "SAKANA_SUBSCRIPTION_API_KEY" },
31522
+ "qwen-cloud": { apiKeyEnvVar: "QWEN_CLOUD_PLAN_API_KEY" },
31503
31523
  ollamacloud: { apiKeyEnvVar: "OLLAMA_API_KEY" },
31504
31524
  "native-anthropic": { apiKeyEnvVar: "ANTHROPIC_API_KEY" },
31505
31525
  openrouter: { apiKeyEnvVar: "OPENROUTER_API_KEY" },
@@ -31559,9 +31579,13 @@ function lookupModel(modelId, cachePath) {
31559
31579
  return {
31560
31580
  modelId: entry.modelId,
31561
31581
  contextWindow: entry.contextWindow,
31562
- supportsVision: entry.supportsVision
31582
+ supportsVision: entry.supportsVision,
31583
+ releaseDate: entry.releaseDate
31563
31584
  };
31564
31585
  }
31586
+ function lookupModelReasoning(modelId, cachePath) {
31587
+ return findCacheEntry(modelId, cachePath)?.reasoning;
31588
+ }
31565
31589
  function lookupModelForProvider(modelId, provider, cachePath) {
31566
31590
  const entry = findCacheEntry(modelId, cachePath);
31567
31591
  if (!entry)
@@ -31668,6 +31692,7 @@ var init_default_routing_rules = __esm(() => {
31668
31692
  "k3*": ["kimi-coding", "kimi", "openrouter"],
31669
31693
  "minimax-*": ["minimax-coding", "minimax", "openrouter"],
31670
31694
  "glm-*": ["glm-coding", "glm", "openrouter"],
31695
+ "qwen3.*": ["qwen-cloud", "openrouter"],
31671
31696
  "z-ai-*": ["z-ai", "openrouter"],
31672
31697
  "deepseek-*": ["deepseek", "openrouter"],
31673
31698
  fugu: ["sakana-subscription", "sakana"],
@@ -32917,18 +32942,80 @@ var init_cache_ttl = __esm(() => {
32917
32942
  FIREBASE_CACHE_TTL_MS = FIREBASE_CACHE_TTL_HOURS * 60 * 60 * 1000;
32918
32943
  });
32919
32944
 
32945
+ // src/providers/model-ordering.ts
32946
+ function extractVersionParts(modelId) {
32947
+ const tokens = modelId.toLowerCase().split(/[\/_-]+/);
32948
+ let started = false;
32949
+ const parts = [];
32950
+ for (const token of tokens) {
32951
+ const match = token.match(/\d+(?:\.\d+)*/);
32952
+ if (!match) {
32953
+ if (started)
32954
+ break;
32955
+ continue;
32956
+ }
32957
+ if (!started) {
32958
+ started = true;
32959
+ for (const part of match[0].split(".")) {
32960
+ parts.push(Number.parseInt(part, 10));
32961
+ }
32962
+ if (!/^\d+(?:\.\d+)*$/.test(token)) {
32963
+ break;
32964
+ }
32965
+ continue;
32966
+ }
32967
+ if (!/^\d{1,2}(?:\.\d+)?$/.test(token)) {
32968
+ break;
32969
+ }
32970
+ for (const part of token.split(".")) {
32971
+ parts.push(Number.parseInt(part, 10));
32972
+ }
32973
+ }
32974
+ return parts;
32975
+ }
32976
+ function compareVersionPartsDesc(a, b) {
32977
+ const maxLength = Math.max(a.length, b.length);
32978
+ for (let i = 0;i < maxLength; i++) {
32979
+ const aPart = a[i] ?? -1;
32980
+ const bPart = b[i] ?? -1;
32981
+ if (aPart !== bPart) {
32982
+ return bPart - aPart;
32983
+ }
32984
+ }
32985
+ return 0;
32986
+ }
32987
+ function compareByReleaseDateDesc(a, b) {
32988
+ const aReleaseRaw = a.releaseDate ? Date.parse(a.releaseDate) : 0;
32989
+ const bReleaseRaw = b.releaseDate ? Date.parse(b.releaseDate) : 0;
32990
+ const aRelease = Number.isNaN(aReleaseRaw) ? 0 : aReleaseRaw;
32991
+ const bRelease = Number.isNaN(bReleaseRaw) ? 0 : bReleaseRaw;
32992
+ if (aRelease !== bRelease) {
32993
+ return bRelease - aRelease;
32994
+ }
32995
+ const aId = a.id ?? a.modelId ?? "";
32996
+ const bId = b.id ?? b.modelId ?? "";
32997
+ const versionCompare = compareVersionPartsDesc(extractVersionParts(aId), extractVersionParts(bId));
32998
+ if (versionCompare !== 0) {
32999
+ return versionCompare;
33000
+ }
33001
+ return aId.localeCompare(bId);
33002
+ }
33003
+
32920
33004
  // src/model-loader.ts
32921
33005
  import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
32922
33006
  import { homedir as homedir17 } from "os";
32923
33007
  import { join as join17 } from "path";
32924
33008
  function groupRecommendedModels(entries) {
32925
33009
  const byId = new Map;
33010
+ const categoryOrder = new Map;
32926
33011
  for (const entry of entries) {
32927
33012
  const list = byId.get(entry.id);
32928
33013
  if (list)
32929
33014
  list.push(entry);
32930
33015
  else
32931
33016
  byId.set(entry.id, [entry]);
33017
+ if (!categoryOrder.has(entry.category))
33018
+ categoryOrder.set(entry.category, categoryOrder.size);
32932
33019
  }
32933
33020
  const flagship = [];
32934
33021
  const fast = [];
@@ -32942,6 +33029,17 @@ function groupRecommendedModels(entries) {
32942
33029
  else
32943
33030
  fast.push(group);
32944
33031
  }
33032
+ const byCuratedPriorityThenFreshness = (a, b) => {
33033
+ const aCat = categoryOrder.get(a.primary.category) ?? Number.MAX_SAFE_INTEGER;
33034
+ const bCat = categoryOrder.get(b.primary.category) ?? Number.MAX_SAFE_INTEGER;
33035
+ if (aCat !== bCat)
33036
+ return aCat - bCat;
33037
+ if (a.primary.priority !== b.primary.priority)
33038
+ return a.primary.priority - b.primary.priority;
33039
+ return compareByReleaseDateDesc(a.primary, b.primary);
33040
+ };
33041
+ flagship.sort(byCuratedPriorityThenFreshness);
33042
+ fast.sort(byCuratedPriorityThenFreshness);
32945
33043
  return { flagship, fast };
32946
33044
  }
32947
33045
  function collectRoutingPrefixes(group, getNativePrefix) {
@@ -34932,6 +35030,9 @@ var cors = (options) => {
34932
35030
  var init_cors = () => {};
34933
35031
 
34934
35032
  // src/handlers/shared/remote-provider-types.ts
35033
+ function isSubscriptionProvider(provider) {
35034
+ return SUBSCRIPTION_PROVIDERS.has(provider.toLowerCase());
35035
+ }
34935
35036
  function registerDynamicPricingLookup(fn) {
34936
35037
  _dynamicLookup = fn;
34937
35038
  }
@@ -34940,7 +35041,7 @@ function getModelPricing(provider, modelName) {
34940
35041
  if (FREE_PROVIDERS.has(p)) {
34941
35042
  return { inputCostPer1M: 0, outputCostPer1M: 0, isFree: true };
34942
35043
  }
34943
- if (SUBSCRIPTION_PROVIDERS.has(p)) {
35044
+ if (isSubscriptionProvider(p)) {
34944
35045
  return { inputCostPer1M: 0, outputCostPer1M: 0, isSubscription: true };
34945
35046
  }
34946
35047
  if (_dynamicLookup) {
@@ -34962,7 +35063,12 @@ var init_remote_provider_types = __esm(() => {
34962
35063
  ollamacloud: { inputCostPer1M: 1, outputCostPer1M: 4, isEstimate: true }
34963
35064
  };
34964
35065
  FREE_PROVIDERS = new Set(["opencode-zen", "zen"]);
34965
- SUBSCRIPTION_PROVIDERS = new Set(["minimax-coding", "kimi-coding", "glm-coding"]);
35066
+ SUBSCRIPTION_PROVIDERS = new Set([
35067
+ "minimax-coding",
35068
+ "kimi-coding",
35069
+ "glm-coding",
35070
+ "qwen-cloud"
35071
+ ]);
34966
35072
  PROVIDER_ALIAS = {
34967
35073
  google: "gemini",
34968
35074
  oai: "openai",
@@ -35326,16 +35432,24 @@ function matchesModelFamily(modelId, family) {
35326
35432
  const fam = family.toLowerCase();
35327
35433
  return lower.startsWith(fam) || lower.includes(`/${fam}`);
35328
35434
  }
35435
+ function isEffortLevel(value) {
35436
+ return typeof value === "string" && EFFORT_ORDER.includes(value);
35437
+ }
35329
35438
 
35330
35439
  class BaseAPIFormat {
35331
35440
  modelId;
35441
+ wireFormat;
35332
35442
  toolNameMap = new Map;
35333
- constructor(modelId) {
35443
+ constructor(modelId, wireFormat) {
35334
35444
  this.modelId = modelId;
35445
+ this.wireFormat = wireFormat;
35335
35446
  }
35336
35447
  getModelId() {
35337
35448
  return this.modelId;
35338
35449
  }
35450
+ getWireFormat() {
35451
+ return this.wireFormat;
35452
+ }
35339
35453
  getToolNameLimit() {
35340
35454
  return null;
35341
35455
  }
@@ -35348,9 +35462,114 @@ class BaseAPIFormat {
35348
35462
  restoreToolName(name) {
35349
35463
  return this.toolNameMap.get(name) || name;
35350
35464
  }
35351
- prepareRequest(request, _originalRequest) {
35465
+ prepareRequest(request, originalRequest) {
35466
+ const prepared = this.prepareRequestCommon(request, originalRequest) ?? request;
35467
+ if (!this.isAnthropicWire()) {
35468
+ return this.applyNativeReasoning(prepared, originalRequest) ?? prepared;
35469
+ }
35470
+ this.stripNonAnthropicReasoningFields(prepared);
35471
+ return this.applyAnthropicWireReasoning(prepared, originalRequest) ?? prepared;
35472
+ }
35473
+ prepareRequestCommon(request, _originalRequest) {
35474
+ return request;
35475
+ }
35476
+ applyNativeReasoning(request, _originalRequest) {
35477
+ return request;
35478
+ }
35479
+ isAnthropicWire() {
35480
+ return this.wireFormat === "anthropic-sse";
35481
+ }
35482
+ stripNonAnthropicReasoningFields(request) {
35483
+ if (!request)
35484
+ return;
35485
+ for (const field of NON_ANTHROPIC_REASONING_FIELDS) {
35486
+ if (request[field] !== undefined)
35487
+ delete request[field];
35488
+ }
35489
+ }
35490
+ applyAnthropicWireReasoning(request, originalRequest) {
35491
+ const reasoning = this.lookupReasoningCapability();
35492
+ if (reasoning?.supported === false) {
35493
+ request.thinking = { type: "disabled" };
35494
+ log(`[${this.getName()}] ${this.modelId} reports no reasoning support -> thinking: disabled`);
35495
+ return request;
35496
+ }
35497
+ const effort = this.resolveEffortLevel(originalRequest);
35498
+ if (!effort)
35499
+ return request;
35500
+ if (effort === "none" || effort === "minimal") {
35501
+ request.thinking = { type: "disabled" };
35502
+ log(`[${this.getName()}] effort ${effort} -> thinking.type: disabled for ${this.modelId}`);
35503
+ return request;
35504
+ }
35505
+ if (reasoning && (reasoning.control === "budget" || reasoning.supportsBudgetTokens)) {
35506
+ return this.enableAnthropicThinkingWithBudget(request, effort, "catalog: budget-controlled");
35507
+ }
35508
+ const advertised = reasoning?.efforts?.length ? reasoning : undefined;
35509
+ if (advertised) {
35510
+ const level = this.clampToAdvertisedEffort(effort, advertised);
35511
+ request.thinking = { type: "enabled" };
35512
+ if (level) {
35513
+ request.output_config = { ...request.output_config ?? {}, effort: level };
35514
+ }
35515
+ log(`[${this.getName()}] effort ${effort} -> thinking: enabled, output_config.effort: ${level ?? "(none advertised)"} for ${this.modelId} (advertised: ${advertised.efforts?.join("/")})`);
35516
+ return request;
35517
+ }
35518
+ if (reasoning) {
35519
+ request.thinking = { type: "enabled" };
35520
+ log(`[${this.getName()}] effort ${effort} -> thinking: enabled (no depth knob; catalog control=${reasoning.control ?? "unknown"}) for ${this.modelId}`);
35521
+ return request;
35522
+ }
35523
+ return this.enableAnthropicThinkingWithBudget(request, effort, "no catalog entry");
35524
+ }
35525
+ enableAnthropicThinkingWithBudget(request, effort, why) {
35526
+ const budget = this.effortToThinkingTokenBudget(effort);
35527
+ request.thinking = budget === undefined ? { type: "enabled" } : { type: "enabled", budget_tokens: budget };
35528
+ log(`[${this.getName()}] effort ${effort} -> thinking: enabled, budget_tokens: ${budget ?? "(model max)"} for ${this.modelId} (${why})`);
35352
35529
  return request;
35353
35530
  }
35531
+ clampToAdvertisedEffort(requested, reasoning) {
35532
+ const advertised = (reasoning.efforts ?? []).filter(isEffortLevel);
35533
+ if (advertised.length === 0) {
35534
+ return isEffortLevel(reasoning.defaultEffort) ? reasoning.defaultEffort : undefined;
35535
+ }
35536
+ if (advertised.includes(requested))
35537
+ return requested;
35538
+ const target = EFFORT_ORDER.indexOf(requested);
35539
+ let best = advertised[0];
35540
+ let bestDistance = Number.POSITIVE_INFINITY;
35541
+ for (const candidate of advertised) {
35542
+ const distance = Math.abs(EFFORT_ORDER.indexOf(candidate) - target);
35543
+ if (distance < bestDistance || distance === bestDistance && EFFORT_ORDER.indexOf(candidate) > EFFORT_ORDER.indexOf(best)) {
35544
+ best = candidate;
35545
+ bestDistance = distance;
35546
+ }
35547
+ }
35548
+ return best;
35549
+ }
35550
+ lookupReasoningCapability() {
35551
+ try {
35552
+ return lookupModelReasoning(this.modelId);
35553
+ } catch {
35554
+ return;
35555
+ }
35556
+ }
35557
+ effortToThinkingTokenBudget(effort) {
35558
+ switch (effort) {
35559
+ case "low":
35560
+ return 2048;
35561
+ case "medium":
35562
+ return 8192;
35563
+ case "high":
35564
+ return 24576;
35565
+ case "xhigh":
35566
+ return 38912;
35567
+ case "max":
35568
+ return;
35569
+ default:
35570
+ return 8192;
35571
+ }
35572
+ }
35354
35573
  resolveEffortLevel(originalRequest) {
35355
35574
  const lvl = originalRequest?.output_config?.effort;
35356
35575
  if (typeof lvl === "string") {
@@ -35412,7 +35631,7 @@ class BaseAPIFormat {
35412
35631
  return true;
35413
35632
  }
35414
35633
  shouldFilterThinking() {
35415
- return false;
35634
+ return this.isAnthropicWire();
35416
35635
  }
35417
35636
  truncateToolNames(request) {
35418
35637
  const limit = this.getToolNameLimit();
@@ -35451,13 +35670,19 @@ class BaseAPIFormat {
35451
35670
  }
35452
35671
  }
35453
35672
  }
35454
- var EFFORT_ORDER, DefaultAPIFormat;
35673
+ var EFFORT_ORDER, NON_ANTHROPIC_REASONING_FIELDS, DefaultAPIFormat;
35455
35674
  var init_base_api_format = __esm(() => {
35456
35675
  init_remote_provider_types();
35676
+ init_logger();
35457
35677
  init_model_catalog();
35458
35678
  init_tool_name_utils();
35459
35679
  init_openai_tools();
35460
35680
  EFFORT_ORDER = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
35681
+ NON_ANTHROPIC_REASONING_FIELDS = [
35682
+ "reasoning_effort",
35683
+ "enable_thinking",
35684
+ "thinking_budget"
35685
+ ];
35461
35686
  DefaultAPIFormat = class DefaultAPIFormat extends BaseAPIFormat {
35462
35687
  processTextContent(textContent, _accumulatedText) {
35463
35688
  return {
@@ -35707,7 +35932,7 @@ var init_deepseek_model_dialect = __esm(() => {
35707
35932
  wasTransformed: false
35708
35933
  };
35709
35934
  }
35710
- prepareRequest(request, originalRequest) {
35935
+ applyNativeReasoning(request, originalRequest) {
35711
35936
  const effort = this.resolveEffortLevel(originalRequest);
35712
35937
  if (effort && this.isV4Model()) {
35713
35938
  if (effort === "none" || effort === "minimal") {
@@ -37136,7 +37361,7 @@ var init_glm_model_dialect = __esm(() => {
37136
37361
  wasTransformed: false
37137
37362
  };
37138
37363
  }
37139
- prepareRequest(request, originalRequest) {
37364
+ applyNativeReasoning(request, originalRequest) {
37140
37365
  const effort = this.resolveEffortLevel(originalRequest);
37141
37366
  if (effort && this.isHybridThinkingModel()) {
37142
37367
  const type = effort === "none" || effort === "minimal" ? "disabled" : "enabled";
@@ -37218,7 +37443,7 @@ var init_grok_model_dialect = __esm(() => {
37218
37443
  wasTransformed: true
37219
37444
  };
37220
37445
  }
37221
- prepareRequest(request, originalRequest) {
37446
+ applyNativeReasoning(request, originalRequest) {
37222
37447
  const effort = this.resolveEffortLevel(originalRequest);
37223
37448
  if (effort) {
37224
37449
  const value = this.effortToReasoningEffort(effort);
@@ -37310,7 +37535,7 @@ var init_minimax_model_dialect = __esm(() => {
37310
37535
  wasTransformed: false
37311
37536
  };
37312
37537
  }
37313
- prepareRequest(request, originalRequest) {
37538
+ prepareRequestCommon(request, _originalRequest) {
37314
37539
  if (request.temperature !== undefined) {
37315
37540
  if (request.temperature < TEMPERATURE_RANGE.min) {
37316
37541
  log(`[MiniMaxModelDialect] Clamping temperature ${request.temperature} \u2192 ${TEMPERATURE_RANGE.min} (MiniMax requires >= ${TEMPERATURE_RANGE.min})`);
@@ -37320,6 +37545,9 @@ var init_minimax_model_dialect = __esm(() => {
37320
37545
  request.temperature = TEMPERATURE_RANGE.max;
37321
37546
  }
37322
37547
  }
37548
+ return request;
37549
+ }
37550
+ applyMiniMaxThinking(request, originalRequest) {
37323
37551
  const effort = this.resolveEffortLevel(originalRequest);
37324
37552
  if (effort) {
37325
37553
  const type = effort === "none" ? "disabled" : "adaptive";
@@ -37328,6 +37556,12 @@ var init_minimax_model_dialect = __esm(() => {
37328
37556
  }
37329
37557
  return request;
37330
37558
  }
37559
+ applyNativeReasoning(request, originalRequest) {
37560
+ return this.applyMiniMaxThinking(request, originalRequest);
37561
+ }
37562
+ applyAnthropicWireReasoning(request, originalRequest) {
37563
+ return this.applyMiniMaxThinking(request, originalRequest);
37564
+ }
37331
37565
  getContextWindow() {
37332
37566
  return lookupModel(this.modelId)?.contextWindow ?? 0;
37333
37567
  }
@@ -37365,7 +37599,14 @@ var init_openai_api_format = __esm(() => {
37365
37599
  getMaxToolCount() {
37366
37600
  return 128;
37367
37601
  }
37368
- prepareRequest(request, originalRequest) {
37602
+ prepareRequestCommon(request, _originalRequest) {
37603
+ this.truncateToolNames(request);
37604
+ if (request.messages) {
37605
+ this.truncateToolNamesInMessages(request.messages);
37606
+ }
37607
+ return request;
37608
+ }
37609
+ applyNativeReasoning(request, originalRequest) {
37369
37610
  if (this.supportsReasoningEffort() && request.reasoning_effort === undefined) {
37370
37611
  const effort = this.resolveReasoningEffort(originalRequest);
37371
37612
  if (effort) {
@@ -37375,10 +37616,6 @@ var init_openai_api_format = __esm(() => {
37375
37616
  }
37376
37617
  if (request.thinking)
37377
37618
  delete request.thinking;
37378
- this.truncateToolNames(request);
37379
- if (request.messages) {
37380
- this.truncateToolNamesInMessages(request.messages);
37381
- }
37382
37619
  return request;
37383
37620
  }
37384
37621
  shouldHandle(modelId) {
@@ -37536,41 +37773,25 @@ var init_qwen_model_dialect = __esm(() => {
37536
37773
  wasTransformed
37537
37774
  };
37538
37775
  }
37539
- prepareRequest(request, originalRequest) {
37776
+ applyNativeReasoning(request, originalRequest) {
37540
37777
  const effort = this.resolveEffortLevel(originalRequest);
37541
- if (effort) {
37542
- if (effort === "none" || effort === "minimal") {
37543
- request.enable_thinking = false;
37544
- log(`[QwenModelDialect] effort ${effort} -> enable_thinking: false for ${this.modelId}`);
37545
- } else {
37546
- request.enable_thinking = true;
37547
- const budget = this.effortToThinkingBudget(effort);
37548
- if (budget !== undefined) {
37549
- request.thinking_budget = budget;
37550
- }
37551
- log(`[QwenModelDialect] effort ${effort} -> enable_thinking: true, thinking_budget: ${budget ?? "(model max)"} for ${this.modelId}`);
37778
+ if (!effort)
37779
+ return request;
37780
+ if (effort === "none" || effort === "minimal") {
37781
+ request.enable_thinking = false;
37782
+ log(`[QwenModelDialect] effort ${effort} -> enable_thinking: false for ${this.modelId}`);
37783
+ } else {
37784
+ request.enable_thinking = true;
37785
+ const budget = this.effortToThinkingTokenBudget(effort);
37786
+ if (budget !== undefined) {
37787
+ request.thinking_budget = budget;
37552
37788
  }
37553
- if (originalRequest.thinking)
37554
- delete request.thinking;
37789
+ log(`[QwenModelDialect] effort ${effort} -> enable_thinking: true, thinking_budget: ${budget ?? "(model max)"} for ${this.modelId}`);
37555
37790
  }
37791
+ if (originalRequest.thinking)
37792
+ delete request.thinking;
37556
37793
  return request;
37557
37794
  }
37558
- effortToThinkingBudget(effort) {
37559
- switch (effort) {
37560
- case "low":
37561
- return 2048;
37562
- case "medium":
37563
- return 8192;
37564
- case "high":
37565
- return 24576;
37566
- case "xhigh":
37567
- return 38912;
37568
- case "max":
37569
- return;
37570
- default:
37571
- return 8192;
37572
- }
37573
- }
37574
37795
  shouldHandle(modelId) {
37575
37796
  return matchesModelFamily(modelId, "qwen") || matchesModelFamily(modelId, "alibaba");
37576
37797
  }
@@ -37596,17 +37817,20 @@ var init_xiaomi_model_dialect = __esm(() => {
37596
37817
  getToolNameLimit() {
37597
37818
  return 64;
37598
37819
  }
37599
- prepareRequest(request, originalRequest) {
37600
- if (originalRequest.thinking) {
37601
- log("[XiaomiModelDialect] Stripping thinking object (not supported by Xiaomi API)");
37602
- delete request.thinking;
37603
- }
37820
+ prepareRequestCommon(request, _originalRequest) {
37604
37821
  this.truncateToolNames(request);
37605
37822
  if (request.messages) {
37606
37823
  this.truncateToolNamesInMessages(request.messages);
37607
37824
  }
37608
37825
  return request;
37609
37826
  }
37827
+ applyNativeReasoning(request, originalRequest) {
37828
+ if (originalRequest.thinking) {
37829
+ log("[XiaomiModelDialect] Stripping thinking object (not supported by Xiaomi API)");
37830
+ delete request.thinking;
37831
+ }
37832
+ return request;
37833
+ }
37610
37834
  shouldHandle(modelId) {
37611
37835
  return matchesModelFamily(modelId, "xiaomi") || matchesModelFamily(modelId, "mimo");
37612
37836
  }
@@ -37626,19 +37850,19 @@ __export(exports_dialect_manager, {
37626
37850
  class DialectManager {
37627
37851
  adapters;
37628
37852
  defaultAdapter;
37629
- constructor(modelId) {
37853
+ constructor(modelId, wireFormat) {
37630
37854
  this.adapters = [
37631
- new GrokModelDialect(modelId),
37632
- new GeminiAPIFormat(modelId),
37633
- new CodexAPIFormat(modelId),
37634
- new OpenAIAPIFormat(modelId),
37635
- new QwenModelDialect(modelId),
37636
- new MiniMaxModelDialect(modelId),
37637
- new DeepSeekModelDialect(modelId),
37638
- new GLMModelDialect(modelId),
37639
- new XiaomiModelDialect(modelId)
37855
+ new GrokModelDialect(modelId, wireFormat),
37856
+ new GeminiAPIFormat(modelId, wireFormat),
37857
+ new CodexAPIFormat(modelId, wireFormat),
37858
+ new OpenAIAPIFormat(modelId, wireFormat),
37859
+ new QwenModelDialect(modelId, wireFormat),
37860
+ new MiniMaxModelDialect(modelId, wireFormat),
37861
+ new DeepSeekModelDialect(modelId, wireFormat),
37862
+ new GLMModelDialect(modelId, wireFormat),
37863
+ new XiaomiModelDialect(modelId, wireFormat)
37640
37864
  ];
37641
- this.defaultAdapter = new DefaultAPIFormat(modelId);
37865
+ this.defaultAdapter = new DefaultAPIFormat(modelId, wireFormat);
37642
37866
  }
37643
37867
  getAdapter() {
37644
37868
  for (const adapter of this.adapters) {
@@ -37745,7 +37969,7 @@ ${messages[0].content}`;
37745
37969
  }
37746
37970
  return payload;
37747
37971
  }
37748
- prepareRequest(request, originalRequest) {
37972
+ prepareRequestCommon(request, originalRequest) {
37749
37973
  this.innerAdapter.prepareRequest(request, originalRequest);
37750
37974
  for (const [k, v] of this.innerAdapter.getToolNameMap()) {
37751
37975
  this.toolNameMap.set(k, v);
@@ -37931,7 +38155,7 @@ ${text}`;
37931
38155
  }
37932
38156
  return payload;
37933
38157
  }
37934
- prepareRequest(request, originalRequest) {
38158
+ prepareRequestCommon(request, originalRequest) {
37935
38159
  return this.innerAdapter.prepareRequest(request, originalRequest);
37936
38160
  }
37937
38161
  getToolNameMap() {
@@ -40104,7 +40328,8 @@ var init_telemetry = __esm(() => {
40104
40328
  "x-ai",
40105
40329
  "minimax-coding",
40106
40330
  "kimi-coding",
40107
- "glm-coding"
40331
+ "glm-coding",
40332
+ "qwen-cloud"
40108
40333
  ]);
40109
40334
  });
40110
40335
 
@@ -40602,6 +40827,60 @@ var init_connection_error = __esm(() => {
40602
40827
  BUN_CONNECT_MESSAGE = /unable to connect\. is the computer able to access the url\?/i;
40603
40828
  });
40604
40829
 
40830
+ // src/handlers/shared/context-window-fallback.ts
40831
+ function isDisabled() {
40832
+ if (process.env.CLAUDISH_NO_CATALOG_FALLBACK)
40833
+ return true;
40834
+ return false;
40835
+ }
40836
+ function resolveCatalogContextWindow(modelId) {
40837
+ if (!modelId || isDisabled())
40838
+ return Promise.resolve(null);
40839
+ const cached2 = results.get(modelId);
40840
+ if (cached2 !== undefined)
40841
+ return Promise.resolve(cached2);
40842
+ const pending = inFlight2.get(modelId);
40843
+ if (pending)
40844
+ return pending;
40845
+ const promise3 = fetcher(modelId).then((cw) => {
40846
+ const value = typeof cw === "number" && cw > 0 ? cw : null;
40847
+ results.set(modelId, value);
40848
+ return value;
40849
+ }).catch((err) => {
40850
+ results.set(modelId, null);
40851
+ log(`[ContextWindow] Catalog lookup failed for ${modelId}: ${err}`);
40852
+ return null;
40853
+ }).finally(() => {
40854
+ inFlight2.delete(modelId);
40855
+ });
40856
+ inFlight2.set(modelId, promise3);
40857
+ return promise3;
40858
+ }
40859
+ function requestCatalogContextWindow(modelId, apply) {
40860
+ resolveCatalogContextWindow(modelId).then((cw) => {
40861
+ if (cw === null)
40862
+ return;
40863
+ try {
40864
+ apply(cw);
40865
+ log(`[ContextWindow] Resolved ${modelId} = ${cw} tokens from the cloud catalog`);
40866
+ } catch (err) {
40867
+ log(`[ContextWindow] Failed to apply catalog window for ${modelId}: ${err}`);
40868
+ }
40869
+ });
40870
+ }
40871
+ var defaultFetcher = async (modelId) => {
40872
+ const doc2 = await getModelByIdFromFirebase(modelId);
40873
+ const cw = doc2?.contextWindow;
40874
+ return typeof cw === "number" && cw > 0 ? cw : null;
40875
+ }, fetcher, results, inFlight2;
40876
+ var init_context_window_fallback = __esm(() => {
40877
+ init_logger();
40878
+ init_model_loader();
40879
+ fetcher = defaultFetcher;
40880
+ results = new Map;
40881
+ inFlight2 = new Map;
40882
+ });
40883
+
40605
40884
  // src/handlers/shared/stream-head-sniffer.ts
40606
40885
  function isRetryableStreamError(code, type, message) {
40607
40886
  if (RETRYABLE_ERROR_CODES.has(code))
@@ -40737,6 +41016,12 @@ var init_stream_head_sniffer = __esm(() => {
40737
41016
  });
40738
41017
 
40739
41018
  // src/handlers/shared/stream-parsers/anthropic-sse.ts
41019
+ function sseDataPayload(line) {
41020
+ if (!line.startsWith("data:"))
41021
+ return null;
41022
+ const rest = line.slice(5);
41023
+ return rest.startsWith(" ") ? rest.slice(1) : rest;
41024
+ }
40740
41025
  function createToolRepairInterceptor(opts) {
40741
41026
  const heldTools = new Map;
40742
41027
  const flush = (index, stopFrame) => {
@@ -40809,12 +41094,24 @@ function createAnthropicPassthroughStream(c, response, opts) {
40809
41094
  let pingInterval = null;
40810
41095
  const filterThinking = opts.adapter?.shouldFilterThinking() ?? false;
40811
41096
  const interceptToolFrame = createToolRepairInterceptor(opts);
41097
+ let pendingEventLine = null;
41098
+ const flushPendingEvent = (controller) => {
41099
+ if (pendingEventLine !== null && !isClosed) {
41100
+ controller.enqueue(encoder.encode(`${pendingEventLine}
41101
+ `));
41102
+ }
41103
+ pendingEventLine = null;
41104
+ };
40812
41105
  const enqueueData = (controller, data, line) => {
40813
41106
  if (isClosed)
40814
41107
  return;
40815
41108
  const out = interceptToolFrame(data, line);
40816
- if (out !== null)
40817
- controller.enqueue(encoder.encode(out));
41109
+ if (out === null) {
41110
+ pendingEventLine = null;
41111
+ return;
41112
+ }
41113
+ flushPendingEvent(controller);
41114
+ controller.enqueue(encoder.encode(out));
40818
41115
  };
40819
41116
  return c.body(new ReadableStream({
40820
41117
  async start(controller) {
@@ -40843,6 +41140,7 @@ data: {"type":"ping"}
40843
41140
  let stopReason = null;
40844
41141
  let insideThinkingBlock = false;
40845
41142
  let thinkingBlocksSuppressed = 0;
41143
+ let suppressedFrame = false;
40846
41144
  while (true) {
40847
41145
  const { done, value } = await reader.read();
40848
41146
  if (done)
@@ -40854,9 +41152,10 @@ data: {"type":"ping"}
40854
41152
  buffer = lines.pop() || "";
40855
41153
  for (const line of lines) {
40856
41154
  totalLines++;
40857
- if (filterThinking && line.startsWith("data: ")) {
41155
+ const payload = sseDataPayload(line);
41156
+ if (filterThinking && payload !== null) {
40858
41157
  try {
40859
- const data = JSON.parse(line.slice(6));
41158
+ const data = JSON.parse(payload);
40860
41159
  if (data.error) {
40861
41160
  const errMsg = data.error.message || JSON.stringify(data.error);
40862
41161
  log(`[AnthropicSSE] In-stream error detected: ${errMsg}`);
@@ -40881,19 +41180,26 @@ data: ${JSON.stringify({
40881
41180
  insideThinkingBlock = true;
40882
41181
  thinkingBlocksSuppressed++;
40883
41182
  log(`[AnthropicSSE] Filtering thinking block at index ${data.index}`);
41183
+ pendingEventLine = null;
41184
+ suppressedFrame = true;
40884
41185
  continue;
40885
41186
  }
40886
41187
  if (insideThinkingBlock && data.type === "content_block_stop") {
40887
41188
  insideThinkingBlock = false;
41189
+ pendingEventLine = null;
41190
+ suppressedFrame = true;
40888
41191
  continue;
40889
41192
  }
40890
41193
  if (insideThinkingBlock) {
41194
+ pendingEventLine = null;
41195
+ suppressedFrame = true;
40891
41196
  continue;
40892
41197
  }
40893
41198
  if (typeof data.index === "number" && thinkingBlocksSuppressed > 0) {
40894
41199
  const reindexed = data.index - thinkingBlocksSuppressed;
40895
41200
  const modifiedLine = `data: ${JSON.stringify({ ...data, index: reindexed })}`;
40896
41201
  if (!isClosed) {
41202
+ flushPendingEvent(controller);
40897
41203
  controller.enqueue(encoder.encode(`${modifiedLine}
40898
41204
  `));
40899
41205
  }
@@ -40902,14 +41208,15 @@ data: ${JSON.stringify({
40902
41208
  }
40903
41209
  } catch {
40904
41210
  if (!isClosed) {
41211
+ flushPendingEvent(controller);
40905
41212
  controller.enqueue(encoder.encode(`${line}
40906
41213
  `));
40907
41214
  }
40908
41215
  }
40909
41216
  } else {
40910
- if (!filterThinking && line.startsWith("data: ")) {
41217
+ if (!filterThinking && payload !== null) {
40911
41218
  try {
40912
- const data = JSON.parse(line.slice(6));
41219
+ const data = JSON.parse(payload);
40913
41220
  if (data.error) {
40914
41221
  const errMsg = data.error.message || JSON.stringify(data.error);
40915
41222
  log(`[AnthropicSSE] In-stream error detected: ${errMsg}`);
@@ -40957,6 +41264,15 @@ data: ${JSON.stringify({
40957
41264
  `));
40958
41265
  }
40959
41266
  }
41267
+ } else if (filterThinking) {
41268
+ if (line.startsWith("event:")) {
41269
+ pendingEventLine = line;
41270
+ } else if (line.trim() === "" && suppressedFrame) {
41271
+ suppressedFrame = false;
41272
+ } else if (!isClosed) {
41273
+ controller.enqueue(encoder.encode(`${line}
41274
+ `));
41275
+ }
40960
41276
  } else {
40961
41277
  if (!isClosed) {
40962
41278
  controller.enqueue(encoder.encode(`${line}
@@ -40964,9 +41280,9 @@ data: ${JSON.stringify({
40964
41280
  }
40965
41281
  }
40966
41282
  }
40967
- if (filterThinking && line.startsWith("data: ")) {
41283
+ if (filterThinking && payload !== null) {
40968
41284
  try {
40969
- const data = JSON.parse(line.slice(6));
41285
+ const data = JSON.parse(payload);
40970
41286
  if (data.message?.usage) {
40971
41287
  inputTokens = data.message.usage.input_tokens || inputTokens;
40972
41288
  outputTokens = data.message.usage.output_tokens || outputTokens;
@@ -41838,6 +42154,10 @@ var init_openai_responses_sse = __esm(() => {
41838
42154
  import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
41839
42155
  import { homedir as homedir22 } from "os";
41840
42156
  import { dirname as dirname7, join as join22 } from "path";
42157
+ function stripProviderPrefix(name) {
42158
+ const at = name.indexOf("@");
42159
+ return at === -1 ? name : name.slice(at + 1);
42160
+ }
41841
42161
 
41842
42162
  class TokenTracker {
41843
42163
  port;
@@ -41928,6 +42248,9 @@ class TokenTracker {
41928
42248
  setContextWindow(contextWindow) {
41929
42249
  this.config.contextWindow = contextWindow;
41930
42250
  }
42251
+ getContextWindow() {
42252
+ return this.config.contextWindow;
42253
+ }
41931
42254
  getTotalCost() {
41932
42255
  return this.sessionTotalCost;
41933
42256
  }
@@ -41974,8 +42297,9 @@ class TokenTracker {
41974
42297
  is_free: isFreeModel,
41975
42298
  is_estimated: isEstimate || false
41976
42299
  };
41977
- if (this.modelNameOverride) {
41978
- data.model_name = this.modelNameOverride;
42300
+ const displayModel = stripProviderPrefix(this.modelNameOverride || this.config.modelName || "");
42301
+ if (displayModel) {
42302
+ data.model_name = displayModel;
41979
42303
  }
41980
42304
  if (this.quotaRemaining !== undefined) {
41981
42305
  data.quota_remaining = this.quotaRemaining;
@@ -42026,7 +42350,7 @@ class ComposedHandler {
42026
42350
  this.options = options;
42027
42351
  this.explicitAdapter = options.adapter;
42028
42352
  this.isInteractive = options.isInteractive ?? false;
42029
- this.adapterManager = new DialectManager(this.bareModelName);
42353
+ this.adapterManager = new DialectManager(this.bareModelName, this.explicitAdapter?.getStreamFormat());
42030
42354
  const resolvedModelAdapter = this.adapterManager.getAdapter();
42031
42355
  if (resolvedModelAdapter.getName() !== "DefaultAPIFormat") {
42032
42356
  this.modelAdapter = resolvedModelAdapter;
@@ -42209,7 +42533,13 @@ class ComposedHandler {
42209
42533
  }
42210
42534
  }
42211
42535
  if (this.provider.getContextWindow) {
42212
- this.tokenTracker.setContextWindow(this.provider.getContextWindow());
42536
+ const providerWindow = this.provider.getContextWindow();
42537
+ if (providerWindow > 0) {
42538
+ this.tokenTracker.setContextWindow(providerWindow);
42539
+ }
42540
+ }
42541
+ if (this.tokenTracker.getContextWindow() <= 0) {
42542
+ requestCatalogContextWindow(this.bareModelName, (cw) => this.tokenTracker.setContextWindow(cw));
42213
42543
  }
42214
42544
  if (this.provider.transformPayload) {
42215
42545
  requestPayload = this.provider.transformPayload(requestPayload);
@@ -42592,7 +42922,7 @@ class ComposedHandler {
42592
42922
  return createAnthropicPassthroughStream(c, response, {
42593
42923
  modelName: this.bareModelName,
42594
42924
  onTokenUpdate,
42595
- adapter,
42925
+ adapter: this.modelAdapter ?? adapter,
42596
42926
  shouldBufferTool: (name) => behaviorSession?.interceptsTool(name) ?? false,
42597
42927
  repairToolArgs: (name, argsJson) => behaviorSession?.repairToolCall(name, argsJson) ?? null
42598
42928
  });
@@ -42694,6 +43024,7 @@ var init_composed_handler = __esm(() => {
42694
43024
  init_transform();
42695
43025
  init_anthropic_error();
42696
43026
  init_connection_error();
43027
+ init_context_window_fallback();
42697
43028
  init_openai_compat();
42698
43029
  init_stream_head_sniffer();
42699
43030
  init_anthropic_sse();
@@ -43151,11 +43482,11 @@ ${a.text}`).join(`
43151
43482
  }
43152
43483
  }
43153
43484
  async function fetchMultiModelAdvice(_toolUseId, messages, models, collector, apiKeys) {
43154
- const results = await Promise.allSettled(models.map((model) => callAdvisorModel(model, messages, apiKeys)));
43485
+ const results2 = await Promise.allSettled(models.map((model) => callAdvisorModel(model, messages, apiKeys)));
43155
43486
  const sections = [];
43156
43487
  const successfulAdvice = [];
43157
43488
  for (let i = 0;i < models.length; i++) {
43158
- const result = results[i];
43489
+ const result = results2[i];
43159
43490
  if (result.status === "fulfilled") {
43160
43491
  sections.push(`## ${models[i]}
43161
43492
  ${result.value}`);
@@ -43474,6 +43805,7 @@ var init_api_key_map = __esm(() => {
43474
43805
  envVar: "SAKANA_SUBSCRIPTION_API_KEY",
43475
43806
  aliases: ["SAKANA_CODING_API_KEY"]
43476
43807
  },
43808
+ "qwen-cloud": { envVar: "QWEN_CLOUD_PLAN_API_KEY" },
43477
43809
  ollamacloud: { envVar: "OLLAMA_API_KEY" },
43478
43810
  "opencode-zen": { envVar: "OPENCODE_API_KEY" },
43479
43811
  "opencode-zen-go": { envVar: "OPENCODE_API_KEY" },
@@ -43699,90 +44031,127 @@ var init_config_schema = __esm(() => {
43699
44031
  DefaultProviderSchema = exports_external.union([BuiltinDefaultProviderSchema, exports_external.string().min(1)]);
43700
44032
  });
43701
44033
 
43702
- // src/providers/transport/anthropic-compat.ts
43703
- class AnthropicProviderTransport {
43704
- name;
43705
- displayName;
43706
- streamFormat = "anthropic-sse";
43707
- provider;
43708
- apiKey;
43709
- constructor(provider, apiKey) {
43710
- this.provider = provider;
43711
- this.apiKey = apiKey;
43712
- this.name = provider.name;
43713
- this.displayName = AnthropicProviderTransport.formatDisplayName(provider.name);
44034
+ // src/providers/model-discovery.ts
44035
+ function resolveBaseUrl2(catalogName) {
44036
+ const def = getProviderByName(catalogName);
44037
+ if (!def)
44038
+ return null;
44039
+ for (const envVar of def.baseUrlEnvVars ?? []) {
44040
+ const v = process.env[envVar];
44041
+ if (v)
44042
+ return v.replace(/\/+$/, "");
43714
44043
  }
43715
- getEndpoint() {
43716
- return `${this.provider.baseUrl}${this.provider.apiPath}`;
44044
+ return (def.baseUrl || "").replace(/\/+$/, "") || null;
44045
+ }
44046
+ function readContextWindow(row) {
44047
+ for (const field of ["context_length", "context_window", "max_context_length"]) {
44048
+ const v = row[field];
44049
+ if (typeof v === "number" && Number.isFinite(v) && v > 0)
44050
+ return v;
43717
44051
  }
43718
- async getHeaders() {
43719
- const headers = {
43720
- "anthropic-version": "2023-06-01"
43721
- };
43722
- if (this.provider.authScheme === "bearer") {
43723
- headers.Authorization = `Bearer ${this.apiKey}`;
43724
- } else {
43725
- headers["x-api-key"] = this.apiKey;
43726
- }
43727
- if (this.provider.headers) {
43728
- Object.assign(headers, this.provider.headers);
43729
- }
43730
- if (this.provider.name === "kimi-coding") {
43731
- try {
43732
- const auth = await credentials.getRequestAuth("kimi-coding", { model: "" });
43733
- if (auth.headers.Authorization) {
43734
- delete headers["x-api-key"];
43735
- }
43736
- Object.assign(headers, auth.headers);
43737
- } catch (e) {
43738
- log(`[${this.displayName}] OAuth path failed, falling back to API key: ${e.message}`);
43739
- }
43740
- }
43741
- return headers;
44052
+ return;
44053
+ }
44054
+ function readCreatedDate(row) {
44055
+ const raw2 = row.created;
44056
+ const seconds = typeof raw2 === "number" ? raw2 : typeof raw2 === "string" ? Number(raw2) : NaN;
44057
+ if (!Number.isFinite(seconds))
44058
+ return;
44059
+ if (seconds < MIN_CREATED_SECONDS || seconds > MAX_CREATED_SECONDS)
44060
+ return;
44061
+ const iso = new Date(seconds * 1000).toISOString();
44062
+ return iso.slice(0, 10);
44063
+ }
44064
+ function parseOpenAIModelsList(body) {
44065
+ const data = body?.data;
44066
+ if (!Array.isArray(data))
44067
+ return [];
44068
+ const models = [];
44069
+ for (const raw2 of data) {
44070
+ if (!raw2 || typeof raw2 !== "object")
44071
+ continue;
44072
+ const row = raw2;
44073
+ const id = row.id;
44074
+ if (typeof id !== "string" || id.trim().length === 0)
44075
+ continue;
44076
+ const displayName = typeof row.display_name === "string" ? row.display_name : undefined;
44077
+ models.push({
44078
+ id,
44079
+ displayName,
44080
+ contextWindow: readContextWindow(row),
44081
+ releaseDate: readCreatedDate(row)
44082
+ });
43742
44083
  }
43743
- async enqueueRequest(fetchFn) {
43744
- const maxRetries = 2;
43745
- let lastResponse = null;
43746
- for (let attempt = 0;attempt <= maxRetries; attempt++) {
43747
- const response = await fetchFn();
43748
- if (response.status === 429 && attempt < maxRetries) {
43749
- const bodyText = await response.clone().text().catch(() => "");
43750
- if (isTerminal429(bodyText)) {
43751
- log(`[${this.displayName}] 429 is terminal (billing/quota), not retrying`);
43752
- return response;
43753
- }
43754
- lastResponse = response;
43755
- const retryAfter = response.headers.get("Retry-After");
43756
- let delayMs;
43757
- if (retryAfter && !Number.isNaN(Number(retryAfter))) {
43758
- delayMs = Math.min(Number(retryAfter) * 1000, 2000);
43759
- } else {
43760
- delayMs = 500 * (attempt + 1);
43761
- }
43762
- log(`[${this.displayName}] 429 rate limited, retry ${attempt + 1}/${maxRetries} in ${(delayMs / 1000).toFixed(1)}s`);
43763
- await new Promise((resolve2) => setTimeout(resolve2, delayMs));
43764
- continue;
43765
- }
43766
- return response;
43767
- }
43768
- return lastResponse;
44084
+ return models;
44085
+ }
44086
+ async function discoverProviderModels(providerName) {
44087
+ const cached2 = _cache.get(providerName);
44088
+ if (cached2 && cached2.expiresAt > Date.now())
44089
+ return cached2.models;
44090
+ const def = getProviderByName(providerName);
44091
+ const descriptor = def?.modelDiscovery;
44092
+ if (!def || !descriptor)
44093
+ return [];
44094
+ const baseUrl = resolveBaseUrl2(providerName);
44095
+ if (!baseUrl)
44096
+ return [];
44097
+ const endpoint = `${baseUrl}${descriptor.path}`;
44098
+ let headers = {};
44099
+ try {
44100
+ const auth = await credentials.getRequestAuth(providerName, { model: "" });
44101
+ headers = { ...auth.headers };
44102
+ } catch (e) {
44103
+ log(`[model-discovery:${providerName}] no credentials, skipping: ${e?.message}`);
44104
+ return [];
43769
44105
  }
43770
- static formatDisplayName(name) {
43771
- const map3 = {
43772
- minimax: "MiniMax",
43773
- "minimax-coding": "MiniMax Coding",
43774
- kimi: "Kimi",
43775
- "kimi-coding": "Kimi Coding",
43776
- moonshot: "Kimi",
43777
- "z-ai": "Z.AI"
43778
- };
43779
- return map3[name.toLowerCase()] || name.charAt(0).toUpperCase() + name.slice(1);
44106
+ let response;
44107
+ try {
44108
+ response = await fetch(endpoint, {
44109
+ method: "GET",
44110
+ headers,
44111
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
44112
+ });
44113
+ } catch (e) {
44114
+ log(`[model-discovery:${providerName}] fetch failed: ${e?.message}`);
44115
+ return [];
43780
44116
  }
44117
+ if (!response.ok) {
44118
+ log(`[model-discovery:${providerName}] HTTP ${response.status} from ${endpoint}`);
44119
+ return [];
44120
+ }
44121
+ let body;
44122
+ try {
44123
+ body = await response.json();
44124
+ } catch {
44125
+ log(`[model-discovery:${providerName}] response was not JSON`);
44126
+ return [];
44127
+ }
44128
+ const models = parseOpenAIModelsList(body);
44129
+ if (models.length === 0) {
44130
+ log(`[model-discovery:${providerName}] endpoint reachable but listed no models`);
44131
+ return [];
44132
+ }
44133
+ log(`[model-discovery:${providerName}] discovered ${models.length} models: ` + models.map((m) => `${m.id}(${m.contextWindow ?? "?"})`).join(", "));
44134
+ _cache.set(providerName, { models, expiresAt: Date.now() + CACHE_TTL_MS });
44135
+ return models;
43781
44136
  }
43782
- var init_anthropic_compat = __esm(() => {
44137
+ async function discoverContextWindow(providerName, modelId) {
44138
+ const models = await discoverProviderModels(providerName);
44139
+ const match2 = models.find((m) => m.id.toLowerCase() === modelId.toLowerCase());
44140
+ return match2?.contextWindow;
44141
+ }
44142
+ function rankDiscoveredModels(models) {
44143
+ return [...models].sort((a, b) => {
44144
+ const diff = (b.contextWindow ?? 0) - (a.contextWindow ?? 0);
44145
+ return diff !== 0 ? diff : a.id.localeCompare(b.id);
44146
+ });
44147
+ }
44148
+ var CACHE_TTL_MS, FETCH_TIMEOUT_MS = 5000, _cache, MIN_CREATED_SECONDS = 946684800, MAX_CREATED_SECONDS = 4102444800;
44149
+ var init_model_discovery = __esm(() => {
43783
44150
  init_authority();
43784
44151
  init_logger();
43785
- init_openai();
44152
+ init_provider_definitions();
44153
+ CACHE_TTL_MS = 5 * 60 * 1000;
44154
+ _cache = new Map;
43786
44155
  });
43787
44156
 
43788
44157
  // src/providers/transport/probe-discovery.ts
@@ -43813,11 +44182,11 @@ function rankProbeCandidates(names) {
43813
44182
  });
43814
44183
  }
43815
44184
  function cacheGet(key, exclude = new Set) {
43816
- const hit = _cache.get(key);
44185
+ const hit = _cache2.get(key);
43817
44186
  if (!hit)
43818
44187
  return;
43819
44188
  if (Date.now() > hit.expiresAt) {
43820
- _cache.delete(key);
44189
+ _cache2.delete(key);
43821
44190
  return;
43822
44191
  }
43823
44192
  if (hit.ranked.length === 0) {
@@ -43833,10 +44202,10 @@ function cacheGet(key, exclude = new Set) {
43833
44202
  return { model: pick2 };
43834
44203
  }
43835
44204
  function cacheSetFailure(key, reason) {
43836
- _cache.set(key, { ranked: [], reason, expiresAt: Date.now() + CACHE_TTL_MS });
44205
+ _cache2.set(key, { ranked: [], reason, expiresAt: Date.now() + CACHE_TTL_MS2 });
43837
44206
  }
43838
44207
  function cacheSetRanked(key, ranked) {
43839
- _cache.set(key, { ranked, expiresAt: Date.now() + CACHE_TTL_MS });
44208
+ _cache2.set(key, { ranked, expiresAt: Date.now() + CACHE_TTL_MS2 });
43840
44209
  }
43841
44210
  async function discoverViaOpenAIModels(endpoint, headers, cacheKey) {
43842
44211
  const cached2 = cacheGet(cacheKey.key, cacheKey.exclude);
@@ -43847,7 +44216,7 @@ async function discoverViaOpenAIModels(endpoint, headers, cacheKey) {
43847
44216
  response = await fetch(endpoint, {
43848
44217
  method: "GET",
43849
44218
  headers,
43850
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
44219
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
43851
44220
  });
43852
44221
  } catch (e) {
43853
44222
  const reason = classifyFetchError(e, endpoint);
@@ -43901,7 +44270,7 @@ function classifyFetchError(e, endpoint) {
43901
44270
  const host = url2?.host ?? endpoint;
43902
44271
  const isLocal = !!url2 && /^(localhost|127\.0\.0\.1|0\.0\.0\.0|::1)$/i.test(url2.hostname);
43903
44272
  if (name === "TimeoutError" || name === "AbortError" || /timeout/i.test(msg)) {
43904
- return `${host} unresponsive (>${FETCH_TIMEOUT_MS / 1000}s) \u2014 check if the server is overloaded`;
44273
+ return `${host} unresponsive (>${FETCH_TIMEOUT_MS2 / 1000}s) \u2014 check if the server is overloaded`;
43905
44274
  }
43906
44275
  if (code === "ENOTFOUND" || code === "EAI_AGAIN") {
43907
44276
  return `cannot resolve host ${url2?.hostname ?? endpoint} \u2014 check the URL`;
@@ -43984,7 +44353,7 @@ async function discoverViaLMStudio(baseUrl, headers, cacheKey) {
43984
44353
  response = await fetch(`${baseUrl}/api/v0/models`, {
43985
44354
  method: "GET",
43986
44355
  headers,
43987
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
44356
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
43988
44357
  });
43989
44358
  } catch (e) {
43990
44359
  return discoverViaOpenAIModels(`${baseUrl}/v1/models`, headers, cacheKey);
@@ -44056,7 +44425,7 @@ function extractLMStudioModels(body) {
44056
44425
  async function fetchOllamaModels2(url2) {
44057
44426
  const response = await fetch(url2, {
44058
44427
  method: "GET",
44059
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
44428
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
44060
44429
  });
44061
44430
  if (!response.ok)
44062
44431
  return [];
@@ -44069,17 +44438,17 @@ async function fetchOllamaModels2(url2) {
44069
44438
  })).filter((m) => m.name.length > 0);
44070
44439
  }
44071
44440
  function invalidateProbeDiscovery(providerSlug) {
44072
- for (const key of _cache.keys()) {
44441
+ for (const key of _cache2.keys()) {
44073
44442
  if (key.startsWith(`${providerSlug}:`)) {
44074
- _cache.delete(key);
44443
+ _cache2.delete(key);
44075
44444
  }
44076
44445
  }
44077
44446
  }
44078
- var _cache, CACHE_TTL_MS, FETCH_TIMEOUT_MS = 5000, SMALL_MODEL_PATTERNS, NON_CHAT_PATTERNS, STANDARD_VENDOR_PREFIXES;
44447
+ var _cache2, CACHE_TTL_MS2, FETCH_TIMEOUT_MS2 = 5000, SMALL_MODEL_PATTERNS, NON_CHAT_PATTERNS, STANDARD_VENDOR_PREFIXES;
44079
44448
  var init_probe_discovery = __esm(() => {
44080
44449
  init_logger();
44081
- _cache = new Map;
44082
- CACHE_TTL_MS = 5 * 60 * 1000;
44450
+ _cache2 = new Map;
44451
+ CACHE_TTL_MS2 = 5 * 60 * 1000;
44083
44452
  SMALL_MODEL_PATTERNS = [
44084
44453
  /\bmini\b/i,
44085
44454
  /\bnano\b/i,
@@ -44127,6 +44496,127 @@ var init_probe_discovery = __esm(() => {
44127
44496
  ];
44128
44497
  });
44129
44498
 
44499
+ // src/providers/transport/anthropic-compat.ts
44500
+ class AnthropicProviderTransport {
44501
+ name;
44502
+ displayName;
44503
+ streamFormat = "anthropic-sse";
44504
+ provider;
44505
+ apiKey;
44506
+ constructor(provider, apiKey) {
44507
+ this.provider = provider;
44508
+ this.apiKey = apiKey;
44509
+ this.name = provider.name;
44510
+ this.displayName = AnthropicProviderTransport.formatDisplayName(provider.name);
44511
+ }
44512
+ getEndpoint() {
44513
+ return `${this.provider.baseUrl}${this.provider.apiPath}`;
44514
+ }
44515
+ async getHeaders() {
44516
+ const headers = {
44517
+ "anthropic-version": "2023-06-01"
44518
+ };
44519
+ if (this.provider.authScheme === "bearer") {
44520
+ headers.Authorization = `Bearer ${this.apiKey}`;
44521
+ } else {
44522
+ headers["x-api-key"] = this.apiKey;
44523
+ }
44524
+ if (this.provider.headers) {
44525
+ Object.assign(headers, this.provider.headers);
44526
+ }
44527
+ if (this.provider.name === "kimi-coding") {
44528
+ try {
44529
+ const auth = await credentials.getRequestAuth("kimi-coding", { model: "" });
44530
+ if (auth.headers.Authorization) {
44531
+ delete headers["x-api-key"];
44532
+ }
44533
+ Object.assign(headers, auth.headers);
44534
+ } catch (e) {
44535
+ log(`[${this.displayName}] OAuth path failed, falling back to API key: ${e.message}`);
44536
+ }
44537
+ }
44538
+ return headers;
44539
+ }
44540
+ async discoverProbeModel(exclude) {
44541
+ const def = getProviderByName(this.provider.name);
44542
+ if (!def?.modelDiscovery) {
44543
+ return {
44544
+ model: null,
44545
+ reason: `${this.displayName} publishes no live model list (no modelDiscovery endpoint) \u2014 its probe model must come from the cloud catalog`
44546
+ };
44547
+ }
44548
+ const discovered = await discoverProviderModels(this.provider.name);
44549
+ if (discovered.length === 0) {
44550
+ return {
44551
+ model: null,
44552
+ reason: `${this.displayName} listed no models at ${def.modelDiscovery.path} \u2014 check the API key and that the subscription is active`
44553
+ };
44554
+ }
44555
+ const ranked = rankDiscoveredModels(discovered).map((m) => m.id).filter(isChatCapable);
44556
+ if (ranked.length === 0) {
44557
+ return {
44558
+ model: null,
44559
+ reason: `no chat-capable model among the ${discovered.length} listed by ${this.displayName}`
44560
+ };
44561
+ }
44562
+ const pick2 = ranked.find((m) => !exclude?.has(m));
44563
+ if (!pick2) {
44564
+ return {
44565
+ model: null,
44566
+ reason: `all ${ranked.length} candidate model(s) already tried`
44567
+ };
44568
+ }
44569
+ return { model: pick2 };
44570
+ }
44571
+ async enqueueRequest(fetchFn) {
44572
+ const maxRetries = 2;
44573
+ let lastResponse = null;
44574
+ for (let attempt = 0;attempt <= maxRetries; attempt++) {
44575
+ const response = await fetchFn();
44576
+ if (response.status === 429 && attempt < maxRetries) {
44577
+ const bodyText = await response.clone().text().catch(() => "");
44578
+ if (isTerminal429(bodyText)) {
44579
+ log(`[${this.displayName}] 429 is terminal (billing/quota), not retrying`);
44580
+ return response;
44581
+ }
44582
+ lastResponse = response;
44583
+ const retryAfter = response.headers.get("Retry-After");
44584
+ let delayMs;
44585
+ if (retryAfter && !Number.isNaN(Number(retryAfter))) {
44586
+ delayMs = Math.min(Number(retryAfter) * 1000, 2000);
44587
+ } else {
44588
+ delayMs = 500 * (attempt + 1);
44589
+ }
44590
+ log(`[${this.displayName}] 429 rate limited, retry ${attempt + 1}/${maxRetries} in ${(delayMs / 1000).toFixed(1)}s`);
44591
+ await new Promise((resolve2) => setTimeout(resolve2, delayMs));
44592
+ continue;
44593
+ }
44594
+ return response;
44595
+ }
44596
+ return lastResponse;
44597
+ }
44598
+ static formatDisplayName(name) {
44599
+ const map3 = {
44600
+ minimax: "MiniMax",
44601
+ "minimax-coding": "MiniMax Coding",
44602
+ kimi: "Kimi",
44603
+ "kimi-coding": "Kimi Coding",
44604
+ "qwen-cloud": "Qwen Plan",
44605
+ moonshot: "Kimi",
44606
+ "z-ai": "Z.AI"
44607
+ };
44608
+ return map3[name.toLowerCase()] || name.charAt(0).toUpperCase() + name.slice(1);
44609
+ }
44610
+ }
44611
+ var init_anthropic_compat = __esm(() => {
44612
+ init_authority();
44613
+ init_logger();
44614
+ init_model_discovery();
44615
+ init_provider_definitions();
44616
+ init_openai();
44617
+ init_probe_discovery();
44618
+ });
44619
+
44130
44620
  // src/providers/transport/litellm.ts
44131
44621
  class LiteLLMProviderTransport {
44132
44622
  name = "litellm";
@@ -44549,14 +45039,14 @@ function resolveApiKeyProvenance(envVar, aliases) {
44549
45039
  }
44550
45040
  return {
44551
45041
  envVar: runtimeVar,
44552
- effectiveValue: runtimeValue,
45042
+ hasValue: !!runtimeValue,
44553
45043
  effectiveMasked: maskKey(runtimeValue),
44554
45044
  effectiveSource,
44555
45045
  layers
44556
45046
  };
44557
45047
  }
44558
45048
  function formatProvenanceLog(p) {
44559
- if (!p.effectiveValue) {
45049
+ if (!p.hasValue) {
44560
45050
  return `${p.envVar}=(not set)`;
44561
45051
  }
44562
45052
  return `${p.envVar}=${p.effectiveMasked} [from: ${p.effectiveSource}]`;
@@ -45324,6 +45814,7 @@ var init_provider_profiles = __esm(() => {
45324
45814
  "minimax-coding": anthropicCompatProfile,
45325
45815
  kimi: anthropicCompatProfile,
45326
45816
  "kimi-coding": anthropicCompatProfile,
45817
+ "qwen-cloud": anthropicCompatProfile,
45327
45818
  "z-ai": anthropicCompatProfile,
45328
45819
  glm: glmProfile,
45329
45820
  "glm-coding": glmProfile,
@@ -46097,7 +46588,7 @@ function loadDiskCache() {
46097
46588
  return false;
46098
46589
  const stat2 = statSync4(CACHE_FILE);
46099
46590
  const age = Date.now() - stat2.mtimeMs;
46100
- const isFresh = age < CACHE_TTL_MS2;
46591
+ const isFresh = age < CACHE_TTL_MS3;
46101
46592
  const raw2 = readFileSync15(CACHE_FILE, "utf-8");
46102
46593
  const data = JSON.parse(raw2);
46103
46594
  for (const [key, pricing] of Object.entries(data)) {
@@ -46108,7 +46599,7 @@ function loadDiskCache() {
46108
46599
  return false;
46109
46600
  }
46110
46601
  }
46111
- var pricingMap, CACHE_DIR, CACHE_FILE, CACHE_TTL_MS2, cacheWarmed = false;
46602
+ var pricingMap, CACHE_DIR, CACHE_FILE, CACHE_TTL_MS3, cacheWarmed = false;
46112
46603
  var init_pricing_cache = __esm(() => {
46113
46604
  init_remote_provider_types();
46114
46605
  init_logger();
@@ -46116,7 +46607,7 @@ var init_pricing_cache = __esm(() => {
46116
46607
  pricingMap = new Map;
46117
46608
  CACHE_DIR = join24(homedir24(), ".claudish");
46118
46609
  CACHE_FILE = join24(CACHE_DIR, "pricing-cache.json");
46119
- CACHE_TTL_MS2 = 24 * 60 * 60 * 1000;
46610
+ CACHE_TTL_MS3 = 24 * 60 * 60 * 1000;
46120
46611
  });
46121
46612
 
46122
46613
  // src/proxy-server.ts
@@ -47407,6 +47898,10 @@ function fuzzyScore(text, query) {
47407
47898
  }
47408
47899
  return queryIndex === lowerQuery.length ? score / lowerText.length : 0;
47409
47900
  }
47901
+ function orderingKey(model) {
47902
+ const releaseDate = typeof model?.releaseDate === "string" ? model.releaseDate : typeof model?.created === "number" && Number.isFinite(model.created) ? new Date(model.created * 1000).toISOString() : undefined;
47903
+ return { releaseDate, id: typeof model?.id === "string" ? model.id : "" };
47904
+ }
47410
47905
  function fmtSize(n) {
47411
47906
  if (n <= 0)
47412
47907
  return "0B";
@@ -47634,13 +48129,17 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
47634
48129
  isError: true
47635
48130
  };
47636
48131
  }
47637
- const results = allModels.map((model) => {
48132
+ const results2 = allModels.map((model) => {
47638
48133
  const nameScore = fuzzyScore(model.name || "", query);
47639
48134
  const idScore = fuzzyScore(model.id || "", query);
47640
48135
  const descScore = fuzzyScore(model.description || "", query) * 0.5;
47641
48136
  return { model, score: Math.max(nameScore, idScore, descScore) };
47642
- }).filter((item) => item.score > 0.2).sort((a, b) => b.score - a.score).slice(0, maxResults);
47643
- if (results.length === 0) {
48137
+ }).filter((item) => item.score > 0.2).sort((a, b) => {
48138
+ if (Math.abs(a.score - b.score) > SCORE_TIE_EPSILON)
48139
+ return b.score - a.score;
48140
+ return compareByReleaseDateDesc(orderingKey(a.model), orderingKey(b.model));
48141
+ }).slice(0, maxResults);
48142
+ if (results2.length === 0) {
47644
48143
  return {
47645
48144
  content: [{ type: "text", text: `No models found matching "${query}"` }]
47646
48145
  };
@@ -47652,7 +48151,7 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
47652
48151
  `;
47653
48152
  output += `|-------|----------|---------|----------|
47654
48153
  `;
47655
- for (const { model } of results) {
48154
+ for (const { model } of results2) {
47656
48155
  const provider = model.id.split("/")[0];
47657
48156
  const promptPrice = Number.parseFloat(model.pricing?.prompt || "0") * 1e6;
47658
48157
  const completionPrice = Number.parseFloat(model.pricing?.completion || "0") * 1e6;
@@ -47663,7 +48162,7 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
47663
48162
  `;
47664
48163
  }
47665
48164
  output += `
47666
- Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
48165
+ Use with: run_prompt(model="${results2[0].model.id}", prompt="your prompt")`;
47667
48166
  return { content: [{ type: "text", text: output }] };
47668
48167
  }
47669
48168
  });
@@ -47693,13 +48192,13 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
47693
48192
  const prompt = args.prompt;
47694
48193
  const systemPrompt = args.system_prompt;
47695
48194
  const maxTokens = args.max_tokens;
47696
- const results = [];
48195
+ const results2 = [];
47697
48196
  for (const model of modelIds) {
47698
48197
  try {
47699
48198
  const result = await runPromptViaProxy(model, prompt, systemPrompt, maxTokens);
47700
- results.push({ model, response: result.content, tokens: result.usage });
48199
+ results2.push({ model, response: result.content, tokens: result.usage });
47701
48200
  } catch (error46) {
47702
- results.push({
48201
+ results2.push({
47703
48202
  model,
47704
48203
  response: "",
47705
48204
  error: error46 instanceof Error ? error46.message : String(error46)
@@ -47712,7 +48211,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
47712
48211
  output += `**Prompt:** ${prompt.slice(0, 100)}${prompt.length > 100 ? "..." : ""}
47713
48212
 
47714
48213
  `;
47715
- for (const result of results) {
48214
+ for (const result of results2) {
47716
48215
  output += `## ${result.model}
47717
48216
 
47718
48217
  `;
@@ -47734,7 +48233,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
47734
48233
 
47735
48234
  `;
47736
48235
  }
47737
- const failed = results.filter((r) => r.error);
48236
+ const failed = results2.filter((r) => r.error);
47738
48237
  if (failed.length > 0) {
47739
48238
  output += '---\n**To report failed model(s)**, use the `report_error` tool with `error_type: "provider_failure"` and the model ID(s) above.\n';
47740
48239
  }
@@ -48296,7 +48795,7 @@ When channel mode is active, you receive <channel source="claudish" ...> notific
48296
48795
  5. Use list_sessions to see all active/completed sessions.
48297
48796
  6. Use cancel_session to stop a running session.
48298
48797
 
48299
- The session_id in the channel tag's meta attributes is the key for all tool calls.`, proxyInstance = null, proxyStarting = null, NEXT_STEP, sanitize, EVENT_TO_TASK_STATUS;
48798
+ The session_id in the channel tag's meta attributes is the key for all tool calls.`, proxyInstance = null, proxyStarting = null, SCORE_TIE_EPSILON = 0.000001, NEXT_STEP, sanitize, EVENT_TO_TASK_STATUS;
48300
48799
  var init_mcp_server = __esm(() => {
48301
48800
  init_server2();
48302
48801
  init_stdio2();
@@ -60761,13 +61260,13 @@ var init_dist14 = __esm(() => {
60761
61260
  setSearchError(undefined);
60762
61261
  const fetchResults = async () => {
60763
61262
  try {
60764
- const results = await config3.source(searchTerm || undefined, {
61263
+ const results2 = await config3.source(searchTerm || undefined, {
60765
61264
  signal: controller.signal
60766
61265
  });
60767
61266
  if (!controller.signal.aborted) {
60768
61267
  setActive(undefined);
60769
61268
  setSearchError(undefined);
60770
- setSearchResults(normalizeChoices4(results));
61269
+ setSearchResults(normalizeChoices4(results2));
60771
61270
  setStatus("idle");
60772
61271
  }
60773
61272
  } catch (error47) {
@@ -61475,6 +61974,8 @@ var init_config2 = __esm(() => {
61475
61974
  CLAUDISH_MODEL: "CLAUDISH_MODEL",
61476
61975
  CLAUDISH_PORT: "CLAUDISH_PORT",
61477
61976
  CLAUDISH_ACTIVE_MODEL_NAME: "CLAUDISH_ACTIVE_MODEL_NAME",
61977
+ CLAUDISH_TOKEN_FILE: "CLAUDISH_TOKEN_FILE",
61978
+ CLAUDISH_PROVIDER_NAME: "CLAUDISH_PROVIDER_NAME",
61478
61979
  ANTHROPIC_MODEL: "ANTHROPIC_MODEL",
61479
61980
  ANTHROPIC_SMALL_FAST_MODEL: "ANTHROPIC_SMALL_FAST_MODEL",
61480
61981
  CLAUDISH_MODEL_OPUS: "CLAUDISH_MODEL_OPUS",
@@ -61655,114 +62156,6 @@ var init_model_catalog2 = __esm(() => {
61655
62156
  NO_CATALOG_VENDOR_SLUGS = new Set(["litellm", "ollama", "lmstudio", "lm-studio"]);
61656
62157
  });
61657
62158
 
61658
- // src/providers/model-discovery.ts
61659
- function resolveBaseUrl2(catalogName) {
61660
- const def = getProviderByName(catalogName);
61661
- if (!def)
61662
- return null;
61663
- for (const envVar of def.baseUrlEnvVars ?? []) {
61664
- const v = process.env[envVar];
61665
- if (v)
61666
- return v.replace(/\/+$/, "");
61667
- }
61668
- return (def.baseUrl || "").replace(/\/+$/, "") || null;
61669
- }
61670
- function readContextWindow(row) {
61671
- for (const field of ["context_length", "context_window", "max_context_length"]) {
61672
- const v = row[field];
61673
- if (typeof v === "number" && Number.isFinite(v) && v > 0)
61674
- return v;
61675
- }
61676
- return;
61677
- }
61678
- function parseOpenAIModelsList(body) {
61679
- const data = body?.data;
61680
- if (!Array.isArray(data))
61681
- return [];
61682
- const models = [];
61683
- for (const raw2 of data) {
61684
- if (!raw2 || typeof raw2 !== "object")
61685
- continue;
61686
- const row = raw2;
61687
- const id = row.id;
61688
- if (typeof id !== "string" || id.trim().length === 0)
61689
- continue;
61690
- const displayName = typeof row.display_name === "string" ? row.display_name : undefined;
61691
- models.push({ id, displayName, contextWindow: readContextWindow(row) });
61692
- }
61693
- return models;
61694
- }
61695
- async function discoverProviderModels(providerName) {
61696
- const cached2 = _cache2.get(providerName);
61697
- if (cached2 && cached2.expiresAt > Date.now())
61698
- return cached2.models;
61699
- const def = getProviderByName(providerName);
61700
- const descriptor = def?.modelDiscovery;
61701
- if (!def || !descriptor)
61702
- return [];
61703
- const baseUrl = resolveBaseUrl2(providerName);
61704
- if (!baseUrl)
61705
- return [];
61706
- const endpoint = `${baseUrl}${descriptor.path}`;
61707
- let headers = {};
61708
- try {
61709
- const auth = await credentials.getRequestAuth(providerName, { model: "" });
61710
- headers = { ...auth.headers };
61711
- } catch (e) {
61712
- log(`[model-discovery:${providerName}] no credentials, skipping: ${e?.message}`);
61713
- return [];
61714
- }
61715
- let response;
61716
- try {
61717
- response = await fetch(endpoint, {
61718
- method: "GET",
61719
- headers,
61720
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
61721
- });
61722
- } catch (e) {
61723
- log(`[model-discovery:${providerName}] fetch failed: ${e?.message}`);
61724
- return [];
61725
- }
61726
- if (!response.ok) {
61727
- log(`[model-discovery:${providerName}] HTTP ${response.status} from ${endpoint}`);
61728
- return [];
61729
- }
61730
- let body;
61731
- try {
61732
- body = await response.json();
61733
- } catch {
61734
- log(`[model-discovery:${providerName}] response was not JSON`);
61735
- return [];
61736
- }
61737
- const models = parseOpenAIModelsList(body);
61738
- if (models.length === 0) {
61739
- log(`[model-discovery:${providerName}] endpoint reachable but listed no models`);
61740
- return [];
61741
- }
61742
- log(`[model-discovery:${providerName}] discovered ${models.length} models: ` + models.map((m) => `${m.id}(${m.contextWindow ?? "?"})`).join(", "));
61743
- _cache2.set(providerName, { models, expiresAt: Date.now() + CACHE_TTL_MS3 });
61744
- return models;
61745
- }
61746
- async function discoverContextWindow(providerName, modelId) {
61747
- const models = await discoverProviderModels(providerName);
61748
- const match2 = models.find((m) => m.id.toLowerCase() === modelId.toLowerCase());
61749
- return match2?.contextWindow;
61750
- }
61751
- function rankDiscoveredModels(models) {
61752
- return [...models].sort((a, b) => {
61753
- const diff = (b.contextWindow ?? 0) - (a.contextWindow ?? 0);
61754
- return diff !== 0 ? diff : a.id.localeCompare(b.id);
61755
- });
61756
- }
61757
- var CACHE_TTL_MS3, FETCH_TIMEOUT_MS2 = 5000, _cache2;
61758
- var init_model_discovery = __esm(() => {
61759
- init_authority();
61760
- init_logger();
61761
- init_provider_definitions();
61762
- CACHE_TTL_MS3 = 5 * 60 * 1000;
61763
- _cache2 = new Map;
61764
- });
61765
-
61766
62159
  // src/model-selector.ts
61767
62160
  var exports_model_selector = {};
61768
62161
  __export(exports_model_selector, {
@@ -61778,7 +62171,8 @@ __export(exports_model_selector, {
61778
62171
  isUserDeployedProvider: () => isUserDeployedProvider,
61779
62172
  confirmAction: () => confirmAction,
61780
62173
  compareByReleaseDateDesc: () => compareByReleaseDateDesc,
61781
- buildExplicitModelSpec: () => buildExplicitModelSpec
62174
+ buildExplicitModelSpec: () => buildExplicitModelSpec,
62175
+ buildDiscoveredModelRows: () => buildDiscoveredModelRows
61782
62176
  });
61783
62177
  function isUserDeployedProvider(value) {
61784
62178
  return LOCAL_OR_USER_DEPLOYED.has(value);
@@ -61810,7 +62204,7 @@ function formatFirebaseProviderLabel(slug) {
61810
62204
  async function loadRecommendedModels(forceRefresh = false) {
61811
62205
  try {
61812
62206
  const doc2 = await getRecommendedModels({ forceRefresh });
61813
- return doc2.models.map((model) => ({
62207
+ return sortModelsNewestFirst(doc2.models.map((model) => ({
61814
62208
  id: model.id,
61815
62209
  name: model.name,
61816
62210
  description: model.description,
@@ -61823,7 +62217,7 @@ async function loadRecommendedModels(forceRefresh = false) {
61823
62217
  supportsReasoning: model.supportsReasoning,
61824
62218
  supportsVision: model.supportsVision,
61825
62219
  source: formatFirebaseProviderLabel(model.provider)
61826
- }));
62220
+ })));
61827
62221
  } catch {
61828
62222
  return [];
61829
62223
  }
@@ -61867,6 +62261,48 @@ function formatAveragePricing(pricing) {
61867
62261
  average: avg === 0 ? "FREE" : `$${avg.toFixed(2)}/1M`
61868
62262
  };
61869
62263
  }
62264
+ function resolveDiscoveredContextLength(m) {
62265
+ if (typeof m.contextWindow === "number" && m.contextWindow > 0)
62266
+ return m.contextWindow;
62267
+ try {
62268
+ return lookupModel(m.id)?.contextWindow ?? 0;
62269
+ } catch {
62270
+ return 0;
62271
+ }
62272
+ }
62273
+ function resolveDiscoveredReleaseDate(m) {
62274
+ try {
62275
+ const catalogDate = lookupModel(m.id)?.releaseDate;
62276
+ if (catalogDate)
62277
+ return catalogDate;
62278
+ } catch {}
62279
+ return m.releaseDate;
62280
+ }
62281
+ async function resolveMissingContextWindows(ids, timeoutMs = DISCOVERY_CONTEXT_LOOKUP_TIMEOUT_MS) {
62282
+ const resolved = new Map;
62283
+ if (ids.length === 0)
62284
+ return resolved;
62285
+ let timer;
62286
+ const budget = new Promise((resolve4) => {
62287
+ timer = setTimeout(() => resolve4(null), timeoutMs);
62288
+ timer.unref?.();
62289
+ });
62290
+ try {
62291
+ const lookups = Promise.all(ids.map(async (id) => [id, await resolveCatalogContextWindow(id)]));
62292
+ const settled = await Promise.race([lookups, budget]);
62293
+ if (settled) {
62294
+ for (const [id, contextWindow] of settled) {
62295
+ if (typeof contextWindow === "number" && contextWindow > 0) {
62296
+ resolved.set(id, contextWindow);
62297
+ }
62298
+ }
62299
+ }
62300
+ } catch {} finally {
62301
+ if (timer)
62302
+ clearTimeout(timer);
62303
+ }
62304
+ return resolved;
62305
+ }
61870
62306
  function modelDocToModelInfo(model) {
61871
62307
  const providerLabel = formatFirebaseProviderLabel(model.provider || "unknown");
61872
62308
  const contextLength = model.contextWindow || 0;
@@ -61918,63 +62354,6 @@ function dedupeModels(models) {
61918
62354
  }
61919
62355
  return deduped;
61920
62356
  }
61921
- function extractVersionParts(modelId) {
61922
- const tokens = modelId.toLowerCase().split(/[\/_-]+/);
61923
- let started = false;
61924
- const parts = [];
61925
- for (const token of tokens) {
61926
- const match2 = token.match(/\d+(?:\.\d+)*/);
61927
- if (!match2) {
61928
- if (started)
61929
- break;
61930
- continue;
61931
- }
61932
- if (!started) {
61933
- started = true;
61934
- for (const part of match2[0].split(".")) {
61935
- parts.push(Number.parseInt(part, 10));
61936
- }
61937
- if (!/^\d+(?:\.\d+)*$/.test(token)) {
61938
- break;
61939
- }
61940
- continue;
61941
- }
61942
- if (!/^\d{1,2}(?:\.\d+)?$/.test(token)) {
61943
- break;
61944
- }
61945
- for (const part of token.split(".")) {
61946
- parts.push(Number.parseInt(part, 10));
61947
- }
61948
- }
61949
- return parts;
61950
- }
61951
- function compareVersionPartsDesc(a, b) {
61952
- const maxLength = Math.max(a.length, b.length);
61953
- for (let i = 0;i < maxLength; i++) {
61954
- const aPart = a[i] ?? -1;
61955
- const bPart = b[i] ?? -1;
61956
- if (aPart !== bPart) {
61957
- return bPart - aPart;
61958
- }
61959
- }
61960
- return 0;
61961
- }
61962
- function compareByReleaseDateDesc(a, b) {
61963
- const aReleaseRaw = a.releaseDate ? Date.parse(a.releaseDate) : 0;
61964
- const bReleaseRaw = b.releaseDate ? Date.parse(b.releaseDate) : 0;
61965
- const aRelease = Number.isNaN(aReleaseRaw) ? 0 : aReleaseRaw;
61966
- const bRelease = Number.isNaN(bReleaseRaw) ? 0 : bReleaseRaw;
61967
- if (aRelease !== bRelease) {
61968
- return bRelease - aRelease;
61969
- }
61970
- const aId = a.id ?? a.modelId ?? "";
61971
- const bId = b.id ?? b.modelId ?? "";
61972
- const versionCompare = compareVersionPartsDesc(extractVersionParts(aId), extractVersionParts(bId));
61973
- if (versionCompare !== 0) {
61974
- return versionCompare;
61975
- }
61976
- return aId.localeCompare(bId);
61977
- }
61978
62357
  function sortModelsNewestFirst(models) {
61979
62358
  return [...models].sort(compareByReleaseDateDesc);
61980
62359
  }
@@ -62272,22 +62651,42 @@ async function pickModelFromList(provider, displayName, tierName, models) {
62272
62651
  });
62273
62652
  return selected === CUSTOM_VALUE ? null : selected;
62274
62653
  }
62654
+ async function buildDiscoveredModelRows(provider, displayName, catalog) {
62655
+ const discovered = rankDiscoveredModels(await discoverProviderModels(provider)).filter((m) => isChatCapable(m.id));
62656
+ if (discovered.length === 0)
62657
+ return [];
62658
+ const subscription = isSubscriptionProvider(provider);
62659
+ const pricingById = subscription ? new Map : new Map((await loadModelsForPickerProvider(provider, catalog)).map((m) => [
62660
+ m.id.toLowerCase(),
62661
+ m.pricing
62662
+ ]));
62663
+ const offlineContext = new Map(discovered.map((m) => [m.id, resolveDiscoveredContextLength(m)]));
62664
+ const cloudContext = await resolveMissingContextWindows(discovered.filter((m) => !offlineContext.get(m.id)).map((m) => m.id));
62665
+ const rows = discovered.map((m) => {
62666
+ const contextLength = offlineContext.get(m.id) || cloudContext.get(m.id) || 0;
62667
+ return {
62668
+ id: m.id,
62669
+ name: m.displayName || m.id,
62670
+ description: contextLength ? `${m.displayName ?? m.id} \xB7 ${Math.round(contextLength / 1024)}K context` : m.displayName ?? m.id,
62671
+ provider: displayName,
62672
+ releaseDate: resolveDiscoveredReleaseDate(m),
62673
+ pricing: subscription ? SUBSCRIPTION_PRICING : pricingById.get(m.id.toLowerCase()),
62674
+ context: formatContextLength(contextLength),
62675
+ contextLength,
62676
+ supportsTools: true,
62677
+ isFree: subscription,
62678
+ source: displayName
62679
+ };
62680
+ });
62681
+ return sortModelsNewestFirst(rows);
62682
+ }
62275
62683
  async function selectModelFromProvider(provider, tierName, recommendedModels, _forceUpdate, catalog) {
62276
62684
  const prefix = PROVIDER_MODEL_PREFIX[provider] || `${provider}@`;
62277
62685
  const displayName = getPickerDisplayName(provider);
62278
62686
  const def = getProviderByName(provider);
62279
62687
  if (def?.modelDiscovery) {
62280
- const discovered = rankDiscoveredModels(await discoverProviderModels(provider));
62281
- if (discovered.length > 0) {
62282
- const discoveredModels = discovered.map((m) => ({
62283
- id: m.id,
62284
- name: m.displayName || m.id,
62285
- description: m.contextWindow ? `${m.displayName ?? m.id} \xB7 ${Math.round(m.contextWindow / 1024)}K context` : m.displayName ?? m.id,
62286
- provider: displayName,
62287
- supportsTools: true,
62288
- isFree: true,
62289
- source: displayName
62290
- }));
62688
+ const discoveredModels = await buildDiscoveredModelRows(provider, displayName, catalog);
62689
+ if (discoveredModels.length > 0) {
62291
62690
  const picked = await pickModelFromList(provider, displayName, tierName, discoveredModels);
62292
62691
  if (picked)
62293
62692
  return picked;
@@ -62295,7 +62694,7 @@ async function selectModelFromProvider(provider, tierName, recommendedModels, _f
62295
62694
  }
62296
62695
  if (provider === "ollama") {
62297
62696
  const ollamaModels = await fetchOllamaModels({ enrichCapabilities: false });
62298
- const chatModels = ollamaModels.map((m) => ({
62697
+ const chatModels = sortModelsNewestFirst(ollamaModels.map((m) => ({
62299
62698
  id: m.name,
62300
62699
  name: m.name,
62301
62700
  description: m.description,
@@ -62303,7 +62702,7 @@ async function selectModelFromProvider(provider, tierName, recommendedModels, _f
62303
62702
  supportsTools: m.supportsTools,
62304
62703
  isFree: true,
62305
62704
  source: displayName
62306
- }));
62705
+ })));
62307
62706
  if (chatModels.length > 0) {
62308
62707
  const picked = await pickModelFromList(provider, displayName, tierName, chatModels);
62309
62708
  if (picked)
@@ -62464,14 +62863,18 @@ async function selectProfile(profiles) {
62464
62863
  async function confirmAction(message) {
62465
62864
  return dist_default4({ message, default: false });
62466
62865
  }
62467
- var pickerProviderToFirebaseSlug, LOCAL_OR_USER_DEPLOYED, PROVIDER_FILTER_ALIASES, ALL_PROVIDER_CHOICES, PROVIDER_MODEL_PREFIX;
62866
+ var pickerProviderToFirebaseSlug, LOCAL_OR_USER_DEPLOYED, SUBSCRIPTION_PRICING, DISCOVERY_CONTEXT_LOOKUP_TIMEOUT_MS = 1500, PROVIDER_FILTER_ALIASES, ALL_PROVIDER_CHOICES, PROVIDER_MODEL_PREFIX;
62468
62867
  var init_model_selector = __esm(() => {
62469
62868
  init_dist16();
62869
+ init_model_catalog();
62470
62870
  init_authority();
62871
+ init_context_window_fallback();
62872
+ init_remote_provider_types();
62471
62873
  init_model_loader();
62472
62874
  init_model_catalog2();
62473
62875
  init_model_discovery();
62474
62876
  init_provider_definitions();
62877
+ init_probe_discovery();
62475
62878
  pickerProviderToFirebaseSlug = {
62476
62879
  openrouter: "openrouter",
62477
62880
  google: "google",
@@ -62495,6 +62898,11 @@ var init_model_selector = __esm(() => {
62495
62898
  ollamacloud: "ollamacloud"
62496
62899
  };
62497
62900
  LOCAL_OR_USER_DEPLOYED = new Set(["litellm", "ollama", "lmstudio"]);
62901
+ SUBSCRIPTION_PRICING = {
62902
+ input: "SUB",
62903
+ output: "SUB",
62904
+ average: "SUB"
62905
+ };
62498
62906
  PROVIDER_FILTER_ALIASES = {
62499
62907
  openrouter: "openrouter",
62500
62908
  or: "openrouter",
@@ -62531,7 +62939,9 @@ var init_model_selector = __esm(() => {
62531
62939
  sakana: "sakana",
62532
62940
  fugu: "sakana",
62533
62941
  "sakana-subscription": "sakana-subscription",
62534
- sc: "sakana-subscription"
62942
+ sc: "sakana-subscription",
62943
+ "qwen-cloud": "qwen-cloud",
62944
+ qc: "qwen-cloud"
62535
62945
  };
62536
62946
  ALL_PROVIDER_CHOICES = [
62537
62947
  {
@@ -62582,6 +62992,12 @@ var init_model_selector = __esm(() => {
62582
62992
  description: "Coding subscription",
62583
62993
  provider: "kimi-coding"
62584
62994
  },
62995
+ {
62996
+ name: "Qwen Plan",
62997
+ value: "qwen-cloud",
62998
+ description: "Alibaba Model Studio subscription",
62999
+ provider: "qwen-cloud"
63000
+ },
62585
63001
  { name: "GLM / Zhipu", value: "glm", description: "Direct API", provider: "glm" },
62586
63002
  {
62587
63003
  name: "GLM Coding Plan",
@@ -62628,6 +63044,7 @@ var init_model_selector = __esm(() => {
62628
63044
  kimi: "kimi@",
62629
63045
  "minimax-coding": "mmc@",
62630
63046
  "kimi-coding": "kc@",
63047
+ "qwen-cloud": "qc@",
62631
63048
  glm: "glm@",
62632
63049
  "glm-coding": "gc@",
62633
63050
  "z-ai": "z-ai@",
@@ -63251,7 +63668,7 @@ function wordWrap(text, maxWidth) {
63251
63668
  lines.push(current);
63252
63669
  return lines;
63253
63670
  }
63254
- function computeBarScales(results) {
63671
+ function computeBarScales(results2) {
63255
63672
  let maxTokPerSec = 1;
63256
63673
  const liveTotals = [];
63257
63674
  const consider = (probe) => {
@@ -63264,7 +63681,7 @@ function computeBarScales(results) {
63264
63681
  if (scaledTps > maxTokPerSec)
63265
63682
  maxTokPerSec = scaledTps;
63266
63683
  };
63267
- for (const r of results) {
63684
+ for (const r of results2) {
63268
63685
  consider(r.directProbe);
63269
63686
  for (const c of r.chain ?? [])
63270
63687
  consider(c.probe);
@@ -63564,7 +63981,7 @@ function formatContextWindow(ctx) {
63564
63981
  function buildKeyLine(activeEntry, directKeyVar) {
63565
63982
  if (activeEntry?.provenance) {
63566
63983
  const p = activeEntry.provenance;
63567
- if (p.effectiveValue) {
63984
+ if (p.hasValue) {
63568
63985
  return `${pc.bold}Key${pc.reset} $${p.envVar} ${pc.dim}(${p.effectiveSource})${pc.reset}`;
63569
63986
  }
63570
63987
  return `${pc.bold}Key${pc.reset} $${p.envVar} ${pc.dim}(not set)${pc.reset}`;
@@ -63720,8 +64137,8 @@ function pickRepresentative(result) {
63720
64137
  }
63721
64138
  return { model: result.model, provider: result.nativeProvider };
63722
64139
  }
63723
- function renderLeaderboard(results, scales, maxWidth, w) {
63724
- const reps = results.map(pickRepresentative);
64140
+ function renderLeaderboard(results2, scales, maxWidth, w) {
64141
+ const reps = results2.map(pickRepresentative);
63725
64142
  const live = reps.filter((r) => r.timing).sort((a, b) => a.timing.totalMs - b.timing.totalMs);
63726
64143
  const unavailable = reps.filter((r) => !r.timing);
63727
64144
  if (live.length === 0)
@@ -63822,16 +64239,16 @@ function renderLeaderboard(results, scales, maxWidth, w) {
63822
64239
  w(`
63823
64240
  `);
63824
64241
  }
63825
- function printProbeResults(results, isLiveProbe) {
64242
+ function printProbeResults(results2, isLiveProbe) {
63826
64243
  const w = process.stderr.write.bind(process.stderr);
63827
64244
  w(`
63828
64245
  `);
63829
- const scales = computeBarScales(results);
63830
- const anyTimedLive = results.some((r) => r.directProbe?.state === "live" && r.directProbe.timing !== undefined) || results.some((r) => (r.chain ?? []).some((c) => c.probe?.state === "live" && c.probe.timing !== undefined));
64246
+ const scales = computeBarScales(results2);
64247
+ const anyTimedLive = results2.some((r) => r.directProbe?.state === "live" && r.directProbe.timing !== undefined) || results2.some((r) => (r.chain ?? []).some((c) => c.probe?.state === "live" && c.probe.timing !== undefined));
63831
64248
  if (isLiveProbe && anyTimedLive) {
63832
64249
  renderLegend(w);
63833
64250
  }
63834
- const requiredWidths = results.map((r) => computeRequiredWidth(r, isLiveProbe));
64251
+ const requiredWidths = results2.map((r) => computeRequiredWidth(r, isLiveProbe));
63835
64252
  const termCols = process.stderr.columns ?? process.stdout.columns ?? 100;
63836
64253
  const maxAllowed = Math.max(MIN_CARD_WIDTH, termCols - 4);
63837
64254
  let globalWidth = requiredWidths.reduce((a, b) => Math.max(a, b), MIN_CARD_WIDTH);
@@ -63839,14 +64256,14 @@ function printProbeResults(results, isLiveProbe) {
63839
64256
  globalWidth = maxAllowed;
63840
64257
  const showedLeaderboard = isLiveProbe && anyTimedLive;
63841
64258
  if (showedLeaderboard) {
63842
- renderLeaderboard(results, scales, maxAllowed, w);
64259
+ renderLeaderboard(results2, scales, maxAllowed, w);
63843
64260
  }
63844
64261
  if (showedLeaderboard) {
63845
64262
  w(` ${pc.bold}${pc.cyan}Details${pc.reset}${pc.dim} \u2014 per-model routing chains${pc.reset}
63846
64263
 
63847
64264
  `);
63848
64265
  }
63849
- for (const result of results) {
64266
+ for (const result of results2) {
63850
64267
  renderCard(result, isLiveProbe, w, globalWidth, scales);
63851
64268
  w(`
63852
64269
  `);
@@ -63898,8 +64315,8 @@ class ProbeStore {
63898
64315
  for (const fn of this.listeners)
63899
64316
  fn();
63900
64317
  }
63901
- setResults(results) {
63902
- this.setState((prev) => ({ ...prev, results, phase: "done" }));
64318
+ setResults(results2) {
64319
+ this.setState((prev) => ({ ...prev, results: results2, phase: "done" }));
63903
64320
  }
63904
64321
  setActiveTab(tab) {
63905
64322
  this.setState((prev) => ({ ...prev, activeTab: tab }));
@@ -64740,24 +65157,24 @@ function DetailModel({
64740
65157
  }, undefined, true, undefined, this);
64741
65158
  }
64742
65159
  function DetailsView({
64743
- results,
65160
+ results: results2,
64744
65161
  layout,
64745
65162
  termWidth,
64746
65163
  maxTotalMs,
64747
65164
  maxTokPerSec
64748
65165
  }) {
64749
- const provW = Math.min(22, Math.max(8, ...results.flatMap((r) => r.links.map((l) => l.displayName.length))));
65166
+ const provW = Math.min(22, Math.max(8, ...results2.flatMap((r) => r.links.map((l) => l.displayName.length))));
64750
65167
  const headerW = Math.max(24, Math.min(detailRowWidth(provW, layout), (termWidth || 100) - 3));
64751
65168
  return /* @__PURE__ */ jsxDEV("box", {
64752
65169
  flexDirection: "column",
64753
- children: results.map((r, idx) => /* @__PURE__ */ jsxDEV(DetailModel, {
65170
+ children: results2.map((r, idx) => /* @__PURE__ */ jsxDEV(DetailModel, {
64754
65171
  result: r,
64755
65172
  provW,
64756
65173
  headerW,
64757
65174
  layout,
64758
65175
  maxTotalMs,
64759
65176
  maxTokPerSec,
64760
- isLast: idx === results.length - 1
65177
+ isLast: idx === results2.length - 1
64761
65178
  }, r.model, false, undefined, this))
64762
65179
  }, undefined, false, undefined, this);
64763
65180
  }
@@ -64931,12 +65348,12 @@ function LeaderLiveRow({
64931
65348
  }, undefined, true, undefined, this);
64932
65349
  }
64933
65350
  function LeaderboardView({
64934
- results,
65351
+ results: results2,
64935
65352
  layout,
64936
65353
  maxTotalMs,
64937
65354
  maxTokPerSec
64938
65355
  }) {
64939
- const reps = results.map(pickRepresentativeLink);
65356
+ const reps = results2.map(pickRepresentativeLink);
64940
65357
  const live = reps.filter((r) => r.timing).sort((a, b) => a.timing.totalMs - b.timing.totalMs);
64941
65358
  const unavailable = reps.filter((r) => !r.timing);
64942
65359
  const nameW = Math.min(28, Math.max(5, ...reps.map((r) => r.model.length)));
@@ -65785,16 +66202,16 @@ function formatModelDocCaps(caps) {
65785
66202
  return parts.length > 0 ? parts.join("") : "\xB7";
65786
66203
  }
65787
66204
  async function searchAndPrintModels(query, jsonOutput) {
65788
- let results;
66205
+ let results2;
65789
66206
  try {
65790
66207
  console.error(`\uD83D\uDD04 Searching Firebase catalog for "${query}"...`);
65791
- results = await searchModels(query, 50);
66208
+ results2 = await searchModels(query, 50);
65792
66209
  } catch (error46) {
65793
66210
  console.error(`\u274C Failed to reach Firebase model catalog: ${error46 instanceof Error ? error46.message : String(error46)}`);
65794
66211
  console.error(" Check your network connection.");
65795
66212
  process.exit(1);
65796
66213
  }
65797
- if (results.length === 0) {
66214
+ if (results2.length === 0) {
65798
66215
  if (jsonOutput) {
65799
66216
  console.log(JSON.stringify({ query, count: 0, models: [] }, null, 2));
65800
66217
  } else {
@@ -65805,8 +66222,8 @@ async function searchAndPrintModels(query, jsonOutput) {
65805
66222
  if (jsonOutput) {
65806
66223
  console.log(JSON.stringify({
65807
66224
  query,
65808
- count: results.length,
65809
- models: results.map((m) => ({
66225
+ count: results2.length,
66226
+ models: results2.map((m) => ({
65810
66227
  id: m.modelId,
65811
66228
  provider: m.provider,
65812
66229
  contextWindow: m.contextWindow,
@@ -65819,9 +66236,9 @@ async function searchAndPrintModels(query, jsonOutput) {
65819
66236
  return;
65820
66237
  }
65821
66238
  console.log(`
65822
- Found ${results.length} matching models:
66239
+ Found ${results2.length} matching models:
65823
66240
  `);
65824
- const sorted = [...results].sort(compareByReleaseDateDesc);
66241
+ const sorted = [...results2].sort(compareByReleaseDateDesc);
65825
66242
  renderModelDocTable(sorted, false);
65826
66243
  console.log("");
65827
66244
  console.log("Caps: T = tools R = reasoning V = vision");
@@ -66112,7 +66529,7 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
66112
66529
  hasCredentials = true;
66113
66530
  } else {
66114
66531
  provenance = resolveApiKeyProvenance(keyInfo.envVar, keyInfo.aliases);
66115
- hasCredentials = !!provenance.effectiveValue;
66532
+ hasCredentials = provenance.hasValue;
66116
66533
  if (!hasCredentials && keyInfo.aliases) {
66117
66534
  hasCredentials = keyInfo.aliases.some((a) => !!process.env[a]);
66118
66535
  }
@@ -66185,7 +66602,14 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
66185
66602
  const modelName = resolvedSpec?.modelName || parsedModel;
66186
66603
  let formatAdapterName = "OpenAIAPIFormat";
66187
66604
  let declaredStreamFormat = "openai-sse";
66188
- const anthropicCompatProviders = ["minimax", "minimax-coding", "kimi", "kimi-coding", "z-ai"];
66605
+ const anthropicCompatProviders = [
66606
+ "minimax",
66607
+ "minimax-coding",
66608
+ "kimi",
66609
+ "kimi-coding",
66610
+ "qwen-cloud",
66611
+ "z-ai"
66612
+ ];
66189
66613
  const isMinimaxModel = modelName.toLowerCase().includes("minimax");
66190
66614
  if (anthropicCompatProviders.includes(providerName)) {
66191
66615
  formatAdapterName = "AnthropicAPIFormat";
@@ -66246,7 +66670,7 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
66246
66670
  }
66247
66671
  }
66248
66672
  try {
66249
- const results = [];
66673
+ const results2 = [];
66250
66674
  for (const modelInput of models) {
66251
66675
  const { parsed, chain, chainDetails } = buildModelChain(modelInput);
66252
66676
  let directProbeResult;
@@ -66284,7 +66708,7 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
66284
66708
  }
66285
66709
  }
66286
66710
  const wiring = await computeWiring(chainDetails, parsed.model);
66287
- results.push({
66711
+ results2.push({
66288
66712
  model: modelInput,
66289
66713
  nativeProvider: parsed.provider,
66290
66714
  isExplicit: parsed.isExplicitProvider,
@@ -66295,7 +66719,7 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
66295
66719
  wiring
66296
66720
  });
66297
66721
  }
66298
- console.log(JSON.stringify(results, null, 2));
66722
+ console.log(JSON.stringify(results2, null, 2));
66299
66723
  } finally {
66300
66724
  if (liveProxy2) {
66301
66725
  try {
@@ -66439,7 +66863,7 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
66439
66863
  }
66440
66864
  const isLiveProbe = !!liveProxy;
66441
66865
  const printable = [];
66442
- const results = [];
66866
+ const results2 = [];
66443
66867
  for (const { modelInput, parsed, chain, chainDetails } of modelChains) {
66444
66868
  const wiring = await computeWiring(chainDetails, parsed.model);
66445
66869
  const directProbe = directProbeResults.get(modelInput);
@@ -66461,7 +66885,7 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
66461
66885
  directProbe,
66462
66886
  wiring
66463
66887
  });
66464
- results.push({
66888
+ results2.push({
66465
66889
  model: modelInput,
66466
66890
  nativeProvider: parsed.provider,
66467
66891
  isExplicit: parsed.isExplicitProvider,
@@ -66480,7 +66904,7 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
66480
66904
  } catch {}
66481
66905
  liveProxy = null;
66482
66906
  }
66483
- tui.store.setResults(results);
66907
+ tui.store.setResults(results2);
66484
66908
  await tui.waitForQuit();
66485
66909
  await tui.shutdown();
66486
66910
  } else {
@@ -67856,8 +68280,8 @@ async function pingLocalProvider(catalogName, timeoutMs = PING_TIMEOUT_MS) {
67856
68280
  }
67857
68281
  }
67858
68282
  async function pingLocalProviders(catalogNames, timeoutMs = PING_TIMEOUT_MS) {
67859
- const results = await Promise.all(catalogNames.map(async (name) => [name, await pingLocalProvider(name, timeoutMs)]));
67860
- return Object.fromEntries(results);
68283
+ const results2 = await Promise.all(catalogNames.map(async (name) => [name, await pingLocalProvider(name, timeoutMs)]));
68284
+ return Object.fromEntries(results2);
67861
68285
  }
67862
68286
  var PING_TIMEOUT_MS = 2000, HEALTH_PATH;
67863
68287
  var init_local_liveness = __esm(() => {
@@ -71764,6 +72188,7 @@ var init_RoutingContent = __esm(() => {
71764
72188
  "minimax-coding": "MiniMax Coding Plan",
71765
72189
  glm: "Native GLM API",
71766
72190
  "glm-coding": "GLM Coding Plan",
72191
+ "qwen-cloud": "Qwen Plan",
71767
72192
  google: "Direct Gemini API",
71768
72193
  openai: "Direct OpenAI API",
71769
72194
  "openai-codex": "OpenAI Codex (Responses API)",
@@ -74334,13 +74759,20 @@ __export(exports_claude_runner, {
74334
74759
  resolveContextWindowEnv: () => resolveContextWindowEnv,
74335
74760
  managedSettingsForcesClaudeAi: () => managedSettingsForcesClaudeAi,
74336
74761
  isProxyAuthMode: () => isProxyAuthMode,
74762
+ initializeTokenFile: () => initializeTokenFile,
74763
+ discoverUserStatusLineCommand: () => discoverUserStatusLineCommand,
74337
74764
  createTempSettingsFile: () => createTempSettingsFile,
74338
74765
  createStatusLineScript: () => createStatusLineScript,
74339
74766
  computeMainThreadContextWindow: () => computeMainThreadContextWindow,
74767
+ cleanupStaleTokenFiles: () => cleanupStaleTokenFiles,
74340
74768
  checkClaudeInstalled: () => checkClaudeInstalled,
74341
74769
  buildClaudishSettingsOverlay: () => buildClaudishSettingsOverlay,
74770
+ buildChainedStatusCommand: () => buildChainedStatusCommand,
74771
+ USER_STATUS_LINE_TIMEOUT_SECONDS: () => USER_STATUS_LINE_TIMEOUT_SECONDS,
74772
+ STALE_TOKEN_FILE_MS: () => STALE_TOKEN_FILE_MS,
74342
74773
  MIN_AUTO_COMPACT_WINDOW: () => MIN_AUTO_COMPACT_WINDOW,
74343
- CLAUDE_CODE_DEFAULT_MAX_CONTEXT: () => CLAUDE_CODE_DEFAULT_MAX_CONTEXT
74774
+ CLAUDE_CODE_DEFAULT_MAX_CONTEXT: () => CLAUDE_CODE_DEFAULT_MAX_CONTEXT,
74775
+ CATALOG_WINDOW_TIMEOUT_MS: () => CATALOG_WINDOW_TIMEOUT_MS
74344
74776
  });
74345
74777
  import { spawn as spawn4 } from "child_process";
74346
74778
  import {
@@ -74349,11 +74781,13 @@ import {
74349
74781
  mkdirSync as mkdirSync16,
74350
74782
  openSync as openSync5,
74351
74783
  readFileSync as readFileSync24,
74784
+ readdirSync as readdirSync6,
74785
+ statSync as statSync5,
74352
74786
  unlinkSync as unlinkSync9,
74353
74787
  writeFileSync as writeFileSync18
74354
74788
  } from "fs";
74355
74789
  import { homedir as homedir29, tmpdir as tmpdir2 } from "os";
74356
- import { join as join31 } from "path";
74790
+ import { dirname as dirname11, join as join31 } from "path";
74357
74791
  import { isatty } from "tty";
74358
74792
  function releaseTerminalIsolation() {
74359
74793
  if (!restoreTerminal)
@@ -74532,7 +74966,111 @@ process.stdin.on('end', () => {
74532
74966
  writeFileSync18(scriptPath, script, "utf-8");
74533
74967
  return scriptPath;
74534
74968
  }
74535
- function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
74969
+ function initializeTokenFile(tokenFilePath) {
74970
+ try {
74971
+ mkdirSync16(dirname11(tokenFilePath), { recursive: true });
74972
+ writeFileSync18(tokenFilePath, JSON.stringify({
74973
+ input_tokens: 0,
74974
+ output_tokens: 0,
74975
+ total_tokens: 0,
74976
+ total_cost: 0,
74977
+ context_window: "unknown",
74978
+ context_left_percent: -1,
74979
+ updated_at: Date.now(),
74980
+ is_free: false,
74981
+ is_estimated: false
74982
+ }), "utf-8");
74983
+ } catch (e) {
74984
+ log(`[claude-runner] Could not initialize token file ${tokenFilePath}: ${e}`);
74985
+ }
74986
+ }
74987
+ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FILE_MS) {
74988
+ let removed = 0;
74989
+ let entries;
74990
+ try {
74991
+ entries = readdirSync6(dir);
74992
+ } catch {
74993
+ return 0;
74994
+ }
74995
+ const cutoff = now - maxAgeMs;
74996
+ let scanned = 0;
74997
+ for (const name of entries) {
74998
+ if (scanned >= MAX_TOKEN_FILES_SCANNED)
74999
+ break;
75000
+ if (!name.startsWith("tokens-") || !name.endsWith(".json"))
75001
+ continue;
75002
+ scanned++;
75003
+ const full = join31(dir, name);
75004
+ try {
75005
+ if (statSync5(full).mtimeMs >= cutoff)
75006
+ continue;
75007
+ unlinkSync9(full);
75008
+ removed++;
75009
+ } catch {}
75010
+ }
75011
+ if (removed > 0) {
75012
+ log(`[claude-runner] Removed ${removed} stale token file(s) from ${dir}`);
75013
+ }
75014
+ return removed;
75015
+ }
75016
+ function parseSettingsArg(value) {
75017
+ if (value.trimStart().startsWith("{")) {
75018
+ return JSON.parse(value);
75019
+ }
75020
+ return JSON.parse(readFileSync24(value, "utf-8"));
75021
+ }
75022
+ function parseSettingsArgSafe(value) {
75023
+ try {
75024
+ const parsed = parseSettingsArg(value);
75025
+ return parsed && typeof parsed === "object" ? parsed : null;
75026
+ } catch {
75027
+ return null;
75028
+ }
75029
+ }
75030
+ function userSettingsFileCandidates(cwd) {
75031
+ return [
75032
+ join31(homedir29(), ".claude", "settings.json"),
75033
+ join31(cwd, ".claude", "settings.json"),
75034
+ join31(cwd, ".claude", "settings.local.json")
75035
+ ];
75036
+ }
75037
+ function discoverUserStatusLineCommand(claudeArgs = [], cwd = process.cwd()) {
75038
+ const sources = userSettingsFileCandidates(cwd).filter((file2) => existsSync25(file2));
75039
+ const idx = claudeArgs.indexOf("--settings");
75040
+ const settingsArg = idx === -1 ? undefined : claudeArgs[idx + 1];
75041
+ if (settingsArg)
75042
+ sources.push(settingsArg);
75043
+ let effective;
75044
+ for (const source of sources) {
75045
+ const layer = parseSettingsArgSafe(source);
75046
+ if (layer && "statusLine" in layer)
75047
+ effective = layer.statusLine;
75048
+ }
75049
+ return chainableCommandOf(effective);
75050
+ }
75051
+ function chainableCommandOf(statusLine) {
75052
+ if (!statusLine || typeof statusLine !== "object")
75053
+ return null;
75054
+ const { type, command } = statusLine;
75055
+ if (type !== "command" || typeof command !== "string")
75056
+ return null;
75057
+ const trimmed = command.trim();
75058
+ if (!trimmed)
75059
+ return null;
75060
+ if (trimmed.includes("CLAUDISH_ACTIVE_MODEL_NAME") || trimmed.includes("CLAUDISH_IS_LOCAL")) {
75061
+ return null;
75062
+ }
75063
+ return trimmed;
75064
+ }
75065
+ function buildChainedStatusCommand(userCommand, claudishBody, claudishSegment) {
75066
+ const quotedUser = `'${userCommand.replace(/'/g, `'\\''`)}'`;
75067
+ const ESC2 = "\x1B";
75068
+ const separator = `SEP=' ${ESC2}[2m\u2022${ESC2}[0m '`;
75069
+ const runUser = `if command -v timeout >/dev/null 2>&1; then _CT="timeout ${USER_STATUS_LINE_TIMEOUT_SECONDS}"; elif command -v gtimeout >/dev/null 2>&1; then _CT="gtimeout ${USER_STATUS_LINE_TIMEOUT_SECONDS}"; else _CT=""; fi; USER_OUT=$(printf '%s' "$JSON" | $_CT bash -c ${quotedUser} 2>/dev/null)`;
75070
+ const emit2 = `if [ -n "$USER_OUT" ]; then LAST="\${USER_OUT##*$'\\n'}"; if [ "$LAST" = "$USER_OUT" ]; then printf '%s%s%s\\n' "$USER_OUT" "$SEP" "$SEG"; else printf '%s\\n%s%s%s\\n' "\${USER_OUT%$'\\n'*}" "$LAST" "$SEP" "$SEG"; fi; else printf '%s\\n' "$SEG"; fi`;
75071
+ return `JSON=$(cat); ${runUser}; ${claudishBody}; SEG=$(${claudishSegment}); ${separator}; ${emit2}`;
75072
+ }
75073
+ function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLineCommand) {
74536
75074
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
74537
75075
  const claudishDir = join31(homeDir, ".claudish");
74538
75076
  try {
@@ -74541,6 +75079,8 @@ function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
74541
75079
  const timestamp = Date.now();
74542
75080
  const tempPath = join31(claudishDir, `settings-${timestamp}.json`);
74543
75081
  const tokenFilePath = join31(claudishDir, `tokens-${port}.json`);
75082
+ cleanupStaleTokenFiles(claudishDir);
75083
+ initializeTokenFile(tokenFilePath);
74544
75084
  let statusCommand;
74545
75085
  if (isWindows2()) {
74546
75086
  const scriptPath = createStatusLineScript(tokenFilePath);
@@ -74555,7 +75095,13 @@ function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
74555
75095
  const BOLD4 = "\\033[1m";
74556
75096
  const formatTokensBash = `fmt_tok() { local n=\${1:-0}; if [ "$n" -ge 1000000 ]; then echo "$((n/1000000))M"; elif [ "$n" -ge 1000 ]; then echo "$((n/1000))k"; else echo "$n"; fi; }`;
74557
75097
  const effWinBash = `eff_win() { local w=\${1:-0}; local m=\${CLAUDE_CODE_MAX_CONTEXT_TOKENS:-}; local a=\${CLAUDE_CODE_AUTO_COMPACT_WINDOW:-}; case "$m" in ''|*[!0-9]*) m=${CLAUDE_CODE_DEFAULT_MAX_CONTEXT};; esac; case "$a" in ''|*[!0-9]*) a=0;; esac; case "$w" in ''|*[!0-9]*) w=0;; esac; if [ "$w" -gt 0 ]; then if [ "$m" -gt 0 ] && [ "$m" -lt "$w" ]; then w=$m; fi; if [ "$a" -gt 0 ] && [ "$a" -lt "$w" ]; then w=$a; fi; fi; echo "$w"; }`;
74558
- statusCommand = `JSON=$(cat) && DIR=$(basename "$(pwd)") && [ \${#DIR} -gt 15 ] && DIR="\${DIR:0:12}..." || true && CTX=-1 && COST="0" && IS_FREE="false" && IS_EST="false" && PROVIDER="" && TOKEN_MODEL="" && IN_TOK=0 && CTX_WIN=0 && ${formatTokensBash} && ${effWinBash} && if [ -f "${tokenFilePath}" ]; then TOKENS=$(cat "${tokenFilePath}" 2>/dev/null | tr -d ' \\n') && REAL_CTX=$(echo "$TOKENS" | grep -o '"context_left_percent":-\\?[0-9]*' | grep -o '\\-\\?[0-9]*') && if [ ! -z "$REAL_CTX" ]; then CTX="$REAL_CTX"; fi && REAL_COST=$(echo "$TOKENS" | grep -o '"total_cost":[0-9.]*' | cut -d: -f2) && if [ ! -z "$REAL_COST" ]; then COST="$REAL_COST"; fi && IN_TOK=$(echo "$TOKENS" | grep -o '"input_tokens":[0-9]*' | grep -o '[0-9]*') && CTX_WIN=$(echo "$TOKENS" | grep -o '"context_window":[0-9]*' | grep -o '[0-9]*') && IS_FREE=$(echo "$TOKENS" | grep -o '"is_free":[a-z]*' | cut -d: -f2) && IS_EST=$(echo "$TOKENS" | grep -o '"is_estimated":[a-z]*' | cut -d: -f2) && PROVIDER=$(echo "$TOKENS" | grep -o '"provider_name":"[^"]*"' | cut -d'"' -f4) && TOKEN_MODEL=$(echo "$TOKENS" | grep -o '"model_name":"[^"]*"' | cut -d'"' -f4); fi && if [ "$CLAUDISH_IS_LOCAL" = "true" ]; then COST_DISPLAY="LOCAL"; elif [ "$IS_FREE" = "true" ]; then COST_DISPLAY="FREE"; elif [ "$IS_EST" = "true" ]; then COST_DISPLAY=$(printf "~\\$%.3f" "$COST"); else COST_DISPLAY=$(printf "\\$%.3f" "$COST"); fi && MODEL_DISPLAY="\${TOKEN_MODEL:-$CLAUDISH_ACTIVE_MODEL_NAME}" && if [ ! -z "$PROVIDER" ]; then MODEL_DISPLAY="$PROVIDER $MODEL_DISPLAY"; fi && EFF_WIN=$(eff_win $CTX_WIN) && if [ "$EFF_WIN" -gt 0 ] 2>/dev/null && [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX=$(( ((EFF_WIN - IN_TOK) * 200 / EFF_WIN + 1) / 2 )); if [ "$CTX" -lt 0 ]; then CTX=0; fi; fi && if [ "$CTX" -lt 0 ] 2>/dev/null || [ "$EFF_WIN" -le 0 ] 2>/dev/null; then if [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX_DISPLAY="$(fmt_tok $IN_TOK) tokens"; else CTX_DISPLAY="N/A"; fi; elif [ "$IN_TOK" -gt 0 ] 2>/dev/null; then if [ "$EFF_WIN" -lt "$CTX_WIN" ] 2>/dev/null; then CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN) of $(fmt_tok $CTX_WIN))"; else CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN))"; fi; else CTX_DISPLAY="$CTX%"; fi && printf "${CYAN4}${BOLD4}%s${RESET4} ${DIM4}\u2022${RESET4} ${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}\\n" "$DIR" "$MODEL_DISPLAY" "$COST_DISPLAY" "$CTX_DISPLAY"`;
75098
+ const dirPrelude = `DIR=$(basename "$(pwd)"); [ \${#DIR} -gt 15 ] && DIR="\${DIR:0:12}..." || true; `;
75099
+ const readState = `CTX=-1; COST="0"; IS_FREE="false"; IS_EST="false"; PROVIDER=""; TOKEN_MODEL=""; IN_TOK=0; CTX_WIN=0; ${formatTokensBash}; ${effWinBash}; if [ -f "${tokenFilePath}" ]; then TOKENS=$(cat "${tokenFilePath}" 2>/dev/null | tr -d '\\n\\r'); V=$(echo "$TOKENS" | grep -o '"context_left_percent": *-\\?[0-9]*' | grep -o '\\-\\?[0-9]*'); [ -n "$V" ] && CTX="$V"; V=$(echo "$TOKENS" | grep -o '"total_cost": *[0-9.]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && COST="$V"; V=$(echo "$TOKENS" | grep -o '"input_tokens": *[0-9]*' | grep -o '[0-9]*'); [ -n "$V" ] && IN_TOK="$V"; V=$(echo "$TOKENS" | grep -o '"context_window": *[0-9]*' | grep -o '[0-9]*'); [ -n "$V" ] && CTX_WIN="$V"; V=$(echo "$TOKENS" | grep -o '"is_free": *[a-z]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && IS_FREE="$V"; V=$(echo "$TOKENS" | grep -o '"is_estimated": *[a-z]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && IS_EST="$V"; V=$(echo "$TOKENS" | grep -o '"provider_name": *"[^"]*"' | cut -d'"' -f4); [ -n "$V" ] && PROVIDER="$V"; V=$(echo "$TOKENS" | grep -o '"model_name": *"[^"]*"' | cut -d'"' -f4); [ -n "$V" ] && TOKEN_MODEL="$V"; fi; if [ "$CLAUDISH_IS_LOCAL" = "true" ]; then COST_DISPLAY="LOCAL"; elif [ "$IS_FREE" = "true" ]; then COST_DISPLAY="FREE"; elif [ "$IS_EST" = "true" ]; then COST_DISPLAY=$(printf "~\\$%.3f" "$COST"); else COST_DISPLAY=$(printf "\\$%.3f" "$COST"); fi; MODEL_DISPLAY="\${TOKEN_MODEL:-$CLAUDISH_ACTIVE_MODEL_NAME}"; if [ -n "$PROVIDER" ]; then MODEL_DISPLAY="$PROVIDER $MODEL_DISPLAY"; fi; EFF_WIN=$(eff_win $CTX_WIN); if [ "$EFF_WIN" -gt 0 ] 2>/dev/null && [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX=$(( ((EFF_WIN - IN_TOK) * 200 / EFF_WIN + 1) / 2 )); if [ "$CTX" -lt 0 ]; then CTX=0; fi; fi; if [ "$CTX" -lt 0 ] 2>/dev/null || [ "$EFF_WIN" -le 0 ] 2>/dev/null; then if [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX_DISPLAY="$(fmt_tok $IN_TOK) tokens"; else CTX_DISPLAY="N/A"; fi; elif [ "$IN_TOK" -gt 0 ] 2>/dev/null; then if [ "$EFF_WIN" -lt "$CTX_WIN" ] 2>/dev/null; then CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN) of $(fmt_tok $CTX_WIN))"; else CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN))"; fi; else CTX_DISPLAY="$CTX%"; fi`;
75100
+ const segmentWithDir = `printf "${CYAN4}${BOLD4}%s${RESET4} ${DIM4}\u2022${RESET4} ${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}\\n" "$DIR" "$MODEL_DISPLAY" "$COST_DISPLAY" "$CTX_DISPLAY"`;
75101
+ const segmentNoDirWithProvider = `printf "${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}\\n" "$PROVIDER" "$COST_DISPLAY" "$CTX_DISPLAY"`;
75102
+ const segmentNoDirNoProvider = `printf "${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}\\n" "$COST_DISPLAY" "$CTX_DISPLAY"`;
75103
+ const segmentNoDir = `if [ -n "$PROVIDER" ]; then ${segmentNoDirWithProvider}; else ${segmentNoDirNoProvider}; fi`;
75104
+ statusCommand = userStatusLineCommand ? buildChainedStatusCommand(userStatusLineCommand, readState, segmentNoDir) : `JSON=$(cat); ${dirPrelude}${readState}; ${segmentWithDir}`;
74559
75105
  }
74560
75106
  const statusLine = {
74561
75107
  type: "command",
@@ -74564,7 +75110,7 @@ function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
74564
75110
  };
74565
75111
  const settings = buildClaudishSettingsOverlay(statusLine, proxyAuthMode);
74566
75112
  writeFileSync18(tempPath, JSON.stringify(settings, null, 2), "utf-8");
74567
- return { path: tempPath, statusLine };
75113
+ return { path: tempPath, statusLine, tokenFilePath };
74568
75114
  }
74569
75115
  function buildClaudishSettingsOverlay(statusLine, proxyAuthMode) {
74570
75116
  const settings = { statusLine, disableClaudeAiConnectors: true };
@@ -74580,13 +75126,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxy
74580
75126
  }
74581
75127
  const userSettingsValue = config3.claudeArgs[idx + 1];
74582
75128
  try {
74583
- let userSettings;
74584
- if (userSettingsValue.trimStart().startsWith("{")) {
74585
- userSettings = JSON.parse(userSettingsValue);
74586
- } else {
74587
- const rawUserSettings = readFileSync24(userSettingsValue, "utf-8");
74588
- userSettings = JSON.parse(rawUserSettings);
74589
- }
75129
+ const userSettings = parseSettingsArg(userSettingsValue);
74590
75130
  userSettings.statusLine = statusLine;
74591
75131
  if (!("disableClaudeAiConnectors" in userSettings)) {
74592
75132
  userSettings.disableClaudeAiConnectors = true;
@@ -74602,27 +75142,64 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxy
74602
75142
  }
74603
75143
  config3.claudeArgs.splice(idx, 2);
74604
75144
  }
75145
+ function withDeadline(promise3, ms) {
75146
+ return new Promise((resolve4) => {
75147
+ const timer = setTimeout(() => resolve4(null), ms);
75148
+ timer.unref?.();
75149
+ promise3.then((value) => {
75150
+ clearTimeout(timer);
75151
+ resolve4(value);
75152
+ }).catch(() => {
75153
+ clearTimeout(timer);
75154
+ resolve4(null);
75155
+ });
75156
+ });
75157
+ }
75158
+ async function resolveLocalContextWindow(spec, cachePath) {
75159
+ const parsed = parseModelSpec(spec);
75160
+ let provider = parsed.provider;
75161
+ if (!parsed.isExplicitProvider) {
75162
+ const plan = await route(spec);
75163
+ if (plan.kind !== "ok")
75164
+ return null;
75165
+ provider = plan.primary.provider;
75166
+ }
75167
+ const win = await discoverContextWindow(provider, parsed.model) ?? lookupModelForProvider(parsed.model, provider, cachePath);
75168
+ return {
75169
+ modelId: parsed.model,
75170
+ window: typeof win === "number" && win > 0 ? win : null
75171
+ };
75172
+ }
75173
+ async function catalogWindowMin(modelIds) {
75174
+ const misses = [...new Set(modelIds)];
75175
+ if (misses.length === 0)
75176
+ return Number.POSITIVE_INFINITY;
75177
+ const windows = await withDeadline(Promise.all(misses.map((id) => resolveCatalogContextWindow(id).catch(() => null))), CATALOG_WINDOW_TIMEOUT_MS);
75178
+ let min = Number.POSITIVE_INFINITY;
75179
+ for (const win of windows ?? []) {
75180
+ if (typeof win === "number" && win > 0)
75181
+ min = Math.min(min, win);
75182
+ }
75183
+ return min;
75184
+ }
74605
75185
  async function computeMainThreadContextWindow(config3, cachePath) {
74606
75186
  const specs = [config3.model, config3.modelOpus, config3.modelSonnet].filter((s) => typeof s === "string" && s.length > 0);
74607
75187
  if (specs.length === 0)
74608
75188
  return 0;
74609
75189
  let min = Number.POSITIVE_INFINITY;
75190
+ const unresolved = [];
74610
75191
  for (const spec of specs) {
74611
75192
  try {
74612
- const parsed = parseModelSpec(spec);
74613
- let provider = parsed.provider;
74614
- if (!parsed.isExplicitProvider) {
74615
- const plan = await route(spec);
74616
- if (plan.kind !== "ok")
74617
- continue;
74618
- provider = plan.primary.provider;
74619
- }
74620
- const win = await discoverContextWindow(provider, parsed.model) ?? lookupModelForProvider(parsed.model, provider, cachePath);
74621
- if (typeof win === "number" && win > 0) {
74622
- min = Math.min(min, win);
74623
- }
75193
+ const resolved = await resolveLocalContextWindow(spec, cachePath);
75194
+ if (!resolved)
75195
+ continue;
75196
+ if (resolved.window !== null)
75197
+ min = Math.min(min, resolved.window);
75198
+ else
75199
+ unresolved.push(resolved.modelId);
74624
75200
  } catch {}
74625
75201
  }
75202
+ min = Math.min(min, await catalogWindowMin(unresolved));
74626
75203
  return Number.isFinite(min) ? min : 0;
74627
75204
  }
74628
75205
  function resolveContextWindowEnv(realWindow, processEnv = process.env) {
@@ -74659,7 +75236,12 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
74659
75236
  onCleanup?.();
74660
75237
  return 1;
74661
75238
  }
74662
- const { path: tempSettingsPath, statusLine } = createTempSettingsFile(modelId ?? "default", port, proxyAuthMode);
75239
+ const userStatusLineCommand = discoverUserStatusLineCommand(config3.claudeArgs);
75240
+ const {
75241
+ path: tempSettingsPath,
75242
+ statusLine,
75243
+ tokenFilePath
75244
+ } = createTempSettingsFile(modelId ?? "default", port, proxyAuthMode, userStatusLineCommand);
74663
75245
  mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxyAuthMode);
74664
75246
  const claudeArgs = [];
74665
75247
  claudeArgs.push("--settings", tempSettingsPath);
@@ -74692,8 +75274,16 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
74692
75274
  ...process.env,
74693
75275
  ANTHROPIC_BASE_URL: proxyUrl,
74694
75276
  [ENV.CLAUDISH_ACTIVE_MODEL_NAME]: modelDisplayName,
74695
- CLAUDISH_IS_LOCAL: isLocalModel2 ? "true" : "false"
75277
+ CLAUDISH_IS_LOCAL: isLocalModel2 ? "true" : "false",
75278
+ [ENV.CLAUDISH_TOKEN_FILE]: tokenFilePath
74696
75279
  };
75280
+ if (modelId) {
75281
+ const parsedSpec = parseModelSpec(modelId);
75282
+ const providerDisplayName = parsedSpec.isExplicitProvider ? getProviderByName(parsedSpec.provider)?.displayName : undefined;
75283
+ if (providerDisplayName) {
75284
+ env[ENV.CLAUDISH_PROVIDER_NAME] = providerDisplayName;
75285
+ }
75286
+ }
74697
75287
  let hidAnthropicApiKey = false;
74698
75288
  delete env.CLAUDECODE;
74699
75289
  if (config3.monitor) {
@@ -74904,17 +75494,20 @@ async function checkClaudeInstalled() {
74904
75494
  const binary = await findClaudeBinary();
74905
75495
  return binary !== null;
74906
75496
  }
74907
- var restoreTerminal = null, CLAUDE_CODE_DEFAULT_MAX_CONTEXT = 200000, MIN_AUTO_COMPACT_WINDOW = 200000;
75497
+ var restoreTerminal = null, STALE_TOKEN_FILE_MS, MAX_TOKEN_FILES_SCANNED = 4000, CLAUDE_CODE_DEFAULT_MAX_CONTEXT = 200000, USER_STATUS_LINE_TIMEOUT_SECONDS = 3, MIN_AUTO_COMPACT_WINDOW = 200000, CATALOG_WINDOW_TIMEOUT_MS = 1500;
74908
75498
  var init_claude_runner = __esm(() => {
74909
75499
  init_model_catalog();
74910
75500
  init_config2();
75501
+ init_context_window_fallback();
74911
75502
  init_logger();
74912
75503
  init_profile_config();
74913
75504
  init_model_discovery();
74914
75505
  init_model_parser();
75506
+ init_provider_definitions();
74915
75507
  init_routing_rules();
74916
75508
  init_telemetry();
74917
75509
  init_terminal_isolation();
75510
+ STALE_TOKEN_FILE_MS = 7 * 24 * 60 * 60 * 1000;
74918
75511
  });
74919
75512
 
74920
75513
  // src/diag-output.ts
@@ -75148,7 +75741,7 @@ import { spawn as spawn5 } from "child_process";
75148
75741
  import { execSync as execSync2 } from "child_process";
75149
75742
  import { existsSync as existsSync26, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
75150
75743
  import { connect as netConnect } from "net";
75151
- import { dirname as dirname11, join as join33 } from "path";
75744
+ import { dirname as dirname12, join as join33 } from "path";
75152
75745
  import { setTimeout as wait } from "timers/promises";
75153
75746
  import { fileURLToPath as fileURLToPath3 } from "url";
75154
75747
  function resolveRouteInfo(modelId) {
@@ -75241,7 +75834,7 @@ function buildPaneHeader(model, prompt, bg) {
75241
75834
  }
75242
75835
  function findMagmuxBinary() {
75243
75836
  const thisFile = fileURLToPath3(import.meta.url);
75244
- const thisDir = dirname11(thisFile);
75837
+ const thisDir = dirname12(thisFile);
75245
75838
  const pkgRoot = join33(thisDir, "..");
75246
75839
  const platform3 = process.platform;
75247
75840
  const arch = process.arch;
@@ -75255,7 +75848,7 @@ function findMagmuxBinary() {
75255
75848
  const candidate = join33(searchDir, "node_modules", pkgName, "bin", "magmux");
75256
75849
  if (existsSync26(candidate))
75257
75850
  return candidate;
75258
- const parent = dirname11(searchDir);
75851
+ const parent = dirname12(searchDir);
75259
75852
  if (parent === searchDir)
75260
75853
  break;
75261
75854
  searchDir = parent;
@@ -75316,12 +75909,12 @@ async function subscribeToMagmux(sockPath, onEvent) {
75316
75909
  client.once("error", done);
75317
75910
  });
75318
75911
  }
75319
- function buildTeamStatus(manifest, startedAt, results) {
75912
+ function buildTeamStatus(manifest, startedAt, results2) {
75320
75913
  const anonIds = Object.keys(manifest.models);
75321
75914
  const models = {};
75322
75915
  for (let i = 0;i < anonIds.length; i++) {
75323
75916
  const anonId = anonIds[i];
75324
- const result = results?.find((r) => r.pane === i);
75917
+ const result = results2?.find((r) => r.pane === i);
75325
75918
  if (!result) {
75326
75919
  models[anonId] = {
75327
75920
  state: "TIMEOUT",
@@ -75390,8 +75983,8 @@ async function runWithGrid(sessionPath, models, input, opts) {
75390
75983
  proc.on("exit", () => resolve4());
75391
75984
  proc.on("error", () => resolve4());
75392
75985
  });
75393
- const [{ results }] = await Promise.all([subscription, procExit]);
75394
- const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
75986
+ const [{ results: results2 }] = await Promise.all([subscription, procExit]);
75987
+ const status = buildTeamStatus(manifest, startedAt, results2?.panes ?? null);
75395
75988
  const statusPath = join33(sessionPath, "status.json");
75396
75989
  writeFileSync20(statusPath, JSON.stringify(status, null, 2), "utf-8");
75397
75990
  return status;