@kenkaiiii/gg-core 5.3.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../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/oauth/kimi.ts","../src/file-lock.ts","../src/model-registry.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\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 * Refresh refreshable OAuth tokens this long BEFORE their hard expiry. Renewing\n * proactively keeps the credential (and its refresh token) alive across\n * sessions instead of waiting until a request fails with 401 — which, for\n * providers like Kimi, is otherwise misread as a dead credential and triggers a\n * silent fall back to a static API key.\n */\nconst REFRESH_SKEW_MS = 60_000;\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]);\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 return false;\n }\n return STATIC_API_KEY_PROVIDERS.has(provider);\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 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.ensureLoaded();\n this.data[provider] = creds;\n await this.save();\n }\n\n async clearCredentials(provider: string): Promise<void> {\n await this.ensureLoaded();\n delete this.data[provider];\n await this.save();\n }\n\n async clearAll(): Promise<void> {\n this.data = {};\n await this.save();\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 // 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 try {\n return await this.resolveCredentials(MOONSHOT_OAUTH_KEY, opts);\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 - REFRESH_SKEW_MS) {\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 // Re-read from disk in case another process refreshed while we waited for the lock\n try {\n const content = await fs.readFile(this.filePath, \"utf-8\");\n const freshData = JSON.parse(content) as AuthData;\n const freshCreds = freshData[provider];\n if (\n freshCreds &&\n !opts?.forceRefresh &&\n Date.now() < freshCreds.expiresAt - REFRESH_SKEW_MS\n ) {\n // Another process already refreshed — use their token\n this.data[provider] = freshCreds;\n return freshCreds;\n }\n } catch {\n // Fall through to refresh\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(creds.refreshToken);\n } catch (err) {\n // Refresh token revoked / expired / invalid → the stored creds are\n // unusable. Wipe them so the next launch surfaces a clean\n // NotLoggedInError instead of hitting the same dead refresh path\n // every time. The user must re-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 this.data[provider];\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n throw new NotLoggedInError(provider);\n }\n throw err;\n }\n if (!refreshed.accountId && creds.accountId) {\n refreshed.accountId = creds.accountId;\n }\n if (!refreshed.projectId && creds.projectId) {\n refreshed.projectId = creds.projectId;\n }\n if (!refreshed.baseUrl && creds.baseUrl) {\n refreshed.baseUrl = creds.baseUrl;\n }\n this.data[provider] = refreshed;\n // Write atomically (we already hold the file lock)\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, 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 private async save(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n });\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\";\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 sessionId = \"\";\nlet appName = \"app\";\nlet cleanups: (() => void)[] = [];\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) return false;\n appName = name;\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 return false;\n }\n sessionId = randomBytes(4).toString(\"hex\");\n // Visible separator between sessions when back-reading the log.\n try {\n fs.writeSync(fd, \"\\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 let line = `[${ts}] [sid=${sessionId}] [${level}] [${category}] ${message}`;\n if (data) {\n const pairs = Object.entries(data)\n .map(([k, v]) => `${k}=${typeof v === \"string\" ? v : JSON.stringify(v)}`)\n .join(\" \");\n if (pairs) line += ` ${pairs}`;\n }\n line += \"\\n\";\n try {\n 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) return;\n if (opts?.shutdownLine !== false) log(\"INFO\", \"shutdown\", `${appName} shutting down`);\n try {\n fs.closeSync(fd);\n } catch {\n // Ignore close errors\n }\n fd = null;\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","/**\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 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 { 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 { 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.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 * - GLM / Moonshot / 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 Fable 5 (`claude-fable-5`) and Claude Mythos 5\n // (`claude-mythos-5`) are temporarily unavailable, so they're commented out\n // here to keep them out of the /model selector and avoid user confusion.\n // Re-enable once they're generally available again.\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 {\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 {\n id: \"gpt-5.4\",\n name: \"GPT-5.4\",\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 {\n id: \"gpt-5.4-mini\",\n name: \"GPT-5.4 Mini\",\n provider: \"openai\",\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"xhigh\",\n },\n {\n id: \"gpt-5.3-codex\",\n name: \"GPT-5.3 Codex\",\n provider: \"openai\",\n contextWindow: 400_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 // ── Gemini ─────────────────────────────────────────────\n {\n id: \"gemini-3.1-flash-lite-preview\",\n name: \"Gemini 3.1 Flash Lite 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: \"low\",\n maxThinkingLevel: \"high\",\n },\n {\n id: \"gemini-3.5-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 // ── Moonshot (Kimi) ────────────────────────────────────\n {\n id: \"kimi-k2.7-code\",\n name: \"Kimi K2.7\",\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.5\")!;\n if (provider === \"gemini\") return MODELS.find((m) => m.id === \"gemini-3.1-flash-lite-preview\")!;\n if (provider === \"glm\") return MODELS.find((m) => m.id === \"glm-5.2\")!;\n if (provider === \"moonshot\") return MODELS.find((m) => m.id === \"kimi-k2.7-code\")!;\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 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\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 * 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"],"mappings":";;;;;AAAA,OAAOA,SAAQ;AACf,OAAOC,aAAY;;;ACDnB,OAAOC,aAAY;;;ACAnB,SAAS,gBAAgB,OAA2B;AAClD,MAAI,SAAS;AACb,aAAW,QAAQ,OAAO;AACxB,cAAU,OAAO,aAAa,IAAI;AAAA,EACpC;AACA,SAAO,KAAK,MAAM,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,MAAM,EAAE;AAC9E;AAEA,eAAsB,eAAiE;AACrF,QAAM,gBAAgB,IAAI,WAAW,EAAE;AACvC,SAAO,gBAAgB,aAAa;AACpC,QAAM,WAAW,gBAAgB,aAAa;AAE9C,QAAM,OAAO,IAAI,YAAY,EAAE,OAAO,QAAQ;AAC9C,QAAM,aAAa,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI;AAC7D,QAAM,YAAY,gBAAgB,IAAI,WAAW,UAAU,CAAC;AAE5D,SAAO,EAAE,UAAU,UAAU;AAC/B;;;AClBA,OAAOC,SAAQ;AACf,OAAOC,WAAU;;;ACDjB,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,mBAAmB;AAQ5B,IAAM,YAAY,KAAK,OAAO;AAE9B,IAAI,KAAoB;AACxB,IAAI,YAAY;AAChB,IAAI,UAAU;AACd,IAAI,WAA2B,CAAC;AAEhC,SAAS,eAAe,UAAwB;AAC9C,MAAI;AACF,UAAM,KAAK,GAAG,SAAS,QAAQ;AAC/B,QAAI,GAAG,OAAO,UAAW;AACzB,UAAM,UAAU,GAAG,QAAQ;AAG3B,QAAI;AACF,SAAG,WAAW,OAAO;AAAA,IACvB,QAAQ;AAAA,IAER;AACA,OAAG,WAAW,UAAU,OAAO;AAAA,EACjC,QAAQ;AAAA,EAER;AACF;AASO,SAAS,QAAQ,UAAkB,MAAuB;AAC/D,MAAI,OAAO,KAAM,QAAO;AACxB,YAAU;AACV,MAAI;AACF,OAAG,UAAU,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAAA,EACvE,QAAQ;AAAA,EAER;AACA,iBAAe,QAAQ;AACvB,MAAI;AACF,SAAK,GAAG,SAAS,UAAU,GAAG;AAAA,EAChC,QAAQ;AAEN,WAAO;AAAA,EACT;AACA,cAAY,YAAY,CAAC,EAAE,SAAS,KAAK;AAEzC,MAAI;AACF,OAAG,UAAU,IAAI,IAAI;AAAA,EACvB,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAGO,SAAS,eAAuB;AACrC,SAAO;AACT;AAGO,SAAS,eAAwB;AACtC,SAAO,OAAO;AAChB;AAGO,SAAS,IACd,OACA,UACA,SACA,MACM;AACN,MAAI,OAAO,KAAM;AACjB,QAAM,MAAK,oBAAI,KAAK,GAAE,YAAY;AAClC,MAAI,OAAO,IAAI,EAAE,UAAU,SAAS,MAAM,KAAK,MAAM,QAAQ,KAAK,OAAO;AACzE,MAAI,MAAM;AACR,UAAM,QAAQ,OAAO,QAAQ,IAAI,EAC9B,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,MAAM,WAAW,IAAI,KAAK,UAAU,CAAC,CAAC,EAAE,EACvE,KAAK,GAAG;AACX,QAAI,MAAO,SAAQ,IAAI,KAAK;AAAA,EAC9B;AACA,UAAQ;AACR,MAAI;AACF,OAAG,UAAU,IAAI,IAAI;AAAA,EACvB,QAAQ;AAAA,EAER;AACF;AAOO,SAAS,mBAAmB,IAAsB;AACvD,WAAS,KAAK,EAAE;AAClB;AAMO,SAAS,YAAY,MAAyC;AACnE,MAAI,OAAO,KAAM;AACjB,MAAI,MAAM,iBAAiB,MAAO,KAAI,QAAQ,YAAY,GAAG,OAAO,gBAAgB;AACpF,MAAI;AACF,OAAG,UAAU,EAAE;AAAA,EACjB,QAAQ;AAAA,EAER;AACA,OAAK;AACL,aAAW,SAAS,SAAU,OAAM;AACpC,aAAW,CAAC;AACd;;;ADrHA,IAAM,iBAAiB;AACvB,IAAM,eAAe,KAAK,KAAK,KAAK;AACpC,IAAM,mBAAmB;AAIzB,IAAM,mBAAmB;AAIzB,IAAI,cAA6D;AACjE,IAAI,WAAmC;AAEvC,SAAS,YAAoB;AAC3B,SAAOC,MAAK,KAAK,YAAY,EAAE,UAAU,0BAA0B;AACrE;AAEA,eAAe,gBAA+C;AAC5D,MAAI;AACF,UAAM,MAAM,MAAMC,IAAG,SAAS,UAAU,GAAG,OAAO;AAClD,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,OAAO,OAAO,YAAY,YAAY,OAAO,OAAO,cAAc,UAAU;AAC9E,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,eAAe,MAAoC;AAChE,MAAI;AACF,UAAMA,IAAG,MAAM,YAAY,EAAE,UAAU,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACvE,UAAMA,IAAG,UAAU,UAAU,GAAG,KAAK,UAAU,IAAI,GAAG,EAAE,MAAM,IAAM,CAAC;AAAA,EACvE,SAAS,KAAK;AACZ;AAAA,MACE;AAAA,MACA;AAAA,MACA,0BAA0B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC5E;AAAA,EACF;AACF;AAEA,eAAe,cAAsC;AACnD,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,gBAAgB;AACnE,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,gBAAgB,EAAE,QAAQ,WAAW,OAAO,CAAC;AAC1E,QAAI,CAAC,SAAS,GAAI,QAAO;AACzB,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,QAAI,OAAO,KAAK,YAAY,YAAY,MAAM,KAAK,KAAK,OAAO,GAAG;AAChE,aAAO,KAAK;AAAA,IACd;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT,UAAE;AACA,iBAAa,KAAK;AAAA,EACpB;AACF;AAQA,eAAsB,uBAAwC;AAC5D,MAAI,eAAe,KAAK,IAAI,IAAI,YAAY,WAAW;AACrD,WAAO,YAAY;AAAA,EACrB;AACA,MAAI,SAAU,QAAO;AAErB,cAAY,YAAY;AACtB,UAAM,OAAO,MAAM,cAAc;AACjC,UAAM,YAAY,QAAQ,KAAK,IAAI,IAAI,KAAK,YAAY;AACxD,QAAI,QAAQ,WAAW;AACrB,oBAAc,EAAE,SAAS,KAAK,SAAS,WAAW,KAAK,IAAI,IAAI,aAAa;AAC5E,aAAO,KAAK;AAAA,IACd;AACA,UAAM,UAAU,MAAM,YAAY;AAClC,QAAI,SAAS;AACX,YAAM,eAAe,EAAE,SAAS,SAAS,WAAW,KAAK,IAAI,EAAE,CAAC;AAChE,oBAAc,EAAE,SAAS,SAAS,WAAW,KAAK,IAAI,IAAI,aAAa;AACvE,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,MAAM,WAAW;AAElC,kBAAc,EAAE,SAAS,UAAU,WAAW,KAAK,IAAI,IAAI,IAAI,KAAK,IAAK;AACzE;AAAA,MACE;AAAA,MACA;AAAA,MACA,qDAAqD,QAAQ;AAAA,IAC/D;AACA,WAAO;AAAA,EACT,GAAG;AAEH,MAAI;AACF,WAAO,MAAM;AAAA,EACf,UAAE;AACA,eAAW;AAAA,EACb;AACF;AAGA,eAAsB,wBAAyC;AAC7D,QAAM,UAAU,MAAM,qBAAqB;AAC3C,SAAO,cAAc,OAAO;AAC9B;;;AFhHA,IAAM,YAAY,KAAK,kDAAkD;AACzE,IAAM,gBAAgB;AAItB,IAAM,aAAa;AAAA,EACjB;AAAA,EACA;AACF;AACA,IAAM,eAAe;AACrB,IAAM,SACJ;AAQF,eAAe,iBACb,MACA,OACwB;AACxB,QAAM,UAAU,KAAK,UAAU,IAAI;AAInC,QAAM,UAAU;AAAA,IACd,gBAAgB;AAAA,IAChB,cAAc,MAAM,sBAAsB;AAAA,IAC1C,kBAAkB;AAAA,EACpB;AACA,MAAI,YAA0B;AAC9B,aAAW,OAAO,YAAY;AAC5B,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,MAAM,KAAK,EAAE,QAAQ,QAAQ,SAAS,MAAM,QAAQ,CAAC;AAAA,IACxE,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAC9D;AAAA,IACF;AACA,QAAI,SAAS,IAAI;AACf,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AACA,UAAM,OAAO,MAAM,SAAS,KAAK;AAIjC,QAAI,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;AACnD,YAAM,IAAI,MAAM,aAAa,KAAK,YAAY,SAAS,MAAM,MAAM,IAAI,EAAE;AAAA,IAC3E;AACA,gBAAY,IAAI,MAAM,aAAa,KAAK,YAAY,SAAS,MAAM,MAAM,IAAI,EAAE;AAAA,EACjF;AACA,QAAM,aAAa,IAAI,MAAM,aAAa,KAAK,oCAAoC;AACrF;AAEA,SAAS,cAAc,MAAuC;AAC5D,SAAO;AAAA,IACL,aAAa,KAAK;AAAA,IAClB,cAAc,KAAK;AAAA,IACnB,WAAW,KAAK,IAAI,IAAI,KAAK,aAAa,MAAO,IAAI,KAAK;AAAA,EAC5D;AACF;AAEA,eAAsB,eAAe,WAA2D;AAC9F,QAAM,EAAE,UAAU,UAAU,IAAI,MAAM,aAAa;AACnD,QAAM,QAAQC,QAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AAEnD,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,MAAM;AAAA,IACN,WAAW;AAAA,IACX,eAAe;AAAA,IACf,cAAc;AAAA,IACd,OAAO;AAAA,IACP,gBAAgB;AAAA,IAChB,uBAAuB;AAAA,IACvB;AAAA,EACF,CAAC;AAED,QAAM,UAAU,GAAG,aAAa,IAAI,MAAM;AAC1C,YAAU,UAAU,OAAO;AAE3B,QAAM,MAAM,MAAM,UAAU,aAAa,uDAAuD;AAEhG,QAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,GAAG;AAClC,MAAI,MAAM,WAAW,KAAK,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,OAAO;AACzD,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AAEA,SAAO,sBAAsB,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,QAAQ;AAC3D;AAEA,eAAe,sBACb,MACA,OACA,UAC2B;AAC3B,QAAM,OAAO,MAAM;AAAA,IACjB;AAAA,MACE,YAAY;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACA,SAAO,cAAc,IAAI;AAC3B;AAEA,eAAsB,sBAAsB,cAAiD;AAC3F,QAAM,OAAO,MAAM;AAAA,IACjB;AAAA,MACE,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,eAAe;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACA,SAAO,cAAc,IAAI;AAC3B;;;AI9HA,OAAO,UAAU;AACjB,OAAOC,aAAY;AAInB,IAAMC,aAAY;AAClB,IAAMC,iBAAgB;AACtB,IAAM,YAAY;AAClB,IAAMC,gBAAe;AACrB,IAAM,QAAQ;AACd,IAAM,iBAAiB;AAEvB,eAAsB,YAAY,WAA2D;AAC3F,QAAM,EAAE,UAAU,UAAU,IAAI,MAAM,aAAa;AACnD,QAAM,QAAQC,QAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AAEnD,QAAM,MAAM,IAAI,IAAIF,cAAa;AACjC,MAAI,aAAa,IAAI,iBAAiB,MAAM;AAC5C,MAAI,aAAa,IAAI,aAAaD,UAAS;AAC3C,MAAI,aAAa,IAAI,gBAAgBE,aAAY;AACjD,MAAI,aAAa,IAAI,SAAS,KAAK;AACnC,MAAI,aAAa,IAAI,kBAAkB,SAAS;AAChD,MAAI,aAAa,IAAI,yBAAyB,MAAM;AACpD,MAAI,aAAa,IAAI,SAAS,KAAK;AAGnC,MAAI,aAAa,IAAI,UAAU,OAAO;AACtC,MAAI,aAAa,IAAI,8BAA8B,MAAM;AACzD,MAAI,aAAa,IAAI,6BAA6B,MAAM;AACxD,MAAI,aAAa,IAAI,cAAc,SAAS;AAE5C,MAAI;AAEJ,MAAI;AACF,WAAO,MAAM,gBAAgB,IAAI,SAAS,GAAG,OAAO,SAAS;AAAA,EAC/D,QAAQ;AAEN,cAAU,UAAU,IAAI,SAAS,CAAC;AAClC,UAAM,MAAM,MAAM,UAAU;AAAA,MAC1B;AAAA,IACF;AACA,UAAM,SAAS,wBAAwB,GAAG;AAC1C,QAAI,CAAC,OAAO,MAAM;AAChB,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AACA,WAAO,OAAO;AAAA,EAChB;AAEA,QAAM,QAAQ,MAAM,mBAAmB,MAAM,QAAQ;AAErD,QAAM,YAAY,aAAa,MAAM,WAAW;AAChD,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AACA,QAAM,YAAY;AAElB,SAAO;AACT;AAEA,SAAS,wBAAwB,OAAkD;AACjF,QAAM,QAAQ,MAAM,KAAK;AACzB,MAAI,CAAC,MAAO,QAAO,CAAC;AAGpB,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,KAAK;AACzB,WAAO;AAAA,MACL,MAAM,IAAI,aAAa,IAAI,MAAM,KAAK;AAAA,MACtC,OAAO,IAAI,aAAa,IAAI,OAAO,KAAK;AAAA,IAC1C;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,MAAI,MAAM,SAAS,GAAG,GAAG;AACvB,UAAM,CAAC,MAAM,KAAK,IAAI,MAAM,MAAM,KAAK,CAAC;AACxC,WAAO,EAAE,MAAM,MAAM;AAAA,EACvB;AAGA,MAAI,MAAM,SAAS,OAAO,GAAG;AAC3B,UAAM,SAAS,IAAI,gBAAgB,KAAK;AACxC,WAAO;AAAA,MACL,MAAM,OAAO,IAAI,MAAM,KAAK;AAAA,MAC5B,OAAO,OAAO,IAAI,OAAO,KAAK;AAAA,IAChC;AAAA,EACF;AAGA,SAAO,EAAE,MAAM,MAAM;AACvB;AAEA,SAAS,UAAU,OAA+C;AAChE,MAAI;AACF,UAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,QAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,UAAM,UAAU,KAAK,MAAM,CAAC,CAAC;AAC7B,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,aAAa,aAAoC;AACxD,QAAM,UAAU,UAAU,WAAW;AACrC,QAAM,OAAO,UAAU,cAAc;AACrC,QAAM,YAAY,MAAM;AACxB,SAAO,OAAO,cAAc,YAAY,UAAU,SAAS,IAAI,YAAY;AAC7E;AAEA,eAAe,gBACb,SACA,eACA,WACiB;AACjB,SAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,QAAI,eAA8B;AAElC,UAAM,SAAS,KAAK,aAAa,CAAC,KAAK,QAAQ;AAC7C,YAAM,MAAM,IAAI,IAAI,IAAI,OAAO,IAAI,kBAAkB;AAErD,UAAI,IAAI,aAAa,kBAAkB;AACrC,YAAI,aAAa;AACjB,YAAI,IAAI,WAAW;AACnB;AAAA,MACF;AAEA,UAAI,IAAI,aAAa,IAAI,OAAO,MAAM,eAAe;AACnD,YAAI,aAAa;AACjB,YAAI,IAAI,gBAAgB;AACxB;AAAA,MACF;AAEA,qBAAe,IAAI,aAAa,IAAI,MAAM;AAE1C,UAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,UAAI,IAAI,oFAAoF;AAE5F,aAAO,MAAM;AAAA,IACf,CAAC;AAED,WAAO,GAAG,SAAS,CAAC,QAAQ;AAC1B,aAAO,GAAG;AAAA,IACZ,CAAC;AAED,WAAO,OAAO,MAAM,aAAa,MAAM;AACrC,gBAAU,UAAU,OAAO;AAC3B,gBAAU,SAAS,iCAAiC;AAAA,IACtD,CAAC;AAED,UAAM,UAAU,WAAW,MAAM;AAC/B,UAAI,CAAC,cAAc;AACjB,eAAO,MAAM;AAAA,MACf;AAAA,IACF,GAAG,IAAO;AACV,YAAQ,MAAM;AAEd,WAAO,GAAG,SAAS,MAAM;AACvB,mBAAa,OAAO;AACpB,UAAI,cAAc;AAChB,gBAAQ,YAAY;AAAA,MACtB,OAAO;AACL,eAAO,IAAI,MAAM,sCAAsC,CAAC;AAAA,MAC1D;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAe,mBAAmB,MAAc,UAA6C;AAC3F,QAAM,WAAW,MAAM,MAAM,WAAW;AAAA,IACtC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,IAC/D,MAAM,IAAI,gBAAgB;AAAA,MACxB,YAAY;AAAA,MACZ,WAAWF;AAAA,MACX;AAAA,MACA,cAAcE;AAAA,MACd,eAAe;AAAA,IACjB,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,MAAM,IAAI,EAAE;AAAA,EAC9E;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAMlC,SAAO;AAAA,IACL,aAAa,KAAK;AAAA,IAClB,cAAc,KAAK;AAAA,IACnB,WAAW,KAAK,IAAI,IAAI,KAAK,aAAa;AAAA,EAC5C;AACF;AAEA,eAAsB,mBAAmB,cAAiD;AACxF,QAAM,WAAW,MAAM,MAAM,WAAW;AAAA,IACtC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,IAC/D,MAAM,IAAI,gBAAgB;AAAA,MACxB,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,WAAWF;AAAA,IACb,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,IAAI,MAAM,gCAAgC,SAAS,MAAM,MAAM,IAAI,EAAE;AAAA,EAC7E;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAMlC,QAAM,QAA0B;AAAA,IAC9B,aAAa,KAAK;AAAA,IAClB,cAAc,KAAK;AAAA,IACnB,WAAW,KAAK,IAAI,IAAI,KAAK,aAAa;AAAA,EAC5C;AAEA,QAAM,YAAY,aAAa,MAAM,WAAW;AAChD,MAAI,WAAW;AACb,UAAM,YAAY;AAAA,EACpB;AAEA,SAAO;AACT;;;AC1OA,OAAOI,WAAU;AACjB,OAAOC,aAAY;AAInB,IAAM,gBAAgB;AACtB,IAAM,oBAAoB;AAO1B,IAAM,oBACJ;AACF,IAAM,wBAAwB;AAC9B,IAAMC,iBAAgB;AACtB,IAAMC,aAAY;AAClB,IAAM,uBAAuB;AAC7B,IAAM,0BAA0B;AAChC,IAAM,2BAA2B;AACjC,IAAM,kCAAkC;AACxC,IAAMC,SAAQ;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AA6CV,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,6BAA6B;AACnC,IAAM,gBAAgB;AAEtB,IAAM,sBAAN,cAAkC,MAAM;AAAA,EAC7B;AAAA,EACA;AAAA,EAET,YAAY,OAAe,QAAgB,MAAc;AACvD,UAAM,sBAAsB,KAAK,YAAY,MAAM,MAAM,IAAI,EAAE;AAC/D,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;AAEA,eAAsB,YAAY,WAA2D;AAC3F,QAAM,EAAE,UAAU,aAAa,IAAI,gCAAgC;AACnE,QAAM,EAAE,UAAU,UAAU,IAAI,MAAM,aAAa;AACnD,QAAM,QAAQC,QAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AACnD,QAAM,cAAc,MAAM,uBAAuB;AAEjD,QAAM,MAAM,IAAI,IAAIH,cAAa;AACjC,MAAI,aAAa,IAAI,iBAAiB,MAAM;AAC5C,MAAI,aAAa,IAAI,aAAa,QAAQ;AAC1C,MAAI,aAAa,IAAI,gBAAgB,WAAW;AAChD,MAAI,aAAa,IAAI,SAASE,MAAK;AACnC,MAAI,aAAa,IAAI,eAAe,SAAS;AAC7C,MAAI,aAAa,IAAI,UAAU,SAAS;AACxC,MAAI,aAAa,IAAI,kBAAkB,SAAS;AAChD,MAAI,aAAa,IAAI,yBAAyB,MAAM;AACpD,MAAI,aAAa,IAAI,SAAS,KAAK;AAEnC,MAAI;AACJ,MAAI;AACF,WAAO,MAAME,iBAAgB,IAAI,SAAS,GAAG,aAAa,OAAO,SAAS;AAAA,EAC5E,QAAQ;AACN,cAAU,UAAU,IAAI,SAAS,CAAC;AAClC,UAAM,MAAM,MAAM,UAAU;AAAA,MAC1B;AAAA,IACF;AACA,UAAM,SAASC,yBAAwB,GAAG;AAC1C,QAAI,CAAC,OAAO,MAAM;AAChB,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AACA,QAAI,OAAO,SAAS,OAAO,UAAU,OAAO;AAC1C,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AACA,WAAO,OAAO;AAAA,EAChB;AAEA,QAAM,QAAQ,MAAM,mBAAmB,MAAM,UAAU,aAAa,UAAU,YAAY;AAC1F,YAAU,SAAS,yCAAyC;AAC5D,QAAM,YAAY,MAAM,uBAAuB,MAAM,aAAa,SAAS;AAE3E,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,EACF;AACF;AAEA,eAAsB,mBAAmB,cAAiD;AACxF,QAAM,EAAE,UAAU,aAAa,IAAI,gCAAgC;AACnE,QAAM,OAAO,MAAMC,kBAAiB;AAAA,IAClC,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,WAAW;AAAA,IACX,eAAe;AAAA,EACjB,CAAC;AAED,SAAO;AAAA,IACL,aAAa,KAAK;AAAA,IAClB,cAAc,KAAK,iBAAiB;AAAA,IACpC,WAAW,KAAK,IAAI,IAAI,KAAK,aAAa,MAAO,IAAI,KAAK;AAAA,EAC5D;AACF;AAEA,SAAS,kCAAgE;AACvE,QAAM,WAAW,QAAQ,IAAI,aAAa,GAAG,KAAK,KAAK;AACvD,QAAM,eAAe,QAAQ,IAAI,iBAAiB,GAAG,KAAK,KAAK;AAC/D,SAAO,EAAE,UAAU,aAAa;AAClC;AAEA,eAAe,yBAA0C;AACvD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAASC,MAAK,aAAa;AACjC,WAAO,OAAO,GAAG,aAAa,MAAM;AAClC,YAAM,OAAO,OAAO,QAAQ;AAC5B,aAAO,MAAM,MAAM;AACjB,YAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,kBAAQ,oBAAoB,KAAK,IAAI,iBAAiB;AAAA,QACxD,OAAO;AACL,iBAAO,IAAI,MAAM,yCAAyC,CAAC;AAAA,QAC7D;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AACD,WAAO,GAAG,SAAS,MAAM;AAAA,EAC3B,CAAC;AACH;AAEA,SAASF,yBAAwB,OAAkD;AACjF,QAAM,QAAQ,MAAM,KAAK;AACzB,MAAI,CAAC,MAAO,QAAO,CAAC;AAEpB,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,KAAK;AACzB,WAAO;AAAA,MACL,MAAM,IAAI,aAAa,IAAI,MAAM,KAAK;AAAA,MACtC,OAAO,IAAI,aAAa,IAAI,OAAO,KAAK;AAAA,IAC1C;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,MAAI,MAAM,SAAS,OAAO,GAAG;AAC3B,UAAM,SAAS,IAAI,gBAAgB,KAAK;AACxC,WAAO;AAAA,MACL,MAAM,OAAO,IAAI,MAAM,KAAK;AAAA,MAC5B,OAAO,OAAO,IAAI,OAAO,KAAK;AAAA,IAChC;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,MAAM;AACvB;AAEA,eAAeD,iBACb,SACA,aACA,eACA,WACiB;AACjB,QAAM,WAAW,IAAI,IAAI,WAAW;AACpC,QAAM,OAAO,OAAO,SAAS,IAAI;AAEjC,SAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,QAAI,eAA8B;AAElC,UAAM,SAASG,MAAK,aAAa,CAAC,KAAK,QAAQ;AAC7C,YAAM,MAAM,IAAI,IAAI,IAAI,OAAO,IAAI,SAAS,MAAM;AAElD,UAAI,IAAI,aAAa,SAAS,UAAU;AACtC,YAAI,aAAa;AACjB,YAAI,IAAI,WAAW;AACnB;AAAA,MACF;AAEA,UAAI,IAAI,aAAa,IAAI,OAAO,MAAM,eAAe;AACnD,YAAI,aAAa;AACjB,YAAI,IAAI,gBAAgB;AACxB;AAAA,MACF;AAEA,qBAAe,IAAI,aAAa,IAAI,MAAM;AAC1C,UAAI,UAAU,KAAK,EAAE,gBAAgB,aAAa,YAAY,QAAQ,CAAC;AACvE,UAAI,IAAI,oFAAoF;AAC5F,aAAO,MAAM;AAAA,IACf,CAAC;AAED,WAAO,GAAG,SAAS,CAAC,QAAQ,OAAO,GAAG,CAAC;AACvC,WAAO,OAAO,MAAM,aAAa,MAAM;AACrC,gBAAU,UAAU,OAAO;AAC3B,gBAAU,SAAS,iCAAiC;AAAA,IACtD,CAAC;AAED,UAAM,UAAU,WAAW,MAAM;AAC/B,UAAI,CAAC,aAAc,QAAO,MAAM;AAAA,IAClC,GAAG,IAAO;AACV,YAAQ,MAAM;AAEd,WAAO,GAAG,SAAS,MAAM;AACvB,mBAAa,OAAO;AACpB,UAAI,cAAc;AAChB,gBAAQ,YAAY;AAAA,MACtB,OAAO;AACL,eAAO,IAAI,MAAM,uCAAuC,CAAC;AAAA,MAC3D;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAe,mBACb,MACA,UACA,aACA,UACA,cAC2B;AAC3B,QAAM,OAAO,MAAMD,kBAAiB;AAAA,IAClC,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,eAAe;AAAA,IACf;AAAA,IACA,cAAc;AAAA,IACd,eAAe;AAAA,EACjB,CAAC;AAED,MAAI,CAAC,KAAK,eAAe;AACvB,UAAM,IAAI,MAAM,sEAAsE;AAAA,EACxF;AAEA,SAAO;AAAA,IACL,aAAa,KAAK;AAAA,IAClB,cAAc,KAAK;AAAA,IACnB,WAAW,KAAK,IAAI,IAAI,KAAK,aAAa,MAAO,IAAI,KAAK;AAAA,EAC5D;AACF;AAEA,eAAeA,kBAAiB,MAA4D;AAC1F,QAAM,WAAW,MAAM,MAAML,YAAW;AAAA,IACtC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,IAC/D,MAAM,IAAI,gBAAgB,IAAI;AAAA,EAChC,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,IAAI,MAAM,gCAAgC,SAAS,MAAM,MAAM,IAAI,EAAE;AAAA,EAC7E;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAEA,eAAe,uBACb,aACA,WACiB;AACjB,QAAM,aAAa,QAAQ,IAAI,wBAAwB,QAAQ,IAAI;AACnE,MAAI,cAAc,QAAQ,KAAK,UAAU,GAAG;AAC1C,UAAM,IAAI,MAAM,0EAA0E;AAAA,EAC5F;AAEA,QAAM,eAAe;AAAA,IACnB,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACA,QAAM,kBAAkB;AAAA,IACtB,GAAG;AAAA,IACH,GAAI,aAAa,EAAE,aAAa,WAAW,IAAI,CAAC;AAAA,EAClD;AAEA,MAAI;AACJ,SAAO,MAAM;AACX,cAAU,MAAM,eAAe,aAAa,YAAY,eAAe;AACvE,UAAM,aAAa,0BAA0B,OAAO;AACpD,QAAI,CAAC,WAAY;AAEjB,cAAU;AAAA,MACR,iDACE,WAAW,gBAAgB,KAAK,WAAW,aAAa,KAAK,EAC/D;AAAA,IACF;AACA,cAAU,UAAU,WAAW,aAAa;AAC5C,UAAM,SAAS,MAAM,UAAU;AAAA,MAC7B;AAAA,IACF;AACA,QAAI,OAAO,KAAK,EAAE,YAAY,MAAM,UAAU;AAC5C,YAAM,IAAI,MAAM,sDAAsD;AAAA,IACxE;AAAA,EACF;AAEA,MAAI,QAAQ,aAAa;AACvB,UAAMO,WAAU,QAAQ,2BAA2B;AACnD,QAAI,CAACA,SAAS,mBAAkB,OAAO;AACvC,WAAOA;AAAA,EACT;AAEA,QAAM,OAAO,eAAe,OAAO;AACnC,QAAM,aACJ,KAAK,OAAO,iBACR;AAAA,IACE,QAAQ,KAAK;AAAA,IACb,yBAAyB;AAAA,IACzB,UAAU;AAAA,EACZ,IACA;AAAA,IACE,QAAQ,KAAK;AAAA,IACb,yBAAyB;AAAA,IACzB,UAAU;AAAA,EACZ;AAEN,MAAI,YAAY,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,CAAC,UAAU,QAAQ,UAAU,MAAM;AACxC,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAK,CAAC;AACzD,gBAAY,MAAM,cAA4C,aAAa,UAAU,IAAI;AAAA,EAC3F;AAEA,QAAM,UAAU,UAAU,UAAU,yBAAyB,MAAM;AACnE,MAAI,CAAC,QAAS,mBAAkB,OAAO;AACvC,SAAO;AACT;AAEA,eAAe,eACb,aACA,YACA,UACiC;AACjC,MAAI;AACF,WAAO,MAAM,eAAuC,aAAa,kBAAkB;AAAA,MACjF,GAAI,aAAa,EAAE,yBAAyB,WAAW,IAAI,CAAC;AAAA,MAC5D;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,QAAI,eAAe,uBAAuB,qBAAqB,GAAG,GAAG;AACnE,aAAO,EAAE,aAAa,EAAE,IAAI,mBAAmB,EAAE;AAAA,IACnD;AACA,QACE,eAAe,uBACf,IAAI,WAAW,OACf,eAAe,kBACf;AACA,YAAM,IAAI;AAAA,QACR;AAAA,QAIA,EAAE,OAAO,IAAI;AAAA,MACf;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAEA,SAAS,0BACP,UAC0D;AAC1D,SAAO,SAAS,iBAAiB;AAAA,IAC/B,CAAC,SACC,KAAK,eAAe,8BAA8B,OAAO,KAAK,kBAAkB;AAAA,EACpF;AACF;AAEA,SAAS,eAAe,UAAkD;AACxE,QAAM,cAAc,SAAS,cAAc,KAAK,CAAC,SAAS,KAAK,SAAS;AACxE,SAAO,eAAe,EAAE,IAAI,kBAAkB,MAAM,GAAG;AACzD;AAEA,SAAS,kBAAkB,UAAyC;AAClE,QAAM,UAAU,SAAS,iBACrB,IAAI,CAAC,SAAS,KAAK,iBAAiB,KAAK,QAAQ,EAClD,OAAO,CAAC,WAA6B,QAAQ,MAAM,CAAC;AACvD,MAAI,WAAW,QAAQ,SAAS,GAAG;AACjC,UAAM,IAAI,MAAM,oCAAoC,QAAQ,KAAK,IAAI,CAAC,EAAE;AAAA,EAC1E;AACA,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;AAEA,eAAe,eACb,aACA,QACA,MACY;AACZ,MAAI;AACJ,WAAS,UAAU,GAAG,WAAW,0BAA0B,WAAW;AACpE,QAAI;AACF,aAAO,MAAM,kBAAqB,uBAAuB,MAAM,GAAG,aAAa,QAAQ;AAAA,QACrF,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,UACE,EAAE,eAAe,wBACjB,YAAY,4BACZ,CAAC,4BAA4B,IAAI,MAAM,GACvC;AACA,cAAM;AAAA,MACR;AACA,kBAAY;AAAA,IACd;AACA,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,+BAA+B,CAAC;AAAA,EACrF;AAEA,QAAM,aAAa,IAAI,MAAM,sBAAsB,MAAM,UAAU;AACrE;AAEA,eAAe,cAAiB,aAAqB,eAAmC;AACtF,SAAO,kBAAqB,0BAA0B,aAAa,GAAG,aAAa,aAAa;AAAA,IAC9F,QAAQ;AAAA,EACV,CAAC;AACH;AAEA,eAAe,kBACb,KACA,aACA,OACA,MACY;AACZ,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,GAAG;AAAA,IACH,SAAS,kBAAkB,WAAW;AAAA,EACxC,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,IAAI,oBAAoB,OAAO,SAAS,QAAQ,IAAI;AAAA,EAC5D;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAEA,SAAS,uBAA+B;AACtC,QAAM,WAAW,QAAQ,IAAI,wBAAwB;AACrD,QAAM,UAAU,QAAQ,IAAI,2BAA2B;AACvD,SAAO,GAAG,QAAQ,IAAI,OAAO;AAC/B;AAEA,SAAS,uBAAuB,QAAwB;AACtD,SAAO,GAAG,qBAAqB,CAAC,IAAI,MAAM;AAC5C;AAEA,SAAS,0BAA0B,eAA+B;AAChE,SAAO,GAAG,qBAAqB,CAAC,IAAI,aAAa;AACnD;AAEA,SAAS,4BAA4B,QAAyB;AAC5D,SAAO,WAAW,OAAO,WAAW,OAAQ,UAAU,OAAO,UAAU;AACzE;AAEA,SAAS,qBAAqB,OAAqC;AACjE,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,MAAM,IAAI;AACpC,QAAI,CAAC,UAAU,OAAO,WAAW,YAAY,EAAE,WAAW,QAAS,QAAO;AAC1E,UAAM,UAAW,OAA+C,OAAO;AACvE,WAAO,MAAM,QAAQ,OAAO,IACxB,QAAQ;AAAA,MACN,CAAC,WACC,UAAU,QACV,OAAO,WAAW,YAClB,YAAY,UACZ,OAAO,WAAW;AAAA,IACtB,IACA;AAAA,EACN,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,kBAAkB,aAA6C;AACtE,SAAO;AAAA,IACL,eAAe,UAAU,WAAW;AAAA,IACpC,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,qBAAqB;AAAA,EACvB;AACF;;;ACxfA,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,MAAM,UAAU,SAAS,YAAY;AAC9C,OAAOC,WAAU;AAMjB,IAAMC,aAAY;AAElB,IAAM,qBAAqB;AAC3B,IAAM,0BAA0B;AAGhC,IAAM,gBAAgB;AAMtB,IAAM,uBAAuB;AAG7B,IAAM,oBAAoB,KAAK,KAAK;AAEpC,SAAS,YAAoB;AAC3B,QAAM,OACJ,QAAQ,IAAI,wBAAwB,QAAQ,IAAI,mBAAmB;AACrE,SAAO,KAAK,QAAQ,QAAQ,EAAE;AAChC;AAGO,SAAS,kBAA0B;AACxC,UAAQ,QAAQ,IAAI,sBAAsB,yBAAyB,QAAQ,QAAQ,EAAE;AACvF;AAEA,SAAS,cAAsB;AAC7B,QAAM,IAAI,QAAQ,IAAI,qBAAqB;AAC3C,SAAO,YAAY,GAAG,oBAAoB;AAC5C;AAEA,SAAS,YAAY,OAAe,WAAW,WAAmB;AAChE,QAAM,UAAU,MAAM,QAAQ,qBAAqB,EAAE,EAAE,KAAK;AAC5D,SAAO,QAAQ,SAAS,IAAI,UAAU;AACxC;AAEA,SAAS,sBAA0C;AACjD,MAAI;AACF,UAAM,UAAU,aAAa,oBAAoB,CAAC,iBAAiB,GAAG;AAAA,MACpE,UAAU;AAAA,MACV,SAAS;AAAA,IACX,CAAC,EAAE,KAAK;AACR,WAAO,QAAQ,SAAS,IAAI,UAAU;AAAA,EACxC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,cAAsB;AAC7B,QAAM,KAAK,KAAK;AAChB,QAAM,UAAU,QAAQ;AACxB,QAAM,SAAS,KAAK;AACpB,MAAI,OAAO,SAAU,QAAO,SAAS,oBAAoB,KAAK,OAAO,IAAI,MAAM;AAC/E,MAAI,OAAO,aAAc,QAAO,WAAW,OAAO,IAAI,MAAM;AAC5D,SAAO,GAAG,EAAE,IAAI,OAAO,IAAI,MAAM,GAAG,KAAK;AAC3C;AAGA,SAAS,WAAmB;AAC1B,QAAM,SAASC,MAAK,KAAK,YAAY,EAAE,UAAU,gBAAgB;AACjE,MAAI,WAAW,MAAM,GAAG;AACtB,QAAI;AACF,YAAM,OAAO,aAAa,QAAQ,OAAO,EAAE,KAAK;AAChD,UAAI,KAAK,SAAS,EAAG,QAAO;AAAA,IAC9B,QAAQ;AAAA,IAER;AAAA,EACF;AACA,QAAM,KAAK,WAAW;AACtB,MAAI;AACF,cAAU,YAAY,EAAE,UAAU,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAClE,kBAAc,QAAQ,IAAI,EAAE,UAAU,SAAS,MAAM,IAAM,CAAC;AAAA,EAC9D,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,gBAAwC;AAC/C,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,iBAAiB,YAAY;AAAA,IAC7B,qBAAqB,YAAY,SAAS,CAAC;AAAA,IAC3C,sBAAsB,YAAY,YAAY,CAAC;AAAA,IAC/C,oBAAoB,YAAY,QAAQ,CAAC;AAAA,IACzC,mBAAmB,SAAS;AAAA,EAC9B;AACF;AASO,SAAS,oBAA4C;AAC1D,SAAO;AAAA,IACL,cAAc,iBAAiB,YAAY,CAAC;AAAA,IAC5C,GAAG,cAAc;AAAA,EACnB;AACF;AAQO,SAAS,qBAAqB,SAAsC;AACzE,MAAI,OAAO,YAAY,YAAY,QAAQ,WAAW,EAAG,QAAO;AAChE,QAAM,aAAa,QAAQ,QAAQ,QAAQ,EAAE;AAC7C,SAAO,eAAe,gBAAgB,KAAK,mBAAmB,KAAK,UAAU;AAC/E;AAEA,eAAe,SACb,UACA,QAC4D;AAC5D,QAAM,WAAW,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,QAAQ,IAAI;AAAA,IACxD,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,GAAG,cAAc;AAAA,MACjB,gBAAgB;AAAA,MAChB,QAAQ;AAAA,IACV;AAAA,IACA,MAAM,IAAI,gBAAgB,MAAM,EAAE,SAAS;AAAA,EAC7C,CAAC;AACD,MAAI,OAAgC,CAAC;AACrC,MAAI;AACF,UAAM,SAAkB,MAAM,SAAS,KAAK;AAC5C,QAAI,UAAU,OAAO,WAAW,SAAU,QAAO;AAAA,EACnD,QAAQ;AAAA,EAER;AACA,SAAO,EAAE,QAAQ,SAAS,QAAQ,KAAK;AACzC;AAEA,SAAS,YAAY,MAAuC;AAC1D,QAAM,OAAO,KAAK,qBAAqB,KAAK,WAAW,KAAK;AAC5D,SAAO,OAAO,SAAS,YAAY,KAAK,SAAS,IAAI,OAAO;AAC9D;AAEA,SAAS,uBACP,MACA,MACkB;AAClB,QAAM,cAAc,KAAK;AACzB,QAAM,uBAAuB,KAAK;AAClC,QAAM,YAAY,OAAO,KAAK,UAAU;AACxC,MAAI,OAAO,gBAAgB,YAAY,YAAY,WAAW,GAAG;AAC/D,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAMA,QAAM,eACJ,OAAO,yBAAyB,YAAY,qBAAqB,SAAS,IACtE,uBACC,MAAM,wBAAwB;AACrC,MAAI,aAAa,WAAW,GAAG;AAC7B,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACA,MAAI,CAAC,OAAO,SAAS,SAAS,KAAK,aAAa,GAAG;AACjD,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAI,IAAI,YAAY;AAAA,IACpC,SAAS,gBAAgB;AAAA,EAC3B;AACF;AAUA,eAAe,6BAA2D;AACxE,QAAM,EAAE,QAAQ,KAAK,IAAI,MAAM,SAAS,mCAAmC;AAAA,IACzE,WAAWD;AAAA,EACb,CAAC;AACD,MAAI,WAAW,KAAK;AAClB,UAAM,IAAI,MAAM,qCAAqC,MAAM,MAAM,YAAY,IAAI,CAAC,EAAE;AAAA,EACtF;AACA,QAAM,WAAW,KAAK;AACtB,QAAM,aAAa,KAAK;AACxB,QAAM,0BAA0B,KAAK;AACrC,MAAI,OAAO,aAAa,YAAY,OAAO,eAAe,UAAU;AAClE,UAAM,IAAI,MAAM,mEAAmE;AAAA,EACrF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,iBAAiB,OAAO,KAAK,qBAAqB,WAAW,KAAK,mBAAmB;AAAA,IACrF,yBACE,OAAO,4BAA4B,WAAW,0BAA0B;AAAA,IAC1E,UAAU,OAAO,KAAK,YAAY,CAAC,KAAK;AAAA,EAC1C;AACF;AASA,eAAe,gBAAgB,YAAyC;AACtE,QAAM,EAAE,QAAQ,KAAK,IAAI,MAAM,SAAS,oBAAoB;AAAA,IAC1D,WAAWA;AAAA,IACX,aAAa;AAAA,IACb,YAAY;AAAA,EACd,CAAC;AACD,MAAI,WAAW,OAAO,OAAO,KAAK,iBAAiB,UAAU;AAC3D,WAAO,EAAE,MAAM,WAAW,OAAO,uBAAuB,IAAI,EAAE;AAAA,EAChE;AACA,MAAI,UAAU,KAAK;AACjB,UAAM,IAAI,MAAM,oCAAoC,MAAM,MAAM,YAAY,IAAI,CAAC,EAAE;AAAA,EACrF;AACA,QAAM,YAAY,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAChE,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,aAAO,EAAE,MAAM,UAAU;AAAA,IAC3B,KAAK;AACH,aAAO,EAAE,MAAM,YAAY;AAAA,IAC7B,KAAK;AACH,aAAO,EAAE,MAAM,UAAU;AAAA,IAC3B,KAAK;AACH,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AACE,YAAM,IAAI,MAAM,8BAA8B,MAAM,MAAM,YAAY,IAAI,CAAC,EAAE;AAAA,EACjF;AACF;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,eAAW,SAAS,EAAE;AAAA,EACxB,CAAC;AACH;AAOA,eAAsB,UAAU,WAA2D;AACzF,QAAM,OAAO,MAAM,2BAA2B;AAE9C,YAAU;AAAA,IACR,SAAS,KAAK,mBAAmB,KAAK,uBAAuB,oBAAoB,KAAK,QAAQ;AAAA,EAChG;AACA,YAAU,UAAU,KAAK,2BAA2B,KAAK,eAAe;AACxE,YAAU,SAAS,gDAAgD;AAEnE,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,MAAI,WAAW,KAAK,IAAI,KAAK,UAAU,CAAC;AAExC,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,UAAM,MAAM,WAAW,GAAI;AAC3B,UAAM,SAAS,MAAM,gBAAgB,KAAK,UAAU;AACpD,QAAI,OAAO,SAAS,UAAW,QAAO,OAAO;AAC7C,QAAI,OAAO,SAAS,UAAU;AAC5B,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,QAAI,OAAO,SAAS,WAAW;AAC7B,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AACA,QAAI,OAAO,SAAS,aAAa;AAC/B,kBAAY;AAAA,IACd;AAAA,EAEF;AAEA,QAAM,IAAI,MAAM,+CAA+C;AACjE;AAGA,eAAsB,iBAAiB,cAAiD;AACtF,QAAM,EAAE,QAAQ,KAAK,IAAI,MAAM,SAAS,oBAAoB;AAAA,IAC1D,WAAWA;AAAA,IACX,YAAY;AAAA,IACZ,eAAe;AAAA,EACjB,CAAC;AACD,MAAI,WAAW,OAAO,OAAO,KAAK,iBAAiB,UAAU;AAC3D,WAAO,uBAAuB,MAAM,EAAE,sBAAsB,aAAa,CAAC;AAAA,EAC5E;AACA,QAAM,YAAY,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAGhE,QAAM,IAAI,MAAM,8BAA8B,MAAM,MAAM,aAAa,YAAY,IAAI,CAAC,EAAE;AAC5F;;;ACzUA,OAAOE,SAAQ;AACf,SAAS,cAAAC,mBAAkB;AAE3B,IAAM,mBAAmB;AACzB,IAAM,oBAAoB;AAC1B,IAAM,cAAc;AAWpB,eAAsB,aAAgB,UAAkB,IAAkC;AACxF,QAAM,WAAW,WAAW;AAC5B,QAAM,YAAY,QAAQ;AAC1B,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,UAAE;AACA,UAAM,YAAY,QAAQ;AAAA,EAC5B;AACF;AAEA,eAAe,YAAY,UAAiC;AAC1D,QAAM,YAAY,KAAK,IAAI;AAE3B,SAAO,MAAM;AACX,QAAI;AAEF,YAAM,OAAiB,EAAE,KAAK,QAAQ,KAAK,WAAW,KAAK,IAAI,EAAE;AACjE,YAAMD,IAAG,UAAU,UAAU,KAAK,UAAU,IAAI,GAAG,EAAE,MAAM,KAAK,CAAC;AACjE;AAAA,IACF,SAAS,KAAK;AACZ,UAAK,IAA8B,SAAS,SAAU,OAAM;AAG5D,UAAI;AACF,cAAM,UAAU,MAAMA,IAAG,SAAS,UAAU,OAAO;AACnD,cAAM,OAAO,KAAK,MAAM,OAAO;AAG/B,cAAM,iBAAiB,QAAQ,KAAK,GAAG;AACvC,cAAM,UAAU,KAAK,IAAI,IAAI,KAAK,YAAY;AAE9C,YAAI,CAAC,kBAAkB,SAAS;AAE9B,gBAAMA,IAAG,OAAO,QAAQ,EAAE,MAAM,MAAM;AAAA,UAAC,CAAC;AACxC;AAAA,QACF;AAAA,MACF,QAAQ;AAEN,cAAMA,IAAG,OAAO,QAAQ,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AACxC;AAAA,MACF;AAGA,UAAI,KAAK,IAAI,IAAI,YAAY,aAAa;AAExC,cAAMA,IAAG,OAAO,QAAQ,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AACxC;AAAA,MACF;AAEA,YAAMC,YAAW,iBAAiB;AAAA,IACpC;AAAA,EACF;AACF;AAEA,eAAe,YAAY,UAAiC;AAC1D,QAAMD,IAAG,OAAO,QAAQ,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AAC1C;AAEA,SAAS,QAAQ,KAAsB;AACrC,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,SAAS,KAAK;AAEZ,QAAK,IAA8B,SAAS,QAAS,QAAO;AAE5D,WAAO;AAAA,EACT;AACF;;;ARlEO,IAAM,qBAAqB;AAU3B,IAAM,qBAAqB;AASlC,IAAM,kBAAkB;AAGxB,IAAM,2BAA2B,oBAAI,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,cAAN,MAAkB;AAAA,EACf,OAAiB,CAAC;AAAA,EAClB;AAAA,EACA,SAAS;AAAA;AAAA,EAET,eAAe,oBAAI,IAAuC;AAAA,EAElE,YAAY,UAAmB;AAC7B,SAAK,WAAW,YAAY,YAAY,EAAE;AAAA,EAC5C;AAAA;AAAA,EAGA,IAAI,OAAe;AACjB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,gBAAmC;AACvC,UAAM,KAAK,aAAa;AACxB,WAAO,OAAO,KAAK,KAAK,IAAI;AAAA,EAC9B;AAAA;AAAA,EAGA,MAAM,eAAe,UAAoC;AACvD,UAAM,KAAK,aAAa;AACxB,WAAO,QAAQ,KAAK,KAAK,QAAQ,CAAC;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,eAAe,MAA6C;AAChE,UAAM,KAAK,aAAa;AACxB,WAAO,KAAK,KAAK,CAAC,QAAQ,QAAQ,KAAK,KAAK,GAAG,CAAC,CAAC;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBAAgB,UAAoC;AACxD,UAAM,KAAK,aAAa;AACxB,QAAI,aAAa,YAAY;AAC3B,aAAO,QAAQ,KAAK,KAAK,kBAAkB,KAAK,KAAK,KAAK,UAAU,CAAC;AAAA,IACvE;AACA,QAAI,aAAa,UAAU;AACzB,aAAO,QAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK,KAAK,kBAAkB,CAAC;AAAA,IACrE;AACA,WAAO,QAAQ,KAAK,KAAK,QAAQ,CAAC;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eAAe,UAAoC;AACvD,UAAM,KAAK,aAAa;AACxB,QAAI,aAAa,cAAc,KAAK,KAAK,kBAAkB,GAAG;AAC5D,aAAO;AAAA,IACT;AACA,WAAO,yBAAyB,IAAI,QAAQ;AAAA,EAC9C;AAAA,EAEA,MAAM,OAAsB;AAC1B,UAAM,aAAa,KAAK,UAAU,YAAY;AAC5C,UAAI;AACF,cAAM,UAAU,MAAME,IAAG,SAAS,KAAK,UAAU,OAAO;AACxD,aAAK,OAAO,KAAK,MAAM,OAAO;AAC9B,YAAI,QAAQ,QAAQ,2BAA2B,KAAK,QAAQ,IAAI;AAAA,UAC9D,WAAW,OAAO,KAAK,KAAK,IAAI,EAAE,KAAK,GAAG,KAAK;AAAA,QACjD,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,aAAK,OAAO,CAAC;AACb,cAAM,OAAQ,IAA8B;AAC5C,YAAI,SAAS,UAAU;AACrB,cAAI,QAAQ,QAAQ,yBAAyB,KAAK,QAAQ,cAAc;AAAA,QAC1E,OAAO;AACL;AAAA,YACE;AAAA,YACA;AAAA,YACA,6BAA6B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,YAC7E,EAAE,MAAM,KAAK,UAAU,MAAM,QAAQ,UAAU;AAAA,UACjD;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AACD,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAc,eAA8B;AAC1C,QAAI,CAAC,KAAK,OAAQ,OAAM,KAAK,KAAK;AAAA,EACpC;AAAA,EAEA,MAAM,eAAe,UAAyD;AAC5E,UAAM,KAAK,aAAa;AACxB,WAAO,KAAK,KAAK,QAAQ;AAAA,EAC3B;AAAA,EAEA,MAAM,eAAe,UAAkB,OAAwC;AAC7E,UAAM,KAAK,aAAa;AACxB,SAAK,KAAK,QAAQ,IAAI;AACtB,UAAM,KAAK,KAAK;AAAA,EAClB;AAAA,EAEA,MAAM,iBAAiB,UAAiC;AACtD,UAAM,KAAK,aAAa;AACxB,WAAO,KAAK,KAAK,QAAQ;AACzB,UAAM,KAAK,KAAK;AAAA,EAClB;AAAA,EAEA,MAAM,WAA0B;AAC9B,SAAK,OAAO,CAAC;AACb,UAAM,KAAK,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,mBACJ,UACA,MAC2B;AAC3B,UAAM,KAAK,aAAa;AAQxB,QAAI,MAAM,eAAe,EAAE,KAAK,YAAY,WAAW,KAAK,KAAK,YAAY,CAAC,MAAM,WAAW;AAC7F,iBAAW,OAAO,KAAK,aAAa;AAClC,cAAMC,SAAQ,KAAK,KAAK,GAAG;AAC3B,YAAIA,OAAO,QAAOA;AAAA,MACpB;AACA,YAAM,IAAI,iBAAiB,QAAQ;AAAA,IACrC;AAKA,QAAI,aAAa,cAAc,KAAK,KAAK,kBAAkB,GAAG;AAC5D,UAAI;AACF,eAAO,MAAM,KAAK,mBAAmB,oBAAoB,IAAI;AAAA,MAC/D,SAAS,KAAK;AAMZ,YAAI,eAAe,oBAAoB,KAAK,KAAK,UAAU,GAAG;AAC5D;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,UAEF;AACA,iBAAO,KAAK,KAAK,UAAU;AAAA,QAC7B;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,KAAK,QAAQ;AAChC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,iBAAiB,QAAQ;AAAA,IACrC;AAIA,QAAI,yBAAyB,IAAI,QAAQ,GAAG;AAC1C,aAAO;AAAA,IACT;AAGA,QAAI,CAAC,MAAM,gBAAgB,KAAK,IAAI,IAAI,MAAM,YAAY,iBAAiB;AACzE,aAAO;AAAA,IACT;AAGA,UAAM,WAAW,KAAK,aAAa,IAAI,QAAQ;AAC/C,QAAI,SAAU,QAAO;AAErB,UAAM,iBAAiB,aAAa,KAAK,UAAU,YAAY;AAE7D,UAAI;AACF,cAAM,UAAU,MAAMD,IAAG,SAAS,KAAK,UAAU,OAAO;AACxD,cAAM,YAAY,KAAK,MAAM,OAAO;AACpC,cAAM,aAAa,UAAU,QAAQ;AACrC,YACE,cACA,CAAC,MAAM,gBACP,KAAK,IAAI,IAAI,WAAW,YAAY,iBACpC;AAEA,eAAK,KAAK,QAAQ,IAAI;AACtB,iBAAO;AAAA,QACT;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,YAAM,YACJ,aAAa,cACT,wBACA,aAAa,WACX,qBACA,aAAa,qBACX,mBACA;AACV,UAAI;AACJ,UAAI;AACF,oBAAY,MAAM,UAAU,MAAM,YAAY;AAAA,MAChD,SAAS,KAAK;AAKZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAM,gBACJ,gBAAgB,KAAK,GAAG,KACxB,gDAAgD,KAAK,GAAG,KACxD,gBAAgB,KAAK,GAAG;AAC1B,YAAI,eAAe;AACjB,iBAAO,KAAK,KAAK,QAAQ;AACzB,gBAAM,gBAAgB,KAAK,UAAU,KAAK,UAAU,KAAK,MAAM,MAAM,CAAC,CAAC;AACvE,gBAAM,IAAI,iBAAiB,QAAQ;AAAA,QACrC;AACA,cAAM;AAAA,MACR;AACA,UAAI,CAAC,UAAU,aAAa,MAAM,WAAW;AAC3C,kBAAU,YAAY,MAAM;AAAA,MAC9B;AACA,UAAI,CAAC,UAAU,aAAa,MAAM,WAAW;AAC3C,kBAAU,YAAY,MAAM;AAAA,MAC9B;AACA,UAAI,CAAC,UAAU,WAAW,MAAM,SAAS;AACvC,kBAAU,UAAU,MAAM;AAAA,MAC5B;AACA,WAAK,KAAK,QAAQ,IAAI;AAEtB,YAAM,gBAAgB,KAAK,UAAU,KAAK,UAAU,KAAK,MAAM,MAAM,CAAC,CAAC;AACvE,aAAO;AAAA,IACT,CAAC;AAED,SAAK,aAAa,IAAI,UAAU,cAAc;AAC9C,QAAI;AACF,aAAO,MAAM;AAAA,IACf,UAAE;AACA,WAAK,aAAa,OAAO,QAAQ;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,UAAmC;AACpD,UAAM,QAAQ,MAAM,KAAK,mBAAmB,QAAQ;AACpD,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,MAAc,OAAsB;AAClC,UAAM,aAAa,KAAK,UAAU,YAAY;AAC5C,YAAM,gBAAgB,KAAK,UAAU,KAAK,UAAU,KAAK,MAAM,MAAM,CAAC,CAAC;AAAA,IACzE,CAAC;AAAA,EACH;AACF;AAMA,eAAe,gBAAgB,UAAkB,SAAgC;AAC/E,QAAM,UAAU,GAAG,QAAQ,IAAI,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,IAAIE,QAAO,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC;AAC3F,MAAI;AACF,UAAMF,IAAG,UAAU,SAAS,SAAS,EAAE,UAAU,SAAS,MAAM,IAAM,CAAC;AACvE,UAAMA,IAAG,OAAO,SAAS,QAAQ;AAAA,EACnC,SAAS,KAAK;AACZ,UAAMA,IAAG,OAAO,OAAO,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACvC,UAAM;AAAA,EACR;AACF;AAEO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1C;AAAA,EACA,YAAY,UAAkB;AAC5B,UAAM,oBAAoB,QAAQ,wCAAwC;AAC1E,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EAClB;AACF;;;AS9RO,IAAM,SAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiCjC;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe,KAAK,OAAO;AAAA,IAC3B,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe,KAAK,OAAO;AAAA,IAC3B,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe,MAAM,OAAO;AAAA,IAC5B,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe,KAAK,OAAO;AAAA,IAC3B,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,iBAAiB,CAAC,UAAU,kBAAkB;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,iBAAiB,CAAC,kBAAkB;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe,KAAK,OAAO;AAAA,IAC3B,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,iBAAiB,CAAC,UAAU,kBAAkB;AAAA,EAChD;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA;AAAA,IAEV,kBAAkB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB;AACF;AAEO,SAAS,SAAS,IAAmC;AAC1D,SAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACvC;AAEO,SAAS,qBAAqB,UAAiC;AACpE,SAAO,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,QAAQ;AACrD;AAUO,SAAS,mBAAmB,UAAoB,SAA2B;AAChF,QAAM,QAAQ,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,WAAW,EAAE,aAAa,QAAQ;AAC5E,SAAO,OAAO,mBAAmB,CAAC,QAAQ;AAC5C;AAGO,SAAS,kBAAkB,UAAoB,SAAyB;AAC7E,SAAO,mBAAmB,UAAU,OAAO,EAAE,CAAC;AAChD;AAGO,IAAM,0BAA0B,KAAK,OAAO;AAO5C,SAAS,kBAAkB,SAAqC;AACrE,QAAM,QAAQ,SAAS,OAAO;AAC9B,MAAI,CAAC,OAAO,cAAe,QAAO;AAClC,SAAO,MAAM,iBAAiB;AAChC;AAEO,SAAS,gBAAgB,UAA+B;AAC7D,MAAI,aAAa,SAAU,QAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,eAAe;AAC7E,MAAI,aAAa,SAAU,QAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS;AACvE,MAAI,aAAa,SAAU,QAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,+BAA+B;AAC7F,MAAI,aAAa,MAAO,QAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS;AACpE,MAAI,aAAa,WAAY,QAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,gBAAgB;AAChF,MAAI,aAAa,UAAW,QAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,YAAY;AAC3E,MAAI,aAAa,WAAY,QAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,iBAAiB;AACjF,MAAI,aAAa,aAAc,QAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,mBAAmB;AACrF,MAAI,aAAa,SAAU,QAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM;AACpE,SAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,iBAAiB;AACtD;AAOO,SAAS,yBAAyB,SAAyC;AAChF,SAAO,SAAS,aAAa,YAAY,QAAQ,QAAQ,SAAS;AACpE;AAEO,SAAS,iBAAiB,SAAiB,SAAwC;AACxF,QAAM,QAAQ,SAAS,OAAO;AAC9B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,yBAAyB,OAAO,KAAK,MAAM,oBAAoB;AACjE,WAAO,MAAM;AAAA,EACf;AACA,SAAO,MAAM;AACf;AAMO,SAAS,oBAAoB,SAAgC;AAClE,SAAO,SAAS,OAAO,GAAG,oBAAoB;AAChD;AAUO,SAAS,gBAAgB,UAAoB,gBAAmC;AACrF,MAAI,aAAa,aAAa;AAC5B,WAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,iBAAiB;AAAA,EACtD;AACA,MAAI,aAAa,YAAY,aAAa,SAAS,aAAa,YAAY;AAC1E,UAAM,MAAM,qBAAqB,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,KAAK;AAC3E,QAAI,IAAK,QAAO;AAAA,EAClB;AAEA,SAAO,SAAS,cAAc,KAAK,gBAAgB,QAAQ;AAC7D;","names":["fs","crypto","crypto","fs","path","path","fs","crypto","crypto","CLIENT_ID","AUTHORIZE_URL","REDIRECT_URI","crypto","http","crypto","AUTHORIZE_URL","TOKEN_URL","SCOPE","crypto","loginWithServer","parseAuthorizationInput","postTokenRequest","http","project","path","CLIENT_ID","path","fs","setTimeout","fs","creds","crypto"]}
1
+ {"version":3,"sources":["../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/oauth/kimi.ts","../src/file-lock.ts","../src/model-registry.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\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 * Refresh refreshable OAuth tokens this long BEFORE their hard expiry. Renewing\n * proactively keeps the credential (and its refresh token) alive across\n * sessions instead of waiting until a request fails with 401 — which, for\n * providers like Kimi, is otherwise misread as a dead credential and triggers a\n * silent fall back to a static API key.\n */\nconst REFRESH_SKEW_MS = 60_000;\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]);\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 return false;\n }\n return STATIC_API_KEY_PROVIDERS.has(provider);\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 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.ensureLoaded();\n this.data[provider] = creds;\n await this.save();\n }\n\n async clearCredentials(provider: string): Promise<void> {\n await this.ensureLoaded();\n delete this.data[provider];\n await this.save();\n }\n\n async clearAll(): Promise<void> {\n this.data = {};\n await this.save();\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 // 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 try {\n return await this.resolveCredentials(MOONSHOT_OAUTH_KEY, opts);\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 - REFRESH_SKEW_MS) {\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 // Re-read from disk in case another process refreshed while we waited for the lock\n try {\n const content = await fs.readFile(this.filePath, \"utf-8\");\n const freshData = JSON.parse(content) as AuthData;\n const freshCreds = freshData[provider];\n if (\n freshCreds &&\n !opts?.forceRefresh &&\n Date.now() < freshCreds.expiresAt - REFRESH_SKEW_MS\n ) {\n // Another process already refreshed — use their token\n this.data[provider] = freshCreds;\n return freshCreds;\n }\n } catch {\n // Fall through to refresh\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(creds.refreshToken);\n } catch (err) {\n // Refresh token revoked / expired / invalid → the stored creds are\n // unusable. Wipe them so the next launch surfaces a clean\n // NotLoggedInError instead of hitting the same dead refresh path\n // every time. The user must re-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 this.data[provider];\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n throw new NotLoggedInError(provider);\n }\n throw err;\n }\n if (!refreshed.accountId && creds.accountId) {\n refreshed.accountId = creds.accountId;\n }\n if (!refreshed.projectId && creds.projectId) {\n refreshed.projectId = creds.projectId;\n }\n if (!refreshed.baseUrl && creds.baseUrl) {\n refreshed.baseUrl = creds.baseUrl;\n }\n this.data[provider] = refreshed;\n // Write atomically (we already hold the file lock)\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, 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 private async save(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n });\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\";\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 sessionId = \"\";\nlet appName = \"app\";\nlet cleanups: (() => void)[] = [];\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) return false;\n appName = name;\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 return false;\n }\n sessionId = randomBytes(4).toString(\"hex\");\n // Visible separator between sessions when back-reading the log.\n try {\n fs.writeSync(fd, \"\\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 let line = `[${ts}] [sid=${sessionId}] [${level}] [${category}] ${message}`;\n if (data) {\n const pairs = Object.entries(data)\n .map(([k, v]) => `${k}=${typeof v === \"string\" ? v : JSON.stringify(v)}`)\n .join(\" \");\n if (pairs) line += ` ${pairs}`;\n }\n line += \"\\n\";\n try {\n 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) return;\n if (opts?.shutdownLine !== false) log(\"INFO\", \"shutdown\", `${appName} shutting down`);\n try {\n fs.closeSync(fd);\n } catch {\n // Ignore close errors\n }\n fd = null;\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","/**\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 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 { 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 { 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.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 * - GLM / Moonshot / 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 {\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 {\n id: \"gpt-5.4\",\n name: \"GPT-5.4\",\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 {\n id: \"gpt-5.4-mini\",\n name: \"GPT-5.4 Mini\",\n provider: \"openai\",\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"xhigh\",\n },\n {\n id: \"gpt-5.3-codex\",\n name: \"GPT-5.3 Codex\",\n provider: \"openai\",\n contextWindow: 400_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 // ── Gemini ─────────────────────────────────────────────\n {\n id: \"gemini-3.1-flash-lite-preview\",\n name: \"Gemini 3.1 Flash Lite 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: \"low\",\n maxThinkingLevel: \"high\",\n },\n {\n id: \"gemini-3.5-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 // ── Moonshot (Kimi) ────────────────────────────────────\n {\n id: \"kimi-k2.7-code\",\n name: \"Kimi K2.7\",\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.5\")!;\n if (provider === \"gemini\") return MODELS.find((m) => m.id === \"gemini-3.1-flash-lite-preview\")!;\n if (provider === \"glm\") return MODELS.find((m) => m.id === \"glm-5.2\")!;\n if (provider === \"moonshot\") return MODELS.find((m) => m.id === \"kimi-k2.7-code\")!;\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 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\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 * 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"],"mappings":"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","names":["fs","crypto","crypto","fs","path","path","fs","crypto","crypto","CLIENT_ID","AUTHORIZE_URL","REDIRECT_URI","crypto","http","crypto","AUTHORIZE_URL","TOKEN_URL","SCOPE","crypto","loginWithServer","parseAuthorizationInput","postTokenRequest","http","project","path","CLIENT_ID","path","fs","setTimeout","fs","creds","crypto"]}