yingclaw 2.0.0 → 2.0.4
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 +2 -2
- package/lib/desktop.js +100 -74
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ claw code
|
|
|
40
40
|
```bash
|
|
41
41
|
claw desktop
|
|
42
42
|
```
|
|
43
|
-
将当前模型配置写入 Claude Desktop 的第三方推理(Cowork on 3P)本地配置。macOS
|
|
43
|
+
将当前模型配置写入 Claude Desktop 的第三方推理(Cowork on 3P)本地配置。macOS 会自动重启并打开 Claude 桌面应用;Windows 需要手动重新打开。如果配置未生效,请完全退出 Claude Desktop 后重新打开。
|
|
44
44
|
|
|
45
45
|
恢复 Claude Code 终端默认配置:
|
|
46
46
|
```bash
|
|
@@ -127,7 +127,7 @@ npm uninstall -g yingclaw
|
|
|
127
127
|
- macOS:`~/Library/Application Support/Claude-3p/claude_desktop_config.json`
|
|
128
128
|
- Windows:`%APPDATA%\Claude-3p\claude_desktop_config.json`
|
|
129
129
|
|
|
130
|
-
写入的 `enterpriseConfig` 使用 `inferenceProvider=gateway`、`inferenceGatewayAuthScheme=bearer
|
|
130
|
+
写入的 `enterpriseConfig` 使用 `inferenceProvider=gateway`、`inferenceGatewayAuthScheme=bearer`,并按旧版方式把当前厂商模型写入 `inferenceModels`。如果本机存在新版 `configLibrary` 本地配置,`claw desktop` 会同步移除,避免 Claude 优先读取旧的错误配置。DeepSeek 的 Claude Code 终端模型仍使用 `deepseek-v4-pro[1m]`;Claude 桌面应用会写入 `deepseek-v4-pro` 和 `deepseek-v4-flash`。
|
|
131
131
|
|
|
132
132
|
## License
|
|
133
133
|
|
package/lib/desktop.js
CHANGED
|
@@ -6,7 +6,15 @@ const { spawnSync } = require('child_process');
|
|
|
6
6
|
const { normalizeAnthropicBaseUrl } = require('./config');
|
|
7
7
|
|
|
8
8
|
const CLAUDE_DESKTOP_LABEL = 'Claude 桌面应用配置';
|
|
9
|
-
const
|
|
9
|
+
const DESKTOP_GATEWAY_KEYS = [
|
|
10
|
+
'inferenceProvider',
|
|
11
|
+
'inferenceGatewayBaseUrl',
|
|
12
|
+
'inferenceGatewayApiKey',
|
|
13
|
+
'inferenceGatewayAuthScheme',
|
|
14
|
+
'inferenceModels',
|
|
15
|
+
'disableDeploymentModeChooser',
|
|
16
|
+
'deploymentOrganizationUuid',
|
|
17
|
+
];
|
|
10
18
|
|
|
11
19
|
// Claude 3P 数据目录(与 1P 的 Claude/ 目录区分)
|
|
12
20
|
function getClaudeDesktopDataDir(options = {}) {
|
|
@@ -18,23 +26,21 @@ function getClaudeDesktopDataDir(options = {}) {
|
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
if (platform === 'win32') {
|
|
21
|
-
const
|
|
22
|
-
return path.join(
|
|
29
|
+
const appData = options.appData || process.env.APPDATA || options.localAppData || path.join(homeDir, 'AppData', 'Roaming');
|
|
30
|
+
return path.join(appData, 'Claude-3p');
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
return null;
|
|
26
34
|
}
|
|
27
35
|
|
|
28
|
-
function
|
|
36
|
+
function getClaudeDesktopConfigPath(options = {}) {
|
|
29
37
|
const dataDir = options.dataDir || getClaudeDesktopDataDir(options);
|
|
30
|
-
|
|
31
|
-
return path.join(dataDir, 'configLibrary');
|
|
38
|
+
return dataDir ? path.join(dataDir, 'claude_desktop_config.json') : null;
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return lib ? path.join(lib, '_meta.json') : null;
|
|
41
|
+
function getClaudeDesktopConfigLibraryDir(options = {}) {
|
|
42
|
+
const dataDir = options.dataDir || getClaudeDesktopDataDir(options);
|
|
43
|
+
return dataDir ? path.join(dataDir, 'configLibrary') : null;
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
function readJsonFile(file) {
|
|
@@ -45,11 +51,19 @@ function readJsonFile(file) {
|
|
|
45
51
|
}
|
|
46
52
|
}
|
|
47
53
|
|
|
54
|
+
function normalizeLegacyDesktopModelId(model) {
|
|
55
|
+
return model.replace(/\[\w+\]$/, '');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function toDesktopModelId(model) {
|
|
59
|
+
return model.startsWith('claude-') ? model : `claude-${model}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
48
62
|
function collectModels(config) {
|
|
49
63
|
const list = Array.isArray(config.availableModels) && config.availableModels.length > 0
|
|
50
64
|
? [config.model, config.fastModel, ...config.availableModels]
|
|
51
65
|
: [config.model, config.fastModel];
|
|
52
|
-
return [...new Set(list.filter(Boolean))];
|
|
66
|
+
return [...new Set(list.filter(Boolean).map(normalizeLegacyDesktopModelId).map(toDesktopModelId))];
|
|
53
67
|
}
|
|
54
68
|
|
|
55
69
|
// 按官方 schema:所有值必须是字符串(包括布尔、数组都序列化)
|
|
@@ -70,92 +84,104 @@ function buildClaudeDesktopEnterpriseConfig(config, options = {}) {
|
|
|
70
84
|
};
|
|
71
85
|
}
|
|
72
86
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return { result: 'unsupported', file: null };
|
|
87
|
+
function clearClaudeDesktopConfigLibrary(options = {}) {
|
|
88
|
+
const dir = options.configLibraryDir || getClaudeDesktopConfigLibraryDir(options);
|
|
89
|
+
if (!dir || !fs.existsSync(dir)) {
|
|
90
|
+
return { result: 'missing', dir };
|
|
78
91
|
}
|
|
79
92
|
|
|
80
|
-
|
|
93
|
+
const metaFile = path.join(dir, '_meta.json');
|
|
94
|
+
const meta = readJsonFile(metaFile);
|
|
95
|
+
const ids = new Set();
|
|
96
|
+
if (typeof meta.appliedId === 'string' && meta.appliedId) {
|
|
97
|
+
ids.add(meta.appliedId);
|
|
98
|
+
}
|
|
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);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
81
106
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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)) {
|
|
114
|
+
fs.unlinkSync(metaFile);
|
|
115
|
+
}
|
|
88
116
|
|
|
89
|
-
|
|
117
|
+
return { result: 'updated', dir };
|
|
118
|
+
}
|
|
90
119
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
120
|
+
// 旧版写法:写入 Claude-3p/claude_desktop_config.json,保留用户其他偏好。
|
|
121
|
+
function writeClaudeDesktopConfig(config, options = {}) {
|
|
122
|
+
const file = options.configFile || getClaudeDesktopConfigPath(options);
|
|
123
|
+
if (!file) {
|
|
124
|
+
return { result: 'unsupported', file: null };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const current = readJsonFile(file);
|
|
128
|
+
const existingEnterpriseConfig = current.enterpriseConfig && typeof current.enterpriseConfig === 'object'
|
|
129
|
+
? current.enterpriseConfig
|
|
130
|
+
: {};
|
|
131
|
+
const deploymentUuid = existingEnterpriseConfig.deploymentOrganizationUuid || options.uuid;
|
|
95
132
|
|
|
96
133
|
const enterpriseConfig = buildClaudeDesktopEnterpriseConfig(config, {
|
|
97
134
|
authScheme: options.authScheme,
|
|
98
135
|
uuid: deploymentUuid,
|
|
99
136
|
});
|
|
100
137
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const meta = {
|
|
109
|
-
appliedId: entryId,
|
|
110
|
-
entries: [
|
|
111
|
-
...otherEntries,
|
|
112
|
-
{
|
|
113
|
-
id: entryId,
|
|
114
|
-
name: CONFIG_NAME,
|
|
115
|
-
provider: 'gateway',
|
|
116
|
-
note: enterpriseConfig.inferenceGatewayBaseUrl,
|
|
117
|
-
},
|
|
118
|
-
],
|
|
138
|
+
const next = {
|
|
139
|
+
...current,
|
|
140
|
+
deploymentMode: '3p',
|
|
141
|
+
enterpriseConfig: {
|
|
142
|
+
...existingEnterpriseConfig,
|
|
143
|
+
...enterpriseConfig,
|
|
144
|
+
},
|
|
119
145
|
};
|
|
120
|
-
fs.writeFileSync(metaFile, JSON.stringify(meta, null, 2) + '\n');
|
|
121
146
|
|
|
122
|
-
|
|
147
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
148
|
+
const before = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
|
|
149
|
+
const body = JSON.stringify(next, null, 2) + '\n';
|
|
150
|
+
fs.writeFileSync(file, body);
|
|
151
|
+
clearClaudeDesktopConfigLibrary({ ...options, dataDir: path.dirname(file) });
|
|
152
|
+
return { result: before === body ? 'unchanged' : 'updated', file };
|
|
123
153
|
}
|
|
124
154
|
|
|
125
155
|
function clearClaudeDesktopConfig(options = {}) {
|
|
126
|
-
const
|
|
127
|
-
if (!
|
|
128
|
-
return { result: 'missing', file
|
|
156
|
+
const file = options.configFile || getClaudeDesktopConfigPath(options);
|
|
157
|
+
if (!file || !fs.existsSync(file)) {
|
|
158
|
+
return { result: 'missing', file };
|
|
129
159
|
}
|
|
130
160
|
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const yingclawEntry = entries.find(e => e.name === CONFIG_NAME);
|
|
135
|
-
|
|
136
|
-
if (!yingclawEntry) {
|
|
137
|
-
return { result: 'missing', file: lib };
|
|
161
|
+
const current = readJsonFile(file);
|
|
162
|
+
if (!current.enterpriseConfig || typeof current.enterpriseConfig !== 'object') {
|
|
163
|
+
return { result: 'missing', file };
|
|
138
164
|
}
|
|
139
165
|
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
fs.unlinkSync(configFile);
|
|
166
|
+
const enterpriseConfig = { ...current.enterpriseConfig };
|
|
167
|
+
for (const key of DESKTOP_GATEWAY_KEYS) {
|
|
168
|
+
delete enterpriseConfig[key];
|
|
144
169
|
}
|
|
145
170
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
fs.unlinkSync(metaFile);
|
|
171
|
+
const next = { ...current };
|
|
172
|
+
if (Object.keys(enterpriseConfig).length > 0) {
|
|
173
|
+
next.enterpriseConfig = enterpriseConfig;
|
|
150
174
|
} else {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
fs.writeFileSync(metaFile, JSON.stringify(newMeta, null, 2) + '\n');
|
|
175
|
+
delete next.enterpriseConfig;
|
|
176
|
+
}
|
|
177
|
+
if (Object.keys(next).length === 1 && next.deploymentMode === '3p') {
|
|
178
|
+
delete next.deploymentMode;
|
|
156
179
|
}
|
|
157
180
|
|
|
158
|
-
|
|
181
|
+
fs.writeFileSync(file, JSON.stringify(next, null, 2) + '\n');
|
|
182
|
+
clearClaudeDesktopConfigLibrary({ ...options, dataDir: path.dirname(file) });
|
|
183
|
+
|
|
184
|
+
return { result: 'updated', file };
|
|
159
185
|
}
|
|
160
186
|
|
|
161
187
|
function buildClaudeDesktopOpenCommands(platform = process.platform) {
|
|
@@ -181,10 +207,11 @@ async function openClaudeDesktop(options = {}) {
|
|
|
181
207
|
|
|
182
208
|
const runner = options.runner || spawnSync;
|
|
183
209
|
const isMocked = options.runner !== undefined;
|
|
210
|
+
const timeoutMs = options.timeoutMs || 5000;
|
|
184
211
|
|
|
185
212
|
const trace = [];
|
|
186
213
|
for (const { command, args, optional, waitAfter } of commands) {
|
|
187
|
-
const result = runner(command, args, { stdio: 'pipe', encoding: 'utf8', windowsHide: true });
|
|
214
|
+
const result = runner(command, args, { stdio: 'pipe', encoding: 'utf8', windowsHide: true, timeout: timeoutMs });
|
|
188
215
|
const stderr = (result.stderr || '').toString().trim();
|
|
189
216
|
trace.push({ command, args, status: result.status, stderr });
|
|
190
217
|
|
|
@@ -207,7 +234,6 @@ module.exports = {
|
|
|
207
234
|
clearClaudeDesktopConfig,
|
|
208
235
|
getClaudeDesktopConfigPath,
|
|
209
236
|
getClaudeDesktopDataDir,
|
|
210
|
-
getClaudeDesktopConfigLibrary,
|
|
211
237
|
openClaudeDesktop,
|
|
212
238
|
writeClaudeDesktopConfig,
|
|
213
239
|
CLAUDE_DESKTOP_LABEL,
|