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
+8 -5
View File
@@ -13,7 +13,7 @@ impl Database {
pub fn get_all_mcp_servers(&self) -> Result<IndexMap<String, McpServer>, AppError> {
let conn = lock_conn!(self.conn);
let mut stmt = conn.prepare(
"SELECT id, name, server_config, description, homepage, docs, tags, enabled_claude, enabled_codex, enabled_gemini, enabled_opencode, enabled_hermes
"SELECT id, name, server_config, description, homepage, docs, tags, enabled_claude, enabled_codex, enabled_gemini, enabled_grokbuild, enabled_opencode, enabled_hermes
FROM mcp_servers
ORDER BY name ASC, id ASC"
).map_err(|e| AppError::Database(e.to_string()))?;
@@ -30,8 +30,9 @@ impl Database {
let enabled_claude: bool = row.get(7)?;
let enabled_codex: bool = row.get(8)?;
let enabled_gemini: bool = row.get(9)?;
let enabled_opencode: bool = row.get(10)?;
let enabled_hermes: bool = row.get(11)?;
let enabled_grokbuild: bool = row.get(10)?;
let enabled_opencode: bool = row.get(11)?;
let enabled_hermes: bool = row.get(12)?;
let server = serde_json::from_str(&server_config_str).unwrap_or_default();
let tags = serde_json::from_str(&tags_str).unwrap_or_default();
@@ -46,6 +47,7 @@ impl Database {
claude: enabled_claude,
codex: enabled_codex,
gemini: enabled_gemini,
grokbuild: enabled_grokbuild,
opencode: enabled_opencode,
hermes: enabled_hermes,
},
@@ -72,8 +74,8 @@ impl Database {
conn.execute(
"INSERT OR REPLACE INTO mcp_servers (
id, name, server_config, description, homepage, docs, tags,
enabled_claude, enabled_codex, enabled_gemini, enabled_opencode, enabled_hermes
) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)",
enabled_claude, enabled_codex, enabled_gemini, enabled_grokbuild, enabled_opencode, enabled_hermes
) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)",
params![
server.id,
server.name,
@@ -88,6 +90,7 @@ impl Database {
server.apps.claude,
server.apps.codex,
server.apps.gemini,
server.apps.grokbuild,
server.apps.opencode,
server.apps.hermes,
],
+13
View File
@@ -328,6 +328,7 @@ impl Database {
"claude" => (6, 90, 180, 8, 3, 90, 0.7, 15),
"codex" => (3, 60, 120, 4, 2, 60, 0.6, 10),
"gemini" => (5, 60, 120, 4, 2, 60, 0.6, 10),
"grokbuild" => (3, 60, 120, 4, 2, 60, 0.6, 10),
_ => (3, 60, 120, 4, 2, 60, 0.6, 10), // 默认值
};
@@ -398,6 +399,18 @@ impl Database {
)
.map_err(|e| AppError::Database(e.to_string()))?;
// grokbuild: Responses protocol, same timeout defaults as Codex.
conn.execute(
"INSERT OR IGNORE INTO proxy_config (
app_type, max_retries,
streaming_first_byte_timeout, streaming_idle_timeout, non_streaming_timeout,
circuit_failure_threshold, circuit_success_threshold, circuit_timeout_seconds,
circuit_error_rate_threshold, circuit_min_requests
) VALUES ('grokbuild', 3, 60, 120, 600, 4, 2, 60, 0.6, 10)",
[],
)
.map_err(|e| AppError::Database(e.to_string()))?;
Ok(())
}
+21 -18
View File
@@ -22,8 +22,8 @@ impl Database {
let mut stmt = conn
.prepare(
"SELECT id, name, description, directory, repo_owner, repo_name, repo_branch,
readme_url, enabled_claude, enabled_codex, enabled_gemini, enabled_opencode,
enabled_hermes, installed_at, content_hash, updated_at
readme_url, enabled_claude, enabled_codex, enabled_gemini, enabled_grokbuild,
enabled_opencode, enabled_hermes, installed_at, content_hash, updated_at
FROM skills ORDER BY name ASC",
)
.map_err(|e| AppError::Database(e.to_string()))?;
@@ -43,12 +43,13 @@ impl Database {
claude: row.get(8)?,
codex: row.get(9)?,
gemini: row.get(10)?,
opencode: row.get(11)?,
hermes: row.get(12)?,
grokbuild: row.get(11)?,
opencode: row.get(12)?,
hermes: row.get(13)?,
},
installed_at: row.get(13)?,
content_hash: row.get(14)?,
updated_at: row.get::<_, i64>(15).unwrap_or(0),
installed_at: row.get(14)?,
content_hash: row.get(15)?,
updated_at: row.get::<_, i64>(16).unwrap_or(0),
})
})
.map_err(|e| AppError::Database(e.to_string()))?;
@@ -67,8 +68,8 @@ impl Database {
let mut stmt = conn
.prepare(
"SELECT id, name, description, directory, repo_owner, repo_name, repo_branch,
readme_url, enabled_claude, enabled_codex, enabled_gemini, enabled_opencode,
enabled_hermes, installed_at, content_hash, updated_at
readme_url, enabled_claude, enabled_codex, enabled_gemini, enabled_grokbuild,
enabled_opencode, enabled_hermes, installed_at, content_hash, updated_at
FROM skills WHERE id = ?1",
)
.map_err(|e| AppError::Database(e.to_string()))?;
@@ -87,12 +88,13 @@ impl Database {
claude: row.get(8)?,
codex: row.get(9)?,
gemini: row.get(10)?,
opencode: row.get(11)?,
hermes: row.get(12)?,
grokbuild: row.get(11)?,
opencode: row.get(12)?,
hermes: row.get(13)?,
},
installed_at: row.get(13)?,
content_hash: row.get(14)?,
updated_at: row.get::<_, i64>(15).unwrap_or(0),
installed_at: row.get(14)?,
content_hash: row.get(15)?,
updated_at: row.get::<_, i64>(16).unwrap_or(0),
})
});
@@ -109,9 +111,9 @@ impl Database {
conn.execute(
"INSERT OR REPLACE INTO skills
(id, name, description, directory, repo_owner, repo_name, repo_branch,
readme_url, enabled_claude, enabled_codex, enabled_gemini, enabled_opencode, enabled_hermes,
readme_url, enabled_claude, enabled_codex, enabled_gemini, enabled_grokbuild, enabled_opencode, enabled_hermes,
installed_at, content_hash, updated_at)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16)",
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17)",
params![
skill.id,
skill.name,
@@ -124,6 +126,7 @@ impl Database {
skill.apps.claude,
skill.apps.codex,
skill.apps.gemini,
skill.apps.grokbuild,
skill.apps.opencode,
skill.apps.hermes,
skill.installed_at,
@@ -157,8 +160,8 @@ impl Database {
let conn = lock_conn!(self.conn);
let affected = conn
.execute(
"UPDATE skills SET enabled_claude = ?1, enabled_codex = ?2, enabled_gemini = ?3, enabled_opencode = ?4, enabled_hermes = ?5 WHERE id = ?6",
params![apps.claude, apps.codex, apps.gemini, apps.opencode, apps.hermes, id],
"UPDATE skills SET enabled_claude = ?1, enabled_codex = ?2, enabled_gemini = ?3, enabled_grokbuild = ?4, enabled_opencode = ?5, enabled_hermes = ?6 WHERE id = ?7",
params![apps.claude, apps.codex, apps.gemini, apps.grokbuild, apps.opencode, apps.hermes, id],
)
.map_err(|e| AppError::Database(e.to_string()))?;
Ok(affected > 0)