claudish 9.0.0 → 9.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +520 -395
- 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.
|
|
734
|
+
var VERSION = "9.0.2";
|
|
735
735
|
|
|
736
736
|
// src/logger.ts
|
|
737
737
|
var exports_logger = {};
|
|
@@ -835,7 +835,7 @@ function redactDeep(val, key) {
|
|
|
835
835
|
return val;
|
|
836
836
|
}
|
|
837
837
|
function isStructuralLogWorthy(msg) {
|
|
838
|
-
return msg.startsWith("[SSE:") || msg.startsWith("[Suppressed]") || msg.startsWith("[Proxy]") || msg.startsWith("[Fallback]") || msg.startsWith("[Streaming] ===") || msg.startsWith("[Streaming] Chunk:") || msg.startsWith("[Streaming] Received") || msg.startsWith("[Streaming] Text-based tool calls") || msg.startsWith("[Streaming] Final usage") || msg.startsWith("[Streaming] Sending") || msg.startsWith("[AnthropicSSE] Stream complete") || msg.startsWith("[AnthropicSSE] Tool use:") || msg.includes("Response status:") || msg.includes("Error") || msg.includes("error") || msg.includes("[Auto-route]");
|
|
838
|
+
return msg.startsWith("[SSE:") || msg.startsWith("[Suppressed]") || msg.startsWith("[Proxy]") || msg.startsWith("[Claude Code]") || msg.startsWith("[Fallback]") || msg.startsWith("[Streaming] ===") || msg.startsWith("[Streaming] Chunk:") || msg.startsWith("[Streaming] Received") || msg.startsWith("[Streaming] Text-based tool calls") || msg.startsWith("[Streaming] Final usage") || msg.startsWith("[Streaming] Sending") || msg.startsWith("[AnthropicSSE] Stream complete") || msg.startsWith("[AnthropicSSE] Tool use:") || msg.includes("Response status:") || msg.includes("Error") || msg.includes("error") || msg.includes("[Auto-route]");
|
|
839
839
|
}
|
|
840
840
|
function redactLogLine(message, timestamp) {
|
|
841
841
|
if (message.startsWith("[SSE:")) {
|
|
@@ -27477,11 +27477,13 @@ function readAllModelsCache(path = ALL_MODELS_CACHE_PATH) {
|
|
|
27477
27477
|
const lastUpdated = typeof data.lastUpdated === "string" ? data.lastUpdated : new Date(0).toISOString();
|
|
27478
27478
|
const models = Array.isArray(data.models) ? data.models : [];
|
|
27479
27479
|
const entries = Array.isArray(data.entries) ? data.entries : [];
|
|
27480
|
+
const plans = Array.isArray(data.plans) ? data.plans : undefined;
|
|
27480
27481
|
return {
|
|
27481
27482
|
version: 2,
|
|
27482
27483
|
lastUpdated,
|
|
27483
27484
|
entries,
|
|
27484
|
-
models
|
|
27485
|
+
models,
|
|
27486
|
+
...plans !== undefined ? { plans } : {}
|
|
27485
27487
|
};
|
|
27486
27488
|
}
|
|
27487
27489
|
function writeAllModelsCache(data, path = ALL_MODELS_CACHE_PATH) {
|
|
@@ -27490,7 +27492,8 @@ function writeAllModelsCache(data, path = ALL_MODELS_CACHE_PATH) {
|
|
|
27490
27492
|
version: 2,
|
|
27491
27493
|
lastUpdated: data.lastUpdated ?? new Date().toISOString(),
|
|
27492
27494
|
entries: data.entries ?? existing?.entries ?? [],
|
|
27493
|
-
models: data.models ?? existing?.models ?? []
|
|
27495
|
+
models: data.models ?? existing?.models ?? [],
|
|
27496
|
+
...data.plans !== undefined || existing?.plans !== undefined ? { plans: data.plans ?? existing?.plans ?? [] } : {}
|
|
27494
27497
|
};
|
|
27495
27498
|
mkdirSync5(dirname4(path), { recursive: true });
|
|
27496
27499
|
writeFileSync5(path, JSON.stringify(merged), "utf-8");
|
|
@@ -27632,13 +27635,32 @@ function resolveSubscriptionRouting(modelId, provider, cachePath) {
|
|
|
27632
27635
|
const entry = findCacheEntry(modelId, cachePath);
|
|
27633
27636
|
if (!entry)
|
|
27634
27637
|
return { kind: "unknown" };
|
|
27635
|
-
|
|
27638
|
+
const cache = readAllModelsCache(cachePath);
|
|
27639
|
+
const providerPlans = cache?.plans?.filter((plan) => plan.routing?.providerUid === provider) ?? [];
|
|
27640
|
+
if (cache?.plans === undefined) {
|
|
27641
|
+
if (entry.subscriptionPlans?.includes(provider)) {
|
|
27642
|
+
const agg = entry.aggregators?.find((a) => a.provider === provider);
|
|
27643
|
+
return agg?.externalId ? { kind: "serves", externalId: agg.externalId } : { kind: "unknown" };
|
|
27644
|
+
}
|
|
27645
|
+
return isLegacySubscriptionPlan(provider, cachePath) ? { kind: "not-served" } : { kind: "unknown" };
|
|
27646
|
+
}
|
|
27647
|
+
if (providerPlans.length === 0)
|
|
27648
|
+
return { kind: "unknown" };
|
|
27649
|
+
const providerPlanIds = new Set(providerPlans.map((plan) => plan.id));
|
|
27650
|
+
const hasMembership = entry.subscriptionPlans?.some((planId) => providerPlanIds.has(planId));
|
|
27651
|
+
if (hasMembership) {
|
|
27636
27652
|
const agg = entry.aggregators?.find((a) => a.provider === provider);
|
|
27637
27653
|
return agg?.externalId ? { kind: "serves", externalId: agg.externalId } : { kind: "unknown" };
|
|
27638
27654
|
}
|
|
27639
|
-
|
|
27655
|
+
const hasPublishedProviderRoster = cache.entries.some((candidate) => candidate.subscriptionPlans?.some((planId) => providerPlanIds.has(planId)));
|
|
27656
|
+
if (!hasPublishedProviderRoster)
|
|
27657
|
+
return { kind: "unknown" };
|
|
27658
|
+
return providerPlans.every(isCatalogDiscoveredPlan) ? { kind: "not-served" } : { kind: "unknown" };
|
|
27640
27659
|
}
|
|
27641
|
-
function
|
|
27660
|
+
function isCatalogDiscoveredPlan(plan) {
|
|
27661
|
+
return plan.modelDiscovery === "catalog";
|
|
27662
|
+
}
|
|
27663
|
+
function isLegacySubscriptionPlan(provider, cachePath) {
|
|
27642
27664
|
const cache = readAllModelsCache(cachePath);
|
|
27643
27665
|
if (!cache)
|
|
27644
27666
|
return false;
|
|
@@ -46348,6 +46370,16 @@ var init_auto_route = __esm(() => {
|
|
|
46348
46370
|
});
|
|
46349
46371
|
|
|
46350
46372
|
// src/providers/catalog-client.ts
|
|
46373
|
+
function derivePlansUrl(catalogUrl) {
|
|
46374
|
+
try {
|
|
46375
|
+
const url2 = new URL(catalogUrl);
|
|
46376
|
+
url2.pathname = url2.pathname.replace(/\/queryModels$/, "/queryPlans");
|
|
46377
|
+
url2.search = "";
|
|
46378
|
+
return url2.toString();
|
|
46379
|
+
} catch {
|
|
46380
|
+
return "https://us-central1-claudish-6da10.cloudfunctions.net/queryPlans";
|
|
46381
|
+
}
|
|
46382
|
+
}
|
|
46351
46383
|
function getCatalogEntries() {
|
|
46352
46384
|
if (_catalogEntriesForTest !== undefined)
|
|
46353
46385
|
return _catalogEntriesForTest;
|
|
@@ -46481,6 +46513,7 @@ function logResolution(userInput, result, quiet = false) {
|
|
|
46481
46513
|
}
|
|
46482
46514
|
}
|
|
46483
46515
|
async function refreshCatalog(timeoutMs) {
|
|
46516
|
+
const plansPromise = fetchSubscriptionPlans(timeoutMs);
|
|
46484
46517
|
let response;
|
|
46485
46518
|
try {
|
|
46486
46519
|
response = await fetch(FIREBASE_CATALOG_URL, { signal: AbortSignal.timeout(timeoutMs) });
|
|
@@ -46507,10 +46540,28 @@ async function refreshCatalog(timeoutMs) {
|
|
|
46507
46540
|
backwardCompatModels.push({ id });
|
|
46508
46541
|
}
|
|
46509
46542
|
_memCache = data.models;
|
|
46510
|
-
|
|
46543
|
+
const plans = await plansPromise;
|
|
46544
|
+
writeAllModelsCache({
|
|
46545
|
+
entries: data.models,
|
|
46546
|
+
models: backwardCompatModels,
|
|
46547
|
+
...plans !== undefined ? { plans } : {}
|
|
46548
|
+
});
|
|
46511
46549
|
_warmPromise = Promise.resolve();
|
|
46512
46550
|
return { kind: "refreshed", modelCount: data.models.length };
|
|
46513
46551
|
}
|
|
46552
|
+
async function fetchSubscriptionPlans(timeoutMs) {
|
|
46553
|
+
try {
|
|
46554
|
+
const response = await fetch(FIREBASE_PLANS_URL, {
|
|
46555
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
46556
|
+
});
|
|
46557
|
+
if (!response.ok)
|
|
46558
|
+
return;
|
|
46559
|
+
const data = await response.json();
|
|
46560
|
+
return Array.isArray(data.plans) ? data.plans : undefined;
|
|
46561
|
+
} catch {
|
|
46562
|
+
return;
|
|
46563
|
+
}
|
|
46564
|
+
}
|
|
46514
46565
|
async function warmCatalog() {
|
|
46515
46566
|
if (!_warmPromise) {
|
|
46516
46567
|
_warmPromise = refreshCatalog(8000).then(() => {
|
|
@@ -46532,10 +46583,11 @@ async function ensureCatalogReady(timeoutMs = 5000) {
|
|
|
46532
46583
|
new Promise((resolve3) => setTimeout(resolve3, timeoutMs))
|
|
46533
46584
|
]);
|
|
46534
46585
|
}
|
|
46535
|
-
var FIREBASE_CATALOG_URL, _memCache = null, _catalogEntriesForTest, _warmPromise = null;
|
|
46586
|
+
var FIREBASE_CATALOG_URL, FIREBASE_PLANS_URL, _memCache = null, _catalogEntriesForTest, _warmPromise = null;
|
|
46536
46587
|
var init_catalog_client = __esm(() => {
|
|
46537
46588
|
init_all_models_cache();
|
|
46538
46589
|
FIREBASE_CATALOG_URL = process.env.CLAUDISH_CATALOG_URL ?? process.env.FIREBASE_CATALOG_URL ?? "https://us-central1-claudish-6da10.cloudfunctions.net/queryModels?status=active&catalog=slim&limit=1000";
|
|
46590
|
+
FIREBASE_PLANS_URL = process.env.CLAUDISH_PLANS_URL ?? derivePlansUrl(FIREBASE_CATALOG_URL);
|
|
46539
46591
|
});
|
|
46540
46592
|
|
|
46541
46593
|
// src/config-schema.ts
|
|
@@ -47633,6 +47685,349 @@ var init_routing_hints = __esm(() => {
|
|
|
47633
47685
|
};
|
|
47634
47686
|
});
|
|
47635
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
|
+
|
|
47636
48031
|
// src/providers/default-routing-rules.ts
|
|
47637
48032
|
function validateRoutingRulesAgainstProviders(rules) {
|
|
47638
48033
|
const unknown3 = [];
|
|
@@ -47729,7 +48124,21 @@ function loadRoutingRules() {
|
|
|
47729
48124
|
const global_ = loadConfig().routing ?? {};
|
|
47730
48125
|
validateRoutingRules(local);
|
|
47731
48126
|
validateRoutingRules(global_);
|
|
47732
|
-
|
|
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;
|
|
47733
48142
|
}
|
|
47734
48143
|
function validateRoutingRules(rules) {
|
|
47735
48144
|
const seenLower = new Map;
|
|
@@ -47924,6 +48333,7 @@ var init_routing_rules = __esm(() => {
|
|
|
47924
48333
|
init_authority();
|
|
47925
48334
|
init_remote_provider_types();
|
|
47926
48335
|
init_logger();
|
|
48336
|
+
init_model_loader();
|
|
47927
48337
|
init_profile_config();
|
|
47928
48338
|
init_auto_route();
|
|
47929
48339
|
init_catalog_client();
|
|
@@ -47931,6 +48341,7 @@ var init_routing_rules = __esm(() => {
|
|
|
47931
48341
|
init_model_availability();
|
|
47932
48342
|
init_model_parser();
|
|
47933
48343
|
init_model_parser();
|
|
48344
|
+
init_provider_definitions();
|
|
47934
48345
|
init_routing_hints();
|
|
47935
48346
|
});
|
|
47936
48347
|
|
|
@@ -49066,8 +49477,8 @@ __export(exports_session_discovery, {
|
|
|
49066
49477
|
});
|
|
49067
49478
|
import { execFile, execFileSync as execFileSync2 } from "child_process";
|
|
49068
49479
|
import { closeSync as closeSync6, openSync as openSync6, readSync as readSync2, readdirSync as readdirSync4, realpathSync, statSync as statSync5 } from "fs";
|
|
49069
|
-
import { homedir as
|
|
49070
|
-
import { basename, join as
|
|
49480
|
+
import { homedir as homedir28 } from "os";
|
|
49481
|
+
import { basename, join as join28 } from "path";
|
|
49071
49482
|
function slugForPath(absPath) {
|
|
49072
49483
|
return absPath.replace(/[/.]/g, "-");
|
|
49073
49484
|
}
|
|
@@ -49076,7 +49487,7 @@ function transcriptPathFor(cwd, sessionUuid) {
|
|
|
49076
49487
|
try {
|
|
49077
49488
|
real = realpathSync(cwd);
|
|
49078
49489
|
} catch {}
|
|
49079
|
-
return
|
|
49490
|
+
return join28(PROJECTS_DIR, slugForPath(real), `${sessionUuid}.jsonl`);
|
|
49080
49491
|
}
|
|
49081
49492
|
function isAgentSession(row) {
|
|
49082
49493
|
return row.entrypoint !== undefined && row.entrypoint !== "cli";
|
|
@@ -49123,7 +49534,7 @@ function projectDirs() {
|
|
|
49123
49534
|
}
|
|
49124
49535
|
}
|
|
49125
49536
|
function sessionsIn(dirName) {
|
|
49126
|
-
const dir =
|
|
49537
|
+
const dir = join28(PROJECTS_DIR, dirName);
|
|
49127
49538
|
let names;
|
|
49128
49539
|
try {
|
|
49129
49540
|
names = readdirSync4(dir).filter((n) => n.endsWith(".jsonl"));
|
|
@@ -49132,7 +49543,7 @@ function sessionsIn(dirName) {
|
|
|
49132
49543
|
}
|
|
49133
49544
|
const rows = [];
|
|
49134
49545
|
for (const n of names) {
|
|
49135
|
-
const file2 =
|
|
49546
|
+
const file2 = join28(dir, n);
|
|
49136
49547
|
try {
|
|
49137
49548
|
const st = statSync5(file2);
|
|
49138
49549
|
if (st.size === 0)
|
|
@@ -49491,7 +49902,7 @@ function findLatestSessionId(cwd = process.cwd(), sinceMs = 0) {
|
|
|
49491
49902
|
}
|
|
49492
49903
|
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;
|
|
49493
49904
|
var init_session_discovery = __esm(() => {
|
|
49494
|
-
PROJECTS_DIR =
|
|
49905
|
+
PROJECTS_DIR = join28(homedir28(), ".claude", "projects");
|
|
49495
49906
|
HEAD_BYTES = 64 * 1024;
|
|
49496
49907
|
TAIL_BYTES = 128 * 1024;
|
|
49497
49908
|
HARNESS_ENVELOPES = [
|
|
@@ -49526,19 +49937,19 @@ function newStdioDecoder() {
|
|
|
49526
49937
|
var init_stdio_decode = () => {};
|
|
49527
49938
|
|
|
49528
49939
|
// src/team-stats.ts
|
|
49529
|
-
import { existsSync as
|
|
49530
|
-
import { join as
|
|
49940
|
+
import { existsSync as existsSync20, readFileSync as readFileSync19, writeFileSync as writeFileSync11 } from "fs";
|
|
49941
|
+
import { join as join29 } from "path";
|
|
49531
49942
|
function statsDir(sessionPath) {
|
|
49532
|
-
return
|
|
49943
|
+
return join29(sessionPath, "stats");
|
|
49533
49944
|
}
|
|
49534
49945
|
function tokenFileFor(sessionPath, anonId) {
|
|
49535
|
-
return
|
|
49946
|
+
return join29(statsDir(sessionPath), `${anonId}.json`);
|
|
49536
49947
|
}
|
|
49537
49948
|
function readTokenStatsAt(path) {
|
|
49538
|
-
if (!
|
|
49949
|
+
if (!existsSync20(path))
|
|
49539
49950
|
return null;
|
|
49540
49951
|
try {
|
|
49541
|
-
return JSON.parse(
|
|
49952
|
+
return JSON.parse(readFileSync19(path, "utf-8"));
|
|
49542
49953
|
} catch {
|
|
49543
49954
|
return null;
|
|
49544
49955
|
}
|
|
@@ -49689,7 +50100,7 @@ ${segs.join(" \xB7 ")}`;
|
|
|
49689
50100
|
}
|
|
49690
50101
|
function writeStatusFile(sessionPath, manifest, status, opts) {
|
|
49691
50102
|
try {
|
|
49692
|
-
|
|
50103
|
+
writeFileSync11(join29(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
|
|
49693
50104
|
`, "utf-8");
|
|
49694
50105
|
} catch {}
|
|
49695
50106
|
}
|
|
@@ -49724,13 +50135,13 @@ __export(exports_team_orchestrator, {
|
|
|
49724
50135
|
import { spawn as spawn2 } from "child_process";
|
|
49725
50136
|
import {
|
|
49726
50137
|
createWriteStream,
|
|
49727
|
-
existsSync as
|
|
49728
|
-
mkdirSync as
|
|
49729
|
-
readFileSync as
|
|
50138
|
+
existsSync as existsSync21,
|
|
50139
|
+
mkdirSync as mkdirSync12,
|
|
50140
|
+
readFileSync as readFileSync20,
|
|
49730
50141
|
readdirSync as readdirSync5,
|
|
49731
|
-
writeFileSync as
|
|
50142
|
+
writeFileSync as writeFileSync12
|
|
49732
50143
|
} from "fs";
|
|
49733
|
-
import { basename as basename2, join as
|
|
50144
|
+
import { basename as basename2, join as join30, resolve as resolve3 } from "path";
|
|
49734
50145
|
function resolveCaptureMode(explicit, env = process.env) {
|
|
49735
50146
|
if (explicit)
|
|
49736
50147
|
return explicit;
|
|
@@ -49848,7 +50259,7 @@ function persistErrorLog(errorLogPath, header, stderr, stdoutTail) {
|
|
|
49848
50259
|
parts.push("--- stderr ---", stderr.trim() ? redactSecrets(stderr) : "(empty)", "");
|
|
49849
50260
|
parts.push("--- stdout (tail) ---", stdoutTail.trim() ? redactSecrets(stdoutTail) : "(empty)", "");
|
|
49850
50261
|
try {
|
|
49851
|
-
|
|
50262
|
+
writeFileSync12(errorLogPath, parts.join(`
|
|
49852
50263
|
`), "utf-8");
|
|
49853
50264
|
} catch {}
|
|
49854
50265
|
}
|
|
@@ -49866,10 +50277,10 @@ function readTeamInputFile(inputPath) {
|
|
|
49866
50277
|
if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
|
|
49867
50278
|
throw new Error(`Input file must be within current directory: ${inputPath}`);
|
|
49868
50279
|
}
|
|
49869
|
-
if (!
|
|
50280
|
+
if (!existsSync21(resolved)) {
|
|
49870
50281
|
throw new Error(`Input file not found: ${resolved}`);
|
|
49871
50282
|
}
|
|
49872
|
-
const text =
|
|
50283
|
+
const text = readFileSync20(resolved, "utf-8");
|
|
49873
50284
|
if (text.trim().length === 0) {
|
|
49874
50285
|
throw new Error(`Input file is empty: ${resolved}`);
|
|
49875
50286
|
}
|
|
@@ -49879,14 +50290,14 @@ function setupSession(sessionPath, models, input) {
|
|
|
49879
50290
|
if (models.length === 0) {
|
|
49880
50291
|
throw new Error("At least one model is required");
|
|
49881
50292
|
}
|
|
49882
|
-
if (
|
|
50293
|
+
if (existsSync21(join30(sessionPath, "manifest.json"))) {
|
|
49883
50294
|
throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
|
|
49884
50295
|
}
|
|
49885
|
-
|
|
49886
|
-
|
|
50296
|
+
mkdirSync12(join30(sessionPath, "work"), { recursive: true });
|
|
50297
|
+
mkdirSync12(join30(sessionPath, "errors"), { recursive: true });
|
|
49887
50298
|
if (input !== undefined) {
|
|
49888
|
-
|
|
49889
|
-
} else if (!
|
|
50299
|
+
writeFileSync12(join30(sessionPath, "input.md"), input, "utf-8");
|
|
50300
|
+
} else if (!existsSync21(join30(sessionPath, "input.md"))) {
|
|
49890
50301
|
throw new Error(`No input.md found at ${sessionPath} and no input provided`);
|
|
49891
50302
|
}
|
|
49892
50303
|
const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
|
|
@@ -49903,9 +50314,9 @@ function setupSession(sessionPath, models, input) {
|
|
|
49903
50314
|
model: models[i],
|
|
49904
50315
|
assignedAt: now2
|
|
49905
50316
|
};
|
|
49906
|
-
|
|
50317
|
+
mkdirSync12(join30(sessionPath, "work", anonId), { recursive: true });
|
|
49907
50318
|
}
|
|
49908
|
-
|
|
50319
|
+
writeFileSync12(join30(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
49909
50320
|
const status = {
|
|
49910
50321
|
startedAt: now2,
|
|
49911
50322
|
models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
|
|
@@ -49919,7 +50330,7 @@ function setupSession(sessionPath, models, input) {
|
|
|
49919
50330
|
}
|
|
49920
50331
|
]))
|
|
49921
50332
|
};
|
|
49922
|
-
|
|
50333
|
+
writeFileSync12(join30(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
|
|
49923
50334
|
return manifest;
|
|
49924
50335
|
}
|
|
49925
50336
|
function assertValidRequirePattern(pattern) {
|
|
@@ -49936,22 +50347,22 @@ function readFullOutputIfNeeded(opts) {
|
|
|
49936
50347
|
if (crashed || !requirePattern || outputSize <= STDOUT_TAIL_LIMIT)
|
|
49937
50348
|
return;
|
|
49938
50349
|
try {
|
|
49939
|
-
return
|
|
50350
|
+
return readFileSync20(outputPath, "utf-8");
|
|
49940
50351
|
} catch {
|
|
49941
50352
|
return;
|
|
49942
50353
|
}
|
|
49943
50354
|
}
|
|
49944
50355
|
async function startModels(sessionPath, opts = {}) {
|
|
49945
50356
|
assertValidRequirePattern(opts.requirePattern);
|
|
49946
|
-
const manifest = JSON.parse(
|
|
49947
|
-
const statusPath =
|
|
49948
|
-
const inputPath =
|
|
49949
|
-
const inputContent =
|
|
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");
|
|
49950
50361
|
const spawnPlan = await (opts.spawnPlanner ?? prehydrateCredentialsForSpawn)(Object.values(manifest.models).map((m) => m.model));
|
|
49951
|
-
const statusCache = JSON.parse(
|
|
50362
|
+
const statusCache = JSON.parse(readFileSync20(statusPath, "utf-8"));
|
|
49952
50363
|
function updateModelStatus(id, update) {
|
|
49953
50364
|
statusCache.models[id] = { ...statusCache.models[id], ...update };
|
|
49954
|
-
|
|
50365
|
+
writeFileSync12(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
|
|
49955
50366
|
}
|
|
49956
50367
|
const minOutputBytes = opts.minOutputBytes ?? DEFAULT_MIN_OUTPUT_BYTES;
|
|
49957
50368
|
const requirePattern = opts.requirePattern;
|
|
@@ -49984,7 +50395,7 @@ async function startModels(sessionPath, opts = {}) {
|
|
|
49984
50395
|
persistErrorLog(rt.errorLogPath, `RECOVERED: ${note}`, stderr, stdoutTail);
|
|
49985
50396
|
opts.onStatusChange?.(id, statusCache.models[id]);
|
|
49986
50397
|
}
|
|
49987
|
-
|
|
50398
|
+
mkdirSync12(statsDir(sessionPath), { recursive: true });
|
|
49988
50399
|
const processes = new Map;
|
|
49989
50400
|
const runtimes = new Map;
|
|
49990
50401
|
const cancelledSlots = new Set;
|
|
@@ -49997,9 +50408,9 @@ async function startModels(sessionPath, opts = {}) {
|
|
|
49997
50408
|
process.on("SIGINT", sigintHandler);
|
|
49998
50409
|
const completionPromises = [];
|
|
49999
50410
|
for (const [anonId, entry] of Object.entries(manifest.models)) {
|
|
50000
|
-
const outputPath =
|
|
50001
|
-
const errorLogPath =
|
|
50002
|
-
const upstreamErrorLogPath =
|
|
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`);
|
|
50003
50414
|
const spawnModel = spawnPlan.pinned.get(entry.model) ?? entry.model;
|
|
50004
50415
|
const args = [
|
|
50005
50416
|
"--model",
|
|
@@ -50139,7 +50550,7 @@ async function startModels(sessionPath, opts = {}) {
|
|
|
50139
50550
|
stderrSnippet: stderr ? redactSecrets(stderr).slice(-2000) : undefined,
|
|
50140
50551
|
stdoutSnippet: stdoutTail ? redactSecrets(stdoutTail).slice(-2000) : undefined,
|
|
50141
50552
|
errorLogPath,
|
|
50142
|
-
upstreamErrorLogPath:
|
|
50553
|
+
upstreamErrorLogPath: existsSync21(upstreamErrorLogPath) ? upstreamErrorLogPath : undefined,
|
|
50143
50554
|
workDir: sessionPath
|
|
50144
50555
|
}
|
|
50145
50556
|
});
|
|
@@ -50159,7 +50570,7 @@ async function startModels(sessionPath, opts = {}) {
|
|
|
50159
50570
|
proc.on("exit", (code) => {
|
|
50160
50571
|
const timedOut = statusCache.models[anonId]?.state === "TIMEOUT";
|
|
50161
50572
|
if (!timedOut && meaningfulStderr(stderr)) {
|
|
50162
|
-
|
|
50573
|
+
writeFileSync12(errorLogPath, redactSecrets(stderr), "utf-8");
|
|
50163
50574
|
}
|
|
50164
50575
|
exitCode = code;
|
|
50165
50576
|
if (outputStream.destroyed) {
|
|
@@ -50239,23 +50650,23 @@ async function judgeResponses(sessionPath, opts = {}) {
|
|
|
50239
50650
|
const responses = {};
|
|
50240
50651
|
for (const file2 of responseFiles) {
|
|
50241
50652
|
const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
|
|
50242
|
-
responses[id] =
|
|
50653
|
+
responses[id] = readFileSync20(join30(sessionPath, file2), "utf-8");
|
|
50243
50654
|
}
|
|
50244
|
-
const input =
|
|
50655
|
+
const input = readFileSync20(join30(sessionPath, "input.md"), "utf-8");
|
|
50245
50656
|
const judgePrompt = buildJudgePrompt(input, responses);
|
|
50246
|
-
|
|
50657
|
+
writeFileSync12(join30(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
|
|
50247
50658
|
const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
|
|
50248
|
-
const judgePath =
|
|
50249
|
-
|
|
50659
|
+
const judgePath = join30(sessionPath, "judging");
|
|
50660
|
+
mkdirSync12(judgePath, { recursive: true });
|
|
50250
50661
|
setupSession(judgePath, judgeModels, judgePrompt);
|
|
50251
50662
|
await runModels(judgePath, { claudeFlags: opts.claudeFlags });
|
|
50252
50663
|
const votes = parseJudgeVotes(judgePath, Object.keys(responses));
|
|
50253
50664
|
const verdict = aggregateVerdict(votes, Object.keys(responses));
|
|
50254
|
-
|
|
50665
|
+
writeFileSync12(join30(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
|
|
50255
50666
|
return verdict;
|
|
50256
50667
|
}
|
|
50257
50668
|
function getStatus(sessionPath) {
|
|
50258
|
-
return JSON.parse(
|
|
50669
|
+
return JSON.parse(readFileSync20(join30(sessionPath, "status.json"), "utf-8"));
|
|
50259
50670
|
}
|
|
50260
50671
|
function fisherYatesShuffle(arr) {
|
|
50261
50672
|
for (let i = arr.length - 1;i > 0; i--) {
|
|
@@ -50265,7 +50676,7 @@ function fisherYatesShuffle(arr) {
|
|
|
50265
50676
|
return arr;
|
|
50266
50677
|
}
|
|
50267
50678
|
function getDefaultJudgeModels(sessionPath) {
|
|
50268
|
-
const manifest = JSON.parse(
|
|
50679
|
+
const manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
|
|
50269
50680
|
return Object.values(manifest.models).map((e) => e.model);
|
|
50270
50681
|
}
|
|
50271
50682
|
function buildJudgePrompt(input, responses) {
|
|
@@ -50328,7 +50739,7 @@ function parseJudgeVotes(judgePath, responseIds) {
|
|
|
50328
50739
|
const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
|
|
50329
50740
|
let content;
|
|
50330
50741
|
try {
|
|
50331
|
-
content =
|
|
50742
|
+
content = readFileSync20(join30(judgePath, file2), "utf-8");
|
|
50332
50743
|
} catch {
|
|
50333
50744
|
continue;
|
|
50334
50745
|
}
|
|
@@ -50380,7 +50791,7 @@ function aggregateVerdict(votes, responseIds) {
|
|
|
50380
50791
|
function formatVerdict(verdict, sessionPath) {
|
|
50381
50792
|
let manifest = null;
|
|
50382
50793
|
try {
|
|
50383
|
-
manifest = JSON.parse(
|
|
50794
|
+
manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
|
|
50384
50795
|
} catch {}
|
|
50385
50796
|
let output = `# Team Verdict
|
|
50386
50797
|
|
|
@@ -50434,15 +50845,15 @@ import {
|
|
|
50434
50845
|
appendFileSync as appendFileSync6,
|
|
50435
50846
|
closeSync as closeSync7,
|
|
50436
50847
|
createWriteStream as createWriteStream2,
|
|
50437
|
-
mkdirSync as
|
|
50848
|
+
mkdirSync as mkdirSync13,
|
|
50438
50849
|
openSync as openSync7,
|
|
50439
|
-
readFileSync as
|
|
50850
|
+
readFileSync as readFileSync21,
|
|
50440
50851
|
readSync as readSync3,
|
|
50441
50852
|
statSync as statSync6,
|
|
50442
|
-
writeFileSync as
|
|
50853
|
+
writeFileSync as writeFileSync13
|
|
50443
50854
|
} from "fs";
|
|
50444
|
-
import { homedir as
|
|
50445
|
-
import { join as
|
|
50855
|
+
import { homedir as homedir29 } from "os";
|
|
50856
|
+
import { join as join31, resolve as resolve4, sep } from "path";
|
|
50446
50857
|
import { StringDecoder as StringDecoder2 } from "string_decoder";
|
|
50447
50858
|
function buildChannelSpawnArgs(opts) {
|
|
50448
50859
|
return [
|
|
@@ -50517,7 +50928,7 @@ function readJsonObject(path, maxBytes) {
|
|
|
50517
50928
|
try {
|
|
50518
50929
|
if (fileSize(path) > maxBytes)
|
|
50519
50930
|
return null;
|
|
50520
|
-
const parsed = JSON.parse(
|
|
50931
|
+
const parsed = JSON.parse(readFileSync21(path, "utf-8"));
|
|
50521
50932
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
50522
50933
|
return null;
|
|
50523
50934
|
return parsed;
|
|
@@ -50533,7 +50944,7 @@ function dropLeadingFragment(tail) {
|
|
|
50533
50944
|
return firstBreak === -1 ? tail.text : tail.text.slice(firstBreak + 1);
|
|
50534
50945
|
}
|
|
50535
50946
|
function diskAccounting(sessionDir) {
|
|
50536
|
-
const stats = readTokenStatsAt(
|
|
50947
|
+
const stats = readTokenStatsAt(join31(sessionDir, "tokens.json"));
|
|
50537
50948
|
return {
|
|
50538
50949
|
tokensUsed: (stats?.total_tokens ?? 0) || (stats?.input_tokens ?? 0) + (stats?.output_tokens ?? 0),
|
|
50539
50950
|
costUsd: stats?.total_cost ?? 0,
|
|
@@ -50573,7 +50984,7 @@ class SessionManager {
|
|
|
50573
50984
|
this.maxSessions = options?.maxSessions ?? DEFAULT_MAX_SESSIONS;
|
|
50574
50985
|
this.scrollbackCapacity = options?.scrollbackCapacity ?? DEFAULT_SCROLLBACK;
|
|
50575
50986
|
this.terminalRetentionMs = options?.terminalRetentionMs ?? TERMINAL_RETENTION_MS;
|
|
50576
|
-
this.sessionsDir = options?.sessionsDir ?? process.env.CLAUDISH_SESSIONS_DIR ??
|
|
50987
|
+
this.sessionsDir = options?.sessionsDir ?? process.env.CLAUDISH_SESSIONS_DIR ?? join31(homedir29(), ".claudish", "sessions");
|
|
50577
50988
|
this.stallSeconds = options?.stallSeconds;
|
|
50578
50989
|
this.onStateChange = options?.onStateChange;
|
|
50579
50990
|
}
|
|
@@ -50589,19 +51000,19 @@ class SessionManager {
|
|
|
50589
51000
|
const claudeSessionId = randomUUID4();
|
|
50590
51001
|
const timeout = Math.min(opts.timeoutSeconds ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
|
|
50591
51002
|
const startedAt = new Date().toISOString();
|
|
50592
|
-
const sessionDir = opts.sessionDir ??
|
|
50593
|
-
|
|
51003
|
+
const sessionDir = opts.sessionDir ?? join31(this.sessionsDir, sessionId2);
|
|
51004
|
+
mkdirSync13(sessionDir, { recursive: true });
|
|
50594
51005
|
if (opts.prompt) {
|
|
50595
|
-
|
|
51006
|
+
writeFileSync13(join31(sessionDir, "prompt.md"), opts.prompt, "utf-8");
|
|
50596
51007
|
}
|
|
50597
51008
|
const args = buildChannelSpawnArgs({
|
|
50598
51009
|
model: opts.spawnModel ?? opts.model,
|
|
50599
51010
|
claudeSessionId,
|
|
50600
51011
|
claudishFlags: opts.claudishFlags
|
|
50601
51012
|
});
|
|
50602
|
-
const tokenFile = opts.tokenFile ??
|
|
50603
|
-
const eventLogPath =
|
|
50604
|
-
const upstreamErrorLogPath =
|
|
51013
|
+
const tokenFile = opts.tokenFile ?? join31(sessionDir, "tokens.json");
|
|
51014
|
+
const eventLogPath = join31(sessionDir, "events.jsonl");
|
|
51015
|
+
const upstreamErrorLogPath = join31(sessionDir, "upstream-errors.jsonl");
|
|
50605
51016
|
const cwd = opts.cwd ?? process.cwd();
|
|
50606
51017
|
const spawnTarget = resolveClaudishSpawn();
|
|
50607
51018
|
const proc = spawn3(spawnTarget.command, [...spawnTarget.prefixArgs, ...args], {
|
|
@@ -50616,7 +51027,7 @@ class SessionManager {
|
|
|
50616
51027
|
}
|
|
50617
51028
|
});
|
|
50618
51029
|
const scrollback = new ScrollbackBuffer(this.scrollbackCapacity);
|
|
50619
|
-
const outputLogStream = createWriteStream2(
|
|
51030
|
+
const outputLogStream = createWriteStream2(join31(sessionDir, "output.log"));
|
|
50620
51031
|
const entry = {
|
|
50621
51032
|
info: {
|
|
50622
51033
|
sessionId: sessionId2,
|
|
@@ -50908,7 +51319,7 @@ class SessionManager {
|
|
|
50908
51319
|
return null;
|
|
50909
51320
|
const root = resolve4(this.sessionsDir);
|
|
50910
51321
|
const dir = resolve4(root, sessionId2);
|
|
50911
|
-
if (dir !==
|
|
51322
|
+
if (dir !== join31(root, sessionId2))
|
|
50912
51323
|
return null;
|
|
50913
51324
|
if (!dir.startsWith(root + sep))
|
|
50914
51325
|
return null;
|
|
@@ -50927,7 +51338,7 @@ class SessionManager {
|
|
|
50927
51338
|
} catch {
|
|
50928
51339
|
return null;
|
|
50929
51340
|
}
|
|
50930
|
-
const meta3 = readJsonObject(
|
|
51341
|
+
const meta3 = readJsonObject(join31(sessionDir, "meta.json"), META_READ_LIMIT);
|
|
50931
51342
|
const partial2 = meta3 === null;
|
|
50932
51343
|
const measured = diskAccounting(sessionDir);
|
|
50933
51344
|
const startedAt = metaString(meta3?.startedAt) ?? new Date(dirMtimeMs).toISOString();
|
|
@@ -50957,7 +51368,7 @@ class SessionManager {
|
|
|
50957
51368
|
};
|
|
50958
51369
|
}
|
|
50959
51370
|
diskOutput(record4, tailLines) {
|
|
50960
|
-
const tail = readTailText(
|
|
51371
|
+
const tail = readTailText(join31(record4.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
|
|
50961
51372
|
const buffer = new ScrollbackBuffer(this.scrollbackCapacity);
|
|
50962
51373
|
if (tail?.text)
|
|
50963
51374
|
buffer.append(dropLeadingFragment(tail));
|
|
@@ -50976,9 +51387,9 @@ class SessionManager {
|
|
|
50976
51387
|
}
|
|
50977
51388
|
diskDiagnostics(record4, limit) {
|
|
50978
51389
|
const { sessionDir, info } = record4;
|
|
50979
|
-
const eventLogPath =
|
|
50980
|
-
const upstreamErrorLogPath =
|
|
50981
|
-
const outputLogPath =
|
|
51390
|
+
const eventLogPath = join31(sessionDir, "events.jsonl");
|
|
51391
|
+
const upstreamErrorLogPath = join31(sessionDir, "upstream-errors.jsonl");
|
|
51392
|
+
const outputLogPath = join31(sessionDir, "output.log");
|
|
50982
51393
|
const events = readTailLines(eventLogPath, EVENT_TAIL_BYTES);
|
|
50983
51394
|
const outputTail = readTailText(outputLogPath, OUTPUT_TAIL_BYTES);
|
|
50984
51395
|
return {
|
|
@@ -51020,7 +51431,7 @@ class SessionManager {
|
|
|
51020
51431
|
};
|
|
51021
51432
|
}
|
|
51022
51433
|
diskStderrForDiagnostics(record4) {
|
|
51023
|
-
const tail = readTailText(
|
|
51434
|
+
const tail = readTailText(join31(record4.sessionDir, "stderr.log"), STDERR_READ_BYTES);
|
|
51024
51435
|
const raw = tail?.text ?? "";
|
|
51025
51436
|
const filtered = record4.info.status === "completed";
|
|
51026
51437
|
const source = filtered ? meaningfulStderr(raw) : raw;
|
|
@@ -51196,11 +51607,11 @@ ${STDERR_TRUNCATION_MARKER} ${STDERR_SIDE_LIMIT} bytes per end \u2026
|
|
|
51196
51607
|
entry.outputLogStream?.end();
|
|
51197
51608
|
entry.outputLogStream = null;
|
|
51198
51609
|
if (entry.stderr) {
|
|
51199
|
-
|
|
51610
|
+
writeFileSync13(join31(entry.sessionDir, "stderr.log"), redactSecrets(entry.stderr), "utf-8");
|
|
51200
51611
|
}
|
|
51201
51612
|
this.refreshAccounting(entry);
|
|
51202
51613
|
entry.info.claudeSessionId = entry.reducer.claudeSessionId ?? entry.info.claudeSessionId;
|
|
51203
|
-
|
|
51614
|
+
writeFileSync13(join31(entry.sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
|
|
51204
51615
|
}
|
|
51205
51616
|
scheduleEviction(entry) {
|
|
51206
51617
|
if (entry.evictHandle)
|
|
@@ -51260,7 +51671,7 @@ ${STDERR_TRUNCATION_MARKER} ${STDERR_SIDE_LIMIT} bytes per end \u2026
|
|
|
51260
51671
|
return { state: "completed", content: "" };
|
|
51261
51672
|
}
|
|
51262
51673
|
refreshAccounting(entry) {
|
|
51263
|
-
const stats = readTokenStatsAt(
|
|
51674
|
+
const stats = readTokenStatsAt(join31(entry.sessionDir, "tokens.json"));
|
|
51264
51675
|
const fileTokens = (stats?.total_tokens ?? 0) || (stats?.input_tokens ?? 0) + (stats?.output_tokens ?? 0);
|
|
51265
51676
|
entry.info.tokensUsed = fileTokens || entry.reducer.tokens;
|
|
51266
51677
|
entry.info.costUsd = stats?.total_cost ?? 0;
|
|
@@ -51451,309 +51862,6 @@ var init_progress_heartbeat = __esm(() => {
|
|
|
51451
51862
|
});
|
|
51452
51863
|
});
|
|
51453
51864
|
|
|
51454
|
-
// src/providers/cache-ttl.ts
|
|
51455
|
-
var FIREBASE_CACHE_TTL_HOURS = 24, FIREBASE_CACHE_TTL_MS;
|
|
51456
|
-
var init_cache_ttl = __esm(() => {
|
|
51457
|
-
FIREBASE_CACHE_TTL_MS = FIREBASE_CACHE_TTL_HOURS * 60 * 60 * 1000;
|
|
51458
|
-
});
|
|
51459
|
-
|
|
51460
|
-
// src/model-loader.ts
|
|
51461
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
|
|
51462
|
-
import { homedir as homedir29 } from "os";
|
|
51463
|
-
import { join as join31 } from "path";
|
|
51464
|
-
function groupRecommendedModels(entries) {
|
|
51465
|
-
const byId = new Map;
|
|
51466
|
-
const categoryOrder = new Map;
|
|
51467
|
-
for (const entry of entries) {
|
|
51468
|
-
const list = byId.get(entry.id);
|
|
51469
|
-
if (list)
|
|
51470
|
-
list.push(entry);
|
|
51471
|
-
else
|
|
51472
|
-
byId.set(entry.id, [entry]);
|
|
51473
|
-
if (!categoryOrder.has(entry.category))
|
|
51474
|
-
categoryOrder.set(entry.category, categoryOrder.size);
|
|
51475
|
-
}
|
|
51476
|
-
const flagship = [];
|
|
51477
|
-
const fast = [];
|
|
51478
|
-
for (const [id, members] of byId.entries()) {
|
|
51479
|
-
const primary = members.find((m) => m.category !== "subscription") ?? members[0];
|
|
51480
|
-
const subscriptions = members.filter((m) => m.category === "subscription");
|
|
51481
|
-
const bucket = primary.category === "programming" || primary.category === "vision" || primary.category === "reasoning" ? "flagship" : "fast";
|
|
51482
|
-
const group = { id, primary, subscriptions, bucket };
|
|
51483
|
-
if (bucket === "flagship")
|
|
51484
|
-
flagship.push(group);
|
|
51485
|
-
else
|
|
51486
|
-
fast.push(group);
|
|
51487
|
-
}
|
|
51488
|
-
const byCuratedPriorityThenFreshness = (a, b) => {
|
|
51489
|
-
const aCat = categoryOrder.get(a.primary.category) ?? Number.MAX_SAFE_INTEGER;
|
|
51490
|
-
const bCat = categoryOrder.get(b.primary.category) ?? Number.MAX_SAFE_INTEGER;
|
|
51491
|
-
if (aCat !== bCat)
|
|
51492
|
-
return aCat - bCat;
|
|
51493
|
-
if (a.primary.priority !== b.primary.priority)
|
|
51494
|
-
return a.primary.priority - b.primary.priority;
|
|
51495
|
-
return compareByReleaseDateDesc(a.primary, b.primary);
|
|
51496
|
-
};
|
|
51497
|
-
flagship.sort(byCuratedPriorityThenFreshness);
|
|
51498
|
-
fast.sort(byCuratedPriorityThenFreshness);
|
|
51499
|
-
return { flagship, fast };
|
|
51500
|
-
}
|
|
51501
|
-
function collectRoutingPrefixes(group, getNativePrefix) {
|
|
51502
|
-
const slug = (group.primary.provider || "").toLowerCase();
|
|
51503
|
-
const native = getNativePrefix(slug);
|
|
51504
|
-
const seen = new Set;
|
|
51505
|
-
const out = [];
|
|
51506
|
-
if (native) {
|
|
51507
|
-
out.push(native);
|
|
51508
|
-
seen.add(native);
|
|
51509
|
-
}
|
|
51510
|
-
for (const subscriptionRow of group.subscriptions) {
|
|
51511
|
-
const routes = subscriptionRow.subscriptions && subscriptionRow.subscriptions.length > 0 ? subscriptionRow.subscriptions : subscriptionRow.subscription ? [subscriptionRow.subscription] : [];
|
|
51512
|
-
for (const route2 of routes) {
|
|
51513
|
-
const p = route2?.prefix;
|
|
51514
|
-
if (!p || seen.has(p))
|
|
51515
|
-
continue;
|
|
51516
|
-
seen.add(p);
|
|
51517
|
-
out.push(p);
|
|
51518
|
-
}
|
|
51519
|
-
}
|
|
51520
|
-
return out;
|
|
51521
|
-
}
|
|
51522
|
-
function parsePriceAvg(s) {
|
|
51523
|
-
if (!s || s === "N/A")
|
|
51524
|
-
return Number.POSITIVE_INFINITY;
|
|
51525
|
-
if (s === "FREE")
|
|
51526
|
-
return 0;
|
|
51527
|
-
const m = s.match(/\$([\d.]+)/);
|
|
51528
|
-
return m ? Number.parseFloat(m[1]) : Number.POSITIVE_INFINITY;
|
|
51529
|
-
}
|
|
51530
|
-
function parseCtx(s) {
|
|
51531
|
-
if (!s || s === "N/A")
|
|
51532
|
-
return 0;
|
|
51533
|
-
const upper = s.toUpperCase();
|
|
51534
|
-
if (upper.includes("M"))
|
|
51535
|
-
return Number.parseFloat(upper) * 1e6;
|
|
51536
|
-
if (upper.includes("K"))
|
|
51537
|
-
return Number.parseFloat(upper) * 1000;
|
|
51538
|
-
return Number.parseInt(s, 10) || 0;
|
|
51539
|
-
}
|
|
51540
|
-
function normalizePricingDisplay(raw) {
|
|
51541
|
-
const pricing = raw || "N/A";
|
|
51542
|
-
if (pricing.includes("-1000000"))
|
|
51543
|
-
return "varies";
|
|
51544
|
-
if (pricing === "$0.00/1M" || pricing === "FREE")
|
|
51545
|
-
return "FREE";
|
|
51546
|
-
return pricing;
|
|
51547
|
-
}
|
|
51548
|
-
function formatListingPrice(entry, opts) {
|
|
51549
|
-
const rate = normalizePricingDisplay(entry.pricing?.average);
|
|
51550
|
-
if (rate !== "N/A")
|
|
51551
|
-
return rate;
|
|
51552
|
-
const plan = entry.subscription?.plan;
|
|
51553
|
-
if (!plan)
|
|
51554
|
-
return "N/A";
|
|
51555
|
-
return opts?.compact ? "SUB" : `SUB (${plan})`;
|
|
51556
|
-
}
|
|
51557
|
-
function computeQuickPicks(primaries) {
|
|
51558
|
-
if (primaries.length === 0) {
|
|
51559
|
-
return {
|
|
51560
|
-
budget: null,
|
|
51561
|
-
largeContext: null,
|
|
51562
|
-
mostCapable: null,
|
|
51563
|
-
visionCoding: null,
|
|
51564
|
-
agentic: null
|
|
51565
|
-
};
|
|
51566
|
-
}
|
|
51567
|
-
const priced = primaries.filter((m) => {
|
|
51568
|
-
const p = parsePriceAvg(m.pricing?.average);
|
|
51569
|
-
return p > 0 && p !== Number.POSITIVE_INFINITY;
|
|
51570
|
-
}).sort((a, b) => parsePriceAvg(a.pricing?.average) - parsePriceAvg(b.pricing?.average));
|
|
51571
|
-
const budget = priced[0] ?? null;
|
|
51572
|
-
const byCtx = [...primaries].sort((a, b) => parseCtx(b.context) - parseCtx(a.context));
|
|
51573
|
-
const largeContext = byCtx[0] ?? null;
|
|
51574
|
-
const byPrice = [...primaries].sort((a, b) => parsePriceAvg(b.pricing?.average) - parsePriceAvg(a.pricing?.average));
|
|
51575
|
-
const mostCapable = byPrice.find((m) => parsePriceAvg(m.pricing?.average) !== Number.POSITIVE_INFINITY) ?? null;
|
|
51576
|
-
const visionCoding = primaries.find((m) => m.supportsVision === true && m.id !== budget?.id && m.id !== mostCapable?.id) ?? null;
|
|
51577
|
-
const agentic = primaries.find((m) => m.supportsReasoning === true && m.id !== mostCapable?.id) ?? null;
|
|
51578
|
-
return { budget, largeContext, mostCapable, visionCoding, agentic };
|
|
51579
|
-
}
|
|
51580
|
-
async function getRecommendedModels(opts = {}) {
|
|
51581
|
-
const { forceRefresh = false } = opts;
|
|
51582
|
-
if (!forceRefresh && _cachedRecommendedModels) {
|
|
51583
|
-
return _cachedRecommendedModels;
|
|
51584
|
-
}
|
|
51585
|
-
if (!forceRefresh && existsSync21(RECOMMENDED_MODELS_CACHE_PATH)) {
|
|
51586
|
-
try {
|
|
51587
|
-
const cacheData = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
|
|
51588
|
-
if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
|
|
51589
|
-
_cachedRecommendedModels = cacheData;
|
|
51590
|
-
return cacheData;
|
|
51591
|
-
}
|
|
51592
|
-
} catch {}
|
|
51593
|
-
}
|
|
51594
|
-
try {
|
|
51595
|
-
const response = await fetch(FIREBASE_RECOMMENDED_URL, {
|
|
51596
|
-
signal: AbortSignal.timeout(RECOMMENDED_FETCH_TIMEOUT_MS)
|
|
51597
|
-
});
|
|
51598
|
-
if (response.ok) {
|
|
51599
|
-
const data = await response.json();
|
|
51600
|
-
if (data.models && data.models.length > 0) {
|
|
51601
|
-
_cachedRecommendedModels = data;
|
|
51602
|
-
try {
|
|
51603
|
-
const cacheDir = join31(homedir29(), ".claudish");
|
|
51604
|
-
mkdirSync13(cacheDir, { recursive: true });
|
|
51605
|
-
writeFileSync13(RECOMMENDED_MODELS_CACHE_PATH, JSON.stringify(data), "utf-8");
|
|
51606
|
-
} catch {}
|
|
51607
|
-
return data;
|
|
51608
|
-
}
|
|
51609
|
-
}
|
|
51610
|
-
} catch {}
|
|
51611
|
-
throw new Error("Unable to load recommended models: Firebase unreachable and no local cache. " + "Check connectivity.");
|
|
51612
|
-
}
|
|
51613
|
-
function getRecommendedModelsSync() {
|
|
51614
|
-
if (_cachedRecommendedModels)
|
|
51615
|
-
return _cachedRecommendedModels;
|
|
51616
|
-
if (existsSync21(RECOMMENDED_MODELS_CACHE_PATH)) {
|
|
51617
|
-
try {
|
|
51618
|
-
const cacheData = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
|
|
51619
|
-
if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
|
|
51620
|
-
_cachedRecommendedModels = cacheData;
|
|
51621
|
-
return cacheData;
|
|
51622
|
-
}
|
|
51623
|
-
} catch {}
|
|
51624
|
-
}
|
|
51625
|
-
return { version: "0", lastUpdated: "", models: [] };
|
|
51626
|
-
}
|
|
51627
|
-
async function warmRecommendedModels() {
|
|
51628
|
-
try {
|
|
51629
|
-
return await getRecommendedModels({ forceRefresh: true });
|
|
51630
|
-
} catch {
|
|
51631
|
-
return null;
|
|
51632
|
-
}
|
|
51633
|
-
}
|
|
51634
|
-
function isFreshEnough(doc2) {
|
|
51635
|
-
const generatedAt = doc2.generatedAt;
|
|
51636
|
-
if (!generatedAt)
|
|
51637
|
-
return true;
|
|
51638
|
-
const ageHours = (Date.now() - new Date(generatedAt).getTime()) / (1000 * 60 * 60);
|
|
51639
|
-
return ageHours <= FIREBASE_CACHE_TTL_HOURS;
|
|
51640
|
-
}
|
|
51641
|
-
async function searchModels(query, limit = 50) {
|
|
51642
|
-
const url2 = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(query)}&limit=${limit}&status=active`;
|
|
51643
|
-
const response = await fetch(url2, {
|
|
51644
|
-
signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
|
|
51645
|
-
});
|
|
51646
|
-
if (!response.ok) {
|
|
51647
|
-
throw new Error(`Firebase search returned ${response.status} ${response.statusText}`);
|
|
51648
|
-
}
|
|
51649
|
-
const data = await response.json();
|
|
51650
|
-
return data.models ?? [];
|
|
51651
|
-
}
|
|
51652
|
-
async function getModelByIdFromFirebase(modelId) {
|
|
51653
|
-
const url2 = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(modelId)}&limit=5`;
|
|
51654
|
-
const response = await fetch(url2, {
|
|
51655
|
-
signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
|
|
51656
|
-
});
|
|
51657
|
-
if (!response.ok) {
|
|
51658
|
-
throw new Error(`Firebase lookup returned ${response.status} ${response.statusText}`);
|
|
51659
|
-
}
|
|
51660
|
-
const data = await response.json();
|
|
51661
|
-
const models = data.models ?? [];
|
|
51662
|
-
for (const m of models) {
|
|
51663
|
-
if (m.modelId === modelId)
|
|
51664
|
-
return m;
|
|
51665
|
-
if (m.aliases?.includes(modelId))
|
|
51666
|
-
return m;
|
|
51667
|
-
}
|
|
51668
|
-
return null;
|
|
51669
|
-
}
|
|
51670
|
-
async function getTop100Models() {
|
|
51671
|
-
const url2 = `${FIREBASE_BASE_URL}?catalog=top100`;
|
|
51672
|
-
const response = await fetch(url2, {
|
|
51673
|
-
signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
|
|
51674
|
-
});
|
|
51675
|
-
if (!response.ok) {
|
|
51676
|
-
throw new Error(`Firebase top100 fetch failed: ${response.status} ${response.statusText}`);
|
|
51677
|
-
}
|
|
51678
|
-
const data = await response.json();
|
|
51679
|
-
return data;
|
|
51680
|
-
}
|
|
51681
|
-
async function getProviderList() {
|
|
51682
|
-
const url2 = `${FIREBASE_BASE_URL}?catalog=providers`;
|
|
51683
|
-
const response = await fetch(url2, {
|
|
51684
|
-
signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
|
|
51685
|
-
});
|
|
51686
|
-
if (!response.ok) {
|
|
51687
|
-
throw new Error(`Firebase providers fetch failed: ${response.status} ${response.statusText}`);
|
|
51688
|
-
}
|
|
51689
|
-
const data = await response.json();
|
|
51690
|
-
return data.providers ?? [];
|
|
51691
|
-
}
|
|
51692
|
-
async function getModelsByProvider(provider, limit = 200) {
|
|
51693
|
-
const url2 = `${FIREBASE_BASE_URL}?provider=${encodeURIComponent(provider)}&status=active&limit=${limit}`;
|
|
51694
|
-
const response = await fetch(url2, {
|
|
51695
|
-
signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
|
|
51696
|
-
});
|
|
51697
|
-
if (!response.ok) {
|
|
51698
|
-
throw new Error(`Firebase provider query returned ${response.status} ${response.statusText}`);
|
|
51699
|
-
}
|
|
51700
|
-
const data = await response.json();
|
|
51701
|
-
if (Array.isArray(data))
|
|
51702
|
-
return data;
|
|
51703
|
-
return data.models ?? [];
|
|
51704
|
-
}
|
|
51705
|
-
function loadModelInfo() {
|
|
51706
|
-
if (_cachedModelInfo) {
|
|
51707
|
-
return _cachedModelInfo;
|
|
51708
|
-
}
|
|
51709
|
-
const data = getRecommendedModelsSync();
|
|
51710
|
-
const modelInfo = {};
|
|
51711
|
-
for (const model of data.models) {
|
|
51712
|
-
modelInfo[model.id] = {
|
|
51713
|
-
name: model.name,
|
|
51714
|
-
description: model.description,
|
|
51715
|
-
priority: model.priority,
|
|
51716
|
-
provider: model.provider
|
|
51717
|
-
};
|
|
51718
|
-
}
|
|
51719
|
-
modelInfo.custom = {
|
|
51720
|
-
name: "Custom Model",
|
|
51721
|
-
description: "Enter any model ID manually",
|
|
51722
|
-
priority: 999,
|
|
51723
|
-
provider: "Custom"
|
|
51724
|
-
};
|
|
51725
|
-
_cachedModelInfo = modelInfo;
|
|
51726
|
-
return modelInfo;
|
|
51727
|
-
}
|
|
51728
|
-
function getAvailableModels() {
|
|
51729
|
-
if (_cachedModelIds) {
|
|
51730
|
-
return _cachedModelIds;
|
|
51731
|
-
}
|
|
51732
|
-
const data = getRecommendedModelsSync();
|
|
51733
|
-
const modelIds = data.models.sort((a, b) => a.priority - b.priority).map((m) => m.id);
|
|
51734
|
-
const result = [...modelIds, "custom"];
|
|
51735
|
-
_cachedModelIds = result;
|
|
51736
|
-
return result;
|
|
51737
|
-
}
|
|
51738
|
-
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;
|
|
51739
|
-
var init_model_loader = __esm(() => {
|
|
51740
|
-
init_cache_ttl();
|
|
51741
|
-
FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
|
|
51742
|
-
RECOMMENDED_MODELS_CACHE_PATH = join31(homedir29(), ".claudish", "recommended-models-cache.json");
|
|
51743
|
-
FIREBASE_SLUG_TO_PROVIDER_NAME = {
|
|
51744
|
-
openai: "openai",
|
|
51745
|
-
google: "google",
|
|
51746
|
-
"x-ai": "x-ai",
|
|
51747
|
-
"z-ai": "z-ai",
|
|
51748
|
-
moonshotai: "kimi",
|
|
51749
|
-
minimax: "minimax",
|
|
51750
|
-
qwen: "qwen",
|
|
51751
|
-
deepseek: "deepseek",
|
|
51752
|
-
mistralai: "mistralai",
|
|
51753
|
-
sakana: "sakana"
|
|
51754
|
-
};
|
|
51755
|
-
});
|
|
51756
|
-
|
|
51757
51865
|
// src/port-manager.ts
|
|
51758
51866
|
var exports_port_manager = {};
|
|
51759
51867
|
__export(exports_port_manager, {
|
|
@@ -56062,6 +56170,12 @@ ${plan.hint}` : `[Route] ${plan.reason}`;
|
|
|
56062
56170
|
};
|
|
56063
56171
|
const app = new Hono2;
|
|
56064
56172
|
app.use("*", cors());
|
|
56173
|
+
let modelRequestCount = 0;
|
|
56174
|
+
app.use("*", async (c, next) => {
|
|
56175
|
+
if (c.req.path === "/v1/messages")
|
|
56176
|
+
modelRequestCount++;
|
|
56177
|
+
await next();
|
|
56178
|
+
});
|
|
56065
56179
|
app.onError((err, c) => {
|
|
56066
56180
|
logStderr(`[Proxy] Unhandled error on ${c.req.method} ${c.req.path}: ${err?.message ?? err}`);
|
|
56067
56181
|
log(`[Proxy] Unhandled error stack: ${err?.stack ?? "(no stack)"}`);
|
|
@@ -56194,6 +56308,7 @@ ${plan.hint}` : `[Route] ${plan.reason}`;
|
|
|
56194
56308
|
return {
|
|
56195
56309
|
port: resolvedPort,
|
|
56196
56310
|
url: `http://127.0.0.1:${resolvedPort}`,
|
|
56311
|
+
modelRequestCount: () => modelRequestCount,
|
|
56197
56312
|
shutdown: async () => {
|
|
56198
56313
|
await server.stop(true);
|
|
56199
56314
|
},
|
|
@@ -85631,12 +85746,16 @@ Or set CLAUDE_PATH to your custom installation:`);
|
|
|
85631
85746
|
});
|
|
85632
85747
|
}
|
|
85633
85748
|
setupSignalHandlers(proc, tempSettingsPath, config3.quiet, onCleanup);
|
|
85634
|
-
const exitCode = await new Promise((resolve6) => {
|
|
85635
|
-
proc.on("exit", (code) => {
|
|
85749
|
+
const { exitCode, exitSignal } = await new Promise((resolve6) => {
|
|
85750
|
+
proc.on("exit", (code, signal) => {
|
|
85636
85751
|
setClaudeCodeRunning(false);
|
|
85637
|
-
resolve6(
|
|
85752
|
+
resolve6({
|
|
85753
|
+
exitCode: signal ? 128 + (SIGNAL_EXIT_NUMBERS[signal] ?? 0) : code ?? 1,
|
|
85754
|
+
exitSignal: signal
|
|
85755
|
+
});
|
|
85638
85756
|
});
|
|
85639
85757
|
});
|
|
85758
|
+
log(exitSignal ? `[Claude Code] Exited from ${exitSignal} (exit code ${exitCode})` : `[Claude Code] Exited with code ${exitCode}`);
|
|
85640
85759
|
releaseTerminalIsolation();
|
|
85641
85760
|
try {
|
|
85642
85761
|
unlinkSync10(tempSettingsPath);
|
|
@@ -89011,9 +89130,15 @@ Team Status`);
|
|
|
89011
89130
|
}
|
|
89012
89131
|
}
|
|
89013
89132
|
const sessionLogPath = getAlwaysOnLogPath2();
|
|
89014
|
-
|
|
89133
|
+
const quitBySignal = exitCode === 130 || exitCode === 143;
|
|
89134
|
+
if (exitCode !== 0 && !quitBySignal && sessionLogPath && !cliConfig.quiet) {
|
|
89015
89135
|
console.error(`
|
|
89016
|
-
[claudish] Session ended with errors
|
|
89136
|
+
[claudish] Session ended with errors (exit code ${exitCode}).`);
|
|
89137
|
+
if (proxy.modelRequestCount() === 0) {
|
|
89138
|
+
console.error("[claudish] Claude Code exited before sending any model request, so the fault is on its side, not the model's.");
|
|
89139
|
+
console.error(`[claudish] Run \`claude\` in ${process.cwd()} to see its own error.`);
|
|
89140
|
+
}
|
|
89141
|
+
console.error(`[claudish] Log: ${sessionLogPath}`);
|
|
89017
89142
|
console.error(`[claudish] To review: /debug-logs ${sessionLogPath}`);
|
|
89018
89143
|
}
|
|
89019
89144
|
process.exit(exitCode);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudish",
|
|
3
|
-
"version": "9.0.
|
|
3
|
+
"version": "9.0.2",
|
|
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.
|
|
64
|
-
"@claudish/magmux-darwin-x64": "9.0.
|
|
65
|
-
"@claudish/magmux-linux-arm64": "9.0.
|
|
66
|
-
"@claudish/magmux-linux-x64": "9.0.
|
|
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"
|
|
67
67
|
},
|
|
68
68
|
"author": "Jack Rudenko <i@madappgang.com>",
|
|
69
69
|
"license": "MIT",
|