@pikecode/api-key-manager 1.0.38 → 1.0.42

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.
@@ -1,19 +1,43 @@
1
+ /**
2
+ * Provider Adder Command
3
+ * 添加新供应商的交互式命令
4
+ * @module commands/add
5
+ */
6
+
1
7
  const inquirer = require('inquirer');
2
8
  const chalk = require('chalk');
3
9
  const { configManager } = require('../config');
4
10
  const { validator } = require('../utils/validator');
5
11
  const { Logger } = require('../utils/logger');
6
12
  const { UIHelper } = require('../utils/ui-helper');
7
- const { maskToken } = require('../utils/secrets');
8
13
  const { BaseCommand } = require('./BaseCommand');
9
-
14
+ const {
15
+ AUTH_MODE_DISPLAY_DETAILED,
16
+ TOKEN_TYPE_DISPLAY,
17
+ IDE_NAMES
18
+ } = require('../constants');
19
+
20
+ /**
21
+ * 供应商添加器类
22
+ * 用于交互式添加新的 API 供应商配置
23
+ * @extends BaseCommand
24
+ */
10
25
  class ProviderAdder extends BaseCommand {
26
+ /**
27
+ * 创建供应商添加器实例
28
+ * @param {Object} options - 配置选项
29
+ * @param {string} [options.ideName] - 预设的 IDE 名称(claude-code 或 codex)
30
+ */
11
31
  constructor(options = {}) {
12
32
  super();
13
33
  this.configManager = configManager;
14
34
  this.presetIdeName = options.ideName || null;
15
35
  }
16
36
 
37
+ /**
38
+ * 执行交互式添加供应商流程
39
+ * @returns {Promise<void>}
40
+ */
17
41
  async interactive() {
18
42
  console.log(UIHelper.createTitle('添加新供应商', UIHelper.icons.add));
19
43
  console.log();
@@ -26,18 +50,10 @@ class ProviderAdder extends BaseCommand {
26
50
  ['ESC', '取消添加']
27
51
  ]));
28
52
  console.log();
29
-
30
- // 设置 ESC 键监听
31
- const escListener = this.createESCListener(() => {
32
- Logger.info('取消添加供应商');
33
- // 使用CommandRegistry避免循环引用
34
- const { registry } = require('../CommandRegistry');
35
- registry.executeCommand('switch');
36
- }, '取消添加');
37
53
 
38
54
  try {
39
55
  // 首先选择是否使用预设配置
40
- const typeAnswer = await this.prompt([
56
+ const typeAnswer = await this.promptWithESC([
41
57
  {
42
58
  type: 'list',
43
59
  name: 'providerType',
@@ -48,10 +64,12 @@ class ProviderAdder extends BaseCommand {
48
64
  ],
49
65
  default: 'custom'
50
66
  }
51
- ]);
52
-
53
- // 移除 ESC 键监听
54
- this.removeESCListener(escListener);
67
+ ], '取消添加', () => {
68
+ Logger.info('取消添加供应商');
69
+ // 使用CommandRegistry避免循环引用
70
+ const { registry } = require('../CommandRegistry');
71
+ registry.executeCommand('switch');
72
+ });
55
73
 
56
74
  if (typeAnswer.providerType === 'official_oauth') {
57
75
  return await this.addOfficialOAuthProvider();
@@ -59,8 +77,6 @@ class ProviderAdder extends BaseCommand {
59
77
  return await this.addCustomProvider();
60
78
  }
61
79
  } catch (error) {
62
- // 移除 ESC 键监听
63
- this.removeESCListener(escListener);
64
80
  if (this.isEscCancelled(error)) {
65
81
  return;
66
82
  }
@@ -80,17 +96,9 @@ class ProviderAdder extends BaseCommand {
80
96
  ['ESC', '取消添加']
81
97
  ]));
82
98
  console.log();
83
-
84
- // 设置 ESC 键监听
85
- const escListener = this.createESCListener(() => {
86
- Logger.info('取消添加供应商');
87
- // 使用CommandRegistry避免循环引用
88
- const { registry } = require('../CommandRegistry');
89
- registry.executeCommand('switch');
90
- }, '取消添加');
91
99
 
92
100
  try {
93
- const answers = await this.prompt([
101
+ const answers = await this.promptWithESC([
94
102
  {
95
103
  type: 'input',
96
104
  name: 'name',
@@ -132,11 +140,13 @@ class ProviderAdder extends BaseCommand {
132
140
  message: '是否设置为当前供应商?',
133
141
  default: true
134
142
  }
135
- ]);
143
+ ], '取消添加', () => {
144
+ Logger.info('取消添加供应商');
145
+ // 使用CommandRegistry避免循环引用
146
+ const { registry } = require('../CommandRegistry');
147
+ registry.executeCommand('switch');
148
+ });
136
149
 
137
- // 移除 ESC 键监听
138
- this.removeESCListener(escListener);
139
-
140
150
  // 使用官方 OAuth 配置
141
151
  await this.saveProvider({
142
152
  ...answers,
@@ -144,8 +154,6 @@ class ProviderAdder extends BaseCommand {
144
154
  baseUrl: null // OAuth 模式不需要 baseUrl
145
155
  });
146
156
  } catch (error) {
147
- // 移除 ESC 键监听
148
- this.removeESCListener(escListener);
149
157
  if (this.isEscCancelled(error)) {
150
158
  return;
151
159
  }
@@ -166,16 +174,8 @@ class ProviderAdder extends BaseCommand {
166
174
  ]));
167
175
  console.log();
168
176
 
169
- // 设置 ESC 键监听
170
- const escListener = this.createESCListener(() => {
171
- Logger.info('取消添加供应商');
172
- // 使用CommandRegistry避免循环引用
173
- const { registry } = require('../CommandRegistry');
174
- registry.executeCommand('switch');
175
- }, '取消添加');
176
-
177
177
  try {
178
- const answers = await this.prompt([
178
+ const answers = await this.promptWithESC([
179
179
  {
180
180
  type: 'list',
181
181
  name: 'ideName',
@@ -218,6 +218,17 @@ class ProviderAdder extends BaseCommand {
218
218
  return true;
219
219
  }
220
220
  },
221
+ {
222
+ type: 'input',
223
+ name: 'alias',
224
+ message: '请输入供应商别名 (可选,用于快速切换):',
225
+ validate: (input) => {
226
+ if (!input) return true; // 别名是可选的
227
+ const error = validator.validateName(input);
228
+ if (error) return error;
229
+ return true;
230
+ }
231
+ },
221
232
  {
222
233
  type: 'list',
223
234
  name: 'authMode',
@@ -270,15 +281,15 @@ class ProviderAdder extends BaseCommand {
270
281
  name: 'authToken',
271
282
  message: (answers) => {
272
283
  switch (answers.authMode) {
273
- case 'api_key':
274
- const tokenTypeLabel = answers.tokenType === 'auth_token' ? 'ANTHROPIC_AUTH_TOKEN' : 'ANTHROPIC_API_KEY';
275
- return `请输入Token (${tokenTypeLabel}):`;
276
- case 'auth_token':
277
- return '请输入认证令牌 (ANTHROPIC_AUTH_TOKEN):';
278
- case 'oauth_token':
279
- return '请输入OAuth令牌 (CLAUDE_CODE_OAUTH_TOKEN):';
280
- default:
281
- return '请输入认证令牌:';
284
+ case 'api_key':
285
+ const tokenTypeLabel = answers.tokenType === 'auth_token' ? 'ANTHROPIC_AUTH_TOKEN' : 'ANTHROPIC_API_KEY';
286
+ return `请输入Token (${tokenTypeLabel}):`;
287
+ case 'auth_token':
288
+ return '请输入认证令牌 (ANTHROPIC_AUTH_TOKEN):';
289
+ case 'oauth_token':
290
+ return '请输入OAuth令牌 (CLAUDE_CODE_OAUTH_TOKEN):';
291
+ default:
292
+ return '请输入认证令牌:';
282
293
  }
283
294
  },
284
295
  validate: (input) => {
@@ -340,10 +351,12 @@ class ProviderAdder extends BaseCommand {
340
351
  default: false,
341
352
  when: (answers) => (answers.ideName || this.presetIdeName) !== 'codex'
342
353
  }
343
- ]);
344
-
345
- // 移除 ESC 键监听
346
- this.removeESCListener(escListener);
354
+ ], '取消添加', () => {
355
+ Logger.info('取消添加供应商');
356
+ // 使用CommandRegistry避免循环引用
357
+ const { registry } = require('../CommandRegistry');
358
+ registry.executeCommand('switch');
359
+ });
347
360
 
348
361
  // 如果是预设的 ideName,设置到 answers 中
349
362
  if (!answers.ideName && this.presetIdeName) {
@@ -390,8 +403,6 @@ class ProviderAdder extends BaseCommand {
390
403
 
391
404
  await this.saveProvider(answers);
392
405
  } catch (error) {
393
- // 移除 ESC 键监听
394
- this.removeESCListener(escListener);
395
406
  if (this.isEscCancelled(error)) {
396
407
  return;
397
408
  }
@@ -448,26 +459,22 @@ class ProviderAdder extends BaseCommand {
448
459
  }
449
460
 
450
461
  async confirmOverwrite(name) {
451
- const escListener = this.createESCListener(() => {
452
- Logger.info('取消覆盖供应商');
453
- const { switchCommand } = require('./switch');
454
- switchCommand();
455
- }, '取消覆盖');
456
-
457
462
  try {
458
- const { overwrite } = await this.prompt([
463
+ const { overwrite } = await this.promptWithESC([
459
464
  {
460
465
  type: 'confirm',
461
466
  name: 'overwrite',
462
467
  message: `供应商 '${name}' 已存在,是否覆盖?`,
463
468
  default: false
464
469
  }
465
- ]);
470
+ ], '取消覆盖', () => {
471
+ Logger.info('取消覆盖供应商');
472
+ const { switchCommand } = require('./switch');
473
+ switchCommand();
474
+ });
466
475
 
467
- this.removeESCListener(escListener);
468
476
  return overwrite;
469
477
  } catch (error) {
470
- this.removeESCListener(escListener);
471
478
  throw error;
472
479
  }
473
480
  }
@@ -487,33 +494,22 @@ class ProviderAdder extends BaseCommand {
487
494
  ]));
488
495
  console.log();
489
496
 
490
- const escListener = this.createESCListener(() => {
497
+ const result = await this.promptWithESCAndDefault([
498
+ {
499
+ type: 'checkbox',
500
+ name: 'launchArgs',
501
+ message: '请选择启动参数:',
502
+ choices: validator.getAvailableLaunchArgs().map(arg => ({
503
+ name: `${arg.name} - ${arg.description}`,
504
+ value: arg.name,
505
+ checked: false
506
+ }))
507
+ }
508
+ ], '跳过配置', () => {
491
509
  Logger.info('跳过启动参数配置');
492
- }, '跳过配置');
510
+ }, { launchArgs: [] });
493
511
 
494
- try {
495
- const { launchArgs } = await this.prompt([
496
- {
497
- type: 'checkbox',
498
- name: 'launchArgs',
499
- message: '请选择启动参数:',
500
- choices: validator.getAvailableLaunchArgs().map(arg => ({
501
- name: `${arg.name} - ${arg.description}`,
502
- value: arg.name,
503
- checked: false
504
- }))
505
- }
506
- ]);
507
-
508
- this.removeESCListener(escListener);
509
- return launchArgs;
510
- } catch (error) {
511
- this.removeESCListener(escListener);
512
- if (this.isEscCancelled(error)) {
513
- return [];
514
- }
515
- throw error;
516
- }
512
+ return result.launchArgs;
517
513
  }
518
514
 
519
515
  async promptModelConfiguration() {
@@ -528,48 +524,37 @@ class ProviderAdder extends BaseCommand {
528
524
  ]));
529
525
  console.log();
530
526
 
531
- const escListener = this.createESCListener(() => {
532
- Logger.info('跳过模型参数配置');
533
- }, '跳过配置');
534
-
535
- try {
536
- const responses = await this.prompt([
537
- {
538
- type: 'input',
539
- name: 'primaryModel',
540
- message: '主模型 (ANTHROPIC_MODEL):',
541
- default: '',
542
- validate: (input) => {
543
- const error = validator.validateModel(input);
544
- if (error) return error;
545
- return true;
546
- }
547
- },
548
- {
549
- type: 'input',
550
- name: 'smallFastModel',
551
- message: '快速模型 (ANTHROPIC_SMALL_FAST_MODEL):',
552
- default: '',
553
- validate: (input) => {
554
- const error = validator.validateModel(input);
555
- if (error) return error;
556
- return true;
557
- }
527
+ const responses = await this.promptWithESCAndDefault([
528
+ {
529
+ type: 'input',
530
+ name: 'primaryModel',
531
+ message: '主模型 (ANTHROPIC_MODEL):',
532
+ default: '',
533
+ validate: (input) => {
534
+ const error = validator.validateModel(input);
535
+ if (error) return error;
536
+ return true;
537
+ }
538
+ },
539
+ {
540
+ type: 'input',
541
+ name: 'smallFastModel',
542
+ message: '快速模型 (ANTHROPIC_SMALL_FAST_MODEL):',
543
+ default: '',
544
+ validate: (input) => {
545
+ const error = validator.validateModel(input);
546
+ if (error) return error;
547
+ return true;
558
548
  }
559
- ]);
560
-
561
- this.removeESCListener(escListener);
562
- return {
563
- primaryModel: responses.primaryModel,
564
- smallFastModel: responses.smallFastModel
565
- };
566
- } catch (error) {
567
- this.removeESCListener(escListener);
568
- if (this.isEscCancelled(error)) {
569
- return { primaryModel: null, smallFastModel: null };
570
549
  }
571
- throw error;
572
- }
550
+ ], '跳过配置', () => {
551
+ Logger.info('跳过模型参数配置');
552
+ }, { primaryModel: null, smallFastModel: null });
553
+
554
+ return {
555
+ primaryModel: responses.primaryModel,
556
+ smallFastModel: responses.smallFastModel
557
+ };
573
558
  }
574
559
 
575
560
  async importCodexConfig() {
@@ -590,11 +575,18 @@ class ProviderAdder extends BaseCommand {
590
575
  }
591
576
 
592
577
  // 尝试从 config.toml 获取 base URL
578
+ // 支持 api_base_url(akm 写入的格式)和 api_base(某些旧配置可能使用)
593
579
  let baseUrl = null;
594
580
  if (codexFiles.configToml) {
595
- const baseUrlMatch = codexFiles.configToml.match(/api_base\s*=\s*["']([^"']+)["']/);
581
+ const baseUrlMatch = codexFiles.configToml.match(/api_base_url\s*=\s*["']([^"']+)["']/);
596
582
  if (baseUrlMatch) {
597
583
  baseUrl = baseUrlMatch[1];
584
+ } else {
585
+ // 兼容旧格式
586
+ const legacyMatch = codexFiles.configToml.match(/api_base\s*=\s*["']([^"']+)["']/);
587
+ if (legacyMatch) {
588
+ baseUrl = legacyMatch[1];
589
+ }
598
590
  }
599
591
  }
600
592
 
@@ -620,15 +612,11 @@ class ProviderAdder extends BaseCommand {
620
612
  ]));
621
613
  console.log();
622
614
 
623
- const escListener = this.createESCListener(() => {
624
- Logger.info('跳过 Codex 启动参数配置');
625
- }, '跳过配置');
626
-
627
615
  try {
628
616
  const { getCodexLaunchArgs, checkExclusiveArgs } = require('../utils/launch-args');
629
617
  const codexArgs = getCodexLaunchArgs();
630
618
 
631
- const { launchArgs } = await this.prompt([
619
+ const result = await this.promptWithESCAndDefault([
632
620
  {
633
621
  type: 'checkbox',
634
622
  name: 'launchArgs',
@@ -639,9 +627,11 @@ class ProviderAdder extends BaseCommand {
639
627
  checked: arg.checked
640
628
  }))
641
629
  }
642
- ]);
630
+ ], '跳过配置', () => {
631
+ Logger.info('跳过 Codex 启动参数配置');
632
+ }, { launchArgs: [] });
643
633
 
644
- this.removeESCListener(escListener);
634
+ const { launchArgs } = result;
645
635
 
646
636
  const conflictError = checkExclusiveArgs(launchArgs, codexArgs);
647
637
  if (conflictError) {
@@ -650,10 +640,6 @@ class ProviderAdder extends BaseCommand {
650
640
  }
651
641
  return launchArgs;
652
642
  } catch (error) {
653
- this.removeESCListener(escListener);
654
- if (this.isEscCancelled(error)) {
655
- return [];
656
- }
657
643
  throw error;
658
644
  }
659
645
  }
@@ -672,7 +658,7 @@ class ProviderAdder extends BaseCommand {
672
658
  console.log(chalk.gray(` OPENAI_BASE_URL: ${answers.baseUrl}`));
673
659
  }
674
660
  if (answers.authToken) {
675
- console.log(chalk.gray(` OPENAI_API_KEY: ${maskToken(answers.authToken)}`));
661
+ console.log(chalk.gray(` OPENAI_API_KEY: ${answers.authToken}`));
676
662
  }
677
663
  if (answers.launchArgs && answers.launchArgs.length > 0) {
678
664
  console.log(chalk.gray(` 启动参数: ${answers.launchArgs.join(' ')}`));
@@ -681,24 +667,18 @@ class ProviderAdder extends BaseCommand {
681
667
  return;
682
668
  }
683
669
 
684
- const authModeDisplay = {
685
- api_key: '通用API密钥模式',
686
- auth_token: '认证令牌模式 (仅 ANTHROPIC_AUTH_TOKEN)',
687
- oauth_token: 'OAuth令牌模式 (CLAUDE_CODE_OAUTH_TOKEN)'
688
- };
689
-
690
- console.log(chalk.gray(` 认证模式: ${authModeDisplay[answers.authMode] || answers.authMode}`));
670
+ console.log(chalk.gray(` 认证模式: ${AUTH_MODE_DISPLAY_DETAILED[answers.authMode] || answers.authMode}`));
691
671
 
692
672
  // 如果是 api_key 模式,显示 tokenType
693
673
  if (answers.authMode === 'api_key' && answers.tokenType) {
694
- const tokenTypeDisplay = answers.tokenType === 'auth_token' ? 'ANTHROPIC_AUTH_TOKEN' : 'ANTHROPIC_API_KEY';
674
+ const tokenTypeDisplay = TOKEN_TYPE_DISPLAY[answers.tokenType];
695
675
  console.log(chalk.gray(` Token类型: ${tokenTypeDisplay}`));
696
676
  }
697
677
 
698
678
  if (answers.baseUrl) {
699
679
  console.log(chalk.gray(` 基础URL: ${answers.baseUrl}`));
700
680
  }
701
- console.log(chalk.gray(` Token: ${maskToken(answers.authToken)}`));
681
+ console.log(chalk.gray(` Token: ${answers.authToken}`));
702
682
 
703
683
  if (launchArgs.length > 0) {
704
684
  console.log(chalk.gray(` 启动参数: ${launchArgs.join(' ')}`));
@@ -1,10 +1,23 @@
1
+ /**
2
+ * Backup Manager Command
3
+ * 配置备份和恢复管理
4
+ * @module commands/backup
5
+ */
6
+
1
7
  const fs = require('fs-extra');
2
8
  const path = require('path');
3
9
  const chalk = require('chalk');
4
10
  const { configManager } = require('../config');
5
11
  const { Logger } = require('../utils/logger');
6
12
 
13
+ /**
14
+ * 备份管理器类
15
+ * 用于导出、导入和管理供应商配置备份
16
+ */
7
17
  class BackupManager {
18
+ /**
19
+ * 创建备份管理器实例
20
+ */
8
21
  constructor() {
9
22
  this.configManager = configManager;
10
23
  }
@@ -116,7 +129,7 @@ class BackupManager {
116
129
 
117
130
  await this.configManager.save();
118
131
 
119
- Logger.success(`配置导入完成`);
132
+ Logger.success('配置导入完成');
120
133
  console.log(chalk.gray(` 导入文件: ${absolutePath}`));
121
134
  console.log(chalk.gray(` 成功导入: ${addedCount} 个供应商`));
122
135
  if (skippedCount > 0) {