claudish 7.29.1 → 7.30.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 +1741 -921
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -651,7 +651,7 @@ var init_onepassword_config = __esm(() => {
|
|
|
651
651
|
});
|
|
652
652
|
|
|
653
653
|
// src/version.ts
|
|
654
|
-
var VERSION = "7.
|
|
654
|
+
var VERSION = "7.30.0";
|
|
655
655
|
|
|
656
656
|
// src/logger.ts
|
|
657
657
|
var exports_logger = {};
|
|
@@ -27704,6 +27704,26 @@ var init_provider_definitions = __esm(() => {
|
|
|
27704
27704
|
isDirectApi: true,
|
|
27705
27705
|
description: "Direct Gemini API (g@, google@)"
|
|
27706
27706
|
},
|
|
27707
|
+
{
|
|
27708
|
+
name: "antigravity",
|
|
27709
|
+
displayName: "Antigravity",
|
|
27710
|
+
transport: "antigravity",
|
|
27711
|
+
baseUrl: "https://cloudcode-pa.googleapis.com",
|
|
27712
|
+
apiPath: "/v1internal:streamGenerateContent?alt=sse",
|
|
27713
|
+
apiKeyEnvVar: "",
|
|
27714
|
+
apiKeyDescription: "Antigravity (shared OAuth token)",
|
|
27715
|
+
apiKeyUrl: "https://antigravity.google/",
|
|
27716
|
+
oauthLoginSlug: "gemini",
|
|
27717
|
+
shortcuts: ["ag", "antigravity", "go"],
|
|
27718
|
+
shortestPrefix: "ag",
|
|
27719
|
+
legacyPrefixes: [
|
|
27720
|
+
{ prefix: "ag/", stripPrefix: true },
|
|
27721
|
+
{ prefix: "antigravity/", stripPrefix: true },
|
|
27722
|
+
{ prefix: "go/", stripPrefix: true }
|
|
27723
|
+
],
|
|
27724
|
+
isDirectApi: true,
|
|
27725
|
+
description: "Antigravity subscription (ag@; go@ deprecated)"
|
|
27726
|
+
},
|
|
27707
27727
|
{
|
|
27708
27728
|
name: "gemini-codeassist",
|
|
27709
27729
|
displayName: "Gemini Code Assist",
|
|
@@ -27714,11 +27734,11 @@ var init_provider_definitions = __esm(() => {
|
|
|
27714
27734
|
apiKeyDescription: "Gemini Code Assist (OAuth)",
|
|
27715
27735
|
apiKeyUrl: "https://cloud.google.com/code-assist",
|
|
27716
27736
|
oauthLoginSlug: "gemini",
|
|
27717
|
-
shortcuts: [
|
|
27718
|
-
shortestPrefix: "
|
|
27719
|
-
legacyPrefixes: [
|
|
27737
|
+
shortcuts: [],
|
|
27738
|
+
shortestPrefix: "gemini-codeassist",
|
|
27739
|
+
legacyPrefixes: [],
|
|
27720
27740
|
isDirectApi: true,
|
|
27721
|
-
description: "Gemini Code Assist OAuth (
|
|
27741
|
+
description: "Gemini Code Assist OAuth (routing fallback for gemini-*)"
|
|
27722
27742
|
},
|
|
27723
27743
|
{
|
|
27724
27744
|
name: "openai",
|
|
@@ -28231,125 +28251,191 @@ var init_provider_definitions = __esm(() => {
|
|
|
28231
28251
|
];
|
|
28232
28252
|
});
|
|
28233
28253
|
|
|
28234
|
-
// src/auth/
|
|
28254
|
+
// src/auth/antigravity-token.ts
|
|
28255
|
+
import { execFileSync } from "child_process";
|
|
28235
28256
|
import { existsSync as existsSync6 } from "fs";
|
|
28236
28257
|
import { homedir as homedir8 } from "os";
|
|
28237
28258
|
import { join as join8 } from "path";
|
|
28238
|
-
function
|
|
28239
|
-
if (
|
|
28240
|
-
|
|
28241
|
-
|
|
28259
|
+
function defaultReadStore() {
|
|
28260
|
+
if (process.platform !== "darwin") {
|
|
28261
|
+
logStderr("[Antigravity] Shared token store is macOS-only for now (other keyring backends are a follow-up).");
|
|
28262
|
+
return null;
|
|
28263
|
+
}
|
|
28264
|
+
try {
|
|
28265
|
+
const out = execFileSync("security", ["find-generic-password", "-s", KC_SERVICE, "-a", KC_ACCOUNT, "-w"], { encoding: "utf8" });
|
|
28266
|
+
const trimmed = out.trim();
|
|
28267
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
28268
|
+
} catch {
|
|
28269
|
+
return null;
|
|
28270
|
+
}
|
|
28242
28271
|
}
|
|
28243
|
-
|
|
28244
|
-
|
|
28245
|
-
|
|
28246
|
-
envVar;
|
|
28247
|
-
aliases;
|
|
28248
|
-
authScheme;
|
|
28249
|
-
staticHeaders;
|
|
28250
|
-
publicKeyFallback;
|
|
28251
|
-
oauthFallback;
|
|
28252
|
-
declaredKey;
|
|
28253
|
-
cachedKey;
|
|
28254
|
-
resolving;
|
|
28255
|
-
constructor(descriptor) {
|
|
28256
|
-
this.catalogName = descriptor.catalogName;
|
|
28257
|
-
this.envVar = descriptor.envVar;
|
|
28258
|
-
this.aliases = descriptor.aliases ?? [];
|
|
28259
|
-
this.authScheme = descriptor.authScheme ?? "bearer";
|
|
28260
|
-
this.staticHeaders = descriptor.staticHeaders ?? {};
|
|
28261
|
-
this.publicKeyFallback = descriptor.publicKeyFallback;
|
|
28262
|
-
this.oauthFallback = descriptor.oauthFallback;
|
|
28263
|
-
this.declaredKey = descriptor.declaredKey;
|
|
28272
|
+
function defaultWriteStore(rawValue) {
|
|
28273
|
+
if (process.platform !== "darwin") {
|
|
28274
|
+
throw new Error("[Antigravity] Cannot write the shared token store on a non-macOS platform.");
|
|
28264
28275
|
}
|
|
28265
|
-
|
|
28266
|
-
|
|
28276
|
+
execFileSync("security", ["add-generic-password", "-U", "-s", KC_SERVICE, "-a", KC_ACCOUNT, "-w", rawValue], { stdio: ["ignore", "ignore", "ignore"] });
|
|
28277
|
+
}
|
|
28278
|
+
function locateAgyBinary() {
|
|
28279
|
+
try {
|
|
28280
|
+
const p = execFileSync("which", ["agy"], { encoding: "utf8" }).trim();
|
|
28281
|
+
if (p.length > 0)
|
|
28282
|
+
return p;
|
|
28283
|
+
} catch {}
|
|
28284
|
+
const fallback = join8(homedir8(), ".local", "bin", "agy");
|
|
28285
|
+
return existsSync6(fallback) ? fallback : null;
|
|
28286
|
+
}
|
|
28287
|
+
function defaultExtractCreds() {
|
|
28288
|
+
const agy = locateAgyBinary();
|
|
28289
|
+
if (!agy) {
|
|
28290
|
+
logStderr("[Antigravity] Could not locate the `agy` binary \u2014 self-refresh is unavailable.");
|
|
28291
|
+
return [];
|
|
28267
28292
|
}
|
|
28268
|
-
|
|
28269
|
-
|
|
28270
|
-
|
|
28271
|
-
|
|
28272
|
-
|
|
28273
|
-
}
|
|
28293
|
+
let dump;
|
|
28294
|
+
try {
|
|
28295
|
+
dump = execFileSync("strings", [agy], {
|
|
28296
|
+
encoding: "utf8",
|
|
28297
|
+
maxBuffer: 128 * 1024 * 1024
|
|
28298
|
+
});
|
|
28299
|
+
} catch {
|
|
28300
|
+
logStderr("[Antigravity] `strings` failed on the agy binary \u2014 self-refresh is unavailable.");
|
|
28301
|
+
return [];
|
|
28274
28302
|
}
|
|
28275
|
-
|
|
28276
|
-
|
|
28277
|
-
|
|
28278
|
-
|
|
28279
|
-
|
|
28280
|
-
|
|
28281
|
-
return false;
|
|
28303
|
+
const clientIds = Array.from(new Set(dump.match(/[0-9]{6,}-[a-z0-9]+\.apps\.googleusercontent\.com/g) ?? []));
|
|
28304
|
+
const secrets = Array.from(new Set(dump.match(/GOCSPX-[A-Za-z0-9_-]{20,}/g) ?? []));
|
|
28305
|
+
const combos = [];
|
|
28306
|
+
for (const clientId of clientIds) {
|
|
28307
|
+
for (const clientSecret of secrets) {
|
|
28308
|
+
combos.push({ clientId, clientSecret });
|
|
28282
28309
|
}
|
|
28283
28310
|
}
|
|
28284
|
-
|
|
28285
|
-
|
|
28286
|
-
|
|
28287
|
-
|
|
28288
|
-
|
|
28289
|
-
|
|
28290
|
-
|
|
28291
|
-
|
|
28292
|
-
this.cachedKey = local;
|
|
28293
|
-
return local;
|
|
28294
|
-
}
|
|
28295
|
-
if (hasOpSources()) {
|
|
28296
|
-
const wanted = new Set([this.envVar, ...this.aliases]);
|
|
28297
|
-
const resolved = await resolveOpKeyForEnvVars(wanted, {
|
|
28298
|
-
onAuthFailure: "skip",
|
|
28299
|
-
allowPrompt: opts?.allowOpPrompt ?? false
|
|
28300
|
-
});
|
|
28301
|
-
const value = resolved[this.envVar] ?? this.aliases.map((a) => resolved[a]).find((v) => !!v);
|
|
28302
|
-
if (value) {
|
|
28303
|
-
process.env[this.envVar] = value;
|
|
28304
|
-
this.cachedKey = value;
|
|
28305
|
-
return value;
|
|
28306
|
-
}
|
|
28307
|
-
return "";
|
|
28308
|
-
}
|
|
28309
|
-
this.cachedKey = "";
|
|
28310
|
-
return "";
|
|
28311
|
-
})();
|
|
28312
|
-
try {
|
|
28313
|
-
return await this.resolving;
|
|
28314
|
-
} finally {
|
|
28315
|
-
this.resolving = undefined;
|
|
28316
|
-
}
|
|
28311
|
+
return combos;
|
|
28312
|
+
}
|
|
28313
|
+
function parseRecord(raw) {
|
|
28314
|
+
if (!raw)
|
|
28315
|
+
return null;
|
|
28316
|
+
if (!raw.startsWith(PREFIX)) {
|
|
28317
|
+
logStderr("[Antigravity] Shared token is in an unsupported keyring format (not go-keyring-base64) \u2014 skipping.");
|
|
28318
|
+
return null;
|
|
28317
28319
|
}
|
|
28318
|
-
|
|
28319
|
-
|
|
28320
|
-
|
|
28321
|
-
if (
|
|
28322
|
-
return
|
|
28323
|
-
|
|
28324
|
-
|
|
28325
|
-
|
|
28326
|
-
return
|
|
28320
|
+
try {
|
|
28321
|
+
const json2 = Buffer.from(raw.slice(PREFIX.length), "base64").toString("utf8");
|
|
28322
|
+
const rec = JSON.parse(json2);
|
|
28323
|
+
if (!rec?.token?.access_token)
|
|
28324
|
+
return null;
|
|
28325
|
+
return rec;
|
|
28326
|
+
} catch (err) {
|
|
28327
|
+
log(`[Antigravity] Failed to decode shared token: ${err}`);
|
|
28328
|
+
return null;
|
|
28327
28329
|
}
|
|
28328
|
-
|
|
28329
|
-
|
|
28330
|
-
|
|
28330
|
+
}
|
|
28331
|
+
function encodeRecord(rec) {
|
|
28332
|
+
return PREFIX + Buffer.from(JSON.stringify(rec), "utf8").toString("base64");
|
|
28333
|
+
}
|
|
28334
|
+
function readSharedAntigravityToken(deps = defaultDeps) {
|
|
28335
|
+
const rec = parseRecord(deps.readStore());
|
|
28336
|
+
return rec ? rec.token : null;
|
|
28337
|
+
}
|
|
28338
|
+
function hasSharedAntigravityToken(deps = defaultDeps) {
|
|
28339
|
+
const now = Date.now();
|
|
28340
|
+
if (cachedHasToken && now - cachedHasToken.at < HAS_TOKEN_TTL_MS)
|
|
28341
|
+
return cachedHasToken.value;
|
|
28342
|
+
let value = false;
|
|
28343
|
+
try {
|
|
28344
|
+
value = readSharedAntigravityToken(deps) != null;
|
|
28345
|
+
} catch {
|
|
28346
|
+
value = false;
|
|
28331
28347
|
}
|
|
28332
|
-
|
|
28333
|
-
|
|
28334
|
-
|
|
28335
|
-
|
|
28336
|
-
|
|
28337
|
-
|
|
28338
|
-
|
|
28339
|
-
|
|
28340
|
-
|
|
28348
|
+
cachedHasToken = { at: now, value };
|
|
28349
|
+
return value;
|
|
28350
|
+
}
|
|
28351
|
+
function writeSharedAntigravityToken(tok, deps = defaultDeps) {
|
|
28352
|
+
const existing = parseRecord(deps.readStore());
|
|
28353
|
+
const base = existing ?? { token: tok };
|
|
28354
|
+
const merged = {
|
|
28355
|
+
...base,
|
|
28356
|
+
token: { ...base.token, ...tok }
|
|
28357
|
+
};
|
|
28358
|
+
deps.writeStore(encodeRecord(merged));
|
|
28359
|
+
}
|
|
28360
|
+
function needsRefresh(tok, now) {
|
|
28361
|
+
const expMs = Date.parse(tok.expiry);
|
|
28362
|
+
if (Number.isNaN(expMs))
|
|
28363
|
+
return true;
|
|
28364
|
+
return now >= expMs - EXPIRY_SKEW_MS;
|
|
28365
|
+
}
|
|
28366
|
+
async function refreshToken(tok, deps) {
|
|
28367
|
+
const combos = cachedCred ? [cachedCred] : deps.extractCreds();
|
|
28368
|
+
if (combos.length === 0) {
|
|
28369
|
+
throw new Error("[Antigravity] Access token expired and no OAuth client credentials could be extracted " + "from the `agy` binary to refresh it. Re-run the Antigravity CLI to refresh your session, " + "or use g@<model> with GEMINI_API_KEY.");
|
|
28370
|
+
}
|
|
28371
|
+
let lastStatus = 0;
|
|
28372
|
+
let lastBody = "";
|
|
28373
|
+
for (const cred of combos) {
|
|
28374
|
+
const res = await deps.fetch(REFRESH_ENDPOINT, {
|
|
28375
|
+
method: "POST",
|
|
28376
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
28377
|
+
body: new URLSearchParams({
|
|
28378
|
+
client_id: cred.clientId,
|
|
28379
|
+
client_secret: cred.clientSecret,
|
|
28380
|
+
refresh_token: tok.refresh_token,
|
|
28381
|
+
grant_type: "refresh_token"
|
|
28382
|
+
})
|
|
28383
|
+
});
|
|
28384
|
+
if (res.ok) {
|
|
28385
|
+
cachedCred = cred;
|
|
28386
|
+
const j = await res.json();
|
|
28387
|
+
const expiry = new Date(deps.now() + j.expires_in * 1000).toISOString();
|
|
28388
|
+
return {
|
|
28389
|
+
access_token: j.access_token,
|
|
28390
|
+
token_type: tok.token_type || "Bearer",
|
|
28391
|
+
refresh_token: j.refresh_token || tok.refresh_token,
|
|
28392
|
+
expiry
|
|
28393
|
+
};
|
|
28341
28394
|
}
|
|
28342
|
-
|
|
28395
|
+
lastStatus = res.status;
|
|
28396
|
+
lastBody = await res.text().catch(() => "");
|
|
28343
28397
|
}
|
|
28398
|
+
throw new Error(`[Antigravity] Token refresh failed for all ${combos.length} client-cred combo(s) ` + `(last HTTP ${lastStatus}${lastBody ? `: ${lastBody.slice(0, 200)}` : ""}). ` + "Re-run the Antigravity CLI to refresh your session, or use g@<model> with GEMINI_API_KEY.");
|
|
28344
28399
|
}
|
|
28345
|
-
|
|
28346
|
-
|
|
28347
|
-
|
|
28348
|
-
|
|
28349
|
-
|
|
28400
|
+
async function resolveValidToken(deps) {
|
|
28401
|
+
if (process.platform !== "darwin") {
|
|
28402
|
+
throw new Error("[Antigravity] The shared Antigravity token store is macOS-only for now. " + "Use g@<model> with GEMINI_API_KEY on this platform.");
|
|
28403
|
+
}
|
|
28404
|
+
const rec = parseRecord(deps.readStore());
|
|
28405
|
+
if (!rec) {
|
|
28406
|
+
throw new Error("[Antigravity] No Antigravity session found. Install Antigravity and sign in " + "(the `agy` CLI), or use g@<model> with GEMINI_API_KEY " + "(get one at https://aistudio.google.com/app/apikey).");
|
|
28407
|
+
}
|
|
28408
|
+
const tok = rec.token;
|
|
28409
|
+
if (!needsRefresh(tok, deps.now())) {
|
|
28410
|
+
return tok.access_token;
|
|
28411
|
+
}
|
|
28412
|
+
log("[Antigravity] Access token expired/near-expiry \u2014 refreshing.");
|
|
28413
|
+
const refreshed = await refreshToken(tok, deps);
|
|
28414
|
+
writeSharedAntigravityToken(refreshed, deps);
|
|
28415
|
+
log("[Antigravity] Token refreshed and written back to the shared store.");
|
|
28416
|
+
return refreshed.access_token;
|
|
28417
|
+
}
|
|
28418
|
+
function getValidAntigravityAccessToken(deps = defaultDeps) {
|
|
28419
|
+
if (inFlight)
|
|
28420
|
+
return inFlight;
|
|
28421
|
+
inFlight = resolveValidToken(deps).finally(() => {
|
|
28422
|
+
inFlight = null;
|
|
28423
|
+
});
|
|
28424
|
+
return inFlight;
|
|
28425
|
+
}
|
|
28426
|
+
var KC_SERVICE = "gemini", KC_ACCOUNT = "antigravity", PREFIX = "go-keyring-base64:", REFRESH_ENDPOINT = "https://oauth2.googleapis.com/token", EXPIRY_SKEW_MS = 120000, defaultDeps, cachedHasToken = null, HAS_TOKEN_TTL_MS = 5000, cachedCred = null, inFlight = null;
|
|
28427
|
+
var init_antigravity_token = __esm(() => {
|
|
28428
|
+
init_logger();
|
|
28429
|
+
defaultDeps = {
|
|
28430
|
+
readStore: defaultReadStore,
|
|
28431
|
+
writeStore: defaultWriteStore,
|
|
28432
|
+
extractCreds: defaultExtractCreds,
|
|
28433
|
+
fetch: (input, init) => fetch(input, init),
|
|
28434
|
+
now: () => Date.now()
|
|
28435
|
+
};
|
|
28350
28436
|
});
|
|
28351
28437
|
|
|
28352
|
-
// src/auth/
|
|
28438
|
+
// src/auth/gemini-oauth.ts
|
|
28353
28439
|
import { exec } from "child_process";
|
|
28354
28440
|
import { createHash as createHash2, randomBytes } from "crypto";
|
|
28355
28441
|
import { closeSync as closeSync2, existsSync as existsSync7, openSync as openSync2, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeSync as writeSync2 } from "fs";
|
|
@@ -28357,18 +28443,25 @@ import { createServer } from "http";
|
|
|
28357
28443
|
import { homedir as homedir9 } from "os";
|
|
28358
28444
|
import { join as join9 } from "path";
|
|
28359
28445
|
import { promisify } from "util";
|
|
28446
|
+
function buildCodeAssistUserAgent(model) {
|
|
28447
|
+
if (USE_LEGACY_GEMINI_IDENTITY) {
|
|
28448
|
+
const modelSegment = model || "gemini-code-assist";
|
|
28449
|
+
return `GeminiCLI/0.5.6/${modelSegment} (${process.platform}; ${process.arch})`;
|
|
28450
|
+
}
|
|
28451
|
+
return `antigravity/cli/1.1.9 (aidev_client; os_type=${process.platform}; arch=${process.arch}; auth_method=consumer)`;
|
|
28452
|
+
}
|
|
28360
28453
|
|
|
28361
|
-
class
|
|
28454
|
+
class GeminiOAuth {
|
|
28362
28455
|
static instance = null;
|
|
28363
28456
|
credentials = null;
|
|
28364
28457
|
refreshPromise = null;
|
|
28365
28458
|
tokenRefreshMargin = 5 * 60 * 1000;
|
|
28366
28459
|
oauthState = null;
|
|
28367
28460
|
static getInstance() {
|
|
28368
|
-
if (!
|
|
28369
|
-
|
|
28461
|
+
if (!GeminiOAuth.instance) {
|
|
28462
|
+
GeminiOAuth.instance = new GeminiOAuth;
|
|
28370
28463
|
}
|
|
28371
|
-
return
|
|
28464
|
+
return GeminiOAuth.instance;
|
|
28372
28465
|
}
|
|
28373
28466
|
constructor() {
|
|
28374
28467
|
this.credentials = this.loadCredentials();
|
|
@@ -28382,60 +28475,55 @@ class CodexOAuth {
|
|
|
28382
28475
|
}
|
|
28383
28476
|
getCredentialsPath() {
|
|
28384
28477
|
const claudishDir = join9(homedir9(), ".claudish");
|
|
28385
|
-
return join9(claudishDir, "
|
|
28478
|
+
return join9(claudishDir, "gemini-oauth.json");
|
|
28386
28479
|
}
|
|
28387
28480
|
async login() {
|
|
28388
|
-
log("[
|
|
28481
|
+
log("[GeminiOAuth] Starting OAuth login flow");
|
|
28389
28482
|
const codeVerifier = this.generateCodeVerifier();
|
|
28390
28483
|
const codeChallenge = await this.generateCodeChallenge(codeVerifier);
|
|
28391
28484
|
this.oauthState = randomBytes(32).toString("base64url");
|
|
28392
28485
|
const { authCode, redirectUri } = await this.startCallbackServer(codeChallenge, this.oauthState);
|
|
28393
28486
|
const tokens = await this.exchangeCodeForTokens(authCode, codeVerifier, redirectUri);
|
|
28394
|
-
const accountId = tokens.id_token ? this.extractAccountId(tokens.id_token) : undefined;
|
|
28395
28487
|
const credentials = {
|
|
28396
28488
|
access_token: tokens.access_token,
|
|
28397
28489
|
refresh_token: tokens.refresh_token,
|
|
28398
|
-
expires_at: Date.now() + tokens.expires_in * 1000
|
|
28399
|
-
account_id: accountId
|
|
28490
|
+
expires_at: Date.now() + tokens.expires_in * 1000
|
|
28400
28491
|
};
|
|
28401
28492
|
this.saveCredentials(credentials);
|
|
28402
28493
|
this.credentials = credentials;
|
|
28403
28494
|
this.oauthState = null;
|
|
28404
|
-
log("[
|
|
28405
|
-
if (accountId) {
|
|
28406
|
-
log(`[CodexOAuth] Account ID: ${accountId}`);
|
|
28407
|
-
}
|
|
28495
|
+
log("[GeminiOAuth] Login successful");
|
|
28408
28496
|
}
|
|
28409
28497
|
async logout() {
|
|
28410
28498
|
const credPath = this.getCredentialsPath();
|
|
28411
28499
|
if (existsSync7(credPath)) {
|
|
28412
28500
|
unlinkSync2(credPath);
|
|
28413
|
-
log("[
|
|
28501
|
+
log("[GeminiOAuth] Credentials deleted");
|
|
28414
28502
|
}
|
|
28415
28503
|
this.credentials = null;
|
|
28416
28504
|
}
|
|
28417
28505
|
async getAccessToken() {
|
|
28418
28506
|
if (this.refreshPromise) {
|
|
28419
|
-
log("[
|
|
28507
|
+
log("[GeminiOAuth] Waiting for in-progress refresh");
|
|
28420
28508
|
return this.refreshPromise;
|
|
28421
28509
|
}
|
|
28422
28510
|
if (!this.credentials) {
|
|
28423
|
-
throw new Error("No
|
|
28511
|
+
throw new Error("No Gemini OAuth credentials found. Please run `claudish login gemini` first.");
|
|
28424
28512
|
}
|
|
28425
28513
|
if (this.isTokenValid()) {
|
|
28426
28514
|
return this.credentials.access_token;
|
|
28427
28515
|
}
|
|
28428
|
-
this.refreshPromise = this.doRefreshToken()
|
|
28516
|
+
this.refreshPromise = this.doRefreshToken();
|
|
28517
|
+
try {
|
|
28518
|
+
const token = await this.refreshPromise;
|
|
28519
|
+
return token;
|
|
28520
|
+
} finally {
|
|
28429
28521
|
this.refreshPromise = null;
|
|
28430
|
-
}
|
|
28431
|
-
return this.refreshPromise;
|
|
28432
|
-
}
|
|
28433
|
-
getAccountId() {
|
|
28434
|
-
return this.credentials?.account_id;
|
|
28522
|
+
}
|
|
28435
28523
|
}
|
|
28436
28524
|
async refreshToken() {
|
|
28437
28525
|
if (!this.credentials) {
|
|
28438
|
-
throw new Error("No
|
|
28526
|
+
throw new Error("No Gemini OAuth credentials found. Please run `claudish login gemini` first.");
|
|
28439
28527
|
}
|
|
28440
28528
|
await this.doRefreshToken();
|
|
28441
28529
|
}
|
|
@@ -28446,19 +28534,20 @@ class CodexOAuth {
|
|
|
28446
28534
|
}
|
|
28447
28535
|
async doRefreshToken() {
|
|
28448
28536
|
if (!this.credentials) {
|
|
28449
|
-
throw new Error("No
|
|
28537
|
+
throw new Error("No Gemini OAuth credentials found. Please run `claudish login gemini` first.");
|
|
28450
28538
|
}
|
|
28451
|
-
log("[
|
|
28539
|
+
log("[GeminiOAuth] Refreshing access token");
|
|
28452
28540
|
try {
|
|
28453
28541
|
const response = await fetch(OAUTH_CONFIG.tokenUrl, {
|
|
28454
28542
|
method: "POST",
|
|
28455
28543
|
headers: {
|
|
28456
|
-
"Content-Type": "application/
|
|
28544
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
28457
28545
|
},
|
|
28458
|
-
body:
|
|
28546
|
+
body: new URLSearchParams({
|
|
28459
28547
|
grant_type: "refresh_token",
|
|
28460
28548
|
refresh_token: this.credentials.refresh_token,
|
|
28461
|
-
client_id: OAUTH_CONFIG.clientId
|
|
28549
|
+
client_id: OAUTH_CONFIG.clientId,
|
|
28550
|
+
client_secret: OAUTH_CONFIG.clientSecret
|
|
28462
28551
|
})
|
|
28463
28552
|
});
|
|
28464
28553
|
if (!response.ok) {
|
|
@@ -28466,20 +28555,18 @@ class CodexOAuth {
|
|
|
28466
28555
|
throw new Error(`Token refresh failed: ${response.status} - ${errorText}`);
|
|
28467
28556
|
}
|
|
28468
28557
|
const tokens = await response.json();
|
|
28469
|
-
const accountId = tokens.id_token ? this.extractAccountId(tokens.id_token) : this.credentials.account_id;
|
|
28470
28558
|
const updatedCredentials = {
|
|
28471
28559
|
access_token: tokens.access_token,
|
|
28472
28560
|
refresh_token: tokens.refresh_token || this.credentials.refresh_token,
|
|
28473
|
-
expires_at: Date.now() + tokens.expires_in * 1000
|
|
28474
|
-
account_id: accountId
|
|
28561
|
+
expires_at: Date.now() + tokens.expires_in * 1000
|
|
28475
28562
|
};
|
|
28476
28563
|
this.saveCredentials(updatedCredentials);
|
|
28477
28564
|
this.credentials = updatedCredentials;
|
|
28478
|
-
log(`[
|
|
28565
|
+
log(`[GeminiOAuth] Token refreshed, valid until ${new Date(updatedCredentials.expires_at).toISOString()}`);
|
|
28479
28566
|
return updatedCredentials.access_token;
|
|
28480
28567
|
} catch (e) {
|
|
28481
|
-
log(`[
|
|
28482
|
-
throw new Error(`OAuth credentials invalid. Please run \`claudish login
|
|
28568
|
+
log(`[GeminiOAuth] Refresh failed: ${e.message}`);
|
|
28569
|
+
throw new Error(`OAuth credentials invalid. Please run \`claudish login gemini\` again.
|
|
28483
28570
|
|
|
28484
28571
|
Details: ${e.message}`);
|
|
28485
28572
|
}
|
|
@@ -28493,13 +28580,13 @@ Details: ${e.message}`);
|
|
|
28493
28580
|
const data = readFileSync6(credPath, "utf-8");
|
|
28494
28581
|
const credentials = JSON.parse(data);
|
|
28495
28582
|
if (!credentials.access_token || !credentials.refresh_token || !credentials.expires_at) {
|
|
28496
|
-
log("[
|
|
28583
|
+
log("[GeminiOAuth] Invalid credentials file structure");
|
|
28497
28584
|
return null;
|
|
28498
28585
|
}
|
|
28499
|
-
log("[
|
|
28586
|
+
log("[GeminiOAuth] Loaded credentials from file");
|
|
28500
28587
|
return credentials;
|
|
28501
28588
|
} catch (e) {
|
|
28502
|
-
log(`[
|
|
28589
|
+
log(`[GeminiOAuth] Failed to load credentials: ${e.message}`);
|
|
28503
28590
|
return null;
|
|
28504
28591
|
}
|
|
28505
28592
|
}
|
|
@@ -28517,7 +28604,7 @@ Details: ${e.message}`);
|
|
|
28517
28604
|
} finally {
|
|
28518
28605
|
closeSync2(fd);
|
|
28519
28606
|
}
|
|
28520
|
-
log(`[
|
|
28607
|
+
log(`[GeminiOAuth] Credentials saved to ${credPath}`);
|
|
28521
28608
|
}
|
|
28522
28609
|
generateCodeVerifier() {
|
|
28523
28610
|
return randomBytes(64).toString("base64url");
|
|
@@ -28526,46 +28613,26 @@ Details: ${e.message}`);
|
|
|
28526
28613
|
const hash2 = createHash2("sha256").update(verifier).digest("base64url");
|
|
28527
28614
|
return hash2;
|
|
28528
28615
|
}
|
|
28529
|
-
extractAccountId(idToken) {
|
|
28530
|
-
try {
|
|
28531
|
-
const parts = idToken.split(".");
|
|
28532
|
-
if (parts.length !== 3)
|
|
28533
|
-
return;
|
|
28534
|
-
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
|
|
28535
|
-
const authClaim = payload["https://api.openai.com/auth"];
|
|
28536
|
-
const accountId = authClaim?.chatgpt_account_id || payload.chatgpt_account_id || authClaim?.user_id;
|
|
28537
|
-
if (accountId) {
|
|
28538
|
-
log(`[CodexOAuth] Extracted account ID from id_token: ${accountId}`);
|
|
28539
|
-
return accountId;
|
|
28540
|
-
}
|
|
28541
|
-
return;
|
|
28542
|
-
} catch (e) {
|
|
28543
|
-
log(`[CodexOAuth] Failed to extract account ID from id_token: ${e.message}`);
|
|
28544
|
-
return;
|
|
28545
|
-
}
|
|
28546
|
-
}
|
|
28547
28616
|
buildAuthUrl(codeChallenge, state, redirectUri) {
|
|
28548
|
-
const
|
|
28549
|
-
|
|
28550
|
-
|
|
28551
|
-
|
|
28552
|
-
|
|
28553
|
-
|
|
28554
|
-
|
|
28555
|
-
"
|
|
28556
|
-
"
|
|
28557
|
-
|
|
28558
|
-
|
|
28559
|
-
|
|
28560
|
-
].join("&");
|
|
28561
|
-
return `${OAUTH_CONFIG.authUrl}?${params}`;
|
|
28617
|
+
const params = new URLSearchParams({
|
|
28618
|
+
client_id: OAUTH_CONFIG.clientId,
|
|
28619
|
+
redirect_uri: redirectUri,
|
|
28620
|
+
response_type: "code",
|
|
28621
|
+
scope: OAUTH_CONFIG.scopes.join(" "),
|
|
28622
|
+
code_challenge: codeChallenge,
|
|
28623
|
+
code_challenge_method: "S256",
|
|
28624
|
+
access_type: "offline",
|
|
28625
|
+
prompt: "consent",
|
|
28626
|
+
state
|
|
28627
|
+
});
|
|
28628
|
+
return `${OAUTH_CONFIG.authUrl}?${params.toString()}`;
|
|
28562
28629
|
}
|
|
28563
28630
|
async startCallbackServer(codeChallenge, state) {
|
|
28564
28631
|
return new Promise((resolve, reject) => {
|
|
28565
28632
|
let redirectUri = "";
|
|
28566
28633
|
const server = createServer((req, res) => {
|
|
28567
|
-
const url2 = new URL(req.url, redirectUri.replace("/
|
|
28568
|
-
if (url2.pathname === "/
|
|
28634
|
+
const url2 = new URL(req.url, redirectUri.replace("/callback", ""));
|
|
28635
|
+
if (url2.pathname === "/callback") {
|
|
28569
28636
|
const code = url2.searchParams.get("code");
|
|
28570
28637
|
const callbackState = url2.searchParams.get("state");
|
|
28571
28638
|
const error46 = url2.searchParams.get("error");
|
|
@@ -28630,15 +28697,15 @@ Details: ${e.message}`);
|
|
|
28630
28697
|
res.end("Not found");
|
|
28631
28698
|
}
|
|
28632
28699
|
});
|
|
28633
|
-
server.listen(
|
|
28700
|
+
server.listen(0, () => {
|
|
28634
28701
|
const address = server.address();
|
|
28635
28702
|
if (!address || typeof address === "string") {
|
|
28636
28703
|
reject(new Error("Failed to get server port"));
|
|
28637
28704
|
return;
|
|
28638
28705
|
}
|
|
28639
28706
|
const port = address.port;
|
|
28640
|
-
redirectUri = `http://localhost:${port}/
|
|
28641
|
-
log(`[
|
|
28707
|
+
redirectUri = `http://localhost:${port}/callback`;
|
|
28708
|
+
log(`[GeminiOAuth] Callback server started on http://localhost:${port}`);
|
|
28642
28709
|
const authUrl = this.buildAuthUrl(codeChallenge, state, redirectUri);
|
|
28643
28710
|
this.openBrowser(authUrl);
|
|
28644
28711
|
});
|
|
@@ -28652,7 +28719,7 @@ Details: ${e.message}`);
|
|
|
28652
28719
|
});
|
|
28653
28720
|
}
|
|
28654
28721
|
async exchangeCodeForTokens(code, verifier, redirectUri) {
|
|
28655
|
-
log("[
|
|
28722
|
+
log("[GeminiOAuth] Exchanging auth code for tokens");
|
|
28656
28723
|
try {
|
|
28657
28724
|
const response = await fetch(OAUTH_CONFIG.tokenUrl, {
|
|
28658
28725
|
method: "POST",
|
|
@@ -28664,6 +28731,7 @@ Details: ${e.message}`);
|
|
|
28664
28731
|
code,
|
|
28665
28732
|
redirect_uri: redirectUri,
|
|
28666
28733
|
client_id: OAUTH_CONFIG.clientId,
|
|
28734
|
+
client_secret: OAUTH_CONFIG.clientSecret,
|
|
28667
28735
|
code_verifier: verifier
|
|
28668
28736
|
})
|
|
28669
28737
|
});
|
|
@@ -28677,7 +28745,7 @@ Details: ${e.message}`);
|
|
|
28677
28745
|
}
|
|
28678
28746
|
return tokens;
|
|
28679
28747
|
} catch (e) {
|
|
28680
|
-
throw new Error(`Failed to authenticate with
|
|
28748
|
+
throw new Error(`Failed to authenticate with Google OAuth: ${e.message}`);
|
|
28681
28749
|
}
|
|
28682
28750
|
}
|
|
28683
28751
|
async openBrowser(url2) {
|
|
@@ -28691,7 +28759,7 @@ Details: ${e.message}`);
|
|
|
28691
28759
|
await execAsync(`xdg-open "${url2}"`);
|
|
28692
28760
|
}
|
|
28693
28761
|
console.log(`
|
|
28694
|
-
Opening browser for
|
|
28762
|
+
Opening browser for authentication...`);
|
|
28695
28763
|
console.log(`If the browser doesn't open, visit this URL:
|
|
28696
28764
|
${url2}
|
|
28697
28765
|
`);
|
|
@@ -28703,136 +28771,1006 @@ Please open this URL in your browser to authenticate:`);
|
|
|
28703
28771
|
}
|
|
28704
28772
|
}
|
|
28705
28773
|
}
|
|
28706
|
-
function
|
|
28707
|
-
|
|
28774
|
+
function reloadGeminiCredentials() {
|
|
28775
|
+
GeminiOAuth.getInstance().reloadCredentials();
|
|
28776
|
+
resetGeminiUserCache();
|
|
28708
28777
|
}
|
|
28709
|
-
|
|
28710
|
-
|
|
28778
|
+
function rankCodeAssistModel(model) {
|
|
28779
|
+
const lower = model.toLowerCase();
|
|
28780
|
+
let tier;
|
|
28781
|
+
if (lower.includes("pro"))
|
|
28782
|
+
tier = 0;
|
|
28783
|
+
else if (lower.includes("lite"))
|
|
28784
|
+
tier = 2;
|
|
28785
|
+
else if (lower.includes("flash"))
|
|
28786
|
+
tier = 1;
|
|
28787
|
+
else
|
|
28788
|
+
tier = 3;
|
|
28789
|
+
const vMatch = lower.match(/^gemini-(\d+(?:\.\d+)?)(?![\d.])/);
|
|
28790
|
+
const version2 = vMatch ? Number.parseFloat(vMatch[1]) : 0;
|
|
28791
|
+
return tier * 1000 - version2;
|
|
28792
|
+
}
|
|
28793
|
+
async function getServedCodeAssistModels(accessToken, projectId, opts) {
|
|
28794
|
+
const now = Date.now();
|
|
28795
|
+
if (!opts?.force && servedModelsCache && now - servedModelsCacheAt < SERVED_MODELS_TTL_MS) {
|
|
28796
|
+
return servedModelsCache;
|
|
28797
|
+
}
|
|
28798
|
+
try {
|
|
28799
|
+
const data = await retrieveUserQuota(accessToken, projectId);
|
|
28800
|
+
const ids = (data?.buckets ?? []).map((b) => b.modelId).filter((m) => typeof m === "string" && m.length > 0);
|
|
28801
|
+
if (ids.length > 0) {
|
|
28802
|
+
const sorted = ids.slice().sort((a, b) => rankCodeAssistModel(a) - rankCodeAssistModel(b));
|
|
28803
|
+
servedModelsCache = sorted;
|
|
28804
|
+
servedModelsCacheAt = now;
|
|
28805
|
+
return sorted;
|
|
28806
|
+
}
|
|
28807
|
+
} catch (err) {
|
|
28808
|
+
log(`[GeminiOAuth] getServedCodeAssistModels error: ${err}`);
|
|
28809
|
+
}
|
|
28810
|
+
if (servedModelsCache)
|
|
28811
|
+
return servedModelsCache;
|
|
28812
|
+
return CODE_ASSIST_FALLBACK_CHAIN.slice().sort((a, b) => rankCodeAssistModel(a) - rankCodeAssistModel(b));
|
|
28813
|
+
}
|
|
28814
|
+
async function getValidAccessToken() {
|
|
28815
|
+
const oauth = GeminiOAuth.getInstance();
|
|
28816
|
+
return oauth.getAccessToken();
|
|
28817
|
+
}
|
|
28818
|
+
function resetGeminiUserCache() {
|
|
28819
|
+
cachedProjectId = null;
|
|
28820
|
+
cachedTierId = null;
|
|
28821
|
+
cachedTierName = null;
|
|
28822
|
+
cachedSetupError = null;
|
|
28823
|
+
}
|
|
28824
|
+
function getGeminiTierDisplayName() {
|
|
28825
|
+
if (!cachedTierId)
|
|
28826
|
+
return "GeminiCA";
|
|
28827
|
+
return TIER_SHORT_NAMES[cachedTierId] || cachedTierId.replace(/-tier$/, "");
|
|
28828
|
+
}
|
|
28829
|
+
function getGeminiTierFullName() {
|
|
28830
|
+
if (cachedTierName)
|
|
28831
|
+
return cachedTierName;
|
|
28832
|
+
return getGeminiTierDisplayName();
|
|
28833
|
+
}
|
|
28834
|
+
function makeTerminalSetupError(message) {
|
|
28835
|
+
const err = new Error(message);
|
|
28836
|
+
err.terminal = true;
|
|
28837
|
+
return err;
|
|
28838
|
+
}
|
|
28839
|
+
function buildProjectRequiredError(tierId, chosenTier, loadRes) {
|
|
28840
|
+
const tierLabel = chosenTier?.name || chosenTier?.displayName || tierId;
|
|
28841
|
+
const lines = [
|
|
28842
|
+
`Gemini Code Assist requires a Google Cloud project for the "${tierLabel}" tier (${tierId}), and none is configured.`,
|
|
28843
|
+
"",
|
|
28844
|
+
"Set the project that holds your Code Assist license:",
|
|
28845
|
+
" export GOOGLE_CLOUD_PROJECT='your-project-id'"
|
|
28846
|
+
];
|
|
28847
|
+
const refused = loadRes.ineligibleTiers ?? [];
|
|
28848
|
+
if (refused.length > 0) {
|
|
28849
|
+
lines.push("", "Google refused the other tier(s) on this account:");
|
|
28850
|
+
for (const t of refused) {
|
|
28851
|
+
const name = t.tierName || t.tierId || "unknown tier";
|
|
28852
|
+
const code = t.reasonCode ? ` [${t.reasonCode}]` : "";
|
|
28853
|
+
lines.push(` \u2022 ${name}${code}`);
|
|
28854
|
+
if (t.reasonMessage)
|
|
28855
|
+
lines.push(` ${t.reasonMessage}`);
|
|
28856
|
+
}
|
|
28857
|
+
}
|
|
28858
|
+
lines.push("", "No project / no Code Assist seat? Use the direct Gemini API instead:", " export GEMINI_API_KEY='your-key' # https://aistudio.google.com/app/apikey", ' claudish --model google@gemini-2.5-pro "..."');
|
|
28859
|
+
return lines.join(`
|
|
28860
|
+
`);
|
|
28861
|
+
}
|
|
28862
|
+
async function setupGeminiUser(accessToken) {
|
|
28863
|
+
if (cachedProjectId && cachedTierId) {
|
|
28864
|
+
log(`[GeminiOAuth] Using cached project ID: ${cachedProjectId}, tier: ${cachedTierId}`);
|
|
28865
|
+
return { projectId: cachedProjectId, tierId: cachedTierId };
|
|
28866
|
+
}
|
|
28867
|
+
if (cachedSetupError) {
|
|
28868
|
+
log("[GeminiOAuth] Re-raising cached setup failure (no network retry)");
|
|
28869
|
+
throw makeTerminalSetupError(cachedSetupError);
|
|
28870
|
+
}
|
|
28871
|
+
const envProject = process.env.GOOGLE_CLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT_ID;
|
|
28872
|
+
log("[GeminiOAuth] Calling loadCodeAssist...");
|
|
28873
|
+
const loadRes = await callLoadCodeAssist(accessToken, envProject);
|
|
28874
|
+
log(`[GeminiOAuth] loadCodeAssist response: ${JSON.stringify(loadRes)}`);
|
|
28875
|
+
const resolvedTier = loadRes.paidTier?.id || (typeof loadRes.currentTier === "object" ? loadRes.currentTier?.id : loadRes.currentTier) || null;
|
|
28876
|
+
if ((loadRes.currentTier || loadRes.paidTier) && loadRes.cloudaicompanionProject) {
|
|
28877
|
+
const projectId2 = envProject || loadRes.cloudaicompanionProject;
|
|
28878
|
+
if (projectId2) {
|
|
28879
|
+
cachedProjectId = projectId2;
|
|
28880
|
+
cachedTierId = resolvedTier || "free-tier";
|
|
28881
|
+
cachedTierName = loadRes.paidTier?.name || null;
|
|
28882
|
+
log(`[GeminiOAuth] User already set up, project: ${projectId2}, tier: ${cachedTierId}`);
|
|
28883
|
+
return { projectId: projectId2, tierId: cachedTierId };
|
|
28884
|
+
}
|
|
28885
|
+
}
|
|
28886
|
+
const tierId = resolvedTier || loadRes.allowedTiers?.[0]?.id || "free-tier";
|
|
28887
|
+
const isFree = tierId === "free-tier";
|
|
28888
|
+
const onboardProject = isFree ? undefined : envProject;
|
|
28889
|
+
const chosenTier = loadRes.allowedTiers?.find((t) => t.id === tierId);
|
|
28890
|
+
if (!isFree && chosenTier?.userDefinedCloudaicompanionProject && !onboardProject) {
|
|
28891
|
+
cachedSetupError = buildProjectRequiredError(tierId, chosenTier, loadRes);
|
|
28892
|
+
throw makeTerminalSetupError(cachedSetupError);
|
|
28893
|
+
}
|
|
28894
|
+
const MAX_POLL_ATTEMPTS = 30;
|
|
28895
|
+
log(`[GeminiOAuth] Onboarding user to ${tierId}...`);
|
|
28896
|
+
let lro = await callOnboardUser(accessToken, tierId, onboardProject);
|
|
28897
|
+
log(`[GeminiOAuth] Initial onboardUser response: done=${lro.done}`);
|
|
28898
|
+
let attempts = 0;
|
|
28899
|
+
while (!lro.done && attempts < MAX_POLL_ATTEMPTS) {
|
|
28900
|
+
attempts++;
|
|
28901
|
+
log(`[GeminiOAuth] Polling onboardUser (attempt ${attempts}/${MAX_POLL_ATTEMPTS})...`);
|
|
28902
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
28903
|
+
lro = await callOnboardUser(accessToken, tierId, onboardProject);
|
|
28904
|
+
}
|
|
28905
|
+
if (!lro.done) {
|
|
28906
|
+
throw new Error(`Gemini onboarding timed out after ${MAX_POLL_ATTEMPTS * 2} seconds`);
|
|
28907
|
+
}
|
|
28908
|
+
if (lro.error) {
|
|
28909
|
+
throw new Error(`Gemini onboarding failed: ${JSON.stringify(lro.error)}`);
|
|
28910
|
+
}
|
|
28911
|
+
const projectId = lro.response?.cloudaicompanionProject?.id;
|
|
28912
|
+
if (!projectId) {
|
|
28913
|
+
if (envProject) {
|
|
28914
|
+
cachedProjectId = envProject;
|
|
28915
|
+
cachedTierId = tierId;
|
|
28916
|
+
return { projectId: envProject, tierId };
|
|
28917
|
+
}
|
|
28918
|
+
cachedSetupError = buildProjectRequiredError(tierId, chosenTier, loadRes);
|
|
28919
|
+
throw makeTerminalSetupError(cachedSetupError);
|
|
28920
|
+
}
|
|
28921
|
+
cachedProjectId = projectId;
|
|
28922
|
+
cachedTierId = tierId;
|
|
28923
|
+
log(`[GeminiOAuth] Onboarding complete, project: ${projectId}, tier: ${tierId}`);
|
|
28924
|
+
return { projectId, tierId };
|
|
28925
|
+
}
|
|
28926
|
+
async function callLoadCodeAssist(accessToken, projectId) {
|
|
28927
|
+
const metadata = GEMINI_IDENTITY_IS_ANTIGRAVITY ? { ideType: GEMINI_IDE_TYPE } : {
|
|
28928
|
+
pluginType: "GEMINI",
|
|
28929
|
+
ideType: GEMINI_IDE_TYPE,
|
|
28930
|
+
platform: "PLATFORM_UNSPECIFIED",
|
|
28931
|
+
duetProject: projectId
|
|
28932
|
+
};
|
|
28933
|
+
const res = await fetch(`${CODE_ASSIST_API_BASE}:loadCodeAssist`, {
|
|
28934
|
+
method: "POST",
|
|
28935
|
+
headers: {
|
|
28936
|
+
Authorization: `Bearer ${accessToken}`,
|
|
28937
|
+
"Content-Type": "application/json",
|
|
28938
|
+
"User-Agent": buildCodeAssistUserAgent()
|
|
28939
|
+
},
|
|
28940
|
+
body: JSON.stringify({ metadata, cloudaicompanionProject: projectId })
|
|
28941
|
+
});
|
|
28942
|
+
if (!res.ok) {
|
|
28943
|
+
throw new Error(`loadCodeAssist failed: ${res.status} ${await res.text()}`);
|
|
28944
|
+
}
|
|
28945
|
+
return await res.json();
|
|
28946
|
+
}
|
|
28947
|
+
async function callOnboardUser(accessToken, tierId, projectId) {
|
|
28948
|
+
const metadata = {
|
|
28949
|
+
pluginType: "GEMINI",
|
|
28950
|
+
ideType: GEMINI_IDE_TYPE,
|
|
28951
|
+
platform: "PLATFORM_UNSPECIFIED",
|
|
28952
|
+
duetProject: projectId
|
|
28953
|
+
};
|
|
28954
|
+
const res = await fetch(`${CODE_ASSIST_API_BASE}:onboardUser`, {
|
|
28955
|
+
method: "POST",
|
|
28956
|
+
headers: {
|
|
28957
|
+
Authorization: `Bearer ${accessToken}`,
|
|
28958
|
+
"Content-Type": "application/json",
|
|
28959
|
+
"User-Agent": buildCodeAssistUserAgent()
|
|
28960
|
+
},
|
|
28961
|
+
body: JSON.stringify({
|
|
28962
|
+
tierId,
|
|
28963
|
+
metadata,
|
|
28964
|
+
cloudaicompanionProject: projectId
|
|
28965
|
+
})
|
|
28966
|
+
});
|
|
28967
|
+
if (!res.ok) {
|
|
28968
|
+
throw new Error(`onboardUser failed: ${res.status} ${await res.text()}`);
|
|
28969
|
+
}
|
|
28970
|
+
return await res.json();
|
|
28971
|
+
}
|
|
28972
|
+
async function retrieveUserQuota(accessToken, projectId) {
|
|
28973
|
+
try {
|
|
28974
|
+
const res = await fetch(`${CODE_ASSIST_API_BASE}:retrieveUserQuota`, {
|
|
28975
|
+
method: "POST",
|
|
28976
|
+
headers: {
|
|
28977
|
+
Authorization: `Bearer ${accessToken}`,
|
|
28978
|
+
"Content-Type": "application/json",
|
|
28979
|
+
"User-Agent": `GeminiCLI/0.5.6/gemini-code-assist (${process.platform}; ${process.arch})`
|
|
28980
|
+
},
|
|
28981
|
+
body: JSON.stringify({ project: projectId })
|
|
28982
|
+
});
|
|
28983
|
+
if (!res.ok) {
|
|
28984
|
+
log(`[GeminiOAuth] retrieveUserQuota failed: ${res.status}`);
|
|
28985
|
+
return null;
|
|
28986
|
+
}
|
|
28987
|
+
return await res.json();
|
|
28988
|
+
} catch (err) {
|
|
28989
|
+
log(`[GeminiOAuth] retrieveUserQuota error: ${err}`);
|
|
28990
|
+
return null;
|
|
28991
|
+
}
|
|
28992
|
+
}
|
|
28993
|
+
function buildAntigravityUserAgent() {
|
|
28994
|
+
return `antigravity/cli/1.1.9 (aidev_client; os_type=${process.platform}; arch=${process.arch}; auth_method=consumer)`;
|
|
28995
|
+
}
|
|
28996
|
+
async function callLoadCodeAssistAntigravity(accessToken) {
|
|
28997
|
+
const res = await fetch(`${CODE_ASSIST_API_BASE}:loadCodeAssist`, {
|
|
28998
|
+
method: "POST",
|
|
28999
|
+
headers: {
|
|
29000
|
+
Authorization: `Bearer ${accessToken}`,
|
|
29001
|
+
"Content-Type": "application/json",
|
|
29002
|
+
"User-Agent": buildAntigravityUserAgent()
|
|
29003
|
+
},
|
|
29004
|
+
body: JSON.stringify({ metadata: { ideType: ANTIGRAVITY_IDE_TYPE } })
|
|
29005
|
+
});
|
|
29006
|
+
if (!res.ok) {
|
|
29007
|
+
throw new Error(`loadCodeAssist (antigravity) failed: ${res.status} ${await res.text()}`);
|
|
29008
|
+
}
|
|
29009
|
+
return await res.json();
|
|
29010
|
+
}
|
|
29011
|
+
async function setupAntigravityUser(accessToken) {
|
|
29012
|
+
if (cachedAgProjectId && cachedAgTierId) {
|
|
29013
|
+
return { projectId: cachedAgProjectId, tierId: cachedAgTierId };
|
|
29014
|
+
}
|
|
29015
|
+
const loadRes = await callLoadCodeAssistAntigravity(accessToken);
|
|
29016
|
+
log(`[Antigravity] loadCodeAssist response: ${JSON.stringify(loadRes)}`);
|
|
29017
|
+
const resolvedTier = loadRes.paidTier?.id || (typeof loadRes.currentTier === "object" ? loadRes.currentTier?.id : loadRes.currentTier) || "free-tier";
|
|
29018
|
+
const projectId = loadRes.cloudaicompanionProject;
|
|
29019
|
+
if (!projectId) {
|
|
29020
|
+
throw makeTerminalSetupError("Antigravity did not return a project for this account. Sign in to Antigravity " + "(the `agy` CLI) and try again, or use g@<model> with GEMINI_API_KEY " + "(get one at https://aistudio.google.com/app/apikey).");
|
|
29021
|
+
}
|
|
29022
|
+
cachedAgProjectId = projectId;
|
|
29023
|
+
cachedAgTierId = resolvedTier;
|
|
29024
|
+
cachedAgTierName = loadRes.paidTier?.name || null;
|
|
29025
|
+
log(`[Antigravity] User set up, project: ${projectId}, tier: ${resolvedTier}`);
|
|
29026
|
+
return { projectId, tierId: resolvedTier };
|
|
29027
|
+
}
|
|
29028
|
+
function getAntigravityTierDisplayName() {
|
|
29029
|
+
if (!cachedAgTierName && !cachedAgTierId)
|
|
29030
|
+
return "Antigravity";
|
|
29031
|
+
const id = cachedAgTierId || "";
|
|
29032
|
+
if (id.includes("ultra"))
|
|
29033
|
+
return "Antigravity Ultra";
|
|
29034
|
+
if (id.includes("pro"))
|
|
29035
|
+
return "Antigravity Pro";
|
|
29036
|
+
if (id === "free-tier")
|
|
29037
|
+
return "Antigravity Free";
|
|
29038
|
+
return cachedAgTierName || "Antigravity";
|
|
29039
|
+
}
|
|
29040
|
+
async function getServedAntigravityModels(accessToken, projectId, opts) {
|
|
29041
|
+
const now = Date.now();
|
|
29042
|
+
if (!opts?.force && agServedCache && now - agServedCacheAt < SERVED_MODELS_TTL_MS) {
|
|
29043
|
+
return agServedCache;
|
|
29044
|
+
}
|
|
29045
|
+
try {
|
|
29046
|
+
const res = await fetch(`${CODE_ASSIST_API_BASE}:fetchAvailableModels`, {
|
|
29047
|
+
method: "POST",
|
|
29048
|
+
headers: {
|
|
29049
|
+
Authorization: `Bearer ${accessToken}`,
|
|
29050
|
+
"Content-Type": "application/json",
|
|
29051
|
+
"User-Agent": buildAntigravityUserAgent()
|
|
29052
|
+
},
|
|
29053
|
+
body: JSON.stringify({ project: projectId })
|
|
29054
|
+
});
|
|
29055
|
+
if (res.ok) {
|
|
29056
|
+
const data = await res.json();
|
|
29057
|
+
const servedIds = data.models ? Object.keys(data.models) : [];
|
|
29058
|
+
const defaultId = typeof data.defaultAgentModelId === "string" ? data.defaultAgentModelId : null;
|
|
29059
|
+
if (servedIds.length > 0) {
|
|
29060
|
+
agServedCache = { servedIds, defaultId };
|
|
29061
|
+
agServedCacheAt = now;
|
|
29062
|
+
return agServedCache;
|
|
29063
|
+
}
|
|
29064
|
+
} else {
|
|
29065
|
+
log(`[Antigravity] fetchAvailableModels failed: ${res.status}`);
|
|
29066
|
+
}
|
|
29067
|
+
} catch (err) {
|
|
29068
|
+
log(`[Antigravity] fetchAvailableModels error: ${err}`);
|
|
29069
|
+
}
|
|
29070
|
+
if (agServedCache)
|
|
29071
|
+
return agServedCache;
|
|
29072
|
+
return { servedIds: [], defaultId: null };
|
|
29073
|
+
}
|
|
29074
|
+
var execAsync, getDefaultClientId = () => {
|
|
29075
|
+
const parts = [
|
|
29076
|
+
"681255809395",
|
|
29077
|
+
"oo8ft2oprdrnp9e3aqf6av3hmdib135j",
|
|
29078
|
+
"apps",
|
|
29079
|
+
"googleusercontent",
|
|
29080
|
+
"com"
|
|
29081
|
+
];
|
|
29082
|
+
return `${parts[0]}-${parts[1]}.${parts[2]}.${parts[3]}.${parts[4]}`;
|
|
29083
|
+
}, getDefaultClientSecret = () => {
|
|
29084
|
+
const p = ["GOCSPX", "4uHgMPm", "1o7Sk", "geV6Cu5clXFsxl"];
|
|
29085
|
+
return `${p[0]}-${p[1]}-${p[2]}-${p[3]}`;
|
|
29086
|
+
}, OAUTH_CONFIG, USE_ANTIGRAVITY_GEMINI_IDENTITY, USE_LEGACY_GEMINI_IDENTITY, GEMINI_IDE_TYPE, GEMINI_IDENTITY_IS_ANTIGRAVITY, CODE_ASSIST_API_BASE = "https://cloudcode-pa.googleapis.com/v1internal", CODE_ASSIST_FALLBACK_CHAIN, servedModelsCache = null, servedModelsCacheAt = 0, SERVED_MODELS_TTL_MS, cachedProjectId = null, cachedTierId = null, cachedTierName = null, cachedSetupError = null, TIER_SHORT_NAMES, ANTIGRAVITY_IDE_TYPE = "ANTIGRAVITY", cachedAgProjectId = null, cachedAgTierId = null, cachedAgTierName = null, agServedCache = null, agServedCacheAt = 0;
|
|
29087
|
+
var init_gemini_oauth = __esm(() => {
|
|
28711
29088
|
init_logger();
|
|
28712
29089
|
execAsync = promisify(exec);
|
|
28713
29090
|
OAUTH_CONFIG = {
|
|
28714
|
-
clientId:
|
|
28715
|
-
|
|
28716
|
-
|
|
28717
|
-
|
|
29091
|
+
clientId: process.env.GEMINI_CLIENT_ID || getDefaultClientId(),
|
|
29092
|
+
clientSecret: process.env.GEMINI_CLIENT_SECRET || getDefaultClientSecret(),
|
|
29093
|
+
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
29094
|
+
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
29095
|
+
scopes: [
|
|
29096
|
+
"https://www.googleapis.com/auth/cloud-platform",
|
|
29097
|
+
"https://www.googleapis.com/auth/userinfo.email",
|
|
29098
|
+
"https://www.googleapis.com/auth/userinfo.profile"
|
|
29099
|
+
]
|
|
29100
|
+
};
|
|
29101
|
+
USE_ANTIGRAVITY_GEMINI_IDENTITY = process.env.CLAUDISH_GEMINI_ANTIGRAVITY === "1";
|
|
29102
|
+
USE_LEGACY_GEMINI_IDENTITY = !USE_ANTIGRAVITY_GEMINI_IDENTITY;
|
|
29103
|
+
GEMINI_IDE_TYPE = USE_LEGACY_GEMINI_IDENTITY ? "GEMINI_CLI" : "ANTIGRAVITY";
|
|
29104
|
+
GEMINI_IDENTITY_IS_ANTIGRAVITY = !USE_LEGACY_GEMINI_IDENTITY;
|
|
29105
|
+
CODE_ASSIST_FALLBACK_CHAIN = [
|
|
29106
|
+
"gemini-2.5-pro",
|
|
29107
|
+
"gemini-2.5-flash",
|
|
29108
|
+
"gemini-2.5-flash-lite",
|
|
29109
|
+
"gemini-3.1-flash-lite"
|
|
29110
|
+
];
|
|
29111
|
+
SERVED_MODELS_TTL_MS = 10 * 60 * 1000;
|
|
29112
|
+
TIER_SHORT_NAMES = {
|
|
29113
|
+
"free-tier": "GeminiCA Free",
|
|
29114
|
+
"standard-tier": "GeminiCA Std",
|
|
29115
|
+
"g1-pro-tier": "GeminiCA Pro",
|
|
29116
|
+
"legacy-tier": "GeminiCA Legacy"
|
|
28718
29117
|
};
|
|
28719
29118
|
});
|
|
28720
29119
|
|
|
28721
|
-
// src/
|
|
28722
|
-
class
|
|
28723
|
-
|
|
28724
|
-
|
|
28725
|
-
|
|
28726
|
-
|
|
28727
|
-
|
|
28728
|
-
|
|
28729
|
-
|
|
28730
|
-
|
|
28731
|
-
|
|
29120
|
+
// src/handlers/shared/gemini-queue.ts
|
|
29121
|
+
class GeminiRequestQueue {
|
|
29122
|
+
static instance = null;
|
|
29123
|
+
queue = [];
|
|
29124
|
+
processing = false;
|
|
29125
|
+
minDelayMs = 1000;
|
|
29126
|
+
lastRequestTime = 0;
|
|
29127
|
+
consecutiveErrors = 0;
|
|
29128
|
+
totalProcessed = 0;
|
|
29129
|
+
totalErrors = 0;
|
|
29130
|
+
baseDelayMs = 1000;
|
|
29131
|
+
maxDelayMs = 1e4;
|
|
29132
|
+
maxQueueSize = 100;
|
|
29133
|
+
constructor() {
|
|
29134
|
+
log("[GeminiQueue] Queue initialized with minDelay=1000ms, maxQueueSize=100");
|
|
28732
29135
|
}
|
|
28733
|
-
|
|
28734
|
-
|
|
29136
|
+
static getInstance() {
|
|
29137
|
+
if (!GeminiRequestQueue.instance) {
|
|
29138
|
+
GeminiRequestQueue.instance = new GeminiRequestQueue;
|
|
29139
|
+
}
|
|
29140
|
+
return GeminiRequestQueue.instance;
|
|
28735
29141
|
}
|
|
28736
|
-
|
|
28737
|
-
this.
|
|
28738
|
-
|
|
29142
|
+
async enqueue(fetchFn) {
|
|
29143
|
+
if (this.queue.length >= this.maxQueueSize) {
|
|
29144
|
+
log(`[GeminiQueue] Queue full (${this.queue.length}/${this.maxQueueSize}), rejecting request`);
|
|
29145
|
+
throw new Error("Gemini request queue full. Please retry later.");
|
|
29146
|
+
}
|
|
29147
|
+
return new Promise((resolve, reject) => {
|
|
29148
|
+
const queuedRequest = {
|
|
29149
|
+
fetchFn,
|
|
29150
|
+
resolve,
|
|
29151
|
+
reject
|
|
29152
|
+
};
|
|
29153
|
+
this.queue.push(queuedRequest);
|
|
29154
|
+
log(`[GeminiQueue] Request enqueued (queue length: ${this.queue.length})`);
|
|
29155
|
+
if (!this.processing) {
|
|
29156
|
+
this.processQueue();
|
|
29157
|
+
}
|
|
29158
|
+
});
|
|
28739
29159
|
}
|
|
28740
|
-
async
|
|
28741
|
-
if (
|
|
29160
|
+
async processQueue() {
|
|
29161
|
+
if (this.processing) {
|
|
29162
|
+
return;
|
|
29163
|
+
}
|
|
29164
|
+
this.processing = true;
|
|
29165
|
+
log("[GeminiQueue] Worker started");
|
|
29166
|
+
while (this.queue.length > 0) {
|
|
29167
|
+
const request = this.queue.shift();
|
|
29168
|
+
if (!request)
|
|
29169
|
+
break;
|
|
29170
|
+
log(`[GeminiQueue] Processing request (${this.queue.length} remaining in queue)`);
|
|
28742
29171
|
try {
|
|
28743
|
-
|
|
28744
|
-
|
|
28745
|
-
|
|
28746
|
-
if (
|
|
28747
|
-
|
|
29172
|
+
await this.waitForNextSlot();
|
|
29173
|
+
const response = await request.fetchFn();
|
|
29174
|
+
this.lastRequestTime = Date.now();
|
|
29175
|
+
if (response.status === 429) {
|
|
29176
|
+
this.totalErrors++;
|
|
29177
|
+
const errorText = await response.clone().text();
|
|
29178
|
+
this.handleRateLimitResponse(errorText);
|
|
29179
|
+
log(`[GeminiQueue] Rate limit hit (429), adjusted delay to ${this.minDelayMs}ms`);
|
|
29180
|
+
} else {
|
|
29181
|
+
this.handleSuccessResponse();
|
|
28748
29182
|
}
|
|
28749
|
-
|
|
29183
|
+
this.totalProcessed++;
|
|
29184
|
+
request.resolve(response);
|
|
29185
|
+
} catch (error46) {
|
|
29186
|
+
this.totalErrors++;
|
|
29187
|
+
log(`[GeminiQueue] Request failed with error: ${error46}`);
|
|
29188
|
+
request.reject(error46 instanceof Error ? error46 : new Error(String(error46)));
|
|
28750
29189
|
}
|
|
28751
29190
|
}
|
|
28752
|
-
|
|
29191
|
+
this.processing = false;
|
|
29192
|
+
log("[GeminiQueue] Worker stopped (queue empty)");
|
|
28753
29193
|
}
|
|
28754
|
-
async
|
|
28755
|
-
|
|
29194
|
+
async waitForNextSlot() {
|
|
29195
|
+
const now = Date.now();
|
|
29196
|
+
const timeSinceLastRequest = now - this.lastRequestTime;
|
|
29197
|
+
let delayMs = this.minDelayMs;
|
|
29198
|
+
if (this.consecutiveErrors > 0) {
|
|
29199
|
+
const backoffMultiplier = 1 + this.consecutiveErrors * 0.5;
|
|
29200
|
+
delayMs = Math.min(this.minDelayMs * backoffMultiplier, this.maxDelayMs);
|
|
29201
|
+
log(`[GeminiQueue] Applying backoff (${this.consecutiveErrors} errors): ${delayMs}ms`);
|
|
29202
|
+
}
|
|
29203
|
+
if (timeSinceLastRequest < delayMs) {
|
|
29204
|
+
const waitMs = delayMs - timeSinceLastRequest;
|
|
29205
|
+
log(`[GeminiQueue] Waiting ${waitMs}ms before next request`);
|
|
29206
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
29207
|
+
}
|
|
28756
29208
|
}
|
|
28757
|
-
|
|
28758
|
-
|
|
29209
|
+
handleRateLimitResponse(errorText) {
|
|
29210
|
+
this.consecutiveErrors++;
|
|
29211
|
+
try {
|
|
29212
|
+
const errorData = JSON.parse(errorText);
|
|
29213
|
+
const quotaDetail = errorData?.error?.details?.find((d) => d.quotaResetDelay);
|
|
29214
|
+
if (quotaDetail?.quotaResetDelay) {
|
|
29215
|
+
const delayStr = quotaDetail.quotaResetDelay;
|
|
29216
|
+
const match = delayStr.match(/(\d+(?:\.\d+)?)/);
|
|
29217
|
+
if (match) {
|
|
29218
|
+
const delaySeconds = Number.parseFloat(match[1]);
|
|
29219
|
+
const suggestedDelayMs = Math.ceil(delaySeconds * 1000);
|
|
29220
|
+
this.minDelayMs = Math.max(suggestedDelayMs, this.minDelayMs, this.baseDelayMs);
|
|
29221
|
+
this.minDelayMs = Math.min(this.minDelayMs, this.maxDelayMs);
|
|
29222
|
+
log(`[GeminiQueue] Parsed quotaResetDelay: ${delayStr} (${suggestedDelayMs}ms), ` + `new minDelay: ${this.minDelayMs}ms`);
|
|
29223
|
+
}
|
|
29224
|
+
}
|
|
29225
|
+
} catch {
|
|
29226
|
+
log("[GeminiQueue] Failed to parse rate limit response, using backoff");
|
|
29227
|
+
}
|
|
29228
|
+
const backoffMultiplier = 1 + this.consecutiveErrors * 0.5;
|
|
29229
|
+
this.minDelayMs = Math.min(this.baseDelayMs * backoffMultiplier, this.maxDelayMs);
|
|
29230
|
+
}
|
|
29231
|
+
handleSuccessResponse() {
|
|
29232
|
+
if (this.consecutiveErrors > 0) {
|
|
29233
|
+
log(`[GeminiQueue] Success after ${this.consecutiveErrors} errors, resetting counter`);
|
|
29234
|
+
this.consecutiveErrors = 0;
|
|
29235
|
+
}
|
|
29236
|
+
if (this.minDelayMs > this.baseDelayMs) {
|
|
29237
|
+
this.minDelayMs = Math.max(this.baseDelayMs, this.minDelayMs * 0.9);
|
|
29238
|
+
log(`[GeminiQueue] Reducing delay to ${this.minDelayMs}ms`);
|
|
29239
|
+
}
|
|
29240
|
+
}
|
|
29241
|
+
getStats() {
|
|
29242
|
+
return {
|
|
29243
|
+
queueLength: this.queue.length,
|
|
29244
|
+
processing: this.processing,
|
|
29245
|
+
consecutiveErrors: this.consecutiveErrors,
|
|
29246
|
+
currentDelayMs: this.minDelayMs,
|
|
29247
|
+
totalProcessed: this.totalProcessed,
|
|
29248
|
+
totalErrors: this.totalErrors
|
|
29249
|
+
};
|
|
28759
29250
|
}
|
|
28760
29251
|
}
|
|
29252
|
+
var init_gemini_queue = __esm(() => {
|
|
29253
|
+
init_logger();
|
|
29254
|
+
});
|
|
28761
29255
|
|
|
28762
|
-
// src/
|
|
28763
|
-
|
|
28764
|
-
|
|
28765
|
-
|
|
28766
|
-
|
|
28767
|
-
|
|
28768
|
-
|
|
28769
|
-
|
|
28770
|
-
if (
|
|
28771
|
-
|
|
28772
|
-
|
|
28773
|
-
|
|
29256
|
+
// src/providers/transport/antigravity.ts
|
|
29257
|
+
import { randomUUID } from "crypto";
|
|
29258
|
+
function rankReasoningSuffix(suffix) {
|
|
29259
|
+
const rank = REASONING_TIER_RANK[suffix.toLowerCase()];
|
|
29260
|
+
return rank === undefined ? Number.MAX_SAFE_INTEGER : rank;
|
|
29261
|
+
}
|
|
29262
|
+
function resolveAntigravityModelId(requested, servedIds, defaultId) {
|
|
29263
|
+
const req = requested.trim();
|
|
29264
|
+
if (servedIds.includes(req))
|
|
29265
|
+
return req;
|
|
29266
|
+
const familyPrefix = `${req}-`;
|
|
29267
|
+
const variants = servedIds.filter((id) => id.startsWith(familyPrefix));
|
|
29268
|
+
if (variants.length > 0) {
|
|
29269
|
+
if (defaultId && variants.includes(defaultId))
|
|
29270
|
+
return defaultId;
|
|
29271
|
+
let best = variants[0];
|
|
29272
|
+
let bestRank = rankReasoningSuffix(best.slice(familyPrefix.length));
|
|
29273
|
+
for (const variant of variants.slice(1)) {
|
|
29274
|
+
const rank = rankReasoningSuffix(variant.slice(familyPrefix.length));
|
|
29275
|
+
if (rank < bestRank) {
|
|
29276
|
+
best = variant;
|
|
29277
|
+
bestRank = rank;
|
|
29278
|
+
}
|
|
29279
|
+
}
|
|
29280
|
+
return best;
|
|
29281
|
+
}
|
|
29282
|
+
return req;
|
|
29283
|
+
}
|
|
29284
|
+
function createActivityRequestId() {
|
|
29285
|
+
return Math.random().toString(36).substring(7);
|
|
29286
|
+
}
|
|
29287
|
+
function classify429(responseBody) {
|
|
29288
|
+
try {
|
|
29289
|
+
const raw = JSON.parse(responseBody);
|
|
29290
|
+
const error46 = Array.isArray(raw) ? raw[0]?.error : raw?.error;
|
|
29291
|
+
const details = Array.isArray(error46?.details) ? error46.details : [];
|
|
29292
|
+
const retryInfo = details.find((d) => d["@type"] === "type.googleapis.com/google.rpc.RetryInfo");
|
|
29293
|
+
let retryDelayMs = parseRetryDelay(retryInfo?.retryDelay);
|
|
29294
|
+
if (retryDelayMs === undefined && typeof error46?.message === "string") {
|
|
29295
|
+
const match = error46.message.match(/retry in ([\d.]+)(ms|s)/i);
|
|
29296
|
+
if (match) {
|
|
29297
|
+
const val = Number.parseFloat(match[1]);
|
|
29298
|
+
retryDelayMs = match[2] === "ms" ? Math.round(val) : Math.round(val * 1000);
|
|
29299
|
+
}
|
|
29300
|
+
}
|
|
29301
|
+
const errorInfo = details.find((d) => d["@type"] === "type.googleapis.com/google.rpc.ErrorInfo");
|
|
29302
|
+
const reason = errorInfo?.reason;
|
|
29303
|
+
if (reason === "QUOTA_EXHAUSTED") {
|
|
29304
|
+
return { terminal: true, retryDelayMs, reason };
|
|
29305
|
+
}
|
|
29306
|
+
if (reason === "RATE_LIMIT_EXCEEDED") {
|
|
29307
|
+
return { terminal: false, retryDelayMs: retryDelayMs ?? DEFAULT_RATE_LIMIT_DELAY_MS, reason };
|
|
29308
|
+
}
|
|
29309
|
+
if (reason === "MODEL_CAPACITY_EXHAUSTED") {
|
|
29310
|
+
return { terminal: true, retryDelayMs, reason };
|
|
29311
|
+
}
|
|
29312
|
+
const quotaFailure = details.find((d) => d["@type"] === "type.googleapis.com/google.rpc.QuotaFailure");
|
|
29313
|
+
if (quotaFailure?.violations?.length) {
|
|
29314
|
+
const text = quotaFailure.violations.map((v) => `${v.quotaId || ""} ${v.description || ""}`).join(" ").toLowerCase();
|
|
29315
|
+
if (text.includes("perday") || text.includes("daily") || text.includes("per day")) {
|
|
29316
|
+
return { terminal: true, retryDelayMs, reason };
|
|
29317
|
+
}
|
|
29318
|
+
if (text.includes("perminute") || text.includes("per minute")) {
|
|
29319
|
+
return { terminal: false, retryDelayMs: retryDelayMs ?? 60000, reason };
|
|
29320
|
+
}
|
|
29321
|
+
}
|
|
29322
|
+
return { terminal: false, retryDelayMs, reason };
|
|
29323
|
+
} catch {
|
|
29324
|
+
return null;
|
|
28774
29325
|
}
|
|
28775
|
-
|
|
29326
|
+
}
|
|
29327
|
+
function parseRetryDelay(value) {
|
|
29328
|
+
if (!value)
|
|
29329
|
+
return;
|
|
29330
|
+
if (typeof value === "string") {
|
|
29331
|
+
const match = value.match(/([\d.]+)s/);
|
|
29332
|
+
return match ? Math.round(Number.parseFloat(match[1]) * 1000) : undefined;
|
|
29333
|
+
}
|
|
29334
|
+
if (typeof value === "object") {
|
|
29335
|
+
const seconds = typeof value.seconds === "number" ? value.seconds : 0;
|
|
29336
|
+
const nanos = typeof value.nanos === "number" ? value.nanos : 0;
|
|
29337
|
+
const ms = Math.round(seconds * 1000 + nanos / 1e6);
|
|
29338
|
+
return ms > 0 ? ms : undefined;
|
|
29339
|
+
}
|
|
29340
|
+
return;
|
|
28776
29341
|
}
|
|
28777
29342
|
|
|
28778
|
-
class
|
|
28779
|
-
|
|
28780
|
-
|
|
28781
|
-
|
|
28782
|
-
return this.
|
|
29343
|
+
class AntigravityProviderTransport {
|
|
29344
|
+
name = "antigravity";
|
|
29345
|
+
_displayName = "Antigravity";
|
|
29346
|
+
get displayName() {
|
|
29347
|
+
return this._displayName;
|
|
28783
29348
|
}
|
|
28784
|
-
|
|
28785
|
-
|
|
28786
|
-
|
|
29349
|
+
streamFormat = "gemini-sse";
|
|
29350
|
+
modelName;
|
|
29351
|
+
servedModelName;
|
|
29352
|
+
accessToken = null;
|
|
29353
|
+
projectId = null;
|
|
29354
|
+
tierId = null;
|
|
29355
|
+
cachedAuth = null;
|
|
29356
|
+
lastEnvelope = null;
|
|
29357
|
+
_activeModelName;
|
|
29358
|
+
servedModels = [];
|
|
29359
|
+
defaultServedModel = null;
|
|
29360
|
+
constructor(modelName) {
|
|
29361
|
+
this.modelName = modelName;
|
|
29362
|
+
this.servedModelName = modelName;
|
|
29363
|
+
}
|
|
29364
|
+
getActiveModelName() {
|
|
29365
|
+
return this._activeModelName;
|
|
29366
|
+
}
|
|
29367
|
+
getEndpoint() {
|
|
29368
|
+
return CODE_ASSIST_ENDPOINT;
|
|
29369
|
+
}
|
|
29370
|
+
async getHeaders() {
|
|
29371
|
+
if (this.cachedAuth)
|
|
29372
|
+
return { ...this.cachedAuth.headers };
|
|
29373
|
+
return this.buildLocalHeaders();
|
|
29374
|
+
}
|
|
29375
|
+
buildLocalHeaders() {
|
|
28787
29376
|
return {
|
|
28788
|
-
|
|
28789
|
-
|
|
28790
|
-
|
|
28791
|
-
...p,
|
|
28792
|
-
store: false,
|
|
28793
|
-
include: ["reasoning.encrypted_content"]
|
|
28794
|
-
})
|
|
29377
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
29378
|
+
"User-Agent": buildAntigravityUserAgent(),
|
|
29379
|
+
"x-activity-request-id": createActivityRequestId()
|
|
28795
29380
|
};
|
|
28796
29381
|
}
|
|
28797
|
-
async
|
|
28798
|
-
await
|
|
29382
|
+
async refreshAuth() {
|
|
29383
|
+
this.cachedAuth = await credentials.getRequestAuth("antigravity", {
|
|
29384
|
+
model: this.modelName
|
|
29385
|
+
});
|
|
29386
|
+
this.accessToken = await getValidAntigravityAccessToken();
|
|
29387
|
+
const { projectId, tierId } = await setupAntigravityUser(this.accessToken);
|
|
29388
|
+
this.projectId = projectId;
|
|
29389
|
+
this.tierId = tierId;
|
|
29390
|
+
this._displayName = getAntigravityTierDisplayName();
|
|
29391
|
+
const served = await getServedAntigravityModels(this.accessToken, this.projectId);
|
|
29392
|
+
this.servedModels = served.servedIds;
|
|
29393
|
+
this.defaultServedModel = served.defaultId;
|
|
29394
|
+
this.servedModelName = resolveAntigravityModelId(this.modelName, this.servedModels, this.defaultServedModel);
|
|
29395
|
+
log(`[Antigravity] Auth refreshed, project: ${this.projectId}, tier: ${this._displayName}, ` + `model: ${this.modelName} -> ${this.servedModelName}, served: ${this.servedModels.join(",") || "(none)"}`);
|
|
28799
29396
|
}
|
|
28800
|
-
|
|
28801
|
-
|
|
29397
|
+
transformPayload(payload) {
|
|
29398
|
+
const envelope = this.cachedAuth?.transformPayload ? this.cachedAuth.transformPayload(payload) : this.buildEnvelope(payload, this.servedModelName);
|
|
29399
|
+
this.lastEnvelope = envelope;
|
|
29400
|
+
return envelope;
|
|
29401
|
+
}
|
|
29402
|
+
buildEnvelope(innerPayload, model) {
|
|
29403
|
+
const envelope = {
|
|
29404
|
+
model,
|
|
29405
|
+
project: this.projectId,
|
|
29406
|
+
user_prompt_id: randomUUID(),
|
|
29407
|
+
request: innerPayload
|
|
29408
|
+
};
|
|
29409
|
+
if (this.tierId && this.tierId !== "free-tier") {
|
|
29410
|
+
envelope.enabled_credit_types = ["GOOGLE_ONE_AI"];
|
|
29411
|
+
}
|
|
29412
|
+
return envelope;
|
|
29413
|
+
}
|
|
29414
|
+
async enqueueRequest(fetchFn) {
|
|
29415
|
+
const queue = GeminiRequestQueue.getInstance();
|
|
29416
|
+
let lastResponse = null;
|
|
29417
|
+
for (let attempt = 1;attempt <= MAX_RETRY_ATTEMPTS; attempt++) {
|
|
29418
|
+
const response = attempt === 1 ? await queue.enqueue(fetchFn) : await queue.enqueue(fetchFn);
|
|
29419
|
+
if (response.status !== 429) {
|
|
29420
|
+
if (response.status === 404) {
|
|
29421
|
+
return this.rewriteModelNotFound(response);
|
|
29422
|
+
}
|
|
29423
|
+
return response;
|
|
29424
|
+
}
|
|
29425
|
+
const bodyText = await response.clone().text();
|
|
29426
|
+
const classification = classify429(bodyText);
|
|
29427
|
+
lastResponse = response;
|
|
29428
|
+
if (!classification) {
|
|
29429
|
+
log("[Antigravity] 429 response could not be classified, returning to caller");
|
|
29430
|
+
return response;
|
|
29431
|
+
}
|
|
29432
|
+
log(`[Antigravity] 429 classified: reason=${classification.reason}, terminal=${classification.terminal}, delay=${classification.retryDelayMs}ms`);
|
|
29433
|
+
if (classification.reason === "MODEL_CAPACITY_EXHAUSTED") {
|
|
29434
|
+
return this.handleCapacityExhausted(response, queue);
|
|
29435
|
+
}
|
|
29436
|
+
if (classification.terminal) {
|
|
29437
|
+
logStderr(`[Antigravity] Quota exhausted (${classification.reason || "daily limit"}). Check plan limits.`);
|
|
29438
|
+
return response;
|
|
29439
|
+
}
|
|
29440
|
+
if (attempt < MAX_RETRY_ATTEMPTS) {
|
|
29441
|
+
const delay = classification.retryDelayMs ?? DEFAULT_RATE_LIMIT_DELAY_MS;
|
|
29442
|
+
logStderr(`[Antigravity] Rate limited (${classification.reason || "unknown"}), retrying in ${(delay / 1000).toFixed(1)}s (attempt ${attempt}/${MAX_RETRY_ATTEMPTS})`);
|
|
29443
|
+
if (attempt === 1) {
|
|
29444
|
+
await this.logQuotaInfo();
|
|
29445
|
+
}
|
|
29446
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
29447
|
+
}
|
|
29448
|
+
}
|
|
29449
|
+
logStderr(`[Antigravity] Rate limit persisted after ${MAX_RETRY_ATTEMPTS} retries`);
|
|
29450
|
+
return lastResponse;
|
|
29451
|
+
}
|
|
29452
|
+
async handleCapacityExhausted(originalResponse, queue) {
|
|
29453
|
+
const candidates = this.servedModels.filter((m) => m !== this.servedModelName);
|
|
29454
|
+
if (candidates.length === 0) {
|
|
29455
|
+
log(`[Antigravity] ${this.servedModelName} capacity exhausted, no fallback models available`);
|
|
29456
|
+
return originalResponse;
|
|
29457
|
+
}
|
|
29458
|
+
if (!this.lastEnvelope) {
|
|
29459
|
+
log(`[Antigravity] ${this.servedModelName} capacity exhausted but no stored envelope for retry`);
|
|
29460
|
+
return originalResponse;
|
|
29461
|
+
}
|
|
29462
|
+
log(`[Antigravity] Model ${this.servedModelName} capacity exhausted, starting fallback chain`);
|
|
29463
|
+
logStderr(`[Antigravity] ${this.servedModelName} capacity exhausted, trying fallback models...`);
|
|
29464
|
+
let lastResponse = originalResponse;
|
|
29465
|
+
const innerPayload = this.lastEnvelope.request;
|
|
29466
|
+
const endpoint = this.getEndpoint();
|
|
29467
|
+
const tried = [this.servedModelName];
|
|
29468
|
+
for (const fallbackModel of candidates) {
|
|
29469
|
+
log(`[Antigravity] Trying fallback model: ${fallbackModel}`);
|
|
29470
|
+
tried.push(fallbackModel);
|
|
29471
|
+
const fallbackEnvelope = this.buildEnvelope(innerPayload, fallbackModel);
|
|
29472
|
+
const headers = this.buildLocalHeaders();
|
|
29473
|
+
headers["Content-Type"] = "application/json";
|
|
29474
|
+
const fallbackResponse = await queue.enqueue(() => fetch(endpoint, {
|
|
29475
|
+
method: "POST",
|
|
29476
|
+
headers,
|
|
29477
|
+
body: JSON.stringify(fallbackEnvelope)
|
|
29478
|
+
}));
|
|
29479
|
+
if (fallbackResponse.status === 200) {
|
|
29480
|
+
this._activeModelName = fallbackModel;
|
|
29481
|
+
logStderr(`[Antigravity] Using fallback model: ${fallbackModel} (${this.servedModelName} had no capacity)`);
|
|
29482
|
+
return fallbackResponse;
|
|
29483
|
+
}
|
|
29484
|
+
if (fallbackResponse.status === 404) {
|
|
29485
|
+
log(`[Antigravity] ${fallbackModel} returned 404, skipping to next fallback`);
|
|
29486
|
+
lastResponse = fallbackResponse;
|
|
29487
|
+
continue;
|
|
29488
|
+
}
|
|
29489
|
+
if (fallbackResponse.status === 429) {
|
|
29490
|
+
const fallbackBodyText = await fallbackResponse.clone().text();
|
|
29491
|
+
const classification = classify429(fallbackBodyText);
|
|
29492
|
+
if (classification?.reason === "MODEL_CAPACITY_EXHAUSTED") {
|
|
29493
|
+
log(`[Antigravity] ${fallbackModel} also capacity exhausted, trying next...`);
|
|
29494
|
+
lastResponse = fallbackResponse;
|
|
29495
|
+
continue;
|
|
29496
|
+
}
|
|
29497
|
+
return fallbackResponse;
|
|
29498
|
+
}
|
|
29499
|
+
return fallbackResponse;
|
|
29500
|
+
}
|
|
29501
|
+
log("[Antigravity] All fallback models exhausted");
|
|
29502
|
+
logStderr(`[Antigravity] All models capacity exhausted (tried: ${tried.join(" -> ")})`);
|
|
29503
|
+
if (lastResponse.status === 404) {
|
|
29504
|
+
return this.rewriteModelNotFound(lastResponse, true);
|
|
29505
|
+
}
|
|
29506
|
+
return lastResponse;
|
|
29507
|
+
}
|
|
29508
|
+
rewriteModelNotFound(response, capacityFallbacksExhausted = false) {
|
|
29509
|
+
const served = this.servedModels;
|
|
29510
|
+
if (!capacityFallbacksExhausted && served.includes(this.servedModelName)) {
|
|
29511
|
+
log(`[Antigravity] 404 for ${this.servedModelName}, which IS in the served set \u2014 passing through unmodified`);
|
|
29512
|
+
return response;
|
|
29513
|
+
}
|
|
29514
|
+
response.text().catch(() => {});
|
|
29515
|
+
const servesClause = served.length > 0 ? `That tier currently serves: ${served.join(", ")}. ` : "";
|
|
29516
|
+
const tier = this._displayName || "Antigravity";
|
|
29517
|
+
const reason = capacityFallbacksExhausted ? `${this.modelName} could not be served after every Antigravity capacity fallback failed (${tier}, via ag@). ` + servesClause : `${this.modelName} is not served by your Antigravity tier (${tier}, via ag@). ` + servesClause;
|
|
29518
|
+
const message = reason + `To use ${this.modelName}, go through the direct Gemini API instead \u2014 ` + `set GEMINI_API_KEY (get one at https://aistudio.google.com/app/apikey) and run ` + `google@${this.modelName}.`;
|
|
29519
|
+
const list = served.join(", ");
|
|
29520
|
+
const body = JSON.stringify({
|
|
29521
|
+
error: { code: 404, status: "NOT_FOUND", message }
|
|
29522
|
+
});
|
|
29523
|
+
if (capacityFallbacksExhausted) {
|
|
29524
|
+
logStderr(`[Antigravity] ${this.modelName} capacity fallbacks exhausted (404). Reported models: ${list}`);
|
|
29525
|
+
} else {
|
|
29526
|
+
logStderr(`[Antigravity] ${this.modelName} not served by ${tier} (404). Serves: ${list}`);
|
|
29527
|
+
}
|
|
29528
|
+
return new Response(body, {
|
|
29529
|
+
status: 404,
|
|
29530
|
+
headers: { "Content-Type": "application/json" }
|
|
29531
|
+
});
|
|
29532
|
+
}
|
|
29533
|
+
async logQuotaInfo() {
|
|
29534
|
+
if (!this.accessToken || !this.projectId)
|
|
29535
|
+
return;
|
|
29536
|
+
try {
|
|
29537
|
+
const data = await retrieveUserQuota(this.accessToken, this.projectId);
|
|
29538
|
+
if (!data?.buckets?.length)
|
|
29539
|
+
return;
|
|
29540
|
+
const lines = [];
|
|
29541
|
+
for (const bucket of data.buckets) {
|
|
29542
|
+
if (!bucket.modelId)
|
|
29543
|
+
continue;
|
|
29544
|
+
const pct = typeof bucket.remainingFraction === "number" ? `${(bucket.remainingFraction * 100).toFixed(1)}%` : "?";
|
|
29545
|
+
const reset = bucket.resetTime ? new Date(bucket.resetTime).toLocaleTimeString([], {
|
|
29546
|
+
hour: "2-digit",
|
|
29547
|
+
minute: "2-digit"
|
|
29548
|
+
}) : "?";
|
|
29549
|
+
lines.push(` ${bucket.modelId}: ${pct} remaining (resets ${reset})`);
|
|
29550
|
+
}
|
|
29551
|
+
if (lines.length > 0) {
|
|
29552
|
+
logStderr(`[Antigravity] Quota status:
|
|
29553
|
+
${lines.join(`
|
|
29554
|
+
`)}`);
|
|
29555
|
+
}
|
|
29556
|
+
} catch {}
|
|
29557
|
+
}
|
|
29558
|
+
async getQuotaRemaining(modelName) {
|
|
29559
|
+
if (!this.accessToken || !this.projectId)
|
|
29560
|
+
return;
|
|
29561
|
+
try {
|
|
29562
|
+
const data = await retrieveUserQuota(this.accessToken, this.projectId);
|
|
29563
|
+
if (!data?.buckets?.length)
|
|
29564
|
+
return;
|
|
29565
|
+
const bucket = data.buckets.find((b) => b.modelId === modelName);
|
|
29566
|
+
return typeof bucket?.remainingFraction === "number" ? bucket.remainingFraction : undefined;
|
|
29567
|
+
} catch {
|
|
29568
|
+
return;
|
|
29569
|
+
}
|
|
28802
29570
|
}
|
|
28803
29571
|
}
|
|
28804
|
-
|
|
28805
|
-
|
|
28806
|
-
|
|
28807
|
-
|
|
28808
|
-
|
|
29572
|
+
var CODE_ASSIST_BASE = "https://cloudcode-pa.googleapis.com", CODE_ASSIST_ENDPOINT, MAX_RETRY_ATTEMPTS = 3, DEFAULT_RATE_LIMIT_DELAY_MS = 1e4, REASONING_TIER_RANK;
|
|
29573
|
+
var init_antigravity = __esm(() => {
|
|
29574
|
+
init_authority();
|
|
29575
|
+
init_antigravity_token();
|
|
29576
|
+
init_gemini_oauth();
|
|
29577
|
+
init_gemini_queue();
|
|
29578
|
+
init_logger();
|
|
29579
|
+
CODE_ASSIST_ENDPOINT = `${CODE_ASSIST_BASE}/v1internal:streamGenerateContent?alt=sse`;
|
|
29580
|
+
REASONING_TIER_RANK = {
|
|
29581
|
+
high: 0,
|
|
29582
|
+
medium: 1,
|
|
29583
|
+
low: 2,
|
|
29584
|
+
"extra-low": 3,
|
|
29585
|
+
tiered: 4
|
|
29586
|
+
};
|
|
29587
|
+
});
|
|
29588
|
+
|
|
29589
|
+
// src/auth/credentials/antigravity-credential.ts
|
|
29590
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
29591
|
+
function createActivityRequestId2() {
|
|
29592
|
+
return Math.random().toString(36).substring(7);
|
|
28809
29593
|
}
|
|
28810
|
-
|
|
28811
|
-
|
|
28812
|
-
|
|
28813
|
-
|
|
29594
|
+
|
|
29595
|
+
class AntigravityCredentialProvider {
|
|
29596
|
+
catalogName = "antigravity";
|
|
29597
|
+
async isAvailable() {
|
|
29598
|
+
try {
|
|
29599
|
+
return readSharedAntigravityToken() !== null;
|
|
29600
|
+
} catch {
|
|
29601
|
+
return false;
|
|
29602
|
+
}
|
|
29603
|
+
}
|
|
29604
|
+
async getRequestAuth(ctx) {
|
|
29605
|
+
const token = await getValidAntigravityAccessToken();
|
|
29606
|
+
const { projectId, tierId } = await setupAntigravityUser(token);
|
|
29607
|
+
const { servedIds, defaultId } = await getServedAntigravityModels(token, projectId);
|
|
29608
|
+
const servedModel = resolveAntigravityModelId(ctx.model, servedIds, defaultId);
|
|
29609
|
+
return {
|
|
29610
|
+
headers: {
|
|
29611
|
+
Authorization: `Bearer ${token}`,
|
|
29612
|
+
"User-Agent": buildAntigravityUserAgent(),
|
|
29613
|
+
"x-activity-request-id": createActivityRequestId2()
|
|
29614
|
+
},
|
|
29615
|
+
transformPayload: (inner) => {
|
|
29616
|
+
const env = {
|
|
29617
|
+
model: servedModel,
|
|
29618
|
+
project: projectId,
|
|
29619
|
+
user_prompt_id: randomUUID2(),
|
|
29620
|
+
request: inner
|
|
29621
|
+
};
|
|
29622
|
+
if (tierId && tierId !== "free-tier") {
|
|
29623
|
+
env.enabled_credit_types = ["GOOGLE_ONE_AI"];
|
|
29624
|
+
}
|
|
29625
|
+
return env;
|
|
29626
|
+
}
|
|
29627
|
+
};
|
|
29628
|
+
}
|
|
29629
|
+
}
|
|
29630
|
+
var init_antigravity_credential = __esm(() => {
|
|
29631
|
+
init_antigravity();
|
|
29632
|
+
init_antigravity_token();
|
|
29633
|
+
init_gemini_oauth();
|
|
28814
29634
|
});
|
|
28815
29635
|
|
|
28816
|
-
// src/auth/
|
|
29636
|
+
// src/auth/credentials/api-key-credential.ts
|
|
29637
|
+
import { existsSync as existsSync8 } from "fs";
|
|
29638
|
+
import { homedir as homedir10 } from "os";
|
|
29639
|
+
import { join as join10 } from "path";
|
|
29640
|
+
function realValue(v) {
|
|
29641
|
+
if (!v)
|
|
29642
|
+
return;
|
|
29643
|
+
return UNEXPANDED_PLACEHOLDER.test(v.trim()) ? undefined : v;
|
|
29644
|
+
}
|
|
29645
|
+
|
|
29646
|
+
class ApiKeyCredentialProvider {
|
|
29647
|
+
catalogName;
|
|
29648
|
+
envVar;
|
|
29649
|
+
aliases;
|
|
29650
|
+
authScheme;
|
|
29651
|
+
staticHeaders;
|
|
29652
|
+
publicKeyFallback;
|
|
29653
|
+
oauthFallback;
|
|
29654
|
+
declaredKey;
|
|
29655
|
+
cachedKey;
|
|
29656
|
+
resolving;
|
|
29657
|
+
constructor(descriptor) {
|
|
29658
|
+
this.catalogName = descriptor.catalogName;
|
|
29659
|
+
this.envVar = descriptor.envVar;
|
|
29660
|
+
this.aliases = descriptor.aliases ?? [];
|
|
29661
|
+
this.authScheme = descriptor.authScheme ?? "bearer";
|
|
29662
|
+
this.staticHeaders = descriptor.staticHeaders ?? {};
|
|
29663
|
+
this.publicKeyFallback = descriptor.publicKeyFallback;
|
|
29664
|
+
this.oauthFallback = descriptor.oauthFallback;
|
|
29665
|
+
this.declaredKey = descriptor.declaredKey;
|
|
29666
|
+
}
|
|
29667
|
+
resolveFromEnvConfig() {
|
|
29668
|
+
return realValue(process.env[this.envVar]) || this.aliases.map((a) => realValue(process.env[a])).find((v) => !!v) || realValue(getApiKey(this.envVar)) || realValue(this.resolveDeclared());
|
|
29669
|
+
}
|
|
29670
|
+
resolveDeclared() {
|
|
29671
|
+
try {
|
|
29672
|
+
return this.declaredKey?.() || undefined;
|
|
29673
|
+
} catch {
|
|
29674
|
+
return;
|
|
29675
|
+
}
|
|
29676
|
+
}
|
|
29677
|
+
hasOauthFallbackFile() {
|
|
29678
|
+
if (!this.oauthFallback)
|
|
29679
|
+
return false;
|
|
29680
|
+
try {
|
|
29681
|
+
return existsSync8(join10(homedir10(), ".claudish", this.oauthFallback));
|
|
29682
|
+
} catch {
|
|
29683
|
+
return false;
|
|
29684
|
+
}
|
|
29685
|
+
}
|
|
29686
|
+
async resolveKey(opts) {
|
|
29687
|
+
if (this.cachedKey !== undefined)
|
|
29688
|
+
return this.cachedKey;
|
|
29689
|
+
if (this.resolving)
|
|
29690
|
+
return this.resolving;
|
|
29691
|
+
this.resolving = (async () => {
|
|
29692
|
+
const local = this.resolveFromEnvConfig();
|
|
29693
|
+
if (local) {
|
|
29694
|
+
this.cachedKey = local;
|
|
29695
|
+
return local;
|
|
29696
|
+
}
|
|
29697
|
+
if (hasOpSources()) {
|
|
29698
|
+
const wanted = new Set([this.envVar, ...this.aliases]);
|
|
29699
|
+
const resolved = await resolveOpKeyForEnvVars(wanted, {
|
|
29700
|
+
onAuthFailure: "skip",
|
|
29701
|
+
allowPrompt: opts?.allowOpPrompt ?? false
|
|
29702
|
+
});
|
|
29703
|
+
const value = resolved[this.envVar] ?? this.aliases.map((a) => resolved[a]).find((v) => !!v);
|
|
29704
|
+
if (value) {
|
|
29705
|
+
process.env[this.envVar] = value;
|
|
29706
|
+
this.cachedKey = value;
|
|
29707
|
+
return value;
|
|
29708
|
+
}
|
|
29709
|
+
return "";
|
|
29710
|
+
}
|
|
29711
|
+
this.cachedKey = "";
|
|
29712
|
+
return "";
|
|
29713
|
+
})();
|
|
29714
|
+
try {
|
|
29715
|
+
return await this.resolving;
|
|
29716
|
+
} finally {
|
|
29717
|
+
this.resolving = undefined;
|
|
29718
|
+
}
|
|
29719
|
+
}
|
|
29720
|
+
async isAvailable(opts) {
|
|
29721
|
+
if (this.publicKeyFallback)
|
|
29722
|
+
return true;
|
|
29723
|
+
if (this.resolveFromEnvConfig())
|
|
29724
|
+
return true;
|
|
29725
|
+
if (this.hasOauthFallbackFile())
|
|
29726
|
+
return true;
|
|
29727
|
+
const key = await this.resolveKey(opts);
|
|
29728
|
+
return !!key;
|
|
29729
|
+
}
|
|
29730
|
+
invalidate() {
|
|
29731
|
+
this.cachedKey = undefined;
|
|
29732
|
+
this.resolving = undefined;
|
|
29733
|
+
}
|
|
29734
|
+
async getRequestAuth(ctx) {
|
|
29735
|
+
const key = await this.resolveKey({ allowOpPrompt: ctx.allowOpPrompt }) || this.publicKeyFallback || "";
|
|
29736
|
+
let headers;
|
|
29737
|
+
if (this.authScheme === "x-api-key") {
|
|
29738
|
+
headers = { "x-api-key": key, ...this.staticHeaders };
|
|
29739
|
+
} else if (key) {
|
|
29740
|
+
headers = { Authorization: `Bearer ${key}`, ...this.staticHeaders };
|
|
29741
|
+
} else {
|
|
29742
|
+
headers = { ...this.staticHeaders };
|
|
29743
|
+
}
|
|
29744
|
+
return { headers };
|
|
29745
|
+
}
|
|
29746
|
+
}
|
|
29747
|
+
var UNEXPANDED_PLACEHOLDER;
|
|
29748
|
+
var init_api_key_credential = __esm(() => {
|
|
29749
|
+
init_profile_config();
|
|
29750
|
+
init_op_source();
|
|
29751
|
+
UNEXPANDED_PLACEHOLDER = /^\$\{[^}]*\}$/;
|
|
29752
|
+
});
|
|
29753
|
+
|
|
29754
|
+
// src/auth/codex-oauth.ts
|
|
28817
29755
|
import { exec as exec2 } from "child_process";
|
|
28818
29756
|
import { createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
|
|
28819
|
-
import { closeSync as closeSync3, existsSync as
|
|
29757
|
+
import { closeSync as closeSync3, existsSync as existsSync9, openSync as openSync3, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeSync as writeSync3 } from "fs";
|
|
28820
29758
|
import { createServer as createServer2 } from "http";
|
|
28821
|
-
import { homedir as
|
|
28822
|
-
import { join as
|
|
29759
|
+
import { homedir as homedir11 } from "os";
|
|
29760
|
+
import { join as join11 } from "path";
|
|
28823
29761
|
import { promisify as promisify2 } from "util";
|
|
28824
29762
|
|
|
28825
|
-
class
|
|
29763
|
+
class CodexOAuth {
|
|
28826
29764
|
static instance = null;
|
|
28827
29765
|
credentials = null;
|
|
28828
29766
|
refreshPromise = null;
|
|
28829
29767
|
tokenRefreshMargin = 5 * 60 * 1000;
|
|
28830
29768
|
oauthState = null;
|
|
28831
29769
|
static getInstance() {
|
|
28832
|
-
if (!
|
|
28833
|
-
|
|
29770
|
+
if (!CodexOAuth.instance) {
|
|
29771
|
+
CodexOAuth.instance = new CodexOAuth;
|
|
28834
29772
|
}
|
|
28835
|
-
return
|
|
29773
|
+
return CodexOAuth.instance;
|
|
28836
29774
|
}
|
|
28837
29775
|
constructor() {
|
|
28838
29776
|
this.credentials = this.loadCredentials();
|
|
@@ -28845,56 +29783,61 @@ class GeminiOAuth {
|
|
|
28845
29783
|
return this.credentials !== null && !!this.credentials.refresh_token;
|
|
28846
29784
|
}
|
|
28847
29785
|
getCredentialsPath() {
|
|
28848
|
-
const claudishDir =
|
|
28849
|
-
return
|
|
29786
|
+
const claudishDir = join11(homedir11(), ".claudish");
|
|
29787
|
+
return join11(claudishDir, "codex-oauth.json");
|
|
28850
29788
|
}
|
|
28851
29789
|
async login() {
|
|
28852
|
-
log("[
|
|
29790
|
+
log("[CodexOAuth] Starting OAuth login flow");
|
|
28853
29791
|
const codeVerifier = this.generateCodeVerifier();
|
|
28854
29792
|
const codeChallenge = await this.generateCodeChallenge(codeVerifier);
|
|
28855
29793
|
this.oauthState = randomBytes2(32).toString("base64url");
|
|
28856
29794
|
const { authCode, redirectUri } = await this.startCallbackServer(codeChallenge, this.oauthState);
|
|
28857
29795
|
const tokens = await this.exchangeCodeForTokens(authCode, codeVerifier, redirectUri);
|
|
28858
|
-
const
|
|
29796
|
+
const accountId = tokens.id_token ? this.extractAccountId(tokens.id_token) : undefined;
|
|
29797
|
+
const credentials2 = {
|
|
28859
29798
|
access_token: tokens.access_token,
|
|
28860
29799
|
refresh_token: tokens.refresh_token,
|
|
28861
|
-
expires_at: Date.now() + tokens.expires_in * 1000
|
|
29800
|
+
expires_at: Date.now() + tokens.expires_in * 1000,
|
|
29801
|
+
account_id: accountId
|
|
28862
29802
|
};
|
|
28863
|
-
this.saveCredentials(
|
|
28864
|
-
this.credentials =
|
|
29803
|
+
this.saveCredentials(credentials2);
|
|
29804
|
+
this.credentials = credentials2;
|
|
28865
29805
|
this.oauthState = null;
|
|
28866
|
-
log("[
|
|
29806
|
+
log("[CodexOAuth] Login successful");
|
|
29807
|
+
if (accountId) {
|
|
29808
|
+
log(`[CodexOAuth] Account ID: ${accountId}`);
|
|
29809
|
+
}
|
|
28867
29810
|
}
|
|
28868
29811
|
async logout() {
|
|
28869
29812
|
const credPath = this.getCredentialsPath();
|
|
28870
|
-
if (
|
|
29813
|
+
if (existsSync9(credPath)) {
|
|
28871
29814
|
unlinkSync3(credPath);
|
|
28872
|
-
log("[
|
|
29815
|
+
log("[CodexOAuth] Credentials deleted");
|
|
28873
29816
|
}
|
|
28874
29817
|
this.credentials = null;
|
|
28875
29818
|
}
|
|
28876
29819
|
async getAccessToken() {
|
|
28877
29820
|
if (this.refreshPromise) {
|
|
28878
|
-
log("[
|
|
29821
|
+
log("[CodexOAuth] Waiting for in-progress refresh");
|
|
28879
29822
|
return this.refreshPromise;
|
|
28880
29823
|
}
|
|
28881
29824
|
if (!this.credentials) {
|
|
28882
|
-
throw new Error("No
|
|
29825
|
+
throw new Error("No OpenAI Codex OAuth credentials found. Please run `claudish login codex` first.");
|
|
28883
29826
|
}
|
|
28884
29827
|
if (this.isTokenValid()) {
|
|
28885
29828
|
return this.credentials.access_token;
|
|
28886
29829
|
}
|
|
28887
|
-
this.refreshPromise = this.doRefreshToken()
|
|
28888
|
-
try {
|
|
28889
|
-
const token = await this.refreshPromise;
|
|
28890
|
-
return token;
|
|
28891
|
-
} finally {
|
|
29830
|
+
this.refreshPromise = this.doRefreshToken().finally(() => {
|
|
28892
29831
|
this.refreshPromise = null;
|
|
28893
|
-
}
|
|
29832
|
+
});
|
|
29833
|
+
return this.refreshPromise;
|
|
29834
|
+
}
|
|
29835
|
+
getAccountId() {
|
|
29836
|
+
return this.credentials?.account_id;
|
|
28894
29837
|
}
|
|
28895
29838
|
async refreshToken() {
|
|
28896
29839
|
if (!this.credentials) {
|
|
28897
|
-
throw new Error("No
|
|
29840
|
+
throw new Error("No OpenAI Codex OAuth credentials found. Please run `claudish login codex` first.");
|
|
28898
29841
|
}
|
|
28899
29842
|
await this.doRefreshToken();
|
|
28900
29843
|
}
|
|
@@ -28905,20 +29848,19 @@ class GeminiOAuth {
|
|
|
28905
29848
|
}
|
|
28906
29849
|
async doRefreshToken() {
|
|
28907
29850
|
if (!this.credentials) {
|
|
28908
|
-
throw new Error("No
|
|
29851
|
+
throw new Error("No OpenAI Codex OAuth credentials found. Please run `claudish login codex` first.");
|
|
28909
29852
|
}
|
|
28910
|
-
log("[
|
|
29853
|
+
log("[CodexOAuth] Refreshing access token");
|
|
28911
29854
|
try {
|
|
28912
29855
|
const response = await fetch(OAUTH_CONFIG2.tokenUrl, {
|
|
28913
29856
|
method: "POST",
|
|
28914
29857
|
headers: {
|
|
28915
|
-
"Content-Type": "application/
|
|
29858
|
+
"Content-Type": "application/json"
|
|
28916
29859
|
},
|
|
28917
|
-
body:
|
|
29860
|
+
body: JSON.stringify({
|
|
28918
29861
|
grant_type: "refresh_token",
|
|
28919
29862
|
refresh_token: this.credentials.refresh_token,
|
|
28920
|
-
client_id: OAUTH_CONFIG2.clientId
|
|
28921
|
-
client_secret: OAUTH_CONFIG2.clientSecret
|
|
29863
|
+
client_id: OAUTH_CONFIG2.clientId
|
|
28922
29864
|
})
|
|
28923
29865
|
});
|
|
28924
29866
|
if (!response.ok) {
|
|
@@ -28926,56 +29868,58 @@ class GeminiOAuth {
|
|
|
28926
29868
|
throw new Error(`Token refresh failed: ${response.status} - ${errorText}`);
|
|
28927
29869
|
}
|
|
28928
29870
|
const tokens = await response.json();
|
|
29871
|
+
const accountId = tokens.id_token ? this.extractAccountId(tokens.id_token) : this.credentials.account_id;
|
|
28929
29872
|
const updatedCredentials = {
|
|
28930
29873
|
access_token: tokens.access_token,
|
|
28931
29874
|
refresh_token: tokens.refresh_token || this.credentials.refresh_token,
|
|
28932
|
-
expires_at: Date.now() + tokens.expires_in * 1000
|
|
29875
|
+
expires_at: Date.now() + tokens.expires_in * 1000,
|
|
29876
|
+
account_id: accountId
|
|
28933
29877
|
};
|
|
28934
29878
|
this.saveCredentials(updatedCredentials);
|
|
28935
29879
|
this.credentials = updatedCredentials;
|
|
28936
|
-
log(`[
|
|
29880
|
+
log(`[CodexOAuth] Token refreshed, valid until ${new Date(updatedCredentials.expires_at).toISOString()}`);
|
|
28937
29881
|
return updatedCredentials.access_token;
|
|
28938
29882
|
} catch (e) {
|
|
28939
|
-
log(`[
|
|
28940
|
-
throw new Error(`OAuth credentials invalid. Please run \`claudish login
|
|
29883
|
+
log(`[CodexOAuth] Refresh failed: ${e.message}`);
|
|
29884
|
+
throw new Error(`OAuth credentials invalid. Please run \`claudish login codex\` again.
|
|
28941
29885
|
|
|
28942
29886
|
Details: ${e.message}`);
|
|
28943
29887
|
}
|
|
28944
29888
|
}
|
|
28945
29889
|
loadCredentials() {
|
|
28946
29890
|
const credPath = this.getCredentialsPath();
|
|
28947
|
-
if (!
|
|
29891
|
+
if (!existsSync9(credPath)) {
|
|
28948
29892
|
return null;
|
|
28949
29893
|
}
|
|
28950
29894
|
try {
|
|
28951
29895
|
const data = readFileSync7(credPath, "utf-8");
|
|
28952
|
-
const
|
|
28953
|
-
if (!
|
|
28954
|
-
log("[
|
|
29896
|
+
const credentials2 = JSON.parse(data);
|
|
29897
|
+
if (!credentials2.access_token || !credentials2.refresh_token || !credentials2.expires_at) {
|
|
29898
|
+
log("[CodexOAuth] Invalid credentials file structure");
|
|
28955
29899
|
return null;
|
|
28956
29900
|
}
|
|
28957
|
-
log("[
|
|
28958
|
-
return
|
|
29901
|
+
log("[CodexOAuth] Loaded credentials from file");
|
|
29902
|
+
return credentials2;
|
|
28959
29903
|
} catch (e) {
|
|
28960
|
-
log(`[
|
|
29904
|
+
log(`[CodexOAuth] Failed to load credentials: ${e.message}`);
|
|
28961
29905
|
return null;
|
|
28962
29906
|
}
|
|
28963
29907
|
}
|
|
28964
|
-
saveCredentials(
|
|
29908
|
+
saveCredentials(credentials2) {
|
|
28965
29909
|
const credPath = this.getCredentialsPath();
|
|
28966
|
-
const claudishDir =
|
|
28967
|
-
if (!
|
|
29910
|
+
const claudishDir = join11(homedir11(), ".claudish");
|
|
29911
|
+
if (!existsSync9(claudishDir)) {
|
|
28968
29912
|
const { mkdirSync: mkdirSync6 } = __require("fs");
|
|
28969
29913
|
mkdirSync6(claudishDir, { recursive: true });
|
|
28970
29914
|
}
|
|
28971
29915
|
const fd = openSync3(credPath, "w", 384);
|
|
28972
29916
|
try {
|
|
28973
|
-
const data = JSON.stringify(
|
|
29917
|
+
const data = JSON.stringify(credentials2, null, 2);
|
|
28974
29918
|
writeSync3(fd, data, 0, "utf-8");
|
|
28975
29919
|
} finally {
|
|
28976
29920
|
closeSync3(fd);
|
|
28977
29921
|
}
|
|
28978
|
-
log(`[
|
|
29922
|
+
log(`[CodexOAuth] Credentials saved to ${credPath}`);
|
|
28979
29923
|
}
|
|
28980
29924
|
generateCodeVerifier() {
|
|
28981
29925
|
return randomBytes2(64).toString("base64url");
|
|
@@ -28984,26 +29928,46 @@ Details: ${e.message}`);
|
|
|
28984
29928
|
const hash2 = createHash3("sha256").update(verifier).digest("base64url");
|
|
28985
29929
|
return hash2;
|
|
28986
29930
|
}
|
|
29931
|
+
extractAccountId(idToken) {
|
|
29932
|
+
try {
|
|
29933
|
+
const parts = idToken.split(".");
|
|
29934
|
+
if (parts.length !== 3)
|
|
29935
|
+
return;
|
|
29936
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
|
|
29937
|
+
const authClaim = payload["https://api.openai.com/auth"];
|
|
29938
|
+
const accountId = authClaim?.chatgpt_account_id || payload.chatgpt_account_id || authClaim?.user_id;
|
|
29939
|
+
if (accountId) {
|
|
29940
|
+
log(`[CodexOAuth] Extracted account ID from id_token: ${accountId}`);
|
|
29941
|
+
return accountId;
|
|
29942
|
+
}
|
|
29943
|
+
return;
|
|
29944
|
+
} catch (e) {
|
|
29945
|
+
log(`[CodexOAuth] Failed to extract account ID from id_token: ${e.message}`);
|
|
29946
|
+
return;
|
|
29947
|
+
}
|
|
29948
|
+
}
|
|
28987
29949
|
buildAuthUrl(codeChallenge, state, redirectUri) {
|
|
28988
|
-
const
|
|
28989
|
-
|
|
28990
|
-
|
|
28991
|
-
|
|
28992
|
-
|
|
28993
|
-
|
|
28994
|
-
|
|
28995
|
-
|
|
28996
|
-
|
|
28997
|
-
|
|
28998
|
-
|
|
28999
|
-
|
|
29950
|
+
const scope = OAUTH_CONFIG2.scopes.join("+");
|
|
29951
|
+
const params = [
|
|
29952
|
+
"response_type=code",
|
|
29953
|
+
`client_id=${encodeURIComponent(OAUTH_CONFIG2.clientId)}`,
|
|
29954
|
+
`redirect_uri=${encodeURIComponent(redirectUri)}`,
|
|
29955
|
+
`scope=${scope}`,
|
|
29956
|
+
`code_challenge=${encodeURIComponent(codeChallenge)}`,
|
|
29957
|
+
"code_challenge_method=S256",
|
|
29958
|
+
"id_token_add_organizations=true",
|
|
29959
|
+
"codex_cli_simplified_flow=true",
|
|
29960
|
+
`state=${encodeURIComponent(state)}`,
|
|
29961
|
+
"originator=opencode"
|
|
29962
|
+
].join("&");
|
|
29963
|
+
return `${OAUTH_CONFIG2.authUrl}?${params}`;
|
|
29000
29964
|
}
|
|
29001
29965
|
async startCallbackServer(codeChallenge, state) {
|
|
29002
29966
|
return new Promise((resolve, reject) => {
|
|
29003
29967
|
let redirectUri = "";
|
|
29004
29968
|
const server = createServer2((req, res) => {
|
|
29005
|
-
const url2 = new URL(req.url, redirectUri.replace("/callback", ""));
|
|
29006
|
-
if (url2.pathname === "/callback") {
|
|
29969
|
+
const url2 = new URL(req.url, redirectUri.replace("/auth/callback", ""));
|
|
29970
|
+
if (url2.pathname === "/auth/callback") {
|
|
29007
29971
|
const code = url2.searchParams.get("code");
|
|
29008
29972
|
const callbackState = url2.searchParams.get("state");
|
|
29009
29973
|
const error46 = url2.searchParams.get("error");
|
|
@@ -29068,15 +30032,15 @@ Details: ${e.message}`);
|
|
|
29068
30032
|
res.end("Not found");
|
|
29069
30033
|
}
|
|
29070
30034
|
});
|
|
29071
|
-
server.listen(
|
|
30035
|
+
server.listen(1455, () => {
|
|
29072
30036
|
const address = server.address();
|
|
29073
30037
|
if (!address || typeof address === "string") {
|
|
29074
30038
|
reject(new Error("Failed to get server port"));
|
|
29075
30039
|
return;
|
|
29076
30040
|
}
|
|
29077
30041
|
const port = address.port;
|
|
29078
|
-
redirectUri = `http://localhost:${port}/callback`;
|
|
29079
|
-
log(`[
|
|
30042
|
+
redirectUri = `http://localhost:${port}/auth/callback`;
|
|
30043
|
+
log(`[CodexOAuth] Callback server started on http://localhost:${port}`);
|
|
29080
30044
|
const authUrl = this.buildAuthUrl(codeChallenge, state, redirectUri);
|
|
29081
30045
|
this.openBrowser(authUrl);
|
|
29082
30046
|
});
|
|
@@ -29090,7 +30054,7 @@ Details: ${e.message}`);
|
|
|
29090
30054
|
});
|
|
29091
30055
|
}
|
|
29092
30056
|
async exchangeCodeForTokens(code, verifier, redirectUri) {
|
|
29093
|
-
log("[
|
|
30057
|
+
log("[CodexOAuth] Exchanging auth code for tokens");
|
|
29094
30058
|
try {
|
|
29095
30059
|
const response = await fetch(OAUTH_CONFIG2.tokenUrl, {
|
|
29096
30060
|
method: "POST",
|
|
@@ -29102,7 +30066,6 @@ Details: ${e.message}`);
|
|
|
29102
30066
|
code,
|
|
29103
30067
|
redirect_uri: redirectUri,
|
|
29104
30068
|
client_id: OAUTH_CONFIG2.clientId,
|
|
29105
|
-
client_secret: OAUTH_CONFIG2.clientSecret,
|
|
29106
30069
|
code_verifier: verifier
|
|
29107
30070
|
})
|
|
29108
30071
|
});
|
|
@@ -29116,7 +30079,7 @@ Details: ${e.message}`);
|
|
|
29116
30079
|
}
|
|
29117
30080
|
return tokens;
|
|
29118
30081
|
} catch (e) {
|
|
29119
|
-
throw new Error(`Failed to authenticate with
|
|
30082
|
+
throw new Error(`Failed to authenticate with OpenAI OAuth: ${e.message}`);
|
|
29120
30083
|
}
|
|
29121
30084
|
}
|
|
29122
30085
|
async openBrowser(url2) {
|
|
@@ -29130,7 +30093,7 @@ Details: ${e.message}`);
|
|
|
29130
30093
|
await execAsync2(`xdg-open "${url2}"`);
|
|
29131
30094
|
}
|
|
29132
30095
|
console.log(`
|
|
29133
|
-
Opening browser for authentication...`);
|
|
30096
|
+
Opening browser for OpenAI authentication...`);
|
|
29134
30097
|
console.log(`If the browser doesn't open, visit this URL:
|
|
29135
30098
|
${url2}
|
|
29136
30099
|
`);
|
|
@@ -29142,197 +30105,123 @@ Please open this URL in your browser to authenticate:`);
|
|
|
29142
30105
|
}
|
|
29143
30106
|
}
|
|
29144
30107
|
}
|
|
29145
|
-
function
|
|
29146
|
-
|
|
29147
|
-
resetGeminiUserCache();
|
|
29148
|
-
}
|
|
29149
|
-
async function getValidAccessToken() {
|
|
29150
|
-
const oauth = GeminiOAuth.getInstance();
|
|
29151
|
-
return oauth.getAccessToken();
|
|
29152
|
-
}
|
|
29153
|
-
function resetGeminiUserCache() {
|
|
29154
|
-
cachedProjectId = null;
|
|
29155
|
-
cachedTierId = null;
|
|
29156
|
-
cachedTierName = null;
|
|
29157
|
-
}
|
|
29158
|
-
function getGeminiTierDisplayName() {
|
|
29159
|
-
if (!cachedTierId)
|
|
29160
|
-
return "Gemini Free";
|
|
29161
|
-
return TIER_SHORT_NAMES[cachedTierId] || cachedTierId.replace(/-tier$/, "");
|
|
29162
|
-
}
|
|
29163
|
-
function getGeminiTierFullName() {
|
|
29164
|
-
if (cachedTierName)
|
|
29165
|
-
return cachedTierName;
|
|
29166
|
-
return getGeminiTierDisplayName();
|
|
30108
|
+
function getCodexOAuth() {
|
|
30109
|
+
return CodexOAuth.getInstance();
|
|
29167
30110
|
}
|
|
29168
|
-
|
|
29169
|
-
|
|
29170
|
-
|
|
29171
|
-
|
|
30111
|
+
var execAsync2, OAUTH_CONFIG2;
|
|
30112
|
+
var init_codex_oauth = __esm(() => {
|
|
30113
|
+
init_logger();
|
|
30114
|
+
execAsync2 = promisify2(exec2);
|
|
30115
|
+
OAUTH_CONFIG2 = {
|
|
30116
|
+
clientId: "app_EMoamEEZ73f0CkXaXp7hrann",
|
|
30117
|
+
authUrl: "https://auth.openai.com/oauth/authorize",
|
|
30118
|
+
tokenUrl: "https://auth.openai.com/oauth/token",
|
|
30119
|
+
scopes: ["openid", "profile", "email", "offline_access"]
|
|
30120
|
+
};
|
|
30121
|
+
});
|
|
30122
|
+
|
|
30123
|
+
// src/auth/credentials/composite-credential.ts
|
|
30124
|
+
class CompositeCredentialProvider {
|
|
30125
|
+
catalogName;
|
|
30126
|
+
primary;
|
|
30127
|
+
fallback;
|
|
30128
|
+
opts;
|
|
30129
|
+
constructor(catalogName, primary, fallback, opts = {}) {
|
|
30130
|
+
this.catalogName = catalogName;
|
|
30131
|
+
this.primary = primary;
|
|
30132
|
+
this.fallback = fallback;
|
|
30133
|
+
this.opts = opts;
|
|
29172
30134
|
}
|
|
29173
|
-
|
|
29174
|
-
|
|
29175
|
-
const loadRes = await callLoadCodeAssist(accessToken, envProject);
|
|
29176
|
-
log(`[GeminiOAuth] loadCodeAssist response: ${JSON.stringify(loadRes)}`);
|
|
29177
|
-
const resolvedTier = loadRes.paidTier?.id || (typeof loadRes.currentTier === "object" ? loadRes.currentTier?.id : loadRes.currentTier) || null;
|
|
29178
|
-
if ((loadRes.currentTier || loadRes.paidTier) && loadRes.cloudaicompanionProject) {
|
|
29179
|
-
const projectId2 = envProject || loadRes.cloudaicompanionProject;
|
|
29180
|
-
if (projectId2) {
|
|
29181
|
-
cachedProjectId = projectId2;
|
|
29182
|
-
cachedTierId = resolvedTier || "free-tier";
|
|
29183
|
-
cachedTierName = loadRes.paidTier?.name || null;
|
|
29184
|
-
log(`[GeminiOAuth] User already set up, project: ${projectId2}, tier: ${cachedTierId}`);
|
|
29185
|
-
return { projectId: projectId2, tierId: cachedTierId };
|
|
29186
|
-
}
|
|
30135
|
+
async isAvailable(opts) {
|
|
30136
|
+
return await this.primary.isAvailable(opts) || await this.fallback.isAvailable(opts);
|
|
29187
30137
|
}
|
|
29188
|
-
|
|
29189
|
-
|
|
29190
|
-
|
|
29191
|
-
const MAX_POLL_ATTEMPTS = 30;
|
|
29192
|
-
log(`[GeminiOAuth] Onboarding user to ${tierId}...`);
|
|
29193
|
-
let lro = await callOnboardUser(accessToken, tierId, onboardProject);
|
|
29194
|
-
log(`[GeminiOAuth] Initial onboardUser response: done=${lro.done}`);
|
|
29195
|
-
let attempts = 0;
|
|
29196
|
-
while (!lro.done && attempts < MAX_POLL_ATTEMPTS) {
|
|
29197
|
-
attempts++;
|
|
29198
|
-
log(`[GeminiOAuth] Polling onboardUser (attempt ${attempts}/${MAX_POLL_ATTEMPTS})...`);
|
|
29199
|
-
await new Promise((r) => setTimeout(r, 2000));
|
|
29200
|
-
lro = await callOnboardUser(accessToken, tierId, onboardProject);
|
|
30138
|
+
invalidate() {
|
|
30139
|
+
this.primary.invalidate?.();
|
|
30140
|
+
this.fallback.invalidate?.();
|
|
29201
30141
|
}
|
|
29202
|
-
|
|
29203
|
-
|
|
30142
|
+
async getRequestAuth(ctx) {
|
|
30143
|
+
if (await this.primary.isAvailable({ allowOpPrompt: ctx.allowOpPrompt })) {
|
|
30144
|
+
try {
|
|
30145
|
+
return await this.primary.getRequestAuth(ctx);
|
|
30146
|
+
} catch (e) {
|
|
30147
|
+
const signal = this.opts.fallbackSignal;
|
|
30148
|
+
if (signal && String(e?.message) === signal) {
|
|
30149
|
+
return this.fallback.getRequestAuth(ctx);
|
|
30150
|
+
}
|
|
30151
|
+
throw e;
|
|
30152
|
+
}
|
|
30153
|
+
}
|
|
30154
|
+
return this.fallback.getRequestAuth(ctx);
|
|
29204
30155
|
}
|
|
29205
|
-
|
|
29206
|
-
|
|
30156
|
+
async login() {
|
|
30157
|
+
await this.primary.login?.();
|
|
29207
30158
|
}
|
|
29208
|
-
|
|
29209
|
-
|
|
29210
|
-
if (envProject) {
|
|
29211
|
-
cachedProjectId = envProject;
|
|
29212
|
-
cachedTierId = tierId;
|
|
29213
|
-
return { projectId: envProject, tierId };
|
|
29214
|
-
}
|
|
29215
|
-
throw new Error("Gemini onboarding completed but no project ID returned.");
|
|
30159
|
+
async logout() {
|
|
30160
|
+
await this.primary.logout?.();
|
|
29216
30161
|
}
|
|
29217
|
-
cachedProjectId = projectId;
|
|
29218
|
-
cachedTierId = tierId;
|
|
29219
|
-
log(`[GeminiOAuth] Onboarding complete, project: ${projectId}, tier: ${tierId}`);
|
|
29220
|
-
return { projectId, tierId };
|
|
29221
30162
|
}
|
|
29222
|
-
|
|
29223
|
-
|
|
29224
|
-
|
|
29225
|
-
|
|
29226
|
-
|
|
29227
|
-
|
|
30163
|
+
|
|
30164
|
+
// src/auth/credentials/codex-credential.ts
|
|
30165
|
+
function buildOAuthHeaders(token, accountId) {
|
|
30166
|
+
const headers = {
|
|
30167
|
+
Authorization: `Bearer ${token}`,
|
|
30168
|
+
"OpenAI-Beta": "responses=experimental",
|
|
30169
|
+
originator: "codex_cli_rs",
|
|
30170
|
+
accept: "text/event-stream"
|
|
29228
30171
|
};
|
|
29229
|
-
|
|
29230
|
-
|
|
29231
|
-
headers
|
|
29232
|
-
|
|
29233
|
-
"Content-Type": "application/json"
|
|
29234
|
-
},
|
|
29235
|
-
body: JSON.stringify({ metadata, cloudaicompanionProject: projectId })
|
|
29236
|
-
});
|
|
29237
|
-
if (!res.ok) {
|
|
29238
|
-
throw new Error(`loadCodeAssist failed: ${res.status} ${await res.text()}`);
|
|
30172
|
+
if (accountId) {
|
|
30173
|
+
headers["chatgpt-account-id"] = accountId;
|
|
30174
|
+
headers["x-conversation-id"] = "claudish-session";
|
|
30175
|
+
headers["x-session-id"] = "claudish-session";
|
|
29239
30176
|
}
|
|
29240
|
-
return
|
|
30177
|
+
return headers;
|
|
29241
30178
|
}
|
|
29242
|
-
|
|
29243
|
-
|
|
29244
|
-
|
|
29245
|
-
|
|
29246
|
-
|
|
29247
|
-
|
|
29248
|
-
};
|
|
29249
|
-
const res = await fetch(`${CODE_ASSIST_API_BASE}:onboardUser`, {
|
|
29250
|
-
method: "POST",
|
|
29251
|
-
headers: {
|
|
29252
|
-
Authorization: `Bearer ${accessToken}`,
|
|
29253
|
-
"Content-Type": "application/json"
|
|
29254
|
-
},
|
|
29255
|
-
body: JSON.stringify({
|
|
29256
|
-
tierId,
|
|
29257
|
-
metadata,
|
|
29258
|
-
cloudaicompanionProject: projectId
|
|
29259
|
-
})
|
|
29260
|
-
});
|
|
29261
|
-
if (!res.ok) {
|
|
29262
|
-
throw new Error(`onboardUser failed: ${res.status} ${await res.text()}`);
|
|
30179
|
+
|
|
30180
|
+
class CodexOAuthHalf {
|
|
30181
|
+
catalogName = "openai-codex";
|
|
30182
|
+
oauth = CodexOAuth.getInstance();
|
|
30183
|
+
async isAvailable() {
|
|
30184
|
+
return this.oauth.hasCredentials();
|
|
29263
30185
|
}
|
|
29264
|
-
|
|
29265
|
-
|
|
29266
|
-
|
|
29267
|
-
|
|
29268
|
-
|
|
29269
|
-
|
|
29270
|
-
|
|
29271
|
-
|
|
29272
|
-
|
|
29273
|
-
|
|
29274
|
-
}
|
|
29275
|
-
|
|
29276
|
-
|
|
29277
|
-
|
|
29278
|
-
|
|
29279
|
-
|
|
29280
|
-
|
|
29281
|
-
|
|
29282
|
-
} catch (err) {
|
|
29283
|
-
log(`[GeminiOAuth] retrieveUserQuota error: ${err}`);
|
|
29284
|
-
return null;
|
|
30186
|
+
async getRequestAuth(_ctx) {
|
|
30187
|
+
const token = await this.oauth.getAccessToken();
|
|
30188
|
+
const accountId = this.oauth.getAccountId();
|
|
30189
|
+
return {
|
|
30190
|
+
headers: buildOAuthHeaders(token, accountId),
|
|
30191
|
+
endpoint: CODEX_RESPONSES_ENDPOINT,
|
|
30192
|
+
transformPayload: (p) => ({
|
|
30193
|
+
...p,
|
|
30194
|
+
store: false,
|
|
30195
|
+
include: ["reasoning.encrypted_content"]
|
|
30196
|
+
})
|
|
30197
|
+
};
|
|
30198
|
+
}
|
|
30199
|
+
async login() {
|
|
30200
|
+
await this.oauth.login();
|
|
30201
|
+
}
|
|
30202
|
+
async logout() {
|
|
30203
|
+
await this.oauth.logout();
|
|
29285
30204
|
}
|
|
29286
30205
|
}
|
|
29287
|
-
|
|
29288
|
-
|
|
29289
|
-
"
|
|
29290
|
-
"
|
|
29291
|
-
|
|
29292
|
-
|
|
29293
|
-
|
|
29294
|
-
|
|
29295
|
-
|
|
29296
|
-
|
|
29297
|
-
const p = ["GOCSPX", "4uHgMPm", "1o7Sk", "geV6Cu5clXFsxl"];
|
|
29298
|
-
return `${p[0]}-${p[1]}-${p[2]}-${p[3]}`;
|
|
29299
|
-
}, OAUTH_CONFIG2, CODE_ASSIST_API_BASE = "https://cloudcode-pa.googleapis.com/v1internal", CODE_ASSIST_FALLBACK_CHAIN, cachedProjectId = null, cachedTierId = null, cachedTierName = null, TIER_SHORT_NAMES;
|
|
29300
|
-
var init_gemini_oauth = __esm(() => {
|
|
29301
|
-
init_logger();
|
|
29302
|
-
execAsync2 = promisify2(exec2);
|
|
29303
|
-
OAUTH_CONFIG2 = {
|
|
29304
|
-
clientId: process.env.GEMINI_CLIENT_ID || getDefaultClientId(),
|
|
29305
|
-
clientSecret: process.env.GEMINI_CLIENT_SECRET || getDefaultClientSecret(),
|
|
29306
|
-
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
29307
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
29308
|
-
scopes: [
|
|
29309
|
-
"https://www.googleapis.com/auth/cloud-platform",
|
|
29310
|
-
"https://www.googleapis.com/auth/userinfo.email",
|
|
29311
|
-
"https://www.googleapis.com/auth/userinfo.profile"
|
|
29312
|
-
]
|
|
29313
|
-
};
|
|
29314
|
-
CODE_ASSIST_FALLBACK_CHAIN = [
|
|
29315
|
-
"gemini-3.1-pro-preview",
|
|
29316
|
-
"gemini-3-pro-preview",
|
|
29317
|
-
"gemini-3-flash-preview",
|
|
29318
|
-
"gemini-2.5-pro",
|
|
29319
|
-
"gemini-2.5-flash"
|
|
29320
|
-
];
|
|
29321
|
-
TIER_SHORT_NAMES = {
|
|
29322
|
-
"free-tier": "GeminiCA Free",
|
|
29323
|
-
"standard-tier": "GeminiCA Std",
|
|
29324
|
-
"g1-pro-tier": "GeminiCA Pro",
|
|
29325
|
-
"legacy-tier": "GeminiCA Legacy"
|
|
29326
|
-
};
|
|
30206
|
+
function makeCodexCredential() {
|
|
30207
|
+
return new CompositeCredentialProvider("openai-codex", new CodexOAuthHalf, new ApiKeyCredentialProvider({
|
|
30208
|
+
catalogName: "openai-codex",
|
|
30209
|
+
envVar: "OPENAI_CODEX_API_KEY"
|
|
30210
|
+
}));
|
|
30211
|
+
}
|
|
30212
|
+
var CODEX_RESPONSES_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
|
|
30213
|
+
var init_codex_credential = __esm(() => {
|
|
30214
|
+
init_codex_oauth();
|
|
30215
|
+
init_api_key_credential();
|
|
29327
30216
|
});
|
|
29328
30217
|
|
|
29329
30218
|
// src/auth/oauth-registry.ts
|
|
29330
|
-
import { existsSync as
|
|
29331
|
-
import { homedir as
|
|
29332
|
-
import { join as
|
|
30219
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
|
|
30220
|
+
import { homedir as homedir12 } from "os";
|
|
30221
|
+
import { join as join12 } from "path";
|
|
29333
30222
|
function hasValidOAuthCredentials(descriptor) {
|
|
29334
|
-
const credPath =
|
|
29335
|
-
if (!
|
|
30223
|
+
const credPath = join12(homedir12(), ".claudish", descriptor.credentialFile);
|
|
30224
|
+
if (!existsSync10(credPath))
|
|
29336
30225
|
return false;
|
|
29337
30226
|
if (descriptor.validationMode === "file-exists") {
|
|
29338
30227
|
return true;
|
|
@@ -29395,13 +30284,8 @@ var init_oauth_registry = __esm(() => {
|
|
|
29395
30284
|
});
|
|
29396
30285
|
|
|
29397
30286
|
// src/auth/credentials/gemini-credential.ts
|
|
29398
|
-
import { randomUUID } from "crypto";
|
|
29399
|
-
function
|
|
29400
|
-
const version2 = "0.5.6";
|
|
29401
|
-
const modelSegment = model || "gemini-code-assist";
|
|
29402
|
-
return `GeminiCLI/${version2}/${modelSegment} (${process.platform}; ${process.arch})`;
|
|
29403
|
-
}
|
|
29404
|
-
function createActivityRequestId() {
|
|
30287
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
30288
|
+
function createActivityRequestId3() {
|
|
29405
30289
|
return Math.random().toString(36).substring(7);
|
|
29406
30290
|
}
|
|
29407
30291
|
|
|
@@ -29416,14 +30300,14 @@ class GeminiCodeAssistCredentialProvider {
|
|
|
29416
30300
|
return {
|
|
29417
30301
|
headers: {
|
|
29418
30302
|
Authorization: `Bearer ${token}`,
|
|
29419
|
-
"User-Agent":
|
|
29420
|
-
"x-activity-request-id":
|
|
30303
|
+
"User-Agent": buildCodeAssistUserAgent(ctx.model),
|
|
30304
|
+
"x-activity-request-id": createActivityRequestId3()
|
|
29421
30305
|
},
|
|
29422
30306
|
transformPayload: (inner) => {
|
|
29423
30307
|
const env = {
|
|
29424
30308
|
model: ctx.model,
|
|
29425
30309
|
project: projectId,
|
|
29426
|
-
user_prompt_id:
|
|
30310
|
+
user_prompt_id: randomUUID3(),
|
|
29427
30311
|
request: inner
|
|
29428
30312
|
};
|
|
29429
30313
|
if (tierId && tierId !== "free-tier") {
|
|
@@ -29448,9 +30332,9 @@ var init_gemini_credential = __esm(() => {
|
|
|
29448
30332
|
// src/auth/kimi-oauth.ts
|
|
29449
30333
|
import { exec as exec3 } from "child_process";
|
|
29450
30334
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
29451
|
-
import { closeSync as closeSync4, existsSync as
|
|
29452
|
-
import { homedir as
|
|
29453
|
-
import { join as
|
|
30335
|
+
import { closeSync as closeSync4, existsSync as existsSync11, openSync as openSync4, readFileSync as readFileSync9, unlinkSync as unlinkSync4, writeSync as writeSync4 } from "fs";
|
|
30336
|
+
import { homedir as homedir13, hostname as hostname3, platform, release as release2 } from "os";
|
|
30337
|
+
import { join as join13 } from "path";
|
|
29454
30338
|
import { promisify as promisify3 } from "util";
|
|
29455
30339
|
|
|
29456
30340
|
class KimiOAuth {
|
|
@@ -29478,21 +30362,21 @@ class KimiOAuth {
|
|
|
29478
30362
|
return this.credentials !== null && !!this.credentials.refresh_token;
|
|
29479
30363
|
}
|
|
29480
30364
|
getCredentialsPath() {
|
|
29481
|
-
const claudishDir =
|
|
29482
|
-
return
|
|
30365
|
+
const claudishDir = join13(homedir13(), ".claudish");
|
|
30366
|
+
return join13(claudishDir, "kimi-oauth.json");
|
|
29483
30367
|
}
|
|
29484
30368
|
getDeviceIdPath() {
|
|
29485
|
-
const claudishDir =
|
|
29486
|
-
return
|
|
30369
|
+
const claudishDir = join13(homedir13(), ".claudish");
|
|
30370
|
+
return join13(claudishDir, "kimi-device-id");
|
|
29487
30371
|
}
|
|
29488
30372
|
loadOrCreateDeviceId() {
|
|
29489
30373
|
const deviceIdPath = this.getDeviceIdPath();
|
|
29490
|
-
const claudishDir =
|
|
29491
|
-
if (!
|
|
30374
|
+
const claudishDir = join13(homedir13(), ".claudish");
|
|
30375
|
+
if (!existsSync11(claudishDir)) {
|
|
29492
30376
|
const { mkdirSync: mkdirSync6 } = __require("fs");
|
|
29493
30377
|
mkdirSync6(claudishDir, { recursive: true });
|
|
29494
30378
|
}
|
|
29495
|
-
if (
|
|
30379
|
+
if (existsSync11(deviceIdPath)) {
|
|
29496
30380
|
try {
|
|
29497
30381
|
const deviceId2 = readFileSync9(deviceIdPath, "utf-8").trim();
|
|
29498
30382
|
if (deviceId2) {
|
|
@@ -29544,15 +30428,15 @@ Please authorize this device:`);
|
|
|
29544
30428
|
Waiting for authorization...`);
|
|
29545
30429
|
await this.openBrowser(deviceAuth.verification_uri_complete);
|
|
29546
30430
|
const tokens = await this.pollForToken(deviceAuth.device_code, deviceAuth.interval, deviceAuth.expires_in);
|
|
29547
|
-
const
|
|
30431
|
+
const credentials2 = {
|
|
29548
30432
|
access_token: tokens.access_token,
|
|
29549
30433
|
refresh_token: tokens.refresh_token,
|
|
29550
30434
|
expires_at: Date.now() + tokens.expires_in * 1000,
|
|
29551
30435
|
scope: tokens.scope,
|
|
29552
30436
|
token_type: tokens.token_type
|
|
29553
30437
|
};
|
|
29554
|
-
this.saveCredentials(
|
|
29555
|
-
this.credentials =
|
|
30438
|
+
this.saveCredentials(credentials2);
|
|
30439
|
+
this.credentials = credentials2;
|
|
29556
30440
|
log("[KimiOAuth] Login successful");
|
|
29557
30441
|
}
|
|
29558
30442
|
async requestDeviceAuthorization() {
|
|
@@ -29665,7 +30549,7 @@ Waiting for authorization...`);
|
|
|
29665
30549
|
}
|
|
29666
30550
|
async logout() {
|
|
29667
30551
|
const credPath = this.getCredentialsPath();
|
|
29668
|
-
if (
|
|
30552
|
+
if (existsSync11(credPath)) {
|
|
29669
30553
|
unlinkSync4(credPath);
|
|
29670
30554
|
log("[KimiOAuth] Credentials deleted");
|
|
29671
30555
|
}
|
|
@@ -29732,7 +30616,7 @@ Waiting for authorization...`);
|
|
|
29732
30616
|
} catch (e) {
|
|
29733
30617
|
log(`[KimiOAuth] Refresh failed: ${e.message}`);
|
|
29734
30618
|
const credPath = this.getCredentialsPath();
|
|
29735
|
-
if (
|
|
30619
|
+
if (existsSync11(credPath)) {
|
|
29736
30620
|
unlinkSync4(credPath);
|
|
29737
30621
|
}
|
|
29738
30622
|
this.credentials = null;
|
|
@@ -29749,33 +30633,33 @@ Details: ${e.message}`);
|
|
|
29749
30633
|
}
|
|
29750
30634
|
loadCredentials() {
|
|
29751
30635
|
const credPath = this.getCredentialsPath();
|
|
29752
|
-
if (!
|
|
30636
|
+
if (!existsSync11(credPath)) {
|
|
29753
30637
|
return null;
|
|
29754
30638
|
}
|
|
29755
30639
|
try {
|
|
29756
30640
|
const data = readFileSync9(credPath, "utf-8");
|
|
29757
|
-
const
|
|
29758
|
-
if (!
|
|
30641
|
+
const credentials2 = JSON.parse(data);
|
|
30642
|
+
if (!credentials2.access_token || !credentials2.refresh_token || !credentials2.expires_at || !credentials2.scope || !credentials2.token_type) {
|
|
29759
30643
|
log("[KimiOAuth] Invalid credentials file structure");
|
|
29760
30644
|
return null;
|
|
29761
30645
|
}
|
|
29762
30646
|
log("[KimiOAuth] Loaded credentials from file");
|
|
29763
|
-
return
|
|
30647
|
+
return credentials2;
|
|
29764
30648
|
} catch (e) {
|
|
29765
30649
|
log(`[KimiOAuth] Failed to load credentials: ${e.message}`);
|
|
29766
30650
|
return null;
|
|
29767
30651
|
}
|
|
29768
30652
|
}
|
|
29769
|
-
saveCredentials(
|
|
30653
|
+
saveCredentials(credentials2) {
|
|
29770
30654
|
const credPath = this.getCredentialsPath();
|
|
29771
|
-
const claudishDir =
|
|
29772
|
-
if (!
|
|
30655
|
+
const claudishDir = join13(homedir13(), ".claudish");
|
|
30656
|
+
if (!existsSync11(claudishDir)) {
|
|
29773
30657
|
const { mkdirSync: mkdirSync6 } = __require("fs");
|
|
29774
30658
|
mkdirSync6(claudishDir, { recursive: true });
|
|
29775
30659
|
}
|
|
29776
30660
|
const fd = openSync4(credPath, "w", 384);
|
|
29777
30661
|
try {
|
|
29778
|
-
const data = JSON.stringify(
|
|
30662
|
+
const data = JSON.stringify(credentials2, null, 2);
|
|
29779
30663
|
writeSync4(fd, data, 0, "utf-8");
|
|
29780
30664
|
} finally {
|
|
29781
30665
|
closeSync4(fd);
|
|
@@ -29943,9 +30827,9 @@ var init_native_anthropic_credential = __esm(() => {
|
|
|
29943
30827
|
|
|
29944
30828
|
// src/auth/vertex-auth.ts
|
|
29945
30829
|
import { exec as exec4 } from "child_process";
|
|
29946
|
-
import { existsSync as
|
|
29947
|
-
import { homedir as
|
|
29948
|
-
import { join as
|
|
30830
|
+
import { existsSync as existsSync12 } from "fs";
|
|
30831
|
+
import { homedir as homedir14 } from "os";
|
|
30832
|
+
import { join as join14 } from "path";
|
|
29949
30833
|
import { promisify as promisify4 } from "util";
|
|
29950
30834
|
|
|
29951
30835
|
class VertexAuthManager {
|
|
@@ -30000,8 +30884,8 @@ class VertexAuthManager {
|
|
|
30000
30884
|
}
|
|
30001
30885
|
async tryADC() {
|
|
30002
30886
|
try {
|
|
30003
|
-
const adcPath =
|
|
30004
|
-
if (!
|
|
30887
|
+
const adcPath = join14(homedir14(), ".config/gcloud/application_default_credentials.json");
|
|
30888
|
+
if (!existsSync12(adcPath)) {
|
|
30005
30889
|
log("[VertexAuth] ADC credentials file not found");
|
|
30006
30890
|
return null;
|
|
30007
30891
|
}
|
|
@@ -30025,7 +30909,7 @@ class VertexAuthManager {
|
|
|
30025
30909
|
if (!credPath) {
|
|
30026
30910
|
return null;
|
|
30027
30911
|
}
|
|
30028
|
-
if (!
|
|
30912
|
+
if (!existsSync12(credPath)) {
|
|
30029
30913
|
throw new Error(`Service account file not found: ${credPath}
|
|
30030
30914
|
|
|
30031
30915
|
Check GOOGLE_APPLICATION_CREDENTIALS path.`);
|
|
@@ -30064,8 +30948,8 @@ function validateVertexOAuthConfig() {
|
|
|
30064
30948
|
` + ` export VERTEX_PROJECT='your-gcp-project-id'
|
|
30065
30949
|
` + " export VERTEX_LOCATION='us-central1' # optional";
|
|
30066
30950
|
}
|
|
30067
|
-
const adcPath =
|
|
30068
|
-
const hasADC =
|
|
30951
|
+
const adcPath = join14(homedir14(), ".config/gcloud/application_default_credentials.json");
|
|
30952
|
+
const hasADC = existsSync12(adcPath);
|
|
30069
30953
|
const hasServiceAccount = !!process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
30070
30954
|
if (!hasADC && !hasServiceAccount) {
|
|
30071
30955
|
return `No Vertex AI credentials found.
|
|
@@ -30184,6 +31068,7 @@ class CredentialAuthority {
|
|
|
30184
31068
|
const authority = new CredentialAuthority;
|
|
30185
31069
|
authority.register(makeCodexCredential(), ["openai-codex"]);
|
|
30186
31070
|
authority.register(new GeminiCodeAssistCredentialProvider, ["gemini-codeassist"]);
|
|
31071
|
+
authority.register(new AntigravityCredentialProvider, ["antigravity"]);
|
|
30187
31072
|
authority.register(makeKimiCredential(), ["kimi"]);
|
|
30188
31073
|
authority.register(makeKimiCodingCredential(), ["kimi-coding"]);
|
|
30189
31074
|
authority.register(new VertexCredentialProvider, ["vertex"]);
|
|
@@ -30194,6 +31079,7 @@ class CredentialAuthority {
|
|
|
30194
31079
|
const alreadyRegistered = new Set([
|
|
30195
31080
|
"openai-codex",
|
|
30196
31081
|
"gemini-codeassist",
|
|
31082
|
+
"antigravity",
|
|
30197
31083
|
"kimi",
|
|
30198
31084
|
"kimi-coding",
|
|
30199
31085
|
"vertex",
|
|
@@ -30222,6 +31108,7 @@ class CredentialAuthority {
|
|
|
30222
31108
|
var LOCAL_PROVIDER_NAMES, RUNTIME_NAME_ALIASES, credentials;
|
|
30223
31109
|
var init_authority = __esm(() => {
|
|
30224
31110
|
init_provider_definitions();
|
|
31111
|
+
init_antigravity_credential();
|
|
30225
31112
|
init_api_key_credential();
|
|
30226
31113
|
init_codex_credential();
|
|
30227
31114
|
init_gemini_credential();
|
|
@@ -30237,6 +31124,13 @@ var init_authority = __esm(() => {
|
|
|
30237
31124
|
});
|
|
30238
31125
|
|
|
30239
31126
|
// src/providers/model-parser.ts
|
|
31127
|
+
function warnGoAliasDeprecatedOnce() {
|
|
31128
|
+
if (_goDeprecationWarned)
|
|
31129
|
+
return;
|
|
31130
|
+
_goDeprecationWarned = true;
|
|
31131
|
+
process.stderr.write(`[claudish] go@ is deprecated \u2014 use ag@<model> (Antigravity). Routing there.
|
|
31132
|
+
`);
|
|
31133
|
+
}
|
|
30240
31134
|
function parseModelSpec(modelSpec) {
|
|
30241
31135
|
const original = modelSpec;
|
|
30242
31136
|
if (modelSpec.startsWith("http://") || modelSpec.startsWith("https://")) {
|
|
@@ -30259,6 +31153,8 @@ function parseModelSpec(modelSpec) {
|
|
|
30259
31153
|
concurrency = Number.parseInt(concurrencyMatch[2], 10);
|
|
30260
31154
|
}
|
|
30261
31155
|
const provider = PROVIDER_SHORTCUTS[providerPart] || providerPart;
|
|
31156
|
+
if (providerPart === "go")
|
|
31157
|
+
warnGoAliasDeprecatedOnce();
|
|
30262
31158
|
return {
|
|
30263
31159
|
provider,
|
|
30264
31160
|
model: modelPart,
|
|
@@ -30272,6 +31168,8 @@ function parseModelSpec(modelSpec) {
|
|
|
30272
31168
|
for (const { prefix, provider, stripPrefix } of LEGACY_PREFIX_PATTERNS) {
|
|
30273
31169
|
if (lowerSpec.startsWith(prefix)) {
|
|
30274
31170
|
const model = stripPrefix ? modelSpec.slice(prefix.length) : modelSpec;
|
|
31171
|
+
if (prefix === "go/")
|
|
31172
|
+
warnGoAliasDeprecatedOnce();
|
|
30275
31173
|
let concurrency;
|
|
30276
31174
|
let modelName = model;
|
|
30277
31175
|
if (LOCAL_PROVIDERS.has(provider)) {
|
|
@@ -30332,7 +31230,7 @@ function getLegacySyntaxWarning(parsed) {
|
|
|
30332
31230
|
return `Deprecation warning: "${parsed.original}" uses legacy prefix syntax.
|
|
30333
31231
|
` + ` Consider using: ${newSyntax}`;
|
|
30334
31232
|
}
|
|
30335
|
-
var PROVIDER_SHORTCUTS, LOCAL_PROVIDERS, NATIVE_MODEL_PATTERNS, LEGACY_PREFIX_PATTERNS;
|
|
31233
|
+
var PROVIDER_SHORTCUTS, _goDeprecationWarned = false, LOCAL_PROVIDERS, NATIVE_MODEL_PATTERNS, LEGACY_PREFIX_PATTERNS;
|
|
30336
31234
|
var init_model_parser = __esm(() => {
|
|
30337
31235
|
init_provider_definitions();
|
|
30338
31236
|
PROVIDER_SHORTCUTS = getShortcuts();
|
|
@@ -30612,11 +31510,11 @@ var init_routing_hints = __esm(() => {
|
|
|
30612
31510
|
});
|
|
30613
31511
|
|
|
30614
31512
|
// src/providers/all-models-cache.ts
|
|
30615
|
-
import { existsSync as
|
|
30616
|
-
import { homedir as
|
|
30617
|
-
import { dirname as dirname5, join as
|
|
31513
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
|
|
31514
|
+
import { homedir as homedir15 } from "os";
|
|
31515
|
+
import { dirname as dirname5, join as join15 } from "path";
|
|
30618
31516
|
function readAllModelsCache(path = ALL_MODELS_CACHE_PATH) {
|
|
30619
|
-
if (!
|
|
31517
|
+
if (!existsSync13(path))
|
|
30620
31518
|
return null;
|
|
30621
31519
|
let raw;
|
|
30622
31520
|
try {
|
|
@@ -30650,7 +31548,7 @@ function writeAllModelsCache(data, path = ALL_MODELS_CACHE_PATH) {
|
|
|
30650
31548
|
}
|
|
30651
31549
|
var ALL_MODELS_CACHE_PATH;
|
|
30652
31550
|
var init_all_models_cache = __esm(() => {
|
|
30653
|
-
ALL_MODELS_CACHE_PATH =
|
|
31551
|
+
ALL_MODELS_CACHE_PATH = join15(homedir15(), ".claudish", "all-models.json");
|
|
30654
31552
|
});
|
|
30655
31553
|
|
|
30656
31554
|
// src/adapters/model-catalog.ts
|
|
@@ -31745,10 +32643,10 @@ var init_signal_watcher = __esm(() => {
|
|
|
31745
32643
|
|
|
31746
32644
|
// src/channel/session-manager.ts
|
|
31747
32645
|
import { spawn } from "child_process";
|
|
31748
|
-
import { randomUUID as
|
|
32646
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
31749
32647
|
import { createWriteStream, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
31750
|
-
import { homedir as
|
|
31751
|
-
import { join as
|
|
32648
|
+
import { homedir as homedir16 } from "os";
|
|
32649
|
+
import { join as join16 } from "path";
|
|
31752
32650
|
|
|
31753
32651
|
class SessionManager {
|
|
31754
32652
|
sessions = new Map;
|
|
@@ -31765,13 +32663,13 @@ class SessionManager {
|
|
|
31765
32663
|
if (this.activeSessions >= this.maxSessions) {
|
|
31766
32664
|
throw new Error(`Max sessions (${this.maxSessions}) reached`);
|
|
31767
32665
|
}
|
|
31768
|
-
const sessionId =
|
|
32666
|
+
const sessionId = randomUUID4().slice(0, 8);
|
|
31769
32667
|
const timeout = Math.min(opts.timeoutSeconds ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
|
|
31770
32668
|
const startedAt = new Date().toISOString();
|
|
31771
|
-
const sessionDir =
|
|
32669
|
+
const sessionDir = join16(homedir16(), ".claudish", "sessions", sessionId);
|
|
31772
32670
|
mkdirSync7(sessionDir, { recursive: true });
|
|
31773
32671
|
if (opts.prompt) {
|
|
31774
|
-
writeFileSync7(
|
|
32672
|
+
writeFileSync7(join16(sessionDir, "prompt.md"), opts.prompt, "utf-8");
|
|
31775
32673
|
}
|
|
31776
32674
|
const args = ["--model", opts.model, "-y", "--stdin", "--quiet", ...opts.claudishFlags ?? []];
|
|
31777
32675
|
const proc = spawn("claudish", args, {
|
|
@@ -31798,7 +32696,7 @@ class SessionManager {
|
|
|
31798
32696
|
});
|
|
31799
32697
|
}
|
|
31800
32698
|
});
|
|
31801
|
-
const outputLogStream = createWriteStream(
|
|
32699
|
+
const outputLogStream = createWriteStream(join16(sessionDir, "output.log"));
|
|
31802
32700
|
const entry = {
|
|
31803
32701
|
info: {
|
|
31804
32702
|
sessionId,
|
|
@@ -31845,9 +32743,9 @@ class SessionManager {
|
|
|
31845
32743
|
watcher.processExited(code);
|
|
31846
32744
|
outputLogStream.end();
|
|
31847
32745
|
if (entry.stderr) {
|
|
31848
|
-
writeFileSync7(
|
|
32746
|
+
writeFileSync7(join16(sessionDir, "stderr.log"), entry.stderr, "utf-8");
|
|
31849
32747
|
}
|
|
31850
|
-
writeFileSync7(
|
|
32748
|
+
writeFileSync7(join16(sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
|
|
31851
32749
|
this.cleanupSigint();
|
|
31852
32750
|
});
|
|
31853
32751
|
proc.on("error", (err) => {
|
|
@@ -32020,9 +32918,9 @@ var init_cache_ttl = __esm(() => {
|
|
|
32020
32918
|
});
|
|
32021
32919
|
|
|
32022
32920
|
// src/model-loader.ts
|
|
32023
|
-
import { existsSync as
|
|
32024
|
-
import { homedir as
|
|
32025
|
-
import { join as
|
|
32921
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
|
|
32922
|
+
import { homedir as homedir17 } from "os";
|
|
32923
|
+
import { join as join17 } from "path";
|
|
32026
32924
|
function groupRecommendedModels(entries) {
|
|
32027
32925
|
const byId = new Map;
|
|
32028
32926
|
for (const entry of entries) {
|
|
@@ -32118,7 +33016,7 @@ async function getRecommendedModels(opts = {}) {
|
|
|
32118
33016
|
if (!forceRefresh && _cachedRecommendedModels) {
|
|
32119
33017
|
return _cachedRecommendedModels;
|
|
32120
33018
|
}
|
|
32121
|
-
if (!forceRefresh &&
|
|
33019
|
+
if (!forceRefresh && existsSync14(RECOMMENDED_MODELS_CACHE_PATH)) {
|
|
32122
33020
|
try {
|
|
32123
33021
|
const cacheData = JSON.parse(readFileSync11(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
|
|
32124
33022
|
if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
|
|
@@ -32136,7 +33034,7 @@ async function getRecommendedModels(opts = {}) {
|
|
|
32136
33034
|
if (data.models && data.models.length > 0) {
|
|
32137
33035
|
_cachedRecommendedModels = data;
|
|
32138
33036
|
try {
|
|
32139
|
-
const cacheDir =
|
|
33037
|
+
const cacheDir = join17(homedir17(), ".claudish");
|
|
32140
33038
|
mkdirSync8(cacheDir, { recursive: true });
|
|
32141
33039
|
writeFileSync8(RECOMMENDED_MODELS_CACHE_PATH, JSON.stringify(data), "utf-8");
|
|
32142
33040
|
} catch {}
|
|
@@ -32149,7 +33047,7 @@ async function getRecommendedModels(opts = {}) {
|
|
|
32149
33047
|
function getRecommendedModelsSync() {
|
|
32150
33048
|
if (_cachedRecommendedModels)
|
|
32151
33049
|
return _cachedRecommendedModels;
|
|
32152
|
-
if (
|
|
33050
|
+
if (existsSync14(RECOMMENDED_MODELS_CACHE_PATH)) {
|
|
32153
33051
|
try {
|
|
32154
33052
|
const cacheData = JSON.parse(readFileSync11(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
|
|
32155
33053
|
if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
|
|
@@ -32275,7 +33173,7 @@ var _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels =
|
|
|
32275
33173
|
var init_model_loader = __esm(() => {
|
|
32276
33174
|
init_cache_ttl();
|
|
32277
33175
|
FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
|
|
32278
|
-
RECOMMENDED_MODELS_CACHE_PATH =
|
|
33176
|
+
RECOMMENDED_MODELS_CACHE_PATH = join17(homedir17(), ".claudish", "recommended-models-cache.json");
|
|
32279
33177
|
FIREBASE_SLUG_TO_PROVIDER_NAME = {
|
|
32280
33178
|
openai: "openai",
|
|
32281
33179
|
google: "google",
|
|
@@ -37176,8 +38074,8 @@ var init_harness = __esm(() => {
|
|
|
37176
38074
|
|
|
37177
38075
|
// src/behavior/journal.ts
|
|
37178
38076
|
import { appendFile as appendFile2, mkdir, stat } from "fs/promises";
|
|
37179
|
-
import { homedir as
|
|
37180
|
-
import { dirname as dirname6, join as
|
|
38077
|
+
import { homedir as homedir18 } from "os";
|
|
38078
|
+
import { dirname as dirname6, join as join18 } from "path";
|
|
37181
38079
|
function classifyPath(observed, expected) {
|
|
37182
38080
|
if (!observed)
|
|
37183
38081
|
return "not_applicable";
|
|
@@ -37189,7 +38087,7 @@ function classifyPath(observed, expected) {
|
|
|
37189
38087
|
return dirOf(observed) === dirOf(expected) ? "same_dir_wrong_name" : "outside_expected_dir";
|
|
37190
38088
|
}
|
|
37191
38089
|
function journalPath() {
|
|
37192
|
-
return
|
|
38090
|
+
return join18(homedir18(), ".claudish", "behavior-journal.jsonl");
|
|
37193
38091
|
}
|
|
37194
38092
|
async function recordDecision(entry, path = journalPath()) {
|
|
37195
38093
|
try {
|
|
@@ -37406,10 +38304,10 @@ __export(exports_live_log, {
|
|
|
37406
38304
|
recordLiveDivergence: () => recordLiveDivergence
|
|
37407
38305
|
});
|
|
37408
38306
|
import { appendFile as appendFile3 } from "fs/promises";
|
|
37409
|
-
import { homedir as
|
|
37410
|
-
import { join as
|
|
38307
|
+
import { homedir as homedir19 } from "os";
|
|
38308
|
+
import { join as join19 } from "path";
|
|
37411
38309
|
function defaultPath() {
|
|
37412
|
-
return
|
|
38310
|
+
return join19(homedir19(), ".claudish", "behavior-divergences.jsonl");
|
|
37413
38311
|
}
|
|
37414
38312
|
async function recordLiveDivergence(entry, path = defaultPath()) {
|
|
37415
38313
|
try {
|
|
@@ -37830,8 +38728,8 @@ var init_hooks = __esm(() => {
|
|
|
37830
38728
|
|
|
37831
38729
|
// src/behavior/observer/corpus.ts
|
|
37832
38730
|
import { appendFileSync as appendFileSync3, readFileSync as readFileSync12, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
37833
|
-
import { homedir as
|
|
37834
|
-
import { join as
|
|
38731
|
+
import { homedir as homedir20 } from "os";
|
|
38732
|
+
import { join as join20 } from "path";
|
|
37835
38733
|
function directoryOf2(filePath) {
|
|
37836
38734
|
const slash = filePath.lastIndexOf("/");
|
|
37837
38735
|
return slash > 0 ? filePath.slice(0, slash) : undefined;
|
|
@@ -37910,26 +38808,26 @@ function listTranscripts(root) {
|
|
|
37910
38808
|
return files;
|
|
37911
38809
|
}
|
|
37912
38810
|
for (const project of projects) {
|
|
37913
|
-
const dir =
|
|
38811
|
+
const dir = join20(root, project);
|
|
37914
38812
|
try {
|
|
37915
38813
|
if (!statSync2(dir).isDirectory())
|
|
37916
38814
|
continue;
|
|
37917
38815
|
for (const f of readdirSync2(dir)) {
|
|
37918
38816
|
if (f.endsWith(".jsonl"))
|
|
37919
|
-
files.push(
|
|
38817
|
+
files.push(join20(dir, f));
|
|
37920
38818
|
}
|
|
37921
38819
|
} catch {}
|
|
37922
38820
|
}
|
|
37923
38821
|
return files;
|
|
37924
38822
|
}
|
|
37925
38823
|
function buildCorpus(options = {}) {
|
|
37926
|
-
const root = options.projectsRoot ??
|
|
38824
|
+
const root = options.projectsRoot ?? join20(homedir20(), ".claude", "projects");
|
|
37927
38825
|
const files = listTranscripts(root);
|
|
37928
38826
|
const records = [];
|
|
37929
38827
|
for (const f of files)
|
|
37930
38828
|
records.push(...replayTranscript(f));
|
|
37931
38829
|
if (options.write && records.length > 0) {
|
|
37932
|
-
const outputPath = options.outputPath ??
|
|
38830
|
+
const outputPath = options.outputPath ?? join20(homedir20(), ".claudish", "behavior-divergences.jsonl");
|
|
37933
38831
|
try {
|
|
37934
38832
|
appendFileSync3(outputPath, `${records.map((r) => JSON.stringify(r)).join(`
|
|
37935
38833
|
`)}
|
|
@@ -38540,23 +39438,23 @@ var init_vision_proxy = __esm(() => {
|
|
|
38540
39438
|
|
|
38541
39439
|
// src/stats-buffer.ts
|
|
38542
39440
|
import {
|
|
38543
|
-
existsSync as
|
|
39441
|
+
existsSync as existsSync15,
|
|
38544
39442
|
mkdirSync as mkdirSync9,
|
|
38545
39443
|
readFileSync as readFileSync13,
|
|
38546
39444
|
renameSync,
|
|
38547
39445
|
unlinkSync as unlinkSync5,
|
|
38548
39446
|
writeFileSync as writeFileSync9
|
|
38549
39447
|
} from "fs";
|
|
38550
|
-
import { homedir as
|
|
38551
|
-
import { join as
|
|
39448
|
+
import { homedir as homedir21 } from "os";
|
|
39449
|
+
import { join as join21 } from "path";
|
|
38552
39450
|
function ensureDir() {
|
|
38553
|
-
if (!
|
|
39451
|
+
if (!existsSync15(CLAUDISH_DIR)) {
|
|
38554
39452
|
mkdirSync9(CLAUDISH_DIR, { recursive: true });
|
|
38555
39453
|
}
|
|
38556
39454
|
}
|
|
38557
39455
|
function readFromDisk() {
|
|
38558
39456
|
try {
|
|
38559
|
-
if (!
|
|
39457
|
+
if (!existsSync15(BUFFER_FILE))
|
|
38560
39458
|
return [];
|
|
38561
39459
|
const raw2 = readFileSync13(BUFFER_FILE, "utf-8");
|
|
38562
39460
|
const parsed = JSON.parse(raw2);
|
|
@@ -38583,7 +39481,7 @@ function writeToDisk(events) {
|
|
|
38583
39481
|
ensureDir();
|
|
38584
39482
|
const trimmed = enforceSizeCap([...events]);
|
|
38585
39483
|
const payload = { version: 1, events: trimmed };
|
|
38586
|
-
const tmpFile =
|
|
39484
|
+
const tmpFile = join21(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
|
|
38587
39485
|
writeFileSync9(tmpFile, JSON.stringify(payload, null, 2), "utf-8");
|
|
38588
39486
|
renameSync(tmpFile, BUFFER_FILE);
|
|
38589
39487
|
memoryCache = trimmed;
|
|
@@ -38627,7 +39525,7 @@ function clearBuffer() {
|
|
|
38627
39525
|
try {
|
|
38628
39526
|
memoryCache = [];
|
|
38629
39527
|
eventsSinceLastFlush = 0;
|
|
38630
|
-
if (
|
|
39528
|
+
if (existsSync15(BUFFER_FILE)) {
|
|
38631
39529
|
unlinkSync5(BUFFER_FILE);
|
|
38632
39530
|
}
|
|
38633
39531
|
} catch {}
|
|
@@ -38656,8 +39554,8 @@ function syncFlushOnExit() {
|
|
|
38656
39554
|
var BUFFER_MAX_BYTES, CLAUDISH_DIR, BUFFER_FILE, memoryCache = null, eventsSinceLastFlush = 0, flushScheduled = false;
|
|
38657
39555
|
var init_stats_buffer = __esm(() => {
|
|
38658
39556
|
BUFFER_MAX_BYTES = 64 * 1024;
|
|
38659
|
-
CLAUDISH_DIR =
|
|
38660
|
-
BUFFER_FILE =
|
|
39557
|
+
CLAUDISH_DIR = join21(homedir21(), ".claudish");
|
|
39558
|
+
BUFFER_FILE = join21(CLAUDISH_DIR, "stats-buffer.json");
|
|
38661
39559
|
process.on("exit", syncFlushOnExit);
|
|
38662
39560
|
process.on("SIGTERM", () => {
|
|
38663
39561
|
try {
|
|
@@ -40938,8 +41836,8 @@ var init_openai_responses_sse = __esm(() => {
|
|
|
40938
41836
|
|
|
40939
41837
|
// src/handlers/shared/token-tracker.ts
|
|
40940
41838
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
40941
|
-
import { homedir as
|
|
40942
|
-
import { dirname as dirname7, join as
|
|
41839
|
+
import { homedir as homedir22 } from "os";
|
|
41840
|
+
import { dirname as dirname7, join as join22 } from "path";
|
|
40943
41841
|
|
|
40944
41842
|
class TokenTracker {
|
|
40945
41843
|
port;
|
|
@@ -41083,7 +41981,7 @@ class TokenTracker {
|
|
|
41083
41981
|
data.quota_remaining = this.quotaRemaining;
|
|
41084
41982
|
}
|
|
41085
41983
|
const override = process.env.CLAUDISH_TOKEN_FILE;
|
|
41086
|
-
const outPath = override ||
|
|
41984
|
+
const outPath = override || join22(homedir22(), ".claudish", `tokens-${this.port}.json`);
|
|
41087
41985
|
mkdirSync10(dirname7(outPath), { recursive: true });
|
|
41088
41986
|
writeFileSync10(outPath, JSON.stringify(data), "utf-8");
|
|
41089
41987
|
} catch (e) {
|
|
@@ -41304,6 +42202,9 @@ class ComposedHandler {
|
|
|
41304
42202
|
isInteractive: this.isInteractive,
|
|
41305
42203
|
authType: "oauth"
|
|
41306
42204
|
});
|
|
42205
|
+
if (err?.terminal) {
|
|
42206
|
+
return c.json(wrapAnthropicError(400, err.message, "invalid_request_error"), 400);
|
|
42207
|
+
}
|
|
41307
42208
|
return c.json(wrapAnthropicError(401, err.message, "authentication_error"), 401);
|
|
41308
42209
|
}
|
|
41309
42210
|
}
|
|
@@ -41898,7 +42799,7 @@ function isRetryableError(status, errorBody) {
|
|
|
41898
42799
|
}
|
|
41899
42800
|
}
|
|
41900
42801
|
if (status === 400) {
|
|
41901
|
-
if (lower.includes("model not found") || lower.includes("not registered") || lower.includes("does not exist") || lower.includes("unknown model") || lower.includes("unsupported model") || lower.includes("no healthy deployment")) {
|
|
42802
|
+
if (lower.includes("model not found") || lower.includes("not registered") || lower.includes("does not exist") || lower.includes("unknown model") || lower.includes("unsupported model") || lower.includes("no healthy deployment") || lower.includes("requires a google cloud project") || lower.includes("unsupported_client")) {
|
|
41902
42803
|
return true;
|
|
41903
42804
|
}
|
|
41904
42805
|
}
|
|
@@ -43582,11 +44483,11 @@ var init_ollama_api_format = __esm(() => {
|
|
|
43582
44483
|
});
|
|
43583
44484
|
|
|
43584
44485
|
// src/providers/api-key-provenance.ts
|
|
43585
|
-
import { existsSync as
|
|
43586
|
-
import { homedir as
|
|
43587
|
-
import { join as
|
|
44486
|
+
import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
|
|
44487
|
+
import { homedir as homedir23 } from "os";
|
|
44488
|
+
import { join as join23, resolve as resolve2 } from "path";
|
|
43588
44489
|
function activeConfigPath() {
|
|
43589
|
-
return activeGlobalConfigFile(
|
|
44490
|
+
return activeGlobalConfigFile(join23(homedir23(), ".claudish", "config.json"));
|
|
43590
44491
|
}
|
|
43591
44492
|
function configLayerLabel() {
|
|
43592
44493
|
return getConfigFileOverride() ? activeConfigPath() : "~/.claudish/config.json";
|
|
@@ -43663,7 +44564,7 @@ function formatProvenanceLog(p) {
|
|
|
43663
44564
|
function readDotenvKey(envVars) {
|
|
43664
44565
|
try {
|
|
43665
44566
|
const dotenvPath = resolve2(".env");
|
|
43666
|
-
if (!
|
|
44567
|
+
if (!existsSync16(dotenvPath))
|
|
43667
44568
|
return null;
|
|
43668
44569
|
const parsed = import_dotenv.parse(readFileSync14(dotenvPath, "utf-8"));
|
|
43669
44570
|
for (const v of envVars) {
|
|
@@ -43678,7 +44579,7 @@ function readDotenvKey(envVars) {
|
|
|
43678
44579
|
function readConfigKey(envVar) {
|
|
43679
44580
|
try {
|
|
43680
44581
|
const configPath = activeConfigPath();
|
|
43681
|
-
if (!
|
|
44582
|
+
if (!existsSync16(configPath))
|
|
43682
44583
|
return null;
|
|
43683
44584
|
const cfg = JSON.parse(readFileSync14(configPath, "utf-8"));
|
|
43684
44585
|
return cfg.apiKeys?.[envVar] || null;
|
|
@@ -43692,142 +44593,6 @@ var init_api_key_provenance = __esm(() => {
|
|
|
43692
44593
|
import_dotenv = __toESM(require_main(), 1);
|
|
43693
44594
|
});
|
|
43694
44595
|
|
|
43695
|
-
// src/handlers/shared/gemini-queue.ts
|
|
43696
|
-
class GeminiRequestQueue {
|
|
43697
|
-
static instance = null;
|
|
43698
|
-
queue = [];
|
|
43699
|
-
processing = false;
|
|
43700
|
-
minDelayMs = 1000;
|
|
43701
|
-
lastRequestTime = 0;
|
|
43702
|
-
consecutiveErrors = 0;
|
|
43703
|
-
totalProcessed = 0;
|
|
43704
|
-
totalErrors = 0;
|
|
43705
|
-
baseDelayMs = 1000;
|
|
43706
|
-
maxDelayMs = 1e4;
|
|
43707
|
-
maxQueueSize = 100;
|
|
43708
|
-
constructor() {
|
|
43709
|
-
log("[GeminiQueue] Queue initialized with minDelay=1000ms, maxQueueSize=100");
|
|
43710
|
-
}
|
|
43711
|
-
static getInstance() {
|
|
43712
|
-
if (!GeminiRequestQueue.instance) {
|
|
43713
|
-
GeminiRequestQueue.instance = new GeminiRequestQueue;
|
|
43714
|
-
}
|
|
43715
|
-
return GeminiRequestQueue.instance;
|
|
43716
|
-
}
|
|
43717
|
-
async enqueue(fetchFn) {
|
|
43718
|
-
if (this.queue.length >= this.maxQueueSize) {
|
|
43719
|
-
log(`[GeminiQueue] Queue full (${this.queue.length}/${this.maxQueueSize}), rejecting request`);
|
|
43720
|
-
throw new Error("Gemini request queue full. Please retry later.");
|
|
43721
|
-
}
|
|
43722
|
-
return new Promise((resolve3, reject) => {
|
|
43723
|
-
const queuedRequest = {
|
|
43724
|
-
fetchFn,
|
|
43725
|
-
resolve: resolve3,
|
|
43726
|
-
reject
|
|
43727
|
-
};
|
|
43728
|
-
this.queue.push(queuedRequest);
|
|
43729
|
-
log(`[GeminiQueue] Request enqueued (queue length: ${this.queue.length})`);
|
|
43730
|
-
if (!this.processing) {
|
|
43731
|
-
this.processQueue();
|
|
43732
|
-
}
|
|
43733
|
-
});
|
|
43734
|
-
}
|
|
43735
|
-
async processQueue() {
|
|
43736
|
-
if (this.processing) {
|
|
43737
|
-
return;
|
|
43738
|
-
}
|
|
43739
|
-
this.processing = true;
|
|
43740
|
-
log("[GeminiQueue] Worker started");
|
|
43741
|
-
while (this.queue.length > 0) {
|
|
43742
|
-
const request = this.queue.shift();
|
|
43743
|
-
if (!request)
|
|
43744
|
-
break;
|
|
43745
|
-
log(`[GeminiQueue] Processing request (${this.queue.length} remaining in queue)`);
|
|
43746
|
-
try {
|
|
43747
|
-
await this.waitForNextSlot();
|
|
43748
|
-
const response = await request.fetchFn();
|
|
43749
|
-
this.lastRequestTime = Date.now();
|
|
43750
|
-
if (response.status === 429) {
|
|
43751
|
-
this.totalErrors++;
|
|
43752
|
-
const errorText = await response.clone().text();
|
|
43753
|
-
this.handleRateLimitResponse(errorText);
|
|
43754
|
-
log(`[GeminiQueue] Rate limit hit (429), adjusted delay to ${this.minDelayMs}ms`);
|
|
43755
|
-
} else {
|
|
43756
|
-
this.handleSuccessResponse();
|
|
43757
|
-
}
|
|
43758
|
-
this.totalProcessed++;
|
|
43759
|
-
request.resolve(response);
|
|
43760
|
-
} catch (error46) {
|
|
43761
|
-
this.totalErrors++;
|
|
43762
|
-
log(`[GeminiQueue] Request failed with error: ${error46}`);
|
|
43763
|
-
request.reject(error46 instanceof Error ? error46 : new Error(String(error46)));
|
|
43764
|
-
}
|
|
43765
|
-
}
|
|
43766
|
-
this.processing = false;
|
|
43767
|
-
log("[GeminiQueue] Worker stopped (queue empty)");
|
|
43768
|
-
}
|
|
43769
|
-
async waitForNextSlot() {
|
|
43770
|
-
const now = Date.now();
|
|
43771
|
-
const timeSinceLastRequest = now - this.lastRequestTime;
|
|
43772
|
-
let delayMs = this.minDelayMs;
|
|
43773
|
-
if (this.consecutiveErrors > 0) {
|
|
43774
|
-
const backoffMultiplier = 1 + this.consecutiveErrors * 0.5;
|
|
43775
|
-
delayMs = Math.min(this.minDelayMs * backoffMultiplier, this.maxDelayMs);
|
|
43776
|
-
log(`[GeminiQueue] Applying backoff (${this.consecutiveErrors} errors): ${delayMs}ms`);
|
|
43777
|
-
}
|
|
43778
|
-
if (timeSinceLastRequest < delayMs) {
|
|
43779
|
-
const waitMs = delayMs - timeSinceLastRequest;
|
|
43780
|
-
log(`[GeminiQueue] Waiting ${waitMs}ms before next request`);
|
|
43781
|
-
await new Promise((resolve3) => setTimeout(resolve3, waitMs));
|
|
43782
|
-
}
|
|
43783
|
-
}
|
|
43784
|
-
handleRateLimitResponse(errorText) {
|
|
43785
|
-
this.consecutiveErrors++;
|
|
43786
|
-
try {
|
|
43787
|
-
const errorData = JSON.parse(errorText);
|
|
43788
|
-
const quotaDetail = errorData?.error?.details?.find((d) => d.quotaResetDelay);
|
|
43789
|
-
if (quotaDetail?.quotaResetDelay) {
|
|
43790
|
-
const delayStr = quotaDetail.quotaResetDelay;
|
|
43791
|
-
const match2 = delayStr.match(/(\d+(?:\.\d+)?)/);
|
|
43792
|
-
if (match2) {
|
|
43793
|
-
const delaySeconds = Number.parseFloat(match2[1]);
|
|
43794
|
-
const suggestedDelayMs = Math.ceil(delaySeconds * 1000);
|
|
43795
|
-
this.minDelayMs = Math.max(suggestedDelayMs, this.minDelayMs, this.baseDelayMs);
|
|
43796
|
-
this.minDelayMs = Math.min(this.minDelayMs, this.maxDelayMs);
|
|
43797
|
-
log(`[GeminiQueue] Parsed quotaResetDelay: ${delayStr} (${suggestedDelayMs}ms), ` + `new minDelay: ${this.minDelayMs}ms`);
|
|
43798
|
-
}
|
|
43799
|
-
}
|
|
43800
|
-
} catch {
|
|
43801
|
-
log("[GeminiQueue] Failed to parse rate limit response, using backoff");
|
|
43802
|
-
}
|
|
43803
|
-
const backoffMultiplier = 1 + this.consecutiveErrors * 0.5;
|
|
43804
|
-
this.minDelayMs = Math.min(this.baseDelayMs * backoffMultiplier, this.maxDelayMs);
|
|
43805
|
-
}
|
|
43806
|
-
handleSuccessResponse() {
|
|
43807
|
-
if (this.consecutiveErrors > 0) {
|
|
43808
|
-
log(`[GeminiQueue] Success after ${this.consecutiveErrors} errors, resetting counter`);
|
|
43809
|
-
this.consecutiveErrors = 0;
|
|
43810
|
-
}
|
|
43811
|
-
if (this.minDelayMs > this.baseDelayMs) {
|
|
43812
|
-
this.minDelayMs = Math.max(this.baseDelayMs, this.minDelayMs * 0.9);
|
|
43813
|
-
log(`[GeminiQueue] Reducing delay to ${this.minDelayMs}ms`);
|
|
43814
|
-
}
|
|
43815
|
-
}
|
|
43816
|
-
getStats() {
|
|
43817
|
-
return {
|
|
43818
|
-
queueLength: this.queue.length,
|
|
43819
|
-
processing: this.processing,
|
|
43820
|
-
consecutiveErrors: this.consecutiveErrors,
|
|
43821
|
-
currentDelayMs: this.minDelayMs,
|
|
43822
|
-
totalProcessed: this.totalProcessed,
|
|
43823
|
-
totalErrors: this.totalErrors
|
|
43824
|
-
};
|
|
43825
|
-
}
|
|
43826
|
-
}
|
|
43827
|
-
var init_gemini_queue = __esm(() => {
|
|
43828
|
-
init_logger();
|
|
43829
|
-
});
|
|
43830
|
-
|
|
43831
44596
|
// src/providers/transport/gemini-apikey.ts
|
|
43832
44597
|
class GeminiProviderTransport {
|
|
43833
44598
|
name = "gemini";
|
|
@@ -43860,22 +44625,17 @@ var init_gemini_apikey = __esm(() => {
|
|
|
43860
44625
|
});
|
|
43861
44626
|
|
|
43862
44627
|
// src/providers/transport/gemini-codeassist.ts
|
|
43863
|
-
import { randomUUID as
|
|
43864
|
-
function
|
|
43865
|
-
const version2 = "0.5.6";
|
|
43866
|
-
const modelSegment = model || "gemini-code-assist";
|
|
43867
|
-
return `GeminiCLI/${version2}/${modelSegment} (${process.platform}; ${process.arch})`;
|
|
43868
|
-
}
|
|
43869
|
-
function createActivityRequestId2() {
|
|
44628
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
44629
|
+
function createActivityRequestId4() {
|
|
43870
44630
|
return Math.random().toString(36).substring(7);
|
|
43871
44631
|
}
|
|
43872
|
-
function
|
|
44632
|
+
function classify4292(responseBody) {
|
|
43873
44633
|
try {
|
|
43874
44634
|
const raw2 = JSON.parse(responseBody);
|
|
43875
44635
|
const error46 = Array.isArray(raw2) ? raw2[0]?.error : raw2?.error;
|
|
43876
44636
|
const details = Array.isArray(error46?.details) ? error46.details : [];
|
|
43877
44637
|
const retryInfo = details.find((d) => d["@type"] === "type.googleapis.com/google.rpc.RetryInfo");
|
|
43878
|
-
let retryDelayMs =
|
|
44638
|
+
let retryDelayMs = parseRetryDelay2(retryInfo?.retryDelay);
|
|
43879
44639
|
if (retryDelayMs === undefined && typeof error46?.message === "string") {
|
|
43880
44640
|
const match2 = error46.message.match(/retry in ([\d.]+)(ms|s)/i);
|
|
43881
44641
|
if (match2) {
|
|
@@ -43889,7 +44649,7 @@ function classify429(responseBody) {
|
|
|
43889
44649
|
return { terminal: true, retryDelayMs, reason };
|
|
43890
44650
|
}
|
|
43891
44651
|
if (reason === "RATE_LIMIT_EXCEEDED") {
|
|
43892
|
-
return { terminal: false, retryDelayMs: retryDelayMs ??
|
|
44652
|
+
return { terminal: false, retryDelayMs: retryDelayMs ?? DEFAULT_RATE_LIMIT_DELAY_MS2, reason };
|
|
43893
44653
|
}
|
|
43894
44654
|
if (reason === "MODEL_CAPACITY_EXHAUSTED") {
|
|
43895
44655
|
return { terminal: true, retryDelayMs, reason };
|
|
@@ -43909,7 +44669,7 @@ function classify429(responseBody) {
|
|
|
43909
44669
|
return null;
|
|
43910
44670
|
}
|
|
43911
44671
|
}
|
|
43912
|
-
function
|
|
44672
|
+
function parseRetryDelay2(value) {
|
|
43913
44673
|
if (!value)
|
|
43914
44674
|
return;
|
|
43915
44675
|
if (typeof value === "string") {
|
|
@@ -43927,7 +44687,7 @@ function parseRetryDelay(value) {
|
|
|
43927
44687
|
|
|
43928
44688
|
class GeminiCodeAssistProviderTransport {
|
|
43929
44689
|
name = "gemini-codeassist";
|
|
43930
|
-
_displayName = "
|
|
44690
|
+
_displayName = "GeminiCA";
|
|
43931
44691
|
get displayName() {
|
|
43932
44692
|
return this._displayName;
|
|
43933
44693
|
}
|
|
@@ -43937,19 +44697,17 @@ class GeminiCodeAssistProviderTransport {
|
|
|
43937
44697
|
projectId = null;
|
|
43938
44698
|
tierId = null;
|
|
43939
44699
|
cachedAuth = null;
|
|
43940
|
-
fallbackStartIndex;
|
|
43941
44700
|
lastEnvelope = null;
|
|
43942
44701
|
_activeModelName;
|
|
44702
|
+
servedModels = [];
|
|
43943
44703
|
constructor(modelName) {
|
|
43944
44704
|
this.modelName = modelName;
|
|
43945
|
-
const idx = CODE_ASSIST_FALLBACK_CHAIN.indexOf(modelName);
|
|
43946
|
-
this.fallbackStartIndex = idx >= 0 ? idx : CODE_ASSIST_FALLBACK_CHAIN.length;
|
|
43947
44705
|
}
|
|
43948
44706
|
getActiveModelName() {
|
|
43949
44707
|
return this._activeModelName;
|
|
43950
44708
|
}
|
|
43951
44709
|
getEndpoint() {
|
|
43952
|
-
return
|
|
44710
|
+
return CODE_ASSIST_ENDPOINT2;
|
|
43953
44711
|
}
|
|
43954
44712
|
async getHeaders() {
|
|
43955
44713
|
if (this.cachedAuth)
|
|
@@ -43959,8 +44717,8 @@ class GeminiCodeAssistProviderTransport {
|
|
|
43959
44717
|
buildLocalHeaders() {
|
|
43960
44718
|
return {
|
|
43961
44719
|
Authorization: `Bearer ${this.accessToken}`,
|
|
43962
|
-
"User-Agent":
|
|
43963
|
-
"x-activity-request-id":
|
|
44720
|
+
"User-Agent": buildCodeAssistUserAgent(this.modelName),
|
|
44721
|
+
"x-activity-request-id": createActivityRequestId4()
|
|
43964
44722
|
};
|
|
43965
44723
|
}
|
|
43966
44724
|
async refreshAuth() {
|
|
@@ -43972,7 +44730,8 @@ class GeminiCodeAssistProviderTransport {
|
|
|
43972
44730
|
this.projectId = projectId;
|
|
43973
44731
|
this.tierId = tierId;
|
|
43974
44732
|
this._displayName = getGeminiTierDisplayName();
|
|
43975
|
-
|
|
44733
|
+
this.servedModels = await getServedCodeAssistModels(this.accessToken, this.projectId);
|
|
44734
|
+
log(`[GeminiCodeAssist] Auth refreshed, project: ${this.projectId}, tier: ${this._displayName}, served: ${this.servedModels.join(",") || "(none)"}`);
|
|
43976
44735
|
}
|
|
43977
44736
|
transformPayload(payload) {
|
|
43978
44737
|
const envelope = this.cachedAuth?.transformPayload ? this.cachedAuth.transformPayload(payload) : this.buildEnvelope(payload, this.modelName);
|
|
@@ -43983,7 +44742,7 @@ class GeminiCodeAssistProviderTransport {
|
|
|
43983
44742
|
const envelope = {
|
|
43984
44743
|
model,
|
|
43985
44744
|
project: this.projectId,
|
|
43986
|
-
user_prompt_id:
|
|
44745
|
+
user_prompt_id: randomUUID5(),
|
|
43987
44746
|
request: innerPayload
|
|
43988
44747
|
};
|
|
43989
44748
|
if (this.tierId && this.tierId !== "free-tier") {
|
|
@@ -43994,13 +44753,16 @@ class GeminiCodeAssistProviderTransport {
|
|
|
43994
44753
|
async enqueueRequest(fetchFn) {
|
|
43995
44754
|
const queue = GeminiRequestQueue.getInstance();
|
|
43996
44755
|
let lastResponse = null;
|
|
43997
|
-
for (let attempt = 1;attempt <=
|
|
44756
|
+
for (let attempt = 1;attempt <= MAX_RETRY_ATTEMPTS2; attempt++) {
|
|
43998
44757
|
const response = attempt === 1 ? await queue.enqueue(fetchFn) : await queue.enqueue(fetchFn);
|
|
43999
44758
|
if (response.status !== 429) {
|
|
44759
|
+
if (response.status === 404) {
|
|
44760
|
+
return this.rewriteModelNotFound(response);
|
|
44761
|
+
}
|
|
44000
44762
|
return response;
|
|
44001
44763
|
}
|
|
44002
44764
|
const bodyText = await response.clone().text();
|
|
44003
|
-
const classification =
|
|
44765
|
+
const classification = classify4292(bodyText);
|
|
44004
44766
|
lastResponse = response;
|
|
44005
44767
|
if (!classification) {
|
|
44006
44768
|
log("[GeminiCodeAssist] 429 response could not be classified, returning to caller");
|
|
@@ -44014,20 +44776,21 @@ class GeminiCodeAssistProviderTransport {
|
|
|
44014
44776
|
logStderr(`[GeminiCodeAssist] Quota exhausted (${classification.reason || "daily limit"}). Check plan limits.`);
|
|
44015
44777
|
return response;
|
|
44016
44778
|
}
|
|
44017
|
-
if (attempt <
|
|
44018
|
-
const delay = classification.retryDelayMs ??
|
|
44019
|
-
logStderr(`[GeminiCodeAssist] Rate limited (${classification.reason || "unknown"}), retrying in ${(delay / 1000).toFixed(1)}s (attempt ${attempt}/${
|
|
44779
|
+
if (attempt < MAX_RETRY_ATTEMPTS2) {
|
|
44780
|
+
const delay = classification.retryDelayMs ?? DEFAULT_RATE_LIMIT_DELAY_MS2;
|
|
44781
|
+
logStderr(`[GeminiCodeAssist] Rate limited (${classification.reason || "unknown"}), retrying in ${(delay / 1000).toFixed(1)}s (attempt ${attempt}/${MAX_RETRY_ATTEMPTS2})`);
|
|
44020
44782
|
if (attempt === 1) {
|
|
44021
44783
|
await this.logQuotaInfo();
|
|
44022
44784
|
}
|
|
44023
44785
|
await new Promise((r) => setTimeout(r, delay));
|
|
44024
44786
|
}
|
|
44025
44787
|
}
|
|
44026
|
-
logStderr(`[GeminiCodeAssist] Rate limit persisted after ${
|
|
44788
|
+
logStderr(`[GeminiCodeAssist] Rate limit persisted after ${MAX_RETRY_ATTEMPTS2} retries`);
|
|
44027
44789
|
return lastResponse;
|
|
44028
44790
|
}
|
|
44029
44791
|
async handleCapacityExhausted(originalResponse, queue) {
|
|
44030
|
-
|
|
44792
|
+
const candidates = this.servedModels.filter((m) => m !== this.modelName);
|
|
44793
|
+
if (candidates.length === 0) {
|
|
44031
44794
|
log(`[GeminiCodeAssist] ${this.modelName} capacity exhausted, no fallback models available`);
|
|
44032
44795
|
return originalResponse;
|
|
44033
44796
|
}
|
|
@@ -44039,11 +44802,12 @@ class GeminiCodeAssistProviderTransport {
|
|
|
44039
44802
|
logStderr(`[GeminiCodeAssist] ${this.modelName} capacity exhausted, trying fallback models...`);
|
|
44040
44803
|
let lastResponse = originalResponse;
|
|
44041
44804
|
const innerPayload = this.lastEnvelope.request;
|
|
44042
|
-
|
|
44043
|
-
|
|
44805
|
+
const endpoint = this.getEndpoint();
|
|
44806
|
+
const tried = [this.modelName];
|
|
44807
|
+
for (const fallbackModel of candidates) {
|
|
44044
44808
|
log(`[GeminiCodeAssist] Trying fallback model: ${fallbackModel}`);
|
|
44809
|
+
tried.push(fallbackModel);
|
|
44045
44810
|
const fallbackEnvelope = this.buildEnvelope(innerPayload, fallbackModel);
|
|
44046
|
-
const endpoint = this.getEndpoint();
|
|
44047
44811
|
const headers = this.buildLocalHeaders();
|
|
44048
44812
|
headers["Content-Type"] = "application/json";
|
|
44049
44813
|
const fallbackResponse = await queue.enqueue(() => fetch(endpoint, {
|
|
@@ -44051,23 +44815,59 @@ class GeminiCodeAssistProviderTransport {
|
|
|
44051
44815
|
headers,
|
|
44052
44816
|
body: JSON.stringify(fallbackEnvelope)
|
|
44053
44817
|
}));
|
|
44054
|
-
if (fallbackResponse.status
|
|
44818
|
+
if (fallbackResponse.status === 200) {
|
|
44055
44819
|
this._activeModelName = fallbackModel;
|
|
44056
44820
|
logStderr(`[GeminiCodeAssist] Using fallback model: ${fallbackModel} (${this.modelName} had no capacity)`);
|
|
44057
44821
|
return fallbackResponse;
|
|
44058
44822
|
}
|
|
44059
|
-
|
|
44060
|
-
|
|
44061
|
-
|
|
44823
|
+
if (fallbackResponse.status === 404) {
|
|
44824
|
+
log(`[GeminiCodeAssist] ${fallbackModel} returned 404, skipping to next fallback`);
|
|
44825
|
+
lastResponse = fallbackResponse;
|
|
44826
|
+
continue;
|
|
44827
|
+
}
|
|
44828
|
+
if (fallbackResponse.status === 429) {
|
|
44829
|
+
const fallbackBodyText = await fallbackResponse.clone().text();
|
|
44830
|
+
const classification = classify4292(fallbackBodyText);
|
|
44831
|
+
if (classification?.reason === "MODEL_CAPACITY_EXHAUSTED") {
|
|
44832
|
+
log(`[GeminiCodeAssist] ${fallbackModel} also capacity exhausted, trying next...`);
|
|
44833
|
+
lastResponse = fallbackResponse;
|
|
44834
|
+
continue;
|
|
44835
|
+
}
|
|
44062
44836
|
return fallbackResponse;
|
|
44063
44837
|
}
|
|
44064
|
-
|
|
44065
|
-
lastResponse = fallbackResponse;
|
|
44838
|
+
return fallbackResponse;
|
|
44066
44839
|
}
|
|
44067
44840
|
log("[GeminiCodeAssist] All fallback models exhausted");
|
|
44068
|
-
logStderr(`[GeminiCodeAssist] All models capacity exhausted (tried: ${
|
|
44841
|
+
logStderr(`[GeminiCodeAssist] All models capacity exhausted (tried: ${tried.join(" -> ")})`);
|
|
44842
|
+
if (lastResponse.status === 404) {
|
|
44843
|
+
return this.rewriteModelNotFound(lastResponse, true);
|
|
44844
|
+
}
|
|
44069
44845
|
return lastResponse;
|
|
44070
44846
|
}
|
|
44847
|
+
rewriteModelNotFound(response, capacityFallbacksExhausted = false) {
|
|
44848
|
+
const served = this.servedModels.length > 0 ? this.servedModels : CODE_ASSIST_FALLBACK_CHAIN.slice();
|
|
44849
|
+
if (!capacityFallbacksExhausted && served.includes(this.modelName)) {
|
|
44850
|
+
log(`[GeminiCodeAssist] 404 for ${this.modelName}, which IS in the served set \u2014 passing through unmodified`);
|
|
44851
|
+
return response;
|
|
44852
|
+
}
|
|
44853
|
+
response.text().catch(() => {});
|
|
44854
|
+
const list = served.join(", ");
|
|
44855
|
+
const tier = this._displayName || "Gemini Code Assist";
|
|
44856
|
+
const reason = capacityFallbacksExhausted ? `${this.modelName} could not be served after every Gemini Code Assist capacity fallback failed (${tier}, via go@). ` + `That tier currently reports: ${list}. ` : `${this.modelName} is not served by your Gemini Code Assist tier (${tier}, via go@). ` + `That tier currently serves: ${list}. `;
|
|
44857
|
+
const message = reason + `To use ${this.modelName}, go through the direct Gemini API instead \u2014 ` + `set GEMINI_API_KEY (get one at https://aistudio.google.com/app/apikey) and run ` + `google@${this.modelName}.`;
|
|
44858
|
+
const body = JSON.stringify({
|
|
44859
|
+
error: { code: 404, status: "NOT_FOUND", message }
|
|
44860
|
+
});
|
|
44861
|
+
if (capacityFallbacksExhausted) {
|
|
44862
|
+
logStderr(`[GeminiCodeAssist] ${this.modelName} capacity fallbacks exhausted (404). Reported models: ${list}`);
|
|
44863
|
+
} else {
|
|
44864
|
+
logStderr(`[GeminiCodeAssist] ${this.modelName} not served by ${tier} (404). Serves: ${list}`);
|
|
44865
|
+
}
|
|
44866
|
+
return new Response(body, {
|
|
44867
|
+
status: 404,
|
|
44868
|
+
headers: { "Content-Type": "application/json" }
|
|
44869
|
+
});
|
|
44870
|
+
}
|
|
44071
44871
|
async logQuotaInfo() {
|
|
44072
44872
|
if (!this.accessToken || !this.projectId)
|
|
44073
44873
|
return;
|
|
@@ -44107,13 +44907,13 @@ ${lines.join(`
|
|
|
44107
44907
|
}
|
|
44108
44908
|
}
|
|
44109
44909
|
}
|
|
44110
|
-
var
|
|
44910
|
+
var CODE_ASSIST_BASE2 = "https://cloudcode-pa.googleapis.com", CODE_ASSIST_ENDPOINT2, MAX_RETRY_ATTEMPTS2 = 3, DEFAULT_RATE_LIMIT_DELAY_MS2 = 1e4;
|
|
44111
44911
|
var init_gemini_codeassist = __esm(() => {
|
|
44112
44912
|
init_authority();
|
|
44113
44913
|
init_gemini_oauth();
|
|
44114
44914
|
init_gemini_queue();
|
|
44115
44915
|
init_logger();
|
|
44116
|
-
|
|
44916
|
+
CODE_ASSIST_ENDPOINT2 = `${CODE_ASSIST_BASE2}/v1internal:streamGenerateContent?alt=sse`;
|
|
44117
44917
|
});
|
|
44118
44918
|
|
|
44119
44919
|
// src/providers/transport/ollamacloud.ts
|
|
@@ -44275,7 +45075,7 @@ function createHandlerForProvider(ctx) {
|
|
|
44275
45075
|
log(`[Proxy] Handler: provider=${ctx.provider.name}, model=${ctx.modelName}`);
|
|
44276
45076
|
return profile.createHandler(ctx);
|
|
44277
45077
|
}
|
|
44278
|
-
var geminiProfile, geminiCodeAssistProfile, openaiProfile, openaiCodexProfile, anthropicCompatProfile, glmProfile, openCodeZenProfile, ollamaCloudProfile, litellmProfile, vertexProfile, PROVIDER_PROFILES;
|
|
45078
|
+
var geminiProfile, geminiCodeAssistProfile, antigravityProfile, openaiProfile, openaiCodexProfile, anthropicCompatProfile, glmProfile, openCodeZenProfile, ollamaCloudProfile, litellmProfile, vertexProfile, PROVIDER_PROFILES;
|
|
44279
45079
|
var init_provider_profiles = __esm(() => {
|
|
44280
45080
|
init_anthropic_api_format();
|
|
44281
45081
|
init_base_api_format();
|
|
@@ -44291,6 +45091,7 @@ var init_provider_profiles = __esm(() => {
|
|
|
44291
45091
|
init_remote_provider_registry();
|
|
44292
45092
|
init_runtime_providers();
|
|
44293
45093
|
init_anthropic_compat();
|
|
45094
|
+
init_antigravity();
|
|
44294
45095
|
init_gemini_apikey();
|
|
44295
45096
|
init_gemini_codeassist();
|
|
44296
45097
|
init_litellm();
|
|
@@ -44323,6 +45124,19 @@ var init_provider_profiles = __esm(() => {
|
|
|
44323
45124
|
return handler;
|
|
44324
45125
|
}
|
|
44325
45126
|
};
|
|
45127
|
+
antigravityProfile = {
|
|
45128
|
+
createHandler(ctx) {
|
|
45129
|
+
const transport = new AntigravityProviderTransport(ctx.modelName);
|
|
45130
|
+
const adapter = new GeminiAPIFormat(ctx.modelName);
|
|
45131
|
+
const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
|
|
45132
|
+
adapter,
|
|
45133
|
+
unwrapGeminiResponse: true,
|
|
45134
|
+
...ctx.sharedOpts
|
|
45135
|
+
});
|
|
45136
|
+
log(`[Proxy] Created Antigravity handler (composed): ${ctx.modelName}`);
|
|
45137
|
+
return handler;
|
|
45138
|
+
}
|
|
45139
|
+
};
|
|
44326
45140
|
openaiProfile = {
|
|
44327
45141
|
createHandler(ctx) {
|
|
44328
45142
|
if (requiresResponsesApi(ctx.modelName)) {
|
|
@@ -44501,6 +45315,7 @@ var init_provider_profiles = __esm(() => {
|
|
|
44501
45315
|
PROVIDER_PROFILES = {
|
|
44502
45316
|
gemini: geminiProfile,
|
|
44503
45317
|
"gemini-codeassist": geminiCodeAssistProfile,
|
|
45318
|
+
antigravity: antigravityProfile,
|
|
44504
45319
|
openai: openaiProfile,
|
|
44505
45320
|
"openai-codex": openaiCodexProfile,
|
|
44506
45321
|
"x-ai": openaiProfile,
|
|
@@ -45238,9 +46053,9 @@ var init_poe = __esm(() => {
|
|
|
45238
46053
|
});
|
|
45239
46054
|
|
|
45240
46055
|
// src/services/pricing-cache.ts
|
|
45241
|
-
import { existsSync as
|
|
45242
|
-
import { homedir as
|
|
45243
|
-
import { join as
|
|
46056
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15, statSync as statSync4 } from "fs";
|
|
46057
|
+
import { homedir as homedir24 } from "os";
|
|
46058
|
+
import { join as join24 } from "path";
|
|
45244
46059
|
function prefixMatch(modelName) {
|
|
45245
46060
|
for (const [key, pricing] of pricingMap) {
|
|
45246
46061
|
if (modelName.startsWith(key))
|
|
@@ -45278,7 +46093,7 @@ async function warmPricingCache() {
|
|
|
45278
46093
|
}
|
|
45279
46094
|
function loadDiskCache() {
|
|
45280
46095
|
try {
|
|
45281
|
-
if (!
|
|
46096
|
+
if (!existsSync17(CACHE_FILE))
|
|
45282
46097
|
return false;
|
|
45283
46098
|
const stat2 = statSync4(CACHE_FILE);
|
|
45284
46099
|
const age = Date.now() - stat2.mtimeMs;
|
|
@@ -45299,8 +46114,8 @@ var init_pricing_cache = __esm(() => {
|
|
|
45299
46114
|
init_logger();
|
|
45300
46115
|
init_catalog_query();
|
|
45301
46116
|
pricingMap = new Map;
|
|
45302
|
-
CACHE_DIR =
|
|
45303
|
-
CACHE_FILE =
|
|
46117
|
+
CACHE_DIR = join24(homedir24(), ".claudish");
|
|
46118
|
+
CACHE_FILE = join24(CACHE_DIR, "pricing-cache.json");
|
|
45304
46119
|
CACHE_TTL_MS2 = 24 * 60 * 60 * 1000;
|
|
45305
46120
|
});
|
|
45306
46121
|
|
|
@@ -45757,17 +46572,17 @@ var init_proxy_server = __esm(() => {
|
|
|
45757
46572
|
});
|
|
45758
46573
|
|
|
45759
46574
|
// src/team-stats.ts
|
|
45760
|
-
import { existsSync as
|
|
45761
|
-
import { join as
|
|
46575
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16, writeFileSync as writeFileSync11 } from "fs";
|
|
46576
|
+
import { join as join25 } from "path";
|
|
45762
46577
|
function statsDir(sessionPath) {
|
|
45763
|
-
return
|
|
46578
|
+
return join25(sessionPath, "stats");
|
|
45764
46579
|
}
|
|
45765
46580
|
function tokenFileFor(sessionPath, anonId) {
|
|
45766
|
-
return
|
|
46581
|
+
return join25(statsDir(sessionPath), `${anonId}.json`);
|
|
45767
46582
|
}
|
|
45768
46583
|
function readTokenStats(sessionPath, anonId) {
|
|
45769
46584
|
const path = tokenFileFor(sessionPath, anonId);
|
|
45770
|
-
if (!
|
|
46585
|
+
if (!existsSync18(path))
|
|
45771
46586
|
return null;
|
|
45772
46587
|
try {
|
|
45773
46588
|
return JSON.parse(readFileSync16(path, "utf-8"));
|
|
@@ -45918,7 +46733,7 @@ ${segs.join(" \xB7 ")}`;
|
|
|
45918
46733
|
}
|
|
45919
46734
|
function writeStatusFile(sessionPath, manifest, status, opts) {
|
|
45920
46735
|
try {
|
|
45921
|
-
writeFileSync11(
|
|
46736
|
+
writeFileSync11(join25(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
|
|
45922
46737
|
`, "utf-8");
|
|
45923
46738
|
} catch {}
|
|
45924
46739
|
}
|
|
@@ -45944,13 +46759,13 @@ __export(exports_team_orchestrator, {
|
|
|
45944
46759
|
import { spawn as spawn2 } from "child_process";
|
|
45945
46760
|
import {
|
|
45946
46761
|
createWriteStream as createWriteStream2,
|
|
45947
|
-
existsSync as
|
|
46762
|
+
existsSync as existsSync19,
|
|
45948
46763
|
mkdirSync as mkdirSync11,
|
|
45949
46764
|
readFileSync as readFileSync17,
|
|
45950
46765
|
readdirSync as readdirSync3,
|
|
45951
46766
|
writeFileSync as writeFileSync12
|
|
45952
46767
|
} from "fs";
|
|
45953
|
-
import { join as
|
|
46768
|
+
import { join as join26, resolve as resolve3 } from "path";
|
|
45954
46769
|
function classifyRunOutput(opts) {
|
|
45955
46770
|
const { outputSize, stdoutTail, stderr, minOutputBytes } = opts;
|
|
45956
46771
|
const apiError = API_ERROR_RE.exec(stdoutTail);
|
|
@@ -46011,18 +46826,18 @@ function setupSession(sessionPath, models, input) {
|
|
|
46011
46826
|
if (models.length === 0) {
|
|
46012
46827
|
throw new Error("At least one model is required");
|
|
46013
46828
|
}
|
|
46014
|
-
if (
|
|
46829
|
+
if (existsSync19(join26(sessionPath, "manifest.json"))) {
|
|
46015
46830
|
throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
|
|
46016
46831
|
}
|
|
46017
46832
|
const sentinels = models.filter(isSentinelModel);
|
|
46018
46833
|
if (sentinels.length > 0) {
|
|
46019
46834
|
throw new Error(`Invalid model(s) for team run: ${sentinels.join(", ")}. These are Claude Code agent selectors, not external model IDs. Use real external models (e.g., "gemini-2.0-flash", "gpt-4o", "or@deepseek/deepseek-r1"). For Claude models, use a Task agent instead of the team tool.`);
|
|
46020
46835
|
}
|
|
46021
|
-
mkdirSync11(
|
|
46022
|
-
mkdirSync11(
|
|
46836
|
+
mkdirSync11(join26(sessionPath, "work"), { recursive: true });
|
|
46837
|
+
mkdirSync11(join26(sessionPath, "errors"), { recursive: true });
|
|
46023
46838
|
if (input !== undefined) {
|
|
46024
|
-
writeFileSync12(
|
|
46025
|
-
} else if (!
|
|
46839
|
+
writeFileSync12(join26(sessionPath, "input.md"), input, "utf-8");
|
|
46840
|
+
} else if (!existsSync19(join26(sessionPath, "input.md"))) {
|
|
46026
46841
|
throw new Error(`No input.md found at ${sessionPath} and no input provided`);
|
|
46027
46842
|
}
|
|
46028
46843
|
const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
|
|
@@ -46039,9 +46854,9 @@ function setupSession(sessionPath, models, input) {
|
|
|
46039
46854
|
model: models[i],
|
|
46040
46855
|
assignedAt: now
|
|
46041
46856
|
};
|
|
46042
|
-
mkdirSync11(
|
|
46857
|
+
mkdirSync11(join26(sessionPath, "work", anonId), { recursive: true });
|
|
46043
46858
|
}
|
|
46044
|
-
writeFileSync12(
|
|
46859
|
+
writeFileSync12(join26(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
46045
46860
|
const status = {
|
|
46046
46861
|
startedAt: now,
|
|
46047
46862
|
models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
|
|
@@ -46055,14 +46870,14 @@ function setupSession(sessionPath, models, input) {
|
|
|
46055
46870
|
}
|
|
46056
46871
|
]))
|
|
46057
46872
|
};
|
|
46058
|
-
writeFileSync12(
|
|
46873
|
+
writeFileSync12(join26(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
|
|
46059
46874
|
return manifest;
|
|
46060
46875
|
}
|
|
46061
46876
|
async function runModels(sessionPath, opts = {}) {
|
|
46062
46877
|
const timeoutMs = (opts.timeout ?? 300) * 1000;
|
|
46063
|
-
const manifest = JSON.parse(readFileSync17(
|
|
46064
|
-
const statusPath =
|
|
46065
|
-
const inputPath =
|
|
46878
|
+
const manifest = JSON.parse(readFileSync17(join26(sessionPath, "manifest.json"), "utf-8"));
|
|
46879
|
+
const statusPath = join26(sessionPath, "status.json");
|
|
46880
|
+
const inputPath = join26(sessionPath, "input.md");
|
|
46066
46881
|
const inputContent = readFileSync17(inputPath, "utf-8");
|
|
46067
46882
|
await prehydrateCredentialsForSpawn(Object.values(manifest.models).map((m) => m.model));
|
|
46068
46883
|
const statusCache = JSON.parse(readFileSync17(statusPath, "utf-8"));
|
|
@@ -46084,8 +46899,8 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
46084
46899
|
process.on("SIGINT", sigintHandler);
|
|
46085
46900
|
const completionPromises = [];
|
|
46086
46901
|
for (const [anonId, entry] of Object.entries(manifest.models)) {
|
|
46087
|
-
const outputPath =
|
|
46088
|
-
const errorLogPath =
|
|
46902
|
+
const outputPath = join26(sessionPath, `response-${anonId}.md`);
|
|
46903
|
+
const errorLogPath = join26(sessionPath, "errors", `${anonId}.log`);
|
|
46089
46904
|
const args = ["--model", entry.model, "-y", "--stdin", "--quiet", ...opts.claudeFlags ?? []];
|
|
46090
46905
|
updateModelStatus(anonId, {
|
|
46091
46906
|
state: "RUNNING",
|
|
@@ -46274,23 +47089,23 @@ async function judgeResponses(sessionPath, opts = {}) {
|
|
|
46274
47089
|
const responses = {};
|
|
46275
47090
|
for (const file2 of responseFiles) {
|
|
46276
47091
|
const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
|
|
46277
|
-
responses[id] = readFileSync17(
|
|
47092
|
+
responses[id] = readFileSync17(join26(sessionPath, file2), "utf-8");
|
|
46278
47093
|
}
|
|
46279
|
-
const input = readFileSync17(
|
|
47094
|
+
const input = readFileSync17(join26(sessionPath, "input.md"), "utf-8");
|
|
46280
47095
|
const judgePrompt = buildJudgePrompt(input, responses);
|
|
46281
|
-
writeFileSync12(
|
|
47096
|
+
writeFileSync12(join26(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
|
|
46282
47097
|
const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
|
|
46283
|
-
const judgePath =
|
|
47098
|
+
const judgePath = join26(sessionPath, "judging");
|
|
46284
47099
|
mkdirSync11(judgePath, { recursive: true });
|
|
46285
47100
|
setupSession(judgePath, judgeModels, judgePrompt);
|
|
46286
47101
|
await runModels(judgePath, { claudeFlags: opts.claudeFlags });
|
|
46287
47102
|
const votes = parseJudgeVotes(judgePath, Object.keys(responses));
|
|
46288
47103
|
const verdict = aggregateVerdict(votes, Object.keys(responses));
|
|
46289
|
-
writeFileSync12(
|
|
47104
|
+
writeFileSync12(join26(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
|
|
46290
47105
|
return verdict;
|
|
46291
47106
|
}
|
|
46292
47107
|
function getStatus(sessionPath) {
|
|
46293
|
-
return JSON.parse(readFileSync17(
|
|
47108
|
+
return JSON.parse(readFileSync17(join26(sessionPath, "status.json"), "utf-8"));
|
|
46294
47109
|
}
|
|
46295
47110
|
function fisherYatesShuffle(arr) {
|
|
46296
47111
|
for (let i = arr.length - 1;i > 0; i--) {
|
|
@@ -46300,7 +47115,7 @@ function fisherYatesShuffle(arr) {
|
|
|
46300
47115
|
return arr;
|
|
46301
47116
|
}
|
|
46302
47117
|
function getDefaultJudgeModels(sessionPath) {
|
|
46303
|
-
const manifest = JSON.parse(readFileSync17(
|
|
47118
|
+
const manifest = JSON.parse(readFileSync17(join26(sessionPath, "manifest.json"), "utf-8"));
|
|
46304
47119
|
return Object.values(manifest.models).map((e) => e.model);
|
|
46305
47120
|
}
|
|
46306
47121
|
function buildJudgePrompt(input, responses) {
|
|
@@ -46363,7 +47178,7 @@ function parseJudgeVotes(judgePath, responseIds) {
|
|
|
46363
47178
|
const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
|
|
46364
47179
|
let content;
|
|
46365
47180
|
try {
|
|
46366
|
-
content = readFileSync17(
|
|
47181
|
+
content = readFileSync17(join26(judgePath, file2), "utf-8");
|
|
46367
47182
|
} catch {
|
|
46368
47183
|
continue;
|
|
46369
47184
|
}
|
|
@@ -46415,7 +47230,7 @@ function aggregateVerdict(votes, responseIds) {
|
|
|
46415
47230
|
function formatVerdict(verdict, sessionPath) {
|
|
46416
47231
|
let manifest = null;
|
|
46417
47232
|
try {
|
|
46418
|
-
manifest = JSON.parse(readFileSync17(
|
|
47233
|
+
manifest = JSON.parse(readFileSync17(join26(sessionPath, "manifest.json"), "utf-8"));
|
|
46419
47234
|
} catch {}
|
|
46420
47235
|
let output = `# Team Verdict
|
|
46421
47236
|
|
|
@@ -46470,12 +47285,12 @@ __export(exports_mcp_server, {
|
|
|
46470
47285
|
parseAnthropicSse: () => parseAnthropicSse,
|
|
46471
47286
|
formatTeamResult: () => formatTeamResult
|
|
46472
47287
|
});
|
|
46473
|
-
import { existsSync as
|
|
46474
|
-
import { homedir as
|
|
46475
|
-
import { dirname as dirname8, join as
|
|
47288
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync12, readFileSync as readFileSync18, readdirSync as readdirSync4, writeFileSync as writeFileSync13 } from "fs";
|
|
47289
|
+
import { homedir as homedir25 } from "os";
|
|
47290
|
+
import { dirname as dirname8, join as join27 } from "path";
|
|
46476
47291
|
import { fileURLToPath } from "url";
|
|
46477
47292
|
async function loadAllModels(forceRefresh = false) {
|
|
46478
|
-
if (!forceRefresh &&
|
|
47293
|
+
if (!forceRefresh && existsSync20(ALL_MODELS_CACHE_PATH2)) {
|
|
46479
47294
|
try {
|
|
46480
47295
|
const cacheData = JSON.parse(readFileSync18(ALL_MODELS_CACHE_PATH2, "utf-8"));
|
|
46481
47296
|
const lastUpdated = new Date(cacheData.lastUpdated);
|
|
@@ -46495,7 +47310,7 @@ async function loadAllModels(forceRefresh = false) {
|
|
|
46495
47310
|
writeFileSync13(ALL_MODELS_CACHE_PATH2, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
|
|
46496
47311
|
return models;
|
|
46497
47312
|
} catch {
|
|
46498
|
-
if (
|
|
47313
|
+
if (existsSync20(ALL_MODELS_CACHE_PATH2)) {
|
|
46499
47314
|
const cacheData = JSON.parse(readFileSync18(ALL_MODELS_CACHE_PATH2, "utf-8"));
|
|
46500
47315
|
return cacheData.models || [];
|
|
46501
47316
|
}
|
|
@@ -47071,16 +47886,16 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
47071
47886
|
const sp = session_path;
|
|
47072
47887
|
for (const file2 of ["status.json", "manifest.json", "input.md"]) {
|
|
47073
47888
|
try {
|
|
47074
|
-
sessionData[file2] = readFileSync18(
|
|
47889
|
+
sessionData[file2] = readFileSync18(join27(sp, file2), "utf-8");
|
|
47075
47890
|
} catch {}
|
|
47076
47891
|
}
|
|
47077
47892
|
try {
|
|
47078
|
-
const errorDir =
|
|
47079
|
-
if (
|
|
47893
|
+
const errorDir = join27(sp, "errors");
|
|
47894
|
+
if (existsSync20(errorDir)) {
|
|
47080
47895
|
for (const f of readdirSync4(errorDir)) {
|
|
47081
47896
|
if (f.endsWith(".log")) {
|
|
47082
47897
|
try {
|
|
47083
|
-
sessionData[`errors/${f}`] = readFileSync18(
|
|
47898
|
+
sessionData[`errors/${f}`] = readFileSync18(join27(errorDir, f), "utf-8");
|
|
47084
47899
|
} catch {}
|
|
47085
47900
|
}
|
|
47086
47901
|
}
|
|
@@ -47090,7 +47905,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
47090
47905
|
for (const f of readdirSync4(sp)) {
|
|
47091
47906
|
if (f.startsWith("response-") && f.endsWith(".md")) {
|
|
47092
47907
|
try {
|
|
47093
|
-
const content = readFileSync18(
|
|
47908
|
+
const content = readFileSync18(join27(sp, f), "utf-8");
|
|
47094
47909
|
sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
|
|
47095
47910
|
} catch {}
|
|
47096
47911
|
}
|
|
@@ -47099,8 +47914,8 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
47099
47914
|
}
|
|
47100
47915
|
let version2 = "unknown";
|
|
47101
47916
|
try {
|
|
47102
|
-
const pkgPath =
|
|
47103
|
-
if (
|
|
47917
|
+
const pkgPath = join27(__dirname2, "../package.json");
|
|
47918
|
+
if (existsSync20(pkgPath)) {
|
|
47104
47919
|
version2 = JSON.parse(readFileSync18(pkgPath, "utf-8")).version;
|
|
47105
47920
|
}
|
|
47106
47921
|
} catch {}
|
|
@@ -47499,8 +48314,8 @@ var init_mcp_server = __esm(() => {
|
|
|
47499
48314
|
import_dotenv2.config({ quiet: true });
|
|
47500
48315
|
__filename2 = fileURLToPath(import.meta.url);
|
|
47501
48316
|
__dirname2 = dirname8(__filename2);
|
|
47502
|
-
CLAUDISH_CACHE_DIR =
|
|
47503
|
-
ALL_MODELS_CACHE_PATH2 =
|
|
48317
|
+
CLAUDISH_CACHE_DIR = join27(homedir25(), ".claudish");
|
|
48318
|
+
ALL_MODELS_CACHE_PATH2 = join27(CLAUDISH_CACHE_DIR, "all-models.json");
|
|
47504
48319
|
NEXT_STEP = {
|
|
47505
48320
|
nonzero_exit: "read the evidence log, then retry or drop the model",
|
|
47506
48321
|
timeout: "raise `timeout`, or pick a faster model",
|
|
@@ -47525,7 +48340,7 @@ var exports_serve_command = {};
|
|
|
47525
48340
|
__export(exports_serve_command, {
|
|
47526
48341
|
serveCommand: () => serveCommand
|
|
47527
48342
|
});
|
|
47528
|
-
import { existsSync as
|
|
48343
|
+
import { existsSync as existsSync21, readFileSync as readFileSync19 } from "fs";
|
|
47529
48344
|
function parseServeArgs(args) {
|
|
47530
48345
|
const out = {};
|
|
47531
48346
|
for (let i = 0;i < args.length; i++) {
|
|
@@ -47544,7 +48359,7 @@ function parseServeArgs(args) {
|
|
|
47544
48359
|
return out;
|
|
47545
48360
|
}
|
|
47546
48361
|
function loadModelMap(path) {
|
|
47547
|
-
if (!
|
|
48362
|
+
if (!existsSync21(path)) {
|
|
47548
48363
|
throw new Error(`--models file not found: ${path}`);
|
|
47549
48364
|
}
|
|
47550
48365
|
let raw2;
|
|
@@ -47748,6 +48563,8 @@ function describeSourceSync(p, config3) {
|
|
|
47748
48563
|
return isLocalProviderEnabled(p.catalogName, config3) ? "local" : null;
|
|
47749
48564
|
if (p.oauthSlug && hasOAuthCredentials(p.catalogName))
|
|
47750
48565
|
return "oauth";
|
|
48566
|
+
if (p.catalogName === "antigravity" && hasSharedAntigravityToken())
|
|
48567
|
+
return "oauth";
|
|
47751
48568
|
const hasCfg = !!p.apiKeyEnvVar && !!realValue(config3.apiKeys?.[p.apiKeyEnvVar]);
|
|
47752
48569
|
const hasEnv = !!p.apiKeyEnvVar && !!realValue(process.env[p.apiKeyEnvVar]);
|
|
47753
48570
|
if (hasEnv && hasCfg)
|
|
@@ -47768,6 +48585,7 @@ async function describeSource(p, config3) {
|
|
|
47768
48585
|
}
|
|
47769
48586
|
var init_source = __esm(() => {
|
|
47770
48587
|
init_profile_config();
|
|
48588
|
+
init_antigravity_token();
|
|
47771
48589
|
init_oauth_registry();
|
|
47772
48590
|
init_api_key_credential();
|
|
47773
48591
|
init_authority();
|
|
@@ -47815,7 +48633,7 @@ function providerAuthCapabilities(p, config3) {
|
|
|
47815
48633
|
const apiKeySupported = !!p.apiKeyEnvVar;
|
|
47816
48634
|
const apiKeySet = apiKeySupported && (!!process.env[p.apiKeyEnvVar] || !!config3.apiKeys?.[p.apiKeyEnvVar]);
|
|
47817
48635
|
const oauthSupported = !!p.oauthSlug;
|
|
47818
|
-
const oauthSet = oauthSupported && hasOAuthCredentials(p.catalogName);
|
|
48636
|
+
const oauthSet = oauthSupported && (hasOAuthCredentials(p.catalogName) || p.catalogName === "antigravity" && hasSharedAntigravityToken());
|
|
47819
48637
|
return {
|
|
47820
48638
|
apiKey: { supported: apiKeySupported, set: apiKeySet },
|
|
47821
48639
|
oauth: { supported: oauthSupported, set: oauthSet }
|
|
@@ -47831,6 +48649,7 @@ function maskKey2(key) {
|
|
|
47831
48649
|
var SKIP, PROVIDERS;
|
|
47832
48650
|
var init_providers = __esm(() => {
|
|
47833
48651
|
init_source();
|
|
48652
|
+
init_antigravity_token();
|
|
47834
48653
|
init_oauth_registry();
|
|
47835
48654
|
init_provider_definitions();
|
|
47836
48655
|
SKIP = new Set(["qwen", "native-anthropic"]);
|
|
@@ -59145,7 +59964,7 @@ import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
|
|
|
59145
59964
|
import { readFileSync as readFileSync20, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
|
|
59146
59965
|
import path from "path";
|
|
59147
59966
|
import os from "os";
|
|
59148
|
-
import { randomUUID as
|
|
59967
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
59149
59968
|
function editAsync(text = "", callback, fileOptions) {
|
|
59150
59969
|
const editor = new ExternalEditor(text, fileOptions);
|
|
59151
59970
|
editor.runAsync((err, result) => {
|
|
@@ -59237,7 +60056,7 @@ class ExternalEditor {
|
|
|
59237
60056
|
createTemporaryFile() {
|
|
59238
60057
|
try {
|
|
59239
60058
|
const baseDir = this.fileOptions.dir ?? os.tmpdir();
|
|
59240
|
-
const id =
|
|
60059
|
+
const id = randomUUID6();
|
|
59241
60060
|
const prefix = sanitizeAffix(this.fileOptions.prefix);
|
|
59242
60061
|
const postfix = sanitizeAffix(this.fileOptions.postfix);
|
|
59243
60062
|
const filename = `${prefix}${id}${postfix}`;
|
|
@@ -60413,13 +61232,14 @@ async function geminiQuotaHandler() {
|
|
|
60413
61232
|
}
|
|
60414
61233
|
console.log("");
|
|
60415
61234
|
}
|
|
61235
|
+
const fallbackChain = quota.buckets.map((b) => b.modelId).filter((m) => typeof m === "string" && m.length > 0).sort((a, b) => rankCodeAssistModel(a) - rankCodeAssistModel(b));
|
|
60416
61236
|
console.log(` ${B}${CYN}Fallback Chain${R} ${D}(on capacity exhaustion)${R}`);
|
|
60417
|
-
for (let i = 0;i <
|
|
60418
|
-
const model =
|
|
61237
|
+
for (let i = 0;i < fallbackChain.length; i++) {
|
|
61238
|
+
const model = fallbackChain[i];
|
|
60419
61239
|
const rem = remainingByModel.get(model);
|
|
60420
61240
|
const pct = rem !== undefined ? `${((1 - rem) * 100).toFixed(0)}%` : "?";
|
|
60421
61241
|
const color = rem === undefined ? GRY : rem > 0.5 ? GRN : rem > 0.2 ? YEL : RED;
|
|
60422
|
-
const arrow = i <
|
|
61242
|
+
const arrow = i < fallbackChain.length - 1 ? ` ${GRY}\u2192${R}` : "";
|
|
60423
61243
|
const marker = i === 0 ? `${CYN}\u25B8${R} ` : " ";
|
|
60424
61244
|
console.log(` ${marker}${WHT}${model}${R} ${color}${pct}${R}${arrow}`);
|
|
60425
61245
|
}
|
|
@@ -60453,11 +61273,11 @@ async function geminiQuotaHandler() {
|
|
|
60453
61273
|
}
|
|
60454
61274
|
}
|
|
60455
61275
|
async function codexQuotaHandler() {
|
|
60456
|
-
const { readFileSync: readFileSync21, existsSync:
|
|
60457
|
-
const { join:
|
|
60458
|
-
const { homedir:
|
|
60459
|
-
const credPath =
|
|
60460
|
-
if (!
|
|
61276
|
+
const { readFileSync: readFileSync21, existsSync: existsSync22 } = await import("fs");
|
|
61277
|
+
const { join: join28 } = await import("path");
|
|
61278
|
+
const { homedir: homedir26 } = await import("os");
|
|
61279
|
+
const credPath = join28(homedir26(), ".claudish", "codex-oauth.json");
|
|
61280
|
+
if (!existsSync22(credPath)) {
|
|
60461
61281
|
console.error(`${RED}No Codex credentials found.${R} Run: ${B}claudish login codex${R}`);
|
|
60462
61282
|
process.exit(1);
|
|
60463
61283
|
}
|
|
@@ -60513,8 +61333,8 @@ async function codexQuotaHandler() {
|
|
|
60513
61333
|
}
|
|
60514
61334
|
let modelSlugs = [];
|
|
60515
61335
|
try {
|
|
60516
|
-
const modelsPath =
|
|
60517
|
-
if (
|
|
61336
|
+
const modelsPath = join28(homedir26(), ".codex", "models_cache.json");
|
|
61337
|
+
if (existsSync22(modelsPath)) {
|
|
60518
61338
|
const cache2 = JSON.parse(readFileSync21(modelsPath, "utf-8"));
|
|
60519
61339
|
modelSlugs = (cache2.models || []).map((m) => m.slug || m.id).filter(Boolean);
|
|
60520
61340
|
}
|
|
@@ -64485,22 +65305,22 @@ __export(exports_cli, {
|
|
|
64485
65305
|
});
|
|
64486
65306
|
import {
|
|
64487
65307
|
copyFileSync as copyFileSync2,
|
|
64488
|
-
existsSync as
|
|
65308
|
+
existsSync as existsSync22,
|
|
64489
65309
|
mkdirSync as mkdirSync13,
|
|
64490
65310
|
readFileSync as readFileSync21,
|
|
64491
65311
|
readdirSync as readdirSync5,
|
|
64492
65312
|
unlinkSync as unlinkSync7,
|
|
64493
65313
|
writeFileSync as writeFileSync15
|
|
64494
65314
|
} from "fs";
|
|
64495
|
-
import { homedir as
|
|
64496
|
-
import { dirname as dirname9, join as
|
|
65315
|
+
import { homedir as homedir26 } from "os";
|
|
65316
|
+
import { dirname as dirname9, join as join28 } from "path";
|
|
64497
65317
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
64498
65318
|
function getVersion3() {
|
|
64499
65319
|
return VERSION;
|
|
64500
65320
|
}
|
|
64501
65321
|
function clearAllModelCaches() {
|
|
64502
|
-
const cacheDir =
|
|
64503
|
-
if (!
|
|
65322
|
+
const cacheDir = join28(homedir26(), ".claudish");
|
|
65323
|
+
if (!existsSync22(cacheDir))
|
|
64504
65324
|
return;
|
|
64505
65325
|
const cachePatterns = ["pricing-cache.json", "recommended-models-cache.json"];
|
|
64506
65326
|
let cleared = 0;
|
|
@@ -64508,7 +65328,7 @@ function clearAllModelCaches() {
|
|
|
64508
65328
|
const files = readdirSync5(cacheDir);
|
|
64509
65329
|
for (const file2 of files) {
|
|
64510
65330
|
if (cachePatterns.includes(file2)) {
|
|
64511
|
-
unlinkSync7(
|
|
65331
|
+
unlinkSync7(join28(cacheDir, file2));
|
|
64512
65332
|
cleared++;
|
|
64513
65333
|
}
|
|
64514
65334
|
}
|
|
@@ -64918,8 +65738,8 @@ Usage: claudish --models --provider <slug>`);
|
|
|
64918
65738
|
});
|
|
64919
65739
|
config3.resolvedDefaultProvider = resolved;
|
|
64920
65740
|
if (resolved.legacyAutoPromoted && !config3.quiet) {
|
|
64921
|
-
const markerFile =
|
|
64922
|
-
if (!
|
|
65741
|
+
const markerFile = join28(homedir26(), ".claudish", ".legacy-litellm-hint-shown");
|
|
65742
|
+
if (!existsSync22(markerFile)) {
|
|
64923
65743
|
const hint = buildLegacyHint(resolved);
|
|
64924
65744
|
if (hint) {
|
|
64925
65745
|
console.error(hint);
|
|
@@ -65986,7 +66806,7 @@ ${h("MORE INFO")}
|
|
|
65986
66806
|
}
|
|
65987
66807
|
function printAIAgentGuide() {
|
|
65988
66808
|
try {
|
|
65989
|
-
const guidePath =
|
|
66809
|
+
const guidePath = join28(__dirname3, "../AI_AGENT_GUIDE.md");
|
|
65990
66810
|
const guideContent = readFileSync21(guidePath, "utf-8");
|
|
65991
66811
|
console.log(guideContent);
|
|
65992
66812
|
} catch (error46) {
|
|
@@ -66003,19 +66823,19 @@ async function initializeClaudishSkill() {
|
|
|
66003
66823
|
console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
|
|
66004
66824
|
`);
|
|
66005
66825
|
const cwd = process.cwd();
|
|
66006
|
-
const claudeDir =
|
|
66007
|
-
const skillsDir =
|
|
66008
|
-
const claudishSkillDir =
|
|
66009
|
-
const skillFile =
|
|
66010
|
-
if (
|
|
66826
|
+
const claudeDir = join28(cwd, ".claude");
|
|
66827
|
+
const skillsDir = join28(claudeDir, "skills");
|
|
66828
|
+
const claudishSkillDir = join28(skillsDir, "claudish-usage");
|
|
66829
|
+
const skillFile = join28(claudishSkillDir, "SKILL.md");
|
|
66830
|
+
if (existsSync22(skillFile)) {
|
|
66011
66831
|
console.log("\u2705 Claudish skill already installed at:");
|
|
66012
66832
|
console.log(` ${skillFile}
|
|
66013
66833
|
`);
|
|
66014
66834
|
console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
|
|
66015
66835
|
return;
|
|
66016
66836
|
}
|
|
66017
|
-
const sourceSkillPath =
|
|
66018
|
-
if (!
|
|
66837
|
+
const sourceSkillPath = join28(__dirname3, "../skills/claudish-usage/SKILL.md");
|
|
66838
|
+
if (!existsSync22(sourceSkillPath)) {
|
|
66019
66839
|
console.error("\u274C Error: Claudish skill file not found in installation.");
|
|
66020
66840
|
console.error(` Expected at: ${sourceSkillPath}`);
|
|
66021
66841
|
console.error(`
|
|
@@ -66024,15 +66844,15 @@ async function initializeClaudishSkill() {
|
|
|
66024
66844
|
process.exit(1);
|
|
66025
66845
|
}
|
|
66026
66846
|
try {
|
|
66027
|
-
if (!
|
|
66847
|
+
if (!existsSync22(claudeDir)) {
|
|
66028
66848
|
mkdirSync13(claudeDir, { recursive: true });
|
|
66029
66849
|
console.log("\uD83D\uDCC1 Created .claude/ directory");
|
|
66030
66850
|
}
|
|
66031
|
-
if (!
|
|
66851
|
+
if (!existsSync22(skillsDir)) {
|
|
66032
66852
|
mkdirSync13(skillsDir, { recursive: true });
|
|
66033
66853
|
console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
|
|
66034
66854
|
}
|
|
66035
|
-
if (!
|
|
66855
|
+
if (!existsSync22(claudishSkillDir)) {
|
|
66036
66856
|
mkdirSync13(claudishSkillDir, { recursive: true });
|
|
66037
66857
|
console.log("\uD83D\uDCC1 Created .claude/skills/claudish-usage/ directory");
|
|
66038
66858
|
}
|
|
@@ -66117,30 +66937,30 @@ __export(exports_update_checker, {
|
|
|
66117
66937
|
clearCache: () => clearCache,
|
|
66118
66938
|
checkForUpdates: () => checkForUpdates
|
|
66119
66939
|
});
|
|
66120
|
-
import { existsSync as
|
|
66121
|
-
import { homedir as
|
|
66122
|
-
import { join as
|
|
66940
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync14, readFileSync as readFileSync22, unlinkSync as unlinkSync8, writeFileSync as writeFileSync16 } from "fs";
|
|
66941
|
+
import { homedir as homedir27, platform as platform2, tmpdir } from "os";
|
|
66942
|
+
import { join as join29 } from "path";
|
|
66123
66943
|
function getCacheFilePath() {
|
|
66124
66944
|
let cacheDir;
|
|
66125
66945
|
if (isWindows) {
|
|
66126
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
66127
|
-
cacheDir =
|
|
66946
|
+
const localAppData = process.env.LOCALAPPDATA || join29(homedir27(), "AppData", "Local");
|
|
66947
|
+
cacheDir = join29(localAppData, "claudish");
|
|
66128
66948
|
} else {
|
|
66129
|
-
cacheDir =
|
|
66949
|
+
cacheDir = join29(homedir27(), ".cache", "claudish");
|
|
66130
66950
|
}
|
|
66131
66951
|
try {
|
|
66132
|
-
if (!
|
|
66952
|
+
if (!existsSync23(cacheDir)) {
|
|
66133
66953
|
mkdirSync14(cacheDir, { recursive: true });
|
|
66134
66954
|
}
|
|
66135
|
-
return
|
|
66955
|
+
return join29(cacheDir, "update-check.json");
|
|
66136
66956
|
} catch {
|
|
66137
|
-
return
|
|
66957
|
+
return join29(tmpdir(), "claudish-update-check.json");
|
|
66138
66958
|
}
|
|
66139
66959
|
}
|
|
66140
66960
|
function readCache() {
|
|
66141
66961
|
try {
|
|
66142
66962
|
const cachePath = getCacheFilePath();
|
|
66143
|
-
if (!
|
|
66963
|
+
if (!existsSync23(cachePath)) {
|
|
66144
66964
|
return null;
|
|
66145
66965
|
}
|
|
66146
66966
|
const data = JSON.parse(readFileSync22(cachePath, "utf-8"));
|
|
@@ -66166,7 +66986,7 @@ function isCacheValid(cache2) {
|
|
|
66166
66986
|
function clearCache() {
|
|
66167
66987
|
try {
|
|
66168
66988
|
const cachePath = getCacheFilePath();
|
|
66169
|
-
if (
|
|
66989
|
+
if (existsSync23(cachePath)) {
|
|
66170
66990
|
unlinkSync8(cachePath);
|
|
66171
66991
|
}
|
|
66172
66992
|
} catch {}
|
|
@@ -67051,11 +67871,11 @@ var init_local_liveness = __esm(() => {
|
|
|
67051
67871
|
});
|
|
67052
67872
|
|
|
67053
67873
|
// src/providers/probe-catalog.ts
|
|
67054
|
-
import { existsSync as
|
|
67055
|
-
import { homedir as
|
|
67056
|
-
import { dirname as dirname10, join as
|
|
67874
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync15, readFileSync as readFileSync23, writeFileSync as writeFileSync17 } from "fs";
|
|
67875
|
+
import { homedir as homedir28 } from "os";
|
|
67876
|
+
import { dirname as dirname10, join as join30 } from "path";
|
|
67057
67877
|
function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
|
|
67058
|
-
if (!
|
|
67878
|
+
if (!existsSync24(path2))
|
|
67059
67879
|
return null;
|
|
67060
67880
|
let raw2;
|
|
67061
67881
|
try {
|
|
@@ -67188,7 +68008,7 @@ function isValidResponse(raw2) {
|
|
|
67188
68008
|
var PROBE_MODELS_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/probeModels", CACHE_TTL_MS4, FETCH_TIMEOUT_MS3 = 15000, PROBE_MODELS_CACHE_PATH, _inFlight = null;
|
|
67189
68009
|
var init_probe_catalog = __esm(() => {
|
|
67190
68010
|
CACHE_TTL_MS4 = 60 * 60 * 1000;
|
|
67191
|
-
PROBE_MODELS_CACHE_PATH =
|
|
68011
|
+
PROBE_MODELS_CACHE_PATH = join30(homedir28(), ".claudish", "probe-models.json");
|
|
67192
68012
|
});
|
|
67193
68013
|
|
|
67194
68014
|
// src/tui/constants.ts
|
|
@@ -73525,15 +74345,15 @@ __export(exports_claude_runner, {
|
|
|
73525
74345
|
import { spawn as spawn4 } from "child_process";
|
|
73526
74346
|
import {
|
|
73527
74347
|
closeSync as closeSync5,
|
|
73528
|
-
existsSync as
|
|
74348
|
+
existsSync as existsSync25,
|
|
73529
74349
|
mkdirSync as mkdirSync16,
|
|
73530
74350
|
openSync as openSync5,
|
|
73531
74351
|
readFileSync as readFileSync24,
|
|
73532
74352
|
unlinkSync as unlinkSync9,
|
|
73533
74353
|
writeFileSync as writeFileSync18
|
|
73534
74354
|
} from "fs";
|
|
73535
|
-
import { homedir as
|
|
73536
|
-
import { join as
|
|
74355
|
+
import { homedir as homedir29, tmpdir as tmpdir2 } from "os";
|
|
74356
|
+
import { join as join31 } from "path";
|
|
73537
74357
|
import { isatty } from "tty";
|
|
73538
74358
|
function releaseTerminalIsolation() {
|
|
73539
74359
|
if (!restoreTerminal)
|
|
@@ -73568,7 +74388,7 @@ function isProxyAuthMode(config3) {
|
|
|
73568
74388
|
}
|
|
73569
74389
|
function managedSettingsPath() {
|
|
73570
74390
|
if (isWindows2()) {
|
|
73571
|
-
return
|
|
74391
|
+
return join31(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
|
|
73572
74392
|
}
|
|
73573
74393
|
if (process.platform === "darwin") {
|
|
73574
74394
|
return "/Library/Application Support/ClaudeCode/managed-settings.json";
|
|
@@ -73589,9 +74409,9 @@ function isWindows2() {
|
|
|
73589
74409
|
}
|
|
73590
74410
|
function createStatusLineScript(tokenFilePath) {
|
|
73591
74411
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
|
|
73592
|
-
const claudishDir =
|
|
74412
|
+
const claudishDir = join31(homeDir, ".claudish");
|
|
73593
74413
|
const timestamp = Date.now();
|
|
73594
|
-
const scriptPath =
|
|
74414
|
+
const scriptPath = join31(claudishDir, `status-${timestamp}.js`);
|
|
73595
74415
|
const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
|
|
73596
74416
|
const script = `
|
|
73597
74417
|
const fs = require('fs');
|
|
@@ -73714,13 +74534,13 @@ process.stdin.on('end', () => {
|
|
|
73714
74534
|
}
|
|
73715
74535
|
function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
|
|
73716
74536
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
|
|
73717
|
-
const claudishDir =
|
|
74537
|
+
const claudishDir = join31(homeDir, ".claudish");
|
|
73718
74538
|
try {
|
|
73719
74539
|
mkdirSync16(claudishDir, { recursive: true });
|
|
73720
74540
|
} catch {}
|
|
73721
74541
|
const timestamp = Date.now();
|
|
73722
|
-
const tempPath =
|
|
73723
|
-
const tokenFilePath =
|
|
74542
|
+
const tempPath = join31(claudishDir, `settings-${timestamp}.json`);
|
|
74543
|
+
const tokenFilePath = join31(claudishDir, `tokens-${port}.json`);
|
|
73724
74544
|
let statusCommand;
|
|
73725
74545
|
if (isWindows2()) {
|
|
73726
74546
|
const scriptPath = createStatusLineScript(tokenFilePath);
|
|
@@ -73935,8 +74755,8 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
|
|
|
73935
74755
|
console.error("Install it from: https://claude.com/claude-code");
|
|
73936
74756
|
console.error(`
|
|
73937
74757
|
Or set CLAUDE_PATH to your custom installation:`);
|
|
73938
|
-
const home =
|
|
73939
|
-
const localPath = isWindows2() ?
|
|
74758
|
+
const home = homedir29();
|
|
74759
|
+
const localPath = isWindows2() ? join31(home, ".claude", "local", "claude.exe") : join31(home, ".claude", "local", "claude");
|
|
73940
74760
|
console.error(` export CLAUDE_PATH=${localPath}`);
|
|
73941
74761
|
process.exit(1);
|
|
73942
74762
|
}
|
|
@@ -74016,23 +74836,23 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
|
|
|
74016
74836
|
async function findClaudeBinary() {
|
|
74017
74837
|
const isWindows3 = process.platform === "win32";
|
|
74018
74838
|
if (process.env.CLAUDE_PATH) {
|
|
74019
|
-
if (
|
|
74839
|
+
if (existsSync25(process.env.CLAUDE_PATH)) {
|
|
74020
74840
|
return process.env.CLAUDE_PATH;
|
|
74021
74841
|
}
|
|
74022
74842
|
}
|
|
74023
|
-
const home =
|
|
74024
|
-
const localPath = isWindows3 ?
|
|
74025
|
-
if (
|
|
74843
|
+
const home = homedir29();
|
|
74844
|
+
const localPath = isWindows3 ? join31(home, ".claude", "local", "claude.exe") : join31(home, ".claude", "local", "claude");
|
|
74845
|
+
if (existsSync25(localPath)) {
|
|
74026
74846
|
return localPath;
|
|
74027
74847
|
}
|
|
74028
74848
|
if (isWindows3) {
|
|
74029
74849
|
const windowsPaths = [
|
|
74030
|
-
|
|
74031
|
-
|
|
74032
|
-
|
|
74850
|
+
join31(home, "AppData", "Roaming", "npm", "claude.cmd"),
|
|
74851
|
+
join31(home, ".npm-global", "claude.cmd"),
|
|
74852
|
+
join31(home, "node_modules", ".bin", "claude.cmd")
|
|
74033
74853
|
];
|
|
74034
74854
|
for (const path2 of windowsPaths) {
|
|
74035
|
-
if (
|
|
74855
|
+
if (existsSync25(path2)) {
|
|
74036
74856
|
return path2;
|
|
74037
74857
|
}
|
|
74038
74858
|
}
|
|
@@ -74040,14 +74860,14 @@ async function findClaudeBinary() {
|
|
|
74040
74860
|
const commonPaths = [
|
|
74041
74861
|
"/usr/local/bin/claude",
|
|
74042
74862
|
"/opt/homebrew/bin/claude",
|
|
74043
|
-
|
|
74044
|
-
|
|
74045
|
-
|
|
74863
|
+
join31(home, ".npm-global/bin/claude"),
|
|
74864
|
+
join31(home, ".local/bin/claude"),
|
|
74865
|
+
join31(home, "node_modules/.bin/claude"),
|
|
74046
74866
|
"/data/data/com.termux/files/usr/bin/claude",
|
|
74047
|
-
|
|
74867
|
+
join31(home, "../usr/bin/claude")
|
|
74048
74868
|
];
|
|
74049
74869
|
for (const path2 of commonPaths) {
|
|
74050
|
-
if (
|
|
74870
|
+
if (existsSync25(path2)) {
|
|
74051
74871
|
return path2;
|
|
74052
74872
|
}
|
|
74053
74873
|
}
|
|
@@ -74105,17 +74925,17 @@ __export(exports_diag_output, {
|
|
|
74105
74925
|
LogFileDiagOutput: () => LogFileDiagOutput
|
|
74106
74926
|
});
|
|
74107
74927
|
import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync17, unlinkSync as unlinkSync10, writeFileSync as writeFileSync19 } from "fs";
|
|
74108
|
-
import { homedir as
|
|
74109
|
-
import { join as
|
|
74928
|
+
import { homedir as homedir30 } from "os";
|
|
74929
|
+
import { join as join32 } from "path";
|
|
74110
74930
|
function getClaudishDir() {
|
|
74111
|
-
const dir =
|
|
74931
|
+
const dir = join32(homedir30(), ".claudish");
|
|
74112
74932
|
try {
|
|
74113
74933
|
mkdirSync17(dir, { recursive: true });
|
|
74114
74934
|
} catch {}
|
|
74115
74935
|
return dir;
|
|
74116
74936
|
}
|
|
74117
74937
|
function getDiagLogPath() {
|
|
74118
|
-
return
|
|
74938
|
+
return join32(getClaudishDir(), `diag-${process.pid}.log`);
|
|
74119
74939
|
}
|
|
74120
74940
|
|
|
74121
74941
|
class LogFileDiagOutput {
|
|
@@ -74326,9 +75146,9 @@ __export(exports_team_grid, {
|
|
|
74326
75146
|
});
|
|
74327
75147
|
import { spawn as spawn5 } from "child_process";
|
|
74328
75148
|
import { execSync as execSync2 } from "child_process";
|
|
74329
|
-
import { existsSync as
|
|
75149
|
+
import { existsSync as existsSync26, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
|
|
74330
75150
|
import { connect as netConnect } from "net";
|
|
74331
|
-
import { dirname as dirname11, join as
|
|
75151
|
+
import { dirname as dirname11, join as join33 } from "path";
|
|
74332
75152
|
import { setTimeout as wait } from "timers/promises";
|
|
74333
75153
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
74334
75154
|
function resolveRouteInfo(modelId) {
|
|
@@ -74422,18 +75242,18 @@ function buildPaneHeader(model, prompt, bg) {
|
|
|
74422
75242
|
function findMagmuxBinary() {
|
|
74423
75243
|
const thisFile = fileURLToPath3(import.meta.url);
|
|
74424
75244
|
const thisDir = dirname11(thisFile);
|
|
74425
|
-
const pkgRoot =
|
|
75245
|
+
const pkgRoot = join33(thisDir, "..");
|
|
74426
75246
|
const platform3 = process.platform;
|
|
74427
75247
|
const arch = process.arch;
|
|
74428
|
-
const bundledMagmux =
|
|
74429
|
-
if (
|
|
75248
|
+
const bundledMagmux = join33(pkgRoot, "native", `magmux-${platform3}-${arch}`);
|
|
75249
|
+
if (existsSync26(bundledMagmux))
|
|
74430
75250
|
return bundledMagmux;
|
|
74431
75251
|
try {
|
|
74432
75252
|
const pkgName = `@claudish/magmux-${platform3}-${arch}`;
|
|
74433
75253
|
let searchDir = pkgRoot;
|
|
74434
75254
|
for (let i = 0;i < 5; i++) {
|
|
74435
|
-
const candidate =
|
|
74436
|
-
if (
|
|
75255
|
+
const candidate = join33(searchDir, "node_modules", pkgName, "bin", "magmux");
|
|
75256
|
+
if (existsSync26(candidate))
|
|
74437
75257
|
return candidate;
|
|
74438
75258
|
const parent = dirname11(searchDir);
|
|
74439
75259
|
if (parent === searchDir)
|
|
@@ -74452,7 +75272,7 @@ function findMagmuxBinary() {
|
|
|
74452
75272
|
async function subscribeToMagmux(sockPath, onEvent) {
|
|
74453
75273
|
let client = null;
|
|
74454
75274
|
for (let attempt = 0;attempt < 40; attempt++) {
|
|
74455
|
-
if (
|
|
75275
|
+
if (existsSync26(sockPath)) {
|
|
74456
75276
|
try {
|
|
74457
75277
|
client = await new Promise((resolve4, reject) => {
|
|
74458
75278
|
const s = netConnect(sockPath);
|
|
@@ -74539,9 +75359,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
|
|
|
74539
75359
|
const keep = opts?.keep ?? false;
|
|
74540
75360
|
const manifest = setupSession(sessionPath, models, input);
|
|
74541
75361
|
const startedAt = new Date().toISOString();
|
|
74542
|
-
const gridfilePath =
|
|
74543
|
-
const prompt = readFileSync25(
|
|
74544
|
-
const rawPrompt = readFileSync25(
|
|
75362
|
+
const gridfilePath = join33(sessionPath, "gridfile.txt");
|
|
75363
|
+
const prompt = readFileSync25(join33(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
|
|
75364
|
+
const rawPrompt = readFileSync25(join33(sessionPath, "input.md"), "utf-8");
|
|
74545
75365
|
const usedBannerColors = new Set;
|
|
74546
75366
|
const gridLines = Object.entries(manifest.models).map(([anonId]) => {
|
|
74547
75367
|
const model = manifest.models[anonId].model;
|
|
@@ -74572,7 +75392,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
|
|
|
74572
75392
|
});
|
|
74573
75393
|
const [{ results }] = await Promise.all([subscription, procExit]);
|
|
74574
75394
|
const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
|
|
74575
|
-
const statusPath =
|
|
75395
|
+
const statusPath = join33(sessionPath, "status.json");
|
|
74576
75396
|
writeFileSync20(statusPath, JSON.stringify(status, null, 2), "utf-8");
|
|
74577
75397
|
return status;
|
|
74578
75398
|
}
|
|
@@ -74596,8 +75416,8 @@ var init_team_grid = __esm(() => {
|
|
|
74596
75416
|
init_op_source();
|
|
74597
75417
|
init_startup_trace();
|
|
74598
75418
|
var import_dotenv3 = __toESM(require_main(), 1);
|
|
74599
|
-
import { existsSync as
|
|
74600
|
-
import { join as
|
|
75419
|
+
import { existsSync as existsSync27, readFileSync as readFileSync26 } from "fs";
|
|
75420
|
+
import { join as join34, resolve as resolve4 } from "path";
|
|
74601
75421
|
import_dotenv3.config({ quiet: true });
|
|
74602
75422
|
function classifyStartupKind() {
|
|
74603
75423
|
const argv = process.argv.slice(2);
|
|
@@ -74696,7 +75516,7 @@ async function applyConfigOverride() {
|
|
|
74696
75516
|
const { planConfigOverride: planConfigOverride2, setConfigFileOverride: setConfigFileOverride2 } = await Promise.resolve().then(() => exports_config_override);
|
|
74697
75517
|
const plan = planConfigOverride2(process.argv.slice(2), process.env, {
|
|
74698
75518
|
resolve: resolve4,
|
|
74699
|
-
exists:
|
|
75519
|
+
exists: existsSync27
|
|
74700
75520
|
});
|
|
74701
75521
|
if (plan.kind === "none")
|
|
74702
75522
|
return;
|
|
@@ -74845,7 +75665,7 @@ async function runCli() {
|
|
|
74845
75665
|
process.exit(1);
|
|
74846
75666
|
}
|
|
74847
75667
|
const mode = cliConfig.teamMode ?? "default";
|
|
74848
|
-
const sessionPath =
|
|
75668
|
+
const sessionPath = join34(process.cwd(), `.claudish-team-${Date.now()}`);
|
|
74849
75669
|
if (mode === "json") {
|
|
74850
75670
|
const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
|
|
74851
75671
|
setupSession2(sessionPath, cliConfig.team, prompt);
|
|
@@ -74855,7 +75675,7 @@ async function runCli() {
|
|
|
74855
75675
|
});
|
|
74856
75676
|
const result = { ...status2, responses: {} };
|
|
74857
75677
|
for (const anonId of Object.keys(status2.models)) {
|
|
74858
|
-
const responsePath =
|
|
75678
|
+
const responsePath = join34(sessionPath, `response-${anonId}.md`);
|
|
74859
75679
|
try {
|
|
74860
75680
|
const raw2 = readFileSync26(responsePath, "utf-8").trim();
|
|
74861
75681
|
try {
|