yingclaw 1.9.1 → 2.0.1
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 +4 -4
- package/lib/desktop.js +101 -52
- 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
|
|
@@ -124,10 +124,10 @@ npm uninstall -g yingclaw
|
|
|
124
124
|
|
|
125
125
|
`claw desktop` 会额外写入 Claude Desktop 第三方推理配置:
|
|
126
126
|
|
|
127
|
-
- macOS:`~/Library/Application Support/Claude-3p/
|
|
128
|
-
- Windows:`%
|
|
127
|
+
- macOS:`~/Library/Application Support/Claude-3p/configLibrary/`
|
|
128
|
+
- Windows:`%LOCALAPPDATA%\Claude-3p\configLibrary`
|
|
129
129
|
|
|
130
|
-
写入的 `enterpriseConfig` 使用 `inferenceProvider=gateway`、`inferenceGatewayAuthScheme=bearer
|
|
130
|
+
写入的 `enterpriseConfig` 使用 `inferenceProvider=gateway`、`inferenceGatewayAuthScheme=bearer`,并把可用于 Claude 桌面的模型路由写入 `inferenceModels`。DeepSeek 的终端模型仍使用 `deepseek-v4-pro[1m]` / `deepseek-v4-flash`;Claude 桌面应用会使用 DeepSeek 支持的 Anthropic 路由名:`claude-sonnet-4-5`、`claude-opus-4-5`、`claude-haiku-4-5`。
|
|
131
131
|
|
|
132
132
|
## License
|
|
133
133
|
|
package/lib/desktop.js
CHANGED
|
@@ -6,32 +6,37 @@ const { spawnSync } = require('child_process');
|
|
|
6
6
|
const { normalizeAnthropicBaseUrl } = require('./config');
|
|
7
7
|
|
|
8
8
|
const CLAUDE_DESKTOP_LABEL = 'Claude 桌面应用配置';
|
|
9
|
-
const
|
|
10
|
-
'inferenceProvider',
|
|
11
|
-
'inferenceGatewayBaseUrl',
|
|
12
|
-
'inferenceGatewayApiKey',
|
|
13
|
-
'inferenceGatewayAuthScheme',
|
|
14
|
-
'inferenceModels',
|
|
15
|
-
'disableDeploymentModeChooser',
|
|
16
|
-
'deploymentOrganizationUuid',
|
|
17
|
-
];
|
|
9
|
+
const CONFIG_NAME = 'yingclaw';
|
|
18
10
|
|
|
19
|
-
|
|
11
|
+
// Claude 3P 数据目录(与 1P 的 Claude/ 目录区分)
|
|
12
|
+
function getClaudeDesktopDataDir(options = {}) {
|
|
20
13
|
const platform = options.platform || process.platform;
|
|
21
14
|
const homeDir = options.homeDir || os.homedir();
|
|
22
15
|
|
|
23
16
|
if (platform === 'darwin') {
|
|
24
|
-
return path.join(homeDir, 'Library', 'Application Support', 'Claude'
|
|
17
|
+
return path.join(homeDir, 'Library', 'Application Support', 'Claude-3p');
|
|
25
18
|
}
|
|
26
19
|
|
|
27
20
|
if (platform === 'win32') {
|
|
28
|
-
const
|
|
29
|
-
return path.join(
|
|
21
|
+
const localAppData = options.localAppData || process.env.LOCALAPPDATA || path.join(homeDir, 'AppData', 'Local');
|
|
22
|
+
return path.join(localAppData, 'Claude-3p');
|
|
30
23
|
}
|
|
31
24
|
|
|
32
25
|
return null;
|
|
33
26
|
}
|
|
34
27
|
|
|
28
|
+
function getClaudeDesktopConfigLibrary(options = {}) {
|
|
29
|
+
const dataDir = options.dataDir || getClaudeDesktopDataDir(options);
|
|
30
|
+
if (!dataDir) return null;
|
|
31
|
+
return path.join(dataDir, 'configLibrary');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 兼容旧测试名(指向 _meta.json 入口)
|
|
35
|
+
function getClaudeDesktopConfigPath(options = {}) {
|
|
36
|
+
const lib = getClaudeDesktopConfigLibrary(options);
|
|
37
|
+
return lib ? path.join(lib, '_meta.json') : null;
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
function readJsonFile(file) {
|
|
36
41
|
try {
|
|
37
42
|
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
@@ -40,15 +45,27 @@ function readJsonFile(file) {
|
|
|
40
45
|
}
|
|
41
46
|
}
|
|
42
47
|
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
function isDeepSeekConfig(config) {
|
|
49
|
+
const baseUrl = normalizeAnthropicBaseUrl(config.baseUrl);
|
|
50
|
+
return config.provider === 'deepseek' || baseUrl === 'https://api.deepseek.com/anthropic';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getDesktopGatewayModels(config) {
|
|
54
|
+
if (isDeepSeekConfig(config)) {
|
|
55
|
+
return ['claude-sonnet-4-5', 'claude-opus-4-5', 'claude-haiku-4-5'];
|
|
56
|
+
}
|
|
57
|
+
|
|
46
58
|
const list = Array.isArray(config.availableModels) && config.availableModels.length > 0
|
|
47
59
|
? [config.model, config.fastModel, ...config.availableModels]
|
|
48
60
|
: [config.model, config.fastModel];
|
|
49
|
-
return
|
|
61
|
+
return list.filter(Boolean);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function collectModels(config) {
|
|
65
|
+
return [...new Set(getDesktopGatewayModels(config))];
|
|
50
66
|
}
|
|
51
67
|
|
|
68
|
+
// 按官方 schema:所有值必须是字符串(包括布尔、数组都序列化)
|
|
52
69
|
function buildClaudeDesktopEnterpriseConfig(config, options = {}) {
|
|
53
70
|
const models = collectModels(config);
|
|
54
71
|
const baseUrl = normalizeAnthropicBaseUrl(config.baseUrl);
|
|
@@ -66,67 +83,97 @@ function buildClaudeDesktopEnterpriseConfig(config, options = {}) {
|
|
|
66
83
|
};
|
|
67
84
|
}
|
|
68
85
|
|
|
86
|
+
// 写入官方 3P 配置目录:configLibrary/_meta.json + configLibrary/<id>.json
|
|
69
87
|
function writeClaudeDesktopConfig(config, options = {}) {
|
|
70
|
-
const
|
|
71
|
-
if (!
|
|
88
|
+
const lib = options.configLibrary || getClaudeDesktopConfigLibrary(options);
|
|
89
|
+
if (!lib) {
|
|
72
90
|
return { result: 'unsupported', file: null };
|
|
73
91
|
}
|
|
74
92
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
93
|
+
fs.mkdirSync(lib, { recursive: true });
|
|
94
|
+
|
|
95
|
+
// 读已有 _meta.json,复用 entry id(保持稳定 UUID)
|
|
96
|
+
const metaFile = path.join(lib, '_meta.json');
|
|
97
|
+
const existingMeta = readJsonFile(metaFile);
|
|
98
|
+
const existingEntry = Array.isArray(existingMeta.entries)
|
|
99
|
+
? existingMeta.entries.find(e => e.name === CONFIG_NAME)
|
|
100
|
+
: null;
|
|
101
|
+
|
|
102
|
+
const entryId = existingEntry?.id || crypto.randomUUID();
|
|
103
|
+
|
|
104
|
+
// 读已有 <id>.json,复用 deploymentOrganizationUuid
|
|
105
|
+
const configFile = path.join(lib, `${entryId}.json`);
|
|
106
|
+
const existingConfig = readJsonFile(configFile);
|
|
107
|
+
const deploymentUuid = existingConfig.deploymentOrganizationUuid || options.uuid;
|
|
108
|
+
|
|
80
109
|
const enterpriseConfig = buildClaudeDesktopEnterpriseConfig(config, {
|
|
81
110
|
authScheme: options.authScheme,
|
|
82
|
-
uuid:
|
|
111
|
+
uuid: deploymentUuid,
|
|
83
112
|
});
|
|
84
113
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
114
|
+
// 写 <id>.json
|
|
115
|
+
fs.writeFileSync(configFile, JSON.stringify(enterpriseConfig, null, 2) + '\n');
|
|
116
|
+
|
|
117
|
+
// 更新 _meta.json:appliedId + entries(复用其他 entry,仅替换 yingclaw 这一条)
|
|
118
|
+
const otherEntries = Array.isArray(existingMeta.entries)
|
|
119
|
+
? existingMeta.entries.filter(e => e.name !== CONFIG_NAME)
|
|
120
|
+
: [];
|
|
121
|
+
const meta = {
|
|
122
|
+
appliedId: entryId,
|
|
123
|
+
entries: [
|
|
124
|
+
...otherEntries,
|
|
125
|
+
{
|
|
126
|
+
id: entryId,
|
|
127
|
+
name: CONFIG_NAME,
|
|
128
|
+
provider: 'gateway',
|
|
129
|
+
note: enterpriseConfig.inferenceGatewayBaseUrl,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
91
132
|
};
|
|
133
|
+
fs.writeFileSync(metaFile, JSON.stringify(meta, null, 2) + '\n');
|
|
92
134
|
|
|
93
|
-
|
|
94
|
-
const before = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
|
|
95
|
-
const body = JSON.stringify(next, null, 2) + '\n';
|
|
96
|
-
fs.writeFileSync(file, body);
|
|
97
|
-
return { result: before === body ? 'unchanged' : 'updated', file };
|
|
135
|
+
return { result: 'updated', file: lib, entryId };
|
|
98
136
|
}
|
|
99
137
|
|
|
100
138
|
function clearClaudeDesktopConfig(options = {}) {
|
|
101
|
-
const
|
|
102
|
-
if (!
|
|
103
|
-
return { result: 'missing', file };
|
|
139
|
+
const lib = options.configLibrary || getClaudeDesktopConfigLibrary(options);
|
|
140
|
+
if (!lib || !fs.existsSync(lib)) {
|
|
141
|
+
return { result: 'missing', file: lib };
|
|
104
142
|
}
|
|
105
143
|
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
144
|
+
const metaFile = path.join(lib, '_meta.json');
|
|
145
|
+
const meta = readJsonFile(metaFile);
|
|
146
|
+
const entries = Array.isArray(meta.entries) ? meta.entries : [];
|
|
147
|
+
const yingclawEntry = entries.find(e => e.name === CONFIG_NAME);
|
|
148
|
+
|
|
149
|
+
if (!yingclawEntry) {
|
|
150
|
+
return { result: 'missing', file: lib };
|
|
109
151
|
}
|
|
110
152
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
153
|
+
// 删除 <id>.json
|
|
154
|
+
const configFile = path.join(lib, `${yingclawEntry.id}.json`);
|
|
155
|
+
if (fs.existsSync(configFile)) {
|
|
156
|
+
fs.unlinkSync(configFile);
|
|
114
157
|
}
|
|
115
158
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
159
|
+
// 更新 _meta.json
|
|
160
|
+
const remaining = entries.filter(e => e.name !== CONFIG_NAME);
|
|
161
|
+
if (remaining.length === 0) {
|
|
162
|
+
fs.unlinkSync(metaFile);
|
|
119
163
|
} else {
|
|
120
|
-
|
|
164
|
+
const newMeta = {
|
|
165
|
+
appliedId: meta.appliedId === yingclawEntry.id ? (remaining[0]?.id || '') : meta.appliedId,
|
|
166
|
+
entries: remaining,
|
|
167
|
+
};
|
|
168
|
+
fs.writeFileSync(metaFile, JSON.stringify(newMeta, null, 2) + '\n');
|
|
121
169
|
}
|
|
122
170
|
|
|
123
|
-
|
|
124
|
-
return { result: 'updated', file };
|
|
171
|
+
return { result: 'updated', file: lib };
|
|
125
172
|
}
|
|
126
173
|
|
|
127
174
|
function buildClaudeDesktopOpenCommands(platform = process.platform) {
|
|
128
175
|
if (platform !== 'darwin') return null;
|
|
129
|
-
//
|
|
176
|
+
// 必须先完全退出 Claude,新配置只在启动时读取一次
|
|
130
177
|
return [
|
|
131
178
|
{ command: 'osascript', args: ['-e', 'tell application "Claude" to quit'], optional: true, waitAfter: 800 },
|
|
132
179
|
{ command: 'pkill', args: ['-TERM', '-x', 'Claude'], optional: true, waitAfter: 500 },
|
|
@@ -172,6 +219,8 @@ module.exports = {
|
|
|
172
219
|
buildClaudeDesktopOpenCommands,
|
|
173
220
|
clearClaudeDesktopConfig,
|
|
174
221
|
getClaudeDesktopConfigPath,
|
|
222
|
+
getClaudeDesktopDataDir,
|
|
223
|
+
getClaudeDesktopConfigLibrary,
|
|
175
224
|
openClaudeDesktop,
|
|
176
225
|
writeClaudeDesktopConfig,
|
|
177
226
|
CLAUDE_DESKTOP_LABEL,
|