Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
1 line
382 KiB
JSON
1 line
382 KiB
JSON
{"repo": "asma-a1v/codexbar", "files": {"rust/src/settings/api_keys.rs": {"3c6f3c3b6ef1dabfb3daa23538c62af10aebebe4": {"t": 1785595458.5423992, "n": 21358, "h": "4b6eb87d506c291f", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n let masked = mask_api_key(&entry.api_key);\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\nfn mask_api_key(api_key: &str) -> String {\n let chars: Vec<char> = api_key.chars().collect();\n if chars.len() > 12 {\n let prefix: String = chars.iter().take(4).collect();\n let suffix: String = chars.iter().skip(chars.len() - 4).collect();\n format!(\"{prefix}...{suffix}\")\n } else if chars.len() > 4 {\n let prefix: String = chars.iter().take(4).collect();\n format!(\"{prefix}...\")\n } else {\n \"****\".to_string()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"Z_AI_API_KEY or ZAI_API_TOKEN\"),\n api_key_help: Some(\n \"Get your API token from z.ai Dashboard. BigModel team usage can set Z_AI_BIGMODEL_ORGANIZATION + Z_AI_BIGMODEL_PROJECT, or provider workspace_id as organization|project.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/manage-apikey/coding-plan/personal/my-plan\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Ollama,\n name: \"Ollama\",\n requires_api_key: false,\n api_key_env_var: Some(\"OLLAMA_API_KEY / OLLAMA_KEY\"),\n api_key_help: Some(\n \"Optional: use an Ollama API key for Cloud validation, or browser cookies for usage.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://ollama.com/settings\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AzureOpenAI,\n name: \"Azure OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT\",\n ),\n api_key_help: Some(\n \"Use env vars, or save JSON {api_key, endpoint, deployment, api_version}; composite api_key|endpoint|deployment[|api_version] also works.\",\n ),\n config_file_path: Some(\"~/.codexbar/api_keys.json\"),\n dashboard_url: Some(\"https://ai.azure.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kimi,\n name: \"Kimi Code API\",\n requires_api_key: true,\n api_key_env_var: Some(\"KIMI_CODE_API_KEY\"),\n api_key_help: Some(\n \"Get your Kimi Code API key from Kimi. Optional HTTPS proxy base URL: KIMI_CODE_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.moonshot.cn/console/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN] or AWS_PROFILE\",\n ),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, profile:name, or use AWS env vars/AWS CLI profiles.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepInfra,\n name: \"DeepInfra\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPINFRA_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from deepinfra.com/dash. Also accepts DEEPINFRA_TOKEN.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://deepinfra.com/dash\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AiAnd,\n name: \"ai&\",\n requires_api_key: true,\n api_key_env_var: Some(\"AIAND_API_KEY\"),\n api_key_help: Some(\"Get your API key from console.aiand.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aiand.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ZenMux,\n name: \"ZenMux\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZENMUX_MANAGEMENT_API_KEY\"),\n api_key_help: Some(\n \"Use a ZenMux Management API key (not an inference key). Also accepts ZENMUX_API_KEY.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://zenmux.ai/platform/management\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ClinePass,\n name: \"ClinePass\",\n requires_api_key: true,\n api_key_env_var: Some(\"CLINEPASS_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Cline / ClinePass. Also accepts CLINE_API_KEY.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://app.cline.bot/dashboard/subscription?personal=true\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Neuralwatt,\n name: \"Neuralwatt\",\n requires_api_key: true,\n api_key_env_var: Some(\"NEURALWATT_API_KEY\"),\n api_key_help: Some(\"Get your API key from portal.neuralwatt.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://portal.neuralwatt.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"ARK_API_KEY or VOLCENGINE_ACCESS_KEY_ID + VOLCENGINE_SECRET_ACCESS_KEY\",\n ),\n api_key_help: Some(\n \"Use ARK_API_KEY for chat probe fallback, or paste Coding Plan credentials as access_key|secret_key|region (region defaults to cn-beijing).\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Chutes,\n name: \"Chutes\",\n requires_api_key: true,\n api_key_env_var: Some(\"CHUTES_API_KEY\"),\n api_key_help: Some(\n \"Paste a Chutes API key. Optional API URL override: CHUTES_API_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://chutes.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LiteLLM,\n name: \"LiteLLM\",\n requires_api_key: true,\n api_key_env_var: Some(\"LITELLM_API_KEY + LITELLM_BASE_URL\"),\n api_key_help: Some(\n \"Paste a LiteLLM key and set the base URL in provider extras or LITELLM_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Poe,\n name: \"Poe\",\n requires_api_key: true,\n api_key_env_var: Some(\"POE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Poe API settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://poe.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Devin,\n name: \"Devin\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEVIN_BEARER_TOKEN + DEVIN_ORG\"),\n api_key_help: Some(\n \"Paste a Devin bearer token and set the organization in provider extras or DEVIN_ORG.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://app.devin.ai/settings/billing\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zed,\n name: \"Zed\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZED_CREDENTIALS\"),\n api_key_help: Some(\n \"Paste Zed credentials as `user_id access_token`; optional API URL in provider extras.\",\n ),\n config_file_path: Some(\"~/.config/zed/settings.json\"),\n dashboard_url: Some(\"https://zed.dev/account\"),\n },\n ProviderConfigInfo {\n id: ProviderId::CrossModel,\n name: \"CrossModel\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROSSMODEL_API_KEY\"),\n api_key_help: Some(\n \"Paste a CrossModel API key. Optional API URL override: CROSSMODEL_API_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://crossmodel.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Sub2Api,\n name: \"sub2api\",\n requires_api_key: true,\n api_key_env_var: Some(\"SUB2API_API_KEY\"),\n api_key_help: Some(\n \"Paste a group API key and set the base URL in provider extras or SUB2API_BASE_URL. HTTPS required (loopback HTTP allowed for local dev).\",\n ),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Factory,\n name: \"Droid (Factory)\",\n requires_api_key: true,\n api_key_env_var: Some(\"FACTORY_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Factory → Settings → API Keys. Optional fallback: %USERPROFILE%\\\\.factory\\\\.env. Auto mode tries the key first, then browser cookies.\",\n ),\n config_file_path: Some(\"%USERPROFILE%\\\\.factory\\\\.env\"),\n dashboard_url: Some(\"https://app.factory.ai/settings/api-keys\"),\n },\n ]\n}\n"}, "c1a6ff9297deb57662cbcb3dffb13e28f1904aa0": {"t": 1785757144.2596292, "n": 19227, "h": "9896af728b4af9b2", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n let masked = mask_api_key(&entry.api_key);\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\nfn mask_api_key(api_key: &str) -> String {\n let chars: Vec<char> = api_key.chars().collect();\n if chars.len() > 12 {\n let prefix: String = chars.iter().take(4).collect();\n let suffix: String = chars.iter().skip(chars.len() - 4).collect();\n format!(\"{prefix}...{suffix}\")\n } else if chars.len() > 4 {\n let prefix: String = chars.iter().take(4).collect();\n format!(\"{prefix}...\")\n } else {\n \"****\".to_string()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"Z_AI_API_KEY or ZAI_API_TOKEN\"),\n api_key_help: Some(\n \"Get your API token from z.ai Dashboard. BigModel team usage can set Z_AI_BIGMODEL_ORGANIZATION + Z_AI_BIGMODEL_PROJECT, or provider workspace_id as organization|project.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/manage-apikey/coding-plan/personal/my-plan\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Ollama,\n name: \"Ollama\",\n requires_api_key: false,\n api_key_env_var: Some(\"OLLAMA_API_KEY / OLLAMA_KEY\"),\n api_key_help: Some(\n \"Optional: use an Ollama API key for Cloud validation, or browser cookies for usage.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://ollama.com/settings\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AzureOpenAI,\n name: \"Azure OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT\",\n ),\n api_key_help: Some(\n \"Use env vars, or save JSON {api_key, endpoint, deployment, api_version}; composite api_key|endpoint|deployment[|api_version] also works.\",\n ),\n config_file_path: Some(\"~/.codexbar/api_keys.json\"),\n dashboard_url: Some(\"https://ai.azure.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kimi,\n name: \"Kimi Code API\",\n requires_api_key: true,\n api_key_env_var: Some(\"KIMI_CODE_API_KEY\"),\n api_key_help: Some(\n \"Get your Kimi Code API key from Kimi. Optional HTTPS proxy base URL: KIMI_CODE_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.moonshot.cn/console/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN] or AWS_PROFILE\",\n ),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, profile:name, or use AWS env vars/AWS CLI profiles.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"ARK_API_KEY or VOLCENGINE_ACCESS_KEY_ID + VOLCENGINE_SECRET_ACCESS_KEY\",\n ),\n api_key_help: Some(\n \"Use ARK_API_KEY for chat probe fallback, or paste Coding Plan credentials as access_key|secret_key|region (region defaults to cn-beijing).\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Chutes,\n name: \"Chutes\",\n requires_api_key: true,\n api_key_env_var: Some(\"CHUTES_API_KEY\"),\n api_key_help: Some(\n \"Paste a Chutes API key. Optional API URL override: CHUTES_API_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://chutes.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LiteLLM,\n name: \"LiteLLM\",\n requires_api_key: true,\n api_key_env_var: Some(\"LITELLM_API_KEY + LITELLM_BASE_URL\"),\n api_key_help: Some(\n \"Paste a LiteLLM key and set the base URL in provider extras or LITELLM_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Poe,\n name: \"Poe\",\n requires_api_key: true,\n api_key_env_var: Some(\"POE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Poe API settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://poe.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Devin,\n name: \"Devin\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEVIN_BEARER_TOKEN + DEVIN_ORG\"),\n api_key_help: Some(\n \"Paste a Devin bearer token and set the organization in provider extras or DEVIN_ORG.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://app.devin.ai/settings/billing\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zed,\n name: \"Zed\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZED_CREDENTIALS\"),\n api_key_help: Some(\n \"Paste Zed credentials as `user_id access_token`; optional API URL in provider extras.\",\n ),\n config_file_path: Some(\"~/.config/zed/settings.json\"),\n dashboard_url: Some(\"https://zed.dev/account\"),\n },\n ProviderConfigInfo {\n id: ProviderId::CrossModel,\n name: \"CrossModel\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROSSMODEL_API_KEY\"),\n api_key_help: Some(\n \"Paste a CrossModel API key. Optional API URL override: CROSSMODEL_API_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://crossmodel.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Sub2Api,\n name: \"sub2api\",\n requires_api_key: true,\n api_key_env_var: Some(\"SUB2API_API_KEY\"),\n api_key_help: Some(\n \"Paste a group API key and set the base URL in provider extras or SUB2API_BASE_URL. HTTPS required (loopback HTTP allowed for local dev).\",\n ),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Factory,\n name: \"Droid (Factory)\",\n requires_api_key: true,\n api_key_env_var: Some(\"FACTORY_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Factory → Settings → API Keys. Optional fallback: %USERPROFILE%\\\\.factory\\\\.env. Auto mode tries the key first, then browser cookies.\",\n ),\n config_file_path: Some(\"%USERPROFILE%\\\\.factory\\\\.env\"),\n dashboard_url: Some(\"https://app.factory.ai/settings/api-keys\"),\n },\n ]\n}\n"}, "3b39f595cf9fdd7cd74243f1e8cff837022919fa": {"t": 1785757145.9895194, "n": 18187, "h": "2e5e270f5e9a17bf", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n let masked = mask_api_key(&entry.api_key);\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\nfn mask_api_key(api_key: &str) -> String {\n let chars: Vec<char> = api_key.chars().collect();\n if chars.len() > 12 {\n let prefix: String = chars.iter().take(4).collect();\n let suffix: String = chars.iter().skip(chars.len() - 4).collect();\n format!(\"{prefix}...{suffix}\")\n } else if chars.len() > 4 {\n let prefix: String = chars.iter().take(4).collect();\n format!(\"{prefix}...\")\n } else {\n \"****\".to_string()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"Z_AI_API_KEY or ZAI_API_TOKEN\"),\n api_key_help: Some(\n \"Get your API token from z.ai Dashboard. BigModel team usage can set Z_AI_BIGMODEL_ORGANIZATION + Z_AI_BIGMODEL_PROJECT, or provider workspace_id as organization|project.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/manage-apikey/coding-plan/personal/my-plan\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Ollama,\n name: \"Ollama\",\n requires_api_key: false,\n api_key_env_var: Some(\"OLLAMA_API_KEY / OLLAMA_KEY\"),\n api_key_help: Some(\n \"Optional: use an Ollama API key for Cloud validation, or browser cookies for usage.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://ollama.com/settings\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AzureOpenAI,\n name: \"Azure OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT\",\n ),\n api_key_help: Some(\n \"Use env vars, or save JSON {api_key, endpoint, deployment, api_version}; composite api_key|endpoint|deployment[|api_version] also works.\",\n ),\n config_file_path: Some(\"~/.codexbar/api_keys.json\"),\n dashboard_url: Some(\"https://ai.azure.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kimi,\n name: \"Kimi Code API\",\n requires_api_key: true,\n api_key_env_var: Some(\"KIMI_CODE_API_KEY\"),\n api_key_help: Some(\n \"Get your Kimi Code API key from Kimi. Optional HTTPS proxy base URL: KIMI_CODE_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.moonshot.cn/console/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN] or AWS_PROFILE\",\n ),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, profile:name, or use AWS env vars/AWS CLI profiles.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"ARK_API_KEY or VOLCENGINE_ACCESS_KEY_ID + VOLCENGINE_SECRET_ACCESS_KEY\",\n ),\n api_key_help: Some(\n \"Use ARK_API_KEY for chat probe fallback, or paste Coding Plan credentials as access_key|secret_key|region (region defaults to cn-beijing).\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Chutes,\n name: \"Chutes\",\n requires_api_key: true,\n api_key_env_var: Some(\"CHUTES_API_KEY\"),\n api_key_help: Some(\n \"Paste a Chutes API key. Optional API URL override: CHUTES_API_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://chutes.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LiteLLM,\n name: \"LiteLLM\",\n requires_api_key: true,\n api_key_env_var: Some(\"LITELLM_API_KEY + LITELLM_BASE_URL\"),\n api_key_help: Some(\n \"Paste a LiteLLM key and set the base URL in provider extras or LITELLM_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Poe,\n name: \"Poe\",\n requires_api_key: true,\n api_key_env_var: Some(\"POE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Poe API settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://poe.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Devin,\n name: \"Devin\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEVIN_BEARER_TOKEN + DEVIN_ORG\"),\n api_key_help: Some(\n \"Paste a Devin bearer token and set the organization in provider extras or DEVIN_ORG.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://app.devin.ai/settings/billing\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zed,\n name: \"Zed\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZED_CREDENTIALS\"),\n api_key_help: Some(\n \"Paste Zed credentials as `user_id access_token`; optional API URL in provider extras.\",\n ),\n config_file_path: Some(\"~/.config/zed/settings.json\"),\n dashboard_url: Some(\"https://zed.dev/account\"),\n },\n ProviderConfigInfo {\n id: ProviderId::CrossModel,\n name: \"CrossModel\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROSSMODEL_API_KEY\"),\n api_key_help: Some(\n \"Paste a CrossModel API key. Optional API URL override: CROSSMODEL_API_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://crossmodel.ai\"),\n },\n ]\n}\n"}, "2b96b75cc9449841a52f8f32e07902c2f0115e1e": {"t": 1785757149.8842795, "n": 17325, "h": "d42cdbbf7c420ab1", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n let masked = mask_api_key(&entry.api_key);\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\nfn mask_api_key(api_key: &str) -> String {\n let chars: Vec<char> = api_key.chars().collect();\n if chars.len() > 12 {\n let prefix: String = chars.iter().take(4).collect();\n let suffix: String = chars.iter().skip(chars.len() - 4).collect();\n format!(\"{prefix}...{suffix}\")\n } else if chars.len() > 4 {\n let prefix: String = chars.iter().take(4).collect();\n format!(\"{prefix}...\")\n } else {\n \"****\".to_string()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZAI_API_TOKEN\"),\n api_key_help: Some(\"Get your API token from z.ai Dashboard → Settings\"),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Ollama,\n name: \"Ollama\",\n requires_api_key: false,\n api_key_env_var: Some(\"OLLAMA_API_KEY / OLLAMA_KEY\"),\n api_key_help: Some(\n \"Optional: use an Ollama API key for Cloud validation, or browser cookies for usage.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://ollama.com/settings\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AzureOpenAI,\n name: \"Azure OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT\",\n ),\n api_key_help: Some(\n \"Use env vars, or save JSON {api_key, endpoint, deployment, api_version}; composite api_key|endpoint|deployment[|api_version] also works.\",\n ),\n config_file_path: Some(\"~/.codexbar/api_keys.json\"),\n dashboard_url: Some(\"https://ai.azure.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kimi,\n name: \"Kimi Code API\",\n requires_api_key: true,\n api_key_env_var: Some(\"KIMI_CODE_API_KEY\"),\n api_key_help: Some(\n \"Get your Kimi Code API key from Kimi. Optional HTTPS proxy base URL: KIMI_CODE_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.moonshot.cn/console/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN] or AWS_PROFILE\",\n ),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, profile:name, or use AWS env vars/AWS CLI profiles.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\"ARK_API_KEY\"),\n api_key_help: Some(\"Get your API key from Volcengine Ark.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Chutes,\n name: \"Chutes\",\n requires_api_key: true,\n api_key_env_var: Some(\"CHUTES_API_KEY\"),\n api_key_help: Some(\n \"Paste a Chutes API key. Optional API URL override: CHUTES_API_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://chutes.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LiteLLM,\n name: \"LiteLLM\",\n requires_api_key: true,\n api_key_env_var: Some(\"LITELLM_API_KEY + LITELLM_BASE_URL\"),\n api_key_help: Some(\n \"Paste a LiteLLM key and set the base URL in provider extras or LITELLM_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Poe,\n name: \"Poe\",\n requires_api_key: true,\n api_key_env_var: Some(\"POE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Poe API settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://poe.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Devin,\n name: \"Devin\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEVIN_BEARER_TOKEN + DEVIN_ORG\"),\n api_key_help: Some(\n \"Paste a Devin bearer token and set the organization in provider extras or DEVIN_ORG.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://app.devin.ai/settings/billing\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zed,\n name: \"Zed\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZED_CREDENTIALS\"),\n api_key_help: Some(\n \"Paste Zed credentials as `user_id access_token`; optional API URL in provider extras.\",\n ),\n config_file_path: Some(\"~/.config/zed/settings.json\"),\n dashboard_url: Some(\"https://zed.dev/account\"),\n },\n ]\n}\n"}, "6312d373f9267bcd71dbfa298c30fa8632e01fce": {"t": 1785757152.5289474, "n": 17320, "h": "fd8d16bdf73fb445", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n // Mask the key for display (show first 4 and last 4 chars)\n let masked = if entry.api_key.len() > 12 {\n format!(\n \"{}...{}\",\n &entry.api_key[..4],\n &entry.api_key[entry.api_key.len() - 4..]\n )\n } else if entry.api_key.len() > 4 {\n format!(\"{}...\", &entry.api_key[..4])\n } else {\n \"****\".to_string()\n };\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZAI_API_TOKEN\"),\n api_key_help: Some(\"Get your API token from z.ai Dashboard → Settings\"),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Ollama,\n name: \"Ollama\",\n requires_api_key: false,\n api_key_env_var: Some(\"OLLAMA_API_KEY / OLLAMA_KEY\"),\n api_key_help: Some(\n \"Optional: use an Ollama API key for Cloud validation, or browser cookies for usage.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://ollama.com/settings\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AzureOpenAI,\n name: \"Azure OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT\",\n ),\n api_key_help: Some(\n \"Use env vars, or save JSON {api_key, endpoint, deployment, api_version}; composite api_key|endpoint|deployment[|api_version] also works.\",\n ),\n config_file_path: Some(\"~/.codexbar/api_keys.json\"),\n dashboard_url: Some(\"https://ai.azure.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kimi,\n name: \"Kimi Code API\",\n requires_api_key: true,\n api_key_env_var: Some(\"KIMI_CODE_API_KEY\"),\n api_key_help: Some(\n \"Get your Kimi Code API key from Kimi. Optional HTTPS proxy base URL: KIMI_CODE_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.moonshot.cn/console/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN] or AWS_PROFILE\",\n ),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, profile:name, or use AWS env vars/AWS CLI profiles.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\"ARK_API_KEY\"),\n api_key_help: Some(\"Get your API key from Volcengine Ark.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Chutes,\n name: \"Chutes\",\n requires_api_key: true,\n api_key_env_var: Some(\"CHUTES_API_KEY\"),\n api_key_help: Some(\n \"Paste a Chutes API key. Optional API URL override: CHUTES_API_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://chutes.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LiteLLM,\n name: \"LiteLLM\",\n requires_api_key: true,\n api_key_env_var: Some(\"LITELLM_API_KEY + LITELLM_BASE_URL\"),\n api_key_help: Some(\n \"Paste a LiteLLM key and set the base URL in provider extras or LITELLM_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Poe,\n name: \"Poe\",\n requires_api_key: true,\n api_key_env_var: Some(\"POE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Poe API settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://poe.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Devin,\n name: \"Devin\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEVIN_BEARER_TOKEN + DEVIN_ORG\"),\n api_key_help: Some(\n \"Paste a Devin bearer token and set the organization in provider extras or DEVIN_ORG.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://app.devin.ai/settings/billing\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zed,\n name: \"Zed\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZED_CREDENTIALS\"),\n api_key_help: Some(\n \"Paste Zed credentials as `user_id access_token`; optional API URL in provider extras.\",\n ),\n config_file_path: Some(\"~/.config/zed/settings.json\"),\n dashboard_url: Some(\"https://zed.dev/account\"),\n },\n ]\n}\n"}, "0d3ef883a3d17a4f948083482738a4d0af96dbea": {"t": 1785757153.882827, "n": 17745, "h": "bd9b0f517aae7a4d", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n // Mask the key for display (show first 4 and last 4 chars)\n let masked = if entry.api_key.len() > 12 {\n format!(\n \"{}...{}\",\n &entry.api_key[..4],\n &entry.api_key[entry.api_key.len() - 4..]\n )\n } else if entry.api_key.len() > 4 {\n format!(\"{}...\", &entry.api_key[..4])\n } else {\n \"****\".to_string()\n };\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Synthetic,\n name: \"Synthetic\",\n requires_api_key: true,\n api_key_env_var: Some(\"SYNTHETIC_API_KEY\"),\n api_key_help: Some(\"Get your API key from Synthetic → Account → API Keys\"),\n config_file_path: Some(\"~/.synthetic/config.json\"),\n dashboard_url: Some(\"https://synthetic.computer/account\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZAI_API_TOKEN\"),\n api_key_help: Some(\"Get your API token from z.ai Dashboard → Settings\"),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Ollama,\n name: \"Ollama\",\n requires_api_key: false,\n api_key_env_var: Some(\"OLLAMA_API_KEY / OLLAMA_KEY\"),\n api_key_help: Some(\n \"Optional: use an Ollama API key for Cloud validation, or browser cookies for usage.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://ollama.com/settings\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AzureOpenAI,\n name: \"Azure OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT\",\n ),\n api_key_help: Some(\n \"Use env vars, or save JSON {api_key, endpoint, deployment, api_version}; composite api_key|endpoint|deployment[|api_version] also works.\",\n ),\n config_file_path: Some(\"~/.codexbar/api_keys.json\"),\n dashboard_url: Some(\"https://ai.azure.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kimi,\n name: \"Kimi Code API\",\n requires_api_key: true,\n api_key_env_var: Some(\"KIMI_CODE_API_KEY\"),\n api_key_help: Some(\n \"Get your Kimi Code API key from Kimi. Optional HTTPS proxy base URL: KIMI_CODE_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.moonshot.cn/console/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN] or AWS_PROFILE\",\n ),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, profile:name, or use AWS env vars/AWS CLI profiles.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\"ARK_API_KEY\"),\n api_key_help: Some(\"Get your API key from Volcengine Ark.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Chutes,\n name: \"Chutes\",\n requires_api_key: true,\n api_key_env_var: Some(\"CHUTES_API_KEY\"),\n api_key_help: Some(\n \"Paste a Chutes API key. Optional API URL override: CHUTES_API_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://chutes.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LiteLLM,\n name: \"LiteLLM\",\n requires_api_key: true,\n api_key_env_var: Some(\"LITELLM_API_KEY + LITELLM_BASE_URL\"),\n api_key_help: Some(\n \"Paste a LiteLLM key and set the base URL in provider extras or LITELLM_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: None,\n },\n ProviderConfigInfo {\n id: ProviderId::Poe,\n name: \"Poe\",\n requires_api_key: true,\n api_key_env_var: Some(\"POE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Poe API settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://poe.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Devin,\n name: \"Devin\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEVIN_BEARER_TOKEN + DEVIN_ORG\"),\n api_key_help: Some(\n \"Paste a Devin bearer token and set the organization in provider extras or DEVIN_ORG.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://app.devin.ai/settings/billing\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zed,\n name: \"Zed\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZED_CREDENTIALS\"),\n api_key_help: Some(\n \"Paste Zed credentials as `user_id access_token`; optional API URL in provider extras.\",\n ),\n config_file_path: Some(\"~/.config/zed/settings.json\"),\n dashboard_url: Some(\"https://zed.dev/account\"),\n },\n ]\n}\n"}, "79dea44cb913f25d6b9bf088567a52cc3451fd3f": {"t": 1785757155.3437402, "n": 15594, "h": "a2ed4120e9e8e00a", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n // Mask the key for display (show first 4 and last 4 chars)\n let masked = if entry.api_key.len() > 12 {\n format!(\n \"{}...{}\",\n &entry.api_key[..4],\n &entry.api_key[entry.api_key.len() - 4..]\n )\n } else if entry.api_key.len() > 4 {\n format!(\"{}...\", &entry.api_key[..4])\n } else {\n \"****\".to_string()\n };\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Synthetic,\n name: \"Synthetic\",\n requires_api_key: true,\n api_key_env_var: Some(\"SYNTHETIC_API_KEY\"),\n api_key_help: Some(\"Get your API key from Synthetic → Account → API Keys\"),\n config_file_path: Some(\"~/.synthetic/config.json\"),\n dashboard_url: Some(\"https://synthetic.computer/account\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZAI_API_TOKEN\"),\n api_key_help: Some(\"Get your API token from z.ai Dashboard → Settings\"),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Ollama,\n name: \"Ollama\",\n requires_api_key: false,\n api_key_env_var: Some(\"OLLAMA_API_KEY / OLLAMA_KEY\"),\n api_key_help: Some(\n \"Optional: use an Ollama API key for Cloud validation, or browser cookies for usage.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://ollama.com/settings\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AzureOpenAI,\n name: \"Azure OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT\",\n ),\n api_key_help: Some(\n \"Use env vars, or save JSON {api_key, endpoint, deployment, api_version}; composite api_key|endpoint|deployment[|api_version] also works.\",\n ),\n config_file_path: Some(\"~/.codexbar/api_keys.json\"),\n dashboard_url: Some(\"https://ai.azure.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kimi,\n name: \"Kimi Code API\",\n requires_api_key: true,\n api_key_env_var: Some(\"KIMI_CODE_API_KEY\"),\n api_key_help: Some(\n \"Get your Kimi Code API key from Kimi. Optional HTTPS proxy base URL: KIMI_CODE_BASE_URL.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.moonshot.cn/console/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN] or AWS_PROFILE\",\n ),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, profile:name, or use AWS env vars/AWS CLI profiles.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\"ARK_API_KEY\"),\n api_key_help: Some(\"Get your API key from Volcengine Ark.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ]\n}\n"}, "f001ae23ae0ae249dfc7b35d5d75a09d480d6ed2": {"t": 1785757156.9945087, "n": 15120, "h": "f424d4e665c6abe0", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n // Mask the key for display (show first 4 and last 4 chars)\n let masked = if entry.api_key.len() > 12 {\n format!(\n \"{}...{}\",\n &entry.api_key[..4],\n &entry.api_key[entry.api_key.len() - 4..]\n )\n } else if entry.api_key.len() > 4 {\n format!(\"{}...\", &entry.api_key[..4])\n } else {\n \"****\".to_string()\n };\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Synthetic,\n name: \"Synthetic\",\n requires_api_key: true,\n api_key_env_var: Some(\"SYNTHETIC_API_KEY\"),\n api_key_help: Some(\"Get your API key from Synthetic → Account → API Keys\"),\n config_file_path: Some(\"~/.synthetic/config.json\"),\n dashboard_url: Some(\"https://synthetic.computer/account\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZAI_API_TOKEN\"),\n api_key_help: Some(\"Get your API token from z.ai Dashboard → Settings\"),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Ollama,\n name: \"Ollama\",\n requires_api_key: false,\n api_key_env_var: Some(\"OLLAMA_API_KEY / OLLAMA_KEY\"),\n api_key_help: Some(\n \"Optional: use an Ollama API key for Cloud validation, or browser cookies for usage.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://ollama.com/settings\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AzureOpenAI,\n name: \"Azure OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT\",\n ),\n api_key_help: Some(\n \"Use env vars, or save JSON {api_key, endpoint, deployment, api_version}; composite api_key|endpoint|deployment[|api_version] also works.\",\n ),\n config_file_path: Some(\"~/.codexbar/api_keys.json\"),\n dashboard_url: Some(\"https://ai.azure.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN] or AWS_PROFILE\",\n ),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, profile:name, or use AWS env vars/AWS CLI profiles.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\"ARK_API_KEY\"),\n api_key_help: Some(\"Get your API key from Volcengine Ark.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ]\n}\n"}, "0b1582d8f62b8a3b8740f42078dd3dfeee6e3cd3": {"t": 1785757158.5353673, "n": 15043, "h": "67758103987a5905", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n // Mask the key for display (show first 4 and last 4 chars)\n let masked = if entry.api_key.len() > 12 {\n format!(\n \"{}...{}\",\n &entry.api_key[..4],\n &entry.api_key[entry.api_key.len() - 4..]\n )\n } else if entry.api_key.len() > 4 {\n format!(\"{}...\", &entry.api_key[..4])\n } else {\n \"****\".to_string()\n };\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Synthetic,\n name: \"Synthetic\",\n requires_api_key: true,\n api_key_env_var: Some(\"SYNTHETIC_API_KEY\"),\n api_key_help: Some(\"Get your API key from Synthetic → Account → API Keys\"),\n config_file_path: Some(\"~/.synthetic/config.json\"),\n dashboard_url: Some(\"https://synthetic.computer/account\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZAI_API_TOKEN\"),\n api_key_help: Some(\"Get your API token from z.ai Dashboard → Settings\"),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Ollama,\n name: \"Ollama\",\n requires_api_key: false,\n api_key_env_var: Some(\"OLLAMA_API_KEY / OLLAMA_KEY\"),\n api_key_help: Some(\n \"Optional: use an Ollama API key for Cloud validation, or browser cookies for usage.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://ollama.com/settings\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AzureOpenAI,\n name: \"Azure OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT\",\n ),\n api_key_help: Some(\n \"Use env vars, or save JSON {api_key, endpoint, deployment, api_version}; composite api_key|endpoint|deployment[|api_version] also works.\",\n ),\n config_file_path: Some(\"~/.codexbar/api_keys.json\"),\n dashboard_url: Some(\"https://ai.azure.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN]\"),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, or use AWS env vars.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\"ARK_API_KEY\"),\n api_key_help: Some(\"Get your API key from Volcengine Ark.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ]\n}\n"}, "60427c2e09c72bd64f9d9cc4ca506e645df32881": {"t": 1785757160.0663733, "n": 15502, "h": "6ae4fd6a4b963625", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n // Mask the key for display (show first 4 and last 4 chars)\n let masked = if entry.api_key.len() > 12 {\n format!(\n \"{}...{}\",\n &entry.api_key[..4],\n &entry.api_key[entry.api_key.len() - 4..]\n )\n } else if entry.api_key.len() > 4 {\n format!(\"{}...\", &entry.api_key[..4])\n } else {\n \"****\".to_string()\n };\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Synthetic,\n name: \"Synthetic\",\n requires_api_key: true,\n api_key_env_var: Some(\"SYNTHETIC_API_KEY\"),\n api_key_help: Some(\"Get your API key from Synthetic → Account → API Keys\"),\n config_file_path: Some(\"~/.synthetic/config.json\"),\n dashboard_url: Some(\"https://synthetic.computer/account\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZAI_API_TOKEN\"),\n api_key_help: Some(\"Get your API token from z.ai Dashboard → Settings\"),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Ollama,\n name: \"Ollama\",\n requires_api_key: false,\n api_key_env_var: Some(\"OLLAMA_API_KEY / OLLAMA_KEY\"),\n api_key_help: Some(\n \"Optional: use an Ollama API key for Cloud validation, or browser cookies for usage.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://ollama.com/settings\"),\n },\n ProviderConfigInfo {\n id: ProviderId::AzureOpenAI,\n name: \"Azure OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\n \"AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT\",\n ),\n api_key_help: Some(\n \"Use env vars, or save JSON {api_key, endpoint, deployment, api_version}; composite api_key|endpoint|deployment[|api_version] also works.\",\n ),\n config_file_path: Some(\"~/.codexbar/api_keys.json\"),\n dashboard_url: Some(\"https://ai.azure.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::T3Chat,\n name: \"T3 Chat\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\n \"Uses T3 Chat browser cookies. Paste a full browser cURL if cookie-only refreshes hit a Vercel challenge.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://t3.chat/settings/customization\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN]\"),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, or use AWS env vars.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\"ARK_API_KEY\"),\n api_key_help: Some(\"Get your API key from Volcengine Ark.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ]\n}\n"}, "be7282ab98039b9cc2ea2f33b1ec6774830365f5": {"t": 1785757161.2687237, "n": 13970, "h": "6bdbe256cf8c1b4d", "c": "use super::*;\n\n/// API key storage for providers that need tokens\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct ApiKeys {\n /// Provider ID -> API key mapping\n pub keys: HashMap<String, ApiKeyEntry>,\n}\n\n/// A single API key entry\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ApiKeyEntry {\n pub api_key: String,\n pub saved_at: String,\n /// Optional label for the key (e.g., \"Personal\", \"Work\")\n #[serde(default)]\n pub label: Option<String>,\n}\n\nimpl ApiKeys {\n /// Get the API keys file path\n pub fn keys_path() -> Option<PathBuf> {\n dirs::config_dir().map(|p| p.join(\"CodexBar\").join(\"api_keys.json\"))\n }\n\n /// Load API keys from disk\n pub fn load() -> Self {\n if let Some(path) = Self::keys_path()\n && path.exists()\n && let Ok(content) = crate::secure_file::read_string(&path)\n {\n return serde_json::from_str(&content).unwrap_or_default();\n }\n Self::default()\n }\n\n /// Save API keys to disk\n pub fn save(&self) -> anyhow::Result<()> {\n let path = Self::keys_path()\n .ok_or_else(|| anyhow::anyhow!(\"Could not determine API keys path\"))?;\n\n if let Some(parent) = path.parent() {\n std::fs::create_dir_all(parent)?;\n }\n\n let json = serde_json::to_string_pretty(self)?;\n crate::secure_file::write_string(&path, &json)?;\n\n Ok(())\n }\n\n /// Get API key for a provider\n pub fn get(&self, provider_id: &str) -> Option<&str> {\n self.keys.get(provider_id).map(|e| e.api_key.as_str())\n }\n\n /// Set API key for a provider\n pub fn set(&mut self, provider_id: &str, api_key: &str, label: Option<&str>) {\n let now = chrono::Utc::now().format(\"%Y-%m-%d %H:%M\").to_string();\n self.keys.insert(\n provider_id.to_string(),\n ApiKeyEntry {\n api_key: api_key.to_string(),\n saved_at: now,\n label: label.map(|s| s.to_string()),\n },\n );\n }\n\n /// Remove API key for a provider\n pub fn remove(&mut self, provider_id: &str) {\n self.keys.remove(provider_id);\n }\n\n /// Check if a provider has an API key configured\n pub fn has_key(&self, provider_id: &str) -> bool {\n self.keys\n .get(provider_id)\n .map(|e| !e.api_key.is_empty())\n .unwrap_or(false)\n }\n\n /// Get all saved API keys for UI display (with masked values)\n pub fn get_all_for_display(&self) -> Vec<SavedApiKeyInfo> {\n self.keys\n .iter()\n .map(|(id, entry)| {\n let provider_name = ProviderId::from_cli_name(id)\n .map(|p| p.display_name().to_string())\n .unwrap_or_else(|| id.clone());\n\n // Mask the key for display (show first 4 and last 4 chars)\n let masked = if entry.api_key.len() > 12 {\n format!(\n \"{}...{}\",\n &entry.api_key[..4],\n &entry.api_key[entry.api_key.len() - 4..]\n )\n } else if entry.api_key.len() > 4 {\n format!(\"{}...\", &entry.api_key[..4])\n } else {\n \"****\".to_string()\n };\n\n SavedApiKeyInfo {\n provider_id: id.clone(),\n provider: provider_name,\n masked_key: masked,\n saved_at: entry.saved_at.clone(),\n label: entry.label.clone(),\n }\n })\n .collect()\n }\n}\n\n/// Info about a saved API key for UI display\n#[derive(Debug, Clone, Serialize)]\npub struct SavedApiKeyInfo {\n pub provider_id: String,\n pub provider: String,\n pub masked_key: String,\n pub saved_at: String,\n pub label: Option<String>,\n}\n\n/// Provider configuration info\n#[derive(Debug, Clone)]\npub struct ProviderConfigInfo {\n pub id: ProviderId,\n pub name: &'static str,\n pub requires_api_key: bool,\n pub api_key_env_var: Option<&'static str>,\n pub api_key_help: Option<&'static str>,\n pub config_file_path: Option<&'static str>,\n pub dashboard_url: Option<&'static str>,\n}\n\n/// Get configuration info for providers that need API keys\npub fn get_api_key_providers() -> Vec<ProviderConfigInfo> {\n vec![\n ProviderConfigInfo {\n id: ProviderId::Alibaba,\n name: \"Alibaba Coding Plan\",\n requires_api_key: true,\n api_key_env_var: Some(\"ALIBABA_CODING_PLAN_API_KEY\"),\n api_key_help: Some(\"Get your Coding Plan API key from Alibaba Model Studio / Bailian\"),\n config_file_path: Some(\"~/.codexbar/config.json\"),\n dashboard_url: Some(\n \"https://modelstudio.console.alibabacloud.com/ap-southeast-1/?tab=coding-plan#/efm/detail\",\n ),\n },\n ProviderConfigInfo {\n id: ProviderId::Amp,\n name: \"Amp (Sourcegraph)\",\n requires_api_key: true,\n api_key_env_var: Some(\"SRC_ACCESS_TOKEN\"),\n api_key_help: Some(\"Get your token from Sourcegraph → Settings → Access Tokens\"),\n config_file_path: Some(\"~/.amp/config.json\"),\n dashboard_url: Some(\"https://sourcegraph.com/cody/manage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Synthetic,\n name: \"Synthetic\",\n requires_api_key: true,\n api_key_env_var: Some(\"SYNTHETIC_API_KEY\"),\n api_key_help: Some(\"Get your API key from Synthetic → Account → API Keys\"),\n config_file_path: Some(\"~/.synthetic/config.json\"),\n dashboard_url: Some(\"https://synthetic.computer/account\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Copilot,\n name: \"GitHub Copilot (legacy token)\",\n requires_api_key: true,\n api_key_env_var: Some(\"GITHUB_TOKEN\"),\n api_key_help: Some(\n \"Optional fallback. Prefer Providers → Copilot → Sign in with GitHub.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://github.com/settings/copilot\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Zai,\n name: \"z.ai\",\n requires_api_key: true,\n api_key_env_var: Some(\"ZAI_API_TOKEN\"),\n api_key_help: Some(\"Get your API token from z.ai Dashboard → Settings\"),\n config_file_path: None,\n dashboard_url: Some(\"https://z.ai/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Warp,\n name: \"Warp\",\n requires_api_key: true,\n api_key_env_var: Some(\"WARP_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Warp → Settings → API Keys (docs.warp.dev/reference/cli/api-keys)\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://docs.warp.dev/reference/cli/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenRouter,\n name: \"OpenRouter\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENROUTER_API_KEY\"),\n api_key_help: Some(\"Get your API key from openrouter.ai/settings/keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://openrouter.ai/settings/credits\"),\n },\n ProviderConfigInfo {\n id: ProviderId::NanoGPT,\n name: \"NanoGPT\",\n requires_api_key: true,\n api_key_env_var: Some(\"NANOGPT_API_KEY\"),\n api_key_help: Some(\"Get your API key from nano-gpt.com/api\"),\n config_file_path: None,\n dashboard_url: Some(\"https://nano-gpt.com/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Infini,\n name: \"Infini AI\",\n requires_api_key: true,\n api_key_env_var: Some(\"INFINI_API_KEY\"),\n api_key_help: Some(\"Get your API key from Infini Cloud → Settings → API Keys\"),\n config_file_path: None,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Kilo,\n name: \"Kilo\",\n requires_api_key: true,\n api_key_env_var: Some(\"KILO_API_KEY\"),\n api_key_help: Some(\"Get your API key from Kilo, or sign in with Kilo CLI.\"),\n config_file_path: Some(\"~/.local/share/kilo/auth.json\"),\n dashboard_url: Some(\"https://app.kilo.ai/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Bedrock,\n name: \"AWS Bedrock\",\n requires_api_key: true,\n api_key_env_var: Some(\"AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY[:AWS_SESSION_TOKEN]\"),\n api_key_help: Some(\n \"Paste access_key:secret_key[:session_token], JSON credentials, or use AWS env vars.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://console.aws.amazon.com/bedrock\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Codebuff,\n name: \"Codebuff\",\n requires_api_key: true,\n api_key_env_var: Some(\"CODEBUFF_API_KEY\"),\n api_key_help: Some(\n \"Get your API key from Codebuff, or sign in with Codebuff/Manicode.\",\n ),\n config_file_path: Some(\"~/.config/manicode/credentials.json\"),\n dashboard_url: Some(\"https://www.codebuff.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::DeepSeek,\n name: \"DeepSeek\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPSEEK_API_KEY\"),\n api_key_help: Some(\"Get your API key from platform.deepseek.com.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.deepseek.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Doubao,\n name: \"Doubao / Volcengine Ark\",\n requires_api_key: true,\n api_key_env_var: Some(\"ARK_API_KEY\"),\n api_key_help: Some(\"Get your API key from Volcengine Ark.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.volcengine.com/ark/region:ark+cn-beijing/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Crof,\n name: \"Crof\",\n requires_api_key: true,\n api_key_env_var: Some(\"CROF_API_KEY\"),\n api_key_help: Some(\"Get your API key from Crof.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://crof.ai\"),\n },\n ProviderConfigInfo {\n id: ProviderId::StepFun,\n name: \"StepFun\",\n requires_api_key: true,\n api_key_env_var: Some(\"STEPFUN_OASIS_TOKEN\"),\n api_key_help: Some(\"Paste an existing Oasis-Token from StepFun login.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.stepfun.com/dashboard\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Venice,\n name: \"Venice\",\n requires_api_key: true,\n api_key_env_var: Some(\"VENICE_API_KEY\"),\n api_key_help: Some(\"Get your API key from Venice settings.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://venice.ai/settings/api\"),\n },\n ProviderConfigInfo {\n id: ProviderId::OpenAIApi,\n name: \"OpenAI\",\n requires_api_key: true,\n api_key_env_var: Some(\"OPENAI_ADMIN_KEY / OPENAI_API_KEY\"),\n api_key_help: Some(\n \"Use an OpenAI Admin API key for usage, or a platform key for legacy billing balance.\",\n ),\n config_file_path: None,\n dashboard_url: Some(\"https://platform.openai.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Grok,\n name: \"Grok\",\n requires_api_key: false,\n api_key_env_var: None,\n api_key_help: Some(\"Uses Grok browser cookies or ~/.grok/auth.json.\"),\n config_file_path: Some(\"~/.grok/auth.json\"),\n dashboard_url: Some(\"https://grok.com/settings/subscription\"),\n },\n ProviderConfigInfo {\n id: ProviderId::ElevenLabs,\n name: \"ElevenLabs\",\n requires_api_key: true,\n api_key_env_var: Some(\"ELEVENLABS_API_KEY\"),\n api_key_help: Some(\"Get your API key from ElevenLabs Settings > API Keys.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://elevenlabs.io/app/settings/api-keys\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Deepgram,\n name: \"Deepgram\",\n requires_api_key: true,\n api_key_env_var: Some(\"DEEPGRAM_API_KEY\"),\n api_key_help: Some(\"Use a Deepgram API key with Management API access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.deepgram.com/usage\"),\n },\n ProviderConfigInfo {\n id: ProviderId::Groq,\n name: \"Groq\",\n requires_api_key: true,\n api_key_env_var: Some(\"GROQ_API_KEY\"),\n api_key_help: Some(\"Groq metrics require Enterprise Prometheus metrics access.\"),\n config_file_path: None,\n dashboard_url: Some(\"https://console.groq.com/settings/metrics\"),\n },\n ProviderConfigInfo {\n id: ProviderId::LLMProxy,\n name: \"LLM Proxy\",\n requires_api_key: true,\n api_key_env_var: Some(\"LLM_PROXY_API_KEY + LLM_PROXY_BASE_URL\"),\n api_key_help: Some(\"Set an LLM Proxy API key and base URL for quota-stats.\"),\n config_file_path: None,\n dashboard_url: None,\n },\n ]\n}\n"}}, "rust/src/providers/infini.rs": {"3c6f3c3b6ef1dabfb3daa23538c62af10aebebe4": {"t": 1785595523.9990776, "n": 12202, "h": "0e597ffaf416b5bb", "c": "//! Infini AI Coding Plan Provider\n\nuse async_trait::async_trait;\nuse reqwest::Client;\nuse serde::{Deserialize, Serialize};\nuse thiserror::Error;\n\nuse crate::core::{\n FetchContext, Provider, ProviderError, ProviderFetchResult, ProviderId, ProviderMetadata,\n RateWindow, SourceMode, UsageSnapshot,\n};\n\n/// Infini AI Coding Plan 用量数据\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct InfiniUsage {\n #[serde(rename = \"5_hour\")]\n pub five_hour: UsagePeriod,\n #[serde(rename = \"7_day\")]\n pub seven_day: UsagePeriod,\n #[serde(rename = \"30_day\")]\n pub thirty_day: UsagePeriod,\n}\n\n/// 单个时间周期的用量数据\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct UsagePeriod {\n pub quota: u64,\n pub used: u64,\n pub remain: u64,\n}\n\n/// Infini 套餐类型\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum PlanType {\n Lite,\n Pro,\n Unknown,\n}\n\nimpl InfiniUsage {\n /// 根据配额判断套餐类型\n pub fn plan_type(&self) -> PlanType {\n match self.five_hour.quota {\n 1000 => PlanType::Lite,\n 5000 => PlanType::Pro,\n _ => PlanType::Unknown,\n }\n }\n\n /// 5小时周期使用百分比\n pub fn five_hour_percentage(&self) -> f64 {\n if self.five_hour.quota == 0 {\n return 0.0;\n }\n (self.five_hour.used as f64 / self.five_hour.quota as f64) * 100.0\n }\n\n /// 7天周期使用百分比\n pub fn seven_day_percentage(&self) -> f64 {\n if self.seven_day.quota == 0 {\n return 0.0;\n }\n (self.seven_day.used as f64 / self.seven_day.quota as f64) * 100.0\n }\n\n /// 30天周期使用百分比\n pub fn thirty_day_percentage(&self) -> f64 {\n if self.thirty_day.quota == 0 {\n return 0.0;\n }\n (self.thirty_day.used as f64 / self.thirty_day.quota as f64) * 100.0\n }\n}\n\n/// Infini API 客户端\n#[derive(Debug, Clone)]\npub struct InfiniClient {\n api_key: String,\n base_url: String,\n client: Client,\n}\n\n/// Infini API 错误类型\n#[derive(Debug, Error)]\npub enum InfiniError {\n #[error(\"HTTP request failed: {0}\")]\n HttpError(#[from] reqwest::Error),\n\n #[error(\"Unauthorized: invalid API key\")]\n Unauthorized,\n\n #[error(\"Rate limited: {0}\")]\n RateLimited(String),\n\n #[error(\"Server error: {0}\")]\n ServerError(String),\n\n #[error(\"Parse error: {0}\")]\n ParseError(String),\n}\n\nimpl InfiniClient {\n pub const DEFAULT_BASE_URL: &'static str = \"https://cloud.infini-ai.com\";\n\n pub fn new(api_key: String) -> Self {\n Self {\n api_key,\n base_url: Self::DEFAULT_BASE_URL.to_string(),\n client: Client::new(),\n }\n }\n\n pub fn with_base_url(mut self, base_url: String) -> Self {\n self.base_url = base_url;\n self\n }\n\n /// Get the configured base URL\n pub fn base_url(&self) -> &str {\n &self.base_url\n }\n\n pub async fn fetch_usage(&self) -> Result<InfiniUsage, InfiniError> {\n let url = format!(\"{}/maas/coding/usage\", self.base_url);\n\n let response = self\n .client\n .get(&url)\n .header(\"Authorization\", format!(\"Bearer {}\", self.api_key))\n .header(\"Content-Type\", \"application/json\")\n .send()\n .await?;\n\n let status = response.status();\n\n match status.as_u16() {\n 200 => {\n let text = response\n .text()\n .await\n .map_err(|e| InfiniError::ParseError(e.to_string()))?;\n serde_json::from_str(&text)\n .map_err(|e| InfiniError::ParseError(format!(\"{}: {}\", e, text)))\n }\n 401 => Err(InfiniError::Unauthorized),\n 429 => {\n let body = response.text().await.unwrap_or_default();\n Err(InfiniError::RateLimited(body))\n }\n 500..=599 => {\n let body = response.text().await.unwrap_or_default();\n Err(InfiniError::ServerError(body))\n }\n _ => Err(InfiniError::HttpError(\n response.error_for_status().unwrap_err(),\n )),\n }\n }\n}\n\n#[cfg(test)]\n#[allow(clippy::items_after_test_module)]\nmod tests {\n use super::*;\n\n #[test]\n fn test_usage_period_deserialization() {\n let json = r#\"{\"quota\": 5000, \"used\": 1000, \"remain\": 4000}\"#;\n let period: UsagePeriod = serde_json::from_str(json).unwrap();\n assert_eq!(period.quota, 5000);\n assert_eq!(period.used, 1000);\n assert_eq!(period.remain, 4000);\n }\n\n #[test]\n fn test_infini_usage_deserialization() {\n let json = r#\"{\n \"5_hour\": {\"quota\": 5000, \"used\": 1000, \"remain\": 4000},\n \"7_day\": {\"quota\": 30000, \"used\": 5000, \"remain\": 25000},\n \"30_day\": {\"quota\": 60000, \"used\": 10000, \"remain\": 50000}\n }\"#;\n let usage: InfiniUsage = serde_json::from_str(json).unwrap();\n assert_eq!(usage.five_hour.quota, 5000);\n assert_eq!(usage.seven_day.used, 5000);\n assert_eq!(usage.thirty_day.remain, 50000);\n }\n\n #[test]\n fn test_plan_type_pro() {\n let usage = InfiniUsage {\n five_hour: UsagePeriod {\n quota: 5000,\n used: 1000,\n remain: 4000,\n },\n seven_day: UsagePeriod {\n quota: 30000,\n used: 5000,\n remain: 25000,\n },\n thirty_day: UsagePeriod {\n quota: 60000,\n used: 10000,\n remain: 50000,\n },\n };\n assert_eq!(usage.plan_type(), PlanType::Pro);\n }\n\n #[test]\n fn test_plan_type_lite() {\n let usage = InfiniUsage {\n five_hour: UsagePeriod {\n quota: 1000,\n used: 500,\n remain: 500,\n },\n seven_day: UsagePeriod {\n quota: 7000,\n used: 3500,\n remain: 3500,\n },\n thirty_day: UsagePeriod {\n quota: 30000,\n used: 15000,\n remain: 15000,\n },\n };\n assert_eq!(usage.plan_type(), PlanType::Lite);\n }\n\n #[test]\n fn test_percentage_calculation() {\n let usage = InfiniUsage {\n five_hour: UsagePeriod {\n quota: 5000,\n used: 2500,\n remain: 2500,\n },\n seven_day: UsagePeriod {\n quota: 30000,\n used: 15000,\n remain: 15000,\n },\n thirty_day: UsagePeriod {\n quota: 60000,\n used: 30000,\n remain: 30000,\n },\n };\n assert_eq!(usage.five_hour_percentage(), 50.0);\n assert_eq!(usage.seven_day_percentage(), 50.0);\n assert_eq!(usage.thirty_day_percentage(), 50.0);\n }\n\n #[test]\n fn test_zero_quota_percentage() {\n let usage = InfiniUsage {\n five_hour: UsagePeriod {\n quota: 0,\n used: 0,\n remain: 0,\n },\n seven_day: UsagePeriod {\n quota: 0,\n used: 0,\n remain: 0,\n },\n thirty_day: UsagePeriod {\n quota: 0,\n used: 0,\n remain: 0,\n },\n };\n assert_eq!(usage.five_hour_percentage(), 0.0);\n assert_eq!(usage.seven_day_percentage(), 0.0);\n assert_eq!(usage.thirty_day_percentage(), 0.0);\n }\n}\n\n// ==================== InfiniProvider ====================\n\n/// Infini AI Provider 实现\npub struct InfiniProvider {\n metadata: ProviderMetadata,\n client: InfiniClient,\n}\n\nimpl InfiniProvider {\n /// 创建新的 InfiniProvider\n pub fn new(api_key: String) -> Self {\n Self {\n metadata: ProviderMetadata {\n id: ProviderId::Infini,\n display_name: \"Infini\",\n session_label: \"5-Hour\",\n weekly_label: \"7-Day\",\n supports_opus: false,\n supports_credits: false,\n default_enabled: false,\n is_primary: false,\n dashboard_url: Some(\"https://cloud.infini-ai.com\"),\n status_page_url: None,\n },\n client: InfiniClient::new(api_key),\n }\n }\n\n /// 设置自定义 API 基础 URL(用于测试)\n pub fn with_base_url(mut self, base_url: String) -> Self {\n self.client = self.client.with_base_url(base_url);\n self\n }\n\n /// 从环境变量读取 API Key\n fn read_api_key() -> Option<String> {\n std::env::var(\"INFINI_API_KEY\").ok()\n }\n}\n\nimpl Default for InfiniProvider {\n fn default() -> Self {\n Self::new(String::new())\n }\n}\n\n#[async_trait]\nimpl Provider for InfiniProvider {\n fn id(&self) -> ProviderId {\n ProviderId::Infini\n }\n\n fn metadata(&self) -> &ProviderMetadata {\n &self.metadata\n }\n\n async fn fetch_usage(&self, ctx: &FetchContext) -> Result<ProviderFetchResult, ProviderError> {\n tracing::debug!(\"Fetching Infini usage\");\n\n // Determine which client to use while preserving the configured base_url\n let client = if let Some(ref api_key) = ctx.api_key {\n if api_key.is_empty() {\n return Err(ProviderError::AuthRequired);\n }\n // Use provided key but preserve the base_url from self.client\n InfiniClient::new(api_key.clone()).with_base_url(self.client.base_url().to_string())\n } else if let Some(env_key) = Self::read_api_key() {\n // Use env key but preserve the base_url from self.client\n InfiniClient::new(env_key).with_base_url(self.client.base_url().to_string())\n } else if !self.client.api_key.is_empty() {\n // Use the pre-configured client (has custom base_url if set via with_base_url)\n self.client.clone()\n } else {\n return Err(ProviderError::AuthRequired);\n };\n\n match ctx.source_mode {\n SourceMode::Auto | SourceMode::Web => {\n let usage = client.fetch_usage().await.map_err(|e| match e {\n InfiniError::Unauthorized => ProviderError::AuthRequired,\n InfiniError::RateLimited(msg) => {\n ProviderError::Other(format!(\"Rate limited: {}\", msg))\n }\n InfiniError::ServerError(msg) => {\n ProviderError::Other(format!(\"Server error: {}\", msg))\n }\n InfiniError::ParseError(msg) => ProviderError::Parse(msg),\n InfiniError::HttpError(e) => ProviderError::Network(e),\n })?;\n\n // 创建 primary rate window (5-hour)\n let primary = RateWindow::new(usage.five_hour_percentage());\n\n // 创建 secondary rate window (7-day)\n let secondary = RateWindow::new(usage.seven_day_percentage());\n\n // 创建 tertiary rate window (30-day)\n let tertiary = RateWindow::new(usage.thirty_day_percentage());\n\n // 构建使用快照\n let snapshot = UsageSnapshot::new(primary)\n .with_secondary(secondary)\n .with_tertiary(tertiary)\n .with_login_method(usage.plan_type().to_string());\n\n Ok(ProviderFetchResult::new(snapshot, \"web\"))\n }\n SourceMode::Cli => Err(ProviderError::UnsupportedSource(SourceMode::Cli)),\n SourceMode::OAuth => Err(ProviderError::UnsupportedSource(SourceMode::OAuth)),\n }\n }\n\n fn available_sources(&self) -> Vec<SourceMode> {\n vec![SourceMode::Auto, SourceMode::Web]\n }\n\n fn supports_web(&self) -> bool {\n true\n }\n\n fn supports_cli(&self) -> bool {\n false\n }\n}\n\nimpl std::fmt::Display for PlanType {\n fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n match self {\n PlanType::Lite => write!(f, \"Infini Lite\"),\n PlanType::Pro => write!(f, \"Infini Pro\"),\n PlanType::Unknown => write!(f, \"Infini\"),\n }\n }\n}\n"}}, "rust/README.md": {"3c6f3c3b6ef1dabfb3daa23538c62af10aebebe4": {"t": 1785747247.7897906, "n": 7768, "h": "e044cdbda99c9fcd", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 40 AI providers:\n - Codex, Claude, Cursor, Factory, Gemini, Copilot, Antigravity, z.ai\n - MiniMax, Kiro, Vertex AI, Augment, OpenCode, OpenCode Go, Kimi, Kimi K2\n - Amp, Warp, Ollama, OpenRouter, JetBrains AI, Alibaba\n - NanoGPT, Infini, Perplexity, Abacus AI, Mistral, Kilo, AWS Bedrock, Codebuff, DeepSeek, Windsurf\n - Manus, Xiaomi MiMo, Doubao, Command Code, Crof, StepFun, Venice, OpenAI API\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.exe`\n - Run it directly without installing.\n - Release builds statically link the WebView2 loader, so no `WebView2Loader.dll` sidecar is required.\n - Best for machines that already have the Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Build the Tauri desktop shell\ncd ../apps/desktop-tauri\nnpm install\nnpm run tauri:build\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar.exe\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run installed CLI commands like `codexbar-cli usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow, gh CLI auth, legacy token fallback |\n| Antigravity | Local language server |\n| Windsurf | Local cache |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n| OpenCode / OpenCode Go | Browser cookies |\n| Kimi / Kimi K2 | Browser cookies / API cookies |\n| Amp | Sourcegraph token |\n| Warp | API key |\n| Ollama | Browser cookies |\n| OpenRouter | API key |\n| JetBrains AI | Local IDE config |\n| Alibaba | API key / browser cookies |\n| NanoGPT | API key |\n| Infini | API key |\n| Perplexity | Browser cookies |\n| Abacus AI | Browser cookies |\n| Mistral | Browser cookies |\n| Kilo | API key / local CLI config |\n| Codebuff | API key / local Manicode config |\n| DeepSeek | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "2b96b75cc9449841a52f8f32e07902c2f0115e1e": {"t": 1785757142.1597502, "n": 7768, "h": "e044cdbda99c9fcd", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 40 AI providers:\n - Codex, Claude, Cursor, Factory, Gemini, Copilot, Antigravity, z.ai\n - MiniMax, Kiro, Vertex AI, Augment, OpenCode, OpenCode Go, Kimi, Kimi K2\n - Amp, Warp, Ollama, OpenRouter, JetBrains AI, Alibaba\n - NanoGPT, Infini, Perplexity, Abacus AI, Mistral, Kilo, AWS Bedrock, Codebuff, DeepSeek, Windsurf\n - Manus, Xiaomi MiMo, Doubao, Command Code, Crof, StepFun, Venice, OpenAI API\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.exe`\n - Run it directly without installing.\n - Release builds statically link the WebView2 loader, so no `WebView2Loader.dll` sidecar is required.\n - Best for machines that already have the Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Build the Tauri desktop shell\ncd ../apps/desktop-tauri\nnpm install\nnpm run tauri:build\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar.exe\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run installed CLI commands like `codexbar-cli usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow, gh CLI auth, legacy token fallback |\n| Antigravity | Local language server |\n| Windsurf | Local cache |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n| OpenCode / OpenCode Go | Browser cookies |\n| Kimi / Kimi K2 | Browser cookies / API cookies |\n| Amp | Sourcegraph token |\n| Warp | API key |\n| Ollama | Browser cookies |\n| OpenRouter | API key |\n| JetBrains AI | Local IDE config |\n| Alibaba | API key / browser cookies |\n| NanoGPT | API key |\n| Infini | API key |\n| Perplexity | Browser cookies |\n| Abacus AI | Browser cookies |\n| Mistral | Browser cookies |\n| Kilo | API key / local CLI config |\n| Codebuff | API key / local Manicode config |\n| DeepSeek | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "6312d373f9267bcd71dbfa298c30fa8632e01fce": {"t": 1785757143.8949587, "n": 7768, "h": "0a0d5d8eb28b38e1", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 40 AI providers:\n - Codex, Claude, Cursor, Factory, Gemini, Copilot, Antigravity, z.ai\n - MiniMax, Kiro, Vertex AI, Augment, OpenCode, OpenCode Go, Kimi, Kimi K2\n - Amp, Warp, Ollama, OpenRouter, JetBrains AI, Alibaba\n - NanoGPT, Infini, Perplexity, Abacus AI, Mistral, Kilo, AWS Bedrock, Codebuff, DeepSeek, Windsurf\n - Manus, Xiaomi MiMo, Doubao, Command Code, Crof, StepFun, Venice, OpenAI API\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.exe`\n - Run it directly without installing.\n - Release builds statically link the WebView2 loader, so no `WebView2Loader.dll` sidecar is required.\n - Best for machines that already have the Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Build the Tauri desktop shell\ncd ../apps/desktop-tauri\nnpm install\nnpm run tauri:build\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar-desktop-tauri.exe\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow, gh CLI auth, legacy token fallback |\n| Antigravity | Local language server |\n| Windsurf | Local cache |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n| OpenCode / OpenCode Go | Browser cookies |\n| Kimi / Kimi K2 | Browser cookies / API cookies |\n| Amp | Sourcegraph token |\n| Warp | API key |\n| Ollama | Browser cookies |\n| OpenRouter | API key |\n| JetBrains AI | Local IDE config |\n| Alibaba | API key / browser cookies |\n| NanoGPT | API key |\n| Infini | API key |\n| Perplexity | Browser cookies |\n| Abacus AI | Browser cookies |\n| Mistral | Browser cookies |\n| Kilo | API key / local CLI config |\n| Codebuff | API key / local Manicode config |\n| DeepSeek | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "0a01233dd169a6c4f5cc78de34b8f8991fd4bb70": {"t": 1785757145.5133688, "n": 7803, "h": "d1b88b45dde29bbf", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 41 AI providers:\n - Codex, Claude, Cursor, Factory, Gemini, Copilot, Antigravity, z.ai\n - MiniMax, Kiro, Vertex AI, Augment, OpenCode, OpenCode Go, Kimi, Kimi K2\n - Amp, Warp, Ollama, OpenRouter, Synthetic, JetBrains AI, Alibaba\n - NanoGPT, Infini, Perplexity, Abacus AI, Mistral, Kilo, AWS Bedrock, Codebuff, DeepSeek, Windsurf\n - Manus, Xiaomi MiMo, Doubao, Command Code, Crof, StepFun, Venice, OpenAI API\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.exe`\n - Run it directly without installing.\n - Release builds statically link the WebView2 loader, so no `WebView2Loader.dll` sidecar is required.\n - Best for machines that already have the Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Build the Tauri desktop shell\ncd ../apps/desktop-tauri\nnpm install\nnpm run tauri:build\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar-desktop-tauri.exe\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow, gh CLI auth, legacy token fallback |\n| Antigravity | Local language server |\n| Windsurf | Local cache |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n| OpenCode / OpenCode Go | Browser cookies |\n| Kimi / Kimi K2 | Browser cookies / API cookies |\n| Amp | Sourcegraph token |\n| Warp | API key |\n| Ollama | Browser cookies |\n| OpenRouter | API key |\n| Synthetic | API key |\n| JetBrains AI | Local IDE config |\n| Alibaba | API key / browser cookies |\n| NanoGPT | API key |\n| Infini | API key |\n| Perplexity | Browser cookies |\n| Abacus AI | Browser cookies |\n| Mistral | Browser cookies |\n| Kilo | API key / local CLI config |\n| Codebuff | API key / local Manicode config |\n| DeepSeek | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "865d0f0c7f6805959f754fa7ddbb4afdad3fc8a8": {"t": 1785757147.1398642, "n": 7767, "h": "7db794f9f56d14e4", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 41 AI providers:\n - Codex, Claude, Cursor, Factory, Gemini, Copilot, Antigravity, z.ai\n - MiniMax, Kiro, Vertex AI, Augment, OpenCode, OpenCode Go, Kimi, Kimi K2\n - Amp, Warp, Ollama, OpenRouter, Synthetic, JetBrains AI, Alibaba\n - NanoGPT, Infini, Perplexity, Abacus AI, Mistral, Kilo, AWS Bedrock, Codebuff, DeepSeek, Windsurf\n - Manus, Xiaomi MiMo, Doubao, Command Code, Crof, StepFun, Venice, OpenAI API\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.exe`\n - Run it directly without installing.\n - Release builds statically link the WebView2 loader, so no `WebView2Loader.dll` sidecar is required.\n - Best for machines that already have the Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Build the Tauri desktop shell\ncd ../apps/desktop-tauri\nnpm install\nnpm run tauri:build\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar-desktop-tauri.exe\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\n| Antigravity | Local language server |\n| Windsurf | Local cache |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n| OpenCode / OpenCode Go | Browser cookies |\n| Kimi / Kimi K2 | Browser cookies / API cookies |\n| Amp | Sourcegraph token |\n| Warp | API key |\n| Ollama | Browser cookies |\n| OpenRouter | API key |\n| Synthetic | API key |\n| JetBrains AI | Local IDE config |\n| Alibaba | API key / browser cookies |\n| NanoGPT | API key |\n| Infini | API key |\n| Perplexity | Browser cookies |\n| Abacus AI | Browser cookies |\n| Mistral | Browser cookies |\n| Kilo | API key / local CLI config |\n| Codebuff | API key / local Manicode config |\n| DeepSeek | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "ed2c878b972daefe939c897e7cfd2b5facd2bddb": {"t": 1785757148.4379802, "n": 7754, "h": "9502bfa7e6ce3c4e", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 40 AI providers:\n - Codex, Claude, Cursor, Factory, Gemini, Copilot, Antigravity, z.ai\n - MiniMax, Kiro, Vertex AI, Augment, OpenCode, OpenCode Go, Kimi, Kimi K2\n - Amp, Warp, Ollama, OpenRouter, Synthetic, JetBrains AI, Alibaba\n - NanoGPT, Infini, Perplexity, Abacus AI, Mistral, Kilo, Codebuff, DeepSeek, Windsurf\n - Manus, Xiaomi MiMo, Doubao, Command Code, Crof, StepFun, Venice, OpenAI API\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.exe`\n - Run it directly without installing.\n - Release builds statically link the WebView2 loader, so no `WebView2Loader.dll` sidecar is required.\n - Best for machines that already have the Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Build the Tauri desktop shell\ncd ../apps/desktop-tauri\nnpm install\nnpm run tauri:build\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar-desktop-tauri.exe\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\n| Antigravity | Local language server |\n| Windsurf | Local cache |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n| OpenCode / OpenCode Go | Browser cookies |\n| Kimi / Kimi K2 | Browser cookies / API cookies |\n| Amp | Sourcegraph token |\n| Warp | API key |\n| Ollama | Browser cookies |\n| OpenRouter | API key |\n| Synthetic | API key |\n| JetBrains AI | Local IDE config |\n| Alibaba | API key / browser cookies |\n| NanoGPT | API key |\n| Infini | API key |\n| Perplexity | Browser cookies |\n| Abacus AI | Browser cookies |\n| Mistral | Browser cookies |\n| Kilo | API key / local CLI config |\n| Codebuff | API key / local Manicode config |\n| DeepSeek | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "89086d5ebef3bd969f10078f76da6872b48d485e": {"t": 1785757150.780559, "n": 7683, "h": "f4de8afaa3cfc7aa", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 40 AI providers:\n - Codex, Claude, Cursor, Factory, Gemini, Copilot, Antigravity, z.ai\n - MiniMax, Kiro, Vertex AI, Augment, OpenCode, OpenCode Go, Kimi, Kimi K2\n - Amp, Warp, Ollama, OpenRouter, Synthetic, JetBrains AI, Alibaba\n - NanoGPT, Infini, Perplexity, Abacus AI, Mistral, Kilo, Codebuff, DeepSeek, Windsurf\n - Manus, Xiaomi MiMo, Doubao, Command Code, Crof, StepFun, Venice, OpenAI API\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.zip`\n - Extract the zip and keep `codexbar.exe` beside `WebView2Loader.dll`.\n - Best for machines that already have the Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Build the Tauri desktop shell\ncd ../apps/desktop-tauri\nnpm install\nnpm run tauri:build\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar-desktop-tauri.exe\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\n| Antigravity | Local language server |\n| Windsurf | Local cache |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n| OpenCode / OpenCode Go | Browser cookies |\n| Kimi / Kimi K2 | Browser cookies / API cookies |\n| Amp | Sourcegraph token |\n| Warp | API key |\n| Ollama | Browser cookies |\n| OpenRouter | API key |\n| Synthetic | API key |\n| JetBrains AI | Local IDE config |\n| Alibaba | API key / browser cookies |\n| NanoGPT | API key |\n| Infini | API key |\n| Perplexity | Browser cookies |\n| Abacus AI | Browser cookies |\n| Mistral | Browser cookies |\n| Kilo | API key / local CLI config |\n| Codebuff | API key / local Manicode config |\n| DeepSeek | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "d0804935b85b12e9998f793e71ff02cd09df94fe": {"t": 1785757152.1784124, "n": 7603, "h": "310facdd486e12af", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 32 AI providers:\n - Codex, Claude, Cursor, Factory, Gemini, Copilot, Antigravity, z.ai\n - MiniMax, Kiro, Vertex AI, Augment, OpenCode, OpenCode Go, Kimi, Kimi K2\n - Amp, Warp, Ollama, OpenRouter, Synthetic, JetBrains AI, Alibaba\n - NanoGPT, Infini, Perplexity, Abacus AI, Mistral, Kilo, Codebuff, DeepSeek, Windsurf\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.zip`\n - Extract the zip and keep `codexbar.exe` beside `WebView2Loader.dll`.\n - Best for machines that already have the Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Build the Tauri desktop shell\ncd ../apps/desktop-tauri\nnpm install\nnpm run tauri:build\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar-desktop-tauri.exe\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\n| Antigravity | Local language server |\n| Windsurf | Local cache |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n| OpenCode / OpenCode Go | Browser cookies |\n| Kimi / Kimi K2 | Browser cookies / API cookies |\n| Amp | Sourcegraph token |\n| Warp | API key |\n| Ollama | Browser cookies |\n| OpenRouter | API key |\n| Synthetic | API key |\n| JetBrains AI | Local IDE config |\n| Alibaba | API key / browser cookies |\n| NanoGPT | API key |\n| Infini | API key |\n| Perplexity | Browser cookies |\n| Abacus AI | Browser cookies |\n| Mistral | Browser cookies |\n| Kilo | API key / local CLI config |\n| Codebuff | API key / local Manicode config |\n| DeepSeek | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "2a0fd8a4f441b200e8ce73923a91be9a8b422b7c": {"t": 1785757153.6581163, "n": 7531, "h": "48c66165ba0d6a44", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 32 AI providers:\n - Codex, Claude, Cursor, Factory, Gemini, Copilot, Antigravity, z.ai\n - MiniMax, Kiro, Vertex AI, Augment, OpenCode, OpenCode Go, Kimi, Kimi K2\n - Amp, Warp, Ollama, OpenRouter, Synthetic, JetBrains AI, Alibaba\n - NanoGPT, Infini, Perplexity, Abacus AI, Mistral, Kilo, Codebuff, DeepSeek, Windsurf\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.zip`\n - Extract the zip and keep `codexbar.exe` beside `WebView2Loader.dll`.\n - Best for machines that already have the Microsoft Visual C++ runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Build the Tauri desktop shell\ncd ../apps/desktop-tauri\nnpm install\nnpm run tauri:build\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar-desktop-tauri.exe\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\n| Antigravity | Local language server |\n| Windsurf | Local cache |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n| OpenCode / OpenCode Go | Browser cookies |\n| Kimi / Kimi K2 | Browser cookies / API cookies |\n| Amp | Sourcegraph token |\n| Warp | API key |\n| Ollama | Browser cookies |\n| OpenRouter | API key |\n| Synthetic | API key |\n| JetBrains AI | Local IDE config |\n| Alibaba | API key / browser cookies |\n| NanoGPT | API key |\n| Infini | API key |\n| Perplexity | Browser cookies |\n| Abacus AI | Browser cookies |\n| Mistral | Browser cookies |\n| Kilo | API key / local CLI config |\n| Codebuff | API key / local Manicode config |\n| DeepSeek | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "d9dd80db7352fe71fb9188d0caf985ad0c683386": {"t": 1785757155.19804, "n": 6909, "h": "ffa77a14ea37d138", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.zip`\n - Extract the zip and keep `codexbar.exe` beside `WebView2Loader.dll`.\n - Best for machines that already have the Microsoft Visual C++ runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\n| MiniMax | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "4d15857f8a36750b6313486d8dcd7479f2ae6858": {"t": 1785757157.0298853, "n": 6754, "h": "a1835f279f77aeb7", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.zip`\n - Extract the zip and keep `codexbar.exe` beside `WebView2Loader.dll`.\n - Best for machines that already have the Microsoft Visual C++ runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\r\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\n| MiniMax | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "2b9ade557f6b16cd677d5ab8a899e37ee3f3fd3c": {"t": 1785757158.3654191, "n": 6662, "h": "acdd150c714cd26e", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime on clean Windows machines before launching CodexBar.\n- Portable: `codexbar.exe`\n - Best for machines that already have the Microsoft Visual C++ runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\r\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\n| MiniMax | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "653faa9e9783bc20cb06097cdda0adca8c03ad16": {"t": 1785757159.9507802, "n": 6481, "h": "8399f3e600a7a71a", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime on clean Windows machines before launching CodexBar.\n- Portable: `codexbar.exe`\n - Best for machines that already have the Microsoft Visual C++ runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\r\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\n| MiniMax | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\r\n\r\n```powershell\ncargo test\n```\n\nOn Linux hosts, override the repo's default Windows target:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "e321861cecdb34428d4ce7918da105dd085a5f75": {"t": 1785757161.1757333, "n": 5791, "h": "d857b75b882b20e1", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime on clean Windows machines before launching CodexBar.\n- Portable: `codexbar.exe`\n - Best for machines that already have the Microsoft Visual C++ runtime installed.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\r\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\r\n|----------|-------------|\r\n| Claude | Browser cookies (Chrome/Edge), OAuth |\r\n| Codex | Local CLI, Browser cookies |\r\n| Cursor | Browser cookies |\r\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\r\n| MiniMax | API key |\r\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\r\n\r\n```powershell\r\ncargo test\r\n```\r\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "d25d621c3987d8d7136c7693739feca1992334c3": {"t": 1785757162.6878688, "n": 5580, "h": "aca7a98d6c571acc", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n- Portable: `codexbar.exe`\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\r\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\r\n|----------|-------------|\r\n| Claude | Browser cookies (Chrome/Edge), OAuth |\r\n| Codex | Local CLI, Browser cookies |\r\n| Cursor | Browser cookies |\r\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\r\n| MiniMax | API key |\r\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\r\n\r\n```powershell\r\ncargo test\r\n```\r\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "c8d2f00c2c1e1e574f479710b9b0b5e95897e7bb": {"t": 1785757164.2160378, "n": 5409, "h": "c66a2aad832c348c", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n- Portable: `codexbar.exe`\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run CLI commands like `codexbar usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\r\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\r\n|----------|-------------|\r\n| Claude | Browser cookies (Chrome/Edge), OAuth |\r\n| Codex | Local CLI, Browser cookies |\r\n| Cursor | Browser cookies |\r\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\r\n| MiniMax | API key |\r\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\r\n\r\n```powershell\r\ncargo test\r\n```\r\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "163f8e41b87bd6674ff971e0d392abe3267210fe": {"t": 1785757165.7755015, "n": 5150, "h": "b919b0660624a48b", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n- Portable: `codexbar.exe`\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\r\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\r\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\r\n|----------|-------------|\r\n| Claude | Browser cookies (Chrome/Edge), OAuth |\r\n| Codex | Local CLI, Browser cookies |\r\n| Cursor | Browser cookies |\r\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\r\n| MiniMax | API key |\r\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\r\n\r\n```powershell\r\ncargo test\r\n```\r\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "6f8e345f98099fff382c614011a6bd7306ac8e92": {"t": 1785757167.0494964, "n": 5273, "h": "b1222fdf1974c831", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n- Portable: `codexbar.exe`\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\r\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n- On Windows, the GUI prefers the `wgpu` renderer so it can still start in RDP and VM sessions where OpenGL is unavailable\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\r\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\r\n|----------|-------------|\r\n| Claude | Browser cookies (Chrome/Edge), OAuth |\r\n| Codex | Local CLI, Browser cookies |\r\n| Cursor | Browser cookies |\r\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\r\n| MiniMax | API key |\r\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\r\n\r\n```powershell\r\ncargo test\r\n```\r\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "a2a0a55712b0206c044413ff35e1b4e117c1815f": {"t": 1785757168.3905182, "n": 5150, "h": "b919b0660624a48b", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n- Portable: `codexbar.exe`\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\r\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\r\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\r\n|----------|-------------|\r\n| Claude | Browser cookies (Chrome/Edge), OAuth |\r\n| Codex | Local CLI, Browser cookies |\r\n| Cursor | Browser cookies |\r\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\r\n| MiniMax | API key |\r\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\r\n\r\n```powershell\r\ncargo test\r\n```\r\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "d00b66452cca052d8bcb2217d2b7f08aadec3ac0": {"t": 1785757169.8520176, "n": 4976, "h": "0e45ec84139017c3", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 12 AI providers:\r\n - Claude (Anthropic)\r\n - Codex (OpenAI)\r\n - Cursor\r\n - Gemini (Google)\r\n - Copilot (GitHub)\r\n - Antigravity\r\n - Windsurf (Factory/Codeium)\r\n - Zai\r\n - Kiro (AWS)\r\n - Vertex AI (Google Cloud)\r\n - Augment\r\n - MiniMax\r\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\r\n\r\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\r\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Run the GUI (system tray)\r\n./target/release/codexbar.exe menubar\r\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\r\n\r\n```powershell\r\ncodexbar menubar\r\n```\r\n\r\nThis launches the system tray application:\r\n- Click the tray icon to show the usage panel\r\n- Use the Settings button to configure providers and refresh intervals\r\n- Use the Cookies button for manual cookie input if needed\r\n- Use the About button for version info\r\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\r\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\r\n|----------|-------------|\r\n| Claude | Browser cookies (Chrome/Edge), OAuth |\r\n| Codex | Local CLI, Browser cookies |\r\n| Cursor | Browser cookies |\r\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow |\r\n| Antigravity | Local language server |\r\n| Windsurf | Browser cookies, local config |\r\n| Zai | Local config |\r\n| Kiro | AWS credentials |\r\n| Vertex AI | gcloud OAuth |\r\n| Augment | VS Code extension |\r\n| MiniMax | API key |\r\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\r\n\r\n```powershell\r\ncargo test\r\n```\r\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}, "31cbdd2a39d9ff403210e1341c46501613681ae0": {"t": 1785757171.7993968, "n": 5295, "h": "d0efb1887fe869a6", "c": "# CodexBar for Windows\n\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\n\n\n\n## Features\n\n- **System Tray Icon** - Color-coded usage indicator with incident badges\n- **Multiple Providers** - Support for 12 AI providers:\n - Claude (Anthropic)\n - Codex (OpenAI)\n - Cursor\n - Gemini (Google)\n - Copilot (GitHub)\n - Antigravity\n - Windsurf (Factory/Codeium)\n - Zai\n - Kiro (AWS)\n - Vertex AI (Google Cloud)\n - Augment\n - MiniMax\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\n- **Status Page Polling** - Shows provider incidents with visual badges\n- **CLI Tool** - Command-line interface for scripts and automation\n\n## Installation\n\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Primary installable asset: `CodexBar-<version>-Setup.exe`\n- Optional manual asset: `codexbar.exe`\n\n### Build from Source\n\nRequirements:\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\n- Windows 10/11\n\n```powershell\n# Clone the repository\ngit clone https://github.com/Finesssee/Win-CodexBar.git\ncd Win-CodexBar/rust\n\n# Build release binaries\ncargo build --release --bins\n\n# Run the CLI\n./target/x86_64-pc-windows-gnu/release/codexbar.exe --help\n\n# Run the GUI (system tray)\n./target/x86_64-pc-windows-gnu/release/codexbar.exe menubar\n```\n\n### Build The Setup Installer Locally\n\n```bash\n./scripts/build-installer.sh\n```\n\nThis writes `target/installer/CodexBar-<version>-Setup.exe`.\n\n## Usage\n\n### GUI Mode (System Tray)\n\n```powershell\ncodexbar menubar\n```\n\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use the Settings button to configure providers and refresh intervals\n- Use the Cookies button for manual cookie input if needed\n- Use the About button for version info\n\n### CLI Mode\n\n```powershell\n# Show usage for all enabled providers\ncodexbar\n\n# Show usage for specific provider\ncodexbar -p claude\n\n# Show usage for all providers\ncodexbar -p all\n\n# Output as JSON\ncodexbar --json --pretty\n\n# Include provider status\ncodexbar --status\n\n# Show local cost usage (Claude + Codex logs)\ncodexbar cost\n\n# Enable/disable auto-start on Windows boot\ncodexbar autostart enable\ncodexbar autostart disable\ncodexbar autostart status\n```\n\n### Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| 0 | Success |\n| 1 | Unexpected failure |\n| 2 | Provider not installed |\n| 3 | Parse error |\n| 4 | Timeout |\n\n## Configuration\n\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\n\n```json\n{\n \"enabled_providers\": [\"claude\", \"codex\"],\n \"refresh_interval_secs\": 300,\n \"show_notifications\": true,\n \"high_usage_threshold\": 70.0,\n \"critical_usage_threshold\": 90.0\n}\n```\n\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\n\n## Provider Authentication\n\nEach provider has different authentication methods:\n\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\n| Copilot | GitHub device flow |\n| Antigravity | Local language server |\n| Windsurf | Browser cookies, local config |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n\n## Screenshots\n\n### System Tray\n\n\nThe tray icon color indicates overall usage:\n- Green: 0-50% used\n- Yellow: 50-80% used\n- Orange: 80-95% used\n- Red: 95-100% used\n- Gray: Unknown/loading\n\nA badge appears in the corner for status issues:\n- Yellow badge: Degraded performance\n- Red badge: Major outage\n\n### Main Panel\n\n\n### Settings\n\n\n### About\n\n\n## Development\n\n### Running Tests\n\n```powershell\ncargo test\ncargo clippy --all-targets -- -D warnings\n```\n\n### Local Release\n\n```bash\n./scripts/release-local.sh <version>\n```\n\nThis builds the Windows binaries locally, creates the Setup installer, and publishes the GitHub release with `gh`.\n\n### Project Structure\n\n```\nrust/\n├── src/\n│ ├── main.rs # Entry point\n│ ├── cli/ # CLI commands\n│ ├── core/ # Core data models\n│ ├── providers/ # Provider implementations\n│ ├── browser/ # Cookie extraction\n│ ├── tauri_app/ # Tauri GUI\n│ ├── tray/ # Tray icon types\n│ ├── settings.rs # Settings management\n│ ├── status.rs # Status page polling\n│ └── notifications.rs # Windows notifications\n├── ui/ # HTML/CSS/JS for GUI\n│ ├── index.html # Main panel\n│ ├── settings.html # Settings page\n│ ├── about.html # About dialog\n│ └── cookies.html # Cookie input\n└── Cargo.toml\n```\n\n## Credits\n\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\n\n## License\n\nMIT\n"}, "c71ca2fe566a822372a54e4e37c548d591a42e34": {"t": 1785757173.2406237, "n": 4814, "h": "6d835d04d72b8cda", "c": "# CodexBar for Windows\n\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\n\n\n\n## Features\n\n- **System Tray Icon** - Color-coded usage indicator with incident badges\n- **Multiple Providers** - Support for 12 AI providers:\n - Claude (Anthropic)\n - Codex (OpenAI)\n - Cursor\n - Gemini (Google)\n - Copilot (GitHub)\n - Antigravity\n - Windsurf (Factory/Codeium)\n - Zai\n - Kiro (AWS)\n - Vertex AI (Google Cloud)\n - Augment\n - MiniMax\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\n- **Status Page Polling** - Shows provider incidents with visual badges\n- **CLI Tool** - Command-line interface for scripts and automation\n\n## Installation\n\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n### Build from Source\n\nRequirements:\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\n- Windows 10/11\n\n```powershell\n# Clone the repository\ngit clone https://github.com/Finesssee/Win-CodexBar.git\ncd Win-CodexBar/rust\n\n# Build release version\ncargo build --release\n\n# Run the CLI\n./target/release/codexbar.exe --help\n\n# Run the GUI (system tray)\n./target/release/codexbar.exe menubar\n```\n\n## Usage\n\n### GUI Mode (System Tray)\n\n```powershell\ncodexbar menubar\n```\n\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use the Settings button to configure providers and refresh intervals\n- Use the Cookies button for manual cookie input if needed\n- Use the About button for version info\n\n### CLI Mode\n\n```powershell\n# Show usage for all enabled providers\ncodexbar\n\n# Show usage for specific provider\ncodexbar -p claude\n\n# Show usage for all providers\ncodexbar -p all\n\n# Output as JSON\ncodexbar --json --pretty\n\n# Include provider status\ncodexbar --status\n\n# Show local cost usage (Claude + Codex logs)\ncodexbar cost\n\n# Enable/disable auto-start on Windows boot\ncodexbar autostart enable\ncodexbar autostart disable\ncodexbar autostart status\n```\n\n### Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| 0 | Success |\n| 1 | Unexpected failure |\n| 2 | Provider not installed |\n| 3 | Parse error |\n| 4 | Timeout |\n\n## Configuration\n\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\n\n```json\n{\n \"enabled_providers\": [\"claude\", \"codex\"],\n \"refresh_interval_secs\": 300,\n \"show_notifications\": true,\n \"high_usage_threshold\": 70.0,\n \"critical_usage_threshold\": 90.0\n}\n```\n\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\n\n## Provider Authentication\n\nEach provider has different authentication methods:\n\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\n| Copilot | GitHub device flow |\n| Antigravity | Local language server |\n| Windsurf | Browser cookies, local config |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n\n## Screenshots\n\n### System Tray\n\n\nThe tray icon color indicates overall usage:\n- Green: 0-50% used\n- Yellow: 50-80% used\n- Orange: 80-95% used\n- Red: 95-100% used\n- Gray: Unknown/loading\n\nA badge appears in the corner for status issues:\n- Yellow badge: Degraded performance\n- Red badge: Major outage\n\n### Main Panel\n\n\n### Settings\n\n\n### About\n\n\n## Development\n\n### Running Tests\n\n```powershell\ncargo test\ncargo clippy --all-targets -- -D warnings\n```\n\n### Project Structure\n\n```\nrust/\n├── src/\n│ ├── main.rs # Entry point\n│ ├── cli/ # CLI commands\n│ ├── core/ # Core data models\n│ ├── providers/ # Provider implementations\n│ ├── browser/ # Cookie extraction\n│ ├── tauri_app/ # Tauri GUI\n│ ├── tray/ # Tray icon types\n│ ├── settings.rs # Settings management\n│ ├── status.rs # Status page polling\n│ └── notifications.rs # Windows notifications\n├── ui/ # HTML/CSS/JS for GUI\n│ ├── index.html # Main panel\n│ ├── settings.html # Settings page\n│ ├── about.html # About dialog\n│ └── cookies.html # Cookie input\n└── Cargo.toml\n```\n\n## Credits\n\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\n\n## License\n\nMIT\n"}, "5fa9bca2ea0fce41cfa4885f1fa2ac0d1d79c548": {"t": 1785757174.6957302, "n": 4772, "h": "c4fa0c34e288005d", "c": "# CodexBar for Windows\n\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\n\n\n\n## Features\n\n- **System Tray Icon** - Color-coded usage indicator with incident badges\n- **Multiple Providers** - Support for 12 AI providers:\n - Claude (Anthropic)\n - Codex (OpenAI)\n - Cursor\n - Gemini (Google)\n - Copilot (GitHub)\n - Antigravity\n - Windsurf (Factory/Codeium)\n - Zai\n - Kiro (AWS)\n - Vertex AI (Google Cloud)\n - Augment\n - MiniMax\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\n- **Status Page Polling** - Shows provider incidents with visual badges\n- **CLI Tool** - Command-line interface for scripts and automation\n\n## Installation\n\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n### Build from Source\n\nRequirements:\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\n- Windows 10/11\n\n```powershell\n# Clone the repository\ngit clone https://github.com/Finesssee/Win-CodexBar.git\ncd Win-CodexBar/rust\n\n# Build release version\ncargo build --release\n\n# Run the CLI\n./target/release/codexbar.exe --help\n\n# Run the GUI (system tray)\n./target/release/codexbar.exe menubar\n```\n\n## Usage\n\n### GUI Mode (System Tray)\n\n```powershell\ncodexbar menubar\n```\n\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use the Settings button to configure providers and refresh intervals\n- Use the Cookies button for manual cookie input if needed\n- Use the About button for version info\n\n### CLI Mode\n\n```powershell\n# Show usage for all enabled providers\ncodexbar\n\n# Show usage for specific provider\ncodexbar -p claude\n\n# Show usage for all providers\ncodexbar -p all\n\n# Output as JSON\ncodexbar --json --pretty\n\n# Include provider status\ncodexbar --status\n\n# Show local cost usage (Claude + Codex logs)\ncodexbar cost\n\n# Enable/disable auto-start on Windows boot\ncodexbar autostart enable\ncodexbar autostart disable\ncodexbar autostart status\n```\n\n### Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| 0 | Success |\n| 1 | Unexpected failure |\n| 2 | Provider not installed |\n| 3 | Parse error |\n| 4 | Timeout |\n\n## Configuration\n\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\n\n```json\n{\n \"enabled_providers\": [\"claude\", \"codex\"],\n \"refresh_interval_secs\": 300,\n \"show_notifications\": true,\n \"high_usage_threshold\": 70.0,\n \"critical_usage_threshold\": 90.0\n}\n```\n\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\n\n## Provider Authentication\n\nEach provider has different authentication methods:\n\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\n| Copilot | GitHub device flow |\n| Antigravity | Local language server |\n| Windsurf | Browser cookies, local config |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n\n## Screenshots\n\n### System Tray\n\n\nThe tray icon color indicates overall usage:\n- Green: 0-50% used\n- Yellow: 50-80% used\n- Orange: 80-95% used\n- Red: 95-100% used\n- Gray: Unknown/loading\n\nA badge appears in the corner for status issues:\n- Yellow badge: Degraded performance\n- Red badge: Major outage\n\n### Main Panel\n\n\n### Settings\n\n\n### About\n\n\n## Development\n\n### Running Tests\n\n```powershell\ncargo test\n```\n\n### Project Structure\n\n```\nrust/\n├── src/\n│ ├── main.rs # Entry point\n│ ├── cli/ # CLI commands\n│ ├── core/ # Core data models\n│ ├── providers/ # Provider implementations\n│ ├── browser/ # Cookie extraction\n│ ├── tauri_app/ # Tauri GUI\n│ ├── tray/ # Tray icon types\n│ ├── settings.rs # Settings management\n│ ├── status.rs # Status page polling\n│ └── notifications.rs # Windows notifications\n├── ui/ # HTML/CSS/JS for GUI\n│ ├── index.html # Main panel\n│ ├── settings.html # Settings page\n│ ├── about.html # About dialog\n│ └── cookies.html # Cookie input\n└── Cargo.toml\n```\n\n## Credits\n\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\n\n## License\n\nMIT\n"}, "516aed6fb529c14811181d96388a47729b4da249": {"t": 1785757176.519044, "n": 4778, "h": "58e9b4cd1f5e1595", "c": "# CodexBar for Windows\n\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\n\n\n\n## Features\n\n- **System Tray Icon** - Color-coded usage indicator with incident badges\n- **Multiple Providers** - Support for 12 AI providers:\n - Claude (Anthropic)\n - Codex (OpenAI)\n - Cursor\n - Gemini (Google)\n - Copilot (GitHub)\n - Antigravity\n - Windsurf (Factory/Codeium)\n - Zed AI\n - Kiro (AWS)\n - Vertex AI (Google Cloud)\n - Augment\n - MiniMax\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\n- **Status Page Polling** - Shows provider incidents with visual badges\n- **CLI Tool** - Command-line interface for scripts and automation\n\n## Installation\n\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n### Build from Source\n\nRequirements:\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\n- Windows 10/11\n\n```powershell\n# Clone the repository\ngit clone https://github.com/Finesssee/Win-CodexBar.git\ncd Win-CodexBar/rust\n\n# Build release version\ncargo build --release\n\n# Run the CLI\n./target/release/codexbar.exe --help\n\n# Run the GUI (system tray)\n./target/release/codexbar.exe menubar\n```\n\n## Usage\n\n### GUI Mode (System Tray)\n\n```powershell\ncodexbar menubar\n```\n\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use the Settings button to configure providers and refresh intervals\n- Use the Cookies button for manual cookie input if needed\n- Use the About button for version info\n\n### CLI Mode\n\n```powershell\n# Show usage for all enabled providers\ncodexbar\n\n# Show usage for specific provider\ncodexbar -p claude\n\n# Show usage for all providers\ncodexbar -p all\n\n# Output as JSON\ncodexbar --json --pretty\n\n# Include provider status\ncodexbar --status\n\n# Show local cost usage (Claude + Codex logs)\ncodexbar cost\n\n# Enable/disable auto-start on Windows boot\ncodexbar autostart enable\ncodexbar autostart disable\ncodexbar autostart status\n```\n\n### Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| 0 | Success |\n| 1 | Unexpected failure |\n| 2 | Provider not installed |\n| 3 | Parse error |\n| 4 | Timeout |\n\n## Configuration\n\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\n\n```json\n{\n \"enabled_providers\": [\"claude\", \"codex\"],\n \"refresh_interval_secs\": 300,\n \"show_notifications\": true,\n \"high_usage_threshold\": 70.0,\n \"critical_usage_threshold\": 90.0\n}\n```\n\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\n\n## Provider Authentication\n\nEach provider has different authentication methods:\n\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\n| Copilot | GitHub device flow |\n| Antigravity | Local language server |\n| Windsurf | Browser cookies, local config |\n| Zed AI | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n\n## Screenshots\n\n### System Tray\n\n\nThe tray icon color indicates overall usage:\n- Green: 0-50% used\n- Yellow: 50-80% used\n- Orange: 80-95% used\n- Red: 95-100% used\n- Gray: Unknown/loading\n\nA badge appears in the corner for status issues:\n- Yellow badge: Degraded performance\n- Red badge: Major outage\n\n### Main Panel\n\n\n### Settings\n\n\n### About\n\n\n## Development\n\n### Running Tests\n\n```powershell\ncargo test\n```\n\n### Project Structure\n\n```\nrust/\n├── src/\n│ ├── main.rs # Entry point\n│ ├── cli/ # CLI commands\n│ ├── core/ # Core data models\n│ ├── providers/ # Provider implementations\n│ ├── browser/ # Cookie extraction\n│ ├── tauri_app/ # Tauri GUI\n│ ├── tray/ # Tray icon types\n│ ├── settings.rs # Settings management\n│ ├── status.rs # Status page polling\n│ └── notifications.rs # Windows notifications\n├── ui/ # HTML/CSS/JS for GUI\n│ ├── index.html # Main panel\n│ ├── settings.html # Settings page\n│ ├── about.html # About dialog\n│ └── cookies.html # Cookie input\n└── Cargo.toml\n```\n\n## Credits\n\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\n\n## License\n\nMIT\n"}, "16ba797fef7a623b667b7c5977a64523cb650e46": {"t": 1785757178.139805, "n": 4774, "h": "86b952c259ccaf18", "c": "# CodexBar for Windows\n\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\n\n\n\n## Features\n\n- **System Tray Icon** - Color-coded usage indicator with incident badges\n- **Multiple Providers** - Support for 12 AI providers:\n - Claude (Anthropic)\n - Codex (OpenAI)\n - Cursor\n - Gemini (Google)\n - Copilot (GitHub)\n - Antigravity\n - Windsurf (Factory/Codeium)\n - Zed AI\n - Kiro (AWS)\n - Vertex AI (Google Cloud)\n - Augment\n - MiniMax\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\n- **Status Page Polling** - Shows provider incidents with visual badges\n- **CLI Tool** - Command-line interface for scripts and automation\n\n## Installation\n\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/example/win-codexbar/releases) page.\n\n### Build from Source\n\nRequirements:\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\n- Windows 10/11\n\n```powershell\n# Clone the repository\ngit clone https://github.com/example/win-codexbar.git\ncd win-codexbar/rust\n\n# Build release version\ncargo build --release\n\n# Run the CLI\n./target/release/codexbar.exe --help\n\n# Run the GUI (system tray)\n./target/release/codexbar.exe menubar\n```\n\n## Usage\n\n### GUI Mode (System Tray)\n\n```powershell\ncodexbar menubar\n```\n\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use the Settings button to configure providers and refresh intervals\n- Use the Cookies button for manual cookie input if needed\n- Use the About button for version info\n\n### CLI Mode\n\n```powershell\n# Show usage for all enabled providers\ncodexbar\n\n# Show usage for specific provider\ncodexbar -p claude\n\n# Show usage for all providers\ncodexbar -p all\n\n# Output as JSON\ncodexbar --json --pretty\n\n# Include provider status\ncodexbar --status\n\n# Show local cost usage (Claude + Codex logs)\ncodexbar cost\n\n# Enable/disable auto-start on Windows boot\ncodexbar autostart enable\ncodexbar autostart disable\ncodexbar autostart status\n```\n\n### Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| 0 | Success |\n| 1 | Unexpected failure |\n| 2 | Provider not installed |\n| 3 | Parse error |\n| 4 | Timeout |\n\n## Configuration\n\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\n\n```json\n{\n \"enabled_providers\": [\"claude\", \"codex\"],\n \"refresh_interval_secs\": 300,\n \"show_notifications\": true,\n \"high_usage_threshold\": 70.0,\n \"critical_usage_threshold\": 90.0\n}\n```\n\nManual cookies are stored separately in `%APPDATA%\\CodexBar\\manual_cookies.json`.\n\n## Provider Authentication\n\nEach provider has different authentication methods:\n\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\n| Copilot | GitHub device flow |\n| Antigravity | Local language server |\n| Windsurf | Browser cookies, local config |\n| Zed AI | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n\n## Screenshots\n\n### System Tray\n\n\nThe tray icon color indicates overall usage:\n- Green: 0-50% used\n- Yellow: 50-80% used\n- Orange: 80-95% used\n- Red: 95-100% used\n- Gray: Unknown/loading\n\nA badge appears in the corner for status issues:\n- Yellow badge: Degraded performance\n- Red badge: Major outage\n\n### Main Panel\n\n\n### Settings\n\n\n### About\n\n\n## Development\n\n### Running Tests\n\n```powershell\ncargo test\n```\n\n### Project Structure\n\n```\nrust/\n├── src/\n│ ├── main.rs # Entry point\n│ ├── cli/ # CLI commands\n│ ├── core/ # Core data models\n│ ├── providers/ # Provider implementations\n│ ├── browser/ # Cookie extraction\n│ ├── tauri_app/ # Tauri GUI\n│ ├── tray/ # Tray icon types\n│ ├── settings.rs # Settings management\n│ ├── status.rs # Status page polling\n│ └── notifications.rs # Windows notifications\n├── ui/ # HTML/CSS/JS for GUI\n│ ├── index.html # Main panel\n│ ├── settings.html # Settings page\n│ ├── about.html # About dialog\n│ └── cookies.html # Cookie input\n└── Cargo.toml\n```\n\n## Credits\n\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\n\n## License\n\nMIT\n"}, "d3b12d4b3749e8581626453f8f71e612966d424f": {"t": 1786068576.6051273, "n": 7768, "h": "e044cdbda99c9fcd", "c": "# CodexBar for Windows\r\n\r\nA Windows port of [CodexBar](https://github.com/steipete/CodexBar) - a system tray application for monitoring AI provider usage limits.\r\n\r\n\r\n\r\n## Features\r\n\r\n- **System Tray Icon** - Color-coded usage indicator with incident badges\r\n- **Multiple Providers** - Support for 40 AI providers:\n - Codex, Claude, Cursor, Factory, Gemini, Copilot, Antigravity, z.ai\n - MiniMax, Kiro, Vertex AI, Augment, OpenCode, OpenCode Go, Kimi, Kimi K2\n - Amp, Warp, Ollama, OpenRouter, JetBrains AI, Alibaba\n - NanoGPT, Infini, Perplexity, Abacus AI, Mistral, Kilo, AWS Bedrock, Codebuff, DeepSeek, Windsurf\n - Manus, Xiaomi MiMo, Doubao, Command Code, Crof, StepFun, Venice, OpenAI API\n- **Usage Notifications** - Windows toast alerts when usage hits thresholds\r\n- **Settings Panel** - Enable/disable providers, configure refresh intervals\r\n- **Manual Cookie Input** - Fallback for when automatic cookie extraction fails\r\n- **Status Page Polling** - Shows provider incidents with visual badges\r\n- **CLI Tool** - Command-line interface for scripts and automation\r\n\r\n## Installation\r\n\r\n### From Release\n\nDownload the latest release from the [Releases](https://github.com/Finesssee/Win-CodexBar/releases) page.\n\n- Recommended: `CodexBar-<version>-Setup.exe`\n - This installer now installs the required Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime on clean Windows machines before launching CodexBar.\n- Portable: `CodexBar-<version>-portable.exe`\n - Run it directly without installing.\n - Release builds statically link the WebView2 loader, so no `WebView2Loader.dll` sidecar is required.\n - Best for machines that already have the Microsoft Visual C++ runtime and Microsoft Edge WebView2 Runtime installed.\n- Linux CLI: `codexbar-v<version>-linux-x86_64.tar.gz` or `codexbar-v<version>-linux-aarch64.tar.gz`\n - Includes the standalone `codexbar` CLI binary plus README and license files.\n\r\n### Build from Source\r\n\r\nRequirements:\r\n- Rust 1.70+ (install from [rustup.rs](https://rustup.rs))\r\n- Windows 10/11\r\n\r\n```powershell\r\n# Clone the repository\r\ngit clone https://github.com/Finesssee/Win-CodexBar.git\r\ncd Win-CodexBar/rust\r\n\r\n# Build release version\r\ncargo build --release\r\n\r\n# Run the CLI\r\n./target/release/codexbar.exe --help\r\n\r\n# Build the Tauri desktop shell\ncd ../apps/desktop-tauri\nnpm install\nnpm run tauri:build\n```\r\n\r\n## Usage\r\n\r\n### GUI Mode (System Tray)\n\r\n```powershell\r\ncodexbar.exe\n```\r\n\r\nThis launches the system tray application:\n- Click the tray icon to show the usage panel\n- Use Settings to pick English or Chinese in `General`\n- Use `General -> Updates` to choose the release channel, background auto-download behavior, and whether a ready installer should run automatically when you quit CodexBar\n- Use the Providers tab to re-enable providers and review auth/account state\n- Use the Cookies, API Keys, or provider account sections to recover credentials if status stops updating\n- Use the About button for version info\n\nOn Windows Remote Desktop sessions, CodexBar now exits with a direct error dialog instead of crashing with renderer errors. Use the local Windows desktop session for the native UI, or run installed CLI commands like `codexbar-cli usage -p claude` while connected over RDP.\n\r\n### CLI Mode\r\n\r\n```powershell\r\n# Show usage for all enabled providers\r\ncodexbar\r\n\r\n# Show usage for specific provider\r\ncodexbar -p claude\r\n\r\n# Show usage for all providers\r\ncodexbar -p all\r\n\r\n# Output as JSON\r\ncodexbar --json --pretty\r\n\r\n# Include provider status\r\ncodexbar --status\r\n\r\n# Show local cost usage (Claude + Codex logs)\r\ncodexbar cost\r\n\r\n# Enable/disable auto-start on Windows boot\r\ncodexbar autostart enable\r\ncodexbar autostart disable\r\ncodexbar autostart status\r\n```\r\n\r\n### Exit Codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 0 | Success |\r\n| 1 | Unexpected failure |\r\n| 2 | Provider not installed |\r\n| 3 | Parse error |\r\n| 4 | Timeout |\r\n\r\n## Configuration\r\n\r\nSettings are stored in `%APPDATA%\\CodexBar\\settings.json`:\r\n\r\n```json\r\n{\r\n \"enabled_providers\": [\"claude\", \"codex\"],\r\n \"refresh_interval_secs\": 300,\r\n \"show_notifications\": true,\r\n \"high_usage_threshold\": 70.0,\r\n \"critical_usage_threshold\": 90.0\r\n}\r\n```\r\n\r\nManual cookies, API keys, token accounts, and settings are stored under `%APPDATA%\\CodexBar`.\nOn Windows, new saves are wrapped with DPAPI protection. Existing plaintext files remain readable\nand are rewritten protected on the next save.\n\r\n## Provider Authentication\r\n\r\nEach provider has different authentication methods:\r\n\r\n| Provider | Auth Method |\n|----------|-------------|\n| Claude | Browser cookies (Chrome/Edge), OAuth, session env vars |\n| Codex | Local CLI, Browser cookies |\n| Cursor | Browser cookies |\n| Gemini | gcloud CLI credentials |\r\n| Copilot | GitHub device flow, gh CLI auth, legacy token fallback |\n| Antigravity | Local language server |\n| Windsurf | Local cache |\n| Zai | Local config |\n| Kiro | AWS credentials |\n| Vertex AI | gcloud OAuth |\n| Augment | VS Code extension |\n| MiniMax | API key |\n| OpenCode / OpenCode Go | Browser cookies |\n| Kimi / Kimi K2 | Browser cookies / API cookies |\n| Amp | Sourcegraph token |\n| Warp | API key |\n| Ollama | Browser cookies |\n| OpenRouter | API key |\n| JetBrains AI | Local IDE config |\n| Alibaba | API key / browser cookies |\n| NanoGPT | API key |\n| Infini | API key |\n| Perplexity | Browser cookies |\n| Abacus AI | Browser cookies |\n| Mistral | Browser cookies |\n| Kilo | API key / local CLI config |\n| Codebuff | API key / local Manicode config |\n| DeepSeek | API key |\n\n### Claude session env vars\n\nWhen browser cookie extraction is unreliable, Claude can also read a session key from the environment:\n\n```powershell\n$env:CLAUDE_AI_SESSION_KEY = \"sk-ant-...\"\ncodexbar -p claude\n```\n\n`CLAUDE_AI_SESSION_KEY` and `CLAUDE_WEB_SESSION_KEY` both work. Each accepts either the raw token or the full cookie-style value, for example `sessionKey=sk-ant-...`.\n\r\n## Screenshots\r\n\r\n### System Tray\r\n\r\n\r\nThe tray icon color indicates overall usage:\r\n- Green: 0-50% used\r\n- Yellow: 50-80% used\r\n- Orange: 80-95% used\r\n- Red: 95-100% used\r\n- Gray: Unknown/loading\r\n\r\nA badge appears in the corner for status issues:\r\n- Yellow badge: Degraded performance\r\n- Red badge: Major outage\r\n\r\n### Main Panel\r\n\r\n\r\n### Settings\r\n\r\n\r\n### About\r\n\r\n\r\n## Development\r\n\r\n### Running Tests\n\n```powershell\ncargo test\n```\n\nPlain `cargo test` now follows the host target by default:\n- Windows hosts build and test the native Windows target\n- Linux hosts build and test the native Linux target\n\nIf you explicitly want a cross-target pass, provide the target yourself:\n\n```bash\ncargo test --target x86_64-unknown-linux-gnu\n```\n\r\n### Project Structure\r\n\r\n```\r\nrust/\r\n├── src/\r\n│ ├── main.rs # Entry point\r\n│ ├── cli/ # CLI commands\r\n│ ├── core/ # Core data models\r\n│ ├── providers/ # Provider implementations\r\n│ ├── browser/ # Cookie extraction\r\n│ ├── tauri_app/ # Tauri GUI\r\n│ ├── tray/ # Tray icon types\r\n│ ├── settings.rs # Settings management\r\n│ ├── status.rs # Status page polling\r\n│ └── notifications.rs # Windows notifications\r\n├── ui/ # HTML/CSS/JS for GUI\r\n│ ├── index.html # Main panel\r\n│ ├── settings.html # Settings page\r\n│ ├── about.html # About dialog\r\n│ └── cookies.html # Cookie input\r\n└── Cargo.toml\r\n```\r\n\r\n## Credits\r\n\r\nThis is a Windows port of [CodexBar](https://github.com/steipete/CodexBar) by [Peter Steinberger](https://twitter.com/steipete).\r\n\r\n## License\r\n\r\nMIT\r\n"}}}} |