yingclaw 2.1.6 → 2.1.8
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 +16 -6
- package/lib/config.js +1 -0
- package/lib/desktop.js +37 -19
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -415,7 +415,7 @@ program
|
|
|
415
415
|
console.log(await getBanner());
|
|
416
416
|
|
|
417
417
|
try {
|
|
418
|
-
const ver = execSync('claude --version
|
|
418
|
+
const ver = execSync('claude --version', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
419
419
|
console.log(chalk.green(`\n✔ Claude Code 已安装:${ver}\n`));
|
|
420
420
|
const yes = await confirm({ message: '是否重新安装/更新?', default: false });
|
|
421
421
|
if (!yes) return;
|
|
@@ -435,8 +435,8 @@ program
|
|
|
435
435
|
|
|
436
436
|
console.log(chalk.dim('\n安装中,实时输出:\n'));
|
|
437
437
|
|
|
438
|
-
//
|
|
439
|
-
const result = spawnSync(installCommand.command, installCommand.args, { stdio: 'inherit' });
|
|
438
|
+
// 实时输出安装日志(Windows 下 npm 是 npm.cmd,需要 shell: true 才能找到)
|
|
439
|
+
const result = spawnSync(installCommand.command, installCommand.args, { stdio: 'inherit', shell: process.platform === 'win32' });
|
|
440
440
|
|
|
441
441
|
if (result.status === 0) {
|
|
442
442
|
console.log(chalk.green('\n✔ Claude Code 安装成功!'));
|
|
@@ -857,11 +857,20 @@ program
|
|
|
857
857
|
return;
|
|
858
858
|
}
|
|
859
859
|
|
|
860
|
-
const
|
|
861
|
-
|
|
860
|
+
const network = await select({ loop: false,
|
|
861
|
+
message: chalk.cyan('你的网络环境'),
|
|
862
|
+
choices: [
|
|
863
|
+
{ name: '有梯子 / 海外网络(走官方)', value: 'vpn' },
|
|
864
|
+
{ name: '国内网络 / 没有梯子(走镜像)', value: 'cn' },
|
|
865
|
+
],
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
const upgradeArgs = ['install', '-g', 'yingclaw@latest'];
|
|
869
|
+
if (network === 'cn') upgradeArgs.push('--registry=https://registry.npmmirror.com');
|
|
870
|
+
const upgradeCmd = { command: 'npm', args: upgradeArgs };
|
|
862
871
|
|
|
863
872
|
console.log(chalk.dim('\n升级中...\n'));
|
|
864
|
-
const result = spawnSync(upgradeCmd.command, upgradeCmd.args, { stdio: 'inherit' });
|
|
873
|
+
const result = spawnSync(upgradeCmd.command, upgradeCmd.args, { stdio: 'inherit', shell: process.platform === 'win32' });
|
|
865
874
|
|
|
866
875
|
if (result.status === 0) {
|
|
867
876
|
console.log(boxen(
|
|
@@ -1042,6 +1051,7 @@ async function runMenu() {
|
|
|
1042
1051
|
const child = spawn('claude', [], {
|
|
1043
1052
|
stdio: 'inherit',
|
|
1044
1053
|
env: { ...process.env, ...buildClaudeEnv(cfg) },
|
|
1054
|
+
shell: process.platform === 'win32',
|
|
1045
1055
|
});
|
|
1046
1056
|
child.on('error', () => {
|
|
1047
1057
|
console.log(chalk.yellow('\nClaude Code 未找到,请先选择"安装 Claude Code"'));
|
package/lib/config.js
CHANGED
package/lib/desktop.js
CHANGED
|
@@ -6,6 +6,7 @@ const { spawnSync } = require('child_process');
|
|
|
6
6
|
const { normalizeAnthropicBaseUrl } = require('./config');
|
|
7
7
|
|
|
8
8
|
const CLAUDE_DESKTOP_LABEL = 'Claude 桌面应用配置';
|
|
9
|
+
const YINGCLAW_ENTRY_NAME = 'yingclaw';
|
|
9
10
|
const DESKTOP_GATEWAY_KEYS = [
|
|
10
11
|
'inferenceProvider',
|
|
11
12
|
'inferenceGatewayBaseUrl',
|
|
@@ -84,6 +85,7 @@ function buildClaudeDesktopEnterpriseConfig(config, options = {}) {
|
|
|
84
85
|
};
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
// 只清除 yingclaw 写入的那条 entry,保留用户其它 3P 配置
|
|
87
89
|
function clearClaudeDesktopConfigLibrary(options = {}) {
|
|
88
90
|
const dir = options.configLibraryDir || getClaudeDesktopConfigLibraryDir(options);
|
|
89
91
|
if (!dir || !fs.existsSync(dir)) {
|
|
@@ -91,27 +93,37 @@ function clearClaudeDesktopConfigLibrary(options = {}) {
|
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
const metaFile = path.join(dir, '_meta.json');
|
|
96
|
+
if (!fs.existsSync(metaFile)) {
|
|
97
|
+
return { result: 'missing', dir };
|
|
98
|
+
}
|
|
99
|
+
|
|
94
100
|
const meta = readJsonFile(metaFile);
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
101
|
+
const entries = Array.isArray(meta.entries) ? meta.entries : [];
|
|
102
|
+
const yingclawEntries = entries.filter((entry) => entry && entry.name === YINGCLAW_ENTRY_NAME);
|
|
103
|
+
if (yingclawEntries.length === 0) {
|
|
104
|
+
return { result: 'missing', dir };
|
|
98
105
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
|
|
107
|
+
for (const entry of yingclawEntries) {
|
|
108
|
+
if (entry && typeof entry.id === 'string' && entry.id) {
|
|
109
|
+
const file = path.join(dir, `${entry.id}.json`);
|
|
110
|
+
if (fs.existsSync(file)) {
|
|
111
|
+
fs.unlinkSync(file);
|
|
103
112
|
}
|
|
104
113
|
}
|
|
105
114
|
}
|
|
106
115
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (
|
|
116
|
+
const remaining = entries.filter((entry) => entry && entry.name !== YINGCLAW_ENTRY_NAME);
|
|
117
|
+
const yingclawIds = new Set(yingclawEntries.map((e) => e.id));
|
|
118
|
+
const newAppliedId = yingclawIds.has(meta.appliedId)
|
|
119
|
+
? (remaining[0]?.id || '')
|
|
120
|
+
: meta.appliedId;
|
|
121
|
+
|
|
122
|
+
if (remaining.length === 0 && !newAppliedId) {
|
|
114
123
|
fs.unlinkSync(metaFile);
|
|
124
|
+
} else {
|
|
125
|
+
const newMeta = { ...meta, appliedId: newAppliedId, entries: remaining };
|
|
126
|
+
fs.writeFileSync(metaFile, JSON.stringify(newMeta, null, 2) + '\n');
|
|
115
127
|
}
|
|
116
128
|
|
|
117
129
|
return { result: 'updated', dir };
|
|
@@ -132,7 +144,10 @@ function writeClaudeDesktopConfig(config, options = {}) {
|
|
|
132
144
|
const configLibraryDir = path.join(dataDir, 'configLibrary');
|
|
133
145
|
const existingMetaFile = path.join(configLibraryDir, '_meta.json');
|
|
134
146
|
const existingMeta = readJsonFile(existingMetaFile);
|
|
135
|
-
const
|
|
147
|
+
const existingEntries = Array.isArray(existingMeta.entries) ? existingMeta.entries : [];
|
|
148
|
+
// 用 name='yingclaw' 标记自己的 entry;不复用用户的 appliedId 以免覆盖别家的配置
|
|
149
|
+
const existingYingclaw = existingEntries.find((entry) => entry && entry.name === YINGCLAW_ENTRY_NAME);
|
|
150
|
+
const uuid = existingYingclaw?.id || options.uuid || crypto.randomUUID();
|
|
136
151
|
|
|
137
152
|
const models = collectModels(config);
|
|
138
153
|
|
|
@@ -146,11 +161,13 @@ function writeClaudeDesktopConfig(config, options = {}) {
|
|
|
146
161
|
deploymentOrganizationUuid: uuid,
|
|
147
162
|
};
|
|
148
163
|
|
|
164
|
+
const otherEntries = existingEntries.filter((entry) => entry && entry.name !== YINGCLAW_ENTRY_NAME);
|
|
149
165
|
const meta = {
|
|
166
|
+
...existingMeta,
|
|
150
167
|
appliedId: uuid,
|
|
151
|
-
entries: [{ id: uuid, name:
|
|
152
|
-
isManaged: false,
|
|
153
|
-
platform: process.platform,
|
|
168
|
+
entries: [...otherEntries, { id: uuid, name: YINGCLAW_ENTRY_NAME }],
|
|
169
|
+
isManaged: typeof existingMeta.isManaged === 'boolean' ? existingMeta.isManaged : false,
|
|
170
|
+
platform: existingMeta.platform || process.platform,
|
|
154
171
|
};
|
|
155
172
|
|
|
156
173
|
fs.mkdirSync(configLibraryDir, { recursive: true });
|
|
@@ -210,7 +227,8 @@ function isDesktopConfigured(options = {}) {
|
|
|
210
227
|
const dir = options.dataDir || getClaudeDesktopDataDir(options);
|
|
211
228
|
if (!dir) return false;
|
|
212
229
|
const meta = readJsonFile(path.join(dir, 'configLibrary', '_meta.json'));
|
|
213
|
-
|
|
230
|
+
if (!Array.isArray(meta.entries)) return false;
|
|
231
|
+
return meta.entries.some((entry) => entry && entry.name === YINGCLAW_ENTRY_NAME);
|
|
214
232
|
}
|
|
215
233
|
|
|
216
234
|
function buildClaudeDesktopOpenCommands(platform = process.platform) {
|