diff --git a/src-tauri/src/database/dao/providers.rs b/src-tauri/src/database/dao/providers.rs index 1c5188839..04f138876 100644 --- a/src-tauri/src/database/dao/providers.rs +++ b/src-tauri/src/database/dao/providers.rs @@ -3,7 +3,7 @@ use crate::error::AppError; use crate::provider::{Provider, ProviderMeta}; use indexmap::IndexMap; use rusqlite::params; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; type OmoProviderRow = ( String, @@ -502,6 +502,25 @@ impl Database { })) } + /// 仅获取指定 app 下所有 provider 的 id 集合。 + /// + /// 比 `get_all_providers` 轻量得多:只读 id 列、无 endpoint 子查询。 + /// 用于只需要做存在性检查的场景(如 additive 模式的 live 同步去重)。 + pub fn get_provider_ids(&self, app_type: &str) -> Result, AppError> { + let conn = lock_conn!(self.conn); + let mut stmt = conn + .prepare("SELECT id FROM providers WHERE app_type = ?1") + .map_err(|e| AppError::Database(e.to_string()))?; + let rows = stmt + .query_map(params![app_type], |row| row.get::<_, String>(0)) + .map_err(|e| AppError::Database(e.to_string()))?; + let mut ids = HashSet::new(); + for row in rows { + ids.insert(row.map_err(|e| AppError::Database(e.to_string()))?); + } + Ok(ids) + } + /// 判断指定 app 下是否存在非官方种子的供应商。 /// /// 比 `get_all_providers` 轻量得多:只读 id 列、无 endpoint 子查询、首条命中即返回。 diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 67de2bf90..99c28677b 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -502,6 +502,30 @@ pub fn run() { Err(e) => log::warn!("✗ Failed to seed official providers: {e}"), } + // 1.6. 自动同步 OpenCode / OpenClaw 的 live providers 到数据库 + // + // additive 模式(OpenCode / OpenClaw)的 import 函数本身按 id 幂等, + // 已有的 provider 会被跳过,所以每次启动都跑是安全的——既保证新装 + // 用户开箱可见 live 中的供应商,也让外部修改的 live 文件能在重启 + // 后同步到数据库(与之前依赖前端"导入当前配置"按钮手动触发不同)。 + // + // 底层 read_*_config 在文件不存在时返回默认空配置,因此新装且无 + // live 文件的用户走 Ok(0) 路径,不会产生错误日志噪音。 + match crate::services::provider::import_opencode_providers_from_live(&app_state) { + Ok(count) if count > 0 => { + log::info!("✓ Imported {count} OpenCode provider(s) from live config"); + } + Ok(_) => log::debug!("○ No new OpenCode providers to import"), + Err(e) => log::warn!("✗ Failed to import OpenCode providers: {e}"), + } + match crate::services::provider::import_openclaw_providers_from_live(&app_state) { + Ok(count) if count > 0 => { + log::info!("✓ Imported {count} OpenClaw provider(s) from live config"); + } + Ok(_) => log::debug!("○ No new OpenClaw providers to import"), + Err(e) => log::warn!("✗ Failed to import OpenClaw providers: {e}"), + } + // 2. OMO 配置导入(当数据库中无 OMO provider 时,从本地文件导入) { let has_omo = app_state diff --git a/src-tauri/src/services/provider/live.rs b/src-tauri/src/services/provider/live.rs index f577892a3..3dec78d06 100644 --- a/src-tauri/src/services/provider/live.rs +++ b/src-tauri/src/services/provider/live.rs @@ -1209,11 +1209,11 @@ pub fn import_opencode_providers_from_live(state: &AppState) -> Result Result Result