@kenkaiiii/gg-core 5.22.3 → 5.22.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-TST5LJWL.js → chunk-EM7AJOOC.js} +10 -4
- package/dist/chunk-EM7AJOOC.js.map +1 -0
- package/dist/index.cjs +9 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -1
- package/dist/model-registry.cjs.map +1 -1
- package/dist/model-registry.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-TST5LJWL.js.map +0 -1
|
@@ -126,6 +126,7 @@ function credsFromTokenResponse(data, opts) {
|
|
|
126
126
|
accessToken,
|
|
127
127
|
refreshToken,
|
|
128
128
|
expiresAt: Date.now() + expiresIn * 1e3,
|
|
129
|
+
expiresIn,
|
|
129
130
|
baseUrl: kimiCodeBaseUrl()
|
|
130
131
|
};
|
|
131
132
|
}
|
|
@@ -1178,7 +1179,12 @@ function readStoredBaseUrlSync(authFile, provider) {
|
|
|
1178
1179
|
return void 0;
|
|
1179
1180
|
}
|
|
1180
1181
|
}
|
|
1181
|
-
var
|
|
1182
|
+
var MIN_REFRESH_THRESHOLD_MS = 3e5;
|
|
1183
|
+
var REFRESH_THRESHOLD_RATIO = 0.5;
|
|
1184
|
+
function refreshThresholdMs(creds) {
|
|
1185
|
+
const lifetimeMs = (creds.expiresIn ?? 0) * 1e3;
|
|
1186
|
+
return Math.max(MIN_REFRESH_THRESHOLD_MS, lifetimeMs * REFRESH_THRESHOLD_RATIO);
|
|
1187
|
+
}
|
|
1182
1188
|
var USAGE_EXHAUSTED_DEFAULT_MS = 15 * 60 * 1e3;
|
|
1183
1189
|
var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
|
|
1184
1190
|
"glm",
|
|
@@ -1412,7 +1418,7 @@ var AuthStorage = class {
|
|
|
1412
1418
|
if (STATIC_API_KEY_PROVIDERS.has(provider)) {
|
|
1413
1419
|
return creds;
|
|
1414
1420
|
}
|
|
1415
|
-
if (!opts?.forceRefresh && Date.now() < creds.expiresAt -
|
|
1421
|
+
if (!opts?.forceRefresh && Date.now() < creds.expiresAt - refreshThresholdMs(creds)) {
|
|
1416
1422
|
return creds;
|
|
1417
1423
|
}
|
|
1418
1424
|
const existing = this.refreshLocks.get(provider);
|
|
@@ -1425,7 +1431,7 @@ var AuthStorage = class {
|
|
|
1425
1431
|
throw new NotLoggedInError(provider);
|
|
1426
1432
|
}
|
|
1427
1433
|
const credentialWasReplaced = latestCreds.accessToken !== creds.accessToken || latestCreds.refreshToken !== creds.refreshToken || latestCreds.expiresAt !== creds.expiresAt;
|
|
1428
|
-
if (credentialWasReplaced || !opts?.forceRefresh && Date.now() < latestCreds.expiresAt -
|
|
1434
|
+
if (credentialWasReplaced || !opts?.forceRefresh && Date.now() < latestCreds.expiresAt - refreshThresholdMs(latestCreds)) {
|
|
1429
1435
|
this.data = latest;
|
|
1430
1436
|
return latestCreds;
|
|
1431
1437
|
}
|
|
@@ -2036,4 +2042,4 @@ export {
|
|
|
2036
2042
|
getSummaryModel,
|
|
2037
2043
|
getFastModel
|
|
2038
2044
|
};
|
|
2039
|
-
//# sourceMappingURL=chunk-
|
|
2045
|
+
//# sourceMappingURL=chunk-EM7AJOOC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/oauth/kimi.ts","../src/auth-storage.ts","../src/oauth/anthropic.ts","../src/oauth/pkce.ts","../src/claude-code-version.ts","../src/logger.ts","../src/oauth/openai.ts","../src/oauth/gemini.ts","../src/file-lock.ts","../src/model-registry.ts"],"sourcesContent":["/**\n * Kimi Code OAuth — Device Authorization Grant (RFC 8628).\n *\n * Mirrors MoonshotAI/kimi-code's managed-auth flow. Three form-encoded\n * POST endpoints against the OAuth host (default `https://auth.kimi.com`):\n *\n * - `/api/oauth/device_authorization` (client_id) → device + user code\n * - `/api/oauth/token` (grant_type=device_code) → poll until authorized\n * - `/api/oauth/token` (grant_type=refresh_token) → refresh access token\n *\n * Unlike Anthropic/OpenAI/Gemini (browser-redirect PKCE), this is a\n * device-code/poll flow: we show the user a URL + code, they authorize in a\n * browser on any device, and we poll for the token.\n *\n * After login the issued token is used against the managed coding API\n * (`https://api.kimi.com/coding/v1`, distinct from the `api.moonshot.ai`\n * API-key endpoint) via `Authorization: Bearer <access_token>`. We persist\n * that base URL on the credential so the runtime routes there automatically.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { arch, hostname, release, type } from \"node:os\";\nimport path from \"node:path\";\n\nimport { getAppPaths } from \"../paths.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\n/** Public OAuth client id registered by Kimi Code (no client secret / PKCE). */\nconst CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\n\nconst DEFAULT_OAUTH_HOST = \"https://auth.kimi.com\";\nconst DEFAULT_CODING_BASE_URL = \"https://api.kimi.com/coding/v1\";\n\n/** Platform identifier Kimi Code reports for the device flow. */\nconst KIMI_PLATFORM = \"kimi_code_cli\";\n// Must match (or exceed) the current published `kimi-code` CLI version. The\n// managed coding endpoint gates on the `kimi-code-cli` client identity and\n// REJECTS versions below its expected minimum with a 403 \"only available for\n// Coding Agents\". Keep aligned with the latest npm `kimi-code` release;\n// overridable via KIMI_CODE_VERSION.\nconst DEFAULT_KIMI_VERSION = \"1.0.11\";\n\n/** Local wall-clock budget for the whole device flow (15 min, matches Kimi). */\nconst DEVICE_TIMEOUT_MS = 15 * 60 * 1000;\n\nfunction oauthHost(): string {\n const host =\n process.env.KIMI_CODE_OAUTH_HOST ?? process.env.KIMI_OAUTH_HOST ?? DEFAULT_OAUTH_HOST;\n return host.replace(/\\/+$/, \"\");\n}\n\n/** Managed coding API base URL the issued OAuth token is used against. */\nexport function kimiCodeBaseUrl(): string {\n return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\\/+$/, \"\");\n}\n\nfunction kimiVersion(): string {\n const v = process.env.KIMI_CODE_VERSION ?? DEFAULT_KIMI_VERSION;\n return asciiHeader(v, DEFAULT_KIMI_VERSION);\n}\n\nfunction asciiHeader(value: string, fallback = \"unknown\"): string {\n const cleaned = value.replace(/[^\\u0020-\\u007E]/g, \"\").trim();\n return cleaned.length > 0 ? cleaned : fallback;\n}\n\nfunction macOsProductVersion(): string | undefined {\n try {\n const version = execFileSync(\"/usr/bin/sw_vers\", [\"-productVersion\"], {\n encoding: \"utf-8\",\n timeout: 1000,\n }).trim();\n return version.length > 0 ? version : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction deviceModel(): string {\n const os = type();\n const version = release();\n const osArch = arch();\n if (os === \"Darwin\") return `macOS ${macOsProductVersion() ?? version} ${osArch}`;\n if (os === \"Windows_NT\") return `Windows ${version} ${osArch}`;\n return `${os} ${version} ${osArch}`.trim();\n}\n\n/** Stable per-machine device id, persisted under the gg config dir. */\nfunction deviceId(): string {\n const idPath = path.join(getAppPaths().agentDir, \"kimi_device_id\");\n if (existsSync(idPath)) {\n try {\n const text = readFileSync(idPath, \"utf-8\").trim();\n if (text.length > 0) return text;\n } catch {\n // fall through to regenerate\n }\n }\n const id = randomUUID();\n try {\n mkdirSync(getAppPaths().agentDir, { recursive: true, mode: 0o700 });\n writeFileSync(idPath, id, { encoding: \"utf-8\", mode: 0o600 });\n } catch {\n // best-effort: in-memory id still works for this run\n }\n return id;\n}\n\nfunction deviceHeaders(): Record<string, string> {\n return {\n \"X-Msh-Platform\": KIMI_PLATFORM,\n \"X-Msh-Version\": kimiVersion(),\n \"X-Msh-Device-Name\": asciiHeader(hostname()),\n \"X-Msh-Device-Model\": asciiHeader(deviceModel()),\n \"X-Msh-Os-Version\": asciiHeader(release()),\n \"X-Msh-Device-Id\": deviceId(),\n };\n}\n\n/**\n * Headers the Kimi For Coding API requires on every model request. The\n * managed endpoint gates access to recognized coding agents: requests must\n * carry a `kimi_code_cli` platform identity and matching `User-Agent`, or the\n * server rejects with \"only available for Coding Agents\". Attach these to the\n * inference client's default headers whenever the Kimi OAuth token is used.\n */\nexport function kimiCodingHeaders(): Record<string, string> {\n return {\n \"User-Agent\": `kimi-code-cli/${kimiVersion()}`,\n ...deviceHeaders(),\n };\n}\n\n/**\n * True if `baseUrl` targets the Kimi For Coding managed endpoint (the URL\n * persisted on Kimi OAuth credentials). Callers use this to decide whether to\n * attach `kimiCodingHeaders()` — the Moonshot API-key path uses a different\n * host and must NOT receive the coding-agent identity headers.\n */\nexport function isKimiCodingEndpoint(baseUrl: string | undefined): boolean {\n if (typeof baseUrl !== \"string\" || baseUrl.length === 0) return false;\n const normalized = baseUrl.replace(/\\/+$/, \"\");\n return normalized === kimiCodeBaseUrl() || /(^|\\.)kimi\\.com/i.test(normalized);\n}\n\nasync function postForm(\n endpoint: string,\n params: Record<string, string>,\n): Promise<{ status: number; data: Record<string, unknown> }> {\n const response = await fetch(`${oauthHost()}${endpoint}`, {\n method: \"POST\",\n headers: {\n ...deviceHeaders(),\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body: new URLSearchParams(params).toString(),\n });\n let data: Record<string, unknown> = {};\n try {\n const parsed: unknown = await response.json();\n if (parsed && typeof parsed === \"object\") data = parsed as Record<string, unknown>;\n } catch {\n // non-JSON response — interpret by status\n }\n return { status: response.status, data };\n}\n\nfunction errorDetail(data: Record<string, unknown>): string {\n const desc = data.error_description ?? data.message ?? data.error;\n return typeof desc === \"string\" && desc.length > 0 ? desc : \"unknown error\";\n}\n\nfunction credsFromTokenResponse(\n data: Record<string, unknown>,\n opts?: { fallbackRefreshToken?: string },\n): OAuthCredentials {\n const accessToken = data.access_token;\n const responseRefreshToken = data.refresh_token;\n const expiresIn = Number(data.expires_in);\n if (typeof accessToken !== \"string\" || accessToken.length === 0) {\n throw new Error(\"Kimi OAuth response missing access_token.\");\n }\n // OAuth servers may rotate the refresh token (returning a new one) OR keep\n // the existing one (omitting it from the refresh response). Honor a rotated\n // token when present, otherwise reuse the caller's existing refresh token so\n // a non-rotating refresh never strands the credential. Only the initial\n // device-code exchange (no fallback) hard-requires a refresh token.\n const refreshToken =\n typeof responseRefreshToken === \"string\" && responseRefreshToken.length > 0\n ? responseRefreshToken\n : (opts?.fallbackRefreshToken ?? \"\");\n if (refreshToken.length === 0) {\n throw new Error(\"Kimi OAuth response missing refresh_token.\");\n }\n if (!Number.isFinite(expiresIn) || expiresIn <= 0) {\n throw new Error(\"Kimi OAuth response missing or invalid expires_in.\");\n }\n return {\n accessToken,\n refreshToken,\n expiresAt: Date.now() + expiresIn * 1000,\n expiresIn,\n baseUrl: kimiCodeBaseUrl(),\n };\n}\n\ninterface DeviceAuthorization {\n userCode: string;\n deviceCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n interval: number;\n}\n\nasync function requestDeviceAuthorization(): Promise<DeviceAuthorization> {\n const { status, data } = await postForm(\"/api/oauth/device_authorization\", {\n client_id: CLIENT_ID,\n });\n if (status !== 200) {\n throw new Error(`Kimi device authorization failed (${status}): ${errorDetail(data)}`);\n }\n const userCode = data.user_code;\n const deviceCode = data.device_code;\n const verificationUriComplete = data.verification_uri_complete;\n if (typeof userCode !== \"string\" || typeof deviceCode !== \"string\") {\n throw new Error(\"Kimi device authorization response missing user_code/device_code.\");\n }\n return {\n userCode,\n deviceCode,\n verificationUri: typeof data.verification_uri === \"string\" ? data.verification_uri : \"\",\n verificationUriComplete:\n typeof verificationUriComplete === \"string\" ? verificationUriComplete : \"\",\n interval: Number(data.interval ?? 5) || 5,\n };\n}\n\ntype PollResult =\n | { kind: \"success\"; creds: OAuthCredentials }\n | { kind: \"pending\" }\n | { kind: \"slow_down\" }\n | { kind: \"expired\" }\n | { kind: \"denied\" };\n\nasync function pollDeviceToken(deviceCode: string): Promise<PollResult> {\n const { status, data } = await postForm(\"/api/oauth/token\", {\n client_id: CLIENT_ID,\n device_code: deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n });\n if (status === 200 && typeof data.access_token === \"string\") {\n return { kind: \"success\", creds: credsFromTokenResponse(data) };\n }\n if (status >= 500) {\n throw new Error(`Kimi token polling server error (${status}): ${errorDetail(data)}`);\n }\n const errorCode = typeof data.error === \"string\" ? data.error : \"unknown_error\";\n switch (errorCode) {\n case \"authorization_pending\":\n return { kind: \"pending\" };\n case \"slow_down\":\n return { kind: \"slow_down\" };\n case \"expired_token\":\n return { kind: \"expired\" };\n case \"access_denied\":\n return { kind: \"denied\" };\n default:\n throw new Error(`Kimi token polling failed (${status}): ${errorDetail(data)}`);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\n/**\n * Drive the Kimi device-code flow end-to-end. Shows the verification URL +\n * user code via callbacks, opens the browser, and polls until the user\n * authorizes (or a 15-minute local timeout elapses).\n */\nexport async function loginKimi(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const auth = await requestDeviceAuthorization();\n\n callbacks.onStatus(\n `Visit ${auth.verificationUri || auth.verificationUriComplete} and enter code: ${auth.userCode}`,\n );\n callbacks.onOpenUrl(auth.verificationUriComplete || auth.verificationUri);\n callbacks.onStatus(\"Waiting for you to authorize in the browser...\");\n\n const deadline = Date.now() + DEVICE_TIMEOUT_MS;\n let interval = Math.max(auth.interval, 1);\n\n while (Date.now() < deadline) {\n await sleep(interval * 1000);\n const result = await pollDeviceToken(auth.deviceCode);\n if (result.kind === \"success\") return result.creds;\n if (result.kind === \"denied\") {\n throw new Error(\"Kimi authorization was denied.\");\n }\n if (result.kind === \"expired\") {\n throw new Error(\"Kimi device code expired. Please run login again.\");\n }\n if (result.kind === \"slow_down\") {\n interval += 5;\n }\n // pending → keep polling\n }\n\n throw new Error(\"Kimi login timed out. Please run login again.\");\n}\n\n/** Exchange a refresh token for a fresh Kimi access token. */\nexport async function refreshKimiToken(refreshToken: string): Promise<OAuthCredentials> {\n const { status, data } = await postForm(\"/api/oauth/token\", {\n client_id: CLIENT_ID,\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n });\n if (status === 200 && typeof data.access_token === \"string\") {\n return credsFromTokenResponse(data, { fallbackRefreshToken: refreshToken });\n }\n const errorCode = typeof data.error === \"string\" ? data.error : \"\";\n // Surface 401/403/invalid_grant in a shape AuthStorage's refresh-failure\n // detection recognizes, so dead refresh tokens get wiped for re-login.\n throw new Error(`Kimi token refresh failed (${status}): ${errorCode || errorDetail(data)}`);\n}\n","import fs from \"node:fs/promises\";\nimport { readFileSync } from \"node:fs\";\nimport crypto from \"node:crypto\";\nimport { getAppPaths } from \"./paths.js\";\nimport type { OAuthCredentials } from \"./oauth/types.js\";\nimport { refreshAnthropicToken } from \"./oauth/anthropic.js\";\nimport { refreshOpenAIToken } from \"./oauth/openai.js\";\nimport { refreshGeminiToken } from \"./oauth/gemini.js\";\nimport { refreshKimiToken } from \"./oauth/kimi.js\";\nimport { withFileLock } from \"./file-lock.js\";\nimport { log } from \"./logger.js\";\n\ntype AuthData = Record<string, OAuthCredentials>;\n\n/**\n * Storage key for Kimi Code OAuth credentials. Kept distinct from the\n * `moonshot` API-key entry so a user can configure BOTH and we always\n * prefer OAuth for the logical `moonshot` provider.\n */\nexport const MOONSHOT_OAUTH_KEY = \"moonshot-oauth\";\n\n/**\n * Storage key for the Xiaomi API Credits credential (`https://api.xiaomimimo.com/v1`).\n * Kept distinct from the `xiaomi` Token Plan entry (`token-plan-sgp.xiaomimimo.com`)\n * so a user can configure BOTH — `mimo-v2.5-pro-ultraspeed` is API Credits-only,\n * while `mimo-v2.5-pro`/`mimo-v2.5` prefer the Token Plan but fall back to API\n * Credits when only that's configured. Which key(s) a model tries, and in what\n * order, is decided per-model via `getAuthStorageKeys()` in model-registry.ts.\n */\nexport const XIAOMI_CREDITS_KEY = \"xiaomi-credits\";\n\n/**\n * The credential entry whose baseUrl applies right now. For `moonshot` this\n * mirrors resolveCredentials' preference: the Kimi OAuth entry, sidelined to\n * the Moonshot API key only while its usage window is exhausted and a key is\n * configured. Shared by {@link AuthStorage.getStoredBaseUrl} and\n * {@link readStoredBaseUrlSync} so both paths agree on the active endpoint.\n */\nfunction activeBaseUrlEntry(data: AuthData, provider: string): OAuthCredentials | undefined {\n if (provider === \"moonshot\") {\n const oauth = data[MOONSHOT_OAUTH_KEY];\n if (oauth) {\n const exhaustedUntil = oauth.usageExhaustedUntil ?? 0;\n if (Date.now() < exhaustedUntil && data[\"moonshot\"]) return data[\"moonshot\"];\n return oauth;\n }\n return data[\"moonshot\"];\n }\n return data[provider];\n}\n\n/**\n * Synchronous baseUrl read straight from the auth file, for boot paths that\n * need the active endpoint before an AuthStorage instance exists (e.g. the\n * CLI's sync main()). Missing/corrupt files yield undefined — callers treat\n * that as the provider's public endpoint. Read-only: safe without the file\n * lock (a torn mid-write read just falls back to undefined).\n */\nexport function readStoredBaseUrlSync(authFile: string, provider: string): string | undefined {\n try {\n const data = JSON.parse(readFileSync(authFile, \"utf-8\")) as AuthData;\n return activeBaseUrlEntry(data, provider)?.baseUrl;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Proactive-refresh threshold, ported from MoonshotAI/kimi-code's OAuthManager\n * (`defaultRefreshThreshold`): refresh when the token is within\n * `max(MIN_REFRESH_THRESHOLD_MS, lifetime * REFRESH_THRESHOLD_RATIO)` of expiry.\n *\n * A flat skew is wrong for short-lived tokens. Kimi access tokens live only\n * 15 min, so a 60s skew rode them to the boundary and reliably 401'd — misread\n * as a dead credential, silently falling back to a static API key (or hard-\n * failing the run when a concurrent-session refresh race rotated the token).\n * Scaling by lifetime refreshes a 15-min token at its 7.5-min halfway point,\n * and never earlier than 5 min before expiry for longer-lived tokens.\n */\nconst MIN_REFRESH_THRESHOLD_MS = 300_000;\nconst REFRESH_THRESHOLD_RATIO = 0.5;\n\nfunction refreshThresholdMs(creds: OAuthCredentials): number {\n const lifetimeMs = (creds.expiresIn ?? 0) * 1000;\n return Math.max(MIN_REFRESH_THRESHOLD_MS, lifetimeMs * REFRESH_THRESHOLD_RATIO);\n}\n\n/**\n * How long a usage-exhausted mark holds when the provider gave no reset time.\n * Short on purpose: after it lapses we try the preferred (OAuth) credential\n * again — if the window is still out, the caller re-marks and falls back again,\n * costing one rejected request per window instead of sticking to the fallback\n * key forever.\n */\nconst USAGE_EXHAUSTED_DEFAULT_MS = 15 * 60 * 1000;\n\n/** Providers whose credentials are static API keys (no refresh mechanism). */\nconst STATIC_API_KEY_PROVIDERS = new Set([\n \"glm\",\n \"moonshot\",\n \"xiaomi\",\n \"minimax\",\n \"deepseek\",\n \"openrouter\",\n \"sakana\",\n \"xai\",\n]);\n\nexport class AuthStorage {\n private data: AuthData = {};\n private filePath: string;\n private loaded = false;\n /** Per-provider lock to serialize concurrent refresh calls. */\n private refreshLocks = new Map<string, Promise<OAuthCredentials>>();\n\n constructor(filePath?: string) {\n this.filePath = filePath ?? getAppPaths().authFile;\n }\n\n /** Path to the on-disk auth file. Useful for status output. */\n get path(): string {\n return this.filePath;\n }\n\n /** List provider keys with stored credentials. */\n async listProviders(): Promise<string[]> {\n await this.ensureLoaded();\n return Object.keys(this.data);\n }\n\n /** True if credentials exist for `provider`. */\n async hasCredentials(provider: string): Promise<boolean> {\n await this.ensureLoaded();\n return Boolean(this.data[provider]);\n }\n\n /**\n * First key in `keys` (in order) that has stored credentials, or `undefined`\n * if none do. Mirrors the first-match logic `resolveCredentials({ storageKeys })`\n * uses internally — callers that need to know WHICH credential will actually\n * be used (e.g. to clear the right one after a 401) call this directly\n * instead of re-deriving the same order.\n */\n async pickStorageKey(keys: string[]): Promise<string | undefined> {\n await this.ensureLoaded();\n return keys.find((key) => Boolean(this.data[key]));\n }\n\n /**\n * True if the user has any usable auth for the logical provider. For\n * `moonshot` this is satisfied by either the Kimi OAuth credential or the\n * Moonshot API key.\n */\n async hasProviderAuth(provider: string): Promise<boolean> {\n await this.ensureLoaded();\n if (provider === \"moonshot\") {\n return Boolean(this.data[MOONSHOT_OAUTH_KEY] || this.data[\"moonshot\"]);\n }\n if (provider === \"xiaomi\") {\n return Boolean(this.data[\"xiaomi\"] || this.data[XIAOMI_CREDITS_KEY]);\n }\n return Boolean(this.data[provider]);\n }\n\n /**\n * True if the active credential for `provider` is a static API key with no\n * refresh mechanism. For `moonshot` this is only true when the Kimi OAuth\n * credential is absent (a present OAuth credential is refreshable).\n */\n async isStaticApiKey(provider: string): Promise<boolean> {\n await this.ensureLoaded();\n if (provider === \"moonshot\" && this.data[MOONSHOT_OAUTH_KEY]) {\n // A usage-exhausted OAuth credential with an API key configured means\n // the API key is what actually resolves right now — treat it as the\n // static key it is (so a 401 clears the key instead of pointlessly\n // force-refreshing the sidelined OAuth token).\n const exhaustedUntil = this.data[MOONSHOT_OAUTH_KEY].usageExhaustedUntil ?? 0;\n const apiKeyActive = Date.now() < exhaustedUntil && Boolean(this.data[\"moonshot\"]);\n if (!apiKeyActive) return false;\n }\n return STATIC_API_KEY_PROVIDERS.has(provider);\n }\n\n /**\n * The base URL on the credential that is active right now, if any.\n * Synchronous — call only after load()/resolveCredentials() populated the\n * snapshot. For `moonshot` this is the Kimi For Coding URL whenever the\n * OAuth entry is the one resolveCredentials would serve (i.e. not currently\n * usage-exhausted with an API key configured).\n */\n getStoredBaseUrl(provider: string): string | undefined {\n return activeBaseUrlEntry(this.data, provider)?.baseUrl;\n }\n\n async load(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n try {\n const content = await fs.readFile(this.filePath, \"utf-8\");\n this.data = JSON.parse(content) as AuthData;\n log(\"INFO\", \"auth\", `Loaded credentials from ${this.filePath}`, {\n providers: Object.keys(this.data).join(\",\") || \"(none)\",\n });\n } catch (err) {\n this.data = {};\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") {\n log(\"INFO\", \"auth\", `No auth file found at ${this.filePath} (first run)`);\n } else {\n log(\n \"ERROR\",\n \"auth\",\n `Failed to load auth file: ${err instanceof Error ? err.message : String(err)}`,\n { path: this.filePath, code: code ?? \"unknown\" },\n );\n }\n }\n });\n this.loaded = true;\n }\n\n private async ensureLoaded(): Promise<void> {\n if (!this.loaded) await this.load();\n }\n\n /**\n * Apply one provider-scoped mutation to the latest on-disk snapshot.\n * AuthStorage instances live in every app session/process, so writing this\n * instance's cached snapshot can erase credentials another instance just\n * added. The file lock only serializes writers; the re-read prevents stale\n * full-file overwrites.\n */\n private async mutateLatest(mutator: (data: AuthData) => void): Promise<void> {\n await this.ensureLoaded();\n await withFileLock(this.filePath, async () => {\n const latest = await readAuthData(this.filePath);\n mutator(latest);\n await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));\n this.data = latest;\n });\n }\n\n private async reloadLatest(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n this.data = await readAuthData(this.filePath);\n });\n }\n\n async getCredentials(provider: string): Promise<OAuthCredentials | undefined> {\n await this.ensureLoaded();\n return this.data[provider];\n }\n\n async setCredentials(provider: string, creds: OAuthCredentials): Promise<void> {\n await this.mutateLatest((latest) => {\n latest[provider] = creds;\n });\n }\n\n async clearCredentials(provider: string): Promise<void> {\n await this.mutateLatest((latest) => {\n delete latest[provider];\n });\n }\n\n /**\n * Mark the credential stored under `storageKey` as usage-exhausted until\n * `resetsAt` (unix SECONDS, from the provider's rate-limit response) or a\n * 15-minute default when no reset time is known. While the mark is in the\n * future, `resolveCredentials(\"moonshot\")` serves the Moonshot API key\n * instead of the Kimi OAuth credential (when both are configured) — OAuth\n * stays the preferred credential and is retried automatically once the mark\n * lapses. Persisted to auth.json so a restart (or another gg-app window)\n * doesn't burn a request rediscovering the same exhausted window. No-op if\n * nothing is stored under `storageKey`.\n */\n async markUsageExhausted(storageKey: string, resetsAt?: number): Promise<void> {\n const until =\n resetsAt !== undefined && resetsAt * 1000 > Date.now()\n ? resetsAt * 1000\n : Date.now() + USAGE_EXHAUSTED_DEFAULT_MS;\n let marked = false;\n await this.mutateLatest((latest) => {\n const creds = latest[storageKey];\n if (!creds) return;\n creds.usageExhaustedUntil = until;\n marked = true;\n });\n if (!marked) return;\n log(\n \"WARN\",\n \"auth\",\n `Marked ${storageKey} usage-exhausted until ${new Date(until).toISOString()}`,\n );\n }\n\n async clearAll(): Promise<void> {\n await this.ensureLoaded();\n await withFileLock(this.filePath, async () => {\n this.data = {};\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n });\n }\n\n /**\n * Returns valid credentials, auto-refreshing if expired.\n * If `forceRefresh` is true, refreshes even if the token hasn't expired\n * (useful when the provider rejects a token with 401 before its stored expiry).\n * Throws if not logged in.\n */\n async resolveCredentials(\n provider: string,\n opts?: { forceRefresh?: boolean; storageKeys?: string[] },\n ): Promise<OAuthCredentials> {\n await this.ensureLoaded();\n\n // A failed refresh removes the credential from this session's cache. If\n // the user then re-logs in through another app session, recover that new\n // on-disk credential instead of remaining \"not logged in\" until restart.\n const directStorageKeys =\n opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider)\n ? opts.storageKeys\n : provider === \"moonshot\"\n ? [MOONSHOT_OAUTH_KEY, \"moonshot\"]\n : [provider];\n if (!directStorageKeys.some((key) => Boolean(this.data[key]))) {\n await this.reloadLatest();\n }\n\n // Explicit ordered storage-key override (e.g. Xiaomi: prefer the Token\n // Plan credential, fall back to API Credits if only that's configured).\n // Bypasses the provider-name resolution below entirely when given —\n // these are always static API keys with no refresh mechanism, so a\n // direct first-match lookup is correct. A single-entry list equal to\n // `[provider]` falls through to normal resolution below.\n if (opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider)) {\n for (const key of opts.storageKeys) {\n const creds = this.data[key];\n if (creds) return creds;\n }\n throw new NotLoggedInError(provider);\n }\n\n // Prefer Kimi OAuth over the Moonshot API key for the logical `moonshot`\n // provider. When an OAuth credential exists, resolve (and refresh) that\n // instead — this is the \"default to OAuth first\" rule.\n if (provider === \"moonshot\" && this.data[MOONSHOT_OAUTH_KEY]) {\n // OAuth plan usage window exhausted (marked by the agent loop when the\n // managed endpoint rejected with a usage/quota stop). Serve the API key\n // while the window recovers — but ONLY when one is configured; with no\n // API key the OAuth credential still resolves so the real usage-limit\n // error (with its reset time) surfaces to the user instead of a\n // misleading \"not logged in\".\n const exhaustedUntil = this.data[MOONSHOT_OAUTH_KEY].usageExhaustedUntil ?? 0;\n if (Date.now() < exhaustedUntil && this.data[\"moonshot\"]) {\n log(\n \"WARN\",\n \"auth\",\n \"Kimi OAuth usage window is exhausted — using the Moonshot API key until \" +\n `${new Date(exhaustedUntil).toISOString()} (OAuth resumes automatically).`,\n );\n return this.data[\"moonshot\"];\n }\n try {\n // Do NOT forward `storageKeys` here: the caller's keys (e.g.\n // AgentSession's [\"moonshot\"]) no longer match the recursive\n // provider (\"moonshot-oauth\"), so forwarding them tripped the\n // storage-key override branch — silently returning the raw API key\n // when both credentials existed (misattributed \"usage is out\"\n // errors) and throwing NotLoggedInError for OAuth-only users.\n return await this.resolveCredentials(MOONSHOT_OAUTH_KEY, {\n ...(opts?.forceRefresh ? { forceRefresh: true } : {}),\n });\n } catch (err) {\n // OAuth refresh token is dead and was wiped. Fall back to the\n // Moonshot API key if the user also configured one. This is a billing\n // switch (OAuth → paid API key), so make it loud in the debug log\n // rather than silent — the user expects OAuth to stay active and\n // should know a re-login is needed to restore it.\n if (err instanceof NotLoggedInError && this.data[\"moonshot\"]) {\n log(\n \"WARN\",\n \"auth\",\n \"Kimi OAuth credential is no longer valid — falling back to the Moonshot API key. \" +\n 'Run \"ggcoder login\" and choose Kimi OAuth to restore OAuth auth.',\n );\n return this.data[\"moonshot\"];\n }\n throw err;\n }\n }\n\n const creds = this.data[provider];\n if (!creds) {\n throw new NotLoggedInError(provider);\n }\n\n // Static API-key providers have no refresh mechanism. The Kimi OAuth key\n // (MOONSHOT_OAUTH_KEY) is intentionally excluded — it refreshes below.\n if (STATIC_API_KEY_PROVIDERS.has(provider)) {\n return creds;\n }\n\n // Return if not expired (with a safety skew) and not force-refreshing\n if (!opts?.forceRefresh && Date.now() < creds.expiresAt - refreshThresholdMs(creds)) {\n return creds;\n }\n\n // Serialize concurrent refresh calls per provider to avoid races\n const existing = this.refreshLocks.get(provider);\n if (existing) return existing;\n\n const refreshPromise = withFileLock(this.filePath, async () => {\n // Always refresh against the latest complete file. A different app\n // session may have re-logged in this provider or changed another one\n // since this instance loaded its cached snapshot.\n const latest = await readAuthData(this.filePath);\n const latestCreds = latest[provider];\n if (!latestCreds) {\n this.data = latest;\n throw new NotLoggedInError(provider);\n }\n\n const credentialWasReplaced =\n latestCreds.accessToken !== creds.accessToken ||\n latestCreds.refreshToken !== creds.refreshToken ||\n latestCreds.expiresAt !== creds.expiresAt;\n if (\n credentialWasReplaced ||\n (!opts?.forceRefresh &&\n Date.now() < latestCreds.expiresAt - refreshThresholdMs(latestCreds))\n ) {\n // Another process refreshed or re-logged in while this session still\n // held the rejected token. Trust that replacement even for a forced\n // refresh; retrying the revoked OLD refresh token would delete the new\n // login that just landed on disk.\n this.data = latest;\n return latestCreds;\n }\n\n const refreshFn =\n provider === \"anthropic\"\n ? refreshAnthropicToken\n : provider === \"gemini\"\n ? refreshGeminiToken\n : provider === MOONSHOT_OAUTH_KEY\n ? refreshKimiToken\n : refreshOpenAIToken;\n let refreshed: OAuthCredentials;\n try {\n refreshed = await refreshFn(latestCreds.refreshToken);\n } catch (err) {\n // Refresh token revoked / expired / invalid → the stored creds are\n // unusable. Delete only this provider from the latest snapshot so a\n // failed refresh can never erase another provider's concurrent login.\n const msg = err instanceof Error ? err.message : String(err);\n const isAuthFailure =\n /\\((401|400)\\)/.test(msg) ||\n /invalid_grant|invalid_token|invalid.*refresh/i.test(msg) ||\n /unauthorized/i.test(msg);\n if (isAuthFailure) {\n delete latest[provider];\n this.data = latest;\n await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));\n throw new NotLoggedInError(provider);\n }\n throw err;\n }\n if (!refreshed.accountId && latestCreds.accountId) {\n refreshed.accountId = latestCreds.accountId;\n }\n if (!refreshed.projectId && latestCreds.projectId) {\n refreshed.projectId = latestCreds.projectId;\n }\n if (!refreshed.baseUrl && latestCreds.baseUrl) {\n refreshed.baseUrl = latestCreds.baseUrl;\n }\n latest[provider] = refreshed;\n this.data = latest;\n // Write atomically (we already hold the file lock).\n await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));\n return refreshed;\n });\n\n this.refreshLocks.set(provider, refreshPromise);\n try {\n return await refreshPromise;\n } finally {\n this.refreshLocks.delete(provider);\n }\n }\n\n /**\n * Returns a valid access token, auto-refreshing if expired.\n * Throws if not logged in.\n */\n async resolveToken(provider: string): Promise<string> {\n const creds = await this.resolveCredentials(provider);\n return creds.accessToken;\n }\n}\n\n/** Read the latest complete auth snapshot while a caller holds the file lock. */\nasync function readAuthData(filePath: string): Promise<AuthData> {\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n return JSON.parse(content) as AuthData;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {};\n throw error;\n }\n}\n\n/**\n * Atomic file write using temp file + rename pattern.\n * Prevents partial/corrupt data if the process crashes mid-write.\n */\nasync function atomicWriteFile(filePath: string, content: string): Promise<void> {\n const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${crypto.randomUUID().slice(0, 8)}.tmp`;\n try {\n await fs.writeFile(tmpPath, content, { encoding: \"utf-8\", mode: 0o600 });\n await fs.rename(tmpPath, filePath);\n } catch (err) {\n await fs.unlink(tmpPath).catch(() => {});\n throw err;\n }\n}\n\nexport class NotLoggedInError extends Error {\n provider: string;\n constructor(provider: string) {\n super(`Not logged in to ${provider}. Run \"ggcoder login\" to authenticate.`);\n this.name = \"NotLoggedInError\";\n this.provider = provider;\n }\n}\n","import crypto from \"node:crypto\";\nimport { generatePKCE } from \"./pkce.js\";\nimport { getClaudeCliUserAgent } from \"../claude-code-version.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\nconst CLIENT_ID = atob(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\n// Anthropic migrated OAuth from console.anthropic.com to platform.claude.com\n// in Claude Code v2.1.81+. Try the new endpoint first, fall back to the old one\n// so a transient outage on either edge doesn't wipe the user's credentials.\nconst TOKEN_URLS = [\n \"https://platform.claude.com/v1/oauth/token\",\n \"https://console.anthropic.com/v1/oauth/token\",\n];\nconst REDIRECT_URI = \"https://platform.claude.com/oauth/code/callback\";\nconst SCOPES =\n \"org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload\";\n\ntype TokenResponse = {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n};\n\nasync function postTokenRequest(\n body: Record<string, string>,\n label: string,\n): Promise<TokenResponse> {\n const encoded = JSON.stringify(body);\n // Claude Code identity. Anthropic's OAuth edge intermittently rejects\n // requests without a recognized claude-cli UA + oauth beta header. Resolve\n // the UA version dynamically so it tracks real Claude Code releases.\n const headers = {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": await getClaudeCliUserAgent(),\n \"anthropic-beta\": \"oauth-2025-04-20\",\n };\n let lastError: Error | null = null;\n for (const url of TOKEN_URLS) {\n let response: Response;\n try {\n response = await fetch(url, { method: \"POST\", headers, body: encoded });\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n continue;\n }\n if (response.ok) {\n return (await response.json()) as TokenResponse;\n }\n const text = await response.text();\n // 4xx is an authoritative auth failure (invalid_grant, invalid_client, etc.)\n // — don't paper over it by trying another endpoint, the result will be the\n // same and the caller relies on this signal to wipe stale creds.\n if (response.status >= 400 && response.status < 500) {\n throw new Error(`Anthropic ${label} failed (${response.status}): ${text}`);\n }\n lastError = new Error(`Anthropic ${label} failed (${response.status}): ${text}`);\n }\n throw lastError ?? new Error(`Anthropic ${label} failed: all endpoints unreachable`);\n}\n\nfunction toCredentials(data: TokenResponse): OAuthCredentials {\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n };\n}\n\nexport async function loginAnthropic(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { verifier, challenge } = await generatePKCE();\n const state = crypto.randomBytes(16).toString(\"hex\");\n\n const params = new URLSearchParams({\n code: \"true\",\n client_id: CLIENT_ID,\n response_type: \"code\",\n redirect_uri: REDIRECT_URI,\n scope: SCOPES,\n code_challenge: challenge,\n code_challenge_method: \"S256\",\n state,\n });\n\n const authUrl = `${AUTHORIZE_URL}?${params}`;\n callbacks.onOpenUrl(authUrl);\n\n const raw = await callbacks.onPromptCode(\"Paste the code from the browser (format: code#state):\");\n\n const parts = raw.trim().split(\"#\");\n if (parts.length !== 2 || !parts[0] || parts[1] !== state) {\n throw new Error(\"Invalid code or state mismatch. Please try again.\");\n }\n\n return exchangeAnthropicCode(parts[0], parts[1], verifier);\n}\n\nasync function exchangeAnthropicCode(\n code: string,\n state: string,\n verifier: string,\n): Promise<OAuthCredentials> {\n const data = await postTokenRequest(\n {\n grant_type: \"authorization_code\",\n client_id: CLIENT_ID,\n code,\n state,\n redirect_uri: REDIRECT_URI,\n code_verifier: verifier,\n },\n \"token exchange\",\n );\n return toCredentials(data);\n}\n\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n const data = await postTokenRequest(\n {\n grant_type: \"refresh_token\",\n client_id: CLIENT_ID,\n refresh_token: refreshToken,\n },\n \"token refresh\",\n );\n return toCredentials(data);\n}\n","function base64urlEncode(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=/g, \"\");\n}\n\nexport async function generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n const verifierBytes = new Uint8Array(32);\n crypto.getRandomValues(verifierBytes);\n const verifier = base64urlEncode(verifierBytes);\n\n const data = new TextEncoder().encode(verifier);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n const challenge = base64urlEncode(new Uint8Array(hashBuffer));\n\n return { verifier, challenge };\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getAppPaths } from \"./paths.js\";\nimport { log } from \"./logger.js\";\n\n// Anthropic's OAuth edge rejects requests whose claude-cli UA version lags too\n// far behind the actual Claude Code release. Resolve dynamically from the npm\n// registry so we never ship a stale-version time bomb.\nconst NPM_LATEST_URL = \"https://registry.npmjs.org/@anthropic-ai/claude-code/latest\";\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000;\nconst FETCH_TIMEOUT_MS = 3000;\n// Last known good version at publish time. Used only when the npm fetch fails\n// and no on-disk cache exists (e.g. first run on an offline machine). Keep\n// reasonably current — bump on each ggcoder release.\nconst FALLBACK_VERSION = \"2.1.88\";\n\ntype CachedVersion = { version: string; fetchedAt: number };\n\nlet memoryCache: { version: string; expiresAt: number } | null = null;\nlet inflight: Promise<string> | null = null;\n\nfunction cachePath(): string {\n return path.join(getAppPaths().agentDir, \"claude-code-version.json\");\n}\n\nasync function readDiskCache(): Promise<CachedVersion | null> {\n try {\n const raw = await fs.readFile(cachePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as CachedVersion;\n if (typeof parsed.version === \"string\" && typeof parsed.fetchedAt === \"number\") {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nasync function writeDiskCache(data: CachedVersion): Promise<void> {\n try {\n await fs.mkdir(getAppPaths().agentDir, { recursive: true, mode: 0o700 });\n await fs.writeFile(cachePath(), JSON.stringify(data), { mode: 0o600 });\n } catch (err) {\n log(\n \"WARN\",\n \"claude-code-version\",\n `Failed to write cache: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\nasync function fetchLatest(): Promise<string | null> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const response = await fetch(NPM_LATEST_URL, { signal: controller.signal });\n if (!response.ok) return null;\n const data = (await response.json()) as { version?: unknown };\n if (typeof data.version === \"string\" && /^\\d/.test(data.version)) {\n return data.version;\n }\n return null;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Resolve the current Claude Code release version for spoofing the claude-cli\n * User-Agent on OAuth and inference requests. Cached in-memory for the process\n * lifetime and on disk for 24h. Falls back to a hardcoded constant if the npm\n * registry is unreachable and no cache exists.\n */\nexport async function getClaudeCodeVersion(): Promise<string> {\n if (memoryCache && Date.now() < memoryCache.expiresAt) {\n return memoryCache.version;\n }\n if (inflight) return inflight;\n\n inflight = (async () => {\n const disk = await readDiskCache();\n const diskFresh = disk && Date.now() - disk.fetchedAt < CACHE_TTL_MS;\n if (disk && diskFresh) {\n memoryCache = { version: disk.version, expiresAt: Date.now() + CACHE_TTL_MS };\n return disk.version;\n }\n const fetched = await fetchLatest();\n if (fetched) {\n await writeDiskCache({ version: fetched, fetchedAt: Date.now() });\n memoryCache = { version: fetched, expiresAt: Date.now() + CACHE_TTL_MS };\n return fetched;\n }\n // npm unreachable — prefer stale disk cache over hardcoded fallback.\n const resolved = disk?.version ?? FALLBACK_VERSION;\n // Short TTL so we retry the npm fetch soon, but don't hammer it.\n memoryCache = { version: resolved, expiresAt: Date.now() + 5 * 60 * 1000 };\n log(\n \"WARN\",\n \"claude-code-version\",\n `Failed to fetch latest Claude Code version; using ${resolved}`,\n );\n return resolved;\n })();\n\n try {\n return await inflight;\n } finally {\n inflight = null;\n }\n}\n\n/** Build the User-Agent string Anthropic's OAuth + inference edges expect. */\nexport async function getClaudeCliUserAgent(): Promise<string> {\n const version = await getClaudeCodeVersion();\n return `claude-cli/${version} (external, cli)`;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { randomBytes } from \"node:crypto\";\nimport { environmentSecrets, redactText, redactValue } from \"@kenkaiiii/gg-ai\";\n\nexport type LogLevel = \"INFO\" | \"ERROR\" | \"WARN\" | \"DEBUG\";\n\n// Cross-session log retention: the log is appended across launches so you can\n// grep back through prior sessions. Rotated at MAX_BYTES to keep it bounded; we\n// keep one generation (debug.log.1) — enough to survive one rotation's worth of\n// scrollback while bounding disk usage.\nconst MAX_BYTES = 10 * 1024 * 1024; // 10 MB\n\nlet fd: number | null = null;\nlet bytesWritten = 0;\nlet capped = false;\nlet sessionId = \"\";\nlet appName = \"app\";\nlet cleanups: (() => void)[] = [];\nlet exactSecrets: string[] = [];\n\nfunction rotateIfNeeded(filePath: string): void {\n try {\n const st = fs.statSync(filePath);\n if (st.size < MAX_BYTES) return;\n const rotated = `${filePath}.1`;\n // Replace prior rotation (fs.renameSync overwrites on POSIX; on Windows it\n // fails if dest exists, so unlink first defensively).\n try {\n fs.unlinkSync(rotated);\n } catch {\n // No prior rotation\n }\n fs.renameSync(filePath, rotated);\n } catch {\n // Log file doesn't exist yet or stat failed — nothing to rotate\n }\n}\n\n/**\n * Open the debug log in append mode, tagging this process with a session id and\n * remembering `name` for the shutdown line. Idempotent — re-calling while open\n * is a no-op. Returns true only when it *newly* opened the file (so callers can\n * write a one-time startup line); returns false if already open or if the file\n * could not be opened.\n */\nexport function openLog(filePath: string, name: string): boolean {\n if (fd !== null || capped) return false;\n appName = name;\n exactSecrets = environmentSecrets(process.env);\n try {\n fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });\n } catch {\n // Directory may already exist or be uncreatable — fall through to open\n }\n rotateIfNeeded(filePath);\n try {\n fd = fs.openSync(filePath, \"a\");\n } catch {\n // Can't open log file — silently disable logging\n fd = null;\n bytesWritten = 0;\n return false;\n }\n try {\n bytesWritten = fs.fstatSync(fd).size;\n } catch {\n try {\n fs.closeSync(fd);\n } catch {\n // Ignore cleanup failure\n }\n fd = null;\n bytesWritten = 0;\n return false;\n }\n sessionId = randomBytes(4).toString(\"hex\");\n // Visible separator between sessions when back-reading the log.\n try {\n if (bytesWritten < MAX_BYTES) {\n bytesWritten += fs.writeSync(fd, \"\\n\");\n }\n } catch {\n // Write failed — proceed without the separator\n }\n return true;\n}\n\n/** Session identifier included on every log line as `sid=<id>`. */\nexport function getSessionId(): string {\n return sessionId;\n}\n\n/** True if the logger has an open file descriptor. */\nexport function isLoggerOpen(): boolean {\n return fd !== null;\n}\n\n/** Write a timestamped log line. No-op if the logger is not open. */\nexport function log(\n level: LogLevel,\n category: string,\n message: string,\n data?: Record<string, unknown>,\n): void {\n if (fd === null) return;\n const ts = new Date().toISOString();\n const safeMessage = redactText(message, { secrets: exactSecrets });\n let line = `[${ts}] [sid=${sessionId}] [${level}] [${category}] ${safeMessage}`;\n if (data) {\n const safeData = redactValue(data, { secrets: exactSecrets });\n const pairs = Object.entries(safeData)\n .map(([k, v]) => {\n if (typeof v === \"string\") return `${k}=${v}`;\n if (typeof v === \"bigint\") return `${k}=${String(v)}`;\n return `${k}=${JSON.stringify(v)}`;\n })\n .join(\" \");\n if (pairs) line += ` ${pairs}`;\n }\n line += \"\\n\";\n\n const lineBytes = Buffer.byteLength(line);\n if (bytesWritten + lineBytes > MAX_BYTES) {\n // A noisy production path must not turn one long-lived process into an\n // unbounded SSD writer. Stop file logging for this process at the hard cap;\n // later launches can use any remaining budget and rotate once it is full.\n const capLine = `[${ts}] [sid=${sessionId}] [WARN] [logger] Log cap reached; file logging disabled until restart\\n`;\n try {\n if (bytesWritten + Buffer.byteLength(capLine) <= MAX_BYTES) {\n bytesWritten += fs.writeSync(fd, capLine);\n }\n fs.closeSync(fd);\n } catch {\n // Write/close failure still disables logging below.\n }\n fd = null;\n capped = true;\n return;\n }\n\n try {\n bytesWritten += fs.writeSync(fd, line);\n } catch {\n // Write failed — don't crash\n }\n}\n\n/**\n * Register a cleanup callback (e.g. an EventBus unsubscriber) to run when the\n * logger closes. Lets app-side bridges hook into the shared lifecycle without\n * the core needing to know about app types.\n */\nexport function registerLogCleanup(fn: () => void): void {\n cleanups.push(fn);\n}\n\n/**\n * Write a shutdown line (unless suppressed), close the file descriptor, and run\n * any registered cleanups.\n */\nexport function closeLogger(opts?: { shutdownLine?: boolean }): void {\n if (fd !== null) {\n if (opts?.shutdownLine !== false) log(\"INFO\", \"shutdown\", `${appName} shutting down`);\n try {\n if (fd !== null) fs.closeSync(fd);\n } catch {\n // Ignore close errors\n }\n }\n fd = null;\n bytesWritten = 0;\n capped = false;\n exactSecrets = [];\n for (const unsub of cleanups) unsub();\n cleanups = [];\n}\n","import http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\nconst CLIENT_ID = \"app_EMoamEEZ73f0CkXaXp7hrann\";\nconst AUTHORIZE_URL = \"https://auth.openai.com/oauth/authorize\";\nconst TOKEN_URL = \"https://auth.openai.com/oauth/token\";\nconst REDIRECT_URI = \"http://localhost:1455/auth/callback\";\nconst SCOPE = \"openid profile email offline_access api.connectors.read api.connectors.invoke\";\nconst JWT_CLAIM_PATH = \"https://api.openai.com/auth\";\n\nexport async function loginOpenAI(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { verifier, challenge } = await generatePKCE();\n const state = crypto.randomBytes(16).toString(\"hex\");\n\n const url = new URL(AUTHORIZE_URL);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"client_id\", CLIENT_ID);\n url.searchParams.set(\"redirect_uri\", REDIRECT_URI);\n url.searchParams.set(\"scope\", SCOPE);\n url.searchParams.set(\"code_challenge\", challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n url.searchParams.set(\"state\", state);\n // Force account chooser / re-authentication so switching accounts actually works.\n // Without this, the browser silently re-approves the cached session.\n url.searchParams.set(\"prompt\", \"login\");\n url.searchParams.set(\"id_token_add_organizations\", \"true\");\n url.searchParams.set(\"codex_cli_simplified_flow\", \"true\");\n url.searchParams.set(\"originator\", \"ggcoder\");\n\n let code: string;\n\n try {\n code = await loginWithServer(url.toString(), state, callbacks);\n } catch {\n // Fallback: manual code paste\n callbacks.onOpenUrl(url.toString());\n const raw = await callbacks.onPromptCode(\n \"Could not start local server. Paste the callback URL or code from the browser:\",\n );\n const parsed = parseAuthorizationInput(raw);\n if (!parsed.code) {\n throw new Error(\"No authorization code found in input.\");\n }\n code = parsed.code;\n }\n\n const creds = await exchangeOpenAICode(code, verifier);\n\n const accountId = getAccountId(creds.accessToken);\n if (!accountId) {\n throw new Error(\"Failed to extract accountId from OpenAI token.\");\n }\n creds.accountId = accountId;\n\n return creds;\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n const value = input.trim();\n if (!value) return {};\n\n // Full URL\n try {\n const url = new URL(value);\n return {\n code: url.searchParams.get(\"code\") ?? undefined,\n state: url.searchParams.get(\"state\") ?? undefined,\n };\n } catch {\n // not a URL\n }\n\n // code#state\n if (value.includes(\"#\")) {\n const [code, state] = value.split(\"#\", 2);\n return { code, state };\n }\n\n // Query string with code=\n if (value.includes(\"code=\")) {\n const params = new URLSearchParams(value);\n return {\n code: params.get(\"code\") ?? undefined,\n state: params.get(\"state\") ?? undefined,\n };\n }\n\n // Raw code\n return { code: value };\n}\n\nfunction decodeJwt(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return null;\n const decoded = atob(parts[1]);\n return JSON.parse(decoded) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction getAccountId(accessToken: string): string | null {\n const payload = decodeJwt(accessToken);\n const auth = payload?.[JWT_CLAIM_PATH] as { chatgpt_account_id?: string } | undefined;\n const accountId = auth?.chatgpt_account_id;\n return typeof accountId === \"string\" && accountId.length > 0 ? accountId : null;\n}\n\nasync function loginWithServer(\n authUrl: string,\n expectedState: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n let receivedCode: string | null = null;\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url || \"\", \"http://localhost\");\n\n if (url.pathname !== \"/auth/callback\") {\n res.statusCode = 404;\n res.end(\"Not found\");\n return;\n }\n\n if (url.searchParams.get(\"state\") !== expectedState) {\n res.statusCode = 400;\n res.end(\"State mismatch\");\n return;\n }\n\n receivedCode = url.searchParams.get(\"code\");\n\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(\"<html><body><h1>Login successful!</h1><p>You can close this tab.</p></body></html>\");\n\n server.close();\n });\n\n server.on(\"error\", (err) => {\n reject(err);\n });\n\n server.listen(1455, \"127.0.0.1\", () => {\n callbacks.onOpenUrl(authUrl);\n callbacks.onStatus(\"Waiting for browser callback...\");\n });\n\n const timeout = setTimeout(() => {\n if (!receivedCode) {\n server.close();\n }\n }, 120_000);\n timeout.unref();\n\n server.on(\"close\", () => {\n clearTimeout(timeout);\n if (receivedCode) {\n resolve(receivedCode);\n } else {\n reject(new Error(\"Server closed without receiving code\"));\n }\n });\n });\n}\n\nasync function exchangeOpenAICode(code: string, verifier: string): Promise<OAuthCredentials> {\n const response = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"authorization_code\",\n client_id: CLIENT_ID,\n code,\n redirect_uri: REDIRECT_URI,\n code_verifier: verifier,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`OpenAI token exchange failed (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n };\n}\n\nexport async function refreshOpenAIToken(refreshToken: string): Promise<OAuthCredentials> {\n const response = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: CLIENT_ID,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`OpenAI token refresh failed (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n\n const creds: OAuthCredentials = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n };\n\n const accountId = getAccountId(creds.accessToken);\n if (accountId) {\n creds.accountId = accountId;\n }\n\n return creds;\n}\n","import http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\nconst CLIENT_ID_ENV = \"GGCODER_GEMINI_OAUTH_CLIENT_ID\";\nconst CLIENT_SECRET_ENV = \"GGCODER_GEMINI_OAUTH_CLIENT_SECRET\";\n// Public \"installed application\" OAuth client shipped with the official Gemini CLI.\n// Unlike the OpenAI/Anthropic flows (pure PKCE, no secret), Google's token endpoint\n// requires a client_secret for the installed-app authorization_code / refresh_token\n// grants — so it must be embedded to support local login like the other providers.\n// This is the published gemini-cli installed-app secret (non-confidential by design);\n// the env vars above override it for users who bring their own Google Cloud client.\nconst DEFAULT_CLIENT_ID =\n \"681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com\";\nconst DEFAULT_CLIENT_SECRET = \"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\";\nconst AUTHORIZE_URL = \"https://accounts.google.com/o/oauth2/v2/auth\";\nconst TOKEN_URL = \"https://oauth2.googleapis.com/token\";\nconst CODE_ASSIST_BASE_URL = \"https://cloudcode-pa.googleapis.com\";\nconst CODE_ASSIST_API_VERSION = \"v1internal\";\nconst CODE_ASSIST_POST_RETRIES = 3;\nconst CODE_ASSIST_POST_RETRY_DELAY_MS = 100;\nconst SCOPE = [\n \"https://www.googleapis.com/auth/cloud-platform\",\n \"https://www.googleapis.com/auth/userinfo.email\",\n \"https://www.googleapis.com/auth/userinfo.profile\",\n].join(\" \");\n\ninterface GoogleTokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n}\n\ninterface GeminiOAuthClientCredentials {\n clientId: string;\n clientSecret: string;\n}\n\ninterface CodeAssistLoadResponse {\n currentTier?: GeminiUserTier | null;\n allowedTiers?: GeminiUserTier[] | null;\n ineligibleTiers?: IneligibleTier[] | null;\n cloudaicompanionProject?: string | null;\n paidTier?: GeminiUserTier | null;\n}\n\ninterface GeminiUserTier {\n id?: string;\n name?: string;\n isDefault?: boolean;\n}\n\ninterface IneligibleTier {\n reasonCode?: string;\n reasonMessage?: string;\n tierName?: string;\n validationUrl?: string;\n}\n\ninterface LongRunningOperationResponse {\n name?: string;\n done?: boolean;\n response?: {\n cloudaicompanionProject?: {\n id?: string;\n name?: string;\n };\n };\n}\n\nconst USER_TIER_FREE = \"free-tier\";\nconst USER_TIER_LEGACY = \"legacy-tier\";\nconst USER_TIER_STANDARD = \"standard-tier\";\nconst VALIDATION_REQUIRED_REASON = \"VALIDATION_REQUIRED\";\nconst VPC_SC_REASON = \"SECURITY_POLICY_VIOLATED\";\n\nclass CodeAssistHttpError extends Error {\n readonly status: number;\n readonly body: string;\n\n constructor(label: string, status: number, body: string) {\n super(`Gemini Code Assist ${label} failed (${status}): ${body}`);\n this.name = \"CodeAssistHttpError\";\n this.status = status;\n this.body = body;\n }\n}\n\nexport async function loginGemini(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { clientId, clientSecret } = getGeminiOAuthClientCredentials();\n const { verifier, challenge } = await generatePKCE();\n const state = crypto.randomBytes(32).toString(\"hex\");\n const redirectUri = await getLoopbackRedirectUri();\n\n const url = new URL(AUTHORIZE_URL);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"client_id\", clientId);\n url.searchParams.set(\"redirect_uri\", redirectUri);\n url.searchParams.set(\"scope\", SCOPE);\n url.searchParams.set(\"access_type\", \"offline\");\n url.searchParams.set(\"prompt\", \"consent\");\n url.searchParams.set(\"code_challenge\", challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n url.searchParams.set(\"state\", state);\n\n let code: string;\n try {\n code = await loginWithServer(url.toString(), redirectUri, state, callbacks);\n } catch {\n callbacks.onOpenUrl(url.toString());\n const raw = await callbacks.onPromptCode(\n \"Could not start local server. Paste the callback URL or code from the browser:\",\n );\n const parsed = parseAuthorizationInput(raw);\n if (!parsed.code) {\n throw new Error(\"No authorization code found in input.\");\n }\n if (parsed.state && parsed.state !== state) {\n throw new Error(\"Invalid state. Please try again.\");\n }\n code = parsed.code;\n }\n\n const creds = await exchangeGeminiCode(code, verifier, redirectUri, clientId, clientSecret);\n callbacks.onStatus(\"Setting up Gemini Code Assist access...\");\n const projectId = await setupCodeAssistProject(creds.accessToken, callbacks);\n\n return {\n ...creds,\n projectId,\n };\n}\n\nexport async function refreshGeminiToken(refreshToken: string): Promise<OAuthCredentials> {\n const { clientId, clientSecret } = getGeminiOAuthClientCredentials();\n const data = await postTokenRequest({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n });\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? refreshToken,\n expiresAt: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n };\n}\n\nfunction getGeminiOAuthClientCredentials(): GeminiOAuthClientCredentials {\n const clientId = process.env[CLIENT_ID_ENV]?.trim() || DEFAULT_CLIENT_ID;\n const clientSecret = process.env[CLIENT_SECRET_ENV]?.trim() || DEFAULT_CLIENT_SECRET;\n return { clientId, clientSecret };\n}\n\nasync function getLoopbackRedirectUri(): Promise<string> {\n return new Promise((resolve, reject) => {\n const server = http.createServer();\n server.listen(0, \"127.0.0.1\", () => {\n const addr = server.address();\n server.close(() => {\n if (addr && typeof addr === \"object\") {\n resolve(`http://127.0.0.1:${addr.port}/oauth2callback`);\n } else {\n reject(new Error(\"Failed to allocate OAuth callback port.\"));\n }\n });\n });\n server.on(\"error\", reject);\n });\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n const value = input.trim();\n if (!value) return {};\n\n try {\n const url = new URL(value);\n return {\n code: url.searchParams.get(\"code\") ?? undefined,\n state: url.searchParams.get(\"state\") ?? undefined,\n };\n } catch {\n // not a URL\n }\n\n if (value.includes(\"code=\")) {\n const params = new URLSearchParams(value);\n return {\n code: params.get(\"code\") ?? undefined,\n state: params.get(\"state\") ?? undefined,\n };\n }\n\n return { code: value };\n}\n\nasync function loginWithServer(\n authUrl: string,\n redirectUri: string,\n expectedState: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<string> {\n const redirect = new URL(redirectUri);\n const port = Number(redirect.port);\n\n return new Promise<string>((resolve, reject) => {\n let receivedCode: string | null = null;\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url || \"\", redirect.origin);\n\n if (url.pathname !== redirect.pathname) {\n res.statusCode = 404;\n res.end(\"Not found\");\n return;\n }\n\n if (url.searchParams.get(\"state\") !== expectedState) {\n res.statusCode = 400;\n res.end(\"State mismatch\");\n return;\n }\n\n receivedCode = url.searchParams.get(\"code\");\n res.writeHead(200, { \"Content-Type\": \"text/html\", Connection: \"close\" });\n res.end(\"<html><body><h1>Login successful!</h1><p>You can close this tab.</p></body></html>\");\n server.close();\n });\n\n server.on(\"error\", (err) => reject(err));\n server.listen(port, \"127.0.0.1\", () => {\n callbacks.onOpenUrl(authUrl);\n callbacks.onStatus(\"Waiting for browser callback...\");\n });\n\n const timeout = setTimeout(() => {\n if (!receivedCode) server.close();\n }, 120_000);\n timeout.unref();\n\n server.on(\"close\", () => {\n clearTimeout(timeout);\n if (receivedCode) {\n resolve(receivedCode);\n } else {\n reject(new Error(\"Server closed without receiving code.\"));\n }\n });\n });\n}\n\nasync function exchangeGeminiCode(\n code: string,\n verifier: string,\n redirectUri: string,\n clientId: string,\n clientSecret: string,\n): Promise<OAuthCredentials> {\n const data = await postTokenRequest({\n grant_type: \"authorization_code\",\n client_id: clientId,\n client_secret: clientSecret,\n code,\n redirect_uri: redirectUri,\n code_verifier: verifier,\n });\n\n if (!data.refresh_token) {\n throw new Error(\"Gemini OAuth did not return a refresh token. Please try login again.\");\n }\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n };\n}\n\nasync function postTokenRequest(body: Record<string, string>): Promise<GoogleTokenResponse> {\n const response = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams(body),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Gemini token request failed (${response.status}): ${text}`);\n }\n\n return (await response.json()) as GoogleTokenResponse;\n}\n\nasync function setupCodeAssistProject(\n accessToken: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<string> {\n const envProject = process.env.GOOGLE_CLOUD_PROJECT ?? process.env.GOOGLE_CLOUD_PROJECT_ID;\n if (envProject && /^\\d+$/.test(envProject)) {\n throw new Error(\"GOOGLE_CLOUD_PROJECT must be a project ID, not a numeric project number.\");\n }\n\n const coreMetadata = {\n ideType: \"IDE_UNSPECIFIED\",\n platform: \"PLATFORM_UNSPECIFIED\",\n pluginType: \"GEMINI\",\n };\n const projectMetadata = {\n ...coreMetadata,\n ...(envProject ? { duetProject: envProject } : {}),\n };\n\n let loadRes: CodeAssistLoadResponse;\n while (true) {\n loadRes = await loadCodeAssist(accessToken, envProject, projectMetadata);\n const validation = getValidationRequiredTier(loadRes);\n if (!validation) break;\n\n callbacks.onStatus(\n `Gemini Code Assist requires account validation${\n validation.reasonMessage ? `: ${validation.reasonMessage}` : \"\"\n }`,\n );\n callbacks.onOpenUrl(validation.validationUrl);\n const answer = await callbacks.onPromptCode(\n \"Complete validation in the browser, then press Enter to retry (or type cancel):\",\n );\n if (answer.trim().toLowerCase() === \"cancel\") {\n throw new Error(\"Gemini Code Assist account validation was cancelled.\");\n }\n }\n\n if (loadRes.currentTier) {\n const project = loadRes.cloudaicompanionProject ?? envProject;\n if (!project) throwProjectError(loadRes);\n return project;\n }\n\n const tier = getOnboardTier(loadRes);\n const onboardReq =\n tier.id === USER_TIER_FREE\n ? {\n tierId: tier.id,\n cloudaicompanionProject: undefined,\n metadata: coreMetadata,\n }\n : {\n tierId: tier.id,\n cloudaicompanionProject: envProject,\n metadata: projectMetadata,\n };\n\n let operation = await codeAssistPost<LongRunningOperationResponse>(\n accessToken,\n \"onboardUser\",\n onboardReq,\n );\n\n while (!operation.done && operation.name) {\n await new Promise((resolve) => setTimeout(resolve, 5_000));\n operation = await codeAssistGet<LongRunningOperationResponse>(accessToken, operation.name);\n }\n\n const project = operation.response?.cloudaicompanionProject?.id ?? envProject;\n if (!project) throwProjectError(loadRes);\n return project;\n}\n\nasync function loadCodeAssist(\n accessToken: string,\n envProject: string | undefined,\n metadata: Record<string, string>,\n): Promise<CodeAssistLoadResponse> {\n try {\n return await codeAssistPost<CodeAssistLoadResponse>(accessToken, \"loadCodeAssist\", {\n ...(envProject ? { cloudaicompanionProject: envProject } : {}),\n metadata,\n });\n } catch (err) {\n if (err instanceof CodeAssistHttpError && isVpcScAffectedError(err)) {\n return { currentTier: { id: USER_TIER_STANDARD } };\n }\n if (\n err instanceof CodeAssistHttpError &&\n err.status === 403 &&\n envProject === \"cloudshell-gca\"\n ) {\n throw new Error(\n \"Access to the default Cloud Shell Gemini project was denied.\\n\" +\n \"Please set your own Google Cloud project by running:\\n\" +\n \"gcloud config set project [PROJECT_ID]\\n\" +\n \"or setting export GOOGLE_CLOUD_PROJECT=...\",\n { cause: err },\n );\n }\n throw err;\n }\n}\n\nfunction getValidationRequiredTier(\n response: CodeAssistLoadResponse,\n): (IneligibleTier & { validationUrl: string }) | undefined {\n return response.ineligibleTiers?.find(\n (tier): tier is IneligibleTier & { validationUrl: string } =>\n tier.reasonCode === VALIDATION_REQUIRED_REASON && typeof tier.validationUrl === \"string\",\n );\n}\n\nfunction getOnboardTier(response: CodeAssistLoadResponse): GeminiUserTier {\n const defaultTier = response.allowedTiers?.find((tier) => tier.isDefault);\n return defaultTier ?? { id: USER_TIER_LEGACY, name: \"\" };\n}\n\nfunction throwProjectError(response: CodeAssistLoadResponse): never {\n const reasons = response.ineligibleTiers\n ?.map((tier) => tier.reasonMessage ?? tier.tierName)\n .filter((reason): reason is string => Boolean(reason));\n if (reasons && reasons.length > 0) {\n throw new Error(`Gemini Code Assist setup failed: ${reasons.join(\", \")}`);\n }\n throw new Error(\n \"Gemini requires a Google Cloud project for this account. Set GOOGLE_CLOUD_PROJECT and try again.\",\n );\n}\n\nasync function codeAssistPost<T>(\n accessToken: string,\n method: string,\n body: Record<string, unknown>,\n): Promise<T> {\n let lastError: Error | undefined;\n for (let attempt = 0; attempt <= CODE_ASSIST_POST_RETRIES; attempt++) {\n try {\n return await codeAssistRequest<T>(getCodeAssistMethodUrl(method), accessToken, method, {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n } catch (err) {\n if (\n !(err instanceof CodeAssistHttpError) ||\n attempt === CODE_ASSIST_POST_RETRIES ||\n !shouldRetryCodeAssistStatus(err.status)\n ) {\n throw err;\n }\n lastError = err;\n }\n await new Promise((resolve) => setTimeout(resolve, CODE_ASSIST_POST_RETRY_DELAY_MS));\n }\n\n throw lastError ?? new Error(`Gemini Code Assist ${method} failed.`);\n}\n\nasync function codeAssistGet<T>(accessToken: string, operationName: string): Promise<T> {\n return codeAssistRequest<T>(getCodeAssistOperationUrl(operationName), accessToken, \"operation\", {\n method: \"GET\",\n });\n}\n\nasync function codeAssistRequest<T>(\n url: string,\n accessToken: string,\n label: string,\n init: Pick<RequestInit, \"method\" | \"body\">,\n): Promise<T> {\n const response = await fetch(url, {\n ...init,\n headers: codeAssistHeaders(accessToken),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new CodeAssistHttpError(label, response.status, text);\n }\n\n return (await response.json()) as T;\n}\n\nfunction getCodeAssistBaseUrl(): string {\n const endpoint = process.env.CODE_ASSIST_ENDPOINT ?? CODE_ASSIST_BASE_URL;\n const version = process.env.CODE_ASSIST_API_VERSION || CODE_ASSIST_API_VERSION;\n return `${endpoint}/${version}`;\n}\n\nfunction getCodeAssistMethodUrl(method: string): string {\n return `${getCodeAssistBaseUrl()}:${method}`;\n}\n\nfunction getCodeAssistOperationUrl(operationName: string): string {\n return `${getCodeAssistBaseUrl()}/${operationName}`;\n}\n\nfunction shouldRetryCodeAssistStatus(status: number): boolean {\n return status === 429 || status === 499 || (status >= 500 && status <= 599);\n}\n\nfunction isVpcScAffectedError(error: CodeAssistHttpError): boolean {\n try {\n const parsed = JSON.parse(error.body) as unknown;\n if (!parsed || typeof parsed !== \"object\" || !(\"error\" in parsed)) return false;\n const details = (parsed as { error?: { details?: unknown[] } }).error?.details;\n return Array.isArray(details)\n ? details.some(\n (detail) =>\n detail != null &&\n typeof detail === \"object\" &&\n \"reason\" in detail &&\n detail.reason === VPC_SC_REASON,\n )\n : false;\n } catch {\n return false;\n }\n}\n\nfunction codeAssistHeaders(accessToken: string): Record<string, string> {\n return {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"google-gemini-cli\",\n \"X-Goog-Api-Client\": \"gemini-cli/0.0.0\",\n };\n}\n","import fs from \"node:fs/promises\";\nimport { setTimeout } from \"node:timers/promises\";\n\nconst STALE_TIMEOUT_MS = 10_000; // Lock is stale after 10s\nconst RETRY_INTERVAL_MS = 50; // Retry every 50ms\nconst MAX_WAIT_MS = 5_000; // Give up after 5s\n\ninterface LockInfo {\n pid: number;\n timestamp: number;\n}\n\n/**\n * Simple file-based lock with PID tracking and stale detection.\n * Uses atomic file creation (wx flag) to prevent races.\n */\nexport async function withFileLock<T>(filePath: string, fn: () => Promise<T>): Promise<T> {\n const lockPath = filePath + \".lock\";\n await acquireLock(lockPath);\n try {\n return await fn();\n } finally {\n await releaseLock(lockPath);\n }\n}\n\nasync function acquireLock(lockPath: string): Promise<void> {\n const startTime = Date.now();\n\n while (true) {\n try {\n // O_EXCL: fail if file exists — atomic lock acquisition\n const info: LockInfo = { pid: process.pid, timestamp: Date.now() };\n await fs.writeFile(lockPath, JSON.stringify(info), { flag: \"wx\" });\n return; // Lock acquired\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n\n // Lock file exists — check if it's stale\n try {\n const content = await fs.readFile(lockPath, \"utf-8\");\n const info = JSON.parse(content) as LockInfo;\n\n // Check if the holding process is still alive\n const isProcessAlive = isAlive(info.pid);\n const isStale = Date.now() - info.timestamp > STALE_TIMEOUT_MS;\n\n if (!isProcessAlive || isStale) {\n // Stale lock — remove and retry\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n } catch {\n // Corrupt lock file — remove and retry\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n\n // Lock is held by a live process — wait and retry\n if (Date.now() - startTime > MAX_WAIT_MS) {\n // Timeout — force break the lock (better than deadlocking)\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n\n await setTimeout(RETRY_INTERVAL_MS);\n }\n }\n}\n\nasync function releaseLock(lockPath: string): Promise<void> {\n await fs.unlink(lockPath).catch(() => {});\n}\n\nfunction isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0); // Signal 0 = check existence without killing\n return true;\n } catch (err) {\n // EPERM = process exists but belongs to a different user — still alive\n if ((err as NodeJS.ErrnoException).code === \"EPERM\") return true;\n // ESRCH = no such process — it's dead\n return false;\n }\n}\n","import type { Provider, ThinkingLevel } from \"@kenkaiiii/gg-ai\";\nimport { isKimiCodingEndpoint } from \"./oauth/kimi.js\";\nimport { XIAOMI_CREDITS_KEY } from \"./auth-storage.js\";\n\nexport interface ModelInfo {\n id: string;\n name: string;\n provider: Provider;\n contextWindow: number;\n /**\n * ChatGPT Codex transport uses product-specific windows that can differ from\n * the public API model window. OpenAI OAuth requests include an accountId and\n * route through `/codex/responses`; API-key requests do not.\n */\n codexContextWindow?: number;\n maxOutputTokens: number;\n supportsThinking: boolean;\n supportsImages: boolean;\n supportsVideo: boolean;\n /**\n * Max video payload (bytes) this model's transport accepts, used to decide\n * when an attached/read video must be compressed before sending. Differs by\n * provider delivery mechanism:\n * - Moonshot/Kimi: 100 MB (file-service upload cap)\n * - MiniMax: 50 MB (Anthropic-compatible base64 inline cap)\n * - Gemini: 20 MB (inlineData per-request cap)\n * - Xiaomi (MiMo): ~36 MB raw — the API caps the base64 STRING at 50 MB,\n * and base64 inflates bytes by ~4/3, so 36 MB raw ≈ 48 MB encoded.\n * Only meaningful when `supportsVideo` is true.\n */\n maxVideoBytes?: number;\n costTier: \"low\" | \"medium\" | \"high\";\n /**\n * The top reasoning tier this model genuinely uses. Used when thinking is\n * enabled to pick the strongest setting per model:\n * - OpenAI GPT-5.6-era (Sol/Terra/Luna): `max` (the 5.6 ladder adds `max`\n * and `ultra`; gg-ai caps at `max` — `ultra` needs a ThinkingLevel bump)\n * - OpenAI GPT-5.5-era: `xhigh`\n * - OpenAI Pro/Codex/old: clamped to what the model accepts\n * - Claude Fable 5 / Mythos 5, Opus 4.8 / 4.7 / 4.6 and Sonnet 5: `max`\n * (Fable 5 / Mythos 5 use always-on adaptive thinking, low→max ladder)\n * - Claude Haiku 4.5: `high` (no adaptive `max` tier)\n * - Kimi K3: `max` (always-on reasoning; currently the only API effort)\n * - GLM / Kimi K2.x / Xiaomi / MiniMax / Qwen: `high` — binary-thinking\n * providers ignore the level on the wire, so the value is cosmetic\n * - DeepSeek V4: `xhigh` (DeepSeek maps `xhigh` → its internal `max`)\n */\n maxThinkingLevel: ThinkingLevel;\n /**\n * Ordered preference of auth-storage keys this model resolves credentials\n * from, for providers that split auth across multiple distinct\n * endpoints/keys (currently only Xiaomi: the Token Plan endpoint vs. the\n * API Credits endpoint). The first key with stored credentials wins, so a\n * model can both prefer one endpoint AND fall back to another the user has\n * configured instead:\n * - `mimo-v2.5-pro` / `mimo-v2.5`: `[\"xiaomi\", XIAOMI_CREDITS_KEY]` —\n * prefer the Token Plan, fall back to API Credits (API Credits serves\n * every MiMo model, so a Credits-only user still reaches these).\n * - `mimo-v2.5-pro-ultraspeed`: `[XIAOMI_CREDITS_KEY]` only — not served\n * over the Token Plan endpoint, so there's no fallback to it.\n * Falls back to `[provider]` — the normal single-credential case — when\n * unset. Read via `getAuthStorageKeys()` / `getAuthStorageKey()`.\n */\n authStorageKeys?: string[];\n}\n\n// Provider display order — mirrors `PROVIDERS` in ui/login.tsx so the\n// /model selector and login selector sort models identically.\nexport const MODELS: ModelInfo[] = [\n // ── Anthropic ──────────────────────────────────────────\n // NOTE: Claude Mythos 5 (`claude-mythos-5`) is kept commented out — it's a\n // Project Glasswing (limited, invitation-only) model unavailable to most\n // users. Re-enable once it's generally available.\n {\n id: \"claude-fable-5\",\n name: \"Claude Fable 5\",\n provider: \"anthropic\",\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"high\",\n maxThinkingLevel: \"max\",\n },\n // {\n // // Mythos-class model offered through Project Glasswing (limited\n // // availability, invitation-only). Same underlying model as Fable 5 with\n // // some safeguards lifted; kept here so approved accounts can select it.\n // id: \"claude-mythos-5\",\n // name: \"Claude Mythos 5\",\n // provider: \"anthropic\",\n // contextWindow: 1_000_000,\n // maxOutputTokens: 128_000,\n // supportsThinking: true,\n // supportsImages: true,\n // supportsVideo: false,\n // costTier: \"high\",\n // maxThinkingLevel: \"max\",\n // },\n {\n id: \"claude-opus-4-8\",\n name: \"Claude Opus 4.8\",\n provider: \"anthropic\",\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"high\",\n maxThinkingLevel: \"max\",\n },\n {\n id: \"claude-sonnet-5\",\n name: \"Claude Sonnet 5\",\n provider: \"anthropic\",\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"max\",\n },\n {\n id: \"claude-haiku-4-5-20251001\",\n name: \"Claude Haiku 4.5\",\n provider: \"anthropic\",\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"high\",\n },\n // ── OpenAI (Codex) ─────────────────────────────────────\n // GPT-5.6 family — three agentic coding tiers launched July 2026. The public\n // Responses API advertises a 1.05M context window; OpenAI's Codex product\n // catalog advertises 272K on the ChatGPT OAuth route (corrected from the\n // initially advertised 372K — openai/codex PR #33972, Jul 18 2026 hotfix). All three take\n // text+image input, freeform apply_patch, text+image web search, and parallel\n // tool calls.\n {\n // Sol — \"Latest frontier agentic coding model.\" (priority 1, default low).\n // Reasoning ladder: low → medium → high → xhigh → max → ultra. Ultra is a\n // Codex orchestration preset: the request uses max effort while the local\n // runtime proactively delegates suitable independent work to subagents.\n id: \"gpt-5.6-sol\",\n name: \"GPT-5.6 Sol\",\n provider: \"openai\",\n contextWindow: 1_050_000,\n codexContextWindow: 272_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"high\",\n maxThinkingLevel: \"ultra\",\n },\n {\n // Terra — \"Balanced agentic coding model for everyday work.\" (priority 2,\n // default medium).\n id: \"gpt-5.6-terra\",\n name: \"GPT-5.6 Terra\",\n provider: \"openai\",\n contextWindow: 1_050_000,\n codexContextWindow: 272_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"ultra\",\n },\n {\n // Luna — \"Fast and affordable agentic coding model.\" (priority 3, default\n // medium). Reasoning tops out at `max`.\n id: \"gpt-5.6-luna\",\n name: \"GPT-5.6 Luna\",\n provider: \"openai\",\n contextWindow: 1_050_000,\n codexContextWindow: 272_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"max\",\n },\n {\n id: \"gpt-5.5\",\n name: \"GPT-5.5\",\n provider: \"openai\",\n contextWindow: 1_050_000,\n codexContextWindow: 272_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"high\",\n maxThinkingLevel: \"xhigh\",\n },\n // ── Sakana (Fugu) ──────────────────────────────────────\n // Sakana Fugu is a multi-agent system surfaced as a standard LLM via the\n // OpenAI-compatible Sakana API (https://api.sakana.ai/v1). Both models take\n // text + image input and only accept \"high\"/\"xhigh\" reasoning effort, so the\n // top tier is `xhigh`. `fugu` routes across all providers; `fugu-ultra` is\n // the heavier tier (may need larger client timeouts on complex tasks).\n {\n id: \"fugu\",\n name: \"Fugu\",\n provider: \"sakana\",\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"xhigh\",\n },\n {\n id: \"fugu-ultra\",\n name: \"Fugu Ultra\",\n provider: \"sakana\",\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"high\",\n maxThinkingLevel: \"xhigh\",\n },\n // ── xAI (Grok) ─────────────────────────────────────────\n // Grok 4.5 (released 2026-07-08) is xAI's flagship for coding, agentic\n // tasks, and knowledge work — 500K context, text+image input, configurable\n // `reasoning_effort` (low/medium/high, server default high; reasoning can't\n // be fully disabled). Served over the OpenAI-compatible API at\n // https://api.x.ai/v1 (API key from console.x.ai). xAI hasn't published an\n // official max-output cap for 4.5; 131K matches the Grok Responses ceiling\n // third-party integrations use.\n {\n id: \"grok-4.5\",\n name: \"Grok 4.5\",\n provider: \"xai\",\n contextWindow: 500_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n // ── Gemini ─────────────────────────────────────────────\n {\n id: \"gemini-3.1-flash-lite\",\n name: \"Gemini 3.1 Flash Lite\",\n provider: \"gemini\",\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 20 * 1024 * 1024,\n costTier: \"low\",\n maxThinkingLevel: \"high\",\n },\n {\n // Wire name `gemini-3-flash` — the Code Assist (OAuth) backend rejects the\n // display string `gemini-3.5-flash` with a 404, so gemini-cli keeps this\n // alternative name (SECONDARY_GEMINI_3_5_FLASH_MODEL) for that endpoint.\n id: \"gemini-3-flash\",\n name: \"Gemini 3.5 Flash\",\n provider: \"gemini\",\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 20 * 1024 * 1024,\n costTier: \"low\",\n maxThinkingLevel: \"high\",\n },\n {\n // Gemini 3.1 Pro is public preview — gated behind Code Assist preview\n // enablement, so free/personal OAuth accounts 404 on it (see\n // ACCOUNT_GATED_MODELS in gg-ai's gemini provider).\n id: \"gemini-3.1-pro-preview\",\n name: \"Gemini 3.1 Pro (Preview)\",\n provider: \"gemini\",\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 20 * 1024 * 1024,\n costTier: \"high\",\n maxThinkingLevel: \"high\",\n },\n // ── Moonshot (Kimi) ────────────────────────────────────\n // K3 is Kimi's 2.8T-parameter flagship for long-horizon coding, knowledge\n // work, and deep reasoning. Its effort ladder is server-declared as\n // low/high/max on both the public API (default max) and the Kimi For Coding\n // OAuth endpoint (default high); thinking can also be fully disabled.\n {\n id: \"kimi-k3\",\n name: \"Kimi K3\",\n provider: \"moonshot\",\n contextWindow: 1_048_576,\n // The API can be raised as high as the full context window, but 131K is the\n // documented default and keeps room for input in AgentSession's fixed cap.\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 100 * 1024 * 1024,\n costTier: \"high\",\n maxThinkingLevel: \"max\",\n },\n // Retain the cheaper dedicated coding model as an explicit alternative.\n {\n id: \"kimi-k2.7-code\",\n name: \"Kimi K2.7 Code\",\n provider: \"moonshot\",\n contextWindow: 262_144,\n maxOutputTokens: 262_144,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 100 * 1024 * 1024,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n // ── Z.AI (GLM) ─────────────────────────────────────────\n // GLM-5.2: coding-first flagship with a usable 1M-token context window\n // (5x jump over GLM-5.1's ~200K) and 131K max output. Released 2026-06-13.\n {\n id: \"glm-5.2\",\n name: \"GLM-5.2\",\n provider: \"glm\",\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n {\n id: \"glm-5.1\",\n name: \"GLM-5.1\",\n provider: \"glm\",\n contextWindow: 204_800,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n {\n id: \"glm-4.7\",\n name: \"GLM-4.7\",\n provider: \"glm\",\n contextWindow: 200_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"high\",\n },\n {\n id: \"glm-4.7-flash\",\n name: \"GLM-4.7 Flash\",\n provider: \"glm\",\n contextWindow: 200_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"high\",\n },\n // ── MiniMax ────────────────────────────────────────────\n {\n id: \"MiniMax-M3\",\n name: \"MiniMax M3\",\n provider: \"minimax\",\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 50 * 1024 * 1024,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n // ── Xiaomi (MiMo) ──────────────────────────────────────\n // Pro series: text-only coding/agentic flagship. The legacy mimo-v2-pro\n // auto-routes to v2.5 on 2026-06-01 and is fully deprecated by 2026-06-30.\n {\n id: \"mimo-v2.5-pro\",\n name: \"MiMo-V2.5-Pro\",\n provider: \"xiaomi\",\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n authStorageKeys: [\"xiaomi\", XIAOMI_CREDITS_KEY],\n },\n // UltraSpeed: lower-latency sibling of the Pro coding flagship, same\n // text-only capability surface, premium-priced for the throughput gain.\n // API-only — not served over the Token Plan endpoint, so credentials\n // resolve from the distinct API Credits key only (see authStorageKeys doc).\n {\n id: \"mimo-v2.5-pro-ultraspeed\",\n name: \"MiMo-V2.5-Pro-UltraSpeed\",\n provider: \"xiaomi\",\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"high\",\n maxThinkingLevel: \"high\",\n authStorageKeys: [XIAOMI_CREDITS_KEY],\n },\n // Omni series: native full-modal understanding (image + audio + video).\n // Video/image ride the OpenAI-compatible transport as base64 data URLs\n // (`video_url`/`image_url`), which the shared transform already emits.\n {\n id: \"mimo-v2.5\",\n name: \"MiMo-V2.5\",\n provider: \"xiaomi\",\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 36 * 1024 * 1024,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n authStorageKeys: [\"xiaomi\", XIAOMI_CREDITS_KEY],\n },\n // ── DeepSeek ───────────────────────────────────────────\n {\n id: \"deepseek-v4-pro\",\n name: \"DeepSeek V4 Pro\",\n provider: \"deepseek\",\n contextWindow: 1_048_576,\n maxOutputTokens: 384_000,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"high\",\n // DeepSeek V4 maps `xhigh` → its internal `max` tier.\n maxThinkingLevel: \"xhigh\",\n },\n {\n id: \"deepseek-v4-flash\",\n name: \"DeepSeek V4 Flash\",\n provider: \"deepseek\",\n contextWindow: 1_048_576,\n maxOutputTokens: 384_000,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"xhigh\",\n },\n // ── OpenRouter ─────────────────────────────────────────\n {\n id: \"qwen/qwen3.6-plus\",\n name: \"Qwen3.6-Plus\",\n provider: \"openrouter\",\n contextWindow: 1_000_000,\n maxOutputTokens: 65_536,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n];\n\nexport function getModel(id: string): ModelInfo | undefined {\n return MODELS.find((m) => m.id === id);\n}\n\nexport function getModelsForProvider(provider: Provider): ModelInfo[] {\n return MODELS.filter((m) => m.provider === provider);\n}\n\n/**\n * Ordered auth-storage keys to try resolving credentials from for\n * `(provider, model)`, first match wins. Almost every model just uses its\n * provider id (one credential per provider). Models with `authStorageKeys`\n * set (currently only Xiaomi) can prefer one endpoint and fall back to\n * another — e.g. `mimo-v2.5-pro` prefers the Token Plan but falls back to API\n * Credits, while the API-only `mimo-v2.5-pro-ultraspeed` has no fallback.\n */\nexport function getAuthStorageKeys(provider: Provider, modelId: string): string[] {\n const model = MODELS.find((m) => m.id === modelId && m.provider === provider);\n return model?.authStorageKeys ?? [provider];\n}\n\n/** The preferred (first) auth-storage key for `(provider, model)` — see `getAuthStorageKeys()`. */\nexport function getAuthStorageKey(provider: Provider, modelId: string): string {\n return getAuthStorageKeys(provider, modelId)[0]!;\n}\n\n/** Default video payload cap (bytes) when a video model doesn't declare one. */\nexport const DEFAULT_MAX_VIDEO_BYTES = 20 * 1024 * 1024;\n\n/**\n * Max video payload (bytes) the given model's transport accepts before the clip\n * must be compressed. Returns `undefined` for models without video support, so\n * callers can skip the native-video path entirely.\n */\nexport function getVideoByteLimit(modelId: string): number | undefined {\n const model = getModel(modelId);\n if (!model?.supportsVideo) return undefined;\n return model.maxVideoBytes ?? DEFAULT_MAX_VIDEO_BYTES;\n}\n\nexport function getDefaultModel(provider: Provider): ModelInfo {\n if (provider === \"xiaomi\") return MODELS.find((m) => m.id === \"mimo-v2.5-pro\")!;\n if (provider === \"openai\") return MODELS.find((m) => m.id === \"gpt-5.6-sol\")!;\n if (provider === \"gemini\") return MODELS.find((m) => m.id === \"gemini-3.1-flash-lite\")!;\n if (provider === \"glm\") return MODELS.find((m) => m.id === \"glm-5.2\")!;\n if (provider === \"moonshot\") return MODELS.find((m) => m.id === \"kimi-k3\")!;\n if (provider === \"minimax\") return MODELS.find((m) => m.id === \"MiniMax-M3\")!;\n if (provider === \"deepseek\") return MODELS.find((m) => m.id === \"deepseek-v4-pro\")!;\n if (provider === \"openrouter\") return MODELS.find((m) => m.id === \"qwen/qwen3.6-plus\")!;\n if (provider === \"sakana\") return MODELS.find((m) => m.id === \"fugu\")!;\n if (provider === \"xai\") return MODELS.find((m) => m.id === \"grok-4.5\")!;\n return MODELS.find((m) => m.id === \"claude-sonnet-5\")!;\n}\n\nexport interface ContextWindowOptions {\n provider?: Provider;\n accountId?: string;\n}\n\nexport function usesOpenAICodexTransport(options?: ContextWindowOptions): boolean {\n return options?.provider === \"openai\" && Boolean(options.accountId);\n}\n\n/**\n * Codex applies a 10K-token history cap to every tool/function output. GG's\n * generic 30%-of-context allowance is far larger on 272K/372K Codex windows\n * and can turn a few reads into 100K+ fresh input tokens. Four characters per\n * token matches Codex's byte approximation and keeps this provider policy in\n * the shared model registry instead of an app-specific copy.\n */\nexport function getToolResultCharLimit(\n _modelId: string,\n options?: ContextWindowOptions,\n): number | undefined {\n return usesOpenAICodexTransport(options) ? 10_000 * 4 : undefined;\n}\n\nexport function getContextWindow(modelId: string, options?: ContextWindowOptions): number {\n const model = getModel(modelId);\n if (!model) return 200_000;\n if (usesOpenAICodexTransport(options) && model.codexContextWindow) {\n return model.codexContextWindow;\n }\n return model.contextWindow;\n}\n\n/**\n * The strongest thinking level the given model genuinely uses. Falls back to\n * `\"high\"` for unknown models since every provider we ship accepts it.\n */\nexport function getMaxThinkingLevel(modelId: string): ThinkingLevel {\n return getModel(modelId)?.maxThinkingLevel ?? \"high\";\n}\n\n/**\n * The thinking level a fresh session starts at. Identical to\n * {@link getMaxThinkingLevel} except where the provider declares a lower\n * default effort server-side — Kimi K3's Kimi For Coding OAuth endpoint\n * declares `default_effort: \"high\"` in its /models think_efforts (the public\n * Moonshot API declares \"max\"), and the official kimi-code CLI starts there.\n * Pass the active credential's baseUrl so the endpoint-aware default resolves;\n * matching it keeps plan-usage burn identical to the official CLI (users can\n * still toggle up to max).\n */\nexport function getDefaultThinkingLevel(\n modelId: string,\n options?: { baseUrl?: string },\n): ThinkingLevel {\n const model = getModel(modelId);\n if (model?.id === \"kimi-k3\" && isKimiCodingEndpoint(options?.baseUrl)) return \"high\";\n return model?.maxThinkingLevel ?? \"high\";\n}\n\n/**\n * Get the model to use for compaction summarization.\n * - Anthropic: always Sonnet 5\n * - OpenAI: cheapest (Codex Mini)\n * - Gemini: use the current model\n * - GLM: GLM-4.7 Flash (cheap alternative)\n * - Moonshot: use the current model (no cheap alternative)\n */\nexport function getSummaryModel(provider: Provider, currentModelId: string): ModelInfo {\n if (provider === \"anthropic\") {\n return MODELS.find((m) => m.id === \"claude-sonnet-5\")!;\n }\n if (provider === \"openai\" || provider === \"glm\" || provider === \"deepseek\") {\n const low = getModelsForProvider(provider).find((m) => m.costTier === \"low\");\n if (low) return low;\n }\n // Moonshot or fallback: use current model\n return getModel(currentModelId) ?? getDefaultModel(provider);\n}\n\n/**\n * Fastest/cheapest sibling within the SAME provider, for scout-style read-only\n * sub-agents (recon, research) where a low-latency model is enough and the\n * frontier model is wasted spend + latency.\n *\n * Routes off each model's `costTier` — the single source of truth that already\n * travels with the registry entry — so a model rename/bump needs no change\n * here. Providers with no low-tier sibling (Moonshot, MiniMax, Xiaomi, Sakana,\n * OpenRouter) gracefully keep the parent model, so there's never a crash or a\n * cross-provider jump to a login the user may not have.\n */\nexport function getFastModel(provider: Provider, currentModelId: string): ModelInfo {\n const low = getModelsForProvider(provider).find((m) => m.costTier === \"low\");\n return low ?? getModel(currentModelId) ?? getDefaultModel(provider);\n}\n"],"mappings":"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","names":["fs","readFileSync","crypto","crypto","fs","path","path","path","fs","CLIENT_ID","crypto","crypto","CLIENT_ID","AUTHORIZE_URL","REDIRECT_URI","crypto","http","crypto","AUTHORIZE_URL","TOKEN_URL","SCOPE","crypto","loginWithServer","parseAuthorizationInput","postTokenRequest","http","project","fs","setTimeout","readFileSync","fs","creds","crypto"]}
|
package/dist/index.cjs
CHANGED
|
@@ -239,6 +239,7 @@ function credsFromTokenResponse(data, opts) {
|
|
|
239
239
|
accessToken,
|
|
240
240
|
refreshToken,
|
|
241
241
|
expiresAt: Date.now() + expiresIn * 1e3,
|
|
242
|
+
expiresIn,
|
|
242
243
|
baseUrl: kimiCodeBaseUrl()
|
|
243
244
|
};
|
|
244
245
|
}
|
|
@@ -1291,7 +1292,12 @@ function readStoredBaseUrlSync(authFile, provider) {
|
|
|
1291
1292
|
return void 0;
|
|
1292
1293
|
}
|
|
1293
1294
|
}
|
|
1294
|
-
var
|
|
1295
|
+
var MIN_REFRESH_THRESHOLD_MS = 3e5;
|
|
1296
|
+
var REFRESH_THRESHOLD_RATIO = 0.5;
|
|
1297
|
+
function refreshThresholdMs(creds) {
|
|
1298
|
+
const lifetimeMs = (creds.expiresIn ?? 0) * 1e3;
|
|
1299
|
+
return Math.max(MIN_REFRESH_THRESHOLD_MS, lifetimeMs * REFRESH_THRESHOLD_RATIO);
|
|
1300
|
+
}
|
|
1295
1301
|
var USAGE_EXHAUSTED_DEFAULT_MS = 15 * 60 * 1e3;
|
|
1296
1302
|
var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
|
|
1297
1303
|
"glm",
|
|
@@ -1525,7 +1531,7 @@ var AuthStorage = class {
|
|
|
1525
1531
|
if (STATIC_API_KEY_PROVIDERS.has(provider)) {
|
|
1526
1532
|
return creds;
|
|
1527
1533
|
}
|
|
1528
|
-
if (!opts?.forceRefresh && Date.now() < creds.expiresAt -
|
|
1534
|
+
if (!opts?.forceRefresh && Date.now() < creds.expiresAt - refreshThresholdMs(creds)) {
|
|
1529
1535
|
return creds;
|
|
1530
1536
|
}
|
|
1531
1537
|
const existing = this.refreshLocks.get(provider);
|
|
@@ -1538,7 +1544,7 @@ var AuthStorage = class {
|
|
|
1538
1544
|
throw new NotLoggedInError(provider);
|
|
1539
1545
|
}
|
|
1540
1546
|
const credentialWasReplaced = latestCreds.accessToken !== creds.accessToken || latestCreds.refreshToken !== creds.refreshToken || latestCreds.expiresAt !== creds.expiresAt;
|
|
1541
|
-
if (credentialWasReplaced || !opts?.forceRefresh && Date.now() < latestCreds.expiresAt -
|
|
1547
|
+
if (credentialWasReplaced || !opts?.forceRefresh && Date.now() < latestCreds.expiresAt - refreshThresholdMs(latestCreds)) {
|
|
1542
1548
|
this.data = latest;
|
|
1543
1549
|
return latestCreds;
|
|
1544
1550
|
}
|