@within-7/minto 0.1.4 → 0.1.6

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 (264) hide show
  1. package/dist/commands/agents/AgentsCommand.js +2342 -0
  2. package/dist/commands/agents/AgentsCommand.js.map +7 -0
  3. package/dist/commands/agents/constants.js +58 -0
  4. package/dist/commands/agents/constants.js.map +7 -0
  5. package/dist/commands/agents/index.js +37 -0
  6. package/dist/commands/agents/index.js.map +7 -0
  7. package/dist/commands/agents/types.js +10 -0
  8. package/dist/commands/agents/types.js.map +7 -0
  9. package/dist/commands/agents/utils/fileOperations.js +185 -0
  10. package/dist/commands/agents/utils/fileOperations.js.map +7 -0
  11. package/dist/commands/agents/utils/index.js +21 -0
  12. package/dist/commands/agents/utils/index.js.map +7 -0
  13. package/dist/commands/bug.js +2 -2
  14. package/dist/commands/bug.js.map +2 -2
  15. package/dist/commands/compact.js +5 -5
  16. package/dist/commands/compact.js.map +2 -2
  17. package/dist/commands/ctx_viz.js +55 -22
  18. package/dist/commands/ctx_viz.js.map +2 -2
  19. package/dist/commands/mcp-interactive.js +11 -11
  20. package/dist/commands/mcp-interactive.js.map +2 -2
  21. package/dist/commands/model.js +94 -32
  22. package/dist/commands/model.js.map +3 -3
  23. package/dist/commands/plugin/AddMarketplaceForm.js +49 -21
  24. package/dist/commands/plugin/AddMarketplaceForm.js.map +2 -2
  25. package/dist/commands/plugin/ConfirmDialog.js +38 -26
  26. package/dist/commands/plugin/ConfirmDialog.js.map +2 -2
  27. package/dist/commands/plugin/InstalledPluginsByMarketplace.js +24 -8
  28. package/dist/commands/plugin/InstalledPluginsByMarketplace.js.map +2 -2
  29. package/dist/commands/plugin/InstalledPluginsManager.js +3 -1
  30. package/dist/commands/plugin/InstalledPluginsManager.js.map +2 -2
  31. package/dist/commands/plugin/MainMenu.js +16 -7
  32. package/dist/commands/plugin/MainMenu.js.map +2 -2
  33. package/dist/commands/plugin/MarketplaceManager.js +84 -39
  34. package/dist/commands/plugin/MarketplaceManager.js.map +2 -2
  35. package/dist/commands/plugin/MarketplaceSelector.js +7 -3
  36. package/dist/commands/plugin/MarketplaceSelector.js.map +2 -2
  37. package/dist/commands/plugin/PlaceholderScreen.js +16 -2
  38. package/dist/commands/plugin/PlaceholderScreen.js.map +2 -2
  39. package/dist/commands/plugin/PluginBrowser.js +4 -2
  40. package/dist/commands/plugin/PluginBrowser.js.map +2 -2
  41. package/dist/commands/plugin/PluginDetailsInstall.js +12 -6
  42. package/dist/commands/plugin/PluginDetailsInstall.js.map +2 -2
  43. package/dist/commands/plugin/PluginDetailsManage.js +14 -5
  44. package/dist/commands/plugin/PluginDetailsManage.js.map +2 -2
  45. package/dist/commands/plugin/example-usage.js.map +2 -2
  46. package/dist/commands/plugin/utils.js.map +2 -2
  47. package/dist/commands/plugin.js +226 -46
  48. package/dist/commands/plugin.js.map +2 -2
  49. package/dist/commands/refreshCommands.js +6 -3
  50. package/dist/commands/refreshCommands.js.map +2 -2
  51. package/dist/commands/resume.js +2 -1
  52. package/dist/commands/resume.js.map +2 -2
  53. package/dist/commands/setup.js +19 -5
  54. package/dist/commands/setup.js.map +2 -2
  55. package/dist/commands/terminalSetup.js +2 -2
  56. package/dist/commands/terminalSetup.js.map +1 -1
  57. package/dist/commands.js +14 -30
  58. package/dist/commands.js.map +2 -2
  59. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
  60. package/dist/components/AskUserQuestionDialog/QuestionView.js +10 -1
  61. package/dist/components/AskUserQuestionDialog/QuestionView.js.map +2 -2
  62. package/dist/components/BackgroundTasksPanel.js +5 -1
  63. package/dist/components/BackgroundTasksPanel.js.map +2 -2
  64. package/dist/components/Config.js +17 -4
  65. package/dist/components/Config.js.map +2 -2
  66. package/dist/components/ConsoleOAuthFlow.js.map +2 -2
  67. package/dist/components/CustomSelect/select-option.js +4 -1
  68. package/dist/components/CustomSelect/select-option.js.map +2 -2
  69. package/dist/components/Help.js +6 -8
  70. package/dist/components/Help.js.map +2 -2
  71. package/dist/components/Logo.js +1 -1
  72. package/dist/components/Logo.js.map +2 -2
  73. package/dist/components/ModelListManager.js.map +2 -2
  74. package/dist/components/ModelSelector/ModelSelector.js +2030 -0
  75. package/dist/components/ModelSelector/ModelSelector.js.map +7 -0
  76. package/dist/components/ModelSelector/ScreenContainer.js +27 -0
  77. package/dist/components/ModelSelector/ScreenContainer.js.map +7 -0
  78. package/dist/components/ModelSelector/constants.js +37 -0
  79. package/dist/components/ModelSelector/constants.js.map +7 -0
  80. package/dist/components/ModelSelector/hooks/index.js +5 -0
  81. package/dist/components/ModelSelector/hooks/index.js.map +7 -0
  82. package/dist/components/ModelSelector/hooks/useEscapeNavigation.js +21 -0
  83. package/dist/components/ModelSelector/hooks/useEscapeNavigation.js.map +7 -0
  84. package/dist/components/ModelSelector/index.js +17 -0
  85. package/dist/components/ModelSelector/index.js.map +7 -0
  86. package/dist/components/ModelSelector/types.js +1 -0
  87. package/dist/components/ModelSelector/types.js.map +7 -0
  88. package/dist/components/PressEnterToContinue.js +1 -1
  89. package/dist/components/PressEnterToContinue.js.map +2 -2
  90. package/dist/components/ProjectOnboarding.js +1 -1
  91. package/dist/components/ProjectOnboarding.js.map +2 -2
  92. package/dist/components/PromptInput.js +88 -37
  93. package/dist/components/PromptInput.js.map +2 -2
  94. package/dist/components/QuitSummary.js +17 -10
  95. package/dist/components/QuitSummary.js.map +2 -2
  96. package/dist/components/SentryErrorBoundary.js.map +2 -2
  97. package/dist/components/StreamingBashOutput.js.map +2 -2
  98. package/dist/components/StructuredDiff.js.map +2 -2
  99. package/dist/components/SubagentProgress.js.map +2 -2
  100. package/dist/components/TaskCard.js.map +2 -2
  101. package/dist/components/TextInput.js.map +1 -1
  102. package/dist/components/TodoItem.js.map +1 -1
  103. package/dist/components/binary-feedback/BinaryFeedbackOption.js +1 -3
  104. package/dist/components/binary-feedback/BinaryFeedbackOption.js.map +2 -2
  105. package/dist/components/messages/AssistantLocalCommandOutputMessage.js.map +1 -1
  106. package/dist/components/messages/AssistantToolUseMessage.js +3 -1
  107. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  108. package/dist/components/messages/TaskProgressMessage.js.map +2 -2
  109. package/dist/components/messages/TaskToolMessage.js.map +2 -2
  110. package/dist/components/messages/UserToolResultMessage/utils.js.map +2 -2
  111. package/dist/components/permissions/FileEditPermissionRequest/FileEditToolDiff.js.map +2 -2
  112. package/dist/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.js.map +2 -2
  113. package/dist/components/permissions/hooks.js.map +2 -2
  114. package/dist/constants/modelCapabilities.js +1 -1
  115. package/dist/constants/modelCapabilities.js.map +2 -2
  116. package/dist/constants/prompts.js.map +1 -1
  117. package/dist/constants/timing.js +34 -0
  118. package/dist/constants/timing.js.map +7 -0
  119. package/dist/entrypoints/cli.js +128 -33
  120. package/dist/entrypoints/cli.js.map +3 -3
  121. package/dist/entrypoints/mcp.js +13 -18
  122. package/dist/entrypoints/mcp.js.map +2 -2
  123. package/dist/hooks/useCanUseTool.js.map +2 -2
  124. package/dist/hooks/useCancelRequest.js.map +1 -1
  125. package/dist/hooks/useHistorySearch.js.map +2 -2
  126. package/dist/hooks/useLogStartupTime.js.map +2 -2
  127. package/dist/hooks/usePermissionRequestLogging.js.map +2 -2
  128. package/dist/hooks/useTextInput.js.map +1 -1
  129. package/dist/hooks/useUnifiedCompletion.js +493 -394
  130. package/dist/hooks/useUnifiedCompletion.js.map +2 -2
  131. package/dist/index.js.map +2 -2
  132. package/dist/permissions.js +4 -7
  133. package/dist/permissions.js.map +2 -2
  134. package/dist/query.js +6 -1
  135. package/dist/query.js.map +2 -2
  136. package/dist/screens/REPL.js +72 -36
  137. package/dist/screens/REPL.js.map +2 -2
  138. package/dist/screens/ResumeConversation.js +2 -1
  139. package/dist/screens/ResumeConversation.js.map +2 -2
  140. package/dist/services/adapters/base.js.map +2 -2
  141. package/dist/services/adapters/chatCompletions.js.map +2 -2
  142. package/dist/services/adapters/responsesAPI.js +3 -1
  143. package/dist/services/adapters/responsesAPI.js.map +2 -2
  144. package/dist/services/claude.js +327 -328
  145. package/dist/services/claude.js.map +2 -2
  146. package/dist/services/customCommands.js +6 -1
  147. package/dist/services/customCommands.js.map +2 -2
  148. package/dist/services/fileFreshness.js.map +2 -2
  149. package/dist/services/gpt5ConnectionTest.js +20 -7
  150. package/dist/services/gpt5ConnectionTest.js.map +2 -2
  151. package/dist/services/hookExecutor.js +6 -12
  152. package/dist/services/hookExecutor.js.map +2 -2
  153. package/dist/services/mcpClient.js +29 -2
  154. package/dist/services/mcpClient.js.map +2 -2
  155. package/dist/services/mentionProcessor.js +23 -10
  156. package/dist/services/mentionProcessor.js.map +2 -2
  157. package/dist/services/modelAdapterFactory.js.map +2 -2
  158. package/dist/services/oauth.js.map +2 -2
  159. package/dist/services/openai.js +109 -72
  160. package/dist/services/openai.js.map +3 -3
  161. package/dist/services/responseStateManager.js.map +2 -2
  162. package/dist/services/systemReminder.js.map +2 -2
  163. package/dist/tools/ArchitectTool/ArchitectTool.js.map +1 -1
  164. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +14 -8
  165. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  166. package/dist/tools/BashOutputTool/BashOutputTool.js.map +2 -2
  167. package/dist/tools/BashTool/BashTool.js.map +2 -2
  168. package/dist/tools/FileReadTool/FileReadTool.js.map +1 -1
  169. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  170. package/dist/tools/GrepTool/GrepTool.js +1 -4
  171. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  172. package/dist/tools/MultiEditTool/MultiEditTool.js +4 -1
  173. package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
  174. package/dist/tools/NotebookReadTool/NotebookReadTool.js +3 -1
  175. package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +2 -2
  176. package/dist/tools/SkillTool/SkillTool.js +12 -6
  177. package/dist/tools/SkillTool/SkillTool.js.map +2 -2
  178. package/dist/tools/TaskTool/TaskTool.js +14 -5
  179. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  180. package/dist/tools/TaskTool/prompt.js.map +2 -2
  181. package/dist/tools/ThinkTool/ThinkTool.js +6 -1
  182. package/dist/tools/ThinkTool/ThinkTool.js.map +2 -2
  183. package/dist/tools/TodoWriteTool/TodoWriteTool.js +23 -3
  184. package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +2 -2
  185. package/dist/tools/URLFetcherTool/URLFetcherTool.js +2 -2
  186. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
  187. package/dist/tools/URLFetcherTool/cache.js +6 -3
  188. package/dist/tools/URLFetcherTool/cache.js.map +2 -2
  189. package/dist/tools/URLFetcherTool/htmlToMarkdown.js +3 -1
  190. package/dist/tools/URLFetcherTool/htmlToMarkdown.js.map +2 -2
  191. package/dist/tools/WebSearchTool/WebSearchTool.js.map +2 -2
  192. package/dist/tools/WebSearchTool/prompt.js.map +2 -2
  193. package/dist/tools/WebSearchTool/searchProviders.js +15 -6
  194. package/dist/tools/WebSearchTool/searchProviders.js.map +2 -2
  195. package/dist/tools.js +4 -1
  196. package/dist/tools.js.map +2 -2
  197. package/dist/types/core.js +1 -0
  198. package/dist/types/core.js.map +7 -0
  199. package/dist/types/hooks.js +1 -4
  200. package/dist/types/hooks.js.map +2 -2
  201. package/dist/types/marketplace.js +8 -2
  202. package/dist/types/marketplace.js.map +2 -2
  203. package/dist/types/plugin.js +9 -6
  204. package/dist/types/plugin.js.map +2 -2
  205. package/dist/utils/BackgroundShellManager.js +76 -10
  206. package/dist/utils/BackgroundShellManager.js.map +2 -2
  207. package/dist/utils/PersistentShell.js +7 -2
  208. package/dist/utils/PersistentShell.js.map +2 -2
  209. package/dist/utils/advancedFuzzyMatcher.js +4 -1
  210. package/dist/utils/advancedFuzzyMatcher.js.map +2 -2
  211. package/dist/utils/agentLoader.js +69 -35
  212. package/dist/utils/agentLoader.js.map +2 -2
  213. package/dist/utils/agentStorage.js.map +2 -2
  214. package/dist/utils/async.js +163 -0
  215. package/dist/utils/async.js.map +7 -0
  216. package/dist/utils/autoUpdater.js +8 -2
  217. package/dist/utils/autoUpdater.js.map +2 -2
  218. package/dist/utils/commands.js +23 -11
  219. package/dist/utils/commands.js.map +2 -2
  220. package/dist/utils/commonUnixCommands.js +3 -1
  221. package/dist/utils/commonUnixCommands.js.map +2 -2
  222. package/dist/utils/compressionMode.js.map +2 -2
  223. package/dist/utils/config.js +30 -14
  224. package/dist/utils/config.js.map +2 -2
  225. package/dist/utils/debugLogger.js.map +2 -2
  226. package/dist/utils/env.js.map +2 -2
  227. package/dist/utils/envConfig.js +82 -0
  228. package/dist/utils/envConfig.js.map +7 -0
  229. package/dist/utils/errorHandling.js +89 -0
  230. package/dist/utils/errorHandling.js.map +7 -0
  231. package/dist/utils/expertChatStorage.js.map +2 -2
  232. package/dist/utils/fuzzyMatcher.js +13 -7
  233. package/dist/utils/fuzzyMatcher.js.map +2 -2
  234. package/dist/utils/hookManager.js +14 -4
  235. package/dist/utils/hookManager.js.map +2 -2
  236. package/dist/utils/log.js.map +2 -2
  237. package/dist/utils/marketplaceManager.js +44 -9
  238. package/dist/utils/marketplaceManager.js.map +2 -2
  239. package/dist/utils/messageContextManager.js.map +1 -1
  240. package/dist/utils/messages.js +6 -3
  241. package/dist/utils/messages.js.map +2 -2
  242. package/dist/utils/model.js +3 -1
  243. package/dist/utils/model.js.map +2 -2
  244. package/dist/utils/pluginInstaller.js +3 -15
  245. package/dist/utils/pluginInstaller.js.map +2 -2
  246. package/dist/utils/pluginLoader.js +41 -13
  247. package/dist/utils/pluginLoader.js.map +2 -2
  248. package/dist/utils/pluginRegistry.js.map +2 -2
  249. package/dist/utils/pluginValidator.js +71 -49
  250. package/dist/utils/pluginValidator.js.map +2 -2
  251. package/dist/utils/ptyCompat.js.map +2 -2
  252. package/dist/utils/roundConverter.js.map +2 -2
  253. package/dist/utils/secureFile.js +43 -14
  254. package/dist/utils/secureFile.js.map +2 -2
  255. package/dist/utils/sessionState.js.map +2 -2
  256. package/dist/utils/skillLoader.js.map +2 -2
  257. package/dist/utils/teamConfig.js +7 -4
  258. package/dist/utils/teamConfig.js.map +2 -2
  259. package/dist/utils/theme.js.map +2 -2
  260. package/dist/utils/thinking.js.map +2 -2
  261. package/dist/utils/unaryLogging.js.map +2 -2
  262. package/dist/version.js +2 -2
  263. package/dist/version.js.map +1 -1
  264. package/package.json +5 -5
@@ -215,6 +215,7 @@ function getMcprcServerStatus(serverName) {
215
215
  }
216
216
  return "pending";
217
217
  }
218
+ let connectedClients = [];
218
219
  const getClients = memoize(async () => {
219
220
  if (process.env.CI && process.env.NODE_ENV !== "test") {
220
221
  return [];
@@ -238,7 +239,7 @@ const getClients = memoize(async () => {
238
239
  (server) => server.enabled !== false
239
240
  // Default to enabled if not specified
240
241
  );
241
- return await Promise.all(
242
+ const clients = await Promise.all(
242
243
  Object.entries(enabledServers).map(async ([name, serverRef]) => {
243
244
  try {
244
245
  const client = await connectToServer(name, serverRef);
@@ -252,6 +253,8 @@ const getClients = memoize(async () => {
252
253
  }
253
254
  })
254
255
  );
256
+ connectedClients = clients;
257
+ return clients;
255
258
  });
256
259
  async function requestAll(req, resultSchema, requiredCapability) {
257
260
  const clients = await getClients();
@@ -432,6 +435,29 @@ function refreshMCPConnections() {
432
435
  getMCPCommands.cache.clear();
433
436
  }
434
437
  }
438
+ async function shutdownMCPClients() {
439
+ if (connectedClients.length === 0) {
440
+ return;
441
+ }
442
+ const closePromises = connectedClients.map(async (wrappedClient) => {
443
+ if (wrappedClient.type === "connected") {
444
+ try {
445
+ await wrappedClient.client.close();
446
+ } catch {
447
+ }
448
+ }
449
+ });
450
+ const SHUTDOWN_TIMEOUT_MS = 3e3;
451
+ try {
452
+ await Promise.race([
453
+ Promise.allSettled(closePromises),
454
+ new Promise((resolve) => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS))
455
+ ]);
456
+ } catch {
457
+ }
458
+ connectedClients = [];
459
+ refreshMCPConnections();
460
+ }
435
461
  export {
436
462
  addMcpServer,
437
463
  ensureConfigScope,
@@ -444,6 +470,7 @@ export {
444
470
  parseEnvVars,
445
471
  refreshMCPConnections,
446
472
  removeMcpServer,
447
- runCommand
473
+ runCommand,
474
+ shutdownMCPClients
448
475
  };
449
476
  //# sourceMappingURL=mcpClient.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/services/mcpClient.ts"],
4
- "sourcesContent": ["import { zipObject } from 'lodash-es'\nimport {\n getCurrentProjectConfig,\n McpServerConfig,\n saveCurrentProjectConfig,\n getGlobalConfig,\n saveGlobalConfig,\n getMcprcConfig,\n addMcprcServerForTesting,\n removeMcprcServerForTesting,\n} from '@utils/config'\nimport { existsSync, readFileSync, writeFileSync } from 'fs'\nimport { join } from 'path'\nimport { getCwd } from '@utils/state'\nimport { safeParseJSON } from '@utils/json'\nimport {\n ImageBlockParam,\n MessageParam,\n ToolResultBlockParam,\n} from '@anthropic-ai/sdk/resources/index.mjs'\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'\nimport {\n CallToolResultSchema,\n ClientRequest,\n ListPromptsResult,\n ListPromptsResultSchema,\n ListToolsResult,\n ListToolsResultSchema,\n Result,\n ResultSchema,\n} from '@modelcontextprotocol/sdk/types.js'\nimport { memoize, pickBy } from 'lodash-es'\nimport type { Tool } from '@tool'\nimport { MCPTool } from '@tools/MCPTool/MCPTool'\nimport { logMCPError } from '@utils/log'\nimport { Command } from '@commands'\nimport { PRODUCT_COMMAND } from '@constants/product'\n\ntype McpName = string\n\nexport function parseEnvVars(\n rawEnvArgs: string[] | undefined,\n): Record<string, string> {\n const parsedEnv: Record<string, string> = {}\n\n // Parse individual env vars\n if (rawEnvArgs) {\n for (const envStr of rawEnvArgs) {\n const [key, ...valueParts] = envStr.split('=')\n if (!key || valueParts.length === 0) {\n throw new Error(\n `Invalid environment variable format: ${envStr}, environment variables should be added as: -e KEY1=value1 -e KEY2=value2`,\n )\n }\n parsedEnv[key] = valueParts.join('=')\n }\n }\n return parsedEnv\n}\n\nconst VALID_SCOPES = ['project', 'global', 'mcprc'] as const\ntype ConfigScope = (typeof VALID_SCOPES)[number]\nconst EXTERNAL_SCOPES = ['project', 'global'] as ConfigScope[]\n\nexport function ensureConfigScope(scope?: string): ConfigScope {\n if (!scope) return 'project'\n\n const scopesToCheck =\n process.env.USER_TYPE === 'external' ? EXTERNAL_SCOPES : VALID_SCOPES\n\n if (!scopesToCheck.includes(scope as ConfigScope)) {\n throw new Error(\n `Invalid scope: ${scope}. Must be one of: ${scopesToCheck.join(', ')}`,\n )\n }\n\n return scope as ConfigScope\n}\n\nexport function addMcpServer(\n name: McpName,\n server: McpServerConfig,\n scope: ConfigScope = 'project',\n): void {\n if (scope === 'mcprc') {\n if (process.env.NODE_ENV === 'test') {\n addMcprcServerForTesting(name, server)\n } else {\n const mcprcPath = join(getCwd(), '.mcprc')\n let mcprcConfig: Record<string, McpServerConfig> = {}\n\n // Read existing config if present\n if (existsSync(mcprcPath)) {\n try {\n const mcprcContent = readFileSync(mcprcPath, 'utf-8')\n const existingConfig = safeParseJSON(mcprcContent)\n if (existingConfig && typeof existingConfig === 'object') {\n mcprcConfig = existingConfig as Record<string, McpServerConfig>\n }\n } catch {\n // If we can't read/parse, start with empty config\n }\n }\n\n // Add the server\n mcprcConfig[name] = server\n\n // Write back to .mcprc\n try {\n writeFileSync(mcprcPath, JSON.stringify(mcprcConfig, null, 2), 'utf-8')\n } catch (error) {\n throw new Error(`Failed to write to .mcprc: ${error}`)\n }\n }\n } else if (scope === 'global') {\n const config = getGlobalConfig()\n if (!config.mcpServers) {\n config.mcpServers = {}\n }\n config.mcpServers[name] = server\n saveGlobalConfig(config)\n } else {\n const config = getCurrentProjectConfig()\n if (!config.mcpServers) {\n config.mcpServers = {}\n }\n config.mcpServers[name] = server\n saveCurrentProjectConfig(config)\n }\n}\n\nexport function removeMcpServer(\n name: McpName,\n scope: ConfigScope = 'project',\n): void {\n if (scope === 'mcprc') {\n if (process.env.NODE_ENV === 'test') {\n removeMcprcServerForTesting(name)\n } else {\n const mcprcPath = join(getCwd(), '.mcprc')\n if (!existsSync(mcprcPath)) {\n throw new Error('No .mcprc file found in this directory')\n }\n\n try {\n const mcprcContent = readFileSync(mcprcPath, 'utf-8')\n const mcprcConfig = safeParseJSON(mcprcContent) as Record<\n string,\n McpServerConfig\n > | null\n\n if (\n !mcprcConfig ||\n typeof mcprcConfig !== 'object' ||\n !mcprcConfig[name]\n ) {\n throw new Error(`No MCP server found with name: ${name} in .mcprc`)\n }\n\n delete mcprcConfig[name]\n writeFileSync(mcprcPath, JSON.stringify(mcprcConfig, null, 2), 'utf-8')\n } catch (error) {\n if (error instanceof Error) {\n throw error\n }\n throw new Error(`Failed to remove from .mcprc: ${error}`)\n }\n }\n } else if (scope === 'global') {\n const config = getGlobalConfig()\n if (!config.mcpServers?.[name]) {\n throw new Error(`No global MCP server found with name: ${name}`)\n }\n delete config.mcpServers[name]\n saveGlobalConfig(config)\n } else {\n const config = getCurrentProjectConfig()\n if (!config.mcpServers?.[name]) {\n throw new Error(`No local MCP server found with name: ${name}`)\n }\n delete config.mcpServers[name]\n saveCurrentProjectConfig(config)\n }\n}\n\nexport function listMCPServers(): Record<string, McpServerConfig> {\n const globalConfig = getGlobalConfig()\n const mcprcConfig = getMcprcConfig()\n const projectConfig = getCurrentProjectConfig()\n return {\n ...(globalConfig.mcpServers ?? {}),\n ...(mcprcConfig ?? {}), // mcprc configs override global ones\n ...(projectConfig.mcpServers ?? {}), // Project configs override mcprc ones\n }\n}\n\nexport type ScopedMcpServerConfig = McpServerConfig & {\n scope: ConfigScope\n}\n\nexport function getMcpServer(name: McpName): ScopedMcpServerConfig | undefined {\n const projectConfig = getCurrentProjectConfig()\n const mcprcConfig = getMcprcConfig()\n const globalConfig = getGlobalConfig()\n\n // Check each scope in order of precedence\n if (projectConfig.mcpServers?.[name]) {\n return { ...projectConfig.mcpServers[name], scope: 'project' }\n }\n\n if (mcprcConfig?.[name]) {\n return { ...mcprcConfig[name], scope: 'mcprc' }\n }\n\n if (globalConfig.mcpServers?.[name]) {\n return { ...globalConfig.mcpServers[name], scope: 'global' }\n }\n\n return undefined\n}\n\nasync function connectToServer(\n name: string,\n serverRef: McpServerConfig,\n): Promise<Client> {\n const transport =\n serverRef.type === 'sse'\n ? new SSEClientTransport(new URL(serverRef.url))\n : new StdioClientTransport({\n command: serverRef.command,\n args: serverRef.args,\n env: {\n ...process.env,\n ...serverRef.env,\n } as Record<string, string>,\n stderr: 'pipe', // prevents error output from the MCP server from printing to the UI\n })\n\n const client = new Client(\n {\n name: PRODUCT_COMMAND,\n version: '0.1.0',\n },\n {\n capabilities: {},\n },\n )\n\n // Add a timeout to connection attempts to prevent tests from hanging indefinitely\n const CONNECTION_TIMEOUT_MS = 5000\n const connectPromise = client.connect(transport)\n const timeoutPromise = new Promise<never>((_, reject) => {\n const timeoutId = setTimeout(() => {\n reject(\n new Error(\n `Connection to MCP server \"${name}\" timed out after ${CONNECTION_TIMEOUT_MS}ms`,\n ),\n )\n }, CONNECTION_TIMEOUT_MS)\n\n // Clean up timeout if connect resolves or rejects\n connectPromise.then(\n () => clearTimeout(timeoutId),\n () => clearTimeout(timeoutId),\n )\n })\n\n await Promise.race([connectPromise, timeoutPromise])\n\n if (serverRef.type === 'stdio') {\n ;(transport as StdioClientTransport).stderr?.on('data', (data: Buffer) => {\n const errorText = data.toString().trim()\n if (errorText) {\n logMCPError(name, `Server stderr: ${errorText}`)\n }\n })\n }\n return client\n}\n\ntype ConnectedClient = {\n client: Client\n name: string\n type: 'connected'\n}\ntype FailedClient = {\n name: string\n type: 'failed'\n}\nexport type WrappedClient = ConnectedClient | FailedClient\n\nexport function getMcprcServerStatus(\n serverName: string,\n): 'approved' | 'rejected' | 'pending' {\n const config = getCurrentProjectConfig()\n if (config.approvedMcprcServers?.includes(serverName)) {\n return 'approved'\n }\n if (config.rejectedMcprcServers?.includes(serverName)) {\n return 'rejected'\n }\n return 'pending'\n}\n\nexport const getClients = memoize(async (): Promise<WrappedClient[]> => {\n // TODO: This is a temporary fix for a hang during npm run verify in CI.\n // We need to investigate why MCP client connections hang in CI verify but not in CI tests.\n if (process.env.CI && process.env.NODE_ENV !== 'test') {\n return []\n }\n\n const globalServers = getGlobalConfig().mcpServers ?? {}\n const mcprcServers = getMcprcConfig()\n const projectServers = getCurrentProjectConfig().mcpServers ?? {}\n\n // Filter mcprc servers to only include approved ones\n const approvedMcprcServers = pickBy(\n mcprcServers,\n (_, name) => getMcprcServerStatus(name) === 'approved',\n )\n\n const allServers = {\n ...globalServers,\n ...approvedMcprcServers, // Approved .mcprc servers override global ones\n ...projectServers, // Project servers take highest precedence\n }\n\n // Filter out disabled servers\n const enabledServers = pickBy(\n allServers,\n (server) => server.enabled !== false, // Default to enabled if not specified\n )\n\n return await Promise.all(\n Object.entries(enabledServers).map(async ([name, serverRef]) => {\n try {\n const client = await connectToServer(name, serverRef as McpServerConfig)\n return { name, client, type: 'connected' as const }\n } catch (error) {\n logMCPError(\n name,\n `Connection failed: ${error instanceof Error ? error.message : String(error)}`,\n )\n return { name, type: 'failed' as const }\n }\n }),\n )\n})\n\nasync function requestAll<\n ResultT extends Result,\n ResultSchemaT extends typeof ResultSchema,\n>(\n req: ClientRequest,\n resultSchema: ResultSchemaT,\n requiredCapability: string,\n): Promise<{ client: ConnectedClient; result: ResultT }[]> {\n const clients = await getClients()\n const results = await Promise.allSettled(\n clients.map(async client => {\n if (client.type === 'failed') return null\n\n try {\n const capabilities = await client.client.getServerCapabilities()\n if (!capabilities?.[requiredCapability]) {\n return null\n }\n return {\n client,\n result: (await client.client.request(req, resultSchema)) as ResultT,\n }\n } catch (error) {\n if (client.type === 'connected') {\n logMCPError(\n client.name,\n `Failed to request '${req.method}': ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n return null\n }\n }),\n )\n return results\n .filter(\n (\n result,\n ): result is PromiseFulfilledResult<{\n client: ConnectedClient\n result: ResultT\n } | null> => result.status === 'fulfilled',\n )\n .map(result => result.value)\n .filter(\n (result): result is { client: ConnectedClient; result: ResultT } =>\n result !== null,\n )\n}\n\nexport const getMCPTools = memoize(async (): Promise<Tool[]> => {\n const toolsList = await requestAll<\n ListToolsResult,\n typeof ListToolsResultSchema\n >(\n {\n method: 'tools/list',\n },\n ListToolsResultSchema,\n 'tools',\n )\n\n // TODO: Add zod schema validation\n return toolsList.flatMap(({ client, result: { tools } }) =>\n tools.map(\n (tool): Tool => ({\n ...MCPTool,\n name: 'mcp__' + client.name + '__' + tool.name,\n async description() {\n return tool.description ?? ''\n },\n async prompt() {\n return tool.description ?? ''\n },\n inputJSONSchema: tool.inputSchema as Tool['inputJSONSchema'],\n async validateInput(input, context) {\n // MCP tools handle their own validation through their schemas\n return { result: true }\n },\n async *call(args: Record<string, unknown>, context) {\n const data = await callMCPTool({ client, tool: tool.name, args })\n yield {\n type: 'result' as const,\n data,\n resultForAssistant: data,\n }\n },\n userFacingName() {\n return `${client.name}:${tool.name} (MCP)`\n },\n }),\n ),\n )\n})\n\nasync function callMCPTool({\n client: { client, name },\n tool,\n args,\n}: {\n client: ConnectedClient\n tool: string\n args: Record<string, unknown>\n}): Promise<ToolResultBlockParam['content']> {\n const result = await client.callTool(\n {\n name: tool,\n arguments: args,\n },\n CallToolResultSchema,\n )\n\n if ('isError' in result && result.isError) {\n const errorMessage = `Error calling tool ${tool}: ${result.error}`\n logMCPError(name, errorMessage)\n throw Error(errorMessage)\n }\n\n // Handle toolResult-type response\n if ('toolResult' in result) {\n return String(result.toolResult)\n }\n\n // Handle content array response\n if ('content' in result && Array.isArray(result.content)) {\n return result.content.map(item => {\n if (item.type === 'image') {\n return {\n type: 'image',\n source: {\n type: 'base64',\n data: String(item.data),\n media_type: item.mimeType as ImageBlockParam.Source['media_type'],\n },\n }\n }\n return item\n })\n }\n\n throw Error(`Unexpected response format from tool ${tool}`)\n}\n\nexport const getMCPCommands = memoize(async (): Promise<Command[]> => {\n const results = await requestAll<\n ListPromptsResult,\n typeof ListPromptsResultSchema\n >(\n {\n method: 'prompts/list',\n },\n ListPromptsResultSchema,\n 'prompts',\n )\n\n return results.flatMap(({ client, result }) =>\n result.prompts?.map(_ => {\n const argNames = Object.values(_.arguments ?? {}).map(k => k.name)\n return {\n type: 'prompt',\n name: 'mcp__' + client.name + '__' + _.name,\n description: _.description ?? '',\n isEnabled: true,\n isHidden: false,\n progressMessage: 'running',\n userFacingName() {\n return `${client.name}:${_.name} (MCP)`\n },\n argNames,\n async getPromptForCommand(args: string) {\n const argsArray = args.split(' ')\n return await runCommand(\n { name: _.name, client },\n zipObject(argNames, argsArray),\n )\n },\n }\n }),\n )\n})\n\nexport async function runCommand(\n { name, client }: { name: string; client: ConnectedClient },\n args: Record<string, string>,\n): Promise<MessageParam[]> {\n try {\n const result = await client.client.getPrompt({ name, arguments: args })\n // TODO: Support type == resource\n return result.messages.map(\n (message): MessageParam => ({\n role: message.role,\n content: [\n message.content.type === 'text'\n ? {\n type: 'text',\n text: message.content.text,\n }\n : {\n type: 'image',\n source: {\n data: String(message.content.data),\n media_type: message.content\n .mimeType as ImageBlockParam.Source['media_type'],\n type: 'base64',\n },\n },\n ],\n }),\n )\n } catch (error) {\n logMCPError(\n client.name,\n `Error running command '${name}': ${error instanceof Error ? error.message : String(error)}`,\n )\n throw error\n }\n}\n\n/**\n * Refreshes MCP connections by clearing memoization cache and reconnecting\n * Useful when MCP configuration changes or servers become available after app startup\n */\nexport function refreshMCPConnections(): void {\n // Clear memoization caches\n if (typeof getClients.cache?.clear === 'function') {\n getClients.cache.clear()\n }\n if (typeof getMCPTools.cache?.clear === 'function') {\n getMCPTools.cache.clear()\n }\n if (typeof getMCPCommands.cache?.clear === 'function') {\n getMCPCommands.cache.clear()\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { zipObject } from 'lodash-es'\nimport {\n getCurrentProjectConfig,\n McpServerConfig,\n saveCurrentProjectConfig,\n getGlobalConfig,\n saveGlobalConfig,\n getMcprcConfig,\n addMcprcServerForTesting,\n removeMcprcServerForTesting,\n} from '@utils/config'\nimport { existsSync, readFileSync, writeFileSync } from 'fs'\nimport { join } from 'path'\nimport { getCwd } from '@utils/state'\nimport { safeParseJSON } from '@utils/json'\nimport {\n ImageBlockParam,\n MessageParam,\n ToolResultBlockParam,\n} from '@anthropic-ai/sdk/resources/index.mjs'\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'\nimport {\n CallToolResultSchema,\n ClientRequest,\n ListPromptsResult,\n ListPromptsResultSchema,\n ListToolsResult,\n ListToolsResultSchema,\n Result,\n ResultSchema,\n} from '@modelcontextprotocol/sdk/types.js'\nimport { memoize, pickBy } from 'lodash-es'\nimport type { Tool } from '@tool'\nimport { MCPTool } from '@tools/MCPTool/MCPTool'\nimport { logMCPError } from '@utils/log'\nimport { Command } from '@commands'\nimport { PRODUCT_COMMAND } from '@constants/product'\n\ntype McpName = string\n\nexport function parseEnvVars(\n rawEnvArgs: string[] | undefined,\n): Record<string, string> {\n const parsedEnv: Record<string, string> = {}\n\n // Parse individual env vars\n if (rawEnvArgs) {\n for (const envStr of rawEnvArgs) {\n const [key, ...valueParts] = envStr.split('=')\n if (!key || valueParts.length === 0) {\n throw new Error(\n `Invalid environment variable format: ${envStr}, environment variables should be added as: -e KEY1=value1 -e KEY2=value2`,\n )\n }\n parsedEnv[key] = valueParts.join('=')\n }\n }\n return parsedEnv\n}\n\nconst VALID_SCOPES = ['project', 'global', 'mcprc'] as const\ntype ConfigScope = (typeof VALID_SCOPES)[number]\nconst EXTERNAL_SCOPES = ['project', 'global'] as ConfigScope[]\n\nexport function ensureConfigScope(scope?: string): ConfigScope {\n if (!scope) return 'project'\n\n const scopesToCheck =\n process.env.USER_TYPE === 'external' ? EXTERNAL_SCOPES : VALID_SCOPES\n\n if (!scopesToCheck.includes(scope as ConfigScope)) {\n throw new Error(\n `Invalid scope: ${scope}. Must be one of: ${scopesToCheck.join(', ')}`,\n )\n }\n\n return scope as ConfigScope\n}\n\nexport function addMcpServer(\n name: McpName,\n server: McpServerConfig,\n scope: ConfigScope = 'project',\n): void {\n if (scope === 'mcprc') {\n if (process.env.NODE_ENV === 'test') {\n addMcprcServerForTesting(name, server)\n } else {\n const mcprcPath = join(getCwd(), '.mcprc')\n let mcprcConfig: Record<string, McpServerConfig> = {}\n\n // Read existing config if present\n if (existsSync(mcprcPath)) {\n try {\n const mcprcContent = readFileSync(mcprcPath, 'utf-8')\n const existingConfig = safeParseJSON(mcprcContent)\n if (existingConfig && typeof existingConfig === 'object') {\n mcprcConfig = existingConfig as Record<string, McpServerConfig>\n }\n } catch {\n // If we can't read/parse, start with empty config\n }\n }\n\n // Add the server\n mcprcConfig[name] = server\n\n // Write back to .mcprc\n try {\n writeFileSync(mcprcPath, JSON.stringify(mcprcConfig, null, 2), 'utf-8')\n } catch (error) {\n throw new Error(`Failed to write to .mcprc: ${error}`)\n }\n }\n } else if (scope === 'global') {\n const config = getGlobalConfig()\n if (!config.mcpServers) {\n config.mcpServers = {}\n }\n config.mcpServers[name] = server\n saveGlobalConfig(config)\n } else {\n const config = getCurrentProjectConfig()\n if (!config.mcpServers) {\n config.mcpServers = {}\n }\n config.mcpServers[name] = server\n saveCurrentProjectConfig(config)\n }\n}\n\nexport function removeMcpServer(\n name: McpName,\n scope: ConfigScope = 'project',\n): void {\n if (scope === 'mcprc') {\n if (process.env.NODE_ENV === 'test') {\n removeMcprcServerForTesting(name)\n } else {\n const mcprcPath = join(getCwd(), '.mcprc')\n if (!existsSync(mcprcPath)) {\n throw new Error('No .mcprc file found in this directory')\n }\n\n try {\n const mcprcContent = readFileSync(mcprcPath, 'utf-8')\n const mcprcConfig = safeParseJSON(mcprcContent) as Record<\n string,\n McpServerConfig\n > | null\n\n if (\n !mcprcConfig ||\n typeof mcprcConfig !== 'object' ||\n !mcprcConfig[name]\n ) {\n throw new Error(`No MCP server found with name: ${name} in .mcprc`)\n }\n\n delete mcprcConfig[name]\n writeFileSync(mcprcPath, JSON.stringify(mcprcConfig, null, 2), 'utf-8')\n } catch (error) {\n if (error instanceof Error) {\n throw error\n }\n throw new Error(`Failed to remove from .mcprc: ${error}`)\n }\n }\n } else if (scope === 'global') {\n const config = getGlobalConfig()\n if (!config.mcpServers?.[name]) {\n throw new Error(`No global MCP server found with name: ${name}`)\n }\n delete config.mcpServers[name]\n saveGlobalConfig(config)\n } else {\n const config = getCurrentProjectConfig()\n if (!config.mcpServers?.[name]) {\n throw new Error(`No local MCP server found with name: ${name}`)\n }\n delete config.mcpServers[name]\n saveCurrentProjectConfig(config)\n }\n}\n\nexport function listMCPServers(): Record<string, McpServerConfig> {\n const globalConfig = getGlobalConfig()\n const mcprcConfig = getMcprcConfig()\n const projectConfig = getCurrentProjectConfig()\n return {\n ...(globalConfig.mcpServers ?? {}),\n ...(mcprcConfig ?? {}), // mcprc configs override global ones\n ...(projectConfig.mcpServers ?? {}), // Project configs override mcprc ones\n }\n}\n\nexport type ScopedMcpServerConfig = McpServerConfig & {\n scope: ConfigScope\n}\n\nexport function getMcpServer(name: McpName): ScopedMcpServerConfig | undefined {\n const projectConfig = getCurrentProjectConfig()\n const mcprcConfig = getMcprcConfig()\n const globalConfig = getGlobalConfig()\n\n // Check each scope in order of precedence\n if (projectConfig.mcpServers?.[name]) {\n return { ...projectConfig.mcpServers[name], scope: 'project' }\n }\n\n if (mcprcConfig?.[name]) {\n return { ...mcprcConfig[name], scope: 'mcprc' }\n }\n\n if (globalConfig.mcpServers?.[name]) {\n return { ...globalConfig.mcpServers[name], scope: 'global' }\n }\n\n return undefined\n}\n\nasync function connectToServer(\n name: string,\n serverRef: McpServerConfig,\n): Promise<Client> {\n const transport =\n serverRef.type === 'sse'\n ? new SSEClientTransport(new URL(serverRef.url))\n : new StdioClientTransport({\n command: serverRef.command,\n args: serverRef.args,\n env: {\n ...process.env,\n ...serverRef.env,\n } as Record<string, string>,\n stderr: 'pipe', // prevents error output from the MCP server from printing to the UI\n })\n\n const client = new Client(\n {\n name: PRODUCT_COMMAND,\n version: '0.1.0',\n },\n {\n capabilities: {},\n },\n )\n\n // Add a timeout to connection attempts to prevent tests from hanging indefinitely\n const CONNECTION_TIMEOUT_MS = 5000\n const connectPromise = client.connect(transport)\n const timeoutPromise = new Promise<never>((_, reject) => {\n const timeoutId = setTimeout(() => {\n reject(\n new Error(\n `Connection to MCP server \"${name}\" timed out after ${CONNECTION_TIMEOUT_MS}ms`,\n ),\n )\n }, CONNECTION_TIMEOUT_MS)\n\n // Clean up timeout if connect resolves or rejects\n connectPromise.then(\n () => clearTimeout(timeoutId),\n () => clearTimeout(timeoutId),\n )\n })\n\n await Promise.race([connectPromise, timeoutPromise])\n\n if (serverRef.type === 'stdio') {\n ;(transport as StdioClientTransport).stderr?.on('data', (data: Buffer) => {\n const errorText = data.toString().trim()\n if (errorText) {\n logMCPError(name, `Server stderr: ${errorText}`)\n }\n })\n }\n return client\n}\n\ntype ConnectedClient = {\n client: Client\n name: string\n type: 'connected'\n}\ntype FailedClient = {\n name: string\n type: 'failed'\n}\nexport type WrappedClient = ConnectedClient | FailedClient\n\nexport function getMcprcServerStatus(\n serverName: string,\n): 'approved' | 'rejected' | 'pending' {\n const config = getCurrentProjectConfig()\n if (config.approvedMcprcServers?.includes(serverName)) {\n return 'approved'\n }\n if (config.rejectedMcprcServers?.includes(serverName)) {\n return 'rejected'\n }\n return 'pending'\n}\n\n// Store connected clients for cleanup on shutdown\nlet connectedClients: WrappedClient[] = []\n\nexport const getClients = memoize(async (): Promise<WrappedClient[]> => {\n // TODO: This is a temporary fix for a hang during npm run verify in CI.\n // We need to investigate why MCP client connections hang in CI verify but not in CI tests.\n if (process.env.CI && process.env.NODE_ENV !== 'test') {\n return []\n }\n\n const globalServers = getGlobalConfig().mcpServers ?? {}\n const mcprcServers = getMcprcConfig()\n const projectServers = getCurrentProjectConfig().mcpServers ?? {}\n\n // Filter mcprc servers to only include approved ones\n const approvedMcprcServers = pickBy(\n mcprcServers,\n (_, name) => getMcprcServerStatus(name) === 'approved',\n )\n\n const allServers = {\n ...globalServers,\n ...approvedMcprcServers, // Approved .mcprc servers override global ones\n ...projectServers, // Project servers take highest precedence\n }\n\n // Filter out disabled servers\n const enabledServers = pickBy(\n allServers,\n server => server.enabled !== false, // Default to enabled if not specified\n )\n\n const clients = await Promise.all(\n Object.entries(enabledServers).map(async ([name, serverRef]) => {\n try {\n const client = await connectToServer(name, serverRef as McpServerConfig)\n return { name, client, type: 'connected' as const }\n } catch (error) {\n logMCPError(\n name,\n `Connection failed: ${error instanceof Error ? error.message : String(error)}`,\n )\n return { name, type: 'failed' as const }\n }\n }),\n )\n\n // Store reference for shutdown cleanup\n connectedClients = clients\n return clients\n})\n\nasync function requestAll<\n ResultT extends Result,\n ResultSchemaT extends typeof ResultSchema,\n>(\n req: ClientRequest,\n resultSchema: ResultSchemaT,\n requiredCapability: string,\n): Promise<{ client: ConnectedClient; result: ResultT }[]> {\n const clients = await getClients()\n const results = await Promise.allSettled(\n clients.map(async client => {\n if (client.type === 'failed') return null\n\n try {\n const capabilities = await client.client.getServerCapabilities()\n if (!capabilities?.[requiredCapability]) {\n return null\n }\n return {\n client,\n result: (await client.client.request(req, resultSchema)) as ResultT,\n }\n } catch (error) {\n if (client.type === 'connected') {\n logMCPError(\n client.name,\n `Failed to request '${req.method}': ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n return null\n }\n }),\n )\n return results\n .filter(\n (\n result,\n ): result is PromiseFulfilledResult<{\n client: ConnectedClient\n result: ResultT\n } | null> => result.status === 'fulfilled',\n )\n .map(result => result.value)\n .filter(\n (result): result is { client: ConnectedClient; result: ResultT } =>\n result !== null,\n )\n}\n\nexport const getMCPTools = memoize(async (): Promise<Tool[]> => {\n const toolsList = await requestAll<\n ListToolsResult,\n typeof ListToolsResultSchema\n >(\n {\n method: 'tools/list',\n },\n ListToolsResultSchema,\n 'tools',\n )\n\n // TODO: Add zod schema validation\n return toolsList.flatMap(({ client, result: { tools } }) =>\n tools.map(\n (tool): Tool => ({\n ...MCPTool,\n name: 'mcp__' + client.name + '__' + tool.name,\n async description() {\n return tool.description ?? ''\n },\n async prompt() {\n return tool.description ?? ''\n },\n inputJSONSchema: tool.inputSchema as Tool['inputJSONSchema'],\n async validateInput(input, context) {\n // MCP tools handle their own validation through their schemas\n return { result: true }\n },\n async *call(args: Record<string, unknown>, context) {\n const data = await callMCPTool({ client, tool: tool.name, args })\n yield {\n type: 'result' as const,\n data,\n resultForAssistant: data,\n }\n },\n userFacingName() {\n return `${client.name}:${tool.name} (MCP)`\n },\n }),\n ),\n )\n})\n\nasync function callMCPTool({\n client: { client, name },\n tool,\n args,\n}: {\n client: ConnectedClient\n tool: string\n args: Record<string, unknown>\n}): Promise<ToolResultBlockParam['content']> {\n const result = await client.callTool(\n {\n name: tool,\n arguments: args,\n },\n CallToolResultSchema,\n )\n\n if ('isError' in result && result.isError) {\n const errorMessage = `Error calling tool ${tool}: ${result.error}`\n logMCPError(name, errorMessage)\n throw Error(errorMessage)\n }\n\n // Handle toolResult-type response\n if ('toolResult' in result) {\n return String(result.toolResult)\n }\n\n // Handle content array response\n if ('content' in result && Array.isArray(result.content)) {\n return result.content.map(item => {\n if (item.type === 'image') {\n return {\n type: 'image',\n source: {\n type: 'base64',\n data: String(item.data),\n media_type: item.mimeType as ImageBlockParam.Source['media_type'],\n },\n }\n }\n return item\n })\n }\n\n throw Error(`Unexpected response format from tool ${tool}`)\n}\n\nexport const getMCPCommands = memoize(async (): Promise<Command[]> => {\n const results = await requestAll<\n ListPromptsResult,\n typeof ListPromptsResultSchema\n >(\n {\n method: 'prompts/list',\n },\n ListPromptsResultSchema,\n 'prompts',\n )\n\n return results.flatMap(({ client, result }) =>\n result.prompts?.map(_ => {\n const argNames = Object.values(_.arguments ?? {}).map(k => k.name)\n return {\n type: 'prompt',\n name: 'mcp__' + client.name + '__' + _.name,\n description: _.description ?? '',\n isEnabled: true,\n isHidden: false,\n progressMessage: 'running',\n userFacingName() {\n return `${client.name}:${_.name} (MCP)`\n },\n argNames,\n async getPromptForCommand(args: string) {\n const argsArray = args.split(' ')\n return await runCommand(\n { name: _.name, client },\n zipObject(argNames, argsArray),\n )\n },\n }\n }),\n )\n})\n\nexport async function runCommand(\n { name, client }: { name: string; client: ConnectedClient },\n args: Record<string, string>,\n): Promise<MessageParam[]> {\n try {\n const result = await client.client.getPrompt({ name, arguments: args })\n // TODO: Support type == resource\n return result.messages.map(\n (message): MessageParam => ({\n role: message.role,\n content: [\n message.content.type === 'text'\n ? {\n type: 'text',\n text: message.content.text,\n }\n : {\n type: 'image',\n source: {\n data: String(message.content.data),\n media_type: message.content\n .mimeType as ImageBlockParam.Source['media_type'],\n type: 'base64',\n },\n },\n ],\n }),\n )\n } catch (error) {\n logMCPError(\n client.name,\n `Error running command '${name}': ${error instanceof Error ? error.message : String(error)}`,\n )\n throw error\n }\n}\n\n/**\n * Refreshes MCP connections by clearing memoization cache and reconnecting\n * Useful when MCP configuration changes or servers become available after app startup\n */\nexport function refreshMCPConnections(): void {\n // Clear memoization caches\n if (typeof getClients.cache?.clear === 'function') {\n getClients.cache.clear()\n }\n if (typeof getMCPTools.cache?.clear === 'function') {\n getMCPTools.cache.clear()\n }\n if (typeof getMCPCommands.cache?.clear === 'function') {\n getMCPCommands.cache.clear()\n }\n}\n\n/**\n * Shuts down all MCP client connections gracefully\n * Should be called when the application is exiting\n */\nexport async function shutdownMCPClients(): Promise<void> {\n if (connectedClients.length === 0) {\n return\n }\n\n // Close all connected clients\n const closePromises = connectedClients.map(async wrappedClient => {\n if (wrappedClient.type === 'connected') {\n try {\n await wrappedClient.client.close()\n } catch {\n // Ignore errors during shutdown - the process is exiting anyway\n }\n }\n })\n\n // Wait for all clients to close with a timeout\n const SHUTDOWN_TIMEOUT_MS = 3000\n try {\n await Promise.race([\n Promise.allSettled(closePromises),\n new Promise(resolve => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS)),\n ])\n } catch {\n // Ignore timeout errors during shutdown\n }\n\n // Clear references\n connectedClients = []\n refreshMCPConnections()\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -46,8 +46,12 @@ class MentionProcessorService {
46
46
  }
47
47
  }
48
48
  }
49
- const fileMatches = [...input.matchAll(MentionProcessorService.MENTION_PATTERNS.file)];
50
- const processedAgentMentions = new Set(agentMentions.map((am) => am.mention));
49
+ const fileMatches = [
50
+ ...input.matchAll(MentionProcessorService.MENTION_PATTERNS.file)
51
+ ];
52
+ const processedAgentMentions = new Set(
53
+ agentMentions.map((am) => am.mention)
54
+ );
51
55
  for (const match of fileMatches) {
52
56
  const mention = match[1];
53
57
  if (mention.startsWith("run-agent-") || mention.startsWith("agent-") || mention.startsWith("ask-") || processedAgentMentions.has(mention)) {
@@ -115,11 +119,14 @@ class MentionProcessorService {
115
119
  });
116
120
  }
117
121
  } catch (error) {
118
- console.warn("[MentionProcessor] Failed to refresh agent cache, keeping existing cache:", {
119
- error: error instanceof Error ? error.message : error,
120
- cacheSize: this.agentCache.size,
121
- lastRefresh: new Date(this.lastAgentCheck).toISOString()
122
- });
122
+ console.warn(
123
+ "[MentionProcessor] Failed to refresh agent cache, keeping existing cache:",
124
+ {
125
+ error: error instanceof Error ? error.message : error,
126
+ cacheSize: this.agentCache.size,
127
+ lastRefresh: new Date(this.lastAgentCheck).toISOString()
128
+ }
129
+ );
123
130
  }
124
131
  }
125
132
  /**
@@ -128,19 +135,25 @@ class MentionProcessorService {
128
135
  */
129
136
  extractAgentMentions(input) {
130
137
  const mentions = [];
131
- const runAgentMatches = [...input.matchAll(MentionProcessorService.MENTION_PATTERNS.runAgent)];
138
+ const runAgentMatches = [
139
+ ...input.matchAll(MentionProcessorService.MENTION_PATTERNS.runAgent)
140
+ ];
132
141
  for (const match of runAgentMatches) {
133
142
  const mention = match[1];
134
143
  const agentType = mention.replace(/^run-agent-/, "");
135
144
  mentions.push({ mention, agentType, isAskModel: false });
136
145
  }
137
- const agentMatches = [...input.matchAll(MentionProcessorService.MENTION_PATTERNS.agent)];
146
+ const agentMatches = [
147
+ ...input.matchAll(MentionProcessorService.MENTION_PATTERNS.agent)
148
+ ];
138
149
  for (const match of agentMatches) {
139
150
  const mention = match[1];
140
151
  const agentType = mention.replace(/^agent-/, "");
141
152
  mentions.push({ mention, agentType, isAskModel: false });
142
153
  }
143
- const askModelMatches = [...input.matchAll(MentionProcessorService.MENTION_PATTERNS.askModel)];
154
+ const askModelMatches = [
155
+ ...input.matchAll(MentionProcessorService.MENTION_PATTERNS.askModel)
156
+ ];
144
157
  for (const match of askModelMatches) {
145
158
  const mention = match[1];
146
159
  mentions.push({ mention, agentType: mention, isAskModel: true });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/services/mentionProcessor.ts"],
4
- "sourcesContent": ["/**\n * Mention Processor Service\n * Handles @agent and @file mentions through the system reminder infrastructure\n * Designed to integrate naturally with the existing event-driven architecture\n */\n\nimport { emitReminderEvent } from './systemReminder'\nimport { getAvailableAgentTypes } from '@utils/agentLoader'\nimport { existsSync } from 'fs'\nimport { resolve } from 'path'\nimport { getCwd } from '@utils/state'\nimport { debug as debugLogger } from '@utils/debugLogger'\n\nexport interface MentionContext {\n type: 'agent' | 'file'\n mention: string\n resolved: string\n exists: boolean\n metadata?: any\n}\n\nexport interface ProcessedMentions {\n agents: MentionContext[]\n files: MentionContext[]\n hasAgentMentions: boolean\n hasFileMentions: boolean\n}\n\nclass MentionProcessorService {\n // Centralized mention patterns - single source of truth\n private static readonly MENTION_PATTERNS = {\n runAgent: /@(run-agent-[\\w\\-]+)/g,\n agent: /@(agent-[\\w\\-]+)/g, // Legacy support\n askModel: /@(ask-[\\w\\-]+)/g,\n file: /@([a-zA-Z0-9/._-]+(?:\\.[a-zA-Z0-9]+)?)/g\n } as const\n\n private agentCache: Map<string, boolean> = new Map()\n private lastAgentCheck: number = 0\n private CACHE_TTL = 60000 // 1 minute cache\n\n /**\n * Process mentions in user input and emit appropriate events\n * This follows the event-driven philosophy of system reminders\n */\n public async processMentions(input: string): Promise<ProcessedMentions> {\n const result: ProcessedMentions = {\n agents: [],\n files: [],\n hasAgentMentions: false,\n hasFileMentions: false,\n }\n\n try {\n\n // Process agent mentions with unified logic to eliminate code duplication\n const agentMentions = this.extractAgentMentions(input)\n if (agentMentions.length > 0) {\n await this.refreshAgentCache()\n \n for (const { mention, agentType, isAskModel } of agentMentions) {\n if (isAskModel || this.agentCache.has(agentType)) {\n result.agents.push({\n type: 'agent',\n mention,\n resolved: agentType,\n exists: true,\n metadata: isAskModel ? { type: 'ask-model' } : undefined\n })\n result.hasAgentMentions = true\n \n // Emit appropriate event based on mention type\n this.emitAgentMentionEvent(mention, agentType, isAskModel)\n }\n }\n }\n \n // No longer process @xxx format - treat as regular text (emails, etc.)\n\n // Process file mentions (exclude agent and ask-model mentions)\n const fileMatches = [...input.matchAll(MentionProcessorService.MENTION_PATTERNS.file)]\n const processedAgentMentions = new Set(agentMentions.map(am => am.mention))\n \n for (const match of fileMatches) {\n const mention = match[1]\n \n // Skip if this is an agent or ask-model mention (already processed)\n if (mention.startsWith('run-agent-') || mention.startsWith('agent-') || mention.startsWith('ask-') || processedAgentMentions.has(mention)) {\n continue\n }\n \n // Check if it's a file\n const filePath = this.resolveFilePath(mention)\n if (existsSync(filePath)) {\n result.files.push({\n type: 'file',\n mention,\n resolved: filePath,\n exists: true,\n })\n result.hasFileMentions = true\n \n // Emit file mention event for system reminder to handle\n emitReminderEvent('file:mentioned', {\n filePath: filePath,\n originalMention: mention,\n timestamp: Date.now(),\n })\n }\n }\n\n return result\n } catch (error) {\n console.warn('[MentionProcessor] Failed to process mentions:', {\n input: input.substring(0, 100) + (input.length > 100 ? '...' : ''),\n error: error instanceof Error ? error.message : error\n })\n \n // Return empty result on error to maintain system stability\n return {\n agents: [],\n files: [],\n hasAgentMentions: false,\n hasFileMentions: false,\n }\n }\n }\n\n // Removed identifyMention method as it's no longer needed with separate processing\n\n /**\n * Resolve file path relative to current working directory\n */\n private resolveFilePath(mention: string): string {\n // Simple consistent logic: mention is always relative to current directory\n return resolve(getCwd(), mention)\n }\n\n /**\n * Refresh the agent cache periodically\n * This avoids hitting the agent loader on every mention\n */\n private async refreshAgentCache(): Promise<void> {\n const now = Date.now()\n if (now - this.lastAgentCheck < this.CACHE_TTL) {\n return // Cache is still fresh\n }\n\n try {\n const agents = await getAvailableAgentTypes()\n const previousCacheSize = this.agentCache.size\n this.agentCache.clear()\n \n for (const agent of agents) {\n // Store only the agent type without prefix for consistent lookup\n this.agentCache.set(agent.agentType, true)\n }\n \n this.lastAgentCheck = now\n \n // Log cache refresh for debugging mention resolution issues\n if (agents.length !== previousCacheSize) {\n debugLogger.info('MENTION_PROCESSOR_CACHE_REFRESHED', {\n agentCount: agents.length,\n previousCacheSize,\n cacheAge: now - this.lastAgentCheck,\n })\n }\n } catch (error) {\n console.warn('[MentionProcessor] Failed to refresh agent cache, keeping existing cache:', {\n error: error instanceof Error ? error.message : error,\n cacheSize: this.agentCache.size,\n lastRefresh: new Date(this.lastAgentCheck).toISOString()\n })\n // Keep existing cache on error to maintain functionality\n }\n }\n\n /**\n * Extract agent mentions with unified pattern matching\n * Consolidates run-agent, agent, and ask-model detection logic\n */\n private extractAgentMentions(input: string): Array<{ mention: string; agentType: string; isAskModel: boolean }> {\n const mentions: Array<{ mention: string; agentType: string; isAskModel: boolean }> = []\n \n // Process @run-agent-xxx format (preferred)\n const runAgentMatches = [...input.matchAll(MentionProcessorService.MENTION_PATTERNS.runAgent)]\n for (const match of runAgentMatches) {\n const mention = match[1]\n const agentType = mention.replace(/^run-agent-/, '')\n mentions.push({ mention, agentType, isAskModel: false })\n }\n \n // Process @agent-xxx format (legacy)\n const agentMatches = [...input.matchAll(MentionProcessorService.MENTION_PATTERNS.agent)]\n for (const match of agentMatches) {\n const mention = match[1]\n const agentType = mention.replace(/^agent-/, '')\n mentions.push({ mention, agentType, isAskModel: false })\n }\n \n // Process @ask-model mentions\n const askModelMatches = [...input.matchAll(MentionProcessorService.MENTION_PATTERNS.askModel)]\n for (const match of askModelMatches) {\n const mention = match[1]\n mentions.push({ mention, agentType: mention, isAskModel: true })\n }\n \n return mentions\n }\n \n /**\n * Emit agent mention event with proper typing\n * Centralized event emission to ensure consistency\n */\n private emitAgentMentionEvent(mention: string, agentType: string, isAskModel: boolean): void {\n try {\n const eventData = {\n originalMention: mention,\n timestamp: Date.now(),\n }\n\n if (isAskModel) {\n emitReminderEvent('ask-model:mentioned', {\n ...eventData,\n modelName: mention,\n })\n } else {\n emitReminderEvent('agent:mentioned', {\n ...eventData,\n agentType,\n })\n }\n \n // Debug log for mention event emission tracking\n debugLogger.info('MENTION_PROCESSOR_EVENT_EMITTED', {\n type: isAskModel ? 'ask-model' : 'agent',\n mention,\n agentType: isAskModel ? undefined : agentType,\n })\n } catch (error) {\n debugLogger.error('MENTION_PROCESSOR_EVENT_FAILED', {\n mention,\n agentType,\n isAskModel,\n error: error instanceof Error ? error.message : error,\n })\n }\n }\n\n /**\n * Clear caches - useful for testing or reset\n */\n public clearCache(): void {\n this.agentCache.clear()\n this.lastAgentCheck = 0\n }\n}\n\n// Export singleton instance\nexport const mentionProcessor = new MentionProcessorService()\n\n/**\n * Process mentions in user input\n * This is the main API for the mention processor\n */\nexport const processMentions = (input: string) => \n mentionProcessor.processMentions(input)\n\n/**\n * Clear mention processor caches\n */\nexport const clearMentionCache = () =>\n mentionProcessor.clearCache()\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Mention Processor Service\n * Handles @agent and @file mentions through the system reminder infrastructure\n * Designed to integrate naturally with the existing event-driven architecture\n */\n\nimport { emitReminderEvent } from './systemReminder'\nimport { getAvailableAgentTypes } from '@utils/agentLoader'\nimport { existsSync } from 'fs'\nimport { resolve } from 'path'\nimport { getCwd } from '@utils/state'\nimport { debug as debugLogger } from '@utils/debugLogger'\n\nexport interface MentionContext {\n type: 'agent' | 'file'\n mention: string\n resolved: string\n exists: boolean\n metadata?: any\n}\n\nexport interface ProcessedMentions {\n agents: MentionContext[]\n files: MentionContext[]\n hasAgentMentions: boolean\n hasFileMentions: boolean\n}\n\nclass MentionProcessorService {\n // Centralized mention patterns - single source of truth\n private static readonly MENTION_PATTERNS = {\n runAgent: /@(run-agent-[\\w\\-]+)/g,\n agent: /@(agent-[\\w\\-]+)/g, // Legacy support\n askModel: /@(ask-[\\w\\-]+)/g,\n file: /@([a-zA-Z0-9/._-]+(?:\\.[a-zA-Z0-9]+)?)/g,\n } as const\n\n private agentCache: Map<string, boolean> = new Map()\n private lastAgentCheck: number = 0\n private CACHE_TTL = 60000 // 1 minute cache\n\n /**\n * Process mentions in user input and emit appropriate events\n * This follows the event-driven philosophy of system reminders\n */\n public async processMentions(input: string): Promise<ProcessedMentions> {\n const result: ProcessedMentions = {\n agents: [],\n files: [],\n hasAgentMentions: false,\n hasFileMentions: false,\n }\n\n try {\n // Process agent mentions with unified logic to eliminate code duplication\n const agentMentions = this.extractAgentMentions(input)\n if (agentMentions.length > 0) {\n await this.refreshAgentCache()\n\n for (const { mention, agentType, isAskModel } of agentMentions) {\n if (isAskModel || this.agentCache.has(agentType)) {\n result.agents.push({\n type: 'agent',\n mention,\n resolved: agentType,\n exists: true,\n metadata: isAskModel ? { type: 'ask-model' } : undefined,\n })\n result.hasAgentMentions = true\n\n // Emit appropriate event based on mention type\n this.emitAgentMentionEvent(mention, agentType, isAskModel)\n }\n }\n }\n\n // No longer process @xxx format - treat as regular text (emails, etc.)\n\n // Process file mentions (exclude agent and ask-model mentions)\n const fileMatches = [\n ...input.matchAll(MentionProcessorService.MENTION_PATTERNS.file),\n ]\n const processedAgentMentions = new Set(\n agentMentions.map(am => am.mention),\n )\n\n for (const match of fileMatches) {\n const mention = match[1]\n\n // Skip if this is an agent or ask-model mention (already processed)\n if (\n mention.startsWith('run-agent-') ||\n mention.startsWith('agent-') ||\n mention.startsWith('ask-') ||\n processedAgentMentions.has(mention)\n ) {\n continue\n }\n\n // Check if it's a file\n const filePath = this.resolveFilePath(mention)\n if (existsSync(filePath)) {\n result.files.push({\n type: 'file',\n mention,\n resolved: filePath,\n exists: true,\n })\n result.hasFileMentions = true\n\n // Emit file mention event for system reminder to handle\n emitReminderEvent('file:mentioned', {\n filePath: filePath,\n originalMention: mention,\n timestamp: Date.now(),\n })\n }\n }\n\n return result\n } catch (error) {\n console.warn('[MentionProcessor] Failed to process mentions:', {\n input: input.substring(0, 100) + (input.length > 100 ? '...' : ''),\n error: error instanceof Error ? error.message : error,\n })\n\n // Return empty result on error to maintain system stability\n return {\n agents: [],\n files: [],\n hasAgentMentions: false,\n hasFileMentions: false,\n }\n }\n }\n\n // Removed identifyMention method as it's no longer needed with separate processing\n\n /**\n * Resolve file path relative to current working directory\n */\n private resolveFilePath(mention: string): string {\n // Simple consistent logic: mention is always relative to current directory\n return resolve(getCwd(), mention)\n }\n\n /**\n * Refresh the agent cache periodically\n * This avoids hitting the agent loader on every mention\n */\n private async refreshAgentCache(): Promise<void> {\n const now = Date.now()\n if (now - this.lastAgentCheck < this.CACHE_TTL) {\n return // Cache is still fresh\n }\n\n try {\n const agents = await getAvailableAgentTypes()\n const previousCacheSize = this.agentCache.size\n this.agentCache.clear()\n\n for (const agent of agents) {\n // Store only the agent type without prefix for consistent lookup\n this.agentCache.set(agent.agentType, true)\n }\n\n this.lastAgentCheck = now\n\n // Log cache refresh for debugging mention resolution issues\n if (agents.length !== previousCacheSize) {\n debugLogger.info('MENTION_PROCESSOR_CACHE_REFRESHED', {\n agentCount: agents.length,\n previousCacheSize,\n cacheAge: now - this.lastAgentCheck,\n })\n }\n } catch (error) {\n console.warn(\n '[MentionProcessor] Failed to refresh agent cache, keeping existing cache:',\n {\n error: error instanceof Error ? error.message : error,\n cacheSize: this.agentCache.size,\n lastRefresh: new Date(this.lastAgentCheck).toISOString(),\n },\n )\n // Keep existing cache on error to maintain functionality\n }\n }\n\n /**\n * Extract agent mentions with unified pattern matching\n * Consolidates run-agent, agent, and ask-model detection logic\n */\n private extractAgentMentions(\n input: string,\n ): Array<{ mention: string; agentType: string; isAskModel: boolean }> {\n const mentions: Array<{\n mention: string\n agentType: string\n isAskModel: boolean\n }> = []\n\n // Process @run-agent-xxx format (preferred)\n const runAgentMatches = [\n ...input.matchAll(MentionProcessorService.MENTION_PATTERNS.runAgent),\n ]\n for (const match of runAgentMatches) {\n const mention = match[1]\n const agentType = mention.replace(/^run-agent-/, '')\n mentions.push({ mention, agentType, isAskModel: false })\n }\n\n // Process @agent-xxx format (legacy)\n const agentMatches = [\n ...input.matchAll(MentionProcessorService.MENTION_PATTERNS.agent),\n ]\n for (const match of agentMatches) {\n const mention = match[1]\n const agentType = mention.replace(/^agent-/, '')\n mentions.push({ mention, agentType, isAskModel: false })\n }\n\n // Process @ask-model mentions\n const askModelMatches = [\n ...input.matchAll(MentionProcessorService.MENTION_PATTERNS.askModel),\n ]\n for (const match of askModelMatches) {\n const mention = match[1]\n mentions.push({ mention, agentType: mention, isAskModel: true })\n }\n\n return mentions\n }\n\n /**\n * Emit agent mention event with proper typing\n * Centralized event emission to ensure consistency\n */\n private emitAgentMentionEvent(\n mention: string,\n agentType: string,\n isAskModel: boolean,\n ): void {\n try {\n const eventData = {\n originalMention: mention,\n timestamp: Date.now(),\n }\n\n if (isAskModel) {\n emitReminderEvent('ask-model:mentioned', {\n ...eventData,\n modelName: mention,\n })\n } else {\n emitReminderEvent('agent:mentioned', {\n ...eventData,\n agentType,\n })\n }\n\n // Debug log for mention event emission tracking\n debugLogger.info('MENTION_PROCESSOR_EVENT_EMITTED', {\n type: isAskModel ? 'ask-model' : 'agent',\n mention,\n agentType: isAskModel ? undefined : agentType,\n })\n } catch (error) {\n debugLogger.error('MENTION_PROCESSOR_EVENT_FAILED', {\n mention,\n agentType,\n isAskModel,\n error: error instanceof Error ? error.message : error,\n })\n }\n }\n\n /**\n * Clear caches - useful for testing or reset\n */\n public clearCache(): void {\n this.agentCache.clear()\n this.lastAgentCheck = 0\n }\n}\n\n// Export singleton instance\nexport const mentionProcessor = new MentionProcessorService()\n\n/**\n * Process mentions in user input\n * This is the main API for the mention processor\n */\nexport const processMentions = (input: string) =>\n mentionProcessor.processMentions(input)\n\n/**\n * Clear mention processor caches\n */\nexport const clearMentionCache = () => mentionProcessor.clearCache()\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/services/modelAdapterFactory.ts"],
4
- "sourcesContent": ["import { ModelAPIAdapter } from './adapters/base'\nimport { ResponsesAPIAdapter } from './adapters/responsesAPI'\nimport { ChatCompletionsAdapter } from './adapters/chatCompletions'\nimport { getModelCapabilities } from '@constants/modelCapabilities'\nimport { ModelProfile, getGlobalConfig } from '@utils/config'\nimport { ModelCapabilities } from '@minto-types/modelCapabilities'\n\nexport class ModelAdapterFactory {\n /**\n * Create appropriate adapter based on model configuration\n */\n static createAdapter(modelProfile: ModelProfile): ModelAPIAdapter {\n const capabilities = getModelCapabilities(modelProfile.modelName)\n \n // Determine which API to use\n const apiType = this.determineAPIType(modelProfile, capabilities)\n \n // Create corresponding adapter\n switch (apiType) {\n case 'responses_api':\n return new ResponsesAPIAdapter(capabilities, modelProfile)\n case 'chat_completions':\n default:\n return new ChatCompletionsAdapter(capabilities, modelProfile)\n }\n }\n \n /**\n * Determine which API should be used\n */\n private static determineAPIType(\n modelProfile: ModelProfile,\n capabilities: ModelCapabilities\n ): 'responses_api' | 'chat_completions' {\n // If model doesn't support Responses API, use Chat Completions directly\n if (capabilities.apiArchitecture.primary !== 'responses_api') {\n return 'chat_completions'\n }\n \n // Check if this is official OpenAI endpoint\n const isOfficialOpenAI = !modelProfile.baseURL || \n modelProfile.baseURL.includes('api.openai.com')\n \n // Non-official endpoints use Chat Completions (even if model supports Responses API)\n if (!isOfficialOpenAI) {\n // If there's a fallback option, use fallback\n if (capabilities.apiArchitecture.fallback === 'chat_completions') {\n return 'chat_completions'\n }\n // Otherwise use primary (might fail, but let it try)\n return capabilities.apiArchitecture.primary\n }\n \n // For now, always use Responses API for supported models when on official endpoint\n // Streaming fallback will be handled at runtime if needed\n \n // Use primary API type\n return capabilities.apiArchitecture.primary\n }\n \n /**\n * Check if model should use Responses API\n */\n static shouldUseResponsesAPI(modelProfile: ModelProfile): boolean {\n const capabilities = getModelCapabilities(modelProfile.modelName)\n const apiType = this.determineAPIType(modelProfile, capabilities)\n return apiType === 'responses_api'\n }\n}\n"],
5
- "mappings": "AACA,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,4BAA4B;AAI9B,MAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA,EAI/B,OAAO,cAAc,cAA6C;AAChE,UAAM,eAAe,qBAAqB,aAAa,SAAS;AAGhE,UAAM,UAAU,KAAK,iBAAiB,cAAc,YAAY;AAGhE,YAAQ,SAAS;AAAA,MACf,KAAK;AACH,eAAO,IAAI,oBAAoB,cAAc,YAAY;AAAA,MAC3D,KAAK;AAAA,MACL;AACE,eAAO,IAAI,uBAAuB,cAAc,YAAY;AAAA,IAChE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe,iBACb,cACA,cACsC;AAEtC,QAAI,aAAa,gBAAgB,YAAY,iBAAiB;AAC5D,aAAO;AAAA,IACT;AAGA,UAAM,mBAAmB,CAAC,aAAa,WACrC,aAAa,QAAQ,SAAS,gBAAgB;AAGhD,QAAI,CAAC,kBAAkB;AAErB,UAAI,aAAa,gBAAgB,aAAa,oBAAoB;AAChE,eAAO;AAAA,MACT;AAEA,aAAO,aAAa,gBAAgB;AAAA,IACtC;AAMA,WAAO,aAAa,gBAAgB;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,sBAAsB,cAAqC;AAChE,UAAM,eAAe,qBAAqB,aAAa,SAAS;AAChE,UAAM,UAAU,KAAK,iBAAiB,cAAc,YAAY;AAChE,WAAO,YAAY;AAAA,EACrB;AACF;",
4
+ "sourcesContent": ["import { ModelAPIAdapter } from './adapters/base'\nimport { ResponsesAPIAdapter } from './adapters/responsesAPI'\nimport { ChatCompletionsAdapter } from './adapters/chatCompletions'\nimport { getModelCapabilities } from '@constants/modelCapabilities'\nimport { ModelProfile, getGlobalConfig } from '@utils/config'\nimport { ModelCapabilities } from '@minto-types/modelCapabilities'\n\nexport class ModelAdapterFactory {\n /**\n * Create appropriate adapter based on model configuration\n */\n static createAdapter(modelProfile: ModelProfile): ModelAPIAdapter {\n const capabilities = getModelCapabilities(modelProfile.modelName)\n\n // Determine which API to use\n const apiType = this.determineAPIType(modelProfile, capabilities)\n\n // Create corresponding adapter\n switch (apiType) {\n case 'responses_api':\n return new ResponsesAPIAdapter(capabilities, modelProfile)\n case 'chat_completions':\n default:\n return new ChatCompletionsAdapter(capabilities, modelProfile)\n }\n }\n\n /**\n * Determine which API should be used\n */\n private static determineAPIType(\n modelProfile: ModelProfile,\n capabilities: ModelCapabilities,\n ): 'responses_api' | 'chat_completions' {\n // If model doesn't support Responses API, use Chat Completions directly\n if (capabilities.apiArchitecture.primary !== 'responses_api') {\n return 'chat_completions'\n }\n\n // Check if this is official OpenAI endpoint\n const isOfficialOpenAI =\n !modelProfile.baseURL || modelProfile.baseURL.includes('api.openai.com')\n\n // Non-official endpoints use Chat Completions (even if model supports Responses API)\n if (!isOfficialOpenAI) {\n // If there's a fallback option, use fallback\n if (capabilities.apiArchitecture.fallback === 'chat_completions') {\n return 'chat_completions'\n }\n // Otherwise use primary (might fail, but let it try)\n return capabilities.apiArchitecture.primary\n }\n\n // For now, always use Responses API for supported models when on official endpoint\n // Streaming fallback will be handled at runtime if needed\n\n // Use primary API type\n return capabilities.apiArchitecture.primary\n }\n\n /**\n * Check if model should use Responses API\n */\n static shouldUseResponsesAPI(modelProfile: ModelProfile): boolean {\n const capabilities = getModelCapabilities(modelProfile.modelName)\n const apiType = this.determineAPIType(modelProfile, capabilities)\n return apiType === 'responses_api'\n }\n}\n"],
5
+ "mappings": "AACA,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,4BAA4B;AAI9B,MAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA,EAI/B,OAAO,cAAc,cAA6C;AAChE,UAAM,eAAe,qBAAqB,aAAa,SAAS;AAGhE,UAAM,UAAU,KAAK,iBAAiB,cAAc,YAAY;AAGhE,YAAQ,SAAS;AAAA,MACf,KAAK;AACH,eAAO,IAAI,oBAAoB,cAAc,YAAY;AAAA,MAC3D,KAAK;AAAA,MACL;AACE,eAAO,IAAI,uBAAuB,cAAc,YAAY;AAAA,IAChE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe,iBACb,cACA,cACsC;AAEtC,QAAI,aAAa,gBAAgB,YAAY,iBAAiB;AAC5D,aAAO;AAAA,IACT;AAGA,UAAM,mBACJ,CAAC,aAAa,WAAW,aAAa,QAAQ,SAAS,gBAAgB;AAGzE,QAAI,CAAC,kBAAkB;AAErB,UAAI,aAAa,gBAAgB,aAAa,oBAAoB;AAChE,eAAO;AAAA,MACT;AAEA,aAAO,aAAa,gBAAgB;AAAA,IACtC;AAMA,WAAO,aAAa,gBAAgB;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,sBAAsB,cAAqC;AAChE,UAAM,eAAe,qBAAqB,aAAa,SAAS;AAChE,UAAM,UAAU,KAAK,iBAAiB,cAAc,YAAY;AAChE,WAAO,YAAY;AAAA,EACrB;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/services/oauth.ts"],
4
- "sourcesContent": ["import * as crypto from 'crypto'\nimport * as http from 'http'\nimport { IncomingMessage, ServerResponse } from 'http'\nimport * as url from 'url'\n\nimport { OAUTH_CONFIG } from '@constants/oauth'\nimport { openBrowser } from '@utils/browser'\nimport { logError } from '@utils/log'\nimport { resetAnthropicClient } from './claude'\nimport {\n AccountInfo,\n getGlobalConfig,\n saveGlobalConfig,\n normalizeApiKeyForConfig,\n} from '@utils/config'\n\n// Base64URL encoding function (RFC 4648)\nfunction base64URLEncode(buffer: Buffer): string {\n return buffer\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n}\n\nfunction generateCodeVerifier(): string {\n return base64URLEncode(crypto.randomBytes(32))\n}\n\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder()\n const data = encoder.encode(verifier)\n const digest = await crypto.subtle.digest('SHA-256', data)\n return base64URLEncode(Buffer.from(digest))\n}\n\ntype OAuthTokenExchangeResponse = {\n access_token: string\n account?: {\n uuid: string\n email_address: string\n }\n organization?: {\n uuid: string\n name: string\n }\n}\n\nexport type OAuthResult = {\n accessToken: string\n}\n\nexport class OAuthService {\n private server: http.Server | null = null\n private codeVerifier: string\n private expectedState: string | null = null\n private pendingCodePromise: {\n resolve: (result: {\n authorizationCode: string\n useManualRedirect: boolean\n }) => void\n reject: (err: Error) => void\n } | null = null\n\n constructor() {\n this.codeVerifier = generateCodeVerifier()\n }\n\n private generateAuthUrls(\n codeChallenge: string,\n state: string,\n ): { autoUrl: string; manualUrl: string } {\n function makeUrl(isManual: boolean): string {\n const authUrl = new URL(OAUTH_CONFIG.AUTHORIZE_URL)\n authUrl.searchParams.append('client_id', OAUTH_CONFIG.CLIENT_ID)\n authUrl.searchParams.append('response_type', 'code')\n authUrl.searchParams.append(\n 'redirect_uri',\n isManual\n ? OAUTH_CONFIG.MANUAL_REDIRECT_URL\n : `http://localhost:${OAUTH_CONFIG.REDIRECT_PORT}/callback`,\n )\n authUrl.searchParams.append('scope', OAUTH_CONFIG.SCOPES.join(' '))\n authUrl.searchParams.append('code_challenge', codeChallenge)\n authUrl.searchParams.append('code_challenge_method', 'S256')\n authUrl.searchParams.append('state', state)\n return authUrl.toString()\n }\n\n return {\n autoUrl: makeUrl(false),\n manualUrl: makeUrl(true),\n }\n }\n\n async startOAuthFlow(\n authURLHandler: (url: string) => Promise<void>,\n ): Promise<OAuthResult> {\n const codeChallenge = await generateCodeChallenge(this.codeVerifier)\n const state = base64URLEncode(crypto.randomBytes(32))\n this.expectedState = state\n const { autoUrl, manualUrl } = this.generateAuthUrls(codeChallenge, state)\n\n const onReady = async () => {\n await authURLHandler(manualUrl)\n await openBrowser(autoUrl)\n }\n\n const { authorizationCode, useManualRedirect } = await new Promise<{\n authorizationCode: string\n useManualRedirect: boolean\n }>((resolve, reject) => {\n this.pendingCodePromise = { resolve, reject }\n this.startLocalServer(state, onReady)\n })\n\n // Exchange code for tokens\n const {\n access_token: accessToken,\n account,\n organization,\n } = await this.exchangeCodeForTokens(\n authorizationCode,\n state,\n useManualRedirect,\n )\n\n // Store account info\n if (account) {\n const accountInfo: AccountInfo = {\n accountUuid: account.uuid,\n emailAddress: account.email_address,\n organizationUuid: organization?.uuid,\n }\n const config = getGlobalConfig()\n config.oauthAccount = accountInfo\n saveGlobalConfig(config)\n }\n\n return { accessToken }\n }\n\n private startLocalServer(state: string, onReady?: () => void): void {\n if (this.server) {\n this.closeServer()\n }\n this.server = http.createServer(\n (req: IncomingMessage, res: ServerResponse) => {\n const parsedUrl = url.parse(req.url || '', true)\n\n if (parsedUrl.pathname === '/callback') {\n const authorizationCode = parsedUrl.query.code as string\n const returnedState = parsedUrl.query.state as string\n\n if (!authorizationCode) {\n res.writeHead(400)\n res.end('Authorization code not found')\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('No authorization code received'),\n )\n }\n return\n }\n\n if (returnedState !== state) {\n res.writeHead(400)\n res.end('Invalid state parameter')\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('Invalid state parameter'), // Possible CSRF attack\n )\n }\n return\n }\n\n res.writeHead(302, {\n Location: OAUTH_CONFIG.SUCCESS_URL,\n })\n res.end()\n\n \n\n this.processCallback({\n authorizationCode,\n state,\n useManualRedirect: false,\n })\n } else {\n res.writeHead(404)\n res.end()\n }\n },\n )\n\n this.server.listen(OAUTH_CONFIG.REDIRECT_PORT, async () => {\n onReady?.()\n })\n\n this.server.on('error', (err: Error) => {\n const portError = err as NodeJS.ErrnoException\n if (portError.code === 'EADDRINUSE') {\n const error = new Error(\n `Port ${OAUTH_CONFIG.REDIRECT_PORT} is already in use. Please ensure no other applications are using this port.`,\n )\n logError(error)\n this.closeServer()\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(error)\n }\n return\n } else {\n logError(err)\n this.closeServer()\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(err)\n }\n return\n }\n })\n }\n\n private async exchangeCodeForTokens(\n authorizationCode: string,\n state: string,\n useManualRedirect: boolean = false,\n ): Promise<OAuthTokenExchangeResponse> {\n const requestBody = {\n grant_type: 'authorization_code',\n code: authorizationCode,\n redirect_uri: useManualRedirect\n ? OAUTH_CONFIG.MANUAL_REDIRECT_URL\n : `http://localhost:${OAUTH_CONFIG.REDIRECT_PORT}/callback`,\n client_id: OAUTH_CONFIG.CLIENT_ID,\n code_verifier: this.codeVerifier,\n state,\n }\n\n const response = await fetch(OAUTH_CONFIG.TOKEN_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n })\n\n if (!response.ok) {\n throw new Error(`Token exchange failed: ${response.statusText}`)\n }\n\n const data = await response.json()\n return data\n }\n\n processCallback({\n authorizationCode,\n state,\n useManualRedirect,\n }: {\n authorizationCode: string\n state: string\n useManualRedirect: boolean\n }): void {\n this.closeServer()\n\n if (state !== this.expectedState) {\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('Invalid state parameter'), // Possible CSRF attack\n )\n this.pendingCodePromise = null\n }\n return\n }\n\n if (this.pendingCodePromise) {\n this.pendingCodePromise.resolve({ authorizationCode, useManualRedirect })\n this.pendingCodePromise = null\n }\n }\n\n private closeServer(): void {\n if (this.server) {\n this.server.close()\n this.server = null\n }\n }\n}\n\nexport async function createAndStoreApiKey(\n accessToken: string,\n): Promise<string | null> {\n try {\n // Call create_api_key endpoint\n const createApiKeyResp = await fetch(OAUTH_CONFIG.API_KEY_URL, {\n method: 'POST',\n headers: { Authorization: `Bearer ${accessToken}` },\n })\n\n let apiKeyData\n let errorText = ''\n\n try {\n apiKeyData = await createApiKeyResp.json()\n } catch (_e) {\n // If response is not valid JSON, get as text for error logging\n errorText = await createApiKeyResp.text()\n }\n\n \n\n if (createApiKeyResp.ok && apiKeyData && apiKeyData.raw_key) {\n const apiKey = apiKeyData.raw_key\n\n // Store in global config\n const config = getGlobalConfig()\n\n // Note: API key is now managed per model profile\n\n // Add to approved list\n if (!config.customApiKeyResponses) {\n config.customApiKeyResponses = { approved: [], rejected: [] }\n }\n if (!config.customApiKeyResponses.approved) {\n config.customApiKeyResponses.approved = []\n }\n\n const normalizedKey = normalizeApiKeyForConfig(apiKey)\n if (!config.customApiKeyResponses.approved.includes(normalizedKey)) {\n config.customApiKeyResponses.approved.push(normalizedKey)\n }\n\n // Save config\n saveGlobalConfig(config)\n\n // Reset the Anthropic client to force creation with new API key\n resetAnthropicClient()\n\n return apiKey\n }\n\n return null\n } catch (error) {\n \n throw error\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as crypto from 'crypto'\nimport * as http from 'http'\nimport { IncomingMessage, ServerResponse } from 'http'\nimport * as url from 'url'\n\nimport { OAUTH_CONFIG } from '@constants/oauth'\nimport { openBrowser } from '@utils/browser'\nimport { logError } from '@utils/log'\nimport { resetAnthropicClient } from './claude'\nimport {\n AccountInfo,\n getGlobalConfig,\n saveGlobalConfig,\n normalizeApiKeyForConfig,\n} from '@utils/config'\n\n// Base64URL encoding function (RFC 4648)\nfunction base64URLEncode(buffer: Buffer): string {\n return buffer\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n}\n\nfunction generateCodeVerifier(): string {\n return base64URLEncode(crypto.randomBytes(32))\n}\n\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder()\n const data = encoder.encode(verifier)\n const digest = await crypto.subtle.digest('SHA-256', data)\n return base64URLEncode(Buffer.from(digest))\n}\n\ntype OAuthTokenExchangeResponse = {\n access_token: string\n account?: {\n uuid: string\n email_address: string\n }\n organization?: {\n uuid: string\n name: string\n }\n}\n\nexport type OAuthResult = {\n accessToken: string\n}\n\nexport class OAuthService {\n private server: http.Server | null = null\n private codeVerifier: string\n private expectedState: string | null = null\n private pendingCodePromise: {\n resolve: (result: {\n authorizationCode: string\n useManualRedirect: boolean\n }) => void\n reject: (err: Error) => void\n } | null = null\n\n constructor() {\n this.codeVerifier = generateCodeVerifier()\n }\n\n private generateAuthUrls(\n codeChallenge: string,\n state: string,\n ): { autoUrl: string; manualUrl: string } {\n function makeUrl(isManual: boolean): string {\n const authUrl = new URL(OAUTH_CONFIG.AUTHORIZE_URL)\n authUrl.searchParams.append('client_id', OAUTH_CONFIG.CLIENT_ID)\n authUrl.searchParams.append('response_type', 'code')\n authUrl.searchParams.append(\n 'redirect_uri',\n isManual\n ? OAUTH_CONFIG.MANUAL_REDIRECT_URL\n : `http://localhost:${OAUTH_CONFIG.REDIRECT_PORT}/callback`,\n )\n authUrl.searchParams.append('scope', OAUTH_CONFIG.SCOPES.join(' '))\n authUrl.searchParams.append('code_challenge', codeChallenge)\n authUrl.searchParams.append('code_challenge_method', 'S256')\n authUrl.searchParams.append('state', state)\n return authUrl.toString()\n }\n\n return {\n autoUrl: makeUrl(false),\n manualUrl: makeUrl(true),\n }\n }\n\n async startOAuthFlow(\n authURLHandler: (url: string) => Promise<void>,\n ): Promise<OAuthResult> {\n const codeChallenge = await generateCodeChallenge(this.codeVerifier)\n const state = base64URLEncode(crypto.randomBytes(32))\n this.expectedState = state\n const { autoUrl, manualUrl } = this.generateAuthUrls(codeChallenge, state)\n\n const onReady = async () => {\n await authURLHandler(manualUrl)\n await openBrowser(autoUrl)\n }\n\n const { authorizationCode, useManualRedirect } = await new Promise<{\n authorizationCode: string\n useManualRedirect: boolean\n }>((resolve, reject) => {\n this.pendingCodePromise = { resolve, reject }\n this.startLocalServer(state, onReady)\n })\n\n // Exchange code for tokens\n const {\n access_token: accessToken,\n account,\n organization,\n } = await this.exchangeCodeForTokens(\n authorizationCode,\n state,\n useManualRedirect,\n )\n\n // Store account info\n if (account) {\n const accountInfo: AccountInfo = {\n accountUuid: account.uuid,\n emailAddress: account.email_address,\n organizationUuid: organization?.uuid,\n }\n const config = getGlobalConfig()\n config.oauthAccount = accountInfo\n saveGlobalConfig(config)\n }\n\n return { accessToken }\n }\n\n private startLocalServer(state: string, onReady?: () => void): void {\n if (this.server) {\n this.closeServer()\n }\n this.server = http.createServer(\n (req: IncomingMessage, res: ServerResponse) => {\n const parsedUrl = url.parse(req.url || '', true)\n\n if (parsedUrl.pathname === '/callback') {\n const authorizationCode = parsedUrl.query.code as string\n const returnedState = parsedUrl.query.state as string\n\n if (!authorizationCode) {\n res.writeHead(400)\n res.end('Authorization code not found')\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('No authorization code received'),\n )\n }\n return\n }\n\n if (returnedState !== state) {\n res.writeHead(400)\n res.end('Invalid state parameter')\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('Invalid state parameter'), // Possible CSRF attack\n )\n }\n return\n }\n\n res.writeHead(302, {\n Location: OAUTH_CONFIG.SUCCESS_URL,\n })\n res.end()\n\n this.processCallback({\n authorizationCode,\n state,\n useManualRedirect: false,\n })\n } else {\n res.writeHead(404)\n res.end()\n }\n },\n )\n\n this.server.listen(OAUTH_CONFIG.REDIRECT_PORT, async () => {\n onReady?.()\n })\n\n this.server.on('error', (err: Error) => {\n const portError = err as NodeJS.ErrnoException\n if (portError.code === 'EADDRINUSE') {\n const error = new Error(\n `Port ${OAUTH_CONFIG.REDIRECT_PORT} is already in use. Please ensure no other applications are using this port.`,\n )\n logError(error)\n this.closeServer()\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(error)\n }\n return\n } else {\n logError(err)\n this.closeServer()\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(err)\n }\n return\n }\n })\n }\n\n private async exchangeCodeForTokens(\n authorizationCode: string,\n state: string,\n useManualRedirect: boolean = false,\n ): Promise<OAuthTokenExchangeResponse> {\n const requestBody = {\n grant_type: 'authorization_code',\n code: authorizationCode,\n redirect_uri: useManualRedirect\n ? OAUTH_CONFIG.MANUAL_REDIRECT_URL\n : `http://localhost:${OAUTH_CONFIG.REDIRECT_PORT}/callback`,\n client_id: OAUTH_CONFIG.CLIENT_ID,\n code_verifier: this.codeVerifier,\n state,\n }\n\n const response = await fetch(OAUTH_CONFIG.TOKEN_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n })\n\n if (!response.ok) {\n throw new Error(`Token exchange failed: ${response.statusText}`)\n }\n\n const data = await response.json()\n return data\n }\n\n processCallback({\n authorizationCode,\n state,\n useManualRedirect,\n }: {\n authorizationCode: string\n state: string\n useManualRedirect: boolean\n }): void {\n this.closeServer()\n\n if (state !== this.expectedState) {\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('Invalid state parameter'), // Possible CSRF attack\n )\n this.pendingCodePromise = null\n }\n return\n }\n\n if (this.pendingCodePromise) {\n this.pendingCodePromise.resolve({ authorizationCode, useManualRedirect })\n this.pendingCodePromise = null\n }\n }\n\n private closeServer(): void {\n if (this.server) {\n this.server.close()\n this.server = null\n }\n }\n}\n\nexport async function createAndStoreApiKey(\n accessToken: string,\n): Promise<string | null> {\n try {\n // Call create_api_key endpoint\n const createApiKeyResp = await fetch(OAUTH_CONFIG.API_KEY_URL, {\n method: 'POST',\n headers: { Authorization: `Bearer ${accessToken}` },\n })\n\n let apiKeyData\n let errorText = ''\n\n try {\n apiKeyData = await createApiKeyResp.json()\n } catch (_e) {\n // If response is not valid JSON, get as text for error logging\n errorText = await createApiKeyResp.text()\n }\n\n if (createApiKeyResp.ok && apiKeyData && apiKeyData.raw_key) {\n const apiKey = apiKeyData.raw_key\n\n // Store in global config\n const config = getGlobalConfig()\n\n // Note: API key is now managed per model profile\n\n // Add to approved list\n if (!config.customApiKeyResponses) {\n config.customApiKeyResponses = { approved: [], rejected: [] }\n }\n if (!config.customApiKeyResponses.approved) {\n config.customApiKeyResponses.approved = []\n }\n\n const normalizedKey = normalizeApiKeyForConfig(apiKey)\n if (!config.customApiKeyResponses.approved.includes(normalizedKey)) {\n config.customApiKeyResponses.approved.push(normalizedKey)\n }\n\n // Save config\n saveGlobalConfig(config)\n\n // Reset the Anthropic client to force creation with new API key\n resetAnthropicClient()\n\n return apiKey\n }\n\n return null\n } catch (error) {\n throw error\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }