claudish 8.0.0 → 8.1.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 +343 -242
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -731,7 +731,7 @@ var init_onepassword_config = __esm(() => {
731
731
  });
732
732
 
733
733
  // src/version.ts
734
- var VERSION = "8.0.0";
734
+ var VERSION = "8.1.0";
735
735
 
736
736
  // src/logger.ts
737
737
  var exports_logger = {};
@@ -27458,6 +27458,271 @@ var init_stdio2 = __esm(() => {
27458
27458
  init_stdio();
27459
27459
  });
27460
27460
 
27461
+ // src/providers/all-models-cache.ts
27462
+ import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
27463
+ import { homedir as homedir7 } from "os";
27464
+ import { dirname as dirname4, join as join7 } from "path";
27465
+ function readAllModelsCache(path = ALL_MODELS_CACHE_PATH) {
27466
+ if (!existsSync5(path))
27467
+ return null;
27468
+ let raw;
27469
+ try {
27470
+ raw = JSON.parse(readFileSync5(path, "utf-8"));
27471
+ } catch {
27472
+ return null;
27473
+ }
27474
+ if (!raw || typeof raw !== "object")
27475
+ return null;
27476
+ const data = raw;
27477
+ const lastUpdated = typeof data.lastUpdated === "string" ? data.lastUpdated : new Date(0).toISOString();
27478
+ const models = Array.isArray(data.models) ? data.models : [];
27479
+ const entries = Array.isArray(data.entries) ? data.entries : [];
27480
+ return {
27481
+ version: 2,
27482
+ lastUpdated,
27483
+ entries,
27484
+ models
27485
+ };
27486
+ }
27487
+ function writeAllModelsCache(data, path = ALL_MODELS_CACHE_PATH) {
27488
+ const existing = readAllModelsCache(path);
27489
+ const merged = {
27490
+ version: 2,
27491
+ lastUpdated: data.lastUpdated ?? new Date().toISOString(),
27492
+ entries: data.entries ?? existing?.entries ?? [],
27493
+ models: data.models ?? existing?.models ?? []
27494
+ };
27495
+ mkdirSync5(dirname4(path), { recursive: true });
27496
+ writeFileSync5(path, JSON.stringify(merged), "utf-8");
27497
+ }
27498
+ var ALL_MODELS_CACHE_PATH;
27499
+ var init_all_models_cache = __esm(() => {
27500
+ ALL_MODELS_CACHE_PATH = join7(homedir7(), ".claudish", "all-models.json");
27501
+ });
27502
+
27503
+ // src/providers/model-ordering.ts
27504
+ function extractVersionParts(modelId) {
27505
+ const tokens = modelId.toLowerCase().split(/[\/_-]+/);
27506
+ let started = false;
27507
+ const parts = [];
27508
+ for (const token of tokens) {
27509
+ const match = token.match(/\d+(?:\.\d+)*/);
27510
+ if (!match) {
27511
+ if (started)
27512
+ break;
27513
+ continue;
27514
+ }
27515
+ if (!started && /^\d+b$/.test(token) && Number.parseInt(match[0], 10) > 10) {
27516
+ continue;
27517
+ }
27518
+ if (!started) {
27519
+ started = true;
27520
+ for (const part of match[0].split(".")) {
27521
+ parts.push(Number.parseInt(part, 10));
27522
+ }
27523
+ if (!/^\d+(?:\.\d+)*$/.test(token)) {
27524
+ break;
27525
+ }
27526
+ continue;
27527
+ }
27528
+ if (!/^\d{1,2}(?:\.\d+)?$/.test(token)) {
27529
+ break;
27530
+ }
27531
+ for (const part of token.split(".")) {
27532
+ parts.push(Number.parseInt(part, 10));
27533
+ }
27534
+ }
27535
+ return parts;
27536
+ }
27537
+ function compareVersionPartsDesc(a, b) {
27538
+ const maxLength = Math.max(a.length, b.length);
27539
+ for (let i = 0;i < maxLength; i++) {
27540
+ const aPart = a[i] ?? -1;
27541
+ const bPart = b[i] ?? -1;
27542
+ if (aPart !== bPart) {
27543
+ return bPart - aPart;
27544
+ }
27545
+ }
27546
+ return 0;
27547
+ }
27548
+ function compareByReleaseDateDesc(a, b) {
27549
+ const aReleaseRaw = a.releaseDate ? Date.parse(a.releaseDate) : 0;
27550
+ const bReleaseRaw = b.releaseDate ? Date.parse(b.releaseDate) : 0;
27551
+ const aRelease = Number.isNaN(aReleaseRaw) ? 0 : aReleaseRaw;
27552
+ const bRelease = Number.isNaN(bReleaseRaw) ? 0 : bReleaseRaw;
27553
+ if (aRelease !== bRelease) {
27554
+ return bRelease - aRelease;
27555
+ }
27556
+ const aId = a.id ?? a.modelId ?? "";
27557
+ const bId = b.id ?? b.modelId ?? "";
27558
+ const versionCompare = compareVersionPartsDesc(extractVersionParts(aId), extractVersionParts(bId));
27559
+ if (versionCompare !== 0) {
27560
+ return versionCompare;
27561
+ }
27562
+ return aId.localeCompare(bId);
27563
+ }
27564
+
27565
+ // src/adapters/model-catalog.ts
27566
+ function lookupModel(modelId, cachePath) {
27567
+ const entry = findCacheEntry(modelId, cachePath);
27568
+ if (!entry || entry.contextWindow === undefined)
27569
+ return;
27570
+ return {
27571
+ modelId: entry.modelId,
27572
+ contextWindow: entry.contextWindow,
27573
+ supportsVision: entry.supportsVision,
27574
+ releaseDate: entry.releaseDate
27575
+ };
27576
+ }
27577
+ function lookupModelReasoning(modelId, cachePath) {
27578
+ return findCacheEntry(modelId, cachePath)?.reasoning;
27579
+ }
27580
+ function lookupModelTokenParam(modelId, cachePath) {
27581
+ return findCacheEntry(modelId, cachePath)?.tokenParam;
27582
+ }
27583
+ function lookupRouteReasoningMode(modelId, provider, cachePath) {
27584
+ return findCacheEntry(modelId, cachePath)?.aggregators?.find((aggregator) => aggregator.provider === provider)?.reasoning?.mode;
27585
+ }
27586
+ function lookupFamilyDefaultVariant(familyId, provider, cachePath) {
27587
+ const cache = readAllModelsCache(cachePath);
27588
+ if (!cache)
27589
+ return;
27590
+ for (const entry of cache.entries) {
27591
+ const rv = entry.routeVariant;
27592
+ if (!rv?.isDefault)
27593
+ continue;
27594
+ if (rv.provider !== provider)
27595
+ continue;
27596
+ if (rv.familyId === familyId || rv.baseModelId === familyId)
27597
+ return entry.modelId;
27598
+ }
27599
+ return;
27600
+ }
27601
+ function lookupVariantPresets(baseModelId, provider, cachePath) {
27602
+ const cache = readAllModelsCache(cachePath);
27603
+ if (!cache)
27604
+ return [];
27605
+ const wanted = stripVendorPrefix(baseModelId.toLowerCase());
27606
+ const found = [];
27607
+ for (const entry of cache.entries) {
27608
+ const rv = entry.routeVariant;
27609
+ if (!rv?.preset || !rv.baseModelId)
27610
+ continue;
27611
+ if (stripVendorPrefix(rv.baseModelId.toLowerCase()) !== wanted)
27612
+ continue;
27613
+ if (provider !== undefined && rv.provider !== provider)
27614
+ continue;
27615
+ found.push({ modelId: entry.modelId, preset: rv.preset, provider: rv.provider });
27616
+ }
27617
+ return found;
27618
+ }
27619
+ function lookupModelCapabilities(modelId, cachePath) {
27620
+ const entry = findCacheEntry(modelId, cachePath);
27621
+ if (!entry)
27622
+ return;
27623
+ return { supportsTools: entry.supportsTools, supportsThinking: entry.supportsThinking };
27624
+ }
27625
+ function lookupModelForProvider(modelId, provider, cachePath) {
27626
+ const entry = findCacheEntry(modelId, cachePath);
27627
+ if (!entry)
27628
+ return;
27629
+ return entry.aggregators?.find((a) => a.provider === provider)?.contextWindow ?? entry.contextWindow;
27630
+ }
27631
+ function resolveSubscriptionRouting(modelId, provider, cachePath) {
27632
+ const entry = findCacheEntry(modelId, cachePath);
27633
+ if (!entry)
27634
+ return { kind: "unknown" };
27635
+ if (entry.subscriptionPlans?.includes(provider)) {
27636
+ const agg = entry.aggregators?.find((a) => a.provider === provider);
27637
+ return agg?.externalId ? { kind: "serves", externalId: agg.externalId } : { kind: "unknown" };
27638
+ }
27639
+ return isSubscriptionPlan(provider, cachePath) ? { kind: "not-served" } : { kind: "unknown" };
27640
+ }
27641
+ function isSubscriptionPlan(provider, cachePath) {
27642
+ const cache = readAllModelsCache(cachePath);
27643
+ if (!cache)
27644
+ return false;
27645
+ return cache.entries.some((e) => e.subscriptionPlans?.includes(provider));
27646
+ }
27647
+ function stripVendorPrefix(lowerId) {
27648
+ return lowerId.includes("/") ? lowerId.substring(lowerId.lastIndexOf("/") + 1) : lowerId;
27649
+ }
27650
+ function findCacheEntry(modelId, cachePath) {
27651
+ if (modelId.includes("@")) {
27652
+ throw new Error(`model-catalog lookup received provider-routed ID "${modelId}" \u2014 callers must strip the "@" prefix before calling`);
27653
+ }
27654
+ const cache = readAllModelsCache(cachePath);
27655
+ if (!cache || cache.entries.length === 0)
27656
+ return;
27657
+ const lower = modelId.toLowerCase();
27658
+ const unprefixed = stripVendorPrefix(lower);
27659
+ for (const entry of cache.entries) {
27660
+ const entryId = entry.modelId.toLowerCase();
27661
+ const exactMatch = entryId === unprefixed || entryId === lower;
27662
+ const aliasMatch = entry.aliases?.some((a) => a.toLowerCase() === unprefixed || a.toLowerCase() === lower);
27663
+ if (exactMatch || aliasMatch) {
27664
+ return entry;
27665
+ }
27666
+ }
27667
+ return;
27668
+ }
27669
+ function classifyCatalogHit(entry, q) {
27670
+ const id = entry.modelId.toLowerCase();
27671
+ if (id === q || stripVendorPrefix(id) === q)
27672
+ return { bucket: "exact" };
27673
+ const aliases = entry.aliases ?? [];
27674
+ const exactAlias = aliases.find((a) => a.toLowerCase() === q || stripVendorPrefix(a.toLowerCase()) === q);
27675
+ if (exactAlias)
27676
+ return { bucket: "exact", matchedAlias: exactAlias };
27677
+ if (id.includes(q))
27678
+ return { bucket: "id" };
27679
+ const partialAlias = aliases.find((a) => a.toLowerCase().includes(q));
27680
+ return partialAlias ? { bucket: "alias", matchedAlias: partialAlias } : undefined;
27681
+ }
27682
+ function searchCatalogModels(query, limit = 10, cachePath) {
27683
+ const q = query.trim().toLowerCase();
27684
+ if (!q)
27685
+ return [];
27686
+ const cache = readAllModelsCache(cachePath);
27687
+ if (!cache || cache.entries.length === 0)
27688
+ return [];
27689
+ const exact = [];
27690
+ const idPartial = [];
27691
+ const aliasPartial = [];
27692
+ for (const entry of cache.entries) {
27693
+ const hit = classifyCatalogHit(entry, q);
27694
+ if (!hit)
27695
+ continue;
27696
+ const ranked = {
27697
+ entry,
27698
+ match: {
27699
+ modelId: entry.modelId,
27700
+ aliases: entry.aliases ?? [],
27701
+ subscriptionPlans: entry.subscriptionPlans ?? [],
27702
+ ...hit.matchedAlias ? { matchedAlias: hit.matchedAlias } : {}
27703
+ }
27704
+ };
27705
+ if (hit.bucket === "exact")
27706
+ exact.push(ranked);
27707
+ else if (hit.bucket === "id")
27708
+ idPartial.push(ranked);
27709
+ else
27710
+ aliasPartial.push(ranked);
27711
+ }
27712
+ const byRelevance = (a, b) => {
27713
+ const lengthDelta = a.entry.modelId.length - b.entry.modelId.length;
27714
+ if (lengthDelta !== 0)
27715
+ return lengthDelta;
27716
+ return compareByReleaseDateDesc(a.entry, b.entry);
27717
+ };
27718
+ idPartial.sort(byRelevance);
27719
+ aliasPartial.sort(byRelevance);
27720
+ return [...exact, ...idPartial, ...aliasPartial].slice(0, limit).map((r) => r.match);
27721
+ }
27722
+ var init_model_catalog = __esm(() => {
27723
+ init_all_models_cache();
27724
+ });
27725
+
27461
27726
  // src/agent-availability.ts
27462
27727
  import { spawn } from "child_process";
27463
27728
  function parseAvailableAgents(output) {
@@ -27574,26 +27839,26 @@ __export(exports_profile_config, {
27574
27839
  setKeychainEnabled: () => setKeychainEnabled,
27575
27840
  setProfile: () => setProfile
27576
27841
  });
27577
- import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
27578
- import { homedir as homedir7 } from "os";
27579
- import { dirname as dirname4, join as join7, parse as parse6 } from "path";
27842
+ import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
27843
+ import { homedir as homedir8 } from "os";
27844
+ import { dirname as dirname5, join as join8, parse as parse6 } from "path";
27580
27845
  function activeConfigFile() {
27581
27846
  return activeGlobalConfigFile(CONFIG_FILE);
27582
27847
  }
27583
27848
  function ensureConfigDir() {
27584
- if (!existsSync5(CONFIG_DIR)) {
27585
- mkdirSync5(CONFIG_DIR, { recursive: true });
27849
+ if (!existsSync6(CONFIG_DIR)) {
27850
+ mkdirSync6(CONFIG_DIR, { recursive: true });
27586
27851
  }
27587
27852
  }
27588
27853
  function loadConfig() {
27589
27854
  const activeFile = activeConfigFile();
27590
27855
  if (!getConfigFileOverride())
27591
27856
  ensureConfigDir();
27592
- if (!existsSync5(activeFile)) {
27857
+ if (!existsSync6(activeFile)) {
27593
27858
  return { ...DEFAULT_CONFIG };
27594
27859
  }
27595
27860
  try {
27596
- const content = readFileSync5(activeFile, "utf-8");
27861
+ const content = readFileSync6(activeFile, "utf-8");
27597
27862
  const config2 = JSON.parse(content);
27598
27863
  const merged = {
27599
27864
  version: config2.version || DEFAULT_CONFIG.version,
@@ -27663,39 +27928,39 @@ function loadConfig() {
27663
27928
  function saveConfig(config2) {
27664
27929
  if (!getConfigFileOverride())
27665
27930
  ensureConfigDir();
27666
- writeFileSync5(activeConfigFile(), JSON.stringify(config2, null, 2), "utf-8");
27931
+ writeFileSync6(activeConfigFile(), JSON.stringify(config2, null, 2), "utf-8");
27667
27932
  }
27668
27933
  function configExists() {
27669
- return existsSync5(CONFIG_FILE);
27934
+ return existsSync6(CONFIG_FILE);
27670
27935
  }
27671
27936
  function getConfigPath() {
27672
27937
  return CONFIG_FILE;
27673
27938
  }
27674
27939
  function getLocalConfigPath() {
27675
- const home = homedir7();
27940
+ const home = homedir8();
27676
27941
  let dir = process.cwd();
27677
27942
  const root = parse6(dir).root;
27678
27943
  while (dir !== root && dir !== home) {
27679
- const candidate = join7(dir, LOCAL_CONFIG_FILENAME);
27680
- if (existsSync5(candidate))
27944
+ const candidate = join8(dir, LOCAL_CONFIG_FILENAME);
27945
+ if (existsSync6(candidate))
27681
27946
  return candidate;
27682
- if (existsSync5(join7(dir, ".git"))) {
27947
+ if (existsSync6(join8(dir, ".git"))) {
27683
27948
  return candidate;
27684
27949
  }
27685
- dir = dirname4(dir);
27950
+ dir = dirname5(dir);
27686
27951
  }
27687
- return join7(process.cwd(), LOCAL_CONFIG_FILENAME);
27952
+ return join8(process.cwd(), LOCAL_CONFIG_FILENAME);
27688
27953
  }
27689
27954
  function localConfigExists() {
27690
- return existsSync5(getLocalConfigPath());
27955
+ return existsSync6(getLocalConfigPath());
27691
27956
  }
27692
27957
  function readProOnUltracode(paths = defaultScopedConfigPaths) {
27693
27958
  for (const pathFn of [paths.project, paths.global]) {
27694
27959
  try {
27695
27960
  const path = pathFn();
27696
- if (!existsSync5(path))
27961
+ if (!existsSync6(path))
27697
27962
  continue;
27698
- const parsed = JSON.parse(readFileSync5(path, "utf-8"));
27963
+ const parsed = JSON.parse(readFileSync6(path, "utf-8"));
27699
27964
  if (typeof parsed?.proOnUltracode === "boolean")
27700
27965
  return parsed.proOnUltracode;
27701
27966
  } catch {}
@@ -27704,17 +27969,17 @@ function readProOnUltracode(paths = defaultScopedConfigPaths) {
27704
27969
  }
27705
27970
  function isProjectDirectory() {
27706
27971
  const cwd = process.cwd();
27707
- return [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".claudish.json"].some((f) => existsSync5(join7(cwd, f)));
27972
+ return [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".claudish.json"].some((f) => existsSync6(join8(cwd, f)));
27708
27973
  }
27709
27974
  function loadLocalConfig() {
27710
27975
  if (getConfigFileOverride())
27711
27976
  return null;
27712
27977
  const localPath = getLocalConfigPath();
27713
- if (!existsSync5(localPath)) {
27978
+ if (!existsSync6(localPath)) {
27714
27979
  return null;
27715
27980
  }
27716
27981
  try {
27717
- const content = readFileSync5(localPath, "utf-8");
27982
+ const content = readFileSync6(localPath, "utf-8");
27718
27983
  const config2 = JSON.parse(content);
27719
27984
  return {
27720
27985
  ...config2,
@@ -27732,7 +27997,7 @@ function saveLocalConfig(config2) {
27732
27997
  if (toWrite.routing !== undefined && Object.keys(toWrite.routing).length === 0) {
27733
27998
  delete toWrite.routing;
27734
27999
  }
27735
- writeFileSync5(getLocalConfigPath(), JSON.stringify(toWrite, null, 2), "utf-8");
28000
+ writeFileSync6(getLocalConfigPath(), JSON.stringify(toWrite, null, 2), "utf-8");
27736
28001
  }
27737
28002
  function loadConfigForScope(scope) {
27738
28003
  if (scope === "local") {
@@ -27987,8 +28252,8 @@ function disableLocalProvider(providerName) {
27987
28252
  }
27988
28253
  var CONFIG_DIR, CONFIG_FILE, LOCAL_CONFIG_FILENAME = ".claudish.json", DEFAULT_CONFIG, defaultScopedConfigPaths;
27989
28254
  var init_profile_config = __esm(() => {
27990
- CONFIG_DIR = join7(homedir7(), ".claudish");
27991
- CONFIG_FILE = join7(CONFIG_DIR, "config.json");
28255
+ CONFIG_DIR = join8(homedir8(), ".claudish");
28256
+ CONFIG_FILE = join8(CONFIG_DIR, "config.json");
27992
28257
  DEFAULT_CONFIG = {
27993
28258
  version: "1.0.0",
27994
28259
  defaultProfile: "default",
@@ -28095,153 +28360,6 @@ var init_remote_provider_types = __esm(() => {
28095
28360
  };
28096
28361
  });
28097
28362
 
28098
- // src/providers/all-models-cache.ts
28099
- import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
28100
- import { homedir as homedir8 } from "os";
28101
- import { dirname as dirname5, join as join8 } from "path";
28102
- function readAllModelsCache(path = ALL_MODELS_CACHE_PATH) {
28103
- if (!existsSync6(path))
28104
- return null;
28105
- let raw;
28106
- try {
28107
- raw = JSON.parse(readFileSync6(path, "utf-8"));
28108
- } catch {
28109
- return null;
28110
- }
28111
- if (!raw || typeof raw !== "object")
28112
- return null;
28113
- const data = raw;
28114
- const lastUpdated = typeof data.lastUpdated === "string" ? data.lastUpdated : new Date(0).toISOString();
28115
- const models = Array.isArray(data.models) ? data.models : [];
28116
- const entries = Array.isArray(data.entries) ? data.entries : [];
28117
- return {
28118
- version: 2,
28119
- lastUpdated,
28120
- entries,
28121
- models
28122
- };
28123
- }
28124
- function writeAllModelsCache(data, path = ALL_MODELS_CACHE_PATH) {
28125
- const existing = readAllModelsCache(path);
28126
- const merged = {
28127
- version: 2,
28128
- lastUpdated: data.lastUpdated ?? new Date().toISOString(),
28129
- entries: data.entries ?? existing?.entries ?? [],
28130
- models: data.models ?? existing?.models ?? []
28131
- };
28132
- mkdirSync6(dirname5(path), { recursive: true });
28133
- writeFileSync6(path, JSON.stringify(merged), "utf-8");
28134
- }
28135
- var ALL_MODELS_CACHE_PATH;
28136
- var init_all_models_cache = __esm(() => {
28137
- ALL_MODELS_CACHE_PATH = join8(homedir8(), ".claudish", "all-models.json");
28138
- });
28139
-
28140
- // src/adapters/model-catalog.ts
28141
- function lookupModel(modelId, cachePath) {
28142
- const entry = findCacheEntry(modelId, cachePath);
28143
- if (!entry || entry.contextWindow === undefined)
28144
- return;
28145
- return {
28146
- modelId: entry.modelId,
28147
- contextWindow: entry.contextWindow,
28148
- supportsVision: entry.supportsVision,
28149
- releaseDate: entry.releaseDate
28150
- };
28151
- }
28152
- function lookupModelReasoning(modelId, cachePath) {
28153
- return findCacheEntry(modelId, cachePath)?.reasoning;
28154
- }
28155
- function lookupModelTokenParam(modelId, cachePath) {
28156
- return findCacheEntry(modelId, cachePath)?.tokenParam;
28157
- }
28158
- function lookupFamilyDefaultVariant(familyId, provider, cachePath) {
28159
- const cache2 = readAllModelsCache(cachePath);
28160
- if (!cache2)
28161
- return;
28162
- for (const entry of cache2.entries) {
28163
- const rv = entry.routeVariant;
28164
- if (!rv?.isDefault)
28165
- continue;
28166
- if (rv.provider !== provider)
28167
- continue;
28168
- if (rv.familyId === familyId || rv.baseModelId === familyId)
28169
- return entry.modelId;
28170
- }
28171
- return;
28172
- }
28173
- function lookupVariantPresets(baseModelId, provider, cachePath) {
28174
- const cache2 = readAllModelsCache(cachePath);
28175
- if (!cache2)
28176
- return [];
28177
- const wanted = stripVendorPrefix(baseModelId.toLowerCase());
28178
- const found = [];
28179
- for (const entry of cache2.entries) {
28180
- const rv = entry.routeVariant;
28181
- if (!rv?.preset || !rv.baseModelId)
28182
- continue;
28183
- if (stripVendorPrefix(rv.baseModelId.toLowerCase()) !== wanted)
28184
- continue;
28185
- if (provider !== undefined && rv.provider !== provider)
28186
- continue;
28187
- found.push({ modelId: entry.modelId, preset: rv.preset, provider: rv.provider });
28188
- }
28189
- return found;
28190
- }
28191
- function lookupModelCapabilities(modelId, cachePath) {
28192
- const entry = findCacheEntry(modelId, cachePath);
28193
- if (!entry)
28194
- return;
28195
- return { supportsTools: entry.supportsTools, supportsThinking: entry.supportsThinking };
28196
- }
28197
- function lookupModelForProvider(modelId, provider, cachePath) {
28198
- const entry = findCacheEntry(modelId, cachePath);
28199
- if (!entry)
28200
- return;
28201
- return entry.aggregators?.find((a) => a.provider === provider)?.contextWindow ?? entry.contextWindow;
28202
- }
28203
- function resolveSubscriptionRouting(modelId, provider, cachePath) {
28204
- const entry = findCacheEntry(modelId, cachePath);
28205
- if (!entry)
28206
- return { kind: "unknown" };
28207
- if (entry.subscriptionPlans?.includes(provider)) {
28208
- const agg = entry.aggregators?.find((a) => a.provider === provider);
28209
- return agg?.externalId ? { kind: "serves", externalId: agg.externalId } : { kind: "unknown" };
28210
- }
28211
- return isSubscriptionPlan(provider, cachePath) ? { kind: "not-served" } : { kind: "unknown" };
28212
- }
28213
- function isSubscriptionPlan(provider, cachePath) {
28214
- const cache2 = readAllModelsCache(cachePath);
28215
- if (!cache2)
28216
- return false;
28217
- return cache2.entries.some((e) => e.subscriptionPlans?.includes(provider));
28218
- }
28219
- function stripVendorPrefix(lowerId) {
28220
- return lowerId.includes("/") ? lowerId.substring(lowerId.lastIndexOf("/") + 1) : lowerId;
28221
- }
28222
- function findCacheEntry(modelId, cachePath) {
28223
- if (modelId.includes("@")) {
28224
- throw new Error(`model-catalog lookup received provider-routed ID "${modelId}" \u2014 callers must strip the "@" prefix before calling`);
28225
- }
28226
- const cache2 = readAllModelsCache(cachePath);
28227
- if (!cache2 || cache2.entries.length === 0)
28228
- return;
28229
- const lower = modelId.toLowerCase();
28230
- const unprefixed = stripVendorPrefix(lower);
28231
- for (const entry of cache2.entries) {
28232
- const entryId = entry.modelId.toLowerCase();
28233
- const exactMatch = entryId === unprefixed || entryId === lower;
28234
- const aliasMatch = entry.aliases?.some((a) => a.toLowerCase() === unprefixed || a.toLowerCase() === lower);
28235
- if (exactMatch || aliasMatch) {
28236
- return entry;
28237
- }
28238
- }
28239
- return;
28240
- }
28241
- var init_model_catalog = __esm(() => {
28242
- init_all_models_cache();
28243
- });
28244
-
28245
28363
  // src/adapters/tool-name-utils.ts
28246
28364
  function hashToolName(name) {
28247
28365
  let h1 = 3735928559;
@@ -39642,6 +39760,18 @@ var init_session_events = __esm(() => {
39642
39760
 
39643
39761
  // src/session-events/pro-injection.ts
39644
39762
  function resolveVariantPreset(bareModelName, provider, cachePath) {
39763
+ const routeMode = lookupRouteReasoningMode(bareModelName, provider, cachePath);
39764
+ if (routeMode) {
39765
+ if (routeMode.status !== "supported" || !routeMode.values.includes("pro")) {
39766
+ return;
39767
+ }
39768
+ return {
39769
+ params: { reasoning: { mode: "pro" } },
39770
+ provider,
39771
+ preset: "reasoning.mode=pro",
39772
+ sourceLabel: `route capability @ ${provider}`
39773
+ };
39774
+ }
39645
39775
  for (const variant of lookupVariantPresets(bareModelName, provider, cachePath)) {
39646
39776
  try {
39647
39777
  const params = parseModelParams(variant.preset);
@@ -39649,9 +39779,9 @@ function resolveVariantPreset(bareModelName, provider, cachePath) {
39649
39779
  continue;
39650
39780
  return {
39651
39781
  params,
39652
- variantModelId: variant.modelId,
39653
39782
  provider: variant.provider,
39654
- preset: variant.preset
39783
+ preset: variant.preset,
39784
+ sourceLabel: `variant ${variant.modelId} @ ${variant.provider}`
39655
39785
  };
39656
39786
  } catch {}
39657
39787
  }
@@ -39675,7 +39805,7 @@ function applyProInjection(requestPayload, opts) {
39675
39805
  if (!resolved)
39676
39806
  return false;
39677
39807
  deepMergeParams(requestPayload, resolved.params);
39678
- log(`[SessionEvents] ultracode active \u2192 preset ${resolved.preset} for ${opts.targetModel} ` + `(catalog variant ${resolved.variantModelId} @ ${resolved.provider}, session ${opts.sessionId})`);
39808
+ log(`[SessionEvents] ultracode active \u2192 preset ${resolved.preset} for ${opts.targetModel} ` + `(catalog ${resolved.sourceLabel}, session ${opts.sessionId})`);
39679
39809
  return true;
39680
39810
  } catch {
39681
39811
  return false;
@@ -51266,68 +51396,6 @@ var init_cache_ttl = __esm(() => {
51266
51396
  FIREBASE_CACHE_TTL_MS = FIREBASE_CACHE_TTL_HOURS * 60 * 60 * 1000;
51267
51397
  });
51268
51398
 
51269
- // src/providers/model-ordering.ts
51270
- function extractVersionParts(modelId) {
51271
- const tokens = modelId.toLowerCase().split(/[\/_-]+/);
51272
- let started = false;
51273
- const parts = [];
51274
- for (const token of tokens) {
51275
- const match = token.match(/\d+(?:\.\d+)*/);
51276
- if (!match) {
51277
- if (started)
51278
- break;
51279
- continue;
51280
- }
51281
- if (!started && /^\d+b$/.test(token) && Number.parseInt(match[0], 10) > 10) {
51282
- continue;
51283
- }
51284
- if (!started) {
51285
- started = true;
51286
- for (const part of match[0].split(".")) {
51287
- parts.push(Number.parseInt(part, 10));
51288
- }
51289
- if (!/^\d+(?:\.\d+)*$/.test(token)) {
51290
- break;
51291
- }
51292
- continue;
51293
- }
51294
- if (!/^\d{1,2}(?:\.\d+)?$/.test(token)) {
51295
- break;
51296
- }
51297
- for (const part of token.split(".")) {
51298
- parts.push(Number.parseInt(part, 10));
51299
- }
51300
- }
51301
- return parts;
51302
- }
51303
- function compareVersionPartsDesc(a, b) {
51304
- const maxLength = Math.max(a.length, b.length);
51305
- for (let i = 0;i < maxLength; i++) {
51306
- const aPart = a[i] ?? -1;
51307
- const bPart = b[i] ?? -1;
51308
- if (aPart !== bPart) {
51309
- return bPart - aPart;
51310
- }
51311
- }
51312
- return 0;
51313
- }
51314
- function compareByReleaseDateDesc(a, b) {
51315
- const aReleaseRaw = a.releaseDate ? Date.parse(a.releaseDate) : 0;
51316
- const bReleaseRaw = b.releaseDate ? Date.parse(b.releaseDate) : 0;
51317
- const aRelease = Number.isNaN(aReleaseRaw) ? 0 : aReleaseRaw;
51318
- const bRelease = Number.isNaN(bReleaseRaw) ? 0 : bReleaseRaw;
51319
- if (aRelease !== bRelease) {
51320
- return bRelease - aRelease;
51321
- }
51322
- const aId = a.id ?? a.modelId ?? "";
51323
- const bId = b.id ?? b.modelId ?? "";
51324
- const versionCompare = compareVersionPartsDesc(extractVersionParts(aId), extractVersionParts(bId));
51325
- if (versionCompare !== 0) {
51326
- return versionCompare;
51327
- }
51328
- return aId.localeCompare(bId);
51329
- }
51330
-
51331
51399
  // src/model-loader.ts
51332
51400
  import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
51333
51401
  import { homedir as homedir29 } from "os";
@@ -56488,7 +56556,7 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
56488
56556
  });
56489
56557
  tools.push({
56490
56558
  name: "search_models",
56491
- description: "Search all OpenRouter models by name, provider, or capability",
56559
+ description: "Search OpenRouter's listing by name, provider, or capability, and cross-reference " + "claudish's own catalog. SCOPE: the listing covers OpenRouter only, so a name's " + "absence from it is NOT evidence the name is unroutable \u2014 subscription wire ids " + "(`k3`) and catalog aliases live outside that namespace and are reported separately " + "here. This tool cannot tell you which provider will serve a model or whether the " + "hop is subscription or metered; call `preflight` for that.",
56492
56560
  inputSchema: {
56493
56561
  type: "object",
56494
56562
  properties: {
@@ -56523,13 +56591,40 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
56523
56591
  return b.score - a.score;
56524
56592
  return compareByReleaseDateDesc(orderingKey(a.model), orderingKey(b.model));
56525
56593
  }).slice(0, maxResults);
56594
+ const catalogMatches = searchCatalogModels(query, Math.max(maxResults, 5));
56595
+ const renderCatalogSection = () => {
56596
+ if (catalogMatches.length === 0)
56597
+ return "";
56598
+ let s = `
56599
+ ## Catalog names (what claudish routes)
56600
+
56601
+ `;
56602
+ s += `| Bare name | Matched alias | Subscription plan |
56603
+ `;
56604
+ s += `|-----------|---------------|-------------------|
56605
+ `;
56606
+ for (const m of catalogMatches) {
56607
+ const plans = m.subscriptionPlans.length > 0 ? m.subscriptionPlans.join(", ") : "-";
56608
+ s += `| ${m.modelId} | ${m.matchedAlias ?? "-"} | ${plans} |
56609
+ `;
56610
+ }
56611
+ s += `
56612
+ Pass the **bare name**. Routing puts a subscription ahead of the metered API and ` + "rewrites the model to that plan's wire id for you. An aggregator-qualified id " + "(`moonshotai/...`, `accounts/fireworks/...`) pins that aggregator and bills per token.\n";
56613
+ return s;
56614
+ };
56526
56615
  if (results.length === 0) {
56527
- return {
56528
- content: [{ type: "text", text: `No models found matching "${query}"` }]
56529
- };
56616
+ const catalog = renderCatalogSection();
56617
+ const text = catalog ? `No OpenRouter listing matches "${query}", but claudish's catalog knows these:
56618
+ ${catalog}` : `No models found matching "${query}".
56619
+
56620
+ ` + "This searched OpenRouter's listing only. Subscription wire ids and catalog " + "aliases are not in it, so this is not proof the name is unroutable. Call " + "`list_models` for the recommended set, or `preflight` to test a specific name " + "against real routing.";
56621
+ return { content: [{ type: "text", text }] };
56530
56622
  }
56531
56623
  let output = `# Search Results for "${query}"
56532
56624
 
56625
+ `;
56626
+ output += `## OpenRouter listing
56627
+
56533
56628
  `;
56534
56629
  output += `| Model | Provider | Pricing | Context |
56535
56630
  `;
@@ -56545,8 +56640,13 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
56545
56640
  output += `| ${model.id} | ${provider} | ${pricing} | ${context} |
56546
56641
  `;
56547
56642
  }
56643
+ output += renderCatalogSection();
56644
+ const suggested = catalogMatches[0]?.modelId ?? results[0].model.id;
56548
56645
  output += `
56549
- Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
56646
+ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
56647
+ output += `
56648
+
56649
+ To learn which provider would actually serve \`${suggested}\`, and whether that ` + "hop is covered by a subscription or billed per token, call " + `\`preflight({models: ["${suggested}"]})\`. This listing cannot answer that.`;
56550
56650
  return { content: [{ type: "text", text: output }] };
56551
56651
  }
56552
56652
  });
@@ -57450,6 +57550,7 @@ var init_mcp_server = __esm(() => {
57450
57550
  init_server2();
57451
57551
  init_stdio2();
57452
57552
  init_types();
57553
+ init_model_catalog();
57453
57554
  init_agent_availability();
57454
57555
  init_prehydrate();
57455
57556
  init_diagnostics();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "8.0.0",
3
+ "version": "8.1.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",
@@ -60,10 +60,10 @@
60
60
  "ai"
61
61
  ],
62
62
  "optionalDependencies": {
63
- "@claudish/magmux-darwin-arm64": "8.0.0",
64
- "@claudish/magmux-darwin-x64": "8.0.0",
65
- "@claudish/magmux-linux-arm64": "8.0.0",
66
- "@claudish/magmux-linux-x64": "8.0.0"
63
+ "@claudish/magmux-darwin-arm64": "8.1.0",
64
+ "@claudish/magmux-darwin-x64": "8.1.0",
65
+ "@claudish/magmux-linux-arm64": "8.1.0",
66
+ "@claudish/magmux-linux-x64": "8.1.0"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",