yingclaw 2.1.7 → 2.2.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/bin/cli.js CHANGED
@@ -79,13 +79,20 @@ function getConfigValidationMessage(config) {
79
79
  return validation.valid ? null : validation.message;
80
80
  }
81
81
 
82
+ let _claudeInstalledCache;
82
83
  function isClaudeInstalled() {
84
+ if (_claudeInstalledCache !== undefined) return _claudeInstalledCache;
83
85
  try {
84
86
  execSync('claude --version', { stdio: 'pipe' });
85
- return true;
87
+ _claudeInstalledCache = true;
86
88
  } catch {
87
- return false;
89
+ _claudeInstalledCache = false;
88
90
  }
91
+ return _claudeInstalledCache;
92
+ }
93
+
94
+ function invalidateClaudeInstalledCache() {
95
+ _claudeInstalledCache = undefined;
89
96
  }
90
97
 
91
98
  function isValidUrl(value) {
@@ -131,7 +138,7 @@ async function offerDesktopSync(chalk, ora, config) {
131
138
  spinner.fail(chalk.red(`桌面配置同步失败: ${e.message}`));
132
139
  return;
133
140
  }
134
- if (process.platform === 'darwin') {
141
+ if (process.platform === 'darwin' || process.platform === 'win32') {
135
142
  const shouldOpen = await confirm({ message: '是否重启 Claude 桌面应用使新配置生效?', default: true });
136
143
  if (shouldOpen) {
137
144
  const openSpinner = ora('正在重启 Claude 桌面应用...').start();
@@ -139,7 +146,13 @@ async function offerDesktopSync(chalk, ora, config) {
139
146
  await openClaudeDesktop();
140
147
  openSpinner.succeed(chalk.green('Claude 桌面应用已重启'));
141
148
  } catch (e) {
142
- openSpinner.fail(chalk.red(`打开失败: ${e.message}`));
149
+ openSpinner.fail(chalk.red(`自动重启失败: ${e.message}`));
150
+ if (process.platform === 'win32') {
151
+ console.log(chalk.yellow('\n请手动操作(仅关闭窗口不够,进程还在系统托盘):'));
152
+ console.log(chalk.dim(' 1. 任务栏右下角找 Claude 图标 → 右键 → 退出'));
153
+ console.log(chalk.dim(' 2. 或在任务管理器中结束所有 Claude.exe 进程'));
154
+ console.log(chalk.dim(' 3. 然后重新打开 Claude'));
155
+ }
143
156
  }
144
157
  }
145
158
  }
@@ -334,6 +347,7 @@ async function runConfigFlow({ writeCodeEnv = false } = {}) {
334
347
  } else if (step === 'apikey') {
335
348
  const k = await input({
336
349
  message: chalk.cyan(`${provider.name} API Key(输入 b 返回上一步)`),
350
+ default: apiKey || undefined,
337
351
  transformer: (v) => v && v !== 'b' ? chalk.dim('•'.repeat(v.length)) : v,
338
352
  validate: (v) => v.trim().length > 0 ? true : 'API Key 不能为空',
339
353
  });
@@ -397,6 +411,8 @@ async function runConfigFlow({ writeCodeEnv = false } = {}) {
397
411
  nextStep,
398
412
  { padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'green', margin: { top: 1, bottom: 1 } }
399
413
  ));
414
+
415
+ await offerDesktopSync(chalk, ora, cfg);
400
416
  }
401
417
 
402
418
  program
@@ -415,7 +431,7 @@ program
415
431
  console.log(await getBanner());
416
432
 
417
433
  try {
418
- const ver = execSync('claude --version 2>/dev/null', { encoding: 'utf8' }).trim();
434
+ const ver = execSync('claude --version', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
419
435
  console.log(chalk.green(`\n✔ Claude Code 已安装:${ver}\n`));
420
436
  const yes = await confirm({ message: '是否重新安装/更新?', default: false });
421
437
  if (!yes) return;
@@ -435,8 +451,8 @@ program
435
451
 
436
452
  console.log(chalk.dim('\n安装中,实时输出:\n'));
437
453
 
438
- // 实时输出安装日志
439
- const result = spawnSync(installCommand.command, installCommand.args, { stdio: 'inherit' });
454
+ // 实时输出安装日志(Windows 下 npm 是 npm.cmd,需要 shell: true 才能找到)
455
+ const result = spawnSync(installCommand.command, installCommand.args, { stdio: 'inherit', shell: process.platform === 'win32' });
440
456
 
441
457
  if (result.status === 0) {
442
458
  console.log(chalk.green('\n✔ Claude Code 安装成功!'));
@@ -614,6 +630,8 @@ program
614
630
  validate: (v) => v.trim().length > 0 ? true : 'API Key 不能为空',
615
631
  });
616
632
  apiKey = apiKey.trim();
633
+ } else {
634
+ console.log(chalk.yellow('⚠ 沿用旧 Key 通常无法访问新厂商,模型列表可能拉取失败'));
617
635
  }
618
636
  }
619
637
 
@@ -706,16 +724,23 @@ program
706
724
  { padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'cyan', margin: { top: 1, bottom: 1 } }
707
725
  ));
708
726
 
709
- if (process.platform === 'darwin') {
710
- const shouldOpen = await confirm({ message: '是否现在打开 Claude 桌面应用?', default: true });
727
+ if (process.platform === 'darwin' || process.platform === 'win32') {
728
+ const shouldOpen = await confirm({ message: '是否现在重启 Claude 桌面应用?', default: true });
711
729
  if (shouldOpen) {
712
- const openSpinner = ora('正在打开 Claude 桌面应用...').start();
730
+ const openSpinner = ora('正在重启 Claude 桌面应用...').start();
713
731
  try {
714
732
  await openClaudeDesktop();
715
733
  openSpinner.succeed(chalk.green('Claude 桌面应用已重新打开(旧实例已退出,新配置生效)'));
716
734
  } catch (e) {
717
- openSpinner.fail(chalk.red(`打开失败: ${e.message}`));
718
- console.log(chalk.dim(getDesktopOpenHint()));
735
+ openSpinner.fail(chalk.red(`自动重启失败: ${e.message}`));
736
+ if (process.platform === 'win32') {
737
+ console.log(chalk.yellow('\n请手动操作(仅关闭窗口不够,进程还在系统托盘):'));
738
+ console.log(chalk.dim(' 1. 任务栏右下角找 Claude 图标 → 右键 → 退出'));
739
+ console.log(chalk.dim(' 2. 或在任务管理器中结束所有 Claude.exe 进程'));
740
+ console.log(chalk.dim(' 3. 然后重新打开 Claude'));
741
+ } else {
742
+ console.log(chalk.dim(getDesktopOpenHint()));
743
+ }
719
744
  }
720
745
  }
721
746
  } else {
@@ -870,7 +895,7 @@ program
870
895
  const upgradeCmd = { command: 'npm', args: upgradeArgs };
871
896
 
872
897
  console.log(chalk.dim('\n升级中...\n'));
873
- const result = spawnSync(upgradeCmd.command, upgradeCmd.args, { stdio: 'inherit' });
898
+ const result = spawnSync(upgradeCmd.command, upgradeCmd.args, { stdio: 'inherit', shell: process.platform === 'win32' });
874
899
 
875
900
  if (result.status === 0) {
876
901
  console.log(boxen(
@@ -1051,6 +1076,7 @@ async function runMenu() {
1051
1076
  const child = spawn('claude', [], {
1052
1077
  stdio: 'inherit',
1053
1078
  env: { ...process.env, ...buildClaudeEnv(cfg) },
1079
+ shell: process.platform === 'win32',
1054
1080
  });
1055
1081
  child.on('error', () => {
1056
1082
  console.log(chalk.yellow('\nClaude Code 未找到,请先选择"安装 Claude Code"'));
@@ -1086,6 +1112,10 @@ async function runMenu() {
1086
1112
  lastCheckResult = undefined;
1087
1113
  lastCheckedHash = null;
1088
1114
  }
1115
+ // 安装 Claude 后刷新检测缓存
1116
+ if (resolvedAction === 'install') {
1117
+ invalidateClaudeInstalledCache();
1118
+ }
1089
1119
 
1090
1120
  console.log();
1091
1121
  const next = await select({ loop: false,
package/lib/desktop.js CHANGED
@@ -232,15 +232,26 @@ function isDesktopConfigured(options = {}) {
232
232
  }
233
233
 
234
234
  function buildClaudeDesktopOpenCommands(platform = process.platform) {
235
- if (platform !== 'darwin') return null;
236
235
  // 必须先完全退出 Claude,新配置只在启动时读取一次
237
- return [
238
- { command: 'osascript', args: ['-e', 'tell application "Claude" to quit'], optional: true, waitAfter: 800 },
239
- { command: 'pkill', args: ['-TERM', '-x', 'Claude'], optional: true, waitAfter: 500 },
240
- { command: 'pkill', args: ['-KILL', '-x', 'Claude'], optional: true, waitAfter: 800 },
241
- { command: 'open', args: ['-a', 'Claude'], waitAfter: 600 },
242
- { command: 'osascript', args: ['-e', 'tell application "Claude" to activate'], optional: true },
243
- ];
236
+ if (platform === 'darwin') {
237
+ return [
238
+ { command: 'osascript', args: ['-e', 'tell application "Claude" to quit'], optional: true, waitAfter: 800 },
239
+ { command: 'pkill', args: ['-TERM', '-x', 'Claude'], optional: true, waitAfter: 500 },
240
+ { command: 'pkill', args: ['-KILL', '-x', 'Claude'], optional: true, waitAfter: 800 },
241
+ { command: 'open', args: ['-a', 'Claude'], waitAfter: 600 },
242
+ { command: 'osascript', args: ['-e', 'tell application "Claude" to activate'], optional: true },
243
+ ];
244
+ }
245
+
246
+ if (platform === 'win32') {
247
+ // taskkill /T 也连带杀掉子进程;start "" 找已注册的 Claude.exe
248
+ return [
249
+ { command: 'taskkill', args: ['/IM', 'Claude.exe', '/F', '/T'], optional: true, waitAfter: 1200, shell: true },
250
+ { command: 'cmd', args: ['/c', 'start', '""', '/B', 'claude:'], optional: true, waitAfter: 600, shell: true },
251
+ ];
252
+ }
253
+
254
+ return null;
244
255
  }
245
256
 
246
257
  async function sleep(ms) {
@@ -257,8 +268,8 @@ async function openClaudeDesktop(options = {}) {
257
268
  const timeoutMs = options.timeoutMs || 5000;
258
269
 
259
270
  const trace = [];
260
- for (const { command, args, optional, waitAfter } of commands) {
261
- const result = runner(command, args, { stdio: 'pipe', encoding: 'utf8', windowsHide: true, timeout: timeoutMs });
271
+ for (const { command, args, optional, waitAfter, shell } of commands) {
272
+ const result = runner(command, args, { stdio: 'pipe', encoding: 'utf8', windowsHide: true, timeout: timeoutMs, shell });
262
273
  const stderr = (result.stderr || '').toString().trim();
263
274
  trace.push({ command, args, status: result.status, stderr });
264
275
 
package/lib/panel.js CHANGED
@@ -23,8 +23,12 @@ function buildStatusView(config, options = {}) {
23
23
  const envActive = isEnvActive(config, env);
24
24
  const warnings = [];
25
25
 
26
- if (config.provider === 'deepseek' && config.model === 'deepseek-v4-pro') {
27
- warnings.push('检测到旧 DeepSeek 模型名,建议运行 claw switch 更新到 deepseek-v4-pro[1m]');
26
+ if (config.provider === 'deepseek' && (
27
+ config.model === 'deepseek-v4-pro' ||
28
+ config.model === 'deepseek-v4-flash' ||
29
+ config.fastModel === 'deepseek-v4-flash'
30
+ )) {
31
+ warnings.push('检测到旧 DeepSeek 模型名,建议运行 claw switch 更新到 [1m] 长上下文版本');
28
32
  }
29
33
 
30
34
  return {
@@ -63,7 +67,7 @@ function buildMenuStatusLines(view, options = {}) {
63
67
  lines.push(`主模型 ${view.mainModel} · 快速模型 ${view.fastModel}`);
64
68
 
65
69
  if (view.warnings.some((warning) => warning.includes('旧 DeepSeek 模型名'))) {
66
- lines.push('旧模型名:选择下方“切换厂商或模型”更新');
70
+ lines.push('旧模型名:选择下方"切换厂商或模型"更新到 [1m]');
67
71
  }
68
72
 
69
73
  return lines;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yingclaw",
3
- "version": "2.1.7",
3
+ "version": "2.2.0",
4
4
  "description": "Claude Code × 国产大模型一键接入:DeepSeek、Kimi、Qwen、MiniMax、GLM、MiMo",
5
5
  "main": "index.js",
6
6
  "bin": {