Skip to content

Commit fb7dbe0

Browse files
WitMiaoclaude
andcommitted
chore: release v2.9.11
- Update version to 2.9.11 - Update CHANGELOG.md with new features and optimizations - Add OpusPlan model option for hybrid strategy - Add Opus-only mode option - Refactor preset selection ordering logic - Generated by /zcf-release command 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 47c958e commit fb7dbe0

11 files changed

Lines changed: 131 additions & 30 deletions

File tree

CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
# Changelog
22

3+
## 2.9.11
4+
5+
### Patch Changes
6+
7+
- ## 新功能
8+
9+
- 新增 OpusPlan 模型选项,支持用 Opus 做计划,Sonnet 编写代码的混合策略
10+
- 添加 Opus 独占模式选项,提供更高质量但更高成本的处理能力
11+
12+
## New Features
13+
14+
- Add OpusPlan model option - use Opus for planning and Sonnet for coding (recommended hybrid strategy)
15+
- Add Opus-only mode option for higher quality but higher cost processing
16+
17+
## 优化
18+
19+
- 重构预设选择排序逻辑,提升用户体验
20+
- 优化代码导入顺序,提升可读性
21+
- 改进模型配置选项的描述文本
22+
23+
## Optimization
24+
25+
- Refactor preset selection ordering logic for better user experience
26+
- Optimize code import ordering for better readability
27+
- Improve model configuration option descriptions
28+
29+
## 修复
30+
31+
- 修复配置验证逻辑
32+
- 完善测试覆盖率
33+
34+
## Fixes
35+
36+
- Fix configuration validation logic
37+
- Improve test coverage
38+
339
## 2.9.10
440

541
### Patch Changes

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "zcf",
33
"type": "module",
4-
"version": "2.9.10",
4+
"version": "2.9.11",
55
"packageManager": "pnpm@9.15.9",
66
"description": "Zero-Config Claude-Code Flow - One-click configuration tool for Claude Code",
77
"license": "MIT",

src/i18n/locales/en/configuration.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ export const configuration = {
1616
currentModel: 'Current model',
1717
modifyModel: 'Modify model configuration?',
1818
keepModel: 'Keeping existing model configuration',
19-
defaultModelOption: 'Default (Let Claude Code choose)',
19+
defaultModelOption: 'Default - Let Claude Code choose',
20+
opusModelOption: 'Opus - Only use opus, high token consumption, use with caution',
21+
opusPlanModelOption: 'OpusPlan - Use Opus for planning, write code with sonnet, recommended',
2022
modelConfigured: 'Default model configured',
2123

2224
// AI memory configuration
@@ -58,7 +60,7 @@ export const configuration = {
5860
envImportSuccess: 'Environment variables imported',
5961
permissionsImportSuccess: 'Permissions imported',
6062
openingSettingsJson: 'Opening settings.json...',
61-
63+
6264
// JSON config related
6365
invalidConfiguration: 'Invalid configuration',
6466
failedToParseJson: 'Failed to parse JSON file:',

src/i18n/locales/zh-CN/configuration.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ export const configuration = {
1616
currentModel: '当前模型',
1717
modifyModel: '是否修改模型配置?',
1818
keepModel: '保持当前模型配置',
19-
defaultModelOption: '默认(让 Claude Code 自动选择)',
19+
defaultModelOption: '默认 - 让 Claude Code 自动选择',
20+
opusModelOption: 'Opus - 只用opus,token消耗高,慎用',
21+
opusPlanModelOption: 'OpusPlan - Opus做计划,sonnet编写代码,推荐',
2022
modelConfigured: '默认模型已配置',
2123

2224
// AI memory configuration
@@ -57,7 +59,7 @@ export const configuration = {
5759
envImportSuccess: '环境变量已导入',
5860
permissionsImportSuccess: '权限配置已导入',
5961
openingSettingsJson: '正在打开 settings.json...',
60-
62+
6163
// JSON config related
6264
invalidConfiguration: '配置无效',
6365
failedToParseJson: '解析 JSON 文件失败:',

src/types/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export interface StatusLineConfig {
1212
}
1313

1414
export interface ClaudeSettings {
15-
model?: 'opus' | 'sonnet';
15+
model?: 'opus' | 'sonnet' | 'opusplan';
1616
env?: {
1717
ANTHROPIC_API_KEY?: string;
1818
ANTHROPIC_AUTH_TOKEN?: string;

src/utils/config-validator.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ export function validateClaudeSettings(settings: any): settings is ClaudeSetting
1717
const i18n = getTranslation(lang);
1818

1919
// Validate model if present
20-
if (settings.model && !['opus', 'sonnet'].includes(settings.model)) {
21-
console.warn(`Invalid model: ${settings.model}. Expected 'opus' or 'sonnet'`);
20+
if (settings.model && !['opus', 'sonnet', 'opusplan'].includes(settings.model)) {
21+
console.warn(`Invalid model: ${settings.model}. Expected 'opus', 'sonnet', or 'opusplan'`);
2222
return false;
2323
}
2424

@@ -76,7 +76,7 @@ export function sanitizeClaudeSettings(settings: any): ClaudeSettings {
7676
}
7777

7878
// Copy valid model
79-
if (settings.model && ['opus', 'sonnet'].includes(settings.model)) {
79+
if (settings.model && ['opus', 'sonnet', 'opusplan'].includes(settings.model)) {
8080
sanitized.model = settings.model;
8181
}
8282

src/utils/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export function mergeConfigs(sourceFile: string, targetFile: string) {
183183
writeJsonConfig(targetFile, merged);
184184
}
185185

186-
export function updateDefaultModel(model: 'opus' | 'sonnet' | 'default') {
186+
export function updateDefaultModel(model: 'opus' | 'sonnet' | 'opusplan' | 'default') {
187187
let settings = getDefaultSettings();
188188

189189
const existingSettings = readJsonConfig<ClaudeSettings>(SETTINGS_FILE);
@@ -272,7 +272,7 @@ export function mergeSettingsFile(templatePath: string, targetPath: string): voi
272272
/**
273273
* Get existing model configuration from settings.json
274274
*/
275-
export function getExistingModelConfig(): 'opus' | 'sonnet' | 'default' | null {
275+
export function getExistingModelConfig(): 'opus' | 'sonnet' | 'opusplan' | 'default' | null {
276276
const settings = readJsonConfig<ClaudeSettings>(SETTINGS_FILE);
277277

278278
if (!settings) {

src/utils/features.ts

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,36 @@
1-
import inquirer from 'inquirer';
21
import ansis from 'ansis';
2+
import inquirer from 'inquirer';
33
import { existsSync, unlinkSync } from 'node:fs';
44
import type { SupportedLang } from '../constants';
55
import { LANG_LABELS, MCP_SERVICES, SUPPORTED_LANGS, ZCF_CONFIG_FILE } from '../constants';
66
import { getTranslation } from '../i18n';
7-
import { addNumbersToChoices } from './prompt-helpers';
87
import type { McpServerConfig } from '../types';
8+
import { configureAiPersonality } from './ai-personality';
9+
import { setupCcrConfiguration } from './ccr/config';
10+
import { installCcr, isCcrInstalled } from './ccr/installer';
911
import {
1012
applyAiLanguageDirective,
1113
configureApi,
12-
updateDefaultModel,
1314
getExistingApiConfig,
1415
getExistingModelConfig,
16+
updateDefaultModel,
1517
} from './config';
18+
import { modifyApiConfigPartially } from './config-operations';
1619
import {
20+
addCompletedOnboarding,
1721
backupMcpConfig,
1822
buildMcpServerConfig,
1923
fixWindowsMcpConfig,
2024
mergeMcpServers,
2125
readMcpConfig,
2226
writeMcpConfig,
2327
} from './mcp';
24-
import { isWindows } from './platform';
25-
import { readZcfConfig, updateZcfConfig } from './zcf-config';
26-
import { validateApiKey, formatApiKeyDisplay } from './validator';
27-
import { configureAiPersonality } from './ai-personality';
28-
import { modifyApiConfigPartially } from './config-operations';
2928
import { selectMcpServices } from './mcp-selector';
29+
import { isWindows } from './platform';
30+
import { addNumbersToChoices } from './prompt-helpers';
3031
import { importRecommendedEnv, importRecommendedPermissions, openSettingsJson } from './simple-config';
31-
import { isCcrInstalled, installCcr } from './ccr/installer';
32-
import { setupCcrConfiguration } from './ccr/config';
33-
import { addCompletedOnboarding } from './mcp';
32+
import { formatApiKeyDisplay, validateApiKey } from './validator';
33+
import { readZcfConfig, updateZcfConfig } from './zcf-config';
3434

3535
// Helper function to handle cancelled operations
3636
function handleCancellation(scriptLang: SupportedLang): void {
@@ -313,19 +313,27 @@ export async function configureDefaultModelFeature(scriptLang: SupportedLang) {
313313
}
314314
}
315315

316-
const { model } = await inquirer.prompt<{ model: 'opus' | 'sonnet' | 'default' }>({
316+
const { model } = await inquirer.prompt<{ model: 'opus' | 'sonnet' | 'opusplan' | 'default' }>({
317317
type: 'list',
318318
name: 'model',
319319
message: i18n.configuration.selectDefaultModel || 'Select default model',
320320
choices: addNumbersToChoices([
321321
{
322-
name: i18n.configuration.defaultModelOption || 'Default (Let Claude Code choose)',
322+
name: i18n.configuration.defaultModelOption || 'Default - Let Claude Code choose',
323323
value: 'default' as const,
324324
},
325-
{ name: 'Opus', value: 'opus' as const },
326-
{ name: 'Sonnet', value: 'sonnet' as const },
325+
{
326+
name: i18n.configuration.opusModelOption || 'Opus - Only use opus, high token consumption, use with caution',
327+
value: 'opus' as const,
328+
},
329+
{
330+
name:
331+
i18n.configuration.opusPlanModelOption ||
332+
'OpusPlan - Use Opus for planning, write code with sonnet, recommended',
333+
value: 'opusplan' as const,
334+
},
327335
]),
328-
default: existingModel ? ['opus', 'sonnet', 'default'].indexOf(existingModel) : 2,
336+
default: existingModel ? ['default', 'opus', 'opusplan'].indexOf(existingModel) : 0,
329337
});
330338

331339
if (!model) {
@@ -344,7 +352,7 @@ export async function configureAiMemoryFeature(scriptLang: SupportedLang) {
344352
const { option } = await inquirer.prompt<{ option: string }>({
345353
type: 'list',
346354
name: 'option',
347-
message: 'Select configuration option',
355+
message: i18n.configuration.selectMemoryOption || 'Select configuration option',
348356
choices: addNumbersToChoices([
349357
{
350358
name: i18n.configuration.configureAiLanguage || 'Configure AI output language',

test/unit/utils/config-validator.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ describe('config-validator utilities', () => {
3030
it('should validate valid model values', () => {
3131
expect(validateClaudeSettings({ model: 'opus' })).toBe(true);
3232
expect(validateClaudeSettings({ model: 'sonnet' })).toBe(true);
33+
expect(validateClaudeSettings({ model: 'opusplan' })).toBe(true);
3334
});
3435

3536
it('should reject invalid model values', () => {
3637
const consoleSpy = vi.spyOn(console, 'warn');
3738
expect(validateClaudeSettings({ model: 'invalid' })).toBe(false);
38-
expect(consoleSpy).toHaveBeenCalledWith("Invalid model: invalid. Expected 'opus' or 'sonnet'");
39+
expect(consoleSpy).toHaveBeenCalledWith("Invalid model: invalid. Expected 'opus', 'sonnet', or 'opusplan'");
3940
});
4041

4142
it('should validate env object', () => {
@@ -146,6 +147,7 @@ describe('config-validator utilities', () => {
146147
it('should copy valid model', () => {
147148
expect(sanitizeClaudeSettings({ model: 'opus' })).toEqual({ model: 'opus' });
148149
expect(sanitizeClaudeSettings({ model: 'sonnet' })).toEqual({ model: 'sonnet' });
150+
expect(sanitizeClaudeSettings({ model: 'opusplan' })).toEqual({ model: 'opusplan' });
149151
});
150152

151153
it('should filter out invalid model', () => {

test/unit/utils/config.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,20 @@ describe('config utilities', () => {
190190
})
191191
);
192192
});
193+
194+
it('should update model to opusplan', () => {
195+
const mockSettings = { model: 'opus' };
196+
vi.mocked(jsonConfig.readJsonConfig).mockReturnValue(mockSettings);
197+
198+
updateDefaultModel('opusplan');
199+
200+
expect(jsonConfig.writeJsonConfig).toHaveBeenCalledWith(
201+
SETTINGS_FILE,
202+
expect.objectContaining({
203+
model: 'opusplan',
204+
})
205+
);
206+
});
193207
});
194208

195209
describe('getExistingApiConfig', () => {
@@ -368,6 +382,14 @@ describe('config utilities', () => {
368382
expect(result).toBe('sonnet');
369383
});
370384

385+
it('should return "opusplan" when model is set to opusplan', () => {
386+
vi.mocked(jsonConfig.readJsonConfig).mockReturnValue({ model: 'opusplan' });
387+
388+
const result = getExistingModelConfig();
389+
390+
expect(result).toBe('opusplan');
391+
});
392+
371393
it('should return "default" when model is explicitly set to default', () => {
372394
vi.mocked(jsonConfig.readJsonConfig).mockReturnValue({ model: 'default' });
373395

0 commit comments

Comments
 (0)