@expiren/opencode-antigravity-auth 1.6.1 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1,7 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/plugin.ts", "../node_modules/@opencode-ai/plugin/dist/tool.js", "../src/constants.ts", "../src/antigravity/oauth.ts", "../src/plugin/debug.ts", "../src/plugin/logging-utils.ts", "../src/plugin/storage.ts", "../src/plugin/logger.ts", "../src/plugin/auth.ts", "../src/plugin/cli.ts", "../src/plugin/ui/ansi.ts", "../src/plugin/ui/select.ts", "../src/plugin/ui/confirm.ts", "../src/plugin/ui/auth-menu.ts", "../src/plugin/config/updater.ts", "../src/plugin/config/models.ts", "../src/plugin/project.ts", "../src/plugin/request.ts", "../src/plugin/cache.ts", "../src/plugin/cache/signature-cache.ts", "../src/plugin/config/schema.ts", "../src/plugin/config/loader.ts", "../src/plugin/image-saver.ts", "../src/plugin/core/streaming/transformer.ts", "../src/plugin/stores/signature-store.ts", "../src/plugin/request-helpers.ts", "../src/plugin/thinking-recovery.ts", "../src/plugin/transform/claude.ts", "../src/plugin/transform/gemini.ts", "../src/plugin/transform/cross-model-sanitizer.ts", "../src/plugin/transform/model-resolver.ts", "../src/plugin/recovery/storage.ts", "../src/plugin/recovery/constants.ts", "../src/plugin/recovery.ts", "../src/plugin/fingerprint.ts", "../src/plugin/errors.ts", "../src/plugin/token.ts", "../src/plugin/server.ts", "../src/plugin/rotation.ts", "../src/plugin/accounts.ts", "../src/hooks/auto-update-checker/checker.ts", "../src/hooks/auto-update-checker/constants.ts", "../src/hooks/auto-update-checker/logging.ts", "../src/hooks/auto-update-checker/cache.ts", "../src/hooks/auto-update-checker/index.ts", "../src/plugin/quota.ts", "../src/plugin/refresh-queue.ts", "../src/plugin/version.ts", "../src/plugin/search.ts"],
4
+ "sourcesContent": ["import { exec } from \"node:child_process\";\r\nimport { tool } from \"@opencode-ai/plugin\";\r\nimport {\r\n ANTIGRAVITY_DEFAULT_PROJECT_ID,\r\n ANTIGRAVITY_ENDPOINT_FALLBACKS,\r\n ANTIGRAVITY_ENDPOINT_PROD,\r\n ANTIGRAVITY_PROVIDER_ID,\r\n getAntigravityHeaders,\r\n type HeaderStyle,\r\n} from \"./constants\";\r\nimport { authorizeAntigravity, exchangeAntigravity } from \"./antigravity/oauth\";\r\nimport type { AntigravityTokenExchangeResult } from \"./antigravity/oauth\";\r\nimport { accessTokenExpired, isOAuthAuth, parseRefreshParts, formatRefreshParts } from \"./plugin/auth\";\r\nimport { promptAddAnotherAccount, promptLoginMode, promptProjectId } from \"./plugin/cli\";\r\nimport { ensureProjectContext } from \"./plugin/project\";\r\nimport {\r\n startAntigravityDebugRequest, \r\n logAntigravityDebugResponse,\r\n logAccountContext,\r\n logRateLimitEvent,\r\n logRateLimitSnapshot,\r\n logResponseBody,\r\n logModelFamily,\r\n isDebugEnabled,\r\n getLogFilePath,\r\n initializeDebug,\r\n} from \"./plugin/debug\";\r\nimport {\r\n buildThinkingWarmupBody,\r\n isGenerativeLanguageRequest,\r\n prepareAntigravityRequest,\r\n transformAntigravityResponse,\r\n} from \"./plugin/request\";\r\nimport { resolveModelWithTier } from \"./plugin/transform/model-resolver\";\r\nimport {\r\n isEmptyResponseBody,\r\n createSyntheticErrorResponse,\r\n} from \"./plugin/request-helpers\";\r\nimport { EmptyResponseError } from \"./plugin/errors\";\r\nimport { AntigravityTokenRefreshError, refreshAccessToken } from \"./plugin/token\";\r\nimport { startOAuthListener, type OAuthListener } from \"./plugin/server\";\r\nimport { clearAccounts, loadAccounts, saveAccounts, saveAccountsReplace } from \"./plugin/storage\";\r\nimport { AccountManager, type ModelFamily, parseRateLimitReason, calculateBackoffMs, computeSoftQuotaCacheTtlMs } from \"./plugin/accounts\";\r\nimport { createAutoUpdateCheckerHook } from \"./hooks/auto-update-checker\";\r\nimport { loadConfig, initRuntimeConfig, type AntigravityConfig } from \"./plugin/config\";\r\nimport { createSessionRecoveryHook, getRecoverySuccessToast } from \"./plugin/recovery\";\r\nimport { checkAccountsQuota } from \"./plugin/quota\";\r\nimport { initDiskSignatureCache } from \"./plugin/cache\";\r\nimport { createProactiveRefreshQueue, type ProactiveRefreshQueue } from \"./plugin/refresh-queue\";\r\nimport { initLogger, createLogger } from \"./plugin/logger\";\r\nimport { initHealthTracker, getHealthTracker, initTokenTracker, getTokenTracker } from \"./plugin/rotation\";\r\nimport { initAntigravityVersion } from \"./plugin/version\";\r\nimport { executeSearch } from \"./plugin/search\";\r\nimport type {\r\n GetAuth,\r\n LoaderResult,\r\n PluginClient,\r\n PluginContext,\r\n PluginResult,\r\n ProjectContextResult,\r\n Provider,\r\n} from \"./plugin/types\";\r\n\r\nconst MAX_OAUTH_ACCOUNTS = 10;\r\nconst MAX_WARMUP_SESSIONS = 1000;\r\nconst MAX_WARMUP_RETRIES = 2;\r\nconst CAPACITY_BACKOFF_TIERS_MS = [5000, 10000, 20000, 30000, 60000];\r\n\r\nfunction getCapacityBackoffDelay(consecutiveFailures: number): number {\r\n const index = Math.min(consecutiveFailures, CAPACITY_BACKOFF_TIERS_MS.length - 1);\r\n return CAPACITY_BACKOFF_TIERS_MS[Math.max(0, index)] ?? 5000;\r\n}\r\nconst warmupAttemptedSessionIds = new Set<string>();\r\nconst warmupSucceededSessionIds = new Set<string>();\r\n\r\n// Track if this plugin instance is running in a child session (subagent, background task)\r\n// Used to filter toasts based on toast_scope config\r\nlet isChildSession = false;\r\nlet childSessionParentID: string | undefined = undefined;\r\n\r\nconst log = createLogger(\"plugin\");\r\n\r\n// Module-level toast debounce to persist across requests (fixes toast spam)\r\nconst rateLimitToastCooldowns = new Map<string, number>();\r\nconst RATE_LIMIT_TOAST_COOLDOWN_MS = 5000;\r\nconst MAX_TOAST_COOLDOWN_ENTRIES = 100;\r\n\r\n// Track if \"all accounts blocked\" toasts were shown to prevent spam in while loop\r\nlet softQuotaToastShown = false;\r\nlet rateLimitToastShown = false;\r\n\r\n// Module-level reference to AccountManager for access from auth.login\r\nlet activeAccountManager: import(\"./plugin/accounts\").AccountManager | null = null;\r\n\r\nfunction cleanupToastCooldowns(): void {\r\n if (rateLimitToastCooldowns.size > MAX_TOAST_COOLDOWN_ENTRIES) {\r\n const now = Date.now();\r\n for (const [key, time] of rateLimitToastCooldowns) {\r\n if (now - time > RATE_LIMIT_TOAST_COOLDOWN_MS * 2) {\r\n rateLimitToastCooldowns.delete(key);\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction shouldShowRateLimitToast(message: string): boolean {\r\n cleanupToastCooldowns();\r\n const toastKey = message.replace(/\\d+/g, \"X\");\r\n const lastShown = rateLimitToastCooldowns.get(toastKey) ?? 0;\r\n const now = Date.now();\r\n if (now - lastShown < RATE_LIMIT_TOAST_COOLDOWN_MS) {\r\n return false;\r\n }\r\n rateLimitToastCooldowns.set(toastKey, now);\r\n return true;\r\n}\r\n\r\nfunction resetAllAccountsBlockedToasts(): void {\r\n softQuotaToastShown = false;\r\n rateLimitToastShown = false;\r\n}\r\n\r\nconst quotaRefreshInProgressByEmail = new Set<string>();\r\n\r\nasync function triggerAsyncQuotaRefreshForAccount(\r\n accountManager: AccountManager,\r\n accountIndex: number,\r\n client: PluginClient,\r\n providerId: string,\r\n intervalMinutes: number,\r\n): Promise<void> {\r\n if (intervalMinutes <= 0) return;\r\n \r\n const accounts = accountManager.getAccounts();\r\n const account = accounts[accountIndex];\r\n if (!account || account.enabled === false) return;\r\n \r\n const accountKey = account.email ?? `idx-${accountIndex}`;\r\n if (quotaRefreshInProgressByEmail.has(accountKey)) return;\r\n \r\n const intervalMs = intervalMinutes * 60 * 1000;\r\n const age = account.cachedQuotaUpdatedAt != null \r\n ? Date.now() - account.cachedQuotaUpdatedAt \r\n : Infinity;\r\n \r\n if (age < intervalMs) return;\r\n \r\n quotaRefreshInProgressByEmail.add(accountKey);\r\n \r\n try {\r\n const accountsForCheck = accountManager.getAccountsForQuotaCheck();\r\n const singleAccount = accountsForCheck[accountIndex];\r\n if (!singleAccount) {\r\n quotaRefreshInProgressByEmail.delete(accountKey);\r\n return;\r\n }\r\n \r\n const results = await checkAccountsQuota([singleAccount], client, providerId);\r\n \r\n if (results[0]?.status === \"ok\" && results[0]?.quota?.groups) {\r\n accountManager.updateQuotaCache(accountIndex, results[0].quota.groups);\r\n accountManager.requestSaveToDisk();\r\n }\r\n } catch (err) {\r\n log.debug(`quota-refresh-failed email=${accountKey}`, { error: String(err) });\r\n } finally {\r\n quotaRefreshInProgressByEmail.delete(accountKey);\r\n }\r\n}\r\n\r\nfunction trackWarmupAttempt(sessionId: string): boolean {\r\n if (warmupSucceededSessionIds.has(sessionId)) {\r\n return false;\r\n }\r\n if (warmupAttemptedSessionIds.size >= MAX_WARMUP_SESSIONS) {\r\n const first = warmupAttemptedSessionIds.values().next().value;\r\n if (first) {\r\n warmupAttemptedSessionIds.delete(first);\r\n warmupSucceededSessionIds.delete(first);\r\n }\r\n }\r\n const attempts = getWarmupAttemptCount(sessionId);\r\n if (attempts >= MAX_WARMUP_RETRIES) {\r\n return false;\r\n }\r\n warmupAttemptedSessionIds.add(sessionId);\r\n return true;\r\n}\r\n\r\nfunction getWarmupAttemptCount(sessionId: string): number {\r\n return warmupAttemptedSessionIds.has(sessionId) ? 1 : 0;\r\n}\r\n\r\nfunction markWarmupSuccess(sessionId: string): void {\r\n warmupSucceededSessionIds.add(sessionId);\r\n if (warmupSucceededSessionIds.size >= MAX_WARMUP_SESSIONS) {\r\n const first = warmupSucceededSessionIds.values().next().value;\r\n if (first) warmupSucceededSessionIds.delete(first);\r\n }\r\n}\r\n\r\nfunction clearWarmupAttempt(sessionId: string): void {\r\n warmupAttemptedSessionIds.delete(sessionId);\r\n}\r\n\r\nfunction isWSL(): boolean {\r\n if (process.platform !== \"linux\") return false;\r\n try {\r\n const { readFileSync } = require(\"node:fs\");\r\n const release = readFileSync(\"/proc/version\", \"utf8\").toLowerCase();\r\n return release.includes(\"microsoft\") || release.includes(\"wsl\");\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nfunction isWSL2(): boolean {\r\n if (!isWSL()) return false;\r\n try {\r\n const { readFileSync } = require(\"node:fs\");\r\n const version = readFileSync(\"/proc/version\", \"utf8\").toLowerCase();\r\n return version.includes(\"wsl2\") || version.includes(\"microsoft-standard\");\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nfunction isRemoteEnvironment(): boolean {\r\n if (process.env.SSH_CLIENT || process.env.SSH_TTY || process.env.SSH_CONNECTION) {\r\n return true;\r\n }\r\n if (process.env.REMOTE_CONTAINERS || process.env.CODESPACES) {\r\n return true;\r\n }\r\n if (process.platform === \"linux\" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY && !isWSL()) {\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\nfunction shouldSkipLocalServer(): boolean {\r\n return isWSL2() || isRemoteEnvironment();\r\n}\r\n\r\nasync function openBrowser(url: string): Promise<boolean> {\r\n try {\r\n if (process.platform === \"darwin\") {\r\n exec(`open \"${url}\"`);\r\n return true;\r\n }\r\n if (process.platform === \"win32\") {\r\n exec(`start \"\" \"${url}\"`);\r\n return true;\r\n }\r\n if (isWSL()) {\r\n try {\r\n exec(`wslview \"${url}\"`);\r\n return true;\r\n } catch {}\r\n }\r\n if (!process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {\r\n return false;\r\n }\r\n exec(`xdg-open \"${url}\"`);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\ntype VerificationProbeResult = {\r\n status: \"ok\" | \"blocked\" | \"error\";\r\n message: string;\r\n verifyUrl?: string;\r\n};\r\n\r\nfunction decodeEscapedText(input: string): string {\r\n return input\r\n .replace(/&amp;/g, \"&\")\r\n .replace(/\\\\u([0-9a-fA-F]{4})/g, (_, hex: string) => String.fromCharCode(Number.parseInt(hex, 16)));\r\n}\r\n\r\nfunction normalizeGoogleVerificationUrl(rawUrl: string): string | undefined {\r\n const normalized = decodeEscapedText(rawUrl).trim();\r\n if (!normalized) {\r\n return undefined;\r\n }\r\n try {\r\n const parsed = new URL(normalized);\r\n if (parsed.hostname !== \"accounts.google.com\") {\r\n return undefined;\r\n }\r\n return parsed.toString();\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\nfunction selectBestVerificationUrl(urls: string[]): string | undefined {\r\n const unique = Array.from(new Set(urls.map((url) => normalizeGoogleVerificationUrl(url)).filter(Boolean) as string[]));\r\n if (unique.length === 0) {\r\n return undefined;\r\n }\r\n unique.sort((a, b) => {\r\n const score = (value: string): number => {\r\n let total = 0;\r\n if (value.includes(\"plt=\")) total += 4;\r\n if (value.includes(\"/signin/continue\")) total += 3;\r\n if (value.includes(\"continue=\")) total += 2;\r\n if (value.includes(\"service=cloudcode\")) total += 1;\r\n return total;\r\n };\r\n return score(b) - score(a);\r\n });\r\n return unique[0];\r\n}\r\n\r\nfunction extractVerificationErrorDetails(bodyText: string): {\r\n validationRequired: boolean;\r\n message?: string;\r\n verifyUrl?: string;\r\n} {\r\n const decodedBody = decodeEscapedText(bodyText);\r\n const lowerBody = decodedBody.toLowerCase();\r\n let validationRequired = lowerBody.includes(\"validation_required\");\r\n let message: string | undefined;\r\n const verificationUrls = new Set<string>();\r\n\r\n const collectUrlsFromText = (text: string): void => {\r\n for (const match of text.matchAll(/https:\\/\\/accounts\\.google\\.com\\/[^\\s\"'<>]+/gi)) {\r\n if (match[0]) {\r\n verificationUrls.add(match[0]);\r\n }\r\n }\r\n };\r\n\r\n collectUrlsFromText(decodedBody);\r\n\r\n const payloads: unknown[] = [];\r\n const trimmed = decodedBody.trim();\r\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\r\n try {\r\n payloads.push(JSON.parse(trimmed));\r\n } catch {\r\n }\r\n }\r\n\r\n for (const rawLine of decodedBody.split(\"\\n\")) {\r\n const line = rawLine.trim();\r\n if (!line.startsWith(\"data:\")) {\r\n continue;\r\n }\r\n const payloadText = line.slice(5).trim();\r\n if (!payloadText || payloadText === \"[DONE]\") {\r\n continue;\r\n }\r\n try {\r\n payloads.push(JSON.parse(payloadText));\r\n } catch {\r\n collectUrlsFromText(payloadText);\r\n }\r\n }\r\n\r\n const visited = new Set<unknown>();\r\n const walk = (value: unknown, key?: string): void => {\r\n if (typeof value === \"string\") {\r\n const normalizedValue = decodeEscapedText(value);\r\n const lowerValue = normalizedValue.toLowerCase();\r\n const lowerKey = key?.toLowerCase() ?? \"\";\r\n\r\n if (lowerValue.includes(\"validation_required\")) {\r\n validationRequired = true;\r\n }\r\n if (\r\n !message &&\r\n (lowerKey.includes(\"message\") || lowerKey.includes(\"detail\") || lowerKey.includes(\"description\"))\r\n ) {\r\n message = normalizedValue;\r\n }\r\n if (\r\n lowerKey.includes(\"validation_url\") ||\r\n lowerKey.includes(\"verify_url\") ||\r\n lowerKey.includes(\"verification_url\") ||\r\n lowerKey === \"url\"\r\n ) {\r\n verificationUrls.add(normalizedValue);\r\n }\r\n collectUrlsFromText(normalizedValue);\r\n return;\r\n }\r\n\r\n if (!value || typeof value !== \"object\" || visited.has(value)) {\r\n return;\r\n }\r\n\r\n visited.add(value);\r\n\r\n if (Array.isArray(value)) {\r\n for (const item of value) {\r\n walk(item);\r\n }\r\n return;\r\n }\r\n\r\n for (const [childKey, childValue] of Object.entries(value as Record<string, unknown>)) {\r\n walk(childValue, childKey);\r\n }\r\n };\r\n\r\n for (const payload of payloads) {\r\n walk(payload);\r\n }\r\n\r\n if (!validationRequired) {\r\n validationRequired =\r\n lowerBody.includes(\"verification required\") ||\r\n lowerBody.includes(\"verify your account\") ||\r\n lowerBody.includes(\"account verification\");\r\n }\r\n\r\n if (!message) {\r\n const fallback = decodedBody\r\n .split(\"\\n\")\r\n .map((line) => line.trim())\r\n .find((line) => line && !line.startsWith(\"data:\") && /(verify|validation|required)/i.test(line));\r\n if (fallback) {\r\n message = fallback;\r\n }\r\n }\r\n\r\n return {\r\n validationRequired,\r\n message,\r\n verifyUrl: selectBestVerificationUrl([...verificationUrls]),\r\n };\r\n}\r\n\r\nasync function verifyAccountAccess(\r\n account: {\r\n refreshToken: string;\r\n email?: string;\r\n projectId?: string;\r\n managedProjectId?: string;\r\n },\r\n client: PluginClient,\r\n providerId: string,\r\n): Promise<VerificationProbeResult> {\r\n const parsed = parseRefreshParts(account.refreshToken);\r\n if (!parsed.refreshToken) {\r\n return { status: \"error\", message: \"Missing refresh token for selected account.\" };\r\n }\r\n\r\n const auth = {\r\n type: \"oauth\" as const,\r\n refresh: formatRefreshParts({\r\n refreshToken: parsed.refreshToken,\r\n projectId: parsed.projectId ?? account.projectId,\r\n managedProjectId: parsed.managedProjectId ?? account.managedProjectId,\r\n }),\r\n access: \"\",\r\n expires: 0,\r\n };\r\n\r\n let refreshedAuth: Awaited<ReturnType<typeof refreshAccessToken>>;\r\n try {\r\n refreshedAuth = await refreshAccessToken(auth, client, providerId);\r\n } catch (error) {\r\n if (error instanceof AntigravityTokenRefreshError) {\r\n return { status: \"error\", message: error.message };\r\n }\r\n return { status: \"error\", message: `Token refresh failed: ${String(error)}` };\r\n }\r\n\r\n if (!refreshedAuth?.access) {\r\n return { status: \"error\", message: \"Could not refresh access token for this account.\" };\r\n }\r\n\r\n const projectId =\r\n parsed.managedProjectId ??\r\n parsed.projectId ??\r\n account.managedProjectId ??\r\n account.projectId ??\r\n ANTIGRAVITY_DEFAULT_PROJECT_ID;\r\n\r\n const headers: Record<string, string> = {\r\n ...getAntigravityHeaders(),\r\n Authorization: `Bearer ${refreshedAuth.access}`,\r\n \"Content-Type\": \"application/json\",\r\n };\r\n if (projectId) {\r\n headers[\"x-goog-user-project\"] = projectId;\r\n }\r\n\r\n const requestBody = {\r\n model: \"gemini-3-flash\",\r\n request: {\r\n model: \"gemini-3-flash\",\r\n contents: [{ role: \"user\", parts: [{ text: \"ping\" }] }],\r\n generationConfig: { maxOutputTokens: 1, temperature: 0 },\r\n },\r\n };\r\n\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), 20000);\r\n\r\n let response: Response;\r\n try {\r\n response = await fetch(`${ANTIGRAVITY_ENDPOINT_PROD}/v1internal:streamGenerateContent?alt=sse`, {\r\n method: \"POST\",\r\n headers,\r\n body: JSON.stringify(requestBody),\r\n signal: controller.signal,\r\n });\r\n } catch (error) {\r\n if (error instanceof Error && error.name === \"AbortError\") {\r\n return { status: \"error\", message: \"Verification check timed out.\" };\r\n }\r\n return { status: \"error\", message: `Verification check failed: ${String(error)}` };\r\n } finally {\r\n clearTimeout(timeoutId);\r\n }\r\n\r\n let responseBody = \"\";\r\n try {\r\n responseBody = await response.text();\r\n } catch {\r\n responseBody = \"\";\r\n }\r\n\r\n if (response.ok) {\r\n return { status: \"ok\", message: \"Account verification check passed.\" };\r\n }\r\n\r\n const extracted = extractVerificationErrorDetails(responseBody);\r\n if (response.status === 403 && extracted.validationRequired) {\r\n return {\r\n status: \"blocked\",\r\n message: extracted.message ?? \"Google requires additional account verification.\",\r\n verifyUrl: extracted.verifyUrl,\r\n };\r\n }\r\n\r\n const fallbackMessage = extracted.message ?? `Request failed (${response.status} ${response.statusText}).`;\r\n return {\r\n status: \"error\",\r\n message: fallbackMessage,\r\n };\r\n}\r\n\r\nasync function promptAccountIndexForVerification(\r\n accounts: Array<{ email?: string; index: number }>,\r\n): Promise<number | undefined> {\r\n const { createInterface } = await import(\"node:readline/promises\");\r\n const { stdin, stdout } = await import(\"node:process\");\r\n const rl = createInterface({ input: stdin, output: stdout });\r\n try {\r\n console.log(\"\\nSelect an account to verify:\");\r\n for (const account of accounts) {\r\n const label = account.email || `Account ${account.index + 1}`;\r\n console.log(` ${account.index + 1}. ${label}`);\r\n }\r\n console.log(\"\");\r\n\r\n while (true) {\r\n const answer = (await rl.question(\"Account number (leave blank to cancel): \")).trim();\r\n if (!answer) {\r\n return undefined;\r\n }\r\n const parsedIndex = Number(answer);\r\n if (!Number.isInteger(parsedIndex)) {\r\n console.log(\"Please enter a valid account number.\");\r\n continue;\r\n }\r\n const normalizedIndex = parsedIndex - 1;\r\n const selected = accounts.find((account) => account.index === normalizedIndex);\r\n if (!selected) {\r\n console.log(\"Please enter a number from the list above.\");\r\n continue;\r\n }\r\n return selected.index;\r\n }\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\nasync function promptOpenVerificationUrl(): Promise<boolean> {\r\n const answer = (await promptOAuthCallbackValue(\"Open verification URL in your browser now? [Y/n]: \")).trim().toLowerCase();\r\n return answer === \"\" || answer === \"y\" || answer === \"yes\";\r\n}\r\n\r\ntype VerificationStoredAccount = {\r\n enabled?: boolean;\r\n verificationRequired?: boolean;\r\n verificationRequiredAt?: number;\r\n verificationRequiredReason?: string;\r\n verificationUrl?: string;\r\n};\r\n\r\nfunction markStoredAccountVerificationRequired(\r\n account: VerificationStoredAccount,\r\n reason: string,\r\n verifyUrl?: string,\r\n): boolean {\r\n let changed = false;\r\n const wasVerificationRequired = account.verificationRequired === true;\r\n\r\n if (!wasVerificationRequired) {\r\n account.verificationRequired = true;\r\n changed = true;\r\n }\r\n\r\n if (!wasVerificationRequired || account.verificationRequiredAt === undefined) {\r\n account.verificationRequiredAt = Date.now();\r\n changed = true;\r\n }\r\n\r\n const normalizedReason = reason.trim();\r\n if (account.verificationRequiredReason !== normalizedReason) {\r\n account.verificationRequiredReason = normalizedReason;\r\n changed = true;\r\n }\r\n\r\n const normalizedUrl = verifyUrl?.trim();\r\n if (normalizedUrl && account.verificationUrl !== normalizedUrl) {\r\n account.verificationUrl = normalizedUrl;\r\n changed = true;\r\n }\r\n\r\n if (account.enabled !== false) {\r\n account.enabled = false;\r\n changed = true;\r\n }\r\n\r\n return changed;\r\n}\r\n\r\nfunction clearStoredAccountVerificationRequired(\r\n account: VerificationStoredAccount,\r\n enableIfRequired = false,\r\n): { changed: boolean; wasVerificationRequired: boolean } {\r\n const wasVerificationRequired = account.verificationRequired === true;\r\n let changed = false;\r\n\r\n if (account.verificationRequired !== false) {\r\n account.verificationRequired = false;\r\n changed = true;\r\n }\r\n if (account.verificationRequiredAt !== undefined) {\r\n account.verificationRequiredAt = undefined;\r\n changed = true;\r\n }\r\n if (account.verificationRequiredReason !== undefined) {\r\n account.verificationRequiredReason = undefined;\r\n changed = true;\r\n }\r\n if (account.verificationUrl !== undefined) {\r\n account.verificationUrl = undefined;\r\n changed = true;\r\n }\r\n\r\n if (enableIfRequired && wasVerificationRequired && account.enabled === false) {\r\n account.enabled = true;\r\n changed = true;\r\n }\r\n\r\n return { changed, wasVerificationRequired };\r\n}\r\n\r\nasync function promptOAuthCallbackValue(message: string): Promise<string> {\r\n const { createInterface } = await import(\"node:readline/promises\");\r\n const { stdin, stdout } = await import(\"node:process\");\r\n const rl = createInterface({ input: stdin, output: stdout });\r\n try {\r\n return (await rl.question(message)).trim();\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\ntype OAuthCallbackParams = { code: string; state: string };\r\n\r\nfunction getStateFromAuthorizationUrl(authorizationUrl: string): string {\r\n try {\r\n return new URL(authorizationUrl).searchParams.get(\"state\") ?? \"\";\r\n } catch {\r\n return \"\";\r\n }\r\n}\r\n\r\nfunction extractOAuthCallbackParams(url: URL): OAuthCallbackParams | null {\r\n const code = url.searchParams.get(\"code\");\r\n const state = url.searchParams.get(\"state\");\r\n if (!code || !state) {\r\n return null;\r\n }\r\n return { code, state };\r\n}\r\n\r\nfunction parseOAuthCallbackInput(\r\n value: string,\r\n fallbackState: string,\r\n): OAuthCallbackParams | { error: string } {\r\n const trimmed = value.trim();\r\n if (!trimmed) {\r\n return { error: \"Missing authorization code\" };\r\n }\r\n\r\n try {\r\n const url = new URL(trimmed);\r\n const code = url.searchParams.get(\"code\");\r\n const state = url.searchParams.get(\"state\") ?? fallbackState;\r\n\r\n if (!code) {\r\n return { error: \"Missing code in callback URL\" };\r\n }\r\n if (!state) {\r\n return { error: \"Missing state in callback URL\" };\r\n }\r\n\r\n return { code, state };\r\n } catch {\r\n if (!fallbackState) {\r\n return { error: \"Missing state. Paste the full redirect URL instead of only the code.\" };\r\n }\r\n\r\n return { code: trimmed, state: fallbackState };\r\n }\r\n}\r\n\r\nasync function promptManualOAuthInput(\r\n fallbackState: string,\r\n): Promise<AntigravityTokenExchangeResult> {\r\n console.log(\"1. Open the URL above in your browser and complete Google sign-in.\");\r\n console.log(\"2. After approving, copy the full redirected localhost URL from the address bar.\");\r\n console.log(\"3. Paste it back here.\\n\");\r\n\r\n const callbackInput = await promptOAuthCallbackValue(\r\n \"Paste the redirect URL (or just the code) here: \",\r\n );\r\n const params = parseOAuthCallbackInput(callbackInput, fallbackState);\r\n if (\"error\" in params) {\r\n return { type: \"failed\", error: params.error };\r\n }\r\n\r\n return exchangeAntigravity(params.code, params.state);\r\n}\r\n\r\nfunction clampInt(value: number, min: number, max: number): number {\r\n if (!Number.isFinite(value)) {\r\n return min;\r\n }\r\n return Math.min(max, Math.max(min, Math.floor(value)));\r\n}\r\n\r\nasync function persistAccountPool(\r\n results: Array<Extract<AntigravityTokenExchangeResult, { type: \"success\" }>>,\r\n replaceAll: boolean = false,\r\n): Promise<void> {\r\n if (results.length === 0) {\r\n return;\r\n }\r\n\r\n const now = Date.now();\r\n \r\n // If replaceAll is true (fresh login), start with empty accounts\r\n // Otherwise, load existing accounts and merge\r\n const stored = replaceAll ? null : await loadAccounts();\r\n const accounts = stored?.accounts ? [...stored.accounts] : [];\r\n\r\n const indexByRefreshToken = new Map<string, number>();\r\n const indexByEmail = new Map<string, number>();\r\n for (let i = 0; i < accounts.length; i++) {\r\n const acc = accounts[i];\r\n if (acc?.refreshToken) {\r\n indexByRefreshToken.set(acc.refreshToken, i);\r\n }\r\n if (acc?.email) {\r\n indexByEmail.set(acc.email, i);\r\n }\r\n }\r\n\r\n for (const result of results) {\r\n const parts = parseRefreshParts(result.refresh);\r\n if (!parts.refreshToken) {\r\n continue;\r\n }\r\n\r\n // First, check for existing account by email (prevents duplicates when refresh token changes)\r\n // Only use email-based deduplication if the new account has an email\r\n const existingByEmail = result.email ? indexByEmail.get(result.email) : undefined;\r\n const existingByToken = indexByRefreshToken.get(parts.refreshToken);\r\n \r\n // Prefer email-based match to handle refresh token rotation\r\n const existingIndex = existingByEmail ?? existingByToken;\r\n \r\n if (existingIndex === undefined) {\r\n // New account - add it\r\n const newIndex = accounts.length;\r\n indexByRefreshToken.set(parts.refreshToken, newIndex);\r\n if (result.email) {\r\n indexByEmail.set(result.email, newIndex);\r\n }\r\n accounts.push({\r\n email: result.email,\r\n refreshToken: parts.refreshToken,\r\n projectId: parts.projectId,\r\n managedProjectId: parts.managedProjectId,\r\n addedAt: now,\r\n lastUsed: now,\r\n enabled: true,\r\n });\r\n continue;\r\n }\r\n\r\n const existing = accounts[existingIndex];\r\n if (!existing) {\r\n continue;\r\n }\r\n\r\n // Update existing account (this handles both email match and token match cases)\r\n // When email matches but token differs, this effectively replaces the old token\r\n const oldToken = existing.refreshToken;\r\n accounts[existingIndex] = {\r\n ...existing,\r\n email: result.email ?? existing.email,\r\n refreshToken: parts.refreshToken,\r\n projectId: parts.projectId ?? existing.projectId,\r\n managedProjectId: parts.managedProjectId ?? existing.managedProjectId,\r\n lastUsed: now,\r\n };\r\n \r\n // Update the token index if the token changed\r\n if (oldToken !== parts.refreshToken) {\r\n indexByRefreshToken.delete(oldToken);\r\n indexByRefreshToken.set(parts.refreshToken, existingIndex);\r\n }\r\n }\r\n\r\n if (accounts.length === 0) {\r\n return;\r\n }\r\n\r\n // For fresh logins, always start at index 0\r\n const activeIndex = replaceAll \r\n ? 0 \r\n : (typeof stored?.activeIndex === \"number\" && Number.isFinite(stored.activeIndex) ? stored.activeIndex : 0);\r\n\r\n await saveAccounts({\r\n version: 4,\r\n accounts,\r\n activeIndex: clampInt(activeIndex, 0, accounts.length - 1),\r\n activeIndexByFamily: {\r\n claude: clampInt(activeIndex, 0, accounts.length - 1),\r\n gemini: clampInt(activeIndex, 0, accounts.length - 1),\r\n },\r\n });\r\n}\r\n\r\nfunction buildAuthSuccessFromStoredAccount(account: {\r\n refreshToken: string;\r\n projectId?: string;\r\n managedProjectId?: string;\r\n email?: string;\r\n}): Extract<AntigravityTokenExchangeResult, { type: \"success\" }> {\r\n const refresh = formatRefreshParts({\r\n refreshToken: account.refreshToken,\r\n projectId: account.projectId,\r\n managedProjectId: account.managedProjectId,\r\n });\r\n\r\n return {\r\n type: \"success\",\r\n refresh,\r\n access: \"\",\r\n expires: 0,\r\n email: account.email,\r\n projectId: account.projectId ?? \"\",\r\n };\r\n}\r\n\r\nfunction retryAfterMsFromResponse(response: Response, defaultRetryMs: number = 60_000): number {\r\n const retryAfterMsHeader = response.headers.get(\"retry-after-ms\");\r\n if (retryAfterMsHeader) {\r\n const parsed = Number.parseInt(retryAfterMsHeader, 10);\r\n if (!Number.isNaN(parsed) && parsed > 0) {\r\n return parsed;\r\n }\r\n }\r\n\r\n const retryAfterHeader = response.headers.get(\"retry-after\");\r\n if (retryAfterHeader) {\r\n const parsed = Number.parseInt(retryAfterHeader, 10);\r\n if (!Number.isNaN(parsed) && parsed > 0) {\r\n return parsed * 1000;\r\n }\r\n }\r\n\r\n return defaultRetryMs;\r\n}\r\n\r\n/**\r\n * Parse Go-style duration strings to milliseconds.\r\n * Supports compound durations: \"1h16m0.667s\", \"1.5s\", \"200ms\", \"5m30s\"\r\n * \r\n * @param duration - Duration string in Go format\r\n * @returns Duration in milliseconds, or null if parsing fails\r\n */\r\nfunction parseDurationToMs(duration: string): number | null {\r\n // Handle simple formats first for backwards compatibility\r\n const simpleMatch = duration.match(/^(\\d+(?:\\.\\d+)?)(ms|s|m|h)?$/i);\r\n if (simpleMatch) {\r\n const value = parseFloat(simpleMatch[1]!);\r\n const unit = (simpleMatch[2] || \"s\").toLowerCase();\r\n switch (unit) {\r\n case \"h\": return value * 3600 * 1000;\r\n case \"m\": return value * 60 * 1000;\r\n case \"s\": return value * 1000;\r\n case \"ms\": return value;\r\n default: return value * 1000;\r\n }\r\n }\r\n \r\n // Parse compound Go-style durations: \"1h16m0.667s\", \"5m30s\", etc.\r\n const compoundRegex = /(\\d+(?:\\.\\d+)?)(h|m(?!s)|s|ms)/gi;\r\n let totalMs = 0;\r\n let matchFound = false;\r\n let match;\r\n \r\n while ((match = compoundRegex.exec(duration)) !== null) {\r\n matchFound = true;\r\n const value = parseFloat(match[1]!);\r\n const unit = match[2]!.toLowerCase();\r\n switch (unit) {\r\n case \"h\": totalMs += value * 3600 * 1000; break;\r\n case \"m\": totalMs += value * 60 * 1000; break;\r\n case \"s\": totalMs += value * 1000; break;\r\n case \"ms\": totalMs += value; break;\r\n }\r\n }\r\n \r\n return matchFound ? totalMs : null;\r\n}\r\n\r\ninterface RateLimitBodyInfo {\r\n retryDelayMs: number | null;\r\n message?: string;\r\n quotaResetTime?: string;\r\n reason?: string;\r\n}\r\n\r\nfunction extractRateLimitBodyInfo(body: unknown): RateLimitBodyInfo {\r\n if (!body || typeof body !== \"object\") {\r\n return { retryDelayMs: null };\r\n }\r\n\r\n const error = (body as { error?: unknown }).error;\r\n const message = error && typeof error === \"object\" \r\n ? (error as { message?: string }).message \r\n : undefined;\r\n\r\n const details = error && typeof error === \"object\" \r\n ? (error as { details?: unknown[] }).details \r\n : undefined;\r\n\r\n let reason: string | undefined;\r\n if (Array.isArray(details)) {\r\n for (const detail of details) {\r\n if (!detail || typeof detail !== \"object\") continue;\r\n const type = (detail as { \"@type\"?: string })[\"@type\"];\r\n if (typeof type === \"string\" && type.includes(\"google.rpc.ErrorInfo\")) {\r\n const detailReason = (detail as { reason?: string }).reason;\r\n if (typeof detailReason === \"string\") {\r\n reason = detailReason;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n for (const detail of details) {\r\n if (!detail || typeof detail !== \"object\") continue;\r\n const type = (detail as { \"@type\"?: string })[\"@type\"];\r\n if (typeof type === \"string\" && type.includes(\"google.rpc.RetryInfo\")) {\r\n const retryDelay = (detail as { retryDelay?: string }).retryDelay;\r\n if (typeof retryDelay === \"string\") {\r\n const retryDelayMs = parseDurationToMs(retryDelay);\r\n if (retryDelayMs !== null) {\r\n return { retryDelayMs, message, reason };\r\n }\r\n }\r\n }\r\n }\r\n\r\n for (const detail of details) {\r\n if (!detail || typeof detail !== \"object\") continue;\r\n const metadata = (detail as { metadata?: Record<string, string> }).metadata;\r\n if (metadata && typeof metadata === \"object\") {\r\n const quotaResetDelay = metadata.quotaResetDelay;\r\n const quotaResetTime = metadata.quotaResetTimeStamp;\r\n if (typeof quotaResetDelay === \"string\") {\r\n const quotaResetDelayMs = parseDurationToMs(quotaResetDelay);\r\n if (quotaResetDelayMs !== null) {\r\n return { retryDelayMs: quotaResetDelayMs, message, quotaResetTime, reason };\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (message) {\r\n const afterMatch = message.match(/reset after\\s+([0-9hms.]+)/i);\r\n const rawDuration = afterMatch?.[1];\r\n if (rawDuration) {\r\n const parsed = parseDurationToMs(rawDuration);\r\n if (parsed !== null) {\r\n return { retryDelayMs: parsed, message, reason };\r\n }\r\n }\r\n }\r\n\r\n return { retryDelayMs: null, message, reason };\r\n}\r\n\r\nasync function extractRetryInfoFromBody(response: Response): Promise<RateLimitBodyInfo> {\r\n try {\r\n const text = await response.clone().text();\r\n try {\r\n const parsed = JSON.parse(text) as unknown;\r\n return extractRateLimitBodyInfo(parsed);\r\n } catch {\r\n return { retryDelayMs: null };\r\n }\r\n } catch {\r\n return { retryDelayMs: null };\r\n }\r\n}\r\n\r\nfunction formatWaitTime(ms: number): string {\r\n if (ms < 1000) return `${ms}ms`;\r\n const seconds = Math.ceil(ms / 1000);\r\n if (seconds < 60) return `${seconds}s`;\r\n const minutes = Math.floor(seconds / 60);\r\n const remainingSeconds = seconds % 60;\r\n if (minutes < 60) {\r\n return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;\r\n }\r\n const hours = Math.floor(minutes / 60);\r\n const remainingMinutes = minutes % 60;\r\n return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`;\r\n}\r\n\r\n// Progressive rate limit retry delays\r\nconst FIRST_RETRY_DELAY_MS = 1000; // 1s - first 429 quick retry on same account\r\nconst SWITCH_ACCOUNT_DELAY_MS = 5000; // 5s - delay before switching to another account\r\n\r\n/**\r\n * Rate limit state tracking with time-window deduplication.\r\n * \r\n * Problem: When multiple subagents hit 429 simultaneously, each would increment\r\n * the consecutive counter, causing incorrect exponential backoff (5 concurrent\r\n * 429s = 2^5 backoff instead of 2^1).\r\n * \r\n * Solution: Track per account+quota with deduplication window. Multiple 429s\r\n * within RATE_LIMIT_DEDUP_WINDOW_MS are treated as a single event.\r\n */\r\nconst RATE_LIMIT_DEDUP_WINDOW_MS = 2000; // 2 seconds - concurrent requests within this window are deduplicated\r\nconst RATE_LIMIT_STATE_RESET_MS = 120_000; // Reset consecutive counter after 2 minutes of no 429s\r\n\r\ninterface RateLimitState {\r\n consecutive429: number;\r\n lastAt: number;\r\n quotaKey: string; // Track which quota this state is for\r\n}\r\n\r\n// Key format: `${accountIndex}:${quotaKey}` for per-account-per-quota tracking\r\nconst rateLimitStateByAccountQuota = new Map<string, RateLimitState>();\r\n\r\n// Track empty response retry attempts (ported from LLM-API-Key-Proxy)\r\nconst emptyResponseAttempts = new Map<string, number>();\r\n\r\n/**\r\n * Get rate limit backoff with time-window deduplication.\r\n * \r\n * @param accountIndex - The account index\r\n * @param quotaKey - The quota key (e.g., \"gemini-cli\", \"gemini-antigravity\", \"claude\")\r\n * @param serverRetryAfterMs - Server-provided retry delay (if any)\r\n * @param maxBackoffMs - Maximum backoff delay in milliseconds (default 60000)\r\n * @returns { attempt, delayMs, isDuplicate } - isDuplicate=true if within dedup window\r\n */\r\nfunction getRateLimitBackoff(\r\n accountIndex: number, \r\n quotaKey: string,\r\n serverRetryAfterMs: number | null,\r\n maxBackoffMs: number = 60_000\r\n): { attempt: number; delayMs: number; isDuplicate: boolean } {\r\n const now = Date.now();\r\n const stateKey = `${accountIndex}:${quotaKey}`;\r\n const previous = rateLimitStateByAccountQuota.get(stateKey);\r\n \r\n // Check if this is a duplicate 429 within the dedup window\r\n if (previous && (now - previous.lastAt < RATE_LIMIT_DEDUP_WINDOW_MS)) {\r\n // Same rate limit event from concurrent request - don't increment\r\n const baseDelay = serverRetryAfterMs ?? 1000;\r\n const backoffDelay = Math.min(baseDelay * Math.pow(2, previous.consecutive429 - 1), maxBackoffMs);\r\n return { \r\n attempt: previous.consecutive429, \r\n delayMs: Math.max(baseDelay, backoffDelay),\r\n isDuplicate: true \r\n };\r\n }\r\n \r\n // Check if we should reset (no 429 for 2 minutes) or increment\r\n const attempt = previous && (now - previous.lastAt < RATE_LIMIT_STATE_RESET_MS) \r\n ? previous.consecutive429 + 1 \r\n : 1;\r\n \r\n rateLimitStateByAccountQuota.set(stateKey, { \r\n consecutive429: attempt, \r\n lastAt: now,\r\n quotaKey \r\n });\r\n \r\n const baseDelay = serverRetryAfterMs ?? 1000;\r\n const backoffDelay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxBackoffMs);\r\n return { attempt, delayMs: Math.max(baseDelay, backoffDelay), isDuplicate: false };\r\n}\r\n\r\n/**\r\n * Reset rate limit state for an account+quota combination.\r\n * Only resets the specific quota, not all quotas for the account.\r\n */\r\nfunction resetRateLimitState(accountIndex: number, quotaKey: string): void {\r\n const stateKey = `${accountIndex}:${quotaKey}`;\r\n rateLimitStateByAccountQuota.delete(stateKey);\r\n}\r\n\r\n/**\r\n * Reset all rate limit state for an account (all quotas).\r\n * Used when account is completely healthy.\r\n */\r\nfunction resetAllRateLimitStateForAccount(accountIndex: number): void {\r\n for (const key of rateLimitStateByAccountQuota.keys()) {\r\n if (key.startsWith(`${accountIndex}:`)) {\r\n rateLimitStateByAccountQuota.delete(key);\r\n }\r\n }\r\n}\r\n\r\nfunction headerStyleToQuotaKey(headerStyle: HeaderStyle, family: ModelFamily): string {\r\n if (family === \"claude\") return \"claude\";\r\n return headerStyle === \"antigravity\" ? \"gemini-antigravity\" : \"gemini-cli\";\r\n}\r\n\r\n// Track consecutive non-429 failures per account to prevent infinite loops\r\nconst accountFailureState = new Map<number, { consecutiveFailures: number; lastFailureAt: number }>();\r\nconst MAX_CONSECUTIVE_FAILURES = 5;\r\nconst FAILURE_COOLDOWN_MS = 30_000; // 30 seconds cooldown after max failures\r\nconst FAILURE_STATE_RESET_MS = 120_000; // Reset failure count after 2 minutes of no failures\r\n\r\nfunction trackAccountFailure(accountIndex: number): { failures: number; shouldCooldown: boolean; cooldownMs: number } {\r\n const now = Date.now();\r\n const previous = accountFailureState.get(accountIndex);\r\n \r\n // Reset if last failure was more than 2 minutes ago\r\n const failures = previous && (now - previous.lastFailureAt < FAILURE_STATE_RESET_MS) \r\n ? previous.consecutiveFailures + 1 \r\n : 1;\r\n \r\n accountFailureState.set(accountIndex, { consecutiveFailures: failures, lastFailureAt: now });\r\n \r\n const shouldCooldown = failures >= MAX_CONSECUTIVE_FAILURES;\r\n const cooldownMs = shouldCooldown ? FAILURE_COOLDOWN_MS : 0;\r\n \r\n return { failures, shouldCooldown, cooldownMs };\r\n}\r\n\r\nfunction resetAccountFailureState(accountIndex: number): void {\r\n accountFailureState.delete(accountIndex);\r\n}\r\n\r\n/**\r\n * Sleep for a given number of milliseconds, respecting an abort signal.\r\n */\r\nfunction sleep(ms: number, signal?: AbortSignal | null): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n if (signal?.aborted) {\r\n reject(signal.reason instanceof Error ? signal.reason : new Error(\"Aborted\"));\r\n return;\r\n }\r\n\r\n const timeout = setTimeout(() => {\r\n cleanup();\r\n resolve();\r\n }, ms);\r\n\r\n const onAbort = () => {\r\n cleanup();\r\n reject(signal?.reason instanceof Error ? signal.reason : new Error(\"Aborted\"));\r\n };\r\n\r\n const cleanup = () => {\r\n clearTimeout(timeout);\r\n signal?.removeEventListener(\"abort\", onAbort);\r\n };\r\n\r\n signal?.addEventListener(\"abort\", onAbort, { once: true });\r\n });\r\n}\r\n\r\n/**\r\n * Creates an Antigravity OAuth plugin for a specific provider ID.\r\n */\r\nexport const createAntigravityPlugin = (providerId: string) => async (\r\n { client, directory }: PluginContext,\r\n): Promise<PluginResult> => {\r\n // Load configuration from files and environment variables\r\n const config = loadConfig(directory);\r\n initRuntimeConfig(config);\r\n\r\n // Cached getAuth function for tool access\r\n let cachedGetAuth: GetAuth | null = null;\r\n \r\n // Initialize debug with config\r\n initializeDebug(config);\r\n \r\n // Initialize structured logger for TUI integration\r\n initLogger(client);\r\n \r\n // Fetch latest Antigravity version from remote API (non-blocking, falls back to hardcoded)\r\n await initAntigravityVersion();\r\n \r\n // Initialize health tracker for hybrid strategy\r\n if (config.health_score) {\r\n initHealthTracker({\r\n initial: config.health_score.initial,\r\n successReward: config.health_score.success_reward,\r\n rateLimitPenalty: config.health_score.rate_limit_penalty,\r\n failurePenalty: config.health_score.failure_penalty,\r\n recoveryRatePerHour: config.health_score.recovery_rate_per_hour,\r\n minUsable: config.health_score.min_usable,\r\n maxScore: config.health_score.max_score,\r\n });\r\n }\r\n\r\n // Initialize token tracker for hybrid strategy\r\n if (config.token_bucket) {\r\n initTokenTracker({\r\n maxTokens: config.token_bucket.max_tokens,\r\n regenerationRatePerMinute: config.token_bucket.regeneration_rate_per_minute,\r\n initialTokens: config.token_bucket.initial_tokens,\r\n });\r\n }\r\n \r\n // Initialize disk signature cache if keep_thinking is enabled\r\n // This integrates with the in-memory cacheSignature/getCachedSignature functions\r\n if (config.keep_thinking) {\r\n initDiskSignatureCache(config.signature_cache);\r\n }\r\n \r\n // Initialize session recovery hook with full context\r\n const sessionRecovery = createSessionRecoveryHook({ client, directory }, config);\r\n \r\n const updateChecker = createAutoUpdateCheckerHook(client, directory, {\r\n showStartupToast: true,\r\n autoUpdate: config.auto_update,\r\n });\r\n\r\n // Event handler for session recovery and updates\r\n const eventHandler = async (input: { event: { type: string; properties?: unknown } }) => {\r\n // Forward to update checker\r\n await updateChecker.event(input);\r\n \r\n // Track if this is a child session (subagent, background task)\r\n // This is used to filter toasts based on toast_scope config\r\n if (input.event.type === \"session.created\") {\r\n const props = input.event.properties as { info?: { parentID?: string } } | undefined;\r\n if (props?.info?.parentID) {\r\n isChildSession = true;\r\n childSessionParentID = props.info.parentID;\r\n log.debug(\"child-session-detected\", { parentID: props.info.parentID });\r\n } else {\r\n // Reset for root sessions - important when plugin instance is reused\r\n isChildSession = false;\r\n childSessionParentID = undefined;\r\n log.debug(\"root-session-detected\", {});\r\n }\r\n }\r\n \r\n // Handle session recovery\r\n if (sessionRecovery && input.event.type === \"session.error\") {\r\n const props = input.event.properties as Record<string, unknown> | undefined;\r\n const sessionID = props?.sessionID as string | undefined;\r\n const messageID = props?.messageID as string | undefined;\r\n const error = props?.error;\r\n \r\n if (sessionRecovery.isRecoverableError(error)) {\r\n const messageInfo = {\r\n id: messageID,\r\n role: \"assistant\" as const,\r\n sessionID,\r\n error,\r\n };\r\n \r\n // handleSessionRecovery now does the actual fix (injects tool_result, etc.)\r\n const recovered = await sessionRecovery.handleSessionRecovery(messageInfo);\r\n\r\n // Only send \"continue\" AFTER successful tool_result_missing recovery\r\n // (thinking recoveries already resume inside handleSessionRecovery)\r\n if (recovered && sessionID && config.auto_resume) {\r\n // For tool_result_missing, we need to send continue after injecting tool_results\r\n await client.session.prompt({\r\n path: { id: sessionID },\r\n body: { parts: [{ type: \"text\", text: config.resume_text }] },\r\n query: { directory },\r\n }).catch(() => {});\r\n \r\n // Show success toast (respects toast_scope for child sessions)\r\n const successToast = getRecoverySuccessToast();\r\n log.debug(\"recovery-toast\", { ...successToast, isChildSession, toastScope: config.toast_scope });\r\n if (!(config.toast_scope === \"root_only\" && isChildSession)) {\r\n await client.tui.showToast({\r\n body: {\r\n title: successToast.title,\r\n message: successToast.message,\r\n variant: \"success\",\r\n },\r\n }).catch(() => {});\r\n }\r\n }\r\n }\r\n }\r\n };\r\n\r\n // Create google_search tool with access to auth context\r\n const googleSearchTool = tool({\r\n description: \"Search the web using Google Search and analyze URLs. Returns real-time information from the internet with source citations. Use this when you need up-to-date information about current events, recent developments, or any topic that may have changed. You can also provide specific URLs to analyze. IMPORTANT: If the user mentions or provides any URLs in their query, you MUST extract those URLs and pass them in the 'urls' parameter for direct analysis.\",\r\n args: {\r\n query: tool.schema.string().describe(\"The search query or question to answer using web search\"),\r\n urls: tool.schema.array(tool.schema.string()).optional().describe(\"List of specific URLs to fetch and analyze. IMPORTANT: Always extract and include any URLs mentioned by the user in their query here.\"),\r\n thinking: tool.schema.boolean().optional().default(true).describe(\"Enable deep thinking for more thorough analysis (default: true)\"),\r\n },\r\n async execute(args, ctx) {\r\n log.debug(\"Google Search tool called\", { query: args.query, urlCount: args.urls?.length ?? 0 });\r\n\r\n // Get current auth context\r\n const auth = cachedGetAuth ? await cachedGetAuth() : null;\r\n if (!auth || !isOAuthAuth(auth)) {\r\n return \"Error: Not authenticated with Antigravity. Please run `opencode auth login` to authenticate.\";\r\n }\r\n\r\n // Get access token and project ID\r\n const parts = parseRefreshParts(auth.refresh);\r\n const projectId = parts.managedProjectId || parts.projectId || \"unknown\";\r\n\r\n // Ensure we have a valid access token\r\n let accessToken = auth.access;\r\n if (!accessToken || accessTokenExpired(auth)) {\r\n try {\r\n const refreshed = await refreshAccessToken(auth, client, providerId);\r\n accessToken = refreshed?.access;\r\n } catch (error) {\r\n return `Error: Failed to refresh access token: ${error instanceof Error ? error.message : String(error)}`;\r\n }\r\n }\r\n\r\n if (!accessToken) {\r\n return \"Error: No valid access token available. Please run `opencode auth login` to re-authenticate.\";\r\n }\r\n\r\n return executeSearch(\r\n {\r\n query: args.query,\r\n urls: args.urls,\r\n thinking: args.thinking,\r\n },\r\n accessToken,\r\n projectId,\r\n ctx.abort,\r\n );\r\n },\r\n });\r\n\r\n return {\r\n event: eventHandler,\r\n tool: {\r\n google_search: googleSearchTool,\r\n },\r\n auth: {\r\n provider: providerId,\r\n loader: async (getAuth: GetAuth, provider: Provider): Promise<LoaderResult | Record<string, unknown>> => {\r\n // Cache getAuth for tool access\r\n cachedGetAuth = getAuth;\r\n\r\n const auth = await getAuth();\r\n \r\n // If OpenCode has no valid OAuth auth, clear any stale account storage\r\n if (!isOAuthAuth(auth)) {\r\n try {\r\n await clearAccounts();\r\n } catch {\r\n // ignore\r\n }\r\n return {};\r\n }\r\n\r\n // Validate that stored accounts are in sync with OpenCode's auth\r\n // If OpenCode's refresh token doesn't match any stored account, clear stale storage\r\n const authParts = parseRefreshParts(auth.refresh);\r\n const storedAccounts = await loadAccounts();\r\n \r\n // Note: AccountManager now ensures the current auth is always included in accounts\r\n\r\n const accountManager = await AccountManager.loadFromDisk(auth);\r\n activeAccountManager = accountManager;\r\n if (accountManager.getAccountCount() > 0) {\r\n accountManager.requestSaveToDisk();\r\n }\r\n\r\n // Initialize proactive token refresh queue (ported from LLM-API-Key-Proxy)\r\n let refreshQueue: ProactiveRefreshQueue | null = null;\r\n if (config.proactive_token_refresh && accountManager.getAccountCount() > 0) {\r\n refreshQueue = createProactiveRefreshQueue(client, providerId, {\r\n enabled: config.proactive_token_refresh,\r\n bufferSeconds: config.proactive_refresh_buffer_seconds,\r\n checkIntervalSeconds: config.proactive_refresh_check_interval_seconds,\r\n });\r\n refreshQueue.setAccountManager(accountManager);\r\n refreshQueue.start();\r\n }\r\n\r\n if (isDebugEnabled()) {\r\n const logPath = getLogFilePath();\r\n if (logPath) {\r\n try {\r\n await client.tui.showToast({\r\n body: { message: `Debug log: ${logPath}`, variant: \"info\" },\r\n });\r\n } catch {\r\n // TUI may not be available\r\n }\r\n }\r\n }\r\n\r\n if (provider.models) {\r\n for (const model of Object.values(provider.models)) {\r\n if (model) {\r\n model.cost = { input: 0, output: 0 };\r\n }\r\n }\r\n }\r\n\r\n return {\r\n apiKey: \"\",\r\n async fetch(input, init) {\r\n if (!isGenerativeLanguageRequest(input)) {\r\n return fetch(input, init);\r\n }\r\n\r\n const latestAuth = await getAuth();\r\n if (!isOAuthAuth(latestAuth)) {\r\n return fetch(input, init);\r\n }\r\n\r\n if (accountManager.getAccountCount() === 0) {\r\n throw new Error(\"No Antigravity accounts configured. Run `opencode auth login`.\");\r\n }\r\n\r\n const urlString = toUrlString(input);\r\n const family = getModelFamilyFromUrl(urlString);\r\n const model = extractModelFromUrl(urlString);\r\n const debugLines: string[] = [];\r\n const pushDebug = (line: string) => {\r\n if (!isDebugEnabled()) return;\r\n debugLines.push(line);\r\n };\r\n pushDebug(`request=${urlString}`);\r\n\r\n type FailureContext = {\r\n response: Response;\r\n streaming: boolean;\r\n debugContext: ReturnType<typeof startAntigravityDebugRequest>;\r\n requestedModel?: string;\r\n projectId?: string;\r\n endpoint?: string;\r\n effectiveModel?: string;\r\n sessionId?: string;\r\n toolDebugMissing?: number;\r\n toolDebugSummary?: string;\r\n toolDebugPayload?: string;\r\n };\r\n\r\n let lastFailure: FailureContext | null = null;\r\n let lastError: Error | null = null;\r\n const abortSignal = init?.signal ?? undefined;\r\n\r\n // Helper to check if request was aborted\r\n const checkAborted = () => {\r\n if (abortSignal?.aborted) {\r\n throw abortSignal.reason instanceof Error ? abortSignal.reason : new Error(\"Aborted\");\r\n }\r\n };\r\n\r\n // Use while(true) loop to handle rate limits with backoff\r\n // This ensures we wait and retry when all accounts are rate-limited\r\n const quietMode = config.quiet_mode;\r\n const toastScope = config.toast_scope;\r\n\r\n // Helper to show toast without blocking on abort (respects quiet_mode and toast_scope)\r\n const showToast = async (message: string, variant: \"info\" | \"warning\" | \"success\" | \"error\") => {\r\n // Always log to debug regardless of toast filtering\r\n log.debug(\"toast\", { message, variant, isChildSession, toastScope });\r\n \r\n if (quietMode) return;\r\n if (abortSignal?.aborted) return;\r\n \r\n // Filter toasts for child sessions when toast_scope is \"root_only\"\r\n if (toastScope === \"root_only\" && isChildSession) {\r\n log.debug(\"toast-suppressed-child-session\", { message, variant, parentID: childSessionParentID });\r\n return;\r\n }\r\n \r\n if (variant === \"warning\" && message.toLowerCase().includes(\"rate\")) {\r\n if (!shouldShowRateLimitToast(message)) {\r\n return;\r\n }\r\n }\r\n \r\n try {\r\n await client.tui.showToast({\r\n body: { message, variant },\r\n });\r\n } catch {\r\n // TUI may not be available\r\n }\r\n };\r\n \r\n const hasOtherAccountWithAntigravity = (currentAccount: any): boolean => {\r\n if (family !== \"gemini\") return false;\r\n // Use AccountManager method which properly checks for disabled/cooling-down accounts\r\n return accountManager.hasOtherAccountWithAntigravityAvailable(currentAccount.index, family, model);\r\n };\r\n\r\n while (true) {\r\n // Check for abort at the start of each iteration\r\n checkAborted();\r\n \r\n const accountCount = accountManager.getAccountCount();\r\n const routingDecision = resolveHeaderRoutingDecision(urlString, family, config);\r\n const {\r\n cliFirst,\r\n preferredHeaderStyle,\r\n explicitQuota,\r\n allowQuotaFallback,\r\n } = routingDecision;\r\n \r\n if (accountCount === 0) {\r\n throw new Error(\"No Antigravity accounts available. Run `opencode auth login`.\");\r\n }\r\n\r\n const softQuotaCacheTtlMs = computeSoftQuotaCacheTtlMs(\r\n config.soft_quota_cache_ttl_minutes,\r\n config.quota_refresh_interval_minutes,\r\n );\r\n\r\n let account = accountManager.getCurrentOrNextForFamily(\r\n family, \r\n model, \r\n config.account_selection_strategy,\r\n preferredHeaderStyle,\r\n config.pid_offset_enabled,\r\n config.soft_quota_threshold_percent,\r\n softQuotaCacheTtlMs,\r\n );\r\n\r\n if (!account && allowQuotaFallback) {\r\n const alternateHeaderStyle: HeaderStyle =\r\n preferredHeaderStyle === \"antigravity\" ? \"gemini-cli\" : \"antigravity\";\r\n account = accountManager.getCurrentOrNextForFamily(\r\n family,\r\n model,\r\n config.account_selection_strategy,\r\n alternateHeaderStyle,\r\n config.pid_offset_enabled,\r\n config.soft_quota_threshold_percent,\r\n softQuotaCacheTtlMs,\r\n );\r\n if (account) {\r\n pushDebug(\r\n `selected-by-fallback idx=${account.index} preferred=${preferredHeaderStyle} alternate=${alternateHeaderStyle}`,\r\n );\r\n }\r\n }\r\n \r\n if (!account) {\r\n if (accountManager.areAllAccountsOverSoftQuota(family, config.soft_quota_threshold_percent, softQuotaCacheTtlMs, model)) {\r\n const threshold = config.soft_quota_threshold_percent;\r\n const softQuotaWaitMs = accountManager.getMinWaitTimeForSoftQuota(family, threshold, softQuotaCacheTtlMs, model);\r\n const maxWaitMs = (config.max_rate_limit_wait_seconds ?? 300) * 1000;\r\n \r\n if (softQuotaWaitMs === null || (maxWaitMs > 0 && softQuotaWaitMs > maxWaitMs)) {\r\n const waitTimeFormatted = softQuotaWaitMs ? formatWaitTime(softQuotaWaitMs) : \"unknown\";\r\n await showToast(\r\n `All accounts over ${threshold}% quota threshold. Resets in ${waitTimeFormatted}.`,\r\n \"error\"\r\n );\r\n throw new Error(\r\n `Quota protection: All ${accountCount} account(s) are over ${threshold}% usage for ${family}. ` +\r\n `Quota resets in ${waitTimeFormatted}. ` +\r\n `Add more accounts, wait for quota reset, or set soft_quota_threshold_percent: 100 to disable.`\r\n );\r\n }\r\n \r\n const waitSecValue = Math.max(1, Math.ceil(softQuotaWaitMs / 1000));\r\n pushDebug(`all-over-soft-quota family=${family} accounts=${accountCount} waitMs=${softQuotaWaitMs}`);\r\n \r\n if (!softQuotaToastShown) {\r\n await showToast(`All ${accountCount} account(s) over ${threshold}% quota. Waiting ${formatWaitTime(softQuotaWaitMs)}...`, \"warning\");\r\n softQuotaToastShown = true;\r\n }\r\n \r\n await sleep(softQuotaWaitMs, abortSignal);\r\n continue;\r\n }\r\n\r\n const strictWait = !allowQuotaFallback;\r\n // All accounts are rate-limited - wait and retry\r\n const waitMs = accountManager.getMinWaitTimeForFamily(\r\n family,\r\n model,\r\n preferredHeaderStyle,\r\n strictWait,\r\n ) || 60_000;\r\n const waitSecValue = Math.max(1, Math.ceil(waitMs / 1000));\r\n\r\n pushDebug(`all-rate-limited family=${family} accounts=${accountCount} waitMs=${waitMs}`);\r\n if (isDebugEnabled()) {\r\n logAccountContext(\"All accounts rate-limited\", {\r\n index: -1,\r\n family,\r\n totalAccounts: accountCount,\r\n });\r\n logRateLimitSnapshot(family, accountManager.getAccountsSnapshot());\r\n }\r\n\r\n // If wait time exceeds max threshold, return error immediately instead of hanging\r\n // 0 means disabled (wait indefinitely)\r\n const maxWaitMs = (config.max_rate_limit_wait_seconds ?? 300) * 1000;\r\n if (maxWaitMs > 0 && waitMs > maxWaitMs) {\r\n const waitTimeFormatted = formatWaitTime(waitMs);\r\n await showToast(\r\n `Rate limited for ${waitTimeFormatted}. Try again later or add another account.`,\r\n \"error\"\r\n );\r\n \r\n // Return a proper rate limit error response\r\n throw new Error(\r\n `All ${accountCount} account(s) rate-limited for ${family}. ` +\r\n `Quota resets in ${waitTimeFormatted}. ` +\r\n `Add more accounts with \\`opencode auth login\\` or wait and retry.`\r\n );\r\n }\r\n\r\n if (!rateLimitToastShown) {\r\n await showToast(`All ${accountCount} account(s) rate-limited for ${family}. Waiting ${waitSecValue}s...`, \"warning\");\r\n rateLimitToastShown = true;\r\n }\r\n\r\n // Wait for the rate-limit cooldown to expire, then retry\r\n await sleep(waitMs, abortSignal);\r\n continue;\r\n }\r\n\r\n // Account is available - reset the toast flag\r\n resetAllAccountsBlockedToasts();\r\n\r\n pushDebug(\r\n `selected idx=${account.index} email=${account.email ?? \"\"} family=${family} accounts=${accountCount} strategy=${config.account_selection_strategy}`,\r\n );\r\n if (isDebugEnabled()) {\r\n logAccountContext(\"Selected\", {\r\n index: account.index,\r\n email: account.email,\r\n family,\r\n totalAccounts: accountCount,\r\n rateLimitState: account.rateLimitResetTimes,\r\n });\r\n }\r\n\r\n // Show toast when switching to a different account (debounced, quiet_mode handled by showToast)\r\n if (accountCount > 1 && accountManager.shouldShowAccountToast(account.index)) {\r\n const accountLabel = account.email || `Account ${account.index + 1}`;\r\n // Calculate position among enabled accounts (not absolute index)\r\n const enabledAccounts = accountManager.getEnabledAccounts();\r\n const enabledPosition = enabledAccounts.findIndex(a => a.index === account.index) + 1;\r\n await showToast(\r\n `Using ${accountLabel} (${enabledPosition}/${accountCount})`,\r\n \"info\"\r\n );\r\n accountManager.markToastShown(account.index);\r\n }\r\n\r\n accountManager.requestSaveToDisk();\r\n\r\n let authRecord = accountManager.toAuthDetails(account);\r\n\r\n if (accessTokenExpired(authRecord)) {\r\n try {\r\n const refreshed = await refreshAccessToken(authRecord, client, providerId);\r\n if (!refreshed) {\r\n const { failures, shouldCooldown, cooldownMs } = trackAccountFailure(account.index);\r\n getHealthTracker().recordFailure(account.index);\r\n lastError = new Error(\"Antigravity token refresh failed\");\r\n if (shouldCooldown) {\r\n accountManager.markAccountCoolingDown(account, cooldownMs, \"auth-failure\");\r\n accountManager.markRateLimited(account, cooldownMs, family, \"antigravity\", model);\r\n pushDebug(`token-refresh-failed: cooldown ${cooldownMs}ms after ${failures} failures`);\r\n }\r\n continue;\r\n }\r\n resetAccountFailureState(account.index);\r\n accountManager.updateFromAuth(account, refreshed);\r\n authRecord = refreshed;\r\n try {\r\n await accountManager.saveToDisk();\r\n } catch (error) {\r\n log.error(\"Failed to persist refreshed auth\", { error: String(error) });\r\n }\r\n } catch (error) {\r\n if (error instanceof AntigravityTokenRefreshError && error.code === \"invalid_grant\") {\r\n const removed = accountManager.removeAccount(account);\r\n if (removed) {\r\n log.warn(\"Removed revoked account from pool - reauthenticate via `opencode auth login`\");\r\n try {\r\n await accountManager.saveToDisk();\r\n } catch (persistError) {\r\n log.error(\"Failed to persist revoked account removal\", { error: String(persistError) });\r\n }\r\n }\r\n\r\n if (accountManager.getAccountCount() === 0) {\r\n try {\r\n await client.auth.set({\r\n path: { id: providerId },\r\n body: { type: \"oauth\", refresh: \"\", access: \"\", expires: 0 },\r\n });\r\n } catch (storeError) {\r\n log.error(\"Failed to clear stored Antigravity OAuth credentials\", { error: String(storeError) });\r\n }\r\n\r\n throw new Error(\r\n \"All Antigravity accounts have invalid refresh tokens. Run `opencode auth login` and reauthenticate.\",\r\n );\r\n }\r\n\r\n lastError = error;\r\n continue;\r\n }\r\n\r\n const { failures, shouldCooldown, cooldownMs } = trackAccountFailure(account.index);\r\n getHealthTracker().recordFailure(account.index);\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n if (shouldCooldown) {\r\n accountManager.markAccountCoolingDown(account, cooldownMs, \"auth-failure\");\r\n accountManager.markRateLimited(account, cooldownMs, family, \"antigravity\", model);\r\n pushDebug(`token-refresh-error: cooldown ${cooldownMs}ms after ${failures} failures`);\r\n }\r\n continue;\r\n }\r\n }\r\n\r\n const accessToken = authRecord.access;\r\n if (!accessToken) {\r\n lastError = new Error(\"Missing access token\");\r\n if (accountCount <= 1) {\r\n throw lastError;\r\n }\r\n continue;\r\n }\r\n\r\n let projectContext: ProjectContextResult;\r\n try {\r\n projectContext = await ensureProjectContext(authRecord);\r\n resetAccountFailureState(account.index);\r\n } catch (error) {\r\n const { failures, shouldCooldown, cooldownMs } = trackAccountFailure(account.index);\r\n getHealthTracker().recordFailure(account.index);\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n if (shouldCooldown) {\r\n accountManager.markAccountCoolingDown(account, cooldownMs, \"project-error\");\r\n accountManager.markRateLimited(account, cooldownMs, family, \"antigravity\", model);\r\n pushDebug(`project-context-error: cooldown ${cooldownMs}ms after ${failures} failures`);\r\n }\r\n continue;\r\n }\r\n\r\n if (projectContext.auth.refresh !== authRecord.refresh || \r\n projectContext.auth.access !== authRecord.access) {\r\n accountManager.updateFromAuth(account, projectContext.auth);\r\n authRecord = projectContext.auth;\r\n try {\r\n await accountManager.saveToDisk();\r\n } catch (error) {\r\n log.error(\"Failed to persist project context\", { error: String(error) });\r\n }\r\n }\r\n\r\n const runThinkingWarmup = async (\r\n prepared: ReturnType<typeof prepareAntigravityRequest>,\r\n projectId: string,\r\n ): Promise<void> => {\r\n if (!prepared.needsSignedThinkingWarmup || !prepared.sessionId) {\r\n return;\r\n }\r\n\r\n if (!trackWarmupAttempt(prepared.sessionId)) {\r\n return;\r\n }\r\n\r\n const warmupBody = buildThinkingWarmupBody(\r\n typeof prepared.init.body === \"string\" ? prepared.init.body : undefined,\r\n Boolean(prepared.effectiveModel?.toLowerCase().includes(\"claude\") && prepared.effectiveModel?.toLowerCase().includes(\"thinking\")),\r\n );\r\n if (!warmupBody) {\r\n return;\r\n }\r\n\r\n const warmupUrl = toWarmupStreamUrl(prepared.request);\r\n const warmupHeaders = new Headers(prepared.init.headers ?? {});\r\n warmupHeaders.set(\"accept\", \"text/event-stream\");\r\n\r\n const warmupInit: RequestInit = {\r\n ...prepared.init,\r\n method: prepared.init.method ?? \"POST\",\r\n headers: warmupHeaders,\r\n body: warmupBody,\r\n };\r\n\r\n const warmupDebugContext = startAntigravityDebugRequest({\r\n originalUrl: warmupUrl,\r\n resolvedUrl: warmupUrl,\r\n method: warmupInit.method,\r\n headers: warmupHeaders,\r\n body: warmupBody,\r\n streaming: true,\r\n projectId,\r\n });\r\n\r\n try {\r\n pushDebug(\"thinking-warmup: start\");\r\n const warmupResponse = await fetch(warmupUrl, warmupInit);\r\n const transformed = await transformAntigravityResponse(\r\n warmupResponse,\r\n true,\r\n warmupDebugContext,\r\n prepared.requestedModel,\r\n projectId,\r\n warmupUrl,\r\n prepared.effectiveModel,\r\n prepared.sessionId,\r\n );\r\n await transformed.text();\r\n markWarmupSuccess(prepared.sessionId);\r\n pushDebug(\"thinking-warmup: done\");\r\n } catch (error) {\r\n clearWarmupAttempt(prepared.sessionId);\r\n pushDebug(\r\n `thinking-warmup: failed ${error instanceof Error ? error.message : String(error)}`,\r\n );\r\n }\r\n };\r\n\r\n // Try endpoint fallbacks with single header style based on model suffix\r\n let shouldSwitchAccount = false;\r\n \r\n // Determine header style from model suffix:\r\n // - Models with antigravity- prefix -> use Antigravity quota\r\n // - Gemini models without explicit prefix -> follow cli_first\r\n // - Claude models -> always use Antigravity\r\n let headerStyle = preferredHeaderStyle;\r\n pushDebug(`headerStyle=${headerStyle} explicit=${explicitQuota}`);\r\n if (account.fingerprint) {\r\n pushDebug(`fingerprint: quotaUser=${account.fingerprint.quotaUser} deviceId=${account.fingerprint.deviceId.slice(0, 8)}...`);\r\n }\r\n \r\n // Check if this header style is rate-limited for this account\r\n if (accountManager.isRateLimitedForHeaderStyle(account, family, headerStyle, model)) {\r\n // Antigravity-first fallback: exhaust antigravity across ALL accounts before gemini-cli\r\n if (allowQuotaFallback && family === \"gemini\" && headerStyle === \"antigravity\") {\r\n // Check if ANY other account has antigravity available\r\n if (accountManager.hasOtherAccountWithAntigravityAvailable(account.index, family, model)) {\r\n // Switch to another account with antigravity (preserve antigravity priority)\r\n pushDebug(`antigravity rate-limited on account ${account.index}, but available on other accounts. Switching.`);\r\n shouldSwitchAccount = true;\r\n } else {\r\n // All accounts exhausted antigravity - fall back to gemini-cli on this account\r\n const alternateStyle = accountManager.getAvailableHeaderStyle(account, family, model);\r\n const fallbackStyle = resolveQuotaFallbackHeaderStyle({\r\n family,\r\n headerStyle,\r\n alternateStyle,\r\n });\r\n if (fallbackStyle) {\r\n await showToast(\r\n `Antigravity quota exhausted on all accounts. Using Gemini CLI quota.`,\r\n \"warning\"\r\n );\r\n headerStyle = fallbackStyle;\r\n pushDebug(`all-accounts antigravity exhausted, quota fallback: ${headerStyle}`);\r\n } else {\r\n shouldSwitchAccount = true;\r\n }\r\n }\r\n } else if (allowQuotaFallback && family === \"gemini\") {\r\n // gemini-cli rate-limited - try alternate style (antigravity) on same account\r\n const alternateStyle = accountManager.getAvailableHeaderStyle(account, family, model);\r\n const fallbackStyle = resolveQuotaFallbackHeaderStyle({\r\n family,\r\n headerStyle,\r\n alternateStyle,\r\n });\r\n if (fallbackStyle) {\r\n const quotaName = headerStyle === \"gemini-cli\" ? \"Gemini CLI\" : \"Antigravity\";\r\n const altQuotaName = fallbackStyle === \"gemini-cli\" ? \"Gemini CLI\" : \"Antigravity\";\r\n await showToast(\r\n `${quotaName} quota exhausted, using ${altQuotaName} quota`,\r\n \"warning\"\r\n );\r\n headerStyle = fallbackStyle;\r\n pushDebug(`quota fallback: ${headerStyle}`);\r\n } else {\r\n shouldSwitchAccount = true;\r\n }\r\n } else {\r\n shouldSwitchAccount = true;\r\n }\r\n }\r\n \r\n while (!shouldSwitchAccount) {\r\n \r\n // Flag to force thinking recovery on retry after API error\r\n let forceThinkingRecovery = false;\r\n \r\n // Track if token was consumed (for hybrid strategy refund on error)\r\n let tokenConsumed = false;\r\n \r\n // Track capacity retries per endpoint to prevent infinite loops\r\n let capacityRetryCount = 0;\r\n let lastEndpointIndex = -1;\r\n \r\n for (let i = 0; i < ANTIGRAVITY_ENDPOINT_FALLBACKS.length; i++) {\r\n // Reset capacity retry counter when switching to a new endpoint\r\n if (i !== lastEndpointIndex) {\r\n capacityRetryCount = 0;\r\n lastEndpointIndex = i;\r\n }\r\n\r\n const currentEndpoint = ANTIGRAVITY_ENDPOINT_FALLBACKS[i];\r\n\r\n // Skip sandbox endpoints for Gemini CLI models - they only work with Antigravity quota\r\n // Gemini CLI models must use production endpoint (cloudcode-pa.googleapis.com)\r\n if (headerStyle === \"gemini-cli\" && currentEndpoint !== ANTIGRAVITY_ENDPOINT_PROD) {\r\n pushDebug(`Skipping sandbox endpoint ${currentEndpoint} for gemini-cli headerStyle`);\r\n continue;\r\n }\r\n\r\n try {\r\n const prepared = prepareAntigravityRequest(\r\n input,\r\n init,\r\n accessToken,\r\n projectContext.effectiveProjectId,\r\n currentEndpoint,\r\n headerStyle,\r\n forceThinkingRecovery,\r\n {\r\n claudeToolHardening: config.claude_tool_hardening,\r\n claudePromptAutoCaching: config.claude_prompt_auto_caching,\r\n fingerprint: account.fingerprint,\r\n },\r\n );\r\n\r\n const originalUrl = toUrlString(input);\r\n const resolvedUrl = toUrlString(prepared.request);\r\n pushDebug(`endpoint=${currentEndpoint}`);\r\n pushDebug(`resolved=${resolvedUrl}`);\r\n const debugContext = startAntigravityDebugRequest({\r\n originalUrl,\r\n resolvedUrl,\r\n method: prepared.init.method,\r\n headers: prepared.init.headers,\r\n body: prepared.init.body,\r\n streaming: prepared.streaming,\r\n projectId: projectContext.effectiveProjectId,\r\n });\r\n\r\n const createFailureContext = (failureResponse: Response): FailureContext => ({\r\n response: failureResponse,\r\n streaming: prepared.streaming,\r\n debugContext,\r\n requestedModel: prepared.requestedModel,\r\n projectId: prepared.projectId,\r\n endpoint: prepared.endpoint,\r\n effectiveModel: prepared.effectiveModel,\r\n sessionId: prepared.sessionId,\r\n toolDebugMissing: prepared.toolDebugMissing,\r\n toolDebugSummary: prepared.toolDebugSummary,\r\n toolDebugPayload: prepared.toolDebugPayload,\r\n });\r\n\r\n await runThinkingWarmup(prepared, projectContext.effectiveProjectId);\r\n\r\n if (config.request_jitter_max_ms > 0) {\r\n const jitterMs = Math.floor(Math.random() * config.request_jitter_max_ms);\r\n if (jitterMs > 0) {\r\n await sleep(jitterMs, abortSignal);\r\n }\r\n }\r\n\r\n // Consume token for hybrid strategy\r\n // Refunded later if request fails (429 or network error)\r\n if (config.account_selection_strategy === 'hybrid') {\r\n tokenConsumed = getTokenTracker().consume(account.index);\r\n }\r\n\r\n const response = await fetch(prepared.request, prepared.init);\r\n pushDebug(`status=${response.status} ${response.statusText}`);\r\n\r\n\r\n\r\n\r\n // Handle 429 rate limit (or Service Overloaded) with improved logic\r\n if (response.status === 429 || response.status === 503 || response.status === 529) {\r\n // Refund token on rate limit\r\n if (tokenConsumed) {\r\n getTokenTracker().refund(account.index);\r\n tokenConsumed = false;\r\n }\r\n\r\n const defaultRetryMs = (config.default_retry_after_seconds ?? 60) * 1000;\r\n const maxBackoffMs = (config.max_backoff_seconds ?? 60) * 1000;\r\n const headerRetryMs = retryAfterMsFromResponse(response, defaultRetryMs);\r\n const bodyInfo = await extractRetryInfoFromBody(response);\r\n const serverRetryMs = bodyInfo.retryDelayMs ?? headerRetryMs;\r\n\r\n // [Enhanced Parsing] Pass status to handling logic\r\n const rateLimitReason = parseRateLimitReason(bodyInfo.reason, bodyInfo.message, response.status);\r\n\r\n // STRATEGY 1: CAPACITY / SERVER ERROR (Transient)\r\n // Goal: Wait and Retry SAME Account. DO NOT LOCK.\r\n // We handle this FIRST to avoid calling getRateLimitBackoff() and polluting the global rate limit state for transient errors.\r\n if (rateLimitReason === \"MODEL_CAPACITY_EXHAUSTED\" || rateLimitReason === \"SERVER_ERROR\") {\r\n // Exponential backoff with jitter for capacity errors: 1s \u2192 2s \u2192 4s \u2192 8s (max)\r\n // Matches Antigravity-Manager's ExponentialBackoff(1s, 8s)\r\n const baseDelayMs = 1000;\r\n const maxDelayMs = 8000;\r\n const exponentialDelay = Math.min(baseDelayMs * Math.pow(2, capacityRetryCount), maxDelayMs);\r\n // Add \u00B110% jitter to prevent thundering herd\r\n const jitter = exponentialDelay * (0.9 + Math.random() * 0.2);\r\n const waitMs = Math.round(jitter);\r\n const waitSec = Math.round(waitMs / 1000);\r\n \r\n pushDebug(`Server busy (${rateLimitReason}) on account ${account.index}, exponential backoff ${waitMs}ms (attempt ${capacityRetryCount + 1})`);\r\n\r\n await showToast(\r\n `\u23F3 Server busy (${response.status}). Retrying in ${waitSec}s...`,\r\n \"warning\",\r\n );\r\n \r\n await sleep(waitMs, abortSignal);\r\n \r\n // CRITICAL FIX: Decrement i so that the loop 'continue' retries the SAME endpoint index\r\n // (i++ in the loop will bring it back to the current index)\r\n // But limit retries to prevent infinite loops (Greptile feedback)\r\n if (capacityRetryCount < 3) {\r\n capacityRetryCount++;\r\n i -= 1;\r\n continue; \r\n } else {\r\n pushDebug(`Max capacity retries (3) exhausted for endpoint ${currentEndpoint}, regenerating fingerprint...`);\r\n // Regenerate fingerprint to get fresh device identity before trying next endpoint\r\n const newFingerprint = accountManager.regenerateAccountFingerprint(account.index);\r\n if (newFingerprint) {\r\n pushDebug(`Fingerprint regenerated for account ${account.index}`);\r\n }\r\n continue;\r\n }\r\n }\r\n\r\n // STRATEGY 2: RATE LIMIT EXCEEDED (RPM) / QUOTA EXHAUSTED / UNKNOWN\r\n // Goal: Lock and Rotate (Standard Logic)\r\n \r\n // Only now do we call getRateLimitBackoff, which increments the global failure tracker\r\n const quotaKey = headerStyleToQuotaKey(headerStyle, family);\r\n const { attempt, delayMs, isDuplicate } = getRateLimitBackoff(account.index, quotaKey, serverRetryMs);\r\n \r\n // Calculate potential backoffs\r\n const smartBackoffMs = calculateBackoffMs(rateLimitReason, account.consecutiveFailures ?? 0, serverRetryMs);\r\n const effectiveDelayMs = Math.max(delayMs, smartBackoffMs);\r\n\r\n pushDebug(\r\n `429 idx=${account.index} email=${account.email ?? \"\"} family=${family} delayMs=${effectiveDelayMs} attempt=${attempt} reason=${rateLimitReason}`,\r\n );\r\n if (bodyInfo.message) {\r\n pushDebug(`429 message=${bodyInfo.message}`);\r\n }\r\n if (bodyInfo.quotaResetTime) {\r\n pushDebug(`429 quotaResetTime=${bodyInfo.quotaResetTime}`);\r\n }\r\n if (bodyInfo.reason) {\r\n pushDebug(`429 reason=${bodyInfo.reason}`);\r\n }\r\n\r\n logRateLimitEvent(\r\n account.index,\r\n account.email,\r\n family,\r\n response.status,\r\n effectiveDelayMs,\r\n bodyInfo,\r\n );\r\n\r\n await logResponseBody(debugContext, response, 429);\r\n\r\n getHealthTracker().recordRateLimit(account.index);\r\n\r\n const accountLabel = account.email || `Account ${account.index + 1}`;\r\n\r\n // Progressive retry for standard 429s: 1st 429 \u2192 1s then switch (if enabled) or retry same\r\n if (attempt === 1 && rateLimitReason !== \"QUOTA_EXHAUSTED\") {\r\n await showToast(`Rate limited. Quick retry in 1s...`, \"warning\");\r\n await sleep(FIRST_RETRY_DELAY_MS, abortSignal);\r\n \r\n // CacheFirst mode: wait for same account if within threshold (preserves prompt cache)\r\n if (config.scheduling_mode === 'cache_first') {\r\n const maxCacheFirstWaitMs = config.max_cache_first_wait_seconds * 1000;\r\n // effectiveDelayMs is the backoff calculated for this account\r\n if (effectiveDelayMs <= maxCacheFirstWaitMs) {\r\n pushDebug(`cache_first: waiting ${effectiveDelayMs}ms for same account to recover`);\r\n await showToast(`\u23F3 Waiting ${Math.ceil(effectiveDelayMs / 1000)}s for same account (prompt cache preserved)...`, \"info\");\r\n accountManager.markRateLimitedWithReason(account, family, headerStyle, model, rateLimitReason, serverRetryMs);\r\n await sleep(effectiveDelayMs, abortSignal);\r\n // Retry same endpoint after wait\r\n i -= 1;\r\n continue;\r\n }\r\n // Wait time exceeds threshold, fall through to switch\r\n pushDebug(`cache_first: wait ${effectiveDelayMs}ms exceeds max ${maxCacheFirstWaitMs}ms, switching account`);\r\n }\r\n \r\n if (config.switch_on_first_rate_limit && accountCount > 1) {\r\n accountManager.markRateLimitedWithReason(account, family, headerStyle, model, rateLimitReason, serverRetryMs, config.failure_ttl_seconds * 1000);\r\n shouldSwitchAccount = true;\r\n break;\r\n }\r\n \r\n // Same endpoint retry for first RPM hit\r\n i -= 1; \r\n continue;\r\n }\r\n\r\n accountManager.markRateLimitedWithReason(account, family, headerStyle, model, rateLimitReason, serverRetryMs, config.failure_ttl_seconds * 1000);\r\n\r\n accountManager.requestSaveToDisk();\r\n\r\n // For Gemini, preserve preferred quota across accounts before fallback\r\n if (family === \"gemini\") {\r\n if (headerStyle === \"antigravity\") {\r\n // Check if any other account has Antigravity quota for this model\r\n if (hasOtherAccountWithAntigravity(account)) {\r\n pushDebug(`antigravity exhausted on account ${account.index}, but available on others. Switching account.`);\r\n await showToast(`Rate limited again. Switching account in 5s...`, \"warning\");\r\n await sleep(SWITCH_ACCOUNT_DELAY_MS, abortSignal);\r\n shouldSwitchAccount = true;\r\n break;\r\n }\r\n\r\n // All accounts exhausted for Antigravity on THIS model.\r\n // Before falling back to gemini-cli, check if it's the last option (automatic fallback)\r\n if (allowQuotaFallback) {\r\n const alternateStyle = accountManager.getAvailableHeaderStyle(account, family, model);\r\n const fallbackStyle = resolveQuotaFallbackHeaderStyle({\r\n family,\r\n headerStyle,\r\n alternateStyle,\r\n });\r\n if (fallbackStyle) {\r\n const safeModelName = model || \"this model\";\r\n await showToast(\r\n `Antigravity quota exhausted for ${safeModelName}. Switching to Gemini CLI quota...`,\r\n \"warning\"\r\n );\r\n headerStyle = fallbackStyle;\r\n pushDebug(`quota fallback: ${headerStyle}`);\r\n continue;\r\n }\r\n }\r\n } else if (headerStyle === \"gemini-cli\") {\r\n if (allowQuotaFallback) {\r\n const alternateStyle = accountManager.getAvailableHeaderStyle(account, family, model);\r\n const fallbackStyle = resolveQuotaFallbackHeaderStyle({\r\n family,\r\n headerStyle,\r\n alternateStyle,\r\n });\r\n if (fallbackStyle) {\r\n const safeModelName = model || \"this model\";\r\n await showToast(\r\n `Gemini CLI quota exhausted for ${safeModelName}. Switching to Antigravity quota...`,\r\n \"warning\"\r\n );\r\n headerStyle = fallbackStyle;\r\n pushDebug(`quota fallback: ${headerStyle}`);\r\n continue;\r\n }\r\n }\r\n }\r\n }\r\n\r\n const quotaName = headerStyle === \"antigravity\" ? \"Antigravity\" : \"Gemini CLI\";\r\n\r\n if (accountCount > 1) {\r\n const quotaMsg = bodyInfo.quotaResetTime \r\n ? ` (quota resets ${bodyInfo.quotaResetTime})`\r\n : ``;\r\n await showToast(`Rate limited again. Switching account in 5s...${quotaMsg}`, \"warning\");\r\n await sleep(SWITCH_ACCOUNT_DELAY_MS, abortSignal);\r\n } else {\r\n // Single account: exponential backoff (1s, 2s, 4s, 8s... max 60s)\r\n const expBackoffMs = Math.min(FIRST_RETRY_DELAY_MS * Math.pow(2, attempt - 1), 60000);\r\n const expBackoffFormatted = expBackoffMs >= 1000 ? `${Math.round(expBackoffMs / 1000)}s` : `${expBackoffMs}ms`;\r\n await showToast(`Rate limited. Retrying in ${expBackoffFormatted} (attempt ${attempt})...`, \"warning\");\r\n await sleep(expBackoffMs, abortSignal);\r\n }\r\n\r\n lastFailure = createFailureContext(response);\r\n shouldSwitchAccount = true;\r\n break;\r\n }\r\n\r\n // Success - reset rate limit backoff state for this quota\r\n const quotaKey = headerStyleToQuotaKey(headerStyle, family);\r\n resetRateLimitState(account.index, quotaKey);\r\n resetAccountFailureState(account.index);\r\n\r\n if (response.status === 403) {\r\n const errorBodyText = await response.clone().text().catch(() => \"\");\r\n const extracted = extractVerificationErrorDetails(errorBodyText);\r\n\r\n if (extracted.validationRequired) {\r\n const verificationReason = extracted.message ?? \"Google requires account verification.\";\r\n const cooldownMs = 10 * 60 * 1000;\r\n\r\n accountManager.markAccountVerificationRequired(account.index, verificationReason, extracted.verifyUrl);\r\n accountManager.markAccountCoolingDown(account, cooldownMs, \"validation-required\");\r\n accountManager.markRateLimited(account, cooldownMs, family, headerStyle, model);\r\n\r\n const label = account.email || `Account ${account.index + 1}`;\r\n if (accountManager.shouldShowAccountToast(account.index, 60000)) {\r\n await showToast(\r\n `\u26A0 ${label} needs verification. Run 'opencode auth login' and use Verify accounts.`,\r\n \"warning\",\r\n );\r\n accountManager.markToastShown(account.index);\r\n }\r\n\r\n pushDebug(`verification-required: disabled account ${account.index}`);\r\n getHealthTracker().recordFailure(account.index);\r\n\r\n lastFailure = createFailureContext(response);\r\n shouldSwitchAccount = true;\r\n break;\r\n }\r\n }\r\n\r\n const shouldRetryEndpoint = (\r\n response.status === 403 ||\r\n response.status === 404 ||\r\n response.status >= 500\r\n );\r\n\r\n if (shouldRetryEndpoint && i < ANTIGRAVITY_ENDPOINT_FALLBACKS.length - 1) {\r\n await logResponseBody(debugContext, response, response.status);\r\n lastFailure = createFailureContext(response);\r\n continue;\r\n }\r\n\r\n // Success or non-retryable error - return the response\r\n if (response.ok) {\r\n account.consecutiveFailures = 0;\r\n getHealthTracker().recordSuccess(account.index);\r\n accountManager.markAccountUsed(account.index);\r\n \r\n void triggerAsyncQuotaRefreshForAccount(\r\n accountManager,\r\n account.index,\r\n client,\r\n providerId,\r\n config.quota_refresh_interval_minutes,\r\n );\r\n }\r\n logAntigravityDebugResponse(debugContext, response, {\r\n note: response.ok ? \"Success\" : `Error ${response.status}`,\r\n });\r\n if (response.ok && !prepared.streaming) {\r\n await logResponseBody(debugContext, response, response.status);\r\n }\r\n if (!response.ok) {\r\n await logResponseBody(debugContext, response, response.status);\r\n \r\n // Handle 400 \"Prompt too long\" with synthetic response to avoid session lock\r\n if (response.status === 400) {\r\n const cloned = response.clone();\r\n const bodyText = await cloned.text();\r\n if (bodyText.includes(\"Prompt is too long\") || bodyText.includes(\"prompt_too_long\")) {\r\n await showToast(\r\n \"Context too long - use /compact to reduce size\",\r\n \"warning\"\r\n );\r\n const errorMessage = `[Antigravity Error] Context is too long for this model.\\n\\nPlease use /compact to reduce context size, then retry your request.\\n\\nAlternatively, you can:\\n- Use /clear to start fresh\\n- Use /undo to remove recent messages\\n- Switch to a model with larger context window`;\r\n return createSyntheticErrorResponse(errorMessage, prepared.requestedModel);\r\n }\r\n }\r\n }\r\n \r\n // Empty response retry logic (ported from LLM-API-Key-Proxy)\r\n // For non-streaming responses, check if the response body is empty\r\n // and retry if so (up to config.empty_response_max_attempts times)\r\n if (response.ok && !prepared.streaming) {\r\n const maxAttempts = config.empty_response_max_attempts ?? 4;\r\n const retryDelayMs = config.empty_response_retry_delay_ms ?? 2000;\r\n \r\n // Clone to check body without consuming original\r\n const clonedForCheck = response.clone();\r\n const bodyText = await clonedForCheck.text();\r\n \r\n if (isEmptyResponseBody(bodyText)) {\r\n // Track empty response attempts per request\r\n const emptyAttemptKey = `${prepared.sessionId ?? \"none\"}:${prepared.effectiveModel ?? \"unknown\"}`;\r\n const currentAttempts = (emptyResponseAttempts.get(emptyAttemptKey) ?? 0) + 1;\r\n emptyResponseAttempts.set(emptyAttemptKey, currentAttempts);\r\n \r\n pushDebug(`empty-response: attempt ${currentAttempts}/${maxAttempts}`);\r\n \r\n if (currentAttempts < maxAttempts) {\r\n await showToast(\r\n `Empty response received. Retrying (${currentAttempts}/${maxAttempts})...`,\r\n \"warning\"\r\n );\r\n await sleep(retryDelayMs, abortSignal);\r\n continue; // Retry the endpoint loop\r\n }\r\n \r\n // Clean up and throw after max attempts\r\n emptyResponseAttempts.delete(emptyAttemptKey);\r\n throw new EmptyResponseError(\r\n \"antigravity\",\r\n prepared.effectiveModel ?? \"unknown\",\r\n currentAttempts,\r\n );\r\n }\r\n \r\n // Clean up successful attempt tracking\r\n const emptyAttemptKeyClean = `${prepared.sessionId ?? \"none\"}:${prepared.effectiveModel ?? \"unknown\"}`;\r\n emptyResponseAttempts.delete(emptyAttemptKeyClean);\r\n }\r\n \r\n const transformedResponse = await transformAntigravityResponse(\r\n response,\r\n prepared.streaming,\r\n debugContext,\r\n prepared.requestedModel,\r\n prepared.projectId,\r\n prepared.endpoint,\r\n prepared.effectiveModel,\r\n prepared.sessionId,\r\n prepared.toolDebugMissing,\r\n prepared.toolDebugSummary,\r\n prepared.toolDebugPayload,\r\n debugLines,\r\n );\r\n\r\n // Check for context errors and show appropriate toast\r\n const contextError = transformedResponse.headers.get(\"x-antigravity-context-error\");\r\n if (contextError) {\r\n if (contextError === \"prompt_too_long\") {\r\n await showToast(\r\n \"Context too long - use /compact to reduce size, or trim your request\",\r\n \"warning\"\r\n );\r\n } else if (contextError === \"tool_pairing\") {\r\n await showToast(\r\n \"Tool call/result mismatch - use /compact to fix, or /undo last message\",\r\n \"warning\"\r\n );\r\n }\r\n }\r\n\r\n return transformedResponse;\r\n } catch (error) {\r\n // Refund token on network/API error (only if consumed)\r\n if (tokenConsumed) {\r\n getTokenTracker().refund(account.index);\r\n tokenConsumed = false;\r\n }\r\n\r\n // Handle recoverable thinking errors - retry with forced recovery\r\n if (error instanceof Error && error.message === \"THINKING_RECOVERY_NEEDED\") {\r\n // Only retry once with forced recovery to avoid infinite loops\r\n if (!forceThinkingRecovery) {\r\n pushDebug(\"thinking-recovery: API error detected, retrying with forced recovery\");\r\n forceThinkingRecovery = true;\r\n i = -1; // Will become 0 after loop increment, restart endpoint loop\r\n continue;\r\n }\r\n \r\n // Already tried with forced recovery, give up and return error\r\n const recoveryError = error as any;\r\n const originalError = recoveryError.originalError || { error: { message: \"Thinking recovery triggered\" } };\r\n \r\n const recoveryMessage = `${originalError.error?.message || \"Session recovery failed\"}\\n\\n[RECOVERY] Thinking block corruption could not be resolved. Try starting a new session.`;\r\n \r\n return new Response(JSON.stringify({\r\n type: \"error\",\r\n error: {\r\n type: \"unrecoverable_error\",\r\n message: recoveryMessage\r\n }\r\n }), {\r\n status: 400,\r\n headers: { \"Content-Type\": \"application/json\" }\r\n });\r\n }\r\n\r\n if (i < ANTIGRAVITY_ENDPOINT_FALLBACKS.length - 1) {\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n continue;\r\n }\r\n\r\n // All endpoints failed for this account - track failure and try next account\r\n const { failures, shouldCooldown, cooldownMs } = trackAccountFailure(account.index);\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n if (shouldCooldown) {\r\n accountManager.markAccountCoolingDown(account, cooldownMs, \"network-error\");\r\n accountManager.markRateLimited(account, cooldownMs, family, headerStyle, model);\r\n pushDebug(`endpoint-error: cooldown ${cooldownMs}ms after ${failures} failures`);\r\n }\r\n shouldSwitchAccount = true;\r\n break;\r\n }\r\n }\r\n } // end headerStyleLoop\r\n \r\n if (shouldSwitchAccount) {\r\n // Avoid tight retry loops when there's only one account.\r\n if (accountCount <= 1) {\r\n if (lastFailure) {\r\n return transformAntigravityResponse(\r\n lastFailure.response,\r\n lastFailure.streaming,\r\n lastFailure.debugContext,\r\n lastFailure.requestedModel,\r\n lastFailure.projectId,\r\n lastFailure.endpoint,\r\n lastFailure.effectiveModel,\r\n lastFailure.sessionId,\r\n lastFailure.toolDebugMissing,\r\n lastFailure.toolDebugSummary,\r\n lastFailure.toolDebugPayload,\r\n debugLines,\r\n );\r\n }\r\n\r\n throw lastError || new Error(\"All Antigravity endpoints failed\");\r\n }\r\n\r\n continue;\r\n }\r\n\r\n // If we get here without returning, something went wrong\r\n if (lastFailure) {\r\n return transformAntigravityResponse(\r\n lastFailure.response,\r\n lastFailure.streaming,\r\n lastFailure.debugContext,\r\n lastFailure.requestedModel,\r\n lastFailure.projectId,\r\n lastFailure.endpoint,\r\n lastFailure.effectiveModel,\r\n lastFailure.sessionId,\r\n lastFailure.toolDebugMissing,\r\n lastFailure.toolDebugSummary,\r\n lastFailure.toolDebugPayload,\r\n debugLines,\r\n );\r\n }\r\n\r\n throw lastError || new Error(\"All Antigravity accounts failed\");\r\n }\r\n },\r\n };\r\n },\r\n methods: [\r\n {\r\n label: \"OAuth with Google (Antigravity)\",\r\n type: \"oauth\",\r\n authorize: async (inputs?: Record<string, string>) => {\r\n const isHeadless = !!(\r\n process.env.SSH_CONNECTION ||\r\n process.env.SSH_CLIENT ||\r\n process.env.SSH_TTY ||\r\n process.env.OPENCODE_HEADLESS\r\n );\r\n\r\n // CLI flow (`opencode auth login`) passes an inputs object.\r\n if (inputs) {\r\n const accounts: Array<Extract<AntigravityTokenExchangeResult, { type: \"success\" }>> = [];\r\n const noBrowser = inputs.noBrowser === \"true\" || inputs[\"no-browser\"] === \"true\";\r\n const useManualMode = noBrowser || shouldSkipLocalServer();\r\n\r\n // Check for existing accounts and prompt user for login mode\r\n let startFresh = true;\r\n let refreshAccountIndex: number | undefined;\r\n const existingStorage = await loadAccounts();\r\n if (existingStorage && existingStorage.accounts.length > 0) {\r\n let menuResult;\r\n while (true) {\r\n const now = Date.now();\r\n const existingAccounts = existingStorage.accounts.map((acc, idx) => {\r\n let status: 'active' | 'rate-limited' | 'expired' | 'verification-required' | 'unknown' = 'unknown';\r\n\r\n if (acc.verificationRequired) {\r\n status = 'verification-required';\r\n } else {\r\n const rateLimits = acc.rateLimitResetTimes;\r\n if (rateLimits) {\r\n const isRateLimited = Object.values(rateLimits).some(\r\n (resetTime) => typeof resetTime === 'number' && resetTime > now\r\n );\r\n if (isRateLimited) {\r\n status = 'rate-limited';\r\n } else {\r\n status = 'active';\r\n }\r\n } else {\r\n status = 'active';\r\n }\r\n\r\n if (acc.coolingDownUntil && acc.coolingDownUntil > now) {\r\n status = 'rate-limited';\r\n }\r\n }\r\n\r\n return {\r\n email: acc.email,\r\n index: idx,\r\n addedAt: acc.addedAt,\r\n lastUsed: acc.lastUsed,\r\n status,\r\n isCurrentAccount: idx === (existingStorage.activeIndex ?? 0),\r\n enabled: acc.enabled !== false,\r\n };\r\n });\r\n \r\n menuResult = await promptLoginMode(existingAccounts);\r\n\r\n if (menuResult.mode === \"check\") {\r\n console.log(\"\\n\uD83D\uDCCA Checking quotas for all accounts...\\n\");\r\n const results = await checkAccountsQuota(existingStorage.accounts, client, providerId);\r\n let storageUpdated = false;\r\n \r\n for (const res of results) {\r\n const label = res.email || `Account ${res.index + 1}`;\r\n const disabledStr = res.disabled ? \" (disabled)\" : \"\";\r\n console.log(`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`);\r\n console.log(` ${label}${disabledStr}`);\r\n console.log(`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`);\r\n \r\n if (res.status === \"error\") {\r\n console.log(` \u274C Error: ${res.error}\\n`);\r\n continue;\r\n }\r\n\r\n // ANSI color codes\r\n const colors = {\r\n red: '\\x1b[31m',\r\n orange: '\\x1b[33m', // Yellow/orange\r\n green: '\\x1b[32m',\r\n reset: '\\x1b[0m',\r\n };\r\n\r\n // Get color based on remaining percentage\r\n const getColor = (remaining?: number): string => {\r\n if (typeof remaining !== 'number') return colors.reset;\r\n if (remaining < 0.2) return colors.red;\r\n if (remaining < 0.6) return colors.orange;\r\n return colors.green;\r\n };\r\n\r\n // Helper to create colored progress bar\r\n const createProgressBar = (remaining?: number, width: number = 20): string => {\r\n if (typeof remaining !== 'number') return '\u2591'.repeat(width) + ' ???';\r\n const filled = Math.round(remaining * width);\r\n const empty = width - filled;\r\n const color = getColor(remaining);\r\n const bar = `${color}${'\u2588'.repeat(filled)}${colors.reset}${'\u2591'.repeat(empty)}`;\r\n const pct = `${color}${Math.round(remaining * 100)}%${colors.reset}`.padStart(4 + color.length + colors.reset.length);\r\n return `${bar} ${pct}`;\r\n };\r\n\r\n // Helper to format reset time with days support\r\n const formatReset = (resetTime?: string): string => {\r\n if (!resetTime) return '';\r\n const ms = Date.parse(resetTime) - Date.now();\r\n if (ms <= 0) return ' (resetting...)';\r\n \r\n const hours = ms / (1000 * 60 * 60);\r\n if (hours >= 24) {\r\n const days = Math.floor(hours / 24);\r\n const remainingHours = Math.floor(hours % 24);\r\n if (remainingHours > 0) {\r\n return ` (resets in ${days}d ${remainingHours}h)`;\r\n }\r\n return ` (resets in ${days}d)`;\r\n }\r\n return ` (resets in ${formatWaitTime(ms)})`;\r\n };\r\n\r\n // Display Gemini CLI Quota first (as requested - swap order)\r\n const hasGeminiCli = res.geminiCliQuota && res.geminiCliQuota.models.length > 0;\r\n console.log(`\\n \u250C\u2500 Gemini CLI Quota`);\r\n if (!hasGeminiCli) {\r\n const errorMsg = res.geminiCliQuota?.error || \"No Gemini CLI quota available\";\r\n console.log(` \u2502 \u2514\u2500 ${errorMsg}`);\r\n } else {\r\n const models = res.geminiCliQuota!.models;\r\n models.forEach((model, idx) => {\r\n const isLast = idx === models.length - 1;\r\n const connector = isLast ? \"\u2514\u2500\" : \"\u251C\u2500\";\r\n const bar = createProgressBar(model.remainingFraction);\r\n const reset = formatReset(model.resetTime);\r\n const modelName = model.modelId.padEnd(29);\r\n console.log(` \u2502 ${connector} ${modelName} ${bar}${reset}`);\r\n });\r\n }\r\n\r\n // Display Antigravity Quota second\r\n const hasAntigravity = res.quota && Object.keys(res.quota.groups).length > 0;\r\n console.log(` \u2502`);\r\n console.log(` \u2514\u2500 Antigravity Quota`);\r\n if (!hasAntigravity) {\r\n const errorMsg = res.quota?.error || \"No quota information available\";\r\n console.log(` \u2514\u2500 ${errorMsg}`);\r\n } else {\r\n const groups = res.quota!.groups;\r\n const groupEntries = [\r\n { name: \"Claude\", data: groups.claude },\r\n { name: \"Gemini 3 Pro\", data: groups[\"gemini-pro\"] },\r\n { name: \"Gemini 3 Flash\", data: groups[\"gemini-flash\"] },\r\n ].filter(g => g.data);\r\n \r\n groupEntries.forEach((g, idx) => {\r\n const isLast = idx === groupEntries.length - 1;\r\n const connector = isLast ? \"\u2514\u2500\" : \"\u251C\u2500\";\r\n const bar = createProgressBar(g.data!.remainingFraction);\r\n const reset = formatReset(g.data!.resetTime);\r\n const modelName = g.name.padEnd(29);\r\n console.log(` ${connector} ${modelName} ${bar}${reset}`);\r\n });\r\n }\r\n console.log(\"\");\r\n\r\n // Cache quota data for soft quota protection\r\n if (res.quota?.groups) {\r\n const acc = existingStorage.accounts[res.index];\r\n if (acc) {\r\n acc.cachedQuota = res.quota.groups;\r\n acc.cachedQuotaUpdatedAt = Date.now();\r\n storageUpdated = true;\r\n }\r\n }\r\n\r\n if (res.updatedAccount) {\r\n existingStorage.accounts[res.index] = {\r\n ...res.updatedAccount,\r\n cachedQuota: res.quota?.groups,\r\n cachedQuotaUpdatedAt: Date.now(),\r\n };\r\n storageUpdated = true;\r\n }\r\n }\r\n if (storageUpdated) {\r\n await saveAccounts(existingStorage);\r\n }\r\n console.log(\"\");\r\n continue;\r\n }\r\n\r\n if (menuResult.mode === \"manage\") {\r\n if (menuResult.toggleAccountIndex !== undefined) {\r\n const acc = existingStorage.accounts[menuResult.toggleAccountIndex];\r\n if (acc) {\r\n acc.enabled = acc.enabled === false;\r\n await saveAccounts(existingStorage);\r\n activeAccountManager?.setAccountEnabled(menuResult.toggleAccountIndex, acc.enabled);\r\n console.log(`\\nAccount ${acc.email || menuResult.toggleAccountIndex + 1} ${acc.enabled ? 'enabled' : 'disabled'}.\\n`);\r\n }\r\n }\r\n continue;\r\n }\r\n\r\n if (menuResult.mode === \"verify\" || menuResult.mode === \"verify-all\") {\r\n const verifyAll = menuResult.mode === \"verify-all\" || menuResult.verifyAll === true;\r\n\r\n if (verifyAll) {\r\n if (existingStorage.accounts.length === 0) {\r\n console.log(\"\\nNo accounts available to verify.\\n\");\r\n continue;\r\n }\r\n\r\n console.log(`\\nChecking verification status for ${existingStorage.accounts.length} account(s)...\\n`);\r\n\r\n let okCount = 0;\r\n let blockedCount = 0;\r\n let errorCount = 0;\r\n let storageUpdated = false;\r\n\r\n const blockedResults: Array<{ label: string; message: string; verifyUrl?: string }> = [];\r\n\r\n for (let i = 0; i < existingStorage.accounts.length; i++) {\r\n const account = existingStorage.accounts[i];\r\n if (!account) continue;\r\n\r\n const label = account.email || `Account ${i + 1}`;\r\n process.stdout.write(`- [${i + 1}/${existingStorage.accounts.length}] ${label} ... `);\r\n\r\n const verification = await verifyAccountAccess(account, client, providerId);\r\n if (verification.status === \"ok\") {\r\n const { changed, wasVerificationRequired } = clearStoredAccountVerificationRequired(account, true);\r\n if (changed) {\r\n storageUpdated = true;\r\n }\r\n activeAccountManager?.clearAccountVerificationRequired(i, wasVerificationRequired);\r\n okCount += 1;\r\n console.log(\"ok\");\r\n continue;\r\n }\r\n\r\n if (verification.status === \"blocked\") {\r\n const changed = markStoredAccountVerificationRequired(\r\n account,\r\n verification.message,\r\n verification.verifyUrl,\r\n );\r\n if (changed) {\r\n storageUpdated = true;\r\n }\r\n activeAccountManager?.markAccountVerificationRequired(i, verification.message, verification.verifyUrl);\r\n\r\n blockedCount += 1;\r\n console.log(\"needs verification\");\r\n const verifyUrl = verification.verifyUrl ?? account.verificationUrl;\r\n blockedResults.push({\r\n label,\r\n message: verification.message,\r\n verifyUrl,\r\n });\r\n continue;\r\n }\r\n\r\n errorCount += 1;\r\n console.log(`error (${verification.message})`);\r\n }\r\n\r\n if (storageUpdated) {\r\n await saveAccounts(existingStorage);\r\n }\r\n\r\n console.log(`\\nVerification summary: ${okCount} ready, ${blockedCount} need verification, ${errorCount} errors.`);\r\n\r\n if (blockedResults.length > 0) {\r\n console.log(\"\\nAccounts needing verification:\");\r\n for (const result of blockedResults) {\r\n console.log(`\\n- ${result.label}`);\r\n console.log(` ${result.message}`);\r\n if (result.verifyUrl) {\r\n console.log(` URL: ${result.verifyUrl}`);\r\n } else {\r\n console.log(\" URL: not provided by API response\");\r\n }\r\n }\r\n console.log(\"\");\r\n } else {\r\n console.log(\"\");\r\n }\r\n\r\n continue;\r\n }\r\n\r\n let verifyAccountIndex = menuResult.verifyAccountIndex;\r\n if (verifyAccountIndex === undefined) {\r\n verifyAccountIndex = await promptAccountIndexForVerification(existingAccounts);\r\n }\r\n\r\n if (verifyAccountIndex === undefined) {\r\n console.log(\"\\nVerification cancelled.\\n\");\r\n continue;\r\n }\r\n\r\n const account = existingStorage.accounts[verifyAccountIndex];\r\n if (!account) {\r\n console.log(`\\nAccount ${verifyAccountIndex + 1} not found.\\n`);\r\n continue;\r\n }\r\n\r\n const label = account.email || `Account ${verifyAccountIndex + 1}`;\r\n console.log(`\\nChecking verification status for ${label}...\\n`);\r\n\r\n const verification = await verifyAccountAccess(account, client, providerId);\r\n\r\n if (verification.status === \"ok\") {\r\n const { changed, wasVerificationRequired } = clearStoredAccountVerificationRequired(account, true);\r\n if (changed) {\r\n await saveAccounts(existingStorage);\r\n }\r\n activeAccountManager?.clearAccountVerificationRequired(verifyAccountIndex, wasVerificationRequired);\r\n\r\n if (wasVerificationRequired) {\r\n console.log(`\u2713 ${label} is ready for requests and has been re-enabled.\\n`);\r\n } else {\r\n console.log(`\u2713 ${label} is ready for requests.\\n`);\r\n }\r\n continue;\r\n }\r\n\r\n if (verification.status === \"blocked\") {\r\n const changed = markStoredAccountVerificationRequired(\r\n account,\r\n verification.message,\r\n verification.verifyUrl,\r\n );\r\n if (changed) {\r\n await saveAccounts(existingStorage);\r\n }\r\n activeAccountManager?.markAccountVerificationRequired(\r\n verifyAccountIndex,\r\n verification.message,\r\n verification.verifyUrl,\r\n );\r\n\r\n const verifyUrl = verification.verifyUrl ?? account.verificationUrl;\r\n console.log(`\u26A0 ${label} needs Google verification before it can be used.`);\r\n if (verification.message) {\r\n console.log(verification.message);\r\n }\r\n console.log(`${label} has been disabled until verification is completed.`);\r\n if (verifyUrl) {\r\n console.log(`\\nVerification URL:\\n${verifyUrl}\\n`);\r\n if (await promptOpenVerificationUrl()) {\r\n const opened = await openBrowser(verifyUrl);\r\n if (opened) {\r\n console.log(\"Opened verification URL in your browser.\\n\");\r\n } else {\r\n console.log(\"Could not open browser automatically. Please open the URL manually.\\n\");\r\n }\r\n }\r\n } else {\r\n console.log(\"No verification URL was returned. Try re-authenticating this account.\\n\");\r\n }\r\n continue;\r\n }\r\n\r\n console.log(`\u2717 ${label}: ${verification.message}\\n`);\r\n continue;\r\n }\r\n\r\n break;\r\n }\r\n \r\n if (menuResult.mode === \"cancel\") {\r\n return {\r\n url: \"\",\r\n instructions: \"Authentication cancelled\",\r\n method: \"auto\",\r\n callback: async () => ({ type: \"failed\", error: \"Authentication cancelled\" }),\r\n };\r\n }\r\n \r\n if (menuResult.deleteAccountIndex !== undefined) {\r\n const updatedAccounts = existingStorage.accounts.filter(\r\n (_, idx) => idx !== menuResult.deleteAccountIndex\r\n );\r\n // Use saveAccountsReplace to bypass merge (otherwise deleted account gets merged back)\r\n await saveAccountsReplace({\r\n version: 4,\r\n accounts: updatedAccounts,\r\n activeIndex: 0,\r\n activeIndexByFamily: { claude: 0, gemini: 0 },\r\n });\r\n // Sync in-memory state so deleted account stops being used immediately\r\n activeAccountManager?.removeAccountByIndex(menuResult.deleteAccountIndex);\r\n console.log(\"\\nAccount deleted.\\n\");\r\n\r\n if (updatedAccounts.length > 0) {\r\n const fallbackAccount = updatedAccounts[0];\r\n if (fallbackAccount?.refreshToken) {\r\n const fallbackResult = buildAuthSuccessFromStoredAccount(fallbackAccount);\r\n try {\r\n await client.auth.set({\r\n path: { id: providerId },\r\n body: { type: \"oauth\", refresh: fallbackResult.refresh, access: \"\", expires: 0 },\r\n });\r\n } catch (storeError) {\r\n log.error(\"Failed to update stored Antigravity OAuth credentials\", { error: String(storeError) });\r\n }\r\n\r\n const label = fallbackAccount.email || `Account ${1}`;\r\n return {\r\n url: \"\",\r\n instructions: `Account deleted. Using ${label} for future requests.`,\r\n method: \"auto\",\r\n callback: async () => fallbackResult,\r\n };\r\n }\r\n }\r\n\r\n try {\r\n await client.auth.set({\r\n path: { id: providerId },\r\n body: { type: \"oauth\", refresh: \"\", access: \"\", expires: 0 },\r\n });\r\n } catch (storeError) {\r\n log.error(\"Failed to clear stored Antigravity OAuth credentials\", { error: String(storeError) });\r\n }\r\n\r\n return {\r\n url: \"\",\r\n instructions: \"All accounts deleted. Run `opencode auth login` to reauthenticate.\",\r\n method: \"auto\",\r\n callback: async () => ({\r\n type: \"failed\",\r\n error: \"All accounts deleted. Reauthentication required.\",\r\n }),\r\n };\r\n }\r\n\r\n if (menuResult.refreshAccountIndex !== undefined) {\r\n refreshAccountIndex = menuResult.refreshAccountIndex;\r\n const refreshEmail = existingStorage.accounts[refreshAccountIndex]?.email;\r\n console.log(`\\nRe-authenticating ${refreshEmail || 'account'}...\\n`);\r\n startFresh = false;\r\n }\r\n \r\n if (menuResult.deleteAll) {\r\n await clearAccounts();\r\n console.log(\"\\nAll accounts deleted.\\n\");\r\n startFresh = true;\r\n try {\r\n await client.auth.set({\r\n path: { id: providerId },\r\n body: { type: \"oauth\", refresh: \"\", access: \"\", expires: 0 },\r\n });\r\n } catch (storeError) {\r\n log.error(\"Failed to clear stored Antigravity OAuth credentials\", { error: String(storeError) });\r\n }\r\n } else {\r\n startFresh = menuResult.mode === \"fresh\";\r\n }\r\n \r\n if (startFresh && !menuResult.deleteAll) {\r\n console.log(\"\\nStarting fresh - existing accounts will be replaced.\\n\");\r\n } else if (!startFresh) {\r\n console.log(\"\\nAdding to existing accounts.\\n\");\r\n }\r\n }\r\n\r\n while (accounts.length < MAX_OAUTH_ACCOUNTS) {\r\n console.log(`\\n=== Antigravity OAuth (Account ${accounts.length + 1}) ===`);\r\n\r\n const projectId = await promptProjectId();\r\n\r\n const result = await (async (): Promise<AntigravityTokenExchangeResult> => {\r\n const authorization = await authorizeAntigravity(projectId);\r\n const fallbackState = getStateFromAuthorizationUrl(authorization.url);\r\n\r\n console.log(\"\\nOAuth URL:\\n\" + authorization.url + \"\\n\");\r\n\r\n if (useManualMode) {\r\n const browserOpened = await openBrowser(authorization.url);\r\n if (!browserOpened) {\r\n console.log(\"Could not open browser automatically.\");\r\n console.log(\"Please open the URL above manually in your local browser.\\n\");\r\n }\r\n return promptManualOAuthInput(fallbackState);\r\n }\r\n\r\n let listener: OAuthListener | null = null;\r\n if (!isHeadless) {\r\n try {\r\n listener = await startOAuthListener();\r\n } catch {\r\n listener = null;\r\n }\r\n }\r\n\r\n if (!isHeadless) {\r\n await openBrowser(authorization.url);\r\n }\r\n\r\n if (listener) {\r\n try {\r\n const SOFT_TIMEOUT_MS = 30000;\r\n const callbackPromise = listener.waitForCallback();\r\n const timeoutPromise = new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(new Error(\"SOFT_TIMEOUT\")), SOFT_TIMEOUT_MS)\r\n );\r\n\r\n let callbackUrl: URL;\r\n try {\r\n callbackUrl = await Promise.race([callbackPromise, timeoutPromise]);\r\n } catch (err) {\r\n if (err instanceof Error && err.message === \"SOFT_TIMEOUT\") {\r\n console.log(\"\\n\u23F3 Automatic callback not received after 30 seconds.\");\r\n console.log(\"You can paste the redirect URL manually.\\n\");\r\n console.log(\"OAuth URL (in case you need it again):\");\r\n console.log(authorization.url + \"\\n\");\r\n \r\n try {\r\n await listener.close();\r\n } catch {}\r\n \r\n return promptManualOAuthInput(fallbackState);\r\n }\r\n throw err;\r\n }\r\n\r\n const params = extractOAuthCallbackParams(callbackUrl);\r\n if (!params) {\r\n return { type: \"failed\", error: \"Missing code or state in callback URL\" };\r\n }\r\n\r\n return exchangeAntigravity(params.code, params.state);\r\n } catch (error) {\r\n if (error instanceof Error && error.message !== \"SOFT_TIMEOUT\") {\r\n return {\r\n type: \"failed\",\r\n error: error.message,\r\n };\r\n }\r\n return {\r\n type: \"failed\",\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n };\r\n } finally {\r\n try {\r\n await listener.close();\r\n } catch {}\r\n }\r\n }\r\n\r\n return promptManualOAuthInput(fallbackState);\r\n })();\r\n\r\n if (result.type === \"failed\") {\r\n if (accounts.length === 0) {\r\n return {\r\n url: \"\",\r\n instructions: `Authentication failed: ${result.error}`,\r\n method: \"auto\",\r\n callback: async () => result,\r\n };\r\n }\r\n\r\n console.warn(\r\n `[opencode-antigravity-auth] Skipping failed account ${accounts.length + 1}: ${result.error}`,\r\n );\r\n break;\r\n }\r\n\r\n accounts.push(result);\r\n\r\n try {\r\n await client.tui.showToast({\r\n body: {\r\n message: `Account ${accounts.length} authenticated${result.email ? ` (${result.email})` : \"\"}`,\r\n variant: \"success\",\r\n },\r\n });\r\n } catch {\r\n }\r\n\r\n try {\r\n if (refreshAccountIndex !== undefined) {\r\n const currentStorage = await loadAccounts();\r\n if (currentStorage) {\r\n const updatedAccounts = [...currentStorage.accounts];\r\n const parts = parseRefreshParts(result.refresh);\r\n if (parts.refreshToken) {\r\n updatedAccounts[refreshAccountIndex] = {\r\n email: result.email ?? updatedAccounts[refreshAccountIndex]?.email,\r\n refreshToken: parts.refreshToken,\r\n projectId: parts.projectId ?? updatedAccounts[refreshAccountIndex]?.projectId,\r\n managedProjectId: parts.managedProjectId ?? updatedAccounts[refreshAccountIndex]?.managedProjectId,\r\n addedAt: updatedAccounts[refreshAccountIndex]?.addedAt ?? Date.now(),\r\n lastUsed: Date.now(),\r\n };\r\n await saveAccounts({\r\n version: 4,\r\n accounts: updatedAccounts,\r\n activeIndex: currentStorage.activeIndex,\r\n activeIndexByFamily: currentStorage.activeIndexByFamily,\r\n });\r\n }\r\n }\r\n } else {\r\n const isFirstAccount = accounts.length === 1;\r\n await persistAccountPool([result], isFirstAccount && startFresh);\r\n }\r\n } catch {\r\n }\r\n\r\n if (refreshAccountIndex !== undefined) {\r\n break;\r\n }\r\n\r\n if (accounts.length >= MAX_OAUTH_ACCOUNTS) {\r\n break;\r\n }\r\n\r\n // Get the actual deduplicated account count from storage for the prompt\r\n let currentAccountCount = accounts.length;\r\n try {\r\n const currentStorage = await loadAccounts();\r\n if (currentStorage) {\r\n currentAccountCount = currentStorage.accounts.length;\r\n }\r\n } catch {\r\n // Fall back to accounts.length if we can't read storage\r\n }\r\n\r\n const addAnother = await promptAddAnotherAccount(currentAccountCount);\r\n if (!addAnother) {\r\n break;\r\n }\r\n }\r\n\r\n const primary = accounts[0];\r\n if (!primary) {\r\n return {\r\n url: \"\",\r\n instructions: \"Authentication cancelled\",\r\n method: \"auto\",\r\n callback: async () => ({ type: \"failed\", error: \"Authentication cancelled\" }),\r\n };\r\n }\r\n\r\n let actualAccountCount = accounts.length;\r\n try {\r\n const finalStorage = await loadAccounts();\r\n if (finalStorage) {\r\n actualAccountCount = finalStorage.accounts.length;\r\n }\r\n } catch {\r\n }\r\n\r\n const successMessage = refreshAccountIndex !== undefined\r\n ? `Token refreshed successfully.`\r\n : `Multi-account setup complete (${actualAccountCount} account(s)).`;\r\n\r\n return {\r\n url: \"\",\r\n instructions: successMessage,\r\n method: \"auto\",\r\n callback: async (): Promise<AntigravityTokenExchangeResult> => primary,\r\n };\r\n }\r\n\r\n // TUI flow (`/connect`) does not support per-account prompts.\r\n // Default to adding new accounts (non-destructive).\r\n // Users can run `opencode auth logout` first if they want a fresh start.\r\n const projectId = \"\";\r\n\r\n // Check existing accounts count for toast message\r\n const existingStorage = await loadAccounts();\r\n const existingCount = existingStorage?.accounts.length ?? 0;\r\n\r\n const useManualFlow = isHeadless || shouldSkipLocalServer();\r\n\r\n let listener: OAuthListener | null = null;\r\n if (!useManualFlow) {\r\n try {\r\n listener = await startOAuthListener();\r\n } catch {\r\n listener = null;\r\n }\r\n }\r\n\r\n const authorization = await authorizeAntigravity(projectId);\r\n const fallbackState = getStateFromAuthorizationUrl(authorization.url);\r\n\r\n if (!useManualFlow) {\r\n const browserOpened = await openBrowser(authorization.url);\r\n if (!browserOpened) {\r\n listener?.close().catch(() => {});\r\n listener = null;\r\n }\r\n }\r\n\r\n if (listener) {\r\n return {\r\n url: authorization.url,\r\n instructions:\r\n \"Complete sign-in in your browser. We'll automatically detect the redirect back to localhost.\",\r\n method: \"auto\",\r\n callback: async (): Promise<AntigravityTokenExchangeResult> => {\r\n const CALLBACK_TIMEOUT_MS = 30000;\r\n try {\r\n const callbackPromise = listener.waitForCallback();\r\n const timeoutPromise = new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(new Error(\"CALLBACK_TIMEOUT\")), CALLBACK_TIMEOUT_MS),\r\n );\r\n\r\n let callbackUrl: URL;\r\n try {\r\n callbackUrl = await Promise.race([callbackPromise, timeoutPromise]);\r\n } catch (err) {\r\n if (err instanceof Error && err.message === \"CALLBACK_TIMEOUT\") {\r\n return {\r\n type: \"failed\",\r\n error: \"Callback timeout - please use CLI with --no-browser flag for manual input\",\r\n };\r\n }\r\n throw err;\r\n }\r\n\r\n const params = extractOAuthCallbackParams(callbackUrl);\r\n if (!params) {\r\n return { type: \"failed\", error: \"Missing code or state in callback URL\" };\r\n }\r\n\r\n const result = await exchangeAntigravity(params.code, params.state);\r\n if (result.type === \"success\") {\r\n try {\r\n await persistAccountPool([result], false);\r\n } catch {\r\n }\r\n\r\n const newTotal = existingCount + 1;\r\n const toastMessage = existingCount > 0\r\n ? `Added account${result.email ? ` (${result.email})` : \"\"} - ${newTotal} total`\r\n : `Authenticated${result.email ? ` (${result.email})` : \"\"}`;\r\n\r\n try {\r\n await client.tui.showToast({\r\n body: {\r\n message: toastMessage,\r\n variant: \"success\",\r\n },\r\n });\r\n } catch {\r\n }\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n return {\r\n type: \"failed\",\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n };\r\n } finally {\r\n try {\r\n await listener.close();\r\n } catch {\r\n }\r\n }\r\n },\r\n };\r\n }\r\n\r\n return {\r\n url: authorization.url,\r\n instructions:\r\n \"Visit the URL above, complete OAuth, then paste either the full redirect URL or the authorization code.\",\r\n method: \"code\",\r\n callback: async (codeInput: string): Promise<AntigravityTokenExchangeResult> => {\r\n const params = parseOAuthCallbackInput(codeInput, fallbackState);\r\n if (\"error\" in params) {\r\n return { type: \"failed\", error: params.error };\r\n }\r\n\r\n const result = await exchangeAntigravity(params.code, params.state);\r\n if (result.type === \"success\") {\r\n try {\r\n // TUI flow adds to existing accounts (non-destructive)\r\n await persistAccountPool([result], false);\r\n } catch {\r\n // ignore\r\n }\r\n\r\n // Show appropriate toast message\r\n const newTotal = existingCount + 1;\r\n const toastMessage = existingCount > 0\r\n ? `Added account${result.email ? ` (${result.email})` : \"\"} - ${newTotal} total`\r\n : `Authenticated${result.email ? ` (${result.email})` : \"\"}`;\r\n\r\n try {\r\n await client.tui.showToast({\r\n body: {\r\n message: toastMessage,\r\n variant: \"success\",\r\n },\r\n });\r\n } catch {\r\n // TUI may not be available\r\n }\r\n }\r\n\r\n return result;\r\n },\r\n };\r\n },\r\n },\r\n {\r\n label: \"Manually enter API Key\",\r\n type: \"api\",\r\n },\r\n ],\r\n },\r\n };\r\n};\r\n\r\nexport const AntigravityCLIOAuthPlugin = createAntigravityPlugin(ANTIGRAVITY_PROVIDER_ID);\r\nexport const GoogleOAuthPlugin = AntigravityCLIOAuthPlugin;\r\n\r\nfunction toUrlString(value: RequestInfo): string {\r\n if (typeof value === \"string\") {\r\n return value;\r\n }\r\n const candidate = (value as Request).url;\r\n if (candidate) {\r\n return candidate;\r\n }\r\n return value.toString();\r\n}\r\n\r\nfunction toWarmupStreamUrl(value: RequestInfo): string {\r\n const urlString = toUrlString(value);\r\n try {\r\n const url = new URL(urlString);\r\n if (!url.pathname.includes(\":streamGenerateContent\")) {\r\n url.pathname = url.pathname.replace(\":generateContent\", \":streamGenerateContent\");\r\n }\r\n url.searchParams.set(\"alt\", \"sse\");\r\n return url.toString();\r\n } catch {\r\n return urlString;\r\n }\r\n}\r\n\r\nfunction extractModelFromUrl(urlString: string): string | null {\r\n const match = urlString.match(/\\/models\\/([^:\\/?]+)(?::\\w+)?/);\r\n return match?.[1] ?? null;\r\n}\r\n\r\nfunction extractModelFromUrlWithSuffix(urlString: string): string | null {\r\n const match = urlString.match(/\\/models\\/([^:\\/\\?]+)/);\r\n return match?.[1] ?? null;\r\n}\r\n\r\nfunction getModelFamilyFromUrl(urlString: string): ModelFamily {\r\n const model = extractModelFromUrl(urlString);\r\n let family: ModelFamily = \"gemini\";\r\n if (model && model.includes(\"claude\")) {\r\n family = \"claude\";\r\n }\r\n if (isDebugEnabled()) {\r\n logModelFamily(urlString, model, family);\r\n }\r\n return family;\r\n}\r\n\r\nfunction resolveQuotaFallbackHeaderStyle(input: {\r\n family: ModelFamily;\r\n headerStyle: HeaderStyle;\r\n alternateStyle: HeaderStyle | null;\r\n}): HeaderStyle | null {\r\n if (input.family !== \"gemini\") {\r\n return null;\r\n }\r\n if (!input.alternateStyle || input.alternateStyle === input.headerStyle) {\r\n return null;\r\n }\r\n return input.alternateStyle;\r\n}\r\n\r\ntype HeaderRoutingDecision = {\r\n cliFirst: boolean;\r\n preferredHeaderStyle: HeaderStyle;\r\n explicitQuota: boolean;\r\n allowQuotaFallback: boolean;\r\n};\r\n\r\nfunction resolveHeaderRoutingDecision(\r\n urlString: string,\r\n family: ModelFamily,\r\n config: AntigravityConfig,\r\n): HeaderRoutingDecision {\r\n const cliFirst = getCliFirst(config);\r\n const preferredHeaderStyle = getHeaderStyleFromUrl(urlString, family, cliFirst);\r\n const explicitQuota = isExplicitQuotaFromUrl(urlString);\r\n return {\r\n cliFirst,\r\n preferredHeaderStyle,\r\n explicitQuota,\r\n allowQuotaFallback: family === \"gemini\",\r\n };\r\n}\r\n\r\nfunction getCliFirst(config: AntigravityConfig): boolean {\r\n return (config as AntigravityConfig & { cli_first?: boolean }).cli_first ?? false;\r\n}\r\n\r\nfunction getHeaderStyleFromUrl(\r\n urlString: string,\r\n family: ModelFamily,\r\n cliFirst: boolean = false,\r\n): HeaderStyle {\r\n if (family === \"claude\") {\r\n return \"antigravity\";\r\n }\r\n const modelWithSuffix = extractModelFromUrlWithSuffix(urlString);\r\n if (!modelWithSuffix) {\r\n return cliFirst ? \"gemini-cli\" : \"antigravity\";\r\n }\r\n const { quotaPreference } = resolveModelWithTier(modelWithSuffix, { cli_first: cliFirst });\r\n return quotaPreference ?? \"antigravity\";\r\n}\r\n\r\nfunction isExplicitQuotaFromUrl(urlString: string): boolean {\r\n const modelWithSuffix = extractModelFromUrlWithSuffix(urlString);\r\n if (!modelWithSuffix) {\r\n return false;\r\n }\r\n const { explicitQuota } = resolveModelWithTier(modelWithSuffix);\r\n return explicitQuota ?? false;\r\n}\r\n\r\nexport const __testExports = {\r\n getHeaderStyleFromUrl,\r\n resolveHeaderRoutingDecision,\r\n resolveQuotaFallbackHeaderStyle,\r\n};\r\n", "import { z } from \"zod\";\nexport function tool(input) {\n return input;\n}\ntool.schema = z;\n", "/**\r\n * Constants used for Antigravity OAuth flows and Cloud Code Assist API integration.\r\n */\r\nexport const ANTIGRAVITY_CLIENT_ID = \"1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com\";\r\n\r\n/**\r\n * Client secret issued for the Antigravity OAuth application.\r\n */\r\nexport const ANTIGRAVITY_CLIENT_SECRET = \"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\";\r\n\r\n/**\r\n * Scopes required for Antigravity integrations.\r\n */\r\nexport const ANTIGRAVITY_SCOPES: readonly string[] = [\r\n \"https://www.googleapis.com/auth/cloud-platform\",\r\n \"https://www.googleapis.com/auth/userinfo.email\",\r\n \"https://www.googleapis.com/auth/userinfo.profile\",\r\n \"https://www.googleapis.com/auth/cclog\",\r\n \"https://www.googleapis.com/auth/experimentsandconfigs\",\r\n];\r\n\r\n/**\r\n * OAuth redirect URI used by the local CLI callback server.\r\n */\r\nexport const ANTIGRAVITY_REDIRECT_URI = \"http://localhost:51121/oauth-callback\";\r\n\r\n/**\r\n * Root endpoints for the Antigravity API (in fallback order).\r\n * CLIProxy and Vibeproxy use the daily sandbox endpoint first,\r\n * then fallback to autopush and prod if needed.\r\n */\r\nexport const ANTIGRAVITY_ENDPOINT_DAILY = \"https://daily-cloudcode-pa.sandbox.googleapis.com\";\r\nexport const ANTIGRAVITY_ENDPOINT_AUTOPUSH = \"https://autopush-cloudcode-pa.sandbox.googleapis.com\";\r\nexport const ANTIGRAVITY_ENDPOINT_PROD = \"https://cloudcode-pa.googleapis.com\";\r\n\r\n/**\r\n * Endpoint fallback order (daily \u2192 autopush \u2192 prod).\r\n * Shared across request handling and project discovery to mirror CLIProxy behavior.\r\n */\r\nexport const ANTIGRAVITY_ENDPOINT_FALLBACKS = [\r\n ANTIGRAVITY_ENDPOINT_DAILY,\r\n ANTIGRAVITY_ENDPOINT_AUTOPUSH,\r\n ANTIGRAVITY_ENDPOINT_PROD,\r\n] as const;\r\n\r\n/**\r\n * Preferred endpoint order for project discovery (prod first, then fallbacks).\r\n * loadCodeAssist appears to be best supported on prod for managed project resolution.\r\n */\r\nexport const ANTIGRAVITY_LOAD_ENDPOINTS = [\r\n ANTIGRAVITY_ENDPOINT_PROD,\r\n ANTIGRAVITY_ENDPOINT_DAILY,\r\n ANTIGRAVITY_ENDPOINT_AUTOPUSH,\r\n] as const;\r\n\r\n/**\r\n * Primary endpoint to use (daily sandbox - same as CLIProxy/Vibeproxy).\r\n */\r\nexport const ANTIGRAVITY_ENDPOINT = ANTIGRAVITY_ENDPOINT_DAILY;\r\n\r\n/**\r\n * Gemini CLI endpoint (production).\r\n * Used for models without :antigravity suffix.\r\n * Same as opencode-gemini-auth's GEMINI_CODE_ASSIST_ENDPOINT.\r\n */\r\nexport const GEMINI_CLI_ENDPOINT = ANTIGRAVITY_ENDPOINT_PROD;\r\n\r\n/**\r\n * Hardcoded project id used when Antigravity does not return one (e.g., business/workspace accounts).\r\n */\r\nexport const ANTIGRAVITY_DEFAULT_PROJECT_ID = \"rising-fact-p41fc\";\r\n\r\nexport const ANTIGRAVITY_VERSION_FALLBACK = \"1.18.3\";\r\nlet antigravityVersion = ANTIGRAVITY_VERSION_FALLBACK;\r\nlet versionLocked = false;\r\n\r\nexport function getAntigravityVersion(): string { return antigravityVersion; }\r\n\r\n/**\r\n * Set the runtime Antigravity version. Can only be called once (at startup).\r\n * Subsequent calls are silently ignored to prevent accidental mutation.\r\n */\r\nexport function setAntigravityVersion(version: string): void {\r\n if (versionLocked) return;\r\n antigravityVersion = version;\r\n versionLocked = true;\r\n}\r\n\r\n/** @deprecated Use getAntigravityVersion() for runtime access. */\r\nexport const ANTIGRAVITY_VERSION = ANTIGRAVITY_VERSION_FALLBACK;\r\n\r\nexport function getAntigravityHeaders(): HeaderSet & { \"Client-Metadata\": string } {\r\n return {\r\n \"User-Agent\": `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Antigravity/${getAntigravityVersion()} Chrome/138.0.7204.235 Electron/37.3.1 Safari/537.36`,\r\n \"X-Goog-Api-Client\": \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\r\n \"Client-Metadata\": `{\"ideType\":\"ANTIGRAVITY\",\"platform\":\"${process.platform === \"win32\" ? \"WINDOWS\" : \"MACOS\"}\",\"pluginType\":\"GEMINI\"}`,\r\n };\r\n}\r\n\r\n/** @deprecated Use getAntigravityHeaders() for runtime access. */\r\nexport const ANTIGRAVITY_HEADERS = {\r\n \"User-Agent\": `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Antigravity/${ANTIGRAVITY_VERSION} Chrome/138.0.7204.235 Electron/37.3.1 Safari/537.36`,\r\n \"X-Goog-Api-Client\": \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\r\n \"Client-Metadata\": `{\"ideType\":\"ANTIGRAVITY\",\"platform\":\"${process.platform === \"win32\" ? \"WINDOWS\" : \"MACOS\"}\",\"pluginType\":\"GEMINI\"}`,\r\n} as const;\r\n\r\nexport const GEMINI_CLI_HEADERS = {\r\n \"User-Agent\": \"google-api-nodejs-client/9.15.1\",\r\n \"X-Goog-Api-Client\": \"gl-node/22.17.0\",\r\n \"Client-Metadata\": \"ideType=IDE_UNSPECIFIED,platform=PLATFORM_UNSPECIFIED,pluginType=GEMINI\",\r\n} as const;\r\n\r\nconst ANTIGRAVITY_PLATFORMS = [\"windows/amd64\", \"darwin/arm64\", \"darwin/amd64\"] as const;\r\n\r\nconst ANTIGRAVITY_API_CLIENTS = [\r\n \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\r\n \"google-cloud-sdk vscode/1.96.0\",\r\n \"google-cloud-sdk vscode/1.95.0\",\r\n] as const;\r\n\r\nfunction randomFrom<T>(arr: readonly T[]): T {\r\n return arr[Math.floor(Math.random() * arr.length)]!;\r\n}\r\n\r\nexport type HeaderSet = {\r\n \"User-Agent\": string;\r\n \"X-Goog-Api-Client\"?: string;\r\n \"Client-Metadata\"?: string;\r\n};\r\n\r\nexport function getRandomizedHeaders(style: HeaderStyle, model?: string): HeaderSet {\r\n if (style === \"gemini-cli\") {\r\n return {\r\n \"User-Agent\": GEMINI_CLI_HEADERS[\"User-Agent\"],\r\n \"X-Goog-Api-Client\": GEMINI_CLI_HEADERS[\"X-Goog-Api-Client\"],\r\n \"Client-Metadata\": GEMINI_CLI_HEADERS[\"Client-Metadata\"],\r\n };\r\n }\r\n const platform = randomFrom(ANTIGRAVITY_PLATFORMS);\r\n const metadataPlatform = platform.startsWith(\"windows\") ? \"WINDOWS\" : \"MACOS\";\r\n return {\r\n \"User-Agent\": `antigravity/${getAntigravityVersion()} ${platform}`,\r\n \"X-Goog-Api-Client\": randomFrom(ANTIGRAVITY_API_CLIENTS),\r\n \"Client-Metadata\": `{\"ideType\":\"ANTIGRAVITY\",\"platform\":\"${metadataPlatform}\",\"pluginType\":\"GEMINI\"}`,\r\n };\r\n}\r\n\r\nexport type HeaderStyle = \"antigravity\" | \"gemini-cli\";\r\n\r\n/**\r\n * Provider identifier shared between the plugin loader and credential store.\r\n */\r\nexport const ANTIGRAVITY_PROVIDER_ID = \"google\";\r\n\r\n// ============================================================================\r\n// TOOL HALLUCINATION PREVENTION (Ported from LLM-API-Key-Proxy)\r\n// ============================================================================\r\n\r\n/**\r\n * System instruction for Claude tool usage hardening.\r\n * Prevents hallucinated parameters by explicitly stating the rules.\r\n * \r\n * This is injected when tools are present to reduce cases where Claude\r\n * uses parameter names from its training data instead of the actual schema.\r\n */\r\nexport const CLAUDE_TOOL_SYSTEM_INSTRUCTION = `CRITICAL TOOL USAGE INSTRUCTIONS:\r\nYou are operating in a custom environment where tool definitions differ from your training data.\r\nYou MUST follow these rules strictly:\r\n\r\n1. DO NOT use your internal training data to guess tool parameters\r\n2. ONLY use the exact parameter structure defined in the tool schema\r\n3. Parameter names in schemas are EXACT - do not substitute with similar names from your training\r\n4. Array parameters have specific item types - check the schema's 'items' field for the exact structure\r\n5. When you see \"STRICT PARAMETERS\" in a tool description, those type definitions override any assumptions\r\n6. Tool use in agentic workflows is REQUIRED - you must call tools with the exact parameters specified\r\n\r\nIf you are unsure about a tool's parameters, YOU MUST read the schema definition carefully.`;\r\n\r\n/**\r\n * Template for parameter signature injection into tool descriptions.\r\n * {params} will be replaced with the actual parameter list.\r\n */\r\nexport const CLAUDE_DESCRIPTION_PROMPT = \"\\n\\n\u26A0\uFE0F STRICT PARAMETERS: {params}.\";\r\n\r\nexport const EMPTY_SCHEMA_PLACEHOLDER_NAME = \"_placeholder\";\r\nexport const EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION = \"Placeholder. Always pass true.\";\r\n\r\n/**\r\n * Sentinel value to bypass thought signature validation.\r\n * \r\n * When a thinking block has an invalid or missing signature (e.g., cache miss,\r\n * session mismatch, plugin restart), this sentinel can be injected to skip\r\n * validation instead of failing with \"Invalid signature in thinking block\".\r\n * \r\n * This is an officially supported Google API feature, used by:\r\n * - gemini-cli: https://github.com/google-gemini/gemini-cli\r\n * - Google .NET SDK: PredictionServiceChatClient.cs\r\n * \r\n * @see https://ai.google.dev/gemini-api/docs/thought-signatures\r\n */\r\nexport const SKIP_THOUGHT_SIGNATURE = \"skip_thought_signature_validator\";\r\n\r\n// ============================================================================\n// GOOGLE SEARCH TOOL CONSTANTS\r\n// ============================================================================\r\n\r\n/**\r\n * Model used for Google Search grounding requests.\r\n * Uses gemini-2.5-flash for fast, cost-effective search operations. (3-flash is always at capacity and doesn't support souce citation).\r\n */\r\nexport const SEARCH_MODEL = \"gemini-2.5-flash\";\r\n\r\n/**\r\n * Thinking budget for deep search (more thorough analysis).\r\n */\r\nexport const SEARCH_THINKING_BUDGET_DEEP = 16384;\r\n\r\n/**\r\n * Thinking budget for fast search (quick results).\r\n */\r\nexport const SEARCH_THINKING_BUDGET_FAST = 4096;\r\n\r\n/**\r\n * Timeout for search requests in milliseconds (60 seconds).\r\n */\r\nexport const SEARCH_TIMEOUT_MS = 60000;\r\n\r\n/**\r\n * System instruction for the Google Search tool.\r\n */\r\nexport const SEARCH_SYSTEM_INSTRUCTION = `You are an expert web search assistant with access to Google Search and URL analysis tools.\r\n\r\nYour capabilities:\r\n- Use google_search to find real-time information from the web\r\n- Use url_context to fetch and analyze content from specific URLs when provided\r\n\r\nGuidelines:\r\n- Always provide accurate, well-sourced information\r\n- Cite your sources when presenting facts\r\n- If analyzing URLs, extract the most relevant information\r\n- Be concise but comprehensive in your responses\r\n- If information is uncertain or conflicting, acknowledge it\r\n- Focus on answering the user's question directly`;\r\n\r\n", "import { generatePKCE } from \"@openauthjs/openauth/pkce\";\r\n\r\nimport {\r\n ANTIGRAVITY_CLIENT_ID,\r\n ANTIGRAVITY_CLIENT_SECRET,\r\n ANTIGRAVITY_REDIRECT_URI,\r\n ANTIGRAVITY_SCOPES,\r\n ANTIGRAVITY_ENDPOINT_FALLBACKS,\r\n ANTIGRAVITY_LOAD_ENDPOINTS,\r\n getAntigravityHeaders,\r\n GEMINI_CLI_HEADERS,\r\n} from \"../constants\";\r\nimport { createLogger } from \"../plugin/logger\";\r\nimport { calculateTokenExpiry } from \"../plugin/auth\";\r\n\r\nconst log = createLogger(\"oauth\");\r\n\r\ninterface PkcePair {\r\n challenge: string;\r\n verifier: string;\r\n}\r\n\r\ninterface AntigravityAuthState {\r\n verifier: string;\r\n projectId: string;\r\n}\r\n\r\n/**\r\n * Result returned to the caller after constructing an OAuth authorization URL.\r\n */\r\nexport interface AntigravityAuthorization {\r\n url: string;\r\n verifier: string;\r\n projectId: string;\r\n}\r\n\r\ninterface AntigravityTokenExchangeSuccess {\r\n type: \"success\";\r\n refresh: string;\r\n access: string;\r\n expires: number;\r\n email?: string;\r\n projectId: string;\r\n}\r\n\r\ninterface AntigravityTokenExchangeFailure {\r\n type: \"failed\";\r\n error: string;\r\n}\r\n\r\nexport type AntigravityTokenExchangeResult =\r\n | AntigravityTokenExchangeSuccess\r\n | AntigravityTokenExchangeFailure;\r\n\r\ninterface AntigravityTokenResponse {\r\n access_token: string;\r\n expires_in: number;\r\n refresh_token: string;\r\n}\r\n\r\ninterface AntigravityUserInfo {\r\n email?: string;\r\n}\r\n\r\n/**\r\n * Encode an object into a URL-safe base64 string.\r\n */\r\nfunction encodeState(payload: AntigravityAuthState): string {\r\n return Buffer.from(JSON.stringify(payload), \"utf8\").toString(\"base64url\");\r\n}\r\n\r\n/**\r\n * Decode an OAuth state parameter back into its structured representation.\r\n */\r\nfunction decodeState(state: string): AntigravityAuthState {\r\n const normalized = state.replace(/-/g, \"+\").replace(/_/g, \"/\");\r\n const padded = normalized.padEnd(normalized.length + ((4 - normalized.length % 4) % 4), \"=\");\r\n const json = Buffer.from(padded, \"base64\").toString(\"utf8\");\r\n const parsed = JSON.parse(json);\r\n if (typeof parsed.verifier !== \"string\") {\r\n throw new Error(\"Missing PKCE verifier in state\");\r\n }\r\n return {\r\n verifier: parsed.verifier,\r\n projectId: typeof parsed.projectId === \"string\" ? parsed.projectId : \"\",\r\n };\r\n}\r\n\r\n/**\r\n * Build the Antigravity OAuth authorization URL including PKCE and optional project metadata.\r\n */\r\nexport async function authorizeAntigravity(projectId = \"\"): Promise<AntigravityAuthorization> {\r\n const pkce = (await generatePKCE()) as PkcePair;\r\n\r\n const url = new URL(\"https://accounts.google.com/o/oauth2/v2/auth\");\r\n url.searchParams.set(\"client_id\", ANTIGRAVITY_CLIENT_ID);\r\n url.searchParams.set(\"response_type\", \"code\");\r\n url.searchParams.set(\"redirect_uri\", ANTIGRAVITY_REDIRECT_URI);\r\n url.searchParams.set(\"scope\", ANTIGRAVITY_SCOPES.join(\" \"));\r\n url.searchParams.set(\"code_challenge\", pkce.challenge);\r\n url.searchParams.set(\"code_challenge_method\", \"S256\");\r\n url.searchParams.set(\r\n \"state\",\r\n encodeState({ verifier: pkce.verifier, projectId: projectId || \"\" }),\r\n );\r\n url.searchParams.set(\"access_type\", \"offline\");\r\n url.searchParams.set(\"prompt\", \"consent\");\r\n\r\n return {\r\n url: url.toString(),\r\n verifier: pkce.verifier,\r\n projectId: projectId || \"\",\r\n };\r\n}\r\n\r\nconst FETCH_TIMEOUT_MS = 10000;\r\n\r\nasync function fetchWithTimeout(\r\n url: string,\r\n options: RequestInit,\r\n timeoutMs = FETCH_TIMEOUT_MS,\r\n): Promise<Response> {\r\n const controller = new AbortController();\r\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\r\n try {\r\n return await fetch(url, { ...options, signal: controller.signal });\r\n } finally {\r\n clearTimeout(timeout);\r\n }\r\n}\r\n\r\nasync function fetchProjectID(accessToken: string): Promise<string> {\r\n const errors: string[] = [];\r\n const loadHeaders: Record<string, string> = {\r\n Authorization: `Bearer ${accessToken}`,\r\n \"Content-Type\": \"application/json\",\r\n \"User-Agent\": GEMINI_CLI_HEADERS[\"User-Agent\"],\r\n \"Client-Metadata\": getAntigravityHeaders()[\"Client-Metadata\"],\r\n };\r\n\r\n const loadEndpoints = Array.from(\r\n new Set<string>([...ANTIGRAVITY_LOAD_ENDPOINTS, ...ANTIGRAVITY_ENDPOINT_FALLBACKS]),\r\n );\r\n\r\n for (const baseEndpoint of loadEndpoints) {\r\n try {\r\n const url = `${baseEndpoint}/v1internal:loadCodeAssist`;\r\n const response = await fetchWithTimeout(url, {\r\n method: \"POST\",\r\n headers: loadHeaders,\r\n body: JSON.stringify({\r\n metadata: {\r\n ideType: \"ANTIGRAVITY\",\r\n platform: process.platform === \"win32\" ? \"WINDOWS\" : \"MACOS\",\r\n pluginType: \"GEMINI\",\r\n },\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const message = await response.text().catch(() => \"\");\r\n errors.push(\r\n `loadCodeAssist ${response.status} at ${baseEndpoint}${\r\n message ? `: ${message}` : \"\"\r\n }`,\r\n );\r\n continue;\r\n }\r\n\r\n const data = await response.json();\r\n if (typeof data.cloudaicompanionProject === \"string\" && data.cloudaicompanionProject) {\r\n return data.cloudaicompanionProject;\r\n }\r\n if (\r\n data.cloudaicompanionProject &&\r\n typeof data.cloudaicompanionProject.id === \"string\" &&\r\n data.cloudaicompanionProject.id\r\n ) {\r\n return data.cloudaicompanionProject.id;\r\n }\r\n\r\n errors.push(`loadCodeAssist missing project id at ${baseEndpoint}`);\r\n } catch (e) {\r\n errors.push(\r\n `loadCodeAssist error at ${baseEndpoint}: ${\r\n e instanceof Error ? e.message : String(e)\r\n }`,\r\n );\r\n }\r\n }\r\n\r\n if (errors.length) {\r\n log.warn(\"Failed to resolve Antigravity project via loadCodeAssist\", { errors: errors.join(\"; \") });\r\n }\r\n return \"\";\r\n}\r\n\r\n/**\r\n * Exchange an authorization code for Antigravity CLI access and refresh tokens.\r\n */\r\nexport async function exchangeAntigravity(\r\n code: string,\r\n state: string,\r\n): Promise<AntigravityTokenExchangeResult> {\r\n try {\r\n const { verifier, projectId } = decodeState(state);\r\n\r\n const startTime = Date.now();\r\n const tokenResponse = await fetch(\"https://oauth2.googleapis.com/token\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded;charset=UTF-8\",\r\n \"Accept\": \"*/*\",\r\n \"Accept-Encoding\": \"gzip, deflate, br\",\r\n \"User-Agent\": GEMINI_CLI_HEADERS[\"User-Agent\"],\r\n },\r\n body: new URLSearchParams({\r\n client_id: ANTIGRAVITY_CLIENT_ID,\r\n client_secret: ANTIGRAVITY_CLIENT_SECRET,\r\n code,\r\n grant_type: \"authorization_code\",\r\n redirect_uri: ANTIGRAVITY_REDIRECT_URI,\r\n code_verifier: verifier,\r\n }),\r\n });\r\n\r\n if (!tokenResponse.ok) {\r\n const errorText = await tokenResponse.text();\r\n return { type: \"failed\", error: errorText };\r\n }\r\n\r\n const tokenPayload = (await tokenResponse.json()) as AntigravityTokenResponse;\r\n\r\n const userInfoResponse = await fetch(\r\n \"https://www.googleapis.com/oauth2/v1/userinfo?alt=json\",\r\n {\r\n headers: {\r\n Authorization: `Bearer ${tokenPayload.access_token}`,\r\n \"User-Agent\": GEMINI_CLI_HEADERS[\"User-Agent\"],\r\n },\r\n },\r\n );\r\n\r\n const userInfo = userInfoResponse.ok\r\n ? ((await userInfoResponse.json()) as AntigravityUserInfo)\r\n : {};\r\n\r\n const refreshToken = tokenPayload.refresh_token;\r\n if (!refreshToken) {\r\n return { type: \"failed\", error: \"Missing refresh token in response\" };\r\n }\r\n\r\n let effectiveProjectId = projectId;\r\n if (!effectiveProjectId) {\r\n effectiveProjectId = await fetchProjectID(tokenPayload.access_token);\r\n }\r\n\r\n const storedRefresh = `${refreshToken}|${effectiveProjectId || \"\"}`;\r\n\r\n return {\r\n type: \"success\",\r\n refresh: storedRefresh,\r\n access: tokenPayload.access_token,\r\n expires: calculateTokenExpiry(startTime, tokenPayload.expires_in),\r\n email: userInfo.email,\r\n projectId: effectiveProjectId || \"\",\r\n };\r\n } catch (error) {\r\n return {\r\n type: \"failed\",\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n };\r\n }\r\n}\r\n", "import { createWriteStream, mkdirSync, readdirSync, statSync, unlinkSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\nimport { env } from \"node:process\";\r\nimport { homedir } from \"node:os\";\r\nimport type { AntigravityConfig } from \"./config\";\r\nimport {\r\n deriveDebugPolicy,\r\n formatAccountContextLabel,\r\n formatAccountLabel,\r\n formatBodyPreviewForLog,\r\n formatErrorForLog,\r\n isTruthyFlag,\r\n truncateTextForLog,\r\n} from \"./logging-utils\";\r\nimport { ensureGitignoreSync } from \"./storage\";\r\n\r\nconst MAX_BODY_PREVIEW_CHARS = 12000;\r\nconst MAX_BODY_LOG_CHARS = 50000;\r\n\r\nexport const DEBUG_MESSAGE_PREFIX = \"[opencode-antigravity-auth debug]\";\r\n\r\n// =============================================================================\r\n// Debug State (lazily initialized with config)\r\n// =============================================================================\r\n\r\ninterface DebugState {\r\n debugEnabled: boolean;\r\n debugTuiEnabled: boolean;\r\n logFilePath: string | undefined;\r\n logWriter: (line: string) => void;\r\n}\r\n\r\nlet debugState: DebugState | null = null;\r\n\r\n/**\r\n * Get the OS-specific config directory.\r\n */\r\nfunction getConfigDir(): string {\r\n const platform = process.platform;\r\n if (platform === \"win32\") {\r\n return join(env.APPDATA || join(homedir(), \"AppData\", \"Roaming\"), \"opencode\");\r\n }\r\n const xdgConfig = env.XDG_CONFIG_HOME || join(homedir(), \".config\");\r\n return join(xdgConfig, \"opencode\");\r\n}\r\n\r\n/**\r\n * Returns the logs directory, creating it if needed.\r\n */\r\nfunction getLogsDir(customLogDir?: string): string {\r\n const logsDir = customLogDir || join(getConfigDir(), \"antigravity-logs\");\r\n\r\n try {\r\n mkdirSync(logsDir, { recursive: true });\r\n } catch {\r\n // Directory may already exist or we don't have permission\r\n }\r\n\r\n return logsDir;\r\n}\r\n\r\n/**\r\n * Builds a timestamped log file path.\r\n */\r\nfunction createLogFilePath(customLogDir?: string): string {\r\n const logsDir = getLogsDir(customLogDir);\r\n cleanupOldLogs(logsDir, 25);\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\r\n return join(logsDir, `antigravity-debug-${timestamp}.log`);\r\n}\r\n\r\n/**\r\n * Cleans up old log files, keeping only the most recent maxFiles.\r\n */\r\nfunction cleanupOldLogs(logsDir: string, maxFiles: number): void {\r\n try {\r\n const files = readdirSync(logsDir)\r\n .filter((file) => file.startsWith(\"antigravity-debug-\") && file.endsWith(\".log\"))\r\n .map((file) => join(logsDir, file));\r\n\r\n if (files.length <= maxFiles) {\r\n return;\r\n }\r\n\r\n const sortedFiles = files\r\n .map((file) => ({\r\n file,\r\n mtime: statSync(file).mtimeMs,\r\n }))\r\n .sort((a, b) => b.mtime - a.mtime);\r\n\r\n for (let i = maxFiles; i < sortedFiles.length; i++) {\r\n try {\r\n unlinkSync(sortedFiles[i]!.file);\r\n } catch {\r\n // Ignore deletion errors\r\n }\r\n }\r\n } catch {\r\n // Ignore directory read errors\r\n }\r\n}\r\n\r\n/**\r\n * Creates a log writer function that writes to a file.\r\n */\r\nfunction createLogWriter(filePath?: string): (line: string) => void {\r\n if (!filePath) {\r\n return () => {};\r\n }\r\n\r\n try {\r\n const stream = createWriteStream(filePath, { flags: \"a\" });\r\n stream.on(\"error\", () => {});\r\n return (line: string) => {\r\n const timestamp = new Date().toISOString();\r\n const formatted = `[${timestamp}] ${line}`;\r\n stream.write(`${formatted}\\n`);\r\n };\r\n } catch {\r\n return () => {};\r\n }\r\n}\r\n\r\n/**\r\n * Initialize or reinitialize debug state with the given config.\r\n * Call this once at plugin startup after loading config.\r\n */\r\nexport function initializeDebug(config: AntigravityConfig): void {\r\n // Config takes precedence, but env var can force enable for debugging\r\n const envDebugFlag = env.OPENCODE_ANTIGRAVITY_DEBUG ?? \"\";\r\n const { debugEnabled } = deriveDebugPolicy({\r\n configDebug: config.debug,\r\n configDebugTui: config.debug_tui,\r\n envDebugFlag,\r\n envDebugTuiFlag: env.OPENCODE_ANTIGRAVITY_DEBUG_TUI,\r\n });\r\n const debugTuiEnabled = config.debug_tui || isTruthyFlag(env.OPENCODE_ANTIGRAVITY_DEBUG_TUI);\r\n const logFilePath = debugEnabled ? createLogFilePath(config.log_dir) : undefined;\r\n const logWriter = createLogWriter(logFilePath);\r\n\r\n if (debugEnabled) {\r\n ensureGitignoreSync(getConfigDir());\r\n }\r\n\r\n debugState = {\r\n debugEnabled,\r\n debugTuiEnabled,\r\n logFilePath,\r\n logWriter,\r\n };\r\n}\r\n\r\n/**\r\n * Get the current debug state, initializing with defaults if needed.\r\n * This allows the module to work even before initializeDebug is called.\r\n */\r\nfunction getDebugState(): DebugState {\r\n if (!debugState) {\r\n // Fallback to env-based initialization for backward compatibility\r\n const { debugEnabled } = deriveDebugPolicy({\r\n configDebug: false,\r\n configDebugTui: false,\r\n envDebugFlag: env.OPENCODE_ANTIGRAVITY_DEBUG,\r\n envDebugTuiFlag: env.OPENCODE_ANTIGRAVITY_DEBUG_TUI,\r\n });\r\n const debugTuiEnabled = isTruthyFlag(env.OPENCODE_ANTIGRAVITY_DEBUG_TUI);\r\n const logFilePath = debugEnabled ? createLogFilePath() : undefined;\r\n const logWriter = createLogWriter(logFilePath);\r\n\r\n debugState = {\r\n debugEnabled,\r\n debugTuiEnabled,\r\n logFilePath,\r\n logWriter,\r\n };\r\n }\r\n return debugState;\r\n}\r\n\r\n// =============================================================================\r\n// Public API\r\n// =============================================================================\r\n\r\nexport function isDebugEnabled(): boolean {\r\n return getDebugState().debugEnabled;\r\n}\r\n\r\nexport function isDebugTuiEnabled(): boolean {\r\n return getDebugState().debugTuiEnabled;\r\n}\r\n\r\nexport function getLogFilePath(): string | undefined {\r\n return getDebugState().logFilePath;\r\n}\r\n\r\nexport interface AntigravityDebugContext {\r\n id: string;\r\n streaming: boolean;\r\n startedAt: number;\r\n}\r\n\r\ninterface AntigravityDebugRequestMeta {\r\n originalUrl: string;\r\n resolvedUrl: string;\r\n method?: string;\r\n headers?: HeadersInit;\r\n body?: BodyInit | null;\r\n streaming: boolean;\r\n projectId?: string;\r\n}\r\n\r\ninterface AntigravityDebugResponseMeta {\r\n body?: string;\r\n note?: string;\r\n error?: unknown;\r\n headersOverride?: HeadersInit;\r\n}\r\n\r\nlet requestCounter = 0;\r\n\r\n/**\r\n * Begins a debug trace for an Antigravity request.\r\n */\r\nexport function startAntigravityDebugRequest(meta: AntigravityDebugRequestMeta): AntigravityDebugContext | null {\r\n const state = getDebugState();\r\n if (!state.debugEnabled) {\r\n return null;\r\n }\r\n\r\n const id = `ANTIGRAVITY-${++requestCounter}`;\r\n const method = meta.method ?? \"GET\";\r\n logDebug(`[Antigravity Debug ${id}] pid=${process.pid} ${method} ${meta.resolvedUrl}`);\r\n if (meta.originalUrl && meta.originalUrl !== meta.resolvedUrl) {\r\n logDebug(`[Antigravity Debug ${id}] Original URL: ${meta.originalUrl}`);\r\n }\r\n if (meta.projectId) {\r\n logDebug(`[Antigravity Debug ${id}] Project: ${meta.projectId}`);\r\n }\r\n logDebug(`[Antigravity Debug ${id}] Streaming: ${meta.streaming ? \"yes\" : \"no\"}`);\r\n logDebug(`[Antigravity Debug ${id}] Headers: ${JSON.stringify(maskHeaders(meta.headers))}`);\r\n const bodyPreview = formatBodyPreviewForLog(meta.body, MAX_BODY_PREVIEW_CHARS);\r\n if (bodyPreview) {\r\n logDebug(`[Antigravity Debug ${id}] Body Preview: ${bodyPreview}`);\r\n }\r\n\r\n return { id, streaming: meta.streaming, startedAt: Date.now() };\r\n}\r\n\r\n/**\r\n * Logs response details for a previously started debug trace.\r\n */\r\nexport function logAntigravityDebugResponse(\r\n context: AntigravityDebugContext | null | undefined,\r\n response: Response,\r\n meta: AntigravityDebugResponseMeta = {},\r\n): void {\r\n const state = getDebugState();\r\n if (!state.debugEnabled || !context) {\r\n return;\r\n }\r\n\r\n const durationMs = Date.now() - context.startedAt;\r\n logDebug(\r\n `[Antigravity Debug ${context.id}] Response ${response.status} ${response.statusText} (${durationMs}ms)`,\r\n );\r\n logDebug(\r\n `[Antigravity Debug ${context.id}] Response Headers: ${JSON.stringify(\r\n maskHeaders(meta.headersOverride ?? response.headers),\r\n )}`,\r\n );\r\n\r\n if (meta.note) {\r\n logDebug(`[Antigravity Debug ${context.id}] Note: ${meta.note}`);\r\n }\r\n\r\n if (meta.error) {\r\n logDebug(`[Antigravity Debug ${context.id}] Error: ${formatErrorForLog(meta.error)}`);\r\n }\r\n\r\n if (meta.body) {\r\n logDebug(\r\n `[Antigravity Debug ${context.id}] Response Body Preview: ${truncateTextForLog(meta.body, MAX_BODY_PREVIEW_CHARS)}`,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Obscures sensitive headers and returns a plain object for logging.\r\n */\r\nfunction maskHeaders(headers?: HeadersInit | Headers): Record<string, string> {\r\n if (!headers) {\r\n return {};\r\n }\r\n\r\n const result: Record<string, string> = {};\r\n const SENSITIVE_HEADERS = new Set([\"authorization\", \"x-api-key\", \"x-goog-api-key\", \"cookie\", \"set-cookie\"]);\n const parsed = headers instanceof Headers ? headers : new Headers(headers);\n parsed.forEach((value, key) => {\n if (SENSITIVE_HEADERS.has(key.toLowerCase())) {\n result[key] = \"[redacted]\";\n } else {\n result[key] = value;\n }\n }); return result;\r\n}\r\n\r\n/**\r\n * Writes a single debug line using the configured writer.\r\n */\r\nfunction logDebug(line: string): void {\r\n getDebugState().logWriter(line);\r\n}\r\n\r\nfunction runWithDebugEnabled(action: () => void): void {\r\n if (!getDebugState().debugEnabled) return;\r\n action();\r\n}\r\n\r\nexport interface AccountDebugInfo {\r\n index: number;\r\n email?: string;\r\n family: string;\r\n totalAccounts: number;\r\n rateLimitState?: { claude?: number; gemini?: number };\r\n}\r\n\r\nexport function logAccountContext(label: string, info: AccountDebugInfo): void {\r\n runWithDebugEnabled(() => {\r\n const accountLabel = formatAccountContextLabel(info.email, info.index);\r\n\r\n const indexLabel = info.index >= 0 ? `${info.index + 1}/${info.totalAccounts}` : `-/${info.totalAccounts}`;\r\n\r\n let rateLimitInfo = \"\";\r\n if (info.rateLimitState && Object.keys(info.rateLimitState).length > 0) {\r\n const now = Date.now();\r\n const activeRateLimits: Record<string, string> = {};\r\n for (const [key, resetTime] of Object.entries(info.rateLimitState)) {\r\n if (typeof resetTime === \"number\" && resetTime > now) {\r\n const remainingSec = Math.ceil((resetTime - now) / 1000);\r\n activeRateLimits[key] = `${remainingSec}s`;\r\n }\r\n }\r\n if (Object.keys(activeRateLimits).length > 0) {\r\n rateLimitInfo = ` rateLimits=${JSON.stringify(activeRateLimits)}`;\r\n }\r\n }\r\n\r\n logDebug(`[Account] ${label}: ${accountLabel} (${indexLabel}) family=${info.family}${rateLimitInfo}`);\r\n });\r\n}\r\n\r\nexport function logRateLimitEvent(\r\n accountIndex: number,\r\n email: string | undefined,\r\n family: string,\r\n status: number,\r\n retryAfterMs: number,\r\n bodyInfo: { message?: string; quotaResetTime?: string; retryDelayMs?: number | null; reason?: string },\r\n): void {\r\n runWithDebugEnabled(() => {\r\n const accountLabel = formatAccountLabel(email, accountIndex);\r\n logDebug(`[RateLimit] ${status} on ${accountLabel} family=${family} retryAfterMs=${retryAfterMs}`);\r\n if (bodyInfo.message) {\r\n logDebug(`[RateLimit] message: ${bodyInfo.message}`);\r\n }\r\n if (bodyInfo.quotaResetTime) {\r\n logDebug(`[RateLimit] quotaResetTime: ${bodyInfo.quotaResetTime}`);\r\n }\r\n if (bodyInfo.retryDelayMs !== undefined && bodyInfo.retryDelayMs !== null) {\r\n logDebug(`[RateLimit] body retryDelayMs: ${bodyInfo.retryDelayMs}`);\r\n }\r\n if (bodyInfo.reason) {\r\n logDebug(`[RateLimit] reason: ${bodyInfo.reason}`);\r\n }\r\n });\r\n}\r\n\r\nexport function logRateLimitSnapshot(\r\n family: string,\r\n accounts: Array<{ index: number; email?: string; rateLimitResetTimes?: { claude?: number; gemini?: number } }>,\r\n): void {\r\n runWithDebugEnabled(() => {\r\n const now = Date.now();\r\n const entries = accounts.map((account) => {\r\n const label = formatAccountLabel(account.email, account.index);\r\n const reset = account.rateLimitResetTimes?.[family as \"claude\" | \"gemini\"];\r\n if (typeof reset !== \"number\") {\r\n return `${label}=ready`;\r\n }\r\n const remaining = Math.max(0, reset - now);\r\n const seconds = Math.ceil(remaining / 1000);\r\n return `${label}=wait ${seconds}s`;\r\n });\r\n logDebug(`[RateLimit] snapshot family=${family} ${entries.join(\" | \")}`);\r\n });\r\n}\r\n\r\nexport async function logResponseBody(\r\n context: AntigravityDebugContext | null | undefined,\r\n response: Response,\r\n status: number,\r\n): Promise<string | undefined> {\r\n const state = getDebugState();\r\n if (!state.debugEnabled || !context) return undefined;\r\n\r\n try {\r\n const text = await response.clone().text();\r\n const preview = truncateTextForLog(text, MAX_BODY_LOG_CHARS);\r\n logDebug(`[Antigravity Debug ${context.id}] Response Body (${status}): ${preview}`);\r\n return text;\r\n } catch (e) {\r\n logDebug(`[Antigravity Debug ${context.id}] Failed to read response body: ${formatErrorForLog(e)}`);\r\n return undefined;\r\n }\r\n}\r\n\r\nexport function logModelFamily(url: string, extractedModel: string | null, family: string): void {\r\n runWithDebugEnabled(() => {\r\n logDebug(`[ModelFamily] url=${url} model=${extractedModel ?? \"unknown\"} family=${family}`);\r\n });\r\n}\r\n\r\nexport function debugLogToFile(message: string): void {\r\n runWithDebugEnabled(() => {\r\n logDebug(message);\r\n });\r\n}\r\n\r\n/**\r\n * Logs a toast message to the debug file.\r\n * This helps correlate what the user saw with debug events.\r\n */\r\nexport function logToast(message: string, variant: \"info\" | \"warning\" | \"success\" | \"error\"): void {\r\n runWithDebugEnabled(() => {\r\n const variantLabel = variant.toUpperCase();\r\n logDebug(`[Toast/${variantLabel}] ${message}`);\r\n });\r\n}\r\n\r\n/**\r\n * Logs retry attempt information.\r\n * @param maxAttempts - Use -1 for unlimited retries\r\n */\r\nexport function logRetryAttempt(\r\n attempt: number,\r\n maxAttempts: number,\r\n reason: string,\r\n delayMs?: number,\r\n): void {\r\n runWithDebugEnabled(() => {\r\n const delayInfo = delayMs !== undefined ? ` delay=${delayMs}ms` : \"\";\r\n const maxInfo = maxAttempts < 0 ? \"\u221E\" : maxAttempts.toString();\r\n logDebug(`[Retry] Attempt ${attempt}/${maxInfo} reason=${reason}${delayInfo}`);\r\n });\r\n}\r\n\r\n/**\r\n * Logs cache hit/miss information from response usage metadata.\r\n */\r\nexport function logCacheStats(\r\n model: string,\r\n cacheReadTokens: number,\r\n cacheWriteTokens: number,\r\n totalInputTokens: number,\r\n): void {\r\n runWithDebugEnabled(() => {\r\n const cacheHitRate = totalInputTokens > 0 \r\n ? Math.round((cacheReadTokens / totalInputTokens) * 100) \r\n : 0;\r\n const status = cacheReadTokens > 0 ? \"HIT\" : (cacheWriteTokens > 0 ? \"WRITE\" : \"MISS\");\r\n logDebug(`[Cache] ${status} model=${model} read=${cacheReadTokens} write=${cacheWriteTokens} total=${totalInputTokens} hitRate=${cacheHitRate}%`);\r\n });\r\n}\r\n\r\n/**\r\n * Logs quota status for an account.\r\n */\r\nexport function logQuotaStatus(\r\n accountEmail: string | undefined,\r\n accountIndex: number,\r\n quotaPercent: number,\r\n family?: string,\r\n): void {\r\n runWithDebugEnabled(() => {\r\n const accountLabel = formatAccountLabel(accountEmail, accountIndex);\r\n const familyInfo = family ? ` family=${family}` : \"\";\r\n const status = quotaPercent <= 0 ? \"EXHAUSTED\" : quotaPercent < 20 ? \"LOW\" : \"OK\";\r\n logDebug(`[Quota] ${accountLabel} remaining=${quotaPercent.toFixed(1)}% status=${status}${familyInfo}`);\r\n });\r\n}\r\n\r\n/**\r\n * Logs background quota fetch events.\r\n */\r\nexport function logQuotaFetch(\r\n event: \"start\" | \"complete\" | \"error\",\r\n accountCount?: number,\r\n details?: string,\r\n): void {\r\n runWithDebugEnabled(() => {\r\n const countInfo = accountCount !== undefined ? ` accounts=${accountCount}` : \"\";\r\n const detailsInfo = details ? ` ${details}` : \"\";\r\n logDebug(`[QuotaFetch] ${event.toUpperCase()}${countInfo}${detailsInfo}`);\r\n });\r\n}\r\n\r\n/**\r\n * Logs which model is being used for a request.\r\n */\r\nexport function logModelUsed(\r\n requestedModel: string,\r\n actualModel: string,\r\n accountEmail?: string,\r\n): void {\r\n runWithDebugEnabled(() => {\r\n const accountInfo = accountEmail ? ` account=${accountEmail}` : \"\";\r\n if (requestedModel !== actualModel) {\r\n logDebug(`[Model] requested=${requestedModel} actual=${actualModel}${accountInfo}`);\r\n } else {\r\n logDebug(`[Model] ${actualModel}${accountInfo}`);\r\n }\r\n });\r\n}\r\n", "export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\"\r\n\r\nexport interface DebugPolicyInput {\r\n configDebug: boolean\r\n configDebugTui: boolean\r\n envDebugFlag?: string\r\n envDebugTuiFlag?: string\r\n}\r\n\r\nexport interface DebugPolicy {\r\n debugLevel: number\r\n debugEnabled: boolean\r\n debugTuiEnabled: boolean\r\n verboseEnabled: boolean\r\n}\r\n\r\nexport function isTruthyFlag(flag?: string): boolean {\r\n return flag === \"1\" || flag?.toLowerCase() === \"true\"\r\n}\r\n\r\nexport function parseDebugLevel(flag: string): number {\r\n const trimmed = flag.trim()\r\n if (trimmed === \"2\" || trimmed === \"verbose\") return 2\r\n if (trimmed === \"1\" || trimmed === \"true\") return 1\r\n return 0\r\n}\r\n\r\nexport function deriveDebugPolicy(input: DebugPolicyInput): DebugPolicy {\r\n const envDebugFlag = input.envDebugFlag ?? \"\"\r\n const debugLevel = input.configDebug\r\n ? envDebugFlag === \"2\" || envDebugFlag === \"verbose\"\r\n ? 2\r\n : 1\r\n : parseDebugLevel(envDebugFlag)\r\n const debugEnabled = debugLevel >= 1\r\n const verboseEnabled = debugLevel >= 2\r\n const debugTuiEnabled = debugEnabled && (input.configDebugTui || isTruthyFlag(input.envDebugTuiFlag))\r\n\r\n return {\r\n debugLevel,\r\n debugEnabled,\r\n debugTuiEnabled,\r\n verboseEnabled,\r\n }\r\n}\r\n\r\nexport function formatAccountLabel(email: string | undefined, accountIndex: number): string {\r\n return email || `Account ${accountIndex + 1}`\r\n}\r\n\r\nexport function formatAccountContextLabel(email: string | undefined, accountIndex: number): string {\r\n if (email) {\r\n return email\r\n }\r\n if (accountIndex >= 0) {\r\n return `Account ${accountIndex + 1}`\r\n }\r\n return \"All accounts\"\r\n}\r\n\r\nexport function formatErrorForLog(error: unknown): string {\r\n if (error instanceof Error) {\r\n return error.stack ?? error.message\r\n }\r\n try {\r\n return JSON.stringify(error)\r\n } catch {\r\n return String(error)\r\n }\r\n}\r\n\r\nexport function truncateTextForLog(text: string, maxChars: number): string {\r\n if (text.length <= maxChars) {\r\n return text\r\n }\r\n return `${text.slice(0, maxChars)}... (truncated ${text.length - maxChars} chars)`\r\n}\r\n\r\nexport function formatBodyPreviewForLog(\r\n body: BodyInit | null | undefined,\r\n maxChars: number,\r\n): string | undefined {\r\n if (body == null) {\r\n return undefined\r\n }\r\n\r\n if (typeof body === \"string\") {\r\n return truncateTextForLog(body, maxChars)\r\n }\r\n\r\n if (body instanceof URLSearchParams) {\r\n return truncateTextForLog(body.toString(), maxChars)\r\n }\r\n\r\n if (typeof Blob !== \"undefined\" && body instanceof Blob) {\r\n return `[Blob size=${body.size}]`\r\n }\r\n\r\n if (typeof FormData !== \"undefined\" && body instanceof FormData) {\r\n return \"[FormData payload omitted]\"\r\n }\r\n\r\n return `[${body.constructor?.name ?? typeof body} payload omitted]`\r\n}\r\n\r\nexport function writeConsoleLog(level: LogLevel, ...args: unknown[]): void {\r\n switch (level) {\r\n case \"debug\":\r\n console.debug(...args)\r\n break\r\n case \"info\":\r\n console.info(...args)\r\n break\r\n case \"warn\":\r\n console.warn(...args)\r\n break\r\n case \"error\":\r\n console.error(...args)\r\n break\r\n }\r\n}\r\n", "import { promises as fs } from \"node:fs\";\r\nimport {\r\n existsSync,\r\n readFileSync,\r\n writeFileSync,\r\n appendFileSync,\r\n mkdirSync,\r\n renameSync,\r\n copyFileSync,\r\n unlinkSync,\r\n} from \"node:fs\";\r\nimport { dirname, join } from \"node:path\";\r\nimport { homedir } from \"node:os\";\r\nimport { randomBytes } from \"node:crypto\";\r\n// proper-lockfile is CJS \u2014 lazy-load to avoid ESM default-export errors\ntype LockFunction = (path: string, options?: Record<string, unknown>) => Promise<() => Promise<void>>\nlet _cachedLock: LockFunction | undefined\nasync function getLockFunction(): Promise<LockFunction> {\n if (_cachedLock) return _cachedLock\n const mod = await import(\"proper-lockfile\") as Record<string, unknown>\n const fn = (typeof mod.lock === \"function\" ? mod.lock : undefined)\n || (mod.default && typeof (mod.default as Record<string, unknown>).lock === \"function\"\n ? (mod.default as Record<string, unknown>).lock : undefined)\n _cachedLock = (fn as LockFunction) || (async () => async () => {})\n return _cachedLock\n}\nconst lockfile = { lock: (path: string, options?: Record<string, unknown>) => getLockFunction().then(fn => fn(path, options)) }\r\nimport type { HeaderStyle } from \"../constants\";\r\nimport { createLogger } from \"./logger\";\r\n\r\nconst log = createLogger(\"storage\");\r\n\r\n/**\r\n * Files/directories that should be gitignored in the config directory.\r\n * These contain sensitive data or machine-specific state.\r\n */\r\nexport const GITIGNORE_ENTRIES = [\r\n \".gitignore\",\r\n \"antigravity-accounts.json\",\r\n \"antigravity-accounts.json.*.tmp\",\r\n \"antigravity-signature-cache.json\",\r\n \"antigravity-logs/\",\r\n];\r\n\r\n/**\r\n * Ensures a .gitignore file exists in the config directory with entries\r\n * for sensitive files. Creates the file if missing, or appends missing\r\n * entries if it already exists.\r\n */\r\nexport async function ensureGitignore(configDir: string): Promise<void> {\r\n const gitignorePath = join(configDir, \".gitignore\");\r\n\r\n try {\r\n let content: string;\r\n let existingLines: string[] = [];\r\n\r\n try {\r\n content = await fs.readFile(gitignorePath, \"utf-8\");\r\n existingLines = content.split(\"\\n\").map((line) => line.trim());\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\r\n return;\r\n }\r\n content = \"\";\r\n }\r\n\r\n const missingEntries = GITIGNORE_ENTRIES.filter(\r\n (entry) => !existingLines.includes(entry),\r\n );\r\n\r\n if (missingEntries.length === 0) {\r\n return;\r\n }\r\n\r\n if (content === \"\") {\r\n await fs.writeFile(\r\n gitignorePath,\r\n missingEntries.join(\"\\n\") + \"\\n\",\r\n \"utf-8\",\r\n );\r\n log.info(\"Created .gitignore in config directory\");\r\n } else {\r\n const suffix = content.endsWith(\"\\n\") ? \"\" : \"\\n\";\r\n await fs.appendFile(\r\n gitignorePath,\r\n suffix + missingEntries.join(\"\\n\") + \"\\n\",\r\n \"utf-8\",\r\n );\r\n log.info(\"Updated .gitignore with missing entries\", {\r\n added: missingEntries,\r\n });\r\n }\r\n } catch (error) {\n log.warn(\"Failed to update .gitignore with account storage entries\", {\n error: String(error),\n });\n }\n}\r\n/**\r\n * Synchronous version of ensureGitignore for use in sync code paths.\r\n */\r\nexport function ensureGitignoreSync(configDir: string): void {\r\n const gitignorePath = join(configDir, \".gitignore\");\r\n\r\n try {\r\n let content: string;\r\n let existingLines: string[] = [];\r\n\r\n if (existsSync(gitignorePath)) {\r\n content = readFileSync(gitignorePath, \"utf-8\");\r\n existingLines = content.split(\"\\n\").map((line) => line.trim());\r\n } else {\r\n content = \"\";\r\n }\r\n\r\n const missingEntries = GITIGNORE_ENTRIES.filter(\r\n (entry) => !existingLines.includes(entry),\r\n );\r\n\r\n if (missingEntries.length === 0) {\r\n return;\r\n }\r\n\r\n if (content === \"\") {\r\n writeFileSync(gitignorePath, missingEntries.join(\"\\n\") + \"\\n\", \"utf-8\");\r\n log.info(\"Created .gitignore in config directory\");\r\n } else {\r\n const suffix = content.endsWith(\"\\n\") ? \"\" : \"\\n\";\r\n appendFileSync(\r\n gitignorePath,\r\n suffix + missingEntries.join(\"\\n\") + \"\\n\",\r\n \"utf-8\",\r\n );\r\n log.info(\"Updated .gitignore with missing entries\", {\r\n added: missingEntries,\r\n });\r\n }\r\n } catch (error) {\n log.warn(\"Failed to update .gitignore with account storage entries\", {\n error: String(error),\n });\n }\n}\r\nexport type ModelFamily = \"claude\" | \"gemini\";\r\nexport type { HeaderStyle };\r\n\r\nexport interface RateLimitState {\r\n claude?: number;\r\n gemini?: number;\r\n}\r\n\r\nexport interface RateLimitStateV3 {\r\n claude?: number;\r\n \"gemini-antigravity\"?: number;\r\n \"gemini-cli\"?: number;\r\n [key: string]: number | undefined;\r\n}\r\n\r\nexport interface AccountMetadataV1 {\r\n email?: string;\r\n refreshToken: string;\r\n projectId?: string;\r\n managedProjectId?: string;\r\n addedAt: number;\r\n lastUsed: number;\r\n isRateLimited?: boolean;\r\n rateLimitResetTime?: number;\r\n lastSwitchReason?: \"rate-limit\" | \"initial\" | \"rotation\";\r\n}\r\n\r\nexport interface AccountStorageV1 {\r\n version: 1;\r\n accounts: AccountMetadataV1[];\r\n activeIndex: number;\r\n}\r\n\r\nexport interface AccountMetadata {\r\n email?: string;\r\n refreshToken: string;\r\n projectId?: string;\r\n managedProjectId?: string;\r\n addedAt: number;\r\n lastUsed: number;\r\n lastSwitchReason?: \"rate-limit\" | \"initial\" | \"rotation\";\r\n rateLimitResetTimes?: RateLimitState;\r\n}\r\n\r\nexport interface AccountStorage {\r\n version: 2;\r\n accounts: AccountMetadata[];\r\n activeIndex: number;\r\n}\r\n\r\nexport type CooldownReason = \"auth-failure\" | \"network-error\" | \"project-error\" | \"validation-required\";\r\n\r\nexport interface AccountMetadataV3 {\r\n email?: string;\r\n refreshToken: string;\r\n projectId?: string;\r\n managedProjectId?: string;\r\n addedAt: number;\r\n lastUsed: number;\r\n enabled?: boolean;\r\n lastSwitchReason?: \"rate-limit\" | \"initial\" | \"rotation\";\r\n rateLimitResetTimes?: RateLimitStateV3;\r\n coolingDownUntil?: number;\r\n cooldownReason?: CooldownReason;\r\n /** Per-account device fingerprint for rate limit mitigation */\r\n fingerprint?: import(\"./fingerprint\").Fingerprint;\r\n fingerprintHistory?: import(\"./fingerprint\").FingerprintVersion[];\r\n /** Set when Google asks the user to verify this account before requests can continue. */\r\n verificationRequired?: boolean;\r\n verificationRequiredAt?: number;\r\n verificationRequiredReason?: string;\r\n verificationUrl?: string;\r\n /** Cached soft quota data */\r\n cachedQuota?: Record<string, { remainingFraction?: number; resetTime?: string; modelCount: number }>;\r\n cachedQuotaUpdatedAt?: number;\r\n}\r\n\r\nexport interface AccountStorageV3 {\r\n version: 3;\r\n accounts: AccountMetadataV3[];\r\n activeIndex: number;\r\n activeIndexByFamily?: {\r\n claude?: number;\r\n gemini?: number;\r\n };\r\n}\r\n\r\nexport interface AccountStorageV4 {\r\n version: 4;\r\n accounts: AccountMetadataV3[];\r\n activeIndex: number;\r\n activeIndexByFamily?: {\r\n claude?: number;\r\n gemini?: number;\r\n };\r\n}\r\n\r\ntype AnyAccountStorage =\r\n | AccountStorageV1\r\n | AccountStorage\r\n | AccountStorageV3\r\n | AccountStorageV4;\r\n\r\n/**\r\n * Gets the legacy Windows config directory (%APPDATA%\\opencode).\r\n * Used for migration from older plugin versions.\r\n */\r\nfunction getLegacyWindowsConfigDir(): string {\r\n return join(\r\n process.env.APPDATA || join(homedir(), \"AppData\", \"Roaming\"),\r\n \"opencode\",\r\n );\r\n}\r\n\r\n/**\r\n * Gets the config directory path, with the following precedence:\r\n * 1. OPENCODE_CONFIG_DIR env var (if set)\r\n * 2. ~/.config/opencode (all platforms, including Windows)\r\n *\r\n * On Windows, also checks for legacy %APPDATA%\\opencode path for migration.\r\n */\r\nfunction getConfigDir(): string {\r\n // 1. Check for explicit override via env var\r\n if (process.env.OPENCODE_CONFIG_DIR) {\r\n return process.env.OPENCODE_CONFIG_DIR;\r\n }\r\n\r\n // 2. Use ~/.config/opencode on all platforms (including Windows)\r\n const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), \".config\");\r\n return join(xdgConfig, \"opencode\");\r\n}\r\n\r\n/**\r\n * Migrates config from legacy Windows location to the new path.\r\n * Moves the file if legacy exists and new doesn't.\r\n * Returns true if migration was performed.\r\n */\r\nfunction migrateLegacyWindowsConfig(): boolean {\r\n if (process.platform !== \"win32\") {\r\n return false;\r\n }\r\n\r\n const newPath = join(getConfigDir(), \"antigravity-accounts.json\");\r\n const legacyPath = join(\r\n getLegacyWindowsConfigDir(),\r\n \"antigravity-accounts.json\",\r\n );\r\n\r\n // Only migrate if legacy exists and new doesn't\r\n if (!existsSync(legacyPath) || existsSync(newPath)) {\r\n return false;\r\n }\r\n\r\n try {\r\n // Ensure new config directory exists\r\n const newConfigDir = getConfigDir();\r\n\r\n mkdirSync(newConfigDir, { recursive: true });\r\n\r\n // Try rename first (atomic, but fails across filesystems)\r\n try {\r\n renameSync(legacyPath, newPath);\r\n log.info(\"Migrated Windows config via rename\", { from: legacyPath, to: newPath });\r\n } catch {\r\n // Fallback: copy then delete (for cross-filesystem moves)\r\n copyFileSync(legacyPath, newPath);\r\n unlinkSync(legacyPath);\r\n log.info(\"Migrated Windows config via copy+delete\", { from: legacyPath, to: newPath });\r\n }\r\n\r\n return true;\r\n } catch (error) {\r\n log.warn(\"Failed to migrate legacy Windows config, will use legacy path\", {\r\n legacyPath,\r\n newPath,\r\n error: String(error),\r\n });\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Gets the storage path, migrating from legacy Windows location if needed.\r\n * On Windows, attempts to move legacy config to new path for alignment.\r\n */\r\nfunction getStoragePathWithMigration(): string {\r\n const newPath = join(getConfigDir(), \"antigravity-accounts.json\");\r\n\r\n // On Windows, attempt to migrate legacy config to new location\r\n if (process.platform === \"win32\") {\r\n migrateLegacyWindowsConfig();\r\n\r\n // If migration failed and legacy still exists, fall back to it\r\n if (!existsSync(newPath)) {\r\n const legacyPath = join(\r\n getLegacyWindowsConfigDir(),\r\n \"antigravity-accounts.json\",\r\n );\r\n if (existsSync(legacyPath)) {\r\n log.info(\"Using legacy Windows config path (migration failed)\", {\r\n legacyPath,\r\n newPath,\r\n });\r\n return legacyPath;\r\n }\r\n }\r\n }\r\n\r\n return newPath;\r\n}\r\n\r\nexport function getStoragePath(): string {\r\n return getStoragePathWithMigration();\r\n}\r\n\r\n/**\r\n * Gets the config directory path. Exported for use by other modules.\r\n */\r\nexport { getConfigDir };\r\n\r\nconst LOCK_OPTIONS = {\r\n stale: 10000,\r\n retries: {\r\n retries: 5,\r\n minTimeout: 100,\r\n maxTimeout: 1000,\r\n factor: 2,\r\n },\r\n};\r\n\r\n/**\r\n * Ensures the file has secure permissions (0600) on POSIX systems.\r\n * This is a best-effort operation and ignores errors on Windows/unsupported FS.\r\n */\r\nasync function ensureSecurePermissions(path: string): Promise<void> {\r\n try {\r\n await fs.chmod(path, 0o600);\r\n } catch {\r\n // Ignore errors (e.g. Windows, file doesn't exist, FS doesn't support chmod)\r\n }\r\n}\r\n\r\nasync function ensureFileExists(path: string): Promise<void> {\r\n try {\r\n await fs.access(path);\r\n } catch {\r\n await fs.mkdir(dirname(path), { recursive: true });\r\n await fs.writeFile(\r\n path,\r\n JSON.stringify({ version: 4, accounts: [], activeIndex: 0 }, null, 2),\r\n { encoding: \"utf-8\", mode: 0o600 },\r\n );\r\n }\r\n}\r\n\r\nasync function withFileLock<T>(path: string, fn: () => Promise<T>): Promise<T> {\r\n await ensureFileExists(path);\r\n let release: (() => Promise<void>) | null = null;\r\n try {\r\n release = await lockfile.lock(path, LOCK_OPTIONS);\r\n return await fn();\r\n } finally {\r\n if (release) {\r\n try {\r\n await release();\r\n } catch (unlockError) {\r\n log.warn(\"Failed to release lock\", { error: String(unlockError) });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction mergeAccountStorage(\r\n existing: AccountStorageV4,\r\n incoming: AccountStorageV4,\r\n): AccountStorageV4 {\r\n const accountMap = new Map<string, AccountMetadataV3>();\r\n\r\n for (const acc of existing.accounts) {\r\n if (acc.refreshToken) {\r\n accountMap.set(acc.refreshToken, acc);\r\n }\r\n }\r\n\r\n for (const acc of incoming.accounts) {\r\n if (acc.refreshToken) {\r\n const existingAcc = accountMap.get(acc.refreshToken);\r\n if (existingAcc) {\r\n accountMap.set(acc.refreshToken, {\r\n ...existingAcc,\r\n ...acc,\r\n // Preserve manually configured projectId/managedProjectId if not in incoming\r\n projectId: acc.projectId ?? existingAcc.projectId,\r\n managedProjectId: acc.managedProjectId ?? existingAcc.managedProjectId,\r\n rateLimitResetTimes: {\r\n ...existingAcc.rateLimitResetTimes,\r\n ...acc.rateLimitResetTimes,\r\n },\r\n lastUsed: Math.max(existingAcc.lastUsed || 0, acc.lastUsed || 0),\r\n });\r\n } else {\r\n accountMap.set(acc.refreshToken, acc);\r\n }\r\n }\r\n }\r\n\r\n return {\r\n version: 4,\r\n accounts: Array.from(accountMap.values()),\r\n activeIndex: incoming.activeIndex,\r\n activeIndexByFamily: incoming.activeIndexByFamily,\r\n };\r\n}\r\n\r\nexport function deduplicateAccountsByEmail<\r\n T extends { email?: string; lastUsed?: number; addedAt?: number },\r\n>(accounts: T[]): T[] {\r\n const emailToNewestIndex = new Map<string, number>();\r\n const indicesToKeep = new Set<number>();\r\n\r\n // First pass: find the newest account for each email (by lastUsed, then addedAt)\r\n for (let i = 0; i < accounts.length; i++) {\r\n const acc = accounts[i];\r\n if (!acc) continue;\r\n\r\n if (!acc.email) {\r\n // No email - keep this account (can't deduplicate without email)\r\n indicesToKeep.add(i);\r\n continue;\r\n }\r\n\r\n const existingIndex = emailToNewestIndex.get(acc.email);\r\n if (existingIndex === undefined) {\r\n emailToNewestIndex.set(acc.email, i);\r\n continue;\r\n }\r\n\r\n // Compare to find which is newer\r\n const existing = accounts[existingIndex];\r\n if (!existing) {\r\n emailToNewestIndex.set(acc.email, i);\r\n continue;\r\n }\r\n\r\n // Prefer higher lastUsed, then higher addedAt\r\n // Compare fields separately to avoid integer overflow with large timestamps\r\n const currLastUsed = acc.lastUsed || 0;\r\n const existLastUsed = existing.lastUsed || 0;\r\n const currAddedAt = acc.addedAt || 0;\r\n const existAddedAt = existing.addedAt || 0;\r\n\r\n const isNewer =\r\n currLastUsed > existLastUsed ||\r\n (currLastUsed === existLastUsed && currAddedAt > existAddedAt);\r\n\r\n if (isNewer) {\r\n emailToNewestIndex.set(acc.email, i);\r\n }\r\n }\r\n\r\n // Add all the newest email-based indices to the keep set\r\n for (const idx of emailToNewestIndex.values()) {\r\n indicesToKeep.add(idx);\r\n }\r\n\r\n // Build the deduplicated list, preserving original order for kept items\r\n const result: T[] = [];\r\n for (let i = 0; i < accounts.length; i++) {\r\n if (indicesToKeep.has(i)) {\r\n const acc = accounts[i];\r\n if (acc) {\r\n result.push(acc);\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction migrateV1ToV2(v1: AccountStorageV1): AccountStorage {\r\n return {\r\n version: 2,\r\n accounts: v1.accounts.map((acc) => {\r\n const rateLimitResetTimes: RateLimitState = {};\r\n if (\r\n acc.isRateLimited &&\r\n acc.rateLimitResetTime &&\r\n acc.rateLimitResetTime > Date.now()\r\n ) {\r\n rateLimitResetTimes.claude = acc.rateLimitResetTime;\r\n rateLimitResetTimes.gemini = acc.rateLimitResetTime;\r\n }\r\n return {\r\n email: acc.email,\r\n refreshToken: acc.refreshToken,\r\n projectId: acc.projectId,\r\n managedProjectId: acc.managedProjectId,\r\n addedAt: acc.addedAt,\r\n lastUsed: acc.lastUsed,\r\n lastSwitchReason: acc.lastSwitchReason,\r\n rateLimitResetTimes:\r\n Object.keys(rateLimitResetTimes).length > 0\r\n ? rateLimitResetTimes\r\n : undefined,\r\n };\r\n }),\r\n activeIndex: v1.activeIndex,\r\n };\r\n}\r\n\r\nexport function migrateV2ToV3(v2: AccountStorage): AccountStorageV3 {\r\n return {\r\n version: 3,\r\n accounts: v2.accounts.map((acc) => {\r\n const rateLimitResetTimes: RateLimitStateV3 = {};\r\n if (\r\n acc.rateLimitResetTimes?.claude &&\r\n acc.rateLimitResetTimes.claude > Date.now()\r\n ) {\r\n rateLimitResetTimes.claude = acc.rateLimitResetTimes.claude;\r\n }\r\n if (\r\n acc.rateLimitResetTimes?.gemini &&\r\n acc.rateLimitResetTimes.gemini > Date.now()\r\n ) {\r\n rateLimitResetTimes[\"gemini-antigravity\"] =\r\n acc.rateLimitResetTimes.gemini;\r\n }\r\n return {\r\n email: acc.email,\r\n refreshToken: acc.refreshToken,\r\n projectId: acc.projectId,\r\n managedProjectId: acc.managedProjectId,\r\n addedAt: acc.addedAt,\r\n lastUsed: acc.lastUsed,\r\n lastSwitchReason: acc.lastSwitchReason,\r\n rateLimitResetTimes:\r\n Object.keys(rateLimitResetTimes).length > 0\r\n ? rateLimitResetTimes\r\n : undefined,\r\n };\r\n }),\r\n activeIndex: v2.activeIndex,\r\n };\r\n}\r\n\r\nexport function migrateV3ToV4(v3: AccountStorageV3): AccountStorageV4 {\r\n return {\r\n version: 4,\r\n accounts: v3.accounts.map((acc) => ({\r\n ...acc,\r\n fingerprint: undefined,\r\n fingerprintHistory: undefined,\r\n })),\r\n activeIndex: v3.activeIndex,\r\n activeIndexByFamily: v3.activeIndexByFamily,\r\n };\r\n}\r\n\r\nexport async function loadAccounts(): Promise<AccountStorageV4 | null> {\r\n try {\r\n const path = getStoragePath();\r\n // Ensure permissions are correct on load (fixes existing files)\r\n await ensureSecurePermissions(path);\r\n\r\n const content = await fs.readFile(path, \"utf-8\");\r\n const data = JSON.parse(content) as AnyAccountStorage;\r\n\r\n if (!Array.isArray(data.accounts)) {\r\n log.warn(\"Invalid storage format, ignoring\");\r\n return null;\r\n }\r\n\r\n let storage: AccountStorageV4;\r\n\r\n if (data.version === 1) {\r\n log.info(\"Migrating account storage from v1 to v4\");\r\n const v2 = migrateV1ToV2(data);\r\n const v3 = migrateV2ToV3(v2);\r\n storage = migrateV3ToV4(v3);\r\n try {\r\n await saveAccounts(storage);\r\n log.info(\"Migration to v4 complete\");\r\n } catch (saveError) {\r\n log.warn(\"Failed to persist migrated storage\", {\r\n error: String(saveError),\r\n });\r\n }\r\n } else if (data.version === 2) {\r\n log.info(\"Migrating account storage from v2 to v4\");\r\n const v3 = migrateV2ToV3(data);\r\n storage = migrateV3ToV4(v3);\r\n try {\r\n await saveAccounts(storage);\r\n log.info(\"Migration to v4 complete\");\r\n } catch (saveError) {\r\n log.warn(\"Failed to persist migrated storage\", {\r\n error: String(saveError),\r\n });\r\n }\r\n } else if (data.version === 3) {\r\n log.info(\"Migrating account storage from v3 to v4\");\r\n storage = migrateV3ToV4(data);\r\n try {\r\n await saveAccounts(storage);\r\n log.info(\"Migration to v4 complete\");\r\n } catch (saveError) {\r\n log.warn(\"Failed to persist migrated storage\", {\r\n error: String(saveError),\r\n });\r\n }\r\n } else if (data.version === 4) {\r\n storage = data;\r\n } else {\r\n log.warn(\"Unknown storage version, ignoring\", {\r\n version: (data as { version?: unknown }).version,\r\n });\r\n return null;\r\n }\r\n\r\n // Validate accounts have required fields\r\n const validAccounts = storage.accounts.filter(\r\n (a): a is AccountMetadataV3 => {\r\n return (\r\n !!a &&\r\n typeof a === \"object\" &&\r\n typeof (a as AccountMetadataV3).refreshToken === \"string\"\r\n );\r\n },\r\n );\r\n\r\n // Deduplicate accounts by email (keeps newest entry for each email)\r\n const deduplicatedAccounts = deduplicateAccountsByEmail(validAccounts);\r\n\r\n // Clamp activeIndex to valid range after deduplication\r\n let activeIndex =\r\n typeof storage.activeIndex === \"number\" &&\r\n Number.isFinite(storage.activeIndex)\r\n ? storage.activeIndex\r\n : 0;\r\n if (deduplicatedAccounts.length > 0) {\r\n activeIndex = Math.min(activeIndex, deduplicatedAccounts.length - 1);\r\n activeIndex = Math.max(activeIndex, 0);\r\n } else {\r\n activeIndex = 0;\r\n }\r\n\r\n return {\r\n version: 4,\r\n accounts: deduplicatedAccounts,\r\n activeIndex,\r\n activeIndexByFamily: storage.activeIndexByFamily,\r\n };\r\n } catch (error) {\r\n const code = (error as NodeJS.ErrnoException).code;\r\n if (code === \"ENOENT\") {\r\n return null;\r\n }\r\n log.error(\"Failed to load account storage\", { error: String(error) });\r\n return null;\r\n }\r\n}\r\n\r\nexport async function saveAccounts(storage: AccountStorageV4): Promise<void> {\r\n const path = getStoragePath();\r\n const configDir = dirname(path);\r\n await fs.mkdir(configDir, { recursive: true });\r\n await ensureGitignore(configDir);\r\n\r\n await withFileLock(path, async () => {\r\n const existing = await loadAccountsUnsafe();\r\n const merged = existing ? mergeAccountStorage(existing, storage) : storage;\r\n\r\n const tempPath = `${path}.${randomBytes(6).toString(\"hex\")}.tmp`;\r\n const content = JSON.stringify(merged, null, 2);\r\n\r\n try {\r\n await fs.writeFile(tempPath, content, { encoding: \"utf-8\", mode: 0o600 });\r\n await fs.rename(tempPath, path);\r\n } catch (error) {\r\n // Clean up temp file on failure to prevent accumulation\r\n try {\r\n await fs.unlink(tempPath);\r\n } catch {\r\n // Ignore cleanup errors (file may not exist)\r\n }\r\n throw error;\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Save accounts storage by replacing the entire file (no merge).\r\n * Use this for destructive operations like delete where we need to\r\n * remove accounts that would otherwise be merged back from existing storage.\r\n */\r\nexport async function saveAccountsReplace(storage: AccountStorageV4): Promise<void> {\r\n const path = getStoragePath();\r\n const configDir = dirname(path);\r\n await fs.mkdir(configDir, { recursive: true });\r\n await ensureGitignore(configDir);\r\n\r\n await withFileLock(path, async () => {\r\n const tempPath = `${path}.${randomBytes(6).toString(\"hex\")}.tmp`;\r\n const content = JSON.stringify(storage, null, 2);\r\n\r\n try {\r\n await fs.writeFile(tempPath, content, { encoding: \"utf-8\", mode: 0o600 });\r\n await fs.rename(tempPath, path);\r\n } catch (error) {\r\n try {\r\n await fs.unlink(tempPath);\r\n } catch {\r\n // Ignore cleanup errors\r\n }\r\n throw error;\r\n }\r\n });\r\n}\r\n\r\nasync function loadAccountsUnsafe(): Promise<AccountStorageV4 | null> {\r\n try {\r\n const path = getStoragePath();\r\n // Ensure permissions are correct on load (fixes existing files)\r\n await ensureSecurePermissions(path);\r\n\r\n const content = await fs.readFile(path, \"utf-8\");\r\n const parsed = JSON.parse(content);\r\n\r\n if (parsed.version === 1) {\r\n return migrateV3ToV4(migrateV2ToV3(migrateV1ToV2(parsed)));\r\n }\r\n if (parsed.version === 2) {\r\n return migrateV3ToV4(migrateV2ToV3(parsed));\r\n }\r\n if (parsed.version === 3) {\r\n return migrateV3ToV4(parsed);\r\n }\r\n\r\n return {\r\n ...parsed,\r\n accounts: deduplicateAccountsByEmail(parsed.accounts),\r\n };\r\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") {\n return null;\n }\n log.error(\"Failed to load account storage (file exists but unreadable)\", {\n error: String(error),\n code: code ?? \"unknown\",\n });\n return null;\n }\n}\r\nexport async function clearAccounts(): Promise<void> {\r\n try {\r\n const path = getStoragePath();\r\n await fs.unlink(path);\r\n } catch (error) {\r\n const code = (error as NodeJS.ErrnoException).code;\r\n if (code !== \"ENOENT\") {\r\n log.error(\"Failed to clear account storage\", { error: String(error) });\r\n }\r\n }\r\n}\r\n", "/**\r\n * Structured Logger for Antigravity Plugin\r\n *\r\n * Logging behavior:\r\n * - debug controls file logs only (via debug.ts)\r\n * - debug_tui controls TUI log panel only\r\n * - either sink can be enabled independently\r\n * - OPENCODE_ANTIGRAVITY_CONSOLE_LOG=1 \u2192 console output (independent of debug flags)\r\n */\r\n\r\nimport type { PluginClient } from \"./types\";\r\nimport { isDebugTuiEnabled } from \"./debug\";\r\nimport {\r\n isTruthyFlag,\r\n writeConsoleLog,\r\n} from \"./logging-utils\";\r\n\r\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\r\n\r\nconst ENV_CONSOLE_LOG = \"OPENCODE_ANTIGRAVITY_CONSOLE_LOG\";\r\n\r\nexport interface Logger {\r\n debug(message: string, extra?: Record<string, unknown>): void;\r\n info(message: string, extra?: Record<string, unknown>): void;\r\n warn(message: string, extra?: Record<string, unknown>): void;\r\n error(message: string, extra?: Record<string, unknown>): void;\r\n}\r\n\r\nlet _client: PluginClient | null = null;\r\n\r\n/**\r\n * Check if console logging is enabled via environment variable.\r\n */\r\nfunction isConsoleLogEnabled(): boolean {\r\n return isTruthyFlag(process.env[ENV_CONSOLE_LOG]);\r\n}\r\n\r\n/**\r\n * Initialize the logger with the plugin client.\r\n * Must be called during plugin initialization to enable TUI logging.\r\n */\r\nexport function initLogger(client: PluginClient): void {\r\n _client = client;\r\n}\r\n\r\n/**\r\n * Create a logger instance for a specific module.\r\n *\r\n * @param module - The module name (e.g., \"refresh-queue\", \"transform.claude\")\r\n * @returns Logger instance with debug, info, warn, error methods\r\n *\r\n * @example\r\n * ```typescript\r\n * const log = createLogger(\"refresh-queue\");\r\n * log.debug(\"Checking tokens\", { count: 5 });\r\n * log.warn(\"Token expired\", { accountIndex: 0 });\r\n * ```\r\n */\r\nexport function createLogger(module: string): Logger {\r\n const service = `antigravity.${module}`;\r\n\r\n const log = (level: LogLevel, message: string, extra?: Record<string, unknown>): void => {\r\n // TUI logging: controlled only by debug_tui policy\r\n if (isDebugTuiEnabled()) {\r\n const app = _client?.app;\r\n if (app && typeof app.log === \"function\") {\r\n app\r\n .log({\r\n body: { service, level, message, extra },\r\n })\r\n .catch(() => {\r\n // Silently ignore logging errors\r\n });\r\n }\r\n }\r\n\r\n // Console fallback: when env var is set (independent of debug flags)\r\n if (isConsoleLogEnabled()) {\r\n const prefix = `[${service}]`;\r\n const args = extra ? [prefix, message, extra] : [prefix, message];\r\n writeConsoleLog(level, ...args);\r\n }\r\n // If neither TUI nor console logging is enabled, log is silently discarded\r\n };\r\n\r\n return {\r\n debug: (message, extra) => log(\"debug\", message, extra),\r\n info: (message, extra) => log(\"info\", message, extra),\r\n warn: (message, extra) => log(\"warn\", message, extra),\r\n error: (message, extra) => log(\"error\", message, extra),\r\n };\r\n}\r\n", "import type { OAuthAuthDetails, RefreshParts } from \"./types\";\n\r\nconst ACCESS_TOKEN_EXPIRY_BUFFER_MS = 60 * 1000;\r\n\r\nexport function isOAuthAuth(auth: unknown): auth is OAuthAuthDetails {\n return typeof auth === \"object\" && auth !== null && \"type\" in auth && auth.type === \"oauth\";\n}\n\r\n/**\r\n * Splits a packed refresh string into its constituent refresh token and project IDs.\r\n */\r\nexport function parseRefreshParts(refresh: string): RefreshParts {\r\n const [refreshToken = \"\", projectId = \"\", managedProjectId = \"\"] = (refresh ?? \"\").split(\"|\");\r\n return {\r\n refreshToken,\r\n projectId: projectId || undefined,\r\n managedProjectId: managedProjectId || undefined,\r\n };\r\n}\r\n\r\n/**\r\n * Serializes refresh token parts into the stored string format.\r\n */\r\nexport function formatRefreshParts(parts: RefreshParts): string {\r\n const projectSegment = parts.projectId ?? \"\";\r\n const base = `${parts.refreshToken}|${projectSegment}`;\r\n return parts.managedProjectId ? `${base}|${parts.managedProjectId}` : base;\r\n}\r\n\r\n/**\r\n * Determines whether an access token is expired or missing, with buffer for clock skew.\r\n */\r\nexport function accessTokenExpired(auth: OAuthAuthDetails): boolean {\r\n if (!auth.access || typeof auth.expires !== \"number\") {\r\n return true;\r\n }\r\n return auth.expires <= Date.now() + ACCESS_TOKEN_EXPIRY_BUFFER_MS;\r\n}\r\n\r\n/**\r\n * Calculates absolute expiry timestamp based on a duration.\r\n * @param requestTimeMs The local time when the request was initiated\r\n * @param expiresInSeconds The duration returned by the server\r\n */\r\nexport function calculateTokenExpiry(requestTimeMs: number, expiresInSeconds: unknown): number {\r\n const seconds = typeof expiresInSeconds === \"number\" ? expiresInSeconds : 3600;\r\n // Safety check for bad data - if it's not a positive number, treat as immediately expired\r\n if (isNaN(seconds) || seconds <= 0) {\r\n return requestTimeMs;\r\n }\r\n return requestTimeMs + seconds * 1000;\r\n}\r\n", "import { createInterface } from \"node:readline/promises\";\r\nimport { stdin as input, stdout as output } from \"node:process\";\r\nimport {\r\n showAuthMenu,\r\n showAccountDetails,\r\n isTTY,\r\n type AccountInfo,\r\n type AccountStatus,\r\n} from \"./ui/auth-menu\";\r\nimport { updateOpencodeConfig } from \"./config/updater\";\r\n\r\nexport async function promptProjectId(): Promise<string> {\r\n const rl = createInterface({ input, output });\r\n try {\r\n const answer = await rl.question(\"Project ID (leave blank to use your default project): \");\r\n return answer.trim();\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\nexport async function promptAddAnotherAccount(currentCount: number): Promise<boolean> {\r\n const rl = createInterface({ input, output });\r\n try {\r\n const answer = await rl.question(`Add another account? (${currentCount} added) (y/n): `);\r\n const normalized = answer.trim().toLowerCase();\r\n return normalized === \"y\" || normalized === \"yes\";\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\nexport type LoginMode = \"add\" | \"fresh\" | \"manage\" | \"check\" | \"verify\" | \"verify-all\" | \"cancel\";\r\n\r\nexport interface ExistingAccountInfo {\r\n email?: string;\r\n index: number;\r\n addedAt?: number;\r\n lastUsed?: number;\r\n status?: AccountStatus;\r\n isCurrentAccount?: boolean;\r\n enabled?: boolean;\r\n}\r\n\r\nexport interface LoginMenuResult {\r\n mode: LoginMode;\r\n deleteAccountIndex?: number;\r\n refreshAccountIndex?: number;\r\n toggleAccountIndex?: number;\r\n verifyAccountIndex?: number;\r\n verifyAll?: boolean;\r\n deleteAll?: boolean;\r\n}\r\n\r\nasync function promptLoginModeFallback(existingAccounts: ExistingAccountInfo[]): Promise<LoginMenuResult> {\r\n const rl = createInterface({ input, output });\r\n try {\r\n console.log(`\\n${existingAccounts.length} account(s) saved:`);\r\n for (const acc of existingAccounts) {\r\n const label = acc.email || `Account ${acc.index + 1}`;\r\n console.log(` ${acc.index + 1}. ${label}`);\r\n }\r\n console.log(\"\");\r\n\r\n while (true) {\r\n const answer = await rl.question(\"(a)dd new, (f)resh start, (c)heck quotas, (v)erify account, (va) verify all? [a/f/c/v/va]: \");\r\n const normalized = answer.trim().toLowerCase();\r\n\r\n if (normalized === \"a\" || normalized === \"add\") {\r\n return { mode: \"add\" };\r\n }\r\n if (normalized === \"f\" || normalized === \"fresh\") {\r\n return { mode: \"fresh\" };\r\n }\r\n if (normalized === \"c\" || normalized === \"check\") {\r\n return { mode: \"check\" };\r\n }\r\n if (normalized === \"v\" || normalized === \"verify\") {\r\n return { mode: \"verify\" };\r\n }\r\n if (normalized === \"va\" || normalized === \"verify-all\" || normalized === \"all\") {\r\n return { mode: \"verify-all\", verifyAll: true };\r\n }\r\n\r\n console.log(\"Please enter 'a', 'f', 'c', 'v', or 'va'.\");\r\n }\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\nexport async function promptLoginMode(existingAccounts: ExistingAccountInfo[]): Promise<LoginMenuResult> {\r\n if (!isTTY()) {\r\n return promptLoginModeFallback(existingAccounts);\r\n }\r\n\r\n const accounts: AccountInfo[] = existingAccounts.map(acc => ({\r\n email: acc.email,\r\n index: acc.index,\r\n addedAt: acc.addedAt,\r\n lastUsed: acc.lastUsed,\r\n status: acc.status,\r\n isCurrentAccount: acc.isCurrentAccount,\r\n enabled: acc.enabled,\r\n }));\r\n\r\n console.log(\"\");\r\n\r\n while (true) {\r\n const action = await showAuthMenu(accounts);\r\n\r\n switch (action.type) {\r\n case \"add\":\r\n return { mode: \"add\" };\r\n\r\n case \"check\":\r\n return { mode: \"check\" };\r\n\r\n case \"verify\":\r\n return { mode: \"verify\" };\r\n\r\n case \"verify-all\":\r\n return { mode: \"verify-all\", verifyAll: true };\r\n\r\n case \"select-account\": {\r\n const accountAction = await showAccountDetails(action.account);\r\n if (accountAction === \"delete\") {\r\n return { mode: \"add\", deleteAccountIndex: action.account.index };\r\n }\r\n if (accountAction === \"refresh\") {\r\n return { mode: \"add\", refreshAccountIndex: action.account.index };\r\n }\r\n if (accountAction === \"toggle\") {\r\n return { mode: \"manage\", toggleAccountIndex: action.account.index };\r\n }\r\n if (accountAction === \"verify\") {\r\n return { mode: \"verify\", verifyAccountIndex: action.account.index };\r\n }\r\n continue;\r\n }\r\n\r\n case \"delete-all\":\r\n return { mode: \"fresh\", deleteAll: true };\r\n\r\n case \"configure-models\": {\r\n const result = await updateOpencodeConfig();\r\n if (result.success) {\r\n console.log(`\\n\u2713 Models configured in ${result.configPath}\\n`);\r\n } else {\r\n console.log(`\\n\u2717 Failed to configure models: ${result.error}\\n`);\r\n }\r\n continue;\r\n }\r\n\r\n case \"cancel\":\r\n return { mode: \"cancel\" };\r\n }\r\n }\r\n}\r\n\r\nexport { isTTY } from \"./ui/auth-menu\";\r\nexport type { AccountStatus } from \"./ui/auth-menu\";\r\n", "/**\r\n * ANSI escape codes and key parsing for interactive CLI menus.\r\n * Works cross-platform (Windows/Mac/Linux).\r\n */\r\n\r\nexport const ANSI = {\r\n // Cursor control\r\n hide: '\\x1b[?25l',\r\n show: '\\x1b[?25h',\r\n up: (n = 1) => `\\x1b[${n}A`,\r\n down: (n = 1) => `\\x1b[${n}B`,\r\n clearLine: '\\x1b[2K',\r\n clearScreen: '\\x1b[2J',\r\n moveTo: (row: number, col: number) => `\\x1b[${row};${col}H`,\r\n \r\n // Styles\r\n cyan: '\\x1b[36m',\r\n green: '\\x1b[32m',\r\n red: '\\x1b[31m',\r\n yellow: '\\x1b[33m',\r\n dim: '\\x1b[2m',\r\n bold: '\\x1b[1m',\r\n reset: '\\x1b[0m',\r\n inverse: '\\x1b[7m',\r\n} as const;\r\n\r\nexport type KeyAction = 'up' | 'down' | 'enter' | 'escape' | 'escape-start' | null;\r\n\r\n/**\r\n * Parse raw keyboard input buffer into a key action.\r\n * Handles Windows/Mac/Linux differences in arrow key sequences.\r\n */\r\nexport function parseKey(data: Buffer): KeyAction {\r\n const s = data.toString();\r\n \r\n // Arrow keys (ANSI escape sequences)\r\n // Standard: \\x1b[A (up), \\x1b[B (down)\r\n // Application mode: \\x1bOA (up), \\x1bOB (down)\r\n if (s === '\\x1b[A' || s === '\\x1bOA') return 'up';\r\n if (s === '\\x1b[B' || s === '\\x1bOB') return 'down';\r\n \r\n // Enter (CR or LF)\r\n if (s === '\\r' || s === '\\n') return 'enter';\r\n \r\n if (s === '\\x03') return 'escape';\r\n \r\n if (s === '\\x1b') return 'escape-start';\r\n \r\n return null;\r\n}\r\n\r\n/**\r\n * Check if the terminal supports interactive input.\r\n */\r\nexport function isTTY(): boolean {\r\n return Boolean(process.stdin.isTTY);\r\n}\r\n", "import { ANSI, isTTY, parseKey } from './ansi';\r\n\r\nexport interface MenuItem<T = string> {\r\n label: string;\r\n value: T;\r\n hint?: string;\r\n disabled?: boolean;\r\n separator?: boolean;\r\n /** Non-selectable label row (section heading). */\r\n kind?: 'heading';\r\n color?: 'red' | 'green' | 'yellow' | 'cyan';\r\n}\r\n\r\nexport interface SelectOptions {\r\n message: string;\r\n subtitle?: string;\r\n /** Override the help line shown at the bottom of the menu. */\r\n help?: string;\r\n /**\r\n * Clear the terminal before each render (opt-in).\r\n * Useful for nested flows where previous logs make menus feel cluttered.\r\n */\r\n clearScreen?: boolean;\r\n}\r\n\r\nconst ESCAPE_TIMEOUT_MS = 50;\r\n\r\nconst ANSI_REGEX = new RegExp(\"\\\\x1b\\\\[[0-9;]*m\", \"g\");\r\nconst ANSI_LEADING_REGEX = new RegExp(\"^\\\\x1b\\\\[[0-9;]*m\");\r\n\r\nfunction stripAnsi(input: string): string {\r\n return input.replace(ANSI_REGEX, '');\r\n}\r\n\r\nfunction truncateAnsi(input: string, maxVisibleChars: number): string {\r\n if (maxVisibleChars <= 0) return '';\r\n\r\n const visible = stripAnsi(input);\r\n if (visible.length <= maxVisibleChars) return input;\r\n\r\n const suffix = maxVisibleChars >= 3 ? '...' : '.'.repeat(maxVisibleChars);\r\n const keep = Math.max(0, maxVisibleChars - suffix.length);\r\n\r\n let out = '';\r\n let i = 0;\r\n let kept = 0;\r\n\r\n while (i < input.length && kept < keep) {\r\n // Preserve ANSI sequences without counting them.\r\n if (input[i] === '\\x1b') {\r\n const m = input.slice(i).match(ANSI_LEADING_REGEX);\r\n if (m) {\r\n out += m[0];\r\n i += m[0].length;\r\n continue;\r\n }\r\n }\r\n\r\n out += input[i];\r\n i += 1;\r\n kept += 1;\r\n }\r\n\r\n if (out.includes('\\x1b[')) {\r\n return `${out}${ANSI.reset}${suffix}`;\r\n }\r\n\r\n return out + suffix;\r\n}\r\n\r\nfunction getColorCode(color: MenuItem['color']): string {\r\n switch (color) {\r\n case 'red': return ANSI.red;\r\n case 'green': return ANSI.green;\r\n case 'yellow': return ANSI.yellow;\r\n case 'cyan': return ANSI.cyan;\r\n default: return '';\r\n }\r\n}\r\n\r\nexport async function select<T>(\r\n items: MenuItem<T>[],\r\n options: SelectOptions\r\n): Promise<T | null> {\r\n if (!isTTY()) {\r\n throw new Error('Interactive select requires a TTY terminal');\r\n }\r\n\r\n if (items.length === 0) {\r\n throw new Error('No menu items provided');\r\n }\r\n\r\n const isSelectable = (i: MenuItem<T>) => !i.disabled && !i.separator && i.kind !== 'heading';\r\n const enabledItems = items.filter(isSelectable);\r\n if (enabledItems.length === 0) {\r\n throw new Error('All items disabled');\r\n }\r\n\r\n if (enabledItems.length === 1) {\r\n return enabledItems[0]!.value;\r\n }\r\n\r\n const { message, subtitle } = options;\r\n const { stdin, stdout } = process;\r\n\r\n let cursor = items.findIndex(isSelectable);\r\n if (cursor === -1) cursor = 0; // Fallback, though validation above should prevent this\r\n let escapeTimeout: ReturnType<typeof setTimeout> | null = null;\r\n let isCleanedUp = false;\r\n let renderedLines = 0;\r\n\r\n const render = () => {\r\n const columns = stdout.columns ?? 80;\r\n const rows = stdout.rows ?? 24;\r\n const shouldClearScreen = options.clearScreen === true;\r\n const previousRenderedLines = renderedLines;\r\n\r\n if (shouldClearScreen) {\r\n stdout.write(ANSI.clearScreen + ANSI.moveTo(1, 1));\r\n } else if (previousRenderedLines > 0) {\r\n stdout.write(ANSI.up(previousRenderedLines));\r\n }\r\n\r\n let linesWritten = 0;\r\n const writeLine = (line: string) => {\r\n stdout.write(`${ANSI.clearLine}${line}\\n`);\r\n linesWritten += 1;\r\n };\r\n\r\n // Subtitle renders as 3 lines:\r\n // 1) blank \"\u2502\" spacer, 2) subtitle line, 3) blank line. Header is counted separately.\r\n const subtitleLines = subtitle ? 3 : 0;\r\n const fixedLines = 1 + subtitleLines + 2; // header + subtitle + (help + bottom)\r\n // Keep a small safety margin so the final newline doesn't scroll the terminal.\r\n const maxVisibleItems = Math.max(1, Math.min(items.length, rows - fixedLines - 1));\r\n\r\n // If the menu is taller than the viewport, only render a window around the cursor.\r\n // This prevents terminal scrollback spam (e.g. repeated headers when pressing arrows).\r\n let windowStart = 0;\r\n let windowEnd = items.length;\r\n if (items.length > maxVisibleItems) {\r\n windowStart = cursor - Math.floor(maxVisibleItems / 2);\r\n windowStart = Math.max(0, Math.min(windowStart, items.length - maxVisibleItems));\r\n windowEnd = windowStart + maxVisibleItems;\r\n }\r\n\r\n const visibleItems = items.slice(windowStart, windowEnd);\r\n const headerMessage = truncateAnsi(message, Math.max(1, columns - 4));\r\n writeLine(`${ANSI.dim}\u250C ${ANSI.reset}${headerMessage}`);\r\n \r\n if (subtitle) {\r\n writeLine(`${ANSI.dim}\u2502${ANSI.reset}`);\r\n const sub = truncateAnsi(subtitle, Math.max(1, columns - 4));\r\n writeLine(`${ANSI.cyan}\u25C6${ANSI.reset} ${sub}`);\r\n writeLine(\"\");\r\n }\r\n\r\n for (let i = 0; i < visibleItems.length; i++) {\r\n const itemIndex = windowStart + i;\r\n const item = visibleItems[i];\r\n if (!item) continue;\r\n\r\n if (item.separator) {\r\n writeLine(`${ANSI.dim}\u2502${ANSI.reset}`);\r\n continue;\r\n }\r\n\r\n if (item.kind === 'heading') {\r\n const heading = truncateAnsi(`${ANSI.dim}${ANSI.bold}${item.label}${ANSI.reset}`, Math.max(1, columns - 6));\r\n writeLine(`${ANSI.cyan}\u2502${ANSI.reset} ${heading}`);\r\n continue;\r\n }\r\n\r\n const isSelected = itemIndex === cursor;\r\n const colorCode = getColorCode(item.color);\r\n\r\n let labelText: string;\r\n if (item.disabled) {\r\n labelText = `${ANSI.dim}${item.label} (unavailable)${ANSI.reset}`;\r\n } else if (isSelected) {\r\n labelText = colorCode ? `${colorCode}${item.label}${ANSI.reset}` : item.label;\r\n if (item.hint) labelText += ` ${ANSI.dim}${item.hint}${ANSI.reset}`;\r\n } else {\r\n labelText = colorCode \r\n ? `${ANSI.dim}${colorCode}${item.label}${ANSI.reset}` \r\n : `${ANSI.dim}${item.label}${ANSI.reset}`;\r\n if (item.hint) labelText += ` ${ANSI.dim}${item.hint}${ANSI.reset}`;\r\n }\r\n\r\n // Prevent wrapping: cursor positioning relies on a fixed line count.\r\n labelText = truncateAnsi(labelText, Math.max(1, columns - 8));\r\n\r\n if (isSelected) {\r\n writeLine(`${ANSI.cyan}\u2502${ANSI.reset} ${ANSI.green}\u25CF${ANSI.reset} ${labelText}`);\r\n } else {\r\n writeLine(`${ANSI.cyan}\u2502${ANSI.reset} ${ANSI.dim}\u25CB${ANSI.reset} ${labelText}`);\r\n }\r\n }\r\n\r\n const windowHint = items.length > visibleItems.length\r\n ? ` (${windowStart + 1}-${windowEnd}/${items.length})`\r\n : '';\r\n const helpText = options.help ?? `Up/Down to select | Enter: confirm | Esc: back${windowHint}`;\r\n const help = truncateAnsi(helpText, Math.max(1, columns - 6));\r\n writeLine(`${ANSI.cyan}\u2502${ANSI.reset} ${ANSI.dim}${help}${ANSI.reset}`);\r\n writeLine(`${ANSI.cyan}\u2514${ANSI.reset}`);\r\n\r\n if (!shouldClearScreen && previousRenderedLines > linesWritten) {\r\n const extra = previousRenderedLines - linesWritten;\r\n for (let i = 0; i < extra; i++) {\r\n writeLine(\"\");\r\n }\r\n }\r\n\r\n renderedLines = linesWritten;\r\n };\r\n\r\n return new Promise((resolve) => {\r\n const wasRaw = stdin.isRaw ?? false;\r\n\r\n const cleanup = () => {\r\n if (isCleanedUp) return;\r\n isCleanedUp = true;\r\n\r\n if (escapeTimeout) {\r\n clearTimeout(escapeTimeout);\r\n escapeTimeout = null;\r\n }\r\n\r\n try {\r\n stdin.removeListener('data', onKey);\r\n stdin.setRawMode(wasRaw);\r\n stdin.pause();\r\n stdout.write(ANSI.show);\r\n } catch {\r\n // Intentionally ignored - cleanup is best-effort\r\n }\r\n\r\n process.removeListener('SIGINT', onSignal);\r\n process.removeListener('SIGTERM', onSignal);\r\n };\r\n\r\n const onSignal = () => {\r\n cleanup();\r\n resolve(null);\r\n };\r\n\r\n const finishWithValue = (value: T | null) => {\r\n cleanup();\r\n resolve(value);\r\n };\r\n\r\n const findNextSelectable = (from: number, direction: 1 | -1): number => {\r\n if (items.length === 0) return from;\r\n \r\n let next = from;\r\n do {\r\n next = (next + direction + items.length) % items.length;\r\n } while (items[next]?.disabled || items[next]?.separator || items[next]?.kind === 'heading');\r\n return next;\r\n };\r\n\r\n const onKey = (data: Buffer) => {\r\n if (escapeTimeout) {\r\n clearTimeout(escapeTimeout);\r\n escapeTimeout = null;\r\n }\r\n\r\n const action = parseKey(data);\r\n\r\n switch (action) {\r\n case 'up':\r\n cursor = findNextSelectable(cursor, -1);\r\n render();\r\n return;\r\n case 'down':\r\n cursor = findNextSelectable(cursor, 1);\r\n render();\r\n return;\r\n case 'enter':\r\n finishWithValue(items[cursor]?.value ?? null);\r\n return;\r\n case 'escape':\r\n finishWithValue(null);\r\n return;\r\n case 'escape-start':\r\n // Bare escape byte - wait to see if more bytes coming (arrow key sequence)\r\n escapeTimeout = setTimeout(() => {\r\n finishWithValue(null);\r\n }, ESCAPE_TIMEOUT_MS);\r\n return;\r\n default:\r\n // Unknown key - ignore\r\n return;\r\n }\r\n };\r\n\r\n process.once('SIGINT', onSignal);\r\n process.once('SIGTERM', onSignal);\r\n\r\n try {\r\n stdin.setRawMode(true);\r\n } catch {\r\n // Failed to enable raw mode - cleanup and return null\r\n cleanup();\r\n resolve(null);\r\n return;\r\n }\r\n\r\n stdin.resume();\r\n stdout.write(ANSI.hide);\r\n render();\r\n\r\n stdin.on('data', onKey);\r\n });\r\n}\r\n", "import { select } from './select';\r\n\r\nexport async function confirm(message: string, defaultYes = false): Promise<boolean> {\r\n const items = defaultYes\r\n ? [\r\n { label: 'Yes', value: true },\r\n { label: 'No', value: false },\r\n ]\r\n : [\r\n { label: 'No', value: false },\r\n { label: 'Yes', value: true },\r\n ];\r\n\r\n const result = await select(items, { message });\r\n return result ?? false;\r\n}\r\n", "import { ANSI } from './ansi';\r\nimport { select, type MenuItem } from './select';\r\nimport { confirm } from './confirm';\r\n\r\nexport type AccountStatus = 'active' | 'rate-limited' | 'expired' | 'verification-required' | 'unknown';\r\n\r\nexport interface AccountInfo {\r\n email?: string;\r\n index: number;\r\n addedAt?: number;\r\n lastUsed?: number;\r\n status?: AccountStatus;\r\n isCurrentAccount?: boolean;\r\n enabled?: boolean;\r\n}\r\n\r\nexport type AuthMenuAction =\r\n | { type: 'add' }\r\n | { type: 'select-account'; account: AccountInfo }\r\n | { type: 'delete-all' }\r\n | { type: 'check' }\r\n | { type: 'verify' }\r\n | { type: 'verify-all' }\r\n | { type: 'configure-models' }\r\n | { type: 'cancel' };\r\n\r\nexport type AccountAction = 'back' | 'delete' | 'refresh' | 'toggle' | 'verify' | 'cancel';\r\n\r\nfunction formatRelativeTime(timestamp: number | undefined): string {\r\n if (!timestamp) return 'never';\r\n const days = Math.floor((Date.now() - timestamp) / 86400000);\r\n if (days === 0) return 'today';\r\n if (days === 1) return 'yesterday';\r\n if (days < 7) return `${days}d ago`;\r\n if (days < 30) return `${Math.floor(days / 7)}w ago`;\r\n return new Date(timestamp).toLocaleDateString();\r\n}\r\n\r\nfunction formatDate(timestamp: number | undefined): string {\r\n if (!timestamp) return 'unknown';\r\n return new Date(timestamp).toLocaleDateString();\r\n}\r\n\r\nfunction getStatusBadge(status: AccountStatus | undefined): string {\r\n switch (status) {\r\n case 'active': return `${ANSI.green}[active]${ANSI.reset}`;\r\n case 'rate-limited': return `${ANSI.yellow}[rate-limited]${ANSI.reset}`;\r\n case 'expired': return `${ANSI.red}[expired]${ANSI.reset}`;\r\n case 'verification-required': return `${ANSI.red}[needs verification]${ANSI.reset}`;\r\n default: return '';\r\n }\r\n}\r\n\r\nexport async function showAuthMenu(accounts: AccountInfo[]): Promise<AuthMenuAction> {\r\n const items: MenuItem<AuthMenuAction>[] = [\r\n { label: 'Actions', value: { type: 'cancel' }, kind: 'heading' },\r\n { label: 'Add account', value: { type: 'add' }, color: 'cyan' },\r\n { label: 'Check quotas', value: { type: 'check' }, color: 'cyan' },\r\n { label: 'Verify one account', value: { type: 'verify' }, color: 'cyan' },\r\n { label: 'Verify all accounts', value: { type: 'verify-all' }, color: 'cyan' },\r\n { label: 'Configure models in opencode.json', value: { type: 'configure-models' }, color: 'cyan' },\r\n\r\n { label: '', value: { type: 'cancel' }, separator: true },\r\n\r\n { label: 'Accounts', value: { type: 'cancel' }, kind: 'heading' },\r\n\r\n ...accounts.map(account => {\r\n const statusBadge = getStatusBadge(account.status);\r\n const currentBadge = account.isCurrentAccount ? ` ${ANSI.cyan}[current]${ANSI.reset}` : '';\r\n const disabledBadge = account.enabled === false ? ` ${ANSI.red}[disabled]${ANSI.reset}` : '';\r\n const baseLabel = account.email || `Account ${account.index + 1}`;\r\n const numbered = `${account.index + 1}. ${baseLabel}`;\r\n const fullLabel = `${numbered}${currentBadge}${statusBadge ? ' ' + statusBadge : ''}${disabledBadge}`;\r\n\r\n return {\r\n label: fullLabel,\r\n hint: account.lastUsed ? `used ${formatRelativeTime(account.lastUsed)}` : '',\r\n value: { type: 'select-account' as const, account },\r\n };\r\n }),\r\n\r\n { label: '', value: { type: 'cancel' }, separator: true },\r\n\r\n { label: 'Danger zone', value: { type: 'cancel' }, kind: 'heading' },\r\n { label: 'Delete all accounts', value: { type: 'delete-all' }, color: 'red' as const },\r\n ];\r\n\r\n while (true) {\r\n const result = await select(items, { \r\n message: 'Google accounts (Antigravity)',\r\n subtitle: 'Select an action or account',\r\n clearScreen: true,\r\n });\r\n\r\n if (!result) return { type: 'cancel' };\r\n\r\n if (result.type === 'delete-all') {\r\n const confirmed = await confirm('Delete ALL accounts? This cannot be undone.');\r\n if (!confirmed) continue;\r\n }\r\n\r\n return result;\r\n }\r\n}\r\n\r\nexport async function showAccountDetails(account: AccountInfo): Promise<AccountAction> {\r\n const label = account.email || `Account ${account.index + 1}`;\r\n const badge = getStatusBadge(account.status);\r\n const disabledBadge = account.enabled === false ? ` ${ANSI.red}[disabled]${ANSI.reset}` : '';\r\n const header = `${label}${badge ? ' ' + badge : ''}${disabledBadge}`;\r\n const subtitleParts = [\r\n `Added: ${formatDate(account.addedAt)}`,\r\n `Last used: ${formatRelativeTime(account.lastUsed)}`,\r\n ];\r\n\r\n while (true) {\r\n const result = await select([\r\n { label: 'Back', value: 'back' as const },\r\n { label: 'Verify account access', value: 'verify' as const, color: 'cyan' },\r\n { label: account.enabled === false ? 'Enable account' : 'Disable account', value: 'toggle' as const, color: account.enabled === false ? 'green' : 'yellow' },\r\n { label: 'Refresh token', value: 'refresh' as const, color: 'cyan' },\r\n { label: 'Delete this account', value: 'delete' as const, color: 'red' },\r\n ], { \r\n message: header,\r\n subtitle: subtitleParts.join(' | '),\r\n clearScreen: true,\r\n });\r\n\r\n if (result === 'delete') {\r\n const confirmed = await confirm(`Delete ${label}?`);\r\n if (!confirmed) continue;\r\n }\r\n\r\n if (result === 'refresh') {\r\n const confirmed = await confirm(`Re-authenticate ${label}?`);\r\n if (!confirmed) continue;\r\n }\r\n\r\n return result ?? 'cancel';\r\n }\r\n}\r\n\r\nexport { isTTY } from './ansi';\r\n", "/**\r\n * OpenCode configuration file updater.\r\n *\r\n * Updates ~/.config/opencode/opencode.json(c) with plugin models.\r\n */\r\n\r\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\r\nimport { join, dirname } from \"node:path\";\r\nimport { homedir } from \"node:os\";\r\nimport { OPENCODE_MODEL_DEFINITIONS } from \"./models\";\r\n\r\n// =============================================================================\r\n// Types\r\n// =============================================================================\r\n\r\nexport interface UpdateConfigResult {\r\n success: boolean;\r\n configPath: string;\r\n error?: string;\r\n}\r\n\r\nexport interface OpencodeConfig {\r\n $schema?: string;\r\n plugin?: string[];\r\n provider?: {\r\n google?: {\r\n models?: Record<string, unknown>;\r\n [key: string]: unknown;\r\n };\r\n [key: string]: unknown;\r\n };\r\n [key: string]: unknown;\r\n}\r\n\r\nexport interface UpdateConfigOptions {\r\n /** Override the config file path (for testing) */\r\n configPath?: string;\r\n}\r\n\r\n// =============================================================================\r\n// Constants\r\n// =============================================================================\r\n\r\nconst PLUGIN_NAME = \"@expiren/opencode-antigravity-auth@latest\";\r\nconst SCHEMA_URL = \"https://opencode.ai/config.json\";\r\nconst OPENCODE_JSON_FILENAME = \"opencode.json\";\r\nconst OPENCODE_JSONC_FILENAME = \"opencode.jsonc\";\r\n\r\nfunction stripJsonCommentsAndTrailingCommas(json: string): string {\r\n return json\r\n .replace(\r\n /\\\\\"|\"(?:\\\\\"|[^\"])*\"|(\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\/)/g,\r\n (match: string, group: string | undefined) => (group ? \"\" : match)\r\n )\r\n .replace(/,(\\s*[}\\]])/g, \"$1\");\r\n}\r\n\r\n/**\r\n * Get the opencode config directory path.\r\n */\r\nexport function getOpencodeConfigDir(): string {\r\n const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), \".config\");\r\n return join(xdgConfig, \"opencode\");\r\n}\r\n\r\n/**\r\n * Get the opencode config file path.\r\n *\r\n * Prefers opencode.jsonc when present so we update the active config file\r\n * instead of creating a new opencode.json.\r\n */\r\nexport function getOpencodeConfigPath(): string {\r\n const configDir = getOpencodeConfigDir();\r\n const jsoncPath = join(configDir, OPENCODE_JSONC_FILENAME);\r\n const jsonPath = join(configDir, OPENCODE_JSON_FILENAME);\r\n\r\n if (existsSync(jsoncPath)) {\r\n return jsoncPath;\r\n }\r\n if (existsSync(jsonPath)) {\r\n return jsonPath;\r\n }\r\n\r\n return jsonPath;\r\n}\r\n\r\n// =============================================================================\r\n// Main Function\r\n// =============================================================================\r\n\r\n/**\r\n * Updates the opencode configuration file with plugin models.\r\n *\r\n * This function:\r\n * 1. Reads existing opencode.json/opencode.jsonc (or creates default structure)\r\n * 2. Replaces `provider.google.models` with plugin models\r\n * 3. Writes back to disk with proper formatting\r\n *\r\n * Preserves:\r\n * - $schema and other top-level config keys\r\n * - Non-google provider sections\r\n * - Other settings within google provider (except models)\r\n *\r\n * @param options - Optional configuration (e.g., custom configPath for testing)\r\n * @returns UpdateConfigResult with success status and path\r\n */\r\nexport async function updateOpencodeConfig(\r\n options: UpdateConfigOptions = {}\r\n): Promise<UpdateConfigResult> {\r\n const configPath = options.configPath ?? getOpencodeConfigPath();\r\n\r\n try {\r\n let config: OpencodeConfig;\r\n\r\n // Read existing config or create default\r\n if (existsSync(configPath)) {\r\n const content = readFileSync(configPath, \"utf-8\");\r\n config = JSON.parse(stripJsonCommentsAndTrailingCommas(content)) as OpencodeConfig;\r\n } else {\r\n // Create default config structure\r\n config = {\r\n $schema: SCHEMA_URL,\r\n plugin: [],\r\n provider: {},\r\n };\r\n }\r\n\r\n // Ensure $schema is set\r\n if (!config.$schema) {\r\n config.$schema = SCHEMA_URL;\r\n }\r\n\r\n // Ensure plugin array exists and contains our plugin\r\n if (!Array.isArray(config.plugin)) {\r\n config.plugin = [];\r\n }\r\n\r\n // Check if plugin is already in the list (any version)\r\n const hasPlugin = config.plugin.some((p) =>\r\n p.includes(\"opencode-antigravity-auth\")\r\n );\r\n if (!hasPlugin) {\r\n config.plugin.push(PLUGIN_NAME);\r\n }\r\n\r\n // Ensure provider.google structure exists\r\n if (!config.provider) {\r\n config.provider = {};\r\n }\r\n if (!config.provider.google) {\r\n config.provider.google = {};\r\n }\r\n\r\n // Replace google models with plugin models\r\n config.provider.google.models = { ...OPENCODE_MODEL_DEFINITIONS };\r\n\r\n // Ensure config directory exists\r\n const configDir = dirname(configPath);\r\n if (!existsSync(configDir)) {\r\n mkdirSync(configDir, { recursive: true });\r\n }\r\n\r\n // Write config with proper formatting (2-space indent)\r\n writeFileSync(configPath, JSON.stringify(config, null, 2), \"utf-8\");\r\n\r\n return {\r\n success: true,\r\n configPath,\r\n };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n configPath,\r\n error: error instanceof Error ? error.message : String(error),\r\n };\r\n }\r\n}\r\n", "import type { ProviderModel } from \"../types\";\r\n\r\nexport type ModelThinkingLevel = \"minimal\" | \"low\" | \"medium\" | \"high\";\r\n\r\nexport interface ModelThinkingConfig {\r\n thinkingBudget: number;\r\n}\r\n\r\nexport interface ModelVariant {\r\n thinkingLevel?: ModelThinkingLevel;\r\n thinkingConfig?: ModelThinkingConfig;\r\n}\r\n\r\nexport interface ModelLimit {\r\n context: number;\r\n output: number;\r\n}\r\n\r\nexport type ModelModality = \"text\" | \"image\" | \"pdf\";\r\n\r\nexport interface ModelModalities {\r\n input: ModelModality[];\r\n output: ModelModality[];\r\n}\r\n\r\nexport interface OpencodeModelDefinition extends ProviderModel {\r\n name: string;\r\n limit: ModelLimit;\r\n modalities: ModelModalities;\r\n variants?: Record<string, ModelVariant>;\r\n}\r\n\r\nexport type OpencodeModelDefinitions = Record<string, OpencodeModelDefinition>;\r\n\r\nconst DEFAULT_MODALITIES: ModelModalities = {\r\n input: [\"text\", \"image\", \"pdf\"],\r\n output: [\"text\"],\r\n};\r\n\r\nexport const OPENCODE_MODEL_DEFINITIONS: OpencodeModelDefinitions = {\r\n \"antigravity-gemini-3-pro\": {\r\n name: \"Gemini 3 Pro (Antigravity)\",\r\n limit: { context: 1048576, output: 65535 },\r\n modalities: DEFAULT_MODALITIES,\r\n variants: {\r\n low: { thinkingLevel: \"low\" },\r\n high: { thinkingLevel: \"high\" },\r\n },\r\n },\r\n \"antigravity-gemini-3.1-pro\": {\r\n name: \"Gemini 3.1 Pro (Antigravity)\",\r\n limit: { context: 1048576, output: 65535 },\r\n modalities: DEFAULT_MODALITIES,\r\n variants: {\r\n low: { thinkingLevel: \"low\" },\r\n high: { thinkingLevel: \"high\" },\r\n },\r\n },\r\n \"antigravity-gemini-3-flash\": {\r\n name: \"Gemini 3 Flash (Antigravity)\",\r\n limit: { context: 1048576, output: 65536 },\r\n modalities: DEFAULT_MODALITIES,\r\n variants: {\r\n minimal: { thinkingLevel: \"minimal\" },\r\n low: { thinkingLevel: \"low\" },\r\n medium: { thinkingLevel: \"medium\" },\r\n high: { thinkingLevel: \"high\" },\r\n },\r\n },\r\n \"antigravity-claude-sonnet-4-6\": {\r\n name: \"Claude Sonnet 4.6 (Antigravity)\",\r\n limit: { context: 200000, output: 64000 },\r\n modalities: DEFAULT_MODALITIES,\r\n },\r\n \"antigravity-claude-opus-4-6-thinking\": {\r\n name: \"Claude Opus 4.6 Thinking (Antigravity)\",\r\n limit: { context: 200000, output: 64000 },\r\n modalities: DEFAULT_MODALITIES,\r\n variants: {\r\n low: { thinkingConfig: { thinkingBudget: 8192 } },\r\n max: { thinkingConfig: { thinkingBudget: 32768 } },\r\n },\r\n },\r\n \"gemini-2.5-flash\": {\r\n name: \"Gemini 2.5 Flash (Gemini CLI)\",\r\n limit: { context: 1048576, output: 65536 },\r\n modalities: DEFAULT_MODALITIES,\r\n },\r\n \"gemini-2.5-pro\": {\r\n name: \"Gemini 2.5 Pro (Gemini CLI)\",\r\n limit: { context: 1048576, output: 65536 },\r\n modalities: DEFAULT_MODALITIES,\r\n },\r\n \"gemini-3-flash-preview\": {\r\n name: \"Gemini 3 Flash Preview (Gemini CLI)\",\r\n limit: { context: 1048576, output: 65536 },\r\n modalities: DEFAULT_MODALITIES,\r\n },\r\n \"gemini-3-pro-preview\": {\r\n name: \"Gemini 3 Pro Preview (Gemini CLI)\",\r\n limit: { context: 1048576, output: 65535 },\r\n modalities: DEFAULT_MODALITIES,\r\n },\r\n \"gemini-3.1-pro-preview\": {\r\n name: \"Gemini 3.1 Pro Preview (Gemini CLI)\",\r\n limit: { context: 1048576, output: 65535 },\r\n modalities: DEFAULT_MODALITIES,\r\n },\r\n \"gemini-3.1-pro-preview-customtools\": {\r\n name: \"Gemini 3.1 Pro Preview Custom Tools (Gemini CLI)\",\r\n limit: { context: 1048576, output: 65535 },\r\n modalities: DEFAULT_MODALITIES,\r\n },\r\n};\r\n", "import {\r\n getAntigravityHeaders,\r\n ANTIGRAVITY_ENDPOINT_FALLBACKS,\r\n ANTIGRAVITY_LOAD_ENDPOINTS,\r\n ANTIGRAVITY_DEFAULT_PROJECT_ID,\r\n} from \"../constants\";\r\nimport { formatRefreshParts, parseRefreshParts } from \"./auth\";\r\nimport { createLogger } from \"./logger\";\r\nimport type { OAuthAuthDetails, ProjectContextResult } from \"./types\";\r\n\r\nconst log = createLogger(\"project\");\r\n\r\n/** TTL for project context cache entries (30 minutes). */\nconst PROJECT_CONTEXT_CACHE_TTL_MS = 30 * 60 * 1000;\n\ninterface CachedProjectContext {\n result: ProjectContextResult;\n cachedAt: number;\n}\n\nconst projectContextResultCache = new Map<string, CachedProjectContext>();\nconst projectContextPendingCache = new Map<string, Promise<ProjectContextResult>>();\r\nconst CODE_ASSIST_METADATA = {\r\n ideType: \"ANTIGRAVITY\",\r\n platform: process.platform === \"win32\" ? \"WINDOWS\" : \"MACOS\",\r\n pluginType: \"GEMINI\",\r\n} as const;\r\n\r\ninterface AntigravityUserTier {\r\n id?: string;\r\n isDefault?: boolean;\r\n userDefinedCloudaicompanionProject?: boolean;\r\n}\r\n\r\ninterface LoadCodeAssistPayload {\r\n cloudaicompanionProject?: string | { id?: string };\r\n currentTier?: {\r\n id?: string;\r\n };\r\n allowedTiers?: AntigravityUserTier[];\r\n}\r\n\r\ninterface OnboardUserPayload {\r\n done?: boolean;\r\n response?: {\r\n cloudaicompanionProject?: {\r\n id?: string;\r\n };\r\n };\r\n}\r\n\r\nfunction buildMetadata(projectId?: string): Record<string, string> {\r\n const metadata: Record<string, string> = {\r\n ideType: CODE_ASSIST_METADATA.ideType,\r\n platform: CODE_ASSIST_METADATA.platform,\r\n pluginType: CODE_ASSIST_METADATA.pluginType,\r\n };\r\n if (projectId) {\r\n metadata.duetProject = projectId;\r\n }\r\n return metadata;\r\n}\r\n\r\n/**\r\n * Selects the default tier ID from the allowed tiers list.\r\n */\r\nfunction getDefaultTierId(allowedTiers?: AntigravityUserTier[]): string | undefined {\r\n if (!allowedTiers || allowedTiers.length === 0) {\r\n return undefined;\r\n }\r\n for (const tier of allowedTiers) {\r\n if (tier?.isDefault) {\r\n return tier.id;\r\n }\r\n }\r\n return allowedTiers[0]?.id;\r\n}\r\n\r\n/**\r\n * Promise-based delay utility.\r\n */\r\nfunction wait(ms: number): Promise<void> {\r\n return new Promise(function (resolve) {\r\n setTimeout(resolve, ms);\r\n });\r\n}\r\n\r\n/**\r\n * Extracts the cloudaicompanion project id from loadCodeAssist responses.\r\n */\r\nfunction extractManagedProjectId(payload: LoadCodeAssistPayload | null): string | undefined {\r\n if (!payload) {\r\n return undefined;\r\n }\r\n if (typeof payload.cloudaicompanionProject === \"string\") {\r\n return payload.cloudaicompanionProject;\r\n }\r\n if (payload.cloudaicompanionProject && typeof payload.cloudaicompanionProject.id === \"string\") {\r\n return payload.cloudaicompanionProject.id;\r\n }\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Generates a cache key for project context based on refresh token.\r\n */\r\nfunction getCacheKey(auth: OAuthAuthDetails): string | undefined {\r\n const refresh = auth.refresh?.trim();\r\n return refresh ? refresh : undefined;\r\n}\r\n\r\n/**\r\n * Clears cached project context results and pending promises, globally or for a refresh key.\r\n */\r\nexport function invalidateProjectContextCache(refresh?: string): void {\r\n if (!refresh) {\r\n projectContextPendingCache.clear();\r\n projectContextResultCache.clear();\r\n return;\r\n }\r\n projectContextPendingCache.delete(refresh);\r\n projectContextResultCache.delete(refresh);\r\n}\r\n\r\n/**\r\n * Loads managed project information for the given access token and optional project.\r\n */\r\nexport async function loadManagedProject(\r\n accessToken: string,\r\n projectId?: string,\r\n): Promise<LoadCodeAssistPayload | null> {\r\n const metadata = buildMetadata(projectId);\r\n const requestBody: Record<string, unknown> = { metadata };\r\n\r\n const loadHeaders: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: `Bearer ${accessToken}`,\r\n \"User-Agent\": \"google-api-nodejs-client/9.15.1\",\r\n \"X-Goog-Api-Client\": \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\r\n \"Client-Metadata\": getAntigravityHeaders()[\"Client-Metadata\"],\r\n };\r\n\r\n const loadEndpoints = Array.from(\r\n new Set<string>([...ANTIGRAVITY_LOAD_ENDPOINTS, ...ANTIGRAVITY_ENDPOINT_FALLBACKS]),\r\n );\r\n\r\n for (const baseEndpoint of loadEndpoints) {\r\n try {\r\n const response = await fetch(\r\n `${baseEndpoint}/v1internal:loadCodeAssist`,\r\n {\r\n method: \"POST\",\r\n headers: loadHeaders,\r\n body: JSON.stringify(requestBody),\r\n },\r\n );\r\n\r\n if (!response.ok) {\r\n continue;\r\n }\r\n\r\n return (await response.json()) as LoadCodeAssistPayload;\r\n } catch (error) {\r\n log.debug(\"Failed to load managed project\", { endpoint: baseEndpoint, error: String(error) });\r\n continue;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n\r\n/**\r\n * Onboards a managed project for the user, optionally retrying until completion.\r\n */\r\nexport async function onboardManagedProject(\r\n accessToken: string,\r\n tierId: string,\r\n projectId?: string,\r\n attempts = 10,\r\n delayMs = 5000,\r\n): Promise<string | undefined> {\r\n const metadata = buildMetadata(projectId);\r\n const requestBody: Record<string, unknown> = {\r\n tierId,\r\n metadata,\r\n };\r\n\r\n for (const baseEndpoint of ANTIGRAVITY_ENDPOINT_FALLBACKS) {\r\n for (let attempt = 0; attempt < attempts; attempt += 1) {\r\n try {\r\n const response = await fetch(\r\n `${baseEndpoint}/v1internal:onboardUser`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: `Bearer ${accessToken}`,\r\n ...getAntigravityHeaders(),\r\n },\r\n body: JSON.stringify(requestBody),\r\n },\r\n );\r\n\r\n if (!response.ok) {\r\n break;\r\n }\r\n\r\n const payload = (await response.json()) as OnboardUserPayload;\r\n const managedProjectId = payload.response?.cloudaicompanionProject?.id;\r\n if (payload.done && managedProjectId) {\r\n return managedProjectId;\r\n }\r\n if (payload.done && projectId) {\r\n return projectId;\r\n }\r\n } catch (error) {\r\n log.debug(\"Failed to onboard managed project\", { endpoint: baseEndpoint, error: String(error) });\r\n break;\r\n }\r\n\r\n await wait(delayMs);\r\n }\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Resolves an effective project ID for the current auth state, caching results per refresh token.\r\n */\r\nexport async function ensureProjectContext(auth: OAuthAuthDetails): Promise<ProjectContextResult> {\r\n const accessToken = auth.access;\r\n if (!accessToken) {\r\n return { auth, effectiveProjectId: \"\" };\r\n }\r\n\r\n const cacheKey = getCacheKey(auth);\r\n if (cacheKey) {\r\n const cached = projectContextResultCache.get(cacheKey);\n if (cached && (Date.now() - cached.cachedAt) < PROJECT_CONTEXT_CACHE_TTL_MS) {\n return cached.result;\n }\n if (cached) {\n // Expired \u2014 evict stale entry\n projectContextResultCache.delete(cacheKey);\n } const pending = projectContextPendingCache.get(cacheKey);\r\n if (pending) {\r\n return pending;\r\n }\r\n }\r\n\r\n const resolveContext = async (): Promise<ProjectContextResult> => {\r\n const parts = parseRefreshParts(auth.refresh);\r\n if (parts.managedProjectId) {\r\n return { auth, effectiveProjectId: parts.managedProjectId };\r\n }\r\n\r\n const fallbackProjectId = ANTIGRAVITY_DEFAULT_PROJECT_ID;\r\n const persistManagedProject = async (managedProjectId: string): Promise<ProjectContextResult> => {\r\n const updatedAuth: OAuthAuthDetails = {\r\n ...auth,\r\n refresh: formatRefreshParts({\r\n refreshToken: parts.refreshToken,\r\n projectId: parts.projectId,\r\n managedProjectId,\r\n }),\r\n };\r\n\r\n return { auth: updatedAuth, effectiveProjectId: managedProjectId };\r\n };\r\n\r\n // Try to resolve a managed project from Antigravity if possible.\r\n const loadPayload = await loadManagedProject(accessToken, parts.projectId ?? fallbackProjectId);\r\n const resolvedManagedProjectId = extractManagedProjectId(loadPayload);\r\n\r\n if (resolvedManagedProjectId) {\r\n return persistManagedProject(resolvedManagedProjectId);\r\n }\r\n\r\n // No managed project found - try to auto-provision one via onboarding.\r\n // This handles accounts that were added before managed project provisioning was required.\r\n const tierId = getDefaultTierId(loadPayload?.allowedTiers) ?? \"FREE\";\r\n log.debug(\"Auto-provisioning managed project\", { tierId, projectId: parts.projectId });\r\n \r\n const provisionedProjectId = await onboardManagedProject(\r\n accessToken,\r\n tierId,\r\n parts.projectId,\r\n );\r\n\r\n if (provisionedProjectId) {\r\n log.debug(\"Successfully provisioned managed project\", { provisionedProjectId });\r\n return persistManagedProject(provisionedProjectId);\r\n }\r\n\r\n log.warn(\"Failed to provision managed project - account may not work correctly\", {\r\n hasProjectId: !!parts.projectId,\r\n });\r\n\r\n if (parts.projectId) {\r\n return { auth, effectiveProjectId: parts.projectId };\r\n }\r\n\r\n // No project id present in auth; fall back to the hardcoded id for requests.\r\n return { auth, effectiveProjectId: fallbackProjectId };\r\n };\r\n\r\n if (!cacheKey) {\r\n return resolveContext();\r\n }\r\n\r\n const promise = resolveContext()\r\n .then((result) => {\r\n const nextKey = getCacheKey(result.auth) ?? cacheKey;\r\n projectContextPendingCache.delete(cacheKey);\r\n projectContextResultCache.set(nextKey, { result, cachedAt: Date.now() });\r\n if (nextKey !== cacheKey) {\r\n projectContextResultCache.delete(cacheKey);\r\n }\r\n return result;\r\n })\r\n .catch((error) => {\r\n projectContextPendingCache.delete(cacheKey);\r\n throw error;\r\n });\r\n\r\n projectContextPendingCache.set(cacheKey, promise);\r\n return promise;\r\n}\r\n", "import crypto from \"node:crypto\";\nimport {\r\n ANTIGRAVITY_ENDPOINT,\r\n GEMINI_CLI_ENDPOINT,\r\n GEMINI_CLI_HEADERS,\r\n EMPTY_SCHEMA_PLACEHOLDER_NAME,\r\n EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,\r\n SKIP_THOUGHT_SIGNATURE,\r\n getRandomizedHeaders,\r\n type HeaderStyle,\r\n} from \"../constants\";\r\nimport { cacheSignature, getCachedSignature } from \"./cache\";\r\nimport { getKeepThinking } from \"./config\";\r\nimport {\r\n createStreamingTransformer,\r\n transformSseLine,\r\n transformStreamingPayload,\r\n} from \"./core/streaming\";\r\nimport { defaultSignatureStore } from \"./stores/signature-store\";\r\nimport {\r\n DEBUG_MESSAGE_PREFIX,\r\n isDebugEnabled,\r\n isDebugTuiEnabled,\r\n logAntigravityDebugResponse,\r\n logCacheStats,\r\n type AntigravityDebugContext,\r\n} from \"./debug\";\r\nimport { createLogger } from \"./logger\";\r\nimport {\r\n cleanJSONSchemaForAntigravity,\r\n DEFAULT_THINKING_BUDGET,\r\n deepFilterThinkingBlocks,\r\n extractThinkingConfig,\r\n extractVariantThinkingConfig,\r\n extractUsageFromSsePayload,\r\n extractUsageMetadata,\r\n fixToolResponseGrouping,\r\n validateAndFixClaudeToolPairing,\r\n applyToolPairingFixes,\r\n injectParameterSignatures,\r\n injectToolHardeningInstruction,\r\n isThinkingCapableModel,\r\n normalizeThinkingConfig,\r\n parseAntigravityApiBody,\r\n resolveThinkingConfig,\r\n rewriteAntigravityPreviewAccessError,\r\n transformThinkingParts,\r\n type AntigravityApiBody,\r\n} from \"./request-helpers\";\r\nimport {\n CLAUDE_TOOL_SYSTEM_INSTRUCTION,\n CLAUDE_DESCRIPTION_PROMPT,\n} from \"../constants\";\nimport {\r\n analyzeConversationState,\r\n closeToolLoopForThinking,\r\n needsThinkingRecovery,\r\n} from \"./thinking-recovery\";\r\nimport { sanitizeCrossModelPayloadInPlace } from \"./transform/cross-model-sanitizer\";\r\nimport { isGemini3Model, isImageGenerationModel, buildImageGenerationConfig, applyGeminiTransforms } from \"./transform\";\r\nimport {\r\n resolveModelWithTier,\r\n resolveModelWithVariant,\r\n resolveModelForHeaderStyle,\r\n isClaudeModel,\r\n isClaudeThinkingModel,\r\n CLAUDE_THINKING_MAX_OUTPUT_TOKENS,\r\n type ThinkingTier,\r\n} from \"./transform\";\r\nimport { detectErrorType } from \"./recovery\";\r\nimport { getSessionFingerprint, buildFingerprintHeaders, type Fingerprint } from \"./fingerprint\";\r\nimport type { GoogleSearchConfig } from \"./transform/types\";\r\n\r\nconst log = createLogger(\"request\");\r\n\r\nconst PLUGIN_SESSION_ID = `-${crypto.randomUUID()}`;\r\n\r\nconst sessionDisplayedThinkingHashes = new Set<string>();\r\n\r\nconst MIN_SIGNATURE_LENGTH = 50;\r\n\r\nfunction buildSignatureSessionKey(\r\n sessionId: string,\r\n model?: string,\r\n conversationKey?: string,\r\n projectKey?: string,\r\n): string {\r\n const modelKey = typeof model === \"string\" && model.trim() ? model.toLowerCase() : \"unknown\";\r\n const projectPart = typeof projectKey === \"string\" && projectKey.trim()\r\n ? projectKey.trim()\r\n : \"default\";\r\n const conversationPart = typeof conversationKey === \"string\" && conversationKey.trim()\r\n ? conversationKey.trim()\r\n : \"default\";\r\n return `${sessionId}:${modelKey}:${projectPart}:${conversationPart}`;\r\n}\n\n/**\n * JSON.stringify replacer \u2014 operates AT the serialization layer.\n * Every key-value pair passes through this function during stringify.\n * Nothing can bypass it \u2014 no code path, no nesting depth, no object structure.\n *\n * Preserves Schema objects in tool declarations (e.g., {type: \"boolean\"})\n * by checking for JSON Schema primitive types. Everything else that's\n * a non-string `thinking` value gets flattened to \"\".\n */\nconst JSON_SCHEMA_TYPES = new Set([\"boolean\", \"string\", \"number\", \"integer\", \"array\", \"object\"])\n\nfunction thinkingSafeReplacer(key: string, value: unknown): unknown {\n if (key === \"thinking\" && typeof value === \"object\" && value !== null) {\n // Preserve Schema objects in tool declarations (e.g., {type: \"boolean\"})\n const rec = value as Record<string, unknown>\n if (typeof rec.type === \"string\" && JSON_SCHEMA_TYPES.has(rec.type)) {\n return value\n }\n // Flatten any non-string, non-Schema thinking to empty string\n return \"\"\n }\n return value\n}\n\n/** Stringify with built-in thinking sanitization. Impossible to bypass. */\nfunction ensureThinkingFields(obj: unknown): void {\n if (!obj || typeof obj !== \"object\") return\n if (Array.isArray(obj)) {\n for (const item of obj) ensureThinkingFields(item)\n return\n }\n const rec = obj as Record<string, unknown>\n // Fix: check for missing OR undefined OR non-string thinking field.\n // JSON.stringify silently drops undefined values, so key-exists-but-undefined\n // produces { type: \"thinking\", signature: \"...\" } with NO thinking field.\n if (rec.type === \"thinking\" && typeof rec.thinking !== \"string\") {\n rec.thinking = \"\"\n }\n if (rec.thought === true && typeof rec.text !== \"string\") {\n rec.text = \"\"\n }\n for (const val of Object.values(rec)) {\n ensureThinkingFields(val)\n }\n}\n\nfunction safeStringify(obj: unknown): string {\n ensureThinkingFields(obj)\n return JSON.stringify(obj, thinkingSafeReplacer)\n}\n\n\r\n\r\n\r\n\r\nfunction shouldCacheThinkingSignatures(model?: string): boolean {\r\n if (typeof model !== \"string\") return false;\r\n const lower = model.toLowerCase();\r\n // Both Claude and Gemini 3 models require thought signature caching\r\n // for multi-turn conversations with function calling\r\n return lower.includes(\"claude\") || lower.includes(\"gemini-3\");\r\n}\r\n\r\nfunction hashConversationSeed(seed: string): string {\r\n return crypto.createHash(\"sha256\").update(seed, \"utf8\").digest(\"hex\").slice(0, 16);\r\n}\r\n\r\nfunction extractTextFromContent(content: unknown): string {\r\n if (typeof content === \"string\") {\r\n return content;\r\n }\r\n if (!Array.isArray(content)) {\r\n return \"\";\r\n }\r\n for (const block of content) {\r\n if (!block || typeof block !== \"object\") {\r\n continue;\r\n }\r\n const anyBlock = block as any;\r\n if (typeof anyBlock.text === \"string\") {\r\n return anyBlock.text;\r\n }\r\n if (anyBlock.text && typeof anyBlock.text === \"object\" && typeof anyBlock.text.text === \"string\") {\r\n return anyBlock.text.text;\r\n }\r\n }\r\n return \"\";\r\n}\r\n\r\nfunction extractConversationSeedFromMessages(messages: any[]): string {\r\n const system = messages.find((message) => message?.role === \"system\");\r\n const users = messages.filter((message) => message?.role === \"user\");\r\n const firstUser = users[0];\r\n const lastUser = users.length > 0 ? users[users.length - 1] : undefined;\r\n const systemText = system ? extractTextFromContent(system.content) : \"\";\r\n const userText = firstUser ? extractTextFromContent(firstUser.content) : \"\";\r\n const fallbackUserText = !userText && lastUser ? extractTextFromContent(lastUser.content) : \"\";\r\n return [systemText, userText || fallbackUserText].filter(Boolean).join(\"|\");\r\n}\r\n\r\nfunction extractConversationSeedFromContents(contents: any[]): string {\r\n const users = contents.filter((content) => content?.role === \"user\");\r\n const firstUser = users[0];\r\n const lastUser = users.length > 0 ? users[users.length - 1] : undefined;\r\n const primaryUser = firstUser && Array.isArray(firstUser.parts) ? extractTextFromContent(firstUser.parts) : \"\";\r\n if (primaryUser) {\r\n return primaryUser;\r\n }\r\n if (lastUser && Array.isArray(lastUser.parts)) {\r\n return extractTextFromContent(lastUser.parts);\r\n }\r\n return \"\";\r\n}\r\n\r\nfunction resolveConversationKey(requestPayload: Record<string, unknown>): string | undefined {\r\n const anyPayload = requestPayload as any;\r\n const candidates = [\r\n anyPayload.conversationId,\r\n anyPayload.conversation_id,\r\n anyPayload.thread_id,\r\n anyPayload.threadId,\r\n anyPayload.chat_id,\r\n anyPayload.chatId,\r\n anyPayload.sessionId,\r\n anyPayload.session_id,\r\n anyPayload.metadata?.conversation_id,\r\n anyPayload.metadata?.conversationId,\r\n anyPayload.metadata?.thread_id,\r\n anyPayload.metadata?.threadId,\r\n ];\r\n\r\n for (const candidate of candidates) {\r\n if (typeof candidate === \"string\" && candidate.trim()) {\r\n return candidate.trim();\r\n }\r\n }\r\n\r\n const systemSeed = extractTextFromContent(\r\n (anyPayload.systemInstruction as any)?.parts\r\n ?? anyPayload.systemInstruction\r\n ?? anyPayload.system\r\n ?? anyPayload.system_instruction,\r\n );\r\n const messageSeed = Array.isArray(anyPayload.messages)\r\n ? extractConversationSeedFromMessages(anyPayload.messages)\r\n : Array.isArray(anyPayload.contents)\r\n ? extractConversationSeedFromContents(anyPayload.contents)\r\n : \"\";\r\n const seed = [systemSeed, messageSeed].filter(Boolean).join(\"|\");\r\n if (!seed) {\r\n return undefined;\r\n }\r\n return `seed-${hashConversationSeed(seed)}`;\r\n}\r\n\r\nfunction resolveConversationKeyFromRequests(requestObjects: Array<Record<string, unknown>>): string | undefined {\r\n for (const req of requestObjects) {\r\n const key = resolveConversationKey(req);\r\n if (key) {\r\n return key;\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction resolveProjectKey(candidate?: unknown, fallback?: string): string | undefined {\r\n if (typeof candidate === \"string\" && candidate.trim()) {\r\n return candidate.trim();\r\n }\r\n if (typeof fallback === \"string\" && fallback.trim()) {\r\n return fallback.trim();\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction formatDebugLinesForThinking(lines: string[]): string {\r\n const cleaned = lines\r\n .map((line) => line.trim())\r\n .filter((line) => line.length > 0)\r\n .slice(-50);\r\n const prelude = `[ThinkingResolution] source=debug_tui lines=${cleaned.length}`;\r\n return `${DEBUG_MESSAGE_PREFIX}\\n- ${prelude}\\n${cleaned.map((line) => `- ${line}`).join(\"\\n\")}`;\r\n}\r\n\r\nfunction injectDebugThinking(response: unknown, debugText: string): unknown {\r\n if (!response || typeof response !== \"object\") {\r\n return response;\r\n }\r\n\r\n const resp = response as any;\r\n\r\n if (Array.isArray(resp.candidates) && resp.candidates.length > 0) {\r\n const candidates = resp.candidates.slice();\r\n const first = candidates[0];\r\n\r\n if (\r\n first &&\r\n typeof first === \"object\" &&\r\n first.content &&\r\n typeof first.content === \"object\" &&\r\n Array.isArray(first.content.parts)\r\n ) {\r\n const parts = [{ thought: true, text: debugText }, ...first.content.parts];\r\n candidates[0] = { ...first, content: { ...first.content, parts } };\r\n return { ...resp, candidates };\r\n }\r\n\r\n return resp;\r\n }\r\n\r\n if (Array.isArray(resp.content)) {\r\n const content = [{ type: \"thinking\", thinking: debugText }, ...resp.content];\r\n return { ...resp, content };\r\n }\r\n\r\n if (!resp.reasoning_content) {\r\n return { ...resp, reasoning_content: debugText };\r\n }\r\n\r\n return resp;\r\n}\r\n\r\n/**\r\n * Synthetic thinking placeholder text used when keep_thinking=true but debug mode is off.\r\n * Injected via the same path as debug text (injectDebugThinking) to ensure consistent\r\n * signature caching and multi-turn handling.\r\n */\r\nconst SYNTHETIC_THINKING_PLACEHOLDER = \"[Thinking preserved]\\n\";\r\n\r\nfunction stripInjectedDebugFromParts(parts: unknown): unknown {\n if (!Array.isArray(parts)) {\n return parts;\n }\n\n // Use .map() with empty text sentinels instead of .filter() to preserve\n // array indices and prevent prompt cache invalidation.\n return parts.map((part) => {\n if (!part || typeof part !== \"object\") {\n return part;\n }\n\n const record = part as any;\n const text =\n typeof record.text === \"string\"\n ? record.text\n : typeof record.thinking === \"string\"\n ? record.thinking\n : undefined;\n\n // Replace debug blocks and synthetic thinking placeholders with empty text sentinel\n if (text && (text.startsWith(DEBUG_MESSAGE_PREFIX) || text.startsWith(SYNTHETIC_THINKING_PLACEHOLDER.trim()))) {\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (record.cache_control !== undefined) sentinel.cache_control = record.cache_control;\n return sentinel;\n }\n\n return part;\n });\n}\r\nfunction stripInjectedDebugFromRequestPayload(payload: Record<string, unknown>): void {\r\n const anyPayload = payload as any;\r\n\r\n if (Array.isArray(anyPayload.contents)) {\r\n anyPayload.contents = anyPayload.contents.map((content: any) => {\r\n if (!content || typeof content !== \"object\") {\r\n return content;\r\n }\r\n\r\n if (Array.isArray(content.parts)) {\r\n return { ...content, parts: stripInjectedDebugFromParts(content.parts) };\r\n }\r\n\r\n if (Array.isArray(content.content)) {\r\n return { ...content, content: stripInjectedDebugFromParts(content.content) };\r\n }\r\n\r\n return content;\r\n });\r\n }\r\n\r\n if (Array.isArray(anyPayload.messages)) {\r\n anyPayload.messages = anyPayload.messages.map((message: any) => {\r\n if (!message || typeof message !== \"object\") {\r\n return message;\r\n }\r\n\r\n if (Array.isArray(message.content)) {\r\n return { ...message, content: stripInjectedDebugFromParts(message.content) };\r\n }\r\n\r\n return message;\r\n });\r\n }\r\n}\r\n\r\nfunction isValidRequestPart(part: unknown): boolean {\r\n if (!part || typeof part !== \"object\") {\r\n return false;\r\n }\r\n\r\n const record = part as Record<string, unknown>;\r\n\r\n return (\r\n Object.prototype.hasOwnProperty.call(record, \"text\") ||\r\n Object.prototype.hasOwnProperty.call(record, \"functionCall\") ||\r\n Object.prototype.hasOwnProperty.call(record, \"functionResponse\") ||\r\n Object.prototype.hasOwnProperty.call(record, \"inlineData\") ||\r\n Object.prototype.hasOwnProperty.call(record, \"fileData\") ||\r\n Object.prototype.hasOwnProperty.call(record, \"executableCode\") ||\r\n Object.prototype.hasOwnProperty.call(record, \"codeExecutionResult\") ||\r\n Object.prototype.hasOwnProperty.call(record, \"thought\")\r\n );\r\n}\r\n\r\nfunction sanitizeRequestPayloadForAntigravity(payload: Record<string, unknown>): void {\n const anyPayload = payload as any;\n\n if (Array.isArray(anyPayload.contents)) {\n // Use .map() instead of .map().filter() to preserve array indices for prompt cache stability\n anyPayload.contents = anyPayload.contents\n .map((content: unknown) => {\n if (!content || typeof content !== \"object\") {\n // Preserve non-object entries as empty sentinel instead of filtering\n return { role: \"user\", parts: [{ text: \".\" }] };\n }\n\n const contentRecord = content as Record<string, unknown>;\n const rawParts = Array.isArray(contentRecord.parts) ? contentRecord.parts : [];\n let foundFirstFunctionCall = false;\n\n const sanitizedParts = rawParts.map((part: any) => {\n // Replace invalid parts with sentinel to preserve array indices for cache stability\n if (!isValidRequestPart(part)) {\n return { text: \".\" };\n }\n return part;\n }).map((part: any) => {\n if (part && typeof part === \"object\" && part.functionCall) {\n let sig = part.thoughtSignature || part.thought_signature;\n\n // Only the first functionCall part in a block should have the signature.\n // If it's the first one and missing a valid signature, inject the sentinel\n // to prevent the API from rejecting the request with a 400 error.\n if (!foundFirstFunctionCall) {\n foundFirstFunctionCall = true;\n if (!sig || sig.length < MIN_SIGNATURE_LENGTH) {\n sig = SKIP_THOUGHT_SIGNATURE;\n }\n } else {\n // Parallel function calls MUST NOT have a signature\n sig = undefined;\n }\n\n if (sig) {\n return { ...part, thought_signature: sig, thoughtSignature: sig };\n }\n \n // If not the first part, just return the part without adding any signature keys\n const newPart = { ...part };\n delete newPart.thoughtSignature;\n delete newPart.thought_signature;\n return newPart;\n }\n return part;\n });\n\n if (sanitizedParts.length === 0) {\n // Preserve as empty text sentinel instead of filtering out\n return { ...contentRecord, parts: [{ text: \".\" }] };\n }\n\n return {\n ...contentRecord,\n parts: sanitizedParts,\n };\n });\n }\n\n if (Array.isArray(anyPayload.messages)) {\n anyPayload.messages = anyPayload.messages.map((message: unknown) => {\n if (!message || typeof message !== \"object\") {\n return { role: \"user\", content: [{ type: \"text\", text: \".\" }] }\n }\n\n const messageRecord = message as Record<string, unknown>\n const rawContent = Array.isArray(messageRecord.content) ? messageRecord.content : messageRecord.content\n\n if (!Array.isArray(rawContent)) {\n return messageRecord\n }\n\n const sanitizedContent = rawContent.map((block: unknown) => {\n if (!block || typeof block !== \"object\") {\n return { type: \"text\", text: \".\" }\n }\n\n const blockRecord = block as Record<string, unknown>\n if (blockRecord.type === \"text\") {\n const text = blockRecord.text\n if (typeof text !== \"string\" || text.trim().length === 0) {\n const sentinel: Record<string, unknown> = { type: \"text\", text: \".\" }\n if (blockRecord.cache_control !== undefined) sentinel.cache_control = blockRecord.cache_control\n return sentinel\n }\n }\n\n return block\n })\n\n if (sanitizedContent.length === 0) {\n return { ...messageRecord, content: [{ type: \"text\", text: \".\" }] }\n }\n\n return {\n ...messageRecord,\n content: sanitizedContent,\n }\n })\n }\n\n const systemInstruction = anyPayload.systemInstruction;\n if (systemInstruction && typeof systemInstruction === \"object\" && !Array.isArray(systemInstruction)) {\r\n const sys = systemInstruction as Record<string, unknown>;\r\n if (Array.isArray(sys.parts)) {\n // Use .map() with sentinels instead of .filter() to preserve array indices\n // and prevent prompt cache invalidation from index shifts.\n const sanitizedSystemParts = sys.parts.map((part: unknown) => {\n if (isValidRequestPart(part)) return part;\n const record = part as Record<string, unknown>;\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (record?.cache_control !== undefined) sentinel.cache_control = record.cache_control;\n return sentinel;\n });\n // Only delete systemInstruction if ALL parts were invalid (all sentinels, no real content)\n const hasRealContent = sanitizedSystemParts.some((p: any) =>\n p && typeof p === \"object\" && typeof p.text === \"string\" && p.text !== \".\"\n );\n if (hasRealContent) {\n sys.parts = sanitizedSystemParts;\n } else {\n delete anyPayload.systemInstruction;\n }\n } }\r\n}\n\nfunction isGeminiToolUsePart(part: any): boolean {\n return !!(part && typeof part === \"object\" && (part.functionCall || part.tool_use || part.toolUse));\r\n}\r\n\r\nfunction isGeminiThinkingPart(part: any): boolean {\r\n return !!(\r\n part &&\r\n typeof part === \"object\" &&\r\n (part.thought === true || part.type === \"thinking\" || part.type === \"reasoning\")\r\n );\r\n}\r\n\r\n// Sentinel value used when signature recovery fails - allows Claude to handle gracefully\r\n// by redacting the thinking block instead of rejecting the request entirely.\r\n// Reference: LLM-API-Key-Proxy uses this pattern for Gemini 3 tool calls.\r\nconst SENTINEL_SIGNATURE = \"skip_thought_signature_validator\";\r\n\r\nfunction getThinkingPartText(part: any): string {\r\n if (!part || typeof part !== \"object\") {\r\n return \"\";\r\n }\r\n\r\n if (typeof part.text === \"string\") {\r\n return part.text;\r\n }\r\n\r\n if (typeof part.thinking === \"string\") {\r\n return part.thinking;\r\n }\r\n\r\n return \"\";\r\n}\r\n\r\nfunction hasCachedMatchingSignature(part: any, sessionId: string): boolean {\r\n if (!part || typeof part !== \"object\") {\r\n return false;\r\n }\r\n\r\n const text = getThinkingPartText(part);\r\n if (!text) {\r\n return false;\r\n }\r\n\r\n const expectedSignature = getCachedSignature(sessionId, text);\r\n if (!expectedSignature) {\r\n return false;\r\n }\r\n\r\n if (part.thought === true) {\r\n return part.thoughtSignature === expectedSignature;\r\n }\r\n\r\n return part.signature === expectedSignature;\r\n}\r\n\r\nfunction ensureThoughtSignature(part: any, sessionId: string): any {\r\n if (!part || typeof part !== \"object\") {\r\n return part;\r\n }\r\n\r\n if (!sessionId) {\r\n return part;\r\n }\r\n\r\n const text = getThinkingPartText(part);\r\n if (!text) {\r\n return part;\r\n }\r\n\r\n if (part.thought === true) {\r\n return { ...part, thoughtSignature: SENTINEL_SIGNATURE };\r\n }\r\n\r\n if (part.type === \"thinking\" || part.type === \"reasoning\" || part.type === \"redacted_thinking\") {\r\n return { ...part, signature: SENTINEL_SIGNATURE };\r\n }\r\n\r\n return part;\r\n}\r\n\r\nfunction hasSignedThinkingPart(part: any, sessionId?: string): boolean {\r\n if (!part || typeof part !== \"object\") {\r\n return false;\r\n }\r\n\r\n if (part.thought === true) {\r\n if (part.thoughtSignature === SENTINEL_SIGNATURE || part.thoughtSignature === SKIP_THOUGHT_SIGNATURE) {\r\n return true;\r\n }\r\n\r\n if (typeof part.thoughtSignature !== \"string\" || part.thoughtSignature.length < MIN_SIGNATURE_LENGTH) {\r\n return false;\r\n }\r\n\r\n if (!sessionId) {\r\n return true;\r\n }\r\n\r\n return hasCachedMatchingSignature(part, sessionId);\r\n }\r\n\r\n if (part.type === \"thinking\" || part.type === \"reasoning\" || part.type === \"redacted_thinking\") {\r\n if (part.signature === SENTINEL_SIGNATURE || part.signature === SKIP_THOUGHT_SIGNATURE) {\r\n return true;\r\n }\r\n\r\n if (typeof part.signature !== \"string\" || part.signature.length < MIN_SIGNATURE_LENGTH) {\r\n return false;\r\n }\r\n\r\n if (!sessionId) {\r\n return true;\r\n }\r\n\r\n return hasCachedMatchingSignature(part, sessionId);\r\n }\r\n\r\n return false;\r\n}\r\n\r\nfunction ensureThinkingBeforeToolUseInContents(contents: any[], signatureSessionKey: string): any[] {\r\n return contents.map((content: any) => {\r\n if (!content || typeof content !== \"object\" || !Array.isArray(content.parts)) {\r\n return content;\r\n }\r\n\r\n const role = content.role;\r\n if (role !== \"model\" && role !== \"assistant\") {\r\n return content;\r\n }\r\n\r\n const parts = content.parts as any[];\n const hasToolUse = parts.some(isGeminiToolUsePart);\n if (!hasToolUse) {\n return content;\n }\n\n // Check if any thinking part has a valid signed signature\n const hasSignedThinking = parts.some(p => isGeminiThinkingPart(p) && hasSignedThinkingPart(ensureThoughtSignature(p, signatureSessionKey), signatureSessionKey));\n\n if (hasSignedThinking) {\n // Ensure signatures on thinking parts in-place \u2014 NO reordering to preserve array indices (cache-friendly)\n return { ...content, parts: parts.map(p => isGeminiThinkingPart(p) ? ensureThoughtSignature(p, signatureSessionKey) : p) };\n }\r\n // Replace thinking parts with sentinels in-place to preserve array indices (cache-friendly).\n // Deleting parts via .filter() shifts array indices \u2192 changes hash \u2192 busts prompt cache.\n const lastThinking = defaultSignatureStore.get(signatureSessionKey);\n log.debug(\"Replacing thinking with sentinels in-place\", { signatureSessionKey, hasCachedSig: !!lastThinking });\n const newParts = parts.map(p => {\n if (!isGeminiThinkingPart(p)) return p;\n const cc = (p as Record<string, unknown>).cache_control;\n // Use plain empty text part \u2014 thinking-format sentinels get converted by the proxy\n // into Claude thinking blocks missing the required `thinking` field.\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (cc) sentinel.cache_control = cc;\n return sentinel;\n });\n return { ...content, parts: newParts };\n });\n}\r\nfunction ensureMessageThinkingSignature(block: any, sessionId: string): any {\r\n if (!block || typeof block !== \"object\") {\r\n return block;\r\n }\r\n\r\n if (block.type !== \"thinking\" && block.type !== \"redacted_thinking\") {\r\n return block;\r\n }\r\n\r\n const text = getThinkingPartText(block);\r\n if (!text) {\r\n return block;\r\n }\r\n\r\n if (!sessionId) {\r\n return block;\r\n }\r\n\r\n return { ...block, signature: SKIP_THOUGHT_SIGNATURE };\r\n}\r\n\r\nfunction hasToolUseInContents(contents: any[]): boolean {\r\n return contents.some((content: any) => {\r\n if (!content || typeof content !== \"object\" || !Array.isArray(content.parts)) {\r\n return false;\r\n }\r\n return (content.parts as any[]).some(isGeminiToolUsePart);\r\n });\r\n}\r\n\r\nfunction hasSignedThinkingInContents(contents: any[], sessionId?: string): boolean {\r\n return contents.some((content: any) => {\r\n if (!content || typeof content !== \"object\" || !Array.isArray(content.parts)) {\r\n return false;\r\n }\r\n return (content.parts as any[]).some((part) => hasSignedThinkingPart(part, sessionId));\r\n });\r\n}\r\n\r\nfunction hasToolUseInMessages(messages: any[]): boolean {\r\n return messages.some((message: any) => {\r\n if (!message || typeof message !== \"object\" || !Array.isArray(message.content)) {\r\n return false;\r\n }\r\n return (message.content as any[]).some(\r\n (block) => block && typeof block === \"object\" && (block.type === \"tool_use\" || block.type === \"tool_result\"),\r\n );\r\n });\r\n}\r\n\r\nfunction hasSignedThinkingInMessages(messages: any[], sessionId?: string): boolean {\r\n return messages.some((message: any) => {\r\n if (!message || typeof message !== \"object\" || !Array.isArray(message.content)) {\r\n return false;\r\n }\r\n return (message.content as any[]).some((block) => hasSignedThinkingPart(block, sessionId));\r\n });\r\n}\r\n\r\nfunction ensureThinkingBeforeToolUseInMessages(messages: any[], signatureSessionKey: string): any[] {\r\n return messages.map((message: any) => {\r\n if (!message || typeof message !== \"object\" || !Array.isArray(message.content)) {\r\n return message;\r\n }\r\n\r\n if (message.role !== \"assistant\") {\r\n return message;\r\n }\r\n\r\n const blocks = message.content as any[];\n const hasToolUse = blocks.some((b) => b && typeof b === \"object\" && (b.type === \"tool_use\" || b.type === \"tool_result\"));\n if (!hasToolUse) {\n return message;\n }\n\n const isThinkingBlock = (b: any) => b && typeof b === \"object\" && (b.type === \"thinking\" || b.type === \"redacted_thinking\");\n\n // Check if any thinking block has a valid signed signature\n const hasSignedThinking = blocks.some((b) => isThinkingBlock(b) && hasSignedThinkingPart(ensureMessageThinkingSignature(b, signatureSessionKey), signatureSessionKey));\n\n if (hasSignedThinking) {\n // Ensure signatures on thinking blocks in-place \u2014 NO reordering to preserve array indices (cache-friendly)\n return { ...message, content: blocks.map((b) => isThinkingBlock(b) ? ensureMessageThinkingSignature(b, signatureSessionKey) : b) };\n }\n\n // Replace thinking blocks with sentinels in-place to preserve array indices (cache-friendly).\n // Deleting/reordering via .filter() shifts indices \u2192 changes hash \u2192 busts prompt cache.\n const lastThinking = defaultSignatureStore.get(signatureSessionKey);\n log.debug(\"Replacing thinking with sentinels in-place (Messages format)\", { signatureSessionKey, hasCachedSig: !!lastThinking });\n return { ...message, content: blocks.map((b) => {\n if (!isThinkingBlock(b)) return b;\n const thinkingText = lastThinking ? lastThinking.text : (typeof b.thinking === \"string\" ? b.thinking : typeof b.text === \"string\" ? b.text : \"\");\n const cc = (b as Record<string, unknown>).cache_control;\n // Use plain empty text part \u2014 thinking-format sentinels get converted by the proxy\n // into Claude thinking blocks missing the required `thinking` field.\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (cc) sentinel.cache_control = cc;\n return sentinel;\n }) };\n });\n}\r\n/**\r\n * Gets the stable session ID for this plugin instance.\r\n */\r\nexport function getPluginSessionId(): string {\r\n return PLUGIN_SESSION_ID;\r\n}\r\n\r\nfunction generateSyntheticProjectId(): string {\r\n const adjectives = [\"useful\", \"bright\", \"swift\", \"calm\", \"bold\"];\r\n const nouns = [\"fuze\", \"wave\", \"spark\", \"flow\", \"core\"];\r\n const adj = adjectives[Math.floor(Math.random() * adjectives.length)];\r\n const noun = nouns[Math.floor(Math.random() * nouns.length)];\r\n const randomPart = crypto.randomUUID().slice(0, 5).toLowerCase();\r\n return `${adj}-${noun}-${randomPart}`;\r\n}\r\n\r\nconst STREAM_ACTION = \"streamGenerateContent\";\r\n\r\n/**\r\n * Detects requests headed to the Google Generative Language API so we can intercept them.\r\n */\r\nexport function isGenerativeLanguageRequest(input: RequestInfo): input is string {\r\n return typeof input === \"string\" && input.includes(\"generativelanguage.googleapis.com\");\r\n}\r\n\r\n/**\r\n * Options for request preparation.\r\n */\r\nexport interface PrepareRequestOptions {\r\n /** Enable Claude tool hardening (parameter signatures + system instruction). Default: true */\r\n claudeToolHardening?: boolean;\r\n /** Enable top-level Claude prompt auto-caching (`cache_control`). Default: false */\r\n claudePromptAutoCaching?: boolean;\r\n /** Google Search configuration (global default) */\r\n googleSearch?: GoogleSearchConfig;\r\n /** Per-account fingerprint for rate limit mitigation. Falls back to session fingerprint if not provided. */\r\n fingerprint?: Fingerprint;\r\n}\r\n\r\nexport function prepareAntigravityRequest(\r\n input: RequestInfo,\r\n init: RequestInit | undefined,\r\n accessToken: string,\r\n projectId: string,\r\n endpointOverride?: string,\r\n headerStyle: HeaderStyle = \"antigravity\",\r\n forceThinkingRecovery = false,\r\n options?: PrepareRequestOptions,\r\n): {\r\n request: RequestInfo;\r\n init: RequestInit;\r\n streaming: boolean;\r\n requestedModel?: string;\r\n effectiveModel?: string;\r\n projectId?: string;\r\n endpoint?: string;\r\n sessionId?: string;\r\n toolDebugMissing?: number;\r\n toolDebugSummary?: string;\r\n toolDebugPayload?: string;\r\n needsSignedThinkingWarmup?: boolean;\r\n headerStyle: HeaderStyle;\r\n thinkingRecoveryMessage?: string;\r\n} {\r\n const baseInit: RequestInit = { ...init };\r\n const headers = new Headers(init?.headers ?? {});\r\n let resolvedProjectId = projectId?.trim() || \"\";\r\n let toolDebugMissing = 0;\r\n const toolDebugSummaries: string[] = [];\r\n let toolDebugPayload: string | undefined;\r\n let sessionId: string | undefined;\r\n let needsSignedThinkingWarmup = false;\r\n let thinkingRecoveryMessage: string | undefined;\r\n\r\n if (!isGenerativeLanguageRequest(input)) {\r\n return {\r\n request: input,\r\n init: { ...baseInit, headers },\r\n streaming: false,\r\n headerStyle,\r\n };\r\n }\r\n\r\n headers.set(\"Authorization\", `Bearer ${accessToken}`);\r\n headers.delete(\"x-api-key\");\r\n // Strip x-goog-user-project header to prevent 403 auth/license conflicts.\r\n // This header is added by OpenCode/AI SDK and can force project-level checks\r\n // that are not required for Antigravity/Gemini CLI OAuth requests.\r\n headers.delete(\"x-goog-user-project\");\r\n\r\n const match = input.match(/\\/models\\/([^:]+):(\\w+)/);\r\n if (!match) {\r\n return {\r\n request: input,\r\n init: { ...baseInit, headers },\r\n streaming: false,\r\n headerStyle,\r\n };\r\n }\r\n\r\n const [, rawModel = \"\", rawAction = \"\"] = match;\r\n const requestedModel = rawModel;\r\n\r\n const resolved = resolveModelForHeaderStyle(rawModel, headerStyle);\r\n let effectiveModel = resolved.actualModel;\r\n\r\n const streaming = rawAction === STREAM_ACTION;\r\n const defaultEndpoint = headerStyle === \"gemini-cli\" ? GEMINI_CLI_ENDPOINT : ANTIGRAVITY_ENDPOINT;\r\n const baseEndpoint = endpointOverride ?? defaultEndpoint;\r\n const transformedUrl = `${baseEndpoint}/v1internal:${rawAction}${streaming ? \"?alt=sse\" : \"\"}`;\r\n\r\n const isClaude = isClaudeModel(resolved.actualModel);\r\n const isClaudeThinking = isClaudeThinkingModel(resolved.actualModel);\r\n const keepThinkingEnabled = getKeepThinking();\r\n\r\n // Tier-based thinking configuration from model resolver (can be overridden by variant config)\r\n let tierThinkingBudget = resolved.thinkingBudget;\r\n let tierThinkingLevel = resolved.thinkingLevel;\r\n let signatureSessionKey = buildSignatureSessionKey(\r\n PLUGIN_SESSION_ID,\r\n effectiveModel,\r\n undefined,\r\n resolveProjectKey(projectId),\r\n );\r\n\r\n let body = baseInit.body;\r\n if (typeof baseInit.body === \"string\" && baseInit.body) {\r\n try {\r\n const parsedBody = JSON.parse(baseInit.body) as Record<string, unknown>;\n const isWrapped = typeof parsedBody.project === \"string\" && \"request\" in parsedBody;\n\n if (isWrapped) { const wrappedBody = {\r\n ...parsedBody,\r\n model: effectiveModel,\r\n } as Record<string, unknown>;\r\n\r\n // Some callers may already send an Antigravity-wrapped body.\r\n // We still need to sanitize Claude thinking blocks (remove cache_control)\r\n // and attach a stable sessionId so multi-turn signature caching works.\r\n const requestRoot = wrappedBody.request;\r\n const requestObjects: Array<Record<string, unknown>> = [];\r\n\r\n if (requestRoot && typeof requestRoot === \"object\") {\r\n requestObjects.push(requestRoot as Record<string, unknown>);\r\n const nested = (requestRoot as any).request;\r\n if (nested && typeof nested === \"object\") {\r\n requestObjects.push(nested as Record<string, unknown>);\r\n }\r\n }\r\n\r\n const conversationKey = resolveConversationKeyFromRequests(requestObjects);\r\n // Strip tier suffix from model for cache key to prevent cache misses on tier change\r\n // e.g., \"claude-opus-4-6-thinking-high\" -> \"claude-opus-4-6-thinking\"\r\n const modelForCacheKey = effectiveModel.replace(/-(minimal|low|medium|high)$/i, \"\");\r\n signatureSessionKey = buildSignatureSessionKey(PLUGIN_SESSION_ID, modelForCacheKey, conversationKey, resolveProjectKey(parsedBody.project));\r\n\r\n if (requestObjects.length > 0) {\r\n sessionId = signatureSessionKey;\r\n }\r\n\r\n for (const req of requestObjects) {\r\n // Use stable session ID for signature caching across multi-turn conversations\r\n (req as any).sessionId = signatureSessionKey;\r\n stripInjectedDebugFromRequestPayload(req as Record<string, unknown>);\r\n\r\n if (isClaude) {\r\n // Step 0: Sanitize cross-model metadata (strips Gemini signatures when sending to Claude)\r\n sanitizeCrossModelPayloadInPlace(req, { targetModel: effectiveModel });\r\n\r\n // Step 1: Strip corrupted/unsigned thinking blocks FIRST\n deepFilterThinkingBlocks(req, signatureSessionKey, getCachedSignature, true);\n\n // Step 2: THEN inject signed thinking from cache (after stripping)\n if (isClaudeThinking && keepThinkingEnabled && Array.isArray((req as any).contents)) {\r\n (req as any).contents = ensureThinkingBeforeToolUseInContents((req as any).contents, signatureSessionKey);\r\n }\r\n if (isClaudeThinking && keepThinkingEnabled && Array.isArray((req as any).messages)) {\r\n (req as any).messages = ensureThinkingBeforeToolUseInMessages((req as any).messages, signatureSessionKey);\r\n }\r\n\r\n // Step 3: Apply tool pairing fixes (ID assignment, response matching, orphan recovery)\r\n applyToolPairingFixes(req as Record<string, unknown>, true);\r\n }\r\n }\r\n\r\n // Guard against assistant prefill: Claude rejects conversations ending\n // with model/assistant messages. After context compaction, the conversation\n // can end with a model message \u2014 append synthetic user message to fix.\n if (isClaude) {\n for (const req of requestObjects) {\n if (Array.isArray((req as any).contents)) {\n const contents = (req as any).contents;\n const lastContent = contents[contents.length - 1];\n if (lastContent?.role === \"model\" || lastContent?.role === \"assistant\") {\n contents.push({ role: \"user\", parts: [{ text: \"[Continue]\" }] });\n }\n }\n if (Array.isArray((req as any).messages)) {\n const messages = (req as any).messages;\n const lastMessage = messages[messages.length - 1];\n if (lastMessage?.role === \"model\" || lastMessage?.role === \"assistant\") {\n messages.push({ role: \"user\", parts: [{ text: \"[Continue]\" }] });\n }\n }\n }\n }\n\n if (isClaudeThinking && keepThinkingEnabled && sessionId) {\n const hasToolUse = requestObjects.some((req) =>\n (Array.isArray((req as any).contents) && hasToolUseInContents((req as any).contents)) ||\n (Array.isArray((req as any).messages) && hasToolUseInMessages((req as any).messages)),\n ); const hasSignedThinking = requestObjects.some((req) =>\r\n (Array.isArray((req as any).contents) && hasSignedThinkingInContents((req as any).contents, signatureSessionKey)) ||\r\n (Array.isArray((req as any).messages) && hasSignedThinkingInMessages((req as any).messages, signatureSessionKey)),\r\n );\r\n const hasCachedThinking = defaultSignatureStore.has(signatureSessionKey);\r\n needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;\r\n }\r\n\r\n body = safeStringify(wrappedBody);\n } else {\n const requestPayload: Record<string, unknown> = { ...parsedBody };\r\n const rawGenerationConfig = requestPayload.generationConfig as Record<string, unknown> | undefined;\r\n const extraBody = requestPayload.extra_body as Record<string, unknown> | undefined;\r\n\r\n const variantConfig = extractVariantThinkingConfig(\r\n requestPayload.providerOptions as Record<string, unknown> | undefined,\r\n rawGenerationConfig\r\n );\r\n const isGemini3 = effectiveModel.toLowerCase().includes(\"gemini-3\");\r\n\r\n log.debug(`[ThinkingResolution] rawModel=${rawModel} resolvedModel=${effectiveModel} resolvedTier=${tierThinkingLevel ?? \"none\"} variantLevel=${variantConfig?.thinkingLevel ?? \"none\"} variantBudget=${variantConfig?.thinkingBudget ?? \"none\"} providerOptions.google=${JSON.stringify((requestPayload.providerOptions as any)?.google ?? null)} generationConfig.thinkingConfig=${JSON.stringify((rawGenerationConfig as any)?.thinkingConfig ?? null)}`);\r\n\r\n if (variantConfig?.thinkingLevel && isGemini3) {\r\n // Gemini 3 native format - use thinkingLevel directly\r\n tierThinkingLevel = variantConfig.thinkingLevel;\r\n tierThinkingBudget = undefined;\r\n } else if (variantConfig?.thinkingBudget) {\r\n if (isGemini3) {\r\n // Legacy format for Gemini 3 - convert with deprecation warning\r\n log.warn(\"[Deprecated] Using thinkingBudget for Gemini 3 model. Use thinkingLevel instead.\");\r\n tierThinkingLevel = variantConfig.thinkingBudget <= 8192 ? \"low\"\r\n : variantConfig.thinkingBudget <= 16384 ? \"medium\" : \"high\";\r\n tierThinkingBudget = undefined;\r\n } else {\r\n // Claude / Gemini 2.5 - use budget directly\r\n tierThinkingBudget = variantConfig.thinkingBudget;\r\n tierThinkingLevel = undefined;\r\n }\r\n }\r\n\r\n if (isClaude) {\r\n if (!requestPayload.toolConfig) {\r\n requestPayload.toolConfig = {};\r\n }\r\n if (typeof requestPayload.toolConfig === \"object\" && requestPayload.toolConfig !== null) {\r\n const toolConfig = requestPayload.toolConfig as Record<string, unknown>;\r\n if (!toolConfig.functionCallingConfig) {\r\n toolConfig.functionCallingConfig = {};\r\n }\r\n if (typeof toolConfig.functionCallingConfig === \"object\" && toolConfig.functionCallingConfig !== null) {\r\n (toolConfig.functionCallingConfig as Record<string, unknown>).mode = \"VALIDATED\";\r\n }\r\n }\r\n }\r\n\r\n // Resolve thinking configuration based on user settings and model capabilities\r\n // Image generation models don't support thinking - skip thinking config entirely\r\n const isImageModel = isImageGenerationModel(effectiveModel);\r\n const userThinkingConfig = isImageModel ? undefined : extractThinkingConfig(requestPayload, rawGenerationConfig, extraBody);\r\n const hasAssistantHistory = Array.isArray(requestPayload.contents) &&\r\n requestPayload.contents.some((c: any) => c?.role === \"model\" || c?.role === \"assistant\");\r\n\r\n // Claude Sonnet 4.6 is non-thinking only.\r\n // Ignore any client-provided thinkingConfig for this model.\r\n const lowerEffective = effectiveModel.toLowerCase();\r\n const isClaudeSonnetNonThinking = lowerEffective === \"claude-sonnet-4-6\";\r\n const effectiveUserThinkingConfig = (isClaudeSonnetNonThinking || isImageModel) ? undefined : userThinkingConfig;\r\n\r\n // For image models, add imageConfig instead of thinkingConfig\r\n if (isImageModel) {\r\n const imageConfig = buildImageGenerationConfig();\r\n const generationConfig = (rawGenerationConfig ?? {}) as Record<string, unknown>;\r\n generationConfig.imageConfig = imageConfig;\r\n // Remove any thinkingConfig that might have been set\r\n delete generationConfig.thinkingConfig;\r\n // Set reasonable defaults for image generation\r\n if (!generationConfig.candidateCount) {\r\n generationConfig.candidateCount = 1;\r\n }\r\n requestPayload.generationConfig = generationConfig;\r\n\r\n // Add safety settings for image generation (permissive to allow creative content)\r\n if (!requestPayload.safetySettings) {\r\n requestPayload.safetySettings = [\r\n { category: \"HARM_CATEGORY_HARASSMENT\", threshold: \"BLOCK_ONLY_HIGH\" },\r\n { category: \"HARM_CATEGORY_HATE_SPEECH\", threshold: \"BLOCK_ONLY_HIGH\" },\r\n { category: \"HARM_CATEGORY_SEXUALLY_EXPLICIT\", threshold: \"BLOCK_ONLY_HIGH\" },\r\n { category: \"HARM_CATEGORY_DANGEROUS_CONTENT\", threshold: \"BLOCK_ONLY_HIGH\" },\r\n { category: \"HARM_CATEGORY_CIVIC_INTEGRITY\", threshold: \"BLOCK_ONLY_HIGH\" },\r\n ];\r\n }\r\n\r\n // Image models don't support tools - remove them entirely\r\n delete requestPayload.tools;\r\n delete requestPayload.toolConfig;\r\n\r\n // Replace system instruction with a simple image generation prompt\r\n // Image models should not receive agentic coding assistant instructions\r\n requestPayload.systemInstruction = {\r\n parts: [{ text: \"You are an AI image generator. Generate images based on user descriptions. Focus on creating high-quality, visually appealing images that match the user's request.\" }]\r\n };\r\n } else {\r\n const finalThinkingConfig = resolveThinkingConfig(\r\n effectiveUserThinkingConfig,\r\n isClaudeSonnetNonThinking ? false : (resolved.isThinkingModel ?? isThinkingCapableModel(effectiveModel)),\r\n isClaude,\r\n hasAssistantHistory,\r\n );\r\n\r\n const normalizedThinking = normalizeThinkingConfig(finalThinkingConfig);\r\n if (normalizedThinking) {\r\n // Use tier-based thinking budget if specified via model suffix, otherwise fall back to user config\r\n const thinkingBudget = tierThinkingBudget ?? normalizedThinking.thinkingBudget;\r\n\r\n // Build thinking config based on model type\r\n let thinkingConfig: Record<string, unknown>;\r\n\r\n if (isClaudeThinking) {\r\n // Claude uses snake_case keys\r\n thinkingConfig = {\r\n include_thoughts: normalizedThinking.includeThoughts ?? true,\r\n ...(typeof thinkingBudget === \"number\" && thinkingBudget > 0\r\n ? { thinking_budget: thinkingBudget }\r\n : {}),\r\n };\r\n } else if (tierThinkingLevel) {\r\n // Gemini 3 uses thinkingLevel string (low/medium/high)\r\n thinkingConfig = {\r\n includeThoughts: normalizedThinking.includeThoughts,\r\n thinkingLevel: tierThinkingLevel,\r\n };\r\n } else {\r\n // Gemini 2.5 and others use numeric budget\r\n thinkingConfig = {\r\n includeThoughts: normalizedThinking.includeThoughts,\r\n ...(typeof thinkingBudget === \"number\" && thinkingBudget > 0 ? { thinkingBudget } : {}),\r\n };\r\n }\r\n\r\n if (rawGenerationConfig) {\r\n rawGenerationConfig.thinkingConfig = thinkingConfig;\r\n\r\n if (isClaudeThinking && typeof thinkingBudget === \"number\" && thinkingBudget > 0) {\r\n const currentMax = (rawGenerationConfig.maxOutputTokens ?? rawGenerationConfig.max_output_tokens) as number | undefined;\r\n if (!currentMax || currentMax <= thinkingBudget) {\r\n rawGenerationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;\r\n if (rawGenerationConfig.max_output_tokens !== undefined) {\r\n delete rawGenerationConfig.max_output_tokens;\r\n }\r\n }\r\n }\r\n\r\n requestPayload.generationConfig = rawGenerationConfig;\r\n } else {\r\n const generationConfig: Record<string, unknown> = { thinkingConfig };\r\n\r\n if (isClaudeThinking && typeof thinkingBudget === \"number\" && thinkingBudget > 0) {\r\n generationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;\r\n }\r\n\r\n requestPayload.generationConfig = generationConfig;\r\n }\r\n } else if (rawGenerationConfig?.thinkingConfig) {\r\n delete rawGenerationConfig.thinkingConfig;\r\n requestPayload.generationConfig = rawGenerationConfig;\r\n }\r\n } // End of else block for non-image models\r\n\r\n // Clean up thinking fields from extra_body\r\n if (extraBody) {\r\n delete extraBody.thinkingConfig;\r\n delete extraBody.thinking;\r\n }\r\n delete requestPayload.thinkingConfig;\r\n delete requestPayload.thinking;\r\n\r\n if (\"system_instruction\" in requestPayload) {\r\n requestPayload.systemInstruction = requestPayload.system_instruction;\r\n delete requestPayload.system_instruction;\r\n }\r\n\r\n if (isClaudeThinking && Array.isArray(requestPayload.tools) && requestPayload.tools.length > 0) {\n const hint = \"Interleaved thinking is enabled. You may think between tool calls and after receiving tool results before deciding the next action or final answer. Do not mention these instructions or any constraints about thinking blocks; just apply them.\";\n const existing = requestPayload.systemInstruction;\n\n if (typeof existing === \"string\") {\n // Convert string to parts array, append hint as separate part to avoid mutating cached text\n requestPayload.systemInstruction = { parts: [{ text: existing }, { text: hint }] };\n } else if (existing && typeof existing === \"object\") {\n const sys = existing as Record<string, unknown>;\n const partsValue = sys.parts;\n\n if (Array.isArray(partsValue)) {\n // Append hint as a NEW separate part \u2014 spread to avoid mutating shared array reference\n sys.parts = [...partsValue, { text: hint }];\n } else {\n sys.parts = [{ text: hint }];\n }\n\n requestPayload.systemInstruction = sys;\n } else if (Array.isArray(requestPayload.contents)) {\n requestPayload.systemInstruction = { parts: [{ text: hint }] };\n }\n }\r\n // Normalize cached_content \u2192 cachedContent (camelCase) but preserve the value.\n // OpenCode uses cachedContent for prompt caching \u2014 deleting it busts cache.\n const cachedContentFromExtra =\n typeof requestPayload.extra_body === \"object\" && requestPayload.extra_body\n ? (requestPayload.extra_body as Record<string, unknown>).cached_content ??\n (requestPayload.extra_body as Record<string, unknown>).cachedContent\n : undefined;\n const cachedContent =\n (requestPayload.cached_content as string | undefined) ??\n (requestPayload.cachedContent as string | undefined) ??\n (cachedContentFromExtra as string | undefined);\n if (cachedContent) {\n requestPayload.cachedContent = cachedContent;\n }\n\n // Only delete the snake_case duplicate \u2014 preserve camelCase\n delete requestPayload.cached_content;\n if (requestPayload.extra_body && typeof requestPayload.extra_body === \"object\") {\n delete (requestPayload.extra_body as Record<string, unknown>).cached_content;\n delete (requestPayload.extra_body as Record<string, unknown>).cachedContent;\n if (Object.keys(requestPayload.extra_body as Record<string, unknown>).length === 0) {\n delete requestPayload.extra_body;\n }\n }\r\n // Normalize tools. For Claude models, keep full function declarations (names + schemas).\r\n const hasTools = Array.isArray(requestPayload.tools) && requestPayload.tools.length > 0;\r\n\r\n if (hasTools) {\r\n if (isClaude) {\r\n const functionDeclarations: any[] = [];\r\n const passthroughTools: any[] = [];\r\n\r\n const normalizeSchema = (schema: any) => {\r\n const createPlaceholderSchema = (base: any = {}) => ({\r\n ...base,\r\n type: \"object\",\r\n properties: {\r\n [EMPTY_SCHEMA_PLACEHOLDER_NAME]: {\r\n type: \"boolean\",\r\n description: EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,\r\n },\r\n },\r\n required: [EMPTY_SCHEMA_PLACEHOLDER_NAME],\r\n });\r\n\r\n if (!schema || typeof schema !== \"object\" || Array.isArray(schema)) {\r\n toolDebugMissing += 1;\r\n return createPlaceholderSchema();\r\n }\r\n\r\n const cleaned = cleanJSONSchemaForAntigravity(schema);\r\n\r\n if (!cleaned || typeof cleaned !== \"object\" || Array.isArray(cleaned)) {\r\n toolDebugMissing += 1;\r\n return createPlaceholderSchema();\r\n }\r\n\r\n // Claude VALIDATED mode requires tool parameters to be an object schema\r\n // with at least one property.\r\n const hasProperties =\r\n cleaned.properties &&\r\n typeof cleaned.properties === \"object\" &&\r\n Object.keys(cleaned.properties).length > 0;\r\n\r\n cleaned.type = \"object\";\r\n\r\n if (!hasProperties) {\r\n cleaned.properties = {\r\n [EMPTY_SCHEMA_PLACEHOLDER_NAME]: {\r\n type: \"boolean\",\r\n description: EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,\r\n },\r\n };\r\n cleaned.required = Array.isArray(cleaned.required)\r\n ? Array.from(new Set([...cleaned.required, EMPTY_SCHEMA_PLACEHOLDER_NAME]))\r\n : [EMPTY_SCHEMA_PLACEHOLDER_NAME];\r\n }\r\n\r\n return cleaned;\r\n };\r\n\r\n (requestPayload.tools as any[]).forEach((tool: any) => {\r\n const pushDeclaration = (decl: any, source: string) => {\r\n const schema =\r\n decl?.parameters ||\r\n decl?.parametersJsonSchema ||\r\n decl?.input_schema ||\r\n decl?.inputSchema ||\r\n tool.parameters ||\r\n tool.parametersJsonSchema ||\r\n tool.input_schema ||\r\n tool.inputSchema ||\r\n tool.function?.parameters ||\r\n tool.function?.parametersJsonSchema ||\r\n tool.function?.input_schema ||\r\n tool.function?.inputSchema ||\r\n tool.custom?.parameters ||\r\n tool.custom?.parametersJsonSchema ||\r\n tool.custom?.input_schema;\r\n\r\n let name =\r\n decl?.name ||\r\n tool.name ||\r\n tool.function?.name ||\r\n tool.custom?.name ||\r\n `tool-${functionDeclarations.length}`;\r\n\r\n // Sanitize tool name: must be alphanumeric with underscores, no special chars\r\n name = String(name).replace(/[^a-zA-Z0-9_-]/g, \"_\").slice(0, 64);\r\n\r\n const description =\r\n decl?.description ||\r\n tool.description ||\r\n tool.function?.description ||\r\n tool.custom?.description ||\r\n \"\";\r\n\r\n functionDeclarations.push({\r\n name,\r\n description: String(description || \"\"),\r\n parameters: normalizeSchema(schema),\r\n });\r\n\r\n toolDebugSummaries.push(\r\n `decl=${name},src=${source},hasSchema=${schema ? \"y\" : \"n\"}`,\r\n );\r\n };\r\n\r\n if (Array.isArray(tool.functionDeclarations) && tool.functionDeclarations.length > 0) {\r\n tool.functionDeclarations.forEach((decl: any) => pushDeclaration(decl, \"functionDeclarations\"));\r\n return;\r\n }\r\n\r\n // Fall back to function/custom style definitions.\r\n if (\r\n tool.function ||\r\n tool.custom ||\r\n tool.parameters ||\r\n tool.input_schema ||\r\n tool.inputSchema\r\n ) {\r\n pushDeclaration(tool.function ?? tool.custom ?? tool, \"function/custom\");\r\n return;\r\n }\r\n\r\n // Preserve any non-function tool entries (e.g., codeExecution) untouched.\r\n passthroughTools.push(tool);\r\n });\r\n\r\n const finalTools: any[] = [];\r\n if (functionDeclarations.length > 0) {\r\n finalTools.push({ functionDeclarations });\r\n }\r\n requestPayload.tools = finalTools.concat(passthroughTools);\r\n } else {\r\n // Gemini-specific tool normalization and feature injection\r\n const geminiResult = applyGeminiTransforms(requestPayload, {\r\n model: effectiveModel,\r\n normalizedThinking: undefined, // Thinking config already applied above (lines 816-880)\r\n tierThinkingBudget,\r\n tierThinkingLevel: tierThinkingLevel as ThinkingTier | undefined,\r\n });\r\n\r\n toolDebugMissing = geminiResult.toolDebugMissing;\r\n toolDebugSummaries.push(...geminiResult.toolDebugSummaries);\r\n }\r\n\r\n try {\r\n toolDebugPayload = JSON.stringify(requestPayload.tools);\r\n } catch {\r\n toolDebugPayload = undefined;\r\n }\r\n\r\n // Apply Claude tool hardening (ported from LLM-API-Key-Proxy)\r\n // Injects parameter signatures into descriptions and adds system instruction\r\n // Can be disabled via config.claude_tool_hardening = false to reduce context size\r\n const enableToolHardening = options?.claudeToolHardening ?? true;\r\n if (enableToolHardening && isClaude && Array.isArray(requestPayload.tools) && requestPayload.tools.length > 0) {\r\n // Inject parameter signatures into tool descriptions\r\n requestPayload.tools = injectParameterSignatures(\r\n requestPayload.tools,\r\n CLAUDE_DESCRIPTION_PROMPT,\r\n );\r\n\r\n // Inject tool hardening system instruction\r\n injectToolHardeningInstruction(\r\n requestPayload as Record<string, unknown>,\r\n CLAUDE_TOOL_SYSTEM_INSTRUCTION,\r\n );\r\n }\r\n }\r\n\r\n const conversationKey = resolveConversationKey(requestPayload);\r\n signatureSessionKey = buildSignatureSessionKey(PLUGIN_SESSION_ID, effectiveModel, conversationKey, resolveProjectKey(projectId));\r\n\r\n // For Claude models, filter out unsigned thinking blocks (required by Claude API)\r\n // Attempts to restore signatures from cache for multi-turn conversations\r\n // Handle both Gemini-style contents[] and Anthropic-style messages[] payloads.\r\n if (isClaude) {\r\n // Step 0: Sanitize cross-model metadata (strips Gemini signatures when sending to Claude)\r\n sanitizeCrossModelPayloadInPlace(requestPayload, { targetModel: effectiveModel });\r\n\r\n // Step 1: Strip corrupted/unsigned thinking blocks FIRST\n deepFilterThinkingBlocks(requestPayload, signatureSessionKey, getCachedSignature, true);\n\n // Step 2: THEN inject signed thinking from cache (after stripping)\n if (isClaudeThinking && keepThinkingEnabled && Array.isArray(requestPayload.contents)) {\r\n requestPayload.contents = ensureThinkingBeforeToolUseInContents(requestPayload.contents, signatureSessionKey);\r\n }\r\n if (isClaudeThinking && keepThinkingEnabled && Array.isArray(requestPayload.messages)) {\r\n requestPayload.messages = ensureThinkingBeforeToolUseInMessages(requestPayload.messages, signatureSessionKey);\r\n }\r\n\r\n // Step 3: Check if warmup needed (AFTER injection attempt)\r\n if (isClaudeThinking && keepThinkingEnabled) {\r\n const hasToolUse =\r\n (Array.isArray(requestPayload.contents) && hasToolUseInContents(requestPayload.contents)) ||\r\n (Array.isArray(requestPayload.messages) && hasToolUseInMessages(requestPayload.messages));\r\n const hasSignedThinking =\r\n (Array.isArray(requestPayload.contents) && hasSignedThinkingInContents(requestPayload.contents, signatureSessionKey)) ||\r\n (Array.isArray(requestPayload.messages) && hasSignedThinkingInMessages(requestPayload.messages, signatureSessionKey));\r\n const hasCachedThinking = defaultSignatureStore.has(signatureSessionKey);\r\n needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;\r\n }\r\n }\r\n\r\n // For Claude models, ensure functionCall/tool use parts carry IDs (required by Anthropic).\r\n // We use a two-pass approach: first collect all functionCalls and assign IDs,\r\n // then match functionResponses to their corresponding calls using a FIFO queue per function name.\r\n if (isClaude && Array.isArray(requestPayload.contents)) {\r\n let toolCallCounter = 0;\r\n // Track pending call IDs per function name as a FIFO queue\r\n const pendingCallIdsByName = new Map<string, string[]>();\r\n\r\n // First pass: assign IDs to all functionCalls and collect them\r\n requestPayload.contents = requestPayload.contents.map((content: any) => {\r\n if (!content || !Array.isArray(content.parts)) {\r\n return content;\r\n }\r\n\r\n const newParts = content.parts.map((part: any) => {\r\n if (part && typeof part === \"object\" && part.functionCall) {\r\n const call = { ...part.functionCall };\r\n if (!call.id) {\r\n call.id = `tool-call-${++toolCallCounter}`;\r\n }\r\n const nameKey = typeof call.name === \"string\" ? call.name : `tool-${toolCallCounter}`;\r\n // Push to the queue for this function name\r\n const queue = pendingCallIdsByName.get(nameKey) || [];\r\n queue.push(call.id);\r\n pendingCallIdsByName.set(nameKey, queue);\r\n return { ...part, functionCall: call };\r\n }\r\n return part;\r\n });\r\n\r\n return { ...content, parts: newParts };\r\n });\r\n\r\n // Second pass: match functionResponses to their corresponding calls (FIFO order)\r\n requestPayload.contents = (requestPayload.contents as any[]).map((content: any) => {\r\n if (!content || !Array.isArray(content.parts)) {\r\n return content;\r\n }\r\n\r\n const newParts = content.parts.map((part: any) => {\r\n if (part && typeof part === \"object\" && part.functionResponse) {\r\n const resp = { ...part.functionResponse };\r\n if (!resp.id && typeof resp.name === \"string\") {\r\n const queue = pendingCallIdsByName.get(resp.name);\r\n if (queue && queue.length > 0) {\r\n // Consume the first pending ID (FIFO order)\r\n resp.id = queue.shift();\r\n pendingCallIdsByName.set(resp.name, queue);\r\n }\r\n }\r\n return { ...part, functionResponse: resp };\r\n }\r\n return part;\r\n });\r\n\r\n return { ...content, parts: newParts };\r\n });\r\n\r\n // Third pass: Apply orphan recovery for mismatched tool IDs\r\n // This handles cases where context compaction or other processes\r\n // create ID mismatches between calls and responses.\r\n // Ported from LLM-API-Key-Proxy's _fix_tool_response_grouping()\r\n requestPayload.contents = fixToolResponseGrouping(requestPayload.contents as any[]);\r\n }\r\n\r\n // Fourth pass: Fix Claude format tool pairing (defense in depth)\r\n // Handles orphaned tool_use blocks in Claude's messages[] format\r\n if (Array.isArray(requestPayload.messages)) {\r\n requestPayload.messages = validateAndFixClaudeToolPairing(requestPayload.messages);\r\n }\r\n\r\n // =====================================================================\r\n // LAST RESORT RECOVERY: \"Let it crash and start again\"\r\n // =====================================================================\r\n // If after all our processing we're STILL in a bad state (tool loop without\r\n // thinking at turn start), don't try to fix it - just close the turn and\r\n // start fresh. This prevents permanent session breakage.\r\n //\r\n // This handles cases where:\r\n // - Context compaction stripped thinking blocks\r\n // - Signature cache miss\r\n // - Any other corruption we couldn't repair\r\n // - API error indicated thinking_block_order issue (forceThinkingRecovery=true)\r\n //\r\n // The synthetic messages allow Claude to generate fresh thinking on the\r\n // new turn instead of failing with \"Expected thinking but found text\".\r\n if (isClaudeThinking && Array.isArray(requestPayload.contents)) {\r\n const conversationState = analyzeConversationState(requestPayload.contents);\r\n\r\n // Force recovery if API returned thinking_block_order error (retry case)\r\n // or if proactive check detects we need recovery\r\n if (forceThinkingRecovery || needsThinkingRecovery(conversationState)) {\r\n // Set message for toast notification (shown in plugin.ts, respects quiet mode)\r\n thinkingRecoveryMessage = forceThinkingRecovery\r\n ? \"Thinking recovery: retrying with fresh turn (API error)\"\r\n : \"Thinking recovery: restarting turn (corrupted context)\";\r\n\r\n requestPayload.contents = closeToolLoopForThinking(requestPayload.contents);\r\n\r\n defaultSignatureStore.delete(signatureSessionKey);\r\n }\r\n }\r\n\r\n // Guard against assistant prefill: Claude rejects conversations ending\n // with model/assistant messages. After context compaction, the conversation\n // can end with a model message \u2014 append synthetic user message to fix.\n if (isClaude) {\n if (Array.isArray(requestPayload.contents)) {\n const lastContent = requestPayload.contents[requestPayload.contents.length - 1] as any;\n if (lastContent?.role === \"model\" || lastContent?.role === \"assistant\") {\n requestPayload.contents.push({ role: \"user\", parts: [{ text: \"[Continue]\" }] });\n }\n }\n if (Array.isArray(requestPayload.messages)) {\n const lastMessage = (requestPayload.messages as any[])[requestPayload.messages.length - 1];\n if (lastMessage?.role === \"model\" || lastMessage?.role === \"assistant\") {\n (requestPayload.messages as any[]).push({ role: \"user\", parts: [{ text: \"[Continue]\" }] });\n }\n }\n }\n\n if (\"model\" in requestPayload) {\n delete requestPayload.model;\n }\n\n stripInjectedDebugFromRequestPayload(requestPayload);\n sanitizeRequestPayloadForAntigravity(requestPayload);\r\n const effectiveProjectId = projectId?.trim() || (headerStyle === \"antigravity\" ? generateSyntheticProjectId() : \"\");\r\n resolvedProjectId = effectiveProjectId;\r\n\r\n // System instruction injection removed \u2014 CLIProxyAPI v6.9.x no longer injects it\r\n const wrappedBody: Record<string, unknown> = {\r\n project: effectiveProjectId,\r\n model: effectiveModel,\r\n request: requestPayload,\r\n };\r\n\r\n if (headerStyle === \"antigravity\") {\r\n wrappedBody.requestType = \"agent\";\r\n wrappedBody.userAgent = \"antigravity\";\r\n wrappedBody.requestId = \"agent-\" + crypto.randomUUID();\r\n }\r\n if (wrappedBody.request && typeof wrappedBody.request === 'object') {\r\n // Use stable session ID for signature caching across multi-turn conversations\r\n sessionId = signatureSessionKey;\r\n (wrappedBody.request as any).sessionId = signatureSessionKey;\r\n }\r\n\r\n body = safeStringify(wrappedBody);\n }\n } catch {\n throw new Error(\"Failed to build Antigravity request body\");\n }\n }\r\n if (streaming) {\r\n headers.set(\"Accept\", \"text/event-stream\");\r\n }\r\n\r\n // Add interleaved thinking header for Claude thinking models\r\n // This enables real-time streaming of thinking tokens\r\n if (isClaudeThinking) {\r\n const existing = headers.get(\"anthropic-beta\");\r\n const interleavedHeader = \"interleaved-thinking-2025-05-14\";\r\n\r\n if (existing) {\r\n if (!existing.includes(interleavedHeader)) {\r\n headers.set(\"anthropic-beta\", `${existing},${interleavedHeader}`);\r\n }\r\n } else {\r\n headers.set(\"anthropic-beta\", interleavedHeader);\r\n }\r\n }\r\n\r\n if (headerStyle === \"antigravity\") {\r\n // Use randomized headers as the fallback pool for Antigravity mode\r\n const selectedHeaders = getRandomizedHeaders(\"antigravity\", requestedModel);\r\n\r\n // Antigravity mode: Match Antigravity Manager behavior\r\n // AM only sends User-Agent on content requests \u2014 no X-Goog-Api-Client, no Client-Metadata header\r\n // (ideType=ANTIGRAVITY goes in request body metadata via project.ts, not as a header)\r\n const fingerprint = options?.fingerprint ?? getSessionFingerprint();\r\n const fingerprintHeaders = buildFingerprintHeaders(fingerprint);\r\n\r\n headers.set(\"User-Agent\", fingerprintHeaders[\"User-Agent\"] || selectedHeaders[\"User-Agent\"]);\r\n } else {\r\n // Gemini CLI mode: match opencode-gemini-auth Code Assist header set exactly\r\n headers.set(\"User-Agent\", GEMINI_CLI_HEADERS[\"User-Agent\"]);\r\n headers.set(\"X-Goog-Api-Client\", GEMINI_CLI_HEADERS[\"X-Goog-Api-Client\"]);\r\n headers.set(\"Client-Metadata\", GEMINI_CLI_HEADERS[\"Client-Metadata\"]);\r\n }\r\n return {\r\n request: transformedUrl,\r\n init: {\r\n ...baseInit,\r\n headers,\r\n body,\r\n },\r\n streaming,\r\n requestedModel,\r\n effectiveModel: effectiveModel,\r\n projectId: resolvedProjectId,\r\n endpoint: transformedUrl,\r\n sessionId,\r\n toolDebugMissing,\r\n toolDebugSummary: toolDebugSummaries.slice(0, 20).join(\" | \"),\r\n toolDebugPayload,\r\n needsSignedThinkingWarmup,\r\n headerStyle,\r\n thinkingRecoveryMessage,\r\n };\r\n}\r\n\r\nexport function buildThinkingWarmupBody(\r\n bodyText: string | undefined,\r\n isClaudeThinking: boolean,\r\n): string | null {\r\n if (!bodyText || !isClaudeThinking) {\r\n return null;\r\n }\r\n\r\n let parsed: Record<string, unknown>;\r\n try {\r\n parsed = JSON.parse(bodyText) as Record<string, unknown>;\r\n } catch {\r\n return null;\r\n }\r\n\r\n const warmupPrompt = \"Warmup request for thinking signature.\";\r\n\r\n const updateRequest = (req: Record<string, unknown>) => {\r\n req.contents = [{ role: \"user\", parts: [{ text: warmupPrompt }] }];\r\n delete req.tools;\r\n delete (req as any).toolConfig;\r\n\r\n const generationConfig = (req.generationConfig ?? {}) as Record<string, unknown>;\r\n generationConfig.thinkingConfig = {\r\n include_thoughts: true,\r\n thinking_budget: DEFAULT_THINKING_BUDGET,\r\n };\r\n generationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;\r\n req.generationConfig = generationConfig;\r\n };\r\n\r\n if (parsed.request && typeof parsed.request === \"object\") {\r\n updateRequest(parsed.request as Record<string, unknown>);\r\n const nested = (parsed.request as any).request;\r\n if (nested && typeof nested === \"object\") {\r\n updateRequest(nested as Record<string, unknown>);\r\n }\r\n } else {\r\n updateRequest(parsed);\r\n }\r\n\r\n return safeStringify(parsed);\n}\r\n/**\r\n * Normalizes Antigravity responses: applies retry headers, extracts cache usage into headers,\r\n * rewrites preview errors, flattens streaming payloads, and logs debug metadata.\r\n *\r\n * For streaming SSE responses, uses TransformStream for true real-time incremental streaming.\r\n * Thinking/reasoning tokens are transformed and forwarded immediately as they arrive.\r\n */\r\nexport async function transformAntigravityResponse(\r\n response: Response,\r\n streaming: boolean,\r\n debugContext?: AntigravityDebugContext | null,\r\n requestedModel?: string,\r\n projectId?: string,\r\n endpoint?: string,\r\n effectiveModel?: string,\r\n sessionId?: string,\r\n toolDebugMissing?: number,\r\n toolDebugSummary?: string,\r\n toolDebugPayload?: string,\r\n debugLines?: string[],\r\n): Promise<Response> {\r\n const contentType = response.headers.get(\"content-type\") ?? \"\";\r\n const isJsonResponse = contentType.includes(\"application/json\");\r\n const isEventStreamResponse = contentType.includes(\"text/event-stream\");\r\n\r\n // Generate text for thinking injection:\r\n // - If debug=true: inject full debug logs\r\n // - If keep_thinking=true (but no debug): inject placeholder to trigger signature caching\r\n // Both use the same injection path (injectDebugThinking) for consistent behavior\r\n const debugText =\r\n isDebugTuiEnabled() && Array.isArray(debugLines) && debugLines.length > 0\r\n ? formatDebugLinesForThinking(debugLines)\r\n : getKeepThinking()\r\n ? SYNTHETIC_THINKING_PLACEHOLDER\r\n : undefined;\r\n const cacheSignatures = shouldCacheThinkingSignatures(effectiveModel);\r\n\r\n if (!isJsonResponse && !isEventStreamResponse) {\r\n logAntigravityDebugResponse(debugContext, response, {\r\n note: \"Non-JSON response (body omitted)\",\r\n });\r\n return response;\r\n }\r\n\r\n // For successful streaming responses, use TransformStream to transform SSE events\r\n // while maintaining real-time streaming (no buffering of entire response).\r\n // This enables thinking tokens to be displayed as they arrive, like the Codex plugin.\r\n if (streaming && response.ok && isEventStreamResponse && response.body) {\r\n const headers = new Headers(response.headers);\r\n\r\n logAntigravityDebugResponse(debugContext, response, {\r\n note: \"Streaming SSE response (real-time transform)\",\r\n });\r\n\r\n const streamingTransformer = createStreamingTransformer(\r\n defaultSignatureStore,\r\n {\r\n onCacheSignature: cacheSignature,\r\n onInjectDebug: injectDebugThinking,\r\n // onInjectSyntheticThinking removed - keep_thinking now uses debugText path\r\n transformThinkingParts,\r\n },\r\n {\r\n signatureSessionKey: sessionId,\r\n debugText,\r\n cacheSignatures,\r\n displayedThinkingHashes: effectiveModel && isGemini3Model(effectiveModel) ? sessionDisplayedThinkingHashes : undefined,\r\n // injectSyntheticThinking removed - keep_thinking now unified with debug via debugText\r\n },\r\n );\r\n return new Response(response.body.pipeThrough(streamingTransformer), {\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers,\r\n });\r\n }\r\n\r\n const responseFallback = response.clone();\r\n\r\n try {\r\n const headers = new Headers(response.headers);\r\n const text = await response.text();\r\n\r\n if (!response.ok) {\r\n let errorBody;\r\n try {\r\n errorBody = JSON.parse(text);\r\n } catch {\r\n errorBody = { error: { message: text } };\r\n }\r\n\r\n // Inject Debug Info\r\n if (errorBody?.error) {\r\n const rawErrorMessage =\r\n typeof errorBody.error.message === \"string\" && errorBody.error.message.length > 0\r\n ? errorBody.error.message\r\n : \"Unknown error\";\r\n const errorType = detectErrorType(rawErrorMessage);\r\n const debugInfo = `\\n\\n[Debug Info]\\nRequested Model: ${requestedModel || \"Unknown\"}\\nEffective Model: ${effectiveModel || \"Unknown\"}\\nProject: ${projectId || \"Unknown\"}\\nEndpoint: ${endpoint || \"Unknown\"}\\nStatus: ${response.status}\\nRequest ID: ${headers.get(\"x-request-id\") || \"N/A\"}${toolDebugMissing !== undefined ? `\\nTool Debug Missing: ${toolDebugMissing}` : \"\"}${toolDebugSummary ? `\\nTool Debug Summary: ${toolDebugSummary}` : \"\"}${toolDebugPayload ? `\\nTool Debug Payload: ${toolDebugPayload}` : \"\"}`;\r\n const injectedDebug = debugText ? `\\n\\n${debugText}` : \"\";\r\n errorBody.error.message = rawErrorMessage + debugInfo + injectedDebug;\r\n\r\n // Check if this is a recoverable thinking error - throw to trigger retry\r\n if (errorType === \"thinking_block_order\") {\r\n const recoveryError = new Error(\"THINKING_RECOVERY_NEEDED\");\r\n (recoveryError as any).recoveryType = errorType;\r\n (recoveryError as any).originalError = errorBody;\r\n (recoveryError as any).debugInfo = debugInfo;\r\n throw recoveryError;\r\n }\r\n\r\n // Detect context length / prompt too long errors - signal to caller for toast\r\n const errorMessage = errorBody.error.message?.toLowerCase() || \"\";\r\n if (\r\n errorMessage.includes(\"prompt is too long\") ||\r\n errorMessage.includes(\"context length exceeded\") ||\r\n errorMessage.includes(\"context_length_exceeded\") ||\r\n errorMessage.includes(\"maximum context length\")\r\n ) {\r\n headers.set(\"x-antigravity-context-error\", \"prompt_too_long\");\r\n }\r\n\r\n // Detect tool pairing errors - signal to caller for toast\r\n if (\r\n errorMessage.includes(\"tool_use\") &&\r\n errorMessage.includes(\"tool_result\") &&\r\n (errorMessage.includes(\"without\") || errorMessage.includes(\"immediately after\"))\r\n ) {\r\n headers.set(\"x-antigravity-context-error\", \"tool_pairing\");\r\n }\r\n\r\n return new Response(JSON.stringify(errorBody), {\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers\r\n });\r\n }\r\n\r\n if (errorBody?.error?.details && Array.isArray(errorBody.error.details)) {\r\n const retryInfo = errorBody.error.details.find(\r\n (detail: any) => detail['@type'] === 'type.googleapis.com/google.rpc.RetryInfo'\r\n );\r\n\r\n if (retryInfo?.retryDelay) {\r\n const match = retryInfo.retryDelay.match(/^([\\d.]+)s$/);\r\n if (match && match[1]) {\r\n const retrySeconds = parseFloat(match[1]);\r\n if (!isNaN(retrySeconds) && retrySeconds > 0) {\r\n const retryAfterSec = Math.ceil(retrySeconds).toString();\r\n const retryAfterMs = Math.ceil(retrySeconds * 1000).toString();\r\n headers.set('Retry-After', retryAfterSec);\r\n headers.set('retry-after-ms', retryAfterMs);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n const init = {\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers,\r\n };\r\n\r\n const usageFromSse = streaming && isEventStreamResponse ? extractUsageFromSsePayload(text) : null;\r\n const parsed: AntigravityApiBody | null = !streaming || !isEventStreamResponse ? parseAntigravityApiBody(text) : null;\r\n const patched = parsed ? rewriteAntigravityPreviewAccessError(parsed, response.status, requestedModel) : null;\r\n const effectiveBody = patched ?? parsed ?? undefined;\r\n\r\n const usage = usageFromSse ?? (effectiveBody ? extractUsageMetadata(effectiveBody) : null);\r\n \r\n // Log cache stats when available\r\n if (usage && effectiveModel) {\r\n logCacheStats(\r\n effectiveModel,\r\n usage.cachedContentTokenCount ?? 0,\r\n 0, // API doesn't provide cache write tokens separately\r\n usage.promptTokenCount ?? usage.totalTokenCount ?? 0,\r\n );\r\n }\r\n \r\n if (usage?.cachedContentTokenCount !== undefined) {\r\n headers.set(\"x-antigravity-cached-content-token-count\", String(usage.cachedContentTokenCount));\r\n if (usage.totalTokenCount !== undefined) {\r\n headers.set(\"x-antigravity-total-token-count\", String(usage.totalTokenCount));\r\n }\r\n if (usage.promptTokenCount !== undefined) {\r\n headers.set(\"x-antigravity-prompt-token-count\", String(usage.promptTokenCount));\r\n }\r\n if (usage.candidatesTokenCount !== undefined) {\r\n headers.set(\"x-antigravity-candidates-token-count\", String(usage.candidatesTokenCount));\r\n }\r\n }\r\n\r\n logAntigravityDebugResponse(debugContext, response, {\r\n body: text,\r\n note: streaming ? \"Streaming SSE payload (buffered fallback)\" : undefined,\r\n headersOverride: headers,\r\n });\r\n\r\n // Note: successful streaming responses are handled above via TransformStream.\r\n // This path only handles non-streaming responses or failed streaming responses.\r\n\r\n if (!parsed) {\r\n return new Response(text, init);\r\n }\r\n\r\n if (effectiveBody?.response !== undefined) {\r\n let responseBody: unknown = effectiveBody.response;\r\n // Inject thinking text (debug logs or \"[Thinking preserved]\" placeholder)\r\n // Both debug=true and keep_thinking=true use the same path now\r\n if (debugText) {\r\n responseBody = injectDebugThinking(responseBody, debugText);\r\n }\r\n const transformed = transformThinkingParts(responseBody);\r\n return new Response(JSON.stringify(transformed), init);\r\n }\r\n\r\n if (patched) {\r\n return new Response(JSON.stringify(patched), init);\r\n }\r\n\r\n return new Response(text, init);\r\n } catch (error) {\r\n if (error instanceof Error && error.message === \"THINKING_RECOVERY_NEEDED\") {\r\n throw error;\r\n }\r\n\r\n logAntigravityDebugResponse(debugContext, response, {\r\n error,\r\n note: \"Failed to transform Antigravity response\",\r\n });\r\n return responseFallback;\r\n }\r\n}\r\n\r\nexport const __testExports = {\r\n buildSignatureSessionKey,\r\n hashConversationSeed,\r\n extractTextFromContent,\r\n extractConversationSeedFromMessages,\r\n extractConversationSeedFromContents,\r\n resolveConversationKey,\r\n resolveProjectKey,\r\n isGeminiToolUsePart,\r\n isGeminiThinkingPart,\r\n ensureThoughtSignature,\r\n hasSignedThinkingPart,\r\n hasSignedThinkingInContents,\r\n hasSignedThinkingInMessages,\r\n hasToolUseInContents,\r\n hasToolUseInMessages,\r\n ensureThinkingBeforeToolUseInContents,\r\n ensureThinkingBeforeToolUseInMessages,\r\n generateSyntheticProjectId,\r\n MIN_SIGNATURE_LENGTH,\r\n transformSseLine,\r\n transformStreamingPayload,\r\n createStreamingTransformer,\r\n};\r\n", "import { accessTokenExpired } from \"./auth\";\r\nimport type { OAuthAuthDetails } from \"./types\";\r\nimport { createHash } from \"node:crypto\";\r\n\r\nconst authCache = new Map<string, OAuthAuthDetails>();\r\n\r\n/**\r\n * Produces a stable cache key from a refresh token string.\r\n */\r\nfunction normalizeRefreshKey(refresh?: string): string | undefined {\r\n const key = refresh?.trim();\r\n return key ? key : undefined;\r\n}\r\n\r\n/**\r\n * Returns a cached auth snapshot when available, favoring unexpired tokens.\r\n */\r\nexport function resolveCachedAuth(auth: OAuthAuthDetails): OAuthAuthDetails {\r\n const key = normalizeRefreshKey(auth.refresh);\r\n if (!key) {\r\n return auth;\r\n }\r\n\r\n const cached = authCache.get(key);\r\n if (!cached) {\r\n authCache.set(key, auth);\r\n return auth;\r\n }\r\n\r\n if (!accessTokenExpired(auth)) {\r\n authCache.set(key, auth);\r\n return auth;\r\n }\r\n\r\n if (!accessTokenExpired(cached)) {\r\n return cached;\r\n }\r\n\r\n authCache.set(key, auth);\r\n return auth;\r\n}\r\n\r\n/**\r\n * Stores the latest auth snapshot keyed by refresh token.\r\n */\r\nexport function storeCachedAuth(auth: OAuthAuthDetails): void {\r\n const key = normalizeRefreshKey(auth.refresh);\r\n if (!key) {\r\n return;\r\n }\r\n authCache.set(key, auth);\r\n}\r\n\r\n/**\r\n * Clears cached auth globally or for a specific refresh token.\r\n */\r\nexport function clearCachedAuth(refresh?: string): void {\r\n if (!refresh) {\r\n authCache.clear();\r\n return;\r\n }\r\n const key = normalizeRefreshKey(refresh);\r\n if (key) {\r\n authCache.delete(key);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Thinking Signature Cache (for Claude multi-turn conversations)\r\n// ============================================================================\r\n\r\nimport { SignatureCache, createSignatureCache } from \"./cache/signature-cache\";\r\nimport type { SignatureCacheConfig } from \"./config\";\r\n\r\ninterface SignatureEntry {\r\n signature: string;\r\n timestamp: number;\r\n}\r\n\r\n// Map: sessionId -> Map<textHash, SignatureEntry>\r\nconst signatureCache = new Map<string, Map<string, SignatureEntry>>();\r\n\r\n// Cache entries expire after 1 hour\r\nconst SIGNATURE_CACHE_TTL_MS = 60 * 60 * 1000;\r\n\r\n// Maximum entries per session to prevent memory bloat\nconst MAX_ENTRIES_PER_SESSION = 100;\n\n// Maximum sessions tracked in the outer Map to prevent unbounded growth\nconst MAX_CACHED_SESSIONS = 10;\r\n// 16 hex chars = 64-bit key space; keeps memory bounded while making collisions extremely unlikely.\r\nconst SIGNATURE_TEXT_HASH_HEX_LEN = 16;\r\n\r\n// Disk cache instance (initialized via initDiskSignatureCache)\r\nlet diskCache: SignatureCache | null = null;\r\n\r\n/**\r\n * Initialize the disk-based signature cache.\r\n * Call this from plugin initialization when keep_thinking is enabled.\r\n */\r\nexport function initDiskSignatureCache(config: SignatureCacheConfig | undefined): SignatureCache | null {\r\n diskCache = createSignatureCache(config);\r\n return diskCache;\r\n}\r\n\r\n/**\r\n * Get the disk cache instance (for testing/debugging).\r\n */\r\nexport function getDiskSignatureCache(): SignatureCache | null {\r\n return diskCache;\r\n}\r\n\r\n/**\r\n * Hashes text content into a stable, Unicode-safe key.\r\n *\r\n * Uses SHA-256 over UTF-8 bytes and truncates to keep memory usage bounded.\r\n */\r\nfunction hashText(text: string): string {\r\n return createHash(\"sha256\").update(text, \"utf8\").digest(\"hex\").slice(0, SIGNATURE_TEXT_HASH_HEX_LEN);\r\n}\r\n\r\n/**\r\n * Create a disk cache key from sessionId and textHash.\r\n */\r\nfunction makeDiskKey(sessionId: string, textHash: string): string {\r\n return `${sessionId}:${textHash}`;\r\n}\r\n\r\n/**\n * Prune stale sessions from the outer signatureCache Map.\n * Removes sessions where all entries have expired, then evicts the\n * oldest sessions if the Map still exceeds MAX_CACHED_SESSIONS.\n */\nfunction pruneSignatureSessions(): void {\n if (signatureCache.size <= MAX_CACHED_SESSIONS) return;\n\n const now = Date.now();\n\n // First pass: remove sessions where ALL entries are expired\n for (const [sid, innerMap] of signatureCache) {\n let allExpired = true;\n for (const entry of innerMap.values()) {\n if (now - entry.timestamp <= SIGNATURE_CACHE_TTL_MS) {\n allExpired = false;\n break;\n }\n }\n if (allExpired) {\n signatureCache.delete(sid);\n }\n }\n\n // Second pass: if still over cap, evict oldest sessions by newest entry timestamp\n if (signatureCache.size > MAX_CACHED_SESSIONS) {\n const sessionsByAge: Array<{ sid: string; newestTs: number }> = [];\n for (const [sid, innerMap] of signatureCache) {\n let newestTs = 0;\n for (const entry of innerMap.values()) {\n if (entry.timestamp > newestTs) newestTs = entry.timestamp;\n }\n sessionsByAge.push({ sid, newestTs });\n }\n // Sort oldest-first, evict until at cap\n sessionsByAge.sort((a, b) => a.newestTs - b.newestTs);\n const toEvict = signatureCache.size - MAX_CACHED_SESSIONS;\n for (let i = 0; i < toEvict; i++) {\n const entry = sessionsByAge[i];\n if (entry) signatureCache.delete(entry.sid);\n }\n }\n}\n\n/**\n * Caches a thinking signature for a given session and text.\n * Used for Claude models that require signed thinking blocks in multi-turn conversations.\n * Also writes to disk cache if enabled.\n */\nexport function cacheSignature(sessionId: string, text: string, signature: string): void {\n if (!sessionId || !text || !signature) return;\n\n const textHash = hashText(text);\n\n // Write to memory cache\n let sessionMemCache = signatureCache.get(sessionId);\n if (!sessionMemCache) {\n // About to add a new session \u2014 prune stale ones first\n pruneSignatureSessions();\n sessionMemCache = new Map();\n signatureCache.set(sessionId, sessionMemCache);\n }\r\n // Evict old entries if we're at capacity\r\n if (sessionMemCache.size >= MAX_ENTRIES_PER_SESSION) {\r\n const now = Date.now();\r\n for (const [key, entry] of sessionMemCache.entries()) {\r\n if (now - entry.timestamp > SIGNATURE_CACHE_TTL_MS) {\r\n sessionMemCache.delete(key);\r\n }\r\n }\r\n // If still at capacity, remove oldest entries\r\n if (sessionMemCache.size >= MAX_ENTRIES_PER_SESSION) {\r\n const entries = Array.from(sessionMemCache.entries())\r\n .sort((a, b) => a[1].timestamp - b[1].timestamp);\r\n const toRemove = entries.slice(0, Math.floor(MAX_ENTRIES_PER_SESSION / 4));\r\n for (const [key] of toRemove) {\r\n sessionMemCache.delete(key);\r\n }\r\n }\r\n }\r\n\r\n sessionMemCache.set(textHash, { signature, timestamp: Date.now() });\r\n\r\n // Write to disk cache if enabled\r\n if (diskCache) {\r\n const diskKey = makeDiskKey(sessionId, textHash);\r\n diskCache.store(diskKey, signature);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves a cached signature for a given session and text.\r\n * Checks memory first, then falls back to disk cache.\r\n * Returns undefined if not found or expired.\r\n */\r\nexport function getCachedSignature(sessionId: string, text: string): string | undefined {\r\n if (!sessionId || !text) return undefined;\r\n\r\n const textHash = hashText(text);\r\n\r\n // Check memory cache first\r\n const sessionMemCache = signatureCache.get(sessionId);\r\n if (sessionMemCache) {\r\n const entry = sessionMemCache.get(textHash);\r\n if (entry) {\r\n // Check if expired\r\n if (Date.now() - entry.timestamp > SIGNATURE_CACHE_TTL_MS) {\r\n sessionMemCache.delete(textHash);\r\n } else {\r\n return entry.signature;\r\n }\r\n }\r\n }\r\n\r\n // Fall back to disk cache\r\n if (diskCache) {\r\n const diskKey = makeDiskKey(sessionId, textHash);\r\n const diskValue = diskCache.retrieve(diskKey);\r\n if (diskValue) {\r\n // Promote to memory cache for faster subsequent access\r\n let memCache = signatureCache.get(sessionId);\r\n if (!memCache) {\r\n memCache = new Map();\r\n signatureCache.set(sessionId, memCache);\r\n }\r\n memCache.set(textHash, { signature: diskValue, timestamp: Date.now() });\r\n return diskValue;\r\n }\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Clears signature cache for a specific session or all sessions.\r\n * Also clears from disk cache if enabled.\r\n */\r\nexport function clearSignatureCache(sessionId?: string): void {\r\n if (sessionId) {\r\n signatureCache.delete(sessionId);\r\n // Note: We don't clear individual sessions from disk cache to avoid\r\n // expensive iteration. Disk cache entries will expire naturally.\r\n } else {\r\n signatureCache.clear();\r\n // For full clear, we could clear disk cache, but leaving it for now\r\n // since entries have TTL and will expire naturally.\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Disk-Persistent Signature Cache (re-export from cache/ folder)\r\n// ============================================================================\r\n\r\n// Re-export SignatureCache class and factory for direct use\r\nexport { SignatureCache, createSignatureCache } from \"./cache/signature-cache\";\r\nexport type { SignatureCacheConfig } from \"./config\";\r\n", "/**\r\n * Signature cache for persisting thinking block signatures to disk.\r\n * \r\n * Features (based on LLM-API-Key-Proxy's ProviderCache):\r\n * - Dual-TTL system: short memory TTL, longer disk TTL\r\n * - Background disk persistence with batched writes\r\n * - Atomic writes with temp file + move pattern\r\n * - Automatic cleanup of expired entries\r\n * \r\n * Cache key format: `${sessionId}:${modelId}`\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync } from \"node:fs\";\r\nimport { join, dirname } from \"node:path\";\r\nimport { homedir } from \"node:os\";\r\nimport { tmpdir } from \"node:os\";\r\nimport type { SignatureCacheConfig } from \"../config\";\r\nimport { ensureGitignoreSync } from \"../storage\";\r\n\r\n// =============================================================================\r\n// Types\r\n// =============================================================================\r\n\r\ninterface CacheEntry {\r\n value: string;\r\n timestamp: number;\r\n /** Full thinking text content (optional, for recovery) */\r\n thinkingText?: string;\r\n /** Preview of the thinking text for debugging */\r\n textPreview?: string;\r\n /** Tool call IDs associated with this thinking block */\r\n toolIds?: string[];\r\n}\r\n\r\ninterface CacheData {\r\n version: \"1.0\";\r\n memory_ttl_seconds: number;\r\n disk_ttl_seconds: number;\r\n entries: Record<string, CacheEntry>;\r\n statistics: {\r\n memory_hits: number;\r\n disk_hits: number;\r\n misses: number;\r\n writes: number;\r\n last_write: number;\r\n };\r\n}\r\n\r\ninterface CacheStats {\r\n memoryHits: number;\r\n diskHits: number;\r\n misses: number;\r\n writes: number;\r\n memoryEntries: number;\r\n dirty: boolean;\r\n diskEnabled: boolean;\r\n}\r\n\r\n/**\r\n * Full thinking content with signature (for recovery)\r\n */\r\nexport interface ThinkingCacheData {\r\n text: string;\r\n signature: string;\r\n toolIds?: string[];\r\n}\r\n\r\n// =============================================================================\r\n// Path Utilities\r\n// =============================================================================\r\n\r\nfunction getConfigDir(): string {\r\n const platform = process.platform;\r\n if (platform === \"win32\") {\r\n return join(process.env.APPDATA || join(homedir(), \"AppData\", \"Roaming\"), \"opencode\");\r\n }\r\n const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), \".config\");\r\n return join(xdgConfig, \"opencode\");\r\n}\r\n\r\nfunction getCacheFilePath(): string {\r\n return join(getConfigDir(), \"antigravity-signature-cache.json\");\r\n}\r\n\r\n// =============================================================================\r\n// Signature Cache Class\r\n// =============================================================================\r\n\r\nexport class SignatureCache {\r\n // In-memory cache: key -> entry with signature and optional thinking text\r\n private cache: Map<string, CacheEntry> = new Map();\r\n \r\n // Configuration\r\n private memoryTtlMs: number;\r\n private diskTtlMs: number;\r\n private writeIntervalMs: number;\r\n private cacheFilePath: string;\r\n private enabled: boolean;\r\n \r\n // State\r\n private dirty: boolean = false;\r\n private writeTimer: ReturnType<typeof setInterval> | null = null;\r\n private cleanupTimer: ReturnType<typeof setInterval> | null = null;\r\n \r\n // Statistics\r\n private stats = {\r\n memoryHits: 0,\r\n diskHits: 0,\r\n misses: 0,\r\n writes: 0,\r\n };\r\n\r\n constructor(config: SignatureCacheConfig) {\r\n this.enabled = config.enabled;\r\n this.memoryTtlMs = config.memory_ttl_seconds * 1000;\r\n this.diskTtlMs = config.disk_ttl_seconds * 1000;\r\n this.writeIntervalMs = config.write_interval_seconds * 1000;\r\n this.cacheFilePath = getCacheFilePath();\r\n\r\n if (this.enabled) {\r\n this.loadFromDisk();\r\n this.startBackgroundTasks();\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // Public API\r\n // ===========================================================================\r\n\r\n /**\r\n * Generate a cache key from sessionId and modelId.\r\n */\r\n static makeKey(sessionId: string, modelId: string): string {\r\n return `${sessionId}:${modelId}`;\r\n }\r\n\r\n /**\r\n * Store a signature in the cache.\r\n */\r\n store(key: string, signature: string): void {\r\n if (!this.enabled) return;\r\n\r\n this.cache.set(key, {\r\n value: signature,\r\n timestamp: Date.now(),\r\n });\r\n this.dirty = true;\r\n }\r\n\r\n /**\r\n * Retrieve a signature from the cache.\r\n * Returns null if not found or expired.\r\n */\r\n retrieve(key: string): string | null {\r\n if (!this.enabled) return null;\r\n\r\n const entry = this.cache.get(key);\r\n if (entry) {\r\n const age = Date.now() - entry.timestamp;\r\n if (age <= this.memoryTtlMs) {\r\n this.stats.memoryHits++;\r\n return entry.value;\r\n }\r\n // Expired from memory, remove it\r\n this.cache.delete(key);\r\n }\r\n\r\n this.stats.misses++;\r\n return null;\r\n }\r\n\r\n /**\r\n * Check if a key exists in the cache (without updating stats).\r\n */\r\n has(key: string): boolean {\r\n if (!this.enabled) return false;\r\n\r\n const entry = this.cache.get(key);\r\n if (!entry) return false;\r\n\r\n const age = Date.now() - entry.timestamp;\r\n return age <= this.memoryTtlMs;\r\n }\r\n\r\n // ===========================================================================\r\n // Full Thinking Cache (ported from LLM-API-Key-Proxy)\r\n // ===========================================================================\r\n\r\n /**\r\n * Store full thinking content with signature.\r\n * This enables recovery even after thinking text is stripped by compaction.\r\n * \r\n * Port of LLM-API-Key-Proxy's _cache_thinking()\r\n */\r\n storeThinking(\r\n key: string,\r\n thinkingText: string,\r\n signature: string,\r\n toolIds?: string[],\r\n ): void {\r\n if (!this.enabled || !thinkingText || !signature) return;\r\n\r\n this.cache.set(key, {\r\n value: signature,\r\n timestamp: Date.now(),\r\n thinkingText,\r\n textPreview: thinkingText.slice(0, 100),\r\n toolIds,\r\n });\r\n this.dirty = true;\r\n }\r\n\r\n /**\r\n * Retrieve full thinking content by key.\r\n * Returns null if not found or expired.\r\n */\r\n retrieveThinking(key: string): ThinkingCacheData | null {\r\n if (!this.enabled) return null;\r\n\r\n const entry = this.cache.get(key);\r\n if (!entry || !entry.thinkingText) return null;\r\n\r\n const age = Date.now() - entry.timestamp;\r\n if (age > this.memoryTtlMs) {\r\n this.cache.delete(key);\r\n return null;\r\n }\r\n\r\n this.stats.memoryHits++;\r\n return {\r\n text: entry.thinkingText,\r\n signature: entry.value,\r\n toolIds: entry.toolIds,\r\n };\r\n }\r\n\r\n /**\r\n * Check if full thinking content exists for a key.\r\n */\r\n hasThinking(key: string): boolean {\r\n if (!this.enabled) return false;\r\n\r\n const entry = this.cache.get(key);\r\n if (!entry || !entry.thinkingText) return false;\r\n\r\n const age = Date.now() - entry.timestamp;\r\n return age <= this.memoryTtlMs;\r\n }\r\n\r\n /**\r\n * Get cache statistics.\r\n */\r\n getStats(): CacheStats {\r\n return {\r\n ...this.stats,\r\n memoryEntries: this.cache.size,\r\n dirty: this.dirty,\r\n diskEnabled: this.enabled,\r\n };\r\n }\r\n\r\n /**\r\n * Manually trigger a disk save.\r\n */\r\n async flush(): Promise<boolean> {\r\n if (!this.enabled) return true;\r\n return this.saveToDisk();\r\n }\r\n\r\n /**\r\n * Graceful shutdown: stop timers and flush to disk.\r\n */\r\n shutdown(): void {\r\n if (this.writeTimer) {\r\n clearInterval(this.writeTimer);\r\n this.writeTimer = null;\r\n }\r\n if (this.cleanupTimer) {\r\n clearInterval(this.cleanupTimer);\r\n this.cleanupTimer = null;\r\n }\r\n\r\n if (this.dirty && this.enabled) {\r\n this.saveToDisk();\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // Disk Operations\r\n // ===========================================================================\r\n\r\n /**\r\n * Load cache from disk file with TTL validation.\r\n */\r\n private loadFromDisk(): void {\r\n try {\r\n if (!existsSync(this.cacheFilePath)) {\r\n return;\r\n }\r\n\r\n const content = readFileSync(this.cacheFilePath, \"utf-8\");\r\n const data = JSON.parse(content) as CacheData;\r\n\r\n if (data.version !== \"1.0\") {\r\n // Version mismatch - silently start fresh\r\n return;\r\n }\r\n\r\n const now = Date.now();\r\n let loaded = 0;\r\n let expired = 0;\r\n\r\n for (const [key, entry] of Object.entries(data.entries)) {\r\n const age = now - entry.timestamp;\r\n if (age <= this.diskTtlMs) {\r\n this.cache.set(key, {\r\n value: entry.value,\r\n timestamp: entry.timestamp,\r\n });\r\n loaded++;\r\n } else {\r\n expired++;\r\n }\r\n }\r\n\r\n // Silently load - no console output\r\n } catch {\r\n // Silently start fresh on any error (corruption, file not found, etc.)\r\n }\r\n }\r\n\r\n /**\r\n * Save cache to disk with atomic write pattern.\r\n * Merges with existing disk entries that haven't expired.\r\n */\r\n private saveToDisk(): boolean {\r\n try {\r\n // Ensure directory exists\r\n const dir = dirname(this.cacheFilePath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n\r\n ensureGitignoreSync(dir);\r\n\r\n const now = Date.now();\r\n\r\n // Step 1: Load existing disk entries (if any)\r\n let existingEntries: Record<string, CacheEntry> = {};\r\n if (existsSync(this.cacheFilePath)) {\r\n try {\r\n const content = readFileSync(this.cacheFilePath, \"utf-8\");\r\n const data = JSON.parse(content) as CacheData;\r\n existingEntries = data.entries || {};\r\n } catch {\r\n // Start fresh if corrupted\r\n }\r\n }\r\n\r\n // Step 2: Filter existing disk entries by disk_ttl\r\n const validDiskEntries: Record<string, CacheEntry> = {};\r\n for (const [key, entry] of Object.entries(existingEntries)) {\r\n const age = now - entry.timestamp;\r\n if (age <= this.diskTtlMs) {\r\n validDiskEntries[key] = entry;\r\n }\r\n }\r\n\r\n // Step 3: Merge - memory entries take precedence\r\n const mergedEntries: Record<string, CacheEntry> = { ...validDiskEntries };\r\n for (const [key, entry] of this.cache.entries()) {\r\n mergedEntries[key] = {\r\n value: entry.value,\r\n timestamp: entry.timestamp,\r\n };\r\n }\r\n\r\n // Step 4: Build cache data\r\n const cacheData: CacheData = {\r\n version: \"1.0\",\r\n memory_ttl_seconds: this.memoryTtlMs / 1000,\r\n disk_ttl_seconds: this.diskTtlMs / 1000,\r\n entries: mergedEntries,\r\n statistics: {\r\n memory_hits: this.stats.memoryHits,\r\n disk_hits: this.stats.diskHits,\r\n misses: this.stats.misses,\r\n writes: this.stats.writes + 1,\r\n last_write: now,\r\n },\r\n };\r\n\r\n // Step 5: Atomic write (temp file + rename)\r\n const tmpPath = join(tmpdir(), `antigravity-cache-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);\r\n writeFileSync(tmpPath, JSON.stringify(cacheData, null, 2), \"utf-8\");\r\n\r\n try {\r\n renameSync(tmpPath, this.cacheFilePath);\r\n } catch {\r\n // On Windows, rename across volumes may fail\r\n // Fall back to copy + delete\r\n writeFileSync(this.cacheFilePath, readFileSync(tmpPath));\r\n try {\r\n unlinkSync(tmpPath);\r\n } catch {\r\n // Ignore cleanup errors\r\n }\r\n }\r\n\r\n this.stats.writes++;\r\n this.dirty = false;\r\n return true;\r\n } catch {\r\n // Silently fail - disk cache is optional\r\n return false;\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // Background Tasks\r\n // ===========================================================================\r\n\r\n /**\r\n * Start background write and cleanup timers.\r\n */\r\n private startBackgroundTasks(): void {\r\n // Periodic disk writes\r\n this.writeTimer = setInterval(() => {\r\n if (this.dirty) {\r\n this.saveToDisk();\r\n }\r\n }, this.writeIntervalMs);\r\n\r\n // Periodic memory cleanup (every 30 minutes)\r\n this.cleanupTimer = setInterval(() => {\r\n this.cleanupExpired();\r\n }, 30 * 60 * 1000);\r\n }\r\n\r\n /**\r\n * Remove expired entries from memory.\r\n */\r\n private cleanupExpired(): void {\r\n const now = Date.now();\r\n let cleaned = 0;\r\n\r\n for (const [key, entry] of this.cache.entries()) {\r\n const age = now - entry.timestamp;\r\n if (age > this.memoryTtlMs) {\r\n this.cache.delete(key);\r\n cleaned++;\r\n }\r\n }\r\n\r\n // Silently clean - no console output\r\n }\r\n}\r\n\r\n// =============================================================================\r\n// Factory Function\r\n// =============================================================================\r\n\r\n/**\r\n * Create a signature cache with the given configuration.\r\n * Returns null if caching is disabled.\r\n */\r\nexport function createSignatureCache(config: SignatureCacheConfig | undefined): SignatureCache | null {\r\n if (!config || !config.enabled) {\r\n return null;\r\n }\r\n\r\n return new SignatureCache(config);\r\n}\r\n", "/**\r\n * Configuration schema for opencode-antigravity-auth plugin.\r\n * \r\n * Config file locations (in priority order, highest wins):\r\n * - Project: .opencode/antigravity.json\r\n * - User: ~/.config/opencode/antigravity.json (Linux/Mac)\r\n * %APPDATA%\\opencode\\antigravity.json (Windows)\r\n * \r\n * Environment variables always override config file values.\r\n */\r\n\r\nimport { z } from \"zod\";\r\n\r\n/**\r\n * Account selection strategy for distributing requests across accounts.\r\n * \r\n * - `sticky`: Use same account until rate-limited. Preserves prompt cache.\r\n * - `round-robin`: Rotate to next account on every request. Maximum throughput.\r\n * - `hybrid` (default): Deterministic selection based on health score + token bucket + LRU freshness.\r\n */\r\nexport const AccountSelectionStrategySchema = z.enum(['sticky', 'round-robin', 'hybrid']);\r\nexport type AccountSelectionStrategy = z.infer<typeof AccountSelectionStrategySchema>;\r\n\r\n/**\r\n * Toast notification scope for controlling which sessions show toasts.\r\n * \r\n * - `root_only` (default): Only show toasts for root sessions (no parentID).\r\n * Subagents and background tasks won't show toast notifications.\r\n * - `all`: Show toasts for all sessions including subagents and background tasks.\r\n */\r\nexport const ToastScopeSchema = z.enum(['root_only', 'all']);\r\nexport type ToastScope = z.infer<typeof ToastScopeSchema>;\r\n\r\n/**\r\n * Scheduling mode for rate limit behavior.\r\n * \r\n * - `cache_first`: Wait for same account to recover (preserves prompt cache). Default.\r\n * - `balance`: Switch account immediately on rate limit. Maximum availability.\r\n * - `performance_first`: Round-robin distribution for maximum throughput.\r\n */\r\nexport const SchedulingModeSchema = z.enum(['cache_first', 'balance', 'performance_first']);\r\nexport type SchedulingMode = z.infer<typeof SchedulingModeSchema>;\r\n\r\n/**\r\n * Signature cache configuration for persisting thinking block signatures to disk.\r\n */\r\nexport const SignatureCacheConfigSchema = z.object({\r\n /** Enable disk caching of signatures (default: true) */\r\n enabled: z.boolean().default(true),\r\n \r\n /** In-memory TTL in seconds (default: 3600 = 1 hour) */\r\n memory_ttl_seconds: z.number().min(60).max(86400).default(3600),\r\n \r\n /** Disk TTL in seconds (default: 172800 = 48 hours) */\r\n disk_ttl_seconds: z.number().min(3600).max(604800).default(172800),\r\n \r\n /** Background write interval in seconds (default: 60) */\r\n write_interval_seconds: z.number().min(10).max(600).default(60),\r\n});\r\n\r\n/**\r\n * Main configuration schema for the Antigravity OAuth plugin.\r\n */\r\nexport const AntigravityConfigSchema = z.object({\r\n /** JSON Schema reference for IDE support */\r\n $schema: z.string().optional(),\r\n \r\n // =========================================================================\r\n // General Settings\r\n // =========================================================================\r\n \r\n /** \r\n * Suppress most toast notifications (rate limit, account switching, etc.)\r\n * Recovery toasts are always shown regardless of this setting.\r\n * Env override: OPENCODE_ANTIGRAVITY_QUIET=1\r\n * @default false\r\n */\r\n quiet_mode: z.boolean().default(false),\r\n \r\n /**\r\n * Control which sessions show toast notifications.\r\n * \r\n * - `root_only` (default): Only root sessions show toasts.\r\n * Subagents and background tasks will be silent (less spam).\r\n * - `all`: All sessions show toasts including subagents and background tasks.\r\n * \r\n * Debug logging captures all toasts regardless of this setting.\r\n * Env override: OPENCODE_ANTIGRAVITY_TOAST_SCOPE=all\r\n * @default \"root_only\"\r\n */\r\n toast_scope: ToastScopeSchema.default('root_only'),\r\n \r\n /**\r\n * Enable debug logging to file.\r\n * Env override: OPENCODE_ANTIGRAVITY_DEBUG=1\r\n * @default false\r\n */\r\n debug: z.boolean().default(false),\r\n\r\n /**\r\n * Show debug logs in the TUI log panel.\r\n * Works independently from `debug` file logging.\r\n * Env override: OPENCODE_ANTIGRAVITY_DEBUG_TUI=1\r\n * @default false\r\n */\r\n debug_tui: z.boolean().default(false),\r\n \r\n /**\r\n * Custom directory for debug logs.\r\n * Env override: OPENCODE_ANTIGRAVITY_LOG_DIR=/path/to/logs\r\n * @default OS-specific config dir + \"/antigravity-logs\"\r\n */\r\n log_dir: z.string().optional(),\r\n \r\n // =========================================================================\r\n // Thinking Blocks\r\n // =========================================================================\r\n \r\n /**\r\n * Preserve thinking blocks for Claude models using signature caching.\r\n * \r\n * When false (default): Thinking blocks are stripped for reliability.\r\n * When true: Full context preserved, but may encounter signature errors.\r\n * \r\n * Env override: OPENCODE_ANTIGRAVITY_KEEP_THINKING=1\r\n * @default false\r\n */\r\n keep_thinking: z.boolean().default(false),\r\n \r\n // =========================================================================\r\n // Session Recovery\r\n // =========================================================================\r\n \r\n /**\r\n * Enable automatic session recovery from tool_result_missing errors.\r\n * When enabled, shows a toast notification when recoverable errors occur.\r\n * \r\n * @default true\r\n */\r\n session_recovery: z.boolean().default(true),\r\n \r\n /**\r\n * Automatically send a \"continue\" prompt after successful recovery.\r\n * Only applies when session_recovery is enabled.\r\n * \r\n * When false: Only shows toast notification, user must manually continue.\r\n * When true: Automatically sends \"continue\" to resume the session.\r\n * \r\n * @default false\r\n */\r\n auto_resume: z.boolean().default(false),\r\n \r\n /**\r\n * Custom text to send when auto-resuming after recovery.\r\n * Only used when auto_resume is enabled.\r\n * \r\n * @default \"continue\"\r\n */\r\n resume_text: z.string().default(\"continue\"),\r\n \r\n // =========================================================================\r\n // Signature Caching\r\n // =========================================================================\r\n \r\n /**\r\n * Signature cache configuration for persisting thinking block signatures.\r\n * Only used when keep_thinking is enabled.\r\n */\r\n signature_cache: SignatureCacheConfigSchema.optional(),\r\n \r\n // =========================================================================\r\n // Empty Response Retry (ported from LLM-API-Key-Proxy)\r\n // =========================================================================\r\n \r\n /**\r\n * Maximum retry attempts when Antigravity returns an empty response.\r\n * Empty responses occur when no candidates/choices are returned.\r\n * \r\n * @default 4\r\n */\r\n empty_response_max_attempts: z.number().min(1).max(10).default(4),\r\n \r\n /**\r\n * Delay in milliseconds between empty response retries.\r\n * \r\n * @default 2000\r\n */\r\n empty_response_retry_delay_ms: z.number().min(500).max(10000).default(2000),\r\n \r\n // =========================================================================\r\n // Tool ID Recovery (ported from LLM-API-Key-Proxy)\r\n // =========================================================================\r\n \r\n /**\r\n * Enable tool ID orphan recovery.\r\n * When tool responses have mismatched IDs (due to context compaction),\r\n * attempt to match them by function name or create placeholders.\r\n * \r\n * @default true\r\n */\r\n tool_id_recovery: z.boolean().default(true),\r\n \r\n // =========================================================================\r\n // Tool Hallucination Prevention (ported from LLM-API-Key-Proxy)\r\n // =========================================================================\r\n \r\n /**\r\n * Enable tool hallucination prevention for Claude models.\r\n * When enabled, injects:\r\n * - Parameter signatures into tool descriptions\r\n * - System instruction with strict tool usage rules\r\n * \r\n * This helps prevent Claude from using parameter names from its training\r\n * data instead of the actual schema.\r\n * \r\n * @default true\r\n */\r\n claude_tool_hardening: z.boolean().default(true),\r\n\r\n /**\r\n * Enable Claude prompt auto-caching by adding top-level cache_control when absent.\r\n *\r\n * @default false\r\n */\r\n claude_prompt_auto_caching: z.boolean().default(false),\r\n \r\n // =========================================================================\r\n // Proactive Token Refresh (ported from LLM-API-Key-Proxy)\r\n // =========================================================================\r\n \r\n /**\r\n * Enable proactive background token refresh.\r\n * When enabled, tokens are refreshed in the background before they expire,\r\n * ensuring requests never block on token refresh.\r\n * \r\n * @default true\r\n */\r\n proactive_token_refresh: z.boolean().default(true),\r\n \r\n /**\r\n * Seconds before token expiry to trigger proactive refresh.\r\n * Default is 30 minutes (1800 seconds).\r\n * \r\n * @default 1800\r\n */\r\n proactive_refresh_buffer_seconds: z.number().min(60).max(7200).default(1800),\r\n \r\n /**\r\n * Interval between proactive refresh checks in seconds.\r\n * Default is 5 minutes (300 seconds).\r\n * \r\n * @default 300\r\n */\r\n proactive_refresh_check_interval_seconds: z.number().min(30).max(1800).default(300),\r\n \r\n // =========================================================================\r\n // Rate Limiting\r\n // =========================================================================\r\n \r\n /**\r\n * Maximum time in seconds to wait when all accounts are rate-limited.\r\n * If the minimum wait time across all accounts exceeds this threshold,\r\n * the plugin fails fast with an error instead of hanging.\r\n * \r\n * Set to 0 to disable (wait indefinitely).\r\n * \r\n * @default 300 (5 minutes)\r\n */\r\n max_rate_limit_wait_seconds: z.number().min(0).max(3600).default(300),\r\n \r\n /**\r\n * @deprecated Kept only for backward compatibility.\r\n * This flag is ignored at runtime.\r\n * Gemini requests always fall back between Antigravity and Gemini CLI quotas.\r\n *\r\n * @default false\r\n */\r\n quota_fallback: z.boolean().default(false),\r\n\r\n /**\r\n * Prefer gemini-cli routing before Antigravity for Gemini models.\r\n * \r\n * When false (default): Antigravity is tried first, then gemini-cli.\r\n * When true: gemini-cli is tried first, then Antigravity.\r\n * \r\n * @default false\r\n */\r\n cli_first: z.boolean().default(false),\r\n \r\n /**\r\n * Strategy for selecting accounts when making requests.\r\n * Env override: OPENCODE_ANTIGRAVITY_ACCOUNT_SELECTION_STRATEGY\r\n * @default \"hybrid\"\r\n */\r\n account_selection_strategy: AccountSelectionStrategySchema.default('hybrid'),\r\n \r\n /**\r\n * Enable PID-based account offset for multi-session distribution.\r\n * \r\n * When enabled, different sessions (PIDs) will prefer different starting\r\n * accounts, which helps distribute load when running multiple parallel agents.\r\n * \r\n * When disabled (default), accounts start from the same index, which preserves\r\n * Anthropic's prompt cache across restarts (recommended for single-session use).\r\n * \r\n * Env override: OPENCODE_ANTIGRAVITY_PID_OFFSET_ENABLED=1\r\n * @default false\r\n */\r\n pid_offset_enabled: z.boolean().default(false),\r\n \r\n /**\r\n * Switch to another account immediately on first rate limit (after 1s delay).\r\n * When disabled, retries same account first, then switches on second rate limit.\r\n * \r\n * @default true\r\n */\r\n switch_on_first_rate_limit: z.boolean().default(true),\r\n \r\n /**\r\n * Scheduling mode for rate limit behavior.\r\n * \r\n * - `cache_first`: Wait for same account to recover (preserves prompt cache). Default.\r\n * - `balance`: Switch account immediately on rate limit. Maximum availability.\r\n * - `performance_first`: Round-robin distribution for maximum throughput.\r\n * \r\n * Env override: OPENCODE_ANTIGRAVITY_SCHEDULING_MODE\r\n * @default \"cache_first\"\r\n */\r\n scheduling_mode: SchedulingModeSchema.default('cache_first'),\r\n \r\n /**\r\n * Maximum seconds to wait for same account in cache_first mode.\r\n * If the account's rate limit reset time exceeds this, switch accounts.\r\n * \r\n * @default 60\r\n */\r\n max_cache_first_wait_seconds: z.number().min(5).max(300).default(60),\r\n \r\n /**\r\n * TTL in seconds for failure count expiration.\r\n * After this period of no failures, consecutiveFailures resets to 0.\r\n * This prevents old failures from permanently penalizing an account.\r\n * \r\n * @default 3600 (1 hour)\r\n */\r\n failure_ttl_seconds: z.number().min(60).max(7200).default(3600),\r\n \r\n /**\r\n * Default retry delay in seconds when API doesn't return a retry-after header.\r\n * Lower values allow faster retries but may trigger more 429 errors.\r\n * \r\n * @default 60\r\n */\r\n default_retry_after_seconds: z.number().min(1).max(300).default(60),\r\n \r\n /**\r\n * Maximum backoff delay in seconds for exponential retry.\r\n * This caps how long the exponential backoff can grow.\r\n * \r\n * @default 60\r\n */\r\n max_backoff_seconds: z.number().min(5).max(300).default(60),\r\n \r\n /**\r\n * Maximum random delay in milliseconds before each API request.\r\n * Adds timing jitter to break predictable request cadence patterns.\r\n * Set to 0 to disable request jitter.\r\n * \r\n * @default 0\r\n */\r\n request_jitter_max_ms: z.number().min(0).max(5000).default(0),\r\n \r\n /**\r\n * Soft quota threshold percentage (1-100).\r\n * When an account's quota usage reaches this percentage, skip it during\r\n * account selection (same as if it were rate-limited).\r\n * \r\n * Example: 90 means skip account when 90% of quota is used (10% remaining).\r\n * Set to 100 to disable soft quota protection.\r\n * \r\n * @default 90\r\n */\r\n soft_quota_threshold_percent: z.number().min(1).max(100).default(90),\r\n \r\n /**\r\n * How often to refresh quota data in the background (in minutes).\r\n * Quota is refreshed opportunistically after successful API requests.\r\n * Set to 0 to disable automatic refresh (manual only via Check quotas).\r\n * \r\n * @default 15\r\n */\r\n quota_refresh_interval_minutes: z.number().min(0).max(60).default(15),\r\n \r\n /**\r\n * How long quota cache is considered fresh for threshold checks (in minutes).\r\n * After this time, cache is stale and account is allowed (fail-open).\r\n * \r\n * \"auto\" = derive from refresh interval: max(2 * refresh_interval, 10)\r\n * \r\n * @default \"auto\"\r\n */\r\n soft_quota_cache_ttl_minutes: z.union([\r\n z.literal(\"auto\"),\r\n z.number().min(1).max(120)\r\n ]).default(\"auto\"),\r\n \r\n // =========================================================================\r\n // Health Score (used by hybrid strategy)\r\n // =========================================================================\r\n \r\n health_score: z.object({\r\n initial: z.number().min(0).max(100).default(70),\r\n success_reward: z.number().min(0).max(10).default(1),\r\n rate_limit_penalty: z.number().min(-50).max(0).default(-10),\r\n failure_penalty: z.number().min(-100).max(0).default(-20),\r\n recovery_rate_per_hour: z.number().min(0).max(20).default(2),\r\n min_usable: z.number().min(0).max(100).default(50),\r\n max_score: z.number().min(50).max(100).default(100),\r\n }).optional(),\r\n \r\n // =========================================================================\r\n // Token Bucket (for hybrid strategy)\r\n // =========================================================================\r\n \r\n token_bucket: z.object({\r\n max_tokens: z.number().min(1).max(1000).default(50),\r\n regeneration_rate_per_minute: z.number().min(0.1).max(60).default(6),\r\n initial_tokens: z.number().min(1).max(1000).default(50),\r\n }).optional(),\r\n \r\n // =========================================================================\r\n // Auto-Update\r\n // =========================================================================\r\n \r\n /**\r\n * Enable automatic plugin updates.\r\n * @default true\r\n */\r\n auto_update: z.boolean().default(true),\r\n\r\n});\r\n\r\nexport type AntigravityConfig = z.infer<typeof AntigravityConfigSchema>;\r\nexport type SignatureCacheConfig = z.infer<typeof SignatureCacheConfigSchema>;\r\n\r\n/**\r\n * Default configuration values.\r\n */\r\nexport const DEFAULT_CONFIG: AntigravityConfig = {\r\n quiet_mode: false,\r\n toast_scope: 'root_only',\r\n debug: false,\r\n debug_tui: false,\r\n keep_thinking: false,\r\n session_recovery: true,\r\n auto_resume: true,\r\n resume_text: \"continue\",\r\n empty_response_max_attempts: 4,\r\n empty_response_retry_delay_ms: 2000,\r\n tool_id_recovery: true,\r\n claude_tool_hardening: true,\r\n claude_prompt_auto_caching: false,\r\n proactive_token_refresh: true,\r\n proactive_refresh_buffer_seconds: 1800,\r\n proactive_refresh_check_interval_seconds: 300,\r\n max_rate_limit_wait_seconds: 300,\r\n quota_fallback: false,\r\n cli_first: false,\r\n account_selection_strategy: 'hybrid',\r\n pid_offset_enabled: false,\r\n switch_on_first_rate_limit: true,\r\n scheduling_mode: 'cache_first',\r\n max_cache_first_wait_seconds: 60,\r\n failure_ttl_seconds: 3600,\r\n default_retry_after_seconds: 60,\r\n max_backoff_seconds: 60,\r\n request_jitter_max_ms: 0,\r\n soft_quota_threshold_percent: 90,\r\n quota_refresh_interval_minutes: 15,\r\n soft_quota_cache_ttl_minutes: \"auto\",\r\n auto_update: true,\r\n signature_cache: {\r\n enabled: true,\r\n memory_ttl_seconds: 3600,\r\n disk_ttl_seconds: 172800,\r\n write_interval_seconds: 60,\r\n },\r\n health_score: {\r\n initial: 70,\r\n success_reward: 1,\r\n rate_limit_penalty: -10,\r\n failure_penalty: -20,\r\n recovery_rate_per_hour: 2,\r\n min_usable: 50,\r\n max_score: 100,\r\n },\r\n token_bucket: {\r\n max_tokens: 50,\r\n regeneration_rate_per_minute: 6,\r\n initial_tokens: 50,\r\n },\r\n};\r\n", "/**\r\n * Configuration loader for opencode-antigravity-auth plugin.\r\n * \r\n * Loads config from files.\r\n * Priority (lowest to highest):\r\n * 1. Schema defaults\r\n * 2. User config file\r\n * 3. Project config file\r\n */\r\n\r\nimport { existsSync, readFileSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\nimport { homedir } from \"node:os\";\r\nimport { AntigravityConfigSchema, DEFAULT_CONFIG, type AntigravityConfig } from \"./schema\";\r\nimport { createLogger } from \"../logger\";\r\n\r\nconst log = createLogger(\"config\");\r\n\r\n// =============================================================================\r\n// Path Utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Get the config directory path, with the following precedence:\r\n * 1. OPENCODE_CONFIG_DIR env var (if set)\r\n * 2. ~/.config/opencode (all platforms, including Windows)\r\n */\r\nfunction getConfigDir(): string {\r\n // 1. Check for explicit override via env var\r\n if (process.env.OPENCODE_CONFIG_DIR) {\r\n return process.env.OPENCODE_CONFIG_DIR;\r\n }\r\n\r\n // 2. Use ~/.config/opencode on all platforms (including Windows)\r\n const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), \".config\");\r\n return join(xdgConfig, \"opencode\");\r\n}\r\n\r\n/**\r\n * Get the user-level config file path.\r\n */\r\nexport function getUserConfigPath(): string {\r\n return join(getConfigDir(), \"antigravity.json\");\r\n}\r\n\r\n/**\r\n * Get the project-level config file path.\r\n */\r\nexport function getProjectConfigPath(directory: string): string {\r\n return join(directory, \".opencode\", \"antigravity.json\");\r\n}\r\n\r\n// =============================================================================\r\n// Config Loading\r\n// =============================================================================\r\n\r\n/**\r\n * Load and parse a config file, returning null if not found or invalid.\r\n */\r\nfunction loadConfigFile(path: string): Partial<AntigravityConfig> | null {\r\n try {\r\n if (!existsSync(path)) {\r\n return null;\r\n }\r\n\r\n const content = readFileSync(path, \"utf-8\");\r\n const rawConfig = JSON.parse(content);\r\n\r\n // Validate with Zod (partial - we'll merge with defaults later)\r\n const result = AntigravityConfigSchema.partial().safeParse(rawConfig);\r\n\r\n if (!result.success) {\r\n log.warn(\"Config validation error\", {\r\n path,\r\n issues: result.error.issues.map(i => `${i.path.join(\".\")}: ${i.message}`).join(\", \"),\r\n });\r\n return null;\r\n }\r\n\r\n return result.data;\r\n } catch (error) {\r\n if (error instanceof SyntaxError) {\r\n log.warn(\"Invalid JSON in config file\", { path, error: error.message });\r\n } else {\r\n log.warn(\"Failed to load config file\", { path, error: String(error) });\r\n }\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Deep merge two config objects, with override taking precedence.\r\n */\r\nfunction mergeConfigs(\r\n base: AntigravityConfig,\r\n override: Partial<AntigravityConfig>\r\n): AntigravityConfig {\r\n return {\r\n ...base,\r\n ...override,\r\n // Deep merge signature_cache if both exist\r\n signature_cache: override.signature_cache\r\n ? {\r\n ...base.signature_cache,\r\n ...override.signature_cache,\r\n }\r\n : base.signature_cache,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// Main Loader\r\n// =============================================================================\r\n\r\n/**\r\n * Load the complete configuration.\r\n * \r\n * @param directory - The project directory (for project-level config)\r\n * @returns Fully resolved configuration\r\n */\r\nexport function loadConfig(directory: string): AntigravityConfig {\r\n // Start with defaults\r\n let config: AntigravityConfig = { ...DEFAULT_CONFIG };\r\n\r\n // Load user config file (if exists)\r\n const userConfigPath = getUserConfigPath();\r\n const userConfig = loadConfigFile(userConfigPath);\r\n if (userConfig) {\r\n config = mergeConfigs(config, userConfig);\r\n }\r\n\r\n // Load project config file (if exists) - overrides user config\r\n const projectConfigPath = getProjectConfigPath(directory);\r\n const projectConfig = loadConfigFile(projectConfigPath);\r\n if (projectConfig) {\r\n config = mergeConfigs(config, projectConfig);\r\n }\r\n\r\n return config;\r\n}\r\n\r\n/**\r\n * Check if a config file exists at the given path.\r\n */\r\nexport function configExists(path: string): boolean {\r\n return existsSync(path);\r\n}\r\n\r\n/**\r\n * Get the default logs directory.\r\n */\r\nexport function getDefaultLogsDir(): string {\r\n return join(getConfigDir(), \"antigravity-logs\");\r\n}\r\n\r\nlet runtimeConfig: AntigravityConfig | null = null;\r\n\r\nexport function initRuntimeConfig(config: AntigravityConfig): void {\r\n runtimeConfig = config;\r\n}\r\n\r\nexport function getKeepThinking(): boolean {\r\n return runtimeConfig?.keep_thinking ?? false;\r\n}\r\n", "/**\r\n * Image Saving Utility\r\n * \r\n * Handles saving generated images to disk and returning file paths.\r\n */\r\n\r\nimport * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport * as os from 'os';\r\n\r\n/**\r\n * Default directory for saving generated images.\r\n * Uses ~/.opencode/generated-images/\r\n */\r\nfunction getImageOutputDir(): string {\r\n const homeDir = os.homedir();\r\n const outputDir = path.join(homeDir, '.opencode', 'generated-images');\r\n \r\n // Create directory if it doesn't exist\r\n if (!fs.existsSync(outputDir)) {\r\n fs.mkdirSync(outputDir, { recursive: true });\r\n }\r\n \r\n return outputDir;\r\n}\r\n\r\n/**\r\n * Generate a unique filename for the image.\r\n */\r\nfunction generateImageFilename(mimeType: string): string {\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\r\n const random = Math.random().toString(36).substring(2, 8);\r\n \r\n // Determine extension from mime type\r\n let ext = 'png';\r\n if (mimeType.includes('jpeg') || mimeType.includes('jpg')) {\r\n ext = 'jpg';\r\n } else if (mimeType.includes('gif')) {\r\n ext = 'gif';\r\n } else if (mimeType.includes('webp')) {\r\n ext = 'webp';\r\n }\r\n \r\n return `image-${timestamp}-${random}.${ext}`;\r\n}\r\n\r\n/**\r\n * Save base64 image data to disk and return the file path.\r\n * \r\n * @param base64Data - The base64-encoded image data\r\n * @param mimeType - The MIME type of the image (e.g., \"image/jpeg\")\r\n * @returns The absolute path to the saved image file\r\n */\r\nexport function saveImageToDisk(base64Data: string, mimeType: string): string {\r\n try {\r\n const outputDir = getImageOutputDir();\r\n const filename = generateImageFilename(mimeType);\r\n const filePath = path.join(outputDir, filename);\r\n \r\n // Decode base64 and write to file\r\n const buffer = Buffer.from(base64Data, 'base64');\r\n fs.writeFileSync(filePath, buffer);\r\n \r\n return filePath;\r\n } catch (error) {\r\n // If saving fails, return empty string (caller will fall back to base64)\r\n console.error('[image-saver] Failed to save image:', error);\r\n return '';\r\n }\r\n}\r\n\r\n/**\r\n * Process inlineData and return either a file path or base64 data URL.\r\n * Attempts to save to disk first, falls back to base64 if saving fails.\r\n * \r\n * @param inlineData - Object containing mimeType and base64 data\r\n * @returns Markdown image string with either file path or data URL\r\n */\r\nexport function processImageData(inlineData: { mimeType?: string; data?: string }): string | null {\r\n const mimeType = inlineData.mimeType || 'image/png';\r\n const data = inlineData.data;\r\n \r\n if (!data) {\r\n return null;\r\n }\r\n \r\n // Try to save to disk first\r\n const filePath = saveImageToDisk(data, mimeType);\r\n \r\n if (filePath) {\r\n // Successfully saved - return file path with open command hint\r\n return `![Generated Image](${filePath})\\n\\nImage saved to: \\`${filePath}\\`\\n\\nTo view: \\`open \"${filePath}\"\\``;\r\n }\r\n \r\n // Fall back to base64 data URL\r\n return `![Generated Image](data:${mimeType};base64,${data})`;\r\n}\r\n", "import type {\r\n SignatureStore,\r\n StreamingCallbacks,\r\n StreamingOptions,\r\n ThoughtBuffer,\r\n} from './types';\r\nimport { processImageData } from '../../image-saver';\r\n\r\n/**\r\n * Simple string hash for thinking deduplication.\r\n * Uses DJB2-like algorithm.\r\n */\r\nfunction hashString(str: string): string {\r\n let hash = 5381;\r\n for (let i = 0; i < str.length; i++) {\r\n hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */\r\n }\r\n return (hash >>> 0).toString(16);\r\n}\r\n\r\nexport function createThoughtBuffer(): ThoughtBuffer {\r\n const buffer = new Map<number, string>();\r\n return {\r\n get: (index: number) => buffer.get(index),\r\n set: (index: number, text: string) => buffer.set(index, text),\r\n clear: () => buffer.clear(),\r\n };\r\n}\r\n\r\nexport function transformStreamingPayload(\r\n payload: string,\r\n transformThinkingParts?: (response: unknown) => unknown,\r\n): string {\r\n return payload\r\n .split('\\n')\r\n .map((line) => {\r\n if (!line.startsWith('data:')) {\r\n return line;\r\n }\r\n const json = line.slice(5).trim();\r\n if (!json) {\r\n return line;\r\n }\r\n try {\r\n const parsed = JSON.parse(json) as { response?: unknown };\r\n if (parsed.response !== undefined) {\r\n const transformed = transformThinkingParts\r\n ? transformThinkingParts(parsed.response)\r\n : parsed.response;\r\n return `data: ${JSON.stringify(transformed)}`;\r\n }\r\n } catch (_) {\n console.warn(\"[antigravity] Malformed SSE chunk, passing through untransformed:\", json.slice(0, 200));\n }\n return line;\n })\n .join('\\n');\n}\r\nexport function deduplicateThinkingText(\r\n response: unknown,\r\n sentBuffer: ThoughtBuffer,\r\n displayedThinkingHashes?: Set<string>,\r\n): unknown {\r\n if (!response || typeof response !== 'object') return response;\r\n\r\n const resp = response as Record<string, unknown>;\r\n\r\n if (Array.isArray(resp.candidates)) {\r\n const newCandidates = resp.candidates.map((candidate: unknown, index: number) => {\r\n const cand = candidate as Record<string, unknown> | null;\r\n if (!cand?.content) return candidate;\r\n\r\n const content = cand.content as Record<string, unknown>;\r\n if (!Array.isArray(content.parts)) return candidate;\r\n\r\n const newParts = content.parts.flatMap((part: unknown) => {\n const p = part as Record<string, unknown>;\r\n \r\n // Handle image data - save to disk and return file path\r\n if (p.inlineData) {\r\n const inlineData = p.inlineData as Record<string, unknown>;\r\n const result = processImageData({\r\n mimeType: inlineData.mimeType as string | undefined,\r\n data: inlineData.data as string | undefined,\r\n });\r\n if (result) {\r\n return { text: result };\r\n }\r\n }\r\n \r\n if (p.thought === true || p.type === 'thinking') {\n const fullText = typeof p.text === \"string\" ? p.text : typeof p.thinking === \"string\" ? p.thinking : \"\";\n \n if (displayedThinkingHashes) {\n const hash = hashString(fullText);\n if (displayedThinkingHashes.has(hash)) {\n sentBuffer.set(index, fullText);\n return [];\n }\n displayedThinkingHashes.add(hash);\n }\n\n const sentText = sentBuffer.get(index) ?? '';\n\n if (fullText.startsWith(sentText)) {\n const delta = fullText.slice(sentText.length);\n sentBuffer.set(index, fullText);\n\n if (delta) {\n // Clean object \u2014 NO spread to prevent thinking: <object> leaking\n return { thought: true, text: delta };\n }\n return [];\n }\n\n sentBuffer.set(index, fullText);\n return part;\n } return [part];\n });\n\n return {\n ...cand,\n content: { ...content, parts: newParts },\n }; });\r\n\r\n return { ...resp, candidates: newCandidates };\r\n }\r\n\r\n if (Array.isArray(resp.content)) {\r\n let thinkingIndex = 0;\r\n const newContent = resp.content.flatMap((block: unknown) => {\n const b = block as Record<string, unknown> | null;\r\n if (b?.type === 'thinking') {\n const fullText = typeof b.thinking === \"string\" ? b.thinking : typeof b.text === \"string\" ? b.text : \"\";\n \n if (displayedThinkingHashes) {\n const hash = hashString(fullText);\n if (displayedThinkingHashes.has(hash)) {\n sentBuffer.set(thinkingIndex, fullText);\n thinkingIndex++;\n return [];\n }\n displayedThinkingHashes.add(hash);\n }\n\n const sentText = sentBuffer.get(thinkingIndex) ?? '';\n\n if (fullText.startsWith(sentText)) {\n const delta = fullText.slice(sentText.length);\n sentBuffer.set(thinkingIndex, fullText);\n thinkingIndex++;\n\n if (delta) {\n // Clean object \u2014 NO spread to prevent thinking: <object> leaking\n return { type: b.type, thinking: delta, text: delta };\n }\n return [];\n }\n\n sentBuffer.set(thinkingIndex, fullText);\n thinkingIndex++;\n return block;\n } return [block];\n });\n\n return { ...resp, content: newContent }; }\r\n\r\n return response;\r\n}\r\n\r\nexport function transformSseLine(\r\n line: string,\r\n signatureStore: SignatureStore,\r\n thoughtBuffer: ThoughtBuffer,\r\n sentThinkingBuffer: ThoughtBuffer,\r\n callbacks: StreamingCallbacks,\r\n options: StreamingOptions,\r\n debugState: { injected: boolean },\r\n): string {\r\n if (!line.startsWith('data:')) {\r\n return line;\r\n }\r\n const json = line.slice(5).trim();\r\n if (!json) {\r\n return line;\r\n }\r\n\r\n try {\r\n const parsed = JSON.parse(json) as { response?: unknown };\r\n if (parsed.response !== undefined) {\r\n if (options.cacheSignatures && options.signatureSessionKey) {\r\n cacheThinkingSignaturesFromResponse(\r\n parsed.response,\r\n options.signatureSessionKey,\r\n signatureStore,\r\n thoughtBuffer,\r\n callbacks.onCacheSignature,\r\n );\r\n }\r\n\r\n let response: unknown = deduplicateThinkingText(\r\n parsed.response,\r\n sentThinkingBuffer,\r\n options.displayedThinkingHashes\r\n );\r\n\r\n if (options.debugText && callbacks.onInjectDebug && !debugState.injected) {\r\n response = callbacks.onInjectDebug(response, options.debugText);\r\n debugState.injected = true;\r\n }\r\n // Note: onInjectSyntheticThinking removed - keep_thinking now uses debugText path\r\n\r\n const transformed = callbacks.transformThinkingParts\r\n ? callbacks.transformThinkingParts(response)\r\n : response;\r\n return `data: ${JSON.stringify(transformed)}`;\r\n }\r\n } catch (_) {\n console.warn(\"[antigravity] Malformed SSE chunk in streaming transform, passing through untransformed:\", json.slice(0, 200));\n }\n return line;\n}\r\nexport function cacheThinkingSignaturesFromResponse(\r\n response: unknown,\r\n signatureSessionKey: string,\r\n signatureStore: SignatureStore,\r\n thoughtBuffer: ThoughtBuffer,\r\n onCacheSignature?: (sessionKey: string, text: string, signature: string) => void,\r\n): void {\r\n if (!response || typeof response !== 'object') return;\r\n\r\n const resp = response as Record<string, unknown>;\r\n\r\n if (Array.isArray(resp.candidates)) {\r\n resp.candidates.forEach((candidate: unknown, index: number) => {\r\n const cand = candidate as Record<string, unknown> | null;\r\n if (!cand?.content) return;\r\n const content = cand.content as Record<string, unknown>;\r\n if (!Array.isArray(content.parts)) return;\r\n\r\n content.parts.forEach((part: unknown) => {\r\n const p = part as Record<string, unknown>;\r\n if (p.thought === true || p.type === 'thinking') {\n const text = typeof p.text === \"string\" ? p.text : typeof p.thinking === \"string\" ? p.thinking : \"\";\n if (text) {\n const current = thoughtBuffer.get(index) ?? '';\n thoughtBuffer.set(index, current + text);\n }\n }\r\n if (p.thoughtSignature) {\r\n const fullText = thoughtBuffer.get(index) ?? '';\r\n if (fullText) {\r\n const signature = p.thoughtSignature as string;\r\n onCacheSignature?.(signatureSessionKey, fullText, signature);\r\n signatureStore.set(signatureSessionKey, { text: fullText, signature });\r\n }\r\n }\r\n });\r\n });\r\n }\r\n\r\n if (Array.isArray(resp.content)) {\r\n // Use thoughtBuffer to accumulate thinking text across SSE events\r\n // Claude streams thinking content and signature in separate events\r\n const CLAUDE_BUFFER_KEY = 0; // Use index 0 for Claude's single-stream content\r\n resp.content.forEach((block: unknown) => {\r\n const b = block as Record<string, unknown> | null;\r\n if (b?.type === 'thinking') {\r\n const text = typeof b.thinking === \"string\" ? b.thinking : typeof b.text === \"string\" ? b.text : \"\";\r\n if (text) {\r\n const current = thoughtBuffer.get(CLAUDE_BUFFER_KEY) ?? '';\r\n thoughtBuffer.set(CLAUDE_BUFFER_KEY, current + text);\r\n }\r\n }\r\n if (b?.signature) {\r\n const fullText = thoughtBuffer.get(CLAUDE_BUFFER_KEY) ?? '';\r\n if (fullText) {\r\n const signature = b.signature as string;\r\n onCacheSignature?.(signatureSessionKey, fullText, signature);\r\n signatureStore.set(signatureSessionKey, { text: fullText, signature });\r\n }\r\n }\r\n });\r\n }\r\n}\r\n\r\nexport function createStreamingTransformer(\r\n signatureStore: SignatureStore,\r\n callbacks: StreamingCallbacks,\r\n options: StreamingOptions = {},\r\n): TransformStream<Uint8Array, Uint8Array> {\r\n const decoder = new TextDecoder();\r\n const encoder = new TextEncoder();\r\n let buffer = '';\r\n const thoughtBuffer = createThoughtBuffer();\r\n const sentThinkingBuffer = createThoughtBuffer();\r\n const debugState = { injected: false };\r\n let hasSeenUsageMetadata = false;\r\n\r\n return new TransformStream({\r\n transform(chunk, controller) {\r\n buffer += decoder.decode(chunk, { stream: true });\r\n\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() || '';\r\n\r\n for (const line of lines) {\r\n // Quick check for usage metadata presence in the raw line\r\n if (line.includes('usageMetadata')) {\r\n hasSeenUsageMetadata = true;\r\n }\r\n\r\n const transformedLine = transformSseLine(\r\n line,\r\n signatureStore,\r\n thoughtBuffer,\r\n sentThinkingBuffer,\r\n callbacks,\r\n options,\r\n debugState,\r\n );\r\n controller.enqueue(encoder.encode(transformedLine + '\\n'));\r\n }\r\n },\r\n flush(controller) {\r\n buffer += decoder.decode();\r\n\r\n if (buffer) {\r\n if (buffer.includes('usageMetadata')) {\r\n hasSeenUsageMetadata = true;\r\n }\r\n const transformedLine = transformSseLine(\r\n buffer,\r\n signatureStore,\r\n thoughtBuffer,\r\n sentThinkingBuffer,\r\n callbacks,\r\n options,\r\n debugState,\r\n );\r\n controller.enqueue(encoder.encode(transformedLine));\r\n }\r\n\r\n // Inject synthetic usage metadata if missing (fixes \"Context % used: 0%\" issue)\r\n if (!hasSeenUsageMetadata) {\r\n const syntheticUsage = {\r\n response: {\r\n usageMetadata: {\r\n promptTokenCount: 0,\r\n candidatesTokenCount: 0,\r\n totalTokenCount: 0,\r\n }\r\n }\r\n };\r\n controller.enqueue(encoder.encode(`\\ndata: ${JSON.stringify(syntheticUsage)}\\n\\n`));\r\n }\r\n },\r\n });\r\n}\r\n", "import type { SignatureStore, SignedThinking, ThoughtBuffer } from '../core/streaming/types';\r\n\r\nexport function createSignatureStore(): SignatureStore {\r\n const store = new Map<string, SignedThinking>();\r\n\r\n return {\r\n get: (key: string) => store.get(key),\r\n set: (key: string, value: SignedThinking) => {\r\n store.set(key, value);\r\n },\r\n has: (key: string) => store.has(key),\r\n delete: (key: string) => {\r\n store.delete(key);\r\n },\r\n };\r\n}\r\n\r\nexport function createThoughtBuffer(): ThoughtBuffer {\r\n const buffer = new Map<number, string>();\r\n\r\n return {\r\n get: (index: number) => buffer.get(index),\r\n set: (index: number, text: string) => {\r\n buffer.set(index, text);\r\n },\r\n clear: () => buffer.clear(),\r\n };\r\n}\r\n\r\nexport const defaultSignatureStore = createSignatureStore();\r\n", "import { getKeepThinking } from \"./config\";\r\nimport { createLogger } from \"./logger\";\r\nimport { cacheSignature } from \"./cache\";\r\nimport {\r\n EMPTY_SCHEMA_PLACEHOLDER_NAME,\r\n EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,\r\n SKIP_THOUGHT_SIGNATURE,\r\n} from \"../constants\";\r\nimport { processImageData } from \"./image-saver\";\r\nimport type { GoogleSearchConfig } from \"./transform/types\";\r\n\r\nconst log = createLogger(\"request-helpers\");\r\n\r\nconst ANTIGRAVITY_PREVIEW_LINK = \"https://goo.gle/enable-preview-features\"; // TODO: Update to Antigravity link if available\r\n\r\n// ============================================================================\r\n// JSON SCHEMA CLEANING FOR ANTIGRAVITY API\r\n// Ported from CLIProxyAPI's CleanJSONSchemaForAntigravity (gemini_schema.go)\r\n// ============================================================================\r\n\r\n/**\r\n * Unsupported constraint keywords that should be moved to description hints.\r\n * Claude/Gemini reject these in VALIDATED mode.\r\n */\r\nconst UNSUPPORTED_CONSTRAINTS = [\r\n \"minLength\", \"maxLength\", \"exclusiveMinimum\", \"exclusiveMaximum\",\r\n \"pattern\", \"minItems\", \"maxItems\", \"format\",\r\n \"default\", \"examples\",\r\n] as const;\r\n\r\n/**\r\n * Keywords that should be removed after hint extraction.\r\n */\r\nconst UNSUPPORTED_KEYWORDS = [\r\n ...UNSUPPORTED_CONSTRAINTS,\r\n \"$schema\", \"$defs\", \"definitions\", \"const\", \"$ref\", \"additionalProperties\",\r\n \"propertyNames\", \"title\", \"$id\", \"$comment\",\r\n] as const;\r\n\r\n/**\r\n * Appends a hint to a schema's description field.\r\n */\r\nfunction appendDescriptionHint(schema: any, hint: string): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n const existing = typeof schema.description === \"string\" ? schema.description : \"\";\r\n const newDescription = existing ? `${existing} (${hint})` : hint;\r\n return { ...schema, description: newDescription };\r\n}\r\n\r\n/**\r\n * Phase 1a: Converts $ref to description hints.\r\n * $ref: \"#/$defs/Foo\" \u2192 { type: \"object\", description: \"See: Foo\" }\r\n */\r\nfunction convertRefsToHints(schema: any): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map(item => convertRefsToHints(item));\r\n }\r\n\r\n // If this object has $ref, replace it with a hint\r\n if (typeof schema.$ref === \"string\") {\r\n const refVal = schema.$ref;\r\n const defName = refVal.includes(\"/\") ? refVal.split(\"/\").pop() : refVal;\r\n const hint = `See: ${defName}`;\r\n const existingDesc = typeof schema.description === \"string\" ? schema.description : \"\";\r\n const newDescription = existingDesc ? `${existingDesc} (${hint})` : hint;\r\n return { type: \"object\", description: newDescription };\r\n }\r\n\r\n // Recursively process all properties\r\n const result: any = {};\r\n for (const [key, value] of Object.entries(schema)) {\r\n result[key] = convertRefsToHints(value);\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Phase 1b: Converts const to enum.\r\n * { const: \"foo\" } \u2192 { enum: [\"foo\"] }\r\n */\r\nfunction convertConstToEnum(schema: any): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map(item => convertConstToEnum(item));\r\n }\r\n\r\n const result: any = {};\r\n for (const [key, value] of Object.entries(schema)) {\r\n if (key === \"const\" && !schema.enum) {\r\n result.enum = [value];\r\n } else {\r\n result[key] = convertConstToEnum(value);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Phase 1c: Adds enum hints to description.\r\n * { enum: [\"a\", \"b\", \"c\"] } \u2192 adds \"(Allowed: a, b, c)\" to description\r\n */\r\nfunction addEnumHints(schema: any): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map(item => addEnumHints(item));\r\n }\r\n\r\n let result: any = { ...schema };\r\n\r\n // Add enum hint if enum has 2-10 items\r\n if (Array.isArray(result.enum) && result.enum.length > 1 && result.enum.length <= 10) {\r\n const vals = result.enum.map((v: any) => String(v)).join(\", \");\r\n result = appendDescriptionHint(result, `Allowed: ${vals}`);\r\n }\r\n\r\n // Recursively process nested objects\r\n for (const [key, value] of Object.entries(result)) {\r\n if (key !== \"enum\" && typeof value === \"object\" && value !== null) {\r\n result[key] = addEnumHints(value);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Phase 1d: Adds additionalProperties hints.\r\n * { additionalProperties: false } \u2192 adds \"(No extra properties allowed)\" to description\r\n */\r\nfunction addAdditionalPropertiesHints(schema: any): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map(item => addAdditionalPropertiesHints(item));\r\n }\r\n\r\n let result: any = { ...schema };\r\n\r\n if (result.additionalProperties === false) {\r\n result = appendDescriptionHint(result, \"No extra properties allowed\");\r\n }\r\n\r\n // Recursively process nested objects\r\n for (const [key, value] of Object.entries(result)) {\r\n if (key !== \"additionalProperties\" && typeof value === \"object\" && value !== null) {\r\n result[key] = addAdditionalPropertiesHints(value);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Phase 1e: Moves unsupported constraints to description hints.\r\n * { minLength: 1, maxLength: 100 } \u2192 adds \"(minLength: 1) (maxLength: 100)\" to description\r\n */\r\nfunction moveConstraintsToDescription(schema: any): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map(item => moveConstraintsToDescription(item));\r\n }\r\n\r\n let result: any = { ...schema };\r\n\r\n // Move constraint values to description\r\n for (const constraint of UNSUPPORTED_CONSTRAINTS) {\r\n if (result[constraint] !== undefined && typeof result[constraint] !== \"object\") {\r\n result = appendDescriptionHint(result, `${constraint}: ${result[constraint]}`);\r\n }\r\n }\r\n\r\n // Recursively process nested objects\r\n for (const [key, value] of Object.entries(result)) {\r\n if (typeof value === \"object\" && value !== null) {\r\n result[key] = moveConstraintsToDescription(value);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Phase 2a: Merges allOf schemas into a single object.\r\n * { allOf: [{ properties: { a: ... } }, { properties: { b: ... } }] }\r\n * \u2192 { properties: { a: ..., b: ... } }\r\n */\r\nfunction mergeAllOf(schema: any): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map(item => mergeAllOf(item));\r\n }\r\n\r\n let result: any = { ...schema };\r\n\r\n // If this object has allOf, merge its contents\r\n if (Array.isArray(result.allOf)) {\r\n const merged: any = {};\r\n const mergedRequired: string[] = [];\r\n\r\n for (const item of result.allOf) {\r\n if (!item || typeof item !== \"object\") continue;\r\n\r\n // Merge properties\r\n if (item.properties && typeof item.properties === \"object\") {\r\n merged.properties = { ...merged.properties, ...item.properties };\r\n }\r\n\r\n // Merge required arrays\r\n if (Array.isArray(item.required)) {\r\n for (const req of item.required) {\r\n if (!mergedRequired.includes(req)) {\r\n mergedRequired.push(req);\r\n }\r\n }\r\n }\r\n\r\n // Copy other fields from allOf items\r\n for (const [key, value] of Object.entries(item)) {\r\n if (key !== \"properties\" && key !== \"required\" && merged[key] === undefined) {\r\n merged[key] = value;\r\n }\r\n }\r\n }\r\n\r\n // Apply merged content to result\r\n if (merged.properties) {\r\n result.properties = { ...result.properties, ...merged.properties };\r\n }\r\n if (mergedRequired.length > 0) {\r\n const existingRequired = Array.isArray(result.required) ? result.required : [];\r\n result.required = Array.from(new Set([...existingRequired, ...mergedRequired]));\r\n }\r\n\r\n // Copy other merged fields\r\n for (const [key, value] of Object.entries(merged)) {\r\n if (key !== \"properties\" && key !== \"required\" && result[key] === undefined) {\r\n result[key] = value;\r\n }\r\n }\r\n\r\n delete result.allOf;\r\n }\r\n\r\n // Recursively process nested objects\r\n for (const [key, value] of Object.entries(result)) {\r\n if (typeof value === \"object\" && value !== null) {\r\n result[key] = mergeAllOf(value);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Scores a schema option for selection in anyOf/oneOf flattening.\r\n * Higher score = more preferred.\r\n */\r\nfunction scoreSchemaOption(schema: any): { score: number; typeName: string } {\r\n if (!schema || typeof schema !== \"object\") {\r\n return { score: 0, typeName: \"unknown\" };\r\n }\r\n\r\n const type = schema.type;\r\n\r\n // Object or has properties = highest priority\r\n if (type === \"object\" || schema.properties) {\r\n return { score: 3, typeName: \"object\" };\r\n }\r\n\r\n // Array or has items = second priority\r\n if (type === \"array\" || schema.items) {\r\n return { score: 2, typeName: \"array\" };\r\n }\r\n\r\n // Any other non-null type\r\n if (type && type !== \"null\") {\r\n return { score: 1, typeName: type };\r\n }\r\n\r\n // Null or no type\r\n return { score: 0, typeName: type || \"null\" };\r\n}\r\n\r\n/**\r\n * Checks if an anyOf/oneOf array represents enum choices.\r\n * Returns the merged enum values if so, otherwise null.\r\n *\r\n * Handles patterns like:\r\n * - anyOf: [{ const: \"a\" }, { const: \"b\" }]\r\n * - anyOf: [{ enum: [\"a\"] }, { enum: [\"b\"] }]\r\n * - anyOf: [{ type: \"string\", const: \"a\" }, { type: \"string\", const: \"b\" }]\r\n */\r\nfunction tryMergeEnumFromUnion(options: any[]): string[] | null {\r\n if (!Array.isArray(options) || options.length === 0) {\r\n return null;\r\n }\r\n\r\n const enumValues: string[] = [];\r\n\r\n for (const option of options) {\r\n if (!option || typeof option !== \"object\") {\r\n return null;\r\n }\r\n\r\n // Check for const value\r\n if (option.const !== undefined) {\r\n enumValues.push(String(option.const));\r\n continue;\r\n }\r\n\r\n // Check for single-value enum\r\n if (Array.isArray(option.enum) && option.enum.length === 1) {\r\n enumValues.push(String(option.enum[0]));\r\n continue;\r\n }\r\n\r\n // Check for multi-value enum (merge all values)\r\n if (Array.isArray(option.enum) && option.enum.length > 0) {\r\n for (const val of option.enum) {\r\n enumValues.push(String(val));\r\n }\r\n continue;\r\n }\r\n\r\n // If option has complex structure (properties, items, etc.), it's not a simple enum\r\n if (option.properties || option.items || option.anyOf || option.oneOf || option.allOf) {\r\n return null;\r\n }\r\n\r\n // If option has only type (no const/enum), it's not an enum pattern\r\n if (option.type && !option.const && !option.enum) {\r\n return null;\r\n }\r\n }\r\n\r\n // Only return if we found actual enum values\r\n return enumValues.length > 0 ? enumValues : null;\r\n}\r\n\r\n/**\r\n * Phase 2b: Flattens anyOf/oneOf to the best option with type hints.\r\n * { anyOf: [{ type: \"string\" }, { type: \"number\" }] }\r\n * \u2192 { type: \"string\", description: \"(Accepts: string | number)\" }\r\n *\r\n * Special handling for enum patterns:\r\n * { anyOf: [{ const: \"a\" }, { const: \"b\" }] }\r\n * \u2192 { type: \"string\", enum: [\"a\", \"b\"] }\r\n */\r\nfunction flattenAnyOfOneOf(schema: any): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map(item => flattenAnyOfOneOf(item));\r\n }\r\n\r\n let result: any = { ...schema };\r\n\r\n // Process anyOf or oneOf\r\n for (const unionKey of [\"anyOf\", \"oneOf\"] as const) {\r\n if (Array.isArray(result[unionKey]) && result[unionKey].length > 0) {\r\n const options = result[unionKey];\r\n const parentDesc = typeof result.description === \"string\" ? result.description : \"\";\r\n\r\n // First, check if this is an enum pattern (anyOf with const/enum values)\r\n // This is crucial for tools like WebFetch where format: anyOf[{const:\"text\"},{const:\"markdown\"},{const:\"html\"}]\r\n const mergedEnum = tryMergeEnumFromUnion(options);\r\n if (mergedEnum !== null) {\r\n // This is an enum pattern - merge all values into a single enum\r\n const { [unionKey]: _, ...rest } = result;\r\n result = {\r\n ...rest,\r\n type: \"string\",\r\n enum: mergedEnum,\r\n };\r\n // Preserve parent description\r\n if (parentDesc) {\r\n result.description = parentDesc;\r\n }\r\n continue;\r\n }\r\n\r\n // Not an enum pattern - use standard flattening logic\r\n // Score each option and find the best\r\n let bestIdx = 0;\r\n let bestScore = -1;\r\n const allTypes: string[] = [];\r\n\r\n for (let i = 0; i < options.length; i++) {\r\n const { score, typeName } = scoreSchemaOption(options[i]);\r\n if (typeName) {\r\n allTypes.push(typeName);\r\n }\r\n if (score > bestScore) {\r\n bestScore = score;\r\n bestIdx = i;\r\n }\r\n }\r\n\r\n // Select the best option and flatten it recursively\r\n let selected = flattenAnyOfOneOf(options[bestIdx]) || { type: \"string\" };\r\n\r\n // Preserve parent description\r\n if (parentDesc) {\r\n const childDesc = typeof selected.description === \"string\" ? selected.description : \"\";\r\n if (childDesc && childDesc !== parentDesc) {\r\n selected = { ...selected, description: `${parentDesc} (${childDesc})` };\r\n } else if (!childDesc) {\r\n selected = { ...selected, description: parentDesc };\r\n }\r\n }\r\n\r\n if (allTypes.length > 1) {\r\n const uniqueTypes = Array.from(new Set(allTypes));\r\n const hint = `Accepts: ${uniqueTypes.join(\" | \")}`;\r\n selected = appendDescriptionHint(selected, hint);\r\n }\r\n\r\n // Replace result with selected schema, preserving other fields\r\n const { [unionKey]: _, description: __, ...rest } = result;\r\n result = { ...rest, ...selected };\r\n }\r\n }\r\n\r\n // Recursively process nested objects\r\n for (const [key, value] of Object.entries(result)) {\r\n if (typeof value === \"object\" && value !== null) {\r\n result[key] = flattenAnyOfOneOf(value);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Phase 2c: Flattens type arrays to single type with nullable hint.\r\n * { type: [\"string\", \"null\"] } \u2192 { type: \"string\", description: \"(nullable)\" }\r\n */\r\nfunction flattenTypeArrays(schema: any, nullableFields?: Map<string, string[]>, currentPath?: string): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map((item, idx) => flattenTypeArrays(item, nullableFields, `${currentPath || \"\"}[${idx}]`));\r\n }\r\n\r\n let result: any = { ...schema };\r\n const localNullableFields = nullableFields || new Map<string, string[]>();\r\n\r\n // Handle type array\r\n if (Array.isArray(result.type)) {\r\n const types = result.type as string[];\r\n const hasNull = types.includes(\"null\");\r\n const nonNullTypes = types.filter(t => t !== \"null\" && t);\r\n\r\n // Select first non-null type, or \"string\" as fallback\r\n const firstType = nonNullTypes.length > 0 ? nonNullTypes[0] : \"string\";\r\n result.type = firstType;\r\n\r\n // Add hint for multiple types\r\n if (nonNullTypes.length > 1) {\r\n result = appendDescriptionHint(result, `Accepts: ${nonNullTypes.join(\" | \")}`);\r\n }\r\n\r\n // Add nullable hint\r\n if (hasNull) {\r\n result = appendDescriptionHint(result, \"nullable\");\r\n }\r\n }\r\n\r\n // Recursively process properties\r\n if (result.properties && typeof result.properties === \"object\") {\r\n const newProps: any = {};\r\n for (const [propKey, propValue] of Object.entries(result.properties)) {\r\n const propPath = currentPath ? `${currentPath}.properties.${propKey}` : `properties.${propKey}`;\r\n const processed = flattenTypeArrays(propValue, localNullableFields, propPath);\r\n newProps[propKey] = processed;\r\n\r\n // Track nullable fields for required array cleanup\r\n if (processed && typeof processed === \"object\" && \r\n typeof processed.description === \"string\" && \r\n processed.description.includes(\"nullable\")) {\r\n const objectPath = currentPath || \"\";\r\n const existing = localNullableFields.get(objectPath) || [];\r\n existing.push(propKey);\r\n localNullableFields.set(objectPath, existing);\r\n }\r\n }\r\n result.properties = newProps;\r\n }\r\n\r\n // Remove nullable fields from required array\r\n if (Array.isArray(result.required) && !nullableFields) {\r\n // Only at root level, filter out nullable fields\r\n const nullableAtRoot = localNullableFields.get(\"\") || [];\r\n if (nullableAtRoot.length > 0) {\r\n result.required = result.required.filter((r: string) => !nullableAtRoot.includes(r));\r\n if (result.required.length === 0) {\r\n delete result.required;\r\n }\r\n }\r\n }\r\n\r\n // Recursively process other nested objects\r\n for (const [key, value] of Object.entries(result)) {\r\n if (key !== \"properties\" && typeof value === \"object\" && value !== null) {\r\n result[key] = flattenTypeArrays(value, localNullableFields, `${currentPath || \"\"}.${key}`);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Phase 3: Removes unsupported keywords after hints have been extracted.\r\n * @param insideProperties - When true, keys are property NAMES (preserve); when false, keys are JSON Schema keywords (filter).\r\n */\r\nfunction removeUnsupportedKeywords(schema: any, insideProperties: boolean = false): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map(item => removeUnsupportedKeywords(item, false));\r\n }\r\n\r\n const result: any = {};\r\n for (const [key, value] of Object.entries(schema)) {\r\n if (!insideProperties && (UNSUPPORTED_KEYWORDS as readonly string[]).includes(key)) {\r\n continue;\r\n }\r\n\r\n if (typeof value === \"object\" && value !== null) {\r\n if (key === \"properties\") {\r\n const propertiesResult: any = {};\r\n for (const [propName, propSchema] of Object.entries(value as object)) {\r\n propertiesResult[propName] = removeUnsupportedKeywords(propSchema, false);\r\n }\r\n result[key] = propertiesResult;\r\n } else {\r\n result[key] = removeUnsupportedKeywords(value, false);\r\n }\r\n } else {\r\n result[key] = value;\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Phase 3b: Cleans up required fields - removes entries that don't exist in properties.\r\n */\r\nfunction cleanupRequiredFields(schema: any): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map(item => cleanupRequiredFields(item));\r\n }\r\n\r\n let result: any = { ...schema };\r\n\r\n // Clean up required array if properties exist\r\n if (Array.isArray(result.required) && result.properties && typeof result.properties === \"object\") {\r\n const validRequired = result.required.filter((req: string) => \r\n Object.prototype.hasOwnProperty.call(result.properties, req)\r\n );\r\n if (validRequired.length === 0) {\r\n delete result.required;\r\n } else if (validRequired.length !== result.required.length) {\r\n result.required = validRequired;\r\n }\r\n }\r\n\r\n // Recursively process nested objects\r\n for (const [key, value] of Object.entries(result)) {\r\n if (typeof value === \"object\" && value !== null) {\r\n result[key] = cleanupRequiredFields(value);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Phase 4: Adds placeholder property for empty object schemas.\r\n * Claude VALIDATED mode requires at least one property.\r\n */\r\nfunction addEmptySchemaPlaceholder(schema: any): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n if (Array.isArray(schema)) {\r\n return schema.map(item => addEmptySchemaPlaceholder(item));\r\n }\r\n\r\n let result: any = { ...schema };\r\n\r\n // Check if this is an empty object schema\r\n const isObjectType = result.type === \"object\";\r\n\r\n if (isObjectType) {\r\n const hasProperties =\r\n result.properties &&\r\n typeof result.properties === \"object\" &&\r\n Object.keys(result.properties).length > 0;\r\n\r\n if (!hasProperties) {\r\n result.properties = {\r\n [EMPTY_SCHEMA_PLACEHOLDER_NAME]: {\r\n type: \"boolean\",\r\n description: EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,\r\n },\r\n };\r\n result.required = [EMPTY_SCHEMA_PLACEHOLDER_NAME];\r\n }\r\n }\r\n\r\n // Recursively process nested objects\r\n for (const [key, value] of Object.entries(result)) {\r\n if (typeof value === \"object\" && value !== null) {\r\n result[key] = addEmptySchemaPlaceholder(value);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Cleans a JSON schema for Antigravity API compatibility.\r\n * Transforms unsupported features into description hints while preserving semantic information.\r\n * \r\n * Ported from CLIProxyAPI's CleanJSONSchemaForAntigravity (gemini_schema.go)\r\n */\r\nexport function cleanJSONSchemaForAntigravity(schema: any): any {\r\n if (!schema || typeof schema !== \"object\") {\r\n return schema;\r\n }\r\n\r\n let result = schema;\r\n\r\n // Phase 1: Convert and add hints\r\n result = convertRefsToHints(result);\r\n result = convertConstToEnum(result);\r\n result = addEnumHints(result);\r\n result = addAdditionalPropertiesHints(result);\r\n result = moveConstraintsToDescription(result);\r\n\r\n // Phase 2: Flatten complex structures\r\n result = mergeAllOf(result);\r\n result = flattenAnyOfOneOf(result);\r\n result = flattenTypeArrays(result);\r\n\r\n // Phase 3: Cleanup\r\n result = removeUnsupportedKeywords(result);\r\n result = cleanupRequiredFields(result);\r\n\r\n // Phase 4: Add placeholder for empty object schemas\r\n result = addEmptySchemaPlaceholder(result);\r\n\r\n return result;\r\n}\r\n\r\n// ============================================================================\r\n// END JSON SCHEMA CLEANING\r\n// ============================================================================\r\n\r\nexport interface AntigravityApiError {\r\n code?: number;\r\n message?: string;\r\n status?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * Minimal representation of Antigravity API responses we touch.\r\n */\r\nexport interface AntigravityApiBody {\r\n response?: unknown;\r\n error?: AntigravityApiError;\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * Usage metadata exposed by Antigravity responses. Fields are optional to reflect partial payloads.\r\n */\r\nexport interface AntigravityUsageMetadata {\r\n totalTokenCount?: number;\r\n promptTokenCount?: number;\r\n candidatesTokenCount?: number;\r\n cachedContentTokenCount?: number;\r\n thoughtsTokenCount?: number;\r\n}\r\n\r\n/**\r\n * Normalized thinking configuration accepted by Antigravity.\r\n */\r\nexport interface ThinkingConfig {\r\n thinkingBudget?: number;\r\n includeThoughts?: boolean;\r\n}\r\n\r\n/**\r\n * Default token budget for thinking/reasoning. 16000 tokens provides sufficient\r\n * space for complex reasoning while staying within typical model limits.\r\n */\r\nexport const DEFAULT_THINKING_BUDGET = 16000;\r\n\r\n/**\r\n * Checks if a model name indicates thinking/reasoning capability.\r\n * Models with \"thinking\", \"gemini-3\", or \"opus\" in their name support extended thinking.\r\n */\r\nexport function isThinkingCapableModel(modelName: string): boolean {\r\n const lowerModel = modelName.toLowerCase();\r\n return lowerModel.includes(\"thinking\")\r\n || lowerModel.includes(\"gemini-3\")\r\n || lowerModel.includes(\"opus\");\r\n}\r\n\r\n/**\r\n * Extracts thinking configuration from various possible request locations.\r\n * Supports both Gemini-style thinkingConfig and Anthropic-style thinking options.\r\n */\r\nexport function extractThinkingConfig(\r\n requestPayload: Record<string, unknown>,\r\n rawGenerationConfig: Record<string, unknown> | undefined,\r\n extraBody: Record<string, unknown> | undefined,\r\n): ThinkingConfig | undefined {\r\n const thinkingConfig = rawGenerationConfig?.thinkingConfig\r\n ?? extraBody?.thinkingConfig\r\n ?? requestPayload.thinkingConfig;\r\n\r\n if (thinkingConfig && typeof thinkingConfig === \"object\") {\r\n const config = thinkingConfig as Record<string, unknown>;\r\n return {\r\n includeThoughts: Boolean(config.includeThoughts),\r\n thinkingBudget: typeof config.thinkingBudget === \"number\" ? config.thinkingBudget : DEFAULT_THINKING_BUDGET,\r\n };\r\n }\r\n\r\n // Convert Anthropic-style \"thinking\" option: { type: \"enabled\", budgetTokens: N }\r\n const anthropicThinking = extraBody?.thinking ?? requestPayload.thinking;\r\n if (anthropicThinking && typeof anthropicThinking === \"object\") {\r\n const thinking = anthropicThinking as Record<string, unknown>;\r\n if (thinking.type === \"enabled\" || thinking.budgetTokens) {\r\n return {\r\n includeThoughts: true,\r\n thinkingBudget: typeof thinking.budgetTokens === \"number\" ? thinking.budgetTokens : DEFAULT_THINKING_BUDGET,\r\n };\r\n }\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Variant thinking config extracted from OpenCode's providerOptions.\r\n */\r\nexport interface VariantThinkingConfig {\r\n /** Gemini 3 native thinking level (low/medium/high) */\r\n thinkingLevel?: string;\r\n /** Numeric thinking budget for Claude and Gemini 2.5 */\r\n thinkingBudget?: number;\r\n /** Whether to include thoughts in output */\r\n includeThoughts?: boolean;\r\n /** Google Search configuration */\r\n googleSearch?: GoogleSearchConfig;\r\n}\r\n\r\n/**\r\n * Extracts variant thinking config from OpenCode's providerOptions.\r\n * \r\n * All Antigravity models route through the Google provider, so we only check\r\n * providerOptions.google. Supports two formats:\r\n * \r\n * 1. Gemini 3 native: { google: { thinkingLevel: \"high\", includeThoughts: true } }\r\n * 2. Budget-based (Claude/Gemini 2.5): { google: { thinkingConfig: { thinkingBudget: 32000 } } }\r\n * \r\n * When providerOptions is missing or has no thinking config (common with OpenCode\r\n * model variants), falls back to extracting from generationConfig directly:\r\n * 3. generationConfig fallback: { thinkingConfig: { thinkingBudget: 8192 } }\r\n */\r\nexport function extractVariantThinkingConfig(\r\n providerOptions: Record<string, unknown> | undefined,\r\n generationConfig?: Record<string, unknown> | undefined\r\n): VariantThinkingConfig | undefined {\r\n const result: VariantThinkingConfig = {};\r\n\r\n // Primary path: extract from providerOptions.google\r\n const google = (providerOptions?.google) as Record<string, unknown> | undefined;\r\n if (google) {\r\n // Gemini 3 native format: { google: { thinkingLevel: \"high\", includeThoughts: true } }\r\n // thinkingLevel takes priority over thinkingBudget - they are mutually exclusive\r\n if (typeof google.thinkingLevel === \"string\") {\r\n result.thinkingLevel = google.thinkingLevel;\r\n result.includeThoughts = typeof google.includeThoughts === \"boolean\" ? google.includeThoughts : undefined;\r\n } else if (google.thinkingConfig && typeof google.thinkingConfig === \"object\") {\r\n // Budget-based format (Claude/Gemini 2.5): { google: { thinkingConfig: { thinkingBudget } } }\r\n // Only used when thinkingLevel is not present\r\n const tc = google.thinkingConfig as Record<string, unknown>;\r\n if (typeof tc.thinkingBudget === \"number\") {\r\n result.thinkingBudget = tc.thinkingBudget;\r\n }\r\n }\r\n\r\n // Extract Google Search config\r\n if (google.googleSearch && typeof google.googleSearch === \"object\") {\r\n const search = google.googleSearch as Record<string, unknown>;\r\n result.googleSearch = {\r\n mode: search.mode === 'auto' || search.mode === 'off' ? search.mode : undefined,\r\n threshold: typeof search.threshold === 'number' ? search.threshold : undefined,\r\n };\r\n }\r\n }\r\n\r\n // Fallback: OpenCode may pass thinking config in generationConfig\r\n // instead of providerOptions (common when using model variants)\r\n if (result.thinkingBudget === undefined && !result.thinkingLevel && generationConfig) {\r\n if (generationConfig.thinkingConfig && typeof generationConfig.thinkingConfig === \"object\") {\r\n const tc = generationConfig.thinkingConfig as Record<string, unknown>;\r\n if (typeof tc.thinkingLevel === \"string\") {\r\n // Gemini 3 native format sent via generationConfig\r\n result.thinkingLevel = tc.thinkingLevel;\r\n result.includeThoughts = typeof tc.includeThoughts === \"boolean\" ? tc.includeThoughts : undefined;\r\n } else if (typeof tc.thinkingBudget === \"number\") {\r\n result.thinkingBudget = tc.thinkingBudget;\r\n }\r\n }\r\n }\r\n\r\n return Object.keys(result).length > 0 ? result : undefined;\r\n}\r\n\r\n/**\r\n * Determines the final thinking configuration based on model capabilities and user settings.\r\n * For Claude thinking models, we keep thinking enabled even in multi-turn conversations.\r\n * The filterUnsignedThinkingBlocks function will handle signature validation/restoration.\r\n */\r\nexport function resolveThinkingConfig(\r\n userConfig: ThinkingConfig | undefined,\r\n isThinkingModel: boolean,\r\n _isClaudeModel: boolean,\r\n _hasAssistantHistory: boolean,\r\n): ThinkingConfig | undefined {\r\n // For thinking-capable models (including Claude thinking models), enable thinking by default\r\n // The signature validation/restoration is handled by filterUnsignedThinkingBlocks\r\n if (isThinkingModel && !userConfig) {\r\n return { includeThoughts: true, thinkingBudget: DEFAULT_THINKING_BUDGET };\r\n }\r\n\r\n return userConfig;\r\n}\r\n\r\n/**\r\n * Checks if a part is a thinking/reasoning block (Anthropic or Gemini style).\r\n */\r\nfunction isThinkingPart(part: Record<string, unknown>): boolean {\r\n return part.type === \"thinking\"\r\n || part.type === \"redacted_thinking\"\r\n || part.type === \"reasoning\"\r\n || part.thinking !== undefined\r\n || part.thought === true;\r\n}\r\n\r\n/**\r\n * Checks if a part has a signature field (thinking block signature).\r\n * Used to detect foreign thinking blocks that might have unknown type values.\r\n */\r\nfunction hasSignatureField(part: Record<string, unknown>): boolean {\r\n return part.signature !== undefined || part.thoughtSignature !== undefined;\r\n}\r\n\r\n/**\r\n * Checks if a part is a tool block (tool_use or tool_result).\r\n * Tool blocks must never be filtered - they're required for tool call/result pairing.\r\n * Handles multiple formats:\r\n * - Anthropic: { type: \"tool_use\" }, { type: \"tool_result\", tool_use_id }\r\n * - Nested: { tool_result: { tool_use_id } }, { tool_use: { id } }\r\n * - Gemini: { functionCall }, { functionResponse }\r\n */\r\nfunction isToolBlock(part: Record<string, unknown>): boolean {\r\n return part.type === \"tool_use\"\r\n || part.type === \"tool_result\"\r\n || part.tool_use_id !== undefined\r\n || part.tool_call_id !== undefined\r\n || part.tool_result !== undefined\r\n || part.tool_use !== undefined\r\n || part.toolUse !== undefined\r\n || part.functionCall !== undefined\r\n || part.functionResponse !== undefined;\r\n}\r\n\r\n/**\r\n * Unconditionally strips ALL thinking/reasoning blocks from a content array.\r\n * Used for Claude models to avoid signature validation errors entirely.\r\n * Claude will generate fresh thinking for each turn.\r\n */\r\nfunction stripAllThinkingBlocks(contentArray: any[]): any[] {\n return contentArray.map(item => {\n if (!item || typeof item !== \"object\") return item;\n if (isToolBlock(item)) return item;\n if (isThinkingPart(item) || hasSignatureField(item)) {\n // Preserve cache_control from stripped thinking parts\n const cc = (item as Record<string, unknown>).cache_control;\n // Use plain empty text part \u2014 thinking-format sentinels get converted by the proxy\n // into Claude thinking blocks missing the required `thinking` field.\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (cc) sentinel.cache_control = cc;\n return sentinel;\n }\n return item;\n });\n}\r\nfunction removeTrailingThinkingBlocks(\n contentArray: any[],\n sessionId?: string,\n getCachedSignatureFn?: (sessionId: string, text: string) => string | undefined,\n): any[] {\n // Find the last index that is a trailing unsigned thinking block\n // Work backwards: replace trailing unsigned thinking blocks with sentinels\n // to preserve array length and cache breakpoints\n const result = [...contentArray];\n\n for (let i = result.length - 1; i >= 0; i--) {\n if (!isThinkingPart(result[i])) break;\n\n const part = result[i];\n const isValid = sessionId && getCachedSignatureFn\n ? isOurCachedSignature(part as Record<string, unknown>, sessionId, getCachedSignatureFn)\n : hasValidSignature(part as Record<string, unknown>);\n if (isValid) break;\n\n // Replace with sentinel instead of popping \u2014 preserves array length\n const cc = part?.cache_control;\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (cc) sentinel.cache_control = cc;\n result[i] = sentinel;\n }\n\n return result;\n}\r\n\r\n/**\r\n * Checks if a thinking part has a valid signature.\r\n * A valid signature is a non-empty string with at least 50 characters.\r\n */\r\nfunction hasValidSignature(part: Record<string, unknown>): boolean {\r\n const signature = part.thought === true ? part.thoughtSignature : part.signature;\r\n return typeof signature === \"string\" && signature.length >= 50;\r\n}\r\n\r\n/**\r\n * Gets the signature from a thinking part, if present.\r\n */\r\nfunction getSignature(part: Record<string, unknown>): string | undefined {\r\n const signature = part.thought === true ? part.thoughtSignature : part.signature;\r\n return typeof signature === \"string\" ? signature : undefined;\r\n}\r\n\r\n/**\r\n * Checks if a thinking part's signature was generated by our plugin (exists in our cache).\r\n * This prevents accepting signatures from other providers (e.g., direct Anthropic API, OpenAI)\r\n * which would cause \"Invalid signature\" errors when sent to Antigravity Claude.\r\n */\r\nfunction isOurCachedSignature(\r\n part: Record<string, unknown>,\r\n sessionId: string | undefined,\r\n getCachedSignatureFn: ((sessionId: string, text: string) => string | undefined) | undefined,\r\n): boolean {\r\n if (!sessionId || !getCachedSignatureFn) {\r\n return false;\r\n }\r\n\r\n const text = getThinkingText(part);\r\n if (!text) {\r\n return false;\r\n }\r\n\r\n const partSignature = getSignature(part);\r\n if (!partSignature) {\r\n return false;\r\n }\r\n\r\n const cachedSignature = getCachedSignatureFn(sessionId, text);\r\n return cachedSignature === partSignature;\r\n}\r\n\r\n/**\r\n * Gets the text content from a thinking part.\r\n */\r\nfunction getThinkingText(part: Record<string, unknown>): string {\r\n if (typeof part.text === \"string\") return part.text;\r\n if (typeof part.thinking === \"string\") return part.thinking;\r\n\r\n if (part.text && typeof part.text === \"object\") {\r\n const maybeText = (part.text as any).text;\r\n if (typeof maybeText === \"string\") return maybeText;\r\n }\r\n\r\n if (part.thinking && typeof part.thinking === \"object\") {\r\n const maybeText = (part.thinking as any).text ?? (part.thinking as any).thinking;\r\n if (typeof maybeText === \"string\") return maybeText;\r\n }\r\n\r\n return \"\";\r\n}\r\n\r\n/**\r\n * Recursively strips cache_control and providerOptions from any object.\r\n * These fields can be injected by SDKs, but Claude rejects them inside thinking blocks.\r\n */\r\nfunction stripCacheControlRecursively(obj: unknown): unknown {\r\n if (obj === null || obj === undefined) return obj;\r\n if (typeof obj !== \"object\") return obj;\r\n if (Array.isArray(obj)) return obj.map(item => stripCacheControlRecursively(item));\r\n\r\n const result: Record<string, unknown> = {};\r\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\r\n if (key === \"cache_control\" || key === \"providerOptions\") continue;\r\n result[key] = stripCacheControlRecursively(value);\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Sanitizes a thinking part by keeping only the allowed fields.\r\n * In particular, ensures `thinking` is a string (not an object with cache_control).\r\n * Returns null if the thinking block has no valid content.\r\n */\r\nfunction sanitizeThinkingPart(part: Record<string, unknown>): Record<string, unknown> | null {\r\n // Gemini-style thought blocks: { thought: true, text, thoughtSignature }\r\n if (part.thought === true) {\r\n let textContent: unknown = part.text;\r\n if (typeof textContent === \"object\" && textContent !== null) {\r\n const maybeText = (textContent as any).text;\r\n textContent = typeof maybeText === \"string\" ? maybeText : undefined;\r\n }\r\n\r\n const hasContent = typeof textContent === \"string\" && textContent.trim().length > 0;\r\n if (!hasContent && !part.thoughtSignature) {\r\n return null;\r\n }\r\n\r\n const sanitized: Record<string, unknown> = { thought: true };\n sanitized.text = typeof textContent === \"string\" ? textContent : \"\";\n if (part.thoughtSignature !== undefined) sanitized.thoughtSignature = part.thoughtSignature;\n if (part.cache_control !== undefined) sanitized.cache_control = part.cache_control;\n return sanitized;\n }\n\n // Anthropic-style thinking/redacted_thinking blocks: { type: \"thinking\"|\"redacted_thinking\", thinking, signature }\n if (part.type === \"thinking\" || part.type === \"redacted_thinking\" || part.thinking !== undefined) {\n let thinkingContent: unknown = part.thinking ?? part.text;\n if (thinkingContent !== undefined && typeof thinkingContent === \"object\" && thinkingContent !== null) {\n const maybeText = (thinkingContent as any).text ?? (thinkingContent as any).thinking;\n thinkingContent = typeof maybeText === \"string\" ? maybeText : undefined;\n }\n\n const hasContent = typeof thinkingContent === \"string\" && thinkingContent.trim().length > 0;\n if (!hasContent && !part.signature) {\n return null;\n }\n\n const sanitized: Record<string, unknown> = { type: part.type === \"redacted_thinking\" ? \"redacted_thinking\" : \"thinking\" };\n sanitized.thinking = typeof thinkingContent === \"string\" ? thinkingContent : \"\";\n if (part.signature !== undefined) sanitized.signature = part.signature;\n if (part.cache_control !== undefined) sanitized.cache_control = part.cache_control;\n return sanitized;\n }\n\n // Reasoning blocks (OpenCode format): { type: \"reasoning\", text, signature }\n if (part.type === \"reasoning\") {\n let textContent: unknown = part.text;\n if (typeof textContent === \"object\" && textContent !== null) {\n const maybeText = (textContent as any).text;\n textContent = typeof maybeText === \"string\" ? maybeText : undefined;\n }\n\n const hasContent = typeof textContent === \"string\" && textContent.trim().length > 0;\n if (!hasContent && !part.signature) {\n return null;\n }\n\n const sanitized: Record<string, unknown> = { type: \"reasoning\" };\n sanitized.text = typeof textContent === \"string\" ? textContent : \"\";\n if (part.signature !== undefined) sanitized.signature = part.signature;\n if (part.cache_control !== undefined) sanitized.cache_control = part.cache_control;\n return sanitized;\n }\n\n // Fallback: only strip cache_control from nested content objects, not part-level markers.\n // Part-level cache_control is used by OpenCode for prompt caching and must be preserved.\n return stripCacheControlRecursively(part) as Record<string, unknown>;}\r\n\r\nfunction findLastAssistantIndex(contents: any[], roleValue: \"model\" | \"assistant\"): number {\r\n for (let i = contents.length - 1; i >= 0; i--) {\r\n const content = contents[i];\r\n if (content && typeof content === \"object\" && content.role === roleValue) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n}\r\n\r\nfunction filterContentArray(\r\n contentArray: any[],\r\n sessionId?: string,\r\n getCachedSignatureFn?: (sessionId: string, text: string) => string | undefined,\r\n isClaudeModel?: boolean,\r\n isLastAssistantMessage: boolean = false,\r\n): any[] {\r\n // For Claude models, strip thinking blocks by default for reliability\r\n // User can opt-in to keep thinking via config: { \"keep_thinking\": true }\r\n if (isClaudeModel && !getKeepThinking()) {\r\n return stripAllThinkingBlocks(contentArray);\r\n }\r\n\r\n const filtered: any[] = [];\r\n\r\n for (const item of contentArray) {\r\n if (!item || typeof item !== \"object\") {\r\n filtered.push(item);\r\n continue;\r\n }\r\n\r\n if (isToolBlock(item)) {\r\n if (!isClaudeModel) {\r\n filtered.push(item);\r\n continue;\r\n }\r\n\r\n const sanitizedToolBlock = { ...(item as Record<string, unknown>) };\r\n delete (sanitizedToolBlock as any).signature;\r\n delete (sanitizedToolBlock as any).thoughtSignature;\r\n delete (sanitizedToolBlock as any).thought_signature;\r\n delete (sanitizedToolBlock as any).thought;\r\n filtered.push(sanitizedToolBlock);\r\n continue;\r\n }\r\n\r\n const isThinking = isThinkingPart(item);\r\n const hasSignature = hasSignatureField(item);\r\n\r\n if (!isThinking && !hasSignature) {\r\n filtered.push(item);\r\n continue;\r\n }\r\n\r\n if (isClaudeModel && (isThinking || hasSignature)) {\n // Use plain empty text part \u2014 thinking-format sentinels get converted by the proxy\n // into Claude thinking blocks with missing required fields\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (item.cache_control) sentinel.cache_control = item.cache_control;\n filtered.push(sentinel);\n continue;\n }\r\n // For the LAST assistant message with thinking blocks:\r\n // - If signature is OUR cached signature, pass through unchanged\r\n // - Otherwise inject sentinel to bypass Antigravity validation\r\n // NOTE: We can't trust signatures just because they're >= 50 chars - Claude returns\r\n // its own signatures which are long but invalid for Antigravity.\r\n if (isLastAssistantMessage && (isThinking || hasSignature)) {\r\n // First check if it's our cached signature\r\n if (isOurCachedSignature(item, sessionId, getCachedSignatureFn)) {\r\n const sanitized = sanitizeThinkingPart(item);\n if (sanitized) {\n filtered.push(sanitized);\n } else {\n // sanitizeThinkingPart returned null \u2014 use sentinel to preserve array length\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (item.cache_control) sentinel.cache_control = item.cache_control;\n filtered.push(sentinel);\n }\n continue;\n }\n \n // Not our signature (or no signature) - use plain empty text sentinel // Thinking-format sentinels get converted by the proxy into Claude thinking blocks with missing required fields\n const existingSignature = item.signature || item.thoughtSignature;\n const signatureInfo = existingSignature ? `foreign signature (${String(existingSignature).length} chars)` : \"no signature\";\n log.debug(`Injecting plain text sentinel for last-message thinking block with ${signatureInfo}`);\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (item.cache_control) sentinel.cache_control = item.cache_control;\n filtered.push(sentinel);\n continue; }\r\n\r\n if (isOurCachedSignature(item, sessionId, getCachedSignatureFn)) {\n const sanitized = sanitizeThinkingPart(item);\n if (sanitized) {\n filtered.push(sanitized);\n } else {\n // sanitizeThinkingPart returned null \u2014 use sentinel to preserve array length\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (item.cache_control) sentinel.cache_control = item.cache_control;\n filtered.push(sentinel);\n }\n continue;\n }\n\n if (sessionId && getCachedSignatureFn) {\n const text = getThinkingText(item);\n if (text) {\n const cachedSignature = getCachedSignatureFn(sessionId, text);\n if (cachedSignature && cachedSignature.length >= 50) {\n const restoredPart = { ...item };\n if ((item as any).thought === true) {\n (restoredPart as any).thoughtSignature = cachedSignature;\n } else {\n (restoredPart as any).signature = cachedSignature;\n }\n const sanitized = sanitizeThinkingPart(restoredPart as Record<string, unknown>);\n if (sanitized) {\n filtered.push(sanitized);\n } else {\n // sanitizeThinkingPart returned null \u2014 use sentinel to preserve array length\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (item.cache_control) sentinel.cache_control = item.cache_control;\n filtered.push(sentinel);\n }\n continue;\n }\n }\n }\n\n // Catch-all: thinking/signature part that didn't match any branch above\n // Use sentinel instead of silently dropping to preserve array length\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (item.cache_control) sentinel.cache_control = item.cache_control;\n filtered.push(sentinel);\n }\n\n return filtered;}\r\n\r\n/**\r\n * Filters thinking blocks from contents unless the signature matches our cache.\r\n * Attempts to restore signatures from cache for thinking blocks that lack signatures.\r\n *\r\n * @param contents - The contents array from the request\r\n * @param sessionId - Optional session ID for signature cache lookup\r\n * @param getCachedSignatureFn - Optional function to retrieve cached signatures\r\n */\r\nexport function filterUnsignedThinkingBlocks(\r\n contents: any[],\r\n sessionId?: string,\r\n getCachedSignatureFn?: (sessionId: string, text: string) => string | undefined,\r\n isClaudeModel?: boolean,\r\n): any[] {\r\n const lastAssistantIdx = findLastAssistantIndex(contents, \"model\");\r\n\r\n return contents.map((content: any, idx: number) => {\r\n if (!content || typeof content !== \"object\") {\r\n return content;\r\n }\r\n\r\n const isLastAssistant = idx === lastAssistantIdx;\r\n\r\n if (Array.isArray((content as any).parts)) {\r\n const filteredParts = filterContentArray(\r\n (content as any).parts,\r\n sessionId,\r\n getCachedSignatureFn,\r\n isClaudeModel,\r\n isLastAssistant,\r\n );\r\n\r\n const trimmedParts = (content as any).role === \"model\" && !isClaudeModel\r\n ? removeTrailingThinkingBlocks(filteredParts, sessionId, getCachedSignatureFn)\r\n : filteredParts;\r\n\r\n return { ...content, parts: trimmedParts };\r\n }\r\n\r\n if (Array.isArray((content as any).content)) {\r\n const isAssistantRole = (content as any).role === \"assistant\";\r\n const isLastAssistantContent = idx === lastAssistantIdx || \r\n (isAssistantRole && idx === findLastAssistantIndex(contents, \"assistant\"));\r\n \r\n const filteredContent = filterContentArray(\r\n (content as any).content,\r\n sessionId,\r\n getCachedSignatureFn,\r\n isClaudeModel,\r\n isLastAssistantContent,\r\n );\r\n\r\n const trimmedContent = isAssistantRole && !isClaudeModel\r\n ? removeTrailingThinkingBlocks(filteredContent, sessionId, getCachedSignatureFn)\r\n : filteredContent;\r\n\r\n return { ...content, content: trimmedContent };\r\n }\r\n\r\n return content;\r\n });\r\n}\r\n\r\n/**\r\n * Filters thinking blocks from Anthropic-style messages[] payloads using cached signatures.\r\n */\r\nexport function filterMessagesThinkingBlocks(\r\n messages: any[],\r\n sessionId?: string,\r\n getCachedSignatureFn?: (sessionId: string, text: string) => string | undefined,\r\n isClaudeModel?: boolean,\r\n): any[] {\r\n const lastAssistantIdx = findLastAssistantIndex(messages, \"assistant\");\r\n\r\n return messages.map((message: any, idx: number) => {\r\n if (!message || typeof message !== \"object\") {\r\n return message;\r\n }\r\n\r\n if (Array.isArray((message as any).content)) {\r\n const isAssistantRole = (message as any).role === \"assistant\";\r\n const isLastAssistant = isAssistantRole && idx === lastAssistantIdx;\r\n \r\n const filteredContent = filterContentArray(\r\n (message as any).content,\r\n sessionId,\r\n getCachedSignatureFn,\r\n isClaudeModel,\r\n isLastAssistant,\r\n );\r\n\r\n const trimmedContent = isAssistantRole && !isClaudeModel\r\n ? removeTrailingThinkingBlocks(filteredContent, sessionId, getCachedSignatureFn)\r\n : filteredContent;\r\n\r\n return { ...message, content: trimmedContent };\r\n }\r\n\r\n return message;\r\n });\r\n}\r\n\r\nexport function deepFilterThinkingBlocks(\r\n payload: unknown,\r\n sessionId?: string,\r\n getCachedSignatureFn?: (sessionId: string, text: string) => string | undefined,\r\n isClaudeModel?: boolean,\r\n): unknown {\r\n const visited = new WeakSet<object>();\r\n\r\n const walk = (value: unknown): void => {\r\n if (!value || typeof value !== \"object\") {\r\n return;\r\n }\r\n\r\n if (visited.has(value as object)) {\r\n return;\r\n }\r\n\r\n visited.add(value as object);\r\n\r\n if (Array.isArray(value)) {\r\n value.forEach((item) => walk(item));\r\n return;\r\n }\r\n\r\n const obj = value as Record<string, unknown>;\r\n\r\n if (Array.isArray(obj.contents)) {\r\n obj.contents = filterUnsignedThinkingBlocks(\r\n obj.contents as any[],\r\n sessionId,\r\n getCachedSignatureFn,\r\n isClaudeModel,\r\n );\r\n }\r\n\r\n if (Array.isArray(obj.messages)) {\r\n obj.messages = filterMessagesThinkingBlocks(\r\n obj.messages as any[],\r\n sessionId,\r\n getCachedSignatureFn,\r\n isClaudeModel,\r\n );\r\n }\r\n\r\n Object.keys(obj).forEach((key) => walk(obj[key]));\r\n };\r\n\r\n walk(payload);\r\n return payload;\r\n}\r\n\r\n/**\r\n * Transforms Gemini-style thought parts (thought: true) and Anthropic-style\r\n * thinking parts (type: \"thinking\") to reasoning format.\r\n * Claude responses through Antigravity may use candidates structure with Anthropic-style parts.\r\n */\r\nfunction transformGeminiCandidate(candidate: any): any {\r\n if (!candidate || typeof candidate !== \"object\") {\r\n return candidate;\r\n }\r\n\r\n const content = candidate.content;\r\n if (!content || typeof content !== \"object\" || !Array.isArray(content.parts)) {\r\n return candidate;\r\n }\r\n\r\n const thinkingTexts: string[] = [];\r\n const transformedParts = content.parts.map((part: any) => {\r\n if (!part || typeof part !== \"object\") {\r\n return part;\r\n }\r\n\r\n // Handle Gemini-style: thought: true\n if (part.thought === true) {\n const thinkingText = typeof part.text === \"string\" ? part.text : \"\";\n thinkingTexts.push(thinkingText);\n // Clean object \u2014 NO spread to prevent thinking: <object> leaking into output\n const transformed: Record<string, unknown> = {\n type: \"reasoning\",\n text: thinkingText,\n thought: true,\n };\n const sig = part.signature || part.thoughtSignature;\n if (typeof sig === \"string\" && sig) transformed.signature = sig;\n if (part.cache_control) transformed.cache_control = part.cache_control;\n return transformed;\n }\n\n // Handle Anthropic-style in candidates: type: \"thinking\"\n if (part.type === \"thinking\") {\n const thinkingText = typeof part.thinking === \"string\" ? part.thinking : typeof part.text === \"string\" ? part.text : \"\";\n thinkingTexts.push(thinkingText);\n // Clean object \u2014 NO spread to prevent thinking: <object> leaking into output\n const transformed: Record<string, unknown> = {\n type: \"reasoning\",\n text: thinkingText,\n thought: true,\n };\n const sig = part.signature || part.thoughtSignature;\n if (typeof sig === \"string\" && sig) transformed.signature = sig;\n if (part.cache_control) transformed.cache_control = part.cache_control;\n return transformed;\n }\r\n // Handle functionCall: parse JSON strings in args and ensure args is always defined\r\n // (Ported from LLM-API-Key-Proxy's _extract_tool_call)\r\n // Fix: When Claude calls a tool with no parameters, args may be undefined.\r\n // opencode expects state.input to be a record, so we must ensure args: {} as fallback.\r\n if (part.functionCall) {\r\n const parsedArgs = part.functionCall.args\r\n ? recursivelyParseJsonStrings(part.functionCall.args)\r\n : {};\r\n return {\r\n ...part,\r\n functionCall: {\r\n ...part.functionCall,\r\n args: parsedArgs,\r\n },\r\n };\r\n }\r\n\r\n // Handle image data (inlineData) - save to disk and return file path\r\n if (part.inlineData) {\r\n const result = processImageData({\r\n mimeType: part.inlineData.mimeType,\r\n data: part.inlineData.data,\r\n });\r\n if (result) {\r\n return { text: result };\r\n }\r\n }\r\n\r\n return part;\r\n });\r\n\r\n return {\r\n ...candidate,\r\n content: { ...content, parts: transformedParts },\r\n ...(thinkingTexts.length > 0 ? { reasoning_content: thinkingTexts.join(\"\\n\\n\") } : {}),\r\n };\r\n}\r\n\r\n/**\r\n * Transforms thinking/reasoning content in response parts to OpenCode's expected format.\r\n * Handles both Gemini-style (thought: true) and Anthropic-style (type: \"thinking\") formats.\r\n * Also extracts reasoning_content for Anthropic-style responses.\r\n */\r\nexport function transformThinkingParts(response: unknown): unknown {\r\n if (!response || typeof response !== \"object\") {\r\n return response;\r\n }\r\n\r\n const resp = response as Record<string, unknown>;\r\n const result: Record<string, unknown> = { ...resp };\r\n const reasoningTexts: string[] = [];\r\n\r\n // Handle Anthropic-style content array (type: \"thinking\")\r\n if (Array.isArray(resp.content)) {\r\n const transformedContent: any[] = [];\r\n for (const block of resp.content) {\r\n if (block && typeof block === \"object\" && (block as any).type === \"thinking\") {\n const thinkingText = typeof (block as any).thinking === \"string\" ? (block as any).thinking : typeof (block as any).text === \"string\" ? (block as any).text : \"\";\n reasoningTexts.push(thinkingText);\n // Clean object \u2014 NO spread to prevent thinking: <object> leaking into output\n const transformed: Record<string, unknown> = {\n type: \"reasoning\",\n text: thinkingText,\n thought: true,\n };\n const sig = (block as any).signature || (block as any).thoughtSignature;\n if (typeof sig === \"string\" && sig) transformed.signature = sig;\n if ((block as any).cache_control) transformed.cache_control = (block as any).cache_control;\n\n transformedContent.push(transformed); } else {\r\n transformedContent.push(block);\r\n }\r\n }\r\n result.content = transformedContent;\r\n }\r\n\r\n // Handle Gemini-style candidates array\r\n if (Array.isArray(resp.candidates)) {\r\n result.candidates = resp.candidates.map(transformGeminiCandidate);\r\n }\r\n\r\n // Add reasoning_content if we found any thinking blocks (for Anthropic-style)\r\n if (reasoningTexts.length > 0 && !result.reasoning_content) {\r\n result.reasoning_content = reasoningTexts.join(\"\\n\\n\");\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Ensures thinkingConfig is valid: includeThoughts only allowed when budget > 0.\r\n */\r\nexport function normalizeThinkingConfig(config: unknown): ThinkingConfig | undefined {\r\n if (!config || typeof config !== \"object\") {\r\n return undefined;\r\n }\r\n\r\n const record = config as Record<string, unknown>;\r\n const budgetRaw = record.thinkingBudget ?? record.thinking_budget;\r\n const includeRaw = record.includeThoughts ?? record.include_thoughts;\r\n\r\n const thinkingBudget = typeof budgetRaw === \"number\" && Number.isFinite(budgetRaw) ? budgetRaw : undefined;\r\n const includeThoughts = typeof includeRaw === \"boolean\" ? includeRaw : undefined;\r\n\r\n const enableThinking = thinkingBudget !== undefined && thinkingBudget > 0;\r\n const finalInclude = enableThinking ? includeThoughts ?? false : false;\r\n\r\n if (!enableThinking && finalInclude === false && thinkingBudget === undefined && includeThoughts === undefined) {\r\n return undefined;\r\n }\r\n\r\n const normalized: ThinkingConfig = {};\r\n if (thinkingBudget !== undefined) {\r\n normalized.thinkingBudget = thinkingBudget;\r\n }\r\n if (finalInclude !== undefined) {\r\n normalized.includeThoughts = finalInclude;\r\n }\r\n return normalized;\r\n}\r\n\r\n/**\r\n * Parses an Antigravity API body; handles array-wrapped responses the API sometimes returns.\r\n */\r\nexport function parseAntigravityApiBody(rawText: string): AntigravityApiBody | null {\r\n try {\r\n const parsed = JSON.parse(rawText);\r\n if (Array.isArray(parsed)) {\r\n const firstObject = parsed.find((item: unknown) => typeof item === \"object\" && item !== null);\r\n if (firstObject && typeof firstObject === \"object\") {\r\n return firstObject as AntigravityApiBody;\r\n }\r\n return null;\r\n }\r\n\r\n if (parsed && typeof parsed === \"object\") {\r\n return parsed as AntigravityApiBody;\r\n }\r\n\r\n return null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Extracts usageMetadata from a response object, guarding types.\r\n */\r\nexport function extractUsageMetadata(body: AntigravityApiBody): AntigravityUsageMetadata | null {\r\n const usage = (body.response && typeof body.response === \"object\"\r\n ? (body.response as { usageMetadata?: unknown }).usageMetadata\r\n : undefined) as AntigravityUsageMetadata | undefined;\r\n\r\n if (!usage || typeof usage !== \"object\") {\r\n return null;\r\n }\r\n\r\n const asRecord = usage as Record<string, unknown>;\r\n const toNumber = (value: unknown): number | undefined =>\r\n typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\r\n\r\n return {\r\n totalTokenCount: toNumber(asRecord.totalTokenCount),\r\n promptTokenCount: toNumber(asRecord.promptTokenCount),\r\n candidatesTokenCount: toNumber(asRecord.candidatesTokenCount),\r\n cachedContentTokenCount: toNumber(asRecord.cachedContentTokenCount),\r\n thoughtsTokenCount: toNumber(asRecord.thoughtsTokenCount),\r\n };\r\n}\r\n\r\n/**\r\n * Walks SSE lines to find a usage-bearing response chunk.\r\n */\r\nexport function extractUsageFromSsePayload(payload: string): AntigravityUsageMetadata | null {\r\n const lines = payload.split(\"\\n\");\r\n for (const line of lines) {\r\n if (!line.startsWith(\"data:\")) {\r\n continue;\r\n }\r\n const jsonText = line.slice(5).trim();\r\n if (!jsonText) {\r\n continue;\r\n }\r\n try {\r\n const parsed = JSON.parse(jsonText);\r\n if (parsed && typeof parsed === \"object\") {\r\n const usage = extractUsageMetadata({ response: (parsed as Record<string, unknown>).response });\r\n if (usage) {\r\n return usage;\r\n }\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Enhances 404 errors for Antigravity models with a direct preview-access message.\r\n */\r\nexport function rewriteAntigravityPreviewAccessError(\r\n body: AntigravityApiBody,\r\n status: number,\r\n requestedModel?: string,\r\n): AntigravityApiBody | null {\r\n if (!needsPreviewAccessOverride(status, body, requestedModel)) {\r\n return null;\r\n }\r\n\r\n const error: AntigravityApiError = body.error ?? {};\r\n const trimmedMessage = typeof error.message === \"string\" ? error.message.trim() : \"\";\r\n const messagePrefix = trimmedMessage.length > 0\r\n ? trimmedMessage\r\n : \"Antigravity preview features are not enabled for this account.\";\r\n const enhancedMessage = `${messagePrefix} Request preview access at ${ANTIGRAVITY_PREVIEW_LINK} before using this model.`;\r\n\r\n return {\r\n ...body,\r\n error: {\r\n ...error,\r\n message: enhancedMessage,\r\n },\r\n };\r\n}\r\n\r\nfunction needsPreviewAccessOverride(\r\n status: number,\r\n body: AntigravityApiBody,\r\n requestedModel?: string,\r\n): boolean {\r\n if (status !== 404) {\r\n return false;\r\n }\r\n\r\n if (isAntigravityModel(requestedModel)) {\r\n return true;\r\n }\r\n\r\n const errorMessage = typeof body.error?.message === \"string\" ? body.error.message : \"\";\r\n return isAntigravityModel(errorMessage);\r\n}\r\n\r\nfunction isAntigravityModel(target?: string): boolean {\r\n if (!target) {\r\n return false;\r\n }\r\n\r\n // Check for Antigravity models instead of Gemini 3\r\n return /antigravity/i.test(target) || /opus/i.test(target) || /claude/i.test(target);\r\n}\r\n\r\n// ============================================================================\r\n// EMPTY RESPONSE DETECTION (Ported from LLM-API-Key-Proxy)\r\n// ============================================================================\r\n\r\n/**\r\n * Checks if a JSON response body represents an empty response.\r\n * \r\n * Empty responses occur when:\r\n * - No candidates in Gemini format\r\n * - No choices in OpenAI format\r\n * - Candidates/choices exist but have no content\r\n * \r\n * @param text - The response body text (should be valid JSON)\r\n * @returns true if the response is empty\r\n */\r\nexport function isEmptyResponseBody(text: string): boolean {\r\n if (!text || !text.trim()) {\r\n return true;\r\n }\r\n\r\n try {\r\n const parsed = JSON.parse(text);\r\n \r\n // Check for empty candidates (Gemini/Antigravity format)\r\n if (parsed.candidates !== undefined) {\r\n if (!Array.isArray(parsed.candidates) || parsed.candidates.length === 0) {\r\n return true;\r\n }\r\n \r\n // Check if first candidate has empty content\r\n const firstCandidate = parsed.candidates[0];\r\n if (!firstCandidate) {\r\n return true;\r\n }\r\n \r\n // Check for empty parts in content\r\n const content = firstCandidate.content;\r\n if (!content || typeof content !== \"object\") {\r\n return true;\r\n }\r\n \r\n const parts = content.parts;\r\n if (!Array.isArray(parts) || parts.length === 0) {\r\n return true;\r\n }\r\n \r\n // Check if all parts are empty (no text, no functionCall)\r\n const hasContent = parts.some((part: any) => {\r\n if (!part || typeof part !== \"object\") return false;\r\n if (typeof part.text === \"string\" && part.text.length > 0) return true;\r\n if (part.functionCall) return true;\r\n if (part.thought === true && typeof part.text === \"string\") return true;\r\n return false;\r\n });\r\n \r\n if (!hasContent) {\r\n return true;\r\n }\r\n }\r\n \r\n // Check for empty choices (OpenAI format - shouldn't occur but handle it)\r\n if (parsed.choices !== undefined) {\r\n if (!Array.isArray(parsed.choices) || parsed.choices.length === 0) {\r\n return true;\r\n }\r\n \r\n const firstChoice = parsed.choices[0];\r\n if (!firstChoice) {\r\n return true;\r\n }\r\n \r\n // Check for empty message/delta\r\n const message = firstChoice.message || firstChoice.delta;\r\n if (!message) {\r\n return true;\r\n }\r\n \r\n // Check if message has content or tool_calls\r\n if (!message.content && !message.tool_calls && !message.reasoning_content) {\r\n return true;\r\n }\r\n }\r\n \r\n // Check response wrapper (Antigravity envelope)\r\n if (parsed.response !== undefined) {\r\n const response = parsed.response;\r\n if (!response || typeof response !== \"object\") {\r\n return true;\r\n }\r\n return isEmptyResponseBody(JSON.stringify(response));\r\n }\r\n \r\n return false;\r\n } catch {\r\n // JSON parse error - treat as empty\r\n return true;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if a streaming SSE response yielded zero meaningful chunks.\r\n * \r\n * This is used after consuming a streaming response to determine if retry is needed.\r\n */\r\nexport interface StreamingChunkCounter {\r\n increment: () => void;\r\n getCount: () => number;\r\n hasContent: () => boolean;\r\n}\r\n\r\nexport function createStreamingChunkCounter(): StreamingChunkCounter {\r\n let count = 0;\r\n let hasRealContent = false;\r\n\r\n return {\r\n increment: () => {\r\n count++;\r\n },\r\n getCount: () => count,\r\n hasContent: () => hasRealContent || count > 0,\r\n };\r\n}\r\n\r\n/**\r\n * Checks if an SSE line contains meaningful content.\r\n * \r\n * @param line - A single SSE line (e.g., \"data: {...}\")\r\n * @returns true if the line contains content worth counting\r\n */\r\nexport function isMeaningfulSseLine(line: string): boolean {\r\n if (!line.startsWith(\"data: \")) {\r\n return false;\r\n }\r\n\r\n const data = line.slice(6).trim();\r\n \r\n if (data === \"[DONE]\") {\r\n return false;\r\n }\r\n\r\n if (!data) {\r\n return false;\r\n }\r\n\r\n try {\r\n const parsed = JSON.parse(data);\r\n \r\n // Check for candidates with content\r\n if (parsed.candidates && Array.isArray(parsed.candidates)) {\r\n for (const candidate of parsed.candidates) {\r\n const parts = candidate?.content?.parts;\r\n if (Array.isArray(parts) && parts.length > 0) {\r\n for (const part of parts) {\r\n if (typeof part?.text === \"string\" && part.text.length > 0) return true;\r\n if (part?.functionCall) return true;\r\n }\r\n }\r\n }\r\n }\r\n \r\n // Check response wrapper\r\n if (parsed.response?.candidates) {\r\n return isMeaningfulSseLine(`data: ${JSON.stringify(parsed.response)}`);\r\n }\r\n \r\n return false;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// RECURSIVE JSON STRING AUTO-PARSING (Ported from LLM-API-Key-Proxy)\r\n// ============================================================================\r\n\r\n/**\r\n * Recursively parses JSON strings in nested data structures.\r\n * \r\n * This is a port of LLM-API-Key-Proxy's _recursively_parse_json_strings() function.\r\n * \r\n * Handles:\r\n * - JSON-stringified values: {\"files\": \"[{...}]\"} \u2192 {\"files\": [{...}]}\r\n * - Malformed double-encoded JSON (extra trailing chars)\r\n * - Escaped control characters (\\\\n \u2192 \\n, \\\\t \u2192 \\t)\r\n * \r\n * This is useful because Antigravity sometimes returns JSON-stringified values\r\n * in tool arguments, which can cause downstream parsing issues.\r\n * \r\n * @param obj - The object to recursively parse\r\n * @param skipParseKeys - Set of keys whose values should NOT be parsed as JSON (preserved as strings)\r\n * @param currentKey - The current key being processed (internal use)\r\n * @returns The parsed object with JSON strings expanded\r\n */\r\n// Keys whose string values should NOT be parsed as JSON - they contain literal text content\r\nconst SKIP_PARSE_KEYS = new Set([\r\n \"oldString\",\r\n \"newString\",\r\n \"content\",\r\n \"filePath\",\r\n \"path\",\r\n \"text\",\r\n \"code\",\r\n \"source\",\r\n \"data\",\r\n \"body\",\r\n \"message\",\r\n \"prompt\",\r\n \"input\",\r\n \"output\",\r\n \"result\",\r\n \"value\",\r\n \"query\",\r\n \"pattern\",\r\n \"replacement\",\r\n \"template\",\r\n \"script\",\r\n \"command\",\r\n \"snippet\",\r\n]);\r\n\r\nexport function recursivelyParseJsonStrings(\r\n obj: unknown,\r\n skipParseKeys: Set<string> = SKIP_PARSE_KEYS,\r\n currentKey?: string,\r\n): unknown {\r\n if (obj === null || obj === undefined) {\r\n return obj;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map((item) => recursivelyParseJsonStrings(item, skipParseKeys));\r\n }\r\n\r\n if (typeof obj === \"object\") {\r\n const result: Record<string, unknown> = {};\r\n for (const [key, value] of Object.entries(obj)) {\r\n result[key] = recursivelyParseJsonStrings(value, skipParseKeys, key);\r\n }\r\n return result;\r\n }\r\n\r\n if (typeof obj !== \"string\") {\r\n return obj;\r\n }\r\n\r\n if (currentKey && skipParseKeys.has(currentKey)) {\r\n return obj;\r\n }\r\n\r\n const stripped = obj.trim();\r\n\r\n // Check if string contains control character escape sequences\r\n // that need unescaping (\\\\n, \\\\t but NOT \\\\\" or \\\\\\\\)\r\n const hasControlCharEscapes = obj.includes(\"\\\\n\") || obj.includes(\"\\\\t\");\r\n const hasIntentionalEscapes = obj.includes('\\\\\"') || obj.includes(\"\\\\\\\\\");\r\n\r\n if (hasControlCharEscapes && !hasIntentionalEscapes) {\r\n try {\r\n // Use JSON.parse with quotes to unescape the string\r\n return JSON.parse(`\"${obj}\"`);\r\n } catch {\r\n // Continue with original processing\r\n }\r\n }\r\n\r\n // Check if it looks like JSON (starts with { or [)\r\n if (stripped && (stripped[0] === \"{\" || stripped[0] === \"[\")) {\r\n // Try standard parsing first\r\n if (\r\n (stripped.startsWith(\"{\") && stripped.endsWith(\"}\")) ||\r\n (stripped.startsWith(\"[\") && stripped.endsWith(\"]\"))\r\n ) {\r\n try {\r\n const parsed = JSON.parse(obj);\r\n return recursivelyParseJsonStrings(parsed);\r\n } catch {\r\n // Continue\r\n }\r\n }\r\n\r\n // Handle malformed JSON: array that doesn't end with ]\r\n if (stripped.startsWith(\"[\") && !stripped.endsWith(\"]\")) {\r\n try {\r\n const lastBracket = stripped.lastIndexOf(\"]\");\r\n if (lastBracket > 0) {\r\n const cleaned = stripped.slice(0, lastBracket + 1);\r\n const parsed = JSON.parse(cleaned);\r\n log.debug(\"Auto-corrected malformed JSON array\", {\r\n truncatedChars: stripped.length - cleaned.length,\r\n });\r\n return recursivelyParseJsonStrings(parsed);\r\n }\r\n } catch {\r\n // Continue\r\n }\r\n }\r\n\r\n // Handle malformed JSON: object that doesn't end with }\r\n if (stripped.startsWith(\"{\") && !stripped.endsWith(\"}\")) {\r\n try {\r\n const lastBrace = stripped.lastIndexOf(\"}\");\r\n if (lastBrace > 0) {\r\n const cleaned = stripped.slice(0, lastBrace + 1);\r\n const parsed = JSON.parse(cleaned);\r\n log.debug(\"Auto-corrected malformed JSON object\", {\r\n truncatedChars: stripped.length - cleaned.length,\r\n });\r\n return recursivelyParseJsonStrings(parsed);\r\n }\r\n } catch {\r\n // Continue\r\n }\r\n }\r\n }\r\n\r\n return obj;\r\n}\r\n\r\n// ============================================================================\r\n// TOOL ID ORPHAN RECOVERY (Ported from LLM-API-Key-Proxy)\r\n// ============================================================================\r\n\r\n/**\r\n * Groups function calls with their responses, handling ID mismatches.\r\n * \r\n * This is a port of LLM-API-Key-Proxy's _fix_tool_response_grouping() function.\r\n * \r\n * When context compaction or other processes strip tool responses, the tool call\r\n * IDs become orphaned. This function attempts to recover by:\r\n * \r\n * 1. Pass 1: Match by exact ID (normal case)\r\n * 2. Pass 2: Match by function name (for ID mismatches)\r\n * 3. Pass 3: Match \"unknown_function\" orphans or take first available\r\n * 4. Fallback: Create placeholder responses for missing tool results\r\n * \r\n * @param contents - Array of Gemini-style content messages\r\n * @returns Fixed contents array with matched tool responses\r\n */\r\nexport function fixToolResponseGrouping(contents: any[]): any[] {\r\n if (!Array.isArray(contents) || contents.length === 0) {\r\n return contents;\r\n }\r\n\r\n const newContents: any[] = [];\r\n \r\n // Track pending tool call groups that need responses\r\n const pendingGroups: Array<{\r\n ids: string[];\r\n funcNames: string[];\r\n insertAfterIdx: number;\r\n }> = [];\r\n \r\n // Collected orphan responses (by ID)\r\n const collectedResponses = new Map<string, any>();\r\n \r\n for (const content of contents) {\r\n const role = content.role;\r\n const parts = content.parts || [];\r\n \r\n // Check if this is a tool response message\r\n const responseParts = parts.filter((p: any) => p?.functionResponse);\r\n \r\n if (responseParts.length > 0) {\r\n // Collect responses by ID (skip duplicates)\r\n for (const resp of responseParts) {\r\n const respId = resp.functionResponse?.id || \"\";\r\n if (respId && !collectedResponses.has(respId)) {\r\n collectedResponses.set(respId, resp);\r\n }\r\n }\r\n \r\n // Try to satisfy the most recent pending group\r\n for (let i = pendingGroups.length - 1; i >= 0; i--) {\r\n const group = pendingGroups[i]!;\r\n if (group.ids.every(id => collectedResponses.has(id))) {\r\n // All IDs found - build the response group\r\n const groupResponses = group.ids.map(id => {\r\n const resp = collectedResponses.get(id);\r\n collectedResponses.delete(id);\r\n return resp;\r\n });\r\n newContents.push({ parts: groupResponses, role: \"user\" });\r\n pendingGroups.splice(i, 1);\r\n break; // Only satisfy one group at a time\r\n }\r\n }\r\n continue; // Don't add the original response message\r\n }\r\n \r\n if (role === \"model\") {\r\n // Check for function calls in this model message\r\n const funcCalls = parts.filter((p: any) => p?.functionCall);\r\n newContents.push(content);\r\n \r\n if (funcCalls.length > 0) {\r\n const callIds = funcCalls\r\n .map((fc: any) => fc.functionCall?.id || \"\")\r\n .filter(Boolean);\r\n const funcNames = funcCalls\r\n .map((fc: any) => fc.functionCall?.name || \"\");\r\n \r\n if (callIds.length > 0) {\r\n pendingGroups.push({\r\n ids: callIds,\r\n funcNames,\r\n insertAfterIdx: newContents.length - 1,\r\n });\r\n }\r\n }\r\n } else {\r\n newContents.push(content);\r\n }\r\n }\r\n \r\n // Handle remaining pending groups with orphan recovery\r\n // Process in reverse order so insertions don't shift indices\r\n pendingGroups.sort((a, b) => b.insertAfterIdx - a.insertAfterIdx);\r\n \r\n for (const group of pendingGroups) {\r\n const groupResponses: any[] = [];\r\n \r\n for (let i = 0; i < group.ids.length; i++) {\r\n const expectedId = group.ids[i]!;\r\n const expectedName = group.funcNames[i] || \"\";\r\n \r\n if (collectedResponses.has(expectedId)) {\r\n // Direct ID match - ideal case\r\n groupResponses.push(collectedResponses.get(expectedId));\r\n collectedResponses.delete(expectedId);\r\n } else if (collectedResponses.size > 0) {\r\n // Need to find an orphan response\r\n let matchedId: string | null = null;\r\n \r\n // Pass 1: Match by function name\r\n for (const [orphanId, orphanResp] of collectedResponses) {\r\n const orphanName = orphanResp.functionResponse?.name || \"\";\r\n if (orphanName === expectedName) {\r\n matchedId = orphanId;\r\n break;\r\n }\r\n }\r\n \r\n // Pass 2: Match \"unknown_function\" orphans\r\n if (!matchedId) {\r\n for (const [orphanId, orphanResp] of collectedResponses) {\r\n if (orphanResp.functionResponse?.name === \"unknown_function\") {\r\n matchedId = orphanId;\r\n break;\r\n }\r\n }\r\n }\r\n \r\n // Pass 3: Take first available\r\n if (!matchedId) {\r\n matchedId = collectedResponses.keys().next().value ?? null;\r\n }\r\n \r\n if (matchedId) {\r\n const orphanResp = collectedResponses.get(matchedId)!;\r\n collectedResponses.delete(matchedId);\r\n \r\n // Fix the ID and name to match expected\r\n orphanResp.functionResponse.id = expectedId;\r\n if (orphanResp.functionResponse.name === \"unknown_function\" && expectedName) {\r\n orphanResp.functionResponse.name = expectedName;\r\n }\r\n \r\n log.debug(\"Auto-repaired tool ID mismatch\", {\r\n mappedFrom: matchedId,\r\n mappedTo: expectedId,\r\n functionName: expectedName,\r\n });\r\n \r\n groupResponses.push(orphanResp);\r\n }\r\n } else {\r\n // No responses available - create placeholder\r\n const placeholder = {\r\n functionResponse: {\r\n name: expectedName || \"unknown_function\",\r\n response: {\r\n result: {\r\n error: \"Tool response was lost during context processing. \" +\r\n \"This is a recovered placeholder.\",\r\n recovered: true,\r\n },\r\n },\r\n id: expectedId,\r\n },\r\n };\r\n \r\n log.debug(\"Created placeholder response for missing tool\", {\r\n id: expectedId,\r\n name: expectedName,\r\n });\r\n \r\n groupResponses.push(placeholder);\r\n }\r\n }\r\n \r\n if (groupResponses.length > 0) {\r\n // Insert at correct position (after the model message that made the calls)\r\n newContents.splice(group.insertAfterIdx + 1, 0, {\r\n parts: groupResponses,\r\n role: \"user\",\r\n });\r\n }\r\n }\r\n \r\n return newContents;\r\n}\r\n\r\n/**\r\n * Checks if contents have any tool call/response ID mismatches.\r\n * \r\n * @param contents - Array of Gemini-style content messages\r\n * @returns Object with mismatch details\r\n */\r\nexport function detectToolIdMismatches(contents: any[]): {\r\n hasMismatches: boolean;\r\n expectedIds: string[];\r\n foundIds: string[];\r\n missingIds: string[];\r\n orphanIds: string[];\r\n} {\r\n const expectedIds: string[] = [];\r\n const foundIds: string[] = [];\r\n \r\n for (const content of contents) {\r\n const parts = content.parts || [];\r\n \r\n for (const part of parts) {\r\n if (part?.functionCall?.id) {\r\n expectedIds.push(part.functionCall.id);\r\n }\r\n if (part?.functionResponse?.id) {\r\n foundIds.push(part.functionResponse.id);\r\n }\r\n }\r\n }\r\n \r\n const expectedSet = new Set(expectedIds);\r\n const foundSet = new Set(foundIds);\r\n \r\n const missingIds = expectedIds.filter(id => !foundSet.has(id));\r\n const orphanIds = foundIds.filter(id => !expectedSet.has(id));\r\n \r\n return {\r\n hasMismatches: missingIds.length > 0 || orphanIds.length > 0,\r\n expectedIds,\r\n foundIds,\r\n missingIds,\r\n orphanIds,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// CLAUDE FORMAT TOOL PAIRING (Defense in Depth)\r\n// ============================================================================\r\n\r\n/**\r\n * Find orphaned tool_use IDs (tool_use without matching tool_result).\r\n * Works on Claude format messages.\r\n */\r\nexport function findOrphanedToolUseIds(messages: any[]): Set<string> {\r\n const toolUseIds = new Set<string>();\r\n const toolResultIds = new Set<string>();\r\n\r\n for (const msg of messages) {\r\n if (Array.isArray(msg.content)) {\r\n for (const block of msg.content) {\r\n if (block.type === \"tool_use\" && block.id) {\r\n toolUseIds.add(block.id);\r\n }\r\n if (block.type === \"tool_result\" && block.tool_use_id) {\r\n toolResultIds.add(block.tool_use_id);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return new Set([...toolUseIds].filter((id) => !toolResultIds.has(id)));\r\n}\r\n\r\n/**\r\n * Fix orphaned tool_use blocks in Claude format messages.\r\n * Mirrors fixToolResponseGrouping() but for Claude's messages[] format.\r\n *\r\n * Claude format:\r\n * - assistant message with content[]: { type: 'tool_use', id, name, input }\r\n * - user message with content[]: { type: 'tool_result', tool_use_id, content }\r\n *\r\n * @param messages - Claude format messages array\r\n * @returns Fixed messages with placeholder tool_results for orphans\r\n */\r\nexport function fixClaudeToolPairing(messages: any[]): any[] {\r\n if (!Array.isArray(messages) || messages.length === 0) {\r\n return messages;\r\n }\r\n\r\n // 1. Collect all tool_use IDs from assistant messages\r\n const toolUseMap = new Map<string, { name: string; msgIndex: number }>();\r\n\r\n for (let i = 0; i < messages.length; i++) {\r\n const msg = messages[i];\r\n if (msg.role === \"assistant\" && Array.isArray(msg.content)) {\r\n for (const block of msg.content) {\r\n if (block.type === \"tool_use\" && block.id) {\r\n toolUseMap.set(block.id, { name: block.name || `tool-${toolUseMap.size}`, msgIndex: i });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 2. Collect all tool_result IDs from user messages\r\n const toolResultIds = new Set<string>();\r\n\r\n for (const msg of messages) {\r\n if (msg.role === \"user\" && Array.isArray(msg.content)) {\r\n for (const block of msg.content) {\r\n if (block.type === \"tool_result\" && block.tool_use_id) {\r\n toolResultIds.add(block.tool_use_id);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 3. Find orphaned tool_use (no matching tool_result)\r\n const orphans: Array<{ id: string; name: string; msgIndex: number }> = [];\r\n\r\n for (const [id, info] of toolUseMap) {\r\n if (!toolResultIds.has(id)) {\r\n orphans.push({ id, ...info });\r\n }\r\n }\r\n\r\n if (orphans.length === 0) {\r\n return messages;\r\n }\r\n\r\n // 4. Group orphans by message index (insert after each assistant message)\r\n const orphansByMsgIndex = new Map<number, typeof orphans>();\r\n for (const orphan of orphans) {\r\n const existing = orphansByMsgIndex.get(orphan.msgIndex) || [];\r\n existing.push(orphan);\r\n orphansByMsgIndex.set(orphan.msgIndex, existing);\r\n }\r\n\r\n // 5. Build new messages array with injected tool_results\r\n const result: any[] = [];\r\n\r\n for (let i = 0; i < messages.length; i++) {\r\n result.push(messages[i]);\r\n\r\n const orphansForMsg = orphansByMsgIndex.get(i);\r\n if (orphansForMsg && orphansForMsg.length > 0) {\r\n // Check if next message is user with tool_result - if so, merge into it\r\n const nextMsg = messages[i + 1];\r\n if (nextMsg?.role === \"user\" && Array.isArray(nextMsg.content)) {\r\n // Will be handled when we push nextMsg - add to its content\r\n const placeholders = orphansForMsg.map((o) => ({\r\n type: \"tool_result\",\r\n tool_use_id: o.id,\r\n content: `[Tool \"${o.name}\" execution was cancelled or failed]`,\r\n is_error: true,\r\n }));\r\n // Prepend placeholders to next message's content\r\n nextMsg.content = [...placeholders, ...nextMsg.content];\r\n } else {\r\n // Inject new user message with placeholder tool_results\r\n result.push({\r\n role: \"user\",\r\n content: orphansForMsg.map((o) => ({\r\n type: \"tool_result\",\r\n tool_use_id: o.id,\r\n content: `[Tool \"${o.name}\" execution was cancelled or failed]`,\r\n is_error: true,\r\n })),\r\n });\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Nuclear option: Remove orphaned tool_use blocks entirely.\r\n * Called when fixClaudeToolPairing() fails to pair all tools.\r\n */\r\nfunction removeOrphanedToolUse(messages: any[], orphanIds: Set<string>): any[] {\r\n return messages\r\n .map((msg) => {\r\n if (msg.role === \"assistant\" && Array.isArray(msg.content)) {\r\n return {\r\n ...msg,\r\n content: msg.content.filter(\r\n (block: any) => block.type !== \"tool_use\" || !orphanIds.has(block.id)\r\n ),\r\n };\r\n }\r\n return msg;\r\n })\r\n .filter(\r\n (msg) =>\r\n // Remove empty assistant messages\r\n !(msg.role === \"assistant\" && Array.isArray(msg.content) && msg.content.length === 0)\r\n );\r\n}\r\n\r\n/**\r\n * Validate and fix tool pairing with fallback nuclear option.\r\n * Defense in depth: tries gentle fix first, then nuclear removal.\r\n */\r\nexport function validateAndFixClaudeToolPairing(messages: any[]): any[] {\r\n if (!Array.isArray(messages) || messages.length === 0) {\r\n return messages;\r\n }\r\n\r\n // First: Try gentle fix (inject placeholder tool_results)\r\n let fixed = fixClaudeToolPairing(messages);\r\n\r\n // Second: Validate - find any remaining orphans\r\n const orphanIds = findOrphanedToolUseIds(fixed);\r\n\r\n if (orphanIds.size === 0) {\r\n return fixed;\r\n }\r\n\r\n // Third: Nuclear option - remove orphaned tool_use entirely\r\n // This should rarely happen, but provides defense in depth\r\n console.warn(\"[antigravity] fixClaudeToolPairing left orphans, applying nuclear option\", {\r\n orphanIds: [...orphanIds],\r\n });\r\n\r\n return removeOrphanedToolUse(fixed, orphanIds);\r\n}\r\n\r\n// ============================================================================\r\n// TOOL HALLUCINATION PREVENTION (Ported from LLM-API-Key-Proxy)\r\n// ============================================================================\r\n\r\n/**\r\n * Formats a type hint for a property schema.\r\n * Port of LLM-API-Key-Proxy's _format_type_hint()\r\n */\r\nfunction formatTypeHint(propData: Record<string, unknown>, depth = 0): string {\r\n const type = propData.type as string ?? \"unknown\";\r\n\r\n // Handle enum values\r\n if (propData.enum && Array.isArray(propData.enum)) {\r\n const enumVals = propData.enum as unknown[];\r\n if (enumVals.length <= 5) {\r\n return `string ENUM[${enumVals.map(v => JSON.stringify(v)).join(\", \")}]`;\r\n }\r\n return `string ENUM[${enumVals.length} options]`;\r\n }\r\n\r\n // Handle const values\r\n if (propData.const !== undefined) {\r\n return `string CONST=${JSON.stringify(propData.const)}`;\r\n }\r\n\r\n if (type === \"array\") {\r\n const items = propData.items as Record<string, unknown> | undefined;\r\n if (items && typeof items === \"object\") {\r\n const itemType = items.type as string ?? \"unknown\";\r\n if (itemType === \"object\") {\r\n const nestedProps = items.properties as Record<string, unknown> | undefined;\r\n const nestedReq = items.required as string[] | undefined ?? [];\r\n if (nestedProps && depth < 1) {\r\n const nestedList = Object.entries(nestedProps).map(([n, d]) => {\r\n const t = (d as Record<string, unknown>).type as string ?? \"unknown\";\r\n const req = nestedReq.includes(n) ? \" REQUIRED\" : \"\";\r\n return `${n}: ${t}${req}`;\r\n });\r\n return `ARRAY_OF_OBJECTS[${nestedList.join(\", \")}]`;\r\n }\r\n return \"ARRAY_OF_OBJECTS\";\r\n }\r\n return `ARRAY_OF_${itemType.toUpperCase()}`;\r\n }\r\n return \"ARRAY\";\r\n }\r\n\r\n if (type === \"object\") {\r\n const nestedProps = propData.properties as Record<string, unknown> | undefined;\r\n const nestedReq = propData.required as string[] | undefined ?? [];\r\n if (nestedProps && depth < 1) {\r\n const nestedList = Object.entries(nestedProps).map(([n, d]) => {\r\n const t = (d as Record<string, unknown>).type as string ?? \"unknown\";\r\n const req = nestedReq.includes(n) ? \" REQUIRED\" : \"\";\r\n return `${n}: ${t}${req}`;\r\n });\r\n return `object{${nestedList.join(\", \")}}`;\r\n }\r\n }\r\n\r\n return type;\r\n}\r\n\r\n/**\r\n * Injects parameter signatures into tool descriptions.\r\n * Port of LLM-API-Key-Proxy's _inject_signature_into_descriptions()\r\n * \r\n * This helps prevent tool hallucination by explicitly listing parameters\r\n * in the description, making it harder for the model to hallucinate\r\n * parameters from its training data.\r\n * \r\n * @param tools - Array of tool definitions (Gemini format)\r\n * @param promptTemplate - Template for the signature (default: \"\\\\n\\\\nSTRICT PARAMETERS: {params}.\")\r\n * @returns Modified tools array with signatures injected\r\n */\r\nexport function injectParameterSignatures(\r\n tools: any[],\r\n promptTemplate = \"\\n\\n\u26A0\uFE0F STRICT PARAMETERS: {params}.\",\r\n): any[] {\r\n if (!tools || !Array.isArray(tools)) return tools;\r\n\r\n return tools.map((tool) => {\r\n const declarations = tool.functionDeclarations;\r\n if (!Array.isArray(declarations)) return tool;\r\n\r\n const newDeclarations = declarations.map((decl: any) => {\r\n // Skip if signature already injected (avoids duplicate injection)\r\n if (decl.description?.includes(\"STRICT PARAMETERS:\")) {\r\n return decl;\r\n }\r\n\r\n const schema = decl.parameters || decl.parametersJsonSchema;\r\n if (!schema) return decl;\r\n\r\n const required = schema.required as string[] ?? [];\r\n const properties = schema.properties as Record<string, unknown> ?? {};\r\n\r\n if (Object.keys(properties).length === 0) return decl;\r\n\r\n const paramList = Object.entries(properties).map(([propName, propData]) => {\r\n const typeHint = formatTypeHint(propData as Record<string, unknown>);\r\n const isRequired = required.includes(propName);\r\n return `${propName} (${typeHint}${isRequired ? \", REQUIRED\" : \"\"})`;\r\n });\r\n\r\n const sigStr = promptTemplate.replace(\"{params}\", paramList.join(\", \"));\r\n \r\n return {\r\n ...decl,\r\n description: (decl.description || \"\") + sigStr,\r\n };\r\n });\r\n\r\n return { ...tool, functionDeclarations: newDeclarations };\r\n });\r\n}\r\n\r\n/**\r\n * Injects a tool hardening system instruction into the request payload.\r\n * Port of LLM-API-Key-Proxy's _inject_tool_hardening_instruction()\r\n * \r\n * @param payload - The Gemini request payload\r\n * @param instructionText - The instruction text to inject\r\n */\r\nexport function injectToolHardeningInstruction(\r\n payload: Record<string, unknown>,\r\n instructionText: string,\r\n): void {\r\n if (!instructionText) return;\r\n\r\n // Skip if instruction already present (avoids duplicate injection)\r\n const existing = payload.systemInstruction as Record<string, unknown> | undefined;\r\n if (existing && typeof existing === \"object\" && \"parts\" in existing) {\r\n const parts = existing.parts as Array<{ text?: string }>;\r\n if (Array.isArray(parts) && parts.some(p => p.text?.includes(\"CRITICAL TOOL USAGE INSTRUCTIONS\"))) {\r\n return;\r\n }\r\n }\r\n\r\n const instructionPart = { text: instructionText };\r\n\r\n if (payload.systemInstruction) {\r\n if (existing && typeof existing === \"object\" && \"parts\" in existing) {\r\n const parts = existing.parts as unknown[];\r\n if (Array.isArray(parts)) {\r\n parts.unshift(instructionPart);\r\n }\r\n } else if (typeof existing === \"string\") {\r\n payload.systemInstruction = {\r\n role: \"user\",\r\n parts: [instructionPart, { text: existing }],\r\n };\r\n } else {\r\n payload.systemInstruction = {\r\n role: \"user\",\r\n parts: [instructionPart],\r\n };\r\n }\r\n } else {\r\n payload.systemInstruction = {\r\n role: \"user\",\r\n parts: [instructionPart],\r\n };\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// TOOL PROCESSING FOR WRAPPED REQUESTS\r\n// Shared logic for assigning tool IDs and fixing tool pairing\r\n// ============================================================================\r\n\r\n/**\r\n * Assigns IDs to functionCall parts and returns the pending call IDs by name.\r\n * This is the first pass of tool ID assignment.\r\n * \r\n * @param contents - Gemini-style contents array\r\n * @returns Object with modified contents and pending call IDs map\r\n */\r\nexport function assignToolIdsToContents(\r\n contents: any[]\r\n): { contents: any[]; pendingCallIdsByName: Map<string, string[]>; toolCallCounter: number } {\r\n if (!Array.isArray(contents)) {\r\n return { contents, pendingCallIdsByName: new Map(), toolCallCounter: 0 };\r\n }\r\n\r\n let toolCallCounter = 0;\r\n const pendingCallIdsByName = new Map<string, string[]>();\r\n\r\n const newContents = contents.map((content: any) => {\r\n if (!content || !Array.isArray(content.parts)) {\r\n return content;\r\n }\r\n\r\n const newParts = content.parts.map((part: any) => {\r\n if (part && typeof part === \"object\" && part.functionCall) {\r\n const call = { ...part.functionCall };\r\n if (!call.id) {\r\n call.id = `tool-call-${++toolCallCounter}`;\r\n }\r\n const nameKey = typeof call.name === \"string\" ? call.name : `tool-${toolCallCounter}`;\r\n const queue = pendingCallIdsByName.get(nameKey) || [];\r\n queue.push(call.id);\r\n pendingCallIdsByName.set(nameKey, queue);\r\n return { ...part, functionCall: call };\r\n }\r\n return part;\r\n });\r\n\r\n return { ...content, parts: newParts };\r\n });\r\n\r\n return { contents: newContents, pendingCallIdsByName, toolCallCounter };\r\n}\r\n\r\n/**\r\n * Matches functionResponse IDs to their corresponding functionCall IDs.\r\n * This is the second pass of tool ID assignment.\r\n * \r\n * @param contents - Gemini-style contents array\r\n * @param pendingCallIdsByName - Map of function names to pending call IDs\r\n * @returns Modified contents with matched response IDs\r\n */\r\nexport function matchResponseIdsToContents(\r\n contents: any[],\r\n pendingCallIdsByName: Map<string, string[]>\r\n): any[] {\r\n if (!Array.isArray(contents)) {\r\n return contents;\r\n }\r\n\r\n return contents.map((content: any) => {\r\n if (!content || !Array.isArray(content.parts)) {\r\n return content;\r\n }\r\n\r\n const newParts = content.parts.map((part: any) => {\r\n if (part && typeof part === \"object\" && part.functionResponse) {\r\n const resp = { ...part.functionResponse };\r\n if (!resp.id && typeof resp.name === \"string\") {\r\n const queue = pendingCallIdsByName.get(resp.name);\r\n if (queue && queue.length > 0) {\r\n resp.id = queue.shift();\r\n pendingCallIdsByName.set(resp.name, queue);\r\n }\r\n }\r\n return { ...part, functionResponse: resp };\r\n }\r\n return part;\r\n });\r\n\r\n return { ...content, parts: newParts };\r\n });\r\n}\r\n\r\n/**\r\n * Applies all tool fixes to a request payload for Claude models.\r\n * This includes:\r\n * 1. Tool ID assignment for functionCalls\r\n * 2. Response ID matching for functionResponses\r\n * 3. Orphan recovery via fixToolResponseGrouping\r\n * 4. Claude format pairing fix via validateAndFixClaudeToolPairing\r\n * \r\n * @param payload - Request payload object\r\n * @param isClaude - Whether this is a Claude model request\r\n * @returns Object with fix applied status\r\n */\r\nexport function applyToolPairingFixes(\r\n payload: Record<string, unknown>,\r\n isClaude: boolean\r\n): { contentsFixed: boolean; messagesFixed: boolean } {\r\n let contentsFixed = false;\r\n let messagesFixed = false;\r\n\r\n if (!isClaude) {\r\n return { contentsFixed, messagesFixed };\r\n }\r\n\r\n // Fix Gemini format (contents[])\r\n if (Array.isArray(payload.contents)) {\r\n // First pass: assign IDs to functionCalls\r\n const { contents: contentsWithIds, pendingCallIdsByName } = assignToolIdsToContents(\r\n payload.contents as any[]\r\n );\r\n\r\n // Second pass: match functionResponse IDs\r\n const contentsWithMatchedIds = matchResponseIdsToContents(contentsWithIds, pendingCallIdsByName);\r\n\r\n // Third pass: fix orphan recovery\r\n payload.contents = fixToolResponseGrouping(contentsWithMatchedIds);\r\n contentsFixed = true;\r\n\r\n log.debug(\"Applied tool pairing fixes to contents[]\", {\r\n originalLength: (payload.contents as any[]).length,\r\n });\r\n }\r\n\r\n // Fix Claude format (messages[])\r\n if (Array.isArray(payload.messages)) {\r\n payload.messages = validateAndFixClaudeToolPairing(payload.messages as any[]);\r\n messagesFixed = true;\r\n\r\n log.debug(\"Applied tool pairing fixes to messages[]\", {\r\n originalLength: (payload.messages as any[]).length,\r\n });\r\n }\r\n\r\n return { contentsFixed, messagesFixed };\r\n}\r\n\r\n// ============================================================================\r\n// SYNTHETIC CLAUDE SSE RESPONSE\r\n// Used to return error messages as \"successful\" responses to avoid locking\r\n// the OpenCode session when unrecoverable errors (like 400 Prompt Too Long) occur.\r\n// ============================================================================\r\n\r\n/**\r\n * Creates a synthetic Claude SSE streaming response with error content.\r\n * \r\n * When returning HTTP 400/500 errors to OpenCode, the session becomes locked\r\n * and the user cannot use /compact or other commands. This function creates\r\n * a fake \"successful\" SSE response (200 OK) with the error message as text content,\r\n * allowing the user to continue using the session.\r\n * \r\n * @param errorMessage - The error message to include in the response\r\n * @param requestedModel - The model that was requested\r\n * @returns A Response object with synthetic SSE stream\r\n */\r\nexport function createSyntheticErrorResponse(\r\n errorMessage: string,\r\n requestedModel: string = \"unknown\",\r\n): Response {\r\n // Generate a unique message ID\r\n const messageId = `msg_synthetic_${Date.now()}`;\r\n \r\n // Build Claude SSE events that represent a complete message with error text\r\n const events: string[] = [];\r\n \r\n // 1. message_start event\r\n events.push(`event: message_start\r\ndata: ${JSON.stringify({\r\n type: \"message_start\",\r\n message: {\r\n id: messageId,\r\n type: \"message\",\r\n role: \"assistant\",\r\n content: [],\r\n model: requestedModel,\r\n stop_reason: null,\r\n stop_sequence: null,\r\n usage: { input_tokens: 0, output_tokens: 0 },\r\n },\r\n })}\r\n\r\n`);\r\n\r\n // 2. content_block_start event\r\n events.push(`event: content_block_start\r\ndata: ${JSON.stringify({\r\n type: \"content_block_start\",\r\n index: 0,\r\n content_block: { type: \"text\", text: \"\" },\r\n })}\r\n\r\n`);\r\n\r\n // 3. content_block_delta event with the error message\r\n events.push(`event: content_block_delta\r\ndata: ${JSON.stringify({\r\n type: \"content_block_delta\",\r\n index: 0,\r\n delta: { type: \"text_delta\", text: errorMessage },\r\n })}\r\n\r\n`);\r\n\r\n // 4. content_block_stop event\r\n events.push(`event: content_block_stop\r\ndata: ${JSON.stringify({\r\n type: \"content_block_stop\",\r\n index: 0,\r\n })}\r\n\r\n`);\r\n\r\n // 5. message_delta event (end_turn)\r\n events.push(`event: message_delta\r\ndata: ${JSON.stringify({\r\n type: \"message_delta\",\r\n delta: { stop_reason: \"end_turn\", stop_sequence: null },\r\n usage: { output_tokens: Math.ceil(errorMessage.length / 4) },\r\n })}\r\n\r\n`);\r\n\r\n // 6. message_stop event\r\n events.push(`event: message_stop\r\ndata: ${JSON.stringify({ type: \"message_stop\" })}\r\n\r\n`);\r\n\r\n const body = events.join(\"\");\r\n\r\n return new Response(body, {\r\n status: 200,\r\n headers: {\r\n \"Content-Type\": \"text/event-stream\",\r\n \"Cache-Control\": \"no-cache\",\r\n \"Connection\": \"keep-alive\",\r\n \"X-Antigravity-Synthetic\": \"true\",\r\n \"X-Antigravity-Error-Type\": \"prompt_too_long\",\r\n },\r\n });\r\n}\r\n", "/**\r\n * Thinking Recovery Module\r\n *\r\n * Minimal implementation for recovering from corrupted thinking state.\r\n * When Claude's conversation history gets corrupted (thinking blocks stripped/malformed),\r\n * this module provides a \"last resort\" recovery by closing the current turn and starting fresh.\r\n *\r\n * Philosophy: \"Let it crash and start again\" - Instead of trying to fix corrupted state,\r\n * we abandon the corrupted turn and let Claude generate fresh thinking.\r\n */\r\n\r\n// ============================================================================\r\n// TYPES\r\n// ============================================================================\r\n\r\n/**\r\n * Conversation state for thinking mode analysis\r\n */\r\nexport interface ConversationState {\r\n /** True if we're in an incomplete tool use loop (ends with functionResponse) */\r\n inToolLoop: boolean;\r\n /** Index of first model message in current turn */\r\n turnStartIdx: number;\r\n /** Whether the TURN started with thinking */\r\n turnHasThinking: boolean;\r\n /** Index of last model message */\r\n lastModelIdx: number;\r\n /** Whether last model msg has thinking */\r\n lastModelHasThinking: boolean;\r\n /** Whether last model msg has tool calls */\r\n lastModelHasToolCalls: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// DETECTION HELPERS\r\n// ============================================================================\r\n\r\n/**\r\n * Checks if a message part is a thinking/reasoning block.\r\n */\r\nfunction isThinkingPart(part: any): boolean {\r\n if (!part || typeof part !== \"object\") return false;\r\n return (\r\n part.thought === true ||\r\n part.type === \"thinking\" ||\r\n part.type === \"redacted_thinking\"\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a message part is a function response (tool result).\r\n */\r\nfunction isFunctionResponsePart(part: any): boolean {\r\n return part && typeof part === \"object\" && \"functionResponse\" in part;\r\n}\r\n\r\n/**\r\n * Checks if a message part is a function call.\r\n */\r\nfunction isFunctionCallPart(part: any): boolean {\r\n return part && typeof part === \"object\" && \"functionCall\" in part;\r\n}\r\n\r\n/**\r\n * Checks if a message is a tool result container (user role with functionResponse).\r\n */\r\nfunction isToolResultMessage(msg: any): boolean {\r\n if (!msg || msg.role !== \"user\") return false;\r\n const parts = msg.parts || [];\r\n return parts.some(isFunctionResponsePart);\r\n}\r\n\r\n/**\r\n * Checks if a message contains thinking/reasoning content.\r\n */\r\nfunction messageHasThinking(msg: any): boolean {\r\n if (!msg || typeof msg !== \"object\") return false;\r\n\r\n // Gemini format: parts array\r\n if (Array.isArray(msg.parts)) {\r\n return msg.parts.some(isThinkingPart);\r\n }\r\n\r\n // Anthropic format: content array\r\n if (Array.isArray(msg.content)) {\r\n return msg.content.some(\r\n (block: any) =>\r\n block?.type === \"thinking\" || block?.type === \"redacted_thinking\",\r\n );\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Checks if a message contains tool calls.\r\n */\r\nfunction messageHasToolCalls(msg: any): boolean {\r\n if (!msg || typeof msg !== \"object\") return false;\r\n\r\n // Gemini format: parts array with functionCall\r\n if (Array.isArray(msg.parts)) {\r\n return msg.parts.some(isFunctionCallPart);\r\n }\r\n\r\n // Anthropic format: content array with tool_use\r\n if (Array.isArray(msg.content)) {\r\n return msg.content.some((block: any) => block?.type === \"tool_use\");\r\n }\r\n\r\n return false;\r\n}\r\n\r\n// ============================================================================\r\n// CONVERSATION STATE ANALYSIS\r\n// ============================================================================\r\n\r\n/**\r\n * Analyzes conversation state to detect tool use loops and thinking mode issues.\r\n *\r\n * Key insight: A \"turn\" can span multiple assistant messages in a tool-use loop.\r\n * We need to find the TURN START (first assistant message after last real user message)\r\n * and check if THAT message had thinking, not just the last assistant message.\r\n */\r\nexport function analyzeConversationState(contents: any[]): ConversationState {\r\n const state: ConversationState = {\r\n inToolLoop: false,\r\n turnStartIdx: -1,\r\n turnHasThinking: false,\r\n lastModelIdx: -1,\r\n lastModelHasThinking: false,\r\n lastModelHasToolCalls: false,\r\n };\r\n\r\n if (!Array.isArray(contents) || contents.length === 0) {\r\n return state;\r\n }\r\n\r\n // First pass: Find the last \"real\" user message (not a tool result)\r\n let lastRealUserIdx = -1;\r\n for (let i = 0; i < contents.length; i++) {\r\n const msg = contents[i];\r\n if (msg?.role === \"user\" && !isToolResultMessage(msg)) {\r\n lastRealUserIdx = i;\r\n }\r\n }\r\n\r\n // Second pass: Analyze conversation and find turn boundaries\r\n for (let i = 0; i < contents.length; i++) {\r\n const msg = contents[i];\r\n const role = msg?.role;\r\n\r\n if (role === \"model\" || role === \"assistant\") {\r\n const hasThinking = messageHasThinking(msg);\r\n const hasToolCalls = messageHasToolCalls(msg);\r\n\r\n // Track if this is the turn start\r\n if (i > lastRealUserIdx && state.turnStartIdx === -1) {\r\n state.turnStartIdx = i;\r\n state.turnHasThinking = hasThinking;\r\n }\r\n\r\n state.lastModelIdx = i;\r\n state.lastModelHasToolCalls = hasToolCalls;\r\n state.lastModelHasThinking = hasThinking;\r\n }\r\n }\r\n\r\n // Determine if we're in a tool loop\r\n // We're in a tool loop if the conversation ends with a tool result\r\n if (contents.length > 0) {\r\n const lastMsg = contents[contents.length - 1];\r\n if (lastMsg?.role === \"user\" && isToolResultMessage(lastMsg)) {\r\n state.inToolLoop = true;\r\n }\r\n }\r\n\r\n return state;\r\n}\r\n\r\n// ============================================================================\r\n// RECOVERY FUNCTIONS\r\n// ============================================================================\r\n\r\n/**\n * Strips all thinking blocks from messages.\n * Uses sentinel replacement (.map) instead of deletion (.filter) to preserve\n * array indices and prevent prompt cache invalidation.\n */\nfunction stripAllThinkingBlocks(contents: any[]): any[] {\n return contents.map((content) => {\n if (!content || typeof content !== \"object\") return content;\n\n // Handle Gemini-style parts\n if (Array.isArray(content.parts)) {\n const mappedParts = content.parts.map((part: any) => {\n if (!isThinkingPart(part)) return part;\n // Replace with Gemini-format sentinel preserving cache_control\n // Use plain empty text part \u2014 thinking-format sentinels get converted by the proxy\n // into Claude thinking blocks missing the required `thinking` field.\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (part.cache_control !== undefined) sentinel.cache_control = part.cache_control;\n return sentinel;\n });\n return { ...content, parts: mappedParts };\n }\n\n // Handle Anthropic-style content\n if (Array.isArray(content.content)) {\n const mappedContent = content.content.map((block: any) => {\n if (block?.type !== \"thinking\" && block?.type !== \"redacted_thinking\") return block;\n // Replace with Anthropic-format sentinel preserving cache_control\n // Use plain empty text part \u2014 thinking-format sentinels get converted by the proxy\n // into Claude thinking blocks missing the required `thinking` field.\n const sentinel: Record<string, unknown> = { text: \".\" };\n if (block?.cache_control !== undefined) sentinel.cache_control = block.cache_control;\n return sentinel;\n });\n return { ...content, content: mappedContent };\n }\n\n return content;\n });\n}\r\n/**\r\n * Counts tool results at the end of the conversation.\r\n */\r\nfunction countTrailingToolResults(contents: any[]): number {\r\n let count = 0;\r\n\r\n for (let i = contents.length - 1; i >= 0; i--) {\r\n const msg = contents[i];\r\n\r\n if (msg?.role === \"user\") {\r\n const parts = msg.parts || [];\r\n const functionResponses = parts.filter(isFunctionResponsePart);\r\n\r\n if (functionResponses.length > 0) {\r\n count += functionResponses.length;\r\n } else {\r\n break; // Real user message, stop counting\r\n }\r\n } else if (msg?.role === \"model\" || msg?.role === \"assistant\") {\r\n break; // Stop at the model that made the tool calls\r\n }\r\n }\r\n\r\n return count;\r\n}\r\n\r\n/**\r\n * Closes an incomplete tool loop by injecting synthetic messages to start a new turn.\r\n *\r\n * This is the \"let it crash and start again\" recovery mechanism.\r\n *\r\n * When we detect:\r\n * - We're in a tool loop (conversation ends with functionResponse)\r\n * - The tool call was made WITHOUT thinking (thinking was stripped/corrupted)\r\n * - We NOW want to enable thinking\r\n *\r\n * Instead of trying to fix the corrupted state, we:\r\n * 1. Strip ALL thinking blocks (removes any corrupted ones)\r\n * 2. Add synthetic MODEL message to complete the non-thinking turn\r\n * 3. Add synthetic USER message to start a NEW turn\r\n *\r\n * This allows Claude to generate fresh thinking for the new turn.\r\n */\r\nexport function closeToolLoopForThinking(contents: any[]): any[] {\r\n // Strip any old/corrupted thinking first\r\n const strippedContents = stripAllThinkingBlocks(contents);\r\n\r\n // Count tool results from the end of the conversation\r\n const toolResultCount = countTrailingToolResults(strippedContents);\r\n\r\n // Build synthetic model message content based on tool count\r\n let syntheticModelContent: string;\r\n if (toolResultCount === 0) {\r\n syntheticModelContent = \"[Processing previous context.]\";\r\n } else if (toolResultCount === 1) {\r\n syntheticModelContent = \"[Tool execution completed.]\";\r\n } else {\r\n syntheticModelContent = `[${toolResultCount} tool executions completed.]`;\r\n }\r\n\r\n // Step 1: Inject synthetic MODEL message to complete the non-thinking turn\r\n const syntheticModel = {\r\n role: \"model\",\r\n parts: [{ text: syntheticModelContent }],\r\n };\r\n\r\n // Step 2: Inject synthetic USER message to start a NEW turn\r\n const syntheticUser = {\r\n role: \"user\",\r\n parts: [{ text: \"[Continue]\" }],\r\n };\r\n\r\n return [...strippedContents, syntheticModel, syntheticUser];\r\n}\r\n\r\n/**\r\n * Checks if conversation state requires tool loop closure for thinking recovery.\r\n *\r\n * Returns true if:\r\n * - We're in a tool loop (state.inToolLoop)\r\n * - The turn didn't start with thinking (state.turnHasThinking === false)\r\n *\r\n * This is the trigger for the \"let it crash and start again\" recovery.\r\n */\r\nexport function needsThinkingRecovery(state: ConversationState): boolean {\r\n return state.inToolLoop && !state.turnHasThinking;\r\n}\r\n\r\n// ============================================================================\r\n// COMPACTED THINKING TURN DETECTION (Ported from LLM-API-Key-Proxy)\r\n// ============================================================================\r\n\r\n/**\r\n * Detects if a message looks like it was compacted from a thinking-enabled turn.\r\n * \r\n * This is a heuristic to distinguish between:\r\n * - \"Never had thinking\" (model didn't use thinking mode)\r\n * - \"Thinking was stripped\" (context compaction removed thinking blocks)\r\n * \r\n * Port of LLM-API-Key-Proxy's _looks_like_compacted_thinking_turn()\r\n * \r\n * Heuristics:\r\n * 1. Has functionCall parts (typical thinking flow produces tool calls)\r\n * 2. No thinking parts (thought: true)\r\n * 3. No text content before functionCall (thinking responses usually have text)\r\n * \r\n * @param msg - A single message from the conversation\r\n * @returns true if the message looks like thinking was stripped\r\n */\r\nexport function looksLikeCompactedThinkingTurn(msg: any): boolean {\r\n if (!msg || typeof msg !== \"object\") return false;\r\n\r\n const parts = msg.parts || [];\r\n if (parts.length === 0) return false;\r\n\r\n // Check if message has function calls\r\n const hasFunctionCall = parts.some(\r\n (p: any) => p && typeof p === \"object\" && p.functionCall,\r\n );\r\n\r\n if (!hasFunctionCall) return false;\r\n\r\n // Check for thinking blocks\r\n const hasThinking = parts.some(\r\n (p: any) =>\r\n p &&\r\n typeof p === \"object\" &&\r\n (p.thought === true || p.type === \"thinking\" || p.type === \"redacted_thinking\"),\r\n );\r\n\r\n if (hasThinking) return false;\r\n\r\n // Check for text content (not thinking)\r\n const hasTextBeforeFunctionCall = parts.some((p: any, idx: number) => {\r\n if (!p || typeof p !== \"object\") return false;\r\n // Only check parts before the first functionCall\r\n const firstFuncIdx = parts.findIndex(\r\n (fp: any) => fp && typeof fp === \"object\" && fp.functionCall,\r\n );\r\n if (idx >= firstFuncIdx) return false;\r\n // Check for non-thinking text\r\n return (\r\n \"text\" in p &&\r\n typeof p.text === \"string\" &&\r\n p.text.trim().length > 0 &&\r\n !p.thought\r\n );\r\n });\r\n\r\n // If we have functionCall but no text before it, likely compacted\r\n return !hasTextBeforeFunctionCall;\r\n}\r\n\r\n/**\r\n * Checks if any message in the current turn looks like it was compacted.\r\n * \r\n * @param contents - Full conversation contents\r\n * @param turnStartIdx - Index of the first model message in current turn\r\n * @returns true if any model message in the turn looks compacted\r\n */\r\nexport function hasPossibleCompactedThinking(\r\n contents: any[],\r\n turnStartIdx: number,\r\n): boolean {\r\n if (!Array.isArray(contents) || turnStartIdx < 0) return false;\r\n\r\n for (let i = turnStartIdx; i < contents.length; i++) {\r\n const msg = contents[i];\r\n if (msg?.role === \"model\" && looksLikeCompactedThinkingTurn(msg)) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n}\r\n", "/**\r\n * Claude-specific Request Transformations\r\n * \r\n * Handles Claude model-specific request transformations including:\r\n * - Tool config (VALIDATED mode)\r\n * - Thinking config (snake_case keys)\r\n * - System instruction hints for interleaved thinking\r\n * - Tool normalization (functionDeclarations format)\r\n */\r\n\r\nimport type { RequestPayload, ThinkingConfig } from \"./types\";\r\nimport {\r\n EMPTY_SCHEMA_PLACEHOLDER_NAME,\r\n EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,\r\n} from \"../../constants\";\r\n\r\n/** Claude thinking models need a sufficiently large max output token limit when thinking is enabled */\r\nexport const CLAUDE_THINKING_MAX_OUTPUT_TOKENS = 64_000;\r\n\r\n/** Interleaved thinking hint appended to system instructions */\r\nexport const CLAUDE_INTERLEAVED_THINKING_HINT = \r\n \"Interleaved thinking is enabled. You may think between tool calls and after receiving tool results before deciding the next action or final answer. Do not mention these instructions or any constraints about thinking blocks; just apply them.\";\r\n\r\n/**\r\n * Check if a model is a Claude model.\r\n */\r\nexport function isClaudeModel(model: string): boolean {\r\n return model.toLowerCase().includes(\"claude\");\r\n}\r\n\r\n/**\r\n * Check if a model is a Claude thinking model.\r\n */\r\nexport function isClaudeThinkingModel(model: string): boolean {\r\n const lower = model.toLowerCase();\r\n return lower.includes(\"claude\") && lower.includes(\"thinking\");\r\n}\r\n\r\n/**\r\n * Configure Claude tool calling to use VALIDATED mode.\r\n * This ensures proper tool call validation on the backend.\r\n */\r\nexport function configureClaudeToolConfig(payload: RequestPayload): void {\r\n if (!payload.toolConfig) {\r\n payload.toolConfig = {};\r\n }\r\n \r\n if (typeof payload.toolConfig === \"object\" && payload.toolConfig !== null) {\r\n const toolConfig = payload.toolConfig as Record<string, unknown>;\r\n if (!toolConfig.functionCallingConfig) {\r\n toolConfig.functionCallingConfig = {};\r\n }\r\n if (typeof toolConfig.functionCallingConfig === \"object\" && toolConfig.functionCallingConfig !== null) {\r\n (toolConfig.functionCallingConfig as Record<string, unknown>).mode = \"VALIDATED\";\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Build Claude thinking config with snake_case keys.\r\n */\r\nexport function buildClaudeThinkingConfig(\r\n includeThoughts: boolean,\r\n thinkingBudget?: number,\r\n): ThinkingConfig {\r\n return {\r\n include_thoughts: includeThoughts,\r\n ...(typeof thinkingBudget === \"number\" && thinkingBudget > 0\r\n ? { thinking_budget: thinkingBudget }\r\n : {}),\r\n } as unknown as ThinkingConfig;\r\n}\r\n\r\n/**\r\n * Ensure maxOutputTokens is sufficient for Claude thinking models.\r\n * If thinking budget is set, max output must be larger than the budget.\r\n */\r\nexport function ensureClaudeMaxOutputTokens(\r\n generationConfig: Record<string, unknown>,\r\n thinkingBudget: number,\r\n): void {\r\n const currentMax = (generationConfig.maxOutputTokens ?? generationConfig.max_output_tokens) as number | undefined;\r\n \r\n if (!currentMax || currentMax <= thinkingBudget) {\r\n generationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;\r\n if (generationConfig.max_output_tokens !== undefined) {\r\n delete generationConfig.max_output_tokens;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Append interleaved thinking hint to system instruction.\r\n * Handles various system instruction formats (string, object with parts array).\r\n */\r\nexport function appendClaudeThinkingHint(\r\n payload: RequestPayload,\r\n hint: string = CLAUDE_INTERLEAVED_THINKING_HINT,\r\n): void {\r\n const existing = payload.systemInstruction;\r\n\r\n if (typeof existing === \"string\") {\r\n payload.systemInstruction = existing.trim().length > 0 ? `${existing}\\n\\n${hint}` : hint;\r\n } else if (existing && typeof existing === \"object\") {\r\n const sys = existing as Record<string, unknown>;\r\n const partsValue = sys.parts;\r\n\r\n if (Array.isArray(partsValue)) {\r\n const parts = partsValue as unknown[];\r\n let appended = false;\r\n\r\n // Find the last text part and append to it\r\n for (let i = parts.length - 1; i >= 0; i--) {\r\n const part = parts[i];\r\n if (part && typeof part === \"object\") {\r\n const partRecord = part as Record<string, unknown>;\r\n const text = partRecord.text;\r\n if (typeof text === \"string\") {\r\n partRecord.text = `${text}\\n\\n${hint}`;\r\n appended = true;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!appended) {\r\n parts.push({ text: hint });\r\n }\r\n } else {\r\n sys.parts = [{ text: hint }];\r\n }\r\n\r\n payload.systemInstruction = sys;\r\n } else if (Array.isArray(payload.contents)) {\r\n // No existing system instruction, create one\r\n payload.systemInstruction = { parts: [{ text: hint }] };\r\n }\r\n}\r\n\r\n/**\r\n * Normalize tools for Claude models.\r\n * Converts various tool formats to functionDeclarations format.\r\n * \r\n * @returns Debug info about tool normalization\r\n */\r\nexport function normalizeClaudeTools(\r\n payload: RequestPayload,\r\n cleanJSONSchema: (schema: unknown) => Record<string, unknown>,\r\n): { toolDebugMissing: number; toolDebugSummaries: string[] } {\r\n let toolDebugMissing = 0;\r\n const toolDebugSummaries: string[] = [];\r\n\r\n if (!Array.isArray(payload.tools)) {\r\n return { toolDebugMissing, toolDebugSummaries };\r\n }\r\n\r\n const functionDeclarations: unknown[] = [];\r\n const passthroughTools: unknown[] = [];\r\n\r\n const normalizeSchema = (schema: unknown): Record<string, unknown> => {\r\n const createPlaceholderSchema = (base: Record<string, unknown> = {}): Record<string, unknown> => ({\r\n ...base,\r\n type: \"object\",\r\n properties: {\r\n [EMPTY_SCHEMA_PLACEHOLDER_NAME]: {\r\n type: \"boolean\",\r\n description: EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,\r\n },\r\n },\r\n required: [EMPTY_SCHEMA_PLACEHOLDER_NAME],\r\n });\r\n\r\n if (!schema || typeof schema !== \"object\" || Array.isArray(schema)) {\r\n toolDebugMissing += 1;\r\n return createPlaceholderSchema();\r\n }\r\n\r\n const cleaned = cleanJSONSchema(schema);\r\n\r\n if (!cleaned || typeof cleaned !== \"object\" || Array.isArray(cleaned)) {\r\n toolDebugMissing += 1;\r\n return createPlaceholderSchema();\r\n }\r\n\r\n // Claude VALIDATED mode requires tool parameters to be an object schema\r\n // with at least one property.\r\n const hasProperties =\r\n cleaned.properties &&\r\n typeof cleaned.properties === \"object\" &&\r\n Object.keys(cleaned.properties as Record<string, unknown>).length > 0;\r\n\r\n cleaned.type = \"object\";\r\n\r\n if (!hasProperties) {\r\n cleaned.properties = {\r\n _placeholder: {\r\n type: \"boolean\",\r\n description: \"Placeholder. Always pass true.\",\r\n },\r\n };\r\n cleaned.required = Array.isArray(cleaned.required)\r\n ? Array.from(new Set([...(cleaned.required as string[]), \"_placeholder\"]))\r\n : [\"_placeholder\"];\r\n }\r\n\r\n return cleaned;\r\n };\r\n\r\n (payload.tools as unknown[]).forEach((tool: unknown) => {\r\n const t = tool as Record<string, unknown>;\r\n\r\n const pushDeclaration = (decl: Record<string, unknown> | undefined, source: string): void => {\r\n const schema =\r\n decl?.parameters ||\r\n decl?.parametersJsonSchema ||\r\n decl?.input_schema ||\r\n decl?.inputSchema ||\r\n t.parameters ||\r\n t.parametersJsonSchema ||\r\n t.input_schema ||\r\n t.inputSchema ||\r\n (t.function as Record<string, unknown> | undefined)?.parameters ||\r\n (t.function as Record<string, unknown> | undefined)?.parametersJsonSchema ||\r\n (t.function as Record<string, unknown> | undefined)?.input_schema ||\r\n (t.function as Record<string, unknown> | undefined)?.inputSchema ||\r\n (t.custom as Record<string, unknown> | undefined)?.parameters ||\r\n (t.custom as Record<string, unknown> | undefined)?.parametersJsonSchema ||\r\n (t.custom as Record<string, unknown> | undefined)?.input_schema;\r\n\r\n let name =\r\n decl?.name ||\r\n t.name ||\r\n (t.function as Record<string, unknown> | undefined)?.name ||\r\n (t.custom as Record<string, unknown> | undefined)?.name ||\r\n `tool-${functionDeclarations.length}`;\r\n\r\n // Sanitize tool name: must be alphanumeric with underscores, no special chars\r\n name = String(name).replace(/[^a-zA-Z0-9_-]/g, \"_\").slice(0, 64);\r\n\r\n const description =\r\n decl?.description ||\r\n t.description ||\r\n (t.function as Record<string, unknown> | undefined)?.description ||\r\n (t.custom as Record<string, unknown> | undefined)?.description ||\r\n \"\";\r\n\r\n functionDeclarations.push({\r\n name,\r\n description: String(description || \"\"),\r\n parameters: normalizeSchema(schema),\r\n });\r\n\r\n toolDebugSummaries.push(\r\n `decl=${name},src=${source},hasSchema=${schema ? \"y\" : \"n\"}`,\r\n );\r\n };\r\n\r\n // Check for functionDeclarations array first\r\n if (Array.isArray(t.functionDeclarations) && (t.functionDeclarations as unknown[]).length > 0) {\r\n (t.functionDeclarations as Record<string, unknown>[]).forEach((decl) => \r\n pushDeclaration(decl, \"functionDeclarations\")\r\n );\r\n return;\r\n }\r\n\r\n // Fall back to function/custom style definitions\r\n if (t.function || t.custom || t.parameters || t.input_schema || t.inputSchema) {\r\n pushDeclaration(\r\n (t.function as Record<string, unknown> | undefined) ?? \r\n (t.custom as Record<string, unknown> | undefined) ?? \r\n t,\r\n \"function/custom\"\r\n );\r\n return;\r\n }\r\n\r\n // Preserve any non-function tool entries (e.g., codeExecution) untouched\r\n passthroughTools.push(tool);\r\n });\r\n\r\n const finalTools: unknown[] = [];\r\n if (functionDeclarations.length > 0) {\r\n finalTools.push({ functionDeclarations });\r\n }\r\n payload.tools = finalTools.concat(passthroughTools);\r\n\r\n return { toolDebugMissing, toolDebugSummaries };\r\n}\r\n\r\n/**\r\n * Convert snake_case stop_sequences to camelCase stopSequences.\r\n */\r\nexport function convertStopSequences(\r\n generationConfig: Record<string, unknown>,\r\n): void {\r\n if (Array.isArray(generationConfig.stop_sequences)) {\r\n generationConfig.stopSequences = generationConfig.stop_sequences;\r\n delete generationConfig.stop_sequences;\r\n }\r\n}\r\n\r\n/**\r\n * Apply all Claude-specific transformations to a request payload.\r\n */\r\nexport interface ClaudeTransformOptions {\r\n /** The effective model name (resolved) */\r\n model: string;\r\n /** Tier-based thinking budget (from model suffix) */\r\n tierThinkingBudget?: number;\r\n /** Normalized thinking config from user settings */\r\n normalizedThinking?: { includeThoughts?: boolean; thinkingBudget?: number };\r\n /** Function to clean JSON schema for Antigravity */\r\n cleanJSONSchema: (schema: unknown) => Record<string, unknown>;\r\n}\r\n\r\nexport interface ClaudeTransformResult {\r\n toolDebugMissing: number;\r\n toolDebugSummaries: string[];\r\n}\r\n\r\n/**\r\n * Apply all Claude-specific transformations.\r\n */\r\nexport function applyClaudeTransforms(\r\n payload: RequestPayload,\r\n options: ClaudeTransformOptions,\r\n): ClaudeTransformResult {\r\n const { model, tierThinkingBudget, normalizedThinking, cleanJSONSchema } = options;\r\n const isThinking = isClaudeThinkingModel(model);\r\n\r\n // 1. Configure tool calling mode\r\n configureClaudeToolConfig(payload);\r\n\r\n if (payload.generationConfig) {\r\n convertStopSequences(payload.generationConfig as Record<string, unknown>);\r\n }\r\n\r\n // 2. Apply thinking config if needed\r\n if (normalizedThinking) {\r\n const thinkingBudget = tierThinkingBudget ?? normalizedThinking.thinkingBudget;\r\n \r\n if (isThinking) {\r\n const thinkingConfig = buildClaudeThinkingConfig(\r\n normalizedThinking.includeThoughts ?? true,\r\n thinkingBudget,\r\n );\r\n\r\n const generationConfig = (payload.generationConfig ?? {}) as Record<string, unknown>;\r\n generationConfig.thinkingConfig = thinkingConfig;\r\n\r\n if (typeof thinkingBudget === \"number\" && thinkingBudget > 0) {\r\n ensureClaudeMaxOutputTokens(generationConfig, thinkingBudget);\r\n }\r\n\r\n payload.generationConfig = generationConfig;\r\n }\r\n }\r\n\r\n // 3. Append interleaved thinking hint for thinking models with tools\r\n if (isThinking && Array.isArray(payload.tools) && (payload.tools as unknown[]).length > 0) {\r\n appendClaudeThinkingHint(payload);\r\n }\r\n\r\n // 4. Normalize tools\r\n return normalizeClaudeTools(payload, cleanJSONSchema);\r\n}\r\n", "/**\r\n * Gemini-specific Request Transformations\r\n * \r\n * Handles Gemini model-specific request transformations including:\r\n * - Thinking config (camelCase keys, thinkingLevel for Gemini 3)\r\n * - Tool normalization (function/custom format)\r\n * - Schema transformation (JSON Schema -> Gemini Schema format)\r\n */\r\n\r\nimport type { RequestPayload, ThinkingConfig, ThinkingTier, GoogleSearchConfig } from \"./types\";\r\n\r\n/**\r\n * Transform a JSON Schema to Gemini-compatible format.\r\n * Based on @google/genai SDK's processJsonSchema() function.\r\n * \r\n * Key transformations:\r\n * - Converts type values to uppercase (object -> OBJECT)\r\n * - Removes unsupported fields like additionalProperties, $schema\r\n * - Recursively processes nested schemas (properties, items, anyOf, etc.)\r\n * \r\n * @param schema - A JSON Schema object or primitive value\r\n * @returns Gemini-compatible schema\r\n * \r\n * Fields that Gemini API rejects and must be removed from schemas.\r\n * Antigravity uses strict protobuf-backed JSON validation.\r\n */\r\nconst UNSUPPORTED_SCHEMA_FIELDS = new Set([\r\n \"additionalProperties\",\r\n \"$schema\",\r\n \"$id\",\r\n \"$comment\",\r\n \"$ref\",\r\n \"$defs\",\r\n \"definitions\",\r\n \"const\",\r\n \"contentMediaType\",\r\n \"contentEncoding\",\r\n \"if\",\r\n \"then\",\r\n \"else\",\r\n \"not\",\r\n \"patternProperties\",\r\n \"unevaluatedProperties\",\r\n \"unevaluatedItems\",\r\n \"dependentRequired\",\r\n \"dependentSchemas\",\r\n \"propertyNames\",\r\n \"minContains\",\r\n \"maxContains\",\r\n]);\r\n\r\nexport function toGeminiSchema(schema: unknown): unknown {\r\n // Return primitives and arrays as-is\r\n if (!schema || typeof schema !== \"object\" || Array.isArray(schema)) {\r\n return schema;\r\n }\r\n\r\n const inputSchema = schema as Record<string, unknown>;\r\n const result: Record<string, unknown> = {};\r\n\r\n // First pass: collect all property names for required validation\r\n const propertyNames = new Set<string>();\r\n if (inputSchema.properties && typeof inputSchema.properties === \"object\") {\r\n for (const propName of Object.keys(inputSchema.properties as Record<string, unknown>)) {\r\n propertyNames.add(propName);\r\n }\r\n }\r\n\r\n for (const [key, value] of Object.entries(inputSchema)) {\r\n // Skip unsupported fields that Gemini API rejects\r\n if (UNSUPPORTED_SCHEMA_FIELDS.has(key)) {\r\n continue;\r\n }\r\n\r\n if (key === \"type\" && typeof value === \"string\") {\r\n // Convert type to uppercase for Gemini API\r\n result[key] = value.toUpperCase();\r\n } else if (key === \"properties\" && typeof value === \"object\" && value !== null) {\r\n // Recursively transform nested property schemas\r\n const props: Record<string, unknown> = {};\r\n for (const [propName, propSchema] of Object.entries(value as Record<string, unknown>)) {\r\n props[propName] = toGeminiSchema(propSchema);\r\n }\r\n result[key] = props;\r\n } else if (key === \"items\" && typeof value === \"object\") {\r\n // Transform array items schema\r\n result[key] = toGeminiSchema(value);\r\n } else if ((key === \"anyOf\" || key === \"oneOf\" || key === \"allOf\") && Array.isArray(value)) {\r\n // Transform union type schemas\r\n result[key] = value.map((item) => toGeminiSchema(item));\r\n } else if (key === \"enum\" && Array.isArray(value)) {\r\n // Keep enum values as-is\r\n result[key] = value;\r\n } else if (key === \"default\" || key === \"examples\") {\r\n // Keep default and examples as-is\r\n result[key] = value;\r\n } else if (key === \"required\" && Array.isArray(value)) {\r\n // Filter required array to only include properties that exist\r\n // This fixes: \"parameters.required[X]: property is not defined\"\r\n if (propertyNames.size > 0) {\r\n const validRequired = value.filter((prop) =>\r\n typeof prop === \"string\" && propertyNames.has(prop)\r\n );\r\n if (validRequired.length > 0) {\r\n result[key] = validRequired;\r\n }\r\n // If no valid required properties, omit the required field entirely\r\n } else {\r\n // If there are no properties, keep required as-is (might be a schema without properties)\r\n result[key] = value;\r\n }\r\n } else {\r\n result[key] = value;\r\n }\r\n }\r\n\r\n // Issue #80: Ensure array schemas have an 'items' field\r\n // Gemini API requires: \"parameters.properties[X].items: missing field\"\r\n if (result.type === \"ARRAY\" && !result.items) {\r\n result.items = { type: \"STRING\" };\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Check if a model is a Gemini model (not Claude).\r\n */\r\nexport function isGeminiModel(model: string): boolean {\r\n const lower = model.toLowerCase();\r\n return lower.includes(\"gemini\") && !lower.includes(\"claude\");\r\n}\r\n\r\n/**\r\n * Check if a model is Gemini 3 (uses thinkingLevel string).\r\n */\r\nexport function isGemini3Model(model: string): boolean {\r\n return model.toLowerCase().includes(\"gemini-3\");\r\n}\r\n\r\n/**\r\n * Check if a model is Gemini 2.5 (uses numeric thinkingBudget).\r\n */\r\nexport function isGemini25Model(model: string): boolean {\r\n return model.toLowerCase().includes(\"gemini-2.5\");\r\n}\r\n\r\n/**\r\n * Check if a model is an image generation model.\r\n * Image models don't support thinking and require imageConfig.\r\n */\r\nexport function isImageGenerationModel(model: string): boolean {\r\n const lower = model.toLowerCase();\r\n return (\r\n lower.includes(\"image\") ||\r\n lower.includes(\"imagen\")\r\n );\r\n}\r\n\r\n/**\r\n * Build Gemini 3 thinking config with thinkingLevel string.\r\n */\r\nexport function buildGemini3ThinkingConfig(\r\n includeThoughts: boolean,\r\n thinkingLevel: ThinkingTier,\r\n): ThinkingConfig {\r\n return {\r\n includeThoughts,\r\n thinkingLevel,\r\n };\r\n}\r\n\r\n/**\r\n * Build Gemini 2.5 thinking config with numeric thinkingBudget.\r\n */\r\nexport function buildGemini25ThinkingConfig(\r\n includeThoughts: boolean,\r\n thinkingBudget?: number,\r\n): ThinkingConfig {\r\n return {\r\n includeThoughts,\r\n ...(typeof thinkingBudget === \"number\" && thinkingBudget > 0 ? { thinkingBudget } : {}),\r\n };\r\n}\r\n\r\n/**\r\n * Image generation config for Gemini image models.\r\n * \r\n * Supported aspect ratios: \"1:1\", \"2:3\", \"3:2\", \"3:4\", \"4:3\", \"4:5\", \"5:4\", \"9:16\", \"16:9\", \"21:9\"\r\n */\r\nexport interface ImageConfig {\r\n aspectRatio?: string;\r\n}\r\n\r\n/**\r\n * Valid aspect ratios for image generation.\r\n */\r\nconst VALID_ASPECT_RATIOS = [\"1:1\", \"2:3\", \"3:2\", \"3:4\", \"4:3\", \"4:5\", \"5:4\", \"9:16\", \"16:9\", \"21:9\"];\r\n\r\n/**\r\n * Build image generation config for Gemini image models.\r\n * \r\n * Configuration is read from environment variables:\r\n * - OPENCODE_IMAGE_ASPECT_RATIO: Aspect ratio (e.g., \"16:9\", \"4:3\")\r\n * \r\n * Defaults to 1:1 aspect ratio if not specified.\r\n * \r\n * Note: Resolution setting is not currently supported by the Antigravity API.\r\n */\r\nexport function buildImageGenerationConfig(): ImageConfig {\r\n // Read aspect ratio from environment or default to 1:1\r\n const aspectRatio = process.env.OPENCODE_IMAGE_ASPECT_RATIO || \"1:1\";\r\n\r\n if (VALID_ASPECT_RATIOS.includes(aspectRatio)) {\r\n return { aspectRatio };\r\n }\r\n\r\n console.warn(`[gemini] Invalid aspect ratio \"${aspectRatio}\". Using default \"1:1\". Valid values: ${VALID_ASPECT_RATIOS.join(\", \")}`);\r\n\r\n // Default to 1:1 square aspect ratio\r\n return { aspectRatio: \"1:1\" };\r\n}\r\n\r\n/**\r\n * Normalize tools for Gemini models.\r\n * Ensures tools have proper function-style format.\r\n * \r\n * @returns Debug info about tool normalization\r\n */\r\nexport function normalizeGeminiTools(\r\n payload: RequestPayload,\r\n): { toolDebugMissing: number; toolDebugSummaries: string[] } {\r\n let toolDebugMissing = 0;\r\n const toolDebugSummaries: string[] = [];\r\n\r\n if (!Array.isArray(payload.tools)) {\r\n return { toolDebugMissing, toolDebugSummaries };\r\n }\r\n\r\n payload.tools = (payload.tools as unknown[]).map((tool: unknown, toolIndex: number) => {\r\n const t = tool as Record<string, unknown>;\r\n\r\n // Skip normalization for Google Search tools (both old and new API)\r\n if (t.googleSearch || t.googleSearchRetrieval) {\r\n return t;\r\n }\r\n\r\n const newTool = { ...t };\r\n\r\n const schemaCandidates = [\r\n (newTool.function as Record<string, unknown> | undefined)?.input_schema,\r\n (newTool.function as Record<string, unknown> | undefined)?.parameters,\r\n (newTool.function as Record<string, unknown> | undefined)?.inputSchema,\r\n (newTool.custom as Record<string, unknown> | undefined)?.input_schema,\r\n (newTool.custom as Record<string, unknown> | undefined)?.parameters,\r\n newTool.parameters,\r\n newTool.input_schema,\r\n newTool.inputSchema,\r\n ].filter(Boolean);\r\n\r\n const placeholderSchema: Record<string, unknown> = {\r\n type: \"OBJECT\",\r\n properties: {\r\n _placeholder: {\r\n type: \"BOOLEAN\",\r\n description: \"Placeholder. Always pass true.\",\r\n },\r\n },\r\n required: [\"_placeholder\"],\r\n };\r\n\r\n let schema = schemaCandidates[0] as Record<string, unknown> | undefined;\r\n const schemaObjectOk = schema && typeof schema === \"object\" && !Array.isArray(schema);\r\n if (!schemaObjectOk) {\r\n schema = placeholderSchema;\r\n toolDebugMissing += 1;\r\n } else {\r\n // Transform existing schema to Gemini-compatible format\r\n schema = toGeminiSchema(schema) as Record<string, unknown>;\r\n }\r\n\r\n const nameCandidate =\r\n newTool.name ||\r\n (newTool.function as Record<string, unknown> | undefined)?.name ||\r\n (newTool.custom as Record<string, unknown> | undefined)?.name ||\r\n `tool-${toolIndex}`;\r\n\r\n // Always update function.input_schema with transformed schema\r\n if (newTool.function && schema) {\r\n (newTool.function as Record<string, unknown>).input_schema = schema;\r\n }\r\n\r\n // Always update custom.input_schema with transformed schema\r\n if (newTool.custom && schema) {\r\n (newTool.custom as Record<string, unknown>).input_schema = schema;\r\n }\r\n\r\n // Create custom from function if missing\r\n if (!newTool.custom && newTool.function) {\r\n const fn = newTool.function as Record<string, unknown>;\r\n newTool.custom = {\r\n name: fn.name || nameCandidate,\r\n description: fn.description,\r\n input_schema: schema,\r\n };\r\n }\r\n\r\n // Create custom if both missing\r\n if (!newTool.custom && !newTool.function) {\r\n newTool.custom = {\r\n name: nameCandidate,\r\n description: newTool.description,\r\n input_schema: schema,\r\n };\r\n\r\n if (!newTool.parameters && !newTool.input_schema && !newTool.inputSchema) {\r\n newTool.parameters = schema;\r\n }\r\n }\r\n\r\n if (newTool.custom && !(newTool.custom as Record<string, unknown>).input_schema) {\r\n (newTool.custom as Record<string, unknown>).input_schema = {\r\n type: \"OBJECT\",\r\n properties: {},\r\n };\r\n toolDebugMissing += 1;\r\n }\r\n\r\n toolDebugSummaries.push(\r\n `idx=${toolIndex}, hasCustom=${!!newTool.custom}, customSchema=${!!(newTool.custom as Record<string, unknown> | undefined)?.input_schema}, hasFunction=${!!newTool.function}, functionSchema=${!!(newTool.function as Record<string, unknown> | undefined)?.input_schema}`,\r\n );\r\n\r\n // Strip custom wrappers for Gemini; only function-style is accepted.\r\n if (newTool.custom) {\r\n delete newTool.custom;\r\n }\r\n\r\n return newTool;\r\n });\r\n\r\n return { toolDebugMissing, toolDebugSummaries };\r\n}\r\n\r\n/**\r\n * Apply all Gemini-specific transformations to a request payload.\r\n */\r\nexport interface GeminiTransformOptions {\r\n /** The effective model name (resolved) */\r\n model: string;\r\n /** Tier-based thinking budget (from model suffix, for Gemini 2.5) */\r\n tierThinkingBudget?: number;\r\n /** Tier-based thinking level (from model suffix, for Gemini 3) */\r\n tierThinkingLevel?: ThinkingTier;\r\n /** Normalized thinking config from user settings */\r\n normalizedThinking?: { includeThoughts?: boolean; thinkingBudget?: number };\r\n /** Google Search configuration */\r\n googleSearch?: GoogleSearchConfig;\r\n}\r\n\r\nexport interface GeminiTransformResult {\r\n toolDebugMissing: number;\r\n toolDebugSummaries: string[];\r\n /** Number of function declarations after wrapping */\r\n wrappedFunctionCount: number;\r\n /** Number of passthrough tools (googleSearch, googleSearchRetrieval, codeExecution) */\r\n passthroughToolCount: number;\r\n}\r\n\r\n/**\r\n * Apply all Gemini-specific transformations.\r\n */\r\nexport function applyGeminiTransforms(\r\n payload: RequestPayload,\r\n options: GeminiTransformOptions,\r\n): GeminiTransformResult {\r\n const { model, tierThinkingBudget, tierThinkingLevel, normalizedThinking, googleSearch } = options;\r\n\r\n // 1. Apply thinking config if needed\r\n if (normalizedThinking) {\r\n let thinkingConfig: ThinkingConfig;\r\n\r\n if (tierThinkingLevel && isGemini3Model(model)) {\r\n // Gemini 3 uses thinkingLevel string\r\n thinkingConfig = buildGemini3ThinkingConfig(\r\n normalizedThinking.includeThoughts ?? true,\r\n tierThinkingLevel,\r\n );\r\n } else {\r\n // Gemini 2.5 and others use numeric budget\r\n const thinkingBudget = tierThinkingBudget ?? normalizedThinking.thinkingBudget;\r\n thinkingConfig = buildGemini25ThinkingConfig(\r\n normalizedThinking.includeThoughts ?? true,\r\n thinkingBudget,\r\n );\r\n }\r\n\r\n const generationConfig = (payload.generationConfig ?? {}) as Record<string, unknown>;\r\n generationConfig.thinkingConfig = thinkingConfig;\r\n payload.generationConfig = generationConfig;\r\n }\r\n\r\n // 2. Apply Google Search (Grounding) if enabled\r\n // Uses the new googleSearch API for Gemini 2.0+ / Gemini 3 models\r\n // Note: The old googleSearchRetrieval with dynamicRetrievalConfig is deprecated\r\n // The new API doesn't support threshold - the model decides when to search automatically\r\n if (googleSearch && googleSearch.mode === 'auto') {\r\n const tools = (payload.tools as unknown[]) || [];\r\n if (!payload.tools) {\r\n payload.tools = tools;\r\n }\r\n\r\n // Add Google Search tool using new API format for Gemini 2.0+\r\n // See: https://ai.google.dev/gemini-api/docs/grounding\r\n (payload.tools as any[]).push({\r\n googleSearch: {},\r\n });\r\n }\r\n\r\n // 3. Normalize tools\r\n const result = normalizeGeminiTools(payload);\r\n\r\n // 4. Wrap tools in functionDeclarations format (fixes #203, #206)\r\n // Antigravity strict protobuf validation rejects wrapper-level 'parameters' field\r\n // Must be: [{ functionDeclarations: [{ name, description, parameters }] }]\r\n const wrapResult = wrapToolsAsFunctionDeclarations(payload);\r\n\r\n return {\r\n ...result,\r\n wrappedFunctionCount: wrapResult.wrappedFunctionCount,\r\n passthroughToolCount: wrapResult.passthroughToolCount,\r\n };\r\n}\r\n\r\nexport interface WrapToolsResult {\r\n wrappedFunctionCount: number;\r\n passthroughToolCount: number;\r\n}\r\n\r\n/**\r\n * Wrap tools array in Gemini's required functionDeclarations format.\r\n * \r\n * Gemini/Antigravity API expects:\r\n * { tools: [{ functionDeclarations: [{ name, description, parameters }] }] }\r\n * \r\n * NOT:\r\n * { tools: [{ function: {...}, parameters: {...} }] }\r\n * \r\n * The wrapper-level 'parameters' field causes:\r\n * \"Unknown name 'parameters' at 'request.tools[0]'\"\r\n */\r\n/**\r\n * Detect if a tool is a web search tool in any of the supported formats:\r\n * - Claude/Anthropic: { type: \"web_search_20250305\" } or { name: \"web_search\" }\r\n * - Gemini native: { googleSearch: {} } or { googleSearchRetrieval: {} }\r\n */\r\nfunction isWebSearchTool(tool: Record<string, unknown>): boolean {\r\n // 1. Gemini native format\r\n if (tool.googleSearch || tool.googleSearchRetrieval) {\r\n return true;\r\n }\r\n\r\n // 2. Claude/Anthropic format: { type: \"web_search_20250305\" }\r\n if (tool.type === \"web_search_20250305\") {\r\n return true;\r\n }\r\n\r\n // 3. Simple name-based format: { name: \"web_search\" | \"google_search\" }\r\n const name = tool.name as string | undefined;\r\n if (name === \"web_search\" || name === \"google_search\") {\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\nexport function wrapToolsAsFunctionDeclarations(payload: RequestPayload): WrapToolsResult {\r\n if (!Array.isArray(payload.tools) || payload.tools.length === 0) {\r\n return { wrappedFunctionCount: 0, passthroughToolCount: 0 };\r\n }\r\n\r\n const functionDeclarations: Array<{\r\n name: string;\r\n description: string;\r\n parameters: Record<string, unknown>;\r\n }> = [];\r\n\r\n const passthroughTools: unknown[] = [];\r\n let hasWebSearchTool = false;\r\n\r\n for (const tool of payload.tools as Array<Record<string, unknown>>) {\r\n // Handle passthrough tools (Google Search and Code Execution)\r\n if (tool.googleSearch || tool.googleSearchRetrieval || tool.codeExecution) {\r\n passthroughTools.push(tool);\r\n continue;\r\n }\r\n\r\n // Detect and convert web search tools to Gemini format\r\n if (isWebSearchTool(tool)) {\r\n hasWebSearchTool = true;\r\n continue; // Will be added as { googleSearch: {} } at the end\r\n }\r\n\r\n if (tool.functionDeclarations) {\r\n if (Array.isArray(tool.functionDeclarations)) {\r\n for (const decl of tool.functionDeclarations as Array<Record<string, unknown>>) {\r\n functionDeclarations.push({\r\n name: String(decl.name || `tool-${functionDeclarations.length}`),\r\n description: String(decl.description || \"\"),\r\n parameters: (decl.parameters as Record<string, unknown>) || { type: \"OBJECT\", properties: {} },\r\n });\r\n }\r\n }\r\n continue;\r\n }\r\n\r\n const fn = tool.function as Record<string, unknown> | undefined;\r\n const custom = tool.custom as Record<string, unknown> | undefined;\r\n\r\n const name = String(\r\n tool.name ||\r\n fn?.name ||\r\n custom?.name ||\r\n `tool-${functionDeclarations.length}`\r\n );\r\n\r\n const description = String(\r\n tool.description ||\r\n fn?.description ||\r\n custom?.description ||\r\n \"\"\r\n );\r\n\r\n const schema = (\r\n fn?.input_schema ||\r\n fn?.parameters ||\r\n fn?.inputSchema ||\r\n custom?.input_schema ||\r\n custom?.parameters ||\r\n tool.parameters ||\r\n tool.input_schema ||\r\n tool.inputSchema ||\r\n { type: \"OBJECT\", properties: {} }\r\n ) as Record<string, unknown>;\r\n\r\n functionDeclarations.push({\r\n name,\r\n description,\r\n parameters: schema,\r\n });\r\n }\r\n\r\n const finalTools: unknown[] = [];\r\n\r\n if (functionDeclarations.length > 0) {\r\n finalTools.push({ functionDeclarations });\r\n }\r\n\r\n finalTools.push(...passthroughTools);\r\n\r\n // Add googleSearch tool if a web search tool was detected\r\n // Note: googleSearch cannot be combined with functionDeclarations in the same request\r\n // If there are function declarations, we skip adding googleSearch (Gemini API limitation)\r\n if (hasWebSearchTool && functionDeclarations.length === 0) {\r\n finalTools.push({ googleSearch: {} });\r\n } else if (hasWebSearchTool && functionDeclarations.length > 0) {\r\n // Log warning: web search requested but can't be used with functions\r\n console.warn(\r\n \"[gemini] web_search tool detected but cannot be combined with function declarations. \" +\r\n \"Use the explicit google_search() tool call instead.\"\r\n );\r\n }\r\n\r\n payload.tools = finalTools;\r\n\r\n return {\r\n wrappedFunctionCount: functionDeclarations.length,\r\n passthroughToolCount: passthroughTools.length + (hasWebSearchTool && functionDeclarations.length === 0 ? 1 : 0),\r\n };\r\n}\r\n", "/**\r\n * Cross-Model Metadata Sanitization\r\n *\r\n * Fixes: \"Invalid `signature` in `thinking` block\" error when switching models mid-session.\r\n * \r\n * Root cause: Gemini stores thoughtSignature in metadata.google, Claude stores signature\r\n * in top-level thinking blocks. Foreign signatures fail validation on the target model.\r\n */\r\n\r\nimport { isClaudeModel } from \"./claude\";\r\nimport { isGeminiModel } from \"./gemini\";\r\n\r\nexport type ModelFamily = \"claude\" | \"gemini\" | \"unknown\";\r\n\r\nexport interface SanitizerOptions {\r\n targetModel: string;\r\n sourceModel?: string;\r\n preserveNonSignatureMetadata?: boolean;\r\n}\r\n\r\nexport interface SanitizationResult {\r\n payload: unknown;\r\n modified: boolean;\r\n signaturesStripped: number;\r\n}\r\n\r\nconst GEMINI_SIGNATURE_FIELDS = [\"thoughtSignature\", \"thinkingMetadata\"] as const;\r\nconst CLAUDE_SIGNATURE_FIELDS = [\"signature\"] as const;\r\n\r\nexport function getModelFamily(model: string): ModelFamily {\r\n if (isClaudeModel(model)) return \"claude\";\r\n if (isGeminiModel(model)) return \"gemini\";\r\n return \"unknown\";\r\n}\r\n\r\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\nexport function stripGeminiThinkingMetadata(\r\n part: Record<string, unknown>,\r\n preserveNonSignature = true\r\n): { part: Record<string, unknown>; stripped: number } {\r\n let stripped = 0;\r\n\r\n if (\"thoughtSignature\" in part) {\r\n delete part.thoughtSignature;\r\n stripped++;\r\n }\r\n\r\n if (\"thinkingMetadata\" in part) {\r\n delete part.thinkingMetadata;\r\n stripped++;\r\n }\r\n\r\n if (isPlainObject(part.metadata)) {\r\n const metadata = part.metadata as Record<string, unknown>;\r\n if (isPlainObject(metadata.google)) {\r\n const google = metadata.google as Record<string, unknown>;\r\n\r\n for (const field of GEMINI_SIGNATURE_FIELDS) {\r\n if (field in google) {\r\n delete google[field];\r\n stripped++;\r\n }\r\n }\r\n\r\n if (!preserveNonSignature || Object.keys(google).length === 0) {\r\n delete metadata.google;\r\n }\r\n\r\n if (Object.keys(metadata).length === 0) {\r\n delete part.metadata;\r\n }\r\n }\r\n }\r\n\r\n return { part, stripped };\r\n}\r\n\r\nexport function stripClaudeThinkingFields(\r\n part: Record<string, unknown>\r\n): { part: Record<string, unknown>; stripped: number } {\r\n let stripped = 0;\r\n\r\n if (part.type === \"thinking\" || part.type === \"redacted_thinking\") {\r\n for (const field of CLAUDE_SIGNATURE_FIELDS) {\r\n if (field in part) {\r\n delete part[field];\r\n stripped++;\r\n }\r\n }\r\n }\r\n\r\n if (\"signature\" in part && typeof part.signature === \"string\") {\r\n if ((part.signature as string).length >= 50) {\r\n delete part.signature;\r\n stripped++;\r\n }\r\n }\r\n\r\n return { part, stripped };\r\n}\r\n\r\nfunction sanitizePart(\r\n part: unknown,\r\n targetFamily: ModelFamily,\r\n preserveNonSignature: boolean\r\n): { part: unknown; stripped: number } {\r\n if (!isPlainObject(part)) {\r\n return { part, stripped: 0 };\r\n }\r\n\r\n let totalStripped = 0;\r\n const partObj = { ...part } as Record<string, unknown>;\r\n\r\n if (targetFamily === \"claude\") {\r\n const result = stripGeminiThinkingMetadata(partObj, preserveNonSignature);\r\n totalStripped += result.stripped;\r\n } else if (targetFamily === \"gemini\") {\r\n const result = stripClaudeThinkingFields(partObj);\r\n totalStripped += result.stripped;\r\n }\r\n\r\n return { part: partObj, stripped: totalStripped };\r\n}\r\n\r\nfunction sanitizeParts(\r\n parts: unknown[],\r\n targetFamily: ModelFamily,\r\n preserveNonSignature: boolean\r\n): { parts: unknown[]; stripped: number } {\r\n let totalStripped = 0;\r\n\r\n const sanitizedParts = parts.map((part) => {\r\n const result = sanitizePart(part, targetFamily, preserveNonSignature);\r\n totalStripped += result.stripped;\r\n return result.part;\r\n });\r\n\r\n return { parts: sanitizedParts, stripped: totalStripped };\r\n}\r\n\r\nfunction sanitizeContents(\r\n contents: unknown[],\r\n targetFamily: ModelFamily,\r\n preserveNonSignature: boolean\r\n): { contents: unknown[]; stripped: number } {\r\n let totalStripped = 0;\r\n\r\n const sanitizedContents = contents.map((content) => {\r\n if (!isPlainObject(content)) return content;\r\n\r\n const contentObj = { ...content } as Record<string, unknown>;\r\n\r\n if (Array.isArray(contentObj.parts)) {\r\n const result = sanitizeParts(\r\n contentObj.parts,\r\n targetFamily,\r\n preserveNonSignature\r\n );\r\n contentObj.parts = result.parts;\r\n totalStripped += result.stripped;\r\n }\r\n\r\n return contentObj;\r\n });\r\n\r\n return { contents: sanitizedContents, stripped: totalStripped };\r\n}\r\n\r\nfunction sanitizeMessages(\r\n messages: unknown[],\r\n targetFamily: ModelFamily,\r\n preserveNonSignature: boolean\r\n): { messages: unknown[]; stripped: number } {\r\n let totalStripped = 0;\r\n\r\n const sanitizedMessages = messages.map((message) => {\r\n if (!isPlainObject(message)) return message;\r\n\r\n const messageObj = { ...message } as Record<string, unknown>;\r\n\r\n if (Array.isArray(messageObj.content)) {\r\n const result = sanitizeParts(\r\n messageObj.content,\r\n targetFamily,\r\n preserveNonSignature\r\n );\r\n messageObj.content = result.parts;\r\n totalStripped += result.stripped;\r\n }\r\n\r\n return messageObj;\r\n });\r\n\r\n return { messages: sanitizedMessages, stripped: totalStripped };\r\n}\r\n\r\nexport function deepSanitizeCrossModelMetadata(\r\n obj: unknown,\r\n targetFamily: ModelFamily,\r\n preserveNonSignature = true\r\n): { obj: unknown; stripped: number } {\r\n if (!isPlainObject(obj)) {\r\n return { obj, stripped: 0 };\r\n }\r\n\r\n let totalStripped = 0;\r\n const result = { ...obj } as Record<string, unknown>;\r\n\r\n if (Array.isArray(result.contents)) {\r\n const sanitized = sanitizeContents(\r\n result.contents,\r\n targetFamily,\r\n preserveNonSignature\r\n );\r\n result.contents = sanitized.contents;\r\n totalStripped += sanitized.stripped;\r\n }\r\n\r\n if (Array.isArray(result.messages)) {\r\n const sanitized = sanitizeMessages(\r\n result.messages,\r\n targetFamily,\r\n preserveNonSignature\r\n );\r\n result.messages = sanitized.messages;\r\n totalStripped += sanitized.stripped;\r\n }\r\n\r\n if (isPlainObject(result.extra_body)) {\r\n const extraBody = { ...result.extra_body } as Record<string, unknown>;\r\n if (Array.isArray(extraBody.messages)) {\r\n const sanitized = sanitizeMessages(\r\n extraBody.messages,\r\n targetFamily,\r\n preserveNonSignature\r\n );\r\n extraBody.messages = sanitized.messages;\r\n totalStripped += sanitized.stripped;\r\n }\r\n result.extra_body = extraBody;\r\n }\r\n\r\n if (Array.isArray(result.requests)) {\r\n const sanitizedRequests = result.requests.map((req) => {\r\n const sanitized = deepSanitizeCrossModelMetadata(\r\n req,\r\n targetFamily,\r\n preserveNonSignature\r\n );\r\n totalStripped += sanitized.stripped;\r\n return sanitized.obj;\r\n });\r\n result.requests = sanitizedRequests;\r\n }\r\n\r\n return { obj: result, stripped: totalStripped };\r\n}\r\n\r\nexport function sanitizeCrossModelPayload(\r\n payload: unknown,\r\n options: SanitizerOptions\r\n): SanitizationResult {\r\n const targetFamily = getModelFamily(options.targetModel);\r\n\r\n if (targetFamily === \"unknown\") {\r\n return {\r\n payload,\r\n modified: false,\r\n signaturesStripped: 0,\r\n };\r\n }\r\n\r\n const preserveNonSignature = options.preserveNonSignatureMetadata ?? true;\r\n const result = deepSanitizeCrossModelMetadata(\r\n payload,\r\n targetFamily,\r\n preserveNonSignature\r\n );\r\n\r\n return {\r\n payload: result.obj,\r\n modified: result.stripped > 0,\r\n signaturesStripped: result.stripped,\r\n };\r\n}\r\n\r\nexport function sanitizeCrossModelPayloadInPlace(\r\n payload: Record<string, unknown>,\r\n options: SanitizerOptions\r\n): number {\r\n const targetFamily = getModelFamily(options.targetModel);\r\n\r\n if (targetFamily === \"unknown\") {\r\n return 0;\r\n }\r\n\r\n const preserveNonSignature = options.preserveNonSignatureMetadata ?? true;\r\n let totalStripped = 0;\r\n\r\n const sanitizePartsInPlace = (parts: unknown[]): void => {\r\n for (const part of parts) {\r\n if (!isPlainObject(part)) continue;\r\n\r\n if (targetFamily === \"claude\") {\r\n const result = stripGeminiThinkingMetadata(\r\n part as Record<string, unknown>,\r\n preserveNonSignature\r\n );\r\n totalStripped += result.stripped;\r\n } else if (targetFamily === \"gemini\") {\r\n const result = stripClaudeThinkingFields(\r\n part as Record<string, unknown>\r\n );\r\n totalStripped += result.stripped;\r\n }\r\n }\r\n };\r\n\r\n if (Array.isArray(payload.contents)) {\r\n for (const content of payload.contents) {\r\n if (isPlainObject(content) && Array.isArray(content.parts)) {\r\n sanitizePartsInPlace(content.parts);\r\n }\r\n }\r\n }\r\n\r\n if (Array.isArray(payload.messages)) {\r\n for (const message of payload.messages) {\r\n if (isPlainObject(message) && Array.isArray(message.content)) {\r\n sanitizePartsInPlace(message.content);\r\n }\r\n }\r\n }\r\n\r\n if (isPlainObject(payload.extra_body)) {\r\n const extraBody = payload.extra_body as Record<string, unknown>;\r\n if (Array.isArray(extraBody.messages)) {\r\n for (const message of extraBody.messages) {\r\n if (isPlainObject(message) && Array.isArray(message.content)) {\r\n sanitizePartsInPlace(message.content);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return totalStripped;\r\n}\r\n", "/**\r\n * Model Resolution with Thinking Tier Support\r\n * \r\n * Resolves model names with tier suffixes (e.g., gemini-3-pro-high, claude-opus-4-6-thinking-low)\r\n * to their actual API model names and corresponding thinking configurations.\r\n */\r\n\r\nimport type { ResolvedModel, ThinkingTier, GoogleSearchConfig } from \"./types\";\r\n\r\nexport interface ModelResolverOptions {\r\n cli_first?: boolean;\r\n}\r\n\r\n/**\r\n * Thinking tier budgets by model family.\r\n * Claude and Gemini 2.5 Pro use numeric budgets.\r\n */\r\nexport const THINKING_TIER_BUDGETS = {\r\n claude: { low: 8192, medium: 16384, high: 32768 },\r\n \"gemini-2.5-pro\": { low: 8192, medium: 16384, high: 32768 },\r\n \"gemini-2.5-flash\": { low: 6144, medium: 12288, high: 24576 },\r\n default: { low: 4096, medium: 8192, high: 16384 },\r\n} as const;\r\n\r\n/**\r\n * Gemini 3 uses thinkingLevel strings instead of numeric budgets.\r\n * Flash supports: minimal, low, medium, high\r\n * Pro supports: low, high (no minimal/medium)\r\n */\r\nexport const GEMINI_3_THINKING_LEVELS = [\"minimal\", \"low\", \"medium\", \"high\"] as const;\r\n\r\n/**\r\n * Model aliases - maps user-friendly names to API model names.\r\n * \r\n * Format:\r\n * - Gemini 3 Pro variants: gemini-3-pro-{low,medium,high}\r\n * - Claude thinking variants: claude-{model}-thinking-{low,medium,high}\r\n * - Claude non-thinking: claude-{model} (no -thinking suffix)\r\n */\r\nexport const MODEL_ALIASES: Record<string, string> = {\r\n // Gemini 3 variants - for Gemini CLI only (tier stripped, thinkingLevel used)\r\n // For Antigravity, these are bypassed and full model name is kept\r\n \"gemini-3-pro-low\": \"gemini-3-pro\",\r\n \"gemini-3-pro-high\": \"gemini-3-pro\",\r\n \"gemini-3.1-pro-low\": \"gemini-3.1-pro\",\r\n \"gemini-3.1-pro-high\": \"gemini-3.1-pro\",\r\n \"gemini-3-flash-low\": \"gemini-3-flash\",\r\n \"gemini-3-flash-medium\": \"gemini-3-flash\",\r\n \"gemini-3-flash-high\": \"gemini-3-flash\",\r\n\r\n // Claude proxy names (gemini- prefix for compatibility)\r\n \"gemini-claude-opus-4-6-thinking-low\": \"claude-opus-4-6-thinking\",\r\n \"gemini-claude-opus-4-6-thinking-medium\": \"claude-opus-4-6-thinking\",\r\n \"gemini-claude-opus-4-6-thinking-high\": \"claude-opus-4-6-thinking\",\r\n \"gemini-claude-sonnet-4-6\": \"claude-sonnet-4-6\",\r\n\r\n // Image generation models - only gemini-3-pro-image is available via Antigravity API\r\n // Note: gemini-2.5-flash-image (Nano Banana) is NOT supported by Antigravity - only Google AI API\r\n // Reference: Antigravity-Manager/src-tauri/src/proxy/common/model_mapping.rs\r\n};\r\n\r\nconst TIER_REGEX = /-(minimal|low|medium|high)$/;\r\nconst QUOTA_PREFIX_REGEX = /^antigravity-/i;\r\nconst GEMINI_3_PRO_REGEX = /^gemini-3(?:\\.\\d+)?-pro/i;\r\nconst GEMINI_3_FLASH_REGEX = /^gemini-3(?:\\.\\d+)?-flash/i;\r\n\r\n// ANTIGRAVITY_ONLY_MODELS removed - all models now default to antigravity\r\n\r\n/**\r\n * Image generation models - always route to Antigravity.\r\n * These models don't support thinking and require imageConfig.\r\n */\r\nconst IMAGE_GENERATION_MODELS = /image|imagen/i;\r\n\r\n// Legacy LEGACY_ANTIGRAVITY_GEMINI3 regex removed - all Gemini models now default to antigravity\r\n\r\n/**\r\n * Models that support thinking tier suffixes.\r\n * Only these models should have -low/-medium/-high stripped as thinking tiers.\r\n * GPT models like gpt-oss-120b-medium should NOT have -medium stripped.\r\n */\r\nfunction supportsThinkingTiers(model: string): boolean {\r\n const lower = model.toLowerCase();\r\n return (\r\n lower.includes(\"gemini-3\") ||\r\n lower.includes(\"gemini-2.5\") ||\r\n (lower.includes(\"claude\") && lower.includes(\"thinking\"))\r\n );\r\n}\r\n\r\n/**\r\n * Extracts thinking tier from model name suffix.\r\n * Only extracts tier for models that support thinking tiers.\r\n */\r\nfunction extractThinkingTierFromModel(model: string): ThinkingTier | undefined {\r\n // Only extract tier for models that support thinking tiers\r\n if (!supportsThinkingTiers(model)) {\r\n return undefined;\r\n }\r\n const tierMatch = model.match(TIER_REGEX);\r\n return tierMatch?.[1] as ThinkingTier | undefined;\r\n}\r\n\r\n/**\r\n * Determines the budget family for a model.\r\n */\r\nfunction getBudgetFamily(model: string): keyof typeof THINKING_TIER_BUDGETS {\r\n if (model.includes(\"claude\")) {\r\n return \"claude\";\r\n }\r\n if (model.includes(\"gemini-2.5-pro\")) {\r\n return \"gemini-2.5-pro\";\r\n }\r\n if (model.includes(\"gemini-2.5-flash\")) {\r\n return \"gemini-2.5-flash\";\r\n }\r\n return \"default\";\r\n}\r\n\r\n/**\r\n * Checks if a model is a thinking-capable model.\r\n */\r\nfunction isThinkingCapableModel(model: string): boolean {\r\n const lower = model.toLowerCase();\r\n return (\r\n lower.includes(\"thinking\") ||\r\n lower.includes(\"gemini-3\") ||\r\n lower.includes(\"gemini-2.5\")\r\n );\r\n}\r\n\r\nfunction isGemini3ProModel(model: string): boolean {\r\n return GEMINI_3_PRO_REGEX.test(model);\r\n}\r\n\r\nfunction isGemini3FlashModel(model: string): boolean {\r\n return GEMINI_3_FLASH_REGEX.test(model);\r\n}\r\n\r\n/**\r\n * Resolves a model name with optional tier suffix and quota prefix to its actual API model name\r\n * and corresponding thinking configuration.\r\n *\r\n * Quota routing:\r\n * - Default to Antigravity quota unless cli_first is enabled for Gemini models\r\n * - Fallback to Gemini CLI happens at account rotation level when Antigravity is exhausted\r\n * - \"antigravity-\" prefix marks explicit quota (no fallback allowed)\r\n * - Claude and image models always use Antigravity\r\n *\r\n * Examples:\r\n * - \"gemini-2.5-flash\" \u2192 { quotaPreference: \"antigravity\" }\r\n * - \"gemini-3-pro-preview\" \u2192 { quotaPreference: \"antigravity\" }\r\n * - \"antigravity-gemini-3-pro-high\" \u2192 { quotaPreference: \"antigravity\", explicitQuota: true }\r\n * - \"claude-opus-4-6-thinking-medium\" \u2192 { quotaPreference: \"antigravity\" }\r\n *\r\n * @param requestedModel - The model name from the request\r\n * @param options - Optional configuration including cli_first preference\r\n * @returns Resolved model with thinking configuration\r\n */\r\nexport function resolveModelWithTier(requestedModel: string, options: ModelResolverOptions = {}): ResolvedModel {\r\n const isAntigravity = QUOTA_PREFIX_REGEX.test(requestedModel);\r\n const modelWithoutQuota = requestedModel.replace(QUOTA_PREFIX_REGEX, \"\");\r\n\r\n const tier = extractThinkingTierFromModel(modelWithoutQuota);\r\n const baseName = tier ? modelWithoutQuota.replace(TIER_REGEX, \"\") : modelWithoutQuota;\r\n\r\n const isImageModel = IMAGE_GENERATION_MODELS.test(modelWithoutQuota);\r\n const isClaudeModel = modelWithoutQuota.toLowerCase().includes(\"claude\");\r\n \r\n // All models default to Antigravity quota unless cli_first is enabled\r\n // Fallback to gemini-cli happens at the account rotation level when Antigravity is exhausted\r\n const preferGeminiCli = options.cli_first === true && !isAntigravity && !isImageModel && !isClaudeModel;\r\n const quotaPreference = preferGeminiCli ? \"gemini-cli\" as const : \"antigravity\" as const;\r\n const explicitQuota = isAntigravity || isImageModel;\r\n\r\n const isGemini3 = modelWithoutQuota.toLowerCase().startsWith(\"gemini-3\");\r\n const skipAlias = isAntigravity && isGemini3;\r\n\r\n // For Antigravity Gemini 3 Pro models without explicit tier, append default tier\r\n // Antigravity API: gemini-3-pro requires tier suffix (gemini-3-pro-low/high)\r\n // gemini-3-flash uses bare name + thinkingLevel param\r\n // Pro defaults to -low unless an explicit tier is provided\r\n const isGemini3Pro = isGemini3ProModel(modelWithoutQuota);\r\n const isGemini3Flash = isGemini3FlashModel(modelWithoutQuota);\r\n \r\n let antigravityModel = modelWithoutQuota;\r\n if (skipAlias) {\r\n if (isGemini3Pro && !tier && !isImageModel) {\r\n antigravityModel = `${modelWithoutQuota}-low`;\r\n } else if (isGemini3Flash && tier) {\r\n antigravityModel = baseName;\r\n }\r\n }\r\n\r\n const actualModel = skipAlias\r\n ? antigravityModel\r\n : MODEL_ALIASES[modelWithoutQuota] || MODEL_ALIASES[baseName] || baseName;\r\n\r\n const resolvedModel = actualModel;\r\n\r\n const isThinking = isThinkingCapableModel(resolvedModel);\r\n\r\n // Image generation models don't support thinking - return early without thinking config\r\n if (isImageModel) {\r\n return {\r\n actualModel: resolvedModel,\r\n isThinkingModel: false,\r\n isImageModel: true,\r\n quotaPreference,\r\n explicitQuota,\r\n };\r\n }\r\n\r\n // Check if this is a Gemini 3 model (works for both aliased and skipAlias paths)\r\n const isEffectiveGemini3 = resolvedModel.toLowerCase().includes(\"gemini-3\");\r\n const isClaudeThinking = resolvedModel.toLowerCase().includes(\"claude\") && resolvedModel.toLowerCase().includes(\"thinking\");\r\n\r\n if (!tier) {\r\n // Gemini 3 models without explicit tier get a default thinkingLevel\r\n if (isEffectiveGemini3) {\r\n return {\r\n actualModel: resolvedModel,\r\n thinkingLevel: \"low\",\r\n isThinkingModel: true,\r\n quotaPreference,\r\n explicitQuota,\r\n };\r\n }\r\n // Claude thinking models without explicit tier get max budget (32768)\r\n // Per Anthropic docs, budget_tokens is required when enabling extended thinking\r\n if (isClaudeThinking) {\r\n return {\r\n actualModel: resolvedModel,\r\n thinkingBudget: THINKING_TIER_BUDGETS.claude.high,\r\n isThinkingModel: true,\r\n quotaPreference,\r\n explicitQuota,\r\n };\r\n }\r\n return { actualModel: resolvedModel, isThinkingModel: isThinking, quotaPreference, explicitQuota };\r\n }\r\n\r\n // Gemini 3 models with tier always get thinkingLevel set\r\n if (isEffectiveGemini3) {\r\n return {\r\n actualModel: resolvedModel,\r\n thinkingLevel: tier,\r\n tier,\r\n isThinkingModel: true,\r\n quotaPreference,\r\n explicitQuota,\r\n };\r\n }\r\n\r\n const budgetFamily = getBudgetFamily(resolvedModel);\r\n const budgets = THINKING_TIER_BUDGETS[budgetFamily];\r\n const thinkingBudget = budgets[tier];\r\n\r\n return {\r\n actualModel: resolvedModel,\r\n thinkingBudget,\r\n tier,\r\n isThinkingModel: isThinking,\r\n quotaPreference,\r\n explicitQuota,\r\n };\r\n}\r\n\r\n/**\r\n * Gets the model family for routing decisions.\r\n */\r\nexport function getModelFamily(model: string): \"claude\" | \"gemini-flash\" | \"gemini-pro\" {\r\n const lower = model.toLowerCase();\r\n if (lower.includes(\"claude\")) {\r\n return \"claude\";\r\n }\r\n if (lower.includes(\"flash\")) {\r\n return \"gemini-flash\";\r\n }\r\n return \"gemini-pro\";\r\n}\r\n\r\n/**\r\n * Variant config from OpenCode's providerOptions.\r\n */\r\nexport interface VariantConfig {\r\n thinkingBudget?: number;\r\n googleSearch?: GoogleSearchConfig;\r\n}\r\n\r\n/**\r\n * Maps a thinking budget to Gemini 3 thinking level.\r\n * \u22648192 \u2192 low, \u226416384 \u2192 medium, >16384 \u2192 high\r\n */\r\nfunction budgetToGemini3Level(budget: number): \"low\" | \"medium\" | \"high\" {\r\n if (budget <= 8192) return \"low\";\r\n if (budget <= 16384) return \"medium\";\r\n return \"high\";\r\n}\r\n\r\n/**\r\n * Resolves model name for a specific headerStyle (quota fallback support).\r\n * Transforms model names when switching between gemini-cli and antigravity quotas.\r\n * \r\n * Issue #103: When quota fallback occurs, model names need to be transformed:\r\n * - gemini-3-flash-preview (gemini-cli) \u2192 gemini-3-flash (antigravity)\r\n * - gemini-3-pro-preview (gemini-cli) \u2192 gemini-3-pro-low (antigravity)\r\n * - gemini-3-flash (antigravity) \u2192 gemini-3-flash-preview (gemini-cli)\r\n */\r\nexport function resolveModelForHeaderStyle(\r\n requestedModel: string,\r\n headerStyle: \"antigravity\" | \"gemini-cli\"\r\n): ResolvedModel {\r\n const lower = requestedModel.toLowerCase();\r\n const isGemini3 = lower.includes(\"gemini-3\");\r\n \r\n if (!isGemini3) {\r\n return resolveModelWithTier(requestedModel);\r\n }\r\n\r\n if (headerStyle === \"antigravity\") {\r\n let transformedModel = requestedModel\r\n .replace(/-preview-customtools$/i, \"\")\r\n .replace(/-preview$/i, \"\")\r\n .replace(/^antigravity-/i, \"\");\r\n \r\n const isGemini3Pro = isGemini3ProModel(transformedModel);\r\n const hasTierSuffix = /-(low|medium|high)$/i.test(transformedModel);\r\n const isImageModel = IMAGE_GENERATION_MODELS.test(transformedModel);\r\n \r\n // Don't add tier suffix to image models - they don't support thinking\r\n if (isGemini3Pro && !hasTierSuffix && !isImageModel) {\r\n transformedModel = `${transformedModel}-low`;\r\n }\r\n \r\n const prefixedModel = `antigravity-${transformedModel}`;\r\n return resolveModelWithTier(prefixedModel);\r\n }\r\n \r\n if (headerStyle === \"gemini-cli\") {\r\n let transformedModel = requestedModel\r\n .replace(/^antigravity-/i, \"\")\r\n .replace(/-(low|medium|high)$/i, \"\");\r\n\r\n const hasPreviewSuffix = /-preview($|-)/i.test(transformedModel);\r\n if (!hasPreviewSuffix) {\r\n transformedModel = `${transformedModel}-preview`;\r\n }\r\n \r\n return {\r\n ...resolveModelWithTier(transformedModel),\r\n quotaPreference: \"gemini-cli\",\r\n };\r\n }\r\n\r\n return resolveModelWithTier(requestedModel);\r\n}\r\n\r\n/**\r\n * Resolves model with variant config from providerOptions.\r\n * Variant config takes priority over tier suffix in model name.\r\n */\r\nexport function resolveModelWithVariant(\r\n requestedModel: string,\r\n variantConfig?: VariantConfig\r\n): ResolvedModel {\r\n const base = resolveModelWithTier(requestedModel);\r\n\r\n if (!variantConfig) {\r\n return base;\r\n }\r\n\r\n // Apply Google Search config if present\r\n if (variantConfig.googleSearch) {\r\n base.googleSearch = variantConfig.googleSearch;\r\n base.configSource = \"variant\";\r\n }\r\n\r\n if (!variantConfig.thinkingBudget) {\r\n return base;\r\n }\r\n\r\n const budget = variantConfig.thinkingBudget;\r\n const isGemini3 = base.actualModel.toLowerCase().includes(\"gemini-3\");\r\n\r\n if (isGemini3) {\r\n const level = budgetToGemini3Level(budget);\r\n const isAntigravityGemini3Pro = base.quotaPreference === \"antigravity\" &&\r\n isGemini3ProModel(base.actualModel);\r\n\r\n let actualModel = base.actualModel;\r\n if (isAntigravityGemini3Pro) {\r\n const baseModel = base.actualModel.replace(/-(low|medium|high)$/, \"\");\r\n actualModel = `${baseModel}-${level}`;\r\n }\r\n\r\n return {\r\n ...base,\r\n actualModel,\r\n thinkingLevel: level,\r\n thinkingBudget: undefined,\r\n configSource: \"variant\",\r\n };\r\n }\r\n\r\n return {\r\n ...base,\r\n thinkingBudget: budget,\r\n configSource: \"variant\",\r\n };\r\n}\r\n", "/**\r\n * Storage utilities for reading OpenCode's session data.\r\n * \r\n * Based on oh-my-opencode/src/hooks/session-recovery/storage.ts\r\n */\r\n\r\nimport { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\nimport { MESSAGE_STORAGE, PART_STORAGE, THINKING_TYPES, META_TYPES } from \"./constants\";\r\nimport type { StoredMessageMeta, StoredPart, StoredTextPart } from \"./types\";\r\n\r\n// =============================================================================\r\n// ID Generation\r\n// =============================================================================\r\n\r\nexport function generatePartId(): string {\r\n const timestamp = Date.now().toString(16);\r\n const random = Math.random().toString(36).substring(2, 10);\r\n return `prt_${timestamp}${random}`;\r\n}\r\n\r\n// =============================================================================\r\n// Directory Helpers\r\n// =============================================================================\r\n\r\nexport function getMessageDir(sessionID: string): string {\r\n if (!existsSync(MESSAGE_STORAGE)) return \"\";\r\n\r\n const directPath = join(MESSAGE_STORAGE, sessionID);\r\n if (existsSync(directPath)) {\r\n return directPath;\r\n }\r\n\r\n // Search in subdirectories\r\n try {\r\n for (const dir of readdirSync(MESSAGE_STORAGE)) {\r\n const sessionPath = join(MESSAGE_STORAGE, dir, sessionID);\r\n if (existsSync(sessionPath)) {\r\n return sessionPath;\r\n }\r\n }\r\n } catch {\r\n // Ignore read errors\r\n }\r\n\r\n return \"\";\r\n}\r\n\r\n// =============================================================================\r\n// Message Reading\r\n// =============================================================================\r\n\r\nexport function readMessages(sessionID: string): StoredMessageMeta[] {\r\n const messageDir = getMessageDir(sessionID);\r\n if (!messageDir || !existsSync(messageDir)) return [];\r\n\r\n const messages: StoredMessageMeta[] = [];\r\n try {\r\n for (const file of readdirSync(messageDir)) {\r\n if (!file.endsWith(\".json\")) continue;\r\n try {\r\n const content = readFileSync(join(messageDir, file), \"utf-8\");\r\n messages.push(JSON.parse(content));\r\n } catch {\r\n continue;\r\n }\r\n }\r\n } catch {\r\n return [];\r\n }\r\n\r\n return messages.sort((a, b) => {\r\n const aTime = a.time?.created ?? 0;\r\n const bTime = b.time?.created ?? 0;\r\n if (aTime !== bTime) return aTime - bTime;\r\n return a.id.localeCompare(b.id);\r\n });\r\n}\r\n\r\n// =============================================================================\r\n// Part Reading\r\n// =============================================================================\r\n\r\nexport function readParts(messageID: string): StoredPart[] {\r\n const partDir = join(PART_STORAGE, messageID);\r\n if (!existsSync(partDir)) return [];\r\n\r\n const parts: StoredPart[] = [];\r\n try {\r\n for (const file of readdirSync(partDir)) {\r\n if (!file.endsWith(\".json\")) continue;\r\n try {\r\n const content = readFileSync(join(partDir, file), \"utf-8\");\r\n parts.push(JSON.parse(content));\r\n } catch {\r\n continue;\r\n }\r\n }\r\n } catch {\r\n return [];\r\n }\r\n\r\n return parts;\r\n}\r\n\r\n// =============================================================================\r\n// Content Helpers\r\n// =============================================================================\r\n\r\nexport function hasContent(part: StoredPart): boolean {\r\n if (THINKING_TYPES.has(part.type)) return false;\r\n if (META_TYPES.has(part.type)) return false;\r\n\r\n if (part.type === \"text\") {\r\n const textPart = part as StoredTextPart;\r\n return !!(textPart.text?.trim());\r\n }\r\n\r\n if (part.type === \"tool\" || part.type === \"tool_use\") {\r\n return true;\r\n }\r\n\r\n if (part.type === \"tool_result\") {\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\nexport function messageHasContent(messageID: string): boolean {\r\n const parts = readParts(messageID);\r\n return parts.some(hasContent);\r\n}\r\n\r\n// =============================================================================\r\n// Part Injection (for recovery)\r\n// =============================================================================\r\n\r\nexport function injectTextPart(sessionID: string, messageID: string, text: string): boolean {\r\n const partDir = join(PART_STORAGE, messageID);\r\n\r\n try {\r\n if (!existsSync(partDir)) {\r\n mkdirSync(partDir, { recursive: true });\r\n }\r\n\r\n const partId = generatePartId();\r\n const part: StoredTextPart = {\r\n id: partId,\r\n sessionID,\r\n messageID,\r\n type: \"text\",\r\n text,\r\n synthetic: true,\r\n };\r\n\r\n writeFileSync(join(partDir, `${partId}.json`), JSON.stringify(part, null, 2));\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// =============================================================================\r\n// Thinking Block Recovery\r\n// =============================================================================\r\n\r\nexport function findMessagesWithThinkingBlocks(sessionID: string): string[] {\r\n const messages = readMessages(sessionID);\r\n const result: string[] = [];\r\n\r\n for (const msg of messages) {\r\n if (msg.role !== \"assistant\") continue;\r\n\r\n const parts = readParts(msg.id);\r\n const hasThinking = parts.some((p) => THINKING_TYPES.has(p.type));\r\n if (hasThinking) {\r\n result.push(msg.id);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\nexport function findMessagesWithThinkingOnly(sessionID: string): string[] {\r\n const messages = readMessages(sessionID);\r\n const result: string[] = [];\r\n\r\n for (const msg of messages) {\r\n if (msg.role !== \"assistant\") continue;\r\n\r\n const parts = readParts(msg.id);\r\n if (parts.length === 0) continue;\r\n\r\n const hasThinking = parts.some((p) => THINKING_TYPES.has(p.type));\r\n const hasTextContent = parts.some(hasContent);\r\n\r\n // Has thinking but no text content = orphan thinking\r\n if (hasThinking && !hasTextContent) {\r\n result.push(msg.id);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\nexport function findMessagesWithOrphanThinking(sessionID: string): string[] {\r\n const messages = readMessages(sessionID);\r\n const result: string[] = [];\r\n\r\n for (let i = 0; i < messages.length; i++) {\r\n const msg = messages[i];\r\n if (!msg || msg.role !== \"assistant\") continue;\r\n\r\n const parts = readParts(msg.id);\r\n if (parts.length === 0) continue;\r\n\r\n const sortedParts = [...parts].sort((a, b) => a.id.localeCompare(b.id));\r\n const firstPart = sortedParts[0];\r\n if (!firstPart) continue;\r\n\r\n const firstIsThinking = THINKING_TYPES.has(firstPart.type);\r\n\r\n // If first part is not thinking, it's orphan\r\n if (!firstIsThinking) {\r\n result.push(msg.id);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\nexport function prependThinkingPart(sessionID: string, messageID: string): boolean {\r\n const partDir = join(PART_STORAGE, messageID);\r\n\r\n try {\r\n if (!existsSync(partDir)) {\r\n mkdirSync(partDir, { recursive: true });\r\n }\r\n\r\n const partId = \"prt_0000000000_thinking\";\r\n const part = {\r\n id: partId,\r\n sessionID,\r\n messageID,\r\n type: \"thinking\",\r\n thinking: \"\",\r\n synthetic: true,\r\n };\r\n\r\n writeFileSync(join(partDir, `${partId}.json`), JSON.stringify(part, null, 2));\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function stripThinkingParts(messageID: string): boolean {\r\n const partDir = join(PART_STORAGE, messageID);\r\n if (!existsSync(partDir)) return false;\r\n\r\n let anyRemoved = false;\r\n try {\r\n for (const file of readdirSync(partDir)) {\r\n if (!file.endsWith(\".json\")) continue;\r\n try {\r\n const filePath = join(partDir, file);\r\n const content = readFileSync(filePath, \"utf-8\");\r\n const part = JSON.parse(content) as StoredPart;\r\n if (THINKING_TYPES.has(part.type)) {\r\n unlinkSync(filePath);\r\n anyRemoved = true;\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n } catch {\r\n return false;\r\n }\r\n\r\n return anyRemoved;\r\n}\r\n\r\n// =============================================================================\r\n// Empty Message Recovery\r\n// =============================================================================\r\n\r\nexport function findEmptyMessages(sessionID: string): string[] {\r\n const messages = readMessages(sessionID);\r\n const emptyIds: string[] = [];\r\n\r\n for (const msg of messages) {\r\n if (!messageHasContent(msg.id)) {\r\n emptyIds.push(msg.id);\r\n }\r\n }\r\n\r\n return emptyIds;\r\n}\r\n\r\nexport function findEmptyMessageByIndex(sessionID: string, targetIndex: number): string | null {\r\n const messages = readMessages(sessionID);\r\n\r\n // API index may differ from storage index due to system messages\r\n const indicesToTry = [targetIndex, targetIndex - 1, targetIndex - 2];\r\n\r\n for (const idx of indicesToTry) {\r\n if (idx < 0 || idx >= messages.length) continue;\r\n\r\n const targetMsg = messages[idx];\r\n if (!targetMsg) continue;\r\n\r\n if (!messageHasContent(targetMsg.id)) {\r\n return targetMsg.id;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function findMessageByIndexNeedingThinking(sessionID: string, targetIndex: number): string | null {\r\n const messages = readMessages(sessionID);\r\n\r\n if (targetIndex < 0 || targetIndex >= messages.length) return null;\r\n\r\n const targetMsg = messages[targetIndex];\r\n if (!targetMsg || targetMsg.role !== \"assistant\") return null;\r\n\r\n const parts = readParts(targetMsg.id);\r\n if (parts.length === 0) return null;\r\n\r\n const sortedParts = [...parts].sort((a, b) => a.id.localeCompare(b.id));\r\n const firstPart = sortedParts[0];\r\n if (!firstPart) return null;\r\n\r\n const firstIsThinking = THINKING_TYPES.has(firstPart.type);\r\n\r\n if (!firstIsThinking) {\r\n return targetMsg.id;\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function replaceEmptyTextParts(messageID: string, replacementText: string): boolean {\r\n const partDir = join(PART_STORAGE, messageID);\r\n if (!existsSync(partDir)) return false;\r\n\r\n let anyReplaced = false;\r\n try {\r\n for (const file of readdirSync(partDir)) {\r\n if (!file.endsWith(\".json\")) continue;\r\n try {\r\n const filePath = join(partDir, file);\r\n const content = readFileSync(filePath, \"utf-8\");\r\n const part = JSON.parse(content) as StoredPart;\r\n\r\n if (part.type === \"text\") {\r\n const textPart = part as StoredTextPart;\r\n if (!textPart.text?.trim()) {\r\n textPart.text = replacementText;\r\n textPart.synthetic = true;\r\n writeFileSync(filePath, JSON.stringify(textPart, null, 2));\r\n anyReplaced = true;\r\n }\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n } catch {\r\n return false;\r\n }\r\n\r\n return anyReplaced;\r\n}\r\n\r\nexport function findMessagesWithEmptyTextParts(sessionID: string): string[] {\r\n const messages = readMessages(sessionID);\r\n const result: string[] = [];\r\n\r\n for (const msg of messages) {\r\n const parts = readParts(msg.id);\r\n const hasEmptyTextPart = parts.some((p) => {\r\n if (p.type !== \"text\") return false;\r\n const textPart = p as StoredTextPart;\r\n return !textPart.text?.trim();\r\n });\r\n\r\n if (hasEmptyTextPart) {\r\n result.push(msg.id);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n", "/**\r\n * Constants for session recovery storage paths.\r\n * \r\n * Based on oh-my-opencode/src/hooks/session-recovery/constants.ts\r\n */\r\n\r\nimport { join } from \"node:path\";\r\nimport { homedir } from \"node:os\";\r\n\r\n/**\r\n * Get the XDG data directory for OpenCode storage.\r\n * Falls back to ~/.local/share on Linux/Mac, or APPDATA on Windows.\r\n */\r\nfunction getXdgData(): string {\r\n const platform = process.platform;\r\n \r\n if (platform === \"win32\") {\r\n return process.env.APPDATA || join(homedir(), \"AppData\", \"Roaming\");\r\n }\r\n \r\n return process.env.XDG_DATA_HOME || join(homedir(), \".local\", \"share\");\r\n}\r\n\r\n/**\r\n * Get the XDG config directory for Antigravity config.\r\n * Falls back to ~/.config on Linux/Mac, or APPDATA on Windows.\r\n */\r\nexport function getXdgConfig(): string {\r\n const platform = process.platform;\r\n \r\n if (platform === \"win32\") {\r\n return process.env.APPDATA || join(homedir(), \"AppData\", \"Roaming\");\r\n }\r\n \r\n return process.env.XDG_CONFIG_HOME || join(homedir(), \".config\");\r\n}\r\n\r\n/**\r\n * Get the Antigravity config directory.\r\n * Default: ~/.config/opencode/antigravity.json\r\n */\r\nexport function getAntigravityConfigDir(): string {\r\n return join(getXdgConfig(), \"opencode\");\r\n}\r\n\r\nexport const OPENCODE_STORAGE = join(getXdgData(), \"opencode\", \"storage\");\r\nexport const MESSAGE_STORAGE = join(OPENCODE_STORAGE, \"message\");\r\nexport const PART_STORAGE = join(OPENCODE_STORAGE, \"part\");\r\n\r\nexport const THINKING_TYPES = new Set([\"thinking\", \"redacted_thinking\", \"reasoning\"]);\r\nexport const META_TYPES = new Set([\"step-start\", \"step-finish\"]);\r\nexport const CONTENT_TYPES = new Set([\"text\", \"tool\", \"tool_use\", \"tool_result\"]);\r\n", "/**\r\n * Session recovery hook for handling recoverable errors.\r\n * \r\n * Supports:\r\n * - tool_result_missing: When ESC is pressed during tool execution\r\n * - thinking_block_order: When thinking blocks are corrupted/stripped\r\n * - thinking_disabled_violation: Thinking in non-thinking model\r\n * \r\n * Based on oh-my-opencode/src/hooks/session-recovery/index.ts\r\n */\r\n\r\nimport type { AntigravityConfig } from \"./config\";\r\nimport { createLogger } from \"./logger\";\r\nimport { logToast } from \"./debug\";\r\nimport type { PluginClient } from \"./types\";\r\nimport {\r\n readParts,\r\n findMessagesWithThinkingBlocks,\r\n findMessagesWithOrphanThinking,\r\n findMessageByIndexNeedingThinking,\r\n prependThinkingPart,\r\n stripThinkingParts,\r\n} from \"./recovery/storage\";\r\nimport type {\r\n MessageInfo,\r\n MessageData,\r\n MessagePart,\r\n RecoveryErrorType,\r\n ResumeConfig,\r\n} from \"./recovery/types\";\r\n\r\n// =============================================================================\r\n// Constants\r\n// =============================================================================\r\n\r\nconst RECOVERY_RESUME_TEXT = \"[session recovered - continuing previous task]\";\r\n\r\n// =============================================================================\r\n// Error Detection\r\n// =============================================================================\r\n\r\n/**\r\n * Extract a normalized error message string from an unknown error.\r\n */\r\nfunction getErrorMessage(error: unknown): string {\r\n if (!error) return \"\";\r\n if (typeof error === \"string\") return error.toLowerCase();\r\n\r\n const errorObj = error as Record<string, unknown>;\r\n const paths = [\r\n errorObj.data,\r\n errorObj.error,\r\n errorObj,\r\n (errorObj.data as Record<string, unknown>)?.error,\r\n ];\r\n\r\n for (const obj of paths) {\r\n if (obj && typeof obj === \"object\") {\r\n const msg = (obj as Record<string, unknown>).message;\r\n if (typeof msg === \"string\" && msg.length > 0) {\r\n return msg.toLowerCase();\r\n }\r\n }\r\n }\r\n\r\n try {\r\n return JSON.stringify(error).toLowerCase();\r\n } catch {\r\n return \"\";\r\n }\r\n}\r\n\r\n/**\r\n * Extract the message index from an error message (e.g., \"messages.79\").\r\n */\r\nfunction extractMessageIndex(error: unknown): number | null {\r\n const message = getErrorMessage(error);\r\n const match = message.match(/messages\\.(\\d+)/);\r\n if (!match || !match[1]) return null;\r\n return parseInt(match[1], 10);\r\n}\r\n\r\n/**\r\n * Detect the type of recoverable error from an error object.\r\n */\r\nexport function detectErrorType(error: unknown): RecoveryErrorType {\r\n const message = getErrorMessage(error);\r\n const hasExpectedFoundThinkingOrder =\r\n (message.includes(\"expected thinking\") || message.includes(\"expected a thinking\")) &&\r\n message.includes(\"found\");\r\n\r\n // tool_result_missing: Happens when ESC is pressed during tool execution\r\n if (message.includes(\"tool_use\") && message.includes(\"tool_result\")) {\r\n return \"tool_result_missing\";\r\n }\r\n\r\n // thinking_block_order: Happens when thinking blocks are corrupted\r\n if (\r\n message.includes(\"thinking\") &&\r\n (message.includes(\"first block\") ||\r\n message.includes(\"must start with\") ||\r\n message.includes(\"preceeding\") ||\r\n message.includes(\"preceding\") ||\r\n hasExpectedFoundThinkingOrder)\r\n ) {\r\n return \"thinking_block_order\";\r\n }\r\n\r\n // thinking_disabled_violation: Thinking in non-thinking model\r\n if (message.includes(\"thinking is disabled\") && message.includes(\"cannot contain\")) {\r\n return \"thinking_disabled_violation\";\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Check if an error is recoverable.\r\n */\r\nexport function isRecoverableError(error: unknown): boolean {\r\n return detectErrorType(error) !== null;\r\n}\r\n\r\n// =============================================================================\r\n// Tool Use Extraction\r\n// =============================================================================\r\n\r\ninterface ToolUsePart {\r\n type: \"tool_use\";\r\n id: string;\r\n name: string;\r\n input: Record<string, unknown>;\r\n}\r\n\r\nfunction extractToolUseIds(parts: MessagePart[]): string[] {\r\n return parts\r\n .filter((p): p is ToolUsePart & MessagePart => p.type === \"tool_use\" && !!p.id)\r\n .map((p) => p.id!);\r\n}\r\n\r\n// =============================================================================\r\n// Recovery Functions\r\n// =============================================================================\r\n\r\n/**\r\n * Recover from tool_result_missing error by injecting synthetic tool_result blocks.\r\n */\r\nasync function recoverToolResultMissing(\r\n client: PluginClient,\r\n sessionID: string,\r\n failedMsg: MessageData\r\n): Promise<boolean> {\r\n // Try API parts first, fallback to filesystem if empty\r\n let parts = failedMsg.parts || [];\r\n if (parts.length === 0 && failedMsg.info?.id) {\r\n const storedParts = readParts(failedMsg.info.id);\r\n parts = storedParts.map((p) => ({\r\n type: p.type === \"tool\" ? \"tool_use\" : p.type,\r\n id: \"callID\" in p ? (p as { callID?: string }).callID : p.id,\r\n name: \"tool\" in p ? (p as { tool?: string }).tool : undefined,\r\n input: \"state\" in p ? (p as { state?: { input?: Record<string, unknown> } }).state?.input : undefined,\r\n }));\r\n }\r\n\r\n const toolUseIds = extractToolUseIds(parts);\r\n\r\n if (toolUseIds.length === 0) {\r\n return false;\r\n }\r\n\r\n const toolResultParts = toolUseIds.map((id) => ({\r\n type: \"tool_result\" as const,\r\n tool_use_id: id,\r\n content: \"Operation cancelled by user (ESC pressed)\",\r\n }));\r\n\r\n try {\r\n await client.session.prompt({\r\n path: { id: sessionID },\r\n // @ts-expect-error - SDK types may not include tool_result parts\r\n body: { parts: toolResultParts },\r\n });\r\n\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Recover from thinking_block_order error by prepending thinking parts.\r\n */\r\nasync function recoverThinkingBlockOrder(\r\n sessionID: string,\r\n _failedMsg: MessageData,\r\n error: unknown\r\n): Promise<boolean> {\r\n // Try to find the target message index from error\r\n const targetIndex = extractMessageIndex(error);\r\n if (targetIndex !== null) {\r\n const targetMessageID = findMessageByIndexNeedingThinking(sessionID, targetIndex);\r\n if (targetMessageID) {\r\n return prependThinkingPart(sessionID, targetMessageID);\r\n }\r\n }\r\n\r\n // Fallback: find all orphan thinking messages\r\n const orphanMessages = findMessagesWithOrphanThinking(sessionID);\r\n\r\n if (orphanMessages.length === 0) {\r\n return false;\r\n }\r\n\r\n let anySuccess = false;\r\n for (const messageID of orphanMessages) {\r\n if (prependThinkingPart(sessionID, messageID)) {\r\n anySuccess = true;\r\n }\r\n }\r\n\r\n return anySuccess;\r\n}\r\n\r\n/**\r\n * Recover from thinking_disabled_violation by stripping thinking parts.\r\n */\r\nasync function recoverThinkingDisabledViolation(\r\n sessionID: string,\r\n _failedMsg: MessageData\r\n): Promise<boolean> {\r\n const messagesWithThinking = findMessagesWithThinkingBlocks(sessionID);\r\n\r\n if (messagesWithThinking.length === 0) {\r\n return false;\r\n }\r\n\r\n let anySuccess = false;\r\n for (const messageID of messagesWithThinking) {\r\n if (stripThinkingParts(messageID)) {\r\n anySuccess = true;\r\n }\r\n }\r\n\r\n return anySuccess;\r\n}\r\n\r\n// =============================================================================\r\n// Resume Session Helper\r\n// =============================================================================\r\n\r\nfunction findLastUserMessage(messages: MessageData[]): MessageData | undefined {\r\n for (let i = messages.length - 1; i >= 0; i--) {\r\n if (messages[i]?.info?.role === \"user\") {\r\n return messages[i];\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction extractResumeConfig(userMessage: MessageData | undefined, sessionID: string): ResumeConfig {\r\n return {\r\n sessionID,\r\n agent: userMessage?.info?.agent,\r\n model: userMessage?.info?.model,\r\n };\r\n}\r\n\r\nasync function resumeSession(\r\n client: PluginClient,\r\n config: ResumeConfig,\r\n directory: string\r\n): Promise<boolean> {\r\n try {\r\n await client.session.prompt({\r\n path: { id: config.sessionID },\r\n body: {\r\n parts: [{ type: \"text\", text: RECOVERY_RESUME_TEXT }],\r\n agent: config.agent,\r\n model: config.model,\r\n },\r\n query: { directory },\r\n });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// =============================================================================\r\n// Toast Messages\r\n// =============================================================================\r\n\r\nconst TOAST_TITLES: Record<string, string> = {\r\n tool_result_missing: \"Tool Crash Recovery\",\r\n thinking_block_order: \"Thinking Block Recovery\",\r\n thinking_disabled_violation: \"Thinking Strip Recovery\",\r\n};\r\n\r\nconst TOAST_MESSAGES: Record<string, string> = {\r\n tool_result_missing: \"Injecting cancelled tool results...\",\r\n thinking_block_order: \"Fixing message structure...\",\r\n thinking_disabled_violation: \"Stripping thinking blocks...\",\r\n};\r\n\r\nexport function getRecoveryToastContent(errorType: RecoveryErrorType): {\r\n title: string;\r\n message: string;\r\n} {\r\n if (!errorType) {\r\n return {\r\n title: \"Session Recovery\",\r\n message: \"Attempting to recover session...\",\r\n };\r\n }\r\n return {\r\n title: TOAST_TITLES[errorType] || \"Session Recovery\",\r\n message: TOAST_MESSAGES[errorType] || \"Attempting to recover session...\",\r\n };\r\n}\r\n\r\nexport function getRecoverySuccessToast(): {\r\n title: string;\r\n message: string;\r\n} {\r\n return {\r\n title: \"Session Recovered\",\r\n message: \"Continuing where you left off...\",\r\n };\r\n}\r\n\r\nexport function getRecoveryFailureToast(): {\r\n title: string;\r\n message: string;\r\n} {\r\n return {\r\n title: \"Recovery Failed\",\r\n message: \"Please retry or start a new session.\",\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// Session Recovery Hook\r\n// =============================================================================\r\n\r\nexport interface SessionRecoveryHook {\r\n /**\r\n * Main recovery handler. Performs the actual fix.\r\n * Returns true if recovery was successful.\r\n */\r\n handleSessionRecovery: (info: MessageInfo) => Promise<boolean>;\r\n\r\n /**\r\n * Check if the error is recoverable.\r\n */\r\n isRecoverableError: (error: unknown) => boolean;\r\n\r\n /**\r\n * Callback for when a session is being aborted for recovery.\r\n */\r\n setOnAbortCallback: (callback: (sessionID: string) => void) => void;\r\n\r\n /**\r\n * Callback for when recovery is complete (success or failure).\r\n */\r\n setOnRecoveryCompleteCallback: (callback: (sessionID: string) => void) => void;\r\n}\r\n\r\nexport interface SessionRecoveryContext {\r\n client: PluginClient;\r\n directory: string;\r\n}\r\n\r\n/**\r\n * Create a session recovery hook with the given configuration.\r\n */\r\nexport function createSessionRecoveryHook(\r\n ctx: SessionRecoveryContext,\r\n config: AntigravityConfig\r\n): SessionRecoveryHook | null {\r\n // If session recovery is disabled, return null\r\n if (!config.session_recovery) {\r\n return null;\r\n }\r\n\r\n const { client, directory } = ctx;\r\n const processingErrors = new Set<string>();\r\n let onAbortCallback: ((sessionID: string) => void) | null = null;\r\n let onRecoveryCompleteCallback: ((sessionID: string) => void) | null = null;\r\n\r\n const setOnAbortCallback = (callback: (sessionID: string) => void): void => {\r\n onAbortCallback = callback;\r\n };\r\n\r\n const setOnRecoveryCompleteCallback = (callback: (sessionID: string) => void): void => {\r\n onRecoveryCompleteCallback = callback;\r\n };\r\n\r\n const handleSessionRecovery = async (info: MessageInfo): Promise<boolean> => {\r\n // Validate input\r\n if (!info || info.role !== \"assistant\" || !info.error) return false;\r\n\r\n const errorType = detectErrorType(info.error);\r\n if (!errorType) return false;\r\n\r\n const sessionID = info.sessionID;\r\n if (!sessionID) return false;\r\n\r\n // OpenCode's session.error event may not include messageID\r\n // In that case, we need to fetch messages and find the latest assistant with error\r\n let assistantMsgID = info.id;\r\n let msgs: MessageData[] | undefined;\r\n const log = createLogger(\"session-recovery\");\r\n\r\n log.debug(\"Recovery attempt started\", {\r\n errorType,\r\n sessionID,\r\n providedMsgID: assistantMsgID ?? \"none\",\r\n });\r\n\r\n // Notify abort callback early\r\n if (onAbortCallback) {\r\n onAbortCallback(sessionID);\r\n }\r\n\r\n // Abort current request\r\n await client.session.abort({ path: { id: sessionID } }).catch(() => {});\r\n\r\n // Fetch messages - needed to find the failed message\r\n const messagesResp = await client.session.messages({\r\n path: { id: sessionID },\r\n query: { directory },\r\n });\r\n msgs = (messagesResp as { data?: MessageData[] }).data;\r\n\r\n // If messageID wasn't provided, find the latest assistant message with an error\r\n if (!assistantMsgID && msgs && msgs.length > 0) {\r\n // Find the last assistant message (most recent is typically last in array)\r\n for (let i = msgs.length - 1; i >= 0; i--) {\r\n const m = msgs[i];\r\n if (m && m.info?.role === \"assistant\" && m.info?.id) {\r\n assistantMsgID = m.info.id;\r\n log.debug(\"Found assistant message ID from session messages\", {\r\n msgID: assistantMsgID,\r\n msgIndex: i,\r\n });\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!assistantMsgID) {\r\n log.debug(\"No assistant message ID found, cannot recover\");\r\n return false;\r\n }\r\n if (processingErrors.has(assistantMsgID)) return false;\r\n processingErrors.add(assistantMsgID);\r\n\r\n try {\r\n const failedMsg = msgs?.find((m) => m.info?.id === assistantMsgID);\r\n if (!failedMsg) {\r\n return false;\r\n }\r\n\r\n // Show toast notification\r\n const toastContent = getRecoveryToastContent(errorType);\r\n logToast(`${toastContent.title}: ${toastContent.message}`, \"warning\");\r\n await client.tui\r\n .showToast({\r\n body: {\r\n title: toastContent.title,\r\n message: toastContent.message,\r\n variant: \"warning\",\r\n },\r\n })\r\n .catch(() => {});\r\n\r\n // Perform recovery based on error type\r\n let success = false;\r\n\r\n if (errorType === \"tool_result_missing\") {\r\n success = await recoverToolResultMissing(client, sessionID, failedMsg);\r\n } else if (errorType === \"thinking_block_order\") {\r\n success = await recoverThinkingBlockOrder(sessionID, failedMsg, info.error);\r\n if (success && config.auto_resume) {\r\n const lastUser = findLastUserMessage(msgs ?? []);\r\n const resumeConfig = extractResumeConfig(lastUser, sessionID);\r\n await resumeSession(client, resumeConfig, directory);\r\n }\r\n } else if (errorType === \"thinking_disabled_violation\") {\r\n success = await recoverThinkingDisabledViolation(sessionID, failedMsg);\r\n if (success && config.auto_resume) {\r\n const lastUser = findLastUserMessage(msgs ?? []);\r\n const resumeConfig = extractResumeConfig(lastUser, sessionID);\r\n await resumeSession(client, resumeConfig, directory);\r\n }\r\n }\r\n\r\n return success;\r\n } catch (err) {\r\n log.error(\"Recovery failed\", { error: String(err) });\r\n return false;\r\n } finally {\r\n processingErrors.delete(assistantMsgID);\r\n\r\n // Always notify recovery complete\r\n if (sessionID && onRecoveryCompleteCallback) {\r\n onRecoveryCompleteCallback(sessionID);\r\n }\r\n }\r\n };\r\n\r\n return {\r\n handleSessionRecovery,\r\n isRecoverableError,\r\n setOnAbortCallback,\r\n setOnRecoveryCompleteCallback,\r\n };\r\n}\r\n", "/**\r\n * Device Fingerprint Generator for Rate Limit Mitigation\r\n *\r\n * Ported from antigravity-claude-proxy PR #170\r\n * https://github.com/badrisnarayanan/antigravity-claude-proxy/pull/170\r\n *\r\n * Generates randomized device fingerprints to help distribute API usage\r\n * across different apparent device identities.\r\n */\r\n\r\nimport * as crypto from \"node:crypto\";\r\nimport * as os from \"node:os\";\r\nimport { getAntigravityVersion } from \"../constants\";\r\n\r\nconst OS_VERSIONS: Record<string, string[]> = {\r\n darwin: [\"10.15.7\", \"11.6.8\", \"12.6.3\", \"13.5.2\", \"14.2.1\", \"14.5\"],\r\n win32: [\"10.0.19041\", \"10.0.19042\", \"10.0.19043\", \"10.0.22000\", \"10.0.22621\", \"10.0.22631\"],\r\n linux: [\"5.15.0\", \"5.19.0\", \"6.1.0\", \"6.2.0\", \"6.5.0\", \"6.6.0\"],\r\n};\r\n\r\nconst ARCHITECTURES = [\"x64\", \"arm64\"];\r\n\r\nconst IDE_TYPES = [\r\n \"ANTIGRAVITY\",\r\n] as const;\r\n\r\nconst PLATFORMS = [\r\n \"WINDOWS\",\r\n \"MACOS\",\r\n] as const;\r\n\r\nconst SDK_CLIENTS = [\r\n \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\r\n \"google-cloud-sdk vscode/1.86.0\",\r\n \"google-cloud-sdk vscode/1.87.0\",\r\n \"google-cloud-sdk vscode/1.96.0\",\r\n];\r\n\r\nexport interface ClientMetadata {\r\n ideType: string;\r\n platform: string;\r\n pluginType: string;\r\n}\r\n\r\nexport interface Fingerprint {\r\n deviceId: string;\r\n sessionToken: string;\r\n userAgent: string;\r\n apiClient: string;\r\n clientMetadata: ClientMetadata;\r\n createdAt: number;\r\n /** @deprecated Kept for backward compat with stored fingerprints */\r\n quotaUser?: string;\r\n}\r\n\r\n/**\r\n * Fingerprint version for history tracking.\r\n * Stores a snapshot of a fingerprint with metadata about when/why it was saved.\r\n */\r\nexport interface FingerprintVersion {\r\n fingerprint: Fingerprint;\r\n timestamp: number;\r\n reason: 'initial' | 'regenerated' | 'restored';\r\n}\r\n\r\n/** Maximum number of fingerprint versions to keep per account */\r\nexport const MAX_FINGERPRINT_HISTORY = 5;\r\n\r\nexport interface FingerprintHeaders {\r\n \"User-Agent\": string;\r\n}\r\n\r\nconst PLATFORM_CHOICES = [\"darwin\", \"win32\"] as const;\r\ntype PlatformChoice = typeof PLATFORM_CHOICES[number];\r\n\r\nfunction randomFrom<T>(arr: readonly T[]): T {\r\n const index = crypto.getRandomValues(new Uint32Array(1))[0]! % arr.length;\r\n return arr[index]!;\r\n}\r\n\nfunction platformToDisplayName(platform: string): \"WINDOWS\" | \"MACOS\" {\n return platform === \"win32\" ? \"WINDOWS\" : \"MACOS\";\n}\nfunction generateDeviceId(): string {\r\n return crypto.randomUUID();\r\n}\r\n\r\nfunction generateSessionToken(): string {\r\n return crypto.randomBytes(16).toString(\"hex\");\r\n}\r\n\r\n/**\r\n * Generate a randomized device fingerprint.\r\n * Each fingerprint represents a unique \"device\" identity.\r\n */\r\nexport function generateFingerprint(): Fingerprint {\r\n const platform = randomFrom(PLATFORM_CHOICES);\r\n const arch = randomFrom(ARCHITECTURES);\r\n const osVersion = randomFrom(OS_VERSIONS[platform] ?? OS_VERSIONS.darwin!);\r\n\r\n return {\r\n deviceId: generateDeviceId(),\r\n sessionToken: generateSessionToken(),\r\n userAgent: `antigravity/${getAntigravityVersion()} ${platform}/${arch}`,\r\n apiClient: randomFrom(SDK_CLIENTS),\r\n clientMetadata: {\r\n ideType: randomFrom(IDE_TYPES),\r\n platform: platformToDisplayName(platform),\r\n pluginType: \"GEMINI\",\r\n },\r\n createdAt: Date.now(),\r\n };\r\n}\r\n\r\n/**\r\n * Collect fingerprint based on actual current system.\r\n * Uses real OS info instead of randomized values.\r\n */\r\nexport function collectCurrentFingerprint(): Fingerprint {\r\n const platform = os.platform();\r\n const arch = os.arch();\r\n\r\n return {\r\n deviceId: generateDeviceId(),\r\n sessionToken: generateSessionToken(),\r\n userAgent: `antigravity/${getAntigravityVersion()} ${platform}/${arch}`,\r\n apiClient: \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\r\n clientMetadata: {\r\n ideType: \"ANTIGRAVITY\",\r\n platform: platformToDisplayName(platform),\r\n pluginType: \"GEMINI\",\r\n },\r\n createdAt: Date.now(),\r\n };\r\n}\r\n\r\n/**\r\n * Update the version in a fingerprint's userAgent to match the current runtime version.\r\n * Called after version fetcher resolves so saved fingerprints always carry the latest version.\r\n * Returns true if the userAgent was changed.\r\n */\r\nexport function updateFingerprintVersion(fingerprint: Fingerprint): boolean {\r\n const currentVersion = getAntigravityVersion();\r\n const versionPattern = /^(antigravity\\/)([\\d.]+)/;\r\n const match = fingerprint.userAgent.match(versionPattern);\r\n\r\n if (!match || match[2] === currentVersion) {\r\n return false;\r\n }\r\n\r\n fingerprint.userAgent = fingerprint.userAgent.replace(versionPattern, `$1${currentVersion}`);\r\n return true;\r\n}\r\n\r\n/**\r\n * Build HTTP headers from a fingerprint object.\r\n * These headers are used to identify the \"device\" making API requests.\r\n */\r\nexport function buildFingerprintHeaders(fingerprint: Fingerprint | null): Partial<FingerprintHeaders> {\r\n if (!fingerprint) {\r\n return {};\r\n }\r\n\r\n return {\r\n \"User-Agent\": fingerprint.userAgent,\r\n };\r\n}\r\n\r\n/**\r\n * Session-level fingerprint instance.\r\n * Generated once at module load, persists for the lifetime of the process.\r\n */\r\nlet sessionFingerprint: Fingerprint | null = null;\r\n\r\n/**\r\n * Get or create the session fingerprint.\r\n * Returns the same fingerprint for all calls within a session.\r\n */\r\nexport function getSessionFingerprint(): Fingerprint {\r\n if (!sessionFingerprint) {\r\n sessionFingerprint = generateFingerprint();\r\n }\r\n return sessionFingerprint;\r\n}\r\n\r\n/**\r\n * Regenerate the session fingerprint.\r\n * Call this to get a fresh identity (e.g., after rate limiting).\r\n */\r\nexport function regenerateSessionFingerprint(): Fingerprint {\r\n sessionFingerprint = generateFingerprint();\r\n return sessionFingerprint;\r\n}\r\n", "/**\r\n * Custom error types for opencode-antigravity-auth plugin.\r\n * \r\n * Ported from LLM-API-Key-Proxy for robust error handling.\r\n */\r\n\r\n/**\r\n * Error thrown when Antigravity returns an empty response after retry attempts.\r\n * \r\n * Empty responses can occur when:\r\n * - The model has no candidates/choices\r\n * - The response body is empty or malformed\r\n * - A temporary service issue prevents generation\r\n */\r\nexport class EmptyResponseError extends Error {\r\n readonly provider: string;\r\n readonly model: string;\r\n readonly attempts: number;\r\n\r\n constructor(\r\n provider: string,\r\n model: string,\r\n attempts: number,\r\n message?: string,\r\n ) {\r\n super(\r\n message ??\r\n `The model returned an empty response after ${attempts} attempts. ` +\r\n `This may indicate a temporary service issue. Please try again.`,\r\n );\r\n this.name = \"EmptyResponseError\";\r\n this.provider = provider;\r\n this.model = model;\r\n this.attempts = attempts;\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown when tool ID matching fails and cannot be recovered.\r\n */\r\nexport class ToolIdMismatchError extends Error {\r\n readonly expectedIds: string[];\r\n readonly foundIds: string[];\r\n\r\n constructor(expectedIds: string[], foundIds: string[], message?: string) {\r\n super(\r\n message ??\r\n `Tool ID mismatch: expected [${expectedIds.join(\", \")}] but found [${foundIds.join(\", \")}]`,\r\n );\r\n this.name = \"ToolIdMismatchError\";\r\n this.expectedIds = expectedIds;\r\n this.foundIds = foundIds;\r\n }\r\n}\r\n", "import { ANTIGRAVITY_CLIENT_ID, ANTIGRAVITY_CLIENT_SECRET } from \"../constants\";\r\nimport { formatRefreshParts, parseRefreshParts, calculateTokenExpiry } from \"./auth\";\r\nimport { clearCachedAuth, storeCachedAuth } from \"./cache\";\r\nimport { createLogger } from \"./logger\";\r\nimport { invalidateProjectContextCache } from \"./project\";\r\nimport type { OAuthAuthDetails, PluginClient, RefreshParts } from \"./types\";\r\n\r\nconst log = createLogger(\"token\");\r\n\r\ninterface OAuthErrorPayload {\r\n error?:\r\n | string\r\n | {\r\n code?: string;\r\n status?: string;\r\n message?: string;\r\n };\r\n error_description?: string;\r\n}\r\n\r\n/**\r\n * Parses OAuth error payloads returned by Google token endpoints, tolerating varied shapes.\r\n */\r\nfunction parseOAuthErrorPayload(text: string | undefined): { code?: string; description?: string } {\r\n if (!text) {\r\n return {};\r\n }\r\n\r\n try {\r\n const payload = JSON.parse(text) as OAuthErrorPayload;\r\n if (!payload || typeof payload !== \"object\") {\r\n return { description: text };\r\n }\r\n\r\n let code: string | undefined;\r\n if (typeof payload.error === \"string\") {\r\n code = payload.error;\r\n } else if (payload.error && typeof payload.error === \"object\") {\r\n code = payload.error.status ?? payload.error.code;\r\n if (!payload.error_description && payload.error.message) {\r\n return { code, description: payload.error.message };\r\n }\r\n }\r\n\r\n const description = payload.error_description;\r\n if (description) {\r\n return { code, description };\r\n }\r\n\r\n if (payload.error && typeof payload.error === \"object\" && payload.error.message) {\r\n return { code, description: payload.error.message };\r\n }\r\n\r\n return { code };\r\n } catch {\r\n return { description: text };\r\n }\r\n}\r\n\r\nexport class AntigravityTokenRefreshError extends Error {\r\n code?: string;\r\n description?: string;\r\n status: number;\r\n statusText: string;\r\n\r\n constructor(options: {\r\n message: string;\r\n code?: string;\r\n description?: string;\r\n status: number;\r\n statusText: string;\r\n }) {\r\n super(options.message);\r\n this.name = \"AntigravityTokenRefreshError\";\r\n this.code = options.code;\r\n this.description = options.description;\r\n this.status = options.status;\r\n this.statusText = options.statusText;\r\n }\r\n}\r\n\r\n/**\r\n * Refreshes an Antigravity OAuth access token, updates persisted credentials, and handles revocation.\r\n */\r\nexport async function refreshAccessToken(\r\n auth: OAuthAuthDetails,\r\n client: PluginClient,\r\n providerId: string,\r\n): Promise<OAuthAuthDetails | undefined> {\r\n const parts = parseRefreshParts(auth.refresh);\r\n if (!parts.refreshToken) {\r\n return undefined;\r\n }\r\n\r\n try {\r\n const startTime = Date.now();\r\n const response = await fetch(\"https://oauth2.googleapis.com/token\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n },\r\n body: new URLSearchParams({\r\n grant_type: \"refresh_token\",\r\n refresh_token: parts.refreshToken,\r\n client_id: ANTIGRAVITY_CLIENT_ID,\r\n client_secret: ANTIGRAVITY_CLIENT_SECRET,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n let errorText: string | undefined;\r\n try {\r\n errorText = await response.text();\r\n } catch {\r\n errorText = undefined;\r\n }\r\n\r\n const { code, description } = parseOAuthErrorPayload(errorText);\r\n const details = [code, description ?? errorText].filter(Boolean).join(\": \");\r\n const baseMessage = `Antigravity token refresh failed (${response.status} ${response.statusText})`;\r\n const message = details ? `${baseMessage} - ${details}` : baseMessage;\r\n log.warn(\"Token refresh failed\", { status: response.status, code, details });\r\n\r\n if (code === \"invalid_grant\") {\r\n log.warn(\"Google revoked the stored refresh token - reauthentication required\");\r\n invalidateProjectContextCache(auth.refresh);\r\n clearCachedAuth(auth.refresh);\r\n }\r\n\r\n throw new AntigravityTokenRefreshError({\r\n message,\r\n code,\r\n description: description ?? errorText,\r\n status: response.status,\r\n statusText: response.statusText,\r\n });\r\n }\r\n\r\n const payload = (await response.json()) as {\r\n access_token: string;\r\n expires_in: number;\r\n refresh_token?: string;\r\n };\r\n\r\n const refreshedParts: RefreshParts = {\r\n refreshToken: payload.refresh_token ?? parts.refreshToken,\r\n projectId: parts.projectId,\r\n managedProjectId: parts.managedProjectId,\r\n };\r\n\r\n const updatedAuth: OAuthAuthDetails = {\r\n ...auth,\r\n access: payload.access_token,\r\n expires: calculateTokenExpiry(startTime, payload.expires_in),\r\n refresh: formatRefreshParts(refreshedParts),\r\n };\r\n\r\n storeCachedAuth(updatedAuth);\r\n invalidateProjectContextCache(auth.refresh);\r\n\r\n return updatedAuth;\r\n } catch (error) {\r\n if (error instanceof AntigravityTokenRefreshError) {\r\n throw error;\r\n }\r\n log.error(\"Unexpected token refresh error\", { error: String(error) });\r\n return undefined;\r\n }\r\n}\r\n\r\n", "import { createServer } from \"node:http\";\r\nimport { readFileSync, existsSync } from \"node:fs\";\r\n\r\nimport { ANTIGRAVITY_REDIRECT_URI } from \"../constants\";\r\n\r\ninterface OAuthListenerOptions {\r\n /**\r\n * How long to wait for the OAuth redirect before timing out (in milliseconds).\r\n */\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface OAuthListener {\r\n /**\r\n * Resolves with the callback URL once Google redirects back to the local server.\r\n */\r\n waitForCallback(): Promise<URL>;\r\n /**\r\n * Cleanly stop listening for callbacks.\r\n */\r\n close(): Promise<void>;\r\n}\r\n\r\nconst redirectUri = new URL(ANTIGRAVITY_REDIRECT_URI);\r\nconst callbackPath = redirectUri.pathname || \"/\";\r\n\r\n/**\r\n * Detect if running in OrbStack Docker with --network host mode.\r\n * OrbStack's host networking only forwards ports bound to 127.0.0.1 to macOS.\r\n */\r\nfunction isOrbStackDockerHost(): boolean {\r\n // Check if we're in Docker\r\n if (!existsSync(\"/.dockerenv\")) {\r\n return false;\r\n }\r\n \r\n // Check for OrbStack-specific indicators\r\n // OrbStack sets specific environment variables or has identifiable characteristics\r\n try {\r\n // OrbStack containers often have /run/.containerenv or specific mount patterns\r\n // Also check if /proc/version contains orbstack\r\n if (existsSync(\"/proc/version\")) {\r\n const version = readFileSync(\"/proc/version\", \"utf8\").toLowerCase();\r\n if (version.includes(\"orbstack\")) {\r\n return true;\r\n }\r\n }\r\n \r\n // Check hostname pattern (OrbStack uses specific patterns)\r\n const hostname = process.env.HOSTNAME || \"\";\r\n if (hostname.startsWith(\"orbstack-\") || hostname.endsWith(\".orb\") || hostname === \"orbstack\") {\r\n return true;\r\n }\r\n \r\n // Check for OrbStack's network host mode by looking at resolv.conf\r\n // OrbStack with --network host has specific DNS configuration\r\n if (existsSync(\"/etc/resolv.conf\")) {\r\n const resolv = readFileSync(\"/etc/resolv.conf\", \"utf8\");\r\n if (resolv.includes(\"orb.local\") || resolv.includes(\"orbstack\")) {\r\n return true;\r\n }\r\n }\r\n \r\n // Fallback: Check if running on macOS/Darwin host via Docker\r\n // This is a heuristic - if in Docker on Linux but /proc/version shows darwin-like patterns\r\n if (process.platform === \"linux\" && existsSync(\"/.dockerenv\")) {\r\n // Most OrbStack containers will have been caught above\r\n // For safety, also check common OrbStack mount patterns\r\n if (existsSync(\"/run/host-services\")) {\r\n return true;\r\n }\r\n }\r\n } catch {\r\n // Ignore errors, fall through to default\r\n }\r\n \r\n return false;\r\n}\r\n\r\n/**\r\n * Detect WSL (Windows Subsystem for Linux) environment.\r\n */\r\nfunction isWSL(): boolean {\r\n if (process.platform !== \"linux\") return false;\r\n try {\r\n const release = readFileSync(\"/proc/version\", \"utf8\").toLowerCase();\r\n return release.includes(\"microsoft\") || release.includes(\"wsl\");\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Detect remote/SSH environment where localhost may not be accessible from browser.\r\n */\r\nfunction isRemoteEnvironment(): boolean {\r\n if (process.env.SSH_CLIENT || process.env.SSH_TTY || process.env.SSH_CONNECTION) {\r\n return true;\r\n }\r\n if (process.env.REMOTE_CONTAINERS || process.env.CODESPACES) {\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Determine the best bind address for the OAuth callback server.\r\n * \r\n * Priority:\r\n * 1. OPENCODE_ANTIGRAVITY_OAUTH_BIND environment variable (user override)\r\n * 2. OrbStack Docker with --network host: 127.0.0.1 (required for port forwarding)\r\n * 3. WSL/SSH/Remote: 0.0.0.0 (needed for cross-network access)\r\n * 4. Default: 127.0.0.1 (most secure for local development)\r\n */\r\nfunction getBindAddress(): string {\r\n // Allow user override via environment variable\r\n const envBind = process.env.OPENCODE_ANTIGRAVITY_OAUTH_BIND;\r\n if (envBind) {\r\n return envBind;\r\n }\r\n \r\n // OrbStack Docker needs 127.0.0.1 for --network host port forwarding\r\n if (isOrbStackDockerHost()) {\r\n return \"127.0.0.1\";\r\n }\r\n \r\n // WSL and remote environments need 0.0.0.0 to be reachable\r\n if (isWSL() || isRemoteEnvironment()) {\r\n return \"0.0.0.0\";\r\n }\r\n \r\n // Default to 127.0.0.1 for security (local-only access)\r\n return \"127.0.0.1\";\r\n}\r\n\r\n/**\r\n * Starts a lightweight HTTP server that listens for the Antigravity OAuth redirect\r\n * and resolves with the captured callback URL.\r\n */\r\nexport async function startOAuthListener(\r\n { timeoutMs = 5 * 60 * 1000 }: OAuthListenerOptions = {},\r\n): Promise<OAuthListener> {\r\n const port = redirectUri.port\r\n ? Number.parseInt(redirectUri.port, 10)\r\n : redirectUri.protocol === \"https:\"\r\n ? 443\r\n : 80;\r\n const origin = `${redirectUri.protocol}//${redirectUri.host}`;\r\n\r\n let settled = false;\r\n let resolveCallback: (url: URL) => void;\r\n let rejectCallback: (error: Error) => void;\r\n let timeoutHandle: NodeJS.Timeout;\r\n const callbackPromise = new Promise<URL>((resolve, reject) => {\r\n resolveCallback = (url: URL) => {\r\n if (settled) return;\r\n settled = true;\r\n if (timeoutHandle) clearTimeout(timeoutHandle);\r\n resolve(url);\r\n };\r\n rejectCallback = (error: Error) => {\r\n if (settled) return;\r\n settled = true;\r\n if (timeoutHandle) clearTimeout(timeoutHandle);\r\n reject(error);\r\n };\r\n });\r\n\r\nconst successResponse = `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n <head>\r\n <meta charset=\"utf-8\" />\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n <title>Authentication Successful</title>\r\n <style>\r\n :root {\r\n --bg: #FAFAFA;\r\n --card-bg: #FFFFFF;\r\n --text-primary: #1F2937;\r\n --text-secondary: #6B7280;\r\n --accent: #2563EB;\r\n --success: #10B981;\r\n --border: #E5E7EB;\r\n }\r\n @media (prefers-color-scheme: dark) {\r\n :root {\r\n --bg: #111827;\r\n --card-bg: #1F2937;\r\n --text-primary: #F9FAFB;\r\n --text-secondary: #9CA3AF;\r\n --accent: #3B82F6;\r\n --success: #34D399;\r\n --border: #374151;\r\n }\r\n }\r\n body {\r\n margin: 0;\r\n min-height: 100vh;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\r\n background: var(--bg);\r\n color: var(--text-primary);\r\n padding: 1rem;\r\n }\r\n .card {\r\n background: var(--card-bg);\r\n border-radius: 16px;\r\n padding: 3rem 2rem;\r\n width: 100%;\r\n max-width: 400px;\r\n text-align: center;\r\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);\r\n border: 1px solid var(--border);\r\n }\r\n .icon-wrapper {\r\n width: 64px;\r\n height: 64px;\r\n background: rgba(16, 185, 129, 0.1);\r\n border-radius: 50%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n margin: 0 auto 1.5rem;\r\n }\r\n .icon {\r\n width: 32px;\r\n height: 32px;\r\n color: var(--success);\r\n }\r\n h1 {\r\n font-size: 1.5rem;\r\n font-weight: 600;\r\n margin: 0 0 0.5rem;\r\n letter-spacing: -0.025em;\r\n }\r\n p {\r\n color: var(--text-secondary);\r\n font-size: 0.95rem;\r\n line-height: 1.5;\r\n margin: 0 0 2rem;\r\n }\r\n .btn {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n background: var(--text-primary);\r\n color: var(--card-bg);\r\n font-weight: 500;\r\n padding: 0.75rem 1.5rem;\r\n border-radius: 8px;\r\n text-decoration: none;\r\n transition: opacity 0.2s;\r\n font-size: 0.95rem;\r\n border: none;\r\n cursor: pointer;\r\n width: 100%;\r\n box-sizing: border-box;\r\n }\r\n .btn:hover {\r\n opacity: 0.9;\r\n }\r\n .sub-text {\r\n margin-top: 1rem;\r\n font-size: 0.8rem;\r\n color: var(--text-secondary);\r\n }\r\n </style>\r\n </head>\r\n <body>\r\n <div class=\"card\">\r\n <div class=\"icon-wrapper\">\r\n <svg class=\"icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2.5\" d=\"M5 13l4 4L19 7\" />\r\n </svg>\r\n </div>\r\n <h1>All set!</h1>\r\n <p>You've successfully authenticated with Antigravity. You can now return to Opencode.</p>\r\n <button class=\"btn\" onclick=\"closeWindow()\">Close this tab</button>\r\n <div class=\"sub-text\">Usage Tip: Most browsers block auto-closing. If the button doesn't work, please close the tab manually.</div>\r\n </div>\r\n <script>\r\n function closeWindow() {\r\n window.close();\r\n // Fallback if window.close() is blocked\r\n document.querySelector('.btn').textContent = \"Tab cannot be closed automatically\";\r\n document.querySelector('.btn').style.opacity = \"0.5\";\r\n document.querySelector('.btn').style.cursor = \"default\";\r\n }\r\n </script>\r\n </body>\r\n</html>`;\r\n\r\n timeoutHandle = setTimeout(() => {\r\n rejectCallback(new Error(\"Timed out waiting for OAuth callback\"));\r\n }, timeoutMs);\r\n timeoutHandle.unref?.();\r\n\r\n const server = createServer((request, response) => {\r\n if (!request.url) {\r\n response.writeHead(400, { \"Content-Type\": \"text/plain\" });\r\n response.end(\"Invalid request\");\r\n return;\r\n }\r\n\r\n const url = new URL(request.url, origin);\r\n if (url.pathname !== callbackPath) {\r\n response.writeHead(404, { \"Content-Type\": \"text/plain\" });\r\n response.end(\"Not found\");\r\n return;\r\n }\r\n\r\n response.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\r\n response.end(successResponse);\r\n\r\n resolveCallback(url);\r\n\r\n setImmediate(() => {\r\n server.close();\r\n });\r\n });\r\n\r\n const bindAddress = getBindAddress();\r\n \r\n await new Promise<void>((resolve, reject) => {\r\n const handleError = (error: NodeJS.ErrnoException) => {\r\n server.off(\"error\", handleError);\r\n if (error.code === \"EADDRINUSE\") {\r\n reject(new Error(\r\n `Port ${port} is already in use. ` +\r\n `Another process is occupying this port. ` +\r\n `Please terminate the process or try again later.`\r\n ));\r\n return;\r\n }\r\n reject(error);\r\n };\r\n server.once(\"error\", handleError);\r\n server.listen(port, bindAddress, () => {\r\n server.off(\"error\", handleError);\r\n resolve();\r\n });\r\n });\r\n\r\n server.on(\"error\", (error) => {\r\n rejectCallback(error instanceof Error ? error : new Error(String(error)));\r\n });\r\n\r\n return {\r\n waitForCallback: () => callbackPromise,\r\n close: () =>\r\n new Promise<void>((resolve, reject) => {\r\n server.close((error) => {\r\n if (error && (error as NodeJS.ErrnoException).code !== \"ERR_SERVER_NOT_RUNNING\") {\r\n reject(error);\r\n return;\r\n }\r\n if (!settled) {\r\n rejectCallback(new Error(\"OAuth listener closed before callback\"));\r\n }\r\n resolve();\r\n });\r\n }),\r\n };\r\n}\r\n", "/**\r\n * Account Rotation System\r\n * \r\n * Implements advanced account selection algorithms:\r\n * - Health Score: Track account wellness based on success/failure\r\n * - LRU Selection: Prefer accounts with longest rest periods\r\n * - Jitter: Add random variance to break predictable patterns\r\n * \r\n * Used by 'hybrid' strategy for improved ban prevention and load distribution.\r\n */\r\n\r\n// ============================================================================\r\n// HEALTH SCORE SYSTEM\r\n// ============================================================================\r\n\r\nexport interface HealthScoreConfig {\r\n /** Initial score for new accounts (default: 70) */\r\n initial: number;\r\n /** Points added on successful request (default: 1) */\r\n successReward: number;\r\n /** Points removed on rate limit (default: -10) */\r\n rateLimitPenalty: number;\r\n /** Points removed on failure (auth, network, etc.) (default: -20) */\r\n failurePenalty: number;\r\n /** Points recovered per hour of rest (default: 2) */\r\n recoveryRatePerHour: number;\r\n /** Minimum score to be considered usable (default: 50) */\r\n minUsable: number;\r\n /** Maximum score cap (default: 100) */\r\n maxScore: number;\r\n}\r\n\r\nexport const DEFAULT_HEALTH_SCORE_CONFIG: HealthScoreConfig = {\r\n initial: 70,\r\n successReward: 1,\r\n rateLimitPenalty: -10,\r\n failurePenalty: -20,\r\n recoveryRatePerHour: 2,\r\n minUsable: 50,\r\n maxScore: 100,\r\n};\r\n\r\ninterface HealthScoreState {\r\n score: number;\r\n lastUpdated: number;\r\n lastSuccess: number;\r\n consecutiveFailures: number;\r\n}\r\n\r\n/**\r\n * Tracks health scores for accounts.\r\n * Higher score = healthier account = preferred for selection.\r\n */\r\nexport class HealthScoreTracker {\r\n private readonly scores = new Map<number, HealthScoreState>();\r\n private readonly config: HealthScoreConfig;\r\n\r\n constructor(config: Partial<HealthScoreConfig> = {}) {\r\n this.config = { ...DEFAULT_HEALTH_SCORE_CONFIG, ...config };\r\n }\r\n\r\n /**\r\n * Get current health score for an account, applying time-based recovery.\r\n */\r\n getScore(accountIndex: number): number {\r\n const state = this.scores.get(accountIndex);\r\n if (!state) {\r\n return this.config.initial;\r\n }\r\n\r\n // Apply passive recovery based on time since last update\r\n const now = Date.now();\r\n const hoursSinceUpdate = (now - state.lastUpdated) / (1000 * 60 * 60);\r\n const recoveredPoints = Math.floor(hoursSinceUpdate * this.config.recoveryRatePerHour);\r\n \r\n return Math.min(\r\n this.config.maxScore,\r\n state.score + recoveredPoints\r\n );\r\n }\r\n\r\n /**\r\n * Record a successful request - improves health score.\r\n */\r\n recordSuccess(accountIndex: number): void {\r\n const now = Date.now();\r\n const current = this.getScore(accountIndex);\r\n \r\n this.scores.set(accountIndex, {\r\n score: Math.min(this.config.maxScore, current + this.config.successReward),\r\n lastUpdated: now,\r\n lastSuccess: now,\r\n consecutiveFailures: 0,\r\n });\r\n }\r\n\r\n /**\r\n * Record a rate limit hit - moderate penalty.\r\n */\r\n recordRateLimit(accountIndex: number): void {\r\n const now = Date.now();\r\n const state = this.scores.get(accountIndex);\r\n const current = this.getScore(accountIndex);\r\n \r\n this.scores.set(accountIndex, {\r\n score: Math.max(0, current + this.config.rateLimitPenalty),\r\n lastUpdated: now,\r\n lastSuccess: state?.lastSuccess ?? 0,\r\n consecutiveFailures: (state?.consecutiveFailures ?? 0) + 1,\r\n });\r\n }\r\n\r\n /**\r\n * Record a failure (auth, network, etc.) - larger penalty.\r\n */\r\n recordFailure(accountIndex: number): void {\r\n const now = Date.now();\r\n const state = this.scores.get(accountIndex);\r\n const current = this.getScore(accountIndex);\r\n \r\n this.scores.set(accountIndex, {\r\n score: Math.max(0, current + this.config.failurePenalty),\r\n lastUpdated: now,\r\n lastSuccess: state?.lastSuccess ?? 0,\r\n consecutiveFailures: (state?.consecutiveFailures ?? 0) + 1,\r\n });\r\n }\r\n\r\n /**\r\n * Check if account is healthy enough to use.\r\n */\r\n isUsable(accountIndex: number): boolean {\r\n return this.getScore(accountIndex) >= this.config.minUsable;\r\n }\r\n\r\n /**\r\n * Get consecutive failure count for an account.\r\n */\r\n getConsecutiveFailures(accountIndex: number): number {\r\n return this.scores.get(accountIndex)?.consecutiveFailures ?? 0;\r\n }\r\n\r\n /**\r\n * Reset health state for an account (e.g., after removal).\r\n */\r\n reset(accountIndex: number): void {\r\n this.scores.delete(accountIndex);\r\n }\r\n\r\n /**\r\n * Get all scores for debugging/logging.\r\n */\r\n getSnapshot(): Map<number, { score: number; consecutiveFailures: number }> {\r\n const result = new Map<number, { score: number; consecutiveFailures: number }>();\r\n for (const [index] of this.scores) {\r\n result.set(index, {\r\n score: this.getScore(index),\r\n consecutiveFailures: this.getConsecutiveFailures(index),\r\n });\r\n }\r\n return result;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// JITTER UTILITIES\r\n// ============================================================================\r\n\r\n/**\r\n * Add random jitter to a delay value.\r\n * Helps break predictable timing patterns.\r\n * \r\n * @param baseMs - Base delay in milliseconds\r\n * @param jitterFactor - Fraction of base to vary (default: 0.3 = \u00B130%)\r\n * @returns Jittered delay in milliseconds\r\n */\r\nexport function addJitter(baseMs: number, jitterFactor: number = 0.3): number {\r\n const jitterRange = baseMs * jitterFactor;\r\n const jitter = (Math.random() * 2 - 1) * jitterRange; // -jitterRange to +jitterRange\r\n return Math.max(0, Math.round(baseMs + jitter));\r\n}\r\n\r\n/**\r\n * Generate a random delay within a range.\r\n * \r\n * @param minMs - Minimum delay in milliseconds\r\n * @param maxMs - Maximum delay in milliseconds\r\n * @returns Random delay between min and max\r\n */\r\nexport function randomDelay(minMs: number, maxMs: number): number {\r\n return Math.round(minMs + Math.random() * (maxMs - minMs));\r\n}\r\n\r\n// ============================================================================\r\n// LRU SELECTION\r\n// ============================================================================\r\n\r\nexport interface AccountWithMetrics {\r\n index: number;\r\n lastUsed: number;\r\n healthScore: number;\r\n isRateLimited: boolean;\r\n isCoolingDown: boolean;\r\n}\r\n\r\n/**\r\n * Sort accounts by LRU (least recently used first) with health score tiebreaker.\r\n * \r\n * Priority:\r\n * 1. Filter out rate-limited and cooling-down accounts\r\n * 2. Filter out unhealthy accounts (score < minUsable)\r\n * 3. Sort by lastUsed ascending (oldest first = most rested)\r\n * 4. Tiebreaker: higher health score wins\r\n */\r\nexport function sortByLruWithHealth(\r\n accounts: AccountWithMetrics[],\r\n minHealthScore: number = 50,\r\n): AccountWithMetrics[] {\r\n return accounts\r\n .filter(acc => !acc.isRateLimited && !acc.isCoolingDown && acc.healthScore >= minHealthScore)\r\n .sort((a, b) => {\r\n // Primary: LRU (oldest lastUsed first)\r\n const lruDiff = a.lastUsed - b.lastUsed;\r\n if (lruDiff !== 0) return lruDiff;\r\n \r\n // Tiebreaker: higher health score wins\r\n return b.healthScore - a.healthScore;\r\n });\r\n}\r\n\r\n/** Stickiness bonus added to current account's score to prevent unnecessary switching */\r\nconst STICKINESS_BONUS = 150;\r\n\r\n/** Minimum score advantage required to switch away from current account */\r\nconst SWITCH_THRESHOLD = 100;\r\n\r\n/**\r\n * Select account using hybrid strategy with stickiness:\r\n * 1. Filter available accounts (not rate-limited, not cooling down, healthy, has tokens)\r\n * 2. Calculate priority score: health (2x) + tokens (5x) + freshness (0.1x)\r\n * 3. Apply stickiness bonus to current account\r\n * 4. Only switch if another account beats current by SWITCH_THRESHOLD\r\n * \r\n * @param accounts - All accounts with their metrics\r\n * @param tokenTracker - Token bucket tracker for token balances\r\n * @param currentAccountIndex - Currently active account index (for stickiness)\r\n * @param minHealthScore - Minimum health score to be considered\r\n * @returns Best account index, or null if none available\r\n */\r\nexport function selectHybridAccount(\r\n accounts: AccountWithMetrics[],\r\n tokenTracker: TokenBucketTracker,\r\n currentAccountIndex: number | null = null,\r\n minHealthScore: number = 50,\r\n): number | null {\r\n const candidates = accounts\r\n .filter(acc => \r\n !acc.isRateLimited && \r\n !acc.isCoolingDown && \r\n acc.healthScore >= minHealthScore &&\r\n tokenTracker.hasTokens(acc.index)\r\n )\r\n .map(acc => ({\r\n ...acc,\r\n tokens: tokenTracker.getTokens(acc.index)\r\n }));\r\n\r\n if (candidates.length === 0) {\r\n return null;\r\n }\r\n\r\n const maxTokens = tokenTracker.getMaxTokens();\r\n const scored = candidates\r\n .map(acc => {\r\n const baseScore = calculateHybridScore(acc, maxTokens);\r\n // Apply stickiness bonus to current account\r\n const stickinessBonus = acc.index === currentAccountIndex ? STICKINESS_BONUS : 0;\r\n return {\r\n index: acc.index,\r\n baseScore,\r\n score: baseScore + stickinessBonus,\r\n isCurrent: acc.index === currentAccountIndex\r\n };\r\n })\r\n .sort((a, b) => b.score - a.score);\r\n\r\n const best = scored[0];\r\n if (!best) {\r\n return null;\r\n }\r\n\r\n // If current account is still a candidate, check if switch is warranted\r\n const currentCandidate = scored.find(s => s.isCurrent);\r\n if (currentCandidate && !best.isCurrent) {\r\n // Only switch if best beats current's BASE score by threshold\r\n // (compare base scores to avoid circular stickiness bonus comparison)\r\n const advantage = best.baseScore - currentCandidate.baseScore;\r\n if (advantage < SWITCH_THRESHOLD) {\r\n return currentCandidate.index;\r\n }\r\n }\r\n\r\n return best.index;\r\n}\r\n\r\ninterface AccountWithTokens extends AccountWithMetrics {\r\n tokens: number;\r\n}\r\n\r\nfunction calculateHybridScore(\r\n account: AccountWithTokens,\r\n maxTokens: number\r\n): number {\r\n const healthComponent = account.healthScore * 2; // 0-200\r\n const tokenComponent = (account.tokens / maxTokens) * 100 * 5; // 0-500\r\n const secondsSinceUsed = (Date.now() - account.lastUsed) / 1000;\r\n const freshnessComponent = Math.min(secondsSinceUsed, 3600) * 0.1; // 0-360\r\n return Math.max(0, healthComponent + tokenComponent + freshnessComponent);\r\n}\r\n\r\n// ============================================================================\r\n// TOKEN BUCKET SYSTEM\r\n// ============================================================================\r\n\r\nexport interface TokenBucketConfig {\r\n /** Maximum tokens per account (default: 50) */\r\n maxTokens: number;\r\n /** Tokens regenerated per minute (default: 6) */\r\n regenerationRatePerMinute: number;\r\n /** Initial tokens for new accounts (default: 50) */\r\n initialTokens: number;\r\n}\r\n\r\nexport const DEFAULT_TOKEN_BUCKET_CONFIG: TokenBucketConfig = {\r\n maxTokens: 50,\r\n regenerationRatePerMinute: 6,\r\n initialTokens: 50,\r\n};\r\n\r\ninterface TokenBucketState {\r\n tokens: number;\r\n lastUpdated: number;\r\n}\r\n\r\n/**\r\n * Client-side rate limiting using Token Bucket algorithm.\r\n * Helps prevent hitting server 429s by tracking \"cost\" of requests.\r\n */\r\nexport class TokenBucketTracker {\r\n private readonly buckets = new Map<number, TokenBucketState>();\r\n private readonly config: TokenBucketConfig;\r\n\r\n constructor(config: Partial<TokenBucketConfig> = {}) {\r\n this.config = { ...DEFAULT_TOKEN_BUCKET_CONFIG, ...config };\r\n }\r\n\r\n /**\r\n * Get current token balance for an account, applying regeneration.\r\n */\r\n getTokens(accountIndex: number): number {\r\n const state = this.buckets.get(accountIndex);\r\n if (!state) {\r\n return this.config.initialTokens;\r\n }\r\n\r\n const now = Date.now();\r\n const minutesSinceUpdate = (now - state.lastUpdated) / (1000 * 60);\r\n const recoveredTokens = minutesSinceUpdate * this.config.regenerationRatePerMinute;\r\n \r\n return Math.min(\r\n this.config.maxTokens,\r\n state.tokens + recoveredTokens\r\n );\r\n }\r\n\r\n /**\r\n * Check if account has enough tokens for a request.\r\n * @param cost Cost of the request (default: 1)\r\n */\r\n hasTokens(accountIndex: number, cost: number = 1): boolean {\r\n return this.getTokens(accountIndex) >= cost;\r\n }\r\n\r\n /**\r\n * Consume tokens for a request.\r\n * @returns true if tokens were consumed, false if insufficient\r\n */\r\n consume(accountIndex: number, cost: number = 1): boolean {\r\n const current = this.getTokens(accountIndex);\r\n if (current < cost) {\r\n return false;\r\n }\r\n\r\n this.buckets.set(accountIndex, {\r\n tokens: current - cost,\r\n lastUpdated: Date.now(),\r\n });\r\n return true;\r\n }\r\n\r\n /**\r\n * Refund tokens (e.g., if request wasn't actually sent).\r\n */\r\n refund(accountIndex: number, amount: number = 1): void {\r\n const current = this.getTokens(accountIndex);\r\n this.buckets.set(accountIndex, {\r\n tokens: Math.min(this.config.maxTokens, current + amount),\r\n lastUpdated: Date.now(),\r\n });\r\n }\r\n\r\n getMaxTokens(): number {\r\n return this.config.maxTokens;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// SINGLETON TRACKERS\r\n// ============================================================================\r\n\r\nlet globalTokenTracker: TokenBucketTracker | null = null;\r\n\r\nexport function getTokenTracker(): TokenBucketTracker {\r\n if (!globalTokenTracker) {\r\n globalTokenTracker = new TokenBucketTracker();\r\n }\r\n return globalTokenTracker;\r\n}\r\n\r\nexport function initTokenTracker(config: Partial<TokenBucketConfig>): TokenBucketTracker {\r\n globalTokenTracker = new TokenBucketTracker(config);\r\n return globalTokenTracker;\r\n}\r\n\r\nlet globalHealthTracker: HealthScoreTracker | null = null;\r\n\r\n/**\r\n * Get the global health score tracker instance.\r\n * Creates one with default config if not initialized.\r\n */\r\nexport function getHealthTracker(): HealthScoreTracker {\r\n if (!globalHealthTracker) {\r\n globalHealthTracker = new HealthScoreTracker();\r\n }\r\n return globalHealthTracker;\r\n}\r\n\r\n/**\r\n * Initialize the global health tracker with custom config.\r\n * Call this at plugin startup if custom config is needed.\r\n */\r\nexport function initHealthTracker(config: Partial<HealthScoreConfig>): HealthScoreTracker {\r\n globalHealthTracker = new HealthScoreTracker(config);\r\n return globalHealthTracker;\r\n}\r\n", "import { formatRefreshParts, parseRefreshParts } from \"./auth\";\r\nimport { loadAccounts, saveAccounts, type AccountStorageV4, type AccountMetadataV3, type RateLimitStateV3, type ModelFamily, type HeaderStyle, type CooldownReason } from \"./storage\";\r\nimport type { OAuthAuthDetails, RefreshParts } from \"./types\";\r\nimport type { AccountSelectionStrategy } from \"./config/schema\";\r\nimport { getHealthTracker, getTokenTracker, selectHybridAccount, type AccountWithMetrics } from \"./rotation\";\r\nimport { generateFingerprint, updateFingerprintVersion, type Fingerprint, type FingerprintVersion, MAX_FINGERPRINT_HISTORY } from \"./fingerprint\";\r\nimport type { QuotaGroup, QuotaGroupSummary } from \"./quota\";\r\nimport { getModelFamily } from \"./transform/model-resolver\";\r\nimport { debugLogToFile } from \"./debug\";\r\nimport { formatAccountLabel } from \"./logging-utils\";\r\n\r\n\r\nexport type { ModelFamily, HeaderStyle, CooldownReason } from \"./storage\";\r\nexport type { AccountSelectionStrategy } from \"./config/schema\";\r\n\r\n\r\nexport type RateLimitReason = \r\n | \"QUOTA_EXHAUSTED\"\r\n | \"RATE_LIMIT_EXCEEDED\" \r\n | \"MODEL_CAPACITY_EXHAUSTED\"\r\n | \"SERVER_ERROR\"\r\n | \"UNKNOWN\";\r\n\r\nexport interface RateLimitBackoffResult {\r\n backoffMs: number;\r\n reason: RateLimitReason;\r\n}\r\n\r\nconst QUOTA_EXHAUSTED_BACKOFFS = [60_000, 300_000, 1_800_000, 7_200_000] as const;\r\nconst RATE_LIMIT_EXCEEDED_BACKOFF = 30_000;\r\n// Increased from 15s to 45s base + jitter to reduce retry pressure on capacity errors\r\nconst MODEL_CAPACITY_EXHAUSTED_BASE_BACKOFF = 45_000;\r\nconst MODEL_CAPACITY_EXHAUSTED_JITTER_MAX = 30_000; // \u00B115s jitter range\r\nconst SERVER_ERROR_BACKOFF = 20_000;\r\nconst UNKNOWN_BACKOFF = 60_000;\r\nconst MIN_BACKOFF_MS = 2_000;\r\n\r\n/**\r\n * Generate a random jitter value for backoff timing.\r\n * Helps prevent thundering herd problem when multiple clients retry simultaneously.\r\n */\r\nfunction generateJitter(maxJitterMs: number): number {\r\n return Math.random() * maxJitterMs - (maxJitterMs / 2);\r\n}\r\n\r\nexport function parseRateLimitReason(\r\n reason: string | undefined, \r\n message: string | undefined, \r\n status?: number\r\n): RateLimitReason {\r\n // 1. Status Code Checks (Rust parity)\r\n // 529 = Site Overloaded, 503 = Service Unavailable -> Capacity issues\r\n if (status === 529 || status === 503) return \"MODEL_CAPACITY_EXHAUSTED\";\r\n // 500 = Internal Server Error -> Treat as Server Error (soft wait)\r\n if (status === 500) return \"SERVER_ERROR\";\r\n\r\n // 2. Explicit Reason String\r\n if (reason) {\r\n switch (reason.toUpperCase()) {\r\n case \"QUOTA_EXHAUSTED\": return \"QUOTA_EXHAUSTED\";\r\n case \"RATE_LIMIT_EXCEEDED\": return \"RATE_LIMIT_EXCEEDED\";\r\n case \"MODEL_CAPACITY_EXHAUSTED\": return \"MODEL_CAPACITY_EXHAUSTED\";\r\n }\r\n }\r\n \r\n // 3. Message Text Scanning (Rust Regex parity)\r\n if (message) {\r\n const lower = message.toLowerCase();\r\n \r\n // Capacity / Overloaded (Transient) - Check FIRST before \"exhausted\"\r\n if (lower.includes(\"capacity\") || lower.includes(\"overloaded\") || lower.includes(\"resource exhausted\")) {\r\n return \"MODEL_CAPACITY_EXHAUSTED\";\r\n }\r\n\r\n // RPM / TPM (Short Wait)\r\n // \"per minute\", \"rate limit\", \"too many requests\"\r\n // \"presque\" (French: almost) - retained for i18n parity with Rust reference\r\n if (lower.includes(\"per minute\") || lower.includes(\"rate limit\") || lower.includes(\"too many requests\") || lower.includes(\"presque\")) {\r\n return \"RATE_LIMIT_EXCEEDED\";\r\n }\r\n\r\n // Quota (Long Wait)\r\n if (lower.includes(\"exhausted\") || lower.includes(\"quota\")) {\r\n return \"QUOTA_EXHAUSTED\";\r\n }\r\n }\r\n \r\n // Default fallback for 429 without clearer info\r\n if (status === 429) {\r\n return \"UNKNOWN\"; \r\n }\r\n \r\n return \"UNKNOWN\";\r\n}\r\n\r\nexport function calculateBackoffMs(\r\n reason: RateLimitReason,\r\n consecutiveFailures: number,\r\n retryAfterMs?: number | null\r\n): number {\r\n // Respect explicit Retry-After header if reasonable\r\n if (retryAfterMs && retryAfterMs > 0) {\r\n // Rust uses 2s min buffer, we keep 2s\r\n return Math.max(retryAfterMs, MIN_BACKOFF_MS);\r\n }\r\n \r\n switch (reason) {\r\n case \"QUOTA_EXHAUSTED\": {\r\n const index = Math.min(consecutiveFailures, QUOTA_EXHAUSTED_BACKOFFS.length - 1);\r\n return QUOTA_EXHAUSTED_BACKOFFS[index] ?? UNKNOWN_BACKOFF;\r\n }\r\n case \"RATE_LIMIT_EXCEEDED\":\r\n return RATE_LIMIT_EXCEEDED_BACKOFF; // 30s\r\n case \"MODEL_CAPACITY_EXHAUSTED\":\r\n // Apply jitter to prevent thundering herd on capacity errors\r\n return MODEL_CAPACITY_EXHAUSTED_BASE_BACKOFF + generateJitter(MODEL_CAPACITY_EXHAUSTED_JITTER_MAX);\r\n case \"SERVER_ERROR\":\r\n return SERVER_ERROR_BACKOFF; // 20s\r\n case \"UNKNOWN\":\r\n default:\r\n return UNKNOWN_BACKOFF; // 60s\r\n }\r\n}\r\n\r\nexport type BaseQuotaKey = \"claude\" | \"gemini-antigravity\" | \"gemini-cli\";\r\nexport type QuotaKey = BaseQuotaKey | `${BaseQuotaKey}:${string}`;\r\n\r\nexport interface ManagedAccount {\r\n index: number;\r\n email?: string;\r\n addedAt: number;\r\n lastUsed: number;\r\n parts: RefreshParts;\r\n access?: string;\r\n expires?: number;\r\n enabled: boolean;\r\n rateLimitResetTimes: RateLimitStateV3;\r\n lastSwitchReason?: \"rate-limit\" | \"initial\" | \"rotation\";\r\n coolingDownUntil?: number;\r\n cooldownReason?: CooldownReason;\r\n touchedForQuota: Record<string, number>;\r\n consecutiveFailures?: number;\r\n /** Timestamp of last failure for TTL-based reset of consecutiveFailures */\r\n lastFailureTime?: number;\r\n /** Per-account device fingerprint for rate limit mitigation */\r\n fingerprint?: import(\"./fingerprint\").Fingerprint;\r\n /** History of previous fingerprints for this account */\r\n fingerprintHistory?: FingerprintVersion[];\r\n /** Cached quota data from last checkAccountsQuota() call */\r\n cachedQuota?: Partial<Record<QuotaGroup, QuotaGroupSummary>>;\r\n cachedQuotaUpdatedAt?: number;\r\n verificationRequired?: boolean;\r\n verificationRequiredAt?: number;\r\n verificationRequiredReason?: string;\r\n verificationUrl?: string;\r\n}\r\n\r\nfunction nowMs(): number {\r\n return Date.now();\r\n}\r\n\r\nfunction clampNonNegativeInt(value: unknown, fallback: number): number {\r\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\r\n return fallback;\r\n }\r\n return value < 0 ? 0 : Math.floor(value);\r\n}\r\n\r\nfunction getQuotaKey(family: ModelFamily, headerStyle: HeaderStyle, model?: string | null): QuotaKey {\r\n if (family === \"claude\") {\r\n return \"claude\";\r\n }\r\n const base = headerStyle === \"gemini-cli\" ? \"gemini-cli\" : \"gemini-antigravity\";\r\n if (model) {\r\n return `${base}:${model}`;\r\n }\r\n return base;\r\n}\r\n\r\nfunction isRateLimitedForQuotaKey(account: ManagedAccount, key: QuotaKey): boolean {\r\n const resetTime = account.rateLimitResetTimes[key];\r\n return resetTime !== undefined && nowMs() < resetTime;\r\n}\r\n\r\nfunction isRateLimitedForFamily(account: ManagedAccount, family: ModelFamily, model?: string | null): boolean {\r\n if (family === \"claude\") {\r\n return isRateLimitedForQuotaKey(account, \"claude\");\r\n }\r\n \r\n const antigravityIsLimited = isRateLimitedForHeaderStyle(account, family, \"antigravity\", model);\r\n const cliIsLimited = isRateLimitedForHeaderStyle(account, family, \"gemini-cli\", model);\r\n \r\n return antigravityIsLimited && cliIsLimited;\r\n}\r\n\r\nfunction isRateLimitedForHeaderStyle(account: ManagedAccount, family: ModelFamily, headerStyle: HeaderStyle, model?: string | null): boolean {\r\n clearExpiredRateLimits(account);\r\n \r\n if (family === \"claude\") {\r\n return isRateLimitedForQuotaKey(account, \"claude\");\r\n }\r\n\r\n // Check model-specific quota first if provided\r\n if (model) {\r\n const modelKey = getQuotaKey(family, headerStyle, model);\r\n if (isRateLimitedForQuotaKey(account, modelKey)) {\r\n return true;\r\n }\r\n }\r\n\r\n // Then check base family quota\r\n const baseKey = getQuotaKey(family, headerStyle);\r\n return isRateLimitedForQuotaKey(account, baseKey);\r\n}\r\n\r\nfunction clearExpiredRateLimits(account: ManagedAccount): void {\r\n const now = nowMs();\r\n const keys = Object.keys(account.rateLimitResetTimes) as QuotaKey[];\r\n for (const key of keys) {\r\n const resetTime = account.rateLimitResetTimes[key];\r\n if (resetTime !== undefined && now >= resetTime) {\r\n delete account.rateLimitResetTimes[key];\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Resolve the quota group for soft quota checks.\r\n * \r\n * When a model string is available, we can precisely determine the quota group.\r\n * When model is null/undefined, we fall back based on family:\r\n * - Claude \u2192 \"claude\" quota group\r\n * - Gemini \u2192 \"gemini-pro\" (conservative fallback; may misclassify flash models)\r\n * \r\n * @param family - The model family (\"claude\" | \"gemini\")\r\n * @param model - Optional model string for precise resolution\r\n * @returns The QuotaGroup to use for soft quota checks\r\n */\r\nexport function resolveQuotaGroup(family: ModelFamily, model?: string | null): QuotaGroup {\r\n if (model) {\r\n return getModelFamily(model);\r\n }\r\n return family === \"claude\" ? \"claude\" : \"gemini-pro\";\r\n}\r\n\r\nfunction isOverSoftQuotaThreshold(\r\n account: ManagedAccount,\r\n family: ModelFamily,\r\n thresholdPercent: number,\r\n cacheTtlMs: number,\r\n model?: string | null\r\n): boolean {\r\n if (thresholdPercent >= 100) return false;\r\n if (!account.cachedQuota) return false;\r\n \r\n if (account.cachedQuotaUpdatedAt == null) return false;\r\n const age = nowMs() - account.cachedQuotaUpdatedAt;\r\n if (age > cacheTtlMs) return false;\r\n \r\n const quotaGroup = resolveQuotaGroup(family, model);\r\n \r\n const groupData = account.cachedQuota[quotaGroup];\r\n if (groupData?.remainingFraction == null) return false;\r\n \r\n const remainingFraction = Math.max(0, Math.min(1, groupData.remainingFraction));\r\n const usedPercent = (1 - remainingFraction) * 100;\r\n const isOverThreshold = usedPercent >= thresholdPercent;\r\n \r\n if (isOverThreshold) {\r\n const accountLabel = formatAccountLabel(account.email, account.index);\r\n const resetSuffix = groupData.resetTime ? ` (resets: ${groupData.resetTime})` : \"\";\r\n const message = `[SoftQuota] Skipping ${accountLabel}: ${quotaGroup} usage ${usedPercent.toFixed(1)}% >= threshold ${thresholdPercent}%${resetSuffix}`;\r\n debugLogToFile(message);\r\n }\r\n \r\n return isOverThreshold;\r\n}\r\n\r\nexport function computeSoftQuotaCacheTtlMs(\r\n ttlConfig: \"auto\" | number,\r\n refreshIntervalMinutes: number\r\n): number {\r\n if (ttlConfig === \"auto\") {\r\n return Math.max(2 * refreshIntervalMinutes, 10) * 60 * 1000;\r\n }\r\n return ttlConfig * 60 * 1000;\r\n}\r\n\r\n/**\r\n * In-memory multi-account manager with sticky account selection.\r\n *\r\n * Uses the same account until it hits a rate limit (429), then switches.\r\n * Rate limits are tracked per-model-family (claude/gemini) so an account\r\n * rate-limited for Claude can still be used for Gemini.\r\n *\r\n * Source of truth for the pool is `antigravity-accounts.json`.\r\n */\r\nexport class AccountManager {\r\n private accounts: ManagedAccount[] = [];\r\n private cursor = 0;\r\n private currentAccountIndexByFamily: Record<ModelFamily, number> = {\r\n claude: -1,\r\n gemini: -1,\r\n };\r\n private sessionOffsetApplied: Record<ModelFamily, boolean> = {\r\n claude: false,\r\n gemini: false,\r\n };\r\n private lastToastAccountIndex = -1;\r\n private lastToastTime = 0;\r\n\r\n private savePending = false;\r\n private saveTimeout: ReturnType<typeof setTimeout> | null = null;\r\n private savePromiseResolvers: Array<{ resolve: () => void; reject: (err: unknown) => void }> = [];\r\n\r\n static async loadFromDisk(authFallback?: OAuthAuthDetails): Promise<AccountManager> {\r\n const stored = await loadAccounts();\r\n return new AccountManager(authFallback, stored);\r\n }\r\n\r\n constructor(authFallback?: OAuthAuthDetails, stored?: AccountStorageV4 | null) {\r\n const authParts = authFallback ? parseRefreshParts(authFallback.refresh) : null;\r\n\r\n if (stored && stored.accounts.length === 0) {\r\n this.accounts = [];\r\n this.cursor = 0;\r\n return;\r\n }\r\n\r\n if (stored && stored.accounts.length > 0) {\r\n const baseNow = nowMs();\r\n this.accounts = stored.accounts\r\n .map((acc, index): ManagedAccount | null => {\r\n if (!acc.refreshToken || typeof acc.refreshToken !== \"string\") {\r\n return null;\r\n }\r\n const matchesFallback = !!(\r\n authFallback &&\r\n authParts &&\r\n authParts.refreshToken &&\r\n acc.refreshToken === authParts.refreshToken\r\n );\r\n\r\n return {\r\n index,\r\n email: acc.email,\r\n addedAt: clampNonNegativeInt(acc.addedAt, baseNow),\r\n lastUsed: clampNonNegativeInt(acc.lastUsed, 0),\r\n parts: {\r\n refreshToken: acc.refreshToken,\r\n projectId: acc.projectId,\r\n managedProjectId: acc.managedProjectId,\r\n },\r\n access: matchesFallback ? authFallback?.access : undefined,\r\n expires: matchesFallback ? authFallback?.expires : undefined,\r\n enabled: acc.enabled !== false,\r\n rateLimitResetTimes: acc.rateLimitResetTimes ?? {},\r\n lastSwitchReason: acc.lastSwitchReason,\r\n coolingDownUntil: acc.coolingDownUntil,\r\n cooldownReason: acc.cooldownReason,\r\n touchedForQuota: {},\r\n fingerprint: acc.fingerprint ?? generateFingerprint(),\r\n fingerprintHistory: acc.fingerprintHistory ?? [],\r\n cachedQuota: acc.cachedQuota as Partial<Record<QuotaGroup, QuotaGroupSummary>> | undefined,\r\n cachedQuotaUpdatedAt: acc.cachedQuotaUpdatedAt,\r\n verificationRequired: acc.verificationRequired,\r\n verificationRequiredAt: acc.verificationRequiredAt,\r\n verificationRequiredReason: acc.verificationRequiredReason,\r\n verificationUrl: acc.verificationUrl,\r\n };\r\n })\r\n .filter((a): a is ManagedAccount => a !== null);\r\n\r\n // Update fingerprint versions to match the current runtime version.\r\n // Saved fingerprints may carry an older version string; this ensures\r\n // they always reflect the latest fetched (or fallback) version.\r\n let fingerprintVersionChanged = false;\r\n for (const acc of this.accounts) {\r\n if (acc.fingerprint && updateFingerprintVersion(acc.fingerprint)) {\r\n fingerprintVersionChanged = true;\r\n }\r\n }\r\n\r\n this.cursor = clampNonNegativeInt(stored.activeIndex, 0);\r\n if (this.accounts.length > 0) {\r\n this.cursor = this.cursor % this.accounts.length;\r\n const defaultIndex = this.cursor;\r\n this.currentAccountIndexByFamily.claude = clampNonNegativeInt(\r\n stored.activeIndexByFamily?.claude,\r\n defaultIndex\r\n ) % this.accounts.length;\r\n this.currentAccountIndexByFamily.gemini = clampNonNegativeInt(\r\n stored.activeIndexByFamily?.gemini,\r\n defaultIndex\r\n ) % this.accounts.length;\r\n }\r\n\r\n // Persist updated fingerprint versions to disk\n if (fingerprintVersionChanged) {\n this.requestSaveToDisk();\n }\n\n // If current auth isn't in the loaded accounts, add it to the pool\n if (authFallback && authParts && authParts.refreshToken) {\n const hasMatching = this.accounts.some(acc => acc.parts.refreshToken === authParts.refreshToken);\n if (!hasMatching) {\n const now = nowMs();\n const newAccount: ManagedAccount = {\n index: this.accounts.length,\n email: undefined,\n addedAt: now,\n lastUsed: 0,\n parts: authParts,\n access: authFallback.access,\n expires: authFallback.expires,\n enabled: true,\n rateLimitResetTimes: {},\n touchedForQuota: {},\n fingerprint: generateFingerprint(),\n fingerprintHistory: [],\n };\n this.accounts.push(newAccount);\n }\n }\n\n return;\n }\n\n if (authFallback) { const parts = parseRefreshParts(authFallback.refresh);\r\n if (parts.refreshToken) {\r\n const now = nowMs();\r\n this.accounts = [\r\n {\r\n index: 0,\r\n email: undefined,\r\n addedAt: now,\r\n lastUsed: 0,\r\n parts,\r\n access: authFallback.access,\r\n expires: authFallback.expires,\r\n enabled: true,\r\n rateLimitResetTimes: {},\r\n touchedForQuota: {},\r\n },\r\n ];\r\n this.cursor = 0;\r\n this.currentAccountIndexByFamily.claude = 0;\r\n this.currentAccountIndexByFamily.gemini = 0;\r\n }\r\n }\r\n }\r\n\r\n getAccountCount(): number {\r\n return this.getEnabledAccounts().length;\r\n }\r\n\r\n getTotalAccountCount(): number {\r\n return this.accounts.length;\r\n }\r\n\r\n getEnabledAccounts(): ManagedAccount[] {\r\n return this.accounts.filter((account) => account.enabled !== false);\r\n }\r\n\r\n getAccountsSnapshot(): ManagedAccount[] {\r\n return this.accounts.map((a) => ({ ...a, parts: { ...a.parts }, rateLimitResetTimes: { ...a.rateLimitResetTimes } }));\r\n }\r\n\r\n getCurrentAccountForFamily(family: ModelFamily): ManagedAccount | null {\r\n const currentIndex = this.currentAccountIndexByFamily[family];\r\n if (currentIndex >= 0 && currentIndex < this.accounts.length) {\r\n const account = this.accounts[currentIndex] ?? null;\r\n // Only return account if it's enabled - disabled accounts should not be selected\r\n if (account && account.enabled !== false) {\r\n return account;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n markSwitched(account: ManagedAccount, reason: \"rate-limit\" | \"initial\" | \"rotation\", family: ModelFamily): void {\r\n account.lastSwitchReason = reason;\r\n this.currentAccountIndexByFamily[family] = account.index;\r\n }\r\n\r\n /**\r\n * Check if we should show an account switch toast.\r\n * Debounces repeated toasts for the same account.\r\n */\r\n shouldShowAccountToast(accountIndex: number, debounceMs = 30000): boolean {\r\n const now = nowMs();\r\n if (accountIndex !== this.lastToastAccountIndex) {\r\n return true;\r\n }\r\n return now - this.lastToastTime >= debounceMs;\r\n }\r\n\r\n markToastShown(accountIndex: number): void {\r\n this.lastToastAccountIndex = accountIndex;\r\n this.lastToastTime = nowMs();\r\n }\r\n\r\n getCurrentOrNextForFamily(\r\n family: ModelFamily, \r\n model?: string | null,\r\n strategy: AccountSelectionStrategy = 'sticky',\r\n headerStyle: HeaderStyle = 'antigravity',\r\n pidOffsetEnabled: boolean = false,\r\n softQuotaThresholdPercent: number = 100,\r\n softQuotaCacheTtlMs: number = 10 * 60 * 1000,\r\n ): ManagedAccount | null {\r\n const quotaKey = getQuotaKey(family, headerStyle, model);\r\n\r\n if (strategy === 'round-robin') {\r\n const next = this.getNextForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs);\r\n if (next) {\r\n this.markTouchedForQuota(next, quotaKey);\r\n this.currentAccountIndexByFamily[family] = next.index;\r\n }\r\n return next;\r\n }\r\n\r\n if (strategy === 'hybrid') {\r\n const healthTracker = getHealthTracker();\r\n const tokenTracker = getTokenTracker();\r\n \r\n const accountsWithMetrics: AccountWithMetrics[] = this.accounts\r\n .filter(acc => acc.enabled !== false)\r\n .map(acc => {\r\n clearExpiredRateLimits(acc);\r\n return {\r\n index: acc.index,\r\n lastUsed: acc.lastUsed,\r\n healthScore: healthTracker.getScore(acc.index),\r\n isRateLimited: isRateLimitedForFamily(acc, family, model) || \r\n isOverSoftQuotaThreshold(acc, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model),\r\n isCoolingDown: this.isAccountCoolingDown(acc),\r\n };\r\n });\r\n\r\n // Get current account index for stickiness\r\n const currentIndex = this.currentAccountIndexByFamily[family] ?? null;\r\n \r\n const selectedIndex = selectHybridAccount(accountsWithMetrics, tokenTracker, currentIndex);\r\n if (selectedIndex !== null) {\r\n const selected = this.accounts[selectedIndex];\r\n if (selected) {\r\n selected.lastUsed = nowMs();\r\n this.markTouchedForQuota(selected, quotaKey);\r\n this.currentAccountIndexByFamily[family] = selected.index;\r\n return selected;\r\n }\r\n }\r\n }\r\n\r\n // Fallback: sticky selection (used when hybrid finds no candidates)\r\n // PID-based offset for multi-session distribution (opt-in)\r\n // Different sessions (PIDs) will prefer different starting accounts\r\n if (pidOffsetEnabled && !this.sessionOffsetApplied[family] && this.accounts.length > 1) {\r\n const pidOffset = process.pid % this.accounts.length;\r\n const baseIndex = this.currentAccountIndexByFamily[family] ?? 0;\r\n const newIndex = (baseIndex + pidOffset) % this.accounts.length;\r\n \r\n debugLogToFile(`[Account] Applying PID offset: pid=${process.pid} offset=${pidOffset} family=${family} index=${baseIndex}->${newIndex}`);\r\n \r\n this.currentAccountIndexByFamily[family] = newIndex;\r\n this.sessionOffsetApplied[family] = true;\r\n }\r\n\r\n const current = this.getCurrentAccountForFamily(family);\r\n if (current) {\r\n clearExpiredRateLimits(current);\r\n const isLimitedForRequestedStyle = isRateLimitedForHeaderStyle(current, family, headerStyle, model);\r\n const isOverThreshold = isOverSoftQuotaThreshold(current, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model);\r\n if (!isLimitedForRequestedStyle && !isOverThreshold && !this.isAccountCoolingDown(current)) {\r\n this.markTouchedForQuota(current, quotaKey);\r\n return current;\r\n }\r\n }\r\n\r\n const next = this.getNextForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs);\r\n if (next) {\r\n this.markTouchedForQuota(next, quotaKey);\r\n this.currentAccountIndexByFamily[family] = next.index;\r\n }\r\n return next;\r\n }\r\n\r\n getNextForFamily(family: ModelFamily, model?: string | null, headerStyle: HeaderStyle = \"antigravity\", softQuotaThresholdPercent: number = 100, softQuotaCacheTtlMs: number = 10 * 60 * 1000): ManagedAccount | null {\r\n const available = this.accounts.filter((a) => {\r\n clearExpiredRateLimits(a);\r\n return a.enabled !== false && \r\n !isRateLimitedForHeaderStyle(a, family, headerStyle, model) && \r\n !isOverSoftQuotaThreshold(a, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model) &&\r\n !this.isAccountCoolingDown(a);\r\n });\r\n\r\n if (available.length === 0) {\r\n return null;\r\n }\r\n\r\n const account = available[this.cursor % available.length];\r\n if (!account) {\r\n return null;\r\n }\r\n\r\n this.cursor++;\r\n // Note: lastUsed is now updated after successful request via markAccountUsed()\r\n return account;\r\n }\r\n\r\n markRateLimited(\r\n account: ManagedAccount,\r\n retryAfterMs: number,\r\n family: ModelFamily,\r\n headerStyle: HeaderStyle = \"antigravity\",\r\n model?: string | null\r\n ): void {\r\n const key = getQuotaKey(family, headerStyle, model);\r\n account.rateLimitResetTimes[key] = nowMs() + retryAfterMs;\r\n }\r\n\r\n /**\r\n * Mark an account as used after a successful API request.\r\n * This updates the lastUsed timestamp for freshness calculations.\r\n * Should be called AFTER request completion, not during account selection.\r\n */\r\n markAccountUsed(accountIndex: number): void {\r\n const account = this.accounts.find(a => a.index === accountIndex);\r\n if (account) {\r\n account.lastUsed = nowMs();\r\n }\r\n }\r\n\r\n markRateLimitedWithReason(\r\n account: ManagedAccount,\r\n family: ModelFamily,\r\n headerStyle: HeaderStyle,\r\n model: string | null | undefined,\r\n reason: RateLimitReason,\r\n retryAfterMs?: number | null,\r\n failureTtlMs: number = 3600_000, // Default 1 hour TTL\r\n ): number {\r\n const now = nowMs();\r\n \r\n // TTL-based reset: if last failure was more than failureTtlMs ago, reset count\r\n if (account.lastFailureTime !== undefined && (now - account.lastFailureTime) > failureTtlMs) {\r\n account.consecutiveFailures = 0;\r\n }\r\n \r\n const failures = (account.consecutiveFailures ?? 0) + 1;\r\n account.consecutiveFailures = failures;\r\n account.lastFailureTime = now;\r\n \r\n const backoffMs = calculateBackoffMs(reason, failures - 1, retryAfterMs);\r\n const key = getQuotaKey(family, headerStyle, model);\r\n account.rateLimitResetTimes[key] = now + backoffMs;\r\n \r\n return backoffMs;\r\n }\r\n\r\n markRequestSuccess(account: ManagedAccount): void {\r\n if (account.consecutiveFailures) {\r\n account.consecutiveFailures = 0;\r\n }\r\n }\r\n\r\n clearAllRateLimitsForFamily(family: ModelFamily, model?: string | null): void {\r\n for (const account of this.accounts) {\r\n if (family === \"claude\") {\r\n delete account.rateLimitResetTimes.claude;\r\n } else {\r\n const antigravityKey = getQuotaKey(family, \"antigravity\", model);\r\n const cliKey = getQuotaKey(family, \"gemini-cli\", model);\r\n delete account.rateLimitResetTimes[antigravityKey];\r\n delete account.rateLimitResetTimes[cliKey];\r\n }\r\n account.consecutiveFailures = 0;\r\n }\r\n }\r\n\r\n shouldTryOptimisticReset(family: ModelFamily, model?: string | null): boolean {\r\n const minWaitMs = this.getMinWaitTimeForFamily(family, model);\r\n return minWaitMs > 0 && minWaitMs <= 2_000;\r\n }\r\n\r\n markAccountCoolingDown(account: ManagedAccount, cooldownMs: number, reason: CooldownReason): void {\r\n account.coolingDownUntil = nowMs() + cooldownMs;\r\n account.cooldownReason = reason;\r\n }\r\n\r\n isAccountCoolingDown(account: ManagedAccount): boolean {\r\n if (account.coolingDownUntil === undefined) {\r\n return false;\r\n }\r\n if (nowMs() >= account.coolingDownUntil) {\r\n this.clearAccountCooldown(account);\r\n return false;\r\n }\r\n return true;\r\n }\r\n\r\n clearAccountCooldown(account: ManagedAccount): void {\r\n delete account.coolingDownUntil;\r\n delete account.cooldownReason;\r\n }\r\n\r\n getAccountCooldownReason(account: ManagedAccount): CooldownReason | undefined {\r\n return this.isAccountCoolingDown(account) ? account.cooldownReason : undefined;\r\n }\r\n\r\n markTouchedForQuota(account: ManagedAccount, quotaKey: string): void {\r\n account.touchedForQuota[quotaKey] = nowMs();\r\n }\r\n\r\n isFreshForQuota(account: ManagedAccount, quotaKey: string): boolean {\r\n const touchedAt = account.touchedForQuota[quotaKey];\r\n if (!touchedAt) return true;\r\n \r\n const resetTime = account.rateLimitResetTimes[quotaKey as QuotaKey];\r\n if (resetTime && touchedAt < resetTime) return true;\r\n \r\n return false;\r\n }\r\n\r\n getFreshAccountsForQuota(quotaKey: string, family: ModelFamily, model?: string | null): ManagedAccount[] {\r\n return this.accounts.filter(acc => {\r\n clearExpiredRateLimits(acc);\r\n return acc.enabled !== false &&\r\n this.isFreshForQuota(acc, quotaKey) && \r\n !isRateLimitedForFamily(acc, family, model) && \r\n !this.isAccountCoolingDown(acc);\r\n });\r\n }\r\n\r\n isRateLimitedForHeaderStyle(\r\n account: ManagedAccount,\r\n family: ModelFamily,\r\n headerStyle: HeaderStyle,\r\n model?: string | null\r\n ): boolean {\r\n return isRateLimitedForHeaderStyle(account, family, headerStyle, model);\r\n }\r\n\r\n getAvailableHeaderStyle(account: ManagedAccount, family: ModelFamily, model?: string | null): HeaderStyle | null {\r\n clearExpiredRateLimits(account);\r\n if (family === \"claude\") {\r\n return isRateLimitedForHeaderStyle(account, family, \"antigravity\") ? null : \"antigravity\";\r\n }\r\n if (!isRateLimitedForHeaderStyle(account, family, \"antigravity\", model)) {\r\n return \"antigravity\";\r\n }\r\n if (!isRateLimitedForHeaderStyle(account, family, \"gemini-cli\", model)) {\r\n return \"gemini-cli\";\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Check if any OTHER account has antigravity quota available for the given family/model.\r\n * \r\n * Used to determine whether to switch accounts vs fall back to gemini-cli:\r\n * - If true: Switch to another account (preserve antigravity priority)\r\n * - If false: All accounts exhausted antigravity, safe to fall back to gemini-cli\r\n * \r\n * @param currentAccountIndex - Index of the current account (will be excluded from check)\r\n * @param family - Model family (\"gemini\" or \"claude\")\r\n * @param model - Optional model name for model-specific rate limits\r\n * @returns true if any other enabled, non-cooling-down account has antigravity available\r\n */\r\n hasOtherAccountWithAntigravityAvailable(\r\n currentAccountIndex: number,\r\n family: ModelFamily,\r\n model?: string | null\r\n ): boolean {\r\n // Claude has no gemini-cli fallback - always return false\r\n // (This method is only relevant for Gemini's dual quota pools)\r\n if (family === \"claude\") {\r\n return false;\r\n }\r\n\r\n return this.accounts.some(acc => {\r\n // Skip current account\r\n if (acc.index === currentAccountIndex) {\r\n return false;\r\n }\r\n // Skip disabled accounts\r\n if (acc.enabled === false) {\r\n return false;\r\n }\r\n // Skip cooling down accounts\r\n if (this.isAccountCoolingDown(acc)) {\r\n return false;\r\n }\r\n // Clear expired rate limits before checking\r\n clearExpiredRateLimits(acc);\r\n // Check if antigravity is available for this account\r\n return !isRateLimitedForHeaderStyle(acc, family, \"antigravity\", model);\r\n });\r\n }\r\n\r\n setAccountEnabled(accountIndex: number, enabled: boolean): boolean {\r\n const account = this.accounts[accountIndex];\r\n if (!account) {\r\n return false;\r\n }\r\n account.enabled = enabled;\r\n\r\n if (!enabled) {\r\n for (const family of Object.keys(this.currentAccountIndexByFamily) as ModelFamily[]) {\r\n if (this.currentAccountIndexByFamily[family] === accountIndex) {\r\n const next = this.accounts.find((a, i) => i !== accountIndex && a.enabled !== false);\r\n this.currentAccountIndexByFamily[family] = next?.index ?? -1;\r\n }\r\n }\r\n }\r\n\r\n this.requestSaveToDisk();\r\n return true;\r\n }\r\n\r\n markAccountVerificationRequired(accountIndex: number, reason?: string, verifyUrl?: string): boolean {\r\n const account = this.accounts[accountIndex];\r\n if (!account) {\r\n return false;\r\n }\r\n\r\n account.verificationRequired = true;\r\n account.verificationRequiredAt = nowMs();\r\n account.verificationRequiredReason = reason?.trim() || undefined;\r\n\r\n const normalizedVerifyUrl = verifyUrl?.trim();\r\n if (normalizedVerifyUrl) {\r\n account.verificationUrl = normalizedVerifyUrl;\r\n }\r\n\r\n if (account.enabled !== false) {\r\n this.setAccountEnabled(accountIndex, false);\r\n } else {\r\n this.requestSaveToDisk();\r\n }\r\n\r\n return true;\r\n }\r\n\r\n clearAccountVerificationRequired(accountIndex: number, enableAccount = false): boolean {\r\n const account = this.accounts[accountIndex];\r\n if (!account) {\r\n return false;\r\n }\r\n\r\n const wasVerificationRequired = account.verificationRequired === true;\r\n const hadMetadata = (\r\n account.verificationRequiredAt !== undefined ||\r\n account.verificationRequiredReason !== undefined ||\r\n account.verificationUrl !== undefined\r\n );\r\n\r\n account.verificationRequired = false;\r\n account.verificationRequiredAt = undefined;\r\n account.verificationRequiredReason = undefined;\r\n account.verificationUrl = undefined;\r\n\r\n if (enableAccount && wasVerificationRequired && account.enabled === false) {\r\n this.setAccountEnabled(accountIndex, true);\r\n } else if (wasVerificationRequired || hadMetadata) {\r\n this.requestSaveToDisk();\r\n }\r\n\r\n return true;\r\n }\r\n\r\n removeAccountByIndex(accountIndex: number): boolean {\r\n if (accountIndex < 0 || accountIndex >= this.accounts.length) {\r\n return false;\r\n }\r\n const account = this.accounts[accountIndex];\r\n if (!account) {\r\n return false;\r\n }\r\n return this.removeAccount(account);\r\n }\r\n\r\n removeAccount(account: ManagedAccount): boolean {\r\n const idx = this.accounts.indexOf(account);\r\n if (idx < 0) {\r\n return false;\r\n }\r\n\r\n this.accounts.splice(idx, 1);\r\n this.accounts.forEach((acc, index) => {\r\n acc.index = index;\r\n });\r\n\r\n if (this.accounts.length === 0) {\r\n this.cursor = 0;\r\n this.currentAccountIndexByFamily.claude = -1;\r\n this.currentAccountIndexByFamily.gemini = -1;\r\n return true;\r\n }\r\n\r\n if (this.cursor > idx) {\r\n this.cursor -= 1;\r\n }\r\n this.cursor = this.cursor % this.accounts.length;\r\n\r\n for (const family of [\"claude\", \"gemini\"] as ModelFamily[]) {\r\n if (this.currentAccountIndexByFamily[family] > idx) {\r\n this.currentAccountIndexByFamily[family] -= 1;\r\n }\r\n if (this.currentAccountIndexByFamily[family] >= this.accounts.length) {\r\n this.currentAccountIndexByFamily[family] = -1;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n updateFromAuth(account: ManagedAccount, auth: OAuthAuthDetails): void {\r\n const parts = parseRefreshParts(auth.refresh);\r\n // Preserve existing projectId/managedProjectId if not in the new parts\r\n account.parts = {\r\n ...parts,\r\n projectId: parts.projectId ?? account.parts.projectId,\r\n managedProjectId: parts.managedProjectId ?? account.parts.managedProjectId,\r\n };\r\n account.access = auth.access;\r\n account.expires = auth.expires;\r\n }\r\n\r\n toAuthDetails(account: ManagedAccount): OAuthAuthDetails {\r\n return {\r\n type: \"oauth\",\r\n refresh: formatRefreshParts(account.parts),\r\n access: account.access,\r\n expires: account.expires,\r\n };\r\n }\r\n\r\n getMinWaitTimeForFamily(\r\n family: ModelFamily,\r\n model?: string | null,\r\n headerStyle?: HeaderStyle,\r\n strict?: boolean,\r\n ): number {\r\n const available = this.accounts.filter((a) => {\r\n clearExpiredRateLimits(a);\r\n return a.enabled !== false && (strict && headerStyle\r\n ? !isRateLimitedForHeaderStyle(a, family, headerStyle, model)\r\n : !isRateLimitedForFamily(a, family, model));\r\n });\r\n if (available.length > 0) {\r\n return 0;\r\n }\r\n\r\n const waitTimes: number[] = [];\r\n for (const a of this.accounts) {\r\n if (family === \"claude\") {\r\n const t = a.rateLimitResetTimes.claude;\r\n if (t !== undefined) waitTimes.push(Math.max(0, t - nowMs()));\r\n } else if (strict && headerStyle) {\r\n const key = getQuotaKey(family, headerStyle, model);\r\n const t = a.rateLimitResetTimes[key];\r\n if (t !== undefined) waitTimes.push(Math.max(0, t - nowMs()));\r\n } else {\r\n // For Gemini, account becomes available when EITHER pool expires for this model/family\r\n const antigravityKey = getQuotaKey(family, \"antigravity\", model);\r\n const cliKey = getQuotaKey(family, \"gemini-cli\", model);\r\n\r\n const t1 = a.rateLimitResetTimes[antigravityKey];\r\n const t2 = a.rateLimitResetTimes[cliKey];\r\n \r\n const accountWait = Math.min(\r\n t1 !== undefined ? Math.max(0, t1 - nowMs()) : Infinity,\r\n t2 !== undefined ? Math.max(0, t2 - nowMs()) : Infinity\r\n );\r\n if (accountWait !== Infinity) waitTimes.push(accountWait);\r\n }\r\n }\r\n\r\n return waitTimes.length > 0 ? Math.min(...waitTimes) : 0;\r\n }\r\n\r\n getAccounts(): ManagedAccount[] {\r\n return [...this.accounts];\r\n }\r\n\r\n async saveToDisk(): Promise<void> {\r\n const claudeIndex = Math.max(0, this.currentAccountIndexByFamily.claude);\r\n const geminiIndex = Math.max(0, this.currentAccountIndexByFamily.gemini);\r\n \r\n const storage: AccountStorageV4 = {\r\n version: 4,\r\n accounts: this.accounts.map((a) => ({\r\n email: a.email,\r\n refreshToken: a.parts.refreshToken,\r\n projectId: a.parts.projectId,\r\n managedProjectId: a.parts.managedProjectId,\r\n addedAt: a.addedAt,\r\n lastUsed: a.lastUsed,\r\n enabled: a.enabled,\r\n lastSwitchReason: a.lastSwitchReason,\r\n rateLimitResetTimes: Object.keys(a.rateLimitResetTimes).length > 0 ? a.rateLimitResetTimes : undefined,\r\n coolingDownUntil: a.coolingDownUntil,\r\n cooldownReason: a.cooldownReason,\r\n fingerprint: a.fingerprint,\r\n fingerprintHistory: a.fingerprintHistory?.length ? a.fingerprintHistory : undefined,\r\n cachedQuota: a.cachedQuota && Object.keys(a.cachedQuota).length > 0 ? a.cachedQuota : undefined,\r\n cachedQuotaUpdatedAt: a.cachedQuotaUpdatedAt,\r\n verificationRequired: a.verificationRequired,\r\n verificationRequiredAt: a.verificationRequiredAt,\r\n verificationRequiredReason: a.verificationRequiredReason,\r\n verificationUrl: a.verificationUrl,\r\n })),\r\n activeIndex: claudeIndex,\r\n activeIndexByFamily: {\r\n claude: claudeIndex,\r\n gemini: geminiIndex,\r\n },\r\n };\r\n\r\n await saveAccounts(storage);\r\n }\r\n\r\n requestSaveToDisk(): void {\r\n if (this.savePending) {\r\n return;\r\n }\r\n this.savePending = true;\r\n this.saveTimeout = setTimeout(() => {\r\n void this.executeSave();\r\n }, 1000);\r\n }\r\n\r\n async flushSaveToDisk(): Promise<void> {\n if (!this.savePending) {\n return;\n }\n return new Promise<void>((resolve, reject) => {\n this.savePromiseResolvers.push({ resolve, reject });\n });\n }\r\n private async executeSave(): Promise<void> {\n this.savePending = false;\n this.saveTimeout = null;\n \n const resolvers = this.savePromiseResolvers;\n this.savePromiseResolvers = [];\n\n try {\n await this.saveToDisk();\n for (const { resolve } of resolvers) {\n resolve();\n }\n } catch (error) {\n console.warn(\"[antigravity] Failed to persist account state to disk:\", String(error));\n for (const { reject } of resolvers) {\n reject(error);\n }\n }\n }\r\n // ========== Fingerprint Management ==========\r\n\r\n /**\r\n * Regenerate fingerprint for an account, saving the old one to history.\r\n * @param accountIndex - Index of the account to regenerate fingerprint for\r\n * @returns The new fingerprint, or null if account not found\r\n */\r\n regenerateAccountFingerprint(accountIndex: number): Fingerprint | null {\r\n const account = this.accounts[accountIndex];\r\n if (!account) return null;\r\n \r\n // Save current fingerprint to history if it exists\r\n if (account.fingerprint) {\r\n const historyEntry: FingerprintVersion = {\r\n fingerprint: account.fingerprint,\r\n timestamp: nowMs(),\r\n reason: 'regenerated',\r\n };\r\n \r\n if (!account.fingerprintHistory) {\r\n account.fingerprintHistory = [];\r\n }\r\n \r\n // Add to beginning of history (most recent first)\r\n account.fingerprintHistory.unshift(historyEntry);\r\n \r\n // Trim to max history size\r\n if (account.fingerprintHistory.length > MAX_FINGERPRINT_HISTORY) {\r\n account.fingerprintHistory = account.fingerprintHistory.slice(0, MAX_FINGERPRINT_HISTORY);\r\n }\r\n }\r\n\r\n // Generate and assign new fingerprint\r\n account.fingerprint = generateFingerprint();\r\n this.requestSaveToDisk();\r\n \r\n return account.fingerprint;\r\n }\r\n\r\n /**\r\n * Restore a fingerprint from history for an account.\r\n * @param accountIndex - Index of the account\r\n * @param historyIndex - Index in the fingerprint history to restore from (0 = most recent)\r\n * @returns The restored fingerprint, or null if account/history not found\r\n */\r\n restoreAccountFingerprint(accountIndex: number, historyIndex: number): Fingerprint | null {\r\n const account = this.accounts[accountIndex];\r\n if (!account) return null;\r\n\r\n const history = account.fingerprintHistory;\r\n if (!history || historyIndex < 0 || historyIndex >= history.length) {\r\n return null;\r\n }\r\n \r\n // Capture the fingerprint to restore BEFORE modifying history\r\n const fingerprintToRestore = history[historyIndex]!.fingerprint;\r\n \r\n // Save current fingerprint to history before restoring (if it exists)\r\n if (account.fingerprint) {\r\n const historyEntry: FingerprintVersion = {\r\n fingerprint: account.fingerprint,\r\n timestamp: nowMs(),\r\n reason: 'restored',\r\n };\r\n \r\n account.fingerprintHistory!.unshift(historyEntry);\r\n \r\n // Trim to max history size\r\n if (account.fingerprintHistory!.length > MAX_FINGERPRINT_HISTORY) {\r\n account.fingerprintHistory = account.fingerprintHistory!.slice(0, MAX_FINGERPRINT_HISTORY);\r\n }\r\n }\r\n\r\n // Restore the fingerprint\r\n account.fingerprint = { ...fingerprintToRestore, createdAt: nowMs() };\r\n \r\n this.requestSaveToDisk();\r\n \r\n return account.fingerprint;\r\n }\r\n\r\n /**\r\n * Get fingerprint history for an account.\r\n * @param accountIndex - Index of the account\r\n * @returns Array of fingerprint versions, or empty array if not found\r\n */\r\n getAccountFingerprintHistory(accountIndex: number): FingerprintVersion[] {\r\n const account = this.accounts[accountIndex];\r\n if (!account || !account.fingerprintHistory) {\r\n return [];\r\n }\r\n return [...account.fingerprintHistory];\r\n }\r\n\r\n updateQuotaCache(accountIndex: number, quotaGroups: Partial<Record<QuotaGroup, QuotaGroupSummary>>): void {\r\n const account = this.accounts[accountIndex];\r\n if (account) {\r\n account.cachedQuota = quotaGroups;\r\n account.cachedQuotaUpdatedAt = nowMs();\r\n }\r\n }\r\n\r\n isAccountOverSoftQuota(account: ManagedAccount, family: ModelFamily, thresholdPercent: number, cacheTtlMs: number, model?: string | null): boolean {\r\n return isOverSoftQuotaThreshold(account, family, thresholdPercent, cacheTtlMs, model);\r\n }\r\n\r\n getAccountsForQuotaCheck(): AccountMetadataV3[] {\r\n return this.accounts.map((a) => ({\r\n email: a.email,\r\n refreshToken: a.parts.refreshToken,\r\n projectId: a.parts.projectId,\r\n managedProjectId: a.parts.managedProjectId,\r\n addedAt: a.addedAt,\r\n lastUsed: a.lastUsed,\r\n enabled: a.enabled,\r\n }));\r\n }\r\n\r\n getOldestQuotaCacheAge(): number | null {\r\n let oldest: number | null = null;\r\n for (const acc of this.accounts) {\r\n if (acc.enabled === false) continue;\r\n if (acc.cachedQuotaUpdatedAt == null) return null;\r\n const age = nowMs() - acc.cachedQuotaUpdatedAt;\r\n if (oldest === null || age > oldest) oldest = age;\r\n }\r\n return oldest;\r\n }\r\n\r\n areAllAccountsOverSoftQuota(family: ModelFamily, thresholdPercent: number, cacheTtlMs: number, model?: string | null): boolean {\r\n if (thresholdPercent >= 100) return false;\r\n const enabled = this.accounts.filter(a => a.enabled !== false);\r\n if (enabled.length === 0) return false;\r\n return enabled.every(a => isOverSoftQuotaThreshold(a, family, thresholdPercent, cacheTtlMs, model));\r\n }\r\n\r\n /**\r\n * Get minimum wait time until any account's soft quota resets.\r\n * Returns 0 if any account is available (not over threshold).\r\n * Returns the minimum resetTime across all over-threshold accounts.\r\n * Returns null if no resetTime data is available.\r\n */\r\n getMinWaitTimeForSoftQuota(\r\n family: ModelFamily,\r\n thresholdPercent: number,\r\n cacheTtlMs: number,\r\n model?: string | null\r\n ): number | null {\r\n if (thresholdPercent >= 100) return 0;\r\n \r\n const enabled = this.accounts.filter(a => a.enabled !== false);\r\n if (enabled.length === 0) return null;\r\n \r\n // If any account is available (not over threshold), no wait needed\r\n const available = enabled.filter(a => !isOverSoftQuotaThreshold(a, family, thresholdPercent, cacheTtlMs, model));\r\n if (available.length > 0) return 0;\r\n \r\n // All accounts are over threshold - find earliest reset time\r\n // For gemini family, we MUST have the model to distinguish pro vs flash quotas.\r\n // Fail-open (return null = no wait info) if model is missing to avoid blocking on wrong quota.\r\n if (!model && family !== \"claude\") return null;\r\n const quotaGroup = resolveQuotaGroup(family, model);\r\n const now = nowMs();\r\n const waitTimes: number[] = [];\r\n \r\n for (const acc of enabled) {\r\n const groupData = acc.cachedQuota?.[quotaGroup];\r\n if (groupData?.resetTime) {\r\n const resetTimestamp = Date.parse(groupData.resetTime);\r\n if (Number.isFinite(resetTimestamp)) {\r\n waitTimes.push(Math.max(0, resetTimestamp - now));\r\n }\r\n }\r\n }\r\n \r\n if (waitTimes.length === 0) return null;\r\n const minWait = Math.min(...waitTimes);\r\n // Treat 0 as stale cache (resetTime in the past) \u2192 fail-open to avoid spin loop\r\n return minWait === 0 ? null : minWait;\r\n }\r\n}\r\n", "import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\nimport { fileURLToPath } from \"node:url\";\r\nimport type { NpmDistTags, OpencodeConfig, PackageJson, UpdateCheckResult } from \"./types\";\r\nimport {\r\n PACKAGE_NAME,\r\n NPM_REGISTRY_URL,\r\n NPM_FETCH_TIMEOUT,\r\n INSTALLED_PACKAGE_JSON,\r\n USER_OPENCODE_CONFIG,\r\n USER_OPENCODE_CONFIG_JSONC,\r\n} from \"./constants\";\r\nimport { logAutoUpdate } from \"./logging\";\r\n\r\nexport function isLocalDevMode(directory: string): boolean {\r\n return getLocalDevPath(directory) !== null;\r\n}\r\n\r\nfunction stripJsonComments(json: string): string {\r\n return json\r\n .replace(/\\\\\"|\"(?:\\\\\"|[^\"])*\"|(\\/\\/.*|\\/\\*[\\s\\S]*?\\*\\/)/g, (m: string, g: string | undefined) => (g ? \"\" : m))\r\n .replace(/,(\\s*[}\\]])/g, \"$1\");\r\n}\r\n\r\nfunction getConfigPaths(directory: string): string[] {\r\n return [\r\n path.join(directory, \".opencode\", \"opencode.json\"),\r\n path.join(directory, \".opencode\", \"opencode.jsonc\"),\r\n path.join(directory, \".opencode.json\"),\r\n USER_OPENCODE_CONFIG,\r\n USER_OPENCODE_CONFIG_JSONC,\r\n ];\r\n}\r\n\r\nexport function getLocalDevPath(directory: string): string | null {\r\n for (const configPath of getConfigPaths(directory)) {\r\n try {\r\n if (!fs.existsSync(configPath)) continue;\r\n const content = fs.readFileSync(configPath, \"utf-8\");\r\n const config = JSON.parse(stripJsonComments(content)) as OpencodeConfig;\r\n const plugins = config.plugin ?? [];\r\n\r\n for (const entry of plugins) {\r\n if (entry.startsWith(\"file://\") && entry.includes(PACKAGE_NAME)) {\r\n try {\r\n return fileURLToPath(entry);\r\n } catch {\r\n return entry.replace(\"file://\", \"\");\r\n }\r\n }\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nfunction findPackageJsonUp(startPath: string): string | null {\r\n try {\r\n const stat = fs.statSync(startPath);\r\n let dir = stat.isDirectory() ? startPath : path.dirname(startPath);\r\n\r\n for (let i = 0; i < 10; i++) {\r\n const pkgPath = path.join(dir, \"package.json\");\r\n if (fs.existsSync(pkgPath)) {\r\n try {\r\n const content = fs.readFileSync(pkgPath, \"utf-8\");\r\n const pkg = JSON.parse(content) as PackageJson;\r\n if (pkg.name === PACKAGE_NAME) return pkgPath;\r\n } catch {\r\n continue;\r\n }\r\n }\r\n const parent = path.dirname(dir);\r\n if (parent === dir) break;\r\n dir = parent;\r\n }\r\n } catch {\r\n return null;\r\n }\r\n return null;\r\n}\r\n\r\nexport function getLocalDevVersion(directory: string): string | null {\r\n const localPath = getLocalDevPath(directory);\r\n if (!localPath) return null;\r\n\r\n try {\r\n const pkgPath = findPackageJsonUp(localPath);\r\n if (!pkgPath) return null;\r\n const content = fs.readFileSync(pkgPath, \"utf-8\");\r\n const pkg = JSON.parse(content) as PackageJson;\r\n return pkg.version ?? null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport interface PluginEntryInfo {\r\n entry: string;\r\n isPinned: boolean;\r\n pinnedVersion: string | null;\r\n configPath: string;\r\n}\r\n\r\nexport function findPluginEntry(directory: string): PluginEntryInfo | null {\r\n for (const configPath of getConfigPaths(directory)) {\r\n try {\r\n if (!fs.existsSync(configPath)) continue;\r\n const content = fs.readFileSync(configPath, \"utf-8\");\r\n const config = JSON.parse(stripJsonComments(content)) as OpencodeConfig;\r\n const plugins = config.plugin ?? [];\r\n\r\n for (const entry of plugins) {\r\n if (entry === PACKAGE_NAME) {\r\n return { entry, isPinned: false, pinnedVersion: null, configPath };\r\n }\r\n if (entry.startsWith(`${PACKAGE_NAME}@`)) {\r\n const pinnedVersion = entry.slice(PACKAGE_NAME.length + 1);\r\n const isPinned = pinnedVersion !== \"latest\";\r\n return { entry, isPinned, pinnedVersion: isPinned ? pinnedVersion : null, configPath };\r\n }\r\n if (entry.startsWith(\"file://\") && entry.includes(PACKAGE_NAME)) {\r\n return { entry, isPinned: false, pinnedVersion: null, configPath };\r\n }\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function getCachedVersion(): string | null {\r\n try {\r\n if (fs.existsSync(INSTALLED_PACKAGE_JSON)) {\r\n const content = fs.readFileSync(INSTALLED_PACKAGE_JSON, \"utf-8\");\r\n const pkg = JSON.parse(content) as PackageJson;\r\n if (pkg.version) return pkg.version;\r\n }\r\n } catch {\r\n return null;\r\n }\r\n\r\n try {\r\n const currentDir = path.dirname(fileURLToPath(import.meta.url));\r\n const pkgPath = findPackageJsonUp(currentDir);\r\n if (pkgPath) {\r\n const content = fs.readFileSync(pkgPath, \"utf-8\");\r\n const pkg = JSON.parse(content) as PackageJson;\r\n if (pkg.version) return pkg.version;\r\n }\r\n } catch (err) {\r\n logAutoUpdate(`Failed to resolve version from current directory: ${err}`);\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function updatePinnedVersion(configPath: string, oldEntry: string, newVersion: string): boolean {\r\n try {\r\n const content = fs.readFileSync(configPath, \"utf-8\");\r\n const newEntry = `${PACKAGE_NAME}@${newVersion}`;\r\n\r\n const pluginMatch = content.match(/\"plugin\"\\s*:\\s*\\[/);\r\n if (!pluginMatch || pluginMatch.index === undefined) {\r\n logAutoUpdate(`No \"plugin\" array found in ${configPath}`);\r\n return false;\r\n }\r\n\r\n const startIdx = pluginMatch.index + pluginMatch[0].length;\r\n let bracketCount = 1;\r\n let endIdx = startIdx;\r\n\r\n for (let i = startIdx; i < content.length && bracketCount > 0; i++) {\r\n if (content[i] === \"[\") bracketCount++;\r\n else if (content[i] === \"]\") bracketCount--;\r\n endIdx = i;\r\n }\r\n\r\n const before = content.slice(0, startIdx);\r\n const pluginArrayContent = content.slice(startIdx, endIdx);\r\n const after = content.slice(endIdx);\r\n\r\n const escapedOldEntry = oldEntry.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n const regex = new RegExp(`[\"']${escapedOldEntry}[\"']`);\r\n\r\n if (!regex.test(pluginArrayContent)) {\r\n logAutoUpdate(`Entry \"${oldEntry}\" not found in plugin array of ${configPath}`);\r\n return false;\r\n }\r\n\r\n const updatedPluginArray = pluginArrayContent.replace(regex, `\"${newEntry}\"`);\r\n const updatedContent = before + updatedPluginArray + after;\r\n\r\n if (updatedContent === content) {\r\n logAutoUpdate(`No changes made to ${configPath}`);\r\n return false;\r\n }\r\n\r\n fs.writeFileSync(configPath, updatedContent, \"utf-8\");\r\n logAutoUpdate(`Updated ${configPath}: ${oldEntry} \u2192 ${newEntry}`);\r\n return true;\r\n } catch (err) {\r\n console.error(`[auto-update-checker] Failed to update config file ${configPath}:`, err);\r\n return false;\r\n }\r\n}\r\n\r\nexport async function getLatestVersion(): Promise<string | null> {\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), NPM_FETCH_TIMEOUT);\r\n\r\n try {\r\n const response = await fetch(NPM_REGISTRY_URL, {\r\n signal: controller.signal,\r\n headers: { Accept: \"application/json\" },\r\n });\r\n\r\n if (!response.ok) return null;\r\n\r\n const data = (await response.json()) as NpmDistTags;\r\n return data.latest ?? null;\r\n } catch {\r\n return null;\r\n } finally {\r\n clearTimeout(timeoutId);\r\n }\r\n}\r\n\r\nexport async function checkForUpdate(directory: string): Promise<UpdateCheckResult> {\r\n if (isLocalDevMode(directory)) {\r\n logAutoUpdate(\"Local dev mode detected, skipping update check\");\r\n return { needsUpdate: false, currentVersion: null, latestVersion: null, isLocalDev: true, isPinned: false };\r\n }\r\n\r\n const pluginInfo = findPluginEntry(directory);\r\n if (!pluginInfo) {\r\n logAutoUpdate(\"Plugin not found in config\");\r\n return { needsUpdate: false, currentVersion: null, latestVersion: null, isLocalDev: false, isPinned: false };\r\n }\r\n\r\n const currentVersion = getCachedVersion() ?? pluginInfo.pinnedVersion;\r\n if (!currentVersion) {\r\n logAutoUpdate(\"No version found (cached or pinned)\");\r\n return { needsUpdate: false, currentVersion: null, latestVersion: null, isLocalDev: false, isPinned: pluginInfo.isPinned };\r\n }\r\n\r\n const latestVersion = await getLatestVersion();\r\n if (!latestVersion) {\r\n logAutoUpdate(\"Failed to fetch latest version\");\r\n return { needsUpdate: false, currentVersion, latestVersion: null, isLocalDev: false, isPinned: pluginInfo.isPinned };\r\n }\r\n\r\n const needsUpdate = currentVersion !== latestVersion;\r\n logAutoUpdate(`Current: ${currentVersion}, Latest: ${latestVersion}, NeedsUpdate: ${needsUpdate}`);\r\n return { needsUpdate, currentVersion, latestVersion, isLocalDev: false, isPinned: pluginInfo.isPinned };\r\n}\r\n", "import * as path from \"node:path\";\r\nimport * as os from \"node:os\";\r\n\r\nexport const PACKAGE_NAME = \"@expiren/opencode-antigravity-auth\";\r\nexport const NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;\r\nexport const NPM_FETCH_TIMEOUT = 5000;\r\n\r\nfunction getCacheDir(): string {\r\n if (process.platform === \"win32\") {\r\n return path.join(process.env.LOCALAPPDATA ?? os.homedir(), \"opencode\");\r\n }\r\n return path.join(os.homedir(), \".cache\", \"opencode\");\r\n}\r\n\r\nexport const CACHE_DIR = getCacheDir();\r\nexport const INSTALLED_PACKAGE_JSON = path.join(\r\n CACHE_DIR,\r\n \"node_modules\",\r\n PACKAGE_NAME,\r\n \"package.json\"\r\n);\r\n\r\nfunction getUserConfigDir(): string {\r\n if (process.platform === \"win32\") {\r\n return process.env.APPDATA ?? path.join(os.homedir(), \"AppData\", \"Roaming\");\r\n }\r\n return process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), \".config\");\r\n}\r\n\r\nexport const USER_CONFIG_DIR = getUserConfigDir();\r\nexport const USER_OPENCODE_CONFIG = path.join(USER_CONFIG_DIR, \"opencode\", \"opencode.json\");\r\nexport const USER_OPENCODE_CONFIG_JSONC = path.join(USER_CONFIG_DIR, \"opencode\", \"opencode.jsonc\");\r\n", "import { debugLogToFile } from \"../../plugin/debug\";\r\n\r\nconst AUTO_UPDATE_LOG_PREFIX = \"[auto-update-checker]\";\r\n\r\nexport function formatAutoUpdateLogMessage(message: string): string {\r\n return `${AUTO_UPDATE_LOG_PREFIX} ${message}`;\r\n}\r\n\r\nexport function logAutoUpdate(message: string): void {\r\n debugLogToFile(formatAutoUpdateLogMessage(message));\r\n}\r\n", "import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\nimport { CACHE_DIR, PACKAGE_NAME } from \"./constants\";\r\n\r\ninterface BunLockfile {\r\n workspaces?: {\r\n \"\"?: {\r\n dependencies?: Record<string, string>;\r\n };\r\n };\r\n packages?: Record<string, unknown>;\r\n}\r\n\r\nfunction stripTrailingCommas(json: string): string {\r\n return json.replace(/,(\\s*[}\\]])/g, \"$1\");\r\n}\r\n\r\nfunction removeFromBunLock(packageName: string): boolean {\r\n const lockPath = path.join(CACHE_DIR, \"bun.lock\");\r\n if (!fs.existsSync(lockPath)) return false;\r\n\r\n try {\r\n const content = fs.readFileSync(lockPath, \"utf-8\");\r\n const lock = JSON.parse(stripTrailingCommas(content)) as BunLockfile;\r\n let modified = false;\r\n\r\n if (lock.workspaces?.[\"\"]?.dependencies?.[packageName]) {\r\n delete lock.workspaces[\"\"].dependencies[packageName];\r\n modified = true;\r\n }\r\n\r\n if (lock.packages?.[packageName]) {\r\n delete lock.packages[packageName];\r\n modified = true;\r\n }\r\n\r\n if (modified) {\r\n fs.writeFileSync(lockPath, JSON.stringify(lock, null, 2));\r\n console.log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);\r\n }\r\n\r\n return modified;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function invalidatePackage(packageName: string = PACKAGE_NAME): boolean {\r\n try {\r\n const pkgDir = path.join(CACHE_DIR, \"node_modules\", packageName);\r\n const pkgJsonPath = path.join(CACHE_DIR, \"package.json\");\r\n\r\n let packageRemoved = false;\r\n let dependencyRemoved = false;\r\n let lockRemoved = false;\r\n\r\n if (fs.existsSync(pkgDir)) {\r\n fs.rmSync(pkgDir, { recursive: true, force: true });\r\n console.log(`[auto-update-checker] Package removed: ${pkgDir}`);\r\n packageRemoved = true;\r\n }\r\n\r\n if (fs.existsSync(pkgJsonPath)) {\r\n const content = fs.readFileSync(pkgJsonPath, \"utf-8\");\r\n const pkgJson = JSON.parse(content);\r\n if (pkgJson.dependencies?.[packageName]) {\r\n delete pkgJson.dependencies[packageName];\r\n fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));\r\n console.log(`[auto-update-checker] Dependency removed from package.json: ${packageName}`);\r\n dependencyRemoved = true;\r\n }\r\n }\r\n\r\n lockRemoved = removeFromBunLock(packageName);\r\n\r\n if (!packageRemoved && !dependencyRemoved && !lockRemoved) {\r\n console.log(`[auto-update-checker] Package not found, nothing to invalidate: ${packageName}`);\r\n return false;\r\n }\r\n\r\n return true;\r\n } catch (err) {\r\n console.error(\"[auto-update-checker] Failed to invalidate package:\", err);\r\n return false;\r\n }\r\n}\r\n\r\nexport function invalidateCache(): boolean {\r\n console.warn(\"[auto-update-checker] WARNING: invalidateCache is deprecated, use invalidatePackage\");\r\n return invalidatePackage();\r\n}\r\n", "import type { AutoUpdateCheckerOptions } from \"./types\";\r\nimport { getCachedVersion, getLocalDevVersion, findPluginEntry, getLatestVersion, updatePinnedVersion } from \"./checker\";\r\nimport { invalidatePackage } from \"./cache\";\r\nimport { PACKAGE_NAME } from \"./constants\";\r\nimport { logAutoUpdate } from \"./logging\";\r\n\r\ninterface PluginClient {\r\n tui: {\r\n showToast(options: {\r\n body: {\r\n title?: string;\r\n message: string;\r\n variant: \"info\" | \"warning\" | \"success\" | \"error\";\r\n duration?: number;\r\n };\r\n }): Promise<unknown>;\r\n };\r\n}\r\n\r\ninterface SessionCreatedEvent {\r\n type: \"session.created\";\r\n properties?: {\r\n info?: {\r\n parentID?: string;\r\n };\r\n };\r\n}\r\n\r\ntype PluginEvent = SessionCreatedEvent | { type: string; properties?: unknown };\r\n\r\nexport function createAutoUpdateCheckerHook(\r\n client: PluginClient,\r\n directory: string,\r\n options: AutoUpdateCheckerOptions = {}\r\n) {\r\n const { showStartupToast = true, autoUpdate = true } = options;\r\n\r\n let hasChecked = false;\r\n\r\n return {\r\n event: ({ event }: { event: PluginEvent }) => {\r\n if (event.type !== \"session.created\") return;\r\n if (hasChecked) return;\r\n\r\n const props = event.properties as { info?: { parentID?: string } } | undefined;\r\n if (props?.info?.parentID) return;\r\n\r\n hasChecked = true;\r\n\r\n setTimeout(() => {\r\n const localDevVersion = getLocalDevVersion(directory);\r\n\r\n if (localDevVersion) {\r\n if (showStartupToast) {\r\n showLocalDevToast(client, localDevVersion).catch(() => {});\r\n }\r\n logAutoUpdate(\"Local development mode\");\r\n return;\r\n }\r\n\r\n runBackgroundUpdateCheck(client, directory, autoUpdate).catch((err) => {\r\n logAutoUpdate(`Background update check failed: ${err}`);\r\n });\r\n }, 0);\r\n },\r\n };\r\n}\r\n\r\nasync function runBackgroundUpdateCheck(\r\n client: PluginClient,\r\n directory: string,\r\n autoUpdate: boolean\r\n): Promise<void> {\r\n const pluginInfo = findPluginEntry(directory);\r\n if (!pluginInfo) {\r\n logAutoUpdate(\"Plugin not found in config\");\r\n return;\r\n }\r\n\r\n const cachedVersion = getCachedVersion();\r\n const currentVersion = cachedVersion ?? pluginInfo.pinnedVersion;\r\n if (!currentVersion) {\r\n logAutoUpdate(\"No version found (cached or pinned)\");\r\n return;\r\n }\r\n\r\n if (currentVersion.includes('-')) {\r\n logAutoUpdate(`Prerelease version (${currentVersion}), skipping auto-update`);\r\n return;\r\n }\r\n\r\n const latestVersion = await getLatestVersion();\r\n if (!latestVersion) {\r\n logAutoUpdate(\"Failed to fetch latest version\");\r\n return;\r\n }\r\n\r\n if (currentVersion === latestVersion) {\r\n logAutoUpdate(\"Already on latest version\");\r\n return;\r\n }\r\n\r\n logAutoUpdate(`Update available: ${currentVersion} \u2192 ${latestVersion}`);\r\n\r\n if (!autoUpdate) {\r\n await showUpdateAvailableToast(client, latestVersion);\r\n logAutoUpdate(\"Auto-update disabled, notification only\");\r\n return;\r\n }\r\n\r\n if (pluginInfo.isPinned) {\r\n const updated = updatePinnedVersion(pluginInfo.configPath, pluginInfo.entry, latestVersion);\r\n if (updated) {\r\n invalidatePackage(PACKAGE_NAME);\r\n await showAutoUpdatedToast(client, currentVersion, latestVersion);\r\n logAutoUpdate(`Config updated: ${pluginInfo.entry} \u2192 ${PACKAGE_NAME}@${latestVersion}`);\r\n } else {\r\n await showUpdateAvailableToast(client, latestVersion);\r\n }\r\n } else {\r\n invalidatePackage(PACKAGE_NAME);\r\n await showUpdateAvailableToast(client, latestVersion);\r\n }\r\n}\r\n\r\nasync function showUpdateAvailableToast(client: PluginClient, latestVersion: string): Promise<void> {\r\n await client.tui\r\n .showToast({\r\n body: {\r\n title: `Antigravity Auth Update`,\r\n message: `v${latestVersion} available. Restart OpenCode to apply.`,\r\n variant: \"info\" as const,\r\n duration: 8000,\r\n },\r\n })\r\n .catch(() => {});\r\n logAutoUpdate(`Update available toast shown: v${latestVersion}`);\r\n}\r\n\r\nasync function showAutoUpdatedToast(client: PluginClient, oldVersion: string, newVersion: string): Promise<void> {\r\n await client.tui\r\n .showToast({\r\n body: {\r\n title: `Antigravity Auth Updated!`,\r\n message: `v${oldVersion} \u2192 v${newVersion}\\nRestart OpenCode to apply.`,\r\n variant: \"success\" as const,\r\n duration: 8000,\r\n },\r\n })\r\n .catch(() => {});\r\n logAutoUpdate(`Auto-updated toast shown: v${oldVersion} \u2192 v${newVersion}`);\r\n}\r\n\r\nasync function showLocalDevToast(client: PluginClient, version: string): Promise<void> {\r\n await client.tui\r\n .showToast({\r\n body: {\r\n title: `Antigravity Auth ${version} (dev)`,\r\n message: \"Running in local development mode.\",\r\n variant: \"warning\" as const,\r\n duration: 5000,\r\n },\r\n })\r\n .catch(() => {});\r\n logAutoUpdate(`Local dev toast shown: v${version}`);\r\n}\r\n\r\nexport type { UpdateCheckResult, AutoUpdateCheckerOptions } from \"./types\";\r\nexport { checkForUpdate, getCachedVersion, getLatestVersion } from \"./checker\";\r\nexport { invalidatePackage, invalidateCache } from \"./cache\";\r\n", "import {\r\n ANTIGRAVITY_ENDPOINT_PROD,\r\n getAntigravityHeaders,\r\n ANTIGRAVITY_PROVIDER_ID,\r\n} from \"../constants\";\r\nimport { accessTokenExpired, formatRefreshParts, parseRefreshParts } from \"./auth\";\r\nimport { logQuotaFetch, logQuotaStatus } from \"./debug\";\r\nimport { ensureProjectContext } from \"./project\";\r\nimport { refreshAccessToken } from \"./token\";\r\nimport { getModelFamily } from \"./transform/model-resolver\";\r\nimport type { PluginClient, OAuthAuthDetails } from \"./types\";\r\nimport type { AccountMetadataV3 } from \"./storage\";\r\n\r\nconst FETCH_TIMEOUT_MS = 10000;\r\n\r\nexport type QuotaGroup = \"claude\" | \"gemini-pro\" | \"gemini-flash\";\r\n\r\nexport interface QuotaGroupSummary {\r\n remainingFraction?: number;\r\n resetTime?: string;\r\n modelCount: number;\r\n}\r\n\r\nexport interface QuotaSummary {\r\n groups: Partial<Record<QuotaGroup, QuotaGroupSummary>>;\r\n modelCount: number;\r\n error?: string;\r\n}\r\n\r\n// Gemini CLI quota types\r\nexport interface GeminiCliQuotaModel {\r\n modelId: string;\r\n remainingFraction: number;\r\n resetTime?: string;\r\n}\r\n\r\nexport interface GeminiCliQuotaSummary {\r\n models: GeminiCliQuotaModel[];\r\n error?: string;\r\n}\r\n\r\ninterface RetrieveUserQuotaResponse {\r\n buckets?: {\r\n remainingAmount?: string;\r\n remainingFraction?: number;\r\n resetTime?: string;\r\n tokenType?: string;\r\n modelId?: string;\r\n }[];\r\n}\r\n\r\nexport type AccountQuotaStatus = \"ok\" | \"disabled\" | \"error\";\r\n\r\nexport interface AccountQuotaResult {\r\n index: number;\r\n email?: string;\r\n status: AccountQuotaStatus;\r\n error?: string;\r\n disabled?: boolean;\r\n quota?: QuotaSummary;\r\n geminiCliQuota?: GeminiCliQuotaSummary;\r\n updatedAccount?: AccountMetadataV3;\r\n}\r\n\r\ninterface FetchAvailableModelsResponse {\r\n models?: Record<string, FetchAvailableModelEntry>;\r\n}\r\n\r\ninterface FetchAvailableModelEntry {\r\n quotaInfo?: {\r\n remainingFraction?: number;\r\n resetTime?: string;\r\n };\r\n displayName?: string;\r\n modelName?: string;\r\n}\r\n\r\nfunction buildAuthFromAccount(account: AccountMetadataV3): OAuthAuthDetails {\r\n return {\r\n type: \"oauth\",\r\n refresh: formatRefreshParts({\r\n refreshToken: account.refreshToken,\r\n projectId: account.projectId,\r\n managedProjectId: account.managedProjectId,\r\n }),\r\n access: undefined,\r\n expires: undefined,\r\n };\r\n}\r\n\r\nfunction normalizeRemainingFraction(value: unknown): number {\r\n // If value is missing or invalid, treat as exhausted (0%)\r\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\r\n return 0;\r\n }\r\n if (value < 0) return 0;\r\n if (value > 1) return 1;\r\n return value;\r\n}\r\n\r\nfunction parseResetTime(resetTime?: string): number | null {\r\n if (!resetTime) return null;\r\n const timestamp = Date.parse(resetTime);\r\n if (!Number.isFinite(timestamp)) {\r\n return null;\r\n }\r\n return timestamp;\r\n}\r\n\r\nfunction classifyQuotaGroup(modelName: string, displayName?: string): QuotaGroup | null {\r\n const combined = `${modelName} ${displayName ?? \"\"}`.toLowerCase();\r\n if (combined.includes(\"claude\")) {\r\n return \"claude\";\r\n }\r\n const isGemini3 = combined.includes(\"gemini-3\") || combined.includes(\"gemini 3\");\r\n if (!isGemini3) {\r\n return null;\r\n }\r\n const family = getModelFamily(modelName);\r\n return family === \"gemini-flash\" ? \"gemini-flash\" : \"gemini-pro\";\r\n}\r\n\r\nfunction aggregateQuota(models?: Record<string, FetchAvailableModelEntry>): QuotaSummary {\r\n const groups: Partial<Record<QuotaGroup, QuotaGroupSummary>> = {};\r\n if (!models) {\r\n return { groups, modelCount: 0 };\r\n }\r\n\r\n let totalCount = 0;\r\n for (const [modelName, entry] of Object.entries(models)) {\r\n const group = classifyQuotaGroup(modelName, entry.displayName ?? entry.modelName);\r\n if (!group) {\r\n continue;\r\n }\r\n const quotaInfo = entry.quotaInfo;\r\n const remainingFraction = quotaInfo\r\n ? normalizeRemainingFraction(quotaInfo.remainingFraction)\r\n : undefined;\r\n const resetTime = quotaInfo?.resetTime;\r\n const resetTimestamp = parseResetTime(resetTime);\r\n\r\n totalCount += 1;\r\n\r\n const existing = groups[group];\r\n const nextCount = (existing?.modelCount ?? 0) + 1;\r\n const nextRemaining =\r\n remainingFraction === undefined\r\n ? existing?.remainingFraction\r\n : existing?.remainingFraction === undefined\r\n ? remainingFraction\r\n : Math.min(existing.remainingFraction, remainingFraction);\r\n\r\n let nextResetTime = existing?.resetTime;\r\n if (resetTimestamp !== null) {\r\n if (!existing?.resetTime) {\r\n nextResetTime = resetTime;\r\n } else {\r\n const existingTimestamp = parseResetTime(existing.resetTime);\r\n if (existingTimestamp === null || resetTimestamp < existingTimestamp) {\r\n nextResetTime = resetTime;\r\n }\r\n }\r\n }\r\n\r\n groups[group] = {\r\n remainingFraction: nextRemaining,\r\n resetTime: nextResetTime,\r\n modelCount: nextCount,\r\n };\r\n }\r\n\r\n return { groups, modelCount: totalCount };\r\n}\r\n\r\nasync function fetchWithTimeout(url: string, options: RequestInit, timeoutMs = FETCH_TIMEOUT_MS): Promise<Response> {\r\n const controller = new AbortController();\r\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\r\n try {\r\n return await fetch(url, { ...options, signal: controller.signal });\r\n } finally {\r\n clearTimeout(timeout);\r\n }\r\n}\r\n\r\nasync function fetchAvailableModels(\r\n accessToken: string,\r\n projectId: string,\r\n): Promise<FetchAvailableModelsResponse> {\r\n const endpoint = ANTIGRAVITY_ENDPOINT_PROD;\r\n const quotaUserAgent = getAntigravityHeaders()[\"User-Agent\"] || \"antigravity/windows/amd64\";\r\n const errors: string[] = [];\r\n\r\n const body = projectId ? { project: projectId } : {};\r\n const response = await fetchWithTimeout(`${endpoint}/v1internal:fetchAvailableModels`, {\r\n method: \"POST\",\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n \"Content-Type\": \"application/json\",\r\n \"User-Agent\": quotaUserAgent,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (response.ok) {\r\n return (await response.json()) as FetchAvailableModelsResponse;\r\n }\r\n\r\n const message = await response.text().catch(() => \"\");\r\n const snippet = message.trim().slice(0, 200);\r\n errors.push(\r\n `fetchAvailableModels ${response.status} at ${endpoint}${snippet ? `: ${snippet}` : \"\"}`,\r\n );\r\n\r\n throw new Error(errors.join(\"; \") || \"fetchAvailableModels failed\");\r\n}\r\n\r\nasync function fetchGeminiCliQuota(\r\n accessToken: string,\r\n projectId: string,\r\n): Promise<RetrieveUserQuotaResponse> {\r\n const endpoint = ANTIGRAVITY_ENDPOINT_PROD;\r\n // Use Gemini CLI user-agent to get CLI quota buckets (not Antigravity buckets)\r\n const platform = process.platform || \"darwin\";\r\n const arch = process.arch || \"arm64\";\r\n const geminiCliUserAgent = `GeminiCLI/1.0.0/gemini-2.5-pro (${platform}; ${arch})`;\r\n\r\n const body = projectId ? { project: projectId } : {};\r\n \r\n try {\r\n const response = await fetchWithTimeout(`${endpoint}/v1internal:retrieveUserQuota`, {\r\n method: \"POST\",\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n \"Content-Type\": \"application/json\",\r\n \"User-Agent\": geminiCliUserAgent,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (response.ok) {\r\n const data = (await response.json()) as RetrieveUserQuotaResponse;\r\n return data;\r\n }\r\n\r\n // Non-OK response - return empty buckets\r\n return { buckets: [] };\r\n } catch {\r\n // Network error or timeout - return empty buckets\r\n return { buckets: [] };\r\n }\r\n}\r\n\r\nfunction aggregateGeminiCliQuota(response: RetrieveUserQuotaResponse): GeminiCliQuotaSummary {\r\n const models: GeminiCliQuotaModel[] = [];\r\n \r\n if (!response.buckets || response.buckets.length === 0) {\r\n return { models };\r\n }\r\n\r\n for (const bucket of response.buckets) {\r\n if (!bucket.modelId) {\r\n continue;\r\n }\r\n \r\n // Filter out models we don't care about for Gemini CLI quotas\r\n // Only show gemini-3-* and gemini-2.5-pro models (the premium ones)\r\n const modelId = bucket.modelId;\r\n const isRelevantModel = \r\n modelId.startsWith(\"gemini-3-\") || \r\n modelId === \"gemini-2.5-pro\";\r\n \r\n if (!isRelevantModel) {\r\n continue;\r\n }\r\n \r\n models.push({\r\n modelId: bucket.modelId,\r\n remainingFraction: normalizeRemainingFraction(bucket.remainingFraction),\r\n resetTime: bucket.resetTime,\r\n });\r\n }\r\n\r\n // Sort by model ID for consistent display\r\n models.sort((a, b) => a.modelId.localeCompare(b.modelId));\r\n\r\n return { models };\r\n}\r\n\r\nfunction applyAccountUpdates(account: AccountMetadataV3, auth: OAuthAuthDetails): AccountMetadataV3 | undefined {\r\n const parts = parseRefreshParts(auth.refresh);\r\n if (!parts.refreshToken) {\r\n return undefined;\r\n }\r\n\r\n const updated: AccountMetadataV3 = {\r\n ...account,\r\n refreshToken: parts.refreshToken,\r\n projectId: parts.projectId ?? account.projectId,\r\n managedProjectId: parts.managedProjectId ?? account.managedProjectId,\r\n };\r\n\r\n const changed =\r\n updated.refreshToken !== account.refreshToken ||\r\n updated.projectId !== account.projectId ||\r\n updated.managedProjectId !== account.managedProjectId;\r\n\r\n return changed ? updated : undefined;\r\n}\r\n\r\nexport async function checkAccountsQuota(\r\n accounts: AccountMetadataV3[],\r\n client: PluginClient,\r\n providerId = ANTIGRAVITY_PROVIDER_ID,\r\n): Promise<AccountQuotaResult[]> {\r\n const results: AccountQuotaResult[] = [];\r\n \r\n logQuotaFetch(\"start\", accounts.length);\r\n\r\n for (const [index, account] of accounts.entries()) {\r\n const disabled = account.enabled === false;\r\n\r\n let auth = buildAuthFromAccount(account);\r\n\r\n try {\r\n if (accessTokenExpired(auth)) {\r\n const refreshed = await refreshAccessToken(auth, client, providerId);\r\n if (!refreshed) {\r\n throw new Error(\"Token refresh failed\");\r\n }\r\n auth = refreshed;\r\n }\r\n\r\n const projectContext = await ensureProjectContext(auth);\r\n auth = projectContext.auth;\r\n const updatedAccount = applyAccountUpdates(account, auth);\r\n\r\n let quotaResult: QuotaSummary;\r\n let geminiCliQuotaResult: GeminiCliQuotaSummary;\r\n \r\n // Fetch both Antigravity and Gemini CLI quotas in parallel\r\n const [antigravityResponse, geminiCliResponse] = await Promise.all([\r\n fetchAvailableModels(auth.access ?? \"\", projectContext.effectiveProjectId)\r\n .catch((error): FetchAvailableModelsResponse => ({ models: undefined })),\r\n fetchGeminiCliQuota(auth.access ?? \"\", projectContext.effectiveProjectId),\r\n ]);\r\n\r\n // Process Antigravity quota\r\n if (antigravityResponse.models === undefined) {\r\n quotaResult = {\r\n groups: {},\r\n modelCount: 0,\r\n error: \"Failed to fetch Antigravity quota\",\r\n };\r\n } else {\r\n quotaResult = aggregateQuota(antigravityResponse.models);\r\n }\r\n\r\n // Process Gemini CLI quota\r\n geminiCliQuotaResult = aggregateGeminiCliQuota(geminiCliResponse);\r\n if (geminiCliResponse.buckets === undefined || geminiCliResponse.buckets.length === 0) {\r\n geminiCliQuotaResult.error = geminiCliQuotaResult.models.length === 0 \r\n ? \"No Gemini CLI quota available\" \r\n : undefined;\r\n }\r\n\r\n results.push({\r\n index,\r\n email: account.email,\r\n status: \"ok\",\r\n disabled,\r\n quota: quotaResult,\r\n geminiCliQuota: geminiCliQuotaResult,\r\n updatedAccount,\r\n });\r\n \r\n // Log quota status for each family\r\n for (const [family, groupQuota] of Object.entries(quotaResult.groups)) {\r\n const remainingPercent = (groupQuota.remainingFraction ?? 0) * 100;\r\n logQuotaStatus(account.email, index, remainingPercent, family);\r\n }\r\n } catch (error) {\r\n results.push({\r\n index,\r\n email: account.email,\r\n status: \"error\",\r\n disabled,\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n logQuotaFetch(\"error\", undefined, `account=${account.email ?? index} error=${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n }\r\n\r\n logQuotaFetch(\"complete\", accounts.length, `ok=${results.filter(r => r.status === \"ok\").length} errors=${results.filter(r => r.status === \"error\").length}`);\r\n return results;\r\n}\r\n", "/**\r\n * Proactive Token Refresh Queue\r\n * \r\n * Ported from LLM-API-Key-Proxy's BackgroundRefresher.\r\n * \r\n * This module provides background token refresh to ensure OAuth tokens\r\n * remain valid without blocking user requests. It periodically checks\r\n * all accounts and refreshes tokens that are approaching expiry.\r\n * \r\n * Features:\r\n * - Non-blocking background refresh (doesn't block requests)\r\n * - Configurable refresh buffer (default: 30 minutes before expiry)\r\n * - Configurable check interval (default: 5 minutes)\r\n * - Serialized refresh to prevent concurrent refresh storms\r\n * - Integrates with existing AccountManager and token refresh logic\r\n * - Silent operation: no console output, uses structured logger\r\n */\r\n\r\nimport type { AccountManager, ManagedAccount } from \"./accounts\";\r\nimport type { PluginClient, OAuthAuthDetails } from \"./types\";\r\nimport { refreshAccessToken } from \"./token\";\r\nimport { createLogger } from \"./logger\";\r\n\r\nconst log = createLogger(\"refresh-queue\");\r\n\r\n/** Configuration for the proactive refresh queue */\r\nexport interface ProactiveRefreshConfig {\r\n /** Enable proactive token refresh (default: true) */\r\n enabled: boolean;\r\n /** Seconds before expiry to trigger proactive refresh (default: 1800 = 30 minutes) */\r\n bufferSeconds: number;\r\n /** Interval between refresh checks in seconds (default: 300 = 5 minutes) */\r\n checkIntervalSeconds: number;\r\n}\r\n\r\nexport const DEFAULT_PROACTIVE_REFRESH_CONFIG: ProactiveRefreshConfig = {\r\n enabled: true,\r\n bufferSeconds: 1800, // 30 minutes\r\n checkIntervalSeconds: 300, // 5 minutes\r\n};\r\n\r\n/** State for tracking refresh operations */\r\ninterface RefreshQueueState {\r\n isRunning: boolean;\r\n intervalHandle: ReturnType<typeof setInterval> | null;\r\n isRefreshing: boolean;\r\n lastCheckTime: number;\r\n lastRefreshTime: number;\r\n refreshCount: number;\r\n errorCount: number;\r\n}\r\n\r\n/**\r\n * Proactive Token Refresh Queue\r\n * \r\n * Runs in the background and proactively refreshes tokens before they expire.\r\n * This ensures that user requests never block on token refresh.\r\n * \r\n * All logging is silent by default - uses structured logger with TUI integration.\r\n */\r\nexport class ProactiveRefreshQueue {\r\n private readonly config: ProactiveRefreshConfig;\r\n private readonly client: PluginClient;\r\n private readonly providerId: string;\r\n private accountManager: AccountManager | null = null;\r\n \r\n private state: RefreshQueueState = {\r\n isRunning: false,\r\n intervalHandle: null,\r\n isRefreshing: false,\r\n lastCheckTime: 0,\r\n lastRefreshTime: 0,\r\n refreshCount: 0,\r\n errorCount: 0,\r\n };\r\n\r\n constructor(\r\n client: PluginClient,\r\n providerId: string,\r\n config?: Partial<ProactiveRefreshConfig>,\r\n ) {\r\n this.client = client;\r\n this.providerId = providerId;\r\n this.config = {\r\n ...DEFAULT_PROACTIVE_REFRESH_CONFIG,\r\n ...config,\r\n };\r\n }\r\n\r\n /**\r\n * Set the account manager to use for refresh operations.\r\n * Must be called before start().\r\n */\r\n setAccountManager(manager: AccountManager): void {\r\n this.accountManager = manager;\r\n }\r\n\r\n /**\r\n * Check if a token needs proactive refresh.\r\n * Returns true if the token expires within the buffer period.\r\n */\r\n needsRefresh(account: ManagedAccount): boolean {\r\n if (!account.expires) {\r\n // No expiry set - assume it's fine\r\n return false;\r\n }\r\n\r\n const now = Date.now();\r\n const bufferMs = this.config.bufferSeconds * 1000;\r\n const refreshThreshold = now + bufferMs;\r\n\r\n return account.expires <= refreshThreshold;\r\n }\r\n\r\n /**\r\n * Check if a token is already expired.\r\n */\r\n isExpired(account: ManagedAccount): boolean {\r\n if (!account.expires) {\r\n return false;\r\n }\r\n return account.expires <= Date.now();\r\n }\r\n\r\n /**\r\n * Get all accounts that need proactive refresh.\r\n */\r\n getAccountsNeedingRefresh(): ManagedAccount[] {\r\n if (!this.accountManager) {\r\n return [];\r\n }\r\n\r\n return this.accountManager.getAccounts().filter((account) => {\r\n // Skip disabled accounts - they shouldn't receive proactive refresh\r\n if (account.enabled === false) {\r\n return false;\r\n }\r\n // Only refresh if not already expired (let the main flow handle expired tokens)\r\n if (this.isExpired(account)) {\r\n return false;\r\n }\r\n return this.needsRefresh(account);\r\n });\r\n }\r\n\r\n /**\r\n * Perform a single refresh check iteration.\r\n * This is called periodically by the background interval.\r\n */\r\n private async runRefreshCheck(): Promise<void> {\r\n if (this.state.isRefreshing) {\r\n // Already refreshing - skip this iteration\r\n return;\r\n }\r\n\r\n if (!this.accountManager) {\r\n return;\r\n }\r\n\r\n this.state.isRefreshing = true;\r\n this.state.lastCheckTime = Date.now();\r\n\r\n try {\r\n const accountsToRefresh = this.getAccountsNeedingRefresh();\r\n\r\n if (accountsToRefresh.length === 0) {\r\n return;\r\n }\r\n\r\n log.debug(\"Found accounts needing refresh\", { count: accountsToRefresh.length });\r\n\r\n // Refresh accounts serially to avoid concurrent refresh storms\r\n for (const account of accountsToRefresh) {\r\n if (!this.state.isRunning) {\r\n // Queue was stopped - abort\r\n break;\r\n }\r\n\r\n try {\r\n const auth = this.accountManager.toAuthDetails(account);\r\n const refreshed = await this.refreshToken(auth, account);\r\n\r\n if (refreshed) {\r\n this.accountManager.updateFromAuth(account, refreshed);\r\n this.state.refreshCount++;\r\n this.state.lastRefreshTime = Date.now();\r\n\r\n // Persist the refreshed token\r\n try {\r\n await this.accountManager.saveToDisk();\r\n } catch {\r\n // Non-fatal - token is refreshed in memory\r\n }\r\n }\r\n } catch (error) {\r\n this.state.errorCount++;\r\n // Log but don't throw - continue with other accounts\r\n log.warn(\"Failed to refresh account\", {\r\n accountIndex: account.index,\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n }\r\n }\r\n } finally {\r\n this.state.isRefreshing = false;\r\n }\r\n }\r\n\r\n /**\r\n * Refresh a single token.\r\n */\r\n private async refreshToken(\r\n auth: OAuthAuthDetails,\r\n account: ManagedAccount,\r\n ): Promise<OAuthAuthDetails | undefined> {\r\n const minutesUntilExpiry = account.expires\r\n ? Math.round((account.expires - Date.now()) / 60000)\r\n : \"unknown\";\r\n\r\n log.debug(\"Proactively refreshing token\", {\r\n accountIndex: account.index,\r\n email: account.email ?? \"unknown\",\r\n minutesUntilExpiry,\r\n });\r\n\r\n return refreshAccessToken(auth, this.client, this.providerId);\r\n }\r\n\r\n /**\r\n * Start the background refresh queue.\r\n */\r\n start(): void {\r\n if (this.state.isRunning) {\r\n return;\r\n }\r\n\r\n if (!this.config.enabled) {\r\n log.debug(\"Proactive refresh disabled by config\");\r\n return;\r\n }\r\n\r\n this.state.isRunning = true;\r\n const intervalMs = this.config.checkIntervalSeconds * 1000;\r\n\r\n log.debug(\"Started proactive refresh queue\", {\r\n checkIntervalSeconds: this.config.checkIntervalSeconds,\r\n bufferSeconds: this.config.bufferSeconds,\r\n });\r\n\r\n // Run initial check after a short delay (let things settle)\r\n setTimeout(() => {\r\n if (this.state.isRunning) {\r\n this.runRefreshCheck().catch((error) => {\r\n log.error(\"Initial check failed\", {\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n });\r\n }\r\n }, 5000);\r\n\r\n // Set up periodic checks\r\n this.state.intervalHandle = setInterval(() => {\r\n this.runRefreshCheck().catch((error) => {\r\n log.error(\"Check failed\", {\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n });\r\n }, intervalMs);\r\n }\r\n\r\n /**\r\n * Stop the background refresh queue.\r\n */\r\n stop(): void {\r\n if (!this.state.isRunning) {\r\n return;\r\n }\r\n\r\n this.state.isRunning = false;\r\n\r\n if (this.state.intervalHandle) {\r\n clearInterval(this.state.intervalHandle);\r\n this.state.intervalHandle = null;\r\n }\r\n\r\n log.debug(\"Stopped proactive refresh queue\", {\r\n refreshCount: this.state.refreshCount,\r\n errorCount: this.state.errorCount,\r\n });\r\n }\r\n\r\n /**\r\n * Get current queue statistics.\r\n */\r\n getStats(): {\r\n isRunning: boolean;\r\n isRefreshing: boolean;\r\n lastCheckTime: number;\r\n lastRefreshTime: number;\r\n refreshCount: number;\r\n errorCount: number;\r\n } {\r\n return { ...this.state };\r\n }\r\n\r\n /**\r\n * Check if the queue is currently running.\r\n */\r\n isRunning(): boolean {\r\n return this.state.isRunning;\r\n }\r\n}\r\n\r\n/**\r\n * Create a proactive refresh queue instance.\r\n */\r\nexport function createProactiveRefreshQueue(\r\n client: PluginClient,\r\n providerId: string,\r\n config?: Partial<ProactiveRefreshConfig>,\r\n): ProactiveRefreshQueue {\r\n return new ProactiveRefreshQueue(client, providerId, config);\r\n}\r\n", "/**\r\n * Remote Antigravity version fetcher.\r\n *\r\n * Mirrors the Antigravity-Manager's version resolution strategy:\r\n * 1. Auto-updater API (plain text with semver)\r\n * 2. Changelog page scrape (first 5000 chars)\r\n * 3. Hardcoded fallback in constants.ts\r\n *\r\n * Called once at plugin startup to ensure headers use the latest\r\n * supported version, avoiding \"version no longer supported\" errors.\r\n *\r\n * @see https://github.com/lbjlaq/Antigravity-Manager (src-tauri/src/constants.rs)\r\n */\r\n\r\nimport { getAntigravityVersion, setAntigravityVersion } from \"../constants\";\r\nimport { createLogger } from \"./logger\";\r\n\r\nconst VERSION_URL = \"https://antigravity-auto-updater-974169037036.us-central1.run.app\";\r\nconst CHANGELOG_URL = \"https://antigravity.google/changelog\";\r\nconst FETCH_TIMEOUT_MS = 5000;\r\nconst CHANGELOG_SCAN_CHARS = 5000;\r\nconst VERSION_REGEX = /\\d+\\.\\d+\\.\\d+/;\r\n\r\ntype VersionSource = \"api\" | \"changelog\" | \"fallback\";\r\n\r\nfunction parseVersion(text: string): string | null {\r\n const match = text.match(VERSION_REGEX);\r\n return match ? match[0] : null;\r\n}\r\n\r\nasync function tryFetchVersion(url: string, maxChars?: number): Promise<string | null> {\r\n const controller = new AbortController();\r\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\r\n try {\r\n const response = await fetch(url, { signal: controller.signal });\r\n if (!response.ok) return null;\r\n let text = await response.text();\r\n if (maxChars) text = text.slice(0, maxChars);\r\n return parseVersion(text);\r\n } catch {\r\n return null;\r\n } finally {\r\n clearTimeout(timeout);\r\n }\r\n}\r\n\r\n/**\r\n * Fetch the latest Antigravity version and update the global constant.\r\n * Safe to call before logger is initialized (will silently skip logging).\r\n */\r\nexport async function initAntigravityVersion(): Promise<void> {\r\n const log = createLogger(\"version\");\r\n const fallback = getAntigravityVersion();\r\n let version: string | null;\r\n let source: VersionSource;\r\n\r\n // 1. Try auto-updater API\r\n version = await tryFetchVersion(VERSION_URL);\r\n if (version) {\r\n source = \"api\";\r\n } else {\r\n // 2. Try changelog page scrape\r\n version = await tryFetchVersion(CHANGELOG_URL, CHANGELOG_SCAN_CHARS);\r\n if (version) {\r\n source = \"changelog\";\r\n } else {\r\n // 3. Fall back to hardcoded\r\n source = \"fallback\";\r\n setAntigravityVersion(fallback);\r\n log.info(\"version-fetch-failed\", { fallback });\r\n return;\r\n }\r\n }\r\n\r\n if (version !== fallback) {\r\n log.info(\"version-updated\", { version, source, previous: fallback });\r\n } else {\r\n log.debug(\"version-unchanged\", { version, source });\r\n }\r\n setAntigravityVersion(version);\r\n}\r\n", "/**\r\n * Google Search Tool Implementation\r\n *\r\n * Due to Gemini API limitations, native search tools (googleSearch, urlContext)\r\n * cannot be combined with function declarations. This module implements a\r\n * wrapper that makes separate API calls with only the grounding tools enabled.\r\n */\r\n\r\nimport {\r\n ANTIGRAVITY_ENDPOINT,\r\n getAntigravityHeaders,\r\n SEARCH_MODEL,\r\n SEARCH_TIMEOUT_MS,\r\n SEARCH_SYSTEM_INSTRUCTION,\r\n} from \"../constants\";\r\nimport { createLogger } from \"./logger\";\r\n\r\nconst log = createLogger(\"search\");\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\ninterface GroundingChunk {\r\n web?: {\r\n uri?: string;\r\n title?: string;\r\n };\r\n}\r\n\r\ninterface GroundingSupport {\r\n segment?: {\r\n startIndex?: number;\r\n endIndex?: number;\r\n text?: string;\r\n };\r\n groundingChunkIndices?: number[];\r\n}\r\n\r\ninterface GroundingMetadata {\r\n webSearchQueries?: string[];\r\n groundingChunks?: GroundingChunk[];\r\n groundingSupports?: GroundingSupport[];\r\n searchEntryPoint?: {\r\n renderedContent?: string;\r\n };\r\n}\r\n\r\ninterface UrlMetadata {\r\n retrieved_url?: string;\r\n url_retrieval_status?: string;\r\n}\r\n\r\ninterface UrlContextMetadata {\r\n url_metadata?: UrlMetadata[];\r\n}\r\n\r\ninterface SearchResponse {\r\n candidates?: Array<{\r\n content?: {\r\n parts?: Array<{ text?: string }>;\r\n role?: string;\r\n };\r\n finishReason?: string;\r\n groundingMetadata?: GroundingMetadata;\r\n urlContextMetadata?: UrlContextMetadata;\r\n }>;\r\n error?: {\r\n code?: number;\r\n message?: string;\r\n status?: string;\r\n };\r\n}\r\n\r\ninterface AntigravitySearchResponse {\r\n response?: SearchResponse;\r\n error?: {\r\n code?: number;\r\n message?: string;\r\n status?: string;\r\n };\r\n}\r\n\r\nexport interface SearchArgs {\r\n query: string;\r\n urls?: string[];\r\n thinking?: boolean;\r\n}\r\n\r\nexport interface SearchResult {\r\n text: string;\r\n sources: Array<{ title: string; url: string }>;\r\n searchQueries: string[];\r\n urlsRetrieved: Array<{ url: string; status: string }>;\r\n}\r\n\r\n// ============================================================================\r\n// Helper Functions\r\n// ============================================================================\r\n\r\nlet sessionCounter = 0;\r\nconst sessionPrefix = `search-${Date.now().toString(36)}`;\r\n\r\nfunction generateRequestId(): string {\r\n return `search-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\r\n}\r\n\r\nfunction getSessionId(): string {\r\n sessionCounter++;\r\n return `${sessionPrefix}-${sessionCounter}`;\r\n}\r\n\r\nfunction formatSearchResult(result: SearchResult): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(\"## Search Results\\n\");\r\n lines.push(result.text);\r\n lines.push(\"\");\r\n\r\n if (result.sources.length > 0) {\r\n lines.push(\"### Sources\");\r\n for (const source of result.sources) {\r\n lines.push(`- [${source.title}](${source.url})`);\r\n }\r\n lines.push(\"\");\r\n }\r\n\r\n if (result.urlsRetrieved.length > 0) {\r\n lines.push(\"### URLs Retrieved\");\r\n for (const url of result.urlsRetrieved) {\r\n const status = url.status === \"URL_RETRIEVAL_STATUS_SUCCESS\" ? \"\u2713\" : \"\u2717\";\r\n lines.push(`- ${status} ${url.url}`);\r\n }\r\n lines.push(\"\");\r\n }\r\n\r\n if (result.searchQueries.length > 0) {\r\n lines.push(\"### Search Queries Used\");\r\n for (const q of result.searchQueries) {\r\n lines.push(`- \"${q}\"`);\r\n }\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n\r\nfunction parseSearchResponse(data: AntigravitySearchResponse): SearchResult {\r\n const result: SearchResult = {\r\n text: \"\",\r\n sources: [],\r\n searchQueries: [],\r\n urlsRetrieved: [],\r\n };\r\n\r\n const response = data.response;\r\n if (!response || !response.candidates || response.candidates.length === 0) {\r\n if (data.error) {\r\n result.text = `Error: ${data.error.message ?? \"Unknown error\"}`;\r\n } else if (response?.error) {\r\n result.text = `Error: ${response.error.message ?? \"Unknown error\"}`;\r\n }\r\n return result;\r\n }\r\n\r\n const candidate = response.candidates[0];\r\n if (!candidate) {\r\n return result;\r\n }\r\n\r\n // Extract text content\r\n if (candidate.content?.parts) {\r\n result.text = candidate.content.parts\r\n .map((p: { text?: string }) => p.text ?? \"\")\r\n .filter(Boolean)\r\n .join(\"\\n\");\r\n }\r\n\r\n // Extract grounding metadata\r\n if (candidate.groundingMetadata) {\r\n const groundingMeta = candidate.groundingMetadata;\r\n\r\n if (groundingMeta.webSearchQueries) {\r\n result.searchQueries = groundingMeta.webSearchQueries;\r\n }\r\n\r\n if (groundingMeta.groundingChunks) {\r\n for (const chunk of groundingMeta.groundingChunks) {\r\n if (chunk.web?.uri && chunk.web?.title) {\r\n result.sources.push({\r\n title: chunk.web.title,\r\n url: chunk.web.uri,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Extract URL context metadata\r\n if (candidate.urlContextMetadata?.url_metadata) {\r\n for (const meta of candidate.urlContextMetadata.url_metadata) {\r\n if (meta.retrieved_url) {\r\n result.urlsRetrieved.push({\r\n url: meta.retrieved_url,\r\n status: meta.url_retrieval_status ?? \"UNKNOWN\",\r\n });\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ============================================================================\r\n// Main Search Function\r\n// ============================================================================\r\n\r\n/**\r\n * Execute a Google Search using the Gemini grounding API.\r\n *\r\n * This makes a SEPARATE API call with only googleSearch/urlContext tools,\r\n * which is required because these tools cannot be combined with function declarations.\r\n */\r\nexport async function executeSearch(\r\n args: SearchArgs,\r\n accessToken: string,\r\n projectId: string,\r\n abortSignal?: AbortSignal,\r\n): Promise<string> {\r\n const { query, urls, thinking = true } = args;\r\n\r\n // Build prompt with optional URLs\r\n let prompt = query;\r\n if (urls && urls.length > 0) {\r\n const urlList = urls.join(\"\\n\");\r\n prompt = `${query}\\n\\nURLs to analyze:\\n${urlList}`;\r\n }\r\n\r\n // Build tools array - only grounding tools, no function declarations\r\n const tools: Array<Record<string, unknown>> = [];\r\n tools.push({ googleSearch: {} });\r\n if (urls && urls.length > 0) {\r\n tools.push({ urlContext: {} });\r\n }\r\n\r\n const requestPayload = {\r\n systemInstruction: {\r\n parts: [{ text: SEARCH_SYSTEM_INSTRUCTION }],\r\n },\r\n contents: [\r\n {\r\n role: \"user\",\r\n parts: [{ text: prompt }],\r\n },\r\n ],\r\n tools,\r\n generationConfig: {\r\n temperature: 0,\r\n topP: 1,\r\n },\r\n };\r\n\r\n // Wrap in Antigravity format\r\n const wrappedBody = {\r\n project: projectId,\r\n model: SEARCH_MODEL,\r\n userAgent: \"antigravity\",\r\n requestId: generateRequestId(),\r\n request: {\r\n ...requestPayload,\r\n sessionId: getSessionId(),\r\n },\r\n };\r\n\r\n // Use non-streaming endpoint for search\r\n const url = `${ANTIGRAVITY_ENDPOINT}/v1internal:generateContent`;\r\n\r\n log.debug(\"Executing search\", {\r\n query,\r\n urlCount: urls?.length ?? 0,\r\n thinking,\r\n });\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n ...getAntigravityHeaders(),\r\n Authorization: `Bearer ${accessToken}`,\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify(wrappedBody),\r\n signal: abortSignal ?? AbortSignal.timeout(SEARCH_TIMEOUT_MS),\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text();\r\n log.debug(\"Search API error\", { status: response.status, error: errorText });\r\n return `## Search Error\\n\\nFailed to execute search: ${response.status} ${response.statusText}\\n\\n${errorText}\\n\\nPlease try again with a different query.`;\r\n }\r\n\r\n const data = (await response.json()) as AntigravitySearchResponse;\r\n log.debug(\"Search response received\", { hasResponse: !!data.response });\r\n\r\n const result = parseSearchResponse(data);\r\n const formatted = formatSearchResult(result);\r\n log.debug(\"Search response formatted\", { resultLength: formatted.length });\r\n return formatted;\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n log.debug(\"Search execution error\", { error: message });\r\n return `## Search Error\\n\\nFailed to execute search: ${message}. Please try again with a different query.`;\r\n }\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": ["input", "mkdirSync", "unlinkSync", "join", "homedir", "input", "path", "path", "getConfigDir", "join", "homedir", "mkdirSync", "unlinkSync", "log", "log", "input", "existsSync", "readFileSync", "writeFileSync", "mkdirSync", "join", "dirname", "homedir", "join", "homedir", "existsSync", "readFileSync", "dirname", "mkdirSync", "writeFileSync", "log", "crypto", "existsSync", "mkdirSync", "readFileSync", "writeFileSync", "renameSync", "unlinkSync", "join", "dirname", "homedir", "getConfigDir", "join", "homedir", "existsSync", "readFileSync", "dirname", "mkdirSync", "writeFileSync", "renameSync", "unlinkSync", "z", "existsSync", "readFileSync", "join", "homedir", "log", "getConfigDir", "join", "homedir", "path", "existsSync", "readFileSync", "fs", "debugState", "log", "_", "rest", "isClaudeModel", "sentinel", "log", "tool", "log", "isThinkingPart", "stripAllThinkingBlocks", "tool", "isThinkingCapableModel", "isClaudeModel", "getModelFamily", "existsSync", "mkdirSync", "readdirSync", "readFileSync", "unlinkSync", "writeFileSync", "join", "join", "homedir", "join", "existsSync", "join", "readdirSync", "readFileSync", "join", "existsSync", "mkdirSync", "writeFileSync", "readdirSync", "readFileSync", "unlinkSync", "log", "randomFrom", "log", "crypto", "crypto", "input", "log", "tool", "log", "readFileSync", "existsSync", "existsSync", "readFileSync", "getModelFamily", "next", "fs", "path", "path", "os", "fs", "path", "FETCH_TIMEOUT_MS", "getModelFamily", "fetchWithTimeout", "log", "FETCH_TIMEOUT_MS", "log", "log", "log", "isWSL", "readFileSync", "isWSL2", "isRemoteEnvironment", "input", "createInterface", "baseDelay", "backoffDelay", "input", "log", "maxWaitMs", "waitSecValue", "quotaKey", "existingStorage", "account", "label", "verification", "projectId", "authorization", "fallbackState", "listener"]
7
+ }