@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.
Files changed (35) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +8 -0
  3. package/dist/web/assets/icons-Dom8a0SN.js +1 -0
  4. package/dist/web/assets/index-CQeUIH7E.css +41 -0
  5. package/dist/web/assets/index-YrjlFzC4.js +14 -0
  6. package/dist/web/assets/naive-ui-BjMHakwv.js +1 -0
  7. package/dist/web/assets/vendors-DtJKdpSj.js +7 -0
  8. package/dist/web/assets/vue-vendor-VFuFB5f4.js +44 -0
  9. package/dist/web/index.html +6 -2
  10. package/package.json +2 -2
  11. package/src/commands/export-config.js +205 -0
  12. package/src/config/default.js +1 -1
  13. package/src/server/api/config-export.js +122 -0
  14. package/src/server/api/config-sync.js +155 -0
  15. package/src/server/api/config-templates.js +12 -6
  16. package/src/server/api/health-check.js +1 -89
  17. package/src/server/api/permissions.js +92 -69
  18. package/src/server/api/projects.js +2 -2
  19. package/src/server/api/sessions.js +70 -70
  20. package/src/server/api/skills.js +206 -0
  21. package/src/server/api/terminal.js +26 -0
  22. package/src/server/index.js +7 -11
  23. package/src/server/services/config-export-service.js +415 -0
  24. package/src/server/services/config-sync-service.js +515 -0
  25. package/src/server/services/config-templates-service.js +61 -38
  26. package/src/server/services/enhanced-cache.js +196 -0
  27. package/src/server/services/health-check.js +1 -315
  28. package/src/server/services/permission-templates-service.js +339 -0
  29. package/src/server/services/pty-manager.js +35 -1
  30. package/src/server/services/sessions.js +122 -44
  31. package/src/server/services/skill-service.js +252 -2
  32. package/src/server/services/workspace-service.js +44 -84
  33. package/src/server/websocket-server.js +4 -1
  34. package/dist/web/assets/index-dhun1bYQ.js +0 -3555
  35. 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
+ };