coding-tool-x 3.6.7 → 3.6.8

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 (54) hide show
  1. package/dist/web/assets/{Analytics-CKycBI0G.js → Analytics-C57ZRDq5.js} +1 -1
  2. package/dist/web/assets/{ConfigTemplates-CACLQb8e.js → ConfigTemplates-B3qqqL05.js} +1 -1
  3. package/dist/web/assets/Home-CG5XrTNc.js +1 -0
  4. package/dist/web/assets/Home-CIua-b-o.css +1 -0
  5. package/dist/web/assets/{PluginManager-CQJl_uso.js → PluginManager-BhX0LUzr.js} +1 -1
  6. package/dist/web/assets/{ProjectList-DSkvQFEP.js → ProjectList-BQ01OZn9.js} +1 -1
  7. package/dist/web/assets/{SessionList-Czjs1GN1.js → SessionList-DPv2IOXG.js} +1 -1
  8. package/dist/web/assets/{SkillManager-Cg1xZ5Cv.js → SkillManager-D5CfQm2O.js} +1 -1
  9. package/dist/web/assets/{WorkspaceManager-COjYeKvN.js → WorkspaceManager-Ce8ggteK.js} +1 -1
  10. package/dist/web/assets/index-CpnFNWqC.js +2 -0
  11. package/dist/web/assets/index-DJ9VFidd.css +1 -0
  12. package/dist/web/assets/{naive-ui-DM897mIP.js → naive-ui-kcWDeJwl.js} +1 -1
  13. package/dist/web/index.html +3 -3
  14. package/package.json +1 -1
  15. package/src/commands/stats.js +1 -1
  16. package/src/config/channel-preset-websites.js +2 -1
  17. package/src/config/paths.js +8 -0
  18. package/src/server/api/agents.js +16 -54
  19. package/src/server/api/claude-hooks.js +1 -1
  20. package/src/server/api/claude-statistics.js +57 -0
  21. package/src/server/api/commands.js +16 -54
  22. package/src/server/api/dashboard.js +2 -2
  23. package/src/server/api/gemini-channels.js +2 -0
  24. package/src/server/api/hooks.js +4 -1
  25. package/src/server/api/plugins.js +40 -65
  26. package/src/server/api/skills.js +21 -77
  27. package/src/server/api/validation-errors.js +34 -0
  28. package/src/server/gemini-proxy-server.js +205 -21
  29. package/src/server/index.js +1 -0
  30. package/src/server/services/agents-service.js +166 -75
  31. package/src/server/services/base/base-channel-service.js +15 -0
  32. package/src/server/services/base/response-usage-parser.js +44 -0
  33. package/src/server/services/channel-balance.js +86 -1
  34. package/src/server/services/claude-statistics-service.js +139 -0
  35. package/src/server/services/commands-service.js +203 -121
  36. package/src/server/services/config-artifact-paths.js +116 -0
  37. package/src/server/services/config-export-service.js +7 -6
  38. package/src/server/services/config-registry-service.js +2 -2
  39. package/src/server/services/config-sync-manager.js +45 -11
  40. package/src/server/services/config-templates-service.js +21 -19
  41. package/src/server/services/format-converter.js +42 -4
  42. package/src/server/services/gemini-channels.js +30 -1
  43. package/src/server/services/gemini-sessions.js +347 -61
  44. package/src/server/services/mcp-client.js +236 -49
  45. package/src/server/services/mcp-service.js +51 -64
  46. package/src/server/services/notification-hooks.js +659 -88
  47. package/src/server/services/opencode-channels.js +15 -0
  48. package/src/server/services/plugins-service.js +771 -63
  49. package/src/server/services/repo-scanner-base.js +6 -29
  50. package/src/server/services/skill-service.js +187 -63
  51. package/dist/web/assets/Home-BeGkC4bb.css +0 -1
  52. package/dist/web/assets/Home-Bk6sP5Ed.js +0 -1
  53. package/dist/web/assets/index-0isNzXNY.css +0 -1
  54. package/dist/web/assets/index-fWgvlZQx.js +0 -2
@@ -7,9 +7,10 @@
7
7
  const express = require('express');
8
8
  const { PluginsService } = require('../services/plugins-service');
9
9
  const { maskToken } = require('../services/oauth-utils');
10
+ const { sendApiError } = require('./validation-errors');
10
11
 
11
12
  const router = express.Router();
12
- const SUPPORTED_PLATFORMS = ['claude', 'opencode'];
13
+ const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
13
14
  const pluginServices = new Map();
14
15
 
15
16
  function resolvePlatform(rawPlatform) {
@@ -63,6 +64,28 @@ function sanitizeRepos(service, repos = []) {
63
64
  return (Array.isArray(repos) ? repos : []).map(sanitizeRepo);
64
65
  }
65
66
 
67
+ /**
68
+ * 获取平台插件能力
69
+ * GET /api/plugins/capabilities
70
+ */
71
+ router.get('/capabilities', (req, res) => {
72
+ try {
73
+ const { platform, service } = getPluginsService(req);
74
+ const capabilities = typeof service.getCapabilities === 'function'
75
+ ? service.getCapabilities()
76
+ : { platform, supportsPlugins: true };
77
+
78
+ res.json({
79
+ success: true,
80
+ platform,
81
+ capabilities
82
+ });
83
+ } catch (err) {
84
+ console.error('[Plugins API] Get capabilities error:', err);
85
+ sendApiError(res, err);
86
+ }
87
+ });
88
+
66
89
  /**
67
90
  * 获取插件列表
68
91
  * GET /api/plugins
@@ -79,10 +102,7 @@ router.get('/', (req, res) => {
79
102
  });
80
103
  } catch (err) {
81
104
  console.error('[Plugins API] List plugins error:', err);
82
- res.status(500).json({
83
- success: false,
84
- message: err.message
85
- });
105
+ sendApiError(res, err);
86
106
  }
87
107
  });
88
108
 
@@ -107,10 +127,7 @@ router.get('/market', async (req, res) => {
107
127
  });
108
128
  } catch (err) {
109
129
  console.error('[Plugins API] Get market plugins error:', err);
110
- res.status(500).json({
111
- success: false,
112
- message: err.message
113
- });
130
+ sendApiError(res, err);
114
131
  }
115
132
  });
116
133
 
@@ -164,10 +181,7 @@ router.post('/install', async (req, res) => {
164
181
  });
165
182
  } catch (err) {
166
183
  console.error('[Plugins API] Install plugin error:', err);
167
- res.status(500).json({
168
- success: false,
169
- message: err.message
170
- });
184
+ sendApiError(res, err);
171
185
  }
172
186
  });
173
187
 
@@ -188,10 +202,7 @@ router.get('/repos', (req, res) => {
188
202
  });
189
203
  } catch (err) {
190
204
  console.error('[Plugins API] Get repos error:', err);
191
- res.status(500).json({
192
- success: false,
193
- message: err.message
194
- });
205
+ sendApiError(res, err);
195
206
  }
196
207
  });
197
208
 
@@ -223,10 +234,7 @@ router.post('/repos', (req, res) => {
223
234
  });
224
235
  } catch (err) {
225
236
  console.error('[Plugins API] Add repo error:', err);
226
- res.status(500).json({
227
- success: false,
228
- message: err.message
229
- });
237
+ sendApiError(res, err);
230
238
  }
231
239
  });
232
240
 
@@ -243,10 +251,7 @@ router.delete('/repos', (req, res) => {
243
251
  });
244
252
  } catch (err) {
245
253
  console.error('[Plugins API] Remove repo error:', err);
246
- res.status(500).json({
247
- success: false,
248
- message: err.message
249
- });
254
+ sendApiError(res, err);
250
255
  }
251
256
  });
252
257
 
@@ -271,10 +276,7 @@ router.put('/repos/toggle', (req, res) => {
271
276
  });
272
277
  } catch (err) {
273
278
  console.error('[Plugins API] Toggle repo error:', err);
274
- res.status(500).json({
275
- success: false,
276
- message: err.message
277
- });
279
+ sendApiError(res, err);
278
280
  }
279
281
  });
280
282
 
@@ -298,10 +300,7 @@ router.delete('/repos/:owner/:name', (req, res) => {
298
300
  });
299
301
  } catch (err) {
300
302
  console.error('[Plugins API] Remove repo error:', err);
301
- res.status(500).json({
302
- success: false,
303
- message: err.message
304
- });
303
+ sendApiError(res, err);
305
304
  }
306
305
  });
307
306
 
@@ -333,10 +332,7 @@ router.put('/repos/:owner/:name/toggle', (req, res) => {
333
332
  });
334
333
  } catch (err) {
335
334
  console.error('[Plugins API] Toggle repo error:', err);
336
- res.status(500).json({
337
- success: false,
338
- message: err.message
339
- });
335
+ sendApiError(res, err);
340
336
  }
341
337
  });
342
338
 
@@ -367,10 +363,7 @@ router.put('/repos/auth', (req, res) => {
367
363
  });
368
364
  } catch (err) {
369
365
  console.error('[Plugins API] Update repo auth error:', err);
370
- res.status(500).json({
371
- success: false,
372
- message: err.message
373
- });
366
+ sendApiError(res, err);
374
367
  }
375
368
  });
376
369
 
@@ -391,10 +384,7 @@ router.post('/repos/sync', async (req, res) => {
391
384
  });
392
385
  } catch (err) {
393
386
  console.error('[Plugins API] Sync repos error:', err);
394
- res.status(500).json({
395
- success: false,
396
- message: err.message
397
- });
387
+ sendApiError(res, err);
398
388
  }
399
389
  });
400
390
 
@@ -415,10 +405,7 @@ router.post('/sync', async (req, res) => {
415
405
  });
416
406
  } catch (err) {
417
407
  console.error('[Plugins API] Sync plugins error:', err);
418
- res.status(500).json({
419
- success: false,
420
- message: err.message
421
- });
408
+ sendApiError(res, err);
422
409
  }
423
410
  });
424
411
 
@@ -504,10 +491,7 @@ router.get('/:name', (req, res) => {
504
491
  });
505
492
  } catch (err) {
506
493
  console.error('[Plugins API] Get plugin error:', err);
507
- res.status(500).json({
508
- success: false,
509
- message: err.message
510
- });
494
+ sendApiError(res, err);
511
495
  }
512
496
  });
513
497
 
@@ -536,10 +520,7 @@ router.delete('/:name', (req, res) => {
536
520
  });
537
521
  } catch (err) {
538
522
  console.error('[Plugins API] Uninstall plugin error:', err);
539
- res.status(500).json({
540
- success: false,
541
- message: err.message
542
- });
523
+ sendApiError(res, err);
543
524
  }
544
525
  });
545
526
 
@@ -571,10 +552,7 @@ router.put('/:name/toggle', (req, res) => {
571
552
  });
572
553
  } catch (err) {
573
554
  console.error('[Plugins API] Toggle plugin error:', err);
574
- res.status(500).json({
575
- success: false,
576
- message: err.message
577
- });
555
+ sendApiError(res, err);
578
556
  }
579
557
  });
580
558
 
@@ -605,10 +583,7 @@ router.put('/:name/config', (req, res) => {
605
583
  });
606
584
  } catch (err) {
607
585
  console.error('[Plugins API] Update plugin config error:', err);
608
- res.status(500).json({
609
- success: false,
610
- message: err.message
611
- });
586
+ sendApiError(res, err);
612
587
  }
613
588
  });
614
589
 
@@ -5,6 +5,7 @@
5
5
  const express = require('express');
6
6
  const { SkillService } = require('../services/skill-service');
7
7
  const { maskToken } = require('../services/oauth-utils');
8
+ const { sendApiError } = require('./validation-errors');
8
9
 
9
10
  const router = express.Router();
10
11
  const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
@@ -84,10 +85,7 @@ router.get('/', async (req, res) => {
84
85
  });
85
86
  } catch (err) {
86
87
  console.error('[Skills API] List skills error:', err);
87
- res.status(500).json({
88
- success: false,
89
- message: err.message
90
- });
88
+ sendApiError(res, err);
91
89
  }
92
90
  });
93
91
 
@@ -116,10 +114,7 @@ router.get('/detail/*', async (req, res) => {
116
114
  });
117
115
  } catch (err) {
118
116
  console.error('[Skills API] Get skill detail error:', err);
119
- res.status(500).json({
120
- success: false,
121
- message: err.message
122
- });
117
+ sendApiError(res, err);
123
118
  }
124
119
  });
125
120
 
@@ -138,10 +133,7 @@ router.get('/installed', (req, res) => {
138
133
  });
139
134
  } catch (err) {
140
135
  console.error('[Skills API] Get installed skills error:', err);
141
- res.status(500).json({
142
- success: false,
143
- message: err.message
144
- });
136
+ sendApiError(res, err);
145
137
  }
146
138
  });
147
139
 
@@ -184,10 +176,7 @@ router.post('/install', async (req, res) => {
184
176
  });
185
177
  } catch (err) {
186
178
  console.error('[Skills API] Install skill error:', err);
187
- res.status(500).json({
188
- success: false,
189
- message: err.message
190
- });
179
+ sendApiError(res, err);
191
180
  }
192
181
  });
193
182
 
@@ -209,7 +198,7 @@ router.post('/install-local', (req, res) => {
209
198
  res.json({ success: true, platform, ...result });
210
199
  } catch (err) {
211
200
  console.error('[Skills API] Install local skill error:', err);
212
- res.status(500).json({ success: false, message: err.message });
201
+ sendApiError(res, err);
213
202
  }
214
203
  });
215
204
 
@@ -259,10 +248,7 @@ router.post('/create', (req, res) => {
259
248
  });
260
249
  } catch (err) {
261
250
  console.error('[Skills API] Create skill error:', err);
262
- res.status(500).json({
263
- success: false,
264
- message: err.message
265
- });
251
+ sendApiError(res, err);
266
252
  }
267
253
  });
268
254
 
@@ -292,10 +278,7 @@ router.post('/uninstall', (req, res) => {
292
278
  });
293
279
  } catch (err) {
294
280
  console.error('[Skills API] Uninstall skill error:', err);
295
- res.status(500).json({
296
- success: false,
297
- message: err.message
298
- });
281
+ sendApiError(res, err);
299
282
  }
300
283
  });
301
284
 
@@ -314,10 +297,7 @@ router.get('/repos', (req, res) => {
314
297
  });
315
298
  } catch (err) {
316
299
  console.error('[Skills API] Get repos error:', err);
317
- res.status(500).json({
318
- success: false,
319
- message: err.message
320
- });
300
+ sendApiError(res, err);
321
301
  }
322
302
  });
323
303
 
@@ -349,10 +329,7 @@ router.post('/repos', (req, res) => {
349
329
  });
350
330
  } catch (err) {
351
331
  console.error('[Skills API] Add repo error:', err);
352
- res.status(500).json({
353
- success: false,
354
- message: err.message
355
- });
332
+ sendApiError(res, err);
356
333
  }
357
334
  });
358
335
 
@@ -369,10 +346,7 @@ router.delete('/repos', (req, res) => {
369
346
  });
370
347
  } catch (err) {
371
348
  console.error('[Skills API] Remove repo error:', err);
372
- res.status(500).json({
373
- success: false,
374
- message: err.message
375
- });
349
+ sendApiError(res, err);
376
350
  }
377
351
  });
378
352
 
@@ -390,10 +364,7 @@ router.put('/repos/toggle', (req, res) => {
390
364
  });
391
365
  } catch (err) {
392
366
  console.error('[Skills API] Toggle repo error:', err);
393
- res.status(500).json({
394
- success: false,
395
- message: err.message
396
- });
367
+ sendApiError(res, err);
397
368
  }
398
369
  });
399
370
 
@@ -425,10 +396,7 @@ router.put('/repos/auth', (req, res) => {
425
396
  });
426
397
  } catch (err) {
427
398
  console.error('[Skills API] Update repo auth error:', err);
428
- res.status(500).json({
429
- success: false,
430
- message: err.message
431
- });
399
+ sendApiError(res, err);
432
400
  }
433
401
  });
434
402
 
@@ -451,10 +419,7 @@ router.delete('/repos/:owner/:name', (req, res) => {
451
419
  });
452
420
  } catch (err) {
453
421
  console.error('[Skills API] Remove repo error:', err);
454
- res.status(500).json({
455
- success: false,
456
- message: err.message
457
- });
422
+ sendApiError(res, err);
458
423
  }
459
424
  });
460
425
 
@@ -479,10 +444,7 @@ router.put('/repos/:owner/:name/toggle', (req, res) => {
479
444
  });
480
445
  } catch (err) {
481
446
  console.error('[Skills API] Toggle repo error:', err);
482
- res.status(500).json({
483
- success: false,
484
- message: err.message
485
- });
447
+ sendApiError(res, err);
486
448
  }
487
449
  });
488
450
 
@@ -529,10 +491,7 @@ router.post('/create-with-files', (req, res) => {
529
491
  });
530
492
  } catch (err) {
531
493
  console.error('[Skills API] Create skill with files error:', err);
532
- res.status(500).json({
533
- success: false,
534
- message: err.message
535
- });
494
+ sendApiError(res, err);
536
495
  }
537
496
  });
538
497
 
@@ -554,10 +513,7 @@ router.get('/:directory/files', (req, res) => {
554
513
  });
555
514
  } catch (err) {
556
515
  console.error('[Skills API] Get skill files error:', err);
557
- res.status(500).json({
558
- success: false,
559
- message: err.message
560
- });
516
+ sendApiError(res, err);
561
517
  }
562
518
  });
563
519
 
@@ -588,10 +544,7 @@ router.get('/:directory/file/*', (req, res) => {
588
544
  });
589
545
  } catch (err) {
590
546
  console.error('[Skills API] Get skill file content error:', err);
591
- res.status(500).json({
592
- success: false,
593
- message: err.message
594
- });
547
+ sendApiError(res, err);
595
548
  }
596
549
  });
597
550
 
@@ -622,10 +575,7 @@ router.post('/:directory/files', (req, res) => {
622
575
  });
623
576
  } catch (err) {
624
577
  console.error('[Skills API] Add skill files error:', err);
625
- res.status(500).json({
626
- success: false,
627
- message: err.message
628
- });
578
+ sendApiError(res, err);
629
579
  }
630
580
  });
631
581
 
@@ -655,10 +605,7 @@ router.delete('/:directory/file/*', (req, res) => {
655
605
  });
656
606
  } catch (err) {
657
607
  console.error('[Skills API] Delete skill file error:', err);
658
- res.status(500).json({
659
- success: false,
660
- message: err.message
661
- });
608
+ sendApiError(res, err);
662
609
  }
663
610
  });
664
611
 
@@ -697,10 +644,7 @@ router.put('/:directory/file/*', (req, res) => {
697
644
  });
698
645
  } catch (err) {
699
646
  console.error('[Skills API] Update skill file error:', err);
700
- res.status(500).json({
701
- success: false,
702
- message: err.message
703
- });
647
+ sendApiError(res, err);
704
648
  }
705
649
  });
706
650
 
@@ -0,0 +1,34 @@
1
+ const VALIDATION_ERROR_PATTERNS = [
2
+ /^Invalid\b/i,
3
+ /不能为空/,
4
+ /不合法/,
5
+ /只能包含/,
6
+ /不能包含/,
7
+ /必须/,
8
+ /不能/,
9
+ /Missing\b/i,
10
+ /requires?/i,
11
+ /required/i,
12
+ /escapes/i,
13
+ /not support/i,
14
+ /不支持/
15
+ ];
16
+
17
+ function isValidationError(error) {
18
+ const message = String(error?.message || error || '');
19
+ return VALIDATION_ERROR_PATTERNS.some(pattern => pattern.test(message));
20
+ }
21
+
22
+ function sendApiError(res, error, fallbackStatus = 500, extra = {}) {
23
+ const status = isValidationError(error) ? 400 : fallbackStatus;
24
+ return res.status(status).json({
25
+ success: false,
26
+ message: error?.message || String(error),
27
+ ...extra
28
+ });
29
+ }
30
+
31
+ module.exports = {
32
+ isValidationError,
33
+ sendApiError
34
+ };