@adversity/coding-tool-x 2.3.0 → 2.4.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/CHANGELOG.md +41 -0
- package/README.md +8 -0
- package/dist/web/assets/icons-Dom8a0SN.js +1 -0
- package/dist/web/assets/index-CQeUIH7E.css +41 -0
- package/dist/web/assets/index-YrjlFzC4.js +14 -0
- package/dist/web/assets/naive-ui-BjMHakwv.js +1 -0
- package/dist/web/assets/vendors-DtJKdpSj.js +7 -0
- package/dist/web/assets/vue-vendor-VFuFB5f4.js +44 -0
- package/dist/web/index.html +6 -2
- package/package.json +2 -2
- package/src/commands/export-config.js +205 -0
- package/src/config/default.js +1 -1
- package/src/server/api/config-export.js +122 -0
- package/src/server/api/config-sync.js +155 -0
- package/src/server/api/config-templates.js +12 -6
- package/src/server/api/health-check.js +1 -89
- package/src/server/api/permissions.js +92 -69
- package/src/server/api/projects.js +2 -2
- package/src/server/api/sessions.js +70 -70
- package/src/server/api/skills.js +206 -0
- package/src/server/api/terminal.js +26 -0
- package/src/server/index.js +7 -11
- package/src/server/services/config-export-service.js +415 -0
- package/src/server/services/config-sync-service.js +515 -0
- package/src/server/services/config-templates-service.js +61 -38
- package/src/server/services/enhanced-cache.js +196 -0
- package/src/server/services/health-check.js +1 -315
- package/src/server/services/permission-templates-service.js +339 -0
- package/src/server/services/pty-manager.js +35 -1
- package/src/server/services/sessions.js +122 -44
- package/src/server/services/skill-service.js +252 -2
- package/src/server/services/workspace-service.js +44 -84
- package/src/server/websocket-server.js +4 -1
- package/dist/web/assets/index-dhun1bYQ.js +0 -3555
- package/dist/web/assets/index-hHb7DAda.css +0 -41
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置导出/导入服务
|
|
3
|
+
* 支持权限模板、配置模板、频道配置的导出与导入
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const permissionTemplatesService = require('./permission-templates-service');
|
|
9
|
+
const configTemplatesService = require('./config-templates-service');
|
|
10
|
+
const channelsService = require('./channels');
|
|
11
|
+
|
|
12
|
+
const CONFIG_VERSION = '1.0.0';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 导出所有配置为JSON
|
|
16
|
+
* @returns {Object} 配置导出对象
|
|
17
|
+
*/
|
|
18
|
+
function exportAllConfigs() {
|
|
19
|
+
try {
|
|
20
|
+
// 获取所有权限模板(只导出自定义模板)
|
|
21
|
+
const allPermissionTemplates = permissionTemplatesService.getAllTemplates();
|
|
22
|
+
const customPermissionTemplates = allPermissionTemplates.filter(t => !t.isBuiltin);
|
|
23
|
+
|
|
24
|
+
// 获取所有配置模板(只导出自定义模板)
|
|
25
|
+
const allConfigTemplates = configTemplatesService.getAllTemplates();
|
|
26
|
+
const customConfigTemplates = allConfigTemplates.filter(t => !t.isBuiltin);
|
|
27
|
+
|
|
28
|
+
// 获取所有频道配置
|
|
29
|
+
const channelsData = channelsService.getAllChannels();
|
|
30
|
+
const channels = channelsData?.channels || [];
|
|
31
|
+
|
|
32
|
+
// 获取工作区配置
|
|
33
|
+
const workspaceService = require('./workspace-service');
|
|
34
|
+
const workspaces = workspaceService.loadWorkspaces();
|
|
35
|
+
|
|
36
|
+
// 获取收藏配置
|
|
37
|
+
const favoritesService = require('./favorites');
|
|
38
|
+
const favorites = favoritesService.loadFavorites();
|
|
39
|
+
|
|
40
|
+
// 获取 Agents 配置
|
|
41
|
+
const agentsService = require('./agents-service');
|
|
42
|
+
const agents = agentsService.getAllAgents();
|
|
43
|
+
|
|
44
|
+
// 获取 Skills 配置
|
|
45
|
+
const skillService = require('./skill-service');
|
|
46
|
+
const skills = skillService.getAllSkills();
|
|
47
|
+
|
|
48
|
+
// 获取 Commands 配置
|
|
49
|
+
const commandsService = require('./commands-service');
|
|
50
|
+
const commands = commandsService.getAllCommands();
|
|
51
|
+
|
|
52
|
+
// 获取 Rules 配置
|
|
53
|
+
const rulesService = require('./rules-service');
|
|
54
|
+
const rules = rulesService.getAllRules();
|
|
55
|
+
|
|
56
|
+
// 获取 MCP 配置
|
|
57
|
+
const mcpService = require('./mcp-service');
|
|
58
|
+
const mcpServers = mcpService.getAllServers();
|
|
59
|
+
|
|
60
|
+
// 读取 Markdown 配置文件
|
|
61
|
+
const { PATHS } = require('../../config/paths');
|
|
62
|
+
const markdownFiles = {};
|
|
63
|
+
const mdFileNames = ['CLAUDE.md', 'AGENTS.md', 'GEMINI.md'];
|
|
64
|
+
|
|
65
|
+
for (const fileName of mdFileNames) {
|
|
66
|
+
const filePath = path.join(PATHS.base, fileName);
|
|
67
|
+
if (fs.existsSync(filePath)) {
|
|
68
|
+
try {
|
|
69
|
+
markdownFiles[fileName] = fs.readFileSync(filePath, 'utf8');
|
|
70
|
+
} catch (err) {
|
|
71
|
+
console.warn(`无法读取 ${fileName}:`, err.message);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const exportData = {
|
|
77
|
+
version: CONFIG_VERSION,
|
|
78
|
+
exportedAt: new Date().toISOString(),
|
|
79
|
+
data: {
|
|
80
|
+
permissionTemplates: customPermissionTemplates,
|
|
81
|
+
configTemplates: customConfigTemplates,
|
|
82
|
+
channels: channels || [],
|
|
83
|
+
workspaces: workspaces || { workspaces: [] },
|
|
84
|
+
favorites: favorites || { favorites: [] },
|
|
85
|
+
agents: agents || [],
|
|
86
|
+
skills: skills || [],
|
|
87
|
+
commands: commands || [],
|
|
88
|
+
rules: rules || [],
|
|
89
|
+
mcpServers: mcpServers || [],
|
|
90
|
+
markdownFiles: markdownFiles
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
success: true,
|
|
96
|
+
data: exportData
|
|
97
|
+
};
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('[ConfigExport] 导出配置失败:', error);
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
message: error.message
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 导入配置
|
|
109
|
+
* @param {Object} importData - 导入的配置对象
|
|
110
|
+
* @param {Object} options - 导入选项 { overwrite: boolean }
|
|
111
|
+
* @returns {Object} 导入结果
|
|
112
|
+
*/
|
|
113
|
+
function importConfigs(importData, options = {}) {
|
|
114
|
+
const { overwrite = true } = options; // 默认覆盖模式
|
|
115
|
+
const results = {
|
|
116
|
+
permissionTemplates: { success: 0, failed: 0, skipped: 0 },
|
|
117
|
+
configTemplates: { success: 0, failed: 0, skipped: 0 },
|
|
118
|
+
channels: { success: 0, failed: 0, skipped: 0 },
|
|
119
|
+
workspaces: { success: 0, failed: 0, skipped: 0 },
|
|
120
|
+
favorites: { success: 0, failed: 0, skipped: 0 },
|
|
121
|
+
agents: { success: 0, failed: 0, skipped: 0 },
|
|
122
|
+
skills: { success: 0, failed: 0, skipped: 0 },
|
|
123
|
+
commands: { success: 0, failed: 0, skipped: 0 },
|
|
124
|
+
rules: { success: 0, failed: 0, skipped: 0 },
|
|
125
|
+
mcpServers: { success: 0, failed: 0, skipped: 0 },
|
|
126
|
+
markdownFiles: { success: 0, failed: 0, skipped: 0 }
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
// 验证导入数据格式
|
|
131
|
+
if (!importData || !importData.data) {
|
|
132
|
+
throw new Error('无效的导入数据格式');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const {
|
|
136
|
+
permissionTemplates = [],
|
|
137
|
+
configTemplates = [],
|
|
138
|
+
channels = [],
|
|
139
|
+
workspaces = null,
|
|
140
|
+
favorites = null,
|
|
141
|
+
agents = [],
|
|
142
|
+
skills = [],
|
|
143
|
+
commands = [],
|
|
144
|
+
rules = [],
|
|
145
|
+
mcpServers = [],
|
|
146
|
+
markdownFiles = {}
|
|
147
|
+
} = importData.data;
|
|
148
|
+
|
|
149
|
+
// 导入权限模板
|
|
150
|
+
for (const template of permissionTemplates) {
|
|
151
|
+
try {
|
|
152
|
+
const existing = permissionTemplatesService.getTemplateById(template.id);
|
|
153
|
+
|
|
154
|
+
if (existing && !overwrite) {
|
|
155
|
+
results.permissionTemplates.skipped++;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (existing && overwrite) {
|
|
160
|
+
permissionTemplatesService.updateTemplate(template.id, template);
|
|
161
|
+
} else {
|
|
162
|
+
const newTemplate = {
|
|
163
|
+
...template,
|
|
164
|
+
isBuiltin: false,
|
|
165
|
+
importedAt: new Date().toISOString()
|
|
166
|
+
};
|
|
167
|
+
permissionTemplatesService.createTemplate(newTemplate);
|
|
168
|
+
}
|
|
169
|
+
results.permissionTemplates.success++;
|
|
170
|
+
} catch (err) {
|
|
171
|
+
console.error(`[ConfigImport] 导入权限模板失败: ${template.name}`, err);
|
|
172
|
+
results.permissionTemplates.failed++;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 导入配置模板
|
|
177
|
+
for (const template of configTemplates) {
|
|
178
|
+
try {
|
|
179
|
+
const existing = configTemplatesService.getTemplateById(template.id);
|
|
180
|
+
|
|
181
|
+
if (existing && !overwrite) {
|
|
182
|
+
results.configTemplates.skipped++;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (existing && overwrite) {
|
|
187
|
+
configTemplatesService.updateTemplate(template.id, template);
|
|
188
|
+
} else {
|
|
189
|
+
const newTemplate = {
|
|
190
|
+
...template,
|
|
191
|
+
isBuiltin: false,
|
|
192
|
+
importedAt: new Date().toISOString()
|
|
193
|
+
};
|
|
194
|
+
configTemplatesService.createTemplate(newTemplate);
|
|
195
|
+
}
|
|
196
|
+
results.configTemplates.success++;
|
|
197
|
+
} catch (err) {
|
|
198
|
+
console.error(`[ConfigImport] 导入配置模板失败: ${template.name}`, err);
|
|
199
|
+
results.configTemplates.failed++;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 导入频道配置
|
|
204
|
+
for (const channel of channels) {
|
|
205
|
+
try {
|
|
206
|
+
const channelsData = channelsService.getAllChannels();
|
|
207
|
+
const existingChannels = channelsData?.channels || [];
|
|
208
|
+
const existing = existingChannels.find(c => c.id === channel.id);
|
|
209
|
+
|
|
210
|
+
if (existing && !overwrite) {
|
|
211
|
+
results.channels.skipped++;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (existing && overwrite) {
|
|
216
|
+
channelsService.updateChannel(channel.id, channel);
|
|
217
|
+
} else {
|
|
218
|
+
const { name, baseUrl, apiKey, websiteUrl, ...extraConfig } = channel;
|
|
219
|
+
channelsService.createChannel(name, baseUrl, apiKey, websiteUrl, extraConfig);
|
|
220
|
+
}
|
|
221
|
+
results.channels.success++;
|
|
222
|
+
} catch (err) {
|
|
223
|
+
console.error(`[ConfigImport] 导入频道失败: ${channel.name}`, err);
|
|
224
|
+
results.channels.failed++;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 导入工作区配置
|
|
229
|
+
if (workspaces && overwrite) {
|
|
230
|
+
try {
|
|
231
|
+
const workspaceService = require('./workspace-service');
|
|
232
|
+
workspaceService.saveWorkspaces(workspaces);
|
|
233
|
+
results.workspaces.success = workspaces.workspaces?.length || 0;
|
|
234
|
+
} catch (err) {
|
|
235
|
+
console.error('[ConfigImport] 导入工作区失败:', err);
|
|
236
|
+
results.workspaces.failed++;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 导入收藏配置
|
|
241
|
+
if (favorites && overwrite) {
|
|
242
|
+
try {
|
|
243
|
+
const favoritesService = require('./favorites');
|
|
244
|
+
favoritesService.saveFavorites(favorites);
|
|
245
|
+
const count = Object.values(favorites).reduce((sum, arr) => sum + (Array.isArray(arr) ? arr.length : 0), 0);
|
|
246
|
+
results.favorites.success = count;
|
|
247
|
+
} catch (err) {
|
|
248
|
+
console.error('[ConfigImport] 导入收藏失败:', err);
|
|
249
|
+
results.favorites.failed++;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 导入 Agents
|
|
254
|
+
if (agents && agents.length > 0 && overwrite) {
|
|
255
|
+
try {
|
|
256
|
+
const agentsService = require('./agents-service');
|
|
257
|
+
for (const agent of agents) {
|
|
258
|
+
try {
|
|
259
|
+
agentsService.saveAgent(agent);
|
|
260
|
+
results.agents.success++;
|
|
261
|
+
} catch (err) {
|
|
262
|
+
console.error(`[ConfigImport] 导入 Agent 失败: ${agent.name}`, err);
|
|
263
|
+
results.agents.failed++;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
} catch (err) {
|
|
267
|
+
console.error('[ConfigImport] 导入 Agents 失败:', err);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// 导入 Skills
|
|
272
|
+
if (skills && skills.length > 0 && overwrite) {
|
|
273
|
+
try {
|
|
274
|
+
const skillService = require('./skill-service');
|
|
275
|
+
for (const skill of skills) {
|
|
276
|
+
try {
|
|
277
|
+
skillService.saveSkill(skill);
|
|
278
|
+
results.skills.success++;
|
|
279
|
+
} catch (err) {
|
|
280
|
+
console.error(`[ConfigImport] 导入 Skill 失败: ${skill.name}`, err);
|
|
281
|
+
results.skills.failed++;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
} catch (err) {
|
|
285
|
+
console.error('[ConfigImport] 导入 Skills 失败:', err);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// 导入 Commands
|
|
290
|
+
if (commands && commands.length > 0 && overwrite) {
|
|
291
|
+
try {
|
|
292
|
+
const commandsService = require('./commands-service');
|
|
293
|
+
for (const command of commands) {
|
|
294
|
+
try {
|
|
295
|
+
commandsService.saveCommand(command);
|
|
296
|
+
results.commands.success++;
|
|
297
|
+
} catch (err) {
|
|
298
|
+
console.error(`[ConfigImport] 导入 Command 失败: ${command.name}`, err);
|
|
299
|
+
results.commands.failed++;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
} catch (err) {
|
|
303
|
+
console.error('[ConfigImport] 导入 Commands 失败:', err);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// 导入 Rules
|
|
308
|
+
if (rules && rules.length > 0 && overwrite) {
|
|
309
|
+
try {
|
|
310
|
+
const rulesService = require('./rules-service');
|
|
311
|
+
for (const rule of rules) {
|
|
312
|
+
try {
|
|
313
|
+
rulesService.saveRule(rule);
|
|
314
|
+
results.rules.success++;
|
|
315
|
+
} catch (err) {
|
|
316
|
+
console.error(`[ConfigImport] 导入 Rule 失败: ${rule.name}`, err);
|
|
317
|
+
results.rules.failed++;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
} catch (err) {
|
|
321
|
+
console.error('[ConfigImport] 导入 Rules 失败:', err);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// 导入 MCP Servers
|
|
326
|
+
if (mcpServers && mcpServers.length > 0 && overwrite) {
|
|
327
|
+
try {
|
|
328
|
+
const mcpService = require('./mcp-service');
|
|
329
|
+
for (const server of mcpServers) {
|
|
330
|
+
try {
|
|
331
|
+
mcpService.saveServer(server);
|
|
332
|
+
results.mcpServers.success++;
|
|
333
|
+
} catch (err) {
|
|
334
|
+
console.error(`[ConfigImport] 导入 MCP Server 失败: ${server.name}`, err);
|
|
335
|
+
results.mcpServers.failed++;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
} catch (err) {
|
|
339
|
+
console.error('[ConfigImport] 导入 MCP Servers 失败:', err);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 导入 Markdown 文件
|
|
344
|
+
if (markdownFiles && Object.keys(markdownFiles).length > 0 && overwrite) {
|
|
345
|
+
const { PATHS } = require('../../config/paths');
|
|
346
|
+
for (const [fileName, content] of Object.entries(markdownFiles)) {
|
|
347
|
+
try {
|
|
348
|
+
const filePath = path.join(PATHS.base, fileName);
|
|
349
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
350
|
+
results.markdownFiles.success++;
|
|
351
|
+
} catch (err) {
|
|
352
|
+
console.error(`[ConfigImport] 导入 ${fileName} 失败:`, err);
|
|
353
|
+
results.markdownFiles.failed++;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
success: true,
|
|
360
|
+
results,
|
|
361
|
+
message: generateImportSummary(results)
|
|
362
|
+
};
|
|
363
|
+
} catch (error) {
|
|
364
|
+
console.error('[ConfigImport] 导入配置失败:', error);
|
|
365
|
+
return {
|
|
366
|
+
success: false,
|
|
367
|
+
message: error.message,
|
|
368
|
+
results
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* 生成导入摘要消息
|
|
375
|
+
*/
|
|
376
|
+
function generateImportSummary(results) {
|
|
377
|
+
const parts = [];
|
|
378
|
+
|
|
379
|
+
const types = [
|
|
380
|
+
{ key: 'permissionTemplates', label: '权限模板' },
|
|
381
|
+
{ key: 'configTemplates', label: '配置模板' },
|
|
382
|
+
{ key: 'channels', label: '频道' },
|
|
383
|
+
{ key: 'workspaces', label: '工作区' },
|
|
384
|
+
{ key: 'favorites', label: '收藏' },
|
|
385
|
+
{ key: 'agents', label: 'Agents' },
|
|
386
|
+
{ key: 'skills', label: 'Skills' },
|
|
387
|
+
{ key: 'commands', label: 'Commands' },
|
|
388
|
+
{ key: 'rules', label: 'Rules' },
|
|
389
|
+
{ key: 'mcpServers', label: 'MCP服务器' },
|
|
390
|
+
{ key: 'markdownFiles', label: 'Markdown文件' }
|
|
391
|
+
];
|
|
392
|
+
|
|
393
|
+
for (const { key, label } of types) {
|
|
394
|
+
if (results[key] && results[key].success > 0) {
|
|
395
|
+
parts.push(`${label}: ${results[key].success}成功`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const totalSkipped = Object.values(results).reduce((sum, r) => sum + (r.skipped || 0), 0);
|
|
400
|
+
if (totalSkipped > 0) {
|
|
401
|
+
parts.push(`${totalSkipped}项已跳过`);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const totalFailed = Object.values(results).reduce((sum, r) => sum + (r.failed || 0), 0);
|
|
405
|
+
if (totalFailed > 0) {
|
|
406
|
+
parts.push(`${totalFailed}项失败`);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return parts.join(', ') || '无数据导入';
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
module.exports = {
|
|
413
|
+
exportAllConfigs,
|
|
414
|
+
importConfigs
|
|
415
|
+
};
|