📄 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 - 不再需要迁移逻辑