yingclaw 2.1.5 → 2.1.7

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
@@ -857,8 +857,17 @@ program
857
857
  return;
858
858
  }
859
859
 
860
- const installCmd = buildClaudeInstallCommand('vpn');
861
- const upgradeCmd = { command: installCmd.command, args: [...installCmd.args.slice(0, -1), 'yingclaw@latest'] };
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
873
  const result = spawnSync(upgradeCmd.command, upgradeCmd.args, { stdio: 'inherit' });
package/lib/config.js CHANGED
@@ -73,8 +73,13 @@ const PROVIDERS = {
73
73
  name: '小米 MiMo',
74
74
  baseUrl: 'https://api.xiaomimimo.com/anthropic',
75
75
  modelsUrl: 'https://api.xiaomimimo.com/v1/models',
76
+ fastModel: 'mimo-v2-flash',
76
77
  models: [
77
78
  { name: 'MiMo V2.5 Pro(旗舰)', value: 'mimo-v2.5-pro' },
79
+ { name: 'MiMo V2.5(均衡)', value: 'mimo-v2.5' },
80
+ { name: 'MiMo V2 Pro(强力)', value: 'mimo-v2-pro' },
81
+ { name: 'MiMo V2 Omni(多模态)', value: 'mimo-v2-omni' },
82
+ { name: 'MiMo V2 Flash(快速)', value: 'mimo-v2-flash' },
78
83
  ],
79
84
  },
80
85
  custom: {
@@ -402,4 +407,5 @@ module.exports = {
402
407
  classifyValidationStatus,
403
408
  PROVIDERS,
404
409
  CONFIG_FILE,
410
+ CLAUDE_ENV_KEYS,
405
411
  };
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 ids = new Set();
96
- if (typeof meta.appliedId === 'string' && meta.appliedId) {
97
- ids.add(meta.appliedId);
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
- if (Array.isArray(meta.entries)) {
100
- for (const entry of meta.entries) {
101
- if (entry && typeof entry.id === 'string' && entry.id) {
102
- ids.add(entry.id);
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
- for (const id of ids) {
108
- const file = path.join(dir, `${id}.json`);
109
- if (fs.existsSync(file)) {
110
- fs.unlinkSync(file);
111
- }
112
- }
113
- if (fs.existsSync(metaFile)) {
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 uuid = existingMeta.appliedId || options.uuid || crypto.randomUUID();
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: 'yingclaw' }],
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
- return typeof meta.appliedId === 'string' && meta.appliedId.length > 0;
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yingclaw",
3
- "version": "2.1.5",
3
+ "version": "2.1.7",
4
4
  "description": "Claude Code × 国产大模型一键接入:DeepSeek、Kimi、Qwen、MiniMax、GLM、MiMo",
5
5
  "main": "index.js",
6
6
  "bin": {