claudish 8.1.0 → 9.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +583 -410
- 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 = "
|
|
734
|
+
var VERSION = "9.0.1";
|
|
735
735
|
|
|
736
736
|
// src/logger.ts
|
|
737
737
|
var exports_logger = {};
|
|
@@ -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;
|
|
@@ -28305,17 +28327,24 @@ var init_runtime_providers = __esm(() => {
|
|
|
28305
28327
|
});
|
|
28306
28328
|
|
|
28307
28329
|
// src/handlers/shared/remote-provider-types.ts
|
|
28330
|
+
function registerSubscriptionCredentialProbe(fn) {
|
|
28331
|
+
const previous = _subscriptionCredentialProbe;
|
|
28332
|
+
_subscriptionCredentialProbe = fn;
|
|
28333
|
+
return previous;
|
|
28334
|
+
}
|
|
28308
28335
|
function isSubscriptionProvider(provider) {
|
|
28309
|
-
|
|
28336
|
+
const p = provider.toLowerCase();
|
|
28337
|
+
if (SUBSCRIPTION_PROVIDERS.has(p))
|
|
28338
|
+
return true;
|
|
28339
|
+
if (!CREDENTIAL_DECIDED_PROVIDERS.has(p))
|
|
28340
|
+
return false;
|
|
28341
|
+
return _subscriptionCredentialProbe?.(p) === true;
|
|
28310
28342
|
}
|
|
28311
28343
|
function registerDynamicPricingLookup(fn) {
|
|
28312
28344
|
_dynamicLookup = fn;
|
|
28313
28345
|
}
|
|
28314
28346
|
function getModelPricing(provider, modelName) {
|
|
28315
28347
|
const p = provider.toLowerCase();
|
|
28316
|
-
if (FREE_PROVIDERS.has(p)) {
|
|
28317
|
-
return { inputCostPer1M: 0, outputCostPer1M: 0, isFree: true };
|
|
28318
|
-
}
|
|
28319
28348
|
if (isSubscriptionProvider(p)) {
|
|
28320
28349
|
return { inputCostPer1M: 0, outputCostPer1M: 0, isSubscription: true };
|
|
28321
28350
|
}
|
|
@@ -28327,7 +28356,7 @@ function getModelPricing(provider, modelName) {
|
|
|
28327
28356
|
const canonical = PROVIDER_ALIAS[p] || p;
|
|
28328
28357
|
return PROVIDER_DEFAULTS[canonical] || { inputCostPer1M: 1, outputCostPer1M: 4, isEstimate: true };
|
|
28329
28358
|
}
|
|
28330
|
-
var PROVIDER_DEFAULTS,
|
|
28359
|
+
var PROVIDER_DEFAULTS, SUBSCRIPTION_PROVIDERS, CREDENTIAL_DECIDED_PROVIDERS, _subscriptionCredentialProbe = null, PROVIDER_ALIAS, _dynamicLookup = null;
|
|
28331
28360
|
var init_remote_provider_types = __esm(() => {
|
|
28332
28361
|
PROVIDER_DEFAULTS = {
|
|
28333
28362
|
gemini: { inputCostPer1M: 0.5, outputCostPer1M: 2, isEstimate: true },
|
|
@@ -28337,7 +28366,6 @@ var init_remote_provider_types = __esm(() => {
|
|
|
28337
28366
|
glm: { inputCostPer1M: 0.16, outputCostPer1M: 0.8, isEstimate: true },
|
|
28338
28367
|
ollamacloud: { inputCostPer1M: 1, outputCostPer1M: 4, isEstimate: true }
|
|
28339
28368
|
};
|
|
28340
|
-
FREE_PROVIDERS = new Set(["opencode-zen", "zen"]);
|
|
28341
28369
|
SUBSCRIPTION_PROVIDERS = new Set([
|
|
28342
28370
|
"minimax-coding",
|
|
28343
28371
|
"kimi-coding",
|
|
@@ -28346,8 +28374,10 @@ var init_remote_provider_types = __esm(() => {
|
|
|
28346
28374
|
"devin",
|
|
28347
28375
|
"antigravity",
|
|
28348
28376
|
"sakana-subscription",
|
|
28349
|
-
"grok-subscription"
|
|
28377
|
+
"grok-subscription",
|
|
28378
|
+
"opencode-zen-go"
|
|
28350
28379
|
]);
|
|
28380
|
+
CREDENTIAL_DECIDED_PROVIDERS = new Set(["openai-codex"]);
|
|
28351
28381
|
PROVIDER_ALIAS = {
|
|
28352
28382
|
google: "gemini",
|
|
28353
28383
|
oai: "openai",
|
|
@@ -36548,7 +36578,7 @@ class ApiKeyCredentialProvider {
|
|
|
36548
36578
|
} else {
|
|
36549
36579
|
headers = { ...this.staticHeaders };
|
|
36550
36580
|
}
|
|
36551
|
-
return { headers };
|
|
36581
|
+
return { arm: "api-key", headers };
|
|
36552
36582
|
}
|
|
36553
36583
|
}
|
|
36554
36584
|
var init_api_key_credential = __esm(() => {
|
|
@@ -36927,6 +36957,34 @@ var init_codex_oauth = __esm(() => {
|
|
|
36927
36957
|
};
|
|
36928
36958
|
});
|
|
36929
36959
|
|
|
36960
|
+
// src/auth/credentials/billing-probe.ts
|
|
36961
|
+
function recordSignedArm(provider, arm) {
|
|
36962
|
+
signedArm.set(provider.toLowerCase(), arm);
|
|
36963
|
+
}
|
|
36964
|
+
function clearSignedArm(provider) {
|
|
36965
|
+
if (provider)
|
|
36966
|
+
signedArm.delete(provider.toLowerCase());
|
|
36967
|
+
else
|
|
36968
|
+
signedArm.clear();
|
|
36969
|
+
}
|
|
36970
|
+
function installBillingProbes() {
|
|
36971
|
+
return registerSubscriptionCredentialProbe((p) => {
|
|
36972
|
+
const recorded = signedArm.get(p);
|
|
36973
|
+
if (recorded)
|
|
36974
|
+
return recorded === "subscription";
|
|
36975
|
+
return PROBES[p]?.() === true;
|
|
36976
|
+
});
|
|
36977
|
+
}
|
|
36978
|
+
var signedArm, PROBES;
|
|
36979
|
+
var init_billing_probe = __esm(() => {
|
|
36980
|
+
init_remote_provider_types();
|
|
36981
|
+
init_codex_oauth();
|
|
36982
|
+
signedArm = new Map;
|
|
36983
|
+
PROBES = {
|
|
36984
|
+
"openai-codex": () => CodexOAuth.getInstance().hasCredentials()
|
|
36985
|
+
};
|
|
36986
|
+
});
|
|
36987
|
+
|
|
36930
36988
|
// src/auth/credentials/composite-credential.ts
|
|
36931
36989
|
class CompositeCredentialProvider {
|
|
36932
36990
|
catalogName;
|
|
@@ -36994,6 +37052,7 @@ class CodexOAuthHalf {
|
|
|
36994
37052
|
const token = await this.oauth.getAccessToken();
|
|
36995
37053
|
const accountId = this.oauth.getAccountId();
|
|
36996
37054
|
return {
|
|
37055
|
+
arm: "oauth",
|
|
36997
37056
|
headers: buildOAuthHeaders(token, accountId),
|
|
36998
37057
|
endpoint: CODEX_RESPONSES_ENDPOINT,
|
|
36999
37058
|
transformPayload: (p) => ({
|
|
@@ -37483,6 +37542,17 @@ var init_kimi_oauth = __esm(() => {
|
|
|
37483
37542
|
import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
|
|
37484
37543
|
import { homedir as homedir22 } from "os";
|
|
37485
37544
|
import { join as join22 } from "path";
|
|
37545
|
+
function credentialSatisfies(descriptor, data) {
|
|
37546
|
+
if (!data?.access_token)
|
|
37547
|
+
return false;
|
|
37548
|
+
if (data.refresh_token)
|
|
37549
|
+
return true;
|
|
37550
|
+
if (descriptor.expiresAtField && data[descriptor.expiresAtField]) {
|
|
37551
|
+
const buffer = descriptor.expiryBufferMs ?? 0;
|
|
37552
|
+
return data[descriptor.expiresAtField] > Date.now() + buffer;
|
|
37553
|
+
}
|
|
37554
|
+
return true;
|
|
37555
|
+
}
|
|
37486
37556
|
function hasValidOAuthCredentials(descriptor) {
|
|
37487
37557
|
const credPath = join22(homedir22(), ".claudish", descriptor.credentialFile);
|
|
37488
37558
|
if (!existsSync15(credPath))
|
|
@@ -37491,16 +37561,7 @@ function hasValidOAuthCredentials(descriptor) {
|
|
|
37491
37561
|
return true;
|
|
37492
37562
|
}
|
|
37493
37563
|
try {
|
|
37494
|
-
|
|
37495
|
-
if (!data.access_token)
|
|
37496
|
-
return false;
|
|
37497
|
-
if (data.refresh_token)
|
|
37498
|
-
return true;
|
|
37499
|
-
if (descriptor.expiresAtField && data[descriptor.expiresAtField]) {
|
|
37500
|
-
const buffer = descriptor.expiryBufferMs ?? 0;
|
|
37501
|
-
return data[descriptor.expiresAtField] > Date.now() + buffer;
|
|
37502
|
-
}
|
|
37503
|
-
return true;
|
|
37564
|
+
return credentialSatisfies(descriptor, JSON.parse(readFileSync14(credPath, "utf-8")));
|
|
37504
37565
|
} catch {
|
|
37505
37566
|
return false;
|
|
37506
37567
|
}
|
|
@@ -37551,6 +37612,7 @@ class KimiOAuthHalf {
|
|
|
37551
37612
|
async getRequestAuth(_ctx) {
|
|
37552
37613
|
const token = await this.oauth.getAccessToken();
|
|
37553
37614
|
return {
|
|
37615
|
+
arm: "oauth",
|
|
37554
37616
|
headers: {
|
|
37555
37617
|
"anthropic-version": "2023-06-01",
|
|
37556
37618
|
Authorization: `Bearer ${token}`,
|
|
@@ -37750,6 +37812,7 @@ class CredentialAuthority {
|
|
|
37750
37812
|
return p.getRequestAuth(ctx);
|
|
37751
37813
|
}
|
|
37752
37814
|
invalidate(name) {
|
|
37815
|
+
clearSignedArm(name);
|
|
37753
37816
|
if (name) {
|
|
37754
37817
|
this.registry.get(name)?.invalidate?.();
|
|
37755
37818
|
return;
|
|
@@ -37764,9 +37827,11 @@ class CredentialAuthority {
|
|
|
37764
37827
|
}
|
|
37765
37828
|
async login(name) {
|
|
37766
37829
|
await this.registry.get(name)?.login?.();
|
|
37830
|
+
clearSignedArm(name);
|
|
37767
37831
|
}
|
|
37768
37832
|
async logout(name) {
|
|
37769
37833
|
await this.registry.get(name)?.logout?.();
|
|
37834
|
+
clearSignedArm(name);
|
|
37770
37835
|
}
|
|
37771
37836
|
get(name) {
|
|
37772
37837
|
return this.registry.get(name);
|
|
@@ -37817,6 +37882,7 @@ var init_authority = __esm(() => {
|
|
|
37817
37882
|
init_provider_definitions();
|
|
37818
37883
|
init_antigravity_credential();
|
|
37819
37884
|
init_api_key_credential();
|
|
37885
|
+
init_billing_probe();
|
|
37820
37886
|
init_codex_credential();
|
|
37821
37887
|
init_devin_credential();
|
|
37822
37888
|
init_grok_credential();
|
|
@@ -37829,6 +37895,7 @@ var init_authority = __esm(() => {
|
|
|
37829
37895
|
google: ["gemini"]
|
|
37830
37896
|
};
|
|
37831
37897
|
credentials = CredentialAuthority.buildDefault();
|
|
37898
|
+
installBillingProbes();
|
|
37832
37899
|
});
|
|
37833
37900
|
|
|
37834
37901
|
// src/providers/devin/proto-codec.ts
|
|
@@ -44976,6 +45043,7 @@ var init_openai_codex = __esm(() => {
|
|
|
44976
45043
|
init_codex_api_format();
|
|
44977
45044
|
init_model_catalog();
|
|
44978
45045
|
init_authority();
|
|
45046
|
+
init_billing_probe();
|
|
44979
45047
|
init_harness();
|
|
44980
45048
|
init_openai();
|
|
44981
45049
|
FALLBACK_CONVERSATION_KEY = randomBytes6(16).toString("hex");
|
|
@@ -44989,6 +45057,8 @@ var init_openai_codex = __esm(() => {
|
|
|
44989
45057
|
} catch {
|
|
44990
45058
|
this.cachedAuth = null;
|
|
44991
45059
|
}
|
|
45060
|
+
const signedWithOAuth = this.cachedAuth?.arm === "oauth";
|
|
45061
|
+
recordSignedArm("openai-codex", signedWithOAuth ? "subscription" : "metered");
|
|
44992
45062
|
}
|
|
44993
45063
|
getEndpoint(_targetModel) {
|
|
44994
45064
|
return this.cachedAuth?.endpoint ?? super.getEndpoint();
|
|
@@ -45477,16 +45547,28 @@ function describeMissingCredential(providerName) {
|
|
|
45477
45547
|
const keyNames = info?.envVar ? [info.envVar, ...info.aliases ?? []].join(" or ") : undefined;
|
|
45478
45548
|
const signup = info?.url ? ` Get one at ${info.url}.` : "";
|
|
45479
45549
|
const def = getProviderByName(providerName);
|
|
45550
|
+
const sibling = describeSiblingKeys(def);
|
|
45480
45551
|
if (isLocalTransport(providerName)) {
|
|
45481
45552
|
const where = def ? ` Claudish will use ${getEffectiveBaseUrl(def)}.` : "";
|
|
45482
45553
|
const keyClause = keyNames ? ` (Only set ${keyNames} if your local server requires a bearer token.)` : "";
|
|
45483
|
-
return `Provider "${providerName}" is a LOCAL server and is not enabled. Enable it in \`claudish config\` (Providers tab), or add "localProviders": ["${providerName}"] to ~/.claudish/config.json.${where}${keyClause}`;
|
|
45554
|
+
return `Provider "${providerName}" is a LOCAL server and is not enabled. Enable it in \`claudish config\` (Providers tab), or add "localProviders": ["${providerName}"] to ~/.claudish/config.json.${where}${keyClause}${sibling}`;
|
|
45484
45555
|
}
|
|
45485
45556
|
if (def?.oauthFallback) {
|
|
45486
45557
|
const keyClause = keyNames ? ` Or set ${keyNames} (env, config, or 1Password import) to use a metered API key instead.${signup}` : "";
|
|
45487
|
-
return `No credential for provider "${providerName}". Sign in with \`claudish login ${providerName}\` to use your existing subscription.${keyClause}`;
|
|
45558
|
+
return `No credential for provider "${providerName}". Sign in with \`claudish login ${providerName}\` to use your existing subscription.${keyClause}${sibling}`;
|
|
45488
45559
|
}
|
|
45489
|
-
return keyNames ? `No API key for provider "${providerName}". Set ${keyNames} (env, config, or 1Password import).${signup}` : `No API key for provider "${providerName}"
|
|
45560
|
+
return keyNames ? `No API key for provider "${providerName}". Set ${keyNames} (env, config, or 1Password import).${signup}${sibling}` : `No API key for provider "${providerName}".${sibling}`;
|
|
45561
|
+
}
|
|
45562
|
+
function describeSiblingKeys(def) {
|
|
45563
|
+
const vars = def?.siblingKeyEnvVars ?? [];
|
|
45564
|
+
if (vars.length === 0)
|
|
45565
|
+
return "";
|
|
45566
|
+
const all = getAllProviders();
|
|
45567
|
+
const named = vars.map((v) => {
|
|
45568
|
+
const owner = all.find((p) => p.name !== def?.name && p.apiKeyEnvVar === v);
|
|
45569
|
+
return owner ? `${v} (${owner.name})` : v;
|
|
45570
|
+
});
|
|
45571
|
+
return ` Note: ${named.join(" or ")} is a DIFFERENT plan's key and is not accepted here.`;
|
|
45490
45572
|
}
|
|
45491
45573
|
function getDisplayName(providerName) {
|
|
45492
45574
|
const def = getProviderByName(providerName);
|
|
@@ -45952,7 +46034,7 @@ var init_provider_definitions = __esm(() => {
|
|
|
45952
46034
|
apiPath: "/v1/chat/completions",
|
|
45953
46035
|
modelDiscovery: { path: "/v1/models", format: "openai-models-list" },
|
|
45954
46036
|
apiKeyEnvVar: "OPENCODE_GO_API_KEY",
|
|
45955
|
-
|
|
46037
|
+
siblingKeyEnvVars: ["OPENCODE_API_KEY"],
|
|
45956
46038
|
apiKeyDescription: "OpenCode Zen Go (Lite Plan) API Key",
|
|
45957
46039
|
apiKeyUrl: "https://opencode.ai/",
|
|
45958
46040
|
shortcuts: ["zengo", "zgo"],
|
|
@@ -46288,6 +46370,16 @@ var init_auto_route = __esm(() => {
|
|
|
46288
46370
|
});
|
|
46289
46371
|
|
|
46290
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
|
+
}
|
|
46291
46383
|
function getCatalogEntries() {
|
|
46292
46384
|
if (_catalogEntriesForTest !== undefined)
|
|
46293
46385
|
return _catalogEntriesForTest;
|
|
@@ -46421,6 +46513,7 @@ function logResolution(userInput, result, quiet = false) {
|
|
|
46421
46513
|
}
|
|
46422
46514
|
}
|
|
46423
46515
|
async function refreshCatalog(timeoutMs) {
|
|
46516
|
+
const plansPromise = fetchSubscriptionPlans(timeoutMs);
|
|
46424
46517
|
let response;
|
|
46425
46518
|
try {
|
|
46426
46519
|
response = await fetch(FIREBASE_CATALOG_URL, { signal: AbortSignal.timeout(timeoutMs) });
|
|
@@ -46447,10 +46540,28 @@ async function refreshCatalog(timeoutMs) {
|
|
|
46447
46540
|
backwardCompatModels.push({ id });
|
|
46448
46541
|
}
|
|
46449
46542
|
_memCache = data.models;
|
|
46450
|
-
|
|
46543
|
+
const plans = await plansPromise;
|
|
46544
|
+
writeAllModelsCache({
|
|
46545
|
+
entries: data.models,
|
|
46546
|
+
models: backwardCompatModels,
|
|
46547
|
+
...plans !== undefined ? { plans } : {}
|
|
46548
|
+
});
|
|
46451
46549
|
_warmPromise = Promise.resolve();
|
|
46452
46550
|
return { kind: "refreshed", modelCount: data.models.length };
|
|
46453
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
|
+
}
|
|
46454
46565
|
async function warmCatalog() {
|
|
46455
46566
|
if (!_warmPromise) {
|
|
46456
46567
|
_warmPromise = refreshCatalog(8000).then(() => {
|
|
@@ -46472,10 +46583,11 @@ async function ensureCatalogReady(timeoutMs = 5000) {
|
|
|
46472
46583
|
new Promise((resolve3) => setTimeout(resolve3, timeoutMs))
|
|
46473
46584
|
]);
|
|
46474
46585
|
}
|
|
46475
|
-
var FIREBASE_CATALOG_URL, _memCache = null, _catalogEntriesForTest, _warmPromise = null;
|
|
46586
|
+
var FIREBASE_CATALOG_URL, FIREBASE_PLANS_URL, _memCache = null, _catalogEntriesForTest, _warmPromise = null;
|
|
46476
46587
|
var init_catalog_client = __esm(() => {
|
|
46477
46588
|
init_all_models_cache();
|
|
46478
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);
|
|
46479
46591
|
});
|
|
46480
46592
|
|
|
46481
46593
|
// src/config-schema.ts
|
|
@@ -47568,7 +47680,351 @@ var init_routing_hints = __esm(() => {
|
|
|
47568
47680
|
openrouter: { apiKeyEnvVar: "OPENROUTER_API_KEY" },
|
|
47569
47681
|
"x-ai": { apiKeyEnvVar: "XAI_API_KEY" },
|
|
47570
47682
|
"z-ai": { apiKeyEnvVar: "ZAI_API_KEY" },
|
|
47571
|
-
"opencode-zen": { apiKeyEnvVar: "OPENCODE_API_KEY" }
|
|
47683
|
+
"opencode-zen": { apiKeyEnvVar: "OPENCODE_API_KEY" },
|
|
47684
|
+
"opencode-zen-go": { apiKeyEnvVar: "OPENCODE_GO_API_KEY" }
|
|
47685
|
+
};
|
|
47686
|
+
});
|
|
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
|
|
47572
48028
|
};
|
|
47573
48029
|
});
|
|
47574
48030
|
|
|
@@ -47668,7 +48124,21 @@ function loadRoutingRules() {
|
|
|
47668
48124
|
const global_ = loadConfig().routing ?? {};
|
|
47669
48125
|
validateRoutingRules(local);
|
|
47670
48126
|
validateRoutingRules(global_);
|
|
47671
|
-
|
|
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;
|
|
47672
48142
|
}
|
|
47673
48143
|
function validateRoutingRules(rules) {
|
|
47674
48144
|
const seenLower = new Map;
|
|
@@ -47863,6 +48333,7 @@ var init_routing_rules = __esm(() => {
|
|
|
47863
48333
|
init_authority();
|
|
47864
48334
|
init_remote_provider_types();
|
|
47865
48335
|
init_logger();
|
|
48336
|
+
init_model_loader();
|
|
47866
48337
|
init_profile_config();
|
|
47867
48338
|
init_auto_route();
|
|
47868
48339
|
init_catalog_client();
|
|
@@ -47870,6 +48341,7 @@ var init_routing_rules = __esm(() => {
|
|
|
47870
48341
|
init_model_availability();
|
|
47871
48342
|
init_model_parser();
|
|
47872
48343
|
init_model_parser();
|
|
48344
|
+
init_provider_definitions();
|
|
47873
48345
|
init_routing_hints();
|
|
47874
48346
|
});
|
|
47875
48347
|
|
|
@@ -49005,8 +49477,8 @@ __export(exports_session_discovery, {
|
|
|
49005
49477
|
});
|
|
49006
49478
|
import { execFile, execFileSync as execFileSync2 } from "child_process";
|
|
49007
49479
|
import { closeSync as closeSync6, openSync as openSync6, readSync as readSync2, readdirSync as readdirSync4, realpathSync, statSync as statSync5 } from "fs";
|
|
49008
|
-
import { homedir as
|
|
49009
|
-
import { basename, join as
|
|
49480
|
+
import { homedir as homedir28 } from "os";
|
|
49481
|
+
import { basename, join as join28 } from "path";
|
|
49010
49482
|
function slugForPath(absPath) {
|
|
49011
49483
|
return absPath.replace(/[/.]/g, "-");
|
|
49012
49484
|
}
|
|
@@ -49015,7 +49487,7 @@ function transcriptPathFor(cwd, sessionUuid) {
|
|
|
49015
49487
|
try {
|
|
49016
49488
|
real = realpathSync(cwd);
|
|
49017
49489
|
} catch {}
|
|
49018
|
-
return
|
|
49490
|
+
return join28(PROJECTS_DIR, slugForPath(real), `${sessionUuid}.jsonl`);
|
|
49019
49491
|
}
|
|
49020
49492
|
function isAgentSession(row) {
|
|
49021
49493
|
return row.entrypoint !== undefined && row.entrypoint !== "cli";
|
|
@@ -49062,7 +49534,7 @@ function projectDirs() {
|
|
|
49062
49534
|
}
|
|
49063
49535
|
}
|
|
49064
49536
|
function sessionsIn(dirName) {
|
|
49065
|
-
const dir =
|
|
49537
|
+
const dir = join28(PROJECTS_DIR, dirName);
|
|
49066
49538
|
let names;
|
|
49067
49539
|
try {
|
|
49068
49540
|
names = readdirSync4(dir).filter((n) => n.endsWith(".jsonl"));
|
|
@@ -49071,7 +49543,7 @@ function sessionsIn(dirName) {
|
|
|
49071
49543
|
}
|
|
49072
49544
|
const rows = [];
|
|
49073
49545
|
for (const n of names) {
|
|
49074
|
-
const file2 =
|
|
49546
|
+
const file2 = join28(dir, n);
|
|
49075
49547
|
try {
|
|
49076
49548
|
const st = statSync5(file2);
|
|
49077
49549
|
if (st.size === 0)
|
|
@@ -49430,7 +49902,7 @@ function findLatestSessionId(cwd = process.cwd(), sinceMs = 0) {
|
|
|
49430
49902
|
}
|
|
49431
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;
|
|
49432
49904
|
var init_session_discovery = __esm(() => {
|
|
49433
|
-
PROJECTS_DIR =
|
|
49905
|
+
PROJECTS_DIR = join28(homedir28(), ".claude", "projects");
|
|
49434
49906
|
HEAD_BYTES = 64 * 1024;
|
|
49435
49907
|
TAIL_BYTES = 128 * 1024;
|
|
49436
49908
|
HARNESS_ENVELOPES = [
|
|
@@ -49465,19 +49937,19 @@ function newStdioDecoder() {
|
|
|
49465
49937
|
var init_stdio_decode = () => {};
|
|
49466
49938
|
|
|
49467
49939
|
// src/team-stats.ts
|
|
49468
|
-
import { existsSync as
|
|
49469
|
-
import { join as
|
|
49940
|
+
import { existsSync as existsSync20, readFileSync as readFileSync19, writeFileSync as writeFileSync11 } from "fs";
|
|
49941
|
+
import { join as join29 } from "path";
|
|
49470
49942
|
function statsDir(sessionPath) {
|
|
49471
|
-
return
|
|
49943
|
+
return join29(sessionPath, "stats");
|
|
49472
49944
|
}
|
|
49473
49945
|
function tokenFileFor(sessionPath, anonId) {
|
|
49474
|
-
return
|
|
49946
|
+
return join29(statsDir(sessionPath), `${anonId}.json`);
|
|
49475
49947
|
}
|
|
49476
49948
|
function readTokenStatsAt(path) {
|
|
49477
|
-
if (!
|
|
49949
|
+
if (!existsSync20(path))
|
|
49478
49950
|
return null;
|
|
49479
49951
|
try {
|
|
49480
|
-
return JSON.parse(
|
|
49952
|
+
return JSON.parse(readFileSync19(path, "utf-8"));
|
|
49481
49953
|
} catch {
|
|
49482
49954
|
return null;
|
|
49483
49955
|
}
|
|
@@ -49628,7 +50100,7 @@ ${segs.join(" \xB7 ")}`;
|
|
|
49628
50100
|
}
|
|
49629
50101
|
function writeStatusFile(sessionPath, manifest, status, opts) {
|
|
49630
50102
|
try {
|
|
49631
|
-
|
|
50103
|
+
writeFileSync11(join29(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
|
|
49632
50104
|
`, "utf-8");
|
|
49633
50105
|
} catch {}
|
|
49634
50106
|
}
|
|
@@ -49663,13 +50135,13 @@ __export(exports_team_orchestrator, {
|
|
|
49663
50135
|
import { spawn as spawn2 } from "child_process";
|
|
49664
50136
|
import {
|
|
49665
50137
|
createWriteStream,
|
|
49666
|
-
existsSync as
|
|
49667
|
-
mkdirSync as
|
|
49668
|
-
readFileSync as
|
|
50138
|
+
existsSync as existsSync21,
|
|
50139
|
+
mkdirSync as mkdirSync12,
|
|
50140
|
+
readFileSync as readFileSync20,
|
|
49669
50141
|
readdirSync as readdirSync5,
|
|
49670
|
-
writeFileSync as
|
|
50142
|
+
writeFileSync as writeFileSync12
|
|
49671
50143
|
} from "fs";
|
|
49672
|
-
import { basename as basename2, join as
|
|
50144
|
+
import { basename as basename2, join as join30, resolve as resolve3 } from "path";
|
|
49673
50145
|
function resolveCaptureMode(explicit, env = process.env) {
|
|
49674
50146
|
if (explicit)
|
|
49675
50147
|
return explicit;
|
|
@@ -49787,7 +50259,7 @@ function persistErrorLog(errorLogPath, header, stderr, stdoutTail) {
|
|
|
49787
50259
|
parts.push("--- stderr ---", stderr.trim() ? redactSecrets(stderr) : "(empty)", "");
|
|
49788
50260
|
parts.push("--- stdout (tail) ---", stdoutTail.trim() ? redactSecrets(stdoutTail) : "(empty)", "");
|
|
49789
50261
|
try {
|
|
49790
|
-
|
|
50262
|
+
writeFileSync12(errorLogPath, parts.join(`
|
|
49791
50263
|
`), "utf-8");
|
|
49792
50264
|
} catch {}
|
|
49793
50265
|
}
|
|
@@ -49805,10 +50277,10 @@ function readTeamInputFile(inputPath) {
|
|
|
49805
50277
|
if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
|
|
49806
50278
|
throw new Error(`Input file must be within current directory: ${inputPath}`);
|
|
49807
50279
|
}
|
|
49808
|
-
if (!
|
|
50280
|
+
if (!existsSync21(resolved)) {
|
|
49809
50281
|
throw new Error(`Input file not found: ${resolved}`);
|
|
49810
50282
|
}
|
|
49811
|
-
const text =
|
|
50283
|
+
const text = readFileSync20(resolved, "utf-8");
|
|
49812
50284
|
if (text.trim().length === 0) {
|
|
49813
50285
|
throw new Error(`Input file is empty: ${resolved}`);
|
|
49814
50286
|
}
|
|
@@ -49818,14 +50290,14 @@ function setupSession(sessionPath, models, input) {
|
|
|
49818
50290
|
if (models.length === 0) {
|
|
49819
50291
|
throw new Error("At least one model is required");
|
|
49820
50292
|
}
|
|
49821
|
-
if (
|
|
50293
|
+
if (existsSync21(join30(sessionPath, "manifest.json"))) {
|
|
49822
50294
|
throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
|
|
49823
50295
|
}
|
|
49824
|
-
|
|
49825
|
-
|
|
50296
|
+
mkdirSync12(join30(sessionPath, "work"), { recursive: true });
|
|
50297
|
+
mkdirSync12(join30(sessionPath, "errors"), { recursive: true });
|
|
49826
50298
|
if (input !== undefined) {
|
|
49827
|
-
|
|
49828
|
-
} else if (!
|
|
50299
|
+
writeFileSync12(join30(sessionPath, "input.md"), input, "utf-8");
|
|
50300
|
+
} else if (!existsSync21(join30(sessionPath, "input.md"))) {
|
|
49829
50301
|
throw new Error(`No input.md found at ${sessionPath} and no input provided`);
|
|
49830
50302
|
}
|
|
49831
50303
|
const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
|
|
@@ -49842,9 +50314,9 @@ function setupSession(sessionPath, models, input) {
|
|
|
49842
50314
|
model: models[i],
|
|
49843
50315
|
assignedAt: now2
|
|
49844
50316
|
};
|
|
49845
|
-
|
|
50317
|
+
mkdirSync12(join30(sessionPath, "work", anonId), { recursive: true });
|
|
49846
50318
|
}
|
|
49847
|
-
|
|
50319
|
+
writeFileSync12(join30(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
49848
50320
|
const status = {
|
|
49849
50321
|
startedAt: now2,
|
|
49850
50322
|
models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
|
|
@@ -49858,7 +50330,7 @@ function setupSession(sessionPath, models, input) {
|
|
|
49858
50330
|
}
|
|
49859
50331
|
]))
|
|
49860
50332
|
};
|
|
49861
|
-
|
|
50333
|
+
writeFileSync12(join30(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
|
|
49862
50334
|
return manifest;
|
|
49863
50335
|
}
|
|
49864
50336
|
function assertValidRequirePattern(pattern) {
|
|
@@ -49875,22 +50347,22 @@ function readFullOutputIfNeeded(opts) {
|
|
|
49875
50347
|
if (crashed || !requirePattern || outputSize <= STDOUT_TAIL_LIMIT)
|
|
49876
50348
|
return;
|
|
49877
50349
|
try {
|
|
49878
|
-
return
|
|
50350
|
+
return readFileSync20(outputPath, "utf-8");
|
|
49879
50351
|
} catch {
|
|
49880
50352
|
return;
|
|
49881
50353
|
}
|
|
49882
50354
|
}
|
|
49883
50355
|
async function startModels(sessionPath, opts = {}) {
|
|
49884
50356
|
assertValidRequirePattern(opts.requirePattern);
|
|
49885
|
-
const manifest = JSON.parse(
|
|
49886
|
-
const statusPath =
|
|
49887
|
-
const inputPath =
|
|
49888
|
-
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");
|
|
49889
50361
|
const spawnPlan = await (opts.spawnPlanner ?? prehydrateCredentialsForSpawn)(Object.values(manifest.models).map((m) => m.model));
|
|
49890
|
-
const statusCache = JSON.parse(
|
|
50362
|
+
const statusCache = JSON.parse(readFileSync20(statusPath, "utf-8"));
|
|
49891
50363
|
function updateModelStatus(id, update) {
|
|
49892
50364
|
statusCache.models[id] = { ...statusCache.models[id], ...update };
|
|
49893
|
-
|
|
50365
|
+
writeFileSync12(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
|
|
49894
50366
|
}
|
|
49895
50367
|
const minOutputBytes = opts.minOutputBytes ?? DEFAULT_MIN_OUTPUT_BYTES;
|
|
49896
50368
|
const requirePattern = opts.requirePattern;
|
|
@@ -49923,7 +50395,7 @@ async function startModels(sessionPath, opts = {}) {
|
|
|
49923
50395
|
persistErrorLog(rt.errorLogPath, `RECOVERED: ${note}`, stderr, stdoutTail);
|
|
49924
50396
|
opts.onStatusChange?.(id, statusCache.models[id]);
|
|
49925
50397
|
}
|
|
49926
|
-
|
|
50398
|
+
mkdirSync12(statsDir(sessionPath), { recursive: true });
|
|
49927
50399
|
const processes = new Map;
|
|
49928
50400
|
const runtimes = new Map;
|
|
49929
50401
|
const cancelledSlots = new Set;
|
|
@@ -49936,9 +50408,9 @@ async function startModels(sessionPath, opts = {}) {
|
|
|
49936
50408
|
process.on("SIGINT", sigintHandler);
|
|
49937
50409
|
const completionPromises = [];
|
|
49938
50410
|
for (const [anonId, entry] of Object.entries(manifest.models)) {
|
|
49939
|
-
const outputPath =
|
|
49940
|
-
const errorLogPath =
|
|
49941
|
-
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`);
|
|
49942
50414
|
const spawnModel = spawnPlan.pinned.get(entry.model) ?? entry.model;
|
|
49943
50415
|
const args = [
|
|
49944
50416
|
"--model",
|
|
@@ -50078,7 +50550,7 @@ async function startModels(sessionPath, opts = {}) {
|
|
|
50078
50550
|
stderrSnippet: stderr ? redactSecrets(stderr).slice(-2000) : undefined,
|
|
50079
50551
|
stdoutSnippet: stdoutTail ? redactSecrets(stdoutTail).slice(-2000) : undefined,
|
|
50080
50552
|
errorLogPath,
|
|
50081
|
-
upstreamErrorLogPath:
|
|
50553
|
+
upstreamErrorLogPath: existsSync21(upstreamErrorLogPath) ? upstreamErrorLogPath : undefined,
|
|
50082
50554
|
workDir: sessionPath
|
|
50083
50555
|
}
|
|
50084
50556
|
});
|
|
@@ -50098,7 +50570,7 @@ async function startModels(sessionPath, opts = {}) {
|
|
|
50098
50570
|
proc.on("exit", (code) => {
|
|
50099
50571
|
const timedOut = statusCache.models[anonId]?.state === "TIMEOUT";
|
|
50100
50572
|
if (!timedOut && meaningfulStderr(stderr)) {
|
|
50101
|
-
|
|
50573
|
+
writeFileSync12(errorLogPath, redactSecrets(stderr), "utf-8");
|
|
50102
50574
|
}
|
|
50103
50575
|
exitCode = code;
|
|
50104
50576
|
if (outputStream.destroyed) {
|
|
@@ -50178,23 +50650,23 @@ async function judgeResponses(sessionPath, opts = {}) {
|
|
|
50178
50650
|
const responses = {};
|
|
50179
50651
|
for (const file2 of responseFiles) {
|
|
50180
50652
|
const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
|
|
50181
|
-
responses[id] =
|
|
50653
|
+
responses[id] = readFileSync20(join30(sessionPath, file2), "utf-8");
|
|
50182
50654
|
}
|
|
50183
|
-
const input =
|
|
50655
|
+
const input = readFileSync20(join30(sessionPath, "input.md"), "utf-8");
|
|
50184
50656
|
const judgePrompt = buildJudgePrompt(input, responses);
|
|
50185
|
-
|
|
50657
|
+
writeFileSync12(join30(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
|
|
50186
50658
|
const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
|
|
50187
|
-
const judgePath =
|
|
50188
|
-
|
|
50659
|
+
const judgePath = join30(sessionPath, "judging");
|
|
50660
|
+
mkdirSync12(judgePath, { recursive: true });
|
|
50189
50661
|
setupSession(judgePath, judgeModels, judgePrompt);
|
|
50190
50662
|
await runModels(judgePath, { claudeFlags: opts.claudeFlags });
|
|
50191
50663
|
const votes = parseJudgeVotes(judgePath, Object.keys(responses));
|
|
50192
50664
|
const verdict = aggregateVerdict(votes, Object.keys(responses));
|
|
50193
|
-
|
|
50665
|
+
writeFileSync12(join30(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
|
|
50194
50666
|
return verdict;
|
|
50195
50667
|
}
|
|
50196
50668
|
function getStatus(sessionPath) {
|
|
50197
|
-
return JSON.parse(
|
|
50669
|
+
return JSON.parse(readFileSync20(join30(sessionPath, "status.json"), "utf-8"));
|
|
50198
50670
|
}
|
|
50199
50671
|
function fisherYatesShuffle(arr) {
|
|
50200
50672
|
for (let i = arr.length - 1;i > 0; i--) {
|
|
@@ -50204,7 +50676,7 @@ function fisherYatesShuffle(arr) {
|
|
|
50204
50676
|
return arr;
|
|
50205
50677
|
}
|
|
50206
50678
|
function getDefaultJudgeModels(sessionPath) {
|
|
50207
|
-
const manifest = JSON.parse(
|
|
50679
|
+
const manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
|
|
50208
50680
|
return Object.values(manifest.models).map((e) => e.model);
|
|
50209
50681
|
}
|
|
50210
50682
|
function buildJudgePrompt(input, responses) {
|
|
@@ -50267,7 +50739,7 @@ function parseJudgeVotes(judgePath, responseIds) {
|
|
|
50267
50739
|
const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
|
|
50268
50740
|
let content;
|
|
50269
50741
|
try {
|
|
50270
|
-
content =
|
|
50742
|
+
content = readFileSync20(join30(judgePath, file2), "utf-8");
|
|
50271
50743
|
} catch {
|
|
50272
50744
|
continue;
|
|
50273
50745
|
}
|
|
@@ -50319,7 +50791,7 @@ function aggregateVerdict(votes, responseIds) {
|
|
|
50319
50791
|
function formatVerdict(verdict, sessionPath) {
|
|
50320
50792
|
let manifest = null;
|
|
50321
50793
|
try {
|
|
50322
|
-
manifest = JSON.parse(
|
|
50794
|
+
manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
|
|
50323
50795
|
} catch {}
|
|
50324
50796
|
let output = `# Team Verdict
|
|
50325
50797
|
|
|
@@ -50373,15 +50845,15 @@ import {
|
|
|
50373
50845
|
appendFileSync as appendFileSync6,
|
|
50374
50846
|
closeSync as closeSync7,
|
|
50375
50847
|
createWriteStream as createWriteStream2,
|
|
50376
|
-
mkdirSync as
|
|
50848
|
+
mkdirSync as mkdirSync13,
|
|
50377
50849
|
openSync as openSync7,
|
|
50378
|
-
readFileSync as
|
|
50850
|
+
readFileSync as readFileSync21,
|
|
50379
50851
|
readSync as readSync3,
|
|
50380
50852
|
statSync as statSync6,
|
|
50381
|
-
writeFileSync as
|
|
50853
|
+
writeFileSync as writeFileSync13
|
|
50382
50854
|
} from "fs";
|
|
50383
|
-
import { homedir as
|
|
50384
|
-
import { join as
|
|
50855
|
+
import { homedir as homedir29 } from "os";
|
|
50856
|
+
import { join as join31, resolve as resolve4, sep } from "path";
|
|
50385
50857
|
import { StringDecoder as StringDecoder2 } from "string_decoder";
|
|
50386
50858
|
function buildChannelSpawnArgs(opts) {
|
|
50387
50859
|
return [
|
|
@@ -50456,7 +50928,7 @@ function readJsonObject(path, maxBytes) {
|
|
|
50456
50928
|
try {
|
|
50457
50929
|
if (fileSize(path) > maxBytes)
|
|
50458
50930
|
return null;
|
|
50459
|
-
const parsed = JSON.parse(
|
|
50931
|
+
const parsed = JSON.parse(readFileSync21(path, "utf-8"));
|
|
50460
50932
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
50461
50933
|
return null;
|
|
50462
50934
|
return parsed;
|
|
@@ -50472,7 +50944,7 @@ function dropLeadingFragment(tail) {
|
|
|
50472
50944
|
return firstBreak === -1 ? tail.text : tail.text.slice(firstBreak + 1);
|
|
50473
50945
|
}
|
|
50474
50946
|
function diskAccounting(sessionDir) {
|
|
50475
|
-
const stats = readTokenStatsAt(
|
|
50947
|
+
const stats = readTokenStatsAt(join31(sessionDir, "tokens.json"));
|
|
50476
50948
|
return {
|
|
50477
50949
|
tokensUsed: (stats?.total_tokens ?? 0) || (stats?.input_tokens ?? 0) + (stats?.output_tokens ?? 0),
|
|
50478
50950
|
costUsd: stats?.total_cost ?? 0,
|
|
@@ -50512,7 +50984,7 @@ class SessionManager {
|
|
|
50512
50984
|
this.maxSessions = options?.maxSessions ?? DEFAULT_MAX_SESSIONS;
|
|
50513
50985
|
this.scrollbackCapacity = options?.scrollbackCapacity ?? DEFAULT_SCROLLBACK;
|
|
50514
50986
|
this.terminalRetentionMs = options?.terminalRetentionMs ?? TERMINAL_RETENTION_MS;
|
|
50515
|
-
this.sessionsDir = options?.sessionsDir ?? process.env.CLAUDISH_SESSIONS_DIR ??
|
|
50987
|
+
this.sessionsDir = options?.sessionsDir ?? process.env.CLAUDISH_SESSIONS_DIR ?? join31(homedir29(), ".claudish", "sessions");
|
|
50516
50988
|
this.stallSeconds = options?.stallSeconds;
|
|
50517
50989
|
this.onStateChange = options?.onStateChange;
|
|
50518
50990
|
}
|
|
@@ -50528,19 +51000,19 @@ class SessionManager {
|
|
|
50528
51000
|
const claudeSessionId = randomUUID4();
|
|
50529
51001
|
const timeout = Math.min(opts.timeoutSeconds ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
|
|
50530
51002
|
const startedAt = new Date().toISOString();
|
|
50531
|
-
const sessionDir = opts.sessionDir ??
|
|
50532
|
-
|
|
51003
|
+
const sessionDir = opts.sessionDir ?? join31(this.sessionsDir, sessionId2);
|
|
51004
|
+
mkdirSync13(sessionDir, { recursive: true });
|
|
50533
51005
|
if (opts.prompt) {
|
|
50534
|
-
|
|
51006
|
+
writeFileSync13(join31(sessionDir, "prompt.md"), opts.prompt, "utf-8");
|
|
50535
51007
|
}
|
|
50536
51008
|
const args = buildChannelSpawnArgs({
|
|
50537
51009
|
model: opts.spawnModel ?? opts.model,
|
|
50538
51010
|
claudeSessionId,
|
|
50539
51011
|
claudishFlags: opts.claudishFlags
|
|
50540
51012
|
});
|
|
50541
|
-
const tokenFile = opts.tokenFile ??
|
|
50542
|
-
const eventLogPath =
|
|
50543
|
-
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");
|
|
50544
51016
|
const cwd = opts.cwd ?? process.cwd();
|
|
50545
51017
|
const spawnTarget = resolveClaudishSpawn();
|
|
50546
51018
|
const proc = spawn3(spawnTarget.command, [...spawnTarget.prefixArgs, ...args], {
|
|
@@ -50555,7 +51027,7 @@ class SessionManager {
|
|
|
50555
51027
|
}
|
|
50556
51028
|
});
|
|
50557
51029
|
const scrollback = new ScrollbackBuffer(this.scrollbackCapacity);
|
|
50558
|
-
const outputLogStream = createWriteStream2(
|
|
51030
|
+
const outputLogStream = createWriteStream2(join31(sessionDir, "output.log"));
|
|
50559
51031
|
const entry = {
|
|
50560
51032
|
info: {
|
|
50561
51033
|
sessionId: sessionId2,
|
|
@@ -50847,7 +51319,7 @@ class SessionManager {
|
|
|
50847
51319
|
return null;
|
|
50848
51320
|
const root = resolve4(this.sessionsDir);
|
|
50849
51321
|
const dir = resolve4(root, sessionId2);
|
|
50850
|
-
if (dir !==
|
|
51322
|
+
if (dir !== join31(root, sessionId2))
|
|
50851
51323
|
return null;
|
|
50852
51324
|
if (!dir.startsWith(root + sep))
|
|
50853
51325
|
return null;
|
|
@@ -50866,7 +51338,7 @@ class SessionManager {
|
|
|
50866
51338
|
} catch {
|
|
50867
51339
|
return null;
|
|
50868
51340
|
}
|
|
50869
|
-
const meta3 = readJsonObject(
|
|
51341
|
+
const meta3 = readJsonObject(join31(sessionDir, "meta.json"), META_READ_LIMIT);
|
|
50870
51342
|
const partial2 = meta3 === null;
|
|
50871
51343
|
const measured = diskAccounting(sessionDir);
|
|
50872
51344
|
const startedAt = metaString(meta3?.startedAt) ?? new Date(dirMtimeMs).toISOString();
|
|
@@ -50896,7 +51368,7 @@ class SessionManager {
|
|
|
50896
51368
|
};
|
|
50897
51369
|
}
|
|
50898
51370
|
diskOutput(record4, tailLines) {
|
|
50899
|
-
const tail = readTailText(
|
|
51371
|
+
const tail = readTailText(join31(record4.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
|
|
50900
51372
|
const buffer = new ScrollbackBuffer(this.scrollbackCapacity);
|
|
50901
51373
|
if (tail?.text)
|
|
50902
51374
|
buffer.append(dropLeadingFragment(tail));
|
|
@@ -50915,9 +51387,9 @@ class SessionManager {
|
|
|
50915
51387
|
}
|
|
50916
51388
|
diskDiagnostics(record4, limit) {
|
|
50917
51389
|
const { sessionDir, info } = record4;
|
|
50918
|
-
const eventLogPath =
|
|
50919
|
-
const upstreamErrorLogPath =
|
|
50920
|
-
const outputLogPath =
|
|
51390
|
+
const eventLogPath = join31(sessionDir, "events.jsonl");
|
|
51391
|
+
const upstreamErrorLogPath = join31(sessionDir, "upstream-errors.jsonl");
|
|
51392
|
+
const outputLogPath = join31(sessionDir, "output.log");
|
|
50921
51393
|
const events = readTailLines(eventLogPath, EVENT_TAIL_BYTES);
|
|
50922
51394
|
const outputTail = readTailText(outputLogPath, OUTPUT_TAIL_BYTES);
|
|
50923
51395
|
return {
|
|
@@ -50959,7 +51431,7 @@ class SessionManager {
|
|
|
50959
51431
|
};
|
|
50960
51432
|
}
|
|
50961
51433
|
diskStderrForDiagnostics(record4) {
|
|
50962
|
-
const tail = readTailText(
|
|
51434
|
+
const tail = readTailText(join31(record4.sessionDir, "stderr.log"), STDERR_READ_BYTES);
|
|
50963
51435
|
const raw = tail?.text ?? "";
|
|
50964
51436
|
const filtered = record4.info.status === "completed";
|
|
50965
51437
|
const source = filtered ? meaningfulStderr(raw) : raw;
|
|
@@ -51135,11 +51607,11 @@ ${STDERR_TRUNCATION_MARKER} ${STDERR_SIDE_LIMIT} bytes per end \u2026
|
|
|
51135
51607
|
entry.outputLogStream?.end();
|
|
51136
51608
|
entry.outputLogStream = null;
|
|
51137
51609
|
if (entry.stderr) {
|
|
51138
|
-
|
|
51610
|
+
writeFileSync13(join31(entry.sessionDir, "stderr.log"), redactSecrets(entry.stderr), "utf-8");
|
|
51139
51611
|
}
|
|
51140
51612
|
this.refreshAccounting(entry);
|
|
51141
51613
|
entry.info.claudeSessionId = entry.reducer.claudeSessionId ?? entry.info.claudeSessionId;
|
|
51142
|
-
|
|
51614
|
+
writeFileSync13(join31(entry.sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
|
|
51143
51615
|
}
|
|
51144
51616
|
scheduleEviction(entry) {
|
|
51145
51617
|
if (entry.evictHandle)
|
|
@@ -51199,7 +51671,7 @@ ${STDERR_TRUNCATION_MARKER} ${STDERR_SIDE_LIMIT} bytes per end \u2026
|
|
|
51199
51671
|
return { state: "completed", content: "" };
|
|
51200
51672
|
}
|
|
51201
51673
|
refreshAccounting(entry) {
|
|
51202
|
-
const stats = readTokenStatsAt(
|
|
51674
|
+
const stats = readTokenStatsAt(join31(entry.sessionDir, "tokens.json"));
|
|
51203
51675
|
const fileTokens = (stats?.total_tokens ?? 0) || (stats?.input_tokens ?? 0) + (stats?.output_tokens ?? 0);
|
|
51204
51676
|
entry.info.tokensUsed = fileTokens || entry.reducer.tokens;
|
|
51205
51677
|
entry.info.costUsd = stats?.total_cost ?? 0;
|
|
@@ -51390,306 +51862,6 @@ var init_progress_heartbeat = __esm(() => {
|
|
|
51390
51862
|
});
|
|
51391
51863
|
});
|
|
51392
51864
|
|
|
51393
|
-
// src/providers/cache-ttl.ts
|
|
51394
|
-
var FIREBASE_CACHE_TTL_HOURS = 24, FIREBASE_CACHE_TTL_MS;
|
|
51395
|
-
var init_cache_ttl = __esm(() => {
|
|
51396
|
-
FIREBASE_CACHE_TTL_MS = FIREBASE_CACHE_TTL_HOURS * 60 * 60 * 1000;
|
|
51397
|
-
});
|
|
51398
|
-
|
|
51399
|
-
// src/model-loader.ts
|
|
51400
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
|
|
51401
|
-
import { homedir as homedir29 } from "os";
|
|
51402
|
-
import { join as join31 } from "path";
|
|
51403
|
-
function groupRecommendedModels(entries) {
|
|
51404
|
-
const byId = new Map;
|
|
51405
|
-
const categoryOrder = new Map;
|
|
51406
|
-
for (const entry of entries) {
|
|
51407
|
-
const list = byId.get(entry.id);
|
|
51408
|
-
if (list)
|
|
51409
|
-
list.push(entry);
|
|
51410
|
-
else
|
|
51411
|
-
byId.set(entry.id, [entry]);
|
|
51412
|
-
if (!categoryOrder.has(entry.category))
|
|
51413
|
-
categoryOrder.set(entry.category, categoryOrder.size);
|
|
51414
|
-
}
|
|
51415
|
-
const flagship = [];
|
|
51416
|
-
const fast = [];
|
|
51417
|
-
for (const [id, members] of byId.entries()) {
|
|
51418
|
-
const primary = members.find((m) => m.category !== "subscription") ?? members[0];
|
|
51419
|
-
const subscriptions = members.filter((m) => m.category === "subscription");
|
|
51420
|
-
const bucket = primary.category === "programming" || primary.category === "vision" || primary.category === "reasoning" ? "flagship" : "fast";
|
|
51421
|
-
const group = { id, primary, subscriptions, bucket };
|
|
51422
|
-
if (bucket === "flagship")
|
|
51423
|
-
flagship.push(group);
|
|
51424
|
-
else
|
|
51425
|
-
fast.push(group);
|
|
51426
|
-
}
|
|
51427
|
-
const byCuratedPriorityThenFreshness = (a, b) => {
|
|
51428
|
-
const aCat = categoryOrder.get(a.primary.category) ?? Number.MAX_SAFE_INTEGER;
|
|
51429
|
-
const bCat = categoryOrder.get(b.primary.category) ?? Number.MAX_SAFE_INTEGER;
|
|
51430
|
-
if (aCat !== bCat)
|
|
51431
|
-
return aCat - bCat;
|
|
51432
|
-
if (a.primary.priority !== b.primary.priority)
|
|
51433
|
-
return a.primary.priority - b.primary.priority;
|
|
51434
|
-
return compareByReleaseDateDesc(a.primary, b.primary);
|
|
51435
|
-
};
|
|
51436
|
-
flagship.sort(byCuratedPriorityThenFreshness);
|
|
51437
|
-
fast.sort(byCuratedPriorityThenFreshness);
|
|
51438
|
-
return { flagship, fast };
|
|
51439
|
-
}
|
|
51440
|
-
function collectRoutingPrefixes(group, getNativePrefix) {
|
|
51441
|
-
const slug = (group.primary.provider || "").toLowerCase();
|
|
51442
|
-
const native = getNativePrefix(slug);
|
|
51443
|
-
const seen = new Set;
|
|
51444
|
-
const out = [];
|
|
51445
|
-
if (native) {
|
|
51446
|
-
out.push(native);
|
|
51447
|
-
seen.add(native);
|
|
51448
|
-
}
|
|
51449
|
-
for (const sub of group.subscriptions) {
|
|
51450
|
-
const p = sub.subscription?.prefix;
|
|
51451
|
-
if (!p || seen.has(p))
|
|
51452
|
-
continue;
|
|
51453
|
-
seen.add(p);
|
|
51454
|
-
out.push(p);
|
|
51455
|
-
}
|
|
51456
|
-
return out;
|
|
51457
|
-
}
|
|
51458
|
-
function parsePriceAvg(s) {
|
|
51459
|
-
if (!s || s === "N/A")
|
|
51460
|
-
return Number.POSITIVE_INFINITY;
|
|
51461
|
-
if (s === "FREE")
|
|
51462
|
-
return 0;
|
|
51463
|
-
const m = s.match(/\$([\d.]+)/);
|
|
51464
|
-
return m ? Number.parseFloat(m[1]) : Number.POSITIVE_INFINITY;
|
|
51465
|
-
}
|
|
51466
|
-
function parseCtx(s) {
|
|
51467
|
-
if (!s || s === "N/A")
|
|
51468
|
-
return 0;
|
|
51469
|
-
const upper = s.toUpperCase();
|
|
51470
|
-
if (upper.includes("M"))
|
|
51471
|
-
return Number.parseFloat(upper) * 1e6;
|
|
51472
|
-
if (upper.includes("K"))
|
|
51473
|
-
return Number.parseFloat(upper) * 1000;
|
|
51474
|
-
return Number.parseInt(s, 10) || 0;
|
|
51475
|
-
}
|
|
51476
|
-
function normalizePricingDisplay(raw) {
|
|
51477
|
-
const pricing = raw || "N/A";
|
|
51478
|
-
if (pricing.includes("-1000000"))
|
|
51479
|
-
return "varies";
|
|
51480
|
-
if (pricing === "$0.00/1M" || pricing === "FREE")
|
|
51481
|
-
return "FREE";
|
|
51482
|
-
return pricing;
|
|
51483
|
-
}
|
|
51484
|
-
function formatListingPrice(entry, opts) {
|
|
51485
|
-
const rate = normalizePricingDisplay(entry.pricing?.average);
|
|
51486
|
-
if (rate !== "N/A")
|
|
51487
|
-
return rate;
|
|
51488
|
-
const plan = entry.subscription?.plan;
|
|
51489
|
-
if (!plan)
|
|
51490
|
-
return "N/A";
|
|
51491
|
-
return opts?.compact ? "SUB" : `SUB (${plan})`;
|
|
51492
|
-
}
|
|
51493
|
-
function computeQuickPicks(primaries) {
|
|
51494
|
-
if (primaries.length === 0) {
|
|
51495
|
-
return {
|
|
51496
|
-
budget: null,
|
|
51497
|
-
largeContext: null,
|
|
51498
|
-
mostCapable: null,
|
|
51499
|
-
visionCoding: null,
|
|
51500
|
-
agentic: null
|
|
51501
|
-
};
|
|
51502
|
-
}
|
|
51503
|
-
const priced = primaries.filter((m) => {
|
|
51504
|
-
const p = parsePriceAvg(m.pricing?.average);
|
|
51505
|
-
return p > 0 && p !== Number.POSITIVE_INFINITY;
|
|
51506
|
-
}).sort((a, b) => parsePriceAvg(a.pricing?.average) - parsePriceAvg(b.pricing?.average));
|
|
51507
|
-
const budget = priced[0] ?? null;
|
|
51508
|
-
const byCtx = [...primaries].sort((a, b) => parseCtx(b.context) - parseCtx(a.context));
|
|
51509
|
-
const largeContext = byCtx[0] ?? null;
|
|
51510
|
-
const byPrice = [...primaries].sort((a, b) => parsePriceAvg(b.pricing?.average) - parsePriceAvg(a.pricing?.average));
|
|
51511
|
-
const mostCapable = byPrice.find((m) => parsePriceAvg(m.pricing?.average) !== Number.POSITIVE_INFINITY) ?? null;
|
|
51512
|
-
const visionCoding = primaries.find((m) => m.supportsVision === true && m.id !== budget?.id && m.id !== mostCapable?.id) ?? null;
|
|
51513
|
-
const agentic = primaries.find((m) => m.supportsReasoning === true && m.id !== mostCapable?.id) ?? null;
|
|
51514
|
-
return { budget, largeContext, mostCapable, visionCoding, agentic };
|
|
51515
|
-
}
|
|
51516
|
-
async function getRecommendedModels(opts = {}) {
|
|
51517
|
-
const { forceRefresh = false } = opts;
|
|
51518
|
-
if (!forceRefresh && _cachedRecommendedModels) {
|
|
51519
|
-
return _cachedRecommendedModels;
|
|
51520
|
-
}
|
|
51521
|
-
if (!forceRefresh && existsSync21(RECOMMENDED_MODELS_CACHE_PATH)) {
|
|
51522
|
-
try {
|
|
51523
|
-
const cacheData = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
|
|
51524
|
-
if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
|
|
51525
|
-
_cachedRecommendedModels = cacheData;
|
|
51526
|
-
return cacheData;
|
|
51527
|
-
}
|
|
51528
|
-
} catch {}
|
|
51529
|
-
}
|
|
51530
|
-
try {
|
|
51531
|
-
const response = await fetch(FIREBASE_RECOMMENDED_URL, {
|
|
51532
|
-
signal: AbortSignal.timeout(RECOMMENDED_FETCH_TIMEOUT_MS)
|
|
51533
|
-
});
|
|
51534
|
-
if (response.ok) {
|
|
51535
|
-
const data = await response.json();
|
|
51536
|
-
if (data.models && data.models.length > 0) {
|
|
51537
|
-
_cachedRecommendedModels = data;
|
|
51538
|
-
try {
|
|
51539
|
-
const cacheDir = join31(homedir29(), ".claudish");
|
|
51540
|
-
mkdirSync13(cacheDir, { recursive: true });
|
|
51541
|
-
writeFileSync13(RECOMMENDED_MODELS_CACHE_PATH, JSON.stringify(data), "utf-8");
|
|
51542
|
-
} catch {}
|
|
51543
|
-
return data;
|
|
51544
|
-
}
|
|
51545
|
-
}
|
|
51546
|
-
} catch {}
|
|
51547
|
-
throw new Error("Unable to load recommended models: Firebase unreachable and no local cache. " + "Check connectivity.");
|
|
51548
|
-
}
|
|
51549
|
-
function getRecommendedModelsSync() {
|
|
51550
|
-
if (_cachedRecommendedModels)
|
|
51551
|
-
return _cachedRecommendedModels;
|
|
51552
|
-
if (existsSync21(RECOMMENDED_MODELS_CACHE_PATH)) {
|
|
51553
|
-
try {
|
|
51554
|
-
const cacheData = JSON.parse(readFileSync21(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
|
|
51555
|
-
if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
|
|
51556
|
-
_cachedRecommendedModels = cacheData;
|
|
51557
|
-
return cacheData;
|
|
51558
|
-
}
|
|
51559
|
-
} catch {}
|
|
51560
|
-
}
|
|
51561
|
-
return { version: "0", lastUpdated: "", models: [] };
|
|
51562
|
-
}
|
|
51563
|
-
async function warmRecommendedModels() {
|
|
51564
|
-
try {
|
|
51565
|
-
return await getRecommendedModels({ forceRefresh: true });
|
|
51566
|
-
} catch {
|
|
51567
|
-
return null;
|
|
51568
|
-
}
|
|
51569
|
-
}
|
|
51570
|
-
function isFreshEnough(doc2) {
|
|
51571
|
-
const generatedAt = doc2.generatedAt;
|
|
51572
|
-
if (!generatedAt)
|
|
51573
|
-
return true;
|
|
51574
|
-
const ageHours = (Date.now() - new Date(generatedAt).getTime()) / (1000 * 60 * 60);
|
|
51575
|
-
return ageHours <= FIREBASE_CACHE_TTL_HOURS;
|
|
51576
|
-
}
|
|
51577
|
-
async function searchModels(query, limit = 50) {
|
|
51578
|
-
const url2 = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(query)}&limit=${limit}&status=active`;
|
|
51579
|
-
const response = await fetch(url2, {
|
|
51580
|
-
signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
|
|
51581
|
-
});
|
|
51582
|
-
if (!response.ok) {
|
|
51583
|
-
throw new Error(`Firebase search returned ${response.status} ${response.statusText}`);
|
|
51584
|
-
}
|
|
51585
|
-
const data = await response.json();
|
|
51586
|
-
return data.models ?? [];
|
|
51587
|
-
}
|
|
51588
|
-
async function getModelByIdFromFirebase(modelId) {
|
|
51589
|
-
const url2 = `${FIREBASE_BASE_URL}?search=${encodeURIComponent(modelId)}&limit=5`;
|
|
51590
|
-
const response = await fetch(url2, {
|
|
51591
|
-
signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
|
|
51592
|
-
});
|
|
51593
|
-
if (!response.ok) {
|
|
51594
|
-
throw new Error(`Firebase lookup returned ${response.status} ${response.statusText}`);
|
|
51595
|
-
}
|
|
51596
|
-
const data = await response.json();
|
|
51597
|
-
const models = data.models ?? [];
|
|
51598
|
-
for (const m of models) {
|
|
51599
|
-
if (m.modelId === modelId)
|
|
51600
|
-
return m;
|
|
51601
|
-
if (m.aliases?.includes(modelId))
|
|
51602
|
-
return m;
|
|
51603
|
-
}
|
|
51604
|
-
return null;
|
|
51605
|
-
}
|
|
51606
|
-
async function getTop100Models() {
|
|
51607
|
-
const url2 = `${FIREBASE_BASE_URL}?catalog=top100`;
|
|
51608
|
-
const response = await fetch(url2, {
|
|
51609
|
-
signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
|
|
51610
|
-
});
|
|
51611
|
-
if (!response.ok) {
|
|
51612
|
-
throw new Error(`Firebase top100 fetch failed: ${response.status} ${response.statusText}`);
|
|
51613
|
-
}
|
|
51614
|
-
const data = await response.json();
|
|
51615
|
-
return data;
|
|
51616
|
-
}
|
|
51617
|
-
async function getProviderList() {
|
|
51618
|
-
const url2 = `${FIREBASE_BASE_URL}?catalog=providers`;
|
|
51619
|
-
const response = await fetch(url2, {
|
|
51620
|
-
signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
|
|
51621
|
-
});
|
|
51622
|
-
if (!response.ok) {
|
|
51623
|
-
throw new Error(`Firebase providers fetch failed: ${response.status} ${response.statusText}`);
|
|
51624
|
-
}
|
|
51625
|
-
const data = await response.json();
|
|
51626
|
-
return data.providers ?? [];
|
|
51627
|
-
}
|
|
51628
|
-
async function getModelsByProvider(provider, limit = 200) {
|
|
51629
|
-
const url2 = `${FIREBASE_BASE_URL}?provider=${encodeURIComponent(provider)}&status=active&limit=${limit}`;
|
|
51630
|
-
const response = await fetch(url2, {
|
|
51631
|
-
signal: AbortSignal.timeout(SEARCH_FETCH_TIMEOUT_MS)
|
|
51632
|
-
});
|
|
51633
|
-
if (!response.ok) {
|
|
51634
|
-
throw new Error(`Firebase provider query returned ${response.status} ${response.statusText}`);
|
|
51635
|
-
}
|
|
51636
|
-
const data = await response.json();
|
|
51637
|
-
if (Array.isArray(data))
|
|
51638
|
-
return data;
|
|
51639
|
-
return data.models ?? [];
|
|
51640
|
-
}
|
|
51641
|
-
function loadModelInfo() {
|
|
51642
|
-
if (_cachedModelInfo) {
|
|
51643
|
-
return _cachedModelInfo;
|
|
51644
|
-
}
|
|
51645
|
-
const data = getRecommendedModelsSync();
|
|
51646
|
-
const modelInfo = {};
|
|
51647
|
-
for (const model of data.models) {
|
|
51648
|
-
modelInfo[model.id] = {
|
|
51649
|
-
name: model.name,
|
|
51650
|
-
description: model.description,
|
|
51651
|
-
priority: model.priority,
|
|
51652
|
-
provider: model.provider
|
|
51653
|
-
};
|
|
51654
|
-
}
|
|
51655
|
-
modelInfo.custom = {
|
|
51656
|
-
name: "Custom Model",
|
|
51657
|
-
description: "Enter any model ID manually",
|
|
51658
|
-
priority: 999,
|
|
51659
|
-
provider: "Custom"
|
|
51660
|
-
};
|
|
51661
|
-
_cachedModelInfo = modelInfo;
|
|
51662
|
-
return modelInfo;
|
|
51663
|
-
}
|
|
51664
|
-
function getAvailableModels() {
|
|
51665
|
-
if (_cachedModelIds) {
|
|
51666
|
-
return _cachedModelIds;
|
|
51667
|
-
}
|
|
51668
|
-
const data = getRecommendedModelsSync();
|
|
51669
|
-
const modelIds = data.models.sort((a, b) => a.priority - b.priority).map((m) => m.id);
|
|
51670
|
-
const result = [...modelIds, "custom"];
|
|
51671
|
-
_cachedModelIds = result;
|
|
51672
|
-
return result;
|
|
51673
|
-
}
|
|
51674
|
-
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;
|
|
51675
|
-
var init_model_loader = __esm(() => {
|
|
51676
|
-
init_cache_ttl();
|
|
51677
|
-
FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
|
|
51678
|
-
RECOMMENDED_MODELS_CACHE_PATH = join31(homedir29(), ".claudish", "recommended-models-cache.json");
|
|
51679
|
-
FIREBASE_SLUG_TO_PROVIDER_NAME = {
|
|
51680
|
-
openai: "openai",
|
|
51681
|
-
google: "google",
|
|
51682
|
-
"x-ai": "x-ai",
|
|
51683
|
-
"z-ai": "z-ai",
|
|
51684
|
-
moonshotai: "kimi",
|
|
51685
|
-
minimax: "minimax",
|
|
51686
|
-
qwen: "qwen",
|
|
51687
|
-
deepseek: "deepseek",
|
|
51688
|
-
mistralai: "mistralai",
|
|
51689
|
-
sakana: "sakana"
|
|
51690
|
-
};
|
|
51691
|
-
});
|
|
51692
|
-
|
|
51693
51865
|
// src/port-manager.ts
|
|
51694
51866
|
var exports_port_manager = {};
|
|
51695
51867
|
__export(exports_port_manager, {
|
|
@@ -75450,7 +75622,7 @@ var init_api_key_map = __esm(() => {
|
|
|
75450
75622
|
"qwen-payg": { envVar: "DASHSCOPE_API_KEY", aliases: ["QWEN_API_KEY"] },
|
|
75451
75623
|
ollamacloud: { envVar: "OLLAMA_API_KEY" },
|
|
75452
75624
|
"opencode-zen": { envVar: "OPENCODE_API_KEY" },
|
|
75453
|
-
"opencode-zen-go": { envVar: "OPENCODE_GO_API_KEY"
|
|
75625
|
+
"opencode-zen-go": { envVar: "OPENCODE_GO_API_KEY" },
|
|
75454
75626
|
vertex: { envVar: "VERTEX_API_KEY", aliases: ["VERTEX_PROJECT"] },
|
|
75455
75627
|
poe: { envVar: "POE_API_KEY" }
|
|
75456
75628
|
};
|
|
@@ -77023,6 +77195,7 @@ ${h("ENVIRONMENT VARIABLES")}
|
|
|
77023
77195
|
${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${dim4("(sc@; separate subscription key)")}
|
|
77024
77196
|
${blue("OLLAMA_API_KEY")} OllamaCloud ${dim4("(oc@, llama@)")}
|
|
77025
77197
|
${blue("OPENCODE_API_KEY")} OpenCode Zen ${dim4("(zen@)")}
|
|
77198
|
+
${blue("OPENCODE_GO_API_KEY")} OpenCode Zen Go plan ${dim4("(zgo@, zengo@; separate plan key)")}
|
|
77026
77199
|
${blue("POE_API_KEY")} Poe ${dim4("(poe@)")}
|
|
77027
77200
|
${blue("LITELLM_API_KEY")} LiteLLM ${dim4("(litellm@, ll@; needs LITELLM_BASE_URL)")}
|
|
77028
77201
|
${blue("VERTEX_API_KEY")} Vertex AI Express ${dim4("(v@)")}
|