claudish 9.0.2 → 9.0.4

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 +401 -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.4";
735
735
 
736
736
  // src/logger.ts
737
737
  var exports_logger = {};
@@ -27655,6 +27655,10 @@ function resolveSubscriptionRouting(modelId, provider, cachePath) {
27655
27655
  const hasPublishedProviderRoster = cache.entries.some((candidate) => candidate.subscriptionPlans?.some((planId) => providerPlanIds.has(planId)));
27656
27656
  if (!hasPublishedProviderRoster)
27657
27657
  return { kind: "unknown" };
27658
+ const vendorsInView = new Set(providerPlans.map((plan) => plan.provider).filter((v) => v !== undefined));
27659
+ const hasUnroutableSiblingPlan = (cache.plans ?? []).some((plan) => plan.provider !== undefined && vendorsInView.has(plan.provider) && plan.routing?.providerUid === undefined);
27660
+ if (hasUnroutableSiblingPlan)
27661
+ return { kind: "unknown" };
27658
27662
  return providerPlans.every(isCatalogDiscoveredPlan) ? { kind: "not-served" } : { kind: "unknown" };
27659
27663
  }
27660
27664
  function isCatalogDiscoveredPlan(plan) {
@@ -47685,349 +47689,6 @@ var init_routing_hints = __esm(() => {
47685
47689
  };
47686
47690
  });
47687
47691
 
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
47692
  // src/providers/default-routing-rules.ts
48032
47693
  function validateRoutingRulesAgainstProviders(rules) {
48033
47694
  const unknown3 = [];
@@ -48119,26 +47780,12 @@ var init_model_availability = __esm(() => {
48119
47780
  function mergeRoutingRules(defaults, global_, local) {
48120
47781
  return { ...defaults, ...global_, ...local };
48121
47782
  }
48122
- function loadRoutingRules() {
48123
- const local = loadLocalConfig()?.routing ?? {};
48124
- const global_ = loadConfig().routing ?? {};
47783
+ function loadRoutingRules(sources) {
47784
+ const local = sources ? sources.localRules : loadLocalConfig()?.routing ?? {};
47785
+ const global_ = sources ? sources.globalRules : loadConfig().routing ?? {};
48125
47786
  validateRoutingRules(local);
48126
47787
  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;
47788
+ return mergeRoutingRules(DEFAULT_ROUTING_RULES, global_, local);
48142
47789
  }
48143
47790
  function validateRoutingRules(rules) {
48144
47791
  const seenLower = new Map;
@@ -48333,7 +47980,6 @@ var init_routing_rules = __esm(() => {
48333
47980
  init_authority();
48334
47981
  init_remote_provider_types();
48335
47982
  init_logger();
48336
- init_model_loader();
48337
47983
  init_profile_config();
48338
47984
  init_auto_route();
48339
47985
  init_catalog_client();
@@ -49477,8 +49123,8 @@ __export(exports_session_discovery, {
49477
49123
  });
49478
49124
  import { execFile, execFileSync as execFileSync2 } from "child_process";
49479
49125
  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";
49126
+ import { homedir as homedir27 } from "os";
49127
+ import { basename, join as join27 } from "path";
49482
49128
  function slugForPath(absPath) {
49483
49129
  return absPath.replace(/[/.]/g, "-");
49484
49130
  }
@@ -49487,7 +49133,7 @@ function transcriptPathFor(cwd, sessionUuid) {
49487
49133
  try {
49488
49134
  real = realpathSync(cwd);
49489
49135
  } catch {}
49490
- return join28(PROJECTS_DIR, slugForPath(real), `${sessionUuid}.jsonl`);
49136
+ return join27(PROJECTS_DIR, slugForPath(real), `${sessionUuid}.jsonl`);
49491
49137
  }
49492
49138
  function isAgentSession(row) {
49493
49139
  return row.entrypoint !== undefined && row.entrypoint !== "cli";
@@ -49534,7 +49180,7 @@ function projectDirs() {
49534
49180
  }
49535
49181
  }
49536
49182
  function sessionsIn(dirName) {
49537
- const dir = join28(PROJECTS_DIR, dirName);
49183
+ const dir = join27(PROJECTS_DIR, dirName);
49538
49184
  let names;
49539
49185
  try {
49540
49186
  names = readdirSync4(dir).filter((n) => n.endsWith(".jsonl"));
@@ -49543,7 +49189,7 @@ function sessionsIn(dirName) {
49543
49189
  }
49544
49190
  const rows = [];
49545
49191
  for (const n of names) {
49546
- const file2 = join28(dir, n);
49192
+ const file2 = join27(dir, n);
49547
49193
  try {
49548
49194
  const st = statSync5(file2);
49549
49195
  if (st.size === 0)
@@ -49902,7 +49548,7 @@ function findLatestSessionId(cwd = process.cwd(), sinceMs = 0) {
49902
49548
  }
49903
49549
  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
49550
  var init_session_discovery = __esm(() => {
49905
- PROJECTS_DIR = join28(homedir28(), ".claude", "projects");
49551
+ PROJECTS_DIR = join27(homedir27(), ".claude", "projects");
49906
49552
  HEAD_BYTES = 64 * 1024;
49907
49553
  TAIL_BYTES = 128 * 1024;
49908
49554
  HARNESS_ENVELOPES = [
@@ -49937,19 +49583,19 @@ function newStdioDecoder() {
49937
49583
  var init_stdio_decode = () => {};
49938
49584
 
49939
49585
  // src/team-stats.ts
49940
- import { existsSync as existsSync20, readFileSync as readFileSync19, writeFileSync as writeFileSync11 } from "fs";
49941
- import { join as join29 } from "path";
49586
+ import { existsSync as existsSync19, readFileSync as readFileSync18, writeFileSync as writeFileSync10 } from "fs";
49587
+ import { join as join28 } from "path";
49942
49588
  function statsDir(sessionPath) {
49943
- return join29(sessionPath, "stats");
49589
+ return join28(sessionPath, "stats");
49944
49590
  }
49945
49591
  function tokenFileFor(sessionPath, anonId) {
49946
- return join29(statsDir(sessionPath), `${anonId}.json`);
49592
+ return join28(statsDir(sessionPath), `${anonId}.json`);
49947
49593
  }
49948
49594
  function readTokenStatsAt(path) {
49949
- if (!existsSync20(path))
49595
+ if (!existsSync19(path))
49950
49596
  return null;
49951
49597
  try {
49952
- return JSON.parse(readFileSync19(path, "utf-8"));
49598
+ return JSON.parse(readFileSync18(path, "utf-8"));
49953
49599
  } catch {
49954
49600
  return null;
49955
49601
  }
@@ -50100,7 +49746,7 @@ ${segs.join(" \xB7 ")}`;
50100
49746
  }
50101
49747
  function writeStatusFile(sessionPath, manifest, status, opts) {
50102
49748
  try {
50103
- writeFileSync11(join29(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
49749
+ writeFileSync10(join28(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
50104
49750
  `, "utf-8");
50105
49751
  } catch {}
50106
49752
  }
@@ -50135,13 +49781,13 @@ __export(exports_team_orchestrator, {
50135
49781
  import { spawn as spawn2 } from "child_process";
50136
49782
  import {
50137
49783
  createWriteStream,
50138
- existsSync as existsSync21,
50139
- mkdirSync as mkdirSync12,
50140
- readFileSync as readFileSync20,
49784
+ existsSync as existsSync20,
49785
+ mkdirSync as mkdirSync11,
49786
+ readFileSync as readFileSync19,
50141
49787
  readdirSync as readdirSync5,
50142
- writeFileSync as writeFileSync12
49788
+ writeFileSync as writeFileSync11
50143
49789
  } from "fs";
50144
- import { basename as basename2, join as join30, resolve as resolve3 } from "path";
49790
+ import { basename as basename2, join as join29, resolve as resolve3 } from "path";
50145
49791
  function resolveCaptureMode(explicit, env = process.env) {
50146
49792
  if (explicit)
50147
49793
  return explicit;
@@ -50259,7 +49905,7 @@ function persistErrorLog(errorLogPath, header, stderr, stdoutTail) {
50259
49905
  parts.push("--- stderr ---", stderr.trim() ? redactSecrets(stderr) : "(empty)", "");
50260
49906
  parts.push("--- stdout (tail) ---", stdoutTail.trim() ? redactSecrets(stdoutTail) : "(empty)", "");
50261
49907
  try {
50262
- writeFileSync12(errorLogPath, parts.join(`
49908
+ writeFileSync11(errorLogPath, parts.join(`
50263
49909
  `), "utf-8");
50264
49910
  } catch {}
50265
49911
  }
@@ -50277,10 +49923,10 @@ function readTeamInputFile(inputPath) {
50277
49923
  if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
50278
49924
  throw new Error(`Input file must be within current directory: ${inputPath}`);
50279
49925
  }
50280
- if (!existsSync21(resolved)) {
49926
+ if (!existsSync20(resolved)) {
50281
49927
  throw new Error(`Input file not found: ${resolved}`);
50282
49928
  }
50283
- const text = readFileSync20(resolved, "utf-8");
49929
+ const text = readFileSync19(resolved, "utf-8");
50284
49930
  if (text.trim().length === 0) {
50285
49931
  throw new Error(`Input file is empty: ${resolved}`);
50286
49932
  }
@@ -50290,14 +49936,14 @@ function setupSession(sessionPath, models, input) {
50290
49936
  if (models.length === 0) {
50291
49937
  throw new Error("At least one model is required");
50292
49938
  }
50293
- if (existsSync21(join30(sessionPath, "manifest.json"))) {
49939
+ if (existsSync20(join29(sessionPath, "manifest.json"))) {
50294
49940
  throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
50295
49941
  }
50296
- mkdirSync12(join30(sessionPath, "work"), { recursive: true });
50297
- mkdirSync12(join30(sessionPath, "errors"), { recursive: true });
49942
+ mkdirSync11(join29(sessionPath, "work"), { recursive: true });
49943
+ mkdirSync11(join29(sessionPath, "errors"), { recursive: true });
50298
49944
  if (input !== undefined) {
50299
- writeFileSync12(join30(sessionPath, "input.md"), input, "utf-8");
50300
- } else if (!existsSync21(join30(sessionPath, "input.md"))) {
49945
+ writeFileSync11(join29(sessionPath, "input.md"), input, "utf-8");
49946
+ } else if (!existsSync20(join29(sessionPath, "input.md"))) {
50301
49947
  throw new Error(`No input.md found at ${sessionPath} and no input provided`);
50302
49948
  }
50303
49949
  const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
@@ -50314,9 +49960,9 @@ function setupSession(sessionPath, models, input) {
50314
49960
  model: models[i],
50315
49961
  assignedAt: now2
50316
49962
  };
50317
- mkdirSync12(join30(sessionPath, "work", anonId), { recursive: true });
49963
+ mkdirSync11(join29(sessionPath, "work", anonId), { recursive: true });
50318
49964
  }
50319
- writeFileSync12(join30(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
49965
+ writeFileSync11(join29(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
50320
49966
  const status = {
50321
49967
  startedAt: now2,
50322
49968
  models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
@@ -50330,7 +49976,7 @@ function setupSession(sessionPath, models, input) {
50330
49976
  }
50331
49977
  ]))
50332
49978
  };
50333
- writeFileSync12(join30(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
49979
+ writeFileSync11(join29(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
50334
49980
  return manifest;
50335
49981
  }
50336
49982
  function assertValidRequirePattern(pattern) {
@@ -50347,22 +49993,22 @@ function readFullOutputIfNeeded(opts) {
50347
49993
  if (crashed || !requirePattern || outputSize <= STDOUT_TAIL_LIMIT)
50348
49994
  return;
50349
49995
  try {
50350
- return readFileSync20(outputPath, "utf-8");
49996
+ return readFileSync19(outputPath, "utf-8");
50351
49997
  } catch {
50352
49998
  return;
50353
49999
  }
50354
50000
  }
50355
50001
  async function startModels(sessionPath, opts = {}) {
50356
50002
  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");
50003
+ const manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
50004
+ const statusPath = join29(sessionPath, "status.json");
50005
+ const inputPath = join29(sessionPath, "input.md");
50006
+ const inputContent = readFileSync19(inputPath, "utf-8");
50361
50007
  const spawnPlan = await (opts.spawnPlanner ?? prehydrateCredentialsForSpawn)(Object.values(manifest.models).map((m) => m.model));
50362
- const statusCache = JSON.parse(readFileSync20(statusPath, "utf-8"));
50008
+ const statusCache = JSON.parse(readFileSync19(statusPath, "utf-8"));
50363
50009
  function updateModelStatus(id, update) {
50364
50010
  statusCache.models[id] = { ...statusCache.models[id], ...update };
50365
- writeFileSync12(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
50011
+ writeFileSync11(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
50366
50012
  }
50367
50013
  const minOutputBytes = opts.minOutputBytes ?? DEFAULT_MIN_OUTPUT_BYTES;
50368
50014
  const requirePattern = opts.requirePattern;
@@ -50395,7 +50041,7 @@ async function startModels(sessionPath, opts = {}) {
50395
50041
  persistErrorLog(rt.errorLogPath, `RECOVERED: ${note}`, stderr, stdoutTail);
50396
50042
  opts.onStatusChange?.(id, statusCache.models[id]);
50397
50043
  }
50398
- mkdirSync12(statsDir(sessionPath), { recursive: true });
50044
+ mkdirSync11(statsDir(sessionPath), { recursive: true });
50399
50045
  const processes = new Map;
50400
50046
  const runtimes = new Map;
50401
50047
  const cancelledSlots = new Set;
@@ -50408,9 +50054,9 @@ async function startModels(sessionPath, opts = {}) {
50408
50054
  process.on("SIGINT", sigintHandler);
50409
50055
  const completionPromises = [];
50410
50056
  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`);
50057
+ const outputPath = join29(sessionPath, `response-${anonId}.md`);
50058
+ const errorLogPath = join29(sessionPath, "errors", `${anonId}.log`);
50059
+ const upstreamErrorLogPath = join29(sessionPath, "errors", `${anonId}-upstream.jsonl`);
50414
50060
  const spawnModel = spawnPlan.pinned.get(entry.model) ?? entry.model;
50415
50061
  const args = [
50416
50062
  "--model",
@@ -50550,7 +50196,7 @@ async function startModels(sessionPath, opts = {}) {
50550
50196
  stderrSnippet: stderr ? redactSecrets(stderr).slice(-2000) : undefined,
50551
50197
  stdoutSnippet: stdoutTail ? redactSecrets(stdoutTail).slice(-2000) : undefined,
50552
50198
  errorLogPath,
50553
- upstreamErrorLogPath: existsSync21(upstreamErrorLogPath) ? upstreamErrorLogPath : undefined,
50199
+ upstreamErrorLogPath: existsSync20(upstreamErrorLogPath) ? upstreamErrorLogPath : undefined,
50554
50200
  workDir: sessionPath
50555
50201
  }
50556
50202
  });
@@ -50570,7 +50216,7 @@ async function startModels(sessionPath, opts = {}) {
50570
50216
  proc.on("exit", (code) => {
50571
50217
  const timedOut = statusCache.models[anonId]?.state === "TIMEOUT";
50572
50218
  if (!timedOut && meaningfulStderr(stderr)) {
50573
- writeFileSync12(errorLogPath, redactSecrets(stderr), "utf-8");
50219
+ writeFileSync11(errorLogPath, redactSecrets(stderr), "utf-8");
50574
50220
  }
50575
50221
  exitCode = code;
50576
50222
  if (outputStream.destroyed) {
@@ -50650,23 +50296,23 @@ async function judgeResponses(sessionPath, opts = {}) {
50650
50296
  const responses = {};
50651
50297
  for (const file2 of responseFiles) {
50652
50298
  const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
50653
- responses[id] = readFileSync20(join30(sessionPath, file2), "utf-8");
50299
+ responses[id] = readFileSync19(join29(sessionPath, file2), "utf-8");
50654
50300
  }
50655
- const input = readFileSync20(join30(sessionPath, "input.md"), "utf-8");
50301
+ const input = readFileSync19(join29(sessionPath, "input.md"), "utf-8");
50656
50302
  const judgePrompt = buildJudgePrompt(input, responses);
50657
- writeFileSync12(join30(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
50303
+ writeFileSync11(join29(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
50658
50304
  const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
50659
- const judgePath = join30(sessionPath, "judging");
50660
- mkdirSync12(judgePath, { recursive: true });
50305
+ const judgePath = join29(sessionPath, "judging");
50306
+ mkdirSync11(judgePath, { recursive: true });
50661
50307
  setupSession(judgePath, judgeModels, judgePrompt);
50662
50308
  await runModels(judgePath, { claudeFlags: opts.claudeFlags });
50663
50309
  const votes = parseJudgeVotes(judgePath, Object.keys(responses));
50664
50310
  const verdict = aggregateVerdict(votes, Object.keys(responses));
50665
- writeFileSync12(join30(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
50311
+ writeFileSync11(join29(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
50666
50312
  return verdict;
50667
50313
  }
50668
50314
  function getStatus(sessionPath) {
50669
- return JSON.parse(readFileSync20(join30(sessionPath, "status.json"), "utf-8"));
50315
+ return JSON.parse(readFileSync19(join29(sessionPath, "status.json"), "utf-8"));
50670
50316
  }
50671
50317
  function fisherYatesShuffle(arr) {
50672
50318
  for (let i = arr.length - 1;i > 0; i--) {
@@ -50676,7 +50322,7 @@ function fisherYatesShuffle(arr) {
50676
50322
  return arr;
50677
50323
  }
50678
50324
  function getDefaultJudgeModels(sessionPath) {
50679
- const manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
50325
+ const manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
50680
50326
  return Object.values(manifest.models).map((e) => e.model);
50681
50327
  }
50682
50328
  function buildJudgePrompt(input, responses) {
@@ -50739,7 +50385,7 @@ function parseJudgeVotes(judgePath, responseIds) {
50739
50385
  const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
50740
50386
  let content;
50741
50387
  try {
50742
- content = readFileSync20(join30(judgePath, file2), "utf-8");
50388
+ content = readFileSync19(join29(judgePath, file2), "utf-8");
50743
50389
  } catch {
50744
50390
  continue;
50745
50391
  }
@@ -50791,7 +50437,7 @@ function aggregateVerdict(votes, responseIds) {
50791
50437
  function formatVerdict(verdict, sessionPath) {
50792
50438
  let manifest = null;
50793
50439
  try {
50794
- manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
50440
+ manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
50795
50441
  } catch {}
50796
50442
  let output = `# Team Verdict
50797
50443
 
@@ -50845,15 +50491,15 @@ import {
50845
50491
  appendFileSync as appendFileSync6,
50846
50492
  closeSync as closeSync7,
50847
50493
  createWriteStream as createWriteStream2,
50848
- mkdirSync as mkdirSync13,
50494
+ mkdirSync as mkdirSync12,
50849
50495
  openSync as openSync7,
50850
- readFileSync as readFileSync21,
50496
+ readFileSync as readFileSync20,
50851
50497
  readSync as readSync3,
50852
50498
  statSync as statSync6,
50853
- writeFileSync as writeFileSync13
50499
+ writeFileSync as writeFileSync12
50854
50500
  } from "fs";
50855
- import { homedir as homedir29 } from "os";
50856
- import { join as join31, resolve as resolve4, sep } from "path";
50501
+ import { homedir as homedir28 } from "os";
50502
+ import { join as join30, resolve as resolve4, sep } from "path";
50857
50503
  import { StringDecoder as StringDecoder2 } from "string_decoder";
50858
50504
  function buildChannelSpawnArgs(opts) {
50859
50505
  return [
@@ -50928,7 +50574,7 @@ function readJsonObject(path, maxBytes) {
50928
50574
  try {
50929
50575
  if (fileSize(path) > maxBytes)
50930
50576
  return null;
50931
- const parsed = JSON.parse(readFileSync21(path, "utf-8"));
50577
+ const parsed = JSON.parse(readFileSync20(path, "utf-8"));
50932
50578
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
50933
50579
  return null;
50934
50580
  return parsed;
@@ -50944,7 +50590,7 @@ function dropLeadingFragment(tail) {
50944
50590
  return firstBreak === -1 ? tail.text : tail.text.slice(firstBreak + 1);
50945
50591
  }
50946
50592
  function diskAccounting(sessionDir) {
50947
- const stats = readTokenStatsAt(join31(sessionDir, "tokens.json"));
50593
+ const stats = readTokenStatsAt(join30(sessionDir, "tokens.json"));
50948
50594
  return {
50949
50595
  tokensUsed: (stats?.total_tokens ?? 0) || (stats?.input_tokens ?? 0) + (stats?.output_tokens ?? 0),
50950
50596
  costUsd: stats?.total_cost ?? 0,
@@ -50984,7 +50630,7 @@ class SessionManager {
50984
50630
  this.maxSessions = options?.maxSessions ?? DEFAULT_MAX_SESSIONS;
50985
50631
  this.scrollbackCapacity = options?.scrollbackCapacity ?? DEFAULT_SCROLLBACK;
50986
50632
  this.terminalRetentionMs = options?.terminalRetentionMs ?? TERMINAL_RETENTION_MS;
50987
- this.sessionsDir = options?.sessionsDir ?? process.env.CLAUDISH_SESSIONS_DIR ?? join31(homedir29(), ".claudish", "sessions");
50633
+ this.sessionsDir = options?.sessionsDir ?? process.env.CLAUDISH_SESSIONS_DIR ?? join30(homedir28(), ".claudish", "sessions");
50988
50634
  this.stallSeconds = options?.stallSeconds;
50989
50635
  this.onStateChange = options?.onStateChange;
50990
50636
  }
@@ -51000,19 +50646,19 @@ class SessionManager {
51000
50646
  const claudeSessionId = randomUUID4();
51001
50647
  const timeout = Math.min(opts.timeoutSeconds ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
51002
50648
  const startedAt = new Date().toISOString();
51003
- const sessionDir = opts.sessionDir ?? join31(this.sessionsDir, sessionId2);
51004
- mkdirSync13(sessionDir, { recursive: true });
50649
+ const sessionDir = opts.sessionDir ?? join30(this.sessionsDir, sessionId2);
50650
+ mkdirSync12(sessionDir, { recursive: true });
51005
50651
  if (opts.prompt) {
51006
- writeFileSync13(join31(sessionDir, "prompt.md"), opts.prompt, "utf-8");
50652
+ writeFileSync12(join30(sessionDir, "prompt.md"), opts.prompt, "utf-8");
51007
50653
  }
51008
50654
  const args = buildChannelSpawnArgs({
51009
50655
  model: opts.spawnModel ?? opts.model,
51010
50656
  claudeSessionId,
51011
50657
  claudishFlags: opts.claudishFlags
51012
50658
  });
51013
- const tokenFile = opts.tokenFile ?? join31(sessionDir, "tokens.json");
51014
- const eventLogPath = join31(sessionDir, "events.jsonl");
51015
- const upstreamErrorLogPath = join31(sessionDir, "upstream-errors.jsonl");
50659
+ const tokenFile = opts.tokenFile ?? join30(sessionDir, "tokens.json");
50660
+ const eventLogPath = join30(sessionDir, "events.jsonl");
50661
+ const upstreamErrorLogPath = join30(sessionDir, "upstream-errors.jsonl");
51016
50662
  const cwd = opts.cwd ?? process.cwd();
51017
50663
  const spawnTarget = resolveClaudishSpawn();
51018
50664
  const proc = spawn3(spawnTarget.command, [...spawnTarget.prefixArgs, ...args], {
@@ -51027,7 +50673,7 @@ class SessionManager {
51027
50673
  }
51028
50674
  });
51029
50675
  const scrollback = new ScrollbackBuffer(this.scrollbackCapacity);
51030
- const outputLogStream = createWriteStream2(join31(sessionDir, "output.log"));
50676
+ const outputLogStream = createWriteStream2(join30(sessionDir, "output.log"));
51031
50677
  const entry = {
51032
50678
  info: {
51033
50679
  sessionId: sessionId2,
@@ -51319,7 +50965,7 @@ class SessionManager {
51319
50965
  return null;
51320
50966
  const root = resolve4(this.sessionsDir);
51321
50967
  const dir = resolve4(root, sessionId2);
51322
- if (dir !== join31(root, sessionId2))
50968
+ if (dir !== join30(root, sessionId2))
51323
50969
  return null;
51324
50970
  if (!dir.startsWith(root + sep))
51325
50971
  return null;
@@ -51338,7 +50984,7 @@ class SessionManager {
51338
50984
  } catch {
51339
50985
  return null;
51340
50986
  }
51341
- const meta3 = readJsonObject(join31(sessionDir, "meta.json"), META_READ_LIMIT);
50987
+ const meta3 = readJsonObject(join30(sessionDir, "meta.json"), META_READ_LIMIT);
51342
50988
  const partial2 = meta3 === null;
51343
50989
  const measured = diskAccounting(sessionDir);
51344
50990
  const startedAt = metaString(meta3?.startedAt) ?? new Date(dirMtimeMs).toISOString();
@@ -51368,7 +51014,7 @@ class SessionManager {
51368
51014
  };
51369
51015
  }
51370
51016
  diskOutput(record4, tailLines) {
51371
- const tail = readTailText(join31(record4.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
51017
+ const tail = readTailText(join30(record4.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
51372
51018
  const buffer = new ScrollbackBuffer(this.scrollbackCapacity);
51373
51019
  if (tail?.text)
51374
51020
  buffer.append(dropLeadingFragment(tail));
@@ -51387,9 +51033,9 @@ class SessionManager {
51387
51033
  }
51388
51034
  diskDiagnostics(record4, limit) {
51389
51035
  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");
51036
+ const eventLogPath = join30(sessionDir, "events.jsonl");
51037
+ const upstreamErrorLogPath = join30(sessionDir, "upstream-errors.jsonl");
51038
+ const outputLogPath = join30(sessionDir, "output.log");
51393
51039
  const events = readTailLines(eventLogPath, EVENT_TAIL_BYTES);
51394
51040
  const outputTail = readTailText(outputLogPath, OUTPUT_TAIL_BYTES);
51395
51041
  return {
@@ -51431,7 +51077,7 @@ class SessionManager {
51431
51077
  };
51432
51078
  }
51433
51079
  diskStderrForDiagnostics(record4) {
51434
- const tail = readTailText(join31(record4.sessionDir, "stderr.log"), STDERR_READ_BYTES);
51080
+ const tail = readTailText(join30(record4.sessionDir, "stderr.log"), STDERR_READ_BYTES);
51435
51081
  const raw = tail?.text ?? "";
51436
51082
  const filtered = record4.info.status === "completed";
51437
51083
  const source = filtered ? meaningfulStderr(raw) : raw;
@@ -51607,11 +51253,11 @@ ${STDERR_TRUNCATION_MARKER} ${STDERR_SIDE_LIMIT} bytes per end \u2026
51607
51253
  entry.outputLogStream?.end();
51608
51254
  entry.outputLogStream = null;
51609
51255
  if (entry.stderr) {
51610
- writeFileSync13(join31(entry.sessionDir, "stderr.log"), redactSecrets(entry.stderr), "utf-8");
51256
+ writeFileSync12(join30(entry.sessionDir, "stderr.log"), redactSecrets(entry.stderr), "utf-8");
51611
51257
  }
51612
51258
  this.refreshAccounting(entry);
51613
51259
  entry.info.claudeSessionId = entry.reducer.claudeSessionId ?? entry.info.claudeSessionId;
51614
- writeFileSync13(join31(entry.sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
51260
+ writeFileSync12(join30(entry.sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
51615
51261
  }
51616
51262
  scheduleEviction(entry) {
51617
51263
  if (entry.evictHandle)
@@ -51671,7 +51317,7 @@ ${STDERR_TRUNCATION_MARKER} ${STDERR_SIDE_LIMIT} bytes per end \u2026
51671
51317
  return { state: "completed", content: "" };
51672
51318
  }
51673
51319
  refreshAccounting(entry) {
51674
- const stats = readTokenStatsAt(join31(entry.sessionDir, "tokens.json"));
51320
+ const stats = readTokenStatsAt(join30(entry.sessionDir, "tokens.json"));
51675
51321
  const fileTokens = (stats?.total_tokens ?? 0) || (stats?.input_tokens ?? 0) + (stats?.output_tokens ?? 0);
51676
51322
  entry.info.tokensUsed = fileTokens || entry.reducer.tokens;
51677
51323
  entry.info.costUsd = stats?.total_cost ?? 0;
@@ -51862,6 +51508,321 @@ var init_progress_heartbeat = __esm(() => {
51862
51508
  });
51863
51509
  });
51864
51510
 
51511
+ // src/providers/cache-ttl.ts
51512
+ var FIREBASE_CACHE_TTL_HOURS = 24, FIREBASE_CACHE_TTL_MS;
51513
+ var init_cache_ttl = __esm(() => {
51514
+ FIREBASE_CACHE_TTL_MS = FIREBASE_CACHE_TTL_HOURS * 60 * 60 * 1000;
51515
+ });
51516
+
51517
+ // src/model-loader.ts
51518
+ import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
51519
+ import { homedir as homedir29 } from "os";
51520
+ import { join as join31 } from "path";
51521
+ function groupRecommendedModels(entries) {
51522
+ const byId = new Map;
51523
+ const categoryOrder = new Map;
51524
+ for (const entry of entries) {
51525
+ const list = byId.get(entry.id);
51526
+ if (list)
51527
+ list.push(entry);
51528
+ else
51529
+ byId.set(entry.id, [entry]);
51530
+ if (!categoryOrder.has(entry.category))
51531
+ categoryOrder.set(entry.category, categoryOrder.size);
51532
+ }
51533
+ const flagship = [];
51534
+ const fast = [];
51535
+ for (const [id, members] of byId.entries()) {
51536
+ const primary = members.find((m) => m.category !== "subscription") ?? members[0];
51537
+ const subscriptions = members.filter((m) => m.category === "subscription");
51538
+ const bucket = primary.category === "programming" || primary.category === "vision" || primary.category === "reasoning" ? "flagship" : "fast";
51539
+ const group = { id, primary, subscriptions, bucket };
51540
+ if (bucket === "flagship")
51541
+ flagship.push(group);
51542
+ else
51543
+ fast.push(group);
51544
+ }
51545
+ const byCuratedPriorityThenFreshness = (a, b) => {
51546
+ const aCat = categoryOrder.get(a.primary.category) ?? Number.MAX_SAFE_INTEGER;
51547
+ const bCat = categoryOrder.get(b.primary.category) ?? Number.MAX_SAFE_INTEGER;
51548
+ if (aCat !== bCat)
51549
+ return aCat - bCat;
51550
+ if (a.primary.priority !== b.primary.priority)
51551
+ return a.primary.priority - b.primary.priority;
51552
+ return compareByReleaseDateDesc(a.primary, b.primary);
51553
+ };
51554
+ flagship.sort(byCuratedPriorityThenFreshness);
51555
+ fast.sort(byCuratedPriorityThenFreshness);
51556
+ return { flagship, fast };
51557
+ }
51558
+ function collectRoutingPrefixes(group, getNativePrefix) {
51559
+ const slug = (group.primary.provider || "").toLowerCase();
51560
+ const native = getNativePrefix(slug);
51561
+ const seen = new Set;
51562
+ const out = [];
51563
+ if (native) {
51564
+ out.push(native);
51565
+ seen.add(native);
51566
+ }
51567
+ for (const subscriptionRow of group.subscriptions) {
51568
+ const routes = subscriptionRow.subscriptions && subscriptionRow.subscriptions.length > 0 ? subscriptionRow.subscriptions : subscriptionRow.subscription ? [subscriptionRow.subscription] : [];
51569
+ const orderedRoutes = [...routes].sort(compareRecommendedRoutes);
51570
+ for (const route2 of orderedRoutes) {
51571
+ const p = route2?.prefix;
51572
+ if (!p || seen.has(p))
51573
+ continue;
51574
+ seen.add(p);
51575
+ out.push(p);
51576
+ }
51577
+ }
51578
+ return out;
51579
+ }
51580
+ function compareRecommendedRoutes(left, right) {
51581
+ const leftRank = left?.tier && Object.hasOwn(RECOMMENDED_ROUTE_TIER_ORDER, left.tier) ? RECOMMENDED_ROUTE_TIER_ORDER[left.tier] : Number.MAX_SAFE_INTEGER;
51582
+ const rightRank = right?.tier && Object.hasOwn(RECOMMENDED_ROUTE_TIER_ORDER, right.tier) ? RECOMMENDED_ROUTE_TIER_ORDER[right.tier] : Number.MAX_SAFE_INTEGER;
51583
+ return leftRank - rightRank;
51584
+ }
51585
+ function parsePriceAvg(s) {
51586
+ if (!s || s === "N/A")
51587
+ return Number.POSITIVE_INFINITY;
51588
+ if (s === "FREE")
51589
+ return 0;
51590
+ const m = s.match(/\$([\d.]+)/);
51591
+ return m ? Number.parseFloat(m[1]) : Number.POSITIVE_INFINITY;
51592
+ }
51593
+ function parseCtx(s) {
51594
+ if (!s || s === "N/A")
51595
+ return 0;
51596
+ const upper = s.toUpperCase();
51597
+ if (upper.includes("M"))
51598
+ return Number.parseFloat(upper) * 1e6;
51599
+ if (upper.includes("K"))
51600
+ return Number.parseFloat(upper) * 1000;
51601
+ return Number.parseInt(s, 10) || 0;
51602
+ }
51603
+ function normalizePricingDisplay(raw) {
51604
+ const pricing = raw || "N/A";
51605
+ if (pricing.includes("-1000000"))
51606
+ return "varies";
51607
+ if (pricing === "$0.00/1M" || pricing === "FREE")
51608
+ return "FREE";
51609
+ return pricing;
51610
+ }
51611
+ function formatListingPrice(entry, opts) {
51612
+ const rate = normalizePricingDisplay(entry.pricing?.average);
51613
+ if (rate !== "N/A")
51614
+ return rate;
51615
+ const plan = entry.subscription?.plan;
51616
+ if (!plan)
51617
+ return "N/A";
51618
+ return opts?.compact ? "SUB" : `SUB (${plan})`;
51619
+ }
51620
+ function computeQuickPicks(primaries) {
51621
+ if (primaries.length === 0) {
51622
+ return {
51623
+ budget: null,
51624
+ largeContext: null,
51625
+ mostCapable: null,
51626
+ visionCoding: null,
51627
+ agentic: null
51628
+ };
51629
+ }
51630
+ const priced = primaries.filter((m) => {
51631
+ const p = parsePriceAvg(m.pricing?.average);
51632
+ return p > 0 && p !== Number.POSITIVE_INFINITY;
51633
+ }).sort((a, b) => parsePriceAvg(a.pricing?.average) - parsePriceAvg(b.pricing?.average));
51634
+ const budget = priced[0] ?? null;
51635
+ const byCtx = [...primaries].sort((a, b) => parseCtx(b.context) - parseCtx(a.context));
51636
+ const largeContext = byCtx[0] ?? null;
51637
+ const byPrice = [...primaries].sort((a, b) => parsePriceAvg(b.pricing?.average) - parsePriceAvg(a.pricing?.average));
51638
+ const mostCapable = byPrice.find((m) => parsePriceAvg(m.pricing?.average) !== Number.POSITIVE_INFINITY) ?? null;
51639
+ const visionCoding = primaries.find((m) => m.supportsVision === true && m.id !== budget?.id && m.id !== mostCapable?.id) ?? null;
51640
+ const agentic = primaries.find((m) => m.supportsReasoning === true && m.id !== mostCapable?.id) ?? null;
51641
+ return { budget, largeContext, mostCapable, visionCoding, agentic };
51642
+ }
51643
+ async function getRecommendedModels(opts = {}) {
51644
+ const { forceRefresh = false } = opts;
51645
+ if (!forceRefresh && _cachedRecommendedModels) {
51646
+ return _cachedRecommendedModels;
51647
+ }
51648
+ if (!forceRefresh && existsSync21(RECOMMENDED_MODELS_CACHE_PATH)) {
51649
+ try {
51650
+ const cacheData = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
51651
+ if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
51652
+ _cachedRecommendedModels = cacheData;
51653
+ return cacheData;
51654
+ }
51655
+ } catch {}
51656
+ }
51657
+ try {
51658
+ const response = await fetch(FIREBASE_RECOMMENDED_URL, {
51659
+ signal: AbortSignal.timeout(RECOMMENDED_FETCH_TIMEOUT_MS)
51660
+ });
51661
+ if (response.ok) {
51662
+ const data = await response.json();
51663
+ if (data.models && data.models.length > 0) {
51664
+ _cachedRecommendedModels = data;
51665
+ try {
51666
+ const cacheDir = join31(homedir29(), ".claudish");
51667
+ mkdirSync13(cacheDir, { recursive: true });
51668
+ writeFileSync13(RECOMMENDED_MODELS_CACHE_PATH, JSON.stringify(data), "utf-8");
51669
+ } catch {}
51670
+ return data;
51671
+ }
51672
+ }
51673
+ } catch {}
51674
+ throw new Error("Unable to load recommended models: Firebase unreachable and no local cache. " + "Check connectivity.");
51675
+ }
51676
+ function getRecommendedModelsSync() {
51677
+ if (_cachedRecommendedModels)
51678
+ return _cachedRecommendedModels;
51679
+ if (existsSync21(RECOMMENDED_MODELS_CACHE_PATH)) {
51680
+ try {
51681
+ const cacheData = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
51682
+ if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
51683
+ _cachedRecommendedModels = cacheData;
51684
+ return cacheData;
51685
+ }
51686
+ } catch {}
51687
+ }
51688
+ return { version: "0", lastUpdated: "", models: [] };
51689
+ }
51690
+ async function warmRecommendedModels() {
51691
+ try {
51692
+ return await getRecommendedModels({ forceRefresh: true });
51693
+ } catch {
51694
+ return null;
51695
+ }
51696
+ }
51697
+ function isFreshEnough(doc2) {
51698
+ const generatedAt = doc2.generatedAt;
51699
+ if (!generatedAt)
51700
+ return true;
51701
+ const ageHours = (Date.now() - new Date(generatedAt).getTime()) / (1000 * 60 * 60);
51702
+ return ageHours <= FIREBASE_CACHE_TTL_HOURS;
51703
+ }
51704
+ async function searchModels(query, limit = 50) {
51705
+ const url2 = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(query)}&limit=${limit}&status=active`;
51706
+ const response = await fetch(url2, {
51707
+ signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
51708
+ });
51709
+ if (!response.ok) {
51710
+ throw new Error(`Firebase search returned ${response.status} ${response.statusText}`);
51711
+ }
51712
+ const data = await response.json();
51713
+ return data.models ?? [];
51714
+ }
51715
+ async function getModelByIdFromFirebase(modelId) {
51716
+ const url2 = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(modelId)}&limit=5`;
51717
+ const response = await fetch(url2, {
51718
+ signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
51719
+ });
51720
+ if (!response.ok) {
51721
+ throw new Error(`Firebase lookup returned ${response.status} ${response.statusText}`);
51722
+ }
51723
+ const data = await response.json();
51724
+ const models = data.models ?? [];
51725
+ for (const m of models) {
51726
+ if (m.modelId === modelId)
51727
+ return m;
51728
+ if (m.aliases?.includes(modelId))
51729
+ return m;
51730
+ }
51731
+ return null;
51732
+ }
51733
+ async function getTop100Models() {
51734
+ const url2 = `${FIREBASE_BASE_URL}?catalog=top100`;
51735
+ const response = await fetch(url2, {
51736
+ signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
51737
+ });
51738
+ if (!response.ok) {
51739
+ throw new Error(`Firebase top100 fetch failed: ${response.status} ${response.statusText}`);
51740
+ }
51741
+ const data = await response.json();
51742
+ return data;
51743
+ }
51744
+ async function getProviderList() {
51745
+ const url2 = `${FIREBASE_BASE_URL}?catalog=providers`;
51746
+ const response = await fetch(url2, {
51747
+ signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
51748
+ });
51749
+ if (!response.ok) {
51750
+ throw new Error(`Firebase providers fetch failed: ${response.status} ${response.statusText}`);
51751
+ }
51752
+ const data = await response.json();
51753
+ return data.providers ?? [];
51754
+ }
51755
+ async function getModelsByProvider(provider, limit = 200) {
51756
+ const url2 = `${FIREBASE_BASE_URL}?provider=${encodeURIComponent(provider)}&status=active&limit=${limit}`;
51757
+ const response = await fetch(url2, {
51758
+ signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
51759
+ });
51760
+ if (!response.ok) {
51761
+ throw new Error(`Firebase provider query returned ${response.status} ${response.statusText}`);
51762
+ }
51763
+ const data = await response.json();
51764
+ if (Array.isArray(data))
51765
+ return data;
51766
+ return data.models ?? [];
51767
+ }
51768
+ function loadModelInfo() {
51769
+ if (_cachedModelInfo) {
51770
+ return _cachedModelInfo;
51771
+ }
51772
+ const data = getRecommendedModelsSync();
51773
+ const modelInfo = {};
51774
+ for (const model of data.models) {
51775
+ modelInfo[model.id] = {
51776
+ name: model.name,
51777
+ description: model.description,
51778
+ priority: model.priority,
51779
+ provider: model.provider
51780
+ };
51781
+ }
51782
+ modelInfo.custom = {
51783
+ name: "Custom Model",
51784
+ description: "Enter any model ID manually",
51785
+ priority: 999,
51786
+ provider: "Custom"
51787
+ };
51788
+ _cachedModelInfo = modelInfo;
51789
+ return modelInfo;
51790
+ }
51791
+ function getAvailableModels() {
51792
+ if (_cachedModelIds) {
51793
+ return _cachedModelIds;
51794
+ }
51795
+ const data = getRecommendedModelsSync();
51796
+ const modelIds = data.models.sort((a, b) => a.priority - b.priority).map((m) => m.id);
51797
+ const result = [...modelIds, "custom"];
51798
+ _cachedModelIds = result;
51799
+ return result;
51800
+ }
51801
+ 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;
51802
+ var init_model_loader = __esm(() => {
51803
+ init_cache_ttl();
51804
+ FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
51805
+ RECOMMENDED_MODELS_CACHE_PATH = join31(homedir29(), ".claudish", "recommended-models-cache.json");
51806
+ FIREBASE_SLUG_TO_PROVIDER_NAME = {
51807
+ openai: "openai",
51808
+ google: "google",
51809
+ "x-ai": "x-ai",
51810
+ "z-ai": "z-ai",
51811
+ moonshotai: "kimi",
51812
+ minimax: "minimax",
51813
+ qwen: "qwen",
51814
+ deepseek: "deepseek",
51815
+ mistralai: "mistralai",
51816
+ sakana: "sakana"
51817
+ };
51818
+ RECOMMENDED_ROUTE_TIER_ORDER = {
51819
+ native: 0,
51820
+ general: 1,
51821
+ metered: 2,
51822
+ aggregator: 3
51823
+ };
51824
+ });
51825
+
51865
51826
  // src/port-manager.ts
51866
51827
  var exports_port_manager = {};
51867
51828
  __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.4",
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.4",
64
+ "@claudish/magmux-darwin-x64": "9.0.4",
65
+ "@claudish/magmux-linux-arm64": "9.0.4",
66
+ "@claudish/magmux-linux-x64": "9.0.4"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",