mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +08:00
992dda5c5c
* refactor(provider): switch from full config overwrite to partial key-field merging Replace the provider switching mechanism for Claude/Codex/Gemini from full settings_config overwrite to partial key-field replacement, preserving user's non-provider settings (plugins, MCP, permissions, etc.) across switches. - Add write_live_partial() with per-app implementations for Claude (JSON env merge), Codex (auth replace + TOML partial merge), and Gemini (env merge) - Add backfill_key_fields() to extract only provider-specific fields when saving live config back to provider entries - Update switch_normal, sync_current_to_live, add, update to use partial merge - Remove common config snippet feature for Claude/Codex/Gemini (no longer needed with partial merging); preserve OMO common config - Delete 6 frontend files (3 components + 3 hooks), clean up 11 modified files - Remove backend extract_common_config_* methods, 3 Tauri commands, CommonConfigSnippets struct, and related migration code - Update integration tests to validate key-field-only backfill behavior * refactor(cleanup): remove dead code and redundant MCP sync after partial-merge refactor - Remove ConfigService legacy full-overwrite sync methods (~150 lines) - Remove redundant McpService::sync_all_enabled from switch_normal - Switch proxy fallback recovery from write_live_snapshot to write_live_partial - Remove dead ProviderService::write_gemini_live wrapper - Update tests to reflect partial-merge behavior (MCP preserved, not re-synced) * feat(claude): add Quick Toggles for common Claude Code preferences Add checkbox toggles for hideAttribution, alwaysThinking, and enableTeammates that write directly to the live settings file via RFC 7396 JSON Merge Patch. Mirror changes to the form editor using form.watch for reactive updates. * fix(provider): add missing key fields to partial-merge constants Add provider-specific fields verified against official docs to prevent key residue or loss during provider switching: - Claude: CLAUDE_CODE_SUBAGENT_MODEL (env), model (top-level) - Codex: review_model, plan_mode_reasoning_effort - Gemini: GOOGLE_API_KEY (official alternative to GEMINI_API_KEY) * fix(provider): expand partial-merge key fields for Bedrock, Vertex, Foundry and behavior settings Add missing env/top-level fields to CLAUDE_KEY_ENV_FIELDS and CLAUDE_KEY_TOP_LEVEL so that provider switching correctly replaces (and clears) credentials and flags for AWS Bedrock, Google Vertex AI, Microsoft Foundry, and provider behavior overrides like max output tokens and prompt caching. * feat(provider): add auth field selector for Claude providers (AUTH_TOKEN / API_KEY) Allow users to choose between ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY when creating or editing custom Claude providers, persisted in meta.apiKeyField. * refactor(preset): remove AiHubMix hardcoded API_KEY in favor of generic auth selector AiHubMix was the only preset that hardcoded ANTHROPIC_API_KEY before the generic auth field selector was introduced. Now that users can freely choose between AUTH_TOKEN and API_KEY via the UI, remove the special-case and default AiHubMix to the standard ANTHROPIC_AUTH_TOKEN.
106 lines
2.6 KiB
TypeScript
106 lines
2.6 KiB
TypeScript
import { useEffect, useState, useCallback } from "react";
|
|
import type { ProviderCategory } from "@/types";
|
|
import {
|
|
getApiKeyFromConfig,
|
|
setApiKeyInConfig,
|
|
hasApiKeyField,
|
|
} from "@/utils/providerConfigUtils";
|
|
|
|
interface UseApiKeyStateProps {
|
|
initialConfig?: string;
|
|
onConfigChange: (config: string) => void;
|
|
selectedPresetId: string | null;
|
|
category?: ProviderCategory;
|
|
appType?: string;
|
|
apiKeyField?: string;
|
|
}
|
|
|
|
/**
|
|
* 管理 API Key 输入状态
|
|
* 自动同步 API Key 和 JSON 配置
|
|
*/
|
|
export function useApiKeyState({
|
|
initialConfig,
|
|
onConfigChange,
|
|
selectedPresetId,
|
|
category,
|
|
appType,
|
|
apiKeyField,
|
|
}: UseApiKeyStateProps) {
|
|
const [apiKey, setApiKey] = useState(() => {
|
|
if (initialConfig) {
|
|
return getApiKeyFromConfig(initialConfig, appType);
|
|
}
|
|
return "";
|
|
});
|
|
|
|
// 当外部通过 form.reset / 读取 live 等方式更新配置时,同步回 API Key 状态
|
|
// - 仅在 JSON 可解析时同步,避免用户编辑 JSON 过程中因临时无效导致输入框闪烁
|
|
useEffect(() => {
|
|
if (!initialConfig) return;
|
|
|
|
try {
|
|
JSON.parse(initialConfig);
|
|
} catch {
|
|
return;
|
|
}
|
|
|
|
// 从配置中提取 API Key(如果不存在则返回空字符串)
|
|
const extracted = getApiKeyFromConfig(initialConfig, appType);
|
|
if (extracted !== apiKey) {
|
|
setApiKey(extracted);
|
|
}
|
|
}, [initialConfig, appType, apiKey]);
|
|
|
|
const handleApiKeyChange = useCallback(
|
|
(key: string) => {
|
|
setApiKey(key);
|
|
|
|
const configString = setApiKeyInConfig(
|
|
initialConfig || "{}",
|
|
key.trim(),
|
|
{
|
|
// 最佳实践:仅在"新增模式"且"非官方类别"时补齐缺失字段
|
|
// - 新增模式:selectedPresetId !== null
|
|
// - 非官方类别:category !== undefined && category !== "official"
|
|
// - 官方类别:不创建字段(UI 也会禁用输入框)
|
|
// - 未传入 category:不创建字段(避免意外行为)
|
|
createIfMissing:
|
|
selectedPresetId !== null &&
|
|
category !== undefined &&
|
|
category !== "official",
|
|
appType,
|
|
apiKeyField,
|
|
},
|
|
);
|
|
|
|
onConfigChange(configString);
|
|
},
|
|
[
|
|
initialConfig,
|
|
selectedPresetId,
|
|
category,
|
|
appType,
|
|
apiKeyField,
|
|
onConfigChange,
|
|
],
|
|
);
|
|
|
|
const showApiKey = useCallback(
|
|
(config: string, isEditMode: boolean) => {
|
|
return (
|
|
selectedPresetId !== null ||
|
|
(isEditMode && hasApiKeyField(config, appType))
|
|
);
|
|
},
|
|
[selectedPresetId, appType],
|
|
);
|
|
|
|
return {
|
|
apiKey,
|
|
setApiKey,
|
|
handleApiKeyChange,
|
|
showApiKey,
|
|
};
|
|
}
|