@vibeapi/api-helper 0.0.15 → 0.0.16

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.
Files changed (38) hide show
  1. package/dist/cli.js +1 -17
  2. package/dist/commands/auth.js +1 -119
  3. package/dist/commands/auth.js.map +1 -1
  4. package/dist/commands/config.js +1 -130
  5. package/dist/commands/doctor.js +1 -105
  6. package/dist/commands/doctor.js.map +1 -1
  7. package/dist/commands/index.js +1 -5
  8. package/dist/commands/lang.js +1 -28
  9. package/dist/index.js +1 -10
  10. package/dist/lib/api-validator.js +1 -79
  11. package/dist/lib/claude-code-manager.js +1 -269
  12. package/dist/lib/claude-code-manager.js.map +1 -1
  13. package/dist/lib/command.js +1 -175
  14. package/dist/lib/config.d.ts +1 -6
  15. package/dist/lib/config.js +1 -233
  16. package/dist/lib/config.js.map +1 -1
  17. package/dist/lib/i18n.js +1 -149
  18. package/dist/lib/model-registry.d.ts +20 -0
  19. package/dist/lib/model-registry.js +1 -0
  20. package/dist/lib/model-registry.js.map +1 -0
  21. package/dist/lib/opencode-manager.js +1 -134
  22. package/dist/lib/settings-template.d.ts +6 -0
  23. package/dist/lib/settings-template.js +1 -0
  24. package/dist/lib/settings-template.js.map +1 -0
  25. package/dist/lib/tool-manager.js +1 -280
  26. package/dist/lib/tool-manager.js.map +1 -1
  27. package/dist/lib/wizard.d.ts +3 -3
  28. package/dist/lib/wizard.js +1 -625
  29. package/dist/lib/wizard.js.map +1 -1
  30. package/dist/locales/en_US.json +9 -7
  31. package/dist/locales/zh_CN.json +8 -6
  32. package/dist/models.json +44 -0
  33. package/dist/settings-template.json +12 -0
  34. package/dist/utils/logger.js +1 -202
  35. package/dist/utils/string-width.js +1 -131
  36. package/models.json +44 -0
  37. package/package.json +75 -73
  38. package/settings-template.json +12 -0
@@ -1,625 +1 @@
1
- import inquirer from 'inquirer';
2
- import chalk from 'chalk';
3
- import ora from 'ora';
4
- import { configManager, DEFAULT_MODELS } from './config.js';
5
- import { toolManager, SUPPORTED_TOOLS } from './tool-manager.js';
6
- import { claudeCodeManager } from './claude-code-manager.js';
7
- import { i18n } from './i18n.js';
8
- import { createBorderLine, createContentLine } from '../utils/string-width.js';
9
- import { validateApiKey } from './api-validator.js';
10
- // 主题色
11
- const THEME_COLOR = '#FF8700';
12
- const theme = chalk.hex(THEME_COLOR);
13
- export class Wizard {
14
- static instance;
15
- BOX_WIDTH = 63;
16
- apiKeyValid = false; // 添加 API Key 验证状态
17
- constructor() { }
18
- static getInstance() {
19
- if (!Wizard.instance) {
20
- Wizard.instance = new Wizard();
21
- }
22
- return Wizard.instance;
23
- }
24
- createBox(title) {
25
- console.log(theme.bold('\n' + createBorderLine('╔', '╗', '═', this.BOX_WIDTH)));
26
- console.log(theme.bold(createContentLine(title, '║', '║', this.BOX_WIDTH, 'center')));
27
- console.log(theme.bold(createBorderLine('╚', '╝', '═', this.BOX_WIDTH)));
28
- console.log('');
29
- }
30
- showOperationHints() {
31
- const hints = [
32
- chalk.gray(i18n.t('wizard.hint_navigate')),
33
- chalk.gray(i18n.t('wizard.hint_confirm'))
34
- ];
35
- console.log(chalk.gray('💡 ') + hints.join(chalk.gray(' | ')) + '\n');
36
- }
37
- async promptWithHints(questions) {
38
- this.showOperationHints();
39
- return inquirer.prompt(questions);
40
- }
41
- printBanner() {
42
- const BANNER_WIDTH = 65;
43
- const subtitle = i18n.t('wizard.banner_subtitle');
44
- const subtitleLine = createContentLine(subtitle, '║', '║', BANNER_WIDTH, 'center');
45
- const emptyLine = createContentLine('', '║', '║', BANNER_WIDTH, 'center');
46
- const titleLine = createContentLine('API Helper v0.0.14', '║', '║', BANNER_WIDTH, 'center');
47
- const asciiLines = [
48
- ' ▄▀▄ █▀▄ █ █▄█ ██▀ █ █▀▄ ██▀ █▀▄ ',
49
- ' █▀█ █▀ █ █ █ █▄▄ █▄▄ █▀ █▄▄ █▀▄ '
50
- ].map(line => createContentLine(line, '║', '║', BANNER_WIDTH, 'center'));
51
- const bannerLines = [
52
- createBorderLine('╔', '╗', '═', BANNER_WIDTH),
53
- emptyLine,
54
- ...asciiLines,
55
- emptyLine,
56
- titleLine,
57
- subtitleLine,
58
- createBorderLine('╚', '╝', '═', BANNER_WIDTH)
59
- ];
60
- console.log(theme.bold('\n' + bannerLines.join('\n')));
61
- }
62
- resetScreen() {
63
- console.clear();
64
- this.printBanner();
65
- }
66
- async runFirstTimeSetup() {
67
- this.resetScreen();
68
- console.log(theme.bold('\n' + i18n.t('wizard.welcome')));
69
- console.log(chalk.gray(i18n.t('wizard.privacy_note') + '\n'));
70
- // 1. 先配置语言
71
- await this.configLanguage();
72
- // 2. 必须先验证 API Key
73
- await this.configApiKey();
74
- // 3. 验证 API Key 后才能配置模型和工具
75
- const apiKey = configManager.getApiKey();
76
- if (!apiKey) {
77
- console.log(chalk.red('\n' + i18n.t('wizard.api_key_required')));
78
- return;
79
- }
80
- // 4. 配置模型
81
- await this.configModels();
82
- // 5. 配置工具
83
- await this.selectAndConfigureTool();
84
- }
85
- async configLanguage() {
86
- while (true) {
87
- this.resetScreen();
88
- this.createBox(i18n.t('wizard.select_language'));
89
- const currentLanguage = i18n.getLocale();
90
- const { language } = await this.promptWithHints([
91
- {
92
- type: 'list',
93
- name: 'language',
94
- message: '✨ ' + i18n.t('wizard.select_language'),
95
- choices: [
96
- { name: '[EN] English' + (currentLanguage === 'en_US' ? chalk.green(' ✓ (' + i18n.t('wizard.current_active') + ')') : ''), value: 'en_US' },
97
- { name: '[CN] 中文' + (currentLanguage === 'zh_CN' ? chalk.green(' ✓ (' + i18n.t('wizard.current_active') + ')') : ''), value: 'zh_CN' },
98
- new inquirer.Separator(),
99
- { name: '<- ' + i18n.t('wizard.nav_return'), value: 'back' },
100
- { name: 'x ' + i18n.t('wizard.nav_exit'), value: 'exit' }
101
- ],
102
- default: 'zh_CN'
103
- }
104
- ]);
105
- if (language === 'exit') {
106
- console.log(chalk.green('\n👋 ' + i18n.t('wizard.goodbye_message')));
107
- process.exit(0);
108
- }
109
- else if (language === 'back') {
110
- return;
111
- }
112
- configManager.setLang(language);
113
- i18n.setLocale(language);
114
- return;
115
- }
116
- }
117
- async configModels() {
118
- // 确保 API Key 已配置
119
- const apiKey = configManager.getApiKey();
120
- if (!apiKey) {
121
- console.log(chalk.red('\n' + i18n.t('wizard.api_key_required')));
122
- await inquirer.prompt([{ type: 'input', name: 'continue', message: i18n.t('wizard.press_enter') }]);
123
- return;
124
- }
125
- while (true) {
126
- this.resetScreen();
127
- this.createBox(i18n.t('wizard.config_models'));
128
- const { modelChoice } = await this.promptWithHints([{
129
- type: 'list',
130
- name: 'modelChoice',
131
- message: i18n.t('wizard.select_model_config'),
132
- choices: [
133
- { name: 'MiniMax-M2.5', value: 'MiniMax-M2.5' },
134
- { name: 'MiniMax-M2.7', value: 'MiniMax-M2.7' },
135
- { name: 'GPT-5.4', value: 'gpt-5.4' },
136
- { name: 'Kimi-K2.5', value: 'kimi-k2.5' },
137
- { name: 'Qwen3.5-Plus', value: 'qwen3.5-plus' },
138
- { name: 'GLM-5.1', value: 'glm-5.1' },
139
- new inquirer.Separator(),
140
- { name: i18n.t('wizard.use_default_models'), value: 'default' },
141
- { name: i18n.t('wizard.use_custom_models'), value: 'custom' },
142
- { name: i18n.t('wizard.custom_model_input'), value: 'custom_input' },
143
- new inquirer.Separator(),
144
- { name: '<- ' + i18n.t('wizard.nav_return'), value: 'back' },
145
- { name: 'x ' + i18n.t('wizard.nav_exit'), value: 'exit' }
146
- ]
147
- }]);
148
- if (modelChoice === 'exit') {
149
- console.log(chalk.green('\n👋 ' + i18n.t('wizard.goodbye_message')));
150
- process.exit(0);
151
- }
152
- else if (modelChoice === 'back') {
153
- return;
154
- }
155
- else if (modelChoice === 'default') {
156
- configManager.setModels(DEFAULT_MODELS);
157
- console.log(chalk.green('\n✓ ' + i18n.t('wizard.models_saved')));
158
- await this.promptLoadAfterModelConfig();
159
- return;
160
- }
161
- else if (modelChoice === 'custom') {
162
- // 自定义每个模型
163
- const models = await inquirer.prompt([
164
- {
165
- type: 'input',
166
- name: 'haiku',
167
- message: i18n.t('wizard.model_haiku') + ':',
168
- default: DEFAULT_MODELS.haiku
169
- },
170
- {
171
- type: 'input',
172
- name: 'sonnet',
173
- message: i18n.t('wizard.model_sonnet') + ':',
174
- default: DEFAULT_MODELS.sonnet
175
- },
176
- {
177
- type: 'input',
178
- name: 'opus',
179
- message: i18n.t('wizard.model_opus') + ':',
180
- default: DEFAULT_MODELS.opus
181
- },
182
- {
183
- type: 'input',
184
- name: 'reasoning',
185
- message: i18n.t('wizard.model_reasoning') + ':',
186
- default: DEFAULT_MODELS.reasoning
187
- }
188
- ]);
189
- configManager.setModels(models);
190
- console.log(chalk.green('\n✓ ' + i18n.t('wizard.models_saved')));
191
- await this.promptLoadAfterModelConfig();
192
- return;
193
- }
194
- else if (modelChoice === 'custom_input') {
195
- // 自定义输入一个模型
196
- const { customModel } = await inquirer.prompt([
197
- {
198
- type: 'input',
199
- name: 'customModel',
200
- message: i18n.t('wizard.input_custom_model'),
201
- default: DEFAULT_MODELS.sonnet
202
- }
203
- ]);
204
- const models = {
205
- haiku: customModel,
206
- sonnet: customModel,
207
- opus: customModel,
208
- reasoning: customModel
209
- };
210
- configManager.setModels(models);
211
- console.log(chalk.green('\n✓ ' + i18n.t('wizard.models_saved')));
212
- await this.promptLoadAfterModelConfig();
213
- return;
214
- }
215
- else {
216
- // 选择了预设模型(MiniMax、GPT、Kimi、Qwen)
217
- const models = {
218
- haiku: modelChoice,
219
- sonnet: modelChoice,
220
- opus: modelChoice,
221
- reasoning: modelChoice
222
- };
223
- configManager.setModels(models);
224
- console.log(chalk.green('\n✓ ' + i18n.t('wizard.models_saved')));
225
- await this.promptLoadAfterModelConfig();
226
- return;
227
- }
228
- }
229
- }
230
- async promptLoadAfterModelConfig() {
231
- const { shouldLoad } = await inquirer.prompt([{
232
- type: 'list',
233
- name: 'shouldLoad',
234
- message: i18n.t('wizard.load_config_now'),
235
- choices: [
236
- { name: i18n.t('wizard.load_config_yes'), value: true },
237
- { name: i18n.t('wizard.load_config_later'), value: false }
238
- ]
239
- }]);
240
- if (shouldLoad) {
241
- await this.selectAndConfigureTool();
242
- }
243
- }
244
- async configApiKey() {
245
- while (true) {
246
- this.resetScreen();
247
- this.createBox(i18n.t('wizard.input_api_key'));
248
- // 直接进入输入,不需要额外的选择菜单
249
- console.log(chalk.gray('\n💡 ' + i18n.t('wizard.api_key_input_hint')));
250
- console.log(chalk.gray(' ' + i18n.t('wizard.api_key_get_hint', { url: 'https://www.vibeapi.cn/console/token' })));
251
- console.log();
252
- const { apiKey } = await inquirer.prompt([
253
- {
254
- type: 'password',
255
- name: 'apiKey',
256
- message: i18n.t('wizard.input_your_api_key'),
257
- mask: '*'
258
- }
259
- ]);
260
- if (!apiKey || apiKey.trim() === '') {
261
- const { action } = await inquirer.prompt([{
262
- type: 'list',
263
- name: 'action',
264
- message: i18n.t('wizard.select_action'),
265
- choices: [
266
- { name: i18n.t('wizard.retry_input'), value: 'retry' },
267
- { name: '<- ' + i18n.t('wizard.nav_return'), value: 'back' }
268
- ]
269
- }]);
270
- if (action === 'back') {
271
- return;
272
- }
273
- continue;
274
- }
275
- const spinner = ora(i18n.t('wizard.validating_api_key')).start();
276
- const result = await validateApiKey(apiKey.trim());
277
- spinner.stop();
278
- if (result.valid) {
279
- configManager.setApiKey(apiKey.trim());
280
- this.apiKeyValid = true; // 更新验证状态
281
- console.log(chalk.green('\n✓ ' + i18n.t('wizard.api_key_valid')));
282
- return;
283
- }
284
- else {
285
- this.apiKeyValid = false; // 更新验证状态
286
- if (result.error === 'invalid_api_key') {
287
- console.log(chalk.red('\n✗ ' + i18n.t('wizard.api_key_invalid')));
288
- }
289
- else {
290
- console.log(chalk.red('\n✗ ' + i18n.t('wizard.api_key_network_error')));
291
- }
292
- const { action } = await inquirer.prompt([{
293
- type: 'list',
294
- name: 'action',
295
- message: i18n.t('wizard.select_action'),
296
- choices: [
297
- { name: i18n.t('wizard.retry_input'), value: 'retry' },
298
- { name: '<- ' + i18n.t('wizard.nav_return'), value: 'back' }
299
- ]
300
- }]);
301
- if (action === 'back') {
302
- return;
303
- }
304
- }
305
- }
306
- }
307
- async selectAndConfigureTool() {
308
- while (true) {
309
- this.resetScreen();
310
- this.createBox(i18n.t('wizard.select_tool'));
311
- const { tool } = await this.promptWithHints([
312
- {
313
- type: 'list',
314
- name: 'tool',
315
- message: '🛠️ ' + i18n.t('wizard.select_tool'),
316
- choices: [
317
- { name: 'Claude Code', value: 'claude-code' },
318
- { name: 'OpenCode', value: 'opencode' },
319
- new inquirer.Separator(),
320
- { name: '<- ' + i18n.t('wizard.nav_return'), value: 'back' },
321
- { name: 'x ' + i18n.t('wizard.nav_exit'), value: 'exit' }
322
- ]
323
- }
324
- ]);
325
- if (tool === 'exit') {
326
- console.log(chalk.green('\n👋 ' + i18n.t('wizard.goodbye_message')));
327
- process.exit(0);
328
- }
329
- else if (tool === 'back') {
330
- return;
331
- }
332
- await this.configureTool(tool);
333
- }
334
- }
335
- async configureTool(toolName) {
336
- const toolInfo = SUPPORTED_TOOLS[toolName];
337
- if (!toolInfo)
338
- return;
339
- const isInstalled = toolManager.isToolInstalled(toolName);
340
- if (!isInstalled) {
341
- console.log(chalk.yellow('\n' + i18n.t('wizard.tool_not_installed', { tool: toolInfo.displayName })));
342
- const { install } = await inquirer.prompt([{
343
- type: 'confirm',
344
- name: 'install',
345
- message: i18n.t('wizard.install_tool_confirm'),
346
- default: true
347
- }]);
348
- if (install) {
349
- try {
350
- await toolManager.installTool(toolName);
351
- }
352
- catch (error) {
353
- console.log(chalk.red(i18n.t('wizard.install_failed')));
354
- return;
355
- }
356
- }
357
- else {
358
- return;
359
- }
360
- }
361
- await this.showToolMenu(toolName);
362
- }
363
- async showToolMenu(toolName) {
364
- while (true) {
365
- this.resetScreen();
366
- const toolInfo = SUPPORTED_TOOLS[toolName];
367
- if (!toolInfo)
368
- return;
369
- this.createBox(toolInfo.displayName + ' ' + i18n.t('wizard.menu_title'));
370
- const { action } = await this.promptWithHints([
371
- {
372
- type: 'list',
373
- name: 'action',
374
- message: '⚙️ ' + i18n.t('wizard.select_action'),
375
- choices: [
376
- { name: '📥 ' + i18n.t('wizard.action_load_config', { tool: toolInfo.displayName }), value: 'load' },
377
- { name: '📤 ' + i18n.t('wizard.action_unload_config', { tool: toolInfo.displayName }), value: 'unload' },
378
- new inquirer.Separator(),
379
- { name: '<- ' + i18n.t('wizard.nav_return'), value: 'back' },
380
- { name: 'x ' + i18n.t('wizard.nav_exit'), value: 'exit' }
381
- ]
382
- }
383
- ]);
384
- if (action === 'exit') {
385
- console.log(chalk.green('\n👋 ' + i18n.t('wizard.goodbye_message')));
386
- process.exit(0);
387
- }
388
- else if (action === 'back') {
389
- return;
390
- }
391
- else if (action === 'load') {
392
- await this.loadConfig(toolName);
393
- }
394
- else if (action === 'unload') {
395
- await this.unloadConfig(toolName);
396
- }
397
- }
398
- }
399
- async loadConfig(toolName) {
400
- const apiKey = configManager.getApiKey();
401
- const models = configManager.getModels();
402
- if (!apiKey) {
403
- console.log(chalk.red('\n' + i18n.t('wizard.api_key_required')));
404
- console.log(chalk.yellow(i18n.t('wizard.please_config_api_key_first')));
405
- await inquirer.prompt([{ type: 'input', name: 'continue', message: i18n.t('wizard.press_enter') }]);
406
- return;
407
- }
408
- // 再次验证 API Key 是否有效
409
- const spinner = ora(i18n.t('wizard.validating_api_key')).start();
410
- const result = await validateApiKey(apiKey);
411
- if (!result.valid) {
412
- spinner.fail(i18n.t('wizard.api_key_invalid'));
413
- console.log(chalk.red('\n' + i18n.t('wizard.please_reconfig_api_key')));
414
- await inquirer.prompt([{ type: 'input', name: 'continue', message: i18n.t('wizard.press_enter') }]);
415
- return;
416
- }
417
- spinner.text = i18n.t('wizard.loading_config');
418
- try {
419
- toolManager.loadPrivateConfig(toolName, apiKey, models);
420
- spinner.succeed(i18n.t('wizard.config_loaded', { tool: SUPPORTED_TOOLS[toolName]?.displayName || toolName }));
421
- // 提供选择:退出或继续配置
422
- const { nextAction } = await inquirer.prompt([{
423
- type: 'list',
424
- name: 'nextAction',
425
- message: i18n.t('wizard.what_next'),
426
- choices: [
427
- { name: i18n.t('wizard.exit_and_start'), value: 'exit' },
428
- { name: i18n.t('wizard.continue_config'), value: 'continue' }
429
- ]
430
- }]);
431
- if (nextAction === 'exit') {
432
- console.log(chalk.green('\n👋 ' + i18n.t('wizard.goodbye_message')));
433
- process.exit(0);
434
- }
435
- }
436
- catch (error) {
437
- spinner.fail(i18n.t('wizard.config_failed'));
438
- console.log(chalk.red(error instanceof Error ? error.message : String(error)));
439
- await inquirer.prompt([{ type: 'input', name: 'continue', message: i18n.t('wizard.press_enter') }]);
440
- }
441
- }
442
- async unloadConfig(toolName) {
443
- const { confirm } = await inquirer.prompt([
444
- {
445
- type: 'confirm',
446
- name: 'confirm',
447
- message: i18n.t('wizard.confirm_unload_config', { tool: SUPPORTED_TOOLS[toolName]?.displayName || toolName }),
448
- default: false
449
- }
450
- ]);
451
- if (!confirm)
452
- return;
453
- const spinner = ora(i18n.t('wizard.unloading_config')).start();
454
- try {
455
- toolManager.unloadPrivateConfig(toolName);
456
- spinner.succeed(i18n.t('wizard.config_unloaded'));
457
- // 提供选择:退出或继续配置
458
- const { nextAction } = await inquirer.prompt([{
459
- type: 'list',
460
- name: 'nextAction',
461
- message: i18n.t('wizard.what_next'),
462
- choices: [
463
- { name: i18n.t('wizard.exit_and_start'), value: 'exit' },
464
- { name: i18n.t('wizard.continue_config'), value: 'continue' }
465
- ]
466
- }]);
467
- if (nextAction === 'exit') {
468
- console.log(chalk.green('\n👋 ' + i18n.t('wizard.goodbye_message')));
469
- process.exit(0);
470
- }
471
- }
472
- catch (error) {
473
- spinner.fail(i18n.t('wizard.config_unload_failed'));
474
- console.log(chalk.red(error instanceof Error ? error.message : String(error)));
475
- await inquirer.prompt([{ type: 'input', name: 'continue', message: i18n.t('wizard.press_enter') }]);
476
- }
477
- }
478
- async run() {
479
- const config = configManager.getConfig();
480
- // 初始化时验证 API Key
481
- if (config.api_key) {
482
- const result = await validateApiKey(config.api_key);
483
- this.apiKeyValid = result.valid;
484
- }
485
- else {
486
- this.apiKeyValid = false;
487
- }
488
- if (!config.api_key || !this.apiKeyValid) {
489
- await this.runFirstTimeSetup();
490
- }
491
- else {
492
- await this.showMainMenu();
493
- }
494
- }
495
- async showMainMenu() {
496
- while (true) {
497
- this.resetScreen();
498
- this.createBox(i18n.t('wizard.main_menu_title'));
499
- // 构建菜单选项
500
- const choices = [];
501
- // 只有 API Key 有效时才显示编码工具和模型配置
502
- if (this.apiKeyValid) {
503
- choices.push({ name: '🛠️ ' + i18n.t('wizard.menu_config_tool'), value: 'tools' });
504
- choices.push({ name: '⚙️ ' + i18n.t('wizard.menu_config_models'), value: 'models' });
505
- choices.push(new inquirer.Separator());
506
- }
507
- choices.push({ name: '🔑 ' + i18n.t('wizard.menu_config_api_key'), value: 'apikey' });
508
- choices.push({ name: '🌐 ' + i18n.t('wizard.menu_config_language'), value: 'language' });
509
- choices.push({ name: '🧪 ' + i18n.t('wizard.menu_experimental_features'), value: 'experimental' });
510
- choices.push(new inquirer.Separator());
511
- choices.push({ name: 'x ' + i18n.t('wizard.nav_exit'), value: 'exit' });
512
- const { action } = await this.promptWithHints([
513
- {
514
- type: 'list',
515
- name: 'action',
516
- message: i18n.t('wizard.select_operation'),
517
- choices: choices
518
- }
519
- ]);
520
- if (action === 'exit') {
521
- console.log(chalk.green('\n👋 ' + i18n.t('wizard.goodbye_message')));
522
- process.exit(0);
523
- }
524
- else if (action === 'language') {
525
- await this.configLanguage();
526
- }
527
- else if (action === 'apikey') {
528
- await this.configApiKey();
529
- // 配置完 API Key 后重新验证
530
- const apiKey = configManager.getApiKey();
531
- if (apiKey) {
532
- const result = await validateApiKey(apiKey);
533
- this.apiKeyValid = result.valid;
534
- // 如果 API Key 有效,直接进入模型配置
535
- if (this.apiKeyValid) {
536
- await this.configModels();
537
- }
538
- }
539
- else {
540
- this.apiKeyValid = false;
541
- }
542
- }
543
- else if (action === 'models') {
544
- await this.configModels();
545
- }
546
- else if (action === 'tools') {
547
- await this.selectAndConfigureTool();
548
- }
549
- else if (action === 'experimental') {
550
- await this.configExperimentalFeatures();
551
- }
552
- }
553
- }
554
- async configExperimentalFeatures() {
555
- while (true) {
556
- this.resetScreen();
557
- this.createBox(i18n.t('wizard.experimental_features_title'));
558
- // Check current status
559
- const agentTeamsEnabled = claudeCodeManager.getExperimentalFeature('CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS') === '1';
560
- const { action } = await this.promptWithHints([
561
- {
562
- type: 'list',
563
- name: 'action',
564
- message: i18n.t('wizard.select_experimental_feature'),
565
- choices: [
566
- {
567
- name: '🤖 Agent Teams' + (agentTeamsEnabled ? chalk.green(' ✓ (' + i18n.t('wizard.enabled') + ')') : chalk.gray(' (' + i18n.t('wizard.disabled') + ')')),
568
- value: 'agent-teams'
569
- },
570
- new inquirer.Separator(),
571
- { name: '<- ' + i18n.t('wizard.nav_return'), value: 'back' },
572
- { name: 'x ' + i18n.t('wizard.nav_exit'), value: 'exit' }
573
- ]
574
- }
575
- ]);
576
- if (action === 'exit') {
577
- console.log(chalk.green('\n👋 ' + i18n.t('wizard.goodbye_message')));
578
- process.exit(0);
579
- }
580
- else if (action === 'back') {
581
- return;
582
- }
583
- else if (action === 'agent-teams') {
584
- await this.toggleAgentTeams();
585
- }
586
- }
587
- }
588
- async toggleAgentTeams() {
589
- const isEnabled = claudeCodeManager.getExperimentalFeature('CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS') === '1';
590
- const { action } = await inquirer.prompt([
591
- {
592
- type: 'list',
593
- name: 'action',
594
- message: i18n.t('wizard.agent_teams_current_status') + ': ' + (isEnabled ? chalk.green(i18n.t('wizard.enabled')) : chalk.gray(i18n.t('wizard.disabled'))),
595
- choices: [
596
- { name: i18n.t('wizard.enable'), value: 'enable' },
597
- { name: i18n.t('wizard.disable'), value: 'disable' },
598
- new inquirer.Separator(),
599
- { name: '<- ' + i18n.t('wizard.nav_return'), value: 'back' }
600
- ]
601
- }
602
- ]);
603
- if (action === 'back')
604
- return;
605
- const spinner = ora(i18n.t('wizard.updating_settings')).start();
606
- try {
607
- if (action === 'enable') {
608
- claudeCodeManager.setExperimentalFeature('CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS', '1');
609
- spinner.succeed(chalk.green('✓ ' + i18n.t('wizard.agent_teams_enabled')));
610
- }
611
- else {
612
- claudeCodeManager.removeExperimentalFeature('CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS');
613
- spinner.succeed(chalk.green('✓ ' + i18n.t('wizard.agent_teams_disabled')));
614
- }
615
- await inquirer.prompt([{ type: 'input', name: 'continue', message: i18n.t('wizard.press_enter') }]);
616
- }
617
- catch (error) {
618
- spinner.fail(i18n.t('wizard.update_failed'));
619
- console.log(chalk.red(error instanceof Error ? error.message : String(error)));
620
- await inquirer.prompt([{ type: 'input', name: 'continue', message: i18n.t('wizard.press_enter') }]);
621
- }
622
- }
623
- }
624
- export const wizard = Wizard.getInstance();
625
- //# sourceMappingURL=wizard.js.map
1
+ import e from"inquirer";import t from"chalk";import a from"ora";import{configManager as i,DEFAULT_MODELS as o}from"./config.js";import{getPresets as n,resolvePreset as r}from"./model-registry.js";import{toolManager as s,SUPPORTED_TOOLS as l}from"./tool-manager.js";import{i18n as c}from"./i18n.js";import{createBorderLine as d,createContentLine as p}from"../utils/string-width.js";import{validateApiKey as m}from"./api-validator.js";import{readFileSync as g}from"fs";import{dirname as u,join as w}from"path";import{fileURLToPath as _}from"url";const y=u(_(import.meta.url)),h=t.hex("#FF8700");export class Wizard{static instance;BOX_WIDTH=63;apiKeyValid=!1;constructor(){}static getInstance(){return Wizard.instance||(Wizard.instance=new Wizard),Wizard.instance}createBox(e){console.log(h.bold("\n"+d("╔","╗","═",this.BOX_WIDTH))),console.log(h.bold(p(e,"║","║",this.BOX_WIDTH,"center"))),console.log(h.bold(d("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(c.t("wizard.hint_navigate")),t.gray(c.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const a=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(a)}printBanner(){const e=65,t=c.t("wizard.banner_subtitle"),a=p(t,"║","║",e,"center"),i=p("","║","║",e,"center"),o=p(`API Helper v${function(){try{return JSON.parse(g(w(y,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[" ▄▀▄ █▀▄ █ █▄█ ██▀ █ █▀▄ ██▀ █▀▄ "," █▀█ █▀ █ █ █ █▄▄ █▄▄ █▀ █▄▄ █▀▄ "].map(t=>p(t,"║","║",e,"center")),r=[d("╔","╗","═",e),i,...n,i,o,a,d("╚","╝","═",e)];console.log(h.bold("\n"+r.join("\n")))}resetScreen(){console.clear(),this.printBanner()}async runFirstTimeSetup(){this.resetScreen(),console.log(h.bold("\n"+c.t("wizard.welcome"))),console.log(t.gray(c.t("wizard.privacy_note")+"\n")),await this.configLanguage(),await this.configApiKey(),i.getApiKey()?(await this.configModels({skipLoadPrompt:!0}),await this.selectAndConfigureTool()):console.log(t.red("\n"+c.t("wizard.api_key_required")))}async configLanguage(){for(;;){this.resetScreen(),this.createBox(c.t("wizard.select_language"));const a=c.getLocale(),{language:o}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+c.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===a?t.green(" ✓ ("+c.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===a?t.green(" ✓ ("+c.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+c.t("wizard.nav_return"),value:"back"},{name:"x "+c.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===o)console.log(t.green("\n👋 "+c.t("wizard.goodbye_message"))),process.exit(0);else if("back"===o)return;return i.setLang(o),void c.setLocale(o)}}async configModels(a){if(!i.getApiKey())return console.log(t.red("\n"+c.t("wizard.api_key_required"))),void await e.prompt([{type:"input",name:"continue",message:c.t("wizard.press_enter")}]);for(;;){this.resetScreen(),this.createBox(c.t("wizard.config_models"));const s=n(),l=s.filter(e=>e.recommended),d=s.filter(e=>!e.recommended),p=e=>{const a=e.models?t.gray(` [H:${e.models.haiku} S:${e.models.sonnet} O:${e.models.opus}]`):"";return{name:e.name+a,value:{type:"preset",preset:e}}},m=[];l.length>0&&(m.push(new e.Separator(t.hex("#FF8700")("── "+c.t("wizard.recommended")+" ──"))),m.push(...l.map(p))),d.length>0&&(m.push(new e.Separator(t.gray("── "+c.t("wizard.other_models")+" ──"))),m.push(...d.map(p))),m.push(new e.Separator),m.push({name:"✏️ "+c.t("wizard.custom_model_input"),value:{type:"custom_input"}}),m.push(new e.Separator),m.push({name:"<- "+c.t("wizard.nav_return"),value:{type:"back"}}),m.push({name:"x "+c.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:g}=await this.promptWithHints([{type:"list",name:"modelChoice",message:c.t("wizard.select_model_config"),choices:m}]);if("exit"===g.type)console.log(t.green("\n👋 "+c.t("wizard.goodbye_message"))),process.exit(0);else{if("back"===g.type)return;if("custom_input"===g.type){const{customModel:n}=await e.prompt([{type:"input",name:"customModel",message:c.t("wizard.input_custom_model"),default:o.sonnet}]),r={haiku:n,sonnet:n,opus:n,reasoning:n};return i.setModels(r),console.log(t.green("\n✓ "+c.t("wizard.models_saved"))),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}if("preset"===g.type){const e=r(g.preset);return i.setModels(e),console.log(t.green("\n✓ "+c.t("wizard.models_saved"))),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:c.t("wizard.load_config_now"),choices:[{name:c.t("wizard.load_config_yes"),value:!0},{name:c.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configApiKey(){for(;;){this.resetScreen(),this.createBox(c.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+c.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+c.t("wizard.api_key_get_hint",{url:"https://www.vibeapi.cn/console/token"}))),console.log();const{apiKey:o}=await e.prompt([{type:"password",name:"apiKey",message:c.t("wizard.input_your_api_key"),mask:"*"}]);if(!o||""===o.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:c.t("wizard.select_action"),choices:[{name:c.t("wizard.retry_input"),value:"retry"},{name:"<- "+c.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return;continue}const n=a(c.t("wizard.validating_api_key")).start(),r=await m(o.trim());if(n.stop(),r.valid)return i.setApiKey(o.trim()),this.apiKeyValid=!0,void console.log(t.green("\n✓ "+c.t("wizard.api_key_valid")));{this.apiKeyValid=!1,"invalid_api_key"===r.error?console.log(t.red("\n✗ "+c.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+c.t("wizard.api_key_network_error")));const{action:a}=await e.prompt([{type:"list",name:"action",message:c.t("wizard.select_action"),choices:[{name:c.t("wizard.retry_input"),value:"retry"},{name:"<- "+c.t("wizard.nav_return"),value:"back"}]}]);if("back"===a)return}}}async selectAndConfigureTool(){for(;;){this.resetScreen(),this.createBox(c.t("wizard.select_tool"));const{tool:a}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+c.t("wizard.select_tool"),choices:[{name:"Claude Code",value:"claude-code"},{name:"OpenCode",value:"opencode"},new e.Separator,{name:"<- "+c.t("wizard.nav_return"),value:"back"},{name:"x "+c.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===a)console.log(t.green("\n👋 "+c.t("wizard.goodbye_message"))),process.exit(0);else if("back"===a)return;await this.configureTool(a)}}async configureTool(a){const i=l[a];if(i){if(!s.isToolInstalled(a)){console.log(t.yellow("\n"+c.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:o}=await e.prompt([{type:"confirm",name:"install",message:c.t("wizard.install_tool_confirm"),default:!0}]);if(!o)return;try{await s.installTool(a)}catch(e){return void console.log(t.red(c.t("wizard.install_failed")))}}await this.showToolMenu(a)}}async showToolMenu(a){for(;;){this.resetScreen();const i=l[a];if(!i)return;this.createBox(i.displayName+" "+c.t("wizard.menu_title"));const{action:o}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+c.t("wizard.select_action"),choices:[{name:"📥 "+c.t("wizard.action_load_config",{tool:i.displayName}),value:"load"},{name:"📤 "+c.t("wizard.action_unload_config",{tool:i.displayName}),value:"unload"},new e.Separator,{name:"<- "+c.t("wizard.nav_return"),value:"back"},{name:"x "+c.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===o)console.log(t.green("\n👋 "+c.t("wizard.goodbye_message"))),process.exit(0);else{if("back"===o)return;"load"===o?await this.loadConfig(a):"unload"===o&&await this.unloadConfig(a)}}}async loadConfig(o){const n=i.getApiKey(),r=i.getModels();if(!n)return console.log(t.red("\n"+c.t("wizard.api_key_required"))),console.log(t.yellow(c.t("wizard.please_config_api_key_first"))),void await e.prompt([{type:"input",name:"continue",message:c.t("wizard.press_enter")}]);if(!this.apiKeyValid){const i=a(c.t("wizard.validating_api_key")).start();if(!(await m(n)).valid)return i.fail(c.t("wizard.api_key_invalid")),console.log(t.red("\n"+c.t("wizard.please_reconfig_api_key"))),void await e.prompt([{type:"input",name:"continue",message:c.t("wizard.press_enter")}]);this.apiKeyValid=!0,i.stop()}const d=a(c.t("wizard.loading_config")).start();try{s.loadPrivateConfig(o,n,r),d.succeed(c.t("wizard.config_loaded",{tool:l[o]?.displayName||o}));const{nextAction:a}=await e.prompt([{type:"list",name:"nextAction",message:c.t("wizard.what_next"),choices:[{name:c.t("wizard.exit_and_start"),value:"exit"},{name:c.t("wizard.continue_config"),value:"continue"}]}]);"exit"===a&&(console.log(t.green("\n👋 "+c.t("wizard.goodbye_message"))),process.exit(0))}catch(a){d.fail(c.t("wizard.config_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:c.t("wizard.press_enter")}])}}async unloadConfig(i){const{confirm:o}=await e.prompt([{type:"confirm",name:"confirm",message:c.t("wizard.confirm_unload_config",{tool:l[i]?.displayName||i}),default:!1}]);if(!o)return;const n=a(c.t("wizard.unloading_config")).start();try{s.unloadPrivateConfig(i),n.succeed(c.t("wizard.config_unloaded"));const{nextAction:a}=await e.prompt([{type:"list",name:"nextAction",message:c.t("wizard.what_next"),choices:[{name:c.t("wizard.exit_and_start"),value:"exit"},{name:c.t("wizard.continue_config"),value:"continue"}]}]);"exit"===a&&(console.log(t.green("\n👋 "+c.t("wizard.goodbye_message"))),process.exit(0))}catch(a){n.fail(c.t("wizard.config_unload_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:c.t("wizard.press_enter")}])}}async run(){const e=i.getConfig();if(e.api_key){const t=await m(e.api_key);this.apiKeyValid=t.valid}else this.apiKeyValid=!1;e.api_key&&this.apiKeyValid?await this.showMainMenu():await this.runFirstTimeSetup()}async showMainMenu(){for(;;){this.resetScreen();const a=i.getApiKey()||"",s=a.length>4?"sk-****"+a.slice(-4):"****",l=i.getModels(),d=l.opus||l.sonnet||"N/A";console.log(t.gray(` 🔑 API Key: ${s}`)+t.green(" ✓")),console.log(t.gray(` 🤖 ${c.t("wizard.current_model")}: ${d}`)),console.log("");const p=n(),g=p.filter(e=>e.recommended),u=p.filter(e=>!e.recommended),w=e=>{const a=e.models?t.gray(` [H:${e.models.haiku} S:${e.models.sonnet} O:${e.models.opus}]`):"";return{name:e.name+a,value:{type:"preset",preset:e}}},_=[];g.length>0&&(_.push(new e.Separator(t.hex("#FF8700")("── "+c.t("wizard.recommended")+" ──"))),_.push(...g.map(w))),u.length>0&&(_.push(new e.Separator(t.gray("── "+c.t("wizard.other_models")+" ──"))),_.push(...u.map(w))),_.push(new e.Separator),_.push({name:"✏️ "+c.t("wizard.custom_model_input"),value:{type:"custom_input"}}),_.push({name:"🛠️ "+c.t("wizard.menu_load_to_tool"),value:{type:"load_tool"}}),_.push(new e.Separator(t.gray("── "+c.t("wizard.settings")+" ──"))),_.push({name:"🔑 "+c.t("wizard.menu_change_api_key"),value:{type:"apikey"}}),_.push({name:"🌐 "+c.t("wizard.menu_config_language"),value:{type:"language"}}),_.push(new e.Separator),_.push({name:"x "+c.t("wizard.nav_exit"),value:{type:"exit"}});const{action:y}=await this.promptWithHints([{type:"list",name:"action",message:c.t("wizard.select_model_config"),choices:_}]);if("exit"===y.type)console.log(t.green("\n👋 "+c.t("wizard.goodbye_message"))),process.exit(0);else if("preset"===y.type){const e=r(y.preset);i.setModels(e),console.log(t.green("\n✓ "+c.t("wizard.models_saved"))),await this.promptLoadAfterModelConfig()}else if("custom_input"===y.type){const{customModel:a}=await e.prompt([{type:"input",name:"customModel",message:c.t("wizard.input_custom_model"),default:o.sonnet}]);i.setModels({haiku:a,sonnet:a,opus:a,reasoning:a}),console.log(t.green("\n✓ "+c.t("wizard.models_saved"))),await this.promptLoadAfterModelConfig()}else if("load_tool"===y.type)await this.selectAndConfigureTool();else if("apikey"===y.type){await this.configApiKey();const e=i.getApiKey();if(e){const t=await m(e);this.apiKeyValid=t.valid}else this.apiKeyValid=!1}else"language"===y.type&&await this.configLanguage()}}}export const wizard=Wizard.getInstance();