ccman 0.1.2 → 2.0.0

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 (78) hide show
  1. package/.github/workflows/release.yml +5 -5
  2. package/CLAUDE.md +246 -185
  3. package/README.md +282 -249
  4. package/README_zh.md +283 -250
  5. package/dev-test.sh +40 -0
  6. package/dist/cli.js +421 -369
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands/lang.d.ts +3 -0
  9. package/dist/commands/lang.d.ts.map +1 -0
  10. package/dist/commands/lang.js +99 -0
  11. package/dist/commands/lang.js.map +1 -0
  12. package/dist/core/CCMConfigManager.d.ts +52 -0
  13. package/dist/core/CCMConfigManager.d.ts.map +1 -0
  14. package/dist/core/CCMConfigManager.js +203 -0
  15. package/dist/core/CCMConfigManager.js.map +1 -0
  16. package/dist/core/ClaudeConfigManager.d.ts +35 -0
  17. package/dist/core/ClaudeConfigManager.d.ts.map +1 -0
  18. package/dist/core/ClaudeConfigManager.js +151 -0
  19. package/dist/core/ClaudeConfigManager.js.map +1 -0
  20. package/dist/i18n/LanguageManager.d.ts +43 -0
  21. package/dist/i18n/LanguageManager.d.ts.map +1 -0
  22. package/dist/i18n/LanguageManager.js +157 -0
  23. package/dist/i18n/LanguageManager.js.map +1 -0
  24. package/dist/i18n/messages.d.ts +65 -0
  25. package/dist/i18n/messages.d.ts.map +1 -0
  26. package/dist/i18n/messages.js +144 -0
  27. package/dist/i18n/messages.js.map +1 -0
  28. package/dist/index.d.ts +3 -3
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +3 -8
  31. package/dist/index.js.map +1 -1
  32. package/dist/providers/ProviderManager.d.ts +55 -0
  33. package/dist/providers/ProviderManager.d.ts.map +1 -0
  34. package/dist/providers/ProviderManager.js +326 -0
  35. package/dist/providers/ProviderManager.js.map +1 -0
  36. package/dist/types/index.d.ts +78 -38
  37. package/dist/types/index.d.ts.map +1 -1
  38. package/dist/types/index.js +1 -0
  39. package/dist/types/index.js.map +1 -1
  40. package/dist/utils/version.d.ts +2 -64
  41. package/dist/utils/version.d.ts.map +1 -1
  42. package/dist/utils/version.js +12 -158
  43. package/dist/utils/version.js.map +1 -1
  44. package/package.json +2 -2
  45. package/release-temp/README.md +282 -249
  46. package/release-temp/package.json +2 -2
  47. package/scripts/modules/version-bump.sh +2 -2
  48. package/scripts/smart-release-v3.sh +20 -26
  49. package/src/cli.ts +458 -394
  50. package/src/commands/lang.ts +105 -0
  51. package/src/core/CCMConfigManager.ts +185 -0
  52. package/src/core/ClaudeConfigManager.ts +127 -0
  53. package/src/i18n/LanguageManager.ts +169 -0
  54. package/src/i18n/messages.ts +233 -0
  55. package/src/index.ts +4 -5
  56. package/src/providers/ProviderManager.ts +380 -0
  57. package/src/types/index.ts +80 -39
  58. package/src/utils/version.ts +11 -184
  59. package/dist/config/ConfigManager.d.ts +0 -67
  60. package/dist/config/ConfigManager.d.ts.map +0 -1
  61. package/dist/config/ConfigManager.js +0 -226
  62. package/dist/config/ConfigManager.js.map +0 -1
  63. package/dist/config/EnvironmentManager.d.ts +0 -83
  64. package/dist/config/EnvironmentManager.d.ts.map +0 -1
  65. package/dist/config/EnvironmentManager.js +0 -280
  66. package/dist/config/EnvironmentManager.js.map +0 -1
  67. package/dist/config/constants.d.ts +0 -40
  68. package/dist/config/constants.d.ts.map +0 -1
  69. package/dist/config/constants.js +0 -97
  70. package/dist/config/constants.js.map +0 -1
  71. package/dist/shell/ShellManager.d.ts +0 -81
  72. package/dist/shell/ShellManager.d.ts.map +0 -1
  73. package/dist/shell/ShellManager.js +0 -490
  74. package/dist/shell/ShellManager.js.map +0 -1
  75. package/src/config/ConfigManager.ts +0 -227
  76. package/src/config/EnvironmentManager.ts +0 -327
  77. package/src/config/constants.ts +0 -64
  78. package/src/shell/ShellManager.ts +0 -526
package/dist/cli.js CHANGED
@@ -7,108 +7,370 @@ 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
+ if (providers.length === 0) {
325
+ console.log(chalk_1.default.yellow('No provider configurations found. Use "ccman add" to create one.'));
326
+ return;
327
+ }
328
+ if (options?.brief) {
329
+ // 简洁模式
330
+ console.log();
331
+ providers.forEach(provider => {
332
+ const marker = provider.isCurrent ? chalk_1.default.green('* ') : ' ';
333
+ const name = provider.isCurrent ? chalk_1.default.green(provider.name) : provider.name;
334
+ console.log(`${marker}${name} (${provider.id})`);
335
+ });
336
+ console.log();
337
+ return;
338
+ }
339
+ // 默认详细模式(合并原 list + status 信息)
340
+ const stats = await providerManager.getStats();
341
+ console.log();
342
+ console.log(chalk_1.default.blue('CCM Status:'));
343
+ console.log(`Total providers: ${stats.totalProviders}`);
344
+ console.log(`Current provider: ${stats.currentProvider || 'None'}`);
345
+ console.log(`Claude config: ${stats.claudeConfigPath}`);
346
+ console.log(`CCM config: ${stats.ccmConfigPath}`);
347
+ console.log();
348
+ console.log(chalk_1.default.blue('Providers:'));
349
+ providers.forEach(provider => {
350
+ const marker = provider.isCurrent ? chalk_1.default.green('* ') : ' ';
351
+ const name = provider.isCurrent ? chalk_1.default.green(provider.name) : provider.name;
352
+ console.log(`${marker}${name.padEnd(15)} ${provider.baseUrl}`);
353
+ console.log(`${' '.repeat(17)} ${provider.description}`);
354
+ if (provider.lastUsed) {
355
+ const lastUsed = new Date(provider.lastUsed).toLocaleDateString();
356
+ console.log(`${' '.repeat(17)} Last used: ${lastUsed}, Usage: ${provider.usageCount} times`);
357
+ }
358
+ console.log();
359
+ });
360
+ }
361
+ catch (error) {
362
+ console.error(chalk_1.default.red(`✗ Error: ${error}`));
363
+ process.exit(1);
364
+ }
104
365
  });
105
- // 添加环境
366
+ // 添加供应商
106
367
  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) => {
368
+ .command('add <id> <name> <baseUrl> [apiKey]')
369
+ .description('Add a new provider configuration')
370
+ .option('-d, --description <desc>', 'Provider description')
371
+ .action(async (id, name, baseUrl, apiKey, options) => {
111
372
  try {
373
+ await providerManager.init();
112
374
  if (!apiKey) {
113
375
  const answer = await inquirer_1.default.prompt([
114
376
  {
@@ -121,62 +383,99 @@ program
121
383
  apiKey = answer.apiKey;
122
384
  }
123
385
  const addOptions = {
386
+ id,
124
387
  name,
388
+ description: options?.description,
125
389
  baseUrl,
126
- apiKey: apiKey,
127
- autoWriteShell: options?.autoWrite
390
+ apiKey: apiKey
128
391
  };
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
392
+ const result = await providerManager.addProvider(addOptions);
393
+ if (result.success) {
394
+ console.log(chalk_1.default.green(`✓ ${result.message}`));
395
+ // 询问是否设为当前供应商
396
+ const currentProvider = await providerManager.getCurrentProvider();
397
+ if (!currentProvider || currentProvider.id !== id) {
398
+ const useAnswer = await inquirer_1.default.prompt([
399
+ {
400
+ type: 'confirm',
401
+ name: 'useCurrent',
402
+ message: `Set "${name}" as current provider?`,
403
+ default: true
404
+ }
405
+ ]);
406
+ if (useAnswer.useCurrent) {
407
+ const useResult = await providerManager.useProvider(id);
408
+ if (useResult.success) {
409
+ console.log(chalk_1.default.green(`✓ ${useResult.message}`));
410
+ }
411
+ else {
412
+ console.error(chalk_1.default.red(`✗ ${useResult.message}`));
413
+ }
142
414
  }
143
- ]);
144
- if (useAnswer.useCurrent) {
145
- await performUseEnvironment(name, {
146
- autoWrite: options?.autoWrite,
147
- skipSuccessMessage: true // 因为前面已经显示了添加成功的信息
148
- });
149
415
  }
150
416
  }
417
+ else {
418
+ console.error(chalk_1.default.red(`✗ ${result.message}`));
419
+ process.exit(1);
420
+ }
151
421
  }
152
422
  catch (error) {
153
423
  console.error(chalk_1.default.red(`✗ Error: ${error}`));
154
424
  process.exit(1);
155
425
  }
156
426
  });
157
- // 删除环境
427
+ // 使用供应商
158
428
  program
159
- .command('remove <name>')
160
- .alias('rm')
161
- .description('Remove an environment group')
162
- .action(async (name) => {
429
+ .command('use <id>')
430
+ .description('Switch to a provider configuration')
431
+ .action(async (id) => {
163
432
  try {
164
- const env = envManager.getEnvironment(name);
165
- if (!env) {
166
- console.error(chalk_1.default.red(`✗ Environment "${name}" not found`));
433
+ await providerManager.init();
434
+ const result = await providerManager.useProvider(id);
435
+ if (result.success) {
436
+ console.log(chalk_1.default.green(`✓ ${result.message}`));
437
+ console.log(chalk_1.default.cyan('Claude Code configuration has been updated successfully!'));
438
+ }
439
+ else {
440
+ console.error(chalk_1.default.red(`✗ ${result.message}`));
441
+ process.exit(1);
442
+ }
443
+ }
444
+ catch (error) {
445
+ console.error(chalk_1.default.red(`✗ Error: ${error}`));
446
+ process.exit(1);
447
+ }
448
+ });
449
+ // 删除供应商
450
+ program
451
+ .command('rm <id>')
452
+ .alias('remove')
453
+ .description('Remove a provider configuration')
454
+ .action(async (id) => {
455
+ try {
456
+ await providerManager.init();
457
+ const providers = await providerManager.listProviders();
458
+ const provider = providers.find(p => p.id === id);
459
+ if (!provider) {
460
+ console.error(chalk_1.default.red(`✗ Provider '${id}' not found`));
167
461
  process.exit(1);
168
462
  }
169
463
  const answer = await inquirer_1.default.prompt([
170
464
  {
171
465
  type: 'confirm',
172
466
  name: 'confirm',
173
- message: `Are you sure you want to remove environment "${name}"?`,
467
+ message: `Are you sure you want to remove provider "${provider.name}" (${id})?`,
174
468
  default: false
175
469
  }
176
470
  ]);
177
471
  if (answer.confirm) {
178
- await envManager.removeEnvironment(name);
179
- console.log(chalk_1.default.green(`✓ Removed environment "${name}"`));
472
+ const result = await providerManager.removeProvider(id);
473
+ if (result.success) {
474
+ console.log(chalk_1.default.green(`✓ ${result.message}`));
475
+ }
476
+ else {
477
+ console.error(chalk_1.default.red(`✗ ${result.message}`));
478
+ }
180
479
  }
181
480
  else {
182
481
  console.log(chalk_1.default.yellow('Operation cancelled'));
@@ -187,115 +486,18 @@ program
187
486
  process.exit(1);
188
487
  }
189
488
  });
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
489
  // 清除所有配置
287
490
  program
288
491
  .command('clear')
289
- .alias('clearall')
290
- .description('Clear all environments and shell integration (DESTRUCTIVE)')
492
+ .alias('reset')
493
+ .description('Clear all provider configurations (DESTRUCTIVE)')
291
494
  .action(async () => {
292
495
  try {
293
- // 确认操作
294
496
  const confirmAnswer = await inquirer_1.default.prompt([
295
497
  {
296
498
  type: 'confirm',
297
499
  name: 'confirmed',
298
- message: chalk_1.default.red('⚠️ This will remove ALL environments and shell integration. Are you sure?'),
500
+ message: chalk_1.default.red('⚠️ This will remove ALL provider configurations. Are you sure?'),
299
501
  default: false
300
502
  }
301
503
  ]);
@@ -303,174 +505,24 @@ program
303
505
  console.log(chalk_1.default.yellow('Operation cancelled.'));
304
506
  return;
305
507
  }
306
- // 执行清除
307
- console.log(chalk_1.default.yellow('Clearing CCM configuration...'));
308
- const result = await envManager.clearAll();
309
- // 显示结果
310
- console.log();
508
+ await providerManager.init();
509
+ const result = await providerManager.clearAll();
311
510
  if (result.success) {
312
511
  console.log(chalk_1.default.green(`✓ ${result.message}`));
512
+ console.log(chalk_1.default.cyan('CCM has been reset to initial state.'));
513
+ console.log(chalk_1.default.cyan('You can start fresh with: ccman'));
313
514
  }
314
515
  else {
315
- console.log(chalk_1.default.red(`✗ ${result.message}`));
516
+ console.error(chalk_1.default.red(`✗ ${result.message}`));
316
517
  }
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
518
  }
339
519
  catch (error) {
340
520
  console.error(chalk_1.default.red(`✗ Error: ${error}`));
341
521
  process.exit(1);
342
522
  }
343
523
  });
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
- });
524
+ // 添加语言管理命令
525
+ program.addCommand((0, lang_1.createLanguageCommands)());
474
526
  // 解析命令行参数
475
- program.parse();
527
+ program.parse(process.argv);
476
528
  //# sourceMappingURL=cli.js.map