yingclaw 2.1.8 → 2.2.2

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
@@ -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 {
@@ -1087,6 +1112,10 @@ async function runMenu() {
1087
1112
  lastCheckResult = undefined;
1088
1113
  lastCheckedHash = null;
1089
1114
  }
1115
+ // 安装 Claude 后刷新检测缓存
1116
+ if (resolvedAction === 'install') {
1117
+ invalidateClaudeInstalledCache();
1118
+ }
1090
1119
 
1091
1120
  console.log();
1092
1121
  const next = await select({ loop: false,
package/lib/desktop.js CHANGED
@@ -231,16 +231,32 @@ function isDesktopConfigured(options = {}) {
231
231
  return meta.entries.some((entry) => entry && entry.name === YINGCLAW_ENTRY_NAME);
232
232
  }
233
233
 
234
- function buildClaudeDesktopOpenCommands(platform = process.platform) {
235
- if (platform !== 'darwin') return null;
234
+ function buildClaudeDesktopOpenCommands(platform = process.platform, options = {}) {
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
+ // 在 Node 里展开 LOCALAPPDATA,避免 cmd /c 解析带空格的中文路径出错
248
+ const localAppData = options.localAppData
249
+ || process.env.LOCALAPPDATA
250
+ || `${options.homeDir || os.homedir()}\\AppData\\Local`;
251
+ const claudeDir = `${localAppData}\\AnthropicClaude`;
252
+ // taskkill /T 连带杀子进程;start "" /D 切到 Claude 目录后启动 Claude.exe(Squirrel 标准安装位置)
253
+ return [
254
+ { command: 'taskkill', args: ['/IM', 'Claude.exe', '/F', '/T'], optional: true, waitAfter: 1500 },
255
+ { command: 'cmd', args: ['/c', 'start', '', '/D', claudeDir, 'Claude.exe'], optional: true, waitAfter: 800 },
256
+ ];
257
+ }
258
+
259
+ return null;
244
260
  }
245
261
 
246
262
  async function sleep(ms) {
@@ -249,7 +265,7 @@ async function sleep(ms) {
249
265
 
250
266
  async function openClaudeDesktop(options = {}) {
251
267
  const platform = options.platform || process.platform;
252
- const commands = buildClaudeDesktopOpenCommands(platform);
268
+ const commands = buildClaudeDesktopOpenCommands(platform, options);
253
269
  if (!commands) return { result: 'unsupported' };
254
270
 
255
271
  const runner = options.runner || spawnSync;
@@ -257,8 +273,8 @@ async function openClaudeDesktop(options = {}) {
257
273
  const timeoutMs = options.timeoutMs || 5000;
258
274
 
259
275
  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 });
276
+ for (const { command, args, optional, waitAfter, shell } of commands) {
277
+ const result = runner(command, args, { stdio: 'pipe', encoding: 'utf8', windowsHide: true, timeout: timeoutMs, shell });
262
278
  const stderr = (result.stderr || '').toString().trim();
263
279
  trace.push({ command, args, status: result.status, stderr });
264
280
 
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.8",
3
+ "version": "2.2.2",
4
4
  "description": "Claude Code × 国产大模型一键接入:DeepSeek、Kimi、Qwen、MiniMax、GLM、MiMo",
5
5
  "main": "index.js",
6
6
  "bin": {