claudish 7.65.0 → 7.66.0
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 +1467 -344
- 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.0";
|
|
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;
|
|
@@ -35277,6 +35342,9 @@ var init_gemini_queue = __esm(() => {
|
|
|
35277
35342
|
|
|
35278
35343
|
// src/providers/transport/antigravity.ts
|
|
35279
35344
|
import { randomUUID } from "crypto";
|
|
35345
|
+
function antigravityEndpoint() {
|
|
35346
|
+
return `${antigravityHost()}/v1internal:streamGenerateContent?alt=sse`;
|
|
35347
|
+
}
|
|
35280
35348
|
function rankReasoningSuffix(suffix) {
|
|
35281
35349
|
const rank = REASONING_TIER_RANK[suffix.toLowerCase()];
|
|
35282
35350
|
return rank === undefined ? Number.MAX_SAFE_INTEGER : rank;
|
|
@@ -35343,7 +35411,12 @@ function classify429(responseBody) {
|
|
|
35343
35411
|
return { terminal: false, retryDelayMs: retryDelayMs ?? 60000, reason };
|
|
35344
35412
|
}
|
|
35345
35413
|
}
|
|
35346
|
-
return {
|
|
35414
|
+
return {
|
|
35415
|
+
terminal: false,
|
|
35416
|
+
retryDelayMs,
|
|
35417
|
+
reason,
|
|
35418
|
+
unattributed: reason === undefined && retryDelayMs === undefined
|
|
35419
|
+
};
|
|
35347
35420
|
} catch {
|
|
35348
35421
|
return null;
|
|
35349
35422
|
}
|
|
@@ -35389,7 +35462,7 @@ class AntigravityProviderTransport {
|
|
|
35389
35462
|
return this._activeModelName;
|
|
35390
35463
|
}
|
|
35391
35464
|
getEndpoint() {
|
|
35392
|
-
return
|
|
35465
|
+
return antigravityEndpoint();
|
|
35393
35466
|
}
|
|
35394
35467
|
async getHeaders() {
|
|
35395
35468
|
if (this.cachedAuth)
|
|
@@ -35477,8 +35550,8 @@ class AntigravityProviderTransport {
|
|
|
35477
35550
|
return await this.explainTerminalQuota(response, bodyText, classification.reason);
|
|
35478
35551
|
}
|
|
35479
35552
|
if (attempt < MAX_RETRY_ATTEMPTS) {
|
|
35480
|
-
const delay = classification.retryDelayMs ?? DEFAULT_RATE_LIMIT_DELAY_MS;
|
|
35481
|
-
logStderr(`[Antigravity] Rate limited (${classification.reason || "
|
|
35553
|
+
const delay = classification.retryDelayMs ?? (classification.unattributed ? UNATTRIBUTED_RETRY_DELAY_MS : DEFAULT_RATE_LIMIT_DELAY_MS);
|
|
35554
|
+
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
35555
|
if (attempt === 1) {
|
|
35483
35556
|
await this.logQuotaInfo();
|
|
35484
35557
|
}
|
|
@@ -35665,7 +35738,7 @@ ${lines.join(`
|
|
|
35665
35738
|
}
|
|
35666
35739
|
}
|
|
35667
35740
|
}
|
|
35668
|
-
var
|
|
35741
|
+
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
35742
|
var init_antigravity2 = __esm(() => {
|
|
35670
35743
|
init_model_catalog();
|
|
35671
35744
|
init_antigravity_token();
|
|
@@ -35673,7 +35746,6 @@ var init_antigravity2 = __esm(() => {
|
|
|
35673
35746
|
init_authority();
|
|
35674
35747
|
init_gemini_queue();
|
|
35675
35748
|
init_logger();
|
|
35676
|
-
ANTIGRAVITY_ENDPOINT = `${ANTIGRAVITY_BASE}/v1internal:streamGenerateContent?alt=sse`;
|
|
35677
35749
|
REASONING_TIER_RANK = {
|
|
35678
35750
|
high: 0,
|
|
35679
35751
|
medium: 1,
|
|
@@ -35731,6 +35803,257 @@ var init_antigravity_credential = __esm(() => {
|
|
|
35731
35803
|
init_antigravity_user();
|
|
35732
35804
|
});
|
|
35733
35805
|
|
|
35806
|
+
// src/providers/keychain.ts
|
|
35807
|
+
function syncRun(args, stdin) {
|
|
35808
|
+
try {
|
|
35809
|
+
const proc = Bun.spawnSync([SECURITY_BIN, ...args], {
|
|
35810
|
+
stdin: stdin === undefined ? "ignore" : new TextEncoder().encode(stdin),
|
|
35811
|
+
stdout: "pipe",
|
|
35812
|
+
stderr: "pipe",
|
|
35813
|
+
timeout: SPAWN_TIMEOUT_MS
|
|
35814
|
+
});
|
|
35815
|
+
return normalizeResult(proc.exitCode, proc.signalCode, decode3(proc.stdout), decode3(proc.stderr));
|
|
35816
|
+
} catch (err) {
|
|
35817
|
+
return { code: 1, stdout: "", stderr: err instanceof Error ? err.message : String(err) };
|
|
35818
|
+
}
|
|
35819
|
+
}
|
|
35820
|
+
async function asyncRun(args, stdin) {
|
|
35821
|
+
try {
|
|
35822
|
+
const proc = Bun.spawn([SECURITY_BIN, ...args], {
|
|
35823
|
+
stdin: stdin === undefined ? "ignore" : new TextEncoder().encode(stdin),
|
|
35824
|
+
stdout: "pipe",
|
|
35825
|
+
stderr: "pipe",
|
|
35826
|
+
timeout: SPAWN_TIMEOUT_MS
|
|
35827
|
+
});
|
|
35828
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
35829
|
+
new Response(proc.stdout).text(),
|
|
35830
|
+
new Response(proc.stderr).text(),
|
|
35831
|
+
proc.exited
|
|
35832
|
+
]);
|
|
35833
|
+
return normalizeResult(exitCode, proc.signalCode, stdout, stderr);
|
|
35834
|
+
} catch (err) {
|
|
35835
|
+
return { code: 1, stdout: "", stderr: err instanceof Error ? err.message : String(err) };
|
|
35836
|
+
}
|
|
35837
|
+
}
|
|
35838
|
+
function decode3(buf) {
|
|
35839
|
+
return buf ? new TextDecoder().decode(buf) : "";
|
|
35840
|
+
}
|
|
35841
|
+
function normalizeResult(exitCode, signalCode, stdout, stderr) {
|
|
35842
|
+
if (typeof exitCode === "number")
|
|
35843
|
+
return { code: exitCode, stdout, stderr };
|
|
35844
|
+
const detail = signalCode ? `killed by ${signalCode}` : "terminated without an exit code";
|
|
35845
|
+
return { code: -1, stdout, stderr: stderr.trim() || `security ${detail}` };
|
|
35846
|
+
}
|
|
35847
|
+
function invalidateKeychainCache() {
|
|
35848
|
+
listMemo = null;
|
|
35849
|
+
valueMemo.clear();
|
|
35850
|
+
}
|
|
35851
|
+
function now() {
|
|
35852
|
+
return Date.now();
|
|
35853
|
+
}
|
|
35854
|
+
function isValidKeychainVarName(name) {
|
|
35855
|
+
return ENV_VAR_NAME.test(name);
|
|
35856
|
+
}
|
|
35857
|
+
function describeUnstorableValue(value) {
|
|
35858
|
+
if (value.length === 0)
|
|
35859
|
+
return "value is empty";
|
|
35860
|
+
if (CONTROL_CHARS.test(value)) {
|
|
35861
|
+
return "value contains control characters (tab/newline/etc), which the keychain read path cannot represent unambiguously";
|
|
35862
|
+
}
|
|
35863
|
+
return null;
|
|
35864
|
+
}
|
|
35865
|
+
function isKeychainSupported() {
|
|
35866
|
+
return deps.platform() === "darwin";
|
|
35867
|
+
}
|
|
35868
|
+
function keychainUnavailableReason() {
|
|
35869
|
+
if (!isKeychainSupported()) {
|
|
35870
|
+
return `the macOS Keychain is only available on macOS (this is ${deps.platform()})`;
|
|
35871
|
+
}
|
|
35872
|
+
return null;
|
|
35873
|
+
}
|
|
35874
|
+
function stripOneTrailingNewline(out) {
|
|
35875
|
+
return out.endsWith(`
|
|
35876
|
+
`) ? out.slice(0, -1) : out;
|
|
35877
|
+
}
|
|
35878
|
+
function keychainFileArgs() {
|
|
35879
|
+
const file2 = process.env.CLAUDISH_KEYCHAIN_FILE;
|
|
35880
|
+
return file2 ? [file2] : [];
|
|
35881
|
+
}
|
|
35882
|
+
function findArgs(envVar) {
|
|
35883
|
+
return [
|
|
35884
|
+
"find-generic-password",
|
|
35885
|
+
"-s",
|
|
35886
|
+
KEYCHAIN_SERVICE,
|
|
35887
|
+
"-a",
|
|
35888
|
+
envVar,
|
|
35889
|
+
"-w",
|
|
35890
|
+
...keychainFileArgs()
|
|
35891
|
+
];
|
|
35892
|
+
}
|
|
35893
|
+
function interpretRead(envVar, res) {
|
|
35894
|
+
if (res.code === 0) {
|
|
35895
|
+
const value = stripOneTrailingNewline(res.stdout);
|
|
35896
|
+
return value.length > 0 ? value : null;
|
|
35897
|
+
}
|
|
35898
|
+
if (res.code === EXIT_ITEM_NOT_FOUND)
|
|
35899
|
+
return null;
|
|
35900
|
+
throw new KeychainError(`Keychain lookup for ${envVar} failed: ${res.stderr.trim() || `security exited ${res.code}`}`, res.code);
|
|
35901
|
+
}
|
|
35902
|
+
function readKeychainSecret(envVar) {
|
|
35903
|
+
if (!isKeychainSupported())
|
|
35904
|
+
return null;
|
|
35905
|
+
const cached2 = valueMemo.get(envVar);
|
|
35906
|
+
const at = now();
|
|
35907
|
+
if (cached2 && at - cached2.at < MEMO_TTL_MS)
|
|
35908
|
+
return cached2.value;
|
|
35909
|
+
const value = interpretRead(envVar, deps.run(findArgs(envVar)));
|
|
35910
|
+
valueMemo.set(envVar, { at, value });
|
|
35911
|
+
return value;
|
|
35912
|
+
}
|
|
35913
|
+
async function readKeychainSecretAsync(envVar) {
|
|
35914
|
+
if (!isKeychainSupported())
|
|
35915
|
+
return null;
|
|
35916
|
+
const cached2 = valueMemo.get(envVar);
|
|
35917
|
+
const at = now();
|
|
35918
|
+
if (cached2 && at - cached2.at < MEMO_TTL_MS)
|
|
35919
|
+
return cached2.value;
|
|
35920
|
+
const value = interpretRead(envVar, await deps.runAsync(findArgs(envVar)));
|
|
35921
|
+
valueMemo.set(envVar, { at, value });
|
|
35922
|
+
return value;
|
|
35923
|
+
}
|
|
35924
|
+
function enumerateKeychainVars() {
|
|
35925
|
+
if (!isKeychainSupported())
|
|
35926
|
+
return { names: [], failed: false };
|
|
35927
|
+
const at = now();
|
|
35928
|
+
if (listMemo && at - listMemo.at < MEMO_TTL_MS)
|
|
35929
|
+
return listMemo.value;
|
|
35930
|
+
const res = deps.run(["dump-keychain", ...keychainFileArgs()]);
|
|
35931
|
+
const value = res.code === 0 ? { names: parseDumpAccounts(res.stdout), failed: false } : {
|
|
35932
|
+
names: [],
|
|
35933
|
+
failed: true,
|
|
35934
|
+
error: res.stderr.trim() || `security exited ${res.code}`
|
|
35935
|
+
};
|
|
35936
|
+
listMemo = { at, value };
|
|
35937
|
+
return value;
|
|
35938
|
+
}
|
|
35939
|
+
function listKeychainVars() {
|
|
35940
|
+
return enumerateKeychainVars().names;
|
|
35941
|
+
}
|
|
35942
|
+
function parseDumpAccounts(dump) {
|
|
35943
|
+
const found = new Set;
|
|
35944
|
+
for (const block of dump.split(/\nkeychain: /)) {
|
|
35945
|
+
if (!block.includes(SVCE_MATCH))
|
|
35946
|
+
continue;
|
|
35947
|
+
const m = block.match(ACCT_ATTR);
|
|
35948
|
+
if (m?.[1] && isValidKeychainVarName(m[1]))
|
|
35949
|
+
found.add(m[1]);
|
|
35950
|
+
}
|
|
35951
|
+
return Array.from(found).sort();
|
|
35952
|
+
}
|
|
35953
|
+
function lookupKeychainVar(envVar) {
|
|
35954
|
+
if (!isKeychainSupported())
|
|
35955
|
+
return { present: false, failed: false };
|
|
35956
|
+
const cached2 = valueMemo.get(envVar);
|
|
35957
|
+
if (cached2 && now() - cached2.at < MEMO_TTL_MS && cached2.value !== null) {
|
|
35958
|
+
return { present: true, failed: false };
|
|
35959
|
+
}
|
|
35960
|
+
const listed = enumerateKeychainVars();
|
|
35961
|
+
return { present: listed.names.includes(envVar), failed: listed.failed };
|
|
35962
|
+
}
|
|
35963
|
+
function toHex(value) {
|
|
35964
|
+
return Buffer.from(value, "utf8").toString("hex");
|
|
35965
|
+
}
|
|
35966
|
+
function quoteForStdin(value) {
|
|
35967
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
35968
|
+
}
|
|
35969
|
+
function writeKeychainSecret(envVar, value) {
|
|
35970
|
+
const unsupported2 = keychainUnavailableReason();
|
|
35971
|
+
if (unsupported2)
|
|
35972
|
+
throw new KeychainError(`Cannot write ${envVar}: ${unsupported2}`);
|
|
35973
|
+
if (!isValidKeychainVarName(envVar)) {
|
|
35974
|
+
throw new KeychainError(`Cannot write "${envVar}": not a valid environment variable name`);
|
|
35975
|
+
}
|
|
35976
|
+
const unstorable = describeUnstorableValue(value);
|
|
35977
|
+
if (unstorable)
|
|
35978
|
+
throw new KeychainError(`Cannot store ${envVar}: ${unstorable}`);
|
|
35979
|
+
invalidateKeychainCache();
|
|
35980
|
+
const cmd = [
|
|
35981
|
+
"add-generic-password",
|
|
35982
|
+
"-s",
|
|
35983
|
+
quoteForStdin(KEYCHAIN_SERVICE),
|
|
35984
|
+
"-a",
|
|
35985
|
+
quoteForStdin(envVar),
|
|
35986
|
+
"-l",
|
|
35987
|
+
quoteForStdin(`${KEYCHAIN_SERVICE}: ${envVar}`),
|
|
35988
|
+
"-D",
|
|
35989
|
+
quoteForStdin("application password"),
|
|
35990
|
+
"-j",
|
|
35991
|
+
quoteForStdin("Stored by claudish"),
|
|
35992
|
+
"-X",
|
|
35993
|
+
quoteForStdin(toHex(value)),
|
|
35994
|
+
"-U",
|
|
35995
|
+
"-T",
|
|
35996
|
+
quoteForStdin(SECURITY_BIN),
|
|
35997
|
+
...keychainFileArgs().map(quoteForStdin)
|
|
35998
|
+
].join(" ");
|
|
35999
|
+
const res = deps.run(["-i"], `${cmd}
|
|
36000
|
+
`);
|
|
36001
|
+
if (res.code !== 0) {
|
|
36002
|
+
throw new KeychainError(`Failed to store ${envVar} in the keychain: ${res.stderr.trim() || `security exited ${res.code}`}`, res.code);
|
|
36003
|
+
}
|
|
36004
|
+
invalidateKeychainCache();
|
|
36005
|
+
const readBack = readKeychainSecret(envVar);
|
|
36006
|
+
if (readBack !== value) {
|
|
36007
|
+
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.");
|
|
36008
|
+
}
|
|
36009
|
+
}
|
|
36010
|
+
function deleteKeychainSecret(envVar) {
|
|
36011
|
+
if (!isKeychainSupported())
|
|
36012
|
+
return false;
|
|
36013
|
+
invalidateKeychainCache();
|
|
36014
|
+
const res = deps.run([
|
|
36015
|
+
"delete-generic-password",
|
|
36016
|
+
"-s",
|
|
36017
|
+
KEYCHAIN_SERVICE,
|
|
36018
|
+
"-a",
|
|
36019
|
+
envVar,
|
|
36020
|
+
...keychainFileArgs()
|
|
36021
|
+
]);
|
|
36022
|
+
invalidateKeychainCache();
|
|
36023
|
+
if (res.code === 0)
|
|
36024
|
+
return true;
|
|
36025
|
+
if (res.code === EXIT_ITEM_NOT_FOUND)
|
|
36026
|
+
return false;
|
|
36027
|
+
throw new KeychainError(`Failed to delete ${envVar} from the keychain: ${res.stderr.trim() || `security exited ${res.code}`}`, res.code);
|
|
36028
|
+
}
|
|
36029
|
+
function valueTail2(value) {
|
|
36030
|
+
if (value.length <= 6)
|
|
36031
|
+
return "\u2022\u2022\u2022\u2022";
|
|
36032
|
+
return `\u2022\u2022\u2022\u2022${value.slice(-4)}`;
|
|
36033
|
+
}
|
|
36034
|
+
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;
|
|
36035
|
+
var init_keychain = __esm(() => {
|
|
36036
|
+
KeychainError = class KeychainError extends Error {
|
|
36037
|
+
exitCode;
|
|
36038
|
+
constructor(message, exitCode) {
|
|
36039
|
+
super(message);
|
|
36040
|
+
this.exitCode = exitCode;
|
|
36041
|
+
this.name = "KeychainError";
|
|
36042
|
+
}
|
|
36043
|
+
};
|
|
36044
|
+
defaultDeps2 = {
|
|
36045
|
+
platform: () => process.platform,
|
|
36046
|
+
run: syncRun,
|
|
36047
|
+
runAsync: asyncRun
|
|
36048
|
+
};
|
|
36049
|
+
deps = defaultDeps2;
|
|
36050
|
+
valueMemo = new Map;
|
|
36051
|
+
CONTROL_CHARS = /[\u0000-\u001F\u007F]/;
|
|
36052
|
+
ENV_VAR_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
36053
|
+
ACCT_ATTR = /"acct"<blob>=(?:0x[0-9A-Fa-f]*\s+)?"([^"]*)"/;
|
|
36054
|
+
SVCE_MATCH = `"svce"<blob>="${KEYCHAIN_SERVICE}"`;
|
|
36055
|
+
});
|
|
36056
|
+
|
|
35734
36057
|
// src/auth/credentials/local-api-key.ts
|
|
35735
36058
|
function resolveLocalApiKey(q) {
|
|
35736
36059
|
return realValue(process.env[q.envVar]) || (q.aliases ?? []).map((a) => realValue(process.env[a])).find((v) => !!v) || realValue(getApiKey(q.envVar));
|
|
@@ -35747,6 +36070,108 @@ var init_local_api_key = __esm(() => {
|
|
|
35747
36070
|
init_profile_config();
|
|
35748
36071
|
});
|
|
35749
36072
|
|
|
36073
|
+
// src/auth/credentials/keychain-source.ts
|
|
36074
|
+
function warnOnce2(message) {
|
|
36075
|
+
if (warnedMessages2.has(message))
|
|
36076
|
+
return;
|
|
36077
|
+
warnedMessages2.add(message);
|
|
36078
|
+
console.error(message);
|
|
36079
|
+
}
|
|
36080
|
+
function recordKeychainHydratedVar(envVar) {
|
|
36081
|
+
hydratedVars.add(envVar);
|
|
36082
|
+
}
|
|
36083
|
+
function isKeychainHydratedVar(envVar) {
|
|
36084
|
+
return hydratedVars.has(envVar);
|
|
36085
|
+
}
|
|
36086
|
+
function hasKeychainSource() {
|
|
36087
|
+
if (process.env.CLAUDISH_DISABLE_KEYCHAIN === "1")
|
|
36088
|
+
return false;
|
|
36089
|
+
if (!isKeychainSupported())
|
|
36090
|
+
return false;
|
|
36091
|
+
return isKeychainEnabled();
|
|
36092
|
+
}
|
|
36093
|
+
function resolveKeychainKeyForEnvVars(wanted) {
|
|
36094
|
+
if (!hasKeychainSource())
|
|
36095
|
+
return { failed: false };
|
|
36096
|
+
let failed = false;
|
|
36097
|
+
try {
|
|
36098
|
+
for (const name of wanted) {
|
|
36099
|
+
if (!name)
|
|
36100
|
+
continue;
|
|
36101
|
+
const { present, failed: lookupFailed } = lookupKeychainVar(name);
|
|
36102
|
+
if (lookupFailed)
|
|
36103
|
+
failed = true;
|
|
36104
|
+
if (!present)
|
|
36105
|
+
continue;
|
|
36106
|
+
const value = readKeychainSecret(name);
|
|
36107
|
+
if (value)
|
|
36108
|
+
return { value, failed: false };
|
|
36109
|
+
}
|
|
36110
|
+
} catch (err) {
|
|
36111
|
+
warnOnce2(`[claudish] macOS Keychain lookup skipped: ${err instanceof KeychainError ? err.message : String(err)}`);
|
|
36112
|
+
return { failed: true };
|
|
36113
|
+
}
|
|
36114
|
+
if (failed) {
|
|
36115
|
+
warnOnce2("[claudish] macOS Keychain could not be enumerated \u2014 treating this provider as unresolved rather than uncredentialed.");
|
|
36116
|
+
}
|
|
36117
|
+
return { failed };
|
|
36118
|
+
}
|
|
36119
|
+
async function hydrateKeychainIntoEnv() {
|
|
36120
|
+
if (!hasKeychainSource())
|
|
36121
|
+
return 0;
|
|
36122
|
+
let names;
|
|
36123
|
+
try {
|
|
36124
|
+
const listed = enumerateKeychainVars();
|
|
36125
|
+
if (listed.failed) {
|
|
36126
|
+
warnOnce2(`[claudish] macOS Keychain enumeration skipped: ${listed.error ?? "unknown error"}`);
|
|
36127
|
+
return 0;
|
|
36128
|
+
}
|
|
36129
|
+
names = listed.names;
|
|
36130
|
+
} catch (err) {
|
|
36131
|
+
warnOnce2(`[claudish] macOS Keychain enumeration skipped: ${String(err)}`);
|
|
36132
|
+
return 0;
|
|
36133
|
+
}
|
|
36134
|
+
const missing = names.filter((n) => !resolveLocalApiKey({ envVar: n }));
|
|
36135
|
+
if (missing.length === 0)
|
|
36136
|
+
return 0;
|
|
36137
|
+
const results = await Promise.all(missing.map(async (name) => {
|
|
36138
|
+
try {
|
|
36139
|
+
return { name, value: await readKeychainSecretAsync(name) };
|
|
36140
|
+
} catch (err) {
|
|
36141
|
+
warnOnce2(`[claudish] macOS Keychain read for ${name} skipped: ${err instanceof KeychainError ? err.message : String(err)}`);
|
|
36142
|
+
return { name, value: null };
|
|
36143
|
+
}
|
|
36144
|
+
}));
|
|
36145
|
+
let hydrated = 0;
|
|
36146
|
+
for (const { name, value } of results) {
|
|
36147
|
+
if (!value || resolveLocalApiKey({ envVar: name }))
|
|
36148
|
+
continue;
|
|
36149
|
+
process.env[name] = value;
|
|
36150
|
+
recordKeychainHydratedVar(name);
|
|
36151
|
+
hydrated++;
|
|
36152
|
+
}
|
|
36153
|
+
return hydrated;
|
|
36154
|
+
}
|
|
36155
|
+
function keychainHasAnyOf(names) {
|
|
36156
|
+
if (!hasKeychainSource())
|
|
36157
|
+
return false;
|
|
36158
|
+
try {
|
|
36159
|
+
for (const name of names) {
|
|
36160
|
+
if (name && lookupKeychainVar(name).present)
|
|
36161
|
+
return true;
|
|
36162
|
+
}
|
|
36163
|
+
} catch {}
|
|
36164
|
+
return false;
|
|
36165
|
+
}
|
|
36166
|
+
var warnedMessages2, hydratedVars;
|
|
36167
|
+
var init_keychain_source = __esm(() => {
|
|
36168
|
+
init_profile_config();
|
|
36169
|
+
init_keychain();
|
|
36170
|
+
init_local_api_key();
|
|
36171
|
+
warnedMessages2 = new Set;
|
|
36172
|
+
hydratedVars = new Set;
|
|
36173
|
+
});
|
|
36174
|
+
|
|
35750
36175
|
// src/auth/credentials/api-key-credential.ts
|
|
35751
36176
|
import { existsSync as existsSync12 } from "fs";
|
|
35752
36177
|
import { homedir as homedir18 } from "os";
|
|
@@ -35758,7 +36183,6 @@ class ApiKeyCredentialProvider {
|
|
|
35758
36183
|
aliases;
|
|
35759
36184
|
authScheme;
|
|
35760
36185
|
staticHeaders;
|
|
35761
|
-
publicKeyFallback;
|
|
35762
36186
|
oauthFallback;
|
|
35763
36187
|
declaredKey;
|
|
35764
36188
|
cachedKey;
|
|
@@ -35769,7 +36193,6 @@ class ApiKeyCredentialProvider {
|
|
|
35769
36193
|
this.aliases = descriptor.aliases ?? [];
|
|
35770
36194
|
this.authScheme = descriptor.authScheme ?? "bearer";
|
|
35771
36195
|
this.staticHeaders = descriptor.staticHeaders ?? {};
|
|
35772
|
-
this.publicKeyFallback = descriptor.publicKeyFallback;
|
|
35773
36196
|
this.oauthFallback = descriptor.oauthFallback;
|
|
35774
36197
|
this.declaredKey = descriptor.declaredKey;
|
|
35775
36198
|
}
|
|
@@ -35803,6 +36226,17 @@ class ApiKeyCredentialProvider {
|
|
|
35803
36226
|
this.cachedKey = local;
|
|
35804
36227
|
return local;
|
|
35805
36228
|
}
|
|
36229
|
+
let keychainFailed = false;
|
|
36230
|
+
if (hasKeychainSource()) {
|
|
36231
|
+
const kc = resolveKeychainKeyForEnvVars([this.envVar, ...this.aliases]);
|
|
36232
|
+
if (kc.value) {
|
|
36233
|
+
process.env[this.envVar] = kc.value;
|
|
36234
|
+
recordKeychainHydratedVar(this.envVar);
|
|
36235
|
+
this.cachedKey = kc.value;
|
|
36236
|
+
return kc.value;
|
|
36237
|
+
}
|
|
36238
|
+
keychainFailed = kc.failed;
|
|
36239
|
+
}
|
|
35806
36240
|
if (hasOpSources()) {
|
|
35807
36241
|
const wanted = new Set([this.envVar, ...this.aliases]);
|
|
35808
36242
|
const resolved = await resolveOpKeyForEnvVars(wanted, {
|
|
@@ -35817,7 +36251,8 @@ class ApiKeyCredentialProvider {
|
|
|
35817
36251
|
}
|
|
35818
36252
|
return "";
|
|
35819
36253
|
}
|
|
35820
|
-
|
|
36254
|
+
if (!keychainFailed)
|
|
36255
|
+
this.cachedKey = "";
|
|
35821
36256
|
return "";
|
|
35822
36257
|
})();
|
|
35823
36258
|
try {
|
|
@@ -35829,8 +36264,6 @@ class ApiKeyCredentialProvider {
|
|
|
35829
36264
|
async isAvailable(opts) {
|
|
35830
36265
|
if (this.authScheme === "none")
|
|
35831
36266
|
return true;
|
|
35832
|
-
if (this.publicKeyFallback)
|
|
35833
|
-
return true;
|
|
35834
36267
|
if (this.resolveFromEnvConfig())
|
|
35835
36268
|
return true;
|
|
35836
36269
|
if (this.hasOauthFallbackFile())
|
|
@@ -35846,7 +36279,7 @@ class ApiKeyCredentialProvider {
|
|
|
35846
36279
|
if (this.authScheme === "none") {
|
|
35847
36280
|
return { headers: { ...this.staticHeaders } };
|
|
35848
36281
|
}
|
|
35849
|
-
const key = await this.resolveKey({ allowOpPrompt: ctx.allowOpPrompt })
|
|
36282
|
+
const key = await this.resolveKey({ allowOpPrompt: ctx.allowOpPrompt });
|
|
35850
36283
|
let headers;
|
|
35851
36284
|
if (this.authScheme === "x-api-key") {
|
|
35852
36285
|
headers = { "x-api-key": key, ...this.staticHeaders };
|
|
@@ -35860,6 +36293,7 @@ class ApiKeyCredentialProvider {
|
|
|
35860
36293
|
}
|
|
35861
36294
|
var init_api_key_credential = __esm(() => {
|
|
35862
36295
|
init_env_placeholder();
|
|
36296
|
+
init_keychain_source();
|
|
35863
36297
|
init_local_api_key();
|
|
35864
36298
|
init_op_source();
|
|
35865
36299
|
});
|
|
@@ -37112,7 +37546,6 @@ class CredentialAuthority {
|
|
|
37112
37546
|
envVar: def.apiKeyEnvVar,
|
|
37113
37547
|
aliases: def.apiKeyAliases,
|
|
37114
37548
|
authScheme: normalizeAuthScheme(def.authScheme),
|
|
37115
|
-
publicKeyFallback: def.publicKeyFallback,
|
|
37116
37549
|
oauthFallback: def.oauthFallback
|
|
37117
37550
|
}), [def.name, ...RUNTIME_NAME_ALIASES[def.name] ?? []]);
|
|
37118
37551
|
}
|
|
@@ -37528,8 +37961,8 @@ async function fetchDevinAllowedUids(apiKey) {
|
|
|
37528
37961
|
return uids;
|
|
37529
37962
|
}
|
|
37530
37963
|
async function getServedDevinModels(opts) {
|
|
37531
|
-
const
|
|
37532
|
-
if (!opts?.force && rosterCache &&
|
|
37964
|
+
const now2 = Date.now();
|
|
37965
|
+
if (!opts?.force && rosterCache && now2 - rosterCacheAt < ROSTER_TTL_MS)
|
|
37533
37966
|
return rosterCache;
|
|
37534
37967
|
const apiKey = opts?.apiKey ?? readDevinApiKey();
|
|
37535
37968
|
if (!apiKey)
|
|
@@ -37547,7 +37980,7 @@ async function getServedDevinModels(opts) {
|
|
|
37547
37980
|
log("[Devin] entitlement unknown \u2014 using the full config list (superset)");
|
|
37548
37981
|
}
|
|
37549
37982
|
rosterCache = served;
|
|
37550
|
-
rosterCacheAt =
|
|
37983
|
+
rosterCacheAt = now2;
|
|
37551
37984
|
return served;
|
|
37552
37985
|
} catch (err) {
|
|
37553
37986
|
log(`[Devin] served-model discovery error: ${err}`);
|
|
@@ -37575,12 +38008,12 @@ function nonEmpty(value) {
|
|
|
37575
38008
|
function groupKeyOf(entry) {
|
|
37576
38009
|
return nonEmpty(entry.groupLabel) ?? nonEmpty(entry.family) ?? entry.wireId;
|
|
37577
38010
|
}
|
|
37578
|
-
function offerIsLive(offer,
|
|
38011
|
+
function offerIsLive(offer, now2 = Date.now()) {
|
|
37579
38012
|
if (!offer)
|
|
37580
38013
|
return false;
|
|
37581
38014
|
if (offer.expiresAt === undefined)
|
|
37582
38015
|
return true;
|
|
37583
|
-
return offer.expiresAt * 1000 >
|
|
38016
|
+
return offer.expiresAt * 1000 > now2;
|
|
37584
38017
|
}
|
|
37585
38018
|
|
|
37586
38019
|
// src/providers/model-resolvers/devin.ts
|
|
@@ -37815,6 +38248,9 @@ async function fetchDevinRoster() {
|
|
|
37815
38248
|
return { id: wireId, ...rest };
|
|
37816
38249
|
});
|
|
37817
38250
|
}
|
|
38251
|
+
function isUndeclaredEditorInternal(id) {
|
|
38252
|
+
return id.startsWith("tab_");
|
|
38253
|
+
}
|
|
37818
38254
|
async function fetchAntigravityRoster() {
|
|
37819
38255
|
const { getValidAntigravityAccessToken: getValidAntigravityAccessToken2 } = await Promise.resolve().then(() => (init_antigravity_token(), exports_antigravity_token));
|
|
37820
38256
|
const { setupAntigravityUser: setupAntigravityUser2, getServedAntigravityModels: getServedAntigravityModels2 } = await Promise.resolve().then(() => (init_antigravity_user(), exports_antigravity_user));
|
|
@@ -37822,10 +38258,12 @@ async function fetchAntigravityRoster() {
|
|
|
37822
38258
|
if (!token)
|
|
37823
38259
|
return [];
|
|
37824
38260
|
const { projectId } = await setupAntigravityUser2(token);
|
|
37825
|
-
const { servedIds, meta: meta3 } = await getServedAntigravityModels2(token, projectId);
|
|
37826
|
-
|
|
38261
|
+
const { servedIds, meta: meta3, excludedIds } = await getServedAntigravityModels2(token, projectId);
|
|
38262
|
+
const declaredExcluded = excludedIds ?? new Set;
|
|
38263
|
+
const selectable = servedIds.filter((id) => !declaredExcluded.has(id) && !isUndeclaredEditorInternal(id));
|
|
38264
|
+
return selectable.map((id) => {
|
|
37827
38265
|
const m = meta3[id];
|
|
37828
|
-
return m?.contextWindow ? { id, contextWindow: m.contextWindow } : { id };
|
|
38266
|
+
return m?.contextWindow ? { id, contextWindow: m.contextWindow, ignoreCatalogReleaseDate: true } : { id, ignoreCatalogReleaseDate: true };
|
|
37829
38267
|
});
|
|
37830
38268
|
}
|
|
37831
38269
|
async function fetchOllamaRoster() {
|
|
@@ -38752,13 +39190,6 @@ var init_vision_proxy = __esm(() => {
|
|
|
38752
39190
|
});
|
|
38753
39191
|
|
|
38754
39192
|
// 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
39193
|
function parseModelChain(modelSpec) {
|
|
38763
39194
|
const parts = modelSpec.split(MODEL_CHAIN_SEPARATOR).map((s) => s.trim()).filter(Boolean);
|
|
38764
39195
|
return parts.length > 0 ? parts : [modelSpec];
|
|
@@ -38785,8 +39216,6 @@ function parseModelSpec(modelSpec) {
|
|
|
38785
39216
|
concurrency = Number.parseInt(concurrencyMatch[2], 10);
|
|
38786
39217
|
}
|
|
38787
39218
|
const provider = PROVIDER_SHORTCUTS[providerPart] || providerPart;
|
|
38788
|
-
if (providerPart === "go")
|
|
38789
|
-
warnGoAliasDeprecatedOnce();
|
|
38790
39219
|
return {
|
|
38791
39220
|
provider,
|
|
38792
39221
|
model: modelPart,
|
|
@@ -38800,8 +39229,6 @@ function parseModelSpec(modelSpec) {
|
|
|
38800
39229
|
for (const { prefix, provider, stripPrefix } of LEGACY_PREFIX_PATTERNS) {
|
|
38801
39230
|
if (lowerSpec.startsWith(prefix)) {
|
|
38802
39231
|
const model = stripPrefix ? modelSpec.slice(prefix.length) : modelSpec;
|
|
38803
|
-
if (prefix === "go/")
|
|
38804
|
-
warnGoAliasDeprecatedOnce();
|
|
38805
39232
|
let concurrency;
|
|
38806
39233
|
let modelName = model;
|
|
38807
39234
|
if (LOCAL_PROVIDERS.has(provider)) {
|
|
@@ -38862,7 +39289,7 @@ function getLegacySyntaxWarning(parsed) {
|
|
|
38862
39289
|
return `Deprecation warning: "${parsed.original}" uses legacy prefix syntax.
|
|
38863
39290
|
` + ` Consider using: ${newSyntax}`;
|
|
38864
39291
|
}
|
|
38865
|
-
var PROVIDER_SHORTCUTS,
|
|
39292
|
+
var PROVIDER_SHORTCUTS, LOCAL_PROVIDERS, NATIVE_MODEL_PATTERNS, LEGACY_PREFIX_PATTERNS, MODEL_CHAIN_SEPARATOR = "+";
|
|
38866
39293
|
var init_model_parser = __esm(() => {
|
|
38867
39294
|
init_provider_definitions();
|
|
38868
39295
|
PROVIDER_SHORTCUTS = getShortcuts();
|
|
@@ -39707,9 +40134,9 @@ function showMonthlyBanner() {
|
|
|
39707
40134
|
return;
|
|
39708
40135
|
const profileConfig = loadConfig();
|
|
39709
40136
|
const consent2 = profileConfig.stats;
|
|
39710
|
-
const
|
|
40137
|
+
const now2 = Date.now();
|
|
39711
40138
|
const lastPrompt = consent2?.lastMonthlyPrompt ? new Date(consent2.lastMonthlyPrompt).getTime() : 0;
|
|
39712
|
-
const timeSincePrompt =
|
|
40139
|
+
const timeSincePrompt = now2 - lastPrompt;
|
|
39713
40140
|
const isFirstRun = !consent2?.lastMonthlyPrompt;
|
|
39714
40141
|
const isMonthlyInterval = timeSincePrompt >= MONTHLY_INTERVAL_MS;
|
|
39715
40142
|
if (!isFirstRun && !isMonthlyInterval)
|
|
@@ -39877,7 +40304,7 @@ function statusToErrorType(status) {
|
|
|
39877
40304
|
}
|
|
39878
40305
|
}
|
|
39879
40306
|
function sanitizeErrorMessage(message, maxLength = MAX_ERROR_MESSAGE_LENGTH) {
|
|
39880
|
-
const flattened = String(message ?? "").replace(ANSI_ESCAPE, "").replace(
|
|
40307
|
+
const flattened = String(message ?? "").replace(ANSI_ESCAPE, "").replace(CONTROL_CHARS2, " ").replace(/\s+/g, " ").trim();
|
|
39881
40308
|
if (flattened.length <= maxLength)
|
|
39882
40309
|
return flattened;
|
|
39883
40310
|
return `${flattened.slice(0, maxLength - 1).trimEnd()}\u2026`;
|
|
@@ -39973,10 +40400,10 @@ function ensureAnthropicErrorFormat(status, body) {
|
|
|
39973
40400
|
const errorType = body?.error?.type || body?.type || body?.code;
|
|
39974
40401
|
return wrapAnthropicError(status, String(message), errorType);
|
|
39975
40402
|
}
|
|
39976
|
-
var MAX_ERROR_MESSAGE_LENGTH = 600, ANSI_ESCAPE,
|
|
40403
|
+
var MAX_ERROR_MESSAGE_LENGTH = 600, ANSI_ESCAPE, CONTROL_CHARS2;
|
|
39977
40404
|
var init_anthropic_error = __esm(() => {
|
|
39978
40405
|
ANSI_ESCAPE = /\x1B\[[0-?]*[ -/]*[@-~]|\x1B[@-Z\\-_]/g;
|
|
39979
|
-
|
|
40406
|
+
CONTROL_CHARS2 = /[\x00-\x1F\x7F]/g;
|
|
39980
40407
|
});
|
|
39981
40408
|
|
|
39982
40409
|
// src/handlers/shared/collect-sse-message.ts
|
|
@@ -43199,10 +43626,10 @@ class ComposedHandler {
|
|
|
43199
43626
|
maybePollPlanUsage(adapter) {
|
|
43200
43627
|
if (!adapter.poll)
|
|
43201
43628
|
return;
|
|
43202
|
-
const
|
|
43203
|
-
if (
|
|
43629
|
+
const now2 = Date.now();
|
|
43630
|
+
if (now2 - this.lastPlanPollAt < PLAN_POLL_INTERVAL_MS)
|
|
43204
43631
|
return;
|
|
43205
|
-
this.lastPlanPollAt =
|
|
43632
|
+
this.lastPlanPollAt = now2;
|
|
43206
43633
|
adapter.poll({ modelId: this.bareModelName }).then((plan) => {
|
|
43207
43634
|
if (plan)
|
|
43208
43635
|
this.tokenTracker.setPlanUsage(plan);
|
|
@@ -43354,6 +43781,9 @@ function resolveApiKeyProvenance(envVar, aliases) {
|
|
|
43354
43781
|
effectiveSource = configLayerLabel();
|
|
43355
43782
|
layers[1].isActive = true;
|
|
43356
43783
|
layers[2].isActive = false;
|
|
43784
|
+
} else if (isKeychainHydratedVar(runtimeVar)) {
|
|
43785
|
+
effectiveSource = "macOS Keychain";
|
|
43786
|
+
layers[2].source = `process.env[${runtimeVar}] (from macOS Keychain)`;
|
|
43357
43787
|
} else if (isOpHydratedVar(runtimeVar)) {
|
|
43358
43788
|
effectiveSource = "1Password";
|
|
43359
43789
|
layers[2].source = `process.env[${runtimeVar}] (from 1Password)`;
|
|
@@ -43403,6 +43833,7 @@ function readConfigKey(envVar) {
|
|
|
43403
43833
|
}
|
|
43404
43834
|
var import_dotenv;
|
|
43405
43835
|
var init_api_key_provenance = __esm(() => {
|
|
43836
|
+
init_keychain_source();
|
|
43406
43837
|
init_onepassword();
|
|
43407
43838
|
import_dotenv = __toESM(require_main(), 1);
|
|
43408
43839
|
});
|
|
@@ -44513,16 +44944,15 @@ var init_provider_definitions = __esm(() => {
|
|
|
44513
44944
|
apiKeyDescription: "Antigravity (shared OAuth token)",
|
|
44514
44945
|
apiKeyUrl: "https://antigravity.google/",
|
|
44515
44946
|
oauthLoginSlug: "antigravity",
|
|
44516
|
-
shortcuts: ["ag", "antigravity"
|
|
44947
|
+
shortcuts: ["ag", "antigravity"],
|
|
44517
44948
|
shortestPrefix: "ag",
|
|
44518
44949
|
legacyPrefixes: [
|
|
44519
44950
|
{ prefix: "ag/", stripPrefix: true },
|
|
44520
|
-
{ prefix: "antigravity/", stripPrefix: true }
|
|
44521
|
-
{ prefix: "go/", stripPrefix: true }
|
|
44951
|
+
{ prefix: "antigravity/", stripPrefix: true }
|
|
44522
44952
|
],
|
|
44523
44953
|
modelDiscovery: { path: "", format: "antigravity" },
|
|
44524
44954
|
isDirectApi: true,
|
|
44525
|
-
description: "Antigravity subscription (ag
|
|
44955
|
+
description: "Antigravity subscription (ag@)"
|
|
44526
44956
|
},
|
|
44527
44957
|
{
|
|
44528
44958
|
createHandler: devinHandler,
|
|
@@ -45138,7 +45568,7 @@ var init_provider_definitions = __esm(() => {
|
|
|
45138
45568
|
legacyPrefixes: [{ prefix: "qp/", stripPrefix: true }],
|
|
45139
45569
|
modelDiscovery: { path: "/compatible-mode/v1/models", format: "openai-models-list" },
|
|
45140
45570
|
isDirectApi: true,
|
|
45141
|
-
description: "Alibaba Model Studio pay-as-you-go (qp@)"
|
|
45571
|
+
description: "Alibaba Model Studio API, pay-as-you-go (qp@)"
|
|
45142
45572
|
},
|
|
45143
45573
|
{
|
|
45144
45574
|
createHandler: openaiHandler,
|
|
@@ -46068,10 +46498,10 @@ var init_predefined_catalog = __esm(() => {
|
|
|
46068
46498
|
});
|
|
46069
46499
|
|
|
46070
46500
|
// src/providers/predefined-endpoints.ts
|
|
46071
|
-
function
|
|
46072
|
-
if (
|
|
46501
|
+
function warnOnce3(message) {
|
|
46502
|
+
if (warnedMessages3.has(message))
|
|
46073
46503
|
return;
|
|
46074
|
-
|
|
46504
|
+
warnedMessages3.add(message);
|
|
46075
46505
|
console.error(message);
|
|
46076
46506
|
}
|
|
46077
46507
|
function activeCatalog() {
|
|
@@ -46088,7 +46518,7 @@ function readOptOut(config2) {
|
|
|
46088
46518
|
if (result.success) {
|
|
46089
46519
|
parsed = result.data;
|
|
46090
46520
|
} else {
|
|
46091
|
-
|
|
46521
|
+
warnOnce3("[claudish] config 'predefinedEndpoints' is not valid and was ignored: " + result.error.issues.map((i) => `${i.path.join(".") || "(root)"} ${i.message}`).join(", "));
|
|
46092
46522
|
}
|
|
46093
46523
|
}
|
|
46094
46524
|
return {
|
|
@@ -46135,7 +46565,7 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46135
46565
|
const noteStale = (entry, name, reason) => {
|
|
46136
46566
|
if (!ownRegistrations.has(name) || !runtime.has(entry.name))
|
|
46137
46567
|
return;
|
|
46138
|
-
|
|
46568
|
+
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
46569
|
};
|
|
46140
46570
|
if (optOut.disabled) {
|
|
46141
46571
|
for (const entry of catalog) {
|
|
@@ -46155,7 +46585,7 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46155
46585
|
noteStale(entry, name, reason);
|
|
46156
46586
|
};
|
|
46157
46587
|
if (seen.has(name)) {
|
|
46158
|
-
|
|
46588
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' appears more than once in the bundled ` + "catalog. The first row wins; the later one is ignored.");
|
|
46159
46589
|
skip("duplicate row");
|
|
46160
46590
|
continue;
|
|
46161
46591
|
}
|
|
@@ -46163,19 +46593,19 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46163
46593
|
const owner = reserved.get(name);
|
|
46164
46594
|
if (owner) {
|
|
46165
46595
|
const reason = `'${entry.name}' is already claimed by builtin provider '${owner}' ` + "(as its name, a shortcut, or a legacy prefix)";
|
|
46166
|
-
|
|
46596
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' skipped: ${reason}. ` + "The builtin wins; the bundled entry is inactive.");
|
|
46167
46597
|
recordEndpointUnavailable(entry.name, `bundled endpoint was skipped because ${reason}`);
|
|
46168
46598
|
skip("collides with builtin");
|
|
46169
46599
|
continue;
|
|
46170
46600
|
}
|
|
46171
46601
|
if (runtime.has(entry.name) && !ownRegistrations.has(name)) {
|
|
46172
|
-
|
|
46602
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' skipped: a provider named ` + `'${entry.name}' is already registered for this process.`);
|
|
46173
46603
|
skip("already registered");
|
|
46174
46604
|
continue;
|
|
46175
46605
|
}
|
|
46176
46606
|
if (userEndpoints.has(name)) {
|
|
46177
46607
|
if (hasLocalApiKey({ envVar: entry.apiKeyEnvVar })) {
|
|
46178
|
-
|
|
46608
|
+
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
46609
|
}
|
|
46180
46610
|
skipStale("replaced by customEndpoints");
|
|
46181
46611
|
continue;
|
|
@@ -46185,7 +46615,7 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46185
46615
|
continue;
|
|
46186
46616
|
}
|
|
46187
46617
|
const { envVar, aliases } = credentialEnvVars(entry);
|
|
46188
|
-
const permitted = optOut.enable.has(name) || hasLocalApiKey({ envVar, aliases });
|
|
46618
|
+
const permitted = optOut.enable.has(name) || hasLocalApiKey({ envVar, aliases }) || keychainHasAnyOf([envVar, ...aliases ?? []]);
|
|
46189
46619
|
if (!permitted) {
|
|
46190
46620
|
skipStale("no local credential");
|
|
46191
46621
|
continue;
|
|
@@ -46193,7 +46623,7 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46193
46623
|
const resolvedUrl = classifyEndpointBaseUrl(entry.baseUrl, entry.baseUrlEnvVars);
|
|
46194
46624
|
if (!resolvedUrl.ok) {
|
|
46195
46625
|
const detail = describeBadBaseUrlOverride(resolvedUrl, entry.baseUrl);
|
|
46196
|
-
|
|
46626
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' skipped: ${detail}`);
|
|
46197
46627
|
recordEndpointUnavailable(entry.name, detail);
|
|
46198
46628
|
skipStale("invalid base URL override");
|
|
46199
46629
|
continue;
|
|
@@ -46203,14 +46633,15 @@ function loadPredefinedEndpoints(config2, opts = {}) {
|
|
|
46203
46633
|
ownRegistrations.add(name);
|
|
46204
46634
|
result.registered.push(entry.name);
|
|
46205
46635
|
} catch (err) {
|
|
46206
|
-
|
|
46636
|
+
warnOnce3(`[claudish] predefined endpoint '${entry.name}' skipped: ` + `${err instanceof Error ? err.message : String(err)}`);
|
|
46207
46637
|
skip("invalid catalog row");
|
|
46208
46638
|
}
|
|
46209
46639
|
}
|
|
46210
46640
|
return result;
|
|
46211
46641
|
}
|
|
46212
|
-
var KILL_SWITCH_ENV = "CLAUDISH_NO_PREDEFINED_ENDPOINTS",
|
|
46642
|
+
var KILL_SWITCH_ENV = "CLAUDISH_NO_PREDEFINED_ENDPOINTS", warnedMessages3, ownRegistrations, catalogOverride = null;
|
|
46213
46643
|
var init_predefined_endpoints = __esm(() => {
|
|
46644
|
+
init_keychain_source();
|
|
46214
46645
|
init_local_api_key();
|
|
46215
46646
|
init_config_schema();
|
|
46216
46647
|
init_custom_endpoints_loader();
|
|
@@ -46218,7 +46649,7 @@ var init_predefined_endpoints = __esm(() => {
|
|
|
46218
46649
|
init_predefined_catalog();
|
|
46219
46650
|
init_reserved_namespace();
|
|
46220
46651
|
init_runtime_providers();
|
|
46221
|
-
|
|
46652
|
+
warnedMessages3 = new Set;
|
|
46222
46653
|
ownRegistrations = new Set;
|
|
46223
46654
|
});
|
|
46224
46655
|
|
|
@@ -46258,7 +46689,7 @@ function reportCustomEndpoints(result) {
|
|
|
46258
46689
|
logStderr(`customEndpoints['${name}'] failed validation: ${message}`);
|
|
46259
46690
|
}
|
|
46260
46691
|
for (const { name, reason } of result.refused) {
|
|
46261
|
-
|
|
46692
|
+
warnOnce4(`customEndpoints['${name}'] skipped: ${reason}. The builtin wins. ` + `Rename your entry (e.g. '${name}-custom') to use it.`);
|
|
46262
46693
|
}
|
|
46263
46694
|
}
|
|
46264
46695
|
function warnOnProjectScopedEndpoints() {
|
|
@@ -46267,26 +46698,26 @@ function warnOnProjectScopedEndpoints() {
|
|
|
46267
46698
|
const names = Object.keys(local?.customEndpoints ?? {});
|
|
46268
46699
|
if (names.length === 0)
|
|
46269
46700
|
return;
|
|
46270
|
-
|
|
46701
|
+
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
46702
|
} catch {}
|
|
46272
46703
|
}
|
|
46273
|
-
function
|
|
46274
|
-
if (
|
|
46704
|
+
function warnOnce4(message) {
|
|
46705
|
+
if (warnedMessages4.has(message))
|
|
46275
46706
|
return;
|
|
46276
|
-
|
|
46707
|
+
warnedMessages4.add(message);
|
|
46277
46708
|
logStderr(message);
|
|
46278
46709
|
}
|
|
46279
46710
|
function invalidateEndpointRegistration() {
|
|
46280
46711
|
registered = false;
|
|
46281
46712
|
}
|
|
46282
|
-
var registered = false, lastCustomResult,
|
|
46713
|
+
var registered = false, lastCustomResult, warnedMessages4;
|
|
46283
46714
|
var init_endpoint_registration = __esm(() => {
|
|
46284
46715
|
init_logger();
|
|
46285
46716
|
init_profile_config();
|
|
46286
46717
|
init_custom_endpoints_loader();
|
|
46287
46718
|
init_predefined_endpoints();
|
|
46288
46719
|
lastCustomResult = { registered: 0, errors: [], refused: [] };
|
|
46289
|
-
|
|
46720
|
+
warnedMessages4 = new Set;
|
|
46290
46721
|
});
|
|
46291
46722
|
|
|
46292
46723
|
// src/providers/provider-registry.ts
|
|
@@ -48045,8 +48476,8 @@ function readProjectCwd(dirName) {
|
|
|
48045
48476
|
}
|
|
48046
48477
|
return null;
|
|
48047
48478
|
}
|
|
48048
|
-
function isActive(row,
|
|
48049
|
-
return
|
|
48479
|
+
function isActive(row, now2 = Date.now()) {
|
|
48480
|
+
return now2 - row.mtimeMs < ACTIVE_WINDOW_MS;
|
|
48050
48481
|
}
|
|
48051
48482
|
function discoverWorktreeGroups(repo) {
|
|
48052
48483
|
const rootSlug = slugForPath(repo.root);
|
|
@@ -48661,9 +49092,9 @@ function setupSession(sessionPath, models, input) {
|
|
|
48661
49092
|
}
|
|
48662
49093
|
const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
|
|
48663
49094
|
const shuffled = fisherYatesShuffle([...ids]);
|
|
48664
|
-
const
|
|
49095
|
+
const now2 = new Date().toISOString();
|
|
48665
49096
|
const manifest = {
|
|
48666
|
-
created:
|
|
49097
|
+
created: now2,
|
|
48667
49098
|
models: {},
|
|
48668
49099
|
shuffleOrder: shuffled
|
|
48669
49100
|
};
|
|
@@ -48671,13 +49102,13 @@ function setupSession(sessionPath, models, input) {
|
|
|
48671
49102
|
const anonId = shuffled[i];
|
|
48672
49103
|
manifest.models[anonId] = {
|
|
48673
49104
|
model: models[i],
|
|
48674
|
-
assignedAt:
|
|
49105
|
+
assignedAt: now2
|
|
48675
49106
|
};
|
|
48676
49107
|
mkdirSync11(join28(sessionPath, "work", anonId), { recursive: true });
|
|
48677
49108
|
}
|
|
48678
49109
|
writeFileSync11(join28(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
48679
49110
|
const status = {
|
|
48680
|
-
startedAt:
|
|
49111
|
+
startedAt: now2,
|
|
48681
49112
|
models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
|
|
48682
49113
|
id,
|
|
48683
49114
|
{
|
|
@@ -48958,9 +49389,9 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
48958
49389
|
return Math.max(0, Date.now() - s.updated_at);
|
|
48959
49390
|
};
|
|
48960
49391
|
const graceStartedAt = new Map;
|
|
48961
|
-
const graceUsedMs = (id,
|
|
49392
|
+
const graceUsedMs = (id, now2) => {
|
|
48962
49393
|
const start = graceStartedAt.get(id);
|
|
48963
|
-
return start === undefined ? 0 : Math.max(0,
|
|
49394
|
+
return start === undefined ? 0 : Math.max(0, now2 - start);
|
|
48964
49395
|
};
|
|
48965
49396
|
const runningIds = () => [...processes.keys()].filter((id) => statusCache.models[id]?.state === "RUNNING");
|
|
48966
49397
|
const timeoutModel = async (id, why) => {
|
|
@@ -49013,10 +49444,10 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49013
49444
|
if (running.length === 0)
|
|
49014
49445
|
return;
|
|
49015
49446
|
const extended = [];
|
|
49016
|
-
const
|
|
49447
|
+
const now2 = Date.now();
|
|
49017
49448
|
for (const id of running) {
|
|
49018
49449
|
const idleMs = idleMsFor(id);
|
|
49019
|
-
const usedGrace = graceUsedMs(id,
|
|
49450
|
+
const usedGrace = graceUsedMs(id, now2);
|
|
49020
49451
|
if (!graceEnabled) {
|
|
49021
49452
|
await timeoutModel(id, "deadline reached (grace extension disabled)");
|
|
49022
49453
|
} else if (usedGrace >= maxGraceMs) {
|
|
@@ -49027,7 +49458,7 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49027
49458
|
await timeoutModel(id, `no measurable progress for ${Math.round(idleMs / 1000)}s`);
|
|
49028
49459
|
} else {
|
|
49029
49460
|
if (!graceStartedAt.has(id))
|
|
49030
|
-
graceStartedAt.set(id,
|
|
49461
|
+
graceStartedAt.set(id, now2);
|
|
49031
49462
|
extended.push(id);
|
|
49032
49463
|
}
|
|
49033
49464
|
}
|
|
@@ -50269,6 +50700,9 @@ function extractVersionParts(modelId) {
|
|
|
50269
50700
|
break;
|
|
50270
50701
|
continue;
|
|
50271
50702
|
}
|
|
50703
|
+
if (!started && /^\d+b$/.test(token) && Number.parseInt(match[0], 10) > 10) {
|
|
50704
|
+
continue;
|
|
50705
|
+
}
|
|
50272
50706
|
if (!started) {
|
|
50273
50707
|
started = true;
|
|
50274
50708
|
for (const part of match[0].split(".")) {
|
|
@@ -54277,8 +54711,8 @@ class OpenRouterRequestQueue {
|
|
|
54277
54711
|
}
|
|
54278
54712
|
}
|
|
54279
54713
|
async waitForNextSlot() {
|
|
54280
|
-
const
|
|
54281
|
-
const timeSinceLastRequest =
|
|
54714
|
+
const now2 = Date.now();
|
|
54715
|
+
const timeSinceLastRequest = now2 - this.rateLimitState.lastRequestTime;
|
|
54282
54716
|
const delayMs = this.calculateDelay();
|
|
54283
54717
|
this.rateLimitState.currentDelayMs = delayMs;
|
|
54284
54718
|
if (timeSinceLastRequest < delayMs) {
|
|
@@ -54306,8 +54740,8 @@ class OpenRouterRequestQueue {
|
|
|
54306
54740
|
}
|
|
54307
54741
|
}
|
|
54308
54742
|
if (this.rateLimitState.resetTime !== null && this.rateLimitState.remainingRequests !== null) {
|
|
54309
|
-
const
|
|
54310
|
-
const timeUntilReset = this.rateLimitState.resetTime -
|
|
54743
|
+
const now2 = Date.now() / 1000;
|
|
54744
|
+
const timeUntilReset = this.rateLimitState.resetTime - now2;
|
|
54311
54745
|
if (timeUntilReset > 0 && this.rateLimitState.remainingRequests > 0) {
|
|
54312
54746
|
const optimalDelay = timeUntilReset * 1000 / Math.max(this.rateLimitState.remainingRequests, 1);
|
|
54313
54747
|
delayMs = Math.max(delayMs, Math.min(optimalDelay, this.maxDelayMs));
|
|
@@ -56491,11 +56925,15 @@ __export(exports_theme_mode, {
|
|
|
56491
56925
|
classifyOscBackground: () => classifyOscBackground,
|
|
56492
56926
|
detectAndSetThemeMode: () => detectAndSetThemeMode,
|
|
56493
56927
|
detectAndSetThemeModeSync: () => detectAndSetThemeModeSync,
|
|
56928
|
+
getTerminalBackground: () => getTerminalBackground,
|
|
56929
|
+
getTerminalBackgroundHex: () => getTerminalBackgroundHex,
|
|
56494
56930
|
getThemeMode: () => getThemeMode,
|
|
56495
56931
|
onThemeModeChange: () => onThemeModeChange,
|
|
56932
|
+
parseOscBackgroundHex: () => parseOscBackgroundHex,
|
|
56496
56933
|
queryTerminalThemeMode: () => queryTerminalThemeMode,
|
|
56497
56934
|
relativeLuminance: () => relativeLuminance,
|
|
56498
56935
|
resetThemeModeForTests: () => resetThemeModeForTests,
|
|
56936
|
+
setTerminalBackgroundHex: () => setTerminalBackgroundHex,
|
|
56499
56937
|
setThemeMode: () => setThemeMode,
|
|
56500
56938
|
themeModeFromColorFgBg: () => themeModeFromColorFgBg,
|
|
56501
56939
|
themeModeOverride: () => themeModeOverride
|
|
@@ -56514,6 +56952,7 @@ function onThemeModeChange(cb) {
|
|
|
56514
56952
|
}
|
|
56515
56953
|
function resetThemeModeForTests() {
|
|
56516
56954
|
setThemeMode(null);
|
|
56955
|
+
background = null;
|
|
56517
56956
|
}
|
|
56518
56957
|
function themeModeOverride(env = process.env) {
|
|
56519
56958
|
const raw2 = env.CLAUDISH_THEME?.trim().toLowerCase();
|
|
@@ -56550,6 +56989,31 @@ function classifyOscBackground(reply) {
|
|
|
56550
56989
|
const lum = relativeLuminance(channel(m[1]), channel(m[2]), channel(m[3]));
|
|
56551
56990
|
return lum >= MID_SRGB_LUMINANCE ? "light" : "dark";
|
|
56552
56991
|
}
|
|
56992
|
+
function parseOscBackgroundHex(reply) {
|
|
56993
|
+
const m = reply.match(/\]11;rgb:([0-9a-fA-F]{1,4})\/([0-9a-fA-F]{1,4})\/([0-9a-fA-F]{1,4})/);
|
|
56994
|
+
if (!m)
|
|
56995
|
+
return null;
|
|
56996
|
+
const byte = (hex3) => {
|
|
56997
|
+
const max = 16 ** hex3.length - 1;
|
|
56998
|
+
const v = Math.round(Number.parseInt(hex3, 16) / max * 255);
|
|
56999
|
+
return v.toString(16).padStart(2, "0");
|
|
57000
|
+
};
|
|
57001
|
+
return `#${byte(m[1])}${byte(m[2])}${byte(m[3])}`;
|
|
57002
|
+
}
|
|
57003
|
+
function getTerminalBackgroundHex() {
|
|
57004
|
+
return background?.hex ?? null;
|
|
57005
|
+
}
|
|
57006
|
+
function getTerminalBackground() {
|
|
57007
|
+
return background;
|
|
57008
|
+
}
|
|
57009
|
+
function setTerminalBackgroundHex(hex3) {
|
|
57010
|
+
if (!hex3) {
|
|
57011
|
+
background = null;
|
|
57012
|
+
return;
|
|
57013
|
+
}
|
|
57014
|
+
const mode = classifyOscBackground(`]11;rgb:${hex3.slice(1, 3)}/${hex3.slice(3, 5)}/${hex3.slice(5, 7)}`);
|
|
57015
|
+
background = mode ? { hex: hex3, mode } : null;
|
|
57016
|
+
}
|
|
56553
57017
|
async function queryTerminalThemeMode(timeoutMs = 150) {
|
|
56554
57018
|
const stdin = process.stdin;
|
|
56555
57019
|
const stdout = process.stdout;
|
|
@@ -56577,7 +57041,10 @@ async function queryTerminalThemeMode(timeoutMs = 150) {
|
|
|
56577
57041
|
const onData = (chunk) => {
|
|
56578
57042
|
buffer += chunk.toString("latin1");
|
|
56579
57043
|
if (/\]11;[^\x07\x1b]*(\x07|\x1b\\)/.test(buffer)) {
|
|
56580
|
-
|
|
57044
|
+
const mode = classifyOscBackground(buffer);
|
|
57045
|
+
const hex3 = parseOscBackgroundHex(buffer);
|
|
57046
|
+
background = hex3 && mode ? { hex: hex3, mode } : null;
|
|
57047
|
+
finish(mode);
|
|
56581
57048
|
}
|
|
56582
57049
|
};
|
|
56583
57050
|
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
@@ -56595,17 +57062,18 @@ async function queryTerminalThemeMode(timeoutMs = 150) {
|
|
|
56595
57062
|
async function detectAndSetThemeMode() {
|
|
56596
57063
|
const override = themeModeOverride();
|
|
56597
57064
|
if (override) {
|
|
57065
|
+
setTerminalBackgroundHex(null);
|
|
56598
57066
|
setThemeMode(override);
|
|
56599
57067
|
return override;
|
|
56600
57068
|
}
|
|
56601
|
-
const
|
|
56602
|
-
if (
|
|
56603
|
-
setThemeMode(
|
|
56604
|
-
return
|
|
57069
|
+
const fromOsc = await queryTerminalThemeMode(150);
|
|
57070
|
+
if (fromOsc) {
|
|
57071
|
+
setThemeMode(fromOsc);
|
|
57072
|
+
return fromOsc;
|
|
56605
57073
|
}
|
|
56606
|
-
const
|
|
56607
|
-
setThemeMode(
|
|
56608
|
-
return
|
|
57074
|
+
const fromEnv = themeModeFromColorFgBg();
|
|
57075
|
+
setThemeMode(fromEnv);
|
|
57076
|
+
return fromEnv;
|
|
56609
57077
|
}
|
|
56610
57078
|
function detectAndSetThemeModeSync() {
|
|
56611
57079
|
const mode = themeModeOverride() ?? themeModeFromColorFgBg();
|
|
@@ -56613,7 +57081,7 @@ function detectAndSetThemeModeSync() {
|
|
|
56613
57081
|
setThemeMode(mode);
|
|
56614
57082
|
return mode ?? detected;
|
|
56615
57083
|
}
|
|
56616
|
-
var detected = null, listeners, MID_SRGB_LUMINANCE;
|
|
57084
|
+
var detected = null, listeners, MID_SRGB_LUMINANCE, background = null;
|
|
56617
57085
|
var init_theme_mode = __esm(() => {
|
|
56618
57086
|
listeners = [];
|
|
56619
57087
|
MID_SRGB_LUMINANCE = relativeLuminance(0.5, 0.5, 0.5);
|
|
@@ -57352,8 +57820,6 @@ function describeSourceSync(p, config3) {
|
|
|
57352
57820
|
return "env";
|
|
57353
57821
|
if (hasCfg)
|
|
57354
57822
|
return "cfg";
|
|
57355
|
-
if (p.publicKeyFallback)
|
|
57356
|
-
return "public";
|
|
57357
57823
|
return null;
|
|
57358
57824
|
}
|
|
57359
57825
|
async function describeSource(p, config3) {
|
|
@@ -57394,7 +57860,6 @@ function toProviderDef(def) {
|
|
|
57394
57860
|
defaultEndpoint: def.baseUrl || undefined,
|
|
57395
57861
|
aliases: def.apiKeyAliases,
|
|
57396
57862
|
isLocal: def.isLocal,
|
|
57397
|
-
publicKeyFallback: !!def.publicKeyFallback,
|
|
57398
57863
|
oauthSlug: def.oauthLoginSlug
|
|
57399
57864
|
};
|
|
57400
57865
|
}
|
|
@@ -68585,7 +69050,7 @@ var require_lib3 = __commonJS(function(exports, module) {
|
|
|
68585
69050
|
var trail = encoder.end();
|
|
68586
69051
|
return trail && trail.length > 0 ? Buffer2.concat([res, trail]) : res;
|
|
68587
69052
|
};
|
|
68588
|
-
iconv.decode = function
|
|
69053
|
+
iconv.decode = function decode4(buf, encoding, options) {
|
|
68589
69054
|
if (typeof buf === "string") {
|
|
68590
69055
|
if (!iconv.skipDecodeWarning) {
|
|
68591
69056
|
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 +70306,420 @@ var init_dist16 = __esm(() => {
|
|
|
69841
70306
|
init_dist15();
|
|
69842
70307
|
});
|
|
69843
70308
|
|
|
70309
|
+
// src/keychain-command.ts
|
|
70310
|
+
var exports_keychain_command = {};
|
|
70311
|
+
__export(exports_keychain_command, {
|
|
70312
|
+
keychainCommand: () => keychainCommand
|
|
70313
|
+
});
|
|
70314
|
+
function ok(text) {
|
|
70315
|
+
const c = cliAnsi();
|
|
70316
|
+
return `${c.GREEN}${text}${c.RESET}`;
|
|
70317
|
+
}
|
|
70318
|
+
function warn(text) {
|
|
70319
|
+
const c = cliAnsi();
|
|
70320
|
+
return `${c.YELLOW}${text}${c.RESET}`;
|
|
70321
|
+
}
|
|
70322
|
+
function bad(text) {
|
|
70323
|
+
const c = cliAnsi();
|
|
70324
|
+
return `${c.RED}${text}${c.RESET}`;
|
|
70325
|
+
}
|
|
70326
|
+
function dim3(text) {
|
|
70327
|
+
const c = cliAnsi();
|
|
70328
|
+
return `${c.GRAY}${text}${c.RESET}`;
|
|
70329
|
+
}
|
|
70330
|
+
function strong(text) {
|
|
70331
|
+
const c = cliAnsi();
|
|
70332
|
+
return `${c.BOLD}${text}${c.RESET}`;
|
|
70333
|
+
}
|
|
70334
|
+
function requireKeychain() {
|
|
70335
|
+
const reason = keychainUnavailableReason();
|
|
70336
|
+
if (!reason)
|
|
70337
|
+
return true;
|
|
70338
|
+
console.error(bad(`Keychain unavailable: ${reason}`));
|
|
70339
|
+
console.error(dim3("claudish's keychain backend uses the macOS Security framework via /usr/bin/security."));
|
|
70340
|
+
return false;
|
|
70341
|
+
}
|
|
70342
|
+
function catalogEnvVars() {
|
|
70343
|
+
const names = new Set;
|
|
70344
|
+
for (const p of getAllProviders()) {
|
|
70345
|
+
if (p.apiKeyEnvVar)
|
|
70346
|
+
names.add(p.apiKeyEnvVar);
|
|
70347
|
+
for (const alias of p.apiKeyAliases ?? [])
|
|
70348
|
+
names.add(alias);
|
|
70349
|
+
}
|
|
70350
|
+
return Array.from(names).sort();
|
|
70351
|
+
}
|
|
70352
|
+
function keychainStatus() {
|
|
70353
|
+
const supported = isKeychainSupported();
|
|
70354
|
+
const enabled2 = isKeychainEnabled();
|
|
70355
|
+
console.log(strong("macOS Keychain backend"));
|
|
70356
|
+
console.log(` platform ${supported ? ok("supported") : bad(`unsupported (${process.platform})`)}`);
|
|
70357
|
+
console.log(` backend ${enabled2 ? ok("enabled") : dim3("disabled")}`);
|
|
70358
|
+
console.log(` service ${dim3(KEYCHAIN_SERVICE)}`);
|
|
70359
|
+
if (!supported)
|
|
70360
|
+
return;
|
|
70361
|
+
const listed = enumerateKeychainVars();
|
|
70362
|
+
if (listed.failed) {
|
|
70363
|
+
console.log(` stored keys ${bad("could not read the keychain")}`);
|
|
70364
|
+
console.log();
|
|
70365
|
+
console.log(bad(listed.error ?? "unknown error"));
|
|
70366
|
+
console.log(dim3("The keychain may be locked, or access may have been denied."));
|
|
70367
|
+
process.exitCode = 1;
|
|
70368
|
+
return;
|
|
70369
|
+
}
|
|
70370
|
+
const stored = listed.names;
|
|
70371
|
+
console.log(` stored keys ${stored.length > 0 ? ok(String(stored.length)) : dim3("0")}`);
|
|
70372
|
+
if (!enabled2 && stored.length > 0) {
|
|
70373
|
+
console.log();
|
|
70374
|
+
console.log(warn(`${stored.length} key(s) are in the keychain but the backend is disabled, so claudish will not read them.`));
|
|
70375
|
+
console.log(dim3(" Enable with: claudish keychain enable"));
|
|
70376
|
+
}
|
|
70377
|
+
if (enabled2 && stored.length === 0) {
|
|
70378
|
+
console.log();
|
|
70379
|
+
console.log(dim3("Nothing stored yet. Copy your existing keys in with:"));
|
|
70380
|
+
console.log(dim3(" claudish keychain import"));
|
|
70381
|
+
}
|
|
70382
|
+
console.log();
|
|
70383
|
+
console.log(dim3("Resolution order: env var \u2192 alias \u2192 config.json \u2192 macOS Keychain \u2192 1Password"));
|
|
70384
|
+
}
|
|
70385
|
+
function keychainList() {
|
|
70386
|
+
if (!requireKeychain())
|
|
70387
|
+
return;
|
|
70388
|
+
const listed = enumerateKeychainVars();
|
|
70389
|
+
if (listed.failed) {
|
|
70390
|
+
console.error(bad(`Could not read the keychain: ${listed.error ?? "unknown error"}`));
|
|
70391
|
+
console.error(dim3("The keychain may be locked, or access may have been denied."));
|
|
70392
|
+
process.exitCode = 1;
|
|
70393
|
+
return;
|
|
70394
|
+
}
|
|
70395
|
+
const stored = listed.names;
|
|
70396
|
+
if (stored.length === 0) {
|
|
70397
|
+
console.log(dim3("No keys stored in the keychain."));
|
|
70398
|
+
console.log(dim3("Copy your existing keys in with: claudish keychain import"));
|
|
70399
|
+
return;
|
|
70400
|
+
}
|
|
70401
|
+
const width = Math.max(...stored.map((n) => n.length));
|
|
70402
|
+
for (const name of stored) {
|
|
70403
|
+
let tail;
|
|
70404
|
+
try {
|
|
70405
|
+
const value = readKeychainSecret(name);
|
|
70406
|
+
tail = value ? dim3(valueTail2(value)) : bad("unreadable");
|
|
70407
|
+
} catch (err) {
|
|
70408
|
+
tail = bad(err instanceof KeychainError ? "denied" : "error");
|
|
70409
|
+
}
|
|
70410
|
+
const shadowed = process.env[name] ? warn(" (shadowed by an env var)") : "";
|
|
70411
|
+
console.log(` ${name.padEnd(width)} ${tail}${shadowed}`);
|
|
70412
|
+
}
|
|
70413
|
+
if (!isKeychainEnabled()) {
|
|
70414
|
+
console.log();
|
|
70415
|
+
console.log(warn("The keychain backend is disabled \u2014 claudish will not read these."));
|
|
70416
|
+
console.log(dim3(" Enable with: claudish keychain enable"));
|
|
70417
|
+
}
|
|
70418
|
+
}
|
|
70419
|
+
async function collectImportPlan(opts) {
|
|
70420
|
+
const wanted = opts.only ?? catalogEnvVars();
|
|
70421
|
+
const listed = enumerateKeychainVars();
|
|
70422
|
+
if (listed.failed) {
|
|
70423
|
+
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.");
|
|
70424
|
+
}
|
|
70425
|
+
const stored = new Set(listed.names);
|
|
70426
|
+
const plan = new Map;
|
|
70427
|
+
const classify = (envVar, value, origin) => {
|
|
70428
|
+
const problem = describeUnstorableValue(value) ?? undefined;
|
|
70429
|
+
let action = stored.has(envVar) ? "overwrite" : "new";
|
|
70430
|
+
if (action === "overwrite") {
|
|
70431
|
+
try {
|
|
70432
|
+
if (readKeychainSecret(envVar) === value)
|
|
70433
|
+
action = "unchanged";
|
|
70434
|
+
} catch {}
|
|
70435
|
+
}
|
|
70436
|
+
plan.set(envVar, { envVar, value, origin, action, problem });
|
|
70437
|
+
};
|
|
70438
|
+
if (opts.from === "env" || opts.from === "all") {
|
|
70439
|
+
for (const envVar of wanted) {
|
|
70440
|
+
const value = process.env[envVar];
|
|
70441
|
+
if (value)
|
|
70442
|
+
classify(envVar, value, "environment");
|
|
70443
|
+
}
|
|
70444
|
+
}
|
|
70445
|
+
if ((opts.from === "1password" || opts.from === "all") && hasOpSources()) {
|
|
70446
|
+
const missing = wanted.filter((n) => !plan.has(n));
|
|
70447
|
+
if (missing.length > 0) {
|
|
70448
|
+
const resolved = await resolveOpKeyForEnvVars(new Set(missing), {
|
|
70449
|
+
onAuthFailure: "throw",
|
|
70450
|
+
allowPrompt: true
|
|
70451
|
+
});
|
|
70452
|
+
for (const [envVar, value] of Object.entries(resolved)) {
|
|
70453
|
+
if (value)
|
|
70454
|
+
classify(envVar, value, "1Password");
|
|
70455
|
+
}
|
|
70456
|
+
}
|
|
70457
|
+
}
|
|
70458
|
+
return Array.from(plan.values()).sort((a, b) => a.envVar.localeCompare(b.envVar));
|
|
70459
|
+
}
|
|
70460
|
+
function renderPlan(plan) {
|
|
70461
|
+
const width = Math.max(...plan.map((e) => e.envVar.length));
|
|
70462
|
+
for (const e of plan) {
|
|
70463
|
+
if (e.problem) {
|
|
70464
|
+
console.log(` ${bad("skip")} ${e.envVar.padEnd(width)} ${bad(e.problem)}`);
|
|
70465
|
+
continue;
|
|
70466
|
+
}
|
|
70467
|
+
const label = e.action === "new" ? ok("new") : e.action === "overwrite" ? warn("overwrite") : dim3("unchanged");
|
|
70468
|
+
const pad = " ".repeat(Math.max(0, 10 - (e.action === "new" ? 3 : e.action.length)));
|
|
70469
|
+
console.log(` ${label}${pad} ${e.envVar.padEnd(width)} ${dim3(valueTail2(e.value))} ${dim3(`from ${e.origin}`)}`);
|
|
70470
|
+
}
|
|
70471
|
+
}
|
|
70472
|
+
function writeImportEntries(entries) {
|
|
70473
|
+
let written = 0;
|
|
70474
|
+
const failures = [];
|
|
70475
|
+
for (const entry of entries) {
|
|
70476
|
+
try {
|
|
70477
|
+
writeKeychainSecret(entry.envVar, entry.value);
|
|
70478
|
+
written++;
|
|
70479
|
+
} catch (err) {
|
|
70480
|
+
failures.push(`${entry.envVar}: ${err instanceof Error ? err.message : String(err)}`);
|
|
70481
|
+
}
|
|
70482
|
+
}
|
|
70483
|
+
return { written, failures };
|
|
70484
|
+
}
|
|
70485
|
+
function reportImportResult(written, failures) {
|
|
70486
|
+
if (written > 0 && !isKeychainEnabled()) {
|
|
70487
|
+
setKeychainEnabled(true);
|
|
70488
|
+
console.log(ok("Keychain backend enabled."));
|
|
70489
|
+
}
|
|
70490
|
+
console.log(ok(`Stored ${written} key(s) in the keychain.`));
|
|
70491
|
+
if (failures.length > 0) {
|
|
70492
|
+
console.error(bad(`${failures.length} key(s) failed:`));
|
|
70493
|
+
for (const f of failures)
|
|
70494
|
+
console.error(` ${f}`);
|
|
70495
|
+
process.exitCode = 1;
|
|
70496
|
+
}
|
|
70497
|
+
}
|
|
70498
|
+
async function keychainImport(opts) {
|
|
70499
|
+
if (!requireKeychain())
|
|
70500
|
+
return;
|
|
70501
|
+
let plan;
|
|
70502
|
+
try {
|
|
70503
|
+
plan = await collectImportPlan(opts);
|
|
70504
|
+
} catch (err) {
|
|
70505
|
+
console.error(bad(`Could not build the import plan: ${err instanceof Error ? err.message : String(err)}`));
|
|
70506
|
+
process.exitCode = 1;
|
|
70507
|
+
return;
|
|
70508
|
+
}
|
|
70509
|
+
if (plan.length === 0) {
|
|
70510
|
+
console.log(dim3("Nothing to import \u2014 no matching keys found in the requested sources."));
|
|
70511
|
+
if (opts.from === "1password" && !hasOpSources()) {
|
|
70512
|
+
console.log(dim3("No 1Password source is configured. See: claudish config \u2192 1Password tab"));
|
|
70513
|
+
}
|
|
70514
|
+
return;
|
|
70515
|
+
}
|
|
70516
|
+
const writable = plan.filter((e) => !e.problem && e.action !== "unchanged");
|
|
70517
|
+
const overwrites = writable.filter((e) => e.action === "overwrite");
|
|
70518
|
+
console.log(strong(`Import plan \u2014 ${plan.length} key(s) considered`));
|
|
70519
|
+
renderPlan(plan);
|
|
70520
|
+
console.log();
|
|
70521
|
+
if (writable.length === 0) {
|
|
70522
|
+
console.log(dim3("Everything is already stored with the same value. Nothing to do."));
|
|
70523
|
+
return;
|
|
70524
|
+
}
|
|
70525
|
+
if (overwrites.length > 0) {
|
|
70526
|
+
console.log(warn(`${overwrites.length} existing keychain item(s) will be REPLACED. The previous values cannot be recovered.`));
|
|
70527
|
+
}
|
|
70528
|
+
if (opts.dryRun) {
|
|
70529
|
+
console.log(dim3("--dry-run: nothing was written."));
|
|
70530
|
+
return;
|
|
70531
|
+
}
|
|
70532
|
+
if (!opts.yes) {
|
|
70533
|
+
const { confirm } = await Promise.resolve().then(() => (init_dist16(), exports_dist));
|
|
70534
|
+
const proceed = await confirm({
|
|
70535
|
+
message: `Store ${writable.length} key(s) in the macOS Keychain?`,
|
|
70536
|
+
default: overwrites.length === 0
|
|
70537
|
+
});
|
|
70538
|
+
if (!proceed) {
|
|
70539
|
+
console.log(dim3("Cancelled \u2014 nothing was written."));
|
|
70540
|
+
return;
|
|
70541
|
+
}
|
|
70542
|
+
}
|
|
70543
|
+
const { written, failures } = writeImportEntries(writable);
|
|
70544
|
+
reportImportResult(written, failures);
|
|
70545
|
+
const skipped = plan.filter((e) => e.problem);
|
|
70546
|
+
if (skipped.length > 0) {
|
|
70547
|
+
console.log(warn(`${skipped.length} key(s) skipped \u2014 see the plan above.`));
|
|
70548
|
+
}
|
|
70549
|
+
}
|
|
70550
|
+
async function readSecretInteractively(envVar) {
|
|
70551
|
+
if (!process.stdin.isTTY) {
|
|
70552
|
+
const piped = await new Response(Bun.stdin.stream()).text();
|
|
70553
|
+
const value2 = piped.replace(/\r?\n$/, "");
|
|
70554
|
+
return value2.length > 0 ? value2 : null;
|
|
70555
|
+
}
|
|
70556
|
+
const { password } = await Promise.resolve().then(() => (init_dist16(), exports_dist));
|
|
70557
|
+
const value = await password({ message: `Value for ${envVar}:`, mask: "\u2022" });
|
|
70558
|
+
return value.length > 0 ? value : null;
|
|
70559
|
+
}
|
|
70560
|
+
async function keychainSet(envVar) {
|
|
70561
|
+
if (!requireKeychain())
|
|
70562
|
+
return;
|
|
70563
|
+
if (!envVar) {
|
|
70564
|
+
console.error(bad("Usage: claudish keychain set <ENV_VAR>"));
|
|
70565
|
+
process.exitCode = 1;
|
|
70566
|
+
return;
|
|
70567
|
+
}
|
|
70568
|
+
if (!isValidKeychainVarName(envVar)) {
|
|
70569
|
+
console.error(bad(`"${envVar}" is not a valid environment variable name.`));
|
|
70570
|
+
process.exitCode = 1;
|
|
70571
|
+
return;
|
|
70572
|
+
}
|
|
70573
|
+
const value = await readSecretInteractively(envVar);
|
|
70574
|
+
if (!value) {
|
|
70575
|
+
console.log(dim3("Aborted \u2014 no value given."));
|
|
70576
|
+
return;
|
|
70577
|
+
}
|
|
70578
|
+
try {
|
|
70579
|
+
writeKeychainSecret(envVar, value);
|
|
70580
|
+
} catch (err) {
|
|
70581
|
+
console.error(bad(err instanceof Error ? err.message : String(err)));
|
|
70582
|
+
process.exitCode = 1;
|
|
70583
|
+
return;
|
|
70584
|
+
}
|
|
70585
|
+
if (!isKeychainEnabled())
|
|
70586
|
+
setKeychainEnabled(true);
|
|
70587
|
+
console.log(ok(`Stored ${envVar} ${dim3(valueTail2(value))} in the macOS Keychain.`));
|
|
70588
|
+
if (process.env[envVar]) {
|
|
70589
|
+
console.log(warn(`Note: ${envVar} is also set in this shell, and an env var takes precedence at runtime.`));
|
|
70590
|
+
}
|
|
70591
|
+
}
|
|
70592
|
+
function keychainRemove(envVar) {
|
|
70593
|
+
if (!requireKeychain())
|
|
70594
|
+
return;
|
|
70595
|
+
if (!envVar) {
|
|
70596
|
+
console.error(bad("Usage: claudish keychain rm <ENV_VAR>"));
|
|
70597
|
+
process.exitCode = 1;
|
|
70598
|
+
return;
|
|
70599
|
+
}
|
|
70600
|
+
try {
|
|
70601
|
+
const removed = deleteKeychainSecret(envVar);
|
|
70602
|
+
console.log(removed ? ok(`Removed ${envVar} from the macOS Keychain.`) : dim3(`${envVar} was not in the keychain \u2014 nothing to remove.`));
|
|
70603
|
+
} catch (err) {
|
|
70604
|
+
console.error(bad(err instanceof Error ? err.message : String(err)));
|
|
70605
|
+
process.exitCode = 1;
|
|
70606
|
+
}
|
|
70607
|
+
}
|
|
70608
|
+
function keychainToggle(enabled2) {
|
|
70609
|
+
if (enabled2 && !requireKeychain())
|
|
70610
|
+
return;
|
|
70611
|
+
setKeychainEnabled(enabled2);
|
|
70612
|
+
invalidateKeychainCache();
|
|
70613
|
+
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."));
|
|
70614
|
+
if (!enabled2) {
|
|
70615
|
+
console.log(dim3("Remove the items themselves with: claudish keychain rm <ENV_VAR>"));
|
|
70616
|
+
}
|
|
70617
|
+
}
|
|
70618
|
+
function usage() {
|
|
70619
|
+
console.log(`${strong("claudish keychain")} \u2014 macOS Keychain credential backend
|
|
70620
|
+
|
|
70621
|
+
${strong("status")} Backend state and how many keys are stored (default)
|
|
70622
|
+
${strong("list")} Stored variables, with ${dim3("\u2022\u2022\u2022\u20221234")} identification tails
|
|
70623
|
+
${strong("import")} [options] Copy secrets from env vars / 1Password into the keychain
|
|
70624
|
+
${strong("set")} <ENV_VAR> Store one secret (prompted, or piped on stdin)
|
|
70625
|
+
${strong("rm")} <ENV_VAR> Remove one secret
|
|
70626
|
+
${strong("enable")} | ${strong("disable")} Turn the backend on/off (moves no secrets)
|
|
70627
|
+
|
|
70628
|
+
${strong("import options")}
|
|
70629
|
+
--from env|1password|all Source to copy from (default: all)
|
|
70630
|
+
--only VAR,VAR Restrict to these variables
|
|
70631
|
+
--dry-run Show the plan and stop
|
|
70632
|
+
--yes Skip the confirmation
|
|
70633
|
+
|
|
70634
|
+
Resolution order: ${dim3("env var \u2192 alias \u2192 config.json \u2192 macOS Keychain \u2192 1Password")}
|
|
70635
|
+
`);
|
|
70636
|
+
}
|
|
70637
|
+
function parseOnly(args) {
|
|
70638
|
+
const idx = args.findIndex((a) => a === "--only" || a.startsWith("--only="));
|
|
70639
|
+
if (idx === -1)
|
|
70640
|
+
return;
|
|
70641
|
+
const raw2 = args[idx].includes("=") ? args[idx].split("=").slice(1).join("=") : args[idx + 1];
|
|
70642
|
+
if (!raw2)
|
|
70643
|
+
return;
|
|
70644
|
+
const names = raw2.split(",").map((n) => n.trim()).filter(Boolean);
|
|
70645
|
+
return names.length > 0 ? names : undefined;
|
|
70646
|
+
}
|
|
70647
|
+
function parseFrom(args) {
|
|
70648
|
+
const idx = args.findIndex((a) => a === "--from" || a.startsWith("--from="));
|
|
70649
|
+
if (idx === -1)
|
|
70650
|
+
return "all";
|
|
70651
|
+
const raw2 = (args[idx].includes("=") ? args[idx].split("=").slice(1).join("=") : args[idx + 1])?.trim().toLowerCase();
|
|
70652
|
+
if (raw2 === "env" || raw2 === "1password" || raw2 === "all")
|
|
70653
|
+
return raw2;
|
|
70654
|
+
if (raw2 === "op")
|
|
70655
|
+
return "1password";
|
|
70656
|
+
return "all";
|
|
70657
|
+
}
|
|
70658
|
+
function positionalArgs(args) {
|
|
70659
|
+
const out = [];
|
|
70660
|
+
for (let i = 0;i < args.length; i++) {
|
|
70661
|
+
const arg = args[i];
|
|
70662
|
+
if (arg.startsWith("-")) {
|
|
70663
|
+
if (VALUE_FLAGS.has(arg))
|
|
70664
|
+
i++;
|
|
70665
|
+
continue;
|
|
70666
|
+
}
|
|
70667
|
+
out.push(arg);
|
|
70668
|
+
}
|
|
70669
|
+
return out;
|
|
70670
|
+
}
|
|
70671
|
+
async function keychainCommand(args) {
|
|
70672
|
+
const positional = positionalArgs(args);
|
|
70673
|
+
const sub = positional[0] ?? "status";
|
|
70674
|
+
switch (sub) {
|
|
70675
|
+
case "status":
|
|
70676
|
+
keychainStatus();
|
|
70677
|
+
return;
|
|
70678
|
+
case "list":
|
|
70679
|
+
case "ls":
|
|
70680
|
+
keychainList();
|
|
70681
|
+
return;
|
|
70682
|
+
case "import":
|
|
70683
|
+
await keychainImport({
|
|
70684
|
+
from: parseFrom(args),
|
|
70685
|
+
only: parseOnly(args),
|
|
70686
|
+
dryRun: args.includes("--dry-run"),
|
|
70687
|
+
yes: args.includes("--yes") || args.includes("-y")
|
|
70688
|
+
});
|
|
70689
|
+
return;
|
|
70690
|
+
case "set":
|
|
70691
|
+
await keychainSet(positional[1]);
|
|
70692
|
+
return;
|
|
70693
|
+
case "rm":
|
|
70694
|
+
case "remove":
|
|
70695
|
+
case "delete":
|
|
70696
|
+
keychainRemove(positional[1]);
|
|
70697
|
+
return;
|
|
70698
|
+
case "enable":
|
|
70699
|
+
keychainToggle(true);
|
|
70700
|
+
return;
|
|
70701
|
+
case "disable":
|
|
70702
|
+
keychainToggle(false);
|
|
70703
|
+
return;
|
|
70704
|
+
case "help":
|
|
70705
|
+
usage();
|
|
70706
|
+
return;
|
|
70707
|
+
default:
|
|
70708
|
+
console.error(bad(`Unknown subcommand: ${sub}`));
|
|
70709
|
+
usage();
|
|
70710
|
+
process.exitCode = 1;
|
|
70711
|
+
}
|
|
70712
|
+
}
|
|
70713
|
+
var VALUE_FLAGS;
|
|
70714
|
+
var init_keychain_command = __esm(() => {
|
|
70715
|
+
init_ansi();
|
|
70716
|
+
init_op_source();
|
|
70717
|
+
init_profile_config();
|
|
70718
|
+
init_keychain();
|
|
70719
|
+
init_provider_definitions();
|
|
70720
|
+
VALUE_FLAGS = new Set(["--config", "--from", "--only"]);
|
|
70721
|
+
});
|
|
70722
|
+
|
|
69844
70723
|
// src/auth/antigravity-oauth.ts
|
|
69845
70724
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
69846
70725
|
import { existsSync as existsSync26, unlinkSync as unlinkSync7 } from "fs";
|
|
@@ -69881,16 +70760,16 @@ function defaultRunAgyAuth(agyPath, interactive) {
|
|
|
69881
70760
|
spawnSync3(agyPath, ["-p", "hello", "--print-timeout", "3m"], { stdio: "inherit" });
|
|
69882
70761
|
}
|
|
69883
70762
|
}
|
|
69884
|
-
async function pollForToken(
|
|
69885
|
-
const deadline =
|
|
70763
|
+
async function pollForToken(deps2) {
|
|
70764
|
+
const deadline = deps2.now() + deps2.timing.graceMs;
|
|
69886
70765
|
for (;; ) {
|
|
69887
|
-
const tok =
|
|
70766
|
+
const tok = deps2.readToken();
|
|
69888
70767
|
if (tok)
|
|
69889
70768
|
return tok;
|
|
69890
|
-
if (
|
|
70769
|
+
if (deps2.now() >= deadline)
|
|
69891
70770
|
return null;
|
|
69892
|
-
const remaining = deadline -
|
|
69893
|
-
await
|
|
70771
|
+
const remaining = deadline - deps2.now();
|
|
70772
|
+
await deps2.sleep(Math.min(deps2.timing.intervalMs, Math.max(0, remaining)));
|
|
69894
70773
|
}
|
|
69895
70774
|
}
|
|
69896
70775
|
|
|
@@ -69904,67 +70783,67 @@ class AntigravityOAuth {
|
|
|
69904
70783
|
}
|
|
69905
70784
|
constructor() {}
|
|
69906
70785
|
async login(depsOverride = {}) {
|
|
69907
|
-
const
|
|
70786
|
+
const deps2 = { ...defaultLoginDeps, ...depsOverride };
|
|
69908
70787
|
log("[AntigravityOAuth] Starting agy-delegated login");
|
|
69909
|
-
if (
|
|
69910
|
-
console.log(`\u2705 Already authenticated with Antigravity. Use: claudish --model ag@${await (
|
|
69911
|
-
return
|
|
70788
|
+
if (deps2.hasToken()) {
|
|
70789
|
+
console.log(`\u2705 Already authenticated with Antigravity. Use: claudish --model ag@${await (deps2.suggestModel ?? defaultSuggestModel)()}`);
|
|
70790
|
+
return deps2.exit(0);
|
|
69912
70791
|
}
|
|
69913
|
-
let agyPath =
|
|
70792
|
+
let agyPath = deps2.locateAgy();
|
|
69914
70793
|
if (!agyPath) {
|
|
69915
70794
|
console.log("\nThe Antigravity CLI (`agy`) is required to sign in to Antigravity.");
|
|
69916
70795
|
console.log(`claudish delegates Antigravity sign-in to agy \u2014 agy holds the current OAuth secret
|
|
69917
70796
|
` + "and writes the session to the shared keychain store that claudish reads.");
|
|
69918
|
-
if (!
|
|
70797
|
+
if (!deps2.isInteractive()) {
|
|
69919
70798
|
printManualInstall();
|
|
69920
|
-
return
|
|
70799
|
+
return deps2.exit(0);
|
|
69921
70800
|
}
|
|
69922
|
-
const proceed = await
|
|
70801
|
+
const proceed = await deps2.confirmInstall();
|
|
69923
70802
|
if (!proceed) {
|
|
69924
70803
|
printManualInstall();
|
|
69925
|
-
return
|
|
70804
|
+
return deps2.exit(0);
|
|
69926
70805
|
}
|
|
69927
70806
|
console.log(`
|
|
69928
70807
|
Installing the Antigravity CLI\u2026
|
|
69929
70808
|
`);
|
|
69930
|
-
if (!
|
|
70809
|
+
if (!deps2.runInstall()) {
|
|
69931
70810
|
console.log(`
|
|
69932
70811
|
\u274C Antigravity CLI installation failed.`);
|
|
69933
70812
|
printManualInstall();
|
|
69934
|
-
return
|
|
70813
|
+
return deps2.exit(0);
|
|
69935
70814
|
}
|
|
69936
|
-
agyPath =
|
|
70815
|
+
agyPath = deps2.locateAgy();
|
|
69937
70816
|
if (!agyPath) {
|
|
69938
70817
|
console.log(`
|
|
69939
70818
|
\u274C Antigravity CLI still not found after install.`);
|
|
69940
70819
|
printManualInstall();
|
|
69941
|
-
return
|
|
70820
|
+
return deps2.exit(0);
|
|
69942
70821
|
}
|
|
69943
70822
|
}
|
|
69944
70823
|
console.log(`
|
|
69945
70824
|
Launching the Antigravity CLI to sign in \u2014 complete the sign-in in your browser.
|
|
69946
70825
|
` + `claudish will detect the session automatically.
|
|
69947
70826
|
`);
|
|
69948
|
-
|
|
69949
|
-
let token = await pollForToken(
|
|
70827
|
+
deps2.runAgyAuth(agyPath, false);
|
|
70828
|
+
let token = await pollForToken(deps2);
|
|
69950
70829
|
if (!token) {
|
|
69951
70830
|
console.log(`
|
|
69952
70831
|
No session detected yet. Starting the Antigravity CLI interactively \u2014
|
|
69953
70832
|
` + "sign in, then exit agy (its `/quit` command or Ctrl-C) to return here.\n");
|
|
69954
|
-
|
|
69955
|
-
token = await pollForToken(
|
|
70833
|
+
deps2.runAgyAuth(agyPath, true);
|
|
70834
|
+
token = await pollForToken(deps2);
|
|
69956
70835
|
}
|
|
69957
70836
|
if (token) {
|
|
69958
|
-
|
|
70837
|
+
deps2.onAuthenticated();
|
|
69959
70838
|
console.log(`
|
|
69960
|
-
\u2705 Authenticated with Antigravity. Use: claudish --model ag@${await (
|
|
69961
|
-
return
|
|
70839
|
+
\u2705 Authenticated with Antigravity. Use: claudish --model ag@${await (deps2.suggestModel ?? defaultSuggestModel)()}`);
|
|
70840
|
+
return deps2.exit(0);
|
|
69962
70841
|
}
|
|
69963
70842
|
console.log("\nNo Antigravity session detected. Run `agy` and sign in, then retry `claudish login antigravity`.");
|
|
69964
|
-
return
|
|
70843
|
+
return deps2.exit(0);
|
|
69965
70844
|
}
|
|
69966
|
-
async logout(
|
|
69967
|
-
deleteSharedAntigravityToken(
|
|
70845
|
+
async logout(deps2) {
|
|
70846
|
+
deleteSharedAntigravityToken(deps2);
|
|
69968
70847
|
try {
|
|
69969
70848
|
const tokenFile = join36(homedir31(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
|
|
69970
70849
|
if (existsSync26(tokenFile))
|
|
@@ -70166,7 +71045,7 @@ async function quotaCommand(provider) {
|
|
|
70166
71045
|
`);
|
|
70167
71046
|
return;
|
|
70168
71047
|
}
|
|
70169
|
-
|
|
71048
|
+
renderPlan2(adapter, plan);
|
|
70170
71049
|
}
|
|
70171
71050
|
function resolveAdapterFromInput(input) {
|
|
70172
71051
|
const raw2 = input.toLowerCase().replace(/@+$/, "");
|
|
@@ -70196,7 +71075,7 @@ async function promptForAdapter() {
|
|
|
70196
71075
|
});
|
|
70197
71076
|
return select({ message: "Select provider:", choices });
|
|
70198
71077
|
}
|
|
70199
|
-
function
|
|
71078
|
+
function renderPlan2(adapter, plan) {
|
|
70200
71079
|
console.log("");
|
|
70201
71080
|
boxTop(plan.label);
|
|
70202
71081
|
boxRow("Provider", adapter.providerId);
|
|
@@ -70407,11 +71286,11 @@ function readSlimCacheWithFreshness(reader) {
|
|
|
70407
71286
|
const stale = !Number.isFinite(lastUpdatedMs) || ageMs > FIREBASE_CACHE_TTL_MS;
|
|
70408
71287
|
return { entries: cache3.entries ?? [], stale };
|
|
70409
71288
|
}
|
|
70410
|
-
function createCatalogClient(
|
|
70411
|
-
const _getModelsByProvider =
|
|
70412
|
-
const _getModelByIdFromFirebase =
|
|
70413
|
-
const _searchModels =
|
|
70414
|
-
const _readSlimCache =
|
|
71289
|
+
function createCatalogClient(deps2 = {}) {
|
|
71290
|
+
const _getModelsByProvider = deps2.getModelsByProvider ?? getModelsByProvider;
|
|
71291
|
+
const _getModelByIdFromFirebase = deps2.getModelByIdFromFirebase ?? getModelByIdFromFirebase;
|
|
71292
|
+
const _searchModels = deps2.searchModels ?? searchModels;
|
|
71293
|
+
const _readSlimCache = deps2.readSlimCache ?? readAllModelsCache;
|
|
70415
71294
|
return {
|
|
70416
71295
|
async modelsByVendor(vendorSlug) {
|
|
70417
71296
|
const slug = vendorSlug.toLowerCase();
|
|
@@ -70595,6 +71474,8 @@ function resolveDiscoveredContextLength(m) {
|
|
|
70595
71474
|
}
|
|
70596
71475
|
}
|
|
70597
71476
|
function resolveDiscoveredReleaseDate(m) {
|
|
71477
|
+
if (m.ignoreCatalogReleaseDate)
|
|
71478
|
+
return m.releaseDate;
|
|
70598
71479
|
try {
|
|
70599
71480
|
const catalogDate = lookupModel(m.id)?.releaseDate;
|
|
70600
71481
|
if (catalogDate)
|
|
@@ -71408,10 +72289,42 @@ function registerPaletteRefresher(fn) {
|
|
|
71408
72289
|
paletteRefreshers.push(fn);
|
|
71409
72290
|
fn();
|
|
71410
72291
|
}
|
|
72292
|
+
function hexChannels(hex3) {
|
|
72293
|
+
const m = /^#([0-9a-f]{6})$/i.exec(hex3.trim());
|
|
72294
|
+
if (!m)
|
|
72295
|
+
return null;
|
|
72296
|
+
const n = Number.parseInt(m[1], 16);
|
|
72297
|
+
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
72298
|
+
}
|
|
72299
|
+
function channelsToHex(c) {
|
|
72300
|
+
const hex3 = c.map((v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, "0")).join("");
|
|
72301
|
+
return `#${hex3}`;
|
|
72302
|
+
}
|
|
72303
|
+
function retintSurfaces(palette, pageHex) {
|
|
72304
|
+
const paletteBg = hexChannels(palette.bg);
|
|
72305
|
+
const page = hexChannels(pageHex);
|
|
72306
|
+
if (!paletteBg || !page)
|
|
72307
|
+
return;
|
|
72308
|
+
for (const token of SURFACE_TOKENS) {
|
|
72309
|
+
const original = hexChannels(palette[token]);
|
|
72310
|
+
if (!original)
|
|
72311
|
+
continue;
|
|
72312
|
+
C[token] = channelsToHex([
|
|
72313
|
+
page[0] + (original[0] - paletteBg[0]),
|
|
72314
|
+
page[1] + (original[1] - paletteBg[1]),
|
|
72315
|
+
page[2] + (original[2] - paletteBg[2])
|
|
72316
|
+
]);
|
|
72317
|
+
}
|
|
72318
|
+
}
|
|
71411
72319
|
function applyTuiTheme(mode) {
|
|
71412
72320
|
const palette = mode === "light" ? LIGHT2 : DARK;
|
|
71413
72321
|
activeLatencyBuckets = mode === "light" ? LATENCY_BUCKETS_LIGHT : LATENCY_BUCKETS_DARK;
|
|
71414
72322
|
Object.assign(C, palette);
|
|
72323
|
+
const terminalBg = getTerminalBackground();
|
|
72324
|
+
if (terminalBg && terminalBg.mode === mode) {
|
|
72325
|
+
C.bg = terminalBg.hex;
|
|
72326
|
+
retintSurfaces(palette, terminalBg.hex);
|
|
72327
|
+
}
|
|
71415
72328
|
Object.assign(STAGE_BG, mode === "light" ? STAGE_BG_LIGHT : STAGE_BG_DARK);
|
|
71416
72329
|
STAGE_BG_ANSI.network = hexToAnsiBg(STAGE_BG.network);
|
|
71417
72330
|
STAGE_BG_ANSI.server = hexToAnsiBg(STAGE_BG.server);
|
|
@@ -71488,7 +72401,7 @@ function tokBarCells(tokensPerSec, maxTokPerSec, tokWidth) {
|
|
|
71488
72401
|
const raw2 = Math.round(tokWidth * Math.max(0, tokensPerSec) / denom);
|
|
71489
72402
|
return Math.min(tokWidth, Math.max(0, raw2));
|
|
71490
72403
|
}
|
|
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;
|
|
72404
|
+
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
72405
|
var init_theme2 = __esm(() => {
|
|
71493
72406
|
init_theme_mode();
|
|
71494
72407
|
DARK = {
|
|
@@ -71598,6 +72511,7 @@ var init_theme2 = __esm(() => {
|
|
|
71598
72511
|
streaming: hexToAnsiBg(STAGE_BG.streaming)
|
|
71599
72512
|
};
|
|
71600
72513
|
paletteRefreshers = [];
|
|
72514
|
+
SURFACE_TOKENS = ["bgAlt", "border", "tabInactiveBg", "chipKeyBg", "chipLabelBg"];
|
|
71601
72515
|
onThemeModeChange(applyTuiTheme);
|
|
71602
72516
|
});
|
|
71603
72517
|
|
|
@@ -75057,7 +75971,7 @@ function printHelp2() {
|
|
|
75057
75971
|
const A2 = cliAnsi();
|
|
75058
75972
|
const c = (esc2) => (s) => useColor && esc2 ? `${esc2}${s}${A2.RESET}` : s;
|
|
75059
75973
|
const bold4 = c(A2.BOLD);
|
|
75060
|
-
const
|
|
75974
|
+
const dim4 = c(A2.DIM);
|
|
75061
75975
|
const cyan = c(A2.CYAN);
|
|
75062
75976
|
const green2 = c(A2.GREEN);
|
|
75063
75977
|
const yellow2 = c(A2.YELLOW);
|
|
@@ -75065,89 +75979,89 @@ function printHelp2() {
|
|
|
75065
75979
|
const blue = c(A2.BLUE);
|
|
75066
75980
|
const h = (title) => bold4(cyan(`\u258C ${title}`));
|
|
75067
75981
|
console.log(`
|
|
75068
|
-
${bold4("claudish")} ${
|
|
75069
|
-
${
|
|
75982
|
+
${bold4("claudish")} ${dim4("\xB7")} Run Claude Code with any AI model
|
|
75983
|
+
${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
75984
|
|
|
75071
75985
|
${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")} ${
|
|
75986
|
+
${green2("claudish")} ${dim4("# Interactive mode (default, model selector)")}
|
|
75987
|
+
${green2("claudish")} ${yellow2("[OPTIONS] <claude-args...>")} ${dim4("# Single-shot mode (requires --model)")}
|
|
75988
|
+
${green2("claudish")} ${green2("--team")} ${yellow2("a,b,c")} ${yellow2('"prompt"')} ${dim4("# Run models in parallel (magmux grid)")}
|
|
75989
|
+
${green2("claudish")} ${green2("--team")} ${yellow2("a,b,c")} ${green2("-f")} ${yellow2("input.md")} ${dim4("# Team mode with file input")}
|
|
75076
75990
|
|
|
75077
75991
|
${h("MODEL ROUTING")}
|
|
75078
75992
|
${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")} ${
|
|
75993
|
+
${magenta("google@gemini-3-pro")} ${dim4("Direct Google API (explicit)")}
|
|
75994
|
+
${magenta("openrouter@google/gemini-3-pro")} ${dim4("OpenRouter (explicit)")}
|
|
75995
|
+
${magenta("oai@gpt-5.3")} ${dim4("Direct OpenAI API (shortcut)")}
|
|
75996
|
+
${magenta("ollama@llama3.2:3")} ${dim4("Local Ollama, 3 concurrent requests")}
|
|
75997
|
+
${magenta("ollama@llama3.2:0")} ${dim4("Local Ollama, no limits")}
|
|
75084
75998
|
|
|
75085
75999
|
${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
|
-
${
|
|
76000
|
+
${magenta("g, gemini")} ${dim4("->")} Google Gemini ${dim4("google@gemini-3-pro")}
|
|
76001
|
+
${magenta("oai")} ${dim4("->")} OpenAI Direct ${dim4("oai@gpt-5.3")}
|
|
76002
|
+
${magenta("cx, codex")} ${dim4("->")} OpenAI Codex ${dim4("cx@gpt-5.3 (Responses API)")}
|
|
76003
|
+
${magenta("or")} ${dim4("->")} OpenRouter ${dim4("or@openai/gpt-5.3")}
|
|
76004
|
+
${magenta("x-ai, xai, grok")} ${dim4("->")} xAI / Grok ${dim4("x-ai@grok-3")}
|
|
76005
|
+
${magenta("mm, mmax")} ${dim4("->")} MiniMax Direct ${dim4("mm@MiniMax-M2.1")}
|
|
76006
|
+
${magenta("mmc")} ${dim4("->")} MiniMax Coding ${dim4("mmc@MiniMax-M2.1")}
|
|
76007
|
+
${magenta("kimi, moon")} ${dim4("->")} Kimi Direct ${dim4("kimi@kimi-k2-thinking-turbo")}
|
|
76008
|
+
${magenta("kc")} ${dim4("->")} Kimi Coding ${dim4("kc@kimi-k2-thinking-turbo")}
|
|
76009
|
+
${magenta("glm, zhipu")} ${dim4("->")} GLM Direct ${dim4("glm@glm-4.7")}
|
|
76010
|
+
${magenta("gc")} ${dim4("->")} GLM Coding ${dim4("gc@glm-4.7")}
|
|
76011
|
+
${magenta("z-ai, zai")} ${dim4("->")} Z.AI Direct ${dim4("z-ai@glm-4.7")}
|
|
76012
|
+
${magenta("oc, llama, lc, meta")} ${dim4("->")} OllamaCloud ${dim4("oc@llama-3.1")}
|
|
76013
|
+
${magenta("zen")} ${dim4("->")} OpenCode Zen ${dim4("zen@grok-code")}
|
|
76014
|
+
${magenta("zengo, zgo")} ${dim4("->")} OpenCode Zen Go ${dim4("zengo@grok-code")}
|
|
76015
|
+
${magenta("v, vertex")} ${dim4("->")} Vertex AI ${dim4("v@gemini-2.5-flash")}
|
|
76016
|
+
${magenta("poe")} ${dim4("->")} Poe ${dim4("poe@GPT-4o")}
|
|
76017
|
+
${magenta("litellm, ll")} ${dim4("->")} LiteLLM ${dim4("ll@gpt-4o (needs LITELLM_BASE_URL)")}
|
|
76018
|
+
${magenta("ds")} ${dim4("->")} DeepSeek ${dim4("ds@deepseek-chat")}
|
|
76019
|
+
${magenta("sakana, fugu")} ${dim4("->")} Sakana Fugu ${dim4("fugu@fugu-ultra")}
|
|
76020
|
+
${magenta("sc")} ${dim4("->")} Sakana Subscription ${dim4("sc@fugu-ultra")}
|
|
76021
|
+
${magenta("ollama")} ${dim4("->")} Ollama (local) ${dim4("ollama@llama3.2")}
|
|
76022
|
+
${magenta("lms, lmstudio")} ${dim4("->")} LM Studio (local) ${dim4("lms@qwen")}
|
|
76023
|
+
${magenta("vllm")} ${dim4("->")} vLLM (local) ${dim4("vllm@model")}
|
|
76024
|
+
${magenta("mlx")} ${dim4("->")} MLX (local) ${dim4("mlx@model")}
|
|
76025
|
+
|
|
76026
|
+
${bold4("Native auto-detection")} ${dim4("(when no provider specified):")}
|
|
76027
|
+
${yellow2("google/*, gemini-*")} ${dim4("->")} Google API
|
|
76028
|
+
${yellow2("openai/*, gpt-*, o1-*")} ${dim4("->")} OpenAI API
|
|
76029
|
+
${yellow2("x-ai/*, grok-*")} ${dim4("->")} xAI
|
|
76030
|
+
${yellow2("meta-llama/*, llama-*")} ${dim4("->")} OllamaCloud
|
|
76031
|
+
${yellow2("minimax/*, abab-*")} ${dim4("->")} MiniMax API
|
|
76032
|
+
${yellow2("moonshot/*, kimi-*")} ${dim4("->")} Kimi API
|
|
76033
|
+
${yellow2("zhipu/*, glm-*")} ${dim4("->")} GLM API
|
|
76034
|
+
${yellow2("sakana/*, fugu-*")} ${dim4("->")} Sakana Fugu
|
|
76035
|
+
${yellow2("poe:*")} ${dim4("->")} Poe
|
|
76036
|
+
${yellow2("anthropic/*, claude-*")} ${dim4("->")} Native Anthropic
|
|
76037
|
+
${yellow2("(unknown vendor/)")} ${dim4("->")} Error (use openrouter@vendor/model)
|
|
76038
|
+
|
|
76039
|
+
${dim4("A defaultProvider (config / --default-provider) catches bare names that match no rule.")}
|
|
75126
76040
|
|
|
75127
76041
|
${h("OPTIONS")}
|
|
75128
76042
|
${green2("-i, --interactive")} Run in interactive mode (default when no prompt given)
|
|
75129
76043
|
${green2("-m, --model")} ${yellow2("<model>")} Model to use (required for single-shot mode)
|
|
75130
76044
|
${green2("--profile")} ${yellow2("<name>")} Use named profile for model mapping (default profile if omitted)
|
|
75131
76045
|
${green2("--default-provider")} ${yellow2("<name>")} Fallback provider for bare model names (builtin or customEndpoints key)
|
|
75132
|
-
${
|
|
76046
|
+
${dim4("Precedence: this flag > CLAUDISH_DEFAULT_PROVIDER env > config.json")}
|
|
75133
76047
|
${green2("--anthropic-api-billing")} Use your real ANTHROPIC_API_KEY for native Claude models
|
|
75134
|
-
${
|
|
75135
|
-
${
|
|
75136
|
-
${
|
|
76048
|
+
${dim4("(metered API billing). Default: the key is hidden so Claude Code")}
|
|
76049
|
+
${dim4("uses your claude.ai subscription. Env: CLAUDISH_ANTHROPIC_API_BILLING")}
|
|
76050
|
+
${dim4("Config: anthropicApiBilling: true")}
|
|
75137
76051
|
${green2("--config")} ${yellow2("<file>")} Use THIS config file for the run, fully replacing the machine
|
|
75138
|
-
${
|
|
75139
|
-
${
|
|
75140
|
-
${
|
|
76052
|
+
${dim4("global (~/.claudish/config.json) AND project (.claudish.json).")}
|
|
76053
|
+
${dim4("A file naming no op:// source never touches 1Password (no prompt).")}
|
|
76054
|
+
${dim4("Env vars still resolve first. Env: CLAUDISH_CONFIG")}
|
|
75141
76055
|
${green2("--op")} ${yellow2("<op://glob>")} Load API keys from a 1Password item glob (SDK-based, no op CLI)
|
|
75142
76056
|
${green2("--op")} ${yellow2("<glob>")} ${green2("--list")} Preview which fields the glob would import (names only, no values)
|
|
75143
76057
|
${green2("--op-env")} ${yellow2("<id>")} Load env vars from a 1Password Environment (highest priority)
|
|
75144
76058
|
${green2("--port")} ${yellow2("<port>")} Proxy server port (default: random)
|
|
75145
76059
|
${green2("-d, --debug-claudish")} Enable claudish debug logging to file (logs/claudish_*.log)
|
|
75146
|
-
${
|
|
76060
|
+
${dim4('Always-on: CLAUDISH_DEBUG=1 env var or "debug": true in config.json')}
|
|
75147
76061
|
${green2("--no-debug-claudish")} Force debug logging off for this run (when globally enabled)
|
|
75148
76062
|
${green2("--log-off")} Disable always-on structural logging (~/.claudish/logs/)
|
|
75149
76063
|
${green2("--log-diag")} ${yellow2("<mode>")} Diagnostic output: auto (default), logfile, off
|
|
75150
|
-
${
|
|
76064
|
+
${dim4('Also: CLAUDISH_DIAG_MODE env var or "diagMode" in config.json')}
|
|
75151
76065
|
${green2("--log-level")} ${yellow2("<level>")} Log verbosity: debug (full), info (truncated), minimal (labels)
|
|
75152
76066
|
${green2("-q, --quiet")} Suppress [claudish] log messages (default in single-shot mode)
|
|
75153
76067
|
${green2("-v, --verbose")} Show [claudish] log messages (default in interactive mode)
|
|
@@ -75171,13 +76085,13 @@ ${h("OPTIONS")}
|
|
|
75171
76085
|
${h("MODEL DISCOVERY")}
|
|
75172
76086
|
${green2("--models")} Top 100 ranked (Firebase + local providers)
|
|
75173
76087
|
${green2("--models --provider")} ${yellow2("<slug>")} Filter the catalog to one provider
|
|
75174
|
-
${
|
|
76088
|
+
${dim4("e.g. --provider opencode-zen, anthropic, openai")}
|
|
75175
76089
|
${green2("--providers")} Every provider + active-model count
|
|
75176
76090
|
${green2("-s, --models-search")} ${yellow2("<query>")} Fuzzy search: id, brand synonyms (chatgpt,
|
|
75177
|
-
${
|
|
76091
|
+
${dim4("claude, grok), gateways (zen, oc, codex), caps")}
|
|
75178
76092
|
${green2("--models-top")} Curated recommended models (flagship + fast)
|
|
75179
76093
|
${green2("--probe")} ${yellow2("<models...>")} Probe each provider in the fallback chain with
|
|
75180
|
-
${
|
|
76094
|
+
${dim4("a real 1-token request (may incur tiny cost)")}
|
|
75181
76095
|
${green2("--no-probe")} Skip live requests, show static chain only
|
|
75182
76096
|
${green2("--probe-timeout")} ${yellow2("<secs>")} Per-link timeout for live probes (default: 40)
|
|
75183
76097
|
${green2("--models-refresh")} Force refresh the slim model catalog from Firebase
|
|
@@ -75186,11 +76100,11 @@ ${h("MODEL DISCOVERY")}
|
|
|
75186
76100
|
|
|
75187
76101
|
${h("TEAM MODE")}
|
|
75188
76102
|
${green2("--team")} ${yellow2("<models>")} Run multiple models in parallel (comma-separated)
|
|
75189
|
-
${
|
|
76103
|
+
${dim4('Example: --team minimax-m2.5,kimi-k2.5 "prompt"')}
|
|
75190
76104
|
${green2("--mode")} ${yellow2("<mode>")} Team mode: default (grid), interactive, json
|
|
75191
76105
|
${green2("-f, --file")} ${yellow2("<path>")} Read prompt from file (use with --team or single-shot)
|
|
75192
76106
|
|
|
75193
|
-
${h("MODEL MAPPING")} ${
|
|
76107
|
+
${h("MODEL MAPPING")} ${dim4("(per-role override)")}
|
|
75194
76108
|
${green2("--model-opus")} ${yellow2("<model>")} Model for Opus role (planning, complex tasks)
|
|
75195
76109
|
${green2("--model-sonnet")} ${yellow2("<model>")} Model for Sonnet role (default coding)
|
|
75196
76110
|
${green2("--model-haiku")} ${yellow2("<model>")} Model for Haiku role (fast tasks, background)
|
|
@@ -75198,7 +76112,7 @@ ${h("MODEL MAPPING")} ${dim3("(per-role override)")}
|
|
|
75198
76112
|
|
|
75199
76113
|
${h("SUBCOMMANDS")}
|
|
75200
76114
|
${green2("claudish config")} Open the interactive config TUI (profiles,
|
|
75201
|
-
${
|
|
76115
|
+
${dim4("providers, routing, 1Password)")}
|
|
75202
76116
|
${green2("claudish providers")} ${yellow2("[--json]")} Show provider credential status (no key material)
|
|
75203
76117
|
${green2("claudish quota")} ${yellow2("[provider]")} Show remaining quota/usage (alias: usage)
|
|
75204
76118
|
${green2("claudish serve")} ${yellow2("--port <n> --models <p>")} Run the Claude Desktop redirect gateway
|
|
@@ -75212,39 +76126,50 @@ ${h("SUBCOMMANDS")}
|
|
|
75212
76126
|
${green2("claudish profile use")} ${yellow2("[name] [scope]")} Set default profile
|
|
75213
76127
|
${green2("claudish profile show")} ${yellow2("[name] [scope]")} Show profile details
|
|
75214
76128
|
${green2("claudish profile edit")} ${yellow2("[name] [scope]")} Edit a profile
|
|
75215
|
-
${
|
|
76129
|
+
${dim4("scope = --local (.claudish.json) | --global (~/.claudish/config.json) | (prompted)")}
|
|
75216
76130
|
|
|
75217
76131
|
${bold4("Authentication:")}
|
|
75218
76132
|
${green2("claudish login")} ${yellow2("[provider]")} Login to an OAuth provider (interactive if omitted)
|
|
75219
76133
|
${green2("claudish logout")} ${yellow2("[provider]")} Clear OAuth credentials
|
|
75220
|
-
${
|
|
76134
|
+
${dim4("Providers: gemini, kimi")}
|
|
75221
76135
|
|
|
75222
|
-
${h("1PASSWORD")} ${
|
|
75223
|
-
${
|
|
76136
|
+
${h("1PASSWORD")} ${dim4("(SDK-based \u2014 no op CLI needed for secrets)")}
|
|
76137
|
+
${dim4("Auth via OP_SERVICE_ACCOUNT_TOKEN, or OP_ACCOUNT / onepasswordAccount config (DesktopAuth).")}
|
|
75224
76138
|
${green2("--op")} ${yellow2("<glob> --list")} Preview which fields a glob would import (names only)
|
|
75225
76139
|
${green2("--op")} ${yellow2("<glob>")} ${yellow2("[...args]")} Resolve a glob into env vars, then run a session
|
|
75226
|
-
${
|
|
75227
|
-
${
|
|
76140
|
+
${dim4("Inline op import requires a GLOB (self-names via field labels)")}
|
|
76141
|
+
${dim4('Example: claudish --op "op://Jack/Keys/**" --model gpt-4o "task"')}
|
|
75228
76142
|
${green2("--op-env")} ${yellow2("<id>")} Load a 1Password Environment (highest-priority source)
|
|
75229
|
-
${
|
|
76143
|
+
${dim4("Persistent setup (single refs, sets, environments, account): claudish config -> 1Password tab")}
|
|
76144
|
+
|
|
76145
|
+
${h("MACOS KEYCHAIN")} ${dim4("(local, encrypted at rest, no desktop-app handshake)")}
|
|
76146
|
+
${green2("claudish keychain status")} Backend state and how many keys are stored
|
|
76147
|
+
${green2("claudish keychain list")} Stored variables, with ${dim4("\u2022\u2022\u2022\u20221234")} identification tails
|
|
76148
|
+
${green2("claudish keychain import")} Copy keys from env vars / 1Password into the keychain
|
|
76149
|
+
${dim4("--from env|1password|all --only VAR,VAR --dry-run --yes")}
|
|
76150
|
+
${green2("claudish keychain set")} ${yellow2("<ENV_VAR>")} Store one key (prompted, or piped on stdin \u2014 never in argv)
|
|
76151
|
+
${green2("claudish keychain rm")} ${yellow2("<ENV_VAR>")} Remove one key
|
|
76152
|
+
${green2("claudish keychain enable")}${dim4("|")}${green2("disable")} Turn the backend on/off (moves no secrets)
|
|
76153
|
+
${dim4("Resolution order: env var -> alias -> config.json -> macOS Keychain -> 1Password")}
|
|
76154
|
+
${dim4("The config TUI's Providers tab writes to the keychain by default on macOS.")}
|
|
75230
76155
|
|
|
75231
76156
|
${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
|
-
${
|
|
76157
|
+
${dim4("Any unrecognized flag is forwarded to Claude Code. Claudish flags can appear in any order.")}
|
|
76158
|
+
${green2("claudish")} --model grok ${yellow2("--agent test")} ${yellow2('"task"')} ${dim4("# --agent passes through")}
|
|
76159
|
+
${green2("claudish")} --model grok ${yellow2("--effort high")} --stdin ${yellow2('"task"')} ${dim4("# --effort passes, --stdin stays")}
|
|
76160
|
+
${green2("claudish")} --model grok ${yellow2("--permission-mode plan")} -i ${dim4("# works in interactive too")}
|
|
76161
|
+
${dim4("Use -- when a Claude Code flag value starts with '-':")}
|
|
75237
76162
|
${green2("claudish")} --model grok ${green2("--")} ${yellow2('--system-prompt "-verbose mode" "task"')}
|
|
75238
76163
|
|
|
75239
76164
|
${h("CUSTOM MODELS & ENDPOINTS")}
|
|
75240
|
-
${
|
|
76165
|
+
${dim4("Claudish accepts ANY valid model ID from the Firebase catalog, even if not in --models:")}
|
|
75241
76166
|
${green2("claudish")} --model ${yellow2("openrouter@your_provider/custom-model-123")} ${yellow2('"task"')}
|
|
75242
|
-
${
|
|
76167
|
+
${dim4("Named custom endpoints live in ~/.claudish/config.json under 'customEndpoints' and route via @:")}
|
|
75243
76168
|
${green2("claudish")} --model ${yellow2("my-vllm@llama3.1-70b")} ${yellow2('"task"')}
|
|
75244
76169
|
|
|
75245
76170
|
${h("MODES")}
|
|
75246
|
-
${green2("\u2022")} ${bold4("Interactive")} ${
|
|
75247
|
-
${green2("\u2022")} ${bold4("Single-shot")} ${
|
|
76171
|
+
${green2("\u2022")} ${bold4("Interactive")} ${dim4("(default):")} shows model selector, starts a persistent session
|
|
76172
|
+
${green2("\u2022")} ${bold4("Single-shot")} ${dim4("(--model):")} runs one task headless and exits
|
|
75248
76173
|
|
|
75249
76174
|
${h("NOTES")}
|
|
75250
76175
|
${yellow2("\u2022")} Permission prompts are ${bold4("ENABLED")} by default (normal Claude Code behavior)
|
|
@@ -75253,35 +76178,35 @@ ${h("NOTES")}
|
|
|
75253
76178
|
${yellow2("\u2022")} ${green2("--dangerous")} disables the sandbox \u2014 use with extreme caution
|
|
75254
76179
|
|
|
75255
76180
|
${h("ENVIRONMENT VARIABLES")}
|
|
75256
|
-
${
|
|
76181
|
+
${dim4("Claudish auto-loads a .env file from the current directory.")}
|
|
75257
76182
|
|
|
75258
76183
|
${bold4("Claude Code installation:")}
|
|
75259
76184
|
${blue("CLAUDE_PATH")} Custom path to Claude Code binary
|
|
75260
|
-
${
|
|
76185
|
+
${dim4("Search: CLAUDE_PATH -> ~/.claude/local/claude -> PATH")}
|
|
75261
76186
|
|
|
75262
|
-
${bold4("API keys")} ${
|
|
76187
|
+
${bold4("API keys")} ${dim4("(at least one required for cloud models):")}
|
|
75263
76188
|
${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 ${
|
|
76189
|
+
${blue("GEMINI_API_KEY")} Google Gemini ${dim4("(g@, gemini@; alias GOOGLE_API_KEY)")}
|
|
76190
|
+
${blue("OPENAI_API_KEY")} OpenAI ${dim4("(oai@)")}
|
|
76191
|
+
${blue("OPENAI_CODEX_API_KEY")} OpenAI Codex / Responses API ${dim4("(cx@, codex@)")}
|
|
76192
|
+
${blue("XAI_API_KEY")} xAI / Grok ${dim4("(x-ai@, grok@)")}
|
|
76193
|
+
${blue("MINIMAX_API_KEY")} MiniMax ${dim4("(mm@, mmax@)")}
|
|
76194
|
+
${blue("MINIMAX_CODING_API_KEY")} MiniMax Coding Plan ${dim4("(mmc@)")}
|
|
76195
|
+
${blue("MOONSHOT_API_KEY")} Kimi / Moonshot ${dim4("(kimi@, moon@; alias KIMI_API_KEY)")}
|
|
76196
|
+
${blue("KIMI_CODING_API_KEY")} Kimi Coding Plan ${dim4("(kc@)")}
|
|
76197
|
+
${blue("ZHIPU_API_KEY")} GLM / Zhipu ${dim4("(glm@, zhipu@; alias GLM_API_KEY)")}
|
|
76198
|
+
${blue("GLM_CODING_API_KEY")} GLM Coding Plan ${dim4("(gc@; alias ZAI_CODING_API_KEY)")}
|
|
76199
|
+
${blue("ZAI_API_KEY")} Z.AI ${dim4("(z-ai@, zai@)")}
|
|
76200
|
+
${blue("DEEPSEEK_API_KEY")} DeepSeek ${dim4("(ds@)")}
|
|
76201
|
+
${blue("SAKANA_API_KEY")} Sakana Fugu ${dim4("(sakana@, fugu@)")}
|
|
76202
|
+
${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${dim4("(sc@; separate subscription key)")}
|
|
76203
|
+
${blue("OLLAMA_API_KEY")} OllamaCloud ${dim4("(oc@, llama@)")}
|
|
76204
|
+
${blue("OPENCODE_API_KEY")} OpenCode Zen ${dim4("(zen@)")}
|
|
76205
|
+
${blue("POE_API_KEY")} Poe ${dim4("(poe@)")}
|
|
76206
|
+
${blue("LITELLM_API_KEY")} LiteLLM ${dim4("(litellm@, ll@; needs LITELLM_BASE_URL)")}
|
|
76207
|
+
${blue("VERTEX_API_KEY")} Vertex AI Express ${dim4("(v@)")}
|
|
76208
|
+
${blue("VERTEX_PROJECT")} Vertex AI project ID ${dim4("(OAuth mode, v@)")}
|
|
76209
|
+
${blue("VERTEX_LOCATION")} Vertex AI region ${dim4("(default: us-central1)")}
|
|
75285
76210
|
${blue("ANTHROPIC_API_KEY")} Placeholder (prevents Claude Code dialog)
|
|
75286
76211
|
${blue("ANTHROPIC_AUTH_TOKEN")} Placeholder (prevents Claude Code login screen)
|
|
75287
76212
|
|
|
@@ -75289,27 +76214,27 @@ ${h("ENVIRONMENT VARIABLES")}
|
|
|
75289
76214
|
${blue("GEMINI_BASE_URL")} Custom Gemini endpoint
|
|
75290
76215
|
${blue("OPENAI_BASE_URL")} Custom OpenAI / Azure endpoint
|
|
75291
76216
|
${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 ${
|
|
76217
|
+
${blue("MOONSHOT_BASE_URL")} Custom Kimi / Moonshot endpoint ${dim4("(alias KIMI_BASE_URL)")}
|
|
76218
|
+
${blue("ZHIPU_BASE_URL")} Custom GLM / Zhipu endpoint ${dim4("(alias GLM_BASE_URL)")}
|
|
76219
|
+
${blue("SAKANA_BASE_URL")} Custom Sakana endpoint ${dim4("(default: https://api.sakana.ai)")}
|
|
76220
|
+
${blue("LITELLM_BASE_URL")} LiteLLM gateway base URL ${dim4("(required for ll@)")}
|
|
76221
|
+
${blue("OLLAMACLOUD_BASE_URL")} OllamaCloud ${dim4("(default: https://ollama.com)")}
|
|
76222
|
+
${blue("OPENCODE_BASE_URL")} OpenCode Zen ${dim4("(default: https://opencode.ai/zen)")}
|
|
75298
76223
|
|
|
75299
76224
|
${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 ${
|
|
76225
|
+
${blue("OLLAMA_BASE_URL")} Ollama server ${dim4("(default: http://localhost:11434; alias OLLAMA_HOST)")}
|
|
76226
|
+
${blue("LMSTUDIO_BASE_URL")} LM Studio server ${dim4("(default: http://localhost:1234)")}
|
|
76227
|
+
${blue("VLLM_BASE_URL")} vLLM server ${dim4("(default: http://localhost:8000)")}
|
|
76228
|
+
${blue("MLX_BASE_URL")} MLX server ${dim4("(default: http://127.0.0.1:8080)")}
|
|
75304
76229
|
|
|
75305
76230
|
${bold4("Claudish settings:")}
|
|
75306
|
-
${blue("CLAUDISH_MODEL")} Default model ${
|
|
75307
|
-
${blue("CLAUDISH_DEFAULT_PROVIDER")} Fallback provider for bare names ${
|
|
76231
|
+
${blue("CLAUDISH_MODEL")} Default model ${dim4("(default: openai/gpt-5.3)")}
|
|
76232
|
+
${blue("CLAUDISH_DEFAULT_PROVIDER")} Fallback provider for bare names ${dim4("(see --default-provider)")}
|
|
75308
76233
|
${blue("CLAUDISH_PORT")} Default proxy port
|
|
75309
76234
|
${blue("CLAUDISH_CONTEXT_WINDOW")} Override context window size
|
|
75310
76235
|
${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 ${
|
|
76236
|
+
${blue("CLAUDISH_DEBUG")} Always enable debug logging: 1 / true ${dim4("(same as -d)")}
|
|
76237
|
+
${blue("CLAUDISH_ANTHROPIC_API_BILLING")} Bill native Claude to your API key ${dim4("(see --anthropic-api-billing)")}
|
|
75313
76238
|
${blue("CLAUDISH_MCP_TOOLS")} MCP tool gating: all / low-level / agentic / channel
|
|
75314
76239
|
${blue("CLAUDISH_MODEL_OPUS")} Override model for Opus role
|
|
75315
76240
|
${blue("CLAUDISH_MODEL_SONNET")} Override model for Sonnet role
|
|
@@ -75319,39 +76244,39 @@ ${h("ENVIRONMENT VARIABLES")}
|
|
|
75319
76244
|
|
|
75320
76245
|
${bold4("1Password auth:")}
|
|
75321
76246
|
${blue("OP_SERVICE_ACCOUNT_TOKEN")} Service-account token (preferred for headless)
|
|
75322
|
-
${blue("OP_ACCOUNT")} Account URL for DesktopAuth ${
|
|
76247
|
+
${blue("OP_ACCOUNT")} Account URL for DesktopAuth ${dim4("(e.g. my-team.1password.com)")}
|
|
75323
76248
|
|
|
75324
76249
|
${h("EXAMPLES")}
|
|
75325
|
-
${
|
|
76250
|
+
${dim4("# Interactive (default) - model selector")}
|
|
75326
76251
|
${green2("claudish")}
|
|
75327
|
-
${green2("claudish")} --free ${
|
|
76252
|
+
${green2("claudish")} --free ${dim4("# only FREE models")}
|
|
75328
76253
|
|
|
75329
|
-
${
|
|
76254
|
+
${dim4("# Explicit provider routing")}
|
|
75330
76255
|
${green2("claudish")} --model ${magenta("google@gemini-3-pro")} ${yellow2('"implement auth"')}
|
|
75331
76256
|
${green2("claudish")} --model ${magenta("oai@gpt-5.3")} ${yellow2('"add tests for login"')}
|
|
75332
76257
|
${green2("claudish")} --model ${magenta("openrouter@deepseek/deepseek-r1")} ${yellow2('"unknown vendor"')}
|
|
75333
76258
|
|
|
75334
|
-
${
|
|
76259
|
+
${dim4("# Native auto-detection (provider inferred from model name)")}
|
|
75335
76260
|
${green2("claudish")} --model ${yellow2("gpt-4o")} ${yellow2('"routes to OpenAI"')}
|
|
75336
76261
|
${green2("claudish")} --model ${yellow2("gemini-2.5-pro")} ${yellow2('"routes to Google"')}
|
|
75337
76262
|
|
|
75338
|
-
${
|
|
76263
|
+
${dim4("# Per-role model mapping")}
|
|
75339
76264
|
${green2("claudish")} --model-opus ${magenta("oai@gpt-5.3")} --model-sonnet ${magenta("google@gemini-3-pro")}
|
|
75340
76265
|
|
|
75341
|
-
${
|
|
75342
|
-
${
|
|
76266
|
+
${dim4("# stdin for large prompts (diffs, code review)")}
|
|
76267
|
+
${dim4("git diff |")} ${green2("claudish")} --stdin --model ${magenta("oai@gpt-5.3")} ${yellow2('"Review these changes"')}
|
|
75343
76268
|
|
|
75344
|
-
${
|
|
76269
|
+
${dim4("# Local models with concurrency control")}
|
|
75345
76270
|
${green2("claudish")} --model ${magenta("ollama@llama3.2:3")} ${yellow2('"3 concurrent requests"')}
|
|
75346
76271
|
${green2("claudish")} --model ${magenta("lms@qwen2.5-coder")} ${yellow2('"LM Studio shortcut"')}
|
|
75347
76272
|
${green2("claudish")} --model ${yellow2('"http://localhost:8000/mistral"')} ${yellow2('"any OpenAI-compatible URL"')}
|
|
75348
76273
|
|
|
75349
|
-
${
|
|
76274
|
+
${dim4("# Autonomous (no prompts, no sandbox) \u2014 use with caution")}
|
|
75350
76275
|
${green2("claudish")} -y --dangerous ${yellow2('"refactor entire codebase"')}
|
|
75351
76276
|
|
|
75352
76277
|
${h("MORE INFO")}
|
|
75353
|
-
${
|
|
75354
|
-
${
|
|
76278
|
+
${dim4("GitHub:")} ${blue("https://github.com/MadAppGang/claude-code")}
|
|
76279
|
+
${dim4("OpenRouter:")} ${blue("https://openrouter.ai")}
|
|
75355
76280
|
`);
|
|
75356
76281
|
}
|
|
75357
76282
|
function printAIAgentGuide() {
|
|
@@ -76714,6 +77639,8 @@ function Footer({ activeTab, mode, probeMode, providerCaps }) {
|
|
|
76714
77639
|
[C.blue, "\u2191\u2193", "navigate"],
|
|
76715
77640
|
[C.green, "a", "add"],
|
|
76716
77641
|
[C.cyan, "t", "test"],
|
|
77642
|
+
[C.magenta, "c", "\u2192keychain"],
|
|
77643
|
+
[C.magenta, "C", "all\u2192keychain"],
|
|
76717
77644
|
[C.green, "o", "account"],
|
|
76718
77645
|
[C.red, "x", "remove"],
|
|
76719
77646
|
[C.blue, "Tab", "section"],
|
|
@@ -78885,8 +79812,6 @@ function resolveProviderDetailKeyDisplay(input) {
|
|
|
78885
79812
|
return input.envKeyMask;
|
|
78886
79813
|
if (input.hasCfgKey)
|
|
78887
79814
|
return input.cfgKeyMask;
|
|
78888
|
-
if (input.isPublicKey)
|
|
78889
|
-
return "free";
|
|
78890
79815
|
return "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
|
|
78891
79816
|
}
|
|
78892
79817
|
function ProviderDetail({
|
|
@@ -78900,7 +79825,9 @@ function ProviderDetail({
|
|
|
78900
79825
|
hasKey,
|
|
78901
79826
|
authSource,
|
|
78902
79827
|
isOpKey,
|
|
78903
|
-
|
|
79828
|
+
isKcKey,
|
|
79829
|
+
hasKcKey,
|
|
79830
|
+
keySaveTarget,
|
|
78904
79831
|
cfgKeyMask,
|
|
78905
79832
|
envKeyMask,
|
|
78906
79833
|
activeEndpoint,
|
|
@@ -78914,7 +79841,6 @@ function ProviderDetail({
|
|
|
78914
79841
|
authSource,
|
|
78915
79842
|
hasEnvKey,
|
|
78916
79843
|
hasCfgKey,
|
|
78917
|
-
isPublicKey,
|
|
78918
79844
|
envKeyMask,
|
|
78919
79845
|
cfgKeyMask
|
|
78920
79846
|
});
|
|
@@ -78924,7 +79850,7 @@ function ProviderDetail({
|
|
|
78924
79850
|
border: true,
|
|
78925
79851
|
borderStyle: "single",
|
|
78926
79852
|
borderColor: C.focusBorder,
|
|
78927
|
-
title:
|
|
79853
|
+
title: mode === "input_key" ? ` Set API Key \u2014 ${selectedProvider.displayName} \u2192 ${keySaveTarget} ` : ` Set Endpoint \u2014 ${selectedProvider.displayName} `,
|
|
78928
79854
|
backgroundColor: C.bg,
|
|
78929
79855
|
flexDirection: "column",
|
|
78930
79856
|
paddingX: 1,
|
|
@@ -79058,7 +79984,7 @@ function ProviderDetail({
|
|
|
79058
79984
|
})
|
|
79059
79985
|
]
|
|
79060
79986
|
}),
|
|
79061
|
-
hasKey && !selectedProvider.isLocal &&
|
|
79987
|
+
hasKey && !selectedProvider.isLocal && isOAuth && /* @__PURE__ */ jsxs10(Fragment7, {
|
|
79062
79988
|
children: [
|
|
79063
79989
|
/* @__PURE__ */ jsx11("span", {
|
|
79064
79990
|
fg: C.dim,
|
|
@@ -79070,9 +79996,13 @@ function ProviderDetail({
|
|
|
79070
79996
|
children: "From: "
|
|
79071
79997
|
}),
|
|
79072
79998
|
/* @__PURE__ */ jsx11("span", {
|
|
79073
|
-
fg: C.
|
|
79999
|
+
fg: C.cyan,
|
|
79074
80000
|
attributes: A.bold,
|
|
79075
|
-
children: "
|
|
80001
|
+
children: "oauth"
|
|
80002
|
+
}),
|
|
80003
|
+
/* @__PURE__ */ jsx11("span", {
|
|
80004
|
+
fg: C.fgMuted,
|
|
80005
|
+
children: " (used)"
|
|
79076
80006
|
})
|
|
79077
80007
|
]
|
|
79078
80008
|
}),
|
|
@@ -79094,7 +80024,7 @@ function ProviderDetail({
|
|
|
79094
80024
|
})
|
|
79095
80025
|
]
|
|
79096
80026
|
}),
|
|
79097
|
-
hasKey && !selectedProvider.isLocal && !
|
|
80027
|
+
hasKey && !selectedProvider.isLocal && !isOAuth && /* @__PURE__ */ jsxs10(Fragment7, {
|
|
79098
80028
|
children: [
|
|
79099
80029
|
/* @__PURE__ */ jsx11("span", {
|
|
79100
80030
|
fg: C.dim,
|
|
@@ -79108,7 +80038,7 @@ function ProviderDetail({
|
|
|
79108
80038
|
hasEnvKey && /* @__PURE__ */ jsx11("span", {
|
|
79109
80039
|
fg: C.green,
|
|
79110
80040
|
attributes: A.bold,
|
|
79111
|
-
children: isOpKey ? "1Password" : "env"
|
|
80041
|
+
children: isKcKey ? "keychain" : isOpKey ? "1Password" : "env"
|
|
79112
80042
|
}),
|
|
79113
80043
|
hasEnvKey && hasCfgKey && /* @__PURE__ */ jsx11("span", {
|
|
79114
80044
|
fg: C.fgMuted,
|
|
@@ -79126,6 +80056,18 @@ function ProviderDetail({
|
|
|
79126
80056
|
hasCfgKey && /* @__PURE__ */ jsx11("span", {
|
|
79127
80057
|
fg: C.fgMuted,
|
|
79128
80058
|
children: hasEnvKey ? " (shadowed)" : " (used)"
|
|
80059
|
+
}),
|
|
80060
|
+
hasKcKey && !isKcKey && /* @__PURE__ */ jsxs10(Fragment7, {
|
|
80061
|
+
children: [
|
|
80062
|
+
/* @__PURE__ */ jsx11("span", {
|
|
80063
|
+
fg: C.fgMuted,
|
|
80064
|
+
children: " + "
|
|
80065
|
+
}),
|
|
80066
|
+
/* @__PURE__ */ jsx11("span", {
|
|
80067
|
+
fg: C.fgMuted,
|
|
80068
|
+
children: "keychain (shadowed)"
|
|
80069
|
+
})
|
|
80070
|
+
]
|
|
79129
80071
|
})
|
|
79130
80072
|
]
|
|
79131
80073
|
})
|
|
@@ -79302,8 +80244,6 @@ function ProvidersContent({
|
|
|
79302
80244
|
keyDisplay = "local";
|
|
79303
80245
|
} else if (isOauthOnly) {
|
|
79304
80246
|
keyDisplay = "oauth\xB7\xB7\xB7";
|
|
79305
|
-
} else if (auth === "public") {
|
|
79306
|
-
keyDisplay = "free";
|
|
79307
80247
|
} else if (auth === "cfg") {
|
|
79308
80248
|
keyDisplay = maskKey2(config3.apiKeys?.[p.apiKeyEnvVar]);
|
|
79309
80249
|
} else if (auth === "env" || auth === "e+c") {
|
|
@@ -80734,18 +81674,18 @@ function useProfileWizard(args) {
|
|
|
80734
81674
|
setEditProfileValue("");
|
|
80735
81675
|
return;
|
|
80736
81676
|
}
|
|
80737
|
-
const
|
|
81677
|
+
const now2 = new Date().toISOString();
|
|
80738
81678
|
if (profileScope === "project") {
|
|
80739
81679
|
const localCfg = loadLocalConfig() ?? {
|
|
80740
81680
|
version: "1.0.0",
|
|
80741
81681
|
defaultProfile: "",
|
|
80742
81682
|
profiles: {}
|
|
80743
81683
|
};
|
|
80744
|
-
localCfg.profiles[name] = { name, models: {}, createdAt:
|
|
81684
|
+
localCfg.profiles[name] = { name, models: {}, createdAt: now2, updatedAt: now2 };
|
|
80745
81685
|
saveLocalConfig(localCfg);
|
|
80746
81686
|
} else {
|
|
80747
81687
|
const cfg = loadConfig();
|
|
80748
|
-
cfg.profiles[name] = { name, models: {}, createdAt:
|
|
81688
|
+
cfg.profiles[name] = { name, models: {}, createdAt: now2, updatedAt: now2 };
|
|
80749
81689
|
saveConfig(cfg);
|
|
80750
81690
|
}
|
|
80751
81691
|
refreshConfig();
|
|
@@ -81100,20 +82040,20 @@ function useRouteProbe(config3) {
|
|
|
81100
82040
|
errorMessage: String(e instanceof Error ? e.message : e)
|
|
81101
82041
|
}));
|
|
81102
82042
|
const ms = Date.now() - startMs;
|
|
81103
|
-
const
|
|
82043
|
+
const ok2 = result.state === "live";
|
|
81104
82044
|
setProbeResults((prev) => prev.map((e, idx) => {
|
|
81105
82045
|
if (idx === i)
|
|
81106
82046
|
return {
|
|
81107
82047
|
...e,
|
|
81108
|
-
status:
|
|
81109
|
-
error:
|
|
82048
|
+
status: ok2 ? "success" : "failed",
|
|
82049
|
+
error: ok2 ? undefined : describeProbeState(result),
|
|
81110
82050
|
ms
|
|
81111
82051
|
};
|
|
81112
|
-
if (idx > i &&
|
|
82052
|
+
if (idx > i && ok2 && e.status !== "no_key")
|
|
81113
82053
|
return { ...e, status: "skipped" };
|
|
81114
82054
|
return e;
|
|
81115
82055
|
}));
|
|
81116
|
-
if (
|
|
82056
|
+
if (ok2)
|
|
81117
82057
|
break;
|
|
81118
82058
|
}
|
|
81119
82059
|
setProbeMode("done");
|
|
@@ -81153,6 +82093,50 @@ var init_useRouteProbe = __esm(() => {
|
|
|
81153
82093
|
import { useKeyboard as useKeyboard2, useRenderer, useTerminalDimensions as useTerminalDimensions2 } from "@opentui/react";
|
|
81154
82094
|
import { useCallback as useCallback3, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState5 } from "react";
|
|
81155
82095
|
import { jsx as jsx16, jsxs as jsxs15, Fragment as Fragment10 } from "@opentui/react/jsx-runtime";
|
|
82096
|
+
async function resolveOpEntrySecrets(entries, auth) {
|
|
82097
|
+
const secrets = {};
|
|
82098
|
+
for (const entry of entries) {
|
|
82099
|
+
if (entry.kind === "environment") {
|
|
82100
|
+
Object.assign(secrets, await withSdkRetry(() => readEnvironment(entry.value, { auth }), "tui:copy-keychain"));
|
|
82101
|
+
} else if (entry.kind === "glob" || isGlobImport(entry.value)) {
|
|
82102
|
+
Object.assign(secrets, await withSdkRetry(() => resolveGlobImport(entry.value, { auth }), "tui:copy-keychain"));
|
|
82103
|
+
} else {
|
|
82104
|
+
const r = await withSdkRetry(() => resolveSecrets({ T: entry.value }, { auth }), "tui:copy-keychain");
|
|
82105
|
+
const name = envNameFromOpRef(entry.value);
|
|
82106
|
+
if (name && r.T)
|
|
82107
|
+
secrets[name] = r.T;
|
|
82108
|
+
}
|
|
82109
|
+
}
|
|
82110
|
+
return secrets;
|
|
82111
|
+
}
|
|
82112
|
+
function writeSecretsToKeychain(secrets, alreadyStored) {
|
|
82113
|
+
const outcome = { created: 0, replaced: 0, skipped: [] };
|
|
82114
|
+
for (const [name, value] of Object.entries(secrets)) {
|
|
82115
|
+
if (!value)
|
|
82116
|
+
continue;
|
|
82117
|
+
try {
|
|
82118
|
+
writeKeychainSecret(name, value);
|
|
82119
|
+
if (alreadyStored.has(name))
|
|
82120
|
+
outcome.replaced++;
|
|
82121
|
+
else
|
|
82122
|
+
outcome.created++;
|
|
82123
|
+
} catch {
|
|
82124
|
+
outcome.skipped.push(name);
|
|
82125
|
+
}
|
|
82126
|
+
}
|
|
82127
|
+
return outcome;
|
|
82128
|
+
}
|
|
82129
|
+
function describeCopyOutcome({ created, replaced, skipped }) {
|
|
82130
|
+
if (created + replaced === 0) {
|
|
82131
|
+
return `Nothing copied to the Keychain${skipped.length > 0 ? ` \u2014 ${skipped.length} could not be stored` : ""}.`;
|
|
82132
|
+
}
|
|
82133
|
+
const parts = [`${created} new`];
|
|
82134
|
+
if (replaced > 0)
|
|
82135
|
+
parts.push(`${replaced} replaced`);
|
|
82136
|
+
if (skipped.length > 0)
|
|
82137
|
+
parts.push(`${skipped.length} skipped (${skipped.join(", ")})`);
|
|
82138
|
+
return `Copied to macOS Keychain: ${parts.join(" \xB7 ")}.`;
|
|
82139
|
+
}
|
|
81156
82140
|
function App({ requestLogin } = {}) {
|
|
81157
82141
|
const renderer = useRenderer();
|
|
81158
82142
|
const { width, height: height2 } = useTerminalDimensions2();
|
|
@@ -81162,6 +82146,9 @@ function App({ requestLogin } = {}) {
|
|
|
81162
82146
|
const [activeTab, setActiveTab] = useState5("providers");
|
|
81163
82147
|
const [mode, setMode] = useState5("browse");
|
|
81164
82148
|
const [inputValue, setInputValue] = useState5("");
|
|
82149
|
+
const [keychainVars, setKeychainVars] = useState5(new Set);
|
|
82150
|
+
const keychainSupported = useMemo2(() => isKeychainSupported(), []);
|
|
82151
|
+
const inputTargetRef = useRef4(null);
|
|
81165
82152
|
const [routingPattern, setRoutingPattern] = useState5("");
|
|
81166
82153
|
const [chainSelected, setChainSelected] = useState5(new Set);
|
|
81167
82154
|
const [chainOrder, setChainOrder] = useState5([]);
|
|
@@ -81249,6 +82236,36 @@ function App({ requestLogin } = {}) {
|
|
|
81249
82236
|
setBufStats(getBufferStats());
|
|
81250
82237
|
setOpTick((t) => t + 1);
|
|
81251
82238
|
}, []);
|
|
82239
|
+
const refreshKeychainVars = useCallback3(() => {
|
|
82240
|
+
if (!hasKeychainSource()) {
|
|
82241
|
+
setKeychainVars(new Set);
|
|
82242
|
+
return;
|
|
82243
|
+
}
|
|
82244
|
+
try {
|
|
82245
|
+
setKeychainVars(new Set(listKeychainVars()));
|
|
82246
|
+
} catch {
|
|
82247
|
+
setKeychainVars(new Set);
|
|
82248
|
+
}
|
|
82249
|
+
}, []);
|
|
82250
|
+
useEffect4(() => {
|
|
82251
|
+
if (!keychainSupported)
|
|
82252
|
+
return;
|
|
82253
|
+
let cancelled = false;
|
|
82254
|
+
(async () => {
|
|
82255
|
+
let hydrated = 0;
|
|
82256
|
+
try {
|
|
82257
|
+
hydrated = await hydrateKeychainIntoEnv();
|
|
82258
|
+
} catch {}
|
|
82259
|
+
if (cancelled)
|
|
82260
|
+
return;
|
|
82261
|
+
refreshKeychainVars();
|
|
82262
|
+
if (hydrated > 0)
|
|
82263
|
+
refreshConfig();
|
|
82264
|
+
})();
|
|
82265
|
+
return () => {
|
|
82266
|
+
cancelled = true;
|
|
82267
|
+
};
|
|
82268
|
+
}, [keychainSupported, refreshKeychainVars, refreshConfig]);
|
|
81252
82269
|
const clearTestResult = useCallback3((provName) => {
|
|
81253
82270
|
setTestResults((prev) => {
|
|
81254
82271
|
if (!(provName in prev))
|
|
@@ -81264,11 +82281,12 @@ function App({ requestLogin } = {}) {
|
|
|
81264
82281
|
const { editProfileValue, profileScope, suggestions, suggestionIndex, providerPickerIndex } = wizard;
|
|
81265
82282
|
const hasCfgKey = !!config3.apiKeys?.[selectedProvider.apiKeyEnvVar];
|
|
81266
82283
|
const hasEnvKey = !!process.env[selectedProvider.apiKeyEnvVar];
|
|
82284
|
+
const providerKeychainVars = useMemo2(() => [selectedProvider.apiKeyEnvVar, ...selectedProvider.aliases ?? []].filter((n) => !!n && keychainVars.has(n)), [selectedProvider, keychainVars]);
|
|
82285
|
+
const hasKcKey = providerKeychainVars.length > 0;
|
|
81267
82286
|
const selectedAuthSource = providerAuthSource(selectedProvider, config3);
|
|
81268
|
-
const
|
|
81269
|
-
const hasKey = selectedAuthSource !== null || selectedLocalRunning;
|
|
81270
|
-
const selectedPublicKey = selectedAuthSource === "public";
|
|
82287
|
+
const hasKey = providerIsReadyForDisplay(selectedProvider, config3, localLiveness);
|
|
81271
82288
|
const isOpKey = hasEnvKey && isOpHydratedVar(selectedProvider.apiKeyEnvVar);
|
|
82289
|
+
const isKcKey = hasEnvKey && isKeychainHydratedVar(selectedProvider.apiKeyEnvVar);
|
|
81272
82290
|
const cfgKeyMask = maskKey2(config3.apiKeys?.[selectedProvider.apiKeyEnvVar]);
|
|
81273
82291
|
const envKeyMask = maskKey2(process.env[selectedProvider.apiKeyEnvVar]);
|
|
81274
82292
|
const activeEndpointEnvVar = selectedProvider.endpointEnvVar;
|
|
@@ -81445,6 +82463,36 @@ function App({ requestLogin } = {}) {
|
|
|
81445
82463
|
setOpBusy(false);
|
|
81446
82464
|
}
|
|
81447
82465
|
}, [acquireOpAuth]);
|
|
82466
|
+
const copyOpToKeychain = useCallback3(async (entries, label) => {
|
|
82467
|
+
if (!keychainSupported) {
|
|
82468
|
+
setStatusMsg("macOS Keychain is only available on macOS.");
|
|
82469
|
+
return;
|
|
82470
|
+
}
|
|
82471
|
+
const copyable = entries.filter((e) => e.kind !== "account");
|
|
82472
|
+
if (copyable.length === 0) {
|
|
82473
|
+
setStatusMsg("Nothing to copy \u2014 the account entry holds no secret.");
|
|
82474
|
+
return;
|
|
82475
|
+
}
|
|
82476
|
+
setOpBusy(true);
|
|
82477
|
+
setStatusMsg(`Resolving ${label} from 1Password\u2026`);
|
|
82478
|
+
try {
|
|
82479
|
+
const auth = await acquireOpAuth();
|
|
82480
|
+
const secrets = await resolveOpEntrySecrets(copyable, auth);
|
|
82481
|
+
const outcome = writeSecretsToKeychain(secrets, new Set(keychainVars));
|
|
82482
|
+
if (outcome.created + outcome.replaced > 0) {
|
|
82483
|
+
setKeychainEnabled(true);
|
|
82484
|
+
refreshKeychainVars();
|
|
82485
|
+
credentials.invalidate();
|
|
82486
|
+
invalidateProbeProxyHandlers();
|
|
82487
|
+
refreshConfig();
|
|
82488
|
+
}
|
|
82489
|
+
setStatusMsg(describeCopyOutcome(outcome));
|
|
82490
|
+
} catch (err) {
|
|
82491
|
+
setStatusMsg(err instanceof Error ? err.message : String(err));
|
|
82492
|
+
} finally {
|
|
82493
|
+
setOpBusy(false);
|
|
82494
|
+
}
|
|
82495
|
+
}, [acquireOpAuth, keychainSupported, keychainVars, refreshKeychainVars, refreshConfig]);
|
|
81448
82496
|
const resetOpWizard = useCallback3(() => {
|
|
81449
82497
|
setInputValue("");
|
|
81450
82498
|
setOpPendingValue("");
|
|
@@ -81767,26 +82815,49 @@ function App({ requestLogin } = {}) {
|
|
|
81767
82815
|
setMode("browse");
|
|
81768
82816
|
return;
|
|
81769
82817
|
}
|
|
82818
|
+
const target = inputTargetRef.current ?? selectedProvider;
|
|
81770
82819
|
if (mode === "input_key") {
|
|
81771
|
-
if (!
|
|
81772
|
-
setStatusMsg(`${
|
|
82820
|
+
if (!target.apiKeyEnvVar) {
|
|
82821
|
+
setStatusMsg(`${target.displayName} has no apiKeyEnvVar \u2014 cannot save key.`);
|
|
81773
82822
|
} else {
|
|
81774
|
-
|
|
81775
|
-
|
|
81776
|
-
|
|
82823
|
+
const envVar = target.apiKeyEnvVar;
|
|
82824
|
+
let saved = false;
|
|
82825
|
+
if (keychainSupported) {
|
|
82826
|
+
try {
|
|
82827
|
+
writeKeychainSecret(envVar, val);
|
|
82828
|
+
setKeychainEnabled(true);
|
|
82829
|
+
process.env[envVar] = val;
|
|
82830
|
+
recordKeychainHydratedVar(envVar);
|
|
82831
|
+
refreshKeychainVars();
|
|
82832
|
+
setStatusMsg(`Key saved to macOS Keychain for ${target.displayName} (${envVar}).`);
|
|
82833
|
+
saved = true;
|
|
82834
|
+
} catch (err) {
|
|
82835
|
+
setStatusMsg(`Keychain write failed (${err instanceof Error ? err.message : String(err)}) \u2014 saved to config.json instead.`);
|
|
82836
|
+
}
|
|
82837
|
+
}
|
|
82838
|
+
if (!saved) {
|
|
82839
|
+
setApiKey(envVar, val);
|
|
82840
|
+
process.env[envVar] = val;
|
|
82841
|
+
if (!keychainSupported) {
|
|
82842
|
+
setStatusMsg(`Key saved for ${target.displayName} (${envVar}).`);
|
|
82843
|
+
}
|
|
82844
|
+
}
|
|
82845
|
+
credentials.invalidate(target.catalogName);
|
|
82846
|
+
invalidateProbeProxyHandlers(target.catalogName);
|
|
82847
|
+
clearTestResult(target.name);
|
|
81777
82848
|
}
|
|
81778
82849
|
} else {
|
|
81779
|
-
if (!
|
|
81780
|
-
setStatusMsg(`${
|
|
82850
|
+
if (!target.endpointEnvVar) {
|
|
82851
|
+
setStatusMsg(`${target.displayName} has no endpointEnvVar \u2014 cannot save URL.`);
|
|
81781
82852
|
} else {
|
|
81782
|
-
setEndpoint(
|
|
81783
|
-
process.env[
|
|
81784
|
-
setStatusMsg(`URL saved for ${
|
|
82853
|
+
setEndpoint(target.endpointEnvVar, val);
|
|
82854
|
+
process.env[target.endpointEnvVar] = val;
|
|
82855
|
+
setStatusMsg(`URL saved for ${target.displayName} (${target.endpointEnvVar}=${val}).`);
|
|
81785
82856
|
}
|
|
81786
82857
|
}
|
|
81787
|
-
invalidateProbeProxyHandlers(
|
|
81788
|
-
invalidateProbeDiscovery(
|
|
81789
|
-
clearTestResult(
|
|
82858
|
+
invalidateProbeProxyHandlers(target.catalogName);
|
|
82859
|
+
invalidateProbeDiscovery(target.catalogName);
|
|
82860
|
+
clearTestResult(target.name);
|
|
81790
82861
|
refreshConfig();
|
|
81791
82862
|
setInputValue("");
|
|
81792
82863
|
setMode("browse");
|
|
@@ -82255,10 +83326,12 @@ function App({ requestLogin } = {}) {
|
|
|
82255
83326
|
setStatusMsg(null);
|
|
82256
83327
|
} else if (key.name === "s") {
|
|
82257
83328
|
if (selectedProvider.apiKeyEnvVar) {
|
|
83329
|
+
inputTargetRef.current = selectedProvider;
|
|
82258
83330
|
setInputValue("");
|
|
82259
83331
|
setStatusMsg(null);
|
|
82260
83332
|
setMode("input_key");
|
|
82261
83333
|
} else if (selectedProvider.endpointEnvVar) {
|
|
83334
|
+
inputTargetRef.current = selectedProvider;
|
|
82262
83335
|
setInputValue(activeEndpoint);
|
|
82263
83336
|
setStatusMsg(null);
|
|
82264
83337
|
setMode("input_endpoint");
|
|
@@ -82276,6 +83349,7 @@ function App({ requestLogin } = {}) {
|
|
|
82276
83349
|
}
|
|
82277
83350
|
refreshConfig();
|
|
82278
83351
|
} else if (selectedProvider.endpointEnvVar) {
|
|
83352
|
+
inputTargetRef.current = selectedProvider;
|
|
82279
83353
|
setInputValue(activeEndpoint);
|
|
82280
83354
|
setStatusMsg(null);
|
|
82281
83355
|
setMode("input_endpoint");
|
|
@@ -82284,6 +83358,7 @@ function App({ requestLogin } = {}) {
|
|
|
82284
83358
|
}
|
|
82285
83359
|
} else if (key.name === "u") {
|
|
82286
83360
|
if (selectedProvider.endpointEnvVar) {
|
|
83361
|
+
inputTargetRef.current = selectedProvider;
|
|
82287
83362
|
setInputValue(activeEndpoint);
|
|
82288
83363
|
setStatusMsg(null);
|
|
82289
83364
|
setMode("input_endpoint");
|
|
@@ -82292,24 +83367,43 @@ function App({ requestLogin } = {}) {
|
|
|
82292
83367
|
}
|
|
82293
83368
|
} else if (key.name === "x") {
|
|
82294
83369
|
let changed = false;
|
|
83370
|
+
const removedFrom = [];
|
|
83371
|
+
let failureMsg = null;
|
|
82295
83372
|
if (hasCfgKey) {
|
|
82296
83373
|
removeApiKey(selectedProvider.apiKeyEnvVar);
|
|
83374
|
+
removedFrom.push("config.json");
|
|
82297
83375
|
changed = true;
|
|
82298
83376
|
}
|
|
83377
|
+
if (keychainSupported) {
|
|
83378
|
+
for (const name of providerKeychainVars) {
|
|
83379
|
+
try {
|
|
83380
|
+
if (deleteKeychainSecret(name)) {
|
|
83381
|
+
removedFrom.push(`macOS Keychain (${name})`);
|
|
83382
|
+
changed = true;
|
|
83383
|
+
}
|
|
83384
|
+
} catch (err) {
|
|
83385
|
+
failureMsg = `Keychain delete failed for ${name}: ${err instanceof Error ? err.message : String(err)}`;
|
|
83386
|
+
}
|
|
83387
|
+
}
|
|
83388
|
+
if (providerKeychainVars.length > 0)
|
|
83389
|
+
refreshKeychainVars();
|
|
83390
|
+
}
|
|
83391
|
+
if (changed && (isKcKey || isOpKey)) {
|
|
83392
|
+
delete process.env[selectedProvider.apiKeyEnvVar];
|
|
83393
|
+
}
|
|
82299
83394
|
if (activeEndpointEnvVar && config3.endpoints?.[activeEndpointEnvVar]) {
|
|
82300
83395
|
removeEndpoint(activeEndpointEnvVar);
|
|
82301
83396
|
delete process.env[activeEndpointEnvVar];
|
|
82302
83397
|
changed = true;
|
|
82303
83398
|
}
|
|
82304
83399
|
if (changed) {
|
|
83400
|
+
credentials.invalidate(selectedProvider.catalogName);
|
|
82305
83401
|
invalidateProbeProxyHandlers(selectedProvider.catalogName);
|
|
82306
83402
|
invalidateProbeDiscovery(selectedProvider.catalogName);
|
|
82307
83403
|
clearTestResult(selectedProvider.name);
|
|
82308
83404
|
refreshConfig();
|
|
82309
|
-
setStatusMsg(`Stored config removed for ${selectedProvider.displayName}.`);
|
|
82310
|
-
} else {
|
|
82311
|
-
setStatusMsg("No stored config to remove.");
|
|
82312
83405
|
}
|
|
83406
|
+
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
83407
|
} else if (key.name === "l") {
|
|
82314
83408
|
const slug = selectedProvider.oauthSlug;
|
|
82315
83409
|
if (!slug) {
|
|
@@ -82534,6 +83628,18 @@ function App({ requestLogin } = {}) {
|
|
|
82534
83628
|
} else if (selectedOpEntry) {
|
|
82535
83629
|
testOpEntry(selectedOpEntry);
|
|
82536
83630
|
}
|
|
83631
|
+
} else if (key.raw === "C") {
|
|
83632
|
+
if (opEntries.length === 0) {
|
|
83633
|
+
setStatusMsg("No 1Password entries to copy.");
|
|
83634
|
+
} else {
|
|
83635
|
+
copyOpToKeychain(opEntries, `all ${opEntries.length} entries`);
|
|
83636
|
+
}
|
|
83637
|
+
} else if (key.name === "c") {
|
|
83638
|
+
if (opEntries.length === 0 || !selectedOpEntry) {
|
|
83639
|
+
setStatusMsg("No 1Password entry to copy.");
|
|
83640
|
+
} else {
|
|
83641
|
+
copyOpToKeychain([selectedOpEntry], selectedOpEntry.envName ?? selectedOpEntry.value);
|
|
83642
|
+
}
|
|
82537
83643
|
} else if (key.name === "x") {
|
|
82538
83644
|
if (opEntries.length === 0 || !selectedOpEntry) {
|
|
82539
83645
|
setStatusMsg("No 1Password entry to remove.");
|
|
@@ -82670,7 +83776,9 @@ function App({ requestLogin } = {}) {
|
|
|
82670
83776
|
hasKey,
|
|
82671
83777
|
authSource: selectedAuthSource,
|
|
82672
83778
|
isOpKey,
|
|
82673
|
-
|
|
83779
|
+
isKcKey,
|
|
83780
|
+
hasKcKey,
|
|
83781
|
+
keySaveTarget: keychainSupported ? "macOS Keychain" : "config.json",
|
|
82674
83782
|
cfgKeyMask,
|
|
82675
83783
|
envKeyMask,
|
|
82676
83784
|
activeEndpoint,
|
|
@@ -82798,10 +83906,13 @@ function App({ requestLogin } = {}) {
|
|
|
82798
83906
|
});
|
|
82799
83907
|
}
|
|
82800
83908
|
var init_App = __esm(() => {
|
|
83909
|
+
init_authority();
|
|
83910
|
+
init_keychain_source();
|
|
82801
83911
|
init_op_source();
|
|
82802
83912
|
init_profile_config();
|
|
82803
83913
|
init_default_routing_rules();
|
|
82804
83914
|
init_endpoint_registration();
|
|
83915
|
+
init_keychain();
|
|
82805
83916
|
init_local_liveness();
|
|
82806
83917
|
init_onepassword_config();
|
|
82807
83918
|
init_onepassword();
|
|
@@ -83038,10 +84149,10 @@ function shouldHideIncidentalAnthropicKey(config3, env = process.env) {
|
|
|
83038
84149
|
return false;
|
|
83039
84150
|
return !wantsAnthropicApiBilling(config3, env);
|
|
83040
84151
|
}
|
|
83041
|
-
function hasResolvableAnthropicAuth(
|
|
83042
|
-
const env =
|
|
83043
|
-
const fileExists =
|
|
83044
|
-
const keychainProbe =
|
|
84152
|
+
function hasResolvableAnthropicAuth(deps2 = {}) {
|
|
84153
|
+
const env = deps2.env ?? process.env;
|
|
84154
|
+
const fileExists = deps2.fileExists ?? existsSync30;
|
|
84155
|
+
const keychainProbe = deps2.keychainProbe ?? defaultKeychainAnthropicProbe;
|
|
83045
84156
|
if (env.ANTHROPIC_API_KEY || env.ANTHROPIC_AUTH_TOKEN)
|
|
83046
84157
|
return true;
|
|
83047
84158
|
if (fileExists(join40(homedir35(), ".claude", ".credentials.json")))
|
|
@@ -83233,7 +84344,7 @@ function initializeTokenFile(tokenFilePath) {
|
|
|
83233
84344
|
log(`[claude-runner] Could not initialize token file ${tokenFilePath}: ${e}`);
|
|
83234
84345
|
}
|
|
83235
84346
|
}
|
|
83236
|
-
function cleanupStaleTokenFiles(dir,
|
|
84347
|
+
function cleanupStaleTokenFiles(dir, now2 = Date.now(), maxAgeMs = STALE_TOKEN_FILE_MS) {
|
|
83237
84348
|
let removed = 0;
|
|
83238
84349
|
let entries;
|
|
83239
84350
|
try {
|
|
@@ -83241,7 +84352,7 @@ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FI
|
|
|
83241
84352
|
} catch {
|
|
83242
84353
|
return 0;
|
|
83243
84354
|
}
|
|
83244
|
-
const cutoff =
|
|
84355
|
+
const cutoff = now2 - maxAgeMs;
|
|
83245
84356
|
let scanned = 0;
|
|
83246
84357
|
for (const name of entries) {
|
|
83247
84358
|
if (scanned >= MAX_TOKEN_FILES_SCANNED)
|
|
@@ -83855,7 +84966,7 @@ function shouldWarmCatalog(args) {
|
|
|
83855
84966
|
}
|
|
83856
84967
|
return true;
|
|
83857
84968
|
}
|
|
83858
|
-
function classifyCatalogState(cache3, ttlHours,
|
|
84969
|
+
function classifyCatalogState(cache3, ttlHours, now2) {
|
|
83859
84970
|
if (cache3 === null)
|
|
83860
84971
|
return "missing";
|
|
83861
84972
|
if (cache3.entries.length === 0 && cache3.models.length === 0)
|
|
@@ -83863,7 +84974,7 @@ function classifyCatalogState(cache3, ttlHours, now) {
|
|
|
83863
84974
|
const lastUpdatedMs = Date.parse(cache3.lastUpdated);
|
|
83864
84975
|
if (Number.isNaN(lastUpdatedMs))
|
|
83865
84976
|
return "missing";
|
|
83866
|
-
const ageMs =
|
|
84977
|
+
const ageMs = now2.getTime() - lastUpdatedMs;
|
|
83867
84978
|
const ttlMs = ttlHours * 3600000;
|
|
83868
84979
|
return ageMs < ttlMs ? "fresh" : "stale";
|
|
83869
84980
|
}
|
|
@@ -83920,9 +85031,9 @@ async function warmCatalogIfNeeded(config3, opts) {
|
|
|
83920
85031
|
}
|
|
83921
85032
|
const ttlHoursRaw = opts?.ttlHours ?? Number.parseFloat(process.env.CLAUDISH_CATALOG_TTL_HOURS ?? "24");
|
|
83922
85033
|
const ttlHours = Number.isFinite(ttlHoursRaw) && ttlHoursRaw > 0 ? ttlHoursRaw : 24;
|
|
83923
|
-
const
|
|
85034
|
+
const now2 = opts?.now ?? new Date;
|
|
83924
85035
|
const cache3 = readAllModelsCache();
|
|
83925
|
-
const state = classifyCatalogState(cache3, ttlHours,
|
|
85036
|
+
const state = classifyCatalogState(cache3, ttlHours, now2);
|
|
83926
85037
|
if (state === "fresh" && !config3.forceUpdate) {
|
|
83927
85038
|
return "ok";
|
|
83928
85039
|
}
|
|
@@ -83941,14 +85052,14 @@ async function warmCatalogIfNeeded(config3, opts) {
|
|
|
83941
85052
|
return "ok";
|
|
83942
85053
|
}
|
|
83943
85054
|
if (state === "stale") {
|
|
83944
|
-
const ageMs =
|
|
85055
|
+
const ageMs = now2.getTime() - Date.parse(cache3.lastUpdated);
|
|
83945
85056
|
const ageStr = humanizeAge(ageMs);
|
|
83946
85057
|
process.stderr.write(`WARNING: Catalog stale (${ageStr}). Using cached version. Run \`claudish --models-refresh\` to retry.
|
|
83947
85058
|
`);
|
|
83948
85059
|
return "warned";
|
|
83949
85060
|
}
|
|
83950
85061
|
if (state === "fresh") {
|
|
83951
|
-
const ageMs =
|
|
85062
|
+
const ageMs = now2.getTime() - Date.parse(cache3.lastUpdated);
|
|
83952
85063
|
const ageStr = humanizeAge(ageMs);
|
|
83953
85064
|
process.stderr.write(`WARNING: Catalog refresh failed (cache age ${ageStr}). Using cached version.
|
|
83954
85065
|
`);
|
|
@@ -85410,10 +86521,10 @@ function ResumePicker({ groups, onDone }) {
|
|
|
85410
86521
|
const { fresh, stale, visibleGroups } = useMemo4(() => {
|
|
85411
86522
|
const withSessions = groups.filter((g) => (listed.get(g.name)?.length ?? 0) > 0);
|
|
85412
86523
|
const matching = filter ? withSessions.filter((g) => fuzzy(filter, g.name)) : withSessions;
|
|
85413
|
-
const
|
|
86524
|
+
const now2 = Date.now();
|
|
85414
86525
|
const byRecency = (a, b) => b.lastActiveMs - a.lastActiveMs;
|
|
85415
|
-
const f = matching.filter((g) => g.current ||
|
|
85416
|
-
const st = matching.filter((g) => !g.current &&
|
|
86526
|
+
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));
|
|
86527
|
+
const st = matching.filter((g) => !g.current && now2 - g.lastActiveMs >= STALE_MS).sort(byRecency);
|
|
85417
86528
|
return { fresh: f, stale: st, visibleGroups: [...f, ...st] };
|
|
85418
86529
|
}, [groups, filter, listed]);
|
|
85419
86530
|
const group = visibleGroups[Math.min(wtCursor, visibleGroups.length - 1)];
|
|
@@ -86342,7 +87453,7 @@ function renderSessionSummary(input) {
|
|
|
86342
87453
|
const W2 = cardWidth();
|
|
86343
87454
|
const inner = W2 - CHROME;
|
|
86344
87455
|
const out = [];
|
|
86345
|
-
const
|
|
87456
|
+
const dim4 = (s) => paint(s, tokens.subtle);
|
|
86346
87457
|
const body = (s) => paint(s, tokens.text);
|
|
86347
87458
|
const titleText = exitCode === 0 ? " session " : " session \xB7 failed ";
|
|
86348
87459
|
const titleHex = exitCode === 0 ? tokens.accent : tokens.error;
|
|
@@ -86364,26 +87475,26 @@ function renderSessionSummary(input) {
|
|
|
86364
87475
|
const gap = Math.max(1, inner - visibleWidth(left) - visibleWidth(right));
|
|
86365
87476
|
row(left + " ".repeat(gap) + right);
|
|
86366
87477
|
if (stats.providerName)
|
|
86367
|
-
row(
|
|
87478
|
+
row(dim4(truncate3(stats.providerName, inner)));
|
|
86368
87479
|
blank();
|
|
86369
87480
|
const VALUE_W = 24;
|
|
86370
87481
|
const barW = Math.max(12, inner - LABEL_W - VALUE_W);
|
|
86371
87482
|
const dataRow = (label, bar, values) => {
|
|
86372
|
-
row(
|
|
87483
|
+
row(dim4(padTo(label, LABEL_W)) + bar + padVisible2(values, VALUE_W, "right"));
|
|
86373
87484
|
};
|
|
86374
87485
|
if (stats.contextUsed !== null && stats.contextWindow) {
|
|
86375
87486
|
const pct = stats.contextUsed * 100;
|
|
86376
|
-
dataRow("context", meter(pct, barW, ramps.load), body(padStartTo(`${Math.round(pct)}%`, 4)) +
|
|
87487
|
+
dataRow("context", meter(pct, barW, ramps.load), body(padStartTo(`${Math.round(pct)}%`, 4)) + dim4(` ${compact(stats.inputTokens)}/${compact(stats.contextWindow)}`));
|
|
86377
87488
|
}
|
|
86378
87489
|
dataRow("tokens", stackedBar([
|
|
86379
87490
|
{ value: stats.inputTokens, color: C.blue },
|
|
86380
87491
|
{ value: stats.outputTokens, color: C.cyan }
|
|
86381
|
-
], barW),
|
|
87492
|
+
], barW), dim4("in ") + body(compact(stats.inputTokens)) + dim4(" out ") + body(compact(stats.outputTokens)));
|
|
86382
87493
|
if (!stats.isFree && stats.inputCostUsd + stats.outputCostUsd > 0) {
|
|
86383
87494
|
dataRow("spend", stackedBar([
|
|
86384
87495
|
{ value: stats.inputCostUsd, color: C.blue },
|
|
86385
87496
|
{ value: stats.outputCostUsd, color: C.cyan }
|
|
86386
|
-
], barW),
|
|
87497
|
+
], barW), dim4("in ") + body(usd(stats.inputCostUsd)) + dim4(" out ") + body(usd(stats.outputCostUsd)));
|
|
86387
87498
|
}
|
|
86388
87499
|
if (stats.toolCallTotal > 0) {
|
|
86389
87500
|
const toolCols = toolColors();
|
|
@@ -86393,27 +87504,27 @@ function renderSessionSummary(input) {
|
|
|
86393
87504
|
const segs = shown.map((t, i) => ({ value: t.count, color: toolCols[i] }));
|
|
86394
87505
|
if (rest > 0)
|
|
86395
87506
|
segs.push({ value: rest, color: other });
|
|
86396
|
-
dataRow("tools", stackedBar(segs, barW), body(padStartTo(String(stats.toolCallTotal), 4)) +
|
|
87507
|
+
dataRow("tools", stackedBar(segs, barW), body(padStartTo(String(stats.toolCallTotal), 4)) + dim4(" calls"));
|
|
86397
87508
|
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,
|
|
87509
|
+
for (const line of wrapStyled(legend, dim4(" \xB7 "), inner - LABEL_W)) {
|
|
86399
87510
|
row(" ".repeat(LABEL_W) + line);
|
|
86400
87511
|
}
|
|
86401
87512
|
}
|
|
86402
87513
|
blank();
|
|
86403
|
-
row(
|
|
87514
|
+
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
87515
|
for (const s of stats.savings) {
|
|
86405
87516
|
const label = padTo(`vs ${s.label}`, LABEL_W);
|
|
86406
87517
|
if (s.savedUsd >= 0) {
|
|
86407
87518
|
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) +
|
|
87519
|
+
dataRow(label, meter(pct, barW, ramps.savings), paint(padStartTo(`${Math.round(pct)}%`, 4), tokens.success) + dim4(" saved ") + paint(usd(s.savedUsd), tokens.success));
|
|
86409
87520
|
} else {
|
|
86410
|
-
dataRow(label, meter(0, barW, ramps.savings),
|
|
87521
|
+
dataRow(label, meter(0, barW, ramps.savings), dim4("over by ") + paint(usd(-s.savedUsd), tokens.error));
|
|
86411
87522
|
}
|
|
86412
87523
|
}
|
|
86413
87524
|
out.push(paint(`\u2570${"\u2500".repeat(W2 - 2)}\u256F`, tokens.border));
|
|
86414
87525
|
if (resumeId) {
|
|
86415
87526
|
out.push("");
|
|
86416
|
-
out.push(
|
|
87527
|
+
out.push(dim4("Resume this session with:"));
|
|
86417
87528
|
const modelFlag = resumeModelSpec ? `--model ${resumeModelSpec} ` : "";
|
|
86418
87529
|
out.push(`claudish ${modelFlag}--resume ${resumeId}`);
|
|
86419
87530
|
}
|
|
@@ -86471,6 +87582,7 @@ function classifyStartupKind() {
|
|
|
86471
87582
|
"telemetry",
|
|
86472
87583
|
"stats",
|
|
86473
87584
|
"providers",
|
|
87585
|
+
"keychain",
|
|
86474
87586
|
"login",
|
|
86475
87587
|
"logout",
|
|
86476
87588
|
"quota",
|
|
@@ -86590,6 +87702,7 @@ var isStatsCommand = firstPositional === "stats";
|
|
|
86590
87702
|
var isConfigCommand = firstPositional === "config";
|
|
86591
87703
|
var isServeCommand = firstPositional === "serve";
|
|
86592
87704
|
var isProvidersCommand = firstPositional === "providers";
|
|
87705
|
+
var isKeychainCommand = firstPositional === "keychain";
|
|
86593
87706
|
var isBehaviorCommand = firstPositional === "behavior";
|
|
86594
87707
|
var isTeamCommand = firstPositional === "team";
|
|
86595
87708
|
var isLoginCommand = firstPositional === "login";
|
|
@@ -86629,6 +87742,12 @@ if (isMcpMode) {
|
|
|
86629
87742
|
console.error(`[claudish providers] ${e instanceof Error ? e.message : String(e)}`);
|
|
86630
87743
|
process.exit(1);
|
|
86631
87744
|
}));
|
|
87745
|
+
} else if (isKeychainCommand) {
|
|
87746
|
+
const keychainArgIndex = args.indexOf("keychain");
|
|
87747
|
+
Promise.resolve().then(() => (init_keychain_command(), exports_keychain_command)).then((m) => m.keychainCommand(args.slice(keychainArgIndex + 1)).catch((e) => {
|
|
87748
|
+
console.error(`[claudish keychain] ${e instanceof Error ? e.message : String(e)}`);
|
|
87749
|
+
process.exit(1);
|
|
87750
|
+
}));
|
|
86632
87751
|
} else if (isLoginCommand) {
|
|
86633
87752
|
const loginProviderArg = args.find((a, i) => i > args.indexOf("login") && !a.startsWith("-"));
|
|
86634
87753
|
Promise.resolve().then(() => (init_auth_commands(), exports_auth_commands)).then((m) => m.loginCommand(loginProviderArg).catch(handlePromptExit));
|
|
@@ -86666,6 +87785,10 @@ if (isMcpMode) {
|
|
|
86666
87785
|
});
|
|
86667
87786
|
} else if (isConfigCommand) {
|
|
86668
87787
|
traceSpan("startup:tui-import", () => Promise.resolve().then(() => (init_tui(), exports_tui))).then(async (m) => {
|
|
87788
|
+
await traceSpan("startup:theme-detect", async () => {
|
|
87789
|
+
const { detectAndSetThemeMode: detectAndSetThemeMode2 } = await Promise.resolve().then(() => (init_theme_mode(), exports_theme_mode));
|
|
87790
|
+
await detectAndSetThemeMode2();
|
|
87791
|
+
});
|
|
86669
87792
|
const { credentials: credentials2 } = await Promise.resolve().then(() => (init_authority(), exports_authority));
|
|
86670
87793
|
const { ensureEndpointsRegistered: ensureEndpointsRegistered2 } = await Promise.resolve().then(() => (init_endpoint_registration(), exports_endpoint_registration));
|
|
86671
87794
|
ensureEndpointsRegistered2();
|