mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-28 00:35:32 +08:00
5658d93924
Add OpenCode as the 4th supported application with additive provider management: - Add OpenCode variant to AppType enum with all related match statements - Add enabled_opencode field to McpApps and SkillApps structures - Add opencode field to McpRoot and PromptRoot - Add database schema migration v3→v4 with enabled_opencode columns - Add settings.rs support for opencode_config_dir and current_provider_opencode - Create opencode_config.rs module for config file I/O operations - Update all services (proxy, mcp, skill, provider, stream_check) for OpenCode - Add OpenCode support to deeplink provider and MCP parsing - Update commands/config.rs for OpenCode config status and paths Key design decisions: - OpenCode uses additive mode (no is_current needed, no proxy support) - Config path: ~/.config/opencode/opencode.json - MCP format: stdio→local, sse/http→remote conversion planned - Stream check returns error (not yet implemented for OpenCode)
143 lines
4.4 KiB
Rust
143 lines
4.4 KiB
Rust
//! Gemini MCP 同步和导入模块
|
||
|
||
use serde_json::Value;
|
||
use std::collections::HashMap;
|
||
|
||
use crate::app_config::{McpApps, McpConfig, McpServer, MultiAppConfig};
|
||
use crate::error::AppError;
|
||
|
||
use super::validation::{extract_server_spec, validate_server_spec};
|
||
|
||
fn should_sync_gemini_mcp() -> bool {
|
||
// Gemini 未安装/未初始化时:~/.gemini 目录不存在。
|
||
// 按用户偏好:目录缺失时跳过写入/删除,不创建任何文件或目录。
|
||
crate::gemini_config::get_gemini_dir().exists()
|
||
}
|
||
|
||
/// 返回已启用的 MCP 服务器(过滤 enabled==true)
|
||
fn collect_enabled_servers(cfg: &McpConfig) -> HashMap<String, Value> {
|
||
let mut out = HashMap::new();
|
||
for (id, entry) in cfg.servers.iter() {
|
||
let enabled = entry
|
||
.get("enabled")
|
||
.and_then(|v| v.as_bool())
|
||
.unwrap_or(false);
|
||
if !enabled {
|
||
continue;
|
||
}
|
||
match extract_server_spec(entry) {
|
||
Ok(spec) => {
|
||
out.insert(id.clone(), spec);
|
||
}
|
||
Err(err) => {
|
||
log::warn!("跳过无效的 MCP 条目 '{id}': {err}");
|
||
}
|
||
}
|
||
}
|
||
out
|
||
}
|
||
|
||
/// 将 config.json 中 Gemini 的 enabled==true 项写入 Gemini MCP 配置
|
||
pub fn sync_enabled_to_gemini(config: &MultiAppConfig) -> Result<(), AppError> {
|
||
if !should_sync_gemini_mcp() {
|
||
return Ok(());
|
||
}
|
||
let enabled = collect_enabled_servers(&config.mcp.gemini);
|
||
crate::gemini_mcp::set_mcp_servers_map(&enabled)
|
||
}
|
||
|
||
/// 从 Gemini MCP 配置导入到统一结构(v3.7.0+)
|
||
/// 已存在的服务器将启用 Gemini 应用,不覆盖其他字段和应用状态
|
||
pub fn import_from_gemini(config: &mut MultiAppConfig) -> Result<usize, AppError> {
|
||
let map = crate::gemini_mcp::read_mcp_servers_map()?;
|
||
if map.is_empty() {
|
||
return Ok(0);
|
||
}
|
||
|
||
// 确保新结构存在
|
||
let servers = config.mcp.servers.get_or_insert_with(HashMap::new);
|
||
|
||
let mut changed = 0;
|
||
let mut errors = Vec::new();
|
||
|
||
for (id, spec) in map.iter() {
|
||
// 校验:单项失败不中止,收集错误继续处理
|
||
if let Err(e) = validate_server_spec(spec) {
|
||
log::warn!("跳过无效 MCP 服务器 '{id}': {e}");
|
||
errors.push(format!("{id}: {e}"));
|
||
continue;
|
||
}
|
||
|
||
if let Some(existing) = servers.get_mut(id) {
|
||
// 已存在:仅启用 Gemini 应用
|
||
if !existing.apps.gemini {
|
||
existing.apps.gemini = true;
|
||
changed += 1;
|
||
log::info!("MCP 服务器 '{id}' 已启用 Gemini 应用");
|
||
}
|
||
} else {
|
||
// 新建服务器:默认仅启用 Gemini
|
||
servers.insert(
|
||
id.clone(),
|
||
McpServer {
|
||
id: id.clone(),
|
||
name: id.clone(),
|
||
server: spec.clone(),
|
||
apps: McpApps {
|
||
claude: false,
|
||
codex: false,
|
||
gemini: true,
|
||
opencode: false,
|
||
},
|
||
description: None,
|
||
homepage: None,
|
||
docs: None,
|
||
tags: Vec::new(),
|
||
},
|
||
);
|
||
changed += 1;
|
||
log::info!("导入新 MCP 服务器 '{id}'");
|
||
}
|
||
}
|
||
|
||
if !errors.is_empty() {
|
||
log::warn!("导入完成,但有 {} 项失败: {:?}", errors.len(), errors);
|
||
}
|
||
|
||
Ok(changed)
|
||
}
|
||
|
||
/// 将单个 MCP 服务器同步到 Gemini live 配置
|
||
pub fn sync_single_server_to_gemini(
|
||
_config: &MultiAppConfig,
|
||
id: &str,
|
||
server_spec: &Value,
|
||
) -> Result<(), AppError> {
|
||
if !should_sync_gemini_mcp() {
|
||
return Ok(());
|
||
}
|
||
// 读取现有的 MCP 配置
|
||
let mut current = crate::gemini_mcp::read_mcp_servers_map()?;
|
||
|
||
// 添加/更新当前服务器
|
||
current.insert(id.to_string(), server_spec.clone());
|
||
|
||
// 写回
|
||
crate::gemini_mcp::set_mcp_servers_map(¤t)
|
||
}
|
||
|
||
/// 从 Gemini live 配置中移除单个 MCP 服务器
|
||
pub fn remove_server_from_gemini(id: &str) -> Result<(), AppError> {
|
||
if !should_sync_gemini_mcp() {
|
||
return Ok(());
|
||
}
|
||
// 读取现有的 MCP 配置
|
||
let mut current = crate::gemini_mcp::read_mcp_servers_map()?;
|
||
|
||
// 移除指定服务器
|
||
current.remove(id);
|
||
|
||
// 写回
|
||
crate::gemini_mcp::set_mcp_servers_map(¤t)
|
||
}
|