👤 用户
可以,给hermes提供原子级的可执行指令
🤖 DeepSeek 助手

一、环境准备与现状快照

# 1. 进入项目根目录
cd /home/administrator/CmdCode-V0.5

# 2. 备份当前状态(万一需要回滚)
cp -r /home/administrator/CmdCode-V0.5 /home/administrator/CmdCode-V0.5.backup.$(date +%Y%m%d_%H%M%S)

# 3. 确认加密工具已就绪
grep -n 'encryptSecret\|decryptSecret' src/crypto-util.ts

# 4. 查看当前 models_config.json 内容
cat models_config.json | python3 -c "import sys,json; d=json.load(sys.stdin); [print(k,': ****') for k in d]"

二、扩展加密存储结构

修改文件:src/crypto-util.ts

新增模型密钥专用读写函数:

interface ModelKeyRecord {
  provider: string;
  apiKey: string;
}

export function loadModelKeys(): ModelKeyRecord[] {
  const secrets = loadSecrets();
  const raw = secrets['model_keys'];
  if (!raw) return [];
  try {
    return JSON.parse(decryptSecret(raw));
  } catch {
    return [];
  }
}

export function saveModelKeys(keys: ModelKeyRecord[]): void {
  const secrets = loadSecrets();
  secrets['model_keys'] = encryptSecret(JSON.stringify(keys));
  saveSecrets(secrets);
}

export function upsertModelKey(provider: string, apiKey: string): void {
  const keys = loadModelKeys();
  const idx = keys.findIndex(k => k.provider === provider);
  if (idx >= 0) {
    keys[idx].apiKey = apiKey;
  } else {
    keys.push({ provider, apiKey });
  }
  saveModelKeys(keys);
}

export function removeModelKey(provider: string): void {
  const keys = loadModelKeys().filter(k => k.provider !== provider);
  saveModelKeys(keys);
}

三、实现迁移命令 /migrate-keys

新建文件:src/commands/migrate-keys.ts

import * as fs from 'fs';
import * as path from 'path';
import { loadModelKeys, saveModelKeys, upsertModelKey } from '../crypto-util';

export async function runMigrateKeys(): Promise {
  const configPath = path.join(process.cwd(), 'models_config.json');

  if (!fs.existsSync(configPath)) {
    console.log('未发现 models_config.json,无需迁移。');
    return;
  }

  const raw = fs.readFileSync(configPath, 'utf-8');
  const legacyConfigs: LegacyConfig[] = JSON.parse(raw);

  let migrated = 0;
  for (const cfg of legacyConfigs) {
    if (cfg.apiKey && cfg.provider) {
      upsertModelKey(cfg.provider, cfg.apiKey);
      migrated++;
    }
  }

  if (migrated > 0) {
    console.log(`成功迁移 ${migrated} 个提供商的 API Key 到加密存储。`);
    const backupPath = configPath + '.backup';
    fs.copyFileSync(configPath, backupPath);
    fs.writeFileSync(configPath, '[]', 'utf-8'); // 覆盖为空数组,而非删除
    console.log(`原文件已备份为 ${backupPath} 并清空。`);
  }
}

四、修改运行时密钥加载逻辑

修改文件:src/user-models.ts

import { loadModelKeys } from './crypto-util';

function getApiKeyForProvider(provider: string): string {
  const envMap: Record = {
    deepseek: 'DEEPSEEK_API_KEY',
    minimax: 'MINIMAX_API_KEY',
    // ...
  };
  if (envMap[provider] && process.env[envMap[provider]]) {
    return process.env[envMap[provider]]!;
  }
  const keys = loadModelKeys();
  const found = keys.find(k => k.provider === provider);
  if (found) return found.apiKey;
  throw new Error(`未找到提供商 ${provider} 的 API Key`);
}

五、更新帮助信息与启动提示

src/cli.ts 启动时检测明文 Key:

if (existsSync('models_config.json')) {
  const raw = readFileSync('models_config.json', 'utf-8');
  if (raw.includes('"apiKey"')) {
    console.log('🔐 检测到未加密的 API Key 配置文件,建议执行 /migrate-keys 进行加密迁移。');
  }
}

六、清理与验证

# 运行迁移命令
CmdCode> /migrate-keys

# 检查原文件是否已清空且备份存在
cat models_config.json
ls -la models_config.json.backup

# 测试模型连接功能
CmdCode> /model minimax-m2.7
# 发送一条测试消息,确认正常响应

# 确认无误后删除明文备份
rm models_config.json.backup

七、回滚预案

# 恢复原 models_config.json
cp models_config.json.backup models_config.json

# 或恢复整个项目备份
cp -r /home/administrator/CmdCode-V0.5.backup.XXXXXX/* /home/administrator/CmdCode-V0.5/

以上指令可直接交给 Hermes 逐步执行。所有修改限于 3 个现有文件(crypto-util.ts, user-models.ts, cli.ts)+ 1 个新文件(migrate-keys.ts),无外部依赖,风险可控。