{"version":3,"file":"env-api-keys.d.ts","sourceRoot":"","sources":["../src/env-api-keys.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAgChD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC;AAC1E,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAuEnE,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAkBtD,CAAC;AAUF,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;AAErF,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,gBAAgB,CAAC;IACvB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,UAAU,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAwF1E","sourcesContent":["// NEVER convert to top-level imports - breaks browser/Vite builds (web-ui)\nlet _existsSync: typeof import(\"node:fs\").existsSync | null = null;\nlet _homedir: typeof import(\"node:os\").homedir | null = null;\nlet _join: typeof import(\"node:path\").join | null = null;\n\ntype DynamicImport = (specifier: string) => Promise<unknown>;\n\nconst dynamicImport: DynamicImport = (specifier) => import(specifier);\nconst NODE_FS_SPECIFIER = \"node:\" + \"fs\";\nconst NODE_OS_SPECIFIER = \"node:\" + \"os\";\nconst NODE_PATH_SPECIFIER = \"node:\" + \"path\";\n\n// Eagerly load in Node.js/Bun environment only\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\tdynamicImport(NODE_FS_SPECIFIER).then((m) => {\n\t\t_existsSync = (m as typeof import(\"node:fs\")).existsSync;\n\t});\n\tdynamicImport(NODE_OS_SPECIFIER).then((m) => {\n\t\t_homedir = (m as typeof import(\"node:os\")).homedir;\n\t});\n\tdynamicImport(NODE_PATH_SPECIFIER).then((m) => {\n\t\t_join = (m as typeof import(\"node:path\")).join;\n\t});\n}\n\nimport type { KnownProvider } from \"./types.js\";\n\nlet cachedVertexAdcCredentialsExists: boolean | null = null;\n\nfunction hasVertexAdcCredentials(): boolean {\n\tif (cachedVertexAdcCredentialsExists === null) {\n\t\t// If node modules haven't loaded yet (async import race at startup),\n\t\t// return false WITHOUT caching so the next call retries once they're ready.\n\t\t// Only cache false permanently in a browser environment where fs is never available.\n\t\tif (!_existsSync || !_homedir || !_join) {\n\t\t\tconst isNode = typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun);\n\t\t\tif (!isNode) {\n\t\t\t\t// Definitively in a browser — safe to cache false permanently\n\t\t\t\tcachedVertexAdcCredentialsExists = false;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check GOOGLE_APPLICATION_CREDENTIALS env var first (standard way)\n\t\tconst gacPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;\n\t\tif (gacPath) {\n\t\t\tcachedVertexAdcCredentialsExists = _existsSync(gacPath);\n\t\t} else {\n\t\t\t// Fall back to default ADC path (lazy evaluation)\n\t\t\tcachedVertexAdcCredentialsExists = _existsSync(\n\t\t\t\t_join(_homedir(), \".config\", \"gcloud\", \"application_default_credentials.json\"),\n\t\t\t);\n\t\t}\n\t}\n\treturn cachedVertexAdcCredentialsExists;\n}\n\n/**\n * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.\n *\n * Will not return API keys for providers that require OAuth tokens.\n */\nexport function getEnvApiKey(provider: KnownProvider): string | undefined;\nexport function getEnvApiKey(provider: string): string | undefined;\nexport function getEnvApiKey(provider: any): string | undefined {\n\t// Fall back to environment variables\n\tif (provider === \"github-copilot\") {\n\t\treturn process.env.COPILOT_GITHUB_TOKEN || process.env.GH_TOKEN || process.env.GITHUB_TOKEN;\n\t}\n\n\t// ANTHROPIC_OAUTH_TOKEN takes precedence over ANTHROPIC_API_KEY\n\tif (provider === \"anthropic\") {\n\t\treturn process.env.ANTHROPIC_OAUTH_TOKEN || process.env.ANTHROPIC_API_KEY;\n\t}\n\n\t// Vertex AI supports either an explicit API key or Application Default Credentials\n\t// Auth is configured via `gcloud auth application-default login`\n\tif (provider === \"google-vertex\") {\n\t\tif (process.env.GOOGLE_CLOUD_API_KEY) {\n\t\t\treturn process.env.GOOGLE_CLOUD_API_KEY;\n\t\t}\n\n\t\tconst hasCredentials = hasVertexAdcCredentials();\n\t\tconst hasProject = !!(process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT);\n\t\tconst hasLocation = !!process.env.GOOGLE_CLOUD_LOCATION;\n\n\t\tif (hasCredentials && hasProject && hasLocation) {\n\t\t\treturn \"<authenticated>\";\n\t\t}\n\t}\n\n\tif (provider === \"amazon-bedrock\") {\n\t\t// Amazon Bedrock supports multiple credential sources:\n\t\t// 1. AWS_PROFILE - named profile from ~/.aws/credentials\n\t\t// 2. AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY - standard IAM keys\n\t\t// 3. AWS_BEARER_TOKEN_BEDROCK - Bedrock API keys (bearer token)\n\t\t// 4. AWS_CONTAINER_CREDENTIALS_RELATIVE_URI - ECS task roles\n\t\t// 5. AWS_CONTAINER_CREDENTIALS_FULL_URI - ECS task roles (full URI)\n\t\t// 6. AWS_WEB_IDENTITY_TOKEN_FILE - IRSA (IAM Roles for Service Accounts)\n\t\tif (\n\t\t\tprocess.env.AWS_PROFILE ||\n\t\t\t(process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) ||\n\t\t\tprocess.env.AWS_BEARER_TOKEN_BEDROCK ||\n\t\t\tprocess.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ||\n\t\t\tprocess.env.AWS_CONTAINER_CREDENTIALS_FULL_URI ||\n\t\t\tprocess.env.AWS_WEB_IDENTITY_TOKEN_FILE\n\t\t) {\n\t\t\treturn \"<authenticated>\";\n\t\t}\n\t}\n\n\tconst envMap: Record<string, string> = {\n\t\topenai: \"OPENAI_API_KEY\",\n\t\t\"azure-openai-responses\": \"AZURE_OPENAI_API_KEY\",\n\t\tgoogle: \"GEMINI_API_KEY\",\n\t\tgroq: \"GROQ_API_KEY\",\n\t\tcerebras: \"CEREBRAS_API_KEY\",\n\t\txai: \"XAI_API_KEY\",\n\t\topenrouter: \"OPENROUTER_API_KEY\",\n\t\t\"vercel-ai-gateway\": \"AI_GATEWAY_API_KEY\",\n\t\tzai: \"ZAI_API_KEY\",\n\t\tmistral: \"MISTRAL_API_KEY\",\n\t\tminimax: \"MINIMAX_API_KEY\",\n\t\t\"minimax-cn\": \"MINIMAX_CN_API_KEY\",\n\t\thuggingface: \"HF_TOKEN\",\n\t\topencode: \"OPENCODE_API_KEY\",\n\t\t\"opencode-go\": \"OPENCODE_API_KEY\",\n\t\t\"kimi-coding\": \"KIMI_API_KEY\",\n\t};\n\n\tconst envVar = envMap[provider];\n\treturn envVar ? process.env[envVar] : undefined;\n}\n\nexport const ENV_VAR_BY_PROVIDER: Record<string, string> = {\n\topenai: \"OPENAI_API_KEY\",\n\t\"azure-openai-responses\": \"AZURE_OPENAI_API_KEY\",\n\tanthropic: \"ANTHROPIC_API_KEY\",\n\tgoogle: \"GEMINI_API_KEY\",\n\tgroq: \"GROQ_API_KEY\",\n\tcerebras: \"CEREBRAS_API_KEY\",\n\txai: \"XAI_API_KEY\",\n\topenrouter: \"OPENROUTER_API_KEY\",\n\t\"vercel-ai-gateway\": \"AI_GATEWAY_API_KEY\",\n\tzai: \"ZAI_API_KEY\",\n\tmistral: \"MISTRAL_API_KEY\",\n\tminimax: \"MINIMAX_API_KEY\",\n\t\"minimax-cn\": \"MINIMAX_CN_API_KEY\",\n\thuggingface: \"HF_TOKEN\",\n\topencode: \"OPENCODE_API_KEY\",\n\t\"opencode-go\": \"OPENCODE_API_KEY\",\n\t\"kimi-coding\": \"KIMI_API_KEY\",\n};\n\nconst OAUTH_PROVIDERS = new Set([\n\t\"anthropic\",\n\t\"github-copilot\",\n\t\"google-gemini-cli\",\n\t\"google-antigravity\",\n\t\"openai-codex\",\n]);\n\nexport type ProviderAuthKind = \"env\" | \"oauth\" | \"file\" | \"needs-region\" | \"missing\";\n\nexport interface ProviderAuthStatus {\n\tkind: ProviderAuthKind;\n\t/** Short user-facing hint, e.g. \"set XAI_API_KEY\" or \"/login anthropic\". */\n\thint?: string;\n\t/** The env var name this provider would use, if any. */\n\tenvVar?: string;\n\t/** True when the agent can dispatch a request right now without further setup. */\n\tconfigured: boolean;\n}\n\n/**\n * Describe how a provider authenticates and whether the user is set up for it.\n *\n * The UI uses this to badge providers (`✓` / `🔑` / `✗` / `⚙`) and surface\n * actionable hints without having to know about every provider's idiosyncrasies.\n */\nexport function getProviderAuthStatus(provider: string): ProviderAuthStatus {\n\tif (provider === \"github-copilot\") {\n\t\tconst token = process.env.COPILOT_GITHUB_TOKEN || process.env.GH_TOKEN || process.env.GITHUB_TOKEN;\n\t\tif (token) return { kind: \"env\", configured: true, envVar: \"GITHUB_TOKEN\" };\n\t\treturn {\n\t\t\tkind: \"oauth\",\n\t\t\tconfigured: false,\n\t\t\thint: \"/login github-copilot\",\n\t\t\tenvVar: \"GITHUB_TOKEN\",\n\t\t};\n\t}\n\n\tif (provider === \"anthropic\") {\n\t\tif (process.env.ANTHROPIC_OAUTH_TOKEN) {\n\t\t\treturn { kind: \"oauth\", configured: true, envVar: \"ANTHROPIC_OAUTH_TOKEN\" };\n\t\t}\n\t\tif (process.env.ANTHROPIC_API_KEY) {\n\t\t\treturn { kind: \"env\", configured: true, envVar: \"ANTHROPIC_API_KEY\" };\n\t\t}\n\t\treturn {\n\t\t\tkind: \"missing\",\n\t\t\tconfigured: false,\n\t\t\thint: \"set ANTHROPIC_API_KEY or /login anthropic\",\n\t\t\tenvVar: \"ANTHROPIC_API_KEY\",\n\t\t};\n\t}\n\n\tif (provider === \"google-vertex\") {\n\t\tif (process.env.GOOGLE_CLOUD_API_KEY) {\n\t\t\treturn { kind: \"env\", configured: true, envVar: \"GOOGLE_CLOUD_API_KEY\" };\n\t\t}\n\t\tconst hasCredentials = hasVertexAdcCredentials();\n\t\tconst hasProject = !!(process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT);\n\t\tconst hasLocation = !!process.env.GOOGLE_CLOUD_LOCATION;\n\t\tif (hasCredentials && hasProject && hasLocation) {\n\t\t\treturn { kind: \"file\", configured: true };\n\t\t}\n\t\treturn {\n\t\t\tkind: \"file\",\n\t\t\tconfigured: false,\n\t\t\thint: \"run `gcloud auth application-default login` and set GOOGLE_CLOUD_PROJECT/LOCATION\",\n\t\t};\n\t}\n\n\tif (provider === \"amazon-bedrock\") {\n\t\tconst hasCreds =\n\t\t\tprocess.env.AWS_PROFILE ||\n\t\t\t(process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) ||\n\t\t\tprocess.env.AWS_BEARER_TOKEN_BEDROCK ||\n\t\t\tprocess.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ||\n\t\t\tprocess.env.AWS_CONTAINER_CREDENTIALS_FULL_URI ||\n\t\t\tprocess.env.AWS_WEB_IDENTITY_TOKEN_FILE;\n\t\tif (!hasCreds) {\n\t\t\treturn {\n\t\t\t\tkind: \"missing\",\n\t\t\t\tconfigured: false,\n\t\t\t\thint: \"set AWS_PROFILE or AWS_ACCESS_KEY_ID/SECRET\",\n\t\t\t};\n\t\t}\n\t\t// Region is required for Bedrock. AWS SDK looks at AWS_REGION/AWS_DEFAULT_REGION\n\t\t// or the profile's `region`. We don't read the profile here; the env signal is\n\t\t// the cheap reliable check.\n\t\tif (!(process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION)) {\n\t\t\treturn {\n\t\t\t\tkind: \"needs-region\",\n\t\t\t\tconfigured: false,\n\t\t\t\thint: \"set AWS_REGION (or configure profile region)\",\n\t\t\t};\n\t\t}\n\t\treturn { kind: \"file\", configured: true };\n\t}\n\n\tif (OAUTH_PROVIDERS.has(provider)) {\n\t\treturn {\n\t\t\tkind: \"oauth\",\n\t\t\tconfigured: false,\n\t\t\thint: `/login ${provider}`,\n\t\t};\n\t}\n\n\tconst envVar = ENV_VAR_BY_PROVIDER[provider];\n\tif (envVar) {\n\t\tconst value = process.env[envVar];\n\t\tif (value) return { kind: \"env\", configured: true, envVar };\n\t\treturn { kind: \"missing\", configured: false, hint: `set ${envVar}`, envVar };\n\t}\n\n\treturn { kind: \"missing\", configured: false, hint: \"no known auth source\" };\n}\n"]}