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,664 @@
1
+ import spawn from 'cross-spawn';
2
+ import { EventEmitter } from 'events';
3
+ import { globalLogManager } from '../logging/server-log-manager.js';
4
+ export class StdioAdapter extends EventEmitter {
5
+ name;
6
+ config;
7
+ isConnected = false;
8
+ process;
9
+ requestId = 1;
10
+ pendingRequests = new Map();
11
+ buffer = '';
12
+ stderrBuffer = '';
13
+ // Process stability monitoring
14
+ crashCount = 0;
15
+ lastCrashTime = 0;
16
+ isRecovering = false;
17
+ crashHistory = []; // Crash time history
18
+ isBlacklisted = false; // Whether blacklisted
19
+ blacklistUntil = 0; // Blacklist release time
20
+ isDisabled = false; // Whether disabled, should not auto-reconnect if disabled
21
+ constructor(name, config) {
22
+ super();
23
+ this.name = name;
24
+ this.config = config;
25
+ if (config.transport !== 'stdio') {
26
+ throw new Error(`Invalid transport for StdioAdapter: ${config.transport}`);
27
+ }
28
+ }
29
+ async connect() {
30
+ if (this.isConnected) {
31
+ console.error(`[${this.name}] Already connected, skipping connect() call.`);
32
+ return;
33
+ }
34
+ if (this.isDisabled) {
35
+ console.error(`[${this.name}] Adapter is disabled, skipping connect() call.`);
36
+ throw new Error(`Adapter ${this.name} is disabled.`);
37
+ }
38
+ if (this.isBlacklisted) {
39
+ const remaining = Math.ceil((this.blacklistUntil - Date.now()) / 1000);
40
+ console.error(`[${this.name}] Adapter is blacklisted for ${remaining}s, skipping connect() call.`);
41
+ throw new Error(`Adapter ${this.name} is blacklisted.`);
42
+ }
43
+ if (!this.config.command) {
44
+ throw new Error('Command is required for stdio transport');
45
+ }
46
+ try {
47
+ console.error(`[${this.name}] Attempting to connect via stdio: ${this.config.command} ${this.config.args?.join(' ') || ''}`);
48
+ // Environment variable debug log
49
+ this.logEnvironmentVariables();
50
+ // Prepare process environment variables
51
+ const processEnv = {
52
+ ...process.env,
53
+ ...this.config.env
54
+ };
55
+ // 使用 cross-spawn 启动子进程。
56
+ // Windows 上全局安装的命令(如 npx/npm/codegraph)实为 .cmd 批处理 shim,
57
+ // 仅靠 Node 原生 spawn(shell:false) 无法解析,会立即 ENOENT 导致进程起不来、
58
+ // initialize 握手超时。cross-spawn 内部会自动经 cmd.exe 解析并正确处理转义,
59
+ // 与官方 @modelcontextprotocol/sdk 的 StdioClientTransport 行为一致。
60
+ const spawnOptions = {
61
+ stdio: ['pipe', 'pipe', 'pipe'],
62
+ cwd: this.config.cwd,
63
+ env: processEnv,
64
+ // 经 cmd.exe 启动 .cmd shim 时 Windows 默认会弹出可见的 CMD 窗口,
65
+ // 隐藏之;子进程 stdio 均为管道,无需可见控制台。
66
+ windowsHide: true
67
+ };
68
+ // Enhanced stdio handling for high-output processes like playwright
69
+ if (this.name === 'playwright') {
70
+ spawnOptions.detached = false; // Keep attached but in separate session
71
+ // Increase buffer size for high-volume stderr output
72
+ spawnOptions.stdio = ['pipe', 'pipe', 'pipe'];
73
+ console.error(`[${this.name}] Using special spawn options for playwright`);
74
+ // Verify critical environment variables are set
75
+ if (processEnv.DEBUG) {
76
+ console.error(`[${this.name}] ✅ DEBUG environment variable set: ${processEnv.DEBUG}`);
77
+ }
78
+ else {
79
+ console.error(`[${this.name}] ⚠️ DEBUG environment variable not set`);
80
+ }
81
+ if (processEnv.PWDEBUG) {
82
+ console.error(`[${this.name}] ✅ PWDEBUG environment variable set`);
83
+ }
84
+ }
85
+ this.process = spawn(this.config.command, this.config.args || [], spawnOptions);
86
+ this.setupProcessHandlers();
87
+ // Initialize handshake
88
+ await this.initialize();
89
+ // Mark as connected, let router manage tool list fetching
90
+ this.isConnected = true;
91
+ console.error(`[${this.name}] Connected successfully.`);
92
+ globalLogManager.updateConnectionStatus(this.name, true);
93
+ globalLogManager.addLog(this.name, 'info', `MCP server connected successfully (command: ${this.config.command}, args: ${this.config.args?.join(' ') || 'none'})`, 'system');
94
+ this.emit('connected', { serverName: this.name });
95
+ }
96
+ catch (error) {
97
+ this.cleanup();
98
+ const errorMsg = `[${this.name}] Failed to connect: ${error.message}`;
99
+ console.error(errorMsg);
100
+ globalLogManager.updateConnectionStatus(this.name, false, errorMsg);
101
+ throw new Error(errorMsg);
102
+ }
103
+ }
104
+ async disconnect() {
105
+ if (!this.isConnected) {
106
+ console.error(`[${this.name}] Already disconnected, skipping disconnect() call.`);
107
+ globalLogManager.addLog(this.name, 'warn', 'Disconnect called but server already disconnected', 'system');
108
+ return;
109
+ }
110
+ console.error(`[${this.name}] Attempting to disconnect...`);
111
+ globalLogManager.addLog(this.name, 'info', 'Initiating disconnect...', 'system');
112
+ // Cancel all pending requests
113
+ for (const [id, pending] of this.pendingRequests) {
114
+ clearTimeout(pending.timeout);
115
+ pending.reject(new Error('Connection closed'));
116
+ }
117
+ this.pendingRequests.clear();
118
+ this.cleanup();
119
+ this.isConnected = false;
120
+ console.error(`[${this.name}] Disconnected successfully.`);
121
+ globalLogManager.updateConnectionStatus(this.name, false);
122
+ globalLogManager.addLog(this.name, 'info', 'MCP server disconnected successfully', 'system');
123
+ this.emit('disconnected', { serverName: this.name });
124
+ }
125
+ setupProcessHandlers() {
126
+ if (!this.process)
127
+ return;
128
+ this.process.stdout?.on('data', (data) => {
129
+ const stdout = data.toString();
130
+ // Only log non-JSON response messages to log manager, avoid duplication
131
+ const lines = stdout.trim().split('\n');
132
+ const nonJsonLines = lines.filter(line => {
133
+ try {
134
+ JSON.parse(line.trim());
135
+ return false; // This is a JSON message, do not log
136
+ }
137
+ catch {
138
+ return true; // This is not JSON, log it
139
+ }
140
+ });
141
+ if (nonJsonLines.length > 0) {
142
+ globalLogManager.addServerOutput(this.name, nonJsonLines.join('\n'), 'stdout');
143
+ this.emit('log', { stream: 'stdout', data: nonJsonLines.join('\n') });
144
+ }
145
+ this.handleStdoutData(stdout);
146
+ });
147
+ this.process.stderr?.on('data', (data) => {
148
+ this.stderrBuffer += data.toString();
149
+ const lines = this.stderrBuffer.split('\n');
150
+ this.stderrBuffer = lines.pop() || ''; // Keep incomplete line
151
+ for (const line of lines) {
152
+ if (line.trim()) {
153
+ const stderr = line.trim();
154
+ // Add debug logging for stderr
155
+ console.error(`[${this.name}] DEBUG: STDERR received - length: ${stderr.length}`);
156
+ console.error(`[${this.name}] DEBUG: STDERR content: ${stderr.substring(0, 200)}`);
157
+ // Log to log manager
158
+ globalLogManager.addServerOutput(this.name, stderr, 'stderr');
159
+ this.emit('log', { stream: 'stderr', data: stderr }); // Ensure all output is sent to frontend
160
+ // Detect browsermcp stack overflow errors
161
+ if (stderr.includes('Maximum call stack size exceeded') ||
162
+ stderr.includes('RangeError')) {
163
+ console.error(`⚠️ ${this.name} detected stack overflow, will auto-restart on next request`);
164
+ globalLogManager.addLog(this.name, 'warn', 'Stack overflow detected, will auto-restart on next request', 'system');
165
+ }
166
+ }
167
+ }
168
+ });
169
+ this.process.on('error', (error) => {
170
+ console.error(`${this.name} process error:`, error);
171
+ globalLogManager.addLog(this.name, 'error', `Process error: ${error.message}`, 'system');
172
+ this.emit('error', { error, context: `${this.name}-process` });
173
+ });
174
+ this.process.on('exit', (code, signal) => {
175
+ console.error(`[${this.name}] DEBUG: Process exited with code ${code}, signal ${signal}.`);
176
+ console.error(`[${this.name}] DEBUG: Pending requests at exit: ${this.pendingRequests.size}`);
177
+ globalLogManager.addLog(this.name, 'error', `Process exited with code ${code}, signal ${signal}`, 'system');
178
+ // Log crash history
179
+ const now = Date.now();
180
+ this.crashCount++;
181
+ this.lastCrashTime = now;
182
+ this.crashHistory.push(now);
183
+ // Only keep crash records for the last 5 minutes
184
+ const fiveMinutesAgo = now - 5 * 60 * 1000;
185
+ this.crashHistory = this.crashHistory.filter(time => time > fiveMinutesAgo);
186
+ if (signal === 'SIGKILL') {
187
+ const killMsg = `⚠️ Process was killed with SIGKILL - likely due to internal errors or resource issues. Crash count: ${this.crashCount} (${this.crashHistory.length} in last 5min)`;
188
+ console.error(`[${this.name}] ${killMsg}`);
189
+ globalLogManager.addLog(this.name, 'error', killMsg, 'system');
190
+ }
191
+ // Check if blacklisting is needed
192
+ this.checkAndUpdateBlacklist();
193
+ this.isConnected = false;
194
+ globalLogManager.updateConnectionStatus(this.name, false, `Process exited: code=${code}, signal=${signal}`);
195
+ this.emit('disconnected', {
196
+ serverName: this.name,
197
+ error: new Error(`Process exited: code=${code}, signal=${signal}`)
198
+ });
199
+ // Smart reconnect strategy
200
+ if (this.shouldAttemptReconnect(signal)) {
201
+ const delay = this.getReconnectDelay();
202
+ const reconnectMsg = `🔄 Will attempt reconnect in ${delay}ms`;
203
+ console.error(`[${this.name}] ${reconnectMsg}`);
204
+ globalLogManager.addLog(this.name, 'info', reconnectMsg, 'system');
205
+ setTimeout(() => {
206
+ this.attemptRecovery();
207
+ }, delay);
208
+ }
209
+ else {
210
+ const noReconnectMsg = '🚫 Not attempting reconnect';
211
+ console.error(`[${this.name}] ${noReconnectMsg}`);
212
+ globalLogManager.addLog(this.name, 'warn', noReconnectMsg, 'system');
213
+ }
214
+ });
215
+ }
216
+ handleStdoutData(data) {
217
+ console.error(`[${this.name}] DEBUG: Received stdout data - length: ${data.length}`);
218
+ this.buffer += data;
219
+ const lines = this.buffer.split('\n');
220
+ this.buffer = lines.pop() || ''; // Keep the last incomplete line
221
+ console.error(`[${this.name}] DEBUG: Split into ${lines.length} lines, buffer remaining: ${this.buffer.length}`);
222
+ for (const line of lines) {
223
+ if (line.trim()) {
224
+ console.error(`[${this.name}] DEBUG: Processing line length: ${line.length}`);
225
+ try {
226
+ const message = JSON.parse(line);
227
+ console.error(`[${this.name}] DEBUG: Parsed message - id: ${message.id}, method: ${message.method}`);
228
+ this.handleMessage(message);
229
+ }
230
+ catch (error) {
231
+ console.error(`Failed to parse message from ${this.name}:`, line);
232
+ }
233
+ }
234
+ }
235
+ }
236
+ handleMessage(message) {
237
+ if (message.id && this.pendingRequests.has(message.id)) {
238
+ // This is a response to a request
239
+ const pending = this.pendingRequests.get(message.id);
240
+ this.pendingRequests.delete(message.id);
241
+ clearTimeout(pending.timeout);
242
+ // Log response details (but not the raw JSON)
243
+ if (message.error) {
244
+ globalLogManager.addLog(this.name, 'error', `Method response error (ID: ${message.id}): ${JSON.stringify(message.error)}`, 'system');
245
+ }
246
+ else {
247
+ globalLogManager.addLog(this.name, 'info', `Method response success (ID: ${message.id}): ${message.result ? 'with result' : 'no result'}`, 'system');
248
+ }
249
+ pending.resolve(message);
250
+ }
251
+ else if (!message.id && message.method) {
252
+ // This is a notification
253
+ this.handleNotification(message);
254
+ }
255
+ }
256
+ handleNotification(notification) {
257
+ console.error(`Notification from ${this.name}:`, notification.method);
258
+ globalLogManager.addLog(this.name, 'info', `Notification received: ${notification.method}`, 'system');
259
+ if (notification.method === 'notifications/tools/list_changed') {
260
+ // Tool list changed, notify router for unified handling
261
+ globalLogManager.addLog(this.name, 'info', 'Tools list changed, notifying router', 'system');
262
+ this.emit('tools-changed', { serverName: this.name });
263
+ }
264
+ // Forward notification to upper layer
265
+ this.emit('notification', { serverName: this.name, notification });
266
+ }
267
+ async initialize() {
268
+ const initRequest = {
269
+ jsonrpc: '2.0',
270
+ id: this.getNextRequestId(),
271
+ method: 'initialize',
272
+ params: {
273
+ protocolVersion: '2024-11-05',
274
+ capabilities: {
275
+ tools: {}
276
+ },
277
+ clientInfo: {
278
+ name: 'mcpdog',
279
+ version: '2.0.0'
280
+ }
281
+ }
282
+ };
283
+ const response = await this.sendRequest(initRequest);
284
+ if (response.error) {
285
+ throw new Error(`Initialize failed: ${response.error.message}`);
286
+ }
287
+ // Send initialized notification
288
+ const initializedNotification = {
289
+ jsonrpc: '2.0',
290
+ method: 'notifications/initialized'
291
+ };
292
+ this.sendNotification(initializedNotification);
293
+ }
294
+ async getTools() {
295
+ const request = {
296
+ jsonrpc: '2.0',
297
+ id: this.getNextRequestId(),
298
+ method: 'tools/list',
299
+ params: {}
300
+ };
301
+ const response = await this.sendRequest(request);
302
+ if (response.error) {
303
+ throw new Error(`Failed to get tools: ${response.error.message}`);
304
+ }
305
+ return response.result?.tools || [];
306
+ }
307
+ async callTool(name, args) {
308
+ const startTime = Date.now();
309
+ globalLogManager.addLog(this.name, 'info', `Calling tool: ${name}`, 'system');
310
+ const request = {
311
+ jsonrpc: '2.0',
312
+ id: this.getNextRequestId(),
313
+ method: 'tools/call',
314
+ params: {
315
+ name,
316
+ arguments: args
317
+ }
318
+ };
319
+ try {
320
+ const response = await this.sendRequest(request);
321
+ const duration = Date.now() - startTime;
322
+ if (response.error) {
323
+ globalLogManager.addLog(this.name, 'error', `Tool call failed: ${name} (duration: ${duration}ms, error: ${JSON.stringify(response.error)})`, 'system');
324
+ }
325
+ else {
326
+ globalLogManager.addLog(this.name, 'info', `Tool call successful: ${name} (duration: ${duration}ms)`, 'system');
327
+ if (response.result?.content) {
328
+ // Log content summary without serializing large content to avoid blocking
329
+ const contentCount = Array.isArray(response.result.content) ? response.result.content.length : 1;
330
+ globalLogManager.addLog(this.name, 'debug', `Tool result: ${contentCount} content item(s)`, 'system');
331
+ }
332
+ }
333
+ return response;
334
+ }
335
+ catch (error) {
336
+ const duration = Date.now() - startTime;
337
+ globalLogManager.addLog(this.name, 'error', `Tool call exception: ${name} (duration: ${duration}ms, error: ${error.message})`, 'system');
338
+ throw error;
339
+ }
340
+ }
341
+ async sendRequest(request) {
342
+ // Add detailed debug logging for troubleshooting
343
+ console.error(`[${this.name}] DEBUG: sendRequest called - method: ${request.method}, id: ${request.id}`);
344
+ globalLogManager.addLog(this.name, 'info', `DEBUG: Sending request ${request.method} (ID: ${request.id})`, 'system');
345
+ // Check process status, try to reconnect if dead
346
+ if (!this.process?.stdin || this.process.killed || this.process.exitCode !== null) {
347
+ console.error(`${this.name} process is dead, attempting reconnection...`);
348
+ globalLogManager.addLog(this.name, 'warn', 'Process is dead, attempting reconnection...', 'system');
349
+ try {
350
+ await this.connect();
351
+ globalLogManager.addLog(this.name, 'info', 'Reconnection successful', 'system');
352
+ }
353
+ catch (error) {
354
+ const errorMsg = `Failed to reconnect to ${this.name}: ${error.message}`;
355
+ globalLogManager.addLog(this.name, 'error', errorMsg, 'system');
356
+ throw new Error(errorMsg);
357
+ }
358
+ }
359
+ if (!this.process?.stdin) {
360
+ const errorMsg = `Not connected to ${this.name}`;
361
+ globalLogManager.addLog(this.name, 'error', errorMsg, 'system');
362
+ throw new Error(errorMsg);
363
+ }
364
+ const startTime = Date.now();
365
+ return new Promise((resolve, reject) => {
366
+ const timeout = setTimeout(() => {
367
+ this.pendingRequests.delete(request.id);
368
+ const timeoutMsg = `Request timeout for ${this.name} (method: ${request.method}, timeout: ${this.config.timeout || 30000}ms)`;
369
+ globalLogManager.addLog(this.name, 'error', timeoutMsg, 'system');
370
+ reject(new Error(timeoutMsg));
371
+ }, this.config.timeout || 30000);
372
+ this.pendingRequests.set(request.id, {
373
+ resolve: (response) => {
374
+ // Skip debug logging in resolve
375
+ resolve(response);
376
+ },
377
+ reject: (error) => {
378
+ const duration = Date.now() - startTime;
379
+ globalLogManager.addLog(this.name, 'error', `Request failed: ${request.method} (ID: ${request.id}, duration: ${duration}ms, error: ${error.message})`, 'system');
380
+ reject(error);
381
+ },
382
+ timeout
383
+ });
384
+ try {
385
+ const requestStr = JSON.stringify(request) + '\n';
386
+ console.error(`[${this.name}] DEBUG: Writing to stdin - length: ${requestStr.length}`);
387
+ this.process.stdin.write(requestStr);
388
+ console.error(`[${this.name}] DEBUG: Successfully wrote to stdin`);
389
+ }
390
+ catch (error) {
391
+ this.pendingRequests.delete(request.id);
392
+ clearTimeout(timeout);
393
+ const errorMsg = `Failed to send request to ${this.name}: ${error.message}`;
394
+ globalLogManager.addLog(this.name, 'error', errorMsg, 'system');
395
+ reject(new Error(errorMsg));
396
+ }
397
+ });
398
+ }
399
+ sendNotification(notification) {
400
+ if (!this.isConnected || !this.process?.stdin) {
401
+ return;
402
+ }
403
+ try {
404
+ const notificationStr = JSON.stringify(notification) + '\n';
405
+ this.process.stdin.write(notificationStr);
406
+ }
407
+ catch (error) {
408
+ console.error(`Failed to send notification to ${this.name}:`, error);
409
+ }
410
+ }
411
+ getNextRequestId() {
412
+ return this.requestId++;
413
+ }
414
+ cleanup() {
415
+ if (this.process) {
416
+ try {
417
+ if (!this.process.killed) {
418
+ this.process.kill('SIGTERM');
419
+ }
420
+ // If process does not end within 2 seconds, force kill
421
+ setTimeout(() => {
422
+ if (this.process && !this.process.killed) {
423
+ this.process.kill('SIGKILL');
424
+ }
425
+ }, 2000);
426
+ }
427
+ catch (error) {
428
+ console.error(`Error killing process for ${this.name}:`, error);
429
+ }
430
+ this.process = undefined;
431
+ }
432
+ this.buffer = '';
433
+ }
434
+ // Get current tool list (fetch in real-time from server)
435
+ async getCachedTools() {
436
+ if (!this.isConnected)
437
+ return [];
438
+ return await this.getTools();
439
+ }
440
+ // Check if specific tool is available (check in real-time from server)
441
+ async hasTools(toolName) {
442
+ if (!this.isConnected)
443
+ return false;
444
+ const tools = await this.getTools();
445
+ return tools.some(tool => tool.name === toolName);
446
+ }
447
+ // Get connection status information
448
+ getStatus() {
449
+ const now = Date.now();
450
+ return {
451
+ name: this.name,
452
+ connected: this.isConnected,
453
+ toolCount: 0, // Tool count managed by router
454
+ pendingRequests: this.pendingRequests.size,
455
+ crashCount: this.crashCount,
456
+ recentCrashes: this.crashHistory.length,
457
+ isBlacklisted: this.isBlacklisted,
458
+ blacklistRemaining: this.isBlacklisted ? Math.max(0, this.blacklistUntil - now) : undefined
459
+ };
460
+ }
461
+ // Manually clear blacklist (admin function)
462
+ clearBlacklist() {
463
+ if (this.isBlacklisted) {
464
+ console.error(`🟢 Manually clearing blacklist for ${this.name}`);
465
+ this.isBlacklisted = false;
466
+ this.blacklistUntil = 0;
467
+ this.crashCount = 0;
468
+ this.crashHistory = [];
469
+ }
470
+ }
471
+ // Get crash statistics
472
+ getCrashStats() {
473
+ const now = Date.now();
474
+ return {
475
+ totalCrashes: this.crashCount,
476
+ recentCrashes: this.crashHistory.length,
477
+ crashHistory: this.crashHistory.map(time => new Date(time).toISOString()),
478
+ isBlacklisted: this.isBlacklisted,
479
+ nextAttemptIn: this.isBlacklisted ? Math.max(0, this.blacklistUntil - now) : undefined
480
+ };
481
+ }
482
+ // Check and update blacklist status
483
+ checkAndUpdateBlacklist() {
484
+ const now = Date.now();
485
+ // Check if blacklisted and time not yet reached
486
+ if (this.isBlacklisted && now < this.blacklistUntil) {
487
+ return;
488
+ }
489
+ // If blacklist time has passed, remove from blacklist
490
+ if (this.isBlacklisted && now >= this.blacklistUntil) {
491
+ console.error(`🟢 ${this.name} removed from blacklist, allowing reconnection`);
492
+ this.isBlacklisted = false;
493
+ this.blacklistUntil = 0;
494
+ // Reset some statistics
495
+ this.crashCount = Math.max(0, this.crashCount - 2);
496
+ }
497
+ // Check if blacklisting is needed
498
+ const recentCrashes = this.crashHistory.length;
499
+ if (recentCrashes >= 5) {
500
+ // More than 5 crashes in 5 minutes, blacklist for 30 minutes
501
+ this.isBlacklisted = true;
502
+ this.blacklistUntil = now + 30 * 60 * 1000; // 30 minutes
503
+ console.error(`🔴 ${this.name} blacklisted for 30 minutes due to ${recentCrashes} crashes in 5 minutes`);
504
+ }
505
+ else if (recentCrashes >= 3) {
506
+ // More than 3 crashes in 5 minutes, blacklist for 10 minutes
507
+ this.isBlacklisted = true;
508
+ this.blacklistUntil = now + 10 * 60 * 1000; // 10 minutes
509
+ console.error(`🟡 ${this.name} blacklisted for 10 minutes due to ${recentCrashes} crashes in 5 minutes`);
510
+ }
511
+ }
512
+ // Smart reconnect strategy
513
+ shouldAttemptReconnect(signal) {
514
+ // If server is disabled, should not auto-reconnect
515
+ if (this.isDisabled) {
516
+ console.error(`❌ ${this.name} is disabled, no auto-reconnect`);
517
+ return false;
518
+ }
519
+ // If already recovering, do not try again
520
+ if (this.isRecovering) {
521
+ return false;
522
+ }
523
+ // Check blacklist status
524
+ const now = Date.now();
525
+ if (this.isBlacklisted && now < this.blacklistUntil) {
526
+ const remainingMinutes = Math.ceil((this.blacklistUntil - now) / (60 * 1000));
527
+ console.error(`❌ ${this.name} is blacklisted for ${remainingMinutes} more minutes, no auto-reconnect`);
528
+ return false;
529
+ }
530
+ // If recent crashes are too frequent, be cautious even if not blacklisted
531
+ if (this.crashHistory.length >= 2) {
532
+ const lastTwoCrashes = this.crashHistory.slice(-2);
533
+ const timeBetweenCrashes = lastTwoCrashes[1] - lastTwoCrashes[0];
534
+ // If two crashes are less than 30 seconds apart, pause reconnect
535
+ if (timeBetweenCrashes < 30 * 1000) {
536
+ console.error(`⏸️ ${this.name} crashing too quickly (${Math.round(timeBetweenCrashes / 1000)}s apart), pausing auto-reconnect`);
537
+ return false;
538
+ }
539
+ }
540
+ // Only SIGKILL or other abnormal exits require reconnect
541
+ return signal === 'SIGKILL' || signal === 'SIGTERM' || signal === null;
542
+ }
543
+ getReconnectDelay() {
544
+ // Adjust delay strategy based on crash history
545
+ const recentCrashes = this.crashHistory.length;
546
+ const baseDelay = 2000; // 2 second base delay
547
+ let delay = baseDelay;
548
+ // Adjust delay based on recent crash count
549
+ if (recentCrashes >= 4) {
550
+ delay = 60000; // 1 minute
551
+ }
552
+ else if (recentCrashes >= 3) {
553
+ delay = 30000; // 30 seconds
554
+ }
555
+ else if (recentCrashes >= 2) {
556
+ delay = 10000; // 10 seconds
557
+ }
558
+ else {
559
+ delay = baseDelay; // 2 seconds
560
+ }
561
+ // If frequent crashes, add random delay to avoid thundering herd effect
562
+ if (recentCrashes >= 2) {
563
+ const randomDelay = Math.random() * delay * 0.5; // 0-50% random delay
564
+ delay += randomDelay;
565
+ }
566
+ return Math.round(delay);
567
+ }
568
+ async attemptRecovery() {
569
+ if (this.isRecovering || this.isConnected) {
570
+ return;
571
+ }
572
+ this.isRecovering = true;
573
+ console.error(`🔧 ${this.name} attempting recovery (attempt ${this.crashCount})`);
574
+ try {
575
+ // Clean up old state
576
+ this.cleanup();
577
+ // Wait a bit for system resources to be released
578
+ await new Promise(resolve => setTimeout(resolve, 1000));
579
+ // Try to reconnect
580
+ await this.connect();
581
+ console.error(`✅ ${this.name} recovered successfully`);
582
+ // Reset crash counter (after successful connection)
583
+ if (this.isConnected) {
584
+ this.crashCount = Math.max(0, this.crashCount - 1);
585
+ }
586
+ }
587
+ catch (error) {
588
+ console.error(`❌ ${this.name} recovery failed:`, error.message);
589
+ }
590
+ finally {
591
+ this.isRecovering = false;
592
+ }
593
+ }
594
+ // Manually trigger recovery (for external calls)
595
+ async forceReconnect() {
596
+ console.error(`🔄 Force reconnecting ${this.name}...`);
597
+ this.crashCount = 0; // Reset counter
598
+ await this.disconnect();
599
+ await this.attemptRecovery();
600
+ }
601
+ // Disable adapter, prevent auto-reconnect
602
+ disable() {
603
+ console.error(`🚫 Disabling ${this.name} - no auto-reconnect`);
604
+ this.isDisabled = true;
605
+ }
606
+ // Re-enable adapter, allow auto-reconnect
607
+ enable() {
608
+ console.error(`✅ Enabling ${this.name} - auto-reconnect allowed`);
609
+ this.isDisabled = false;
610
+ }
611
+ /**
612
+ * Log environment variable debug information
613
+ */
614
+ logEnvironmentVariables() {
615
+ const configEnv = this.config.env;
616
+ if (!configEnv || Object.keys(configEnv).length === 0) {
617
+ console.error(`[${this.name}] 🔧 No custom environment variables configured`);
618
+ return;
619
+ }
620
+ console.error(`[${this.name}] 🔧 Environment Variables Configuration:`);
621
+ // Statistics
622
+ const envKeys = Object.keys(configEnv);
623
+ console.error(`[${this.name}] 📊 Total custom environment variables: ${envKeys.length}`);
624
+ // Detailed log (safely, without showing sensitive values)
625
+ envKeys.forEach(key => {
626
+ const value = configEnv[key];
627
+ const isSensitive = this.isSensitiveEnvVar(key);
628
+ if (isSensitive) {
629
+ console.error(`[${this.name}] 🔐 ${key}=[REDACTED] (${value.length} chars, sensitive)`);
630
+ }
631
+ else {
632
+ // For non-sensitive variables, also limit display length
633
+ const displayValue = value.length > 50 ? `${value.substring(0, 47)}...` : value;
634
+ console.error(`[${this.name}] 🔧 ${key}=${displayValue}`);
635
+ }
636
+ });
637
+ // Environment variable override check
638
+ const systemEnvKeys = Object.keys(process.env);
639
+ const overriddenKeys = envKeys.filter(key => systemEnvKeys.includes(key));
640
+ if (overriddenKeys.length > 0) {
641
+ console.error(`[${this.name}] ⚠️ Overriding ${overriddenKeys.length} system environment variables: ${overriddenKeys.join(', ')}`);
642
+ }
643
+ // Working directory information
644
+ if (this.config.cwd) {
645
+ console.error(`[${this.name}] 📁 Working directory: ${this.config.cwd}`);
646
+ }
647
+ else {
648
+ console.error(`[${this.name}] 📁 Working directory: ${process.cwd()} (default)`);
649
+ }
650
+ }
651
+ /**
652
+ * Check if environment variable is sensitive
653
+ */
654
+ isSensitiveEnvVar(key) {
655
+ const sensitiveKeywords = [
656
+ 'password', 'secret', 'key', 'token', 'auth', 'credential',
657
+ 'pass', 'pwd', 'private', 'sensitive', 'security', 'api_key',
658
+ 'access_token', 'refresh_token', 'jwt', 'session'
659
+ ];
660
+ const lowerKey = key.toLowerCase();
661
+ return sensitiveKeywords.some(keyword => lowerKey.includes(keyword));
662
+ }
663
+ }
664
+ //# sourceMappingURL=stdio-adapter.js.map