claudish 9.0.2 → 9.0.3

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 +397 -440
  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 = "9.0.2";
734
+ var VERSION = "9.0.3";
735
735
 
736
736
  // src/logger.ts
737
737
  var exports_logger = {};
@@ -47685,349 +47685,6 @@ var init_routing_hints = __esm(() => {
47685
47685
  };
47686
47686
  });
47687
47687
 
47688
- // src/providers/cache-ttl.ts
47689
- var FIREBASE_CACHE_TTL_HOURS = 24, FIREBASE_CACHE_TTL_MS;
47690
- var init_cache_ttl = __esm(() => {
47691
- FIREBASE_CACHE_TTL_MS = FIREBASE_CACHE_TTL_HOURS * 60 * 60 * 1000;
47692
- });
47693
-
47694
- // src/model-loader.ts
47695
- import { existsSync as existsSync19, mkdirSync as mkdirSync11, readFileSync as readFileSync18, writeFileSync as writeFileSync10 } from "fs";
47696
- import { homedir as homedir27 } from "os";
47697
- import { join as join27 } from "path";
47698
- function groupRecommendedModels(entries) {
47699
- const byId = new Map;
47700
- const categoryOrder = new Map;
47701
- for (const entry of entries) {
47702
- const list = byId.get(entry.id);
47703
- if (list)
47704
- list.push(entry);
47705
- else
47706
- byId.set(entry.id, [entry]);
47707
- if (!categoryOrder.has(entry.category))
47708
- categoryOrder.set(entry.category, categoryOrder.size);
47709
- }
47710
- const flagship = [];
47711
- const fast = [];
47712
- for (const [id, members] of byId.entries()) {
47713
- const primary = members.find((m) => m.category !== "subscription") ?? members[0];
47714
- const subscriptions = members.filter((m) => m.category === "subscription");
47715
- const bucket = primary.category === "programming" || primary.category === "vision" || primary.category === "reasoning" ? "flagship" : "fast";
47716
- const group = { id, primary, subscriptions, bucket };
47717
- if (bucket === "flagship")
47718
- flagship.push(group);
47719
- else
47720
- fast.push(group);
47721
- }
47722
- const byCuratedPriorityThenFreshness = (a, b) => {
47723
- const aCat = categoryOrder.get(a.primary.category) ?? Number.MAX_SAFE_INTEGER;
47724
- const bCat = categoryOrder.get(b.primary.category) ?? Number.MAX_SAFE_INTEGER;
47725
- if (aCat !== bCat)
47726
- return aCat - bCat;
47727
- if (a.primary.priority !== b.primary.priority)
47728
- return a.primary.priority - b.primary.priority;
47729
- return compareByReleaseDateDesc(a.primary, b.primary);
47730
- };
47731
- flagship.sort(byCuratedPriorityThenFreshness);
47732
- fast.sort(byCuratedPriorityThenFreshness);
47733
- return { flagship, fast };
47734
- }
47735
- function collectRoutingPrefixes(group, getNativePrefix) {
47736
- const slug = (group.primary.provider || "").toLowerCase();
47737
- const native = getNativePrefix(slug);
47738
- const seen = new Set;
47739
- const out = [];
47740
- if (native) {
47741
- out.push(native);
47742
- seen.add(native);
47743
- }
47744
- for (const subscriptionRow of group.subscriptions) {
47745
- const routes = subscriptionRow.subscriptions && subscriptionRow.subscriptions.length > 0 ? subscriptionRow.subscriptions : subscriptionRow.subscription ? [subscriptionRow.subscription] : [];
47746
- const orderedRoutes = [...routes].sort(compareRecommendedRoutes);
47747
- for (const route of orderedRoutes) {
47748
- const p = route?.prefix;
47749
- if (!p || seen.has(p))
47750
- continue;
47751
- seen.add(p);
47752
- out.push(p);
47753
- }
47754
- }
47755
- return out;
47756
- }
47757
- function compareRecommendedRoutes(left, right) {
47758
- const leftRank = left?.tier && Object.hasOwn(RECOMMENDED_ROUTE_TIER_ORDER, left.tier) ? RECOMMENDED_ROUTE_TIER_ORDER[left.tier] : Number.MAX_SAFE_INTEGER;
47759
- const rightRank = right?.tier && Object.hasOwn(RECOMMENDED_ROUTE_TIER_ORDER, right.tier) ? RECOMMENDED_ROUTE_TIER_ORDER[right.tier] : Number.MAX_SAFE_INTEGER;
47760
- return leftRank - rightRank;
47761
- }
47762
- function buildCatalogRoutingRules(doc2) {
47763
- const routesByModel = new Map;
47764
- let sourceIndex = 0;
47765
- for (const entry of doc2.models) {
47766
- const routes = entry.subscriptions && entry.subscriptions.length > 0 ? entry.subscriptions : entry.subscription ? [entry.subscription] : [];
47767
- for (const route of routes) {
47768
- routesByModel.set(entry.id, [...routesByModel.get(entry.id) ?? [], { route, sourceIndex }]);
47769
- sourceIndex += 1;
47770
- }
47771
- }
47772
- const rules = {};
47773
- for (const [modelId, candidates] of routesByModel) {
47774
- const seen = new Set;
47775
- const entries = candidates.filter(({ route }) => typeof route?.routingProvider === "string" && route.routingProvider.length > 0 && typeof route.command === "string" && route.command.length > 0).sort((left, right) => compareRecommendedRoutes(left.route, right.route) || left.sourceIndex - right.sourceIndex).map(({ route }) => {
47776
- const at = route.command.indexOf("@");
47777
- const wireId = at >= 0 ? route.command.slice(at + 1) : route.command;
47778
- return `${route.routingProvider}@${wireId}`;
47779
- }).filter((entry) => {
47780
- if (seen.has(entry))
47781
- return false;
47782
- seen.add(entry);
47783
- return true;
47784
- });
47785
- if (entries.length > 0)
47786
- rules[modelId] = entries;
47787
- }
47788
- return rules;
47789
- }
47790
- function parsePriceAvg(s) {
47791
- if (!s || s === "N/A")
47792
- return Number.POSITIVE_INFINITY;
47793
- if (s === "FREE")
47794
- return 0;
47795
- const m = s.match(/\$([\d.]+)/);
47796
- return m ? Number.parseFloat(m[1]) : Number.POSITIVE_INFINITY;
47797
- }
47798
- function parseCtx(s) {
47799
- if (!s || s === "N/A")
47800
- return 0;
47801
- const upper = s.toUpperCase();
47802
- if (upper.includes("M"))
47803
- return Number.parseFloat(upper) * 1e6;
47804
- if (upper.includes("K"))
47805
- return Number.parseFloat(upper) * 1000;
47806
- return Number.parseInt(s, 10) || 0;
47807
- }
47808
- function normalizePricingDisplay(raw) {
47809
- const pricing = raw || "N/A";
47810
- if (pricing.includes("-1000000"))
47811
- return "varies";
47812
- if (pricing === "$0.00/1M" || pricing === "FREE")
47813
- return "FREE";
47814
- return pricing;
47815
- }
47816
- function formatListingPrice(entry, opts) {
47817
- const rate = normalizePricingDisplay(entry.pricing?.average);
47818
- if (rate !== "N/A")
47819
- return rate;
47820
- const plan = entry.subscription?.plan;
47821
- if (!plan)
47822
- return "N/A";
47823
- return opts?.compact ? "SUB" : `SUB (${plan})`;
47824
- }
47825
- function computeQuickPicks(primaries) {
47826
- if (primaries.length === 0) {
47827
- return {
47828
- budget: null,
47829
- largeContext: null,
47830
- mostCapable: null,
47831
- visionCoding: null,
47832
- agentic: null
47833
- };
47834
- }
47835
- const priced = primaries.filter((m) => {
47836
- const p = parsePriceAvg(m.pricing?.average);
47837
- return p > 0 && p !== Number.POSITIVE_INFINITY;
47838
- }).sort((a, b) => parsePriceAvg(a.pricing?.average) - parsePriceAvg(b.pricing?.average));
47839
- const budget = priced[0] ?? null;
47840
- const byCtx = [...primaries].sort((a, b) => parseCtx(b.context) - parseCtx(a.context));
47841
- const largeContext = byCtx[0] ?? null;
47842
- const byPrice = [...primaries].sort((a, b) => parsePriceAvg(b.pricing?.average) - parsePriceAvg(a.pricing?.average));
47843
- const mostCapable = byPrice.find((m) => parsePriceAvg(m.pricing?.average) !== Number.POSITIVE_INFINITY) ?? null;
47844
- const visionCoding = primaries.find((m) => m.supportsVision === true && m.id !== budget?.id && m.id !== mostCapable?.id) ?? null;
47845
- const agentic = primaries.find((m) => m.supportsReasoning === true && m.id !== mostCapable?.id) ?? null;
47846
- return { budget, largeContext, mostCapable, visionCoding, agentic };
47847
- }
47848
- async function getRecommendedModels(opts = {}) {
47849
- const { forceRefresh = false } = opts;
47850
- if (!forceRefresh && _cachedRecommendedModels) {
47851
- return _cachedRecommendedModels;
47852
- }
47853
- if (!forceRefresh && existsSync19(RECOMMENDED_MODELS_CACHE_PATH)) {
47854
- try {
47855
- const cacheData = JSON.parse(readFileSync18(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
47856
- if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
47857
- _cachedRecommendedModels = cacheData;
47858
- return cacheData;
47859
- }
47860
- } catch {}
47861
- }
47862
- try {
47863
- const response = await fetch(FIREBASE_RECOMMENDED_URL, {
47864
- signal: AbortSignal.timeout(RECOMMENDED_FETCH_TIMEOUT_MS)
47865
- });
47866
- if (response.ok) {
47867
- const data = await response.json();
47868
- if (data.models && data.models.length > 0) {
47869
- _cachedRecommendedModels = data;
47870
- try {
47871
- const cacheDir = join27(homedir27(), ".claudish");
47872
- mkdirSync11(cacheDir, { recursive: true });
47873
- writeFileSync10(RECOMMENDED_MODELS_CACHE_PATH, JSON.stringify(data), "utf-8");
47874
- } catch {}
47875
- return data;
47876
- }
47877
- }
47878
- } catch {}
47879
- throw new Error("Unable to load recommended models: Firebase unreachable and no local cache. " + "Check connectivity.");
47880
- }
47881
- function getRecommendedModelsSync() {
47882
- if (_cachedRecommendedModels)
47883
- return _cachedRecommendedModels;
47884
- if (existsSync19(RECOMMENDED_MODELS_CACHE_PATH)) {
47885
- try {
47886
- const cacheData = JSON.parse(readFileSync18(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
47887
- if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
47888
- _cachedRecommendedModels = cacheData;
47889
- return cacheData;
47890
- }
47891
- } catch {}
47892
- }
47893
- return { version: "0", lastUpdated: "", models: [] };
47894
- }
47895
- async function warmRecommendedModels() {
47896
- try {
47897
- return await getRecommendedModels({ forceRefresh: true });
47898
- } catch {
47899
- return null;
47900
- }
47901
- }
47902
- function isFreshEnough(doc2) {
47903
- const generatedAt = doc2.generatedAt;
47904
- if (!generatedAt)
47905
- return true;
47906
- const ageHours = (Date.now() - new Date(generatedAt).getTime()) / (1000 * 60 * 60);
47907
- return ageHours <= FIREBASE_CACHE_TTL_HOURS;
47908
- }
47909
- async function searchModels(query, limit = 50) {
47910
- const url2 = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(query)}&limit=${limit}&status=active`;
47911
- const response = await fetch(url2, {
47912
- signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
47913
- });
47914
- if (!response.ok) {
47915
- throw new Error(`Firebase search returned ${response.status} ${response.statusText}`);
47916
- }
47917
- const data = await response.json();
47918
- return data.models ?? [];
47919
- }
47920
- async function getModelByIdFromFirebase(modelId) {
47921
- const url2 = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(modelId)}&limit=5`;
47922
- const response = await fetch(url2, {
47923
- signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
47924
- });
47925
- if (!response.ok) {
47926
- throw new Error(`Firebase lookup returned ${response.status} ${response.statusText}`);
47927
- }
47928
- const data = await response.json();
47929
- const models = data.models ?? [];
47930
- for (const m of models) {
47931
- if (m.modelId === modelId)
47932
- return m;
47933
- if (m.aliases?.includes(modelId))
47934
- return m;
47935
- }
47936
- return null;
47937
- }
47938
- async function getTop100Models() {
47939
- const url2 = `${FIREBASE_BASE_URL}?catalog=top100`;
47940
- const response = await fetch(url2, {
47941
- signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
47942
- });
47943
- if (!response.ok) {
47944
- throw new Error(`Firebase top100 fetch failed: ${response.status} ${response.statusText}`);
47945
- }
47946
- const data = await response.json();
47947
- return data;
47948
- }
47949
- async function getProviderList() {
47950
- const url2 = `${FIREBASE_BASE_URL}?catalog=providers`;
47951
- const response = await fetch(url2, {
47952
- signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
47953
- });
47954
- if (!response.ok) {
47955
- throw new Error(`Firebase providers fetch failed: ${response.status} ${response.statusText}`);
47956
- }
47957
- const data = await response.json();
47958
- return data.providers ?? [];
47959
- }
47960
- async function getModelsByProvider(provider, limit = 200) {
47961
- const url2 = `${FIREBASE_BASE_URL}?provider=${encodeURIComponent(provider)}&status=active&limit=${limit}`;
47962
- const response = await fetch(url2, {
47963
- signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
47964
- });
47965
- if (!response.ok) {
47966
- throw new Error(`Firebase provider query returned ${response.status} ${response.statusText}`);
47967
- }
47968
- const data = await response.json();
47969
- if (Array.isArray(data))
47970
- return data;
47971
- return data.models ?? [];
47972
- }
47973
- function loadModelInfo() {
47974
- if (_cachedModelInfo) {
47975
- return _cachedModelInfo;
47976
- }
47977
- const data = getRecommendedModelsSync();
47978
- const modelInfo = {};
47979
- for (const model of data.models) {
47980
- modelInfo[model.id] = {
47981
- name: model.name,
47982
- description: model.description,
47983
- priority: model.priority,
47984
- provider: model.provider
47985
- };
47986
- }
47987
- modelInfo.custom = {
47988
- name: "Custom Model",
47989
- description: "Enter any model ID manually",
47990
- priority: 999,
47991
- provider: "Custom"
47992
- };
47993
- _cachedModelInfo = modelInfo;
47994
- return modelInfo;
47995
- }
47996
- function getAvailableModels() {
47997
- if (_cachedModelIds) {
47998
- return _cachedModelIds;
47999
- }
48000
- const data = getRecommendedModelsSync();
48001
- const modelIds = data.models.sort((a, b) => a.priority - b.priority).map((m) => m.id);
48002
- const result = [...modelIds, "custom"];
48003
- _cachedModelIds = result;
48004
- return result;
48005
- }
48006
- var _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels = null, FIREBASE_BASE_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/queryModels", FIREBASE_RECOMMENDED_URL, RECOMMENDED_MODELS_CACHE_PATH, RECOMMENDED_FETCH_TIMEOUT_MS = 5000, SEARCH_FETCH_TIMEOUT_MS = 1e4, FIREBASE_SLUG_TO_PROVIDER_NAME, RECOMMENDED_ROUTE_TIER_ORDER;
48007
- var init_model_loader = __esm(() => {
48008
- init_cache_ttl();
48009
- FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
48010
- RECOMMENDED_MODELS_CACHE_PATH = join27(homedir27(), ".claudish", "recommended-models-cache.json");
48011
- FIREBASE_SLUG_TO_PROVIDER_NAME = {
48012
- openai: "openai",
48013
- google: "google",
48014
- "x-ai": "x-ai",
48015
- "z-ai": "z-ai",
48016
- moonshotai: "kimi",
48017
- minimax: "minimax",
48018
- qwen: "qwen",
48019
- deepseek: "deepseek",
48020
- mistralai: "mistralai",
48021
- sakana: "sakana"
48022
- };
48023
- RECOMMENDED_ROUTE_TIER_ORDER = {
48024
- native: 0,
48025
- general: 1,
48026
- metered: 2,
48027
- aggregator: 3
48028
- };
48029
- });
48030
-
48031
47688
  // src/providers/default-routing-rules.ts
48032
47689
  function validateRoutingRulesAgainstProviders(rules) {
48033
47690
  const unknown3 = [];
@@ -48119,26 +47776,12 @@ var init_model_availability = __esm(() => {
48119
47776
  function mergeRoutingRules(defaults, global_, local) {
48120
47777
  return { ...defaults, ...global_, ...local };
48121
47778
  }
48122
- function loadRoutingRules() {
48123
- const local = loadLocalConfig()?.routing ?? {};
48124
- const global_ = loadConfig().routing ?? {};
47779
+ function loadRoutingRules(sources) {
47780
+ const local = sources ? sources.localRules : loadLocalConfig()?.routing ?? {};
47781
+ const global_ = sources ? sources.globalRules : loadConfig().routing ?? {};
48125
47782
  validateRoutingRules(local);
48126
47783
  validateRoutingRules(global_);
48127
- const catalogRules = retainKnownCatalogRoutingRules(buildCatalogRoutingRules(getRecommendedModelsSync()));
48128
- return mergeRoutingRules({ ...DEFAULT_ROUTING_RULES, ...catalogRules }, global_, local);
48129
- }
48130
- function retainKnownCatalogRoutingRules(rules) {
48131
- const retained = {};
48132
- for (const [modelId, entries] of Object.entries(rules)) {
48133
- const knownEntries = entries.filter((entry) => {
48134
- const providerRaw = entry.split("@", 1)[0]?.toLowerCase() ?? "";
48135
- const provider = PROVIDER_SHORTCUTS[providerRaw] ?? providerRaw;
48136
- return getProviderByName(provider) !== undefined;
48137
- });
48138
- if (knownEntries.length > 0)
48139
- retained[modelId] = knownEntries;
48140
- }
48141
- return retained;
47784
+ return mergeRoutingRules(DEFAULT_ROUTING_RULES, global_, local);
48142
47785
  }
48143
47786
  function validateRoutingRules(rules) {
48144
47787
  const seenLower = new Map;
@@ -48333,7 +47976,6 @@ var init_routing_rules = __esm(() => {
48333
47976
  init_authority();
48334
47977
  init_remote_provider_types();
48335
47978
  init_logger();
48336
- init_model_loader();
48337
47979
  init_profile_config();
48338
47980
  init_auto_route();
48339
47981
  init_catalog_client();
@@ -49477,8 +49119,8 @@ __export(exports_session_discovery, {
49477
49119
  });
49478
49120
  import { execFile, execFileSync as execFileSync2 } from "child_process";
49479
49121
  import { closeSync as closeSync6, openSync as openSync6, readSync as readSync2, readdirSync as readdirSync4, realpathSync, statSync as statSync5 } from "fs";
49480
- import { homedir as homedir28 } from "os";
49481
- import { basename, join as join28 } from "path";
49122
+ import { homedir as homedir27 } from "os";
49123
+ import { basename, join as join27 } from "path";
49482
49124
  function slugForPath(absPath) {
49483
49125
  return absPath.replace(/[/.]/g, "-");
49484
49126
  }
@@ -49487,7 +49129,7 @@ function transcriptPathFor(cwd, sessionUuid) {
49487
49129
  try {
49488
49130
  real = realpathSync(cwd);
49489
49131
  } catch {}
49490
- return join28(PROJECTS_DIR, slugForPath(real), `${sessionUuid}.jsonl`);
49132
+ return join27(PROJECTS_DIR, slugForPath(real), `${sessionUuid}.jsonl`);
49491
49133
  }
49492
49134
  function isAgentSession(row) {
49493
49135
  return row.entrypoint !== undefined && row.entrypoint !== "cli";
@@ -49534,7 +49176,7 @@ function projectDirs() {
49534
49176
  }
49535
49177
  }
49536
49178
  function sessionsIn(dirName) {
49537
- const dir = join28(PROJECTS_DIR, dirName);
49179
+ const dir = join27(PROJECTS_DIR, dirName);
49538
49180
  let names;
49539
49181
  try {
49540
49182
  names = readdirSync4(dir).filter((n) => n.endsWith(".jsonl"));
@@ -49543,7 +49185,7 @@ function sessionsIn(dirName) {
49543
49185
  }
49544
49186
  const rows = [];
49545
49187
  for (const n of names) {
49546
- const file2 = join28(dir, n);
49188
+ const file2 = join27(dir, n);
49547
49189
  try {
49548
49190
  const st = statSync5(file2);
49549
49191
  if (st.size === 0)
@@ -49902,7 +49544,7 @@ function findLatestSessionId(cwd = process.cwd(), sinceMs = 0) {
49902
49544
  }
49903
49545
  var ENTRYPOINT_BYTES = 8192, PROJECTS_DIR, ACTIVE_WINDOW_MS = 120000, HEAD_BYTES, TAIL_BYTES, HARNESS_ENVELOPES, DEEP_TAIL_BYTES, RECENT_AI_TURNS = 5, RECENT_USER_TURNS = 1;
49904
49546
  var init_session_discovery = __esm(() => {
49905
- PROJECTS_DIR = join28(homedir28(), ".claude", "projects");
49547
+ PROJECTS_DIR = join27(homedir27(), ".claude", "projects");
49906
49548
  HEAD_BYTES = 64 * 1024;
49907
49549
  TAIL_BYTES = 128 * 1024;
49908
49550
  HARNESS_ENVELOPES = [
@@ -49937,19 +49579,19 @@ function newStdioDecoder() {
49937
49579
  var init_stdio_decode = () => {};
49938
49580
 
49939
49581
  // src/team-stats.ts
49940
- import { existsSync as existsSync20, readFileSync as readFileSync19, writeFileSync as writeFileSync11 } from "fs";
49941
- import { join as join29 } from "path";
49582
+ import { existsSync as existsSync19, readFileSync as readFileSync18, writeFileSync as writeFileSync10 } from "fs";
49583
+ import { join as join28 } from "path";
49942
49584
  function statsDir(sessionPath) {
49943
- return join29(sessionPath, "stats");
49585
+ return join28(sessionPath, "stats");
49944
49586
  }
49945
49587
  function tokenFileFor(sessionPath, anonId) {
49946
- return join29(statsDir(sessionPath), `${anonId}.json`);
49588
+ return join28(statsDir(sessionPath), `${anonId}.json`);
49947
49589
  }
49948
49590
  function readTokenStatsAt(path) {
49949
- if (!existsSync20(path))
49591
+ if (!existsSync19(path))
49950
49592
  return null;
49951
49593
  try {
49952
- return JSON.parse(readFileSync19(path, "utf-8"));
49594
+ return JSON.parse(readFileSync18(path, "utf-8"));
49953
49595
  } catch {
49954
49596
  return null;
49955
49597
  }
@@ -50100,7 +49742,7 @@ ${segs.join(" \xB7 ")}`;
50100
49742
  }
50101
49743
  function writeStatusFile(sessionPath, manifest, status, opts) {
50102
49744
  try {
50103
- writeFileSync11(join29(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
49745
+ writeFileSync10(join28(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
50104
49746
  `, "utf-8");
50105
49747
  } catch {}
50106
49748
  }
@@ -50135,13 +49777,13 @@ __export(exports_team_orchestrator, {
50135
49777
  import { spawn as spawn2 } from "child_process";
50136
49778
  import {
50137
49779
  createWriteStream,
50138
- existsSync as existsSync21,
50139
- mkdirSync as mkdirSync12,
50140
- readFileSync as readFileSync20,
49780
+ existsSync as existsSync20,
49781
+ mkdirSync as mkdirSync11,
49782
+ readFileSync as readFileSync19,
50141
49783
  readdirSync as readdirSync5,
50142
- writeFileSync as writeFileSync12
49784
+ writeFileSync as writeFileSync11
50143
49785
  } from "fs";
50144
- import { basename as basename2, join as join30, resolve as resolve3 } from "path";
49786
+ import { basename as basename2, join as join29, resolve as resolve3 } from "path";
50145
49787
  function resolveCaptureMode(explicit, env = process.env) {
50146
49788
  if (explicit)
50147
49789
  return explicit;
@@ -50259,7 +49901,7 @@ function persistErrorLog(errorLogPath, header, stderr, stdoutTail) {
50259
49901
  parts.push("--- stderr ---", stderr.trim() ? redactSecrets(stderr) : "(empty)", "");
50260
49902
  parts.push("--- stdout (tail) ---", stdoutTail.trim() ? redactSecrets(stdoutTail) : "(empty)", "");
50261
49903
  try {
50262
- writeFileSync12(errorLogPath, parts.join(`
49904
+ writeFileSync11(errorLogPath, parts.join(`
50263
49905
  `), "utf-8");
50264
49906
  } catch {}
50265
49907
  }
@@ -50277,10 +49919,10 @@ function readTeamInputFile(inputPath) {
50277
49919
  if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
50278
49920
  throw new Error(`Input file must be within current directory: ${inputPath}`);
50279
49921
  }
50280
- if (!existsSync21(resolved)) {
49922
+ if (!existsSync20(resolved)) {
50281
49923
  throw new Error(`Input file not found: ${resolved}`);
50282
49924
  }
50283
- const text = readFileSync20(resolved, "utf-8");
49925
+ const text = readFileSync19(resolved, "utf-8");
50284
49926
  if (text.trim().length === 0) {
50285
49927
  throw new Error(`Input file is empty: ${resolved}`);
50286
49928
  }
@@ -50290,14 +49932,14 @@ function setupSession(sessionPath, models, input) {
50290
49932
  if (models.length === 0) {
50291
49933
  throw new Error("At least one model is required");
50292
49934
  }
50293
- if (existsSync21(join30(sessionPath, "manifest.json"))) {
49935
+ if (existsSync20(join29(sessionPath, "manifest.json"))) {
50294
49936
  throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
50295
49937
  }
50296
- mkdirSync12(join30(sessionPath, "work"), { recursive: true });
50297
- mkdirSync12(join30(sessionPath, "errors"), { recursive: true });
49938
+ mkdirSync11(join29(sessionPath, "work"), { recursive: true });
49939
+ mkdirSync11(join29(sessionPath, "errors"), { recursive: true });
50298
49940
  if (input !== undefined) {
50299
- writeFileSync12(join30(sessionPath, "input.md"), input, "utf-8");
50300
- } else if (!existsSync21(join30(sessionPath, "input.md"))) {
49941
+ writeFileSync11(join29(sessionPath, "input.md"), input, "utf-8");
49942
+ } else if (!existsSync20(join29(sessionPath, "input.md"))) {
50301
49943
  throw new Error(`No input.md found at ${sessionPath} and no input provided`);
50302
49944
  }
50303
49945
  const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
@@ -50314,9 +49956,9 @@ function setupSession(sessionPath, models, input) {
50314
49956
  model: models[i],
50315
49957
  assignedAt: now2
50316
49958
  };
50317
- mkdirSync12(join30(sessionPath, "work", anonId), { recursive: true });
49959
+ mkdirSync11(join29(sessionPath, "work", anonId), { recursive: true });
50318
49960
  }
50319
- writeFileSync12(join30(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
49961
+ writeFileSync11(join29(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
50320
49962
  const status = {
50321
49963
  startedAt: now2,
50322
49964
  models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
@@ -50330,7 +49972,7 @@ function setupSession(sessionPath, models, input) {
50330
49972
  }
50331
49973
  ]))
50332
49974
  };
50333
- writeFileSync12(join30(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
49975
+ writeFileSync11(join29(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
50334
49976
  return manifest;
50335
49977
  }
50336
49978
  function assertValidRequirePattern(pattern) {
@@ -50347,22 +49989,22 @@ function readFullOutputIfNeeded(opts) {
50347
49989
  if (crashed || !requirePattern || outputSize <= STDOUT_TAIL_LIMIT)
50348
49990
  return;
50349
49991
  try {
50350
- return readFileSync20(outputPath, "utf-8");
49992
+ return readFileSync19(outputPath, "utf-8");
50351
49993
  } catch {
50352
49994
  return;
50353
49995
  }
50354
49996
  }
50355
49997
  async function startModels(sessionPath, opts = {}) {
50356
49998
  assertValidRequirePattern(opts.requirePattern);
50357
- const manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
50358
- const statusPath = join30(sessionPath, "status.json");
50359
- const inputPath = join30(sessionPath, "input.md");
50360
- const inputContent = readFileSync20(inputPath, "utf-8");
49999
+ const manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
50000
+ const statusPath = join29(sessionPath, "status.json");
50001
+ const inputPath = join29(sessionPath, "input.md");
50002
+ const inputContent = readFileSync19(inputPath, "utf-8");
50361
50003
  const spawnPlan = await (opts.spawnPlanner ?? prehydrateCredentialsForSpawn)(Object.values(manifest.models).map((m) => m.model));
50362
- const statusCache = JSON.parse(readFileSync20(statusPath, "utf-8"));
50004
+ const statusCache = JSON.parse(readFileSync19(statusPath, "utf-8"));
50363
50005
  function updateModelStatus(id, update) {
50364
50006
  statusCache.models[id] = { ...statusCache.models[id], ...update };
50365
- writeFileSync12(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
50007
+ writeFileSync11(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
50366
50008
  }
50367
50009
  const minOutputBytes = opts.minOutputBytes ?? DEFAULT_MIN_OUTPUT_BYTES;
50368
50010
  const requirePattern = opts.requirePattern;
@@ -50395,7 +50037,7 @@ async function startModels(sessionPath, opts = {}) {
50395
50037
  persistErrorLog(rt.errorLogPath, `RECOVERED: ${note}`, stderr, stdoutTail);
50396
50038
  opts.onStatusChange?.(id, statusCache.models[id]);
50397
50039
  }
50398
- mkdirSync12(statsDir(sessionPath), { recursive: true });
50040
+ mkdirSync11(statsDir(sessionPath), { recursive: true });
50399
50041
  const processes = new Map;
50400
50042
  const runtimes = new Map;
50401
50043
  const cancelledSlots = new Set;
@@ -50408,9 +50050,9 @@ async function startModels(sessionPath, opts = {}) {
50408
50050
  process.on("SIGINT", sigintHandler);
50409
50051
  const completionPromises = [];
50410
50052
  for (const [anonId, entry] of Object.entries(manifest.models)) {
50411
- const outputPath = join30(sessionPath, `response-${anonId}.md`);
50412
- const errorLogPath = join30(sessionPath, "errors", `${anonId}.log`);
50413
- const upstreamErrorLogPath = join30(sessionPath, "errors", `${anonId}-upstream.jsonl`);
50053
+ const outputPath = join29(sessionPath, `response-${anonId}.md`);
50054
+ const errorLogPath = join29(sessionPath, "errors", `${anonId}.log`);
50055
+ const upstreamErrorLogPath = join29(sessionPath, "errors", `${anonId}-upstream.jsonl`);
50414
50056
  const spawnModel = spawnPlan.pinned.get(entry.model) ?? entry.model;
50415
50057
  const args = [
50416
50058
  "--model",
@@ -50550,7 +50192,7 @@ async function startModels(sessionPath, opts = {}) {
50550
50192
  stderrSnippet: stderr ? redactSecrets(stderr).slice(-2000) : undefined,
50551
50193
  stdoutSnippet: stdoutTail ? redactSecrets(stdoutTail).slice(-2000) : undefined,
50552
50194
  errorLogPath,
50553
- upstreamErrorLogPath: existsSync21(upstreamErrorLogPath) ? upstreamErrorLogPath : undefined,
50195
+ upstreamErrorLogPath: existsSync20(upstreamErrorLogPath) ? upstreamErrorLogPath : undefined,
50554
50196
  workDir: sessionPath
50555
50197
  }
50556
50198
  });
@@ -50570,7 +50212,7 @@ async function startModels(sessionPath, opts = {}) {
50570
50212
  proc.on("exit", (code) => {
50571
50213
  const timedOut = statusCache.models[anonId]?.state === "TIMEOUT";
50572
50214
  if (!timedOut && meaningfulStderr(stderr)) {
50573
- writeFileSync12(errorLogPath, redactSecrets(stderr), "utf-8");
50215
+ writeFileSync11(errorLogPath, redactSecrets(stderr), "utf-8");
50574
50216
  }
50575
50217
  exitCode = code;
50576
50218
  if (outputStream.destroyed) {
@@ -50650,23 +50292,23 @@ async function judgeResponses(sessionPath, opts = {}) {
50650
50292
  const responses = {};
50651
50293
  for (const file2 of responseFiles) {
50652
50294
  const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
50653
- responses[id] = readFileSync20(join30(sessionPath, file2), "utf-8");
50295
+ responses[id] = readFileSync19(join29(sessionPath, file2), "utf-8");
50654
50296
  }
50655
- const input = readFileSync20(join30(sessionPath, "input.md"), "utf-8");
50297
+ const input = readFileSync19(join29(sessionPath, "input.md"), "utf-8");
50656
50298
  const judgePrompt = buildJudgePrompt(input, responses);
50657
- writeFileSync12(join30(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
50299
+ writeFileSync11(join29(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
50658
50300
  const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
50659
- const judgePath = join30(sessionPath, "judging");
50660
- mkdirSync12(judgePath, { recursive: true });
50301
+ const judgePath = join29(sessionPath, "judging");
50302
+ mkdirSync11(judgePath, { recursive: true });
50661
50303
  setupSession(judgePath, judgeModels, judgePrompt);
50662
50304
  await runModels(judgePath, { claudeFlags: opts.claudeFlags });
50663
50305
  const votes = parseJudgeVotes(judgePath, Object.keys(responses));
50664
50306
  const verdict = aggregateVerdict(votes, Object.keys(responses));
50665
- writeFileSync12(join30(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
50307
+ writeFileSync11(join29(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
50666
50308
  return verdict;
50667
50309
  }
50668
50310
  function getStatus(sessionPath) {
50669
- return JSON.parse(readFileSync20(join30(sessionPath, "status.json"), "utf-8"));
50311
+ return JSON.parse(readFileSync19(join29(sessionPath, "status.json"), "utf-8"));
50670
50312
  }
50671
50313
  function fisherYatesShuffle(arr) {
50672
50314
  for (let i = arr.length - 1;i > 0; i--) {
@@ -50676,7 +50318,7 @@ function fisherYatesShuffle(arr) {
50676
50318
  return arr;
50677
50319
  }
50678
50320
  function getDefaultJudgeModels(sessionPath) {
50679
- const manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
50321
+ const manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
50680
50322
  return Object.values(manifest.models).map((e) => e.model);
50681
50323
  }
50682
50324
  function buildJudgePrompt(input, responses) {
@@ -50739,7 +50381,7 @@ function parseJudgeVotes(judgePath, responseIds) {
50739
50381
  const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
50740
50382
  let content;
50741
50383
  try {
50742
- content = readFileSync20(join30(judgePath, file2), "utf-8");
50384
+ content = readFileSync19(join29(judgePath, file2), "utf-8");
50743
50385
  } catch {
50744
50386
  continue;
50745
50387
  }
@@ -50791,7 +50433,7 @@ function aggregateVerdict(votes, responseIds) {
50791
50433
  function formatVerdict(verdict, sessionPath) {
50792
50434
  let manifest = null;
50793
50435
  try {
50794
- manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
50436
+ manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
50795
50437
  } catch {}
50796
50438
  let output = `# Team Verdict
50797
50439
 
@@ -50845,15 +50487,15 @@ import {
50845
50487
  appendFileSync as appendFileSync6,
50846
50488
  closeSync as closeSync7,
50847
50489
  createWriteStream as createWriteStream2,
50848
- mkdirSync as mkdirSync13,
50490
+ mkdirSync as mkdirSync12,
50849
50491
  openSync as openSync7,
50850
- readFileSync as readFileSync21,
50492
+ readFileSync as readFileSync20,
50851
50493
  readSync as readSync3,
50852
50494
  statSync as statSync6,
50853
- writeFileSync as writeFileSync13
50495
+ writeFileSync as writeFileSync12
50854
50496
  } from "fs";
50855
- import { homedir as homedir29 } from "os";
50856
- import { join as join31, resolve as resolve4, sep } from "path";
50497
+ import { homedir as homedir28 } from "os";
50498
+ import { join as join30, resolve as resolve4, sep } from "path";
50857
50499
  import { StringDecoder as StringDecoder2 } from "string_decoder";
50858
50500
  function buildChannelSpawnArgs(opts) {
50859
50501
  return [
@@ -50928,7 +50570,7 @@ function readJsonObject(path, maxBytes) {
50928
50570
  try {
50929
50571
  if (fileSize(path) > maxBytes)
50930
50572
  return null;
50931
- const parsed = JSON.parse(readFileSync21(path, "utf-8"));
50573
+ const parsed = JSON.parse(readFileSync20(path, "utf-8"));
50932
50574
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
50933
50575
  return null;
50934
50576
  return parsed;
@@ -50944,7 +50586,7 @@ function dropLeadingFragment(tail) {
50944
50586
  return firstBreak === -1 ? tail.text : tail.text.slice(firstBreak + 1);
50945
50587
  }
50946
50588
  function diskAccounting(sessionDir) {
50947
- const stats = readTokenStatsAt(join31(sessionDir, "tokens.json"));
50589
+ const stats = readTokenStatsAt(join30(sessionDir, "tokens.json"));
50948
50590
  return {
50949
50591
  tokensUsed: (stats?.total_tokens ?? 0) || (stats?.input_tokens ?? 0) + (stats?.output_tokens ?? 0),
50950
50592
  costUsd: stats?.total_cost ?? 0,
@@ -50984,7 +50626,7 @@ class SessionManager {
50984
50626
  this.maxSessions = options?.maxSessions ?? DEFAULT_MAX_SESSIONS;
50985
50627
  this.scrollbackCapacity = options?.scrollbackCapacity ?? DEFAULT_SCROLLBACK;
50986
50628
  this.terminalRetentionMs = options?.terminalRetentionMs ?? TERMINAL_RETENTION_MS;
50987
- this.sessionsDir = options?.sessionsDir ?? process.env.CLAUDISH_SESSIONS_DIR ?? join31(homedir29(), ".claudish", "sessions");
50629
+ this.sessionsDir = options?.sessionsDir ?? process.env.CLAUDISH_SESSIONS_DIR ?? join30(homedir28(), ".claudish", "sessions");
50988
50630
  this.stallSeconds = options?.stallSeconds;
50989
50631
  this.onStateChange = options?.onStateChange;
50990
50632
  }
@@ -51000,19 +50642,19 @@ class SessionManager {
51000
50642
  const claudeSessionId = randomUUID4();
51001
50643
  const timeout = Math.min(opts.timeoutSeconds ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
51002
50644
  const startedAt = new Date().toISOString();
51003
- const sessionDir = opts.sessionDir ?? join31(this.sessionsDir, sessionId2);
51004
- mkdirSync13(sessionDir, { recursive: true });
50645
+ const sessionDir = opts.sessionDir ?? join30(this.sessionsDir, sessionId2);
50646
+ mkdirSync12(sessionDir, { recursive: true });
51005
50647
  if (opts.prompt) {
51006
- writeFileSync13(join31(sessionDir, "prompt.md"), opts.prompt, "utf-8");
50648
+ writeFileSync12(join30(sessionDir, "prompt.md"), opts.prompt, "utf-8");
51007
50649
  }
51008
50650
  const args = buildChannelSpawnArgs({
51009
50651
  model: opts.spawnModel ?? opts.model,
51010
50652
  claudeSessionId,
51011
50653
  claudishFlags: opts.claudishFlags
51012
50654
  });
51013
- const tokenFile = opts.tokenFile ?? join31(sessionDir, "tokens.json");
51014
- const eventLogPath = join31(sessionDir, "events.jsonl");
51015
- const upstreamErrorLogPath = join31(sessionDir, "upstream-errors.jsonl");
50655
+ const tokenFile = opts.tokenFile ?? join30(sessionDir, "tokens.json");
50656
+ const eventLogPath = join30(sessionDir, "events.jsonl");
50657
+ const upstreamErrorLogPath = join30(sessionDir, "upstream-errors.jsonl");
51016
50658
  const cwd = opts.cwd ?? process.cwd();
51017
50659
  const spawnTarget = resolveClaudishSpawn();
51018
50660
  const proc = spawn3(spawnTarget.command, [...spawnTarget.prefixArgs, ...args], {
@@ -51027,7 +50669,7 @@ class SessionManager {
51027
50669
  }
51028
50670
  });
51029
50671
  const scrollback = new ScrollbackBuffer(this.scrollbackCapacity);
51030
- const outputLogStream = createWriteStream2(join31(sessionDir, "output.log"));
50672
+ const outputLogStream = createWriteStream2(join30(sessionDir, "output.log"));
51031
50673
  const entry = {
51032
50674
  info: {
51033
50675
  sessionId: sessionId2,
@@ -51319,7 +50961,7 @@ class SessionManager {
51319
50961
  return null;
51320
50962
  const root = resolve4(this.sessionsDir);
51321
50963
  const dir = resolve4(root, sessionId2);
51322
- if (dir !== join31(root, sessionId2))
50964
+ if (dir !== join30(root, sessionId2))
51323
50965
  return null;
51324
50966
  if (!dir.startsWith(root + sep))
51325
50967
  return null;
@@ -51338,7 +50980,7 @@ class SessionManager {
51338
50980
  } catch {
51339
50981
  return null;
51340
50982
  }
51341
- const meta3 = readJsonObject(join31(sessionDir, "meta.json"), META_READ_LIMIT);
50983
+ const meta3 = readJsonObject(join30(sessionDir, "meta.json"), META_READ_LIMIT);
51342
50984
  const partial2 = meta3 === null;
51343
50985
  const measured = diskAccounting(sessionDir);
51344
50986
  const startedAt = metaString(meta3?.startedAt) ?? new Date(dirMtimeMs).toISOString();
@@ -51368,7 +51010,7 @@ class SessionManager {
51368
51010
  };
51369
51011
  }
51370
51012
  diskOutput(record4, tailLines) {
51371
- const tail = readTailText(join31(record4.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
51013
+ const tail = readTailText(join30(record4.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
51372
51014
  const buffer = new ScrollbackBuffer(this.scrollbackCapacity);
51373
51015
  if (tail?.text)
51374
51016
  buffer.append(dropLeadingFragment(tail));
@@ -51387,9 +51029,9 @@ class SessionManager {
51387
51029
  }
51388
51030
  diskDiagnostics(record4, limit) {
51389
51031
  const { sessionDir, info } = record4;
51390
- const eventLogPath = join31(sessionDir, "events.jsonl");
51391
- const upstreamErrorLogPath = join31(sessionDir, "upstream-errors.jsonl");
51392
- const outputLogPath = join31(sessionDir, "output.log");
51032
+ const eventLogPath = join30(sessionDir, "events.jsonl");
51033
+ const upstreamErrorLogPath = join30(sessionDir, "upstream-errors.jsonl");
51034
+ const outputLogPath = join30(sessionDir, "output.log");
51393
51035
  const events = readTailLines(eventLogPath, EVENT_TAIL_BYTES);
51394
51036
  const outputTail = readTailText(outputLogPath, OUTPUT_TAIL_BYTES);
51395
51037
  return {
@@ -51431,7 +51073,7 @@ class SessionManager {
51431
51073
  };
51432
51074
  }
51433
51075
  diskStderrForDiagnostics(record4) {
51434
- const tail = readTailText(join31(record4.sessionDir, "stderr.log"), STDERR_READ_BYTES);
51076
+ const tail = readTailText(join30(record4.sessionDir, "stderr.log"), STDERR_READ_BYTES);
51435
51077
  const raw = tail?.text ?? "";
51436
51078
  const filtered = record4.info.status === "completed";
51437
51079
  const source = filtered ? meaningfulStderr(raw) : raw;
@@ -51607,11 +51249,11 @@ ${STDERR_TRUNCATION_MARKER} ${STDERR_SIDE_LIMIT} bytes per end \u2026
51607
51249
  entry.outputLogStream?.end();
51608
51250
  entry.outputLogStream = null;
51609
51251
  if (entry.stderr) {
51610
- writeFileSync13(join31(entry.sessionDir, "stderr.log"), redactSecrets(entry.stderr), "utf-8");
51252
+ writeFileSync12(join30(entry.sessionDir, "stderr.log"), redactSecrets(entry.stderr), "utf-8");
51611
51253
  }
51612
51254
  this.refreshAccounting(entry);
51613
51255
  entry.info.claudeSessionId = entry.reducer.claudeSessionId ?? entry.info.claudeSessionId;
51614
- writeFileSync13(join31(entry.sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
51256
+ writeFileSync12(join30(entry.sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
51615
51257
  }
51616
51258
  scheduleEviction(entry) {
51617
51259
  if (entry.evictHandle)
@@ -51671,7 +51313,7 @@ ${STDERR_TRUNCATION_MARKER} ${STDERR_SIDE_LIMIT} bytes per end \u2026
51671
51313
  return { state: "completed", content: "" };
51672
51314
  }
51673
51315
  refreshAccounting(entry) {
51674
- const stats = readTokenStatsAt(join31(entry.sessionDir, "tokens.json"));
51316
+ const stats = readTokenStatsAt(join30(entry.sessionDir, "tokens.json"));
51675
51317
  const fileTokens = (stats?.total_tokens ?? 0) || (stats?.input_tokens ?? 0) + (stats?.output_tokens ?? 0);
51676
51318
  entry.info.tokensUsed = fileTokens || entry.reducer.tokens;
51677
51319
  entry.info.costUsd = stats?.total_cost ?? 0;
@@ -51862,6 +51504,321 @@ var init_progress_heartbeat = __esm(() => {
51862
51504
  });
51863
51505
  });
51864
51506
 
51507
+ // src/providers/cache-ttl.ts
51508
+ var FIREBASE_CACHE_TTL_HOURS = 24, FIREBASE_CACHE_TTL_MS;
51509
+ var init_cache_ttl = __esm(() => {
51510
+ FIREBASE_CACHE_TTL_MS = FIREBASE_CACHE_TTL_HOURS * 60 * 60 * 1000;
51511
+ });
51512
+
51513
+ // src/model-loader.ts
51514
+ import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
51515
+ import { homedir as homedir29 } from "os";
51516
+ import { join as join31 } from "path";
51517
+ function groupRecommendedModels(entries) {
51518
+ const byId = new Map;
51519
+ const categoryOrder = new Map;
51520
+ for (const entry of entries) {
51521
+ const list = byId.get(entry.id);
51522
+ if (list)
51523
+ list.push(entry);
51524
+ else
51525
+ byId.set(entry.id, [entry]);
51526
+ if (!categoryOrder.has(entry.category))
51527
+ categoryOrder.set(entry.category, categoryOrder.size);
51528
+ }
51529
+ const flagship = [];
51530
+ const fast = [];
51531
+ for (const [id, members] of byId.entries()) {
51532
+ const primary = members.find((m) => m.category !== "subscription") ?? members[0];
51533
+ const subscriptions = members.filter((m) => m.category === "subscription");
51534
+ const bucket = primary.category === "programming" || primary.category === "vision" || primary.category === "reasoning" ? "flagship" : "fast";
51535
+ const group = { id, primary, subscriptions, bucket };
51536
+ if (bucket === "flagship")
51537
+ flagship.push(group);
51538
+ else
51539
+ fast.push(group);
51540
+ }
51541
+ const byCuratedPriorityThenFreshness = (a, b) => {
51542
+ const aCat = categoryOrder.get(a.primary.category) ?? Number.MAX_SAFE_INTEGER;
51543
+ const bCat = categoryOrder.get(b.primary.category) ?? Number.MAX_SAFE_INTEGER;
51544
+ if (aCat !== bCat)
51545
+ return aCat - bCat;
51546
+ if (a.primary.priority !== b.primary.priority)
51547
+ return a.primary.priority - b.primary.priority;
51548
+ return compareByReleaseDateDesc(a.primary, b.primary);
51549
+ };
51550
+ flagship.sort(byCuratedPriorityThenFreshness);
51551
+ fast.sort(byCuratedPriorityThenFreshness);
51552
+ return { flagship, fast };
51553
+ }
51554
+ function collectRoutingPrefixes(group, getNativePrefix) {
51555
+ const slug = (group.primary.provider || "").toLowerCase();
51556
+ const native = getNativePrefix(slug);
51557
+ const seen = new Set;
51558
+ const out = [];
51559
+ if (native) {
51560
+ out.push(native);
51561
+ seen.add(native);
51562
+ }
51563
+ for (const subscriptionRow of group.subscriptions) {
51564
+ const routes = subscriptionRow.subscriptions && subscriptionRow.subscriptions.length > 0 ? subscriptionRow.subscriptions : subscriptionRow.subscription ? [subscriptionRow.subscription] : [];
51565
+ const orderedRoutes = [...routes].sort(compareRecommendedRoutes);
51566
+ for (const route2 of orderedRoutes) {
51567
+ const p = route2?.prefix;
51568
+ if (!p || seen.has(p))
51569
+ continue;
51570
+ seen.add(p);
51571
+ out.push(p);
51572
+ }
51573
+ }
51574
+ return out;
51575
+ }
51576
+ function compareRecommendedRoutes(left, right) {
51577
+ const leftRank = left?.tier && Object.hasOwn(RECOMMENDED_ROUTE_TIER_ORDER, left.tier) ? RECOMMENDED_ROUTE_TIER_ORDER[left.tier] : Number.MAX_SAFE_INTEGER;
51578
+ const rightRank = right?.tier && Object.hasOwn(RECOMMENDED_ROUTE_TIER_ORDER, right.tier) ? RECOMMENDED_ROUTE_TIER_ORDER[right.tier] : Number.MAX_SAFE_INTEGER;
51579
+ return leftRank - rightRank;
51580
+ }
51581
+ function parsePriceAvg(s) {
51582
+ if (!s || s === "N/A")
51583
+ return Number.POSITIVE_INFINITY;
51584
+ if (s === "FREE")
51585
+ return 0;
51586
+ const m = s.match(/\$([\d.]+)/);
51587
+ return m ? Number.parseFloat(m[1]) : Number.POSITIVE_INFINITY;
51588
+ }
51589
+ function parseCtx(s) {
51590
+ if (!s || s === "N/A")
51591
+ return 0;
51592
+ const upper = s.toUpperCase();
51593
+ if (upper.includes("M"))
51594
+ return Number.parseFloat(upper) * 1e6;
51595
+ if (upper.includes("K"))
51596
+ return Number.parseFloat(upper) * 1000;
51597
+ return Number.parseInt(s, 10) || 0;
51598
+ }
51599
+ function normalizePricingDisplay(raw) {
51600
+ const pricing = raw || "N/A";
51601
+ if (pricing.includes("-1000000"))
51602
+ return "varies";
51603
+ if (pricing === "$0.00/1M" || pricing === "FREE")
51604
+ return "FREE";
51605
+ return pricing;
51606
+ }
51607
+ function formatListingPrice(entry, opts) {
51608
+ const rate = normalizePricingDisplay(entry.pricing?.average);
51609
+ if (rate !== "N/A")
51610
+ return rate;
51611
+ const plan = entry.subscription?.plan;
51612
+ if (!plan)
51613
+ return "N/A";
51614
+ return opts?.compact ? "SUB" : `SUB (${plan})`;
51615
+ }
51616
+ function computeQuickPicks(primaries) {
51617
+ if (primaries.length === 0) {
51618
+ return {
51619
+ budget: null,
51620
+ largeContext: null,
51621
+ mostCapable: null,
51622
+ visionCoding: null,
51623
+ agentic: null
51624
+ };
51625
+ }
51626
+ const priced = primaries.filter((m) => {
51627
+ const p = parsePriceAvg(m.pricing?.average);
51628
+ return p > 0 && p !== Number.POSITIVE_INFINITY;
51629
+ }).sort((a, b) => parsePriceAvg(a.pricing?.average) - parsePriceAvg(b.pricing?.average));
51630
+ const budget = priced[0] ?? null;
51631
+ const byCtx = [...primaries].sort((a, b) => parseCtx(b.context) - parseCtx(a.context));
51632
+ const largeContext = byCtx[0] ?? null;
51633
+ const byPrice = [...primaries].sort((a, b) => parsePriceAvg(b.pricing?.average) - parsePriceAvg(a.pricing?.average));
51634
+ const mostCapable = byPrice.find((m) => parsePriceAvg(m.pricing?.average) !== Number.POSITIVE_INFINITY) ?? null;
51635
+ const visionCoding = primaries.find((m) => m.supportsVision === true && m.id !== budget?.id && m.id !== mostCapable?.id) ?? null;
51636
+ const agentic = primaries.find((m) => m.supportsReasoning === true && m.id !== mostCapable?.id) ?? null;
51637
+ return { budget, largeContext, mostCapable, visionCoding, agentic };
51638
+ }
51639
+ async function getRecommendedModels(opts = {}) {
51640
+ const { forceRefresh = false } = opts;
51641
+ if (!forceRefresh && _cachedRecommendedModels) {
51642
+ return _cachedRecommendedModels;
51643
+ }
51644
+ if (!forceRefresh && existsSync21(RECOMMENDED_MODELS_CACHE_PATH)) {
51645
+ try {
51646
+ const cacheData = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
51647
+ if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
51648
+ _cachedRecommendedModels = cacheData;
51649
+ return cacheData;
51650
+ }
51651
+ } catch {}
51652
+ }
51653
+ try {
51654
+ const response = await fetch(FIREBASE_RECOMMENDED_URL, {
51655
+ signal: AbortSignal.timeout(RECOMMENDED_FETCH_TIMEOUT_MS)
51656
+ });
51657
+ if (response.ok) {
51658
+ const data = await response.json();
51659
+ if (data.models && data.models.length > 0) {
51660
+ _cachedRecommendedModels = data;
51661
+ try {
51662
+ const cacheDir = join31(homedir29(), ".claudish");
51663
+ mkdirSync13(cacheDir, { recursive: true });
51664
+ writeFileSync13(RECOMMENDED_MODELS_CACHE_PATH, JSON.stringify(data), "utf-8");
51665
+ } catch {}
51666
+ return data;
51667
+ }
51668
+ }
51669
+ } catch {}
51670
+ throw new Error("Unable to load recommended models: Firebase unreachable and no local cache. " + "Check connectivity.");
51671
+ }
51672
+ function getRecommendedModelsSync() {
51673
+ if (_cachedRecommendedModels)
51674
+ return _cachedRecommendedModels;
51675
+ if (existsSync21(RECOMMENDED_MODELS_CACHE_PATH)) {
51676
+ try {
51677
+ const cacheData = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
51678
+ if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
51679
+ _cachedRecommendedModels = cacheData;
51680
+ return cacheData;
51681
+ }
51682
+ } catch {}
51683
+ }
51684
+ return { version: "0", lastUpdated: "", models: [] };
51685
+ }
51686
+ async function warmRecommendedModels() {
51687
+ try {
51688
+ return await getRecommendedModels({ forceRefresh: true });
51689
+ } catch {
51690
+ return null;
51691
+ }
51692
+ }
51693
+ function isFreshEnough(doc2) {
51694
+ const generatedAt = doc2.generatedAt;
51695
+ if (!generatedAt)
51696
+ return true;
51697
+ const ageHours = (Date.now() - new Date(generatedAt).getTime()) / (1000 * 60 * 60);
51698
+ return ageHours <= FIREBASE_CACHE_TTL_HOURS;
51699
+ }
51700
+ async function searchModels(query, limit = 50) {
51701
+ const url2 = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(query)}&limit=${limit}&status=active`;
51702
+ const response = await fetch(url2, {
51703
+ signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
51704
+ });
51705
+ if (!response.ok) {
51706
+ throw new Error(`Firebase search returned ${response.status} ${response.statusText}`);
51707
+ }
51708
+ const data = await response.json();
51709
+ return data.models ?? [];
51710
+ }
51711
+ async function getModelByIdFromFirebase(modelId) {
51712
+ const url2 = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(modelId)}&limit=5`;
51713
+ const response = await fetch(url2, {
51714
+ signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
51715
+ });
51716
+ if (!response.ok) {
51717
+ throw new Error(`Firebase lookup returned ${response.status} ${response.statusText}`);
51718
+ }
51719
+ const data = await response.json();
51720
+ const models = data.models ?? [];
51721
+ for (const m of models) {
51722
+ if (m.modelId === modelId)
51723
+ return m;
51724
+ if (m.aliases?.includes(modelId))
51725
+ return m;
51726
+ }
51727
+ return null;
51728
+ }
51729
+ async function getTop100Models() {
51730
+ const url2 = `${FIREBASE_BASE_URL}?catalog=top100`;
51731
+ const response = await fetch(url2, {
51732
+ signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
51733
+ });
51734
+ if (!response.ok) {
51735
+ throw new Error(`Firebase top100 fetch failed: ${response.status} ${response.statusText}`);
51736
+ }
51737
+ const data = await response.json();
51738
+ return data;
51739
+ }
51740
+ async function getProviderList() {
51741
+ const url2 = `${FIREBASE_BASE_URL}?catalog=providers`;
51742
+ const response = await fetch(url2, {
51743
+ signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
51744
+ });
51745
+ if (!response.ok) {
51746
+ throw new Error(`Firebase providers fetch failed: ${response.status} ${response.statusText}`);
51747
+ }
51748
+ const data = await response.json();
51749
+ return data.providers ?? [];
51750
+ }
51751
+ async function getModelsByProvider(provider, limit = 200) {
51752
+ const url2 = `${FIREBASE_BASE_URL}?provider=${encodeURIComponent(provider)}&status=active&limit=${limit}`;
51753
+ const response = await fetch(url2, {
51754
+ signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
51755
+ });
51756
+ if (!response.ok) {
51757
+ throw new Error(`Firebase provider query returned ${response.status} ${response.statusText}`);
51758
+ }
51759
+ const data = await response.json();
51760
+ if (Array.isArray(data))
51761
+ return data;
51762
+ return data.models ?? [];
51763
+ }
51764
+ function loadModelInfo() {
51765
+ if (_cachedModelInfo) {
51766
+ return _cachedModelInfo;
51767
+ }
51768
+ const data = getRecommendedModelsSync();
51769
+ const modelInfo = {};
51770
+ for (const model of data.models) {
51771
+ modelInfo[model.id] = {
51772
+ name: model.name,
51773
+ description: model.description,
51774
+ priority: model.priority,
51775
+ provider: model.provider
51776
+ };
51777
+ }
51778
+ modelInfo.custom = {
51779
+ name: "Custom Model",
51780
+ description: "Enter any model ID manually",
51781
+ priority: 999,
51782
+ provider: "Custom"
51783
+ };
51784
+ _cachedModelInfo = modelInfo;
51785
+ return modelInfo;
51786
+ }
51787
+ function getAvailableModels() {
51788
+ if (_cachedModelIds) {
51789
+ return _cachedModelIds;
51790
+ }
51791
+ const data = getRecommendedModelsSync();
51792
+ const modelIds = data.models.sort((a, b) => a.priority - b.priority).map((m) => m.id);
51793
+ const result = [...modelIds, "custom"];
51794
+ _cachedModelIds = result;
51795
+ return result;
51796
+ }
51797
+ var _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels = null, FIREBASE_BASE_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/queryModels", FIREBASE_RECOMMENDED_URL, RECOMMENDED_MODELS_CACHE_PATH, RECOMMENDED_FETCH_TIMEOUT_MS = 5000, SEARCH_FETCH_TIMEOUT_MS = 1e4, FIREBASE_SLUG_TO_PROVIDER_NAME, RECOMMENDED_ROUTE_TIER_ORDER;
51798
+ var init_model_loader = __esm(() => {
51799
+ init_cache_ttl();
51800
+ FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
51801
+ RECOMMENDED_MODELS_CACHE_PATH = join31(homedir29(), ".claudish", "recommended-models-cache.json");
51802
+ FIREBASE_SLUG_TO_PROVIDER_NAME = {
51803
+ openai: "openai",
51804
+ google: "google",
51805
+ "x-ai": "x-ai",
51806
+ "z-ai": "z-ai",
51807
+ moonshotai: "kimi",
51808
+ minimax: "minimax",
51809
+ qwen: "qwen",
51810
+ deepseek: "deepseek",
51811
+ mistralai: "mistralai",
51812
+ sakana: "sakana"
51813
+ };
51814
+ RECOMMENDED_ROUTE_TIER_ORDER = {
51815
+ native: 0,
51816
+ general: 1,
51817
+ metered: 2,
51818
+ aggregator: 3
51819
+ };
51820
+ });
51821
+
51865
51822
  // src/port-manager.ts
51866
51823
  var exports_port_manager = {};
51867
51824
  __export(exports_port_manager, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "9.0.2",
3
+ "version": "9.0.3",
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": "9.0.2",
64
- "@claudish/magmux-darwin-x64": "9.0.2",
65
- "@claudish/magmux-linux-arm64": "9.0.2",
66
- "@claudish/magmux-linux-x64": "9.0.2"
63
+ "@claudish/magmux-darwin-arm64": "9.0.3",
64
+ "@claudish/magmux-darwin-x64": "9.0.3",
65
+ "@claudish/magmux-linux-arm64": "9.0.3",
66
+ "@claudish/magmux-linux-x64": "9.0.3"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",