From e0908701b48d2f689da7280d3f8c5a48d592bbac Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 3 Oct 2025 20:03:55 +0800 Subject: [PATCH] Remove deprecated VS Code Codex integration --- CHANGELOG.md | 8 +- README.md | 5 +- docs/roadmap.md | 1 - src-tauri/src/commands.rs | 40 -------- src-tauri/src/lib.rs | 4 - src-tauri/src/vscode.rs | 65 ------------- src/App.tsx | 72 +-------------- src/components/ProviderList.tsx | 152 ------------------------------- src/components/SettingsModal.tsx | 2 - src/hooks/useVSCodeAutoSync.ts | 99 -------------------- src/i18n/locales/en.json | 9 -- src/i18n/locales/zh.json | 9 -- src/lib/tauri-api.ts | 34 ------- src/utils/vscodeSettings.ts | 134 --------------------------- src/vite-env.d.ts | 4 - 15 files changed, 9 insertions(+), 629 deletions(-) delete mode 100644 src-tauri/src/vscode.rs delete mode 100644 src/hooks/useVSCodeAutoSync.ts delete mode 100644 src/utils/vscodeSettings.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 251cda7..9a7edbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### ✨ Features - Enable internationalization via i18next with a Chinese default and English fallback, plus an in-app language switcher -- Add Claude plugin sync alongside the existing VS Code integration controls +- Add Claude plugin sync while retiring the legacy VS Code integration controls (Codex no longer requires settings.json edits) - Extend provider presets with optional API key URLs and updated models, including DeepSeek-V3.1-Terminus and Qwen3-Max - Support portable mode launches and enforce a single running instance to avoid conflicts @@ -22,13 +22,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### 🐛 Fixes - Remove the unnecessary OpenAI auth requirement from third-party provider configurations - Fix layout shifts while switching app types with Claude plugin sync enabled -- Align Enable/In Use button states to avoid visual jank across VS Code and Codex views +- Align Enable/In Use button states to avoid visual jank across app views ## [3.3.0] - 2025-09-22 ### ✨ Features -- Add “Apply to VS Code / Remove from VS Code” actions on provider cards, writing settings for Code/Insiders/VSCodium variants -- Enable VS Code auto-sync by default with window broadcast and tray hooks so Codex switches sync silently +- Add “Apply to VS Code / Remove from VS Code” actions on provider cards, writing settings for Code/Insiders/VSCodium variants *(Removed in 3.4.x)* +- Enable VS Code auto-sync by default with window broadcast and tray hooks so Codex switches sync silently *(Removed in 3.4.x)* - Extend the Codex provider wizard with display name, dedicated API key URL, and clearer guidance - Introduce shared common config snippets with JSON/TOML reuse, validation, and consistent error surfaces diff --git a/README.md b/README.md index aae3e74..7d5c910 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ > v3.4.0 :新增 i18next 国际化(还有部分未完成)、对新模型(qwen-3-max, GLM-4.6, DeepSeek-V3.2-Exp)的支持、Claude 插件、单实例守护、托盘最小化及安装器优化等。 -> v3.3.0 :VS Code Codex 插件一键配置/移除(默认自动同步)、Codex 通用配置片段与自定义向导增强、WSL 环境支持、跨平台托盘与 UI 优化。 +> v3.3.0 :VS Code Codex 插件一键配置/移除(默认自动同步)、Codex 通用配置片段与自定义向导增强、WSL 环境支持、跨平台托盘与 UI 优化。(该 VS Code 写入功能已在 v3.4.x 停用) > v3.2.0 :全新 UI、macOS系统托盘、内置更新器、原子写入与回滚、改进暗色样式、单一事实源(SSOT)与一次性迁移/归档。 @@ -19,7 +19,8 @@ ## 功能特性(v3.4.0) - **国际化与语言切换**:内置 i18next,默认显示中文,可在设置中快速切换到英文,界面文文案自动实时刷新。 -- **Claude 插件同步**:在 VS Code 同步按钮旁新增 Claude 插件同步选项,与 Codex 同步互不冲突,切换供应商后立即应用。 +- **Claude 插件同步**:内置按钮可一键应用或恢复 Claude 插件配置,切换供应商后立即生效。 +- **VS Code Codex 设置停用**:由于新版 Codex 插件无需修改 `settings.json`,应用不再写入 VS Code 设置,避免潜在冲突。 - **供应商预设扩展**:新增 DeepSeek--V3.2-Exp、Qwen3-Max、GLM-4.6 等最新模型。 - **系统托盘与窗口行为**:窗口关闭可最小化到托盘,macOS 支持托盘模式下隐藏/显示 Dock,托盘切换时同步 Claude/Codex/插件状态。 - **单实例**:保证同一时间仅运行一个实例,避免多开冲突。 diff --git a/docs/roadmap.md b/docs/roadmap.md index 8025459..a4d6cdd 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -5,4 +5,3 @@ - i18n - gemini cli - homebrew 支持 -- 自定义 vscode 路径 diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index c8098e6..02d72ed 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -11,7 +11,6 @@ use crate::codex_config; use crate::config::{self, get_claude_settings_path, ConfigStatus}; use crate::provider::Provider; use crate::store::AppState; -use crate::vscode; fn validate_provider_settings(app_type: &AppType, provider: &Provider) -> Result<(), String> { match app_type { @@ -693,45 +692,6 @@ pub async fn is_portable_mode() -> Result { } } -/// VS Code: 获取用户 settings.json 状态 -#[tauri::command] -pub async fn get_vscode_settings_status() -> Result { - if let Some(p) = vscode::find_existing_settings() { - Ok(ConfigStatus { - exists: true, - path: p.to_string_lossy().to_string(), - }) - } else { - // 默认返回 macOS 稳定版路径(或其他平台首选项的第一个候选),但标记不存在 - let preferred = vscode::candidate_settings_paths().into_iter().next(); - Ok(ConfigStatus { - exists: false, - path: preferred.unwrap_or_default().to_string_lossy().to_string(), - }) - } -} - -/// VS Code: 读取 settings.json 文本(仅当文件存在) -#[tauri::command] -pub async fn read_vscode_settings() -> Result { - if let Some(p) = vscode::find_existing_settings() { - std::fs::read_to_string(&p).map_err(|e| format!("读取 VS Code 设置失败: {}", e)) - } else { - Err("未找到 VS Code 用户设置文件".to_string()) - } -} - -/// VS Code: 写入 settings.json 文本(仅当文件存在;不自动创建) -#[tauri::command] -pub async fn write_vscode_settings(content: String) -> Result { - if let Some(p) = vscode::find_existing_settings() { - config::write_text_file(&p, &content)?; - Ok(true) - } else { - Err("未找到 VS Code 用户设置文件".to_string()) - } -} - /// Claude 插件:获取 ~/.claude/config.json 状态 #[tauri::command] pub async fn get_claude_plugin_status() -> Result { diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index f7ecb86..5569b1d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -7,7 +7,6 @@ mod migration; mod provider; mod settings; mod store; -mod vscode; use store::AppState; use tauri::{ @@ -416,9 +415,6 @@ pub fn run() { commands::save_settings, commands::check_for_updates, commands::is_portable_mode, - commands::get_vscode_settings_status, - commands::read_vscode_settings, - commands::write_vscode_settings, commands::get_claude_plugin_status, commands::read_claude_plugin_config, commands::apply_claude_plugin_config, diff --git a/src-tauri/src/vscode.rs b/src-tauri/src/vscode.rs deleted file mode 100644 index dbcfdf2..0000000 --- a/src-tauri/src/vscode.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::path::PathBuf; - -/// 枚举可能的 VS Code 发行版配置目录名称 -fn vscode_product_dirs() -> Vec<&'static str> { - vec![ - "Code", // VS Code Stable - "Code - Insiders", // VS Code Insiders - "VSCodium", // VSCodium - "Code - OSS", // OSS 发行版 - ] -} - -/// 获取 VS Code 用户 settings.json 的候选路径列表(按优先级排序) -pub fn candidate_settings_paths() -> Vec { - let mut paths = Vec::new(); - - #[cfg(target_os = "macos")] - { - if let Some(home) = dirs::home_dir() { - for prod in vscode_product_dirs() { - paths.push( - home.join("Library") - .join("Application Support") - .join(prod) - .join("User") - .join("settings.json"), - ); - } - } - } - - #[cfg(target_os = "windows")] - { - // Windows: %APPDATA%\Code\User\settings.json - if let Some(roaming) = dirs::config_dir() { - for prod in vscode_product_dirs() { - paths.push(roaming.join(prod).join("User").join("settings.json")); - } - } - } - - #[cfg(all(unix, not(target_os = "macos")))] - { - // Linux: ~/.config/Code/User/settings.json - if let Some(config) = dirs::config_dir() { - for prod in vscode_product_dirs() { - paths.push(config.join(prod).join("User").join("settings.json")); - } - } - } - - paths -} - -/// 返回第一个存在的 settings.json 路径 -pub fn find_existing_settings() -> Option { - for p in candidate_settings_paths() { - if let Ok(meta) = std::fs::metadata(&p) { - if meta.is_file() { - return Some(p); - } - } - } - None -} diff --git a/src/App.tsx b/src/App.tsx index c7dfea2..a900ffd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,14 +13,10 @@ import { Plus, Settings, Moon, Sun } from "lucide-react"; import { buttonStyles } from "./lib/styles"; import { useDarkMode } from "./hooks/useDarkMode"; import { extractErrorMessage } from "./utils/errorUtils"; -import { applyProviderToVSCode } from "./utils/vscodeSettings"; -import { getCodexBaseUrl } from "./utils/providerConfigUtils"; -import { useVSCodeAutoSync } from "./hooks/useVSCodeAutoSync"; function App() { const { t } = useTranslation(); const { isDarkMode, toggleDarkMode } = useDarkMode(); - const { isAutoSyncEnabled } = useVSCodeAutoSync(); const [activeApp, setActiveApp] = useState("claude"); const [providers, setProviders] = useState>({}); const [currentProviderId, setCurrentProviderId] = useState(""); @@ -98,11 +94,7 @@ function App() { await loadProviders(); } - // 若为 Codex 且开启自动同步,则静默同步到 VS Code(覆盖) - if (data.appType === "codex" && isAutoSyncEnabled) { - await syncCodexToVSCode(data.providerId, true); - } - + // 若为 Claude,则同步插件配置 if (data.appType === "claude") { await syncClaudePlugin(data.providerId, true); } @@ -120,7 +112,7 @@ function App() { unlisten(); } }; - }, [activeApp, isAutoSyncEnabled]); + }, [activeApp]); const loadProviders = async () => { const loadedProviders = await window.api.getProviders(activeApp); @@ -189,61 +181,6 @@ function App() { }); }; - // 同步Codex供应商到VS Code设置(静默覆盖) - const syncCodexToVSCode = async (providerId: string, silent = false) => { - try { - const status = await window.api.getVSCodeSettingsStatus(); - if (!status.exists) { - if (!silent) { - showNotification( - t("notifications.vscodeSettingsNotFound"), - "error", - 3000 - ); - } - return; - } - - const raw = await window.api.readVSCodeSettings(); - const provider = providers[providerId]; - const isOfficial = provider?.category === "official"; - - // 非官方供应商需要解析 base_url(使用公共工具函数) - let baseUrl: string | undefined = undefined; - if (!isOfficial) { - const parsed = getCodexBaseUrl(provider); - if (!parsed) { - if (!silent) { - showNotification(t("notifications.missingBaseUrl"), "error", 4000); - } - return; - } - baseUrl = parsed; - } - - const updatedSettings = applyProviderToVSCode(raw, { - baseUrl, - isOfficial, - }); - if (updatedSettings !== raw) { - await window.api.writeVSCodeSettings(updatedSettings); - if (!silent) { - showNotification(t("notifications.syncedToVSCode"), "success", 1500); - } - } - - // 触发providers重新加载,以更新VS Code按钮状态 - await loadProviders(); - } catch (error: any) { - console.error(t("console.syncToVSCodeFailed"), error); - if (!silent) { - const errorMessage = - error?.message || t("notifications.syncVSCodeFailed"); - showNotification(errorMessage, "error", 5000); - } - } - }; - // 同步 Claude 插件配置(写入/移除固定 JSON) const syncClaudePlugin = async (providerId: string, silent = false) => { try { @@ -284,11 +221,6 @@ function App() { // 更新托盘菜单 await window.api.updateTrayMenu(); - // Codex: 切换供应商后,只在自动同步启用时同步到 VS Code - if (activeApp === "codex" && isAutoSyncEnabled) { - await syncCodexToVSCode(id, true); // silent模式,不显示通知 - } - if (activeApp === "claude") { await syncClaudePlugin(id, true); } diff --git a/src/components/ProviderList.tsx b/src/components/ProviderList.tsx index 2394183..cd187d5 100644 --- a/src/components/ProviderList.tsx +++ b/src/components/ProviderList.tsx @@ -4,13 +4,6 @@ import { Provider } from "../types"; import { Play, Edit3, Trash2, CheckCircle2, Users, Check } from "lucide-react"; import { buttonStyles, cardStyles, badgeStyles, cn } from "../lib/styles"; import { AppType } from "../lib/tauri-api"; -import { - applyProviderToVSCode, - detectApplied, - normalizeBaseUrl, -} from "../utils/vscodeSettings"; -import { getCodexBaseUrl } from "../utils/providerConfigUtils"; -import { useVSCodeAutoSync } from "../hooks/useVSCodeAutoSync"; // 不再在列表中显示分类徽章,避免造成困惑 interface ProviderListProps { @@ -65,46 +58,8 @@ const ProviderList: React.FC = ({ } }; - // 解析 Codex 配置中的 base_url(已提取到公共工具) - - // VS Code 按钮:仅在 Codex + 当前供应商显示;按钮文案根据是否"已应用"变化 - const [vscodeAppliedFor, setVscodeAppliedFor] = useState(null); - const { enableAutoSync, disableAutoSync } = useVSCodeAutoSync(); const [claudeApplied, setClaudeApplied] = useState(false); - // 当当前供应商或 appType 变化时,尝试读取 VS Code settings 并检测状态 - useEffect(() => { - const check = async () => { - if (appType !== "codex" || !currentProviderId) { - setVscodeAppliedFor(null); - return; - } - const status = await window.api.getVSCodeSettingsStatus(); - if (!status.exists) { - setVscodeAppliedFor(null); - return; - } - try { - const content = await window.api.readVSCodeSettings(); - const detected = detectApplied(content); - // 认为“已应用”的条件(非官方供应商):VS Code 中的 apiBase 与当前供应商的 base_url 完全一致 - const current = providers[currentProviderId]; - let applied = false; - if (current && current.category !== "official") { - const base = getCodexBaseUrl(current); - if (detected.apiBase && base) { - applied = - normalizeBaseUrl(detected.apiBase) === normalizeBaseUrl(base); - } - } - setVscodeAppliedFor(applied ? currentProviderId : null); - } catch { - setVscodeAppliedFor(null); - } - }; - check(); - }, [appType, currentProviderId, providers]); - // 检查 Claude 插件配置是否已应用 useEffect(() => { const checkClaude = async () => { @@ -123,83 +78,6 @@ const ProviderList: React.FC = ({ checkClaude(); }, [appType, currentProviderId, providers]); - const handleApplyToVSCode = async (provider: Provider) => { - try { - const status = await window.api.getVSCodeSettingsStatus(); - if (!status.exists) { - onNotify?.(t("notifications.vscodeSettingsNotFound"), "error", 3000); - return; - } - - const raw = await window.api.readVSCodeSettings(); - - const isOfficial = provider.category === "official"; - // 非官方且缺少 base_url 时直接报错并返回,避免“空写入”假成功 - if (!isOfficial) { - const parsed = getCodexBaseUrl(provider); - if (!parsed) { - onNotify?.(t("notifications.missingBaseUrl"), "error", 4000); - return; - } - } - - const baseUrl = isOfficial ? undefined : getCodexBaseUrl(provider); - const next = applyProviderToVSCode(raw, { baseUrl, isOfficial }); - - if (next === raw) { - // 幂等:没有变化也提示成功 - onNotify?.(t("notifications.appliedToVSCode"), "success", 3000); - setVscodeAppliedFor(provider.id); - // 用户手动应用时,启用自动同步 - enableAutoSync(); - return; - } - - await window.api.writeVSCodeSettings(next); - onNotify?.(t("notifications.appliedToVSCode"), "success", 3000); - setVscodeAppliedFor(provider.id); - // 用户手动应用时,启用自动同步 - enableAutoSync(); - } catch (e: any) { - console.error(e); - const msg = - e && e.message ? e.message : t("notifications.syncVSCodeFailed"); - onNotify?.(msg, "error", 5000); - } - }; - - const handleRemoveFromVSCode = async () => { - try { - const status = await window.api.getVSCodeSettingsStatus(); - if (!status.exists) { - onNotify?.(t("notifications.vscodeSettingsNotFound"), "error", 3000); - return; - } - const raw = await window.api.readVSCodeSettings(); - const next = applyProviderToVSCode(raw, { - baseUrl: undefined, - isOfficial: true, - }); - if (next === raw) { - onNotify?.(t("notifications.removedFromVSCode"), "success", 3000); - setVscodeAppliedFor(null); - // 用户手动移除时,禁用自动同步 - disableAutoSync(); - return; - } - await window.api.writeVSCodeSettings(next); - onNotify?.(t("notifications.removedFromVSCode"), "success", 3000); - setVscodeAppliedFor(null); - // 用户手动移除时,禁用自动同步 - disableAutoSync(); - } catch (e: any) { - console.error(e); - const msg = - e && e.message ? e.message : t("notifications.syncVSCodeFailed"); - onNotify?.(msg, "error", 5000); - } - }; - const handleApplyToClaudePlugin = async () => { try { await window.api.applyClaudePluginConfig({ official: false }); @@ -320,36 +198,6 @@ const ProviderList: React.FC = ({
- {/* 同步按钮占位容器 - 只在对应模式下渲染,避免布局跳动 */} - {appType === "codex" ? ( -
- {provider.category !== "official" && isCurrent && ( - - )} -
- ) : null} - {appType === "claude" ? (
{provider.category !== "official" && isCurrent && ( diff --git a/src/components/SettingsModal.tsx b/src/components/SettingsModal.tsx index 589b8df..ca727ef 100644 --- a/src/components/SettingsModal.tsx +++ b/src/components/SettingsModal.tsx @@ -435,8 +435,6 @@ export default function SettingsModal({ onClose }: SettingsModalProps) {
- {/* VS Code 自动同步设置已移除 */} - {/* 配置文件位置 */}

diff --git a/src/hooks/useVSCodeAutoSync.ts b/src/hooks/useVSCodeAutoSync.ts deleted file mode 100644 index c762eab..0000000 --- a/src/hooks/useVSCodeAutoSync.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; - -const VSCODE_AUTO_SYNC_KEY = "vscode-auto-sync-enabled"; -const VSCODE_AUTO_SYNC_EVENT = "vscode-auto-sync-changed"; - -export function useVSCodeAutoSync() { - // 默认开启自动同步;若本地存储存在记录,则以记录为准 - const [isAutoSyncEnabled, setIsAutoSyncEnabled] = useState(true); - - // 从 localStorage 读取初始状态 - useEffect(() => { - try { - const saved = localStorage.getItem(VSCODE_AUTO_SYNC_KEY); - if (saved !== null) { - setIsAutoSyncEnabled(saved === "true"); - } - } catch (error) { - console.error("读取自动同步状态失败:", error); - } - }, []); - - // 订阅同窗口的自定义事件,以及跨窗口的 storage 事件,实现全局同步 - useEffect(() => { - const onCustom = (e: Event) => { - try { - const detail = (e as CustomEvent).detail as - | { enabled?: boolean } - | undefined; - if (detail && typeof detail.enabled === "boolean") { - setIsAutoSyncEnabled(detail.enabled); - } else { - // 兜底:从 localStorage 读取 - const saved = localStorage.getItem(VSCODE_AUTO_SYNC_KEY); - if (saved !== null) setIsAutoSyncEnabled(saved === "true"); - } - } catch { - // 忽略 - } - }; - const onStorage = (e: StorageEvent) => { - if (e.key === VSCODE_AUTO_SYNC_KEY) { - setIsAutoSyncEnabled(e.newValue === "true"); - } - }; - window.addEventListener(VSCODE_AUTO_SYNC_EVENT, onCustom as EventListener); - window.addEventListener("storage", onStorage); - return () => { - window.removeEventListener( - VSCODE_AUTO_SYNC_EVENT, - onCustom as EventListener, - ); - window.removeEventListener("storage", onStorage); - }; - }, []); - - // 启用自动同步 - const enableAutoSync = useCallback(() => { - try { - localStorage.setItem(VSCODE_AUTO_SYNC_KEY, "true"); - setIsAutoSyncEnabled(true); - // 通知同窗口其他订阅者 - window.dispatchEvent( - new CustomEvent(VSCODE_AUTO_SYNC_EVENT, { detail: { enabled: true } }), - ); - } catch (error) { - console.error("保存自动同步状态失败:", error); - } - }, []); - - // 禁用自动同步 - const disableAutoSync = useCallback(() => { - try { - localStorage.setItem(VSCODE_AUTO_SYNC_KEY, "false"); - setIsAutoSyncEnabled(false); - // 通知同窗口其他订阅者 - window.dispatchEvent( - new CustomEvent(VSCODE_AUTO_SYNC_EVENT, { detail: { enabled: false } }), - ); - } catch (error) { - console.error("保存自动同步状态失败:", error); - } - }, []); - - // 切换自动同步状态 - const toggleAutoSync = useCallback(() => { - if (isAutoSyncEnabled) { - disableAutoSync(); - } else { - enableAutoSync(); - } - }, [isAutoSyncEnabled, enableAutoSync, disableAutoSync]); - - return { - isAutoSyncEnabled, - enableAutoSync, - disableAutoSync, - toggleAutoSync, - }; -} diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 61eb92d..71bd97c 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -38,8 +38,6 @@ "addNewProvider": "Add New Provider", "configError": "Configuration Error", "notConfigured": "Not configured for official website", - "applyToVSCode": "Apply to VS Code", - "removeFromVSCode": "Remove from VS Code", "applyToClaudePlugin": "Apply to Claude plugin", "removeFromClaudePlugin": "Remove from Claude plugin" }, @@ -49,14 +47,8 @@ "switchSuccess": "Switch successful! Please restart {{appName}} terminal to take effect", "switchFailed": "Switch failed, please check configuration", "autoImported": "Default provider created from existing configuration", - "appliedToVSCode": "Applied to VS Code, restart Codex plugin to take effect", - "removedFromVSCode": "Removed from VS Code, restart Codex plugin to take effect", - "syncedToVSCode": "Synced to VS Code", - "vscodeSettingsNotFound": "VS Code user settings file (settings.json) not found", - "missingBaseUrl": "Current configuration missing base_url, cannot write to VS Code", "saveFailed": "Save failed: {{error}}", "saveFailedGeneric": "Save failed, please try again", - "syncVSCodeFailed": "Sync to VS Code failed", "appliedToClaudePlugin": "Applied to Claude plugin", "removedFromClaudePlugin": "Removed from Claude plugin", "syncClaudePluginFailed": "Sync Claude plugin failed" @@ -101,7 +93,6 @@ "providerSwitchReceived": "Received provider switch event:", "setupListenerFailed": "Failed to setup provider switch listener:", "updateProviderFailed": "Update provider failed:", - "syncToVSCodeFailed": "Sync to VS Code failed:", "autoImportFailed": "Auto import default configuration failed:", "openLinkFailed": "Failed to open link:", "getVersionFailed": "Failed to get version info:", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index 3339e6a..9ca0b09 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -38,8 +38,6 @@ "addNewProvider": "添加新供应商", "configError": "配置错误", "notConfigured": "未配置官网地址", - "applyToVSCode": "应用到 VS Code", - "removeFromVSCode": "从 VS Code 移除", "applyToClaudePlugin": "应用到 Claude 插件", "removeFromClaudePlugin": "从 Claude 插件移除" }, @@ -49,14 +47,8 @@ "switchSuccess": "切换成功!请重启 {{appName}} 终端以生效", "switchFailed": "切换失败,请检查配置", "autoImported": "已从现有配置创建默认供应商", - "appliedToVSCode": "已应用到 VS Code,重启 Codex 插件以生效", - "removedFromVSCode": "已从 VS Code 移除,重启 Codex 插件以生效", - "syncedToVSCode": "已同步到 VS Code", - "vscodeSettingsNotFound": "未找到 VS Code 用户设置文件 (settings.json)", - "missingBaseUrl": "当前配置缺少 base_url,无法写入 VS Code", "saveFailed": "保存失败:{{error}}", "saveFailedGeneric": "保存失败,请重试", - "syncVSCodeFailed": "同步 VS Code 失败", "appliedToClaudePlugin": "已应用到 Claude 插件", "removedFromClaudePlugin": "已从 Claude 插件移除", "syncClaudePluginFailed": "同步 Claude 插件失败" @@ -101,7 +93,6 @@ "providerSwitchReceived": "收到供应商切换事件:", "setupListenerFailed": "设置供应商切换监听器失败:", "updateProviderFailed": "更新供应商失败:", - "syncToVSCodeFailed": "同步到VS Code失败:", "autoImportFailed": "自动导入默认配置失败:", "openLinkFailed": "打开链接失败:", "getVersionFailed": "获取版本信息失败:", diff --git a/src/lib/tauri-api.ts b/src/lib/tauri-api.ts index 414a670..f480ef3 100644 --- a/src/lib/tauri-api.ts +++ b/src/lib/tauri-api.ts @@ -197,8 +197,6 @@ export const tauriAPI = { }); }, - // (保留空位,取消迁移提示) - // 选择配置目录 selectConfigDirectory: async ( defaultPath?: string, @@ -275,38 +273,6 @@ export const tauriAPI = { } }, - // VS Code: 获取 settings.json 状态 - getVSCodeSettingsStatus: async (): Promise<{ - exists: boolean; - path: string; - error?: string; - }> => { - try { - return await invoke("get_vscode_settings_status"); - } catch (error) { - console.error("获取 VS Code 设置状态失败:", error); - return { exists: false, path: "", error: String(error) }; - } - }, - - // VS Code: 读取 settings.json 文本 - readVSCodeSettings: async (): Promise => { - try { - return await invoke("read_vscode_settings"); - } catch (error) { - throw new Error(`读取 VS Code 设置失败: ${String(error)}`); - } - }, - - // VS Code: 写回 settings.json 文本(不自动创建) - writeVSCodeSettings: async (content: string): Promise => { - try { - return await invoke("write_vscode_settings", { content }); - } catch (error) { - throw new Error(`写入 VS Code 设置失败: ${String(error)}`); - } - }, - // Claude 插件:获取 ~/.claude/config.json 状态 getClaudePluginStatus: async (): Promise => { try { diff --git a/src/utils/vscodeSettings.ts b/src/utils/vscodeSettings.ts deleted file mode 100644 index ccd5a86..0000000 --- a/src/utils/vscodeSettings.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { applyEdits, modify, parse } from "jsonc-parser"; - -const fmt = { insertSpaces: true, tabSize: 2, eol: "\n" } as const; - -export interface AppliedCheck { - hasApiBase: boolean; - apiBase?: string; - hasPreferredAuthMethod: boolean; -} - -export function normalizeBaseUrl(url: string): string { - return url.replace(/\/+$/, ""); -} - -const isDocEmpty = (s: string) => s.trim().length === 0; - -// 检查 settings.json(JSONC 文本)中是否已经应用了我们的键 -export function detectApplied(content: string): AppliedCheck { - try { - // 允许 JSONC 的宽松解析:jsonc-parser 的 parse 可以直接处理注释 - const data = parse(content) as any; - const apiBase = data?.["chatgpt.apiBase"]; - const method = data?.["chatgpt.config"]?.preferred_auth_method; - return { - hasApiBase: typeof apiBase === "string", - apiBase, - hasPreferredAuthMethod: typeof method === "string", - }; - } catch { - return { hasApiBase: false, hasPreferredAuthMethod: false }; - } -} - -// 生成“清理我们管理的键”后的文本(仅删除我们写入的两个键) -export function removeManagedKeys(content: string): string { - if (isDocEmpty(content)) return content; // 空文档无需删除 - let out = content; - // 删除 chatgpt.apiBase - try { - out = applyEdits( - out, - modify(out, ["chatgpt.apiBase"], undefined, { formattingOptions: fmt }), - ); - } catch { - // 忽略删除失败 - } - // 删除 chatgpt.config.preferred_auth_method(注意 chatgpt.config 是顶层带点的键) - try { - out = applyEdits( - out, - modify(out, ["chatgpt.config", "preferred_auth_method"], undefined, { - formattingOptions: fmt, - }), - ); - } catch { - // 忽略删除失败 - } - - // 兼容早期错误写入:若曾写成嵌套 chatgpt.config.preferred_auth_method,也一并清理 - try { - out = applyEdits( - out, - modify(out, ["chatgpt", "config", "preferred_auth_method"], undefined, { - formattingOptions: fmt, - }), - ); - } catch { - // 忽略删除失败 - } - - // 清理 chatgpt.config 的异常情况: - // 1. 早期遗留的标量值(字符串/数字/null等) - // 2. 空对象 - // 3. 数组类型 - try { - const data = parse(out) as any; - const cfg = data?.["chatgpt.config"]; - - // 需要清理的情况: - // - 标量值(null、字符串、数字等) - // - 数组 - // - 空对象 - const shouldRemove = cfg !== undefined && ( - cfg === null || - typeof cfg !== "object" || - Array.isArray(cfg) || - (typeof cfg === "object" && Object.keys(cfg).length === 0) - ); - - if (shouldRemove) { - out = applyEdits( - out, - modify(out, ["chatgpt.config"], undefined, { formattingOptions: fmt }), - ); - } - } catch { - // 忽略解析失败,保持已删除的键 - } - - return out; -} - -// 生成“应用供应商到 VS Code”后的文本: -// - 先清理我们管理的键 -// - 再根据是否官方决定写入(官方:不写入;非官方:写入两个键) -export function applyProviderToVSCode( - content: string, - opts: { baseUrl?: string | null; isOfficial?: boolean }, -): string { - let out = removeManagedKeys(content); - if (!opts.isOfficial && opts.baseUrl) { - const apiBase = normalizeBaseUrl(opts.baseUrl); - if (isDocEmpty(out)) { - // 简化:空文档直接写入新对象 - const obj: any = { - "chatgpt.apiBase": apiBase, - "chatgpt.config": { preferred_auth_method: "apikey" }, - }; - out = JSON.stringify(obj, null, 2) + "\n"; - } else { - out = applyEdits( - out, - modify(out, ["chatgpt.apiBase"], apiBase, { formattingOptions: fmt }), - ); - out = applyEdits( - out, - modify(out, ["chatgpt.config", "preferred_auth_method"], "apikey", { - formattingOptions: fmt, - }), - ); - } - } - return out; -} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index dec0a3a..c44ff28 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -42,10 +42,6 @@ declare global { isPortable: () => Promise; getAppConfigPath: () => Promise; openAppConfigFolder: () => Promise; - // VS Code settings.json 能力 - getVSCodeSettingsStatus: () => Promise; - readVSCodeSettings: () => Promise; - writeVSCodeSettings: (content: string) => Promise; // Claude 插件配置能力 getClaudePluginStatus: () => Promise; readClaudePluginConfig: () => Promise;