@openhands/agent-canvas 1.5.1 → 1.6.1

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 (720) hide show
  1. package/README.md +1 -1
  2. package/README.windows.md +2 -2
  3. package/build/assets/{Trans-DqF_OEZB.js → Trans-52HCczKK.js} +1 -1
  4. package/build/assets/{acp-providers-DerAmTyY.js → acp-providers-xACMK9ZP.js} +1 -1
  5. package/build/assets/{active-backend-context-B8rMv0X9.js → active-backend-context-Cd1qcZsb.js} +1 -1
  6. package/build/assets/{add-backend-modal-CxC7BNEc.js → add-backend-modal-5chsfln3.js} +1 -1
  7. package/build/assets/{agent-profiles-settings-BJb8YXR1.js → agent-profiles-settings-BWK4H3kR.js} +1 -1
  8. package/build/assets/agent-server-compatibility-DMY0CihN.js +1 -0
  9. package/build/assets/agent-server-conversation-service.api-CI5-xmIX.js +41 -0
  10. package/build/assets/agent-settings-CMd8-O4f.js +2 -0
  11. package/build/assets/agent-settings-CdrhQJXX.js +1 -0
  12. package/build/assets/{alert-banner-Dh51WURQ.js → alert-banner-CLfWuIAX.js} +1 -1
  13. package/build/assets/api-key-entry-screen-Cc3aC7DZ.js +1 -0
  14. package/build/assets/app-settings-B-DQcBoB.js +1 -0
  15. package/build/assets/{automation-detail-CZsu2CoM.js → automation-detail-BgxBIpyK.js} +2 -2
  16. package/build/assets/automation-export-Dbur8OHa.js +2 -0
  17. package/build/assets/automations-list-BWfjizlp.js +1 -0
  18. package/build/assets/{back-nav-button-DVknCcSP.js → back-nav-button-CaKvsD1E.js} +1 -1
  19. package/build/assets/backend-form-modal-YcfpuBZo.js +1 -0
  20. package/build/assets/{backend-synced-settings-badge-BSfN0AZA.js → backend-synced-settings-badge-BellMmgC.js} +1 -1
  21. package/build/assets/{base-modal-CIF_785P.js → base-modal-Cw7enAHz.js} +1 -1
  22. package/build/assets/{brand-button-B1izLAdR.js → brand-button-BulEFHr3.js} +1 -1
  23. package/build/assets/{browser-DKaeq_sT.js → browser-DfVgUREb.js} +2 -2
  24. package/build/assets/browser-store-CBqI3tNR.js +1 -0
  25. package/build/assets/{browser-tab-qb_ftCxW.js → browser-tab-CmIKQB7S.js} +1 -1
  26. package/build/assets/chat-send-button-BchSSwuD.js +1 -0
  27. package/build/assets/circle-check-BXbQ5nEH.js +1 -0
  28. package/build/assets/{circle-plus-check-toggle-DoFIjVE0.js → circle-plus-check-toggle-BhpPjkh9.js} +1 -1
  29. package/build/assets/client-source-DAUgyJsi.js +1 -0
  30. package/build/assets/cloud-funnel-analytics-B5OeWh4y.js +1 -0
  31. package/build/assets/{color-themes-CHizm1xF.js → color-themes-QKMSVfDU.js} +1 -1
  32. package/build/assets/{combobox-caret-CxZpqoSR.js → combobox-caret-kNZtp53R.js} +1 -1
  33. package/build/assets/{command-menu-oTvKDU3Y.js → command-menu-tUsn23zy.js} +1 -1
  34. package/build/assets/{command-store-D8J5LMW1.js → command-store-B0hrIWMN.js} +1 -1
  35. package/build/assets/{condenser-settings-BGlWn93P.js → condenser-settings-BBizzfIH.js} +1 -1
  36. package/build/assets/{confirmation-modal-DGBWM2Ls.js → confirmation-modal-108xng7X.js} +1 -1
  37. package/build/assets/{context-menu-list-item-6psNyl7X.js → context-menu-list-item-BbKfFuN1.js} +1 -1
  38. package/build/assets/conversation-CTzSrLMq.js +1 -0
  39. package/build/assets/conversation-CgcXNb-Z.js +90 -0
  40. package/build/assets/conversation-panel-bscjGQda.js +1 -0
  41. package/build/assets/{conversation-service.api-_f9GlIEi.js → conversation-service.api-DbBvscJA.js} +1 -1
  42. package/build/assets/conversation-state-store-C5GagZHT.js +1 -0
  43. package/build/assets/{conversation-store-LptbOvKa.js → conversation-store-CyVqoa0d.js} +1 -1
  44. package/build/assets/{conversation-tab-empty-state-CNUmIms2.js → conversation-tab-empty-state-2KYlk5Bh.js} +1 -1
  45. package/build/assets/{copy-to-clipboard-button-CFzH_NOX.js → copy-to-clipboard-button-C54YRPMg.js} +1 -1
  46. package/build/assets/declaration-_yumYLEx.js +1 -0
  47. package/build/assets/{device-verify-WBSjJBLH.js → device-verify-D6FW_KZq.js} +1 -1
  48. package/build/assets/{dropdown-classes-D3wMJlXT.js → dropdown-classes-9uONlOg1.js} +1 -1
  49. package/build/assets/{ellipsis-button-CbNnHlIq.js → ellipsis-button-CoaUrKmQ.js} +1 -1
  50. package/build/assets/{entry.client-DNlPGxsu.js → entry.client-BJSVzw7V.js} +2 -2
  51. package/build/assets/{enum-filter-dropdown-JLYv1t8L.js → enum-filter-dropdown-qQzyjk_q.js} +1 -1
  52. package/build/assets/{environment-switch-overlay-B1PFO8P8.js → environment-switch-overlay-XRWCClLu.js} +1 -1
  53. package/build/assets/extensions-hub-DUp9sWQY.js +1 -0
  54. package/build/assets/extensions-navigation-DmkftjAx.js +1 -0
  55. package/build/assets/file-tUAzhmJ3.js +1 -0
  56. package/build/assets/files-tab-GV5hwiIM.js +1 -0
  57. package/build/assets/files-tab-store-DehyITNC.js +1 -0
  58. package/build/assets/{form-control-classes-CbdN5aO3.js → form-control-classes-BPUnoYyg.js} +1 -1
  59. package/build/assets/git-provider-icon-DDkru3b_.js +1 -0
  60. package/build/assets/highlighted-source-view-CYkPZUxr.js +1 -0
  61. package/build/assets/home-C53WekZ2.js +1 -0
  62. package/build/assets/home-EAwq8ah2.js +1 -0
  63. package/build/assets/index-home-kBdZGKtu.js +1 -0
  64. package/build/assets/install-server-modal-DYk4VP3-.js +1 -0
  65. package/build/assets/{launch-CAGavYl-.js → launch-CIecOy_y.js} +1 -1
  66. package/build/assets/lesson-plan-BSEUwflx.js +4 -0
  67. package/build/assets/llm-not-configured-banner-C8uv1PHT.js +27 -0
  68. package/build/assets/llm-settings-0Bb97NCk.js +1 -0
  69. package/build/assets/llm-settings-D4toJ90k.js +1 -0
  70. package/build/assets/{llm-subscription-service-Casyzgn1.js → llm-subscription-service-BPRw3u3H.js} +1 -1
  71. package/build/assets/{loading-spinner-BcdnT0mN.js → loading-spinner-BCInDEXB.js} +1 -1
  72. package/build/assets/manage-backends-modal-Bon32JYr.js +1 -0
  73. package/build/assets/manifest-ec000ae3.js +1 -0
  74. package/build/assets/markdown-renderer-BlaJOAI2.js +2 -0
  75. package/build/assets/mcp-CFIpOkn2.js +9 -0
  76. package/build/assets/messages-eRPeR4pW.js +40 -0
  77. package/build/assets/{modal-body-Cc2zp0xb.js → modal-body-Bg9UCeoV.js} +1 -1
  78. package/build/assets/{modal-classes-3qT9Ap7Q.js → modal-classes-H1KbJkeC.js} +1 -1
  79. package/build/assets/{modal-close-button-BcIBUdSq.js → modal-close-button-BMLYvo0C.js} +1 -1
  80. package/build/assets/{model-selector-DJrMrFAr.js → model-selector-BqX2RvEr.js} +1 -1
  81. package/build/assets/{navigation-link-D8hfwvxI.js → navigation-link-DoJzTCEz.js} +1 -1
  82. package/build/assets/onboarding-3KO4qE6R.js +1 -0
  83. package/build/assets/onboarding-modal-D4vqkJeT.js +1 -0
  84. package/build/assets/{organization-service.api-vrRNwOma.js → organization-service.api-CvfQugOt.js} +1 -1
  85. package/build/assets/{path-utils-PNfCKQDV.js → path-utils-DRgexxnX.js} +1 -1
  86. package/build/assets/{plan-components-BdZXPyZU.js → plan-components-qkMiGs_-.js} +1 -1
  87. package/build/assets/{planner-tab-ByOw1he8.js → planner-tab-ZrjiirRr.js} +1 -1
  88. package/build/assets/{plugins-management-service-B75jyC56.js → plugins-management-service-9qT-r_37.js} +1 -1
  89. package/build/assets/plus-CzE1b-wl.js +1 -0
  90. package/build/assets/{profiles-service.api-BQTklD5D.js → profiles-service.api-CRVlrQpT.js} +1 -1
  91. package/build/assets/{providers-DfTB2gPd.js → providers-C2DFGBrf.js} +1 -1
  92. package/build/assets/{proxy-B3tCGf0X.js → proxy-DnnDqkwn.js} +1 -1
  93. package/build/assets/puzzle-IHQnD54C.js +1 -0
  94. package/build/assets/recommended-automations-launcher-B97vgHuN.js +58 -0
  95. package/build/assets/refresh-cw-DxbAs3SK.js +1 -0
  96. package/build/assets/root-BbONavTg.css +1 -0
  97. package/build/assets/root-D01rpqZU.js +2 -0
  98. package/build/assets/root-layout-BiHbCIkS.js +2 -0
  99. package/build/assets/{runtime-waiting-state-CnyVhX4T.js → runtime-waiting-state-CbUV9txX.js} +1 -1
  100. package/build/assets/{schema-field-CUwk4wrQ.js → schema-field-B9-9Ta9u.js} +1 -1
  101. package/build/assets/sdk-section-page-DG1s25Pr.js +1 -0
  102. package/build/assets/{sdk-settings-schema-CLR01YIK.js → sdk-settings-schema-B42JFr5Y.js} +1 -1
  103. package/build/assets/{secrets-service-CvyPWJhg.js → secrets-service-DvyS6-mV.js} +1 -1
  104. package/build/assets/secrets-settings-CeSq6cQw.js +1 -0
  105. package/build/assets/{segmented-toggle-kzwZkLaj.js → segmented-toggle-DRVJBNy0.js} +1 -1
  106. package/build/assets/settings-Dzo0dJKM.js +1 -0
  107. package/build/assets/{settings-mQUckT0g.js → settings-HcwfqMjJ.js} +1 -1
  108. package/build/assets/{settings-dropdown-input-Dhx9ErGd.js → settings-dropdown-input-B6RL_mt0.js} +1 -1
  109. package/build/assets/settings-index-uAKHyijw.js +1 -0
  110. package/build/assets/{settings-input-BsgQWS5R.js → settings-input-ZoaAPNQh.js} +1 -1
  111. package/build/assets/{settings-list-classes-DSJJX99U.js → settings-list-classes-Dr8LgITi.js} +1 -1
  112. package/build/assets/settings-modal-BVX2G_IT.js +1 -0
  113. package/build/assets/{settings-service.api-DXk5TdeJ.js → settings-service.api-BY7ncxIz.js} +1 -1
  114. package/build/assets/{settings-switch-Bes8dIlV.js → settings-switch-DUlGnP0B.js} +1 -1
  115. package/build/assets/{settings-utils-DzCVfiR3.js → settings-utils-kWEEvcdv.js} +1 -1
  116. package/build/assets/shared-conversation-CV4Rtdz2.js +1 -0
  117. package/build/assets/{sidebar-layout-Bm7pa3Vk.js → sidebar-layout-BhGooCga.js} +1 -1
  118. package/build/assets/sidebar-mobile-menu-toggle-BntOJphE.js +1 -0
  119. package/build/assets/{sidebar-nav-link-CHqyFXwV.js → sidebar-nav-link-DkA1XWV8.js} +1 -1
  120. package/build/assets/{sidebar-store-uiUXBU1N.js → sidebar-store-CF3b12-m.js} +1 -1
  121. package/build/assets/{skill-card-pill-row-BPYKQ3IN.js → skill-card-pill-row-_gWe1Tws.js} +1 -1
  122. package/build/assets/skill-icon-badge-C-zbaXbD.js +1 -0
  123. package/build/assets/skills-plugins-BwoXKtrR.js +1 -0
  124. package/build/assets/skills-settings-Crq-fZSt.js +2 -0
  125. package/build/assets/{styled-tooltip-B14i_Uac.js → styled-tooltip-CdnCJ67u.js} +1 -1
  126. package/build/assets/syntax-highlighter-CZK2ab-O.js +1 -0
  127. package/build/assets/{task-list-tab-DyfgG4MC.js → task-list-tab-CONOO9iI.js} +1 -1
  128. package/build/assets/telemetry-CC32dJYW.js +2 -0
  129. package/build/assets/{terminal-DRXt2Lr4.js → terminal-CTkDpIU-.js} +1 -1
  130. package/build/assets/{toggle-switch-DX_k418f.js → toggle-switch-yVIzmJLM.js} +1 -1
  131. package/build/assets/{typography-CzfoD9DY.js → typography-BBVEW0un.js} +1 -1
  132. package/build/assets/{use-acp-credential-form-Bm8qXdlc.js → use-acp-credential-form-CIsp8hJe.js} +1 -1
  133. package/build/assets/use-activate-agent-profile-BfcTTJJG.js +1 -0
  134. package/build/assets/{use-active-agent-profile-hI-x-UBa.js → use-active-agent-profile-CCeFtmk9.js} +1 -1
  135. package/build/assets/{use-active-conversation-2qeez40F.js → use-active-conversation-Badxj8w4.js} +1 -1
  136. package/build/assets/{use-agent-profiles-0pr5bLS7.js → use-agent-profiles-BSWVN6hH.js} +1 -1
  137. package/build/assets/{use-agent-state-C6peDXUm.js → use-agent-state-BzRrhoPd.js} +1 -1
  138. package/build/assets/use-backends-health-BsZikyFW.js +1 -0
  139. package/build/assets/{use-can-manage-org-profiles-Ck_bsNbH.js → use-can-manage-org-profiles-Do6mYf6P.js} +1 -1
  140. package/build/assets/{use-cloud-current-user-id-DUCSxNjY.js → use-cloud-current-user-id-Cx3B_0-w.js} +1 -1
  141. package/build/assets/use-config-D9zUVw5b.js +1 -0
  142. package/build/assets/{use-create-conversation-r1JHfKO5.js → use-create-conversation-vvl0kvu7.js} +1 -1
  143. package/build/assets/{use-create-secret-Cf2N11d2.js → use-create-secret-CB7Dvd4s.js} +1 -1
  144. package/build/assets/use-event-store-BlpSUF7N.js +4 -0
  145. package/build/assets/{use-handle-plan-click-CsAW3FlH.js → use-handle-plan-click-DDZkew9p.js} +1 -1
  146. package/build/assets/use-is-creating-conversation-fxSzN778.js +1 -0
  147. package/build/assets/{use-launch-skill-in-chat-DJWEfVc5.js → use-launch-skill-in-chat-D6_n1fs3.js} +1 -1
  148. package/build/assets/use-llm-profiles-CNQm7HYS.js +1 -0
  149. package/build/assets/use-plugins-marketplace-CloojomS.js +1 -0
  150. package/build/assets/use-runtime-is-ready-Bx_4cfar.js +1 -0
  151. package/build/assets/{use-save-agent-profile-RqUGqTv6.js → use-save-agent-profile-Bj7N-1jS.js} +1 -1
  152. package/build/assets/{use-save-settings-Chvzeu2s.js → use-save-settings-BMsb2wk_.js} +1 -1
  153. package/build/assets/use-settings-B9XEmh7i.js +1 -0
  154. package/build/assets/use-settings-nav-items-BGfBS0yL.js +16 -0
  155. package/build/assets/{use-skills-xrVoKYrF.js → use-skills-CSRbvPle.js} +1 -1
  156. package/build/assets/{use-task-list-CfisapBW.js → use-task-list-CTIVLrQA.js} +1 -1
  157. package/build/assets/use-tracking-DjdCssvp.js +1 -0
  158. package/build/assets/{use-user-conversation-CnE4zhOA.js → use-user-conversation-BCpFn-Ei.js} +1 -1
  159. package/build/assets/{useTranslation-Cbf5AGg_.js → useTranslation-CHm_6BRr.js} +1 -1
  160. package/build/assets/{utils-DB9LsAzA.js → utils-CrRpzbM2.js} +1 -1
  161. package/build/assets/vendor-markdown-DzO4uO_0.js +37 -0
  162. package/build/assets/{vendor~browser-wXQ-WZEC.js → vendor~browser-Byfuq5J-.js} +1 -1
  163. package/build/assets/{vendor~browser-tab-CsMb-pta.js → vendor~browser-tab-BLk3qxhw.js} +1 -1
  164. package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dhilvkxv-eGLBu60s.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dhilvkxv-DTJ_cjR5.js} +2 -2
  165. package/build/assets/{vendor~files-tab-B-5fBohe.js → vendor~files-tab-XmnauIZI.js} +1 -1
  166. package/build/assets/{vendor~launch-_Km3J77E.js → vendor~launch-DeC8QhXQ.js} +1 -1
  167. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-BrguKXCn.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-DDmLzCzm.js} +1 -1
  168. package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation-YrfJYTQw.js +1 -0
  169. package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~launch~skills-settings~a~j2jlu22h-mC0v44WR.js → vendor~root-layout~index-home~home~conversation-panel~conversation~launch~skills-settings~a~j2jlu22h-DoaS51iW.js} +123 -3
  170. package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation~aler~gfu7qdtz-BOKQkbc6.js → vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation~aler~gfu7qdtz-DEYwoy8u.js} +1 -1
  171. package/build/assets/vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-DZHLw5Sr.js +1 -0
  172. package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~ftka0fnu-cFNmfAE6.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~ftka0fnu-UJ4BNDJP.js} +1 -1
  173. package/build/assets/{verification-settings-CfkrXoSa.js → verification-settings-uwOfc16F.js} +1 -1
  174. package/build/index.html +4 -4
  175. package/build/locales/ar/openhands.json +38 -4
  176. package/build/locales/ca/openhands.json +38 -4
  177. package/build/locales/de/openhands.json +38 -4
  178. package/build/locales/en/openhands.json +38 -4
  179. package/build/locales/es/openhands.json +38 -4
  180. package/build/locales/fr/openhands.json +38 -4
  181. package/build/locales/it/openhands.json +38 -4
  182. package/build/locales/ja/openhands.json +38 -4
  183. package/build/locales/ko-KR/openhands.json +38 -4
  184. package/build/locales/no/openhands.json +38 -4
  185. package/build/locales/pt/openhands.json +38 -4
  186. package/build/locales/tr/openhands.json +38 -4
  187. package/build/locales/uk/openhands.json +38 -4
  188. package/build/locales/zh-CN/openhands.json +38 -4
  189. package/build/locales/zh-TW/openhands.json +38 -4
  190. package/config/defaults.json +7 -3
  191. package/dist/api/agent-canvas-updates.cjs +2 -0
  192. package/dist/api/agent-canvas-updates.cjs.map +1 -0
  193. package/dist/api/agent-canvas-updates.d.ts +7 -0
  194. package/dist/api/agent-canvas-updates.js +19 -0
  195. package/dist/api/agent-canvas-updates.js.map +1 -0
  196. package/dist/api/agent-server-adapter.cjs +1 -1
  197. package/dist/api/agent-server-adapter.cjs.map +1 -1
  198. package/dist/api/agent-server-adapter.d.ts +3 -0
  199. package/dist/api/agent-server-adapter.js +1 -0
  200. package/dist/api/agent-server-adapter.js.map +1 -1
  201. package/dist/api/agent-server-compatibility.cjs +1 -1
  202. package/dist/api/agent-server-compatibility.cjs.map +1 -1
  203. package/dist/api/agent-server-compatibility.d.ts +5 -0
  204. package/dist/api/agent-server-compatibility.js +24 -15
  205. package/dist/api/agent-server-compatibility.js.map +1 -1
  206. package/dist/api/agent-server-config.cjs +1 -1
  207. package/dist/api/agent-server-config.cjs.map +1 -1
  208. package/dist/api/agent-server-config.js +11 -8
  209. package/dist/api/agent-server-config.js.map +1 -1
  210. package/dist/api/automation-service/automation-service.api.cjs +2 -0
  211. package/dist/api/automation-service/automation-service.api.cjs.map +1 -0
  212. package/dist/api/automation-service/automation-service.api.d.ts +3 -0
  213. package/dist/api/automation-service/automation-service.api.js +283 -0
  214. package/dist/api/automation-service/automation-service.api.js.map +1 -0
  215. package/dist/api/client-source.cjs +1 -1
  216. package/dist/api/client-source.cjs.map +1 -1
  217. package/dist/api/client-source.d.ts +3 -0
  218. package/dist/api/client-source.js +4 -4
  219. package/dist/api/client-source.js.map +1 -1
  220. package/dist/api/cloud/settings-service.api.cjs.map +1 -1
  221. package/dist/api/cloud/settings-service.api.js.map +1 -1
  222. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  223. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  224. package/dist/api/conversation-service/agent-server-conversation-service.api.js +111 -109
  225. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  226. package/dist/api/mcp-health/mcp-health-store.cjs +2 -0
  227. package/dist/api/mcp-health/mcp-health-store.cjs.map +1 -0
  228. package/dist/api/mcp-health/mcp-health-store.d.ts +22 -0
  229. package/dist/api/mcp-health/mcp-health-store.js +45 -0
  230. package/dist/api/mcp-health/mcp-health-store.js.map +1 -0
  231. package/dist/api/mcp-health/probe-mcp-server-health.cjs +2 -0
  232. package/dist/api/mcp-health/probe-mcp-server-health.cjs.map +1 -0
  233. package/dist/api/mcp-health/probe-mcp-server-health.d.ts +31 -0
  234. package/dist/api/mcp-health/probe-mcp-server-health.js +57 -0
  235. package/dist/api/mcp-health/probe-mcp-server-health.js.map +1 -0
  236. package/dist/api/mcp-service/mcp-service.api.cjs +1 -1
  237. package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -1
  238. package/dist/api/mcp-service/mcp-service.api.js +66 -46
  239. package/dist/api/mcp-service/mcp-service.api.js.map +1 -1
  240. package/dist/api/plugins-management-service.cjs.map +1 -1
  241. package/dist/api/plugins-management-service.d.ts +6 -1
  242. package/dist/api/plugins-management-service.js.map +1 -1
  243. package/dist/api/plugins-service.d.ts +30 -2
  244. package/dist/api/secrets-service.cjs +1 -1
  245. package/dist/api/secrets-service.cjs.map +1 -1
  246. package/dist/api/secrets-service.d.ts +6 -6
  247. package/dist/api/secrets-service.js +8 -3
  248. package/dist/api/secrets-service.js.map +1 -1
  249. package/dist/api/settings-service/settings-service.api.cjs +1 -1
  250. package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
  251. package/dist/api/settings-service/settings-service.api.d.ts +1 -1
  252. package/dist/api/settings-service/settings-service.api.js +1 -0
  253. package/dist/api/settings-service/settings-service.api.js.map +1 -1
  254. package/dist/components/conversation-events/chat/event-message-components/critic-result-display.cjs +1 -1
  255. package/dist/components/conversation-events/chat/event-message-components/critic-result-display.js +5 -5
  256. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  257. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  258. package/dist/components/features/backends/backend-form-modal.d.ts +4 -1
  259. package/dist/components/features/backends/backend-form-modal.js +15 -16
  260. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  261. package/dist/components/features/backends/backend-selector.cjs +1 -1
  262. package/dist/components/features/backends/backend-selector.cjs.map +1 -1
  263. package/dist/components/features/backends/backend-selector.js +103 -102
  264. package/dist/components/features/backends/backend-selector.js.map +1 -1
  265. package/dist/components/features/backends/manage-backends-modal.cjs +1 -1
  266. package/dist/components/features/backends/manage-backends-modal.cjs.map +1 -1
  267. package/dist/components/features/backends/manage-backends-modal.js +85 -73
  268. package/dist/components/features/backends/manage-backends-modal.js.map +1 -1
  269. package/dist/components/features/chat/chat-interface.cjs +2 -2
  270. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  271. package/dist/components/features/chat/chat-interface.js +131 -129
  272. package/dist/components/features/chat/chat-interface.js.map +1 -1
  273. package/dist/components/features/chat/confirmation-mode-enabled.cjs +1 -1
  274. package/dist/components/features/chat/confirmation-mode-enabled.js +4 -4
  275. package/dist/components/features/chat/skill-install-restart-banner.cjs +2 -0
  276. package/dist/components/features/chat/skill-install-restart-banner.cjs.map +1 -0
  277. package/dist/components/features/chat/skill-install-restart-banner.d.ts +11 -0
  278. package/dist/components/features/chat/skill-install-restart-banner.js +63 -0
  279. package/dist/components/features/chat/skill-install-restart-banner.js.map +1 -0
  280. package/dist/components/features/conversation/right-panel-toggle.cjs +1 -1
  281. package/dist/components/features/conversation/right-panel-toggle.cjs.map +1 -1
  282. package/dist/components/features/conversation/right-panel-toggle.js +1 -1
  283. package/dist/components/features/conversation/right-panel-toggle.js.map +1 -1
  284. package/dist/components/features/conversation-panel/conversation-panel.cjs +1 -1
  285. package/dist/components/features/conversation-panel/conversation-panel.js +10 -10
  286. package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
  287. package/dist/components/features/mcp-page/custom-server-editor.cjs.map +1 -1
  288. package/dist/components/features/mcp-page/custom-server-editor.js +78 -77
  289. package/dist/components/features/mcp-page/custom-server-editor.js.map +1 -1
  290. package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
  291. package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
  292. package/dist/components/features/mcp-page/install-server-modal.d.ts +4 -1
  293. package/dist/components/features/mcp-page/install-server-modal.js +135 -136
  294. package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
  295. package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
  296. package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
  297. package/dist/components/features/mcp-page/installed-server-card.js +40 -34
  298. package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
  299. package/dist/components/features/mcp-page/mcp-server-health.cjs +2 -0
  300. package/dist/components/features/mcp-page/mcp-server-health.cjs.map +1 -0
  301. package/dist/components/features/mcp-page/mcp-server-health.d.ts +18 -0
  302. package/dist/components/features/mcp-page/mcp-server-health.js +117 -0
  303. package/dist/components/features/mcp-page/mcp-server-health.js.map +1 -0
  304. package/dist/components/features/plugins/build-plugins-view-model.d.ts +10 -1
  305. package/dist/components/features/plugins/plugin-files-section.d.ts +13 -0
  306. package/dist/components/features/settings/agent-canvas-update-card.cjs +2 -0
  307. package/dist/components/features/settings/agent-canvas-update-card.cjs.map +1 -0
  308. package/dist/components/features/settings/agent-canvas-update-card.d.ts +7 -0
  309. package/dist/components/features/settings/agent-canvas-update-card.js +170 -0
  310. package/dist/components/features/settings/agent-canvas-update-card.js.map +1 -0
  311. package/dist/components/features/settings/integrations-settings-link.cjs +2 -0
  312. package/dist/components/features/settings/integrations-settings-link.cjs.map +1 -0
  313. package/dist/components/features/settings/integrations-settings-link.d.ts +5 -0
  314. package/dist/components/features/settings/integrations-settings-link.js +41 -0
  315. package/dist/components/features/settings/integrations-settings-link.js.map +1 -0
  316. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.cjs +1 -1
  317. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.js +1 -1
  318. package/dist/components/features/settings/settings-desktop-sidebar.cjs +1 -1
  319. package/dist/components/features/settings/settings-desktop-sidebar.cjs.map +1 -1
  320. package/dist/components/features/settings/settings-desktop-sidebar.js +31 -21
  321. package/dist/components/features/settings/settings-desktop-sidebar.js.map +1 -1
  322. package/dist/components/features/settings/settings-mobile-drawer.cjs +1 -1
  323. package/dist/components/features/settings/settings-mobile-drawer.cjs.map +1 -1
  324. package/dist/components/features/settings/settings-mobile-drawer.js +40 -30
  325. package/dist/components/features/settings/settings-mobile-drawer.js.map +1 -1
  326. package/dist/components/features/skills/extensions-navigation.cjs +1 -1
  327. package/dist/components/features/skills/extensions-navigation.cjs.map +1 -1
  328. package/dist/components/features/skills/extensions-navigation.js +54 -33
  329. package/dist/components/features/skills/extensions-navigation.js.map +1 -1
  330. package/dist/config/defaults.cjs +1 -1
  331. package/dist/config/defaults.cjs.map +1 -1
  332. package/dist/config/defaults.js +7 -3
  333. package/dist/config/defaults.js.map +1 -1
  334. package/dist/constants/acp-providers.cjs.map +1 -1
  335. package/dist/constants/acp-providers.js.map +1 -1
  336. package/dist/contexts/conversation-websocket-context.cjs +2 -2
  337. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  338. package/dist/contexts/conversation-websocket-context.js +169 -166
  339. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  340. package/dist/hooks/mutation/use-delete-llm-profile.cjs +1 -1
  341. package/dist/hooks/mutation/use-delete-llm-profile.js +1 -0
  342. package/dist/hooks/mutation/use-delete-mcp-server.cjs +1 -1
  343. package/dist/hooks/mutation/use-delete-mcp-server.cjs.map +1 -1
  344. package/dist/hooks/mutation/use-delete-mcp-server.js +8 -6
  345. package/dist/hooks/mutation/use-delete-mcp-server.js.map +1 -1
  346. package/dist/hooks/mutation/use-rename-llm-profile.cjs +1 -1
  347. package/dist/hooks/mutation/use-rename-llm-profile.js +1 -0
  348. package/dist/hooks/mutation/use-save-settings.cjs +1 -1
  349. package/dist/hooks/mutation/use-save-settings.js +3 -3
  350. package/dist/hooks/mutation/use-update-mcp-server.cjs +1 -1
  351. package/dist/hooks/mutation/use-update-mcp-server.cjs.map +1 -1
  352. package/dist/hooks/mutation/use-update-mcp-server.js +11 -9
  353. package/dist/hooks/mutation/use-update-mcp-server.js.map +1 -1
  354. package/dist/hooks/query/query-keys.cjs +1 -1
  355. package/dist/hooks/query/query-keys.cjs.map +1 -1
  356. package/dist/hooks/query/query-keys.d.ts +4 -0
  357. package/dist/hooks/query/query-keys.js +2 -2
  358. package/dist/hooks/query/query-keys.js.map +1 -1
  359. package/dist/hooks/query/use-automation-sdk-version.cjs +2 -0
  360. package/dist/hooks/query/use-automation-sdk-version.cjs.map +1 -0
  361. package/dist/hooks/query/use-automation-sdk-version.d.ts +3 -0
  362. package/dist/hooks/query/use-automation-sdk-version.js +63 -0
  363. package/dist/hooks/query/use-automation-sdk-version.js.map +1 -0
  364. package/dist/hooks/query/use-latest-agent-canvas-version.cjs +2 -0
  365. package/dist/hooks/query/use-latest-agent-canvas-version.cjs.map +1 -0
  366. package/dist/hooks/query/use-latest-agent-canvas-version.d.ts +10 -0
  367. package/dist/hooks/query/use-latest-agent-canvas-version.js +19 -0
  368. package/dist/hooks/query/use-latest-agent-canvas-version.js.map +1 -0
  369. package/dist/hooks/query/use-plugin-file-content.d.ts +7 -0
  370. package/dist/hooks/query/use-resolved-workspaces.cjs +1 -1
  371. package/dist/hooks/query/use-resolved-workspaces.cjs.map +1 -1
  372. package/dist/hooks/query/use-resolved-workspaces.js +25 -26
  373. package/dist/hooks/query/use-resolved-workspaces.js.map +1 -1
  374. package/dist/hooks/query/use-search-subdirs.cjs +1 -1
  375. package/dist/hooks/query/use-search-subdirs.cjs.map +1 -1
  376. package/dist/hooks/query/use-search-subdirs.d.ts +5 -0
  377. package/dist/hooks/query/use-search-subdirs.js +16 -4
  378. package/dist/hooks/query/use-search-subdirs.js.map +1 -1
  379. package/dist/hooks/query/use-task-polling.cjs +1 -1
  380. package/dist/hooks/query/use-task-polling.cjs.map +1 -1
  381. package/dist/hooks/query/use-task-polling.d.ts +19 -3
  382. package/dist/hooks/query/use-task-polling.js +36 -35
  383. package/dist/hooks/query/use-task-polling.js.map +1 -1
  384. package/dist/hooks/use-device-flow.cjs +1 -1
  385. package/dist/hooks/use-device-flow.js +6 -6
  386. package/dist/hooks/use-llm-configured.cjs +1 -1
  387. package/dist/hooks/use-llm-configured.js +3 -3
  388. package/dist/hooks/use-mcp-server-health.cjs +2 -0
  389. package/dist/hooks/use-mcp-server-health.cjs.map +1 -0
  390. package/dist/hooks/use-mcp-server-health.d.ts +11 -0
  391. package/dist/hooks/use-mcp-server-health.js +18 -0
  392. package/dist/hooks/use-mcp-server-health.js.map +1 -0
  393. package/dist/hooks/use-skill-installs.cjs +2 -0
  394. package/dist/hooks/use-skill-installs.cjs.map +1 -0
  395. package/dist/hooks/use-skill-installs.d.ts +10 -0
  396. package/dist/hooks/use-skill-installs.js +21 -0
  397. package/dist/hooks/use-skill-installs.js.map +1 -0
  398. package/dist/hooks/use-tracking.cjs +1 -1
  399. package/dist/hooks/use-tracking.cjs.map +1 -1
  400. package/dist/hooks/use-tracking.d.ts +3 -3
  401. package/dist/hooks/use-tracking.js +67 -52
  402. package/dist/hooks/use-tracking.js.map +1 -1
  403. package/dist/i18n/declaration.cjs +1 -1
  404. package/dist/i18n/declaration.cjs.map +1 -1
  405. package/dist/i18n/declaration.d.ts +35 -1
  406. package/dist/i18n/declaration.js +1 -1
  407. package/dist/i18n/declaration.js.map +1 -1
  408. package/dist/i18n/translation.cjs +3 -3
  409. package/dist/i18n/translation.cjs.map +1 -1
  410. package/dist/i18n/translation.js +623 -45
  411. package/dist/i18n/translation.js.map +1 -1
  412. package/dist/index.cjs +1 -1
  413. package/dist/index.js +1 -2
  414. package/dist/lib/index.cjs +1 -1
  415. package/dist/lib/index.d.ts +0 -1
  416. package/dist/lib/index.js +0 -1
  417. package/dist/locales/ar/openhands.json +38 -4
  418. package/dist/locales/ca/openhands.json +38 -4
  419. package/dist/locales/de/openhands.json +38 -4
  420. package/dist/locales/en/openhands.json +38 -4
  421. package/dist/locales/es/openhands.json +38 -4
  422. package/dist/locales/fr/openhands.json +38 -4
  423. package/dist/locales/it/openhands.json +38 -4
  424. package/dist/locales/ja/openhands.json +38 -4
  425. package/dist/locales/ko-KR/openhands.json +38 -4
  426. package/dist/locales/no/openhands.json +38 -4
  427. package/dist/locales/pt/openhands.json +38 -4
  428. package/dist/locales/tr/openhands.json +38 -4
  429. package/dist/locales/uk/openhands.json +38 -4
  430. package/dist/locales/zh-CN/openhands.json +38 -4
  431. package/dist/locales/zh-TW/openhands.json +38 -4
  432. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.cjs +2 -0
  433. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.cjs.map +1 -0
  434. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.js +44 -0
  435. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.js.map +1 -0
  436. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs +1 -1
  437. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs.map +1 -1
  438. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js +13 -0
  439. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js.map +1 -1
  440. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs +1 -1
  441. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs.map +1 -1
  442. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js +21 -1
  443. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -1
  444. package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.cjs +1 -1
  445. package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.cjs.map +1 -1
  446. package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.js +1 -1
  447. package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.js.map +1 -1
  448. package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.cjs +1 -1
  449. package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.cjs.map +1 -1
  450. package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.js +13 -0
  451. package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.js.map +1 -1
  452. package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.cjs +1 -1
  453. package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.cjs.map +1 -1
  454. package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.js +13 -0
  455. package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.js.map +1 -1
  456. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs +1 -1
  457. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs.map +1 -1
  458. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js +13 -0
  459. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js.map +1 -1
  460. package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.cjs +1 -1
  461. package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.cjs.map +1 -1
  462. package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.js +13 -0
  463. package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.js.map +1 -1
  464. package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.cjs +1 -1
  465. package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.cjs.map +1 -1
  466. package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.js +13 -0
  467. package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.js.map +1 -1
  468. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs +1 -1
  469. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs.map +1 -1
  470. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js +16 -2
  471. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js.map +1 -1
  472. package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.cjs +2 -0
  473. package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.cjs.map +1 -0
  474. package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.js +46 -0
  475. package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.js.map +1 -0
  476. package/dist/node_modules/@openhands/extensions/integrations/catalog-index.cjs +1 -1
  477. package/dist/node_modules/@openhands/extensions/integrations/catalog-index.cjs.map +1 -1
  478. package/dist/node_modules/@openhands/extensions/integrations/catalog-index.js +74 -70
  479. package/dist/node_modules/@openhands/extensions/integrations/catalog-index.js.map +1 -1
  480. package/dist/node_modules/@openhands/extensions/skills/index.cjs +123 -3
  481. package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
  482. package/dist/node_modules/@openhands/extensions/skills/index.js +7 -1
  483. package/dist/node_modules/@openhands/extensions/skills/index.js.map +1 -1
  484. package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.cjs +2 -0
  485. package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.cjs.map +1 -0
  486. package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.js +9 -0
  487. package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.js.map +1 -0
  488. package/dist/node_modules/lucide-react/dist/esm/icons/info.cjs +2 -0
  489. package/dist/node_modules/lucide-react/dist/esm/icons/info.cjs.map +1 -0
  490. package/dist/node_modules/lucide-react/dist/esm/icons/info.js +21 -0
  491. package/dist/node_modules/lucide-react/dist/esm/icons/info.js.map +1 -0
  492. package/dist/package.cjs +1 -1
  493. package/dist/package.cjs.map +1 -1
  494. package/dist/package.js +10 -3
  495. package/dist/package.js.map +1 -1
  496. package/dist/routes/app-settings.cjs +1 -1
  497. package/dist/routes/app-settings.cjs.map +1 -1
  498. package/dist/routes/app-settings.js +113 -67
  499. package/dist/routes/app-settings.js.map +1 -1
  500. package/dist/routes/conversation.cjs +1 -1
  501. package/dist/routes/conversation.cjs.map +1 -1
  502. package/dist/routes/conversation.js +1 -1
  503. package/dist/routes/conversation.js.map +1 -1
  504. package/dist/routes/mcp.cjs +1 -1
  505. package/dist/routes/mcp.cjs.map +1 -1
  506. package/dist/routes/mcp.js +1 -0
  507. package/dist/routes/mcp.js.map +1 -1
  508. package/dist/services/cloud-funnel-analytics.cjs +1 -1
  509. package/dist/services/cloud-funnel-analytics.cjs.map +1 -1
  510. package/dist/services/cloud-funnel-analytics.d.ts +2 -2
  511. package/dist/services/cloud-funnel-analytics.js +18 -16
  512. package/dist/services/cloud-funnel-analytics.js.map +1 -1
  513. package/dist/services/settings.cjs +1 -1
  514. package/dist/services/settings.cjs.map +1 -1
  515. package/dist/services/settings.js +1 -0
  516. package/dist/services/settings.js.map +1 -1
  517. package/dist/services/telemetry-context.cjs +2 -0
  518. package/dist/services/telemetry-context.cjs.map +1 -0
  519. package/dist/services/telemetry-context.d.ts +17 -0
  520. package/dist/services/telemetry-context.js +27 -0
  521. package/dist/services/telemetry-context.js.map +1 -0
  522. package/dist/services/telemetry.cjs +1 -1
  523. package/dist/services/telemetry.cjs.map +1 -1
  524. package/dist/services/telemetry.d.ts +7 -5
  525. package/dist/services/telemetry.js +132 -123
  526. package/dist/services/telemetry.js.map +1 -1
  527. package/dist/stores/skill-install-banner-store.cjs +2 -0
  528. package/dist/stores/skill-install-banner-store.cjs.map +1 -0
  529. package/dist/stores/skill-install-banner-store.d.ts +32 -0
  530. package/dist/stores/skill-install-banner-store.js +14 -0
  531. package/dist/stores/skill-install-banner-store.js.map +1 -0
  532. package/dist/stores/use-event-store.cjs +1 -1
  533. package/dist/stores/use-event-store.cjs.map +1 -1
  534. package/dist/stores/use-event-store.js +35 -35
  535. package/dist/stores/use-event-store.js.map +1 -1
  536. package/dist/types/mcp-health.cjs +2 -0
  537. package/dist/types/mcp-health.cjs.map +1 -0
  538. package/dist/types/mcp-health.d.ts +21 -0
  539. package/dist/types/mcp-health.js +6 -0
  540. package/dist/types/mcp-health.js.map +1 -0
  541. package/dist/types/settings.d.ts +1 -0
  542. package/dist/utils/handle-event-for-ui.cjs +1 -1
  543. package/dist/utils/handle-event-for-ui.cjs.map +1 -1
  544. package/dist/utils/handle-event-for-ui.d.ts +5 -0
  545. package/dist/utils/handle-event-for-ui.js +71 -57
  546. package/dist/utils/handle-event-for-ui.js.map +1 -1
  547. package/dist/utils/mcp-credential-validation.cjs +1 -1
  548. package/dist/utils/mcp-credential-validation.cjs.map +1 -1
  549. package/dist/utils/mcp-credential-validation.js +32 -16
  550. package/dist/utils/mcp-credential-validation.js.map +1 -1
  551. package/dist/utils/mcp-server-health-key.cjs +2 -0
  552. package/dist/utils/mcp-server-health-key.cjs.map +1 -0
  553. package/dist/utils/mcp-server-health-key.d.ts +16 -0
  554. package/dist/utils/mcp-server-health-key.js +23 -0
  555. package/dist/utils/mcp-server-health-key.js.map +1 -0
  556. package/dist/utils/mcp-test-error-message.cjs +2 -0
  557. package/dist/utils/mcp-test-error-message.cjs.map +1 -0
  558. package/dist/utils/mcp-test-error-message.d.ts +8 -0
  559. package/dist/utils/mcp-test-error-message.js +14 -0
  560. package/dist/utils/mcp-test-error-message.js.map +1 -0
  561. package/dist/utils/redact-mcp-secrets.cjs +2 -0
  562. package/dist/utils/redact-mcp-secrets.cjs.map +1 -0
  563. package/dist/utils/redact-mcp-secrets.d.ts +13 -0
  564. package/dist/utils/redact-mcp-secrets.js +57 -0
  565. package/dist/utils/redact-mcp-secrets.js.map +1 -0
  566. package/dist/utils/settings-utils.cjs.map +1 -1
  567. package/dist/utils/settings-utils.js.map +1 -1
  568. package/dist/utils/skill-install-events.cjs +3 -0
  569. package/dist/utils/skill-install-events.cjs.map +1 -0
  570. package/dist/utils/skill-install-events.d.ts +16 -0
  571. package/dist/utils/skill-install-events.js +26 -0
  572. package/dist/utils/skill-install-events.js.map +1 -0
  573. package/dist/utils/title-llm-profile.cjs +2 -0
  574. package/dist/utils/title-llm-profile.cjs.map +1 -0
  575. package/dist/utils/title-llm-profile.d.ts +2 -0
  576. package/dist/utils/title-llm-profile.js +11 -0
  577. package/dist/utils/title-llm-profile.js.map +1 -0
  578. package/package.json +10 -3
  579. package/scripts/check-sdk-version-sync.mjs +6 -6
  580. package/scripts/check-translation-completeness.cjs +2 -0
  581. package/scripts/dev-process-utils.mjs +62 -1
  582. package/scripts/dev-safe.mjs +2 -2
  583. package/scripts/dev-static.mjs +5 -3
  584. package/scripts/dev-with-automation.mjs +98 -14
  585. package/scripts/download-node.mjs +382 -0
  586. package/scripts/download-uv.mjs +204 -0
  587. package/scripts/logger.mjs +64 -35
  588. package/build/assets/agent-server-compatibility-BWN-EIQn.js +0 -1
  589. package/build/assets/agent-server-conversation-service.api-DSPIkMwJ.js +0 -41
  590. package/build/assets/agent-settings-CgCnqaAA.js +0 -2
  591. package/build/assets/agent-settings-DDkSavD7.js +0 -1
  592. package/build/assets/api-key-entry-screen-iZc7n8AI.js +0 -1
  593. package/build/assets/app-settings-B5zyipxJ.js +0 -1
  594. package/build/assets/automation-export-BwRX6H32.js +0 -2
  595. package/build/assets/automations-list-lHAVzMoA.js +0 -1
  596. package/build/assets/backend-form-modal-RGcu909r.js +0 -1
  597. package/build/assets/browser-store-BI6uklCG.js +0 -1
  598. package/build/assets/chat-send-button-BZHG2hAW.js +0 -1
  599. package/build/assets/client-source-BZK8vRs2.js +0 -1
  600. package/build/assets/cloud-funnel-analytics-Zcv57hfT.js +0 -1
  601. package/build/assets/conversation-BoCYx8n2.js +0 -89
  602. package/build/assets/conversation-DgHqMjnY.js +0 -1
  603. package/build/assets/conversation-panel-78Rxh_-I.js +0 -1
  604. package/build/assets/conversation-state-store-B2Bp32XI.js +0 -1
  605. package/build/assets/declaration-BGsHjPEW.js +0 -1
  606. package/build/assets/extensions-hub-CCbLA7IM.js +0 -1
  607. package/build/assets/extensions-navigation-CPNjMNvR.js +0 -1
  608. package/build/assets/files-tab-store-DJsPxYdg.js +0 -1
  609. package/build/assets/files-tab-y4K7EXBO.js +0 -1
  610. package/build/assets/git-provider-icon-ITvsH4Ko.js +0 -1
  611. package/build/assets/home-BwbeOWwU.js +0 -1
  612. package/build/assets/home-DKPGQ5P3.js +0 -1
  613. package/build/assets/index-home-Bko2Itv5.js +0 -1
  614. package/build/assets/install-server-modal-Qk1gwyI8.js +0 -1
  615. package/build/assets/lesson-plan-DMCPdtrf.js +0 -4
  616. package/build/assets/llm-not-configured-banner-C1ktyb3C.js +0 -27
  617. package/build/assets/llm-settings-BBsZFi9l.js +0 -1
  618. package/build/assets/llm-settings-DFkJQr_w.js +0 -1
  619. package/build/assets/manage-backends-modal-CKQ46rvw.js +0 -1
  620. package/build/assets/manifest-03478bbf.js +0 -1
  621. package/build/assets/markdown-renderer-B4V2OMFP.js +0 -2
  622. package/build/assets/mcp-BapoJsDc.js +0 -9
  623. package/build/assets/messages-CUBFMY5o.js +0 -40
  624. package/build/assets/objectWithoutPropertiesLoose-BgYIAs2y.js +0 -1
  625. package/build/assets/onboarding-6NMkdNxV.js +0 -1
  626. package/build/assets/onboarding-modal-Q4AnpIdg.js +0 -1
  627. package/build/assets/recommended-automations-launcher-Bj7PuHY1.js +0 -58
  628. package/build/assets/refresh-cw-B9B7-vsy.js +0 -1
  629. package/build/assets/root-CDnuTToz.js +0 -2
  630. package/build/assets/root-CYWeTrWE.css +0 -1
  631. package/build/assets/root-layout-DfYVlcRG.js +0 -2
  632. package/build/assets/sdk-section-page-DLLNrYjI.js +0 -1
  633. package/build/assets/secrets-settings-CHy72A5C.js +0 -1
  634. package/build/assets/settings-B9S8UVQr.js +0 -1
  635. package/build/assets/settings-index-BKDl2CQ-.js +0 -1
  636. package/build/assets/settings-modal-DeK11CyT.js +0 -1
  637. package/build/assets/shared-conversation-9atDzTR4.js +0 -1
  638. package/build/assets/sidebar-mobile-menu-toggle-giMMZctn.js +0 -1
  639. package/build/assets/skills-plugins-Tropusio.js +0 -1
  640. package/build/assets/skills-settings-BvzBBCWk.js +0 -2
  641. package/build/assets/telemetry-C5JMEfqB.js +0 -2
  642. package/build/assets/use-activate-agent-profile-DlykqEfN.js +0 -1
  643. package/build/assets/use-backends-health-CLHPitJM.js +0 -1
  644. package/build/assets/use-config-B5r8erYt.js +0 -1
  645. package/build/assets/use-event-store-Bbaz51GR.js +0 -4
  646. package/build/assets/use-llm-profiles-Dr5__SlZ.js +0 -1
  647. package/build/assets/use-plugins-marketplace-BplU65ae.js +0 -1
  648. package/build/assets/use-runtime-is-ready-vCFOcLFa.js +0 -1
  649. package/build/assets/use-settings-CyxSlyTQ.js +0 -1
  650. package/build/assets/use-settings-nav-items-zEkSO_Bf.js +0 -16
  651. package/build/assets/use-tracking-D2Qg5Lpd.js +0 -1
  652. package/build/assets/useMutationState-OnAsCLA_.js +0 -1
  653. package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BD7v71DM.js +0 -2
  654. package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BT05Osu4.js +0 -28
  655. package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-COhHANvV.js +0 -2
  656. package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DgzWSMRc.js +0 -2
  657. package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DqZatR3B.js +0 -7
  658. package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-FghQ3Z1a.js +0 -1
  659. package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation-BTvhGHHG.js +0 -1
  660. package/build/assets/vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-C4-GDgiF.js +0 -1
  661. package/dist/components/features/analytics/telemetry-consent-banner.cjs +0 -2
  662. package/dist/components/features/analytics/telemetry-consent-banner.cjs.map +0 -1
  663. package/dist/components/features/analytics/telemetry-consent-banner.d.ts +0 -29
  664. package/dist/components/features/analytics/telemetry-consent-banner.js +0 -59
  665. package/dist/components/features/analytics/telemetry-consent-banner.js.map +0 -1
  666. /package/build/assets/{__vite-browser-external-BQUj0sYu.js → __vite-browser-external-CKHVBTNC.js} +0 -0
  667. /package/build/assets/{agent-server-ui-style-scope-qhnhZHBV.js → agent-server-ui-style-scope-BvSa9on7.js} +0 -0
  668. /package/build/assets/{automation-LZB0MjdV.js → automation-BGiPmxFR.js} +0 -0
  669. /package/build/assets/{canvas-ui-COgjltGz.js → canvas-ui-CC4EJo-H.js} +0 -0
  670. /package/build/assets/{checkmark-h7udgXMM.js → checkmark-ygQB1AtV.js} +0 -0
  671. /package/build/assets/{close-DLFb5kfv.js → close-BjSA0HWT.js} +0 -0
  672. /package/build/assets/{code-tag-DYlAhEQY.js → code-tag-D9aPPbOe.js} +0 -0
  673. /package/build/assets/{common-CxbUL3nR.js → common-CCuqQy_S.js} +0 -0
  674. /package/build/assets/{conversation-local-storage-F6zVMM--.js → conversation-local-storage-BDjWPg0Z.js} +0 -0
  675. /package/build/assets/{copy-BLmGeJcd.js → copy-Dce7sOvS.js} +0 -0
  676. /package/build/assets/{copy-D1YGjP-C.js → copy-iPJAncAj.js} +0 -0
  677. /package/build/assets/{dist-CodhvuAP.js → dist-D9PhjOaq.js} +0 -0
  678. /package/build/assets/{environment-switch-store-DkjlKWzN.js → environment-switch-store-DHfcz4M4.js} +0 -0
  679. /package/build/assets/{extension-module-card-classes-9V3J9J_b.js → extension-module-card-classes-BpebKiN6.js} +0 -0
  680. /package/build/assets/{external-link-lhdITPqq.js → external-link-CpPMXxrV.js} +0 -0
  681. /package/build/assets/{folder-Bk311brm.js → folder-BabbYnbF.js} +0 -0
  682. /package/build/assets/{format-time-delta-DhDbkD7V.js → format-time-delta-BkAmJEPT.js} +0 -0
  683. /package/build/assets/{get-language-from-path-DBqBsCWH.js → get-language-from-path-CPNnuVhI.js} +0 -0
  684. /package/build/assets/{git-status-mapper-DnL9OC8_.js → git-status-mapper-BIXK0AAG.js} +0 -0
  685. /package/build/assets/{iconBase-Dz51Zn5x.js → iconBase-Ch-fOe8B.js} +0 -0
  686. /package/build/assets/{link-external-CaBmUEs_.js → link-external-DfKQroKX.js} +0 -0
  687. /package/build/assets/{list-todo-CAtvkzcy.js → list-todo-6J6zc8oS.js} +0 -0
  688. /package/build/assets/{llm-subscription-DtsX5Lhg.js → llm-subscription-Bvu8BLXc.js} +0 -0
  689. /package/build/assets/{loader-circle-CsAsfLIs.js → loader-circle-DGsqG5qw.js} +0 -0
  690. /package/build/assets/{map-provider-BbIb12oh.js → map-provider-BSvXvVR0.js} +0 -0
  691. /package/build/assets/{middleware-DYHYNAnP.js → middleware-_izt7V6U.js} +0 -0
  692. /package/build/assets/{modal-backdrop-zVwfOJZr.js → modal-backdrop-B7H42xHG.js} +0 -0
  693. /package/build/assets/{navigation-context-DPs2G0X8.js → navigation-context-cvyvI1WA.js} +0 -0
  694. /package/build/assets/{openhands-logo-bcNw5bkY.js → openhands-logo-pEw0nKFP.js} +0 -0
  695. /package/build/assets/{pencil-CWhApFIT.js → pencil-DmSqWUA3.js} +0 -0
  696. /package/build/assets/{react-DPDgL6du.js → react-MKQOkha9.js} +0 -0
  697. /package/build/assets/{search-BgOCR7_c.js → search-B5D5EuSn.js} +0 -0
  698. /package/build/assets/{search-dIQ09UY2.js → search-vnYL5jwV.js} +0 -0
  699. /package/build/assets/{settings-gear-MXCyZW0x.js → settings-gear-BOwF59Bs.js} +0 -0
  700. /package/build/assets/{settings-section-header-context-COMOIaxV.js → settings-section-header-context-CGgHZXrf.js} +0 -0
  701. /package/build/assets/{skills-EqzxYBvT.js → skills-arUOHLcS.js} +0 -0
  702. /package/build/assets/{square-chevron-right-DE-JN-2Z.js → square-chevron-right-EizCGtgq.js} +0 -0
  703. /package/build/assets/{switch-skeleton-DqQwalyu.js → switch-skeleton-BjPRx1QD.js} +0 -0
  704. /package/build/assets/{terminal-Cgf___rK.js → terminal-a57bHgZs.js} +0 -0
  705. /package/build/assets/{trash-2-BU6BlW4i.js → trash-2-CF3hilrY.js} +0 -0
  706. /package/build/assets/{u-check-circle-BqoIxNz_.js → u-check-circle-WGqHdtfO.js} +0 -0
  707. /package/build/assets/{u-check-circle-half-MsShT8Ec.js → u-check-circle-half-LiwZkuFe.js} +0 -0
  708. /package/build/assets/{u-edit-DL5LgKon.js → u-edit-BwHepAPi.js} +0 -0
  709. /package/build/assets/{use-breakpoint-BP3lqLMx.js → use-breakpoint-B-O0lQ84.js} +0 -0
  710. /package/build/assets/{use-click-outside-element-D9BYdANT.js → use-click-outside-element-DLQIMQrz.js} +0 -0
  711. /package/build/assets/{use-is-authed-BezEyfeh.js → use-is-authed-BSeo4coy.js} +0 -0
  712. /package/build/assets/{use-onboarding-completion-C_Swglzp.js → use-onboarding-completion-C0hPNGpw.js} +0 -0
  713. /package/build/assets/{v4-DbCkTSoU.js → v4-q4yWTlMz.js} +0 -0
  714. /package/build/assets/{vendor~browser-By2MVv_N.js → vendor~browser-UwB1jbAZ.js} +0 -0
  715. /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-CxfzCmkN.js → vendor~conversation-panel~conversation~alert-banner-DHDkknt5.js} +0 -0
  716. /package/build/assets/{vendor~index-home~home~conversation-panel~conversation-ChmYLVgz.js → vendor~index-home~home~conversation-panel~conversation-Bff9cq5J.js} +0 -0
  717. /package/build/assets/{vendor~module-D5a_AClf.js → vendor~module-D4DeFV4J.js} +0 -0
  718. /package/build/assets/{vendor~terminal-CnKZILnC.js → vendor~terminal-B7Eiak0-.js} +0 -0
  719. /package/build/assets/{x-ZE4iplpF.js → x-DQB_00VJ.js} +0 -0
  720. /package/build/assets/{x-mark-Batp6gXa.js → x-mark-B32XuEwS.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"install-server-modal.js","names":[],"sources":["../../../../src/components/features/mcp-page/install-server-modal.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { AxiosError } from \"axios\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { ModalBackdrop } from \"#/components/shared/modals/modal-backdrop\";\nimport { ModalCloseButton } from \"#/components/shared/modals/modal-close-button\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { SaveAsSecretToggle } from \"#/components/features/mcp-page/save-as-secret-toggle\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport type {\n IntegrationCatalogEntry as MarketplaceEntry,\n MarketplaceField,\n} from \"@openhands/extensions/integrations\";\nimport { McpLogoBadge } from \"#/components/features/mcp-logo-badge\";\nimport { ExtendedMCPTestFailure, MCPServerConfig } from \"#/types/mcp-server\";\nimport type { MCPAuthCredential } from \"#/types/mcp-auth\";\nimport { useAddMcpServer } from \"#/hooks/mutation/use-add-mcp-server\";\nimport { useTestMcpServer } from \"#/hooks/mutation/use-test-mcp-server\";\nimport { displaySuccessToast } from \"#/utils/custom-toast-handlers\";\nimport {\n getMcpOAuthAuthenticationConfig,\n getInstallableMcpConnectionOption,\n type McpMarketplaceConnectionOption,\n} from \"#/utils/mcp-marketplace-utils\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { useSaveFieldsAsSecrets } from \"#/hooks/mutation/use-save-fields-as-secrets\";\nimport { modalTitleLgClassName } from \"#/utils/modal-classes\";\nimport McpService from \"#/api/mcp-service/mcp-service.api\";\nimport { toMcpServerName } from \"#/utils/mcp-server-name\";\n\n/**\n * Renders a helperText string as React nodes, converting any `[text](url)`\n * markdown links into real `<a>` elements. Plain text segments are left as-is.\n * Only `http:` and `https:` URLs are rendered as links; anything else falls\n * back to `#` to guard against `javascript:` / `data:` XSS vectors.\n */\nfunction renderHelperText(text: string): React.ReactNode {\n const linkPattern = /\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\n const parts: React.ReactNode[] = [];\n let lastIndex = 0;\n for (const match of text.matchAll(linkPattern)) {\n if (match.index > lastIndex) {\n parts.push(text.slice(lastIndex, match.index));\n }\n parts.push(\n <a\n key={match.index}\n href={/^https?:\\/\\//i.test(match[2]) ? match[2] : \"#\"}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"underline hover:text-white transition-colors\"\n >\n {match[1]}\n </a>,\n );\n lastIndex = match.index + match[0].length;\n }\n if (lastIndex < text.length) {\n parts.push(text.slice(lastIndex));\n }\n return parts;\n}\n\ninterface InstallServerModalProps {\n entry: MarketplaceEntry;\n onClose: () => void;\n onSuccess?: (entry: MarketplaceEntry) => void;\n}\n\ninterface FieldState {\n values: Record<string, string>;\n errors: Record<string, string | null>;\n savedAsSecret: Record<string, boolean>;\n}\n\nfunction optionNeedsCredentialField(\n option: McpMarketplaceConnectionOption | undefined,\n): boolean {\n if (option?.transport.kind !== \"shttp\" && option?.transport.kind !== \"sse\") {\n return false;\n }\n return [\"api_key\", \"bearer\"].includes(option.auth.strategy);\n}\n\nfunction isOAuthOption(\n option: McpMarketplaceConnectionOption | undefined,\n): boolean {\n return !!option && option.auth.strategy === \"oauth2\";\n}\n\nfunction isCredentialOptional(option: McpMarketplaceConnectionOption): boolean {\n if (option.transport.kind === \"stdio\") {\n return option.auth.apiKeyOptional ?? false;\n }\n return option.auth.apiKeyOptional ?? option.transport.apiKeyOptional ?? false;\n}\n\nfunction getRemoteHeaderFields(\n option: McpMarketplaceConnectionOption | undefined,\n): MarketplaceField[] {\n if (option?.transport.kind !== \"shttp\" && option?.transport.kind !== \"sse\") {\n return [];\n }\n return option.transport.headerFields ?? [];\n}\n\nfunction makeInitialState(entry: MarketplaceEntry): FieldState {\n const values: Record<string, string> = {};\n const savedAsSecret: Record<string, boolean> = {};\n const option = getInstallableMcpConnectionOption(entry);\n const template = option?.transport;\n if (template?.kind === \"stdio\") {\n for (const field of template.envFields ?? []) {\n values[field.key] = \"\";\n // Pre-check password fields; non-password fields default to off.\n savedAsSecret[field.key] = field.type === \"password\";\n }\n for (const field of template.argFields ?? []) {\n values[field.key] = \"\";\n }\n } else if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n values.url = template.url;\n for (const field of getRemoteHeaderFields(option)) {\n values[field.key] = \"\";\n savedAsSecret[field.key] = field.type === \"password\";\n }\n if (optionNeedsCredentialField(option)) {\n values.api_key = \"\";\n if (option?.auth.credentialSecretName) {\n savedAsSecret.api_key =\n option.auth.saveCredentialAsSecretByDefault ?? false;\n }\n }\n }\n return { values, errors: {}, savedAsSecret };\n}\n\n// The marketplace install modal is intentionally add-only: clicking\n// a catalog tile always appends a new server (the user might want\n// two Slack workspaces, two Postgres connections, etc.) even when\n// one of the same template kind is already installed. Editing an\n// existing server is reached via the installed-server-card's edit\n// button, which opens `CustomServerEditor` instead.\nexport function InstallServerModal({\n entry,\n onClose,\n onSuccess,\n}: InstallServerModalProps) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: addMcpServer, isPending: isAdding } = useAddMcpServer();\n const { mutate: testMcpServer, isPending: isTesting } = useTestMcpServer();\n const saveFieldsAsSecrets = useSaveFieldsAsSecrets();\n\n const [state, setState] = React.useState<FieldState>(() =>\n makeInitialState(entry),\n );\n // Always holds the latest state so async callbacks (onSuccess) never read\n // stale closure values, even under React concurrent-mode scheduling.\n const stateRef = React.useRef(state);\n stateRef.current = state;\n\n const [globalError, setGlobalError] = React.useState<string | null>(null);\n const [isFinalizingInstall, setIsFinalizingInstall] = React.useState(false);\n const [isAuthorizingOAuth, setIsAuthorizingOAuth] = React.useState(false);\n const option = getInstallableMcpConnectionOption(entry);\n const template = option?.transport;\n\n const isPending =\n isTesting || isAuthorizingOAuth || isAdding || isFinalizingInstall;\n\n const setValue = (key: string, value: string) => {\n setState((prev) => ({\n ...prev,\n values: { ...prev.values, [key]: value },\n errors: { ...prev.errors, [key]: null },\n }));\n setGlobalError(null);\n };\n\n const toggleSecret = (key: string, value: boolean) => {\n setState((prev) => ({\n ...prev,\n savedAsSecret: { ...prev.savedAsSecret, [key]: value },\n }));\n };\n\n const saveHostedCredentialAsSecret = (): Promise<void> => {\n const secretName = option?.auth.credentialSecretName;\n const apiKey = stateRef.current.values.api_key?.trim();\n if (!secretName || !apiKey || !stateRef.current.savedAsSecret.api_key) {\n return Promise.resolve();\n }\n\n const field: MarketplaceField = {\n key: secretName,\n label: option.auth.credentialLabel ?? secretName,\n type: \"password\",\n };\n return saveFieldsAsSecrets(\n [field],\n { [secretName]: apiKey },\n { [secretName]: true },\n );\n };\n\n const saveSelectedSecrets = (): Promise<void> => {\n if (template?.kind === \"stdio\") {\n return saveFieldsAsSecrets(\n template.envFields ?? [],\n stateRef.current.values,\n stateRef.current.savedAsSecret,\n );\n }\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n return Promise.all([\n saveHostedCredentialAsSecret(),\n saveFieldsAsSecrets(\n getRemoteHeaderFields(option),\n stateRef.current.values,\n stateRef.current.savedAsSecret,\n ),\n ]).then(() => undefined);\n }\n return Promise.resolve();\n };\n\n const makeTestErrorMessage = (failure: ExtendedMCPTestFailure): string => {\n switch (failure.error_kind) {\n case \"timeout\":\n return t(I18nKey.MCP$TEST_ERROR_TIMEOUT);\n case \"connection\":\n return t(I18nKey.MCP$TEST_ERROR_CONNECTION);\n case \"credentials\":\n return t(I18nKey.MCP$TEST_ERROR_CREDENTIALS, { error: failure.error });\n default:\n return t(I18nKey.MCP$TEST_ERROR_UNKNOWN, { error: failure.error });\n }\n };\n\n const submitServer = (payload: MCPServerConfig) => {\n if (payload.auth?.strategy === \"oauth2\") {\n setIsAuthorizingOAuth(true);\n void McpService.authorizeOAuth(payload)\n .then((result) => {\n if (!result.ok) {\n setGlobalError(makeTestErrorMessage(result));\n return;\n }\n const serverToSave = result.oauth_state\n ? {\n ...payload,\n auth: { ...payload.auth!, state: result.oauth_state },\n }\n : payload;\n addMcpServer(serverToSave, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$INSTALL_SUCCESS));\n setIsFinalizingInstall(true);\n void (async () => {\n try {\n await saveSelectedSecrets();\n } finally {\n onSuccess?.(entry);\n onClose();\n }\n })();\n },\n onError: (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n },\n });\n })\n .catch((err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n })\n .finally(() => setIsAuthorizingOAuth(false));\n return;\n }\n testMcpServer(payload, {\n onSuccess: (result) => {\n if (!result.ok) {\n setGlobalError(makeTestErrorMessage(result));\n // Modal stays open — do NOT call onClose.\n return;\n }\n const serverToSave =\n result.oauth_state && payload.auth?.strategy === \"oauth2\"\n ? {\n ...payload,\n auth: { ...payload.auth, state: result.oauth_state },\n }\n : payload;\n addMcpServer(serverToSave, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$INSTALL_SUCCESS));\n setIsFinalizingInstall(true);\n void (async () => {\n try {\n await saveSelectedSecrets();\n } finally {\n onSuccess?.(entry);\n onClose();\n }\n })();\n },\n onError: (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n },\n });\n },\n onError: (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n },\n });\n };\n\n // ------------------------------------------------------------------\n // Per-template submit handlers. Each is small and self-contained:\n // validate user input, build the payload, then hand off to\n // submitServer.\n // ------------------------------------------------------------------\n const handleHttpServerSubmit = () => {\n // TS narrows this branch to shttp|sse; the equality guard is a\n // runtime/defensive belt to make the helper safe in isolation.\n if (template?.kind !== \"shttp\" && template?.kind !== \"sse\") {\n return;\n }\n if (!option) return;\n const apiKey = state.values.api_key?.trim() ?? \"\";\n const url = template.urlEditable\n ? (state.values.url?.trim() ?? \"\")\n : template.url;\n const oauthMode = isOAuthOption(option);\n const needsCredential = optionNeedsCredentialField(option);\n const headerFields = getRemoteHeaderFields(option);\n const headerErrors: Record<string, string | null> = {};\n if (!url) {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_REQUIRED);\n } else {\n try {\n const parsedUrl = new URL(url);\n if (![\"http:\", \"https:\"].includes(parsedUrl.protocol)) {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_INVALID_PROTOCOL);\n }\n } catch {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_INVALID);\n }\n }\n for (const field of headerFields) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n headerErrors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n if (\n !oauthMode &&\n needsCredential &&\n !isCredentialOptional(option) &&\n !apiKey\n ) {\n headerErrors.api_key = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n if (Object.values(headerErrors).some(Boolean)) {\n setState((prev) => ({ ...prev, errors: headerErrors }));\n return;\n }\n const oauthAuthentication = oauthMode\n ? getMcpOAuthAuthenticationConfig(option)\n : undefined;\n const fieldHeaders = Object.fromEntries(\n headerFields\n .map((field) => [field.key, state.values[field.key]?.trim() ?? \"\"])\n .filter(([, value]) => value),\n );\n const hasFieldHeaders = Object.keys(fieldHeaders).length > 0;\n let auth: MCPAuthCredential | undefined;\n if (oauthMode) {\n auth = {\n strategy: \"oauth2\",\n ...(oauthAuthentication && { authentication: oauthAuthentication }),\n };\n } else if (needsCredential && apiKey) {\n auth =\n option.auth.strategy === \"api_key\"\n ? {\n strategy: \"api_key\",\n value: apiKey,\n ...(option.auth.apiKeyHeaderName && {\n header_name: option.auth.apiKeyHeaderName,\n }),\n }\n : { strategy: \"bearer\", value: apiKey };\n } else if (hasFieldHeaders) {\n auth = { strategy: \"header\", headers: fieldHeaders };\n }\n const payload: MCPServerConfig = {\n id: `${template.kind}-${uuidv4()}`,\n type: template.kind,\n // Name remote servers after the catalog slug (e.g. \"github\") so they\n // get a referenceable, LLM-tool-safe mcp_config key instead of the\n // auto-generated \"sse\"/\"shttp\" fallback. Stdio installs already carry\n // serverName from the catalog.\n name: toMcpServerName(entry.id),\n url,\n ...(auth && { auth }),\n ...(hasFieldHeaders &&\n auth?.strategy !== \"header\" && { headers: fieldHeaders }),\n };\n submitServer(payload);\n };\n\n const handleStdioSubmit = () => {\n if (template?.kind !== \"stdio\") return;\n const stdio = template;\n const errors: Record<string, string | null> = {};\n\n for (const field of stdio.envFields ?? []) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n errors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n for (const field of stdio.argFields ?? []) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n errors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n if (Object.values(errors).some(Boolean)) {\n setState((prev) => ({ ...prev, errors }));\n return;\n }\n\n const env: Record<string, string> = {};\n for (const field of stdio.envFields ?? []) {\n const v = state.values[field.key]?.trim();\n if (v) env[field.key] = v;\n }\n const extraArgs: string[] = [];\n for (const field of stdio.argFields ?? []) {\n const v = state.values[field.key]?.trim();\n if (v) {\n // Filesystem-style multi-token input: split on whitespace.\n for (const token of v.split(/\\s+/)) {\n if (token) extraArgs.push(token);\n }\n }\n }\n\n const payload: MCPServerConfig = {\n id: `stdio-${uuidv4()}`,\n type: \"stdio\",\n name: stdio.serverName,\n command: stdio.command,\n args: [...stdio.args, ...extraArgs],\n ...(Object.keys(env).length > 0 && { env }),\n };\n submitServer(payload);\n };\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setGlobalError(null);\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n return handleHttpServerSubmit();\n }\n return handleStdioSubmit();\n };\n\n const renderFields = () => {\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n const oauthMode = isOAuthOption(option);\n const shouldRenderCredential = optionNeedsCredentialField(option);\n const apiKeyOptional = option ? isCredentialOptional(option) : false;\n const credentialSecretName = option?.auth.credentialSecretName;\n const headerFields = getRemoteHeaderFields(option);\n return (\n <>\n <SettingsInput\n testId=\"mcp-install-field-url\"\n name=\"url\"\n type=\"url\"\n label={t(I18nKey.SETTINGS$MCP_URL)}\n value={state.values.url ?? template.url}\n onChange={(value) => setValue(\"url\", value)}\n isDisabled={!template.urlEditable}\n className=\"w-full\"\n />\n {state.errors.url && (\n <p className=\"text-xs text-red-500\">{state.errors.url}</p>\n )}\n {headerFields.map((field) => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <SettingsInput\n testId={`mcp-install-field-${field.key}`}\n name={field.key}\n type={field.type === \"password\" ? \"password\" : \"text\"}\n label={field.label}\n value={state.values[field.key] ?? \"\"}\n onChange={(v) => setValue(field.key, v)}\n placeholder={field.placeholder}\n required={field.required}\n showOptionalTag={!field.required}\n className=\"w-full\"\n />\n {field.helperText && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(field.helperText)}\n </p>\n )}\n {state.errors[field.key] && (\n <p className=\"text-xs text-red-500\">\n {state.errors[field.key]}\n </p>\n )}\n {field.key in state.savedAsSecret && (\n <SaveAsSecretToggle\n fieldKey={field.key}\n checked={state.savedAsSecret[field.key] ?? false}\n onToggle={(v) => toggleSecret(field.key, v)}\n />\n )}\n </div>\n ))}\n {oauthMode ? (\n <div\n data-testid=\"mcp-install-oauth-info\"\n className=\"flex flex-col gap-2 p-3 rounded-lg border border-[var(--oh-border)] bg-base-tertiary\"\n >\n <p className=\"text-sm text-secondary-light\">\n {t(I18nKey.MCP$OAUTH_CONNECT_INFO)}\n </p>\n <p className=\"text-xs text-tertiary-alt\">\n {t(I18nKey.MCP$OAUTH_CONNECT_HINT)}\n </p>\n </div>\n ) : shouldRenderCredential ? (\n <div className=\"flex flex-col gap-1\">\n <SettingsInput\n testId=\"mcp-install-field-api_key\"\n name=\"api_key\"\n type=\"password\"\n label={\n option?.auth.credentialLabel ??\n t(I18nKey.SETTINGS$MCP_API_KEY)\n }\n value={state.values.api_key ?? \"\"}\n onChange={(v) => setValue(\"api_key\", v)}\n placeholder={\n option?.auth.credentialPlaceholder ??\n t(I18nKey.SETTINGS$MCP_API_KEY_PLACEHOLDER)\n }\n showOptionalTag={apiKeyOptional}\n required={!apiKeyOptional}\n className=\"w-full\"\n />\n {option?.auth.credentialHelp && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(option.auth.credentialHelp)}\n </p>\n )}\n {state.errors.api_key && (\n <p className=\"text-xs text-red-500\">{state.errors.api_key}</p>\n )}\n {credentialSecretName && (\n <SaveAsSecretToggle\n fieldKey={credentialSecretName}\n checked={state.savedAsSecret.api_key ?? false}\n onToggle={(v) => toggleSecret(\"api_key\", v)}\n />\n )}\n </div>\n ) : null}\n </>\n );\n }\n\n if (template?.kind !== \"stdio\") return null;\n const stdio = template;\n return (\n <>\n <SettingsInput\n testId=\"mcp-install-field-command-readonly\"\n name=\"command-readonly\"\n type=\"text\"\n label={t(I18nKey.MCP$COMMAND_LABEL)}\n value={`${stdio.command} ${stdio.args.join(\" \")}`.trim()}\n onChange={() => {}}\n isDisabled\n className=\"w-full\"\n />\n {(stdio.envFields ?? []).map((field) => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <SettingsInput\n testId={`mcp-install-field-${field.key}`}\n name={field.key}\n type={field.type === \"password\" ? \"password\" : \"text\"}\n label={field.label}\n value={state.values[field.key] ?? \"\"}\n onChange={(v) => setValue(field.key, v)}\n placeholder={field.placeholder}\n required={field.required}\n showOptionalTag={!field.required}\n className=\"w-full\"\n />\n {field.helperText && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(field.helperText)}\n </p>\n )}\n {state.errors[field.key] && (\n <p className=\"text-xs text-red-500\">{state.errors[field.key]}</p>\n )}\n {field.key in state.savedAsSecret && (\n <SaveAsSecretToggle\n fieldKey={field.key}\n checked={state.savedAsSecret[field.key]}\n onToggle={(v) => toggleSecret(field.key, v)}\n />\n )}\n </div>\n ))}\n {/* argFields are CLI arguments, not credentials — they don't need\n a \"save as secret\" toggle and are excluded from savedAsSecret. */}\n {(stdio.argFields ?? []).map((field) => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <SettingsInput\n testId={`mcp-install-field-${field.key}`}\n name={field.key}\n type={field.type === \"password\" ? \"password\" : \"text\"}\n label={field.label}\n value={state.values[field.key] ?? \"\"}\n onChange={(v) => setValue(field.key, v)}\n placeholder={field.placeholder}\n required={field.required}\n showOptionalTag={!field.required}\n className=\"w-full\"\n />\n {field.helperText && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(field.helperText)}\n </p>\n )}\n {state.errors[field.key] && (\n <p className=\"text-xs text-red-500\">{state.errors[field.key]}</p>\n )}\n </div>\n ))}\n </>\n );\n };\n\n return (\n <ModalBackdrop onClose={onClose} aria-label={entry.name}>\n <form\n data-testid=\"mcp-install-modal\"\n data-marketplace-id={entry.id}\n onSubmit={handleSubmit}\n className=\"relative bg-base-secondary p-6 rounded-xl flex flex-col gap-4 border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[85vh] overflow-y-auto custom-scrollbar\"\n >\n <ModalCloseButton\n onClose={onClose}\n testId=\"mcp-install-modal-close\"\n disabled={isPending}\n />\n <div className=\"flex items-start gap-3 pr-6\">\n <McpLogoBadge entry={entry} />\n <div className=\"flex flex-col flex-1\">\n <h2 className={modalTitleLgClassName}>{entry.name}</h2>\n <p className=\"text-xs text-tertiary-light\">{entry.description}</p>\n </div>\n </div>\n\n {entry.installHint && (\n <p className=\"text-xs text-tertiary-light\">{entry.installHint}</p>\n )}\n\n {entry.docsUrl && (\n <a\n href={entry.docsUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-xs text-[var(--oh-muted)] hover:text-white hover:underline self-start transition-colors\"\n >\n {t(I18nKey.MCP$VIEW_DOCS)}\n </a>\n )}\n\n <div className=\"flex flex-col gap-3\">{renderFields()}</div>\n\n {globalError && (\n <p\n data-testid=\"mcp-install-modal-error\"\n className=\"text-sm text-red-500 whitespace-pre-wrap\"\n >\n {globalError}\n </p>\n )}\n\n <div className=\"flex justify-end gap-2 mt-2\">\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n onClick={onClose}\n testId=\"mcp-install-cancel\"\n isDisabled={isPending}\n >\n {t(I18nKey.BUTTON$CANCEL)}\n </BrandButton>\n <BrandButton\n type=\"submit\"\n variant=\"primary\"\n isDisabled={isPending}\n testId=\"mcp-install-submit\"\n >\n {isTesting || isAuthorizingOAuth\n ? t(I18nKey.MCP$VERIFYING)\n : isAdding || isFinalizingInstall\n ? t(I18nKey.SETTINGS$SAVING)\n : t(I18nKey.MCP$INSTALL_BUTTON)}\n </BrandButton>\n </div>\n </form>\n </ModalBackdrop>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"install-server-modal.js","names":[],"sources":["../../../../src/components/features/mcp-page/install-server-modal.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { AxiosError } from \"axios\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { ModalBackdrop } from \"#/components/shared/modals/modal-backdrop\";\nimport { ModalCloseButton } from \"#/components/shared/modals/modal-close-button\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { SaveAsSecretToggle } from \"#/components/features/mcp-page/save-as-secret-toggle\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport type {\n IntegrationCatalogEntry as MarketplaceEntry,\n MarketplaceField,\n} from \"@openhands/extensions/integrations\";\nimport { McpLogoBadge } from \"#/components/features/mcp-logo-badge\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport type { MCPAuthCredential } from \"#/types/mcp-auth\";\nimport { seedMcpServerHealth } from \"#/api/mcp-health/probe-mcp-server-health\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useAddMcpServer } from \"#/hooks/mutation/use-add-mcp-server\";\nimport { useTestMcpServer } from \"#/hooks/mutation/use-test-mcp-server\";\nimport { displaySuccessToast } from \"#/utils/custom-toast-handlers\";\nimport {\n getMcpOAuthAuthenticationConfig,\n getInstallableMcpConnectionOption,\n type McpMarketplaceConnectionOption,\n} from \"#/utils/mcp-marketplace-utils\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { useSaveFieldsAsSecrets } from \"#/hooks/mutation/use-save-fields-as-secrets\";\nimport { makeMcpTestErrorMessage } from \"#/utils/mcp-test-error-message\";\nimport { modalTitleLgClassName } from \"#/utils/modal-classes\";\nimport McpService from \"#/api/mcp-service/mcp-service.api\";\nimport { toMcpServerName } from \"#/utils/mcp-server-name\";\n\n/**\n * Renders a helperText string as React nodes, converting any `[text](url)`\n * markdown links into real `<a>` elements. Plain text segments are left as-is.\n * Only `http:` and `https:` URLs are rendered as links; anything else falls\n * back to `#` to guard against `javascript:` / `data:` XSS vectors.\n */\nfunction renderHelperText(text: string): React.ReactNode {\n const linkPattern = /\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\n const parts: React.ReactNode[] = [];\n let lastIndex = 0;\n for (const match of text.matchAll(linkPattern)) {\n if (match.index > lastIndex) {\n parts.push(text.slice(lastIndex, match.index));\n }\n parts.push(\n <a\n key={match.index}\n href={/^https?:\\/\\//i.test(match[2]) ? match[2] : \"#\"}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"underline hover:text-white transition-colors\"\n >\n {match[1]}\n </a>,\n );\n lastIndex = match.index + match[0].length;\n }\n if (lastIndex < text.length) {\n parts.push(text.slice(lastIndex));\n }\n return parts;\n}\n\ninterface InstallServerModalProps {\n entry: MarketplaceEntry;\n /** Servers installed before this modal opened — guards health seeding. */\n existingServers: MCPServerConfig[];\n onClose: () => void;\n onSuccess?: (entry: MarketplaceEntry) => void;\n}\n\ninterface FieldState {\n values: Record<string, string>;\n errors: Record<string, string | null>;\n savedAsSecret: Record<string, boolean>;\n}\n\nfunction optionNeedsCredentialField(\n option: McpMarketplaceConnectionOption | undefined,\n): boolean {\n if (option?.transport.kind !== \"shttp\" && option?.transport.kind !== \"sse\") {\n return false;\n }\n return [\"api_key\", \"bearer\"].includes(option.auth.strategy);\n}\n\nfunction isOAuthOption(\n option: McpMarketplaceConnectionOption | undefined,\n): boolean {\n return !!option && option.auth.strategy === \"oauth2\";\n}\n\nfunction isCredentialOptional(option: McpMarketplaceConnectionOption): boolean {\n if (option.transport.kind === \"stdio\") {\n return option.auth.apiKeyOptional ?? false;\n }\n return option.auth.apiKeyOptional ?? option.transport.apiKeyOptional ?? false;\n}\n\nfunction getRemoteHeaderFields(\n option: McpMarketplaceConnectionOption | undefined,\n): MarketplaceField[] {\n if (option?.transport.kind !== \"shttp\" && option?.transport.kind !== \"sse\") {\n return [];\n }\n return option.transport.headerFields ?? [];\n}\n\nfunction makeInitialState(entry: MarketplaceEntry): FieldState {\n const values: Record<string, string> = {};\n const savedAsSecret: Record<string, boolean> = {};\n const option = getInstallableMcpConnectionOption(entry);\n const template = option?.transport;\n if (template?.kind === \"stdio\") {\n for (const field of template.envFields ?? []) {\n values[field.key] = \"\";\n // Pre-check password fields; non-password fields default to off.\n savedAsSecret[field.key] = field.type === \"password\";\n }\n for (const field of template.argFields ?? []) {\n values[field.key] = \"\";\n }\n } else if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n values.url = template.url;\n for (const field of getRemoteHeaderFields(option)) {\n values[field.key] = \"\";\n savedAsSecret[field.key] = field.type === \"password\";\n }\n if (optionNeedsCredentialField(option)) {\n values.api_key = \"\";\n if (option?.auth.credentialSecretName) {\n savedAsSecret.api_key =\n option.auth.saveCredentialAsSecretByDefault ?? false;\n }\n }\n }\n return { values, errors: {}, savedAsSecret };\n}\n\n// The marketplace install modal is intentionally add-only: clicking\n// a catalog tile always appends a new server (the user might want\n// two Slack workspaces, two Postgres connections, etc.) even when\n// one of the same template kind is already installed. Editing an\n// existing server is reached via the installed-server-card's edit\n// button, which opens `CustomServerEditor` instead.\nexport function InstallServerModal({\n entry,\n existingServers,\n onClose,\n onSuccess,\n}: InstallServerModalProps) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: addMcpServer, isPending: isAdding } = useAddMcpServer();\n const { mutate: testMcpServer, isPending: isTesting } = useTestMcpServer();\n const saveFieldsAsSecrets = useSaveFieldsAsSecrets();\n // Cloud backends get a synthetic test success (no local test endpoint);\n // never seed card health from it.\n const { backend } = useActiveBackend();\n const isCloudBackend = backend.kind === \"cloud\";\n\n const [state, setState] = React.useState<FieldState>(() =>\n makeInitialState(entry),\n );\n // Always holds the latest state so async callbacks (onSuccess) never read\n // stale closure values, even under React concurrent-mode scheduling.\n const stateRef = React.useRef(state);\n stateRef.current = state;\n\n const [globalError, setGlobalError] = React.useState<string | null>(null);\n const [isFinalizingInstall, setIsFinalizingInstall] = React.useState(false);\n const [isAuthorizingOAuth, setIsAuthorizingOAuth] = React.useState(false);\n const option = getInstallableMcpConnectionOption(entry);\n const template = option?.transport;\n\n const isPending =\n isTesting || isAuthorizingOAuth || isAdding || isFinalizingInstall;\n\n const setValue = (key: string, value: string) => {\n setState((prev) => ({\n ...prev,\n values: { ...prev.values, [key]: value },\n errors: { ...prev.errors, [key]: null },\n }));\n setGlobalError(null);\n };\n\n const toggleSecret = (key: string, value: boolean) => {\n setState((prev) => ({\n ...prev,\n savedAsSecret: { ...prev.savedAsSecret, [key]: value },\n }));\n };\n\n const saveHostedCredentialAsSecret = (): Promise<void> => {\n const secretName = option?.auth.credentialSecretName;\n const apiKey = stateRef.current.values.api_key?.trim();\n if (!secretName || !apiKey || !stateRef.current.savedAsSecret.api_key) {\n return Promise.resolve();\n }\n\n const field: MarketplaceField = {\n key: secretName,\n label: option.auth.credentialLabel ?? secretName,\n type: \"password\",\n required: true,\n };\n return saveFieldsAsSecrets(\n [field],\n { [secretName]: apiKey },\n { [secretName]: true },\n );\n };\n\n const saveSelectedSecrets = (): Promise<void> => {\n if (template?.kind === \"stdio\") {\n return saveFieldsAsSecrets(\n template.envFields ?? [],\n stateRef.current.values,\n stateRef.current.savedAsSecret,\n );\n }\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n return Promise.all([\n saveHostedCredentialAsSecret(),\n saveFieldsAsSecrets(\n getRemoteHeaderFields(option),\n stateRef.current.values,\n stateRef.current.savedAsSecret,\n ),\n ]).then(() => undefined);\n }\n return Promise.resolve();\n };\n\n const submitServer = (payload: MCPServerConfig) => {\n if (payload.auth?.strategy === \"oauth2\") {\n setIsAuthorizingOAuth(true);\n void McpService.authorizeOAuth(payload)\n .then((result) => {\n if (!result.ok) {\n setGlobalError(\n makeMcpTestErrorMessage(t, result.error_kind, result.error),\n );\n return;\n }\n const serverToSave = result.oauth_state\n ? {\n ...payload,\n auth: { ...payload.auth!, state: result.oauth_state },\n }\n : payload;\n addMcpServer(serverToSave, {\n onSuccess: () => {\n if (!isCloudBackend) {\n seedMcpServerHealth(serverToSave, result, existingServers);\n }\n displaySuccessToast(t(I18nKey.MCP$INSTALL_SUCCESS));\n setIsFinalizingInstall(true);\n void (async () => {\n try {\n await saveSelectedSecrets();\n } finally {\n onSuccess?.(entry);\n onClose();\n }\n })();\n },\n onError: (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n },\n });\n })\n .catch((err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n })\n .finally(() => setIsAuthorizingOAuth(false));\n return;\n }\n testMcpServer(payload, {\n onSuccess: (result) => {\n if (!result.ok) {\n setGlobalError(\n makeMcpTestErrorMessage(t, result.error_kind, result.error),\n );\n // Modal stays open — do NOT call onClose.\n return;\n }\n const serverToSave =\n result.oauth_state && payload.auth?.strategy === \"oauth2\"\n ? {\n ...payload,\n auth: { ...payload.auth, state: result.oauth_state },\n }\n : payload;\n addMcpServer(serverToSave, {\n onSuccess: () => {\n if (!isCloudBackend) {\n seedMcpServerHealth(serverToSave, result, existingServers);\n }\n displaySuccessToast(t(I18nKey.MCP$INSTALL_SUCCESS));\n setIsFinalizingInstall(true);\n void (async () => {\n try {\n await saveSelectedSecrets();\n } finally {\n onSuccess?.(entry);\n onClose();\n }\n })();\n },\n onError: (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n },\n });\n },\n onError: (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n },\n });\n };\n\n // ------------------------------------------------------------------\n // Per-template submit handlers. Each is small and self-contained:\n // validate user input, build the payload, then hand off to\n // submitServer.\n // ------------------------------------------------------------------\n const handleHttpServerSubmit = () => {\n // TS narrows this branch to shttp|sse; the equality guard is a\n // runtime/defensive belt to make the helper safe in isolation.\n if (template?.kind !== \"shttp\" && template?.kind !== \"sse\") {\n return;\n }\n if (!option) return;\n const apiKey = state.values.api_key?.trim() ?? \"\";\n const url = template.urlEditable\n ? (state.values.url?.trim() ?? \"\")\n : template.url;\n const oauthMode = isOAuthOption(option);\n const needsCredential = optionNeedsCredentialField(option);\n const headerFields = getRemoteHeaderFields(option);\n const headerErrors: Record<string, string | null> = {};\n if (!url) {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_REQUIRED);\n } else {\n try {\n const parsedUrl = new URL(url);\n if (![\"http:\", \"https:\"].includes(parsedUrl.protocol)) {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_INVALID_PROTOCOL);\n }\n } catch {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_INVALID);\n }\n }\n for (const field of headerFields) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n headerErrors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n if (\n !oauthMode &&\n needsCredential &&\n !isCredentialOptional(option) &&\n !apiKey\n ) {\n headerErrors.api_key = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n if (Object.values(headerErrors).some(Boolean)) {\n setState((prev) => ({ ...prev, errors: headerErrors }));\n return;\n }\n const oauthAuthentication = oauthMode\n ? getMcpOAuthAuthenticationConfig(option)\n : undefined;\n const fieldHeaders = Object.fromEntries(\n headerFields\n .map((field) => [field.key, state.values[field.key]?.trim() ?? \"\"])\n .filter(([, value]) => value),\n );\n const hasFieldHeaders = Object.keys(fieldHeaders).length > 0;\n let auth: MCPAuthCredential | undefined;\n if (oauthMode) {\n auth = {\n strategy: \"oauth2\",\n ...(oauthAuthentication && { authentication: oauthAuthentication }),\n };\n } else if (needsCredential && apiKey) {\n auth =\n option.auth.strategy === \"api_key\"\n ? {\n strategy: \"api_key\",\n value: apiKey,\n ...(option.auth.apiKeyHeaderName && {\n header_name: option.auth.apiKeyHeaderName,\n }),\n }\n : { strategy: \"bearer\", value: apiKey };\n } else if (hasFieldHeaders) {\n auth = { strategy: \"header\", headers: fieldHeaders };\n }\n const payload: MCPServerConfig = {\n id: `${template.kind}-${uuidv4()}`,\n type: template.kind,\n // Name remote servers after the catalog slug (e.g. \"github\") so they\n // get a referenceable, LLM-tool-safe mcp_config key instead of the\n // auto-generated \"sse\"/\"shttp\" fallback. Stdio installs already carry\n // serverName from the catalog.\n name: toMcpServerName(entry.id),\n url,\n ...(auth && { auth }),\n ...(hasFieldHeaders &&\n auth?.strategy !== \"header\" && { headers: fieldHeaders }),\n };\n submitServer(payload);\n };\n\n const handleStdioSubmit = () => {\n if (template?.kind !== \"stdio\") return;\n const stdio = template;\n const errors: Record<string, string | null> = {};\n\n for (const field of stdio.envFields ?? []) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n errors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n for (const field of stdio.argFields ?? []) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n errors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n if (Object.values(errors).some(Boolean)) {\n setState((prev) => ({ ...prev, errors }));\n return;\n }\n\n const env: Record<string, string> = {};\n for (const field of stdio.envFields ?? []) {\n const v = state.values[field.key]?.trim();\n if (v) env[field.key] = v;\n }\n const extraArgs: string[] = [];\n for (const field of stdio.argFields ?? []) {\n const v = state.values[field.key]?.trim();\n if (v) {\n // Filesystem-style multi-token input: split on whitespace.\n for (const token of v.split(/\\s+/)) {\n if (token) extraArgs.push(token);\n }\n }\n }\n\n const payload: MCPServerConfig = {\n id: `stdio-${uuidv4()}`,\n type: \"stdio\",\n name: stdio.serverName,\n command: stdio.command,\n args: [...stdio.args, ...extraArgs],\n ...(Object.keys(env).length > 0 && { env }),\n };\n submitServer(payload);\n };\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setGlobalError(null);\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n return handleHttpServerSubmit();\n }\n return handleStdioSubmit();\n };\n\n const renderFields = () => {\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n const oauthMode = isOAuthOption(option);\n const shouldRenderCredential = optionNeedsCredentialField(option);\n const apiKeyOptional = option ? isCredentialOptional(option) : false;\n const credentialSecretName = option?.auth.credentialSecretName;\n const headerFields = getRemoteHeaderFields(option);\n return (\n <>\n <SettingsInput\n testId=\"mcp-install-field-url\"\n name=\"url\"\n type=\"url\"\n label={t(I18nKey.SETTINGS$MCP_URL)}\n value={state.values.url ?? template.url}\n onChange={(value) => setValue(\"url\", value)}\n isDisabled={!template.urlEditable}\n className=\"w-full\"\n />\n {state.errors.url && (\n <p className=\"text-xs text-red-500\">{state.errors.url}</p>\n )}\n {headerFields.map((field) => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <SettingsInput\n testId={`mcp-install-field-${field.key}`}\n name={field.key}\n type={field.type === \"password\" ? \"password\" : \"text\"}\n label={field.label}\n value={state.values[field.key] ?? \"\"}\n onChange={(v) => setValue(field.key, v)}\n placeholder={field.placeholder}\n required={field.required}\n showOptionalTag={!field.required}\n className=\"w-full\"\n />\n {field.helperText && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(field.helperText)}\n </p>\n )}\n {state.errors[field.key] && (\n <p className=\"text-xs text-red-500\">\n {state.errors[field.key]}\n </p>\n )}\n {field.key in state.savedAsSecret && (\n <SaveAsSecretToggle\n fieldKey={field.key}\n checked={state.savedAsSecret[field.key] ?? false}\n onToggle={(v) => toggleSecret(field.key, v)}\n />\n )}\n </div>\n ))}\n {oauthMode ? (\n <div\n data-testid=\"mcp-install-oauth-info\"\n className=\"flex flex-col gap-2 p-3 rounded-lg border border-[var(--oh-border)] bg-base-tertiary\"\n >\n <p className=\"text-sm text-secondary-light\">\n {t(I18nKey.MCP$OAUTH_CONNECT_INFO)}\n </p>\n <p className=\"text-xs text-tertiary-alt\">\n {t(I18nKey.MCP$OAUTH_CONNECT_HINT)}\n </p>\n </div>\n ) : shouldRenderCredential ? (\n <div className=\"flex flex-col gap-1\">\n <SettingsInput\n testId=\"mcp-install-field-api_key\"\n name=\"api_key\"\n type=\"password\"\n label={\n option?.auth.credentialLabel ??\n t(I18nKey.SETTINGS$MCP_API_KEY)\n }\n value={state.values.api_key ?? \"\"}\n onChange={(v) => setValue(\"api_key\", v)}\n placeholder={\n option?.auth.credentialPlaceholder ??\n t(I18nKey.SETTINGS$MCP_API_KEY_PLACEHOLDER)\n }\n showOptionalTag={apiKeyOptional}\n required={!apiKeyOptional}\n className=\"w-full\"\n />\n {option?.auth.credentialHelp && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(option.auth.credentialHelp)}\n </p>\n )}\n {state.errors.api_key && (\n <p className=\"text-xs text-red-500\">{state.errors.api_key}</p>\n )}\n {credentialSecretName && (\n <SaveAsSecretToggle\n fieldKey={credentialSecretName}\n checked={state.savedAsSecret.api_key ?? false}\n onToggle={(v) => toggleSecret(\"api_key\", v)}\n />\n )}\n </div>\n ) : null}\n </>\n );\n }\n\n if (template?.kind !== \"stdio\") return null;\n const stdio = template;\n return (\n <>\n <SettingsInput\n testId=\"mcp-install-field-command-readonly\"\n name=\"command-readonly\"\n type=\"text\"\n label={t(I18nKey.MCP$COMMAND_LABEL)}\n value={`${stdio.command} ${stdio.args.join(\" \")}`.trim()}\n onChange={() => {}}\n isDisabled\n className=\"w-full\"\n />\n {(stdio.envFields ?? []).map((field) => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <SettingsInput\n testId={`mcp-install-field-${field.key}`}\n name={field.key}\n type={field.type === \"password\" ? \"password\" : \"text\"}\n label={field.label}\n value={state.values[field.key] ?? \"\"}\n onChange={(v) => setValue(field.key, v)}\n placeholder={field.placeholder}\n required={field.required}\n showOptionalTag={!field.required}\n className=\"w-full\"\n />\n {field.helperText && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(field.helperText)}\n </p>\n )}\n {state.errors[field.key] && (\n <p className=\"text-xs text-red-500\">{state.errors[field.key]}</p>\n )}\n {field.key in state.savedAsSecret && (\n <SaveAsSecretToggle\n fieldKey={field.key}\n checked={state.savedAsSecret[field.key]}\n onToggle={(v) => toggleSecret(field.key, v)}\n />\n )}\n </div>\n ))}\n {/* argFields are CLI arguments, not credentials — they don't need\n a \"save as secret\" toggle and are excluded from savedAsSecret. */}\n {(stdio.argFields ?? []).map((field) => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <SettingsInput\n testId={`mcp-install-field-${field.key}`}\n name={field.key}\n type={field.type === \"password\" ? \"password\" : \"text\"}\n label={field.label}\n value={state.values[field.key] ?? \"\"}\n onChange={(v) => setValue(field.key, v)}\n placeholder={field.placeholder}\n required={field.required}\n showOptionalTag={!field.required}\n className=\"w-full\"\n />\n {field.helperText && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(field.helperText)}\n </p>\n )}\n {state.errors[field.key] && (\n <p className=\"text-xs text-red-500\">{state.errors[field.key]}</p>\n )}\n </div>\n ))}\n </>\n );\n };\n\n return (\n <ModalBackdrop onClose={onClose} aria-label={entry.name}>\n <form\n data-testid=\"mcp-install-modal\"\n data-marketplace-id={entry.id}\n onSubmit={handleSubmit}\n className=\"relative bg-base-secondary p-6 rounded-xl flex flex-col gap-4 border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[85vh] overflow-y-auto custom-scrollbar\"\n >\n <ModalCloseButton\n onClose={onClose}\n testId=\"mcp-install-modal-close\"\n disabled={isPending}\n />\n <div className=\"flex items-start gap-3 pr-6\">\n <McpLogoBadge entry={entry} />\n <div className=\"flex flex-col flex-1\">\n <h2 className={modalTitleLgClassName}>{entry.name}</h2>\n <p className=\"text-xs text-tertiary-light\">{entry.description}</p>\n </div>\n </div>\n\n {entry.installHint && (\n <p className=\"text-xs text-tertiary-light\">{entry.installHint}</p>\n )}\n\n {entry.docsUrl && (\n <a\n href={entry.docsUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-xs text-[var(--oh-muted)] hover:text-white hover:underline self-start transition-colors\"\n >\n {t(I18nKey.MCP$VIEW_DOCS)}\n </a>\n )}\n\n <div className=\"flex flex-col gap-3\">{renderFields()}</div>\n\n {globalError && (\n <p\n data-testid=\"mcp-install-modal-error\"\n className=\"text-sm text-red-500 whitespace-pre-wrap\"\n >\n {globalError}\n </p>\n )}\n\n <div className=\"flex justify-end gap-2 mt-2\">\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n onClick={onClose}\n testId=\"mcp-install-cancel\"\n isDisabled={isPending}\n >\n {t(I18nKey.BUTTON$CANCEL)}\n </BrandButton>\n <BrandButton\n type=\"submit\"\n variant=\"primary\"\n isDisabled={isPending}\n testId=\"mcp-install-submit\"\n >\n {isTesting || isAuthorizingOAuth\n ? t(I18nKey.MCP$VERIFYING)\n : isAdding || isFinalizingInstall\n ? t(I18nKey.SETTINGS$SAVING)\n : t(I18nKey.MCP$INSTALL_BUTTON)}\n </BrandButton>\n </div>\n </form>\n </ModalBackdrop>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../node_modules/lucide-react/dist/esm/icons/puzzle.cjs`),i=require(`../../../utils/utils.cjs`),a=require(`../../../utils/extension-module-card-classes.cjs`),o=require(`../../../utils/mcp-marketplace-utils.cjs`),s=require(`../../../node_modules/@openhands/extensions/integrations/index.cjs`),c=require(`../mcp-logo-badge.cjs`),l=require(`../../shared/buttons/circle-plus-check-toggle.cjs`),u=require(`../../../utils/mcp-installed-server-display.cjs`);let d=require(`react`);d=e.__toESM(d,1);let f=require(`react/jsx-runtime`);function p(e){switch(e){case`sse`:return`SSE`;case`shttp`:return`HTTP`;case`stdio`:return`STDIO`;default:return e}}function m(e){if(e.type===`stdio`){let t=e.args&&e.args.length>0?` ${e.args.join(` `)}`:``;return`${e.command??``}${t}`.trim()}return e.url??``}function h({server:e,onEdit:d,onDelete:h}){let{t:g}=t.useTranslation(`openhands`),_=o.findCatalogEntryForServer(e,o.getMcpMarketplaceCatalog(s.default)),v=u.getInstalledServerTitle(e,_),y=m(e),b=p(e.type);return(0,f.jsx)(`div`,{"data-testid":`mcp-server-item`,"data-server-id":e.id,role:`button`,tabIndex:0,onClick:d,onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),d())},"aria-label":g(n.I18nKey.MCP$EDIT_SERVER_ARIA,{name:v}),className:i.cn(`flex min-h-[132px] flex-col overflow-hidden p-4 text-left`,a.extensionModuleCardSurfaceClassName,a.extensionModuleCardInteractiveClassName),children:(0,f.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,f.jsx)(c.McpLogoBadge,{entry:_,fallback:(0,f.jsx)(r.Puzzle,{strokeWidth:2.25})}),(0,f.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col gap-3`,children:[(0,f.jsxs)(`header`,{className:`flex items-start justify-between gap-3`,children:[(0,f.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,f.jsx)(`h3`,{className:`truncate text-sm font-semibold`,title:v,children:v}),(0,f.jsx)(`p`,{className:`mt-0.5 text-xs text-tertiary-alt`,children:b})]}),(0,f.jsx)(l.CirclePlusCheckToggle,{testId:`mcp-installed-toggle-${e.id}`,isSelected:!0,onToggle:e=>{e||h()},enableLabelKey:n.I18nKey.MCP$TOGGLE_ADD_SERVER,disableLabelKey:n.I18nKey.MCP$TOGGLE_REMOVE_SERVER})]}),_?.description?(0,f.jsx)(`p`,{"data-testid":`mcp-server-description-${e.id}`,className:`line-clamp-2 break-words text-xs leading-relaxed text-tertiary-light`,children:_.description}):null,y?(0,f.jsx)(`p`,{"data-testid":`mcp-server-detail-${e.id}`,className:`truncate text-xs text-tertiary-alt`,title:y,children:y}):null]})]})})}exports.InstalledServerCard=h;
1
+ const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../node_modules/lucide-react/dist/esm/icons/puzzle.cjs`),i=require(`../../../utils/utils.cjs`),a=require(`../../../utils/extension-module-card-classes.cjs`),o=require(`../../../utils/mcp-marketplace-utils.cjs`),s=require(`../../../node_modules/@openhands/extensions/integrations/index.cjs`),c=require(`../mcp-logo-badge.cjs`),l=require(`../../shared/buttons/circle-plus-check-toggle.cjs`),u=require(`../../../utils/mcp-installed-server-display.cjs`),d=require(`./mcp-server-health.cjs`);let f=require(`react`);f=e.__toESM(f,1);let p=require(`react/jsx-runtime`);function m(e){switch(e){case`sse`:return`SSE`;case`shttp`:return`HTTP`;case`stdio`:return`STDIO`;default:return e}}function h(e){if(e.type===`stdio`){let t=e.args&&e.args.length>0?` ${e.args.join(` `)}`:``;return`${e.command??``}${t}`.trim()}return e.url??``}function g({server:e,onEdit:f,onDelete:g}){let{t:_}=t.useTranslation(`openhands`),v=o.findCatalogEntryForServer(e,o.getMcpMarketplaceCatalog(s.default)),y=u.getInstalledServerTitle(e,v),b=h(e),x=m(e.type);return(0,p.jsx)(`div`,{"data-testid":`mcp-server-item`,"data-server-id":e.id,role:`button`,tabIndex:0,onClick:f,onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),f())},"aria-label":_(n.I18nKey.MCP$EDIT_SERVER_ARIA,{name:y}),className:i.cn(`flex min-h-[132px] flex-col overflow-hidden p-4 text-left`,a.extensionModuleCardSurfaceClassName,a.extensionModuleCardInteractiveClassName),children:(0,p.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,p.jsx)(c.McpLogoBadge,{entry:v,fallback:(0,p.jsx)(r.Puzzle,{strokeWidth:2.25})}),(0,p.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col gap-3`,children:[(0,p.jsxs)(`header`,{className:`flex items-start justify-between gap-3`,children:[(0,p.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,p.jsx)(`h3`,{className:`truncate text-sm font-semibold`,title:y,children:y}),(0,p.jsx)(`p`,{className:`mt-0.5 text-xs text-tertiary-alt`,children:x})]}),(0,p.jsx)(l.CirclePlusCheckToggle,{testId:`mcp-installed-toggle-${e.id}`,isSelected:!0,onToggle:e=>{e||g()},enableLabelKey:n.I18nKey.MCP$TOGGLE_ADD_SERVER,disableLabelKey:n.I18nKey.MCP$TOGGLE_REMOVE_SERVER})]}),v?.description?(0,p.jsx)(`p`,{"data-testid":`mcp-server-description-${e.id}`,className:`line-clamp-2 break-words text-xs leading-relaxed text-tertiary-light`,children:v.description}):null,b?(0,p.jsx)(`p`,{"data-testid":`mcp-server-detail-${e.id}`,className:`truncate text-xs text-tertiary-alt`,title:b,children:b}):null,(0,p.jsx)(d.McpServerHealthSection,{server:e,catalog:v,onEdit:f})]})]})})}exports.InstalledServerCard=g;
2
2
  //# sourceMappingURL=installed-server-card.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"installed-server-card.cjs","names":[],"sources":["../../../../src/components/features/mcp-page/installed-server-card.tsx"],"sourcesContent":["import React from \"react\";\nimport { Puzzle } from \"lucide-react\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { McpLogoBadge } from \"#/components/features/mcp-logo-badge\";\nimport { CirclePlusCheckToggle } from \"#/components/shared/buttons/circle-plus-check-toggle\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { INTEGRATION_CATALOG as MCP_MARKETPLACE } from \"@openhands/extensions/integrations\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n} from \"#/utils/mcp-marketplace-utils\";\nimport { cn } from \"#/utils/utils\";\nimport {\n extensionModuleCardInteractiveClassName,\n extensionModuleCardSurfaceClassName,\n} from \"#/utils/extension-module-card-classes\";\nimport { getInstalledServerTitle } from \"#/utils/mcp-installed-server-display\";\n\ninterface InstalledServerCardProps {\n server: MCPServerConfig;\n onEdit: () => void;\n onDelete: () => void;\n}\n\nfunction getServerTransportLabel(type: MCPServerConfig[\"type\"]) {\n switch (type) {\n case \"sse\":\n return \"SSE\";\n case \"shttp\":\n return \"HTTP\";\n case \"stdio\":\n return \"STDIO\";\n default:\n return type;\n }\n}\n\nfunction getServerDetailLine(server: MCPServerConfig): string {\n if (server.type === \"stdio\") {\n const args =\n server.args && server.args.length > 0 ? ` ${server.args.join(\" \")}` : \"\";\n return `${server.command ?? \"\"}${args}`.trim();\n }\n return server.url ?? \"\";\n}\n\nexport function InstalledServerCard({\n server,\n onEdit,\n onDelete,\n}: InstalledServerCardProps) {\n const { t } = useTranslation(\"openhands\");\n const catalog = findCatalogEntryForServer(\n server,\n getMcpMarketplaceCatalog(MCP_MARKETPLACE),\n );\n\n const title = getInstalledServerTitle(server, catalog);\n const detailLine = getServerDetailLine(server);\n const transport = getServerTransportLabel(server.type);\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onEdit();\n }\n };\n\n return (\n <div\n data-testid=\"mcp-server-item\"\n data-server-id={server.id}\n role=\"button\"\n tabIndex={0}\n onClick={onEdit}\n onKeyDown={handleKeyDown}\n aria-label={t(I18nKey.MCP$EDIT_SERVER_ARIA, { name: title })}\n className={cn(\n \"flex min-h-[132px] flex-col overflow-hidden p-4 text-left\",\n extensionModuleCardSurfaceClassName,\n extensionModuleCardInteractiveClassName,\n )}\n >\n <div className=\"flex items-start gap-3\">\n <McpLogoBadge\n entry={catalog}\n fallback={<Puzzle strokeWidth={2.25} />}\n />\n\n <div className=\"flex min-w-0 flex-1 flex-col gap-3\">\n <header className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-sm font-semibold\" title={title}>\n {title}\n </h3>\n <p className=\"mt-0.5 text-xs text-tertiary-alt\">{transport}</p>\n </div>\n <CirclePlusCheckToggle\n testId={`mcp-installed-toggle-${server.id}`}\n isSelected\n onToggle={(selected) => {\n if (!selected) {\n onDelete();\n }\n }}\n enableLabelKey={I18nKey.MCP$TOGGLE_ADD_SERVER}\n disableLabelKey={I18nKey.MCP$TOGGLE_REMOVE_SERVER}\n />\n </header>\n\n {catalog?.description ? (\n <p\n data-testid={`mcp-server-description-${server.id}`}\n className=\"line-clamp-2 break-words text-xs leading-relaxed text-tertiary-light\"\n >\n {catalog.description}\n </p>\n ) : null}\n\n {detailLine ? (\n <p\n data-testid={`mcp-server-detail-${server.id}`}\n className=\"truncate text-xs text-tertiary-alt\"\n title={detailLine}\n >\n {detailLine}\n </p>\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"gtBAyBA,SAAS,EAAwB,EAA+B,CAC9D,OAAQ,EAAR,CACE,IAAK,MACH,MAAO,MACT,IAAK,QACH,MAAO,OACT,IAAK,QACH,MAAO,QACT,QACE,OAAO,GAIb,SAAS,EAAoB,EAAiC,CAC5D,GAAI,EAAO,OAAS,QAAS,CAC3B,IAAM,EACJ,EAAO,MAAQ,EAAO,KAAK,OAAS,EAAI,IAAI,EAAO,KAAK,KAAK,IAAI,GAAK,GACxE,MAAO,GAAG,EAAO,SAAW,KAAK,IAAO,MAAM,CAEhD,OAAO,EAAO,KAAO,GAGvB,SAAgB,EAAoB,CAClC,SACA,SACA,YAC2B,CAC3B,GAAM,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,EAAU,EAAA,0BACd,EACA,EAAA,yBAAyB,EAAA,QAAgB,CAC1C,CAEK,EAAQ,EAAA,wBAAwB,EAAQ,EAAQ,CAChD,EAAa,EAAoB,EAAO,CACxC,EAAY,EAAwB,EAAO,KAAK,CAStD,OACE,EAAA,EAAA,KAAC,MAAD,CACE,cAAY,kBACZ,iBAAgB,EAAO,GACvB,KAAK,SACL,SAAU,EACV,QAAS,EACT,UAdmB,GAA+B,EAChD,EAAM,MAAQ,SAAW,EAAM,MAAQ,OACzC,EAAM,gBAAgB,CACtB,GAAQ,GAYR,aAAY,EAAE,EAAA,QAAQ,qBAAsB,CAAE,KAAM,EAAO,CAAC,CAC5D,UAAW,EAAA,GACT,4DACA,EAAA,oCACA,EAAA,wCACD,WAED,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,kCAAf,EACE,EAAA,EAAA,KAAC,EAAA,aAAD,CACE,MAAO,EACP,UAAU,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,YAAa,KAAQ,CAAA,CACvC,CAAA,EAEF,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,8CAAf,EACE,EAAA,EAAA,MAAC,SAAD,CAAQ,UAAU,kDAAlB,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,iCAAwC,iBACnD,EACE,CAAA,EACL,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,4CAAoC,EAAc,CAAA,CAC3D,IACN,EAAA,EAAA,KAAC,EAAA,sBAAD,CACE,OAAQ,wBAAwB,EAAO,KACvC,WAAA,GACA,SAAW,GAAa,CACjB,GACH,GAAU,EAGd,eAAgB,EAAA,QAAQ,sBACxB,gBAAiB,EAAA,QAAQ,yBACzB,CAAA,CACK,GAER,GAAS,aACR,EAAA,EAAA,KAAC,IAAD,CACE,cAAa,0BAA0B,EAAO,KAC9C,UAAU,gFAET,EAAQ,YACP,CAAA,CACF,KAEH,GACC,EAAA,EAAA,KAAC,IAAD,CACE,cAAa,qBAAqB,EAAO,KACzC,UAAU,qCACV,MAAO,WAEN,EACC,CAAA,CACF,KACA,GACF,GACF,CAAA"}
1
+ {"version":3,"file":"installed-server-card.cjs","names":[],"sources":["../../../../src/components/features/mcp-page/installed-server-card.tsx"],"sourcesContent":["import React from \"react\";\nimport { Puzzle } from \"lucide-react\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { McpLogoBadge } from \"#/components/features/mcp-logo-badge\";\nimport { CirclePlusCheckToggle } from \"#/components/shared/buttons/circle-plus-check-toggle\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { INTEGRATION_CATALOG as MCP_MARKETPLACE } from \"@openhands/extensions/integrations\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n} from \"#/utils/mcp-marketplace-utils\";\nimport { cn } from \"#/utils/utils\";\nimport {\n extensionModuleCardInteractiveClassName,\n extensionModuleCardSurfaceClassName,\n} from \"#/utils/extension-module-card-classes\";\nimport { getInstalledServerTitle } from \"#/utils/mcp-installed-server-display\";\nimport { McpServerHealthSection } from \"./mcp-server-health\";\n\ninterface InstalledServerCardProps {\n server: MCPServerConfig;\n onEdit: () => void;\n onDelete: () => void;\n}\n\nfunction getServerTransportLabel(type: MCPServerConfig[\"type\"]) {\n switch (type) {\n case \"sse\":\n return \"SSE\";\n case \"shttp\":\n return \"HTTP\";\n case \"stdio\":\n return \"STDIO\";\n default:\n return type;\n }\n}\n\nfunction getServerDetailLine(server: MCPServerConfig): string {\n if (server.type === \"stdio\") {\n const args =\n server.args && server.args.length > 0 ? ` ${server.args.join(\" \")}` : \"\";\n return `${server.command ?? \"\"}${args}`.trim();\n }\n return server.url ?? \"\";\n}\n\nexport function InstalledServerCard({\n server,\n onEdit,\n onDelete,\n}: InstalledServerCardProps) {\n const { t } = useTranslation(\"openhands\");\n const catalog = findCatalogEntryForServer(\n server,\n getMcpMarketplaceCatalog(MCP_MARKETPLACE),\n );\n\n const title = getInstalledServerTitle(server, catalog);\n const detailLine = getServerDetailLine(server);\n const transport = getServerTransportLabel(server.type);\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onEdit();\n }\n };\n\n return (\n <div\n data-testid=\"mcp-server-item\"\n data-server-id={server.id}\n role=\"button\"\n tabIndex={0}\n onClick={onEdit}\n onKeyDown={handleKeyDown}\n aria-label={t(I18nKey.MCP$EDIT_SERVER_ARIA, { name: title })}\n className={cn(\n \"flex min-h-[132px] flex-col overflow-hidden p-4 text-left\",\n extensionModuleCardSurfaceClassName,\n extensionModuleCardInteractiveClassName,\n )}\n >\n <div className=\"flex items-start gap-3\">\n <McpLogoBadge\n entry={catalog}\n fallback={<Puzzle strokeWidth={2.25} />}\n />\n\n <div className=\"flex min-w-0 flex-1 flex-col gap-3\">\n <header className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-sm font-semibold\" title={title}>\n {title}\n </h3>\n <p className=\"mt-0.5 text-xs text-tertiary-alt\">{transport}</p>\n </div>\n <CirclePlusCheckToggle\n testId={`mcp-installed-toggle-${server.id}`}\n isSelected\n onToggle={(selected) => {\n if (!selected) {\n onDelete();\n }\n }}\n enableLabelKey={I18nKey.MCP$TOGGLE_ADD_SERVER}\n disableLabelKey={I18nKey.MCP$TOGGLE_REMOVE_SERVER}\n />\n </header>\n\n {catalog?.description ? (\n <p\n data-testid={`mcp-server-description-${server.id}`}\n className=\"line-clamp-2 break-words text-xs leading-relaxed text-tertiary-light\"\n >\n {catalog.description}\n </p>\n ) : null}\n\n {detailLine ? (\n <p\n data-testid={`mcp-server-detail-${server.id}`}\n className=\"truncate text-xs text-tertiary-alt\"\n title={detailLine}\n >\n {detailLine}\n </p>\n ) : null}\n\n <McpServerHealthSection\n server={server}\n catalog={catalog}\n onEdit={onEdit}\n />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"qvBA0BA,SAAS,EAAwB,EAA+B,CAC9D,OAAQ,EAAR,CACE,IAAK,MACH,MAAO,MACT,IAAK,QACH,MAAO,OACT,IAAK,QACH,MAAO,QACT,QACE,OAAO,GAIb,SAAS,EAAoB,EAAiC,CAC5D,GAAI,EAAO,OAAS,QAAS,CAC3B,IAAM,EACJ,EAAO,MAAQ,EAAO,KAAK,OAAS,EAAI,IAAI,EAAO,KAAK,KAAK,IAAI,GAAK,GACxE,MAAO,GAAG,EAAO,SAAW,KAAK,IAAO,MAAM,CAEhD,OAAO,EAAO,KAAO,GAGvB,SAAgB,EAAoB,CAClC,SACA,SACA,YAC2B,CAC3B,GAAM,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,EAAU,EAAA,0BACd,EACA,EAAA,yBAAyB,EAAA,QAAgB,CAC1C,CAEK,EAAQ,EAAA,wBAAwB,EAAQ,EAAQ,CAChD,EAAa,EAAoB,EAAO,CACxC,EAAY,EAAwB,EAAO,KAAK,CAStD,OACE,EAAA,EAAA,KAAC,MAAD,CACE,cAAY,kBACZ,iBAAgB,EAAO,GACvB,KAAK,SACL,SAAU,EACV,QAAS,EACT,UAdmB,GAA+B,EAChD,EAAM,MAAQ,SAAW,EAAM,MAAQ,OACzC,EAAM,gBAAgB,CACtB,GAAQ,GAYR,aAAY,EAAE,EAAA,QAAQ,qBAAsB,CAAE,KAAM,EAAO,CAAC,CAC5D,UAAW,EAAA,GACT,4DACA,EAAA,oCACA,EAAA,wCACD,WAED,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,kCAAf,EACE,EAAA,EAAA,KAAC,EAAA,aAAD,CACE,MAAO,EACP,UAAU,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,YAAa,KAAQ,CAAA,CACvC,CAAA,EAEF,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,8CAAf,EACE,EAAA,EAAA,MAAC,SAAD,CAAQ,UAAU,kDAAlB,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,iCAAwC,iBACnD,EACE,CAAA,EACL,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,4CAAoC,EAAc,CAAA,CAC3D,IACN,EAAA,EAAA,KAAC,EAAA,sBAAD,CACE,OAAQ,wBAAwB,EAAO,KACvC,WAAA,GACA,SAAW,GAAa,CACjB,GACH,GAAU,EAGd,eAAgB,EAAA,QAAQ,sBACxB,gBAAiB,EAAA,QAAQ,yBACzB,CAAA,CACK,GAER,GAAS,aACR,EAAA,EAAA,KAAC,IAAD,CACE,cAAa,0BAA0B,EAAO,KAC9C,UAAU,gFAET,EAAQ,YACP,CAAA,CACF,KAEH,GACC,EAAA,EAAA,KAAC,IAAD,CACE,cAAa,qBAAqB,EAAO,KACzC,UAAU,qCACV,MAAO,WAEN,EACC,CAAA,CACF,MAEJ,EAAA,EAAA,KAAC,EAAA,uBAAD,CACU,SACC,UACD,SACR,CAAA,CACE,GACF,GACF,CAAA"}
@@ -8,10 +8,11 @@ import c from "../../../node_modules/@openhands/extensions/integrations/index.js
8
8
  import { McpLogoBadge as l } from "../mcp-logo-badge.js";
9
9
  import { CirclePlusCheckToggle as u } from "../../shared/buttons/circle-plus-check-toggle.js";
10
10
  import { getInstalledServerTitle as d } from "../../../utils/mcp-installed-server-display.js";
11
+ import { McpServerHealthSection as f } from "./mcp-server-health.js";
11
12
  import "react";
12
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
13
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
13
14
  //#region src/components/features/mcp-page/installed-server-card.tsx
14
- function m(e) {
15
+ function h(e) {
15
16
  switch (e) {
16
17
  case "sse": return "SSE";
17
18
  case "shttp": return "HTTP";
@@ -19,73 +20,78 @@ function m(e) {
19
20
  default: return e;
20
21
  }
21
22
  }
22
- function h(e) {
23
+ function g(e) {
23
24
  if (e.type === "stdio") {
24
25
  let t = e.args && e.args.length > 0 ? ` ${e.args.join(" ")}` : "";
25
26
  return `${e.command ?? ""}${t}`.trim();
26
27
  }
27
28
  return e.url ?? "";
28
29
  }
29
- function g({ server: g, onEdit: _, onDelete: v }) {
30
- let { t: y } = e("openhands"), b = o(g, s(c)), x = d(g, b), S = h(g), C = m(g.type);
31
- return /* @__PURE__ */ f("div", {
30
+ function _({ server: _, onEdit: v, onDelete: y }) {
31
+ let { t: b } = e("openhands"), x = o(_, s(c)), S = d(_, x), C = g(_), w = h(_.type);
32
+ return /* @__PURE__ */ p("div", {
32
33
  "data-testid": "mcp-server-item",
33
- "data-server-id": g.id,
34
+ "data-server-id": _.id,
34
35
  role: "button",
35
36
  tabIndex: 0,
36
- onClick: _,
37
+ onClick: v,
37
38
  onKeyDown: (e) => {
38
- (e.key === "Enter" || e.key === " ") && (e.preventDefault(), _());
39
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), v());
39
40
  },
40
- "aria-label": y(t.MCP$EDIT_SERVER_ARIA, { name: x }),
41
+ "aria-label": b(t.MCP$EDIT_SERVER_ARIA, { name: S }),
41
42
  className: r("flex min-h-[132px] flex-col overflow-hidden p-4 text-left", a, i),
42
- children: /* @__PURE__ */ p("div", {
43
+ children: /* @__PURE__ */ m("div", {
43
44
  className: "flex items-start gap-3",
44
- children: [/* @__PURE__ */ f(l, {
45
- entry: b,
46
- fallback: /* @__PURE__ */ f(n, { strokeWidth: 2.25 })
47
- }), /* @__PURE__ */ p("div", {
45
+ children: [/* @__PURE__ */ p(l, {
46
+ entry: x,
47
+ fallback: /* @__PURE__ */ p(n, { strokeWidth: 2.25 })
48
+ }), /* @__PURE__ */ m("div", {
48
49
  className: "flex min-w-0 flex-1 flex-col gap-3",
49
50
  children: [
50
- /* @__PURE__ */ p("header", {
51
+ /* @__PURE__ */ m("header", {
51
52
  className: "flex items-start justify-between gap-3",
52
- children: [/* @__PURE__ */ p("div", {
53
+ children: [/* @__PURE__ */ m("div", {
53
54
  className: "min-w-0 flex-1",
54
- children: [/* @__PURE__ */ f("h3", {
55
+ children: [/* @__PURE__ */ p("h3", {
55
56
  className: "truncate text-sm font-semibold",
56
- title: x,
57
- children: x
58
- }), /* @__PURE__ */ f("p", {
57
+ title: S,
58
+ children: S
59
+ }), /* @__PURE__ */ p("p", {
59
60
  className: "mt-0.5 text-xs text-tertiary-alt",
60
- children: C
61
+ children: w
61
62
  })]
62
- }), /* @__PURE__ */ f(u, {
63
- testId: `mcp-installed-toggle-${g.id}`,
63
+ }), /* @__PURE__ */ p(u, {
64
+ testId: `mcp-installed-toggle-${_.id}`,
64
65
  isSelected: !0,
65
66
  onToggle: (e) => {
66
- e || v();
67
+ e || y();
67
68
  },
68
69
  enableLabelKey: t.MCP$TOGGLE_ADD_SERVER,
69
70
  disableLabelKey: t.MCP$TOGGLE_REMOVE_SERVER
70
71
  })]
71
72
  }),
72
- b?.description ? /* @__PURE__ */ f("p", {
73
- "data-testid": `mcp-server-description-${g.id}`,
73
+ x?.description ? /* @__PURE__ */ p("p", {
74
+ "data-testid": `mcp-server-description-${_.id}`,
74
75
  className: "line-clamp-2 break-words text-xs leading-relaxed text-tertiary-light",
75
- children: b.description
76
+ children: x.description
76
77
  }) : null,
77
- S ? /* @__PURE__ */ f("p", {
78
- "data-testid": `mcp-server-detail-${g.id}`,
78
+ C ? /* @__PURE__ */ p("p", {
79
+ "data-testid": `mcp-server-detail-${_.id}`,
79
80
  className: "truncate text-xs text-tertiary-alt",
80
- title: S,
81
- children: S
82
- }) : null
81
+ title: C,
82
+ children: C
83
+ }) : null,
84
+ /* @__PURE__ */ p(f, {
85
+ server: _,
86
+ catalog: x,
87
+ onEdit: v
88
+ })
83
89
  ]
84
90
  })]
85
91
  })
86
92
  });
87
93
  }
88
94
  //#endregion
89
- export { g as InstalledServerCard };
95
+ export { _ as InstalledServerCard };
90
96
 
91
97
  //# sourceMappingURL=installed-server-card.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"installed-server-card.js","names":[],"sources":["../../../../src/components/features/mcp-page/installed-server-card.tsx"],"sourcesContent":["import React from \"react\";\nimport { Puzzle } from \"lucide-react\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { McpLogoBadge } from \"#/components/features/mcp-logo-badge\";\nimport { CirclePlusCheckToggle } from \"#/components/shared/buttons/circle-plus-check-toggle\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { INTEGRATION_CATALOG as MCP_MARKETPLACE } from \"@openhands/extensions/integrations\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n} from \"#/utils/mcp-marketplace-utils\";\nimport { cn } from \"#/utils/utils\";\nimport {\n extensionModuleCardInteractiveClassName,\n extensionModuleCardSurfaceClassName,\n} from \"#/utils/extension-module-card-classes\";\nimport { getInstalledServerTitle } from \"#/utils/mcp-installed-server-display\";\n\ninterface InstalledServerCardProps {\n server: MCPServerConfig;\n onEdit: () => void;\n onDelete: () => void;\n}\n\nfunction getServerTransportLabel(type: MCPServerConfig[\"type\"]) {\n switch (type) {\n case \"sse\":\n return \"SSE\";\n case \"shttp\":\n return \"HTTP\";\n case \"stdio\":\n return \"STDIO\";\n default:\n return type;\n }\n}\n\nfunction getServerDetailLine(server: MCPServerConfig): string {\n if (server.type === \"stdio\") {\n const args =\n server.args && server.args.length > 0 ? ` ${server.args.join(\" \")}` : \"\";\n return `${server.command ?? \"\"}${args}`.trim();\n }\n return server.url ?? \"\";\n}\n\nexport function InstalledServerCard({\n server,\n onEdit,\n onDelete,\n}: InstalledServerCardProps) {\n const { t } = useTranslation(\"openhands\");\n const catalog = findCatalogEntryForServer(\n server,\n getMcpMarketplaceCatalog(MCP_MARKETPLACE),\n );\n\n const title = getInstalledServerTitle(server, catalog);\n const detailLine = getServerDetailLine(server);\n const transport = getServerTransportLabel(server.type);\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onEdit();\n }\n };\n\n return (\n <div\n data-testid=\"mcp-server-item\"\n data-server-id={server.id}\n role=\"button\"\n tabIndex={0}\n onClick={onEdit}\n onKeyDown={handleKeyDown}\n aria-label={t(I18nKey.MCP$EDIT_SERVER_ARIA, { name: title })}\n className={cn(\n \"flex min-h-[132px] flex-col overflow-hidden p-4 text-left\",\n extensionModuleCardSurfaceClassName,\n extensionModuleCardInteractiveClassName,\n )}\n >\n <div className=\"flex items-start gap-3\">\n <McpLogoBadge\n entry={catalog}\n fallback={<Puzzle strokeWidth={2.25} />}\n />\n\n <div className=\"flex min-w-0 flex-1 flex-col gap-3\">\n <header className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-sm font-semibold\" title={title}>\n {title}\n </h3>\n <p className=\"mt-0.5 text-xs text-tertiary-alt\">{transport}</p>\n </div>\n <CirclePlusCheckToggle\n testId={`mcp-installed-toggle-${server.id}`}\n isSelected\n onToggle={(selected) => {\n if (!selected) {\n onDelete();\n }\n }}\n enableLabelKey={I18nKey.MCP$TOGGLE_ADD_SERVER}\n disableLabelKey={I18nKey.MCP$TOGGLE_REMOVE_SERVER}\n />\n </header>\n\n {catalog?.description ? (\n <p\n data-testid={`mcp-server-description-${server.id}`}\n className=\"line-clamp-2 break-words text-xs leading-relaxed text-tertiary-light\"\n >\n {catalog.description}\n </p>\n ) : null}\n\n {detailLine ? (\n <p\n data-testid={`mcp-server-detail-${server.id}`}\n className=\"truncate text-xs text-tertiary-alt\"\n title={detailLine}\n >\n {detailLine}\n </p>\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAyBA,SAAS,EAAwB,GAA+B;AAC9D,SAAQ,GAAR;EACE,KAAK,MACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,EAAoB,GAAiC;AAC5D,KAAI,EAAO,SAAS,SAAS;EAC3B,IAAM,IACJ,EAAO,QAAQ,EAAO,KAAK,SAAS,IAAI,IAAI,EAAO,KAAK,KAAK,IAAI,KAAK;AACxE,SAAO,GAAG,EAAO,WAAW,KAAK,IAAO,MAAM;;AAEhD,QAAO,EAAO,OAAO;;AAGvB,SAAgB,EAAoB,EAClC,WACA,WACA,eAC2B;CAC3B,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,IAAU,EACd,GACA,EAAyB,EAAgB,CAC1C,EAEK,IAAQ,EAAwB,GAAQ,EAAQ,EAChD,IAAa,EAAoB,EAAO,EACxC,IAAY,EAAwB,EAAO,KAAK;AAStD,QACE,kBAAC,OAAD;EACE,eAAY;EACZ,kBAAgB,EAAO;EACvB,MAAK;EACL,UAAU;EACV,SAAS;EACT,YAdmB,MAA+B;AACpD,IAAI,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,gBAAgB,EACtB,GAAQ;;EAYR,cAAY,EAAE,EAAQ,sBAAsB,EAAE,MAAM,GAAO,CAAC;EAC5D,WAAW,EACT,6DACA,GACA,EACD;YAED,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IACE,OAAO;IACP,UAAU,kBAAC,GAAD,EAAQ,aAAa,MAAQ,CAAA;IACvC,CAAA,EAEF,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,UAAD;MAAQ,WAAU;gBAAlB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,MAAD;QAAI,WAAU;QAAwC;kBACnD;QACE,CAAA,EACL,kBAAC,KAAD;QAAG,WAAU;kBAAoC;QAAc,CAAA,CAC3D;UACN,kBAAC,GAAD;OACE,QAAQ,wBAAwB,EAAO;OACvC,YAAA;OACA,WAAW,MAAa;AACtB,QAAK,KACH,GAAU;;OAGd,gBAAgB,EAAQ;OACxB,iBAAiB,EAAQ;OACzB,CAAA,CACK;;KAER,GAAS,cACR,kBAAC,KAAD;MACE,eAAa,0BAA0B,EAAO;MAC9C,WAAU;gBAET,EAAQ;MACP,CAAA,GACF;KAEH,IACC,kBAAC,KAAD;MACE,eAAa,qBAAqB,EAAO;MACzC,WAAU;MACV,OAAO;gBAEN;MACC,CAAA,GACF;KACA;MACF;;EACF,CAAA"}
1
+ {"version":3,"file":"installed-server-card.js","names":[],"sources":["../../../../src/components/features/mcp-page/installed-server-card.tsx"],"sourcesContent":["import React from \"react\";\nimport { Puzzle } from \"lucide-react\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { McpLogoBadge } from \"#/components/features/mcp-logo-badge\";\nimport { CirclePlusCheckToggle } from \"#/components/shared/buttons/circle-plus-check-toggle\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { INTEGRATION_CATALOG as MCP_MARKETPLACE } from \"@openhands/extensions/integrations\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n} from \"#/utils/mcp-marketplace-utils\";\nimport { cn } from \"#/utils/utils\";\nimport {\n extensionModuleCardInteractiveClassName,\n extensionModuleCardSurfaceClassName,\n} from \"#/utils/extension-module-card-classes\";\nimport { getInstalledServerTitle } from \"#/utils/mcp-installed-server-display\";\nimport { McpServerHealthSection } from \"./mcp-server-health\";\n\ninterface InstalledServerCardProps {\n server: MCPServerConfig;\n onEdit: () => void;\n onDelete: () => void;\n}\n\nfunction getServerTransportLabel(type: MCPServerConfig[\"type\"]) {\n switch (type) {\n case \"sse\":\n return \"SSE\";\n case \"shttp\":\n return \"HTTP\";\n case \"stdio\":\n return \"STDIO\";\n default:\n return type;\n }\n}\n\nfunction getServerDetailLine(server: MCPServerConfig): string {\n if (server.type === \"stdio\") {\n const args =\n server.args && server.args.length > 0 ? ` ${server.args.join(\" \")}` : \"\";\n return `${server.command ?? \"\"}${args}`.trim();\n }\n return server.url ?? \"\";\n}\n\nexport function InstalledServerCard({\n server,\n onEdit,\n onDelete,\n}: InstalledServerCardProps) {\n const { t } = useTranslation(\"openhands\");\n const catalog = findCatalogEntryForServer(\n server,\n getMcpMarketplaceCatalog(MCP_MARKETPLACE),\n );\n\n const title = getInstalledServerTitle(server, catalog);\n const detailLine = getServerDetailLine(server);\n const transport = getServerTransportLabel(server.type);\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onEdit();\n }\n };\n\n return (\n <div\n data-testid=\"mcp-server-item\"\n data-server-id={server.id}\n role=\"button\"\n tabIndex={0}\n onClick={onEdit}\n onKeyDown={handleKeyDown}\n aria-label={t(I18nKey.MCP$EDIT_SERVER_ARIA, { name: title })}\n className={cn(\n \"flex min-h-[132px] flex-col overflow-hidden p-4 text-left\",\n extensionModuleCardSurfaceClassName,\n extensionModuleCardInteractiveClassName,\n )}\n >\n <div className=\"flex items-start gap-3\">\n <McpLogoBadge\n entry={catalog}\n fallback={<Puzzle strokeWidth={2.25} />}\n />\n\n <div className=\"flex min-w-0 flex-1 flex-col gap-3\">\n <header className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-sm font-semibold\" title={title}>\n {title}\n </h3>\n <p className=\"mt-0.5 text-xs text-tertiary-alt\">{transport}</p>\n </div>\n <CirclePlusCheckToggle\n testId={`mcp-installed-toggle-${server.id}`}\n isSelected\n onToggle={(selected) => {\n if (!selected) {\n onDelete();\n }\n }}\n enableLabelKey={I18nKey.MCP$TOGGLE_ADD_SERVER}\n disableLabelKey={I18nKey.MCP$TOGGLE_REMOVE_SERVER}\n />\n </header>\n\n {catalog?.description ? (\n <p\n data-testid={`mcp-server-description-${server.id}`}\n className=\"line-clamp-2 break-words text-xs leading-relaxed text-tertiary-light\"\n >\n {catalog.description}\n </p>\n ) : null}\n\n {detailLine ? (\n <p\n data-testid={`mcp-server-detail-${server.id}`}\n className=\"truncate text-xs text-tertiary-alt\"\n title={detailLine}\n >\n {detailLine}\n </p>\n ) : null}\n\n <McpServerHealthSection\n server={server}\n catalog={catalog}\n onEdit={onEdit}\n />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AA0BA,SAAS,EAAwB,GAA+B;AAC9D,SAAQ,GAAR;EACE,KAAK,MACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,EAAoB,GAAiC;AAC5D,KAAI,EAAO,SAAS,SAAS;EAC3B,IAAM,IACJ,EAAO,QAAQ,EAAO,KAAK,SAAS,IAAI,IAAI,EAAO,KAAK,KAAK,IAAI,KAAK;AACxE,SAAO,GAAG,EAAO,WAAW,KAAK,IAAO,MAAM;;AAEhD,QAAO,EAAO,OAAO;;AAGvB,SAAgB,EAAoB,EAClC,WACA,WACA,eAC2B;CAC3B,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,IAAU,EACd,GACA,EAAyB,EAAgB,CAC1C,EAEK,IAAQ,EAAwB,GAAQ,EAAQ,EAChD,IAAa,EAAoB,EAAO,EACxC,IAAY,EAAwB,EAAO,KAAK;AAStD,QACE,kBAAC,OAAD;EACE,eAAY;EACZ,kBAAgB,EAAO;EACvB,MAAK;EACL,UAAU;EACV,SAAS;EACT,YAdmB,MAA+B;AACpD,IAAI,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,gBAAgB,EACtB,GAAQ;;EAYR,cAAY,EAAE,EAAQ,sBAAsB,EAAE,MAAM,GAAO,CAAC;EAC5D,WAAW,EACT,6DACA,GACA,EACD;YAED,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IACE,OAAO;IACP,UAAU,kBAAC,GAAD,EAAQ,aAAa,MAAQ,CAAA;IACvC,CAAA,EAEF,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,UAAD;MAAQ,WAAU;gBAAlB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,MAAD;QAAI,WAAU;QAAwC;kBACnD;QACE,CAAA,EACL,kBAAC,KAAD;QAAG,WAAU;kBAAoC;QAAc,CAAA,CAC3D;UACN,kBAAC,GAAD;OACE,QAAQ,wBAAwB,EAAO;OACvC,YAAA;OACA,WAAW,MAAa;AACtB,QAAK,KACH,GAAU;;OAGd,gBAAgB,EAAQ;OACxB,iBAAiB,EAAQ;OACzB,CAAA,CACK;;KAER,GAAS,cACR,kBAAC,KAAD;MACE,eAAa,0BAA0B,EAAO;MAC9C,WAAU;gBAET,EAAQ;MACP,CAAA,GACF;KAEH,IACC,kBAAC,KAAD;MACE,eAAa,qBAAqB,EAAO;MACzC,WAAU;MACV,OAAO;gBAEN;MACC,CAAA,GACF;KAEJ,kBAAC,GAAD;MACU;MACC;MACD;MACR,CAAA;KACE;MACF;;EACF,CAAA"}
@@ -0,0 +1,2 @@
1
+ const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../utils/utils.cjs`),i=require(`../../../utils/retrieve-axios-error-message.cjs`),a=require(`../../../utils/custom-toast-handlers.cjs`),o=require(`../../../contexts/active-backend-context.cjs`),s=require(`../../../api/mcp-health/probe-mcp-server-health.cjs`),c=require(`../../../hooks/mutation/use-update-mcp-server.cjs`),l=require(`../../../hooks/use-mcp-server-health.cjs`),u=require(`../../../utils/mcp-test-error-message.cjs`);let d=require(`react`);d=e.__toESM(d,1);let f=require(`react/jsx-runtime`);var p={unchecked:`bg-[var(--oh-text-tertiary)]`,checking:`bg-[var(--oh-interactive-selected)] animate-pulse`,healthy:`bg-[var(--oh-status-success)]`,failed:`bg-red-500`},m=`text-xs text-[var(--oh-muted)] underline transition-colors hover:text-white disabled:cursor-not-allowed disabled:opacity-60`;function h(e){return e.status===`healthy`?e.verification===`verified`?`healthy`:`healthy-connectivity`:e.status}function g(e,t){switch(t.status){case`checking`:return e(n.I18nKey.MCP$HEALTH_STATUS_CHECKING);case`healthy`:return t.verification===`verified`?e(n.I18nKey.MCP$HEALTH_STATUS_VERIFIED,{count:t.toolCount}):e(n.I18nKey.MCP$HEALTH_STATUS_CONNECTIVITY_ONLY);case`failed`:return u.makeMcpTestErrorMessage(e,t.kind,t.error);default:return e(n.I18nKey.MCP$HEALTH_STATUS_UNCHECKED)}}function _({server:e,catalog:u,onEdit:d}){let{t:_}=t.useTranslation(`openhands`),{backend:v}=o.useActiveBackend(),{health:y,probe:b,reauthorize:x}=l.useMcpServerHealth(e),{mutate:S}=c.useUpdateMcpServer();if(v.kind===`cloud`)return null;let C=y.status===`checking`,w=y.status===`failed`,T=g(_,y),E=async()=>{let t=await x();if(!t?.ok||!t.oauth_state||e.auth?.strategy!==`oauth2`)return;let r={...e,auth:{...e.auth,state:t.oauth_state}};S({serverId:e.id,server:r},{onSuccess:()=>s.seedMcpServerHealth(r,t,[]),onError:e=>a.displayErrorToast(i.retrieveAxiosErrorMessage(e)||_(n.I18nKey.ERROR$GENERIC))})};return(0,f.jsxs)(`div`,{"data-testid":`mcp-server-health-${e.id}`,role:`presentation`,className:`flex flex-col gap-1.5`,onClick:e=>e.stopPropagation(),onKeyDown:e=>e.stopPropagation(),children:[(0,f.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,f.jsx)(`span`,{"data-testid":`mcp-health-dot`,"data-status":h(y),"aria-hidden":`true`,className:r.cn(`inline-block h-2 w-2 shrink-0 rounded-full`,p[y.status])}),(0,f.jsx)(`p`,{"data-testid":`mcp-health-label-${e.id}`,className:r.cn(`line-clamp-2 break-words text-xs`,w?`text-red-500`:`text-tertiary-alt`),title:T,children:T})]}),y.status===`healthy`&&y.verification===`connectivity-only`?(0,f.jsx)(`p`,{className:`text-xs text-tertiary-light`,children:_(n.I18nKey.MCP$HEALTH_CONNECTIVITY_ONLY_HINT)}):null,(0,f.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3`,children:[(0,f.jsx)(`button`,{type:`button`,"data-testid":`mcp-health-probe-${e.id}`,className:m,onClick:()=>void b(),disabled:C,children:_(w?n.I18nKey.MCP$HEALTH_RETRY:n.I18nKey.MCP$TEST_BUTTON)}),w&&y.kind===`credentials`?(0,f.jsx)(`button`,{type:`button`,"data-testid":`mcp-health-update-credentials-${e.id}`,className:m,onClick:d,children:_(n.I18nKey.MCP$HEALTH_UPDATE_CREDENTIALS)}):null,w&&e.auth?.strategy===`oauth2`?(0,f.jsx)(`button`,{type:`button`,"data-testid":`mcp-health-reauthorize-${e.id}`,className:m,onClick:()=>void E(),children:_(n.I18nKey.MCP$HEALTH_REAUTHORIZE)}):null,w&&u?.docsUrl?(0,f.jsx)(`a`,{href:u.docsUrl,target:`_blank`,rel:`noreferrer`,className:m,children:_(n.I18nKey.MCP$VIEW_DOCS)}):null]})]})}exports.McpServerHealthSection=_;
2
+ //# sourceMappingURL=mcp-server-health.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server-health.cjs","names":[],"sources":["../../../../src/components/features/mcp-page/mcp-server-health.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport type { TFunction } from \"i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { seedMcpServerHealth } from \"#/api/mcp-health/probe-mcp-server-health\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useUpdateMcpServer } from \"#/hooks/mutation/use-update-mcp-server\";\nimport { useMcpServerHealth } from \"#/hooks/use-mcp-server-health\";\nimport type { McpServerHealth } from \"#/types/mcp-health\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport type { MarketplaceEntry } from \"#/utils/mcp-marketplace-utils\";\nimport { makeMcpTestErrorMessage } from \"#/utils/mcp-test-error-message\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { cn } from \"#/utils/utils\";\n\ninterface McpServerHealthSectionProps {\n server: MCPServerConfig;\n catalog: MarketplaceEntry | undefined;\n onEdit: () => void;\n}\n\nconst DOT_CLASS_BY_STATUS: Record<McpServerHealth[\"status\"], string> = {\n unchecked: \"bg-[var(--oh-text-tertiary)]\",\n checking: \"bg-[var(--oh-interactive-selected)] animate-pulse\",\n healthy: \"bg-[var(--oh-status-success)]\",\n failed: \"bg-red-500\",\n};\n\nconst actionClassName =\n \"text-xs text-[var(--oh-muted)] underline transition-colors hover:text-white disabled:cursor-not-allowed disabled:opacity-60\";\n\nfunction getDotStatus(health: McpServerHealth): string {\n if (health.status === \"healthy\") {\n return health.verification === \"verified\"\n ? \"healthy\"\n : \"healthy-connectivity\";\n }\n return health.status;\n}\n\nfunction getStatusLabel(\n t: TFunction<\"openhands\">,\n health: McpServerHealth,\n): string {\n switch (health.status) {\n case \"checking\":\n return t(I18nKey.MCP$HEALTH_STATUS_CHECKING);\n case \"healthy\":\n return health.verification === \"verified\"\n ? t(I18nKey.MCP$HEALTH_STATUS_VERIFIED, { count: health.toolCount })\n : t(I18nKey.MCP$HEALTH_STATUS_CONNECTIVITY_ONLY);\n case \"failed\":\n return makeMcpTestErrorMessage(t, health.kind, health.error);\n default:\n return t(I18nKey.MCP$HEALTH_STATUS_UNCHECKED);\n }\n}\n\n/**\n * Connection-health row for an installed server card: status dot + label,\n * a Test connection / Retry action, and — on failure — the relevant\n * recovery actions (fix credentials, re-run OAuth, open the docs).\n *\n * Renders nothing for cloud backends: the test endpoint only exists on the\n * local agent-server (`McpService.testServer` short-circuits cloud with a\n * synthetic success that must not be presented as a health verdict).\n */\nexport function McpServerHealthSection({\n server,\n catalog,\n onEdit,\n}: McpServerHealthSectionProps) {\n const { t } = useTranslation(\"openhands\");\n const { backend } = useActiveBackend();\n const { health, probe, reauthorize } = useMcpServerHealth(server);\n const { mutate: updateMcpServer } = useUpdateMcpServer();\n\n if (backend.kind === \"cloud\") return null;\n\n const isChecking = health.status === \"checking\";\n const isFailed = health.status === \"failed\";\n const label = getStatusLabel(t, health);\n\n const handleReauthorize = async () => {\n const result = await reauthorize();\n if (\n !result?.ok ||\n !result.oauth_state ||\n server.auth?.strategy !== \"oauth2\"\n ) {\n return;\n }\n // Persist the refreshed tokens, mirroring the editor's OAuth save path.\n const serverToSave: MCPServerConfig = {\n ...server,\n auth: { ...server.auth, state: result.oauth_state },\n };\n updateMcpServer(\n { serverId: server.id, server: serverToSave },\n {\n // The update mutation clears this server's health entry; re-seed it\n // from the probe that just succeeded so the verdict survives the save.\n onSuccess: () => seedMcpServerHealth(serverToSave, result, []),\n onError: (err: unknown) =>\n displayErrorToast(\n retrieveAxiosErrorMessage(err as AxiosError) ||\n t(I18nKey.ERROR$GENERIC),\n ),\n },\n );\n };\n\n return (\n // Propagation stopper: the card root is a role=\"button\" that opens the\n // editor on click/Enter; interactions inside the health row must not\n // double as \"edit server\".\n <div\n data-testid={`mcp-server-health-${server.id}`}\n role=\"presentation\"\n className=\"flex flex-col gap-1.5\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n <div className=\"flex items-center gap-2\">\n <span\n data-testid=\"mcp-health-dot\"\n data-status={getDotStatus(health)}\n aria-hidden=\"true\"\n className={cn(\n \"inline-block h-2 w-2 shrink-0 rounded-full\",\n DOT_CLASS_BY_STATUS[health.status],\n )}\n />\n <p\n data-testid={`mcp-health-label-${server.id}`}\n className={cn(\n \"line-clamp-2 break-words text-xs\",\n isFailed ? \"text-red-500\" : \"text-tertiary-alt\",\n )}\n title={label}\n >\n {label}\n </p>\n </div>\n\n {health.status === \"healthy\" &&\n health.verification === \"connectivity-only\" ? (\n <p className=\"text-xs text-tertiary-light\">\n {t(I18nKey.MCP$HEALTH_CONNECTIVITY_ONLY_HINT)}\n </p>\n ) : null}\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <button\n type=\"button\"\n data-testid={`mcp-health-probe-${server.id}`}\n className={actionClassName}\n onClick={() => void probe()}\n disabled={isChecking}\n >\n {isFailed ? t(I18nKey.MCP$HEALTH_RETRY) : t(I18nKey.MCP$TEST_BUTTON)}\n </button>\n {isFailed && health.kind === \"credentials\" ? (\n <button\n type=\"button\"\n data-testid={`mcp-health-update-credentials-${server.id}`}\n className={actionClassName}\n onClick={onEdit}\n >\n {t(I18nKey.MCP$HEALTH_UPDATE_CREDENTIALS)}\n </button>\n ) : null}\n {isFailed && server.auth?.strategy === \"oauth2\" ? (\n <button\n type=\"button\"\n data-testid={`mcp-health-reauthorize-${server.id}`}\n className={actionClassName}\n onClick={() => void handleReauthorize()}\n >\n {t(I18nKey.MCP$HEALTH_REAUTHORIZE)}\n </button>\n ) : null}\n {isFailed && catalog?.docsUrl ? (\n <a\n href={catalog.docsUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className={actionClassName}\n >\n {t(I18nKey.MCP$VIEW_DOCS)}\n </a>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { MCPServerConfig } from "#/types/mcp-server";
2
+ import type { MarketplaceEntry } from "#/utils/mcp-marketplace-utils";
3
+ interface McpServerHealthSectionProps {
4
+ server: MCPServerConfig;
5
+ catalog: MarketplaceEntry | undefined;
6
+ onEdit: () => void;
7
+ }
8
+ /**
9
+ * Connection-health row for an installed server card: status dot + label,
10
+ * a Test connection / Retry action, and — on failure — the relevant
11
+ * recovery actions (fix credentials, re-run OAuth, open the docs).
12
+ *
13
+ * Renders nothing for cloud backends: the test endpoint only exists on the
14
+ * local agent-server (`McpService.testServer` short-circuits cloud with a
15
+ * synthetic success that must not be presented as a health verdict).
16
+ */
17
+ export declare function McpServerHealthSection({ server, catalog, onEdit, }: McpServerHealthSectionProps): import("react/jsx-runtime").JSX.Element | null;
18
+ export {};
@@ -0,0 +1,117 @@
1
+ import { useTranslation as e } from "../../../node_modules/react-i18next/dist/es/useTranslation.js";
2
+ import { I18nKey as t } from "../../../i18n/declaration.js";
3
+ import { cn as n } from "../../../utils/utils.js";
4
+ import { retrieveAxiosErrorMessage as r } from "../../../utils/retrieve-axios-error-message.js";
5
+ import { displayErrorToast as i } from "../../../utils/custom-toast-handlers.js";
6
+ import { useActiveBackend as a } from "../../../contexts/active-backend-context.js";
7
+ import { seedMcpServerHealth as o } from "../../../api/mcp-health/probe-mcp-server-health.js";
8
+ import { useUpdateMcpServer as s } from "../../../hooks/mutation/use-update-mcp-server.js";
9
+ import { useMcpServerHealth as c } from "../../../hooks/use-mcp-server-health.js";
10
+ import { makeMcpTestErrorMessage as l } from "../../../utils/mcp-test-error-message.js";
11
+ import "react";
12
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
13
+ //#region src/components/features/mcp-page/mcp-server-health.tsx
14
+ var f = {
15
+ unchecked: "bg-[var(--oh-text-tertiary)]",
16
+ checking: "bg-[var(--oh-interactive-selected)] animate-pulse",
17
+ healthy: "bg-[var(--oh-status-success)]",
18
+ failed: "bg-red-500"
19
+ }, p = "text-xs text-[var(--oh-muted)] underline transition-colors hover:text-white disabled:cursor-not-allowed disabled:opacity-60";
20
+ function m(e) {
21
+ return e.status === "healthy" ? e.verification === "verified" ? "healthy" : "healthy-connectivity" : e.status;
22
+ }
23
+ function h(e, n) {
24
+ switch (n.status) {
25
+ case "checking": return e(t.MCP$HEALTH_STATUS_CHECKING);
26
+ case "healthy": return n.verification === "verified" ? e(t.MCP$HEALTH_STATUS_VERIFIED, { count: n.toolCount }) : e(t.MCP$HEALTH_STATUS_CONNECTIVITY_ONLY);
27
+ case "failed": return l(e, n.kind, n.error);
28
+ default: return e(t.MCP$HEALTH_STATUS_UNCHECKED);
29
+ }
30
+ }
31
+ function g({ server: l, catalog: g, onEdit: _ }) {
32
+ let { t: v } = e("openhands"), { backend: y } = a(), { health: b, probe: x, reauthorize: S } = c(l), { mutate: C } = s();
33
+ if (y.kind === "cloud") return null;
34
+ let w = b.status === "checking", T = b.status === "failed", E = h(v, b), D = async () => {
35
+ let e = await S();
36
+ if (!e?.ok || !e.oauth_state || l.auth?.strategy !== "oauth2") return;
37
+ let n = {
38
+ ...l,
39
+ auth: {
40
+ ...l.auth,
41
+ state: e.oauth_state
42
+ }
43
+ };
44
+ C({
45
+ serverId: l.id,
46
+ server: n
47
+ }, {
48
+ onSuccess: () => o(n, e, []),
49
+ onError: (e) => i(r(e) || v(t.ERROR$GENERIC))
50
+ });
51
+ };
52
+ return /* @__PURE__ */ d("div", {
53
+ "data-testid": `mcp-server-health-${l.id}`,
54
+ role: "presentation",
55
+ className: "flex flex-col gap-1.5",
56
+ onClick: (e) => e.stopPropagation(),
57
+ onKeyDown: (e) => e.stopPropagation(),
58
+ children: [
59
+ /* @__PURE__ */ d("div", {
60
+ className: "flex items-center gap-2",
61
+ children: [/* @__PURE__ */ u("span", {
62
+ "data-testid": "mcp-health-dot",
63
+ "data-status": m(b),
64
+ "aria-hidden": "true",
65
+ className: n("inline-block h-2 w-2 shrink-0 rounded-full", f[b.status])
66
+ }), /* @__PURE__ */ u("p", {
67
+ "data-testid": `mcp-health-label-${l.id}`,
68
+ className: n("line-clamp-2 break-words text-xs", T ? "text-red-500" : "text-tertiary-alt"),
69
+ title: E,
70
+ children: E
71
+ })]
72
+ }),
73
+ b.status === "healthy" && b.verification === "connectivity-only" ? /* @__PURE__ */ u("p", {
74
+ className: "text-xs text-tertiary-light",
75
+ children: v(t.MCP$HEALTH_CONNECTIVITY_ONLY_HINT)
76
+ }) : null,
77
+ /* @__PURE__ */ d("div", {
78
+ className: "flex flex-wrap items-center gap-3",
79
+ children: [
80
+ /* @__PURE__ */ u("button", {
81
+ type: "button",
82
+ "data-testid": `mcp-health-probe-${l.id}`,
83
+ className: p,
84
+ onClick: () => void x(),
85
+ disabled: w,
86
+ children: v(T ? t.MCP$HEALTH_RETRY : t.MCP$TEST_BUTTON)
87
+ }),
88
+ T && b.kind === "credentials" ? /* @__PURE__ */ u("button", {
89
+ type: "button",
90
+ "data-testid": `mcp-health-update-credentials-${l.id}`,
91
+ className: p,
92
+ onClick: _,
93
+ children: v(t.MCP$HEALTH_UPDATE_CREDENTIALS)
94
+ }) : null,
95
+ T && l.auth?.strategy === "oauth2" ? /* @__PURE__ */ u("button", {
96
+ type: "button",
97
+ "data-testid": `mcp-health-reauthorize-${l.id}`,
98
+ className: p,
99
+ onClick: () => void D(),
100
+ children: v(t.MCP$HEALTH_REAUTHORIZE)
101
+ }) : null,
102
+ T && g?.docsUrl ? /* @__PURE__ */ u("a", {
103
+ href: g.docsUrl,
104
+ target: "_blank",
105
+ rel: "noreferrer",
106
+ className: p,
107
+ children: v(t.MCP$VIEW_DOCS)
108
+ }) : null
109
+ ]
110
+ })
111
+ ]
112
+ });
113
+ }
114
+ //#endregion
115
+ export { g as McpServerHealthSection };
116
+
117
+ //# sourceMappingURL=mcp-server-health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server-health.js","names":[],"sources":["../../../../src/components/features/mcp-page/mcp-server-health.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport type { TFunction } from \"i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { seedMcpServerHealth } from \"#/api/mcp-health/probe-mcp-server-health\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useUpdateMcpServer } from \"#/hooks/mutation/use-update-mcp-server\";\nimport { useMcpServerHealth } from \"#/hooks/use-mcp-server-health\";\nimport type { McpServerHealth } from \"#/types/mcp-health\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport type { MarketplaceEntry } from \"#/utils/mcp-marketplace-utils\";\nimport { makeMcpTestErrorMessage } from \"#/utils/mcp-test-error-message\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { cn } from \"#/utils/utils\";\n\ninterface McpServerHealthSectionProps {\n server: MCPServerConfig;\n catalog: MarketplaceEntry | undefined;\n onEdit: () => void;\n}\n\nconst DOT_CLASS_BY_STATUS: Record<McpServerHealth[\"status\"], string> = {\n unchecked: \"bg-[var(--oh-text-tertiary)]\",\n checking: \"bg-[var(--oh-interactive-selected)] animate-pulse\",\n healthy: \"bg-[var(--oh-status-success)]\",\n failed: \"bg-red-500\",\n};\n\nconst actionClassName =\n \"text-xs text-[var(--oh-muted)] underline transition-colors hover:text-white disabled:cursor-not-allowed disabled:opacity-60\";\n\nfunction getDotStatus(health: McpServerHealth): string {\n if (health.status === \"healthy\") {\n return health.verification === \"verified\"\n ? \"healthy\"\n : \"healthy-connectivity\";\n }\n return health.status;\n}\n\nfunction getStatusLabel(\n t: TFunction<\"openhands\">,\n health: McpServerHealth,\n): string {\n switch (health.status) {\n case \"checking\":\n return t(I18nKey.MCP$HEALTH_STATUS_CHECKING);\n case \"healthy\":\n return health.verification === \"verified\"\n ? t(I18nKey.MCP$HEALTH_STATUS_VERIFIED, { count: health.toolCount })\n : t(I18nKey.MCP$HEALTH_STATUS_CONNECTIVITY_ONLY);\n case \"failed\":\n return makeMcpTestErrorMessage(t, health.kind, health.error);\n default:\n return t(I18nKey.MCP$HEALTH_STATUS_UNCHECKED);\n }\n}\n\n/**\n * Connection-health row for an installed server card: status dot + label,\n * a Test connection / Retry action, and — on failure — the relevant\n * recovery actions (fix credentials, re-run OAuth, open the docs).\n *\n * Renders nothing for cloud backends: the test endpoint only exists on the\n * local agent-server (`McpService.testServer` short-circuits cloud with a\n * synthetic success that must not be presented as a health verdict).\n */\nexport function McpServerHealthSection({\n server,\n catalog,\n onEdit,\n}: McpServerHealthSectionProps) {\n const { t } = useTranslation(\"openhands\");\n const { backend } = useActiveBackend();\n const { health, probe, reauthorize } = useMcpServerHealth(server);\n const { mutate: updateMcpServer } = useUpdateMcpServer();\n\n if (backend.kind === \"cloud\") return null;\n\n const isChecking = health.status === \"checking\";\n const isFailed = health.status === \"failed\";\n const label = getStatusLabel(t, health);\n\n const handleReauthorize = async () => {\n const result = await reauthorize();\n if (\n !result?.ok ||\n !result.oauth_state ||\n server.auth?.strategy !== \"oauth2\"\n ) {\n return;\n }\n // Persist the refreshed tokens, mirroring the editor's OAuth save path.\n const serverToSave: MCPServerConfig = {\n ...server,\n auth: { ...server.auth, state: result.oauth_state },\n };\n updateMcpServer(\n { serverId: server.id, server: serverToSave },\n {\n // The update mutation clears this server's health entry; re-seed it\n // from the probe that just succeeded so the verdict survives the save.\n onSuccess: () => seedMcpServerHealth(serverToSave, result, []),\n onError: (err: unknown) =>\n displayErrorToast(\n retrieveAxiosErrorMessage(err as AxiosError) ||\n t(I18nKey.ERROR$GENERIC),\n ),\n },\n );\n };\n\n return (\n // Propagation stopper: the card root is a role=\"button\" that opens the\n // editor on click/Enter; interactions inside the health row must not\n // double as \"edit server\".\n <div\n data-testid={`mcp-server-health-${server.id}`}\n role=\"presentation\"\n className=\"flex flex-col gap-1.5\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n <div className=\"flex items-center gap-2\">\n <span\n data-testid=\"mcp-health-dot\"\n data-status={getDotStatus(health)}\n aria-hidden=\"true\"\n className={cn(\n \"inline-block h-2 w-2 shrink-0 rounded-full\",\n DOT_CLASS_BY_STATUS[health.status],\n )}\n />\n <p\n data-testid={`mcp-health-label-${server.id}`}\n className={cn(\n \"line-clamp-2 break-words text-xs\",\n isFailed ? \"text-red-500\" : \"text-tertiary-alt\",\n )}\n title={label}\n >\n {label}\n </p>\n </div>\n\n {health.status === \"healthy\" &&\n health.verification === \"connectivity-only\" ? (\n <p className=\"text-xs text-tertiary-light\">\n {t(I18nKey.MCP$HEALTH_CONNECTIVITY_ONLY_HINT)}\n </p>\n ) : null}\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <button\n type=\"button\"\n data-testid={`mcp-health-probe-${server.id}`}\n className={actionClassName}\n onClick={() => void probe()}\n disabled={isChecking}\n >\n {isFailed ? t(I18nKey.MCP$HEALTH_RETRY) : t(I18nKey.MCP$TEST_BUTTON)}\n </button>\n {isFailed && health.kind === \"credentials\" ? (\n <button\n type=\"button\"\n data-testid={`mcp-health-update-credentials-${server.id}`}\n className={actionClassName}\n onClick={onEdit}\n >\n {t(I18nKey.MCP$HEALTH_UPDATE_CREDENTIALS)}\n </button>\n ) : null}\n {isFailed && server.auth?.strategy === \"oauth2\" ? (\n <button\n type=\"button\"\n data-testid={`mcp-health-reauthorize-${server.id}`}\n className={actionClassName}\n onClick={() => void handleReauthorize()}\n >\n {t(I18nKey.MCP$HEALTH_REAUTHORIZE)}\n </button>\n ) : null}\n {isFailed && catalog?.docsUrl ? (\n <a\n href={catalog.docsUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className={actionClassName}\n >\n {t(I18nKey.MCP$VIEW_DOCS)}\n </a>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}