yingclaw 1.5.1 → 1.6.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.
package/README.md CHANGED
@@ -50,7 +50,19 @@ claw status # 查看当前配置,验证 Key 是否有效
50
50
 
51
51
  ## 原理
52
52
 
53
- 各厂商均原生支持 Anthropic API 格式,只需设置 `ANTHROPIC_BASE_URL` `ANTHROPIC_API_KEY` 两个环境变量即可。本工具自动完成配置,无需手动修改任何文件。
53
+ 各厂商均原生支持 Anthropic API 格式。本工具会自动写入 Claude Code 所需的环境变量,包括:
54
+
55
+ - `ANTHROPIC_BASE_URL`
56
+ - `ANTHROPIC_AUTH_TOKEN`
57
+ - `ANTHROPIC_API_KEY`
58
+ - `ANTHROPIC_MODEL`
59
+ - `ANTHROPIC_DEFAULT_OPUS_MODEL`
60
+ - `ANTHROPIC_DEFAULT_SONNET_MODEL`
61
+ - `ANTHROPIC_DEFAULT_HAIKU_MODEL`
62
+ - `CLAUDE_CODE_SUBAGENT_MODEL`
63
+ - `CLAUDE_CODE_EFFORT_LEVEL`
64
+
65
+ 以 DeepSeek 为例,主模型默认使用 `deepseek-v4-pro[1m]`,Haiku/Subagent 快速模型使用 `deepseek-v4-flash`。如果在线模型列表获取失败,会回退到内置默认列表。
54
66
 
55
67
  ## License
56
68
 
package/bin/cli.js CHANGED
@@ -2,10 +2,21 @@
2
2
 
3
3
  const { Command } = require('commander');
4
4
  const { select, input, confirm } = require('@inquirer/prompts');
5
- const { loadConfig, saveConfig, writeEnvToZshrc, fetchModels, PROVIDERS } = require('../lib/config');
5
+ const {
6
+ loadConfig,
7
+ saveConfig,
8
+ writeEnvToZshrc,
9
+ fetchModels,
10
+ resetConfig,
11
+ resolveFastModel,
12
+ buildClaudeEnv,
13
+ classifyValidationStatus,
14
+ PROVIDERS,
15
+ } = require('../lib/config');
6
16
  const { execSync, spawn, spawnSync } = require('child_process');
7
17
  const https = require('https');
8
18
  const pkg = require('../package.json');
19
+ const { buildStatusView } = require('../lib/panel');
9
20
 
10
21
  const program = new Command();
11
22
 
@@ -14,8 +25,9 @@ async function getBanner() {
14
25
  const figlet = require('figlet');
15
26
  const boxen = (await import('boxen')).default;
16
27
  const title = figlet.textSync('claw', { font: 'Standard', horizontalLayout: 'fitted' });
28
+ const subtitle = chalk.dim('Claude Code × 国产大模型 一键接入') + ' ' + chalk.cyan(`v${pkg.version}`);
17
29
  return boxen(
18
- chalk.cyan.bold(title) + '\n' + chalk.dim('Claude Code × 国产大模型 一键接入'),
30
+ chalk.cyan.bold(title) + '\n' + subtitle,
19
31
  { padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'cyan', margin: { top: 1, bottom: 0 } }
20
32
  );
21
33
  }
@@ -45,9 +57,7 @@ async function validateKey(config) {
45
57
  'content-length': body.length,
46
58
  },
47
59
  }, (res) => {
48
- // 401/403 = Key 无效;2xx/400/500 都说明 Key 被识别了
49
- if (res.statusCode === 401 || res.statusCode === 403) resolve(false);
50
- else resolve(true);
60
+ resolve(classifyValidationStatus(res.statusCode));
51
61
  });
52
62
  req.on('error', () => resolve(null));
53
63
  req.on('timeout', () => { req.destroy(); resolve(null); });
@@ -56,6 +66,15 @@ async function validateKey(config) {
56
66
  });
57
67
  }
58
68
 
69
+ function isClaudeInstalled() {
70
+ try {
71
+ execSync('claude --version', { stdio: 'pipe' });
72
+ return true;
73
+ } catch {
74
+ return false;
75
+ }
76
+ }
77
+
59
78
  async function showStatus() {
60
79
  const chalk = (await import('chalk')).default;
61
80
  const boxen = (await import('boxen')).default;
@@ -67,7 +86,6 @@ async function showStatus() {
67
86
  return;
68
87
  }
69
88
 
70
- const provider = PROVIDERS[config.provider];
71
89
  const spinner = ora('验证 API Key...').start();
72
90
  const valid = await validateKey(config);
73
91
 
@@ -75,12 +93,34 @@ async function showStatus() {
75
93
  else if (valid === false) spinner.fail('API Key 无效或已过期');
76
94
  else spinner.warn('网络异常,无法验证');
77
95
 
78
- const lines = [
79
- `${chalk.dim('厂商 ')} ${chalk.white.bold(provider?.name || config.provider)}`,
80
- `${chalk.dim('模型 ')} ${chalk.yellow(config.model)}`,
81
- `${chalk.dim('API Key ')} ${chalk.dim(config.apiKey.slice(0, 10) + '...')} ${valid === true ? chalk.green('✔') : valid === false ? chalk.red('✘') : chalk.yellow('?')}`,
82
- `${chalk.dim('Base URL')} ${chalk.cyan(config.baseUrl)}`,
83
- ];
96
+ const view = buildStatusView(config, {
97
+ apiStatus: valid,
98
+ claudeInstalled: isClaudeInstalled(),
99
+ env: process.env,
100
+ });
101
+
102
+ const lines = view.lines.map(({ label, value }) => {
103
+ const coloredValue = label === '厂商'
104
+ ? chalk.white.bold(value)
105
+ : label.includes('模型')
106
+ ? chalk.yellow(value)
107
+ : label === 'Base URL'
108
+ ? chalk.cyan(value)
109
+ : label === '当前终端' && value === '未生效'
110
+ ? chalk.yellow(value)
111
+ : value;
112
+ return `${chalk.dim(label + ':')} ${coloredValue}`;
113
+ });
114
+
115
+ for (const warning of view.warnings) {
116
+ if (warning.includes('建议运行')) {
117
+ const [summary, action] = warning.split(',建议运行 ');
118
+ lines.push(`${chalk.yellow('提示:')} ${chalk.yellow(summary)}`);
119
+ lines.push(`${chalk.yellow('建议:')} ${chalk.yellow(`运行 ${action}`)}`);
120
+ } else {
121
+ lines.push(`${chalk.yellow('提示:')} ${chalk.yellow(warning)}`);
122
+ }
123
+ }
84
124
 
85
125
  console.log(boxen(lines.join('\n'), {
86
126
  title: chalk.bold('当前配置'),
@@ -237,9 +277,10 @@ program
237
277
  const spinner = ora('写入配置...').start();
238
278
  let result, file;
239
279
  try {
240
- const cfg = { provider: providerKey, model, apiKey, baseUrl: provider.baseUrl };
280
+ const fastModel = resolveFastModel(provider, model);
281
+ const cfg = { provider: providerKey, model, fastModel, apiKey, baseUrl: provider.baseUrl };
241
282
  saveConfig(cfg);
242
- ({ result, file } = writeEnvToZshrc(provider.baseUrl, apiKey));
283
+ ({ result, file } = writeEnvToZshrc(provider.baseUrl, apiKey, model, fastModel));
243
284
  spinner.succeed(chalk.green(result === 'updated' ? `环境变量已更新 → ${file}` : `环境变量已写入 → ${file}`));
244
285
  } catch (e) {
245
286
  spinner.fail(chalk.red(`写入失败: ${e.message}`));
@@ -261,7 +302,7 @@ program
261
302
 
262
303
  spawn('claude', [], {
263
304
  stdio: 'inherit',
264
- env: { ...process.env, ANTHROPIC_BASE_URL: provider.baseUrl, ANTHROPIC_API_KEY: apiKey },
305
+ env: { ...process.env, ...buildClaudeEnv({ provider: providerKey, baseUrl: provider.baseUrl, apiKey, model, fastModel: resolveFastModel(provider, model) }) },
265
306
  }).on('error', () => {
266
307
  console.log(chalk.yellow('\nClaude Code 未找到,请先运行: claw install-claude'));
267
308
  });
@@ -329,9 +370,10 @@ program
329
370
  if (model === '__BACK__') return;
330
371
 
331
372
  const spinner = ora('切换中...').start();
332
- const newConfig = { ...config, provider: providerKey, model, baseUrl: provider.baseUrl, apiKey };
373
+ const fastModel = resolveFastModel(provider, model);
374
+ const newConfig = { ...config, provider: providerKey, model, fastModel, baseUrl: provider.baseUrl, apiKey };
333
375
  saveConfig(newConfig);
334
- const { file } = writeEnvToZshrc(provider.baseUrl, apiKey);
376
+ const { file } = writeEnvToZshrc(provider.baseUrl, apiKey, model, fastModel);
335
377
  await new Promise(r => setTimeout(r, 300));
336
378
  spinner.succeed(chalk.green(`已切换至 ${provider.name} · ${model}`));
337
379
  console.log(chalk.dim(`运行 source ${file} 生效,或重新开一个终端`));
@@ -342,19 +384,57 @@ program
342
384
  .description('查看当前配置和 Key 有效性')
343
385
  .action(showStatus);
344
386
 
387
+ program
388
+ .command('reset')
389
+ .description('恢复默认(清除所有 clawai 配置)')
390
+ .action(async () => {
391
+ const chalk = (await import('chalk')).default;
392
+ const ora = (await import('ora')).default;
393
+ const boxen = (await import('boxen')).default;
394
+
395
+ console.log(await getBanner());
396
+
397
+ const yes = await confirm({
398
+ message: chalk.red('确定要清除所有 clawai 配置吗?此操作不可撤销'),
399
+ default: false,
400
+ });
401
+ if (!yes) {
402
+ console.log(chalk.dim('已取消'));
403
+ return;
404
+ }
405
+
406
+ const spinner = ora('清除中...').start();
407
+ const cleared = resetConfig();
408
+ await new Promise(r => setTimeout(r, 300));
409
+
410
+ if (cleared.length === 0) {
411
+ spinner.warn(chalk.yellow('没有找到任何配置,无需清除'));
412
+ } else {
413
+ spinner.succeed(chalk.green('已恢复默认'));
414
+ console.log(boxen(
415
+ chalk.bold('已清除以下文件中的 clawai 配置:\n\n') +
416
+ cleared.map(f => chalk.cyan(' • ' + f)).join('\n') +
417
+ '\n\n' + chalk.dim('注:当前终端的环境变量还在内存中,重开终端或 unset 才彻底清除'),
418
+ { padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'green', margin: { top: 1, bottom: 1 } }
419
+ ));
420
+ }
421
+ });
422
+
345
423
  async function renderStatusBar(apiStatus) {
346
424
  const chalk = (await import('chalk')).default;
347
425
  const config = loadConfig();
348
- const claudeInstalled = (() => {
349
- try { execSync('claude --version', { stdio: 'pipe' }); return true; } catch { return false; }
350
- })();
426
+ const claudeInstalled = isClaudeInstalled();
351
427
 
352
428
  const claudeIcon = claudeInstalled ? chalk.green('●') : chalk.red('●');
353
429
  const claudeText = chalk.dim('Claude');
354
430
 
355
431
  let cfgPart;
356
432
  if (config) {
357
- const provName = PROVIDERS[config.provider]?.name || config.provider;
433
+ const view = buildStatusView(config, {
434
+ apiStatus,
435
+ claudeInstalled,
436
+ env: process.env,
437
+ });
358
438
  let dot;
359
439
  if (apiStatus === true) dot = chalk.green('●');
360
440
  else if (apiStatus === false) dot = chalk.red('●');
@@ -364,7 +444,9 @@ async function renderStatusBar(apiStatus) {
364
444
  : apiStatus === false ? chalk.red(' API ✘')
365
445
  : apiStatus === null ? chalk.yellow(' 网络异常')
366
446
  : '';
367
- cfgPart = `${dot} ${chalk.white(provName)}${chalk.dim(' · ')}${chalk.yellow(config.model)}${apiTag}`;
447
+ const envTag = view.envActive ? chalk.green(' env ') : chalk.yellow(' env 未生效');
448
+ const legacyTag = view.warnings.length > 0 ? chalk.yellow(' 旧模型') : '';
449
+ cfgPart = `${dot} ${chalk.white(view.providerName)}${apiTag}${envTag}${legacyTag}\n ${chalk.dim('主 ')}${chalk.yellow(view.mainModel)}${chalk.dim(' 快 ')}${chalk.yellow(view.fastModel)}`;
368
450
  } else {
369
451
  cfgPart = chalk.red('●') + ' ' + chalk.dim('未配置');
370
452
  }
@@ -399,9 +481,10 @@ async function runMenu() {
399
481
  { name: '🤖 启动 Claude Code', value: 'launch', disabled: !config && '需先完成配置' },
400
482
  { name: '📦 安装 Claude Code', value: 'install' },
401
483
  { name: config ? '⚙️ 重新配置(输入新的 API Key)' : '⚙️ 首次配置 API Key 和模型', value: 'setup' },
402
- { name: '🔄 切换厂商/模型(保留当前 Key)', value: 'switch', disabled: !config && '需先完成配置' },
484
+ { name: '🔄 切换厂商或模型', value: 'switch', disabled: !config && '需先完成配置' },
403
485
  { name: '📊 查看当前配置', value: 'status', disabled: !config && '需先完成配置' },
404
486
  { name: '🔁 重新检测 API', value: 'recheck', disabled: !config && '需先完成配置' },
487
+ { name: '🗑 恢复默认(清除所有配置)', value: 'reset', disabled: !config && '没有可清除的配置' },
405
488
  { name: '退出', value: 'exit' },
406
489
  ],
407
490
  });
@@ -420,7 +503,7 @@ async function runMenu() {
420
503
  await new Promise((resolve) => {
421
504
  const child = spawn('claude', [], {
422
505
  stdio: 'inherit',
423
- env: { ...process.env, ANTHROPIC_BASE_URL: cfg.baseUrl, ANTHROPIC_API_KEY: cfg.apiKey },
506
+ env: { ...process.env, ...buildClaudeEnv(cfg) },
424
507
  });
425
508
  child.on('error', () => {
426
509
  console.log(chalk.yellow('\nClaude Code 未找到,请先选择"安装 Claude Code"'));
@@ -436,6 +519,7 @@ async function runMenu() {
436
519
  setup: 'setup',
437
520
  switch: 'switch',
438
521
  status: 'status',
522
+ reset: 'reset',
439
523
  };
440
524
 
441
525
  // 执行子命令
package/lib/config.js CHANGED
@@ -10,9 +10,10 @@ const PROVIDERS = {
10
10
  name: 'DeepSeek',
11
11
  baseUrl: 'https://api.deepseek.com/anthropic',
12
12
  modelsUrl: 'https://api.deepseek.com/v1/models',
13
+ fastModel: 'deepseek-v4-flash',
13
14
  models: [
14
15
  { name: 'DeepSeek V4 Flash(快速)', value: 'deepseek-v4-flash' },
15
- { name: 'DeepSeek V4 Pro(强力)', value: 'deepseek-v4-pro' },
16
+ { name: 'DeepSeek V4 Pro(强力)', value: 'deepseek-v4-pro[1m]' },
16
17
  ],
17
18
  },
18
19
  qwen: {
@@ -107,12 +108,63 @@ function loadConfig() {
107
108
 
108
109
  function saveConfig(config) {
109
110
  fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
111
+ try {
112
+ fs.chmodSync(CONFIG_FILE, 0o600);
113
+ } catch {}
114
+ }
115
+
116
+ function resolveFastModel(provider, model) {
117
+ if (/flash|turbo|haiku|air|lite/i.test(model)) return model;
118
+ return provider?.fastModel || model;
119
+ }
120
+
121
+ function buildClaudeEnv({ provider, baseUrl, apiKey, model, fastModel }) {
122
+ const resolvedFastModel = fastModel || resolveFastModel(PROVIDERS[provider], model);
123
+ return {
124
+ ANTHROPIC_BASE_URL: baseUrl,
125
+ ANTHROPIC_AUTH_TOKEN: apiKey,
126
+ ANTHROPIC_API_KEY: apiKey,
127
+ ANTHROPIC_MODEL: model,
128
+ ANTHROPIC_DEFAULT_OPUS_MODEL: model,
129
+ ANTHROPIC_DEFAULT_SONNET_MODEL: model,
130
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: resolvedFastModel,
131
+ CLAUDE_CODE_SUBAGENT_MODEL: resolvedFastModel,
132
+ CLAUDE_CODE_EFFORT_LEVEL: 'max',
133
+ };
134
+ }
135
+
136
+ function classifyValidationStatus(statusCode) {
137
+ if (statusCode >= 200 && statusCode < 300) return true;
138
+ if (statusCode === 401 || statusCode === 403) return false;
139
+ return null;
140
+ }
141
+
142
+ function shellQuote(value) {
143
+ return `'${String(value).replace(/'/g, `'\\''`)}'`;
144
+ }
145
+
146
+ // 构造完整的 clawai 环境变量块
147
+ function buildEnvBlock(baseUrl, apiKey, model, fastModel) {
148
+ const env = buildClaudeEnv({ baseUrl, apiKey, model, fastModel });
149
+ return [
150
+ '',
151
+ '# clawai-start',
152
+ `export ANTHROPIC_BASE_URL=${shellQuote(env.ANTHROPIC_BASE_URL)}`,
153
+ `export ANTHROPIC_AUTH_TOKEN=${shellQuote(env.ANTHROPIC_AUTH_TOKEN)}`,
154
+ `export ANTHROPIC_API_KEY=${shellQuote(env.ANTHROPIC_API_KEY)}`,
155
+ `export ANTHROPIC_MODEL=${shellQuote(env.ANTHROPIC_MODEL)}`,
156
+ `export ANTHROPIC_DEFAULT_OPUS_MODEL=${shellQuote(env.ANTHROPIC_DEFAULT_OPUS_MODEL)}`,
157
+ `export ANTHROPIC_DEFAULT_SONNET_MODEL=${shellQuote(env.ANTHROPIC_DEFAULT_SONNET_MODEL)}`,
158
+ `export ANTHROPIC_DEFAULT_HAIKU_MODEL=${shellQuote(env.ANTHROPIC_DEFAULT_HAIKU_MODEL)}`,
159
+ `export CLAUDE_CODE_SUBAGENT_MODEL=${shellQuote(env.CLAUDE_CODE_SUBAGENT_MODEL)}`,
160
+ `export CLAUDE_CODE_EFFORT_LEVEL=${shellQuote(env.CLAUDE_CODE_EFFORT_LEVEL)}`,
161
+ '# clawai-end',
162
+ '',
163
+ ].join('\n');
110
164
  }
111
165
 
112
166
  // 写入或更新 shell 配置文件中的环境变量块
113
- function writeEnvToZshrc(baseUrl, apiKey) {
114
- // 检测用户 shell,自动选配置文件
115
- // macOS bash 默认读 ~/.bash_profile(登录 shell),Linux 读 ~/.bashrc
167
+ function writeEnvToZshrc(baseUrl, apiKey, model, fastModel) {
116
168
  const shell = process.env.SHELL || '';
117
169
  let rcFile;
118
170
  if (shell.includes('bash')) {
@@ -123,22 +175,59 @@ function writeEnvToZshrc(baseUrl, apiKey) {
123
175
  rcFile = path.join(os.homedir(), '.zshrc');
124
176
  }
125
177
 
126
- // Key 加引号,避免特殊字符(& = 空格)破坏 shell 语法
127
- const safeKey = `"${apiKey.replace(/"/g, '\\"')}"`;
128
- const block = `\n# clawai\nexport ANTHROPIC_BASE_URL=${baseUrl}\nexport ANTHROPIC_API_KEY=${safeKey}\n`;
178
+ const block = buildEnvBlock(baseUrl, apiKey, model, fastModel);
129
179
  const current = fs.existsSync(rcFile) ? fs.readFileSync(rcFile, 'utf8') : '';
130
180
 
131
- if (current.includes('# clawai')) {
132
- const updated = current.replace(
133
- /# clawai\nexport ANTHROPIC_BASE_URL=[^\n]*\nexport ANTHROPIC_API_KEY=[^\n]*/,
134
- `# clawai\nexport ANTHROPIC_BASE_URL=${baseUrl}\nexport ANTHROPIC_API_KEY=${safeKey}`
135
- );
136
- fs.writeFileSync(rcFile, updated);
137
- return { result: 'updated', file: rcFile };
138
- } else {
139
- fs.appendFileSync(rcFile, block);
140
- return { result: 'added', file: rcFile };
181
+ // 兼容旧版(# clawai 单行块)和新版(# clawai-start...# clawai-end 多行块)
182
+ const cleaned = current
183
+ .replace(/\n?# clawai-start[\s\S]*?# clawai-end\n?/g, '')
184
+ .replace(/\n?# clawai\nexport ANTHROPIC_BASE_URL=[^\n]*\nexport ANTHROPIC_API_KEY=[^\n]*\n?/g, '');
185
+
186
+ fs.writeFileSync(rcFile, cleaned + block);
187
+ return { result: cleaned !== current ? 'updated' : 'added', file: rcFile };
188
+ }
189
+
190
+ // 清除所有 clawai 配置(配置文件 + shell 环境变量块)
191
+ function resetConfig() {
192
+ const cleared = [];
193
+
194
+ // 删配置文件
195
+ if (fs.existsSync(CONFIG_FILE)) {
196
+ fs.unlinkSync(CONFIG_FILE);
197
+ cleared.push(CONFIG_FILE);
198
+ }
199
+
200
+ // 清理所有可能的 rc 文件中的 clawai 块
201
+ const rcFiles = [
202
+ path.join(os.homedir(), '.zshrc'),
203
+ path.join(os.homedir(), '.bashrc'),
204
+ path.join(os.homedir(), '.bash_profile'),
205
+ ];
206
+ for (const f of rcFiles) {
207
+ if (!fs.existsSync(f)) continue;
208
+ const content = fs.readFileSync(f, 'utf8');
209
+ if (!content.includes('# clawai')) continue;
210
+ const cleaned = content
211
+ .replace(/\n?# clawai-start[\s\S]*?# clawai-end\n?/g, '')
212
+ .replace(/\n?# clawai\nexport ANTHROPIC_BASE_URL=[^\n]*\nexport ANTHROPIC_API_KEY=[^\n]*\n?/g, '');
213
+ if (cleaned === content) continue;
214
+ fs.writeFileSync(f, cleaned);
215
+ cleared.push(f);
141
216
  }
217
+
218
+ return cleared;
142
219
  }
143
220
 
144
- module.exports = { loadConfig, saveConfig, writeEnvToZshrc, fetchModels, PROVIDERS, CONFIG_FILE };
221
+ module.exports = {
222
+ loadConfig,
223
+ saveConfig,
224
+ writeEnvToZshrc,
225
+ fetchModels,
226
+ resetConfig,
227
+ resolveFastModel,
228
+ buildClaudeEnv,
229
+ buildEnvBlock,
230
+ classifyValidationStatus,
231
+ PROVIDERS,
232
+ CONFIG_FILE,
233
+ };
package/lib/panel.js ADDED
@@ -0,0 +1,49 @@
1
+ const { buildClaudeEnv, PROVIDERS } = require('./config');
2
+
3
+ function apiStatusText(apiStatus) {
4
+ if (apiStatus === true) return 'API 正常';
5
+ if (apiStatus === false) return 'API Key 无效';
6
+ if (apiStatus === null) return '网络/服务异常';
7
+ return '未检测';
8
+ }
9
+
10
+ function isEnvActive(config, env) {
11
+ const expected = buildClaudeEnv(config);
12
+ return Object.entries(expected).every(([key, value]) => env[key] === value);
13
+ }
14
+
15
+ function buildStatusView(config, options = {}) {
16
+ const provider = PROVIDERS[config.provider];
17
+ const providerName = provider?.name || config.provider;
18
+ const claudeInstalled = options.claudeInstalled === true;
19
+ const env = options.env || {};
20
+ const expectedEnv = buildClaudeEnv(config);
21
+ const mainModel = expectedEnv.ANTHROPIC_MODEL;
22
+ const fastModel = expectedEnv.CLAUDE_CODE_SUBAGENT_MODEL;
23
+ const envActive = isEnvActive(config, env);
24
+ const warnings = [];
25
+
26
+ if (config.provider === 'deepseek' && config.model === 'deepseek-v4-pro') {
27
+ warnings.push('检测到旧 DeepSeek 模型名,建议运行 claw switch 更新到 deepseek-v4-pro[1m]');
28
+ }
29
+
30
+ return {
31
+ providerName,
32
+ mainModel,
33
+ fastModel,
34
+ envActive,
35
+ warnings,
36
+ lines: [
37
+ { label: '厂商', value: providerName },
38
+ { label: '主模型', value: mainModel },
39
+ { label: '快速模型', value: fastModel },
40
+ { label: 'API Key', value: '已保存' },
41
+ { label: 'API 状态', value: apiStatusText(options.apiStatus) },
42
+ { label: 'Claude Code', value: claudeInstalled ? '已安装' : '未检测到' },
43
+ { label: '当前终端', value: envActive ? '已生效' : '未生效' },
44
+ { label: 'Base URL', value: config.baseUrl },
45
+ ],
46
+ };
47
+ }
48
+
49
+ module.exports = { buildStatusView, apiStatusText, isEnvActive };
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "yingclaw",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Claude Code × 国产大模型一键接入:DeepSeek、Qwen、MiniMax、GLM、MiMo",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "claw": "bin/cli.js"
8
8
  },
9
9
  "scripts": {
10
- "start": "node bin/cli.js"
10
+ "start": "node bin/cli.js",
11
+ "test": "node --test"
11
12
  },
12
13
  "keywords": [
13
14
  "claude",