// 供应商配置处理工具函数 const isPlainObject = (value: unknown): value is Record => { return Object.prototype.toString.call(value) === "[object Object]"; }; const deepMerge = ( target: Record, source: Record, ): Record => { Object.entries(source).forEach(([key, value]) => { if (isPlainObject(value)) { if (!isPlainObject(target[key])) { target[key] = {}; } deepMerge(target[key], value); } else { // 直接覆盖非对象字段(数组/基础类型) target[key] = value; } }); return target; }; const deepRemove = (target: Record, source: Record) => { Object.entries(source).forEach(([key, value]) => { if (!(key in target)) return; if (isPlainObject(value) && isPlainObject(target[key])) { // 只移除完全匹配的嵌套属性 deepRemove(target[key], value); if (Object.keys(target[key]).length === 0) { delete target[key]; } } else if (isSubset(target[key], value)) { // 只有当值完全匹配时才删除 delete target[key]; } }); }; const isSubset = (target: any, source: any): boolean => { if (isPlainObject(source)) { if (!isPlainObject(target)) return false; return Object.entries(source).every(([key, value]) => isSubset(target[key], value), ); } if (Array.isArray(source)) { if (!Array.isArray(target) || target.length !== source.length) return false; return source.every((item, index) => isSubset(target[index], item)); } return target === source; }; // 深拷贝函数 const deepClone = (obj: T): T => { if (obj === null || typeof obj !== "object") return obj; if (obj instanceof Date) return new Date(obj.getTime()) as T; if (obj instanceof Array) return obj.map(item => deepClone(item)) as T; if (obj instanceof Object) { const clonedObj = {} as T; for (const key in obj) { if (obj.hasOwnProperty(key)) { clonedObj[key] = deepClone(obj[key]); } } return clonedObj; } return obj; }; export interface UpdateCommonConfigResult { updatedConfig: string; error?: string; } // 将通用配置片段写入/移除 settingsConfig export const updateCommonConfigSnippet = ( jsonString: string, snippetString: string, enabled: boolean, ): UpdateCommonConfigResult => { let config: Record; try { config = jsonString ? JSON.parse(jsonString) : {}; } catch (err) { return { updatedConfig: jsonString, error: "配置 JSON 解析失败,无法写入通用配置", }; } if (!snippetString.trim()) { return { updatedConfig: JSON.stringify(config, null, 2), }; } let snippet: Record; try { const parsed = JSON.parse(snippetString); if (!isPlainObject(parsed)) { return { updatedConfig: JSON.stringify(config, null, 2), error: "通用配置片段必须是 JSON 对象", }; } snippet = parsed; } catch (err) { return { updatedConfig: JSON.stringify(config, null, 2), error: "通用配置片段格式错误,需为合法 JSON", }; } if (enabled) { const merged = deepMerge(deepClone(config), snippet); return { updatedConfig: JSON.stringify(merged, null, 2), }; } const cloned = deepClone(config); deepRemove(cloned, snippet); return { updatedConfig: JSON.stringify(cloned, null, 2), }; }; // 检查当前配置是否已包含通用配置片段 export const hasCommonConfigSnippet = ( jsonString: string, snippetString: string, ): boolean => { try { if (!snippetString.trim()) return false; const config = jsonString ? JSON.parse(jsonString) : {}; const snippet = JSON.parse(snippetString); if (!isPlainObject(snippet)) return false; return isSubset(config, snippet); } catch (err) { return false; } }; // 读取配置中的 API Key(env.ANTHROPIC_AUTH_TOKEN) export const getApiKeyFromConfig = (jsonString: string): string => { try { const config = JSON.parse(jsonString); const key = config?.env?.ANTHROPIC_AUTH_TOKEN; return typeof key === "string" ? key : ""; } catch (err) { return ""; } }; // 判断配置中是否存在 API Key 字段 export const hasApiKeyField = (jsonString: string): boolean => { try { const config = JSON.parse(jsonString); return Object.prototype.hasOwnProperty.call( config?.env ?? {}, "ANTHROPIC_AUTH_TOKEN", ); } catch (err) { return false; } }; // 写入/更新配置中的 API Key,默认不新增缺失字段 export const setApiKeyInConfig = ( jsonString: string, apiKey: string, options: { createIfMissing?: boolean } = {}, ): string => { const { createIfMissing = false } = options; try { const config = JSON.parse(jsonString); if (!config.env) { if (!createIfMissing) return jsonString; config.env = {}; } if (!("ANTHROPIC_AUTH_TOKEN" in config.env) && !createIfMissing) { return jsonString; } config.env.ANTHROPIC_AUTH_TOKEN = apiKey; return JSON.stringify(config, null, 2); } catch (err) { return jsonString; } };