feat(config): unify common config snippets persistence across all apps

- Add unified `common_config_snippets` structure to MultiAppConfig
- Implement `get_common_config_snippet` and `set_common_config_snippet` commands
- Replace localStorage with config.json persistence for Codex and Gemini
- Auto-migrate legacy `claude_common_config_snippet` to new unified structure
- Deprecate individual API methods in favor of unified interface
- Add automatic migration from localStorage on first load

BREAKING CHANGE: Common config snippets now stored in unified `common_config_snippets` object instead of separate fields
This commit is contained in:
Jason
2025-11-15 19:52:49 +08:00
parent 2540f6ba08
commit 154ff4c819
7 changed files with 300 additions and 90 deletions

View File

@@ -174,6 +174,39 @@ impl FromStr for AppType {
} }
} }
/// 通用配置片段(按应用分治)
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CommonConfigSnippets {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub claude: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub codex: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub gemini: Option<String>,
}
impl CommonConfigSnippets {
/// 获取指定应用的通用配置片段
pub fn get(&self, app: &AppType) -> Option<&String> {
match app {
AppType::Claude => self.claude.as_ref(),
AppType::Codex => self.codex.as_ref(),
AppType::Gemini => self.gemini.as_ref(),
}
}
/// 设置指定应用的通用配置片段
pub fn set(&mut self, app: &AppType, snippet: Option<String>) {
match app {
AppType::Claude => self.claude = snippet,
AppType::Codex => self.codex = snippet,
AppType::Gemini => self.gemini = snippet,
}
}
}
/// 多应用配置结构(向后兼容) /// 多应用配置结构(向后兼容)
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MultiAppConfig { pub struct MultiAppConfig {
@@ -188,7 +221,10 @@ pub struct MultiAppConfig {
/// Prompt 配置(按客户端分治) /// Prompt 配置(按客户端分治)
#[serde(default)] #[serde(default)]
pub prompts: PromptRoot, pub prompts: PromptRoot,
/// Claude 通用配置片段JSON 字符串,用于跨供应商共享配置 /// 通用配置片段(按应用分治
#[serde(default)]
pub common_config_snippets: CommonConfigSnippets,
/// Claude 通用配置片段(旧字段,用于向后兼容迁移)
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
pub claude_common_config_snippet: Option<String>, pub claude_common_config_snippet: Option<String>,
} }
@@ -209,6 +245,7 @@ impl Default for MultiAppConfig {
apps, apps,
mcp: McpRoot::default(), mcp: McpRoot::default(),
prompts: PromptRoot::default(), prompts: PromptRoot::default(),
common_config_snippets: CommonConfigSnippets::default(),
claude_common_config_snippet: None, claude_common_config_snippet: None,
} }
} }
@@ -278,6 +315,13 @@ impl MultiAppConfig {
updated = true; updated = true;
} }
// 迁移通用配置片段claude_common_config_snippet → common_config_snippets.claude
if let Some(old_claude_snippet) = config.claude_common_config_snippet.take() {
log::info!("迁移通用配置claude_common_config_snippet → common_config_snippets.claude");
config.common_config_snippets.claude = Some(old_claude_snippet);
updated = true;
}
if updated { if updated {
log::info!("配置结构已更新(包括 MCP 迁移或 Prompt 自动导入),保存配置..."); log::info!("配置结构已更新(包括 MCP 迁移或 Prompt 自动导入),保存配置...");
config.save()?; config.save()?;

View File

@@ -136,7 +136,7 @@ pub async fn open_app_config_folder(handle: AppHandle) -> Result<bool, String> {
Ok(true) Ok(true)
} }
/// 获取 Claude 通用配置片段 /// 获取 Claude 通用配置片段(已废弃,使用 get_common_config_snippet
#[tauri::command] #[tauri::command]
pub async fn get_claude_common_config_snippet( pub async fn get_claude_common_config_snippet(
state: tauri::State<'_, crate::store::AppState>, state: tauri::State<'_, crate::store::AppState>,
@@ -145,10 +145,10 @@ pub async fn get_claude_common_config_snippet(
.config .config
.read() .read()
.map_err(|e| format!("读取配置锁失败: {e}"))?; .map_err(|e| format!("读取配置锁失败: {e}"))?;
Ok(guard.claude_common_config_snippet.clone()) Ok(guard.common_config_snippets.claude.clone())
} }
/// 设置 Claude 通用配置片段 /// 设置 Claude 通用配置片段(已废弃,使用 set_common_config_snippet
#[tauri::command] #[tauri::command]
pub async fn set_claude_common_config_snippet( pub async fn set_claude_common_config_snippet(
snippet: String, snippet: String,
@@ -165,7 +165,7 @@ pub async fn set_claude_common_config_snippet(
.map_err(|e| format!("无效的 JSON 格式: {e}"))?; .map_err(|e| format!("无效的 JSON 格式: {e}"))?;
} }
guard.claude_common_config_snippet = if snippet.trim().is_empty() { guard.common_config_snippets.claude = if snippet.trim().is_empty() {
None None
} else { } else {
Some(snippet) Some(snippet)
@@ -174,3 +174,69 @@ pub async fn set_claude_common_config_snippet(
guard.save().map_err(|e| e.to_string())?; guard.save().map_err(|e| e.to_string())?;
Ok(()) Ok(())
} }
/// 获取通用配置片段(统一接口)
#[tauri::command]
pub async fn get_common_config_snippet(
app_type: String,
state: tauri::State<'_, crate::store::AppState>,
) -> Result<Option<String>, String> {
use crate::app_config::AppType;
use std::str::FromStr;
let app = AppType::from_str(&app_type)
.map_err(|e| format!("无效的应用类型: {}", e))?;
let guard = state
.config
.read()
.map_err(|e| format!("读取配置锁失败: {}", e))?;
Ok(guard.common_config_snippets.get(&app).cloned())
}
/// 设置通用配置片段(统一接口)
#[tauri::command]
pub async fn set_common_config_snippet(
app_type: String,
snippet: String,
state: tauri::State<'_, crate::store::AppState>,
) -> Result<(), String> {
use crate::app_config::AppType;
use std::str::FromStr;
let app = AppType::from_str(&app_type)
.map_err(|e| format!("无效的应用类型: {}", e))?;
let mut guard = state
.config
.write()
.map_err(|e| format!("写入配置锁失败: {}", e))?;
// 验证格式(根据应用类型)
if !snippet.trim().is_empty() {
match app {
AppType::Claude | AppType::Gemini => {
// 验证 JSON 格式
serde_json::from_str::<serde_json::Value>(&snippet)
.map_err(|e| format!("无效的 JSON 格式: {}", e))?;
}
AppType::Codex => {
// TOML 格式暂不验证(或可使用 toml crate
// 注意TOML 验证较为复杂,暂时跳过
}
}
}
guard.common_config_snippets.set(
&app,
if snippet.trim().is_empty() {
None
} else {
Some(snippet)
},
);
guard.save().map_err(|e| e.to_string())?;
Ok(())
}

View File

@@ -517,6 +517,8 @@ pub fn run() {
commands::open_app_config_folder, commands::open_app_config_folder,
commands::get_claude_common_config_snippet, commands::get_claude_common_config_snippet,
commands::set_claude_common_config_snippet, commands::set_claude_common_config_snippet,
commands::get_common_config_snippet,
commands::set_common_config_snippet,
commands::read_live_provider_settings, commands::read_live_provider_settings,
commands::get_settings, commands::get_settings,
commands::save_settings, commands::save_settings,

View File

@@ -3,8 +3,9 @@ import {
updateTomlCommonConfigSnippet, updateTomlCommonConfigSnippet,
hasTomlCommonConfigSnippet, hasTomlCommonConfigSnippet,
} from "@/utils/providerConfigUtils"; } from "@/utils/providerConfigUtils";
import { configApi } from "@/lib/api";
const CODEX_COMMON_CONFIG_STORAGE_KEY = "cc-switch:codex-common-config-snippet"; const LEGACY_STORAGE_KEY = "cc-switch:codex-common-config-snippet";
const DEFAULT_CODEX_COMMON_CONFIG_SNIPPET = `# Common Codex config const DEFAULT_CODEX_COMMON_CONFIG_SNIPPET = `# Common Codex config
# Add your common TOML configuration here`; # Add your common TOML configuration here`;
@@ -18,6 +19,7 @@ interface UseCodexCommonConfigProps {
/** /**
* 管理 Codex 通用配置片段 (TOML 格式) * 管理 Codex 通用配置片段 (TOML 格式)
* 从 config.json 读取和保存,支持从 localStorage 平滑迁移
*/ */
export function useCodexCommonConfig({ export function useCodexCommonConfig({
codexConfig, codexConfig,
@@ -26,31 +28,69 @@ export function useCodexCommonConfig({
}: UseCodexCommonConfigProps) { }: UseCodexCommonConfigProps) {
const [useCommonConfig, setUseCommonConfig] = useState(false); const [useCommonConfig, setUseCommonConfig] = useState(false);
const [commonConfigSnippet, setCommonConfigSnippetState] = useState<string>( const [commonConfigSnippet, setCommonConfigSnippetState] = useState<string>(
() => { DEFAULT_CODEX_COMMON_CONFIG_SNIPPET,
if (typeof window === "undefined") {
return DEFAULT_CODEX_COMMON_CONFIG_SNIPPET;
}
try {
const stored = window.localStorage.getItem(
CODEX_COMMON_CONFIG_STORAGE_KEY,
);
if (stored && stored.trim()) {
return stored;
}
} catch {
// ignore localStorage 读取失败
}
return DEFAULT_CODEX_COMMON_CONFIG_SNIPPET;
},
); );
const [commonConfigError, setCommonConfigError] = useState(""); const [commonConfigError, setCommonConfigError] = useState("");
const [isLoading, setIsLoading] = useState(true);
// 用于跟踪是否正在通过通用配置更新 // 用于跟踪是否正在通过通用配置更新
const isUpdatingFromCommonConfig = useRef(false); const isUpdatingFromCommonConfig = useRef(false);
// 初始化:从 config.json 加载,支持从 localStorage 迁移
useEffect(() => {
let mounted = true;
const loadSnippet = async () => {
try {
// 使用统一 API 加载
const snippet = await configApi.getCommonConfigSnippet("codex");
if (snippet && snippet.trim()) {
if (mounted) {
setCommonConfigSnippetState(snippet);
}
} else {
// 如果 config.json 中没有,尝试从 localStorage 迁移
if (typeof window !== "undefined") {
try {
const legacySnippet =
window.localStorage.getItem(LEGACY_STORAGE_KEY);
if (legacySnippet && legacySnippet.trim()) {
// 迁移到 config.json
await configApi.setCommonConfigSnippet("codex", legacySnippet);
if (mounted) {
setCommonConfigSnippetState(legacySnippet);
}
// 清理 localStorage
window.localStorage.removeItem(LEGACY_STORAGE_KEY);
console.log(
"[迁移] Codex 通用配置已从 localStorage 迁移到 config.json",
);
}
} catch (e) {
console.warn("[迁移] 从 localStorage 迁移失败:", e);
}
}
}
} catch (error) {
console.error("加载 Codex 通用配置失败:", error);
} finally {
if (mounted) {
setIsLoading(false);
}
}
};
loadSnippet();
return () => {
mounted = false;
};
}, []);
// 初始化时检查通用配置片段(编辑模式) // 初始化时检查通用配置片段(编辑模式)
useEffect(() => { useEffect(() => {
if (initialData?.settingsConfig) { if (initialData?.settingsConfig && !isLoading) {
const config = const config =
typeof initialData.settingsConfig.config === "string" typeof initialData.settingsConfig.config === "string"
? initialData.settingsConfig.config ? initialData.settingsConfig.config
@@ -58,24 +98,7 @@ export function useCodexCommonConfig({
const hasCommon = hasTomlCommonConfigSnippet(config, commonConfigSnippet); const hasCommon = hasTomlCommonConfigSnippet(config, commonConfigSnippet);
setUseCommonConfig(hasCommon); setUseCommonConfig(hasCommon);
} }
}, [initialData, commonConfigSnippet]); }, [initialData, commonConfigSnippet, isLoading]);
// 同步本地存储的通用配置片段
useEffect(() => {
if (typeof window === "undefined") return;
try {
if (commonConfigSnippet.trim()) {
window.localStorage.setItem(
CODEX_COMMON_CONFIG_STORAGE_KEY,
commonConfigSnippet,
);
} else {
window.localStorage.removeItem(CODEX_COMMON_CONFIG_STORAGE_KEY);
}
} catch {
// ignore
}
}, [commonConfigSnippet]);
// 处理通用配置开关 // 处理通用配置开关
const handleCommonConfigToggle = useCallback( const handleCommonConfigToggle = useCallback(
@@ -114,6 +137,12 @@ export function useCodexCommonConfig({
if (!value.trim()) { if (!value.trim()) {
setCommonConfigError(""); setCommonConfigError("");
// 保存到 config.json清空
configApi.setCommonConfigSnippet("codex", "").catch((error) => {
console.error("保存 Codex 通用配置失败:", error);
setCommonConfigError(`保存失败: ${error}`);
});
if (useCommonConfig) { if (useCommonConfig) {
const { updatedConfig } = updateTomlCommonConfigSnippet( const { updatedConfig } = updateTomlCommonConfigSnippet(
codexConfig, codexConfig,
@@ -128,6 +157,11 @@ export function useCodexCommonConfig({
// TOML 格式校验较为复杂,暂时不做校验,直接清空错误 // TOML 格式校验较为复杂,暂时不做校验,直接清空错误
setCommonConfigError(""); setCommonConfigError("");
// 保存到 config.json
configApi.setCommonConfigSnippet("codex", value).catch((error) => {
console.error("保存 Codex 通用配置失败:", error);
setCommonConfigError(`保存失败: ${error}`);
});
// 若当前启用通用配置,需要替换为最新片段 // 若当前启用通用配置,需要替换为最新片段
if (useCommonConfig) { if (useCommonConfig) {
@@ -165,7 +199,7 @@ export function useCodexCommonConfig({
// 当配置变化时检查是否包含通用配置(但避免在通过通用配置更新时检查) // 当配置变化时检查是否包含通用配置(但避免在通过通用配置更新时检查)
useEffect(() => { useEffect(() => {
if (isUpdatingFromCommonConfig.current) { if (isUpdatingFromCommonConfig.current || isLoading) {
return; return;
} }
const hasCommon = hasTomlCommonConfigSnippet( const hasCommon = hasTomlCommonConfigSnippet(
@@ -173,12 +207,13 @@ export function useCodexCommonConfig({
commonConfigSnippet, commonConfigSnippet,
); );
setUseCommonConfig(hasCommon); setUseCommonConfig(hasCommon);
}, [codexConfig, commonConfigSnippet]); }, [codexConfig, commonConfigSnippet, isLoading]);
return { return {
useCommonConfig, useCommonConfig,
commonConfigSnippet, commonConfigSnippet,
commonConfigError, commonConfigError,
isLoading,
handleCommonConfigToggle, handleCommonConfigToggle,
handleCommonConfigSnippetChange, handleCommonConfigSnippetChange,
}; };

View File

@@ -44,8 +44,8 @@ export function useCommonConfigSnippet({
const loadSnippet = async () => { const loadSnippet = async () => {
try { try {
// 尝试从 config.json 加载 // 使用统一 API 加载
const snippet = await configApi.getClaudeCommonConfigSnippet(); const snippet = await configApi.getCommonConfigSnippet("claude");
if (snippet && snippet.trim()) { if (snippet && snippet.trim()) {
if (mounted) { if (mounted) {
@@ -59,14 +59,14 @@ export function useCommonConfigSnippet({
window.localStorage.getItem(LEGACY_STORAGE_KEY); window.localStorage.getItem(LEGACY_STORAGE_KEY);
if (legacySnippet && legacySnippet.trim()) { if (legacySnippet && legacySnippet.trim()) {
// 迁移到 config.json // 迁移到 config.json
await configApi.setClaudeCommonConfigSnippet(legacySnippet); await configApi.setCommonConfigSnippet("claude", legacySnippet);
if (mounted) { if (mounted) {
setCommonConfigSnippetState(legacySnippet); setCommonConfigSnippetState(legacySnippet);
} }
// 清理 localStorage // 清理 localStorage
window.localStorage.removeItem(LEGACY_STORAGE_KEY); window.localStorage.removeItem(LEGACY_STORAGE_KEY);
console.log( console.log(
"[迁移] 通用配置已从 localStorage 迁移到 config.json", "[迁移] Claude 通用配置已从 localStorage 迁移到 config.json",
); );
} }
} catch (e) { } catch (e) {
@@ -139,8 +139,9 @@ export function useCommonConfigSnippet({
if (!value.trim()) { if (!value.trim()) {
setCommonConfigError(""); setCommonConfigError("");
// 保存到 config.json清空 // 保存到 config.json清空
configApi.setClaudeCommonConfigSnippet("").catch((error) => { configApi.setCommonConfigSnippet("claude", "").catch((error) => {
console.error("保存通用配置失败:", error); console.error("保存通用配置失败:", error);
setCommonConfigError(`保存失败: ${error}`);
}); });
if (useCommonConfig) { if (useCommonConfig) {
@@ -162,7 +163,7 @@ export function useCommonConfigSnippet({
} else { } else {
setCommonConfigError(""); setCommonConfigError("");
// 保存到 config.json // 保存到 config.json
configApi.setClaudeCommonConfigSnippet(value).catch((error) => { configApi.setCommonConfigSnippet("claude", value).catch((error) => {
console.error("保存通用配置失败:", error); console.error("保存通用配置失败:", error);
setCommonConfigError(`保存失败: ${error}`); setCommonConfigError(`保存失败: ${error}`);
}); });

View File

@@ -1,7 +1,7 @@
import { useState, useEffect, useCallback, useRef } from "react"; import { useState, useEffect, useCallback, useRef } from "react";
import { configApi } from "@/lib/api";
const GEMINI_COMMON_CONFIG_STORAGE_KEY = const LEGACY_STORAGE_KEY = "cc-switch:gemini-common-config-snippet";
"cc-switch:gemini-common-config-snippet";
const DEFAULT_GEMINI_COMMON_CONFIG_SNIPPET = `{ const DEFAULT_GEMINI_COMMON_CONFIG_SNIPPET = `{
"timeout": 30000, "timeout": 30000,
"maxRetries": 3 "maxRetries": 3
@@ -105,6 +105,7 @@ function hasCommonConfigSnippet(config: any, commonConfig: any): boolean {
/** /**
* 管理 Gemini 通用配置片段 (JSON 格式) * 管理 Gemini 通用配置片段 (JSON 格式)
* 从 config.json 读取和保存,支持从 localStorage 平滑迁移
*/ */
export function useGeminiCommonConfig({ export function useGeminiCommonConfig({
configValue, configValue,
@@ -113,31 +114,69 @@ export function useGeminiCommonConfig({
}: UseGeminiCommonConfigProps) { }: UseGeminiCommonConfigProps) {
const [useCommonConfig, setUseCommonConfig] = useState(false); const [useCommonConfig, setUseCommonConfig] = useState(false);
const [commonConfigSnippet, setCommonConfigSnippetState] = useState<string>( const [commonConfigSnippet, setCommonConfigSnippetState] = useState<string>(
() => { DEFAULT_GEMINI_COMMON_CONFIG_SNIPPET,
if (typeof window === "undefined") {
return DEFAULT_GEMINI_COMMON_CONFIG_SNIPPET;
}
try {
const stored = window.localStorage.getItem(
GEMINI_COMMON_CONFIG_STORAGE_KEY,
);
if (stored && stored.trim()) {
return stored;
}
} catch {
// ignore localStorage 读取失败
}
return DEFAULT_GEMINI_COMMON_CONFIG_SNIPPET;
},
); );
const [commonConfigError, setCommonConfigError] = useState(""); const [commonConfigError, setCommonConfigError] = useState("");
const [isLoading, setIsLoading] = useState(true);
// 用于跟踪是否正在通过通用配置更新 // 用于跟踪是否正在通过通用配置更新
const isUpdatingFromCommonConfig = useRef(false); const isUpdatingFromCommonConfig = useRef(false);
// 初始化:从 config.json 加载,支持从 localStorage 迁移
useEffect(() => {
let mounted = true;
const loadSnippet = async () => {
try {
// 使用统一 API 加载
const snippet = await configApi.getCommonConfigSnippet("gemini");
if (snippet && snippet.trim()) {
if (mounted) {
setCommonConfigSnippetState(snippet);
}
} else {
// 如果 config.json 中没有,尝试从 localStorage 迁移
if (typeof window !== "undefined") {
try {
const legacySnippet =
window.localStorage.getItem(LEGACY_STORAGE_KEY);
if (legacySnippet && legacySnippet.trim()) {
// 迁移到 config.json
await configApi.setCommonConfigSnippet("gemini", legacySnippet);
if (mounted) {
setCommonConfigSnippetState(legacySnippet);
}
// 清理 localStorage
window.localStorage.removeItem(LEGACY_STORAGE_KEY);
console.log(
"[迁移] Gemini 通用配置已从 localStorage 迁移到 config.json",
);
}
} catch (e) {
console.warn("[迁移] 从 localStorage 迁移失败:", e);
}
}
}
} catch (error) {
console.error("加载 Gemini 通用配置失败:", error);
} finally {
if (mounted) {
setIsLoading(false);
}
}
};
loadSnippet();
return () => {
mounted = false;
};
}, []);
// 初始化时检查通用配置片段(编辑模式) // 初始化时检查通用配置片段(编辑模式)
useEffect(() => { useEffect(() => {
if (initialData?.settingsConfig) { if (initialData?.settingsConfig && !isLoading) {
try { try {
const config = const config =
typeof initialData.settingsConfig.config === "object" typeof initialData.settingsConfig.config === "object"
@@ -150,24 +189,7 @@ export function useGeminiCommonConfig({
// ignore parse error // ignore parse error
} }
} }
}, [initialData, commonConfigSnippet]); }, [initialData, commonConfigSnippet, isLoading]);
// 同步本地存储的通用配置片段
useEffect(() => {
if (typeof window === "undefined") return;
try {
if (commonConfigSnippet.trim()) {
window.localStorage.setItem(
GEMINI_COMMON_CONFIG_STORAGE_KEY,
commonConfigSnippet,
);
} else {
window.localStorage.removeItem(GEMINI_COMMON_CONFIG_STORAGE_KEY);
}
} catch {
// ignore
}
}, [commonConfigSnippet]);
// 处理通用配置开关 // 处理通用配置开关
const handleCommonConfigToggle = useCallback( const handleCommonConfigToggle = useCallback(
@@ -214,6 +236,12 @@ export function useGeminiCommonConfig({
if (!value.trim()) { if (!value.trim()) {
setCommonConfigError(""); setCommonConfigError("");
// 保存到 config.json清空
configApi.setCommonConfigSnippet("gemini", "").catch((error) => {
console.error("保存 Gemini 通用配置失败:", error);
setCommonConfigError(`保存失败: ${error}`);
});
if (useCommonConfig) { if (useCommonConfig) {
// 移除旧的通用配置 // 移除旧的通用配置
try { try {
@@ -236,6 +264,11 @@ export function useGeminiCommonConfig({
try { try {
JSON.parse(value); JSON.parse(value);
setCommonConfigError(""); setCommonConfigError("");
// 保存到 config.json
configApi.setCommonConfigSnippet("gemini", value).catch((error) => {
console.error("保存 Gemini 通用配置失败:", error);
setCommonConfigError(`保存失败: ${error}`);
});
} catch { } catch {
setCommonConfigError("通用配置片段格式错误(必须是有效的 JSON"); setCommonConfigError("通用配置片段格式错误(必须是有效的 JSON");
return; return;
@@ -276,7 +309,7 @@ export function useGeminiCommonConfig({
// 当配置变化时检查是否包含通用配置(但避免在通过通用配置更新时检查) // 当配置变化时检查是否包含通用配置(但避免在通过通用配置更新时检查)
useEffect(() => { useEffect(() => {
if (isUpdatingFromCommonConfig.current) { if (isUpdatingFromCommonConfig.current || isLoading) {
return; return;
} }
try { try {
@@ -287,12 +320,13 @@ export function useGeminiCommonConfig({
} catch { } catch {
// ignore parse error // ignore parse error
} }
}, [configValue, commonConfigSnippet]); }, [configValue, commonConfigSnippet, isLoading]);
return { return {
useCommonConfig, useCommonConfig,
commonConfigSnippet, commonConfigSnippet,
commonConfigError, commonConfigError,
isLoading,
handleCommonConfigToggle, handleCommonConfigToggle,
handleCommonConfigSnippetChange, handleCommonConfigSnippetChange,
}; };

View File

@@ -1,21 +1,49 @@
// 配置相关 API // 配置相关 API
import { invoke } from "@tauri-apps/api/core"; import { invoke } from "@tauri-apps/api/core";
export type AppType = "claude" | "codex" | "gemini";
/** /**
* 获取 Claude 通用配置片段 * 获取 Claude 通用配置片段(已废弃,使用 getCommonConfigSnippet
* @returns 通用配置片段JSON 字符串),如果不存在则返回 null * @returns 通用配置片段JSON 字符串),如果不存在则返回 null
* @deprecated 使用 getCommonConfigSnippet('claude') 替代
*/ */
export async function getClaudeCommonConfigSnippet(): Promise<string | null> { export async function getClaudeCommonConfigSnippet(): Promise<string | null> {
return invoke<string | null>("get_claude_common_config_snippet"); return invoke<string | null>("get_claude_common_config_snippet");
} }
/** /**
* 设置 Claude 通用配置片段 * 设置 Claude 通用配置片段(已废弃,使用 setCommonConfigSnippet
* @param snippet - 通用配置片段JSON 字符串) * @param snippet - 通用配置片段JSON 字符串)
* @throws 如果 JSON 格式无效 * @throws 如果 JSON 格式无效
* @deprecated 使用 setCommonConfigSnippet('claude', snippet) 替代
*/ */
export async function setClaudeCommonConfigSnippet( export async function setClaudeCommonConfigSnippet(
snippet: string, snippet: string,
): Promise<void> { ): Promise<void> {
return invoke("set_claude_common_config_snippet", { snippet }); return invoke("set_claude_common_config_snippet", { snippet });
} }
/**
* 获取通用配置片段(统一接口)
* @param appType - 应用类型claude/codex/gemini
* @returns 通用配置片段(原始字符串),如果不存在则返回 null
*/
export async function getCommonConfigSnippet(
appType: AppType,
): Promise<string | null> {
return invoke<string | null>("get_common_config_snippet", { appType });
}
/**
* 设置通用配置片段(统一接口)
* @param appType - 应用类型claude/codex/gemini
* @param snippet - 通用配置片段(原始字符串)
* @throws 如果格式无效Claude/Gemini 验证 JSONCodex 暂不验证)
*/
export async function setCommonConfigSnippet(
appType: AppType,
snippet: string,
): Promise<void> {
return invoke("set_common_config_snippet", { appType, snippet });
}