📄 config.ts • 3381 bytes
/**
* CmdCode V0.5 - 配置管理(简化版)
* 所有敏感信息统一存储在 secrets.enc
* 支持密钥池轮换机制
*/
import {
loadChatKeyPool, addChatKey, maskSecret, hasSecrets,
loadAppConfig, saveAppConfig,
getChatApiKey, getChatKeyPoolStatus,
type KeyPoolEntry, type AppSettings
} from './apikeys.js'
export interface Config {
apiKey: string
baseUrl: string
model: string
timeoutMs: number
keyName?: string // 密钥名称(用于显示)
}
export interface SafeConfig {
apiKey: string
baseUrl: string
model: string
timeoutMs: number
keySource: string
configSource: string
keyPoolStatus?: { total: number; exhausted: number; remaining: number }
}
const DEFAULT_CONFIG = {
baseUrl: 'https://api.minimaxi.com/v1',
model: 'MiniMax-M2.7',
timeoutMs: 600_000,
}
/** 加载运行时配置 */
export function loadConfig(): Config {
// 1. 用户自定义密钥池(加密存储)- 最高优先级
const pool = loadChatKeyPool()
const customKey = pool.find(e => e.name === 'user-custom')
if (customKey) {
// 需要解密 apiKey
const { decryptField } = require('./crypto-util.js')
const appConfig = loadAppConfig()
try {
const decryptedKey = decryptField(customKey.apiKeyEncrypted)
return {
apiKey: decryptedKey,
baseUrl: customKey.baseUrl || DEFAULT_CONFIG.baseUrl,
model: appConfig?.model || DEFAULT_CONFIG.model,
timeoutMs: DEFAULT_CONFIG.timeoutMs,
keyName: 'user-custom',
}
} catch {
// 解密失败,继续尝试密钥池
}
}
// 2. 从默认密钥池获取(混合池:MiniMax → GLM)
const poolKey = getChatApiKey()
if (poolKey) {
const appConfig = loadAppConfig()
return {
apiKey: poolKey.apiKey,
baseUrl: poolKey.baseUrl,
model: appConfig?.model || poolKey.model,
timeoutMs: DEFAULT_CONFIG.timeoutMs,
keyName: poolKey.name,
}
}
// 3. 密钥池用尽
return {
apiKey: '',
baseUrl: DEFAULT_CONFIG.baseUrl,
model: DEFAULT_CONFIG.model,
timeoutMs: DEFAULT_CONFIG.timeoutMs,
keyName: 'exhausted',
}
}
/** 安全配置(脱敏) */
export function loadSafeConfig(): SafeConfig {
const config = loadConfig()
const poolStatus = getChatKeyPoolStatus()
let keySource = '默认密钥池'
let configSource = '默认值'
if (loadChatKeyPool().some(e => e.name === 'user-custom')) {
keySource = '用户自定义'
configSource = hasSecrets() ? '加密存储' : '默认值'
} else if (config.keyName && config.keyName.startsWith('minimax')) {
keySource = `密钥池 [${config.keyName}]`
} else if (config.keyName === 'exhausted') {
keySource = '⚠️ 密钥池已耗尽'
}
return {
apiKey: maskSecret(config.apiKey),
baseUrl: config.baseUrl,
model: config.model,
timeoutMs: config.timeoutMs,
keySource,
configSource,
keyPoolStatus: poolStatus,
}
}
export function setApiKey(apiKey: string, baseUrl?: string): void {
// 添加到密钥池(name=user-custom)
addChatKey('user-custom', DEFAULT_CONFIG.model, baseUrl || DEFAULT_CONFIG.baseUrl, apiKey)
}
export function updateAppConfig(partial: AppSettings): void {
saveAppConfig(partial)
}
export function getAppConfig(): AppSettings | null {
return loadAppConfig()
}
// 删除 autoMigrate - 不再需要迁移逻辑