agentdog 1.1.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.
Files changed (291) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +244 -0
  3. package/dist/adapters/adapter-factory.d.ts +21 -0
  4. package/dist/adapters/adapter-factory.d.ts.map +1 -0
  5. package/dist/adapters/adapter-factory.js +157 -0
  6. package/dist/adapters/adapter-factory.js.map +1 -0
  7. package/dist/adapters/http-sse-adapter.d.ts +49 -0
  8. package/dist/adapters/http-sse-adapter.d.ts.map +1 -0
  9. package/dist/adapters/http-sse-adapter.js +485 -0
  10. package/dist/adapters/http-sse-adapter.js.map +1 -0
  11. package/dist/adapters/stdio-adapter.d.ts +69 -0
  12. package/dist/adapters/stdio-adapter.d.ts.map +1 -0
  13. package/dist/adapters/stdio-adapter.js +664 -0
  14. package/dist/adapters/stdio-adapter.js.map +1 -0
  15. package/dist/adapters/streamable-http-adapter.d.ts +38 -0
  16. package/dist/adapters/streamable-http-adapter.d.ts.map +1 -0
  17. package/dist/adapters/streamable-http-adapter.js +321 -0
  18. package/dist/adapters/streamable-http-adapter.js.map +1 -0
  19. package/dist/ai-gateway/anthropic-errors.d.ts +4 -0
  20. package/dist/ai-gateway/anthropic-errors.d.ts.map +1 -0
  21. package/dist/ai-gateway/anthropic-errors.js +17 -0
  22. package/dist/ai-gateway/anthropic-errors.js.map +1 -0
  23. package/dist/ai-gateway/auth.d.ts +3 -0
  24. package/dist/ai-gateway/auth.d.ts.map +1 -0
  25. package/dist/ai-gateway/auth.js +14 -0
  26. package/dist/ai-gateway/auth.js.map +1 -0
  27. package/dist/ai-gateway/auth.test.d.ts +2 -0
  28. package/dist/ai-gateway/auth.test.d.ts.map +1 -0
  29. package/dist/ai-gateway/auth.test.js +57 -0
  30. package/dist/ai-gateway/auth.test.js.map +1 -0
  31. package/dist/ai-gateway/count-tokens.d.ts +5 -0
  32. package/dist/ai-gateway/count-tokens.d.ts.map +1 -0
  33. package/dist/ai-gateway/count-tokens.js +37 -0
  34. package/dist/ai-gateway/count-tokens.js.map +1 -0
  35. package/dist/ai-gateway/count-tokens.test.d.ts +2 -0
  36. package/dist/ai-gateway/count-tokens.test.d.ts.map +1 -0
  37. package/dist/ai-gateway/count-tokens.test.js +19 -0
  38. package/dist/ai-gateway/count-tokens.test.js.map +1 -0
  39. package/dist/ai-gateway/dialects.d.ts +4 -0
  40. package/dist/ai-gateway/dialects.d.ts.map +1 -0
  41. package/dist/ai-gateway/dialects.js +15 -0
  42. package/dist/ai-gateway/dialects.js.map +1 -0
  43. package/dist/ai-gateway/gateway-server.d.ts +15 -0
  44. package/dist/ai-gateway/gateway-server.d.ts.map +1 -0
  45. package/dist/ai-gateway/gateway-server.js +121 -0
  46. package/dist/ai-gateway/gateway-server.js.map +1 -0
  47. package/dist/ai-gateway/integration.test.d.ts +2 -0
  48. package/dist/ai-gateway/integration.test.d.ts.map +1 -0
  49. package/dist/ai-gateway/integration.test.js +205 -0
  50. package/dist/ai-gateway/integration.test.js.map +1 -0
  51. package/dist/ai-gateway/ir/anthropic-in.d.ts +3 -0
  52. package/dist/ai-gateway/ir/anthropic-in.d.ts.map +1 -0
  53. package/dist/ai-gateway/ir/anthropic-in.js +121 -0
  54. package/dist/ai-gateway/ir/anthropic-in.js.map +1 -0
  55. package/dist/ai-gateway/ir/anthropic-in.test.d.ts +2 -0
  56. package/dist/ai-gateway/ir/anthropic-in.test.d.ts.map +1 -0
  57. package/dist/ai-gateway/ir/anthropic-in.test.js +93 -0
  58. package/dist/ai-gateway/ir/anthropic-in.test.js.map +1 -0
  59. package/dist/ai-gateway/ir/anthropic-sse.d.ts +22 -0
  60. package/dist/ai-gateway/ir/anthropic-sse.d.ts.map +1 -0
  61. package/dist/ai-gateway/ir/anthropic-sse.js +200 -0
  62. package/dist/ai-gateway/ir/anthropic-sse.js.map +1 -0
  63. package/dist/ai-gateway/ir/anthropic-sse.test.d.ts +2 -0
  64. package/dist/ai-gateway/ir/anthropic-sse.test.d.ts.map +1 -0
  65. package/dist/ai-gateway/ir/anthropic-sse.test.js +101 -0
  66. package/dist/ai-gateway/ir/anthropic-sse.test.js.map +1 -0
  67. package/dist/ai-gateway/ir/gemini-out.d.ts +20 -0
  68. package/dist/ai-gateway/ir/gemini-out.d.ts.map +1 -0
  69. package/dist/ai-gateway/ir/gemini-out.js +218 -0
  70. package/dist/ai-gateway/ir/gemini-out.js.map +1 -0
  71. package/dist/ai-gateway/ir/gemini-out.test.d.ts +2 -0
  72. package/dist/ai-gateway/ir/gemini-out.test.d.ts.map +1 -0
  73. package/dist/ai-gateway/ir/gemini-out.test.js +125 -0
  74. package/dist/ai-gateway/ir/gemini-out.test.js.map +1 -0
  75. package/dist/ai-gateway/ir/openai-out.d.ts +17 -0
  76. package/dist/ai-gateway/ir/openai-out.d.ts.map +1 -0
  77. package/dist/ai-gateway/ir/openai-out.js +226 -0
  78. package/dist/ai-gateway/ir/openai-out.js.map +1 -0
  79. package/dist/ai-gateway/ir/openai-out.test.d.ts +2 -0
  80. package/dist/ai-gateway/ir/openai-out.test.d.ts.map +1 -0
  81. package/dist/ai-gateway/ir/openai-out.test.js +144 -0
  82. package/dist/ai-gateway/ir/openai-out.test.js.map +1 -0
  83. package/dist/ai-gateway/ir/types.d.ts +77 -0
  84. package/dist/ai-gateway/ir/types.d.ts.map +1 -0
  85. package/dist/ai-gateway/ir/types.js +4 -0
  86. package/dist/ai-gateway/ir/types.js.map +1 -0
  87. package/dist/ai-gateway/ir-channel.d.ts +15 -0
  88. package/dist/ai-gateway/ir-channel.d.ts.map +1 -0
  89. package/dist/ai-gateway/ir-channel.js +120 -0
  90. package/dist/ai-gateway/ir-channel.js.map +1 -0
  91. package/dist/ai-gateway/model-router.d.ts +11 -0
  92. package/dist/ai-gateway/model-router.d.ts.map +1 -0
  93. package/dist/ai-gateway/model-router.js +27 -0
  94. package/dist/ai-gateway/model-router.js.map +1 -0
  95. package/dist/ai-gateway/model-router.test.d.ts +2 -0
  96. package/dist/ai-gateway/model-router.test.d.ts.map +1 -0
  97. package/dist/ai-gateway/model-router.test.js +43 -0
  98. package/dist/ai-gateway/model-router.test.js.map +1 -0
  99. package/dist/ai-gateway/passthrough.d.ts +9 -0
  100. package/dist/ai-gateway/passthrough.d.ts.map +1 -0
  101. package/dist/ai-gateway/passthrough.js +81 -0
  102. package/dist/ai-gateway/passthrough.js.map +1 -0
  103. package/dist/ai-gateway/passthrough.test.d.ts +2 -0
  104. package/dist/ai-gateway/passthrough.test.d.ts.map +1 -0
  105. package/dist/ai-gateway/passthrough.test.js +108 -0
  106. package/dist/ai-gateway/passthrough.test.js.map +1 -0
  107. package/dist/ai-gateway/upstream/model-lister.d.ts +13 -0
  108. package/dist/ai-gateway/upstream/model-lister.d.ts.map +1 -0
  109. package/dist/ai-gateway/upstream/model-lister.js +61 -0
  110. package/dist/ai-gateway/upstream/model-lister.js.map +1 -0
  111. package/dist/ai-gateway/upstream/provider-client.d.ts +20 -0
  112. package/dist/ai-gateway/upstream/provider-client.d.ts.map +1 -0
  113. package/dist/ai-gateway/upstream/provider-client.js +76 -0
  114. package/dist/ai-gateway/upstream/provider-client.js.map +1 -0
  115. package/dist/ai-gateway/upstream/provider-client.test.d.ts +2 -0
  116. package/dist/ai-gateway/upstream/provider-client.test.d.ts.map +1 -0
  117. package/dist/ai-gateway/upstream/provider-client.test.js +69 -0
  118. package/dist/ai-gateway/upstream/provider-client.test.js.map +1 -0
  119. package/dist/cli/cli-main.d.ts +7 -0
  120. package/dist/cli/cli-main.d.ts.map +1 -0
  121. package/dist/cli/cli-main.js +116 -0
  122. package/dist/cli/cli-main.js.map +1 -0
  123. package/dist/cli/cli-router.d.ts +20 -0
  124. package/dist/cli/cli-router.d.ts.map +1 -0
  125. package/dist/cli/cli-router.js +271 -0
  126. package/dist/cli/cli-router.js.map +1 -0
  127. package/dist/cli/cli-utils.d.ts +30 -0
  128. package/dist/cli/cli-utils.d.ts.map +1 -0
  129. package/dist/cli/cli-utils.js +219 -0
  130. package/dist/cli/cli-utils.js.map +1 -0
  131. package/dist/cli/commands/audit-commands.d.ts +30 -0
  132. package/dist/cli/commands/audit-commands.d.ts.map +1 -0
  133. package/dist/cli/commands/audit-commands.js +417 -0
  134. package/dist/cli/commands/audit-commands.js.map +1 -0
  135. package/dist/cli/commands/autostart-command.d.ts +21 -0
  136. package/dist/cli/commands/autostart-command.d.ts.map +1 -0
  137. package/dist/cli/commands/autostart-command.js +243 -0
  138. package/dist/cli/commands/autostart-command.js.map +1 -0
  139. package/dist/cli/commands/autostart-command.test.d.ts +2 -0
  140. package/dist/cli/commands/autostart-command.test.d.ts.map +1 -0
  141. package/dist/cli/commands/autostart-command.test.js +35 -0
  142. package/dist/cli/commands/autostart-command.test.js.map +1 -0
  143. package/dist/cli/commands/config-commands.d.ts +30 -0
  144. package/dist/cli/commands/config-commands.d.ts.map +1 -0
  145. package/dist/cli/commands/config-commands.js +1013 -0
  146. package/dist/cli/commands/config-commands.js.map +1 -0
  147. package/dist/cli/commands/daemon-commands.d.ts +76 -0
  148. package/dist/cli/commands/daemon-commands.d.ts.map +1 -0
  149. package/dist/cli/commands/daemon-commands.js +451 -0
  150. package/dist/cli/commands/daemon-commands.js.map +1 -0
  151. package/dist/cli/commands/detect-commands.d.ts +17 -0
  152. package/dist/cli/commands/detect-commands.d.ts.map +1 -0
  153. package/dist/cli/commands/detect-commands.js +293 -0
  154. package/dist/cli/commands/detect-commands.js.map +1 -0
  155. package/dist/cli/commands/diagnose-commands.d.ts +19 -0
  156. package/dist/cli/commands/diagnose-commands.d.ts.map +1 -0
  157. package/dist/cli/commands/diagnose-commands.js +326 -0
  158. package/dist/cli/commands/diagnose-commands.js.map +1 -0
  159. package/dist/cli/commands/optimize-commands.d.ts +14 -0
  160. package/dist/cli/commands/optimize-commands.d.ts.map +1 -0
  161. package/dist/cli/commands/optimize-commands.js +189 -0
  162. package/dist/cli/commands/optimize-commands.js.map +1 -0
  163. package/dist/cli/commands/proxy-command.d.ts +27 -0
  164. package/dist/cli/commands/proxy-command.d.ts.map +1 -0
  165. package/dist/cli/commands/proxy-command.js +212 -0
  166. package/dist/cli/commands/proxy-command.js.map +1 -0
  167. package/dist/cli/commands/start-command.d.ts +22 -0
  168. package/dist/cli/commands/start-command.d.ts.map +1 -0
  169. package/dist/cli/commands/start-command.js +275 -0
  170. package/dist/cli/commands/start-command.js.map +1 -0
  171. package/dist/config/config-manager.d.ts +125 -0
  172. package/dist/config/config-manager.d.ts.map +1 -0
  173. package/dist/config/config-manager.js +569 -0
  174. package/dist/config/config-manager.js.map +1 -0
  175. package/dist/config/config-manager.test.d.ts +2 -0
  176. package/dist/config/config-manager.test.d.ts.map +1 -0
  177. package/dist/config/config-manager.test.js +209 -0
  178. package/dist/config/config-manager.test.js.map +1 -0
  179. package/dist/core/auto-config-generator.d.ts +55 -0
  180. package/dist/core/auto-config-generator.d.ts.map +1 -0
  181. package/dist/core/auto-config-generator.js +278 -0
  182. package/dist/core/auto-config-generator.js.map +1 -0
  183. package/dist/core/mcpdog-server.d.ts +49 -0
  184. package/dist/core/mcpdog-server.d.ts.map +1 -0
  185. package/dist/core/mcpdog-server.js +552 -0
  186. package/dist/core/mcpdog-server.js.map +1 -0
  187. package/dist/core/protocol-detector.d.ts +56 -0
  188. package/dist/core/protocol-detector.d.ts.map +1 -0
  189. package/dist/core/protocol-detector.js +365 -0
  190. package/dist/core/protocol-detector.js.map +1 -0
  191. package/dist/daemon/daemon-client.d.ts +34 -0
  192. package/dist/daemon/daemon-client.d.ts.map +1 -0
  193. package/dist/daemon/daemon-client.js +130 -0
  194. package/dist/daemon/daemon-client.js.map +1 -0
  195. package/dist/daemon/daemon-client.test.d.ts +2 -0
  196. package/dist/daemon/daemon-client.test.d.ts.map +1 -0
  197. package/dist/daemon/daemon-client.test.js +77 -0
  198. package/dist/daemon/daemon-client.test.js.map +1 -0
  199. package/dist/daemon/daemon-info.d.ts +7 -0
  200. package/dist/daemon/daemon-info.d.ts.map +1 -0
  201. package/dist/daemon/daemon-info.js +34 -0
  202. package/dist/daemon/daemon-info.js.map +1 -0
  203. package/dist/daemon/daemon-info.test.d.ts +2 -0
  204. package/dist/daemon/daemon-info.test.d.ts.map +1 -0
  205. package/dist/daemon/daemon-info.test.js +57 -0
  206. package/dist/daemon/daemon-info.test.js.map +1 -0
  207. package/dist/daemon/daemon-web-server.ai.test.d.ts +2 -0
  208. package/dist/daemon/daemon-web-server.ai.test.d.ts.map +1 -0
  209. package/dist/daemon/daemon-web-server.ai.test.js +119 -0
  210. package/dist/daemon/daemon-web-server.ai.test.js.map +1 -0
  211. package/dist/daemon/daemon-web-server.d.ts +59 -0
  212. package/dist/daemon/daemon-web-server.d.ts.map +1 -0
  213. package/dist/daemon/daemon-web-server.js +1236 -0
  214. package/dist/daemon/daemon-web-server.js.map +1 -0
  215. package/dist/daemon/daemon-web-server.test.d.ts +2 -0
  216. package/dist/daemon/daemon-web-server.test.d.ts.map +1 -0
  217. package/dist/daemon/daemon-web-server.test.js +93 -0
  218. package/dist/daemon/daemon-web-server.test.js.map +1 -0
  219. package/dist/daemon/mcpdog-daemon.d.ts +42 -0
  220. package/dist/daemon/mcpdog-daemon.d.ts.map +1 -0
  221. package/dist/daemon/mcpdog-daemon.js +302 -0
  222. package/dist/daemon/mcpdog-daemon.js.map +1 -0
  223. package/dist/daemon/stdio-proxy.d.ts +17 -0
  224. package/dist/daemon/stdio-proxy.d.ts.map +1 -0
  225. package/dist/daemon/stdio-proxy.js +143 -0
  226. package/dist/daemon/stdio-proxy.js.map +1 -0
  227. package/dist/index.d.ts +14 -0
  228. package/dist/index.d.ts.map +1 -0
  229. package/dist/index.js +198 -0
  230. package/dist/index.js.map +1 -0
  231. package/dist/intent-analyzer.d.ts +27 -0
  232. package/dist/intent-analyzer.d.ts.map +1 -0
  233. package/dist/intent-analyzer.js +140 -0
  234. package/dist/intent-analyzer.js.map +1 -0
  235. package/dist/logging/server-log-manager.d.ts +75 -0
  236. package/dist/logging/server-log-manager.d.ts.map +1 -0
  237. package/dist/logging/server-log-manager.js +185 -0
  238. package/dist/logging/server-log-manager.js.map +1 -0
  239. package/dist/mcp-registry.d.ts +35 -0
  240. package/dist/mcp-registry.d.ts.map +1 -0
  241. package/dist/mcp-registry.js +166 -0
  242. package/dist/mcp-registry.js.map +1 -0
  243. package/dist/middleware/auth.d.ts +5 -0
  244. package/dist/middleware/auth.d.ts.map +1 -0
  245. package/dist/middleware/auth.js +81 -0
  246. package/dist/middleware/auth.js.map +1 -0
  247. package/dist/mock-tool-database.d.ts +41 -0
  248. package/dist/mock-tool-database.d.ts.map +1 -0
  249. package/dist/mock-tool-database.js +461 -0
  250. package/dist/mock-tool-database.js.map +1 -0
  251. package/dist/proxy-server-manager.d.ts +11 -0
  252. package/dist/proxy-server-manager.d.ts.map +1 -0
  253. package/dist/proxy-server-manager.js +144 -0
  254. package/dist/proxy-server-manager.js.map +1 -0
  255. package/dist/router/tool-router.d.ts +61 -0
  256. package/dist/router/tool-router.d.ts.map +1 -0
  257. package/dist/router/tool-router.js +539 -0
  258. package/dist/router/tool-router.js.map +1 -0
  259. package/dist/router/tool-router.test.d.ts +2 -0
  260. package/dist/router/tool-router.test.d.ts.map +1 -0
  261. package/dist/router/tool-router.test.js +113 -0
  262. package/dist/router/tool-router.test.js.map +1 -0
  263. package/dist/streamable-http-server.d.ts +27 -0
  264. package/dist/streamable-http-server.d.ts.map +1 -0
  265. package/dist/streamable-http-server.js +302 -0
  266. package/dist/streamable-http-server.js.map +1 -0
  267. package/dist/tool-finder.d.ts +21 -0
  268. package/dist/tool-finder.d.ts.map +1 -0
  269. package/dist/tool-finder.js +86 -0
  270. package/dist/tool-finder.js.map +1 -0
  271. package/dist/tool-recommender.d.ts +23 -0
  272. package/dist/tool-recommender.d.ts.map +1 -0
  273. package/dist/tool-recommender.js +200 -0
  274. package/dist/tool-recommender.js.map +1 -0
  275. package/dist/types/index.d.ts +145 -0
  276. package/dist/types/index.d.ts.map +1 -0
  277. package/dist/types/index.js +2 -0
  278. package/dist/types/index.js.map +1 -0
  279. package/dist/utils/server-name-validator.d.ts +47 -0
  280. package/dist/utils/server-name-validator.d.ts.map +1 -0
  281. package/dist/utils/server-name-validator.js +156 -0
  282. package/dist/utils/server-name-validator.js.map +1 -0
  283. package/dist/web/web-server.d.ts +44 -0
  284. package/dist/web/web-server.d.ts.map +1 -0
  285. package/dist/web/web-server.js +500 -0
  286. package/dist/web/web-server.js.map +1 -0
  287. package/package.json +68 -0
  288. package/web/dist/assets/index-DMVhVtNU.css +1 -0
  289. package/web/dist/assets/index-VMXIgcOH.js +92 -0
  290. package/web/dist/assets/index-VMXIgcOH.js.map +1 -0
  291. package/web/dist/index.html +14 -0
@@ -0,0 +1,1013 @@
1
+ /**
2
+ * Configuration Management CLI Commands
3
+ */
4
+ import { CLIUtils } from '../cli-utils.js';
5
+ import { createInterface } from 'readline';
6
+ import fs from 'fs/promises';
7
+ export class ConfigCommands {
8
+ configManager;
9
+ constructor(configManager) {
10
+ this.configManager = configManager;
11
+ }
12
+ parseAddOptions(args) {
13
+ const options = {};
14
+ const positionalArgs = [];
15
+ for (let i = 0; i < args.length; i++) {
16
+ const arg = args[i];
17
+ if (arg.startsWith('--')) {
18
+ const optionName = arg.slice(2);
19
+ switch (optionName) {
20
+ case 'transport':
21
+ case 'timeout':
22
+ case 'retries':
23
+ case 'headers':
24
+ case 'args':
25
+ // These options require values
26
+ if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
27
+ options[optionName] = args[i + 1];
28
+ i++; // Skip value
29
+ }
30
+ break;
31
+ case 'auto-detect':
32
+ case 'yes':
33
+ // Boolean options
34
+ options[optionName] = true;
35
+ break;
36
+ default:
37
+ // Other options
38
+ if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
39
+ options[optionName] = args[i + 1];
40
+ i++; // Skip value
41
+ }
42
+ else {
43
+ options[optionName] = true;
44
+ }
45
+ }
46
+ }
47
+ else {
48
+ positionalArgs.push(arg);
49
+ }
50
+ }
51
+ return { args: positionalArgs, options };
52
+ }
53
+ async execute(args, options) {
54
+ const [subcommand, ...subArgs] = args;
55
+ if (options.help || !subcommand) {
56
+ this.showHelp();
57
+ return;
58
+ }
59
+ switch (subcommand) {
60
+ case 'init':
61
+ await this.initConfig(subArgs, options);
62
+ break;
63
+ case 'list':
64
+ await this.listServers(subArgs, options);
65
+ break;
66
+ case 'add':
67
+ await this.addServer(subArgs, options);
68
+ break;
69
+ case 'remove':
70
+ await this.removeServer(subArgs, options);
71
+ break;
72
+ case 'update':
73
+ await this.updateServer(subArgs, options);
74
+ break;
75
+ case 'show':
76
+ await this.showServer(subArgs, options);
77
+ break;
78
+ case 'enable':
79
+ await this.enableServer(subArgs, options);
80
+ break;
81
+ case 'disable':
82
+ await this.disableServer(subArgs, options);
83
+ break;
84
+ case 'validate':
85
+ await this.validateConfig(subArgs, options);
86
+ break;
87
+ case 'mcp-config':
88
+ await this.generateMCPConfig(subArgs, options);
89
+ break;
90
+ default:
91
+ CLIUtils.error(`Unknown config subcommand: ${subcommand}`);
92
+ this.showHelp();
93
+ process.exit(1);
94
+ }
95
+ }
96
+ async listServers(args, options) {
97
+ const servers = Object.values(this.configManager.getServers());
98
+ if (CLIUtils.isJsonMode()) {
99
+ CLIUtils.jsonOutput(servers);
100
+ return;
101
+ }
102
+ if (servers.length === 0) {
103
+ CLIUtils.info('No servers configured');
104
+ return;
105
+ }
106
+ CLIUtils.info(`Found ${servers.length} server configurations:
107
+ `);
108
+ const headers = ['Name', 'Status', 'Protocol', 'Endpoint/Command', 'Tool Count'];
109
+ const rows = servers.map((server) => [
110
+ server.name,
111
+ server.enabled ? CLIUtils.colorize('Enabled', 'green') : CLIUtils.colorize('Disabled', 'red'),
112
+ server.transport,
113
+ server.endpoint || server.command || '-',
114
+ 'Pending Detection' // TODO: Actual tool count
115
+ ]);
116
+ CLIUtils.printTable(headers, rows);
117
+ }
118
+ async addServer(args, options) {
119
+ const [name, endpoint] = args;
120
+ console.log('addServer - args:', args);
121
+ console.log('addServer - options:', options);
122
+ if (!name || !endpoint) {
123
+ CLIUtils.error('Usage: agentdog config add <name> <endpoint> [options]');
124
+ return;
125
+ }
126
+ try {
127
+ if (options['auto-detect']) {
128
+ // Use protocol auto-detection
129
+ CLIUtils.info(`🔍 Auto-detecting server protocol: ${endpoint}`);
130
+ // const suggestion = await this.configManager.generateAutoConfig(name, endpoint, {
131
+ // timeout: options.timeout ? parseInt(options.timeout) : undefined
132
+ // });
133
+ // // Display detection results
134
+ // if (!CLIUtils.isJsonMode()) {
135
+ // CLIUtils.success(`Protocol detection complete (confidence: ${suggestion.confidence}%)`);
136
+ // CLIUtils.info(`Recommended protocol: ${suggestion.config.transport}`);
137
+ // if (suggestion.warnings.length > 0) {
138
+ // CLIUtils.warning('Warnings:');
139
+ // suggestion.warnings.forEach(w => CLIUtils.warning(` - ${w}`));
140
+ // }
141
+ // if (suggestion.optimizations.length > 0) {
142
+ // CLIUtils.info('Optimization suggestions:');
143
+ // suggestion.optimizations.forEach(o => CLIUtils.info(` 💡 ${o}`));
144
+ // }
145
+ // }
146
+ // // Confirm add
147
+ // const shouldAdd = options.yes || await CLIUtils.confirm(
148
+ // `Add server '${name}' (protocol: ${suggestion.config.transport})?`,
149
+ // true
150
+ // );
151
+ // if (shouldAdd) {
152
+ // await this.configManager.addServer(name, suggestion.config);
153
+ // CLIUtils.success(`✅ Server '${name}' added successfully`);
154
+ // // Display alternative configurations
155
+ // if (suggestion.alternatives.length > 0 && !CLIUtils.isJsonMode()) {
156
+ // CLIUtils.info(`\n💡 Available alternative configurations:`);
157
+ // suggestion.alternatives.forEach((alt, index) => {
158
+ // CLIUtils.info(` ${index + 1}. ${alt.transport} - ${alt.description}`);
159
+ // });
160
+ // }
161
+ // } else {
162
+ // CLIUtils.info('Operation cancelled');
163
+ // }
164
+ }
165
+ else {
166
+ // Manual configuration mode
167
+ CLIUtils.verbose(`Transport option: ${options.transport} (${typeof options.transport})`);
168
+ const transport = typeof options.transport === 'string' ? options.transport : 'stdio';
169
+ CLIUtils.verbose(`Final transport: ${transport} (${typeof transport})`);
170
+ const config = {
171
+ name: name,
172
+ enabled: true,
173
+ transport: transport,
174
+ timeout: options.timeout ? parseInt(options.timeout) : 30000,
175
+ retries: options.retries ? parseInt(options.retries) : 3
176
+ };
177
+ // Set required fields based on protocol type
178
+ if (transport === 'stdio') {
179
+ // Parse stdio command
180
+ const commandParts = endpoint.split(' ');
181
+ config.command = commandParts[0];
182
+ const cmdArgs = commandParts.slice(1);
183
+ // If there are additional args options, merge them
184
+ if (options.args) {
185
+ const additionalArgs = options.args.split(',').map((arg) => arg.trim());
186
+ config.args = [...cmdArgs, ...additionalArgs];
187
+ }
188
+ else {
189
+ config.args = cmdArgs;
190
+ }
191
+ }
192
+ else {
193
+ config.endpoint = endpoint;
194
+ if (options.headers) {
195
+ config.headers = JSON.parse(options.headers);
196
+ }
197
+ }
198
+ await this.configManager.addServer(name, config);
199
+ await this.configManager.saveConfig();
200
+ CLIUtils.success(`✅ Server '${name}' added successfully (Protocol: ${transport})`);
201
+ }
202
+ if (CLIUtils.isJsonMode()) {
203
+ CLIUtils.jsonOutput({
204
+ success: true,
205
+ server: name,
206
+ message: 'Server added successfully'
207
+ });
208
+ }
209
+ }
210
+ catch (error) {
211
+ CLIUtils.error(`Failed to add server: ${error.message}`);
212
+ if (CLIUtils.isJsonMode()) {
213
+ CLIUtils.jsonOutput({
214
+ success: false,
215
+ error: error.message
216
+ });
217
+ }
218
+ process.exit(1);
219
+ }
220
+ }
221
+ async removeServer(args, options) {
222
+ const [name] = args;
223
+ if (!name) {
224
+ CLIUtils.error('Usage: agentdog config remove <name>');
225
+ return;
226
+ }
227
+ try {
228
+ const server = this.configManager.getServer(name);
229
+ if (!server) {
230
+ CLIUtils.error(`服务器 '${name}' 不存在`);
231
+ return;
232
+ }
233
+ const shouldRemove = options.yes || await CLIUtils.confirm(`确定要删除服务器 '${name}' 吗?`, false);
234
+ if (shouldRemove) {
235
+ await this.configManager.removeServer(name);
236
+ CLIUtils.success(`✅ 服务器 '${name}' 删除成功`);
237
+ }
238
+ else {
239
+ CLIUtils.info('操作已取消');
240
+ }
241
+ }
242
+ catch (error) {
243
+ CLIUtils.error(`删除服务器失败: ${error.message}`);
244
+ process.exit(1);
245
+ }
246
+ }
247
+ async updateServer(args, options) {
248
+ const [name] = args;
249
+ if (!name) {
250
+ CLIUtils.error('使用方法: agentdog config update <name> [options]');
251
+ return;
252
+ }
253
+ try {
254
+ const server = this.configManager.getServer(name);
255
+ if (!server) {
256
+ CLIUtils.error(`服务器 '${name}' 不存在`);
257
+ return;
258
+ }
259
+ const updates = {};
260
+ // 从选项中构建更新对象
261
+ if (options.endpoint)
262
+ updates.endpoint = options.endpoint;
263
+ if (options.transport)
264
+ updates.transport = options.transport;
265
+ if (options.timeout)
266
+ updates.timeout = parseInt(options.timeout);
267
+ if (options.retries)
268
+ updates.retries = parseInt(options.retries);
269
+ if (options.description)
270
+ updates.description = options.description;
271
+ if (Object.keys(updates).length === 0) {
272
+ CLIUtils.warning('没有指定要更新的字段');
273
+ return;
274
+ }
275
+ await this.configManager.updateServer(name, updates);
276
+ CLIUtils.success(`✅ 服务器 '${name}' 更新成功`);
277
+ if (!CLIUtils.isJsonMode()) {
278
+ CLIUtils.info('更新的字段:');
279
+ Object.entries(updates).forEach(([key, value]) => {
280
+ CLIUtils.info(` ${key}: ${value}`);
281
+ });
282
+ }
283
+ }
284
+ catch (error) {
285
+ CLIUtils.error(`更新服务器失败: ${error.message}`);
286
+ process.exit(1);
287
+ }
288
+ }
289
+ async showServer(args, options) {
290
+ const [name] = args;
291
+ if (!name) {
292
+ CLIUtils.error('使用方法: agentdog config show <name>');
293
+ return;
294
+ }
295
+ const server = this.configManager.getServer(name);
296
+ if (!server) {
297
+ CLIUtils.error(`服务器 '${name}' 不存在`);
298
+ return;
299
+ }
300
+ if (CLIUtils.isJsonMode()) {
301
+ CLIUtils.jsonOutput(server);
302
+ return;
303
+ }
304
+ console.log(`\n${CLIUtils.colorize('🔧 服务器配置:', 'cyan')} ${server.name}\n`);
305
+ const details = [
306
+ ['字段', '值'],
307
+ ['名称', server.name],
308
+ ['状态', server.enabled ? CLIUtils.colorize('启用', 'green') : CLIUtils.colorize('禁用', 'red')],
309
+ ['传输协议', server.transport],
310
+ ['端点', server.endpoint || '-'],
311
+ ['命令', server.command || '-'],
312
+ ['参数', server.args?.join(', ') || '-'],
313
+ ['超时时间', `${server.timeout || 30000}ms`],
314
+ ['重试次数', `${server.retries || 3}`],
315
+ ['描述', server.description || '-']
316
+ ];
317
+ CLIUtils.printTable(details[0], details.slice(1));
318
+ }
319
+ async enableServer(args, options) {
320
+ const [name] = args;
321
+ if (!name) {
322
+ CLIUtils.error('使用方法: agentdog config enable <name>');
323
+ return;
324
+ }
325
+ try {
326
+ await this.configManager.toggleServer(name, true);
327
+ CLIUtils.success(`✅ 服务器 '${name}' 已启用`);
328
+ }
329
+ catch (error) {
330
+ CLIUtils.error(`启用服务器失败: ${error.message}`);
331
+ process.exit(1);
332
+ }
333
+ }
334
+ async disableServer(args, options) {
335
+ const [name] = args;
336
+ if (!name) {
337
+ CLIUtils.error('使用方法: agentdog config disable <name>');
338
+ return;
339
+ }
340
+ try {
341
+ await this.configManager.toggleServer(name, false);
342
+ CLIUtils.success(`✅ 服务器 '${name}' 已禁用`);
343
+ }
344
+ catch (error) {
345
+ CLIUtils.error(`禁用服务器失败: ${error.message}`);
346
+ process.exit(1);
347
+ }
348
+ }
349
+ async generateMCPConfig(args, options) {
350
+ const config = this.configManager.getConfig();
351
+ const servers = this.configManager.getServers();
352
+ const enabledServers = Object.entries(servers).filter(([name, s]) => s.enabled !== false);
353
+ // 获取当前工作目录和配置文件路径
354
+ const cwd = process.cwd();
355
+ const configPath = this.configManager['configPath'] || './mcpdog.config.json';
356
+ const { resolve } = await import('path');
357
+ const absoluteConfigPath = resolve(configPath);
358
+ if (CLIUtils.isJsonMode()) {
359
+ const configs = {
360
+ absolutePath: {
361
+ mcpServers: {
362
+ mcpdog: {
363
+ command: "mcpdog",
364
+ args: ["serve", "--config", absoluteConfigPath]
365
+ }
366
+ }
367
+ },
368
+ workingDirectory: {
369
+ mcpServers: {
370
+ mcpdog: {
371
+ command: "mcpdog",
372
+ args: ["serve"],
373
+ cwd: cwd
374
+ }
375
+ }
376
+ }
377
+ };
378
+ CLIUtils.jsonOutput(configs);
379
+ return;
380
+ }
381
+ console.log(`\n${CLIUtils.colorize('🐕 MCPDog MCP客户端配置生成器', 'cyan')}\n`);
382
+ console.log(`${CLIUtils.colorize('📋 环境信息:', 'yellow')}`);
383
+ console.log(` MCPDog目录: ${cwd}`);
384
+ console.log(` 配置文件: ${absoluteConfigPath}`);
385
+ console.log(` 服务器总数: ${servers.length}`);
386
+ console.log(` 启用服务器: ${enabledServers.length}`);
387
+ if (enabledServers.length === 0) {
388
+ CLIUtils.warning('没有启用的服务器配置');
389
+ CLIUtils.info('建议先添加服务器: agentdog config add my-server https://api.example.com --auto-detect');
390
+ console.log('');
391
+ }
392
+ console.log(`\n${CLIUtils.colorize('🔧 推荐的MCP客户端配置:', 'cyan')}\n`);
393
+ // 方案1: 绝对路径 (推荐)
394
+ console.log(`${CLIUtils.colorize('📱 方案1: 使用绝对路径 (推荐)', 'green')}`);
395
+ console.log('```json');
396
+ console.log(JSON.stringify({
397
+ mcpServers: {
398
+ mcpdog: {
399
+ command: "mcpdog",
400
+ args: ["serve", "--config", absoluteConfigPath]
401
+ }
402
+ }
403
+ }, null, 2));
404
+ console.log('```\n');
405
+ // 方案2: 工作目录
406
+ console.log(`${CLIUtils.colorize('📁 方案2: 使用工作目录', 'blue')}`);
407
+ console.log('```json');
408
+ console.log(JSON.stringify({
409
+ mcpServers: {
410
+ mcpdog: {
411
+ command: "mcpdog",
412
+ args: ["serve"],
413
+ cwd: cwd
414
+ }
415
+ }
416
+ }, null, 2));
417
+ console.log('```\n');
418
+ // 方案3: Node.js后备
419
+ console.log(`${CLIUtils.colorize('🔧 方案3: Node.js后备 (如果mcpdog命令不可用)', 'yellow')}`);
420
+ const nodePath = resolve(cwd, 'dist/cli/cli-main.js');
421
+ console.log('```json');
422
+ console.log(JSON.stringify({
423
+ mcpServers: {
424
+ mcpdog: {
425
+ command: "node",
426
+ args: [nodePath, "serve"],
427
+ cwd: cwd
428
+ }
429
+ }
430
+ }, null, 2));
431
+ console.log('```\n');
432
+ console.log(`${CLIUtils.colorize('💡 使用说明:', 'cyan')}`);
433
+ console.log(' • 复制上述配置到你的MCP客户端配置文件');
434
+ console.log(' • Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json');
435
+ console.log(' • Continue.dev: .continue/config.json');
436
+ console.log(' • 重启MCP客户端以加载新配置');
437
+ console.log('');
438
+ console.log(`${CLIUtils.colorize('🚀 验证步骤:', 'cyan')}`);
439
+ console.log(' 1. agentdog diagnose --health-check');
440
+ console.log(' 2. 在MCP客户端中测试连接');
441
+ console.log(' 3. 查看可用工具列表');
442
+ }
443
+ async initConfig(args, options) {
444
+ const configPath = args[0] || this.configManager.getConfigPath();
445
+ console.log(`
446
+ 🚀 ${CLIUtils.colorize('MCPDog Configuration Wizard', 'cyan')}
447
+
448
+ This wizard will help you create a new MCPDog configuration file.
449
+ `);
450
+ // 检查配置文件是否已存在
451
+ try {
452
+ await fs.access(configPath);
453
+ const overwrite = await this.askQuestion(`Configuration file '${configPath}' already exists. Overwrite? (y/N): `);
454
+ if (!overwrite.toLowerCase().startsWith('y')) {
455
+ console.log('Configuration initialization cancelled.');
456
+ return;
457
+ }
458
+ }
459
+ catch {
460
+ // 文件不存在,继续
461
+ }
462
+ const config = {
463
+ version: '2.0.0',
464
+ servers: {},
465
+ web: {
466
+ enabled: false,
467
+ port: 61125,
468
+ host: 'localhost'
469
+ },
470
+ logging: {
471
+ level: 'info'
472
+ }
473
+ };
474
+ console.log(`
475
+ ${CLIUtils.colorize('Step 1: Basic Configuration', 'yellow')}
476
+ `);
477
+ // Web界面配置
478
+ const enableWeb = await this.askQuestion('Enable web management interface? (Y/n): ');
479
+ if (!enableWeb.toLowerCase().startsWith('n')) {
480
+ config.web.enabled = true;
481
+ const webPort = await this.askQuestion(`Web interface port (default: 61125): `);
482
+ if (webPort.trim()) {
483
+ config.web.port = parseInt(webPort) || 61125;
484
+ }
485
+ }
486
+ console.log(`
487
+ ${CLIUtils.colorize('Step 2: MCP Servers', 'yellow')}
488
+
489
+ Let's add some MCP servers. You can add more later using 'agentdog config add'.
490
+ `);
491
+ // 提供常用的MCP服务器模板
492
+ const templates = [
493
+ {
494
+ name: 'memory',
495
+ description: 'Knowledge graph memory server',
496
+ config: {
497
+ name: 'memory',
498
+ enabled: true,
499
+ transport: 'stdio',
500
+ command: 'npx',
501
+ args: ['-y', '@modelcontextprotocol/server-memory'],
502
+ description: 'Knowledge graph memory server',
503
+ timeout: 30000,
504
+ retries: 3
505
+ }
506
+ },
507
+ {
508
+ name: 'filesystem',
509
+ description: 'File system access server',
510
+ config: {
511
+ name: 'filesystem',
512
+ enabled: true,
513
+ transport: 'stdio',
514
+ command: 'npx',
515
+ args: ['-y', '@modelcontextprotocol/server-filesystem', process.cwd()],
516
+ description: 'File system access server',
517
+ timeout: 30000,
518
+ retries: 3
519
+ }
520
+ },
521
+ {
522
+ name: 'github',
523
+ description: 'GitHub integration server',
524
+ config: {
525
+ name: 'github',
526
+ enabled: true,
527
+ transport: 'stdio',
528
+ command: 'npx',
529
+ args: ['-y', '@modelcontextprotocol/server-github'],
530
+ description: 'GitHub integration server',
531
+ timeout: 30000,
532
+ retries: 3
533
+ }
534
+ }
535
+ ];
536
+ console.log('Available MCP server templates:');
537
+ templates.forEach((template, index) => {
538
+ console.log(` ${index + 1}. ${CLIUtils.colorize(template.name, 'green')} - ${template.description}`);
539
+ });
540
+ console.log(` ${templates.length + 1}. Custom server`);
541
+ console.log(` ${templates.length + 2}. Skip (create empty configuration)`);
542
+ let addingServers = true;
543
+ while (addingServers) {
544
+ const choice = await this.askQuestion(`\nSelect a server template (1-${templates.length + 2}): `);
545
+ const choiceNum = parseInt(choice);
546
+ if (choiceNum >= 1 && choiceNum <= templates.length) {
547
+ const template = templates[choiceNum - 1];
548
+ const serverName = await this.askQuestion(`Server name (default: ${template.name}): `) || template.name;
549
+ // 检查是否需要自定义路径(对于filesystem)
550
+ if (template.name === 'filesystem') {
551
+ const customPath = await this.askQuestion(`Filesystem root path (default: ${process.cwd()}): `);
552
+ if (customPath.trim()) {
553
+ template.config.args = ['-y', '@modelcontextprotocol/server-filesystem', customPath.trim()];
554
+ }
555
+ }
556
+ config.servers[serverName] = { ...template.config, name: serverName };
557
+ console.log(`✅ Added ${CLIUtils.colorize(serverName, 'green')} server`);
558
+ }
559
+ else if (choiceNum === templates.length + 1) {
560
+ // 自定义服务器
561
+ await this.addCustomServer(config.servers);
562
+ }
563
+ else if (choiceNum === templates.length + 2) {
564
+ // 跳过
565
+ break;
566
+ }
567
+ else {
568
+ console.log('Invalid choice. Please try again.');
569
+ continue;
570
+ }
571
+ const addMore = await this.askQuestion('Add another server? (y/N): ');
572
+ if (!addMore.toLowerCase().startsWith('y')) {
573
+ addingServers = false;
574
+ }
575
+ }
576
+ // 保存配置
577
+ try {
578
+ const configData = JSON.stringify(config, null, 2);
579
+ await fs.writeFile(configPath, configData, 'utf-8');
580
+ console.log(`
581
+ ✅ ${CLIUtils.colorize('Configuration created successfully!', 'green')}
582
+
583
+ 📁 Configuration file: ${CLIUtils.colorize(configPath, 'cyan')}
584
+ 🔧 MCP servers configured: ${CLIUtils.colorize(Object.keys(config.servers).length.toString(), 'yellow')}
585
+ ${config.web.enabled ? `🌐 Web interface: ${CLIUtils.colorize(`http://localhost:${config.web.port}`, 'blue')}` : ''}
586
+
587
+ ${CLIUtils.colorize('Next steps:', 'yellow')}
588
+ 1. Start MCPDog: ${CLIUtils.colorize(`agentdog start --config ${configPath}`, 'cyan')}
589
+ 2. Configure MCP clients to use: ${CLIUtils.colorize('agentdog proxy', 'cyan')}
590
+ 3. Check status: ${CLIUtils.colorize('agentdog status', 'cyan')}
591
+ `);
592
+ }
593
+ catch (error) {
594
+ CLIUtils.error('Failed to save configuration:', error.message);
595
+ process.exit(1);
596
+ }
597
+ }
598
+ async addCustomServer(servers) {
599
+ console.log(`\n${CLIUtils.colorize('Custom Server Configuration', 'cyan')}`);
600
+ const name = await this.askQuestion('Server name: ');
601
+ if (!name.trim()) {
602
+ console.log('Server name is required.');
603
+ return;
604
+ }
605
+ const description = await this.askQuestion('Description (optional): ');
606
+ console.log('\nTransport types:');
607
+ console.log(' 1. stdio - Command line program');
608
+ console.log(' 2. http-sse - HTTP Server-Sent Events');
609
+ console.log(' 3. streamable-http - HTTP Streaming');
610
+ const transportChoice = await this.askQuestion('Select transport type (1-3): ');
611
+ let transport = 'stdio';
612
+ switch (transportChoice) {
613
+ case '2':
614
+ transport = 'http-sse';
615
+ break;
616
+ case '3':
617
+ transport = 'streamable-http';
618
+ break;
619
+ default:
620
+ transport = 'stdio';
621
+ }
622
+ let serverConfig;
623
+ if (transport === 'stdio') {
624
+ const command = await this.askQuestion('Command to run: ');
625
+ const argsInput = await this.askQuestion('Arguments (comma-separated, optional): ');
626
+ const args = argsInput.trim() ? argsInput.split(',').map(arg => arg.trim()) : [];
627
+ serverConfig = {
628
+ name: name.trim(),
629
+ enabled: true,
630
+ transport,
631
+ command: command.trim(),
632
+ args,
633
+ description: description.trim() || `Custom ${transport} server`,
634
+ timeout: 30000,
635
+ retries: 3
636
+ };
637
+ }
638
+ else {
639
+ const endpoint = await this.askQuestion(`${transport.toUpperCase()} endpoint URL: `);
640
+ serverConfig = {
641
+ name: name.trim(),
642
+ enabled: true,
643
+ transport,
644
+ endpoint: endpoint.trim(),
645
+ description: description.trim() || `Custom ${transport} server`,
646
+ timeout: 30000,
647
+ retries: 3
648
+ };
649
+ }
650
+ servers[name.trim()] = serverConfig;
651
+ console.log(`✅ Added custom server: ${CLIUtils.colorize(name.trim(), 'green')}`);
652
+ }
653
+ async askQuestion(question) {
654
+ const rl = createInterface({
655
+ input: process.stdin,
656
+ output: process.stdout
657
+ });
658
+ return new Promise((resolve) => {
659
+ rl.question(question, (answer) => {
660
+ rl.close();
661
+ resolve(answer);
662
+ });
663
+ });
664
+ }
665
+ async validateConfig(args, options) {
666
+ const configPath = args[0] || this.configManager.getConfigPath();
667
+ console.log(`
668
+ 🔍 ${CLIUtils.colorize('MCPDog Configuration Validation', 'cyan')}
669
+
670
+ Validating configuration file: ${CLIUtils.colorize(configPath, 'yellow')}
671
+ `);
672
+ const validationResults = [];
673
+ let config;
674
+ // 1. 检查文件是否存在并可读取
675
+ try {
676
+ const configData = await fs.readFile(configPath, 'utf-8');
677
+ config = JSON.parse(configData);
678
+ validationResults.push({
679
+ category: 'File',
680
+ test: 'File exists and is readable',
681
+ status: 'pass',
682
+ message: 'Configuration file loaded successfully'
683
+ });
684
+ }
685
+ catch (error) {
686
+ const err = error;
687
+ validationResults.push({
688
+ category: 'File',
689
+ test: 'File exists and is readable',
690
+ status: 'error',
691
+ message: `Cannot read configuration file: ${err.message}`,
692
+ suggestion: 'Check file path and permissions, or run "agentdog config init" to create a new configuration'
693
+ });
694
+ this.displayValidationResults(validationResults);
695
+ return;
696
+ }
697
+ // 2. 验证基本结构
698
+ this.validateBasicStructure(config, validationResults);
699
+ // 3. 验证服务器配置
700
+ this.validateServers(config.servers || {}, validationResults);
701
+ // 4. 验证Web配置
702
+ this.validateWebConfig(config.web, validationResults);
703
+ // 5. 检查可能的最佳实践问题
704
+ this.validateBestPractices(config, validationResults);
705
+ // 显示结果
706
+ this.displayValidationResults(validationResults);
707
+ // 统计结果
708
+ const errors = validationResults.filter(r => r.status === 'error').length;
709
+ const warnings = validationResults.filter(r => r.status === 'warning').length;
710
+ const passes = validationResults.filter(r => r.status === 'pass').length;
711
+ console.log(`
712
+ ${CLIUtils.colorize('Summary:', 'cyan')}
713
+ ✅ Passed: ${CLIUtils.colorize(passes.toString(), 'green')}
714
+ ⚠️ Warnings: ${CLIUtils.colorize(warnings.toString(), 'yellow')}
715
+ ❌ Errors: ${CLIUtils.colorize(errors.toString(), 'red')}
716
+ `);
717
+ if (errors === 0 && warnings === 0) {
718
+ console.log(`🎉 ${CLIUtils.colorize('Configuration is valid and ready to use!', 'green')}`);
719
+ }
720
+ else if (errors === 0) {
721
+ console.log(`✅ ${CLIUtils.colorize('Configuration is valid but has some recommendations.', 'yellow')}`);
722
+ }
723
+ else {
724
+ console.log(`❌ ${CLIUtils.colorize('Configuration has errors that need to be fixed.', 'red')}`);
725
+ process.exit(1);
726
+ }
727
+ }
728
+ validateBasicStructure(config, results) {
729
+ // 检查版本
730
+ if (!config.version) {
731
+ results.push({
732
+ category: 'Structure',
733
+ test: 'Version field present',
734
+ status: 'error',
735
+ message: 'Missing version field',
736
+ suggestion: 'Add "version": "2.0.0" to your configuration'
737
+ });
738
+ }
739
+ else if (config.version !== '2.0.0') {
740
+ results.push({
741
+ category: 'Structure',
742
+ test: 'Version compatibility',
743
+ status: 'warning',
744
+ message: `Version ${config.version} may not be fully compatible`,
745
+ suggestion: 'Consider updating to version "2.0.0"'
746
+ });
747
+ }
748
+ else {
749
+ results.push({
750
+ category: 'Structure',
751
+ test: 'Version field',
752
+ status: 'pass',
753
+ message: 'Version is valid'
754
+ });
755
+ }
756
+ // 检查servers字段
757
+ if (!config.servers || typeof config.servers !== 'object') {
758
+ results.push({
759
+ category: 'Structure',
760
+ test: 'Servers configuration',
761
+ status: 'error',
762
+ message: 'Missing or invalid servers configuration',
763
+ suggestion: 'Add a "servers" object to your configuration'
764
+ });
765
+ }
766
+ else {
767
+ results.push({
768
+ category: 'Structure',
769
+ test: 'Servers configuration',
770
+ status: 'pass',
771
+ message: 'Servers configuration is present'
772
+ });
773
+ }
774
+ }
775
+ validateServers(servers, results) {
776
+ const serverNames = Object.keys(servers);
777
+ if (serverNames.length === 0) {
778
+ results.push({
779
+ category: 'Servers',
780
+ test: 'At least one server configured',
781
+ status: 'warning',
782
+ message: 'No MCP servers configured',
783
+ suggestion: 'Add at least one MCP server using "agentdog config add" or "agentdog config init"'
784
+ });
785
+ return;
786
+ }
787
+ results.push({
788
+ category: 'Servers',
789
+ test: 'Server count',
790
+ status: 'pass',
791
+ message: `${serverNames.length} server(s) configured`
792
+ });
793
+ // 验证每个服务器
794
+ serverNames.forEach(name => {
795
+ const server = servers[name];
796
+ this.validateSingleServer(name, server, results);
797
+ });
798
+ }
799
+ validateSingleServer(name, server, results) {
800
+ const category = `Server: ${name}`;
801
+ // 必需字段检查
802
+ const requiredFields = ['name', 'enabled', 'transport'];
803
+ requiredFields.forEach(field => {
804
+ if (server[field] === undefined) {
805
+ results.push({
806
+ category,
807
+ test: `Required field: ${field}`,
808
+ status: 'error',
809
+ message: `Missing required field: ${field}`,
810
+ suggestion: `Add "${field}" to server configuration`
811
+ });
812
+ }
813
+ });
814
+ // Transport特定验证
815
+ if (server.transport === 'stdio') {
816
+ if (!server.command) {
817
+ results.push({
818
+ category,
819
+ test: 'Stdio command',
820
+ status: 'error',
821
+ message: 'stdio transport requires "command" field',
822
+ suggestion: 'Add "command" field with the executable to run'
823
+ });
824
+ }
825
+ else {
826
+ results.push({
827
+ category,
828
+ test: 'Stdio configuration',
829
+ status: 'pass',
830
+ message: 'Stdio transport is properly configured'
831
+ });
832
+ }
833
+ }
834
+ else if (server.transport === 'http-sse' || server.transport === 'streamable-http') {
835
+ if (!server.endpoint) {
836
+ results.push({
837
+ category,
838
+ test: 'HTTP endpoint',
839
+ status: 'error',
840
+ message: `${server.transport} transport requires "endpoint" field`,
841
+ suggestion: 'Add "endpoint" field with the server URL'
842
+ });
843
+ }
844
+ else {
845
+ try {
846
+ new URL(server.endpoint);
847
+ results.push({
848
+ category,
849
+ test: 'HTTP endpoint format',
850
+ status: 'pass',
851
+ message: 'Endpoint URL is valid'
852
+ });
853
+ }
854
+ catch {
855
+ results.push({
856
+ category,
857
+ test: 'HTTP endpoint format',
858
+ status: 'error',
859
+ message: 'Invalid endpoint URL format',
860
+ suggestion: 'Ensure endpoint is a valid URL (e.g., https://api.example.com)'
861
+ });
862
+ }
863
+ }
864
+ }
865
+ // 超时和重试配置检查
866
+ if (server.timeout && (server.timeout < 1000 || server.timeout > 300000)) {
867
+ results.push({
868
+ category,
869
+ test: 'Timeout value',
870
+ status: 'warning',
871
+ message: 'Timeout value should be between 1000ms and 300000ms',
872
+ suggestion: 'Consider using a timeout between 10s and 60s for most use cases'
873
+ });
874
+ }
875
+ if (server.retries && (server.retries < 0 || server.retries > 10)) {
876
+ results.push({
877
+ category,
878
+ test: 'Retry count',
879
+ status: 'warning',
880
+ message: 'Retry count should be between 0 and 10',
881
+ suggestion: 'Consider using 3-5 retries for most use cases'
882
+ });
883
+ }
884
+ }
885
+ validateWebConfig(webConfig, results) {
886
+ if (!webConfig) {
887
+ results.push({
888
+ category: 'Web',
889
+ test: 'Web configuration',
890
+ status: 'pass',
891
+ message: 'Web interface is disabled (this is fine)'
892
+ });
893
+ return;
894
+ }
895
+ if (webConfig.enabled) {
896
+ const port = webConfig.port || 61125;
897
+ if (port < 1024 || port > 65535) {
898
+ results.push({
899
+ category: 'Web',
900
+ test: 'Web port range',
901
+ status: 'warning',
902
+ message: `Web port ${port} is outside recommended range`,
903
+ suggestion: 'Keep the default 61125 unless it conflicts, or use standard HTTP ports for production'
904
+ });
905
+ }
906
+ else {
907
+ results.push({
908
+ category: 'Web',
909
+ test: 'Web configuration',
910
+ status: 'pass',
911
+ message: `Web interface configured on port ${port}`
912
+ });
913
+ }
914
+ }
915
+ }
916
+ validateBestPractices(config, results) {
917
+ const servers = config.servers || {};
918
+ const enabledServers = Object.values(servers).filter((s) => s.enabled);
919
+ // 检查是否有启用的服务器
920
+ if (enabledServers.length === 0) {
921
+ results.push({
922
+ category: 'Best Practices',
923
+ test: 'Enabled servers',
924
+ status: 'warning',
925
+ message: 'No servers are enabled',
926
+ suggestion: 'Enable at least one server using "agentdog config enable <server-name>"'
927
+ });
928
+ }
929
+ // 检查是否有描述信息
930
+ const serversWithoutDescription = Object.entries(servers)
931
+ .filter(([name, server]) => !server.description)
932
+ .map(([name]) => name);
933
+ if (serversWithoutDescription.length > 0) {
934
+ results.push({
935
+ category: 'Best Practices',
936
+ test: 'Server descriptions',
937
+ status: 'warning',
938
+ message: `${serversWithoutDescription.length} server(s) missing descriptions`,
939
+ suggestion: `Add descriptions to servers: ${serversWithoutDescription.join(', ')}`
940
+ });
941
+ }
942
+ // 检查日志配置
943
+ if (!config.logging || !config.logging.level) {
944
+ results.push({
945
+ category: 'Best Practices',
946
+ test: 'Logging configuration',
947
+ status: 'warning',
948
+ message: 'No logging configuration specified',
949
+ suggestion: 'Consider adding logging configuration for better debugging'
950
+ });
951
+ }
952
+ }
953
+ displayValidationResults(results) {
954
+ const categories = [...new Set(results.map(r => r.category))];
955
+ categories.forEach(category => {
956
+ console.log(`\n${CLIUtils.colorize(category, 'cyan')}:`);
957
+ const categoryResults = results.filter(r => r.category === category);
958
+ categoryResults.forEach(result => {
959
+ const icon = result.status === 'pass' ? '✅' :
960
+ result.status === 'warning' ? '⚠️ ' : '❌';
961
+ const color = result.status === 'pass' ? 'green' :
962
+ result.status === 'warning' ? 'yellow' : 'red';
963
+ console.log(` ${icon} ${CLIUtils.colorize(result.test, color)}: ${result.message}`);
964
+ if (result.suggestion) {
965
+ console.log(` 💡 ${CLIUtils.colorize('Suggestion', 'cyan')}: ${result.suggestion}`);
966
+ }
967
+ });
968
+ });
969
+ }
970
+ showHelp() {
971
+ console.log(`
972
+ ${CLIUtils.colorize('agentdog config', 'cyan')} - 配置管理
973
+
974
+ ${CLIUtils.colorize('子命令:', 'yellow')}
975
+ init Interactive configuration wizard
976
+ validate Validate configuration file
977
+ list 列出所有服务器配置
978
+ add <name> <endpoint> 添加新服务器
979
+ remove <name> 删除服务器
980
+ update <name> 更新服务器配置
981
+ show <name> 显示服务器详情
982
+ enable <name> 启用服务器
983
+ disable <name> 禁用服务器
984
+ mcp-config 生成MCP客户端配置
985
+
986
+ ${CLIUtils.colorize('add命令选项:', 'yellow')}
987
+ --auto-detect 自动检测最佳协议
988
+ --transport <type> 指定传输协议 (stdio|http-sse|streamable-http)
989
+ --timeout <ms> 设置超时时间 (默认: 30000)
990
+ --retries <num> 设置重试次数 (默认: 3)
991
+ --headers <json> HTTP头部信息 (JSON格式)
992
+ --args <list> stdio参数 (逗号分隔)
993
+ --yes 跳过确认提示
994
+
995
+ ${CLIUtils.colorize('update命令选项:', 'yellow')}
996
+ --endpoint <url> 更新端点地址
997
+ --transport <type> 更新传输协议
998
+ --timeout <ms> 更新超时时间
999
+ --retries <num> 更新重试次数
1000
+ --description <text> 更新描述信息
1001
+
1002
+ ${CLIUtils.colorize('示例:', 'yellow')}
1003
+ agentdog config list
1004
+ agentdog config add my-api https://api.example.com --auto-detect
1005
+ agentdog config add stdio-server "node server.js" --transport stdio
1006
+ agentdog config show my-api
1007
+ agentdog config update my-api --timeout 60000
1008
+ agentdog config remove old-server
1009
+ agentdog config mcp-config # 生成MCP客户端配置
1010
+ `);
1011
+ }
1012
+ }
1013
+ //# sourceMappingURL=config-commands.js.map