重大重构:从字段替换切换到完整配置文件切换系统
- 实现基于文件重命名的供应商切换机制,支持完整settings.json配置切换 - 移除所有向后兼容代码,简化为纯JSON配置模式 - 添加导入当前配置功能,解决首次使用时配置丢失问题 - 移除描述字段,简化用户界面 - 完整的错误处理和回滚机制确保配置安全 - 清理所有调试代码,优化代码质量
This commit is contained in:
@@ -3,13 +3,11 @@ import path from 'path'
|
||||
import os from 'os'
|
||||
import { Provider } from '../shared/types'
|
||||
|
||||
interface ClaudeCodeConfig {
|
||||
env?: {
|
||||
ANTHROPIC_AUTH_TOKEN?: string
|
||||
ANTHROPIC_BASE_URL?: string
|
||||
[key: string]: string | undefined
|
||||
}
|
||||
[key: string]: any
|
||||
/**
|
||||
* 清理供应商名称,确保文件名安全
|
||||
*/
|
||||
export function sanitizeProviderName(name: string): string {
|
||||
return name.replace(/[<>:"/\\|?*]/g, '-').toLowerCase()
|
||||
}
|
||||
|
||||
export function getClaudeCodeConfig() {
|
||||
@@ -20,37 +18,157 @@ export function getClaudeCodeConfig() {
|
||||
return { path: configPath, dir: configDir }
|
||||
}
|
||||
|
||||
export async function switchProvider(provider: Provider): Promise<boolean> {
|
||||
try {
|
||||
const { path: configPath, dir: configDir } = getClaudeCodeConfig()
|
||||
/**
|
||||
* 获取供应商配置文件路径
|
||||
*/
|
||||
export function getProviderConfigPath(providerId: string): string {
|
||||
const { dir } = getClaudeCodeConfig()
|
||||
return path.join(dir, `settings-${sanitizeProviderName(providerId)}.json`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存供应商配置到独立文件
|
||||
*/
|
||||
export async function saveProviderConfig(provider: Provider): Promise<boolean> {
|
||||
try {
|
||||
const { dir } = getClaudeCodeConfig()
|
||||
const providerConfigPath = getProviderConfigPath(provider.id)
|
||||
|
||||
// 确保目录存在
|
||||
await fs.mkdir(dir, { recursive: true })
|
||||
|
||||
// 保存配置到供应商专用文件
|
||||
await fs.writeFile(
|
||||
providerConfigPath,
|
||||
JSON.stringify(provider.settingsConfig, null, 2),
|
||||
'utf-8'
|
||||
)
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('保存供应商配置失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否存在
|
||||
*/
|
||||
export async function fileExists(filePath: string): Promise<boolean> {
|
||||
try {
|
||||
await fs.access(filePath)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换供应商配置(基于文件重命名)
|
||||
*/
|
||||
export async function switchProvider(provider: Provider, currentProviderId?: string): Promise<boolean> {
|
||||
try {
|
||||
const { path: settingsPath, dir: configDir } = getClaudeCodeConfig()
|
||||
const newSettingsPath = getProviderConfigPath(provider.id)
|
||||
|
||||
// 确保目录存在
|
||||
await fs.mkdir(configDir, { recursive: true })
|
||||
|
||||
// 读取现有配置
|
||||
let config: ClaudeCodeConfig = {}
|
||||
try {
|
||||
const content = await fs.readFile(configPath, 'utf-8')
|
||||
config = JSON.parse(content)
|
||||
} catch {
|
||||
// 文件不存在或解析失败,使用空配置
|
||||
|
||||
// 检查目标配置文件是否存在
|
||||
if (!(await fileExists(newSettingsPath))) {
|
||||
console.error(`供应商配置文件不存在: ${newSettingsPath}`)
|
||||
return false
|
||||
}
|
||||
|
||||
// 确保 env 对象存在
|
||||
if (!config.env) {
|
||||
config.env = {}
|
||||
|
||||
// 1. 如果当前存在settings.json,先备份到当前供应商的配置文件
|
||||
if (await fileExists(settingsPath)) {
|
||||
if (currentProviderId) {
|
||||
const currentProviderPath = getProviderConfigPath(currentProviderId)
|
||||
await fs.rename(settingsPath, currentProviderPath)
|
||||
} else {
|
||||
// 如果没有当前供应商ID,创建临时备份
|
||||
const backupPath = path.join(configDir, `settings-backup-${Date.now()}.json`)
|
||||
await fs.rename(settingsPath, backupPath)
|
||||
console.log(`已备份当前配置到: ${backupPath}`)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新环境变量配置
|
||||
config.env.ANTHROPIC_AUTH_TOKEN = provider.apiKey
|
||||
config.env.ANTHROPIC_BASE_URL = provider.apiUrl
|
||||
|
||||
// 写回配置文件
|
||||
await fs.writeFile(configPath, JSON.stringify(config, null, 2))
|
||||
|
||||
|
||||
// 2. 将目标供应商配置重命名为settings.json
|
||||
await fs.rename(newSettingsPath, settingsPath)
|
||||
|
||||
console.log(`成功切换到供应商: ${provider.name}`)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('切换供应商失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入当前 settings.json 配置为一个供应商
|
||||
*/
|
||||
export async function importCurrentConfig(name: string): Promise<{ success: boolean; provider?: Provider }> {
|
||||
try {
|
||||
const { path: settingsPath } = getClaudeCodeConfig()
|
||||
|
||||
// 检查当前配置是否存在
|
||||
if (!(await fileExists(settingsPath))) {
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
// 读取当前配置
|
||||
const configContent = await fs.readFile(settingsPath, 'utf-8')
|
||||
const settingsConfig = JSON.parse(configContent)
|
||||
|
||||
// 生成唯一的供应商ID
|
||||
let providerId = name.toLowerCase().replace(/[^a-z0-9]/g, '-')
|
||||
let counter = 1
|
||||
|
||||
// 检查ID是否已存在,如果存在则添加数字后缀
|
||||
while (await fileExists(getProviderConfigPath(providerId))) {
|
||||
providerId = `${name.toLowerCase().replace(/[^a-z0-9]/g, '-')}-${counter}`
|
||||
counter++
|
||||
}
|
||||
|
||||
// 创建供应商对象
|
||||
const provider: Provider = {
|
||||
id: providerId,
|
||||
name: name,
|
||||
settingsConfig: settingsConfig,
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now()
|
||||
}
|
||||
|
||||
// 保存为供应商配置
|
||||
const success = await saveProviderConfig(provider)
|
||||
|
||||
if (success) {
|
||||
console.log(`已导入当前配置为供应商: ${name} (${providerId})`)
|
||||
return { success: true, provider }
|
||||
} else {
|
||||
return { success: false }
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('导入当前配置失败:', error)
|
||||
return { success: false }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除供应商配置文件
|
||||
*/
|
||||
export async function deleteProviderConfig(providerId: string): Promise<boolean> {
|
||||
try {
|
||||
const providerConfigPath = getProviderConfigPath(providerId)
|
||||
|
||||
if (await fileExists(providerConfigPath)) {
|
||||
await fs.unlink(providerConfigPath)
|
||||
console.log(`已删除供应商配置文件: ${providerConfigPath}`)
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('删除供应商配置失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user