claudish 5.7.1 → 5.9.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.
package/dist/index.js CHANGED
@@ -29458,7 +29458,7 @@ var getRemoteProviders = () => [
29458
29458
  authScheme: "bearer",
29459
29459
  capabilities: {
29460
29460
  supportsTools: true,
29461
- supportsVision: true,
29461
+ supportsVision: false,
29462
29462
  supportsStreaming: true,
29463
29463
  supportsJsonMode: false,
29464
29464
  supportsReasoning: false
@@ -29941,9 +29941,7 @@ function checkApiKeyForProvider(nativeProvider, modelName) {
29941
29941
  }
29942
29942
  function getAutoRouteHint(modelName, nativeProvider) {
29943
29943
  const hint = PROVIDER_HINT_MAP[nativeProvider];
29944
- const lines = [
29945
- `No credentials found for "${modelName}". Options:`
29946
- ];
29944
+ const lines = [`No credentials found for "${modelName}". Options:`];
29947
29945
  let hasOption = false;
29948
29946
  if (hint?.loginFlag) {
29949
29947
  lines.push(` Run: claudish ${hint.loginFlag} (authenticate via OAuth)`);
@@ -30004,7 +30002,61 @@ function autoRoute(modelName, nativeProvider) {
30004
30002
  }
30005
30003
  return null;
30006
30004
  }
30007
- var API_KEY_ENV_VARS, PROVIDER_HINT_MAP;
30005
+ function hasProviderCredentials(provider) {
30006
+ const keyInfo = API_KEY_ENV_VARS[provider];
30007
+ if (keyInfo?.envVar && process.env[keyInfo.envVar])
30008
+ return true;
30009
+ if (keyInfo?.aliases?.some((a) => process.env[a]))
30010
+ return true;
30011
+ return hasOAuthCredentials(provider);
30012
+ }
30013
+ function getFallbackChain(modelName, nativeProvider) {
30014
+ const routes = [];
30015
+ const litellmBaseUrl = process.env.LITELLM_BASE_URL;
30016
+ if (litellmBaseUrl && process.env.LITELLM_API_KEY) {
30017
+ routes.push({
30018
+ provider: "litellm",
30019
+ modelSpec: `litellm@${modelName}`,
30020
+ displayName: "LiteLLM"
30021
+ });
30022
+ }
30023
+ if (process.env.OPENCODE_API_KEY) {
30024
+ routes.push({
30025
+ provider: "opencode-zen",
30026
+ modelSpec: `zen@${modelName}`,
30027
+ displayName: "OpenCode Zen"
30028
+ });
30029
+ }
30030
+ const sub = SUBSCRIPTION_ALTERNATIVES[nativeProvider];
30031
+ if (sub && hasProviderCredentials(sub.subscriptionProvider)) {
30032
+ const subModelName = sub.modelName || modelName;
30033
+ routes.push({
30034
+ provider: sub.subscriptionProvider,
30035
+ modelSpec: `${sub.prefix}@${subModelName}`,
30036
+ displayName: sub.displayName
30037
+ });
30038
+ }
30039
+ if (nativeProvider !== "unknown" && nativeProvider !== "qwen" && nativeProvider !== "native-anthropic") {
30040
+ if (hasProviderCredentials(nativeProvider)) {
30041
+ const prefix = PROVIDER_TO_PREFIX[nativeProvider] || nativeProvider;
30042
+ routes.push({
30043
+ provider: nativeProvider,
30044
+ modelSpec: `${prefix}@${modelName}`,
30045
+ displayName: DISPLAY_NAMES[nativeProvider] || nativeProvider
30046
+ });
30047
+ }
30048
+ }
30049
+ if (process.env.OPENROUTER_API_KEY) {
30050
+ const resolution = resolveModelNameSync(modelName, "openrouter");
30051
+ routes.push({
30052
+ provider: "openrouter",
30053
+ modelSpec: resolution.resolvedId,
30054
+ displayName: "OpenRouter"
30055
+ });
30056
+ }
30057
+ return routes;
30058
+ }
30059
+ var API_KEY_ENV_VARS, PROVIDER_HINT_MAP, PROVIDER_TO_PREFIX, DISPLAY_NAMES, SUBSCRIPTION_ALTERNATIVES;
30008
30060
  var init_auto_route = __esm(() => {
30009
30061
  init_oauth_registry();
30010
30062
  init_model_catalog_resolver();
@@ -30068,6 +30120,65 @@ var init_auto_route = __esm(() => {
30068
30120
  apiKeyEnvVar: "OLLAMA_API_KEY"
30069
30121
  }
30070
30122
  };
30123
+ PROVIDER_TO_PREFIX = {
30124
+ google: "g",
30125
+ openai: "oai",
30126
+ minimax: "mm",
30127
+ "minimax-coding": "mmc",
30128
+ kimi: "kimi",
30129
+ "kimi-coding": "kc",
30130
+ glm: "glm",
30131
+ "glm-coding": "gc",
30132
+ zai: "zai",
30133
+ ollamacloud: "oc",
30134
+ "opencode-zen": "zen",
30135
+ "opencode-zen-go": "zengo",
30136
+ litellm: "ll",
30137
+ vertex: "v",
30138
+ "gemini-codeassist": "go"
30139
+ };
30140
+ DISPLAY_NAMES = {
30141
+ google: "Gemini",
30142
+ openai: "OpenAI",
30143
+ minimax: "MiniMax",
30144
+ "minimax-coding": "MiniMax Coding",
30145
+ kimi: "Kimi",
30146
+ "kimi-coding": "Kimi Coding",
30147
+ glm: "GLM",
30148
+ "glm-coding": "GLM Coding",
30149
+ zai: "Z.AI",
30150
+ ollamacloud: "OllamaCloud",
30151
+ "opencode-zen": "OpenCode Zen",
30152
+ "opencode-zen-go": "OpenCode Zen Go",
30153
+ litellm: "LiteLLM",
30154
+ openrouter: "OpenRouter"
30155
+ };
30156
+ SUBSCRIPTION_ALTERNATIVES = {
30157
+ kimi: {
30158
+ subscriptionProvider: "kimi-coding",
30159
+ modelName: "kimi-for-coding",
30160
+ prefix: "kc",
30161
+ displayName: "Kimi Coding"
30162
+ },
30163
+ minimax: {
30164
+ subscriptionProvider: "minimax-coding",
30165
+ modelName: null,
30166
+ prefix: "mmc",
30167
+ displayName: "MiniMax Coding"
30168
+ },
30169
+ glm: {
30170
+ subscriptionProvider: "glm-coding",
30171
+ modelName: null,
30172
+ prefix: "gc",
30173
+ displayName: "GLM Coding"
30174
+ },
30175
+ google: {
30176
+ subscriptionProvider: "gemini-codeassist",
30177
+ modelName: null,
30178
+ prefix: "go",
30179
+ displayName: "Gemini Code Assist"
30180
+ }
30181
+ };
30071
30182
  });
30072
30183
 
30073
30184
  // src/providers/provider-resolver.ts
@@ -30498,7 +30609,15 @@ __export(exports_cli, {
30498
30609
  getMissingKeyResolutions: () => getMissingKeyResolutions,
30499
30610
  getMissingKeyError: () => getMissingKeyError
30500
30611
  });
30501
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, existsSync as existsSync12, mkdirSync as mkdirSync5, copyFileSync, readdirSync, unlinkSync as unlinkSync3 } from "node:fs";
30612
+ import {
30613
+ readFileSync as readFileSync10,
30614
+ writeFileSync as writeFileSync5,
30615
+ existsSync as existsSync12,
30616
+ mkdirSync as mkdirSync5,
30617
+ copyFileSync,
30618
+ readdirSync,
30619
+ unlinkSync as unlinkSync3
30620
+ } from "node:fs";
30502
30621
  import { fileURLToPath as fileURLToPath3 } from "node:url";
30503
30622
  import { dirname as dirname3, join as join12 } from "node:path";
30504
30623
  import { homedir as homedir11 } from "node:os";
@@ -31836,7 +31955,7 @@ async function fetchGLMCodingModels() {
31836
31955
  return [];
31837
31956
  }
31838
31957
  }
31839
- var __filename4, __dirname4, VERSION = "5.7.1", CACHE_MAX_AGE_DAYS2 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR2, ALL_MODELS_JSON_PATH;
31958
+ var __filename4, __dirname4, VERSION = "5.9.0", CACHE_MAX_AGE_DAYS2 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR2, ALL_MODELS_JSON_PATH;
31840
31959
  var init_cli = __esm(() => {
31841
31960
  init_config();
31842
31961
  init_model_loader();
@@ -34501,7 +34620,9 @@ async function fetchZenGoModels() {
34501
34620
  return [];
34502
34621
  const ZEN_GO_BASE = process.env.OPENCODE_BASE_URL ? process.env.OPENCODE_BASE_URL.replace("/zen", "/zen/go") : "https://opencode.ai/zen/go";
34503
34622
  try {
34504
- const mdevResp = await fetch("https://models.dev/api.json", { signal: AbortSignal.timeout(5000) });
34623
+ const mdevResp = await fetch("https://models.dev/api.json", {
34624
+ signal: AbortSignal.timeout(5000)
34625
+ });
34505
34626
  if (!mdevResp.ok)
34506
34627
  return [];
34507
34628
  const mdevData = await mdevResp.json();
@@ -34513,7 +34634,11 @@ async function fetchZenGoModels() {
34513
34634
  const r = await fetch(`${ZEN_GO_BASE}/v1/chat/completions`, {
34514
34635
  method: "POST",
34515
34636
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
34516
- body: JSON.stringify({ model: modelId, messages: [{ role: "user", content: "hi" }], max_tokens: 1 }),
34637
+ body: JSON.stringify({
34638
+ model: modelId,
34639
+ messages: [{ role: "user", content: "hi" }],
34640
+ max_tokens: 1
34641
+ }),
34517
34642
  signal: AbortSignal.timeout(8000)
34518
34643
  });
34519
34644
  if (!r.ok)
@@ -34974,7 +35099,10 @@ async function getAllModelsForSearch(forceUpdate = false) {
34974
35099
  const litellmBaseUrl = process.env.LITELLM_BASE_URL;
34975
35100
  const litellmApiKey = process.env.LITELLM_API_KEY;
34976
35101
  const fetchEntries = [
34977
- { name: "OpenRouter", promise: fetchAllModels(forceUpdate).then((models) => models.map(toModelInfo)) },
35102
+ {
35103
+ name: "OpenRouter",
35104
+ promise: fetchAllModels(forceUpdate).then((models) => models.map(toModelInfo))
35105
+ },
34978
35106
  { name: "xAI", promise: fetchXAIModels() },
34979
35107
  { name: "Gemini", promise: fetchGeminiModels() },
34980
35108
  { name: "OpenAI", promise: fetchOpenAIModels() },
@@ -34985,7 +35113,10 @@ async function getAllModelsForSearch(forceUpdate = false) {
34985
35113
  { name: "Zen Go", promise: fetchZenGoModels() }
34986
35114
  ];
34987
35115
  if (litellmBaseUrl && litellmApiKey) {
34988
- fetchEntries.push({ name: "LiteLLM", promise: fetchLiteLLMModels(litellmBaseUrl, litellmApiKey, forceUpdate) });
35116
+ fetchEntries.push({
35117
+ name: "LiteLLM",
35118
+ promise: fetchLiteLLMModels(litellmBaseUrl, litellmApiKey, forceUpdate)
35119
+ });
34989
35120
  }
34990
35121
  const settled = await Promise.allSettled(fetchEntries.map((e) => e.promise));
34991
35122
  const fetchResults = {};
@@ -35197,9 +35328,24 @@ function getKnownModels(provider) {
35197
35328
  { id: "google@gemini-2.0-flash", name: "Gemini 2.0 Flash", context: "1M" }
35198
35329
  ],
35199
35330
  openai: [
35200
- { id: "oai@gpt-5.3-codex", name: "GPT-5.3 Codex", context: "400K", description: "Latest coding model" },
35201
- { id: "oai@gpt-5.2-codex", name: "GPT-5.2 Codex", context: "400K", description: "Coding model" },
35202
- { id: "oai@gpt-5.1-codex-mini", name: "GPT-5.1 Codex Mini", context: "400K", description: "Fast coding model" },
35331
+ {
35332
+ id: "oai@gpt-5.3-codex",
35333
+ name: "GPT-5.3 Codex",
35334
+ context: "400K",
35335
+ description: "Latest coding model"
35336
+ },
35337
+ {
35338
+ id: "oai@gpt-5.2-codex",
35339
+ name: "GPT-5.2 Codex",
35340
+ context: "400K",
35341
+ description: "Coding model"
35342
+ },
35343
+ {
35344
+ id: "oai@gpt-5.1-codex-mini",
35345
+ name: "GPT-5.1 Codex Mini",
35346
+ context: "400K",
35347
+ description: "Fast coding model"
35348
+ },
35203
35349
  { id: "oai@o3", name: "o3", context: "200K", description: "Reasoning model" },
35204
35350
  { id: "oai@o4-mini", name: "o4-mini", context: "200K", description: "Fast reasoning model" },
35205
35351
  { id: "oai@gpt-4.1", name: "GPT-4.1", context: "1M", description: "Large context model" }
@@ -35207,39 +35353,102 @@ function getKnownModels(provider) {
35207
35353
  xai: [
35208
35354
  { id: "xai@grok-4", name: "Grok 4", context: "256K" },
35209
35355
  { id: "xai@grok-4-fast", name: "Grok 4 Fast", context: "2M" },
35210
- { id: "xai@grok-code-fast-1", name: "Grok Code Fast 1", context: "256K", description: "Optimized for coding" }
35356
+ {
35357
+ id: "xai@grok-code-fast-1",
35358
+ name: "Grok Code Fast 1",
35359
+ context: "256K",
35360
+ description: "Optimized for coding"
35361
+ }
35211
35362
  ],
35212
35363
  minimax: [
35213
- { id: "mm@minimax-m2.1", name: "MiniMax M2.1", context: "196K", description: "Lightweight coding model" }
35364
+ {
35365
+ id: "mm@minimax-m2.1",
35366
+ name: "MiniMax M2.1",
35367
+ context: "196K",
35368
+ description: "Lightweight coding model"
35369
+ }
35214
35370
  ],
35215
35371
  "minimax-coding": [
35216
- { id: "mmc@minimax-m2.5", name: "MiniMax M2.5", context: "196K", description: "MiniMax Coding subscription model" },
35217
- { id: "mmc@minimax-m2.1", name: "MiniMax M2.1", context: "196K", description: "MiniMax Coding subscription model" }
35372
+ {
35373
+ id: "mmc@minimax-m2.5",
35374
+ name: "MiniMax M2.5",
35375
+ context: "196K",
35376
+ description: "MiniMax Coding subscription model"
35377
+ },
35378
+ {
35379
+ id: "mmc@minimax-m2.1",
35380
+ name: "MiniMax M2.1",
35381
+ context: "196K",
35382
+ description: "MiniMax Coding subscription model"
35383
+ }
35218
35384
  ],
35219
35385
  kimi: [
35220
35386
  { id: "kimi@kimi-k2-thinking-turbo", name: "Kimi K2 Thinking Turbo", context: "128K" },
35221
35387
  { id: "kimi@moonshot-v1-128k", name: "Moonshot V1 128K", context: "128K" }
35222
35388
  ],
35223
35389
  "kimi-coding": [
35224
- { id: "kc@kimi-for-coding", name: "Kimi for Coding", context: "128K", description: "Kimi Coding subscription model" }
35390
+ {
35391
+ id: "kc@kimi-for-coding",
35392
+ name: "Kimi for Coding",
35393
+ context: "128K",
35394
+ description: "Kimi Coding subscription model"
35395
+ }
35225
35396
  ],
35226
35397
  glm: [
35227
- { id: "glm@glm-5", name: "GLM-5", context: "200K", description: "Latest GLM model with reasoning" },
35228
- { id: "glm@glm-4.7", name: "GLM-4.7", context: "200K", description: "GLM 4.7 with reasoning" },
35229
- { id: "glm@glm-4.7-flash", name: "GLM-4.7 Flash", context: "200K", description: "Fast GLM 4.7" },
35398
+ {
35399
+ id: "glm@glm-5",
35400
+ name: "GLM-5",
35401
+ context: "200K",
35402
+ description: "Latest GLM model with reasoning"
35403
+ },
35404
+ {
35405
+ id: "glm@glm-4.7",
35406
+ name: "GLM-4.7",
35407
+ context: "200K",
35408
+ description: "GLM 4.7 with reasoning"
35409
+ },
35410
+ {
35411
+ id: "glm@glm-4.7-flash",
35412
+ name: "GLM-4.7 Flash",
35413
+ context: "200K",
35414
+ description: "Fast GLM 4.7"
35415
+ },
35230
35416
  { id: "glm@glm-4.6", name: "GLM-4.6", context: "200K" },
35231
35417
  { id: "glm@glm-4.5-flash", name: "GLM-4.5 Flash", context: "128K" }
35232
35418
  ],
35233
- zai: [
35234
- { id: "zai@glm-4.7", name: "GLM 4.7 (Z.AI)", context: "128K" }
35235
- ],
35419
+ zai: [{ id: "zai@glm-4.7", name: "GLM 4.7 (Z.AI)", context: "128K" }],
35236
35420
  ollamacloud: [
35237
35421
  { id: "oc@glm-5", name: "GLM-5", context: "203K", description: "GLM-5 on OllamaCloud" },
35238
- { id: "oc@deepseek-v3.2", name: "DeepSeek V3.2", context: "164K", description: "DeepSeek V3.2 on OllamaCloud" },
35239
- { id: "oc@gemini-3-pro-preview", name: "Gemini 3 Pro Preview", context: "1M", description: "Gemini 3 Pro on OllamaCloud" },
35240
- { id: "oc@kimi-k2.5", name: "Kimi K2.5", context: "262K", description: "Kimi K2.5 on OllamaCloud" },
35241
- { id: "oc@qwen3-coder-next", name: "Qwen3 Coder Next", context: "262K", description: "Qwen3 Coder on OllamaCloud" },
35242
- { id: "oc@minimax-m2.1", name: "MiniMax M2.1", context: "205K", description: "MiniMax M2.1 on OllamaCloud" }
35422
+ {
35423
+ id: "oc@deepseek-v3.2",
35424
+ name: "DeepSeek V3.2",
35425
+ context: "164K",
35426
+ description: "DeepSeek V3.2 on OllamaCloud"
35427
+ },
35428
+ {
35429
+ id: "oc@gemini-3-pro-preview",
35430
+ name: "Gemini 3 Pro Preview",
35431
+ context: "1M",
35432
+ description: "Gemini 3 Pro on OllamaCloud"
35433
+ },
35434
+ {
35435
+ id: "oc@kimi-k2.5",
35436
+ name: "Kimi K2.5",
35437
+ context: "262K",
35438
+ description: "Kimi K2.5 on OllamaCloud"
35439
+ },
35440
+ {
35441
+ id: "oc@qwen3-coder-next",
35442
+ name: "Qwen3 Coder Next",
35443
+ context: "262K",
35444
+ description: "Qwen3 Coder on OllamaCloud"
35445
+ },
35446
+ {
35447
+ id: "oc@minimax-m2.1",
35448
+ name: "MiniMax M2.1",
35449
+ context: "205K",
35450
+ description: "MiniMax M2.1 on OllamaCloud"
35451
+ }
35243
35452
  ]
35244
35453
  };
35245
35454
  const providerDisplay = provider.charAt(0).toUpperCase() + provider.slice(1);
@@ -35474,23 +35683,76 @@ var init_model_selector = __esm(() => {
35474
35683
  ll: "LiteLLM"
35475
35684
  };
35476
35685
  ALL_PROVIDER_CHOICES = [
35477
- { name: "Skip (keep Claude default)", value: "skip", description: "Use native Claude model for this tier" },
35686
+ {
35687
+ name: "Skip (keep Claude default)",
35688
+ value: "skip",
35689
+ description: "Use native Claude model for this tier"
35690
+ },
35478
35691
  { name: "OpenRouter", value: "openrouter", description: "580+ models via unified API" },
35479
35692
  { name: "OpenCode Zen", value: "zen", description: "Free models, no API key needed" },
35480
- { name: "Google Gemini", value: "google", description: "Direct API (GEMINI_API_KEY)", envVar: "GEMINI_API_KEY" },
35481
- { name: "OpenAI", value: "openai", description: "Direct API (OPENAI_API_KEY)", envVar: "OPENAI_API_KEY" },
35482
- { name: "xAI / Grok", value: "xai", description: "Direct API (XAI_API_KEY)", envVar: "XAI_API_KEY" },
35483
- { name: "MiniMax", value: "minimax", description: "Direct API (MINIMAX_API_KEY)", envVar: "MINIMAX_API_KEY" },
35484
- { name: "MiniMax Coding", value: "minimax-coding", description: "MiniMax Coding subscription (MINIMAX_CODING_API_KEY)", envVar: "MINIMAX_CODING_API_KEY" },
35485
- { name: "Kimi / Moonshot", value: "kimi", description: "Direct API (MOONSHOT_API_KEY)", envVar: "MOONSHOT_API_KEY" },
35486
- { name: "Kimi Coding", value: "kimi-coding", description: "Kimi Coding subscription (KIMI_CODING_API_KEY)", envVar: "KIMI_CODING_API_KEY" },
35487
- { name: "GLM / Zhipu", value: "glm", description: "Direct API (ZHIPU_API_KEY)", envVar: "ZHIPU_API_KEY" },
35488
- { name: "GLM Coding Plan", value: "glm-coding", description: "GLM Coding subscription (GLM_CODING_API_KEY)", envVar: "GLM_CODING_API_KEY" },
35693
+ {
35694
+ name: "Google Gemini",
35695
+ value: "google",
35696
+ description: "Direct API (GEMINI_API_KEY)",
35697
+ envVar: "GEMINI_API_KEY"
35698
+ },
35699
+ {
35700
+ name: "OpenAI",
35701
+ value: "openai",
35702
+ description: "Direct API (OPENAI_API_KEY)",
35703
+ envVar: "OPENAI_API_KEY"
35704
+ },
35705
+ {
35706
+ name: "xAI / Grok",
35707
+ value: "xai",
35708
+ description: "Direct API (XAI_API_KEY)",
35709
+ envVar: "XAI_API_KEY"
35710
+ },
35711
+ {
35712
+ name: "MiniMax",
35713
+ value: "minimax",
35714
+ description: "Direct API (MINIMAX_API_KEY)",
35715
+ envVar: "MINIMAX_API_KEY"
35716
+ },
35717
+ {
35718
+ name: "MiniMax Coding",
35719
+ value: "minimax-coding",
35720
+ description: "MiniMax Coding subscription (MINIMAX_CODING_API_KEY)",
35721
+ envVar: "MINIMAX_CODING_API_KEY"
35722
+ },
35723
+ {
35724
+ name: "Kimi / Moonshot",
35725
+ value: "kimi",
35726
+ description: "Direct API (MOONSHOT_API_KEY)",
35727
+ envVar: "MOONSHOT_API_KEY"
35728
+ },
35729
+ {
35730
+ name: "Kimi Coding",
35731
+ value: "kimi-coding",
35732
+ description: "Kimi Coding subscription (KIMI_CODING_API_KEY)",
35733
+ envVar: "KIMI_CODING_API_KEY"
35734
+ },
35735
+ {
35736
+ name: "GLM / Zhipu",
35737
+ value: "glm",
35738
+ description: "Direct API (ZHIPU_API_KEY)",
35739
+ envVar: "ZHIPU_API_KEY"
35740
+ },
35741
+ {
35742
+ name: "GLM Coding Plan",
35743
+ value: "glm-coding",
35744
+ description: "GLM Coding subscription (GLM_CODING_API_KEY)",
35745
+ envVar: "GLM_CODING_API_KEY"
35746
+ },
35489
35747
  { name: "Z.AI", value: "zai", description: "Z.AI API (ZAI_API_KEY)", envVar: "ZAI_API_KEY" },
35490
35748
  { name: "OllamaCloud", value: "ollamacloud", description: "Cloud models (OLLAMA_API_KEY)" },
35491
35749
  { name: "Ollama (local)", value: "ollama", description: "Local Ollama instance" },
35492
35750
  { name: "LM Studio (local)", value: "lmstudio", description: "Local LM Studio instance" },
35493
- { name: "Enter custom model", value: "custom", description: "Type a provider@model specification" }
35751
+ {
35752
+ name: "Enter custom model",
35753
+ value: "custom",
35754
+ description: "Type a provider@model specification"
35755
+ }
35494
35756
  ];
35495
35757
  PROVIDER_MODEL_PREFIX = {
35496
35758
  google: "google@",
@@ -41347,10 +41609,12 @@ var init_openai_adapter = __esm(() => {
41347
41609
  result.push({
41348
41610
  type: "message",
41349
41611
  role: msg.role,
41350
- content: [{
41351
- type: msg.role === "user" ? "input_text" : "output_text",
41352
- text: msg.content
41353
- }]
41612
+ content: [
41613
+ {
41614
+ type: msg.role === "user" ? "input_text" : "output_text",
41615
+ text: msg.content
41616
+ }
41617
+ ]
41354
41618
  });
41355
41619
  continue;
41356
41620
  }
@@ -62090,7 +62354,7 @@ class LocalTransport {
62090
62354
  this.config = config3;
62091
62355
  this.modelName = modelName;
62092
62356
  this.name = config3.name;
62093
- this.displayName = DISPLAY_NAMES[config3.name] || "Local";
62357
+ this.displayName = DISPLAY_NAMES2[config3.name] || "Local";
62094
62358
  this.concurrency = options?.concurrency;
62095
62359
  const envContextWindow = process.env.CLAUDISH_CONTEXT_WINDOW;
62096
62360
  if (envContextWindow) {
@@ -62271,7 +62535,7 @@ class LocalTransport {
62271
62535
  }
62272
62536
  }
62273
62537
  }
62274
- var localProviderAgent, DISPLAY_NAMES;
62538
+ var localProviderAgent, DISPLAY_NAMES2;
62275
62539
  var init_local = __esm(() => {
62276
62540
  init_local_queue();
62277
62541
  init_logger();
@@ -62282,7 +62546,7 @@ var init_local = __esm(() => {
62282
62546
  keepAliveTimeout: 30000,
62283
62547
  keepAliveMaxTimeout: 600000
62284
62548
  });
62285
- DISPLAY_NAMES = {
62549
+ DISPLAY_NAMES2 = {
62286
62550
  ollama: "Ollama",
62287
62551
  lmstudio: "LM Studio",
62288
62552
  vllm: "vLLM",
@@ -63973,7 +64237,10 @@ data: ${JSON.stringify(data)}
63973
64237
  }
63974
64238
  if (part.text) {
63975
64239
  if (thinkingStarted) {
63976
- send("content_block_stop", { type: "content_block_stop", index: thinkingIdx });
64240
+ send("content_block_stop", {
64241
+ type: "content_block_stop",
64242
+ index: thinkingIdx
64243
+ });
63977
64244
  thinkingStarted = false;
63978
64245
  }
63979
64246
  let cleanedText = part.text;
@@ -64003,7 +64270,10 @@ data: ${JSON.stringify(data)}
64003
64270
  }
64004
64271
  if (part.functionCall) {
64005
64272
  if (thinkingStarted) {
64006
- send("content_block_stop", { type: "content_block_stop", index: thinkingIdx });
64273
+ send("content_block_stop", {
64274
+ type: "content_block_stop",
64275
+ index: thinkingIdx
64276
+ });
64007
64277
  thinkingStarted = false;
64008
64278
  }
64009
64279
  if (textStarted) {
@@ -64935,7 +65205,10 @@ var init_anthropic_passthrough_adapter = __esm(() => {
64935
65205
  const filteredContent = message.content.map((block) => {
64936
65206
  if (block.type === "tool_result" && Array.isArray(block.content)) {
64937
65207
  const filtered = block.content.filter((c) => c.type !== "tool_reference");
64938
- return { ...block, content: filtered.length > 0 ? filtered : [{ type: "text", text: "" }] };
65208
+ return {
65209
+ ...block,
65210
+ content: filtered.length > 0 ? filtered : [{ type: "text", text: "" }]
65211
+ };
64939
65212
  }
64940
65213
  return block;
64941
65214
  }).filter((block) => block.type !== "tool_reference");
@@ -65242,6 +65515,117 @@ var init_pricing_cache = __esm(() => {
65242
65515
  };
65243
65516
  });
65244
65517
 
65518
+ // src/handlers/fallback-handler.ts
65519
+ class FallbackHandler {
65520
+ candidates;
65521
+ constructor(candidates) {
65522
+ this.candidates = candidates;
65523
+ }
65524
+ async handle(c, payload) {
65525
+ const errors6 = [];
65526
+ for (let i = 0;i < this.candidates.length; i++) {
65527
+ const { name, handler } = this.candidates[i];
65528
+ const isLast = i === this.candidates.length - 1;
65529
+ try {
65530
+ const response = await handler.handle(c, payload);
65531
+ if (response.ok) {
65532
+ if (errors6.length > 0) {
65533
+ logStderr(`[Fallback] ${name} succeeded after ${errors6.length} failed attempt(s)`);
65534
+ }
65535
+ return response;
65536
+ }
65537
+ const errorBody = await response.clone().text();
65538
+ if (!isRetryableError(response.status, errorBody)) {
65539
+ if (errors6.length > 0) {
65540
+ errors6.push({ provider: name, status: response.status, message: errorBody });
65541
+ return this.formatCombinedError(c, errors6, payload.model);
65542
+ }
65543
+ return response;
65544
+ }
65545
+ errors6.push({ provider: name, status: response.status, message: errorBody });
65546
+ if (!isLast) {
65547
+ logStderr(`[Fallback] ${name} failed (HTTP ${response.status}), trying next provider...`);
65548
+ }
65549
+ } catch (err) {
65550
+ errors6.push({ provider: name, status: 0, message: err.message });
65551
+ if (!isLast) {
65552
+ logStderr(`[Fallback] ${name} error: ${err.message}, trying next provider...`);
65553
+ }
65554
+ }
65555
+ }
65556
+ return this.formatCombinedError(c, errors6, payload.model);
65557
+ }
65558
+ formatCombinedError(c, errors6, modelName) {
65559
+ const summary = errors6.map((e) => ` ${e.provider}: HTTP ${e.status || "ERR"} — ${truncate(parseErrorMessage(e.message), 150)}`).join(`
65560
+ `);
65561
+ logStderr(`[Fallback] All ${errors6.length} provider(s) failed for ${modelName || "model"}:
65562
+ ${summary}`);
65563
+ return c.json({
65564
+ error: {
65565
+ type: "all_providers_failed",
65566
+ message: `All ${errors6.length} providers failed for model '${modelName || "unknown"}'`,
65567
+ attempts: errors6.map((e) => ({
65568
+ provider: e.provider,
65569
+ status: e.status,
65570
+ error: truncate(parseErrorMessage(e.message), 200)
65571
+ }))
65572
+ }
65573
+ }, 502);
65574
+ }
65575
+ async shutdown() {
65576
+ for (const { handler } of this.candidates) {
65577
+ if (typeof handler.shutdown === "function") {
65578
+ await handler.shutdown();
65579
+ }
65580
+ }
65581
+ }
65582
+ }
65583
+ function isRetryableError(status, errorBody) {
65584
+ if (status === 401 || status === 403)
65585
+ return true;
65586
+ if (status === 402)
65587
+ return true;
65588
+ if (status === 404)
65589
+ return true;
65590
+ if (status === 429)
65591
+ return true;
65592
+ const lower = errorBody.toLowerCase();
65593
+ if (status === 422) {
65594
+ if (lower.includes("not available") || lower.includes("model not found") || lower.includes("not supported")) {
65595
+ return true;
65596
+ }
65597
+ }
65598
+ if (status === 400) {
65599
+ if (lower.includes("model not found") || lower.includes("not registered") || lower.includes("does not exist") || lower.includes("unknown model") || lower.includes("unsupported model")) {
65600
+ return true;
65601
+ }
65602
+ }
65603
+ if (status === 500) {
65604
+ if (lower.includes("insufficient balance") || lower.includes("insufficient credit") || lower.includes("quota exceeded") || lower.includes("billing")) {
65605
+ return true;
65606
+ }
65607
+ }
65608
+ return false;
65609
+ }
65610
+ function parseErrorMessage(body) {
65611
+ try {
65612
+ const parsed = JSON.parse(body);
65613
+ if (typeof parsed.error === "string")
65614
+ return parsed.error;
65615
+ if (typeof parsed.error?.message === "string")
65616
+ return parsed.error.message;
65617
+ if (typeof parsed.message === "string")
65618
+ return parsed.message;
65619
+ } catch {}
65620
+ return body;
65621
+ }
65622
+ function truncate(s, max) {
65623
+ return s.length > max ? s.slice(0, max) + "..." : s;
65624
+ }
65625
+ var init_fallback_handler = __esm(() => {
65626
+ init_logger();
65627
+ });
65628
+
65245
65629
  // src/proxy-server.ts
65246
65630
  var exports_proxy_server = {};
65247
65631
  __export(exports_proxy_server, {
@@ -65259,7 +65643,10 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
65259
65643
  if (!openRouterHandlers.has(modelId)) {
65260
65644
  const orProvider = new OpenRouterProvider(openrouterApiKey || "");
65261
65645
  const orAdapter = new OpenRouterAdapter(modelId);
65262
- openRouterHandlers.set(modelId, new ComposedHandler(orProvider, modelId, modelId, port, { adapter: orAdapter, isInteractive: options.isInteractive }));
65646
+ openRouterHandlers.set(modelId, new ComposedHandler(orProvider, modelId, modelId, port, {
65647
+ adapter: orAdapter,
65648
+ isInteractive: options.isInteractive
65649
+ }));
65263
65650
  }
65264
65651
  return openRouterHandlers.get(modelId);
65265
65652
  };
@@ -65272,7 +65659,9 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
65272
65659
  const modelId = targetModel.replace(/^poe:/, "");
65273
65660
  if (!poeHandlers.has(modelId)) {
65274
65661
  const poeTransport = new PoeProvider(poeApiKey);
65275
- poeHandlers.set(modelId, new ComposedHandler(poeTransport, modelId, modelId, port, { isInteractive: options.isInteractive }));
65662
+ poeHandlers.set(modelId, new ComposedHandler(poeTransport, modelId, modelId, port, {
65663
+ isInteractive: options.isInteractive
65664
+ }));
65276
65665
  }
65277
65666
  return poeHandlers.get(modelId);
65278
65667
  };
@@ -65487,6 +65876,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
65487
65876
  log("[Proxy] LiteLLM model cache pre-warmed for auto-routing");
65488
65877
  }).catch(() => {});
65489
65878
  }
65879
+ const fallbackHandlerCache = new Map;
65490
65880
  const getHandlerForRequest = (requestedModel) => {
65491
65881
  if (monitorMode)
65492
65882
  return nativeHandler;
@@ -65514,6 +65904,38 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
65514
65904
  }
65515
65905
  }
65516
65906
  }
65907
+ {
65908
+ const parsedForFallback = parseModelSpec(target);
65909
+ if (!parsedForFallback.isExplicitProvider && parsedForFallback.provider !== "native-anthropic" && !isPoeModel(target)) {
65910
+ const cacheKey2 = `fallback:${target}`;
65911
+ if (fallbackHandlerCache.has(cacheKey2)) {
65912
+ return fallbackHandlerCache.get(cacheKey2);
65913
+ }
65914
+ const chain = getFallbackChain(parsedForFallback.model, parsedForFallback.provider);
65915
+ if (chain.length > 0) {
65916
+ const candidates = [];
65917
+ for (const route of chain) {
65918
+ let handler = null;
65919
+ if (route.provider === "openrouter") {
65920
+ handler = getOpenRouterHandler(route.modelSpec);
65921
+ } else {
65922
+ handler = getRemoteProviderHandler(route.modelSpec);
65923
+ }
65924
+ if (handler) {
65925
+ candidates.push({ name: route.displayName, handler });
65926
+ }
65927
+ }
65928
+ if (candidates.length > 0) {
65929
+ const resultHandler = candidates.length > 1 ? new FallbackHandler(candidates) : candidates[0].handler;
65930
+ fallbackHandlerCache.set(cacheKey2, resultHandler);
65931
+ if (!options.quiet && candidates.length > 1) {
65932
+ logStderr(`[Fallback] ${candidates.length} providers for ${parsedForFallback.model}: ${candidates.map((c) => c.name).join(" → ")}`);
65933
+ }
65934
+ return resultHandler;
65935
+ }
65936
+ }
65937
+ }
65938
+ }
65517
65939
  if (isPoeModel(target)) {
65518
65940
  const poeHandler = getPoeHandler(target);
65519
65941
  if (poeHandler) {
@@ -65625,6 +66047,8 @@ var init_proxy_server = __esm(() => {
65625
66047
  init_pricing_cache();
65626
66048
  init_model_loader();
65627
66049
  init_model_catalog_resolver();
66050
+ init_fallback_handler();
66051
+ init_auto_route();
65628
66052
  });
65629
66053
 
65630
66054
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "5.7.1",
3
+ "version": "5.9.0",
4
4
  "description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,7 +18,8 @@
18
18
  "typecheck": "tsc --noEmit",
19
19
  "lint": "biome check .",
20
20
  "format": "biome format --write .",
21
- "test": "bun test"
21
+ "test": "bun test",
22
+ "smoke": "bun run scripts/smoke-test.ts"
22
23
  },
23
24
  "dependencies": {
24
25
  "@inquirer/prompts": "^8.0.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "1.2.0",
3
- "lastUpdated": "2026-03-06",
3
+ "lastUpdated": "2026-03-14",
4
4
  "source": "https://openrouter.ai/models?categories=programming&fmt=cards&order=top-weekly",
5
5
  "models": [
6
6
  {
@@ -12,9 +12,9 @@
12
12
  "category": "programming",
13
13
  "priority": 1,
14
14
  "pricing": {
15
- "input": "$0.29/1M",
15
+ "input": "$0.25/1M",
16
16
  "output": "$1.20/1M",
17
- "average": "$0.75/1M"
17
+ "average": "$0.72/1M"
18
18
  },
19
19
  "context": "196K",
20
20
  "maxOutputTokens": 196608,
@@ -56,12 +56,12 @@
56
56
  "category": "reasoning",
57
57
  "priority": 3,
58
58
  "pricing": {
59
- "input": "$0.80/1M",
60
- "output": "$2.56/1M",
61
- "average": "$1.68/1M"
59
+ "input": "$0.72/1M",
60
+ "output": "$2.30/1M",
61
+ "average": "$1.51/1M"
62
62
  },
63
63
  "context": "202K",
64
- "maxOutputTokens": null,
64
+ "maxOutputTokens": 131072,
65
65
  "modality": "text->text",
66
66
  "supportsTools": true,
67
67
  "supportsReasoning": true,