# 自定义模型选择功能 - TDD 开发计划

## 任务背景

在选择默认模型的步骤里增加一个自定义选项，让用户可以输入自定义模型名称。自定义模型和其他预设选项的配置方式不同：
- 预设选项（default/opus/opusplan）：继续使用 `model` 字段
- 自定义选项：删除 `model` 字段，改用环境变量 `ANTHROPIC_MODEL` 和 `ANTHROPIC_SMALL_FAST_MODEL`

支持输入框跳过功能，如果两个输入框都跳过则不改配置。

## 技术上下文

- **项目架构**：TypeScript + inquirer.js + i18next
- **现有模型选择位置**：`src/utils/features.ts:326-347`
- **配置更新函数**：`src/utils/config.ts:148` updateDefaultModel()
- **测试框架**：Vitest，TDD 模式开发

## TDD 执行计划

### 阶段 1：类型定义 (Red-Green-Refactor)

#### 1.1 Red - 编写失败测试
- **文件**：`tests/unit/utils/config.test.ts`
- **测试内容**：
  - `updateDefaultModel('custom')` 应该被接受
  - 类型检查不应报错

#### 1.2 Green - 最小实现
- **文件**：`src/types/config.ts:15`
  ```typescript
  model?: 'opus' | 'sonnet' | 'opusplan' | 'custom'
  ```
- **文件**：`src/utils/config.ts:148`
  ```typescript
  export function updateDefaultModel(model: 'opus' | 'sonnet' | 'opusplan' | 'default' | 'custom'): void
  ```

#### 1.3 Refactor - 类型优化
- 添加 JSDoc 注释
- 确保类型一致性

### 阶段 2：自定义输入功能 (Red-Green-Refactor)

#### 2.1 Red - 编写交互测试
- **文件**：`tests/unit/utils/features.test.ts`
- **测试用例**：
  - 应该显示自定义选项
  - 选择自定义后应该提示两个输入框
  - 空输入应该被认为是跳过
  - 两个都跳过应该不调用配置更新

#### 2.2 Green - 实现输入功能
- **文件**：`src/utils/features.ts:326-347`
  ```typescript
  // 在 choices 数组添加自定义选项
  {
    name: i18n.t('configuration:customModelOption') || 'Custom - Specify custom model names',
    value: 'custom' as const,
  }
  
  // 处理自定义输入
  if (model === 'custom') {
    const customConfig = await promptCustomModels()
    if (customConfig.shouldSkip) {
      console.log('已跳过自定义模型配置')
      return
    }
    updateCustomModel(customConfig.primaryModel, customConfig.fastModel)
  } else {
    updateDefaultModel(model)
  }
  ```

#### 2.3 Refactor - 提取函数
- 提取 `promptCustomModels()` 辅助函数
- 优化用户体验提示

### 阶段 3：配置更新逻辑 (Red-Green-Refactor)

#### 3.1 Red - 编写配置测试
- **文件**：`tests/unit/utils/config.test.ts`
- **测试用例**：
  - `custom` 应该删除 `model` 字段
  - 应该设置 `ANTHROPIC_MODEL` 环境变量
  - 应该设置 `ANTHROPIC_SMALL_FAST_MODEL` 环境变量
  - 跳过的字段不应该设置环境变量
  - 两个都跳过不应该修改配置

#### 3.2 Green - 实现配置逻辑
- **文件**：`src/utils/config.ts`
  ```typescript
  export function updateCustomModel(primaryModel?: string, fastModel?: string): void {
    // 两个都没输入，不修改配置
    if (!primaryModel?.trim() && !fastModel?.trim()) {
      return
    }
    
    let settings = getDefaultSettings()
    const existingSettings = readJsonConfig<ClaudeSettings>(SETTINGS_FILE)
    if (existingSettings) {
      settings = existingSettings
    }
    
    // 删除 model 字段
    delete settings.model
    
    // 设置环境变量
    settings.env = settings.env || {}
    if (primaryModel?.trim()) {
      settings.env.ANTHROPIC_MODEL = primaryModel.trim()
    }
    if (fastModel?.trim()) {
      settings.env.ANTHROPIC_SMALL_FAST_MODEL = fastModel.trim()
    }
    
    writeJsonConfig(SETTINGS_FILE, settings)
  }
  ```

#### 3.3 Refactor - 优化配置合并
- 提取环境变量设置函数
- 优化配置合并逻辑

### 阶段 4：国际化支持 (Red-Green-Refactor)

#### 4.1 Red - 编写 i18n 测试
- 测试翻译键存在性
- 测试中英文完整性

#### 4.2 Green - 添加翻译
- **文件**：`src/i18n/locales/zh-CN/configuration.json`
  ```json
  {
    "customModelOption": "自定义 - 指定自定义模型名称",
    "enterPrimaryModel": "请输入主要使用的模型名称（直接回车跳过）",
    "enterFastModel": "请输入后台任务的快速模型名称（直接回车跳过）",
    "customModelSkipped": "已跳过自定义模型配置",
    "customModelConfigured": "自定义模型配置完成"
  }
  ```
- **文件**：`src/i18n/locales/en/configuration.json`
  ```json
  {
    "customModelOption": "Custom - Specify custom model names", 
    "enterPrimaryModel": "Enter primary model name (press Enter to skip)",
    "enterFastModel": "Enter fast model name for background tasks (press Enter to skip)",
    "customModelSkipped": "Custom model configuration skipped",
    "customModelConfigured": "Custom model configuration completed"
  }
  ```

#### 4.3 Refactor - 优化翻译
- 统一翻译键命名
- 优化文案表达

### 阶段 5：集成测试 (Red-Green-Refactor)

#### 5.1 Red - 编写集成测试
- **文件**：`tests/integration/custom-model.test.ts`
- **测试场景**：
  - 完整用户流程测试
  - 配置文件读写测试
  - 错误处理测试

#### 5.2 Green - 完善错误处理
- 用户取消操作处理
- 文件写入错误处理
- 友好错误提示

#### 5.3 Refactor - 优化集成
- 提取错误处理函数
- 优化用户体验流程

## 预期结果

### 功能输出
- 模型选择列表新增"自定义"选项
- 选择自定义后出现两个输入框
- 支持单个或全部跳过功能
- 自定义模型配置写入环境变量

### 配置文件输出示例
```json
{
  "env": {
    "ANTHROPIC_MODEL": "claude-3-5-sonnet-20241022",
    "ANTHROPIC_SMALL_FAST_MODEL": "claude-3-haiku-20240307"
  }
}
```

### 测试覆盖目标
- 单元测试：95%+ 覆盖率
- 集成测试：完整用户流程
- 边界测试：错误处理和跳过场景

## 开发规范
- 严格遵循 TDD：Red → Green → Refactor
- 每个测试用例先失败，再实现通过
- 所有代码必须有对应测试
- 国际化支持完整
- 向后兼容性保证