@xortex/xcode 3.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 (934) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +171 -0
  3. package/bin/xcode +127 -0
  4. package/bin/xcode-test +84 -0
  5. package/bin/xcode.cmd +31 -0
  6. package/constants/apiLimits.ts +94 -0
  7. package/constants/betas.ts +52 -0
  8. package/constants/common.ts +33 -0
  9. package/constants/cyberRiskInstruction.ts +24 -0
  10. package/constants/errorIds.ts +15 -0
  11. package/constants/figures.ts +45 -0
  12. package/constants/files.ts +156 -0
  13. package/constants/github-app.ts +144 -0
  14. package/constants/keys.ts +11 -0
  15. package/constants/messages.ts +1 -0
  16. package/constants/oauth.ts +234 -0
  17. package/constants/outputStyles.ts +216 -0
  18. package/constants/product.ts +76 -0
  19. package/constants/prompts.ts +939 -0
  20. package/constants/spinnerVerbs.ts +204 -0
  21. package/constants/system.ts +95 -0
  22. package/constants/systemPromptSections.ts +68 -0
  23. package/constants/toolLimits.ts +56 -0
  24. package/constants/tools.ts +112 -0
  25. package/constants/turnCompletionVerbs.ts +12 -0
  26. package/constants/xml.ts +86 -0
  27. package/entrypoints/agentSdkTypes.ts +443 -0
  28. package/entrypoints/cli.tsx +307 -0
  29. package/entrypoints/init.ts +340 -0
  30. package/entrypoints/mcp.ts +196 -0
  31. package/entrypoints/sandboxTypes.ts +156 -0
  32. package/entrypoints/sdk/controlSchemas.ts +663 -0
  33. package/entrypoints/sdk/coreSchemas.ts +1889 -0
  34. package/entrypoints/sdk/coreTypes.generated.ts +2 -0
  35. package/entrypoints/sdk/coreTypes.ts +62 -0
  36. package/entrypoints/sdk/runtimeTypes.ts +140 -0
  37. package/entrypoints/sdk/sdkUtilityTypes.ts +3 -0
  38. package/entrypoints/sdk/toolTypes.ts +90 -0
  39. package/main.tsx +4686 -0
  40. package/package.json +120 -0
  41. package/services/AgentSummary/agentSummary.ts +179 -0
  42. package/services/MagicDocs/magicDocs.ts +254 -0
  43. package/services/MagicDocs/prompts.ts +127 -0
  44. package/services/PromptSuggestion/promptSuggestion.ts +523 -0
  45. package/services/PromptSuggestion/speculation.ts +991 -0
  46. package/services/SessionMemory/prompts.ts +324 -0
  47. package/services/SessionMemory/sessionMemory.ts +495 -0
  48. package/services/SessionMemory/sessionMemoryUtils.ts +207 -0
  49. package/services/analytics/config.ts +38 -0
  50. package/services/analytics/datadog.ts +307 -0
  51. package/services/analytics/firstPartyEventLogger.ts +449 -0
  52. package/services/analytics/firstPartyEventLoggingExporter.ts +806 -0
  53. package/services/analytics/growthbook.ts +1155 -0
  54. package/services/analytics/index.ts +173 -0
  55. package/services/analytics/metadata.ts +973 -0
  56. package/services/analytics/sink.ts +114 -0
  57. package/services/analytics/sinkKillswitch.ts +25 -0
  58. package/services/api/adminRequests.ts +119 -0
  59. package/services/api/bootstrap.ts +141 -0
  60. package/services/api/claude.ts +3422 -0
  61. package/services/api/client.ts +406 -0
  62. package/services/api/dumpPrompts.ts +226 -0
  63. package/services/api/emptyUsage.ts +22 -0
  64. package/services/api/errorUtils.ts +260 -0
  65. package/services/api/errors.ts +1207 -0
  66. package/services/api/filesApi.ts +748 -0
  67. package/services/api/firstTokenDate.ts +60 -0
  68. package/services/api/gemini.ts +359 -0
  69. package/services/api/geminiAdapter.ts +123 -0
  70. package/services/api/geminiClient.ts +291 -0
  71. package/services/api/grove.ts +357 -0
  72. package/services/api/logging.ts +788 -0
  73. package/services/api/metricsOptOut.ts +159 -0
  74. package/services/api/openRouterClient.ts +453 -0
  75. package/services/api/overageCreditGrant.ts +137 -0
  76. package/services/api/promptCacheBreakDetection.ts +727 -0
  77. package/services/api/referral.ts +281 -0
  78. package/services/api/sessionIngress.ts +514 -0
  79. package/services/api/ultrareviewQuota.ts +38 -0
  80. package/services/api/usage.ts +63 -0
  81. package/services/api/withRetry.ts +822 -0
  82. package/services/autoDream/autoDream.ts +324 -0
  83. package/services/autoDream/config.ts +21 -0
  84. package/services/autoDream/consolidationLock.ts +140 -0
  85. package/services/autoDream/consolidationPrompt.ts +65 -0
  86. package/services/awaySummary.ts +74 -0
  87. package/services/claudeAiLimits.ts +515 -0
  88. package/services/claudeAiLimitsHook.ts +23 -0
  89. package/services/compact/apiMicrocompact.ts +153 -0
  90. package/services/compact/autoCompact.ts +351 -0
  91. package/services/compact/compact.ts +1705 -0
  92. package/services/compact/compactWarningHook.ts +16 -0
  93. package/services/compact/compactWarningState.ts +18 -0
  94. package/services/compact/grouping.ts +63 -0
  95. package/services/compact/microCompact.ts +530 -0
  96. package/services/compact/postCompactCleanup.ts +77 -0
  97. package/services/compact/prompt.ts +374 -0
  98. package/services/compact/sessionMemoryCompact.ts +630 -0
  99. package/services/compact/timeBasedMCConfig.ts +43 -0
  100. package/services/diagnosticTracking.ts +397 -0
  101. package/services/extractMemories/extractMemories.ts +517 -0
  102. package/services/extractMemories/prompts.ts +154 -0
  103. package/services/internalLogging.ts +90 -0
  104. package/services/lsp/LSPClient.ts +447 -0
  105. package/services/lsp/LSPDiagnosticRegistry.ts +386 -0
  106. package/services/lsp/LSPServerInstance.ts +511 -0
  107. package/services/lsp/LSPServerManager.ts +420 -0
  108. package/services/lsp/config.ts +79 -0
  109. package/services/lsp/manager.ts +289 -0
  110. package/services/lsp/passiveFeedback.ts +328 -0
  111. package/services/mcp/InProcessTransport.ts +63 -0
  112. package/services/mcp/MCPConnectionManager.tsx +73 -0
  113. package/services/mcp/SdkControlTransport.ts +136 -0
  114. package/services/mcp/auth.ts +2465 -0
  115. package/services/mcp/channelAllowlist.ts +76 -0
  116. package/services/mcp/channelNotification.ts +316 -0
  117. package/services/mcp/channelPermissions.ts +240 -0
  118. package/services/mcp/claudeai.ts +164 -0
  119. package/services/mcp/client.ts +3348 -0
  120. package/services/mcp/config.ts +1578 -0
  121. package/services/mcp/elicitationHandler.ts +313 -0
  122. package/services/mcp/envExpansion.ts +38 -0
  123. package/services/mcp/headersHelper.ts +138 -0
  124. package/services/mcp/mcpStringUtils.ts +106 -0
  125. package/services/mcp/normalization.ts +23 -0
  126. package/services/mcp/oauthPort.ts +78 -0
  127. package/services/mcp/officialRegistry.ts +72 -0
  128. package/services/mcp/types.ts +258 -0
  129. package/services/mcp/useManageMCPConnections.ts +1141 -0
  130. package/services/mcp/utils.ts +575 -0
  131. package/services/mcp/vscodeSdkMcp.ts +112 -0
  132. package/services/mcp/xaa.ts +511 -0
  133. package/services/mcp/xaaIdpLogin.ts +487 -0
  134. package/services/mcpServerApproval.tsx +41 -0
  135. package/services/mockRateLimits.ts +882 -0
  136. package/services/notifier.ts +156 -0
  137. package/services/oauth/auth-code-listener.ts +211 -0
  138. package/services/oauth/client.ts +566 -0
  139. package/services/oauth/crypto.ts +23 -0
  140. package/services/oauth/getOauthProfile.ts +53 -0
  141. package/services/oauth/index.ts +198 -0
  142. package/services/plugins/PluginInstallationManager.ts +184 -0
  143. package/services/plugins/pluginCliCommands.ts +344 -0
  144. package/services/plugins/pluginOperations.ts +1088 -0
  145. package/services/policyLimits/index.ts +663 -0
  146. package/services/policyLimits/types.ts +27 -0
  147. package/services/preventSleep.ts +165 -0
  148. package/services/rateLimitMessages.ts +344 -0
  149. package/services/rateLimitMocking.ts +144 -0
  150. package/services/remoteManagedSettings/index.ts +638 -0
  151. package/services/remoteManagedSettings/securityCheck.tsx +74 -0
  152. package/services/remoteManagedSettings/syncCache.ts +112 -0
  153. package/services/remoteManagedSettings/syncCacheState.ts +96 -0
  154. package/services/remoteManagedSettings/types.ts +31 -0
  155. package/services/settingsSync/index.ts +581 -0
  156. package/services/settingsSync/types.ts +67 -0
  157. package/services/teamMemorySync/index.ts +1256 -0
  158. package/services/teamMemorySync/secretScanner.ts +324 -0
  159. package/services/teamMemorySync/teamMemSecretGuard.ts +44 -0
  160. package/services/teamMemorySync/types.ts +156 -0
  161. package/services/teamMemorySync/watcher.ts +387 -0
  162. package/services/tips/tipHistory.ts +17 -0
  163. package/services/tips/tipRegistry.ts +686 -0
  164. package/services/tips/tipScheduler.ts +58 -0
  165. package/services/tokenEstimation.ts +495 -0
  166. package/services/toolUseSummary/toolUseSummaryGenerator.ts +112 -0
  167. package/services/tools/StreamingToolExecutor.ts +530 -0
  168. package/services/tools/toolExecution.ts +1745 -0
  169. package/services/tools/toolHooks.ts +650 -0
  170. package/services/tools/toolOrchestration.ts +188 -0
  171. package/services/vcr.ts +406 -0
  172. package/services/voice.ts +525 -0
  173. package/services/voiceKeyterms.ts +106 -0
  174. package/services/voiceStreamSTT.ts +544 -0
  175. package/tools/AgentTool/AgentTool.tsx +1398 -0
  176. package/tools/AgentTool/UI.tsx +872 -0
  177. package/tools/AgentTool/agentColorManager.ts +66 -0
  178. package/tools/AgentTool/agentDisplay.ts +104 -0
  179. package/tools/AgentTool/agentMemory.ts +177 -0
  180. package/tools/AgentTool/agentMemorySnapshot.ts +197 -0
  181. package/tools/AgentTool/agentToolUtils.ts +686 -0
  182. package/tools/AgentTool/built-in/claudeCodeGuideAgent.ts +205 -0
  183. package/tools/AgentTool/built-in/exploreAgent.ts +83 -0
  184. package/tools/AgentTool/built-in/generalPurposeAgent.ts +34 -0
  185. package/tools/AgentTool/built-in/planAgent.ts +92 -0
  186. package/tools/AgentTool/built-in/statuslineSetup.ts +144 -0
  187. package/tools/AgentTool/built-in/verificationAgent.ts +152 -0
  188. package/tools/AgentTool/builtInAgents.ts +72 -0
  189. package/tools/AgentTool/constants.ts +12 -0
  190. package/tools/AgentTool/forkSubagent.ts +210 -0
  191. package/tools/AgentTool/loadAgentsDir.ts +755 -0
  192. package/tools/AgentTool/prompt.ts +287 -0
  193. package/tools/AgentTool/resumeAgent.ts +265 -0
  194. package/tools/AgentTool/runAgent.ts +973 -0
  195. package/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +266 -0
  196. package/tools/AskUserQuestionTool/prompt.ts +44 -0
  197. package/tools/BashTool/BashTool.tsx +1144 -0
  198. package/tools/BashTool/BashToolResultMessage.tsx +191 -0
  199. package/tools/BashTool/UI.tsx +185 -0
  200. package/tools/BashTool/bashCommandHelpers.ts +265 -0
  201. package/tools/BashTool/bashPermissions.ts +2621 -0
  202. package/tools/BashTool/bashSecurity.ts +2592 -0
  203. package/tools/BashTool/commandSemantics.ts +140 -0
  204. package/tools/BashTool/commentLabel.ts +13 -0
  205. package/tools/BashTool/destructiveCommandWarning.ts +102 -0
  206. package/tools/BashTool/modeValidation.ts +115 -0
  207. package/tools/BashTool/pathValidation.ts +1303 -0
  208. package/tools/BashTool/prompt.ts +369 -0
  209. package/tools/BashTool/readOnlyValidation.ts +1990 -0
  210. package/tools/BashTool/sedEditParser.ts +322 -0
  211. package/tools/BashTool/sedValidation.ts +684 -0
  212. package/tools/BashTool/shouldUseSandbox.ts +153 -0
  213. package/tools/BashTool/toolName.ts +2 -0
  214. package/tools/BashTool/utils.ts +223 -0
  215. package/tools/BriefTool/BriefTool.ts +204 -0
  216. package/tools/BriefTool/UI.tsx +101 -0
  217. package/tools/BriefTool/attachments.ts +110 -0
  218. package/tools/BriefTool/prompt.ts +22 -0
  219. package/tools/BriefTool/upload.ts +174 -0
  220. package/tools/ConfigTool/ConfigTool.ts +467 -0
  221. package/tools/ConfigTool/UI.tsx +38 -0
  222. package/tools/ConfigTool/constants.ts +1 -0
  223. package/tools/ConfigTool/prompt.ts +93 -0
  224. package/tools/ConfigTool/supportedSettings.ts +211 -0
  225. package/tools/EnterPlanModeTool/EnterPlanModeTool.ts +126 -0
  226. package/tools/EnterPlanModeTool/UI.tsx +33 -0
  227. package/tools/EnterPlanModeTool/constants.ts +1 -0
  228. package/tools/EnterPlanModeTool/prompt.ts +170 -0
  229. package/tools/EnterWorktreeTool/EnterWorktreeTool.ts +127 -0
  230. package/tools/EnterWorktreeTool/UI.tsx +20 -0
  231. package/tools/EnterWorktreeTool/constants.ts +1 -0
  232. package/tools/EnterWorktreeTool/prompt.ts +30 -0
  233. package/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts +493 -0
  234. package/tools/ExitPlanModeTool/UI.tsx +82 -0
  235. package/tools/ExitPlanModeTool/constants.ts +2 -0
  236. package/tools/ExitPlanModeTool/prompt.ts +29 -0
  237. package/tools/ExitWorktreeTool/ExitWorktreeTool.ts +329 -0
  238. package/tools/ExitWorktreeTool/UI.tsx +25 -0
  239. package/tools/ExitWorktreeTool/constants.ts +1 -0
  240. package/tools/ExitWorktreeTool/prompt.ts +32 -0
  241. package/tools/FileEditTool/FileEditTool.ts +625 -0
  242. package/tools/FileEditTool/UI.tsx +289 -0
  243. package/tools/FileEditTool/constants.ts +11 -0
  244. package/tools/FileEditTool/prompt.ts +28 -0
  245. package/tools/FileEditTool/types.ts +85 -0
  246. package/tools/FileEditTool/utils.ts +775 -0
  247. package/tools/FileReadTool/FileReadTool.ts +1183 -0
  248. package/tools/FileReadTool/UI.tsx +185 -0
  249. package/tools/FileReadTool/imageProcessor.ts +94 -0
  250. package/tools/FileReadTool/limits.ts +92 -0
  251. package/tools/FileReadTool/prompt.ts +49 -0
  252. package/tools/FileWriteTool/FileWriteTool.ts +434 -0
  253. package/tools/FileWriteTool/UI.tsx +405 -0
  254. package/tools/FileWriteTool/prompt.ts +18 -0
  255. package/tools/GlobTool/GlobTool.ts +198 -0
  256. package/tools/GlobTool/UI.tsx +63 -0
  257. package/tools/GlobTool/prompt.ts +7 -0
  258. package/tools/GrepTool/GrepTool.ts +577 -0
  259. package/tools/GrepTool/UI.tsx +201 -0
  260. package/tools/GrepTool/prompt.ts +18 -0
  261. package/tools/LSPTool/LSPTool.ts +860 -0
  262. package/tools/LSPTool/UI.tsx +228 -0
  263. package/tools/LSPTool/formatters.ts +592 -0
  264. package/tools/LSPTool/prompt.ts +21 -0
  265. package/tools/LSPTool/schemas.ts +215 -0
  266. package/tools/LSPTool/symbolContext.ts +90 -0
  267. package/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +123 -0
  268. package/tools/ListMcpResourcesTool/UI.tsx +29 -0
  269. package/tools/ListMcpResourcesTool/prompt.ts +20 -0
  270. package/tools/MCPTool/MCPTool.ts +77 -0
  271. package/tools/MCPTool/UI.tsx +403 -0
  272. package/tools/MCPTool/classifyForCollapse.ts +604 -0
  273. package/tools/MCPTool/prompt.ts +3 -0
  274. package/tools/McpAuthTool/McpAuthTool.ts +215 -0
  275. package/tools/NotebookEditTool/NotebookEditTool.ts +490 -0
  276. package/tools/NotebookEditTool/UI.tsx +93 -0
  277. package/tools/NotebookEditTool/constants.ts +2 -0
  278. package/tools/NotebookEditTool/prompt.ts +3 -0
  279. package/tools/PowerShellTool/PowerShellTool.tsx +1001 -0
  280. package/tools/PowerShellTool/UI.tsx +131 -0
  281. package/tools/PowerShellTool/clmTypes.ts +211 -0
  282. package/tools/PowerShellTool/commandSemantics.ts +142 -0
  283. package/tools/PowerShellTool/commonParameters.ts +30 -0
  284. package/tools/PowerShellTool/destructiveCommandWarning.ts +109 -0
  285. package/tools/PowerShellTool/gitSafety.ts +176 -0
  286. package/tools/PowerShellTool/modeValidation.ts +404 -0
  287. package/tools/PowerShellTool/pathValidation.ts +2049 -0
  288. package/tools/PowerShellTool/powershellPermissions.ts +1648 -0
  289. package/tools/PowerShellTool/powershellSecurity.ts +1090 -0
  290. package/tools/PowerShellTool/prompt.ts +145 -0
  291. package/tools/PowerShellTool/readOnlyValidation.ts +1823 -0
  292. package/tools/PowerShellTool/toolName.ts +2 -0
  293. package/tools/REPLTool/constants.ts +46 -0
  294. package/tools/REPLTool/primitiveTools.ts +39 -0
  295. package/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +158 -0
  296. package/tools/ReadMcpResourceTool/UI.tsx +37 -0
  297. package/tools/ReadMcpResourceTool/prompt.ts +16 -0
  298. package/tools/RemoteTriggerTool/RemoteTriggerTool.ts +161 -0
  299. package/tools/RemoteTriggerTool/UI.tsx +17 -0
  300. package/tools/RemoteTriggerTool/prompt.ts +15 -0
  301. package/tools/ScheduleCronTool/CronCreateTool.ts +157 -0
  302. package/tools/ScheduleCronTool/CronDeleteTool.ts +95 -0
  303. package/tools/ScheduleCronTool/CronListTool.ts +97 -0
  304. package/tools/ScheduleCronTool/UI.tsx +60 -0
  305. package/tools/ScheduleCronTool/prompt.ts +135 -0
  306. package/tools/SendMessageTool/SendMessageTool.ts +917 -0
  307. package/tools/SendMessageTool/UI.tsx +31 -0
  308. package/tools/SendMessageTool/constants.ts +1 -0
  309. package/tools/SendMessageTool/prompt.ts +49 -0
  310. package/tools/SkillTool/SkillTool.ts +1108 -0
  311. package/tools/SkillTool/UI.tsx +128 -0
  312. package/tools/SkillTool/constants.ts +1 -0
  313. package/tools/SkillTool/prompt.ts +241 -0
  314. package/tools/SleepTool/prompt.ts +17 -0
  315. package/tools/SyntheticOutputTool/SyntheticOutputTool.ts +163 -0
  316. package/tools/TaskCreateTool/TaskCreateTool.ts +138 -0
  317. package/tools/TaskCreateTool/constants.ts +1 -0
  318. package/tools/TaskCreateTool/prompt.ts +56 -0
  319. package/tools/TaskGetTool/TaskGetTool.ts +128 -0
  320. package/tools/TaskGetTool/constants.ts +1 -0
  321. package/tools/TaskGetTool/prompt.ts +24 -0
  322. package/tools/TaskListTool/TaskListTool.ts +116 -0
  323. package/tools/TaskListTool/constants.ts +1 -0
  324. package/tools/TaskListTool/prompt.ts +49 -0
  325. package/tools/TaskOutputTool/TaskOutputTool.tsx +584 -0
  326. package/tools/TaskOutputTool/constants.ts +1 -0
  327. package/tools/TaskStopTool/TaskStopTool.ts +131 -0
  328. package/tools/TaskStopTool/UI.tsx +41 -0
  329. package/tools/TaskStopTool/prompt.ts +8 -0
  330. package/tools/TaskUpdateTool/TaskUpdateTool.ts +406 -0
  331. package/tools/TaskUpdateTool/constants.ts +1 -0
  332. package/tools/TaskUpdateTool/prompt.ts +77 -0
  333. package/tools/TeamCreateTool/TeamCreateTool.ts +240 -0
  334. package/tools/TeamCreateTool/UI.tsx +6 -0
  335. package/tools/TeamCreateTool/constants.ts +1 -0
  336. package/tools/TeamCreateTool/prompt.ts +113 -0
  337. package/tools/TeamDeleteTool/TeamDeleteTool.ts +139 -0
  338. package/tools/TeamDeleteTool/UI.tsx +20 -0
  339. package/tools/TeamDeleteTool/constants.ts +1 -0
  340. package/tools/TeamDeleteTool/prompt.ts +16 -0
  341. package/tools/TodoWriteTool/TodoWriteTool.ts +115 -0
  342. package/tools/TodoWriteTool/constants.ts +1 -0
  343. package/tools/TodoWriteTool/prompt.ts +184 -0
  344. package/tools/ToolSearchTool/ToolSearchTool.ts +471 -0
  345. package/tools/ToolSearchTool/constants.ts +1 -0
  346. package/tools/ToolSearchTool/prompt.ts +121 -0
  347. package/tools/TungstenTool/TungstenTool.ts +4 -0
  348. package/tools/WebFetchTool/UI.tsx +72 -0
  349. package/tools/WebFetchTool/WebFetchTool.ts +318 -0
  350. package/tools/WebFetchTool/preapproved.ts +166 -0
  351. package/tools/WebFetchTool/prompt.ts +46 -0
  352. package/tools/WebFetchTool/utils.ts +530 -0
  353. package/tools/WebSearchTool/UI.tsx +101 -0
  354. package/tools/WebSearchTool/WebSearchTool.ts +435 -0
  355. package/tools/WebSearchTool/prompt.ts +34 -0
  356. package/tools/WorkflowTool/constants.ts +2 -0
  357. package/tools/XMemIngestTool/XMemIngestTool.ts +140 -0
  358. package/tools/XMemIngestTool/prompt.ts +13 -0
  359. package/tools/XMemRetrieveTool/XMemRetrieveTool.ts +177 -0
  360. package/tools/XMemRetrieveTool/prompt.ts +16 -0
  361. package/tools/XMemSearchTool/XMemSearchTool.ts +172 -0
  362. package/tools/XMemSearchTool/prompt.ts +11 -0
  363. package/tools/shared/gitOperationTracking.ts +277 -0
  364. package/tools/shared/spawnMultiAgent.ts +1093 -0
  365. package/tools/testing/TestingPermissionTool.tsx +74 -0
  366. package/tools/utils.ts +40 -0
  367. package/utils/CircularBuffer.ts +84 -0
  368. package/utils/Cursor.ts +1530 -0
  369. package/utils/QueryGuard.ts +121 -0
  370. package/utils/Shell.ts +474 -0
  371. package/utils/ShellCommand.ts +465 -0
  372. package/utils/abortController.ts +99 -0
  373. package/utils/activityManager.ts +164 -0
  374. package/utils/advisor.ts +145 -0
  375. package/utils/agentContext.ts +178 -0
  376. package/utils/agentId.ts +99 -0
  377. package/utils/agentSwarmsEnabled.ts +44 -0
  378. package/utils/agenticSessionSearch.ts +307 -0
  379. package/utils/analyzeContext.ts +1382 -0
  380. package/utils/ansiToPng.ts +334 -0
  381. package/utils/ansiToSvg.ts +272 -0
  382. package/utils/api.ts +718 -0
  383. package/utils/apiPreconnect.ts +71 -0
  384. package/utils/appleTerminalBackup.ts +124 -0
  385. package/utils/argumentSubstitution.ts +145 -0
  386. package/utils/array.ts +13 -0
  387. package/utils/asciicast.ts +239 -0
  388. package/utils/attachments.ts +4091 -0
  389. package/utils/attribution.ts +393 -0
  390. package/utils/auth.ts +2002 -0
  391. package/utils/authFileDescriptor.ts +196 -0
  392. package/utils/authPortable.ts +19 -0
  393. package/utils/autoModeDenials.ts +26 -0
  394. package/utils/autoRunIssue.tsx +122 -0
  395. package/utils/autoUpdater.ts +561 -0
  396. package/utils/aws.ts +74 -0
  397. package/utils/awsAuthStatusManager.ts +81 -0
  398. package/utils/axios.ts +8 -0
  399. package/utils/background/remote/preconditions.ts +235 -0
  400. package/utils/background/remote/remoteSession.ts +98 -0
  401. package/utils/backgroundHousekeeping.ts +94 -0
  402. package/utils/bash/ParsedCommand.ts +318 -0
  403. package/utils/bash/ShellSnapshot.ts +582 -0
  404. package/utils/bash/ast.ts +2679 -0
  405. package/utils/bash/bashParser.ts +4436 -0
  406. package/utils/bash/bashPipeCommand.ts +294 -0
  407. package/utils/bash/commands.ts +1339 -0
  408. package/utils/bash/heredoc.ts +733 -0
  409. package/utils/bash/parser.ts +230 -0
  410. package/utils/bash/prefix.ts +204 -0
  411. package/utils/bash/registry.ts +53 -0
  412. package/utils/bash/shellCompletion.ts +259 -0
  413. package/utils/bash/shellPrefix.ts +28 -0
  414. package/utils/bash/shellQuote.ts +304 -0
  415. package/utils/bash/shellQuoting.ts +128 -0
  416. package/utils/bash/specs/alias.ts +14 -0
  417. package/utils/bash/specs/index.ts +18 -0
  418. package/utils/bash/specs/nohup.ts +13 -0
  419. package/utils/bash/specs/pyright.ts +91 -0
  420. package/utils/bash/specs/sleep.ts +13 -0
  421. package/utils/bash/specs/srun.ts +31 -0
  422. package/utils/bash/specs/time.ts +13 -0
  423. package/utils/bash/specs/timeout.ts +20 -0
  424. package/utils/bash/treeSitterAnalysis.ts +506 -0
  425. package/utils/betas.ts +434 -0
  426. package/utils/billing.ts +78 -0
  427. package/utils/binaryCheck.ts +53 -0
  428. package/utils/browser.ts +68 -0
  429. package/utils/bufferedWriter.ts +100 -0
  430. package/utils/bundledMode.ts +22 -0
  431. package/utils/caCerts.ts +115 -0
  432. package/utils/caCertsConfig.ts +88 -0
  433. package/utils/cachePaths.ts +38 -0
  434. package/utils/classifierApprovals.ts +88 -0
  435. package/utils/classifierApprovalsHook.ts +17 -0
  436. package/utils/claudeCodeHints.ts +193 -0
  437. package/utils/claudeDesktop.ts +152 -0
  438. package/utils/claudeInChrome/chromeNativeHost.ts +527 -0
  439. package/utils/claudeInChrome/common.ts +540 -0
  440. package/utils/claudeInChrome/mcpServer.ts +292 -0
  441. package/utils/claudeInChrome/prompt.ts +83 -0
  442. package/utils/claudeInChrome/setup.ts +400 -0
  443. package/utils/claudeInChrome/setupPortable.ts +233 -0
  444. package/utils/claudeInChrome/toolRendering.tsx +262 -0
  445. package/utils/claudemd.ts +1479 -0
  446. package/utils/cleanup.ts +602 -0
  447. package/utils/cleanupRegistry.ts +25 -0
  448. package/utils/cliArgs.ts +60 -0
  449. package/utils/cliHighlight.ts +54 -0
  450. package/utils/codeIndexing.ts +206 -0
  451. package/utils/collapseBackgroundBashNotifications.ts +84 -0
  452. package/utils/collapseHookSummaries.ts +59 -0
  453. package/utils/collapseReadSearch.ts +1109 -0
  454. package/utils/collapseTeammateShutdowns.ts +55 -0
  455. package/utils/color-diff-mock.ts +27 -0
  456. package/utils/combinedAbortSignal.ts +47 -0
  457. package/utils/commandLifecycle.ts +21 -0
  458. package/utils/commitAttribution.ts +961 -0
  459. package/utils/completionCache.ts +166 -0
  460. package/utils/computerUse/appNames.ts +196 -0
  461. package/utils/computerUse/cleanup.ts +86 -0
  462. package/utils/computerUse/common.ts +61 -0
  463. package/utils/computerUse/computerUseLock.ts +215 -0
  464. package/utils/computerUse/drainRunLoop.ts +79 -0
  465. package/utils/computerUse/escHotkey.ts +54 -0
  466. package/utils/computerUse/executor.ts +658 -0
  467. package/utils/computerUse/gates.ts +72 -0
  468. package/utils/computerUse/hostAdapter.ts +69 -0
  469. package/utils/computerUse/inputLoader.ts +30 -0
  470. package/utils/computerUse/mcpServer.ts +106 -0
  471. package/utils/computerUse/setup.ts +53 -0
  472. package/utils/computerUse/swiftLoader.ts +23 -0
  473. package/utils/computerUse/toolRendering.tsx +125 -0
  474. package/utils/computerUse/wrapper.tsx +336 -0
  475. package/utils/concurrentSessions.ts +204 -0
  476. package/utils/config.ts +1817 -0
  477. package/utils/configConstants.ts +21 -0
  478. package/utils/contentArray.ts +51 -0
  479. package/utils/context.ts +221 -0
  480. package/utils/contextAnalysis.ts +272 -0
  481. package/utils/contextSuggestions.ts +235 -0
  482. package/utils/controlMessageCompat.ts +32 -0
  483. package/utils/conversationRecovery.ts +597 -0
  484. package/utils/cron.ts +308 -0
  485. package/utils/cronJitterConfig.ts +75 -0
  486. package/utils/cronScheduler.ts +565 -0
  487. package/utils/cronTasks.ts +458 -0
  488. package/utils/cronTasksLock.ts +195 -0
  489. package/utils/crossProjectResume.ts +75 -0
  490. package/utils/crypto.ts +13 -0
  491. package/utils/cwd.ts +32 -0
  492. package/utils/debug.ts +268 -0
  493. package/utils/debugFilter.ts +157 -0
  494. package/utils/deepLink/banner.ts +123 -0
  495. package/utils/deepLink/parseDeepLink.ts +170 -0
  496. package/utils/deepLink/protocolHandler.ts +136 -0
  497. package/utils/deepLink/registerProtocol.ts +348 -0
  498. package/utils/deepLink/terminalLauncher.ts +557 -0
  499. package/utils/deepLink/terminalPreference.ts +54 -0
  500. package/utils/desktopDeepLink.ts +236 -0
  501. package/utils/detectRepository.ts +178 -0
  502. package/utils/diagLogs.ts +94 -0
  503. package/utils/diff.ts +177 -0
  504. package/utils/directMemberMessage.ts +69 -0
  505. package/utils/displayTags.ts +51 -0
  506. package/utils/doctorContextWarnings.ts +265 -0
  507. package/utils/doctorDiagnostic.ts +625 -0
  508. package/utils/dxt/helpers.ts +88 -0
  509. package/utils/dxt/zip.ts +226 -0
  510. package/utils/earlyInput.ts +191 -0
  511. package/utils/editor.ts +183 -0
  512. package/utils/effort.ts +329 -0
  513. package/utils/embeddedTools.ts +29 -0
  514. package/utils/env.ts +347 -0
  515. package/utils/envDynamic.ts +151 -0
  516. package/utils/envUtils.ts +183 -0
  517. package/utils/envValidation.ts +38 -0
  518. package/utils/errorLogSink.ts +235 -0
  519. package/utils/errors.ts +238 -0
  520. package/utils/exampleCommands.ts +184 -0
  521. package/utils/execFileNoThrow.ts +150 -0
  522. package/utils/execFileNoThrowPortable.ts +89 -0
  523. package/utils/execSyncWrapper.ts +38 -0
  524. package/utils/exportRenderer.tsx +98 -0
  525. package/utils/extraUsage.ts +23 -0
  526. package/utils/fastMode.ts +532 -0
  527. package/utils/file.ts +584 -0
  528. package/utils/fileHistory.ts +1115 -0
  529. package/utils/fileOperationAnalytics.ts +71 -0
  530. package/utils/filePersistence/filePersistence.ts +287 -0
  531. package/utils/filePersistence/outputsScanner.ts +126 -0
  532. package/utils/fileRead.ts +102 -0
  533. package/utils/fileReadCache.ts +96 -0
  534. package/utils/fileStateCache.ts +142 -0
  535. package/utils/findExecutable.ts +17 -0
  536. package/utils/fingerprint.ts +76 -0
  537. package/utils/forkedAgent.ts +689 -0
  538. package/utils/format.ts +308 -0
  539. package/utils/formatBriefTimestamp.ts +81 -0
  540. package/utils/fpsTracker.ts +47 -0
  541. package/utils/frontmatterParser.ts +370 -0
  542. package/utils/fsOperations.ts +770 -0
  543. package/utils/fullscreen.ts +202 -0
  544. package/utils/generatedFiles.ts +136 -0
  545. package/utils/generators.ts +88 -0
  546. package/utils/genericProcessUtils.ts +184 -0
  547. package/utils/getWorktreePaths.ts +70 -0
  548. package/utils/getWorktreePathsPortable.ts +27 -0
  549. package/utils/ghPrStatus.ts +106 -0
  550. package/utils/git/gitConfigParser.ts +277 -0
  551. package/utils/git/gitFilesystem.ts +699 -0
  552. package/utils/git/gitignore.ts +99 -0
  553. package/utils/git.ts +926 -0
  554. package/utils/gitDiff.ts +532 -0
  555. package/utils/gitSettings.ts +18 -0
  556. package/utils/github/ghAuthStatus.ts +29 -0
  557. package/utils/githubRepoPathMapping.ts +162 -0
  558. package/utils/glob.ts +130 -0
  559. package/utils/gracefulShutdown.ts +529 -0
  560. package/utils/groupToolUses.ts +182 -0
  561. package/utils/handlePromptSubmit.ts +610 -0
  562. package/utils/hash.ts +46 -0
  563. package/utils/headlessProfiler.ts +178 -0
  564. package/utils/heapDumpService.ts +303 -0
  565. package/utils/heatmap.ts +198 -0
  566. package/utils/highlightMatch.tsx +28 -0
  567. package/utils/hooks/AsyncHookRegistry.ts +309 -0
  568. package/utils/hooks/apiQueryHookHelper.ts +141 -0
  569. package/utils/hooks/execAgentHook.ts +339 -0
  570. package/utils/hooks/execHttpHook.ts +242 -0
  571. package/utils/hooks/execPromptHook.ts +211 -0
  572. package/utils/hooks/fileChangedWatcher.ts +191 -0
  573. package/utils/hooks/hookEvents.ts +192 -0
  574. package/utils/hooks/hookHelpers.ts +83 -0
  575. package/utils/hooks/hooksConfigManager.ts +400 -0
  576. package/utils/hooks/hooksConfigSnapshot.ts +133 -0
  577. package/utils/hooks/hooksSettings.ts +271 -0
  578. package/utils/hooks/postSamplingHooks.ts +70 -0
  579. package/utils/hooks/registerFrontmatterHooks.ts +67 -0
  580. package/utils/hooks/registerSkillHooks.ts +64 -0
  581. package/utils/hooks/sessionHooks.ts +447 -0
  582. package/utils/hooks/skillImprovement.ts +267 -0
  583. package/utils/hooks/ssrfGuard.ts +294 -0
  584. package/utils/hooks.ts +5022 -0
  585. package/utils/horizontalScroll.ts +137 -0
  586. package/utils/http.ts +136 -0
  587. package/utils/hyperlink.ts +39 -0
  588. package/utils/iTermBackup.ts +73 -0
  589. package/utils/ide.ts +1494 -0
  590. package/utils/idePathConversion.ts +90 -0
  591. package/utils/idleTimeout.ts +53 -0
  592. package/utils/imagePaste.ts +416 -0
  593. package/utils/imageResizer.ts +880 -0
  594. package/utils/imageStore.ts +167 -0
  595. package/utils/imageValidation.ts +104 -0
  596. package/utils/immediateCommand.ts +15 -0
  597. package/utils/inProcessTeammateHelpers.ts +102 -0
  598. package/utils/ink.ts +26 -0
  599. package/utils/intl.ts +94 -0
  600. package/utils/jetbrains.ts +191 -0
  601. package/utils/json.ts +277 -0
  602. package/utils/jsonRead.ts +16 -0
  603. package/utils/keyboardShortcuts.ts +14 -0
  604. package/utils/lazySchema.ts +8 -0
  605. package/utils/listSessionsImpl.ts +454 -0
  606. package/utils/localInstaller.ts +162 -0
  607. package/utils/lockfile.ts +43 -0
  608. package/utils/log.ts +362 -0
  609. package/utils/logoV2Utils.ts +347 -0
  610. package/utils/mailbox.ts +73 -0
  611. package/utils/managedEnv.ts +199 -0
  612. package/utils/managedEnvConstants.ts +191 -0
  613. package/utils/markdown.ts +381 -0
  614. package/utils/markdownConfigLoader.ts +600 -0
  615. package/utils/mcp/dateTimeParser.ts +121 -0
  616. package/utils/mcp/elicitationValidation.ts +336 -0
  617. package/utils/mcpInstructionsDelta.ts +130 -0
  618. package/utils/mcpOutputStorage.ts +189 -0
  619. package/utils/mcpValidation.ts +208 -0
  620. package/utils/mcpWebSocketTransport.ts +200 -0
  621. package/utils/memoize.ts +269 -0
  622. package/utils/memory/types.ts +12 -0
  623. package/utils/memory/versions.ts +8 -0
  624. package/utils/memoryFileDetection.ts +289 -0
  625. package/utils/messagePredicates.ts +8 -0
  626. package/utils/messageQueueManager.ts +547 -0
  627. package/utils/messages/mappers.ts +290 -0
  628. package/utils/messages/systemInit.ts +96 -0
  629. package/utils/messages.ts +5520 -0
  630. package/utils/model/agent.ts +157 -0
  631. package/utils/model/aliases.ts +35 -0
  632. package/utils/model/antModels.ts +64 -0
  633. package/utils/model/bedrock.ts +265 -0
  634. package/utils/model/check1mAccess.ts +72 -0
  635. package/utils/model/configs.ts +158 -0
  636. package/utils/model/contextWindowUpgradeCheck.ts +47 -0
  637. package/utils/model/deprecation.ts +101 -0
  638. package/utils/model/model.ts +654 -0
  639. package/utils/model/modelAllowlist.ts +170 -0
  640. package/utils/model/modelCapabilities.ts +118 -0
  641. package/utils/model/modelOptions.ts +589 -0
  642. package/utils/model/modelStrings.ts +170 -0
  643. package/utils/model/modelSupportOverrides.ts +50 -0
  644. package/utils/model/providers.ts +42 -0
  645. package/utils/model/validateModel.ts +159 -0
  646. package/utils/modelCost.ts +231 -0
  647. package/utils/modifiers.ts +36 -0
  648. package/utils/mtls.ts +179 -0
  649. package/utils/nativeInstaller/download.ts +523 -0
  650. package/utils/nativeInstaller/index.ts +18 -0
  651. package/utils/nativeInstaller/installer.ts +1708 -0
  652. package/utils/nativeInstaller/packageManagers.ts +336 -0
  653. package/utils/nativeInstaller/pidLock.ts +433 -0
  654. package/utils/notebook.ts +224 -0
  655. package/utils/objectGroupBy.ts +18 -0
  656. package/utils/pasteStore.ts +104 -0
  657. package/utils/path.ts +155 -0
  658. package/utils/pdf.ts +300 -0
  659. package/utils/pdfUtils.ts +70 -0
  660. package/utils/peerAddress.ts +21 -0
  661. package/utils/permissions/PermissionMode.ts +141 -0
  662. package/utils/permissions/PermissionPromptToolResultSchema.ts +127 -0
  663. package/utils/permissions/PermissionResult.ts +35 -0
  664. package/utils/permissions/PermissionRule.ts +40 -0
  665. package/utils/permissions/PermissionUpdate.ts +389 -0
  666. package/utils/permissions/PermissionUpdateSchema.ts +78 -0
  667. package/utils/permissions/autoModeState.ts +39 -0
  668. package/utils/permissions/bashClassifier.ts +61 -0
  669. package/utils/permissions/bypassPermissionsKillswitch.ts +155 -0
  670. package/utils/permissions/classifierDecision.ts +98 -0
  671. package/utils/permissions/classifierShared.ts +39 -0
  672. package/utils/permissions/dangerousPatterns.ts +80 -0
  673. package/utils/permissions/denialTracking.ts +45 -0
  674. package/utils/permissions/filesystem.ts +1777 -0
  675. package/utils/permissions/getNextPermissionMode.ts +101 -0
  676. package/utils/permissions/pathValidation.ts +485 -0
  677. package/utils/permissions/permissionExplainer.ts +250 -0
  678. package/utils/permissions/permissionRuleParser.ts +198 -0
  679. package/utils/permissions/permissionSetup.ts +1532 -0
  680. package/utils/permissions/permissions.ts +1486 -0
  681. package/utils/permissions/permissionsLoader.ts +296 -0
  682. package/utils/permissions/shadowedRuleDetection.ts +234 -0
  683. package/utils/permissions/shellRuleMatching.ts +228 -0
  684. package/utils/permissions/yoloClassifier.ts +1495 -0
  685. package/utils/planModeV2.ts +95 -0
  686. package/utils/plans.ts +397 -0
  687. package/utils/platform.ts +150 -0
  688. package/utils/plugins/addDirPluginSettings.ts +71 -0
  689. package/utils/plugins/cacheUtils.ts +196 -0
  690. package/utils/plugins/dependencyResolver.ts +305 -0
  691. package/utils/plugins/fetchTelemetry.ts +135 -0
  692. package/utils/plugins/gitAvailability.ts +69 -0
  693. package/utils/plugins/headlessPluginInstall.ts +174 -0
  694. package/utils/plugins/hintRecommendation.ts +164 -0
  695. package/utils/plugins/installCounts.ts +292 -0
  696. package/utils/plugins/installedPluginsManager.ts +1268 -0
  697. package/utils/plugins/loadPluginAgents.ts +348 -0
  698. package/utils/plugins/loadPluginCommands.ts +946 -0
  699. package/utils/plugins/loadPluginHooks.ts +287 -0
  700. package/utils/plugins/loadPluginOutputStyles.ts +178 -0
  701. package/utils/plugins/lspPluginIntegration.ts +387 -0
  702. package/utils/plugins/lspRecommendation.ts +374 -0
  703. package/utils/plugins/managedPlugins.ts +27 -0
  704. package/utils/plugins/marketplaceHelpers.ts +592 -0
  705. package/utils/plugins/marketplaceManager.ts +2643 -0
  706. package/utils/plugins/mcpPluginIntegration.ts +634 -0
  707. package/utils/plugins/mcpbHandler.ts +968 -0
  708. package/utils/plugins/officialMarketplace.ts +25 -0
  709. package/utils/plugins/officialMarketplaceGcs.ts +216 -0
  710. package/utils/plugins/officialMarketplaceStartupCheck.ts +439 -0
  711. package/utils/plugins/orphanedPluginFilter.ts +114 -0
  712. package/utils/plugins/parseMarketplaceInput.ts +162 -0
  713. package/utils/plugins/performStartupChecks.tsx +70 -0
  714. package/utils/plugins/pluginAutoupdate.ts +284 -0
  715. package/utils/plugins/pluginBlocklist.ts +127 -0
  716. package/utils/plugins/pluginDirectories.ts +178 -0
  717. package/utils/plugins/pluginFlagging.ts +208 -0
  718. package/utils/plugins/pluginIdentifier.ts +123 -0
  719. package/utils/plugins/pluginInstallationHelpers.ts +595 -0
  720. package/utils/plugins/pluginLoader.ts +3302 -0
  721. package/utils/plugins/pluginOptionsStorage.ts +400 -0
  722. package/utils/plugins/pluginPolicy.ts +20 -0
  723. package/utils/plugins/pluginStartupCheck.ts +341 -0
  724. package/utils/plugins/pluginVersioning.ts +157 -0
  725. package/utils/plugins/reconciler.ts +265 -0
  726. package/utils/plugins/refresh.ts +215 -0
  727. package/utils/plugins/schemas.ts +1681 -0
  728. package/utils/plugins/validatePlugin.ts +903 -0
  729. package/utils/plugins/walkPluginMarkdown.ts +69 -0
  730. package/utils/plugins/zipCache.ts +406 -0
  731. package/utils/plugins/zipCacheAdapters.ts +164 -0
  732. package/utils/powershell/dangerousCmdlets.ts +185 -0
  733. package/utils/powershell/parser.ts +1804 -0
  734. package/utils/powershell/staticPrefix.ts +316 -0
  735. package/utils/preflightChecks.tsx +151 -0
  736. package/utils/privacyLevel.ts +55 -0
  737. package/utils/process.ts +68 -0
  738. package/utils/processUserInput/processBashCommand.tsx +140 -0
  739. package/utils/processUserInput/processSlashCommand.tsx +922 -0
  740. package/utils/processUserInput/processTextPrompt.ts +100 -0
  741. package/utils/processUserInput/processUserInput.ts +605 -0
  742. package/utils/profilerBase.ts +46 -0
  743. package/utils/promptCategory.ts +49 -0
  744. package/utils/promptEditor.ts +188 -0
  745. package/utils/promptShellExecution.ts +183 -0
  746. package/utils/proxy.ts +426 -0
  747. package/utils/queryContext.ts +179 -0
  748. package/utils/queryHelpers.ts +552 -0
  749. package/utils/queryProfiler.ts +301 -0
  750. package/utils/queueProcessor.ts +95 -0
  751. package/utils/readEditContext.ts +227 -0
  752. package/utils/readFileInRange.ts +383 -0
  753. package/utils/releaseNotes.ts +360 -0
  754. package/utils/renderOptions.ts +113 -0
  755. package/utils/ripgrep.ts +679 -0
  756. package/utils/sandbox/sandbox-adapter.ts +985 -0
  757. package/utils/sandbox/sandbox-ui-utils.ts +12 -0
  758. package/utils/sanitization.ts +91 -0
  759. package/utils/screenshotClipboard.ts +121 -0
  760. package/utils/sdkEventQueue.ts +134 -0
  761. package/utils/secureStorage/fallbackStorage.ts +70 -0
  762. package/utils/secureStorage/index.ts +17 -0
  763. package/utils/secureStorage/keychainPrefetch.ts +116 -0
  764. package/utils/secureStorage/macOsKeychainHelpers.ts +111 -0
  765. package/utils/secureStorage/macOsKeychainStorage.ts +231 -0
  766. package/utils/secureStorage/plainTextStorage.ts +84 -0
  767. package/utils/semanticBoolean.ts +29 -0
  768. package/utils/semanticNumber.ts +36 -0
  769. package/utils/semver.ts +59 -0
  770. package/utils/sequential.ts +56 -0
  771. package/utils/sessionActivity.ts +133 -0
  772. package/utils/sessionEnvVars.ts +22 -0
  773. package/utils/sessionEnvironment.ts +166 -0
  774. package/utils/sessionFileAccessHooks.ts +250 -0
  775. package/utils/sessionIngressAuth.ts +140 -0
  776. package/utils/sessionRestore.ts +551 -0
  777. package/utils/sessionStart.ts +232 -0
  778. package/utils/sessionState.ts +150 -0
  779. package/utils/sessionStorage.ts +5105 -0
  780. package/utils/sessionStoragePortable.ts +793 -0
  781. package/utils/sessionTitle.ts +129 -0
  782. package/utils/sessionUrl.ts +64 -0
  783. package/utils/set.ts +53 -0
  784. package/utils/settings/allErrors.ts +32 -0
  785. package/utils/settings/applySettingsChange.ts +92 -0
  786. package/utils/settings/changeDetector.ts +488 -0
  787. package/utils/settings/constants.ts +202 -0
  788. package/utils/settings/internalWrites.ts +37 -0
  789. package/utils/settings/managedPath.ts +34 -0
  790. package/utils/settings/mdm/constants.ts +81 -0
  791. package/utils/settings/mdm/rawRead.ts +130 -0
  792. package/utils/settings/mdm/settings.ts +316 -0
  793. package/utils/settings/permissionValidation.ts +262 -0
  794. package/utils/settings/pluginOnlyPolicy.ts +60 -0
  795. package/utils/settings/schemaOutput.ts +8 -0
  796. package/utils/settings/settings.ts +1015 -0
  797. package/utils/settings/settingsCache.ts +80 -0
  798. package/utils/settings/toolValidationConfig.ts +103 -0
  799. package/utils/settings/types.ts +1149 -0
  800. package/utils/settings/validateEditTool.ts +45 -0
  801. package/utils/settings/validation.ts +265 -0
  802. package/utils/settings/validationTips.ts +164 -0
  803. package/utils/shell/bashProvider.ts +255 -0
  804. package/utils/shell/outputLimits.ts +14 -0
  805. package/utils/shell/powershellDetection.ts +107 -0
  806. package/utils/shell/powershellProvider.ts +123 -0
  807. package/utils/shell/prefix.ts +367 -0
  808. package/utils/shell/readOnlyCommandValidation.ts +1893 -0
  809. package/utils/shell/resolveDefaultShell.ts +14 -0
  810. package/utils/shell/shellProvider.ts +33 -0
  811. package/utils/shell/shellToolUtils.ts +22 -0
  812. package/utils/shell/specPrefix.ts +241 -0
  813. package/utils/shellConfig.ts +167 -0
  814. package/utils/sideQuery.ts +222 -0
  815. package/utils/sideQuestion.ts +155 -0
  816. package/utils/signal.ts +43 -0
  817. package/utils/sinks.ts +16 -0
  818. package/utils/skills/skillChangeDetector.ts +311 -0
  819. package/utils/slashCommandParsing.ts +60 -0
  820. package/utils/sleep.ts +84 -0
  821. package/utils/sliceAnsi.ts +91 -0
  822. package/utils/slowOperations.ts +286 -0
  823. package/utils/standaloneAgent.ts +23 -0
  824. package/utils/startupProfiler.ts +194 -0
  825. package/utils/staticRender.tsx +116 -0
  826. package/utils/stats.ts +1061 -0
  827. package/utils/statsCache.ts +434 -0
  828. package/utils/status.tsx +362 -0
  829. package/utils/statusNoticeDefinitions.tsx +198 -0
  830. package/utils/statusNoticeHelpers.ts +20 -0
  831. package/utils/stream.ts +76 -0
  832. package/utils/streamJsonStdoutGuard.ts +123 -0
  833. package/utils/streamlinedTransform.ts +201 -0
  834. package/utils/stringUtils.ts +235 -0
  835. package/utils/subprocessEnv.ts +99 -0
  836. package/utils/suggestions/commandSuggestions.ts +567 -0
  837. package/utils/suggestions/directoryCompletion.ts +263 -0
  838. package/utils/suggestions/shellHistoryCompletion.ts +119 -0
  839. package/utils/suggestions/skillUsageTracking.ts +55 -0
  840. package/utils/suggestions/slackChannelSuggestions.ts +209 -0
  841. package/utils/swarm/It2SetupPrompt.tsx +380 -0
  842. package/utils/swarm/backends/ITermBackend.ts +370 -0
  843. package/utils/swarm/backends/InProcessBackend.ts +339 -0
  844. package/utils/swarm/backends/PaneBackendExecutor.ts +354 -0
  845. package/utils/swarm/backends/TmuxBackend.ts +764 -0
  846. package/utils/swarm/backends/detection.ts +128 -0
  847. package/utils/swarm/backends/it2Setup.ts +245 -0
  848. package/utils/swarm/backends/registry.ts +464 -0
  849. package/utils/swarm/backends/teammateModeSnapshot.ts +87 -0
  850. package/utils/swarm/backends/types.ts +311 -0
  851. package/utils/swarm/constants.ts +33 -0
  852. package/utils/swarm/inProcessRunner.ts +1552 -0
  853. package/utils/swarm/leaderPermissionBridge.ts +54 -0
  854. package/utils/swarm/permissionSync.ts +928 -0
  855. package/utils/swarm/reconnection.ts +119 -0
  856. package/utils/swarm/spawnInProcess.ts +328 -0
  857. package/utils/swarm/spawnUtils.ts +146 -0
  858. package/utils/swarm/teamHelpers.ts +683 -0
  859. package/utils/swarm/teammateInit.ts +129 -0
  860. package/utils/swarm/teammateLayoutManager.ts +107 -0
  861. package/utils/swarm/teammateModel.ts +10 -0
  862. package/utils/swarm/teammatePromptAddendum.ts +18 -0
  863. package/utils/systemDirectories.ts +74 -0
  864. package/utils/systemPrompt.ts +123 -0
  865. package/utils/systemPromptType.ts +14 -0
  866. package/utils/systemTheme.ts +119 -0
  867. package/utils/taggedId.ts +54 -0
  868. package/utils/task/TaskOutput.ts +390 -0
  869. package/utils/task/diskOutput.ts +451 -0
  870. package/utils/task/framework.ts +308 -0
  871. package/utils/task/outputFormatting.ts +38 -0
  872. package/utils/task/sdkProgress.ts +36 -0
  873. package/utils/tasks.ts +862 -0
  874. package/utils/teamDiscovery.ts +81 -0
  875. package/utils/teamMemoryOps.ts +88 -0
  876. package/utils/teammate.ts +292 -0
  877. package/utils/teammateContext.ts +96 -0
  878. package/utils/teammateMailbox.ts +1183 -0
  879. package/utils/telemetry/betaSessionTracing.ts +491 -0
  880. package/utils/telemetry/bigqueryExporter.ts +252 -0
  881. package/utils/telemetry/events.ts +75 -0
  882. package/utils/telemetry/instrumentation.ts +825 -0
  883. package/utils/telemetry/logger.ts +26 -0
  884. package/utils/telemetry/perfettoTracing.ts +1120 -0
  885. package/utils/telemetry/pluginTelemetry.ts +289 -0
  886. package/utils/telemetry/sessionTracing.ts +927 -0
  887. package/utils/telemetry/skillLoadedEvent.ts +39 -0
  888. package/utils/telemetryAttributes.ts +71 -0
  889. package/utils/teleport/api.ts +466 -0
  890. package/utils/teleport/environmentSelection.ts +77 -0
  891. package/utils/teleport/environments.ts +120 -0
  892. package/utils/teleport/gitBundle.ts +292 -0
  893. package/utils/teleport.tsx +1226 -0
  894. package/utils/tempfile.ts +31 -0
  895. package/utils/terminal.ts +131 -0
  896. package/utils/terminalPanel.ts +191 -0
  897. package/utils/textHighlighting.ts +166 -0
  898. package/utils/theme.ts +639 -0
  899. package/utils/thinking.ts +162 -0
  900. package/utils/timeouts.ts +39 -0
  901. package/utils/tmuxSocket.ts +427 -0
  902. package/utils/todo/types.ts +18 -0
  903. package/utils/tokenBudget.ts +73 -0
  904. package/utils/tokens.ts +261 -0
  905. package/utils/toolErrors.ts +132 -0
  906. package/utils/toolPool.ts +79 -0
  907. package/utils/toolResultStorage.ts +1040 -0
  908. package/utils/toolSchemaCache.ts +26 -0
  909. package/utils/toolSearch.ts +756 -0
  910. package/utils/transcriptSearch.ts +202 -0
  911. package/utils/treeify.ts +170 -0
  912. package/utils/truncate.ts +179 -0
  913. package/utils/ultraplan/ccrSession.ts +349 -0
  914. package/utils/ultraplan/keyword.ts +127 -0
  915. package/utils/ultraplan/prompt.txt +1 -0
  916. package/utils/unaryLogging.ts +39 -0
  917. package/utils/undercover.ts +89 -0
  918. package/utils/user.ts +194 -0
  919. package/utils/userAgent.ts +10 -0
  920. package/utils/userPromptKeywords.ts +27 -0
  921. package/utils/uuid.ts +27 -0
  922. package/utils/warningHandler.ts +121 -0
  923. package/utils/which.ts +82 -0
  924. package/utils/windowsPaths.ts +173 -0
  925. package/utils/withResolvers.ts +13 -0
  926. package/utils/words.ts +800 -0
  927. package/utils/workloadContext.ts +57 -0
  928. package/utils/worktree.ts +1519 -0
  929. package/utils/worktreeModeEnabled.ts +11 -0
  930. package/utils/xdg.ts +65 -0
  931. package/utils/xmem.ts +6 -0
  932. package/utils/xml.ts +16 -0
  933. package/utils/yaml.ts +15 -0
  934. package/utils/zodToJsonSchema.ts +23 -0
@@ -0,0 +1,1141 @@
1
+ import { feature } from 'bun:bundle'
2
+ import { basename } from 'path'
3
+ import { useCallback, useEffect, useRef } from 'react'
4
+ import { getSessionId } from '../../bootstrap/state.js'
5
+ import type { Command } from '../../commands.js'
6
+ import type { Tool } from '../../Tool.js'
7
+ import {
8
+ clearServerCache,
9
+ fetchCommandsForClient,
10
+ fetchResourcesForClient,
11
+ fetchToolsForClient,
12
+ getMcpToolsCommandsAndResources,
13
+ reconnectMcpServerImpl,
14
+ } from './client.js'
15
+ import type {
16
+ MCPServerConnection,
17
+ ScopedMcpServerConfig,
18
+ ServerResource,
19
+ } from './types.js'
20
+
21
+ /* eslint-disable @typescript-eslint/no-require-imports */
22
+ const fetchMcpSkillsForClient = feature('MCP_SKILLS')
23
+ ? (
24
+ require('../../skills/mcpSkills.js') as typeof import('../../skills/mcpSkills.js')
25
+ ).fetchMcpSkillsForClient
26
+ : null
27
+ const clearSkillIndexCache = feature('EXPERIMENTAL_SKILL_SEARCH')
28
+ ? (
29
+ require('../skillSearch/localSearch.js') as typeof import('../skillSearch/localSearch.js')
30
+ ).clearSkillIndexCache
31
+ : null
32
+
33
+ import {
34
+ PromptListChangedNotificationSchema,
35
+ ResourceListChangedNotificationSchema,
36
+ ToolListChangedNotificationSchema,
37
+ } from '@modelcontextprotocol/sdk/types.js'
38
+ import omit from 'lodash-es/omit.js'
39
+ import reject from 'lodash-es/reject.js'
40
+ import {
41
+ type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
42
+ logEvent,
43
+ } from 'src/services/analytics/index.js'
44
+ import {
45
+ dedupClaudeAiMcpServers,
46
+ doesEnterpriseMcpConfigExist,
47
+ filterMcpServersByPolicy,
48
+ getClaudeCodeMcpConfigs,
49
+ isMcpServerDisabled,
50
+ setMcpServerEnabled,
51
+ } from 'src/services/mcp/config.js'
52
+ import type { AppState } from 'src/state/AppState.js'
53
+ import type { PluginError } from 'src/types/plugin.js'
54
+ import { logForDebugging } from 'src/utils/debug.js'
55
+ import { getAllowedChannels } from '../../bootstrap/state.js'
56
+ import { useNotifications } from '../../context/notifications.js'
57
+ import {
58
+ useAppState,
59
+ useAppStateStore,
60
+ useSetAppState,
61
+ } from '../../state/AppState.js'
62
+ import { errorMessage } from '../../utils/errors.js'
63
+ /* eslint-enable @typescript-eslint/no-require-imports */
64
+ import { logMCPDebug, logMCPError } from '../../utils/log.js'
65
+ import { enqueue } from '../../utils/messageQueueManager.js'
66
+ import {
67
+ CHANNEL_PERMISSION_METHOD,
68
+ ChannelMessageNotificationSchema,
69
+ ChannelPermissionNotificationSchema,
70
+ findChannelEntry,
71
+ gateChannelServer,
72
+ wrapChannelMessage,
73
+ } from './channelNotification.js'
74
+ import {
75
+ type ChannelPermissionCallbacks,
76
+ createChannelPermissionCallbacks,
77
+ isChannelPermissionRelayEnabled,
78
+ } from './channelPermissions.js'
79
+ import {
80
+ clearClaudeAIMcpConfigsCache,
81
+ fetchClaudeAIMcpConfigsIfEligible,
82
+ } from './claudeai.js'
83
+ import { registerElicitationHandler } from './elicitationHandler.js'
84
+ import { getMcpPrefix } from './mcpStringUtils.js'
85
+ import { commandBelongsToServer, excludeStalePluginClients } from './utils.js'
86
+
87
+ // Constants for reconnection with exponential backoff
88
+ const MAX_RECONNECT_ATTEMPTS = 5
89
+ const INITIAL_BACKOFF_MS = 1000
90
+ const MAX_BACKOFF_MS = 30000
91
+
92
+ /**
93
+ * Create a unique key for a plugin error to enable deduplication
94
+ */
95
+ function getErrorKey(error: PluginError): string {
96
+ const plugin = 'plugin' in error ? error.plugin : 'no-plugin'
97
+ return `${error.type}:${error.source}:${plugin}`
98
+ }
99
+
100
+ /**
101
+ * Add errors to AppState, deduplicating to avoid showing the same error multiple times
102
+ */
103
+ function addErrorsToAppState(
104
+ setAppState: (updater: (prev: AppState) => AppState) => void,
105
+ newErrors: PluginError[],
106
+ ): void {
107
+ if (newErrors.length === 0) return
108
+
109
+ setAppState(prevState => {
110
+ // Build set of existing error keys
111
+ const existingKeys = new Set(
112
+ prevState.plugins.errors.map(e => getErrorKey(e)),
113
+ )
114
+
115
+ // Only add errors that don't already exist
116
+ const uniqueNewErrors = newErrors.filter(
117
+ error => !existingKeys.has(getErrorKey(error)),
118
+ )
119
+
120
+ if (uniqueNewErrors.length === 0) {
121
+ return prevState
122
+ }
123
+
124
+ return {
125
+ ...prevState,
126
+ plugins: {
127
+ ...prevState.plugins,
128
+ errors: [...prevState.plugins.errors, ...uniqueNewErrors],
129
+ },
130
+ }
131
+ })
132
+ }
133
+
134
+ /**
135
+ * Hook to manage MCP (Model Context Protocol) server connections and updates
136
+ *
137
+ * This hook:
138
+ * 1. Initializes MCP client connections based on config
139
+ * 2. Sets up handlers for connection lifecycle events and sync with app state
140
+ * 3. Manages automatic reconnection for SSE connections
141
+ * 4. Returns a reconnect function
142
+ */
143
+ export function useManageMCPConnections(
144
+ dynamicMcpConfig: Record<string, ScopedMcpServerConfig> | undefined,
145
+ isStrictMcpConfig = false,
146
+ ) {
147
+ const store = useAppStateStore()
148
+ const _authVersion = useAppState(s => s.authVersion)
149
+ // Incremented by /reload-plugins (refreshActivePlugins) to pick up newly
150
+ // enabled plugin MCP servers. getClaudeCodeMcpConfigs() reads loadAllPlugins()
151
+ // which has been cleared by refreshActivePlugins, so the effects below see
152
+ // fresh plugin data on re-run.
153
+ const _pluginReconnectKey = useAppState(s => s.mcp.pluginReconnectKey)
154
+ const setAppState = useSetAppState()
155
+
156
+ // Track active reconnection attempts to allow cancellation
157
+ const reconnectTimersRef = useRef<Map<string, NodeJS.Timeout>>(new Map())
158
+
159
+ // Dedup the --channels blocked warning per skip kind so that a user who
160
+ // sees "run /login" (auth skip), logs in, then hits the policy gate
161
+ // gets a second toast.
162
+ const channelWarnedKindsRef = useRef<
163
+ Set<'disabled' | 'auth' | 'policy' | 'marketplace' | 'allowlist'>
164
+ >(new Set())
165
+ // Channel permission callbacks — constructed once, stable ref. Stored in
166
+ // AppState so interactiveHandler can subscribe. The pending Map lives inside
167
+ // the closure (not module-level, not AppState — functions-in-state is brittle).
168
+ const channelPermCallbacksRef = useRef<ChannelPermissionCallbacks | null>(
169
+ null,
170
+ )
171
+ if (
172
+ (feature('KAIROS') || feature('KAIROS_CHANNELS')) &&
173
+ channelPermCallbacksRef.current === null
174
+ ) {
175
+ channelPermCallbacksRef.current = createChannelPermissionCallbacks()
176
+ }
177
+ // Store callbacks in AppState so interactiveHandler.ts can reach them via
178
+ // ctx.toolUseContext.getAppState(). One-time set — the ref is stable.
179
+ useEffect(() => {
180
+ if (feature('KAIROS') || feature('KAIROS_CHANNELS')) {
181
+ const callbacks = channelPermCallbacksRef.current
182
+ if (!callbacks) return
183
+ // GrowthBook runtime gate — separate from channels so channels can
184
+ // ship without this. Checked at mount; mid-session flips need restart.
185
+ // If off, callbacks never go into AppState → interactiveHandler sees
186
+ // undefined → never sends → intercept has nothing pending → "yes tbxkq"
187
+ // flows to Claude as normal chat. One gate, full disable.
188
+ if (!isChannelPermissionRelayEnabled()) return
189
+ setAppState(prev => {
190
+ if (prev.channelPermissionCallbacks === callbacks) return prev
191
+ return { ...prev, channelPermissionCallbacks: callbacks }
192
+ })
193
+ return () => {
194
+ setAppState(prev => {
195
+ if (prev.channelPermissionCallbacks === undefined) return prev
196
+ return { ...prev, channelPermissionCallbacks: undefined }
197
+ })
198
+ }
199
+ }
200
+ }, [setAppState])
201
+ const { addNotification } = useNotifications()
202
+
203
+ // Batched MCP state updates: queue individual server updates and flush them
204
+ // in a single setAppState call via setTimeout. Using a time-based window
205
+ // (instead of queueMicrotask) ensures updates are batched even when
206
+ // connection callbacks arrive at different times due to network I/O.
207
+ const MCP_BATCH_FLUSH_MS = 16
208
+ type PendingUpdate = MCPServerConnection & {
209
+ tools?: Tool[]
210
+ commands?: Command[]
211
+ resources?: ServerResource[]
212
+ }
213
+ const pendingUpdatesRef = useRef<PendingUpdate[]>([])
214
+ const flushTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
215
+
216
+ const flushPendingUpdates = useCallback(() => {
217
+ flushTimerRef.current = null
218
+ const updates = pendingUpdatesRef.current
219
+ if (updates.length === 0) return
220
+ pendingUpdatesRef.current = []
221
+
222
+ setAppState(prevState => {
223
+ let mcp = prevState.mcp
224
+
225
+ for (const update of updates) {
226
+ const {
227
+ tools: rawTools,
228
+ commands: rawCmds,
229
+ resources: rawRes,
230
+ ...client
231
+ } = update
232
+ const tools =
233
+ client.type === 'disabled' || client.type === 'failed'
234
+ ? (rawTools ?? [])
235
+ : rawTools
236
+ const commands =
237
+ client.type === 'disabled' || client.type === 'failed'
238
+ ? (rawCmds ?? [])
239
+ : rawCmds
240
+ const resources =
241
+ client.type === 'disabled' || client.type === 'failed'
242
+ ? (rawRes ?? [])
243
+ : rawRes
244
+
245
+ const prefix = getMcpPrefix(client.name)
246
+ const existingClientIndex = mcp.clients.findIndex(
247
+ c => c.name === client.name,
248
+ )
249
+
250
+ const updatedClients =
251
+ existingClientIndex === -1
252
+ ? [...mcp.clients, client]
253
+ : mcp.clients.map(c => (c.name === client.name ? client : c))
254
+
255
+ const updatedTools =
256
+ tools === undefined
257
+ ? mcp.tools
258
+ : [...reject(mcp.tools, t => t.name?.startsWith(prefix)), ...tools]
259
+
260
+ const updatedCommands =
261
+ commands === undefined
262
+ ? mcp.commands
263
+ : [
264
+ ...reject(mcp.commands, c =>
265
+ commandBelongsToServer(c, client.name),
266
+ ),
267
+ ...commands,
268
+ ]
269
+
270
+ const updatedResources =
271
+ resources === undefined
272
+ ? mcp.resources
273
+ : {
274
+ ...mcp.resources,
275
+ ...(resources.length > 0
276
+ ? { [client.name]: resources }
277
+ : omit(mcp.resources, client.name)),
278
+ }
279
+
280
+ mcp = {
281
+ ...mcp,
282
+ clients: updatedClients,
283
+ tools: updatedTools,
284
+ commands: updatedCommands,
285
+ resources: updatedResources,
286
+ }
287
+ }
288
+
289
+ return { ...prevState, mcp }
290
+ })
291
+ }, [setAppState])
292
+
293
+ // Update server state, tools, commands, and resources.
294
+ // When tools, commands, or resources are undefined, the existing values are preserved.
295
+ // When type is 'disabled' or 'failed', tools/commands/resources are automatically cleared.
296
+ // Updates are batched via setTimeout to coalesce updates arriving within MCP_BATCH_FLUSH_MS.
297
+ const updateServer = useCallback(
298
+ (update: PendingUpdate) => {
299
+ pendingUpdatesRef.current.push(update)
300
+ if (flushTimerRef.current === null) {
301
+ flushTimerRef.current = setTimeout(
302
+ flushPendingUpdates,
303
+ MCP_BATCH_FLUSH_MS,
304
+ )
305
+ }
306
+ },
307
+ [flushPendingUpdates],
308
+ )
309
+
310
+ const onConnectionAttempt = useCallback(
311
+ ({
312
+ client,
313
+ tools,
314
+ commands,
315
+ resources,
316
+ }: {
317
+ client: MCPServerConnection
318
+ tools: Tool[]
319
+ commands: Command[]
320
+ resources?: ServerResource[]
321
+ }) => {
322
+ updateServer({ ...client, tools, commands, resources })
323
+
324
+ // Handle side effects based on client state
325
+ switch (client.type) {
326
+ case 'connected': {
327
+ // Overwrite the default elicitation handler registered in connectToServer
328
+ // with the real one (queues elicitation in AppState for UI). Registering
329
+ // here (once per connect) instead of in a [mcpClients] effect avoids
330
+ // re-running for every already-connected server on each state change.
331
+ registerElicitationHandler(client.client, client.name, setAppState)
332
+
333
+ client.client.onclose = () => {
334
+ const configType = client.config.type ?? 'stdio'
335
+
336
+ clearServerCache(client.name, client.config).catch(() => {
337
+ logForDebugging(
338
+ `Failed to invalidate the server cache: ${client.name}`,
339
+ )
340
+ })
341
+
342
+ // TODO: This really isn't great: ideally we'd check appstate as the source of truth
343
+ // as to whether it was disconnected due to a disable, but appstate is stale at this
344
+ // point. Getting a live reference to appstate feels a little hacky, so we'll just
345
+ // check the disk state. We may want to refactor some of this.
346
+ if (isMcpServerDisabled(client.name)) {
347
+ logMCPDebug(
348
+ client.name,
349
+ `Server is disabled, skipping automatic reconnection`,
350
+ )
351
+ return
352
+ }
353
+
354
+ // Handle automatic reconnection for remote transports
355
+ // Skip stdio (local process) and sdk (internal) - they don't support reconnection
356
+ if (configType !== 'stdio' && configType !== 'sdk') {
357
+ const transportType = getTransportDisplayName(configType)
358
+ logMCPDebug(
359
+ client.name,
360
+ `${transportType} transport closed/disconnected, attempting automatic reconnection`,
361
+ )
362
+
363
+ // Cancel any existing reconnection attempt for this server
364
+ const existingTimer = reconnectTimersRef.current.get(client.name)
365
+ if (existingTimer) {
366
+ clearTimeout(existingTimer)
367
+ reconnectTimersRef.current.delete(client.name)
368
+ }
369
+
370
+ // Attempt reconnection with exponential backoff
371
+ const reconnectWithBackoff = async () => {
372
+ for (
373
+ let attempt = 1;
374
+ attempt <= MAX_RECONNECT_ATTEMPTS;
375
+ attempt++
376
+ ) {
377
+ // Check if server was disabled while we were waiting
378
+ if (isMcpServerDisabled(client.name)) {
379
+ logMCPDebug(
380
+ client.name,
381
+ `Server disabled during reconnection, stopping retry`,
382
+ )
383
+ reconnectTimersRef.current.delete(client.name)
384
+ return
385
+ }
386
+
387
+ updateServer({
388
+ ...client,
389
+ type: 'pending',
390
+ reconnectAttempt: attempt,
391
+ maxReconnectAttempts: MAX_RECONNECT_ATTEMPTS,
392
+ })
393
+
394
+ const reconnectStartTime = Date.now()
395
+ try {
396
+ const result = await reconnectMcpServerImpl(
397
+ client.name,
398
+ client.config,
399
+ )
400
+ const elapsed = Date.now() - reconnectStartTime
401
+
402
+ if (result.client.type === 'connected') {
403
+ logMCPDebug(
404
+ client.name,
405
+ `${transportType} reconnection successful after ${elapsed}ms (attempt ${attempt})`,
406
+ )
407
+ reconnectTimersRef.current.delete(client.name)
408
+ onConnectionAttempt(result)
409
+ return
410
+ }
411
+
412
+ logMCPDebug(
413
+ client.name,
414
+ `${transportType} reconnection attempt ${attempt} completed with status: ${result.client.type}`,
415
+ )
416
+
417
+ // On final attempt, update state with the result
418
+ if (attempt === MAX_RECONNECT_ATTEMPTS) {
419
+ logMCPDebug(
420
+ client.name,
421
+ `Max reconnection attempts (${MAX_RECONNECT_ATTEMPTS}) reached, giving up`,
422
+ )
423
+ reconnectTimersRef.current.delete(client.name)
424
+ onConnectionAttempt(result)
425
+ return
426
+ }
427
+ } catch (error) {
428
+ const elapsed = Date.now() - reconnectStartTime
429
+ logMCPError(
430
+ client.name,
431
+ `${transportType} reconnection attempt ${attempt} failed after ${elapsed}ms: ${error}`,
432
+ )
433
+
434
+ // On final attempt, mark as failed
435
+ if (attempt === MAX_RECONNECT_ATTEMPTS) {
436
+ logMCPDebug(
437
+ client.name,
438
+ `Max reconnection attempts (${MAX_RECONNECT_ATTEMPTS}) reached, giving up`,
439
+ )
440
+ reconnectTimersRef.current.delete(client.name)
441
+ updateServer({ ...client, type: 'failed' })
442
+ return
443
+ }
444
+ }
445
+
446
+ // Schedule next retry with exponential backoff
447
+ const backoffMs = Math.min(
448
+ INITIAL_BACKOFF_MS * Math.pow(2, attempt - 1),
449
+ MAX_BACKOFF_MS,
450
+ )
451
+ logMCPDebug(
452
+ client.name,
453
+ `Scheduling reconnection attempt ${attempt + 1} in ${backoffMs}ms`,
454
+ )
455
+
456
+ await new Promise<void>(resolve => {
457
+ // eslint-disable-next-line no-restricted-syntax -- timer stored in ref for cancellation; sleep() doesn't expose the handle
458
+ const timer = setTimeout(resolve, backoffMs)
459
+ reconnectTimersRef.current.set(client.name, timer)
460
+ })
461
+ }
462
+ }
463
+
464
+ void reconnectWithBackoff()
465
+ } else {
466
+ updateServer({ ...client, type: 'failed' })
467
+ }
468
+ }
469
+
470
+ // Channel push: notifications/claude/channel → enqueue().
471
+ // Gate decides whether to register the handler; connection stays
472
+ // up either way (allowedMcpServers controls that).
473
+ if (feature('KAIROS') || feature('KAIROS_CHANNELS')) {
474
+ const gate = gateChannelServer(
475
+ client.name,
476
+ client.capabilities,
477
+ client.config.pluginSource,
478
+ )
479
+ const entry = findChannelEntry(client.name, getAllowedChannels())
480
+ // Plugin identifier for telemetry — log name@marketplace for any
481
+ // plugin-kind entry (same tier as tengu_plugin_installed, which
482
+ // logs arbitrary plugin_id+marketplace_name ungated). server-kind
483
+ // names are MCP-server-name tier; those are opt-in-only elsewhere
484
+ // (see isAnalyticsToolDetailsLoggingEnabled in metadata.ts) and
485
+ // stay unlogged here. is_dev/entry_kind segment the rest.
486
+ const pluginId =
487
+ entry?.kind === 'plugin'
488
+ ? (`${entry.name}@${entry.marketplace}` as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS)
489
+ : undefined
490
+ // Skip capability-miss — every non-channel MCP server trips it.
491
+ if (gate.action === 'register' || gate.kind !== 'capability') {
492
+ logEvent('tengu_mcp_channel_gate', {
493
+ registered: gate.action === 'register',
494
+ skip_kind:
495
+ gate.action === 'skip'
496
+ ? (gate.kind as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS)
497
+ : undefined,
498
+ entry_kind:
499
+ entry?.kind as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
500
+ is_dev: entry?.dev ?? false,
501
+ plugin: pluginId,
502
+ })
503
+ }
504
+ switch (gate.action) {
505
+ case 'register':
506
+ logMCPDebug(client.name, 'Channel notifications registered')
507
+ client.client.setNotificationHandler(
508
+ ChannelMessageNotificationSchema(),
509
+ async notification => {
510
+ const { content, meta } = notification.params
511
+ logMCPDebug(
512
+ client.name,
513
+ `notifications/claude/channel: ${content.slice(0, 80)}`,
514
+ )
515
+ logEvent('tengu_mcp_channel_message', {
516
+ content_length: content.length,
517
+ meta_key_count: Object.keys(meta ?? {}).length,
518
+ entry_kind:
519
+ entry?.kind as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
520
+ is_dev: entry?.dev ?? false,
521
+ plugin: pluginId,
522
+ })
523
+ enqueue({
524
+ mode: 'prompt',
525
+ value: wrapChannelMessage(client.name, content, meta),
526
+ priority: 'next',
527
+ isMeta: true,
528
+ origin: { kind: 'channel', server: client.name },
529
+ skipSlashCommands: true,
530
+ })
531
+ },
532
+ )
533
+ // Permission-reply handler — separate event, separate
534
+ // capability. Only registers if the server declares
535
+ // claude/channel/permission (same opt-in check as the send
536
+ // path in interactiveHandler.ts). Server parses the user's
537
+ // reply and emits {request_id, behavior}; no regex on our
538
+ // side, text in the general channel can't accidentally match.
539
+ if (
540
+ client.capabilities?.experimental?.[
541
+ 'claude/channel/permission'
542
+ ] !== undefined
543
+ ) {
544
+ client.client.setNotificationHandler(
545
+ ChannelPermissionNotificationSchema(),
546
+ async notification => {
547
+ const { request_id, behavior } = notification.params
548
+ const resolved =
549
+ channelPermCallbacksRef.current?.resolve(
550
+ request_id,
551
+ behavior,
552
+ client.name,
553
+ ) ?? false
554
+ logMCPDebug(
555
+ client.name,
556
+ `notifications/claude/channel/permission: ${request_id} → ${behavior} (${resolved ? 'matched pending' : 'no pending entry — stale or unknown ID'})`,
557
+ )
558
+ },
559
+ )
560
+ }
561
+ break
562
+ case 'skip':
563
+ // Idempotent teardown so a register→skip re-gate (e.g.
564
+ // effect re-runs after /logout) actually removes the live
565
+ // handler. Without this, mid-session demotion is one-way:
566
+ // the gate says skip but the earlier handler keeps enqueuing.
567
+ // Map.delete — safe when never registered.
568
+ client.client.removeNotificationHandler(
569
+ 'notifications/claude/channel',
570
+ )
571
+ client.client.removeNotificationHandler(
572
+ CHANNEL_PERMISSION_METHOD,
573
+ )
574
+ logMCPDebug(
575
+ client.name,
576
+ `Channel notifications skipped: ${gate.reason}`,
577
+ )
578
+ // Surface a once-per-kind toast when a channel server is
579
+ // blocked. This is the only
580
+ // user-visible signal (logMCPDebug above requires --debug).
581
+ // Capability/session skips are expected noise and stay
582
+ // debug-only. marketplace/allowlist run after session — if
583
+ // we're here with those kinds, the user asked for it.
584
+ if (
585
+ gate.kind !== 'capability' &&
586
+ gate.kind !== 'session' &&
587
+ !channelWarnedKindsRef.current.has(gate.kind) &&
588
+ (gate.kind === 'marketplace' ||
589
+ gate.kind === 'allowlist' ||
590
+ entry !== undefined)
591
+ ) {
592
+ channelWarnedKindsRef.current.add(gate.kind)
593
+ // disabled/auth/policy get custom toast copy (shorter, actionable);
594
+ // marketplace/allowlist reuse the gate's reason verbatim
595
+ // since it already names the mismatch.
596
+ const text =
597
+ gate.kind === 'disabled'
598
+ ? 'Channels are not currently available'
599
+ : gate.kind === 'auth'
600
+ ? 'Channels require claude.ai authentication · run /login'
601
+ : gate.kind === 'policy'
602
+ ? 'Channels are not enabled for your org · have an administrator set channelsEnabled: true in managed settings'
603
+ : gate.reason
604
+ addNotification({
605
+ key: `channels-blocked-${gate.kind}`,
606
+ priority: 'high',
607
+ text,
608
+ color: 'warning',
609
+ timeoutMs: 12000,
610
+ })
611
+ }
612
+ break
613
+ }
614
+ }
615
+
616
+ // Register notification handlers for list_changed notifications
617
+ // These allow the server to notify us when tools, prompts, or resources change
618
+ if (client.capabilities?.tools?.listChanged) {
619
+ client.client.setNotificationHandler(
620
+ ToolListChangedNotificationSchema,
621
+ async () => {
622
+ logMCPDebug(
623
+ client.name,
624
+ `Received tools/list_changed notification, refreshing tools`,
625
+ )
626
+ try {
627
+ // Grab cached promise before invalidating to log previous count
628
+ const previousToolsPromise = fetchToolsForClient.cache.get(
629
+ client.name,
630
+ )
631
+ fetchToolsForClient.cache.delete(client.name)
632
+ const newTools = await fetchToolsForClient(client)
633
+ const newCount = newTools.length
634
+ if (previousToolsPromise) {
635
+ previousToolsPromise.then(
636
+ (previousTools: Tool[]) => {
637
+ logEvent('tengu_mcp_list_changed', {
638
+ type: 'tools' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
639
+ previousCount: previousTools.length,
640
+ newCount,
641
+ })
642
+ },
643
+ () => {
644
+ logEvent('tengu_mcp_list_changed', {
645
+ type: 'tools' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
646
+ newCount,
647
+ })
648
+ },
649
+ )
650
+ } else {
651
+ logEvent('tengu_mcp_list_changed', {
652
+ type: 'tools' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
653
+ newCount,
654
+ })
655
+ }
656
+ updateServer({ ...client, tools: newTools })
657
+ } catch (error) {
658
+ logMCPError(
659
+ client.name,
660
+ `Failed to refresh tools after list_changed notification: ${errorMessage(error)}`,
661
+ )
662
+ }
663
+ },
664
+ )
665
+ }
666
+
667
+ if (client.capabilities?.prompts?.listChanged) {
668
+ client.client.setNotificationHandler(
669
+ PromptListChangedNotificationSchema,
670
+ async () => {
671
+ logMCPDebug(
672
+ client.name,
673
+ `Received prompts/list_changed notification, refreshing prompts`,
674
+ )
675
+ logEvent('tengu_mcp_list_changed', {
676
+ type: 'prompts' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
677
+ })
678
+ try {
679
+ // Skills come from resources, not prompts — don't invalidate their
680
+ // cache here. fetchMcpSkillsForClient returns the cached result.
681
+ fetchCommandsForClient.cache.delete(client.name)
682
+ const [mcpPrompts, mcpSkills] = await Promise.all([
683
+ fetchCommandsForClient(client),
684
+ feature('MCP_SKILLS')
685
+ ? fetchMcpSkillsForClient!(client)
686
+ : Promise.resolve([]),
687
+ ])
688
+ updateServer({
689
+ ...client,
690
+ commands: [...mcpPrompts, ...mcpSkills],
691
+ })
692
+ // MCP skills changed — invalidate skill-search index so
693
+ // next discovery rebuilds with the new set.
694
+ clearSkillIndexCache?.()
695
+ } catch (error) {
696
+ logMCPError(
697
+ client.name,
698
+ `Failed to refresh prompts after list_changed notification: ${errorMessage(error)}`,
699
+ )
700
+ }
701
+ },
702
+ )
703
+ }
704
+
705
+ if (client.capabilities?.resources?.listChanged) {
706
+ client.client.setNotificationHandler(
707
+ ResourceListChangedNotificationSchema,
708
+ async () => {
709
+ logMCPDebug(
710
+ client.name,
711
+ `Received resources/list_changed notification, refreshing resources`,
712
+ )
713
+ logEvent('tengu_mcp_list_changed', {
714
+ type: 'resources' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
715
+ })
716
+ try {
717
+ fetchResourcesForClient.cache.delete(client.name)
718
+ if (feature('MCP_SKILLS')) {
719
+ // Skills are discovered from resources, so refresh them too.
720
+ // Invalidate prompts cache as well: we write commands here,
721
+ // and a concurrent prompts/list_changed could otherwise have
722
+ // us stomp its fresh result with our cached stale one.
723
+ fetchMcpSkillsForClient!.cache.delete(client.name)
724
+ fetchCommandsForClient.cache.delete(client.name)
725
+ const [newResources, mcpPrompts, mcpSkills] =
726
+ await Promise.all([
727
+ fetchResourcesForClient(client),
728
+ fetchCommandsForClient(client),
729
+ fetchMcpSkillsForClient!(client),
730
+ ])
731
+ updateServer({
732
+ ...client,
733
+ resources: newResources,
734
+ commands: [...mcpPrompts, ...mcpSkills],
735
+ })
736
+ // MCP skills changed — invalidate skill-search index so
737
+ // next discovery rebuilds with the new set.
738
+ clearSkillIndexCache?.()
739
+ } else {
740
+ const newResources = await fetchResourcesForClient(client)
741
+ updateServer({ ...client, resources: newResources })
742
+ }
743
+ } catch (error) {
744
+ logMCPError(
745
+ client.name,
746
+ `Failed to refresh resources after list_changed notification: ${errorMessage(error)}`,
747
+ )
748
+ }
749
+ },
750
+ )
751
+ }
752
+ break
753
+ }
754
+
755
+ case 'needs-auth':
756
+ case 'failed':
757
+ case 'pending':
758
+ case 'disabled':
759
+ break
760
+ }
761
+ },
762
+ [updateServer],
763
+ )
764
+
765
+ // Initialize all servers to pending state if they don't exist in appState.
766
+ // Re-runs on session change (/clear) and on /reload-plugins (pluginReconnectKey).
767
+ // On plugin reload, also disconnects stale plugin MCP servers (scope 'dynamic')
768
+ // that no longer appear in configs — prevents ghost tools from disabled plugins.
769
+ // Skip claude.ai dedup here to avoid blocking on the network fetch; the connect
770
+ // useEffect below runs immediately after and dedups before connecting.
771
+ const sessionId = getSessionId()
772
+ useEffect(() => {
773
+ async function initializeServersAsPending() {
774
+ const { servers: existingConfigs, errors: mcpErrors } = isStrictMcpConfig
775
+ ? { servers: {}, errors: [] }
776
+ : await getClaudeCodeMcpConfigs(dynamicMcpConfig)
777
+ const configs = { ...existingConfigs, ...dynamicMcpConfig }
778
+
779
+ // Add MCP errors to plugin errors for UI visibility (deduplicated)
780
+ addErrorsToAppState(setAppState, mcpErrors)
781
+
782
+ setAppState(prevState => {
783
+ // Disconnect MCP servers that are stale: plugin servers removed from
784
+ // config, or any server whose config hash changed (edited .mcp.json).
785
+ // Stale servers get re-added as 'pending' below since their name is
786
+ // now absent from mcpWithoutStale.clients.
787
+ const { stale, ...mcpWithoutStale } = excludeStalePluginClients(
788
+ prevState.mcp,
789
+ configs,
790
+ )
791
+ // Clean up stale connections. Fire-and-forget — state updaters must
792
+ // be synchronous. Three hazards to defuse before calling cleanup:
793
+ // 1. Pending reconnect timer would fire with the OLD config.
794
+ // 2. onclose (set at L254) starts reconnectWithBackoff with the
795
+ // OLD config from its closure — it checks isMcpServerDisabled
796
+ // but config-changed servers aren't disabled, so it'd race the
797
+ // fresh connection and last updateServer wins.
798
+ // 3. clearServerCache internally calls connectToServer (memoized).
799
+ // For never-connected servers (disabled/pending/failed) the
800
+ // cache is empty → real connect attempt → spawn/OAuth just to
801
+ // immediately kill it. Only connected servers need cleanup.
802
+ for (const s of stale) {
803
+ const timer = reconnectTimersRef.current.get(s.name)
804
+ if (timer) {
805
+ clearTimeout(timer)
806
+ reconnectTimersRef.current.delete(s.name)
807
+ }
808
+ if (s.type === 'connected') {
809
+ s.client.onclose = undefined
810
+ void clearServerCache(s.name, s.config).catch(() => {})
811
+ }
812
+ }
813
+
814
+ const existingServerNames = new Set(
815
+ mcpWithoutStale.clients.map(c => c.name),
816
+ )
817
+ const newClients = Object.entries(configs)
818
+ .filter(([name]) => !existingServerNames.has(name))
819
+ .map(([name, config]) => ({
820
+ name,
821
+ type: isMcpServerDisabled(name)
822
+ ? ('disabled' as const)
823
+ : ('pending' as const),
824
+ config,
825
+ }))
826
+
827
+ if (newClients.length === 0 && stale.length === 0) {
828
+ return prevState
829
+ }
830
+
831
+ return {
832
+ ...prevState,
833
+ mcp: {
834
+ ...prevState.mcp,
835
+ ...mcpWithoutStale,
836
+ clients: [...mcpWithoutStale.clients, ...newClients],
837
+ },
838
+ }
839
+ })
840
+ }
841
+
842
+ void initializeServersAsPending().catch(error => {
843
+ logMCPError(
844
+ 'useManageMCPConnections',
845
+ `Failed to initialize servers as pending: ${errorMessage(error)}`,
846
+ )
847
+ })
848
+ }, [
849
+ isStrictMcpConfig,
850
+ dynamicMcpConfig,
851
+ setAppState,
852
+ sessionId,
853
+ _pluginReconnectKey,
854
+ ])
855
+
856
+ // Load MCP configs and connect to servers
857
+ // Two-phase loading: Claude Code configs first (fast), then claude.ai configs (may be slow)
858
+ useEffect(() => {
859
+ let cancelled = false
860
+
861
+ async function loadAndConnectMcpConfigs() {
862
+ // Clear claude.ai MCP cache so we fetch fresh configs with current auth
863
+ // state. This is important when authVersion changes (e.g., after login/
864
+ // logout). Kick off the fetch now so it overlaps with loadAllPlugins()
865
+ // inside getClaudeCodeMcpConfigs; it's awaited only at the dedup step.
866
+ // Phase 2 below awaits the same promise — no second network call.
867
+ let claudeaiPromise: Promise<Record<string, ScopedMcpServerConfig>>
868
+ if (isStrictMcpConfig || doesEnterpriseMcpConfigExist()) {
869
+ claudeaiPromise = Promise.resolve({})
870
+ } else {
871
+ clearClaudeAIMcpConfigsCache()
872
+ claudeaiPromise = fetchClaudeAIMcpConfigsIfEligible()
873
+ }
874
+
875
+ // Phase 1: Load Claude Code configs. Plugin MCP servers that duplicate a
876
+ // --mcp-config entry or a claude.ai connector are suppressed here so they
877
+ // don't connect alongside the connector in Phase 2.
878
+ const { servers: claudeCodeConfigs, errors: mcpErrors } =
879
+ isStrictMcpConfig
880
+ ? { servers: {}, errors: [] }
881
+ : await getClaudeCodeMcpConfigs(dynamicMcpConfig, claudeaiPromise)
882
+ if (cancelled) return
883
+
884
+ // Add MCP errors to plugin errors for UI visibility (deduplicated)
885
+ addErrorsToAppState(setAppState, mcpErrors)
886
+
887
+ const configs = { ...claudeCodeConfigs, ...dynamicMcpConfig }
888
+
889
+ // Start connecting to Claude Code servers (don't wait - runs concurrently with Phase 2)
890
+ // Filter out disabled servers to avoid unnecessary connection attempts
891
+ const enabledConfigs = Object.fromEntries(
892
+ Object.entries(configs).filter(([name]) => !isMcpServerDisabled(name)),
893
+ )
894
+ getMcpToolsCommandsAndResources(
895
+ onConnectionAttempt,
896
+ enabledConfigs,
897
+ ).catch(error => {
898
+ logMCPError(
899
+ 'useManageMcpConnections',
900
+ `Failed to get MCP resources: ${errorMessage(error)}`,
901
+ )
902
+ })
903
+
904
+ // Phase 2: Await claude.ai configs (started above; memoized — no second fetch)
905
+ let claudeaiConfigs: Record<string, ScopedMcpServerConfig> = {}
906
+ if (!isStrictMcpConfig) {
907
+ claudeaiConfigs = filterMcpServersByPolicy(
908
+ await claudeaiPromise,
909
+ ).allowed
910
+ if (cancelled) return
911
+
912
+ // Suppress claude.ai connectors that duplicate an enabled manual server.
913
+ // Keys never collide (`slack` vs `claude.ai Slack`) so the merge below
914
+ // won't catch this — need content-based dedup by URL signature.
915
+ if (Object.keys(claudeaiConfigs).length > 0) {
916
+ const { servers: dedupedClaudeAi } = dedupClaudeAiMcpServers(
917
+ claudeaiConfigs,
918
+ configs,
919
+ )
920
+ claudeaiConfigs = dedupedClaudeAi
921
+ }
922
+
923
+ if (Object.keys(claudeaiConfigs).length > 0) {
924
+ // Add claude.ai servers as pending immediately so they show up in UI
925
+ setAppState(prevState => {
926
+ const existingServerNames = new Set(
927
+ prevState.mcp.clients.map(c => c.name),
928
+ )
929
+ const newClients = Object.entries(claudeaiConfigs)
930
+ .filter(([name]) => !existingServerNames.has(name))
931
+ .map(([name, config]) => ({
932
+ name,
933
+ type: isMcpServerDisabled(name)
934
+ ? ('disabled' as const)
935
+ : ('pending' as const),
936
+ config,
937
+ }))
938
+ if (newClients.length === 0) return prevState
939
+ return {
940
+ ...prevState,
941
+ mcp: {
942
+ ...prevState.mcp,
943
+ clients: [...prevState.mcp.clients, ...newClients],
944
+ },
945
+ }
946
+ })
947
+
948
+ // Now start connecting (only enabled servers)
949
+ const enabledClaudeaiConfigs = Object.fromEntries(
950
+ Object.entries(claudeaiConfigs).filter(
951
+ ([name]) => !isMcpServerDisabled(name),
952
+ ),
953
+ )
954
+ getMcpToolsCommandsAndResources(
955
+ onConnectionAttempt,
956
+ enabledClaudeaiConfigs,
957
+ ).catch(error => {
958
+ logMCPError(
959
+ 'useManageMcpConnections',
960
+ `Failed to get claude.ai MCP resources: ${errorMessage(error)}`,
961
+ )
962
+ })
963
+ }
964
+ }
965
+
966
+ // Log server counts after both phases complete
967
+ const allConfigs = { ...configs, ...claudeaiConfigs }
968
+ const counts = {
969
+ enterprise: 0,
970
+ global: 0,
971
+ project: 0,
972
+ user: 0,
973
+ plugin: 0,
974
+ claudeai: 0,
975
+ }
976
+ // Ant-only: collect stdio command basenames to correlate with RSS/FPS
977
+ // metrics. Stdio servers like rust-analyzer can be heavy and we want to
978
+ // know which ones correlate with poor session performance.
979
+ const stdioCommands: string[] = []
980
+ for (const [name, serverConfig] of Object.entries(allConfigs)) {
981
+ if (serverConfig.scope === 'enterprise') counts.enterprise++
982
+ else if (serverConfig.scope === 'user') counts.global++
983
+ else if (serverConfig.scope === 'project') counts.project++
984
+ else if (serverConfig.scope === 'local') counts.user++
985
+ else if (serverConfig.scope === 'dynamic') counts.plugin++
986
+ else if (serverConfig.scope === 'claudeai') counts.claudeai++
987
+
988
+ if (
989
+ process.env.USER_TYPE === 'ant' &&
990
+ !isMcpServerDisabled(name) &&
991
+ (serverConfig.type === undefined || serverConfig.type === 'stdio') &&
992
+ 'command' in serverConfig
993
+ ) {
994
+ stdioCommands.push(basename(serverConfig.command))
995
+ }
996
+ }
997
+ logEvent('tengu_mcp_servers', {
998
+ ...counts,
999
+ ...(process.env.USER_TYPE === 'ant' && stdioCommands.length > 0
1000
+ ? {
1001
+ stdio_commands: stdioCommands
1002
+ .sort()
1003
+ .join(
1004
+ ',',
1005
+ ) as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
1006
+ }
1007
+ : {}),
1008
+ })
1009
+ }
1010
+
1011
+ void loadAndConnectMcpConfigs()
1012
+
1013
+ return () => {
1014
+ cancelled = true
1015
+ }
1016
+ }, [
1017
+ isStrictMcpConfig,
1018
+ dynamicMcpConfig,
1019
+ onConnectionAttempt,
1020
+ setAppState,
1021
+ _authVersion,
1022
+ sessionId,
1023
+ _pluginReconnectKey,
1024
+ ])
1025
+
1026
+ // Cleanup all timers on unmount
1027
+ useEffect(() => {
1028
+ const timers = reconnectTimersRef.current
1029
+ return () => {
1030
+ for (const timer of timers.values()) {
1031
+ clearTimeout(timer)
1032
+ }
1033
+ timers.clear()
1034
+ // Flush any pending batched MCP updates before unmount
1035
+ if (flushTimerRef.current !== null) {
1036
+ clearTimeout(flushTimerRef.current)
1037
+ flushTimerRef.current = null
1038
+ flushPendingUpdates()
1039
+ }
1040
+ }
1041
+ }, [flushPendingUpdates])
1042
+
1043
+ // Expose reconnectMcpServer function for components to use.
1044
+ // Reads mcp.clients via store.getState() so this callback stays stable
1045
+ // across client state transitions (no need to re-create on every connect).
1046
+ const reconnectMcpServer = useCallback(
1047
+ async (serverName: string) => {
1048
+ const client = store
1049
+ .getState()
1050
+ .mcp.clients.find(c => c.name === serverName)
1051
+ if (!client) {
1052
+ throw new Error(`MCP server ${serverName} not found`)
1053
+ }
1054
+
1055
+ // Cancel any pending automatic reconnection attempt
1056
+ const existingTimer = reconnectTimersRef.current.get(serverName)
1057
+ if (existingTimer) {
1058
+ clearTimeout(existingTimer)
1059
+ reconnectTimersRef.current.delete(serverName)
1060
+ }
1061
+
1062
+ const result = await reconnectMcpServerImpl(serverName, client.config)
1063
+
1064
+ onConnectionAttempt(result)
1065
+
1066
+ // Don't throw, just let UI handle the client type in case the reconnect failed
1067
+ // (Detailed logs are within the reconnectMcpServerImpl via --debug)
1068
+ return result
1069
+ },
1070
+ [store, onConnectionAttempt],
1071
+ )
1072
+
1073
+ // Expose function to toggle server enabled/disabled state
1074
+ const toggleMcpServer = useCallback(
1075
+ async (serverName: string): Promise<void> => {
1076
+ const client = store
1077
+ .getState()
1078
+ .mcp.clients.find(c => c.name === serverName)
1079
+ if (!client) {
1080
+ throw new Error(`MCP server ${serverName} not found`)
1081
+ }
1082
+
1083
+ const isCurrentlyDisabled = client.type === 'disabled'
1084
+
1085
+ if (!isCurrentlyDisabled) {
1086
+ // Cancel any pending automatic reconnection attempt
1087
+ const existingTimer = reconnectTimersRef.current.get(serverName)
1088
+ if (existingTimer) {
1089
+ clearTimeout(existingTimer)
1090
+ reconnectTimersRef.current.delete(serverName)
1091
+ }
1092
+
1093
+ // Persist disabled state to disk FIRST before clearing cache
1094
+ // This is important because the onclose handler checks disk state
1095
+ setMcpServerEnabled(serverName, false)
1096
+
1097
+ // Disabling: disconnect and clean up if currently connected
1098
+ if (client.type === 'connected') {
1099
+ await clearServerCache(serverName, client.config)
1100
+ }
1101
+
1102
+ // Update to disabled state (tools/commands/resources auto-cleared)
1103
+ updateServer({
1104
+ name: serverName,
1105
+ type: 'disabled',
1106
+ config: client.config,
1107
+ })
1108
+ } else {
1109
+ // Enabling: persist enabled state to disk first
1110
+ setMcpServerEnabled(serverName, true)
1111
+
1112
+ // Mark as pending and reconnect
1113
+ updateServer({
1114
+ name: serverName,
1115
+ type: 'pending',
1116
+ config: client.config,
1117
+ })
1118
+
1119
+ // Reconnect the server
1120
+ const result = await reconnectMcpServerImpl(serverName, client.config)
1121
+
1122
+ onConnectionAttempt(result)
1123
+ }
1124
+ },
1125
+ [store, updateServer, onConnectionAttempt],
1126
+ )
1127
+
1128
+ return { reconnectMcpServer, toggleMcpServer }
1129
+ }
1130
+
1131
+ function getTransportDisplayName(type: string): string {
1132
+ switch (type) {
1133
+ case 'http':
1134
+ return 'HTTP'
1135
+ case 'ws':
1136
+ case 'ws-ide':
1137
+ return 'WebSocket'
1138
+ default:
1139
+ return 'SSE'
1140
+ }
1141
+ }