yingclaw 1.3.0 → 1.4.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 (2) hide show
  1. package/bin/cli.js +64 -35
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -119,8 +119,10 @@ program
119
119
  choices: [
120
120
  { name: '有梯子 / 海外网络(走官方)', value: 'vpn' },
121
121
  { name: '国内网络 / 没有梯子(走镜像)', value: 'cn' },
122
+ { name: chalk.dim('↩ 返回主菜单'), value: '__BACK__' },
122
123
  ],
123
124
  });
125
+ if (network === '__BACK__') return;
124
126
 
125
127
  const cmd = network === 'vpn'
126
128
  ? 'npm install -g @anthropic-ai/claude-code'
@@ -183,42 +185,61 @@ program
183
185
  if (!overwrite) return;
184
186
  }
185
187
 
186
- const providerKey = await select({
187
- message: chalk.cyan('选择 AI 厂商'),
188
- choices: Object.entries(PROVIDERS).map(([value, p]) => ({ name: p.name, value })),
189
- });
190
-
191
- const provider = PROVIDERS[providerKey];
192
-
193
- const apiKey = await input({
194
- message: chalk.cyan(`${provider.name} API Key`),
195
- transformer: (v) => v ? chalk.dim(''.repeat(v.length)) : '',
196
- validate: (v) => v.trim().length > 0 ? true : 'API Key 不能为空',
197
- });
198
-
199
- // 联网拉取支持的模型列表
200
- const fetchSpinner = ora('正在获取可用模型...').start();
201
- const onlineModels = await fetchModels(providerKey, apiKey.trim());
202
- let modelChoices;
203
- if (onlineModels && onlineModels.length > 0) {
204
- fetchSpinner.succeed(chalk.green(`已获取 ${onlineModels.length} 个可用模型`));
205
- modelChoices = onlineModels.map(id => ({ name: id, value: id }));
206
- } else {
207
- fetchSpinner.warn(chalk.yellow('无法获取在线列表,使用内置默认列表'));
208
- modelChoices = provider.models;
188
+ let providerKey, provider, apiKey, model;
189
+ let step = 'provider';
190
+
191
+ while (true) {
192
+ if (step === 'provider') {
193
+ providerKey = await select({
194
+ message: chalk.cyan('选择 AI 厂商'),
195
+ choices: [
196
+ ...Object.entries(PROVIDERS).map(([value, p]) => ({ name: p.name, value })),
197
+ { name: chalk.dim('↩ 返回主菜单'), value: '__BACK__' },
198
+ ],
199
+ });
200
+ if (providerKey === '__BACK__') return;
201
+ provider = PROVIDERS[providerKey];
202
+ step = 'apikey';
203
+ } else if (step === 'apikey') {
204
+ const k = await input({
205
+ message: chalk.cyan(`${provider.name} API Key(输入 b 返回上一步)`),
206
+ transformer: (v) => v && v !== 'b' ? chalk.dim('•'.repeat(v.length)) : v,
207
+ validate: (v) => v.trim().length > 0 ? true : 'API Key 不能为空',
208
+ });
209
+ if (k.trim() === 'b') { step = 'provider'; continue; }
210
+ apiKey = k.trim();
211
+ step = 'model';
212
+ } else if (step === 'model') {
213
+ const fetchSpinner = ora('正在获取可用模型...').start();
214
+ const onlineModels = await fetchModels(providerKey, apiKey);
215
+ let modelChoices;
216
+ if (onlineModels && onlineModels.length > 0) {
217
+ fetchSpinner.succeed(chalk.green(`已获取 ${onlineModels.length} 个可用模型`));
218
+ modelChoices = onlineModels.map(id => ({ name: id, value: id }));
219
+ } else {
220
+ fetchSpinner.warn(chalk.yellow('无法获取在线列表,使用内置默认列表'));
221
+ modelChoices = provider.models;
222
+ }
223
+
224
+ const m = await select({
225
+ message: chalk.cyan('选择模型'),
226
+ choices: [
227
+ ...modelChoices,
228
+ { name: chalk.dim('↩ 返回上一步(重新输入 Key)'), value: '__BACK__' },
229
+ ],
230
+ });
231
+ if (m === '__BACK__') { step = 'apikey'; continue; }
232
+ model = m;
233
+ break;
234
+ }
209
235
  }
210
236
 
211
- const model = await select({
212
- message: chalk.cyan('选择模型'),
213
- choices: modelChoices,
214
- });
215
-
216
237
  const spinner = ora('写入配置...').start();
217
238
  let result, file;
218
239
  try {
219
- const config = { provider: providerKey, model, apiKey: apiKey.trim(), baseUrl: provider.baseUrl };
220
- saveConfig(config);
221
- ({ result, file } = writeEnvToZshrc(provider.baseUrl, apiKey.trim()));
240
+ const cfg = { provider: providerKey, model, apiKey, baseUrl: provider.baseUrl };
241
+ saveConfig(cfg);
242
+ ({ result, file } = writeEnvToZshrc(provider.baseUrl, apiKey));
222
243
  spinner.succeed(chalk.green(result === 'updated' ? `环境变量已更新 → ${file}` : `环境变量已写入 → ${file}`));
223
244
  } catch (e) {
224
245
  spinner.fail(chalk.red(`写入失败: ${e.message}`));
@@ -229,7 +250,7 @@ program
229
250
  console.log(boxen(
230
251
  chalk.bold('配置完成!\n\n') +
231
252
  chalk.dim('ANTHROPIC_BASE_URL ') + chalk.cyan(provider.baseUrl) + '\n' +
232
- chalk.dim('ANTHROPIC_API_KEY ') + chalk.cyan(apiKey.trim().slice(0, 10) + '...') + '\n\n' +
253
+ chalk.dim('ANTHROPIC_API_KEY ') + chalk.cyan(apiKey.slice(0, 10) + '...') + '\n\n' +
233
254
  chalk.white('下次直接输入 ') + chalk.cyan.bold('claude') + chalk.white(' 即可使用'),
234
255
  { padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'green', margin: { top: 1, bottom: 1 } }
235
256
  ));
@@ -240,7 +261,7 @@ program
240
261
 
241
262
  spawn('claude', [], {
242
263
  stdio: 'inherit',
243
- env: { ...process.env, ANTHROPIC_BASE_URL: provider.baseUrl, ANTHROPIC_API_KEY: apiKey.trim() },
264
+ env: { ...process.env, ANTHROPIC_BASE_URL: provider.baseUrl, ANTHROPIC_API_KEY: apiKey },
244
265
  }).on('error', () => {
245
266
  console.log(chalk.yellow('\nClaude Code 未找到,请先运行: claw install-claude'));
246
267
  });
@@ -263,8 +284,12 @@ program
263
284
 
264
285
  const providerKey = await select({
265
286
  message: chalk.cyan('选择 AI 厂商'),
266
- choices: Object.entries(PROVIDERS).map(([value, p]) => ({ name: p.name, value })),
287
+ choices: [
288
+ ...Object.entries(PROVIDERS).map(([value, p]) => ({ name: p.name, value })),
289
+ { name: chalk.dim('↩ 返回主菜单'), value: '__BACK__' },
290
+ ],
267
291
  });
292
+ if (providerKey === '__BACK__') return;
268
293
 
269
294
  const provider = PROVIDERS[providerKey];
270
295
 
@@ -296,8 +321,12 @@ program
296
321
 
297
322
  const model = await select({
298
323
  message: chalk.cyan('选择模型'),
299
- choices: modelChoices,
324
+ choices: [
325
+ ...modelChoices,
326
+ { name: chalk.dim('↩ 返回主菜单'), value: '__BACK__' },
327
+ ],
300
328
  });
329
+ if (model === '__BACK__') return;
301
330
 
302
331
  const spinner = ora('切换中...').start();
303
332
  const newConfig = { ...config, provider: providerKey, model, baseUrl: provider.baseUrl, apiKey };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yingclaw",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Claude Code × 国产大模型一键接入:DeepSeek、Qwen、MiniMax、GLM、MiMo",
5
5
  "main": "index.js",
6
6
  "bin": {