feat(grokbuild): add first-class Grok Build support (#5453)

* feat(grokbuild): add backend integration

* feat(grokbuild): add provider and management UI

* test(grokbuild): cover configuration and integrations

* fix(grokbuild): address backend review feedback

* fix(grokbuild): complete UI review feedback

* feat(grokbuild): add CLI lifecycle management

* fix(grokbuild): align provider icon fallback

* test(grokbuild): cover provider icon persistence
This commit is contained in:
Thefool
2026-07-17 15:50:50 +08:00
committed by GitHub
parent f6e37ed994
commit 1c0ee0c58a
112 changed files with 4530 additions and 246 deletions
+22 -2
View File
@@ -118,7 +118,7 @@ pub struct TrayAppSection {
pub const AUTO_SUFFIX: &str = "auto";
pub const TRAY_ID: &str = "cc-switch";
pub const TRAY_SECTIONS: [TrayAppSection; 3] = [
pub const TRAY_SECTIONS: [TrayAppSection; 4] = [
TrayAppSection {
app_type: AppType::Claude,
prefix: "claude_",
@@ -140,6 +140,13 @@ pub const TRAY_SECTIONS: [TrayAppSection; 3] = [
header_label: "Gemini",
log_name: "Gemini",
},
TrayAppSection {
app_type: AppType::GrokBuild,
prefix: "grokbuild_",
empty_id: "grokbuild_empty",
header_label: "Grok Build",
log_name: "Grok Build",
},
];
/// 配色阈值(与前端 `utilizationColor` 语义一致)。
@@ -1072,7 +1079,8 @@ pub(crate) async fn refresh_all_usage_in_tray(app: &tauri::AppHandle) {
#[cfg(test)]
mod tests {
use super::{format_script_summary, format_subscription_summary, TRAY_ID};
use super::{format_script_summary, format_subscription_summary, TRAY_ID, TRAY_SECTIONS};
use crate::app_config::AppType;
use crate::provider::{UsageData, UsageResult};
use crate::services::subscription::{
CredentialStatus, QuotaTier, SubscriptionQuota, TIER_FIVE_HOUR, TIER_GEMINI_FLASH,
@@ -1086,6 +1094,18 @@ mod tests {
assert_ne!(TRAY_ID, "main");
}
#[test]
fn tray_sections_include_grokbuild_provider_switching() {
let section = TRAY_SECTIONS
.iter()
.find(|section| section.app_type == AppType::GrokBuild)
.expect("Grok Build tray section should exist");
assert_eq!(section.prefix, "grokbuild_");
assert_eq!(section.empty_id, "grokbuild_empty");
assert_eq!(section.header_label, "Grok Build");
}
fn make_quota(tool: &str, success: bool, tiers: Vec<QuotaTier>) -> SubscriptionQuota {
SubscriptionQuota {
tool: tool.to_string(),