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 +43 -13
- package/lib/desktop.js +21 -10
- package/lib/panel.js +7 -3
- package/package.json +1 -1
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
|
-
|
|
87
|
+
_claudeInstalledCache = true;
|
|
86
88
|
} catch {
|
|
87
|
-
|
|
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(
|
|
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
|
|
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: '
|
|
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('
|
|
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(
|
|
718
|
-
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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' &&
|
|
27
|
-
|
|
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;
|