- feat(codex): 引入 Codex 应用与供应商切换(管理 auth.json/config.toml,支持备份与恢复)

- feat(core): 多应用配置 v2(claude/codex)与 ProviderManager;支持 v1→v2 自动迁移
- feat(ui): 新增 Codex 页签与双编辑器表单;统一 window.api 支持 app 参数
- feat(tauri): 新增 get_config_status/open_config_folder/open_external 命令并适配 Codex
- fix(codex): 主配置缺失时不执行默认导入(对齐 Claude 行为)
- chore: 配置目录展示与重启提示等细节优化
This commit is contained in:
Jason
2025-08-30 21:54:11 +08:00
parent 0e803b53d8
commit c10ace7a84
13 changed files with 891 additions and 279 deletions

View File

@@ -1,5 +1,6 @@
import { useState, useEffect, useRef } from "react";
import { Provider } from "./types";
import { AppType } from "./lib/tauri-api";
import ProviderList from "./components/ProviderList";
import AddProviderModal from "./components/AddProviderModal";
import EditProviderModal from "./components/EditProviderModal";
@@ -7,6 +8,7 @@ import { ConfirmDialog } from "./components/ConfirmDialog";
import "./App.css";
function App() {
const [activeApp, setActiveApp] = useState<AppType>("claude");
const [providers, setProviders] = useState<Record<string, Provider>>({});
const [currentProviderId, setCurrentProviderId] = useState<string>("");
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
@@ -60,7 +62,7 @@ function App() {
useEffect(() => {
loadProviders();
loadConfigStatus();
}, []);
}, [activeApp]); // 当切换应用时重新加载
// 清理定时器
useEffect(() => {
@@ -72,8 +74,8 @@ function App() {
}, []);
const loadProviders = async () => {
const loadedProviders = await window.api.getProviders();
const currentId = await window.api.getCurrentProvider();
const loadedProviders = await window.api.getProviders(activeApp);
const currentId = await window.api.getCurrentProvider(activeApp);
setProviders(loadedProviders);
setCurrentProviderId(currentId);
@@ -84,7 +86,7 @@ function App() {
};
const loadConfigStatus = async () => {
const status = await window.api.getClaudeConfigStatus();
const status = await window.api.getConfigStatus(activeApp);
setConfigStatus({
exists: Boolean(status?.exists),
path: String(status?.path || ""),
@@ -101,14 +103,14 @@ function App() {
...provider,
id: generateId(),
};
await window.api.addProvider(newProvider);
await window.api.addProvider(newProvider, activeApp);
await loadProviders();
setIsAddModalOpen(false);
};
const handleEditProvider = async (provider: Provider) => {
try {
await window.api.updateProvider(provider);
await window.api.updateProvider(provider, activeApp);
await loadProviders();
setEditingProviderId(null);
// 显示编辑成功提示
@@ -127,7 +129,7 @@ function App() {
title: "删除供应商",
message: `确定要删除供应商 "${provider?.name}" 吗?此操作无法撤销。`,
onConfirm: async () => {
await window.api.deleteProvider(id);
await window.api.deleteProvider(id, activeApp);
await loadProviders();
setConfirmDialog(null);
showNotification("供应商删除成功", "success");
@@ -136,12 +138,13 @@ function App() {
};
const handleSwitchProvider = async (id: string) => {
const success = await window.api.switchProvider(id);
const success = await window.api.switchProvider(id, activeApp);
if (success) {
setCurrentProviderId(id);
// 显示重启提示
const appName = activeApp === "claude" ? "Claude Code" : "Codex";
showNotification(
"切换成功!请重启 Claude Code 终端以生效",
`切换成功!请重启 ${appName} 终端以生效`,
"success",
2000,
);
@@ -153,7 +156,7 @@ function App() {
// 自动导入现有配置为"default"供应商
const handleAutoImportDefault = async () => {
try {
const result = await window.api.importCurrentConfigAsDefault();
const result = await window.api.importCurrentConfigAsDefault(activeApp);
if (result.success) {
await loadProviders();
@@ -171,13 +174,27 @@ function App() {
};
const handleOpenConfigFolder = async () => {
await window.api.openConfigFolder();
await window.api.openConfigFolder(activeApp);
};
return (
<div className="app">
<header className="app-header">
<h1>Claude Code </h1>
<div className="app-tabs">
<button
className={`app-tab ${activeApp === "claude" ? "active" : ""}`}
onClick={() => setActiveApp("claude")}
>
Claude Code
</button>
<button
className={`app-tab ${activeApp === "codex" ? "active" : ""}`}
onClick={() => setActiveApp("codex")}
>
Codex
</button>
</div>
<h1>{activeApp === "claude" ? "Claude Code" : "Codex"} </h1>
<div className="header-actions">
<button className="add-btn" onClick={() => setIsAddModalOpen(true)}>
@@ -228,6 +245,7 @@ function App() {
{isAddModalOpen && (
<AddProviderModal
appType={activeApp}
onAdd={handleAddProvider}
onClose={() => setIsAddModalOpen(false)}
/>
@@ -235,6 +253,7 @@ function App() {
{editingProviderId && providers[editingProviderId] && (
<EditProviderModal
appType={activeApp}
provider={providers[editingProviderId]}
onSave={handleEditProvider}
onClose={() => setEditingProviderId(null)}