@adversity/coding-tool-x 2.2.0 → 2.3.0

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.
@@ -245,4 +245,192 @@ router.delete('/:scope/:fileName', (req, res) => {
245
245
  }
246
246
  });
247
247
 
248
+ // ==================== 仓库管理 API ====================
249
+
250
+ /**
251
+ * 获取所有代理(包括远程仓库)
252
+ * GET /api/agents/all
253
+ * Query: projectPath, refresh=1 强制刷新缓存
254
+ */
255
+ router.get('/all', async (req, res) => {
256
+ try {
257
+ const { projectPath, refresh } = req.query;
258
+ const forceRefresh = refresh === '1';
259
+ const result = await agentsService.listAllAgents(projectPath || null, forceRefresh);
260
+
261
+ res.json({
262
+ success: true,
263
+ ...result
264
+ });
265
+ } catch (err) {
266
+ console.error('[Agents API] List all agents error:', err);
267
+ res.status(500).json({
268
+ success: false,
269
+ message: err.message
270
+ });
271
+ }
272
+ });
273
+
274
+ /**
275
+ * 获取仓库列表
276
+ * GET /api/agents/repos
277
+ */
278
+ router.get('/repos', (req, res) => {
279
+ try {
280
+ const repos = agentsService.getRepos();
281
+ res.json({
282
+ success: true,
283
+ repos
284
+ });
285
+ } catch (err) {
286
+ console.error('[Agents API] Get repos error:', err);
287
+ res.status(500).json({
288
+ success: false,
289
+ message: err.message
290
+ });
291
+ }
292
+ });
293
+
294
+ /**
295
+ * 添加仓库
296
+ * POST /api/agents/repos
297
+ * Body: { owner, name, branch, directory, enabled }
298
+ */
299
+ router.post('/repos', (req, res) => {
300
+ try {
301
+ const { owner, name, branch = 'main', directory = '', enabled = true } = req.body;
302
+
303
+ if (!owner || !name) {
304
+ return res.status(400).json({
305
+ success: false,
306
+ message: 'Missing owner or name'
307
+ });
308
+ }
309
+
310
+ const repos = agentsService.addRepo({ owner, name, branch, directory, enabled });
311
+
312
+ res.json({
313
+ success: true,
314
+ repos
315
+ });
316
+ } catch (err) {
317
+ console.error('[Agents API] Add repo error:', err);
318
+ res.status(500).json({
319
+ success: false,
320
+ message: err.message
321
+ });
322
+ }
323
+ });
324
+
325
+ /**
326
+ * 删除仓库
327
+ * DELETE /api/agents/repos/:owner/:name
328
+ * Query: directory - 可选,子目录路径
329
+ */
330
+ router.delete('/repos/:owner/:name', (req, res) => {
331
+ try {
332
+ const { owner, name } = req.params;
333
+ const { directory = '' } = req.query;
334
+ const repos = agentsService.removeRepo(owner, name, directory);
335
+
336
+ res.json({
337
+ success: true,
338
+ repos
339
+ });
340
+ } catch (err) {
341
+ console.error('[Agents API] Remove repo error:', err);
342
+ res.status(500).json({
343
+ success: false,
344
+ message: err.message
345
+ });
346
+ }
347
+ });
348
+
349
+ /**
350
+ * 切换仓库启用状态
351
+ * PUT /api/agents/repos/:owner/:name/toggle
352
+ * Body: { enabled, directory }
353
+ */
354
+ router.put('/repos/:owner/:name/toggle', (req, res) => {
355
+ try {
356
+ const { owner, name } = req.params;
357
+ const { enabled, directory = '' } = req.body;
358
+
359
+ const repos = agentsService.toggleRepo(owner, name, directory, enabled);
360
+
361
+ res.json({
362
+ success: true,
363
+ repos
364
+ });
365
+ } catch (err) {
366
+ console.error('[Agents API] Toggle repo error:', err);
367
+ res.status(500).json({
368
+ success: false,
369
+ message: err.message
370
+ });
371
+ }
372
+ });
373
+
374
+ /**
375
+ * 从远程仓库安装代理
376
+ * POST /api/agents/install
377
+ * Body: agent object from listAllAgents
378
+ */
379
+ router.post('/install', async (req, res) => {
380
+ try {
381
+ const agent = req.body;
382
+
383
+ if (!agent || !agent.repoOwner || !agent.repoName) {
384
+ return res.status(400).json({
385
+ success: false,
386
+ message: 'Missing agent info or repo info'
387
+ });
388
+ }
389
+
390
+ const result = await agentsService.installFromRemote(agent);
391
+
392
+ res.json({
393
+ success: true,
394
+ ...result
395
+ });
396
+ } catch (err) {
397
+ console.error('[Agents API] Install agent error:', err);
398
+ res.status(500).json({
399
+ success: false,
400
+ message: err.message
401
+ });
402
+ }
403
+ });
404
+
405
+ /**
406
+ * 卸载代理
407
+ * POST /api/agents/uninstall
408
+ * Body: { fileName } - 代理的文件名(不含扩展名)
409
+ */
410
+ router.post('/uninstall', (req, res) => {
411
+ try {
412
+ const { fileName } = req.body;
413
+
414
+ if (!fileName) {
415
+ return res.status(400).json({
416
+ success: false,
417
+ message: 'Missing fileName'
418
+ });
419
+ }
420
+
421
+ const result = agentsService.uninstallAgent(fileName);
422
+
423
+ res.json({
424
+ success: true,
425
+ ...result
426
+ });
427
+ } catch (err) {
428
+ console.error('[Agents API] Uninstall agent error:', err);
429
+ res.status(500).json({
430
+ success: false,
431
+ message: err.message
432
+ });
433
+ }
434
+ });
435
+
248
436
  module.exports = router;
@@ -242,4 +242,265 @@ router.delete('/:scope/:name', (req, res) => {
242
242
  }
243
243
  });
244
244
 
245
+ // ==================== 仓库管理 API ====================
246
+
247
+ /**
248
+ * 获取所有命令(包括远程仓库)
249
+ * GET /api/commands/all
250
+ * Query: projectPath, refresh=1 强制刷新缓存
251
+ */
252
+ router.get('/all', async (req, res) => {
253
+ try {
254
+ const { projectPath, refresh } = req.query;
255
+ const forceRefresh = refresh === '1';
256
+ const result = await commandsService.listAllCommands(projectPath || null, forceRefresh);
257
+
258
+ res.json({
259
+ success: true,
260
+ ...result
261
+ });
262
+ } catch (err) {
263
+ console.error('[Commands API] List all commands error:', err);
264
+ res.status(500).json({
265
+ success: false,
266
+ message: err.message
267
+ });
268
+ }
269
+ });
270
+
271
+ /**
272
+ * 获取仓库列表
273
+ * GET /api/commands/repos
274
+ */
275
+ router.get('/repos', (req, res) => {
276
+ try {
277
+ const repos = commandsService.getRepos();
278
+ res.json({
279
+ success: true,
280
+ repos
281
+ });
282
+ } catch (err) {
283
+ console.error('[Commands API] Get repos error:', err);
284
+ res.status(500).json({
285
+ success: false,
286
+ message: err.message
287
+ });
288
+ }
289
+ });
290
+
291
+ /**
292
+ * 添加仓库
293
+ * POST /api/commands/repos
294
+ * Body: { owner, name, branch, directory, enabled }
295
+ */
296
+ router.post('/repos', (req, res) => {
297
+ try {
298
+ const { owner, name, branch = 'main', directory = '', enabled = true } = req.body;
299
+
300
+ if (!owner || !name) {
301
+ return res.status(400).json({
302
+ success: false,
303
+ message: 'Missing owner or name'
304
+ });
305
+ }
306
+
307
+ const repos = commandsService.addRepo({ owner, name, branch, directory, enabled });
308
+
309
+ res.json({
310
+ success: true,
311
+ repos
312
+ });
313
+ } catch (err) {
314
+ console.error('[Commands API] Add repo error:', err);
315
+ res.status(500).json({
316
+ success: false,
317
+ message: err.message
318
+ });
319
+ }
320
+ });
321
+
322
+ /**
323
+ * 删除仓库
324
+ * DELETE /api/commands/repos/:owner/:name
325
+ * Query: directory - 可选,子目录路径
326
+ */
327
+ router.delete('/repos/:owner/:name', (req, res) => {
328
+ try {
329
+ const { owner, name } = req.params;
330
+ const { directory = '' } = req.query;
331
+ const repos = commandsService.removeRepo(owner, name, directory);
332
+
333
+ res.json({
334
+ success: true,
335
+ repos
336
+ });
337
+ } catch (err) {
338
+ console.error('[Commands API] Remove repo error:', err);
339
+ res.status(500).json({
340
+ success: false,
341
+ message: err.message
342
+ });
343
+ }
344
+ });
345
+
346
+ /**
347
+ * 切换仓库启用状态
348
+ * PUT /api/commands/repos/:owner/:name/toggle
349
+ * Body: { enabled, directory }
350
+ */
351
+ router.put('/repos/:owner/:name/toggle', (req, res) => {
352
+ try {
353
+ const { owner, name } = req.params;
354
+ const { enabled, directory = '' } = req.body;
355
+
356
+ const repos = commandsService.toggleRepo(owner, name, directory, enabled);
357
+
358
+ res.json({
359
+ success: true,
360
+ repos
361
+ });
362
+ } catch (err) {
363
+ console.error('[Commands API] Toggle repo error:', err);
364
+ res.status(500).json({
365
+ success: false,
366
+ message: err.message
367
+ });
368
+ }
369
+ });
370
+
371
+ /**
372
+ * 从远程仓库安装命令
373
+ * POST /api/commands/install
374
+ * Body: command object from listAllCommands
375
+ */
376
+ router.post('/install', async (req, res) => {
377
+ try {
378
+ const command = req.body;
379
+
380
+ if (!command || !command.repoOwner || !command.repoName) {
381
+ return res.status(400).json({
382
+ success: false,
383
+ message: 'Missing command info or repo info'
384
+ });
385
+ }
386
+
387
+ const result = await commandsService.installFromRemote(command);
388
+
389
+ res.json({
390
+ success: true,
391
+ ...result
392
+ });
393
+ } catch (err) {
394
+ console.error('[Commands API] Install command error:', err);
395
+ res.status(500).json({
396
+ success: false,
397
+ message: err.message
398
+ });
399
+ }
400
+ });
401
+
402
+ /**
403
+ * 卸载命令
404
+ * POST /api/commands/uninstall
405
+ * Body: { path } - 命令的相对路径
406
+ */
407
+ router.post('/uninstall', (req, res) => {
408
+ try {
409
+ const { path } = req.body;
410
+
411
+ if (!path) {
412
+ return res.status(400).json({
413
+ success: false,
414
+ message: 'Missing path'
415
+ });
416
+ }
417
+
418
+ const result = commandsService.uninstallCommand(path);
419
+
420
+ res.json({
421
+ success: true,
422
+ ...result
423
+ });
424
+ } catch (err) {
425
+ console.error('[Commands API] Uninstall command error:', err);
426
+ res.status(500).json({
427
+ success: false,
428
+ message: err.message
429
+ });
430
+ }
431
+ });
432
+
433
+ // ==================== 格式转换 API ====================
434
+
435
+ /**
436
+ * 转换命令格式
437
+ * POST /api/commands/convert
438
+ * Body: { content, targetFormat }
439
+ * - content: 命令内容
440
+ * - targetFormat: 目标格式 ('claude' | 'codex')
441
+ */
442
+ router.post('/convert', (req, res) => {
443
+ try {
444
+ const { content, targetFormat } = req.body;
445
+
446
+ if (!content) {
447
+ return res.status(400).json({
448
+ success: false,
449
+ message: '请提供命令内容'
450
+ });
451
+ }
452
+
453
+ if (!['claude', 'codex'].includes(targetFormat)) {
454
+ return res.status(400).json({
455
+ success: false,
456
+ message: '目标格式必须是 claude 或 codex'
457
+ });
458
+ }
459
+
460
+ const result = commandsService.convertCommandFormat(content, targetFormat);
461
+
462
+ res.json({
463
+ success: true,
464
+ ...result
465
+ });
466
+ } catch (err) {
467
+ console.error('[Commands API] Convert command error:', err);
468
+ res.status(500).json({
469
+ success: false,
470
+ message: err.message
471
+ });
472
+ }
473
+ });
474
+
475
+ /**
476
+ * 检测命令格式
477
+ * POST /api/commands/detect-format
478
+ * Body: { content }
479
+ */
480
+ router.post('/detect-format', (req, res) => {
481
+ try {
482
+ const { content } = req.body;
483
+
484
+ if (!content) {
485
+ return res.status(400).json({
486
+ success: false,
487
+ message: '请提供命令内容'
488
+ });
489
+ }
490
+
491
+ const format = commandsService.detectFormat(content);
492
+
493
+ res.json({
494
+ success: true,
495
+ format
496
+ });
497
+ } catch (err) {
498
+ console.error('[Commands API] Detect format error:', err);
499
+ res.status(500).json({
500
+ success: false,
501
+ message: err.message
502
+ });
503
+ }
504
+ });
505
+
245
506
  module.exports = router;
@@ -46,8 +46,15 @@ router.get('/available-configs', (req, res) => {
46
46
  * GET /api/config-templates/:id
47
47
  * 获取单个配置模板详情
48
48
  */
49
- router.get('/:id', (req, res) => {
49
+ // 注意:此路由需要放在所有静态子路由之后,避免把 /available-configs 等路径当成 id
50
+ router.get('/:id', (req, res, next) => {
50
51
  try {
52
+ // 兜底:即便路由顺序被改动,也避免把保留路径当成模板 ID
53
+ const reservedIds = new Set(['available-configs']);
54
+ if (reservedIds.has(req.params.id)) {
55
+ return next();
56
+ }
57
+
51
58
  const template = templatesService.getTemplateById(req.params.id);
52
59
  if (!template) {
53
60
  return res.status(404).json({
@@ -132,14 +139,18 @@ router.delete('/:id', (req, res) => {
132
139
  */
133
140
  router.post('/:id/apply', (req, res) => {
134
141
  try {
135
- const { targetPath } = req.body;
142
+ const { targetPath, aiConfigType } = req.body;
136
143
  if (!targetPath) {
137
144
  return res.status(400).json({
138
145
  success: false,
139
146
  message: '目标路径不能为空'
140
147
  });
141
148
  }
142
- const result = templatesService.applyTemplateToProject(targetPath, req.params.id);
149
+ const options = {};
150
+ if (aiConfigType) {
151
+ options.aiConfigType = aiConfigType;
152
+ }
153
+ const result = templatesService.applyTemplateToProject(targetPath, req.params.id, options);
143
154
  res.json({
144
155
  success: true,
145
156
  message: '模板应用成功',
@@ -159,14 +170,18 @@ router.post('/:id/apply', (req, res) => {
159
170
  */
160
171
  router.post('/:id/preview', (req, res) => {
161
172
  try {
162
- const { targetPath } = req.body;
173
+ const { targetPath, aiConfigType } = req.body;
163
174
  if (!targetPath) {
164
175
  return res.status(400).json({
165
176
  success: false,
166
177
  message: '目标路径不能为空'
167
178
  });
168
179
  }
169
- const preview = templatesService.previewTemplateApplication(targetPath, req.params.id);
180
+ const options = {};
181
+ if (aiConfigType) {
182
+ options.aiConfigType = aiConfigType;
183
+ }
184
+ const preview = templatesService.previewTemplateApplication(targetPath, req.params.id, options);
170
185
  res.json({
171
186
  success: true,
172
187
  data: preview