yingclaw 2.5.19 → 2.5.25
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/README.md +30 -9
- package/bin/cli.js +232 -29
- package/index.js +3 -0
- package/lib/config.js +137 -24
- package/lib/doctor.js +13 -3
- package/lib/gateway.js +105 -6
- package/lib/install.js +46 -1
- package/lib/openai.js +152 -0
- package/lib/panel.js +17 -5
- package/lib/vscode.js +256 -0
- package/package.json +2 -2
package/lib/panel.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { buildClaudeEnv, PROVIDERS } = require('./config');
|
|
1
|
+
const { buildClaudeEnv, getModelFamily, PROVIDERS } = require('./config');
|
|
2
2
|
|
|
3
3
|
function apiStatusText(apiStatus) {
|
|
4
4
|
if (apiStatus === true) return 'API 正常';
|
|
@@ -39,6 +39,9 @@ function buildStatusView(config, options = {}) {
|
|
|
39
39
|
const desktopGatewayStatus = options.desktopGatewayStatus;
|
|
40
40
|
const desktopGatewayAutostartStatus = options.desktopGatewayAutostartStatus;
|
|
41
41
|
const desktopGatewayText = desktopGatewayStatusText(desktopGatewayStatus, desktopGatewayAutostartStatus);
|
|
42
|
+
const availableModelCount = Array.isArray(config.availableModels) ? config.availableModels.length : 0;
|
|
43
|
+
const mainFamily = getModelFamily(mainModel);
|
|
44
|
+
const fastFamily = getModelFamily(fastModel);
|
|
42
45
|
const warnings = [];
|
|
43
46
|
|
|
44
47
|
if (config.provider === 'deepseek' && (
|
|
@@ -48,11 +51,15 @@ function buildStatusView(config, options = {}) {
|
|
|
48
51
|
)) {
|
|
49
52
|
warnings.push('检测到旧 DeepSeek 模型名,建议运行 claw switch 更新到 [1m] 长上下文版本');
|
|
50
53
|
}
|
|
54
|
+
if (config.provider === 'custom' && mainFamily && fastFamily && mainFamily !== fastFamily) {
|
|
55
|
+
warnings.push(`快速模型跨系列:${mainFamily} → ${fastFamily}`);
|
|
56
|
+
}
|
|
51
57
|
|
|
52
58
|
const view = {
|
|
53
59
|
providerName,
|
|
54
60
|
mainModel,
|
|
55
61
|
fastModel,
|
|
62
|
+
availableModelCount,
|
|
56
63
|
envActive,
|
|
57
64
|
warnings,
|
|
58
65
|
lines: [
|
|
@@ -83,14 +90,15 @@ function buildMenuStatusLines(view, options = {}) {
|
|
|
83
90
|
];
|
|
84
91
|
|
|
85
92
|
if (view.envActive) {
|
|
86
|
-
lines.push('
|
|
93
|
+
lines.push('终端已生效');
|
|
87
94
|
} else if (options.platform === 'win32') {
|
|
88
|
-
lines.push('
|
|
95
|
+
lines.push('终端未生效:重新打开 PowerShell / CMD');
|
|
89
96
|
} else {
|
|
90
|
-
lines.push('
|
|
97
|
+
lines.push('终端未生效:source ~/.zshrc 或重开终端');
|
|
91
98
|
}
|
|
92
99
|
|
|
93
|
-
|
|
100
|
+
const modelCountText = view.availableModelCount ? ` · 可用 ${view.availableModelCount}` : '';
|
|
101
|
+
lines.push(`模型 ${view.mainModel} · 快速 ${view.fastModel}${modelCountText}`);
|
|
94
102
|
|
|
95
103
|
const desktopGatewayText = desktopGatewayStatusText(
|
|
96
104
|
view.desktopGatewayStatus || options.desktopGatewayStatus,
|
|
@@ -103,6 +111,10 @@ function buildMenuStatusLines(view, options = {}) {
|
|
|
103
111
|
if (view.warnings.some((warning) => warning.includes('旧 DeepSeek 模型名'))) {
|
|
104
112
|
lines.push('旧模型名:选择下方"切换厂商或模型"更新到 [1m]');
|
|
105
113
|
}
|
|
114
|
+
const crossFamilyWarning = view.warnings.find((warning) => warning.startsWith('快速模型跨系列'));
|
|
115
|
+
if (crossFamilyWarning) {
|
|
116
|
+
lines.push(crossFamilyWarning);
|
|
117
|
+
}
|
|
106
118
|
|
|
107
119
|
return lines;
|
|
108
120
|
}
|
package/lib/vscode.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { buildClaudeEnv, resolveFastModel, PROVIDERS, CLEAR_CLAUDE_ENV_KEYS } = require('./config');
|
|
5
|
+
const { isDesktopChatModel } = require('./gateway');
|
|
6
|
+
|
|
7
|
+
const CLAUDE_CODE_SETTINGS_SCHEMA = 'https://json.schemastore.org/claude-code-settings.json';
|
|
8
|
+
const VSCODE_CLAUDE_OPEN_URI = 'vscode://anthropic.claude-code/open';
|
|
9
|
+
const VSCODE_MODEL_SETTINGS_KEYS = ['model', 'availableModels'];
|
|
10
|
+
|
|
11
|
+
function readJsonFile(file) {
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
14
|
+
} catch {
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function writeJsonFile(file, value) {
|
|
20
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
21
|
+
fs.writeFileSync(file, JSON.stringify(value, null, 2) + '\n');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getClaudeCodeSettingsPath(options = {}) {
|
|
25
|
+
const homeDir = options.homeDir || os.homedir();
|
|
26
|
+
return options.settingsFile || path.join(homeDir, '.claude', 'settings.json');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getVsCodeUserSettingsPath(options = {}) {
|
|
30
|
+
if (options.vsCodeSettingsFile) return options.vsCodeSettingsFile;
|
|
31
|
+
|
|
32
|
+
const platform = options.platform || process.platform;
|
|
33
|
+
const homeDir = options.homeDir || os.homedir();
|
|
34
|
+
|
|
35
|
+
if (platform === 'darwin') {
|
|
36
|
+
return path.join(homeDir, 'Library', 'Application Support', 'Code', 'User', 'settings.json');
|
|
37
|
+
}
|
|
38
|
+
if (platform === 'win32') {
|
|
39
|
+
const appData = options.appData || process.env.APPDATA || path.join(homeDir, 'AppData', 'Roaming');
|
|
40
|
+
return path.win32.join(appData, 'Code', 'User', 'settings.json');
|
|
41
|
+
}
|
|
42
|
+
return path.join(homeDir, '.config', 'Code', 'User', 'settings.json');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function buildClaudeCodeSettingsPatch(config) {
|
|
46
|
+
const env = buildVsCodeClaudeEnv(config);
|
|
47
|
+
const availableModels = buildVsCodeAvailableModels(config);
|
|
48
|
+
const model = config.vscodeModel || config.model;
|
|
49
|
+
return {
|
|
50
|
+
$schema: CLAUDE_CODE_SETTINGS_SCHEMA,
|
|
51
|
+
model: availableModels.includes(model) ? model : availableModels[0],
|
|
52
|
+
availableModels,
|
|
53
|
+
env,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function buildVsCodeClaudeEnv(config) {
|
|
58
|
+
const { provider, model, fastModel, vscodeModel, vscodeFastModel } = config;
|
|
59
|
+
const selectedModel = vscodeModel || model;
|
|
60
|
+
const resolvedFastModel = vscodeFastModel || fastModel || resolveFastModel(PROVIDERS[provider], selectedModel);
|
|
61
|
+
const claudeEnv = buildClaudeEnv({ ...config, model: selectedModel, fastModel: resolvedFastModel });
|
|
62
|
+
const env = {
|
|
63
|
+
ANTHROPIC_BASE_URL: claudeEnv.ANTHROPIC_BASE_URL,
|
|
64
|
+
ANTHROPIC_AUTH_TOKEN: claudeEnv.ANTHROPIC_AUTH_TOKEN,
|
|
65
|
+
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: '1',
|
|
66
|
+
CLAUDE_CODE_SUBAGENT_MODEL: resolvedFastModel,
|
|
67
|
+
CLAUDE_CODE_EFFORT_LEVEL: 'max',
|
|
68
|
+
};
|
|
69
|
+
if (resolvedFastModel && resolvedFastModel !== selectedModel) {
|
|
70
|
+
env.ANTHROPIC_CUSTOM_MODEL_OPTION = resolvedFastModel;
|
|
71
|
+
env.ANTHROPIC_CUSTOM_MODEL_OPTION_NAME = resolvedFastModel;
|
|
72
|
+
env.ANTHROPIC_CUSTOM_MODEL_OPTION_DESCRIPTION = 'Custom fast model';
|
|
73
|
+
}
|
|
74
|
+
return env;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function buildVsCodeAvailableModels({ model, fastModel, availableModels, vscodeModel, vscodeFastModel }) {
|
|
78
|
+
const providerModels = Array.isArray(availableModels) && availableModels.length > 0
|
|
79
|
+
? availableModels
|
|
80
|
+
: [];
|
|
81
|
+
const models = [vscodeModel || model, vscodeFastModel || fastModel, model, fastModel, ...providerModels].filter(Boolean);
|
|
82
|
+
const chatModels = models.filter(isDesktopChatModel);
|
|
83
|
+
return [...new Set(chatModels.length > 0 ? chatModels : [model, fastModel].filter(Boolean))];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function buildVsCodeModelSelectionIds(config) {
|
|
87
|
+
return buildVsCodeAvailableModels(config);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function writeClaudeCodeSettings(config, options = {}) {
|
|
91
|
+
const file = getClaudeCodeSettingsPath(options);
|
|
92
|
+
const current = readJsonFile(file);
|
|
93
|
+
const patch = buildClaudeCodeSettingsPatch(config);
|
|
94
|
+
const nextEnv = { ...(current.env && typeof current.env === 'object' ? current.env : {}) };
|
|
95
|
+
for (const key of CLEAR_CLAUDE_ENV_KEYS) {
|
|
96
|
+
delete nextEnv[key];
|
|
97
|
+
}
|
|
98
|
+
Object.assign(nextEnv, patch.env);
|
|
99
|
+
|
|
100
|
+
const next = {
|
|
101
|
+
...current,
|
|
102
|
+
$schema: current.$schema || patch.$schema,
|
|
103
|
+
model: patch.model,
|
|
104
|
+
availableModels: patch.availableModels,
|
|
105
|
+
env: nextEnv,
|
|
106
|
+
};
|
|
107
|
+
writeJsonFile(file, next);
|
|
108
|
+
try {
|
|
109
|
+
fs.chmodSync(file, 0o600);
|
|
110
|
+
} catch {}
|
|
111
|
+
return { result: 'updated', file, env: patch.env };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function writeVsCodeExtensionSettings(options = {}) {
|
|
115
|
+
const file = getVsCodeUserSettingsPath(options);
|
|
116
|
+
const current = readJsonFile(file);
|
|
117
|
+
const next = {
|
|
118
|
+
...current,
|
|
119
|
+
'claudeCode.disableLoginPrompt': true,
|
|
120
|
+
};
|
|
121
|
+
if (options.useTerminal === true || options.useTerminal === false) {
|
|
122
|
+
next['claudeCode.useTerminal'] = options.useTerminal;
|
|
123
|
+
}
|
|
124
|
+
writeJsonFile(file, next);
|
|
125
|
+
return { result: 'updated', file };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function writeVsCodeIntegration(config, options = {}) {
|
|
129
|
+
const claudeSettings = writeClaudeCodeSettings(config, options);
|
|
130
|
+
const vscodeSettings = writeVsCodeExtensionSettings(options);
|
|
131
|
+
return {
|
|
132
|
+
result: 'updated',
|
|
133
|
+
files: [claudeSettings.file, vscodeSettings.file],
|
|
134
|
+
claudeSettings,
|
|
135
|
+
vscodeSettings,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function clearClaudeCodeSettingsEnv(options = {}) {
|
|
140
|
+
const file = getClaudeCodeSettingsPath(options);
|
|
141
|
+
if (!fs.existsSync(file)) return { result: 'missing', file };
|
|
142
|
+
|
|
143
|
+
const current = readJsonFile(file);
|
|
144
|
+
const nextEnv = { ...(current.env && typeof current.env === 'object' ? current.env : {}) };
|
|
145
|
+
let changed = false;
|
|
146
|
+
|
|
147
|
+
for (const key of CLEAR_CLAUDE_ENV_KEYS) {
|
|
148
|
+
if (Object.prototype.hasOwnProperty.call(nextEnv, key)) {
|
|
149
|
+
delete nextEnv[key];
|
|
150
|
+
changed = true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for (const key of VSCODE_MODEL_SETTINGS_KEYS) {
|
|
154
|
+
if (Object.prototype.hasOwnProperty.call(current, key)) {
|
|
155
|
+
changed = true;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!changed) return { result: 'missing', file };
|
|
160
|
+
|
|
161
|
+
const next = { ...current };
|
|
162
|
+
for (const key of VSCODE_MODEL_SETTINGS_KEYS) {
|
|
163
|
+
delete next[key];
|
|
164
|
+
}
|
|
165
|
+
if (Object.keys(nextEnv).length > 0) {
|
|
166
|
+
next.env = nextEnv;
|
|
167
|
+
} else {
|
|
168
|
+
delete next.env;
|
|
169
|
+
}
|
|
170
|
+
writeJsonFile(file, next);
|
|
171
|
+
return { result: 'updated', file };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function clearVsCodeExtensionSettings(options = {}) {
|
|
175
|
+
const file = getVsCodeUserSettingsPath(options);
|
|
176
|
+
if (!fs.existsSync(file)) return { result: 'missing', file };
|
|
177
|
+
|
|
178
|
+
const current = readJsonFile(file);
|
|
179
|
+
const next = { ...current };
|
|
180
|
+
let changed = false;
|
|
181
|
+
for (const key of ['claudeCode.disableLoginPrompt', 'claudeCode.useTerminal']) {
|
|
182
|
+
if (Object.prototype.hasOwnProperty.call(next, key)) {
|
|
183
|
+
delete next[key];
|
|
184
|
+
changed = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (!changed) return { result: 'missing', file };
|
|
188
|
+
|
|
189
|
+
writeJsonFile(file, next);
|
|
190
|
+
return { result: 'updated', file };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function clearVsCodeIntegration(options = {}) {
|
|
194
|
+
const claudeSettings = clearClaudeCodeSettingsEnv(options);
|
|
195
|
+
const vscodeSettings = clearVsCodeExtensionSettings(options);
|
|
196
|
+
const files = [claudeSettings, vscodeSettings]
|
|
197
|
+
.filter(result => result.result === 'updated')
|
|
198
|
+
.map(result => result.file);
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
result: files.length > 0 ? 'updated' : 'missing',
|
|
202
|
+
files,
|
|
203
|
+
claudeSettings,
|
|
204
|
+
vscodeSettings,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function checkClaudeCodeSettingsEnv(config, options = {}) {
|
|
209
|
+
const file = getClaudeCodeSettingsPath(options);
|
|
210
|
+
const current = readJsonFile(file);
|
|
211
|
+
const env = current.env && typeof current.env === 'object' ? current.env : {};
|
|
212
|
+
const expected = buildVsCodeClaudeEnv(config);
|
|
213
|
+
const missing = Object.entries(expected)
|
|
214
|
+
.filter(([key, value]) => env[key] !== value)
|
|
215
|
+
.map(([key]) => key);
|
|
216
|
+
const expectedModels = buildVsCodeAvailableModels(config);
|
|
217
|
+
const expectedModel = expectedModels.includes(config.model) ? config.model : expectedModels[0];
|
|
218
|
+
if (current.model !== expectedModel) missing.push('model');
|
|
219
|
+
if (!Array.isArray(current.availableModels) || current.availableModels.join(',') !== expectedModels.join(',')) {
|
|
220
|
+
missing.push('availableModels');
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
file,
|
|
224
|
+
configured: missing.length === 0,
|
|
225
|
+
missing,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function buildVsCodeOpenCommand(platform = process.platform) {
|
|
230
|
+
if (platform === 'darwin') {
|
|
231
|
+
return { command: 'open', args: [VSCODE_CLAUDE_OPEN_URI] };
|
|
232
|
+
}
|
|
233
|
+
if (platform === 'win32') {
|
|
234
|
+
return { command: 'cmd', args: ['/c', 'start', '', VSCODE_CLAUDE_OPEN_URI] };
|
|
235
|
+
}
|
|
236
|
+
return { command: 'xdg-open', args: [VSCODE_CLAUDE_OPEN_URI] };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
module.exports = {
|
|
240
|
+
CLAUDE_CODE_SETTINGS_SCHEMA,
|
|
241
|
+
VSCODE_CLAUDE_OPEN_URI,
|
|
242
|
+
buildClaudeCodeSettingsPatch,
|
|
243
|
+
buildVsCodeAvailableModels,
|
|
244
|
+
buildVsCodeClaudeEnv,
|
|
245
|
+
buildVsCodeModelSelectionIds,
|
|
246
|
+
buildVsCodeOpenCommand,
|
|
247
|
+
checkClaudeCodeSettingsEnv,
|
|
248
|
+
clearClaudeCodeSettingsEnv,
|
|
249
|
+
clearVsCodeExtensionSettings,
|
|
250
|
+
clearVsCodeIntegration,
|
|
251
|
+
getClaudeCodeSettingsPath,
|
|
252
|
+
getVsCodeUserSettingsPath,
|
|
253
|
+
writeClaudeCodeSettings,
|
|
254
|
+
writeVsCodeExtensionSettings,
|
|
255
|
+
writeVsCodeIntegration,
|
|
256
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yingclaw",
|
|
3
|
-
"version": "2.5.
|
|
4
|
-
"description": "Claude Code × 国产大模型一键接入:DeepSeek、Kimi
|
|
3
|
+
"version": "2.5.25",
|
|
4
|
+
"description": "Claude Code × 国产大模型一键接入:DeepSeek、Kimi、火山方舟、Qwen、MiniMax、GLM、MiMo、自定义接口",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"claw": "bin/cli.js"
|