duojie-helper 0.2.21 → 0.2.22
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 +160 -160
- package/bin/cli.js +328 -328
- package/package.json +53 -53
- package/src/index.js +323 -323
- package/src/tools/claude.js +198 -198
- package/src/tools/cline.js +103 -103
- package/src/tools/codex.js +154 -154
- package/src/tools/continue.js +158 -158
- package/src/tools/cursor.js +99 -99
- package/src/tools/droid.js +262 -261
- package/src/tools/openclaw.js +292 -292
- package/src/tools/opencode.js +216 -216
package/src/tools/opencode.js
CHANGED
|
@@ -1,216 +1,216 @@
|
|
|
1
|
-
import fs from 'fs-extra';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import { API_CONFIG, getModels } from '../index.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 获取 OpenCode 配置路径
|
|
8
|
-
*/
|
|
9
|
-
function getOpenCodeConfigPaths() {
|
|
10
|
-
const home = os.homedir();
|
|
11
|
-
|
|
12
|
-
// OpenCode 统一使用 ~/.config/opencode 目录
|
|
13
|
-
const configDir = path.join(home, '.config', 'opencode');
|
|
14
|
-
|
|
15
|
-
return {
|
|
16
|
-
configDir,
|
|
17
|
-
configFile: path.join(configDir, 'opencode.json'),
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 配置 OpenCode
|
|
23
|
-
* 自动配置所有可用模型
|
|
24
|
-
*/
|
|
25
|
-
export async function configureOpenCode(apiKey) {
|
|
26
|
-
const paths = getOpenCodeConfigPaths();
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
// 确保目录存在
|
|
30
|
-
await fs.ensureDir(paths.configDir);
|
|
31
|
-
|
|
32
|
-
// 1. 读取现有配置(如果存在)
|
|
33
|
-
let existingConfig = {};
|
|
34
|
-
if (await fs.pathExists(paths.configFile)) {
|
|
35
|
-
try {
|
|
36
|
-
existingConfig = await fs.readJson(paths.configFile);
|
|
37
|
-
} catch {
|
|
38
|
-
existingConfig = {};
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// 2. 获取模型列表
|
|
43
|
-
const models = getModels();
|
|
44
|
-
|
|
45
|
-
// 3. 构建 Duojie provider 的模型配置
|
|
46
|
-
const duojieModels = {};
|
|
47
|
-
|
|
48
|
-
// Claude 模型
|
|
49
|
-
for (const m of (models.claude || [])) {
|
|
50
|
-
duojieModels[m.id] = {
|
|
51
|
-
limit: {
|
|
52
|
-
context: 200000,
|
|
53
|
-
output: 16384,
|
|
54
|
-
},
|
|
55
|
-
modalities: {
|
|
56
|
-
input: ['text', 'image'],
|
|
57
|
-
output: ['text'],
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// GPT 模型
|
|
63
|
-
for (const m of (models.gpt || [])) {
|
|
64
|
-
duojieModels[m.id] = {
|
|
65
|
-
limit: {
|
|
66
|
-
context: 128000,
|
|
67
|
-
output: 16384,
|
|
68
|
-
},
|
|
69
|
-
modalities: {
|
|
70
|
-
input: ['text', 'image'],
|
|
71
|
-
output: ['text'],
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Gemini 模型
|
|
77
|
-
for (const m of (models.gemini || [])) {
|
|
78
|
-
duojieModels[m.id] = {
|
|
79
|
-
limit: {
|
|
80
|
-
context: 1000000,
|
|
81
|
-
output: 16384,
|
|
82
|
-
},
|
|
83
|
-
modalities: {
|
|
84
|
-
input: ['text', 'image'],
|
|
85
|
-
output: ['text'],
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// 其他模型
|
|
91
|
-
for (const m of (models.other || [])) {
|
|
92
|
-
duojieModels[m.id] = {
|
|
93
|
-
limit: {
|
|
94
|
-
context: 128000,
|
|
95
|
-
output: 4096,
|
|
96
|
-
},
|
|
97
|
-
modalities: {
|
|
98
|
-
input: ['text', 'image'],
|
|
99
|
-
output: ['text'],
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const totalModels = Object.keys(duojieModels).length;
|
|
105
|
-
|
|
106
|
-
if (totalModels === 0) {
|
|
107
|
-
return {
|
|
108
|
-
success: false,
|
|
109
|
-
message: '没有可用的模型',
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// 4. 构建 Duojie provider 配置
|
|
114
|
-
const duojieProvider = {
|
|
115
|
-
npm: '@ai-sdk/anthropic',
|
|
116
|
-
name: 'Duojie API',
|
|
117
|
-
options: {
|
|
118
|
-
baseURL: API_CONFIG.baseUrl,
|
|
119
|
-
},
|
|
120
|
-
models: duojieModels,
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
// 5. 合并配置(保留用户其他配置)
|
|
124
|
-
// 删除旧的 duojie provider
|
|
125
|
-
if (existingConfig.provider?.duojie) {
|
|
126
|
-
delete existingConfig.provider.duojie;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const preferredModel = duojieModels['gpt-5.2'] ? 'duojie/gpt-5.2' : null;
|
|
130
|
-
|
|
131
|
-
const newConfig = {
|
|
132
|
-
...existingConfig,
|
|
133
|
-
$schema: existingConfig.$schema || 'https://opencode.ai/config.json',
|
|
134
|
-
provider: {
|
|
135
|
-
...existingConfig.provider,
|
|
136
|
-
duojie: duojieProvider,
|
|
137
|
-
},
|
|
138
|
-
...(preferredModel ? { model: preferredModel } : {}),
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
// 6. 写入配置文件
|
|
142
|
-
await fs.writeJson(paths.configFile, newConfig, { spaces: 2 });
|
|
143
|
-
|
|
144
|
-
// 7. 提示用户设置环境变量
|
|
145
|
-
return {
|
|
146
|
-
success: true,
|
|
147
|
-
message: `已配置 ${totalModels} 个模型 → ${paths.configFile}`,
|
|
148
|
-
configPath: paths.configFile,
|
|
149
|
-
hint: '请设置环境变量 ANTHROPIC_API_KEY 或在 OpenCode 中配置 API Key',
|
|
150
|
-
};
|
|
151
|
-
} catch (error) {
|
|
152
|
-
return {
|
|
153
|
-
success: false,
|
|
154
|
-
message: `配置失败: ${error.message}`,
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* 检查 OpenCode 配置状态
|
|
161
|
-
*/
|
|
162
|
-
configureOpenCode.checkStatus = async function() {
|
|
163
|
-
const paths = getOpenCodeConfigPaths();
|
|
164
|
-
|
|
165
|
-
if (await fs.pathExists(paths.configFile)) {
|
|
166
|
-
try {
|
|
167
|
-
const config = await fs.readJson(paths.configFile);
|
|
168
|
-
|
|
169
|
-
if (config.provider?.duojie) {
|
|
170
|
-
const modelCount = Object.keys(config.provider.duojie.models || {}).length;
|
|
171
|
-
return {
|
|
172
|
-
configured: true,
|
|
173
|
-
message: `已配置 ${modelCount} 个 Duojie 模型`,
|
|
174
|
-
};
|
|
175
|
-
} else if (config.provider && Object.keys(config.provider).length > 0) {
|
|
176
|
-
return {
|
|
177
|
-
configured: true,
|
|
178
|
-
message: '已配置(非 Duojie)',
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
} catch {
|
|
182
|
-
// ignore
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return { configured: false };
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* 撤销 OpenCode 配置
|
|
191
|
-
*/
|
|
192
|
-
configureOpenCode.revoke = async function() {
|
|
193
|
-
const paths = getOpenCodeConfigPaths();
|
|
194
|
-
|
|
195
|
-
// 清理配置文件中的 duojie provider
|
|
196
|
-
if (await fs.pathExists(paths.configFile)) {
|
|
197
|
-
try {
|
|
198
|
-
const config = await fs.readJson(paths.configFile);
|
|
199
|
-
|
|
200
|
-
if (config.provider?.duojie) {
|
|
201
|
-
delete config.provider.duojie;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// 如果默认模型是 duojie 的,清除它
|
|
205
|
-
if (config.model?.startsWith('duojie/')) {
|
|
206
|
-
delete config.model;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
await fs.writeJson(paths.configFile, config, { spaces: 2 });
|
|
210
|
-
} catch {
|
|
211
|
-
// ignore
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
export default configureOpenCode;
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import { API_CONFIG, getModels } from '../index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 获取 OpenCode 配置路径
|
|
8
|
+
*/
|
|
9
|
+
function getOpenCodeConfigPaths() {
|
|
10
|
+
const home = os.homedir();
|
|
11
|
+
|
|
12
|
+
// OpenCode 统一使用 ~/.config/opencode 目录
|
|
13
|
+
const configDir = path.join(home, '.config', 'opencode');
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
configDir,
|
|
17
|
+
configFile: path.join(configDir, 'opencode.json'),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 配置 OpenCode
|
|
23
|
+
* 自动配置所有可用模型
|
|
24
|
+
*/
|
|
25
|
+
export async function configureOpenCode(apiKey) {
|
|
26
|
+
const paths = getOpenCodeConfigPaths();
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
// 确保目录存在
|
|
30
|
+
await fs.ensureDir(paths.configDir);
|
|
31
|
+
|
|
32
|
+
// 1. 读取现有配置(如果存在)
|
|
33
|
+
let existingConfig = {};
|
|
34
|
+
if (await fs.pathExists(paths.configFile)) {
|
|
35
|
+
try {
|
|
36
|
+
existingConfig = await fs.readJson(paths.configFile);
|
|
37
|
+
} catch {
|
|
38
|
+
existingConfig = {};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 2. 获取模型列表
|
|
43
|
+
const models = getModels();
|
|
44
|
+
|
|
45
|
+
// 3. 构建 Duojie provider 的模型配置
|
|
46
|
+
const duojieModels = {};
|
|
47
|
+
|
|
48
|
+
// Claude 模型
|
|
49
|
+
for (const m of (models.claude || [])) {
|
|
50
|
+
duojieModels[m.id] = {
|
|
51
|
+
limit: {
|
|
52
|
+
context: 200000,
|
|
53
|
+
output: 16384,
|
|
54
|
+
},
|
|
55
|
+
modalities: {
|
|
56
|
+
input: ['text', 'image'],
|
|
57
|
+
output: ['text'],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// GPT 模型
|
|
63
|
+
for (const m of (models.gpt || [])) {
|
|
64
|
+
duojieModels[m.id] = {
|
|
65
|
+
limit: {
|
|
66
|
+
context: 128000,
|
|
67
|
+
output: 16384,
|
|
68
|
+
},
|
|
69
|
+
modalities: {
|
|
70
|
+
input: ['text', 'image'],
|
|
71
|
+
output: ['text'],
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Gemini 模型
|
|
77
|
+
for (const m of (models.gemini || [])) {
|
|
78
|
+
duojieModels[m.id] = {
|
|
79
|
+
limit: {
|
|
80
|
+
context: 1000000,
|
|
81
|
+
output: 16384,
|
|
82
|
+
},
|
|
83
|
+
modalities: {
|
|
84
|
+
input: ['text', 'image'],
|
|
85
|
+
output: ['text'],
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 其他模型
|
|
91
|
+
for (const m of (models.other || [])) {
|
|
92
|
+
duojieModels[m.id] = {
|
|
93
|
+
limit: {
|
|
94
|
+
context: 128000,
|
|
95
|
+
output: 4096,
|
|
96
|
+
},
|
|
97
|
+
modalities: {
|
|
98
|
+
input: ['text', 'image'],
|
|
99
|
+
output: ['text'],
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const totalModels = Object.keys(duojieModels).length;
|
|
105
|
+
|
|
106
|
+
if (totalModels === 0) {
|
|
107
|
+
return {
|
|
108
|
+
success: false,
|
|
109
|
+
message: '没有可用的模型',
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 4. 构建 Duojie provider 配置
|
|
114
|
+
const duojieProvider = {
|
|
115
|
+
npm: '@ai-sdk/anthropic',
|
|
116
|
+
name: 'Duojie API',
|
|
117
|
+
options: {
|
|
118
|
+
baseURL: API_CONFIG.baseUrl,
|
|
119
|
+
},
|
|
120
|
+
models: duojieModels,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// 5. 合并配置(保留用户其他配置)
|
|
124
|
+
// 删除旧的 duojie provider
|
|
125
|
+
if (existingConfig.provider?.duojie) {
|
|
126
|
+
delete existingConfig.provider.duojie;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const preferredModel = duojieModels['gpt-5.2'] ? 'duojie/gpt-5.2' : null;
|
|
130
|
+
|
|
131
|
+
const newConfig = {
|
|
132
|
+
...existingConfig,
|
|
133
|
+
$schema: existingConfig.$schema || 'https://opencode.ai/config.json',
|
|
134
|
+
provider: {
|
|
135
|
+
...existingConfig.provider,
|
|
136
|
+
duojie: duojieProvider,
|
|
137
|
+
},
|
|
138
|
+
...(preferredModel ? { model: preferredModel } : {}),
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// 6. 写入配置文件
|
|
142
|
+
await fs.writeJson(paths.configFile, newConfig, { spaces: 2 });
|
|
143
|
+
|
|
144
|
+
// 7. 提示用户设置环境变量
|
|
145
|
+
return {
|
|
146
|
+
success: true,
|
|
147
|
+
message: `已配置 ${totalModels} 个模型 → ${paths.configFile}`,
|
|
148
|
+
configPath: paths.configFile,
|
|
149
|
+
hint: '请设置环境变量 ANTHROPIC_API_KEY 或在 OpenCode 中配置 API Key',
|
|
150
|
+
};
|
|
151
|
+
} catch (error) {
|
|
152
|
+
return {
|
|
153
|
+
success: false,
|
|
154
|
+
message: `配置失败: ${error.message}`,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 检查 OpenCode 配置状态
|
|
161
|
+
*/
|
|
162
|
+
configureOpenCode.checkStatus = async function() {
|
|
163
|
+
const paths = getOpenCodeConfigPaths();
|
|
164
|
+
|
|
165
|
+
if (await fs.pathExists(paths.configFile)) {
|
|
166
|
+
try {
|
|
167
|
+
const config = await fs.readJson(paths.configFile);
|
|
168
|
+
|
|
169
|
+
if (config.provider?.duojie) {
|
|
170
|
+
const modelCount = Object.keys(config.provider.duojie.models || {}).length;
|
|
171
|
+
return {
|
|
172
|
+
configured: true,
|
|
173
|
+
message: `已配置 ${modelCount} 个 Duojie 模型`,
|
|
174
|
+
};
|
|
175
|
+
} else if (config.provider && Object.keys(config.provider).length > 0) {
|
|
176
|
+
return {
|
|
177
|
+
configured: true,
|
|
178
|
+
message: '已配置(非 Duojie)',
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
} catch {
|
|
182
|
+
// ignore
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return { configured: false };
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* 撤销 OpenCode 配置
|
|
191
|
+
*/
|
|
192
|
+
configureOpenCode.revoke = async function() {
|
|
193
|
+
const paths = getOpenCodeConfigPaths();
|
|
194
|
+
|
|
195
|
+
// 清理配置文件中的 duojie provider
|
|
196
|
+
if (await fs.pathExists(paths.configFile)) {
|
|
197
|
+
try {
|
|
198
|
+
const config = await fs.readJson(paths.configFile);
|
|
199
|
+
|
|
200
|
+
if (config.provider?.duojie) {
|
|
201
|
+
delete config.provider.duojie;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 如果默认模型是 duojie 的,清除它
|
|
205
|
+
if (config.model?.startsWith('duojie/')) {
|
|
206
|
+
delete config.model;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
await fs.writeJson(paths.configFile, config, { spaces: 2 });
|
|
210
|
+
} catch {
|
|
211
|
+
// ignore
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
export default configureOpenCode;
|