claudish 7.65.0 → 7.66.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 +1550 -383
- 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 = "7.
|
|
734
|
+
var VERSION = "7.66.1";
|
|
735
735
|
|
|
736
736
|
// src/logger.ts
|
|
737
737
|
var exports_logger = {};
|
|
@@ -27554,6 +27554,7 @@ __export(exports_profile_config, {
|
|
|
27554
27554
|
getModelMapping: () => getModelMapping,
|
|
27555
27555
|
getProfile: () => getProfile,
|
|
27556
27556
|
getProfileNames: () => getProfileNames,
|
|
27557
|
+
isKeychainEnabled: () => isKeychainEnabled,
|
|
27557
27558
|
isLocalProviderEnabled: () => isLocalProviderEnabled,
|
|
27558
27559
|
isProjectDirectory: () => isProjectDirectory,
|
|
27559
27560
|
listAllProfiles: () => listAllProfiles,
|
|
@@ -27569,6 +27570,7 @@ __export(exports_profile_config, {
|
|
|
27569
27570
|
setConfigFileOverride: () => setConfigFileOverride,
|
|
27570
27571
|
setDefaultProfile: () => setDefaultProfile,
|
|
27571
27572
|
setEndpoint: () => setEndpoint,
|
|
27573
|
+
setKeychainEnabled: () => setKeychainEnabled,
|
|
27572
27574
|
setProfile: () => setProfile
|
|
27573
27575
|
});
|
|
27574
27576
|
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
@@ -27621,6 +27623,9 @@ function loadConfig() {
|
|
|
27621
27623
|
if (config2.onepasswordEnvironments !== undefined) {
|
|
27622
27624
|
merged.onepasswordEnvironments = config2.onepasswordEnvironments;
|
|
27623
27625
|
}
|
|
27626
|
+
if (config2.keychain !== undefined) {
|
|
27627
|
+
merged.keychain = config2.keychain;
|
|
27628
|
+
}
|
|
27624
27629
|
if (config2.anthropicApiBilling !== undefined) {
|
|
27625
27630
|
merged.anthropicApiBilling = config2.anthropicApiBilling;
|
|
27626
27631
|
}
|
|
@@ -27910,6 +27915,20 @@ function removeApiKey(envVar) {
|
|
|
27910
27915
|
saveConfig(config2);
|
|
27911
27916
|
}
|
|
27912
27917
|
}
|
|
27918
|
+
function isKeychainEnabled() {
|
|
27919
|
+
try {
|
|
27920
|
+
return loadConfig().keychain?.enabled === true;
|
|
27921
|
+
} catch {
|
|
27922
|
+
return false;
|
|
27923
|
+
}
|
|
27924
|
+
}
|
|
27925
|
+
function setKeychainEnabled(enabled) {
|
|
27926
|
+
const config2 = loadConfig();
|
|
27927
|
+
if (!config2.keychain)
|
|
27928
|
+
config2.keychain = {};
|
|
27929
|
+
config2.keychain.enabled = enabled;
|
|
27930
|
+
saveConfig(config2);
|
|
27931
|
+
}
|
|
27913
27932
|
function getEndpoint(name) {
|
|
27914
27933
|
const config2 = loadConfig();
|
|
27915
27934
|
return config2.endpoints?.[name];
|
|
@@ -31940,13 +31959,20 @@ function defaultDeleteStore() {
|
|
|
31940
31959
|
function defaultRunAgyRefresh() {
|
|
31941
31960
|
const agy = locateAgyBinary();
|
|
31942
31961
|
if (!agy)
|
|
31943
|
-
return;
|
|
31962
|
+
return { kind: "not-installed" };
|
|
31944
31963
|
try {
|
|
31945
31964
|
execFileSync(agy, ["models"], {
|
|
31946
|
-
stdio: ["ignore", "ignore", "
|
|
31965
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
31966
|
+
encoding: "utf8",
|
|
31947
31967
|
timeout: AGY_REFRESH_TIMEOUT_MS
|
|
31948
31968
|
});
|
|
31949
|
-
|
|
31969
|
+
return { kind: "ran" };
|
|
31970
|
+
} catch (err) {
|
|
31971
|
+
const e = err;
|
|
31972
|
+
if (e.code === "ETIMEDOUT" || e.signal === "SIGTERM")
|
|
31973
|
+
return { kind: "timeout" };
|
|
31974
|
+
return { kind: "failed", detail: (e.stderr ?? "").trim().slice(0, 300) };
|
|
31975
|
+
} finally {
|
|
31950
31976
|
invalidateReadStoreMemo();
|
|
31951
31977
|
}
|
|
31952
31978
|
}
|
|
@@ -32019,13 +32045,25 @@ async function resolveValidToken(deps) {
|
|
|
32019
32045
|
return rec.token.access_token;
|
|
32020
32046
|
}
|
|
32021
32047
|
log("[Antigravity] Access token expired/near-expiry \u2014 asking the Antigravity CLI to refresh.");
|
|
32022
|
-
deps.runAgyRefresh();
|
|
32048
|
+
const outcome = deps.runAgyRefresh();
|
|
32023
32049
|
const refreshedRec = parseRecord(deps.readStore());
|
|
32024
32050
|
if (refreshedRec && !needsRefresh(refreshedRec.token, deps.now())) {
|
|
32025
32051
|
log("[Antigravity] Shared token refreshed by the Antigravity CLI.");
|
|
32026
32052
|
return refreshedRec.token.access_token;
|
|
32027
32053
|
}
|
|
32028
|
-
throw new Error(
|
|
32054
|
+
throw new Error(`[Antigravity] ${describeRefreshFailure(outcome)}`);
|
|
32055
|
+
}
|
|
32056
|
+
function describeRefreshFailure(outcome) {
|
|
32057
|
+
switch (outcome.kind) {
|
|
32058
|
+
case "not-installed":
|
|
32059
|
+
return "The Antigravity CLI (`agy`) is not installed, so the expired session could not be " + "refreshed. Run `claudish login antigravity` \u2014 it installs and authenticates it.";
|
|
32060
|
+
case "timeout":
|
|
32061
|
+
return `The Antigravity CLI did not finish within ${Math.round(AGY_REFRESH_TIMEOUT_MS / 1000)}s, ` + "so the session could not be refreshed. `agy` auto-updates itself (a large download) " + "and is unusably slow while it does \u2014 this usually clears on its own. Try again in a " + "minute; run `agy models` to see what it is doing. You are most likely still signed in.";
|
|
32062
|
+
case "failed":
|
|
32063
|
+
return "The Antigravity CLI could not refresh the session" + (outcome.detail ? `: ${outcome.detail}` : ".") + " If it reports being signed out, run `claudish login antigravity`.";
|
|
32064
|
+
default:
|
|
32065
|
+
return "The Antigravity session is expired and the Antigravity CLI refreshed it without " + "producing a valid token \u2014 the session has most likely been revoked. " + "Run `claudish login antigravity`.";
|
|
32066
|
+
}
|
|
32029
32067
|
}
|
|
32030
32068
|
function getValidAntigravityAccessToken(deps = defaultDeps) {
|
|
32031
32069
|
if (inFlight)
|
|
@@ -32065,7 +32103,7 @@ function _resetAntigravityTokenState() {
|
|
|
32065
32103
|
cachedHasToken = null;
|
|
32066
32104
|
invalidateReadStoreMemo();
|
|
32067
32105
|
}
|
|
32068
|
-
var KC_SERVICE = "gemini", KC_ACCOUNT = "antigravity", PREFIX = "go-keyring-base64:", EXPIRY_SKEW_MS = 120000, AGY_REFRESH_TIMEOUT_MS =
|
|
32106
|
+
var KC_SERVICE = "gemini", KC_ACCOUNT = "antigravity", PREFIX = "go-keyring-base64:", EXPIRY_SKEW_MS = 120000, AGY_REFRESH_TIMEOUT_MS = 12000, READ_STORE_TTL_MS = 3000, cachedRawStore = null, defaultDeps, cachedHasToken = null, HAS_TOKEN_TTL_MS = 5000, inFlight = null;
|
|
32069
32107
|
var init_antigravity_token = __esm(() => {
|
|
32070
32108
|
init_logger();
|
|
32071
32109
|
defaultDeps = {
|
|
@@ -32081,6 +32119,7 @@ var init_antigravity_token = __esm(() => {
|
|
|
32081
32119
|
var exports_antigravity_user = {};
|
|
32082
32120
|
__export(exports_antigravity_user, {
|
|
32083
32121
|
_resetAntigravityServedModelsCache: () => _resetAntigravityServedModelsCache,
|
|
32122
|
+
antigravityHost: () => antigravityHost,
|
|
32084
32123
|
buildAntigravityUserAgent: () => buildAntigravityUserAgent,
|
|
32085
32124
|
getAntigravityTierDisplayName: () => getAntigravityTierDisplayName,
|
|
32086
32125
|
getAntigravityTierFullName: () => getAntigravityTierFullName,
|
|
@@ -32089,6 +32128,13 @@ __export(exports_antigravity_user, {
|
|
|
32089
32128
|
retrieveUserQuota: () => retrieveUserQuota,
|
|
32090
32129
|
setupAntigravityUser: () => setupAntigravityUser
|
|
32091
32130
|
});
|
|
32131
|
+
function antigravityHost() {
|
|
32132
|
+
const override = process.env.AICODE_ENDPOINT_URL?.trim();
|
|
32133
|
+
return override ? override.replace(/\/+$/, "") : ANTIGRAVITY_DEFAULT_HOST;
|
|
32134
|
+
}
|
|
32135
|
+
function apiBase() {
|
|
32136
|
+
return `${antigravityHost()}/v1internal`;
|
|
32137
|
+
}
|
|
32092
32138
|
function makeTerminalSetupError(message) {
|
|
32093
32139
|
const err = new Error(message);
|
|
32094
32140
|
err.terminal = true;
|
|
@@ -32105,7 +32151,7 @@ function resetAntigravityUserCache() {
|
|
|
32105
32151
|
agServedCacheAt = 0;
|
|
32106
32152
|
}
|
|
32107
32153
|
async function callLoadCodeAssistAntigravity(accessToken) {
|
|
32108
|
-
const res = await fetch(`${
|
|
32154
|
+
const res = await fetch(`${apiBase()}:loadCodeAssist`, {
|
|
32109
32155
|
method: "POST",
|
|
32110
32156
|
headers: {
|
|
32111
32157
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -32153,7 +32199,7 @@ function getAntigravityTierFullName() {
|
|
|
32153
32199
|
}
|
|
32154
32200
|
async function retrieveUserQuota(accessToken, projectId) {
|
|
32155
32201
|
try {
|
|
32156
|
-
const res = await fetch(`${
|
|
32202
|
+
const res = await fetch(`${apiBase()}:retrieveUserQuota`, {
|
|
32157
32203
|
method: "POST",
|
|
32158
32204
|
headers: {
|
|
32159
32205
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -32178,7 +32224,7 @@ async function getServedAntigravityModels(accessToken, projectId, opts) {
|
|
|
32178
32224
|
return agServedCache;
|
|
32179
32225
|
}
|
|
32180
32226
|
try {
|
|
32181
|
-
const res = await fetch(`${
|
|
32227
|
+
const res = await fetch(`${apiBase()}:fetchAvailableModels`, {
|
|
32182
32228
|
method: "POST",
|
|
32183
32229
|
headers: {
|
|
32184
32230
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -32206,7 +32252,26 @@ async function getServedAntigravityModels(accessToken, projectId, opts) {
|
|
|
32206
32252
|
}
|
|
32207
32253
|
meta3[id] = entry;
|
|
32208
32254
|
}
|
|
32209
|
-
|
|
32255
|
+
const excludedIds = new Set;
|
|
32256
|
+
for (const [id, record4] of Object.entries(data.models ?? {})) {
|
|
32257
|
+
if (record4?.isInternal === true)
|
|
32258
|
+
excludedIds.add(id);
|
|
32259
|
+
}
|
|
32260
|
+
for (const list of [
|
|
32261
|
+
data.tabModelIds,
|
|
32262
|
+
data.imageGenerationModelIds,
|
|
32263
|
+
data.audioTranscriptionModelIds
|
|
32264
|
+
]) {
|
|
32265
|
+
for (const id of list ?? [])
|
|
32266
|
+
excludedIds.add(id);
|
|
32267
|
+
}
|
|
32268
|
+
const deprecatedReplacements = {};
|
|
32269
|
+
for (const [oldId, info] of Object.entries(data.deprecatedModelIds ?? {})) {
|
|
32270
|
+
excludedIds.add(oldId);
|
|
32271
|
+
if (info?.newModelId)
|
|
32272
|
+
deprecatedReplacements[oldId] = info.newModelId;
|
|
32273
|
+
}
|
|
32274
|
+
agServedCache = { servedIds, defaultId, meta: meta3, excludedIds, deprecatedReplacements };
|
|
32210
32275
|
agServedCacheAt = now;
|
|
32211
32276
|
return agServedCache;
|
|
32212
32277
|
}
|
|
@@ -32224,7 +32289,7 @@ function _resetAntigravityServedModelsCache() {
|
|
|
32224
32289
|
agServedCache = null;
|
|
32225
32290
|
agServedCacheAt = 0;
|
|
32226
32291
|
}
|
|
32227
|
-
var
|
|
32292
|
+
var ANTIGRAVITY_DEFAULT_HOST = "https://daily-cloudcode-pa.googleapis.com", SERVED_MODELS_TTL_MS, ANTIGRAVITY_IDE_TYPE = "ANTIGRAVITY", cachedAgProjectId = null, cachedAgTierId = null, cachedAgTierName = null, agServedCache = null, agServedCacheAt = 0;
|
|
32228
32293
|
var init_antigravity_user = __esm(() => {
|
|
32229
32294
|
init_logger();
|
|
32230
32295
|
SERVED_MODELS_TTL_MS = 10 * 60 * 1000;
|
|
@@ -35117,26 +35182,35 @@ function hasQuotaExhaustionWording(errorBody) {
|
|
|
35117
35182
|
const lower = (errorBody || "").toLowerCase();
|
|
35118
35183
|
return EXHAUSTION_PHRASES.some((phrase) => lower.includes(phrase));
|
|
35119
35184
|
}
|
|
35185
|
+
function hasPlanLimitWording(errorBody) {
|
|
35186
|
+
const lower = (errorBody || "").toLowerCase();
|
|
35187
|
+
if (BALANCE_PHRASES.some((phrase) => lower.includes(phrase)))
|
|
35188
|
+
return false;
|
|
35189
|
+
return PLAN_LIMIT_PHRASES.some((phrase) => lower.includes(phrase));
|
|
35190
|
+
}
|
|
35120
35191
|
function isQuotaExhaustionError(status, errorBody) {
|
|
35121
35192
|
if (status !== 401 && status !== 403 && status !== 429)
|
|
35122
35193
|
return false;
|
|
35123
35194
|
return hasQuotaExhaustionWording(errorBody);
|
|
35124
35195
|
}
|
|
35125
|
-
var EXHAUSTION_PHRASES;
|
|
35196
|
+
var BALANCE_PHRASES, PLAN_LIMIT_PHRASES, EXHAUSTION_PHRASES;
|
|
35126
35197
|
var init_quota_exhaustion = __esm(() => {
|
|
35127
|
-
|
|
35198
|
+
BALANCE_PHRASES = [
|
|
35199
|
+
"insufficient balance",
|
|
35200
|
+
"insufficient_quota",
|
|
35201
|
+
"out of credits",
|
|
35202
|
+
"credit balance"
|
|
35203
|
+
];
|
|
35204
|
+
PLAN_LIMIT_PHRASES = [
|
|
35128
35205
|
"usage limit",
|
|
35129
35206
|
"billing cycle",
|
|
35130
35207
|
"quota",
|
|
35131
|
-
"insufficient balance",
|
|
35132
|
-
"insufficient_quota",
|
|
35133
35208
|
"upgrade your plan",
|
|
35134
35209
|
"exceeded your current",
|
|
35135
|
-
"out of credits",
|
|
35136
|
-
"credit balance",
|
|
35137
35210
|
"daily limit",
|
|
35138
35211
|
"plan limit"
|
|
35139
35212
|
];
|
|
35213
|
+
EXHAUSTION_PHRASES = [...BALANCE_PHRASES, ...PLAN_LIMIT_PHRASES];
|
|
35140
35214
|
});
|
|
35141
35215
|
|
|
35142
35216
|
// src/handlers/shared/gemini-queue.ts
|
|
@@ -35277,6 +35351,9 @@ var init_gemini_queue = __esm(() => {
|
|
|
35277
35351
|
|
|
35278
35352
|
// src/providers/transport/antigravity.ts
|
|
35279
35353
|
import { randomUUID } from "crypto";
|
|
35354
|
+
function antigravityEndpoint() {
|
|
35355
|
+
return `${antigravityHost()}/v1internal:streamGenerateContent?alt=sse`;
|
|
35356
|
+
}
|
|
35280
35357
|
function rankReasoningSuffix(suffix) {
|
|
35281
35358
|
const rank = REASONING_TIER_RANK[suffix.toLowerCase()];
|
|
35282
35359
|
return rank === undefined ? Number.MAX_SAFE_INTEGER : rank;
|
|
@@ -35343,7 +35420,12 @@ function classify429(responseBody) {
|
|
|
35343
35420
|
return { terminal: false, retryDelayMs: retryDelayMs ?? 60000, reason };
|
|
35344
35421
|
}
|
|
35345
35422
|
}
|
|
35346
|
-
return {
|
|
35423
|
+
return {
|
|
35424
|
+
terminal: false,
|
|
35425
|
+
retryDelayMs,
|
|
35426
|
+
reason,
|
|
35427
|
+
unattributed: reason === undefined && retryDelayMs === undefined
|
|
35428
|
+
};
|
|
35347
35429
|
} catch {
|
|
35348
35430
|
return null;
|
|
35349
35431
|
}
|
|
@@ -35389,7 +35471,7 @@ class AntigravityProviderTransport {
|
|
|
35389
35471
|
return this._activeModelName;
|
|
35390
35472
|
}
|
|
35391
35473
|
getEndpoint() {
|
|
35392
|
-
return
|
|
35474
|
+
return antigravityEndpoint();
|
|
35393
35475
|
}
|
|
35394
35476
|
async getHeaders() {
|
|
35395
35477
|
if (this.cachedAuth)
|
|
@@ -35477,8 +35559,8 @@ class AntigravityProviderTransport {
|
|
|
35477
35559
|
return await this.explainTerminalQuota(response, bodyText, classification.reason);
|
|
35478
35560
|
}
|
|
35479
35561
|
if (attempt < MAX_RETRY_ATTEMPTS) {
|
|
35480
|
-
const delay = classification.retryDelayMs ?? DEFAULT_RATE_LIMIT_DELAY_MS;
|
|
35481
|
-
logStderr(`[Antigravity] Rate limited (${classification.reason || "
|
|
35562
|
+
const delay = classification.retryDelayMs ?? (classification.unattributed ? UNATTRIBUTED_RETRY_DELAY_MS : DEFAULT_RATE_LIMIT_DELAY_MS);
|
|
35563
|
+
logStderr(`[Antigravity] Rate limited (${classification.reason || "unattributed \u2014 server gave no reason or retry delay"}), retrying in ${(delay / 1000).toFixed(1)}s (attempt ${attempt}/${MAX_RETRY_ATTEMPTS})`);
|
|
35482
35564
|
if (attempt === 1) {
|
|
35483
35565
|
await this.logQuotaInfo();
|
|
35484
35566
|
}
|
|
@@ -35665,7 +35747,7 @@ ${lines.join(`
|
|
|
35665
35747
|
}
|
|
35666
35748
|
}
|
|
35667
35749
|
}
|
|
35668
|
-
var
|
|
35750
|
+
var MAX_RETRY_ATTEMPTS = 3, DEFAULT_RATE_LIMIT_DELAY_MS = 1e4, UNATTRIBUTED_RETRY_DELAY_MS = 1000, QUOTA_CHECK_TIMEOUT_MS = 3000, REASONING_TIER_RANK;
|
|
35669
35751
|
var init_antigravity2 = __esm(() => {
|
|
35670
35752
|
init_model_catalog();
|
|
35671
35753
|
init_antigravity_token();
|
|
@@ -35673,7 +35755,6 @@ var init_antigravity2 = __esm(() => {
|
|
|
35673
35755
|
init_authority();
|
|
35674
35756
|
init_gemini_queue();
|
|
35675
35757
|
init_logger();
|
|
35676
|
-
ANTIGRAVITY_ENDPOINT = `${ANTIGRAVITY_BASE}/v1internal:streamGenerateContent?alt=sse`;
|
|
35677
35758
|
REASONING_TIER_RANK = {
|
|
35678
35759
|
high: 0,
|
|
35679
35760
|
medium: 1,
|
|
@@ -35731,6 +35812,257 @@ var init_antigravity_credential = __esm(() => {
|
|
|
35731
35812
|
init_antigravity_user();
|
|
35732
35813
|
});
|
|
35733
35814
|
|
|
35815
|
+
// src/providers/keychain.ts
|
|
35816
|
+
function syncRun(args, stdin) {
|
|
35817
|
+
try {
|
|
35818
|
+
const proc = Bun.spawnSync([SECURITY_BIN, ...args], {
|
|
35819
|
+
stdin: stdin === undefined ? "ignore" : new TextEncoder().encode(stdin),
|
|
35820
|
+
stdout: "pipe",
|
|
35821
|
+
stderr: "pipe",
|
|
35822
|
+
timeout: SPAWN_TIMEOUT_MS
|
|
35823
|
+
});
|
|
35824
|
+
return normalizeResult(proc.exitCode, proc.signalCode, decode3(proc.stdout), decode3(proc.stderr));
|
|
35825
|
+
} catch (err) {
|
|
35826
|
+
return { code: 1, stdout: "", stderr: err instanceof Error ? err.message : String(err) };
|
|
35827
|
+
}
|
|
35828
|
+
}
|
|
35829
|
+
async function asyncRun(args, stdin) {
|
|
35830
|
+
try {
|
|
35831
|
+
const proc = Bun.spawn([SECURITY_BIN, ...args], {
|
|
35832
|
+
stdin: stdin === undefined ? "ignore" : new TextEncoder().encode(stdin),
|
|
35833
|
+
stdout: "pipe",
|
|
35834
|
+
stderr: "pipe",
|
|
35835
|
+
timeout: SPAWN_TIMEOUT_MS
|
|
35836
|
+
});
|
|
35837
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
35838
|
+
new Response(proc.stdout).text(),
|
|
35839
|
+
new Response(proc.stderr).text(),
|
|
35840
|
+
proc.exited
|
|
35841
|
+
]);
|
|
35842
|
+
return normalizeResult(exitCode, proc.signalCode, stdout, stderr);
|
|
35843
|
+
} catch (err) {
|
|
35844
|
+
return { code: 1, stdout: "", stderr: err instanceof Error ? err.message : String(err) };
|
|
35845
|
+
}
|
|
35846
|
+
}
|
|
35847
|
+
function decode3(buf) {
|
|
35848
|
+
return buf ? new TextDecoder().decode(buf) : "";
|
|
35849
|
+
}
|
|
35850
|
+
function normalizeResult(exitCode, signalCode, stdout, stderr) {
|
|
35851
|
+
if (typeof exitCode === "number")
|
|
35852
|
+
return { code: exitCode, stdout, stderr };
|
|
35853
|
+
const detail = signalCode ? `killed by ${signalCode}` : "terminated without an exit code";
|
|
35854
|
+
return { code: -1, stdout, stderr: stderr.trim() || `security ${detail}` };
|
|
35855
|
+
}
|
|
35856
|
+
function invalidateKeychainCache() {
|
|
35857
|
+
listMemo = null;
|
|
35858
|
+
valueMemo.clear();
|
|
35859
|
+
}
|
|
35860
|
+
function now() {
|
|
35861
|
+
return Date.now();
|
|
35862
|
+
}
|
|
35863
|
+
function isValidKeychainVarName(name) {
|
|
35864
|
+
return ENV_VAR_NAME.test(name);
|
|
35865
|
+
}
|
|
35866
|
+
function describeUnstorableValue(value) {
|
|
35867
|
+
if (value.length === 0)
|
|
35868
|
+
return "value is empty";
|
|
35869
|
+
if (CONTROL_CHARS.test(value)) {
|
|
35870
|
+
return "value contains control characters (tab/newline/etc), which the keychain read path cannot represent unambiguously";
|
|
35871
|
+
}
|
|
35872
|
+
return null;
|
|
35873
|
+
}
|
|
35874
|
+
function isKeychainSupported() {
|
|
35875
|
+
return deps.platform() === "darwin";
|
|
35876
|
+
}
|
|
35877
|
+
function keychainUnavailableReason() {
|
|
35878
|
+
if (!isKeychainSupported()) {
|
|
35879
|
+
return `the macOS Keychain is only available on macOS (this is ${deps.platform()})`;
|
|
35880
|
+
}
|
|
35881
|
+
return null;
|
|
35882
|
+
}
|
|
35883
|
+
function stripOneTrailingNewline(out) {
|
|
35884
|
+
return out.endsWith(`
|
|
35885
|
+
`) ? out.slice(0, -1) : out;
|
|
35886
|
+
}
|
|
35887
|
+
function keychainFileArgs() {
|
|
35888
|
+
const file2 = process.env.CLAUDISH_KEYCHAIN_FILE;
|
|
35889
|
+
return file2 ? [file2] : [];
|
|
35890
|
+
}
|
|
35891
|
+
function findArgs(envVar) {
|
|
35892
|
+
return [
|
|
35893
|
+
"find-generic-password",
|
|
35894
|
+
"-s",
|
|
35895
|
+
KEYCHAIN_SERVICE,
|
|
35896
|
+
"-a",
|
|
35897
|
+
envVar,
|
|
35898
|
+
"-w",
|
|
35899
|
+
...keychainFileArgs()
|
|
35900
|
+
];
|
|
35901
|
+
}
|
|
35902
|
+
function interpretRead(envVar, res) {
|
|
35903
|
+
if (res.code === 0) {
|
|
35904
|
+
const value = stripOneTrailingNewline(res.stdout);
|
|
35905
|
+
return value.length > 0 ? value : null;
|
|
35906
|
+
}
|
|
35907
|
+
if (res.code === EXIT_ITEM_NOT_FOUND)
|
|
35908
|
+
return null;
|
|
35909
|
+
throw new KeychainError(`Keychain lookup for ${envVar} failed: ${res.stderr.trim() || `security exited ${res.code}`}`, res.code);
|
|
35910
|
+
}
|
|
35911
|
+
function readKeychainSecret(envVar) {
|
|
35912
|
+
if (!isKeychainSupported())
|
|
35913
|
+
return null;
|
|
35914
|
+
const cached2 = valueMemo.get(envVar);
|
|
35915
|
+
const at = now();
|
|
35916
|
+
if (cached2 && at - cached2.at < MEMO_TTL_MS)
|
|
35917
|
+
return cached2.value;
|
|
35918
|
+
const value = interpretRead(envVar, deps.run(findArgs(envVar)));
|
|
35919
|
+
valueMemo.set(envVar, { at, value });
|
|
35920
|
+
return value;
|
|
35921
|
+
}
|
|
35922
|
+
async function readKeychainSecretAsync(envVar) {
|
|
35923
|
+
if (!isKeychainSupported())
|
|
35924
|
+
return null;
|
|
35925
|
+
const cached2 = valueMemo.get(envVar);
|
|
35926
|
+
const at = now();
|
|
35927
|
+
if (cached2 && at - cached2.at < MEMO_TTL_MS)
|
|
35928
|
+
return cached2.value;
|
|
35929
|
+
const value = interpretRead(envVar, await deps.runAsync(findArgs(envVar)));
|
|
35930
|
+
valueMemo.set(envVar, { at, value });
|
|
35931
|
+
return value;
|
|
35932
|
+
}
|
|
35933
|
+
function enumerateKeychainVars() {
|
|
35934
|
+
if (!isKeychainSupported())
|
|
35935
|
+
return { names: [], failed: false };
|
|
35936
|
+
const at = now();
|
|
35937
|
+
if (listMemo && at - listMemo.at < MEMO_TTL_MS)
|
|
35938
|
+
return listMemo.value;
|
|
35939
|
+
const res = deps.run(["dump-keychain", ...keychainFileArgs()]);
|
|
35940
|
+
const value = res.code === 0 ? { names: parseDumpAccounts(res.stdout), failed: false } : {
|
|
35941
|
+
names: [],
|
|
35942
|
+
failed: true,
|
|
35943
|
+
error: res.stderr.trim() || `security exited ${res.code}`
|
|
35944
|
+
};
|
|
35945
|
+
listMemo = { at, value };
|
|
35946
|
+
return value;
|
|
35947
|
+
}
|
|
35948
|
+
function listKeychainVars() {
|
|
35949
|
+
return enumerateKeychainVars().names;
|
|
35950
|
+
}
|
|
35951
|
+
function parseDumpAccounts(dump) {
|
|
35952
|
+
const found = new Set;
|
|
35953
|
+
for (const block of dump.split(/\nkeychain: /)) {
|
|
35954
|
+
if (!block.includes(SVCE_MATCH))
|
|
35955
|
+
continue;
|
|
35956
|
+
const m = block.match(ACCT_ATTR);
|
|
35957
|
+
if (m?.[1] && isValidKeychainVarName(m[1]))
|
|
35958
|
+
found.add(m[1]);
|
|
35959
|
+
}
|
|
35960
|
+
return Array.from(found).sort();
|
|
35961
|
+
}
|
|
35962
|
+
function lookupKeychainVar(envVar) {
|
|
35963
|
+
if (!isKeychainSupported())
|
|
35964
|
+
return { present: false, failed: false };
|
|
35965
|
+
const cached2 = valueMemo.get(envVar);
|
|
35966
|
+
if (cached2 && now() - cached2.at < MEMO_TTL_MS && cached2.value !== null) {
|
|
35967
|
+
return { present: true, failed: false };
|
|
35968
|
+
}
|
|
35969
|
+
const listed = enumerateKeychainVars();
|
|
35970
|
+
return { present: listed.names.includes(envVar), failed: listed.failed };
|
|
35971
|
+
}
|
|
35972
|
+
function toHex(value) {
|
|
35973
|
+
return Buffer.from(value, "utf8").toString("hex");
|
|
35974
|
+
}
|
|
35975
|
+
function quoteForStdin(value) {
|
|
35976
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
35977
|
+
}
|
|
35978
|
+
function writeKeychainSecret(envVar, value) {
|
|
35979
|
+
const unsupported2 = keychainUnavailableReason();
|
|
35980
|
+
if (unsupported2)
|
|
35981
|
+
throw new KeychainError(`Cannot write ${envVar}: ${unsupported2}`);
|
|
35982
|
+
if (!isValidKeychainVarName(envVar)) {
|
|
35983
|
+
throw new KeychainError(`Cannot write "${envVar}": not a valid environment variable name`);
|
|
35984
|
+
}
|
|
35985
|
+
const unstorable = describeUnstorableValue(value);
|
|
35986
|
+
if (unstorable)
|
|
35987
|
+
throw new KeychainError(`Cannot store ${envVar}: ${unstorable}`);
|
|
35988
|
+
invalidateKeychainCache();
|
|
35989
|
+
const cmd = [
|
|
35990
|
+
"add-generic-password",
|
|
35991
|
+
"-s",
|
|
35992
|
+
quoteForStdin(KEYCHAIN_SERVICE),
|
|
35993
|
+
"-a",
|
|
35994
|
+
quoteForStdin(envVar),
|
|
35995
|
+
"-l",
|
|
35996
|
+
quoteForStdin(`${KEYCHAIN_SERVICE}: ${envVar}`),
|
|
35997
|
+
"-D",
|
|
35998
|
+
quoteForStdin("application password"),
|
|
35999
|
+
"-j",
|
|
36000
|
+
quoteForStdin("Stored by claudish"),
|
|
36001
|
+
"-X",
|
|
36002
|
+
quoteForStdin(toHex(value)),
|
|
36003
|
+
"-U",
|
|
36004
|
+
"-T",
|
|
36005
|
+
quoteForStdin(SECURITY_BIN),
|
|
36006
|
+
...keychainFileArgs().map(quoteForStdin)
|
|
36007
|
+
].join(" ");
|
|
36008
|
+
const res = deps.run(["-i"], `${cmd}
|
|
36009
|
+
`);
|
|
36010
|
+
if (res.code !== 0) {
|
|
36011
|
+
throw new KeychainError(`Failed to store ${envVar} in the keychain: ${res.stderr.trim() || `security exited ${res.code}`}`, res.code);
|
|
36012
|
+
}
|
|
36013
|
+
invalidateKeychainCache();
|
|
36014
|
+
const readBack = readKeychainSecret(envVar);
|
|
36015
|
+
if (readBack !== value) {
|
|
36016
|
+
throw new KeychainError(`Keychain write for ${envVar} did not round-trip \u2014 the stored value differs from what was written. ` + "The item may exceed the keychain's size limit; nothing should be assumed saved.");
|
|
36017
|
+
}
|
|
36018
|
+
}
|
|
36019
|
+
function deleteKeychainSecret(envVar) {
|
|
36020
|
+
if (!isKeychainSupported())
|
|
36021
|
+
return false;
|
|
36022
|
+
invalidateKeychainCache();
|
|
36023
|
+
const res = deps.run([
|
|
36024
|
+
"delete-generic-password",
|
|
36025
|
+
"-s",
|
|
36026
|
+
KEYCHAIN_SERVICE,
|
|
36027
|
+
"-a",
|
|
36028
|
+
envVar,
|
|
36029
|
+
...keychainFileArgs()
|
|
36030
|
+
]);
|
|
36031
|
+
invalidateKeychainCache();
|
|
36032
|
+
if (res.code === 0)
|
|
36033
|
+
return true;
|
|
36034
|
+
if (res.code === EXIT_ITEM_NOT_FOUND)
|
|
36035
|
+
return false;
|
|
36036
|
+
throw new KeychainError(`Failed to delete ${envVar} from the keychain: ${res.stderr.trim() || `security exited ${res.code}`}`, res.code);
|
|
36037
|
+
}
|
|
36038
|
+
function valueTail2(value) {
|
|
36039
|
+
if (value.length <= 6)
|
|
36040
|
+
return "\u2022\u2022\u2022\u2022";
|
|
36041
|
+
return `\u2022\u2022\u2022\u2022${value.slice(-4)}`;
|
|
36042
|
+
}
|
|
36043
|
+
var KEYCHAIN_SERVICE = "claudish", SECURITY_BIN = "/usr/bin/security", EXIT_ITEM_NOT_FOUND = 44, MEMO_TTL_MS = 3000, SPAWN_TIMEOUT_MS = 1e4, KeychainError, defaultDeps2, deps, listMemo = null, valueMemo, CONTROL_CHARS, ENV_VAR_NAME, ACCT_ATTR, SVCE_MATCH;
|
|
36044
|
+
var init_keychain = __esm(() => {
|
|
36045
|
+
KeychainError = class KeychainError extends Error {
|
|
36046
|
+
exitCode;
|
|
36047
|
+
constructor(message, exitCode) {
|
|
36048
|
+
super(message);
|
|
36049
|
+
this.exitCode = exitCode;
|
|
36050
|
+
this.name = "KeychainError";
|
|
36051
|
+
}
|
|
36052
|
+
};
|
|
36053
|
+
defaultDeps2 = {
|
|
36054
|
+
platform: () => process.platform,
|
|
36055
|
+
run: syncRun,
|
|
36056
|
+
runAsync: asyncRun
|
|
36057
|
+
};
|
|
36058
|
+
deps = defaultDeps2;
|
|
36059
|
+
valueMemo = new Map;
|
|
36060
|
+
CONTROL_CHARS = /[\u0000-\u001F\u007F]/;
|
|
36061
|
+
ENV_VAR_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
36062
|
+
ACCT_ATTR = /"acct"<blob>=(?:0x[0-9A-Fa-f]*\s+)?"([^"]*)"/;
|
|
36063
|
+
SVCE_MATCH = `"svce"<blob>="${KEYCHAIN_SERVICE}"`;
|
|
36064
|
+
});
|
|
36065
|
+
|
|
35734
36066
|
// src/auth/credentials/local-api-key.ts
|
|
35735
36067
|
function resolveLocalApiKey(q) {
|
|
35736
36068
|
return realValue(process.env[q.envVar]) || (q.aliases ?? []).map((a) => realValue(process.env[a])).find((v) => !!v) || realValue(getApiKey(q.envVar));
|
|
@@ -35747,6 +36079,108 @@ var init_local_api_key = __esm(() => {
|
|
|
35747
36079
|
init_profile_config();
|
|
35748
36080
|
});
|
|
35749
36081
|
|
|
36082
|
+
// src/auth/credentials/keychain-source.ts
|
|
36083
|
+
function warnOnce2(message) {
|
|
36084
|
+
if (warnedMessages2.has(message))
|
|
36085
|
+
return;
|
|
36086
|
+
warnedMessages2.add(message);
|
|
36087
|
+
console.error(message);
|
|
36088
|
+
}
|
|
36089
|
+
function recordKeychainHydratedVar(envVar) {
|
|
36090
|
+
hydratedVars.add(envVar);
|
|
36091
|
+
}
|
|
36092
|
+
function isKeychainHydratedVar(envVar) {
|
|
36093
|
+
return hydratedVars.has(envVar);
|
|
36094
|
+
}
|
|
36095
|
+
function hasKeychainSource() {
|
|
36096
|
+
if (process.env.CLAUDISH_DISABLE_KEYCHAIN === "1")
|
|
36097
|
+
return false;
|
|
36098
|
+
if (!isKeychainSupported())
|
|
36099
|
+
return false;
|
|
36100
|
+
return isKeychainEnabled();
|
|
36101
|
+
}
|
|
36102
|
+
function resolveKeychainKeyForEnvVars(wanted) {
|
|
36103
|
+
if (!hasKeychainSource())
|
|
36104
|
+
return { failed: false };
|
|
36105
|
+
let failed = false;
|
|
36106
|
+
try {
|
|
36107
|
+
for (const name of wanted) {
|
|
36108
|
+
if (!name)
|
|
36109
|
+
continue;
|
|
36110
|
+
const { present, failed: lookupFailed } = lookupKeychainVar(name);
|
|
36111
|
+
if (lookupFailed)
|
|
36112
|
+
failed = true;
|
|
36113
|
+
if (!present)
|
|
36114
|
+
continue;
|
|
36115
|
+
const value = readKeychainSecret(name);
|
|
36116
|
+
if (value)
|
|
36117
|
+
return { value, failed: false };
|
|
36118
|
+
}
|
|
36119
|
+
} catch (err) {
|
|
36120
|
+
warnOnce2(`[claudish] macOS Keychain lookup skipped: ${err instanceof KeychainError ? err.message : String(err)}`);
|
|
36121
|
+
return { failed: true };
|
|
36122
|
+
}
|
|
36123
|
+
if (failed) {
|
|
36124
|
+
warnOnce2("[claudish] macOS Keychain could not be enumerated \u2014 treating this provider as unresolved rather than uncredentialed.");
|
|
36125
|
+
}
|
|
36126
|
+
return { failed };
|
|
36127
|
+
}
|
|
36128
|
+
async function hydrateKeychainIntoEnv() {
|
|
36129
|
+
if (!hasKeychainSource())
|
|
36130
|
+
return 0;
|
|
36131
|
+
let names;
|
|
36132
|
+
try {
|
|
36133
|
+
const listed = enumerateKeychainVars();
|
|
36134
|
+
if (listed.failed) {
|
|
36135
|
+
warnOnce2(`[claudish] macOS Keychain enumeration skipped: ${listed.error ?? "unknown error"}`);
|
|
36136
|
+
return 0;
|
|
36137
|
+
}
|
|
36138
|
+
names = listed.names;
|
|
36139
|
+
} catch (err) {
|
|
36140
|
+
warnOnce2(`[claudish] macOS Keychain enumeration skipped: ${String(err)}`);
|
|
36141
|
+
return 0;
|
|
36142
|
+
}
|
|
36143
|
+
const missing = names.filter((n) => !resolveLocalApiKey({ envVar: n }));
|
|
36144
|
+
if (missing.length === 0)
|
|
36145
|
+
return 0;
|
|
36146
|
+
const results = await Promise.all(missing.map(async (name) => {
|
|
36147
|
+
try {
|
|
36148
|
+
return { name, value: await readKeychainSecretAsync(name) };
|
|
36149
|
+
} catch (err) {
|
|
36150
|
+
warnOnce2(`[claudish] macOS Keychain read for ${name} skipped: ${err instanceof KeychainError ? err.message : String(err)}`);
|
|
36151
|
+
return { name, value: null };
|
|
36152
|
+
}
|
|
36153
|
+
}));
|
|
36154
|
+
let hydrated = 0;
|
|
36155
|
+
for (const { name, value } of results) {
|
|
36156
|
+
if (!value || resolveLocalApiKey({ envVar: name }))
|
|
36157
|
+
continue;
|
|
36158
|
+
process.env[name] = value;
|
|
36159
|
+
recordKeychainHydratedVar(name);
|
|
36160
|
+
hydrated++;
|
|
36161
|
+
}
|
|
36162
|
+
return hydrated;
|
|
36163
|
+
}
|
|
36164
|
+
function keychainHasAnyOf(names) {
|
|
36165
|
+
if (!hasKeychainSource())
|
|
36166
|
+
return false;
|
|
36167
|
+
try {
|
|
36168
|
+
for (const name of names) {
|
|
36169
|
+
if (name && lookupKeychainVar(name).present)
|
|
36170
|
+
return true;
|
|
36171
|
+
}
|
|
36172
|
+
} catch {}
|
|
36173
|
+
return false;
|
|
36174
|
+
}
|
|
36175
|
+
var warnedMessages2, hydratedVars;
|
|
36176
|
+
var init_keychain_source = __esm(() => {
|
|
36177
|
+
init_profile_config();
|
|
36178
|
+
init_keychain();
|
|
36179
|
+
init_local_api_key();
|
|
36180
|
+
warnedMessages2 = new Set;
|
|
36181
|
+
hydratedVars = new Set;
|
|
36182
|
+
});
|
|
36183
|
+
|
|
35750
36184
|
// src/auth/credentials/api-key-credential.ts
|
|
35751
36185
|
import { existsSync as existsSync12 } from "fs";
|
|
35752
36186
|
import { homedir as homedir18 } from "os";
|
|
@@ -35758,7 +36192,6 @@ class ApiKeyCredentialProvider {
|
|
|
35758
36192
|
aliases;
|
|
35759
36193
|
authScheme;
|
|
35760
36194
|
staticHeaders;
|
|
35761
|
-
publicKeyFallback;
|
|
35762
36195
|
oauthFallback;
|
|
35763
36196
|
declaredKey;
|
|
35764
36197
|
cachedKey;
|
|
@@ -35769,7 +36202,6 @@ class ApiKeyCredentialProvider {
|
|
|
35769
36202
|
this.aliases = descriptor.aliases ?? [];
|
|
35770
36203
|
this.authScheme = descriptor.authScheme ?? "bearer";
|
|
35771
36204
|
this.staticHeaders = descriptor.staticHeaders ?? {};
|
|
35772
|
-
this.publicKeyFallback = descriptor.publicKeyFallback;
|
|
35773
36205
|
this.oauthFallback = descriptor.oauthFallback;
|
|
35774
36206
|
this.declaredKey = descriptor.declaredKey;
|
|
35775
36207
|
}
|
|
@@ -35803,6 +36235,17 @@ class ApiKeyCredentialProvider {
|
|
|
35803
36235
|
this.cachedKey = local;
|
|
35804
36236
|
return local;
|
|
35805
36237
|
}
|
|
36238
|
+
let keychainFailed = false;
|
|
36239
|
+
if (hasKeychainSource()) {
|
|
36240
|
+
const kc = resolveKeychainKeyForEnvVars([this.envVar, ...this.aliases]);
|
|
36241
|
+
if (kc.value) {
|
|
36242
|
+
process.env[this.envVar] = kc.value;
|
|
36243
|
+
recordKeychainHydratedVar(this.envVar);
|
|
36244
|
+
this.cachedKey = kc.value;
|
|
36245
|
+
return kc.value;
|
|
36246
|
+
}
|
|
36247
|
+
keychainFailed = kc.failed;
|
|
36248
|
+
}
|
|
35806
36249
|
if (hasOpSources()) {
|
|
35807
36250
|
const wanted = new Set([this.envVar, ...this.aliases]);
|
|
35808
36251
|
const resolved = await resolveOpKeyForEnvVars(wanted, {
|
|
@@ -35817,7 +36260,8 @@ class ApiKeyCredentialProvider {
|
|
|
35817
36260
|
}
|
|
35818
36261
|
return "";
|
|
35819
36262
|
}
|
|
35820
|
-
|
|
36263
|
+
if (!keychainFailed)
|
|
36264
|
+
this.cachedKey = "";
|
|
35821
36265
|
return "";
|
|
35822
36266
|
})();
|
|
35823
36267
|
try {
|
|
@@ -35829,8 +36273,6 @@ class ApiKeyCredentialProvider {
|
|
|
35829
36273
|
async isAvailable(opts) {
|
|
35830
36274
|
if (this.authScheme === "none")
|
|
35831
36275
|
return true;
|
|
35832
|
-
if (this.publicKeyFallback)
|
|
35833
|
-
return true;
|
|
35834
36276
|
if (this.resolveFromEnvConfig())
|
|
35835
36277
|
return true;
|
|
35836
36278
|
if (this.hasOauthFallbackFile())
|
|
@@ -35846,7 +36288,7 @@ class ApiKeyCredentialProvider {
|
|
|
35846
36288
|
if (this.authScheme === "none") {
|
|
35847
36289
|
return { headers: { ...this.staticHeaders } };
|
|
35848
36290
|
}
|
|
35849
|
-
const key = await this.resolveKey({ allowOpPrompt: ctx.allowOpPrompt })
|
|
36291
|
+
const key = await this.resolveKey({ allowOpPrompt: ctx.allowOpPrompt });
|
|
35850
36292
|
let headers;
|
|
35851
36293
|
if (this.authScheme === "x-api-key") {
|
|
35852
36294
|
headers = { "x-api-key": key, ...this.staticHeaders };
|
|
@@ -35860,6 +36302,7 @@ class ApiKeyCredentialProvider {
|
|
|
35860
36302
|
}
|
|
35861
36303
|
var init_api_key_credential = __esm(() => {
|
|
35862
36304
|
init_env_placeholder();
|
|
36305
|
+
init_keychain_source();
|
|
35863
36306
|
init_local_api_key();
|
|
35864
36307
|
init_op_source();
|
|
35865
36308
|
});
|
|
@@ -37112,7 +37555,6 @@ class CredentialAuthority {
|
|
|
37112
37555
|
envVar: def.apiKeyEnvVar,
|
|
37113
37556
|
aliases: def.apiKeyAliases,
|
|
37114
37557
|
authScheme: normalizeAuthScheme(def.authScheme),
|
|
37115
|
-
publicKeyFallback: def.publicKeyFallback,
|
|
37116
37558
|
oauthFallback: def.oauthFallback
|
|
37117
37559
|
}), [def.name, ...RUNTIME_NAME_ALIASES[def.name] ?? []]);
|
|
37118
37560
|
}
|
|
@@ -37528,8 +37970,8 @@ async function fetchDevinAllowedUids(apiKey) {
|
|
|
37528
37970
|
return uids;
|
|
37529
37971
|
}
|
|
37530
37972
|
async function getServedDevinModels(opts) {
|
|
37531
|
-
const
|
|
37532
|
-
if (!opts?.force && rosterCache &&
|
|
37973
|
+
const now2 = Date.now();
|
|
37974
|
+
if (!opts?.force && rosterCache && now2 - rosterCacheAt < ROSTER_TTL_MS)
|
|
37533
37975
|
return rosterCache;
|
|
37534
37976
|
const apiKey = opts?.apiKey ?? readDevinApiKey();
|
|
37535
37977
|
if (!apiKey)
|
|
@@ -37547,7 +37989,7 @@ async function getServedDevinModels(opts) {
|
|
|
37547
37989
|
log("[Devin] entitlement unknown \u2014 using the full config list (superset)");
|
|
37548
37990
|
}
|
|
37549
37991
|
rosterCache = served;
|
|
37550
|
-
rosterCacheAt =
|
|
37992
|
+
rosterCacheAt = now2;
|
|
37551
37993
|
return served;
|
|
37552
37994
|
} catch (err) {
|
|
37553
37995
|
log(`[Devin] served-model discovery error: ${err}`);
|
|
@@ -37575,12 +38017,12 @@ function nonEmpty(value) {
|
|
|
37575
38017
|
function groupKeyOf(entry) {
|
|
37576
38018
|
return nonEmpty(entry.groupLabel) ?? nonEmpty(entry.family) ?? entry.wireId;
|
|
37577
38019
|
}
|
|
37578
|
-
function offerIsLive(offer,
|
|
38020
|
+
function offerIsLive(offer, now2 = Date.now()) {
|
|
37579
38021
|
if (!offer)
|
|
37580
38022
|
return false;
|
|
37581
38023
|
if (offer.expiresAt === undefined)
|
|
37582
38024
|
return true;
|
|
37583
|
-
return offer.expiresAt * 1000 >
|
|
38025
|
+
return offer.expiresAt * 1000 > now2;
|
|
37584
38026
|
}
|
|
37585
38027
|
|
|
37586
38028
|
// src/providers/model-resolvers/devin.ts
|
|
@@ -37815,6 +38257,9 @@ async function fetchDevinRoster() {
|
|
|
37815
38257
|
return { id: wireId, ...rest };
|
|
37816
38258
|
});
|
|
37817
38259
|
}
|
|
38260
|
+
function isUndeclaredEditorInternal(id) {
|
|
38261
|
+
return id.startsWith("tab_");
|
|
38262
|
+
}
|
|
37818
38263
|
async function fetchAntigravityRoster() {
|
|
37819
38264
|
const { getValidAntigravityAccessToken: getValidAntigravityAccessToken2 } = await Promise.resolve().then(() => (init_antigravity_token(), exports_antigravity_token));
|
|
37820
38265
|
const { setupAntigravityUser: setupAntigravityUser2, getServedAntigravityModels: getServedAntigravityModels2 } = await Promise.resolve().then(() => (init_antigravity_user(), exports_antigravity_user));
|
|
@@ -37822,10 +38267,12 @@ async function fetchAntigravityRoster() {
|
|
|
37822
38267
|
if (!token)
|
|
37823
38268
|
return [];
|
|
37824
38269
|
const { projectId } = await setupAntigravityUser2(token);
|
|
37825
|
-
const { servedIds, meta: meta3 } = await getServedAntigravityModels2(token, projectId);
|
|
37826
|
-
|
|
38270
|
+
const { servedIds, meta: meta3, excludedIds } = await getServedAntigravityModels2(token, projectId);
|
|
38271
|
+
const declaredExcluded = excludedIds ?? new Set;
|
|
38272
|
+
const selectable = servedIds.filter((id) => !declaredExcluded.has(id) && !isUndeclaredEditorInternal(id));
|
|
38273
|
+
return selectable.map((id) => {
|
|
37827
38274
|
const m = meta3[id];
|
|
37828
|
-
return m?.contextWindow ? { id, contextWindow: m.contextWindow } : { id };
|
|
38275
|
+
return m?.contextWindow ? { id, contextWindow: m.contextWindow, ignoreCatalogReleaseDate: true } : { id, ignoreCatalogReleaseDate: true };
|
|
37829
38276
|
});
|
|
37830
38277
|
}
|
|
37831
38278
|
async function fetchOllamaRoster() {
|
|
@@ -38752,13 +39199,6 @@ var init_vision_proxy = __esm(() => {
|
|
|
38752
39199
|
});
|
|
38753
39200
|
|
|
38754
39201
|
// src/providers/model-parser.ts
|
|
38755
|
-
function warnGoAliasDeprecatedOnce() {
|
|
38756
|
-
if (_goDeprecationWarned)
|
|
38757
|
-
return;
|
|
38758
|
-
_goDeprecationWarned = true;
|
|
38759
|
-
process.stderr.write(`[claudish] go@ is deprecated \u2014 use ag@<model> (Antigravity). Routing there.
|
|
38760
|
-
`);
|
|
38761
|
-
}
|
|
38762
39202
|
function parseModelChain(modelSpec) {
|
|
38763
39203
|
const parts = modelSpec.split(MODEL_CHAIN_SEPARATOR).map((s) => s.trim()).filter(Boolean);
|
|
38764
39204
|
return parts.length > 0 ? parts : [modelSpec];
|
|
@@ -38785,8 +39225,6 @@ function parseModelSpec(modelSpec) {
|
|
|
38785
39225
|
concurrency = Number.parseInt(concurrencyMatch[2], 10);
|
|
38786
39226
|
}
|
|
38787
39227
|
const provider = PROVIDER_SHORTCUTS[providerPart] || providerPart;
|
|
38788
|
-
if (providerPart === "go")
|
|
38789
|
-
warnGoAliasDeprecatedOnce();
|
|
38790
39228
|
return {
|
|
38791
39229
|
provider,
|
|
38792
39230
|
model: modelPart,
|
|
@@ -38800,8 +39238,6 @@ function parseModelSpec(modelSpec) {
|
|
|
38800
39238
|
for (const { prefix, provider, stripPrefix } of LEGACY_PREFIX_PATTERNS) {
|
|
38801
39239
|
if (lowerSpec.startsWith(prefix)) {
|
|
38802
39240
|
const model = stripPrefix ? modelSpec.slice(prefix.length) : modelSpec;
|
|
38803
|
-
if (prefix === "go/")
|
|
38804
|
-
warnGoAliasDeprecatedOnce();
|
|
38805
39241
|
let concurrency;
|
|
38806
39242
|
let modelName = model;
|
|
38807
39243
|
if (LOCAL_PROVIDERS.has(provider)) {
|
|
@@ -38862,7 +39298,7 @@ function getLegacySyntaxWarning(parsed) {
|
|
|
38862
39298
|
return `Deprecation warning: "${parsed.original}" uses legacy prefix syntax.
|
|
38863
39299
|
` + ` Consider using: ${newSyntax}`;
|
|
38864
39300
|
}
|
|
38865
|
-
var PROVIDER_SHORTCUTS,
|
|
39301
|
+
var PROVIDER_SHORTCUTS, LOCAL_PROVIDERS, NATIVE_MODEL_PATTERNS, LEGACY_PREFIX_PATTERNS, MODEL_CHAIN_SEPARATOR = "+";
|
|
38866
39302
|
var init_model_parser = __esm(() => {
|
|
38867
39303
|
init_provider_definitions();
|
|
38868
39304
|
PROVIDER_SHORTCUTS = getShortcuts();
|
|
@@ -39707,9 +40143,9 @@ function showMonthlyBanner() {
|
|
|
39707
40143
|
return;
|
|
39708
40144
|
const profileConfig = loadConfig();
|
|
39709
40145
|
const consent2 = profileConfig.stats;
|
|
39710
|
-
const
|
|
40146
|
+
const now2 = Date.now();
|
|
39711
40147
|
const lastPrompt = consent2?.lastMonthlyPrompt ? new Date(consent2.lastMonthlyPrompt).getTime() : 0;
|
|
39712
|
-
const timeSincePrompt =
|
|
40148
|
+
const timeSincePrompt = now2 - lastPrompt;
|
|
39713
40149
|
const isFirstRun = !consent2?.lastMonthlyPrompt;
|
|
39714
40150
|
const isMonthlyInterval = timeSincePrompt >= MONTHLY_INTERVAL_MS;
|
|
39715
40151
|
if (!isFirstRun && !isMonthlyInterval)
|
|
@@ -39877,7 +40313,7 @@ function statusToErrorType(status) {
|
|
|
39877
40313
|
}
|
|
39878
40314
|
}
|
|
39879
40315
|
function sanitizeErrorMessage(message, maxLength = MAX_ERROR_MESSAGE_LENGTH) {
|
|
39880
|
-
const flattened = String(message ?? "").replace(ANSI_ESCAPE, "").replace(
|
|
40316
|
+
const flattened = String(message ?? "").replace(ANSI_ESCAPE, "").replace(CONTROL_CHARS2, " ").replace(/\s+/g, " ").trim();
|
|
39881
40317
|
if (flattened.length <= maxLength)
|
|
39882
40318
|
return flattened;
|
|
39883
40319
|
return `${flattened.slice(0, maxLength - 1).trimEnd()}\u2026`;
|
|
@@ -39973,10 +40409,10 @@ function ensureAnthropicErrorFormat(status, body) {
|
|
|
39973
40409
|
const errorType = body?.error?.type || body?.type || body?.code;
|
|
39974
40410
|
return wrapAnthropicError(status, String(message), errorType);
|
|
39975
40411
|
}
|
|
39976
|
-
var MAX_ERROR_MESSAGE_LENGTH = 600, ANSI_ESCAPE,
|
|
40412
|
+
var MAX_ERROR_MESSAGE_LENGTH = 600, ANSI_ESCAPE, CONTROL_CHARS2;
|
|
39977
40413
|
var init_anthropic_error = __esm(() => {
|
|
39978
40414
|
ANSI_ESCAPE = /\x1B\[[0-?]*[ -/]*[@-~]|\x1B[@-Z\\-_]/g;
|
|
39979
|
-
|
|
40415
|
+
CONTROL_CHARS2 = /[\x00-\x1F\x7F]/g;
|
|
39980
40416
|
});
|
|
39981
40417
|
|
|
39982
40418
|
// src/handlers/shared/collect-sse-message.ts
|
|
@@ -43199,10 +43635,10 @@ class ComposedHandler {
|
|
|
43199
43635
|
maybePollPlanUsage(adapter) {
|
|
43200
43636
|
if (!adapter.poll)
|
|
43201
43637
|
return;
|
|
43202
|
-
const
|
|
43203
|
-
if (
|
|
43638
|
+
const now2 = Date.now();
|
|
43639
|
+
if (now2 - this.lastPlanPollAt < PLAN_POLL_INTERVAL_MS)
|
|
43204
43640
|
return;
|
|
43205
|
-
this.lastPlanPollAt =
|
|
43641
|
+
this.lastPlanPollAt = now2;
|
|
43206
43642
|
adapter.poll({ modelId: this.bareModelName }).then((plan) => {
|
|
43207
43643
|
if (plan)
|
|
43208
43644
|
this.tokenTracker.setPlanUsage(plan);
|
|
@@ -43223,6 +43659,9 @@ function getRecoveryHint(status, errorText, providerName, transportTerminal429)
|
|
|
43223
43659
|
return "Provider overloaded. Retry or use a different model.";
|
|
43224
43660
|
}
|
|
43225
43661
|
if (status === 429 && (transportTerminal429 ?? isTerminal429(errorText))) {
|
|
43662
|
+
if (hasPlanLimitWording(errorText)) {
|
|
43663
|
+
return "Plan limit reached \u2014 your allowance is spent for this cycle and refills on the provider's own schedule (see the message below). Wait, upgrade the plan, or switch provider.";
|
|
43664
|
+
}
|
|
43226
43665
|
return "Out of quota \u2014 check your plan & billing details. This won't recover on retry.";
|
|
43227
43666
|
}
|
|
43228
43667
|
if (status === 429 && transportTerminal429 === false) {
|
|
@@ -43239,6 +43678,9 @@ function getRecoveryHint(status, errorText, providerName, transportTerminal429)
|
|
|
43239
43678
|
return "Model not supported by this provider. Verify model name.";
|
|
43240
43679
|
}
|
|
43241
43680
|
if (isQuotaExhaustionError(status, errorText)) {
|
|
43681
|
+
if (hasPlanLimitWording(errorText)) {
|
|
43682
|
+
return "Plan limit reached \u2014 your allowance is spent for this cycle and refills on the provider's own schedule (see the message below). Wait, upgrade the plan, or switch provider.";
|
|
43683
|
+
}
|
|
43242
43684
|
return "Out of quota \u2014 check your plan & billing details. This won't recover on retry.";
|
|
43243
43685
|
}
|
|
43244
43686
|
if (hasActionableLink(errorText)) {
|
|
@@ -43354,6 +43796,9 @@ function resolveApiKeyProvenance(envVar, aliases) {
|
|
|
43354
43796
|
effectiveSource = configLayerLabel();
|
|
43355
43797
|
layers[1].isActive = true;
|
|
43356
43798
|
layers[2].isActive = false;
|
|
43799
|
+
} else if (isKeychainHydratedVar(runtimeVar)) {
|
|
43800
|
+
effectiveSource = "macOS Keychain";
|
|
43801
|
+
layers[2].source = `process.env[${runtimeVar}] (from macOS Keychain)`;
|
|
43357
43802
|
} else if (isOpHydratedVar(runtimeVar)) {
|
|
43358
43803
|
effectiveSource = "1Password";
|
|
43359
43804
|
layers[2].source = `process.env[${runtimeVar}] (from 1Password)`;
|
|
@@ -43403,6 +43848,7 @@ function readConfigKey(envVar) {
|
|
|
43403
43848
|
}
|
|
43404
43849
|
var import_dotenv;
|
|
43405
43850
|
var init_api_key_provenance = __esm(() => {
|
|
43851
|
+
init_keychain_source();
|
|
43406
43852
|
init_onepassword();
|
|
43407
43853
|
import_dotenv = __toESM(require_main(), 1);
|
|
43408
43854
|
});
|
|
@@ -44513,16 +44959,15 @@ var init_provider_definitions = __esm(() => {
|
|
|
44513
44959
|
apiKeyDescription: "Antigravity (shared OAuth token)",
|
|
44514
44960
|
apiKeyUrl: "https://antigravity.google/",
|
|
44515
44961
|
oauthLoginSlug: "antigravity",
|
|
44516
|
-
shortcuts: ["ag", "antigravity"
|
|
44962
|
+
shortcuts: ["ag", "antigravity"],
|
|
44517
44963
|
shortestPrefix: "ag",
|
|
44518
44964
|
legacyPrefixes: [
|
|
44519
44965
|
{ prefix: "ag/", stripPrefix: true },
|
|
44520
|
-
{ prefix: "antigravity/", stripPrefix: true }
|
|
44521
|
-
{ prefix: "go/", stripPrefix: true }
|
|
44966
|
+
{ prefix: "antigravity/", stripPrefix: true }
|
|
44522
44967
|
],
|
|
44523
44968
|
modelDiscovery: { path: "", format: "antigravity" },
|
|
44524
44969
|
isDirectApi: true,
|
|
44525
|
-
description: "Antigravity subscription (ag
|
|
44970
|
+
description: "Antigravity subscription (ag@)"
|
|
44526
44971
|
},
|
|
44527
44972
|
{
|
|
44528
44973
|
createHandler: devinHandler,
|
|
@@ -45138,7 +45583,7 @@ var init_provider_definitions = __esm(() => {
|
|
|
45138
45583
|
legacyPrefixes: [{ prefix: "qp/", stripPrefix: true }],
|
|
45139
45584
|
modelDiscovery: { path: "/compatible-mode/v1/models", format: "openai-models-list" },
|
|
45140
45585
|
isDirectApi: true,
|
|
45141
|
-
description: "Alibaba Model Studio pay-as-you-go (qp@)"
|
|
45586
|
+
description: "Alibaba Model Studio API, pay-as-you-go (qp@)"
|
|
45142
45587
|
},
|
|
45143
45588
|
{
|
|
45144
45589
|
createHandler: openaiHandler,
|
|
@@ -46068,10 +46513,10 @@ var init_predefined_catalog = __esm(() => {
|
|
|
46068
46513
|
});
|
|
46069
46514
|
|
|
46070
46515
|
// src/providers/predefined-endpoints.ts
|
|
46071
|
-
function
|
|
46072
|
-
if (
|
|
46516
|
+
function warnOnce3(message) {
|
|
46517
|
+
if (warnedMessages3.has(message))
|
|
46073
46518
|
return;
|
|
46074
|
-
|
|
46519
|
+
warnedMessages3.add(message);
|
|
46075
46520
|
console.error(message);
|
|
46076
46521
|
}
|
|
46077
46522
|
function activeCatalog() {
|
|
@@ -46088,7 +46533,7 @@ function readOptOut(config2) {
|
|
|
46088
46533
|
if (result.success) {
|
|
46089
46534
|
parsed = result.data;
|
|
46090
46535
|
} else {
|
|
46091
|
-
|
|
46536
|
+
warnOnce3("[claudish] config 'predefinedEndpoints' is not valid and was ignored: " + result.error.issues.map((i) => `${i.path.join(".") || "(root)"} ${i.message}`).join(", "));
|
|
46092
46537
|
}
|
|
46093
46538
|
}
|
|
46094
46539
|
return {
|
|
@@ -46135,7 +46580,7 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46135
46580
|
const noteStale = (entry, name, reason) => {
|
|
46136
46581
|
if (!ownRegistrations.has(name) || !runtime.has(entry.name))
|
|
46137
46582
|
return;
|
|
46138
|
-
|
|
46583
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' is no longer eligible (${reason}) but stays ` + "registered for the rest of this process \u2014 runtime provider registration cannot be " + "undone. Restart claudish to apply the change.");
|
|
46139
46584
|
};
|
|
46140
46585
|
if (optOut.disabled) {
|
|
46141
46586
|
for (const entry of catalog) {
|
|
@@ -46155,7 +46600,7 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46155
46600
|
noteStale(entry, name, reason);
|
|
46156
46601
|
};
|
|
46157
46602
|
if (seen.has(name)) {
|
|
46158
|
-
|
|
46603
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' appears more than once in the bundled ` + "catalog. The first row wins; the later one is ignored.");
|
|
46159
46604
|
skip("duplicate row");
|
|
46160
46605
|
continue;
|
|
46161
46606
|
}
|
|
@@ -46163,19 +46608,19 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46163
46608
|
const owner = reserved.get(name);
|
|
46164
46609
|
if (owner) {
|
|
46165
46610
|
const reason = `'${entry.name}' is already claimed by builtin provider '${owner}' ` + "(as its name, a shortcut, or a legacy prefix)";
|
|
46166
|
-
|
|
46611
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' skipped: ${reason}. ` + "The builtin wins; the bundled entry is inactive.");
|
|
46167
46612
|
recordEndpointUnavailable(entry.name, `bundled endpoint was skipped because ${reason}`);
|
|
46168
46613
|
skip("collides with builtin");
|
|
46169
46614
|
continue;
|
|
46170
46615
|
}
|
|
46171
46616
|
if (runtime.has(entry.name) && !ownRegistrations.has(name)) {
|
|
46172
|
-
|
|
46617
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' skipped: a provider named ` + `'${entry.name}' is already registered for this process.`);
|
|
46173
46618
|
skip("already registered");
|
|
46174
46619
|
continue;
|
|
46175
46620
|
}
|
|
46176
46621
|
if (userEndpoints.has(name)) {
|
|
46177
46622
|
if (hasLocalApiKey({ envVar: entry.apiKeyEnvVar })) {
|
|
46178
|
-
|
|
46623
|
+
warnOnce3(`[claudish] customEndpoints['${entry.name}'] replaces the bundled entry entirely; ` + `${entry.apiKeyEnvVar} no longer applies to it. Add ` + `"apiKey": "\${${entry.apiKeyEnvVar}}" to that entry to keep using it.`);
|
|
46179
46624
|
}
|
|
46180
46625
|
skipStale("replaced by customEndpoints");
|
|
46181
46626
|
continue;
|
|
@@ -46185,7 +46630,7 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46185
46630
|
continue;
|
|
46186
46631
|
}
|
|
46187
46632
|
const { envVar, aliases } = credentialEnvVars(entry);
|
|
46188
|
-
const permitted = optOut.enable.has(name) || hasLocalApiKey({ envVar, aliases });
|
|
46633
|
+
const permitted = optOut.enable.has(name) || hasLocalApiKey({ envVar, aliases }) || keychainHasAnyOf([envVar, ...aliases ?? []]);
|
|
46189
46634
|
if (!permitted) {
|
|
46190
46635
|
skipStale("no local credential");
|
|
46191
46636
|
continue;
|
|
@@ -46193,7 +46638,7 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46193
46638
|
const resolvedUrl = classifyEndpointBaseUrl(entry.baseUrl, entry.baseUrlEnvVars);
|
|
46194
46639
|
if (!resolvedUrl.ok) {
|
|
46195
46640
|
const detail = describeBadBaseUrlOverride(resolvedUrl, entry.baseUrl);
|
|
46196
|
-
|
|
46641
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' skipped: ${detail}`);
|
|
46197
46642
|
recordEndpointUnavailable(entry.name, detail);
|
|
46198
46643
|
skipStale("invalid base URL override");
|
|
46199
46644
|
continue;
|
|
@@ -46203,14 +46648,15 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46203
46648
|
ownRegistrations.add(name);
|
|
46204
46649
|
result.registered.push(entry.name);
|
|
46205
46650
|
} catch (err) {
|
|
46206
|
-
|
|
46651
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' skipped: ` + `${err instanceof Error ? err.message : String(err)}`);
|
|
46207
46652
|
skip("invalid catalog row");
|
|
46208
46653
|
}
|
|
46209
46654
|
}
|
|
46210
46655
|
return result;
|
|
46211
46656
|
}
|
|
46212
|
-
var KILL_SWITCH_ENV = "CLAUDISH_NO_PREDEFINED_ENDPOINTS",
|
|
46657
|
+
var KILL_SWITCH_ENV = "CLAUDISH_NO_PREDEFINED_ENDPOINTS", warnedMessages3, ownRegistrations, catalogOverride = null;
|
|
46213
46658
|
var init_predefined_endpoints = __esm(() => {
|
|
46659
|
+
init_keychain_source();
|
|
46214
46660
|
init_local_api_key();
|
|
46215
46661
|
init_config_schema();
|
|
46216
46662
|
init_custom_endpoints_loader();
|
|
@@ -46218,7 +46664,7 @@ var init_predefined_endpoints = __esm(() => {
|
|
|
46218
46664
|
init_predefined_catalog();
|
|
46219
46665
|
init_reserved_namespace();
|
|
46220
46666
|
init_runtime_providers();
|
|
46221
|
-
|
|
46667
|
+
warnedMessages3 = new Set;
|
|
46222
46668
|
ownRegistrations = new Set;
|
|
46223
46669
|
});
|
|
46224
46670
|
|
|
@@ -46258,7 +46704,7 @@ function reportCustomEndpoints(result) {
|
|
|
46258
46704
|
logStderr(`customEndpoints['${name}'] failed validation: ${message}`);
|
|
46259
46705
|
}
|
|
46260
46706
|
for (const { name, reason } of result.refused) {
|
|
46261
|
-
|
|
46707
|
+
warnOnce4(`customEndpoints['${name}'] skipped: ${reason}. The builtin wins. ` + `Rename your entry (e.g. '${name}-custom') to use it.`);
|
|
46262
46708
|
}
|
|
46263
46709
|
}
|
|
46264
46710
|
function warnOnProjectScopedEndpoints() {
|
|
@@ -46267,26 +46713,26 @@ function warnOnProjectScopedEndpoints() {
|
|
|
46267
46713
|
const names = Object.keys(local?.customEndpoints ?? {});
|
|
46268
46714
|
if (names.length === 0)
|
|
46269
46715
|
return;
|
|
46270
|
-
|
|
46716
|
+
warnOnce4(`.claudish.json declares customEndpoints (${names.join(", ")}) but they are ` + "read from the GLOBAL config only, so they are being ignored. Move them to " + "~/.claudish/config.json.");
|
|
46271
46717
|
} catch {}
|
|
46272
46718
|
}
|
|
46273
|
-
function
|
|
46274
|
-
if (
|
|
46719
|
+
function warnOnce4(message) {
|
|
46720
|
+
if (warnedMessages4.has(message))
|
|
46275
46721
|
return;
|
|
46276
|
-
|
|
46722
|
+
warnedMessages4.add(message);
|
|
46277
46723
|
logStderr(message);
|
|
46278
46724
|
}
|
|
46279
46725
|
function invalidateEndpointRegistration() {
|
|
46280
46726
|
registered = false;
|
|
46281
46727
|
}
|
|
46282
|
-
var registered = false, lastCustomResult,
|
|
46728
|
+
var registered = false, lastCustomResult, warnedMessages4;
|
|
46283
46729
|
var init_endpoint_registration = __esm(() => {
|
|
46284
46730
|
init_logger();
|
|
46285
46731
|
init_profile_config();
|
|
46286
46732
|
init_custom_endpoints_loader();
|
|
46287
46733
|
init_predefined_endpoints();
|
|
46288
46734
|
lastCustomResult = { registered: 0, errors: [], refused: [] };
|
|
46289
|
-
|
|
46735
|
+
warnedMessages4 = new Set;
|
|
46290
46736
|
});
|
|
46291
46737
|
|
|
46292
46738
|
// src/providers/provider-registry.ts
|
|
@@ -48045,8 +48491,8 @@ function readProjectCwd(dirName) {
|
|
|
48045
48491
|
}
|
|
48046
48492
|
return null;
|
|
48047
48493
|
}
|
|
48048
|
-
function isActive(row,
|
|
48049
|
-
return
|
|
48494
|
+
function isActive(row, now2 = Date.now()) {
|
|
48495
|
+
return now2 - row.mtimeMs < ACTIVE_WINDOW_MS;
|
|
48050
48496
|
}
|
|
48051
48497
|
function discoverWorktreeGroups(repo) {
|
|
48052
48498
|
const rootSlug = slugForPath(repo.root);
|
|
@@ -48661,9 +49107,9 @@ function setupSession(sessionPath, models, input) {
|
|
|
48661
49107
|
}
|
|
48662
49108
|
const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
|
|
48663
49109
|
const shuffled = fisherYatesShuffle([...ids]);
|
|
48664
|
-
const
|
|
49110
|
+
const now2 = new Date().toISOString();
|
|
48665
49111
|
const manifest = {
|
|
48666
|
-
created:
|
|
49112
|
+
created: now2,
|
|
48667
49113
|
models: {},
|
|
48668
49114
|
shuffleOrder: shuffled
|
|
48669
49115
|
};
|
|
@@ -48671,13 +49117,13 @@ function setupSession(sessionPath, models, input) {
|
|
|
48671
49117
|
const anonId = shuffled[i];
|
|
48672
49118
|
manifest.models[anonId] = {
|
|
48673
49119
|
model: models[i],
|
|
48674
|
-
assignedAt:
|
|
49120
|
+
assignedAt: now2
|
|
48675
49121
|
};
|
|
48676
49122
|
mkdirSync11(join28(sessionPath, "work", anonId), { recursive: true });
|
|
48677
49123
|
}
|
|
48678
49124
|
writeFileSync11(join28(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
48679
49125
|
const status = {
|
|
48680
|
-
startedAt:
|
|
49126
|
+
startedAt: now2,
|
|
48681
49127
|
models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
|
|
48682
49128
|
id,
|
|
48683
49129
|
{
|
|
@@ -48958,9 +49404,9 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
48958
49404
|
return Math.max(0, Date.now() - s.updated_at);
|
|
48959
49405
|
};
|
|
48960
49406
|
const graceStartedAt = new Map;
|
|
48961
|
-
const graceUsedMs = (id,
|
|
49407
|
+
const graceUsedMs = (id, now2) => {
|
|
48962
49408
|
const start = graceStartedAt.get(id);
|
|
48963
|
-
return start === undefined ? 0 : Math.max(0,
|
|
49409
|
+
return start === undefined ? 0 : Math.max(0, now2 - start);
|
|
48964
49410
|
};
|
|
48965
49411
|
const runningIds = () => [...processes.keys()].filter((id) => statusCache.models[id]?.state === "RUNNING");
|
|
48966
49412
|
const timeoutModel = async (id, why) => {
|
|
@@ -49013,10 +49459,10 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49013
49459
|
if (running.length === 0)
|
|
49014
49460
|
return;
|
|
49015
49461
|
const extended = [];
|
|
49016
|
-
const
|
|
49462
|
+
const now2 = Date.now();
|
|
49017
49463
|
for (const id of running) {
|
|
49018
49464
|
const idleMs = idleMsFor(id);
|
|
49019
|
-
const usedGrace = graceUsedMs(id,
|
|
49465
|
+
const usedGrace = graceUsedMs(id, now2);
|
|
49020
49466
|
if (!graceEnabled) {
|
|
49021
49467
|
await timeoutModel(id, "deadline reached (grace extension disabled)");
|
|
49022
49468
|
} else if (usedGrace >= maxGraceMs) {
|
|
@@ -49027,7 +49473,7 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49027
49473
|
await timeoutModel(id, `no measurable progress for ${Math.round(idleMs / 1000)}s`);
|
|
49028
49474
|
} else {
|
|
49029
49475
|
if (!graceStartedAt.has(id))
|
|
49030
|
-
graceStartedAt.set(id,
|
|
49476
|
+
graceStartedAt.set(id, now2);
|
|
49031
49477
|
extended.push(id);
|
|
49032
49478
|
}
|
|
49033
49479
|
}
|
|
@@ -50269,6 +50715,9 @@ function extractVersionParts(modelId) {
|
|
|
50269
50715
|
break;
|
|
50270
50716
|
continue;
|
|
50271
50717
|
}
|
|
50718
|
+
if (!started && /^\d+b$/.test(token) && Number.parseInt(match[0], 10) > 10) {
|
|
50719
|
+
continue;
|
|
50720
|
+
}
|
|
50272
50721
|
if (!started) {
|
|
50273
50722
|
started = true;
|
|
50274
50723
|
for (const part of match[0].split(".")) {
|
|
@@ -50789,6 +51238,14 @@ function classifyHttpError(status, body, latencyMs) {
|
|
|
50789
51238
|
};
|
|
50790
51239
|
}
|
|
50791
51240
|
if (status === 429) {
|
|
51241
|
+
if (hasPlanLimitWording(body)) {
|
|
51242
|
+
return {
|
|
51243
|
+
state: "plan-limit",
|
|
51244
|
+
latencyMs,
|
|
51245
|
+
httpStatus: status,
|
|
51246
|
+
errorMessage: extractErrorMessage(body) || "Plan allowance spent for this cycle"
|
|
51247
|
+
};
|
|
51248
|
+
}
|
|
50792
51249
|
return {
|
|
50793
51250
|
state: "rate-limited",
|
|
50794
51251
|
latencyMs,
|
|
@@ -50797,6 +51254,14 @@ function classifyHttpError(status, body, latencyMs) {
|
|
|
50797
51254
|
};
|
|
50798
51255
|
}
|
|
50799
51256
|
if (upstream === 429 || status === 402) {
|
|
51257
|
+
if (status !== 402 && hasPlanLimitWording(body)) {
|
|
51258
|
+
return {
|
|
51259
|
+
state: "plan-limit",
|
|
51260
|
+
latencyMs,
|
|
51261
|
+
httpStatus: upstream ?? status,
|
|
51262
|
+
errorMessage: extractErrorMessage(body) || "Plan allowance spent for this cycle"
|
|
51263
|
+
};
|
|
51264
|
+
}
|
|
50800
51265
|
return {
|
|
50801
51266
|
state: "out-of-credit",
|
|
50802
51267
|
latencyMs,
|
|
@@ -50819,7 +51284,7 @@ function classifyHttpError(status, body, latencyMs) {
|
|
|
50819
51284
|
errorMessage: extractErrorMessage(body) || `HTTP ${status}`
|
|
50820
51285
|
};
|
|
50821
51286
|
}
|
|
50822
|
-
function truncateKeepingLink(text, max =
|
|
51287
|
+
function truncateKeepingLink(text, max = 400) {
|
|
50823
51288
|
if (text.length <= max)
|
|
50824
51289
|
return text;
|
|
50825
51290
|
const url2 = text.match(/https?:\/\/\S+/i)?.[0];
|
|
@@ -51036,6 +51501,8 @@ function describeProbeState(result) {
|
|
|
51036
51501
|
return withDetail(`rate limited \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
51037
51502
|
case "out-of-credit":
|
|
51038
51503
|
return withDetail(`out of credit \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
51504
|
+
case "plan-limit":
|
|
51505
|
+
return withDetail(`plan limit reached \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
51039
51506
|
case "server-error":
|
|
51040
51507
|
return withDetail(`server error \xB7 ${status} \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
51041
51508
|
case "timeout":
|
|
@@ -51052,12 +51519,13 @@ function isReadyState(state) {
|
|
|
51052
51519
|
return state === "live";
|
|
51053
51520
|
}
|
|
51054
51521
|
function isFailureState(state) {
|
|
51055
|
-
return state === "auth-failed" || state === "model-not-found" || state === "rate-limited" || state === "out-of-credit" || state === "server-error" || state === "timeout" || state === "network-error" || state === "error";
|
|
51522
|
+
return state === "auth-failed" || state === "model-not-found" || state === "rate-limited" || state === "out-of-credit" || state === "plan-limit" || state === "server-error" || state === "timeout" || state === "network-error" || state === "error";
|
|
51056
51523
|
}
|
|
51057
51524
|
var STREAM_MS_FLOOR = 50, OAUTH_PROVIDERS2, PROBE_PROMPT = "Count from one to twenty in words, one per line.", PROBE_MAX_TOKENS = 512, MINIMAL_EFFORT_UNSUPPORTED;
|
|
51058
51525
|
var init_probe_live = __esm(() => {
|
|
51059
51526
|
init_anthropic_error();
|
|
51060
51527
|
init_model_unsupported();
|
|
51528
|
+
init_quota_exhaustion();
|
|
51061
51529
|
OAUTH_PROVIDERS2 = new Set(["vertex", "antigravity", "devin"]);
|
|
51062
51530
|
MINIMAL_EFFORT_UNSUPPORTED = new Set(["native-anthropic", "anthropic"]);
|
|
51063
51531
|
});
|
|
@@ -54277,8 +54745,8 @@ class OpenRouterRequestQueue {
|
|
|
54277
54745
|
}
|
|
54278
54746
|
}
|
|
54279
54747
|
async waitForNextSlot() {
|
|
54280
|
-
const
|
|
54281
|
-
const timeSinceLastRequest =
|
|
54748
|
+
const now2 = Date.now();
|
|
54749
|
+
const timeSinceLastRequest = now2 - this.rateLimitState.lastRequestTime;
|
|
54282
54750
|
const delayMs = this.calculateDelay();
|
|
54283
54751
|
this.rateLimitState.currentDelayMs = delayMs;
|
|
54284
54752
|
if (timeSinceLastRequest < delayMs) {
|
|
@@ -54306,8 +54774,8 @@ class OpenRouterRequestQueue {
|
|
|
54306
54774
|
}
|
|
54307
54775
|
}
|
|
54308
54776
|
if (this.rateLimitState.resetTime !== null && this.rateLimitState.remainingRequests !== null) {
|
|
54309
|
-
const
|
|
54310
|
-
const timeUntilReset = this.rateLimitState.resetTime -
|
|
54777
|
+
const now2 = Date.now() / 1000;
|
|
54778
|
+
const timeUntilReset = this.rateLimitState.resetTime - now2;
|
|
54311
54779
|
if (timeUntilReset > 0 && this.rateLimitState.remainingRequests > 0) {
|
|
54312
54780
|
const optimalDelay = timeUntilReset * 1000 / Math.max(this.rateLimitState.remainingRequests, 1);
|
|
54313
54781
|
delayMs = Math.max(delayMs, Math.min(optimalDelay, this.maxDelayMs));
|
|
@@ -56491,11 +56959,15 @@ __export(exports_theme_mode, {
|
|
|
56491
56959
|
classifyOscBackground: () => classifyOscBackground,
|
|
56492
56960
|
detectAndSetThemeMode: () => detectAndSetThemeMode,
|
|
56493
56961
|
detectAndSetThemeModeSync: () => detectAndSetThemeModeSync,
|
|
56962
|
+
getTerminalBackground: () => getTerminalBackground,
|
|
56963
|
+
getTerminalBackgroundHex: () => getTerminalBackgroundHex,
|
|
56494
56964
|
getThemeMode: () => getThemeMode,
|
|
56495
56965
|
onThemeModeChange: () => onThemeModeChange,
|
|
56966
|
+
parseOscBackgroundHex: () => parseOscBackgroundHex,
|
|
56496
56967
|
queryTerminalThemeMode: () => queryTerminalThemeMode,
|
|
56497
56968
|
relativeLuminance: () => relativeLuminance,
|
|
56498
56969
|
resetThemeModeForTests: () => resetThemeModeForTests,
|
|
56970
|
+
setTerminalBackgroundHex: () => setTerminalBackgroundHex,
|
|
56499
56971
|
setThemeMode: () => setThemeMode,
|
|
56500
56972
|
themeModeFromColorFgBg: () => themeModeFromColorFgBg,
|
|
56501
56973
|
themeModeOverride: () => themeModeOverride
|
|
@@ -56514,6 +56986,7 @@ function onThemeModeChange(cb) {
|
|
|
56514
56986
|
}
|
|
56515
56987
|
function resetThemeModeForTests() {
|
|
56516
56988
|
setThemeMode(null);
|
|
56989
|
+
background = null;
|
|
56517
56990
|
}
|
|
56518
56991
|
function themeModeOverride(env = process.env) {
|
|
56519
56992
|
const raw2 = env.CLAUDISH_THEME?.trim().toLowerCase();
|
|
@@ -56550,6 +57023,31 @@ function classifyOscBackground(reply) {
|
|
|
56550
57023
|
const lum = relativeLuminance(channel(m[1]), channel(m[2]), channel(m[3]));
|
|
56551
57024
|
return lum >= MID_SRGB_LUMINANCE ? "light" : "dark";
|
|
56552
57025
|
}
|
|
57026
|
+
function parseOscBackgroundHex(reply) {
|
|
57027
|
+
const m = reply.match(/\]11;rgb:([0-9a-fA-F]{1,4})\/([0-9a-fA-F]{1,4})\/([0-9a-fA-F]{1,4})/);
|
|
57028
|
+
if (!m)
|
|
57029
|
+
return null;
|
|
57030
|
+
const byte = (hex3) => {
|
|
57031
|
+
const max = 16 ** hex3.length - 1;
|
|
57032
|
+
const v = Math.round(Number.parseInt(hex3, 16) / max * 255);
|
|
57033
|
+
return v.toString(16).padStart(2, "0");
|
|
57034
|
+
};
|
|
57035
|
+
return `#${byte(m[1])}${byte(m[2])}${byte(m[3])}`;
|
|
57036
|
+
}
|
|
57037
|
+
function getTerminalBackgroundHex() {
|
|
57038
|
+
return background?.hex ?? null;
|
|
57039
|
+
}
|
|
57040
|
+
function getTerminalBackground() {
|
|
57041
|
+
return background;
|
|
57042
|
+
}
|
|
57043
|
+
function setTerminalBackgroundHex(hex3) {
|
|
57044
|
+
if (!hex3) {
|
|
57045
|
+
background = null;
|
|
57046
|
+
return;
|
|
57047
|
+
}
|
|
57048
|
+
const mode = classifyOscBackground(`]11;rgb:${hex3.slice(1, 3)}/${hex3.slice(3, 5)}/${hex3.slice(5, 7)}`);
|
|
57049
|
+
background = mode ? { hex: hex3, mode } : null;
|
|
57050
|
+
}
|
|
56553
57051
|
async function queryTerminalThemeMode(timeoutMs = 150) {
|
|
56554
57052
|
const stdin = process.stdin;
|
|
56555
57053
|
const stdout = process.stdout;
|
|
@@ -56577,7 +57075,10 @@ async function queryTerminalThemeMode(timeoutMs = 150) {
|
|
|
56577
57075
|
const onData = (chunk) => {
|
|
56578
57076
|
buffer += chunk.toString("latin1");
|
|
56579
57077
|
if (/\]11;[^\x07\x1b]*(\x07|\x1b\\)/.test(buffer)) {
|
|
56580
|
-
|
|
57078
|
+
const mode = classifyOscBackground(buffer);
|
|
57079
|
+
const hex3 = parseOscBackgroundHex(buffer);
|
|
57080
|
+
background = hex3 && mode ? { hex: hex3, mode } : null;
|
|
57081
|
+
finish(mode);
|
|
56581
57082
|
}
|
|
56582
57083
|
};
|
|
56583
57084
|
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
@@ -56595,17 +57096,18 @@ async function queryTerminalThemeMode(timeoutMs = 150) {
|
|
|
56595
57096
|
async function detectAndSetThemeMode() {
|
|
56596
57097
|
const override = themeModeOverride();
|
|
56597
57098
|
if (override) {
|
|
57099
|
+
setTerminalBackgroundHex(null);
|
|
56598
57100
|
setThemeMode(override);
|
|
56599
57101
|
return override;
|
|
56600
57102
|
}
|
|
56601
|
-
const
|
|
56602
|
-
if (
|
|
56603
|
-
setThemeMode(
|
|
56604
|
-
return
|
|
57103
|
+
const fromOsc = await queryTerminalThemeMode(150);
|
|
57104
|
+
if (fromOsc) {
|
|
57105
|
+
setThemeMode(fromOsc);
|
|
57106
|
+
return fromOsc;
|
|
56605
57107
|
}
|
|
56606
|
-
const
|
|
56607
|
-
setThemeMode(
|
|
56608
|
-
return
|
|
57108
|
+
const fromEnv = themeModeFromColorFgBg();
|
|
57109
|
+
setThemeMode(fromEnv);
|
|
57110
|
+
return fromEnv;
|
|
56609
57111
|
}
|
|
56610
57112
|
function detectAndSetThemeModeSync() {
|
|
56611
57113
|
const mode = themeModeOverride() ?? themeModeFromColorFgBg();
|
|
@@ -56613,7 +57115,7 @@ function detectAndSetThemeModeSync() {
|
|
|
56613
57115
|
setThemeMode(mode);
|
|
56614
57116
|
return mode ?? detected;
|
|
56615
57117
|
}
|
|
56616
|
-
var detected = null, listeners, MID_SRGB_LUMINANCE;
|
|
57118
|
+
var detected = null, listeners, MID_SRGB_LUMINANCE, background = null;
|
|
56617
57119
|
var init_theme_mode = __esm(() => {
|
|
56618
57120
|
listeners = [];
|
|
56619
57121
|
MID_SRGB_LUMINANCE = relativeLuminance(0.5, 0.5, 0.5);
|
|
@@ -57352,8 +57854,6 @@ function describeSourceSync(p, config3) {
|
|
|
57352
57854
|
return "env";
|
|
57353
57855
|
if (hasCfg)
|
|
57354
57856
|
return "cfg";
|
|
57355
|
-
if (p.publicKeyFallback)
|
|
57356
|
-
return "public";
|
|
57357
57857
|
return null;
|
|
57358
57858
|
}
|
|
57359
57859
|
async function describeSource(p, config3) {
|
|
@@ -57394,7 +57894,6 @@ function toProviderDef(def) {
|
|
|
57394
57894
|
defaultEndpoint: def.baseUrl || undefined,
|
|
57395
57895
|
aliases: def.apiKeyAliases,
|
|
57396
57896
|
isLocal: def.isLocal,
|
|
57397
|
-
publicKeyFallback: !!def.publicKeyFallback,
|
|
57398
57897
|
oauthSlug: def.oauthLoginSlug
|
|
57399
57898
|
};
|
|
57400
57899
|
}
|
|
@@ -68585,7 +69084,7 @@ var require_lib3 = __commonJS(function(exports, module) {
|
|
|
68585
69084
|
var trail = encoder.end();
|
|
68586
69085
|
return trail && trail.length > 0 ? Buffer2.concat([res, trail]) : res;
|
|
68587
69086
|
};
|
|
68588
|
-
iconv.decode = function
|
|
69087
|
+
iconv.decode = function decode4(buf, encoding, options) {
|
|
68589
69088
|
if (typeof buf === "string") {
|
|
68590
69089
|
if (!iconv.skipDecodeWarning) {
|
|
68591
69090
|
console.error("Iconv-lite warning: decode()-ing strings is deprecated. Refer to https://github.com/ashtuchkin/iconv-lite/wiki/Use-Buffers-when-decoding");
|
|
@@ -69841,6 +70340,420 @@ var init_dist16 = __esm(() => {
|
|
|
69841
70340
|
init_dist15();
|
|
69842
70341
|
});
|
|
69843
70342
|
|
|
70343
|
+
// src/keychain-command.ts
|
|
70344
|
+
var exports_keychain_command = {};
|
|
70345
|
+
__export(exports_keychain_command, {
|
|
70346
|
+
keychainCommand: () => keychainCommand
|
|
70347
|
+
});
|
|
70348
|
+
function ok(text) {
|
|
70349
|
+
const c = cliAnsi();
|
|
70350
|
+
return `${c.GREEN}${text}${c.RESET}`;
|
|
70351
|
+
}
|
|
70352
|
+
function warn(text) {
|
|
70353
|
+
const c = cliAnsi();
|
|
70354
|
+
return `${c.YELLOW}${text}${c.RESET}`;
|
|
70355
|
+
}
|
|
70356
|
+
function bad(text) {
|
|
70357
|
+
const c = cliAnsi();
|
|
70358
|
+
return `${c.RED}${text}${c.RESET}`;
|
|
70359
|
+
}
|
|
70360
|
+
function dim3(text) {
|
|
70361
|
+
const c = cliAnsi();
|
|
70362
|
+
return `${c.GRAY}${text}${c.RESET}`;
|
|
70363
|
+
}
|
|
70364
|
+
function strong(text) {
|
|
70365
|
+
const c = cliAnsi();
|
|
70366
|
+
return `${c.BOLD}${text}${c.RESET}`;
|
|
70367
|
+
}
|
|
70368
|
+
function requireKeychain() {
|
|
70369
|
+
const reason = keychainUnavailableReason();
|
|
70370
|
+
if (!reason)
|
|
70371
|
+
return true;
|
|
70372
|
+
console.error(bad(`Keychain unavailable: ${reason}`));
|
|
70373
|
+
console.error(dim3("claudish's keychain backend uses the macOS Security framework via /usr/bin/security."));
|
|
70374
|
+
return false;
|
|
70375
|
+
}
|
|
70376
|
+
function catalogEnvVars() {
|
|
70377
|
+
const names = new Set;
|
|
70378
|
+
for (const p of getAllProviders()) {
|
|
70379
|
+
if (p.apiKeyEnvVar)
|
|
70380
|
+
names.add(p.apiKeyEnvVar);
|
|
70381
|
+
for (const alias of p.apiKeyAliases ?? [])
|
|
70382
|
+
names.add(alias);
|
|
70383
|
+
}
|
|
70384
|
+
return Array.from(names).sort();
|
|
70385
|
+
}
|
|
70386
|
+
function keychainStatus() {
|
|
70387
|
+
const supported = isKeychainSupported();
|
|
70388
|
+
const enabled2 = isKeychainEnabled();
|
|
70389
|
+
console.log(strong("macOS Keychain backend"));
|
|
70390
|
+
console.log(` platform ${supported ? ok("supported") : bad(`unsupported (${process.platform})`)}`);
|
|
70391
|
+
console.log(` backend ${enabled2 ? ok("enabled") : dim3("disabled")}`);
|
|
70392
|
+
console.log(` service ${dim3(KEYCHAIN_SERVICE)}`);
|
|
70393
|
+
if (!supported)
|
|
70394
|
+
return;
|
|
70395
|
+
const listed = enumerateKeychainVars();
|
|
70396
|
+
if (listed.failed) {
|
|
70397
|
+
console.log(` stored keys ${bad("could not read the keychain")}`);
|
|
70398
|
+
console.log();
|
|
70399
|
+
console.log(bad(listed.error ?? "unknown error"));
|
|
70400
|
+
console.log(dim3("The keychain may be locked, or access may have been denied."));
|
|
70401
|
+
process.exitCode = 1;
|
|
70402
|
+
return;
|
|
70403
|
+
}
|
|
70404
|
+
const stored = listed.names;
|
|
70405
|
+
console.log(` stored keys ${stored.length > 0 ? ok(String(stored.length)) : dim3("0")}`);
|
|
70406
|
+
if (!enabled2 && stored.length > 0) {
|
|
70407
|
+
console.log();
|
|
70408
|
+
console.log(warn(`${stored.length} key(s) are in the keychain but the backend is disabled, so claudish will not read them.`));
|
|
70409
|
+
console.log(dim3(" Enable with: claudish keychain enable"));
|
|
70410
|
+
}
|
|
70411
|
+
if (enabled2 && stored.length === 0) {
|
|
70412
|
+
console.log();
|
|
70413
|
+
console.log(dim3("Nothing stored yet. Copy your existing keys in with:"));
|
|
70414
|
+
console.log(dim3(" claudish keychain import"));
|
|
70415
|
+
}
|
|
70416
|
+
console.log();
|
|
70417
|
+
console.log(dim3("Resolution order: env var \u2192 alias \u2192 config.json \u2192 macOS Keychain \u2192 1Password"));
|
|
70418
|
+
}
|
|
70419
|
+
function keychainList() {
|
|
70420
|
+
if (!requireKeychain())
|
|
70421
|
+
return;
|
|
70422
|
+
const listed = enumerateKeychainVars();
|
|
70423
|
+
if (listed.failed) {
|
|
70424
|
+
console.error(bad(`Could not read the keychain: ${listed.error ?? "unknown error"}`));
|
|
70425
|
+
console.error(dim3("The keychain may be locked, or access may have been denied."));
|
|
70426
|
+
process.exitCode = 1;
|
|
70427
|
+
return;
|
|
70428
|
+
}
|
|
70429
|
+
const stored = listed.names;
|
|
70430
|
+
if (stored.length === 0) {
|
|
70431
|
+
console.log(dim3("No keys stored in the keychain."));
|
|
70432
|
+
console.log(dim3("Copy your existing keys in with: claudish keychain import"));
|
|
70433
|
+
return;
|
|
70434
|
+
}
|
|
70435
|
+
const width = Math.max(...stored.map((n) => n.length));
|
|
70436
|
+
for (const name of stored) {
|
|
70437
|
+
let tail;
|
|
70438
|
+
try {
|
|
70439
|
+
const value = readKeychainSecret(name);
|
|
70440
|
+
tail = value ? dim3(valueTail2(value)) : bad("unreadable");
|
|
70441
|
+
} catch (err) {
|
|
70442
|
+
tail = bad(err instanceof KeychainError ? "denied" : "error");
|
|
70443
|
+
}
|
|
70444
|
+
const shadowed = process.env[name] ? warn(" (shadowed by an env var)") : "";
|
|
70445
|
+
console.log(` ${name.padEnd(width)} ${tail}${shadowed}`);
|
|
70446
|
+
}
|
|
70447
|
+
if (!isKeychainEnabled()) {
|
|
70448
|
+
console.log();
|
|
70449
|
+
console.log(warn("The keychain backend is disabled \u2014 claudish will not read these."));
|
|
70450
|
+
console.log(dim3(" Enable with: claudish keychain enable"));
|
|
70451
|
+
}
|
|
70452
|
+
}
|
|
70453
|
+
async function collectImportPlan(opts) {
|
|
70454
|
+
const wanted = opts.only ?? catalogEnvVars();
|
|
70455
|
+
const listed = enumerateKeychainVars();
|
|
70456
|
+
if (listed.failed) {
|
|
70457
|
+
throw new KeychainError(`Cannot read the keychain to plan this import: ${listed.error ?? "unknown error"}. ` + "Refusing to continue \u2014 without knowing what is already stored, an import could " + "silently replace existing keys.");
|
|
70458
|
+
}
|
|
70459
|
+
const stored = new Set(listed.names);
|
|
70460
|
+
const plan = new Map;
|
|
70461
|
+
const classify = (envVar, value, origin) => {
|
|
70462
|
+
const problem = describeUnstorableValue(value) ?? undefined;
|
|
70463
|
+
let action = stored.has(envVar) ? "overwrite" : "new";
|
|
70464
|
+
if (action === "overwrite") {
|
|
70465
|
+
try {
|
|
70466
|
+
if (readKeychainSecret(envVar) === value)
|
|
70467
|
+
action = "unchanged";
|
|
70468
|
+
} catch {}
|
|
70469
|
+
}
|
|
70470
|
+
plan.set(envVar, { envVar, value, origin, action, problem });
|
|
70471
|
+
};
|
|
70472
|
+
if (opts.from === "env" || opts.from === "all") {
|
|
70473
|
+
for (const envVar of wanted) {
|
|
70474
|
+
const value = process.env[envVar];
|
|
70475
|
+
if (value)
|
|
70476
|
+
classify(envVar, value, "environment");
|
|
70477
|
+
}
|
|
70478
|
+
}
|
|
70479
|
+
if ((opts.from === "1password" || opts.from === "all") && hasOpSources()) {
|
|
70480
|
+
const missing = wanted.filter((n) => !plan.has(n));
|
|
70481
|
+
if (missing.length > 0) {
|
|
70482
|
+
const resolved = await resolveOpKeyForEnvVars(new Set(missing), {
|
|
70483
|
+
onAuthFailure: "throw",
|
|
70484
|
+
allowPrompt: true
|
|
70485
|
+
});
|
|
70486
|
+
for (const [envVar, value] of Object.entries(resolved)) {
|
|
70487
|
+
if (value)
|
|
70488
|
+
classify(envVar, value, "1Password");
|
|
70489
|
+
}
|
|
70490
|
+
}
|
|
70491
|
+
}
|
|
70492
|
+
return Array.from(plan.values()).sort((a, b) => a.envVar.localeCompare(b.envVar));
|
|
70493
|
+
}
|
|
70494
|
+
function renderPlan(plan) {
|
|
70495
|
+
const width = Math.max(...plan.map((e) => e.envVar.length));
|
|
70496
|
+
for (const e of plan) {
|
|
70497
|
+
if (e.problem) {
|
|
70498
|
+
console.log(` ${bad("skip")} ${e.envVar.padEnd(width)} ${bad(e.problem)}`);
|
|
70499
|
+
continue;
|
|
70500
|
+
}
|
|
70501
|
+
const label = e.action === "new" ? ok("new") : e.action === "overwrite" ? warn("overwrite") : dim3("unchanged");
|
|
70502
|
+
const pad = " ".repeat(Math.max(0, 10 - (e.action === "new" ? 3 : e.action.length)));
|
|
70503
|
+
console.log(` ${label}${pad} ${e.envVar.padEnd(width)} ${dim3(valueTail2(e.value))} ${dim3(`from ${e.origin}`)}`);
|
|
70504
|
+
}
|
|
70505
|
+
}
|
|
70506
|
+
function writeImportEntries(entries) {
|
|
70507
|
+
let written = 0;
|
|
70508
|
+
const failures = [];
|
|
70509
|
+
for (const entry of entries) {
|
|
70510
|
+
try {
|
|
70511
|
+
writeKeychainSecret(entry.envVar, entry.value);
|
|
70512
|
+
written++;
|
|
70513
|
+
} catch (err) {
|
|
70514
|
+
failures.push(`${entry.envVar}: ${err instanceof Error ? err.message : String(err)}`);
|
|
70515
|
+
}
|
|
70516
|
+
}
|
|
70517
|
+
return { written, failures };
|
|
70518
|
+
}
|
|
70519
|
+
function reportImportResult(written, failures) {
|
|
70520
|
+
if (written > 0 && !isKeychainEnabled()) {
|
|
70521
|
+
setKeychainEnabled(true);
|
|
70522
|
+
console.log(ok("Keychain backend enabled."));
|
|
70523
|
+
}
|
|
70524
|
+
console.log(ok(`Stored ${written} key(s) in the keychain.`));
|
|
70525
|
+
if (failures.length > 0) {
|
|
70526
|
+
console.error(bad(`${failures.length} key(s) failed:`));
|
|
70527
|
+
for (const f of failures)
|
|
70528
|
+
console.error(` ${f}`);
|
|
70529
|
+
process.exitCode = 1;
|
|
70530
|
+
}
|
|
70531
|
+
}
|
|
70532
|
+
async function keychainImport(opts) {
|
|
70533
|
+
if (!requireKeychain())
|
|
70534
|
+
return;
|
|
70535
|
+
let plan;
|
|
70536
|
+
try {
|
|
70537
|
+
plan = await collectImportPlan(opts);
|
|
70538
|
+
} catch (err) {
|
|
70539
|
+
console.error(bad(`Could not build the import plan: ${err instanceof Error ? err.message : String(err)}`));
|
|
70540
|
+
process.exitCode = 1;
|
|
70541
|
+
return;
|
|
70542
|
+
}
|
|
70543
|
+
if (plan.length === 0) {
|
|
70544
|
+
console.log(dim3("Nothing to import \u2014 no matching keys found in the requested sources."));
|
|
70545
|
+
if (opts.from === "1password" && !hasOpSources()) {
|
|
70546
|
+
console.log(dim3("No 1Password source is configured. See: claudish config \u2192 1Password tab"));
|
|
70547
|
+
}
|
|
70548
|
+
return;
|
|
70549
|
+
}
|
|
70550
|
+
const writable = plan.filter((e) => !e.problem && e.action !== "unchanged");
|
|
70551
|
+
const overwrites = writable.filter((e) => e.action === "overwrite");
|
|
70552
|
+
console.log(strong(`Import plan \u2014 ${plan.length} key(s) considered`));
|
|
70553
|
+
renderPlan(plan);
|
|
70554
|
+
console.log();
|
|
70555
|
+
if (writable.length === 0) {
|
|
70556
|
+
console.log(dim3("Everything is already stored with the same value. Nothing to do."));
|
|
70557
|
+
return;
|
|
70558
|
+
}
|
|
70559
|
+
if (overwrites.length > 0) {
|
|
70560
|
+
console.log(warn(`${overwrites.length} existing keychain item(s) will be REPLACED. The previous values cannot be recovered.`));
|
|
70561
|
+
}
|
|
70562
|
+
if (opts.dryRun) {
|
|
70563
|
+
console.log(dim3("--dry-run: nothing was written."));
|
|
70564
|
+
return;
|
|
70565
|
+
}
|
|
70566
|
+
if (!opts.yes) {
|
|
70567
|
+
const { confirm } = await Promise.resolve().then(() => (init_dist16(), exports_dist));
|
|
70568
|
+
const proceed = await confirm({
|
|
70569
|
+
message: `Store ${writable.length} key(s) in the macOS Keychain?`,
|
|
70570
|
+
default: overwrites.length === 0
|
|
70571
|
+
});
|
|
70572
|
+
if (!proceed) {
|
|
70573
|
+
console.log(dim3("Cancelled \u2014 nothing was written."));
|
|
70574
|
+
return;
|
|
70575
|
+
}
|
|
70576
|
+
}
|
|
70577
|
+
const { written, failures } = writeImportEntries(writable);
|
|
70578
|
+
reportImportResult(written, failures);
|
|
70579
|
+
const skipped = plan.filter((e) => e.problem);
|
|
70580
|
+
if (skipped.length > 0) {
|
|
70581
|
+
console.log(warn(`${skipped.length} key(s) skipped \u2014 see the plan above.`));
|
|
70582
|
+
}
|
|
70583
|
+
}
|
|
70584
|
+
async function readSecretInteractively(envVar) {
|
|
70585
|
+
if (!process.stdin.isTTY) {
|
|
70586
|
+
const piped = await new Response(Bun.stdin.stream()).text();
|
|
70587
|
+
const value2 = piped.replace(/\r?\n$/, "");
|
|
70588
|
+
return value2.length > 0 ? value2 : null;
|
|
70589
|
+
}
|
|
70590
|
+
const { password } = await Promise.resolve().then(() => (init_dist16(), exports_dist));
|
|
70591
|
+
const value = await password({ message: `Value for ${envVar}:`, mask: "\u2022" });
|
|
70592
|
+
return value.length > 0 ? value : null;
|
|
70593
|
+
}
|
|
70594
|
+
async function keychainSet(envVar) {
|
|
70595
|
+
if (!requireKeychain())
|
|
70596
|
+
return;
|
|
70597
|
+
if (!envVar) {
|
|
70598
|
+
console.error(bad("Usage: claudish keychain set <ENV_VAR>"));
|
|
70599
|
+
process.exitCode = 1;
|
|
70600
|
+
return;
|
|
70601
|
+
}
|
|
70602
|
+
if (!isValidKeychainVarName(envVar)) {
|
|
70603
|
+
console.error(bad(`"${envVar}" is not a valid environment variable name.`));
|
|
70604
|
+
process.exitCode = 1;
|
|
70605
|
+
return;
|
|
70606
|
+
}
|
|
70607
|
+
const value = await readSecretInteractively(envVar);
|
|
70608
|
+
if (!value) {
|
|
70609
|
+
console.log(dim3("Aborted \u2014 no value given."));
|
|
70610
|
+
return;
|
|
70611
|
+
}
|
|
70612
|
+
try {
|
|
70613
|
+
writeKeychainSecret(envVar, value);
|
|
70614
|
+
} catch (err) {
|
|
70615
|
+
console.error(bad(err instanceof Error ? err.message : String(err)));
|
|
70616
|
+
process.exitCode = 1;
|
|
70617
|
+
return;
|
|
70618
|
+
}
|
|
70619
|
+
if (!isKeychainEnabled())
|
|
70620
|
+
setKeychainEnabled(true);
|
|
70621
|
+
console.log(ok(`Stored ${envVar} ${dim3(valueTail2(value))} in the macOS Keychain.`));
|
|
70622
|
+
if (process.env[envVar]) {
|
|
70623
|
+
console.log(warn(`Note: ${envVar} is also set in this shell, and an env var takes precedence at runtime.`));
|
|
70624
|
+
}
|
|
70625
|
+
}
|
|
70626
|
+
function keychainRemove(envVar) {
|
|
70627
|
+
if (!requireKeychain())
|
|
70628
|
+
return;
|
|
70629
|
+
if (!envVar) {
|
|
70630
|
+
console.error(bad("Usage: claudish keychain rm <ENV_VAR>"));
|
|
70631
|
+
process.exitCode = 1;
|
|
70632
|
+
return;
|
|
70633
|
+
}
|
|
70634
|
+
try {
|
|
70635
|
+
const removed = deleteKeychainSecret(envVar);
|
|
70636
|
+
console.log(removed ? ok(`Removed ${envVar} from the macOS Keychain.`) : dim3(`${envVar} was not in the keychain \u2014 nothing to remove.`));
|
|
70637
|
+
} catch (err) {
|
|
70638
|
+
console.error(bad(err instanceof Error ? err.message : String(err)));
|
|
70639
|
+
process.exitCode = 1;
|
|
70640
|
+
}
|
|
70641
|
+
}
|
|
70642
|
+
function keychainToggle(enabled2) {
|
|
70643
|
+
if (enabled2 && !requireKeychain())
|
|
70644
|
+
return;
|
|
70645
|
+
setKeychainEnabled(enabled2);
|
|
70646
|
+
invalidateKeychainCache();
|
|
70647
|
+
console.log(enabled2 ? ok("Keychain backend enabled \u2014 claudish will now read keys from the macOS Keychain.") : ok("Keychain backend disabled. Stored items were left untouched."));
|
|
70648
|
+
if (!enabled2) {
|
|
70649
|
+
console.log(dim3("Remove the items themselves with: claudish keychain rm <ENV_VAR>"));
|
|
70650
|
+
}
|
|
70651
|
+
}
|
|
70652
|
+
function usage() {
|
|
70653
|
+
console.log(`${strong("claudish keychain")} \u2014 macOS Keychain credential backend
|
|
70654
|
+
|
|
70655
|
+
${strong("status")} Backend state and how many keys are stored (default)
|
|
70656
|
+
${strong("list")} Stored variables, with ${dim3("\u2022\u2022\u2022\u20221234")} identification tails
|
|
70657
|
+
${strong("import")} [options] Copy secrets from env vars / 1Password into the keychain
|
|
70658
|
+
${strong("set")} <ENV_VAR> Store one secret (prompted, or piped on stdin)
|
|
70659
|
+
${strong("rm")} <ENV_VAR> Remove one secret
|
|
70660
|
+
${strong("enable")} | ${strong("disable")} Turn the backend on/off (moves no secrets)
|
|
70661
|
+
|
|
70662
|
+
${strong("import options")}
|
|
70663
|
+
--from env|1password|all Source to copy from (default: all)
|
|
70664
|
+
--only VAR,VAR Restrict to these variables
|
|
70665
|
+
--dry-run Show the plan and stop
|
|
70666
|
+
--yes Skip the confirmation
|
|
70667
|
+
|
|
70668
|
+
Resolution order: ${dim3("env var \u2192 alias \u2192 config.json \u2192 macOS Keychain \u2192 1Password")}
|
|
70669
|
+
`);
|
|
70670
|
+
}
|
|
70671
|
+
function parseOnly(args) {
|
|
70672
|
+
const idx = args.findIndex((a) => a === "--only" || a.startsWith("--only="));
|
|
70673
|
+
if (idx === -1)
|
|
70674
|
+
return;
|
|
70675
|
+
const raw2 = args[idx].includes("=") ? args[idx].split("=").slice(1).join("=") : args[idx + 1];
|
|
70676
|
+
if (!raw2)
|
|
70677
|
+
return;
|
|
70678
|
+
const names = raw2.split(",").map((n) => n.trim()).filter(Boolean);
|
|
70679
|
+
return names.length > 0 ? names : undefined;
|
|
70680
|
+
}
|
|
70681
|
+
function parseFrom(args) {
|
|
70682
|
+
const idx = args.findIndex((a) => a === "--from" || a.startsWith("--from="));
|
|
70683
|
+
if (idx === -1)
|
|
70684
|
+
return "all";
|
|
70685
|
+
const raw2 = (args[idx].includes("=") ? args[idx].split("=").slice(1).join("=") : args[idx + 1])?.trim().toLowerCase();
|
|
70686
|
+
if (raw2 === "env" || raw2 === "1password" || raw2 === "all")
|
|
70687
|
+
return raw2;
|
|
70688
|
+
if (raw2 === "op")
|
|
70689
|
+
return "1password";
|
|
70690
|
+
return "all";
|
|
70691
|
+
}
|
|
70692
|
+
function positionalArgs(args) {
|
|
70693
|
+
const out = [];
|
|
70694
|
+
for (let i = 0;i < args.length; i++) {
|
|
70695
|
+
const arg = args[i];
|
|
70696
|
+
if (arg.startsWith("-")) {
|
|
70697
|
+
if (VALUE_FLAGS.has(arg))
|
|
70698
|
+
i++;
|
|
70699
|
+
continue;
|
|
70700
|
+
}
|
|
70701
|
+
out.push(arg);
|
|
70702
|
+
}
|
|
70703
|
+
return out;
|
|
70704
|
+
}
|
|
70705
|
+
async function keychainCommand(args) {
|
|
70706
|
+
const positional = positionalArgs(args);
|
|
70707
|
+
const sub = positional[0] ?? "status";
|
|
70708
|
+
switch (sub) {
|
|
70709
|
+
case "status":
|
|
70710
|
+
keychainStatus();
|
|
70711
|
+
return;
|
|
70712
|
+
case "list":
|
|
70713
|
+
case "ls":
|
|
70714
|
+
keychainList();
|
|
70715
|
+
return;
|
|
70716
|
+
case "import":
|
|
70717
|
+
await keychainImport({
|
|
70718
|
+
from: parseFrom(args),
|
|
70719
|
+
only: parseOnly(args),
|
|
70720
|
+
dryRun: args.includes("--dry-run"),
|
|
70721
|
+
yes: args.includes("--yes") || args.includes("-y")
|
|
70722
|
+
});
|
|
70723
|
+
return;
|
|
70724
|
+
case "set":
|
|
70725
|
+
await keychainSet(positional[1]);
|
|
70726
|
+
return;
|
|
70727
|
+
case "rm":
|
|
70728
|
+
case "remove":
|
|
70729
|
+
case "delete":
|
|
70730
|
+
keychainRemove(positional[1]);
|
|
70731
|
+
return;
|
|
70732
|
+
case "enable":
|
|
70733
|
+
keychainToggle(true);
|
|
70734
|
+
return;
|
|
70735
|
+
case "disable":
|
|
70736
|
+
keychainToggle(false);
|
|
70737
|
+
return;
|
|
70738
|
+
case "help":
|
|
70739
|
+
usage();
|
|
70740
|
+
return;
|
|
70741
|
+
default:
|
|
70742
|
+
console.error(bad(`Unknown subcommand: ${sub}`));
|
|
70743
|
+
usage();
|
|
70744
|
+
process.exitCode = 1;
|
|
70745
|
+
}
|
|
70746
|
+
}
|
|
70747
|
+
var VALUE_FLAGS;
|
|
70748
|
+
var init_keychain_command = __esm(() => {
|
|
70749
|
+
init_ansi();
|
|
70750
|
+
init_op_source();
|
|
70751
|
+
init_profile_config();
|
|
70752
|
+
init_keychain();
|
|
70753
|
+
init_provider_definitions();
|
|
70754
|
+
VALUE_FLAGS = new Set(["--config", "--from", "--only"]);
|
|
70755
|
+
});
|
|
70756
|
+
|
|
69844
70757
|
// src/auth/antigravity-oauth.ts
|
|
69845
70758
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
69846
70759
|
import { existsSync as existsSync26, unlinkSync as unlinkSync7 } from "fs";
|
|
@@ -69881,16 +70794,16 @@ function defaultRunAgyAuth(agyPath, interactive) {
|
|
|
69881
70794
|
spawnSync3(agyPath, ["-p", "hello", "--print-timeout", "3m"], { stdio: "inherit" });
|
|
69882
70795
|
}
|
|
69883
70796
|
}
|
|
69884
|
-
async function pollForToken(
|
|
69885
|
-
const deadline =
|
|
70797
|
+
async function pollForToken(deps2) {
|
|
70798
|
+
const deadline = deps2.now() + deps2.timing.graceMs;
|
|
69886
70799
|
for (;; ) {
|
|
69887
|
-
const tok =
|
|
70800
|
+
const tok = deps2.readToken();
|
|
69888
70801
|
if (tok)
|
|
69889
70802
|
return tok;
|
|
69890
|
-
if (
|
|
70803
|
+
if (deps2.now() >= deadline)
|
|
69891
70804
|
return null;
|
|
69892
|
-
const remaining = deadline -
|
|
69893
|
-
await
|
|
70805
|
+
const remaining = deadline - deps2.now();
|
|
70806
|
+
await deps2.sleep(Math.min(deps2.timing.intervalMs, Math.max(0, remaining)));
|
|
69894
70807
|
}
|
|
69895
70808
|
}
|
|
69896
70809
|
|
|
@@ -69904,67 +70817,67 @@ class AntigravityOAuth {
|
|
|
69904
70817
|
}
|
|
69905
70818
|
constructor() {}
|
|
69906
70819
|
async login(depsOverride = {}) {
|
|
69907
|
-
const
|
|
70820
|
+
const deps2 = { ...defaultLoginDeps, ...depsOverride };
|
|
69908
70821
|
log("[AntigravityOAuth] Starting agy-delegated login");
|
|
69909
|
-
if (
|
|
69910
|
-
console.log(`\u2705 Already authenticated with Antigravity. Use: claudish --model ag@${await (
|
|
69911
|
-
return
|
|
70822
|
+
if (deps2.hasToken()) {
|
|
70823
|
+
console.log(`\u2705 Already authenticated with Antigravity. Use: claudish --model ag@${await (deps2.suggestModel ?? defaultSuggestModel)()}`);
|
|
70824
|
+
return deps2.exit(0);
|
|
69912
70825
|
}
|
|
69913
|
-
let agyPath =
|
|
70826
|
+
let agyPath = deps2.locateAgy();
|
|
69914
70827
|
if (!agyPath) {
|
|
69915
70828
|
console.log("\nThe Antigravity CLI (`agy`) is required to sign in to Antigravity.");
|
|
69916
70829
|
console.log(`claudish delegates Antigravity sign-in to agy \u2014 agy holds the current OAuth secret
|
|
69917
70830
|
` + "and writes the session to the shared keychain store that claudish reads.");
|
|
69918
|
-
if (!
|
|
70831
|
+
if (!deps2.isInteractive()) {
|
|
69919
70832
|
printManualInstall();
|
|
69920
|
-
return
|
|
70833
|
+
return deps2.exit(0);
|
|
69921
70834
|
}
|
|
69922
|
-
const proceed = await
|
|
70835
|
+
const proceed = await deps2.confirmInstall();
|
|
69923
70836
|
if (!proceed) {
|
|
69924
70837
|
printManualInstall();
|
|
69925
|
-
return
|
|
70838
|
+
return deps2.exit(0);
|
|
69926
70839
|
}
|
|
69927
70840
|
console.log(`
|
|
69928
70841
|
Installing the Antigravity CLI\u2026
|
|
69929
70842
|
`);
|
|
69930
|
-
if (!
|
|
70843
|
+
if (!deps2.runInstall()) {
|
|
69931
70844
|
console.log(`
|
|
69932
70845
|
\u274C Antigravity CLI installation failed.`);
|
|
69933
70846
|
printManualInstall();
|
|
69934
|
-
return
|
|
70847
|
+
return deps2.exit(0);
|
|
69935
70848
|
}
|
|
69936
|
-
agyPath =
|
|
70849
|
+
agyPath = deps2.locateAgy();
|
|
69937
70850
|
if (!agyPath) {
|
|
69938
70851
|
console.log(`
|
|
69939
70852
|
\u274C Antigravity CLI still not found after install.`);
|
|
69940
70853
|
printManualInstall();
|
|
69941
|
-
return
|
|
70854
|
+
return deps2.exit(0);
|
|
69942
70855
|
}
|
|
69943
70856
|
}
|
|
69944
70857
|
console.log(`
|
|
69945
70858
|
Launching the Antigravity CLI to sign in \u2014 complete the sign-in in your browser.
|
|
69946
70859
|
` + `claudish will detect the session automatically.
|
|
69947
70860
|
`);
|
|
69948
|
-
|
|
69949
|
-
let token = await pollForToken(
|
|
70861
|
+
deps2.runAgyAuth(agyPath, false);
|
|
70862
|
+
let token = await pollForToken(deps2);
|
|
69950
70863
|
if (!token) {
|
|
69951
70864
|
console.log(`
|
|
69952
70865
|
No session detected yet. Starting the Antigravity CLI interactively \u2014
|
|
69953
70866
|
` + "sign in, then exit agy (its `/quit` command or Ctrl-C) to return here.\n");
|
|
69954
|
-
|
|
69955
|
-
token = await pollForToken(
|
|
70867
|
+
deps2.runAgyAuth(agyPath, true);
|
|
70868
|
+
token = await pollForToken(deps2);
|
|
69956
70869
|
}
|
|
69957
70870
|
if (token) {
|
|
69958
|
-
|
|
70871
|
+
deps2.onAuthenticated();
|
|
69959
70872
|
console.log(`
|
|
69960
|
-
\u2705 Authenticated with Antigravity. Use: claudish --model ag@${await (
|
|
69961
|
-
return
|
|
70873
|
+
\u2705 Authenticated with Antigravity. Use: claudish --model ag@${await (deps2.suggestModel ?? defaultSuggestModel)()}`);
|
|
70874
|
+
return deps2.exit(0);
|
|
69962
70875
|
}
|
|
69963
70876
|
console.log("\nNo Antigravity session detected. Run `agy` and sign in, then retry `claudish login antigravity`.");
|
|
69964
|
-
return
|
|
70877
|
+
return deps2.exit(0);
|
|
69965
70878
|
}
|
|
69966
|
-
async logout(
|
|
69967
|
-
deleteSharedAntigravityToken(
|
|
70879
|
+
async logout(deps2) {
|
|
70880
|
+
deleteSharedAntigravityToken(deps2);
|
|
69968
70881
|
try {
|
|
69969
70882
|
const tokenFile = join36(homedir31(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
|
|
69970
70883
|
if (existsSync26(tokenFile))
|
|
@@ -70166,7 +71079,7 @@ async function quotaCommand(provider) {
|
|
|
70166
71079
|
`);
|
|
70167
71080
|
return;
|
|
70168
71081
|
}
|
|
70169
|
-
|
|
71082
|
+
renderPlan2(adapter, plan);
|
|
70170
71083
|
}
|
|
70171
71084
|
function resolveAdapterFromInput(input) {
|
|
70172
71085
|
const raw2 = input.toLowerCase().replace(/@+$/, "");
|
|
@@ -70196,7 +71109,7 @@ async function promptForAdapter() {
|
|
|
70196
71109
|
});
|
|
70197
71110
|
return select({ message: "Select provider:", choices });
|
|
70198
71111
|
}
|
|
70199
|
-
function
|
|
71112
|
+
function renderPlan2(adapter, plan) {
|
|
70200
71113
|
console.log("");
|
|
70201
71114
|
boxTop(plan.label);
|
|
70202
71115
|
boxRow("Provider", adapter.providerId);
|
|
@@ -70407,11 +71320,11 @@ function readSlimCacheWithFreshness(reader) {
|
|
|
70407
71320
|
const stale = !Number.isFinite(lastUpdatedMs) || ageMs > FIREBASE_CACHE_TTL_MS;
|
|
70408
71321
|
return { entries: cache3.entries ?? [], stale };
|
|
70409
71322
|
}
|
|
70410
|
-
function createCatalogClient(
|
|
70411
|
-
const _getModelsByProvider =
|
|
70412
|
-
const _getModelByIdFromFirebase =
|
|
70413
|
-
const _searchModels =
|
|
70414
|
-
const _readSlimCache =
|
|
71323
|
+
function createCatalogClient(deps2 = {}) {
|
|
71324
|
+
const _getModelsByProvider = deps2.getModelsByProvider ?? getModelsByProvider;
|
|
71325
|
+
const _getModelByIdFromFirebase = deps2.getModelByIdFromFirebase ?? getModelByIdFromFirebase;
|
|
71326
|
+
const _searchModels = deps2.searchModels ?? searchModels;
|
|
71327
|
+
const _readSlimCache = deps2.readSlimCache ?? readAllModelsCache;
|
|
70415
71328
|
return {
|
|
70416
71329
|
async modelsByVendor(vendorSlug) {
|
|
70417
71330
|
const slug = vendorSlug.toLowerCase();
|
|
@@ -70595,6 +71508,8 @@ function resolveDiscoveredContextLength(m) {
|
|
|
70595
71508
|
}
|
|
70596
71509
|
}
|
|
70597
71510
|
function resolveDiscoveredReleaseDate(m) {
|
|
71511
|
+
if (m.ignoreCatalogReleaseDate)
|
|
71512
|
+
return m.releaseDate;
|
|
70598
71513
|
try {
|
|
70599
71514
|
const catalogDate = lookupModel(m.id)?.releaseDate;
|
|
70600
71515
|
if (catalogDate)
|
|
@@ -71408,10 +72323,42 @@ function registerPaletteRefresher(fn) {
|
|
|
71408
72323
|
paletteRefreshers.push(fn);
|
|
71409
72324
|
fn();
|
|
71410
72325
|
}
|
|
72326
|
+
function hexChannels(hex3) {
|
|
72327
|
+
const m = /^#([0-9a-f]{6})$/i.exec(hex3.trim());
|
|
72328
|
+
if (!m)
|
|
72329
|
+
return null;
|
|
72330
|
+
const n = Number.parseInt(m[1], 16);
|
|
72331
|
+
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
72332
|
+
}
|
|
72333
|
+
function channelsToHex(c) {
|
|
72334
|
+
const hex3 = c.map((v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, "0")).join("");
|
|
72335
|
+
return `#${hex3}`;
|
|
72336
|
+
}
|
|
72337
|
+
function retintSurfaces(palette, pageHex) {
|
|
72338
|
+
const paletteBg = hexChannels(palette.bg);
|
|
72339
|
+
const page = hexChannels(pageHex);
|
|
72340
|
+
if (!paletteBg || !page)
|
|
72341
|
+
return;
|
|
72342
|
+
for (const token of SURFACE_TOKENS) {
|
|
72343
|
+
const original = hexChannels(palette[token]);
|
|
72344
|
+
if (!original)
|
|
72345
|
+
continue;
|
|
72346
|
+
C[token] = channelsToHex([
|
|
72347
|
+
page[0] + (original[0] - paletteBg[0]),
|
|
72348
|
+
page[1] + (original[1] - paletteBg[1]),
|
|
72349
|
+
page[2] + (original[2] - paletteBg[2])
|
|
72350
|
+
]);
|
|
72351
|
+
}
|
|
72352
|
+
}
|
|
71411
72353
|
function applyTuiTheme(mode) {
|
|
71412
72354
|
const palette = mode === "light" ? LIGHT2 : DARK;
|
|
71413
72355
|
activeLatencyBuckets = mode === "light" ? LATENCY_BUCKETS_LIGHT : LATENCY_BUCKETS_DARK;
|
|
71414
72356
|
Object.assign(C, palette);
|
|
72357
|
+
const terminalBg = getTerminalBackground();
|
|
72358
|
+
if (terminalBg && terminalBg.mode === mode) {
|
|
72359
|
+
C.bg = terminalBg.hex;
|
|
72360
|
+
retintSurfaces(palette, terminalBg.hex);
|
|
72361
|
+
}
|
|
71415
72362
|
Object.assign(STAGE_BG, mode === "light" ? STAGE_BG_LIGHT : STAGE_BG_DARK);
|
|
71416
72363
|
STAGE_BG_ANSI.network = hexToAnsiBg(STAGE_BG.network);
|
|
71417
72364
|
STAGE_BG_ANSI.server = hexToAnsiBg(STAGE_BG.server);
|
|
@@ -71488,7 +72435,7 @@ function tokBarCells(tokensPerSec, maxTokPerSec, tokWidth) {
|
|
|
71488
72435
|
const raw2 = Math.round(tokWidth * Math.max(0, tokensPerSec) / denom);
|
|
71489
72436
|
return Math.min(tokWidth, Math.max(0, raw2));
|
|
71490
72437
|
}
|
|
71491
|
-
var DARK, LIGHT2, C, bold3, A, LATENCY_BUCKETS_DARK, LATENCY_BUCKETS_LIGHT, activeLatencyBuckets, latencyFg = "#ffffff", LATENCY_FG_ANSI = "\x1B[38;2;255;255;255m", ANSI_RESET = "\x1B[0m", STAGE_BG_DARK, STAGE_BG_LIGHT, STAGE_BG, STAGE_FG, STAGE_BG_ANSI, paletteRefreshers;
|
|
72438
|
+
var DARK, LIGHT2, C, bold3, A, LATENCY_BUCKETS_DARK, LATENCY_BUCKETS_LIGHT, activeLatencyBuckets, latencyFg = "#ffffff", LATENCY_FG_ANSI = "\x1B[38;2;255;255;255m", ANSI_RESET = "\x1B[0m", STAGE_BG_DARK, STAGE_BG_LIGHT, STAGE_BG, STAGE_FG, STAGE_BG_ANSI, paletteRefreshers, SURFACE_TOKENS;
|
|
71492
72439
|
var init_theme2 = __esm(() => {
|
|
71493
72440
|
init_theme_mode();
|
|
71494
72441
|
DARK = {
|
|
@@ -71598,6 +72545,7 @@ var init_theme2 = __esm(() => {
|
|
|
71598
72545
|
streaming: hexToAnsiBg(STAGE_BG.streaming)
|
|
71599
72546
|
};
|
|
71600
72547
|
paletteRefreshers = [];
|
|
72548
|
+
SURFACE_TOKENS = ["bgAlt", "border", "tabInactiveBg", "chipKeyBg", "chipLabelBg"];
|
|
71601
72549
|
onThemeModeChange(applyTuiTheme);
|
|
71602
72550
|
});
|
|
71603
72551
|
|
|
@@ -71802,6 +72750,8 @@ function shortStatusLabel(probe2, hasCreds, _hint) {
|
|
|
71802
72750
|
return `${pc.red}\u2297 rate-limited${pc.reset}`;
|
|
71803
72751
|
case "out-of-credit":
|
|
71804
72752
|
return `${pc.red}\u2297 no credit${pc.reset}`;
|
|
72753
|
+
case "plan-limit":
|
|
72754
|
+
return `${pc.red}\u2297 plan limit${pc.reset}`;
|
|
71805
72755
|
case "server-error":
|
|
71806
72756
|
return `${pc.red}\u2297 server ${probe2.httpStatus ?? ""}${pc.reset}`;
|
|
71807
72757
|
case "timeout":
|
|
@@ -75057,7 +76007,7 @@ function printHelp2() {
|
|
|
75057
76007
|
const A2 = cliAnsi();
|
|
75058
76008
|
const c = (esc2) => (s) => useColor && esc2 ? `${esc2}${s}${A2.RESET}` : s;
|
|
75059
76009
|
const bold4 = c(A2.BOLD);
|
|
75060
|
-
const
|
|
76010
|
+
const dim4 = c(A2.DIM);
|
|
75061
76011
|
const cyan = c(A2.CYAN);
|
|
75062
76012
|
const green2 = c(A2.GREEN);
|
|
75063
76013
|
const yellow2 = c(A2.YELLOW);
|
|
@@ -75065,89 +76015,89 @@ function printHelp2() {
|
|
|
75065
76015
|
const blue = c(A2.BLUE);
|
|
75066
76016
|
const h = (title) => bold4(cyan(`\u258C ${title}`));
|
|
75067
76017
|
console.log(`
|
|
75068
|
-
${bold4("claudish")} ${
|
|
75069
|
-
${
|
|
76018
|
+
${bold4("claudish")} ${dim4("\xB7")} Run Claude Code with any AI model
|
|
76019
|
+
${dim4("OpenRouter \xB7 Gemini \xB7 OpenAI \xB7 xAI \xB7 MiniMax \xB7 Kimi \xB7 GLM \xB7 Z.AI \xB7 Sakana \xB7 Poe \xB7 LiteLLM \xB7 Local")}
|
|
75070
76020
|
|
|
75071
76021
|
${h("USAGE")}
|
|
75072
|
-
${green2("claudish")} ${
|
|
75073
|
-
${green2("claudish")} ${yellow2("[OPTIONS] <claude-args...>")} ${
|
|
75074
|
-
${green2("claudish")} ${green2("--team")} ${yellow2("a,b,c")} ${yellow2('"prompt"')} ${
|
|
75075
|
-
${green2("claudish")} ${green2("--team")} ${yellow2("a,b,c")} ${green2("-f")} ${yellow2("input.md")} ${
|
|
76022
|
+
${green2("claudish")} ${dim4("# Interactive mode (default, model selector)")}
|
|
76023
|
+
${green2("claudish")} ${yellow2("[OPTIONS] <claude-args...>")} ${dim4("# Single-shot mode (requires --model)")}
|
|
76024
|
+
${green2("claudish")} ${green2("--team")} ${yellow2("a,b,c")} ${yellow2('"prompt"')} ${dim4("# Run models in parallel (magmux grid)")}
|
|
76025
|
+
${green2("claudish")} ${green2("--team")} ${yellow2("a,b,c")} ${green2("-f")} ${yellow2("input.md")} ${dim4("# Team mode with file input")}
|
|
75076
76026
|
|
|
75077
76027
|
${h("MODEL ROUTING")}
|
|
75078
76028
|
${bold4("New syntax:")} ${yellow2("provider@model[:concurrency]")}
|
|
75079
|
-
${magenta("google@gemini-3-pro")} ${
|
|
75080
|
-
${magenta("openrouter@google/gemini-3-pro")} ${
|
|
75081
|
-
${magenta("oai@gpt-5.3")} ${
|
|
75082
|
-
${magenta("ollama@llama3.2:3")} ${
|
|
75083
|
-
${magenta("ollama@llama3.2:0")} ${
|
|
76029
|
+
${magenta("google@gemini-3-pro")} ${dim4("Direct Google API (explicit)")}
|
|
76030
|
+
${magenta("openrouter@google/gemini-3-pro")} ${dim4("OpenRouter (explicit)")}
|
|
76031
|
+
${magenta("oai@gpt-5.3")} ${dim4("Direct OpenAI API (shortcut)")}
|
|
76032
|
+
${magenta("ollama@llama3.2:3")} ${dim4("Local Ollama, 3 concurrent requests")}
|
|
76033
|
+
${magenta("ollama@llama3.2:0")} ${dim4("Local Ollama, no limits")}
|
|
75084
76034
|
|
|
75085
76035
|
${bold4("Provider shortcuts:")}
|
|
75086
|
-
${magenta("g, gemini")} ${
|
|
75087
|
-
${magenta("oai")} ${
|
|
75088
|
-
${magenta("cx, codex")} ${
|
|
75089
|
-
${magenta("or")} ${
|
|
75090
|
-
${magenta("x-ai, xai, grok")} ${
|
|
75091
|
-
${magenta("mm, mmax")} ${
|
|
75092
|
-
${magenta("mmc")} ${
|
|
75093
|
-
${magenta("kimi, moon")} ${
|
|
75094
|
-
${magenta("kc")} ${
|
|
75095
|
-
${magenta("glm, zhipu")} ${
|
|
75096
|
-
${magenta("gc")} ${
|
|
75097
|
-
${magenta("z-ai, zai")} ${
|
|
75098
|
-
${magenta("oc, llama, lc, meta")} ${
|
|
75099
|
-
${magenta("zen")} ${
|
|
75100
|
-
${magenta("zengo, zgo")} ${
|
|
75101
|
-
${magenta("v, vertex")} ${
|
|
75102
|
-
${magenta("poe")} ${
|
|
75103
|
-
${magenta("litellm, ll")} ${
|
|
75104
|
-
${magenta("ds")} ${
|
|
75105
|
-
${magenta("sakana, fugu")} ${
|
|
75106
|
-
${magenta("sc")} ${
|
|
75107
|
-
${magenta("ollama")} ${
|
|
75108
|
-
${magenta("lms, lmstudio")} ${
|
|
75109
|
-
${magenta("vllm")} ${
|
|
75110
|
-
${magenta("mlx")} ${
|
|
75111
|
-
|
|
75112
|
-
${bold4("Native auto-detection")} ${
|
|
75113
|
-
${yellow2("google/*, gemini-*")} ${
|
|
75114
|
-
${yellow2("openai/*, gpt-*, o1-*")} ${
|
|
75115
|
-
${yellow2("x-ai/*, grok-*")} ${
|
|
75116
|
-
${yellow2("meta-llama/*, llama-*")} ${
|
|
75117
|
-
${yellow2("minimax/*, abab-*")} ${
|
|
75118
|
-
${yellow2("moonshot/*, kimi-*")} ${
|
|
75119
|
-
${yellow2("zhipu/*, glm-*")} ${
|
|
75120
|
-
${yellow2("sakana/*, fugu-*")} ${
|
|
75121
|
-
${yellow2("poe:*")} ${
|
|
75122
|
-
${yellow2("anthropic/*, claude-*")} ${
|
|
75123
|
-
${yellow2("(unknown vendor/)")} ${
|
|
75124
|
-
|
|
75125
|
-
${
|
|
76036
|
+
${magenta("g, gemini")} ${dim4("->")} Google Gemini ${dim4("google@gemini-3-pro")}
|
|
76037
|
+
${magenta("oai")} ${dim4("->")} OpenAI Direct ${dim4("oai@gpt-5.3")}
|
|
76038
|
+
${magenta("cx, codex")} ${dim4("->")} OpenAI Codex ${dim4("cx@gpt-5.3 (Responses API)")}
|
|
76039
|
+
${magenta("or")} ${dim4("->")} OpenRouter ${dim4("or@openai/gpt-5.3")}
|
|
76040
|
+
${magenta("x-ai, xai, grok")} ${dim4("->")} xAI / Grok ${dim4("x-ai@grok-3")}
|
|
76041
|
+
${magenta("mm, mmax")} ${dim4("->")} MiniMax Direct ${dim4("mm@MiniMax-M2.1")}
|
|
76042
|
+
${magenta("mmc")} ${dim4("->")} MiniMax Coding ${dim4("mmc@MiniMax-M2.1")}
|
|
76043
|
+
${magenta("kimi, moon")} ${dim4("->")} Kimi Direct ${dim4("kimi@kimi-k2-thinking-turbo")}
|
|
76044
|
+
${magenta("kc")} ${dim4("->")} Kimi Coding ${dim4("kc@kimi-k2-thinking-turbo")}
|
|
76045
|
+
${magenta("glm, zhipu")} ${dim4("->")} GLM Direct ${dim4("glm@glm-4.7")}
|
|
76046
|
+
${magenta("gc")} ${dim4("->")} GLM Coding ${dim4("gc@glm-4.7")}
|
|
76047
|
+
${magenta("z-ai, zai")} ${dim4("->")} Z.AI Direct ${dim4("z-ai@glm-4.7")}
|
|
76048
|
+
${magenta("oc, llama, lc, meta")} ${dim4("->")} OllamaCloud ${dim4("oc@llama-3.1")}
|
|
76049
|
+
${magenta("zen")} ${dim4("->")} OpenCode Zen ${dim4("zen@grok-code")}
|
|
76050
|
+
${magenta("zengo, zgo")} ${dim4("->")} OpenCode Zen Go ${dim4("zengo@grok-code")}
|
|
76051
|
+
${magenta("v, vertex")} ${dim4("->")} Vertex AI ${dim4("v@gemini-2.5-flash")}
|
|
76052
|
+
${magenta("poe")} ${dim4("->")} Poe ${dim4("poe@GPT-4o")}
|
|
76053
|
+
${magenta("litellm, ll")} ${dim4("->")} LiteLLM ${dim4("ll@gpt-4o (needs LITELLM_BASE_URL)")}
|
|
76054
|
+
${magenta("ds")} ${dim4("->")} DeepSeek ${dim4("ds@deepseek-chat")}
|
|
76055
|
+
${magenta("sakana, fugu")} ${dim4("->")} Sakana Fugu ${dim4("fugu@fugu-ultra")}
|
|
76056
|
+
${magenta("sc")} ${dim4("->")} Sakana Subscription ${dim4("sc@fugu-ultra")}
|
|
76057
|
+
${magenta("ollama")} ${dim4("->")} Ollama (local) ${dim4("ollama@llama3.2")}
|
|
76058
|
+
${magenta("lms, lmstudio")} ${dim4("->")} LM Studio (local) ${dim4("lms@qwen")}
|
|
76059
|
+
${magenta("vllm")} ${dim4("->")} vLLM (local) ${dim4("vllm@model")}
|
|
76060
|
+
${magenta("mlx")} ${dim4("->")} MLX (local) ${dim4("mlx@model")}
|
|
76061
|
+
|
|
76062
|
+
${bold4("Native auto-detection")} ${dim4("(when no provider specified):")}
|
|
76063
|
+
${yellow2("google/*, gemini-*")} ${dim4("->")} Google API
|
|
76064
|
+
${yellow2("openai/*, gpt-*, o1-*")} ${dim4("->")} OpenAI API
|
|
76065
|
+
${yellow2("x-ai/*, grok-*")} ${dim4("->")} xAI
|
|
76066
|
+
${yellow2("meta-llama/*, llama-*")} ${dim4("->")} OllamaCloud
|
|
76067
|
+
${yellow2("minimax/*, abab-*")} ${dim4("->")} MiniMax API
|
|
76068
|
+
${yellow2("moonshot/*, kimi-*")} ${dim4("->")} Kimi API
|
|
76069
|
+
${yellow2("zhipu/*, glm-*")} ${dim4("->")} GLM API
|
|
76070
|
+
${yellow2("sakana/*, fugu-*")} ${dim4("->")} Sakana Fugu
|
|
76071
|
+
${yellow2("poe:*")} ${dim4("->")} Poe
|
|
76072
|
+
${yellow2("anthropic/*, claude-*")} ${dim4("->")} Native Anthropic
|
|
76073
|
+
${yellow2("(unknown vendor/)")} ${dim4("->")} Error (use openrouter@vendor/model)
|
|
76074
|
+
|
|
76075
|
+
${dim4("A defaultProvider (config / --default-provider) catches bare names that match no rule.")}
|
|
75126
76076
|
|
|
75127
76077
|
${h("OPTIONS")}
|
|
75128
76078
|
${green2("-i, --interactive")} Run in interactive mode (default when no prompt given)
|
|
75129
76079
|
${green2("-m, --model")} ${yellow2("<model>")} Model to use (required for single-shot mode)
|
|
75130
76080
|
${green2("--profile")} ${yellow2("<name>")} Use named profile for model mapping (default profile if omitted)
|
|
75131
76081
|
${green2("--default-provider")} ${yellow2("<name>")} Fallback provider for bare model names (builtin or customEndpoints key)
|
|
75132
|
-
${
|
|
76082
|
+
${dim4("Precedence: this flag > CLAUDISH_DEFAULT_PROVIDER env > config.json")}
|
|
75133
76083
|
${green2("--anthropic-api-billing")} Use your real ANTHROPIC_API_KEY for native Claude models
|
|
75134
|
-
${
|
|
75135
|
-
${
|
|
75136
|
-
${
|
|
76084
|
+
${dim4("(metered API billing). Default: the key is hidden so Claude Code")}
|
|
76085
|
+
${dim4("uses your claude.ai subscription. Env: CLAUDISH_ANTHROPIC_API_BILLING")}
|
|
76086
|
+
${dim4("Config: anthropicApiBilling: true")}
|
|
75137
76087
|
${green2("--config")} ${yellow2("<file>")} Use THIS config file for the run, fully replacing the machine
|
|
75138
|
-
${
|
|
75139
|
-
${
|
|
75140
|
-
${
|
|
76088
|
+
${dim4("global (~/.claudish/config.json) AND project (.claudish.json).")}
|
|
76089
|
+
${dim4("A file naming no op:// source never touches 1Password (no prompt).")}
|
|
76090
|
+
${dim4("Env vars still resolve first. Env: CLAUDISH_CONFIG")}
|
|
75141
76091
|
${green2("--op")} ${yellow2("<op://glob>")} Load API keys from a 1Password item glob (SDK-based, no op CLI)
|
|
75142
76092
|
${green2("--op")} ${yellow2("<glob>")} ${green2("--list")} Preview which fields the glob would import (names only, no values)
|
|
75143
76093
|
${green2("--op-env")} ${yellow2("<id>")} Load env vars from a 1Password Environment (highest priority)
|
|
75144
76094
|
${green2("--port")} ${yellow2("<port>")} Proxy server port (default: random)
|
|
75145
76095
|
${green2("-d, --debug-claudish")} Enable claudish debug logging to file (logs/claudish_*.log)
|
|
75146
|
-
${
|
|
76096
|
+
${dim4('Always-on: CLAUDISH_DEBUG=1 env var or "debug": true in config.json')}
|
|
75147
76097
|
${green2("--no-debug-claudish")} Force debug logging off for this run (when globally enabled)
|
|
75148
76098
|
${green2("--log-off")} Disable always-on structural logging (~/.claudish/logs/)
|
|
75149
76099
|
${green2("--log-diag")} ${yellow2("<mode>")} Diagnostic output: auto (default), logfile, off
|
|
75150
|
-
${
|
|
76100
|
+
${dim4('Also: CLAUDISH_DIAG_MODE env var or "diagMode" in config.json')}
|
|
75151
76101
|
${green2("--log-level")} ${yellow2("<level>")} Log verbosity: debug (full), info (truncated), minimal (labels)
|
|
75152
76102
|
${green2("-q, --quiet")} Suppress [claudish] log messages (default in single-shot mode)
|
|
75153
76103
|
${green2("-v, --verbose")} Show [claudish] log messages (default in interactive mode)
|
|
@@ -75171,13 +76121,13 @@ ${h("OPTIONS")}
|
|
|
75171
76121
|
${h("MODEL DISCOVERY")}
|
|
75172
76122
|
${green2("--models")} Top 100 ranked (Firebase + local providers)
|
|
75173
76123
|
${green2("--models --provider")} ${yellow2("<slug>")} Filter the catalog to one provider
|
|
75174
|
-
${
|
|
76124
|
+
${dim4("e.g. --provider opencode-zen, anthropic, openai")}
|
|
75175
76125
|
${green2("--providers")} Every provider + active-model count
|
|
75176
76126
|
${green2("-s, --models-search")} ${yellow2("<query>")} Fuzzy search: id, brand synonyms (chatgpt,
|
|
75177
|
-
${
|
|
76127
|
+
${dim4("claude, grok), gateways (zen, oc, codex), caps")}
|
|
75178
76128
|
${green2("--models-top")} Curated recommended models (flagship + fast)
|
|
75179
76129
|
${green2("--probe")} ${yellow2("<models...>")} Probe each provider in the fallback chain with
|
|
75180
|
-
${
|
|
76130
|
+
${dim4("a real 1-token request (may incur tiny cost)")}
|
|
75181
76131
|
${green2("--no-probe")} Skip live requests, show static chain only
|
|
75182
76132
|
${green2("--probe-timeout")} ${yellow2("<secs>")} Per-link timeout for live probes (default: 40)
|
|
75183
76133
|
${green2("--models-refresh")} Force refresh the slim model catalog from Firebase
|
|
@@ -75186,11 +76136,11 @@ ${h("MODEL DISCOVERY")}
|
|
|
75186
76136
|
|
|
75187
76137
|
${h("TEAM MODE")}
|
|
75188
76138
|
${green2("--team")} ${yellow2("<models>")} Run multiple models in parallel (comma-separated)
|
|
75189
|
-
${
|
|
76139
|
+
${dim4('Example: --team minimax-m2.5,kimi-k2.5 "prompt"')}
|
|
75190
76140
|
${green2("--mode")} ${yellow2("<mode>")} Team mode: default (grid), interactive, json
|
|
75191
76141
|
${green2("-f, --file")} ${yellow2("<path>")} Read prompt from file (use with --team or single-shot)
|
|
75192
76142
|
|
|
75193
|
-
${h("MODEL MAPPING")} ${
|
|
76143
|
+
${h("MODEL MAPPING")} ${dim4("(per-role override)")}
|
|
75194
76144
|
${green2("--model-opus")} ${yellow2("<model>")} Model for Opus role (planning, complex tasks)
|
|
75195
76145
|
${green2("--model-sonnet")} ${yellow2("<model>")} Model for Sonnet role (default coding)
|
|
75196
76146
|
${green2("--model-haiku")} ${yellow2("<model>")} Model for Haiku role (fast tasks, background)
|
|
@@ -75198,7 +76148,7 @@ ${h("MODEL MAPPING")} ${dim3("(per-role override)")}
|
|
|
75198
76148
|
|
|
75199
76149
|
${h("SUBCOMMANDS")}
|
|
75200
76150
|
${green2("claudish config")} Open the interactive config TUI (profiles,
|
|
75201
|
-
${
|
|
76151
|
+
${dim4("providers, routing, 1Password)")}
|
|
75202
76152
|
${green2("claudish providers")} ${yellow2("[--json]")} Show provider credential status (no key material)
|
|
75203
76153
|
${green2("claudish quota")} ${yellow2("[provider]")} Show remaining quota/usage (alias: usage)
|
|
75204
76154
|
${green2("claudish serve")} ${yellow2("--port <n> --models <p>")} Run the Claude Desktop redirect gateway
|
|
@@ -75212,39 +76162,50 @@ ${h("SUBCOMMANDS")}
|
|
|
75212
76162
|
${green2("claudish profile use")} ${yellow2("[name] [scope]")} Set default profile
|
|
75213
76163
|
${green2("claudish profile show")} ${yellow2("[name] [scope]")} Show profile details
|
|
75214
76164
|
${green2("claudish profile edit")} ${yellow2("[name] [scope]")} Edit a profile
|
|
75215
|
-
${
|
|
76165
|
+
${dim4("scope = --local (.claudish.json) | --global (~/.claudish/config.json) | (prompted)")}
|
|
75216
76166
|
|
|
75217
76167
|
${bold4("Authentication:")}
|
|
75218
76168
|
${green2("claudish login")} ${yellow2("[provider]")} Login to an OAuth provider (interactive if omitted)
|
|
75219
76169
|
${green2("claudish logout")} ${yellow2("[provider]")} Clear OAuth credentials
|
|
75220
|
-
${
|
|
76170
|
+
${dim4("Providers: gemini, kimi")}
|
|
75221
76171
|
|
|
75222
|
-
${h("1PASSWORD")} ${
|
|
75223
|
-
${
|
|
76172
|
+
${h("1PASSWORD")} ${dim4("(SDK-based \u2014 no op CLI needed for secrets)")}
|
|
76173
|
+
${dim4("Auth via OP_SERVICE_ACCOUNT_TOKEN, or OP_ACCOUNT / onepasswordAccount config (DesktopAuth).")}
|
|
75224
76174
|
${green2("--op")} ${yellow2("<glob> --list")} Preview which fields a glob would import (names only)
|
|
75225
76175
|
${green2("--op")} ${yellow2("<glob>")} ${yellow2("[...args]")} Resolve a glob into env vars, then run a session
|
|
75226
|
-
${
|
|
75227
|
-
${
|
|
76176
|
+
${dim4("Inline op import requires a GLOB (self-names via field labels)")}
|
|
76177
|
+
${dim4('Example: claudish --op "op://Jack/Keys/**" --model gpt-4o "task"')}
|
|
75228
76178
|
${green2("--op-env")} ${yellow2("<id>")} Load a 1Password Environment (highest-priority source)
|
|
75229
|
-
${
|
|
76179
|
+
${dim4("Persistent setup (single refs, sets, environments, account): claudish config -> 1Password tab")}
|
|
76180
|
+
|
|
76181
|
+
${h("MACOS KEYCHAIN")} ${dim4("(local, encrypted at rest, no desktop-app handshake)")}
|
|
76182
|
+
${green2("claudish keychain status")} Backend state and how many keys are stored
|
|
76183
|
+
${green2("claudish keychain list")} Stored variables, with ${dim4("\u2022\u2022\u2022\u20221234")} identification tails
|
|
76184
|
+
${green2("claudish keychain import")} Copy keys from env vars / 1Password into the keychain
|
|
76185
|
+
${dim4("--from env|1password|all --only VAR,VAR --dry-run --yes")}
|
|
76186
|
+
${green2("claudish keychain set")} ${yellow2("<ENV_VAR>")} Store one key (prompted, or piped on stdin \u2014 never in argv)
|
|
76187
|
+
${green2("claudish keychain rm")} ${yellow2("<ENV_VAR>")} Remove one key
|
|
76188
|
+
${green2("claudish keychain enable")}${dim4("|")}${green2("disable")} Turn the backend on/off (moves no secrets)
|
|
76189
|
+
${dim4("Resolution order: env var -> alias -> config.json -> macOS Keychain -> 1Password")}
|
|
76190
|
+
${dim4("The config TUI's Providers tab writes to the keychain by default on macOS.")}
|
|
75230
76191
|
|
|
75231
76192
|
${h("CLAUDE CODE FLAG PASSTHROUGH")}
|
|
75232
|
-
${
|
|
75233
|
-
${green2("claudish")} --model grok ${yellow2("--agent test")} ${yellow2('"task"')} ${
|
|
75234
|
-
${green2("claudish")} --model grok ${yellow2("--effort high")} --stdin ${yellow2('"task"')} ${
|
|
75235
|
-
${green2("claudish")} --model grok ${yellow2("--permission-mode plan")} -i ${
|
|
75236
|
-
${
|
|
76193
|
+
${dim4("Any unrecognized flag is forwarded to Claude Code. Claudish flags can appear in any order.")}
|
|
76194
|
+
${green2("claudish")} --model grok ${yellow2("--agent test")} ${yellow2('"task"')} ${dim4("# --agent passes through")}
|
|
76195
|
+
${green2("claudish")} --model grok ${yellow2("--effort high")} --stdin ${yellow2('"task"')} ${dim4("# --effort passes, --stdin stays")}
|
|
76196
|
+
${green2("claudish")} --model grok ${yellow2("--permission-mode plan")} -i ${dim4("# works in interactive too")}
|
|
76197
|
+
${dim4("Use -- when a Claude Code flag value starts with '-':")}
|
|
75237
76198
|
${green2("claudish")} --model grok ${green2("--")} ${yellow2('--system-prompt "-verbose mode" "task"')}
|
|
75238
76199
|
|
|
75239
76200
|
${h("CUSTOM MODELS & ENDPOINTS")}
|
|
75240
|
-
${
|
|
76201
|
+
${dim4("Claudish accepts ANY valid model ID from the Firebase catalog, even if not in --models:")}
|
|
75241
76202
|
${green2("claudish")} --model ${yellow2("openrouter@your_provider/custom-model-123")} ${yellow2('"task"')}
|
|
75242
|
-
${
|
|
76203
|
+
${dim4("Named custom endpoints live in ~/.claudish/config.json under 'customEndpoints' and route via @:")}
|
|
75243
76204
|
${green2("claudish")} --model ${yellow2("my-vllm@llama3.1-70b")} ${yellow2('"task"')}
|
|
75244
76205
|
|
|
75245
76206
|
${h("MODES")}
|
|
75246
|
-
${green2("\u2022")} ${bold4("Interactive")} ${
|
|
75247
|
-
${green2("\u2022")} ${bold4("Single-shot")} ${
|
|
76207
|
+
${green2("\u2022")} ${bold4("Interactive")} ${dim4("(default):")} shows model selector, starts a persistent session
|
|
76208
|
+
${green2("\u2022")} ${bold4("Single-shot")} ${dim4("(--model):")} runs one task headless and exits
|
|
75248
76209
|
|
|
75249
76210
|
${h("NOTES")}
|
|
75250
76211
|
${yellow2("\u2022")} Permission prompts are ${bold4("ENABLED")} by default (normal Claude Code behavior)
|
|
@@ -75253,35 +76214,35 @@ ${h("NOTES")}
|
|
|
75253
76214
|
${yellow2("\u2022")} ${green2("--dangerous")} disables the sandbox \u2014 use with extreme caution
|
|
75254
76215
|
|
|
75255
76216
|
${h("ENVIRONMENT VARIABLES")}
|
|
75256
|
-
${
|
|
76217
|
+
${dim4("Claudish auto-loads a .env file from the current directory.")}
|
|
75257
76218
|
|
|
75258
76219
|
${bold4("Claude Code installation:")}
|
|
75259
76220
|
${blue("CLAUDE_PATH")} Custom path to Claude Code binary
|
|
75260
|
-
${
|
|
76221
|
+
${dim4("Search: CLAUDE_PATH -> ~/.claude/local/claude -> PATH")}
|
|
75261
76222
|
|
|
75262
|
-
${bold4("API keys")} ${
|
|
76223
|
+
${bold4("API keys")} ${dim4("(at least one required for cloud models):")}
|
|
75263
76224
|
${blue("OPENROUTER_API_KEY")} OpenRouter (default backend)
|
|
75264
|
-
${blue("GEMINI_API_KEY")} Google Gemini ${
|
|
75265
|
-
${blue("OPENAI_API_KEY")} OpenAI ${
|
|
75266
|
-
${blue("OPENAI_CODEX_API_KEY")} OpenAI Codex / Responses API ${
|
|
75267
|
-
${blue("XAI_API_KEY")} xAI / Grok ${
|
|
75268
|
-
${blue("MINIMAX_API_KEY")} MiniMax ${
|
|
75269
|
-
${blue("MINIMAX_CODING_API_KEY")} MiniMax Coding Plan ${
|
|
75270
|
-
${blue("MOONSHOT_API_KEY")} Kimi / Moonshot ${
|
|
75271
|
-
${blue("KIMI_CODING_API_KEY")} Kimi Coding Plan ${
|
|
75272
|
-
${blue("ZHIPU_API_KEY")} GLM / Zhipu ${
|
|
75273
|
-
${blue("GLM_CODING_API_KEY")} GLM Coding Plan ${
|
|
75274
|
-
${blue("ZAI_API_KEY")} Z.AI ${
|
|
75275
|
-
${blue("DEEPSEEK_API_KEY")} DeepSeek ${
|
|
75276
|
-
${blue("SAKANA_API_KEY")} Sakana Fugu ${
|
|
75277
|
-
${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${
|
|
75278
|
-
${blue("OLLAMA_API_KEY")} OllamaCloud ${
|
|
75279
|
-
${blue("OPENCODE_API_KEY")} OpenCode Zen ${
|
|
75280
|
-
${blue("POE_API_KEY")} Poe ${
|
|
75281
|
-
${blue("LITELLM_API_KEY")} LiteLLM ${
|
|
75282
|
-
${blue("VERTEX_API_KEY")} Vertex AI Express ${
|
|
75283
|
-
${blue("VERTEX_PROJECT")} Vertex AI project ID ${
|
|
75284
|
-
${blue("VERTEX_LOCATION")} Vertex AI region ${
|
|
76225
|
+
${blue("GEMINI_API_KEY")} Google Gemini ${dim4("(g@, gemini@; alias GOOGLE_API_KEY)")}
|
|
76226
|
+
${blue("OPENAI_API_KEY")} OpenAI ${dim4("(oai@)")}
|
|
76227
|
+
${blue("OPENAI_CODEX_API_KEY")} OpenAI Codex / Responses API ${dim4("(cx@, codex@)")}
|
|
76228
|
+
${blue("XAI_API_KEY")} xAI / Grok ${dim4("(x-ai@, grok@)")}
|
|
76229
|
+
${blue("MINIMAX_API_KEY")} MiniMax ${dim4("(mm@, mmax@)")}
|
|
76230
|
+
${blue("MINIMAX_CODING_API_KEY")} MiniMax Coding Plan ${dim4("(mmc@)")}
|
|
76231
|
+
${blue("MOONSHOT_API_KEY")} Kimi / Moonshot ${dim4("(kimi@, moon@; alias KIMI_API_KEY)")}
|
|
76232
|
+
${blue("KIMI_CODING_API_KEY")} Kimi Coding Plan ${dim4("(kc@)")}
|
|
76233
|
+
${blue("ZHIPU_API_KEY")} GLM / Zhipu ${dim4("(glm@, zhipu@; alias GLM_API_KEY)")}
|
|
76234
|
+
${blue("GLM_CODING_API_KEY")} GLM Coding Plan ${dim4("(gc@; alias ZAI_CODING_API_KEY)")}
|
|
76235
|
+
${blue("ZAI_API_KEY")} Z.AI ${dim4("(z-ai@, zai@)")}
|
|
76236
|
+
${blue("DEEPSEEK_API_KEY")} DeepSeek ${dim4("(ds@)")}
|
|
76237
|
+
${blue("SAKANA_API_KEY")} Sakana Fugu ${dim4("(sakana@, fugu@)")}
|
|
76238
|
+
${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${dim4("(sc@; separate subscription key)")}
|
|
76239
|
+
${blue("OLLAMA_API_KEY")} OllamaCloud ${dim4("(oc@, llama@)")}
|
|
76240
|
+
${blue("OPENCODE_API_KEY")} OpenCode Zen ${dim4("(zen@)")}
|
|
76241
|
+
${blue("POE_API_KEY")} Poe ${dim4("(poe@)")}
|
|
76242
|
+
${blue("LITELLM_API_KEY")} LiteLLM ${dim4("(litellm@, ll@; needs LITELLM_BASE_URL)")}
|
|
76243
|
+
${blue("VERTEX_API_KEY")} Vertex AI Express ${dim4("(v@)")}
|
|
76244
|
+
${blue("VERTEX_PROJECT")} Vertex AI project ID ${dim4("(OAuth mode, v@)")}
|
|
76245
|
+
${blue("VERTEX_LOCATION")} Vertex AI region ${dim4("(default: us-central1)")}
|
|
75285
76246
|
${blue("ANTHROPIC_API_KEY")} Placeholder (prevents Claude Code dialog)
|
|
75286
76247
|
${blue("ANTHROPIC_AUTH_TOKEN")} Placeholder (prevents Claude Code login screen)
|
|
75287
76248
|
|
|
@@ -75289,27 +76250,27 @@ ${h("ENVIRONMENT VARIABLES")}
|
|
|
75289
76250
|
${blue("GEMINI_BASE_URL")} Custom Gemini endpoint
|
|
75290
76251
|
${blue("OPENAI_BASE_URL")} Custom OpenAI / Azure endpoint
|
|
75291
76252
|
${blue("MINIMAX_BASE_URL")} Custom MiniMax endpoint
|
|
75292
|
-
${blue("MOONSHOT_BASE_URL")} Custom Kimi / Moonshot endpoint ${
|
|
75293
|
-
${blue("ZHIPU_BASE_URL")} Custom GLM / Zhipu endpoint ${
|
|
75294
|
-
${blue("SAKANA_BASE_URL")} Custom Sakana endpoint ${
|
|
75295
|
-
${blue("LITELLM_BASE_URL")} LiteLLM gateway base URL ${
|
|
75296
|
-
${blue("OLLAMACLOUD_BASE_URL")} OllamaCloud ${
|
|
75297
|
-
${blue("OPENCODE_BASE_URL")} OpenCode Zen ${
|
|
76253
|
+
${blue("MOONSHOT_BASE_URL")} Custom Kimi / Moonshot endpoint ${dim4("(alias KIMI_BASE_URL)")}
|
|
76254
|
+
${blue("ZHIPU_BASE_URL")} Custom GLM / Zhipu endpoint ${dim4("(alias GLM_BASE_URL)")}
|
|
76255
|
+
${blue("SAKANA_BASE_URL")} Custom Sakana endpoint ${dim4("(default: https://api.sakana.ai)")}
|
|
76256
|
+
${blue("LITELLM_BASE_URL")} LiteLLM gateway base URL ${dim4("(required for ll@)")}
|
|
76257
|
+
${blue("OLLAMACLOUD_BASE_URL")} OllamaCloud ${dim4("(default: https://ollama.com)")}
|
|
76258
|
+
${blue("OPENCODE_BASE_URL")} OpenCode Zen ${dim4("(default: https://opencode.ai/zen)")}
|
|
75298
76259
|
|
|
75299
76260
|
${bold4("Local providers:")}
|
|
75300
|
-
${blue("OLLAMA_BASE_URL")} Ollama server ${
|
|
75301
|
-
${blue("LMSTUDIO_BASE_URL")} LM Studio server ${
|
|
75302
|
-
${blue("VLLM_BASE_URL")} vLLM server ${
|
|
75303
|
-
${blue("MLX_BASE_URL")} MLX server ${
|
|
76261
|
+
${blue("OLLAMA_BASE_URL")} Ollama server ${dim4("(default: http://localhost:11434; alias OLLAMA_HOST)")}
|
|
76262
|
+
${blue("LMSTUDIO_BASE_URL")} LM Studio server ${dim4("(default: http://localhost:1234)")}
|
|
76263
|
+
${blue("VLLM_BASE_URL")} vLLM server ${dim4("(default: http://localhost:8000)")}
|
|
76264
|
+
${blue("MLX_BASE_URL")} MLX server ${dim4("(default: http://127.0.0.1:8080)")}
|
|
75304
76265
|
|
|
75305
76266
|
${bold4("Claudish settings:")}
|
|
75306
|
-
${blue("CLAUDISH_MODEL")} Default model ${
|
|
75307
|
-
${blue("CLAUDISH_DEFAULT_PROVIDER")} Fallback provider for bare names ${
|
|
76267
|
+
${blue("CLAUDISH_MODEL")} Default model ${dim4("(default: openai/gpt-5.3)")}
|
|
76268
|
+
${blue("CLAUDISH_DEFAULT_PROVIDER")} Fallback provider for bare names ${dim4("(see --default-provider)")}
|
|
75308
76269
|
${blue("CLAUDISH_PORT")} Default proxy port
|
|
75309
76270
|
${blue("CLAUDISH_CONTEXT_WINDOW")} Override context window size
|
|
75310
76271
|
${blue("CLAUDISH_DIAG_MODE")} Diagnostic output: auto / logfile / off
|
|
75311
|
-
${blue("CLAUDISH_DEBUG")} Always enable debug logging: 1 / true ${
|
|
75312
|
-
${blue("CLAUDISH_ANTHROPIC_API_BILLING")} Bill native Claude to your API key ${
|
|
76272
|
+
${blue("CLAUDISH_DEBUG")} Always enable debug logging: 1 / true ${dim4("(same as -d)")}
|
|
76273
|
+
${blue("CLAUDISH_ANTHROPIC_API_BILLING")} Bill native Claude to your API key ${dim4("(see --anthropic-api-billing)")}
|
|
75313
76274
|
${blue("CLAUDISH_MCP_TOOLS")} MCP tool gating: all / low-level / agentic / channel
|
|
75314
76275
|
${blue("CLAUDISH_MODEL_OPUS")} Override model for Opus role
|
|
75315
76276
|
${blue("CLAUDISH_MODEL_SONNET")} Override model for Sonnet role
|
|
@@ -75319,39 +76280,39 @@ ${h("ENVIRONMENT VARIABLES")}
|
|
|
75319
76280
|
|
|
75320
76281
|
${bold4("1Password auth:")}
|
|
75321
76282
|
${blue("OP_SERVICE_ACCOUNT_TOKEN")} Service-account token (preferred for headless)
|
|
75322
|
-
${blue("OP_ACCOUNT")} Account URL for DesktopAuth ${
|
|
76283
|
+
${blue("OP_ACCOUNT")} Account URL for DesktopAuth ${dim4("(e.g. my-team.1password.com)")}
|
|
75323
76284
|
|
|
75324
76285
|
${h("EXAMPLES")}
|
|
75325
|
-
${
|
|
76286
|
+
${dim4("# Interactive (default) - model selector")}
|
|
75326
76287
|
${green2("claudish")}
|
|
75327
|
-
${green2("claudish")} --free ${
|
|
76288
|
+
${green2("claudish")} --free ${dim4("# only FREE models")}
|
|
75328
76289
|
|
|
75329
|
-
${
|
|
76290
|
+
${dim4("# Explicit provider routing")}
|
|
75330
76291
|
${green2("claudish")} --model ${magenta("google@gemini-3-pro")} ${yellow2('"implement auth"')}
|
|
75331
76292
|
${green2("claudish")} --model ${magenta("oai@gpt-5.3")} ${yellow2('"add tests for login"')}
|
|
75332
76293
|
${green2("claudish")} --model ${magenta("openrouter@deepseek/deepseek-r1")} ${yellow2('"unknown vendor"')}
|
|
75333
76294
|
|
|
75334
|
-
${
|
|
76295
|
+
${dim4("# Native auto-detection (provider inferred from model name)")}
|
|
75335
76296
|
${green2("claudish")} --model ${yellow2("gpt-4o")} ${yellow2('"routes to OpenAI"')}
|
|
75336
76297
|
${green2("claudish")} --model ${yellow2("gemini-2.5-pro")} ${yellow2('"routes to Google"')}
|
|
75337
76298
|
|
|
75338
|
-
${
|
|
76299
|
+
${dim4("# Per-role model mapping")}
|
|
75339
76300
|
${green2("claudish")} --model-opus ${magenta("oai@gpt-5.3")} --model-sonnet ${magenta("google@gemini-3-pro")}
|
|
75340
76301
|
|
|
75341
|
-
${
|
|
75342
|
-
${
|
|
76302
|
+
${dim4("# stdin for large prompts (diffs, code review)")}
|
|
76303
|
+
${dim4("git diff |")} ${green2("claudish")} --stdin --model ${magenta("oai@gpt-5.3")} ${yellow2('"Review these changes"')}
|
|
75343
76304
|
|
|
75344
|
-
${
|
|
76305
|
+
${dim4("# Local models with concurrency control")}
|
|
75345
76306
|
${green2("claudish")} --model ${magenta("ollama@llama3.2:3")} ${yellow2('"3 concurrent requests"')}
|
|
75346
76307
|
${green2("claudish")} --model ${magenta("lms@qwen2.5-coder")} ${yellow2('"LM Studio shortcut"')}
|
|
75347
76308
|
${green2("claudish")} --model ${yellow2('"http://localhost:8000/mistral"')} ${yellow2('"any OpenAI-compatible URL"')}
|
|
75348
76309
|
|
|
75349
|
-
${
|
|
76310
|
+
${dim4("# Autonomous (no prompts, no sandbox) \u2014 use with caution")}
|
|
75350
76311
|
${green2("claudish")} -y --dangerous ${yellow2('"refactor entire codebase"')}
|
|
75351
76312
|
|
|
75352
76313
|
${h("MORE INFO")}
|
|
75353
|
-
${
|
|
75354
|
-
${
|
|
76314
|
+
${dim4("GitHub:")} ${blue("https://github.com/MadAppGang/claude-code")}
|
|
76315
|
+
${dim4("OpenRouter:")} ${blue("https://openrouter.ai")}
|
|
75355
76316
|
`);
|
|
75356
76317
|
}
|
|
75357
76318
|
function printAIAgentGuide() {
|
|
@@ -76714,6 +77675,8 @@ function Footer({ activeTab, mode, probeMode, providerCaps }) {
|
|
|
76714
77675
|
[C.blue, "\u2191\u2193", "navigate"],
|
|
76715
77676
|
[C.green, "a", "add"],
|
|
76716
77677
|
[C.cyan, "t", "test"],
|
|
77678
|
+
[C.magenta, "c", "\u2192keychain"],
|
|
77679
|
+
[C.magenta, "C", "all\u2192keychain"],
|
|
76717
77680
|
[C.green, "o", "account"],
|
|
76718
77681
|
[C.red, "x", "remove"],
|
|
76719
77682
|
[C.blue, "Tab", "section"],
|
|
@@ -78869,12 +79832,29 @@ var init_ProfilesContent = __esm(() => {
|
|
|
78869
79832
|
|
|
78870
79833
|
// src/tui/components/ProviderDetail.tsx
|
|
78871
79834
|
import { jsx as jsx11, jsxs as jsxs10, Fragment as Fragment7 } from "@opentui/react/jsx-runtime";
|
|
78872
|
-
function
|
|
79835
|
+
function wrapToLines(text, maxWidth, maxLines) {
|
|
78873
79836
|
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
78874
79837
|
const limit = Math.max(20, maxWidth);
|
|
78875
79838
|
if (collapsed.length <= limit)
|
|
78876
|
-
return collapsed;
|
|
78877
|
-
|
|
79839
|
+
return [collapsed];
|
|
79840
|
+
const lines = [];
|
|
79841
|
+
let rest = collapsed;
|
|
79842
|
+
while (rest.length > 0 && lines.length < maxLines) {
|
|
79843
|
+
if (rest.length <= limit) {
|
|
79844
|
+
lines.push(rest);
|
|
79845
|
+
break;
|
|
79846
|
+
}
|
|
79847
|
+
const slice = rest.slice(0, limit);
|
|
79848
|
+
const cut = slice.lastIndexOf(" ");
|
|
79849
|
+
const at = cut > limit * 0.5 ? cut : limit;
|
|
79850
|
+
lines.push(rest.slice(0, at));
|
|
79851
|
+
rest = rest.slice(at).trimStart();
|
|
79852
|
+
}
|
|
79853
|
+
if (rest.length > 0 && lines.length === maxLines) {
|
|
79854
|
+
const last = lines[maxLines - 1] ?? "";
|
|
79855
|
+
lines[maxLines - 1] = `${last.slice(0, Math.max(1, limit - 1))}\u2026`;
|
|
79856
|
+
}
|
|
79857
|
+
return lines;
|
|
78878
79858
|
}
|
|
78879
79859
|
function resolveProviderDetailKeyDisplay(input) {
|
|
78880
79860
|
if (input.isLocal)
|
|
@@ -78885,8 +79865,6 @@ function resolveProviderDetailKeyDisplay(input) {
|
|
|
78885
79865
|
return input.envKeyMask;
|
|
78886
79866
|
if (input.hasCfgKey)
|
|
78887
79867
|
return input.cfgKeyMask;
|
|
78888
|
-
if (input.isPublicKey)
|
|
78889
|
-
return "free";
|
|
78890
79868
|
return "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
|
|
78891
79869
|
}
|
|
78892
79870
|
function ProviderDetail({
|
|
@@ -78900,7 +79878,9 @@ function ProviderDetail({
|
|
|
78900
79878
|
hasKey,
|
|
78901
79879
|
authSource,
|
|
78902
79880
|
isOpKey,
|
|
78903
|
-
|
|
79881
|
+
isKcKey,
|
|
79882
|
+
hasKcKey,
|
|
79883
|
+
keySaveTarget,
|
|
78904
79884
|
cfgKeyMask,
|
|
78905
79885
|
envKeyMask,
|
|
78906
79886
|
activeEndpoint,
|
|
@@ -78914,7 +79894,6 @@ function ProviderDetail({
|
|
|
78914
79894
|
authSource,
|
|
78915
79895
|
hasEnvKey,
|
|
78916
79896
|
hasCfgKey,
|
|
78917
|
-
isPublicKey,
|
|
78918
79897
|
envKeyMask,
|
|
78919
79898
|
cfgKeyMask
|
|
78920
79899
|
});
|
|
@@ -78924,7 +79903,7 @@ function ProviderDetail({
|
|
|
78924
79903
|
border: true,
|
|
78925
79904
|
borderStyle: "single",
|
|
78926
79905
|
borderColor: C.focusBorder,
|
|
78927
|
-
title:
|
|
79906
|
+
title: mode === "input_key" ? ` Set API Key \u2014 ${selectedProvider.displayName} \u2192 ${keySaveTarget} ` : ` Set Endpoint \u2014 ${selectedProvider.displayName} `,
|
|
78928
79907
|
backgroundColor: C.bg,
|
|
78929
79908
|
flexDirection: "column",
|
|
78930
79909
|
paddingX: 1,
|
|
@@ -78985,6 +79964,7 @@ function ProviderDetail({
|
|
|
78985
79964
|
});
|
|
78986
79965
|
}
|
|
78987
79966
|
const tr = testResults[selectedProvider.name];
|
|
79967
|
+
const failureText = tr && (tr.status === "failed" || tr.status === "unavailable") ? tr.providerMessage ?? tr.error : undefined;
|
|
78988
79968
|
return /* @__PURE__ */ jsxs10("box", {
|
|
78989
79969
|
height: DETAIL_H,
|
|
78990
79970
|
border: true,
|
|
@@ -79058,7 +80038,7 @@ function ProviderDetail({
|
|
|
79058
80038
|
})
|
|
79059
80039
|
]
|
|
79060
80040
|
}),
|
|
79061
|
-
hasKey && !selectedProvider.isLocal &&
|
|
80041
|
+
hasKey && !selectedProvider.isLocal && isOAuth && /* @__PURE__ */ jsxs10(Fragment7, {
|
|
79062
80042
|
children: [
|
|
79063
80043
|
/* @__PURE__ */ jsx11("span", {
|
|
79064
80044
|
fg: C.dim,
|
|
@@ -79070,9 +80050,13 @@ function ProviderDetail({
|
|
|
79070
80050
|
children: "From: "
|
|
79071
80051
|
}),
|
|
79072
80052
|
/* @__PURE__ */ jsx11("span", {
|
|
79073
|
-
fg: C.
|
|
80053
|
+
fg: C.cyan,
|
|
79074
80054
|
attributes: A.bold,
|
|
79075
|
-
children: "
|
|
80055
|
+
children: "oauth"
|
|
80056
|
+
}),
|
|
80057
|
+
/* @__PURE__ */ jsx11("span", {
|
|
80058
|
+
fg: C.fgMuted,
|
|
80059
|
+
children: " (used)"
|
|
79076
80060
|
})
|
|
79077
80061
|
]
|
|
79078
80062
|
}),
|
|
@@ -79094,7 +80078,7 @@ function ProviderDetail({
|
|
|
79094
80078
|
})
|
|
79095
80079
|
]
|
|
79096
80080
|
}),
|
|
79097
|
-
hasKey && !selectedProvider.isLocal && !
|
|
80081
|
+
hasKey && !selectedProvider.isLocal && !isOAuth && /* @__PURE__ */ jsxs10(Fragment7, {
|
|
79098
80082
|
children: [
|
|
79099
80083
|
/* @__PURE__ */ jsx11("span", {
|
|
79100
80084
|
fg: C.dim,
|
|
@@ -79108,7 +80092,7 @@ function ProviderDetail({
|
|
|
79108
80092
|
hasEnvKey && /* @__PURE__ */ jsx11("span", {
|
|
79109
80093
|
fg: C.green,
|
|
79110
80094
|
attributes: A.bold,
|
|
79111
|
-
children: isOpKey ? "1Password" : "env"
|
|
80095
|
+
children: isKcKey ? "keychain" : isOpKey ? "1Password" : "env"
|
|
79112
80096
|
}),
|
|
79113
80097
|
hasEnvKey && hasCfgKey && /* @__PURE__ */ jsx11("span", {
|
|
79114
80098
|
fg: C.fgMuted,
|
|
@@ -79126,6 +80110,18 @@ function ProviderDetail({
|
|
|
79126
80110
|
hasCfgKey && /* @__PURE__ */ jsx11("span", {
|
|
79127
80111
|
fg: C.fgMuted,
|
|
79128
80112
|
children: hasEnvKey ? " (shadowed)" : " (used)"
|
|
80113
|
+
}),
|
|
80114
|
+
hasKcKey && !isKcKey && /* @__PURE__ */ jsxs10(Fragment7, {
|
|
80115
|
+
children: [
|
|
80116
|
+
/* @__PURE__ */ jsx11("span", {
|
|
80117
|
+
fg: C.fgMuted,
|
|
80118
|
+
children: " + "
|
|
80119
|
+
}),
|
|
80120
|
+
/* @__PURE__ */ jsx11("span", {
|
|
80121
|
+
fg: C.fgMuted,
|
|
80122
|
+
children: "keychain (shadowed)"
|
|
80123
|
+
})
|
|
80124
|
+
]
|
|
79129
80125
|
})
|
|
79130
80126
|
]
|
|
79131
80127
|
})
|
|
@@ -79147,7 +80143,7 @@ function ProviderDetail({
|
|
|
79147
80143
|
})
|
|
79148
80144
|
]
|
|
79149
80145
|
}),
|
|
79150
|
-
/* @__PURE__ */ jsxs10("text", {
|
|
80146
|
+
!failureText && /* @__PURE__ */ jsxs10("text", {
|
|
79151
80147
|
children: [
|
|
79152
80148
|
/* @__PURE__ */ jsxs10("span", {
|
|
79153
80149
|
fg: C.blue,
|
|
@@ -79163,7 +80159,7 @@ function ProviderDetail({
|
|
|
79163
80159
|
})
|
|
79164
80160
|
]
|
|
79165
80161
|
}),
|
|
79166
|
-
selectedProvider.keyUrl && /* @__PURE__ */ jsxs10("text", {
|
|
80162
|
+
selectedProvider.keyUrl && !failureText && /* @__PURE__ */ jsxs10("text", {
|
|
79167
80163
|
children: [
|
|
79168
80164
|
/* @__PURE__ */ jsxs10("span", {
|
|
79169
80165
|
fg: C.blue,
|
|
@@ -79208,34 +80204,24 @@ function ProviderDetail({
|
|
|
79208
80204
|
})
|
|
79209
80205
|
]
|
|
79210
80206
|
}),
|
|
79211
|
-
tr.status === "failed" && /* @__PURE__ */
|
|
79212
|
-
|
|
79213
|
-
|
|
79214
|
-
|
|
79215
|
-
attributes: A.bold,
|
|
79216
|
-
children: "\u2717 failed"
|
|
79217
|
-
}),
|
|
79218
|
-
tr.error && /* @__PURE__ */ jsx11("span", {
|
|
79219
|
-
fg: C.red,
|
|
79220
|
-
children: ` ${truncateOneLine(tr.error, width - 16)}`
|
|
79221
|
-
})
|
|
79222
|
-
]
|
|
80207
|
+
tr.status === "failed" && /* @__PURE__ */ jsx11("span", {
|
|
80208
|
+
fg: C.red,
|
|
80209
|
+
attributes: A.bold,
|
|
80210
|
+
children: "\u2717 failed"
|
|
79223
80211
|
}),
|
|
79224
|
-
tr.status === "unavailable" && /* @__PURE__ */
|
|
79225
|
-
|
|
79226
|
-
|
|
79227
|
-
|
|
79228
|
-
attributes: A.bold,
|
|
79229
|
-
children: "\u25CB unavailable"
|
|
79230
|
-
}),
|
|
79231
|
-
tr.error && /* @__PURE__ */ jsx11("span", {
|
|
79232
|
-
fg: C.yellow,
|
|
79233
|
-
children: ` ${truncateOneLine(tr.error, width - 16)}`
|
|
79234
|
-
})
|
|
79235
|
-
]
|
|
80212
|
+
tr.status === "unavailable" && /* @__PURE__ */ jsx11("span", {
|
|
80213
|
+
fg: C.yellow,
|
|
80214
|
+
attributes: A.bold,
|
|
80215
|
+
children: "\u25CB unavailable"
|
|
79236
80216
|
})
|
|
79237
80217
|
]
|
|
79238
|
-
})
|
|
80218
|
+
}),
|
|
80219
|
+
failureText && wrapToLines(failureText, width - 4, 2).map((line, i) => /* @__PURE__ */ jsx11("text", {
|
|
80220
|
+
children: /* @__PURE__ */ jsx11("span", {
|
|
80221
|
+
fg: tr?.status === "unavailable" ? C.yellow : C.red,
|
|
80222
|
+
children: line
|
|
80223
|
+
})
|
|
80224
|
+
}, i))
|
|
79239
80225
|
]
|
|
79240
80226
|
});
|
|
79241
80227
|
}
|
|
@@ -79302,8 +80288,6 @@ function ProvidersContent({
|
|
|
79302
80288
|
keyDisplay = "local";
|
|
79303
80289
|
} else if (isOauthOnly) {
|
|
79304
80290
|
keyDisplay = "oauth\xB7\xB7\xB7";
|
|
79305
|
-
} else if (auth === "public") {
|
|
79306
|
-
keyDisplay = "free";
|
|
79307
80291
|
} else if (auth === "cfg") {
|
|
79308
80292
|
keyDisplay = maskKey2(config3.apiKeys?.[p.apiKeyEnvVar]);
|
|
79309
80293
|
} else if (auth === "env" || auth === "e+c") {
|
|
@@ -80734,18 +81718,18 @@ function useProfileWizard(args) {
|
|
|
80734
81718
|
setEditProfileValue("");
|
|
80735
81719
|
return;
|
|
80736
81720
|
}
|
|
80737
|
-
const
|
|
81721
|
+
const now2 = new Date().toISOString();
|
|
80738
81722
|
if (profileScope === "project") {
|
|
80739
81723
|
const localCfg = loadLocalConfig() ?? {
|
|
80740
81724
|
version: "1.0.0",
|
|
80741
81725
|
defaultProfile: "",
|
|
80742
81726
|
profiles: {}
|
|
80743
81727
|
};
|
|
80744
|
-
localCfg.profiles[name] = { name, models: {}, createdAt:
|
|
81728
|
+
localCfg.profiles[name] = { name, models: {}, createdAt: now2, updatedAt: now2 };
|
|
80745
81729
|
saveLocalConfig(localCfg);
|
|
80746
81730
|
} else {
|
|
80747
81731
|
const cfg = loadConfig();
|
|
80748
|
-
cfg.profiles[name] = { name, models: {}, createdAt:
|
|
81732
|
+
cfg.profiles[name] = { name, models: {}, createdAt: now2, updatedAt: now2 };
|
|
80749
81733
|
saveConfig(cfg);
|
|
80750
81734
|
}
|
|
80751
81735
|
refreshConfig();
|
|
@@ -81100,20 +82084,20 @@ function useRouteProbe(config3) {
|
|
|
81100
82084
|
errorMessage: String(e instanceof Error ? e.message : e)
|
|
81101
82085
|
}));
|
|
81102
82086
|
const ms = Date.now() - startMs;
|
|
81103
|
-
const
|
|
82087
|
+
const ok2 = result.state === "live";
|
|
81104
82088
|
setProbeResults((prev) => prev.map((e, idx) => {
|
|
81105
82089
|
if (idx === i)
|
|
81106
82090
|
return {
|
|
81107
82091
|
...e,
|
|
81108
|
-
status:
|
|
81109
|
-
error:
|
|
82092
|
+
status: ok2 ? "success" : "failed",
|
|
82093
|
+
error: ok2 ? undefined : describeProbeState(result),
|
|
81110
82094
|
ms
|
|
81111
82095
|
};
|
|
81112
|
-
if (idx > i &&
|
|
82096
|
+
if (idx > i && ok2 && e.status !== "no_key")
|
|
81113
82097
|
return { ...e, status: "skipped" };
|
|
81114
82098
|
return e;
|
|
81115
82099
|
}));
|
|
81116
|
-
if (
|
|
82100
|
+
if (ok2)
|
|
81117
82101
|
break;
|
|
81118
82102
|
}
|
|
81119
82103
|
setProbeMode("done");
|
|
@@ -81153,6 +82137,50 @@ var init_useRouteProbe = __esm(() => {
|
|
|
81153
82137
|
import { useKeyboard as useKeyboard2, useRenderer, useTerminalDimensions as useTerminalDimensions2 } from "@opentui/react";
|
|
81154
82138
|
import { useCallback as useCallback3, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState5 } from "react";
|
|
81155
82139
|
import { jsx as jsx16, jsxs as jsxs15, Fragment as Fragment10 } from "@opentui/react/jsx-runtime";
|
|
82140
|
+
async function resolveOpEntrySecrets(entries, auth) {
|
|
82141
|
+
const secrets = {};
|
|
82142
|
+
for (const entry of entries) {
|
|
82143
|
+
if (entry.kind === "environment") {
|
|
82144
|
+
Object.assign(secrets, await withSdkRetry(() => readEnvironment(entry.value, { auth }), "tui:copy-keychain"));
|
|
82145
|
+
} else if (entry.kind === "glob" || isGlobImport(entry.value)) {
|
|
82146
|
+
Object.assign(secrets, await withSdkRetry(() => resolveGlobImport(entry.value, { auth }), "tui:copy-keychain"));
|
|
82147
|
+
} else {
|
|
82148
|
+
const r = await withSdkRetry(() => resolveSecrets({ T: entry.value }, { auth }), "tui:copy-keychain");
|
|
82149
|
+
const name = envNameFromOpRef(entry.value);
|
|
82150
|
+
if (name && r.T)
|
|
82151
|
+
secrets[name] = r.T;
|
|
82152
|
+
}
|
|
82153
|
+
}
|
|
82154
|
+
return secrets;
|
|
82155
|
+
}
|
|
82156
|
+
function writeSecretsToKeychain(secrets, alreadyStored) {
|
|
82157
|
+
const outcome = { created: 0, replaced: 0, skipped: [] };
|
|
82158
|
+
for (const [name, value] of Object.entries(secrets)) {
|
|
82159
|
+
if (!value)
|
|
82160
|
+
continue;
|
|
82161
|
+
try {
|
|
82162
|
+
writeKeychainSecret(name, value);
|
|
82163
|
+
if (alreadyStored.has(name))
|
|
82164
|
+
outcome.replaced++;
|
|
82165
|
+
else
|
|
82166
|
+
outcome.created++;
|
|
82167
|
+
} catch {
|
|
82168
|
+
outcome.skipped.push(name);
|
|
82169
|
+
}
|
|
82170
|
+
}
|
|
82171
|
+
return outcome;
|
|
82172
|
+
}
|
|
82173
|
+
function describeCopyOutcome({ created, replaced, skipped }) {
|
|
82174
|
+
if (created + replaced === 0) {
|
|
82175
|
+
return `Nothing copied to the Keychain${skipped.length > 0 ? ` \u2014 ${skipped.length} could not be stored` : ""}.`;
|
|
82176
|
+
}
|
|
82177
|
+
const parts = [`${created} new`];
|
|
82178
|
+
if (replaced > 0)
|
|
82179
|
+
parts.push(`${replaced} replaced`);
|
|
82180
|
+
if (skipped.length > 0)
|
|
82181
|
+
parts.push(`${skipped.length} skipped (${skipped.join(", ")})`);
|
|
82182
|
+
return `Copied to macOS Keychain: ${parts.join(" \xB7 ")}.`;
|
|
82183
|
+
}
|
|
81156
82184
|
function App({ requestLogin } = {}) {
|
|
81157
82185
|
const renderer = useRenderer();
|
|
81158
82186
|
const { width, height: height2 } = useTerminalDimensions2();
|
|
@@ -81162,6 +82190,9 @@ function App({ requestLogin } = {}) {
|
|
|
81162
82190
|
const [activeTab, setActiveTab] = useState5("providers");
|
|
81163
82191
|
const [mode, setMode] = useState5("browse");
|
|
81164
82192
|
const [inputValue, setInputValue] = useState5("");
|
|
82193
|
+
const [keychainVars, setKeychainVars] = useState5(new Set);
|
|
82194
|
+
const keychainSupported = useMemo2(() => isKeychainSupported(), []);
|
|
82195
|
+
const inputTargetRef = useRef4(null);
|
|
81165
82196
|
const [routingPattern, setRoutingPattern] = useState5("");
|
|
81166
82197
|
const [chainSelected, setChainSelected] = useState5(new Set);
|
|
81167
82198
|
const [chainOrder, setChainOrder] = useState5([]);
|
|
@@ -81249,6 +82280,36 @@ function App({ requestLogin } = {}) {
|
|
|
81249
82280
|
setBufStats(getBufferStats());
|
|
81250
82281
|
setOpTick((t) => t + 1);
|
|
81251
82282
|
}, []);
|
|
82283
|
+
const refreshKeychainVars = useCallback3(() => {
|
|
82284
|
+
if (!hasKeychainSource()) {
|
|
82285
|
+
setKeychainVars(new Set);
|
|
82286
|
+
return;
|
|
82287
|
+
}
|
|
82288
|
+
try {
|
|
82289
|
+
setKeychainVars(new Set(listKeychainVars()));
|
|
82290
|
+
} catch {
|
|
82291
|
+
setKeychainVars(new Set);
|
|
82292
|
+
}
|
|
82293
|
+
}, []);
|
|
82294
|
+
useEffect4(() => {
|
|
82295
|
+
if (!keychainSupported)
|
|
82296
|
+
return;
|
|
82297
|
+
let cancelled = false;
|
|
82298
|
+
(async () => {
|
|
82299
|
+
let hydrated = 0;
|
|
82300
|
+
try {
|
|
82301
|
+
hydrated = await hydrateKeychainIntoEnv();
|
|
82302
|
+
} catch {}
|
|
82303
|
+
if (cancelled)
|
|
82304
|
+
return;
|
|
82305
|
+
refreshKeychainVars();
|
|
82306
|
+
if (hydrated > 0)
|
|
82307
|
+
refreshConfig();
|
|
82308
|
+
})();
|
|
82309
|
+
return () => {
|
|
82310
|
+
cancelled = true;
|
|
82311
|
+
};
|
|
82312
|
+
}, [keychainSupported, refreshKeychainVars, refreshConfig]);
|
|
81252
82313
|
const clearTestResult = useCallback3((provName) => {
|
|
81253
82314
|
setTestResults((prev) => {
|
|
81254
82315
|
if (!(provName in prev))
|
|
@@ -81264,11 +82325,12 @@ function App({ requestLogin } = {}) {
|
|
|
81264
82325
|
const { editProfileValue, profileScope, suggestions, suggestionIndex, providerPickerIndex } = wizard;
|
|
81265
82326
|
const hasCfgKey = !!config3.apiKeys?.[selectedProvider.apiKeyEnvVar];
|
|
81266
82327
|
const hasEnvKey = !!process.env[selectedProvider.apiKeyEnvVar];
|
|
82328
|
+
const providerKeychainVars = useMemo2(() => [selectedProvider.apiKeyEnvVar, ...selectedProvider.aliases ?? []].filter((n) => !!n && keychainVars.has(n)), [selectedProvider, keychainVars]);
|
|
82329
|
+
const hasKcKey = providerKeychainVars.length > 0;
|
|
81267
82330
|
const selectedAuthSource = providerAuthSource(selectedProvider, config3);
|
|
81268
|
-
const
|
|
81269
|
-
const hasKey = selectedAuthSource !== null || selectedLocalRunning;
|
|
81270
|
-
const selectedPublicKey = selectedAuthSource === "public";
|
|
82331
|
+
const hasKey = providerIsReadyForDisplay(selectedProvider, config3, localLiveness);
|
|
81271
82332
|
const isOpKey = hasEnvKey && isOpHydratedVar(selectedProvider.apiKeyEnvVar);
|
|
82333
|
+
const isKcKey = hasEnvKey && isKeychainHydratedVar(selectedProvider.apiKeyEnvVar);
|
|
81272
82334
|
const cfgKeyMask = maskKey2(config3.apiKeys?.[selectedProvider.apiKeyEnvVar]);
|
|
81273
82335
|
const envKeyMask = maskKey2(process.env[selectedProvider.apiKeyEnvVar]);
|
|
81274
82336
|
const activeEndpointEnvVar = selectedProvider.endpointEnvVar;
|
|
@@ -81445,6 +82507,36 @@ function App({ requestLogin } = {}) {
|
|
|
81445
82507
|
setOpBusy(false);
|
|
81446
82508
|
}
|
|
81447
82509
|
}, [acquireOpAuth]);
|
|
82510
|
+
const copyOpToKeychain = useCallback3(async (entries, label) => {
|
|
82511
|
+
if (!keychainSupported) {
|
|
82512
|
+
setStatusMsg("macOS Keychain is only available on macOS.");
|
|
82513
|
+
return;
|
|
82514
|
+
}
|
|
82515
|
+
const copyable = entries.filter((e) => e.kind !== "account");
|
|
82516
|
+
if (copyable.length === 0) {
|
|
82517
|
+
setStatusMsg("Nothing to copy \u2014 the account entry holds no secret.");
|
|
82518
|
+
return;
|
|
82519
|
+
}
|
|
82520
|
+
setOpBusy(true);
|
|
82521
|
+
setStatusMsg(`Resolving ${label} from 1Password\u2026`);
|
|
82522
|
+
try {
|
|
82523
|
+
const auth = await acquireOpAuth();
|
|
82524
|
+
const secrets = await resolveOpEntrySecrets(copyable, auth);
|
|
82525
|
+
const outcome = writeSecretsToKeychain(secrets, new Set(keychainVars));
|
|
82526
|
+
if (outcome.created + outcome.replaced > 0) {
|
|
82527
|
+
setKeychainEnabled(true);
|
|
82528
|
+
refreshKeychainVars();
|
|
82529
|
+
credentials.invalidate();
|
|
82530
|
+
invalidateProbeProxyHandlers();
|
|
82531
|
+
refreshConfig();
|
|
82532
|
+
}
|
|
82533
|
+
setStatusMsg(describeCopyOutcome(outcome));
|
|
82534
|
+
} catch (err) {
|
|
82535
|
+
setStatusMsg(err instanceof Error ? err.message : String(err));
|
|
82536
|
+
} finally {
|
|
82537
|
+
setOpBusy(false);
|
|
82538
|
+
}
|
|
82539
|
+
}, [acquireOpAuth, keychainSupported, keychainVars, refreshKeychainVars, refreshConfig]);
|
|
81448
82540
|
const resetOpWizard = useCallback3(() => {
|
|
81449
82541
|
setInputValue("");
|
|
81450
82542
|
setOpPendingValue("");
|
|
@@ -81715,7 +82807,7 @@ function App({ requestLogin } = {}) {
|
|
|
81715
82807
|
const error46 = tried.size > 1 ? `${baseError} (tried ${tried.size} models)` : baseError;
|
|
81716
82808
|
setTestResults((prev) => ({
|
|
81717
82809
|
...prev,
|
|
81718
|
-
[provName]: { status: "failed", error: error46, ms }
|
|
82810
|
+
[provName]: { status: "failed", error: error46, providerMessage: result.errorMessage, ms }
|
|
81719
82811
|
}));
|
|
81720
82812
|
}
|
|
81721
82813
|
} catch (err) {
|
|
@@ -81767,26 +82859,49 @@ function App({ requestLogin } = {}) {
|
|
|
81767
82859
|
setMode("browse");
|
|
81768
82860
|
return;
|
|
81769
82861
|
}
|
|
82862
|
+
const target = inputTargetRef.current ?? selectedProvider;
|
|
81770
82863
|
if (mode === "input_key") {
|
|
81771
|
-
if (!
|
|
81772
|
-
setStatusMsg(`${
|
|
82864
|
+
if (!target.apiKeyEnvVar) {
|
|
82865
|
+
setStatusMsg(`${target.displayName} has no apiKeyEnvVar \u2014 cannot save key.`);
|
|
81773
82866
|
} else {
|
|
81774
|
-
|
|
81775
|
-
|
|
81776
|
-
|
|
82867
|
+
const envVar = target.apiKeyEnvVar;
|
|
82868
|
+
let saved = false;
|
|
82869
|
+
if (keychainSupported) {
|
|
82870
|
+
try {
|
|
82871
|
+
writeKeychainSecret(envVar, val);
|
|
82872
|
+
setKeychainEnabled(true);
|
|
82873
|
+
process.env[envVar] = val;
|
|
82874
|
+
recordKeychainHydratedVar(envVar);
|
|
82875
|
+
refreshKeychainVars();
|
|
82876
|
+
setStatusMsg(`Key saved to macOS Keychain for ${target.displayName} (${envVar}).`);
|
|
82877
|
+
saved = true;
|
|
82878
|
+
} catch (err) {
|
|
82879
|
+
setStatusMsg(`Keychain write failed (${err instanceof Error ? err.message : String(err)}) \u2014 saved to config.json instead.`);
|
|
82880
|
+
}
|
|
82881
|
+
}
|
|
82882
|
+
if (!saved) {
|
|
82883
|
+
setApiKey(envVar, val);
|
|
82884
|
+
process.env[envVar] = val;
|
|
82885
|
+
if (!keychainSupported) {
|
|
82886
|
+
setStatusMsg(`Key saved for ${target.displayName} (${envVar}).`);
|
|
82887
|
+
}
|
|
82888
|
+
}
|
|
82889
|
+
credentials.invalidate(target.catalogName);
|
|
82890
|
+
invalidateProbeProxyHandlers(target.catalogName);
|
|
82891
|
+
clearTestResult(target.name);
|
|
81777
82892
|
}
|
|
81778
82893
|
} else {
|
|
81779
|
-
if (!
|
|
81780
|
-
setStatusMsg(`${
|
|
82894
|
+
if (!target.endpointEnvVar) {
|
|
82895
|
+
setStatusMsg(`${target.displayName} has no endpointEnvVar \u2014 cannot save URL.`);
|
|
81781
82896
|
} else {
|
|
81782
|
-
setEndpoint(
|
|
81783
|
-
process.env[
|
|
81784
|
-
setStatusMsg(`URL saved for ${
|
|
82897
|
+
setEndpoint(target.endpointEnvVar, val);
|
|
82898
|
+
process.env[target.endpointEnvVar] = val;
|
|
82899
|
+
setStatusMsg(`URL saved for ${target.displayName} (${target.endpointEnvVar}=${val}).`);
|
|
81785
82900
|
}
|
|
81786
82901
|
}
|
|
81787
|
-
invalidateProbeProxyHandlers(
|
|
81788
|
-
invalidateProbeDiscovery(
|
|
81789
|
-
clearTestResult(
|
|
82902
|
+
invalidateProbeProxyHandlers(target.catalogName);
|
|
82903
|
+
invalidateProbeDiscovery(target.catalogName);
|
|
82904
|
+
clearTestResult(target.name);
|
|
81790
82905
|
refreshConfig();
|
|
81791
82906
|
setInputValue("");
|
|
81792
82907
|
setMode("browse");
|
|
@@ -82255,10 +83370,12 @@ function App({ requestLogin } = {}) {
|
|
|
82255
83370
|
setStatusMsg(null);
|
|
82256
83371
|
} else if (key.name === "s") {
|
|
82257
83372
|
if (selectedProvider.apiKeyEnvVar) {
|
|
83373
|
+
inputTargetRef.current = selectedProvider;
|
|
82258
83374
|
setInputValue("");
|
|
82259
83375
|
setStatusMsg(null);
|
|
82260
83376
|
setMode("input_key");
|
|
82261
83377
|
} else if (selectedProvider.endpointEnvVar) {
|
|
83378
|
+
inputTargetRef.current = selectedProvider;
|
|
82262
83379
|
setInputValue(activeEndpoint);
|
|
82263
83380
|
setStatusMsg(null);
|
|
82264
83381
|
setMode("input_endpoint");
|
|
@@ -82276,6 +83393,7 @@ function App({ requestLogin } = {}) {
|
|
|
82276
83393
|
}
|
|
82277
83394
|
refreshConfig();
|
|
82278
83395
|
} else if (selectedProvider.endpointEnvVar) {
|
|
83396
|
+
inputTargetRef.current = selectedProvider;
|
|
82279
83397
|
setInputValue(activeEndpoint);
|
|
82280
83398
|
setStatusMsg(null);
|
|
82281
83399
|
setMode("input_endpoint");
|
|
@@ -82284,6 +83402,7 @@ function App({ requestLogin } = {}) {
|
|
|
82284
83402
|
}
|
|
82285
83403
|
} else if (key.name === "u") {
|
|
82286
83404
|
if (selectedProvider.endpointEnvVar) {
|
|
83405
|
+
inputTargetRef.current = selectedProvider;
|
|
82287
83406
|
setInputValue(activeEndpoint);
|
|
82288
83407
|
setStatusMsg(null);
|
|
82289
83408
|
setMode("input_endpoint");
|
|
@@ -82292,24 +83411,43 @@ function App({ requestLogin } = {}) {
|
|
|
82292
83411
|
}
|
|
82293
83412
|
} else if (key.name === "x") {
|
|
82294
83413
|
let changed = false;
|
|
83414
|
+
const removedFrom = [];
|
|
83415
|
+
let failureMsg = null;
|
|
82295
83416
|
if (hasCfgKey) {
|
|
82296
83417
|
removeApiKey(selectedProvider.apiKeyEnvVar);
|
|
83418
|
+
removedFrom.push("config.json");
|
|
82297
83419
|
changed = true;
|
|
82298
83420
|
}
|
|
83421
|
+
if (keychainSupported) {
|
|
83422
|
+
for (const name of providerKeychainVars) {
|
|
83423
|
+
try {
|
|
83424
|
+
if (deleteKeychainSecret(name)) {
|
|
83425
|
+
removedFrom.push(`macOS Keychain (${name})`);
|
|
83426
|
+
changed = true;
|
|
83427
|
+
}
|
|
83428
|
+
} catch (err) {
|
|
83429
|
+
failureMsg = `Keychain delete failed for ${name}: ${err instanceof Error ? err.message : String(err)}`;
|
|
83430
|
+
}
|
|
83431
|
+
}
|
|
83432
|
+
if (providerKeychainVars.length > 0)
|
|
83433
|
+
refreshKeychainVars();
|
|
83434
|
+
}
|
|
83435
|
+
if (changed && (isKcKey || isOpKey)) {
|
|
83436
|
+
delete process.env[selectedProvider.apiKeyEnvVar];
|
|
83437
|
+
}
|
|
82299
83438
|
if (activeEndpointEnvVar && config3.endpoints?.[activeEndpointEnvVar]) {
|
|
82300
83439
|
removeEndpoint(activeEndpointEnvVar);
|
|
82301
83440
|
delete process.env[activeEndpointEnvVar];
|
|
82302
83441
|
changed = true;
|
|
82303
83442
|
}
|
|
82304
83443
|
if (changed) {
|
|
83444
|
+
credentials.invalidate(selectedProvider.catalogName);
|
|
82305
83445
|
invalidateProbeProxyHandlers(selectedProvider.catalogName);
|
|
82306
83446
|
invalidateProbeDiscovery(selectedProvider.catalogName);
|
|
82307
83447
|
clearTestResult(selectedProvider.name);
|
|
82308
83448
|
refreshConfig();
|
|
82309
|
-
setStatusMsg(`Stored config removed for ${selectedProvider.displayName}.`);
|
|
82310
|
-
} else {
|
|
82311
|
-
setStatusMsg("No stored config to remove.");
|
|
82312
83449
|
}
|
|
83450
|
+
setStatusMsg(failureMsg ?? (changed ? removedFrom.length > 0 ? `Removed ${selectedProvider.displayName} key from ${removedFrom.join(" + ")}.` : `Stored config removed for ${selectedProvider.displayName}.` : "No stored config to remove."));
|
|
82313
83451
|
} else if (key.name === "l") {
|
|
82314
83452
|
const slug = selectedProvider.oauthSlug;
|
|
82315
83453
|
if (!slug) {
|
|
@@ -82534,6 +83672,18 @@ function App({ requestLogin } = {}) {
|
|
|
82534
83672
|
} else if (selectedOpEntry) {
|
|
82535
83673
|
testOpEntry(selectedOpEntry);
|
|
82536
83674
|
}
|
|
83675
|
+
} else if (key.raw === "C") {
|
|
83676
|
+
if (opEntries.length === 0) {
|
|
83677
|
+
setStatusMsg("No 1Password entries to copy.");
|
|
83678
|
+
} else {
|
|
83679
|
+
copyOpToKeychain(opEntries, `all ${opEntries.length} entries`);
|
|
83680
|
+
}
|
|
83681
|
+
} else if (key.name === "c") {
|
|
83682
|
+
if (opEntries.length === 0 || !selectedOpEntry) {
|
|
83683
|
+
setStatusMsg("No 1Password entry to copy.");
|
|
83684
|
+
} else {
|
|
83685
|
+
copyOpToKeychain([selectedOpEntry], selectedOpEntry.envName ?? selectedOpEntry.value);
|
|
83686
|
+
}
|
|
82537
83687
|
} else if (key.name === "x") {
|
|
82538
83688
|
if (opEntries.length === 0 || !selectedOpEntry) {
|
|
82539
83689
|
setStatusMsg("No 1Password entry to remove.");
|
|
@@ -82670,7 +83820,9 @@ function App({ requestLogin } = {}) {
|
|
|
82670
83820
|
hasKey,
|
|
82671
83821
|
authSource: selectedAuthSource,
|
|
82672
83822
|
isOpKey,
|
|
82673
|
-
|
|
83823
|
+
isKcKey,
|
|
83824
|
+
hasKcKey,
|
|
83825
|
+
keySaveTarget: keychainSupported ? "macOS Keychain" : "config.json",
|
|
82674
83826
|
cfgKeyMask,
|
|
82675
83827
|
envKeyMask,
|
|
82676
83828
|
activeEndpoint,
|
|
@@ -82798,10 +83950,13 @@ function App({ requestLogin } = {}) {
|
|
|
82798
83950
|
});
|
|
82799
83951
|
}
|
|
82800
83952
|
var init_App = __esm(() => {
|
|
83953
|
+
init_authority();
|
|
83954
|
+
init_keychain_source();
|
|
82801
83955
|
init_op_source();
|
|
82802
83956
|
init_profile_config();
|
|
82803
83957
|
init_default_routing_rules();
|
|
82804
83958
|
init_endpoint_registration();
|
|
83959
|
+
init_keychain();
|
|
82805
83960
|
init_local_liveness();
|
|
82806
83961
|
init_onepassword_config();
|
|
82807
83962
|
init_onepassword();
|
|
@@ -83038,10 +84193,10 @@ function shouldHideIncidentalAnthropicKey(config3, env = process.env) {
|
|
|
83038
84193
|
return false;
|
|
83039
84194
|
return !wantsAnthropicApiBilling(config3, env);
|
|
83040
84195
|
}
|
|
83041
|
-
function hasResolvableAnthropicAuth(
|
|
83042
|
-
const env =
|
|
83043
|
-
const fileExists =
|
|
83044
|
-
const keychainProbe =
|
|
84196
|
+
function hasResolvableAnthropicAuth(deps2 = {}) {
|
|
84197
|
+
const env = deps2.env ?? process.env;
|
|
84198
|
+
const fileExists = deps2.fileExists ?? existsSync30;
|
|
84199
|
+
const keychainProbe = deps2.keychainProbe ?? defaultKeychainAnthropicProbe;
|
|
83045
84200
|
if (env.ANTHROPIC_API_KEY || env.ANTHROPIC_AUTH_TOKEN)
|
|
83046
84201
|
return true;
|
|
83047
84202
|
if (fileExists(join40(homedir35(), ".claude", ".credentials.json")))
|
|
@@ -83233,7 +84388,7 @@ function initializeTokenFile(tokenFilePath) {
|
|
|
83233
84388
|
log(`[claude-runner] Could not initialize token file ${tokenFilePath}: ${e}`);
|
|
83234
84389
|
}
|
|
83235
84390
|
}
|
|
83236
|
-
function cleanupStaleTokenFiles(dir,
|
|
84391
|
+
function cleanupStaleTokenFiles(dir, now2 = Date.now(), maxAgeMs = STALE_TOKEN_FILE_MS) {
|
|
83237
84392
|
let removed = 0;
|
|
83238
84393
|
let entries;
|
|
83239
84394
|
try {
|
|
@@ -83241,7 +84396,7 @@ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FI
|
|
|
83241
84396
|
} catch {
|
|
83242
84397
|
return 0;
|
|
83243
84398
|
}
|
|
83244
|
-
const cutoff =
|
|
84399
|
+
const cutoff = now2 - maxAgeMs;
|
|
83245
84400
|
let scanned = 0;
|
|
83246
84401
|
for (const name of entries) {
|
|
83247
84402
|
if (scanned >= MAX_TOKEN_FILES_SCANNED)
|
|
@@ -83855,7 +85010,7 @@ function shouldWarmCatalog(args) {
|
|
|
83855
85010
|
}
|
|
83856
85011
|
return true;
|
|
83857
85012
|
}
|
|
83858
|
-
function classifyCatalogState(cache3, ttlHours,
|
|
85013
|
+
function classifyCatalogState(cache3, ttlHours, now2) {
|
|
83859
85014
|
if (cache3 === null)
|
|
83860
85015
|
return "missing";
|
|
83861
85016
|
if (cache3.entries.length === 0 && cache3.models.length === 0)
|
|
@@ -83863,7 +85018,7 @@ function classifyCatalogState(cache3, ttlHours, now) {
|
|
|
83863
85018
|
const lastUpdatedMs = Date.parse(cache3.lastUpdated);
|
|
83864
85019
|
if (Number.isNaN(lastUpdatedMs))
|
|
83865
85020
|
return "missing";
|
|
83866
|
-
const ageMs =
|
|
85021
|
+
const ageMs = now2.getTime() - lastUpdatedMs;
|
|
83867
85022
|
const ttlMs = ttlHours * 3600000;
|
|
83868
85023
|
return ageMs < ttlMs ? "fresh" : "stale";
|
|
83869
85024
|
}
|
|
@@ -83920,9 +85075,9 @@ async function warmCatalogIfNeeded(config3, opts) {
|
|
|
83920
85075
|
}
|
|
83921
85076
|
const ttlHoursRaw = opts?.ttlHours ?? Number.parseFloat(process.env.CLAUDISH_CATALOG_TTL_HOURS ?? "24");
|
|
83922
85077
|
const ttlHours = Number.isFinite(ttlHoursRaw) && ttlHoursRaw > 0 ? ttlHoursRaw : 24;
|
|
83923
|
-
const
|
|
85078
|
+
const now2 = opts?.now ?? new Date;
|
|
83924
85079
|
const cache3 = readAllModelsCache();
|
|
83925
|
-
const state = classifyCatalogState(cache3, ttlHours,
|
|
85080
|
+
const state = classifyCatalogState(cache3, ttlHours, now2);
|
|
83926
85081
|
if (state === "fresh" && !config3.forceUpdate) {
|
|
83927
85082
|
return "ok";
|
|
83928
85083
|
}
|
|
@@ -83941,14 +85096,14 @@ async function warmCatalogIfNeeded(config3, opts) {
|
|
|
83941
85096
|
return "ok";
|
|
83942
85097
|
}
|
|
83943
85098
|
if (state === "stale") {
|
|
83944
|
-
const ageMs =
|
|
85099
|
+
const ageMs = now2.getTime() - Date.parse(cache3.lastUpdated);
|
|
83945
85100
|
const ageStr = humanizeAge(ageMs);
|
|
83946
85101
|
process.stderr.write(`WARNING: Catalog stale (${ageStr}). Using cached version. Run \`claudish --models-refresh\` to retry.
|
|
83947
85102
|
`);
|
|
83948
85103
|
return "warned";
|
|
83949
85104
|
}
|
|
83950
85105
|
if (state === "fresh") {
|
|
83951
|
-
const ageMs =
|
|
85106
|
+
const ageMs = now2.getTime() - Date.parse(cache3.lastUpdated);
|
|
83952
85107
|
const ageStr = humanizeAge(ageMs);
|
|
83953
85108
|
process.stderr.write(`WARNING: Catalog refresh failed (cache age ${ageStr}). Using cached version.
|
|
83954
85109
|
`);
|
|
@@ -85410,10 +86565,10 @@ function ResumePicker({ groups, onDone }) {
|
|
|
85410
86565
|
const { fresh, stale, visibleGroups } = useMemo4(() => {
|
|
85411
86566
|
const withSessions = groups.filter((g) => (listed.get(g.name)?.length ?? 0) > 0);
|
|
85412
86567
|
const matching = filter ? withSessions.filter((g) => fuzzy(filter, g.name)) : withSessions;
|
|
85413
|
-
const
|
|
86568
|
+
const now2 = Date.now();
|
|
85414
86569
|
const byRecency = (a, b) => b.lastActiveMs - a.lastActiveMs;
|
|
85415
|
-
const f = matching.filter((g) => g.current ||
|
|
85416
|
-
const st = matching.filter((g) => !g.current &&
|
|
86570
|
+
const f = matching.filter((g) => g.current || now2 - g.lastActiveMs < STALE_MS).sort((a, b) => a.current !== b.current ? a.current ? -1 : 1 : byRecency(a, b));
|
|
86571
|
+
const st = matching.filter((g) => !g.current && now2 - g.lastActiveMs >= STALE_MS).sort(byRecency);
|
|
85417
86572
|
return { fresh: f, stale: st, visibleGroups: [...f, ...st] };
|
|
85418
86573
|
}, [groups, filter, listed]);
|
|
85419
86574
|
const group = visibleGroups[Math.min(wtCursor, visibleGroups.length - 1)];
|
|
@@ -86342,7 +87497,7 @@ function renderSessionSummary(input) {
|
|
|
86342
87497
|
const W2 = cardWidth();
|
|
86343
87498
|
const inner = W2 - CHROME;
|
|
86344
87499
|
const out = [];
|
|
86345
|
-
const
|
|
87500
|
+
const dim4 = (s) => paint(s, tokens.subtle);
|
|
86346
87501
|
const body = (s) => paint(s, tokens.text);
|
|
86347
87502
|
const titleText = exitCode === 0 ? " session " : " session \xB7 failed ";
|
|
86348
87503
|
const titleHex = exitCode === 0 ? tokens.accent : tokens.error;
|
|
@@ -86364,26 +87519,26 @@ function renderSessionSummary(input) {
|
|
|
86364
87519
|
const gap = Math.max(1, inner - visibleWidth(left) - visibleWidth(right));
|
|
86365
87520
|
row(left + " ".repeat(gap) + right);
|
|
86366
87521
|
if (stats.providerName)
|
|
86367
|
-
row(
|
|
87522
|
+
row(dim4(truncate3(stats.providerName, inner)));
|
|
86368
87523
|
blank();
|
|
86369
87524
|
const VALUE_W = 24;
|
|
86370
87525
|
const barW = Math.max(12, inner - LABEL_W - VALUE_W);
|
|
86371
87526
|
const dataRow = (label, bar, values) => {
|
|
86372
|
-
row(
|
|
87527
|
+
row(dim4(padTo(label, LABEL_W)) + bar + padVisible2(values, VALUE_W, "right"));
|
|
86373
87528
|
};
|
|
86374
87529
|
if (stats.contextUsed !== null && stats.contextWindow) {
|
|
86375
87530
|
const pct = stats.contextUsed * 100;
|
|
86376
|
-
dataRow("context", meter(pct, barW, ramps.load), body(padStartTo(`${Math.round(pct)}%`, 4)) +
|
|
87531
|
+
dataRow("context", meter(pct, barW, ramps.load), body(padStartTo(`${Math.round(pct)}%`, 4)) + dim4(` ${compact(stats.inputTokens)}/${compact(stats.contextWindow)}`));
|
|
86377
87532
|
}
|
|
86378
87533
|
dataRow("tokens", stackedBar([
|
|
86379
87534
|
{ value: stats.inputTokens, color: C.blue },
|
|
86380
87535
|
{ value: stats.outputTokens, color: C.cyan }
|
|
86381
|
-
], barW),
|
|
87536
|
+
], barW), dim4("in ") + body(compact(stats.inputTokens)) + dim4(" out ") + body(compact(stats.outputTokens)));
|
|
86382
87537
|
if (!stats.isFree && stats.inputCostUsd + stats.outputCostUsd > 0) {
|
|
86383
87538
|
dataRow("spend", stackedBar([
|
|
86384
87539
|
{ value: stats.inputCostUsd, color: C.blue },
|
|
86385
87540
|
{ value: stats.outputCostUsd, color: C.cyan }
|
|
86386
|
-
], barW),
|
|
87541
|
+
], barW), dim4("in ") + body(usd(stats.inputCostUsd)) + dim4(" out ") + body(usd(stats.outputCostUsd)));
|
|
86387
87542
|
}
|
|
86388
87543
|
if (stats.toolCallTotal > 0) {
|
|
86389
87544
|
const toolCols = toolColors();
|
|
@@ -86393,27 +87548,27 @@ function renderSessionSummary(input) {
|
|
|
86393
87548
|
const segs = shown.map((t, i) => ({ value: t.count, color: toolCols[i] }));
|
|
86394
87549
|
if (rest > 0)
|
|
86395
87550
|
segs.push({ value: rest, color: other });
|
|
86396
|
-
dataRow("tools", stackedBar(segs, barW), body(padStartTo(String(stats.toolCallTotal), 4)) +
|
|
87551
|
+
dataRow("tools", stackedBar(segs, barW), body(padStartTo(String(stats.toolCallTotal), 4)) + dim4(" calls"));
|
|
86397
87552
|
const legend = shown.map((t, i) => paint(`${t.name} ${t.count}`, toolCols[i])).concat(rest > 0 ? [paint(`other ${rest}`, other)] : []);
|
|
86398
|
-
for (const line of wrapStyled(legend,
|
|
87553
|
+
for (const line of wrapStyled(legend, dim4(" \xB7 "), inner - LABEL_W)) {
|
|
86399
87554
|
row(" ".repeat(LABEL_W) + line);
|
|
86400
87555
|
}
|
|
86401
87556
|
}
|
|
86402
87557
|
blank();
|
|
86403
|
-
row(
|
|
87558
|
+
row(dim4(padTo("cost", LABEL_W)) + paint(stats.isFree ? "free" : usd(stats.costUsd), stats.isFree ? tokens.success : tokens.text, true) + (stats.isEstimated && !stats.isFree ? dim4(" estimated") : ""));
|
|
86404
87559
|
for (const s of stats.savings) {
|
|
86405
87560
|
const label = padTo(`vs ${s.label}`, LABEL_W);
|
|
86406
87561
|
if (s.savedUsd >= 0) {
|
|
86407
87562
|
const pct = s.baselineUsd > 0 ? s.savedUsd / s.baselineUsd * 100 : 0;
|
|
86408
|
-
dataRow(label, meter(pct, barW, ramps.savings), paint(padStartTo(`${Math.round(pct)}%`, 4), tokens.success) +
|
|
87563
|
+
dataRow(label, meter(pct, barW, ramps.savings), paint(padStartTo(`${Math.round(pct)}%`, 4), tokens.success) + dim4(" saved ") + paint(usd(s.savedUsd), tokens.success));
|
|
86409
87564
|
} else {
|
|
86410
|
-
dataRow(label, meter(0, barW, ramps.savings),
|
|
87565
|
+
dataRow(label, meter(0, barW, ramps.savings), dim4("over by ") + paint(usd(-s.savedUsd), tokens.error));
|
|
86411
87566
|
}
|
|
86412
87567
|
}
|
|
86413
87568
|
out.push(paint(`\u2570${"\u2500".repeat(W2 - 2)}\u256F`, tokens.border));
|
|
86414
87569
|
if (resumeId) {
|
|
86415
87570
|
out.push("");
|
|
86416
|
-
out.push(
|
|
87571
|
+
out.push(dim4("Resume this session with:"));
|
|
86417
87572
|
const modelFlag = resumeModelSpec ? `--model ${resumeModelSpec} ` : "";
|
|
86418
87573
|
out.push(`claudish ${modelFlag}--resume ${resumeId}`);
|
|
86419
87574
|
}
|
|
@@ -86471,6 +87626,7 @@ function classifyStartupKind() {
|
|
|
86471
87626
|
"telemetry",
|
|
86472
87627
|
"stats",
|
|
86473
87628
|
"providers",
|
|
87629
|
+
"keychain",
|
|
86474
87630
|
"login",
|
|
86475
87631
|
"logout",
|
|
86476
87632
|
"quota",
|
|
@@ -86590,6 +87746,7 @@ var isStatsCommand = firstPositional === "stats";
|
|
|
86590
87746
|
var isConfigCommand = firstPositional === "config";
|
|
86591
87747
|
var isServeCommand = firstPositional === "serve";
|
|
86592
87748
|
var isProvidersCommand = firstPositional === "providers";
|
|
87749
|
+
var isKeychainCommand = firstPositional === "keychain";
|
|
86593
87750
|
var isBehaviorCommand = firstPositional === "behavior";
|
|
86594
87751
|
var isTeamCommand = firstPositional === "team";
|
|
86595
87752
|
var isLoginCommand = firstPositional === "login";
|
|
@@ -86629,6 +87786,12 @@ if (isMcpMode) {
|
|
|
86629
87786
|
console.error(`[claudish providers] ${e instanceof Error ? e.message : String(e)}`);
|
|
86630
87787
|
process.exit(1);
|
|
86631
87788
|
}));
|
|
87789
|
+
} else if (isKeychainCommand) {
|
|
87790
|
+
const keychainArgIndex = args.indexOf("keychain");
|
|
87791
|
+
Promise.resolve().then(() => (init_keychain_command(), exports_keychain_command)).then((m) => m.keychainCommand(args.slice(keychainArgIndex + 1)).catch((e) => {
|
|
87792
|
+
console.error(`[claudish keychain] ${e instanceof Error ? e.message : String(e)}`);
|
|
87793
|
+
process.exit(1);
|
|
87794
|
+
}));
|
|
86632
87795
|
} else if (isLoginCommand) {
|
|
86633
87796
|
const loginProviderArg = args.find((a, i) => i > args.indexOf("login") && !a.startsWith("-"));
|
|
86634
87797
|
Promise.resolve().then(() => (init_auth_commands(), exports_auth_commands)).then((m) => m.loginCommand(loginProviderArg).catch(handlePromptExit));
|
|
@@ -86666,6 +87829,10 @@ if (isMcpMode) {
|
|
|
86666
87829
|
});
|
|
86667
87830
|
} else if (isConfigCommand) {
|
|
86668
87831
|
traceSpan("startup:tui-import", () => Promise.resolve().then(() => (init_tui(), exports_tui))).then(async (m) => {
|
|
87832
|
+
await traceSpan("startup:theme-detect", async () => {
|
|
87833
|
+
const { detectAndSetThemeMode: detectAndSetThemeMode2 } = await Promise.resolve().then(() => (init_theme_mode(), exports_theme_mode));
|
|
87834
|
+
await detectAndSetThemeMode2();
|
|
87835
|
+
});
|
|
86669
87836
|
const { credentials: credentials2 } = await Promise.resolve().then(() => (init_authority(), exports_authority));
|
|
86670
87837
|
const { ensureEndpointsRegistered: ensureEndpointsRegistered2 } = await Promise.resolve().then(() => (init_endpoint_registration(), exports_endpoint_registration));
|
|
86671
87838
|
ensureEndpointsRegistered2();
|