cckit 0.3.0 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +254 -13
- package/dist/commands.d.ts +13 -3
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +1 -564
- package/dist/commands.js.map +1 -1
- package/dist/config.d.ts +18 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -293
- package/dist/config.js.map +1 -1
- package/dist/i18n.js +1 -246
- package/dist/i18n.js.map +1 -1
- package/dist/index.js +1 -152
- package/dist/index.js.map +1 -1
- package/dist/providers.js +1 -196
- package/dist/providers.js.map +1 -1
- package/dist/proxy/chat-to-response.d.ts +9 -0
- package/dist/proxy/chat-to-response.d.ts.map +1 -0
- package/dist/proxy/chat-to-response.js +1 -0
- package/dist/proxy/chat-to-response.js.map +1 -0
- package/dist/proxy/constants.d.ts +2 -0
- package/dist/proxy/constants.d.ts.map +1 -0
- package/dist/proxy/constants.js +1 -0
- package/dist/proxy/constants.js.map +1 -0
- package/dist/proxy/proxy-manager.d.ts +61 -0
- package/dist/proxy/proxy-manager.d.ts.map +1 -0
- package/dist/proxy/proxy-manager.js +1 -0
- package/dist/proxy/proxy-manager.js.map +1 -0
- package/dist/tools/base-adapter.d.ts +31 -0
- package/dist/tools/base-adapter.d.ts.map +1 -0
- package/dist/tools/base-adapter.js +1 -0
- package/dist/tools/base-adapter.js.map +1 -0
- package/dist/tools/claude-code-adapter.d.ts +15 -0
- package/dist/tools/claude-code-adapter.d.ts.map +1 -0
- package/dist/tools/claude-code-adapter.js +1 -0
- package/dist/tools/claude-code-adapter.js.map +1 -0
- package/dist/tools/codex-adapter.d.ts +43 -0
- package/dist/tools/codex-adapter.d.ts.map +1 -0
- package/dist/tools/codex-adapter.js +1 -0
- package/dist/tools/codex-adapter.js.map +1 -0
- package/dist/tools/index.d.ts +20 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/opencode-adapter.d.ts +41 -0
- package/dist/tools/opencode-adapter.d.ts.map +1 -0
- package/dist/tools/opencode-adapter.js +1 -0
- package/dist/tools/opencode-adapter.js.map +1 -0
- package/dist/tools/types.d.ts +16 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +1 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/constants.d.ts +1 -1
- package/dist/utils/constants.js +1 -69
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/errors.js +1 -92
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/helpers.js +1 -117
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/index.js +1 -8
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/logger.js +1 -68
- package/dist/utils/logger.js.map +1 -1
- package/package.json +2 -3
package/dist/commands.js
CHANGED
|
@@ -1,564 +1 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import { select, input, confirm } from '@inquirer/prompts';
|
|
4
|
-
import { createProvider } from './config.js';
|
|
5
|
-
import { testProvider, PROVIDER_CONFIGS } from './providers.js';
|
|
6
|
-
import { i18n } from './i18n.js';
|
|
7
|
-
export class Commands {
|
|
8
|
-
constructor(configManager) {
|
|
9
|
-
this.configManager = configManager;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Interactive configuration wizard with arrow key selection
|
|
13
|
-
*/
|
|
14
|
-
async interactive() {
|
|
15
|
-
console.log();
|
|
16
|
-
console.log(chalk.blue.bold(' ___ ___ / ___ ( ) __ ___ '));
|
|
17
|
-
console.log(chalk.blue.bold(' // ) ) // ) ) //\\ \\ / / / / '));
|
|
18
|
-
console.log(chalk.blue.bold(' // // // \\ \\ / / / / '));
|
|
19
|
-
console.log(chalk.blue.bold(' ((____ ((____ // \\ \\ / / / / '));
|
|
20
|
-
console.log(chalk.cyan.bold(' 交互式配置向导'));
|
|
21
|
-
console.log();
|
|
22
|
-
// Step 1: Select provider type using arrow keys
|
|
23
|
-
console.log();
|
|
24
|
-
console.log(chalk.cyan.bold('▸ Step 1: 选择要配置的 AI 提供商'));
|
|
25
|
-
console.log();
|
|
26
|
-
const providerTypes = Object.entries(PROVIDER_CONFIGS)
|
|
27
|
-
.filter(([key]) => key !== 'custom')
|
|
28
|
-
.map(([key, config]) => ({
|
|
29
|
-
value: key,
|
|
30
|
-
name: config.display_name,
|
|
31
|
-
defaultModel: config.default_model,
|
|
32
|
-
}));
|
|
33
|
-
const providerTypeChoices = [
|
|
34
|
-
...providerTypes.map((p) => ({
|
|
35
|
-
value: { type: 'preset', id: p.value, name: p.name, defaultModel: p.defaultModel },
|
|
36
|
-
name: p.name,
|
|
37
|
-
})),
|
|
38
|
-
{
|
|
39
|
-
value: { type: 'custom' },
|
|
40
|
-
name: chalk.green('自定义 Provider (Local LLM / OpenAI Compatible)'),
|
|
41
|
-
},
|
|
42
|
-
];
|
|
43
|
-
const providerChoice = await select({
|
|
44
|
-
message: '请选择提供商',
|
|
45
|
-
choices: providerTypeChoices,
|
|
46
|
-
pageSize: 12,
|
|
47
|
-
});
|
|
48
|
-
let providerType;
|
|
49
|
-
let providerName;
|
|
50
|
-
let defaultModel;
|
|
51
|
-
if (providerChoice.type === 'custom') {
|
|
52
|
-
providerType = 'custom';
|
|
53
|
-
providerName = await input({
|
|
54
|
-
message: '请输入自定义 Provider 名称 (例如: ollama, my-api)',
|
|
55
|
-
default: 'ollama',
|
|
56
|
-
});
|
|
57
|
-
defaultModel = 'llama3';
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
providerType = providerChoice.id;
|
|
61
|
-
providerName = providerChoice.name;
|
|
62
|
-
defaultModel = providerChoice.defaultModel;
|
|
63
|
-
}
|
|
64
|
-
console.log();
|
|
65
|
-
console.log(chalk.cyan.bold(`▸ Step 2: 配置 ${providerName}`));
|
|
66
|
-
console.log();
|
|
67
|
-
// Step 2: Enter API key
|
|
68
|
-
const apiKey = await input({
|
|
69
|
-
message: '请输入 API Key',
|
|
70
|
-
validate: (value) => {
|
|
71
|
-
if (!value || value.trim() === '') {
|
|
72
|
-
return 'API Key 不能为空';
|
|
73
|
-
}
|
|
74
|
-
return true;
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
// Step 3: Enter base URL (for custom providers)
|
|
78
|
-
let baseUrl;
|
|
79
|
-
if (providerType === 'custom') {
|
|
80
|
-
baseUrl = await input({
|
|
81
|
-
message: '请输入 Base URL',
|
|
82
|
-
default: 'http://localhost:11434/v1',
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
// Step 4: Enter model name
|
|
86
|
-
console.log();
|
|
87
|
-
console.log(chalk.cyan.bold('▸ Step 3: 设置模型'));
|
|
88
|
-
console.log();
|
|
89
|
-
const modelInput = await input({
|
|
90
|
-
message: '请输入模型名称 (多个模型用逗号分隔,如: claude-3-opus, claude-3-sonnet)',
|
|
91
|
-
default: defaultModel,
|
|
92
|
-
});
|
|
93
|
-
// Parse model names: split by comma and trim whitespace
|
|
94
|
-
const models = modelInput
|
|
95
|
-
.split(',')
|
|
96
|
-
.map((m) => m.trim())
|
|
97
|
-
.filter((m) => m.length > 0);
|
|
98
|
-
const model = models[0] || defaultModel;
|
|
99
|
-
// Step 5: Save configuration
|
|
100
|
-
console.log();
|
|
101
|
-
console.log(chalk.cyan.bold('▸ Step 4: 保存配置'));
|
|
102
|
-
console.log();
|
|
103
|
-
const providers = this.configManager.listProviders();
|
|
104
|
-
const sameTypeProviders = providers.filter((p) => p.provider_type === providerType);
|
|
105
|
-
let provider;
|
|
106
|
-
// If there are existing providers of the same type, ask user what to do
|
|
107
|
-
if (sameTypeProviders.length > 0 && providerType !== 'custom') {
|
|
108
|
-
const updateChoices = [
|
|
109
|
-
...sameTypeProviders.map((p, i) => ({
|
|
110
|
-
value: { action: 'update', index: i },
|
|
111
|
-
name: `${p.name} (模型: ${p.current_model || p.models[0] || 'none'})`,
|
|
112
|
-
})),
|
|
113
|
-
{
|
|
114
|
-
value: { action: 'create' },
|
|
115
|
-
name: chalk.green(`创建新的 ${providerName} 配置`),
|
|
116
|
-
},
|
|
117
|
-
];
|
|
118
|
-
const updateChoice = await select({
|
|
119
|
-
message: `发现 ${sameTypeProviders.length} 个已存在的配置,请选择`,
|
|
120
|
-
choices: updateChoices,
|
|
121
|
-
});
|
|
122
|
-
if (updateChoice.action === 'update') {
|
|
123
|
-
const existingProvider = sameTypeProviders[updateChoice.index];
|
|
124
|
-
existingProvider.api_key = apiKey;
|
|
125
|
-
if (baseUrl)
|
|
126
|
-
existingProvider.base_url = baseUrl;
|
|
127
|
-
// Add all new models that don't already exist
|
|
128
|
-
for (const m of models) {
|
|
129
|
-
if (!existingProvider.models.includes(m)) {
|
|
130
|
-
existingProvider.models.push(m);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
existingProvider.current_model = model;
|
|
134
|
-
existingProvider.updated_at = new Date().toISOString();
|
|
135
|
-
provider = existingProvider;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
else if (providerType === 'custom') {
|
|
139
|
-
// For custom providers, check if a provider with the same name exists
|
|
140
|
-
const existingCustomProvider = providers.find((p) => p.provider_type === 'custom' && p.name === providerName);
|
|
141
|
-
if (existingCustomProvider) {
|
|
142
|
-
const shouldUpdate = await confirm({
|
|
143
|
-
message: `发现已存在的 "${providerName}" 配置,是否更新?`,
|
|
144
|
-
default: true,
|
|
145
|
-
});
|
|
146
|
-
if (shouldUpdate) {
|
|
147
|
-
existingCustomProvider.api_key = apiKey;
|
|
148
|
-
if (baseUrl)
|
|
149
|
-
existingCustomProvider.base_url = baseUrl;
|
|
150
|
-
// Add all new models that don't already exist
|
|
151
|
-
for (const m of models) {
|
|
152
|
-
if (!existingCustomProvider.models.includes(m)) {
|
|
153
|
-
existingCustomProvider.models.push(m);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
existingCustomProvider.current_model = model;
|
|
157
|
-
existingCustomProvider.updated_at = new Date().toISOString();
|
|
158
|
-
provider = existingCustomProvider;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
// If provider is not set, create a new one
|
|
163
|
-
if (!provider) {
|
|
164
|
-
provider = createProvider(providerType, providerName, apiKey, baseUrl, models);
|
|
165
|
-
provider.current_model = model;
|
|
166
|
-
}
|
|
167
|
-
this.configManager.saveProvider(provider);
|
|
168
|
-
console.log(chalk.green(`✓ 配置已保存 (id: ${provider.id})`));
|
|
169
|
-
console.log(` ${i18n.general.provider_label()}: ${providerName}`);
|
|
170
|
-
console.log(` ${i18n.general.model_label()}: ${models.join(', ')}`);
|
|
171
|
-
// Step 6: Ask to test connection
|
|
172
|
-
console.log();
|
|
173
|
-
console.log(chalk.cyan.bold('▸ Step 5: 测试连接'));
|
|
174
|
-
console.log();
|
|
175
|
-
const shouldTest = await confirm({
|
|
176
|
-
message: '是否测试连接?',
|
|
177
|
-
default: true,
|
|
178
|
-
});
|
|
179
|
-
if (shouldTest) {
|
|
180
|
-
console.log(chalk.yellow(`正在测试 ${providerName} 连接...`));
|
|
181
|
-
const result = await testProvider(provider);
|
|
182
|
-
if (result.success) {
|
|
183
|
-
console.log(chalk.green(`✓ 连接成功!`));
|
|
184
|
-
if (result.response_time_ms) {
|
|
185
|
-
console.log(chalk.dim(` 响应时间: ${result.response_time_ms}ms`));
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
console.log(chalk.red(`✗ 连接失败: ${result.message}`));
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
// Step 7: Ask to switch
|
|
193
|
-
console.log();
|
|
194
|
-
console.log(chalk.cyan.bold('▸ Step 6: 切换 Provider'));
|
|
195
|
-
console.log();
|
|
196
|
-
const shouldSwitch = await confirm({
|
|
197
|
-
message: '是否立即切换到该 Provider?',
|
|
198
|
-
default: true,
|
|
199
|
-
});
|
|
200
|
-
if (shouldSwitch) {
|
|
201
|
-
this.configManager.switchProvider(provider.id);
|
|
202
|
-
console.log(chalk.green.bold(`✓ 已切换到 ${providerName}`));
|
|
203
|
-
console.log(chalk.dim(i18n.cli.restart_note()));
|
|
204
|
-
}
|
|
205
|
-
console.log();
|
|
206
|
-
console.log(chalk.green.bold(' ___ ___ / ___ ( ) __ ___ '));
|
|
207
|
-
console.log(chalk.green.bold(' // ) ) // ) ) //\\ \\ / / / / '));
|
|
208
|
-
console.log(chalk.green.bold(' // // // \\ \\ / / / / '));
|
|
209
|
-
console.log(chalk.green.bold(' ((____ ((____ // \\ \\ / / / / '));
|
|
210
|
-
console.log(chalk.cyan.bold(' 配置完成! ✓'));
|
|
211
|
-
console.log();
|
|
212
|
-
}
|
|
213
|
-
list() {
|
|
214
|
-
console.log(chalk.blue.bold(i18n.cli.list_title()));
|
|
215
|
-
console.log();
|
|
216
|
-
const providers = this.configManager.listProviders();
|
|
217
|
-
const currentProvider = this.configManager.getCurrentProvider();
|
|
218
|
-
for (const provider of providers) {
|
|
219
|
-
const isCurrent = currentProvider?.id === provider.id;
|
|
220
|
-
const status = isCurrent
|
|
221
|
-
? chalk.green.bold(i18n.status.active())
|
|
222
|
-
: chalk.dim(i18n.status.inactive());
|
|
223
|
-
const providerName = this.getProviderDisplayName(provider.provider_type, provider.name, true);
|
|
224
|
-
console.log(` ${status} ${chalk.bold(providerName)}`);
|
|
225
|
-
console.log(` ${i18n.general.id_label()}: ${chalk.dim(provider.id)}`);
|
|
226
|
-
if (provider.models.length > 0) {
|
|
227
|
-
const activeModel = provider.current_model || provider.models[0] || 'none';
|
|
228
|
-
console.log(` ${i18n.general.model_label()}: ${provider.models.length} ${provider.models.length === 1 ? 'model' : 'models'} (${chalk.dim(activeModel)})`);
|
|
229
|
-
}
|
|
230
|
-
if (provider.api_key) {
|
|
231
|
-
const maskedKey = provider.api_key.substring(0, 8) + '***';
|
|
232
|
-
console.log(` ${i18n.general.api_key_label()}: ${chalk.dim(maskedKey)}`);
|
|
233
|
-
}
|
|
234
|
-
console.log();
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
switch(providerId) {
|
|
238
|
-
const providers = this.configManager.listProviders();
|
|
239
|
-
const provider = providers.find((p) => p.id === providerId || p.name === providerId || p.provider_type === providerId);
|
|
240
|
-
if (!provider) {
|
|
241
|
-
throw new Error(i18n.errors.provider_not_found(providerId));
|
|
242
|
-
}
|
|
243
|
-
console.log(chalk.yellow(i18n.general.switching()));
|
|
244
|
-
this.configManager.switchProvider(provider.id);
|
|
245
|
-
const providerName = this.getProviderDisplayName(provider.provider_type, provider.name, false);
|
|
246
|
-
console.log(chalk.green.bold(i18n.cli.switch_success(providerName)));
|
|
247
|
-
console.log(chalk.dim(i18n.cli.restart_note()));
|
|
248
|
-
}
|
|
249
|
-
current() {
|
|
250
|
-
const currentProvider = this.configManager.getCurrentProvider();
|
|
251
|
-
if (!currentProvider) {
|
|
252
|
-
console.log(chalk.yellow(i18n.cli.no_active_provider()));
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
console.log(chalk.blue.bold(i18n.cli.current_title()));
|
|
256
|
-
console.log();
|
|
257
|
-
const providerName = this.getProviderDisplayName(currentProvider.provider_type, currentProvider.name, true);
|
|
258
|
-
console.log(` ${chalk.bold(providerName)}`);
|
|
259
|
-
console.log(` ${i18n.general.id_label()}: ${chalk.dim(currentProvider.id)}`);
|
|
260
|
-
console.log(` ${i18n.general.type_label()}: ${chalk.dim(currentProvider.provider_type)}`);
|
|
261
|
-
if (currentProvider.current_model) {
|
|
262
|
-
console.log(` ${i18n.general.model_label()}: ${chalk.dim(currentProvider.current_model)}`);
|
|
263
|
-
}
|
|
264
|
-
if (currentProvider.base_url) {
|
|
265
|
-
console.log(` ${i18n.general.base_url_label()}: ${chalk.dim(currentProvider.base_url)}`);
|
|
266
|
-
}
|
|
267
|
-
if (currentProvider.api_key) {
|
|
268
|
-
const maskedKey = currentProvider.api_key.substring(0, 8) + '***';
|
|
269
|
-
console.log(` ${i18n.general.api_key_label()}: ${chalk.dim(maskedKey)}`);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
configure(providerId, apiKey, baseUrl, models) {
|
|
273
|
-
const providers = this.configManager.listProviders();
|
|
274
|
-
let provider = providers.find((p) => p.id === providerId || p.name === providerId || p.provider_type === providerId);
|
|
275
|
-
if (!provider) {
|
|
276
|
-
const providerTypeMap = {
|
|
277
|
-
zhipu: ['zhipu', i18n.providers.get_display_name('zhipu')],
|
|
278
|
-
智谱: ['zhipu', i18n.providers.get_display_name('zhipu')],
|
|
279
|
-
minimax: ['minimax', i18n.providers.get_display_name('minimax')],
|
|
280
|
-
kimi: ['kimi', i18n.providers.get_display_name('kimi')],
|
|
281
|
-
claude: ['claude', i18n.providers.get_display_name('claude')],
|
|
282
|
-
zenmux: ['zenmux', i18n.providers.get_display_name('zenmux')],
|
|
283
|
-
streamlake: ['streamlake', i18n.providers.get_display_name('streamlake')],
|
|
284
|
-
kuaishou: ['streamlake', i18n.providers.get_display_name('streamlake')],
|
|
285
|
-
快手: ['streamlake', i18n.providers.get_display_name('streamlake')],
|
|
286
|
-
volcengine: ['volcengine', i18n.providers.get_display_name('volcengine')],
|
|
287
|
-
aliyun: ['aliyun', i18n.providers.get_display_name('aliyun')],
|
|
288
|
-
阿里云: ['aliyun', i18n.providers.get_display_name('aliyun')],
|
|
289
|
-
tencent: ['tencent', i18n.providers.get_display_name('tencent')],
|
|
290
|
-
腾讯: ['tencent', i18n.providers.get_display_name('tencent')],
|
|
291
|
-
腾讯云: ['tencent', i18n.providers.get_display_name('tencent')],
|
|
292
|
-
};
|
|
293
|
-
// Check if this is a custom provider (format: custom:<name> or just a new name)
|
|
294
|
-
if (providerId.startsWith('custom:')) {
|
|
295
|
-
const customName = providerId.substring(7); // Remove 'custom:' prefix
|
|
296
|
-
provider = createProvider('custom', customName, apiKey, baseUrl, models);
|
|
297
|
-
}
|
|
298
|
-
else if (!providerTypeMap[providerId]) {
|
|
299
|
-
// Treat unknown providerId as a custom provider name
|
|
300
|
-
provider = createProvider('custom', providerId, apiKey, baseUrl, models);
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
303
|
-
const [providerType, providerName] = providerTypeMap[providerId] || [null, null];
|
|
304
|
-
if (!providerType) {
|
|
305
|
-
throw new Error(i18n.errors.unknown_provider(providerId));
|
|
306
|
-
}
|
|
307
|
-
provider = createProvider(providerType, providerName, apiKey, baseUrl, models);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
else {
|
|
311
|
-
if (apiKey)
|
|
312
|
-
provider.api_key = apiKey;
|
|
313
|
-
if (baseUrl)
|
|
314
|
-
provider.base_url = baseUrl;
|
|
315
|
-
if (models && models.length > 0) {
|
|
316
|
-
for (const model of models) {
|
|
317
|
-
if (!provider.models.includes(model)) {
|
|
318
|
-
provider.models.push(model);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
provider.updated_at = new Date().toISOString();
|
|
323
|
-
}
|
|
324
|
-
this.configManager.saveProvider(provider);
|
|
325
|
-
const providerName = this.getProviderDisplayName(provider.provider_type, provider.name, false);
|
|
326
|
-
console.log(chalk.green.bold(i18n.cli.configure_success(providerName)));
|
|
327
|
-
if (provider.api_key) {
|
|
328
|
-
const maskedKey = provider.api_key.substring(0, 8) + '***';
|
|
329
|
-
console.log(` ${i18n.general.api_key_label()}: ${chalk.dim(maskedKey)}`);
|
|
330
|
-
}
|
|
331
|
-
if (provider.base_url) {
|
|
332
|
-
console.log(` ${i18n.general.base_url_label()}: ${provider.base_url}`);
|
|
333
|
-
}
|
|
334
|
-
if (provider.models.length > 0) {
|
|
335
|
-
console.log(` ${i18n.general.model_label()}: ${provider.models.join(', ')}`);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
show(providerId) {
|
|
339
|
-
const providers = this.configManager.listProviders();
|
|
340
|
-
const provider = providers.find((p) => p.id === providerId || p.name === providerId || p.provider_type === providerId);
|
|
341
|
-
if (!provider) {
|
|
342
|
-
throw new Error(i18n.errors.provider_not_found(providerId));
|
|
343
|
-
}
|
|
344
|
-
const providerName = this.getProviderDisplayName(provider.provider_type, provider.name, false);
|
|
345
|
-
console.log(chalk.blue.bold(i18n.cli.show_config_title(providerName)));
|
|
346
|
-
console.log();
|
|
347
|
-
console.log(` ${i18n.general.id_label()}: ${provider.id}`);
|
|
348
|
-
console.log(` ${i18n.general.name_label()}: ${provider.name}`);
|
|
349
|
-
console.log(` ${i18n.general.type_label()}: ${provider.provider_type}`);
|
|
350
|
-
console.log(` ${i18n.general.created_label()}: ${new Date(provider.created_at).toLocaleString()}`);
|
|
351
|
-
console.log(` ${i18n.general.updated_label()}: ${new Date(provider.updated_at).toLocaleString()}`);
|
|
352
|
-
if (provider.api_key) {
|
|
353
|
-
const maskedKey = provider.api_key.substring(0, 8) + '***';
|
|
354
|
-
console.log(` ${i18n.general.api_key_label()}: ${maskedKey}`);
|
|
355
|
-
}
|
|
356
|
-
else {
|
|
357
|
-
console.log(` ${i18n.general.api_key_label()}: ${chalk.red(i18n.status.not_configured())}`);
|
|
358
|
-
}
|
|
359
|
-
if (provider.base_url) {
|
|
360
|
-
console.log(` ${i18n.general.base_url_label()}: ${provider.base_url}`);
|
|
361
|
-
}
|
|
362
|
-
if (provider.models.length > 0) {
|
|
363
|
-
console.log(` ${i18n.general.model_label()}: ${provider.models.join(', ')}`);
|
|
364
|
-
if (provider.current_model) {
|
|
365
|
-
console.log(` ${chalk.dim(`Active: ${provider.current_model}`)}`);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
async test(providerId) {
|
|
370
|
-
const providers = this.configManager.listProviders();
|
|
371
|
-
const provider = providers.find((p) => p.id === providerId || p.name === providerId || p.provider_type === providerId);
|
|
372
|
-
if (!provider) {
|
|
373
|
-
throw new Error(i18n.errors.provider_not_found(providerId));
|
|
374
|
-
}
|
|
375
|
-
console.log(chalk.yellow(i18n.cli.test_connection(provider.name)));
|
|
376
|
-
if (!provider.api_key) {
|
|
377
|
-
throw new Error(i18n.errors.provider_not_configured());
|
|
378
|
-
}
|
|
379
|
-
const result = await testProvider(provider);
|
|
380
|
-
if (result.success) {
|
|
381
|
-
console.log(chalk.green(`✓ ${result.message}`));
|
|
382
|
-
if (result.model_info) {
|
|
383
|
-
console.log(` Model: ${result.model_info.model_name}`);
|
|
384
|
-
console.log(` Provider: ${result.model_info.provider_name}`);
|
|
385
|
-
console.log(` Response time: ${result.response_time_ms}ms`);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
else {
|
|
389
|
-
console.log(chalk.red(`✗ ${result.message}`));
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
models(providerId) {
|
|
393
|
-
const providers = this.configManager.listProviders();
|
|
394
|
-
const provider = providers.find((p) => p.id === providerId || p.name === providerId || p.provider_type === providerId);
|
|
395
|
-
if (!provider) {
|
|
396
|
-
throw new Error(i18n.errors.provider_not_found(providerId));
|
|
397
|
-
}
|
|
398
|
-
console.log(chalk.blue.bold(`${i18n.general.model_label()} (${provider.models.length} models)`));
|
|
399
|
-
console.log();
|
|
400
|
-
if (provider.models.length === 0) {
|
|
401
|
-
console.log(` ${chalk.dim('No models configured')}`);
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
const activeModel = provider.current_model || provider.models[0];
|
|
405
|
-
for (const model of provider.models) {
|
|
406
|
-
const isActive = model === activeModel;
|
|
407
|
-
const marker = isActive ? '✓' : ' ';
|
|
408
|
-
const display = isActive ? chalk.green.bold(model) : model;
|
|
409
|
-
console.log(` ${marker} ${display}`);
|
|
410
|
-
}
|
|
411
|
-
console.log();
|
|
412
|
-
}
|
|
413
|
-
async setModel(providerId, modelName) {
|
|
414
|
-
const providers = this.configManager.listProviders();
|
|
415
|
-
const provider = providers.find((p) => p.id === providerId || p.name === providerId || p.provider_type === providerId);
|
|
416
|
-
if (!provider) {
|
|
417
|
-
throw new Error(i18n.errors.provider_not_found(providerId));
|
|
418
|
-
}
|
|
419
|
-
if (!provider.models.includes(modelName)) {
|
|
420
|
-
throw new Error(`Model '${modelName}' not found in provider`);
|
|
421
|
-
}
|
|
422
|
-
const currentProvider = this.configManager.getCurrentProvider();
|
|
423
|
-
const isCurrentProvider = currentProvider && currentProvider.id === provider.id;
|
|
424
|
-
// Check if the provider is not the current active one
|
|
425
|
-
if (!isCurrentProvider && currentProvider) {
|
|
426
|
-
const currentProviderName = this.getProviderDisplayName(currentProvider.provider_type, currentProvider.name, false);
|
|
427
|
-
const targetProviderName = this.getProviderDisplayName(provider.provider_type, provider.name, false);
|
|
428
|
-
console.log();
|
|
429
|
-
console.log(chalk.yellow(`⚠ Warning: ${currentProviderName} is currently active.`));
|
|
430
|
-
console.log(chalk.dim(`You are setting a model for ${targetProviderName}, which will not affect your current Claude Code configuration.`));
|
|
431
|
-
console.log();
|
|
432
|
-
// Ask if user wants to switch
|
|
433
|
-
const shouldSwitch = await this.askForSwitch(targetProviderName);
|
|
434
|
-
if (shouldSwitch) {
|
|
435
|
-
// Set the model and switch to this provider
|
|
436
|
-
provider.current_model = modelName;
|
|
437
|
-
provider.updated_at = new Date().toISOString();
|
|
438
|
-
this.configManager.saveProvider(provider);
|
|
439
|
-
this.configManager.switchProvider(provider.id);
|
|
440
|
-
console.log();
|
|
441
|
-
console.log(`${chalk.green('✓ Successfully switched to')} ${chalk.bold(targetProviderName)} ${chalk.dim('with model')} ${chalk.bold(modelName)}`);
|
|
442
|
-
console.log(chalk.dim(i18n.cli.restart_note()));
|
|
443
|
-
}
|
|
444
|
-
else {
|
|
445
|
-
// Only set the model without switching
|
|
446
|
-
provider.current_model = modelName;
|
|
447
|
-
provider.updated_at = new Date().toISOString();
|
|
448
|
-
this.configManager.saveProvider(provider);
|
|
449
|
-
console.log();
|
|
450
|
-
console.log(`${chalk.green('✓ Model set for')} ${chalk.bold(targetProviderName)} ${chalk.dim('to')} ${chalk.bold(modelName)} ${chalk.dim('(provider not switched)')}`);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
// Provider is current or no current provider, just set the model
|
|
455
|
-
provider.current_model = modelName;
|
|
456
|
-
provider.updated_at = new Date().toISOString();
|
|
457
|
-
this.configManager.saveProvider(provider);
|
|
458
|
-
// Update Claude settings if this is the current provider
|
|
459
|
-
if (currentProvider && currentProvider.id === provider.id) {
|
|
460
|
-
this.configManager.updateCurrentProviderSettings();
|
|
461
|
-
}
|
|
462
|
-
const providerName = this.getProviderDisplayName(provider.provider_type, provider.name, false);
|
|
463
|
-
console.log(`${chalk.green('✓')} ${chalk.bold(providerName)} ${chalk.dim('model set to')} ${chalk.bold(modelName)}`);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
removeModel(providerId, modelName) {
|
|
467
|
-
const providers = this.configManager.listProviders();
|
|
468
|
-
const provider = providers.find((p) => p.id === providerId || p.name === providerId || p.provider_type === providerId);
|
|
469
|
-
if (!provider) {
|
|
470
|
-
throw new Error(i18n.errors.provider_not_found(providerId));
|
|
471
|
-
}
|
|
472
|
-
if (!provider.models.includes(modelName)) {
|
|
473
|
-
throw new Error(`Model '${modelName}' not found in provider`);
|
|
474
|
-
}
|
|
475
|
-
const modelIndex = provider.models.indexOf(modelName);
|
|
476
|
-
provider.models.splice(modelIndex, 1);
|
|
477
|
-
if (provider.current_model === modelName) {
|
|
478
|
-
provider.current_model = provider.models.length > 0 ? provider.models[0] : undefined;
|
|
479
|
-
}
|
|
480
|
-
provider.updated_at = new Date().toISOString();
|
|
481
|
-
this.configManager.saveProvider(provider);
|
|
482
|
-
// Update Claude settings if this is the current provider
|
|
483
|
-
const currentProvider = this.configManager.getCurrentProvider();
|
|
484
|
-
if (currentProvider && currentProvider.id === provider.id) {
|
|
485
|
-
this.configManager.updateCurrentProviderSettings();
|
|
486
|
-
}
|
|
487
|
-
const providerName = this.getProviderDisplayName(provider.provider_type, provider.name, false);
|
|
488
|
-
console.log(chalk.green(`Model '${modelName}' removed from ${providerName}`));
|
|
489
|
-
if (provider.models.length === 0) {
|
|
490
|
-
console.log(chalk.yellow('Warning: No models remaining in this provider'));
|
|
491
|
-
}
|
|
492
|
-
else {
|
|
493
|
-
console.log(chalk.dim(`Remaining models: ${provider.models.join(', ')}`));
|
|
494
|
-
if (provider.current_model) {
|
|
495
|
-
console.log(chalk.dim(`Current active model: ${provider.current_model}`));
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
export(output) {
|
|
500
|
-
const config = this.configManager.exportConfig();
|
|
501
|
-
const exportData = {
|
|
502
|
-
...config,
|
|
503
|
-
exported_at: new Date().toISOString(),
|
|
504
|
-
};
|
|
505
|
-
const jsonStr = JSON.stringify(exportData, null, 2);
|
|
506
|
-
if (output) {
|
|
507
|
-
fs.writeFileSync(output, jsonStr);
|
|
508
|
-
console.log(chalk.green.bold(i18n.cli.export_success(output)));
|
|
509
|
-
}
|
|
510
|
-
else {
|
|
511
|
-
console.log(chalk.blue.bold(i18n.general.configuration_label()));
|
|
512
|
-
console.log(jsonStr);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
import(file) {
|
|
516
|
-
if (!fs.existsSync(file)) {
|
|
517
|
-
throw new Error(`File '${file}' not found`);
|
|
518
|
-
}
|
|
519
|
-
const content = fs.readFileSync(file, 'utf-8');
|
|
520
|
-
const importData = JSON.parse(content);
|
|
521
|
-
this.configManager.importConfig(importData);
|
|
522
|
-
console.log(chalk.green.bold(i18n.cli.import_success(file)));
|
|
523
|
-
}
|
|
524
|
-
reset() {
|
|
525
|
-
console.log(chalk.yellow(i18n.general.resetting()));
|
|
526
|
-
this.configManager.resetToClaudeDefault();
|
|
527
|
-
console.log(chalk.green(i18n.cli.reset_success()));
|
|
528
|
-
console.log(chalk.dim(i18n.cli.restart_note()));
|
|
529
|
-
}
|
|
530
|
-
getProviderDisplayName(providerType, providerName, withColor = true) {
|
|
531
|
-
// For custom providers, use the actual name
|
|
532
|
-
if (providerType === 'custom') {
|
|
533
|
-
const displayName = providerName || 'Custom Provider';
|
|
534
|
-
if (!withColor) {
|
|
535
|
-
return displayName;
|
|
536
|
-
}
|
|
537
|
-
return chalk.green(displayName);
|
|
538
|
-
}
|
|
539
|
-
const displayName = i18n.providers.get_display_name(providerType);
|
|
540
|
-
if (!withColor) {
|
|
541
|
-
return displayName;
|
|
542
|
-
}
|
|
543
|
-
const colorMap = {
|
|
544
|
-
zhipu: (s) => chalk.yellow(s),
|
|
545
|
-
minimax: (s) => chalk.cyan(s),
|
|
546
|
-
kimi: (s) => chalk.magenta(s),
|
|
547
|
-
claude: (s) => chalk.white(s),
|
|
548
|
-
zenmux: (s) => chalk.blue(s),
|
|
549
|
-
streamlake: (s) => chalk.hex('#FF6B00')(s), // Kuaishou orange
|
|
550
|
-
volcengine: (s) => chalk.hex('#FF4500')(s), // Volcengine orange-red
|
|
551
|
-
aliyun: (s) => chalk.hex('#FF6A00')(s), // Aliyun orange
|
|
552
|
-
custom: (s) => chalk.green(s), // Custom providers get green color
|
|
553
|
-
};
|
|
554
|
-
const colorFn = colorMap[providerType] || ((s) => s);
|
|
555
|
-
return colorFn(displayName);
|
|
556
|
-
}
|
|
557
|
-
async askForSwitch(providerName) {
|
|
558
|
-
return confirm({
|
|
559
|
-
message: `Do you want to switch to ${providerName} now?`,
|
|
560
|
-
default: false,
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
//# sourceMappingURL=commands.js.map
|
|
1
|
+
import e from"chalk";import o from"fs";import{select as l,input as n,confirm as s}from"@inquirer/prompts";import{createProvider as i}from"./config.js";import{testProvider as t,PROVIDER_CONFIGS as r}from"./providers.js";import{i18n as a}from"./i18n.js";import{getAllToolAdapters as d,getToolAdapter as c}from"./tools/index.js";export class Commands{constructor(e){this.configManager=e}async interactive(){console.log(),console.log(e.blue.bold(" ___ ___ / ___ ( ) __ ___ ")),console.log(e.blue.bold(" // ) ) // ) ) //\\ \\ / / / / ")),console.log(e.blue.bold(" // // // \\ \\ / / / / ")),console.log(e.blue.bold(" ((____ ((____ // \\ \\ / / / / ")),console.log(e.cyan.bold(" 交互式配置向导")),console.log(),console.log(),console.log(e.cyan.bold("▸ Step 1: 选择要配置的 AI 提供商")),console.log();const o=[...Object.entries(r).filter(([e])=>"custom"!==e).map(([e,o])=>({value:e,name:o.display_name,defaultModel:o.default_model})).map(e=>({value:{type:"preset",id:e.value,name:e.name,defaultModel:e.defaultModel},name:e.name})),{value:{type:"custom"},name:e.green("自定义 Provider (Local LLM / OpenAI Compatible)")}],d=await l({message:"请选择提供商",choices:o,pageSize:12});let c,g,m;"custom"===d.type?(c="custom",g=await n({message:"请输入自定义 Provider 名称 (例如: ollama, my-api)",default:"ollama"}),m="llama3"):(c=d.id,g=d.name,m=d.defaultModel),console.log(),console.log(e.cyan.bold(`▸ Step 2: 配置 ${g}`)),console.log();const _=await n({message:"请输入 API Key",validate:e=>!(!e||""===e.trim())||"API Key 不能为空"});let u;"custom"===c&&(u=await n({message:"请输入 Base URL",default:"http://localhost:11434/v1"})),console.log(),console.log(e.cyan.bold("▸ Step 3: 设置模型")),console.log();const p=(await n({message:"请输入模型名称 (多个模型用逗号分隔,如: claude-3-opus, claude-3-sonnet)",default:m})).split(",").map(e=>e.trim()).filter(e=>e.length>0),f=p[0]||m;console.log(),console.log(e.cyan.bold("▸ Step 4: 配置模型类型 (可选)")),console.log(e.dim(" 提示: 可为 Sonnet/Haiku/Opus 模型类型配置不同的模型,不配置则使用默认模型")),console.log();let v,y,$;if(await s({message:"是否为不同模型类型 (Sonnet/Haiku/Opus) 配置不同的默认模型?",default:!1})){const o=async o=>{const n=[{value:"__skip__",name:e.dim("跳过 (使用默认模型)")},...p.map(e=>({value:e,name:e}))],s=await l({message:`选择 ${o} 模型`,choices:n});return"__skip__"===s?void 0:s};v=await o("Sonnet"),y=await o("Haiku"),$=await o("Opus"),console.log(),console.log(e.dim(" 模型类型配置:")),v||y||$?(v&&console.log(e.dim(` Sonnet: ${v}`)),y&&console.log(e.dim(` Haiku: ${y}`)),$&&console.log(e.dim(` Opus: ${$}`))):console.log(e.dim(" 所有类型使用默认模型"))}console.log(),console.log(e.cyan.bold("▸ Step 5: 保存配置")),console.log();const h=this.configManager.listProviders(),b=h.filter(e=>e.provider_type===c);let w;if(b.length>0&&"custom"!==c){const o=[...b.map((e,o)=>({value:{action:"update",index:o},name:`${e.name} (模型: ${e.current_model||e.models[0]||"none"})`})),{value:{action:"create"},name:e.green(`创建新的 ${g} 配置`)}],n=await l({message:`发现 ${b.length} 个已存在的配置,请选择`,choices:o});if("update"===n.action){const e=b[n.index];e.api_key=_,u&&(e.base_url=u);for(const o of p)e.models.includes(o)||e.models.push(o);e.current_model=f,v&&(e.default_sonnet_model=v),y&&(e.default_haiku_model=y),$&&(e.default_opus_model=$),e.updated_at=(new Date).toISOString(),w=e}}else if("custom"===c){const e=h.find(e=>"custom"===e.provider_type&&e.name===g);if(e){if(await s({message:`发现已存在的 "${g}" 配置,是否更新?`,default:!0})){e.api_key=_,u&&(e.base_url=u);for(const o of p)e.models.includes(o)||e.models.push(o);e.current_model=f,v&&(e.default_sonnet_model=v),y&&(e.default_haiku_model=y),$&&(e.default_opus_model=$),e.updated_at=(new Date).toISOString(),w=e}}}w||(w=i(c,g,_,u,p),w.current_model=f,v&&(w.default_sonnet_model=v),y&&(w.default_haiku_model=y),$&&(w.default_opus_model=$)),this.configManager.saveProvider(w),console.log(e.green(`✓ 配置已保存 (id: ${w.id})`)),console.log(` ${a.general.provider_label()}: ${g}`),console.log(` ${a.general.model_label()}: ${p.join(", ")}`),console.log(),console.log(e.cyan.bold("▸ Step 6: 测试连接")),console.log();if(await s({message:"是否测试连接?",default:!0})){console.log(e.yellow(`正在测试 ${g} 连接...`));const o=await t(w);o.success?(console.log(e.green("✓ 连接成功!")),o.response_time_ms&&console.log(e.dim(` 响应时间: ${o.response_time_ms}ms`))):console.log(e.red(`✗ 连接失败: ${o.message}`))}console.log(),console.log(e.cyan.bold("▸ Step 7: 切换 Provider")),console.log();await s({message:"是否立即切换到该 Provider?",default:!0})&&(this.configManager.switchProvider(w.id),console.log(e.green.bold(`✓ 已切换到 ${g}`)),console.log(e.dim(a.cli.restart_note()))),console.log(),console.log(e.green.bold(" ___ ___ / ___ ( ) __ ___ ")),console.log(e.green.bold(" // ) ) // ) ) //\\ \\ / / / / ")),console.log(e.green.bold(" // // // \\ \\ / / / / ")),console.log(e.green.bold(" ((____ ((____ // \\ \\ / / / / ")),console.log(e.cyan.bold(" 配置完成! ✓")),console.log()}list(){console.log(e.blue.bold(a.cli.list_title())),console.log();const o=this.configManager.listProviders(),l=this.configManager.getCurrentProvider();for(const n of o){const o=l?.id===n.id?e.green.bold(a.status.active()):e.dim(a.status.inactive()),s=this.getProviderDisplayName(n.provider_type,n.name,!0);if(console.log(` ${o} ${e.bold(s)}`),console.log(` ${a.general.id_label()}: ${e.dim(n.id)}`),n.models.length>0){const o=n.current_model||n.models[0]||"none";console.log(` ${a.general.model_label()}: ${n.models.length} ${1===n.models.length?"model":"models"} (${e.dim(o)})`)}if(n.api_key){const o=n.api_key.substring(0,8)+"***";console.log(` ${a.general.api_key_label()}: ${e.dim(o)}`)}console.log()}}async switch(o,n){const s=this.configManager.listProviders();if(!o){if(0===s.length)return void console.log(e.yellow("没有配置任何 Provider,请先使用 `cckit configure` 或 `cckit interactive` 进行配置"));n||(n=await this.selectToolInteractive());const i=this.configManager.getCurrentProviderForTool(n),t=s.map(o=>{const l=i?.id===o.id,n=this.getProviderDisplayName(o.provider_type,o.name,!1),s=o.current_model||o.models[0]||"none",t=l?"✓ ":" ",r=l?e.green(" (当前)"):"";return{value:o.id,name:`${t}${n} - ${e.dim(s)}${r}`}});console.log();const r=await l({message:"选择要切换的 Provider",choices:t,pageSize:10});o=r}n||(n="claude-code");const i=s.find(e=>e.id===o||e.name===o||e.provider_type===o);if(!i)throw new Error(a.errors.provider_not_found(o));const t=c(n).toolConfig.display_name,r=this.getProviderDisplayName(i.provider_type,i.name,!1);console.log(e.yellow(`正在为 ${t} 切换到 ${r}...`)),await this.configManager.switchProviderForTool(i.id,n),console.log(e.green.bold(`成功切换 ${t} 到 ${r}`)),console.log(e.dim(a.cli.restart_note())),"codex"===n&&(console.log(),console.log(e.cyan("💡 Codex 提示:")),console.log(e.dim(" • 请确保所选模型支持 OpenAI Responses API")))}async selectToolInteractive(){const o=d().map(o=>{const l=o.isInstalled(),n=this.configManager.getCurrentProviderForTool(o.toolType),s=l?n?e.green(` (${n.name})`):e.dim(" (未配置)"):e.dim(" (未安装)");return{value:o.toolType,name:`${o.toolConfig.display_name}${s}`}});return console.log(),l({message:"选择目标工具",choices:o,pageSize:10})}tools(){console.log(e.blue.bold("支持的 CLI 工具")),console.log();const o=d();for(const l of o){const o=l.isInstalled(),n=this.configManager.getCurrentProviderForTool(l.toolType),s=o?e.green("[已安装]"):e.dim("[未安装]");console.log(` ${s} ${e.bold(l.toolConfig.display_name)}`),console.log(` ID: ${e.dim(l.toolType)}`),console.log(` 配置文件: ${e.dim(l.getConfigPath())}`),n?console.log(` 当前 Provider: ${e.cyan(n.name)}`):console.log(` 当前 Provider: ${e.dim("未配置")}`),console.log()}}current(o){const l=o||"claude-code",n=this.configManager.getCurrentProviderForTool(l);if(!n)return void(o?console.log(e.yellow(`${o} 没有配置活跃的 Provider`)):console.log(e.yellow(a.cli.no_active_provider())));const s=c(l);console.log(e.blue.bold(`${s.toolConfig.display_name} - 当前 Provider`)),console.log();const i=this.getProviderDisplayName(n.provider_type,n.name,!0);if(console.log(` ${e.bold(i)}`),console.log(` ${a.general.id_label()}: ${e.dim(n.id)}`),console.log(` ${a.general.type_label()}: ${e.dim(n.provider_type)}`),n.current_model&&console.log(` ${a.general.model_label()}: ${e.dim(n.current_model)}`),n.base_url&&console.log(` ${a.general.base_url_label()}: ${e.dim(n.base_url)}`),n.api_key){const o=n.api_key.substring(0,8)+"***";console.log(` ${a.general.api_key_label()}: ${e.dim(o)}`)}}configure(o,l,n,s){let t=this.configManager.listProviders().find(e=>e.id===o||e.name===o||e.provider_type===o);if(t){if(l&&(t.api_key=l),n&&(t.base_url=n),s&&s.length>0)for(const e of s)t.models.includes(e)||t.models.push(e);t.updated_at=(new Date).toISOString()}else{const e={zhipu:["zhipu",a.providers.get_display_name("zhipu")],"智谱":["zhipu",a.providers.get_display_name("zhipu")],minimax:["minimax",a.providers.get_display_name("minimax")],kimi:["kimi",a.providers.get_display_name("kimi")],claude:["claude",a.providers.get_display_name("claude")],zenmux:["zenmux",a.providers.get_display_name("zenmux")],streamlake:["streamlake",a.providers.get_display_name("streamlake")],kuaishou:["streamlake",a.providers.get_display_name("streamlake")],"快手":["streamlake",a.providers.get_display_name("streamlake")],volcengine:["volcengine",a.providers.get_display_name("volcengine")],aliyun:["aliyun",a.providers.get_display_name("aliyun")],"阿里云":["aliyun",a.providers.get_display_name("aliyun")],tencent:["tencent",a.providers.get_display_name("tencent")],"腾讯":["tencent",a.providers.get_display_name("tencent")],"腾讯云":["tencent",a.providers.get_display_name("tencent")]};if(o.startsWith("custom:")){const e=o.substring(7);t=i("custom",e,l,n,s)}else if(e[o]){const[r,d]=e[o]||[null,null];if(!r)throw new Error(a.errors.unknown_provider(o));t=i(r,d,l,n,s)}else t=i("custom",o,l,n,s)}this.configManager.saveProvider(t);const r=this.getProviderDisplayName(t.provider_type,t.name,!1);if(console.log(e.green.bold(a.cli.configure_success(r))),t.api_key){const o=t.api_key.substring(0,8)+"***";console.log(` ${a.general.api_key_label()}: ${e.dim(o)}`)}t.base_url&&console.log(` ${a.general.base_url_label()}: ${t.base_url}`),t.models.length>0&&console.log(` ${a.general.model_label()}: ${t.models.join(", ")}`)}show(o){const l=this.configManager.listProviders().find(e=>e.id===o||e.name===o||e.provider_type===o);if(!l)throw new Error(a.errors.provider_not_found(o));const n=this.getProviderDisplayName(l.provider_type,l.name,!1);if(console.log(e.blue.bold(a.cli.show_config_title(n))),console.log(),console.log(` ${a.general.id_label()}: ${l.id}`),console.log(` ${a.general.name_label()}: ${l.name}`),console.log(` ${a.general.type_label()}: ${l.provider_type}`),console.log(` ${a.general.created_label()}: ${new Date(l.created_at).toLocaleString()}`),console.log(` ${a.general.updated_label()}: ${new Date(l.updated_at).toLocaleString()}`),l.api_key){const e=l.api_key.substring(0,8)+"***";console.log(` ${a.general.api_key_label()}: ${e}`)}else console.log(` ${a.general.api_key_label()}: ${e.red(a.status.not_configured())}`);l.base_url&&console.log(` ${a.general.base_url_label()}: ${l.base_url}`),l.models.length>0&&(console.log(` ${a.general.model_label()}: ${l.models.join(", ")}`),l.current_model&&console.log(` ${e.dim(`Active: ${l.current_model}`)}`),l.default_sonnet_model&&console.log(` ${e.dim(`Sonnet: ${l.default_sonnet_model}`)}`),l.default_haiku_model&&console.log(` ${e.dim(`Haiku: ${l.default_haiku_model}`)}`),l.default_opus_model&&console.log(` ${e.dim(`Opus: ${l.default_opus_model}`)}`))}async test(o){const l=this.configManager.listProviders().find(e=>e.id===o||e.name===o||e.provider_type===o);if(!l)throw new Error(a.errors.provider_not_found(o));if(console.log(e.yellow(a.cli.test_connection(l.name))),!l.api_key)throw new Error(a.errors.provider_not_configured());const n=await t(l);n.success?(console.log(e.green(`✓ ${n.message}`)),n.model_info&&(console.log(` Model: ${n.model_info.model_name}`),console.log(` Provider: ${n.model_info.provider_name}`),console.log(` Response time: ${n.response_time_ms}ms`))):console.log(e.red(`✗ ${n.message}`))}models(o){const l=this.configManager.listProviders().find(e=>e.id===o||e.name===o||e.provider_type===o);if(!l)throw new Error(a.errors.provider_not_found(o));if(console.log(e.blue.bold(`${a.general.model_label()} (${l.models.length} models)`)),console.log(),0===l.models.length)return void console.log(` ${e.dim("No models configured")}`);const n=l.current_model||l.models[0];for(const o of l.models){const l=o===n,s=l?"✓":" ",i=l?e.green.bold(o):o;console.log(` ${s} ${i}`)}console.log()}async setModel(o,l,n){const s=this.configManager.listProviders().find(e=>e.id===o||e.name===o||e.provider_type===o);if(!s)throw new Error(a.errors.provider_not_found(o));if(!s.models.includes(l))throw new Error(`Model '${l}' not found in provider. Available models: ${s.models.join(", ")||"none"}`);const i=this.configManager.getCurrentProvider(),t=i&&i.id===s.id;if(!n||"default"===n?s.current_model=l:"sonnet"===n?s.default_sonnet_model=l:"haiku"===n?s.default_haiku_model=l:"opus"===n&&(s.default_opus_model=l),s.updated_at=(new Date).toISOString(),!t&&i){const o=this.getProviderDisplayName(i.provider_type,i.name,!1),t=this.getProviderDisplayName(s.provider_type,s.name,!1);console.log(),console.log(e.yellow(`⚠ Warning: ${o} is currently active.`)),console.log(e.dim(`You are setting a model for ${t}, which will not affect your current Claude Code configuration.`)),console.log();if(await this.askForSwitch(t)){this.configManager.saveProvider(s),this.configManager.switchProvider(s.id);const o=this.getModelTypeLabel(n);console.log(),console.log(`${e.green("✓ Successfully switched to")} ${e.bold(t)} ${e.dim("with")} ${o} ${e.bold(l)}`),console.log(e.dim(a.cli.restart_note()))}else{this.configManager.saveProvider(s);const o=this.getModelTypeLabel(n);console.log(),console.log(`${e.green("✓")} ${o} ${e.dim("set for")} ${e.bold(t)} ${e.dim("to")} ${e.bold(l)} ${e.dim("(provider not switched)")}`)}}else{this.configManager.saveProvider(s),i&&i.id===s.id&&this.configManager.updateCurrentProviderSettings();const o=this.getProviderDisplayName(s.provider_type,s.name,!1),t=this.getModelTypeLabel(n);console.log(`${e.green("✓")} ${e.bold(o)} ${t} ${e.dim("set to")} ${e.bold(l)}`)}}removeModel(o,l){const n=this.configManager.listProviders().find(e=>e.id===o||e.name===o||e.provider_type===o);if(!n)throw new Error(a.errors.provider_not_found(o));if(!n.models.includes(l))throw new Error(`Model '${l}' not found in provider`);const s=n.models.indexOf(l);n.models.splice(s,1),n.current_model===l&&(n.current_model=n.models.length>0?n.models[0]:void 0),n.updated_at=(new Date).toISOString(),this.configManager.saveProvider(n);const i=this.configManager.getCurrentProvider();i&&i.id===n.id&&this.configManager.updateCurrentProviderSettings();const t=this.getProviderDisplayName(n.provider_type,n.name,!1);console.log(e.green(`Model '${l}' removed from ${t}`)),0===n.models.length?console.log(e.yellow("Warning: No models remaining in this provider")):(console.log(e.dim(`Remaining models: ${n.models.join(", ")}`)),n.current_model&&console.log(e.dim(`Current active model: ${n.current_model}`)))}export(l){const n={...this.configManager.exportConfig(),exported_at:(new Date).toISOString()},s=JSON.stringify(n,null,2);l?(o.writeFileSync(l,s),console.log(e.green.bold(a.cli.export_success(l)))):(console.log(e.blue.bold(a.general.configuration_label())),console.log(s))}import(l){if(!o.existsSync(l))throw new Error(`File '${l}' not found`);const n=o.readFileSync(l,"utf-8"),s=JSON.parse(n);this.configManager.importConfig(s),console.log(e.green.bold(a.cli.import_success(l)))}reset(){console.log(e.yellow(a.general.resetting())),this.configManager.resetToClaudeDefault(),console.log(e.green(a.cli.reset_success())),console.log(e.dim(a.cli.restart_note()))}getProviderDisplayName(o,l,n=!0){if("custom"===o){const o=l||"Custom Provider";return n?e.green(o):o}const s=a.providers.get_display_name(o);if(!n)return s;return({zhipu:o=>e.yellow(o),minimax:o=>e.cyan(o),kimi:o=>e.magenta(o),claude:o=>e.white(o),zenmux:o=>e.blue(o),streamlake:o=>e.hex("#FF6B00")(o),volcengine:o=>e.hex("#FF4500")(o),aliyun:o=>e.hex("#FF6A00")(o),custom:o=>e.green(o)}[o]||(e=>e))(s)}async askForSwitch(e){return s({message:`Do you want to switch to ${e} now?`,default:!1})}getModelTypeLabel(e){switch(e){case"sonnet":return"Sonnet model";case"haiku":return"Haiku model";case"opus":return"Opus model";default:return"Default model"}}}
|