yingclaw 1.6.0 → 1.6.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.
package/bin/cli.js CHANGED
@@ -8,6 +8,7 @@ const {
8
8
  writeEnvToZshrc,
9
9
  fetchModels,
10
10
  resetConfig,
11
+ validateConfig,
11
12
  resolveFastModel,
12
13
  buildClaudeEnv,
13
14
  classifyValidationStatus,
@@ -66,6 +67,11 @@ async function validateKey(config) {
66
67
  });
67
68
  }
68
69
 
70
+ function getConfigValidationMessage(config) {
71
+ const validation = validateConfig(config);
72
+ return validation.valid ? null : validation.message;
73
+ }
74
+
69
75
  function isClaudeInstalled() {
70
76
  try {
71
77
  execSync('claude --version', { stdio: 'pipe' });
@@ -85,6 +91,12 @@ async function showStatus() {
85
91
  console.log(chalk.red('\n未配置,请先运行: claw setup\n'));
86
92
  return;
87
93
  }
94
+ const configProblem = getConfigValidationMessage(config);
95
+ if (configProblem) {
96
+ console.log(chalk.red(`\n配置无效:${configProblem}`));
97
+ console.log(chalk.dim('请运行 claw setup 重新配置。\n'));
98
+ return;
99
+ }
88
100
 
89
101
  const spinner = ora('验证 API Key...').start();
90
102
  const valid = await validateKey(config);
@@ -218,7 +230,7 @@ program
218
230
  chalk.bold('当前配置\n\n') +
219
231
  chalk.dim('厂商 ') + chalk.white(existingProvider?.name || existing.provider) + '\n' +
220
232
  chalk.dim('模型 ') + chalk.yellow(existing.model) + '\n' +
221
- chalk.dim('Key ') + chalk.dim(existing.apiKey.slice(0, 10) + '...'),
233
+ chalk.dim('Key ') + chalk.dim(existing.apiKey ? '已保存' : '缺失'),
222
234
  { padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'yellow', margin: { top: 1, bottom: 1 } }
223
235
  ));
224
236
  const overwrite = await confirm({ message: '覆盖现有配置?', default: false });
@@ -291,7 +303,7 @@ program
291
303
  console.log(boxen(
292
304
  chalk.bold('配置完成!\n\n') +
293
305
  chalk.dim('ANTHROPIC_BASE_URL ') + chalk.cyan(provider.baseUrl) + '\n' +
294
- chalk.dim('ANTHROPIC_API_KEY ') + chalk.cyan(apiKey.slice(0, 10) + '...') + '\n\n' +
306
+ chalk.dim('ANTHROPIC_API_KEY ') + chalk.cyan('已保存') + '\n\n' +
295
307
  chalk.white('下次直接输入 ') + chalk.cyan.bold('claude') + chalk.white(' 即可使用'),
296
308
  { padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'green', margin: { top: 1, bottom: 1 } }
297
309
  ));
@@ -322,6 +334,12 @@ program
322
334
  console.log(chalk.red('\n未配置,请先运行: claw setup\n'));
323
335
  return;
324
336
  }
337
+ const configProblem = getConfigValidationMessage(config);
338
+ if (configProblem) {
339
+ console.log(chalk.red(`\n配置无效:${configProblem}`));
340
+ console.log(chalk.dim('请运行 claw setup 重新配置。\n'));
341
+ return;
342
+ }
325
343
 
326
344
  const providerKey = await select({ loop: false,
327
345
  message: chalk.cyan('选择 AI 厂商'),
@@ -464,7 +482,8 @@ async function runMenu() {
464
482
 
465
483
  const config = loadConfig();
466
484
  let apiStatus; // undefined = skipped, true/false/null = checked
467
- if (config) {
485
+ const configProblem = config ? getConfigValidationMessage(config) : null;
486
+ if (config && !configProblem) {
468
487
  const spinner = ora('正在检测 API 是否通畅...').start();
469
488
  apiStatus = await validateKey(config);
470
489
  if (apiStatus === true) spinner.succeed('API 连接正常');
@@ -472,18 +491,23 @@ async function runMenu() {
472
491
  else spinner.warn('网络异常,无法连接 API');
473
492
  }
474
493
 
475
- console.log(await renderStatusBar(apiStatus));
494
+ if (configProblem) {
495
+ console.log(chalk.red(` ● 配置无效:${configProblem}`));
496
+ console.log(chalk.dim(' 请先选择“首次配置 API Key 和模型”重新配置'));
497
+ } else {
498
+ console.log(await renderStatusBar(apiStatus));
499
+ }
476
500
  console.log();
477
501
 
478
502
  const action = await select({ loop: false,
479
503
  message: chalk.cyan('选择操作'),
480
504
  choices: [
481
- { name: '🤖 启动 Claude Code', value: 'launch', disabled: !config && '需先完成配置' },
505
+ { name: '🤖 启动 Claude Code', value: 'launch', disabled: (!config || configProblem) && '需先完成配置' },
482
506
  { name: '📦 安装 Claude Code', value: 'install' },
483
507
  { name: config ? '⚙️ 重新配置(输入新的 API Key)' : '⚙️ 首次配置 API Key 和模型', value: 'setup' },
484
- { name: '🔄 切换厂商或模型', value: 'switch', disabled: !config && '需先完成配置' },
508
+ { name: '🔄 切换厂商或模型', value: 'switch', disabled: (!config || configProblem) && '需先完成配置' },
485
509
  { name: '📊 查看当前配置', value: 'status', disabled: !config && '需先完成配置' },
486
- { name: '🔁 重新检测 API', value: 'recheck', disabled: !config && '需先完成配置' },
510
+ { name: '🔁 重新检测 API', value: 'recheck', disabled: (!config || configProblem) && '需先完成配置' },
487
511
  { name: '🗑 恢复默认(清除所有配置)', value: 'reset', disabled: !config && '没有可清除的配置' },
488
512
  { name: '退出', value: 'exit' },
489
513
  ],
@@ -498,7 +522,7 @@ async function runMenu() {
498
522
 
499
523
  if (action === 'launch') {
500
524
  const cfg = loadConfig();
501
- if (!cfg) continue;
525
+ if (!cfg || getConfigValidationMessage(cfg)) continue;
502
526
  // 启动 claude 后等它退出,然后回菜单
503
527
  await new Promise((resolve) => {
504
528
  const child = spawn('claude', [], {
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ ...require('./lib/config'),
3
+ ...require('./lib/panel'),
4
+ };
package/lib/config.js CHANGED
@@ -106,6 +106,21 @@ function loadConfig() {
106
106
  }
107
107
  }
108
108
 
109
+ function validateConfig(config) {
110
+ if (!config || typeof config !== 'object') {
111
+ return { valid: false, message: '未找到配置' };
112
+ }
113
+ for (const key of ['provider', 'baseUrl', 'apiKey', 'model']) {
114
+ if (typeof config[key] !== 'string' || config[key].trim().length === 0) {
115
+ return { valid: false, message: `配置缺少 ${key}` };
116
+ }
117
+ }
118
+ if (!PROVIDERS[config.provider]) {
119
+ return { valid: false, message: `未知厂商 ${config.provider}` };
120
+ }
121
+ return { valid: true };
122
+ }
123
+
109
124
  function saveConfig(config) {
110
125
  fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
111
126
  try {
@@ -113,6 +128,10 @@ function saveConfig(config) {
113
128
  } catch {}
114
129
  }
115
130
 
131
+ function providerKeyFromBaseUrl(baseUrl) {
132
+ return Object.entries(PROVIDERS).find(([, provider]) => provider.baseUrl === baseUrl)?.[0];
133
+ }
134
+
116
135
  function resolveFastModel(provider, model) {
117
136
  if (/flash|turbo|haiku|air|lite/i.test(model)) return model;
118
137
  return provider?.fastModel || model;
@@ -145,7 +164,8 @@ function shellQuote(value) {
145
164
 
146
165
  // 构造完整的 clawai 环境变量块
147
166
  function buildEnvBlock(baseUrl, apiKey, model, fastModel) {
148
- const env = buildClaudeEnv({ baseUrl, apiKey, model, fastModel });
167
+ const provider = providerKeyFromBaseUrl(baseUrl);
168
+ const env = buildClaudeEnv({ provider, baseUrl, apiKey, model, fastModel });
149
169
  return [
150
170
  '',
151
171
  '# clawai-start',
@@ -224,7 +244,9 @@ module.exports = {
224
244
  writeEnvToZshrc,
225
245
  fetchModels,
226
246
  resetConfig,
247
+ validateConfig,
227
248
  resolveFastModel,
249
+ providerKeyFromBaseUrl,
228
250
  buildClaudeEnv,
229
251
  buildEnvBlock,
230
252
  classifyValidationStatus,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yingclaw",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "Claude Code × 国产大模型一键接入:DeepSeek、Qwen、MiniMax、GLM、MiMo",
5
5
  "main": "index.js",
6
6
  "bin": {