ccman 1.0.1 → 2.0.1

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 (91) hide show
  1. package/.env.development +3 -0
  2. package/.env.production +3 -0
  3. package/.github/workflows/release.yml +5 -5
  4. package/CLAUDE.md +246 -185
  5. package/README.md +282 -249
  6. package/README_zh.md +283 -250
  7. package/dev-test.sh +40 -0
  8. package/dist/cli.js +425 -369
  9. package/dist/cli.js.map +1 -1
  10. package/dist/commands/lang.d.ts +3 -0
  11. package/dist/commands/lang.d.ts.map +1 -0
  12. package/dist/commands/lang.js +99 -0
  13. package/dist/commands/lang.js.map +1 -0
  14. package/dist/config/static-env.d.ts +14 -0
  15. package/dist/config/static-env.d.ts.map +1 -0
  16. package/dist/config/static-env.js +17 -0
  17. package/dist/config/static-env.js.map +1 -0
  18. package/dist/core/CCMConfigManager.d.ts +52 -0
  19. package/dist/core/CCMConfigManager.d.ts.map +1 -0
  20. package/dist/core/CCMConfigManager.js +203 -0
  21. package/dist/core/CCMConfigManager.js.map +1 -0
  22. package/dist/core/ClaudeConfigManager.d.ts +35 -0
  23. package/dist/core/ClaudeConfigManager.d.ts.map +1 -0
  24. package/dist/core/ClaudeConfigManager.js +149 -0
  25. package/dist/core/ClaudeConfigManager.js.map +1 -0
  26. package/dist/i18n/LanguageManager.d.ts +43 -0
  27. package/dist/i18n/LanguageManager.d.ts.map +1 -0
  28. package/dist/i18n/LanguageManager.js +157 -0
  29. package/dist/i18n/LanguageManager.js.map +1 -0
  30. package/dist/i18n/messages.d.ts +65 -0
  31. package/dist/i18n/messages.d.ts.map +1 -0
  32. package/dist/i18n/messages.js +144 -0
  33. package/dist/i18n/messages.js.map +1 -0
  34. package/dist/index.d.ts +3 -3
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +3 -8
  37. package/dist/index.js.map +1 -1
  38. package/dist/providers/ProviderManager.d.ts +58 -0
  39. package/dist/providers/ProviderManager.d.ts.map +1 -0
  40. package/dist/providers/ProviderManager.js +335 -0
  41. package/dist/providers/ProviderManager.js.map +1 -0
  42. package/dist/types/index.d.ts +78 -38
  43. package/dist/types/index.d.ts.map +1 -1
  44. package/dist/types/index.js +1 -0
  45. package/dist/types/index.js.map +1 -1
  46. package/dist/utils/env-config.d.ts +27 -0
  47. package/dist/utils/env-config.d.ts.map +1 -0
  48. package/dist/{config/constants.js → utils/env-config.js} +36 -50
  49. package/dist/utils/env-config.js.map +1 -0
  50. package/dist/utils/version.d.ts +2 -64
  51. package/dist/utils/version.d.ts.map +1 -1
  52. package/dist/utils/version.js +12 -158
  53. package/dist/utils/version.js.map +1 -1
  54. package/package.json +17 -16
  55. package/release-temp/README.md +282 -249
  56. package/release-temp/package.json +17 -16
  57. package/scripts/build-env.js +75 -0
  58. package/scripts/modules/create-tag.sh +53 -10
  59. package/scripts/modules/monitor-release.sh +40 -12
  60. package/scripts/modules/version-bump.sh +14 -17
  61. package/scripts/smart-release-v3.sh +20 -26
  62. package/src/cli.ts +462 -394
  63. package/src/commands/lang.ts +105 -0
  64. package/src/core/CCMConfigManager.ts +185 -0
  65. package/src/core/ClaudeConfigManager.ts +125 -0
  66. package/src/i18n/LanguageManager.ts +169 -0
  67. package/src/i18n/messages.ts +233 -0
  68. package/src/index.ts +4 -5
  69. package/src/providers/ProviderManager.ts +393 -0
  70. package/src/types/index.ts +80 -39
  71. package/src/utils/env-config.ts +53 -0
  72. package/src/utils/version.ts +11 -184
  73. package/dist/config/ConfigManager.d.ts +0 -67
  74. package/dist/config/ConfigManager.d.ts.map +0 -1
  75. package/dist/config/ConfigManager.js +0 -226
  76. package/dist/config/ConfigManager.js.map +0 -1
  77. package/dist/config/EnvironmentManager.d.ts +0 -83
  78. package/dist/config/EnvironmentManager.d.ts.map +0 -1
  79. package/dist/config/EnvironmentManager.js +0 -280
  80. package/dist/config/EnvironmentManager.js.map +0 -1
  81. package/dist/config/constants.d.ts +0 -40
  82. package/dist/config/constants.d.ts.map +0 -1
  83. package/dist/config/constants.js.map +0 -1
  84. package/dist/shell/ShellManager.d.ts +0 -81
  85. package/dist/shell/ShellManager.d.ts.map +0 -1
  86. package/dist/shell/ShellManager.js +0 -490
  87. package/dist/shell/ShellManager.js.map +0 -1
  88. package/src/config/ConfigManager.ts +0 -227
  89. package/src/config/EnvironmentManager.ts +0 -327
  90. package/src/config/constants.ts +0 -64
  91. package/src/shell/ShellManager.ts +0 -526
package/dist/cli.js CHANGED
@@ -7,108 +7,374 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const commander_1 = require("commander");
8
8
  const chalk_1 = __importDefault(require("chalk"));
9
9
  const inquirer_1 = __importDefault(require("inquirer"));
10
- const EnvironmentManager_1 = require("./config/EnvironmentManager");
10
+ const ProviderManager_1 = require("./providers/ProviderManager");
11
+ const LanguageManager_1 = require("./i18n/LanguageManager");
12
+ const lang_1 = require("./commands/lang");
11
13
  const version_1 = require("./utils/version");
12
14
  const program = new commander_1.Command();
13
- const envManager = new EnvironmentManager_1.EnvironmentManager();
14
- /**
15
- * 统一的 use 环境交互逻辑
16
- */
17
- async function performUseEnvironment(name, options) {
18
- const result = await envManager.useEnvironment(name, {
19
- autoWriteShell: options?.autoWrite,
20
- autoSource: options?.autoSource
15
+ const providerManager = new ProviderManager_1.ProviderManager();
16
+ const languageManager = new LanguageManager_1.LanguageManager();
17
+ // 询问是否继续操作
18
+ async function askToContinue() {
19
+ const messages = await languageManager.getMessages();
20
+ const answer = await inquirer_1.default.prompt([
21
+ {
22
+ type: 'confirm',
23
+ name: 'continue',
24
+ message: messages.forms.continueOperation,
25
+ default: true
26
+ }
27
+ ]);
28
+ return answer.continue;
29
+ }
30
+ // 交互式配置菜单
31
+ async function showInteractiveMenu() {
32
+ // 处理首次运行语言设置
33
+ await languageManager.handleFirstRun();
34
+ // 获取当前语言的消息
35
+ const messages = await languageManager.getMessages();
36
+ // 设置 Ctrl+C 优雅退出处理
37
+ process.removeAllListeners('SIGINT');
38
+ process.on('SIGINT', () => {
39
+ console.log(chalk_1.default.yellow(messages.interruptMessage));
40
+ process.exit(0);
21
41
  });
22
- if (!options?.skipSuccessMessage) {
23
- console.log(chalk_1.default.green(`✓ Switched to environment "${name}"`));
24
- console.log(` Base URL: ${result.env.baseUrl}`);
25
- }
26
- if (result.shellWriteResult?.success) {
27
- console.log(chalk_1.default.green(`✓ Environment variables written to ${result.shellWriteResult.filePath}`));
28
- if (options?.autoSource) {
29
- if (result.sourceResult?.success) {
30
- console.log(chalk_1.default.green('✓ Shell configuration sourced automatically'));
31
- console.log(chalk_1.default.yellow('⚠️ Note: Auto-sourcing may not work in all terminal environments'));
32
- }
33
- else {
34
- console.log(chalk_1.default.red(`✗ Failed to source shell config: ${result.sourceResult?.error}`));
35
- console.log(chalk_1.default.cyan('Please run manually: source ~/.bashrc (or ~/.zshrc)'));
42
+ try {
43
+ let shouldContinue = true;
44
+ while (shouldContinue) {
45
+ await providerManager.init();
46
+ const providers = await providerManager.listProviders();
47
+ if (providers.length === 0) {
48
+ console.log(chalk_1.default.yellow(messages.noProvidersFound));
49
+ const answers = await inquirer_1.default.prompt([
50
+ {
51
+ type: 'input',
52
+ name: 'id',
53
+ message: messages.forms.providerId,
54
+ default: 'anthropic'
55
+ },
56
+ {
57
+ type: 'input',
58
+ name: 'name',
59
+ message: messages.forms.providerName,
60
+ default: 'Anthropic Official'
61
+ },
62
+ {
63
+ type: 'input',
64
+ name: 'description',
65
+ message: messages.forms.description,
66
+ default: 'Official Anthropic API'
67
+ },
68
+ {
69
+ type: 'input',
70
+ name: 'baseUrl',
71
+ message: messages.forms.baseUrl,
72
+ default: 'https://api.anthropic.com'
73
+ },
74
+ {
75
+ type: 'password',
76
+ name: 'apiKey',
77
+ message: messages.forms.apiKey,
78
+ mask: '*'
79
+ }
80
+ ]);
81
+ const result = await providerManager.addProvider({
82
+ id: answers.id,
83
+ name: answers.name,
84
+ description: answers.description,
85
+ baseUrl: answers.baseUrl,
86
+ apiKey: answers.apiKey
87
+ });
88
+ if (result.success) {
89
+ console.log(chalk_1.default.green(`✓ ${result.message}`));
90
+ // 自动设为当前供应商
91
+ const useResult = await providerManager.useProvider(answers.id);
92
+ if (useResult.success) {
93
+ console.log(chalk_1.default.green(`✓ ${useResult.message}`));
94
+ }
95
+ }
96
+ else {
97
+ console.error(chalk_1.default.red(`✗ ${result.message}`));
98
+ }
99
+ console.log();
100
+ shouldContinue = await askToContinue();
101
+ continue;
36
102
  }
37
- }
38
- else {
39
- // 询问用户是否要自动 source
40
- const sourceAnswer = await inquirer_1.default.prompt([
103
+ const choices = providers.map(provider => ({
104
+ name: `${provider.name} (${provider.id}) - ${provider.baseUrl}${provider.isCurrent ? ' [current]' : ''}`,
105
+ value: provider.id
106
+ }));
107
+ const action = await inquirer_1.default.prompt([
41
108
  {
42
109
  type: 'list',
43
- name: 'sourceChoice',
44
- message: 'How would you like to apply the environment variables?',
110
+ name: 'action',
111
+ message: messages.mainMenuTitle,
45
112
  choices: [
46
- { name: 'Manual - I will restart terminal or source manually (Recommended)', value: 'manual' },
47
- { name: 'Auto-source - Try to source automatically (May not work in all environments)', value: 'auto' }
48
- ],
49
- default: 'manual'
113
+ { name: messages.mainMenuOptions.switchProvider, value: 'switch' },
114
+ { name: messages.mainMenuOptions.addProvider, value: 'add' },
115
+ { name: messages.mainMenuOptions.updateProvider, value: 'update' },
116
+ { name: messages.mainMenuOptions.removeProvider, value: 'remove' },
117
+ { name: messages.mainMenuOptions.showStatus, value: 'status' },
118
+ { name: messages.mainMenuOptions.exit, value: 'exit' }
119
+ ]
50
120
  }
51
121
  ]);
52
- if (sourceAnswer.sourceChoice === 'auto') {
53
- console.log(chalk_1.default.yellow('⚠️ Attempting auto-source - this may not work in all terminal environments'));
54
- const sourceResult = await envManager.getShellManager().autoSourceShell();
55
- if (sourceResult.success) {
56
- console.log(chalk_1.default.green('✓ Shell configuration sourced successfully'));
122
+ if (action.action === 'exit') {
123
+ console.log(chalk_1.default.cyan(messages.exitMessage));
124
+ break;
125
+ }
126
+ switch (action.action) {
127
+ case 'switch': {
128
+ const switchAnswer = await inquirer_1.default.prompt([
129
+ {
130
+ type: 'list',
131
+ name: 'id',
132
+ message: 'Select provider:',
133
+ choices
134
+ }
135
+ ]);
136
+ const switchResult = await providerManager.useProvider(switchAnswer.id);
137
+ if (switchResult.success) {
138
+ console.log(chalk_1.default.green(`✓ ${switchResult.message}`));
139
+ }
140
+ else {
141
+ console.error(chalk_1.default.red(`✗ ${switchResult.message}`));
142
+ }
143
+ console.log();
144
+ shouldContinue = await askToContinue();
145
+ break;
57
146
  }
58
- else {
59
- console.log(chalk_1.default.red(`✗ Auto-source failed: ${sourceResult.error}`));
60
- console.log(chalk_1.default.cyan('Please run manually: source ~/.bashrc (or ~/.zshrc)'));
147
+ case 'add': {
148
+ const addAnswers = await inquirer_1.default.prompt([
149
+ { type: 'input', name: 'id', message: 'Provider ID:' },
150
+ { type: 'input', name: 'name', message: 'Provider name:' },
151
+ { type: 'input', name: 'description', message: 'Description:' },
152
+ { type: 'input', name: 'baseUrl', message: 'Base URL:' },
153
+ { type: 'password', name: 'apiKey', message: 'API Key:', mask: '*' }
154
+ ]);
155
+ const addResult = await providerManager.addProvider(addAnswers);
156
+ if (addResult.success) {
157
+ console.log(chalk_1.default.green(`✓ ${addResult.message}`));
158
+ }
159
+ else {
160
+ console.error(chalk_1.default.red(`✗ ${addResult.message}`));
161
+ }
162
+ console.log();
163
+ shouldContinue = await askToContinue();
164
+ break;
165
+ }
166
+ case 'update': {
167
+ const updateIdAnswer = await inquirer_1.default.prompt([
168
+ {
169
+ type: 'list',
170
+ name: 'id',
171
+ message: 'Select provider to update:',
172
+ choices
173
+ }
174
+ ]);
175
+ const currentProvider = providers.find(p => p.id === updateIdAnswer.id);
176
+ if (currentProvider) {
177
+ const updateAnswers = await inquirer_1.default.prompt([
178
+ { type: 'input', name: 'name', message: 'Provider name:', default: currentProvider.name },
179
+ { type: 'input', name: 'description', message: 'Description:', default: currentProvider.description },
180
+ { type: 'input', name: 'baseUrl', message: 'Base URL:', default: currentProvider.baseUrl },
181
+ { type: 'password', name: 'apiKey', message: 'API Key (leave empty to keep current):', mask: '*' }
182
+ ]);
183
+ const updateOptions = {
184
+ name: updateAnswers.name,
185
+ description: updateAnswers.description,
186
+ baseUrl: updateAnswers.baseUrl
187
+ };
188
+ if (updateAnswers.apiKey.trim()) {
189
+ updateOptions.apiKey = updateAnswers.apiKey;
190
+ }
191
+ const updateResult = await providerManager.updateProvider(updateIdAnswer.id, updateOptions);
192
+ if (updateResult.success) {
193
+ console.log(chalk_1.default.green(`✓ ${updateResult.message}`));
194
+ }
195
+ else {
196
+ console.error(chalk_1.default.red(`✗ ${updateResult.message}`));
197
+ }
198
+ }
199
+ console.log();
200
+ shouldContinue = await askToContinue();
201
+ break;
202
+ }
203
+ case 'remove': {
204
+ const removeAnswer = await inquirer_1.default.prompt([
205
+ {
206
+ type: 'list',
207
+ name: 'id',
208
+ message: 'Select provider to remove:',
209
+ choices
210
+ }
211
+ ]);
212
+ const confirmRemove = await inquirer_1.default.prompt([
213
+ {
214
+ type: 'confirm',
215
+ name: 'confirm',
216
+ message: `Are you sure you want to remove this provider?`,
217
+ default: false
218
+ }
219
+ ]);
220
+ if (confirmRemove.confirm) {
221
+ const removeResult = await providerManager.removeProvider(removeAnswer.id);
222
+ if (removeResult.success) {
223
+ console.log(chalk_1.default.green(`✓ ${removeResult.message}`));
224
+ }
225
+ else {
226
+ console.error(chalk_1.default.red(`✗ ${removeResult.message}`));
227
+ }
228
+ }
229
+ else {
230
+ console.log(chalk_1.default.yellow('Operation cancelled'));
231
+ }
232
+ console.log();
233
+ shouldContinue = await askToContinue();
234
+ break;
235
+ }
236
+ case 'status': {
237
+ const stats = await providerManager.getStats();
238
+ console.log();
239
+ console.log(chalk_1.default.blue('CCM Status:'));
240
+ console.log(`Total providers: ${stats.totalProviders}`);
241
+ console.log(`Current provider: ${stats.currentProvider || 'None'}`);
242
+ console.log(`Claude config: ${stats.claudeConfigPath}`);
243
+ console.log(`CCM config: ${stats.ccmConfigPath}`);
244
+ if (providers.length > 0) {
245
+ console.log();
246
+ console.log(chalk_1.default.blue('Recent providers:'));
247
+ providers
248
+ .filter(p => p.lastUsed)
249
+ .slice(0, 3)
250
+ .forEach(provider => {
251
+ const marker = provider.isCurrent ? chalk_1.default.green('* ') : ' ';
252
+ const name = provider.isCurrent ? chalk_1.default.green(provider.name) : provider.name;
253
+ const lastUsed = new Date(provider.lastUsed).toLocaleDateString();
254
+ console.log(`${marker}${name} (${lastUsed}, ${provider.usageCount} uses)`);
255
+ });
256
+ }
257
+ console.log();
258
+ console.log();
259
+ shouldContinue = await askToContinue();
260
+ break;
61
261
  }
62
262
  }
63
- else {
64
- console.log(chalk_1.default.cyan('To apply changes, restart your terminal or run:'));
65
- console.log(chalk_1.default.cyan('source ~/.bashrc (or ~/.zshrc)'));
66
- }
67
- }
263
+ } // while 循环结束
68
264
  }
69
- else if (options?.autoWrite !== false) {
70
- console.log(chalk_1.default.yellow('Environment variables have been set, but may not persist.'));
71
- console.log(chalk_1.default.cyan('Consider running: source <(ccman env)'));
265
+ catch (error) {
266
+ console.error(chalk_1.default.red(`✗ Error: ${error}`));
267
+ process.exit(1);
72
268
  }
73
- else {
74
- console.log(chalk_1.default.yellow('To set environment variables manually, run:'));
75
- console.log(chalk_1.default.cyan('source <(ccman env)'));
269
+ finally {
270
+ // 恢复原始的 SIGINT 处理器
271
+ process.removeAllListeners('SIGINT');
76
272
  }
77
273
  }
78
274
  program
79
275
  .name('ccman')
80
- .description('Claude Code Manager - Manage Claude Code API configurations')
81
- .version((0, version_1.getCurrentVersion)());
82
- // 列出所有环境
83
- program
84
- .command('list')
85
- .alias('ls')
86
- .description('List all environment groups')
87
- .action(() => {
88
- const environments = envManager.listEnvironments();
89
- if (environments.length === 0) {
90
- console.log(chalk_1.default.yellow('No environment groups found. Use "ccman add" to create one.'));
91
- return;
276
+ .description('Claude Code Manager - Manage Claude API configurations')
277
+ .version((0, version_1.getPackageVersion)())
278
+ .hook('preAction', () => {
279
+ // 开发模式提示
280
+ if (process.env.CCM_CONFIG_DIR || process.env.CLAUDE_CONFIG_PATH) {
281
+ console.log(chalk_1.default.yellow('🔧 Development Mode:'));
282
+ if (process.env.CCM_CONFIG_DIR) {
283
+ console.log(chalk_1.default.yellow(` CCM Config: ${process.env.CCM_CONFIG_DIR}`));
284
+ }
285
+ if (process.env.CLAUDE_CONFIG_PATH) {
286
+ console.log(chalk_1.default.yellow(` Claude Config: ${process.env.CLAUDE_CONFIG_PATH}`));
287
+ }
288
+ console.log();
92
289
  }
93
- console.log();
94
- environments.forEach(env => {
95
- const marker = env.isCurrent ? chalk_1.default.green('* ') : ' ';
96
- const name = env.isCurrent ? chalk_1.default.green(env.name) : env.name;
97
- console.log(`${marker}${name.padEnd(15)} ${env.baseUrl}`);
98
- if (env.lastUsed) {
99
- const lastUsed = new Date(env.lastUsed).toLocaleDateString();
100
- console.log(`${' '.repeat(17)} Last used: ${lastUsed}`);
290
+ })
291
+ .action(async () => {
292
+ // 默认无参数时进入交互菜单
293
+ await showInteractiveMenu();
294
+ });
295
+ // 智能列表命令
296
+ program
297
+ .command('ls')
298
+ .alias('list')
299
+ .description('List provider configurations')
300
+ .option('--current', 'Show only current provider details')
301
+ .option('--brief', 'Show brief summary')
302
+ .action(async (options) => {
303
+ try {
304
+ await providerManager.init();
305
+ if (options?.current) {
306
+ // 显示当前供应商详情
307
+ const currentProvider = await providerManager.getCurrentProvider();
308
+ if (!currentProvider) {
309
+ console.log(chalk_1.default.yellow('No provider is currently active.'));
310
+ console.log('Use "ccman use <id>" to activate a provider.');
311
+ return;
312
+ }
313
+ console.log();
314
+ console.log(chalk_1.default.green(`Current provider: ${currentProvider.config.name} (${currentProvider.id})`));
315
+ console.log(`Description: ${currentProvider.config.description}`);
316
+ console.log(`Base URL: ${currentProvider.config.config.env.ANTHROPIC_BASE_URL}`);
317
+ console.log(`API Key: ${'*'.repeat(Math.min(currentProvider.config.config.env.ANTHROPIC_AUTH_TOKEN.length, 20))}`);
318
+ console.log(`Usage count: ${currentProvider.config.metadata.usageCount} times`);
319
+ console.log(`Last updated: ${new Date(currentProvider.config.metadata.updatedAt).toLocaleString()}`);
320
+ console.log();
321
+ return;
101
322
  }
102
- });
103
- console.log();
323
+ const providers = await providerManager.listProviders();
324
+ const stats = await providerManager.getStats();
325
+ // 显示状态和配置信息,不管是否有providers
326
+ console.log();
327
+ console.log(chalk_1.default.blue('CCM Status:'));
328
+ console.log(`Total providers: ${stats.totalProviders}`);
329
+ console.log(`Current provider: ${stats.currentProvider || 'None'}`);
330
+ console.log(`Environment: ${stats.environment}`);
331
+ console.log();
332
+ console.log(chalk_1.default.blue('Configuration Files:'));
333
+ console.log(`Claude config: ${chalk_1.default.cyan(stats.claudeConfigPath)}`);
334
+ console.log(`CCM config: ${chalk_1.default.cyan(stats.ccmConfigFile)}`);
335
+ console.log(`Providers dir: ${chalk_1.default.cyan(stats.providersDir)}`);
336
+ console.log();
337
+ if (providers.length === 0) {
338
+ console.log(chalk_1.default.yellow('No provider configurations found. Use "ccman add" to create one.'));
339
+ return;
340
+ }
341
+ if (options?.brief) {
342
+ // 简洁模式
343
+ providers.forEach(provider => {
344
+ const marker = provider.isCurrent ? chalk_1.default.green('* ') : ' ';
345
+ const name = provider.isCurrent ? chalk_1.default.green(provider.name) : provider.name;
346
+ console.log(`${marker}${name} (${provider.id})`);
347
+ });
348
+ console.log();
349
+ return;
350
+ }
351
+ // 详细显示providers信息
352
+ console.log(chalk_1.default.blue('Providers:'));
353
+ providers.forEach(provider => {
354
+ const marker = provider.isCurrent ? chalk_1.default.green('* ') : ' ';
355
+ const name = provider.isCurrent ? chalk_1.default.green(provider.name) : provider.name;
356
+ console.log(`${marker}${name.padEnd(15)} ${provider.baseUrl}`);
357
+ console.log(`${' '.repeat(17)} ${provider.description}`);
358
+ if (provider.lastUsed) {
359
+ const lastUsed = new Date(provider.lastUsed).toLocaleDateString();
360
+ console.log(`${' '.repeat(17)} Last used: ${lastUsed}, Usage: ${provider.usageCount} times`);
361
+ }
362
+ console.log();
363
+ });
364
+ }
365
+ catch (error) {
366
+ console.error(chalk_1.default.red(`✗ Error: ${error}`));
367
+ process.exit(1);
368
+ }
104
369
  });
105
- // 添加环境
370
+ // 添加供应商
106
371
  program
107
- .command('add <name> <baseUrl> [apiKey]')
108
- .description('Add a new environment group')
109
- .option('--no-auto-write', 'Do not automatically write to shell config')
110
- .action(async (name, baseUrl, apiKey, options) => {
372
+ .command('add <id> <name> <baseUrl> [apiKey]')
373
+ .description('Add a new provider configuration')
374
+ .option('-d, --description <desc>', 'Provider description')
375
+ .action(async (id, name, baseUrl, apiKey, options) => {
111
376
  try {
377
+ await providerManager.init();
112
378
  if (!apiKey) {
113
379
  const answer = await inquirer_1.default.prompt([
114
380
  {
@@ -121,62 +387,99 @@ program
121
387
  apiKey = answer.apiKey;
122
388
  }
123
389
  const addOptions = {
390
+ id,
124
391
  name,
392
+ description: options?.description,
125
393
  baseUrl,
126
- apiKey: apiKey,
127
- autoWriteShell: options?.autoWrite
394
+ apiKey: apiKey
128
395
  };
129
- const env = await envManager.addEnvironment(addOptions);
130
- console.log(chalk_1.default.green(`✓ Added environment group "${name}"`));
131
- console.log(` Base URL: ${env.baseUrl}`);
132
- console.log(` Created: ${new Date(env.createdAt).toLocaleString()}`);
133
- // 询问是否设为当前环境
134
- const currentEnv = envManager.getCurrentEnvironment();
135
- if (!currentEnv || currentEnv.name !== name) {
136
- const useAnswer = await inquirer_1.default.prompt([
137
- {
138
- type: 'confirm',
139
- name: 'useCurrent',
140
- message: `Set "${name}" as current environment?`,
141
- default: true
396
+ const result = await providerManager.addProvider(addOptions);
397
+ if (result.success) {
398
+ console.log(chalk_1.default.green(`✓ ${result.message}`));
399
+ // 询问是否设为当前供应商
400
+ const currentProvider = await providerManager.getCurrentProvider();
401
+ if (!currentProvider || currentProvider.id !== id) {
402
+ const useAnswer = await inquirer_1.default.prompt([
403
+ {
404
+ type: 'confirm',
405
+ name: 'useCurrent',
406
+ message: `Set "${name}" as current provider?`,
407
+ default: true
408
+ }
409
+ ]);
410
+ if (useAnswer.useCurrent) {
411
+ const useResult = await providerManager.useProvider(id);
412
+ if (useResult.success) {
413
+ console.log(chalk_1.default.green(`✓ ${useResult.message}`));
414
+ }
415
+ else {
416
+ console.error(chalk_1.default.red(`✗ ${useResult.message}`));
417
+ }
142
418
  }
143
- ]);
144
- if (useAnswer.useCurrent) {
145
- await performUseEnvironment(name, {
146
- autoWrite: options?.autoWrite,
147
- skipSuccessMessage: true // 因为前面已经显示了添加成功的信息
148
- });
149
419
  }
150
420
  }
421
+ else {
422
+ console.error(chalk_1.default.red(`✗ ${result.message}`));
423
+ process.exit(1);
424
+ }
151
425
  }
152
426
  catch (error) {
153
427
  console.error(chalk_1.default.red(`✗ Error: ${error}`));
154
428
  process.exit(1);
155
429
  }
156
430
  });
157
- // 删除环境
431
+ // 使用供应商
158
432
  program
159
- .command('remove <name>')
160
- .alias('rm')
161
- .description('Remove an environment group')
162
- .action(async (name) => {
433
+ .command('use <id>')
434
+ .description('Switch to a provider configuration')
435
+ .action(async (id) => {
163
436
  try {
164
- const env = envManager.getEnvironment(name);
165
- if (!env) {
166
- console.error(chalk_1.default.red(`✗ Environment "${name}" not found`));
437
+ await providerManager.init();
438
+ const result = await providerManager.useProvider(id);
439
+ if (result.success) {
440
+ console.log(chalk_1.default.green(`✓ ${result.message}`));
441
+ console.log(chalk_1.default.cyan('Claude Code configuration has been updated successfully!'));
442
+ }
443
+ else {
444
+ console.error(chalk_1.default.red(`✗ ${result.message}`));
445
+ process.exit(1);
446
+ }
447
+ }
448
+ catch (error) {
449
+ console.error(chalk_1.default.red(`✗ Error: ${error}`));
450
+ process.exit(1);
451
+ }
452
+ });
453
+ // 删除供应商
454
+ program
455
+ .command('rm <id>')
456
+ .alias('remove')
457
+ .description('Remove a provider configuration')
458
+ .action(async (id) => {
459
+ try {
460
+ await providerManager.init();
461
+ const providers = await providerManager.listProviders();
462
+ const provider = providers.find(p => p.id === id);
463
+ if (!provider) {
464
+ console.error(chalk_1.default.red(`✗ Provider '${id}' not found`));
167
465
  process.exit(1);
168
466
  }
169
467
  const answer = await inquirer_1.default.prompt([
170
468
  {
171
469
  type: 'confirm',
172
470
  name: 'confirm',
173
- message: `Are you sure you want to remove environment "${name}"?`,
471
+ message: `Are you sure you want to remove provider "${provider.name}" (${id})?`,
174
472
  default: false
175
473
  }
176
474
  ]);
177
475
  if (answer.confirm) {
178
- await envManager.removeEnvironment(name);
179
- console.log(chalk_1.default.green(`✓ Removed environment "${name}"`));
476
+ const result = await providerManager.removeProvider(id);
477
+ if (result.success) {
478
+ console.log(chalk_1.default.green(`✓ ${result.message}`));
479
+ }
480
+ else {
481
+ console.error(chalk_1.default.red(`✗ ${result.message}`));
482
+ }
180
483
  }
181
484
  else {
182
485
  console.log(chalk_1.default.yellow('Operation cancelled'));
@@ -187,115 +490,18 @@ program
187
490
  process.exit(1);
188
491
  }
189
492
  });
190
- // 使用环境
191
- program
192
- .command('use <name>')
193
- .description('Switch to an environment group')
194
- .option('--no-auto-write', 'Do not automatically write to shell config')
195
- .option('--auto-source', 'Automatically source shell config after writing (risky)')
196
- .action(async (name, options) => {
197
- try {
198
- await performUseEnvironment(name, {
199
- autoWrite: options?.autoWrite,
200
- autoSource: options?.autoSource
201
- });
202
- }
203
- catch (error) {
204
- console.error(chalk_1.default.red(`✗ Error: ${error}`));
205
- process.exit(1);
206
- }
207
- });
208
- // 显示当前环境
209
- program
210
- .command('current')
211
- .description('Show current environment group')
212
- .action(() => {
213
- const currentEnv = envManager.getCurrentEnvironment();
214
- if (!currentEnv) {
215
- console.log(chalk_1.default.yellow('No environment is currently active.'));
216
- console.log('Use "ccman use <name>" to activate an environment.');
217
- return;
218
- }
219
- console.log();
220
- console.log(chalk_1.default.green(`Current environment: ${currentEnv.name}`));
221
- console.log(`Base URL: ${currentEnv.baseUrl}`);
222
- console.log(`API Key: ${'*'.repeat(Math.min(currentEnv.apiKey.length, 20))}`);
223
- console.log(`Created: ${new Date(currentEnv.createdAt).toLocaleString()}`);
224
- if (currentEnv.lastUsed) {
225
- console.log(`Last used: ${new Date(currentEnv.lastUsed).toLocaleString()}`);
226
- }
227
- console.log();
228
- });
229
- // 生成环境变量脚本
230
- program
231
- .command('env')
232
- .description('Generate shell script to set environment variables')
233
- .action(() => {
234
- try {
235
- const script = envManager.generateEnvScript();
236
- console.log(script);
237
- }
238
- catch (error) {
239
- console.error(chalk_1.default.red(`✗ Error: ${error}`));
240
- process.exit(1);
241
- }
242
- });
243
- // 测试环境
244
- program
245
- .command('test [name]')
246
- .description('Test environment configuration (defaults to current)')
247
- .action(async (name) => {
248
- const result = await envManager.testEnvironment(name);
249
- if (result.success) {
250
- console.log(chalk_1.default.green(`✓ ${result.message}`));
251
- }
252
- else {
253
- console.error(chalk_1.default.red(`✗ ${result.message}`));
254
- if (result.error) {
255
- console.error(chalk_1.default.gray(`Details: ${result.error}`));
256
- }
257
- process.exit(1);
258
- }
259
- });
260
- // 显示统计信息
261
- program
262
- .command('status')
263
- .description('Show CCM status and statistics')
264
- .action(() => {
265
- const stats = envManager.getStats();
266
- const environments = envManager.listEnvironments();
267
- console.log();
268
- console.log(chalk_1.default.blue('CCM Status:'));
269
- console.log(`Total environments: ${stats.totalEnvironments}`);
270
- console.log(`Current environment: ${stats.currentEnvironment || 'None'}`);
271
- console.log(`Shell integration: ${stats.hasShellIntegration ? 'Enabled' : 'Disabled'}`);
272
- if (environments.length > 0) {
273
- console.log();
274
- console.log(chalk_1.default.blue('Recent environments:'));
275
- const sortedEnvs = environments
276
- .filter(env => env.lastUsed)
277
- .sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime())
278
- .slice(0, 3);
279
- sortedEnvs.forEach(env => {
280
- const lastUsed = new Date(env.lastUsed).toLocaleDateString();
281
- console.log(` ${env.name} (${lastUsed})`);
282
- });
283
- }
284
- console.log();
285
- });
286
493
  // 清除所有配置
287
494
  program
288
495
  .command('clear')
289
- .alias('clearall')
290
- .description('Clear all environments and shell integration (DESTRUCTIVE)')
496
+ .alias('reset')
497
+ .description('Clear all provider configurations (DESTRUCTIVE)')
291
498
  .action(async () => {
292
499
  try {
293
- // 确认操作
294
500
  const confirmAnswer = await inquirer_1.default.prompt([
295
501
  {
296
502
  type: 'confirm',
297
503
  name: 'confirmed',
298
- message: chalk_1.default.red('⚠️ This will remove ALL environments and shell integration. Are you sure?'),
504
+ message: chalk_1.default.red('⚠️ This will remove ALL provider configurations. Are you sure?'),
299
505
  default: false
300
506
  }
301
507
  ]);
@@ -303,174 +509,24 @@ program
303
509
  console.log(chalk_1.default.yellow('Operation cancelled.'));
304
510
  return;
305
511
  }
306
- // 执行清除
307
- console.log(chalk_1.default.yellow('Clearing CCM configuration...'));
308
- const result = await envManager.clearAll();
309
- // 显示结果
310
- console.log();
512
+ await providerManager.init();
513
+ const result = await providerManager.clearAll();
311
514
  if (result.success) {
312
515
  console.log(chalk_1.default.green(`✓ ${result.message}`));
516
+ console.log(chalk_1.default.cyan('CCM has been reset to initial state.'));
517
+ console.log(chalk_1.default.cyan('You can start fresh with: ccman'));
313
518
  }
314
519
  else {
315
- console.log(chalk_1.default.red(`✗ ${result.message}`));
520
+ console.error(chalk_1.default.red(`✗ ${result.message}`));
316
521
  }
317
- // 显示详细信息
318
- if (result.details.length > 0) {
319
- console.log();
320
- result.details.forEach(detail => {
321
- if (detail.startsWith('✓')) {
322
- console.log(chalk_1.default.green(detail));
323
- }
324
- else if (detail.startsWith('⚠')) {
325
- console.log(chalk_1.default.yellow(detail));
326
- }
327
- else if (detail.startsWith('✗')) {
328
- console.log(chalk_1.default.red(detail));
329
- }
330
- else {
331
- console.log(detail);
332
- }
333
- });
334
- }
335
- console.log();
336
- console.log(chalk_1.default.cyan('CCM has been reset to initial state.'));
337
- console.log(chalk_1.default.cyan('You can start fresh with: ccman config'));
338
522
  }
339
523
  catch (error) {
340
524
  console.error(chalk_1.default.red(`✗ Error: ${error}`));
341
525
  process.exit(1);
342
526
  }
343
527
  });
344
- // 交互式配置
345
- program
346
- .command('config')
347
- .description('Interactive configuration')
348
- .action(async () => {
349
- const environments = envManager.listEnvironments();
350
- if (environments.length === 0) {
351
- console.log(chalk_1.default.yellow('No environments found. Let\'s create your first one.'));
352
- const answers = await inquirer_1.default.prompt([
353
- { type: 'input', name: 'name', message: 'Environment name:', default: 'default' },
354
- { type: 'input', name: 'baseUrl', message: 'Base URL:', default: 'https://api.anthropic.com' },
355
- { type: 'password', name: 'apiKey', message: 'API Key:', mask: '*' },
356
- { type: 'confirm', name: 'autoWrite', message: 'Automatically write to shell config?', default: true }
357
- ]);
358
- try {
359
- await envManager.addEnvironment({
360
- name: answers.name,
361
- baseUrl: answers.baseUrl,
362
- apiKey: answers.apiKey,
363
- autoWriteShell: answers.autoWrite
364
- });
365
- console.log(chalk_1.default.green(`✓ Created environment "${answers.name}"`));
366
- }
367
- catch (error) {
368
- console.error(chalk_1.default.red(`✗ Error: ${error}`));
369
- }
370
- return;
371
- }
372
- const choices = environments.map(env => ({
373
- name: `${env.name} (${env.baseUrl})${env.isCurrent ? ' [current]' : ''}`,
374
- value: env.name
375
- }));
376
- const action = await inquirer_1.default.prompt([
377
- {
378
- type: 'list',
379
- name: 'action',
380
- message: 'What would you like to do?',
381
- choices: [
382
- { name: 'Switch environment', value: 'switch' },
383
- { name: 'Add new environment', value: 'add' },
384
- { name: 'Edit environment', value: 'edit' },
385
- { name: 'Remove environment', value: 'remove' },
386
- { name: 'Show current status', value: 'status' }
387
- ]
388
- }
389
- ]);
390
- switch (action.action) {
391
- case 'switch':
392
- const switchAnswer = await inquirer_1.default.prompt([
393
- {
394
- type: 'list',
395
- name: 'name',
396
- message: 'Select environment:',
397
- choices
398
- }
399
- ]);
400
- try {
401
- await performUseEnvironment(switchAnswer.name);
402
- }
403
- catch (error) {
404
- console.error(chalk_1.default.red(`✗ Error: ${error}`));
405
- }
406
- break;
407
- case 'add':
408
- const addAnswers = await inquirer_1.default.prompt([
409
- { type: 'input', name: 'name', message: 'Environment name:' },
410
- { type: 'input', name: 'baseUrl', message: 'Base URL:' },
411
- { type: 'password', name: 'apiKey', message: 'API Key:', mask: '*' }
412
- ]);
413
- try {
414
- await envManager.addEnvironment(addAnswers);
415
- console.log(chalk_1.default.green(`✓ Added environment "${addAnswers.name}"`));
416
- }
417
- catch (error) {
418
- console.error(chalk_1.default.red(`✗ Error: ${error}`));
419
- }
420
- break;
421
- case 'edit':
422
- const editEnvAnswer = await inquirer_1.default.prompt([
423
- {
424
- type: 'list',
425
- name: 'name',
426
- message: 'Select environment to edit:',
427
- choices
428
- }
429
- ]);
430
- const currentConfig = envManager.getEnvironment(editEnvAnswer.name);
431
- if (currentConfig) {
432
- const editAnswers = await inquirer_1.default.prompt([
433
- { type: 'input', name: 'baseUrl', message: 'Base URL:', default: currentConfig.baseUrl },
434
- { type: 'password', name: 'apiKey', message: 'API Key:', mask: '*', default: currentConfig.apiKey }
435
- ]);
436
- try {
437
- await envManager.updateEnvironment(editEnvAnswer.name, {
438
- baseUrl: editAnswers.baseUrl,
439
- apiKey: editAnswers.apiKey
440
- });
441
- console.log(chalk_1.default.green(`✓ Updated environment "${editEnvAnswer.name}"`));
442
- }
443
- catch (error) {
444
- console.error(chalk_1.default.red(`✗ Error: ${error}`));
445
- }
446
- }
447
- break;
448
- case 'status':
449
- {
450
- const stats = envManager.getStats();
451
- const environments = envManager.listEnvironments();
452
- console.log();
453
- console.log(chalk_1.default.blue('CCM Status:'));
454
- console.log(`Total environments: ${stats.totalEnvironments}`);
455
- console.log(`Current environment: ${stats.currentEnvironment || 'None'}`);
456
- console.log(`Shell integration: ${stats.hasShellIntegration ? 'Enabled' : 'Disabled'}`);
457
- if (environments.length > 0) {
458
- console.log();
459
- console.log(chalk_1.default.blue('Recent environments:'));
460
- environments
461
- .sort((a, b) => new Date(b.lastUsed || b.createdAt).getTime() - new Date(a.lastUsed || a.createdAt).getTime())
462
- .slice(0, 3)
463
- .forEach(env => {
464
- const marker = env.isCurrent ? chalk_1.default.green('* ') : ' ';
465
- const name = env.isCurrent ? chalk_1.default.green(env.name) : env.name;
466
- console.log(`${marker}${name.padEnd(15)} ${env.baseUrl}`);
467
- });
468
- }
469
- console.log();
470
- }
471
- break;
472
- }
473
- });
528
+ // 添加语言管理命令
529
+ program.addCommand((0, lang_1.createLanguageCommands)());
474
530
  // 解析命令行参数
475
- program.parse();
531
+ program.parse(process.argv);
476
532
  //# sourceMappingURL=cli.js.map