@x-all-in-one/coding-helper 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/dist/commands/auth.js +10 -10
- package/dist/commands/config.js +17 -17
- package/dist/commands/doctor.js +14 -14
- package/dist/commands/index.d.ts +2 -2
- package/dist/commands/index.js +2 -2
- package/dist/commands/lang.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/lib/api-validator.js +7 -7
- package/dist/lib/claude-code-manager.d.ts +2 -0
- package/dist/lib/claude-code-manager.js +15 -14
- package/dist/lib/command.js +7 -7
- package/dist/lib/config.d.ts +10 -0
- package/dist/lib/config.js +14 -5
- package/dist/lib/i18n.js +4 -4
- package/dist/lib/opencode-manager.d.ts +93 -0
- package/dist/lib/opencode-manager.js +238 -0
- package/dist/lib/tool-manager.d.ts +2 -2
- package/dist/lib/tool-manager.js +65 -43
- package/dist/lib/wizard.d.ts +5 -1
- package/dist/lib/wizard.js +318 -167
- package/dist/locales/en_US.json +7 -0
- package/dist/locales/zh_CN.json +7 -0
- package/dist/utils/string-width.js +27 -27
- package/package.json +17 -16
package/dist/lib/wizard.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
2
3
|
import chalk from 'chalk';
|
|
3
|
-
import
|
|
4
|
+
import inquirer from 'inquirer';
|
|
4
5
|
import open from 'open';
|
|
6
|
+
import ora from 'ora';
|
|
5
7
|
import terminalLink from 'terminal-link';
|
|
6
|
-
import { configManager } from './config.js';
|
|
7
|
-
import { toolManager, SUPPORTED_TOOLS } from './tool-manager.js';
|
|
8
|
-
import { claudeCodeManager, DEFAULT_CONFIG } from './claude-code-manager.js';
|
|
9
|
-
import { i18n } from './i18n.js';
|
|
10
8
|
import { createBorderLine, createContentLine } from '../utils/string-width.js';
|
|
11
|
-
import { execSync } from 'child_process';
|
|
12
|
-
import { existsSync } from 'fs';
|
|
13
9
|
import { validateApiKey } from './api-validator.js';
|
|
10
|
+
import { claudeCodeManager, DEFAULT_CONFIG } from './claude-code-manager.js';
|
|
11
|
+
import { configManager } from './config.js';
|
|
12
|
+
import { i18n } from './i18n.js';
|
|
13
|
+
import { OPENCODE_DEFAULT_CONFIG, openCodeManager } from './opencode-manager.js';
|
|
14
|
+
import { SUPPORTED_TOOLS, toolManager } from './tool-manager.js';
|
|
14
15
|
// 常量定义
|
|
15
16
|
const OFFICIAL_WEBSITE = 'https://code.x-aio.com';
|
|
16
17
|
const API_KEYS_URL = 'https://code.x-aio.com/dashboard/keys';
|
|
@@ -29,7 +30,7 @@ export class Wizard {
|
|
|
29
30
|
* Create a simple box with title using double-line border style
|
|
30
31
|
*/
|
|
31
32
|
createBox(title) {
|
|
32
|
-
console.log(chalk.cyan.bold(
|
|
33
|
+
console.log(chalk.cyan.bold(`\n${createBorderLine('╔', '╗', '═', this.BOX_WIDTH)}`));
|
|
33
34
|
console.log(chalk.cyan.bold(createContentLine(title, '║', '║', this.BOX_WIDTH, 'center')));
|
|
34
35
|
console.log(chalk.cyan.bold(createBorderLine('╚', '╝', '═', this.BOX_WIDTH)));
|
|
35
36
|
console.log('');
|
|
@@ -40,9 +41,9 @@ export class Wizard {
|
|
|
40
41
|
showOperationHints() {
|
|
41
42
|
const hints = [
|
|
42
43
|
chalk.gray(i18n.t('wizard.hint_navigate')),
|
|
43
|
-
chalk.gray(i18n.t('wizard.hint_confirm'))
|
|
44
|
+
chalk.gray(i18n.t('wizard.hint_confirm')),
|
|
44
45
|
];
|
|
45
|
-
console.log(chalk.gray('💡 ') + hints.join(chalk.gray(' | '))
|
|
46
|
+
console.log(`${chalk.gray('💡 ') + hints.join(chalk.gray(' | '))}\n`);
|
|
46
47
|
}
|
|
47
48
|
/**
|
|
48
49
|
* Prompt wrapper that shows operation hints
|
|
@@ -58,12 +59,12 @@ export class Wizard {
|
|
|
58
59
|
const emptyLine = createContentLine('', '║', '║', BANNER_WIDTH, 'center');
|
|
59
60
|
const titleLine = createContentLine('Coding Helper v0.0.1', '║', '║', BANNER_WIDTH, 'center');
|
|
60
61
|
// 官网链接行
|
|
61
|
-
const websiteText = i18n.t('wizard.official_website')
|
|
62
|
+
const websiteText = `${i18n.t('wizard.official_website')}: ${OFFICIAL_WEBSITE}`;
|
|
62
63
|
const websiteLine = createContentLine(websiteText, '║', '║', BANNER_WIDTH, 'center');
|
|
63
64
|
const asciiLines = [
|
|
64
65
|
' █ █ ▄▀▄ █ ▄▀▄ ',
|
|
65
66
|
' █ ▄▄ █▀█ █ █ █ ',
|
|
66
|
-
' █ █ █ █ █ ▀▄▀ '
|
|
67
|
+
' █ █ █ █ █ ▀▄▀ ',
|
|
67
68
|
].map(line => createContentLine(line, '║', '║', BANNER_WIDTH, 'center'));
|
|
68
69
|
const bannerLines = [
|
|
69
70
|
createBorderLine('╔', '╗', '═', BANNER_WIDTH),
|
|
@@ -73,9 +74,9 @@ export class Wizard {
|
|
|
73
74
|
titleLine,
|
|
74
75
|
subtitleLine,
|
|
75
76
|
websiteLine,
|
|
76
|
-
createBorderLine('╚', '╝', '═', BANNER_WIDTH)
|
|
77
|
+
createBorderLine('╚', '╝', '═', BANNER_WIDTH),
|
|
77
78
|
];
|
|
78
|
-
console.log(chalk.cyan.bold(
|
|
79
|
+
console.log(chalk.cyan.bold(`\n${bannerLines.join('\n')}`));
|
|
79
80
|
}
|
|
80
81
|
resetScreen() {
|
|
81
82
|
console.clear();
|
|
@@ -84,8 +85,8 @@ export class Wizard {
|
|
|
84
85
|
async runFirstTimeSetup() {
|
|
85
86
|
// 清屏并显示欢迎信息
|
|
86
87
|
this.resetScreen();
|
|
87
|
-
console.log(chalk.cyan.bold(
|
|
88
|
-
console.log(chalk.gray(i18n.t('wizard.privacy_note')
|
|
88
|
+
console.log(chalk.cyan.bold(`\n${i18n.t('wizard.welcome')}`));
|
|
89
|
+
console.log(chalk.gray(`${i18n.t('wizard.privacy_note')}\n`));
|
|
89
90
|
// Step 1: Select language
|
|
90
91
|
await this.configLanguage();
|
|
91
92
|
// Step 2: Input API key
|
|
@@ -94,35 +95,32 @@ export class Wizard {
|
|
|
94
95
|
await this.showMainMenu();
|
|
95
96
|
}
|
|
96
97
|
async configLanguage() {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
configManager.setLang(language);
|
|
124
|
-
i18n.setLocale(language);
|
|
125
|
-
return;
|
|
98
|
+
this.resetScreen();
|
|
99
|
+
this.createBox(i18n.t('wizard.select_language'));
|
|
100
|
+
const currentLanguage = i18n.getLocale();
|
|
101
|
+
const { language } = await this.promptWithHints([
|
|
102
|
+
{
|
|
103
|
+
type: 'list',
|
|
104
|
+
name: 'language',
|
|
105
|
+
message: `✨ ${i18n.t('wizard.select_language')}`,
|
|
106
|
+
choices: [
|
|
107
|
+
{ name: `[EN] English${currentLanguage === 'en_US' ? chalk.green(` ✓ (${i18n.t('wizard.current_active')})`) : ''}`, value: 'en_US' },
|
|
108
|
+
{ name: `[CN] 中文${currentLanguage === 'zh_CN' ? chalk.green(` ✓ (${i18n.t('wizard.current_active')})`) : ''}`, value: 'zh_CN' },
|
|
109
|
+
new inquirer.Separator(),
|
|
110
|
+
{ name: `<- ${i18n.t('wizard.nav_return')}`, value: 'back' },
|
|
111
|
+
{ name: `x ${i18n.t('wizard.nav_exit')}`, value: 'exit' },
|
|
112
|
+
],
|
|
113
|
+
default: 'zh_CN',
|
|
114
|
+
},
|
|
115
|
+
]);
|
|
116
|
+
if (language === 'exit') {
|
|
117
|
+
console.log(chalk.green(`\n👋 ${i18n.t('wizard.goodbye_message')}`));
|
|
118
|
+
process.exit(0);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
await i18n.setLocale(language);
|
|
122
|
+
console.log(chalk.green(`\n✨ ${i18n.t('wizard.language_set')}`));
|
|
123
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
126
124
|
}
|
|
127
125
|
}
|
|
128
126
|
async configApiKey() {
|
|
@@ -131,11 +129,11 @@ export class Wizard {
|
|
|
131
129
|
this.createBox(i18n.t('wizard.config_api_key'));
|
|
132
130
|
// 显示获取 API Key 的引导链接
|
|
133
131
|
const apiKeyLink = terminalLink(i18n.t('wizard.get_api_key_link_text'), API_KEYS_URL, { fallback: () => API_KEYS_URL });
|
|
134
|
-
console.log(chalk.blue(
|
|
132
|
+
console.log(chalk.blue(` ${i18n.t('wizard.get_api_key_hint')} ${apiKeyLink}`));
|
|
135
133
|
console.log('');
|
|
136
134
|
const currentConfig = configManager.getConfig();
|
|
137
135
|
if (currentConfig.api_key) {
|
|
138
|
-
console.log(chalk.gray(
|
|
136
|
+
console.log(chalk.gray(` ${i18n.t('wizard.config_api_key')} `) + chalk.gray(`${i18n.t('wizard.api_key_set')} (${currentConfig.api_key.slice(0, 4)}****)`));
|
|
139
137
|
console.log('');
|
|
140
138
|
}
|
|
141
139
|
const { action } = await this.promptWithHints([
|
|
@@ -144,15 +142,15 @@ export class Wizard {
|
|
|
144
142
|
name: 'action',
|
|
145
143
|
message: i18n.t('wizard.select_action'),
|
|
146
144
|
choices: [
|
|
147
|
-
{ name:
|
|
145
|
+
{ name: `> ${currentConfig.api_key ? i18n.t('wizard.update_api_key') : i18n.t('wizard.input_api_key')}`, value: 'input' },
|
|
148
146
|
new inquirer.Separator(),
|
|
149
|
-
{ name:
|
|
150
|
-
{ name:
|
|
151
|
-
]
|
|
152
|
-
}
|
|
147
|
+
{ name: `<- ${i18n.t('wizard.nav_return')}`, value: 'back' },
|
|
148
|
+
{ name: `x ${i18n.t('wizard.nav_exit')}`, value: 'exit' },
|
|
149
|
+
],
|
|
150
|
+
},
|
|
153
151
|
]);
|
|
154
152
|
if (action === 'exit') {
|
|
155
|
-
console.log(chalk.green(
|
|
153
|
+
console.log(chalk.green(`\n👋 ${i18n.t('wizard.goodbye_message')}`));
|
|
156
154
|
process.exit(0);
|
|
157
155
|
}
|
|
158
156
|
else if (action === 'back') {
|
|
@@ -169,16 +167,16 @@ export class Wizard {
|
|
|
169
167
|
message: i18n.t('wizard.input_your_api_key'),
|
|
170
168
|
validate: (input) => {
|
|
171
169
|
if (!input || input.trim().length === 0) {
|
|
172
|
-
return
|
|
170
|
+
return `[!] ${i18n.t('wizard.api_key_required')}`;
|
|
173
171
|
}
|
|
174
172
|
return true;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
173
|
+
},
|
|
174
|
+
},
|
|
177
175
|
]);
|
|
178
176
|
// Validate API Key
|
|
179
177
|
const spinner = ora({
|
|
180
178
|
text: i18n.t('wizard.validating_api_key'),
|
|
181
|
-
spinner: 'star2'
|
|
179
|
+
spinner: 'star2',
|
|
182
180
|
}).start();
|
|
183
181
|
const validationResult = await validateApiKey(apiKey.trim());
|
|
184
182
|
await new Promise(resolve => setTimeout(resolve, 800));
|
|
@@ -195,7 +193,7 @@ export class Wizard {
|
|
|
195
193
|
configManager.setApiKey(apiKey.trim());
|
|
196
194
|
// Clear cached models when API key changes
|
|
197
195
|
this.cachedModels = [];
|
|
198
|
-
spinner.succeed(
|
|
196
|
+
spinner.succeed(`✅ ${i18n.t('wizard.set_success')}`);
|
|
199
197
|
await new Promise(resolve => setTimeout(resolve, 600));
|
|
200
198
|
// 直接返回,不再跳转到模型选择
|
|
201
199
|
return;
|
|
@@ -227,10 +225,10 @@ export class Wizard {
|
|
|
227
225
|
const currentConfig = configManager.getConfig();
|
|
228
226
|
const models = currentConfig;
|
|
229
227
|
// Display current model configuration
|
|
230
|
-
console.log(chalk.cyan.bold(i18n.t('wizard.models_config_title')
|
|
231
|
-
console.log(chalk.gray(
|
|
232
|
-
console.log(chalk.gray(
|
|
233
|
-
console.log(chalk.gray(
|
|
228
|
+
console.log(chalk.cyan.bold(`${i18n.t('wizard.models_config_title')}:`));
|
|
229
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_haiku_model')}: `) + (models.haikuModel ? chalk.green(models.haikuModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
230
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_sonnet_model')}: `) + (models.sonnetModel ? chalk.green(models.sonnetModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
231
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_opus_model')}: `) + (models.opusModel ? chalk.green(models.opusModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
234
232
|
console.log('');
|
|
235
233
|
const { action } = await this.promptWithHints([
|
|
236
234
|
{
|
|
@@ -238,15 +236,15 @@ export class Wizard {
|
|
|
238
236
|
name: 'action',
|
|
239
237
|
message: i18n.t('wizard.select_action'),
|
|
240
238
|
choices: [
|
|
241
|
-
{ name:
|
|
239
|
+
{ name: `> ${i18n.t('wizard.configure_models')}`, value: 'configure' },
|
|
242
240
|
new inquirer.Separator(),
|
|
243
|
-
{ name:
|
|
244
|
-
{ name:
|
|
245
|
-
]
|
|
246
|
-
}
|
|
241
|
+
{ name: `<- ${i18n.t('wizard.nav_return')}`, value: 'back' },
|
|
242
|
+
{ name: `x ${i18n.t('wizard.nav_exit')}`, value: 'exit' },
|
|
243
|
+
],
|
|
244
|
+
},
|
|
247
245
|
]);
|
|
248
246
|
if (action === 'exit') {
|
|
249
|
-
console.log(chalk.green(
|
|
247
|
+
console.log(chalk.green(`\n👋 ${i18n.t('wizard.goodbye_message')}`));
|
|
250
248
|
process.exit(0);
|
|
251
249
|
}
|
|
252
250
|
else if (action === 'back') {
|
|
@@ -260,17 +258,22 @@ export class Wizard {
|
|
|
260
258
|
/**
|
|
261
259
|
* Step-by-step model selection with back navigation
|
|
262
260
|
*/
|
|
263
|
-
async selectModels() {
|
|
261
|
+
async selectModels(toolName) {
|
|
262
|
+
// OpenCode 使用独立的模型选择流程
|
|
263
|
+
if (toolName === 'opencode') {
|
|
264
|
+
await this.selectModelsForOpenCode();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
264
267
|
const apiKey = configManager.getApiKey();
|
|
265
268
|
if (!apiKey) {
|
|
266
|
-
console.log(chalk.red(
|
|
269
|
+
console.log(chalk.red(`\n${i18n.t('wizard.no_models_available')}`));
|
|
267
270
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
268
271
|
return;
|
|
269
272
|
}
|
|
270
273
|
// Fetch available models
|
|
271
274
|
const spinner = ora({
|
|
272
275
|
text: i18n.t('wizard.fetching_models'),
|
|
273
|
-
spinner: 'star2'
|
|
276
|
+
spinner: 'star2',
|
|
274
277
|
}).start();
|
|
275
278
|
const availableModels = await this.fetchModels();
|
|
276
279
|
if (availableModels.length === 0) {
|
|
@@ -281,21 +284,20 @@ export class Wizard {
|
|
|
281
284
|
spinner.succeed(chalk.green(i18n.t('wizard.api_key_valid')));
|
|
282
285
|
await new Promise(resolve => setTimeout(resolve, 300));
|
|
283
286
|
const currentConfig = configManager.getConfig();
|
|
284
|
-
const modelTypes = ['haiku', 'sonnet', 'opus'];
|
|
285
287
|
const titleKeys = [
|
|
286
288
|
'wizard.select_haiku_model',
|
|
287
289
|
'wizard.select_sonnet_model',
|
|
288
|
-
'wizard.select_opus_model'
|
|
290
|
+
'wizard.select_opus_model',
|
|
289
291
|
];
|
|
290
292
|
const defaultModels = [
|
|
291
293
|
DEFAULT_CONFIG.ANTHROPIC_DEFAULT_HAIKU_MODEL,
|
|
292
294
|
DEFAULT_CONFIG.ANTHROPIC_DEFAULT_SONNET_MODEL,
|
|
293
|
-
DEFAULT_CONFIG.ANTHROPIC_DEFAULT_OPUS_MODEL
|
|
295
|
+
DEFAULT_CONFIG.ANTHROPIC_DEFAULT_OPUS_MODEL,
|
|
294
296
|
];
|
|
295
297
|
const currentModels = [
|
|
296
298
|
currentConfig.haikuModel,
|
|
297
299
|
currentConfig.sonnetModel,
|
|
298
|
-
currentConfig.opusModel
|
|
300
|
+
currentConfig.opusModel,
|
|
299
301
|
];
|
|
300
302
|
// Selected models (initialize with current config)
|
|
301
303
|
const selectedModels = [...currentModels];
|
|
@@ -305,16 +307,16 @@ export class Wizard {
|
|
|
305
307
|
this.createBox(i18n.t(titleKeys[step]));
|
|
306
308
|
// Build choices with back option at top
|
|
307
309
|
const choices = [
|
|
308
|
-
{ name:
|
|
309
|
-
new inquirer.Separator()
|
|
310
|
+
{ name: `<- ${i18n.t('wizard.nav_go_back')}`, value: 'back' },
|
|
311
|
+
new inquirer.Separator(),
|
|
310
312
|
];
|
|
311
313
|
// Add model choices
|
|
312
|
-
availableModels.forEach(model => {
|
|
314
|
+
availableModels.forEach((model) => {
|
|
313
315
|
const isCurrentActive = currentModels[step] === model;
|
|
314
316
|
const isSelected = selectedModels[step] === model;
|
|
315
317
|
let label = model;
|
|
316
318
|
if (isCurrentActive) {
|
|
317
|
-
label += chalk.green(
|
|
319
|
+
label += chalk.green(` ✓ (${i18n.t('wizard.current_active')})`);
|
|
318
320
|
}
|
|
319
321
|
else if (isSelected && !isCurrentActive) {
|
|
320
322
|
label += chalk.cyan(' ✓');
|
|
@@ -328,8 +330,8 @@ export class Wizard {
|
|
|
328
330
|
name: 'model',
|
|
329
331
|
message: i18n.t(titleKeys[step]),
|
|
330
332
|
choices,
|
|
331
|
-
default: selectedModels[step] || defaultModels[step]
|
|
332
|
-
}
|
|
333
|
+
default: selectedModels[step] || defaultModels[step],
|
|
334
|
+
},
|
|
333
335
|
]);
|
|
334
336
|
if (model === 'back') {
|
|
335
337
|
step--; // Go back to previous step
|
|
@@ -350,13 +352,121 @@ export class Wizard {
|
|
|
350
352
|
// Save the configuration
|
|
351
353
|
const saveSpinner = ora({
|
|
352
354
|
text: i18n.t('wizard.saving_model_config'),
|
|
353
|
-
spinner: 'star2'
|
|
355
|
+
spinner: 'star2',
|
|
354
356
|
}).start();
|
|
355
357
|
try {
|
|
356
358
|
configManager.setModels({
|
|
357
359
|
haikuModel: selectedModels[0],
|
|
358
360
|
sonnetModel: selectedModels[1],
|
|
359
|
-
opusModel: selectedModels[2]
|
|
361
|
+
opusModel: selectedModels[2],
|
|
362
|
+
});
|
|
363
|
+
await new Promise(resolve => setTimeout(resolve, 600));
|
|
364
|
+
saveSpinner.succeed(chalk.green(i18n.t('wizard.model_config_saved')));
|
|
365
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
saveSpinner.fail(i18n.t('wizard.model_config_failed'));
|
|
369
|
+
console.error(error);
|
|
370
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* OpenCode 专用的模型选择流程(2 步:主模型 + 小模型)
|
|
375
|
+
*/
|
|
376
|
+
async selectModelsForOpenCode() {
|
|
377
|
+
const apiKey = configManager.getApiKey();
|
|
378
|
+
if (!apiKey) {
|
|
379
|
+
console.log(chalk.red(`\n${i18n.t('wizard.no_models_available')}`));
|
|
380
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
// Fetch available models
|
|
384
|
+
const spinner = ora({
|
|
385
|
+
text: i18n.t('wizard.fetching_models'),
|
|
386
|
+
spinner: 'star2',
|
|
387
|
+
}).start();
|
|
388
|
+
const availableModels = await this.fetchModels();
|
|
389
|
+
if (availableModels.length === 0) {
|
|
390
|
+
spinner.fail(chalk.red(i18n.t('wizard.fetch_models_failed')));
|
|
391
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
spinner.succeed(chalk.green(i18n.t('wizard.api_key_valid')));
|
|
395
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
396
|
+
const currentConfig = configManager.getConfig();
|
|
397
|
+
// OpenCode: 使用独立的 openCodeModel 和 openCodeSmallModel
|
|
398
|
+
const titleKeys = [
|
|
399
|
+
'wizard.select_model',
|
|
400
|
+
'wizard.select_small_model',
|
|
401
|
+
];
|
|
402
|
+
const defaultModels = [
|
|
403
|
+
OPENCODE_DEFAULT_CONFIG.DEFAULT_MODEL,
|
|
404
|
+
OPENCODE_DEFAULT_CONFIG.DEFAULT_SMALL_MODEL,
|
|
405
|
+
];
|
|
406
|
+
const currentModels = [
|
|
407
|
+
currentConfig.openCodeModel,
|
|
408
|
+
currentConfig.openCodeSmallModel,
|
|
409
|
+
];
|
|
410
|
+
// Selected models (initialize with current config)
|
|
411
|
+
const selectedModels = [...currentModels];
|
|
412
|
+
let step = 0;
|
|
413
|
+
while (step >= 0 && step < 2) {
|
|
414
|
+
this.resetScreen();
|
|
415
|
+
this.createBox(i18n.t(titleKeys[step]));
|
|
416
|
+
// Build choices with back option at top
|
|
417
|
+
const choices = [
|
|
418
|
+
{ name: `<- ${i18n.t('wizard.nav_go_back')}`, value: 'back' },
|
|
419
|
+
new inquirer.Separator(),
|
|
420
|
+
];
|
|
421
|
+
// Add model choices
|
|
422
|
+
availableModels.forEach((model) => {
|
|
423
|
+
const isCurrentActive = currentModels[step] === model;
|
|
424
|
+
const isSelected = selectedModels[step] === model;
|
|
425
|
+
let label = model;
|
|
426
|
+
if (isCurrentActive) {
|
|
427
|
+
label += chalk.green(` ✓ (${i18n.t('wizard.current_active')})`);
|
|
428
|
+
}
|
|
429
|
+
else if (isSelected && !isCurrentActive) {
|
|
430
|
+
label += chalk.cyan(' ✓');
|
|
431
|
+
}
|
|
432
|
+
choices.push({ name: label, value: model });
|
|
433
|
+
});
|
|
434
|
+
try {
|
|
435
|
+
const { model } = await this.promptWithHints([
|
|
436
|
+
{
|
|
437
|
+
type: 'list',
|
|
438
|
+
name: 'model',
|
|
439
|
+
message: i18n.t(titleKeys[step]),
|
|
440
|
+
choices,
|
|
441
|
+
default: selectedModels[step] || defaultModels[step],
|
|
442
|
+
},
|
|
443
|
+
]);
|
|
444
|
+
if (model === 'back') {
|
|
445
|
+
step--; // Go back to previous step
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
selectedModels[step] = model;
|
|
449
|
+
step++; // Move to next step
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
return; // User pressed Ctrl+C
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
// If step < 0, user went back from first step, exit without saving
|
|
457
|
+
if (step < 0) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
// Save the configuration
|
|
461
|
+
const saveSpinner = ora({
|
|
462
|
+
text: i18n.t('wizard.saving_model_config'),
|
|
463
|
+
spinner: 'star2',
|
|
464
|
+
}).start();
|
|
465
|
+
try {
|
|
466
|
+
// OpenCode: 使用独立的配置键
|
|
467
|
+
configManager.setOpenCodeModels({
|
|
468
|
+
openCodeModel: selectedModels[0],
|
|
469
|
+
openCodeSmallModel: selectedModels[1],
|
|
360
470
|
});
|
|
361
471
|
await new Promise(resolve => setTimeout(resolve, 600));
|
|
362
472
|
saveSpinner.succeed(chalk.green(i18n.t('wizard.model_config_saved')));
|
|
@@ -375,19 +485,19 @@ export class Wizard {
|
|
|
375
485
|
const supportedTools = toolManager.getSupportedTools();
|
|
376
486
|
const toolChoices = supportedTools.map(tool => ({
|
|
377
487
|
name: `> ${tool.displayName}`,
|
|
378
|
-
value: tool.name
|
|
488
|
+
value: tool.name,
|
|
379
489
|
}));
|
|
380
|
-
toolChoices.push(new inquirer.Separator(), { name:
|
|
490
|
+
toolChoices.push(new inquirer.Separator(), { name: `<- ${i18n.t('wizard.nav_return')}`, value: 'back' }, { name: `x ${i18n.t('wizard.nav_exit')}`, value: 'exit' });
|
|
381
491
|
const { selectedTool } = await this.promptWithHints([
|
|
382
492
|
{
|
|
383
493
|
type: 'list',
|
|
384
494
|
name: 'selectedTool',
|
|
385
495
|
message: i18n.t('wizard.select_tool'),
|
|
386
|
-
choices: toolChoices
|
|
387
|
-
}
|
|
496
|
+
choices: toolChoices,
|
|
497
|
+
},
|
|
388
498
|
]);
|
|
389
499
|
if (selectedTool === 'exit') {
|
|
390
|
-
console.log(chalk.green(
|
|
500
|
+
console.log(chalk.green(`\n👋 ${i18n.t('wizard.goodbye_message')}`));
|
|
391
501
|
process.exit(0);
|
|
392
502
|
}
|
|
393
503
|
else if (selectedTool === 'back') {
|
|
@@ -405,8 +515,8 @@ export class Wizard {
|
|
|
405
515
|
type: 'confirm',
|
|
406
516
|
name: 'shouldInstall',
|
|
407
517
|
message: i18n.t('wizard.install_tool_confirm'),
|
|
408
|
-
default: true
|
|
409
|
-
}
|
|
518
|
+
default: true,
|
|
519
|
+
},
|
|
410
520
|
]);
|
|
411
521
|
if (shouldInstall) {
|
|
412
522
|
try {
|
|
@@ -427,9 +537,9 @@ export class Wizard {
|
|
|
427
537
|
message: i18n.t('install.skip_install_confirm'),
|
|
428
538
|
choices: [
|
|
429
539
|
{ name: i18n.t('install.skip_install_yes'), value: true },
|
|
430
|
-
{ name: i18n.t('install.skip_install_no'), value: false }
|
|
431
|
-
]
|
|
432
|
-
}
|
|
540
|
+
{ name: i18n.t('install.skip_install_no'), value: false },
|
|
541
|
+
],
|
|
542
|
+
},
|
|
433
543
|
]);
|
|
434
544
|
if (!skipInstall) {
|
|
435
545
|
return;
|
|
@@ -452,26 +562,26 @@ export class Wizard {
|
|
|
452
562
|
const currentCfg = configManager.getConfig();
|
|
453
563
|
this.createBox(i18n.t('wizard.main_menu_title'));
|
|
454
564
|
// 显示当前配置状态(仅 API Key)
|
|
455
|
-
console.log(chalk.gray(
|
|
565
|
+
console.log(chalk.gray(` ${i18n.t('wizard.config_api_key')}: `) + (currentCfg.api_key ? chalk.gray(`${i18n.t('wizard.api_key_set')} (${currentCfg.api_key.slice(0, 4)}****)`) : chalk.red(i18n.t('wizard.not_set'))));
|
|
456
566
|
console.log('');
|
|
457
567
|
const choices = [
|
|
458
|
-
{ name:
|
|
459
|
-
{ name:
|
|
460
|
-
{ name:
|
|
568
|
+
{ name: `> ${i18n.t('wizard.menu_config_language')}`, value: 'lang' },
|
|
569
|
+
{ name: `> ${i18n.t('wizard.menu_config_api_key')}`, value: 'apikey' },
|
|
570
|
+
{ name: `> ${i18n.t('wizard.menu_config_tool')}`, value: 'tool' },
|
|
461
571
|
new inquirer.Separator(),
|
|
462
|
-
{ name:
|
|
463
|
-
{ name:
|
|
572
|
+
{ name: `> ${i18n.t('wizard.menu_open_website')}`, value: 'website' },
|
|
573
|
+
{ name: `x ${i18n.t('wizard.menu_exit')}`, value: 'exit' },
|
|
464
574
|
];
|
|
465
575
|
const { action } = await this.promptWithHints([
|
|
466
576
|
{
|
|
467
577
|
type: 'list',
|
|
468
578
|
name: 'action',
|
|
469
579
|
message: i18n.t('wizard.select_operation'),
|
|
470
|
-
choices
|
|
471
|
-
}
|
|
580
|
+
choices,
|
|
581
|
+
},
|
|
472
582
|
]);
|
|
473
583
|
if (action === 'exit') {
|
|
474
|
-
console.log(chalk.green(
|
|
584
|
+
console.log(chalk.green(`\n👋 ${i18n.t('wizard.goodbye_message')}`));
|
|
475
585
|
process.exit(0);
|
|
476
586
|
}
|
|
477
587
|
else if (action === 'lang') {
|
|
@@ -491,111 +601,141 @@ export class Wizard {
|
|
|
491
601
|
async openOfficialWebsite() {
|
|
492
602
|
const spinner = ora({
|
|
493
603
|
text: i18n.t('wizard.opening_website'),
|
|
494
|
-
spinner: 'star2'
|
|
604
|
+
spinner: 'star2',
|
|
495
605
|
}).start();
|
|
496
606
|
try {
|
|
497
607
|
await open(OFFICIAL_WEBSITE);
|
|
498
608
|
spinner.succeed(chalk.green(i18n.t('wizard.website_opened')));
|
|
499
609
|
}
|
|
500
|
-
catch
|
|
610
|
+
catch {
|
|
501
611
|
spinner.fail(chalk.red(i18n.t('wizard.website_open_failed')));
|
|
502
612
|
// 显示可点击链接作为备选
|
|
503
613
|
const link = terminalLink(OFFICIAL_WEBSITE, OFFICIAL_WEBSITE, {
|
|
504
|
-
fallback: () => OFFICIAL_WEBSITE
|
|
614
|
+
fallback: () => OFFICIAL_WEBSITE,
|
|
505
615
|
});
|
|
506
|
-
console.log(chalk.blue(
|
|
616
|
+
console.log(chalk.blue(` ${i18n.t('wizard.click_to_open')}: ${link}`));
|
|
507
617
|
}
|
|
508
618
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
509
619
|
}
|
|
510
620
|
async showToolMenu(toolName) {
|
|
511
621
|
while (true) {
|
|
512
|
-
// for claude code now
|
|
513
622
|
this.resetScreen();
|
|
514
623
|
const title = `${SUPPORTED_TOOLS[toolName].displayName} ${i18n.t('wizard.menu_title')}`;
|
|
515
624
|
this.createBox(title);
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}
|
|
625
|
+
// 显示全局配置警告
|
|
626
|
+
console.log(chalk.yellow.bold(i18n.t('wizard.global_config_warning', { tool: SUPPORTED_TOOLS[toolName].displayName })));
|
|
627
|
+
console.log('');
|
|
520
628
|
let actionText = '';
|
|
521
629
|
const chelperConfig = configManager.getConfig();
|
|
522
|
-
|
|
630
|
+
// 根据工具类型获取检测到的配置
|
|
631
|
+
let detectedConfig = null;
|
|
632
|
+
let configMatches = false;
|
|
633
|
+
if (toolName === 'claude-code') {
|
|
634
|
+
detectedConfig = claudeCodeManager.getModelConfig();
|
|
635
|
+
}
|
|
636
|
+
else if (toolName === 'opencode') {
|
|
637
|
+
detectedConfig = openCodeManager.getModelConfig();
|
|
638
|
+
}
|
|
523
639
|
// 显示 chelper 配置
|
|
524
|
-
console.log(chalk.cyan.bold(i18n.t('wizard.chelper_config_title')
|
|
640
|
+
console.log(chalk.cyan.bold(`${i18n.t('wizard.chelper_config_title')}:`));
|
|
525
641
|
if (chelperConfig.api_key) {
|
|
526
|
-
console.log(chalk.gray(
|
|
642
|
+
console.log(chalk.gray(` ${i18n.t('wizard.config_api_key')}: `) + chalk.gray(`${i18n.t('wizard.api_key_set')} (${chelperConfig.api_key.slice(0, 4)}****)`));
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
console.log(chalk.gray(` ${i18n.t('wizard.config_api_key')}: `) + chalk.red(i18n.t('wizard.not_set')));
|
|
646
|
+
}
|
|
647
|
+
// 根据工具类型显示不同的模型配置
|
|
648
|
+
if (toolName === 'opencode') {
|
|
649
|
+
// OpenCode: 使用独立的 openCodeModel 和 openCodeSmallModel
|
|
650
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_model')}: `) + (chelperConfig.openCodeModel ? chalk.green(chelperConfig.openCodeModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
651
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_small_model')}: `) + (chelperConfig.openCodeSmallModel ? chalk.green(chelperConfig.openCodeSmallModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
527
652
|
}
|
|
528
653
|
else {
|
|
529
|
-
|
|
654
|
+
// Claude Code: haiku + sonnet + opus
|
|
655
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_haiku_model')}: `) + (chelperConfig.haikuModel ? chalk.green(chelperConfig.haikuModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
656
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_sonnet_model')}: `) + (chelperConfig.sonnetModel ? chalk.green(chelperConfig.sonnetModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
657
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_opus_model')}: `) + (chelperConfig.opusModel ? chalk.green(chelperConfig.opusModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
530
658
|
}
|
|
531
|
-
console.log(chalk.gray(' ' + i18n.t('wizard.current_haiku_model') + ': ') + (chelperConfig.haikuModel ? chalk.green(chelperConfig.haikuModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
532
|
-
console.log(chalk.gray(' ' + i18n.t('wizard.current_sonnet_model') + ': ') + (chelperConfig.sonnetModel ? chalk.green(chelperConfig.sonnetModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
533
|
-
console.log(chalk.gray(' ' + i18n.t('wizard.current_opus_model') + ': ') + (chelperConfig.opusModel ? chalk.green(chelperConfig.opusModel) : chalk.red(i18n.t('wizard.not_set'))));
|
|
534
659
|
console.log('');
|
|
535
|
-
//
|
|
536
|
-
|
|
660
|
+
// 显示工具当前配置
|
|
661
|
+
const toolConfigTitle = toolName === 'opencode' ? i18n.t('wizard.opencode_config_title') : i18n.t('wizard.claude_code_config_title');
|
|
662
|
+
console.log(chalk.yellow.bold(`${toolConfigTitle}:`));
|
|
537
663
|
if (detectedConfig) {
|
|
538
|
-
console.log(chalk.gray(
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
664
|
+
console.log(chalk.gray(` ${i18n.t('wizard.config_api_key')}: `) + chalk.gray(`${i18n.t('wizard.api_key_set')} (${detectedConfig.apiKey.slice(0, 4)}****)`));
|
|
665
|
+
if (toolName === 'opencode') {
|
|
666
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_model')}: `) + chalk.green(detectedConfig.model));
|
|
667
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_small_model')}: `) + chalk.green(detectedConfig.smallModel));
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_haiku_model')}: `) + chalk.green(detectedConfig.haikuModel));
|
|
671
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_sonnet_model')}: `) + chalk.green(detectedConfig.sonnetModel));
|
|
672
|
+
console.log(chalk.gray(` ${i18n.t('wizard.current_opus_model')}: `) + chalk.green(detectedConfig.opusModel));
|
|
673
|
+
}
|
|
542
674
|
}
|
|
543
675
|
else {
|
|
544
|
-
console.log(chalk.gray(
|
|
676
|
+
console.log(chalk.gray(` ${i18n.t('wizard.config_api_key')}: `) + chalk.red(i18n.t('wizard.not_set')));
|
|
545
677
|
}
|
|
546
678
|
console.log('');
|
|
547
679
|
// 判断是否需要刷新配置
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
680
|
+
if (toolName === 'opencode') {
|
|
681
|
+
configMatches = detectedConfig
|
|
682
|
+
&& detectedConfig.apiKey === chelperConfig.api_key
|
|
683
|
+
&& detectedConfig.model === chelperConfig.openCodeModel
|
|
684
|
+
&& detectedConfig.smallModel === chelperConfig.openCodeSmallModel;
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
configMatches = detectedConfig
|
|
688
|
+
&& detectedConfig.apiKey === chelperConfig.api_key
|
|
689
|
+
&& detectedConfig.haikuModel === chelperConfig.haikuModel
|
|
690
|
+
&& detectedConfig.sonnetModel === chelperConfig.sonnetModel
|
|
691
|
+
&& detectedConfig.opusModel === chelperConfig.opusModel;
|
|
692
|
+
}
|
|
553
693
|
if (detectedConfig && configMatches) {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
actionText = i18n.t('wizard.action_refresh_config', { 'tool': SUPPORTED_TOOLS[toolName].displayName });
|
|
694
|
+
console.log(chalk.green(`✅ ${i18n.t('wizard.config_synced')}`));
|
|
695
|
+
actionText = i18n.t('wizard.action_refresh_config', { tool: SUPPORTED_TOOLS[toolName].displayName });
|
|
557
696
|
}
|
|
558
697
|
else if (detectedConfig) {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
actionText = i18n.t('wizard.action_refresh_config', { 'tool': SUPPORTED_TOOLS[toolName].displayName });
|
|
698
|
+
console.log(chalk.yellow(`⚠️ ${i18n.t('wizard.config_out_of_sync')}`));
|
|
699
|
+
actionText = i18n.t('wizard.action_refresh_config', { tool: SUPPORTED_TOOLS[toolName].displayName });
|
|
562
700
|
}
|
|
563
701
|
else {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
actionText = i18n.t('wizard.action_load_config', { 'tool': SUPPORTED_TOOLS[toolName].displayName });
|
|
702
|
+
console.log(chalk.blue(`ℹ️ ${i18n.t('wizard.config_not_loaded')}`));
|
|
703
|
+
actionText = i18n.t('wizard.action_load_config', { tool: SUPPORTED_TOOLS[toolName].displayName });
|
|
567
704
|
}
|
|
568
705
|
console.log('');
|
|
569
706
|
const choices = [];
|
|
570
|
-
//
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
707
|
+
// 根据工具类型显示不同的配置模型文案
|
|
708
|
+
if (toolName === 'opencode') {
|
|
709
|
+
choices.push({ name: `> ${i18n.t('wizard.action_config_models_opencode')}`, value: 'config_models' });
|
|
710
|
+
}
|
|
711
|
+
else {
|
|
712
|
+
choices.push({ name: `> ${i18n.t('wizard.action_config_models')}`, value: 'config_models' });
|
|
713
|
+
}
|
|
714
|
+
choices.push({ name: `> ${actionText}`, value: 'load_config' });
|
|
574
715
|
if (detectedConfig) {
|
|
575
|
-
choices.push({ name:
|
|
716
|
+
choices.push({ name: `> ${i18n.t('wizard.action_unload_config', { tool: SUPPORTED_TOOLS[toolName].displayName })}`, value: 'unload_config' });
|
|
576
717
|
}
|
|
577
|
-
// 如果已经配置了,显示启动选项
|
|
578
718
|
if (detectedConfig) {
|
|
579
|
-
choices.push({ name:
|
|
719
|
+
choices.push({ name: `> ${i18n.t('wizard.start_tool', { tool: SUPPORTED_TOOLS[toolName].displayName, shell: SUPPORTED_TOOLS[toolName].command })}`, value: 'start_tool' });
|
|
580
720
|
}
|
|
581
|
-
choices.push(new inquirer.Separator(), { name:
|
|
721
|
+
choices.push(new inquirer.Separator(), { name: `<- ${i18n.t('wizard.nav_return')}`, value: 'back' }, { name: `x ${i18n.t('wizard.nav_exit')}`, value: 'exit' });
|
|
582
722
|
const { action } = await this.promptWithHints([
|
|
583
723
|
{
|
|
584
724
|
type: 'list',
|
|
585
725
|
name: 'action',
|
|
586
726
|
message: i18n.t('wizard.select_action'),
|
|
587
|
-
choices
|
|
588
|
-
}
|
|
727
|
+
choices,
|
|
728
|
+
},
|
|
589
729
|
]);
|
|
590
730
|
if (action === 'exit') {
|
|
591
|
-
console.log(chalk.green(
|
|
731
|
+
console.log(chalk.green(`\n👋 ${i18n.t('wizard.goodbye_message')}`));
|
|
592
732
|
process.exit(0);
|
|
593
733
|
}
|
|
594
734
|
else if (action === 'back') {
|
|
595
735
|
return;
|
|
596
736
|
}
|
|
597
737
|
else if (action === 'config_models') {
|
|
598
|
-
await this.selectModels();
|
|
738
|
+
await this.selectModels(toolName);
|
|
599
739
|
}
|
|
600
740
|
else if (action === 'load_config') {
|
|
601
741
|
await this.loadModelConfig(toolName);
|
|
@@ -622,12 +762,12 @@ export class Wizard {
|
|
|
622
762
|
name: 'startOption',
|
|
623
763
|
message: i18n.t('wizard.select_start_directory'),
|
|
624
764
|
choices: [
|
|
625
|
-
{ name:
|
|
626
|
-
{ name:
|
|
765
|
+
{ name: `> ${i18n.t('wizard.start_from_current_dir')} (${process.cwd()})`, value: 'current' },
|
|
766
|
+
{ name: `> ${i18n.t('wizard.start_from_custom_dir')}`, value: 'custom' },
|
|
627
767
|
new inquirer.Separator(),
|
|
628
|
-
{ name:
|
|
629
|
-
]
|
|
630
|
-
}
|
|
768
|
+
{ name: `<- ${i18n.t('wizard.nav_return')}`, value: 'back' },
|
|
769
|
+
],
|
|
770
|
+
},
|
|
631
771
|
]);
|
|
632
772
|
if (startOption === 'back') {
|
|
633
773
|
return;
|
|
@@ -647,14 +787,14 @@ export class Wizard {
|
|
|
647
787
|
return i18n.t('wizard.directory_not_exist');
|
|
648
788
|
}
|
|
649
789
|
return true;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
790
|
+
},
|
|
791
|
+
},
|
|
652
792
|
]);
|
|
653
793
|
workingDir = customDir.trim();
|
|
654
794
|
}
|
|
655
795
|
const spinner = ora({
|
|
656
796
|
text: i18n.t('wizard.starting_tool'),
|
|
657
|
-
spinner: 'star2'
|
|
797
|
+
spinner: 'star2',
|
|
658
798
|
}).start();
|
|
659
799
|
try {
|
|
660
800
|
execSync(tool.command, { stdio: 'inherit', cwd: workingDir });
|
|
@@ -668,7 +808,7 @@ export class Wizard {
|
|
|
668
808
|
async loadModelConfig(toolName) {
|
|
669
809
|
const spinner = ora({
|
|
670
810
|
text: i18n.t('wizard.loading_config'),
|
|
671
|
-
spinner: 'star2'
|
|
811
|
+
spinner: 'star2',
|
|
672
812
|
}).start();
|
|
673
813
|
try {
|
|
674
814
|
const config = configManager.getConfig();
|
|
@@ -681,11 +821,16 @@ export class Wizard {
|
|
|
681
821
|
const haikuModel = config.haikuModel || DEFAULT_CONFIG.ANTHROPIC_DEFAULT_HAIKU_MODEL;
|
|
682
822
|
const sonnetModel = config.sonnetModel || DEFAULT_CONFIG.ANTHROPIC_DEFAULT_SONNET_MODEL;
|
|
683
823
|
const opusModel = config.opusModel || DEFAULT_CONFIG.ANTHROPIC_DEFAULT_OPUS_MODEL;
|
|
684
|
-
|
|
824
|
+
// OpenCode models
|
|
825
|
+
const openCodeModel = config.openCodeModel || OPENCODE_DEFAULT_CONFIG.DEFAULT_MODEL;
|
|
826
|
+
const openCodeSmallModel = config.openCodeSmallModel || OPENCODE_DEFAULT_CONFIG.DEFAULT_SMALL_MODEL;
|
|
827
|
+
await toolManager.loadModelConfig(toolName, {
|
|
685
828
|
apiKey: config.api_key,
|
|
686
829
|
haikuModel,
|
|
687
830
|
sonnetModel,
|
|
688
|
-
opusModel
|
|
831
|
+
opusModel,
|
|
832
|
+
openCodeModel,
|
|
833
|
+
openCodeSmallModel,
|
|
689
834
|
});
|
|
690
835
|
await new Promise(resolve => setTimeout(resolve, 800));
|
|
691
836
|
spinner.succeed(chalk.green(i18n.t('wizard.config_loaded', { tool: SUPPORTED_TOOLS[toolName].displayName })));
|
|
@@ -704,25 +849,31 @@ export class Wizard {
|
|
|
704
849
|
type: 'confirm',
|
|
705
850
|
name: 'confirm',
|
|
706
851
|
message: i18n.t('wizard.confirm_unload_config', { tool: SUPPORTED_TOOLS[toolName].displayName }),
|
|
707
|
-
default: false
|
|
708
|
-
}
|
|
852
|
+
default: false,
|
|
853
|
+
},
|
|
709
854
|
]);
|
|
710
855
|
if (!confirm) {
|
|
711
856
|
return;
|
|
712
857
|
}
|
|
713
858
|
const spinner = ora({
|
|
714
859
|
text: i18n.t('wizard.unloading_config'),
|
|
715
|
-
spinner: 'star2'
|
|
860
|
+
spinner: 'star2',
|
|
716
861
|
}).start();
|
|
717
862
|
try {
|
|
718
863
|
if (toolName === 'claude-code') {
|
|
719
|
-
// 添加短暂延迟,让动画效果更流畅
|
|
720
864
|
await new Promise(resolve => setTimeout(resolve, 300));
|
|
721
865
|
claudeCodeManager.clearModelConfig();
|
|
722
866
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
723
867
|
spinner.succeed(chalk.green(i18n.t('wizard.config_unloaded')));
|
|
724
868
|
await new Promise(resolve => setTimeout(resolve, 800));
|
|
725
869
|
}
|
|
870
|
+
else if (toolName === 'opencode') {
|
|
871
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
872
|
+
openCodeManager.clearModelConfig();
|
|
873
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
874
|
+
spinner.succeed(chalk.green(i18n.t('wizard.config_unloaded')));
|
|
875
|
+
await new Promise(resolve => setTimeout(resolve, 800));
|
|
876
|
+
}
|
|
726
877
|
else {
|
|
727
878
|
spinner.fail(i18n.t('wizard.tool_not_supported'));
|
|
728
879
|
await new Promise(resolve => setTimeout(resolve, 800));
|