codex-linux 1.0.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 (367) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.eslintrc.json +27 -0
  3. package/.github/workflows/ci.yml +156 -0
  4. package/.huskyrc +7 -0
  5. package/.lintstagedrc +13 -0
  6. package/.prettierrc +12 -0
  7. package/CLAUDE.md +163 -0
  8. package/DESIGN_SUPERIOR.md +73 -0
  9. package/Dockerfile +64 -0
  10. package/INSTALLATION.md +152 -0
  11. package/LICENSE +21 -0
  12. package/README.md +245 -0
  13. package/assets/skills/code-review/instructions.md +102 -0
  14. package/assets/skills/code-review/skill.yaml +15 -0
  15. package/assets/skills/refactoring/instructions.md +149 -0
  16. package/assets/skills/refactoring/skill.yaml +15 -0
  17. package/assets/skills/testing/skill.yaml +15 -0
  18. package/commitlint.config.js +23 -0
  19. package/dist/main/DatabaseManager.js +763 -0
  20. package/dist/main/DatabaseManager.js.map +1 -0
  21. package/dist/main/SettingsManager.js +61 -0
  22. package/dist/main/SettingsManager.js.map +1 -0
  23. package/dist/main/agents/AgentOrchestrator.js +787 -0
  24. package/dist/main/agents/AgentOrchestrator.js.map +1 -0
  25. package/dist/main/agents/AgentSDK.js +219 -0
  26. package/dist/main/agents/AgentSDK.js.map +1 -0
  27. package/dist/main/agents/AgentTools.js +348 -0
  28. package/dist/main/agents/AgentTools.js.map +1 -0
  29. package/dist/main/agents/CodeIndex.js +233 -0
  30. package/dist/main/agents/CodeIndex.js.map +1 -0
  31. package/dist/main/agents/EmbeddingService.js +80 -0
  32. package/dist/main/agents/EmbeddingService.js.map +1 -0
  33. package/dist/main/agents/NativeToolCalling.js +206 -0
  34. package/dist/main/agents/NativeToolCalling.js.map +1 -0
  35. package/dist/main/api/APIServer.js +278 -0
  36. package/dist/main/api/APIServer.js.map +1 -0
  37. package/dist/main/api/RateLimiter.js +138 -0
  38. package/dist/main/api/RateLimiter.js.map +1 -0
  39. package/dist/main/api/WebSocketManager.js +300 -0
  40. package/dist/main/api/WebSocketManager.js.map +1 -0
  41. package/dist/main/assistant/ContextOptimizer.js +192 -0
  42. package/dist/main/assistant/ContextOptimizer.js.map +1 -0
  43. package/dist/main/assistant/PredictedOutputManager.js +172 -0
  44. package/dist/main/assistant/PredictedOutputManager.js.map +1 -0
  45. package/dist/main/assistant/PromptCacheManager.js +193 -0
  46. package/dist/main/assistant/PromptCacheManager.js.map +1 -0
  47. package/dist/main/assistant/PromptOptimizer.js +626 -0
  48. package/dist/main/assistant/PromptOptimizer.js.map +1 -0
  49. package/dist/main/assistant/SmartCodeAssistant.js +224 -0
  50. package/dist/main/assistant/SmartCodeAssistant.js.map +1 -0
  51. package/dist/main/auth/SessionManager.js +300 -0
  52. package/dist/main/auth/SessionManager.js.map +1 -0
  53. package/dist/main/automations/AdvancedWebhookSystem.js +212 -0
  54. package/dist/main/automations/AdvancedWebhookSystem.js.map +1 -0
  55. package/dist/main/automations/AutomationScheduler.js +269 -0
  56. package/dist/main/automations/AutomationScheduler.js.map +1 -0
  57. package/dist/main/automations/BatchProcessingSystem.js +159 -0
  58. package/dist/main/automations/BatchProcessingSystem.js.map +1 -0
  59. package/dist/main/automations/BrowserAutomationManager.js +195 -0
  60. package/dist/main/automations/BrowserAutomationManager.js.map +1 -0
  61. package/dist/main/automations/GitHubActionsManager.js +129 -0
  62. package/dist/main/automations/GitHubActionsManager.js.map +1 -0
  63. package/dist/main/automations/GitLabCIManager.js +122 -0
  64. package/dist/main/automations/GitLabCIManager.js.map +1 -0
  65. package/dist/main/automations/PriorityQueueManager.js +240 -0
  66. package/dist/main/automations/PriorityQueueManager.js.map +1 -0
  67. package/dist/main/background/BackgroundModeManager.js +117 -0
  68. package/dist/main/background/BackgroundModeManager.js.map +1 -0
  69. package/dist/main/backup/BackupManager.js +254 -0
  70. package/dist/main/backup/BackupManager.js.map +1 -0
  71. package/dist/main/backup/MigrationManager.js +114 -0
  72. package/dist/main/backup/MigrationManager.js.map +1 -0
  73. package/dist/main/commands/SlashCommandManager.js +399 -0
  74. package/dist/main/commands/SlashCommandManager.js.map +1 -0
  75. package/dist/main/config/ClaudeMdParser.js +519 -0
  76. package/dist/main/config/ClaudeMdParser.js.map +1 -0
  77. package/dist/main/config/CustomizationManager.js +381 -0
  78. package/dist/main/config/CustomizationManager.js.map +1 -0
  79. package/dist/main/config/LaunchConfigManager.js +211 -0
  80. package/dist/main/config/LaunchConfigManager.js.map +1 -0
  81. package/dist/main/config/SettingsManager.js +166 -0
  82. package/dist/main/config/SettingsManager.js.map +1 -0
  83. package/dist/main/connectors/ConnectorManager.js +151 -0
  84. package/dist/main/connectors/ConnectorManager.js.map +1 -0
  85. package/dist/main/connectors/DatabaseConnector.js +222 -0
  86. package/dist/main/connectors/DatabaseConnector.js.map +1 -0
  87. package/dist/main/cowork/CoworkManager.js +324 -0
  88. package/dist/main/cowork/CoworkManager.js.map +1 -0
  89. package/dist/main/evals/AgentEvalFramework.js +538 -0
  90. package/dist/main/evals/AgentEvalFramework.js.map +1 -0
  91. package/dist/main/evals/GraderManager.js +285 -0
  92. package/dist/main/evals/GraderManager.js.map +1 -0
  93. package/dist/main/git/GitWorktreeManager.js +214 -0
  94. package/dist/main/git/GitWorktreeManager.js.map +1 -0
  95. package/dist/main/github/GitHubPRMonitor.js +244 -0
  96. package/dist/main/github/GitHubPRMonitor.js.map +1 -0
  97. package/dist/main/ide/ContinueInManager.js +181 -0
  98. package/dist/main/ide/ContinueInManager.js.map +1 -0
  99. package/dist/main/ide/IDEIntegration.js +277 -0
  100. package/dist/main/ide/IDEIntegration.js.map +1 -0
  101. package/dist/main/integrations/LinearManager.js +252 -0
  102. package/dist/main/integrations/LinearManager.js.map +1 -0
  103. package/dist/main/integrations/SlackBotManager.js +247 -0
  104. package/dist/main/integrations/SlackBotManager.js.map +1 -0
  105. package/dist/main/lsp/LSPManager.js +394 -0
  106. package/dist/main/lsp/LSPManager.js.map +1 -0
  107. package/dist/main/main.js +1087 -0
  108. package/dist/main/main.js.map +1 -0
  109. package/dist/main/mcp/MCPConfigurationManager.js +281 -0
  110. package/dist/main/mcp/MCPConfigurationManager.js.map +1 -0
  111. package/dist/main/mcp/MCPManager.js +710 -0
  112. package/dist/main/mcp/MCPManager.js.map +1 -0
  113. package/dist/main/mcp/MCPRegistry.js +272 -0
  114. package/dist/main/mcp/MCPRegistry.js.map +1 -0
  115. package/dist/main/monitoring/ErrorRecoveryManager.js +268 -0
  116. package/dist/main/monitoring/ErrorRecoveryManager.js.map +1 -0
  117. package/dist/main/monitoring/ErrorTracker.js +57 -0
  118. package/dist/main/monitoring/ErrorTracker.js.map +1 -0
  119. package/dist/main/monitoring/MetricsCollector.js +155 -0
  120. package/dist/main/monitoring/MetricsCollector.js.map +1 -0
  121. package/dist/main/monitoring/TraceGradingSystem.js +148 -0
  122. package/dist/main/monitoring/TraceGradingSystem.js.map +1 -0
  123. package/dist/main/notifications/NotificationManager.js +67 -0
  124. package/dist/main/notifications/NotificationManager.js.map +1 -0
  125. package/dist/main/pair/AIPairProgramming.js +200 -0
  126. package/dist/main/pair/AIPairProgramming.js.map +1 -0
  127. package/dist/main/plugins/PluginManager.js +222 -0
  128. package/dist/main/plugins/PluginManager.js.map +1 -0
  129. package/dist/main/plugins/PluginMarketplace.js +237 -0
  130. package/dist/main/plugins/PluginMarketplace.js.map +1 -0
  131. package/dist/main/preload.js +189 -0
  132. package/dist/main/preload.js.map +1 -0
  133. package/dist/main/preview/PreviewSessionManager.js +170 -0
  134. package/dist/main/preview/PreviewSessionManager.js.map +1 -0
  135. package/dist/main/providers/AIProviderManager.js +327 -0
  136. package/dist/main/providers/AIProviderManager.js.map +1 -0
  137. package/dist/main/providers/FineTuningManager.js +276 -0
  138. package/dist/main/providers/FineTuningManager.js.map +1 -0
  139. package/dist/main/providers/FreeModelsProvider.js +1104 -0
  140. package/dist/main/providers/FreeModelsProvider.js.map +1 -0
  141. package/dist/main/realtime/RealtimeManager.js +116 -0
  142. package/dist/main/realtime/RealtimeManager.js.map +1 -0
  143. package/dist/main/remote/CloudEnvironmentManager.js +232 -0
  144. package/dist/main/remote/CloudEnvironmentManager.js.map +1 -0
  145. package/dist/main/remote/RemoteSessionManager.js +255 -0
  146. package/dist/main/remote/RemoteSessionManager.js.map +1 -0
  147. package/dist/main/search/DeepResearchManager.js +335 -0
  148. package/dist/main/search/DeepResearchManager.js.map +1 -0
  149. package/dist/main/search/WebSearchIntegration.js +147 -0
  150. package/dist/main/search/WebSearchIntegration.js.map +1 -0
  151. package/dist/main/security/AdminConsoleManager.js +223 -0
  152. package/dist/main/security/AdminConsoleManager.js.map +1 -0
  153. package/dist/main/security/AuditLogger.js +136 -0
  154. package/dist/main/security/AuditLogger.js.map +1 -0
  155. package/dist/main/security/PermissionManager.js +144 -0
  156. package/dist/main/security/PermissionManager.js.map +1 -0
  157. package/dist/main/security/SSOManager.js +173 -0
  158. package/dist/main/security/SSOManager.js.map +1 -0
  159. package/dist/main/security/SecurityManager.js +152 -0
  160. package/dist/main/security/SecurityManager.js.map +1 -0
  161. package/dist/main/skills/SkillsManager.js +223 -0
  162. package/dist/main/skills/SkillsManager.js.map +1 -0
  163. package/dist/main/ssh/SSHManager.js +65 -0
  164. package/dist/main/ssh/SSHManager.js.map +1 -0
  165. package/dist/main/streaming/StreamingManager.js +225 -0
  166. package/dist/main/streaming/StreamingManager.js.map +1 -0
  167. package/dist/main/sync/CloudSyncManager.js +422 -0
  168. package/dist/main/sync/CloudSyncManager.js.map +1 -0
  169. package/dist/main/types.js +28 -0
  170. package/dist/main/types.js.map +1 -0
  171. package/dist/main/verification/AutoVerifyManager.js +235 -0
  172. package/dist/main/verification/AutoVerifyManager.js.map +1 -0
  173. package/dist/main/vision/ComputerUseManager.js +376 -0
  174. package/dist/main/vision/ComputerUseManager.js.map +1 -0
  175. package/dist/main/vision/ImageVideoGenerationManager.js +401 -0
  176. package/dist/main/vision/ImageVideoGenerationManager.js.map +1 -0
  177. package/dist/main/vision/VisionManager.js +172 -0
  178. package/dist/main/vision/VisionManager.js.map +1 -0
  179. package/dist/renderer/assets/main-DJlZQBCA.js +304 -0
  180. package/dist/renderer/assets/main-N33ZXEr8.css +1 -0
  181. package/dist/renderer/index.html +21 -0
  182. package/dist/renderer/manifest.json +42 -0
  183. package/dist/renderer/sw.ts +109 -0
  184. package/dist/shared/types.js +35 -0
  185. package/dist/shared/types.js.map +1 -0
  186. package/docker-compose.yml +65 -0
  187. package/docs/API.md +307 -0
  188. package/docs/USER_GUIDE.md +476 -0
  189. package/examples/plugins/sample-plugin/package.json +41 -0
  190. package/examples/plugins/sample-plugin/src/index.ts +75 -0
  191. package/index.html +20 -0
  192. package/jest.config.js +39 -0
  193. package/package.json +180 -0
  194. package/packages/cli/package.json +29 -0
  195. package/packages/cli/src/commands/agents.ts +199 -0
  196. package/packages/cli/src/commands/tasks.ts +61 -0
  197. package/packages/cli/src/index.ts +91 -0
  198. package/packages/cli/src/utils/api.ts +45 -0
  199. package/packages/cli/src/utils/config.ts +61 -0
  200. package/packages/npm-installer/bin/codex-linux +126 -0
  201. package/packages/npm-installer/lib/download.js +273 -0
  202. package/packages/npm-installer/package.json +42 -0
  203. package/packages/vscode-extension/package.json +167 -0
  204. package/packages/vscode-extension/src/api.ts +68 -0
  205. package/packages/vscode-extension/src/extension.ts +161 -0
  206. package/packages/vscode-extension/src/panels/chatPanel.ts +265 -0
  207. package/packages/vscode-extension/src/panels/createAgentPanel.ts +227 -0
  208. package/packages/vscode-extension/src/providers/agentsProvider.ts +80 -0
  209. package/postcss.config.js +6 -0
  210. package/public/manifest.json +42 -0
  211. package/public/sw.ts +109 -0
  212. package/scripts/install-dev.sh +103 -0
  213. package/scripts/install.sh +275 -0
  214. package/src/main/DatabaseManager.ts +950 -0
  215. package/src/main/SettingsManager.ts +63 -0
  216. package/src/main/agents/AgentOrchestrator.ts +930 -0
  217. package/src/main/agents/AgentSDK.ts +269 -0
  218. package/src/main/agents/AgentTools.ts +380 -0
  219. package/src/main/agents/CodeIndex.ts +240 -0
  220. package/src/main/agents/EmbeddingService.ts +88 -0
  221. package/src/main/agents/NativeToolCalling.ts +245 -0
  222. package/src/main/api/APIServer.ts +316 -0
  223. package/src/main/api/RateLimiter.ts +165 -0
  224. package/src/main/api/WebSocketManager.ts +398 -0
  225. package/src/main/assistant/ContextOptimizer.ts +214 -0
  226. package/src/main/assistant/PredictedOutputManager.ts +265 -0
  227. package/src/main/assistant/PromptCacheManager.ts +280 -0
  228. package/src/main/assistant/PromptOptimizer.ts +746 -0
  229. package/src/main/assistant/SmartCodeAssistant.ts +234 -0
  230. package/src/main/auth/SessionManager.ts +415 -0
  231. package/src/main/automations/AdvancedWebhookSystem.ts +281 -0
  232. package/src/main/automations/AutomationScheduler.ts +272 -0
  233. package/src/main/automations/BatchProcessingSystem.ts +207 -0
  234. package/src/main/automations/BrowserAutomationManager.ts +203 -0
  235. package/src/main/automations/GitHubActionsManager.ts +151 -0
  236. package/src/main/automations/GitLabCIManager.ts +206 -0
  237. package/src/main/automations/PriorityQueueManager.ts +328 -0
  238. package/src/main/background/BackgroundModeManager.ts +130 -0
  239. package/src/main/backup/BackupManager.ts +287 -0
  240. package/src/main/backup/MigrationManager.ts +132 -0
  241. package/src/main/commands/SlashCommandManager.ts +407 -0
  242. package/src/main/config/ClaudeMdParser.ts +539 -0
  243. package/src/main/config/CustomizationManager.ts +493 -0
  244. package/src/main/config/LaunchConfigManager.ts +212 -0
  245. package/src/main/config/SettingsManager.ts +163 -0
  246. package/src/main/connectors/ConnectorManager.ts +175 -0
  247. package/src/main/connectors/DatabaseConnector.ts +212 -0
  248. package/src/main/cowork/CoworkManager.ts +431 -0
  249. package/src/main/evals/AgentEvalFramework.ts +665 -0
  250. package/src/main/evals/GraderManager.ts +417 -0
  251. package/src/main/git/GitWorktreeManager.ts +211 -0
  252. package/src/main/github/GitHubPRMonitor.ts +317 -0
  253. package/src/main/ide/ContinueInManager.ts +180 -0
  254. package/src/main/ide/IDEIntegration.ts +288 -0
  255. package/src/main/integrations/LinearManager.ts +327 -0
  256. package/src/main/integrations/SlackBotManager.ts +312 -0
  257. package/src/main/lsp/LSPManager.ts +445 -0
  258. package/src/main/main.ts +1221 -0
  259. package/src/main/mcp/MCPConfigurationManager.ts +281 -0
  260. package/src/main/mcp/MCPManager.ts +799 -0
  261. package/src/main/mcp/MCPRegistry.ts +273 -0
  262. package/src/main/monitoring/ErrorRecoveryManager.ts +359 -0
  263. package/src/main/monitoring/ErrorTracker.ts +60 -0
  264. package/src/main/monitoring/MetricsCollector.ts +196 -0
  265. package/src/main/monitoring/TraceGradingSystem.ts +196 -0
  266. package/src/main/notifications/NotificationManager.ts +96 -0
  267. package/src/main/pair/AIPairProgramming.ts +290 -0
  268. package/src/main/plugins/PluginManager.ts +266 -0
  269. package/src/main/plugins/PluginMarketplace.ts +318 -0
  270. package/src/main/preload.ts +215 -0
  271. package/src/main/preview/PreviewSessionManager.ts +186 -0
  272. package/src/main/providers/AIProviderManager.ts +394 -0
  273. package/src/main/providers/FineTuningManager.ts +390 -0
  274. package/src/main/providers/FreeModelsProvider.ts +1156 -0
  275. package/src/main/realtime/RealtimeManager.ts +147 -0
  276. package/src/main/remote/CloudEnvironmentManager.ts +253 -0
  277. package/src/main/remote/RemoteSessionManager.ts +323 -0
  278. package/src/main/search/DeepResearchManager.ts +458 -0
  279. package/src/main/search/WebSearchIntegration.ts +203 -0
  280. package/src/main/security/AdminConsoleManager.ts +244 -0
  281. package/src/main/security/AuditLogger.ts +143 -0
  282. package/src/main/security/PermissionManager.ts +184 -0
  283. package/src/main/security/SSOManager.ts +241 -0
  284. package/src/main/security/SecurityManager.ts +139 -0
  285. package/src/main/skills/SkillsManager.ts +218 -0
  286. package/src/main/ssh/SSHManager.ts +86 -0
  287. package/src/main/streaming/StreamingManager.ts +306 -0
  288. package/src/main/sync/CloudSyncManager.ts +532 -0
  289. package/src/main/verification/AutoVerifyManager.ts +285 -0
  290. package/src/main/vision/ComputerUseManager.ts +475 -0
  291. package/src/main/vision/ImageVideoGenerationManager.ts +526 -0
  292. package/src/main/vision/VisionManager.ts +186 -0
  293. package/src/renderer/App.tsx +314 -0
  294. package/src/renderer/components/AdvancedSettingsPanel.tsx +225 -0
  295. package/src/renderer/components/AgentPanel.tsx +760 -0
  296. package/src/renderer/components/AppPreview.tsx +220 -0
  297. package/src/renderer/components/AuditTrailPanel.tsx +148 -0
  298. package/src/renderer/components/AutomationPanel.tsx +220 -0
  299. package/src/renderer/components/ChatInterface.tsx +595 -0
  300. package/src/renderer/components/ChatTab.tsx +296 -0
  301. package/src/renderer/components/CodeEditor.tsx +257 -0
  302. package/src/renderer/components/CodeReviewPanel.tsx +256 -0
  303. package/src/renderer/components/CodeWorkspace.tsx +192 -0
  304. package/src/renderer/components/CodebaseDashboard.tsx +295 -0
  305. package/src/renderer/components/ComputerUsePanel.tsx +262 -0
  306. package/src/renderer/components/ConnectorsPanel.tsx +471 -0
  307. package/src/renderer/components/ContextMenu.tsx +155 -0
  308. package/src/renderer/components/ContextUsageDisplay.tsx +248 -0
  309. package/src/renderer/components/CoworkPanel.tsx +415 -0
  310. package/src/renderer/components/DiffViewer.tsx +452 -0
  311. package/src/renderer/components/ErrorBoundary.tsx +273 -0
  312. package/src/renderer/components/ExtendedThinkingToggle.tsx +244 -0
  313. package/src/renderer/components/FileAttachments.tsx +247 -0
  314. package/src/renderer/components/FileExplorer.tsx +242 -0
  315. package/src/renderer/components/FileExplorerPanel.tsx +302 -0
  316. package/src/renderer/components/GitPanel.tsx +154 -0
  317. package/src/renderer/components/Header.tsx +113 -0
  318. package/src/renderer/components/MCPPanel.tsx +326 -0
  319. package/src/renderer/components/MentionAutocomplete.tsx +239 -0
  320. package/src/renderer/components/PermissionPanel.tsx +159 -0
  321. package/src/renderer/components/PermissionSelector.tsx +203 -0
  322. package/src/renderer/components/PluginMarketplace.tsx +325 -0
  323. package/src/renderer/components/PromptOptimizerPanel.tsx +399 -0
  324. package/src/renderer/components/SearchPanel.tsx +173 -0
  325. package/src/renderer/components/SearchReplace.tsx +284 -0
  326. package/src/renderer/components/SessionSidebar.tsx +367 -0
  327. package/src/renderer/components/SettingsPanel.tsx +426 -0
  328. package/src/renderer/components/Sidebar.tsx +100 -0
  329. package/src/renderer/components/SkillsPanel.tsx +245 -0
  330. package/src/renderer/components/SplitPane.tsx +173 -0
  331. package/src/renderer/components/Terminal.tsx +190 -0
  332. package/src/renderer/components/VoiceCommand.tsx +129 -0
  333. package/src/renderer/components/WorktreePanel.tsx +163 -0
  334. package/src/renderer/components/ui/AriaComponents.tsx +193 -0
  335. package/src/renderer/components/ui/Button.tsx +68 -0
  336. package/src/renderer/components/ui/Card.tsx +102 -0
  337. package/src/renderer/components/ui/Input.tsx +44 -0
  338. package/src/renderer/components/ui/Skeleton.tsx +55 -0
  339. package/src/renderer/components/ui/VirtualList.tsx +196 -0
  340. package/src/renderer/i18n/I18nProvider.tsx +101 -0
  341. package/src/renderer/i18n/de.ts +161 -0
  342. package/src/renderer/i18n/en.ts +163 -0
  343. package/src/renderer/i18n/es.ts +161 -0
  344. package/src/renderer/i18n/fr.ts +161 -0
  345. package/src/renderer/i18n/index.ts +44 -0
  346. package/src/renderer/index.css +129 -0
  347. package/src/renderer/lib/accessibility.tsx +287 -0
  348. package/src/renderer/lib/hooks.ts +304 -0
  349. package/src/renderer/lib/utils.ts +6 -0
  350. package/src/renderer/main.tsx +25 -0
  351. package/src/renderer/styles/minimalist.css +539 -0
  352. package/src/renderer/sw.ts +180 -0
  353. package/src/renderer/types.d.ts +138 -0
  354. package/src/shared/types.ts +813 -0
  355. package/supabase/schema.sql +234 -0
  356. package/tailwind.config.js +78 -0
  357. package/tests/e2e/package.json +15 -0
  358. package/tests/e2e/playwright.config.ts +31 -0
  359. package/tests/e2e/specs/app.spec.ts +194 -0
  360. package/tests/setup.ts +99 -0
  361. package/tests/unit/AgentOrchestrator.test.ts +274 -0
  362. package/tests/unit/DatabaseManager.test.ts +262 -0
  363. package/tests/unit/GitWorktreeManager.test.ts +150 -0
  364. package/tests/unit/SecurityManager.test.ts +110 -0
  365. package/tsconfig.main.json +22 -0
  366. package/tsconfig.renderer.json +27 -0
  367. package/vite.config.ts +28 -0
@@ -0,0 +1,799 @@
1
+ import { EventEmitter } from 'events';
2
+ import { spawn, ChildProcess } from 'child_process';
3
+ import * as http from 'http';
4
+ import * as url from 'url';
5
+ import log from 'electron-log';
6
+ import fetch from 'node-fetch';
7
+ import {
8
+ MCPServerDefinition,
9
+ MCPTool,
10
+ MCPResource,
11
+ MCPPrompt,
12
+ MCPScope,
13
+ MCPAuthToken,
14
+ MCPSearchResult
15
+ } from '../../shared/types';
16
+ import { MCPRegistry } from './MCPRegistry';
17
+ import { MCPConfigurationManager } from './MCPConfigurationManager';
18
+
19
+ interface ServerInstance {
20
+ config: MCPServerDefinition;
21
+ process: ChildProcess | null;
22
+ tools: MCPTool[];
23
+ resources: MCPResource[];
24
+ prompts: MCPPrompt[];
25
+ status: 'stopped' | 'starting' | 'running' | 'error';
26
+ lastError?: string;
27
+ authToken?: MCPAuthToken;
28
+ toolsLoaded: boolean;
29
+ toolsByCategory: Map<string, MCPTool[]>;
30
+ }
31
+
32
+ export class MCPManager extends EventEmitter {
33
+ private servers: Map<string, ServerInstance> = new Map();
34
+ private registry: MCPRegistry;
35
+ private configManager: MCPConfigurationManager;
36
+ private messageId = 0;
37
+ private pendingRequests: Map<number, { resolve: Function; reject: Function; timeout: NodeJS.Timeout }> = new Map();
38
+ private toolSearchCache: Map<string, { tools: MCPTool[]; timestamp: number }> = new Map();
39
+ private toolSearchTTL = 5 * 60 * 1000;
40
+
41
+ constructor() {
42
+ super();
43
+ this.registry = new MCPRegistry();
44
+ this.configManager = new MCPConfigurationManager();
45
+ }
46
+
47
+ async initialize(projectPath?: string): Promise<void> {
48
+ await this.registry.initialize();
49
+ await this.configManager.initialize(projectPath);
50
+
51
+ // Load configured servers
52
+ await this.loadConfiguredServers();
53
+
54
+ log.info('MCP Manager initialized with registry and config support');
55
+ }
56
+
57
+ private async loadConfiguredServers(): Promise<void> {
58
+ const servers = this.configManager.getAllServers();
59
+
60
+ for (const [id, config] of servers) {
61
+ this.servers.set(id, {
62
+ config,
63
+ process: null,
64
+ tools: [],
65
+ resources: [],
66
+ prompts: [],
67
+ status: 'stopped',
68
+ toolsLoaded: false,
69
+ toolsByCategory: new Map(),
70
+ });
71
+
72
+ // Auto-start enabled servers
73
+ if (!config.disabled) {
74
+ try {
75
+ await this.startServer(id);
76
+ } catch (error) {
77
+ log.warn(`Failed to auto-start MCP server ${id}:`, error);
78
+ }
79
+ }
80
+ }
81
+ }
82
+
83
+ async addServer(config: MCPServerDefinition): Promise<void> {
84
+ // Save to configuration
85
+ await this.configManager.addServer(config);
86
+
87
+ // Register in memory
88
+ this.servers.set(config.id, {
89
+ config,
90
+ process: null,
91
+ tools: [],
92
+ resources: [],
93
+ prompts: [],
94
+ status: 'stopped',
95
+ toolsLoaded: false,
96
+ toolsByCategory: new Map(),
97
+ });
98
+
99
+ this.emit('server:added', config);
100
+ log.info(`Registered MCP server: ${config.name} (${config.scope})`);
101
+ }
102
+
103
+ async removeServer(serverId: string): Promise<void> {
104
+ const server = this.servers.get(serverId);
105
+ if (!server) return;
106
+
107
+ // Stop if running
108
+ if (server.status === 'running') {
109
+ await this.stopServer(serverId);
110
+ }
111
+
112
+ // Remove from config
113
+ await this.configManager.removeServer(serverId, server.config.scope);
114
+
115
+ // Remove from memory
116
+ this.servers.delete(serverId);
117
+ this.emit('server:removed', serverId);
118
+ log.info(`Removed MCP server: ${serverId}`);
119
+ }
120
+
121
+ async startServer(serverId: string): Promise<void> {
122
+ const server = this.servers.get(serverId);
123
+ if (!server) throw new Error(`Server ${serverId} not found`);
124
+ if (server.config.disabled) throw new Error(`Server ${serverId} is disabled`);
125
+ if (server.status === 'running') return;
126
+
127
+ server.status = 'starting';
128
+ this.emit('server:starting', serverId);
129
+
130
+ try {
131
+ if (server.config.transport === 'stdio' && server.config.command) {
132
+ await this.startStdioServer(server);
133
+ } else if ((server.config.transport === 'http' || server.config.transport === 'streamable-http') && server.config.url) {
134
+ await this.startHttpServer(server);
135
+ } else if (server.config.transport === 'sse' && server.config.url) {
136
+ await this.startSseServer(server);
137
+ } else {
138
+ throw new Error(`Unsupported transport type: ${server.config.transport}`);
139
+ }
140
+
141
+ // Initialize connection
142
+ await this.initializeConnection(serverId);
143
+
144
+ // Fetch tools, resources, and prompts
145
+ await this.discoverCapabilities(serverId);
146
+
147
+ server.status = 'running';
148
+ this.emit('server:started', serverId);
149
+ log.info(`MCP server started: ${server.config.name}`);
150
+
151
+ } catch (error: any) {
152
+ server.status = 'error';
153
+ server.lastError = error.message;
154
+ this.emit('server:error', { serverId, error });
155
+ throw error;
156
+ }
157
+ }
158
+
159
+ private async startStdioServer(server: ServerInstance): Promise<void> {
160
+ const { command, args, env } = server.config;
161
+
162
+ server.process = spawn(command!, args || [], {
163
+ env: { ...process.env, ...env },
164
+ stdio: ['pipe', 'pipe', 'pipe'],
165
+ });
166
+
167
+ // Handle stdout
168
+ server.process.stdout?.on('data', (data) => {
169
+ this.handleServerOutput(server.config.id, data);
170
+ });
171
+
172
+ // Handle stderr
173
+ server.process.stderr?.on('data', (data) => {
174
+ log.error(`MCP server ${server.config.id} stderr:`, data.toString());
175
+ });
176
+
177
+ // Handle exit
178
+ server.process.on('exit', (code) => {
179
+ server.status = code === 0 ? 'stopped' : 'error';
180
+ this.emit('server:stopped', { serverId: server.config.id, code });
181
+ });
182
+ }
183
+
184
+ private async startHttpServer(server: ServerInstance): Promise<void> {
185
+ // For HTTP servers, we just verify connectivity
186
+ const response = await fetch(`${server.config.url}/health`, {
187
+ method: 'GET',
188
+ headers: server.config.headers,
189
+ }).catch(() => null);
190
+
191
+ if (!response || !response.ok) {
192
+ log.warn(`HTTP MCP server ${server.config.id} health check failed, will retry on use`);
193
+ }
194
+ }
195
+
196
+ private async startSseServer(server: ServerInstance): Promise<void> {
197
+ // SSE servers establish connection on first use
198
+ log.info(`SSE MCP server ${server.config.id} registered, connection on first use`);
199
+ }
200
+
201
+ private async initializeConnection(serverId: string): Promise<void> {
202
+ const response = await this.sendMessage(serverId, {
203
+ jsonrpc: '2.0',
204
+ id: this.getNextMessageId(),
205
+ method: 'initialize',
206
+ params: {
207
+ protocolVersion: '2024-11-05',
208
+ capabilities: {
209
+ tools: {},
210
+ resources: {},
211
+ prompts: {},
212
+ logging: {},
213
+ },
214
+ clientInfo: {
215
+ name: 'codex-linux',
216
+ version: '1.0.0',
217
+ },
218
+ },
219
+ });
220
+
221
+ if (response.error) {
222
+ throw new Error(`Initialize failed: ${response.error.message}`);
223
+ }
224
+
225
+ // Send initialized notification
226
+ await this.sendNotification(serverId, 'initialized', {});
227
+ }
228
+
229
+ private async discoverCapabilities(serverId: string): Promise<void> {
230
+ const server = this.servers.get(serverId);
231
+ if (!server) return;
232
+
233
+ // Discover tools
234
+ try {
235
+ const toolsResponse = await this.sendMessage(serverId, {
236
+ jsonrpc: '2.0',
237
+ id: this.getNextMessageId(),
238
+ method: 'tools/list',
239
+ params: {},
240
+ });
241
+
242
+ if (toolsResponse.result?.tools) {
243
+ server.tools = toolsResponse.result.tools.map((t: any) => ({
244
+ ...t,
245
+ serverId,
246
+ }));
247
+
248
+ // Build category index for lazy loading
249
+ this.buildToolsCategoryIndex(server);
250
+ server.toolsLoaded = true;
251
+ }
252
+ } catch (error) {
253
+ log.warn(`Failed to discover tools for ${serverId}:`, error);
254
+ }
255
+
256
+ // Discover resources
257
+ try {
258
+ const resourcesResponse = await this.sendMessage(serverId, {
259
+ jsonrpc: '2.0',
260
+ id: this.getNextMessageId(),
261
+ method: 'resources/list',
262
+ params: {},
263
+ });
264
+
265
+ if (resourcesResponse.result?.resources) {
266
+ server.resources = resourcesResponse.result.resources.map((r: any) => ({
267
+ ...r,
268
+ serverId,
269
+ }));
270
+ }
271
+ } catch (error) {
272
+ log.warn(`Failed to discover resources for ${serverId}:`, error);
273
+ }
274
+
275
+ // Discover prompts
276
+ try {
277
+ const promptsResponse = await this.sendMessage(serverId, {
278
+ jsonrpc: '2.0',
279
+ id: this.getNextMessageId(),
280
+ method: 'prompts/list',
281
+ params: {},
282
+ });
283
+
284
+ if (promptsResponse.result?.prompts) {
285
+ server.prompts = promptsResponse.result.prompts.map((p: any) => ({
286
+ ...p,
287
+ serverId,
288
+ }));
289
+ }
290
+ } catch (error) {
291
+ log.warn(`Failed to discover prompts for ${serverId}:`, error);
292
+ }
293
+
294
+ this.emit('server:capabilities', {
295
+ serverId,
296
+ tools: server.tools,
297
+ resources: server.resources,
298
+ prompts: server.prompts,
299
+ });
300
+ }
301
+
302
+ async stopServer(serverId: string): Promise<void> {
303
+ const server = this.servers.get(serverId);
304
+ if (!server) return;
305
+
306
+ if (server.process) {
307
+ server.process.kill();
308
+ server.process = null;
309
+ }
310
+
311
+ server.status = 'stopped';
312
+ server.tools = [];
313
+ server.resources = [];
314
+ server.prompts = [];
315
+
316
+ this.emit('server:stopped', serverId);
317
+ log.info(`MCP server stopped: ${server.config.name}`);
318
+ }
319
+
320
+ private async sendMessage(serverId: string, message: any): Promise<any> {
321
+ const server = this.servers.get(serverId);
322
+ if (!server) throw new Error(`Server ${serverId} not found`);
323
+
324
+ if (server.config.transport === 'stdio') {
325
+ return this.sendStdioMessage(server, message);
326
+ } else {
327
+ return this.sendHttpMessage(server, message);
328
+ }
329
+ }
330
+
331
+ private async sendStdioMessage(server: ServerInstance, message: any): Promise<any> {
332
+ if (!server.process?.stdin) {
333
+ throw new Error(`Server ${server.config.id} not running`);
334
+ }
335
+
336
+ return new Promise((resolve, reject) => {
337
+ const timeout = setTimeout(() => {
338
+ this.pendingRequests.delete(message.id);
339
+ reject(new Error('MCP request timeout'));
340
+ }, 30000);
341
+
342
+ this.pendingRequests.set(message.id, { resolve, reject, timeout });
343
+ server.process!.stdin!.write(JSON.stringify(message) + '\n');
344
+ });
345
+ }
346
+
347
+ private async sendHttpMessage(server: ServerInstance, message: any): Promise<any> {
348
+ const response = await fetch(`${server.config.url}/mcp`, {
349
+ method: 'POST',
350
+ headers: {
351
+ 'Content-Type': 'application/json',
352
+ ...server.config.headers,
353
+ },
354
+ body: JSON.stringify(message),
355
+ });
356
+
357
+ if (!response.ok) {
358
+ throw new Error(`HTTP error: ${response.status}`);
359
+ }
360
+
361
+ return response.json();
362
+ }
363
+
364
+ private async sendNotification(serverId: string, method: string, params: any): Promise<void> {
365
+ await this.sendMessage(serverId, {
366
+ jsonrpc: '2.0',
367
+ method,
368
+ params,
369
+ });
370
+ }
371
+
372
+ private handleServerOutput(serverId: string, data: Buffer): void {
373
+ const messages = data.toString().trim().split('\n');
374
+
375
+ for (const messageStr of messages) {
376
+ if (!messageStr) continue;
377
+
378
+ try {
379
+ const message = JSON.parse(messageStr);
380
+
381
+ // Handle responses
382
+ if (message.id !== undefined && this.pendingRequests.has(message.id)) {
383
+ const pending = this.pendingRequests.get(message.id)!;
384
+ clearTimeout(pending.timeout);
385
+ this.pendingRequests.delete(message.id);
386
+
387
+ if (message.error) {
388
+ pending.reject(new Error(message.error.message));
389
+ } else {
390
+ pending.resolve(message);
391
+ }
392
+ }
393
+
394
+ // Handle notifications
395
+ if (message.method) {
396
+ this.handleNotification(serverId, message);
397
+ }
398
+ } catch (error) {
399
+ log.debug(`MCP server ${serverId} output:`, messageStr);
400
+ }
401
+ }
402
+ }
403
+
404
+ private handleNotification(serverId: string, message: any): void {
405
+ const server = this.servers.get(serverId);
406
+ if (!server) return;
407
+
408
+ switch (message.method) {
409
+ case 'notifications/tools/list_changed':
410
+ this.discoverCapabilities(serverId);
411
+ break;
412
+ case 'notifications/resources/list_changed':
413
+ this.discoverCapabilities(serverId);
414
+ break;
415
+ case 'notifications/prompts/list_changed':
416
+ this.discoverCapabilities(serverId);
417
+ break;
418
+ case 'notifications/message':
419
+ log.info(`MCP server ${serverId}:`, message.params);
420
+ break;
421
+ }
422
+ }
423
+
424
+ async callTool(serverId: string, toolName: string, args: any): Promise<any> {
425
+ const response = await this.sendMessage(serverId, {
426
+ jsonrpc: '2.0',
427
+ id: this.getNextMessageId(),
428
+ method: 'tools/call',
429
+ params: {
430
+ name: toolName,
431
+ arguments: args,
432
+ },
433
+ });
434
+
435
+ if (response.error) {
436
+ throw new Error(response.error.message);
437
+ }
438
+
439
+ return response.result;
440
+ }
441
+
442
+ async readResource(serverId: string, uri: string): Promise<any> {
443
+ const response = await this.sendMessage(serverId, {
444
+ jsonrpc: '2.0',
445
+ id: this.getNextMessageId(),
446
+ method: 'resources/read',
447
+ params: { uri },
448
+ });
449
+
450
+ if (response.error) {
451
+ throw new Error(response.error.message);
452
+ }
453
+
454
+ return response.result;
455
+ }
456
+
457
+ async getPrompt(serverId: string, promptName: string, args?: Record<string, string>): Promise<any> {
458
+ const response = await this.sendMessage(serverId, {
459
+ jsonrpc: '2.0',
460
+ id: this.getNextMessageId(),
461
+ method: 'prompts/get',
462
+ params: {
463
+ name: promptName,
464
+ arguments: args,
465
+ },
466
+ });
467
+
468
+ if (response.error) {
469
+ throw new Error(response.error.message);
470
+ }
471
+
472
+ return response.result;
473
+ }
474
+
475
+ // Tool Search Optimization
476
+ async searchTools(query: string): Promise<MCPSearchResult> {
477
+ const result: MCPSearchResult = {
478
+ query,
479
+ tools: [],
480
+ resources: [],
481
+ prompts: [],
482
+ };
483
+
484
+ const lowerQuery = query.toLowerCase();
485
+
486
+ for (const server of this.servers.values()) {
487
+ if (server.status !== 'running') continue;
488
+
489
+ // Search tools
490
+ for (const tool of server.tools) {
491
+ if (
492
+ tool.name.toLowerCase().includes(lowerQuery) ||
493
+ tool.description?.toLowerCase().includes(lowerQuery)
494
+ ) {
495
+ result.tools.push(tool);
496
+ }
497
+ }
498
+
499
+ // Search resources
500
+ for (const resource of server.resources) {
501
+ if (
502
+ resource.name.toLowerCase().includes(lowerQuery) ||
503
+ resource.uri.toLowerCase().includes(lowerQuery)
504
+ ) {
505
+ result.resources.push(resource);
506
+ }
507
+ }
508
+
509
+ // Search prompts
510
+ for (const prompt of server.prompts) {
511
+ if (
512
+ prompt.name.toLowerCase().includes(lowerQuery) ||
513
+ prompt.description?.toLowerCase().includes(lowerQuery)
514
+ ) {
515
+ result.prompts.push(prompt);
516
+ }
517
+ }
518
+ }
519
+
520
+ return result;
521
+ }
522
+
523
+ // OAuth Authentication
524
+ async authenticateServer(serverId: string): Promise<boolean> {
525
+ const server = this.servers.get(serverId);
526
+ if (!server?.config.oauth) {
527
+ return false;
528
+ }
529
+
530
+ const { clientId, callbackPort = 8080 } = server.config.oauth;
531
+
532
+ // Start local HTTP server for OAuth callback
533
+ const redirectUri = `http://localhost:${callbackPort}/callback`;
534
+
535
+ return new Promise((resolve, reject) => {
536
+ const httpServer = http.createServer(async (req, res) => {
537
+ const parsedUrl = url.parse(req.url || '', true);
538
+
539
+ if (parsedUrl.pathname === '/callback') {
540
+ const code = parsedUrl.query.code as string;
541
+
542
+ if (code) {
543
+ try {
544
+ // Exchange code for token (implementation depends on OAuth provider)
545
+ // This is a simplified version
546
+ const token: MCPAuthToken = {
547
+ serverId,
548
+ accessToken: code, // In real implementation, exchange code
549
+ expiresAt: new Date(Date.now() + 3600 * 1000), // 1 hour
550
+ };
551
+
552
+ server.authToken = token;
553
+ res.writeHead(200, { 'Content-Type': 'text/html' });
554
+ res.end('<h1>Authentication successful!</h1><p>You can close this window.</p>');
555
+ httpServer.close();
556
+ resolve(true);
557
+ } catch (error) {
558
+ res.writeHead(500, { 'Content-Type': 'text/html' });
559
+ res.end('<h1>Authentication failed</h1>');
560
+ httpServer.close();
561
+ reject(error);
562
+ }
563
+ } else {
564
+ res.writeHead(400, { 'Content-Type': 'text/html' });
565
+ res.end('<h1>Authentication failed</h1><p>No authorization code received.</p>');
566
+ httpServer.close();
567
+ resolve(false);
568
+ }
569
+ }
570
+ });
571
+
572
+ httpServer.listen(callbackPort, () => {
573
+ log.info(`OAuth callback server started on port ${callbackPort}`);
574
+
575
+ // Open browser for OAuth (would need electron shell.openExternal)
576
+ const authUrl = `${server.config.url}/auth?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code`;
577
+ log.info(`Please visit: ${authUrl}`);
578
+ });
579
+
580
+ // Timeout after 5 minutes
581
+ setTimeout(() => {
582
+ httpServer.close();
583
+ reject(new Error('OAuth timeout'));
584
+ }, 5 * 60 * 1000);
585
+ });
586
+ }
587
+
588
+ getAllTools(): MCPTool[] {
589
+ const tools: MCPTool[] = [];
590
+ for (const server of this.servers.values()) {
591
+ if (server.status === 'running') {
592
+ tools.push(...server.tools);
593
+ }
594
+ }
595
+ return tools;
596
+ }
597
+
598
+ getAllResources(): MCPResource[] {
599
+ const resources: MCPResource[] = [];
600
+ for (const server of this.servers.values()) {
601
+ if (server.status === 'running') {
602
+ resources.push(...server.resources);
603
+ }
604
+ }
605
+ return resources;
606
+ }
607
+
608
+ getAllPrompts(): MCPPrompt[] {
609
+ const prompts: MCPPrompt[] = [];
610
+ for (const server of this.servers.values()) {
611
+ if (server.status === 'running') {
612
+ prompts.push(...server.prompts);
613
+ }
614
+ }
615
+ return prompts;
616
+ }
617
+
618
+ getServerStatus(serverId: string): string {
619
+ return this.servers.get(serverId)?.status || 'stopped';
620
+ }
621
+
622
+ getServers(): Array<{
623
+ id: string;
624
+ name: string;
625
+ status: string;
626
+ disabled?: boolean;
627
+ scope: MCPScope;
628
+ transport: string;
629
+ tools: number;
630
+ resources: number;
631
+ }> {
632
+ return Array.from(this.servers.values()).map(s => ({
633
+ id: s.config.id,
634
+ name: s.config.name,
635
+ status: s.status,
636
+ disabled: s.config.disabled,
637
+ scope: s.config.scope,
638
+ transport: s.config.transport,
639
+ tools: s.tools.length,
640
+ resources: s.resources.length,
641
+ }));
642
+ }
643
+
644
+ getRegistry(): MCPRegistry {
645
+ return this.registry;
646
+ }
647
+
648
+ getConfigManager(): MCPConfigurationManager {
649
+ return this.configManager;
650
+ }
651
+
652
+ // Lazy Loading - Build category index for tools
653
+ private buildToolsCategoryIndex(server: ServerInstance): void {
654
+ server.toolsByCategory.clear();
655
+
656
+ for (const tool of server.tools) {
657
+ const category = this.categorizeTool(tool);
658
+ const existing = server.toolsByCategory.get(category) || [];
659
+ existing.push(tool);
660
+ server.toolsByCategory.set(category, existing);
661
+ }
662
+ }
663
+
664
+ private categorizeTool(tool: MCPTool): string {
665
+ const name = tool.name.toLowerCase();
666
+ const inputSchema = JSON.stringify(tool.inputSchema).toLowerCase();
667
+
668
+ if (name.includes('file') || name.includes('read') || name.includes('write') || inputSchema.includes('path')) {
669
+ return 'filesystem';
670
+ }
671
+ if (name.includes('git') || name.includes('branch') || name.includes('commit')) {
672
+ return 'git';
673
+ }
674
+ if (name.includes('search') || name.includes('find') || name.includes('query')) {
675
+ return 'search';
676
+ }
677
+ if (name.includes('db') || name.includes('database') || name.includes('sql')) {
678
+ return 'database';
679
+ }
680
+ if (name.includes('api') || name.includes('http') || name.includes('fetch')) {
681
+ return 'api';
682
+ }
683
+ if (name.includes('run') || name.includes('execute') || name.includes('command')) {
684
+ return 'execution';
685
+ }
686
+ return 'other';
687
+ }
688
+
689
+ // Get tools by category (lazy loaded)
690
+ async getToolsByCategory(serverId: string, category: string): Promise<MCPTool[]> {
691
+ const server = this.servers.get(serverId);
692
+ if (!server) return [];
693
+
694
+ if (!server.toolsLoaded) {
695
+ await this.discoverCapabilities(serverId);
696
+ }
697
+
698
+ return server.toolsByCategory.get(category) || [];
699
+ }
700
+
701
+ // Smart tool retrieval - only loads tools when needed
702
+ async getRelevantTools(serverId: string, context: string): Promise<MCPTool[]> {
703
+ const server = this.servers.get(serverId);
704
+ if (!server) return [];
705
+
706
+ if (!server.toolsLoaded) {
707
+ await this.discoverCapabilities(serverId);
708
+ }
709
+
710
+ const contextLower = context.toLowerCase();
711
+ const relevantTools: MCPTool[] = [];
712
+
713
+ for (const tool of server.tools) {
714
+ const name = tool.name.toLowerCase();
715
+ const desc = (tool.description || '').toLowerCase();
716
+
717
+ // Score tool relevance
718
+ let score = 0;
719
+ if (name.includes(contextLower) || desc.includes(contextLower)) {
720
+ score = 3;
721
+ } else if (this.categorizeTool(tool) === this.inferCategoryFromContext(contextLower)) {
722
+ score = 2;
723
+ }
724
+
725
+ if (score > 0) {
726
+ relevantTools.push(tool);
727
+ }
728
+ }
729
+
730
+ // If no specific tools found, return all (for broader context)
731
+ return relevantTools.length > 0 ? relevantTools : server.tools.slice(0, 10);
732
+ }
733
+
734
+ private inferCategoryFromContext(context: string): string {
735
+ if (context.includes('file') || context.includes('folder') || context.includes('directory')) {
736
+ return 'filesystem';
737
+ }
738
+ if (context.includes('git') || context.includes('commit') || context.includes('branch')) {
739
+ return 'git';
740
+ }
741
+ if (context.includes('search') || context.includes('find')) {
742
+ return 'search';
743
+ }
744
+ if (context.includes('database') || context.includes('query') || context.includes('sql')) {
745
+ return 'database';
746
+ }
747
+ return 'other';
748
+ }
749
+
750
+ // Cached search with TTL
751
+ async searchToolsCached(query: string): Promise<MCPSearchResult> {
752
+ const cached = this.toolSearchCache.get(query);
753
+ if (cached && Date.now() - cached.timestamp < this.toolSearchTTL) {
754
+ return {
755
+ query,
756
+ tools: cached.tools,
757
+ resources: [],
758
+ prompts: [],
759
+ };
760
+ }
761
+
762
+ const result = await this.searchTools(query);
763
+ this.toolSearchCache.set(query, {
764
+ tools: result.tools,
765
+ timestamp: Date.now(),
766
+ });
767
+
768
+ return result;
769
+ }
770
+
771
+ // Clear tool cache
772
+ clearToolCache(): void {
773
+ this.toolSearchCache.clear();
774
+ }
775
+
776
+ // Get tools count for UI
777
+ getToolsCount(): number {
778
+ let count = 0;
779
+ for (const server of this.servers.values()) {
780
+ if (server.status === 'running') {
781
+ count += server.tools.length;
782
+ }
783
+ }
784
+ return count;
785
+ }
786
+
787
+ private getNextMessageId(): number {
788
+ return ++this.messageId;
789
+ }
790
+
791
+ async cleanup(): Promise<void> {
792
+ for (const [serverId] of this.servers) {
793
+ await this.stopServer(serverId);
794
+ }
795
+ this.pendingRequests.clear();
796
+ }
797
+ }
798
+
799
+ export const mcpManager = new MCPManager();