yingclaw 2.5.18 → 2.5.19
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 +29 -9
- package/lib/autostart.js +31 -0
- package/lib/config.js +3 -0
- package/lib/desktop.js +79 -17
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -21,7 +21,7 @@ const {
|
|
|
21
21
|
} = require('../lib/config');
|
|
22
22
|
const { execSync, spawn, spawnSync } = require('child_process');
|
|
23
23
|
const pkg = require('../package.json');
|
|
24
|
-
const { getGatewayAutostartStatus, installGatewayAutostart } = require('../lib/autostart');
|
|
24
|
+
const { getGatewayAutostartStatus, installGatewayAutostart, removeGatewayAutostart } = require('../lib/autostart');
|
|
25
25
|
const { buildMenuStatusLines, buildStatusView } = require('../lib/panel');
|
|
26
26
|
const { buildClaudeInstallCommand, checkNodeEnv, getNodeInstallGuide, getInstallFailureHints } = require('../lib/install');
|
|
27
27
|
const { clearClaudeDesktopConfig, isDesktopConfigured, openClaudeDesktop, writeClaudeDesktopConfig } = require('../lib/desktop');
|
|
@@ -102,6 +102,20 @@ function getSavedConfigHint() {
|
|
|
102
102
|
return '⚠ API Key 以明文存储在 ~/.clawai.json';
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
function clearCurrentProcessClaudeEnv() {
|
|
106
|
+
for (const key of CLEAR_CLAUDE_ENV_KEYS) {
|
|
107
|
+
delete process.env[key];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function desktopConfigClearedPaths(result) {
|
|
112
|
+
const path = require('path');
|
|
113
|
+
return [
|
|
114
|
+
...(Array.isArray(result.dataDirs) ? result.dataDirs.map(dir => path.join(dir, 'configLibrary/')) : []),
|
|
115
|
+
...(Array.isArray(result.files) ? result.files : [result.file]),
|
|
116
|
+
].filter(Boolean);
|
|
117
|
+
}
|
|
118
|
+
|
|
105
119
|
async function offerDesktopSync(chalk, ora, config) {
|
|
106
120
|
if (!isDesktopConfigured()) return;
|
|
107
121
|
const syncDesktop = await confirm({ message: 'Claude 桌面应用已配置,是否同步新模型?', default: true });
|
|
@@ -789,7 +803,10 @@ program
|
|
|
789
803
|
spinner.warn(chalk.yellow('当前系统暂不支持自动配置 Claude 桌面应用'));
|
|
790
804
|
return;
|
|
791
805
|
}
|
|
792
|
-
|
|
806
|
+
const extraFiles = Array.isArray(result.files) && result.files.length > 1
|
|
807
|
+
? chalk.dim(`(已同步 ${result.files.length} 个配置位置)`)
|
|
808
|
+
: '';
|
|
809
|
+
spinner.succeed(chalk.green(`Claude 桌面应用配置已写入 → ${result.file}`) + extraFiles);
|
|
793
810
|
} catch (e) {
|
|
794
811
|
spinner.fail(chalk.red(`写入失败: ${e.message}`));
|
|
795
812
|
return;
|
|
@@ -882,10 +899,7 @@ program
|
|
|
882
899
|
|
|
883
900
|
if (result.result === 'updated') {
|
|
884
901
|
spinner.succeed(chalk.green('Claude 桌面应用已恢复默认'));
|
|
885
|
-
const cleared =
|
|
886
|
-
result.dataDir ? require('path').join(result.dataDir, 'configLibrary/') : null,
|
|
887
|
-
result.file,
|
|
888
|
-
].filter(Boolean);
|
|
902
|
+
const cleared = desktopConfigClearedPaths(result);
|
|
889
903
|
console.log(boxen(
|
|
890
904
|
chalk.bold('已清除 Claude 桌面应用第三方推理配置:\n\n') +
|
|
891
905
|
cleared.map(f => chalk.cyan(' • ' + f)).join('\n'),
|
|
@@ -942,8 +956,11 @@ program
|
|
|
942
956
|
const cleared = resetConfig();
|
|
943
957
|
const desktopCleared = clearClaudeDesktopConfig();
|
|
944
958
|
if (desktopCleared.result === 'updated') {
|
|
945
|
-
|
|
946
|
-
|
|
959
|
+
cleared.push(...desktopConfigClearedPaths(desktopCleared));
|
|
960
|
+
}
|
|
961
|
+
const autostartCleared = removeGatewayAutostart();
|
|
962
|
+
if (autostartCleared.result === 'removed' && autostartCleared.file) {
|
|
963
|
+
cleared.push(autostartCleared.file);
|
|
947
964
|
}
|
|
948
965
|
|
|
949
966
|
if (cleared.length === 0) {
|
|
@@ -1272,10 +1289,13 @@ async function runMenu() {
|
|
|
1272
1289
|
});
|
|
1273
1290
|
|
|
1274
1291
|
// 改 config 的命令需要刷新缓存
|
|
1275
|
-
if (['config', 'switch', 'reset', 'code-reset'].includes(resolvedAction)) {
|
|
1292
|
+
if (['config', 'switch', 'reset', 'code-reset', 'desktop-reset'].includes(resolvedAction)) {
|
|
1276
1293
|
lastCheckResult = undefined;
|
|
1277
1294
|
lastCheckedHash = null;
|
|
1278
1295
|
}
|
|
1296
|
+
if (process.platform === 'win32' && ['reset', 'code-reset'].includes(resolvedAction)) {
|
|
1297
|
+
clearCurrentProcessClaudeEnv();
|
|
1298
|
+
}
|
|
1279
1299
|
// 安装 Claude 后刷新检测缓存
|
|
1280
1300
|
if (resolvedAction === 'install') {
|
|
1281
1301
|
invalidateClaudeInstalledCache();
|
package/lib/autostart.js
CHANGED
|
@@ -188,6 +188,36 @@ function installGatewayAutostart(options = {}) {
|
|
|
188
188
|
return { result: 'installed', file };
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
function removeGatewayAutostart(options = {}) {
|
|
192
|
+
const platform = options.platform || process.platform;
|
|
193
|
+
if (platform === 'win32') {
|
|
194
|
+
const file = options.file || getWindowsStartupScriptPath(options);
|
|
195
|
+
if (!fs.existsSync(file)) {
|
|
196
|
+
return { result: 'missing', file };
|
|
197
|
+
}
|
|
198
|
+
fs.unlinkSync(file);
|
|
199
|
+
return { result: 'removed', file };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (platform !== 'darwin') {
|
|
203
|
+
return { result: 'unsupported', file: null };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const homeDir = options.homeDir || os.homedir();
|
|
207
|
+
const file = options.file || getMacLaunchAgentPath({ homeDir });
|
|
208
|
+
const uid = options.uid || (typeof process.getuid === 'function' ? process.getuid() : null);
|
|
209
|
+
const runner = options.runner || spawnSync;
|
|
210
|
+
|
|
211
|
+
if (uid != null) {
|
|
212
|
+
runLaunchctl(runner, ['bootout', `gui/${uid}/${GATEWAY_LAUNCH_AGENT_LABEL}`], { optional: true });
|
|
213
|
+
}
|
|
214
|
+
if (!fs.existsSync(file)) {
|
|
215
|
+
return { result: 'missing', file };
|
|
216
|
+
}
|
|
217
|
+
fs.unlinkSync(file);
|
|
218
|
+
return { result: 'removed', file };
|
|
219
|
+
}
|
|
220
|
+
|
|
191
221
|
function getGatewayAutostartStatus(options = {}) {
|
|
192
222
|
const platform = options.platform || process.platform;
|
|
193
223
|
if (platform === 'win32') {
|
|
@@ -237,4 +267,5 @@ module.exports = {
|
|
|
237
267
|
getMacLaunchAgentPath,
|
|
238
268
|
getWindowsStartupScriptPath,
|
|
239
269
|
installGatewayAutostart,
|
|
270
|
+
removeGatewayAutostart,
|
|
240
271
|
};
|
package/lib/config.js
CHANGED
|
@@ -407,6 +407,9 @@ function clearClaudeCodeEnv(options = {}) {
|
|
|
407
407
|
|
|
408
408
|
if (platform === 'win32') {
|
|
409
409
|
runWindowsEnvCommands(buildWindowsClearEnvCommands(), options.runner || spawnSync, { ignoreErrors: true });
|
|
410
|
+
for (const key of CLEAR_CLAUDE_ENV_KEYS) {
|
|
411
|
+
delete process.env[key];
|
|
412
|
+
}
|
|
410
413
|
cleared.push(WINDOWS_ENV_LABEL);
|
|
411
414
|
return cleared;
|
|
412
415
|
}
|
package/lib/desktop.js
CHANGED
|
@@ -55,6 +55,25 @@ function getClaudeDesktopDataDir(options = {}) {
|
|
|
55
55
|
return null;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
function getClaudeDesktopDataDirs(options = {}) {
|
|
59
|
+
if (options.dataDir) return [options.dataDir];
|
|
60
|
+
|
|
61
|
+
const platform = options.platform || process.platform;
|
|
62
|
+
const homeDir = options.homeDir || os.homedir();
|
|
63
|
+
|
|
64
|
+
if (platform === 'win32') {
|
|
65
|
+
const roamingAppData = options.appData || process.env.APPDATA || [homeDir, 'AppData', 'Roaming'].join('\\');
|
|
66
|
+
const localAppData = options.localAppData || process.env.LOCALAPPDATA || [homeDir, 'AppData', 'Local'].join('\\');
|
|
67
|
+
return [...new Set([
|
|
68
|
+
roamingAppData + '\\Claude-3p',
|
|
69
|
+
localAppData + '\\Claude-3p',
|
|
70
|
+
])];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const dataDir = getClaudeDesktopDataDir(options);
|
|
74
|
+
return dataDir ? [dataDir] : [];
|
|
75
|
+
}
|
|
76
|
+
|
|
58
77
|
function getClaudeDesktopConfigPath(options = {}) {
|
|
59
78
|
const platform = options.platform || process.platform;
|
|
60
79
|
const dataDir = options.dataDir || getClaudeDesktopDataDir(options);
|
|
@@ -172,7 +191,8 @@ function buildClaudeDesktopDirectEnterpriseConfig(config, options = {}) {
|
|
|
172
191
|
|
|
173
192
|
// 只清除 yingclaw 写入的那条 entry,保留用户其它 3P 配置
|
|
174
193
|
function clearClaudeDesktopConfigLibrary(options = {}) {
|
|
175
|
-
const
|
|
194
|
+
const dataDir = options.dataDir || getClaudeDesktopDataDir(options);
|
|
195
|
+
const dir = options.configLibraryDir || (dataDir ? path.join(dataDir, 'configLibrary') : null);
|
|
176
196
|
if (!dir || !fs.existsSync(dir)) {
|
|
177
197
|
return { result: 'missing', dir };
|
|
178
198
|
}
|
|
@@ -214,17 +234,11 @@ function clearClaudeDesktopConfigLibrary(options = {}) {
|
|
|
214
234
|
return { result: 'updated', dir };
|
|
215
235
|
}
|
|
216
236
|
|
|
217
|
-
|
|
218
|
-
function writeClaudeDesktopConfig(config, options = {}) {
|
|
237
|
+
function writeClaudeDesktopConfigToDir(config, options, dataDir) {
|
|
219
238
|
const effectiveConfig = options.direct
|
|
220
239
|
? config
|
|
221
240
|
: ensureDesktopGatewayConfig(config, options);
|
|
222
241
|
|
|
223
|
-
const dataDir = options.dataDir || getClaudeDesktopDataDir(options);
|
|
224
|
-
if (!dataDir) {
|
|
225
|
-
return { result: 'unsupported', file: null };
|
|
226
|
-
}
|
|
227
|
-
|
|
228
242
|
const configLibraryDir = path.join(dataDir, 'configLibrary');
|
|
229
243
|
const existingMetaFile = path.join(configLibraryDir, '_meta.json');
|
|
230
244
|
const existingMeta = readJsonFile(existingMetaFile);
|
|
@@ -257,7 +271,7 @@ function writeClaudeDesktopConfig(config, options = {}) {
|
|
|
257
271
|
appliedId: uuid,
|
|
258
272
|
entries: [...otherEntries, { id: uuid, name: YINGCLAW_ENTRY_NAME }],
|
|
259
273
|
isManaged: typeof existingMeta.isManaged === 'boolean' ? existingMeta.isManaged : false,
|
|
260
|
-
platform: existingMeta.platform || process.platform,
|
|
274
|
+
platform: existingMeta.platform || options.platform || process.platform,
|
|
261
275
|
};
|
|
262
276
|
|
|
263
277
|
fs.mkdirSync(configLibraryDir, { recursive: true });
|
|
@@ -295,9 +309,32 @@ function writeClaudeDesktopConfig(config, options = {}) {
|
|
|
295
309
|
return { result: beforeEntry === entryBody ? 'unchanged' : 'updated', file, config: effectiveConfig };
|
|
296
310
|
}
|
|
297
311
|
|
|
298
|
-
|
|
312
|
+
// 写入 Claude-3p/configLibrary/ 下的 enterprise config 条目(主进程从此处读取)
|
|
313
|
+
function writeClaudeDesktopConfig(config, options = {}) {
|
|
314
|
+
const dataDirs = options.configFile
|
|
315
|
+
? [options.dataDir || path.dirname(options.configFile)]
|
|
316
|
+
: getClaudeDesktopDataDirs(options);
|
|
317
|
+
if (dataDirs.length === 0) {
|
|
318
|
+
return { result: 'unsupported', file: null, files: [] };
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const results = dataDirs.map((dataDir, index) => {
|
|
322
|
+
const writeOptions = index === 0
|
|
323
|
+
? options
|
|
324
|
+
: { ...options, configFile: null, dataDir };
|
|
325
|
+
return writeClaudeDesktopConfigToDir(config, writeOptions, dataDir);
|
|
326
|
+
});
|
|
327
|
+
const primary = results[0];
|
|
328
|
+
return {
|
|
329
|
+
...primary,
|
|
330
|
+
result: results.some((item) => item.result === 'updated') ? 'updated' : primary.result,
|
|
331
|
+
files: results.map((item) => item.file).filter(Boolean),
|
|
332
|
+
dataDirs,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function clearClaudeDesktopConfigAtDir(options = {}, dataDir) {
|
|
299
337
|
// Derive dataDir only when configFile is not explicitly overridden (to avoid touching real system dirs in tests)
|
|
300
|
-
const dataDir = options.dataDir || (options.configFile ? null : getClaudeDesktopDataDir(options));
|
|
301
338
|
const file = options.configFile || (dataDir ? path.join(dataDir, 'claude_desktop_config.json') : null);
|
|
302
339
|
|
|
303
340
|
// Clear configLibrary regardless of whether the main config file exists
|
|
@@ -320,7 +357,7 @@ function clearClaudeDesktopConfig(options = {}) {
|
|
|
320
357
|
// Remove legacy enterpriseConfig gateway keys
|
|
321
358
|
if (next.enterpriseConfig && typeof next.enterpriseConfig === 'object') {
|
|
322
359
|
const enterpriseConfig = { ...next.enterpriseConfig };
|
|
323
|
-
for (const key of
|
|
360
|
+
for (const key of MAC_POLICY_KEYS) {
|
|
324
361
|
delete enterpriseConfig[key];
|
|
325
362
|
}
|
|
326
363
|
if (Object.keys(enterpriseConfig).length > 0) {
|
|
@@ -338,12 +375,36 @@ function clearClaudeDesktopConfig(options = {}) {
|
|
|
338
375
|
return { result: 'updated', file, dataDir };
|
|
339
376
|
}
|
|
340
377
|
|
|
378
|
+
function clearClaudeDesktopConfig(options = {}) {
|
|
379
|
+
const dataDirs = options.configFile
|
|
380
|
+
? [options.dataDir || path.dirname(options.configFile)]
|
|
381
|
+
: getClaudeDesktopDataDirs(options);
|
|
382
|
+
|
|
383
|
+
if (dataDirs.length === 0) {
|
|
384
|
+
return { result: 'missing', file: null, files: [], dataDir: null, dataDirs: [] };
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const results = dataDirs.map((dataDir, index) => {
|
|
388
|
+
const clearOptions = index === 0
|
|
389
|
+
? options
|
|
390
|
+
: { ...options, configFile: null, dataDir };
|
|
391
|
+
return clearClaudeDesktopConfigAtDir(clearOptions, dataDir);
|
|
392
|
+
});
|
|
393
|
+
const primary = results[0];
|
|
394
|
+
return {
|
|
395
|
+
...primary,
|
|
396
|
+
result: results.some((item) => item.result === 'updated') ? 'updated' : primary.result,
|
|
397
|
+
files: results.map((item) => item.file).filter(Boolean),
|
|
398
|
+
dataDirs,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
341
402
|
function isDesktopConfigured(options = {}) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
403
|
+
return getClaudeDesktopDataDirs(options).some((dir) => {
|
|
404
|
+
const meta = readJsonFile(path.join(dir, 'configLibrary', '_meta.json'));
|
|
405
|
+
if (!Array.isArray(meta.entries)) return false;
|
|
406
|
+
return meta.entries.some((entry) => entry && entry.name === YINGCLAW_ENTRY_NAME);
|
|
407
|
+
});
|
|
347
408
|
}
|
|
348
409
|
|
|
349
410
|
function buildClaudeDesktopOpenCommands(platform = process.platform, options = {}) {
|
|
@@ -432,6 +493,7 @@ module.exports = {
|
|
|
432
493
|
getClaudeDesktopConfigLibraryDir,
|
|
433
494
|
getClaudeDesktopConfigPath,
|
|
434
495
|
getClaudeDesktopDataDir,
|
|
496
|
+
getClaudeDesktopDataDirs,
|
|
435
497
|
isDesktopConfigured,
|
|
436
498
|
openClaudeDesktop,
|
|
437
499
|
writeClaudeDesktopConfig,
|