claudish 7.19.2 → 7.20.1

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 +168 -19
  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.19.2";
654
+ var VERSION = "7.20.1";
655
655
 
656
656
  // src/logger.ts
657
657
  var exports_logger = {};
@@ -28326,8 +28326,8 @@ var init_provider_definitions = __esm(() => {
28326
28326
  shortcuts: ["kc"],
28327
28327
  shortestPrefix: "kc",
28328
28328
  legacyPrefixes: [{ prefix: "kc/", stripPrefix: true }],
28329
- nativeModelPatterns: [{ pattern: /^kimi-for-coding$/i }],
28330
- fixedModel: "kimi-for-coding",
28329
+ nativeModelPatterns: [{ pattern: /^kimi-for-coding/i }, { pattern: /^k3(-|$)/i }],
28330
+ modelDiscovery: { path: "/models", format: "openai-models-list" },
28331
28331
  isDirectApi: true,
28332
28332
  description: "Kimi Coding Plan (kc@)"
28333
28333
  },
@@ -30475,6 +30475,22 @@ function lookupModelForProvider(modelId, provider, cachePath) {
30475
30475
  return;
30476
30476
  return entry.aggregators?.find((a) => a.provider === provider)?.contextWindow ?? entry.contextWindow;
30477
30477
  }
30478
+ function resolveSubscriptionRouting(modelId, provider, cachePath) {
30479
+ const entry = findCacheEntry(modelId, cachePath);
30480
+ if (!entry)
30481
+ return { kind: "unknown" };
30482
+ if (entry.subscriptionPlans?.includes(provider)) {
30483
+ const agg = entry.aggregators?.find((a) => a.provider === provider);
30484
+ return agg?.externalId ? { kind: "serves", externalId: agg.externalId } : { kind: "unknown" };
30485
+ }
30486
+ return isSubscriptionPlan(provider, cachePath) ? { kind: "not-served" } : { kind: "unknown" };
30487
+ }
30488
+ function isSubscriptionPlan(provider, cachePath) {
30489
+ const cache = readAllModelsCache(cachePath);
30490
+ if (!cache)
30491
+ return false;
30492
+ return cache.entries.some((e) => e.subscriptionPlans?.includes(provider));
30493
+ }
30478
30494
  function findCacheEntry(modelId, cachePath) {
30479
30495
  if (modelId.includes("@")) {
30480
30496
  throw new Error(`model-catalog lookup received provider-routed ID "${modelId}" \u2014 callers must strip the "@" prefix before calling`);
@@ -42591,7 +42607,8 @@ var init_default_routing_rules = __esm(() => {
42591
42607
  "o3-*": ["openai-codex", "openai", "openrouter"],
42592
42608
  "gemini-*": ["gemini-codeassist", "google", "openrouter"],
42593
42609
  "grok-*": ["x-ai", "openrouter"],
42594
- "kimi-*": ["kimi-coding@kimi-for-coding", "kimi", "openrouter"],
42610
+ "kimi-*": ["kimi-coding", "kimi", "openrouter"],
42611
+ "k3*": ["kimi-coding", "kimi", "openrouter"],
42595
42612
  "minimax-*": ["minimax-coding", "minimax", "openrouter"],
42596
42613
  "glm-*": ["glm-coding", "glm", "openrouter"],
42597
42614
  "z-ai-*": ["z-ai", "openrouter"],
@@ -42645,7 +42662,7 @@ function matchRoutingRule(modelName, rules) {
42645
42662
  return rules["*"];
42646
42663
  return null;
42647
42664
  }
42648
- function buildRoutingChain(entries, originalModelName) {
42665
+ function buildRoutingChain(entries, originalModelName, cachePath) {
42649
42666
  const routes = [];
42650
42667
  for (const entry of entries) {
42651
42668
  const atIdx = entry.indexOf("@");
@@ -42659,6 +42676,13 @@ function buildRoutingChain(entries, originalModelName) {
42659
42676
  modelName = originalModelName;
42660
42677
  }
42661
42678
  const provider = PROVIDER_SHORTCUTS[providerRaw.toLowerCase()] ?? providerRaw.toLowerCase();
42679
+ if (atIdx === -1) {
42680
+ const routing = resolveSubscriptionRouting(modelName, provider, cachePath);
42681
+ if (routing.kind === "not-served")
42682
+ continue;
42683
+ if (routing.kind === "serves")
42684
+ modelName = routing.externalId;
42685
+ }
42662
42686
  let modelSpec;
42663
42687
  if (provider === "openrouter") {
42664
42688
  const resolution = resolveModelNameSync(modelName, "openrouter");
@@ -42685,7 +42709,7 @@ function globMatch(pattern, value) {
42685
42709
  async function hasCredentialsForProvider(provider) {
42686
42710
  return credentials.isAvailable(provider);
42687
42711
  }
42688
- async function routeExplicit(modelSpec, model, provider) {
42712
+ async function routeExplicit(modelSpec, model, provider, cachePath) {
42689
42713
  if (!await hasCredentialsForProvider(provider)) {
42690
42714
  return {
42691
42715
  kind: "no-route",
@@ -42693,7 +42717,7 @@ async function routeExplicit(modelSpec, model, provider) {
42693
42717
  hint: buildCredentialHint(model, [provider]) ?? undefined
42694
42718
  };
42695
42719
  }
42696
- const built = buildRoutingChain([modelSpec], model)[0];
42720
+ const built = buildRoutingChain([modelSpec], model, cachePath)[0];
42697
42721
  if (!built) {
42698
42722
  return {
42699
42723
  kind: "no-route",
@@ -42702,7 +42726,7 @@ async function routeExplicit(modelSpec, model, provider) {
42702
42726
  }
42703
42727
  return { kind: "ok", primary: built, fallbacks: [] };
42704
42728
  }
42705
- async function routeBare(model, nativeProvider, rules, defaultProvider) {
42729
+ async function routeBare(model, nativeProvider, rules, defaultProvider, cachePath) {
42706
42730
  const matched = matchRoutingRule(model, rules) ?? [];
42707
42731
  const entries = [...matched];
42708
42732
  if (defaultProvider && defaultProvider.length > 0) {
@@ -42723,7 +42747,7 @@ async function routeBare(model, nativeProvider, rules, defaultProvider) {
42723
42747
  hint: buildCredentialHint(model, [nativeProvider]) ?? undefined
42724
42748
  };
42725
42749
  }
42726
- const candidates = buildRoutingChain(entries, model);
42750
+ const candidates = buildRoutingChain(entries, model, cachePath);
42727
42751
  const credentialed = [];
42728
42752
  const skipped = [];
42729
42753
  const checks4 = await Promise.all(candidates.map((candidate) => hasCredentialsForProvider(candidate.provider)));
@@ -42744,16 +42768,17 @@ async function routeBare(model, nativeProvider, rules, defaultProvider) {
42744
42768
  const [primary, ...fallbacks] = credentialed;
42745
42769
  return { kind: "ok", primary, fallbacks };
42746
42770
  }
42747
- async function route(modelSpec, rulesOverride, defaultProviderOverride) {
42771
+ async function route(modelSpec, rulesOverride, defaultProviderOverride, cachePath) {
42748
42772
  const parsed = parseModelSpec(modelSpec);
42749
42773
  if (parsed.isExplicitProvider) {
42750
- return routeExplicit(modelSpec, parsed.model, parsed.provider);
42774
+ return routeExplicit(modelSpec, parsed.model, parsed.provider, cachePath);
42751
42775
  }
42752
42776
  const rules = rulesOverride ?? loadRoutingRules();
42753
42777
  const defaultProvider = defaultProviderOverride !== undefined ? defaultProviderOverride : rulesOverride !== undefined ? undefined : loadConfig().defaultProvider;
42754
- return routeBare(parsed.model, parsed.provider, rules, defaultProvider);
42778
+ return routeBare(parsed.model, parsed.provider, rules, defaultProvider, cachePath);
42755
42779
  }
42756
42780
  var init_routing_rules = __esm(() => {
42781
+ init_model_catalog();
42757
42782
  init_authority();
42758
42783
  init_profile_config();
42759
42784
  init_auto_route();
@@ -58584,6 +58609,114 @@ var init_model_catalog2 = __esm(() => {
58584
58609
  NO_CATALOG_VENDOR_SLUGS = new Set(["litellm", "ollama", "lmstudio", "lm-studio"]);
58585
58610
  });
58586
58611
 
58612
+ // src/providers/model-discovery.ts
58613
+ function resolveBaseUrl2(catalogName) {
58614
+ const def = getProviderByName(catalogName);
58615
+ if (!def)
58616
+ return null;
58617
+ for (const envVar of def.baseUrlEnvVars ?? []) {
58618
+ const v = process.env[envVar];
58619
+ if (v)
58620
+ return v.replace(/\/+$/, "");
58621
+ }
58622
+ return (def.baseUrl || "").replace(/\/+$/, "") || null;
58623
+ }
58624
+ function readContextWindow(row) {
58625
+ for (const field of ["context_length", "context_window", "max_context_length"]) {
58626
+ const v = row[field];
58627
+ if (typeof v === "number" && Number.isFinite(v) && v > 0)
58628
+ return v;
58629
+ }
58630
+ return;
58631
+ }
58632
+ function parseOpenAIModelsList(body) {
58633
+ const data = body?.data;
58634
+ if (!Array.isArray(data))
58635
+ return [];
58636
+ const models = [];
58637
+ for (const raw2 of data) {
58638
+ if (!raw2 || typeof raw2 !== "object")
58639
+ continue;
58640
+ const row = raw2;
58641
+ const id = row.id;
58642
+ if (typeof id !== "string" || id.trim().length === 0)
58643
+ continue;
58644
+ const displayName = typeof row.display_name === "string" ? row.display_name : undefined;
58645
+ models.push({ id, displayName, contextWindow: readContextWindow(row) });
58646
+ }
58647
+ return models;
58648
+ }
58649
+ async function discoverProviderModels(providerName) {
58650
+ const cached2 = _cache2.get(providerName);
58651
+ if (cached2 && cached2.expiresAt > Date.now())
58652
+ return cached2.models;
58653
+ const def = getProviderByName(providerName);
58654
+ const descriptor = def?.modelDiscovery;
58655
+ if (!def || !descriptor)
58656
+ return [];
58657
+ const baseUrl = resolveBaseUrl2(providerName);
58658
+ if (!baseUrl)
58659
+ return [];
58660
+ const endpoint = `${baseUrl}${descriptor.path}`;
58661
+ let headers = {};
58662
+ try {
58663
+ const auth = await credentials.getRequestAuth(providerName, { model: "" });
58664
+ headers = { ...auth.headers };
58665
+ } catch (e) {
58666
+ log(`[model-discovery:${providerName}] no credentials, skipping: ${e?.message}`);
58667
+ return [];
58668
+ }
58669
+ let response;
58670
+ try {
58671
+ response = await fetch(endpoint, {
58672
+ method: "GET",
58673
+ headers,
58674
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
58675
+ });
58676
+ } catch (e) {
58677
+ log(`[model-discovery:${providerName}] fetch failed: ${e?.message}`);
58678
+ return [];
58679
+ }
58680
+ if (!response.ok) {
58681
+ log(`[model-discovery:${providerName}] HTTP ${response.status} from ${endpoint}`);
58682
+ return [];
58683
+ }
58684
+ let body;
58685
+ try {
58686
+ body = await response.json();
58687
+ } catch {
58688
+ log(`[model-discovery:${providerName}] response was not JSON`);
58689
+ return [];
58690
+ }
58691
+ const models = parseOpenAIModelsList(body);
58692
+ if (models.length === 0) {
58693
+ log(`[model-discovery:${providerName}] endpoint reachable but listed no models`);
58694
+ return [];
58695
+ }
58696
+ log(`[model-discovery:${providerName}] discovered ${models.length} models: ` + models.map((m) => `${m.id}(${m.contextWindow ?? "?"})`).join(", "));
58697
+ _cache2.set(providerName, { models, expiresAt: Date.now() + CACHE_TTL_MS3 });
58698
+ return models;
58699
+ }
58700
+ async function discoverContextWindow(providerName, modelId) {
58701
+ const models = await discoverProviderModels(providerName);
58702
+ const match2 = models.find((m) => m.id.toLowerCase() === modelId.toLowerCase());
58703
+ return match2?.contextWindow;
58704
+ }
58705
+ function rankDiscoveredModels(models) {
58706
+ return [...models].sort((a, b) => {
58707
+ const diff = (b.contextWindow ?? 0) - (a.contextWindow ?? 0);
58708
+ return diff !== 0 ? diff : a.id.localeCompare(b.id);
58709
+ });
58710
+ }
58711
+ var CACHE_TTL_MS3, FETCH_TIMEOUT_MS2 = 5000, _cache2;
58712
+ var init_model_discovery = __esm(() => {
58713
+ init_authority();
58714
+ init_logger();
58715
+ init_provider_definitions();
58716
+ CACHE_TTL_MS3 = 5 * 60 * 1000;
58717
+ _cache2 = new Map;
58718
+ });
58719
+
58587
58720
  // src/providers/ollama-discovery.ts
58588
58721
  function ollamaBaseUrl() {
58589
58722
  return process.env.OLLAMA_HOST || process.env.OLLAMA_BASE_URL || "http://localhost:11434";
@@ -59153,8 +59286,22 @@ async function selectModelFromProvider(provider, tierName, recommendedModels, _f
59153
59286
  const prefix = PROVIDER_MODEL_PREFIX[provider] || `${provider}@`;
59154
59287
  const displayName = getPickerDisplayName(provider);
59155
59288
  const def = getProviderByName(provider);
59156
- if (def?.fixedModel) {
59157
- return buildExplicitModelSpec(provider, def.fixedModel);
59289
+ if (def?.modelDiscovery) {
59290
+ const discovered = rankDiscoveredModels(await discoverProviderModels(provider));
59291
+ if (discovered.length > 0) {
59292
+ const discoveredModels = discovered.map((m) => ({
59293
+ id: m.id,
59294
+ name: m.displayName || m.id,
59295
+ description: m.contextWindow ? `${m.displayName ?? m.id} \xB7 ${Math.round(m.contextWindow / 1024)}K context` : m.displayName ?? m.id,
59296
+ provider: displayName,
59297
+ supportsTools: true,
59298
+ isFree: true,
59299
+ source: displayName
59300
+ }));
59301
+ const picked = await pickModelFromList(provider, displayName, tierName, discoveredModels);
59302
+ if (picked)
59303
+ return picked;
59304
+ }
59158
59305
  }
59159
59306
  if (provider === "ollama") {
59160
59307
  const ollamaModels = await fetchOllamaModels2({ enrichCapabilities: false });
@@ -59333,6 +59480,7 @@ var init_model_selector = __esm(() => {
59333
59480
  init_authority();
59334
59481
  init_model_loader();
59335
59482
  init_model_catalog2();
59483
+ init_model_discovery();
59336
59484
  init_provider_definitions();
59337
59485
  pickerProviderToFirebaseSlug = {
59338
59486
  openrouter: "openrouter",
@@ -64740,7 +64888,7 @@ function writeProbeModelsCache(data, path2 = PROBE_MODELS_CACHE_PATH) {
64740
64888
  mkdirSync14(dirname7(path2), { recursive: true });
64741
64889
  writeFileSync16(path2, JSON.stringify(data), "utf-8");
64742
64890
  }
64743
- function isCacheFresh(data, ttlMs = CACHE_TTL_MS3) {
64891
+ function isCacheFresh(data, ttlMs = CACHE_TTL_MS4) {
64744
64892
  if (!data?.generatedAt)
64745
64893
  return false;
64746
64894
  const generatedMs = Date.parse(data.generatedAt);
@@ -64748,7 +64896,7 @@ function isCacheFresh(data, ttlMs = CACHE_TTL_MS3) {
64748
64896
  return false;
64749
64897
  return Date.now() - generatedMs < ttlMs;
64750
64898
  }
64751
- async function fetchProbeModels(url2 = PROBE_MODELS_URL, timeoutMs = FETCH_TIMEOUT_MS2) {
64899
+ async function fetchProbeModels(url2 = PROBE_MODELS_URL, timeoutMs = FETCH_TIMEOUT_MS3) {
64752
64900
  let response;
64753
64901
  try {
64754
64902
  response = await fetch(url2, { signal: AbortSignal.timeout(timeoutMs) });
@@ -64854,9 +65002,9 @@ function isValidResponse(raw2) {
64854
65002
  return false;
64855
65003
  return true;
64856
65004
  }
64857
- var PROBE_MODELS_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/probeModels", CACHE_TTL_MS3, FETCH_TIMEOUT_MS2 = 15000, PROBE_MODELS_CACHE_PATH, _inFlight = null;
65005
+ var PROBE_MODELS_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/probeModels", CACHE_TTL_MS4, FETCH_TIMEOUT_MS3 = 15000, PROBE_MODELS_CACHE_PATH, _inFlight = null;
64858
65006
  var init_probe_catalog = __esm(() => {
64859
- CACHE_TTL_MS3 = 60 * 60 * 1000;
65007
+ CACHE_TTL_MS4 = 60 * 60 * 1000;
64860
65008
  PROBE_MODELS_CACHE_PATH = join24(homedir23(), ".claudish", "probe-models.json");
64861
65009
  });
64862
65010
 
@@ -71435,7 +71583,7 @@ async function computeMainThreadContextWindow(config3, cachePath) {
71435
71583
  continue;
71436
71584
  provider = plan.primary.provider;
71437
71585
  }
71438
- const win = lookupModelForProvider(parsed.model, provider, cachePath);
71586
+ const win = await discoverContextWindow(provider, parsed.model) ?? lookupModelForProvider(parsed.model, provider, cachePath);
71439
71587
  if (typeof win === "number" && win > 0) {
71440
71588
  min = Math.min(min, win);
71441
71589
  }
@@ -71711,6 +71859,7 @@ var init_claude_runner = __esm(() => {
71711
71859
  init_model_catalog();
71712
71860
  init_config();
71713
71861
  init_logger();
71862
+ init_model_discovery();
71714
71863
  init_profile_config();
71715
71864
  init_model_parser();
71716
71865
  init_routing_rules();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "7.19.2",
3
+ "version": "7.20.1",
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",
@@ -60,10 +60,10 @@
60
60
  "ai"
61
61
  ],
62
62
  "optionalDependencies": {
63
- "@claudish/magmux-darwin-arm64": "7.19.2",
64
- "@claudish/magmux-darwin-x64": "7.19.2",
65
- "@claudish/magmux-linux-arm64": "7.19.2",
66
- "@claudish/magmux-linux-x64": "7.19.2"
63
+ "@claudish/magmux-darwin-arm64": "7.20.1",
64
+ "@claudish/magmux-darwin-x64": "7.20.1",
65
+ "@claudish/magmux-linux-arm64": "7.20.1",
66
+ "@claudish/magmux-linux-x64": "7.20.1"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",