feat(provider): use live config for edit and backfill SSOT after switch

- Edit modal (Claude+Codex): when editing the current provider, initialize form from live files (Claude: ~/.claude/settings.json; Codex: ~/.codex/auth.json + ~/.codex/config.toml) instead of SSOT.
- Switch (Claude): after writing live settings.json for the target provider, read it back and update the provider’s SSOT to match live.
- Switch (Codex): keep MCP sync to config.toml, then read back TOML and update the target provider’s SSOT (preserves mcp.servers/mcp_servers schema).
- Add Tauri command read_live_provider_settings for both apps, register handler, and expose window.api.getLiveProviderSettings.
- Types updated accordingly; cargo check and pnpm typecheck pass.
This commit is contained in:
Jason
2025-10-10 15:47:57 +08:00
parent 6cf7dacd0e
commit 56b2681a6f
5 changed files with 119 additions and 3 deletions

View File

@@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Provider } from "../types";
import { AppType } from "../lib/tauri-api";
@@ -18,6 +18,31 @@ const EditProviderModal: React.FC<EditProviderModalProps> = ({
onClose,
}) => {
const { t } = useTranslation();
const [effectiveProvider, setEffectiveProvider] = useState<Provider>(provider);
// 若为当前应用且正在编辑“当前供应商”,则优先读取 live 配置作为初始值Claude/Codex 均适用)
useEffect(() => {
let mounted = true;
const maybeLoadLive = async () => {
try {
const currentId = await window.api.getCurrentProvider(appType);
if (currentId && currentId === provider.id) {
const live = await window.api.getLiveProviderSettings(appType);
if (!mounted) return;
setEffectiveProvider({ ...provider, settingsConfig: live });
} else {
setEffectiveProvider(provider);
}
} catch (e) {
// 读取失败则回退到原 provider
setEffectiveProvider(provider);
}
};
maybeLoadLive();
return () => {
mounted = false;
};
}, [appType, provider]);
const handleSubmit = (data: Omit<Provider, "id">) => {
onSave({
@@ -31,7 +56,7 @@ const EditProviderModal: React.FC<EditProviderModalProps> = ({
appType={appType}
title={t("common.edit")}
submitText={t("common.save")}
initialData={provider}
initialData={effectiveProvider}
showPresets={false}
onSubmit={handleSubmit}
onClose={onClose}

View File

@@ -429,6 +429,22 @@ export const tauriAPI = {
}
},
// 读取当前生效live的 provider settings根据 appType
// Codex: { auth: object, config: string }
// Claude: settings.json 内容
getLiveProviderSettings: async (app?: AppType): Promise<any> => {
try {
return await invoke<any>("read_live_provider_settings", {
app_type: app,
app,
appType: app,
});
} catch (error) {
console.error("读取 live 配置失败:", error);
throw error;
}
},
// ours: 第三方/自定义供应商——测速与端点管理
// 第三方/自定义供应商:批量测试端点延迟
testApiEndpoints: async (

4
src/vite-env.d.ts vendored
View File

@@ -96,6 +96,10 @@ declare global {
syncEnabledMcpToCodex: () => Promise<boolean>;
importMcpFromClaude: () => Promise<number>;
importMcpFromCodex: () => Promise<number>;
// 读取当前生效live的 provider settings根据 appType
// Codex: { auth: object, config: string }
// Claude: settings.json 内容
getLiveProviderSettings: (app?: AppType) => Promise<any>;
testApiEndpoints: (
urls: string[],
options?: { timeoutSecs?: number },