claudish 7.29.0 → 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.
Files changed (2) hide show
  1. package/dist/index.js +1783 -956
  2. 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.29.0";
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: ["go"],
27718
- shortestPrefix: "go",
27719
- legacyPrefixes: [{ prefix: "go/", stripPrefix: true }],
27737
+ shortcuts: [],
27738
+ shortestPrefix: "gemini-codeassist",
27739
+ legacyPrefixes: [],
27720
27740
  isDirectApi: true,
27721
- description: "Gemini Code Assist OAuth (go@)"
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/credentials/api-key-credential.ts
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 realValue(v) {
28239
- if (!v)
28240
- return;
28241
- return UNEXPANDED_PLACEHOLDER.test(v.trim()) ? undefined : v;
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
- class ApiKeyCredentialProvider {
28245
- catalogName;
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
- resolveFromEnvConfig() {
28266
- return realValue(process.env[this.envVar]) || this.aliases.map((a) => realValue(process.env[a])).find((v) => !!v) || realValue(getApiKey(this.envVar)) || realValue(this.resolveDeclared());
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
- resolveDeclared() {
28269
- try {
28270
- return this.declaredKey?.() || undefined;
28271
- } catch {
28272
- return;
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
- hasOauthFallbackFile() {
28276
- if (!this.oauthFallback)
28277
- return false;
28278
- try {
28279
- return existsSync6(join8(homedir8(), ".claudish", this.oauthFallback));
28280
- } catch {
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
- async resolveKey(opts) {
28285
- if (this.cachedKey !== undefined)
28286
- return this.cachedKey;
28287
- if (this.resolving)
28288
- return this.resolving;
28289
- this.resolving = (async () => {
28290
- const local = this.resolveFromEnvConfig();
28291
- if (local) {
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
- async isAvailable(opts) {
28319
- if (this.publicKeyFallback)
28320
- return true;
28321
- if (this.resolveFromEnvConfig())
28322
- return true;
28323
- if (this.hasOauthFallbackFile())
28324
- return true;
28325
- const key = await this.resolveKey(opts);
28326
- return !!key;
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
- invalidate() {
28329
- this.cachedKey = undefined;
28330
- this.resolving = undefined;
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
- async getRequestAuth(ctx) {
28333
- const key = await this.resolveKey({ allowOpPrompt: ctx.allowOpPrompt }) || this.publicKeyFallback || "";
28334
- let headers;
28335
- if (this.authScheme === "x-api-key") {
28336
- headers = { "x-api-key": key, ...this.staticHeaders };
28337
- } else if (key) {
28338
- headers = { Authorization: `Bearer ${key}`, ...this.staticHeaders };
28339
- } else {
28340
- headers = { ...this.staticHeaders };
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
- return { headers };
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
- var UNEXPANDED_PLACEHOLDER;
28346
- var init_api_key_credential = __esm(() => {
28347
- init_profile_config();
28348
- init_op_source();
28349
- UNEXPANDED_PLACEHOLDER = /^\$\{[^}]*\}$/;
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/codex-oauth.ts
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 CodexOAuth {
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 (!CodexOAuth.instance) {
28369
- CodexOAuth.instance = new CodexOAuth;
28461
+ if (!GeminiOAuth.instance) {
28462
+ GeminiOAuth.instance = new GeminiOAuth;
28370
28463
  }
28371
- return CodexOAuth.instance;
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, "codex-oauth.json");
28478
+ return join9(claudishDir, "gemini-oauth.json");
28386
28479
  }
28387
28480
  async login() {
28388
- log("[CodexOAuth] Starting OAuth login flow");
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("[CodexOAuth] Login successful");
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("[CodexOAuth] Credentials deleted");
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("[CodexOAuth] Waiting for in-progress refresh");
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 OpenAI Codex OAuth credentials found. Please run `claudish login codex` first.");
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().finally(() => {
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 OpenAI Codex OAuth credentials found. Please run `claudish login codex` first.");
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 OpenAI Codex OAuth credentials found. Please run `claudish login codex` first.");
28537
+ throw new Error("No Gemini OAuth credentials found. Please run `claudish login gemini` first.");
28450
28538
  }
28451
- log("[CodexOAuth] Refreshing access token");
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/json"
28544
+ "Content-Type": "application/x-www-form-urlencoded"
28457
28545
  },
28458
- body: JSON.stringify({
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(`[CodexOAuth] Token refreshed, valid until ${new Date(updatedCredentials.expires_at).toISOString()}`);
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(`[CodexOAuth] Refresh failed: ${e.message}`);
28482
- throw new Error(`OAuth credentials invalid. Please run \`claudish login codex\` again.
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("[CodexOAuth] Invalid credentials file structure");
28583
+ log("[GeminiOAuth] Invalid credentials file structure");
28497
28584
  return null;
28498
28585
  }
28499
- log("[CodexOAuth] Loaded credentials from file");
28586
+ log("[GeminiOAuth] Loaded credentials from file");
28500
28587
  return credentials;
28501
28588
  } catch (e) {
28502
- log(`[CodexOAuth] Failed to load credentials: ${e.message}`);
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(`[CodexOAuth] Credentials saved to ${credPath}`);
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 scope = OAUTH_CONFIG.scopes.join("+");
28549
- const params = [
28550
- "response_type=code",
28551
- `client_id=${encodeURIComponent(OAUTH_CONFIG.clientId)}`,
28552
- `redirect_uri=${encodeURIComponent(redirectUri)}`,
28553
- `scope=${scope}`,
28554
- `code_challenge=${encodeURIComponent(codeChallenge)}`,
28555
- "code_challenge_method=S256",
28556
- "id_token_add_organizations=true",
28557
- "codex_cli_simplified_flow=true",
28558
- `state=${encodeURIComponent(state)}`,
28559
- "originator=opencode"
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("/auth/callback", ""));
28568
- if (url2.pathname === "/auth/callback") {
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(1455, () => {
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}/auth/callback`;
28641
- log(`[CodexOAuth] Callback server started on http://localhost:${port}`);
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("[CodexOAuth] Exchanging auth code for tokens");
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 OpenAI OAuth: ${e.message}`);
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 OpenAI authentication...`);
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 getCodexOAuth() {
28707
- return CodexOAuth.getInstance();
28774
+ function reloadGeminiCredentials() {
28775
+ GeminiOAuth.getInstance().reloadCredentials();
28776
+ resetGeminiUserCache();
28708
28777
  }
28709
- var execAsync, OAUTH_CONFIG;
28710
- var init_codex_oauth = __esm(() => {
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: "app_EMoamEEZ73f0CkXaXp7hrann",
28715
- authUrl: "https://auth.openai.com/oauth/authorize",
28716
- tokenUrl: "https://auth.openai.com/oauth/token",
28717
- scopes: ["openid", "profile", "email", "offline_access"]
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/auth/credentials/composite-credential.ts
28722
- class CompositeCredentialProvider {
28723
- catalogName;
28724
- primary;
28725
- fallback;
28726
- opts;
28727
- constructor(catalogName, primary, fallback, opts = {}) {
28728
- this.catalogName = catalogName;
28729
- this.primary = primary;
28730
- this.fallback = fallback;
28731
- this.opts = opts;
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
- async isAvailable(opts) {
28734
- return await this.primary.isAvailable(opts) || await this.fallback.isAvailable(opts);
29136
+ static getInstance() {
29137
+ if (!GeminiRequestQueue.instance) {
29138
+ GeminiRequestQueue.instance = new GeminiRequestQueue;
29139
+ }
29140
+ return GeminiRequestQueue.instance;
28735
29141
  }
28736
- invalidate() {
28737
- this.primary.invalidate?.();
28738
- this.fallback.invalidate?.();
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 getRequestAuth(ctx) {
28741
- if (await this.primary.isAvailable({ allowOpPrompt: ctx.allowOpPrompt })) {
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
- return await this.primary.getRequestAuth(ctx);
28744
- } catch (e) {
28745
- const signal = this.opts.fallbackSignal;
28746
- if (signal && String(e?.message) === signal) {
28747
- return this.fallback.getRequestAuth(ctx);
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
- throw e;
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
- return this.fallback.getRequestAuth(ctx);
29191
+ this.processing = false;
29192
+ log("[GeminiQueue] Worker stopped (queue empty)");
28753
29193
  }
28754
- async login() {
28755
- await this.primary.login?.();
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
- async logout() {
28758
- await this.primary.logout?.();
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/auth/credentials/codex-credential.ts
28763
- function buildOAuthHeaders(token, accountId) {
28764
- const headers = {
28765
- Authorization: `Bearer ${token}`,
28766
- "OpenAI-Beta": "responses=experimental",
28767
- originator: "codex_cli_rs",
28768
- accept: "text/event-stream"
28769
- };
28770
- if (accountId) {
28771
- headers["chatgpt-account-id"] = accountId;
28772
- headers["x-conversation-id"] = "claudish-session";
28773
- headers["x-session-id"] = "claudish-session";
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
- return headers;
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 CodexOAuthHalf {
28779
- catalogName = "openai-codex";
28780
- oauth = CodexOAuth.getInstance();
28781
- async isAvailable() {
28782
- return this.oauth.hasCredentials();
29343
+ class AntigravityProviderTransport {
29344
+ name = "antigravity";
29345
+ _displayName = "Antigravity";
29346
+ get displayName() {
29347
+ return this._displayName;
28783
29348
  }
28784
- async getRequestAuth(_ctx) {
28785
- const token = await this.oauth.getAccessToken();
28786
- const accountId = this.oauth.getAccountId();
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
- headers: buildOAuthHeaders(token, accountId),
28789
- endpoint: CODEX_RESPONSES_ENDPOINT,
28790
- transformPayload: (p) => ({
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 login() {
28798
- await this.oauth.login();
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
- async logout() {
28801
- await this.oauth.logout();
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
- function makeCodexCredential() {
28805
- return new CompositeCredentialProvider("openai-codex", new CodexOAuthHalf, new ApiKeyCredentialProvider({
28806
- catalogName: "openai-codex",
28807
- envVar: "OPENAI_CODEX_API_KEY"
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
- var CODEX_RESPONSES_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
28811
- var init_codex_credential = __esm(() => {
28812
- init_codex_oauth();
28813
- init_api_key_credential();
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/gemini-oauth.ts
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 existsSync8, openSync as openSync3, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeSync as writeSync3 } from "fs";
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 homedir10 } from "os";
28822
- import { join as join10 } from "path";
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 GeminiOAuth {
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 (!GeminiOAuth.instance) {
28833
- GeminiOAuth.instance = new GeminiOAuth;
29770
+ if (!CodexOAuth.instance) {
29771
+ CodexOAuth.instance = new CodexOAuth;
28834
29772
  }
28835
- return GeminiOAuth.instance;
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 = join10(homedir10(), ".claudish");
28849
- return join10(claudishDir, "gemini-oauth.json");
29786
+ const claudishDir = join11(homedir11(), ".claudish");
29787
+ return join11(claudishDir, "codex-oauth.json");
28850
29788
  }
28851
29789
  async login() {
28852
- log("[GeminiOAuth] Starting OAuth login flow");
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 credentials = {
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(credentials);
28864
- this.credentials = credentials;
29803
+ this.saveCredentials(credentials2);
29804
+ this.credentials = credentials2;
28865
29805
  this.oauthState = null;
28866
- log("[GeminiOAuth] Login successful");
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 (existsSync8(credPath)) {
29813
+ if (existsSync9(credPath)) {
28871
29814
  unlinkSync3(credPath);
28872
- log("[GeminiOAuth] Credentials deleted");
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("[GeminiOAuth] Waiting for in-progress refresh");
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 Gemini OAuth credentials found. Please run `claudish login gemini` first.");
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 Gemini OAuth credentials found. Please run `claudish login gemini` first.");
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 Gemini OAuth credentials found. Please run `claudish login gemini` first.");
29851
+ throw new Error("No OpenAI Codex OAuth credentials found. Please run `claudish login codex` first.");
28909
29852
  }
28910
- log("[GeminiOAuth] Refreshing access token");
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/x-www-form-urlencoded"
29858
+ "Content-Type": "application/json"
28916
29859
  },
28917
- body: new URLSearchParams({
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(`[GeminiOAuth] Token refreshed, valid until ${new Date(updatedCredentials.expires_at).toISOString()}`);
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(`[GeminiOAuth] Refresh failed: ${e.message}`);
28940
- throw new Error(`OAuth credentials invalid. Please run \`claudish login gemini\` again.
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 (!existsSync8(credPath)) {
29891
+ if (!existsSync9(credPath)) {
28948
29892
  return null;
28949
29893
  }
28950
29894
  try {
28951
29895
  const data = readFileSync7(credPath, "utf-8");
28952
- const credentials = JSON.parse(data);
28953
- if (!credentials.access_token || !credentials.refresh_token || !credentials.expires_at) {
28954
- log("[GeminiOAuth] Invalid credentials file structure");
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("[GeminiOAuth] Loaded credentials from file");
28958
- return credentials;
29901
+ log("[CodexOAuth] Loaded credentials from file");
29902
+ return credentials2;
28959
29903
  } catch (e) {
28960
- log(`[GeminiOAuth] Failed to load credentials: ${e.message}`);
29904
+ log(`[CodexOAuth] Failed to load credentials: ${e.message}`);
28961
29905
  return null;
28962
29906
  }
28963
29907
  }
28964
- saveCredentials(credentials) {
29908
+ saveCredentials(credentials2) {
28965
29909
  const credPath = this.getCredentialsPath();
28966
- const claudishDir = join10(homedir10(), ".claudish");
28967
- if (!existsSync8(claudishDir)) {
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(credentials, null, 2);
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(`[GeminiOAuth] Credentials saved to ${credPath}`);
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 params = new URLSearchParams({
28989
- client_id: OAUTH_CONFIG2.clientId,
28990
- redirect_uri: redirectUri,
28991
- response_type: "code",
28992
- scope: OAUTH_CONFIG2.scopes.join(" "),
28993
- code_challenge: codeChallenge,
28994
- code_challenge_method: "S256",
28995
- access_type: "offline",
28996
- prompt: "consent",
28997
- state
28998
- });
28999
- return `${OAUTH_CONFIG2.authUrl}?${params.toString()}`;
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(0, () => {
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(`[GeminiOAuth] Callback server started on http://localhost:${port}`);
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("[GeminiOAuth] Exchanging auth code for tokens");
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 Google OAuth: ${e.message}`);
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 reloadGeminiCredentials() {
29146
- GeminiOAuth.getInstance().reloadCredentials();
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
- async function setupGeminiUser(accessToken) {
29169
- if (cachedProjectId && cachedTierId) {
29170
- log(`[GeminiOAuth] Using cached project ID: ${cachedProjectId}, tier: ${cachedTierId}`);
29171
- return { projectId: cachedProjectId, tierId: cachedTierId };
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
- const envProject = process.env.GOOGLE_CLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT_ID;
29174
- log("[GeminiOAuth] Calling loadCodeAssist...");
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
- const tierId = resolvedTier || loadRes.allowedTiers?.[0]?.id || "free-tier";
29189
- const isFree = tierId === "free-tier";
29190
- const onboardProject = isFree ? undefined : envProject;
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
- if (!lro.done) {
29203
- throw new Error(`Gemini onboarding timed out after ${MAX_POLL_ATTEMPTS * 2} seconds`);
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
- if (lro.error) {
29206
- throw new Error(`Gemini onboarding failed: ${JSON.stringify(lro.error)}`);
30156
+ async login() {
30157
+ await this.primary.login?.();
29207
30158
  }
29208
- const projectId = lro.response?.cloudaicompanionProject?.id;
29209
- if (!projectId) {
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
- async function callLoadCodeAssist(accessToken, projectId) {
29223
- const metadata = {
29224
- pluginType: "GEMINI",
29225
- ideType: "GEMINI_CLI",
29226
- platform: "PLATFORM_UNSPECIFIED",
29227
- duetProject: projectId
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
- const res = await fetch(`${CODE_ASSIST_API_BASE}:loadCodeAssist`, {
29230
- method: "POST",
29231
- headers: {
29232
- Authorization: `Bearer ${accessToken}`,
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 await res.json();
30177
+ return headers;
29241
30178
  }
29242
- async function callOnboardUser(accessToken, tierId, projectId) {
29243
- const metadata = {
29244
- pluginType: "GEMINI",
29245
- ideType: "GEMINI_CLI",
29246
- platform: "PLATFORM_UNSPECIFIED",
29247
- duetProject: projectId
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
- return await res.json();
29265
- }
29266
- async function retrieveUserQuota(accessToken, projectId) {
29267
- try {
29268
- const res = await fetch(`${CODE_ASSIST_API_BASE}:retrieveUserQuota`, {
29269
- method: "POST",
29270
- headers: {
29271
- Authorization: `Bearer ${accessToken}`,
29272
- "Content-Type": "application/json",
29273
- "User-Agent": `GeminiCLI/0.5.6/gemini-code-assist (${process.platform}; ${process.arch})`
29274
- },
29275
- body: JSON.stringify({ project: projectId })
29276
- });
29277
- if (!res.ok) {
29278
- log(`[GeminiOAuth] retrieveUserQuota failed: ${res.status}`);
29279
- return null;
29280
- }
29281
- return await res.json();
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
- var execAsync2, getDefaultClientId = () => {
29288
- const parts = [
29289
- "681255809395",
29290
- "oo8ft2oprdrnp9e3aqf6av3hmdib135j",
29291
- "apps",
29292
- "googleusercontent",
29293
- "com"
29294
- ];
29295
- return `${parts[0]}-${parts[1]}.${parts[2]}.${parts[3]}.${parts[4]}`;
29296
- }, getDefaultClientSecret = () => {
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 existsSync9, readFileSync as readFileSync8 } from "fs";
29331
- import { homedir as homedir11 } from "os";
29332
- import { join as join11 } from "path";
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 = join11(homedir11(), ".claudish", descriptor.credentialFile);
29335
- if (!existsSync9(credPath))
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 buildGeminiCliUserAgent(model) {
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": buildGeminiCliUserAgent(ctx.model),
29420
- "x-activity-request-id": createActivityRequestId()
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: randomUUID(),
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 existsSync10, openSync as openSync4, readFileSync as readFileSync9, unlinkSync as unlinkSync4, writeSync as writeSync4 } from "fs";
29452
- import { homedir as homedir12, hostname as hostname3, platform, release as release2 } from "os";
29453
- import { join as join12 } from "path";
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 = join12(homedir12(), ".claudish");
29482
- return join12(claudishDir, "kimi-oauth.json");
30365
+ const claudishDir = join13(homedir13(), ".claudish");
30366
+ return join13(claudishDir, "kimi-oauth.json");
29483
30367
  }
29484
30368
  getDeviceIdPath() {
29485
- const claudishDir = join12(homedir12(), ".claudish");
29486
- return join12(claudishDir, "kimi-device-id");
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 = join12(homedir12(), ".claudish");
29491
- if (!existsSync10(claudishDir)) {
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 (existsSync10(deviceIdPath)) {
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 credentials = {
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(credentials);
29555
- this.credentials = 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 (existsSync10(credPath)) {
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 (existsSync10(credPath)) {
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 (!existsSync10(credPath)) {
30636
+ if (!existsSync11(credPath)) {
29753
30637
  return null;
29754
30638
  }
29755
30639
  try {
29756
30640
  const data = readFileSync9(credPath, "utf-8");
29757
- const credentials = JSON.parse(data);
29758
- if (!credentials.access_token || !credentials.refresh_token || !credentials.expires_at || !credentials.scope || !credentials.token_type) {
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 credentials;
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(credentials) {
30653
+ saveCredentials(credentials2) {
29770
30654
  const credPath = this.getCredentialsPath();
29771
- const claudishDir = join12(homedir12(), ".claudish");
29772
- if (!existsSync10(claudishDir)) {
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(credentials, null, 2);
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 existsSync11 } from "fs";
29947
- import { homedir as homedir13 } from "os";
29948
- import { join as join13 } from "path";
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 = join13(homedir13(), ".config/gcloud/application_default_credentials.json");
30004
- if (!existsSync11(adcPath)) {
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 (!existsSync11(credPath)) {
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 = join13(homedir13(), ".config/gcloud/application_default_credentials.json");
30068
- const hasADC = existsSync11(adcPath);
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 existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
30616
- import { homedir as homedir14 } from "os";
30617
- import { dirname as dirname5, join as join14 } from "path";
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 (!existsSync12(path))
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 = join14(homedir14(), ".claudish", "all-models.json");
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 randomUUID2 } from "crypto";
32646
+ import { randomUUID as randomUUID4 } from "crypto";
31749
32647
  import { createWriteStream, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
31750
- import { homedir as homedir15 } from "os";
31751
- import { join as join15 } from "path";
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 = randomUUID2().slice(0, 8);
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 = join15(homedir15(), ".claudish", "sessions", sessionId);
32669
+ const sessionDir = join16(homedir16(), ".claudish", "sessions", sessionId);
31772
32670
  mkdirSync7(sessionDir, { recursive: true });
31773
32671
  if (opts.prompt) {
31774
- writeFileSync7(join15(sessionDir, "prompt.md"), opts.prompt, "utf-8");
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(join15(sessionDir, "output.log"));
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(join15(sessionDir, "stderr.log"), entry.stderr, "utf-8");
32746
+ writeFileSync7(join16(sessionDir, "stderr.log"), entry.stderr, "utf-8");
31849
32747
  }
31850
- writeFileSync7(join15(sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
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 existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
32024
- import { homedir as homedir16 } from "os";
32025
- import { join as join16 } from "path";
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 && existsSync13(RECOMMENDED_MODELS_CACHE_PATH)) {
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 = join16(homedir16(), ".claudish");
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 (existsSync13(RECOMMENDED_MODELS_CACHE_PATH)) {
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 = join16(homedir16(), ".claudish", "recommended-models-cache.json");
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 homedir17 } from "os";
37180
- import { dirname as dirname6, join as join17 } from "path";
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 join17(homedir17(), ".claudish", "behavior-journal.jsonl");
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 homedir18 } from "os";
37410
- import { join as join18 } from "path";
38307
+ import { homedir as homedir19 } from "os";
38308
+ import { join as join19 } from "path";
37411
38309
  function defaultPath() {
37412
- return join18(homedir18(), ".claudish", "behavior-divergences.jsonl");
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 homedir19 } from "os";
37834
- import { join as join19 } from "path";
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 = join19(root, project);
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(join19(dir, f));
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 ?? join19(homedir19(), ".claude", "projects");
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 ?? join19(homedir19(), ".claudish", "behavior-divergences.jsonl");
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 existsSync14,
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 homedir20 } from "os";
38551
- import { join as join20 } from "path";
39448
+ import { homedir as homedir21 } from "os";
39449
+ import { join as join21 } from "path";
38552
39450
  function ensureDir() {
38553
- if (!existsSync14(CLAUDISH_DIR)) {
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 (!existsSync14(BUFFER_FILE))
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 = join20(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
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 (existsSync14(BUFFER_FILE)) {
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 = join20(homedir20(), ".claudish");
38660
- BUFFER_FILE = join20(CLAUDISH_DIR, "stats-buffer.json");
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 homedir21 } from "os";
40942
- import { dirname as dirname7, join as join21 } from "path";
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 || join21(homedir21(), ".claudish", `tokens-${this.port}.json`);
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
  }
@@ -43033,38 +43934,32 @@ function extractModelIds(body) {
43033
43934
  }
43034
43935
  return [];
43035
43936
  }
43937
+ function orderByCost(models) {
43938
+ const sized = models.filter((m) => typeof m.size === "number");
43939
+ const unsized = models.filter((m) => typeof m.size !== "number");
43940
+ const bySize = [...sized].sort((a, b) => (a.size ?? Number.POSITIVE_INFINITY) - (b.size ?? Number.POSITIVE_INFINITY)).map((m) => m.name);
43941
+ return [...bySize, ...rankProbeCandidates(unsized.map((m) => m.name))];
43942
+ }
43036
43943
  async function discoverViaOllama(baseUrl, cacheKey) {
43037
43944
  const cached2 = cacheGet(cacheKey.key, cacheKey.exclude);
43038
43945
  if (cached2 !== undefined)
43039
43946
  return cached2;
43040
- let connectionError;
43041
- let loadedRaw = [];
43042
- try {
43043
- loadedRaw = await fetchOllamaModels2(`${baseUrl}/api/ps`);
43044
- } catch (e) {
43045
- connectionError = classifyFetchError(e, `${baseUrl}/api/ps`);
43046
- }
43047
- let allRaw = loadedRaw;
43048
- if (allRaw.length === 0) {
43049
- try {
43050
- allRaw = await fetchOllamaModels2(`${baseUrl}/api/tags`);
43051
- } catch (e) {
43052
- connectionError ??= classifyFetchError(e, `${baseUrl}/api/tags`);
43053
- }
43054
- }
43055
- const candidates = allRaw.filter((m) => isChatCapable(m.name));
43056
- if (candidates.length === 0) {
43057
- const reason = connectionError ?? (allRaw.length === 0 ? `no models on ${baseUrl} (pull one: ollama pull llama3.2)` : `only embedding/non-chat models on ${baseUrl}`);
43947
+ const [psResult, tagsResult] = await Promise.allSettled([
43948
+ fetchOllamaModels2(`${baseUrl}/api/ps`),
43949
+ fetchOllamaModels2(`${baseUrl}/api/tags`)
43950
+ ]);
43951
+ const loadedRaw = psResult.status === "fulfilled" ? psResult.value : [];
43952
+ const tagsRaw = tagsResult.status === "fulfilled" ? tagsResult.value : [];
43953
+ const connectionError = psResult.status === "rejected" ? classifyFetchError(psResult.reason, `${baseUrl}/api/ps`) : tagsResult.status === "rejected" ? classifyFetchError(tagsResult.reason, `${baseUrl}/api/tags`) : undefined;
43954
+ const loaded = loadedRaw.filter((m) => isChatCapable(m.name));
43955
+ const loadedNames = new Set(loaded.map((m) => m.name));
43956
+ const rest = tagsRaw.filter((m) => isChatCapable(m.name) && !loadedNames.has(m.name));
43957
+ if (loaded.length === 0 && rest.length === 0) {
43958
+ const reason = connectionError ?? (loadedRaw.length === 0 && tagsRaw.length === 0 ? `no models on ${baseUrl} (pull one: ollama pull llama3.2)` : `only embedding/non-chat models on ${baseUrl}`);
43058
43959
  cacheSetFailure(cacheKey.key, reason);
43059
43960
  return { model: null, reason };
43060
43961
  }
43061
- const sized = candidates.filter((m) => typeof m.size === "number");
43062
- let ranked;
43063
- if (sized.length > 0) {
43064
- ranked = [...sized].sort((a, b) => (a.size ?? Number.POSITIVE_INFINITY) - (b.size ?? Number.POSITIVE_INFINITY)).map((m) => m.name);
43065
- } else {
43066
- ranked = rankProbeCandidates(candidates.map((m) => m.name));
43067
- }
43962
+ const ranked = [...orderByCost(loaded), ...orderByCost(rest)];
43068
43963
  if (ranked.length === 0) {
43069
43964
  const reason = "no chat-capable model on Ollama endpoint";
43070
43965
  cacheSetFailure(cacheKey.key, reason);
@@ -43588,11 +44483,11 @@ var init_ollama_api_format = __esm(() => {
43588
44483
  });
43589
44484
 
43590
44485
  // src/providers/api-key-provenance.ts
43591
- import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
43592
- import { homedir as homedir22 } from "os";
43593
- import { join as join22, resolve as resolve2 } from "path";
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";
43594
44489
  function activeConfigPath() {
43595
- return activeGlobalConfigFile(join22(homedir22(), ".claudish", "config.json"));
44490
+ return activeGlobalConfigFile(join23(homedir23(), ".claudish", "config.json"));
43596
44491
  }
43597
44492
  function configLayerLabel() {
43598
44493
  return getConfigFileOverride() ? activeConfigPath() : "~/.claudish/config.json";
@@ -43669,7 +44564,7 @@ function formatProvenanceLog(p) {
43669
44564
  function readDotenvKey(envVars) {
43670
44565
  try {
43671
44566
  const dotenvPath = resolve2(".env");
43672
- if (!existsSync15(dotenvPath))
44567
+ if (!existsSync16(dotenvPath))
43673
44568
  return null;
43674
44569
  const parsed = import_dotenv.parse(readFileSync14(dotenvPath, "utf-8"));
43675
44570
  for (const v of envVars) {
@@ -43684,7 +44579,7 @@ function readDotenvKey(envVars) {
43684
44579
  function readConfigKey(envVar) {
43685
44580
  try {
43686
44581
  const configPath = activeConfigPath();
43687
- if (!existsSync15(configPath))
44582
+ if (!existsSync16(configPath))
43688
44583
  return null;
43689
44584
  const cfg = JSON.parse(readFileSync14(configPath, "utf-8"));
43690
44585
  return cfg.apiKeys?.[envVar] || null;
@@ -43698,142 +44593,6 @@ var init_api_key_provenance = __esm(() => {
43698
44593
  import_dotenv = __toESM(require_main(), 1);
43699
44594
  });
43700
44595
 
43701
- // src/handlers/shared/gemini-queue.ts
43702
- class GeminiRequestQueue {
43703
- static instance = null;
43704
- queue = [];
43705
- processing = false;
43706
- minDelayMs = 1000;
43707
- lastRequestTime = 0;
43708
- consecutiveErrors = 0;
43709
- totalProcessed = 0;
43710
- totalErrors = 0;
43711
- baseDelayMs = 1000;
43712
- maxDelayMs = 1e4;
43713
- maxQueueSize = 100;
43714
- constructor() {
43715
- log("[GeminiQueue] Queue initialized with minDelay=1000ms, maxQueueSize=100");
43716
- }
43717
- static getInstance() {
43718
- if (!GeminiRequestQueue.instance) {
43719
- GeminiRequestQueue.instance = new GeminiRequestQueue;
43720
- }
43721
- return GeminiRequestQueue.instance;
43722
- }
43723
- async enqueue(fetchFn) {
43724
- if (this.queue.length >= this.maxQueueSize) {
43725
- log(`[GeminiQueue] Queue full (${this.queue.length}/${this.maxQueueSize}), rejecting request`);
43726
- throw new Error("Gemini request queue full. Please retry later.");
43727
- }
43728
- return new Promise((resolve3, reject) => {
43729
- const queuedRequest = {
43730
- fetchFn,
43731
- resolve: resolve3,
43732
- reject
43733
- };
43734
- this.queue.push(queuedRequest);
43735
- log(`[GeminiQueue] Request enqueued (queue length: ${this.queue.length})`);
43736
- if (!this.processing) {
43737
- this.processQueue();
43738
- }
43739
- });
43740
- }
43741
- async processQueue() {
43742
- if (this.processing) {
43743
- return;
43744
- }
43745
- this.processing = true;
43746
- log("[GeminiQueue] Worker started");
43747
- while (this.queue.length > 0) {
43748
- const request = this.queue.shift();
43749
- if (!request)
43750
- break;
43751
- log(`[GeminiQueue] Processing request (${this.queue.length} remaining in queue)`);
43752
- try {
43753
- await this.waitForNextSlot();
43754
- const response = await request.fetchFn();
43755
- this.lastRequestTime = Date.now();
43756
- if (response.status === 429) {
43757
- this.totalErrors++;
43758
- const errorText = await response.clone().text();
43759
- this.handleRateLimitResponse(errorText);
43760
- log(`[GeminiQueue] Rate limit hit (429), adjusted delay to ${this.minDelayMs}ms`);
43761
- } else {
43762
- this.handleSuccessResponse();
43763
- }
43764
- this.totalProcessed++;
43765
- request.resolve(response);
43766
- } catch (error46) {
43767
- this.totalErrors++;
43768
- log(`[GeminiQueue] Request failed with error: ${error46}`);
43769
- request.reject(error46 instanceof Error ? error46 : new Error(String(error46)));
43770
- }
43771
- }
43772
- this.processing = false;
43773
- log("[GeminiQueue] Worker stopped (queue empty)");
43774
- }
43775
- async waitForNextSlot() {
43776
- const now = Date.now();
43777
- const timeSinceLastRequest = now - this.lastRequestTime;
43778
- let delayMs = this.minDelayMs;
43779
- if (this.consecutiveErrors > 0) {
43780
- const backoffMultiplier = 1 + this.consecutiveErrors * 0.5;
43781
- delayMs = Math.min(this.minDelayMs * backoffMultiplier, this.maxDelayMs);
43782
- log(`[GeminiQueue] Applying backoff (${this.consecutiveErrors} errors): ${delayMs}ms`);
43783
- }
43784
- if (timeSinceLastRequest < delayMs) {
43785
- const waitMs = delayMs - timeSinceLastRequest;
43786
- log(`[GeminiQueue] Waiting ${waitMs}ms before next request`);
43787
- await new Promise((resolve3) => setTimeout(resolve3, waitMs));
43788
- }
43789
- }
43790
- handleRateLimitResponse(errorText) {
43791
- this.consecutiveErrors++;
43792
- try {
43793
- const errorData = JSON.parse(errorText);
43794
- const quotaDetail = errorData?.error?.details?.find((d) => d.quotaResetDelay);
43795
- if (quotaDetail?.quotaResetDelay) {
43796
- const delayStr = quotaDetail.quotaResetDelay;
43797
- const match2 = delayStr.match(/(\d+(?:\.\d+)?)/);
43798
- if (match2) {
43799
- const delaySeconds = Number.parseFloat(match2[1]);
43800
- const suggestedDelayMs = Math.ceil(delaySeconds * 1000);
43801
- this.minDelayMs = Math.max(suggestedDelayMs, this.minDelayMs, this.baseDelayMs);
43802
- this.minDelayMs = Math.min(this.minDelayMs, this.maxDelayMs);
43803
- log(`[GeminiQueue] Parsed quotaResetDelay: ${delayStr} (${suggestedDelayMs}ms), ` + `new minDelay: ${this.minDelayMs}ms`);
43804
- }
43805
- }
43806
- } catch {
43807
- log("[GeminiQueue] Failed to parse rate limit response, using backoff");
43808
- }
43809
- const backoffMultiplier = 1 + this.consecutiveErrors * 0.5;
43810
- this.minDelayMs = Math.min(this.baseDelayMs * backoffMultiplier, this.maxDelayMs);
43811
- }
43812
- handleSuccessResponse() {
43813
- if (this.consecutiveErrors > 0) {
43814
- log(`[GeminiQueue] Success after ${this.consecutiveErrors} errors, resetting counter`);
43815
- this.consecutiveErrors = 0;
43816
- }
43817
- if (this.minDelayMs > this.baseDelayMs) {
43818
- this.minDelayMs = Math.max(this.baseDelayMs, this.minDelayMs * 0.9);
43819
- log(`[GeminiQueue] Reducing delay to ${this.minDelayMs}ms`);
43820
- }
43821
- }
43822
- getStats() {
43823
- return {
43824
- queueLength: this.queue.length,
43825
- processing: this.processing,
43826
- consecutiveErrors: this.consecutiveErrors,
43827
- currentDelayMs: this.minDelayMs,
43828
- totalProcessed: this.totalProcessed,
43829
- totalErrors: this.totalErrors
43830
- };
43831
- }
43832
- }
43833
- var init_gemini_queue = __esm(() => {
43834
- init_logger();
43835
- });
43836
-
43837
44596
  // src/providers/transport/gemini-apikey.ts
43838
44597
  class GeminiProviderTransport {
43839
44598
  name = "gemini";
@@ -43866,22 +44625,17 @@ var init_gemini_apikey = __esm(() => {
43866
44625
  });
43867
44626
 
43868
44627
  // src/providers/transport/gemini-codeassist.ts
43869
- import { randomUUID as randomUUID3 } from "crypto";
43870
- function buildGeminiCliUserAgent2(model) {
43871
- const version2 = "0.5.6";
43872
- const modelSegment = model || "gemini-code-assist";
43873
- return `GeminiCLI/${version2}/${modelSegment} (${process.platform}; ${process.arch})`;
43874
- }
43875
- function createActivityRequestId2() {
44628
+ import { randomUUID as randomUUID5 } from "crypto";
44629
+ function createActivityRequestId4() {
43876
44630
  return Math.random().toString(36).substring(7);
43877
44631
  }
43878
- function classify429(responseBody) {
44632
+ function classify4292(responseBody) {
43879
44633
  try {
43880
44634
  const raw2 = JSON.parse(responseBody);
43881
44635
  const error46 = Array.isArray(raw2) ? raw2[0]?.error : raw2?.error;
43882
44636
  const details = Array.isArray(error46?.details) ? error46.details : [];
43883
44637
  const retryInfo = details.find((d) => d["@type"] === "type.googleapis.com/google.rpc.RetryInfo");
43884
- let retryDelayMs = parseRetryDelay(retryInfo?.retryDelay);
44638
+ let retryDelayMs = parseRetryDelay2(retryInfo?.retryDelay);
43885
44639
  if (retryDelayMs === undefined && typeof error46?.message === "string") {
43886
44640
  const match2 = error46.message.match(/retry in ([\d.]+)(ms|s)/i);
43887
44641
  if (match2) {
@@ -43895,7 +44649,7 @@ function classify429(responseBody) {
43895
44649
  return { terminal: true, retryDelayMs, reason };
43896
44650
  }
43897
44651
  if (reason === "RATE_LIMIT_EXCEEDED") {
43898
- return { terminal: false, retryDelayMs: retryDelayMs ?? DEFAULT_RATE_LIMIT_DELAY_MS, reason };
44652
+ return { terminal: false, retryDelayMs: retryDelayMs ?? DEFAULT_RATE_LIMIT_DELAY_MS2, reason };
43899
44653
  }
43900
44654
  if (reason === "MODEL_CAPACITY_EXHAUSTED") {
43901
44655
  return { terminal: true, retryDelayMs, reason };
@@ -43915,7 +44669,7 @@ function classify429(responseBody) {
43915
44669
  return null;
43916
44670
  }
43917
44671
  }
43918
- function parseRetryDelay(value) {
44672
+ function parseRetryDelay2(value) {
43919
44673
  if (!value)
43920
44674
  return;
43921
44675
  if (typeof value === "string") {
@@ -43933,7 +44687,7 @@ function parseRetryDelay(value) {
43933
44687
 
43934
44688
  class GeminiCodeAssistProviderTransport {
43935
44689
  name = "gemini-codeassist";
43936
- _displayName = "Gemini Free";
44690
+ _displayName = "GeminiCA";
43937
44691
  get displayName() {
43938
44692
  return this._displayName;
43939
44693
  }
@@ -43943,19 +44697,17 @@ class GeminiCodeAssistProviderTransport {
43943
44697
  projectId = null;
43944
44698
  tierId = null;
43945
44699
  cachedAuth = null;
43946
- fallbackStartIndex;
43947
44700
  lastEnvelope = null;
43948
44701
  _activeModelName;
44702
+ servedModels = [];
43949
44703
  constructor(modelName) {
43950
44704
  this.modelName = modelName;
43951
- const idx = CODE_ASSIST_FALLBACK_CHAIN.indexOf(modelName);
43952
- this.fallbackStartIndex = idx >= 0 ? idx : CODE_ASSIST_FALLBACK_CHAIN.length;
43953
44705
  }
43954
44706
  getActiveModelName() {
43955
44707
  return this._activeModelName;
43956
44708
  }
43957
44709
  getEndpoint() {
43958
- return CODE_ASSIST_ENDPOINT;
44710
+ return CODE_ASSIST_ENDPOINT2;
43959
44711
  }
43960
44712
  async getHeaders() {
43961
44713
  if (this.cachedAuth)
@@ -43965,8 +44717,8 @@ class GeminiCodeAssistProviderTransport {
43965
44717
  buildLocalHeaders() {
43966
44718
  return {
43967
44719
  Authorization: `Bearer ${this.accessToken}`,
43968
- "User-Agent": buildGeminiCliUserAgent2(this.modelName),
43969
- "x-activity-request-id": createActivityRequestId2()
44720
+ "User-Agent": buildCodeAssistUserAgent(this.modelName),
44721
+ "x-activity-request-id": createActivityRequestId4()
43970
44722
  };
43971
44723
  }
43972
44724
  async refreshAuth() {
@@ -43978,7 +44730,8 @@ class GeminiCodeAssistProviderTransport {
43978
44730
  this.projectId = projectId;
43979
44731
  this.tierId = tierId;
43980
44732
  this._displayName = getGeminiTierDisplayName();
43981
- log(`[GeminiCodeAssist] Auth refreshed, project: ${this.projectId}, tier: ${this._displayName}`);
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)"}`);
43982
44735
  }
43983
44736
  transformPayload(payload) {
43984
44737
  const envelope = this.cachedAuth?.transformPayload ? this.cachedAuth.transformPayload(payload) : this.buildEnvelope(payload, this.modelName);
@@ -43989,7 +44742,7 @@ class GeminiCodeAssistProviderTransport {
43989
44742
  const envelope = {
43990
44743
  model,
43991
44744
  project: this.projectId,
43992
- user_prompt_id: randomUUID3(),
44745
+ user_prompt_id: randomUUID5(),
43993
44746
  request: innerPayload
43994
44747
  };
43995
44748
  if (this.tierId && this.tierId !== "free-tier") {
@@ -44000,13 +44753,16 @@ class GeminiCodeAssistProviderTransport {
44000
44753
  async enqueueRequest(fetchFn) {
44001
44754
  const queue = GeminiRequestQueue.getInstance();
44002
44755
  let lastResponse = null;
44003
- for (let attempt = 1;attempt <= MAX_RETRY_ATTEMPTS; attempt++) {
44756
+ for (let attempt = 1;attempt <= MAX_RETRY_ATTEMPTS2; attempt++) {
44004
44757
  const response = attempt === 1 ? await queue.enqueue(fetchFn) : await queue.enqueue(fetchFn);
44005
44758
  if (response.status !== 429) {
44759
+ if (response.status === 404) {
44760
+ return this.rewriteModelNotFound(response);
44761
+ }
44006
44762
  return response;
44007
44763
  }
44008
44764
  const bodyText = await response.clone().text();
44009
- const classification = classify429(bodyText);
44765
+ const classification = classify4292(bodyText);
44010
44766
  lastResponse = response;
44011
44767
  if (!classification) {
44012
44768
  log("[GeminiCodeAssist] 429 response could not be classified, returning to caller");
@@ -44020,20 +44776,21 @@ class GeminiCodeAssistProviderTransport {
44020
44776
  logStderr(`[GeminiCodeAssist] Quota exhausted (${classification.reason || "daily limit"}). Check plan limits.`);
44021
44777
  return response;
44022
44778
  }
44023
- if (attempt < MAX_RETRY_ATTEMPTS) {
44024
- const delay = classification.retryDelayMs ?? DEFAULT_RATE_LIMIT_DELAY_MS;
44025
- logStderr(`[GeminiCodeAssist] Rate limited (${classification.reason || "unknown"}), retrying in ${(delay / 1000).toFixed(1)}s (attempt ${attempt}/${MAX_RETRY_ATTEMPTS})`);
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})`);
44026
44782
  if (attempt === 1) {
44027
44783
  await this.logQuotaInfo();
44028
44784
  }
44029
44785
  await new Promise((r) => setTimeout(r, delay));
44030
44786
  }
44031
44787
  }
44032
- logStderr(`[GeminiCodeAssist] Rate limit persisted after ${MAX_RETRY_ATTEMPTS} retries`);
44788
+ logStderr(`[GeminiCodeAssist] Rate limit persisted after ${MAX_RETRY_ATTEMPTS2} retries`);
44033
44789
  return lastResponse;
44034
44790
  }
44035
44791
  async handleCapacityExhausted(originalResponse, queue) {
44036
- if (this.fallbackStartIndex >= CODE_ASSIST_FALLBACK_CHAIN.length - 1) {
44792
+ const candidates = this.servedModels.filter((m) => m !== this.modelName);
44793
+ if (candidates.length === 0) {
44037
44794
  log(`[GeminiCodeAssist] ${this.modelName} capacity exhausted, no fallback models available`);
44038
44795
  return originalResponse;
44039
44796
  }
@@ -44045,11 +44802,12 @@ class GeminiCodeAssistProviderTransport {
44045
44802
  logStderr(`[GeminiCodeAssist] ${this.modelName} capacity exhausted, trying fallback models...`);
44046
44803
  let lastResponse = originalResponse;
44047
44804
  const innerPayload = this.lastEnvelope.request;
44048
- for (let i = this.fallbackStartIndex + 1;i < CODE_ASSIST_FALLBACK_CHAIN.length; i++) {
44049
- const fallbackModel = CODE_ASSIST_FALLBACK_CHAIN[i];
44805
+ const endpoint = this.getEndpoint();
44806
+ const tried = [this.modelName];
44807
+ for (const fallbackModel of candidates) {
44050
44808
  log(`[GeminiCodeAssist] Trying fallback model: ${fallbackModel}`);
44809
+ tried.push(fallbackModel);
44051
44810
  const fallbackEnvelope = this.buildEnvelope(innerPayload, fallbackModel);
44052
- const endpoint = this.getEndpoint();
44053
44811
  const headers = this.buildLocalHeaders();
44054
44812
  headers["Content-Type"] = "application/json";
44055
44813
  const fallbackResponse = await queue.enqueue(() => fetch(endpoint, {
@@ -44057,23 +44815,59 @@ class GeminiCodeAssistProviderTransport {
44057
44815
  headers,
44058
44816
  body: JSON.stringify(fallbackEnvelope)
44059
44817
  }));
44060
- if (fallbackResponse.status !== 429) {
44818
+ if (fallbackResponse.status === 200) {
44061
44819
  this._activeModelName = fallbackModel;
44062
44820
  logStderr(`[GeminiCodeAssist] Using fallback model: ${fallbackModel} (${this.modelName} had no capacity)`);
44063
44821
  return fallbackResponse;
44064
44822
  }
44065
- const fallbackBodyText = await fallbackResponse.clone().text();
44066
- const classification = classify429(fallbackBodyText);
44067
- if (classification?.reason !== "MODEL_CAPACITY_EXHAUSTED") {
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
+ }
44068
44836
  return fallbackResponse;
44069
44837
  }
44070
- log(`[GeminiCodeAssist] ${fallbackModel} also capacity exhausted, trying next...`);
44071
- lastResponse = fallbackResponse;
44838
+ return fallbackResponse;
44072
44839
  }
44073
44840
  log("[GeminiCodeAssist] All fallback models exhausted");
44074
- logStderr(`[GeminiCodeAssist] All models capacity exhausted (tried: ${CODE_ASSIST_FALLBACK_CHAIN.slice(this.fallbackStartIndex).join(" -> ")})`);
44841
+ logStderr(`[GeminiCodeAssist] All models capacity exhausted (tried: ${tried.join(" -> ")})`);
44842
+ if (lastResponse.status === 404) {
44843
+ return this.rewriteModelNotFound(lastResponse, true);
44844
+ }
44075
44845
  return lastResponse;
44076
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
+ }
44077
44871
  async logQuotaInfo() {
44078
44872
  if (!this.accessToken || !this.projectId)
44079
44873
  return;
@@ -44113,13 +44907,13 @@ ${lines.join(`
44113
44907
  }
44114
44908
  }
44115
44909
  }
44116
- var CODE_ASSIST_BASE = "https://cloudcode-pa.googleapis.com", CODE_ASSIST_ENDPOINT, MAX_RETRY_ATTEMPTS = 3, DEFAULT_RATE_LIMIT_DELAY_MS = 1e4;
44910
+ var CODE_ASSIST_BASE2 = "https://cloudcode-pa.googleapis.com", CODE_ASSIST_ENDPOINT2, MAX_RETRY_ATTEMPTS2 = 3, DEFAULT_RATE_LIMIT_DELAY_MS2 = 1e4;
44117
44911
  var init_gemini_codeassist = __esm(() => {
44118
44912
  init_authority();
44119
44913
  init_gemini_oauth();
44120
44914
  init_gemini_queue();
44121
44915
  init_logger();
44122
- CODE_ASSIST_ENDPOINT = `${CODE_ASSIST_BASE}/v1internal:streamGenerateContent?alt=sse`;
44916
+ CODE_ASSIST_ENDPOINT2 = `${CODE_ASSIST_BASE2}/v1internal:streamGenerateContent?alt=sse`;
44123
44917
  });
44124
44918
 
44125
44919
  // src/providers/transport/ollamacloud.ts
@@ -44281,7 +45075,7 @@ function createHandlerForProvider(ctx) {
44281
45075
  log(`[Proxy] Handler: provider=${ctx.provider.name}, model=${ctx.modelName}`);
44282
45076
  return profile.createHandler(ctx);
44283
45077
  }
44284
- 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;
44285
45079
  var init_provider_profiles = __esm(() => {
44286
45080
  init_anthropic_api_format();
44287
45081
  init_base_api_format();
@@ -44297,6 +45091,7 @@ var init_provider_profiles = __esm(() => {
44297
45091
  init_remote_provider_registry();
44298
45092
  init_runtime_providers();
44299
45093
  init_anthropic_compat();
45094
+ init_antigravity();
44300
45095
  init_gemini_apikey();
44301
45096
  init_gemini_codeassist();
44302
45097
  init_litellm();
@@ -44329,6 +45124,19 @@ var init_provider_profiles = __esm(() => {
44329
45124
  return handler;
44330
45125
  }
44331
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
+ };
44332
45140
  openaiProfile = {
44333
45141
  createHandler(ctx) {
44334
45142
  if (requiresResponsesApi(ctx.modelName)) {
@@ -44507,6 +45315,7 @@ var init_provider_profiles = __esm(() => {
44507
45315
  PROVIDER_PROFILES = {
44508
45316
  gemini: geminiProfile,
44509
45317
  "gemini-codeassist": geminiCodeAssistProfile,
45318
+ antigravity: antigravityProfile,
44510
45319
  openai: openaiProfile,
44511
45320
  "openai-codex": openaiCodexProfile,
44512
45321
  "x-ai": openaiProfile,
@@ -45244,9 +46053,9 @@ var init_poe = __esm(() => {
45244
46053
  });
45245
46054
 
45246
46055
  // src/services/pricing-cache.ts
45247
- import { existsSync as existsSync16, readFileSync as readFileSync15, statSync as statSync4 } from "fs";
45248
- import { homedir as homedir23 } from "os";
45249
- import { join as join23 } from "path";
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";
45250
46059
  function prefixMatch(modelName) {
45251
46060
  for (const [key, pricing] of pricingMap) {
45252
46061
  if (modelName.startsWith(key))
@@ -45284,7 +46093,7 @@ async function warmPricingCache() {
45284
46093
  }
45285
46094
  function loadDiskCache() {
45286
46095
  try {
45287
- if (!existsSync16(CACHE_FILE))
46096
+ if (!existsSync17(CACHE_FILE))
45288
46097
  return false;
45289
46098
  const stat2 = statSync4(CACHE_FILE);
45290
46099
  const age = Date.now() - stat2.mtimeMs;
@@ -45305,8 +46114,8 @@ var init_pricing_cache = __esm(() => {
45305
46114
  init_logger();
45306
46115
  init_catalog_query();
45307
46116
  pricingMap = new Map;
45308
- CACHE_DIR = join23(homedir23(), ".claudish");
45309
- CACHE_FILE = join23(CACHE_DIR, "pricing-cache.json");
46117
+ CACHE_DIR = join24(homedir24(), ".claudish");
46118
+ CACHE_FILE = join24(CACHE_DIR, "pricing-cache.json");
45310
46119
  CACHE_TTL_MS2 = 24 * 60 * 60 * 1000;
45311
46120
  });
45312
46121
 
@@ -45763,17 +46572,17 @@ var init_proxy_server = __esm(() => {
45763
46572
  });
45764
46573
 
45765
46574
  // src/team-stats.ts
45766
- import { existsSync as existsSync17, readFileSync as readFileSync16, writeFileSync as writeFileSync11 } from "fs";
45767
- import { join as join24 } from "path";
46575
+ import { existsSync as existsSync18, readFileSync as readFileSync16, writeFileSync as writeFileSync11 } from "fs";
46576
+ import { join as join25 } from "path";
45768
46577
  function statsDir(sessionPath) {
45769
- return join24(sessionPath, "stats");
46578
+ return join25(sessionPath, "stats");
45770
46579
  }
45771
46580
  function tokenFileFor(sessionPath, anonId) {
45772
- return join24(statsDir(sessionPath), `${anonId}.json`);
46581
+ return join25(statsDir(sessionPath), `${anonId}.json`);
45773
46582
  }
45774
46583
  function readTokenStats(sessionPath, anonId) {
45775
46584
  const path = tokenFileFor(sessionPath, anonId);
45776
- if (!existsSync17(path))
46585
+ if (!existsSync18(path))
45777
46586
  return null;
45778
46587
  try {
45779
46588
  return JSON.parse(readFileSync16(path, "utf-8"));
@@ -45924,7 +46733,7 @@ ${segs.join(" \xB7 ")}`;
45924
46733
  }
45925
46734
  function writeStatusFile(sessionPath, manifest, status, opts) {
45926
46735
  try {
45927
- writeFileSync11(join24(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
46736
+ writeFileSync11(join25(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
45928
46737
  `, "utf-8");
45929
46738
  } catch {}
45930
46739
  }
@@ -45950,13 +46759,13 @@ __export(exports_team_orchestrator, {
45950
46759
  import { spawn as spawn2 } from "child_process";
45951
46760
  import {
45952
46761
  createWriteStream as createWriteStream2,
45953
- existsSync as existsSync18,
46762
+ existsSync as existsSync19,
45954
46763
  mkdirSync as mkdirSync11,
45955
46764
  readFileSync as readFileSync17,
45956
46765
  readdirSync as readdirSync3,
45957
46766
  writeFileSync as writeFileSync12
45958
46767
  } from "fs";
45959
- import { join as join25, resolve as resolve3 } from "path";
46768
+ import { join as join26, resolve as resolve3 } from "path";
45960
46769
  function classifyRunOutput(opts) {
45961
46770
  const { outputSize, stdoutTail, stderr, minOutputBytes } = opts;
45962
46771
  const apiError = API_ERROR_RE.exec(stdoutTail);
@@ -46017,18 +46826,18 @@ function setupSession(sessionPath, models, input) {
46017
46826
  if (models.length === 0) {
46018
46827
  throw new Error("At least one model is required");
46019
46828
  }
46020
- if (existsSync18(join25(sessionPath, "manifest.json"))) {
46829
+ if (existsSync19(join26(sessionPath, "manifest.json"))) {
46021
46830
  throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
46022
46831
  }
46023
46832
  const sentinels = models.filter(isSentinelModel);
46024
46833
  if (sentinels.length > 0) {
46025
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.`);
46026
46835
  }
46027
- mkdirSync11(join25(sessionPath, "work"), { recursive: true });
46028
- mkdirSync11(join25(sessionPath, "errors"), { recursive: true });
46836
+ mkdirSync11(join26(sessionPath, "work"), { recursive: true });
46837
+ mkdirSync11(join26(sessionPath, "errors"), { recursive: true });
46029
46838
  if (input !== undefined) {
46030
- writeFileSync12(join25(sessionPath, "input.md"), input, "utf-8");
46031
- } else if (!existsSync18(join25(sessionPath, "input.md"))) {
46839
+ writeFileSync12(join26(sessionPath, "input.md"), input, "utf-8");
46840
+ } else if (!existsSync19(join26(sessionPath, "input.md"))) {
46032
46841
  throw new Error(`No input.md found at ${sessionPath} and no input provided`);
46033
46842
  }
46034
46843
  const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
@@ -46045,9 +46854,9 @@ function setupSession(sessionPath, models, input) {
46045
46854
  model: models[i],
46046
46855
  assignedAt: now
46047
46856
  };
46048
- mkdirSync11(join25(sessionPath, "work", anonId), { recursive: true });
46857
+ mkdirSync11(join26(sessionPath, "work", anonId), { recursive: true });
46049
46858
  }
46050
- writeFileSync12(join25(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
46859
+ writeFileSync12(join26(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
46051
46860
  const status = {
46052
46861
  startedAt: now,
46053
46862
  models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
@@ -46061,14 +46870,14 @@ function setupSession(sessionPath, models, input) {
46061
46870
  }
46062
46871
  ]))
46063
46872
  };
46064
- writeFileSync12(join25(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
46873
+ writeFileSync12(join26(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
46065
46874
  return manifest;
46066
46875
  }
46067
46876
  async function runModels(sessionPath, opts = {}) {
46068
46877
  const timeoutMs = (opts.timeout ?? 300) * 1000;
46069
- const manifest = JSON.parse(readFileSync17(join25(sessionPath, "manifest.json"), "utf-8"));
46070
- const statusPath = join25(sessionPath, "status.json");
46071
- const inputPath = join25(sessionPath, "input.md");
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");
46072
46881
  const inputContent = readFileSync17(inputPath, "utf-8");
46073
46882
  await prehydrateCredentialsForSpawn(Object.values(manifest.models).map((m) => m.model));
46074
46883
  const statusCache = JSON.parse(readFileSync17(statusPath, "utf-8"));
@@ -46090,8 +46899,8 @@ async function runModels(sessionPath, opts = {}) {
46090
46899
  process.on("SIGINT", sigintHandler);
46091
46900
  const completionPromises = [];
46092
46901
  for (const [anonId, entry] of Object.entries(manifest.models)) {
46093
- const outputPath = join25(sessionPath, `response-${anonId}.md`);
46094
- const errorLogPath = join25(sessionPath, "errors", `${anonId}.log`);
46902
+ const outputPath = join26(sessionPath, `response-${anonId}.md`);
46903
+ const errorLogPath = join26(sessionPath, "errors", `${anonId}.log`);
46095
46904
  const args = ["--model", entry.model, "-y", "--stdin", "--quiet", ...opts.claudeFlags ?? []];
46096
46905
  updateModelStatus(anonId, {
46097
46906
  state: "RUNNING",
@@ -46280,23 +47089,23 @@ async function judgeResponses(sessionPath, opts = {}) {
46280
47089
  const responses = {};
46281
47090
  for (const file2 of responseFiles) {
46282
47091
  const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
46283
- responses[id] = readFileSync17(join25(sessionPath, file2), "utf-8");
47092
+ responses[id] = readFileSync17(join26(sessionPath, file2), "utf-8");
46284
47093
  }
46285
- const input = readFileSync17(join25(sessionPath, "input.md"), "utf-8");
47094
+ const input = readFileSync17(join26(sessionPath, "input.md"), "utf-8");
46286
47095
  const judgePrompt = buildJudgePrompt(input, responses);
46287
- writeFileSync12(join25(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
47096
+ writeFileSync12(join26(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
46288
47097
  const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
46289
- const judgePath = join25(sessionPath, "judging");
47098
+ const judgePath = join26(sessionPath, "judging");
46290
47099
  mkdirSync11(judgePath, { recursive: true });
46291
47100
  setupSession(judgePath, judgeModels, judgePrompt);
46292
47101
  await runModels(judgePath, { claudeFlags: opts.claudeFlags });
46293
47102
  const votes = parseJudgeVotes(judgePath, Object.keys(responses));
46294
47103
  const verdict = aggregateVerdict(votes, Object.keys(responses));
46295
- writeFileSync12(join25(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
47104
+ writeFileSync12(join26(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
46296
47105
  return verdict;
46297
47106
  }
46298
47107
  function getStatus(sessionPath) {
46299
- return JSON.parse(readFileSync17(join25(sessionPath, "status.json"), "utf-8"));
47108
+ return JSON.parse(readFileSync17(join26(sessionPath, "status.json"), "utf-8"));
46300
47109
  }
46301
47110
  function fisherYatesShuffle(arr) {
46302
47111
  for (let i = arr.length - 1;i > 0; i--) {
@@ -46306,7 +47115,7 @@ function fisherYatesShuffle(arr) {
46306
47115
  return arr;
46307
47116
  }
46308
47117
  function getDefaultJudgeModels(sessionPath) {
46309
- const manifest = JSON.parse(readFileSync17(join25(sessionPath, "manifest.json"), "utf-8"));
47118
+ const manifest = JSON.parse(readFileSync17(join26(sessionPath, "manifest.json"), "utf-8"));
46310
47119
  return Object.values(manifest.models).map((e) => e.model);
46311
47120
  }
46312
47121
  function buildJudgePrompt(input, responses) {
@@ -46369,7 +47178,7 @@ function parseJudgeVotes(judgePath, responseIds) {
46369
47178
  const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
46370
47179
  let content;
46371
47180
  try {
46372
- content = readFileSync17(join25(judgePath, file2), "utf-8");
47181
+ content = readFileSync17(join26(judgePath, file2), "utf-8");
46373
47182
  } catch {
46374
47183
  continue;
46375
47184
  }
@@ -46421,7 +47230,7 @@ function aggregateVerdict(votes, responseIds) {
46421
47230
  function formatVerdict(verdict, sessionPath) {
46422
47231
  let manifest = null;
46423
47232
  try {
46424
- manifest = JSON.parse(readFileSync17(join25(sessionPath, "manifest.json"), "utf-8"));
47233
+ manifest = JSON.parse(readFileSync17(join26(sessionPath, "manifest.json"), "utf-8"));
46425
47234
  } catch {}
46426
47235
  let output = `# Team Verdict
46427
47236
 
@@ -46476,12 +47285,12 @@ __export(exports_mcp_server, {
46476
47285
  parseAnthropicSse: () => parseAnthropicSse,
46477
47286
  formatTeamResult: () => formatTeamResult
46478
47287
  });
46479
- import { existsSync as existsSync19, mkdirSync as mkdirSync12, readFileSync as readFileSync18, readdirSync as readdirSync4, writeFileSync as writeFileSync13 } from "fs";
46480
- import { homedir as homedir24 } from "os";
46481
- import { dirname as dirname8, join as join26 } from "path";
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";
46482
47291
  import { fileURLToPath } from "url";
46483
47292
  async function loadAllModels(forceRefresh = false) {
46484
- if (!forceRefresh && existsSync19(ALL_MODELS_CACHE_PATH2)) {
47293
+ if (!forceRefresh && existsSync20(ALL_MODELS_CACHE_PATH2)) {
46485
47294
  try {
46486
47295
  const cacheData = JSON.parse(readFileSync18(ALL_MODELS_CACHE_PATH2, "utf-8"));
46487
47296
  const lastUpdated = new Date(cacheData.lastUpdated);
@@ -46501,7 +47310,7 @@ async function loadAllModels(forceRefresh = false) {
46501
47310
  writeFileSync13(ALL_MODELS_CACHE_PATH2, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
46502
47311
  return models;
46503
47312
  } catch {
46504
- if (existsSync19(ALL_MODELS_CACHE_PATH2)) {
47313
+ if (existsSync20(ALL_MODELS_CACHE_PATH2)) {
46505
47314
  const cacheData = JSON.parse(readFileSync18(ALL_MODELS_CACHE_PATH2, "utf-8"));
46506
47315
  return cacheData.models || [];
46507
47316
  }
@@ -47077,16 +47886,16 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
47077
47886
  const sp = session_path;
47078
47887
  for (const file2 of ["status.json", "manifest.json", "input.md"]) {
47079
47888
  try {
47080
- sessionData[file2] = readFileSync18(join26(sp, file2), "utf-8");
47889
+ sessionData[file2] = readFileSync18(join27(sp, file2), "utf-8");
47081
47890
  } catch {}
47082
47891
  }
47083
47892
  try {
47084
- const errorDir = join26(sp, "errors");
47085
- if (existsSync19(errorDir)) {
47893
+ const errorDir = join27(sp, "errors");
47894
+ if (existsSync20(errorDir)) {
47086
47895
  for (const f of readdirSync4(errorDir)) {
47087
47896
  if (f.endsWith(".log")) {
47088
47897
  try {
47089
- sessionData[`errors/${f}`] = readFileSync18(join26(errorDir, f), "utf-8");
47898
+ sessionData[`errors/${f}`] = readFileSync18(join27(errorDir, f), "utf-8");
47090
47899
  } catch {}
47091
47900
  }
47092
47901
  }
@@ -47096,7 +47905,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
47096
47905
  for (const f of readdirSync4(sp)) {
47097
47906
  if (f.startsWith("response-") && f.endsWith(".md")) {
47098
47907
  try {
47099
- const content = readFileSync18(join26(sp, f), "utf-8");
47908
+ const content = readFileSync18(join27(sp, f), "utf-8");
47100
47909
  sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
47101
47910
  } catch {}
47102
47911
  }
@@ -47105,8 +47914,8 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
47105
47914
  }
47106
47915
  let version2 = "unknown";
47107
47916
  try {
47108
- const pkgPath = join26(__dirname2, "../package.json");
47109
- if (existsSync19(pkgPath)) {
47917
+ const pkgPath = join27(__dirname2, "../package.json");
47918
+ if (existsSync20(pkgPath)) {
47110
47919
  version2 = JSON.parse(readFileSync18(pkgPath, "utf-8")).version;
47111
47920
  }
47112
47921
  } catch {}
@@ -47505,8 +48314,8 @@ var init_mcp_server = __esm(() => {
47505
48314
  import_dotenv2.config({ quiet: true });
47506
48315
  __filename2 = fileURLToPath(import.meta.url);
47507
48316
  __dirname2 = dirname8(__filename2);
47508
- CLAUDISH_CACHE_DIR = join26(homedir24(), ".claudish");
47509
- ALL_MODELS_CACHE_PATH2 = join26(CLAUDISH_CACHE_DIR, "all-models.json");
48317
+ CLAUDISH_CACHE_DIR = join27(homedir25(), ".claudish");
48318
+ ALL_MODELS_CACHE_PATH2 = join27(CLAUDISH_CACHE_DIR, "all-models.json");
47510
48319
  NEXT_STEP = {
47511
48320
  nonzero_exit: "read the evidence log, then retry or drop the model",
47512
48321
  timeout: "raise `timeout`, or pick a faster model",
@@ -47531,7 +48340,7 @@ var exports_serve_command = {};
47531
48340
  __export(exports_serve_command, {
47532
48341
  serveCommand: () => serveCommand
47533
48342
  });
47534
- import { existsSync as existsSync20, readFileSync as readFileSync19 } from "fs";
48343
+ import { existsSync as existsSync21, readFileSync as readFileSync19 } from "fs";
47535
48344
  function parseServeArgs(args) {
47536
48345
  const out = {};
47537
48346
  for (let i = 0;i < args.length; i++) {
@@ -47550,7 +48359,7 @@ function parseServeArgs(args) {
47550
48359
  return out;
47551
48360
  }
47552
48361
  function loadModelMap(path) {
47553
- if (!existsSync20(path)) {
48362
+ if (!existsSync21(path)) {
47554
48363
  throw new Error(`--models file not found: ${path}`);
47555
48364
  }
47556
48365
  let raw2;
@@ -47754,6 +48563,8 @@ function describeSourceSync(p, config3) {
47754
48563
  return isLocalProviderEnabled(p.catalogName, config3) ? "local" : null;
47755
48564
  if (p.oauthSlug && hasOAuthCredentials(p.catalogName))
47756
48565
  return "oauth";
48566
+ if (p.catalogName === "antigravity" && hasSharedAntigravityToken())
48567
+ return "oauth";
47757
48568
  const hasCfg = !!p.apiKeyEnvVar && !!realValue(config3.apiKeys?.[p.apiKeyEnvVar]);
47758
48569
  const hasEnv = !!p.apiKeyEnvVar && !!realValue(process.env[p.apiKeyEnvVar]);
47759
48570
  if (hasEnv && hasCfg)
@@ -47774,6 +48585,7 @@ async function describeSource(p, config3) {
47774
48585
  }
47775
48586
  var init_source = __esm(() => {
47776
48587
  init_profile_config();
48588
+ init_antigravity_token();
47777
48589
  init_oauth_registry();
47778
48590
  init_api_key_credential();
47779
48591
  init_authority();
@@ -47821,7 +48633,7 @@ function providerAuthCapabilities(p, config3) {
47821
48633
  const apiKeySupported = !!p.apiKeyEnvVar;
47822
48634
  const apiKeySet = apiKeySupported && (!!process.env[p.apiKeyEnvVar] || !!config3.apiKeys?.[p.apiKeyEnvVar]);
47823
48635
  const oauthSupported = !!p.oauthSlug;
47824
- const oauthSet = oauthSupported && hasOAuthCredentials(p.catalogName);
48636
+ const oauthSet = oauthSupported && (hasOAuthCredentials(p.catalogName) || p.catalogName === "antigravity" && hasSharedAntigravityToken());
47825
48637
  return {
47826
48638
  apiKey: { supported: apiKeySupported, set: apiKeySet },
47827
48639
  oauth: { supported: oauthSupported, set: oauthSet }
@@ -47837,6 +48649,7 @@ function maskKey2(key) {
47837
48649
  var SKIP, PROVIDERS;
47838
48650
  var init_providers = __esm(() => {
47839
48651
  init_source();
48652
+ init_antigravity_token();
47840
48653
  init_oauth_registry();
47841
48654
  init_provider_definitions();
47842
48655
  SKIP = new Set(["qwen", "native-anthropic"]);
@@ -59151,7 +59964,7 @@ import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
59151
59964
  import { readFileSync as readFileSync20, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
59152
59965
  import path from "path";
59153
59966
  import os from "os";
59154
- import { randomUUID as randomUUID4 } from "crypto";
59967
+ import { randomUUID as randomUUID6 } from "crypto";
59155
59968
  function editAsync(text = "", callback, fileOptions) {
59156
59969
  const editor = new ExternalEditor(text, fileOptions);
59157
59970
  editor.runAsync((err, result) => {
@@ -59243,7 +60056,7 @@ class ExternalEditor {
59243
60056
  createTemporaryFile() {
59244
60057
  try {
59245
60058
  const baseDir = this.fileOptions.dir ?? os.tmpdir();
59246
- const id = randomUUID4();
60059
+ const id = randomUUID6();
59247
60060
  const prefix = sanitizeAffix(this.fileOptions.prefix);
59248
60061
  const postfix = sanitizeAffix(this.fileOptions.postfix);
59249
60062
  const filename = `${prefix}${id}${postfix}`;
@@ -60419,13 +61232,14 @@ async function geminiQuotaHandler() {
60419
61232
  }
60420
61233
  console.log("");
60421
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));
60422
61236
  console.log(` ${B}${CYN}Fallback Chain${R} ${D}(on capacity exhaustion)${R}`);
60423
- for (let i = 0;i < CODE_ASSIST_FALLBACK_CHAIN.length; i++) {
60424
- const model = CODE_ASSIST_FALLBACK_CHAIN[i];
61237
+ for (let i = 0;i < fallbackChain.length; i++) {
61238
+ const model = fallbackChain[i];
60425
61239
  const rem = remainingByModel.get(model);
60426
61240
  const pct = rem !== undefined ? `${((1 - rem) * 100).toFixed(0)}%` : "?";
60427
61241
  const color = rem === undefined ? GRY : rem > 0.5 ? GRN : rem > 0.2 ? YEL : RED;
60428
- const arrow = i < CODE_ASSIST_FALLBACK_CHAIN.length - 1 ? ` ${GRY}\u2192${R}` : "";
61242
+ const arrow = i < fallbackChain.length - 1 ? ` ${GRY}\u2192${R}` : "";
60429
61243
  const marker = i === 0 ? `${CYN}\u25B8${R} ` : " ";
60430
61244
  console.log(` ${marker}${WHT}${model}${R} ${color}${pct}${R}${arrow}`);
60431
61245
  }
@@ -60459,11 +61273,11 @@ async function geminiQuotaHandler() {
60459
61273
  }
60460
61274
  }
60461
61275
  async function codexQuotaHandler() {
60462
- const { readFileSync: readFileSync21, existsSync: existsSync21 } = await import("fs");
60463
- const { join: join27 } = await import("path");
60464
- const { homedir: homedir25 } = await import("os");
60465
- const credPath = join27(homedir25(), ".claudish", "codex-oauth.json");
60466
- if (!existsSync21(credPath)) {
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)) {
60467
61281
  console.error(`${RED}No Codex credentials found.${R} Run: ${B}claudish login codex${R}`);
60468
61282
  process.exit(1);
60469
61283
  }
@@ -60519,8 +61333,8 @@ async function codexQuotaHandler() {
60519
61333
  }
60520
61334
  let modelSlugs = [];
60521
61335
  try {
60522
- const modelsPath = join27(homedir25(), ".codex", "models_cache.json");
60523
- if (existsSync21(modelsPath)) {
61336
+ const modelsPath = join28(homedir26(), ".codex", "models_cache.json");
61337
+ if (existsSync22(modelsPath)) {
60524
61338
  const cache2 = JSON.parse(readFileSync21(modelsPath, "utf-8"));
60525
61339
  modelSlugs = (cache2.models || []).map((m) => m.slug || m.id).filter(Boolean);
60526
61340
  }
@@ -61892,6 +62706,8 @@ function annotateOAuthHint(result, provider, isOAuth) {
61892
62706
  const loginCommand2 = provider === "gemini-codeassist" ? "claudish login gemini" : provider === "vertex" ? "gcloud auth application-default login" : undefined;
61893
62707
  if (!loginCommand2)
61894
62708
  return result;
62709
+ if (result.httpStatus === 403)
62710
+ return result;
61895
62711
  const looksLikeAuthFailure = result.state === "auth-failed" || /auth|token|login|credential|unauthor/i.test(result.errorMessage || "");
61896
62712
  if (!looksLikeAuthFailure)
61897
62713
  return result;
@@ -62174,29 +62990,34 @@ function isContentEvent(parsed, eventType) {
62174
62990
  return true;
62175
62991
  return false;
62176
62992
  }
62993
+ function withDetail(base, message) {
62994
+ return message ? `${base} \u2014 ${message}` : base;
62995
+ }
62177
62996
  function describeProbeState(result) {
62997
+ const status = result.httpStatus ?? "";
62998
+ const latency = result.latencyMs ? ` \xB7 ${result.latencyMs}ms` : "";
62178
62999
  switch (result.state) {
62179
63000
  case "live":
62180
63001
  return `live \xB7 ${result.latencyMs}ms`;
62181
63002
  case "key-missing":
62182
63003
  return result.errorMessage ? `missing (${result.errorMessage})` : "missing";
62183
63004
  case "auth-failed":
62184
- return `auth failed \xB7 ${result.httpStatus ?? ""}${result.latencyMs ? ` \xB7 ${result.latencyMs}ms` : ""}`.trim();
63005
+ return withDetail(`auth failed \xB7 ${status}${latency}`.trim(), result.errorMessage);
62185
63006
  case "model-not-found":
62186
- return `model not found \xB7 ${result.httpStatus ?? ""}${result.latencyMs ? ` \xB7 ${result.latencyMs}ms` : ""}`.trim();
63007
+ return withDetail(`model not found \xB7 ${status}${latency}`.trim(), result.errorMessage);
62187
63008
  case "rate-limited":
62188
- return `rate limited \xB7 ${result.latencyMs}ms`;
63009
+ return withDetail(`rate limited \xB7 ${result.latencyMs}ms`, result.errorMessage);
62189
63010
  case "out-of-credit":
62190
- return `out of credit \xB7 ${result.httpStatus ?? ""}${result.latencyMs ? ` \xB7 ${result.latencyMs}ms` : ""}`.trim();
63011
+ return withDetail(`out of credit \xB7 ${status}${latency}`.trim(), result.errorMessage);
62191
63012
  case "server-error":
62192
- return `server error \xB7 ${result.httpStatus ?? ""} \xB7 ${result.latencyMs}ms`;
63013
+ return withDetail(`server error \xB7 ${status} \xB7 ${result.latencyMs}ms`, result.errorMessage);
62193
63014
  case "timeout":
62194
- return `timeout \xB7 ${result.latencyMs}ms`;
63015
+ return withDetail(`timeout \xB7 ${result.latencyMs}ms`, result.errorMessage);
62195
63016
  case "network-error":
62196
- return `network error \xB7 ${result.latencyMs}ms`;
63017
+ return withDetail(`network error \xB7 ${result.latencyMs}ms`, result.errorMessage);
62197
63018
  case "error": {
62198
- const base = `error${result.httpStatus ? ` \xB7 ${result.httpStatus}` : ""}${result.latencyMs ? ` \xB7 ${result.latencyMs}ms` : ""}`;
62199
- return result.errorMessage ? `${base} \u2014 ${result.errorMessage}` : base;
63019
+ const base = `error${result.httpStatus ? ` \xB7 ${result.httpStatus}` : ""}${latency}`;
63020
+ return withDetail(base, result.errorMessage);
62200
63021
  }
62201
63022
  }
62202
63023
  }
@@ -64484,22 +65305,22 @@ __export(exports_cli, {
64484
65305
  });
64485
65306
  import {
64486
65307
  copyFileSync as copyFileSync2,
64487
- existsSync as existsSync21,
65308
+ existsSync as existsSync22,
64488
65309
  mkdirSync as mkdirSync13,
64489
65310
  readFileSync as readFileSync21,
64490
65311
  readdirSync as readdirSync5,
64491
65312
  unlinkSync as unlinkSync7,
64492
65313
  writeFileSync as writeFileSync15
64493
65314
  } from "fs";
64494
- import { homedir as homedir25 } from "os";
64495
- import { dirname as dirname9, join as join27 } from "path";
65315
+ import { homedir as homedir26 } from "os";
65316
+ import { dirname as dirname9, join as join28 } from "path";
64496
65317
  import { fileURLToPath as fileURLToPath2 } from "url";
64497
65318
  function getVersion3() {
64498
65319
  return VERSION;
64499
65320
  }
64500
65321
  function clearAllModelCaches() {
64501
- const cacheDir = join27(homedir25(), ".claudish");
64502
- if (!existsSync21(cacheDir))
65322
+ const cacheDir = join28(homedir26(), ".claudish");
65323
+ if (!existsSync22(cacheDir))
64503
65324
  return;
64504
65325
  const cachePatterns = ["pricing-cache.json", "recommended-models-cache.json"];
64505
65326
  let cleared = 0;
@@ -64507,7 +65328,7 @@ function clearAllModelCaches() {
64507
65328
  const files = readdirSync5(cacheDir);
64508
65329
  for (const file2 of files) {
64509
65330
  if (cachePatterns.includes(file2)) {
64510
- unlinkSync7(join27(cacheDir, file2));
65331
+ unlinkSync7(join28(cacheDir, file2));
64511
65332
  cleared++;
64512
65333
  }
64513
65334
  }
@@ -64917,8 +65738,8 @@ Usage: claudish --models --provider <slug>`);
64917
65738
  });
64918
65739
  config3.resolvedDefaultProvider = resolved;
64919
65740
  if (resolved.legacyAutoPromoted && !config3.quiet) {
64920
- const markerFile = join27(homedir25(), ".claudish", ".legacy-litellm-hint-shown");
64921
- if (!existsSync21(markerFile)) {
65741
+ const markerFile = join28(homedir26(), ".claudish", ".legacy-litellm-hint-shown");
65742
+ if (!existsSync22(markerFile)) {
64922
65743
  const hint = buildLegacyHint(resolved);
64923
65744
  if (hint) {
64924
65745
  console.error(hint);
@@ -65985,7 +66806,7 @@ ${h("MORE INFO")}
65985
66806
  }
65986
66807
  function printAIAgentGuide() {
65987
66808
  try {
65988
- const guidePath = join27(__dirname3, "../AI_AGENT_GUIDE.md");
66809
+ const guidePath = join28(__dirname3, "../AI_AGENT_GUIDE.md");
65989
66810
  const guideContent = readFileSync21(guidePath, "utf-8");
65990
66811
  console.log(guideContent);
65991
66812
  } catch (error46) {
@@ -66002,19 +66823,19 @@ async function initializeClaudishSkill() {
66002
66823
  console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
66003
66824
  `);
66004
66825
  const cwd = process.cwd();
66005
- const claudeDir = join27(cwd, ".claude");
66006
- const skillsDir = join27(claudeDir, "skills");
66007
- const claudishSkillDir = join27(skillsDir, "claudish-usage");
66008
- const skillFile = join27(claudishSkillDir, "SKILL.md");
66009
- if (existsSync21(skillFile)) {
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)) {
66010
66831
  console.log("\u2705 Claudish skill already installed at:");
66011
66832
  console.log(` ${skillFile}
66012
66833
  `);
66013
66834
  console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
66014
66835
  return;
66015
66836
  }
66016
- const sourceSkillPath = join27(__dirname3, "../skills/claudish-usage/SKILL.md");
66017
- if (!existsSync21(sourceSkillPath)) {
66837
+ const sourceSkillPath = join28(__dirname3, "../skills/claudish-usage/SKILL.md");
66838
+ if (!existsSync22(sourceSkillPath)) {
66018
66839
  console.error("\u274C Error: Claudish skill file not found in installation.");
66019
66840
  console.error(` Expected at: ${sourceSkillPath}`);
66020
66841
  console.error(`
@@ -66023,15 +66844,15 @@ async function initializeClaudishSkill() {
66023
66844
  process.exit(1);
66024
66845
  }
66025
66846
  try {
66026
- if (!existsSync21(claudeDir)) {
66847
+ if (!existsSync22(claudeDir)) {
66027
66848
  mkdirSync13(claudeDir, { recursive: true });
66028
66849
  console.log("\uD83D\uDCC1 Created .claude/ directory");
66029
66850
  }
66030
- if (!existsSync21(skillsDir)) {
66851
+ if (!existsSync22(skillsDir)) {
66031
66852
  mkdirSync13(skillsDir, { recursive: true });
66032
66853
  console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
66033
66854
  }
66034
- if (!existsSync21(claudishSkillDir)) {
66855
+ if (!existsSync22(claudishSkillDir)) {
66035
66856
  mkdirSync13(claudishSkillDir, { recursive: true });
66036
66857
  console.log("\uD83D\uDCC1 Created .claude/skills/claudish-usage/ directory");
66037
66858
  }
@@ -66116,30 +66937,30 @@ __export(exports_update_checker, {
66116
66937
  clearCache: () => clearCache,
66117
66938
  checkForUpdates: () => checkForUpdates
66118
66939
  });
66119
- import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync22, unlinkSync as unlinkSync8, writeFileSync as writeFileSync16 } from "fs";
66120
- import { homedir as homedir26, platform as platform2, tmpdir } from "os";
66121
- import { join as join28 } from "path";
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";
66122
66943
  function getCacheFilePath() {
66123
66944
  let cacheDir;
66124
66945
  if (isWindows) {
66125
- const localAppData = process.env.LOCALAPPDATA || join28(homedir26(), "AppData", "Local");
66126
- cacheDir = join28(localAppData, "claudish");
66946
+ const localAppData = process.env.LOCALAPPDATA || join29(homedir27(), "AppData", "Local");
66947
+ cacheDir = join29(localAppData, "claudish");
66127
66948
  } else {
66128
- cacheDir = join28(homedir26(), ".cache", "claudish");
66949
+ cacheDir = join29(homedir27(), ".cache", "claudish");
66129
66950
  }
66130
66951
  try {
66131
- if (!existsSync22(cacheDir)) {
66952
+ if (!existsSync23(cacheDir)) {
66132
66953
  mkdirSync14(cacheDir, { recursive: true });
66133
66954
  }
66134
- return join28(cacheDir, "update-check.json");
66955
+ return join29(cacheDir, "update-check.json");
66135
66956
  } catch {
66136
- return join28(tmpdir(), "claudish-update-check.json");
66957
+ return join29(tmpdir(), "claudish-update-check.json");
66137
66958
  }
66138
66959
  }
66139
66960
  function readCache() {
66140
66961
  try {
66141
66962
  const cachePath = getCacheFilePath();
66142
- if (!existsSync22(cachePath)) {
66963
+ if (!existsSync23(cachePath)) {
66143
66964
  return null;
66144
66965
  }
66145
66966
  const data = JSON.parse(readFileSync22(cachePath, "utf-8"));
@@ -66165,7 +66986,7 @@ function isCacheValid(cache2) {
66165
66986
  function clearCache() {
66166
66987
  try {
66167
66988
  const cachePath = getCacheFilePath();
66168
- if (existsSync22(cachePath)) {
66989
+ if (existsSync23(cachePath)) {
66169
66990
  unlinkSync8(cachePath);
66170
66991
  }
66171
66992
  } catch {}
@@ -67013,16 +67834,22 @@ function localBaseUrl(catalogName) {
67013
67834
  }
67014
67835
  return (def.baseUrl || "").replace(/\/+$/, "") || null;
67015
67836
  }
67837
+ function isHtmlResponse(res) {
67838
+ const contentType = res.headers.get("content-type") ?? "";
67839
+ return /\btext\/html\b|\bapplication\/xhtml\+xml\b/i.test(contentType);
67840
+ }
67016
67841
  async function pingLocalProvider(catalogName, timeoutMs = PING_TIMEOUT_MS) {
67017
67842
  const base = localBaseUrl(catalogName);
67018
67843
  const path2 = HEALTH_PATH[catalogName];
67019
67844
  if (!base || !path2)
67020
67845
  return "unknown";
67021
67846
  try {
67022
- await fetch(`${base}${path2}`, {
67847
+ const res = await fetch(`${base}${path2}`, {
67023
67848
  method: "GET",
67024
67849
  signal: AbortSignal.timeout(timeoutMs)
67025
67850
  });
67851
+ if (res.ok && isHtmlResponse(res))
67852
+ return "down";
67026
67853
  return "running";
67027
67854
  } catch {
67028
67855
  return "down";
@@ -67044,11 +67871,11 @@ var init_local_liveness = __esm(() => {
67044
67871
  });
67045
67872
 
67046
67873
  // src/providers/probe-catalog.ts
67047
- import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync23, writeFileSync as writeFileSync17 } from "fs";
67048
- import { homedir as homedir27 } from "os";
67049
- import { dirname as dirname10, join as join29 } from "path";
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";
67050
67877
  function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
67051
- if (!existsSync23(path2))
67878
+ if (!existsSync24(path2))
67052
67879
  return null;
67053
67880
  let raw2;
67054
67881
  try {
@@ -67181,7 +68008,7 @@ function isValidResponse(raw2) {
67181
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;
67182
68009
  var init_probe_catalog = __esm(() => {
67183
68010
  CACHE_TTL_MS4 = 60 * 60 * 1000;
67184
- PROBE_MODELS_CACHE_PATH = join29(homedir27(), ".claudish", "probe-models.json");
68011
+ PROBE_MODELS_CACHE_PATH = join30(homedir28(), ".claudish", "probe-models.json");
67185
68012
  });
67186
68013
 
67187
68014
  // src/tui/constants.ts
@@ -73518,15 +74345,15 @@ __export(exports_claude_runner, {
73518
74345
  import { spawn as spawn4 } from "child_process";
73519
74346
  import {
73520
74347
  closeSync as closeSync5,
73521
- existsSync as existsSync24,
74348
+ existsSync as existsSync25,
73522
74349
  mkdirSync as mkdirSync16,
73523
74350
  openSync as openSync5,
73524
74351
  readFileSync as readFileSync24,
73525
74352
  unlinkSync as unlinkSync9,
73526
74353
  writeFileSync as writeFileSync18
73527
74354
  } from "fs";
73528
- import { homedir as homedir28, tmpdir as tmpdir2 } from "os";
73529
- import { join as join30 } from "path";
74355
+ import { homedir as homedir29, tmpdir as tmpdir2 } from "os";
74356
+ import { join as join31 } from "path";
73530
74357
  import { isatty } from "tty";
73531
74358
  function releaseTerminalIsolation() {
73532
74359
  if (!restoreTerminal)
@@ -73561,7 +74388,7 @@ function isProxyAuthMode(config3) {
73561
74388
  }
73562
74389
  function managedSettingsPath() {
73563
74390
  if (isWindows2()) {
73564
- return join30(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
74391
+ return join31(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
73565
74392
  }
73566
74393
  if (process.platform === "darwin") {
73567
74394
  return "/Library/Application Support/ClaudeCode/managed-settings.json";
@@ -73582,9 +74409,9 @@ function isWindows2() {
73582
74409
  }
73583
74410
  function createStatusLineScript(tokenFilePath) {
73584
74411
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
73585
- const claudishDir = join30(homeDir, ".claudish");
74412
+ const claudishDir = join31(homeDir, ".claudish");
73586
74413
  const timestamp = Date.now();
73587
- const scriptPath = join30(claudishDir, `status-${timestamp}.js`);
74414
+ const scriptPath = join31(claudishDir, `status-${timestamp}.js`);
73588
74415
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
73589
74416
  const script = `
73590
74417
  const fs = require('fs');
@@ -73707,13 +74534,13 @@ process.stdin.on('end', () => {
73707
74534
  }
73708
74535
  function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
73709
74536
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
73710
- const claudishDir = join30(homeDir, ".claudish");
74537
+ const claudishDir = join31(homeDir, ".claudish");
73711
74538
  try {
73712
74539
  mkdirSync16(claudishDir, { recursive: true });
73713
74540
  } catch {}
73714
74541
  const timestamp = Date.now();
73715
- const tempPath = join30(claudishDir, `settings-${timestamp}.json`);
73716
- const tokenFilePath = join30(claudishDir, `tokens-${port}.json`);
74542
+ const tempPath = join31(claudishDir, `settings-${timestamp}.json`);
74543
+ const tokenFilePath = join31(claudishDir, `tokens-${port}.json`);
73717
74544
  let statusCommand;
73718
74545
  if (isWindows2()) {
73719
74546
  const scriptPath = createStatusLineScript(tokenFilePath);
@@ -73928,8 +74755,8 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
73928
74755
  console.error("Install it from: https://claude.com/claude-code");
73929
74756
  console.error(`
73930
74757
  Or set CLAUDE_PATH to your custom installation:`);
73931
- const home = homedir28();
73932
- const localPath = isWindows2() ? join30(home, ".claude", "local", "claude.exe") : join30(home, ".claude", "local", "claude");
74758
+ const home = homedir29();
74759
+ const localPath = isWindows2() ? join31(home, ".claude", "local", "claude.exe") : join31(home, ".claude", "local", "claude");
73933
74760
  console.error(` export CLAUDE_PATH=${localPath}`);
73934
74761
  process.exit(1);
73935
74762
  }
@@ -74009,23 +74836,23 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
74009
74836
  async function findClaudeBinary() {
74010
74837
  const isWindows3 = process.platform === "win32";
74011
74838
  if (process.env.CLAUDE_PATH) {
74012
- if (existsSync24(process.env.CLAUDE_PATH)) {
74839
+ if (existsSync25(process.env.CLAUDE_PATH)) {
74013
74840
  return process.env.CLAUDE_PATH;
74014
74841
  }
74015
74842
  }
74016
- const home = homedir28();
74017
- const localPath = isWindows3 ? join30(home, ".claude", "local", "claude.exe") : join30(home, ".claude", "local", "claude");
74018
- if (existsSync24(localPath)) {
74843
+ const home = homedir29();
74844
+ const localPath = isWindows3 ? join31(home, ".claude", "local", "claude.exe") : join31(home, ".claude", "local", "claude");
74845
+ if (existsSync25(localPath)) {
74019
74846
  return localPath;
74020
74847
  }
74021
74848
  if (isWindows3) {
74022
74849
  const windowsPaths = [
74023
- join30(home, "AppData", "Roaming", "npm", "claude.cmd"),
74024
- join30(home, ".npm-global", "claude.cmd"),
74025
- join30(home, "node_modules", ".bin", "claude.cmd")
74850
+ join31(home, "AppData", "Roaming", "npm", "claude.cmd"),
74851
+ join31(home, ".npm-global", "claude.cmd"),
74852
+ join31(home, "node_modules", ".bin", "claude.cmd")
74026
74853
  ];
74027
74854
  for (const path2 of windowsPaths) {
74028
- if (existsSync24(path2)) {
74855
+ if (existsSync25(path2)) {
74029
74856
  return path2;
74030
74857
  }
74031
74858
  }
@@ -74033,14 +74860,14 @@ async function findClaudeBinary() {
74033
74860
  const commonPaths = [
74034
74861
  "/usr/local/bin/claude",
74035
74862
  "/opt/homebrew/bin/claude",
74036
- join30(home, ".npm-global/bin/claude"),
74037
- join30(home, ".local/bin/claude"),
74038
- join30(home, "node_modules/.bin/claude"),
74863
+ join31(home, ".npm-global/bin/claude"),
74864
+ join31(home, ".local/bin/claude"),
74865
+ join31(home, "node_modules/.bin/claude"),
74039
74866
  "/data/data/com.termux/files/usr/bin/claude",
74040
- join30(home, "../usr/bin/claude")
74867
+ join31(home, "../usr/bin/claude")
74041
74868
  ];
74042
74869
  for (const path2 of commonPaths) {
74043
- if (existsSync24(path2)) {
74870
+ if (existsSync25(path2)) {
74044
74871
  return path2;
74045
74872
  }
74046
74873
  }
@@ -74098,17 +74925,17 @@ __export(exports_diag_output, {
74098
74925
  LogFileDiagOutput: () => LogFileDiagOutput
74099
74926
  });
74100
74927
  import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync17, unlinkSync as unlinkSync10, writeFileSync as writeFileSync19 } from "fs";
74101
- import { homedir as homedir29 } from "os";
74102
- import { join as join31 } from "path";
74928
+ import { homedir as homedir30 } from "os";
74929
+ import { join as join32 } from "path";
74103
74930
  function getClaudishDir() {
74104
- const dir = join31(homedir29(), ".claudish");
74931
+ const dir = join32(homedir30(), ".claudish");
74105
74932
  try {
74106
74933
  mkdirSync17(dir, { recursive: true });
74107
74934
  } catch {}
74108
74935
  return dir;
74109
74936
  }
74110
74937
  function getDiagLogPath() {
74111
- return join31(getClaudishDir(), `diag-${process.pid}.log`);
74938
+ return join32(getClaudishDir(), `diag-${process.pid}.log`);
74112
74939
  }
74113
74940
 
74114
74941
  class LogFileDiagOutput {
@@ -74319,9 +75146,9 @@ __export(exports_team_grid, {
74319
75146
  });
74320
75147
  import { spawn as spawn5 } from "child_process";
74321
75148
  import { execSync as execSync2 } from "child_process";
74322
- import { existsSync as existsSync25, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
75149
+ import { existsSync as existsSync26, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
74323
75150
  import { connect as netConnect } from "net";
74324
- import { dirname as dirname11, join as join32 } from "path";
75151
+ import { dirname as dirname11, join as join33 } from "path";
74325
75152
  import { setTimeout as wait } from "timers/promises";
74326
75153
  import { fileURLToPath as fileURLToPath3 } from "url";
74327
75154
  function resolveRouteInfo(modelId) {
@@ -74415,18 +75242,18 @@ function buildPaneHeader(model, prompt, bg) {
74415
75242
  function findMagmuxBinary() {
74416
75243
  const thisFile = fileURLToPath3(import.meta.url);
74417
75244
  const thisDir = dirname11(thisFile);
74418
- const pkgRoot = join32(thisDir, "..");
75245
+ const pkgRoot = join33(thisDir, "..");
74419
75246
  const platform3 = process.platform;
74420
75247
  const arch = process.arch;
74421
- const bundledMagmux = join32(pkgRoot, "native", `magmux-${platform3}-${arch}`);
74422
- if (existsSync25(bundledMagmux))
75248
+ const bundledMagmux = join33(pkgRoot, "native", `magmux-${platform3}-${arch}`);
75249
+ if (existsSync26(bundledMagmux))
74423
75250
  return bundledMagmux;
74424
75251
  try {
74425
75252
  const pkgName = `@claudish/magmux-${platform3}-${arch}`;
74426
75253
  let searchDir = pkgRoot;
74427
75254
  for (let i = 0;i < 5; i++) {
74428
- const candidate = join32(searchDir, "node_modules", pkgName, "bin", "magmux");
74429
- if (existsSync25(candidate))
75255
+ const candidate = join33(searchDir, "node_modules", pkgName, "bin", "magmux");
75256
+ if (existsSync26(candidate))
74430
75257
  return candidate;
74431
75258
  const parent = dirname11(searchDir);
74432
75259
  if (parent === searchDir)
@@ -74445,7 +75272,7 @@ function findMagmuxBinary() {
74445
75272
  async function subscribeToMagmux(sockPath, onEvent) {
74446
75273
  let client = null;
74447
75274
  for (let attempt = 0;attempt < 40; attempt++) {
74448
- if (existsSync25(sockPath)) {
75275
+ if (existsSync26(sockPath)) {
74449
75276
  try {
74450
75277
  client = await new Promise((resolve4, reject) => {
74451
75278
  const s = netConnect(sockPath);
@@ -74532,9 +75359,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
74532
75359
  const keep = opts?.keep ?? false;
74533
75360
  const manifest = setupSession(sessionPath, models, input);
74534
75361
  const startedAt = new Date().toISOString();
74535
- const gridfilePath = join32(sessionPath, "gridfile.txt");
74536
- const prompt = readFileSync25(join32(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
74537
- const rawPrompt = readFileSync25(join32(sessionPath, "input.md"), "utf-8");
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");
74538
75365
  const usedBannerColors = new Set;
74539
75366
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
74540
75367
  const model = manifest.models[anonId].model;
@@ -74565,7 +75392,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
74565
75392
  });
74566
75393
  const [{ results }] = await Promise.all([subscription, procExit]);
74567
75394
  const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
74568
- const statusPath = join32(sessionPath, "status.json");
75395
+ const statusPath = join33(sessionPath, "status.json");
74569
75396
  writeFileSync20(statusPath, JSON.stringify(status, null, 2), "utf-8");
74570
75397
  return status;
74571
75398
  }
@@ -74589,8 +75416,8 @@ var init_team_grid = __esm(() => {
74589
75416
  init_op_source();
74590
75417
  init_startup_trace();
74591
75418
  var import_dotenv3 = __toESM(require_main(), 1);
74592
- import { existsSync as existsSync26, readFileSync as readFileSync26 } from "fs";
74593
- import { join as join33, resolve as resolve4 } from "path";
75419
+ import { existsSync as existsSync27, readFileSync as readFileSync26 } from "fs";
75420
+ import { join as join34, resolve as resolve4 } from "path";
74594
75421
  import_dotenv3.config({ quiet: true });
74595
75422
  function classifyStartupKind() {
74596
75423
  const argv = process.argv.slice(2);
@@ -74689,7 +75516,7 @@ async function applyConfigOverride() {
74689
75516
  const { planConfigOverride: planConfigOverride2, setConfigFileOverride: setConfigFileOverride2 } = await Promise.resolve().then(() => exports_config_override);
74690
75517
  const plan = planConfigOverride2(process.argv.slice(2), process.env, {
74691
75518
  resolve: resolve4,
74692
- exists: existsSync26
75519
+ exists: existsSync27
74693
75520
  });
74694
75521
  if (plan.kind === "none")
74695
75522
  return;
@@ -74838,7 +75665,7 @@ async function runCli() {
74838
75665
  process.exit(1);
74839
75666
  }
74840
75667
  const mode = cliConfig.teamMode ?? "default";
74841
- const sessionPath = join33(process.cwd(), `.claudish-team-${Date.now()}`);
75668
+ const sessionPath = join34(process.cwd(), `.claudish-team-${Date.now()}`);
74842
75669
  if (mode === "json") {
74843
75670
  const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
74844
75671
  setupSession2(sessionPath, cliConfig.team, prompt);
@@ -74848,7 +75675,7 @@ async function runCli() {
74848
75675
  });
74849
75676
  const result = { ...status2, responses: {} };
74850
75677
  for (const anonId of Object.keys(status2.models)) {
74851
- const responsePath = join33(sessionPath, `response-${anonId}.md`);
75678
+ const responsePath = join34(sessionPath, `response-${anonId}.md`);
74852
75679
  try {
74853
75680
  const raw2 = readFileSync26(responsePath, "utf-8").trim();
74854
75681
  try {