@jacobbd/relay-ai 0.9.2 → 0.9.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config.ts","../../src/paths.ts","../../src/constants.ts","../../package.json","../../src/provider-factory.ts","../../src/oauth/refresh-http.ts","../../src/oauth/openai.ts","../../src/oauth/responses-websocket.ts","../../src/oauth/claude-identity.ts","../../src/cline-pass.ts","../../src/registry/io.ts","../../src/registry/types.ts","../../src/registry/migrate.ts","../../src/registry/validate.ts","../../src/core/errors.ts","../../src/core/route-id.ts","../../src/core/catalog.ts","../../src/context-window.ts","../../src/registry/opencode-auth.ts","../../src/oauth/types.ts","../../src/oauth/github.ts","../../src/oauth/xai.ts","../../src/oauth/claude-code.ts","../../src/oauth/antigravity-oauth.ts","../../src/oauth/callback-server.ts","../../src/oauth/cline-pass.ts","../../src/oauth/refresh.ts","../../src/secrets-file.ts","../../src/env.ts","../../src/data/model-incompatible.json","../../src/registry/models-dev.ts","../../src/registry/pricing.ts","../../src/model-compatibility.ts","../../src/registry/import-build.ts","../../src/provider-runtime.ts","../../src/core/antigravity-model.ts","../../src/core/model.ts"],"sourcesContent":["import type { UserPreferences, FavoriteModel } from './types.js';\nimport { dirname, join } from 'node:path';\nimport { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { getAppHome, getConfigPath, getLegacyAppHome, getLegacyConfPath } from './paths.js';\nimport { CODEX_SUBAGENT_MODEL_CAP } from './constants.js';\n\nfunction readJsonFile(path: string): UserPreferences | null {\n try {\n const parsed = JSON.parse(readFileSync(path, 'utf8'));\n return parsed && typeof parsed === 'object' ? parsed as UserPreferences : null;\n } catch {\n return null;\n }\n}\n\nfunction ensureAppHomeMigrated(): void {\n const configPath = getConfigPath();\n if (existsSync(configPath)) return;\n\n const legacyConfig = join(getLegacyAppHome(), 'config.json');\n if (!existsSync(legacyConfig)) return;\n\n mkdirSync(getAppHome(), { recursive: true, mode: 0o700 });\n copyFileSync(legacyConfig, configPath);\n\n const legacyVertex = join(getLegacyAppHome(), 'vertex-models.json');\n const vertexPath = join(getAppHome(), 'vertex-models.json');\n if (existsSync(legacyVertex) && !existsSync(vertexPath)) {\n copyFileSync(legacyVertex, vertexPath);\n }\n}\n\nfunction ensureConfigMigrated(): void {\n ensureAppHomeMigrated();\n\n const configPath = getConfigPath();\n if (existsSync(configPath)) return;\n\n const legacyPath = getLegacyConfPath();\n if (!existsSync(legacyPath)) return;\n\n const legacy = readJsonFile(legacyPath);\n if (!legacy) return;\n\n mkdirSync(dirname(configPath), { recursive: true, mode: 0o700 });\n writeFileSync(configPath, `${JSON.stringify(legacy, null, 2)}\\n`, { encoding: 'utf8', mode: 0o600 });\n\n try {\n renameSync(legacyPath, `${legacyPath}.migrated`);\n } catch {\n // Migration copy is enough; renaming is best-effort.\n }\n}\n\nfunction readConfig(): UserPreferences {\n ensureConfigMigrated();\n return readJsonFile(getConfigPath()) ?? {};\n}\n\nfunction writeConfig(config: UserPreferences): void {\n const configPath = getConfigPath();\n mkdirSync(dirname(configPath), { recursive: true, mode: 0o700 });\n writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, { encoding: 'utf8', mode: 0o600 });\n}\n\nexport function loadPreferences(): UserPreferences {\n const config = readConfig();\n const lastProvider =\n config.lastProvider === 'opencode' ? 'zen' : config.lastProvider;\n return {\n lastBackend: config.lastBackend,\n lastModel: config.lastModel,\n lastProvider,\n lastCodexProvider: config.lastCodexProvider,\n lastCodexModel: config.lastCodexModel,\n lastGeminiProvider: config.lastGeminiProvider,\n lastGeminiModel: config.lastGeminiModel,\n lastAntigravityProvider: config.lastAntigravityProvider,\n lastAntigravityModel: config.lastAntigravityModel,\n lastClaudeTransparentMode: config.lastClaudeTransparentMode,\n recentModelsByProvider: config.recentModelsByProvider,\n favoriteModels: config.favoriteModels,\n codexSubagentModels: Array.isArray(config.codexSubagentModels)\n ? config.codexSubagentModels.slice(0, CODEX_SUBAGENT_MODEL_CAP)\n : undefined,\n antigravityCliFavoriteModels: config.antigravityCliFavoriteModels,\n antigravityCliFavoritesHintShown: config.antigravityCliFavoritesHintShown,\n appPathOverrides: config.appPathOverrides,\n recentLaunchFolders: config.recentLaunchFolders,\n server: config.server,\n };\n}\n\nexport function savePreferences(prefs: Partial<Pick<UserPreferences, 'lastBackend' | 'lastModel' | 'lastProvider' | 'lastCodexProvider' | 'lastCodexModel' | 'lastGeminiProvider' | 'lastGeminiModel' | 'lastAntigravityProvider' | 'lastAntigravityModel' | 'lastClaudeTransparentMode' | 'recentModelsByProvider' | 'favoriteModels' | 'codexSubagentModels' | 'antigravityCliFavoriteModels' | 'antigravityCliFavoritesHintShown' | 'appPathOverrides' | 'recentLaunchFolders'>>): void {\n const config = readConfig();\n if (prefs.lastBackend !== undefined) config.lastBackend = prefs.lastBackend;\n if (prefs.lastModel !== undefined) config.lastModel = prefs.lastModel;\n if (prefs.lastProvider !== undefined) config.lastProvider = prefs.lastProvider;\n if (prefs.lastCodexProvider !== undefined) config.lastCodexProvider = prefs.lastCodexProvider;\n if (prefs.lastCodexModel !== undefined) config.lastCodexModel = prefs.lastCodexModel;\n if (prefs.lastGeminiProvider !== undefined) config.lastGeminiProvider = prefs.lastGeminiProvider;\n if (prefs.lastGeminiModel !== undefined) config.lastGeminiModel = prefs.lastGeminiModel;\n if (prefs.lastAntigravityProvider !== undefined) config.lastAntigravityProvider = prefs.lastAntigravityProvider;\n if (prefs.lastAntigravityModel !== undefined) config.lastAntigravityModel = prefs.lastAntigravityModel;\n if (prefs.lastClaudeTransparentMode !== undefined) config.lastClaudeTransparentMode = prefs.lastClaudeTransparentMode;\n if (prefs.recentModelsByProvider !== undefined) config.recentModelsByProvider = prefs.recentModelsByProvider;\n if (prefs.favoriteModels !== undefined) config.favoriteModels = prefs.favoriteModels;\n if (prefs.codexSubagentModels !== undefined) {\n config.codexSubagentModels = prefs.codexSubagentModels.slice(0, CODEX_SUBAGENT_MODEL_CAP);\n }\n if (prefs.antigravityCliFavoriteModels !== undefined) config.antigravityCliFavoriteModels = prefs.antigravityCliFavoriteModels;\n if (prefs.antigravityCliFavoritesHintShown !== undefined) config.antigravityCliFavoritesHintShown = prefs.antigravityCliFavoritesHintShown;\n if (prefs.appPathOverrides !== undefined) config.appPathOverrides = prefs.appPathOverrides;\n if (prefs.recentLaunchFolders !== undefined) config.recentLaunchFolders = prefs.recentLaunchFolders;\n writeConfig(config);\n}\n\nexport function getAppPathOverride(appId: string): string | undefined {\n const value = loadPreferences().appPathOverrides?.[appId];\n return typeof value === 'string' && value.trim() ? value : undefined;\n}\n\nexport function setAppPathOverride(appId: string, path: string | null): Record<string, string> {\n const config = readConfig();\n const next = { ...(config.appPathOverrides ?? {}) };\n const trimmed = path?.trim() ?? '';\n if (trimmed) next[appId] = trimmed;\n else delete next[appId];\n config.appPathOverrides = next;\n if (Object.keys(next).length === 0) delete config.appPathOverrides;\n writeConfig(config);\n return next;\n}\n\nconst MAX_RECENT_MODELS = 3;\nconst MAX_RECENT_LAUNCH_FOLDERS = 6;\n\nexport function recordLaunchFolder(folder: string): string[] {\n const trimmed = folder.trim();\n if (!trimmed) return loadPreferences().recentLaunchFolders ?? [];\n const config = readConfig();\n const prev = config.recentLaunchFolders ?? [];\n const next = [trimmed, ...prev.filter(path => path !== trimmed)].slice(0, MAX_RECENT_LAUNCH_FOLDERS);\n config.recentLaunchFolders = next;\n writeConfig(config);\n return next;\n}\n\nexport function recordLaunchSelection(\n agent: 'claude' | 'codex' | 'gemini',\n providerId: string,\n modelId: string,\n prefs: UserPreferences,\n): void {\n const prevRecent = prefs.recentModelsByProvider?.[providerId] ?? [];\n const updatedRecent = [modelId, ...prevRecent.filter(id => id !== modelId)].slice(0, MAX_RECENT_MODELS);\n savePreferences({\n ...(agent === 'claude'\n ? { lastProvider: providerId, lastModel: modelId }\n : agent === 'codex'\n ? { lastCodexProvider: providerId, lastCodexModel: modelId }\n : { lastGeminiProvider: providerId, lastGeminiModel: modelId }),\n recentModelsByProvider: { ...prefs.recentModelsByProvider, [providerId]: updatedRecent },\n });\n}\n\nconst SERVER_PASSWORD_SERVICE = 'relay-ai-server-password';\nconst SERVER_PASSWORD_ACCOUNT = 'server-password';\n\nasync function getServerPasswordKeyring(): Promise<any | null> {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n return new Entry(SERVER_PASSWORD_SERVICE, SERVER_PASSWORD_ACCOUNT);\n } catch {\n return null;\n }\n}\n\nexport async function getSavedServerPassword(): Promise<string | null> {\n const config = readConfig();\n if (config.server?.savedPassword) {\n const pwd = config.server.savedPassword;\n const keyring = await getServerPasswordKeyring();\n if (keyring) {\n try {\n await keyring.setPassword(pwd);\n delete config.server.savedPassword;\n if (Object.keys(config.server).length === 0) delete config.server;\n writeConfig(config);\n } catch {\n // Fallback: keep in config.json if keyring fails\n }\n }\n return pwd;\n }\n\n const keyring = await getServerPasswordKeyring();\n if (keyring) {\n try {\n return await keyring.getPassword();\n } catch {\n return null;\n }\n }\n return null;\n}\n\n/** Network gateway password from env (Docker / Compose / quick-start). Never log this. */\nexport function getEnvServerPassword(): string | null {\n const value = process.env['RELAY_AI_SERVER_PASSWORD']?.trim();\n return value || null;\n}\n\n/** Prefer RELAY_AI_SERVER_PASSWORD, then a saved password. */\nexport async function resolveConfiguredServerPassword(): Promise<string | null> {\n return getEnvServerPassword() ?? (await getSavedServerPassword());\n}\n\nexport async function setSavedServerPassword(password: string): Promise<void> {\n const keyring = await getServerPasswordKeyring();\n if (keyring) {\n try {\n await keyring.setPassword(password);\n return;\n } catch {\n // Fallback\n }\n }\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n savedPassword: password,\n };\n writeConfig(config);\n}\n\nexport async function clearSavedServerPassword(): Promise<void> {\n const keyring = await getServerPasswordKeyring();\n if (keyring) {\n try {\n await keyring.deletePassword();\n } catch {\n // Ignore\n }\n }\n const config = readConfig();\n if (!config.server) return;\n delete config.server.savedPassword;\n if (Object.keys(config.server).length === 0) delete config.server;\n writeConfig(config);\n}\n\nexport function getServerExposedProviders(): string[] | null {\n const list = readConfig().server?.exposedProviders;\n return list && list.length > 0 ? list : null;\n}\n\nexport function setServerExposedProviders(providerIds: string[]): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n exposedProviders: providerIds,\n };\n writeConfig(config);\n}\n\nexport function getServerMaskGatewayIds(): boolean {\n return readConfig().server?.maskGatewayIds ?? true;\n}\n\nexport function setServerMaskGatewayIds(mask: boolean): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n maskGatewayIds: mask,\n };\n writeConfig(config);\n}\n\nexport function getServerFavoritesOnly(): boolean {\n return readConfig().server?.favoritesOnly ?? false;\n}\n\nexport function setServerFavoritesOnly(favoritesOnly: boolean): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n favoritesOnly,\n };\n writeConfig(config);\n}\n\nexport function getServerFreeModelsOnly(): boolean {\n return readConfig().server?.freeModelsOnly ?? false;\n}\n\nexport function setServerFreeModelsOnly(freeModelsOnly: boolean): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n freeModelsOnly,\n };\n writeConfig(config);\n}\n\nexport function getServerListenMode(): 'local' | 'network' {\n return readConfig().server?.listenMode === 'network' ? 'network' : 'local';\n}\n\nexport function setServerListenMode(listenMode: 'local' | 'network'): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n listenMode,\n };\n writeConfig(config);\n}\n\nexport function getServerAutostart(): boolean {\n return readConfig().server?.autostart ?? false;\n}\n\nexport function setServerAutostart(autostart: boolean): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n autostart,\n };\n writeConfig(config);\n}\n\n/** Check RELAY_AI_SERVER_AUTOSTART env var first, then config preference. */\nexport function resolveServerAutostart(env: NodeJS.ProcessEnv = process.env): boolean {\n const envVal = env['RELAY_AI_SERVER_AUTOSTART']?.trim().toLowerCase();\n if (envVal !== undefined && envVal !== '') {\n return ['1', 'true', 'yes', 'on'].includes(envVal);\n }\n return getServerAutostart();\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport const APP_DIR_NAME = 'relay-ai';\nexport const LEGACY_APP_DIR_NAME = 'opencode-starter';\n\ninterface HomeEnv {\n APPDATA?: string;\n HOME?: string;\n RELAY_AI_HOME?: string;\n /** @deprecated Use RELAY_AI_HOME */\n OPENCODE_STARTER_HOME?: string;\n USERPROFILE?: string;\n XDG_CONFIG_HOME?: string;\n}\n\nfunction userHome(env: HomeEnv = process.env): string {\n return env.HOME ?? env.USERPROFILE ?? homedir();\n}\n\nexport function resolveAppHomeOverride(env: HomeEnv = process.env): string | undefined {\n const override = env.RELAY_AI_HOME ?? env.OPENCODE_STARTER_HOME;\n return override?.trim() || undefined;\n}\n\nexport function getAppHome(env: HomeEnv = process.env): string {\n const override = resolveAppHomeOverride(env);\n if (override) return override;\n return join(userHome(env), `.${APP_DIR_NAME}`);\n}\n\nexport function getLegacyAppHome(env: HomeEnv = process.env): string {\n return join(userHome(env), `.${LEGACY_APP_DIR_NAME}`);\n}\n\nexport function getConfigPath(env: HomeEnv = process.env): string {\n return join(getAppHome(env), 'config.json');\n}\n\nexport function getProvidersPath(env: HomeEnv = process.env): string {\n return join(getAppHome(env), 'providers.json');\n}\n\nexport function getSecretsPath(env: HomeEnv = process.env): string {\n return join(getAppHome(env), 'secrets.json');\n}\n\nexport function getLogsPath(env: HomeEnv = process.env): string {\n return join(getAppHome(env), 'logs');\n}\n\nexport function getVertexModelsPath(env: HomeEnv = process.env): string {\n return join(getAppHome(env), 'vertex-models.json');\n}\n\nexport function getLegacyConfPath(env: HomeEnv = process.env, platform = process.platform): string {\n const home = userHome(env);\n const appName = `${LEGACY_APP_DIR_NAME}-nodejs`;\n\n if (platform === 'darwin') {\n return join(home, 'Library', 'Preferences', appName, 'config.json');\n }\n\n if (platform === 'win32') {\n return join(env.APPDATA ?? join(home, 'AppData', 'Roaming'), appName, 'Config', 'config.json');\n }\n\n return join(env.XDG_CONFIG_HOME ?? join(home, '.config'), appName, 'config.json');\n}\n","// src/constants.ts\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport pkg from '../package.json' with { type: 'json' };\nimport type { BackendConfig, ModelFormat } from './types.js';\n\nexport const BACKENDS: Record<'zen' | 'go', BackendConfig> = {\n zen: {\n id: 'zen',\n name: 'OpenCode Zen',\n // No /v1 suffix — the Anthropic SDK appends /v1/messages automatically\n baseUrl: 'https://opencode.ai/zen',\n },\n go: {\n id: 'go',\n name: 'OpenCode Go',\n baseUrl: 'https://opencode.ai/zen/go',\n },\n};\n\n// ChatGPT Codex Responses-Lite WebSocket transport (used by models the backend\n// flags with prefer_websockets, e.g. gpt-5.6-luna).\nexport const CODEX_RESPONSES_LITE_WS_URL = 'wss://chatgpt.com/backend-api/codex/responses';\n// `version` header the Codex backend expects on Responses-Lite requests. The\n// official Codex CLI sends its own version here; OpenAI may require this to be\n// bumped over time — confirm via --trace if Luna requests start failing.\nexport const CODEX_RESPONSES_LITE_VERSION = '0.144.1';\n// OpenAI-Beta opt-in for the WebSocket Responses transport.\nexport const CODEX_RESPONSES_WEBSOCKETS_BETA = 'responses_websockets=2026-02-06';\n\n// These must be removed from the child process environment to avoid conflicts\n// with Vertex AI, Bedrock, AWS, Foundry, and any stale Anthropic config.\nexport const CONFLICTING_ENV_VARS = [\n 'CLAUDE_CODE_USE_VERTEX',\n 'ANTHROPIC_VERTEX_PROJECT_ID',\n 'ANTHROPIC_VERTEX_BASE_URL',\n 'CLOUD_ML_REGION',\n 'ANTHROPIC_BEDROCK_BASE_URL',\n 'ANTHROPIC_AWS_BASE_URL',\n 'ANTHROPIC_AWS_API_KEY',\n 'ANTHROPIC_AWS_WORKSPACE_ID',\n 'ANTHROPIC_FOUNDRY_API_KEY',\n 'ANTHROPIC_FOUNDRY_BASE_URL',\n 'ANTHROPIC_AUTH_TOKEN',\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_BASE_URL',\n 'ANTHROPIC_MODEL',\n 'ANTHROPIC_DEFAULT_OPUS_MODEL',\n 'ANTHROPIC_DEFAULT_SONNET_MODEL',\n 'ANTHROPIC_DEFAULT_HAIKU_MODEL',\n] as const;\n\nexport type ConflictingEnvVar = (typeof CONFLICTING_ENV_VARS)[number];\n\n// When relay-ai launches Claude Code from inside an existing Claude Code\n// session (its own terminal, a Code tab, an agent's shell), these identity\n// vars leak into the spawned child via process.env inheritance. The new\n// process then misidentifies itself as a nested child of the outer session\n// (e.g. CLAUDE_CODE_CHILD_SESSION disables transcript saving) even though\n// it's meant to be a fresh top-level launch. Strip before spawning.\nexport const PARENT_SESSION_ENV_VARS = [\n 'CLAUDECODE',\n 'CLAUDE_CODE_CHILD_SESSION',\n 'CLAUDE_CODE_SESSION_ID',\n 'CLAUDE_CODE_HOST_SESSION_ID',\n 'CLAUDE_CODE_ENTRYPOINT',\n 'CLAUDE_PID',\n] as const;\n\n// Optional enrichment from OpenCode CLI (~/.cache/opencode/models.json) — not a runtime dependency.\nexport const OPENCODE_CACHE_PATH = join(homedir(), '.cache', 'opencode', 'models.json');\n\n/** Max models in favorites list and mid-session /model switch catalog. */\nexport const MAX_MODEL_CATALOG = 20;\n\n/** Codex redirects every marked child session to this one explicit Relay model. */\nexport const CODEX_SUBAGENT_MODEL_CAP = 1;\n\n/**\n * Smallest context window worth offering: agent system prompts plus tool definitions\n * consume ~25K before the first user message, so smaller models fail immediately.\n * Antigravity enforces its own, higher floor (see `ANTIGRAVITY_MIN_CONTEXT_WINDOW`).\n */\nexport const MIN_CONTEXT_WINDOW = 128000;\n\n/** Vercel AI SDK package for Anthropic Claude models on Google Vertex AI (ADC auth). */\nexport const VERTEX_ANTHROPIC_NPM = '@ai-sdk/google-vertex/anthropic';\n\n// Classify a model's API format based on cache provider data or ID heuristics.\n// Used to decide whether to route directly or through the translation proxy.\nexport function classifyModelFormat(\n modelId: string,\n providerNpm: string | undefined,\n): ModelFormat {\n if (providerNpm === '@ai-sdk/anthropic') return 'anthropic';\n if (providerNpm === '@ai-sdk/openai') return 'unsupported';\n if (providerNpm === '@ai-sdk/google') return 'unsupported';\n\n // Fallback: ID-prefix heuristics for models not in cache\n const lower = modelId.toLowerCase();\n if (lower.startsWith('claude-')) return 'anthropic';\n if (lower.startsWith('gpt-')) return 'unsupported';\n if (lower.startsWith('gemini-')) return 'unsupported';\n\n return 'openai';\n}\n\nexport const VERSION = pkg.version;\n","{\n \"name\": \"@jacobbd/relay-ai\",\n \"version\": \"0.9.2\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"description\": \"Relay any model into any coding agent — launch Claude Code, Codex, and more with multi-provider gateways\",\n \"author\": \"jacob-bd\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jacob-bd/relay-ai.git\"\n },\n \"homepage\": \"https://github.com/jacob-bd/relay-ai#readme\",\n \"keywords\": [\n \"claude\",\n \"claude-code\",\n \"codex\",\n \"ai\",\n \"llm\",\n \"cli\",\n \"gateway\",\n \"relay\",\n \"vertex\"\n ],\n \"type\": \"module\",\n \"bin\": {\n \"relay-ai\": \"dist/cli.js\"\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"engines\": {\n \"node\": \">=18\"\n },\n \"scripts\": {\n \"build\": \"tsup && tsup --config tsup.core.config.ts && node scripts/copy-ui-assets.mjs\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run --exclude \\\"tests/debug-*.test.ts\\\"\",\n \"test:live\": \"vitest run tests/debug-xai.test.ts tests/debug-openai-oauth.test.ts\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\",\n \"release:check\": \"node scripts/release-metadata.mjs\",\n \"refresh:models-dev\": \"node scripts/refresh-models-dev-cache.mjs\",\n \"prepublishOnly\": \"npm run release:check && npm run build\"\n },\n \"dependencies\": {\n \"@ai-sdk/alibaba\": \"^1.0.26\",\n \"@ai-sdk/amazon-bedrock\": \"^4.0.113\",\n \"@ai-sdk/azure\": \"^3.0.70\",\n \"@ai-sdk/cerebras\": \"^2.0.54\",\n \"@ai-sdk/cohere\": \"^3.0.36\",\n \"@ai-sdk/deepinfra\": \"^2.0.52\",\n \"@ai-sdk/gateway\": \"^3.0.125\",\n \"@ai-sdk/google\": \"^3.0.80\",\n \"@ai-sdk/google-vertex\": \"^4.0.142\",\n \"@ai-sdk/groq\": \"^3.0.39\",\n \"@ai-sdk/mistral\": \"^3.0.37\",\n \"@ai-sdk/openai\": \"^3.0.68\",\n \"@ai-sdk/openai-compatible\": \"^2.0.48\",\n \"@ai-sdk/perplexity\": \"^3.0.33\",\n \"@ai-sdk/togetherai\": \"^2.0.53\",\n \"@ai-sdk/vercel\": \"^2.0.50\",\n \"@ai-sdk/xai\": \"^3.0.93\",\n \"@clack/prompts\": \"^0.9.1\",\n \"@openrouter/ai-sdk-provider\": \"^2.9.0\",\n \"ai\": \"^6.0.197\",\n \"cross-spawn\": \"^7.0.6\",\n \"gitlab-ai-provider\": \"^6.8.0\",\n \"graphql\": \"^16.14.2\",\n \"ipaddr.js\": \"^2.4.0\",\n \"node-forge\": \"^1.4.0\",\n \"open\": \"^11.0.0\",\n \"picocolors\": \"^1.1.1\",\n \"smol-toml\": \"^1.6.1\",\n \"venice-ai-sdk-provider\": \"^2.0.2\",\n \"ws\": \"^8.21.0\",\n \"zod\": \"^3.25.76\"\n },\n \"devDependencies\": {\n \"@types/cross-spawn\": \"^6.0.6\",\n \"@types/node\": \"^22.0.0\",\n \"@types/node-forge\": \"^1.3.14\",\n \"@types/ws\": \"^8.18.1\",\n \"@vitest/coverage-v8\": \"^4.1.10\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.5.0\",\n \"vite-node\": \"^6.0.0\",\n \"vitest\": \"^4.1.10\"\n },\n \"optionalDependencies\": {\n \"@napi-rs/keyring\": \"^1.3.0\"\n },\n \"overrides\": {\n \"ws\": \"^8.21.0\"\n },\n \"exports\": {\n \"./core\": {\n \"types\": \"./dist/core/index.d.ts\",\n \"import\": \"./dist/core/index.js\",\n \"default\": \"./dist/core/index.js\"\n },\n \"./package.json\": \"./package.json\"\n }\n}\n","// Maps an OpenCode provider's `npm` package (the field providers.ts already\n// reads) to a Vercel AI SDK LanguageModel instance. The SDK owns wire format,\n// endpoint selection, and provider quirks.\nimport type { LanguageModel } from 'ai';\nimport { wrapLanguageModel, extractReasoningMiddleware } from 'ai';\nimport { VERTEX_ANTHROPIC_NPM, CODEX_RESPONSES_LITE_VERSION, CODEX_RESPONSES_LITE_WS_URL } from './constants.js';\nimport { extractOpenAiAccountId } from './oauth/openai.js';\nimport { createResponsesWebSocketFetch } from './oauth/responses-websocket.js';\nimport {\n CLAUDE_CODE_USER_AGENT,\n injectClaudeIdentity,\n} from './oauth/claude-identity.js';\nimport {\n createClinePassOAuthFetch,\n formatClineRuntimeCredential,\n isClinePassOAuth,\n} from './cline-pass.js';\n\n/** Models that must use /v1/responses instead of /v1/chat/completions. */\nconst RESPONSES_ONLY_PREFIXES = [\n 'gpt-5-codex',\n 'gpt-5-pro',\n 'gpt-5.2-pro',\n 'o3',\n 'o4',\n];\n\ntype SdkProviderFactory = (options: {\n apiKey: string;\n baseURL?: string;\n name?: string;\n headers?: Record<string, string>;\n fetch?: typeof globalThis.fetch;\n}) => {\n (modelId: string): LanguageModel;\n chat: (modelId: string) => LanguageModel;\n responses: (modelId: string) => LanguageModel;\n};\n\nconst factoryCache = new Map<string, Promise<SdkProviderFactory>>();\n\n/**\n * True when a model id must use the OpenAI/xAI Responses API instead of\n * chat/completions. The SDK reflects this by selecting `provider.responses(id)`.\n */\nexport function modelPrefersResponsesApi(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n if (RESPONSES_ONLY_PREFIXES.some(prefix => lower === prefix || lower.startsWith(`${prefix}-`))) {\n return true;\n }\n // gpt-5.4 and later minor versions require the Responses API (e.g. gpt-5.4, gpt-5.5, gpt-5.6, gpt-5.6-fast).\n const gpt5Minor = lower.match(/^gpt-5\\.(\\d+)(?:-|$)/);\n if (gpt5Minor && Number(gpt5Minor[1]) >= 4) return true;\n // Versioned Codex IDs (e.g. gpt-5.3-codex) don't match the gpt-5-codex prefix.\n if (lower.startsWith('gpt-') && lower.includes('-codex')) return true;\n // xAI multiagent models (e.g. grok-4.20-multi-agent, grok-4.2-multiagent).\n if (lower.startsWith('grok-') && (lower.includes('multi-agent') || lower.includes('multiagent'))) return true;\n return false;\n}\n\n/**\n * OpenAI's Responses API is a strict superset of Chat Completions for every\n * current model — there is no OpenAI model that Chat Completions can serve\n * that Responses cannot. So route every OpenAI model through Responses by\n * default, except pre-chat legacy completion models that predate both APIs\n * and are not agentic chat models at all.\n */\nconst OPENAI_CHAT_COMPLETIONS_ONLY = [\n 'davinci-002',\n 'babbage-002',\n 'gpt-3.5-turbo-instruct',\n];\n\nexport function shouldUseOpenAiResponsesEndpoint(modelId: string): boolean {\n return !OPENAI_CHAT_COMPLETIONS_ONLY.includes(modelId.toLowerCase());\n}\n\nexport interface VertexProviderConfig {\n project: string;\n location: string;\n}\n\nexport interface ProviderModelSpec {\n /** OpenCode `api.npm` package, e.g. `@ai-sdk/xai`. */\n npm: string;\n modelId: string;\n apiKey: string;\n /** Base URL for openai-compatible / openrouter providers (no trailing path). */\n baseURL?: string;\n /** Provider id for naming openai-compatible instances (diagnostics only). */\n providerId?: string;\n /** Registry authentication mode. OpenAI OAuth uses the ChatGPT Codex backend. */\n authType?: 'api' | 'oauth' | 'none';\n oauthAccountId?: string;\n providerData?: Record<string, unknown>;\n /** Google Vertex AI — uses Application Default Credentials, not apiKey. */\n vertex?: VertexProviderConfig;\n /** Static headers sent on every upstream request (e.g. a plan/auth-tracking header a custom endpoint requires). */\n headers?: Record<string, string>;\n /** Refresh an OAuth access token after the SDK receives one 401 response. */\n refreshToken?: () => Promise<string | null>;\n /** Persist a newly refreshed raw token for future requests. */\n onTokenRefreshed?: (token: string) => void;\n /** Backend capability: model requires the Responses-Lite request shape (x-openai-internal-codex-responses-lite). */\n useResponsesLite?: boolean;\n /** Backend capability: model must use the WebSocket Responses transport instead of HTTP. */\n preferWebSockets?: boolean;\n /** Optional debug logger (wired to the proxy trace log) for transport-level diagnostics. */\n onDebug?: (msg: string) => void;\n}\n\n/** True when this provider routes through the SDK adapter (local providers + Zen/Go openai-format). */\nexport function isSdkMigratedNpm(npm: string | undefined): boolean {\n return !!npm && npm !== '@ai-sdk/anthropic';\n}\n\nexport function maxToolsForNpm(npm: string | undefined): number | undefined {\n return npm === '@ai-sdk/groq' ? 128 : undefined;\n}\n\nfunction findCreateFactory(mod: Record<string, unknown>): SdkProviderFactory {\n for (const value of Object.values(mod)) {\n if (typeof value === 'function' && value.name.startsWith('create')) {\n return value as SdkProviderFactory;\n }\n }\n throw new Error('No create* factory export found in provider package');\n}\n\nasync function loadSdkProviderFactory(npm: string): Promise<SdkProviderFactory> {\n let cached = factoryCache.get(npm);\n if (!cached) {\n cached = (async () => {\n try {\n const mod = await import(npm);\n return findCreateFactory(mod as Record<string, unknown>);\n } catch (err) {\n const code = err && typeof err === 'object' && 'code' in err ? err.code : undefined;\n if (code === 'ERR_MODULE_NOT_FOUND') {\n throw new Error(`SDK provider package not installed: ${npm}. Run: npm install ${npm}`);\n }\n throw err;\n }\n })();\n factoryCache.set(npm, cached);\n cached.catch(() => factoryCache.delete(npm));\n }\n return cached;\n}\n\nexport async function createLanguageModel(spec: ProviderModelSpec): Promise<LanguageModel> {\n const { npm, modelId, apiKey, baseURL } = spec;\n\n if (npm === VERTEX_ANTHROPIC_NPM) {\n if (!spec.vertex?.project) {\n throw new Error('Vertex project is required for @ai-sdk/google-vertex/anthropic');\n }\n const { createVertexAnthropic } = await import('@ai-sdk/google-vertex/anthropic');\n const vertex = createVertexAnthropic({\n project: spec.vertex.project,\n location: spec.vertex.location,\n });\n return vertex(modelId);\n }\n\n if (npm === '@ai-sdk/openai') {\n const { createOpenAI } = await import('@ai-sdk/openai');\n const accountId = spec.authType === 'oauth'\n ? spec.oauthAccountId ?? extractOpenAiAccountId({ access_token: apiKey })\n : undefined;\n const oauthOptions = spec.authType === 'oauth'\n ? {\n apiKey,\n baseURL: 'https://chatgpt.com/backend-api/codex',\n headers: {\n ...(accountId ? { 'ChatGPT-Account-Id': accountId } : {}),\n originator: 'relay-ai',\n // Responses-Lite models (backend prefer_websockets/use_responses_lite,\n // e.g. gpt-5.6-luna) require these on the request.\n ...(spec.useResponsesLite\n ? { version: CODEX_RESPONSES_LITE_VERSION, 'x-openai-internal-codex-responses-lite': 'true' }\n : {}),\n },\n // Models the backend flags with prefer_websockets are only served over\n // the WebSocket Responses transport, not HTTP.\n ...(spec.preferWebSockets\n ? { fetch: createResponsesWebSocketFetch(CODEX_RESPONSES_LITE_WS_URL, spec.onDebug) }\n : {}),\n }\n : { apiKey };\n const openai = createOpenAI(oauthOptions);\n return shouldUseOpenAiResponsesEndpoint(modelId) ? openai.responses(modelId) : openai.chat(modelId);\n }\n if (npm === '@ai-sdk/xai') {\n const { createXai } = await import('@ai-sdk/xai');\n const xai = createXai({ apiKey });\n return modelPrefersResponsesApi(modelId) ? xai.responses(modelId) : xai(modelId);\n }\n // @ai-sdk/google owns its native v1beta endpoint. Registry templates store the\n // OpenAI-compatible URL only for GET /v1/models discovery — passing it here\n // produces .../v1beta/openai/models/...:streamGenerateContent → 404.\n if (npm === '@ai-sdk/google') {\n const { createGoogleGenerativeAI } = await import('@ai-sdk/google');\n const google = createGoogleGenerativeAI({ apiKey });\n return google(modelId);\n }\n // Registry stores root URL (no /v1) for GET /v1/models discovery — passing it here\n // makes the SDK call https://api.anthropic.com/messages → 404.\n if (npm === '@ai-sdk/anthropic') {\n const { createAnthropic } = await import('@ai-sdk/anthropic');\n const root = baseURL?.replace(/\\/v1\\/?$/, '').replace(/\\/$/, '');\n const anthropicOptions: Parameters<typeof createAnthropic>[0] = spec.authType === 'oauth'\n ? {\n authToken: apiKey,\n ...(spec.providerId === 'claude-code'\n ? {\n headers: {\n 'User-Agent': CLAUDE_CODE_USER_AGENT,\n 'x-app': 'cli',\n 'X-Claude-Code-Session-Id': injectClaudeIdentity(\n {},\n spec.providerData,\n spec.oauthAccountId ?? apiKey,\n ).sessionId,\n },\n }\n : {}),\n }\n : { apiKey };\n if (spec.headers) {\n anthropicOptions.headers = { ...anthropicOptions.headers, ...spec.headers };\n }\n if (!root || root === 'https://api.anthropic.com') {\n return createAnthropic(anthropicOptions)(modelId);\n }\n const sdkBase = baseURL!.endsWith('/v1') ? baseURL : `${root}/v1`;\n return createAnthropic({ ...anthropicOptions, baseURL: sdkBase })(modelId);\n }\n let model: LanguageModel;\n\n if (npm === '@ai-sdk/openai-compatible') {\n const { createOpenAICompatible } = await import('@ai-sdk/openai-compatible');\n const runtimeApiKey = formatClineRuntimeCredential(spec.providerId, spec.authType, apiKey);\n const options = {\n name: spec.providerId ?? 'openai-compatible',\n baseURL: baseURL ?? '',\n ...(runtimeApiKey.trim() ? { apiKey: runtimeApiKey } : {}),\n ...(spec.headers ? { headers: spec.headers } : {}),\n ...(isClinePassOAuth(spec.providerId, spec.authType) && spec.refreshToken\n ? {\n fetch: createClinePassOAuthFetch(\n runtimeApiKey,\n spec.refreshToken,\n spec.onTokenRefreshed,\n ),\n }\n : {}),\n };\n model = createOpenAICompatible({\n ...options,\n })(modelId);\n } else if (npm === '@openrouter/ai-sdk-provider') {\n const { createOpenRouter } = await import('@openrouter/ai-sdk-provider');\n model = createOpenRouter({ apiKey, baseURL, ...(spec.headers ? { headers: spec.headers } : {}) })(modelId);\n } else {\n const create = await loadSdkProviderFactory(npm);\n const provider = create({\n apiKey,\n ...(baseURL ? { baseURL } : {}),\n ...(spec.headers ? { headers: spec.headers } : {}),\n });\n model = provider(modelId);\n }\n\n const isReasoning = modelId.toLowerCase().match(/deepseek-r1|think|reasoning|qwq/);\n if (isReasoning) {\n return wrapLanguageModel({\n model: model as Parameters<typeof wrapLanguageModel>[0]['model'],\n middleware: [extractReasoningMiddleware({ tagName: 'think' })],\n }) as unknown as LanguageModel;\n }\n\n return model;\n}\n\nexport type ReasoningMode = 'none' | 'internal-only' | 'controllable';\nexport type ReasoningSource = 'provider-metadata' | 'provider-rule' | 'model-metadata' | 'none';\nexport type ReasoningConfidence = 'verified' | 'documented' | 'inferred';\nexport type ReasoningWireFormat =\n | { kind: 'openrouter-reasoning' }\n | { kind: 'openai-reasoning-effort' }\n | { kind: 'anthropic-thinking' }\n | { kind: 'google-thinking-config' }\n | { kind: 'mistral-reasoning-effort' }\n | { kind: 'deepseek-thinking' };\n\nexport interface ReasoningMetadata {\n providerId?: string;\n apiBaseUrl?: string;\n supportedParameters?: string[];\n reasoning?: boolean;\n interleavedReasoningField?: string;\n /**\n * Bare upstream model id (e.g. 'grok-4.5'), distinct from the request's `model`\n * field which may be a gateway alias or catalog slug (e.g. 'xai-oauth__grok-4.5').\n * Reasoning-capability id-pattern checks must match against this, not body.model.\n */\n upstreamModelId?: string;\n}\n\nexport interface ReasoningCapabilities {\n levels: string[];\n defaultLevel: string;\n supportsSummaries: boolean;\n mode: ReasoningMode;\n source: ReasoningSource;\n confidence: ReasoningConfidence;\n wireFormat?: ReasoningWireFormat;\n}\n\nconst ANTHROPIC_EFFORT_LEVELS = ['low', 'medium', 'high'] as const;\nconst OPENAI_EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh'] as const;\nconst GEMINI_EFFORT_LEVELS = ['low', 'medium', 'high'] as const;\nconst MISTRAL_EFFORT_LEVELS = ['high', 'off'] as const;\nconst XAI_EFFORT_LEVELS = ['none', 'low', 'medium', 'high'] as const;\nconst OPENROUTER_EFFORT_LEVELS = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh'] as const;\n/** DeepSeek V4 wire values (low/medium map to high; xhigh maps to max). */\nconst DEEPSEEK_EFFORT_LEVELS = ['high', 'max', 'off'] as const;\n/** GLM-5.2 published efforts (OpenRouter metadata): high and xhigh, default high. */\nconst GLM_52_EFFORT_LEVELS = ['high', 'xhigh'] as const;\n\nconst EMPTY_REASONING: ReasoningCapabilities = {\n levels: [],\n defaultLevel: '',\n supportsSummaries: false,\n mode: 'none',\n source: 'none',\n confidence: 'inferred',\n};\n\nconst EFFORT_DESCRIPTIONS: Record<string, string> = {\n off: 'Turn off extended reasoning',\n none: 'No reasoning',\n minimal: 'Minimal reasoning',\n low: 'Light reasoning',\n medium: 'Balanced reasoning',\n high: 'Deep reasoning',\n xhigh: 'Maximum reasoning',\n max: 'Maximum effort',\n};\n\nconst GEMINI_25_BUDGETS: Record<string, number> = {\n low: 1024,\n medium: 4096,\n high: 8192,\n xhigh: 16384,\n max: 16384,\n minimal: 512,\n none: 0,\n};\n\n/** Claude adaptive-thinking models (opus/sonnet/haiku 4.6+, fable, mythos). */\nfunction isClaudeReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n if (!lower.startsWith('claude-')) return false;\n if (lower.includes('fable') || lower.includes('mythos')) return true;\n const m = lower.match(/claude-(?:opus|sonnet|haiku)-(\\d+)-(\\d+)/);\n if (!m) return false;\n const major = Number(m[1]);\n const minor = Number(m[2]);\n return major > 4 || (major === 4 && minor >= 6);\n}\n\nfunction isGeminiReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower.startsWith('gemini-2.5-')\n || lower.startsWith('gemini-3')\n || lower.startsWith('gemini-3.');\n}\n\nfunction isGemini3Model(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower.startsWith('gemini-3') || lower.startsWith('gemini-3.');\n}\n\nfunction isMistralReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower.startsWith('mistral-')\n || lower.startsWith('magistral-')\n || lower.startsWith('ministral-')\n || lower.includes('reasoning');\n}\n\n/**\n * xAI models that accept `reasoning_effort` on the wire (per xAI docs).\n * models.dev `reasoning: true` is broader — e.g. grok-build-0.1 reasons internally\n * but rejects reasoningEffort (HTTP 400).\n */\nfunction isXaiReasoningEffortModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n if (lower.includes('non-reasoning')) return false;\n if (lower.startsWith('grok-build')) return false;\n if (lower.startsWith('grok-imagine')) return false;\n if (modelPrefersResponsesApi(modelId)) return true;\n if (lower === 'grok-4.3' || lower.startsWith('grok-4.3-')) return true;\n if (lower === 'grok-4.5' || lower.startsWith('grok-4.5-')) return true;\n if (lower.includes('-reasoning')) return true;\n return false;\n}\n\n/**\n * xAI's own default reasoning_effort when the param is omitted (per xAI docs).\n * Varies by model — grok-4.3 defaults to 'low', grok-4.5 defaults to 'high'.\n */\nfunction xaiDefaultReasoningEffort(modelId: string): string {\n const lower = modelId.toLowerCase();\n if (lower === 'grok-4.5' || lower.startsWith('grok-4.5-')) return 'high';\n return 'low';\n}\n\n/** DeepSeek V4 models with thinking mode + reasoning_effort (direct API). */\nfunction isDeepSeekReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower === 'deepseek-v4-flash'\n || lower === 'deepseek-v4-pro'\n || lower.startsWith('deepseek-v4-flash-')\n || lower.startsWith('deepseek-v4-pro-')\n || lower === 'deepseek-reasoner'\n || lower === 'deepseek-chat';\n}\n\nfunction isKimiReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower.startsWith('kimi-');\n}\n\n// Keep exact matching. Kimi uses prefix matching, but switching GLM to prefix\n// would newly classify vendor-aliased IDs as reasoning models. That is a\n// behavior change, not duplication cleanup.\nfunction isGlm52ReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower === 'glm-5.2'\n || lower === 'z-ai/glm-5.2'\n || lower === 'zai/glm-5.2'\n || lower === 'zai-org/glm-5.2'\n || lower === 'zai-org/glm5.2'\n || lower === 'glm5.2';\n}\n\nfunction toCamelCase(str: string): string {\n return str.replace(/[-_]([a-z])/g, (_, g) => g.toUpperCase());\n}\n\nfunction hasSupportedParameter(metadata: ReasoningMetadata | undefined, param: string): boolean {\n return (metadata?.supportedParameters ?? []).some(p => p === param);\n}\n\nfunction isOpenRouterRoute(npm: string, metadata?: ReasoningMetadata): boolean {\n return npm === '@openrouter/ai-sdk-provider'\n || metadata?.providerId === 'openrouter'\n || metadata?.apiBaseUrl?.includes('openrouter.ai') === true;\n}\n\nfunction openRouterReasoningCapabilities(metadata?: ReasoningMetadata): ReasoningCapabilities {\n if (metadata?.supportedParameters && !hasSupportedParameter(metadata, 'reasoning')) {\n return {\n ...EMPTY_REASONING,\n source: 'provider-metadata',\n confidence: 'documented',\n };\n }\n if (hasSupportedParameter(metadata, 'reasoning')) {\n return {\n levels: [...OPENROUTER_EFFORT_LEVELS],\n defaultLevel: 'medium',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-metadata',\n confidence: 'documented',\n wireFormat: { kind: 'openrouter-reasoning' },\n };\n }\n if (metadata?.reasoning) {\n return {\n ...EMPTY_REASONING,\n mode: 'internal-only',\n source: 'model-metadata',\n confidence: 'inferred',\n };\n }\n return EMPTY_REASONING;\n}\n\nfunction mapCodexEffortToDeepSeek(effort: string): 'high' | 'max' | 'off' | undefined {\n switch (effort) {\n case 'off':\n case 'none':\n return 'off';\n case 'low':\n case 'medium':\n case 'high':\n return 'high';\n case 'xhigh':\n case 'max':\n return 'max';\n default:\n if (effort === 'high' || effort === 'max') return effort;\n return undefined;\n }\n}\n\n/** DeepSeek thinking toggle spreads via provider id keys on @ai-sdk/openai-compatible. */\nfunction deepSeekEffortProviderOptions(\n effort: string,\n): Record<string, Record<string, unknown>> | undefined {\n const mapped = mapCodexEffortToDeepSeek(effort);\n if (!mapped) return undefined;\n const thinking = { type: mapped === 'off' ? 'disabled' : 'enabled' };\n const spread = { thinking };\n if (mapped === 'off') {\n return {\n deepseek: spread,\n openaiCompatible: spread,\n };\n }\n return {\n openaiCompatible: { reasoningEffort: mapped, ...spread },\n deepseek: spread,\n };\n}\n\nfunction mapCodexEffortToAnthropic(effort: string): string | undefined {\n switch (effort) {\n case 'none':\n case 'minimal':\n case 'low':\n return 'low';\n case 'medium':\n return 'medium';\n case 'high':\n case 'xhigh':\n case 'max':\n return effort === 'xhigh' ? 'high' : effort === 'max' ? 'max' : 'high';\n default:\n if (ANTHROPIC_EFFORT_LEVELS.includes(effort as typeof ANTHROPIC_EFFORT_LEVELS[number])) {\n return effort;\n }\n return undefined;\n }\n}\n\nfunction mapCodexEffortToOpenAI(effort: string): string | undefined {\n if (effort === 'xhigh') return 'high';\n const allowed = ['low', 'medium', 'high'];\n return allowed.includes(effort) ? effort : undefined;\n}\n\nfunction mapCodexEffortToGlm52(effort: string): 'high' | 'max' | undefined {\n switch (effort) {\n case 'high':\n return 'high';\n case 'xhigh':\n case 'max':\n return 'max';\n default:\n return undefined;\n }\n}\n\nfunction mapCodexEffortToXai(effort: string): string | undefined {\n switch (effort) {\n case 'none':\n case 'minimal':\n return undefined; // xAI SDK only accepts 'low'|'high'; omit param for 'none'\n case 'low':\n case 'medium':\n return 'low'; // 'medium' has no xAI equivalent — nearest valid value\n case 'high':\n case 'xhigh':\n case 'max':\n return 'high';\n default:\n return undefined;\n }\n}\n\nfunction mapCodexEffortToGeminiLevel(effort: string): 'low' | 'medium' | 'high' | undefined {\n switch (effort) {\n case 'none':\n case 'minimal':\n case 'low':\n return 'low';\n case 'medium':\n return 'medium';\n case 'high':\n case 'xhigh':\n case 'max':\n return 'high';\n default:\n return GEMINI_EFFORT_LEVELS.includes(effort as typeof GEMINI_EFFORT_LEVELS[number])\n ? effort as 'low' | 'medium' | 'high'\n : undefined;\n }\n}\n\nfunction mapCodexEffortToGeminiBudget(effort: string): number | undefined {\n const direct = GEMINI_25_BUDGETS[effort];\n if (direct !== undefined) return direct > 0 ? direct : undefined;\n const level = mapCodexEffortToGeminiLevel(effort);\n if (!level) return undefined;\n return GEMINI_25_BUDGETS[level];\n}\n\n/** Per-model reasoning UI + wire metadata for Codex catalog and adapters. */\nexport function getReasoningCapabilities(\n npm: string,\n modelId: string,\n metadata?: ReasoningMetadata,\n): ReasoningCapabilities {\n const id = modelId.toLowerCase();\n\n if (isOpenRouterRoute(npm, metadata)) {\n return openRouterReasoningCapabilities(metadata);\n }\n\n if (npm === '@ai-sdk/anthropic' || id.startsWith('claude-')) {\n const isClaude = isClaudeReasoningModel(modelId);\n if (isClaude || metadata?.reasoning) {\n return {\n levels: [...ANTHROPIC_EFFORT_LEVELS],\n defaultLevel: 'high',\n supportsSummaries: true,\n mode: 'controllable',\n source: isClaude ? 'provider-rule' : 'model-metadata',\n confidence: isClaude ? 'documented' : 'inferred',\n wireFormat: { kind: 'anthropic-thinking' },\n };\n }\n return EMPTY_REASONING;\n }\n\n if (npm === '@ai-sdk/openai' || npm === '@ai-sdk/azure') {\n const prefersResponses = modelPrefersResponsesApi(modelId);\n if (prefersResponses || metadata?.reasoning) {\n return {\n levels: [...OPENAI_EFFORT_LEVELS],\n defaultLevel: 'medium',\n supportsSummaries: true,\n mode: 'controllable',\n source: prefersResponses ? 'provider-rule' : 'model-metadata',\n confidence: prefersResponses ? 'documented' : 'inferred',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n return EMPTY_REASONING;\n }\n\n if (npm === '@ai-sdk/google' || id.startsWith('gemini-')) {\n if (isGeminiReasoningModel(modelId)) {\n return {\n levels: [...GEMINI_EFFORT_LEVELS],\n defaultLevel: 'medium',\n supportsSummaries: true,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'google-thinking-config' },\n };\n }\n return EMPTY_REASONING;\n }\n\n if (npm === '@ai-sdk/mistral') {\n if (isMistralReasoningModel(modelId)) {\n return {\n levels: [...MISTRAL_EFFORT_LEVELS],\n defaultLevel: 'high',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'mistral-reasoning-effort' },\n };\n }\n return EMPTY_REASONING;\n }\n\n if (npm === '@ai-sdk/xai') {\n if (isXaiReasoningEffortModel(modelId)) {\n const levels = modelPrefersResponsesApi(modelId)\n ? ['low', 'medium', 'high', 'xhigh']\n : [...XAI_EFFORT_LEVELS];\n return {\n levels,\n defaultLevel: xaiDefaultReasoningEffort(modelId),\n supportsSummaries: true,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n return EMPTY_REASONING;\n }\n\n if (isDeepSeekReasoningModel(modelId)) {\n return {\n levels: [...DEEPSEEK_EFFORT_LEVELS],\n defaultLevel: 'high',\n supportsSummaries: true,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'deepseek-thinking' },\n };\n }\n\n if (isKimiReasoningModel(modelId)) {\n return {\n levels: [...OPENAI_EFFORT_LEVELS],\n defaultLevel: 'high',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n\n if (isGlm52ReasoningModel(modelId)) {\n return {\n levels: [...GLM_52_EFFORT_LEVELS],\n defaultLevel: 'high',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n\n if (hasSupportedParameter(metadata, 'reasoning_effort')) {\n return {\n levels: ['low', 'medium', 'high', 'xhigh'],\n defaultLevel: 'medium',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-metadata',\n confidence: 'documented',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n\n if (hasSupportedParameter(metadata, 'reasoning')) {\n return {\n levels: [...OPENROUTER_EFFORT_LEVELS],\n defaultLevel: 'medium',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-metadata',\n confidence: 'documented',\n wireFormat: { kind: 'openrouter-reasoning' },\n };\n }\n\n if (metadata?.reasoning) {\n return {\n levels: ['low', 'medium', 'high'],\n defaultLevel: 'medium',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'model-metadata',\n confidence: 'inferred',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n\n return EMPTY_REASONING;\n}\n\nexport function buildCodexReasoningLevels(\n capabilities: Pick<ReasoningCapabilities, 'levels'>,\n): Array<{ effort: string; description: string }> {\n return capabilities.levels.map(effort => ({\n effort,\n description: EFFORT_DESCRIPTIONS[effort] ?? effort,\n }));\n}\n\n/** Per-provider providerOptions for user-selected reasoning effort. */\nexport function effortProviderOptions(\n npm: string,\n effort?: string,\n modelId?: string,\n metadata?: ReasoningMetadata,\n): Record<string, Record<string, unknown>> | undefined {\n if (!effort) return undefined;\n\n if (isOpenRouterRoute(npm, metadata)) {\n const caps = openRouterReasoningCapabilities(metadata);\n if (caps.mode !== 'controllable') return undefined;\n const allowed = new Set(OPENROUTER_EFFORT_LEVELS);\n const mapped = allowed.has(effort as typeof OPENROUTER_EFFORT_LEVELS[number])\n ? effort\n : effort === 'max'\n ? 'xhigh'\n : undefined;\n return mapped\n ? { openrouter: { reasoning: { effort: mapped, exclude: false } } }\n : undefined;\n }\n\n if (npm === '@ai-sdk/openai' || npm === '@ai-sdk/azure') {\n if (!modelId || !modelPrefersResponsesApi(modelId)) return undefined;\n const reasoningEffort = mapCodexEffortToOpenAI(effort);\n return reasoningEffort ? { openai: { reasoningEffort } } : undefined;\n }\n\n if (npm === '@ai-sdk/xai') {\n if (!modelId || !isXaiReasoningEffortModel(modelId)) return undefined;\n const reasoningEffort = mapCodexEffortToXai(effort);\n return reasoningEffort ? { xai: { reasoningEffort } } : undefined;\n }\n\n if (npm === '@ai-sdk/anthropic' || npm === VERTEX_ANTHROPIC_NPM) {\n if (!modelId || !isClaudeReasoningModel(modelId)) return undefined;\n const mapped = mapCodexEffortToAnthropic(effort);\n return mapped\n ? { anthropic: { thinking: { type: 'adaptive', effort: mapped } } }\n : undefined;\n }\n\n if (npm === '@ai-sdk/google') {\n const id = modelId ?? '';\n if (isGemini3Model(id)) {\n const thinkingLevel = mapCodexEffortToGeminiLevel(effort);\n return thinkingLevel\n ? { google: { thinkingConfig: { thinkingLevel, includeThoughts: true } } }\n : undefined;\n }\n const thinkingBudget = mapCodexEffortToGeminiBudget(effort);\n return thinkingBudget\n ? { google: { thinkingConfig: { thinkingBudget, includeThoughts: true } } }\n : undefined;\n }\n\n if (npm === '@ai-sdk/mistral') {\n if (!modelId || !isMistralReasoningModel(modelId)) return undefined;\n const reasoningEffort = effort === 'off' || effort === 'none' ? 'none' : 'high';\n return { mistral: { reasoningEffort } };\n }\n\n if (npm === '@ai-sdk/openai-compatible' || npm === '@ai-sdk/openai') {\n if (!modelId) return undefined;\n if (isDeepSeekReasoningModel(modelId)) {\n return deepSeekEffortProviderOptions(effort);\n }\n if (isKimiReasoningModel(modelId)) {\n const reasoningEffort = mapCodexEffortToOpenAI(effort);\n if (reasoningEffort) {\n const key = metadata?.providerId ? toCamelCase(metadata.providerId) : 'openaiCompatible';\n return { [key]: { reasoningEffort } };\n }\n return undefined;\n }\n if (isGlm52ReasoningModel(modelId)) {\n const reasoningEffort = mapCodexEffortToGlm52(effort);\n if (reasoningEffort) {\n const key = metadata?.providerId ? toCamelCase(metadata.providerId) : 'openaiCompatible';\n return { [key]: { reasoningEffort } };\n }\n return undefined;\n }\n if (hasSupportedParameter(metadata, 'reasoning_effort')) {\n const reasoningEffort = mapCodexEffortToOpenAI(effort);\n return reasoningEffort\n ? { openai: { reasoningEffort }, openaiCompatible: { reasoningEffort } }\n : undefined;\n }\n if (hasSupportedParameter(metadata, 'reasoning')) {\n const allowed = new Set(OPENROUTER_EFFORT_LEVELS);\n const mapped = allowed.has(effort as typeof OPENROUTER_EFFORT_LEVELS[number])\n ? effort\n : effort === 'max' ? 'xhigh' : undefined;\n return mapped\n ? { openrouter: { reasoning: { effort: mapped, exclude: false } } }\n : undefined;\n }\n return undefined;\n }\n\n return undefined;\n}\n\nexport function deepMergeProviderOptions(\n a?: Record<string, Record<string, unknown>>,\n b?: Record<string, Record<string, unknown>>,\n): Record<string, Record<string, unknown>> | undefined {\n if (!a && !b) return undefined;\n if (!a) return b;\n if (!b) return a;\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n const out: Record<string, Record<string, unknown>> = {};\n for (const key of keys) {\n out[key] = { ...(a[key] ?? {}), ...(b[key] ?? {}) };\n }\n return out;\n}\n\n/** Per-provider providerOptions to request reasoning/thinking output. */\nexport function thinkingProviderOptions(npm: string): Record<string, Record<string, unknown>> | undefined {\n if (npm === '@ai-sdk/google') {\n return { google: { thinkingConfig: { includeThoughts: true } } };\n }\n // Responses API: request encrypted reasoning blobs for multi-turn round-trip\n // (proxy owns conversation state — store:false + echo via thinking.signature).\n if (npm === '@ai-sdk/openai') {\n return {\n openai: {\n store: false,\n include: ['reasoning.encrypted_content'],\n },\n };\n }\n return undefined;\n}\n","import type { OAuthTokenResponse } from './types.js';\n\nexport interface PostOAuthRefreshOptions {\n contentType: 'form' | 'json';\n errorPrefix: string;\n includeStatus?: boolean;\n includeBody?: boolean;\n headers?: Record<string, string>;\n}\n\nexport async function postOAuthRefresh(\n url: string,\n body: URLSearchParams | Record<string, string>,\n options: PostOAuthRefreshOptions,\n): Promise<OAuthTokenResponse> {\n const isJson = options.contentType === 'json';\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': isJson ? 'application/json' : 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n ...options.headers,\n },\n body: isJson ? JSON.stringify(body) : (body as URLSearchParams).toString(),\n });\n\n if (!response.ok) {\n const detail = options.includeBody ? await response.text().catch(() => '') : '';\n const status = options.includeStatus ? ` (${response.status})` : '';\n throw new Error(`${options.errorPrefix}${status}${detail ? `: ${detail}` : ''}`);\n }\n\n return response.json() as Promise<OAuthTokenResponse>;\n}\n","// openai.ts — native OpenAI ChatGPT Plus/Pro OAuth (device code, ported from OpenCode)\n\nimport { positiveSecondsToMs, sleepMs } from './pkce.js';\nimport type { OAuthTokenResponse } from './types.js';\nimport { VERSION } from '../constants.js';\nimport { postOAuthRefresh } from './refresh-http.js';\n\nconst CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';\nconst ISSUER = 'https://auth.openai.com';\nconst OAUTH_POLLING_SAFETY_MARGIN_MS = 3_000;\nconst DEVICE_CODE_DEFAULT_EXPIRES_MS = 5 * 60 * 1000;\n\nexport interface OpenAiIdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n 'https://api.openai.com/auth'?: { chatgpt_account_id?: string };\n}\n\nexport interface OpenAiDeviceCodeData {\n device_auth_id: string;\n user_code: string;\n interval: string;\n expires_in?: number;\n}\n\nexport function extractOpenAiAccountId(tokens: OAuthTokenResponse): string | undefined {\n const token = tokens.id_token ?? tokens.access_token;\n if (!token) return undefined;\n const parts = token.split('.');\n if (parts.length !== 3) return undefined;\n try {\n const claims = JSON.parse(Buffer.from(parts[1]!, 'base64url').toString()) as OpenAiIdTokenClaims;\n return claims.chatgpt_account_id\n ?? claims['https://api.openai.com/auth']?.chatgpt_account_id\n ?? claims.organizations?.[0]?.id;\n } catch {\n return undefined;\n }\n}\n\nexport async function requestOpenAiDeviceCode(): Promise<OpenAiDeviceCodeData> {\n const response = await fetch(`${ISSUER}/api/accounts/deviceauth/usercode`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': `relay-ai/${VERSION}`,\n },\n body: JSON.stringify({ client_id: CLIENT_ID }),\n });\n if (!response.ok) {\n throw new Error('Failed to initiate OpenAI device authorization');\n }\n return response.json() as Promise<OpenAiDeviceCodeData>;\n}\n\nexport function openAiDeviceCodeUrl(): string {\n return `${ISSUER}/codex/device`;\n}\n\nexport async function pollOpenAiDeviceCodeToken(\n deviceData: OpenAiDeviceCodeData,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<{ tokens: OAuthTokenResponse; accountId?: string }> {\n const sleep = opts?.sleep ?? sleepMs;\n const now = opts?.now ?? (() => Date.now());\n const intervalMs = Math.max(parseInt(deviceData.interval, 10) || 5, 1) * 1000;\n const deadline = now() + positiveSecondsToMs(deviceData.expires_in, DEVICE_CODE_DEFAULT_EXPIRES_MS);\n\n while (now() < deadline) {\n const response = await fetch(`${ISSUER}/api/accounts/deviceauth/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': `relay-ai/${VERSION}`,\n },\n body: JSON.stringify({\n device_auth_id: deviceData.device_auth_id,\n user_code: deviceData.user_code,\n }),\n });\n\n if (response.ok) {\n const data = await response.json() as { authorization_code: string; code_verifier: string };\n const tokenResponse = await fetch(`${ISSUER}/oauth/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code: data.authorization_code,\n redirect_uri: `${ISSUER}/deviceauth/callback`,\n client_id: CLIENT_ID,\n code_verifier: data.code_verifier,\n }).toString(),\n });\n if (!tokenResponse.ok) {\n throw new Error(`OpenAI token exchange failed (${tokenResponse.status})`);\n }\n const tokens = await tokenResponse.json() as OAuthTokenResponse;\n return { tokens, accountId: extractOpenAiAccountId(tokens) };\n }\n\n if (response.status !== 403 && response.status !== 404) {\n throw new Error(`OpenAI device authorization failed (${response.status})`);\n }\n\n await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, Math.max(0, deadline - now())));\n }\n throw new Error('OpenAI device authorization timed out');\n}\n\nexport async function refreshOpenAiAccessToken(refreshToken: string): Promise<OAuthTokenResponse> {\n return postOAuthRefresh(\n `${ISSUER}/oauth/token`,\n new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: CLIENT_ID,\n }),\n {\n contentType: 'form',\n errorPrefix: 'OpenAI token refresh failed',\n includeStatus: true,\n },\n );\n}\n\nexport async function runOpenAiDeviceCodeFlow(\n onDeviceCode: (info: { url: string; userCode: string }) => void,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<{ tokens: OAuthTokenResponse; accountId?: string }> {\n const deviceData = await requestOpenAiDeviceCode();\n onDeviceCode({ url: openAiDeviceCodeUrl(), userCode: deviceData.user_code });\n return pollOpenAiDeviceCodeToken(deviceData, opts);\n}\n","// responses-websocket.ts — outbound WebSocket transport for OpenAI's Codex\n// \"Responses-Lite\" protocol (wss://chatgpt.com/backend-api/codex/responses).\n//\n// Some ChatGPT Codex models (flagged by the backend with prefer_websockets,\n// e.g. gpt-5.6-luna) are only served over a WebSocket Responses transport, not\n// the HTTP Responses endpoint. This module returns a `fetch` implementation that\n// the Vercel AI SDK's OpenAI provider uses transparently: the SDK still calls\n// `fetch(url, init)` once per request, but instead of an HTTP POST we open one\n// WebSocket per request, send the Responses payload as the first message, and\n// stream the JSON event frames back as Server-Sent Events the SDK already parses.\n//\n// One socket per request → responses are never crossed between concurrent\n// requests (e.g. Claude Code's parallel title-generation + main inference).\n\nimport type { FetchFunction } from '@ai-sdk/provider-utils';\nimport type { RawData, WebSocket as WsWebSocket } from 'ws';\nimport { CODEX_RESPONSES_WEBSOCKETS_BETA } from '../constants.js';\n\nconst RESPONSES_LITE_HEADER = 'x-openai-internal-codex-responses-lite';\n// Responses event types after which the stream is complete and the socket closes.\nconst TERMINAL_EVENT_TYPES = new Set(['response.completed', 'response.failed', 'response.incomplete', 'error']);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction recordKeys(value: unknown): string {\n return isRecord(value) ? Object.keys(value).sort().join(',') : '';\n}\n\n/** Sanitized one-line summary: types, keys, counts, lengths — never field values. */\nexport function summarizeResponsesLiteEvent(event: unknown): string {\n if (!isRecord(event)) return `kind=${event == null ? 'null' : typeof event}`;\n const parts = [`type=${typeof event.type === 'string' ? event.type : 'unknown'}`, `keys=${recordKeys(event)}`];\n if (typeof event.delta === 'string') parts.push(`deltaChars=${event.delta.length}`);\n if (typeof event.output_index === 'number') parts.push(`hasOutputIndex=1`);\n if (typeof event.item_id === 'string') parts.push(`hasItemId=1`);\n if (isRecord(event.item)) {\n parts.push(`itemType=${typeof event.item.type === 'string' ? event.item.type : 'unknown'}`);\n parts.push(`itemKeys=${recordKeys(event.item)}`);\n if (typeof event.item.arguments === 'string') parts.push(`argumentsChars=${event.item.arguments.length}`);\n }\n if (isRecord(event.response)) {\n parts.push(`responseKeys=${recordKeys(event.response)}`);\n if (Array.isArray(event.response.output)) {\n parts.push(`outputCount=${event.response.output.length}`);\n parts.push(`outputTypes=${event.response.output.map(item => (isRecord(item) && typeof item.type === 'string' ? item.type : 'unknown')).join(',')}`);\n }\n if (isRecord(event.response.usage)) parts.push(`usageKeys=${recordKeys(event.response.usage)}`);\n if (typeof event.response.status === 'string') parts.push(`status=${event.response.status}`);\n }\n if (isRecord(event.error)) {\n parts.push(`errorKeys=${recordKeys(event.error)}`);\n if (typeof event.error.message === 'string') parts.push(`messageChars=${event.error.message.length}`);\n }\n return parts.join(' ');\n}\n\nexport interface ResponsesLiteNormalizeState {\n nextId: number;\n lastMessageItemId?: string;\n lastFunctionItemId?: string;\n lastOutputIndex: number;\n textDeltaForwarded: boolean;\n messageAddedIds: Set<string>;\n messageDoneIds: Set<string>;\n functionAddedIndexes: Set<number>;\n functionDeltaIndexes: Set<number>;\n functionDoneCallIds: Set<string>;\n}\n\nexport function createResponsesLiteNormalizeState(): ResponsesLiteNormalizeState {\n return {\n nextId: 1,\n lastOutputIndex: 0,\n textDeltaForwarded: false,\n messageAddedIds: new Set(),\n messageDoneIds: new Set(),\n functionAddedIndexes: new Set(),\n functionDeltaIndexes: new Set(),\n functionDoneCallIds: new Set(),\n };\n}\n\nfunction nextId(state: ResponsesLiteNormalizeState, prefix: string): string {\n const id = `${prefix}_${state.nextId}`;\n state.nextId += 1;\n return id;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction normalizeErrorEvent(event: Record<string, unknown>): Record<string, unknown> {\n const raw = isRecord(event.error) ? event.error : { message: typeof event.error === 'string' ? event.error : 'upstream error' };\n return {\n type: 'error',\n sequence_number: typeof event.sequence_number === 'number' ? event.sequence_number : 0,\n error: {\n type: asString(raw.type) ?? 'server_error',\n code: asString(raw.code) ?? 'unknown',\n message: asString(raw.message) ?? 'upstream error',\n ...(raw.param == null ? {} : { param: raw.param }),\n },\n };\n}\n\nfunction normalizeFunctionItem(item: Record<string, unknown>, state: ResponsesLiteNormalizeState, forDone = false): Record<string, unknown> {\n const callId = asString(item.call_id) ?? asString(item.id) ?? nextId(state, 'call');\n const id = asString(item.id) ?? nextId(state, 'fc');\n state.lastFunctionItemId = id;\n return {\n ...item,\n type: 'function_call',\n id,\n call_id: callId,\n name: asString(item.name) ?? '',\n arguments: typeof item.arguments === 'string' ? item.arguments : '',\n ...(forDone ? { status: 'completed' } : {}),\n };\n}\n\nfunction messageText(item: Record<string, unknown>): string {\n if (typeof item.text === 'string') return item.text;\n if (!Array.isArray(item.content)) return '';\n let out = '';\n for (const part of item.content) {\n if (isRecord(part) && typeof part.text === 'string' && (part.type === 'output_text' || part.type === 'text')) {\n out += part.text;\n }\n }\n return out;\n}\n\nfunction synthesizeMessage(item: Record<string, unknown>, outputIndex: number, state: ResponsesLiteNormalizeState): unknown[] {\n const text = messageText(item);\n if (!text) return [];\n const id = asString(item.id) ?? nextId(state, 'msg');\n state.lastMessageItemId = id;\n state.textDeltaForwarded = true;\n state.messageAddedIds.add(id);\n state.messageDoneIds.add(id);\n return [\n { type: 'response.output_item.added', output_index: outputIndex, item: { type: 'message', id } },\n { type: 'response.output_text.delta', item_id: id, delta: text },\n { type: 'response.output_item.done', output_index: outputIndex, item: { type: 'message', id } },\n ];\n}\n\nfunction synthesizeFunctionCall(item: Record<string, unknown>, outputIndex: number, state: ResponsesLiteNormalizeState): unknown[] {\n const normalized = normalizeFunctionItem(item, state);\n const callId = String(normalized.call_id);\n if (state.functionDoneCallIds.has(callId)) return [];\n const events: unknown[] = [];\n if (!state.functionAddedIndexes.has(outputIndex)) {\n events.push({\n type: 'response.output_item.added',\n output_index: outputIndex,\n item: { ...normalized, arguments: '' },\n });\n state.functionAddedIndexes.add(outputIndex);\n }\n if (!state.functionDeltaIndexes.has(outputIndex) && typeof normalized.arguments === 'string' && normalized.arguments.length > 0) {\n events.push({\n type: 'response.function_call_arguments.delta',\n item_id: normalized.id,\n output_index: outputIndex,\n delta: normalized.arguments,\n });\n state.functionDeltaIndexes.add(outputIndex);\n }\n events.push({\n type: 'response.output_item.done',\n output_index: outputIndex,\n item: { ...normalized, status: 'completed' },\n });\n state.functionDoneCallIds.add(callId);\n state.lastOutputIndex = outputIndex;\n return events;\n}\n\nfunction recoverFromCompletedOutput(response: Record<string, unknown>, state: ResponsesLiteNormalizeState): unknown[] {\n if (!Array.isArray(response.output)) return [];\n const recovered: unknown[] = [];\n response.output.forEach((item, index) => {\n if (!isRecord(item) || typeof item.type !== 'string') return;\n if (item.type === 'message' && !state.textDeltaForwarded) {\n recovered.push(...synthesizeMessage(item, index, state));\n } else if (item.type === 'function_call') {\n recovered.push(...synthesizeFunctionCall(item, index, state));\n }\n });\n return recovered;\n}\n\n/**\n * Fill fields `@ai-sdk/openai` requires and recover final output that only\n * exists on `response.completed`. Incomplete frames otherwise become\n * `unknown_chunk` and are dropped while usage still parses — the production\n * \"empty response after N calls\" shape.\n */\nexport function normalizeResponsesLiteEvent(event: unknown, state: ResponsesLiteNormalizeState): unknown[] {\n if (!isRecord(event) || typeof event.type !== 'string') return [event];\n\n if (event.type === 'error') return [normalizeErrorEvent(event)];\n\n if (event.type === 'response.output_item.added' && isRecord(event.item)) {\n const outputIndex = typeof event.output_index === 'number' ? event.output_index : state.lastOutputIndex;\n state.lastOutputIndex = outputIndex;\n if (event.item.type === 'message') {\n const id = asString(event.item.id) ?? nextId(state, 'msg');\n state.lastMessageItemId = id;\n state.messageAddedIds.add(id);\n return [{ ...event, output_index: outputIndex, item: { ...event.item, id } }];\n }\n if (event.item.type === 'function_call') {\n const item = normalizeFunctionItem(event.item, state);\n state.functionAddedIndexes.add(outputIndex);\n return [{ ...event, output_index: outputIndex, item }];\n }\n return [{ ...event, output_index: outputIndex }];\n }\n\n if (event.type === 'response.output_item.done' && isRecord(event.item)) {\n const outputIndex = typeof event.output_index === 'number' ? event.output_index : state.lastOutputIndex;\n if (event.item.type === 'function_call') {\n const item = normalizeFunctionItem(event.item, state, true);\n const callId = String(item.call_id);\n state.functionDoneCallIds.add(callId);\n return [{ ...event, output_index: outputIndex, item }];\n }\n if (event.item.type === 'message') {\n const id = asString(event.item.id) ?? state.lastMessageItemId ?? nextId(state, 'msg');\n state.lastMessageItemId = id;\n state.messageDoneIds.add(id);\n return [{ ...event, output_index: outputIndex, item: { ...event.item, id } }];\n }\n return [{ ...event, output_index: outputIndex }];\n }\n\n if (event.type === 'response.output_text.delta') {\n const itemId = asString(event.item_id) ?? state.lastMessageItemId ?? nextId(state, 'msg');\n state.lastMessageItemId = itemId;\n state.textDeltaForwarded = true;\n const events: unknown[] = [];\n if (!state.messageAddedIds.has(itemId)) {\n events.push({\n type: 'response.output_item.added',\n output_index: state.lastOutputIndex,\n item: { type: 'message', id: itemId },\n });\n state.messageAddedIds.add(itemId);\n }\n events.push({ ...event, item_id: itemId, delta: typeof event.delta === 'string' ? event.delta : '' });\n return events;\n }\n\n if (event.type === 'response.function_call_arguments.delta') {\n const itemId = asString(event.item_id) ?? state.lastFunctionItemId ?? nextId(state, 'fc');\n const outputIndex = typeof event.output_index === 'number' ? event.output_index : state.lastOutputIndex;\n state.lastFunctionItemId = itemId;\n state.lastOutputIndex = outputIndex;\n state.functionDeltaIndexes.add(outputIndex);\n return [{ ...event, item_id: itemId, output_index: outputIndex, delta: typeof event.delta === 'string' ? event.delta : '' }];\n }\n\n if (event.type === 'response.completed' || event.type === 'response.incomplete') {\n const response = isRecord(event.response) ? event.response : {};\n const recovered = recoverFromCompletedOutput(response, state);\n if (state.lastMessageItemId && state.textDeltaForwarded && !state.messageDoneIds.has(state.lastMessageItemId)) {\n recovered.push({\n type: 'response.output_item.done',\n output_index: state.lastOutputIndex,\n item: { type: 'message', id: state.lastMessageItemId },\n });\n state.messageDoneIds.add(state.lastMessageItemId);\n }\n return [...recovered, event];\n }\n\n return [event];\n}\n\n/** Normalize the SDK's HeadersInit into a plain lowercased-key record for `ws`. */\nfunction toHeaderRecord(headers: HeadersInit | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n if (!headers) return out;\n if (headers instanceof Headers) {\n headers.forEach((value, key) => { out[key] = value; });\n } else if (Array.isArray(headers)) {\n for (const [key, value] of headers) out[key] = value;\n } else {\n for (const [key, value] of Object.entries(headers)) out[key] = String(value);\n }\n return out;\n}\n\nfunction hasResponsesLiteHeader(headers: Record<string, string>): boolean {\n return Object.entries(headers).some(\n ([k, v]) => k.toLowerCase() === RESPONSES_LITE_HEADER && v.toLowerCase() === 'true',\n );\n}\n\n/** Extract the request body as a string (the SDK sends a JSON string). */\nfunction bodyToString(body: BodyInit | null | undefined): string {\n if (body == null) return '';\n if (typeof body === 'string') return body;\n if (body instanceof Uint8Array) return Buffer.from(body).toString('utf8');\n if (body instanceof ArrayBuffer) return Buffer.from(new Uint8Array(body)).toString('utf8');\n return String(body);\n}\n\n/**\n * Apply the Responses-Lite request shape to the outgoing payload. These fields\n * are set on the wire (not via SDK providerOptions) so the transport fully owns\n * the Luna request shape. Adjust here if live traffic shows different field names.\n */\nfunction applyResponsesLiteShape(payload: Record<string, unknown>): Record<string, unknown> {\n const reasoning = (payload.reasoning && typeof payload.reasoning === 'object')\n ? { ...(payload.reasoning as Record<string, unknown>) }\n : {};\n reasoning.context = 'all_turns';\n return {\n ...payload,\n reasoning,\n parallel_tool_calls: false,\n store: false,\n };\n}\n\n/**\n * Build a `fetch` that speaks the Codex Responses-Lite WebSocket protocol.\n * @param wsUrl e.g. wss://chatgpt.com/backend-api/codex/responses\n * @param log optional debug logger (wired to the proxy trace log under --trace)\n */\nexport function createResponsesWebSocketFetch(wsUrl: string, log?: (msg: string) => void): FetchFunction {\n const debug = (msg: string) => { try { log?.(`ws: ${msg}`); } catch { /* ignore */ } };\n return async (_input, init): Promise<Response> => {\n const { WebSocket } = await import('ws');\n\n const headers = toHeaderRecord(init?.headers);\n headers['OpenAI-Beta'] = CODEX_RESPONSES_WEBSOCKETS_BETA;\n debug(`connecting ${wsUrl} headers=[${Object.keys(headers).join(', ')}]`);\n\n // Parse the SDK-built Responses body and, when this is a Responses-Lite\n // model, fold in the transport-specific request fields.\n let payload: Record<string, unknown> = {};\n try {\n payload = JSON.parse(bodyToString(init?.body)) as Record<string, unknown>;\n } catch {\n payload = {};\n }\n if (hasResponsesLiteHeader(headers)) {\n payload = applyResponsesLiteShape(payload);\n }\n debug(\n `request type=response.create keys=${Object.keys(payload).sort().join(',')} `\n + `toolCount=${Array.isArray(payload.tools) ? payload.tools.length : 0} `\n + `store=${String(payload.store)} parallelToolCalls=${String(payload.parallel_tool_calls)} `\n + `reasoningKeys=${recordKeys(payload.reasoning)}`,\n );\n // The Codex WS Responses protocol is internally tagged: the first (and only)\n // client message must be a `response.create` event carrying the Responses\n // body fields at the top level, alongside the type tag — not the raw body.\n // (See openai/codex `ResponsesWsRequest`, `#[serde(tag = \"type\")]`.)\n const outgoing = JSON.stringify({ type: 'response.create', ...payload });\n\n const encoder = new TextEncoder();\n let socket: WsWebSocket;\n let frameCount = 0;\n const normalizeState = createResponsesLiteNormalizeState();\n\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n let closed = false;\n const close = () => {\n if (closed) return;\n closed = true;\n try { controller.close(); } catch { /* already closed */ }\n try { socket.close(); } catch { /* ignore */ }\n };\n const fail = (message: string) => {\n if (closed) return;\n debug(`fail messageChars=${message.length}`);\n // Surface as an SSE error event the SDK's responses parser understands.\n try {\n const [errorEvent] = normalizeResponsesLiteEvent({ type: 'error', error: { message } }, normalizeState);\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(errorEvent)}\\n\\n`));\n } catch { /* ignore */ }\n close();\n };\n\n socket = new WebSocket(wsUrl, { headers });\n\n socket.on('open', () => {\n debug(`open — sending ${outgoing.length}B payload`);\n socket.send(outgoing);\n });\n socket.on('unexpected-response', (_req, res) => {\n debug(`unexpected-response status=${res.statusCode}`);\n });\n\n socket.on('message', (data: RawData) => {\n const text = Array.isArray(data)\n ? Buffer.concat(data).toString('utf8')\n : data.toString('utf8');\n frameCount += 1;\n let event: unknown;\n try {\n event = JSON.parse(text);\n } catch {\n debug(`frame#${frameCount} non-json chars=${text.length}`);\n controller.enqueue(encoder.encode(`data: ${text.replace(/\\r?\\n/g, ' ')}\\n\\n`));\n return;\n }\n if (frameCount <= 8) debug(`frame#${frameCount} ${summarizeResponsesLiteEvent(event)}`);\n for (const next of normalizeResponsesLiteEvent(event, normalizeState)) {\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(next)}\\n\\n`));\n }\n const type = isRecord(event) && typeof event.type === 'string' ? event.type : undefined;\n if (type && TERMINAL_EVENT_TYPES.has(type)) {\n debug(`terminal event: ${type} (after ${frameCount} frames)`);\n close();\n }\n });\n\n socket.on('error', (err: Error) => fail(err.message));\n socket.on('close', (code: number, reason: Buffer) => {\n debug(`close code=${code} frames=${frameCount}${reason?.length ? ` reasonChars=${reason.length}` : ''}`);\n if (closed) return;\n if (code === 1000 || code === 1005) { close(); return; }\n fail(`WebSocket closed (${code})${reason?.length ? `: ${reason.toString('utf8')}` : ''}`);\n });\n\n const signal = init?.signal;\n if (signal) {\n if (signal.aborted) { close(); return; }\n signal.addEventListener('abort', close, { once: true });\n }\n },\n cancel() {\n try { socket?.close(); } catch { /* ignore */ }\n },\n });\n\n return new Response(stream, {\n status: 200,\n headers: { 'content-type': 'text/event-stream; charset=utf-8' },\n });\n };\n}\n","// src/oauth/claude-identity.ts — Request identity simulation for Claude Code OAuth.\n// Anthropic validates that OAuth requests match the claude-cli fingerprint.\n\nimport { createHash, randomUUID } from 'node:crypto';\n\nexport const CLAUDE_CODE_CLI_VERSION = '2.1.195';\nexport const CLAUDE_CODE_USER_AGENT = `claude-cli/${CLAUDE_CODE_CLI_VERSION} (external, cli)`;\nexport const CLAUDE_CODE_ENTRYPOINT = process.env.CLAUDE_CODE_ENTRYPOINT ?? 'cli';\nexport const CLAUDE_CODE_BILLING_HEADER_PREFIX = 'x-anthropic-billing-header:';\n\n// Per-process session IDs keyed by seed — same value emitted for X-Claude-Code-Session-Id\n// and metadata.user_id.session_id.\nconst sessionCache = new Map<string, string>();\n\nfunction getOrCreateSessionId(seed: string): string {\n let id = sessionCache.get(seed);\n if (!id) { id = randomUUID(); sessionCache.set(seed, id); }\n return id;\n}\n\n// Deterministic UUIDv4 from a SHA-256 hash — used as fallback when bootstrap hasn't run.\nfunction uuidFromHash(input: string): string {\n const h = createHash('sha256').update(input).digest('hex');\n return [h.slice(0,8), h.slice(8,12), '4'+h.slice(13,16),\n ((parseInt(h[16]!,16)&3)|8).toString(16)+h.slice(17,20), h.slice(20,32)].join('-');\n}\n\nconst HEX64_RE = /^[a-f0-9]{64}$/i;\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/** Resolve cliUserID (device_id) from stored providerData, falling back to a hash. */\nexport function resolveCliUserID(\n providerData: Record<string, unknown> | undefined,\n seed: string,\n): string {\n const v = providerData?.cliUserID;\n if (typeof v === 'string' && HEX64_RE.test(v)) return v;\n return createHash('sha256').update(`cliUserID:${seed}`).digest('hex');\n}\n\n/** Resolve accountUUID from stored providerData, falling back to a deterministic UUID. */\nexport function resolveAccountUUID(\n providerData: Record<string, unknown> | undefined,\n seed: string,\n): string {\n const v = providerData?.accountUUID;\n if (typeof v === 'string' && UUID_RE.test(v)) return v;\n return uuidFromHash(`account:${seed}`);\n}\n\nexport function buildUserIdJson(deviceId: string, accountUUID: string, sessionId: string): string {\n return JSON.stringify({ device_id: deviceId, account_uuid: accountUUID, session_id: sessionId });\n}\n\nexport function buildClaudeCodeBillingSystemLine(): string {\n return `${CLAUDE_CODE_BILLING_HEADER_PREFIX} cc_version=${CLAUDE_CODE_CLI_VERSION}.0; cc_entrypoint=${CLAUDE_CODE_ENTRYPOINT};`;\n}\n\nfunction systemBlockText(block: unknown): string | undefined {\n if (typeof block === 'string') return block;\n if (block && typeof block === 'object' && 'text' in block) {\n const text = (block as { text?: unknown }).text;\n return typeof text === 'string' ? text : undefined;\n }\n return undefined;\n}\n\nfunction hasClaudeCodeBillingSystemLine(system: unknown): boolean {\n if (typeof system === 'string') return system.startsWith(CLAUDE_CODE_BILLING_HEADER_PREFIX);\n if (!Array.isArray(system)) return false;\n return system.some(block => systemBlockText(block)?.startsWith(CLAUDE_CODE_BILLING_HEADER_PREFIX));\n}\n\nexport function injectClaudeCodeBillingSystemLine(body: Record<string, unknown>): void {\n if (hasClaudeCodeBillingSystemLine(body.system)) return;\n\n const billingBlock = { type: 'text', text: buildClaudeCodeBillingSystemLine() };\n if (body.system === undefined || body.system === null) {\n body.system = [billingBlock];\n } else if (typeof body.system === 'string') {\n body.system = [billingBlock, { type: 'text', text: body.system }];\n } else if (Array.isArray(body.system)) {\n body.system = [billingBlock, ...body.system];\n } else {\n body.system = [billingBlock];\n }\n}\n\n// ── Beta flag selection ────────────────────────────────────────────────────\n// Anthropic validates the anthropic-beta set matches the request shape.\n\nconst ALWAYS: string[] = [\n 'oauth-2025-04-20',\n 'context-management-2025-06-27',\n 'prompt-caching-scope-2026-01-05',\n];\nconst AGENT: string[] = [\n 'claude-code-20250219',\n 'extended-cache-ttl-2025-04-11',\n 'cache-diagnosis-2026-04-07',\n 'advisor-tool-2026-03-01',\n];\nconst THINKING: string[] = [\n 'interleaved-thinking-2025-05-14',\n 'redact-thinking-2026-02-12',\n 'thinking-token-count-2026-05-13',\n];\nconst HEAVY: string[] = ['advanced-tool-use-2025-11-20', 'effort-2025-11-24'];\nconst OPUS_ONLY: string[] = ['context-1m-2025-08-07', 'mid-conversation-system-2026-04-07'];\n\n/**\n * Select anthropic-beta flags matching the request shape.\n * clientBeta: the inbound anthropic-beta header from the client — respected to avoid\n * forcing betas the client never requested (can cause malformed tool_use streams).\n */\nexport function selectBetaFlags(\n body: Record<string, unknown>,\n model?: string | null,\n clientBeta?: string | null,\n): string {\n const hasSystem = !!body.system &&\n (typeof body.system === 'string' || (Array.isArray(body.system) && body.system.length > 0));\n const tools = body.tools as unknown[] | undefined;\n const isFullAgent = hasSystem && Array.isArray(tools) && tools.length > 0;\n const m = (model ?? (typeof body.model === 'string' ? body.model : '')).toLowerCase();\n const isOpus = m.includes('opus');\n const isSonnetOrOpus = isOpus || m.includes('sonnet');\n\n const clientSet = clientBeta\n ? new Set(clientBeta.split(',').map(s => s.trim()).filter(Boolean))\n : null;\n const allowThinking = !clientSet || clientSet.has('interleaved-thinking-2025-05-14');\n const allowHeavy = !clientSet\n || clientSet.has('advanced-tool-use-2025-11-20')\n || clientSet.has('effort-2025-11-24');\n\n const flags = [...ALWAYS];\n if (isFullAgent) flags.push(...AGENT);\n if (isOpus) flags.push(...OPUS_ONLY);\n if (allowThinking) flags.push(...THINKING);\n if (isFullAgent && isSonnetOrOpus && allowHeavy) flags.push(...HEAVY);\n\n return flags.join(',');\n}\n\n/**\n * Inject Claude Code identity metadata into an Anthropic request body in-place.\n * Must be called before forwarding the request to api.anthropic.com.\n */\nexport function injectClaudeIdentity(\n body: Record<string, unknown>,\n providerData: Record<string, unknown> | undefined,\n seed: string,\n): { sessionId: string; userId: string } {\n const deviceId = resolveCliUserID(providerData, seed);\n const accountUUID = resolveAccountUUID(providerData, seed);\n const sessionId = getOrCreateSessionId(seed);\n const userId = buildUserIdJson(deviceId, accountUUID, sessionId);\n const existing = body.metadata as Record<string, unknown> | undefined;\n body.metadata = { ...(existing ?? {}), user_id: userId };\n return { sessionId, userId };\n}\n","/** Shared ClinePass endpoint and runtime credential rules. */\n\nexport const CLINE_PASS_HOST = 'https://api.cline.bot';\nexport const CLINE_PASS_SDK_BASE_URL = `${CLINE_PASS_HOST}/api/v1`;\nexport const CLINE_PASS_CATALOG_URL = `${CLINE_PASS_HOST}/api/v1/ai/cline/recommended-models`;\n/** Authenticated, non-inference endpoint used to verify API-key credentials. */\nexport const CLINE_PASS_VALIDATION_URL = `${CLINE_PASS_HOST}/api/v1/users/me`;\nexport const CLINE_PASS_REGISTER_URL = `${CLINE_PASS_HOST}/api/v1/auth/register`;\nexport const CLINE_PASS_REFRESH_URL = `${CLINE_PASS_HOST}/api/v1/auth/refresh`;\n/** Value written by Relay 0.8.0 before ClinePass reported context metadata. */\nexport const CLINE_PASS_LEGACY_DEFAULT_CONTEXT_WINDOW = 131_072;\nexport const CLINE_PASS_WORKOS_PREFIX = 'workos:';\n\nexport function isClinePassOAuth(providerId?: string, authType?: string): boolean {\n return providerId === 'cline-pass' && authType === 'oauth';\n}\n\n/** Format only ClinePass OAuth access tokens; API keys remain raw. */\nexport function formatClineRuntimeCredential(\n providerId: string | undefined,\n authType: 'api' | 'oauth' | 'none' | undefined,\n key: string,\n): string {\n if (!isClinePassOAuth(providerId, authType)) return key;\n return key.toLowerCase().startsWith(CLINE_PASS_WORKOS_PREFIX)\n ? key\n : `${CLINE_PASS_WORKOS_PREFIX}${key}`;\n}\n\n/**\n * Wrap the SDK fetch used by ClinePass OAuth routes.\n *\n * WorkOS access tokens are stored without the runtime marker. ClinePass\n * requires `workos:` on the wire, and an expired token gets one retry after\n * the caller refreshes it. The request is cloned so a POST body can safely be\n * sent a second time, and the wrapper never retries more than once.\n */\nexport function createClinePassOAuthFetch(\n initialRuntimeCredential: string,\n refreshToken: () => Promise<string | null>,\n onTokenRefreshed?: (rawToken: string) => void,\n fetchImpl: typeof globalThis.fetch = globalThis.fetch,\n): typeof globalThis.fetch {\n let currentRuntimeCredential = initialRuntimeCredential;\n\n return async (input, init) => {\n const request = new Request(input, init);\n const send = (runtimeCredential: string) => {\n const headers = new Headers(request.headers);\n headers.set('Authorization', `Bearer ${runtimeCredential}`);\n return fetchImpl(request.clone(), { headers });\n };\n\n const response = await send(currentRuntimeCredential);\n if (response.status !== 401) return response;\n\n const refreshedRawToken = await refreshToken().catch(() => null);\n const refreshedRuntimeCredential = refreshedRawToken\n ? formatClineRuntimeCredential('cline-pass', 'oauth', refreshedRawToken)\n : null;\n if (!refreshedRawToken || !refreshedRuntimeCredential || refreshedRuntimeCredential === currentRuntimeCredential) {\n return response;\n }\n\n currentRuntimeCredential = refreshedRuntimeCredential;\n onTokenRefreshed?.(refreshedRawToken);\n return send(currentRuntimeCredential);\n };\n}\n","// src/registry/io.ts — load/save providers.json with secure permissions\n\nimport {\n chmodSync,\n copyFileSync,\n existsSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n writeSync,\n closeSync,\n} from 'node:fs';\nimport { dirname } from 'node:path';\nimport { getAppHome, getProvidersPath } from '../paths.js';\nimport type { ProviderRegistry, RegistryProvider } from './types.js';\nimport { REGISTRY_SCHEMA_VERSION } from './types.js';\nimport {\n migrateAlibabaDashScopeChinaLabel,\n migrateLegacyCloudProviders,\n migrateOAuthOpenAiProvider,\n migrateOAuthXaiProvider,\n} from './migrate.js';\nimport { isValidProviderId } from './validate.js';\n\nconst DIR_MODE = 0o700;\nconst FILE_MODE = 0o600;\n\nexport function ensureSecureAppHome(): void {\n const home = getAppHome();\n mkdirSync(home, { recursive: true, mode: DIR_MODE });\n try {\n chmodSync(home, DIR_MODE);\n } catch {\n // best-effort on platforms that restrict chmod\n }\n}\n\nfunction writeSecureFile(path: string, content: string): void {\n ensureSecureAppHome();\n mkdirSync(dirname(path), { recursive: true, mode: DIR_MODE });\n const fd = openSync(path, 'w', FILE_MODE);\n try {\n writeSync(fd, content);\n } finally {\n closeSync(fd);\n }\n try {\n chmodSync(path, FILE_MODE);\n } catch {\n // best-effort\n }\n}\n\nfunction parseProvider(raw: unknown): RegistryProvider | null {\n if (!raw || typeof raw !== 'object') return null;\n const p = raw as Record<string, unknown>;\n if (typeof p.id !== 'string' || !isValidProviderId(p.id)) return null;\n if (typeof p.templateId !== 'string' || !p.templateId) return null;\n if (typeof p.name !== 'string' || !p.name) return null;\n if (typeof p.enabled !== 'boolean') return null;\n if (typeof p.authRef !== 'string' || !p.authRef) return null;\n if (typeof p.addedAt !== 'string' || !p.addedAt) return null;\n const api = p.api;\n if (!api || typeof api !== 'object') return null;\n\n const provider: RegistryProvider = {\n id: p.id,\n templateId: p.templateId,\n name: p.name,\n enabled: p.enabled,\n authRef: p.authRef,\n api: api as RegistryProvider['api'],\n addedAt: p.addedAt,\n };\n\n if (p.subscriptionFilter === 'free' || p.subscriptionFilter === 'zen' || p.subscriptionFilter === 'go') {\n provider.subscriptionFilter = p.subscriptionFilter;\n }\n if (p.authType === 'api' || p.authType === 'oauth' || p.authType === 'none') {\n provider.authType = p.authType;\n }\n if (typeof p.refreshedAt === 'string') provider.refreshedAt = p.refreshedAt;\n if (p.modelsCache && typeof p.modelsCache === 'object') {\n const cache = p.modelsCache as { fetchedAt?: string; models?: unknown[] };\n if (typeof cache.fetchedAt === 'string' && Array.isArray(cache.models)) {\n provider.modelsCache = {\n fetchedAt: cache.fetchedAt,\n models: cache.models.filter(m => m && typeof m === 'object') as RegistryProvider['modelsCache'] extends infer C\n ? C extends { models: infer M } ? M : never\n : never,\n };\n }\n }\n return provider;\n}\n\nfunction parseRegistry(raw: unknown): ProviderRegistry {\n const empty: ProviderRegistry = { schemaVersion: REGISTRY_SCHEMA_VERSION, providers: [] };\n if (!raw || typeof raw !== 'object') return empty;\n const data = raw as Record<string, unknown>;\n const providers: RegistryProvider[] = [];\n if (Array.isArray(data.providers)) {\n for (const entry of data.providers) {\n const parsed = parseProvider(entry);\n if (parsed) providers.push(parsed);\n }\n }\n const registry: ProviderRegistry = {\n schemaVersion:\n typeof data.schemaVersion === 'number' ? data.schemaVersion : REGISTRY_SCHEMA_VERSION,\n providers,\n };\n if (typeof data.importedAt === 'string') registry.importedAt = data.importedAt;\n if (typeof data.pricingCacheAt === 'string') registry.pricingCacheAt = data.pricingCacheAt;\n return registry;\n}\n\nexport function loadRegistry(path = getProvidersPath(), { persist = true }: { persist?: boolean } = {}): ProviderRegistry {\n if (!existsSync(path)) {\n return { schemaVersion: REGISTRY_SCHEMA_VERSION, providers: [] };\n }\n try {\n const raw = JSON.parse(readFileSync(path, 'utf8'));\n const registry = parseRegistry(raw);\n let migrated = migrateLegacyCloudProviders(registry);\n if (migrateOAuthOpenAiProvider(registry)) migrated = true;\n if (migrateOAuthXaiProvider(registry)) migrated = true;\n if (migrateAlibabaDashScopeChinaLabel(registry)) migrated = true;\n // In-memory migrations always run (consumers like the embedded Core API\n // depend on them); persistence is gated so read-only callers never write.\n if (migrated && persist) {\n try {\n saveRegistry(registry, path);\n } catch {\n // Parsed data remains usable even when migration persistence fails.\n }\n }\n return registry;\n } catch {\n return { schemaVersion: REGISTRY_SCHEMA_VERSION, providers: [] };\n }\n}\n\nexport function saveRegistry(registry: ProviderRegistry, path = getProvidersPath()): void {\n const payload = `${JSON.stringify(registry, null, 2)}\\n`;\n const backup = `${path}.bak`;\n if (existsSync(path)) {\n try {\n copyFileSync(path, backup);\n } catch {\n // backup is best-effort\n }\n }\n const tmp = `${path}.tmp`;\n writeSecureFile(tmp, payload);\n renameSync(tmp, path);\n}\n\nexport function emptyRegistry(): ProviderRegistry {\n return { schemaVersion: REGISTRY_SCHEMA_VERSION, providers: [] };\n}\n","// src/registry/types.ts — native provider registry schema (no secrets)\n\nimport type { FreeStatus } from '../free-models.js';\n\nexport const REGISTRY_SCHEMA_VERSION = 1;\n\nexport type RegistrySubscriptionFilter = 'free' | 'zen' | 'go';\n\nexport interface CachedModel {\n id: string;\n name: string;\n upstreamModelId: string;\n family?: string;\n brand?: string;\n contextWindow?: number;\n /** Distinguishes provider-reported context from legacy Relay guesses. */\n contextWindowSource?: 'provider';\n cost?: { input: number; output: number; cache_read?: number; cache_write?: number };\n isFree?: boolean;\n freeStatus?: FreeStatus;\n modelFormat: 'anthropic' | 'openai' | 'cloud-code';\n /** Per-model override — wins over provider-level api.npm */\n npm?: string;\n /** Per-model override — wins over provider-level api.url */\n apiUrl?: string;\n sourceBackend?: string;\n /** Provider-reported request parameters, e.g. OpenRouter supported_parameters. */\n supportedParameters?: string[];\n /** Broad model metadata: model can produce reasoning/thinking output. */\n reasoning?: boolean;\n /** Streaming/interleaved reasoning field name from metadata, e.g. reasoning_content. */\n interleavedReasoningField?: string;\n /** Backend capability: model requires the Responses-Lite request shape (x-openai-internal-codex-responses-lite). */\n useResponsesLite?: boolean;\n /** Backend capability: model must use the WebSocket Responses transport instead of HTTP. */\n preferWebSockets?: boolean;\n}\n\nexport interface RegistryProvider {\n id: string;\n templateId: string;\n name: string;\n enabled: boolean;\n authRef: string;\n authType?: 'api' | 'oauth' | 'none';\n subscriptionFilter?: RegistrySubscriptionFilter;\n api: {\n npm?: string;\n url?: string;\n id?: string;\n /** Static headers sent on every upstream request (e.g. a plan/auth-tracking header a custom endpoint requires). */\n headers?: Record<string, string>;\n };\n modelsCache?: {\n fetchedAt: string;\n models: CachedModel[];\n };\n addedAt: string;\n refreshedAt?: string;\n}\n\nexport interface ProviderRegistry {\n schemaVersion: number;\n providers: RegistryProvider[];\n importedAt?: string;\n pricingCacheAt?: string;\n}\n","import type { ProviderRegistry } from './types.js';\n\nconst LEGACY_CLOUD_PROVIDER_IDS = [\n { legacyId: 'opencode', id: 'zen', name: 'OpenCode Zen' },\n { legacyId: 'opencode-go', id: 'go', name: 'OpenCode Go' },\n] as const;\n\nexport function migrateLegacyCloudProviders(registry: ProviderRegistry): boolean {\n let changed = false;\n\n for (const { legacyId, id, name } of LEGACY_CLOUD_PROVIDER_IDS) {\n const legacyIdx = registry.providers.findIndex(provider => provider.id === legacyId);\n if (legacyIdx < 0) continue;\n\n if (registry.providers.some(provider => provider.id === id)) {\n registry.providers.splice(legacyIdx, 1);\n } else {\n registry.providers[legacyIdx] = {\n ...registry.providers[legacyIdx]!,\n id,\n templateId: id,\n name,\n api: {},\n };\n }\n changed = true;\n }\n\n return changed;\n}\n\n// Rename {id:'openai', authType:'oauth'} → {id:'openai-oauth'} so it can coexist\n// with the API-key 'openai' provider. Preserves the original authRef so the\n// keyring credential isn't orphaned.\nexport function migrateOAuthOpenAiProvider(registry: ProviderRegistry): boolean {\n if (registry.providers.some(p => p.id === 'openai-oauth')) return false;\n\n const idx = registry.providers.findIndex(\n p => p.id === 'openai' && p.authType === 'oauth',\n );\n if (idx < 0) return false;\n\n const existing = registry.providers[idx]!;\n registry.providers[idx] = {\n ...existing,\n id: 'openai-oauth',\n templateId: existing.templateId || 'openai',\n name: existing.name === 'OpenAI' ? 'OpenAI (ChatGPT)' : existing.name,\n };\n return true;\n}\n\n// Rename {id:'xai', authType:'oauth'} → {id:'xai-oauth'}\nexport function migrateOAuthXaiProvider(registry: ProviderRegistry): boolean {\n if (registry.providers.some(p => p.id === 'xai-oauth')) return false;\n\n const idx = registry.providers.findIndex(\n p => p.id === 'xai' && p.authType === 'oauth',\n );\n if (idx < 0) return false;\n\n const existing = registry.providers[idx]!;\n registry.providers[idx] = {\n ...existing,\n id: 'xai-oauth',\n templateId: existing.templateId || 'xai',\n name: existing.name === 'xAI' ? 'xAI Grok (SuperGrok)' : existing.name,\n };\n return true;\n}\n\n/** Clarify the stock China DashScope entry without altering custom configurations. */\nexport function migrateAlibabaDashScopeChinaLabel(registry: ProviderRegistry): boolean {\n const provider = registry.providers.find(p =>\n p.id === 'alibaba' &&\n p.templateId === 'alibaba' &&\n p.name === 'Alibaba DashScope' &&\n p.api.url === 'https://dashscope.aliyuncs.com/compatible-mode/v1',\n );\n if (!provider) return false;\n\n provider.name = 'Alibaba DashScope (China)';\n return true;\n}\n","// src/registry/validate.ts\n\n/** Stable provider slug: lowercase alphanumeric + internal hyphens. */\nexport const PROVIDER_ID_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;\n\nexport function isValidProviderId(id: string): boolean {\n return PROVIDER_ID_PATTERN.test(id);\n}\n\nexport function slugifyProviderId(displayName: string): string {\n const base = displayName\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n if (!base) return 'custom-provider';\n if (isValidProviderId(base)) return base;\n const trimmed = base.replace(/^-+|-+$/g, '');\n return isValidProviderId(trimmed) ? trimmed : `custom-${trimmed.slice(0, 40)}`;\n}\n\nexport function customProviderId(displayName: string): string {\n const slug = slugifyProviderId(displayName);\n return slug.startsWith('custom-') ? slug : `custom-${slug}`;\n}\n","// src/core/errors.ts — RelayCoreError: safe, structured errors for embedded consumers.\n\nimport type { RelayCoreErrorCode, RelayRouteId } from './types.js';\n\nconst DEFAULT_RETRYABLE: Record<RelayCoreErrorCode, boolean> = {\n INVALID_ROUTE_ID: false,\n ROUTE_NOT_FOUND: false,\n PROVIDER_DISABLED: false,\n CREDENTIAL_UNAVAILABLE: false,\n OAUTH_REFRESH_FAILED: true,\n UNSUPPORTED_MODEL: false,\n UNSUPPORTED_REGISTRY_VERSION: false,\n PROVIDER_LOAD_FAILED: true,\n};\n\nexport interface RelayCoreErrorOptions {\n retryable?: boolean;\n providerId?: string;\n routeId?: RelayRouteId;\n cause?: unknown;\n}\n\n/**\n * Error thrown by the embedded Core API. Carries only safe structured metadata —\n * never credential material. `cause` is retained for internal debugging but is\n * omitted from JSON serialization.\n */\nexport class RelayCoreError extends Error {\n readonly code: RelayCoreErrorCode;\n readonly retryable: boolean;\n readonly providerId?: string;\n readonly routeId?: RelayRouteId;\n\n constructor(code: RelayCoreErrorCode, message: string, options: RelayCoreErrorOptions = {}) {\n super(message, options.cause !== undefined ? { cause: options.cause } : undefined);\n this.name = 'RelayCoreError';\n this.code = code;\n this.retryable = options.retryable ?? DEFAULT_RETRYABLE[code];\n if (options.providerId !== undefined) this.providerId = options.providerId;\n if (options.routeId !== undefined) this.routeId = options.routeId;\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n ...(this.providerId !== undefined ? { providerId: this.providerId } : {}),\n ...(this.routeId !== undefined ? { routeId: this.routeId } : {}),\n };\n }\n}\n\nexport function isRelayCoreError(err: unknown): err is RelayCoreError {\n return err instanceof RelayCoreError;\n}\n","// src/core/route-id.ts — `provider::model` route ids (unconditionally scoped).\n\nimport { isValidProviderId } from '../registry/validate.js';\nimport { RelayCoreError } from './errors.js';\nimport type { RelayRouteId } from './types.js';\n\nconst SEPARATOR = '::';\n\n/**\n * Build a route id from a provider id and a model id. The provider id must pass\n * the registry's `PROVIDER_ID_PATTERN`; the model id may contain `/` and `:`.\n */\nexport function toRelayRouteId(providerId: string, modelId: string): RelayRouteId {\n if (!isValidProviderId(providerId)) {\n throw new RelayCoreError('INVALID_ROUTE_ID', `Invalid provider id for route id: ${JSON.stringify(providerId)}`, {});\n }\n if (!modelId) {\n throw new RelayCoreError('INVALID_ROUTE_ID', 'Model id must be non-empty for a route id', { providerId });\n }\n return `${providerId}${SEPARATOR}${modelId}`;\n}\n\n/**\n * Parse a route id back into its parts. Splits on the FIRST `::` only, so model\n * ids containing `/` or `:` (e.g. `openrouter::vendor/model:free`) survive.\n * A bare model id (no `::`) is rejected.\n */\nexport function parseRelayRouteId(routeId: string): { providerId: string; modelId: string } {\n const idx = typeof routeId === 'string' ? routeId.indexOf(SEPARATOR) : -1;\n if (idx <= 0 || idx === routeId.length - SEPARATOR.length) {\n throw new RelayCoreError('INVALID_ROUTE_ID', `Route id must be \"provider::model\", got: ${JSON.stringify(routeId)}`);\n }\n const providerId = routeId.slice(0, idx);\n const modelId = routeId.slice(idx + SEPARATOR.length);\n if (!isValidProviderId(providerId)) {\n throw new RelayCoreError('INVALID_ROUTE_ID', `Invalid provider id in route id: ${JSON.stringify(routeId)}`);\n }\n return { providerId, modelId };\n}\n","// src/core/catalog.ts — credential-free model catalog for embedded consumers.\n\nimport { loadPreferences } from '../config.js';\nimport { getReasoningCapabilities } from '../provider-factory.js';\nimport { loadRegistry } from '../registry/io.js';\nimport { REGISTRY_SCHEMA_VERSION, type CachedModel, type ProviderRegistry, type RegistryProvider } from '../registry/types.js';\nimport { RelayCoreError } from './errors.js';\nimport { toRelayRouteId } from './route-id.js';\nimport type { RelayModelDescriptor } from './types.js';\n\n/** Read the registry without ever persisting migrations, and reject newer schemas. */\nexport function loadCoreRegistry(path?: string): ProviderRegistry {\n const registry = loadRegistry(path, { persist: false });\n if (registry.schemaVersion > REGISTRY_SCHEMA_VERSION) {\n throw new RelayCoreError(\n 'UNSUPPORTED_REGISTRY_VERSION',\n `Registry schema v${registry.schemaVersion} is newer than supported v${REGISTRY_SCHEMA_VERSION} — upgrade relay-ai.`,\n );\n }\n return registry;\n}\n\ntype ReasoningInfo = RelayModelDescriptor['capabilities'];\n\nfunction mapReasoning(provider: RegistryProvider, model: CachedModel): ReasoningInfo {\n const base = { tools: 'unknown' as const, vision: 'unknown' as const };\n const npm = model.npm ?? provider.api.npm ?? '';\n const upstreamModelId = model.upstreamModelId ?? model.id;\n try {\n const caps = getReasoningCapabilities(npm, upstreamModelId, {\n providerId: provider.id,\n apiBaseUrl: model.apiUrl ?? provider.api.url,\n supportedParameters: model.supportedParameters,\n reasoning: model.reasoning,\n interleavedReasoningField: model.interleavedReasoningField,\n upstreamModelId,\n });\n switch (caps.mode) {\n case 'none':\n return { ...base, reasoning: 'none' };\n case 'internal-only':\n return { ...base, reasoning: 'fixed' };\n case 'controllable':\n return {\n ...base,\n reasoning: 'adjustable',\n reasoningLevels: [...caps.levels],\n defaultReasoningLevel: caps.defaultLevel,\n };\n default:\n return { ...base, reasoning: 'unknown' };\n }\n } catch {\n // Reasoning classification is best-effort; never fail the catalog over it.\n return { ...base, reasoning: 'unknown' };\n }\n}\n\nfunction favoriteKey(providerId: string, modelId: string): string {\n return `${providerId}::${modelId}`;\n}\n\nfunction toDescriptor(provider: RegistryProvider, model: CachedModel, favorites: Set<string>): RelayModelDescriptor {\n const upstreamModelId = model.upstreamModelId ?? model.id;\n return {\n routeId: toRelayRouteId(provider.id, model.id),\n providerId: provider.id,\n providerName: provider.name,\n modelId: model.id,\n upstreamModelId,\n displayName: model.name,\n authType: provider.authType ?? 'api',\n favorite: favorites.has(favoriteKey(provider.id, model.id)),\n ...(model.contextWindow !== undefined ? { contextWindow: model.contextWindow } : {}),\n ...(model.cost\n ? {\n pricing: {\n input: model.cost.input,\n output: model.cost.output,\n ...(model.cost.cache_read !== undefined ? { cacheRead: model.cost.cache_read } : {}),\n ...(model.cost.cache_write !== undefined ? { cacheWrite: model.cost.cache_write } : {}),\n },\n }\n : {}),\n capabilities: mapReasoning(provider, model),\n };\n}\n\n/**\n * List the credential-free model catalog: one descriptor per cached model of\n * every enabled provider. Never resolves credentials, refreshes OAuth, hits a\n * provider API, or writes to disk.\n */\nexport function listRelayModels(registryPath?: string): RelayModelDescriptor[] {\n const registry = loadCoreRegistry(registryPath);\n const favorites = new Set(\n (loadPreferences().favoriteModels ?? []).map(f => favoriteKey(f.providerId, f.modelId)),\n );\n\n const descriptors: RelayModelDescriptor[] = [];\n for (const provider of registry.providers) {\n if (!provider.enabled) continue;\n for (const model of provider.modelsCache?.models ?? []) {\n descriptors.push(toDescriptor(provider, model, favorites));\n }\n }\n\n return descriptors.sort((a, b) =>\n Number(b.favorite) - Number(a.favorite)\n || a.providerName.localeCompare(b.providerName)\n || a.displayName.localeCompare(b.displayName),\n );\n}\n","// Context window resolution for proxy /v1/models and Claude Code child env.\n//\n// Priority:\n// 1. OpenCode models.json cache (limit.context) — `opencode` / `opencode-go` file keys first\n// 2. ID-pattern heuristics for models not in cache\n// 3. 200K default (Claude Code's own fallback for unknown models)\nimport { readFileSync } from 'node:fs';\nimport { OPENCODE_CACHE_PATH } from './constants.js';\n\nexport const DEFAULT_CONTEXT_WINDOW = 200_000;\n\n/** OpenCode cache file provider keys for Zen/Go (not relay-ai registry ids). */\nconst CACHE_PROVIDER_PRIORITY = new Set(['opencode', 'opencode-go']);\n\nexport interface OpencodeCacheModel {\n id?: string;\n name?: string;\n family?: string;\n status?: string;\n provider?: { npm?: string };\n cost?: { input: number; output: number };\n limit?: { context?: number; output?: number };\n reasoning?: boolean;\n interleaved?: { field?: string };\n}\n\nexport type OpencodeCacheFile = Record<string, { models?: Record<string, OpencodeCacheModel> }>;\n\n// Ordered by specificity — first match wins.\nconst HEURISTIC_RULES: Array<[RegExp, number]> = [\n [/gemini-2\\.5-pro|gemini-1\\.5-pro|gemini-3-pro/i, 2_000_000],\n [/gemini/i, 1_000_000],\n [/claude-opus-4-[678]|claude-sonnet-4-[678]/i, 1_000_000],\n [/claude-haiku-4-[567]/i, 200_000],\n [/claude.*\\[1m\\]/i, 1_000_000],\n [/claude-opus-4-[56]|claude-sonnet-4-[45]|claude-3/i, 200_000],\n [/claude/i, 200_000],\n [/deepseek-v4|deepseek-r1|deepseek-reasoner/i, 1_000_000],\n [/deepseek/i, 64_000],\n [/gpt-5|gpt-4\\.1|o3-|o4-/i, 1_000_000],\n [/gpt-4o|gpt-4-turbo|gpt-4/i, 128_000],\n [/gpt-oss/i, 131_072],\n [/qwen3|qwen-3|qwen2\\.5-72b|qwen2\\.5-32b|qwen-coder/i, 262_144],\n [/qwen/i, 131_072],\n [/kimi-k2|kimi-k2\\.5|moonshot/i, 262_144],\n [/minimax-m2/i, 204_800],\n [/minimax/i, 128_000],\n [/mistral-large|ministral|mistral/i, 262_144],\n [/llama-3\\.[23]|llama3/i, 131_072],\n [/grok-4\\.20/i, 1_000_000],\n [/grok-4\\.5/i, 500_000],\n [/grok-3|grok-4/i, 131_072],\n [/nemotron/i, 131_072],\n [/glm-4/i, 128_000],\n [/solar-pro3/i, 131_072],\n [/solar-pro2/i, 65_536],\n [/solar/i, 32_768],\n];\n\nlet parsedCache: OpencodeCacheFile | null | undefined;\nlet cacheIndex: Map<string, number> | undefined;\nconst heuristicCache = new Map<string, number>();\n\n/** Shared parse of ~/.cache/opencode/models.json — used by model list and context lookup. */\nexport function loadOpencodeCache(): OpencodeCacheFile | null {\n if (parsedCache === undefined) {\n try {\n parsedCache = JSON.parse(readFileSync(OPENCODE_CACHE_PATH, 'utf8')) as OpencodeCacheFile;\n } catch {\n parsedCache = null;\n }\n }\n return parsedCache;\n}\n\n/** Build a model-id → context-window map from OpenCode cache data. Exported for tests. */\nexport function buildContextWindowIndex(cache: OpencodeCacheFile): Map<string, number> {\n const index = new Map<string, number>();\n const allLimits = new Map<string, number[]>();\n\n for (const [providerKey, providerData] of Object.entries(cache)) {\n const models = providerData?.models;\n if (!models) continue;\n for (const [modelId, entry] of Object.entries(models)) {\n const ctx = entry.limit?.context;\n if (typeof ctx !== 'number' || ctx <= 0) continue;\n\n const limits = allLimits.get(modelId) ?? [];\n limits.push(ctx);\n allLimits.set(modelId, limits);\n\n if (CACHE_PROVIDER_PRIORITY.has(providerKey)) {\n index.set(modelId, ctx);\n }\n }\n }\n\n for (const [modelId, limits] of allLimits) {\n if (!index.has(modelId)) {\n index.set(modelId, Math.max(...limits));\n }\n }\n\n return index;\n}\n\nfunction getCacheIndex(): Map<string, number> {\n if (cacheIndex === undefined) {\n const cache = loadOpencodeCache();\n cacheIndex = cache ? buildContextWindowIndex(cache) : new Map();\n }\n return cacheIndex;\n}\n\nexport function contextWindowFromHeuristics(modelId: string): number {\n const cached = heuristicCache.get(modelId);\n if (cached !== undefined) return cached;\n for (const [pattern, size] of HEURISTIC_RULES) {\n if (pattern.test(modelId)) {\n heuristicCache.set(modelId, size);\n return size;\n }\n }\n heuristicCache.set(modelId, DEFAULT_CONTEXT_WINDOW);\n return DEFAULT_CONTEXT_WINDOW;\n}\n\nexport function lookupContextWindow(modelId: string): number {\n return getCacheIndex().get(modelId) ?? contextWindowFromHeuristics(modelId);\n}\n\n/** Prefer an explicit limit.context (or pre-resolved value), else resolve from cache/heuristics. */\nexport function resolveContextWindow(modelId: string, explicit?: number): number {\n if (typeof explicit === 'number' && explicit > 0) return explicit;\n return lookupContextWindow(modelId);\n}\n","// opencode-auth.ts — read OpenCode ~/.local/share/opencode/auth.json for one-time OAuth import\n\nimport { existsSync, readFileSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport interface OpencodeOAuthCredential {\n type: 'oauth';\n access: string;\n refresh: string;\n expires: number;\n accountId?: string;\n enterpriseUrl?: string;\n providerData?: Record<string, unknown>;\n}\n\nexport interface OpencodeWellKnownCredential {\n type: 'wellknown';\n key: string;\n token: string;\n}\n\nexport type OpencodeAuthEntry = OpencodeOAuthCredential | OpencodeWellKnownCredential | string;\n\nexport interface ReadOpencodeAuthResult {\n path: string;\n entries: Record<string, OpencodeAuthEntry>;\n permissionWarning?: string;\n}\n\nexport function resolveOpencodeAuthPath(env: NodeJS.ProcessEnv = process.env): string {\n const dataHome = env['XDG_DATA_HOME'] ?? join(homedir(), '.local', 'share');\n if (process.platform === 'win32') {\n return join(env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming'), 'opencode', 'auth.json');\n }\n return join(dataHome, 'opencode', 'auth.json');\n}\n\nfunction decodeAuthEntry(value: unknown): OpencodeAuthEntry | null {\n if (typeof value === 'string' && value.trim()) return value.trim();\n if (!value || typeof value !== 'object') return null;\n const record = value as Record<string, unknown>;\n if (record['type'] === 'oauth'\n && typeof record['access'] === 'string'\n && typeof record['refresh'] === 'string'\n && typeof record['expires'] === 'number') {\n return {\n type: 'oauth',\n access: record['access'],\n refresh: record['refresh'],\n expires: record['expires'],\n accountId: typeof record['accountId'] === 'string' ? record['accountId'] : undefined,\n enterpriseUrl: typeof record['enterpriseUrl'] === 'string' ? record['enterpriseUrl'] : undefined,\n providerData: record['providerData'] && typeof record['providerData'] === 'object' && !Array.isArray(record['providerData'])\n ? record['providerData'] as Record<string, unknown>\n : undefined,\n };\n }\n if (record['type'] === 'wellknown'\n && typeof record['key'] === 'string'\n && typeof record['token'] === 'string') {\n return { type: 'wellknown', key: record['key'], token: record['token'] };\n }\n return null;\n}\n\n/** Warn when auth.json is group/world readable (OpenCode uses 0600). */\nexport function authFilePermissionWarning(path: string): string | undefined {\n if (!existsSync(path)) return undefined;\n if (process.platform === 'win32') return undefined;\n try {\n const mode = statSync(path).mode & 0o777;\n if (mode & 0o077) {\n return `OpenCode auth file ${path} is readable by others (mode ${mode.toString(8)}). Consider chmod 600.`;\n }\n } catch {\n // ignore\n }\n return undefined;\n}\n\nexport function readOpencodeAuthFile(env: NodeJS.ProcessEnv = process.env): ReadOpencodeAuthResult | null {\n const path = resolveOpencodeAuthPath(env);\n if (!existsSync(path)) return null;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(readFileSync(path, 'utf8'));\n } catch {\n return { path, entries: {}, permissionWarning: authFilePermissionWarning(path) };\n }\n\n const entries: Record<string, OpencodeAuthEntry> = {};\n if (parsed && typeof parsed === 'object') {\n for (const [providerId, value] of Object.entries(parsed as Record<string, unknown>)) {\n const entry = decodeAuthEntry(value);\n if (entry) entries[providerId] = entry;\n }\n }\n\n return {\n path,\n entries,\n permissionWarning: authFilePermissionWarning(path),\n };\n}\n\nexport function isOpencodeOAuth(entry: OpencodeAuthEntry | undefined): entry is OpencodeOAuthCredential {\n return !!entry && typeof entry === 'object' && entry.type === 'oauth';\n}\n\nexport function oauthCredentialToKeychainJson(cred: OpencodeOAuthCredential): string {\n return JSON.stringify(cred);\n}\n","// oauth/types.ts — stored OAuth credential shape (matches OpenCode auth.json)\n\nimport type { OpencodeOAuthCredential } from '../registry/opencode-auth.js';\n\nexport type StoredOAuthCredential = OpencodeOAuthCredential;\n\nexport interface OAuthTokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n /** Non-secret provider metadata discovered during token exchange. */\n providerData?: Record<string, unknown>;\n}\n\nexport function tokensToStoredCredential(\n tokens: OAuthTokenResponse,\n existingRefresh?: string,\n accountId?: string,\n providerData?: Record<string, unknown>,\n): StoredOAuthCredential {\n const mergedProviderData = providerData || tokens.providerData\n ? { ...providerData, ...tokens.providerData }\n : undefined;\n return {\n type: 'oauth',\n access: tokens.access_token,\n refresh: tokens.refresh_token ?? existingRefresh ?? '',\n expires: Date.now() + (tokens.expires_in ?? 3600) * 1000,\n ...(accountId ? { accountId } : {}),\n ...(mergedProviderData ? { providerData: mergedProviderData } : {}),\n };\n}\n\nexport function parseStoredOAuthCredential(raw: string | null): StoredOAuthCredential | null {\n if (!raw?.trim().startsWith('{')) return null;\n try {\n const parsed = JSON.parse(raw) as StoredOAuthCredential;\n if (parsed.type === 'oauth'\n && typeof parsed.access === 'string'\n && typeof parsed.refresh === 'string'\n && typeof parsed.expires === 'number') {\n return parsed;\n }\n } catch {\n // ignore\n }\n return null;\n}\n\nexport const OAUTH_REFRESH_SKEW_MS = 120_000;\n\nexport function oauthCredentialNeedsRefresh(cred: StoredOAuthCredential, skewMs = OAUTH_REFRESH_SKEW_MS): boolean {\n return cred.expires <= Date.now() + Math.max(0, skewMs);\n}\n\n/** JWT exp claim — best-effort; opaque tokens return false (no proactive refresh). */\nexport function accessTokenIsExpiring(token: string | undefined, skewMs = OAUTH_REFRESH_SKEW_MS): boolean {\n if (!token) return false;\n const parts = token.split('.');\n if (parts.length < 2) return false;\n try {\n let payload = parts[1]!.replace(/-/g, '+').replace(/_/g, '/');\n while (payload.length % 4 !== 0) payload += '=';\n const claims = JSON.parse(Buffer.from(payload, 'base64').toString('utf8')) as { exp?: number };\n if (typeof claims.exp !== 'number') return false;\n return claims.exp * 1000 <= Date.now() + Math.max(0, skewMs);\n } catch {\n return false;\n }\n}\n\nexport const NATIVE_OAUTH_PROVIDER_IDS = ['xai', 'xai-oauth', 'openai', 'openai-oauth', 'github-copilot', 'claude-code', 'antigravity', 'cline-pass'] as const;\nexport type NativeOAuthProviderId = typeof NATIVE_OAUTH_PROVIDER_IDS[number];\n\nexport function supportsNativeOAuth(providerId: string): providerId is NativeOAuthProviderId {\n return (NATIVE_OAUTH_PROVIDER_IDS as readonly string[]).includes(providerId);\n}\n\n/** Providers that use Authorization Code + PKCE (browser redirect), not device code polling. */\nexport const BROWSER_REDIRECT_OAUTH_IDS = ['claude-code', 'antigravity'] as const;\nexport type BrowserRedirectOAuthId = typeof BROWSER_REDIRECT_OAUTH_IDS[number];\n\nexport function isBrowserRedirectOAuth(id: string): id is BrowserRedirectOAuthId {\n return (BROWSER_REDIRECT_OAUTH_IDS as readonly string[]).includes(id);\n}\n","// github.ts — native GitHub Copilot OAuth (RFC 8628 device code)\n// Uses the same public client ID as the VS Code Copilot extension.\n// Flow: device code → ghu_ access token → exchange for short-lived Copilot session token.\n// The ghu_ token is stored as the \"refresh token\" and re-exchanged when the Copilot token expires.\n\nimport { positiveSecondsToMs, sleepMs } from './pkce.js';\nimport type { OAuthTokenResponse } from './types.js';\nimport { VERSION } from '../constants.js';\n\n// Public OAuth App client ID used by VS Code GitHub Copilot extension\nconst CLIENT_ID = 'Iv1.b507a08c87ecfe98';\nconst DEVICE_CODE_URL = 'https://github.com/login/device/code';\nconst TOKEN_URL = 'https://github.com/login/oauth/access_token';\nconst COPILOT_TOKEN_URL = 'https://api.github.com/copilot_internal/v2/token';\nconst COPILOT_USER_URL = 'https://api.github.com/copilot_internal/user';\nconst SCOPE = 'copilot';\n\nconst DEVICE_CODE_DEFAULT_INTERVAL_MS = 5_000;\nconst DEVICE_CODE_DEFAULT_EXPIRES_MS = 15 * 60 * 1000; // 15 minutes\nconst OAUTH_POLLING_SAFETY_MARGIN_MS = 1_000;\nconst FREE_COPILOT_SKUS = new Set([\n 'free_limited_copilot',\n 'free_educational_quota',\n 'no_auth_limited_copilot',\n]);\n\nexport interface CopilotAccountSummary {\n login?: string;\n access_type_sku?: string;\n copilot_plan?: string;\n is_free_plan?: boolean;\n lookup_status: 'known' | 'unknown';\n}\n\nexport interface GithubDeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_in?: number;\n interval?: number;\n}\n\nfunction commonHeaders(): Record<string, string> {\n return {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'User-Agent': `relay-ai/${VERSION}`,\n };\n}\n\nexport function classifyCopilotAccount(user: Record<string, unknown>): CopilotAccountSummary {\n const login = typeof user['login'] === 'string' && user['login'].trim() ? user['login'].trim() : undefined;\n const sku = typeof user['access_type_sku'] === 'string' && user['access_type_sku'].trim()\n ? user['access_type_sku'].trim()\n : undefined;\n const plan = typeof user['copilot_plan'] === 'string' && user['copilot_plan'].trim()\n ? user['copilot_plan'].trim()\n : undefined;\n if (!sku && !plan) {\n return {\n ...(login ? { login } : {}),\n lookup_status: 'unknown',\n };\n }\n const isFree = FREE_COPILOT_SKUS.has(sku?.toLowerCase() ?? '') || plan?.toLowerCase() === 'free';\n return {\n ...(login ? { login } : {}),\n ...(sku ? { access_type_sku: sku } : {}),\n ...(plan ? { copilot_plan: plan } : {}),\n is_free_plan: isFree,\n lookup_status: 'known',\n };\n}\n\nexport async function fetchCopilotAccount(ghuToken: string): Promise<CopilotAccountSummary> {\n const response = await fetch(COPILOT_USER_URL, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${ghuToken}`,\n Accept: 'application/json',\n 'User-Agent': `relay-ai/${VERSION}`,\n 'Editor-Version': 'vscode/1.85.1',\n 'X-GitHub-Api-Version': '2025-04-01',\n },\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => '');\n throw new Error(`GitHub Copilot account lookup failed (${response.status})${detail ? `: ${detail}` : ''}`);\n }\n const json = await response.json() as unknown;\n if (!json || typeof json !== 'object' || Array.isArray(json)) {\n throw new Error('GitHub Copilot account lookup returned invalid JSON');\n }\n return classifyCopilotAccount(json as Record<string, unknown>);\n}\n\nexport async function requestGithubDeviceCode(): Promise<GithubDeviceCodeResponse> {\n const response = await fetch(DEVICE_CODE_URL, {\n method: 'POST',\n headers: commonHeaders(),\n body: new URLSearchParams({ client_id: CLIENT_ID, scope: SCOPE }).toString(),\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => '');\n throw new Error(`GitHub device code request failed (${response.status})${detail ? `: ${detail}` : ''}`);\n }\n const json = await response.json() as GithubDeviceCodeResponse;\n if (!json.device_code || !json.user_code || !json.verification_uri) {\n throw new Error('GitHub device code response is missing required fields');\n }\n return json;\n}\n\n/** Exchange a ghu_ GitHub OAuth user token for a short-lived Copilot session token. */\nexport async function exchangeForCopilotToken(ghuToken: string): Promise<OAuthTokenResponse> {\n const response = await fetch(COPILOT_TOKEN_URL, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${ghuToken}`,\n 'User-Agent': `relay-ai/${VERSION}`,\n Accept: 'application/json',\n },\n });\n if (!response.ok) {\n const msg = await response.text().catch(() => '');\n throw new Error(`GitHub Copilot token exchange failed (${response.status})${msg ? `: ${msg}` : ''}`);\n }\n const json = await response.json() as { token?: string; expires_at?: string };\n if (!json.token) {\n throw new Error('GitHub Copilot token exchange response missing token field — is Copilot subscription active?');\n }\n // expires_at is an ISO string; convert to expires_in seconds\n let expiresIn = 1800; // default 30 min\n if (json.expires_at) {\n const expiresMs = new Date(json.expires_at).getTime() - Date.now();\n if (expiresMs > 0) expiresIn = Math.floor(expiresMs / 1000);\n }\n let account: CopilotAccountSummary = { lookup_status: 'unknown' };\n try {\n account = await fetchCopilotAccount(ghuToken);\n } catch {\n // A plan lookup outage must not invalidate an otherwise usable session token.\n }\n return {\n access_token: json.token,\n expires_in: expiresIn,\n providerData: { copilot: account },\n };\n}\n\n/**\n * Refresh: the stored \"refresh token\" is actually the long-lived ghu_ OAuth token.\n * We just re-exchange it for a new short-lived Copilot session token.\n */\nexport async function refreshGithubCopilotToken(ghuToken: string): Promise<OAuthTokenResponse> {\n const copilot = await exchangeForCopilotToken(ghuToken);\n return {\n ...copilot,\n refresh_token: ghuToken, // keep the same ghu_ token as refresh\n };\n}\n\nexport async function pollGithubDeviceCodeToken(\n device: GithubDeviceCodeResponse,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<OAuthTokenResponse> {\n const sleep = opts?.sleep ?? sleepMs;\n const now = opts?.now ?? (() => Date.now());\n const deadline = now() + positiveSecondsToMs(device.expires_in, DEVICE_CODE_DEFAULT_EXPIRES_MS);\n let intervalMs = Math.max(\n positiveSecondsToMs(device.interval, DEVICE_CODE_DEFAULT_INTERVAL_MS),\n 1_000,\n );\n\n while (now() < deadline) {\n const response = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: commonHeaders(),\n body: new URLSearchParams({\n client_id: CLIENT_ID,\n device_code: device.device_code,\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n }).toString(),\n });\n\n const body = await response.json().catch(() => ({}) as Record<string, unknown>) as Record<string, unknown>;\n const error = body['error'] as string | undefined;\n\n if (!error && body['access_token']) {\n const ghuToken = body['access_token'] as string;\n // Exchange ghu_ token for a Copilot session token\n const copilot = await exchangeForCopilotToken(ghuToken);\n return {\n access_token: copilot.access_token,\n refresh_token: ghuToken, // store ghu_ as refresh for re-exchange later\n expires_in: copilot.expires_in,\n providerData: copilot.providerData,\n };\n }\n\n if (error === 'authorization_pending') {\n await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, Math.max(0, deadline - now())));\n continue;\n }\n if (error === 'slow_down') {\n intervalMs += 5_000;\n await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, Math.max(0, deadline - now())));\n continue;\n }\n if (error === 'expired_token') {\n throw new Error('GitHub device code expired — please run relay-ai providers auth github-copilot again');\n }\n throw new Error(`GitHub device authorization failed${error ? `: ${error}` : ''}`);\n }\n throw new Error('GitHub device authorization timed out');\n}\n\nexport async function runGithubDeviceCodeFlow(\n onDeviceCode: (info: { url: string; userCode: string }) => void,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<OAuthTokenResponse> {\n const device = await requestGithubDeviceCode();\n onDeviceCode({ url: device.verification_uri, userCode: device.user_code });\n return pollGithubDeviceCodeToken(device, opts);\n}\n","// xai.ts — native xAI SuperGrok OAuth (RFC 8628 device code, ported from OpenCode)\n\nimport { positiveSecondsToMs, sleepMs } from './pkce.js';\nimport type { OAuthTokenResponse } from './types.js';\nimport { VERSION } from '../constants.js';\nimport { postOAuthRefresh } from './refresh-http.js';\n\nconst CLIENT_ID = 'b1a00492-073a-47ea-816f-4c329264a828';\nconst TOKEN_URL = 'https://auth.x.ai/oauth2/token';\nconst DEVICE_AUTHORIZATION_URL = 'https://auth.x.ai/oauth2/device/code';\nconst DEVICE_CODE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';\nconst SCOPE = 'openid profile email offline_access grok-cli:access api:access';\n\nconst DEVICE_CODE_DEFAULT_INTERVAL_MS = 5_000;\nconst DEVICE_CODE_MIN_INTERVAL_MS = 1_000;\nconst DEVICE_CODE_SLOW_DOWN_INCREMENT_MS = 5_000;\nconst DEVICE_CODE_DEFAULT_EXPIRES_MS = 5 * 60 * 1000;\nconst OAUTH_POLLING_SAFETY_MARGIN_MS = 3_000;\n\nexport interface XaiDeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete?: string;\n expires_in?: number;\n interval?: number;\n}\n\nfunction authHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n 'User-Agent': `relay-ai/${VERSION}`,\n };\n}\n\nexport async function requestXaiDeviceCode(): Promise<XaiDeviceCodeResponse> {\n const response = await fetch(DEVICE_AUTHORIZATION_URL, {\n method: 'POST',\n headers: authHeaders(),\n body: new URLSearchParams({\n client_id: CLIENT_ID,\n scope: SCOPE,\n }).toString(),\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => '');\n throw new Error(`xAI device code request failed (${response.status})${detail ? `: ${detail}` : ''}`);\n }\n const json = await response.json() as XaiDeviceCodeResponse;\n if (!json.device_code || !json.user_code || !json.verification_uri) {\n throw new Error('xAI device code response is missing required fields');\n }\n return json;\n}\n\nexport async function pollXaiDeviceCodeToken(\n device: XaiDeviceCodeResponse,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<OAuthTokenResponse> {\n const sleep = opts?.sleep ?? sleepMs;\n const now = opts?.now ?? (() => Date.now());\n const deadline = now() + positiveSecondsToMs(device.expires_in, DEVICE_CODE_DEFAULT_EXPIRES_MS);\n let intervalMs = Math.max(\n positiveSecondsToMs(device.interval, DEVICE_CODE_DEFAULT_INTERVAL_MS),\n DEVICE_CODE_MIN_INTERVAL_MS,\n );\n\n while (now() < deadline) {\n const response = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: authHeaders(),\n body: new URLSearchParams({\n grant_type: DEVICE_CODE_GRANT_TYPE,\n client_id: CLIENT_ID,\n device_code: device.device_code,\n }).toString(),\n });\n if (response.ok) return response.json() as Promise<OAuthTokenResponse>;\n\n const body = await response.json().catch(() => ({})) as { error?: string };\n const remaining = Math.max(0, deadline - now());\n if (body.error === 'authorization_pending') {\n await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, remaining));\n continue;\n }\n if (body.error === 'slow_down') {\n intervalMs += DEVICE_CODE_SLOW_DOWN_INCREMENT_MS;\n await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, remaining));\n continue;\n }\n throw new Error(`xAI device authorization failed${body.error ? `: ${body.error}` : ''}`);\n }\n throw new Error('xAI device authorization timed out');\n}\n\nexport async function refreshXaiAccessToken(refreshToken: string): Promise<OAuthTokenResponse> {\n return postOAuthRefresh(\n TOKEN_URL,\n new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: CLIENT_ID,\n }),\n {\n contentType: 'form',\n errorPrefix: 'xAI token refresh failed',\n includeStatus: true,\n includeBody: true,\n headers: authHeaders(),\n },\n );\n}\n\nexport async function runXaiDeviceCodeFlow(\n onDeviceCode: (info: { url: string; userCode: string }) => void,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<OAuthTokenResponse> {\n const device = await requestXaiDeviceCode();\n onDeviceCode({\n url: device.verification_uri_complete ?? device.verification_uri,\n userCode: device.user_code,\n });\n return pollXaiDeviceCodeToken(device, opts);\n}\n","// src/oauth/claude-code.ts — Authorization Code + PKCE flow for Claude Code OAuth.\n// Client ID is the public PKCE credential shipped in the Claude Code CLI binary.\n\nimport { randomBytes } from 'node:crypto';\nimport open from 'open';\nimport { generatePkce, generateOAuthState } from './pkce.js';\nimport type { OAuthTokenResponse } from './types.js';\nimport { postOAuthRefresh } from './refresh-http.js';\n\nexport const CLAUDE_CODE_CLIENT_ID =\n process.env.CLAUDE_OAUTH_CLIENT_ID ?? '9d1c250a-e61b-44d9-88ed-5944d1962f5e';\n\nconst AUTHORIZE_URL = 'https://claude.ai/oauth/authorize';\nconst TOKEN_URL = 'https://api.anthropic.com/v1/oauth/token';\nconst REDIRECT_URI =\n process.env.CLAUDE_CODE_REDIRECT_URI ?? 'https://platform.claude.com/oauth/code/callback';\nconst SCOPES =\n 'org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers';\n\n// Pinned to a captured claude-cli release — bump when Anthropic updates.\nexport const CLAUDE_CODE_CLI_VERSION = '2.1.195';\n\nexport interface ClaudeCodePkceParams {\n authUrl: string;\n codeVerifier: string;\n oauthState: string;\n redirectUri: string;\n}\n\nexport async function buildClaudeCodeAuthUrl(redirectUri = REDIRECT_URI): Promise<ClaudeCodePkceParams> {\n const { verifier, challenge } = await generatePkce();\n const state = generateOAuthState();\n const params = new URLSearchParams({\n code: 'true',\n client_id: CLAUDE_CODE_CLIENT_ID,\n response_type: 'code',\n redirect_uri: redirectUri,\n scope: SCOPES,\n code_challenge: challenge,\n code_challenge_method: 'S256',\n state,\n // Forces fresh auth — prevents session takeover that invalidates previous refresh tokens.\n prompt: 'login',\n });\n return { authUrl: `${AUTHORIZE_URL}?${params}`, codeVerifier: verifier, oauthState: state, redirectUri };\n}\n\nexport async function exchangeClaudeCodeToken(\n code: string,\n codeVerifier: string,\n redirectUri: string,\n state: string,\n): Promise<OAuthTokenResponse> {\n // Anthropic may return code as `authCode#stateValue` — split if needed.\n let authCode = extractClaudeAuthCode(code);\n let codeState = state;\n if (authCode.includes('#')) {\n const idx = authCode.indexOf('#');\n codeState = authCode.slice(idx + 1) || state;\n authCode = authCode.slice(0, idx);\n }\n\n const res = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Accept: 'application/json' },\n body: JSON.stringify({\n code: authCode,\n state: codeState,\n grant_type: 'authorization_code',\n client_id: CLAUDE_CODE_CLIENT_ID,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n }),\n });\n if (!res.ok) throw new Error(`Claude Code token exchange failed: ${await res.text()}`);\n return res.json() as Promise<OAuthTokenResponse>;\n}\n\nexport function extractClaudeAuthCode(input: string): string {\n const trimmed = input.trim();\n try {\n const parsed = new URL(trimmed);\n return parsed.searchParams.get('code') ?? trimmed;\n } catch {\n if (trimmed.startsWith('?') || trimmed.includes('code=')) {\n const query = trimmed.startsWith('?') ? trimmed.slice(1) : trimmed;\n return new URLSearchParams(query).get('code') ?? trimmed;\n }\n return trimmed;\n }\n}\n\nexport async function refreshClaudeCodeToken(refreshToken: string): Promise<OAuthTokenResponse> {\n return postOAuthRefresh(\n TOKEN_URL,\n {\n grant_type: 'refresh_token',\n client_id: CLAUDE_CODE_CLIENT_ID,\n refresh_token: refreshToken,\n },\n {\n contentType: 'json',\n errorPrefix: 'Claude Code token refresh failed',\n includeBody: true,\n },\n );\n}\n\nexport interface ClaudeBootstrapInfo {\n accountId?: string;\n email?: string;\n organizationId?: string;\n organizationName?: string;\n plan?: string;\n}\n\nexport async function fetchClaudeBootstrap(accessToken: string): Promise<ClaudeBootstrapInfo> {\n try {\n const res = await fetch('https://api.anthropic.com/api/claude_cli/bootstrap', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n Accept: 'application/json',\n 'User-Agent': `claude-cli/${CLAUDE_CODE_CLI_VERSION} (external, cli)`,\n 'anthropic-beta': 'oauth-2025-04-20',\n },\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) return {};\n const data = (await res.json()) as Record<string, unknown>;\n const acct = data.oauth_account as Record<string, unknown> | undefined;\n if (!acct) return {};\n return {\n accountId: typeof acct.account_uuid === 'string' ? acct.account_uuid : undefined,\n email: typeof acct.account_email === 'string' ? acct.account_email : undefined,\n organizationId: typeof acct.organization_uuid === 'string' ? acct.organization_uuid : undefined,\n organizationName: typeof acct.organization_name === 'string' ? acct.organization_name : undefined,\n plan: typeof acct.organization_rate_limit_tier === 'string' ? acct.organization_rate_limit_tier : undefined,\n };\n } catch {\n return {};\n }\n}\n\n/** Generate a new cliUserID — created once at provisioning and persisted in providerData. */\nexport function generateCliUserID(): string {\n return randomBytes(32).toString('hex');\n}\n\n/** Full CLI PKCE flow: opens browser, accepts Anthropic's returned code, exchanges it. */\nexport async function runClaudeCodeOAuthFlow(\n onAuthUrl: (url: string) => void,\n readAuthCode: () => Promise<string>,\n): Promise<{ tokens: OAuthTokenResponse; bootstrap: ClaudeBootstrapInfo }> {\n const { authUrl, codeVerifier, oauthState, redirectUri } = await buildClaudeCodeAuthUrl();\n onAuthUrl(authUrl);\n open(authUrl).catch(() => {});\n const code = (await readAuthCode()).trim();\n if (!code) throw new Error('No authorization code received from Anthropic');\n const tokens = await exchangeClaudeCodeToken(code, codeVerifier, redirectUri, oauthState);\n const bootstrap = await fetchClaudeBootstrap(tokens.access_token);\n return { tokens, bootstrap };\n}\n\nexport interface ClaudeCodeModelEntry {\n id: string;\n displayName: string;\n maxInputTokens?: number;\n maxTokens?: number;\n}\n\nexport async function fetchClaudeCodeModels(accessToken: string): Promise<ClaudeCodeModelEntry[]> {\n const res = await fetch('https://api.anthropic.com/v1/models', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'anthropic-version': '2023-06-01',\n Accept: 'application/json',\n 'User-Agent': `claude-cli/${CLAUDE_CODE_CLI_VERSION} (external, cli)`,\n },\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) {\n throw new Error(`Claude Code model discovery failed (HTTP ${res.status}): ${await res.text().catch(() => '')}`);\n }\n const body = (await res.json()) as { data?: Array<Record<string, unknown>> };\n const entries = (body.data ?? [])\n .filter((m): m is Record<string, unknown> & { id: string } =>\n typeof m.id === 'string' && m.id.length > 0)\n .map(m => ({\n id: m.id as string,\n displayName: (typeof m.display_name === 'string' ? m.display_name : m.id) as string,\n maxInputTokens: typeof m.max_input_tokens === 'number' ? m.max_input_tokens : undefined,\n maxTokens: typeof m.max_tokens === 'number' ? m.max_tokens : undefined,\n }));\n if (entries.length === 0) {\n throw new Error('Claude Code model discovery returned no models');\n }\n return entries;\n}\n\n/** For the GUI: complete token exchange given code received via /oauth/callback. */\nexport async function completeClaudeCodeExchange(\n code: string,\n codeVerifier: string,\n oauthState: string,\n redirectUri: string,\n): Promise<{ tokens: OAuthTokenResponse; bootstrap: ClaudeBootstrapInfo }> {\n const tokens = await exchangeClaudeCodeToken(code, codeVerifier, redirectUri, oauthState);\n const bootstrap = await fetchClaudeBootstrap(tokens.access_token);\n return { tokens, bootstrap };\n}\n\n/** Redirect URI for the GUI callback (port extracted from Host header). */\nexport function guiCallbackRedirectUri(host: string): string {\n return `http://${host}/oauth/callback`;\n}\n","// src/oauth/antigravity-oauth.ts — Authorization Code + PKCE flow for Antigravity\n// (Google Cloud Code Assist). Client credentials are the public values shipped in\n// the Antigravity CLI binary (PKCE — not secrets per RFC 8252 / Google docs).\n\nimport open from 'open';\nimport { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join as pathJoin } from 'node:path';\nimport { generatePkce, generateOAuthState } from './pkce.js';\nimport { startCallbackServer } from './callback-server.js';\nimport type { OAuthTokenResponse } from './types.js';\nimport { postOAuthRefresh } from './refresh-http.js';\n\nconst DEFAULT_ANTIGRAVITY_CLIENT_ID = ['107100606059', '1-tmhssin2h2', '1lcre235vtol', 'ojh4g403ep.a', 'pps.googleus', 'ercontent.co', 'm'].join('');\nconst DEFAULT_ANTIGRAVITY_CLIENT_SECRET = ['GOCS', 'PX-K', '58FW', 'R486', 'LdLJ', '1mLB', '8sXC', '4z6q', 'DAf'].join('');\n\nexport const ANTIGRAVITY_CLIENT_ID =\n process.env.ANTIGRAVITY_OAUTH_CLIENT_ID ?? DEFAULT_ANTIGRAVITY_CLIENT_ID;\n\nexport const ANTIGRAVITY_CLIENT_SECRET =\n process.env.ANTIGRAVITY_OAUTH_CLIENT_SECRET ?? DEFAULT_ANTIGRAVITY_CLIENT_SECRET;\n\nconst AUTHORIZE_URL = 'https://accounts.google.com/o/oauth2/v2/auth';\nconst TOKEN_URL = 'https://oauth2.googleapis.com/token';\nconst USER_INFO_URL = 'https://www.googleapis.com/oauth2/v1/userinfo';\n\nconst SCOPES = [\n 'openid',\n 'https://www.googleapis.com/auth/cloud-platform',\n 'https://www.googleapis.com/auth/userinfo.email',\n 'https://www.googleapis.com/auth/userinfo.profile',\n 'https://www.googleapis.com/auth/cclog',\n 'https://www.googleapis.com/auth/experimentsandconfigs',\n].join(' ');\n\n// Pinned to Antigravity-Manager version used for header fingerprinting.\nconst ANTIGRAVITY_VERSION = '4.2.0';\nexport const ANTIGRAVITY_USER_AGENT = `vscode/1.X.X (Antigravity/${ANTIGRAVITY_VERSION})`;\nconst ANTIGRAVITY_METADATA = { ideType: 'ANTIGRAVITY' };\n\n// Cloud Code Assist base URLs — tried in order, first success wins.\nexport const ANTIGRAVITY_BASE_URLS = [\n 'https://daily-cloudcode-pa.googleapis.com',\n 'https://cloudcode-pa.googleapis.com',\n 'https://daily-cloudcode-pa.sandbox.googleapis.com',\n];\nexport const ANTIGRAVITY_API_VERSION = 'v1internal';\n\nexport interface AntigravityPkceParams {\n authUrl: string;\n codeVerifier: string;\n oauthState: string;\n redirectUri: string;\n}\n\nexport async function buildAntigravityAuthUrl(\n redirectUri: string,\n): Promise<AntigravityPkceParams> {\n const { verifier, challenge } = await generatePkce();\n const state = generateOAuthState();\n const params = new URLSearchParams({\n client_id: ANTIGRAVITY_CLIENT_ID,\n response_type: 'code',\n redirect_uri: redirectUri,\n scope: SCOPES,\n state,\n access_type: 'offline',\n prompt: 'consent',\n code_challenge: challenge,\n code_challenge_method: 'S256',\n });\n return { authUrl: `${AUTHORIZE_URL}?${params}`, codeVerifier: verifier, oauthState: state, redirectUri };\n}\n\nexport async function exchangeAntigravityToken(\n code: string,\n codeVerifier: string,\n redirectUri: string,\n): Promise<OAuthTokenResponse> {\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: ANTIGRAVITY_CLIENT_ID,\n client_secret: ANTIGRAVITY_CLIENT_SECRET,\n code,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n });\n\n const res = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n 'User-Agent': ANTIGRAVITY_USER_AGENT,\n },\n body,\n });\n if (!res.ok) throw new Error(`Antigravity token exchange failed: ${await res.text()}`);\n return res.json() as Promise<OAuthTokenResponse>;\n}\n\nexport async function refreshAntigravityToken(refreshToken: string): Promise<OAuthTokenResponse> {\n return postOAuthRefresh(\n TOKEN_URL,\n new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: ANTIGRAVITY_CLIENT_ID,\n client_secret: ANTIGRAVITY_CLIENT_SECRET,\n refresh_token: refreshToken,\n }),\n {\n contentType: 'form',\n errorPrefix: 'Antigravity token refresh failed',\n includeBody: true,\n },\n );\n}\n\nexport interface AntigravityUserInfo {\n email?: string;\n name?: string;\n}\n\nasync function fetchUserInfo(accessToken: string): Promise<AntigravityUserInfo> {\n try {\n const res = await fetch(`${USER_INFO_URL}?alt=json`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) return {};\n const data = (await res.json()) as Record<string, unknown>;\n return {\n email: typeof data.email === 'string' ? data.email : undefined,\n name: typeof data.name === 'string' ? data.name : undefined,\n };\n } catch {\n return {};\n }\n}\n\nfunction apiHeaders(accessToken: string): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': ANTIGRAVITY_USER_AGENT,\n };\n}\n\nasync function fetchFirstOk(\n paths: string[],\n init: RequestInit,\n): Promise<Response> {\n let lastErr: unknown;\n for (const url of paths) {\n try {\n const res = await fetch(url, init);\n if (res.ok) return res;\n lastErr = new Error(`${res.status} ${await res.text()}`);\n } catch (err) {\n lastErr = err;\n }\n }\n throw lastErr ?? new Error('All Antigravity endpoints failed');\n}\n\n// ── Onboarding tier extraction — adapted from OmniRoute codeAssistSubscription.ts (MIT) ──\n\ntype JsonRecord = Record<string, unknown>;\n\nfunction toRecord(v: unknown): JsonRecord {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as JsonRecord) : {};\n}\n\nfunction pickTierId(tier: unknown): string | null {\n const v = toRecord(tier).id;\n return typeof v === 'string' && v.trim() ? v.trim() : null;\n}\n\nfunction findDefaultAllowedTier(sub: JsonRecord): JsonRecord | null {\n if (!Array.isArray(sub.allowedTiers)) return null;\n for (const t of sub.allowedTiers) {\n const tier = toRecord(t);\n if (tier.isDefault) return tier;\n }\n return null;\n}\n\nexport function resolveAntigravityOnboardTierId(data: unknown): string {\n const sub = toRecord(data);\n const hasIneligible = Array.isArray(sub.ineligibleTiers) && sub.ineligibleTiers.length > 0;\n if (!hasIneligible) {\n const current = pickTierId(sub.currentTier);\n if (current) return current;\n }\n const def = findDefaultAllowedTier(sub);\n if (def) {\n const defId = pickTierId(def);\n if (defId) return defId;\n }\n const paid = pickTierId(sub.paidTier);\n if (paid) return paid;\n return pickTierId(sub.currentTier) ?? 'legacy-tier';\n}\n\n// ── Cloud Code Assist bootstrap ────────────────────────────────────────────\n\nexport interface AntigravityBootstrap {\n projectId: string;\n tierId: string;\n}\n\nasync function loadCodeAssist(accessToken: string): Promise<AntigravityBootstrap> {\n const endpoints = ANTIGRAVITY_BASE_URLS.map(b => `${b}/${ANTIGRAVITY_API_VERSION}:loadCodeAssist`);\n\n const res = await fetchFirstOk(endpoints, {\n method: 'POST',\n headers: apiHeaders(accessToken),\n body: JSON.stringify({ metadata: ANTIGRAVITY_METADATA }),\n });\n\n const data = (await res.json()) as Record<string, unknown>;\n let projectId = data.cloudaicompanionProject;\n if (typeof projectId === 'object' && projectId !== null) {\n projectId = (projectId as Record<string, unknown>).id ?? '';\n }\n\n return {\n projectId: typeof projectId === 'string' ? projectId : '',\n tierId: resolveAntigravityOnboardTierId(data),\n };\n}\n\nasync function onboardUser(\n accessToken: string,\n tierId: string,\n maxAttempts = 10,\n): Promise<string> {\n const endpoints = ANTIGRAVITY_BASE_URLS.map(b => `${b}/${ANTIGRAVITY_API_VERSION}:onboardUser`);\n let finalProjectId = '';\n\n for (let i = 0; i < maxAttempts; i++) {\n const res = await fetchFirstOk(endpoints, {\n method: 'POST',\n headers: apiHeaders(accessToken),\n body: JSON.stringify({ tier_id: tierId, metadata: ANTIGRAVITY_METADATA }),\n });\n\n const result = (await res.json()) as Record<string, unknown>;\n if (result.done === true) {\n const p = result.response ? (result.response as Record<string, unknown>).cloudaicompanionProject : undefined;\n if (typeof p === 'string') finalProjectId = p.trim();\n else if (p && typeof p === 'object') finalProjectId = String((p as Record<string, unknown>).id ?? '') || finalProjectId;\n break;\n }\n\n if (i < maxAttempts - 1) await new Promise(r => setTimeout(r, 5000));\n }\n\n return finalProjectId;\n}\n\nexport interface AntigravityOAuthResult {\n tokens: OAuthTokenResponse;\n userInfo: AntigravityUserInfo;\n projectId: string;\n tierId: string;\n}\n\n/** Read the project ID the AGY CLI already set up on this machine, as a fallback\n * when loadCodeAssist fails with a fresh OAuth token. */\nfunction readAgyProjectId(): string {\n try {\n const cache = pathJoin(homedir(), '.gemini', 'antigravity-cli', 'cache', 'projects.json');\n const data = JSON.parse(readFileSync(cache, 'utf8')) as Record<string, string>;\n // Prefer the home-directory project (most general), then any other entry.\n return data[homedir()] ?? Object.values(data)[0] ?? '';\n } catch {\n return '';\n }\n}\n\n/** Shared post-exchange bootstrap: fetch user info + loadCodeAssist + onboardUser.\n * Bootstrap failures are best-effort — auth succeeds even if project setup fails.\n * Falls back to reading the AGY CLI's stored projectId if loadCodeAssist fails. */\nasync function runBootstrap(\n tokens: OAuthTokenResponse,\n): Promise<AntigravityOAuthResult> {\n const [userInfoResult, bootstrapResult] = await Promise.allSettled([\n fetchUserInfo(tokens.access_token),\n loadCodeAssist(tokens.access_token),\n ]);\n\n const userInfo = userInfoResult.status === 'fulfilled' ? userInfoResult.value : {};\n let projectId = bootstrapResult.status === 'fulfilled' ? bootstrapResult.value.projectId : '';\n const tierId = bootstrapResult.status === 'fulfilled' ? bootstrapResult.value.tierId : 'free-tier';\n\n const finalProjectId = await onboardUser(tokens.access_token, tierId, 3).catch(() => '');\n if (finalProjectId) projectId = finalProjectId;\n\n if (!projectId && tierId !== 'free-tier') {\n const freeTierProjectId = await onboardUser(tokens.access_token, 'free-tier', 3).catch(() => '');\n if (freeTierProjectId) projectId = freeTierProjectId;\n }\n\n // Google bootstrap failed or returned no project — fall back to the AGY CLI's stored project.\n if (!projectId) {\n projectId = readAgyProjectId();\n }\n\n return { tokens, userInfo, projectId, tierId };\n}\n\n/** Full CLI PKCE flow: starts local callback server, opens browser, exchanges code. */\nexport async function runAntigravityOAuthFlow(\n onAuthUrl: (url: string) => void,\n): Promise<AntigravityOAuthResult> {\n const server = await startCallbackServer();\n try {\n const { authUrl, codeVerifier, redirectUri } = await buildAntigravityAuthUrl(server.redirectUri);\n onAuthUrl(authUrl);\n open(authUrl).catch(() => {});\n const { code } = await server.waitForCallback();\n if (!code) throw new Error('No authorization code received from Google');\n const tokens = await exchangeAntigravityToken(code, codeVerifier, redirectUri);\n return runBootstrap(tokens);\n } finally {\n server.close();\n }\n}\n\n/** For the GUI: complete token exchange + bootstrap given code from /oauth/callback. */\nexport async function completeAntigravityExchange(\n code: string,\n codeVerifier: string,\n redirectUri: string,\n): Promise<AntigravityOAuthResult> {\n const tokens = await exchangeAntigravityToken(code, codeVerifier, redirectUri);\n return runBootstrap(tokens);\n}\n","// src/oauth/callback-server.ts — CLI fallback local callback server for PKCE OAuth flows.\n// Primary path: the GUI server handles /oauth/callback when the UI is open.\n// This is only used when running `relay-ai providers auth <provider>` without the GUI.\n\nimport http from 'node:http';\n\nexport interface CallbackParams {\n code: string;\n state: string;\n error?: string;\n}\n\nexport interface CallbackServer {\n port: number;\n redirectUri: string;\n waitForCallback(timeoutMs?: number): Promise<CallbackParams>;\n close(): void;\n}\n\nconst SUCCESS_HTML = `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Authorized</title></head>\n<body style=\"font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0\">\n<div style=\"text-align:center;padding:2rem;background:#fff;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,.1)\">\n<div style=\"color:#22c55e;font-size:2.5rem\">&#10003;</div>\n<h1 style=\"margin:.5rem 0\">Authentication successful</h1>\n<p style=\"color:#666\">You can close this tab and return to the terminal.</p>\n</div></body></html>`;\n\nexport function startCallbackServer(): Promise<CallbackServer> {\n return new Promise((resolve, reject) => {\n let codeResolve: ((p: CallbackParams) => void) | undefined;\n let codeReject: ((e: Error) => void) | undefined;\n\n const server = http.createServer((req, res) => {\n const u = new URL(req.url ?? '/', 'http://localhost');\n if (u.pathname !== '/callback' && u.pathname !== '/oauth/callback') {\n res.writeHead(404); res.end(); return;\n }\n const code = u.searchParams.get('code') ?? '';\n const state = u.searchParams.get('state') ?? '';\n const error = u.searchParams.get('error') ?? '';\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(SUCCESS_HTML);\n codeResolve?.({ code, state, error: error || undefined });\n });\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address() as { port: number };\n const port = addr.port;\n resolve({\n port,\n redirectUri: `http://127.0.0.1:${port}/callback`,\n waitForCallback(timeoutMs = 300_000) {\n return new Promise<CallbackParams>((res, rej) => {\n codeResolve = res;\n codeReject = rej;\n setTimeout(\n () => rej(new Error('OAuth timeout — browser closed without completing sign-in')),\n timeoutMs,\n );\n });\n },\n close() { server.close(); codeReject?.(new Error('Server closed')); },\n });\n });\n\n server.on('error', reject);\n });\n}\n","import { CLINE_PASS_REFRESH_URL, CLINE_PASS_REGISTER_URL } from '../cline-pass.js';\nimport { positiveSecondsToMs, sleepMs } from './pkce.js';\nimport type { OAuthTokenResponse } from './types.js';\n\nconst WORKOS_CLIENT_ID = 'client_01K3A541FN8TA3EPPHTD2325AR';\nconst WORKOS_DEVICE_URL = 'https://api.workos.com/user_management/authorize/device';\nconst WORKOS_TOKEN_URL = 'https://api.workos.com/user_management/authenticate';\nconst DEVICE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';\nconst DEFAULT_INTERVAL_MS = 5_000;\nconst SLOW_DOWN_INCREMENT_MS = 1_000;\nconst DEFAULT_EXPIRES_MS = 10 * 60 * 1000;\n\nexport interface ClinePassDeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete?: string;\n expires_in?: number;\n interval?: number;\n}\n\nexport interface ClinePassOAuthResult {\n tokens: OAuthTokenResponse;\n accountId?: string;\n providerData?: Record<string, unknown>;\n}\n\ninterface ClineAuthData {\n accessToken?: unknown;\n refreshToken?: unknown;\n expiresAt?: unknown;\n userInfo?: unknown;\n}\n\nfunction formHeaders(): Record<string, string> {\n return {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n}\n\nfunction jsonHeaders(): Record<string, string> {\n return {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n };\n}\n\nfunction expiresInFromIso(expiresAt: unknown): number {\n if (typeof expiresAt !== 'string') throw new Error('ClinePass response is missing a valid expiresAt');\n const timestamp = Date.parse(expiresAt);\n if (!Number.isFinite(timestamp)) throw new Error('ClinePass response is missing a valid expiresAt');\n return Math.max(1, Math.floor((timestamp - Date.now()) / 1000));\n}\n\nfunction toOAuthResult(data: ClineAuthData): ClinePassOAuthResult {\n if (typeof data.accessToken !== 'string' || !data.accessToken) {\n throw new Error('ClinePass response is missing accessToken');\n }\n const userInfo = data.userInfo && typeof data.userInfo === 'object' && !Array.isArray(data.userInfo)\n ? data.userInfo as Record<string, unknown>\n : undefined;\n const accountId = typeof userInfo?.clineUserId === 'string' ? userInfo.clineUserId : undefined;\n return {\n tokens: {\n access_token: data.accessToken,\n ...(typeof data.refreshToken === 'string' ? { refresh_token: data.refreshToken } : {}),\n expires_in: expiresInFromIso(data.expiresAt),\n ...(userInfo ? { providerData: userInfo } : {}),\n },\n ...(accountId ? { accountId } : {}),\n ...(userInfo ? { providerData: userInfo } : {}),\n };\n}\n\nasync function readError(response: Response): Promise<string> {\n const text = await response.text().catch(() => '');\n if (!text) return `HTTP ${response.status}`;\n try {\n const parsed = JSON.parse(text) as { error?: unknown; message?: unknown };\n const detail = typeof parsed.error === 'string' ? parsed.error : typeof parsed.message === 'string' ? parsed.message : '';\n return detail || `HTTP ${response.status}`;\n } catch {\n return text.slice(0, 120);\n }\n}\n\nexport async function requestClinePassDeviceCode(): Promise<ClinePassDeviceCodeResponse> {\n const response = await fetch(WORKOS_DEVICE_URL, {\n method: 'POST',\n headers: formHeaders(),\n body: new URLSearchParams({ client_id: WORKOS_CLIENT_ID }).toString(),\n });\n if (!response.ok) throw new Error(`ClinePass device code request failed (${response.status})`);\n const json = await response.json() as ClinePassDeviceCodeResponse;\n if (!json.device_code || !json.user_code || !json.verification_uri) {\n throw new Error('ClinePass device code response is missing required fields');\n }\n return json;\n}\n\nexport async function registerClinePassTokens(\n accessToken: string,\n refreshToken: string,\n): Promise<ClinePassOAuthResult> {\n const response = await fetch(CLINE_PASS_REGISTER_URL, {\n method: 'POST',\n headers: jsonHeaders(),\n body: JSON.stringify({ accessToken, refreshToken }),\n });\n if (!response.ok) throw new Error(`ClinePass registration failed (${response.status})`);\n const body = await response.json() as { success?: unknown; data?: ClineAuthData; error?: unknown; message?: unknown };\n if (body.success !== true || !body.data) {\n const detail = typeof body.error === 'string' ? body.error : typeof body.message === 'string' ? body.message : 'unsuccessful response';\n throw new Error(`ClinePass registration failed: ${detail}`);\n }\n return toOAuthResult(body.data);\n}\n\nexport async function pollClinePassDeviceCode(\n device: ClinePassDeviceCodeResponse,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<ClinePassOAuthResult> {\n const sleep = opts?.sleep ?? sleepMs;\n const now = opts?.now ?? (() => Date.now());\n const deadline = now() + positiveSecondsToMs(device.expires_in, DEFAULT_EXPIRES_MS);\n let intervalMs = Math.max(positiveSecondsToMs(device.interval, DEFAULT_INTERVAL_MS), 1_000);\n\n while (now() < deadline) {\n const response = await fetch(WORKOS_TOKEN_URL, {\n method: 'POST',\n headers: formHeaders(),\n body: new URLSearchParams({\n grant_type: DEVICE_GRANT_TYPE,\n client_id: WORKOS_CLIENT_ID,\n device_code: device.device_code,\n }).toString(),\n });\n if (response.ok) {\n const workos = await response.json() as { access_token?: string; refresh_token?: string };\n if (!workos.access_token || !workos.refresh_token) {\n throw new Error('ClinePass WorkOS response is missing required tokens');\n }\n return registerClinePassTokens(workos.access_token, workos.refresh_token);\n }\n\n const body = await response.json().catch(() => ({})) as { error?: string };\n const remaining = Math.max(0, deadline - now());\n if (body.error === 'authorization_pending') {\n await sleep(Math.min(intervalMs, remaining));\n continue;\n }\n if (body.error === 'slow_down') {\n intervalMs += SLOW_DOWN_INCREMENT_MS;\n await sleep(Math.min(intervalMs, remaining));\n continue;\n }\n throw new Error(`ClinePass device authorization failed${body.error ? `: ${body.error}` : ''}`);\n }\n throw new Error('ClinePass device authorization timed out');\n}\n\nexport async function runClinePassDeviceCodeFlow(\n onDeviceCode: (info: { url: string; userCode: string }) => void,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<ClinePassOAuthResult> {\n const device = await requestClinePassDeviceCode();\n onDeviceCode({\n url: device.verification_uri_complete ?? device.verification_uri,\n userCode: device.user_code,\n });\n return pollClinePassDeviceCode(device, opts);\n}\n\nexport async function refreshClinePassAccessToken(refreshToken: string): Promise<OAuthTokenResponse> {\n const response = await fetch(CLINE_PASS_REFRESH_URL, {\n method: 'POST',\n headers: jsonHeaders(),\n body: JSON.stringify({ refreshToken, grantType: 'refresh_token' }),\n });\n if (!response.ok) {\n const detail = await readError(response);\n throw new Error(`ClinePass token refresh failed (${response.status}): ${detail}`);\n }\n const body = await response.json() as { success?: unknown; data?: ClineAuthData; error?: unknown; message?: unknown };\n if (body.success !== true || !body.data) {\n const detail = typeof body.error === 'string' ? body.error : typeof body.message === 'string' ? body.message : 'unsuccessful response';\n throw new Error(`ClinePass token refresh failed: ${detail}`);\n }\n return toOAuthResult(body.data).tokens;\n}\n","// oauth/refresh.ts — refresh OAuth tokens before inference\n\nimport { refreshOpenAiAccessToken } from './openai.js';\nimport { refreshGithubCopilotToken } from './github.js';\nimport type { StoredOAuthCredential } from './types.js';\nimport { accessTokenIsExpiring, NATIVE_OAUTH_PROVIDER_IDS, oauthCredentialNeedsRefresh, tokensToStoredCredential } from './types.js';\nimport { refreshXaiAccessToken } from './xai.js';\nimport { refreshClaudeCodeToken } from './claude-code.js';\nimport { refreshAntigravityToken } from './antigravity-oauth.js';\nimport { refreshClinePassAccessToken } from './cline-pass.js';\n\nexport function oauthCredentialShouldRefresh(\n cred: StoredOAuthCredential,\n providerId: string,\n): boolean {\n if (oauthCredentialNeedsRefresh(cred)) return true;\n // All native OAuth providers use short-lived access tokens — check expiry proactively\n if ((NATIVE_OAUTH_PROVIDER_IDS as readonly string[]).includes(providerId) && accessTokenIsExpiring(cred.access)) return true;\n return false;\n}\n\nexport async function refreshStoredOAuthCredential(\n providerId: string,\n cred: StoredOAuthCredential,\n): Promise<StoredOAuthCredential> {\n if (!cred.refresh) {\n throw new Error(`${providerId}: OAuth refresh token missing — run relay-ai providers auth ${providerId}`);\n }\n\n let tokens;\n if (providerId === 'openai' || providerId === 'openai-oauth') {\n tokens = await refreshOpenAiAccessToken(cred.refresh);\n } else if (providerId === 'xai' || providerId === 'xai-oauth') {\n tokens = await refreshXaiAccessToken(cred.refresh);\n } else if (providerId === 'github-copilot') {\n // cred.refresh is the long-lived ghu_ token; re-exchange for a new Copilot session token\n tokens = await refreshGithubCopilotToken(cred.refresh);\n } else if (providerId === 'claude-code') {\n tokens = await refreshClaudeCodeToken(cred.refresh);\n } else if (providerId === 'antigravity') {\n tokens = await refreshAntigravityToken(cred.refresh);\n } else if (providerId === 'cline-pass') {\n tokens = await refreshClinePassAccessToken(cred.refresh);\n } else {\n throw new Error(`OAuth refresh not implemented for provider \"${providerId}\"`);\n }\n\n const accountId = providerId === 'cline-pass' && typeof tokens.providerData?.clineUserId === 'string'\n ? tokens.providerData.clineUserId\n : cred.accountId;\n return tokensToStoredCredential(tokens, cred.refresh, accountId, cred.providerData);\n}\n","// src/secrets-file.ts — file-backed credential store when OS keyring is unavailable.\n// Prefer keyring; this is the RELAY_AI_HOME fallback (Docker / headless).\n\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { getAppHome, getSecretsPath } from './paths.js';\n\nconst DIR_MODE = 0o700;\nconst FILE_MODE = 0o600;\n\nexport interface SecretsFile {\n version: 1;\n accounts: Record<string, string>;\n}\n\nfunction emptySecrets(): SecretsFile {\n return { version: 1, accounts: {} };\n}\n\nexport function readSecretsFile(env: NodeJS.ProcessEnv = process.env): SecretsFile {\n const path = getSecretsPath(env);\n if (!existsSync(path)) return emptySecrets();\n try {\n const raw = JSON.parse(readFileSync(path, 'utf8')) as Partial<SecretsFile>;\n if (raw?.version !== 1 || !raw.accounts || typeof raw.accounts !== 'object') {\n return emptySecrets();\n }\n const accounts: Record<string, string> = {};\n for (const [k, v] of Object.entries(raw.accounts)) {\n if (typeof v === 'string' && v.length > 0) accounts[k] = v;\n }\n return { version: 1, accounts };\n } catch {\n return emptySecrets();\n }\n}\n\nfunction writeSecretsFile(data: SecretsFile, env: NodeJS.ProcessEnv = process.env): void {\n const home = getAppHome(env);\n mkdirSync(home, { recursive: true, mode: DIR_MODE });\n try {\n chmodSync(home, DIR_MODE);\n } catch {\n // best-effort\n }\n const path = getSecretsPath(env);\n writeFileSync(path, `${JSON.stringify(data, null, 2)}\\n`, { encoding: 'utf8', mode: FILE_MODE });\n try {\n chmodSync(path, FILE_MODE);\n } catch {\n // best-effort (mode on create is ignored if the file already existed)\n }\n}\n\nexport function readFileAccount(account: string, env: NodeJS.ProcessEnv = process.env): string | null {\n const value = readSecretsFile(env).accounts[account];\n return value?.length ? value : null;\n}\n\nexport function writeFileAccount(\n account: string,\n value: string,\n env: NodeJS.ProcessEnv = process.env,\n): boolean {\n if (!account || !value) return false;\n try {\n const data = readSecretsFile(env);\n data.accounts[account] = value;\n writeSecretsFile(data, env);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function deleteFileAccount(account: string, env: NodeJS.ProcessEnv = process.env): boolean {\n try {\n const data = readSecretsFile(env);\n if (!(account in data.accounts)) return true;\n delete data.accounts[account];\n writeSecretsFile(data, env);\n return true;\n } catch {\n return false;\n }\n}\n","// src/env.ts\nimport { CONFLICTING_ENV_VARS, PARENT_SESSION_ENV_VARS } from './constants.js';\nimport { claudeCodeClientModelId, stripOneMContextSuffix } from './context-model-id.js';\nimport { resolveContextWindow } from './context-window.js';\nimport { oauthCredentialToKeychainJson } from './registry/opencode-auth.js';\nimport {\n parseStoredOAuthCredential,\n} from './oauth/types.js';\nimport { refreshStoredOAuthCredential, oauthCredentialShouldRefresh } from './oauth/refresh.js';\nimport { fetchCopilotAccount } from './oauth/github.js';\nimport {\n deleteFileAccount,\n readFileAccount,\n writeFileAccount,\n} from './secrets-file.js';\nimport type { ConflictInfo } from './types.js';\n\nexport function detectConflicts(): ConflictInfo[] {\n return CONFLICTING_ENV_VARS\n .filter(name => process.env[name] !== undefined)\n .map(name => ({ name, value: process.env[name]! }));\n}\n\nexport function resolveApiKey(): string | null {\n const key = process.env['OPENCODE_API_KEY'];\n // Treat empty string as missing — happens when .zshrc auto-load line runs\n // but the Keychain entry has been deleted (security command returns nothing)\n if (!key?.trim()) return null;\n // First line only — users sometimes paste notes below the key in shell profiles\n return key.trim().split(/\\r?\\n/)[0]?.trim() || null;\n}\n\n/** Restore first-party-like Claude Code behavior when routing through a proxy or gateway. */\nexport function applyClaudeCodeThirdPartyCompat(env: NodeJS.ProcessEnv): void {\n // Custom ANTHROPIC_BASE_URL disables MCP tool search by default, loading every\n // MCP tool (100+) on every turn. Requires defer_loading on tools — do not set\n // CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS when using the local translation proxy.\n env['ENABLE_TOOL_SEARCH'] = 'true';\n // Third-party routes may enable a shorter system prompt that drops conversational\n // guardrails while hooks/plugins still inject agentic instructions.\n env['CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT'] = '0';\n}\n\nexport function buildChildEnv(\n baseUrl: string,\n model: string,\n apiKey: string,\n proxyPort?: number,\n contextWindow?: number,\n enableGatewayDiscovery?: boolean,\n): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...process.env };\n for (const name of CONFLICTING_ENV_VARS) {\n delete env[name];\n }\n for (const name of PARENT_SESSION_ENV_VARS) {\n delete env[name];\n }\n env['ANTHROPIC_BASE_URL'] = proxyPort\n ? `http://127.0.0.1:${proxyPort}`\n : baseUrl;\n env['ANTHROPIC_API_KEY'] = apiKey;\n const bareModel = stripOneMContextSuffix(model);\n env['ANTHROPIC_MODEL'] = claudeCodeClientModelId(model, contextWindow);\n // Claude Code defaults to 200K for non-api.anthropic.com base URLs; override with\n // the launch model's real window. NOTE: in switch-menu mode this is fixed at launch\n // and does NOT update on live /model switch — Claude Code's gateway model discovery\n // only carries id + display_name (no context_window), so this env var is the only\n // lever and it reflects the model you started with.\n // Third-party routes also require a `[1m]` model-id suffix for 1M+ windows in the UI.\n env['CLAUDE_CODE_MAX_CONTEXT_TOKENS'] = String(resolveContextWindow(bareModel, contextWindow));\n if (enableGatewayDiscovery) {\n env['CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY'] = '1';\n }\n applyClaudeCodeThirdPartyCompat(env);\n return env;\n}\n\n/** Child env for Antigravity — only CLOUD_CODE_URL, no Anthropic proxy vars. */\nexport function buildAntigravityChildEnv(gatewayUrl: string): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...process.env };\n for (const name of CONFLICTING_ENV_VARS) {\n delete env[name];\n }\n env['CLOUD_CODE_URL'] = gatewayUrl;\n\n // Inject dummy API keys to bypass agy's slow keychain lookup (~500ms).\n // This prevents the race condition where loadCodeAssist fails and falls back\n // to the hardcoded, unsupported FLASH_LITE model.\n // The local Cloud Code Gateway ignores these keys, so any dummy value works.\n env['ANTIGRAVITY_API_KEY'] = 'relay-dummy-key';\n env['GEMINI_API_KEY'] = 'relay-dummy-key';\n env['GOOGLE_API_KEY'] = 'relay-dummy-key';\n env['GOOGLE_GEMINI_API_KEY'] = 'relay-dummy-key';\n\n return env;\n}\n\n/** Classify a keyring error into a human-readable reason (never throws). */\nexport function classifyKeyringError(err: unknown): string {\n const msg = err instanceof Error ? err.message : String(err);\n const lower = msg.toLowerCase();\n if (lower.includes('cannot find module') || lower.includes('module not found') || lower.includes('failed to load')) {\n return 'native keyring module not available on this system';\n }\n if (lower.includes('secret service') || lower.includes('dbus') || lower.includes('daemon')) {\n return 'Secret Service daemon is not running (start GNOME Keyring or KWallet)';\n }\n if (lower.includes('denied') || lower.includes('locked') || lower.includes('cancelled') || lower.includes('user refused')) {\n return 'keychain access was denied or the keychain is locked';\n }\n return `keyring error: ${msg}`;\n}\n\nconst KEYRING_SERVICE = 'relay-ai';\n/** @deprecated Use GLOBAL_OPENCODE_KEYRING_ACCOUNT — kept for migration reads */\nconst KEYRING_ACCOUNT = 'relay-ai';\n// Windows Credential Manager caps a single credential blob at 2560 bytes (CredWriteW).\n// keyring-rs encodes the password as UTF-16 (2 bytes/char) before that check, so the\n// usable limit is 2560 / 2 = 1280 chars — long OAuth tokens (e.g. OpenAI's JWTs) exceed\n// this, so secrets above the threshold are split across multiple keyring entries.\n// Harmless on macOS/Linux, which have no such limit.\nconst KEYRING_CHUNK_PREFIX = '__relay_chunked__:';\nconst KEYRING_CHUNK_SIZE = 1200;\nconst LEGACY_KEYRING_SERVICE = 'opencode-starter';\nconst LEGACY_KEYRING_ACCOUNT = 'opencode-starter';\n\nexport const GLOBAL_OPENCODE_KEYRING_ACCOUNT = 'global:opencode';\n\nexport function providerKeyringAccount(providerId: string): string {\n return `provider:${providerId}`;\n}\n\n/** Auth-ref used for a user-managed Relay override of the shared OpenCode catalog key. */\nexport function preferredRelayCredentialAuthRef(providerId: string, fallbackAuthRef: string): string {\n return providerId === 'go' || providerId === 'zen'\n ? `keyring:${providerKeyringAccount('opencode')}`\n : fallbackAuthRef;\n}\n\nexport function oauthProviderKeyringAccount(providerId: string): string {\n return `oauth:provider:${providerId}`;\n}\n\nfunction oauthProviderIdFromAccount(account: string): string | null {\n const prefix = 'oauth:provider:';\n return account.startsWith(prefix) ? account.slice(prefix.length) : null;\n}\n\nconst oauthRefreshInflight = new Map<string, Promise<string | null>>();\n\nexport type ParsedAuthRef =\n | { kind: 'keyring'; account: string }\n | { kind: 'env'; varName: string };\n\n/** Parse registry authRef strings like `keyring:provider:groq` or `env:OPENCODE_API_KEY`. */\nexport function parseAuthRef(authRef: string): ParsedAuthRef | null {\n if (authRef.startsWith('keyring:')) {\n const account = authRef.slice('keyring:'.length);\n return account ? { kind: 'keyring', account } : null;\n }\n if (authRef.startsWith('env:')) {\n const varName = authRef.slice('env:'.length);\n return varName ? { kind: 'env', varName } : null;\n }\n return null;\n}\n\n/** Env var name for relay-ai namespaced per-provider keys. */\nexport function relayAiKeyEnvVar(providerId: string): string {\n return `RELAY_AI_KEY_${providerId.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`;\n}\n\nfunction readEnvCredential(varName: string): string | null {\n const raw = process.env[varName];\n if (!raw?.trim()) return null;\n return raw.trim().split(/\\r?\\n/)[0]?.trim() || null;\n}\n\nasync function readOsKeyringAccount(account: string, diag?: (msg: string) => void): Promise<string | null> {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n const value = new Entry(KEYRING_SERVICE, account).getPassword() ?? null;\n if (!value?.startsWith(KEYRING_CHUNK_PREFIX)) return value;\n const chunkCount = Number(value.slice(KEYRING_CHUNK_PREFIX.length));\n let combined = '';\n for (let i = 0; i < chunkCount; i++) {\n combined += new Entry(KEYRING_SERVICE, `${account}::chunk::${i}`).getPassword() ?? '';\n }\n return combined;\n } catch (err) {\n diag?.(classifyKeyringError(err));\n return null;\n }\n}\n\nasync function writeOsKeyringAccount(\n account: string,\n key: string,\n diag?: (msg: string) => void,\n): Promise<boolean> {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n if (key.length <= KEYRING_CHUNK_SIZE) {\n new Entry(KEYRING_SERVICE, account).setPassword(key);\n return true;\n }\n const chunkCount = Math.ceil(key.length / KEYRING_CHUNK_SIZE);\n for (let i = 0; i < chunkCount; i++) {\n const chunk = key.slice(i * KEYRING_CHUNK_SIZE, (i + 1) * KEYRING_CHUNK_SIZE);\n new Entry(KEYRING_SERVICE, `${account}::chunk::${i}`).setPassword(chunk);\n }\n new Entry(KEYRING_SERVICE, account).setPassword(`${KEYRING_CHUNK_PREFIX}${chunkCount}`);\n return true;\n } catch (err) {\n diag?.(classifyKeyringError(err));\n return false;\n }\n}\n\nasync function deleteOsKeyringAccount(account: string, diag?: (msg: string) => void): Promise<boolean> {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n const value = new Entry(KEYRING_SERVICE, account).getPassword();\n if (value?.startsWith(KEYRING_CHUNK_PREFIX)) {\n const chunkCount = Number(value.slice(KEYRING_CHUNK_PREFIX.length));\n for (let i = 0; i < chunkCount; i++) {\n new Entry(KEYRING_SERVICE, `${account}::chunk::${i}`).deletePassword();\n }\n }\n new Entry(KEYRING_SERVICE, account).deletePassword();\n return true;\n } catch (err) {\n diag?.(classifyKeyringError(err));\n return false;\n }\n}\n\n/** OS keyring first, then ~/.relay-ai/secrets.json (Docker / headless). */\nasync function readKeyringAccount(account: string, diag?: (msg: string) => void): Promise<string | null> {\n const fromOs = await readOsKeyringAccount(account, diag);\n if (fromOs) return fromOs;\n return readFileAccount(account);\n}\n\n/** Prefer OS keyring; fall back to secrets.json when keyring is unavailable. */\nasync function writeKeyringAccount(\n account: string,\n key: string,\n diag?: (msg: string) => void,\n): Promise<boolean> {\n if (await writeOsKeyringAccount(account, key, diag)) {\n deleteFileAccount(account);\n return true;\n }\n if (writeFileAccount(account, key)) {\n diag?.('OS keyring unavailable — saved to secrets.json under RELAY_AI_HOME');\n return true;\n }\n return false;\n}\n\nasync function deleteKeyringAccount(account: string, diag?: (msg: string) => void): Promise<boolean> {\n const osOk = await deleteOsKeyringAccount(account, diag);\n const fileOk = deleteFileAccount(account);\n return osOk || fileOk;\n}\n\n/** Read Zen/Go API key: env → global:opencode → legacy relay-ai → opencode-starter. */\nexport async function readGlobalOpencodeCredential(diag?: (msg: string) => void): Promise<string | null> {\n const fromEnv = resolveApiKey();\n if (fromEnv) return fromEnv;\n\n const global = await readKeyringAccount(GLOBAL_OPENCODE_KEYRING_ACCOUNT, diag);\n if (global) return global;\n\n const current = await readKeyringAccount(KEYRING_ACCOUNT, diag);\n if (current) return current;\n\n try {\n const { Entry } = await import('@napi-rs/keyring');\n return new Entry(LEGACY_KEYRING_SERVICE, LEGACY_KEYRING_ACCOUNT).getPassword() ?? null;\n } catch (err) {\n diag?.(classifyKeyringError(err));\n return null;\n }\n}\n\n/** Read a stored credential without environment-variable precedence. */\nexport async function readStoredProviderCredential(\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<string | null> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring') return null;\n return readProviderSecret(parsed.account, diag);\n}\n\n/**\n * Migrate legacy keychain entries to `global:opencode`.\n * Protocol: read → write → verify → delete old (only after verify succeeds).\n */\nexport async function migrateGlobalOpencodeCredential(diag?: (msg: string) => void): Promise<boolean> {\n const existing = await readKeyringAccount(GLOBAL_OPENCODE_KEYRING_ACCOUNT, diag);\n if (existing) return true;\n\n const legacy =\n (await readKeyringAccount(KEYRING_ACCOUNT, diag)) ??\n (await (async () => {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n return new Entry(LEGACY_KEYRING_SERVICE, LEGACY_KEYRING_ACCOUNT).getPassword() ?? null;\n } catch (err) {\n diag?.(classifyKeyringError(err));\n return null;\n }\n })());\n\n if (!legacy) return false;\n\n const wrote = await writeKeyringAccount(GLOBAL_OPENCODE_KEYRING_ACCOUNT, legacy, diag);\n if (!wrote) return false;\n\n const verified = await readKeyringAccount(GLOBAL_OPENCODE_KEYRING_ACCOUNT, diag);\n if (verified !== legacy) {\n diag?.('credential migration verification failed — keeping legacy keychain entries');\n return false;\n }\n\n if (await readKeyringAccount(KEYRING_ACCOUNT, diag)) {\n await deleteKeyringAccount(KEYRING_ACCOUNT, diag);\n }\n try {\n const { Entry } = await import('@napi-rs/keyring');\n if (new Entry(LEGACY_KEYRING_SERVICE, LEGACY_KEYRING_ACCOUNT).getPassword()) {\n new Entry(LEGACY_KEYRING_SERVICE, LEGACY_KEYRING_ACCOUNT).deletePassword();\n }\n } catch {\n // best-effort legacy cleanup\n }\n return true;\n}\n\n/** Resolve a provider secret from authRef (env → keyring). */\nexport async function resolveProviderCredential(\n providerId: string,\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<string | null> {\n const parsed = parseAuthRef(authRef);\n if (!parsed) return null;\n\n // A key explicitly saved in Relay for the shared OpenCode catalog is a deliberate\n // override. It must win over OPENCODE_API_KEY, RELAY_AI_KEY_GO/ ZEN, and OpenCode's\n // own global key so a user can actually replace a stale credential.\n if (parsed.kind === 'keyring' && parsed.account === GLOBAL_OPENCODE_KEYRING_ACCOUNT) {\n const relayOverride = await readProviderSecret(providerKeyringAccount('opencode'), diag);\n if (relayOverride) return relayOverride;\n }\n\n const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));\n if (namespaced) return namespaced;\n\n if (parsed.kind === 'env') {\n return readEnvCredential(parsed.varName);\n }\n\n if (parsed.account === GLOBAL_OPENCODE_KEYRING_ACCOUNT) {\n return readGlobalOpencodeCredential(diag);\n }\n\n return readProviderSecret(parsed.account, diag);\n}\n\n/**\n * Force-refresh a stored OAuth credential after an upstream 401.\n * Normal resolution refreshes only when expiry metadata says it is needed;\n * providers can revoke a token early, so the retry path must bypass that gate.\n */\nexport async function forceRefreshProviderCredential(\n providerId: string,\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<string | null> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring') {\n return resolveProviderCredential(providerId, authRef, diag);\n }\n\n if (parsed.account === GLOBAL_OPENCODE_KEYRING_ACCOUNT) {\n const relayOverride = await readProviderSecret(providerKeyringAccount('opencode'), diag);\n if (relayOverride) return relayOverride;\n }\n\n const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));\n if (namespaced) return namespaced;\n\n const oauthProviderId = oauthProviderIdFromAccount(parsed.account);\n const raw = await readKeyringAccount(parsed.account, diag);\n if (!raw || !oauthProviderId) return decodeProviderSecret(raw);\n return refreshOAuthKeyringAccount(parsed.account, oauthProviderId, raw, diag, true);\n}\n\n/** Read OAuth metadata retained alongside the access token. */\nexport async function resolveProviderOAuthAccountId(\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<string | undefined> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring' || !oauthProviderIdFromAccount(parsed.account)) return undefined;\n const raw = await readKeyringAccount(parsed.account, diag);\n return parseStoredOAuthCredential(raw)?.accountId;\n}\n\nexport async function resolveProviderOAuthProviderData(\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<Record<string, unknown> | undefined> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring' || !oauthProviderIdFromAccount(parsed.account)) return undefined;\n const raw = await readKeyringAccount(parsed.account, diag);\n return parseStoredOAuthCredential(raw)?.providerData;\n}\n\n/** Backfill Copilot plan metadata for credentials saved before plan detection existed. */\nexport async function enrichGithubCopilotOAuthProviderData(\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<Record<string, unknown> | undefined> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring' || oauthProviderIdFromAccount(parsed.account) !== 'github-copilot') {\n return undefined;\n }\n const raw = await readKeyringAccount(parsed.account, diag);\n const credential = parseStoredOAuthCredential(raw);\n if (!credential?.refresh) return credential?.providerData;\n try {\n const summary = await fetchCopilotAccount(credential.refresh);\n const providerData = { ...credential.providerData, copilot: summary };\n await writeKeyringAccount(\n parsed.account,\n oauthCredentialToKeychainJson({ ...credential, providerData }),\n diag,\n );\n return providerData;\n } catch (err) {\n diag?.(`GitHub Copilot plan lookup unavailable — ${err instanceof Error ? err.message : String(err)}`);\n return credential.providerData;\n }\n}\n\nfunction decodeProviderSecret(raw: string | null): string | null {\n if (!raw) return null;\n const trimmed = raw.trim();\n if (!trimmed.startsWith('{')) return trimmed;\n const oauth = parseStoredOAuthCredential(trimmed);\n if (oauth) return oauth.access;\n try {\n const parsed = JSON.parse(trimmed) as { type?: string; access?: string; token?: string };\n if (parsed.type === 'oauth' && typeof parsed.access === 'string') return parsed.access;\n if (parsed.type === 'wellknown' && typeof parsed.token === 'string') return parsed.token;\n } catch {\n // fall through\n }\n return trimmed;\n}\n\nasync function refreshOAuthKeyringAccount(\n account: string,\n providerId: string,\n raw: string,\n diag?: (msg: string) => void,\n force = false,\n): Promise<string | null> {\n const existing = oauthRefreshInflight.get(account);\n if (existing) return existing;\n\n const work = (async (): Promise<string | null> => {\n const cred = parseStoredOAuthCredential(raw);\n if (!cred || (!force && !oauthCredentialShouldRefresh(cred, providerId))) {\n return decodeProviderSecret(raw);\n }\n try {\n const refreshed = await refreshStoredOAuthCredential(providerId, cred);\n const json = oauthCredentialToKeychainJson(refreshed);\n await writeKeyringAccount(account, json, diag);\n return refreshed.access;\n } catch (err) {\n diag?.(err instanceof Error ? err.message : String(err));\n if (cred.access && cred.expires > Date.now()) return cred.access;\n throw err;\n }\n })();\n\n oauthRefreshInflight.set(account, work);\n try {\n return await work;\n } finally {\n oauthRefreshInflight.delete(account);\n }\n}\n\nasync function readProviderSecret(account: string, diag?: (msg: string) => void): Promise<string | null> {\n const raw = await readKeyringAccount(account, diag);\n if (!raw) return null;\n\n const oauthProviderId = oauthProviderIdFromAccount(account);\n if (oauthProviderId && raw.trim().startsWith('{')) {\n return refreshOAuthKeyringAccount(account, oauthProviderId, raw, diag);\n }\n return decodeProviderSecret(raw);\n}\n\nexport async function saveProviderCredential(\n authRef: string,\n key: string,\n diag?: (msg: string) => void,\n): Promise<boolean> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring') return false;\n return writeKeyringAccount(parsed.account, key, diag);\n}\n\n/** Delete a provider secret from keyring (no-op for env: refs). */\nexport async function deleteProviderCredential(\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<boolean> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring') return false;\n return deleteKeyringAccount(parsed.account, diag);\n}\n\nexport async function readFromCredentialStore(diag?: (msg: string) => void): Promise<string | null> {\n return readGlobalOpencodeCredential(diag);\n}\n\nexport async function saveToCredentialStore(key: string, diag?: (msg: string) => void): Promise<boolean> {\n const wrote = await writeKeyringAccount(GLOBAL_OPENCODE_KEYRING_ACCOUNT, key, diag);\n if (wrote) {\n await deleteKeyringAccount(KEYRING_ACCOUNT, diag);\n }\n return wrote;\n}\n\nexport async function isSecretServiceAvailable(): Promise<boolean> {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n new Entry(`${KEYRING_SERVICE}-probe`, 'probe').getPassword();\n return true;\n } catch {\n return false;\n }\n}\n","{\n \"schema_version\": \"1\",\n \"entries\": [\n {\n \"provider\": \"google\",\n \"modelId\": \"antigravity-preview-05-2026\",\n \"category\": \"managed_agent\",\n \"reason\": \"Interactions API only; coding agents send multiturn chat via @ai-sdk/google streamGenerateContent\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"manual UAT 2026-06-10\"\n ],\n \"verifiedAt\": \"2026-06-10\"\n },\n {\n \"provider\": \"*\",\n \"modelId\": \"z-ai/glm4.7\",\n \"category\": \"gated_access\",\n \"reason\": \"NVIDIA NIM requires separate access approval (HTTP 410)\",\n \"sources\": [\n \"manual probe 2026-06\"\n ],\n \"verifiedAt\": \"2026-06-10\"\n },\n {\n \"provider\": \"*\",\n \"modelId\": \"qwen3.6-plus-free\",\n \"category\": \"stale_promotion\",\n \"reason\": \"Free promotion ended; API returns 401\",\n \"sources\": [\n \"OpenCode Zen catalog\"\n ],\n \"verifiedAt\": \"2026-06-10\"\n },\n {\n \"provider\": \"*\",\n \"modelId\": \"mimo-v2-pro\",\n \"category\": \"deprecated\",\n \"reason\": \"Deprecated; API returns 400 — use mimo-v2.5-pro\",\n \"sources\": [\n \"OpenCode Zen catalog\"\n ],\n \"verifiedAt\": \"2026-06-10\"\n },\n {\n \"provider\": \"*\",\n \"modelId\": \"mimo-v2-omni\",\n \"category\": \"deprecated\",\n \"reason\": \"Deprecated; API returns 400 — use mimo-v2.5\",\n \"sources\": [\n \"OpenCode Zen catalog\"\n ],\n \"verifiedAt\": \"2026-06-10\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"aqa\",\n \"category\": \"managed_agent\",\n \"reason\": \"Attributed QA model — not for coding agents\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"deep-research-max-preview-04-2026\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"deep-research-preview-04-2026\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"deep-research-pro-preview-12-2025\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-computer-use-preview-10-2025\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-flash-image\",\n \"category\": \"image_generation\",\n \"reason\": \"Image-output model — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-flash-native-audio-latest\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-flash-native-audio-preview-09-2025\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-flash-native-audio-preview-12-2025\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-flash-preview-tts\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-pro-preview-tts\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3-pro-preview\",\n \"category\": \"deprecated\",\n \"reason\": \"Retired preview; API returns 404 — use gemini-3.1-pro-preview or newer\",\n \"sources\": [\n \"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-preview\",\n \"manual UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3-pro-image\",\n \"category\": \"image_generation\",\n \"reason\": \"Image-output model — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3-pro-image-preview\",\n \"category\": \"image_generation\",\n \"reason\": \"Image-output model — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3.1-flash-image\",\n \"category\": \"image_generation\",\n \"reason\": \"Image-output model — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3.1-flash-image-preview\",\n \"category\": \"image_generation\",\n \"reason\": \"Image-output model — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3.1-flash-live-preview\",\n \"category\": \"managed_agent\",\n \"reason\": \"Live/session API — not for Codex multiturn chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3.1-flash-tts-preview\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3.5-live-translate-preview\",\n \"category\": \"managed_agent\",\n \"reason\": \"Live/session API — not for Codex multiturn chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-embedding-001\",\n \"category\": \"embedding\",\n \"reason\": \"Embedding model — not for chat or tools\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-embedding-2\",\n \"category\": \"embedding\",\n \"reason\": \"Embedding model — not for chat or tools\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-embedding-2-preview\",\n \"category\": \"embedding\",\n \"reason\": \"Embedding model — not for chat or tools\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-robotics-er-1.5-preview\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-robotics-er-1.6-preview\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"imagen-4.0-fast-generate-001\",\n \"category\": \"image_generation\",\n \"reason\": \"Image generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"imagen-4.0-generate-001\",\n \"category\": \"image_generation\",\n \"reason\": \"Image generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"imagen-4.0-ultra-generate-001\",\n \"category\": \"image_generation\",\n \"reason\": \"Image generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"lyria-3-clip-preview\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"lyria-3-pro-preview\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"lyria-realtime-exp\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"nano-banana-pro-preview\",\n \"category\": \"image_generation\",\n \"reason\": \"Image generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-2.0-generate-001\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-3.0-fast-generate-001\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-3.0-generate-001\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-3.1-fast-generate-preview\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-3.1-generate-preview\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-3.1-lite-generate-preview\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n }\n ]\n}\n","// src/registry/models-dev.ts — models.dev capability cache (bundled + optional user refresh)\n\nimport {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport bundledCache from '../data/models-dev-cache.json';\nimport { getAppHome } from '../paths.js';\nimport { normalizeModelIdCandidates } from './pricing.js';\n\nexport const MODELS_DEV_API_URL = 'https://models.dev/api.json';\nconst FETCH_TIMEOUT_MS = 15_000;\nconst FILE_MODE = 0o600;\n\nexport interface ModelsDevModalities {\n input?: string[];\n output?: string[];\n}\n\nexport interface ModelsDevModel {\n id?: string;\n name?: string;\n tool_call?: boolean;\n chat?: boolean;\n interactions?: boolean;\n reasoning?: boolean;\n interleaved?: { field?: string };\n modalities?: ModelsDevModalities;\n}\n\nexport interface ModelsDevProvider {\n id?: string;\n name?: string;\n models?: Record<string, ModelsDevModel>;\n}\n\nexport type ModelsDevCacheFile = Record<string, ModelsDevProvider>;\n\nexport interface ModelsDevCacheMeta {\n schema_version?: string;\n fetched_at?: string;\n source?: string;\n provider_count?: number;\n}\n\nconst META_KEY = '_relay_meta';\n\nlet memoryCache: ModelsDevCacheFile | null = null;\nlet memoryCachePath: string | null = null;\nlet memoryCacheMtime = 0;\n\n/** Registry / OpenCode provider id → models.dev top-level key */\nexport const REGISTRY_TO_MODELS_DEV: Record<string, string> = {\n google: 'google',\n openai: 'openai',\n groq: 'groq',\n mistral: 'mistral',\n togetherai: 'together',\n cerebras: 'cerebras',\n deepinfra: 'deepinfra',\n xai: 'xai',\n 'xai-oauth': 'xai',\n perplexity: 'perplexity',\n cohere: 'cohere',\n alibaba: 'alibaba',\n 'qwen-cloud-token-plan': 'alibaba-token-plan',\n 'qwen-cloud-payg': 'alibaba',\n openrouter: 'openrouter',\n anthropic: 'anthropic',\n nvidia: 'nvidia',\n venice: 'openrouter',\n};\n\nexport function readModelsDevCacheMeta(\n cache: ModelsDevCacheFile,\n): ModelsDevCacheMeta | null {\n const raw = cache[META_KEY] as unknown as ModelsDevCacheMeta | undefined;\n if (!raw || typeof raw !== 'object') return null;\n return raw;\n}\n\nexport function stripModelsDevCacheMeta(cache: ModelsDevCacheFile): ModelsDevCacheFile {\n const { [META_KEY]: _meta, ...providers } = cache;\n return providers;\n}\n\nexport function loadBundledModelsDevCache(): ModelsDevCacheFile {\n return bundledCache as unknown as ModelsDevCacheFile;\n}\n\nexport function invalidateModelsDevCache(): void {\n memoryCache = null;\n memoryCachePath = null;\n memoryCacheMtime = 0;\n}\n\nfunction readModelsDevFile(path: string): ModelsDevCacheFile | null {\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as ModelsDevCacheFile;\n } catch {\n return null;\n }\n}\n\nfunction mkdirSafe(dir: string): void {\n try {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n } catch {\n // ignore\n }\n}\n\nfunction attachModelsDevCacheMeta(\n providers: Record<string, ModelsDevProvider>,\n): ModelsDevCacheFile {\n const providerCount = Object.keys(providers).filter(k => !k.startsWith('_')).length;\n return {\n [META_KEY]: {\n schema_version: '1',\n fetched_at: new Date().toISOString(),\n source: MODELS_DEV_API_URL,\n provider_count: providerCount,\n },\n ...providers,\n } as ModelsDevCacheFile;\n}\n\nfunction writeModelsDevCache(path: string, data: ModelsDevCacheFile): void {\n mkdirSafe(dirname(path));\n writeFileSync(path, `${JSON.stringify(data)}\\n`, { mode: FILE_MODE });\n try {\n chmodSync(path, FILE_MODE);\n } catch {\n // best-effort\n }\n invalidateModelsDevCache();\n}\n\nexport function getUserModelsDevCachePath(): string {\n return join(getAppHome(), 'models-dev-cache.json');\n}\n\nfunction rememberModelsDevCache(path: string, data: ModelsDevCacheFile): ModelsDevCacheFile {\n memoryCache = data;\n memoryCachePath = path;\n try {\n memoryCacheMtime = statSync(path).mtimeMs;\n } catch {\n memoryCacheMtime = 0;\n }\n return data;\n}\n\nexport function loadModelsDevCache(): ModelsDevCacheFile {\n const userPath = getUserModelsDevCachePath();\n if (existsSync(userPath)) {\n try {\n const mtime = statSync(userPath).mtimeMs;\n if (memoryCache && memoryCachePath === userPath && memoryCacheMtime === mtime) {\n return memoryCache;\n }\n const data = readModelsDevFile(userPath);\n if (data) return rememberModelsDevCache(userPath, data);\n } catch {\n // fall through to bundled\n }\n }\n\n if (memoryCache && memoryCachePath === 'bundled') return memoryCache;\n return rememberModelsDevCache('bundled', loadBundledModelsDevCache());\n}\n\nexport async function fetchModelsDevCache(): Promise<ModelsDevCacheFile | null> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const response = await fetch(MODELS_DEV_API_URL, {\n signal: controller.signal,\n headers: { Accept: 'application/json' },\n });\n if (!response.ok) return null;\n const data = (await response.json()) as Record<string, ModelsDevProvider>;\n if (!data || typeof data !== 'object') return null;\n const withMeta = attachModelsDevCacheMeta(data);\n writeModelsDevCache(getUserModelsDevCachePath(), withMeta);\n return withMeta;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport function resolveModelsDevSlug(providerId: string): string {\n return REGISTRY_TO_MODELS_DEV[providerId] ?? providerId;\n}\n\n/** Fetch latest models.dev catalog in the background; falls back to bundled snapshot offline. */\nexport function refreshModelsDevCacheAsync(onComplete?: (updated: boolean) => void): void {\n void (async () => {\n const updated = (await fetchModelsDevCache()) !== null;\n onComplete?.(updated);\n })();\n}\n\nexport function findModelsDevModel(\n providerId: string,\n modelId: string,\n cache: ModelsDevCacheFile = loadModelsDevCache(),\n): ModelsDevModel | null {\n const slug = resolveModelsDevSlug(providerId);\n const models = stripModelsDevCacheMeta(cache)[slug]?.models;\n if (!models) return null;\n\n for (const candidate of normalizeModelIdCandidates(modelId)) {\n const entry = models[candidate];\n if (entry) return entry;\n }\n return null;\n}\n\n/** Conservative auto-hide rules — only when models.dev row exists and fields are explicit. */\nexport function shouldHideByModelsDevCapabilities(entry: ModelsDevModel): boolean {\n const output = entry.modalities?.output;\n if (output && output.length > 0 && !output.includes('text')) return true;\n if (entry.tool_call === false) return true;\n if (entry.interactions === true && entry.chat === false) return true;\n return false;\n}\n","// src/registry/pricing.ts — async pricing enrich from ai-model-pricing.com + bundled fallback\n//\n// Schema mapping:\n// ai-model-pricing.com entries use dollars per 1M tokens (input_per_1m_tokens, output_per_1m_tokens).\n// CachedModel.cost stores the same units as OpenCode models.json ({ input, output } per 1M tokens).\n// Multi-tier rows: prefer tier=standard + modality=text for the provider platform; else first text row.\n//\n// Model ID normalization (lookup order):\n// 1. Exact id / upstreamModelId\n// 2. Platform alias from pricing entry (aliases[platform])\n// 3. Lowercase id, strip openrouter/ and provider/ prefixes\n\nimport {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport bundledPricing from '../data/pricing-cache.json';\nimport { getAppHome } from '../paths.js';\nimport type { CachedModel } from './types.js';\nimport { loadRegistry, saveRegistry } from './io.js';\nimport { classifyFreeStatus, isFreeStatus } from '../free-models.js';\n\nexport const PRICING_API_URL = 'https://ai-model-pricing.com/api/v1/pricing.json';\nconst FETCH_TIMEOUT_MS = 15_000;\nconst FILE_MODE = 0o600;\n\nexport interface PricingTierRow {\n platform?: string;\n tier?: string;\n modality?: string;\n input_per_1m_tokens?: number;\n output_per_1m_tokens?: number;\n cached_input_per_1m_tokens?: number;\n}\n\nexport interface PricingModelEntry {\n provider?: string;\n model_id?: string;\n aliases?: Record<string, string>;\n pricing?: PricingTierRow[];\n}\n\nexport interface PricingCacheFile {\n schema_version?: string;\n generated_at?: string;\n models?: PricingModelEntry[];\n}\n\n/** Registry template id → ai-model-pricing platform slug */\nexport const TEMPLATE_TO_PRICING_PLATFORM: Record<string, string> = {\n groq: 'groq',\n mistral: 'mistral',\n togetherai: 'together',\n cerebras: 'cerebras',\n deepinfra: 'deepinfra',\n xai: 'xai',\n 'xai-oauth': 'xai',\n perplexity: 'perplexity',\n cohere: 'cohere',\n openai: 'openai',\n google: 'google_ai_studio',\n alibaba: 'alibaba',\n 'qwen-cloud-payg': 'alibaba',\n openrouter: 'openrouter',\n anthropic: 'anthropic',\n nvidia: 'nvidia',\n venice: 'openrouter',\n};\n\nconst PRICING_OPT_OUT_TEMPLATE_IDS = new Set([\n 'qwen-cloud-token-plan',\n]);\n\nexport function loadBundledPricingCache(): PricingCacheFile {\n return bundledPricing as unknown as PricingCacheFile;\n}\n\nfunction readPricingFile(path: string): PricingCacheFile | null {\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as PricingCacheFile;\n } catch {\n return null;\n }\n}\n\nfunction writePricingCache(path: string, data: PricingCacheFile): void {\n mkdirSafe(dirname(path));\n writeFileSync(path, `${JSON.stringify(data, null, 2)}\\n`, { mode: FILE_MODE });\n try {\n chmodSync(path, FILE_MODE);\n } catch {\n // best-effort\n }\n}\n\nfunction mkdirSafe(dir: string): void {\n try {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n } catch {\n // ignore\n }\n}\n\nexport function getUserPricingCachePath(): string {\n return join(getAppHome(), 'pricing-cache.json');\n}\n\nexport function loadPricingCache(): PricingCacheFile {\n return readPricingFile(getUserPricingCachePath()) ?? loadBundledPricingCache();\n}\n\nexport async function fetchPricingCache(): Promise<PricingCacheFile | null> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const response = await fetch(PRICING_API_URL, {\n signal: controller.signal,\n headers: { Accept: 'application/json' },\n });\n if (!response.ok) return null;\n const data = (await response.json()) as PricingCacheFile;\n if (!Array.isArray(data.models)) return null;\n writePricingCache(getUserPricingCachePath(), data);\n return data;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\nfunction pickPricingRow(rows: PricingTierRow[], platform?: string): PricingTierRow | null {\n const textRows = rows.filter(r => !r.modality || r.modality === 'text');\n const pool = textRows.length > 0 ? textRows : rows;\n if (platform) {\n const platformStandard = pool.find(r => r.platform === platform && r.tier === 'standard');\n if (platformStandard) return platformStandard;\n const platformAny = pool.find(r => r.platform === platform);\n if (platformAny) return platformAny;\n }\n const standard = pool.find(r => r.tier === 'standard');\n if (standard) return standard;\n return pool[0] ?? null;\n}\n\nfunction rowToCost(row: PricingTierRow): CachedModel['cost'] | undefined {\n if (row.input_per_1m_tokens === undefined && row.output_per_1m_tokens === undefined) return undefined;\n return {\n input: row.input_per_1m_tokens ?? 0,\n output: row.output_per_1m_tokens ?? 0,\n };\n}\n\nexport function normalizeModelIdCandidates(id: string): string[] {\n const trimmed = id.trim();\n const lower = trimmed.toLowerCase();\n const candidates = new Set<string>([trimmed, lower]);\n for (const prefix of ['openrouter/', 'moonshotai/', 'anthropic/', 'openai/']) {\n if (lower.startsWith(prefix)) {\n candidates.add(lower.slice(prefix.length));\n candidates.add(trimmed.slice(prefix.length));\n }\n }\n const slash = lower.indexOf('/');\n if (slash > 0) {\n candidates.add(lower.slice(slash + 1));\n }\n return [...candidates];\n}\n\nexport interface PricingIndex {\n byId: Map<string, PricingModelEntry>;\n}\n\nexport function buildPricingIndex(cache: PricingCacheFile): PricingIndex {\n const byId = new Map<string, PricingModelEntry>();\n for (const entry of cache.models ?? []) {\n if (!entry.model_id) continue;\n for (const candidate of normalizeModelIdCandidates(entry.model_id)) {\n byId.set(candidate, entry);\n }\n if (entry.aliases) {\n for (const alias of Object.values(entry.aliases)) {\n for (const candidate of normalizeModelIdCandidates(alias)) {\n byId.set(candidate, entry);\n }\n }\n }\n }\n return { byId };\n}\n\nexport function lookupModelCost(\n index: PricingIndex,\n modelId: string,\n platform?: string,\n): CachedModel['cost'] | undefined {\n for (const candidate of normalizeModelIdCandidates(modelId)) {\n const entry = index.byId.get(candidate);\n if (!entry?.pricing?.length) continue;\n const row = pickPricingRow(entry.pricing, platform);\n const cost = row ? rowToCost(row) : undefined;\n if (cost) return cost;\n }\n return undefined;\n}\n\nexport function enrichModelsWithPricing(\n models: CachedModel[],\n index: PricingIndex,\n platform?: string,\n): CachedModel[] {\n return models.map(model => {\n const cost =\n lookupModelCost(index, model.id, platform) ??\n lookupModelCost(index, model.upstreamModelId, platform);\n if (!cost) return model;\n const freeStatus = classifyFreeStatus({\n model: { ...model, cost },\n // Keep provider-granted free access (e.g. Cloudflare's daily allowance) when\n // real pricing resolves later.\n freeAccess: model.freeStatus === 'free_provider',\n });\n return { ...model, cost, isFree: isFreeStatus(freeStatus), freeStatus };\n });\n}\n\n/**\n * Apply cached pricing for a specific registry provider. Token Plan credits are\n * not PAYG prices, so remove any cached pricing metadata rather than allowing\n * the generic fallback to select an unrelated standard row.\n */\nexport function enrichModelsForProviderPricing(\n models: CachedModel[],\n index: PricingIndex,\n templateId: string,\n providerId: string,\n): CachedModel[] {\n if (PRICING_OPT_OUT_TEMPLATE_IDS.has(templateId) || PRICING_OPT_OUT_TEMPLATE_IDS.has(providerId)) {\n return models.map(({ cost: _cost, isFree: _isFree, freeStatus: _freeStatus, ...model }) => model);\n }\n return enrichModelsWithPricing(\n models,\n index,\n pricingPlatformForProvider(templateId, providerId),\n );\n}\n\nexport function applyPricingToRegistryProviders(\n registry: import('./types.js').ProviderRegistry,\n cache: PricingCacheFile,\n): boolean {\n const index = buildPricingIndex(cache);\n let changed = false;\n for (const provider of registry.providers) {\n if (!provider.modelsCache?.models.length) continue;\n const enriched = enrichModelsForProviderPricing(\n provider.modelsCache.models,\n index,\n provider.templateId,\n provider.id,\n );\n if (JSON.stringify(enriched) !== JSON.stringify(provider.modelsCache.models)) {\n provider.modelsCache = { ...provider.modelsCache, models: enriched };\n changed = true;\n }\n }\n if (changed) {\n registry.pricingCacheAt = cache.generated_at ?? new Date().toISOString();\n }\n return changed;\n}\n\n/** Apply bundled or on-disk pricing cache synchronously (non-blocking enrich baseline). */\nexport function applyCachedPricing(): boolean {\n const registry = loadRegistry();\n const cache = loadPricingCache();\n const changed = applyPricingToRegistryProviders(registry, cache);\n if (changed) saveRegistry(registry);\n return changed;\n}\n\n/** Fetch latest pricing in the background; updates registry when complete. */\nexport function enrichPricingAsync(onComplete?: (updated: boolean) => void): void {\n void (async () => {\n const fetched = await fetchPricingCache();\n const cache = fetched ?? loadPricingCache();\n const registry = loadRegistry();\n const changed = applyPricingToRegistryProviders(registry, cache);\n if (changed) saveRegistry(registry);\n onComplete?.(changed);\n })();\n}\n\nexport function pricingPlatformForProvider(templateId: string, providerId: string): string | undefined {\n return TEMPLATE_TO_PRICING_PLATFORM[templateId] ?? TEMPLATE_TO_PRICING_PLATFORM[providerId];\n}\n","// src/model-compatibility.ts — curated blacklist + models.dev capability filtering\n\nimport blacklistData from './data/model-incompatible.json';\nimport {\n findModelsDevModel,\n loadModelsDevCache,\n shouldHideByModelsDevCapabilities,\n} from './registry/models-dev.js';\n\nexport type CompatibilityAgent = 'claude' | 'codex' | 'codex-app' | 'server' | 'gemini' | 'antigravity';\n\nexport interface CompatibilityContext {\n providerId: string;\n modelId: string;\n agent: CompatibilityAgent;\n}\n\nexport interface IncompatibleModelEntry {\n provider: string;\n modelId: string;\n category: string;\n reason: string;\n agents?: CompatibilityAgent[];\n sources?: string[];\n verifiedAt?: string;\n}\n\ninterface IncompatibleModelFile {\n schema_version?: string;\n entries?: IncompatibleModelEntry[];\n}\n\nconst BLACKLIST_ENTRIES = (blacklistData as IncompatibleModelFile).entries ?? [];\n\n// Cloud Code's fetchAvailableModels blob also contains tab-complete, chat, and\n// image-generation slots. Those are not agent models — drop them. Everything\n// else from the live catalog is shown; there is no Relay allowlist.\nconst ANTIGRAVITY_HELPER_SLOT = /^(tab_|chat_|models\\/)|image/i;\n\nexport function isAntigravityCloudCodeHelperSlot(modelId: string): boolean {\n return ANTIGRAVITY_HELPER_SLOT.test(modelId);\n}\n\nfunction matchesAgent(entryAgents: CompatibilityAgent[] | undefined, agent: CompatibilityAgent): boolean {\n if (!entryAgents || entryAgents.length === 0) return true;\n return entryAgents.includes(agent);\n}\n\nfunction matchesProvider(entryProvider: string, providerId: string): boolean {\n return entryProvider === providerId || entryProvider === '*';\n}\n\nexport function findBlacklistEntry(ctx: CompatibilityContext): IncompatibleModelEntry | null {\n for (const entry of BLACKLIST_ENTRIES) {\n if (entry.modelId !== ctx.modelId) continue;\n if (!matchesProvider(entry.provider, ctx.providerId)) continue;\n if (!matchesAgent(entry.agents, ctx.agent)) continue;\n return entry;\n }\n return null;\n}\n\nexport function hideReason(ctx: CompatibilityContext): string | null {\n if (ctx.providerId === 'antigravity' && isAntigravityCloudCodeHelperSlot(ctx.modelId)) {\n return '[antigravity-oauth] Cloud Code helper/internal slot';\n }\n\n const blacklist = findBlacklistEntry(ctx);\n if (blacklist) return `[blacklist:${blacklist.category}] ${blacklist.reason}`;\n\n const modelsDev = findModelsDevModel(ctx.providerId, ctx.modelId, loadModelsDevCache());\n if (modelsDev && shouldHideByModelsDevCapabilities(modelsDev)) {\n return '[models.dev] incompatible capabilities for coding agents';\n }\n\n return null;\n}\n\nexport function shouldHideModel(ctx: CompatibilityContext): boolean {\n return hideReason(ctx) !== null;\n}\n","// import-opencode.ts — merge API-key and OAuth providers for OpenCode import\n\nimport type { LocalProvider } from '../types.js';\nimport { normalizeProviders, type RawProvider } from '../providers.js';\nimport {\n isOpencodeOAuth,\n type OpencodeAuthEntry,\n type OpencodeOAuthCredential,\n} from './opencode-auth.js';\nimport { isLikelyPlaceholderKey } from './refresh-credentials.js';\n\nexport interface OAuthImportContext {\n oauthByProviderId: Map<string, OpencodeOAuthCredential>;\n}\n\nexport function oauthAuthRef(providerId: string): string {\n return `keyring:oauth:provider:${providerId}`;\n}\n\n/** Maps a canonical OAuth provider ID to its registry slot (openai → openai-oauth; others unchanged). */\nexport function toOAuthRegistryId(id: string): string {\n if (id === 'openai') return 'openai-oauth';\n if (id === 'xai') return 'xai-oauth';\n return id;\n}\n\nfunction normalizeImportProviderIdentity(provider: LocalProvider): LocalProvider {\n if (provider.id === 'opencode') {\n return { ...provider, id: 'zen', name: 'OpenCode Zen' };\n }\n if (provider.id === 'opencode-go') {\n return { ...provider, id: 'go', name: 'OpenCode Go' };\n }\n return provider;\n}\n\n/** Merge API-key providers from serve with OAuth providers backed by auth.json. */\nexport function buildImportProviderList(\n raw: RawProvider[],\n authEntries: Record<string, OpencodeAuthEntry>,\n): { providers: LocalProvider[]; oauth: OAuthImportContext } {\n const oauthByProviderId = new Map<string, OpencodeOAuthCredential>();\n const covered = new Set<string>();\n const merged: LocalProvider[] = [];\n\n for (const provider of normalizeProviders(raw)) {\n const normalized = normalizeImportProviderIdentity(provider);\n if (covered.has(normalized.id)) continue;\n merged.push(normalized);\n covered.add(normalized.id);\n }\n\n for (const provider of raw) {\n if (provider.id === 'opencode' || provider.id === 'opencode-go') continue;\n if (covered.has(provider.id)) continue;\n\n const authEntry = authEntries[provider.id];\n if (!isOpencodeOAuth(authEntry)) continue;\n\n const oauthProviders = normalizeProviders(\n [{ ...provider, key: authEntry.access }],\n { includeOAuthPlaceholders: true },\n );\n if (oauthProviders.length === 0) continue;\n\n const registryId = toOAuthRegistryId(provider.id);\n oauthByProviderId.set(registryId, authEntry);\n merged.push({ ...oauthProviders[0]!, id: registryId, apiKey: '' });\n covered.add(registryId);\n covered.add(provider.id);\n }\n\n return { providers: merged, oauth: { oauthByProviderId } };\n}\n\nexport function isOAuthImportProvider(providerId: string, oauth: OAuthImportContext): boolean {\n return oauth.oauthByProviderId.has(providerId);\n}\n\n/** OpenCode provider ids that authenticate via OAuth (not API keys). */\nexport const OPENCODE_OAUTH_PROVIDER_IDS = new Set([\n 'xai',\n 'openai',\n 'github',\n 'gitlab',\n 'kimi',\n 'moonshot',\n]);\n\n/** OpenCode stubs that use gcloud/AWS/Azure — never API key or OAuth import. */\nexport const OPENCODE_MANUAL_ONLY_IDS = new Set([\n 'google-vertex',\n 'vertex',\n 'bedrock',\n 'azure',\n]);\n\nexport type CredentialGapReason = 'oauth-no-token' | 'no-api-key' | 'manual-only';\n\nexport function classifyOpencodeCredentialGap(providerId: string): CredentialGapReason {\n if (OPENCODE_MANUAL_ONLY_IDS.has(providerId)) return 'manual-only';\n if (OPENCODE_OAUTH_PROVIDER_IDS.has(providerId)) return 'oauth-no-token';\n return 'no-api-key';\n}\n\n/**\n * Providers in OpenCode /config/providers with models but no importable credential.\n * Not all gaps are OAuth — Anthropic/Google often mean \"no API key in OpenCode\".\n */\nexport function listCredentialSkippedProviders(\n raw: RawProvider[],\n authEntries: Record<string, OpencodeAuthEntry>,\n importedIds: Set<string>,\n alreadyReportedIds: Set<string> = new Set(),\n registryProviderIds: Set<string> = new Set(),\n): Array<{ id: string; name: string; reason: CredentialGapReason }> {\n const skipped: Array<{ id: string; name: string; reason: CredentialGapReason }> = [];\n for (const provider of raw) {\n if (provider.id === 'opencode' || provider.id === 'opencode-go') continue;\n if (importedIds.has(provider.id)) continue;\n if (alreadyReportedIds.has(provider.id)) continue;\n const hasApiKey = !!provider.key?.trim() && !isLikelyPlaceholderKey(provider.key);\n if (hasApiKey) continue;\n if (isOpencodeOAuth(authEntries[provider.id])) continue;\n if (!provider.models || Object.keys(provider.models).length === 0) continue;\n\n const reason = classifyOpencodeCredentialGap(provider.id);\n // Only surface actionable gaps: OAuth sign-in needed, or a provider you already\n // use in relay-ai that OpenCode still has without credentials. Skip random OpenCode\n // catalog stubs (e.g. Google with models but no key) the user never configured.\n if (reason !== 'oauth-no-token' && !registryProviderIds.has(provider.id)) continue;\n\n skipped.push({ id: provider.id, name: provider.name, reason });\n }\n return skipped;\n}\n\n/** @deprecated Use listCredentialSkippedProviders */\nexport const listOAuthSkippedProviders = listCredentialSkippedProviders;\n","import { forceRefreshProviderCredential } from './env.js';\nimport { oauthAuthRef } from './registry/import-build.js';\n\n/**\n * Resolve the current raw OAuth access token for a registry provider.\n * `resolveProviderCredential` also performs the existing proactive refresh\n * and persists the refreshed credential when the stored token is expiring.\n */\nexport function providerRefreshToken(\n providerId: string | undefined,\n authType: 'api' | 'oauth' | 'none' | undefined,\n authRef?: string,\n): (() => Promise<string | null>) | undefined {\n if (authType !== 'oauth' || !providerId) return undefined;\n return () => forceRefreshProviderCredential(providerId, authRef ?? oauthAuthRef(providerId));\n}\n","// src/core/antigravity-model.ts — native Google LanguageModel over Cloud Code Assist.\n//\n// Core cannot start a local proxy. Cloud Code models are not OpenAI-compatible:\n// wrap @ai-sdk/google generateContent requests in the Cloud Code envelope and\n// unwrap `{response: ...}` so the Google SDK sees native Gemini payloads.\n\nimport { randomUUID } from 'node:crypto';\nimport type { LanguageModel } from 'ai';\nimport {\n ANTIGRAVITY_API_VERSION,\n ANTIGRAVITY_BASE_URLS,\n ANTIGRAVITY_USER_AGENT,\n} from '../oauth/antigravity-oauth.js';\n\nexport interface AntigravityCloudCodeModelOptions {\n modelId: string;\n accessToken: string;\n projectId: string;\n refreshToken?: () => Promise<string | null>;\n}\n\nconst CLOUD_CODE_BASE = ANTIGRAVITY_BASE_URLS[0]!.replace(/\\/+$/, '');\nconst STREAM_URL = `${CLOUD_CODE_BASE}/${ANTIGRAVITY_API_VERSION}:streamGenerateContent?alt=sse`;\nconst UNARY_URL = `${CLOUD_CODE_BASE}/${ANTIGRAVITY_API_VERSION}:generateContent`;\n/** Syntactically valid Google SDK prefix — every request is intercepted by custom fetch. */\nconst SDK_BASE_URL = `${CLOUD_CODE_BASE}/v1beta`;\n\nexport function unwrapCloudCodeSsePayload(payload: string): string {\n const trimmed = payload.trim();\n if (trimmed === '' || trimmed === '[DONE]') return payload;\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (isWrappedCloudCodeBody(parsed)) {\n return JSON.stringify(parsed.response);\n }\n } catch {\n // Malformed JSON / error events pass through unchanged.\n }\n return payload;\n}\n\nexport function unwrapCloudCodeJsonBody(text: string): string {\n try {\n const parsed: unknown = JSON.parse(text);\n if (isWrappedCloudCodeBody(parsed)) {\n return JSON.stringify(parsed.response);\n }\n } catch {\n // keep original\n }\n return text;\n}\n\nexport function consumeCloudCodeSseBuffer(buffer: string): { emitted: string; rest: string } {\n const separator = /\\r?\\n\\r?\\n/;\n let rest = buffer;\n let emitted = '';\n while (true) {\n const match = separator.exec(rest);\n if (!match || match.index === undefined) break;\n const rawEvent = rest.slice(0, match.index);\n const sep = match[0];\n rest = rest.slice(match.index + sep.length);\n emitted += transformSseEvent(rawEvent) + sep;\n }\n return { emitted, rest };\n}\n\nexport function createCloudCodeSseUnwrapper(): TransformStream<Uint8Array, Uint8Array> {\n const decoder = new TextDecoder();\n const encoder = new TextEncoder();\n let pending = '';\n return new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n pending += decoder.decode(chunk, { stream: true });\n const { emitted, rest } = consumeCloudCodeSseBuffer(pending);\n pending = rest;\n if (emitted) controller.enqueue(encoder.encode(emitted));\n },\n flush(controller) {\n pending += decoder.decode();\n if (!pending) return;\n const { emitted, rest } = consumeCloudCodeSseBuffer(pending);\n const tail = emitted + (rest ? transformSseEvent(rest) : '');\n if (tail) controller.enqueue(encoder.encode(tail));\n },\n });\n}\n\nexport function createCloudCodeFetch(\n options: AntigravityCloudCodeModelOptions,\n fetchImpl?: typeof globalThis.fetch,\n): typeof globalThis.fetch {\n let accessToken = options.accessToken;\n\n return async (input, init) => {\n const url = requestUrl(input);\n const streaming = url.includes('streamGenerateContent');\n const signal = init?.signal ?? (input instanceof Request ? input.signal : undefined);\n const geminiBody = await readJsonBody(input, init);\n const envelope = {\n project: options.projectId,\n requestId: randomUUID(),\n model: options.modelId,\n userAgent: ANTIGRAVITY_USER_AGENT,\n requestType: 'agent' as const,\n enabledCreditTypes: ['GOOGLE_ONE_AI'],\n request: geminiBody,\n };\n const body = JSON.stringify(envelope);\n const upstreamUrl = streaming ? STREAM_URL : UNARY_URL;\n const doFetch = fetchImpl ?? ((input: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(input, init));\n\n const send = (token: string) => doFetch(upstreamUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n 'User-Agent': ANTIGRAVITY_USER_AGENT,\n },\n body,\n signal,\n });\n\n let response: Response;\n try {\n response = await send(accessToken);\n } catch (err) {\n if (isAbortError(err, signal)) throw abortError(signal, err);\n throw err;\n }\n\n if (response.status === 401 && options.refreshToken && !signal?.aborted) {\n const refreshed = await options.refreshToken().catch(() => null);\n if (refreshed && refreshed !== accessToken && !signal?.aborted) {\n accessToken = refreshed;\n try {\n response = await send(accessToken);\n } catch (err) {\n if (isAbortError(err, signal)) throw abortError(signal, err);\n throw err;\n }\n }\n }\n\n return adaptUpstreamResponse(response, streaming);\n };\n}\n\nexport async function createAntigravityCloudCodeModel(\n options: AntigravityCloudCodeModelOptions,\n): Promise<LanguageModel> {\n const { createGoogleGenerativeAI } = await import('@ai-sdk/google');\n const google = createGoogleGenerativeAI({\n apiKey: 'relay-cloud-code',\n baseURL: SDK_BASE_URL,\n fetch: createCloudCodeFetch(options),\n });\n return google(options.modelId);\n}\n\nfunction isWrappedCloudCodeBody(parsed: unknown): parsed is { response: object } {\n return !!parsed\n && typeof parsed === 'object'\n && !Array.isArray(parsed)\n && 'response' in parsed\n && (parsed as { response: unknown }).response !== null\n && typeof (parsed as { response: unknown }).response === 'object';\n}\n\nfunction transformSseEvent(event: string): string {\n return event.replace(/^(data:[ \\t]*)(.*)$/gm, (_all, prefix: string, payload: string) => (\n `${prefix}${unwrapCloudCodeSsePayload(payload)}`\n ));\n}\n\nfunction requestUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') return input;\n if (input instanceof URL) return input.href;\n return input.url;\n}\n\nasync function readJsonBody(input: RequestInfo | URL, init?: RequestInit): Promise<unknown> {\n const body = init?.body;\n if (typeof body === 'string') return JSON.parse(body);\n if (body instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(body));\n if (body instanceof ArrayBuffer) return JSON.parse(new TextDecoder().decode(body));\n const request = input instanceof Request ? input.clone() : new Request(input, init);\n return request.json();\n}\n\nasync function adaptUpstreamResponse(upstream: Response, streaming: boolean): Promise<Response> {\n const fallbackType = streaming ? 'text/event-stream' : 'application/json';\n const contentType = upstream.headers.get('content-type') ?? fallbackType;\n const headers = new Headers({ 'Content-Type': contentType });\n if (!upstream.ok) {\n const errBody = await upstream.text();\n return new Response(errBody, {\n status: upstream.status,\n statusText: upstream.statusText,\n headers,\n });\n }\n if (streaming) {\n const body = upstream.body ? upstream.body.pipeThrough(createCloudCodeSseUnwrapper()) : null;\n return new Response(body, {\n status: upstream.status,\n statusText: upstream.statusText,\n headers,\n });\n }\n const text = await upstream.text();\n headers.set('Content-Type', 'application/json');\n return new Response(unwrapCloudCodeJsonBody(text), { status: 200, headers });\n}\n\nfunction isAbortError(err: unknown, signal?: AbortSignal): boolean {\n if (signal?.aborted) return true;\n return !!err && typeof err === 'object' && (err as { name?: string }).name === 'AbortError';\n}\n\nfunction abortError(signal: AbortSignal | undefined, cause?: unknown): Error {\n if (signal?.reason instanceof Error) return signal.reason;\n if (cause instanceof Error) return cause;\n return new DOMException('This operation was aborted', 'AbortError');\n}\n","// src/core/model.ts — construct a ready Vercel AI SDK LanguageModel from a route id.\n\nimport type { LanguageModel } from 'ai';\nimport {\n resolveProviderCredential,\n resolveProviderOAuthAccountId,\n resolveProviderOAuthProviderData,\n} from '../env.js';\nimport { createLanguageModel, type ProviderModelSpec } from '../provider-factory.js';\nimport { providerRefreshToken } from '../provider-runtime.js';\nimport type { CachedModel, RegistryProvider } from '../registry/types.js';\nimport { createAntigravityCloudCodeModel } from './antigravity-model.js';\nimport { loadCoreRegistry } from './catalog.js';\nimport { RelayCoreError, isRelayCoreError } from './errors.js';\nimport { parseRelayRouteId } from './route-id.js';\nimport type { CreateRelayModelOptions, RelayRouteId } from './types.js';\n\nfunction isAntigravityCloudCodeRoute(provider: RegistryProvider, model: CachedModel): boolean {\n return provider.id === 'antigravity'\n && provider.authType === 'oauth'\n && model.modelFormat === 'cloud-code';\n}\n\nfunction findRoute(registry: ReturnType<typeof loadCoreRegistry>, providerId: string, modelId: string, routeId: RelayRouteId): { provider: RegistryProvider; model: CachedModel } {\n const provider = registry.providers.find(p => p.id === providerId);\n if (!provider) {\n throw new RelayCoreError('ROUTE_NOT_FOUND', `No provider registered with id \"${providerId}\".`, { providerId, routeId });\n }\n if (!provider.enabled) {\n throw new RelayCoreError('PROVIDER_DISABLED', `Provider \"${provider.name}\" is disabled — enable it in relay-ai ui.`, { providerId, routeId });\n }\n const model = provider.modelsCache?.models.find(m => m.id === modelId);\n if (!model) {\n throw new RelayCoreError('UNSUPPORTED_MODEL', `Provider \"${provider.name}\" has no cached model \"${modelId}\" — refresh its models in relay-ai ui.`, { providerId, routeId });\n }\n return { provider, model };\n}\n\nasync function resolveCredential(provider: RegistryProvider, routeId: RelayRouteId): Promise<string> {\n try {\n const credential = await resolveProviderCredential(provider.id, provider.authRef);\n if (credential) return credential;\n if (provider.authType === 'none') return '';\n throw new RelayCoreError(\n 'CREDENTIAL_UNAVAILABLE',\n `No credential available for provider \"${provider.name}\" — re-authenticate in relay-ai ui.`,\n { providerId: provider.id, routeId },\n );\n } catch (err) {\n if (isRelayCoreError(err)) throw err;\n if (provider.authType === 'oauth') {\n throw new RelayCoreError(\n 'OAUTH_REFRESH_FAILED',\n `OAuth token refresh failed for provider \"${provider.name}\" — re-authenticate in relay-ai ui.`,\n { providerId: provider.id, routeId, cause: err },\n );\n }\n throw new RelayCoreError(\n 'PROVIDER_LOAD_FAILED',\n `Failed to resolve the credential for provider \"${provider.name}\".`,\n { providerId: provider.id, routeId, cause: err },\n );\n }\n}\n\n/**\n * Build a ready Vercel AI SDK `LanguageModel` for a `provider::model` route id.\n *\n * Re-reads the registry, credentials, and OAuth state on every call — nothing is\n * cached across calls, so a provider disabled or re-authenticated after the last\n * call takes effect without restarting the consumer process. Credentials are\n * resolved (and OAuth tokens refreshed) by Relay's existing machinery; the\n * credential and the intermediate spec never leave this function.\n */\nexport async function createRelayModel(routeId: RelayRouteId, options?: CreateRelayModelOptions): Promise<LanguageModel> {\n const { providerId, modelId } = parseRelayRouteId(routeId);\n const registry = loadCoreRegistry();\n const { provider, model } = findRoute(registry, providerId, modelId, routeId);\n\n if (isAntigravityCloudCodeRoute(provider, model)) {\n const apiKey = await resolveCredential(provider, routeId);\n const providerData = await resolveProviderOAuthProviderData(provider.authRef);\n const projectId = typeof providerData?.projectId === 'string' ? providerData.projectId.trim() : '';\n if (!projectId) {\n throw new RelayCoreError(\n 'CREDENTIAL_UNAVAILABLE',\n `Provider \"${provider.name}\" is missing project metadata — re-authenticate in relay-ai ui.`,\n { providerId: provider.id, routeId },\n );\n }\n try {\n return await createAntigravityCloudCodeModel({\n modelId: model.upstreamModelId ?? model.id,\n accessToken: apiKey,\n projectId,\n refreshToken: providerRefreshToken(provider.id, provider.authType, provider.authRef),\n });\n } catch (err) {\n if (isRelayCoreError(err)) throw err;\n throw new RelayCoreError(\n 'PROVIDER_LOAD_FAILED',\n `Failed to construct model \"${modelId}\" for provider \"${provider.name}\".`,\n { providerId, routeId, cause: err },\n );\n }\n }\n\n const npm = model.npm ?? provider.api.npm;\n if (!npm) {\n throw new RelayCoreError('UNSUPPORTED_MODEL', `Model \"${modelId}\" has no SDK provider package — refresh the provider's models in relay-ai ui.`, { providerId, routeId });\n }\n\n const apiKey = await resolveCredential(provider, routeId);\n\n let oauthAccountId: string | undefined;\n let providerData: Record<string, unknown> | undefined;\n if (provider.authType === 'oauth') {\n oauthAccountId = await resolveProviderOAuthAccountId(provider.authRef);\n providerData = await resolveProviderOAuthProviderData(provider.authRef);\n }\n\n const spec: ProviderModelSpec = {\n npm,\n modelId: model.upstreamModelId ?? model.id,\n apiKey,\n baseURL: model.apiUrl ?? provider.api.url,\n providerId: provider.id,\n authType: provider.authType,\n oauthAccountId,\n providerData,\n headers: provider.api.headers,\n refreshToken: providerRefreshToken(provider.id, provider.authType, provider.authRef),\n useResponsesLite: model.useResponsesLite,\n preferWebSockets: model.preferWebSockets,\n ...(options?.onDebug ? { onDebug: options.onDebug } : {}),\n };\n\n try {\n return await createLanguageModel(spec);\n } catch (err) {\n if (isRelayCoreError(err)) throw err;\n throw new RelayCoreError(\n 'PROVIDER_LOAD_FAILED',\n `Failed to construct model \"${modelId}\" for provider \"${provider.name}\".`,\n { providerId, routeId, cause: err },\n );\n }\n}\n"],"mappings":"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","names":["join","homedir","join","join","homedir","join","copyFileSync","existsSync","mkdirSync","readFileSync","renameSync","dirname","mkdirSync","dirname","existsSync","readFileSync","copyFileSync","renameSync","readFileSync","existsSync","readFileSync","homedir","join","DEVICE_CODE_DEFAULT_EXPIRES_MS","CLIENT_ID","DEVICE_CODE_DEFAULT_EXPIRES_MS","CLIENT_ID","TOKEN_URL","TOKEN_URL","open","readFileSync","homedir","TOKEN_URL","TOKEN_URL","chmodSync","existsSync","mkdirSync","readFileSync","writeFileSync","DIR_MODE","FILE_MODE","existsSync","readFileSync","mkdirSync","chmodSync","writeFileSync","chmodSync","existsSync","mkdirSync","readFileSync","statSync","writeFileSync","dirname","join","chmodSync","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","randomUUID","randomUUID","input","init","apiKey","providerData"]}
1
+ {"version":3,"sources":["../../src/config.ts","../../src/paths.ts","../../src/constants.ts","../../package.json","../../src/provider-factory.ts","../../src/oauth/refresh-http.ts","../../src/oauth/openai.ts","../../src/oauth/responses-websocket.ts","../../src/oauth/claude-identity.ts","../../src/cline-pass.ts","../../src/registry/io.ts","../../src/registry/types.ts","../../src/registry/migrate.ts","../../src/registry/validate.ts","../../src/core/errors.ts","../../src/core/reasoning.ts","../../src/core/route-id.ts","../../src/core/catalog.ts","../../src/context-window.ts","../../src/registry/opencode-auth.ts","../../src/oauth/types.ts","../../src/oauth/github.ts","../../src/oauth/xai.ts","../../src/oauth/claude-code.ts","../../src/oauth/antigravity-oauth.ts","../../src/oauth/callback-server.ts","../../src/oauth/cline-pass.ts","../../src/oauth/refresh.ts","../../src/secrets-file.ts","../../src/env.ts","../../src/data/model-incompatible.json","../../src/registry/models-dev.ts","../../src/registry/pricing.ts","../../src/model-compatibility.ts","../../src/registry/import-build.ts","../../src/provider-runtime.ts","../../src/core/antigravity-model.ts","../../src/core/model.ts"],"sourcesContent":["import type { UserPreferences, FavoriteModel } from './types.js';\nimport { dirname, join } from 'node:path';\nimport { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { getAppHome, getConfigPath, getLegacyAppHome, getLegacyConfPath } from './paths.js';\nimport { CODEX_SUBAGENT_MODEL_CAP } from './constants.js';\n\nfunction readJsonFile(path: string): UserPreferences | null {\n try {\n const parsed = JSON.parse(readFileSync(path, 'utf8'));\n return parsed && typeof parsed === 'object' ? parsed as UserPreferences : null;\n } catch {\n return null;\n }\n}\n\nfunction ensureAppHomeMigrated(): void {\n const configPath = getConfigPath();\n if (existsSync(configPath)) return;\n\n const legacyConfig = join(getLegacyAppHome(), 'config.json');\n if (!existsSync(legacyConfig)) return;\n\n mkdirSync(getAppHome(), { recursive: true, mode: 0o700 });\n copyFileSync(legacyConfig, configPath);\n\n const legacyVertex = join(getLegacyAppHome(), 'vertex-models.json');\n const vertexPath = join(getAppHome(), 'vertex-models.json');\n if (existsSync(legacyVertex) && !existsSync(vertexPath)) {\n copyFileSync(legacyVertex, vertexPath);\n }\n}\n\nfunction ensureConfigMigrated(): void {\n ensureAppHomeMigrated();\n\n const configPath = getConfigPath();\n if (existsSync(configPath)) return;\n\n const legacyPath = getLegacyConfPath();\n if (!existsSync(legacyPath)) return;\n\n const legacy = readJsonFile(legacyPath);\n if (!legacy) return;\n\n mkdirSync(dirname(configPath), { recursive: true, mode: 0o700 });\n writeFileSync(configPath, `${JSON.stringify(legacy, null, 2)}\\n`, { encoding: 'utf8', mode: 0o600 });\n\n try {\n renameSync(legacyPath, `${legacyPath}.migrated`);\n } catch {\n // Migration copy is enough; renaming is best-effort.\n }\n}\n\nfunction readConfig(): UserPreferences {\n ensureConfigMigrated();\n return readJsonFile(getConfigPath()) ?? {};\n}\n\nfunction writeConfig(config: UserPreferences): void {\n const configPath = getConfigPath();\n mkdirSync(dirname(configPath), { recursive: true, mode: 0o700 });\n writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, { encoding: 'utf8', mode: 0o600 });\n}\n\nexport function loadPreferences(): UserPreferences {\n const config = readConfig();\n const lastProvider =\n config.lastProvider === 'opencode' ? 'zen' : config.lastProvider;\n return {\n lastBackend: config.lastBackend,\n lastModel: config.lastModel,\n lastProvider,\n lastCodexProvider: config.lastCodexProvider,\n lastCodexModel: config.lastCodexModel,\n lastGeminiProvider: config.lastGeminiProvider,\n lastGeminiModel: config.lastGeminiModel,\n lastAntigravityProvider: config.lastAntigravityProvider,\n lastAntigravityModel: config.lastAntigravityModel,\n lastClaudeTransparentMode: config.lastClaudeTransparentMode,\n recentModelsByProvider: config.recentModelsByProvider,\n favoriteModels: config.favoriteModels,\n codexSubagentModels: Array.isArray(config.codexSubagentModels)\n ? config.codexSubagentModels.slice(0, CODEX_SUBAGENT_MODEL_CAP)\n : undefined,\n antigravityCliFavoriteModels: config.antigravityCliFavoriteModels,\n antigravityCliFavoritesHintShown: config.antigravityCliFavoritesHintShown,\n appPathOverrides: config.appPathOverrides,\n recentLaunchFolders: config.recentLaunchFolders,\n server: config.server,\n };\n}\n\nexport function savePreferences(prefs: Partial<Pick<UserPreferences, 'lastBackend' | 'lastModel' | 'lastProvider' | 'lastCodexProvider' | 'lastCodexModel' | 'lastGeminiProvider' | 'lastGeminiModel' | 'lastAntigravityProvider' | 'lastAntigravityModel' | 'lastClaudeTransparentMode' | 'recentModelsByProvider' | 'favoriteModels' | 'codexSubagentModels' | 'antigravityCliFavoriteModels' | 'antigravityCliFavoritesHintShown' | 'appPathOverrides' | 'recentLaunchFolders'>>): void {\n const config = readConfig();\n if (prefs.lastBackend !== undefined) config.lastBackend = prefs.lastBackend;\n if (prefs.lastModel !== undefined) config.lastModel = prefs.lastModel;\n if (prefs.lastProvider !== undefined) config.lastProvider = prefs.lastProvider;\n if (prefs.lastCodexProvider !== undefined) config.lastCodexProvider = prefs.lastCodexProvider;\n if (prefs.lastCodexModel !== undefined) config.lastCodexModel = prefs.lastCodexModel;\n if (prefs.lastGeminiProvider !== undefined) config.lastGeminiProvider = prefs.lastGeminiProvider;\n if (prefs.lastGeminiModel !== undefined) config.lastGeminiModel = prefs.lastGeminiModel;\n if (prefs.lastAntigravityProvider !== undefined) config.lastAntigravityProvider = prefs.lastAntigravityProvider;\n if (prefs.lastAntigravityModel !== undefined) config.lastAntigravityModel = prefs.lastAntigravityModel;\n if (prefs.lastClaudeTransparentMode !== undefined) config.lastClaudeTransparentMode = prefs.lastClaudeTransparentMode;\n if (prefs.recentModelsByProvider !== undefined) config.recentModelsByProvider = prefs.recentModelsByProvider;\n if (prefs.favoriteModels !== undefined) config.favoriteModels = prefs.favoriteModels;\n if (prefs.codexSubagentModels !== undefined) {\n config.codexSubagentModels = prefs.codexSubagentModels.slice(0, CODEX_SUBAGENT_MODEL_CAP);\n }\n if (prefs.antigravityCliFavoriteModels !== undefined) config.antigravityCliFavoriteModels = prefs.antigravityCliFavoriteModels;\n if (prefs.antigravityCliFavoritesHintShown !== undefined) config.antigravityCliFavoritesHintShown = prefs.antigravityCliFavoritesHintShown;\n if (prefs.appPathOverrides !== undefined) config.appPathOverrides = prefs.appPathOverrides;\n if (prefs.recentLaunchFolders !== undefined) config.recentLaunchFolders = prefs.recentLaunchFolders;\n writeConfig(config);\n}\n\nexport function getAppPathOverride(appId: string): string | undefined {\n const value = loadPreferences().appPathOverrides?.[appId];\n return typeof value === 'string' && value.trim() ? value : undefined;\n}\n\nexport function setAppPathOverride(appId: string, path: string | null): Record<string, string> {\n const config = readConfig();\n const next = { ...(config.appPathOverrides ?? {}) };\n const trimmed = path?.trim() ?? '';\n if (trimmed) next[appId] = trimmed;\n else delete next[appId];\n config.appPathOverrides = next;\n if (Object.keys(next).length === 0) delete config.appPathOverrides;\n writeConfig(config);\n return next;\n}\n\nconst MAX_RECENT_MODELS = 3;\nconst MAX_RECENT_LAUNCH_FOLDERS = 6;\n\nexport function recordLaunchFolder(folder: string): string[] {\n const trimmed = folder.trim();\n if (!trimmed) return loadPreferences().recentLaunchFolders ?? [];\n const config = readConfig();\n const prev = config.recentLaunchFolders ?? [];\n const next = [trimmed, ...prev.filter(path => path !== trimmed)].slice(0, MAX_RECENT_LAUNCH_FOLDERS);\n config.recentLaunchFolders = next;\n writeConfig(config);\n return next;\n}\n\nexport function recordLaunchSelection(\n agent: 'claude' | 'codex' | 'gemini',\n providerId: string,\n modelId: string,\n prefs: UserPreferences,\n): void {\n const prevRecent = prefs.recentModelsByProvider?.[providerId] ?? [];\n const updatedRecent = [modelId, ...prevRecent.filter(id => id !== modelId)].slice(0, MAX_RECENT_MODELS);\n savePreferences({\n ...(agent === 'claude'\n ? { lastProvider: providerId, lastModel: modelId }\n : agent === 'codex'\n ? { lastCodexProvider: providerId, lastCodexModel: modelId }\n : { lastGeminiProvider: providerId, lastGeminiModel: modelId }),\n recentModelsByProvider: { ...prefs.recentModelsByProvider, [providerId]: updatedRecent },\n });\n}\n\nconst SERVER_PASSWORD_SERVICE = 'relay-ai-server-password';\nconst SERVER_PASSWORD_ACCOUNT = 'server-password';\n\nasync function getServerPasswordKeyring(): Promise<any | null> {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n return new Entry(SERVER_PASSWORD_SERVICE, SERVER_PASSWORD_ACCOUNT);\n } catch {\n return null;\n }\n}\n\nexport async function getSavedServerPassword(): Promise<string | null> {\n const config = readConfig();\n if (config.server?.savedPassword) {\n const pwd = config.server.savedPassword;\n const keyring = await getServerPasswordKeyring();\n if (keyring) {\n try {\n await keyring.setPassword(pwd);\n delete config.server.savedPassword;\n if (Object.keys(config.server).length === 0) delete config.server;\n writeConfig(config);\n } catch {\n // Fallback: keep in config.json if keyring fails\n }\n }\n return pwd;\n }\n\n const keyring = await getServerPasswordKeyring();\n if (keyring) {\n try {\n return await keyring.getPassword();\n } catch {\n return null;\n }\n }\n return null;\n}\n\n/** Network gateway password from env (Docker / Compose / quick-start). Never log this. */\nexport function getEnvServerPassword(): string | null {\n const value = process.env['RELAY_AI_SERVER_PASSWORD']?.trim();\n return value || null;\n}\n\n/** Prefer RELAY_AI_SERVER_PASSWORD, then a saved password. */\nexport async function resolveConfiguredServerPassword(): Promise<string | null> {\n return getEnvServerPassword() ?? (await getSavedServerPassword());\n}\n\nexport async function setSavedServerPassword(password: string): Promise<void> {\n const keyring = await getServerPasswordKeyring();\n if (keyring) {\n try {\n await keyring.setPassword(password);\n return;\n } catch {\n // Fallback\n }\n }\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n savedPassword: password,\n };\n writeConfig(config);\n}\n\nexport async function clearSavedServerPassword(): Promise<void> {\n const keyring = await getServerPasswordKeyring();\n if (keyring) {\n try {\n await keyring.deletePassword();\n } catch {\n // Ignore\n }\n }\n const config = readConfig();\n if (!config.server) return;\n delete config.server.savedPassword;\n if (Object.keys(config.server).length === 0) delete config.server;\n writeConfig(config);\n}\n\nexport function getServerExposedProviders(): string[] | null {\n const list = readConfig().server?.exposedProviders;\n return list && list.length > 0 ? list : null;\n}\n\nexport function setServerExposedProviders(providerIds: string[]): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n exposedProviders: providerIds,\n };\n writeConfig(config);\n}\n\nexport function getServerMaskGatewayIds(): boolean {\n return readConfig().server?.maskGatewayIds ?? true;\n}\n\nexport function setServerMaskGatewayIds(mask: boolean): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n maskGatewayIds: mask,\n };\n writeConfig(config);\n}\n\nexport function getServerFavoritesOnly(): boolean {\n return readConfig().server?.favoritesOnly ?? false;\n}\n\nexport function setServerFavoritesOnly(favoritesOnly: boolean): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n favoritesOnly,\n };\n writeConfig(config);\n}\n\nexport function getServerFreeModelsOnly(): boolean {\n return readConfig().server?.freeModelsOnly ?? false;\n}\n\nexport function setServerFreeModelsOnly(freeModelsOnly: boolean): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n freeModelsOnly,\n };\n writeConfig(config);\n}\n\nexport function getServerListenMode(): 'local' | 'network' {\n return readConfig().server?.listenMode === 'network' ? 'network' : 'local';\n}\n\nexport function setServerListenMode(listenMode: 'local' | 'network'): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n listenMode,\n };\n writeConfig(config);\n}\n\nexport function getServerAutostart(): boolean {\n return readConfig().server?.autostart ?? false;\n}\n\nexport function setServerAutostart(autostart: boolean): void {\n const config = readConfig();\n config.server = {\n ...(config.server ?? {}),\n autostart,\n };\n writeConfig(config);\n}\n\n/** Check RELAY_AI_SERVER_AUTOSTART env var first, then config preference. */\nexport function resolveServerAutostart(env: NodeJS.ProcessEnv = process.env): boolean {\n const envVal = env['RELAY_AI_SERVER_AUTOSTART']?.trim().toLowerCase();\n if (envVal !== undefined && envVal !== '') {\n return ['1', 'true', 'yes', 'on'].includes(envVal);\n }\n return getServerAutostart();\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport const APP_DIR_NAME = 'relay-ai';\nexport const LEGACY_APP_DIR_NAME = 'opencode-starter';\n\ninterface HomeEnv {\n APPDATA?: string;\n HOME?: string;\n RELAY_AI_HOME?: string;\n /** @deprecated Use RELAY_AI_HOME */\n OPENCODE_STARTER_HOME?: string;\n USERPROFILE?: string;\n XDG_CONFIG_HOME?: string;\n}\n\nfunction userHome(env: HomeEnv = process.env): string {\n return env.HOME ?? env.USERPROFILE ?? homedir();\n}\n\nexport function resolveAppHomeOverride(env: HomeEnv = process.env): string | undefined {\n const override = env.RELAY_AI_HOME ?? env.OPENCODE_STARTER_HOME;\n return override?.trim() || undefined;\n}\n\nexport function getAppHome(env: HomeEnv = process.env): string {\n const override = resolveAppHomeOverride(env);\n if (override) return override;\n return join(userHome(env), `.${APP_DIR_NAME}`);\n}\n\nexport function getLegacyAppHome(env: HomeEnv = process.env): string {\n return join(userHome(env), `.${LEGACY_APP_DIR_NAME}`);\n}\n\nexport function getConfigPath(env: HomeEnv = process.env): string {\n return join(getAppHome(env), 'config.json');\n}\n\nexport function getProvidersPath(env: HomeEnv = process.env): string {\n return join(getAppHome(env), 'providers.json');\n}\n\nexport function getSecretsPath(env: HomeEnv = process.env): string {\n return join(getAppHome(env), 'secrets.json');\n}\n\nexport function getLogsPath(env: HomeEnv = process.env): string {\n return join(getAppHome(env), 'logs');\n}\n\nexport function getVertexModelsPath(env: HomeEnv = process.env): string {\n return join(getAppHome(env), 'vertex-models.json');\n}\n\nexport function getLegacyConfPath(env: HomeEnv = process.env, platform = process.platform): string {\n const home = userHome(env);\n const appName = `${LEGACY_APP_DIR_NAME}-nodejs`;\n\n if (platform === 'darwin') {\n return join(home, 'Library', 'Preferences', appName, 'config.json');\n }\n\n if (platform === 'win32') {\n return join(env.APPDATA ?? join(home, 'AppData', 'Roaming'), appName, 'Config', 'config.json');\n }\n\n return join(env.XDG_CONFIG_HOME ?? join(home, '.config'), appName, 'config.json');\n}\n","// src/constants.ts\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport pkg from '../package.json' with { type: 'json' };\nimport type { BackendConfig, ModelFormat } from './types.js';\n\nexport const BACKENDS: Record<'zen' | 'go', BackendConfig> = {\n zen: {\n id: 'zen',\n name: 'OpenCode Zen',\n // No /v1 suffix — the Anthropic SDK appends /v1/messages automatically\n baseUrl: 'https://opencode.ai/zen',\n },\n go: {\n id: 'go',\n name: 'OpenCode Go',\n baseUrl: 'https://opencode.ai/zen/go',\n },\n};\n\n// ChatGPT Codex Responses-Lite WebSocket transport (used by models the backend\n// flags with prefer_websockets, e.g. gpt-5.6-luna).\nexport const CODEX_RESPONSES_LITE_WS_URL = 'wss://chatgpt.com/backend-api/codex/responses';\n// `version` header the Codex backend expects on Responses-Lite requests. The\n// official Codex CLI sends its own version here; OpenAI may require this to be\n// bumped over time — confirm via --trace if Luna requests start failing.\nexport const CODEX_RESPONSES_LITE_VERSION = '0.144.1';\n// OpenAI-Beta opt-in for the WebSocket Responses transport.\nexport const CODEX_RESPONSES_WEBSOCKETS_BETA = 'responses_websockets=2026-02-06';\n\n// These must be removed from the child process environment to avoid conflicts\n// with Vertex AI, Bedrock, AWS, Foundry, and any stale Anthropic config.\nexport const CONFLICTING_ENV_VARS = [\n 'CLAUDE_CODE_USE_VERTEX',\n 'ANTHROPIC_VERTEX_PROJECT_ID',\n 'ANTHROPIC_VERTEX_BASE_URL',\n 'CLOUD_ML_REGION',\n 'ANTHROPIC_BEDROCK_BASE_URL',\n 'ANTHROPIC_AWS_BASE_URL',\n 'ANTHROPIC_AWS_API_KEY',\n 'ANTHROPIC_AWS_WORKSPACE_ID',\n 'ANTHROPIC_FOUNDRY_API_KEY',\n 'ANTHROPIC_FOUNDRY_BASE_URL',\n 'ANTHROPIC_AUTH_TOKEN',\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_BASE_URL',\n 'ANTHROPIC_MODEL',\n 'ANTHROPIC_DEFAULT_OPUS_MODEL',\n 'ANTHROPIC_DEFAULT_SONNET_MODEL',\n 'ANTHROPIC_DEFAULT_HAIKU_MODEL',\n] as const;\n\nexport type ConflictingEnvVar = (typeof CONFLICTING_ENV_VARS)[number];\n\n// When relay-ai launches Claude Code from inside an existing Claude Code\n// session (its own terminal, a Code tab, an agent's shell), these identity\n// vars leak into the spawned child via process.env inheritance. The new\n// process then misidentifies itself as a nested child of the outer session\n// (e.g. CLAUDE_CODE_CHILD_SESSION disables transcript saving) even though\n// it's meant to be a fresh top-level launch. Strip before spawning.\nexport const PARENT_SESSION_ENV_VARS = [\n 'CLAUDECODE',\n 'CLAUDE_CODE_CHILD_SESSION',\n 'CLAUDE_CODE_SESSION_ID',\n 'CLAUDE_CODE_HOST_SESSION_ID',\n 'CLAUDE_CODE_ENTRYPOINT',\n 'CLAUDE_PID',\n] as const;\n\n// Optional enrichment from OpenCode CLI (~/.cache/opencode/models.json) — not a runtime dependency.\nexport const OPENCODE_CACHE_PATH = join(homedir(), '.cache', 'opencode', 'models.json');\n\n/** Max models in favorites list and mid-session /model switch catalog. */\nexport const MAX_MODEL_CATALOG = 20;\n\n/** Codex redirects every marked child session to this one explicit Relay model. */\nexport const CODEX_SUBAGENT_MODEL_CAP = 1;\n\n/**\n * Smallest context window worth offering: agent system prompts plus tool definitions\n * consume ~25K before the first user message, so smaller models fail immediately.\n * Antigravity enforces its own, higher floor (see `ANTIGRAVITY_MIN_CONTEXT_WINDOW`).\n */\nexport const MIN_CONTEXT_WINDOW = 128000;\n\n/** Vercel AI SDK package for Anthropic Claude models on Google Vertex AI (ADC auth). */\nexport const VERTEX_ANTHROPIC_NPM = '@ai-sdk/google-vertex/anthropic';\n\n// Classify a model's API format based on cache provider data or ID heuristics.\n// Used to decide whether to route directly or through the translation proxy.\nexport function classifyModelFormat(\n modelId: string,\n providerNpm: string | undefined,\n): ModelFormat {\n if (providerNpm === '@ai-sdk/anthropic') return 'anthropic';\n if (providerNpm === '@ai-sdk/openai') return 'unsupported';\n if (providerNpm === '@ai-sdk/google') return 'unsupported';\n\n // Fallback: ID-prefix heuristics for models not in cache\n const lower = modelId.toLowerCase();\n if (lower.startsWith('claude-')) return 'anthropic';\n if (lower.startsWith('gpt-')) return 'unsupported';\n if (lower.startsWith('gemini-')) return 'unsupported';\n\n return 'openai';\n}\n\nexport const VERSION = pkg.version;\n","{\n \"name\": \"@jacobbd/relay-ai\",\n \"version\": \"0.9.3\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"description\": \"Relay any model into any coding agent — launch Claude Code, Codex, and more with multi-provider gateways\",\n \"author\": \"jacob-bd\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jacob-bd/relay-ai.git\"\n },\n \"homepage\": \"https://github.com/jacob-bd/relay-ai#readme\",\n \"keywords\": [\n \"claude\",\n \"claude-code\",\n \"codex\",\n \"ai\",\n \"llm\",\n \"cli\",\n \"gateway\",\n \"relay\",\n \"vertex\"\n ],\n \"type\": \"module\",\n \"bin\": {\n \"relay-ai\": \"dist/cli.js\"\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"engines\": {\n \"node\": \">=18\"\n },\n \"scripts\": {\n \"build\": \"tsup && tsup --config tsup.core.config.ts && node scripts/copy-ui-assets.mjs\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run --exclude \\\"tests/debug-*.test.ts\\\"\",\n \"test:live\": \"vitest run tests/debug-xai.test.ts tests/debug-openai-oauth.test.ts\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\",\n \"release:check\": \"node scripts/release-metadata.mjs\",\n \"refresh:models-dev\": \"node scripts/refresh-models-dev-cache.mjs\",\n \"prepublishOnly\": \"npm run release:check && npm run build\"\n },\n \"dependencies\": {\n \"@ai-sdk/alibaba\": \"^1.0.26\",\n \"@ai-sdk/amazon-bedrock\": \"^4.0.113\",\n \"@ai-sdk/azure\": \"^3.0.70\",\n \"@ai-sdk/cerebras\": \"^2.0.54\",\n \"@ai-sdk/cohere\": \"^3.0.36\",\n \"@ai-sdk/deepinfra\": \"^2.0.52\",\n \"@ai-sdk/gateway\": \"^3.0.125\",\n \"@ai-sdk/google\": \"^3.0.80\",\n \"@ai-sdk/google-vertex\": \"^4.0.142\",\n \"@ai-sdk/groq\": \"^3.0.39\",\n \"@ai-sdk/mistral\": \"^3.0.37\",\n \"@ai-sdk/openai\": \"^3.0.68\",\n \"@ai-sdk/openai-compatible\": \"^2.0.48\",\n \"@ai-sdk/perplexity\": \"^3.0.33\",\n \"@ai-sdk/togetherai\": \"^2.0.53\",\n \"@ai-sdk/vercel\": \"^2.0.50\",\n \"@ai-sdk/xai\": \"^3.0.93\",\n \"@clack/prompts\": \"^0.9.1\",\n \"@openrouter/ai-sdk-provider\": \"^2.9.0\",\n \"ai\": \"^6.0.197\",\n \"cross-spawn\": \"^7.0.6\",\n \"gitlab-ai-provider\": \"^6.8.0\",\n \"graphql\": \"^16.14.2\",\n \"ipaddr.js\": \"^2.4.0\",\n \"node-forge\": \"^1.4.0\",\n \"open\": \"^11.0.0\",\n \"picocolors\": \"^1.1.1\",\n \"smol-toml\": \"^1.6.1\",\n \"venice-ai-sdk-provider\": \"^2.0.2\",\n \"ws\": \"^8.21.0\",\n \"zod\": \"^3.25.76\"\n },\n \"devDependencies\": {\n \"@types/cross-spawn\": \"^6.0.6\",\n \"@types/node\": \"^22.0.0\",\n \"@types/node-forge\": \"^1.3.14\",\n \"@types/ws\": \"^8.18.1\",\n \"@vitest/coverage-v8\": \"^4.1.10\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.5.0\",\n \"vite-node\": \"^6.0.0\",\n \"vitest\": \"^4.1.10\"\n },\n \"optionalDependencies\": {\n \"@napi-rs/keyring\": \"^1.3.0\"\n },\n \"overrides\": {\n \"ws\": \"^8.21.0\"\n },\n \"exports\": {\n \"./core\": {\n \"types\": \"./dist/core/index.d.ts\",\n \"import\": \"./dist/core/index.js\",\n \"default\": \"./dist/core/index.js\"\n },\n \"./package.json\": \"./package.json\"\n }\n}\n","// Maps an OpenCode provider's `npm` package (the field providers.ts already\n// reads) to a Vercel AI SDK LanguageModel instance. The SDK owns wire format,\n// endpoint selection, and provider quirks.\nimport type { LanguageModel } from 'ai';\nimport { wrapLanguageModel, extractReasoningMiddleware } from 'ai';\nimport { VERTEX_ANTHROPIC_NPM, CODEX_RESPONSES_LITE_VERSION, CODEX_RESPONSES_LITE_WS_URL } from './constants.js';\nimport { extractOpenAiAccountId } from './oauth/openai.js';\nimport { createResponsesWebSocketFetch } from './oauth/responses-websocket.js';\nimport {\n CLAUDE_CODE_USER_AGENT,\n injectClaudeIdentity,\n} from './oauth/claude-identity.js';\nimport {\n createClinePassOAuthFetch,\n formatClineRuntimeCredential,\n isClinePassOAuth,\n} from './cline-pass.js';\n\n/** Models that must use /v1/responses instead of /v1/chat/completions. */\nconst RESPONSES_ONLY_PREFIXES = [\n 'gpt-5-codex',\n 'gpt-5-pro',\n 'gpt-5.2-pro',\n 'o3',\n 'o4',\n];\n\ntype SdkProviderFactory = (options: {\n apiKey: string;\n baseURL?: string;\n name?: string;\n headers?: Record<string, string>;\n fetch?: typeof globalThis.fetch;\n}) => {\n (modelId: string): LanguageModel;\n chat: (modelId: string) => LanguageModel;\n responses: (modelId: string) => LanguageModel;\n};\n\nconst factoryCache = new Map<string, Promise<SdkProviderFactory>>();\n\n/**\n * True when a model id must use the OpenAI/xAI Responses API instead of\n * chat/completions. The SDK reflects this by selecting `provider.responses(id)`.\n */\nexport function modelPrefersResponsesApi(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n if (RESPONSES_ONLY_PREFIXES.some(prefix => lower === prefix || lower.startsWith(`${prefix}-`))) {\n return true;\n }\n // gpt-5.4 and later minor versions require the Responses API (e.g. gpt-5.4, gpt-5.5, gpt-5.6, gpt-5.6-fast).\n const gpt5Minor = lower.match(/^gpt-5\\.(\\d+)(?:-|$)/);\n if (gpt5Minor && Number(gpt5Minor[1]) >= 4) return true;\n // Versioned Codex IDs (e.g. gpt-5.3-codex) don't match the gpt-5-codex prefix.\n if (lower.startsWith('gpt-') && lower.includes('-codex')) return true;\n // xAI multiagent models (e.g. grok-4.20-multi-agent, grok-4.2-multiagent).\n if (lower.startsWith('grok-') && (lower.includes('multi-agent') || lower.includes('multiagent'))) return true;\n return false;\n}\n\n/**\n * OpenAI's Responses API is a strict superset of Chat Completions for every\n * current model — there is no OpenAI model that Chat Completions can serve\n * that Responses cannot. So route every OpenAI model through Responses by\n * default, except pre-chat legacy completion models that predate both APIs\n * and are not agentic chat models at all.\n */\nconst OPENAI_CHAT_COMPLETIONS_ONLY = [\n 'davinci-002',\n 'babbage-002',\n 'gpt-3.5-turbo-instruct',\n];\n\nexport function shouldUseOpenAiResponsesEndpoint(modelId: string): boolean {\n return !OPENAI_CHAT_COMPLETIONS_ONLY.includes(modelId.toLowerCase());\n}\n\nexport interface VertexProviderConfig {\n project: string;\n location: string;\n}\n\nexport interface ProviderModelSpec {\n /** OpenCode `api.npm` package, e.g. `@ai-sdk/xai`. */\n npm: string;\n modelId: string;\n apiKey: string;\n /** Base URL for openai-compatible / openrouter providers (no trailing path). */\n baseURL?: string;\n /** Provider id for naming openai-compatible instances (diagnostics only). */\n providerId?: string;\n /** Registry authentication mode. OpenAI OAuth uses the ChatGPT Codex backend. */\n authType?: 'api' | 'oauth' | 'none';\n oauthAccountId?: string;\n providerData?: Record<string, unknown>;\n /** Google Vertex AI — uses Application Default Credentials, not apiKey. */\n vertex?: VertexProviderConfig;\n /** Static headers sent on every upstream request (e.g. a plan/auth-tracking header a custom endpoint requires). */\n headers?: Record<string, string>;\n /** Refresh an OAuth access token after the SDK receives one 401 response. */\n refreshToken?: () => Promise<string | null>;\n /** Persist a newly refreshed raw token for future requests. */\n onTokenRefreshed?: (token: string) => void;\n /** Backend capability: model requires the Responses-Lite request shape (x-openai-internal-codex-responses-lite). */\n useResponsesLite?: boolean;\n /** Backend capability: model must use the WebSocket Responses transport instead of HTTP. */\n preferWebSockets?: boolean;\n /** Optional debug logger (wired to the proxy trace log) for transport-level diagnostics. */\n onDebug?: (msg: string) => void;\n}\n\n/** True when this provider routes through the SDK adapter (local providers + Zen/Go openai-format). */\nexport function isSdkMigratedNpm(npm: string | undefined): boolean {\n return !!npm && npm !== '@ai-sdk/anthropic';\n}\n\nexport function maxToolsForNpm(npm: string | undefined): number | undefined {\n return npm === '@ai-sdk/groq' ? 128 : undefined;\n}\n\nfunction findCreateFactory(mod: Record<string, unknown>): SdkProviderFactory {\n for (const value of Object.values(mod)) {\n if (typeof value === 'function' && value.name.startsWith('create')) {\n return value as SdkProviderFactory;\n }\n }\n throw new Error('No create* factory export found in provider package');\n}\n\nasync function loadSdkProviderFactory(npm: string): Promise<SdkProviderFactory> {\n let cached = factoryCache.get(npm);\n if (!cached) {\n cached = (async () => {\n try {\n const mod = await import(npm);\n return findCreateFactory(mod as Record<string, unknown>);\n } catch (err) {\n const code = err && typeof err === 'object' && 'code' in err ? err.code : undefined;\n if (code === 'ERR_MODULE_NOT_FOUND') {\n throw new Error(`SDK provider package not installed: ${npm}. Run: npm install ${npm}`);\n }\n throw err;\n }\n })();\n factoryCache.set(npm, cached);\n cached.catch(() => factoryCache.delete(npm));\n }\n return cached;\n}\n\nexport async function createLanguageModel(spec: ProviderModelSpec): Promise<LanguageModel> {\n const { npm, modelId, apiKey, baseURL } = spec;\n\n if (npm === VERTEX_ANTHROPIC_NPM) {\n if (!spec.vertex?.project) {\n throw new Error('Vertex project is required for @ai-sdk/google-vertex/anthropic');\n }\n const { createVertexAnthropic } = await import('@ai-sdk/google-vertex/anthropic');\n const vertex = createVertexAnthropic({\n project: spec.vertex.project,\n location: spec.vertex.location,\n });\n return vertex(modelId);\n }\n\n if (npm === '@ai-sdk/openai') {\n const { createOpenAI } = await import('@ai-sdk/openai');\n const accountId = spec.authType === 'oauth'\n ? spec.oauthAccountId ?? extractOpenAiAccountId({ access_token: apiKey })\n : undefined;\n const oauthOptions = spec.authType === 'oauth'\n ? {\n apiKey,\n baseURL: 'https://chatgpt.com/backend-api/codex',\n headers: {\n ...(accountId ? { 'ChatGPT-Account-Id': accountId } : {}),\n originator: 'relay-ai',\n // Responses-Lite models (backend prefer_websockets/use_responses_lite,\n // e.g. gpt-5.6-luna) require these on the request.\n ...(spec.useResponsesLite\n ? { version: CODEX_RESPONSES_LITE_VERSION, 'x-openai-internal-codex-responses-lite': 'true' }\n : {}),\n },\n // Models the backend flags with prefer_websockets are only served over\n // the WebSocket Responses transport, not HTTP.\n ...(spec.preferWebSockets\n ? { fetch: createResponsesWebSocketFetch(CODEX_RESPONSES_LITE_WS_URL, spec.onDebug) }\n : {}),\n }\n : { apiKey };\n const openai = createOpenAI(oauthOptions);\n return shouldUseOpenAiResponsesEndpoint(modelId) ? openai.responses(modelId) : openai.chat(modelId);\n }\n if (npm === '@ai-sdk/xai') {\n const { createXai } = await import('@ai-sdk/xai');\n const xai = createXai({ apiKey });\n return modelPrefersResponsesApi(modelId) ? xai.responses(modelId) : xai(modelId);\n }\n // @ai-sdk/google owns its native v1beta endpoint. Registry templates store the\n // OpenAI-compatible URL only for GET /v1/models discovery — passing it here\n // produces .../v1beta/openai/models/...:streamGenerateContent → 404.\n if (npm === '@ai-sdk/google') {\n const { createGoogleGenerativeAI } = await import('@ai-sdk/google');\n const google = createGoogleGenerativeAI({ apiKey });\n return google(modelId);\n }\n // Registry stores root URL (no /v1) for GET /v1/models discovery — passing it here\n // makes the SDK call https://api.anthropic.com/messages → 404.\n if (npm === '@ai-sdk/anthropic') {\n const { createAnthropic } = await import('@ai-sdk/anthropic');\n const root = baseURL?.replace(/\\/v1\\/?$/, '').replace(/\\/$/, '');\n const anthropicOptions: Parameters<typeof createAnthropic>[0] = spec.authType === 'oauth'\n ? {\n authToken: apiKey,\n ...(spec.providerId === 'claude-code'\n ? {\n headers: {\n 'User-Agent': CLAUDE_CODE_USER_AGENT,\n 'x-app': 'cli',\n 'X-Claude-Code-Session-Id': injectClaudeIdentity(\n {},\n spec.providerData,\n spec.oauthAccountId ?? apiKey,\n ).sessionId,\n },\n }\n : {}),\n }\n : { apiKey };\n if (spec.headers) {\n anthropicOptions.headers = { ...anthropicOptions.headers, ...spec.headers };\n }\n if (!root || root === 'https://api.anthropic.com') {\n return createAnthropic(anthropicOptions)(modelId);\n }\n const sdkBase = baseURL!.endsWith('/v1') ? baseURL : `${root}/v1`;\n return createAnthropic({ ...anthropicOptions, baseURL: sdkBase })(modelId);\n }\n let model: LanguageModel;\n\n if (npm === '@ai-sdk/openai-compatible') {\n const { createOpenAICompatible } = await import('@ai-sdk/openai-compatible');\n const runtimeApiKey = formatClineRuntimeCredential(spec.providerId, spec.authType, apiKey);\n const options = {\n name: spec.providerId ?? 'openai-compatible',\n baseURL: baseURL ?? '',\n ...(runtimeApiKey.trim() ? { apiKey: runtimeApiKey } : {}),\n ...(spec.headers ? { headers: spec.headers } : {}),\n ...(isClinePassOAuth(spec.providerId, spec.authType) && spec.refreshToken\n ? {\n fetch: createClinePassOAuthFetch(\n runtimeApiKey,\n spec.refreshToken,\n spec.onTokenRefreshed,\n ),\n }\n : {}),\n };\n model = createOpenAICompatible({\n ...options,\n })(modelId);\n } else if (npm === '@openrouter/ai-sdk-provider') {\n const { createOpenRouter } = await import('@openrouter/ai-sdk-provider');\n model = createOpenRouter({ apiKey, baseURL, ...(spec.headers ? { headers: spec.headers } : {}) })(modelId);\n } else {\n const create = await loadSdkProviderFactory(npm);\n const provider = create({\n apiKey,\n ...(baseURL ? { baseURL } : {}),\n ...(spec.headers ? { headers: spec.headers } : {}),\n });\n model = provider(modelId);\n }\n\n const isReasoning = modelId.toLowerCase().match(/deepseek-r1|think|reasoning|qwq/);\n if (isReasoning) {\n return wrapLanguageModel({\n model: model as Parameters<typeof wrapLanguageModel>[0]['model'],\n middleware: [extractReasoningMiddleware({ tagName: 'think' })],\n }) as unknown as LanguageModel;\n }\n\n return model;\n}\n\nexport type ReasoningMode = 'none' | 'internal-only' | 'controllable';\nexport type ReasoningSource = 'provider-metadata' | 'provider-rule' | 'model-metadata' | 'none';\nexport type ReasoningConfidence = 'verified' | 'documented' | 'inferred';\nexport type ReasoningWireFormat =\n | { kind: 'openrouter-reasoning' }\n | { kind: 'openai-reasoning-effort' }\n | { kind: 'anthropic-thinking' }\n | { kind: 'google-thinking-config' }\n | { kind: 'mistral-reasoning-effort' }\n | { kind: 'deepseek-thinking' };\n\nexport interface ReasoningMetadata {\n providerId?: string;\n apiBaseUrl?: string;\n supportedParameters?: string[];\n reasoning?: boolean;\n interleavedReasoningField?: string;\n /**\n * Bare upstream model id (e.g. 'grok-4.5'), distinct from the request's `model`\n * field which may be a gateway alias or catalog slug (e.g. 'xai-oauth__grok-4.5').\n * Reasoning-capability id-pattern checks must match against this, not body.model.\n */\n upstreamModelId?: string;\n}\n\nexport interface ReasoningCapabilities {\n levels: string[];\n defaultLevel: string;\n supportsSummaries: boolean;\n mode: ReasoningMode;\n source: ReasoningSource;\n confidence: ReasoningConfidence;\n wireFormat?: ReasoningWireFormat;\n}\n\nconst ANTHROPIC_EFFORT_LEVELS = ['low', 'medium', 'high'] as const;\nconst OPENAI_EFFORT_LEVELS = ['low', 'medium', 'high'] as const;\nconst OPENAI_XHIGH_EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh'] as const;\nconst GEMINI_EFFORT_LEVELS = ['low', 'medium', 'high'] as const;\nconst MISTRAL_EFFORT_LEVELS = ['high', 'off'] as const;\n/**\n * xAI's accepted reasoning_effort values differ by transport, per the installed\n * adapter's own docs (`@ai-sdk/xai/docs/01-xai.mdx`): chat models take\n * `low | high`, Responses models take `low | medium | high`. Neither accepts a\n * `none`/`xhigh` value, so neither is offered.\n */\nconst XAI_CHAT_EFFORT_LEVELS = ['low', 'high'] as const;\nconst XAI_RESPONSES_EFFORT_LEVELS = ['low', 'medium', 'high'] as const;\nconst OPENROUTER_EFFORT_LEVELS = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh'] as const;\n/** DeepSeek V4 wire values (low/medium map to high; xhigh maps to max). */\nconst DEEPSEEK_EFFORT_LEVELS = ['high', 'max', 'off'] as const;\n/** GLM-5.2 published efforts (OpenRouter metadata): high and xhigh, default high. */\nconst GLM_52_EFFORT_LEVELS = ['high', 'xhigh'] as const;\n\nconst EMPTY_REASONING: ReasoningCapabilities = {\n levels: [],\n defaultLevel: '',\n supportsSummaries: false,\n mode: 'none',\n source: 'none',\n confidence: 'inferred',\n};\n\nconst EFFORT_DESCRIPTIONS: Record<string, string> = {\n off: 'Turn off extended reasoning',\n none: 'No reasoning',\n minimal: 'Minimal reasoning',\n low: 'Light reasoning',\n medium: 'Balanced reasoning',\n high: 'Deep reasoning',\n xhigh: 'Maximum reasoning',\n max: 'Maximum effort',\n};\n\nconst GEMINI_25_BUDGETS: Record<string, number> = {\n low: 1024,\n medium: 4096,\n high: 8192,\n xhigh: 16384,\n max: 16384,\n minimal: 512,\n none: 0,\n};\n\n/** Claude adaptive-thinking models (opus/sonnet/haiku 4.6+, fable, mythos). */\nfunction isClaudeReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n if (!lower.startsWith('claude-')) return false;\n if (lower.includes('fable') || lower.includes('mythos')) return true;\n const m = lower.match(/claude-(?:opus|sonnet|haiku)-(\\d+)-(\\d+)/);\n if (!m) return false;\n const major = Number(m[1]);\n const minor = Number(m[2]);\n return major > 4 || (major === 4 && minor >= 6);\n}\n\nfunction isGeminiReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower.startsWith('gemini-2.5-')\n || lower.startsWith('gemini-3')\n || lower.startsWith('gemini-3.');\n}\n\nfunction isGemini3Model(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower.startsWith('gemini-3') || lower.startsWith('gemini-3.');\n}\n\nfunction isMistralReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower.startsWith('mistral-')\n || lower.startsWith('magistral-')\n || lower.startsWith('ministral-')\n || lower.includes('reasoning');\n}\n\n/**\n * xAI models that accept `reasoning_effort` on the wire (per xAI docs).\n * models.dev `reasoning: true` is broader — e.g. grok-build-0.1 reasons internally\n * but rejects reasoningEffort (HTTP 400).\n */\nfunction isXaiReasoningEffortModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n if (lower.includes('non-reasoning')) return false;\n if (lower.startsWith('grok-build')) return false;\n if (lower.startsWith('grok-imagine')) return false;\n if (modelPrefersResponsesApi(modelId)) return true;\n if (lower === 'grok-4.3' || lower.startsWith('grok-4.3-')) return true;\n if (lower === 'grok-4.5' || lower.startsWith('grok-4.5-')) return true;\n if (lower.includes('-reasoning')) return true;\n return false;\n}\n\n/**\n * xAI's own default reasoning_effort when the param is omitted (per xAI docs).\n * Varies by model — grok-4.3 defaults to 'low', grok-4.5 defaults to 'high'.\n */\nfunction xaiDefaultReasoningEffort(modelId: string): string {\n const lower = modelId.toLowerCase();\n if (lower === 'grok-4.5' || lower.startsWith('grok-4.5-')) return 'high';\n return 'low';\n}\n\n/** DeepSeek V4 models with thinking mode + reasoning_effort (direct API). */\nfunction isDeepSeekReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower === 'deepseek-v4-flash'\n || lower === 'deepseek-v4-pro'\n || lower.startsWith('deepseek-v4-flash-')\n || lower.startsWith('deepseek-v4-pro-')\n || lower === 'deepseek-reasoner'\n || lower === 'deepseek-chat';\n}\n\nfunction isKimiReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower.startsWith('kimi-');\n}\n\n// Keep exact matching. Kimi uses prefix matching, but switching GLM to prefix\n// would newly classify vendor-aliased IDs as reasoning models. That is a\n// behavior change, not duplication cleanup.\nfunction isGlm52ReasoningModel(modelId: string): boolean {\n const lower = modelId.toLowerCase();\n return lower === 'glm-5.2'\n || lower === 'z-ai/glm-5.2'\n || lower === 'zai/glm-5.2'\n || lower === 'zai-org/glm-5.2'\n || lower === 'zai-org/glm5.2'\n || lower === 'glm5.2';\n}\n\nfunction toCamelCase(str: string): string {\n return str.replace(/[-_]([a-z])/g, (_, g) => g.toUpperCase());\n}\n\nfunction hasSupportedParameter(metadata: ReasoningMetadata | undefined, param: string): boolean {\n return (metadata?.supportedParameters ?? []).some(p => p === param);\n}\n\nfunction isOpenRouterRoute(npm: string, metadata?: ReasoningMetadata): boolean {\n return npm === '@openrouter/ai-sdk-provider'\n || metadata?.providerId === 'openrouter'\n || metadata?.apiBaseUrl?.includes('openrouter.ai') === true;\n}\n\nfunction openRouterReasoningCapabilities(metadata?: ReasoningMetadata): ReasoningCapabilities {\n if (metadata?.supportedParameters && !hasSupportedParameter(metadata, 'reasoning')) {\n return {\n ...EMPTY_REASONING,\n source: 'provider-metadata',\n confidence: 'documented',\n };\n }\n if (hasSupportedParameter(metadata, 'reasoning')) {\n return {\n levels: [...OPENROUTER_EFFORT_LEVELS],\n defaultLevel: 'medium',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-metadata',\n confidence: 'documented',\n wireFormat: { kind: 'openrouter-reasoning' },\n };\n }\n if (metadata?.reasoning) {\n return {\n ...EMPTY_REASONING,\n mode: 'internal-only',\n source: 'model-metadata',\n confidence: 'inferred',\n };\n }\n return EMPTY_REASONING;\n}\n\nfunction mapCodexEffortToDeepSeek(effort: string): 'high' | 'max' | 'off' | undefined {\n switch (effort) {\n case 'off':\n case 'none':\n return 'off';\n case 'low':\n case 'medium':\n case 'high':\n return 'high';\n case 'xhigh':\n case 'max':\n return 'max';\n default:\n if (effort === 'high' || effort === 'max') return effort;\n return undefined;\n }\n}\n\n/** DeepSeek thinking toggle spreads via provider id keys on @ai-sdk/openai-compatible. */\nfunction deepSeekEffortProviderOptions(\n effort: string,\n): Record<string, Record<string, unknown>> | undefined {\n const mapped = mapCodexEffortToDeepSeek(effort);\n if (!mapped) return undefined;\n const thinking = { type: mapped === 'off' ? 'disabled' : 'enabled' };\n const spread = { thinking };\n if (mapped === 'off') {\n return {\n deepseek: spread,\n openaiCompatible: spread,\n };\n }\n return {\n openaiCompatible: { reasoningEffort: mapped, ...spread },\n deepseek: spread,\n };\n}\n\nfunction mapCodexEffortToAnthropic(effort: string): string | undefined {\n switch (effort) {\n case 'none':\n case 'minimal':\n case 'low':\n return 'low';\n case 'medium':\n return 'medium';\n case 'high':\n case 'xhigh':\n case 'max':\n return effort === 'xhigh' ? 'high' : effort === 'max' ? 'max' : 'high';\n default:\n if (ANTHROPIC_EFFORT_LEVELS.includes(effort as typeof ANTHROPIC_EFFORT_LEVELS[number])) {\n return effort;\n }\n return undefined;\n }\n}\n\ninterface OpenAiReasoningProfile {\n levels: readonly string[];\n defaultLevel: string;\n}\n\n/**\n * Reasoning-effort profile per **exact** OpenAI model id.\n *\n * Sourced from developers.openai.com model pages (verified 2026-08-14) rather\n * than the installed `@ai-sdk/openai` docs, which still describe `xhigh` as\n * GPT-5.1-Codex-Max-only and are behind the API.\n *\n * Matching is deliberately exact, not prefix-based. A named descendant is a\n * different model with a different effort set — `gpt-5.5-pro` drops `none`/`low`\n * and defaults to `high`, `gpt-5.2-codex` drops `none`, and\n * `gpt-5.2-chat-latest` has no reasoning at all. Letting `gpt-5.5` classify\n * every `gpt-5.5-*` id would advertise values OpenAI rejects. The only alias\n * treated as the same model is a dated snapshot suffix.\n *\n * Unlisted reasoning models fall back to OPENAI_EFFORT_LEVELS, which\n * under-offers rather than sending a value the model may reject. Add entries\n * only with a documented source; re-check when new models ship.\n */\nconst OPENAI_MODEL_REASONING: Readonly<Record<string, OpenAiReasoningProfile>> = {\n 'gpt-5-pro': { levels: ['high'], defaultLevel: 'high' },\n 'gpt-5.1': { levels: ['none', 'low', 'medium', 'high'], defaultLevel: 'none' },\n 'gpt-5.1-codex-max': { levels: ['low', 'medium', 'high', 'xhigh'], defaultLevel: 'medium' },\n 'gpt-5.2': { levels: ['none', 'low', 'medium', 'high', 'xhigh'], defaultLevel: 'none' },\n 'gpt-5.2-codex': { levels: ['low', 'medium', 'high', 'xhigh'], defaultLevel: 'medium' },\n 'gpt-5.2-pro': { levels: ['medium', 'high', 'xhigh'], defaultLevel: 'medium' },\n 'gpt-5.3-codex': { levels: ['low', 'medium', 'high', 'xhigh'], defaultLevel: 'medium' },\n 'gpt-5.4': { levels: ['none', 'low', 'medium', 'high', 'xhigh'], defaultLevel: 'none' },\n 'gpt-5.4-mini': { levels: ['none', 'low', 'medium', 'high', 'xhigh'], defaultLevel: 'none' },\n 'gpt-5.4-nano': { levels: ['none', 'low', 'medium', 'high', 'xhigh'], defaultLevel: 'none' },\n 'gpt-5.4-pro': { levels: ['medium', 'high', 'xhigh'], defaultLevel: 'medium' },\n 'gpt-5.5': { levels: ['none', 'low', 'medium', 'high', 'xhigh'], defaultLevel: 'medium' },\n 'gpt-5.5-pro': { levels: ['medium', 'high', 'xhigh'], defaultLevel: 'high' },\n 'gpt-5.6': { levels: ['none', 'low', 'medium', 'high', 'xhigh', 'max'], defaultLevel: 'medium' },\n 'gpt-5.6-luna': { levels: ['none', 'low', 'medium', 'high', 'xhigh', 'max'], defaultLevel: 'medium' },\n 'gpt-5.6-sol': { levels: ['none', 'low', 'medium', 'high', 'xhigh', 'max'], defaultLevel: 'medium' },\n 'gpt-5.6-terra': { levels: ['none', 'low', 'medium', 'high', 'xhigh', 'max'], defaultLevel: 'medium' },\n};\n\n/**\n * Chat-tuned ids documented as having no reasoning-effort support at all.\n *\n * This overrides `metadata.reasoning`: the bundled models.dev cache marks some\n * of these as reasoning-capable, and trusting it would advertise (and send) an\n * effort OpenAI rejects for the model.\n */\nconst OPENAI_NON_REASONING_MODELS = new Set([\n 'chat-latest',\n 'gpt-5-chat-latest',\n 'gpt-5.1-chat-latest',\n 'gpt-5.2-chat-latest',\n 'gpt-5.3-chat-latest',\n]);\n\n/** `gpt-5.5-2026-04-23` is the same model as `gpt-5.5`; `gpt-5.5-pro` is not. */\nconst OPENAI_DATED_SNAPSHOT_SUFFIX = /-\\d{4}-\\d{2}-\\d{2}$/;\n\n/**\n * The id capabilities are decided by: what actually goes on the wire.\n *\n * Catalog ids can be aliases (`gpt-5.5-fast` → `gpt-5.5`), so classifying by\n * the local id would give an alias the wrong — or no — profile, and Codex would\n * then rewrite a valid saved `xhigh` down to the fallback default.\n */\nfunction canonicalOpenAiModelId(modelId: string | undefined, metadata?: ReasoningMetadata): string {\n return (metadata?.upstreamModelId ?? modelId ?? '').toLowerCase();\n}\n\n/** The documented profile for a model, or undefined when it isn't listed. */\nfunction openAiReasoningProfile(modelId: string | undefined, metadata?: ReasoningMetadata): OpenAiReasoningProfile | undefined {\n const id = canonicalOpenAiModelId(modelId, metadata);\n if (!id) return undefined;\n return OPENAI_MODEL_REASONING[id]\n ?? OPENAI_MODEL_REASONING[id.replace(OPENAI_DATED_SNAPSHOT_SUFFIX, '')];\n}\n\n/**\n * Does this OpenAI model reason at all? Shared by the capability table and the\n * request mapper so they cannot disagree — otherwise the mapper happily builds\n * a `reasoning_effort` for a chat model the catalog reports as non-reasoning.\n * Deliberately free of any call back into `getReasoningCapabilities`, which\n * filters its levels *through* the mapper.\n */\nfunction openAiModelReasons(modelId: string, metadata?: ReasoningMetadata): boolean {\n const id = canonicalOpenAiModelId(modelId, metadata);\n if (OPENAI_NON_REASONING_MODELS.has(id.replace(OPENAI_DATED_SNAPSHOT_SUFFIX, ''))) return false;\n return !!openAiReasoningProfile(modelId, metadata) || modelPrefersResponsesApi(id) || !!metadata?.reasoning;\n}\n\n/**\n * First-party OpenAI/Azure: the value is sent verbatim when the model documents\n * it, and omitted otherwise. Never substituted — collapsing `xhigh` to `high`\n * silently sent a weaker level than the caller asked for, and sending `xhigh`\n * to a model without it is an upstream 400.\n */\nfunction mapCodexEffortToOpenAI(effort: string, allowed: readonly string[]): string | undefined {\n return allowed.includes(effort) ? effort : undefined;\n}\n\n/** Legacy nearest-value mapping, still used by metadata-inferred routes. */\nfunction mapCodexEffortToOpenAICompatible(effort: string): string | undefined {\n if (effort === 'xhigh') return 'high';\n const allowed = ['low', 'medium', 'high'];\n return allowed.includes(effort) ? effort : undefined;\n}\n\nfunction mapCodexEffortToGlm52(effort: string): 'high' | 'max' | undefined {\n switch (effort) {\n case 'high':\n return 'high';\n case 'xhigh':\n case 'max':\n return 'max';\n default:\n return undefined;\n }\n}\n\n/** `supportsMedium` is true only for the Responses transport — see XAI_*_EFFORT_LEVELS. */\nfunction mapCodexEffortToXai(effort: string, supportsMedium: boolean): string | undefined {\n switch (effort) {\n case 'low':\n return 'low';\n case 'medium':\n // Chat has no 'medium'; returning 'low' there would be a silent downgrade.\n return supportsMedium ? 'medium' : undefined;\n case 'high':\n case 'xhigh':\n case 'max':\n return 'high';\n default:\n return undefined; // none/minimal have no xAI equivalent\n }\n}\n\nfunction mapCodexEffortToGeminiLevel(effort: string): 'low' | 'medium' | 'high' | undefined {\n switch (effort) {\n case 'none':\n case 'minimal':\n case 'low':\n return 'low';\n case 'medium':\n return 'medium';\n case 'high':\n case 'xhigh':\n case 'max':\n return 'high';\n default:\n return GEMINI_EFFORT_LEVELS.includes(effort as typeof GEMINI_EFFORT_LEVELS[number])\n ? effort as 'low' | 'medium' | 'high'\n : undefined;\n }\n}\n\nfunction mapCodexEffortToGeminiBudget(effort: string): number | undefined {\n const direct = GEMINI_25_BUDGETS[effort];\n if (direct !== undefined) return direct > 0 ? direct : undefined;\n const level = mapCodexEffortToGeminiLevel(effort);\n if (!level) return undefined;\n return GEMINI_25_BUDGETS[level];\n}\n\n/**\n * Keep the advertised levels and the actual request mapping in lockstep.\n *\n * The capability table dispatches largely on *model id* while\n * `effortProviderOptions` dispatches on the SDK *package*, so the two used to\n * disagree — e.g. GLM/DeepSeek/Kimi ids served through `@ai-sdk/alibaba`\n * advertised levels that mapped to nothing, and xAI advertised a `none` its API\n * has no value for. Filtering the advertised list through the mapper makes that\n * class of drift impossible rather than merely fixed once.\n */\nfunction withMappableLevels(\n caps: ReasoningCapabilities,\n npm: string,\n modelId: string,\n metadata?: ReasoningMetadata,\n): ReasoningCapabilities {\n if (caps.mode !== 'controllable') return caps;\n // Keep a level only if it maps to a request at all, *and* to one no\n // lower-ranked level already produces. Two levels that send identical bytes\n // are one level with two names — offering both means the weaker-sounding\n // choice silently wins, which is the substitution this contract forbids.\n const seen = new Set<string>();\n const levels = caps.levels.filter(level => {\n const mapped = effortProviderOptions(npm, level, modelId, metadata);\n if (mapped === undefined) return false;\n const wire = JSON.stringify(mapped);\n if (seen.has(wire)) return false;\n seen.add(wire);\n return true;\n });\n if (levels.length === caps.levels.length) return caps;\n if (levels.length === 0) {\n // Reasons, but nothing about it can actually be set from here.\n return { ...caps, levels: [], defaultLevel: '', mode: 'internal-only' };\n }\n return {\n ...caps,\n levels,\n defaultLevel: levels.includes(caps.defaultLevel) ? caps.defaultLevel : levels[levels.length - 1]!,\n };\n}\n\n/** Per-model reasoning UI + wire metadata for Codex catalog and adapters. */\nexport function getReasoningCapabilities(\n npm: string,\n modelId: string,\n metadata?: ReasoningMetadata,\n): ReasoningCapabilities {\n return withMappableLevels(resolveRawReasoningCapabilities(npm, modelId, metadata), npm, modelId, metadata);\n}\n\nfunction resolveRawReasoningCapabilities(\n npm: string,\n modelId: string,\n metadata?: ReasoningMetadata,\n): ReasoningCapabilities {\n const id = modelId.toLowerCase();\n\n if (isOpenRouterRoute(npm, metadata)) {\n return openRouterReasoningCapabilities(metadata);\n }\n\n if (npm === '@ai-sdk/anthropic' || id.startsWith('claude-')) {\n const isClaude = isClaudeReasoningModel(modelId);\n if (isClaude || metadata?.reasoning) {\n return {\n levels: [...ANTHROPIC_EFFORT_LEVELS],\n defaultLevel: 'high',\n supportsSummaries: true,\n mode: 'controllable',\n source: isClaude ? 'provider-rule' : 'model-metadata',\n confidence: isClaude ? 'documented' : 'inferred',\n wireFormat: { kind: 'anthropic-thinking' },\n };\n }\n return EMPTY_REASONING;\n }\n\n if (npm === '@ai-sdk/openai' || npm === '@ai-sdk/azure') {\n // Everything below keys off the id that actually reaches OpenAI, not a\n // local catalog alias.\n const canonicalId = canonicalOpenAiModelId(modelId, metadata);\n const profile = openAiReasoningProfile(modelId, metadata);\n const prefersResponses = modelPrefersResponsesApi(canonicalId);\n // Two separate questions: does this model reason at all, and can this\n // transport carry `reasoning_effort`? Only the Responses endpoint can, and\n // that decision has to match the one the model factory actually makes.\n if (openAiModelReasons(modelId, metadata) && shouldUseOpenAiResponsesEndpoint(canonicalId)) {\n const levels = profile?.levels ?? [...OPENAI_EFFORT_LEVELS];\n return {\n levels: [...levels],\n defaultLevel: profile?.defaultLevel\n ?? (levels.includes('medium') ? 'medium' : levels[levels.length - 1]!),\n supportsSummaries: true,\n source: profile || prefersResponses ? 'provider-rule' : 'model-metadata',\n confidence: profile || prefersResponses ? 'documented' : 'inferred',\n mode: 'controllable',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n return EMPTY_REASONING;\n }\n\n if (npm === '@ai-sdk/google' || id.startsWith('gemini-')) {\n if (isGeminiReasoningModel(modelId)) {\n return {\n levels: [...GEMINI_EFFORT_LEVELS],\n defaultLevel: 'medium',\n supportsSummaries: true,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'google-thinking-config' },\n };\n }\n return EMPTY_REASONING;\n }\n\n if (npm === '@ai-sdk/mistral') {\n if (isMistralReasoningModel(modelId)) {\n return {\n levels: [...MISTRAL_EFFORT_LEVELS],\n defaultLevel: 'high',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'mistral-reasoning-effort' },\n };\n }\n return EMPTY_REASONING;\n }\n\n if (npm === '@ai-sdk/xai') {\n if (isXaiReasoningEffortModel(modelId)) {\n const levels = modelPrefersResponsesApi(modelId)\n ? [...XAI_RESPONSES_EFFORT_LEVELS]\n : [...XAI_CHAT_EFFORT_LEVELS];\n return {\n levels,\n defaultLevel: xaiDefaultReasoningEffort(modelId),\n supportsSummaries: true,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n return EMPTY_REASONING;\n }\n\n if (isDeepSeekReasoningModel(modelId)) {\n return {\n levels: [...DEEPSEEK_EFFORT_LEVELS],\n defaultLevel: 'high',\n supportsSummaries: true,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'deepseek-thinking' },\n };\n }\n\n if (isKimiReasoningModel(modelId)) {\n return {\n levels: [...OPENAI_EFFORT_LEVELS],\n defaultLevel: 'high',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n\n if (isGlm52ReasoningModel(modelId)) {\n return {\n levels: [...GLM_52_EFFORT_LEVELS],\n defaultLevel: 'high',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-rule',\n confidence: 'documented',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n\n if (hasSupportedParameter(metadata, 'reasoning_effort')) {\n return {\n levels: ['low', 'medium', 'high', 'xhigh'],\n defaultLevel: 'medium',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-metadata',\n confidence: 'documented',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n\n if (hasSupportedParameter(metadata, 'reasoning')) {\n return {\n levels: [...OPENROUTER_EFFORT_LEVELS],\n defaultLevel: 'medium',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'provider-metadata',\n confidence: 'documented',\n wireFormat: { kind: 'openrouter-reasoning' },\n };\n }\n\n if (metadata?.reasoning) {\n return {\n levels: ['low', 'medium', 'high'],\n defaultLevel: 'medium',\n supportsSummaries: false,\n mode: 'controllable',\n source: 'model-metadata',\n confidence: 'inferred',\n wireFormat: { kind: 'openai-reasoning-effort' },\n };\n }\n\n return EMPTY_REASONING;\n}\n\nexport function buildCodexReasoningLevels(\n capabilities: Pick<ReasoningCapabilities, 'levels'>,\n): Array<{ effort: string; description: string }> {\n return capabilities.levels.map(effort => ({\n effort,\n description: EFFORT_DESCRIPTIONS[effort] ?? effort,\n }));\n}\n\n/** Per-provider providerOptions for user-selected reasoning effort. */\nexport function effortProviderOptions(\n npm: string,\n effort?: string,\n modelId?: string,\n metadata?: ReasoningMetadata,\n): Record<string, Record<string, unknown>> | undefined {\n if (!effort) return undefined;\n\n if (isOpenRouterRoute(npm, metadata)) {\n const caps = openRouterReasoningCapabilities(metadata);\n if (caps.mode !== 'controllable') return undefined;\n const allowed = new Set(OPENROUTER_EFFORT_LEVELS);\n const mapped = allowed.has(effort as typeof OPENROUTER_EFFORT_LEVELS[number])\n ? effort\n : effort === 'max'\n ? 'xhigh'\n : undefined;\n return mapped\n ? { openrouter: { reasoning: { effort: mapped, exclude: false } } }\n : undefined;\n }\n\n if (npm === '@ai-sdk/openai' || npm === '@ai-sdk/azure') {\n // `reasoning_effort` only exists on the Responses transport — use the same\n // decision the model factory makes, not the narrower \"prefers responses\" —\n // and only for models that reason at all. Keyed on the upstream id so an\n // alias route gets its real model's levels.\n if (!modelId || !shouldUseOpenAiResponsesEndpoint(canonicalOpenAiModelId(modelId, metadata))) return undefined;\n if (!openAiModelReasons(modelId, metadata)) return undefined;\n const allowed = openAiReasoningProfile(modelId, metadata)?.levels ?? OPENAI_EFFORT_LEVELS;\n const reasoningEffort = mapCodexEffortToOpenAI(effort, allowed);\n return reasoningEffort ? { openai: { reasoningEffort } } : undefined;\n }\n\n if (npm === '@ai-sdk/xai') {\n if (!modelId || !isXaiReasoningEffortModel(modelId)) return undefined;\n const reasoningEffort = mapCodexEffortToXai(effort, modelPrefersResponsesApi(modelId));\n return reasoningEffort ? { xai: { reasoningEffort } } : undefined;\n }\n\n if (npm === '@ai-sdk/anthropic' || npm === VERTEX_ANTHROPIC_NPM) {\n if (!modelId || !isClaudeReasoningModel(modelId)) return undefined;\n const mapped = mapCodexEffortToAnthropic(effort);\n return mapped\n ? { anthropic: { thinking: { type: 'adaptive', effort: mapped } } }\n : undefined;\n }\n\n if (npm === '@ai-sdk/google') {\n const id = modelId ?? '';\n if (isGemini3Model(id)) {\n const thinkingLevel = mapCodexEffortToGeminiLevel(effort);\n return thinkingLevel\n ? { google: { thinkingConfig: { thinkingLevel, includeThoughts: true } } }\n : undefined;\n }\n const thinkingBudget = mapCodexEffortToGeminiBudget(effort);\n return thinkingBudget\n ? { google: { thinkingConfig: { thinkingBudget, includeThoughts: true } } }\n : undefined;\n }\n\n if (npm === '@ai-sdk/mistral') {\n if (!modelId || !isMistralReasoningModel(modelId)) return undefined;\n const reasoningEffort = effort === 'off' || effort === 'none' ? 'none' : 'high';\n return { mistral: { reasoningEffort } };\n }\n\n if (npm === '@ai-sdk/openai-compatible' || npm === '@ai-sdk/openai') {\n if (!modelId) return undefined;\n if (isDeepSeekReasoningModel(modelId)) {\n return deepSeekEffortProviderOptions(effort);\n }\n if (isKimiReasoningModel(modelId)) {\n const reasoningEffort = mapCodexEffortToOpenAICompatible(effort);\n if (reasoningEffort) {\n const key = metadata?.providerId ? toCamelCase(metadata.providerId) : 'openaiCompatible';\n return { [key]: { reasoningEffort } };\n }\n return undefined;\n }\n if (isGlm52ReasoningModel(modelId)) {\n const reasoningEffort = mapCodexEffortToGlm52(effort);\n if (reasoningEffort) {\n const key = metadata?.providerId ? toCamelCase(metadata.providerId) : 'openaiCompatible';\n return { [key]: { reasoningEffort } };\n }\n return undefined;\n }\n if (hasSupportedParameter(metadata, 'reasoning_effort')) {\n const reasoningEffort = mapCodexEffortToOpenAICompatible(effort);\n return reasoningEffort\n ? { openai: { reasoningEffort }, openaiCompatible: { reasoningEffort } }\n : undefined;\n }\n if (hasSupportedParameter(metadata, 'reasoning')) {\n const allowed = new Set(OPENROUTER_EFFORT_LEVELS);\n const mapped = allowed.has(effort as typeof OPENROUTER_EFFORT_LEVELS[number])\n ? effort\n : effort === 'max' ? 'xhigh' : undefined;\n return mapped\n ? { openrouter: { reasoning: { effort: mapped, exclude: false } } }\n : undefined;\n }\n return undefined;\n }\n\n return undefined;\n}\n\nexport function deepMergeProviderOptions(\n a?: Record<string, Record<string, unknown>>,\n b?: Record<string, Record<string, unknown>>,\n): Record<string, Record<string, unknown>> | undefined {\n if (!a && !b) return undefined;\n if (!a) return b;\n if (!b) return a;\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n const out: Record<string, Record<string, unknown>> = {};\n for (const key of keys) {\n out[key] = { ...(a[key] ?? {}), ...(b[key] ?? {}) };\n }\n return out;\n}\n\n/** Per-provider providerOptions to request reasoning/thinking output. */\nexport function thinkingProviderOptions(npm: string): Record<string, Record<string, unknown>> | undefined {\n if (npm === '@ai-sdk/google') {\n return { google: { thinkingConfig: { includeThoughts: true } } };\n }\n // Responses API: request encrypted reasoning blobs for multi-turn round-trip\n // (proxy owns conversation state — store:false + echo via thinking.signature).\n if (npm === '@ai-sdk/openai') {\n return {\n openai: {\n store: false,\n include: ['reasoning.encrypted_content'],\n },\n };\n }\n return undefined;\n}\n","import type { OAuthTokenResponse } from './types.js';\n\nexport interface PostOAuthRefreshOptions {\n contentType: 'form' | 'json';\n errorPrefix: string;\n includeStatus?: boolean;\n includeBody?: boolean;\n headers?: Record<string, string>;\n}\n\nexport async function postOAuthRefresh(\n url: string,\n body: URLSearchParams | Record<string, string>,\n options: PostOAuthRefreshOptions,\n): Promise<OAuthTokenResponse> {\n const isJson = options.contentType === 'json';\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': isJson ? 'application/json' : 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n ...options.headers,\n },\n body: isJson ? JSON.stringify(body) : (body as URLSearchParams).toString(),\n });\n\n if (!response.ok) {\n const detail = options.includeBody ? await response.text().catch(() => '') : '';\n const status = options.includeStatus ? ` (${response.status})` : '';\n throw new Error(`${options.errorPrefix}${status}${detail ? `: ${detail}` : ''}`);\n }\n\n return response.json() as Promise<OAuthTokenResponse>;\n}\n","// openai.ts — native OpenAI ChatGPT Plus/Pro OAuth (device code, ported from OpenCode)\n\nimport { positiveSecondsToMs, sleepMs } from './pkce.js';\nimport type { OAuthTokenResponse } from './types.js';\nimport { VERSION } from '../constants.js';\nimport { postOAuthRefresh } from './refresh-http.js';\n\nconst CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';\nconst ISSUER = 'https://auth.openai.com';\nconst OAUTH_POLLING_SAFETY_MARGIN_MS = 3_000;\nconst DEVICE_CODE_DEFAULT_EXPIRES_MS = 5 * 60 * 1000;\n\nexport interface OpenAiIdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n 'https://api.openai.com/auth'?: { chatgpt_account_id?: string };\n}\n\nexport interface OpenAiDeviceCodeData {\n device_auth_id: string;\n user_code: string;\n interval: string;\n expires_in?: number;\n}\n\nexport function extractOpenAiAccountId(tokens: OAuthTokenResponse): string | undefined {\n const token = tokens.id_token ?? tokens.access_token;\n if (!token) return undefined;\n const parts = token.split('.');\n if (parts.length !== 3) return undefined;\n try {\n const claims = JSON.parse(Buffer.from(parts[1]!, 'base64url').toString()) as OpenAiIdTokenClaims;\n return claims.chatgpt_account_id\n ?? claims['https://api.openai.com/auth']?.chatgpt_account_id\n ?? claims.organizations?.[0]?.id;\n } catch {\n return undefined;\n }\n}\n\nexport async function requestOpenAiDeviceCode(): Promise<OpenAiDeviceCodeData> {\n const response = await fetch(`${ISSUER}/api/accounts/deviceauth/usercode`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': `relay-ai/${VERSION}`,\n },\n body: JSON.stringify({ client_id: CLIENT_ID }),\n });\n if (!response.ok) {\n throw new Error('Failed to initiate OpenAI device authorization');\n }\n return response.json() as Promise<OpenAiDeviceCodeData>;\n}\n\nexport function openAiDeviceCodeUrl(): string {\n return `${ISSUER}/codex/device`;\n}\n\nexport async function pollOpenAiDeviceCodeToken(\n deviceData: OpenAiDeviceCodeData,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<{ tokens: OAuthTokenResponse; accountId?: string }> {\n const sleep = opts?.sleep ?? sleepMs;\n const now = opts?.now ?? (() => Date.now());\n const intervalMs = Math.max(parseInt(deviceData.interval, 10) || 5, 1) * 1000;\n const deadline = now() + positiveSecondsToMs(deviceData.expires_in, DEVICE_CODE_DEFAULT_EXPIRES_MS);\n\n while (now() < deadline) {\n const response = await fetch(`${ISSUER}/api/accounts/deviceauth/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': `relay-ai/${VERSION}`,\n },\n body: JSON.stringify({\n device_auth_id: deviceData.device_auth_id,\n user_code: deviceData.user_code,\n }),\n });\n\n if (response.ok) {\n const data = await response.json() as { authorization_code: string; code_verifier: string };\n const tokenResponse = await fetch(`${ISSUER}/oauth/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code: data.authorization_code,\n redirect_uri: `${ISSUER}/deviceauth/callback`,\n client_id: CLIENT_ID,\n code_verifier: data.code_verifier,\n }).toString(),\n });\n if (!tokenResponse.ok) {\n throw new Error(`OpenAI token exchange failed (${tokenResponse.status})`);\n }\n const tokens = await tokenResponse.json() as OAuthTokenResponse;\n return { tokens, accountId: extractOpenAiAccountId(tokens) };\n }\n\n if (response.status !== 403 && response.status !== 404) {\n throw new Error(`OpenAI device authorization failed (${response.status})`);\n }\n\n await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, Math.max(0, deadline - now())));\n }\n throw new Error('OpenAI device authorization timed out');\n}\n\nexport async function refreshOpenAiAccessToken(refreshToken: string): Promise<OAuthTokenResponse> {\n return postOAuthRefresh(\n `${ISSUER}/oauth/token`,\n new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: CLIENT_ID,\n }),\n {\n contentType: 'form',\n errorPrefix: 'OpenAI token refresh failed',\n includeStatus: true,\n },\n );\n}\n\nexport async function runOpenAiDeviceCodeFlow(\n onDeviceCode: (info: { url: string; userCode: string }) => void,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<{ tokens: OAuthTokenResponse; accountId?: string }> {\n const deviceData = await requestOpenAiDeviceCode();\n onDeviceCode({ url: openAiDeviceCodeUrl(), userCode: deviceData.user_code });\n return pollOpenAiDeviceCodeToken(deviceData, opts);\n}\n","// responses-websocket.ts — outbound WebSocket transport for OpenAI's Codex\n// \"Responses-Lite\" protocol (wss://chatgpt.com/backend-api/codex/responses).\n//\n// Some ChatGPT Codex models (flagged by the backend with prefer_websockets,\n// e.g. gpt-5.6-luna) are only served over a WebSocket Responses transport, not\n// the HTTP Responses endpoint. This module returns a `fetch` implementation that\n// the Vercel AI SDK's OpenAI provider uses transparently: the SDK still calls\n// `fetch(url, init)` once per request, but instead of an HTTP POST we open one\n// WebSocket per request, send the Responses payload as the first message, and\n// stream the JSON event frames back as Server-Sent Events the SDK already parses.\n//\n// One socket per request → responses are never crossed between concurrent\n// requests (e.g. Claude Code's parallel title-generation + main inference).\n\nimport type { FetchFunction } from '@ai-sdk/provider-utils';\nimport type { RawData, WebSocket as WsWebSocket } from 'ws';\nimport { CODEX_RESPONSES_WEBSOCKETS_BETA } from '../constants.js';\n\nconst RESPONSES_LITE_HEADER = 'x-openai-internal-codex-responses-lite';\n// Responses event types after which the stream is complete and the socket closes.\nconst TERMINAL_EVENT_TYPES = new Set(['response.completed', 'response.failed', 'response.incomplete', 'error']);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction recordKeys(value: unknown): string {\n return isRecord(value) ? Object.keys(value).sort().join(',') : '';\n}\n\n/** Sanitized one-line summary: types, keys, counts, lengths — never field values. */\nexport function summarizeResponsesLiteEvent(event: unknown): string {\n if (!isRecord(event)) return `kind=${event == null ? 'null' : typeof event}`;\n const parts = [`type=${typeof event.type === 'string' ? event.type : 'unknown'}`, `keys=${recordKeys(event)}`];\n if (typeof event.delta === 'string') parts.push(`deltaChars=${event.delta.length}`);\n if (typeof event.output_index === 'number') parts.push(`hasOutputIndex=1`);\n if (typeof event.item_id === 'string') parts.push(`hasItemId=1`);\n if (isRecord(event.item)) {\n parts.push(`itemType=${typeof event.item.type === 'string' ? event.item.type : 'unknown'}`);\n parts.push(`itemKeys=${recordKeys(event.item)}`);\n if (typeof event.item.arguments === 'string') parts.push(`argumentsChars=${event.item.arguments.length}`);\n }\n if (isRecord(event.response)) {\n parts.push(`responseKeys=${recordKeys(event.response)}`);\n if (Array.isArray(event.response.output)) {\n parts.push(`outputCount=${event.response.output.length}`);\n parts.push(`outputTypes=${event.response.output.map(item => (isRecord(item) && typeof item.type === 'string' ? item.type : 'unknown')).join(',')}`);\n }\n if (isRecord(event.response.usage)) parts.push(`usageKeys=${recordKeys(event.response.usage)}`);\n if (typeof event.response.status === 'string') parts.push(`status=${event.response.status}`);\n }\n if (isRecord(event.error)) {\n parts.push(`errorKeys=${recordKeys(event.error)}`);\n if (typeof event.error.message === 'string') parts.push(`messageChars=${event.error.message.length}`);\n }\n return parts.join(' ');\n}\n\n/**\n * Durable per-function-call state. Responses-Lite frames routinely omit `id`,\n * `arguments` and `status`, and can omit `item_id`/`output_index` on deltas —\n * so identity and accumulated arguments have to live here rather than being\n * re-derived from each frame in isolation.\n */\ninterface FunctionCallState {\n /** Stable item id reused across added → delta → done for this one call. */\n itemId: string;\n callId: string;\n name: string;\n /** Argument deltas appended in arrival order. */\n args: string;\n /** `arguments` as sent on an authoritative (done / completed.output) frame. */\n upstreamArgs?: string;\n /** Complete upstream item fields, merged across every frame that carried them. */\n upstream: Record<string, unknown>;\n outputIndex: number;\n /** An `output_item.added` has been emitted downstream for this call. */\n added: boolean;\n /** An argument delta has been forwarded downstream for this call. */\n deltaForwarded: boolean;\n /** Upstream sent an `output_item.done` for this call (even an incomplete one). */\n doneSeen: boolean;\n /** An authoritative `output_item.done` has been emitted downstream. */\n done: boolean;\n}\n\nexport interface ResponsesLiteNormalizeState {\n nextId: number;\n lastMessageItemId?: string;\n lastOutputIndex: number;\n textDeltaForwarded: boolean;\n messageAddedIds: Set<string>;\n messageDoneIds: Set<string>;\n functionCalls: FunctionCallState[];\n /** Last function call touched — the only anchor a delta with no identity has. */\n lastFunctionCall?: FunctionCallState;\n}\n\nexport function createResponsesLiteNormalizeState(): ResponsesLiteNormalizeState {\n return {\n nextId: 1,\n lastOutputIndex: 0,\n textDeltaForwarded: false,\n messageAddedIds: new Set(),\n messageDoneIds: new Set(),\n functionCalls: [],\n };\n}\n\nfunction nextId(state: ResponsesLiteNormalizeState, prefix: string): string {\n const id = `${prefix}_${state.nextId}`;\n state.nextId += 1;\n return id;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction normalizeErrorEvent(event: Record<string, unknown>): Record<string, unknown> {\n const raw = isRecord(event.error) ? event.error : { message: typeof event.error === 'string' ? event.error : 'upstream error' };\n return {\n type: 'error',\n sequence_number: typeof event.sequence_number === 'number' ? event.sequence_number : 0,\n error: {\n type: asString(raw.type) ?? 'server_error',\n code: asString(raw.code) ?? 'unknown',\n message: asString(raw.message) ?? 'upstream error',\n ...(raw.param == null ? {} : { param: raw.param }),\n },\n };\n}\n\ninterface FunctionCallHint {\n itemId?: string;\n callId?: string;\n outputIndex?: number;\n}\n\n/**\n * Find the call a frame belongs to, or start tracking a new one.\n *\n * Identity is checked strongest-first (`call_id`, then item id, then output\n * index). A frame carrying no identity at all belongs to the most recently\n * touched call. An output-index match is rejected when both sides know a\n * *different* `call_id`, so two calls can never merge.\n */\nfunction resolveFunctionCall(state: ResponsesLiteNormalizeState, hint: FunctionCallHint): FunctionCallState {\n if (hint.callId) {\n const byCallId = state.functionCalls.find(entry => entry.callId === hint.callId);\n if (byCallId) return byCallId;\n }\n if (hint.itemId) {\n const byItemId = state.functionCalls.find(entry => entry.itemId === hint.itemId);\n if (byItemId) return byItemId;\n }\n if (hint.outputIndex !== undefined) {\n // An index can be reused across sequential calls, so it identifies at most\n // the call *currently open* at that index. Search newest-first and prefer a\n // call that has not completed — matching the oldest entry would send a\n // second call's argument deltas to the first one.\n const open = [...state.functionCalls].reverse().find(entry => (\n entry.outputIndex === hint.outputIndex\n && !entry.done\n && !(hint.callId && entry.callId !== hint.callId)\n ));\n if (open) return open;\n }\n if (hint.callId === undefined && hint.itemId === undefined && hint.outputIndex === undefined && state.lastFunctionCall) {\n return state.lastFunctionCall;\n }\n const entry: FunctionCallState = {\n itemId: hint.itemId ?? nextId(state, 'fc'),\n callId: hint.callId ?? hint.itemId ?? nextId(state, 'call'),\n name: '',\n args: '',\n upstream: {},\n outputIndex: hint.outputIndex ?? state.lastOutputIndex,\n added: false,\n deltaForwarded: false,\n doneSeen: false,\n done: false,\n };\n state.functionCalls.push(entry);\n return entry;\n}\n\n/** Fold whatever this frame's item did carry into the call's durable state. */\nfunction absorbFunctionItem(entry: FunctionCallState, item: Record<string, unknown>, authoritative: boolean): void {\n entry.upstream = { ...entry.upstream, ...item };\n const name = asString(item.name);\n if (name) entry.name = name;\n const callId = asString(item.call_id);\n if (callId) entry.callId = callId;\n // `added` carries `arguments: ''` as a placeholder — only done/completed items\n // are authoritative about the final argument string.\n if (authoritative && typeof item.arguments === 'string') entry.upstreamArgs = item.arguments;\n}\n\n/** The argument string to complete this call with, or undefined if unknowable. */\nfunction resolveFunctionArgs(entry: FunctionCallState): string | undefined {\n if (entry.upstreamArgs) return entry.upstreamArgs;\n if (entry.args) return entry.args;\n return entry.upstreamArgs;\n}\n\nfunction functionItemPayload(entry: FunctionCallState, extra: Record<string, unknown>): Record<string, unknown> {\n return {\n ...entry.upstream,\n type: 'function_call',\n id: entry.itemId,\n call_id: entry.callId,\n name: entry.name,\n ...extra,\n };\n}\n\nfunction functionAddedEvent(entry: FunctionCallState): Record<string, unknown> {\n entry.added = true;\n return {\n type: 'response.output_item.added',\n output_index: entry.outputIndex,\n item: functionItemPayload(entry, { arguments: '' }),\n };\n}\n\nfunction functionDoneEvent(entry: FunctionCallState, args: string): Record<string, unknown> {\n entry.done = true;\n return {\n type: 'response.output_item.done',\n output_index: entry.outputIndex,\n item: functionItemPayload(entry, { arguments: args, status: 'completed' }),\n };\n}\n\n/**\n * Emit the added/delta/done triplet a call still owes, using its retained\n * identity and arguments. Returns nothing when the call is already complete —\n * that is what keeps `response.completed` recovery from duplicating a tool call.\n */\nfunction completeFunctionCall(entry: FunctionCallState, args: string): unknown[] {\n if (entry.done) return [];\n const events: unknown[] = [];\n if (!entry.added) events.push(functionAddedEvent(entry));\n if (!entry.deltaForwarded && args.length > 0) {\n entry.deltaForwarded = true;\n events.push({\n type: 'response.function_call_arguments.delta',\n item_id: entry.itemId,\n output_index: entry.outputIndex,\n delta: args,\n });\n }\n events.push(functionDoneEvent(entry, args));\n return events;\n}\n\nfunction messageText(item: Record<string, unknown>): string {\n if (typeof item.text === 'string') return item.text;\n if (!Array.isArray(item.content)) return '';\n let out = '';\n for (const part of item.content) {\n if (isRecord(part) && typeof part.text === 'string' && (part.type === 'output_text' || part.type === 'text')) {\n out += part.text;\n }\n }\n return out;\n}\n\nfunction synthesizeMessage(item: Record<string, unknown>, outputIndex: number, state: ResponsesLiteNormalizeState): unknown[] {\n const text = messageText(item);\n if (!text) return [];\n const id = asString(item.id) ?? nextId(state, 'msg');\n state.lastMessageItemId = id;\n state.textDeltaForwarded = true;\n state.messageAddedIds.add(id);\n state.messageDoneIds.add(id);\n return [\n { type: 'response.output_item.added', output_index: outputIndex, item: { type: 'message', id } },\n { type: 'response.output_text.delta', item_id: id, delta: text },\n { type: 'response.output_item.done', output_index: outputIndex, item: { type: 'message', id } },\n ];\n}\n\nfunction synthesizeFunctionCall(item: Record<string, unknown>, outputIndex: number, state: ResponsesLiteNormalizeState): unknown[] {\n const entry = resolveFunctionCall(state, {\n itemId: asString(item.id),\n callId: asString(item.call_id),\n outputIndex,\n });\n absorbFunctionItem(entry, item, true);\n state.lastFunctionCall = entry;\n state.lastOutputIndex = entry.outputIndex;\n const args = resolveFunctionArgs(entry);\n if (args === undefined) {\n // `completed.output` is authoritative for identity but still omitted the\n // arguments. Defaulting to `\"\"` here would fabricate the very call the\n // deferral path exists to avoid — mark it seen so it is reported instead.\n entry.doneSeen = true;\n return [];\n }\n return completeFunctionCall(entry, args);\n}\n\nfunction recoverFromCompletedOutput(response: Record<string, unknown>, state: ResponsesLiteNormalizeState): unknown[] {\n const recovered: unknown[] = [];\n if (Array.isArray(response.output)) {\n response.output.forEach((item, index) => {\n if (!isRecord(item) || typeof item.type !== 'string') return;\n if (item.type === 'message' && !state.textDeltaForwarded) {\n recovered.push(...synthesizeMessage(item, index, state));\n } else if (item.type === 'function_call') {\n recovered.push(...synthesizeFunctionCall(item, index, state));\n }\n });\n }\n // Upstream said these calls were done but never supplied arguments, and\n // `response.completed` did not repeat them either. There is no honest\n // completion available: `arguments: \"\"` is not valid JSON and would recreate\n // the empty-argument tool call this normalization exists to prevent. Report\n // the malformed stream instead of inventing one.\n for (const entry of state.functionCalls) {\n if (entry.done || !entry.doneSeen) continue;\n recovered.push(normalizeErrorEvent({\n error: {\n type: 'invalid_response',\n code: 'incomplete_function_call',\n message: `Provider ended the response without arguments for function call \"${entry.callId}\"`\n + `${entry.name ? ` (${entry.name})` : ''}.`,\n },\n }));\n }\n return recovered;\n}\n\n/**\n * Fill fields `@ai-sdk/openai` requires and recover final output that only\n * exists on `response.completed`. Incomplete frames otherwise become\n * `unknown_chunk` and are dropped while usage still parses — the production\n * \"empty response after N calls\" shape.\n */\nexport function normalizeResponsesLiteEvent(event: unknown, state: ResponsesLiteNormalizeState): unknown[] {\n if (!isRecord(event) || typeof event.type !== 'string') return [event];\n\n if (event.type === 'error') return [normalizeErrorEvent(event)];\n\n if (event.type === 'response.output_item.added' && isRecord(event.item)) {\n const outputIndex = typeof event.output_index === 'number' ? event.output_index : state.lastOutputIndex;\n state.lastOutputIndex = outputIndex;\n if (event.item.type === 'message') {\n const id = asString(event.item.id) ?? nextId(state, 'msg');\n state.lastMessageItemId = id;\n state.messageAddedIds.add(id);\n return [{ ...event, output_index: outputIndex, item: { ...event.item, id } }];\n }\n if (event.item.type === 'function_call') {\n const entry = resolveFunctionCall(state, {\n itemId: asString(event.item.id),\n callId: asString(event.item.call_id),\n outputIndex,\n });\n absorbFunctionItem(entry, event.item, false);\n entry.outputIndex = outputIndex;\n entry.added = true;\n state.lastFunctionCall = entry;\n return [{ ...event, output_index: outputIndex, item: functionItemPayload(entry, { arguments: '' }) }];\n }\n return [{ ...event, output_index: outputIndex }];\n }\n\n if (event.type === 'response.output_item.done' && isRecord(event.item)) {\n const outputIndex = typeof event.output_index === 'number' ? event.output_index : state.lastOutputIndex;\n if (event.item.type === 'function_call') {\n const entry = resolveFunctionCall(state, {\n itemId: asString(event.item.id),\n callId: asString(event.item.call_id),\n outputIndex,\n });\n absorbFunctionItem(entry, event.item, true);\n entry.outputIndex = outputIndex;\n entry.doneSeen = true;\n state.lastFunctionCall = entry;\n state.lastOutputIndex = outputIndex;\n const args = resolveFunctionArgs(entry);\n // Nothing to complete with, and no name to complete under: defer to the\n // authoritative `response.completed.output` instead of fabricating a call.\n if (args === undefined || !entry.name) return [];\n if (entry.done) return [];\n const events: unknown[] = [];\n if (!entry.added) events.push(functionAddedEvent(entry));\n events.push({ ...event, output_index: outputIndex, item: functionItemPayload(entry, { arguments: args, status: 'completed' }) });\n entry.done = true;\n return events;\n }\n if (event.item.type === 'message') {\n const id = asString(event.item.id) ?? state.lastMessageItemId ?? nextId(state, 'msg');\n state.lastMessageItemId = id;\n state.messageDoneIds.add(id);\n return [{ ...event, output_index: outputIndex, item: { ...event.item, id } }];\n }\n return [{ ...event, output_index: outputIndex }];\n }\n\n if (event.type === 'response.output_text.delta') {\n const itemId = asString(event.item_id) ?? state.lastMessageItemId ?? nextId(state, 'msg');\n state.lastMessageItemId = itemId;\n state.textDeltaForwarded = true;\n const events: unknown[] = [];\n if (!state.messageAddedIds.has(itemId)) {\n events.push({\n type: 'response.output_item.added',\n output_index: state.lastOutputIndex,\n item: { type: 'message', id: itemId },\n });\n state.messageAddedIds.add(itemId);\n }\n events.push({ ...event, item_id: itemId, delta: typeof event.delta === 'string' ? event.delta : '' });\n return events;\n }\n\n if (event.type === 'response.function_call_arguments.delta') {\n const entry = resolveFunctionCall(state, {\n itemId: asString(event.item_id),\n outputIndex: typeof event.output_index === 'number' ? event.output_index : undefined,\n });\n const delta = typeof event.delta === 'string' ? event.delta : '';\n entry.args += delta;\n entry.deltaForwarded = true;\n state.lastFunctionCall = entry;\n state.lastOutputIndex = entry.outputIndex;\n return [{ ...event, item_id: entry.itemId, output_index: entry.outputIndex, delta }];\n }\n\n if (event.type === 'response.completed' || event.type === 'response.incomplete') {\n const response = isRecord(event.response) ? event.response : {};\n const recovered = recoverFromCompletedOutput(response, state);\n if (state.lastMessageItemId && state.textDeltaForwarded && !state.messageDoneIds.has(state.lastMessageItemId)) {\n recovered.push({\n type: 'response.output_item.done',\n output_index: state.lastOutputIndex,\n item: { type: 'message', id: state.lastMessageItemId },\n });\n state.messageDoneIds.add(state.lastMessageItemId);\n }\n return [...recovered, event];\n }\n\n return [event];\n}\n\n/** Normalize the SDK's HeadersInit into a plain lowercased-key record for `ws`. */\nfunction toHeaderRecord(headers: HeadersInit | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n if (!headers) return out;\n if (headers instanceof Headers) {\n headers.forEach((value, key) => { out[key] = value; });\n } else if (Array.isArray(headers)) {\n for (const [key, value] of headers) out[key] = value;\n } else {\n for (const [key, value] of Object.entries(headers)) out[key] = String(value);\n }\n return out;\n}\n\nfunction hasResponsesLiteHeader(headers: Record<string, string>): boolean {\n return Object.entries(headers).some(\n ([k, v]) => k.toLowerCase() === RESPONSES_LITE_HEADER && v.toLowerCase() === 'true',\n );\n}\n\n/** Extract the request body as a string (the SDK sends a JSON string). */\nfunction bodyToString(body: BodyInit | null | undefined): string {\n if (body == null) return '';\n if (typeof body === 'string') return body;\n if (body instanceof Uint8Array) return Buffer.from(body).toString('utf8');\n if (body instanceof ArrayBuffer) return Buffer.from(new Uint8Array(body)).toString('utf8');\n return String(body);\n}\n\n/**\n * Apply the Responses-Lite request shape to the outgoing payload. These fields\n * are set on the wire (not via SDK providerOptions) so the transport fully owns\n * the Luna request shape. Adjust here if live traffic shows different field names.\n */\nfunction applyResponsesLiteShape(payload: Record<string, unknown>): Record<string, unknown> {\n const reasoning = (payload.reasoning && typeof payload.reasoning === 'object')\n ? { ...(payload.reasoning as Record<string, unknown>) }\n : {};\n reasoning.context = 'all_turns';\n return {\n ...payload,\n reasoning,\n parallel_tool_calls: false,\n store: false,\n };\n}\n\n/**\n * Build a `fetch` that speaks the Codex Responses-Lite WebSocket protocol.\n * @param wsUrl e.g. wss://chatgpt.com/backend-api/codex/responses\n * @param log optional debug logger (wired to the proxy trace log under --trace)\n */\nexport function createResponsesWebSocketFetch(wsUrl: string, log?: (msg: string) => void): FetchFunction {\n const debug = (msg: string) => { try { log?.(`ws: ${msg}`); } catch { /* ignore */ } };\n return async (_input, init): Promise<Response> => {\n const { WebSocket } = await import('ws');\n\n const headers = toHeaderRecord(init?.headers);\n headers['OpenAI-Beta'] = CODEX_RESPONSES_WEBSOCKETS_BETA;\n debug(`connecting ${wsUrl} headers=[${Object.keys(headers).join(', ')}]`);\n\n // Parse the SDK-built Responses body and, when this is a Responses-Lite\n // model, fold in the transport-specific request fields.\n let payload: Record<string, unknown> = {};\n try {\n payload = JSON.parse(bodyToString(init?.body)) as Record<string, unknown>;\n } catch {\n payload = {};\n }\n if (hasResponsesLiteHeader(headers)) {\n payload = applyResponsesLiteShape(payload);\n }\n debug(\n `request type=response.create keys=${Object.keys(payload).sort().join(',')} `\n + `toolCount=${Array.isArray(payload.tools) ? payload.tools.length : 0} `\n + `store=${String(payload.store)} parallelToolCalls=${String(payload.parallel_tool_calls)} `\n + `reasoningKeys=${recordKeys(payload.reasoning)}`,\n );\n // The Codex WS Responses protocol is internally tagged: the first (and only)\n // client message must be a `response.create` event carrying the Responses\n // body fields at the top level, alongside the type tag — not the raw body.\n // (See openai/codex `ResponsesWsRequest`, `#[serde(tag = \"type\")]`.)\n const outgoing = JSON.stringify({ type: 'response.create', ...payload });\n\n const encoder = new TextEncoder();\n let socket: WsWebSocket;\n let frameCount = 0;\n const normalizeState = createResponsesLiteNormalizeState();\n\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n let closed = false;\n const close = () => {\n if (closed) return;\n closed = true;\n try { controller.close(); } catch { /* already closed */ }\n try { socket.close(); } catch { /* ignore */ }\n };\n const fail = (message: string) => {\n if (closed) return;\n debug(`fail messageChars=${message.length}`);\n // Surface as an SSE error event the SDK's responses parser understands.\n try {\n const [errorEvent] = normalizeResponsesLiteEvent({ type: 'error', error: { message } }, normalizeState);\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(errorEvent)}\\n\\n`));\n } catch { /* ignore */ }\n close();\n };\n\n socket = new WebSocket(wsUrl, { headers });\n\n socket.on('open', () => {\n debug(`open — sending ${outgoing.length}B payload`);\n socket.send(outgoing);\n });\n socket.on('unexpected-response', (_req, res) => {\n debug(`unexpected-response status=${res.statusCode}`);\n });\n\n socket.on('message', (data: RawData) => {\n const text = Array.isArray(data)\n ? Buffer.concat(data).toString('utf8')\n : data.toString('utf8');\n frameCount += 1;\n let event: unknown;\n try {\n event = JSON.parse(text);\n } catch {\n debug(`frame#${frameCount} non-json chars=${text.length}`);\n controller.enqueue(encoder.encode(`data: ${text.replace(/\\r?\\n/g, ' ')}\\n\\n`));\n return;\n }\n if (frameCount <= 8) debug(`frame#${frameCount} ${summarizeResponsesLiteEvent(event)}`);\n for (const next of normalizeResponsesLiteEvent(event, normalizeState)) {\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(next)}\\n\\n`));\n }\n const type = isRecord(event) && typeof event.type === 'string' ? event.type : undefined;\n if (type && TERMINAL_EVENT_TYPES.has(type)) {\n debug(`terminal event: ${type} (after ${frameCount} frames)`);\n close();\n }\n });\n\n socket.on('error', (err: Error) => fail(err.message));\n socket.on('close', (code: number, reason: Buffer) => {\n debug(`close code=${code} frames=${frameCount}${reason?.length ? ` reasonChars=${reason.length}` : ''}`);\n if (closed) return;\n if (code === 1000 || code === 1005) { close(); return; }\n fail(`WebSocket closed (${code})${reason?.length ? `: ${reason.toString('utf8')}` : ''}`);\n });\n\n const signal = init?.signal;\n if (signal) {\n if (signal.aborted) { close(); return; }\n signal.addEventListener('abort', close, { once: true });\n }\n },\n cancel() {\n try { socket?.close(); } catch { /* ignore */ }\n },\n });\n\n return new Response(stream, {\n status: 200,\n headers: { 'content-type': 'text/event-stream; charset=utf-8' },\n });\n };\n}\n","// src/oauth/claude-identity.ts — Request identity simulation for Claude Code OAuth.\n// Anthropic validates that OAuth requests match the claude-cli fingerprint.\n\nimport { createHash, randomUUID } from 'node:crypto';\n\nexport const CLAUDE_CODE_CLI_VERSION = '2.1.195';\nexport const CLAUDE_CODE_USER_AGENT = `claude-cli/${CLAUDE_CODE_CLI_VERSION} (external, cli)`;\nexport const CLAUDE_CODE_ENTRYPOINT = process.env.CLAUDE_CODE_ENTRYPOINT ?? 'cli';\nexport const CLAUDE_CODE_BILLING_HEADER_PREFIX = 'x-anthropic-billing-header:';\n\n// Per-process session IDs keyed by seed — same value emitted for X-Claude-Code-Session-Id\n// and metadata.user_id.session_id.\nconst sessionCache = new Map<string, string>();\n\nfunction getOrCreateSessionId(seed: string): string {\n let id = sessionCache.get(seed);\n if (!id) { id = randomUUID(); sessionCache.set(seed, id); }\n return id;\n}\n\n// Deterministic UUIDv4 from a SHA-256 hash — used as fallback when bootstrap hasn't run.\nfunction uuidFromHash(input: string): string {\n const h = createHash('sha256').update(input).digest('hex');\n return [h.slice(0,8), h.slice(8,12), '4'+h.slice(13,16),\n ((parseInt(h[16]!,16)&3)|8).toString(16)+h.slice(17,20), h.slice(20,32)].join('-');\n}\n\nconst HEX64_RE = /^[a-f0-9]{64}$/i;\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/** Resolve cliUserID (device_id) from stored providerData, falling back to a hash. */\nexport function resolveCliUserID(\n providerData: Record<string, unknown> | undefined,\n seed: string,\n): string {\n const v = providerData?.cliUserID;\n if (typeof v === 'string' && HEX64_RE.test(v)) return v;\n return createHash('sha256').update(`cliUserID:${seed}`).digest('hex');\n}\n\n/** Resolve accountUUID from stored providerData, falling back to a deterministic UUID. */\nexport function resolveAccountUUID(\n providerData: Record<string, unknown> | undefined,\n seed: string,\n): string {\n const v = providerData?.accountUUID;\n if (typeof v === 'string' && UUID_RE.test(v)) return v;\n return uuidFromHash(`account:${seed}`);\n}\n\nexport function buildUserIdJson(deviceId: string, accountUUID: string, sessionId: string): string {\n return JSON.stringify({ device_id: deviceId, account_uuid: accountUUID, session_id: sessionId });\n}\n\nexport function buildClaudeCodeBillingSystemLine(): string {\n return `${CLAUDE_CODE_BILLING_HEADER_PREFIX} cc_version=${CLAUDE_CODE_CLI_VERSION}.0; cc_entrypoint=${CLAUDE_CODE_ENTRYPOINT};`;\n}\n\nfunction systemBlockText(block: unknown): string | undefined {\n if (typeof block === 'string') return block;\n if (block && typeof block === 'object' && 'text' in block) {\n const text = (block as { text?: unknown }).text;\n return typeof text === 'string' ? text : undefined;\n }\n return undefined;\n}\n\nfunction hasClaudeCodeBillingSystemLine(system: unknown): boolean {\n if (typeof system === 'string') return system.startsWith(CLAUDE_CODE_BILLING_HEADER_PREFIX);\n if (!Array.isArray(system)) return false;\n return system.some(block => systemBlockText(block)?.startsWith(CLAUDE_CODE_BILLING_HEADER_PREFIX));\n}\n\nexport function injectClaudeCodeBillingSystemLine(body: Record<string, unknown>): void {\n if (hasClaudeCodeBillingSystemLine(body.system)) return;\n\n const billingBlock = { type: 'text', text: buildClaudeCodeBillingSystemLine() };\n if (body.system === undefined || body.system === null) {\n body.system = [billingBlock];\n } else if (typeof body.system === 'string') {\n body.system = [billingBlock, { type: 'text', text: body.system }];\n } else if (Array.isArray(body.system)) {\n body.system = [billingBlock, ...body.system];\n } else {\n body.system = [billingBlock];\n }\n}\n\n// ── Beta flag selection ────────────────────────────────────────────────────\n// Anthropic validates the anthropic-beta set matches the request shape.\n\nconst ALWAYS: string[] = [\n 'oauth-2025-04-20',\n 'context-management-2025-06-27',\n 'prompt-caching-scope-2026-01-05',\n];\nconst AGENT: string[] = [\n 'claude-code-20250219',\n 'extended-cache-ttl-2025-04-11',\n 'cache-diagnosis-2026-04-07',\n 'advisor-tool-2026-03-01',\n];\nconst THINKING: string[] = [\n 'interleaved-thinking-2025-05-14',\n 'redact-thinking-2026-02-12',\n 'thinking-token-count-2026-05-13',\n];\nconst HEAVY: string[] = ['advanced-tool-use-2025-11-20', 'effort-2025-11-24'];\nconst OPUS_ONLY: string[] = ['context-1m-2025-08-07', 'mid-conversation-system-2026-04-07'];\n\n/**\n * Select anthropic-beta flags matching the request shape.\n * clientBeta: the inbound anthropic-beta header from the client — respected to avoid\n * forcing betas the client never requested (can cause malformed tool_use streams).\n */\nexport function selectBetaFlags(\n body: Record<string, unknown>,\n model?: string | null,\n clientBeta?: string | null,\n): string {\n const hasSystem = !!body.system &&\n (typeof body.system === 'string' || (Array.isArray(body.system) && body.system.length > 0));\n const tools = body.tools as unknown[] | undefined;\n const isFullAgent = hasSystem && Array.isArray(tools) && tools.length > 0;\n const m = (model ?? (typeof body.model === 'string' ? body.model : '')).toLowerCase();\n const isOpus = m.includes('opus');\n const isSonnetOrOpus = isOpus || m.includes('sonnet');\n\n const clientSet = clientBeta\n ? new Set(clientBeta.split(',').map(s => s.trim()).filter(Boolean))\n : null;\n const allowThinking = !clientSet || clientSet.has('interleaved-thinking-2025-05-14');\n const allowHeavy = !clientSet\n || clientSet.has('advanced-tool-use-2025-11-20')\n || clientSet.has('effort-2025-11-24');\n\n const flags = [...ALWAYS];\n if (isFullAgent) flags.push(...AGENT);\n if (isOpus) flags.push(...OPUS_ONLY);\n if (allowThinking) flags.push(...THINKING);\n if (isFullAgent && isSonnetOrOpus && allowHeavy) flags.push(...HEAVY);\n\n return flags.join(',');\n}\n\n/**\n * Inject Claude Code identity metadata into an Anthropic request body in-place.\n * Must be called before forwarding the request to api.anthropic.com.\n */\nexport function injectClaudeIdentity(\n body: Record<string, unknown>,\n providerData: Record<string, unknown> | undefined,\n seed: string,\n): { sessionId: string; userId: string } {\n const deviceId = resolveCliUserID(providerData, seed);\n const accountUUID = resolveAccountUUID(providerData, seed);\n const sessionId = getOrCreateSessionId(seed);\n const userId = buildUserIdJson(deviceId, accountUUID, sessionId);\n const existing = body.metadata as Record<string, unknown> | undefined;\n body.metadata = { ...(existing ?? {}), user_id: userId };\n return { sessionId, userId };\n}\n","/** Shared ClinePass endpoint and runtime credential rules. */\n\nexport const CLINE_PASS_HOST = 'https://api.cline.bot';\nexport const CLINE_PASS_SDK_BASE_URL = `${CLINE_PASS_HOST}/api/v1`;\nexport const CLINE_PASS_CATALOG_URL = `${CLINE_PASS_HOST}/api/v1/ai/cline/recommended-models`;\n/** Authenticated, non-inference endpoint used to verify API-key credentials. */\nexport const CLINE_PASS_VALIDATION_URL = `${CLINE_PASS_HOST}/api/v1/users/me`;\nexport const CLINE_PASS_REGISTER_URL = `${CLINE_PASS_HOST}/api/v1/auth/register`;\nexport const CLINE_PASS_REFRESH_URL = `${CLINE_PASS_HOST}/api/v1/auth/refresh`;\n/** Value written by Relay 0.8.0 before ClinePass reported context metadata. */\nexport const CLINE_PASS_LEGACY_DEFAULT_CONTEXT_WINDOW = 131_072;\nexport const CLINE_PASS_WORKOS_PREFIX = 'workos:';\n\nexport function isClinePassOAuth(providerId?: string, authType?: string): boolean {\n return providerId === 'cline-pass' && authType === 'oauth';\n}\n\n/** Format only ClinePass OAuth access tokens; API keys remain raw. */\nexport function formatClineRuntimeCredential(\n providerId: string | undefined,\n authType: 'api' | 'oauth' | 'none' | undefined,\n key: string,\n): string {\n if (!isClinePassOAuth(providerId, authType)) return key;\n return key.toLowerCase().startsWith(CLINE_PASS_WORKOS_PREFIX)\n ? key\n : `${CLINE_PASS_WORKOS_PREFIX}${key}`;\n}\n\n/**\n * Wrap the SDK fetch used by ClinePass OAuth routes.\n *\n * WorkOS access tokens are stored without the runtime marker. ClinePass\n * requires `workos:` on the wire, and an expired token gets one retry after\n * the caller refreshes it. The request is cloned so a POST body can safely be\n * sent a second time, and the wrapper never retries more than once.\n */\nexport function createClinePassOAuthFetch(\n initialRuntimeCredential: string,\n refreshToken: () => Promise<string | null>,\n onTokenRefreshed?: (rawToken: string) => void,\n fetchImpl: typeof globalThis.fetch = globalThis.fetch,\n): typeof globalThis.fetch {\n let currentRuntimeCredential = initialRuntimeCredential;\n\n return async (input, init) => {\n const request = new Request(input, init);\n const send = (runtimeCredential: string) => {\n const headers = new Headers(request.headers);\n headers.set('Authorization', `Bearer ${runtimeCredential}`);\n return fetchImpl(request.clone(), { headers });\n };\n\n const response = await send(currentRuntimeCredential);\n if (response.status !== 401) return response;\n\n const refreshedRawToken = await refreshToken().catch(() => null);\n const refreshedRuntimeCredential = refreshedRawToken\n ? formatClineRuntimeCredential('cline-pass', 'oauth', refreshedRawToken)\n : null;\n if (!refreshedRawToken || !refreshedRuntimeCredential || refreshedRuntimeCredential === currentRuntimeCredential) {\n return response;\n }\n\n currentRuntimeCredential = refreshedRuntimeCredential;\n onTokenRefreshed?.(refreshedRawToken);\n return send(currentRuntimeCredential);\n };\n}\n","// src/registry/io.ts — load/save providers.json with secure permissions\n\nimport {\n chmodSync,\n copyFileSync,\n existsSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n writeSync,\n closeSync,\n} from 'node:fs';\nimport { dirname } from 'node:path';\nimport { getAppHome, getProvidersPath } from '../paths.js';\nimport type { ProviderRegistry, RegistryProvider } from './types.js';\nimport { REGISTRY_SCHEMA_VERSION } from './types.js';\nimport {\n migrateAlibabaDashScopeChinaLabel,\n migrateLegacyCloudProviders,\n migrateOAuthOpenAiProvider,\n migrateOAuthXaiProvider,\n} from './migrate.js';\nimport { isValidProviderId } from './validate.js';\n\nconst DIR_MODE = 0o700;\nconst FILE_MODE = 0o600;\n\nexport function ensureSecureAppHome(): void {\n const home = getAppHome();\n mkdirSync(home, { recursive: true, mode: DIR_MODE });\n try {\n chmodSync(home, DIR_MODE);\n } catch {\n // best-effort on platforms that restrict chmod\n }\n}\n\nfunction writeSecureFile(path: string, content: string): void {\n ensureSecureAppHome();\n mkdirSync(dirname(path), { recursive: true, mode: DIR_MODE });\n const fd = openSync(path, 'w', FILE_MODE);\n try {\n writeSync(fd, content);\n } finally {\n closeSync(fd);\n }\n try {\n chmodSync(path, FILE_MODE);\n } catch {\n // best-effort\n }\n}\n\nfunction parseProvider(raw: unknown): RegistryProvider | null {\n if (!raw || typeof raw !== 'object') return null;\n const p = raw as Record<string, unknown>;\n if (typeof p.id !== 'string' || !isValidProviderId(p.id)) return null;\n if (typeof p.templateId !== 'string' || !p.templateId) return null;\n if (typeof p.name !== 'string' || !p.name) return null;\n if (typeof p.enabled !== 'boolean') return null;\n if (typeof p.authRef !== 'string' || !p.authRef) return null;\n if (typeof p.addedAt !== 'string' || !p.addedAt) return null;\n const api = p.api;\n if (!api || typeof api !== 'object') return null;\n\n const provider: RegistryProvider = {\n id: p.id,\n templateId: p.templateId,\n name: p.name,\n enabled: p.enabled,\n authRef: p.authRef,\n api: api as RegistryProvider['api'],\n addedAt: p.addedAt,\n };\n\n if (p.subscriptionFilter === 'free' || p.subscriptionFilter === 'zen' || p.subscriptionFilter === 'go') {\n provider.subscriptionFilter = p.subscriptionFilter;\n }\n if (p.authType === 'api' || p.authType === 'oauth' || p.authType === 'none') {\n provider.authType = p.authType;\n }\n if (typeof p.refreshedAt === 'string') provider.refreshedAt = p.refreshedAt;\n if (p.modelsCache && typeof p.modelsCache === 'object') {\n const cache = p.modelsCache as { fetchedAt?: string; models?: unknown[] };\n if (typeof cache.fetchedAt === 'string' && Array.isArray(cache.models)) {\n provider.modelsCache = {\n fetchedAt: cache.fetchedAt,\n models: cache.models.filter(m => m && typeof m === 'object') as RegistryProvider['modelsCache'] extends infer C\n ? C extends { models: infer M } ? M : never\n : never,\n };\n }\n }\n return provider;\n}\n\nfunction parseRegistry(raw: unknown): ProviderRegistry {\n const empty: ProviderRegistry = { schemaVersion: REGISTRY_SCHEMA_VERSION, providers: [] };\n if (!raw || typeof raw !== 'object') return empty;\n const data = raw as Record<string, unknown>;\n const providers: RegistryProvider[] = [];\n if (Array.isArray(data.providers)) {\n for (const entry of data.providers) {\n const parsed = parseProvider(entry);\n if (parsed) providers.push(parsed);\n }\n }\n const registry: ProviderRegistry = {\n schemaVersion:\n typeof data.schemaVersion === 'number' ? data.schemaVersion : REGISTRY_SCHEMA_VERSION,\n providers,\n };\n if (typeof data.importedAt === 'string') registry.importedAt = data.importedAt;\n if (typeof data.pricingCacheAt === 'string') registry.pricingCacheAt = data.pricingCacheAt;\n return registry;\n}\n\nexport function loadRegistry(path = getProvidersPath(), { persist = true }: { persist?: boolean } = {}): ProviderRegistry {\n if (!existsSync(path)) {\n return { schemaVersion: REGISTRY_SCHEMA_VERSION, providers: [] };\n }\n try {\n const raw = JSON.parse(readFileSync(path, 'utf8'));\n const registry = parseRegistry(raw);\n let migrated = migrateLegacyCloudProviders(registry);\n if (migrateOAuthOpenAiProvider(registry)) migrated = true;\n if (migrateOAuthXaiProvider(registry)) migrated = true;\n if (migrateAlibabaDashScopeChinaLabel(registry)) migrated = true;\n // In-memory migrations always run (consumers like the embedded Core API\n // depend on them); persistence is gated so read-only callers never write.\n if (migrated && persist) {\n try {\n saveRegistry(registry, path);\n } catch {\n // Parsed data remains usable even when migration persistence fails.\n }\n }\n return registry;\n } catch {\n return { schemaVersion: REGISTRY_SCHEMA_VERSION, providers: [] };\n }\n}\n\nexport function saveRegistry(registry: ProviderRegistry, path = getProvidersPath()): void {\n const payload = `${JSON.stringify(registry, null, 2)}\\n`;\n const backup = `${path}.bak`;\n if (existsSync(path)) {\n try {\n copyFileSync(path, backup);\n } catch {\n // backup is best-effort\n }\n }\n const tmp = `${path}.tmp`;\n writeSecureFile(tmp, payload);\n renameSync(tmp, path);\n}\n\nexport function emptyRegistry(): ProviderRegistry {\n return { schemaVersion: REGISTRY_SCHEMA_VERSION, providers: [] };\n}\n","// src/registry/types.ts — native provider registry schema (no secrets)\n\nimport type { FreeStatus } from '../free-models.js';\n\nexport const REGISTRY_SCHEMA_VERSION = 1;\n\nexport type RegistrySubscriptionFilter = 'free' | 'zen' | 'go';\n\nexport interface CachedModel {\n id: string;\n name: string;\n upstreamModelId: string;\n family?: string;\n brand?: string;\n contextWindow?: number;\n /** Distinguishes provider-reported context from legacy Relay guesses. */\n contextWindowSource?: 'provider';\n cost?: { input: number; output: number; cache_read?: number; cache_write?: number };\n isFree?: boolean;\n freeStatus?: FreeStatus;\n modelFormat: 'anthropic' | 'openai' | 'cloud-code';\n /** Per-model override — wins over provider-level api.npm */\n npm?: string;\n /** Per-model override — wins over provider-level api.url */\n apiUrl?: string;\n sourceBackend?: string;\n /** Provider-reported request parameters, e.g. OpenRouter supported_parameters. */\n supportedParameters?: string[];\n /** Broad model metadata: model can produce reasoning/thinking output. */\n reasoning?: boolean;\n /** Streaming/interleaved reasoning field name from metadata, e.g. reasoning_content. */\n interleavedReasoningField?: string;\n /** Backend capability: model requires the Responses-Lite request shape (x-openai-internal-codex-responses-lite). */\n useResponsesLite?: boolean;\n /** Backend capability: model must use the WebSocket Responses transport instead of HTTP. */\n preferWebSockets?: boolean;\n}\n\nexport interface RegistryProvider {\n id: string;\n templateId: string;\n name: string;\n enabled: boolean;\n authRef: string;\n authType?: 'api' | 'oauth' | 'none';\n subscriptionFilter?: RegistrySubscriptionFilter;\n api: {\n npm?: string;\n url?: string;\n id?: string;\n /** Static headers sent on every upstream request (e.g. a plan/auth-tracking header a custom endpoint requires). */\n headers?: Record<string, string>;\n };\n modelsCache?: {\n fetchedAt: string;\n models: CachedModel[];\n };\n addedAt: string;\n refreshedAt?: string;\n}\n\nexport interface ProviderRegistry {\n schemaVersion: number;\n providers: RegistryProvider[];\n importedAt?: string;\n pricingCacheAt?: string;\n}\n","import type { ProviderRegistry } from './types.js';\n\nconst LEGACY_CLOUD_PROVIDER_IDS = [\n { legacyId: 'opencode', id: 'zen', name: 'OpenCode Zen' },\n { legacyId: 'opencode-go', id: 'go', name: 'OpenCode Go' },\n] as const;\n\nexport function migrateLegacyCloudProviders(registry: ProviderRegistry): boolean {\n let changed = false;\n\n for (const { legacyId, id, name } of LEGACY_CLOUD_PROVIDER_IDS) {\n const legacyIdx = registry.providers.findIndex(provider => provider.id === legacyId);\n if (legacyIdx < 0) continue;\n\n if (registry.providers.some(provider => provider.id === id)) {\n registry.providers.splice(legacyIdx, 1);\n } else {\n registry.providers[legacyIdx] = {\n ...registry.providers[legacyIdx]!,\n id,\n templateId: id,\n name,\n api: {},\n };\n }\n changed = true;\n }\n\n return changed;\n}\n\n// Rename {id:'openai', authType:'oauth'} → {id:'openai-oauth'} so it can coexist\n// with the API-key 'openai' provider. Preserves the original authRef so the\n// keyring credential isn't orphaned.\nexport function migrateOAuthOpenAiProvider(registry: ProviderRegistry): boolean {\n if (registry.providers.some(p => p.id === 'openai-oauth')) return false;\n\n const idx = registry.providers.findIndex(\n p => p.id === 'openai' && p.authType === 'oauth',\n );\n if (idx < 0) return false;\n\n const existing = registry.providers[idx]!;\n registry.providers[idx] = {\n ...existing,\n id: 'openai-oauth',\n templateId: existing.templateId || 'openai',\n name: existing.name === 'OpenAI' ? 'OpenAI (ChatGPT)' : existing.name,\n };\n return true;\n}\n\n// Rename {id:'xai', authType:'oauth'} → {id:'xai-oauth'}\nexport function migrateOAuthXaiProvider(registry: ProviderRegistry): boolean {\n if (registry.providers.some(p => p.id === 'xai-oauth')) return false;\n\n const idx = registry.providers.findIndex(\n p => p.id === 'xai' && p.authType === 'oauth',\n );\n if (idx < 0) return false;\n\n const existing = registry.providers[idx]!;\n registry.providers[idx] = {\n ...existing,\n id: 'xai-oauth',\n templateId: existing.templateId || 'xai',\n name: existing.name === 'xAI' ? 'xAI Grok (SuperGrok)' : existing.name,\n };\n return true;\n}\n\n/** Clarify the stock China DashScope entry without altering custom configurations. */\nexport function migrateAlibabaDashScopeChinaLabel(registry: ProviderRegistry): boolean {\n const provider = registry.providers.find(p =>\n p.id === 'alibaba' &&\n p.templateId === 'alibaba' &&\n p.name === 'Alibaba DashScope' &&\n p.api.url === 'https://dashscope.aliyuncs.com/compatible-mode/v1',\n );\n if (!provider) return false;\n\n provider.name = 'Alibaba DashScope (China)';\n return true;\n}\n","// src/registry/validate.ts\n\n/** Stable provider slug: lowercase alphanumeric + internal hyphens. */\nexport const PROVIDER_ID_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;\n\nexport function isValidProviderId(id: string): boolean {\n return PROVIDER_ID_PATTERN.test(id);\n}\n\nexport function slugifyProviderId(displayName: string): string {\n const base = displayName\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n if (!base) return 'custom-provider';\n if (isValidProviderId(base)) return base;\n const trimmed = base.replace(/^-+|-+$/g, '');\n return isValidProviderId(trimmed) ? trimmed : `custom-${trimmed.slice(0, 40)}`;\n}\n\nexport function customProviderId(displayName: string): string {\n const slug = slugifyProviderId(displayName);\n return slug.startsWith('custom-') ? slug : `custom-${slug}`;\n}\n","// src/core/errors.ts — RelayCoreError: safe, structured errors for embedded consumers.\n\nimport type { RelayCoreErrorCode, RelayRouteId } from './types.js';\n\nconst DEFAULT_RETRYABLE: Record<RelayCoreErrorCode, boolean> = {\n INVALID_ROUTE_ID: false,\n ROUTE_NOT_FOUND: false,\n PROVIDER_DISABLED: false,\n CREDENTIAL_UNAVAILABLE: false,\n OAUTH_REFRESH_FAILED: true,\n UNSUPPORTED_MODEL: false,\n UNSUPPORTED_REASONING_LEVEL: false,\n UNSUPPORTED_REGISTRY_VERSION: false,\n PROVIDER_LOAD_FAILED: true,\n};\n\nexport interface RelayCoreErrorOptions {\n retryable?: boolean;\n providerId?: string;\n routeId?: RelayRouteId;\n cause?: unknown;\n}\n\n/**\n * Error thrown by the embedded Core API. Carries only safe structured metadata —\n * never credential material. `cause` is retained for internal debugging but is\n * omitted from JSON serialization.\n */\nexport class RelayCoreError extends Error {\n readonly code: RelayCoreErrorCode;\n readonly retryable: boolean;\n readonly providerId?: string;\n readonly routeId?: RelayRouteId;\n\n constructor(code: RelayCoreErrorCode, message: string, options: RelayCoreErrorOptions = {}) {\n super(message, options.cause !== undefined ? { cause: options.cause } : undefined);\n this.name = 'RelayCoreError';\n this.code = code;\n this.retryable = options.retryable ?? DEFAULT_RETRYABLE[code];\n if (options.providerId !== undefined) this.providerId = options.providerId;\n if (options.routeId !== undefined) this.routeId = options.routeId;\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n ...(this.providerId !== undefined ? { providerId: this.providerId } : {}),\n ...(this.routeId !== undefined ? { routeId: this.routeId } : {}),\n };\n }\n}\n\nexport function isRelayCoreError(err: unknown): err is RelayCoreError {\n return err instanceof RelayCoreError;\n}\n","// src/core/reasoning.ts — translate a provider-neutral reasoning level into the\n// resolved route's own AI SDK request options.\n//\n// This is the whole point of the contract: a consumer says `'xhigh'`, and Relay\n// Core decides whether that means `openai.reasoningEffort`, a Gemini\n// `thinkingConfig`, an Anthropic `thinking` block, and so on. Consumers must\n// never have to write provider-specific `providerOptions` themselves.\n\nimport type { LanguageModel } from 'ai';\nimport {\n deepMergeProviderOptions,\n effortProviderOptions,\n getReasoningCapabilities,\n type ReasoningMetadata,\n} from '../provider-factory.js';\nimport type { CachedModel, RegistryProvider } from '../registry/types.js';\nimport { RelayCoreError } from './errors.js';\nimport type { RelayReasoningLevel, RelayRouteId } from './types.js';\n\n/** Runtime mirror of `RelayReasoningLevel` — the whole catalog vocabulary. */\nexport const RELAY_REASONING_LEVELS: readonly RelayReasoningLevel[] = [\n 'off', 'none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max',\n];\n\nexport type RelayProviderOptions = Record<string, Record<string, unknown>>;\n\nexport function isRelayReasoningLevel(value: unknown): value is RelayReasoningLevel {\n return typeof value === 'string' && (RELAY_REASONING_LEVELS as readonly string[]).includes(value);\n}\n\n/**\n * The SDK package that actually serves this route. Cloud Code Assist models are\n * served by a specialized native Google transport rather than the generic\n * factory, so their reasoning options are Gemini-shaped even though the\n * registry entry carries no npm package of its own.\n */\nexport function reasoningNpmForRoute(provider: RegistryProvider, model: CachedModel): string {\n if (model.modelFormat === 'cloud-code') return '@ai-sdk/google';\n return model.npm ?? provider.api.npm ?? '';\n}\n\n/**\n * Resolve a reasoning level into route-specific AI SDK `providerOptions`.\n *\n * Throws `UNSUPPORTED_REASONING_LEVEL` when the level is not a known level, or\n * when this route has no way to express it — never returns a silently weaker\n * setting than the caller asked for.\n */\nexport function resolveReasoningProviderOptions(\n level: RelayReasoningLevel,\n provider: RegistryProvider,\n model: CachedModel,\n routeId: RelayRouteId,\n): RelayProviderOptions {\n if (!isRelayReasoningLevel(level)) {\n throw new RelayCoreError(\n 'UNSUPPORTED_REASONING_LEVEL',\n `Unknown reasoning level \"${String(level)}\" — expected one of: ${RELAY_REASONING_LEVELS.join(', ')}.`,\n { providerId: provider.id, routeId },\n );\n }\n\n const npm = reasoningNpmForRoute(provider, model);\n const upstreamModelId = model.upstreamModelId ?? model.id;\n const metadata: ReasoningMetadata = {\n providerId: provider.id,\n upstreamModelId,\n ...(model.apiUrl ?? provider.api.url ? { apiBaseUrl: model.apiUrl ?? provider.api.url } : {}),\n ...(model.supportedParameters ? { supportedParameters: model.supportedParameters } : {}),\n ...(model.reasoning !== undefined ? { reasoning: model.reasoning } : {}),\n ...(model.interleavedReasoningField ? { interleavedReasoningField: model.interleavedReasoningField } : {}),\n };\n\n // `effortProviderOptions` is the CLI picker's mapper: it deliberately\n // substitutes the nearest available value (Gemini has no `xhigh`, so `xhigh`\n // would arrive as `high`). Core promises the opposite, so gate on the route's\n // own advertised vocabulary *before* mapping — anything outside it would be a\n // substitution, not a translation.\n const caps = getReasoningCapabilities(npm, upstreamModelId, metadata);\n if (caps.mode !== 'controllable' || !caps.levels.includes(level)) {\n const available = caps.levels.length > 0 ? caps.levels.join(', ') : 'none';\n throw new RelayCoreError(\n 'UNSUPPORTED_REASONING_LEVEL',\n `Model \"${model.id}\" on provider \"${provider.name}\" does not support reasoning level \"${level}\" `\n + `— available levels: ${available}. See capabilities.reasoningLevels from listRelayModels().`,\n { providerId: provider.id, routeId },\n );\n }\n\n const resolved = effortProviderOptions(npm, level, upstreamModelId, metadata);\n if (!resolved) {\n throw new RelayCoreError(\n 'UNSUPPORTED_REASONING_LEVEL',\n `Model \"${model.id}\" on provider \"${provider.name}\" advertises reasoning level \"${level}\" but `\n + `Relay has no request mapping for it — this is a relay-ai bug, please report it.`,\n { providerId: provider.id, routeId },\n );\n }\n return resolved;\n}\n\n/**\n * Wrap a model so every call carries the resolved reasoning options.\n *\n * Merged *under* whatever the caller passes per call, so an explicit\n * `providerOptions` on `streamText`/`generateText` still wins.\n */\nexport async function withReasoningProviderOptions(\n model: LanguageModel,\n providerOptions: RelayProviderOptions,\n): Promise<LanguageModel> {\n const { wrapLanguageModel } = await import('ai');\n type WrapArgs = Parameters<typeof wrapLanguageModel>[0];\n return wrapLanguageModel({\n // `LanguageModel` also admits a bare model-id string and the legacy v2\n // interface; everything Core builds is a concrete current-spec model.\n model: model as WrapArgs['model'],\n middleware: {\n specificationVersion: 'v3',\n transformParams: async ({ params }) => ({\n ...params,\n providerOptions: deepMergeProviderOptions(\n providerOptions,\n params.providerOptions as RelayProviderOptions | undefined,\n ) as typeof params.providerOptions,\n }),\n },\n });\n}\n","// src/core/route-id.ts — `provider::model` route ids (unconditionally scoped).\n\nimport { isValidProviderId } from '../registry/validate.js';\nimport { RelayCoreError } from './errors.js';\nimport type { RelayRouteId } from './types.js';\n\nconst SEPARATOR = '::';\n\n/**\n * Build a route id from a provider id and a model id. The provider id must pass\n * the registry's `PROVIDER_ID_PATTERN`; the model id may contain `/` and `:`.\n */\nexport function toRelayRouteId(providerId: string, modelId: string): RelayRouteId {\n if (!isValidProviderId(providerId)) {\n throw new RelayCoreError('INVALID_ROUTE_ID', `Invalid provider id for route id: ${JSON.stringify(providerId)}`, {});\n }\n if (!modelId) {\n throw new RelayCoreError('INVALID_ROUTE_ID', 'Model id must be non-empty for a route id', { providerId });\n }\n return `${providerId}${SEPARATOR}${modelId}`;\n}\n\n/**\n * Parse a route id back into its parts. Splits on the FIRST `::` only, so model\n * ids containing `/` or `:` (e.g. `openrouter::vendor/model:free`) survive.\n * A bare model id (no `::`) is rejected.\n */\nexport function parseRelayRouteId(routeId: string): { providerId: string; modelId: string } {\n const idx = typeof routeId === 'string' ? routeId.indexOf(SEPARATOR) : -1;\n if (idx <= 0 || idx === routeId.length - SEPARATOR.length) {\n throw new RelayCoreError('INVALID_ROUTE_ID', `Route id must be \"provider::model\", got: ${JSON.stringify(routeId)}`);\n }\n const providerId = routeId.slice(0, idx);\n const modelId = routeId.slice(idx + SEPARATOR.length);\n if (!isValidProviderId(providerId)) {\n throw new RelayCoreError('INVALID_ROUTE_ID', `Invalid provider id in route id: ${JSON.stringify(routeId)}`);\n }\n return { providerId, modelId };\n}\n","// src/core/catalog.ts — credential-free model catalog for embedded consumers.\n\nimport { loadPreferences } from '../config.js';\nimport { getReasoningCapabilities } from '../provider-factory.js';\nimport { loadRegistry } from '../registry/io.js';\nimport { REGISTRY_SCHEMA_VERSION, type CachedModel, type ProviderRegistry, type RegistryProvider } from '../registry/types.js';\nimport { RelayCoreError } from './errors.js';\nimport { isRelayReasoningLevel, reasoningNpmForRoute } from './reasoning.js';\nimport { toRelayRouteId } from './route-id.js';\nimport type { RelayModelDescriptor } from './types.js';\n\n/** Read the registry without ever persisting migrations, and reject newer schemas. */\nexport function loadCoreRegistry(path?: string): ProviderRegistry {\n const registry = loadRegistry(path, { persist: false });\n if (registry.schemaVersion > REGISTRY_SCHEMA_VERSION) {\n throw new RelayCoreError(\n 'UNSUPPORTED_REGISTRY_VERSION',\n `Registry schema v${registry.schemaVersion} is newer than supported v${REGISTRY_SCHEMA_VERSION} — upgrade relay-ai.`,\n );\n }\n return registry;\n}\n\ntype ReasoningInfo = RelayModelDescriptor['capabilities'];\n\nfunction mapReasoning(provider: RegistryProvider, model: CachedModel): ReasoningInfo {\n const base = { tools: 'unknown' as const, vision: 'unknown' as const };\n // Must be the SDK package the model is actually *built* with, not the\n // provider's registry npm — Cloud Code routes are registered as\n // openai-compatible but served by @ai-sdk/google, so classifying by the\n // registry value reported reasoning capabilities Core does not agree with.\n const npm = reasoningNpmForRoute(provider, model);\n const upstreamModelId = model.upstreamModelId ?? model.id;\n try {\n const caps = getReasoningCapabilities(npm, upstreamModelId, {\n providerId: provider.id,\n apiBaseUrl: model.apiUrl ?? provider.api.url,\n supportedParameters: model.supportedParameters,\n reasoning: model.reasoning,\n interleavedReasoningField: model.interleavedReasoningField,\n upstreamModelId,\n });\n switch (caps.mode) {\n case 'none':\n return { ...base, reasoning: 'none' };\n case 'internal-only':\n return { ...base, reasoning: 'fixed' };\n case 'controllable': {\n // `ReasoningCapabilities.levels` is the internal `string[]`; narrow it\n // so the public descriptor only ever exposes real RelayReasoningLevels.\n const levels = caps.levels.filter(isRelayReasoningLevel);\n if (levels.length === 0) return { ...base, reasoning: 'fixed' };\n return {\n ...base,\n reasoning: 'adjustable',\n reasoningLevels: levels,\n ...(isRelayReasoningLevel(caps.defaultLevel)\n ? { defaultReasoningLevel: caps.defaultLevel }\n : {}),\n };\n }\n default:\n return { ...base, reasoning: 'unknown' };\n }\n } catch {\n // Reasoning classification is best-effort; never fail the catalog over it.\n return { ...base, reasoning: 'unknown' };\n }\n}\n\nfunction favoriteKey(providerId: string, modelId: string): string {\n return `${providerId}::${modelId}`;\n}\n\nfunction toDescriptor(provider: RegistryProvider, model: CachedModel, favorites: Set<string>): RelayModelDescriptor {\n const upstreamModelId = model.upstreamModelId ?? model.id;\n return {\n routeId: toRelayRouteId(provider.id, model.id),\n providerId: provider.id,\n providerName: provider.name,\n modelId: model.id,\n upstreamModelId,\n displayName: model.name,\n authType: provider.authType ?? 'api',\n favorite: favorites.has(favoriteKey(provider.id, model.id)),\n ...(model.contextWindow !== undefined ? { contextWindow: model.contextWindow } : {}),\n ...(model.cost\n ? {\n pricing: {\n input: model.cost.input,\n output: model.cost.output,\n ...(model.cost.cache_read !== undefined ? { cacheRead: model.cost.cache_read } : {}),\n ...(model.cost.cache_write !== undefined ? { cacheWrite: model.cost.cache_write } : {}),\n },\n }\n : {}),\n capabilities: mapReasoning(provider, model),\n };\n}\n\n/**\n * List the credential-free model catalog: one descriptor per cached model of\n * every enabled provider. Never resolves credentials, refreshes OAuth, hits a\n * provider API, or writes to disk.\n */\nexport function listRelayModels(registryPath?: string): RelayModelDescriptor[] {\n const registry = loadCoreRegistry(registryPath);\n const favorites = new Set(\n (loadPreferences().favoriteModels ?? []).map(f => favoriteKey(f.providerId, f.modelId)),\n );\n\n const descriptors: RelayModelDescriptor[] = [];\n for (const provider of registry.providers) {\n if (!provider.enabled) continue;\n for (const model of provider.modelsCache?.models ?? []) {\n descriptors.push(toDescriptor(provider, model, favorites));\n }\n }\n\n return descriptors.sort((a, b) =>\n Number(b.favorite) - Number(a.favorite)\n || a.providerName.localeCompare(b.providerName)\n || a.displayName.localeCompare(b.displayName),\n );\n}\n","// Context window resolution for proxy /v1/models and Claude Code child env.\n//\n// Priority:\n// 1. OpenCode models.json cache (limit.context) — `opencode` / `opencode-go` file keys first\n// 2. ID-pattern heuristics for models not in cache\n// 3. 200K default (Claude Code's own fallback for unknown models)\nimport { readFileSync } from 'node:fs';\nimport { OPENCODE_CACHE_PATH } from './constants.js';\n\nexport const DEFAULT_CONTEXT_WINDOW = 200_000;\n\n/** OpenCode cache file provider keys for Zen/Go (not relay-ai registry ids). */\nconst CACHE_PROVIDER_PRIORITY = new Set(['opencode', 'opencode-go']);\n\nexport interface OpencodeCacheModel {\n id?: string;\n name?: string;\n family?: string;\n status?: string;\n provider?: { npm?: string };\n cost?: { input: number; output: number };\n limit?: { context?: number; output?: number };\n reasoning?: boolean;\n interleaved?: { field?: string };\n}\n\nexport type OpencodeCacheFile = Record<string, { models?: Record<string, OpencodeCacheModel> }>;\n\n// Ordered by specificity — first match wins.\nconst HEURISTIC_RULES: Array<[RegExp, number]> = [\n [/gemini-2\\.5-pro|gemini-1\\.5-pro|gemini-3-pro/i, 2_000_000],\n [/gemini/i, 1_000_000],\n [/claude-opus-4-[678]|claude-sonnet-4-[678]/i, 1_000_000],\n [/claude-haiku-4-[567]/i, 200_000],\n [/claude.*\\[1m\\]/i, 1_000_000],\n [/claude-opus-4-[56]|claude-sonnet-4-[45]|claude-3/i, 200_000],\n [/claude/i, 200_000],\n [/deepseek-v4|deepseek-r1|deepseek-reasoner/i, 1_000_000],\n [/deepseek/i, 64_000],\n [/gpt-5|gpt-4\\.1|o3-|o4-/i, 1_000_000],\n [/gpt-4o|gpt-4-turbo|gpt-4/i, 128_000],\n [/gpt-oss/i, 131_072],\n [/qwen3|qwen-3|qwen2\\.5-72b|qwen2\\.5-32b|qwen-coder/i, 262_144],\n [/qwen/i, 131_072],\n [/kimi-k2|kimi-k2\\.5|moonshot/i, 262_144],\n [/minimax-m2/i, 204_800],\n [/minimax/i, 128_000],\n [/mistral-large|ministral|mistral/i, 262_144],\n [/llama-3\\.[23]|llama3/i, 131_072],\n [/grok-4\\.20/i, 1_000_000],\n [/grok-4\\.5/i, 500_000],\n [/grok-3|grok-4/i, 131_072],\n [/nemotron/i, 131_072],\n [/glm-4/i, 128_000],\n [/solar-pro3/i, 131_072],\n [/solar-pro2/i, 65_536],\n [/solar/i, 32_768],\n];\n\nlet parsedCache: OpencodeCacheFile | null | undefined;\nlet cacheIndex: Map<string, number> | undefined;\nconst heuristicCache = new Map<string, number>();\n\n/** Shared parse of ~/.cache/opencode/models.json — used by model list and context lookup. */\nexport function loadOpencodeCache(): OpencodeCacheFile | null {\n if (parsedCache === undefined) {\n try {\n parsedCache = JSON.parse(readFileSync(OPENCODE_CACHE_PATH, 'utf8')) as OpencodeCacheFile;\n } catch {\n parsedCache = null;\n }\n }\n return parsedCache;\n}\n\n/** Build a model-id → context-window map from OpenCode cache data. Exported for tests. */\nexport function buildContextWindowIndex(cache: OpencodeCacheFile): Map<string, number> {\n const index = new Map<string, number>();\n const allLimits = new Map<string, number[]>();\n\n for (const [providerKey, providerData] of Object.entries(cache)) {\n const models = providerData?.models;\n if (!models) continue;\n for (const [modelId, entry] of Object.entries(models)) {\n const ctx = entry.limit?.context;\n if (typeof ctx !== 'number' || ctx <= 0) continue;\n\n const limits = allLimits.get(modelId) ?? [];\n limits.push(ctx);\n allLimits.set(modelId, limits);\n\n if (CACHE_PROVIDER_PRIORITY.has(providerKey)) {\n index.set(modelId, ctx);\n }\n }\n }\n\n for (const [modelId, limits] of allLimits) {\n if (!index.has(modelId)) {\n index.set(modelId, Math.max(...limits));\n }\n }\n\n return index;\n}\n\nfunction getCacheIndex(): Map<string, number> {\n if (cacheIndex === undefined) {\n const cache = loadOpencodeCache();\n cacheIndex = cache ? buildContextWindowIndex(cache) : new Map();\n }\n return cacheIndex;\n}\n\nexport function contextWindowFromHeuristics(modelId: string): number {\n const cached = heuristicCache.get(modelId);\n if (cached !== undefined) return cached;\n for (const [pattern, size] of HEURISTIC_RULES) {\n if (pattern.test(modelId)) {\n heuristicCache.set(modelId, size);\n return size;\n }\n }\n heuristicCache.set(modelId, DEFAULT_CONTEXT_WINDOW);\n return DEFAULT_CONTEXT_WINDOW;\n}\n\nexport function lookupContextWindow(modelId: string): number {\n return getCacheIndex().get(modelId) ?? contextWindowFromHeuristics(modelId);\n}\n\n/** Prefer an explicit limit.context (or pre-resolved value), else resolve from cache/heuristics. */\nexport function resolveContextWindow(modelId: string, explicit?: number): number {\n if (typeof explicit === 'number' && explicit > 0) return explicit;\n return lookupContextWindow(modelId);\n}\n","// opencode-auth.ts — read OpenCode ~/.local/share/opencode/auth.json for one-time OAuth import\n\nimport { existsSync, readFileSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport interface OpencodeOAuthCredential {\n type: 'oauth';\n access: string;\n refresh: string;\n expires: number;\n accountId?: string;\n enterpriseUrl?: string;\n providerData?: Record<string, unknown>;\n}\n\nexport interface OpencodeWellKnownCredential {\n type: 'wellknown';\n key: string;\n token: string;\n}\n\nexport type OpencodeAuthEntry = OpencodeOAuthCredential | OpencodeWellKnownCredential | string;\n\nexport interface ReadOpencodeAuthResult {\n path: string;\n entries: Record<string, OpencodeAuthEntry>;\n permissionWarning?: string;\n}\n\nexport function resolveOpencodeAuthPath(env: NodeJS.ProcessEnv = process.env): string {\n const dataHome = env['XDG_DATA_HOME'] ?? join(homedir(), '.local', 'share');\n if (process.platform === 'win32') {\n return join(env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming'), 'opencode', 'auth.json');\n }\n return join(dataHome, 'opencode', 'auth.json');\n}\n\nfunction decodeAuthEntry(value: unknown): OpencodeAuthEntry | null {\n if (typeof value === 'string' && value.trim()) return value.trim();\n if (!value || typeof value !== 'object') return null;\n const record = value as Record<string, unknown>;\n if (record['type'] === 'oauth'\n && typeof record['access'] === 'string'\n && typeof record['refresh'] === 'string'\n && typeof record['expires'] === 'number') {\n return {\n type: 'oauth',\n access: record['access'],\n refresh: record['refresh'],\n expires: record['expires'],\n accountId: typeof record['accountId'] === 'string' ? record['accountId'] : undefined,\n enterpriseUrl: typeof record['enterpriseUrl'] === 'string' ? record['enterpriseUrl'] : undefined,\n providerData: record['providerData'] && typeof record['providerData'] === 'object' && !Array.isArray(record['providerData'])\n ? record['providerData'] as Record<string, unknown>\n : undefined,\n };\n }\n if (record['type'] === 'wellknown'\n && typeof record['key'] === 'string'\n && typeof record['token'] === 'string') {\n return { type: 'wellknown', key: record['key'], token: record['token'] };\n }\n return null;\n}\n\n/** Warn when auth.json is group/world readable (OpenCode uses 0600). */\nexport function authFilePermissionWarning(path: string): string | undefined {\n if (!existsSync(path)) return undefined;\n if (process.platform === 'win32') return undefined;\n try {\n const mode = statSync(path).mode & 0o777;\n if (mode & 0o077) {\n return `OpenCode auth file ${path} is readable by others (mode ${mode.toString(8)}). Consider chmod 600.`;\n }\n } catch {\n // ignore\n }\n return undefined;\n}\n\nexport function readOpencodeAuthFile(env: NodeJS.ProcessEnv = process.env): ReadOpencodeAuthResult | null {\n const path = resolveOpencodeAuthPath(env);\n if (!existsSync(path)) return null;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(readFileSync(path, 'utf8'));\n } catch {\n return { path, entries: {}, permissionWarning: authFilePermissionWarning(path) };\n }\n\n const entries: Record<string, OpencodeAuthEntry> = {};\n if (parsed && typeof parsed === 'object') {\n for (const [providerId, value] of Object.entries(parsed as Record<string, unknown>)) {\n const entry = decodeAuthEntry(value);\n if (entry) entries[providerId] = entry;\n }\n }\n\n return {\n path,\n entries,\n permissionWarning: authFilePermissionWarning(path),\n };\n}\n\nexport function isOpencodeOAuth(entry: OpencodeAuthEntry | undefined): entry is OpencodeOAuthCredential {\n return !!entry && typeof entry === 'object' && entry.type === 'oauth';\n}\n\nexport function oauthCredentialToKeychainJson(cred: OpencodeOAuthCredential): string {\n return JSON.stringify(cred);\n}\n","// oauth/types.ts — stored OAuth credential shape (matches OpenCode auth.json)\n\nimport type { OpencodeOAuthCredential } from '../registry/opencode-auth.js';\n\nexport type StoredOAuthCredential = OpencodeOAuthCredential;\n\nexport interface OAuthTokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n /** Non-secret provider metadata discovered during token exchange. */\n providerData?: Record<string, unknown>;\n}\n\nexport function tokensToStoredCredential(\n tokens: OAuthTokenResponse,\n existingRefresh?: string,\n accountId?: string,\n providerData?: Record<string, unknown>,\n): StoredOAuthCredential {\n const mergedProviderData = providerData || tokens.providerData\n ? { ...providerData, ...tokens.providerData }\n : undefined;\n return {\n type: 'oauth',\n access: tokens.access_token,\n refresh: tokens.refresh_token ?? existingRefresh ?? '',\n expires: Date.now() + (tokens.expires_in ?? 3600) * 1000,\n ...(accountId ? { accountId } : {}),\n ...(mergedProviderData ? { providerData: mergedProviderData } : {}),\n };\n}\n\nexport function parseStoredOAuthCredential(raw: string | null): StoredOAuthCredential | null {\n if (!raw?.trim().startsWith('{')) return null;\n try {\n const parsed = JSON.parse(raw) as StoredOAuthCredential;\n if (parsed.type === 'oauth'\n && typeof parsed.access === 'string'\n && typeof parsed.refresh === 'string'\n && typeof parsed.expires === 'number') {\n return parsed;\n }\n } catch {\n // ignore\n }\n return null;\n}\n\nexport const OAUTH_REFRESH_SKEW_MS = 120_000;\n\nexport function oauthCredentialNeedsRefresh(cred: StoredOAuthCredential, skewMs = OAUTH_REFRESH_SKEW_MS): boolean {\n return cred.expires <= Date.now() + Math.max(0, skewMs);\n}\n\n/** JWT exp claim — best-effort; opaque tokens return false (no proactive refresh). */\nexport function accessTokenIsExpiring(token: string | undefined, skewMs = OAUTH_REFRESH_SKEW_MS): boolean {\n if (!token) return false;\n const parts = token.split('.');\n if (parts.length < 2) return false;\n try {\n let payload = parts[1]!.replace(/-/g, '+').replace(/_/g, '/');\n while (payload.length % 4 !== 0) payload += '=';\n const claims = JSON.parse(Buffer.from(payload, 'base64').toString('utf8')) as { exp?: number };\n if (typeof claims.exp !== 'number') return false;\n return claims.exp * 1000 <= Date.now() + Math.max(0, skewMs);\n } catch {\n return false;\n }\n}\n\nexport const NATIVE_OAUTH_PROVIDER_IDS = ['xai', 'xai-oauth', 'openai', 'openai-oauth', 'github-copilot', 'claude-code', 'antigravity', 'cline-pass'] as const;\nexport type NativeOAuthProviderId = typeof NATIVE_OAUTH_PROVIDER_IDS[number];\n\nexport function supportsNativeOAuth(providerId: string): providerId is NativeOAuthProviderId {\n return (NATIVE_OAUTH_PROVIDER_IDS as readonly string[]).includes(providerId);\n}\n\n/** Providers that use Authorization Code + PKCE (browser redirect), not device code polling. */\nexport const BROWSER_REDIRECT_OAUTH_IDS = ['claude-code', 'antigravity'] as const;\nexport type BrowserRedirectOAuthId = typeof BROWSER_REDIRECT_OAUTH_IDS[number];\n\nexport function isBrowserRedirectOAuth(id: string): id is BrowserRedirectOAuthId {\n return (BROWSER_REDIRECT_OAUTH_IDS as readonly string[]).includes(id);\n}\n","// github.ts — native GitHub Copilot OAuth (RFC 8628 device code)\n// Uses the same public client ID as the VS Code Copilot extension.\n// Flow: device code → ghu_ access token → exchange for short-lived Copilot session token.\n// The ghu_ token is stored as the \"refresh token\" and re-exchanged when the Copilot token expires.\n\nimport { positiveSecondsToMs, sleepMs } from './pkce.js';\nimport type { OAuthTokenResponse } from './types.js';\nimport { VERSION } from '../constants.js';\n\n// Public OAuth App client ID used by VS Code GitHub Copilot extension\nconst CLIENT_ID = 'Iv1.b507a08c87ecfe98';\nconst DEVICE_CODE_URL = 'https://github.com/login/device/code';\nconst TOKEN_URL = 'https://github.com/login/oauth/access_token';\nconst COPILOT_TOKEN_URL = 'https://api.github.com/copilot_internal/v2/token';\nconst COPILOT_USER_URL = 'https://api.github.com/copilot_internal/user';\nconst SCOPE = 'copilot';\n\nconst DEVICE_CODE_DEFAULT_INTERVAL_MS = 5_000;\nconst DEVICE_CODE_DEFAULT_EXPIRES_MS = 15 * 60 * 1000; // 15 minutes\nconst OAUTH_POLLING_SAFETY_MARGIN_MS = 1_000;\nconst FREE_COPILOT_SKUS = new Set([\n 'free_limited_copilot',\n 'free_educational_quota',\n 'no_auth_limited_copilot',\n]);\n\nexport interface CopilotAccountSummary {\n login?: string;\n access_type_sku?: string;\n copilot_plan?: string;\n is_free_plan?: boolean;\n lookup_status: 'known' | 'unknown';\n}\n\nexport interface GithubDeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_in?: number;\n interval?: number;\n}\n\nfunction commonHeaders(): Record<string, string> {\n return {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'User-Agent': `relay-ai/${VERSION}`,\n };\n}\n\nexport function classifyCopilotAccount(user: Record<string, unknown>): CopilotAccountSummary {\n const login = typeof user['login'] === 'string' && user['login'].trim() ? user['login'].trim() : undefined;\n const sku = typeof user['access_type_sku'] === 'string' && user['access_type_sku'].trim()\n ? user['access_type_sku'].trim()\n : undefined;\n const plan = typeof user['copilot_plan'] === 'string' && user['copilot_plan'].trim()\n ? user['copilot_plan'].trim()\n : undefined;\n if (!sku && !plan) {\n return {\n ...(login ? { login } : {}),\n lookup_status: 'unknown',\n };\n }\n const isFree = FREE_COPILOT_SKUS.has(sku?.toLowerCase() ?? '') || plan?.toLowerCase() === 'free';\n return {\n ...(login ? { login } : {}),\n ...(sku ? { access_type_sku: sku } : {}),\n ...(plan ? { copilot_plan: plan } : {}),\n is_free_plan: isFree,\n lookup_status: 'known',\n };\n}\n\nexport async function fetchCopilotAccount(ghuToken: string): Promise<CopilotAccountSummary> {\n const response = await fetch(COPILOT_USER_URL, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${ghuToken}`,\n Accept: 'application/json',\n 'User-Agent': `relay-ai/${VERSION}`,\n 'Editor-Version': 'vscode/1.85.1',\n 'X-GitHub-Api-Version': '2025-04-01',\n },\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => '');\n throw new Error(`GitHub Copilot account lookup failed (${response.status})${detail ? `: ${detail}` : ''}`);\n }\n const json = await response.json() as unknown;\n if (!json || typeof json !== 'object' || Array.isArray(json)) {\n throw new Error('GitHub Copilot account lookup returned invalid JSON');\n }\n return classifyCopilotAccount(json as Record<string, unknown>);\n}\n\nexport async function requestGithubDeviceCode(): Promise<GithubDeviceCodeResponse> {\n const response = await fetch(DEVICE_CODE_URL, {\n method: 'POST',\n headers: commonHeaders(),\n body: new URLSearchParams({ client_id: CLIENT_ID, scope: SCOPE }).toString(),\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => '');\n throw new Error(`GitHub device code request failed (${response.status})${detail ? `: ${detail}` : ''}`);\n }\n const json = await response.json() as GithubDeviceCodeResponse;\n if (!json.device_code || !json.user_code || !json.verification_uri) {\n throw new Error('GitHub device code response is missing required fields');\n }\n return json;\n}\n\n/** Exchange a ghu_ GitHub OAuth user token for a short-lived Copilot session token. */\nexport async function exchangeForCopilotToken(ghuToken: string): Promise<OAuthTokenResponse> {\n const response = await fetch(COPILOT_TOKEN_URL, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${ghuToken}`,\n 'User-Agent': `relay-ai/${VERSION}`,\n Accept: 'application/json',\n },\n });\n if (!response.ok) {\n const msg = await response.text().catch(() => '');\n throw new Error(`GitHub Copilot token exchange failed (${response.status})${msg ? `: ${msg}` : ''}`);\n }\n const json = await response.json() as { token?: string; expires_at?: string };\n if (!json.token) {\n throw new Error('GitHub Copilot token exchange response missing token field — is Copilot subscription active?');\n }\n // expires_at is an ISO string; convert to expires_in seconds\n let expiresIn = 1800; // default 30 min\n if (json.expires_at) {\n const expiresMs = new Date(json.expires_at).getTime() - Date.now();\n if (expiresMs > 0) expiresIn = Math.floor(expiresMs / 1000);\n }\n let account: CopilotAccountSummary = { lookup_status: 'unknown' };\n try {\n account = await fetchCopilotAccount(ghuToken);\n } catch {\n // A plan lookup outage must not invalidate an otherwise usable session token.\n }\n return {\n access_token: json.token,\n expires_in: expiresIn,\n providerData: { copilot: account },\n };\n}\n\n/**\n * Refresh: the stored \"refresh token\" is actually the long-lived ghu_ OAuth token.\n * We just re-exchange it for a new short-lived Copilot session token.\n */\nexport async function refreshGithubCopilotToken(ghuToken: string): Promise<OAuthTokenResponse> {\n const copilot = await exchangeForCopilotToken(ghuToken);\n return {\n ...copilot,\n refresh_token: ghuToken, // keep the same ghu_ token as refresh\n };\n}\n\nexport async function pollGithubDeviceCodeToken(\n device: GithubDeviceCodeResponse,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<OAuthTokenResponse> {\n const sleep = opts?.sleep ?? sleepMs;\n const now = opts?.now ?? (() => Date.now());\n const deadline = now() + positiveSecondsToMs(device.expires_in, DEVICE_CODE_DEFAULT_EXPIRES_MS);\n let intervalMs = Math.max(\n positiveSecondsToMs(device.interval, DEVICE_CODE_DEFAULT_INTERVAL_MS),\n 1_000,\n );\n\n while (now() < deadline) {\n const response = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: commonHeaders(),\n body: new URLSearchParams({\n client_id: CLIENT_ID,\n device_code: device.device_code,\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n }).toString(),\n });\n\n const body = await response.json().catch(() => ({}) as Record<string, unknown>) as Record<string, unknown>;\n const error = body['error'] as string | undefined;\n\n if (!error && body['access_token']) {\n const ghuToken = body['access_token'] as string;\n // Exchange ghu_ token for a Copilot session token\n const copilot = await exchangeForCopilotToken(ghuToken);\n return {\n access_token: copilot.access_token,\n refresh_token: ghuToken, // store ghu_ as refresh for re-exchange later\n expires_in: copilot.expires_in,\n providerData: copilot.providerData,\n };\n }\n\n if (error === 'authorization_pending') {\n await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, Math.max(0, deadline - now())));\n continue;\n }\n if (error === 'slow_down') {\n intervalMs += 5_000;\n await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, Math.max(0, deadline - now())));\n continue;\n }\n if (error === 'expired_token') {\n throw new Error('GitHub device code expired — please run relay-ai providers auth github-copilot again');\n }\n throw new Error(`GitHub device authorization failed${error ? `: ${error}` : ''}`);\n }\n throw new Error('GitHub device authorization timed out');\n}\n\nexport async function runGithubDeviceCodeFlow(\n onDeviceCode: (info: { url: string; userCode: string }) => void,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<OAuthTokenResponse> {\n const device = await requestGithubDeviceCode();\n onDeviceCode({ url: device.verification_uri, userCode: device.user_code });\n return pollGithubDeviceCodeToken(device, opts);\n}\n","// xai.ts — native xAI SuperGrok OAuth (RFC 8628 device code, ported from OpenCode)\n\nimport { positiveSecondsToMs, sleepMs } from './pkce.js';\nimport type { OAuthTokenResponse } from './types.js';\nimport { VERSION } from '../constants.js';\nimport { postOAuthRefresh } from './refresh-http.js';\n\nconst CLIENT_ID = 'b1a00492-073a-47ea-816f-4c329264a828';\nconst TOKEN_URL = 'https://auth.x.ai/oauth2/token';\nconst DEVICE_AUTHORIZATION_URL = 'https://auth.x.ai/oauth2/device/code';\nconst DEVICE_CODE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';\nconst SCOPE = 'openid profile email offline_access grok-cli:access api:access';\n\nconst DEVICE_CODE_DEFAULT_INTERVAL_MS = 5_000;\nconst DEVICE_CODE_MIN_INTERVAL_MS = 1_000;\nconst DEVICE_CODE_SLOW_DOWN_INCREMENT_MS = 5_000;\nconst DEVICE_CODE_DEFAULT_EXPIRES_MS = 5 * 60 * 1000;\nconst OAUTH_POLLING_SAFETY_MARGIN_MS = 3_000;\n\nexport interface XaiDeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete?: string;\n expires_in?: number;\n interval?: number;\n}\n\nfunction authHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n 'User-Agent': `relay-ai/${VERSION}`,\n };\n}\n\nexport async function requestXaiDeviceCode(): Promise<XaiDeviceCodeResponse> {\n const response = await fetch(DEVICE_AUTHORIZATION_URL, {\n method: 'POST',\n headers: authHeaders(),\n body: new URLSearchParams({\n client_id: CLIENT_ID,\n scope: SCOPE,\n }).toString(),\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => '');\n throw new Error(`xAI device code request failed (${response.status})${detail ? `: ${detail}` : ''}`);\n }\n const json = await response.json() as XaiDeviceCodeResponse;\n if (!json.device_code || !json.user_code || !json.verification_uri) {\n throw new Error('xAI device code response is missing required fields');\n }\n return json;\n}\n\nexport async function pollXaiDeviceCodeToken(\n device: XaiDeviceCodeResponse,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<OAuthTokenResponse> {\n const sleep = opts?.sleep ?? sleepMs;\n const now = opts?.now ?? (() => Date.now());\n const deadline = now() + positiveSecondsToMs(device.expires_in, DEVICE_CODE_DEFAULT_EXPIRES_MS);\n let intervalMs = Math.max(\n positiveSecondsToMs(device.interval, DEVICE_CODE_DEFAULT_INTERVAL_MS),\n DEVICE_CODE_MIN_INTERVAL_MS,\n );\n\n while (now() < deadline) {\n const response = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: authHeaders(),\n body: new URLSearchParams({\n grant_type: DEVICE_CODE_GRANT_TYPE,\n client_id: CLIENT_ID,\n device_code: device.device_code,\n }).toString(),\n });\n if (response.ok) return response.json() as Promise<OAuthTokenResponse>;\n\n const body = await response.json().catch(() => ({})) as { error?: string };\n const remaining = Math.max(0, deadline - now());\n if (body.error === 'authorization_pending') {\n await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, remaining));\n continue;\n }\n if (body.error === 'slow_down') {\n intervalMs += DEVICE_CODE_SLOW_DOWN_INCREMENT_MS;\n await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, remaining));\n continue;\n }\n throw new Error(`xAI device authorization failed${body.error ? `: ${body.error}` : ''}`);\n }\n throw new Error('xAI device authorization timed out');\n}\n\nexport async function refreshXaiAccessToken(refreshToken: string): Promise<OAuthTokenResponse> {\n return postOAuthRefresh(\n TOKEN_URL,\n new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: CLIENT_ID,\n }),\n {\n contentType: 'form',\n errorPrefix: 'xAI token refresh failed',\n includeStatus: true,\n includeBody: true,\n headers: authHeaders(),\n },\n );\n}\n\nexport async function runXaiDeviceCodeFlow(\n onDeviceCode: (info: { url: string; userCode: string }) => void,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<OAuthTokenResponse> {\n const device = await requestXaiDeviceCode();\n onDeviceCode({\n url: device.verification_uri_complete ?? device.verification_uri,\n userCode: device.user_code,\n });\n return pollXaiDeviceCodeToken(device, opts);\n}\n","// src/oauth/claude-code.ts — Authorization Code + PKCE flow for Claude Code OAuth.\n// Client ID is the public PKCE credential shipped in the Claude Code CLI binary.\n\nimport { randomBytes } from 'node:crypto';\nimport open from 'open';\nimport { generatePkce, generateOAuthState } from './pkce.js';\nimport type { OAuthTokenResponse } from './types.js';\nimport { postOAuthRefresh } from './refresh-http.js';\n\nexport const CLAUDE_CODE_CLIENT_ID =\n process.env.CLAUDE_OAUTH_CLIENT_ID ?? '9d1c250a-e61b-44d9-88ed-5944d1962f5e';\n\nconst AUTHORIZE_URL = 'https://claude.ai/oauth/authorize';\nconst TOKEN_URL = 'https://api.anthropic.com/v1/oauth/token';\nconst REDIRECT_URI =\n process.env.CLAUDE_CODE_REDIRECT_URI ?? 'https://platform.claude.com/oauth/code/callback';\nconst SCOPES =\n 'org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers';\n\n// Pinned to a captured claude-cli release — bump when Anthropic updates.\nexport const CLAUDE_CODE_CLI_VERSION = '2.1.195';\n\nexport interface ClaudeCodePkceParams {\n authUrl: string;\n codeVerifier: string;\n oauthState: string;\n redirectUri: string;\n}\n\nexport async function buildClaudeCodeAuthUrl(redirectUri = REDIRECT_URI): Promise<ClaudeCodePkceParams> {\n const { verifier, challenge } = await generatePkce();\n const state = generateOAuthState();\n const params = new URLSearchParams({\n code: 'true',\n client_id: CLAUDE_CODE_CLIENT_ID,\n response_type: 'code',\n redirect_uri: redirectUri,\n scope: SCOPES,\n code_challenge: challenge,\n code_challenge_method: 'S256',\n state,\n // Forces fresh auth — prevents session takeover that invalidates previous refresh tokens.\n prompt: 'login',\n });\n return { authUrl: `${AUTHORIZE_URL}?${params}`, codeVerifier: verifier, oauthState: state, redirectUri };\n}\n\nexport async function exchangeClaudeCodeToken(\n code: string,\n codeVerifier: string,\n redirectUri: string,\n state: string,\n): Promise<OAuthTokenResponse> {\n // Anthropic may return code as `authCode#stateValue` — split if needed.\n let authCode = extractClaudeAuthCode(code);\n let codeState = state;\n if (authCode.includes('#')) {\n const idx = authCode.indexOf('#');\n codeState = authCode.slice(idx + 1) || state;\n authCode = authCode.slice(0, idx);\n }\n\n const res = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Accept: 'application/json' },\n body: JSON.stringify({\n code: authCode,\n state: codeState,\n grant_type: 'authorization_code',\n client_id: CLAUDE_CODE_CLIENT_ID,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n }),\n });\n if (!res.ok) throw new Error(`Claude Code token exchange failed: ${await res.text()}`);\n return res.json() as Promise<OAuthTokenResponse>;\n}\n\nexport function extractClaudeAuthCode(input: string): string {\n const trimmed = input.trim();\n try {\n const parsed = new URL(trimmed);\n return parsed.searchParams.get('code') ?? trimmed;\n } catch {\n if (trimmed.startsWith('?') || trimmed.includes('code=')) {\n const query = trimmed.startsWith('?') ? trimmed.slice(1) : trimmed;\n return new URLSearchParams(query).get('code') ?? trimmed;\n }\n return trimmed;\n }\n}\n\nexport async function refreshClaudeCodeToken(refreshToken: string): Promise<OAuthTokenResponse> {\n return postOAuthRefresh(\n TOKEN_URL,\n {\n grant_type: 'refresh_token',\n client_id: CLAUDE_CODE_CLIENT_ID,\n refresh_token: refreshToken,\n },\n {\n contentType: 'json',\n errorPrefix: 'Claude Code token refresh failed',\n includeBody: true,\n },\n );\n}\n\nexport interface ClaudeBootstrapInfo {\n accountId?: string;\n email?: string;\n organizationId?: string;\n organizationName?: string;\n plan?: string;\n}\n\nexport async function fetchClaudeBootstrap(accessToken: string): Promise<ClaudeBootstrapInfo> {\n try {\n const res = await fetch('https://api.anthropic.com/api/claude_cli/bootstrap', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n Accept: 'application/json',\n 'User-Agent': `claude-cli/${CLAUDE_CODE_CLI_VERSION} (external, cli)`,\n 'anthropic-beta': 'oauth-2025-04-20',\n },\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) return {};\n const data = (await res.json()) as Record<string, unknown>;\n const acct = data.oauth_account as Record<string, unknown> | undefined;\n if (!acct) return {};\n return {\n accountId: typeof acct.account_uuid === 'string' ? acct.account_uuid : undefined,\n email: typeof acct.account_email === 'string' ? acct.account_email : undefined,\n organizationId: typeof acct.organization_uuid === 'string' ? acct.organization_uuid : undefined,\n organizationName: typeof acct.organization_name === 'string' ? acct.organization_name : undefined,\n plan: typeof acct.organization_rate_limit_tier === 'string' ? acct.organization_rate_limit_tier : undefined,\n };\n } catch {\n return {};\n }\n}\n\n/** Generate a new cliUserID — created once at provisioning and persisted in providerData. */\nexport function generateCliUserID(): string {\n return randomBytes(32).toString('hex');\n}\n\n/** Full CLI PKCE flow: opens browser, accepts Anthropic's returned code, exchanges it. */\nexport async function runClaudeCodeOAuthFlow(\n onAuthUrl: (url: string) => void,\n readAuthCode: () => Promise<string>,\n): Promise<{ tokens: OAuthTokenResponse; bootstrap: ClaudeBootstrapInfo }> {\n const { authUrl, codeVerifier, oauthState, redirectUri } = await buildClaudeCodeAuthUrl();\n onAuthUrl(authUrl);\n open(authUrl).catch(() => {});\n const code = (await readAuthCode()).trim();\n if (!code) throw new Error('No authorization code received from Anthropic');\n const tokens = await exchangeClaudeCodeToken(code, codeVerifier, redirectUri, oauthState);\n const bootstrap = await fetchClaudeBootstrap(tokens.access_token);\n return { tokens, bootstrap };\n}\n\nexport interface ClaudeCodeModelEntry {\n id: string;\n displayName: string;\n maxInputTokens?: number;\n maxTokens?: number;\n}\n\nexport async function fetchClaudeCodeModels(accessToken: string): Promise<ClaudeCodeModelEntry[]> {\n const res = await fetch('https://api.anthropic.com/v1/models', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'anthropic-version': '2023-06-01',\n Accept: 'application/json',\n 'User-Agent': `claude-cli/${CLAUDE_CODE_CLI_VERSION} (external, cli)`,\n },\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) {\n throw new Error(`Claude Code model discovery failed (HTTP ${res.status}): ${await res.text().catch(() => '')}`);\n }\n const body = (await res.json()) as { data?: Array<Record<string, unknown>> };\n const entries = (body.data ?? [])\n .filter((m): m is Record<string, unknown> & { id: string } =>\n typeof m.id === 'string' && m.id.length > 0)\n .map(m => ({\n id: m.id as string,\n displayName: (typeof m.display_name === 'string' ? m.display_name : m.id) as string,\n maxInputTokens: typeof m.max_input_tokens === 'number' ? m.max_input_tokens : undefined,\n maxTokens: typeof m.max_tokens === 'number' ? m.max_tokens : undefined,\n }));\n if (entries.length === 0) {\n throw new Error('Claude Code model discovery returned no models');\n }\n return entries;\n}\n\n/** For the GUI: complete token exchange given code received via /oauth/callback. */\nexport async function completeClaudeCodeExchange(\n code: string,\n codeVerifier: string,\n oauthState: string,\n redirectUri: string,\n): Promise<{ tokens: OAuthTokenResponse; bootstrap: ClaudeBootstrapInfo }> {\n const tokens = await exchangeClaudeCodeToken(code, codeVerifier, redirectUri, oauthState);\n const bootstrap = await fetchClaudeBootstrap(tokens.access_token);\n return { tokens, bootstrap };\n}\n\n/** Redirect URI for the GUI callback (port extracted from Host header). */\nexport function guiCallbackRedirectUri(host: string): string {\n return `http://${host}/oauth/callback`;\n}\n","// src/oauth/antigravity-oauth.ts — Authorization Code + PKCE flow for Antigravity\n// (Google Cloud Code Assist). Client credentials are the public values shipped in\n// the Antigravity CLI binary (PKCE — not secrets per RFC 8252 / Google docs).\n\nimport open from 'open';\nimport { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join as pathJoin } from 'node:path';\nimport { generatePkce, generateOAuthState } from './pkce.js';\nimport { startCallbackServer } from './callback-server.js';\nimport type { OAuthTokenResponse } from './types.js';\nimport { postOAuthRefresh } from './refresh-http.js';\n\nconst DEFAULT_ANTIGRAVITY_CLIENT_ID = ['107100606059', '1-tmhssin2h2', '1lcre235vtol', 'ojh4g403ep.a', 'pps.googleus', 'ercontent.co', 'm'].join('');\nconst DEFAULT_ANTIGRAVITY_CLIENT_SECRET = ['GOCS', 'PX-K', '58FW', 'R486', 'LdLJ', '1mLB', '8sXC', '4z6q', 'DAf'].join('');\n\nexport const ANTIGRAVITY_CLIENT_ID =\n process.env.ANTIGRAVITY_OAUTH_CLIENT_ID ?? DEFAULT_ANTIGRAVITY_CLIENT_ID;\n\nexport const ANTIGRAVITY_CLIENT_SECRET =\n process.env.ANTIGRAVITY_OAUTH_CLIENT_SECRET ?? DEFAULT_ANTIGRAVITY_CLIENT_SECRET;\n\nconst AUTHORIZE_URL = 'https://accounts.google.com/o/oauth2/v2/auth';\nconst TOKEN_URL = 'https://oauth2.googleapis.com/token';\nconst USER_INFO_URL = 'https://www.googleapis.com/oauth2/v1/userinfo';\n\nconst SCOPES = [\n 'openid',\n 'https://www.googleapis.com/auth/cloud-platform',\n 'https://www.googleapis.com/auth/userinfo.email',\n 'https://www.googleapis.com/auth/userinfo.profile',\n 'https://www.googleapis.com/auth/cclog',\n 'https://www.googleapis.com/auth/experimentsandconfigs',\n].join(' ');\n\n// Pinned to Antigravity-Manager version used for header fingerprinting.\nconst ANTIGRAVITY_VERSION = '4.2.0';\nexport const ANTIGRAVITY_USER_AGENT = `vscode/1.X.X (Antigravity/${ANTIGRAVITY_VERSION})`;\nconst ANTIGRAVITY_METADATA = { ideType: 'ANTIGRAVITY' };\n\n// Cloud Code Assist base URLs — tried in order, first success wins.\nexport const ANTIGRAVITY_BASE_URLS = [\n 'https://daily-cloudcode-pa.googleapis.com',\n 'https://cloudcode-pa.googleapis.com',\n 'https://daily-cloudcode-pa.sandbox.googleapis.com',\n];\nexport const ANTIGRAVITY_API_VERSION = 'v1internal';\n\nexport interface AntigravityPkceParams {\n authUrl: string;\n codeVerifier: string;\n oauthState: string;\n redirectUri: string;\n}\n\nexport async function buildAntigravityAuthUrl(\n redirectUri: string,\n): Promise<AntigravityPkceParams> {\n const { verifier, challenge } = await generatePkce();\n const state = generateOAuthState();\n const params = new URLSearchParams({\n client_id: ANTIGRAVITY_CLIENT_ID,\n response_type: 'code',\n redirect_uri: redirectUri,\n scope: SCOPES,\n state,\n access_type: 'offline',\n prompt: 'consent',\n code_challenge: challenge,\n code_challenge_method: 'S256',\n });\n return { authUrl: `${AUTHORIZE_URL}?${params}`, codeVerifier: verifier, oauthState: state, redirectUri };\n}\n\nexport async function exchangeAntigravityToken(\n code: string,\n codeVerifier: string,\n redirectUri: string,\n): Promise<OAuthTokenResponse> {\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: ANTIGRAVITY_CLIENT_ID,\n client_secret: ANTIGRAVITY_CLIENT_SECRET,\n code,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n });\n\n const res = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n 'User-Agent': ANTIGRAVITY_USER_AGENT,\n },\n body,\n });\n if (!res.ok) throw new Error(`Antigravity token exchange failed: ${await res.text()}`);\n return res.json() as Promise<OAuthTokenResponse>;\n}\n\nexport async function refreshAntigravityToken(refreshToken: string): Promise<OAuthTokenResponse> {\n return postOAuthRefresh(\n TOKEN_URL,\n new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: ANTIGRAVITY_CLIENT_ID,\n client_secret: ANTIGRAVITY_CLIENT_SECRET,\n refresh_token: refreshToken,\n }),\n {\n contentType: 'form',\n errorPrefix: 'Antigravity token refresh failed',\n includeBody: true,\n },\n );\n}\n\nexport interface AntigravityUserInfo {\n email?: string;\n name?: string;\n}\n\nasync function fetchUserInfo(accessToken: string): Promise<AntigravityUserInfo> {\n try {\n const res = await fetch(`${USER_INFO_URL}?alt=json`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) return {};\n const data = (await res.json()) as Record<string, unknown>;\n return {\n email: typeof data.email === 'string' ? data.email : undefined,\n name: typeof data.name === 'string' ? data.name : undefined,\n };\n } catch {\n return {};\n }\n}\n\nfunction apiHeaders(accessToken: string): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': ANTIGRAVITY_USER_AGENT,\n };\n}\n\nasync function fetchFirstOk(\n paths: string[],\n init: RequestInit,\n): Promise<Response> {\n let lastErr: unknown;\n for (const url of paths) {\n try {\n const res = await fetch(url, init);\n if (res.ok) return res;\n lastErr = new Error(`${res.status} ${await res.text()}`);\n } catch (err) {\n lastErr = err;\n }\n }\n throw lastErr ?? new Error('All Antigravity endpoints failed');\n}\n\n// ── Onboarding tier extraction — adapted from OmniRoute codeAssistSubscription.ts (MIT) ──\n\ntype JsonRecord = Record<string, unknown>;\n\nfunction toRecord(v: unknown): JsonRecord {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as JsonRecord) : {};\n}\n\nfunction pickTierId(tier: unknown): string | null {\n const v = toRecord(tier).id;\n return typeof v === 'string' && v.trim() ? v.trim() : null;\n}\n\nfunction findDefaultAllowedTier(sub: JsonRecord): JsonRecord | null {\n if (!Array.isArray(sub.allowedTiers)) return null;\n for (const t of sub.allowedTiers) {\n const tier = toRecord(t);\n if (tier.isDefault) return tier;\n }\n return null;\n}\n\nexport function resolveAntigravityOnboardTierId(data: unknown): string {\n const sub = toRecord(data);\n const hasIneligible = Array.isArray(sub.ineligibleTiers) && sub.ineligibleTiers.length > 0;\n if (!hasIneligible) {\n const current = pickTierId(sub.currentTier);\n if (current) return current;\n }\n const def = findDefaultAllowedTier(sub);\n if (def) {\n const defId = pickTierId(def);\n if (defId) return defId;\n }\n const paid = pickTierId(sub.paidTier);\n if (paid) return paid;\n return pickTierId(sub.currentTier) ?? 'legacy-tier';\n}\n\n// ── Cloud Code Assist bootstrap ────────────────────────────────────────────\n\nexport interface AntigravityBootstrap {\n projectId: string;\n tierId: string;\n}\n\nasync function loadCodeAssist(accessToken: string): Promise<AntigravityBootstrap> {\n const endpoints = ANTIGRAVITY_BASE_URLS.map(b => `${b}/${ANTIGRAVITY_API_VERSION}:loadCodeAssist`);\n\n const res = await fetchFirstOk(endpoints, {\n method: 'POST',\n headers: apiHeaders(accessToken),\n body: JSON.stringify({ metadata: ANTIGRAVITY_METADATA }),\n });\n\n const data = (await res.json()) as Record<string, unknown>;\n let projectId = data.cloudaicompanionProject;\n if (typeof projectId === 'object' && projectId !== null) {\n projectId = (projectId as Record<string, unknown>).id ?? '';\n }\n\n return {\n projectId: typeof projectId === 'string' ? projectId : '',\n tierId: resolveAntigravityOnboardTierId(data),\n };\n}\n\nasync function onboardUser(\n accessToken: string,\n tierId: string,\n maxAttempts = 10,\n): Promise<string> {\n const endpoints = ANTIGRAVITY_BASE_URLS.map(b => `${b}/${ANTIGRAVITY_API_VERSION}:onboardUser`);\n let finalProjectId = '';\n\n for (let i = 0; i < maxAttempts; i++) {\n const res = await fetchFirstOk(endpoints, {\n method: 'POST',\n headers: apiHeaders(accessToken),\n body: JSON.stringify({ tier_id: tierId, metadata: ANTIGRAVITY_METADATA }),\n });\n\n const result = (await res.json()) as Record<string, unknown>;\n if (result.done === true) {\n const p = result.response ? (result.response as Record<string, unknown>).cloudaicompanionProject : undefined;\n if (typeof p === 'string') finalProjectId = p.trim();\n else if (p && typeof p === 'object') finalProjectId = String((p as Record<string, unknown>).id ?? '') || finalProjectId;\n break;\n }\n\n if (i < maxAttempts - 1) await new Promise(r => setTimeout(r, 5000));\n }\n\n return finalProjectId;\n}\n\nexport interface AntigravityOAuthResult {\n tokens: OAuthTokenResponse;\n userInfo: AntigravityUserInfo;\n projectId: string;\n tierId: string;\n}\n\n/** Read the project ID the AGY CLI already set up on this machine, as a fallback\n * when loadCodeAssist fails with a fresh OAuth token. */\nfunction readAgyProjectId(): string {\n try {\n const cache = pathJoin(homedir(), '.gemini', 'antigravity-cli', 'cache', 'projects.json');\n const data = JSON.parse(readFileSync(cache, 'utf8')) as Record<string, string>;\n // Prefer the home-directory project (most general), then any other entry.\n return data[homedir()] ?? Object.values(data)[0] ?? '';\n } catch {\n return '';\n }\n}\n\n/** Shared post-exchange bootstrap: fetch user info + loadCodeAssist + onboardUser.\n * Bootstrap failures are best-effort — auth succeeds even if project setup fails.\n * Falls back to reading the AGY CLI's stored projectId if loadCodeAssist fails. */\nasync function runBootstrap(\n tokens: OAuthTokenResponse,\n): Promise<AntigravityOAuthResult> {\n const [userInfoResult, bootstrapResult] = await Promise.allSettled([\n fetchUserInfo(tokens.access_token),\n loadCodeAssist(tokens.access_token),\n ]);\n\n const userInfo = userInfoResult.status === 'fulfilled' ? userInfoResult.value : {};\n let projectId = bootstrapResult.status === 'fulfilled' ? bootstrapResult.value.projectId : '';\n const tierId = bootstrapResult.status === 'fulfilled' ? bootstrapResult.value.tierId : 'free-tier';\n\n const finalProjectId = await onboardUser(tokens.access_token, tierId, 3).catch(() => '');\n if (finalProjectId) projectId = finalProjectId;\n\n if (!projectId && tierId !== 'free-tier') {\n const freeTierProjectId = await onboardUser(tokens.access_token, 'free-tier', 3).catch(() => '');\n if (freeTierProjectId) projectId = freeTierProjectId;\n }\n\n // Google bootstrap failed or returned no project — fall back to the AGY CLI's stored project.\n if (!projectId) {\n projectId = readAgyProjectId();\n }\n\n return { tokens, userInfo, projectId, tierId };\n}\n\n/** Full CLI PKCE flow: starts local callback server, opens browser, exchanges code. */\nexport async function runAntigravityOAuthFlow(\n onAuthUrl: (url: string) => void,\n): Promise<AntigravityOAuthResult> {\n const server = await startCallbackServer();\n try {\n const { authUrl, codeVerifier, redirectUri } = await buildAntigravityAuthUrl(server.redirectUri);\n onAuthUrl(authUrl);\n open(authUrl).catch(() => {});\n const { code } = await server.waitForCallback();\n if (!code) throw new Error('No authorization code received from Google');\n const tokens = await exchangeAntigravityToken(code, codeVerifier, redirectUri);\n return runBootstrap(tokens);\n } finally {\n server.close();\n }\n}\n\n/** For the GUI: complete token exchange + bootstrap given code from /oauth/callback. */\nexport async function completeAntigravityExchange(\n code: string,\n codeVerifier: string,\n redirectUri: string,\n): Promise<AntigravityOAuthResult> {\n const tokens = await exchangeAntigravityToken(code, codeVerifier, redirectUri);\n return runBootstrap(tokens);\n}\n","// src/oauth/callback-server.ts — CLI fallback local callback server for PKCE OAuth flows.\n// Primary path: the GUI server handles /oauth/callback when the UI is open.\n// This is only used when running `relay-ai providers auth <provider>` without the GUI.\n\nimport http from 'node:http';\n\nexport interface CallbackParams {\n code: string;\n state: string;\n error?: string;\n}\n\nexport interface CallbackServer {\n port: number;\n redirectUri: string;\n waitForCallback(timeoutMs?: number): Promise<CallbackParams>;\n close(): void;\n}\n\nconst SUCCESS_HTML = `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Authorized</title></head>\n<body style=\"font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0\">\n<div style=\"text-align:center;padding:2rem;background:#fff;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,.1)\">\n<div style=\"color:#22c55e;font-size:2.5rem\">&#10003;</div>\n<h1 style=\"margin:.5rem 0\">Authentication successful</h1>\n<p style=\"color:#666\">You can close this tab and return to the terminal.</p>\n</div></body></html>`;\n\nexport function startCallbackServer(): Promise<CallbackServer> {\n return new Promise((resolve, reject) => {\n let codeResolve: ((p: CallbackParams) => void) | undefined;\n let codeReject: ((e: Error) => void) | undefined;\n\n const server = http.createServer((req, res) => {\n const u = new URL(req.url ?? '/', 'http://localhost');\n if (u.pathname !== '/callback' && u.pathname !== '/oauth/callback') {\n res.writeHead(404); res.end(); return;\n }\n const code = u.searchParams.get('code') ?? '';\n const state = u.searchParams.get('state') ?? '';\n const error = u.searchParams.get('error') ?? '';\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(SUCCESS_HTML);\n codeResolve?.({ code, state, error: error || undefined });\n });\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address() as { port: number };\n const port = addr.port;\n resolve({\n port,\n redirectUri: `http://127.0.0.1:${port}/callback`,\n waitForCallback(timeoutMs = 300_000) {\n return new Promise<CallbackParams>((res, rej) => {\n codeResolve = res;\n codeReject = rej;\n setTimeout(\n () => rej(new Error('OAuth timeout — browser closed without completing sign-in')),\n timeoutMs,\n );\n });\n },\n close() { server.close(); codeReject?.(new Error('Server closed')); },\n });\n });\n\n server.on('error', reject);\n });\n}\n","import { CLINE_PASS_REFRESH_URL, CLINE_PASS_REGISTER_URL } from '../cline-pass.js';\nimport { positiveSecondsToMs, sleepMs } from './pkce.js';\nimport type { OAuthTokenResponse } from './types.js';\n\nconst WORKOS_CLIENT_ID = 'client_01K3A541FN8TA3EPPHTD2325AR';\nconst WORKOS_DEVICE_URL = 'https://api.workos.com/user_management/authorize/device';\nconst WORKOS_TOKEN_URL = 'https://api.workos.com/user_management/authenticate';\nconst DEVICE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';\nconst DEFAULT_INTERVAL_MS = 5_000;\nconst SLOW_DOWN_INCREMENT_MS = 1_000;\nconst DEFAULT_EXPIRES_MS = 10 * 60 * 1000;\n\nexport interface ClinePassDeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete?: string;\n expires_in?: number;\n interval?: number;\n}\n\nexport interface ClinePassOAuthResult {\n tokens: OAuthTokenResponse;\n accountId?: string;\n providerData?: Record<string, unknown>;\n}\n\ninterface ClineAuthData {\n accessToken?: unknown;\n refreshToken?: unknown;\n expiresAt?: unknown;\n userInfo?: unknown;\n}\n\nfunction formHeaders(): Record<string, string> {\n return {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n}\n\nfunction jsonHeaders(): Record<string, string> {\n return {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n };\n}\n\nfunction expiresInFromIso(expiresAt: unknown): number {\n if (typeof expiresAt !== 'string') throw new Error('ClinePass response is missing a valid expiresAt');\n const timestamp = Date.parse(expiresAt);\n if (!Number.isFinite(timestamp)) throw new Error('ClinePass response is missing a valid expiresAt');\n return Math.max(1, Math.floor((timestamp - Date.now()) / 1000));\n}\n\nfunction toOAuthResult(data: ClineAuthData): ClinePassOAuthResult {\n if (typeof data.accessToken !== 'string' || !data.accessToken) {\n throw new Error('ClinePass response is missing accessToken');\n }\n const userInfo = data.userInfo && typeof data.userInfo === 'object' && !Array.isArray(data.userInfo)\n ? data.userInfo as Record<string, unknown>\n : undefined;\n const accountId = typeof userInfo?.clineUserId === 'string' ? userInfo.clineUserId : undefined;\n return {\n tokens: {\n access_token: data.accessToken,\n ...(typeof data.refreshToken === 'string' ? { refresh_token: data.refreshToken } : {}),\n expires_in: expiresInFromIso(data.expiresAt),\n ...(userInfo ? { providerData: userInfo } : {}),\n },\n ...(accountId ? { accountId } : {}),\n ...(userInfo ? { providerData: userInfo } : {}),\n };\n}\n\nasync function readError(response: Response): Promise<string> {\n const text = await response.text().catch(() => '');\n if (!text) return `HTTP ${response.status}`;\n try {\n const parsed = JSON.parse(text) as { error?: unknown; message?: unknown };\n const detail = typeof parsed.error === 'string' ? parsed.error : typeof parsed.message === 'string' ? parsed.message : '';\n return detail || `HTTP ${response.status}`;\n } catch {\n return text.slice(0, 120);\n }\n}\n\nexport async function requestClinePassDeviceCode(): Promise<ClinePassDeviceCodeResponse> {\n const response = await fetch(WORKOS_DEVICE_URL, {\n method: 'POST',\n headers: formHeaders(),\n body: new URLSearchParams({ client_id: WORKOS_CLIENT_ID }).toString(),\n });\n if (!response.ok) throw new Error(`ClinePass device code request failed (${response.status})`);\n const json = await response.json() as ClinePassDeviceCodeResponse;\n if (!json.device_code || !json.user_code || !json.verification_uri) {\n throw new Error('ClinePass device code response is missing required fields');\n }\n return json;\n}\n\nexport async function registerClinePassTokens(\n accessToken: string,\n refreshToken: string,\n): Promise<ClinePassOAuthResult> {\n const response = await fetch(CLINE_PASS_REGISTER_URL, {\n method: 'POST',\n headers: jsonHeaders(),\n body: JSON.stringify({ accessToken, refreshToken }),\n });\n if (!response.ok) throw new Error(`ClinePass registration failed (${response.status})`);\n const body = await response.json() as { success?: unknown; data?: ClineAuthData; error?: unknown; message?: unknown };\n if (body.success !== true || !body.data) {\n const detail = typeof body.error === 'string' ? body.error : typeof body.message === 'string' ? body.message : 'unsuccessful response';\n throw new Error(`ClinePass registration failed: ${detail}`);\n }\n return toOAuthResult(body.data);\n}\n\nexport async function pollClinePassDeviceCode(\n device: ClinePassDeviceCodeResponse,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<ClinePassOAuthResult> {\n const sleep = opts?.sleep ?? sleepMs;\n const now = opts?.now ?? (() => Date.now());\n const deadline = now() + positiveSecondsToMs(device.expires_in, DEFAULT_EXPIRES_MS);\n let intervalMs = Math.max(positiveSecondsToMs(device.interval, DEFAULT_INTERVAL_MS), 1_000);\n\n while (now() < deadline) {\n const response = await fetch(WORKOS_TOKEN_URL, {\n method: 'POST',\n headers: formHeaders(),\n body: new URLSearchParams({\n grant_type: DEVICE_GRANT_TYPE,\n client_id: WORKOS_CLIENT_ID,\n device_code: device.device_code,\n }).toString(),\n });\n if (response.ok) {\n const workos = await response.json() as { access_token?: string; refresh_token?: string };\n if (!workos.access_token || !workos.refresh_token) {\n throw new Error('ClinePass WorkOS response is missing required tokens');\n }\n return registerClinePassTokens(workos.access_token, workos.refresh_token);\n }\n\n const body = await response.json().catch(() => ({})) as { error?: string };\n const remaining = Math.max(0, deadline - now());\n if (body.error === 'authorization_pending') {\n await sleep(Math.min(intervalMs, remaining));\n continue;\n }\n if (body.error === 'slow_down') {\n intervalMs += SLOW_DOWN_INCREMENT_MS;\n await sleep(Math.min(intervalMs, remaining));\n continue;\n }\n throw new Error(`ClinePass device authorization failed${body.error ? `: ${body.error}` : ''}`);\n }\n throw new Error('ClinePass device authorization timed out');\n}\n\nexport async function runClinePassDeviceCodeFlow(\n onDeviceCode: (info: { url: string; userCode: string }) => void,\n opts?: { sleep?: (ms: number) => Promise<void>; now?: () => number },\n): Promise<ClinePassOAuthResult> {\n const device = await requestClinePassDeviceCode();\n onDeviceCode({\n url: device.verification_uri_complete ?? device.verification_uri,\n userCode: device.user_code,\n });\n return pollClinePassDeviceCode(device, opts);\n}\n\nexport async function refreshClinePassAccessToken(refreshToken: string): Promise<OAuthTokenResponse> {\n const response = await fetch(CLINE_PASS_REFRESH_URL, {\n method: 'POST',\n headers: jsonHeaders(),\n body: JSON.stringify({ refreshToken, grantType: 'refresh_token' }),\n });\n if (!response.ok) {\n const detail = await readError(response);\n throw new Error(`ClinePass token refresh failed (${response.status}): ${detail}`);\n }\n const body = await response.json() as { success?: unknown; data?: ClineAuthData; error?: unknown; message?: unknown };\n if (body.success !== true || !body.data) {\n const detail = typeof body.error === 'string' ? body.error : typeof body.message === 'string' ? body.message : 'unsuccessful response';\n throw new Error(`ClinePass token refresh failed: ${detail}`);\n }\n return toOAuthResult(body.data).tokens;\n}\n","// oauth/refresh.ts — refresh OAuth tokens before inference\n\nimport { refreshOpenAiAccessToken } from './openai.js';\nimport { refreshGithubCopilotToken } from './github.js';\nimport type { StoredOAuthCredential } from './types.js';\nimport { accessTokenIsExpiring, NATIVE_OAUTH_PROVIDER_IDS, oauthCredentialNeedsRefresh, tokensToStoredCredential } from './types.js';\nimport { refreshXaiAccessToken } from './xai.js';\nimport { refreshClaudeCodeToken } from './claude-code.js';\nimport { refreshAntigravityToken } from './antigravity-oauth.js';\nimport { refreshClinePassAccessToken } from './cline-pass.js';\n\nexport function oauthCredentialShouldRefresh(\n cred: StoredOAuthCredential,\n providerId: string,\n): boolean {\n if (oauthCredentialNeedsRefresh(cred)) return true;\n // All native OAuth providers use short-lived access tokens — check expiry proactively\n if ((NATIVE_OAUTH_PROVIDER_IDS as readonly string[]).includes(providerId) && accessTokenIsExpiring(cred.access)) return true;\n return false;\n}\n\nexport async function refreshStoredOAuthCredential(\n providerId: string,\n cred: StoredOAuthCredential,\n): Promise<StoredOAuthCredential> {\n if (!cred.refresh) {\n throw new Error(`${providerId}: OAuth refresh token missing — run relay-ai providers auth ${providerId}`);\n }\n\n let tokens;\n if (providerId === 'openai' || providerId === 'openai-oauth') {\n tokens = await refreshOpenAiAccessToken(cred.refresh);\n } else if (providerId === 'xai' || providerId === 'xai-oauth') {\n tokens = await refreshXaiAccessToken(cred.refresh);\n } else if (providerId === 'github-copilot') {\n // cred.refresh is the long-lived ghu_ token; re-exchange for a new Copilot session token\n tokens = await refreshGithubCopilotToken(cred.refresh);\n } else if (providerId === 'claude-code') {\n tokens = await refreshClaudeCodeToken(cred.refresh);\n } else if (providerId === 'antigravity') {\n tokens = await refreshAntigravityToken(cred.refresh);\n } else if (providerId === 'cline-pass') {\n tokens = await refreshClinePassAccessToken(cred.refresh);\n } else {\n throw new Error(`OAuth refresh not implemented for provider \"${providerId}\"`);\n }\n\n const accountId = providerId === 'cline-pass' && typeof tokens.providerData?.clineUserId === 'string'\n ? tokens.providerData.clineUserId\n : cred.accountId;\n return tokensToStoredCredential(tokens, cred.refresh, accountId, cred.providerData);\n}\n","// src/secrets-file.ts — file-backed credential store when OS keyring is unavailable.\n// Prefer keyring; this is the RELAY_AI_HOME fallback (Docker / headless).\n\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { getAppHome, getSecretsPath } from './paths.js';\n\nconst DIR_MODE = 0o700;\nconst FILE_MODE = 0o600;\n\nexport interface SecretsFile {\n version: 1;\n accounts: Record<string, string>;\n}\n\nfunction emptySecrets(): SecretsFile {\n return { version: 1, accounts: {} };\n}\n\nexport function readSecretsFile(env: NodeJS.ProcessEnv = process.env): SecretsFile {\n const path = getSecretsPath(env);\n if (!existsSync(path)) return emptySecrets();\n try {\n const raw = JSON.parse(readFileSync(path, 'utf8')) as Partial<SecretsFile>;\n if (raw?.version !== 1 || !raw.accounts || typeof raw.accounts !== 'object') {\n return emptySecrets();\n }\n const accounts: Record<string, string> = {};\n for (const [k, v] of Object.entries(raw.accounts)) {\n if (typeof v === 'string' && v.length > 0) accounts[k] = v;\n }\n return { version: 1, accounts };\n } catch {\n return emptySecrets();\n }\n}\n\nfunction writeSecretsFile(data: SecretsFile, env: NodeJS.ProcessEnv = process.env): void {\n const home = getAppHome(env);\n mkdirSync(home, { recursive: true, mode: DIR_MODE });\n try {\n chmodSync(home, DIR_MODE);\n } catch {\n // best-effort\n }\n const path = getSecretsPath(env);\n writeFileSync(path, `${JSON.stringify(data, null, 2)}\\n`, { encoding: 'utf8', mode: FILE_MODE });\n try {\n chmodSync(path, FILE_MODE);\n } catch {\n // best-effort (mode on create is ignored if the file already existed)\n }\n}\n\nexport function readFileAccount(account: string, env: NodeJS.ProcessEnv = process.env): string | null {\n const value = readSecretsFile(env).accounts[account];\n return value?.length ? value : null;\n}\n\nexport function writeFileAccount(\n account: string,\n value: string,\n env: NodeJS.ProcessEnv = process.env,\n): boolean {\n if (!account || !value) return false;\n try {\n const data = readSecretsFile(env);\n data.accounts[account] = value;\n writeSecretsFile(data, env);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function deleteFileAccount(account: string, env: NodeJS.ProcessEnv = process.env): boolean {\n try {\n const data = readSecretsFile(env);\n if (!(account in data.accounts)) return true;\n delete data.accounts[account];\n writeSecretsFile(data, env);\n return true;\n } catch {\n return false;\n }\n}\n","// src/env.ts\nimport { CONFLICTING_ENV_VARS, PARENT_SESSION_ENV_VARS } from './constants.js';\nimport { claudeCodeClientModelId, stripOneMContextSuffix } from './context-model-id.js';\nimport { resolveContextWindow } from './context-window.js';\nimport { oauthCredentialToKeychainJson } from './registry/opencode-auth.js';\nimport {\n parseStoredOAuthCredential,\n} from './oauth/types.js';\nimport { refreshStoredOAuthCredential, oauthCredentialShouldRefresh } from './oauth/refresh.js';\nimport { fetchCopilotAccount } from './oauth/github.js';\nimport {\n deleteFileAccount,\n readFileAccount,\n writeFileAccount,\n} from './secrets-file.js';\nimport type { ConflictInfo } from './types.js';\n\nexport function detectConflicts(): ConflictInfo[] {\n return CONFLICTING_ENV_VARS\n .filter(name => process.env[name] !== undefined)\n .map(name => ({ name, value: process.env[name]! }));\n}\n\nexport function resolveApiKey(): string | null {\n const key = process.env['OPENCODE_API_KEY'];\n // Treat empty string as missing — happens when .zshrc auto-load line runs\n // but the Keychain entry has been deleted (security command returns nothing)\n if (!key?.trim()) return null;\n // First line only — users sometimes paste notes below the key in shell profiles\n return key.trim().split(/\\r?\\n/)[0]?.trim() || null;\n}\n\n/** Restore first-party-like Claude Code behavior when routing through a proxy or gateway. */\nexport function applyClaudeCodeThirdPartyCompat(env: NodeJS.ProcessEnv): void {\n // Custom ANTHROPIC_BASE_URL disables MCP tool search by default, loading every\n // MCP tool (100+) on every turn. Requires defer_loading on tools — do not set\n // CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS when using the local translation proxy.\n env['ENABLE_TOOL_SEARCH'] = 'true';\n // Third-party routes may enable a shorter system prompt that drops conversational\n // guardrails while hooks/plugins still inject agentic instructions.\n env['CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT'] = '0';\n}\n\nexport function buildChildEnv(\n baseUrl: string,\n model: string,\n apiKey: string,\n proxyPort?: number,\n contextWindow?: number,\n enableGatewayDiscovery?: boolean,\n): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...process.env };\n for (const name of CONFLICTING_ENV_VARS) {\n delete env[name];\n }\n for (const name of PARENT_SESSION_ENV_VARS) {\n delete env[name];\n }\n env['ANTHROPIC_BASE_URL'] = proxyPort\n ? `http://127.0.0.1:${proxyPort}`\n : baseUrl;\n env['ANTHROPIC_API_KEY'] = apiKey;\n const bareModel = stripOneMContextSuffix(model);\n env['ANTHROPIC_MODEL'] = claudeCodeClientModelId(model, contextWindow);\n // Claude Code defaults to 200K for non-api.anthropic.com base URLs; override with\n // the launch model's real window. NOTE: in switch-menu mode this is fixed at launch\n // and does NOT update on live /model switch — Claude Code's gateway model discovery\n // only carries id + display_name (no context_window), so this env var is the only\n // lever and it reflects the model you started with.\n // Third-party routes also require a `[1m]` model-id suffix for 1M+ windows in the UI.\n env['CLAUDE_CODE_MAX_CONTEXT_TOKENS'] = String(resolveContextWindow(bareModel, contextWindow));\n if (enableGatewayDiscovery) {\n env['CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY'] = '1';\n }\n applyClaudeCodeThirdPartyCompat(env);\n return env;\n}\n\n/** Child env for Antigravity — only CLOUD_CODE_URL, no Anthropic proxy vars. */\nexport function buildAntigravityChildEnv(gatewayUrl: string): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...process.env };\n for (const name of CONFLICTING_ENV_VARS) {\n delete env[name];\n }\n env['CLOUD_CODE_URL'] = gatewayUrl;\n\n // Inject dummy API keys to bypass agy's slow keychain lookup (~500ms).\n // This prevents the race condition where loadCodeAssist fails and falls back\n // to the hardcoded, unsupported FLASH_LITE model.\n // The local Cloud Code Gateway ignores these keys, so any dummy value works.\n env['ANTIGRAVITY_API_KEY'] = 'relay-dummy-key';\n env['GEMINI_API_KEY'] = 'relay-dummy-key';\n env['GOOGLE_API_KEY'] = 'relay-dummy-key';\n env['GOOGLE_GEMINI_API_KEY'] = 'relay-dummy-key';\n\n return env;\n}\n\n/** Classify a keyring error into a human-readable reason (never throws). */\nexport function classifyKeyringError(err: unknown): string {\n const msg = err instanceof Error ? err.message : String(err);\n const lower = msg.toLowerCase();\n if (lower.includes('cannot find module') || lower.includes('module not found') || lower.includes('failed to load')) {\n return 'native keyring module not available on this system';\n }\n if (lower.includes('secret service') || lower.includes('dbus') || lower.includes('daemon')) {\n return 'Secret Service daemon is not running (start GNOME Keyring or KWallet)';\n }\n if (lower.includes('denied') || lower.includes('locked') || lower.includes('cancelled') || lower.includes('user refused')) {\n return 'keychain access was denied or the keychain is locked';\n }\n return `keyring error: ${msg}`;\n}\n\nconst KEYRING_SERVICE = 'relay-ai';\n/** @deprecated Use GLOBAL_OPENCODE_KEYRING_ACCOUNT — kept for migration reads */\nconst KEYRING_ACCOUNT = 'relay-ai';\n// Windows Credential Manager caps a single credential blob at 2560 bytes (CredWriteW).\n// keyring-rs encodes the password as UTF-16 (2 bytes/char) before that check, so the\n// usable limit is 2560 / 2 = 1280 chars — long OAuth tokens (e.g. OpenAI's JWTs) exceed\n// this, so secrets above the threshold are split across multiple keyring entries.\n// Harmless on macOS/Linux, which have no such limit.\nconst KEYRING_CHUNK_PREFIX = '__relay_chunked__:';\nconst KEYRING_CHUNK_SIZE = 1200;\nconst LEGACY_KEYRING_SERVICE = 'opencode-starter';\nconst LEGACY_KEYRING_ACCOUNT = 'opencode-starter';\n\nexport const GLOBAL_OPENCODE_KEYRING_ACCOUNT = 'global:opencode';\n\nexport function providerKeyringAccount(providerId: string): string {\n return `provider:${providerId}`;\n}\n\n/** Auth-ref used for a user-managed Relay override of the shared OpenCode catalog key. */\nexport function preferredRelayCredentialAuthRef(providerId: string, fallbackAuthRef: string): string {\n return providerId === 'go' || providerId === 'zen'\n ? `keyring:${providerKeyringAccount('opencode')}`\n : fallbackAuthRef;\n}\n\nexport function oauthProviderKeyringAccount(providerId: string): string {\n return `oauth:provider:${providerId}`;\n}\n\nfunction oauthProviderIdFromAccount(account: string): string | null {\n const prefix = 'oauth:provider:';\n return account.startsWith(prefix) ? account.slice(prefix.length) : null;\n}\n\nconst oauthRefreshInflight = new Map<string, Promise<string | null>>();\n\nexport type ParsedAuthRef =\n | { kind: 'keyring'; account: string }\n | { kind: 'env'; varName: string };\n\n/** Parse registry authRef strings like `keyring:provider:groq` or `env:OPENCODE_API_KEY`. */\nexport function parseAuthRef(authRef: string): ParsedAuthRef | null {\n if (authRef.startsWith('keyring:')) {\n const account = authRef.slice('keyring:'.length);\n return account ? { kind: 'keyring', account } : null;\n }\n if (authRef.startsWith('env:')) {\n const varName = authRef.slice('env:'.length);\n return varName ? { kind: 'env', varName } : null;\n }\n return null;\n}\n\n/** Env var name for relay-ai namespaced per-provider keys. */\nexport function relayAiKeyEnvVar(providerId: string): string {\n return `RELAY_AI_KEY_${providerId.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`;\n}\n\nfunction readEnvCredential(varName: string): string | null {\n const raw = process.env[varName];\n if (!raw?.trim()) return null;\n return raw.trim().split(/\\r?\\n/)[0]?.trim() || null;\n}\n\nasync function readOsKeyringAccount(account: string, diag?: (msg: string) => void): Promise<string | null> {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n const value = new Entry(KEYRING_SERVICE, account).getPassword() ?? null;\n if (!value?.startsWith(KEYRING_CHUNK_PREFIX)) return value;\n const chunkCount = Number(value.slice(KEYRING_CHUNK_PREFIX.length));\n let combined = '';\n for (let i = 0; i < chunkCount; i++) {\n combined += new Entry(KEYRING_SERVICE, `${account}::chunk::${i}`).getPassword() ?? '';\n }\n return combined;\n } catch (err) {\n diag?.(classifyKeyringError(err));\n return null;\n }\n}\n\nasync function writeOsKeyringAccount(\n account: string,\n key: string,\n diag?: (msg: string) => void,\n): Promise<boolean> {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n if (key.length <= KEYRING_CHUNK_SIZE) {\n new Entry(KEYRING_SERVICE, account).setPassword(key);\n return true;\n }\n const chunkCount = Math.ceil(key.length / KEYRING_CHUNK_SIZE);\n for (let i = 0; i < chunkCount; i++) {\n const chunk = key.slice(i * KEYRING_CHUNK_SIZE, (i + 1) * KEYRING_CHUNK_SIZE);\n new Entry(KEYRING_SERVICE, `${account}::chunk::${i}`).setPassword(chunk);\n }\n new Entry(KEYRING_SERVICE, account).setPassword(`${KEYRING_CHUNK_PREFIX}${chunkCount}`);\n return true;\n } catch (err) {\n diag?.(classifyKeyringError(err));\n return false;\n }\n}\n\nasync function deleteOsKeyringAccount(account: string, diag?: (msg: string) => void): Promise<boolean> {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n const value = new Entry(KEYRING_SERVICE, account).getPassword();\n if (value?.startsWith(KEYRING_CHUNK_PREFIX)) {\n const chunkCount = Number(value.slice(KEYRING_CHUNK_PREFIX.length));\n for (let i = 0; i < chunkCount; i++) {\n new Entry(KEYRING_SERVICE, `${account}::chunk::${i}`).deletePassword();\n }\n }\n new Entry(KEYRING_SERVICE, account).deletePassword();\n return true;\n } catch (err) {\n diag?.(classifyKeyringError(err));\n return false;\n }\n}\n\n/** OS keyring first, then ~/.relay-ai/secrets.json (Docker / headless). */\nasync function readKeyringAccount(account: string, diag?: (msg: string) => void): Promise<string | null> {\n const fromOs = await readOsKeyringAccount(account, diag);\n if (fromOs) return fromOs;\n return readFileAccount(account);\n}\n\n/** Prefer OS keyring; fall back to secrets.json when keyring is unavailable. */\nasync function writeKeyringAccount(\n account: string,\n key: string,\n diag?: (msg: string) => void,\n): Promise<boolean> {\n if (await writeOsKeyringAccount(account, key, diag)) {\n deleteFileAccount(account);\n return true;\n }\n if (writeFileAccount(account, key)) {\n diag?.('OS keyring unavailable — saved to secrets.json under RELAY_AI_HOME');\n return true;\n }\n return false;\n}\n\nasync function deleteKeyringAccount(account: string, diag?: (msg: string) => void): Promise<boolean> {\n const osOk = await deleteOsKeyringAccount(account, diag);\n const fileOk = deleteFileAccount(account);\n return osOk || fileOk;\n}\n\n/** Read Zen/Go API key: env → global:opencode → legacy relay-ai → opencode-starter. */\nexport async function readGlobalOpencodeCredential(diag?: (msg: string) => void): Promise<string | null> {\n const fromEnv = resolveApiKey();\n if (fromEnv) return fromEnv;\n\n const global = await readKeyringAccount(GLOBAL_OPENCODE_KEYRING_ACCOUNT, diag);\n if (global) return global;\n\n const current = await readKeyringAccount(KEYRING_ACCOUNT, diag);\n if (current) return current;\n\n try {\n const { Entry } = await import('@napi-rs/keyring');\n return new Entry(LEGACY_KEYRING_SERVICE, LEGACY_KEYRING_ACCOUNT).getPassword() ?? null;\n } catch (err) {\n diag?.(classifyKeyringError(err));\n return null;\n }\n}\n\n/** Read a stored credential without environment-variable precedence. */\nexport async function readStoredProviderCredential(\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<string | null> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring') return null;\n return readProviderSecret(parsed.account, diag);\n}\n\n/**\n * Migrate legacy keychain entries to `global:opencode`.\n * Protocol: read → write → verify → delete old (only after verify succeeds).\n */\nexport async function migrateGlobalOpencodeCredential(diag?: (msg: string) => void): Promise<boolean> {\n const existing = await readKeyringAccount(GLOBAL_OPENCODE_KEYRING_ACCOUNT, diag);\n if (existing) return true;\n\n const legacy =\n (await readKeyringAccount(KEYRING_ACCOUNT, diag)) ??\n (await (async () => {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n return new Entry(LEGACY_KEYRING_SERVICE, LEGACY_KEYRING_ACCOUNT).getPassword() ?? null;\n } catch (err) {\n diag?.(classifyKeyringError(err));\n return null;\n }\n })());\n\n if (!legacy) return false;\n\n const wrote = await writeKeyringAccount(GLOBAL_OPENCODE_KEYRING_ACCOUNT, legacy, diag);\n if (!wrote) return false;\n\n const verified = await readKeyringAccount(GLOBAL_OPENCODE_KEYRING_ACCOUNT, diag);\n if (verified !== legacy) {\n diag?.('credential migration verification failed — keeping legacy keychain entries');\n return false;\n }\n\n if (await readKeyringAccount(KEYRING_ACCOUNT, diag)) {\n await deleteKeyringAccount(KEYRING_ACCOUNT, diag);\n }\n try {\n const { Entry } = await import('@napi-rs/keyring');\n if (new Entry(LEGACY_KEYRING_SERVICE, LEGACY_KEYRING_ACCOUNT).getPassword()) {\n new Entry(LEGACY_KEYRING_SERVICE, LEGACY_KEYRING_ACCOUNT).deletePassword();\n }\n } catch {\n // best-effort legacy cleanup\n }\n return true;\n}\n\n/** Resolve a provider secret from authRef (env → keyring). */\nexport async function resolveProviderCredential(\n providerId: string,\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<string | null> {\n const parsed = parseAuthRef(authRef);\n if (!parsed) return null;\n\n // A key explicitly saved in Relay for the shared OpenCode catalog is a deliberate\n // override. It must win over OPENCODE_API_KEY, RELAY_AI_KEY_GO/ ZEN, and OpenCode's\n // own global key so a user can actually replace a stale credential.\n if (parsed.kind === 'keyring' && parsed.account === GLOBAL_OPENCODE_KEYRING_ACCOUNT) {\n const relayOverride = await readProviderSecret(providerKeyringAccount('opencode'), diag);\n if (relayOverride) return relayOverride;\n }\n\n const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));\n if (namespaced) return namespaced;\n\n if (parsed.kind === 'env') {\n return readEnvCredential(parsed.varName);\n }\n\n if (parsed.account === GLOBAL_OPENCODE_KEYRING_ACCOUNT) {\n return readGlobalOpencodeCredential(diag);\n }\n\n return readProviderSecret(parsed.account, diag);\n}\n\n/**\n * Force-refresh a stored OAuth credential after an upstream 401.\n * Normal resolution refreshes only when expiry metadata says it is needed;\n * providers can revoke a token early, so the retry path must bypass that gate.\n */\nexport async function forceRefreshProviderCredential(\n providerId: string,\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<string | null> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring') {\n return resolveProviderCredential(providerId, authRef, diag);\n }\n\n if (parsed.account === GLOBAL_OPENCODE_KEYRING_ACCOUNT) {\n const relayOverride = await readProviderSecret(providerKeyringAccount('opencode'), diag);\n if (relayOverride) return relayOverride;\n }\n\n const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));\n if (namespaced) return namespaced;\n\n const oauthProviderId = oauthProviderIdFromAccount(parsed.account);\n const raw = await readKeyringAccount(parsed.account, diag);\n if (!raw || !oauthProviderId) return decodeProviderSecret(raw);\n return refreshOAuthKeyringAccount(parsed.account, oauthProviderId, raw, diag, true);\n}\n\n/** Read OAuth metadata retained alongside the access token. */\nexport async function resolveProviderOAuthAccountId(\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<string | undefined> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring' || !oauthProviderIdFromAccount(parsed.account)) return undefined;\n const raw = await readKeyringAccount(parsed.account, diag);\n return parseStoredOAuthCredential(raw)?.accountId;\n}\n\nexport async function resolveProviderOAuthProviderData(\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<Record<string, unknown> | undefined> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring' || !oauthProviderIdFromAccount(parsed.account)) return undefined;\n const raw = await readKeyringAccount(parsed.account, diag);\n return parseStoredOAuthCredential(raw)?.providerData;\n}\n\n/** Backfill Copilot plan metadata for credentials saved before plan detection existed. */\nexport async function enrichGithubCopilotOAuthProviderData(\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<Record<string, unknown> | undefined> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring' || oauthProviderIdFromAccount(parsed.account) !== 'github-copilot') {\n return undefined;\n }\n const raw = await readKeyringAccount(parsed.account, diag);\n const credential = parseStoredOAuthCredential(raw);\n if (!credential?.refresh) return credential?.providerData;\n try {\n const summary = await fetchCopilotAccount(credential.refresh);\n const providerData = { ...credential.providerData, copilot: summary };\n await writeKeyringAccount(\n parsed.account,\n oauthCredentialToKeychainJson({ ...credential, providerData }),\n diag,\n );\n return providerData;\n } catch (err) {\n diag?.(`GitHub Copilot plan lookup unavailable — ${err instanceof Error ? err.message : String(err)}`);\n return credential.providerData;\n }\n}\n\nfunction decodeProviderSecret(raw: string | null): string | null {\n if (!raw) return null;\n const trimmed = raw.trim();\n if (!trimmed.startsWith('{')) return trimmed;\n const oauth = parseStoredOAuthCredential(trimmed);\n if (oauth) return oauth.access;\n try {\n const parsed = JSON.parse(trimmed) as { type?: string; access?: string; token?: string };\n if (parsed.type === 'oauth' && typeof parsed.access === 'string') return parsed.access;\n if (parsed.type === 'wellknown' && typeof parsed.token === 'string') return parsed.token;\n } catch {\n // fall through\n }\n return trimmed;\n}\n\nasync function refreshOAuthKeyringAccount(\n account: string,\n providerId: string,\n raw: string,\n diag?: (msg: string) => void,\n force = false,\n): Promise<string | null> {\n const existing = oauthRefreshInflight.get(account);\n if (existing) return existing;\n\n const work = (async (): Promise<string | null> => {\n const cred = parseStoredOAuthCredential(raw);\n if (!cred || (!force && !oauthCredentialShouldRefresh(cred, providerId))) {\n return decodeProviderSecret(raw);\n }\n try {\n const refreshed = await refreshStoredOAuthCredential(providerId, cred);\n const json = oauthCredentialToKeychainJson(refreshed);\n await writeKeyringAccount(account, json, diag);\n return refreshed.access;\n } catch (err) {\n diag?.(err instanceof Error ? err.message : String(err));\n if (cred.access && cred.expires > Date.now()) return cred.access;\n throw err;\n }\n })();\n\n oauthRefreshInflight.set(account, work);\n try {\n return await work;\n } finally {\n oauthRefreshInflight.delete(account);\n }\n}\n\nasync function readProviderSecret(account: string, diag?: (msg: string) => void): Promise<string | null> {\n const raw = await readKeyringAccount(account, diag);\n if (!raw) return null;\n\n const oauthProviderId = oauthProviderIdFromAccount(account);\n if (oauthProviderId && raw.trim().startsWith('{')) {\n return refreshOAuthKeyringAccount(account, oauthProviderId, raw, diag);\n }\n return decodeProviderSecret(raw);\n}\n\nexport async function saveProviderCredential(\n authRef: string,\n key: string,\n diag?: (msg: string) => void,\n): Promise<boolean> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring') return false;\n return writeKeyringAccount(parsed.account, key, diag);\n}\n\n/** Delete a provider secret from keyring (no-op for env: refs). */\nexport async function deleteProviderCredential(\n authRef: string,\n diag?: (msg: string) => void,\n): Promise<boolean> {\n const parsed = parseAuthRef(authRef);\n if (!parsed || parsed.kind !== 'keyring') return false;\n return deleteKeyringAccount(parsed.account, diag);\n}\n\nexport async function readFromCredentialStore(diag?: (msg: string) => void): Promise<string | null> {\n return readGlobalOpencodeCredential(diag);\n}\n\nexport async function saveToCredentialStore(key: string, diag?: (msg: string) => void): Promise<boolean> {\n const wrote = await writeKeyringAccount(GLOBAL_OPENCODE_KEYRING_ACCOUNT, key, diag);\n if (wrote) {\n await deleteKeyringAccount(KEYRING_ACCOUNT, diag);\n }\n return wrote;\n}\n\nexport async function isSecretServiceAvailable(): Promise<boolean> {\n try {\n const { Entry } = await import('@napi-rs/keyring');\n new Entry(`${KEYRING_SERVICE}-probe`, 'probe').getPassword();\n return true;\n } catch {\n return false;\n }\n}\n","{\n \"schema_version\": \"1\",\n \"entries\": [\n {\n \"provider\": \"google\",\n \"modelId\": \"antigravity-preview-05-2026\",\n \"category\": \"managed_agent\",\n \"reason\": \"Interactions API only; coding agents send multiturn chat via @ai-sdk/google streamGenerateContent\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"manual UAT 2026-06-10\"\n ],\n \"verifiedAt\": \"2026-06-10\"\n },\n {\n \"provider\": \"*\",\n \"modelId\": \"z-ai/glm4.7\",\n \"category\": \"gated_access\",\n \"reason\": \"NVIDIA NIM requires separate access approval (HTTP 410)\",\n \"sources\": [\n \"manual probe 2026-06\"\n ],\n \"verifiedAt\": \"2026-06-10\"\n },\n {\n \"provider\": \"*\",\n \"modelId\": \"qwen3.6-plus-free\",\n \"category\": \"stale_promotion\",\n \"reason\": \"Free promotion ended; API returns 401\",\n \"sources\": [\n \"OpenCode Zen catalog\"\n ],\n \"verifiedAt\": \"2026-06-10\"\n },\n {\n \"provider\": \"*\",\n \"modelId\": \"mimo-v2-pro\",\n \"category\": \"deprecated\",\n \"reason\": \"Deprecated; API returns 400 — use mimo-v2.5-pro\",\n \"sources\": [\n \"OpenCode Zen catalog\"\n ],\n \"verifiedAt\": \"2026-06-10\"\n },\n {\n \"provider\": \"*\",\n \"modelId\": \"mimo-v2-omni\",\n \"category\": \"deprecated\",\n \"reason\": \"Deprecated; API returns 400 — use mimo-v2.5\",\n \"sources\": [\n \"OpenCode Zen catalog\"\n ],\n \"verifiedAt\": \"2026-06-10\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"aqa\",\n \"category\": \"managed_agent\",\n \"reason\": \"Attributed QA model — not for coding agents\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"deep-research-max-preview-04-2026\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"deep-research-preview-04-2026\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"deep-research-pro-preview-12-2025\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-computer-use-preview-10-2025\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-flash-image\",\n \"category\": \"image_generation\",\n \"reason\": \"Image-output model — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-flash-native-audio-latest\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-flash-native-audio-preview-09-2025\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-flash-native-audio-preview-12-2025\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-flash-preview-tts\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-2.5-pro-preview-tts\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3-pro-preview\",\n \"category\": \"deprecated\",\n \"reason\": \"Retired preview; API returns 404 — use gemini-3.1-pro-preview or newer\",\n \"sources\": [\n \"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-preview\",\n \"manual UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3-pro-image\",\n \"category\": \"image_generation\",\n \"reason\": \"Image-output model — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3-pro-image-preview\",\n \"category\": \"image_generation\",\n \"reason\": \"Image-output model — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3.1-flash-image\",\n \"category\": \"image_generation\",\n \"reason\": \"Image-output model — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3.1-flash-image-preview\",\n \"category\": \"image_generation\",\n \"reason\": \"Image-output model — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3.1-flash-live-preview\",\n \"category\": \"managed_agent\",\n \"reason\": \"Live/session API — not for Codex multiturn chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3.1-flash-tts-preview\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-3.5-live-translate-preview\",\n \"category\": \"managed_agent\",\n \"reason\": \"Live/session API — not for Codex multiturn chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-embedding-001\",\n \"category\": \"embedding\",\n \"reason\": \"Embedding model — not for chat or tools\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-embedding-2\",\n \"category\": \"embedding\",\n \"reason\": \"Embedding model — not for chat or tools\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-embedding-2-preview\",\n \"category\": \"embedding\",\n \"reason\": \"Embedding model — not for chat or tools\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-robotics-er-1.5-preview\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"gemini-robotics-er-1.6-preview\",\n \"category\": \"managed_agent\",\n \"reason\": \"Specialized agent API — not standard coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"imagen-4.0-fast-generate-001\",\n \"category\": \"image_generation\",\n \"reason\": \"Image generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"imagen-4.0-generate-001\",\n \"category\": \"image_generation\",\n \"reason\": \"Image generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"imagen-4.0-ultra-generate-001\",\n \"category\": \"image_generation\",\n \"reason\": \"Image generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"lyria-3-clip-preview\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"lyria-3-pro-preview\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"lyria-realtime-exp\",\n \"category\": \"audio_only\",\n \"reason\": \"Audio/music output — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"nano-banana-pro-preview\",\n \"category\": \"image_generation\",\n \"reason\": \"Image generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-2.0-generate-001\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-3.0-fast-generate-001\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-3.0-generate-001\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-3.1-fast-generate-preview\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-3.1-generate-preview\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n },\n {\n \"provider\": \"google\",\n \"modelId\": \"veo-3.1-lite-generate-preview\",\n \"category\": \"video_generation\",\n \"reason\": \"Video generation — not for coding chat\",\n \"sources\": [\n \"https://ai.google.dev/gemini-api/docs/models\",\n \"Google GET /v1/models vs models.dev gap — UAT 2026-06-11\"\n ],\n \"verifiedAt\": \"2026-06-11\"\n }\n ]\n}\n","// src/registry/models-dev.ts — models.dev capability cache (bundled + optional user refresh)\n\nimport {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport bundledCache from '../data/models-dev-cache.json';\nimport { getAppHome } from '../paths.js';\nimport { normalizeModelIdCandidates } from './pricing.js';\n\nexport const MODELS_DEV_API_URL = 'https://models.dev/api.json';\nconst FETCH_TIMEOUT_MS = 15_000;\nconst FILE_MODE = 0o600;\n\nexport interface ModelsDevModalities {\n input?: string[];\n output?: string[];\n}\n\nexport interface ModelsDevModel {\n id?: string;\n name?: string;\n tool_call?: boolean;\n chat?: boolean;\n interactions?: boolean;\n reasoning?: boolean;\n interleaved?: { field?: string };\n modalities?: ModelsDevModalities;\n}\n\nexport interface ModelsDevProvider {\n id?: string;\n name?: string;\n models?: Record<string, ModelsDevModel>;\n}\n\nexport type ModelsDevCacheFile = Record<string, ModelsDevProvider>;\n\nexport interface ModelsDevCacheMeta {\n schema_version?: string;\n fetched_at?: string;\n source?: string;\n provider_count?: number;\n}\n\nconst META_KEY = '_relay_meta';\n\nlet memoryCache: ModelsDevCacheFile | null = null;\nlet memoryCachePath: string | null = null;\nlet memoryCacheMtime = 0;\n\n/** Registry / OpenCode provider id → models.dev top-level key */\nexport const REGISTRY_TO_MODELS_DEV: Record<string, string> = {\n google: 'google',\n openai: 'openai',\n groq: 'groq',\n mistral: 'mistral',\n togetherai: 'together',\n cerebras: 'cerebras',\n deepinfra: 'deepinfra',\n xai: 'xai',\n 'xai-oauth': 'xai',\n perplexity: 'perplexity',\n cohere: 'cohere',\n alibaba: 'alibaba',\n 'qwen-cloud-token-plan': 'alibaba-token-plan',\n 'qwen-cloud-payg': 'alibaba',\n openrouter: 'openrouter',\n anthropic: 'anthropic',\n nvidia: 'nvidia',\n venice: 'openrouter',\n};\n\nexport function readModelsDevCacheMeta(\n cache: ModelsDevCacheFile,\n): ModelsDevCacheMeta | null {\n const raw = cache[META_KEY] as unknown as ModelsDevCacheMeta | undefined;\n if (!raw || typeof raw !== 'object') return null;\n return raw;\n}\n\nexport function stripModelsDevCacheMeta(cache: ModelsDevCacheFile): ModelsDevCacheFile {\n const { [META_KEY]: _meta, ...providers } = cache;\n return providers;\n}\n\nexport function loadBundledModelsDevCache(): ModelsDevCacheFile {\n return bundledCache as unknown as ModelsDevCacheFile;\n}\n\nexport function invalidateModelsDevCache(): void {\n memoryCache = null;\n memoryCachePath = null;\n memoryCacheMtime = 0;\n}\n\nfunction readModelsDevFile(path: string): ModelsDevCacheFile | null {\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as ModelsDevCacheFile;\n } catch {\n return null;\n }\n}\n\nfunction mkdirSafe(dir: string): void {\n try {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n } catch {\n // ignore\n }\n}\n\nfunction attachModelsDevCacheMeta(\n providers: Record<string, ModelsDevProvider>,\n): ModelsDevCacheFile {\n const providerCount = Object.keys(providers).filter(k => !k.startsWith('_')).length;\n return {\n [META_KEY]: {\n schema_version: '1',\n fetched_at: new Date().toISOString(),\n source: MODELS_DEV_API_URL,\n provider_count: providerCount,\n },\n ...providers,\n } as ModelsDevCacheFile;\n}\n\nfunction writeModelsDevCache(path: string, data: ModelsDevCacheFile): void {\n mkdirSafe(dirname(path));\n writeFileSync(path, `${JSON.stringify(data)}\\n`, { mode: FILE_MODE });\n try {\n chmodSync(path, FILE_MODE);\n } catch {\n // best-effort\n }\n invalidateModelsDevCache();\n}\n\nexport function getUserModelsDevCachePath(): string {\n return join(getAppHome(), 'models-dev-cache.json');\n}\n\nfunction rememberModelsDevCache(path: string, data: ModelsDevCacheFile): ModelsDevCacheFile {\n memoryCache = data;\n memoryCachePath = path;\n try {\n memoryCacheMtime = statSync(path).mtimeMs;\n } catch {\n memoryCacheMtime = 0;\n }\n return data;\n}\n\nexport function loadModelsDevCache(): ModelsDevCacheFile {\n const userPath = getUserModelsDevCachePath();\n if (existsSync(userPath)) {\n try {\n const mtime = statSync(userPath).mtimeMs;\n if (memoryCache && memoryCachePath === userPath && memoryCacheMtime === mtime) {\n return memoryCache;\n }\n const data = readModelsDevFile(userPath);\n if (data) return rememberModelsDevCache(userPath, data);\n } catch {\n // fall through to bundled\n }\n }\n\n if (memoryCache && memoryCachePath === 'bundled') return memoryCache;\n return rememberModelsDevCache('bundled', loadBundledModelsDevCache());\n}\n\nexport async function fetchModelsDevCache(): Promise<ModelsDevCacheFile | null> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const response = await fetch(MODELS_DEV_API_URL, {\n signal: controller.signal,\n headers: { Accept: 'application/json' },\n });\n if (!response.ok) return null;\n const data = (await response.json()) as Record<string, ModelsDevProvider>;\n if (!data || typeof data !== 'object') return null;\n const withMeta = attachModelsDevCacheMeta(data);\n writeModelsDevCache(getUserModelsDevCachePath(), withMeta);\n return withMeta;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport function resolveModelsDevSlug(providerId: string): string {\n return REGISTRY_TO_MODELS_DEV[providerId] ?? providerId;\n}\n\n/** Fetch latest models.dev catalog in the background; falls back to bundled snapshot offline. */\nexport function refreshModelsDevCacheAsync(onComplete?: (updated: boolean) => void): void {\n void (async () => {\n const updated = (await fetchModelsDevCache()) !== null;\n onComplete?.(updated);\n })();\n}\n\nexport function findModelsDevModel(\n providerId: string,\n modelId: string,\n cache: ModelsDevCacheFile = loadModelsDevCache(),\n): ModelsDevModel | null {\n const slug = resolveModelsDevSlug(providerId);\n const models = stripModelsDevCacheMeta(cache)[slug]?.models;\n if (!models) return null;\n\n for (const candidate of normalizeModelIdCandidates(modelId)) {\n const entry = models[candidate];\n if (entry) return entry;\n }\n return null;\n}\n\n/** Conservative auto-hide rules — only when models.dev row exists and fields are explicit. */\nexport function shouldHideByModelsDevCapabilities(entry: ModelsDevModel): boolean {\n const output = entry.modalities?.output;\n if (output && output.length > 0 && !output.includes('text')) return true;\n if (entry.tool_call === false) return true;\n if (entry.interactions === true && entry.chat === false) return true;\n return false;\n}\n","// src/registry/pricing.ts — async pricing enrich from ai-model-pricing.com + bundled fallback\n//\n// Schema mapping:\n// ai-model-pricing.com entries use dollars per 1M tokens (input_per_1m_tokens, output_per_1m_tokens).\n// CachedModel.cost stores the same units as OpenCode models.json ({ input, output } per 1M tokens).\n// Multi-tier rows: prefer tier=standard + modality=text for the provider platform; else first text row.\n//\n// Model ID normalization (lookup order):\n// 1. Exact id / upstreamModelId\n// 2. Platform alias from pricing entry (aliases[platform])\n// 3. Lowercase id, strip openrouter/ and provider/ prefixes\n\nimport {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport bundledPricing from '../data/pricing-cache.json';\nimport { getAppHome } from '../paths.js';\nimport type { CachedModel } from './types.js';\nimport { loadRegistry, saveRegistry } from './io.js';\nimport { classifyFreeStatus, isFreeStatus } from '../free-models.js';\n\nexport const PRICING_API_URL = 'https://ai-model-pricing.com/api/v1/pricing.json';\nconst FETCH_TIMEOUT_MS = 15_000;\nconst FILE_MODE = 0o600;\n\nexport interface PricingTierRow {\n platform?: string;\n tier?: string;\n modality?: string;\n input_per_1m_tokens?: number;\n output_per_1m_tokens?: number;\n cached_input_per_1m_tokens?: number;\n}\n\nexport interface PricingModelEntry {\n provider?: string;\n model_id?: string;\n aliases?: Record<string, string>;\n pricing?: PricingTierRow[];\n}\n\nexport interface PricingCacheFile {\n schema_version?: string;\n generated_at?: string;\n models?: PricingModelEntry[];\n}\n\n/** Registry template id → ai-model-pricing platform slug */\nexport const TEMPLATE_TO_PRICING_PLATFORM: Record<string, string> = {\n groq: 'groq',\n mistral: 'mistral',\n togetherai: 'together',\n cerebras: 'cerebras',\n deepinfra: 'deepinfra',\n xai: 'xai',\n 'xai-oauth': 'xai',\n perplexity: 'perplexity',\n cohere: 'cohere',\n openai: 'openai',\n google: 'google_ai_studio',\n alibaba: 'alibaba',\n 'qwen-cloud-payg': 'alibaba',\n openrouter: 'openrouter',\n anthropic: 'anthropic',\n nvidia: 'nvidia',\n venice: 'openrouter',\n};\n\nconst PRICING_OPT_OUT_TEMPLATE_IDS = new Set([\n 'qwen-cloud-token-plan',\n]);\n\nexport function loadBundledPricingCache(): PricingCacheFile {\n return bundledPricing as unknown as PricingCacheFile;\n}\n\nfunction readPricingFile(path: string): PricingCacheFile | null {\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as PricingCacheFile;\n } catch {\n return null;\n }\n}\n\nfunction writePricingCache(path: string, data: PricingCacheFile): void {\n mkdirSafe(dirname(path));\n writeFileSync(path, `${JSON.stringify(data, null, 2)}\\n`, { mode: FILE_MODE });\n try {\n chmodSync(path, FILE_MODE);\n } catch {\n // best-effort\n }\n}\n\nfunction mkdirSafe(dir: string): void {\n try {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n } catch {\n // ignore\n }\n}\n\nexport function getUserPricingCachePath(): string {\n return join(getAppHome(), 'pricing-cache.json');\n}\n\nexport function loadPricingCache(): PricingCacheFile {\n return readPricingFile(getUserPricingCachePath()) ?? loadBundledPricingCache();\n}\n\nexport async function fetchPricingCache(): Promise<PricingCacheFile | null> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const response = await fetch(PRICING_API_URL, {\n signal: controller.signal,\n headers: { Accept: 'application/json' },\n });\n if (!response.ok) return null;\n const data = (await response.json()) as PricingCacheFile;\n if (!Array.isArray(data.models)) return null;\n writePricingCache(getUserPricingCachePath(), data);\n return data;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\nfunction pickPricingRow(rows: PricingTierRow[], platform?: string): PricingTierRow | null {\n const textRows = rows.filter(r => !r.modality || r.modality === 'text');\n const pool = textRows.length > 0 ? textRows : rows;\n if (platform) {\n const platformStandard = pool.find(r => r.platform === platform && r.tier === 'standard');\n if (platformStandard) return platformStandard;\n const platformAny = pool.find(r => r.platform === platform);\n if (platformAny) return platformAny;\n }\n const standard = pool.find(r => r.tier === 'standard');\n if (standard) return standard;\n return pool[0] ?? null;\n}\n\nfunction rowToCost(row: PricingTierRow): CachedModel['cost'] | undefined {\n if (row.input_per_1m_tokens === undefined && row.output_per_1m_tokens === undefined) return undefined;\n return {\n input: row.input_per_1m_tokens ?? 0,\n output: row.output_per_1m_tokens ?? 0,\n };\n}\n\nexport function normalizeModelIdCandidates(id: string): string[] {\n const trimmed = id.trim();\n const lower = trimmed.toLowerCase();\n const candidates = new Set<string>([trimmed, lower]);\n for (const prefix of ['openrouter/', 'moonshotai/', 'anthropic/', 'openai/']) {\n if (lower.startsWith(prefix)) {\n candidates.add(lower.slice(prefix.length));\n candidates.add(trimmed.slice(prefix.length));\n }\n }\n const slash = lower.indexOf('/');\n if (slash > 0) {\n candidates.add(lower.slice(slash + 1));\n }\n return [...candidates];\n}\n\nexport interface PricingIndex {\n byId: Map<string, PricingModelEntry>;\n}\n\nexport function buildPricingIndex(cache: PricingCacheFile): PricingIndex {\n const byId = new Map<string, PricingModelEntry>();\n for (const entry of cache.models ?? []) {\n if (!entry.model_id) continue;\n for (const candidate of normalizeModelIdCandidates(entry.model_id)) {\n byId.set(candidate, entry);\n }\n if (entry.aliases) {\n for (const alias of Object.values(entry.aliases)) {\n for (const candidate of normalizeModelIdCandidates(alias)) {\n byId.set(candidate, entry);\n }\n }\n }\n }\n return { byId };\n}\n\nexport function lookupModelCost(\n index: PricingIndex,\n modelId: string,\n platform?: string,\n): CachedModel['cost'] | undefined {\n for (const candidate of normalizeModelIdCandidates(modelId)) {\n const entry = index.byId.get(candidate);\n if (!entry?.pricing?.length) continue;\n const row = pickPricingRow(entry.pricing, platform);\n const cost = row ? rowToCost(row) : undefined;\n if (cost) return cost;\n }\n return undefined;\n}\n\nexport function enrichModelsWithPricing(\n models: CachedModel[],\n index: PricingIndex,\n platform?: string,\n): CachedModel[] {\n return models.map(model => {\n const cost =\n lookupModelCost(index, model.id, platform) ??\n lookupModelCost(index, model.upstreamModelId, platform);\n if (!cost) return model;\n const freeStatus = classifyFreeStatus({\n model: { ...model, cost },\n // Keep provider-granted free access (e.g. Cloudflare's daily allowance) when\n // real pricing resolves later.\n freeAccess: model.freeStatus === 'free_provider',\n });\n return { ...model, cost, isFree: isFreeStatus(freeStatus), freeStatus };\n });\n}\n\n/**\n * Apply cached pricing for a specific registry provider. Token Plan credits are\n * not PAYG prices, so remove any cached pricing metadata rather than allowing\n * the generic fallback to select an unrelated standard row.\n */\nexport function enrichModelsForProviderPricing(\n models: CachedModel[],\n index: PricingIndex,\n templateId: string,\n providerId: string,\n): CachedModel[] {\n if (PRICING_OPT_OUT_TEMPLATE_IDS.has(templateId) || PRICING_OPT_OUT_TEMPLATE_IDS.has(providerId)) {\n return models.map(({ cost: _cost, isFree: _isFree, freeStatus: _freeStatus, ...model }) => model);\n }\n return enrichModelsWithPricing(\n models,\n index,\n pricingPlatformForProvider(templateId, providerId),\n );\n}\n\nexport function applyPricingToRegistryProviders(\n registry: import('./types.js').ProviderRegistry,\n cache: PricingCacheFile,\n): boolean {\n const index = buildPricingIndex(cache);\n let changed = false;\n for (const provider of registry.providers) {\n if (!provider.modelsCache?.models.length) continue;\n const enriched = enrichModelsForProviderPricing(\n provider.modelsCache.models,\n index,\n provider.templateId,\n provider.id,\n );\n if (JSON.stringify(enriched) !== JSON.stringify(provider.modelsCache.models)) {\n provider.modelsCache = { ...provider.modelsCache, models: enriched };\n changed = true;\n }\n }\n if (changed) {\n registry.pricingCacheAt = cache.generated_at ?? new Date().toISOString();\n }\n return changed;\n}\n\n/** Apply bundled or on-disk pricing cache synchronously (non-blocking enrich baseline). */\nexport function applyCachedPricing(): boolean {\n const registry = loadRegistry();\n const cache = loadPricingCache();\n const changed = applyPricingToRegistryProviders(registry, cache);\n if (changed) saveRegistry(registry);\n return changed;\n}\n\n/** Fetch latest pricing in the background; updates registry when complete. */\nexport function enrichPricingAsync(onComplete?: (updated: boolean) => void): void {\n void (async () => {\n const fetched = await fetchPricingCache();\n const cache = fetched ?? loadPricingCache();\n const registry = loadRegistry();\n const changed = applyPricingToRegistryProviders(registry, cache);\n if (changed) saveRegistry(registry);\n onComplete?.(changed);\n })();\n}\n\nexport function pricingPlatformForProvider(templateId: string, providerId: string): string | undefined {\n return TEMPLATE_TO_PRICING_PLATFORM[templateId] ?? TEMPLATE_TO_PRICING_PLATFORM[providerId];\n}\n","// src/model-compatibility.ts — curated blacklist + models.dev capability filtering\n\nimport blacklistData from './data/model-incompatible.json';\nimport {\n findModelsDevModel,\n loadModelsDevCache,\n shouldHideByModelsDevCapabilities,\n} from './registry/models-dev.js';\n\nexport type CompatibilityAgent = 'claude' | 'codex' | 'codex-app' | 'server' | 'gemini' | 'antigravity';\n\nexport interface CompatibilityContext {\n providerId: string;\n modelId: string;\n agent: CompatibilityAgent;\n}\n\nexport interface IncompatibleModelEntry {\n provider: string;\n modelId: string;\n category: string;\n reason: string;\n agents?: CompatibilityAgent[];\n sources?: string[];\n verifiedAt?: string;\n}\n\ninterface IncompatibleModelFile {\n schema_version?: string;\n entries?: IncompatibleModelEntry[];\n}\n\nconst BLACKLIST_ENTRIES = (blacklistData as IncompatibleModelFile).entries ?? [];\n\n// Cloud Code's fetchAvailableModels blob also contains tab-complete, chat, and\n// image-generation slots. Those are not agent models — drop them. Everything\n// else from the live catalog is shown; there is no Relay allowlist.\nconst ANTIGRAVITY_HELPER_SLOT = /^(tab_|chat_|models\\/)|image/i;\n\nexport function isAntigravityCloudCodeHelperSlot(modelId: string): boolean {\n return ANTIGRAVITY_HELPER_SLOT.test(modelId);\n}\n\nfunction matchesAgent(entryAgents: CompatibilityAgent[] | undefined, agent: CompatibilityAgent): boolean {\n if (!entryAgents || entryAgents.length === 0) return true;\n return entryAgents.includes(agent);\n}\n\nfunction matchesProvider(entryProvider: string, providerId: string): boolean {\n return entryProvider === providerId || entryProvider === '*';\n}\n\nexport function findBlacklistEntry(ctx: CompatibilityContext): IncompatibleModelEntry | null {\n for (const entry of BLACKLIST_ENTRIES) {\n if (entry.modelId !== ctx.modelId) continue;\n if (!matchesProvider(entry.provider, ctx.providerId)) continue;\n if (!matchesAgent(entry.agents, ctx.agent)) continue;\n return entry;\n }\n return null;\n}\n\nexport function hideReason(ctx: CompatibilityContext): string | null {\n if (ctx.providerId === 'antigravity' && isAntigravityCloudCodeHelperSlot(ctx.modelId)) {\n return '[antigravity-oauth] Cloud Code helper/internal slot';\n }\n\n const blacklist = findBlacklistEntry(ctx);\n if (blacklist) return `[blacklist:${blacklist.category}] ${blacklist.reason}`;\n\n const modelsDev = findModelsDevModel(ctx.providerId, ctx.modelId, loadModelsDevCache());\n if (modelsDev && shouldHideByModelsDevCapabilities(modelsDev)) {\n return '[models.dev] incompatible capabilities for coding agents';\n }\n\n return null;\n}\n\nexport function shouldHideModel(ctx: CompatibilityContext): boolean {\n return hideReason(ctx) !== null;\n}\n","// import-opencode.ts — merge API-key and OAuth providers for OpenCode import\n\nimport type { LocalProvider } from '../types.js';\nimport { normalizeProviders, type RawProvider } from '../providers.js';\nimport {\n isOpencodeOAuth,\n type OpencodeAuthEntry,\n type OpencodeOAuthCredential,\n} from './opencode-auth.js';\nimport { isLikelyPlaceholderKey } from './refresh-credentials.js';\n\nexport interface OAuthImportContext {\n oauthByProviderId: Map<string, OpencodeOAuthCredential>;\n}\n\nexport function oauthAuthRef(providerId: string): string {\n return `keyring:oauth:provider:${providerId}`;\n}\n\n/** Maps a canonical OAuth provider ID to its registry slot (openai → openai-oauth; others unchanged). */\nexport function toOAuthRegistryId(id: string): string {\n if (id === 'openai') return 'openai-oauth';\n if (id === 'xai') return 'xai-oauth';\n return id;\n}\n\nfunction normalizeImportProviderIdentity(provider: LocalProvider): LocalProvider {\n if (provider.id === 'opencode') {\n return { ...provider, id: 'zen', name: 'OpenCode Zen' };\n }\n if (provider.id === 'opencode-go') {\n return { ...provider, id: 'go', name: 'OpenCode Go' };\n }\n return provider;\n}\n\n/** Merge API-key providers from serve with OAuth providers backed by auth.json. */\nexport function buildImportProviderList(\n raw: RawProvider[],\n authEntries: Record<string, OpencodeAuthEntry>,\n): { providers: LocalProvider[]; oauth: OAuthImportContext } {\n const oauthByProviderId = new Map<string, OpencodeOAuthCredential>();\n const covered = new Set<string>();\n const merged: LocalProvider[] = [];\n\n for (const provider of normalizeProviders(raw)) {\n const normalized = normalizeImportProviderIdentity(provider);\n if (covered.has(normalized.id)) continue;\n merged.push(normalized);\n covered.add(normalized.id);\n }\n\n for (const provider of raw) {\n if (provider.id === 'opencode' || provider.id === 'opencode-go') continue;\n if (covered.has(provider.id)) continue;\n\n const authEntry = authEntries[provider.id];\n if (!isOpencodeOAuth(authEntry)) continue;\n\n const oauthProviders = normalizeProviders(\n [{ ...provider, key: authEntry.access }],\n { includeOAuthPlaceholders: true },\n );\n if (oauthProviders.length === 0) continue;\n\n const registryId = toOAuthRegistryId(provider.id);\n oauthByProviderId.set(registryId, authEntry);\n merged.push({ ...oauthProviders[0]!, id: registryId, apiKey: '' });\n covered.add(registryId);\n covered.add(provider.id);\n }\n\n return { providers: merged, oauth: { oauthByProviderId } };\n}\n\nexport function isOAuthImportProvider(providerId: string, oauth: OAuthImportContext): boolean {\n return oauth.oauthByProviderId.has(providerId);\n}\n\n/** OpenCode provider ids that authenticate via OAuth (not API keys). */\nexport const OPENCODE_OAUTH_PROVIDER_IDS = new Set([\n 'xai',\n 'openai',\n 'github',\n 'gitlab',\n 'kimi',\n 'moonshot',\n]);\n\n/** OpenCode stubs that use gcloud/AWS/Azure — never API key or OAuth import. */\nexport const OPENCODE_MANUAL_ONLY_IDS = new Set([\n 'google-vertex',\n 'vertex',\n 'bedrock',\n 'azure',\n]);\n\nexport type CredentialGapReason = 'oauth-no-token' | 'no-api-key' | 'manual-only';\n\nexport function classifyOpencodeCredentialGap(providerId: string): CredentialGapReason {\n if (OPENCODE_MANUAL_ONLY_IDS.has(providerId)) return 'manual-only';\n if (OPENCODE_OAUTH_PROVIDER_IDS.has(providerId)) return 'oauth-no-token';\n return 'no-api-key';\n}\n\n/**\n * Providers in OpenCode /config/providers with models but no importable credential.\n * Not all gaps are OAuth — Anthropic/Google often mean \"no API key in OpenCode\".\n */\nexport function listCredentialSkippedProviders(\n raw: RawProvider[],\n authEntries: Record<string, OpencodeAuthEntry>,\n importedIds: Set<string>,\n alreadyReportedIds: Set<string> = new Set(),\n registryProviderIds: Set<string> = new Set(),\n): Array<{ id: string; name: string; reason: CredentialGapReason }> {\n const skipped: Array<{ id: string; name: string; reason: CredentialGapReason }> = [];\n for (const provider of raw) {\n if (provider.id === 'opencode' || provider.id === 'opencode-go') continue;\n if (importedIds.has(provider.id)) continue;\n if (alreadyReportedIds.has(provider.id)) continue;\n const hasApiKey = !!provider.key?.trim() && !isLikelyPlaceholderKey(provider.key);\n if (hasApiKey) continue;\n if (isOpencodeOAuth(authEntries[provider.id])) continue;\n if (!provider.models || Object.keys(provider.models).length === 0) continue;\n\n const reason = classifyOpencodeCredentialGap(provider.id);\n // Only surface actionable gaps: OAuth sign-in needed, or a provider you already\n // use in relay-ai that OpenCode still has without credentials. Skip random OpenCode\n // catalog stubs (e.g. Google with models but no key) the user never configured.\n if (reason !== 'oauth-no-token' && !registryProviderIds.has(provider.id)) continue;\n\n skipped.push({ id: provider.id, name: provider.name, reason });\n }\n return skipped;\n}\n\n/** @deprecated Use listCredentialSkippedProviders */\nexport const listOAuthSkippedProviders = listCredentialSkippedProviders;\n","import { forceRefreshProviderCredential } from './env.js';\nimport { oauthAuthRef } from './registry/import-build.js';\n\n/**\n * Resolve the current raw OAuth access token for a registry provider.\n * `resolveProviderCredential` also performs the existing proactive refresh\n * and persists the refreshed credential when the stored token is expiring.\n */\nexport function providerRefreshToken(\n providerId: string | undefined,\n authType: 'api' | 'oauth' | 'none' | undefined,\n authRef?: string,\n): (() => Promise<string | null>) | undefined {\n if (authType !== 'oauth' || !providerId) return undefined;\n return () => forceRefreshProviderCredential(providerId, authRef ?? oauthAuthRef(providerId));\n}\n","// src/core/antigravity-model.ts — native Google LanguageModel over Cloud Code Assist.\n//\n// Core cannot start a local proxy. Cloud Code models are not OpenAI-compatible:\n// wrap @ai-sdk/google generateContent requests in the Cloud Code envelope and\n// unwrap `{response: ...}` so the Google SDK sees native Gemini payloads.\n\nimport { randomUUID } from 'node:crypto';\nimport type { LanguageModel } from 'ai';\nimport {\n ANTIGRAVITY_API_VERSION,\n ANTIGRAVITY_BASE_URLS,\n ANTIGRAVITY_USER_AGENT,\n} from '../oauth/antigravity-oauth.js';\n\nexport interface AntigravityCloudCodeModelOptions {\n modelId: string;\n accessToken: string;\n projectId: string;\n refreshToken?: () => Promise<string | null>;\n /**\n * Sanitized transport diagnostics. Messages carry endpoint host, attempt\n * number, status, byte counts and error *names* only — never tokens, the\n * project id, prompts, tool arguments, or any response body.\n */\n onDebug?: (message: string) => void;\n}\n\nconst CLOUD_CODE_BASES = ANTIGRAVITY_BASE_URLS.map(base => base.replace(/\\/+$/, ''));\nconst CLOUD_CODE_BASE = CLOUD_CODE_BASES[0]!;\n/** Ordered fallback lists — same order as ANTIGRAVITY_BASE_URLS, first success wins. */\nconst STREAM_URLS = CLOUD_CODE_BASES.map(base => `${base}/${ANTIGRAVITY_API_VERSION}:streamGenerateContent?alt=sse`);\nconst UNARY_URLS = CLOUD_CODE_BASES.map(base => `${base}/${ANTIGRAVITY_API_VERSION}:generateContent`);\n/** Syntactically valid Google SDK prefix — every request is intercepted by custom fetch. */\nconst SDK_BASE_URL = `${CLOUD_CODE_BASE}/v1beta`;\n\n/**\n * Statuses that mean \"this endpoint can't serve the request\" rather than\n * \"this request is wrong\". Only these fail over — replaying a 400/401/403 across\n * every endpoint would just repeat a request the caller has to fix.\n */\nconst ENDPOINT_FAILOVER_STATUSES = new Set([404, 408, 429]);\n\nfunction shouldTryNextEndpoint(status: number): boolean {\n return ENDPOINT_FAILOVER_STATUSES.has(status) || status >= 500;\n}\n\n/** Release a response we are abandoning, so its socket is not held open. */\nfunction discardResponse(response: Response): void {\n try { void response.body?.cancel(); } catch { /* already released */ }\n}\n\nexport function unwrapCloudCodeSsePayload(payload: string): string {\n const trimmed = payload.trim();\n if (trimmed === '' || trimmed === '[DONE]') return payload;\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (isWrappedCloudCodeBody(parsed)) {\n return JSON.stringify(parsed.response);\n }\n } catch {\n // Malformed JSON / error events pass through unchanged.\n }\n return payload;\n}\n\nexport function unwrapCloudCodeJsonBody(text: string): string {\n try {\n const parsed: unknown = JSON.parse(text);\n if (isWrappedCloudCodeBody(parsed)) {\n return JSON.stringify(parsed.response);\n }\n } catch {\n // keep original\n }\n return text;\n}\n\nexport function consumeCloudCodeSseBuffer(buffer: string): { emitted: string; rest: string } {\n const separator = /\\r?\\n\\r?\\n/;\n let rest = buffer;\n let emitted = '';\n while (true) {\n const match = separator.exec(rest);\n if (!match || match.index === undefined) break;\n const rawEvent = rest.slice(0, match.index);\n const sep = match[0];\n rest = rest.slice(match.index + sep.length);\n emitted += transformSseEvent(rawEvent) + sep;\n }\n return { emitted, rest };\n}\n\nexport function createCloudCodeSseUnwrapper(): TransformStream<Uint8Array, Uint8Array> {\n const decoder = new TextDecoder();\n const encoder = new TextEncoder();\n let pending = '';\n return new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n pending += decoder.decode(chunk, { stream: true });\n const { emitted, rest } = consumeCloudCodeSseBuffer(pending);\n pending = rest;\n if (emitted) controller.enqueue(encoder.encode(emitted));\n },\n flush(controller) {\n pending += decoder.decode();\n if (!pending) return;\n const { emitted, rest } = consumeCloudCodeSseBuffer(pending);\n const tail = emitted + (rest ? transformSseEvent(rest) : '');\n if (tail) controller.enqueue(encoder.encode(tail));\n },\n });\n}\n\nexport function createCloudCodeFetch(\n options: AntigravityCloudCodeModelOptions,\n fetchImpl?: typeof globalThis.fetch,\n): typeof globalThis.fetch {\n let accessToken = options.accessToken;\n const debug = (msg: string) => { try { options.onDebug?.(`cloud-code: ${msg}`); } catch { /* ignore */ } };\n\n return async (input, init) => {\n const url = requestUrl(input);\n const streaming = url.includes('streamGenerateContent');\n const signal = init?.signal ?? (input instanceof Request ? input.signal : undefined);\n const geminiBody = await readJsonBody(input, init);\n const envelope = {\n project: options.projectId,\n requestId: randomUUID(),\n model: options.modelId,\n userAgent: ANTIGRAVITY_USER_AGENT,\n requestType: 'agent' as const,\n enabledCreditTypes: ['GOOGLE_ONE_AI'],\n request: geminiBody,\n };\n const body = JSON.stringify(envelope);\n // `String.length` is UTF-16 code units, not bytes — non-ASCII prompts would\n // under-report. The diagnostic claims bytes, so measure bytes.\n const bodyByteLength = Buffer.byteLength(body, 'utf8');\n const upstreamUrls = streaming ? STREAM_URLS : UNARY_URLS;\n const doFetch = fetchImpl ?? ((input: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(input, init));\n\n const send = async (url: string, token: string): Promise<Response> => {\n try {\n return await doFetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n 'User-Agent': ANTIGRAVITY_USER_AGENT,\n },\n body,\n signal,\n });\n } catch (err) {\n if (isAbortError(err, signal)) throw abortError(signal, err);\n throw err;\n }\n };\n\n /**\n * Walk the ordered endpoint list. The decision to move on is made from the\n * status line alone, before the body is read — so once a response is\n * returned, its (possibly streaming) body is committed to and no later\n * endpoint is ever tried.\n */\n const sendWithFailover = async (token: string, startIndex = 0): Promise<{ response: Response; url: string; index: number }> => {\n let lastError: unknown;\n for (let i = startIndex; i < upstreamUrls.length; i += 1) {\n const url = upstreamUrls[i]!;\n const isLast = i === upstreamUrls.length - 1;\n const where = `endpoint=${i + 1}/${upstreamUrls.length} host=${endpointHost(url)}`;\n let response: Response | undefined;\n try {\n debug(`request ${where} kind=${streaming ? 'stream' : 'unary'} payloadBytes=${bodyByteLength}`);\n response = await send(url, token);\n } catch (err) {\n if (isAbortError(err, signal)) throw err;\n lastError = err;\n debug(`network failure ${where} errorName=${errorName(err)}`);\n }\n if (response) {\n if (isLast || !shouldTryNextEndpoint(response.status)) {\n debug(`response ${where} status=${response.status}`);\n return { response, url, index: i };\n }\n discardResponse(response);\n lastError = new Error(`Cloud Code Assist endpoint returned ${response.status}`);\n debug(`retryable status=${response.status} ${where} — trying next endpoint`);\n }\n // Only reached when another endpoint is still to be tried.\n if (signal?.aborted) throw abortError(signal);\n }\n throw lastError ?? new Error('All Cloud Code Assist endpoints failed');\n };\n\n // The token *this* request actually sent. Comparing the refresh result\n // against the shared `accessToken` instead would let whichever concurrent\n // request refreshed first suppress every other in-flight request's retry.\n const tokenUsed = accessToken;\n let { response, index: servedByIndex } = await sendWithFailover(tokenUsed);\n\n if (response.status === 401 && options.refreshToken && !signal?.aborted) {\n debug('status=401 — refreshing credential');\n const refreshed = await options.refreshToken().catch(() => null);\n if (refreshed && refreshed !== tokenUsed && !signal?.aborted) {\n accessToken = refreshed;\n discardResponse(response);\n // One refresh, one retry — resuming the ordered fallback *at* the\n // endpoint that issued the 401. Earlier endpoints already failed for\n // their own reasons, so they are not replayed; later ones are still the\n // documented fallback if the retried endpoint is itself down.\n ({ response } = await sendWithFailover(refreshed, servedByIndex));\n debug(`retry after refresh status=${response.status}`);\n } else {\n debug(`refresh did not yield a new credential (refreshed=${refreshed ? 'same' : 'none'})`);\n }\n }\n\n return adaptUpstreamResponse(response, streaming);\n };\n}\n\nexport async function createAntigravityCloudCodeModel(\n options: AntigravityCloudCodeModelOptions,\n): Promise<LanguageModel> {\n const { createGoogleGenerativeAI } = await import('@ai-sdk/google');\n const google = createGoogleGenerativeAI({\n apiKey: 'relay-cloud-code',\n baseURL: SDK_BASE_URL,\n fetch: createCloudCodeFetch(options),\n });\n return google(options.modelId);\n}\n\n/** Host only — the endpoint URLs are compile-time constants, never user data. */\nfunction endpointHost(url: string): string {\n try { return new URL(url).host; } catch { return 'unknown'; }\n}\n\n/** Error *name* only — messages can embed request URLs or upstream body text. */\nfunction errorName(err: unknown): string {\n if (err instanceof Error) return err.name || 'Error';\n return typeof err;\n}\n\nfunction isWrappedCloudCodeBody(parsed: unknown): parsed is { response: object } {\n return !!parsed\n && typeof parsed === 'object'\n && !Array.isArray(parsed)\n && 'response' in parsed\n && (parsed as { response: unknown }).response !== null\n && typeof (parsed as { response: unknown }).response === 'object';\n}\n\nfunction transformSseEvent(event: string): string {\n return event.replace(/^(data:[ \\t]*)(.*)$/gm, (_all, prefix: string, payload: string) => (\n `${prefix}${unwrapCloudCodeSsePayload(payload)}`\n ));\n}\n\nfunction requestUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') return input;\n if (input instanceof URL) return input.href;\n return input.url;\n}\n\nasync function readJsonBody(input: RequestInfo | URL, init?: RequestInit): Promise<unknown> {\n const body = init?.body;\n if (typeof body === 'string') return JSON.parse(body);\n if (body instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(body));\n if (body instanceof ArrayBuffer) return JSON.parse(new TextDecoder().decode(body));\n const request = input instanceof Request ? input.clone() : new Request(input, init);\n return request.json();\n}\n\nasync function adaptUpstreamResponse(upstream: Response, streaming: boolean): Promise<Response> {\n const fallbackType = streaming ? 'text/event-stream' : 'application/json';\n const contentType = upstream.headers.get('content-type') ?? fallbackType;\n const headers = new Headers({ 'Content-Type': contentType });\n if (!upstream.ok) {\n const errBody = await upstream.text();\n return new Response(errBody, {\n status: upstream.status,\n statusText: upstream.statusText,\n headers,\n });\n }\n if (streaming) {\n const body = upstream.body ? upstream.body.pipeThrough(createCloudCodeSseUnwrapper()) : null;\n return new Response(body, {\n status: upstream.status,\n statusText: upstream.statusText,\n headers,\n });\n }\n const text = await upstream.text();\n headers.set('Content-Type', 'application/json');\n return new Response(unwrapCloudCodeJsonBody(text), { status: 200, headers });\n}\n\nfunction isAbortError(err: unknown, signal?: AbortSignal): boolean {\n if (signal?.aborted) return true;\n return !!err && typeof err === 'object' && (err as { name?: string }).name === 'AbortError';\n}\n\nfunction abortError(signal: AbortSignal | undefined, cause?: unknown): Error {\n if (signal?.reason instanceof Error) return signal.reason;\n if (cause instanceof Error) return cause;\n return new DOMException('This operation was aborted', 'AbortError');\n}\n","// src/core/model.ts — construct a ready Vercel AI SDK LanguageModel from a route id.\n\nimport type { LanguageModel } from 'ai';\nimport {\n resolveProviderCredential,\n resolveProviderOAuthAccountId,\n resolveProviderOAuthProviderData,\n} from '../env.js';\nimport { createLanguageModel, type ProviderModelSpec } from '../provider-factory.js';\nimport { providerRefreshToken } from '../provider-runtime.js';\nimport type { CachedModel, RegistryProvider } from '../registry/types.js';\nimport { createAntigravityCloudCodeModel } from './antigravity-model.js';\nimport { loadCoreRegistry } from './catalog.js';\nimport { RelayCoreError, isRelayCoreError } from './errors.js';\nimport { resolveReasoningProviderOptions, withReasoningProviderOptions, type RelayProviderOptions } from './reasoning.js';\nimport { parseRelayRouteId } from './route-id.js';\nimport type { CreateRelayModelOptions, RelayRouteId } from './types.js';\n\nfunction isAntigravityCloudCodeRoute(provider: RegistryProvider, model: CachedModel): boolean {\n return provider.id === 'antigravity'\n && provider.authType === 'oauth'\n && model.modelFormat === 'cloud-code';\n}\n\nfunction findRoute(registry: ReturnType<typeof loadCoreRegistry>, providerId: string, modelId: string, routeId: RelayRouteId): { provider: RegistryProvider; model: CachedModel } {\n const provider = registry.providers.find(p => p.id === providerId);\n if (!provider) {\n throw new RelayCoreError('ROUTE_NOT_FOUND', `No provider registered with id \"${providerId}\".`, { providerId, routeId });\n }\n if (!provider.enabled) {\n throw new RelayCoreError('PROVIDER_DISABLED', `Provider \"${provider.name}\" is disabled — enable it in relay-ai ui.`, { providerId, routeId });\n }\n const model = provider.modelsCache?.models.find(m => m.id === modelId);\n if (!model) {\n throw new RelayCoreError('UNSUPPORTED_MODEL', `Provider \"${provider.name}\" has no cached model \"${modelId}\" — refresh its models in relay-ai ui.`, { providerId, routeId });\n }\n return { provider, model };\n}\n\nasync function resolveCredential(provider: RegistryProvider, routeId: RelayRouteId): Promise<string> {\n try {\n const credential = await resolveProviderCredential(provider.id, provider.authRef);\n if (credential) return credential;\n if (provider.authType === 'none') return '';\n throw new RelayCoreError(\n 'CREDENTIAL_UNAVAILABLE',\n `No credential available for provider \"${provider.name}\" — re-authenticate in relay-ai ui.`,\n { providerId: provider.id, routeId },\n );\n } catch (err) {\n if (isRelayCoreError(err)) throw err;\n if (provider.authType === 'oauth') {\n throw new RelayCoreError(\n 'OAUTH_REFRESH_FAILED',\n `OAuth token refresh failed for provider \"${provider.name}\" — re-authenticate in relay-ai ui.`,\n { providerId: provider.id, routeId, cause: err },\n );\n }\n throw new RelayCoreError(\n 'PROVIDER_LOAD_FAILED',\n `Failed to resolve the credential for provider \"${provider.name}\".`,\n { providerId: provider.id, routeId, cause: err },\n );\n }\n}\n\n/**\n * Build a ready Vercel AI SDK `LanguageModel` for a `provider::model` route id.\n *\n * Re-reads the registry, credentials, and OAuth state on every call — nothing is\n * cached across calls, so a provider disabled or re-authenticated after the last\n * call takes effect without restarting the consumer process. Credentials are\n * resolved (and OAuth tokens refreshed) by Relay's existing machinery; the\n * credential and the intermediate spec never leave this function.\n */\nexport async function createRelayModel(routeId: RelayRouteId, options?: CreateRelayModelOptions): Promise<LanguageModel> {\n const { providerId, modelId } = parseRelayRouteId(routeId);\n const registry = loadCoreRegistry();\n const { provider, model } = findRoute(registry, providerId, modelId, routeId);\n\n // Resolved before any credential work so an unsupported level fails fast and\n // without touching the keyring or the network.\n const reasoningOptions: RelayProviderOptions | undefined = options?.reasoning === undefined\n ? undefined\n : resolveReasoningProviderOptions(options.reasoning, provider, model, routeId);\n const finish = (built: LanguageModel): Promise<LanguageModel> => (\n reasoningOptions ? withReasoningProviderOptions(built, reasoningOptions) : Promise.resolve(built)\n );\n\n if (isAntigravityCloudCodeRoute(provider, model)) {\n const apiKey = await resolveCredential(provider, routeId);\n const providerData = await resolveProviderOAuthProviderData(provider.authRef);\n const projectId = typeof providerData?.projectId === 'string' ? providerData.projectId.trim() : '';\n if (!projectId) {\n throw new RelayCoreError(\n 'CREDENTIAL_UNAVAILABLE',\n `Provider \"${provider.name}\" is missing project metadata — re-authenticate in relay-ai ui.`,\n { providerId: provider.id, routeId },\n );\n }\n try {\n return await finish(await createAntigravityCloudCodeModel({\n modelId: model.upstreamModelId ?? model.id,\n accessToken: apiKey,\n projectId,\n refreshToken: providerRefreshToken(provider.id, provider.authType, provider.authRef),\n ...(options?.onDebug ? { onDebug: options.onDebug } : {}),\n }));\n } catch (err) {\n if (isRelayCoreError(err)) throw err;\n throw new RelayCoreError(\n 'PROVIDER_LOAD_FAILED',\n `Failed to construct model \"${modelId}\" for provider \"${provider.name}\".`,\n { providerId, routeId, cause: err },\n );\n }\n }\n\n const npm = model.npm ?? provider.api.npm;\n if (!npm) {\n throw new RelayCoreError('UNSUPPORTED_MODEL', `Model \"${modelId}\" has no SDK provider package — refresh the provider's models in relay-ai ui.`, { providerId, routeId });\n }\n\n const apiKey = await resolveCredential(provider, routeId);\n\n let oauthAccountId: string | undefined;\n let providerData: Record<string, unknown> | undefined;\n if (provider.authType === 'oauth') {\n oauthAccountId = await resolveProviderOAuthAccountId(provider.authRef);\n providerData = await resolveProviderOAuthProviderData(provider.authRef);\n }\n\n const spec: ProviderModelSpec = {\n npm,\n modelId: model.upstreamModelId ?? model.id,\n apiKey,\n baseURL: model.apiUrl ?? provider.api.url,\n providerId: provider.id,\n authType: provider.authType,\n oauthAccountId,\n providerData,\n headers: provider.api.headers,\n refreshToken: providerRefreshToken(provider.id, provider.authType, provider.authRef),\n useResponsesLite: model.useResponsesLite,\n preferWebSockets: model.preferWebSockets,\n ...(options?.onDebug ? { onDebug: options.onDebug } : {}),\n };\n\n try {\n return await finish(await createLanguageModel(spec));\n } catch (err) {\n if (isRelayCoreError(err)) throw err;\n throw new RelayCoreError(\n 'PROVIDER_LOAD_FAILED',\n `Failed to construct model \"${modelId}\" for provider \"${provider.name}\".`,\n { providerId, routeId, cause: err },\n );\n }\n}\n"],"mappings":"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","names":["join","homedir","join","join","homedir","join","entry","open","copyFileSync","existsSync","mkdirSync","readFileSync","renameSync","dirname","mkdirSync","dirname","existsSync","readFileSync","copyFileSync","renameSync","wrapLanguageModel","readFileSync","existsSync","readFileSync","homedir","join","DEVICE_CODE_DEFAULT_EXPIRES_MS","CLIENT_ID","DEVICE_CODE_DEFAULT_EXPIRES_MS","CLIENT_ID","TOKEN_URL","TOKEN_URL","open","readFileSync","homedir","TOKEN_URL","TOKEN_URL","chmodSync","existsSync","mkdirSync","readFileSync","writeFileSync","DIR_MODE","FILE_MODE","existsSync","readFileSync","mkdirSync","chmodSync","writeFileSync","chmodSync","existsSync","mkdirSync","readFileSync","statSync","writeFileSync","dirname","join","chmodSync","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","randomUUID","randomUUID","input","init","url","response","apiKey","providerData"]}