duojie-helper 0.2.21 → 0.2.23
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 +324 -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/index.js
CHANGED
|
@@ -1,323 +1,324 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import ora from 'ora';
|
|
3
|
-
import { configureClaudeCode } from './tools/claude.js';
|
|
4
|
-
import { configureOpenClaw } from './tools/openclaw.js';
|
|
5
|
-
import { configureCursor } from './tools/cursor.js';
|
|
6
|
-
import { configureCline } from './tools/cline.js';
|
|
7
|
-
import { configureCodex } from './tools/codex.js';
|
|
8
|
-
import { configureContinue } from './tools/continue.js';
|
|
9
|
-
import { configureOpenCode } from './tools/opencode.js';
|
|
10
|
-
import { configureDroid } from './tools/droid.js';
|
|
11
|
-
|
|
12
|
-
// API 配置
|
|
13
|
-
export const API_CONFIG = {
|
|
14
|
-
baseUrl: 'https://api.duojie.games',
|
|
15
|
-
// 动态模型列表(运行时填充)
|
|
16
|
-
models: null,
|
|
17
|
-
// 原始模型数据(包含 endpoint 信息)
|
|
18
|
-
rawModels: null,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function normalizeBaseUrl(url) {
|
|
22
|
-
return `${url || ''}`.replace(/\/+$/, '');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function withV1(url) {
|
|
26
|
-
const normalized = normalizeBaseUrl(url);
|
|
27
|
-
return normalized.endsWith('/v1') ? normalized : `${normalized}/v1`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function withoutV1(url) {
|
|
31
|
-
const normalized = normalizeBaseUrl(url);
|
|
32
|
-
return normalized.endsWith('/v1') ? normalized.slice(0, -3) : normalized;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function getApiBaseForProtocol(protocol = '') {
|
|
36
|
-
const normalizedProtocol = `${protocol}`.toLowerCase();
|
|
37
|
-
|
|
38
|
-
const openaiProtocols = new Set([
|
|
39
|
-
'openai',
|
|
40
|
-
'openai-response',
|
|
41
|
-
'openai-responses',
|
|
42
|
-
'openai-completion',
|
|
43
|
-
'openai-completions',
|
|
44
|
-
'responses',
|
|
45
|
-
'chat',
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
*
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
'
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
console.log(chalk.
|
|
265
|
-
console.log(chalk.gray(`
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { configureClaudeCode } from './tools/claude.js';
|
|
4
|
+
import { configureOpenClaw } from './tools/openclaw.js';
|
|
5
|
+
import { configureCursor } from './tools/cursor.js';
|
|
6
|
+
import { configureCline } from './tools/cline.js';
|
|
7
|
+
import { configureCodex } from './tools/codex.js';
|
|
8
|
+
import { configureContinue } from './tools/continue.js';
|
|
9
|
+
import { configureOpenCode } from './tools/opencode.js';
|
|
10
|
+
import { configureDroid } from './tools/droid.js';
|
|
11
|
+
|
|
12
|
+
// API 配置
|
|
13
|
+
export const API_CONFIG = {
|
|
14
|
+
baseUrl: 'https://api.duojie.games',
|
|
15
|
+
// 动态模型列表(运行时填充)
|
|
16
|
+
models: null,
|
|
17
|
+
// 原始模型数据(包含 endpoint 信息)
|
|
18
|
+
rawModels: null,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function normalizeBaseUrl(url) {
|
|
22
|
+
return `${url || ''}`.replace(/\/+$/, '');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function withV1(url) {
|
|
26
|
+
const normalized = normalizeBaseUrl(url);
|
|
27
|
+
return normalized.endsWith('/v1') ? normalized : `${normalized}/v1`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function withoutV1(url) {
|
|
31
|
+
const normalized = normalizeBaseUrl(url);
|
|
32
|
+
return normalized.endsWith('/v1') ? normalized.slice(0, -3) : normalized;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getApiBaseForProtocol(protocol = '') {
|
|
36
|
+
const normalizedProtocol = `${protocol}`.toLowerCase();
|
|
37
|
+
|
|
38
|
+
const openaiProtocols = new Set([
|
|
39
|
+
'openai',
|
|
40
|
+
'openai-response',
|
|
41
|
+
'openai-responses',
|
|
42
|
+
'openai-completion',
|
|
43
|
+
'openai-completions',
|
|
44
|
+
'responses',
|
|
45
|
+
'chat',
|
|
46
|
+
'generic-chat-completion-api',
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
if (openaiProtocols.has(normalizedProtocol)) {
|
|
50
|
+
return withV1(API_CONFIG.baseUrl);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return withoutV1(API_CONFIG.baseUrl);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 从 pricing 页面获取公开模型 ID 集合
|
|
58
|
+
* 返回 null 表示获取失败,调用方应跳过过滤
|
|
59
|
+
*/
|
|
60
|
+
async function fetchPublicModelIds(apiKey) {
|
|
61
|
+
try {
|
|
62
|
+
const response = await fetch(`${API_CONFIG.baseUrl}/pricing`, {
|
|
63
|
+
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) return null;
|
|
66
|
+
const html = await response.text();
|
|
67
|
+
const ids = new Set();
|
|
68
|
+
for (const m of (html.match(/###\s+([^\n\r]+)/g) || [])) {
|
|
69
|
+
ids.add(m.replace(/^###\s+/, '').trim());
|
|
70
|
+
}
|
|
71
|
+
return ids.size > 0 ? ids : null;
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 从 API 获取模型列表
|
|
79
|
+
*/
|
|
80
|
+
export async function fetchModels(apiKey) {
|
|
81
|
+
try {
|
|
82
|
+
const [response, publicIds] = await Promise.all([
|
|
83
|
+
fetch(`${API_CONFIG.baseUrl}/v1/models`, {
|
|
84
|
+
headers: {
|
|
85
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
86
|
+
'Content-Type': 'application/json',
|
|
87
|
+
},
|
|
88
|
+
}),
|
|
89
|
+
fetchPublicModelIds(apiKey),
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new Error(`HTTP ${response.status}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const data = await response.json();
|
|
97
|
+
|
|
98
|
+
// 保存原始数据
|
|
99
|
+
API_CONFIG.rawModels = data.data || [];
|
|
100
|
+
|
|
101
|
+
// 解析模型列表,根据 ID 和 supported_endpoint_types 分类
|
|
102
|
+
const models = { claude: [], gpt: [], gemini: [], other: [] };
|
|
103
|
+
|
|
104
|
+
if (data.data && Array.isArray(data.data)) {
|
|
105
|
+
for (const model of data.data) {
|
|
106
|
+
const id = model.id;
|
|
107
|
+
// 跳过未在 pricing 页面公开的隐藏模型
|
|
108
|
+
if (publicIds && !publicIds.has(id)) continue;
|
|
109
|
+
// 跳过含 image 的模型(图像生成类,不支持对话)
|
|
110
|
+
if (id.toLowerCase().includes('image')) continue;
|
|
111
|
+
const endpoints = model.supported_endpoint_types || [];
|
|
112
|
+
|
|
113
|
+
// 判断最佳协议:GPT 用 openai,其余统一用 anthropic-messages
|
|
114
|
+
let api = 'anthropic-messages'; // 默认
|
|
115
|
+
if (id.startsWith('gpt')) {
|
|
116
|
+
// GPT 模型优先用 openai-responses,否则 openai-completions
|
|
117
|
+
if (endpoints.includes('openai-response')) {
|
|
118
|
+
api = 'openai-responses';
|
|
119
|
+
} else {
|
|
120
|
+
api = 'openai-completions';
|
|
121
|
+
}
|
|
122
|
+
models.gpt.push({ id, name: id, api, endpoints });
|
|
123
|
+
} else if (id.startsWith('claude')) {
|
|
124
|
+
models.claude.push({ id, name: id, api, endpoints });
|
|
125
|
+
} else if (id.startsWith('gemini')) {
|
|
126
|
+
models.gemini.push({ id, name: id, api, endpoints });
|
|
127
|
+
} else if (id.startsWith('glm')) {
|
|
128
|
+
models.other.push({ id, name: id, api: 'openai-completions', endpoints });
|
|
129
|
+
} else {
|
|
130
|
+
models.other.push({ id, name: id, api, endpoints });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 缓存结果
|
|
136
|
+
API_CONFIG.models = models;
|
|
137
|
+
return models;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.log(chalk.yellow(`⚠ 无法获取模型列表: ${error.message}`));
|
|
140
|
+
return { claude: [], gpt: [], gemini: [], other: [] };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 获取模型列表(优先使用缓存)
|
|
146
|
+
*/
|
|
147
|
+
export function getModels() {
|
|
148
|
+
return API_CONFIG.models || { claude: [], gpt: [], gemini: [], other: [] };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 获取原始模型数据
|
|
153
|
+
*/
|
|
154
|
+
export function getRawModels() {
|
|
155
|
+
return API_CONFIG.rawModels || [];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 工具配置器映射
|
|
159
|
+
const toolConfigurators = {
|
|
160
|
+
claude: configureClaudeCode,
|
|
161
|
+
openclaw: configureOpenClaw,
|
|
162
|
+
cursor: configureCursor,
|
|
163
|
+
cline: configureCline,
|
|
164
|
+
codex: configureCodex,
|
|
165
|
+
continue: configureContinue,
|
|
166
|
+
opencode: configureOpenCode,
|
|
167
|
+
droid: configureDroid,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// 工具信息
|
|
171
|
+
const toolInfo = {
|
|
172
|
+
claude: {
|
|
173
|
+
name: 'Claude Code',
|
|
174
|
+
description: 'Anthropic 官方 CLI 工具(自动配置)',
|
|
175
|
+
configPath: '~/.claude/settings.json',
|
|
176
|
+
},
|
|
177
|
+
droid: {
|
|
178
|
+
name: 'Droid',
|
|
179
|
+
description: 'Factory 的 AI 编程工具(自动配置)',
|
|
180
|
+
configPath: '~/.factory/config.json',
|
|
181
|
+
},
|
|
182
|
+
openclaw: {
|
|
183
|
+
name: 'OpenClaw / Moltbot',
|
|
184
|
+
description: '多平台 AI 助手网关(自动配置)',
|
|
185
|
+
configPath: '~/.openclaw/openclaw.json',
|
|
186
|
+
},
|
|
187
|
+
opencode: {
|
|
188
|
+
name: 'OpenCode',
|
|
189
|
+
description: '终端 AI 编码助手(自动配置)',
|
|
190
|
+
configPath: '~/.config/opencode/opencode.json',
|
|
191
|
+
},
|
|
192
|
+
continue: {
|
|
193
|
+
name: 'Continue',
|
|
194
|
+
description: 'VS Code/JetBrains AI 插件(自动配置)',
|
|
195
|
+
configPath: '~/.continue/config.json',
|
|
196
|
+
},
|
|
197
|
+
codex: {
|
|
198
|
+
name: 'Codex CLI',
|
|
199
|
+
description: 'OpenAI Codex 命令行工具(自动配置)',
|
|
200
|
+
configPath: '~/.codex/config.toml',
|
|
201
|
+
},
|
|
202
|
+
cursor: {
|
|
203
|
+
name: 'Cursor',
|
|
204
|
+
description: 'AI 代码编辑器(需手动配置,需 Pro 订阅)',
|
|
205
|
+
configPath: 'Cursor Settings → Models',
|
|
206
|
+
},
|
|
207
|
+
cline: {
|
|
208
|
+
name: 'Cline',
|
|
209
|
+
description: 'VS Code AI 编程插件(需手动配置)',
|
|
210
|
+
configPath: 'Cline 插件设置',
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 配置所有选中的工具
|
|
216
|
+
*/
|
|
217
|
+
export async function configureAll(apiKey, tools) {
|
|
218
|
+
const results = [];
|
|
219
|
+
|
|
220
|
+
for (const tool of tools) {
|
|
221
|
+
const configurator = toolConfigurators[tool];
|
|
222
|
+
if (configurator) {
|
|
223
|
+
try {
|
|
224
|
+
const result = await configurator(apiKey);
|
|
225
|
+
results.push({ tool: toolInfo[tool]?.name || tool, ...result });
|
|
226
|
+
} catch (error) {
|
|
227
|
+
results.push({
|
|
228
|
+
tool: toolInfo[tool]?.name || tool,
|
|
229
|
+
success: false,
|
|
230
|
+
message: error.message,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
results.push({
|
|
235
|
+
tool,
|
|
236
|
+
success: false,
|
|
237
|
+
message: '暂不支持该工具',
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return results;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* 配置单个工具
|
|
247
|
+
*/
|
|
248
|
+
export async function configureTool(tool, apiKey) {
|
|
249
|
+
const configurator = toolConfigurators[tool];
|
|
250
|
+
if (!configurator) {
|
|
251
|
+
return { success: false, message: `不支持的工具: ${tool}` };
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return await configurator(apiKey);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* 列出支持的工具
|
|
259
|
+
*/
|
|
260
|
+
export function listTools() {
|
|
261
|
+
console.log(chalk.cyan('\n📋 支持的工具列表:\n'));
|
|
262
|
+
|
|
263
|
+
for (const [key, info] of Object.entries(toolInfo)) {
|
|
264
|
+
console.log(chalk.green(` ${key.padEnd(12)}`), chalk.white(info.name));
|
|
265
|
+
console.log(chalk.gray(` ${info.description}`));
|
|
266
|
+
console.log(chalk.gray(` 配置路径: ${info.configPath}\n`));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* 显示当前配置状态
|
|
272
|
+
*/
|
|
273
|
+
export async function showStatus() {
|
|
274
|
+
console.log(chalk.cyan('\n📊 配置状态:\n'));
|
|
275
|
+
|
|
276
|
+
for (const [tool, info] of Object.entries(toolInfo)) {
|
|
277
|
+
const configurator = toolConfigurators[tool];
|
|
278
|
+
if (configurator && configurator.checkStatus) {
|
|
279
|
+
try {
|
|
280
|
+
const status = await configurator.checkStatus();
|
|
281
|
+
const icon = status.configured ? chalk.green('✓') : chalk.gray('○');
|
|
282
|
+
console.log(` ${icon} ${info.name.padEnd(20)} ${status.message || ''}`);
|
|
283
|
+
} catch {
|
|
284
|
+
console.log(` ${chalk.gray('○')} ${info.name.padEnd(20)} ${chalk.gray('未检测到')}`);
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
console.log(` ${chalk.gray('?')} ${info.name.padEnd(20)} ${chalk.gray('状态检测暂不支持')}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
console.log('');
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* 撤销配置
|
|
295
|
+
*/
|
|
296
|
+
export async function revokeKey(tool) {
|
|
297
|
+
const spinner = ora('正在撤销配置...').start();
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
if (tool) {
|
|
301
|
+
const configurator = toolConfigurators[tool];
|
|
302
|
+
if (configurator && configurator.revoke) {
|
|
303
|
+
await configurator.revoke();
|
|
304
|
+
spinner.succeed(`已撤销 ${toolInfo[tool]?.name || tool} 的配置`);
|
|
305
|
+
} else {
|
|
306
|
+
spinner.warn(`${tool} 暂不支持撤销操作`);
|
|
307
|
+
}
|
|
308
|
+
} else {
|
|
309
|
+
// 撤销所有
|
|
310
|
+
for (const [key, configurator] of Object.entries(toolConfigurators)) {
|
|
311
|
+
if (configurator.revoke) {
|
|
312
|
+
try {
|
|
313
|
+
await configurator.revoke();
|
|
314
|
+
} catch {
|
|
315
|
+
// 忽略单个工具的错误
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
spinner.succeed('已撤销所有配置');
|
|
320
|
+
}
|
|
321
|
+
} catch (error) {
|
|
322
|
+
spinner.fail(`撤销失败: ${error.message}`);
|
|
323
|
+
}
|
|
324
|
+
}
|