@openhands/agent-canvas 1.0.0-alpha.8 → 1.0.0-beta.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 (409) hide show
  1. package/README.md +17 -6
  2. package/bin/agent-canvas.mjs +22 -2
  3. package/build/assets/{QueryClientProvider-B7kl84Kj.js → QueryClientProvider-CkGuhXg-.js} +1 -1
  4. package/build/assets/{Trans-1j65oy9O.js → Trans-Cvm_-SMi.js} +1 -1
  5. package/build/assets/acp-providers-CbiRekh9.js +1 -0
  6. package/build/assets/{acp-route-guard-CQTmeJwM.js → acp-route-guard-B2yoBZ_4.js} +1 -1
  7. package/build/assets/{active-backend-context-TVbjnvmP.js → active-backend-context-cCM1vYYZ.js} +1 -1
  8. package/build/assets/add-backend-modal-DIUQzMPa.js +1 -0
  9. package/build/assets/agent-server-client-options-Bc5ZorQZ.js +1 -0
  10. package/build/assets/agent-server-compatibility-BlkUsrX2.js +1 -0
  11. package/build/assets/agent-server-conversation-service.api-DFvqqEDo.js +5 -0
  12. package/build/assets/{agent-settings-B247S9G3.js → agent-settings-CnGSCmK8.js} +1 -1
  13. package/build/assets/{alert-banner-BWoqueRw.js → alert-banner-DtzAX654.js} +1 -1
  14. package/build/assets/{analytics-consent-form-modal-C7sXfxRh.js → analytics-consent-form-modal-CHZ3I37v.js} +1 -1
  15. package/build/assets/api-key-entry-screen-B2gynaCp.js +1 -0
  16. package/build/assets/{app-settings-BVeSaty9.js → app-settings-Db9ITeJH.js} +1 -1
  17. package/build/assets/{automation-detail-g5-RZ0da.js → automation-detail-Di7EOIZD.js} +1 -1
  18. package/build/assets/{automations-list-DHoq_0MM.js → automations-list-IsIWdDiw.js} +1 -1
  19. package/build/assets/backend-form-modal-Dnk33xA_.js +1 -0
  20. package/build/assets/{backend-synced-settings-badge-nAfiUWvM.js → backend-synced-settings-badge-Dc6c7GT4.js} +1 -1
  21. package/build/assets/{base-modal-CQRvRHu1.js → base-modal-_dYTw1ri.js} +1 -1
  22. package/build/assets/{brand-button-C2nEKopC.js → brand-button-Br7f0kZJ.js} +1 -1
  23. package/build/assets/browser-D810xUYt.js +5 -0
  24. package/build/assets/browser-store-Couc4S5D.js +1 -0
  25. package/build/assets/browser-tab-B-aIqXRl.js +1 -0
  26. package/build/assets/{checkmark-BJJrZUF8.js → checkmark-DL7acQA7.js} +1 -1
  27. package/build/assets/{chevron-left-small-CSh-sE9L.js → chevron-left-small-CVWf8TI6.js} +1 -1
  28. package/build/assets/{circle-plus-check-toggle-qs8Va1cC.js → circle-plus-check-toggle-P7ZZToV4.js} +1 -1
  29. package/build/assets/{clock-ZR4Kn-_Y.js → clock-BRjCgHTc.js} +1 -1
  30. package/build/assets/{close-BdmyeRqS.js → close-B5LROHR3.js} +1 -1
  31. package/build/assets/{combobox-caret-B53O9Hsq.js → combobox-caret-to1O8irE.js} +1 -1
  32. package/build/assets/{condenser-settings-A35V3yng.js → condenser-settings-wnEKhBof.js} +1 -1
  33. package/build/assets/{confirmation-modal-C9-La0h3.js → confirmation-modal-Dau3w_sa.js} +1 -1
  34. package/build/assets/{context-menu-list-item-Buu9nc0q.js → context-menu-list-item-CWNFpuiC.js} +1 -1
  35. package/build/assets/conversation-HlncOV7n.js +19 -0
  36. package/build/assets/conversation-MtnkpqA9.js +1 -0
  37. package/build/assets/conversation-panel-DxnM6tRe.js +1 -0
  38. package/build/assets/{conversation-service.api-C8pYCyV6.js → conversation-service.api-nb5W1PqR.js} +1 -1
  39. package/build/assets/{conversation-tab-empty-state-D8dNvo-V.js → conversation-tab-empty-state-DyssnnWa.js} +1 -1
  40. package/build/assets/conversation-websocket-context-C8_PkGLi.js +3 -0
  41. package/build/assets/{copy-C7Ti2d8C.js → copy-DYgmUdIw.js} +1 -1
  42. package/build/assets/{custom-toast-handlers-BOc3qeQ7.js → custom-toast-handlers-C-SZFmto.js} +1 -1
  43. package/build/assets/declaration-BNMqORFE.js +1 -0
  44. package/build/assets/{device-verify-CMusn8nX.js → device-verify-DqDlphsG.js} +1 -1
  45. package/build/assets/{dist-DZHSA2e6.js → dist-C6t0EXL7.js} +1 -1
  46. package/build/assets/{edit-automation-modal-Dnjxbjn7.js → edit-automation-modal-BGzR3nfZ.js} +1 -1
  47. package/build/assets/{ellipsis-button-ugUATsNo.js → ellipsis-button-ZyLMPURn.js} +1 -1
  48. package/build/assets/{entry.client-D9uR9Blz.js → entry.client-1VMHpktY.js} +2 -2
  49. package/build/assets/{enum-filter-dropdown-1vpOGySB.js → enum-filter-dropdown-CEgCdu4A.js} +1 -1
  50. package/build/assets/{environment-switch-overlay-CTCTQikP.js → environment-switch-overlay-XL8yCGP6.js} +1 -1
  51. package/build/assets/{extensions-hub-BSUseHVF.js → extensions-hub-C651jsVh.js} +1 -1
  52. package/build/assets/{extensions-navigation-CT1kc1u_.js → extensions-navigation-BYR8Giqq.js} +1 -1
  53. package/build/assets/files-tab-BhnLgimi.js +1 -0
  54. package/build/assets/{folder-0WSMImNX.js → folder-ZZJVGgd7.js} +1 -1
  55. package/build/assets/git-control-bar-branch-button-M34A5_vX.js +27 -0
  56. package/build/assets/{git-provider-icon-DYE9n7fs.js → git-provider-icon-D5dCNy-k.js} +1 -1
  57. package/build/assets/home-CYQv7yc_.js +1 -0
  58. package/build/assets/{i18n-DjAGhTis.js → i18n-CTohRuoO.js} +1 -1
  59. package/build/assets/install-server-modal-f31_CLrW.js +1 -0
  60. package/build/assets/{launch-hZ0ifhcV.js → launch-DHEUYn2A.js} +1 -1
  61. package/build/assets/{lesson-plan-DRYG5SLI.js → lesson-plan-dH5Bj0pN.js} +1 -1
  62. package/build/assets/{link-external-Df8J52xI.js → link-external-D2POYx4c.js} +1 -1
  63. package/build/assets/{llm-client-ChQzg4wX.js → llm-client-DaH1TuyR.js} +1 -1
  64. package/build/assets/llm-settings-Bql-vydt.js +1 -0
  65. package/build/assets/llm-settings-C_tal6Ds.js +1 -0
  66. package/build/assets/{loading-spinner-C04FGh14.js → loading-spinner-BPtYORNK.js} +1 -1
  67. package/build/assets/{manage-backends-modal-rYeyGx7j.js → manage-backends-modal-l7RkKfwX.js} +1 -1
  68. package/build/assets/{manage-workspaces-modal-C5EuW8m1.js → manage-workspaces-modal-DhKF_8z3.js} +1 -1
  69. package/build/assets/manifest-9fee01b9.js +1 -0
  70. package/build/assets/{markdown-renderer-CEX4Becj.js → markdown-renderer-DMzf2i4x.js} +1 -1
  71. package/build/assets/mcp-D2onbwVk.js +9 -0
  72. package/build/assets/{messages-T2ewVkbp.js → messages-BMzyOW2V.js} +1 -1
  73. package/build/assets/{modal-backdrop-DTYGVmOR.js → modal-backdrop-BAbgYsqB.js} +1 -1
  74. package/build/assets/{modal-body-YElmM1dV.js → modal-body-BI6Ru2Qr.js} +1 -1
  75. package/build/assets/{modal-close-button-C_GpQt9F.js → modal-close-button-t1Gh3qmL.js} +1 -1
  76. package/build/assets/{model-selector-DeMmw-Xa.js → model-selector-SM9IUz-q.js} +1 -1
  77. package/build/assets/{mutation-Cz7N4XAo.js → mutation-D0OogFCz.js} +1 -1
  78. package/build/assets/{navigation-context-DeIPtGPp.js → navigation-context-D0YWpT8d.js} +1 -1
  79. package/build/assets/{navigation-link-C9JD4PYD.js → navigation-link-Cn7KP3c5.js} +1 -1
  80. package/build/assets/{openhands-logo-CI5Fhn1W.js → openhands-logo-CnrF6LKb.js} +1 -1
  81. package/build/assets/{option-service.api-DsI1UW7N.js → option-service.api-KvY_mZMY.js} +1 -1
  82. package/build/assets/{organization-service.api-COwMPFg5.js → organization-service.api-DzYTHTYC.js} +1 -1
  83. package/build/assets/{path-utils-CqJboYxo.js → path-utils-YohAYyMv.js} +1 -1
  84. package/build/assets/{plan-components-DEjMuDDG.js → plan-components-atxXCF0R.js} +1 -1
  85. package/build/assets/{planner-tab-BrntFmb1.js → planner-tab-CFc-hV07.js} +1 -1
  86. package/build/assets/{profiles-client-BGkKEV9j.js → profiles-client-D6IkTJof.js} +1 -1
  87. package/build/assets/{providers-DXvCAN_u.js → providers-Bx6EfrzZ.js} +1 -1
  88. package/build/assets/{proxy-CurRmrqf.js → proxy-CxydCnis.js} +1 -1
  89. package/build/assets/{query-client-config-Ba7qAAoO.js → query-client-config-B7u9asM0.js} +1 -1
  90. package/build/assets/{recommended-automations-launcher-BI9NhG8Y.js → recommended-automations-launcher-sgvfU62c.js} +3 -3
  91. package/build/assets/root-BXWU99D-.js +2 -0
  92. package/build/assets/{root-layout-BLjAEgle.js → root-layout-DVepR4To.js} +2 -2
  93. package/build/assets/sdk-section-page-DOIKvwSL.js +1 -0
  94. package/build/assets/{sdk-settings-schema-QBYH-ONX.js → sdk-settings-schema-DsUf9wu1.js} +1 -1
  95. package/build/assets/{search-Cq_cFrDt.js → search-27Owlc3A.js} +1 -1
  96. package/build/assets/{secrets-service-Bwd5DeUs.js → secrets-service-BsnKFc2x.js} +1 -1
  97. package/build/assets/secrets-settings-Bz_UohPJ.js +1 -0
  98. package/build/assets/{server-client-C3mC8Hl3.js → server-client-DyAQ3NZ_.js} +1 -1
  99. package/build/assets/{settings-D7E2U5tK.js → settings-BYkVX7vW.js} +1 -1
  100. package/build/assets/{settings-client-CwjfwoiB.js → settings-client-C73C7IgV.js} +1 -1
  101. package/build/assets/{settings-dropdown-input-VwAXNrOb.js → settings-dropdown-input-BJYvGdg-.js} +1 -1
  102. package/build/assets/{settings-gear-BJwWR1ej.js → settings-gear-C77PgE_O.js} +1 -1
  103. package/build/assets/{settings-index-J-3BNR0W.js → settings-index-Dz0BmdJD.js} +1 -1
  104. package/build/assets/{settings-input-DBywAnA7.js → settings-input-Bn7F5C75.js} +1 -1
  105. package/build/assets/{settings-list-classes-BOS092DR.js → settings-list-classes-Bf80tWtc.js} +1 -1
  106. package/build/assets/{settings-modal-B8vgWDTe.js → settings-modal-Brzgh5Yw.js} +1 -1
  107. package/build/assets/{settings-section-header-context-32x6WTyL.js → settings-section-header-context-BgZe5YkE.js} +1 -1
  108. package/build/assets/{settings-service.api-FvJGK45W.js → settings-service.api-CZ3uWx4v.js} +1 -1
  109. package/build/assets/{settings-switch-DTKmHC8F.js → settings-switch-BeIKrWms.js} +1 -1
  110. package/build/assets/{shared-conversation-a0QV8o99.js → shared-conversation-DChOdb0t.js} +1 -1
  111. package/build/assets/{sidebar-mobile-menu-toggle-DTUNI1WQ.js → sidebar-mobile-menu-toggle-BWuf4PRH.js} +1 -1
  112. package/build/assets/{sidebar-nav-link-CnWoZcwc.js → sidebar-nav-link-BGjiJq-4.js} +1 -1
  113. package/build/assets/{skill-card-pill-row-tZ599jli.js → skill-card-pill-row-DF1axQCG.js} +1 -1
  114. package/build/assets/{skills-ZyAO5dyK.js → skills-ChIKZPK4.js} +1 -1
  115. package/build/assets/{skills-plugins-BSRz041I.js → skills-plugins-CcI_19lM.js} +1 -1
  116. package/build/assets/{skills-settings-DOnMn9q1.js → skills-settings-DlA5hlXw.js} +1 -1
  117. package/build/assets/{status-CsatcFbK.js → status-hp6M6E7E.js} +1 -1
  118. package/build/assets/{styled-tooltip-CS3mB_1X.js → styled-tooltip-CBzrri6o.js} +1 -1
  119. package/build/assets/{switch-skeleton-C-CfhYYV.js → switch-skeleton-DnC9wLp7.js} +1 -1
  120. package/build/assets/{task-list-tab-Day9nhRT.js → task-list-tab-DUJn1sgz.js} +1 -1
  121. package/build/assets/{terminal-ro4SNjUU.js → terminal-CRf9S0Z2.js} +1 -1
  122. package/build/assets/{terminal-LNa-iU5c.js → terminal-RmuaSdhJ.js} +1 -1
  123. package/build/assets/{toggle-switch-k-IZCDbt.js → toggle-switch-Pvyp2RAN.js} +1 -1
  124. package/build/assets/{typography-vVUMoNUg.js → typography-gpuWmrQO.js} +1 -1
  125. package/build/assets/{u-check-circle-DplbarS5.js → u-check-circle-IUIfACQQ.js} +1 -1
  126. package/build/assets/{u-check-circle-half-yDuiSZHC.js → u-check-circle-half-C1YxB6py.js} +1 -1
  127. package/build/assets/{u-circuit-C9tYkpeK.js → u-circuit-BmVikJHu.js} +1 -1
  128. package/build/assets/{u-edit-KAUlufD8.js → u-edit-CFvXHqZk.js} +1 -1
  129. package/build/assets/use-active-conversation-Db3IWSPK.js +1 -0
  130. package/build/assets/{use-agent-settings-schema-Bvp5UzV8.js → use-agent-settings-schema-33Un7UF2.js} +1 -1
  131. package/build/assets/{use-agent-state-DE5dlEXJ.js → use-agent-state-Bn8vS5sY.js} +1 -1
  132. package/build/assets/{use-cloud-current-user-id-DWVar4st.js → use-cloud-current-user-id-CvkXFnTT.js} +1 -1
  133. package/build/assets/use-config-Co1O8-Ey.js +1 -0
  134. package/build/assets/{use-create-conversation-DW7AGgLA.js → use-create-conversation-CKS3EAHu.js} +1 -1
  135. package/build/assets/{use-event-store-CQZCcVz-.js → use-event-store-BT_gV3ut.js} +1 -1
  136. package/build/assets/use-get-secrets-DuhdIA59.js +1 -0
  137. package/build/assets/{use-handle-plan-click-DpgEQDAV.js → use-handle-plan-click-C9zJpK8A.js} +1 -1
  138. package/build/assets/use-is-authed-BggE5wPj.js +1 -0
  139. package/build/assets/{use-is-creating-conversation-DhDeeWfA.js → use-is-creating-conversation-BZ5hB_Bg.js} +1 -1
  140. package/build/assets/{use-launch-skill-in-chat-DVGPFrbI.js → use-launch-skill-in-chat-fNN_xGZG.js} +1 -1
  141. package/build/assets/{use-llm-profiles-D3-KXwQ0.js → use-llm-profiles-DDOol3gK.js} +1 -1
  142. package/build/assets/use-runtime-is-ready-CQCE3xZC.js +1 -0
  143. package/build/assets/{use-save-settings-CEEKSTWG.js → use-save-settings-VUrj_QNG.js} +1 -1
  144. package/build/assets/{use-settings-DQ7Oo1Hj.js → use-settings-DQIZmIov.js} +1 -1
  145. package/build/assets/{use-settings-nav-items-YmrXrjn9.js → use-settings-nav-items-1ZvovKSr.js} +1 -1
  146. package/build/assets/use-skills-DAMLFjKU.js +1 -0
  147. package/build/assets/{use-task-list-Bs90uF2N.js → use-task-list-CLJbuJgM.js} +1 -1
  148. package/build/assets/use-unified-vscode-url-sZt29HrC.js +1 -0
  149. package/build/assets/use-user-conversation-DfgEB6RW.js +1 -0
  150. package/build/assets/{useMutation-B4OUESdw.js → useMutation-DqrumCWD.js} +1 -1
  151. package/build/assets/{useTranslation-CpIcQBq6.js → useTranslation-DCOdSSMl.js} +1 -1
  152. package/build/assets/{utils-D-HX7JCe.js → utils-i18rdUj2.js} +1 -1
  153. package/build/assets/v4-CNn21NXa.js +1 -0
  154. package/build/assets/{vendor~browser-Dr71AdrG.js → vendor~browser-BNjNhjFU.js} +1 -1
  155. package/build/assets/{vendor~browser-tab-BiVxfjJo.js → vendor~browser-tab-BgwV1mxF.js} +1 -1
  156. package/build/assets/{vendor~conversation-panel~conversation-BlCIz9XQ.js → vendor~conversation-panel~conversation-a9SyrrhV.js} +1 -1
  157. package/build/assets/{vendor~files-tab-DtLR-QD9.js → vendor~files-tab-BGKayPiK.js} +1 -1
  158. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Ds9quNZ9.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-smY2r837.js} +1 -1
  159. package/build/assets/{vendor~home~mcp~automations-list-C5PoHCy6.js → vendor~home~mcp~automations-list-Ccy2I0KU.js} +1 -1
  160. package/build/assets/{vendor~home~mcp~automations-list-BUBGGGYz.js → vendor~home~mcp~automations-list-DoPfwaXj.js} +1 -1
  161. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CGlZoBKa.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-DbfELDJu.js} +2 -2
  162. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-DE11mPxp.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-Z3nsiNNq.js} +1 -1
  163. package/build/assets/{vendor~launch-Dg--Ssk6.js → vendor~launch-vdeRTWFu.js} +1 -1
  164. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-DrXgiSCq.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-DW31UyBp.js} +1 -1
  165. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-8b8V5bfO.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-BkQGKpye.js} +1 -1
  166. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-Dy7L6fMG.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-DzIXV3Ui.js} +1 -1
  167. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-D40EXhZx.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-Bbs7UJ5U.js} +2 -2
  168. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-CHrEOFl6.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-DTwbEEcX.js} +1 -1
  169. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-BP1SKG0F.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-d2oallMa.js} +1 -1
  170. package/build/assets/{vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-CyUbhpbm.js → vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~f2l2lr17-CDXvdvb2.js} +1 -1
  171. package/build/assets/{verification-settings-BtlTiHP8.js → verification-settings-CsbvQcYS.js} +1 -1
  172. package/build/assets/{vscode-tab-C0ShhiSU.js → vscode-tab-Zb-QbTuV.js} +1 -1
  173. package/build/assets/{waiting-for-runtime-message-DWPl_Yby.js → waiting-for-runtime-message-CntjExbU.js} +1 -1
  174. package/build/assets/{x-mark-CWI0f9yI.js → x-mark-CrpjscNc.js} +1 -1
  175. package/build/index.html +4 -4
  176. package/build/locales/ar/openhands.json +7 -0
  177. package/build/locales/ca/openhands.json +7 -0
  178. package/build/locales/de/openhands.json +7 -0
  179. package/build/locales/en/openhands.json +7 -0
  180. package/build/locales/es/openhands.json +7 -0
  181. package/build/locales/fr/openhands.json +7 -0
  182. package/build/locales/it/openhands.json +7 -0
  183. package/build/locales/ja/openhands.json +7 -0
  184. package/build/locales/ko-KR/openhands.json +7 -0
  185. package/build/locales/no/openhands.json +7 -0
  186. package/build/locales/pt/openhands.json +7 -0
  187. package/build/locales/tr/openhands.json +7 -0
  188. package/build/locales/uk/openhands.json +7 -0
  189. package/build/locales/zh-CN/openhands.json +7 -0
  190. package/build/locales/zh-TW/openhands.json +7 -0
  191. package/config/defaults.json +0 -4
  192. package/dist/api/agent-server-adapter.cjs +1 -1
  193. package/dist/api/agent-server-adapter.cjs.map +1 -1
  194. package/dist/api/agent-server-adapter.js +2 -1
  195. package/dist/api/agent-server-adapter.js.map +1 -1
  196. package/dist/api/agent-server-compatibility.cjs +1 -1
  197. package/dist/api/agent-server-compatibility.cjs.map +1 -1
  198. package/dist/api/agent-server-compatibility.d.ts +16 -0
  199. package/dist/api/agent-server-compatibility.js +31 -20
  200. package/dist/api/agent-server-compatibility.js.map +1 -1
  201. package/dist/api/agent-server-config.cjs +1 -1
  202. package/dist/api/agent-server-config.cjs.map +1 -1
  203. package/dist/api/agent-server-config.d.ts +45 -0
  204. package/dist/api/agent-server-config.js +49 -21
  205. package/dist/api/agent-server-config.js.map +1 -1
  206. package/dist/api/backend-registry/storage.cjs +1 -1
  207. package/dist/api/backend-registry/storage.cjs.map +1 -1
  208. package/dist/api/backend-registry/storage.js +34 -32
  209. package/dist/api/backend-registry/storage.js.map +1 -1
  210. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  211. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  212. package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +5 -4
  213. package/dist/api/conversation-service/agent-server-conversation-service.api.js +70 -76
  214. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  215. package/dist/api/skills-service.cjs +1 -1
  216. package/dist/api/skills-service.cjs.map +1 -1
  217. package/dist/api/skills-service.d.ts +1 -1
  218. package/dist/api/skills-service.js +2 -2
  219. package/dist/api/skills-service.js.map +1 -1
  220. package/dist/components/features/backends/api-key-entry-screen.d.ts +10 -0
  221. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  222. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  223. package/dist/components/features/backends/backend-form-modal.d.ts +23 -2
  224. package/dist/components/features/backends/backend-form-modal.js +185 -173
  225. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  226. package/dist/components/features/browser/browser.cjs +1 -1
  227. package/dist/components/features/browser/browser.cjs.map +1 -1
  228. package/dist/components/features/browser/browser.js +10 -16
  229. package/dist/components/features/browser/browser.js.map +1 -1
  230. package/dist/components/features/conversation-panel/skills-modal.cjs +1 -1
  231. package/dist/components/features/conversation-panel/skills-modal.cjs.map +1 -1
  232. package/dist/components/features/conversation-panel/skills-modal.js +1 -1
  233. package/dist/components/features/conversation-panel/skills-modal.js.map +1 -1
  234. package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
  235. package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
  236. package/dist/components/features/mcp-page/install-server-modal.js +123 -116
  237. package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
  238. package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
  239. package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
  240. package/dist/components/features/mcp-page/installed-server-card.js +40 -40
  241. package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
  242. package/dist/components/features/mcp-page/marketplace-card.cjs +1 -1
  243. package/dist/components/features/mcp-page/marketplace-card.cjs.map +1 -1
  244. package/dist/components/features/mcp-page/marketplace-card.js +2 -3
  245. package/dist/components/features/mcp-page/marketplace-card.js.map +1 -1
  246. package/dist/components/features/mcp-page/marketplace-section.cjs +1 -1
  247. package/dist/components/features/mcp-page/marketplace-section.cjs.map +1 -1
  248. package/dist/components/features/mcp-page/marketplace-section.js +21 -21
  249. package/dist/components/features/mcp-page/marketplace-section.js.map +1 -1
  250. package/dist/components/features/onboarding/steps/setup-acp-secrets-step.d.ts +27 -0
  251. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.cjs +1 -1
  252. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.js +2 -0
  253. package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs +1 -1
  254. package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs.map +1 -1
  255. package/dist/components/features/settings/sdk-settings/sdk-section-page.d.ts +10 -1
  256. package/dist/components/features/settings/sdk-settings/sdk-section-page.js +87 -84
  257. package/dist/components/features/settings/sdk-settings/sdk-section-page.js.map +1 -1
  258. package/dist/constants/acp-providers.cjs +1 -1
  259. package/dist/constants/acp-providers.cjs.map +1 -1
  260. package/dist/constants/acp-providers.d.ts +25 -0
  261. package/dist/constants/acp-providers.js +1 -0
  262. package/dist/constants/acp-providers.js.map +1 -1
  263. package/dist/contexts/conversation-websocket-context.cjs +3 -3
  264. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  265. package/dist/contexts/conversation-websocket-context.js +177 -165
  266. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  267. package/dist/hooks/chat/use-model-interceptor.cjs.map +1 -1
  268. package/dist/hooks/chat/use-model-interceptor.js.map +1 -1
  269. package/dist/hooks/chat/use-slash-command.cjs +1 -1
  270. package/dist/hooks/chat/use-slash-command.cjs.map +1 -1
  271. package/dist/hooks/chat/use-slash-command.js +1 -1
  272. package/dist/hooks/chat/use-slash-command.js.map +1 -1
  273. package/dist/hooks/mutation/use-switch-llm-profile.cjs.map +1 -1
  274. package/dist/hooks/mutation/use-switch-llm-profile.d.ts +1 -1
  275. package/dist/hooks/mutation/use-switch-llm-profile.js.map +1 -1
  276. package/dist/hooks/query/use-config.cjs +1 -1
  277. package/dist/hooks/query/use-config.cjs.map +1 -1
  278. package/dist/hooks/query/use-config.js +10 -10
  279. package/dist/hooks/query/use-config.js.map +1 -1
  280. package/dist/hooks/query/use-conversation-skills.cjs +2 -0
  281. package/dist/hooks/query/use-conversation-skills.cjs.map +1 -0
  282. package/dist/hooks/query/use-conversation-skills.d.ts +7 -0
  283. package/dist/hooks/query/use-conversation-skills.js +8 -0
  284. package/dist/hooks/query/use-conversation-skills.js.map +1 -0
  285. package/dist/hooks/query/use-local-git-info.cjs +3 -3
  286. package/dist/hooks/query/use-local-git-info.cjs.map +1 -1
  287. package/dist/hooks/query/use-local-git-info.js +24 -25
  288. package/dist/hooks/query/use-local-git-info.js.map +1 -1
  289. package/dist/hooks/query/use-skills.cjs +1 -1
  290. package/dist/hooks/query/use-skills.cjs.map +1 -1
  291. package/dist/hooks/query/use-skills.d.ts +6 -1
  292. package/dist/hooks/query/use-skills.js +3 -3
  293. package/dist/hooks/query/use-skills.js.map +1 -1
  294. package/dist/i18n/declaration.cjs +1 -1
  295. package/dist/i18n/declaration.cjs.map +1 -1
  296. package/dist/i18n/declaration.d.ts +7 -0
  297. package/dist/i18n/declaration.js +1 -1
  298. package/dist/i18n/declaration.js.map +1 -1
  299. package/dist/i18n/translation.cjs +2 -2
  300. package/dist/i18n/translation.cjs.map +1 -1
  301. package/dist/i18n/translation.js +119 -0
  302. package/dist/i18n/translation.js.map +1 -1
  303. package/dist/locales/ar/openhands.json +7 -0
  304. package/dist/locales/ca/openhands.json +7 -0
  305. package/dist/locales/de/openhands.json +7 -0
  306. package/dist/locales/en/openhands.json +7 -0
  307. package/dist/locales/es/openhands.json +7 -0
  308. package/dist/locales/fr/openhands.json +7 -0
  309. package/dist/locales/it/openhands.json +7 -0
  310. package/dist/locales/ja/openhands.json +7 -0
  311. package/dist/locales/ko-KR/openhands.json +7 -0
  312. package/dist/locales/no/openhands.json +7 -0
  313. package/dist/locales/pt/openhands.json +7 -0
  314. package/dist/locales/tr/openhands.json +7 -0
  315. package/dist/locales/uk/openhands.json +7 -0
  316. package/dist/locales/zh-CN/openhands.json +7 -0
  317. package/dist/locales/zh-TW/openhands.json +7 -0
  318. package/dist/package.cjs +1 -1
  319. package/dist/package.cjs.map +1 -1
  320. package/dist/package.js +3 -3
  321. package/dist/package.js.map +1 -1
  322. package/dist/routes/conversation.cjs +1 -1
  323. package/dist/routes/conversation.cjs.map +1 -1
  324. package/dist/routes/conversation.js +61 -63
  325. package/dist/routes/conversation.js.map +1 -1
  326. package/dist/routes/mcp.cjs +1 -1
  327. package/dist/routes/mcp.cjs.map +1 -1
  328. package/dist/routes/mcp.js +64 -64
  329. package/dist/routes/mcp.js.map +1 -1
  330. package/dist/stores/browser-store.cjs +1 -1
  331. package/dist/stores/browser-store.cjs.map +1 -1
  332. package/dist/stores/browser-store.js +1 -1
  333. package/dist/stores/browser-store.js.map +1 -1
  334. package/dist/stores/use-event-store.cjs +1 -1
  335. package/dist/stores/use-event-store.cjs.map +1 -1
  336. package/dist/stores/use-event-store.d.ts +22 -0
  337. package/dist/stores/use-event-store.js +9 -1
  338. package/dist/stores/use-event-store.js.map +1 -1
  339. package/dist/ui/context-menu.d.ts +1 -1
  340. package/dist/ui/help-link.d.ts +1 -1
  341. package/dist/utils/mcp-marketplace-utils.cjs +1 -1
  342. package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
  343. package/dist/utils/mcp-marketplace-utils.d.ts +13 -22
  344. package/dist/utils/mcp-marketplace-utils.js +46 -28
  345. package/dist/utils/mcp-marketplace-utils.js.map +1 -1
  346. package/dist/utils/sdk-settings-schema.cjs +1 -1
  347. package/dist/utils/sdk-settings-schema.cjs.map +1 -1
  348. package/dist/utils/sdk-settings-schema.d.ts +1 -0
  349. package/dist/utils/sdk-settings-schema.js +1 -1
  350. package/dist/utils/sdk-settings-schema.js.map +1 -1
  351. package/package.json +3 -3
  352. package/scripts/dev-safe.mjs +94 -57
  353. package/scripts/dev-static.mjs +2 -3
  354. package/scripts/dev-with-automation.mjs +98 -67
  355. package/scripts/static-server.mjs +77 -35
  356. package/tools/canvas_ui_tool.py +4 -0
  357. package/build/assets/acp-providers-DauuOsW9.js +0 -1
  358. package/build/assets/add-backend-modal-KMmPQNZU.js +0 -1
  359. package/build/assets/agent-server-client-options-DT2GP6VJ.js +0 -1
  360. package/build/assets/agent-server-compatibility-2aOx5iWd.js +0 -1
  361. package/build/assets/agent-server-conversation-service.api-DSl9G5UR.js +0 -5
  362. package/build/assets/backend-form-modal-K6IMCr3p.js +0 -1
  363. package/build/assets/browser-DKG63inJ.js +0 -5
  364. package/build/assets/browser-store-C3AqxAO7.js +0 -1
  365. package/build/assets/browser-tab-B_BuTvrO.js +0 -1
  366. package/build/assets/conversation-BD5WemJI.js +0 -19
  367. package/build/assets/conversation-C47K62n8.js +0 -1
  368. package/build/assets/conversation-panel-Dn-S56Gk.js +0 -1
  369. package/build/assets/conversation-websocket-context-Ywrxd_9p.js +0 -3
  370. package/build/assets/declaration-D378OjpZ.js +0 -1
  371. package/build/assets/files-tab-B3A1NDlZ.js +0 -1
  372. package/build/assets/git-control-bar-branch-button-CcIpmyfM.js +0 -27
  373. package/build/assets/home-dIzxi5Dd.js +0 -1
  374. package/build/assets/install-server-modal-z5VaHeXd.js +0 -1
  375. package/build/assets/llm-settings-2036m7Wt.js +0 -1
  376. package/build/assets/llm-settings-CcHqGOYL.js +0 -1
  377. package/build/assets/manifest-97e839da.js +0 -1
  378. package/build/assets/mcp-C06YssEI.js +0 -9
  379. package/build/assets/root-BS1Td78t.js +0 -2
  380. package/build/assets/sdk-section-page-CJW0G04-.js +0 -1
  381. package/build/assets/secrets-settings-MLXqOtX2.js +0 -1
  382. package/build/assets/use-active-conversation-D15D9GgR.js +0 -1
  383. package/build/assets/use-config-BSu_53GL.js +0 -1
  384. package/build/assets/use-conversation-id-DajhCn2A.js +0 -1
  385. package/build/assets/use-is-authed-hXC8vxgT.js +0 -1
  386. package/build/assets/use-runtime-is-ready-XFbT16BD.js +0 -1
  387. package/build/assets/use-skills-Xe0vjPMt.js +0 -1
  388. package/build/assets/use-unified-vscode-url-BOsIOd-b.js +0 -1
  389. package/build/assets/use-user-conversation-Mc0mQgkl.js +0 -1
  390. /package/build/assets/{automation-XLxhq3I8.js → automation-IdgZq6ZK.js} +0 -0
  391. /package/build/assets/{common-SMkEaBSr.js → common-DR1t-EeP.js} +0 -0
  392. /package/build/assets/{conversation-state-store-Bc0slAjL.js → conversation-state-store-u5jepov0.js} +0 -0
  393. /package/build/assets/{dist-yMQV8IUk.js → dist-BxBP7tFD.js} +0 -0
  394. /package/build/assets/{git-status-mapper-BI8FyUVp.js → git-status-mapper-DnL9OC8_.js} +0 -0
  395. /package/build/assets/{handle-capture-consent-BfZATzpI.js → handle-capture-consent-3XrjZ8wi.js} +0 -0
  396. /package/build/assets/{iconBase-C7N9pPOs.js → iconBase-DE30Zj_-.js} +0 -0
  397. /package/build/assets/{settings-D5am1n6X.js → settings-D_H-qsRm.js} +0 -0
  398. /package/build/assets/{settings-like-page-layout-classes-Bn-M9oOa.js → settings-like-page-layout-classes-I0BDBEoq.js} +0 -0
  399. /package/build/assets/{settings-utils-BsvSU3OM.js → settings-utils-B6Nl07io.js} +0 -0
  400. /package/build/assets/{sidebar-store-cOeaKmIm.js → sidebar-store-Uy3v0AOV.js} +0 -0
  401. /package/build/assets/{use-breakpoint-B86yKT9n.js → use-breakpoint-DbJ6FkQ-.js} +0 -0
  402. /package/build/assets/{use-click-outside-element-835W9pC6.js → use-click-outside-element-DffgWWoZ.js} +0 -0
  403. /package/build/assets/{vendor~browser-BpdPBhgZ.js → vendor~browser-DDiZgqD3.js} +0 -0
  404. /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-Df7_G0zR.js → vendor~conversation-panel~conversation~alert-banner-DbvX3OcM.js} +0 -0
  405. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~b4cctr4k-B7YVdv1X.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~g56ukk6u-DsSvIDZQ.js} +0 -0
  406. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~i9dbt75i-CI82Did1.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~hkqzh1hb-BZ0HXuHD.js} +0 -0
  407. /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~pfbaerbd-zhv9fooy.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~ninslayh-D9P8e98a.js} +0 -0
  408. /package/build/assets/{vendor~terminal-BUxzHKcC.js → vendor~terminal-DUrOWGFE.js} +0 -0
  409. /package/build/assets/{vscode-url-helper-jesbpos5.js → vscode-url-helper-Cwy1A62q.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.cjs","names":[],"sources":["../../src/routes/conversation.tsx"],"sourcesContent":["import React from \"react\";\nimport { useNavigate, useLocation, useMatch } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\n\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useCommandStore } from \"#/stores/command-store\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { useAgentStore } from \"#/stores/agent-store\";\nimport { useConversationStateStore } from \"#/stores/conversation-state-store\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n clearLastConversationId,\n setLastConversationId,\n} from \"#/api/backend-registry/last-conversation-store\";\nimport { AgentState } from \"#/types/agent-state\";\n\nimport { EventHandler } from \"../wrapper/event-handler\";\n\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useTaskPolling } from \"#/hooks/query/use-task-polling\";\n\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { useIsAuthed } from \"#/hooks/query/use-is-authed\";\nimport {\n ConversationMain,\n ConversationMobilePanelPage,\n} from \"#/components/features/conversation/conversation-main/conversation-main\";\n\nimport { WebSocketProviderWrapper } from \"#/contexts/websocket-provider-wrapper\";\nimport { useErrorMessageStore } from \"#/stores/error-message-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { useEventStore } from \"#/stores/use-event-store\";\nimport { resumeCloudSandbox } from \"#/api/cloud/conversation-service.api\";\n\nfunction AppContent() {\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const panelViewMatch = useMatch(\"/conversations/:conversationId/panel\");\n const clearEvents = useEventStore((state) => state.clearEvents);\n\n const { isTask, taskStatus, taskDetail } = useTaskPolling();\n\n // The conversationId in the URL belongs to whichever backend was\n // active when the route first mounted. If the user switches backends\n // while this route is still mounted, the id is meaningless under the\n // new backend — disable the active-conversation fetch (and its 404\n // toast) so we don't fire a request that the BackendSelector's\n // redirect will immediately navigate away from anyway. Mirrors the\n // same guard in `routes/automation-detail.tsx`.\n const active = useActiveBackend();\n const mountedBackendId = React.useRef(active.backend.id);\n const mountedOrgId = React.useRef(active.orgId);\n const backendChanged =\n mountedBackendId.current !== active.backend.id ||\n mountedOrgId.current !== active.orgId;\n\n const { data: conversation, isFetched } = useActiveConversation();\n const { data: isAuthed } = useIsAuthed();\n const { resetConversationState } = useConversationStore();\n const navigate = useNavigate();\n const location = useLocation();\n const clearTerminal = useCommandStore((state) => state.clearTerminal);\n const resetConversationRuntimeState = useConversationStateStore(\n (state) => state.reset,\n );\n const setCurrentAgentState = useAgentStore(\n (state) => state.setCurrentAgentState,\n );\n const removeErrorMessage = useErrorMessageStore(\n (state) => state.removeErrorMessage,\n );\n\n React.useEffect(() => {\n clearTerminal();\n resetConversationState();\n resetConversationRuntimeState();\n setCurrentAgentState(AgentState.LOADING);\n removeErrorMessage();\n clearEvents();\n }, [\n conversationId,\n clearTerminal,\n resetConversationState,\n resetConversationRuntimeState,\n setCurrentAgentState,\n removeErrorMessage,\n clearEvents,\n ]);\n\n React.useEffect(() => {\n if (isTask && taskStatus === \"ERROR\") {\n displayErrorToast(\n taskDetail || t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK),\n );\n // Navigate back to the original conversation when a resume task fails so\n // the user isn't stranded at the dead task-{id} URL. The resume effect's\n // ref prevents it from immediately retrying once we land there.\n const resumedFrom = (location.state as Record<string, unknown> | null)\n ?.resumedFromConversationId as string | undefined;\n navigate(\n resumedFrom ? `/conversations/${resumedFrom}` : \"/conversations\",\n { replace: true },\n );\n }\n }, [isTask, taskStatus, taskDetail, t, navigate, location.state]);\n\n React.useEffect(() => {\n if (!isFetched || !isAuthed) return;\n // The BackendSelector is in the middle of redirecting us away from\n // this route — don't toast/navigate based on a 404 that's just\n // \"this id doesn't exist on the new backend\".\n if (backendChanged) return;\n\n if (!conversation) {\n // Clear the per-backend \"last selected\" slot so the next switch\n // to this backend doesn't try to revisit a stale id.\n clearLastConversationId(active.backend.id, active.orgId);\n displayErrorToast(t(I18nKey.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION));\n navigate(\"/conversations\");\n }\n }, [\n conversation,\n isFetched,\n isAuthed,\n navigate,\n t,\n backendChanged,\n active.backend.id,\n active.orgId,\n ]);\n\n // Remember the most recently selected conversation for the current\n // (backend, org) so flipping back to this backend later restores the\n // user to where they left off. Skip while a backend switch is in\n // flight: the id in the URL is from the previous backend and would\n // otherwise overwrite the new backend's memory.\n React.useEffect(() => {\n if (backendChanged) return;\n if (!conversationId) return;\n if (conversationId.startsWith(\"task-\")) return;\n setLastConversationId(active.backend.id, active.orgId, conversationId);\n }, [conversationId, backendChanged, active.backend.id, active.orgId]);\n\n // Cloud conversation resume: mirrors OpenHands' useSandboxRecovery.\n //\n // When the cloud API reports sandbox_status === \"PAUSED\" the sandbox is\n // sleeping. The correct wake-up call is POST /api/v1/sandboxes/{id}/resume\n // (a lightweight unpause). The previous approach — creating a new start task\n // via POST /api/v1/app-conversations — was wrong: it tries to provision a\n // fresh conversation in the sandbox and is subject to a 120-second cold-start\n // timeout that can fail. The resume endpoint simply unpauses the existing one.\n //\n // After calling resume we stay on the current URL. The 3-second refetch\n // interval in useActiveConversation (active while conversation_url is null)\n // polls until conversation_url populates, then the WebSocket connects.\n //\n // A ref guards against duplicate triggers per unique conversation.id within\n // the same route-mount lifetime.\n const resumeTriggeredForRef = React.useRef<string | null>(null);\n React.useEffect(() => {\n if (!isFetched || !conversation) return;\n if (active.backend.kind !== \"cloud\") return;\n if (conversation.sandbox_status !== \"PAUSED\") return; // only resume PAUSED sandboxes\n if (!conversation.sandbox_id) return; // no sandbox to resume\n if (resumeTriggeredForRef.current === conversation.id) return; // already sent\n\n resumeTriggeredForRef.current = conversation.id;\n\n resumeCloudSandbox(conversation.sandbox_id).catch(() => {\n displayErrorToast(t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK));\n });\n }, [\n isFetched,\n conversation?.id,\n conversation?.sandbox_status,\n conversation?.sandbox_id,\n active.backend.kind,\n t,\n ]);\n\n const content = (\n <EventHandler>\n <div data-testid=\"app-route\" className=\"flex h-full flex-col\">\n {panelViewMatch ? (\n <ConversationMobilePanelPage\n onNavigateBack={() => navigate(`/conversations/${conversationId}`)}\n />\n ) : (\n <ConversationMain />\n )}\n </div>\n </EventHandler>\n );\n\n return (\n <WebSocketProviderWrapper conversationId={conversationId}>\n {content}\n </WebSocketProviderWrapper>\n );\n}\n\nexport function ConversationView() {\n return <AppContent />;\n}\n\nexport default ConversationView;\n"],"mappings":"mpCAkCA,SAAS,GAAa,CACpB,GAAM,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,CAAE,kBAAmB,EAAA,mBAAmB,CACxC,GAAA,EAAA,EAAA,UAA0B,uCAAuC,CACjE,EAAc,EAAA,cAAe,GAAU,EAAM,YAAY,CAEzD,CAAE,SAAQ,aAAY,cAAe,EAAA,gBAAgB,CASrD,EAAS,EAAA,kBAAkB,CAC3B,EAAmB,EAAA,QAAM,OAAO,EAAO,QAAQ,GAAG,CAClD,EAAe,EAAA,QAAM,OAAO,EAAO,MAAM,CACzC,EACJ,EAAiB,UAAY,EAAO,QAAQ,IAC5C,EAAa,UAAY,EAAO,MAE5B,CAAE,KAAM,EAAc,aAAc,EAAA,uBAAuB,CAC3D,CAAE,KAAM,GAAa,EAAA,aAAa,CAClC,CAAE,0BAA2B,EAAA,sBAAsB,CACnD,GAAA,EAAA,EAAA,cAAwB,CACxB,GAAA,EAAA,EAAA,cAAwB,CACxB,EAAgB,EAAA,gBAAiB,GAAU,EAAM,cAAc,CAC/D,EAAgC,EAAA,0BACnC,GAAU,EAAM,MAClB,CACK,EAAuB,EAAA,cAC1B,GAAU,EAAM,qBAClB,CACK,EAAqB,EAAA,qBACxB,GAAU,EAAM,mBAClB,CAED,EAAA,QAAM,cAAgB,CACpB,GAAe,CACf,GAAwB,CACxB,GAA+B,CAC/B,EAAqB,EAAA,WAAW,QAAQ,CACxC,GAAoB,CACpB,GAAa,EACZ,CACD,EACA,EACA,EACA,EACA,EACA,EACA,EACD,CAAC,CAEF,EAAA,QAAM,cAAgB,CACpB,GAAI,GAAU,IAAe,QAAS,CACpC,EAAA,kBACE,GAAc,EAAE,EAAA,QAAQ,uCAAuC,CAChE,CAID,IAAM,EAAe,EAAS,OAC1B,0BACJ,EACE,EAAc,kBAAkB,IAAgB,iBAChD,CAAE,QAAS,GAAM,CAClB,GAEF,CAAC,EAAQ,EAAY,EAAY,EAAG,EAAU,EAAS,MAAM,CAAC,CAEjE,EAAA,QAAM,cAAgB,CAChB,CAAC,GAAa,CAAC,GAIf,GAEC,IAGH,EAAA,wBAAwB,EAAO,QAAQ,GAAI,EAAO,MAAM,CACxD,EAAA,kBAAkB,EAAE,EAAA,QAAQ,wCAAwC,CAAC,CACrE,EAAS,iBAAiB,GAE3B,CACD,EACA,EACA,EACA,EACA,EACA,EACA,EAAO,QAAQ,GACf,EAAO,MACR,CAAC,CAOF,EAAA,QAAM,cAAgB,CAChB,GACC,IACD,EAAe,WAAW,QAAQ,EACtC,EAAA,sBAAsB,EAAO,QAAQ,GAAI,EAAO,MAAO,EAAe,GACrE,CAAC,EAAgB,EAAgB,EAAO,QAAQ,GAAI,EAAO,MAAM,CAAC,CAiBrE,IAAM,EAAwB,EAAA,QAAM,OAAsB,KAAK,CAoC/D,OAnCA,EAAA,QAAM,cAAgB,CAChB,CAAC,GAAa,CAAC,GACf,EAAO,QAAQ,OAAS,SACxB,EAAa,iBAAmB,UAC/B,EAAa,YACd,EAAsB,UAAY,EAAa,KAEnD,EAAsB,QAAU,EAAa,GAE7C,EAAA,mBAAmB,EAAa,WAAW,CAAC,UAAY,CACtD,EAAA,kBAAkB,EAAE,EAAA,QAAQ,uCAAuC,CAAC,EACpE,GACD,CACD,EACA,GAAc,GACd,GAAc,eACd,GAAc,WACd,EAAO,QAAQ,KACf,EACD,CAAC,EAiBA,EAAA,EAAA,KAAC,EAAA,yBAAD,CAA0C,2BACvC,EAAA,EAAA,KAfF,EAAA,aAAD,CAAA,UACE,EAAA,EAAA,KAAC,MAAD,CAAK,cAAY,YAAY,UAAU,gCACpC,GACC,EAAA,EAAA,KAAC,EAAA,4BAAD,CACE,mBAAsB,EAAS,kBAAkB,IAAiB,CAClE,CAAA,EAEF,EAAA,EAAA,KAAC,EAAA,iBAAD,EAAoB,CAAA,CAElB,CAAA,CACO,CAKZ,CACwB,CAAA,CAI/B,SAAgB,GAAmB,CACjC,OAAO,EAAA,EAAA,KAAC,EAAD,EAAc,CAAA"}
1
+ {"version":3,"file":"conversation.cjs","names":[],"sources":["../../src/routes/conversation.tsx"],"sourcesContent":["import React from \"react\";\nimport { useNavigate, useLocation, useMatch } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\n\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useCommandStore } from \"#/stores/command-store\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { useAgentStore } from \"#/stores/agent-store\";\nimport { useConversationStateStore } from \"#/stores/conversation-state-store\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n clearLastConversationId,\n setLastConversationId,\n} from \"#/api/backend-registry/last-conversation-store\";\nimport { AgentState } from \"#/types/agent-state\";\n\nimport { EventHandler } from \"../wrapper/event-handler\";\n\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useTaskPolling } from \"#/hooks/query/use-task-polling\";\n\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { useIsAuthed } from \"#/hooks/query/use-is-authed\";\nimport {\n ConversationMain,\n ConversationMobilePanelPage,\n} from \"#/components/features/conversation/conversation-main/conversation-main\";\n\nimport { WebSocketProviderWrapper } from \"#/contexts/websocket-provider-wrapper\";\nimport { useErrorMessageStore } from \"#/stores/error-message-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { resumeCloudSandbox } from \"#/api/cloud/conversation-service.api\";\n\nfunction AppContent() {\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const panelViewMatch = useMatch(\"/conversations/:conversationId/panel\");\n\n const { isTask, taskStatus, taskDetail } = useTaskPolling();\n\n // The conversationId in the URL belongs to whichever backend was\n // active when the route first mounted. If the user switches backends\n // while this route is still mounted, the id is meaningless under the\n // new backend — disable the active-conversation fetch (and its 404\n // toast) so we don't fire a request that the BackendSelector's\n // redirect will immediately navigate away from anyway. Mirrors the\n // same guard in `routes/automation-detail.tsx`.\n const active = useActiveBackend();\n const mountedBackendId = React.useRef(active.backend.id);\n const mountedOrgId = React.useRef(active.orgId);\n const backendChanged =\n mountedBackendId.current !== active.backend.id ||\n mountedOrgId.current !== active.orgId;\n\n const { data: conversation, isFetched } = useActiveConversation();\n const { data: isAuthed } = useIsAuthed();\n const { resetConversationState } = useConversationStore();\n const navigate = useNavigate();\n const location = useLocation();\n const clearTerminal = useCommandStore((state) => state.clearTerminal);\n const resetConversationRuntimeState = useConversationStateStore(\n (state) => state.reset,\n );\n const setCurrentAgentState = useAgentStore(\n (state) => state.setCurrentAgentState,\n );\n const removeErrorMessage = useErrorMessageStore(\n (state) => state.removeErrorMessage,\n );\n\n // Per-conversation UI/runtime resets. The event store is cleared separately,\n // inside ConversationWebSocketProvider, so the clear is ordered *before* the\n // preloaded-history re-seed (see the note there) — clearing it here would run\n // too late and wipe the freshly seeded history on a conversation switch.\n React.useEffect(() => {\n clearTerminal();\n resetConversationState();\n resetConversationRuntimeState();\n setCurrentAgentState(AgentState.LOADING);\n removeErrorMessage();\n }, [\n conversationId,\n clearTerminal,\n resetConversationState,\n resetConversationRuntimeState,\n setCurrentAgentState,\n removeErrorMessage,\n ]);\n\n React.useEffect(() => {\n if (isTask && taskStatus === \"ERROR\") {\n displayErrorToast(\n taskDetail || t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK),\n );\n // Navigate back to the original conversation when a resume task fails so\n // the user isn't stranded at the dead task-{id} URL. The resume effect's\n // ref prevents it from immediately retrying once we land there.\n const resumedFrom = (location.state as Record<string, unknown> | null)\n ?.resumedFromConversationId as string | undefined;\n navigate(\n resumedFrom ? `/conversations/${resumedFrom}` : \"/conversations\",\n { replace: true },\n );\n }\n }, [isTask, taskStatus, taskDetail, t, navigate, location.state]);\n\n React.useEffect(() => {\n if (!isFetched || !isAuthed) return;\n // The BackendSelector is in the middle of redirecting us away from\n // this route — don't toast/navigate based on a 404 that's just\n // \"this id doesn't exist on the new backend\".\n if (backendChanged) return;\n\n if (!conversation) {\n // Clear the per-backend \"last selected\" slot so the next switch\n // to this backend doesn't try to revisit a stale id.\n clearLastConversationId(active.backend.id, active.orgId);\n displayErrorToast(t(I18nKey.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION));\n navigate(\"/conversations\");\n }\n }, [\n conversation,\n isFetched,\n isAuthed,\n navigate,\n t,\n backendChanged,\n active.backend.id,\n active.orgId,\n ]);\n\n // Remember the most recently selected conversation for the current\n // (backend, org) so flipping back to this backend later restores the\n // user to where they left off. Skip while a backend switch is in\n // flight: the id in the URL is from the previous backend and would\n // otherwise overwrite the new backend's memory.\n React.useEffect(() => {\n if (backendChanged) return;\n if (!conversationId) return;\n if (conversationId.startsWith(\"task-\")) return;\n setLastConversationId(active.backend.id, active.orgId, conversationId);\n }, [conversationId, backendChanged, active.backend.id, active.orgId]);\n\n // Cloud conversation resume: mirrors OpenHands' useSandboxRecovery.\n //\n // When the cloud API reports sandbox_status === \"PAUSED\" the sandbox is\n // sleeping. The correct wake-up call is POST /api/v1/sandboxes/{id}/resume\n // (a lightweight unpause). The previous approach — creating a new start task\n // via POST /api/v1/app-conversations — was wrong: it tries to provision a\n // fresh conversation in the sandbox and is subject to a 120-second cold-start\n // timeout that can fail. The resume endpoint simply unpauses the existing one.\n //\n // After calling resume we stay on the current URL. The 3-second refetch\n // interval in useActiveConversation (active while conversation_url is null)\n // polls until conversation_url populates, then the WebSocket connects.\n //\n // A ref guards against duplicate triggers per unique conversation.id within\n // the same route-mount lifetime.\n const resumeTriggeredForRef = React.useRef<string | null>(null);\n React.useEffect(() => {\n if (!isFetched || !conversation) return;\n if (active.backend.kind !== \"cloud\") return;\n if (conversation.sandbox_status !== \"PAUSED\") return; // only resume PAUSED sandboxes\n if (!conversation.sandbox_id) return; // no sandbox to resume\n if (resumeTriggeredForRef.current === conversation.id) return; // already sent\n\n resumeTriggeredForRef.current = conversation.id;\n\n resumeCloudSandbox(conversation.sandbox_id).catch(() => {\n displayErrorToast(t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK));\n });\n }, [\n isFetched,\n conversation?.id,\n conversation?.sandbox_status,\n conversation?.sandbox_id,\n active.backend.kind,\n t,\n ]);\n\n const content = (\n <EventHandler>\n <div data-testid=\"app-route\" className=\"flex h-full flex-col\">\n {panelViewMatch ? (\n <ConversationMobilePanelPage\n onNavigateBack={() => navigate(`/conversations/${conversationId}`)}\n />\n ) : (\n <ConversationMain />\n )}\n </div>\n </EventHandler>\n );\n\n return (\n <WebSocketProviderWrapper conversationId={conversationId}>\n {content}\n </WebSocketProviderWrapper>\n );\n}\n\nexport function ConversationView() {\n return <AppContent />;\n}\n\nexport default ConversationView;\n"],"mappings":"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"}
@@ -9,88 +9,86 @@ import { useConversationStateStore as s } from "../stores/conversation-state-sto
9
9
  import { useActiveBackend as c } from "../contexts/active-backend-context.js";
10
10
  import { clearLastConversationId as l, setLastConversationId as u } from "../api/backend-registry/last-conversation-store.js";
11
11
  import { displayErrorToast as d } from "../utils/custom-toast-handlers.js";
12
- import { useEventStore as f } from "../stores/use-event-store.js";
13
- import { useErrorMessageStore as p } from "../stores/error-message-store.js";
14
- import { resumeCloudSandbox as m } from "../api/cloud/conversation-service.api.js";
15
- import { useActiveConversation as h } from "../hooks/query/use-active-conversation.js";
16
- import { EventHandler as g } from "../wrapper/event-handler.js";
17
- import { useTaskPolling as _ } from "../hooks/query/use-task-polling.js";
18
- import { useIsAuthed as v } from "../hooks/query/use-is-authed.js";
19
- import { ConversationMain as y, ConversationMobilePanelPage as b } from "../components/features/conversation/conversation-main/conversation-main.js";
20
- import { WebSocketProviderWrapper as x } from "../contexts/websocket-provider-wrapper.js";
21
- import S from "react";
22
- import { jsx as C } from "react/jsx-runtime";
23
- import { useLocation as w, useMatch as T, useNavigate as E } from "react-router";
12
+ import { useErrorMessageStore as f } from "../stores/error-message-store.js";
13
+ import { resumeCloudSandbox as p } from "../api/cloud/conversation-service.api.js";
14
+ import { useActiveConversation as m } from "../hooks/query/use-active-conversation.js";
15
+ import { EventHandler as h } from "../wrapper/event-handler.js";
16
+ import { useTaskPolling as g } from "../hooks/query/use-task-polling.js";
17
+ import { useIsAuthed as _ } from "../hooks/query/use-is-authed.js";
18
+ import { ConversationMain as v, ConversationMobilePanelPage as y } from "../components/features/conversation/conversation-main/conversation-main.js";
19
+ import { WebSocketProviderWrapper as b } from "../contexts/websocket-provider-wrapper.js";
20
+ import x from "react";
21
+ import { jsx as S } from "react/jsx-runtime";
22
+ import { useLocation as C, useMatch as w, useNavigate as T } from "react-router";
24
23
  //#region src/routes/conversation.tsx
25
- function D() {
26
- let { t: D } = e("openhands"), { conversationId: O } = r(), k = T("/conversations/:conversationId/panel"), A = f((e) => e.clearEvents), { isTask: j, taskStatus: M, taskDetail: N } = _(), P = c(), F = S.useRef(P.backend.id), I = S.useRef(P.orgId), L = F.current !== P.backend.id || I.current !== P.orgId, { data: R, isFetched: z } = h(), { data: B } = v(), { resetConversationState: V } = a(), H = E(), U = w(), W = i((e) => e.clearTerminal), G = s((e) => e.reset), K = o((e) => e.setCurrentAgentState), q = p((e) => e.removeErrorMessage);
27
- S.useEffect(() => {
28
- W(), V(), G(), K(n.LOADING), q(), A();
24
+ function E() {
25
+ let { t: E } = e("openhands"), { conversationId: D } = r(), O = w("/conversations/:conversationId/panel"), { isTask: k, taskStatus: A, taskDetail: j } = g(), M = c(), N = x.useRef(M.backend.id), P = x.useRef(M.orgId), F = N.current !== M.backend.id || P.current !== M.orgId, { data: I, isFetched: L } = m(), { data: R } = _(), { resetConversationState: z } = a(), B = T(), V = C(), H = i((e) => e.clearTerminal), U = s((e) => e.reset), W = o((e) => e.setCurrentAgentState), G = f((e) => e.removeErrorMessage);
26
+ x.useEffect(() => {
27
+ H(), z(), U(), W(n.LOADING), G();
29
28
  }, [
30
- O,
29
+ D,
30
+ H,
31
+ z,
32
+ U,
31
33
  W,
32
- V,
33
- G,
34
- K,
35
- q,
36
- A
37
- ]), S.useEffect(() => {
38
- if (j && M === "ERROR") {
39
- d(N || D(t.CONVERSATION$FAILED_TO_START_FROM_TASK));
40
- let e = U.state?.resumedFromConversationId;
41
- H(e ? `/conversations/${e}` : "/conversations", { replace: !0 });
34
+ G
35
+ ]), x.useEffect(() => {
36
+ if (k && A === "ERROR") {
37
+ d(j || E(t.CONVERSATION$FAILED_TO_START_FROM_TASK));
38
+ let e = V.state?.resumedFromConversationId;
39
+ B(e ? `/conversations/${e}` : "/conversations", { replace: !0 });
42
40
  }
43
41
  }, [
42
+ k,
43
+ A,
44
44
  j,
45
- M,
46
- N,
47
- D,
48
- H,
49
- U.state
50
- ]), S.useEffect(() => {
51
- !z || !B || L || R || (l(P.backend.id, P.orgId), d(D(t.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION)), H("/conversations"));
45
+ E,
46
+ B,
47
+ V.state
48
+ ]), x.useEffect(() => {
49
+ !L || !R || F || I || (l(M.backend.id, M.orgId), d(E(t.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION)), B("/conversations"));
52
50
  }, [
51
+ I,
52
+ L,
53
53
  R,
54
- z,
55
54
  B,
56
- H,
57
- D,
58
- L,
59
- P.backend.id,
60
- P.orgId
61
- ]), S.useEffect(() => {
62
- L || O && (O.startsWith("task-") || u(P.backend.id, P.orgId, O));
55
+ E,
56
+ F,
57
+ M.backend.id,
58
+ M.orgId
59
+ ]), x.useEffect(() => {
60
+ F || D && (D.startsWith("task-") || u(M.backend.id, M.orgId, D));
63
61
  }, [
64
- O,
65
- L,
66
- P.backend.id,
67
- P.orgId
62
+ D,
63
+ F,
64
+ M.backend.id,
65
+ M.orgId
68
66
  ]);
69
- let J = S.useRef(null);
70
- return S.useEffect(() => {
71
- !z || !R || P.backend.kind === "cloud" && R.sandbox_status === "PAUSED" && R.sandbox_id && J.current !== R.id && (J.current = R.id, m(R.sandbox_id).catch(() => {
72
- d(D(t.CONVERSATION$FAILED_TO_START_FROM_TASK));
67
+ let K = x.useRef(null);
68
+ return x.useEffect(() => {
69
+ !L || !I || M.backend.kind === "cloud" && I.sandbox_status === "PAUSED" && I.sandbox_id && K.current !== I.id && (K.current = I.id, p(I.sandbox_id).catch(() => {
70
+ d(E(t.CONVERSATION$FAILED_TO_START_FROM_TASK));
73
71
  }));
74
72
  }, [
75
- z,
76
- R?.id,
77
- R?.sandbox_status,
78
- R?.sandbox_id,
79
- P.backend.kind,
80
- D
81
- ]), /* @__PURE__ */ C(x, {
82
- conversationId: O,
83
- children: /* @__PURE__ */ C(g, { children: /* @__PURE__ */ C("div", {
73
+ L,
74
+ I?.id,
75
+ I?.sandbox_status,
76
+ I?.sandbox_id,
77
+ M.backend.kind,
78
+ E
79
+ ]), /* @__PURE__ */ S(b, {
80
+ conversationId: D,
81
+ children: /* @__PURE__ */ S(h, { children: /* @__PURE__ */ S("div", {
84
82
  "data-testid": "app-route",
85
83
  className: "flex h-full flex-col",
86
- children: k ? /* @__PURE__ */ C(b, { onNavigateBack: () => H(`/conversations/${O}`) }) : /* @__PURE__ */ C(y, {})
84
+ children: O ? /* @__PURE__ */ S(y, { onNavigateBack: () => B(`/conversations/${D}`) }) : /* @__PURE__ */ S(v, {})
87
85
  }) })
88
86
  });
89
87
  }
90
- function O() {
91
- return /* @__PURE__ */ C(D, {});
88
+ function D() {
89
+ return /* @__PURE__ */ S(E, {});
92
90
  }
93
91
  //#endregion
94
- export { O as default };
92
+ export { D as default };
95
93
 
96
94
  //# sourceMappingURL=conversation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.js","names":[],"sources":["../../src/routes/conversation.tsx"],"sourcesContent":["import React from \"react\";\nimport { useNavigate, useLocation, useMatch } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\n\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useCommandStore } from \"#/stores/command-store\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { useAgentStore } from \"#/stores/agent-store\";\nimport { useConversationStateStore } from \"#/stores/conversation-state-store\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n clearLastConversationId,\n setLastConversationId,\n} from \"#/api/backend-registry/last-conversation-store\";\nimport { AgentState } from \"#/types/agent-state\";\n\nimport { EventHandler } from \"../wrapper/event-handler\";\n\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useTaskPolling } from \"#/hooks/query/use-task-polling\";\n\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { useIsAuthed } from \"#/hooks/query/use-is-authed\";\nimport {\n ConversationMain,\n ConversationMobilePanelPage,\n} from \"#/components/features/conversation/conversation-main/conversation-main\";\n\nimport { WebSocketProviderWrapper } from \"#/contexts/websocket-provider-wrapper\";\nimport { useErrorMessageStore } from \"#/stores/error-message-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { useEventStore } from \"#/stores/use-event-store\";\nimport { resumeCloudSandbox } from \"#/api/cloud/conversation-service.api\";\n\nfunction AppContent() {\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const panelViewMatch = useMatch(\"/conversations/:conversationId/panel\");\n const clearEvents = useEventStore((state) => state.clearEvents);\n\n const { isTask, taskStatus, taskDetail } = useTaskPolling();\n\n // The conversationId in the URL belongs to whichever backend was\n // active when the route first mounted. If the user switches backends\n // while this route is still mounted, the id is meaningless under the\n // new backend — disable the active-conversation fetch (and its 404\n // toast) so we don't fire a request that the BackendSelector's\n // redirect will immediately navigate away from anyway. Mirrors the\n // same guard in `routes/automation-detail.tsx`.\n const active = useActiveBackend();\n const mountedBackendId = React.useRef(active.backend.id);\n const mountedOrgId = React.useRef(active.orgId);\n const backendChanged =\n mountedBackendId.current !== active.backend.id ||\n mountedOrgId.current !== active.orgId;\n\n const { data: conversation, isFetched } = useActiveConversation();\n const { data: isAuthed } = useIsAuthed();\n const { resetConversationState } = useConversationStore();\n const navigate = useNavigate();\n const location = useLocation();\n const clearTerminal = useCommandStore((state) => state.clearTerminal);\n const resetConversationRuntimeState = useConversationStateStore(\n (state) => state.reset,\n );\n const setCurrentAgentState = useAgentStore(\n (state) => state.setCurrentAgentState,\n );\n const removeErrorMessage = useErrorMessageStore(\n (state) => state.removeErrorMessage,\n );\n\n React.useEffect(() => {\n clearTerminal();\n resetConversationState();\n resetConversationRuntimeState();\n setCurrentAgentState(AgentState.LOADING);\n removeErrorMessage();\n clearEvents();\n }, [\n conversationId,\n clearTerminal,\n resetConversationState,\n resetConversationRuntimeState,\n setCurrentAgentState,\n removeErrorMessage,\n clearEvents,\n ]);\n\n React.useEffect(() => {\n if (isTask && taskStatus === \"ERROR\") {\n displayErrorToast(\n taskDetail || t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK),\n );\n // Navigate back to the original conversation when a resume task fails so\n // the user isn't stranded at the dead task-{id} URL. The resume effect's\n // ref prevents it from immediately retrying once we land there.\n const resumedFrom = (location.state as Record<string, unknown> | null)\n ?.resumedFromConversationId as string | undefined;\n navigate(\n resumedFrom ? `/conversations/${resumedFrom}` : \"/conversations\",\n { replace: true },\n );\n }\n }, [isTask, taskStatus, taskDetail, t, navigate, location.state]);\n\n React.useEffect(() => {\n if (!isFetched || !isAuthed) return;\n // The BackendSelector is in the middle of redirecting us away from\n // this route — don't toast/navigate based on a 404 that's just\n // \"this id doesn't exist on the new backend\".\n if (backendChanged) return;\n\n if (!conversation) {\n // Clear the per-backend \"last selected\" slot so the next switch\n // to this backend doesn't try to revisit a stale id.\n clearLastConversationId(active.backend.id, active.orgId);\n displayErrorToast(t(I18nKey.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION));\n navigate(\"/conversations\");\n }\n }, [\n conversation,\n isFetched,\n isAuthed,\n navigate,\n t,\n backendChanged,\n active.backend.id,\n active.orgId,\n ]);\n\n // Remember the most recently selected conversation for the current\n // (backend, org) so flipping back to this backend later restores the\n // user to where they left off. Skip while a backend switch is in\n // flight: the id in the URL is from the previous backend and would\n // otherwise overwrite the new backend's memory.\n React.useEffect(() => {\n if (backendChanged) return;\n if (!conversationId) return;\n if (conversationId.startsWith(\"task-\")) return;\n setLastConversationId(active.backend.id, active.orgId, conversationId);\n }, [conversationId, backendChanged, active.backend.id, active.orgId]);\n\n // Cloud conversation resume: mirrors OpenHands' useSandboxRecovery.\n //\n // When the cloud API reports sandbox_status === \"PAUSED\" the sandbox is\n // sleeping. The correct wake-up call is POST /api/v1/sandboxes/{id}/resume\n // (a lightweight unpause). The previous approach — creating a new start task\n // via POST /api/v1/app-conversations — was wrong: it tries to provision a\n // fresh conversation in the sandbox and is subject to a 120-second cold-start\n // timeout that can fail. The resume endpoint simply unpauses the existing one.\n //\n // After calling resume we stay on the current URL. The 3-second refetch\n // interval in useActiveConversation (active while conversation_url is null)\n // polls until conversation_url populates, then the WebSocket connects.\n //\n // A ref guards against duplicate triggers per unique conversation.id within\n // the same route-mount lifetime.\n const resumeTriggeredForRef = React.useRef<string | null>(null);\n React.useEffect(() => {\n if (!isFetched || !conversation) return;\n if (active.backend.kind !== \"cloud\") return;\n if (conversation.sandbox_status !== \"PAUSED\") return; // only resume PAUSED sandboxes\n if (!conversation.sandbox_id) return; // no sandbox to resume\n if (resumeTriggeredForRef.current === conversation.id) return; // already sent\n\n resumeTriggeredForRef.current = conversation.id;\n\n resumeCloudSandbox(conversation.sandbox_id).catch(() => {\n displayErrorToast(t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK));\n });\n }, [\n isFetched,\n conversation?.id,\n conversation?.sandbox_status,\n conversation?.sandbox_id,\n active.backend.kind,\n t,\n ]);\n\n const content = (\n <EventHandler>\n <div data-testid=\"app-route\" className=\"flex h-full flex-col\">\n {panelViewMatch ? (\n <ConversationMobilePanelPage\n onNavigateBack={() => navigate(`/conversations/${conversationId}`)}\n />\n ) : (\n <ConversationMain />\n )}\n </div>\n </EventHandler>\n );\n\n return (\n <WebSocketProviderWrapper conversationId={conversationId}>\n {content}\n </WebSocketProviderWrapper>\n );\n}\n\nexport function ConversationView() {\n return <AppContent />;\n}\n\nexport default ConversationView;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAkCA,SAAS,IAAa;CACpB,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,sBAAmB,GAAmB,EACxC,IAAiB,EAAS,uCAAuC,EACjE,IAAc,GAAe,MAAU,EAAM,YAAY,EAEzD,EAAE,WAAQ,eAAY,kBAAe,GAAgB,EASrD,IAAS,GAAkB,EAC3B,IAAmB,EAAM,OAAO,EAAO,QAAQ,GAAG,EAClD,IAAe,EAAM,OAAO,EAAO,MAAM,EACzC,IACJ,EAAiB,YAAY,EAAO,QAAQ,MAC5C,EAAa,YAAY,EAAO,OAE5B,EAAE,MAAM,GAAc,iBAAc,GAAuB,EAC3D,EAAE,MAAM,MAAa,GAAa,EAClC,EAAE,8BAA2B,GAAsB,EACnD,IAAW,GAAa,EACxB,IAAW,GAAa,EACxB,IAAgB,GAAiB,MAAU,EAAM,cAAc,EAC/D,IAAgC,GACnC,MAAU,EAAM,MAClB,EACK,IAAuB,GAC1B,MAAU,EAAM,qBAClB,EACK,IAAqB,GACxB,MAAU,EAAM,mBAClB;AAkED,CAhEA,EAAM,gBAAgB;AAMpB,EALA,GAAe,EACf,GAAwB,EACxB,GAA+B,EAC/B,EAAqB,EAAW,QAAQ,EACxC,GAAoB,EACpB,GAAa;IACZ;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAEF,EAAM,gBAAgB;AACpB,MAAI,KAAU,MAAe,SAAS;AACpC,KACE,KAAc,EAAE,EAAQ,uCAAuC,CAChE;GAID,IAAM,IAAe,EAAS,OAC1B;AACJ,KACE,IAAc,kBAAkB,MAAgB,kBAChD,EAAE,SAAS,IAAM,CAClB;;IAEF;EAAC;EAAQ;EAAY;EAAY;EAAG;EAAU,EAAS;EAAM,CAAC,EAEjE,EAAM,gBAAgB;AAChB,GAAC,KAAa,CAAC,KAIf,KAEC,MAGH,EAAwB,EAAO,QAAQ,IAAI,EAAO,MAAM,EACxD,EAAkB,EAAE,EAAQ,wCAAwC,CAAC,EACrE,EAAS,iBAAiB;IAE3B;EACD;EACA;EACA;EACA;EACA;EACA;EACA,EAAO,QAAQ;EACf,EAAO;EACR,CAAC,EAOF,EAAM,gBAAgB;AAChB,OACC,MACD,EAAe,WAAW,QAAQ,IACtC,EAAsB,EAAO,QAAQ,IAAI,EAAO,OAAO,EAAe;IACrE;EAAC;EAAgB;EAAgB,EAAO,QAAQ;EAAI,EAAO;EAAM,CAAC;CAiBrE,IAAM,IAAwB,EAAM,OAAsB,KAAK;AAoC/D,QAnCA,EAAM,gBAAgB;AAChB,GAAC,KAAa,CAAC,KACf,EAAO,QAAQ,SAAS,WACxB,EAAa,mBAAmB,YAC/B,EAAa,cACd,EAAsB,YAAY,EAAa,OAEnD,EAAsB,UAAU,EAAa,IAE7C,EAAmB,EAAa,WAAW,CAAC,YAAY;AACtD,KAAkB,EAAE,EAAQ,uCAAuC,CAAC;IACpE;IACD;EACD;EACA,GAAc;EACd,GAAc;EACd,GAAc;EACd,EAAO,QAAQ;EACf;EACD,CAAC,EAiBA,kBAAC,GAAD;EAA0C;YAd1C,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;GAAK,eAAY;GAAY,WAAU;aACpC,IACC,kBAAC,GAAD,EACE,sBAAsB,EAAS,kBAAkB,IAAiB,EAClE,CAAA,GAEF,kBAAC,GAAD,EAAoB,CAAA;GAElB,CAAA,EACO,CAKZ;EACwB,CAAA;;AAI/B,SAAgB,IAAmB;AACjC,QAAO,kBAAC,GAAD,EAAc,CAAA"}
1
+ {"version":3,"file":"conversation.js","names":[],"sources":["../../src/routes/conversation.tsx"],"sourcesContent":["import React from \"react\";\nimport { useNavigate, useLocation, useMatch } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\n\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useCommandStore } from \"#/stores/command-store\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { useAgentStore } from \"#/stores/agent-store\";\nimport { useConversationStateStore } from \"#/stores/conversation-state-store\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n clearLastConversationId,\n setLastConversationId,\n} from \"#/api/backend-registry/last-conversation-store\";\nimport { AgentState } from \"#/types/agent-state\";\n\nimport { EventHandler } from \"../wrapper/event-handler\";\n\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useTaskPolling } from \"#/hooks/query/use-task-polling\";\n\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { useIsAuthed } from \"#/hooks/query/use-is-authed\";\nimport {\n ConversationMain,\n ConversationMobilePanelPage,\n} from \"#/components/features/conversation/conversation-main/conversation-main\";\n\nimport { WebSocketProviderWrapper } from \"#/contexts/websocket-provider-wrapper\";\nimport { useErrorMessageStore } from \"#/stores/error-message-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { resumeCloudSandbox } from \"#/api/cloud/conversation-service.api\";\n\nfunction AppContent() {\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const panelViewMatch = useMatch(\"/conversations/:conversationId/panel\");\n\n const { isTask, taskStatus, taskDetail } = useTaskPolling();\n\n // The conversationId in the URL belongs to whichever backend was\n // active when the route first mounted. If the user switches backends\n // while this route is still mounted, the id is meaningless under the\n // new backend — disable the active-conversation fetch (and its 404\n // toast) so we don't fire a request that the BackendSelector's\n // redirect will immediately navigate away from anyway. Mirrors the\n // same guard in `routes/automation-detail.tsx`.\n const active = useActiveBackend();\n const mountedBackendId = React.useRef(active.backend.id);\n const mountedOrgId = React.useRef(active.orgId);\n const backendChanged =\n mountedBackendId.current !== active.backend.id ||\n mountedOrgId.current !== active.orgId;\n\n const { data: conversation, isFetched } = useActiveConversation();\n const { data: isAuthed } = useIsAuthed();\n const { resetConversationState } = useConversationStore();\n const navigate = useNavigate();\n const location = useLocation();\n const clearTerminal = useCommandStore((state) => state.clearTerminal);\n const resetConversationRuntimeState = useConversationStateStore(\n (state) => state.reset,\n );\n const setCurrentAgentState = useAgentStore(\n (state) => state.setCurrentAgentState,\n );\n const removeErrorMessage = useErrorMessageStore(\n (state) => state.removeErrorMessage,\n );\n\n // Per-conversation UI/runtime resets. The event store is cleared separately,\n // inside ConversationWebSocketProvider, so the clear is ordered *before* the\n // preloaded-history re-seed (see the note there) — clearing it here would run\n // too late and wipe the freshly seeded history on a conversation switch.\n React.useEffect(() => {\n clearTerminal();\n resetConversationState();\n resetConversationRuntimeState();\n setCurrentAgentState(AgentState.LOADING);\n removeErrorMessage();\n }, [\n conversationId,\n clearTerminal,\n resetConversationState,\n resetConversationRuntimeState,\n setCurrentAgentState,\n removeErrorMessage,\n ]);\n\n React.useEffect(() => {\n if (isTask && taskStatus === \"ERROR\") {\n displayErrorToast(\n taskDetail || t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK),\n );\n // Navigate back to the original conversation when a resume task fails so\n // the user isn't stranded at the dead task-{id} URL. The resume effect's\n // ref prevents it from immediately retrying once we land there.\n const resumedFrom = (location.state as Record<string, unknown> | null)\n ?.resumedFromConversationId as string | undefined;\n navigate(\n resumedFrom ? `/conversations/${resumedFrom}` : \"/conversations\",\n { replace: true },\n );\n }\n }, [isTask, taskStatus, taskDetail, t, navigate, location.state]);\n\n React.useEffect(() => {\n if (!isFetched || !isAuthed) return;\n // The BackendSelector is in the middle of redirecting us away from\n // this route — don't toast/navigate based on a 404 that's just\n // \"this id doesn't exist on the new backend\".\n if (backendChanged) return;\n\n if (!conversation) {\n // Clear the per-backend \"last selected\" slot so the next switch\n // to this backend doesn't try to revisit a stale id.\n clearLastConversationId(active.backend.id, active.orgId);\n displayErrorToast(t(I18nKey.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION));\n navigate(\"/conversations\");\n }\n }, [\n conversation,\n isFetched,\n isAuthed,\n navigate,\n t,\n backendChanged,\n active.backend.id,\n active.orgId,\n ]);\n\n // Remember the most recently selected conversation for the current\n // (backend, org) so flipping back to this backend later restores the\n // user to where they left off. Skip while a backend switch is in\n // flight: the id in the URL is from the previous backend and would\n // otherwise overwrite the new backend's memory.\n React.useEffect(() => {\n if (backendChanged) return;\n if (!conversationId) return;\n if (conversationId.startsWith(\"task-\")) return;\n setLastConversationId(active.backend.id, active.orgId, conversationId);\n }, [conversationId, backendChanged, active.backend.id, active.orgId]);\n\n // Cloud conversation resume: mirrors OpenHands' useSandboxRecovery.\n //\n // When the cloud API reports sandbox_status === \"PAUSED\" the sandbox is\n // sleeping. The correct wake-up call is POST /api/v1/sandboxes/{id}/resume\n // (a lightweight unpause). The previous approach — creating a new start task\n // via POST /api/v1/app-conversations — was wrong: it tries to provision a\n // fresh conversation in the sandbox and is subject to a 120-second cold-start\n // timeout that can fail. The resume endpoint simply unpauses the existing one.\n //\n // After calling resume we stay on the current URL. The 3-second refetch\n // interval in useActiveConversation (active while conversation_url is null)\n // polls until conversation_url populates, then the WebSocket connects.\n //\n // A ref guards against duplicate triggers per unique conversation.id within\n // the same route-mount lifetime.\n const resumeTriggeredForRef = React.useRef<string | null>(null);\n React.useEffect(() => {\n if (!isFetched || !conversation) return;\n if (active.backend.kind !== \"cloud\") return;\n if (conversation.sandbox_status !== \"PAUSED\") return; // only resume PAUSED sandboxes\n if (!conversation.sandbox_id) return; // no sandbox to resume\n if (resumeTriggeredForRef.current === conversation.id) return; // already sent\n\n resumeTriggeredForRef.current = conversation.id;\n\n resumeCloudSandbox(conversation.sandbox_id).catch(() => {\n displayErrorToast(t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK));\n });\n }, [\n isFetched,\n conversation?.id,\n conversation?.sandbox_status,\n conversation?.sandbox_id,\n active.backend.kind,\n t,\n ]);\n\n const content = (\n <EventHandler>\n <div data-testid=\"app-route\" className=\"flex h-full flex-col\">\n {panelViewMatch ? (\n <ConversationMobilePanelPage\n onNavigateBack={() => navigate(`/conversations/${conversationId}`)}\n />\n ) : (\n <ConversationMain />\n )}\n </div>\n </EventHandler>\n );\n\n return (\n <WebSocketProviderWrapper conversationId={conversationId}>\n {content}\n </WebSocketProviderWrapper>\n );\n}\n\nexport function ConversationView() {\n return <AppContent />;\n}\n\nexport default ConversationView;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAiCA,SAAS,IAAa;CACpB,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,sBAAmB,GAAmB,EACxC,IAAiB,EAAS,uCAAuC,EAEjE,EAAE,WAAQ,eAAY,kBAAe,GAAgB,EASrD,IAAS,GAAkB,EAC3B,IAAmB,EAAM,OAAO,EAAO,QAAQ,GAAG,EAClD,IAAe,EAAM,OAAO,EAAO,MAAM,EACzC,IACJ,EAAiB,YAAY,EAAO,QAAQ,MAC5C,EAAa,YAAY,EAAO,OAE5B,EAAE,MAAM,GAAc,iBAAc,GAAuB,EAC3D,EAAE,MAAM,MAAa,GAAa,EAClC,EAAE,8BAA2B,GAAsB,EACnD,IAAW,GAAa,EACxB,IAAW,GAAa,EACxB,IAAgB,GAAiB,MAAU,EAAM,cAAc,EAC/D,IAAgC,GACnC,MAAU,EAAM,MAClB,EACK,IAAuB,GAC1B,MAAU,EAAM,qBAClB,EACK,IAAqB,GACxB,MAAU,EAAM,mBAClB;AAoED,CA9DA,EAAM,gBAAgB;AAKpB,EAJA,GAAe,EACf,GAAwB,EACxB,GAA+B,EAC/B,EAAqB,EAAW,QAAQ,EACxC,GAAoB;IACnB;EACD;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAEF,EAAM,gBAAgB;AACpB,MAAI,KAAU,MAAe,SAAS;AACpC,KACE,KAAc,EAAE,EAAQ,uCAAuC,CAChE;GAID,IAAM,IAAe,EAAS,OAC1B;AACJ,KACE,IAAc,kBAAkB,MAAgB,kBAChD,EAAE,SAAS,IAAM,CAClB;;IAEF;EAAC;EAAQ;EAAY;EAAY;EAAG;EAAU,EAAS;EAAM,CAAC,EAEjE,EAAM,gBAAgB;AAChB,GAAC,KAAa,CAAC,KAIf,KAEC,MAGH,EAAwB,EAAO,QAAQ,IAAI,EAAO,MAAM,EACxD,EAAkB,EAAE,EAAQ,wCAAwC,CAAC,EACrE,EAAS,iBAAiB;IAE3B;EACD;EACA;EACA;EACA;EACA;EACA;EACA,EAAO,QAAQ;EACf,EAAO;EACR,CAAC,EAOF,EAAM,gBAAgB;AAChB,OACC,MACD,EAAe,WAAW,QAAQ,IACtC,EAAsB,EAAO,QAAQ,IAAI,EAAO,OAAO,EAAe;IACrE;EAAC;EAAgB;EAAgB,EAAO,QAAQ;EAAI,EAAO;EAAM,CAAC;CAiBrE,IAAM,IAAwB,EAAM,OAAsB,KAAK;AAoC/D,QAnCA,EAAM,gBAAgB;AAChB,GAAC,KAAa,CAAC,KACf,EAAO,QAAQ,SAAS,WACxB,EAAa,mBAAmB,YAC/B,EAAa,cACd,EAAsB,YAAY,EAAa,OAEnD,EAAsB,UAAU,EAAa,IAE7C,EAAmB,EAAa,WAAW,CAAC,YAAY;AACtD,KAAkB,EAAE,EAAQ,uCAAuC,CAAC;IACpE;IACD;EACD;EACA,GAAc;EACd,GAAc;EACd,GAAc;EACd,EAAO,QAAQ;EACf;EACD,CAAC,EAiBA,kBAAC,GAAD;EAA0C;YAd1C,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;GAAK,eAAY;GAAY,WAAU;aACpC,IACC,kBAAC,GAAD,EACE,sBAAsB,EAAS,kBAAkB,IAAiB,EAClE,CAAA,GAEF,kBAAC,GAAD,EAAoB,CAAA;GAElB,CAAA,EACO,CAKZ;EACwB,CAAA;;AAI/B,SAAgB,IAAmB;AACjC,QAAO,kBAAC,GAAD,EAAc,CAAA"}
@@ -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(`../contexts/active-backend-context.cjs`),i=require(`../utils/custom-toast-handlers.cjs`),a=require(`../utils/mcp-config.cjs`),o=require(`../hooks/query/use-settings.cjs`),s=require(`../components/features/settings/brand-button.cjs`),c=require(`../utils/settings-like-page-layout-classes.cjs`),l=require(`../utils/retrieve-axios-error-message.cjs`),u=require(`../components/features/skills/extensions-navigation.cjs`),d=require(`../components/shared/modals/confirmation-modal.cjs`),f=require(`../hooks/mutation/use-delete-mcp-server.cjs`);require(`../utils/acp-route-guard.cjs`);const p=require(`../utils/mcp-marketplace-utils.cjs`),m=require(`../node_modules/@openhands/extensions/integrations/index.cjs`),h=require(`../utils/mcp-installed-servers.cjs`),g=require(`../components/features/mcp-page/installed-servers-section.cjs`),_=require(`../components/features/mcp-page/marketplace-section.cjs`),v=require(`../components/features/mcp-page/install-server-modal.cjs`),y=require(`../components/features/mcp-page/custom-server-editor.cjs`),b=require(`../components/features/mcp-page/mcp-toolbar.cjs`);require(`../components/features/mcp-page/index.cjs`);let x=require(`react`);x=e.__toESM(x,1);let S=require(`react/jsx-runtime`);function C(){let{t:e}=t.useTranslation(`openhands`),{data:C,isLoading:w}=o.useSettings(),{mutate:T,isPending:E}=f.useDeleteMcpServer(),D=r.useActiveBackend().backend.kind,[O,k]=x.default.useState(null),[A,j]=x.default.useState(null),[M,N]=x.default.useState(null),[P,F]=x.default.useState(``),[I,L]=x.default.useState(`all`),R=h.flattenMcpConfig(a.parseMcpConfig(C?.agent_settings?.mcp_config)),z=R.filter(e=>p.installedServerMatchesQuery(e,p.findCatalogEntryForServer(e,m.default),P)),B=e=>{k(e)};return w||!C?(0,S.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,S.jsx)(u.ExtensionsNavigation,{}),(0,S.jsx)(`div`,{className:`flex h-full flex-1 items-center justify-center px-4 md:px-0`,children:(0,S.jsx)(`div`,{className:`h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin`})})]}):(0,S.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,S.jsx)(u.ExtensionsNavigation,{}),(0,S.jsxs)(`main`,{className:c.settingsLikeMainScrollClassName,children:[(0,S.jsxs)(`div`,{className:`mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6`,children:[(0,S.jsx)(`div`,{className:`min-w-0`,children:(0,S.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,S.jsxs)(`div`,{className:`space-y-1`,children:[(0,S.jsx)(`h2`,{className:`text-xl font-medium leading-6 text-foreground`,children:e(n.I18nKey.SETTINGS$MCP_TITLE)}),(0,S.jsx)(`div`,{className:`max-w-2xl text-sm text-tertiary-light`,children:e(n.I18nKey.MCP$PAGE_DESCRIPTION)})]}),(0,S.jsx)(s.BrandButton,{type:`button`,variant:`secondary`,testId:`mcp-add-custom-server`,className:`flex-shrink-0 whitespace-nowrap`,onClick:()=>j({id:``,type:`sse`}),children:e(n.I18nKey.MCP$ADD_CUSTOM)})]})}),(0,S.jsx)(b.McpToolbar,{search:P,onSearchChange:F,sectionFilter:I,onSectionFilterChange:L}),I===`library`?null:(0,S.jsxs)(`section`,{className:`flex flex-col gap-3`,children:[(0,S.jsx)(`h2`,{className:`text-base font-semibold text-foreground`,children:e(n.I18nKey.MCP$INSTALLED_TITLE)}),(0,S.jsx)(g.InstalledServersSection,{servers:z,hasAnyInstalled:R.length>0,query:P,onEdit:e=>{j(e)},onDelete:e=>{let t=R.find(t=>t.id===e);t&&N(t)}})]}),I===`installed`?null:(0,S.jsx)(_.MarketplaceSection,{backendKind:D,onSelect:B,onAdd:B,query:P})]}),O&&(0,S.jsx)(v.InstallServerModal,{entry:O,onClose:()=>k(null)}),A&&(0,S.jsx)(y.CustomServerEditor,{server:A,existingServers:R,onClose:()=>j(null)}),M&&(0,S.jsx)(d.ConfirmationModal,{text:e(n.I18nKey.SETTINGS$MCP_CONFIRM_DELETE),onCancel:()=>N(null),onConfirm:()=>{M&&T(M,{onSuccess:()=>{i.displaySuccessToast(e(n.I18nKey.MCP$REMOVE_SUCCESS)),N(null)},onError:t=>{i.displayErrorToast(l.retrieveAxiosErrorMessage(t)||e(n.I18nKey.ERROR$GENERIC)),N(null)}})},isConfirming:E})]})]})}exports.default=C;
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(`../contexts/active-backend-context.cjs`),i=require(`../utils/custom-toast-handlers.cjs`),a=require(`../utils/mcp-config.cjs`),o=require(`../hooks/query/use-settings.cjs`),s=require(`../components/features/settings/brand-button.cjs`),c=require(`../utils/settings-like-page-layout-classes.cjs`),l=require(`../utils/retrieve-axios-error-message.cjs`),u=require(`../components/features/skills/extensions-navigation.cjs`),d=require(`../components/shared/modals/confirmation-modal.cjs`),f=require(`../hooks/mutation/use-delete-mcp-server.cjs`);require(`../utils/acp-route-guard.cjs`);const p=require(`../utils/mcp-marketplace-utils.cjs`),m=require(`../node_modules/@openhands/extensions/integrations/index.cjs`),h=require(`../utils/mcp-installed-servers.cjs`),g=require(`../components/features/mcp-page/installed-servers-section.cjs`),_=require(`../components/features/mcp-page/marketplace-section.cjs`),v=require(`../components/features/mcp-page/install-server-modal.cjs`),y=require(`../components/features/mcp-page/custom-server-editor.cjs`),b=require(`../components/features/mcp-page/mcp-toolbar.cjs`);require(`../components/features/mcp-page/index.cjs`);let x=require(`react`);x=e.__toESM(x,1);let S=require(`react/jsx-runtime`);function C(){let{t:e}=t.useTranslation(`openhands`),{data:C,isLoading:w}=o.useSettings(),{mutate:T,isPending:E}=f.useDeleteMcpServer(),D=r.useActiveBackend().backend.kind,[O,k]=x.default.useState(null),[A,j]=x.default.useState(null),[M,N]=x.default.useState(null),[P,F]=x.default.useState(``),[I,L]=x.default.useState(`all`),R=h.flattenMcpConfig(a.parseMcpConfig(C?.agent_settings?.mcp_config)),z=p.getMcpMarketplaceCatalog(m.default),B=R.filter(e=>p.installedServerMatchesQuery(e,p.findCatalogEntryForServer(e,z),P)),V=e=>{k(e)};return w||!C?(0,S.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,S.jsx)(u.ExtensionsNavigation,{}),(0,S.jsx)(`div`,{className:`flex h-full flex-1 items-center justify-center px-4 md:px-0`,children:(0,S.jsx)(`div`,{className:`h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin`})})]}):(0,S.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,S.jsx)(u.ExtensionsNavigation,{}),(0,S.jsxs)(`main`,{className:c.settingsLikeMainScrollClassName,children:[(0,S.jsxs)(`div`,{className:`mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6`,children:[(0,S.jsx)(`div`,{className:`min-w-0`,children:(0,S.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,S.jsxs)(`div`,{className:`space-y-1`,children:[(0,S.jsx)(`h2`,{className:`text-xl font-medium leading-6 text-foreground`,children:e(n.I18nKey.SETTINGS$MCP_TITLE)}),(0,S.jsx)(`div`,{className:`max-w-2xl text-sm text-tertiary-light`,children:e(n.I18nKey.MCP$PAGE_DESCRIPTION)})]}),(0,S.jsx)(s.BrandButton,{type:`button`,variant:`secondary`,testId:`mcp-add-custom-server`,className:`flex-shrink-0 whitespace-nowrap`,onClick:()=>j({id:``,type:`sse`}),children:e(n.I18nKey.MCP$ADD_CUSTOM)})]})}),(0,S.jsx)(b.McpToolbar,{search:P,onSearchChange:F,sectionFilter:I,onSectionFilterChange:L}),I===`library`?null:(0,S.jsxs)(`section`,{className:`flex flex-col gap-3`,children:[(0,S.jsx)(`h2`,{className:`text-base font-semibold text-foreground`,children:e(n.I18nKey.MCP$INSTALLED_TITLE)}),(0,S.jsx)(g.InstalledServersSection,{servers:B,hasAnyInstalled:R.length>0,query:P,onEdit:e=>{j(e)},onDelete:e=>{let t=R.find(t=>t.id===e);t&&N(t)}})]}),I===`installed`?null:(0,S.jsx)(_.MarketplaceSection,{backendKind:D,onSelect:V,onAdd:V,query:P})]}),O&&(0,S.jsx)(v.InstallServerModal,{entry:O,onClose:()=>k(null)}),A&&(0,S.jsx)(y.CustomServerEditor,{server:A,existingServers:R,onClose:()=>j(null)}),M&&(0,S.jsx)(d.ConfirmationModal,{text:e(n.I18nKey.SETTINGS$MCP_CONFIRM_DELETE),onCancel:()=>N(null),onConfirm:()=>{M&&T(M,{onSuccess:()=>{i.displaySuccessToast(e(n.I18nKey.MCP$REMOVE_SUCCESS)),N(null)},onError:t=>{i.displayErrorToast(l.retrieveAxiosErrorMessage(t)||e(n.I18nKey.ERROR$GENERIC)),N(null)}})},isConfirming:E})]})]})}exports.default=C;
2
2
  //# sourceMappingURL=mcp.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.cjs","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport { redirectIfAcpActive } from \"#/utils/acp-route-guard\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as INTEGRATION_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// ACP guard: the ACP sub-agent owns its own MCP server configuration —\n// the SDK explicitly rejects `mcp_config` on ACPAgent init, and\n// `agent-server-adapter` already strips it from start payloads. The\n// Settings → Agent page is where the user configures the ACP server, so\n// bouncing there is consistent with how `/settings` and\n// `/settings/condenser` already behave under ACP.\n//\n// Declared with no parameters (rather than typed as Route.ClientLoaderArgs)\n// so the lib build doesn't pull generated React Router types out of rootDir.\nexport const clientLoader = async () => redirectIfAcpActive();\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, INTEGRATION_MARKETPLACE),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp.cjs","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport { redirectIfAcpActive } from \"#/utils/acp-route-guard\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as MCP_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// ACP guard: the ACP sub-agent owns its own MCP server configuration —\n// the SDK explicitly rejects `mcp_config` on ACPAgent init, and\n// `agent-server-adapter` already strips it from start payloads. The\n// Settings → Agent page is where the user configures the ACP server, so\n// bouncing there is consistent with how `/settings` and\n// `/settings/condenser` already behave under ACP.\n//\n// Declared with no parameters (rather than typed as Route.ClientLoaderArgs)\n// so the lib build doesn't pull generated React Router types out of rootDir.\nexport const clientLoader = async () => redirectIfAcpActive();\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n const mcpMarketplace = getMcpMarketplaceCatalog(MCP_MARKETPLACE);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, mcpMarketplace),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"s3CAiDA,SAAwB,GAAU,CAChC,GAAM,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,CAAE,KAAM,EAAU,aAAc,EAAA,aAAa,CAC7C,CAAE,OAAQ,EAAiB,UAAW,GAC1C,EAAA,oBAAoB,CAEhB,EADgB,EAAA,kBACF,CAAc,QAAQ,KAEpC,CAAC,EAAc,GACnB,EAAA,QAAM,SAAkC,KAAK,CACzC,CAAC,EAAe,GACpB,EAAA,QAAM,SAAiC,KAAK,CACxC,CAAC,EAAgB,GACrB,EAAA,QAAM,SAAiC,KAAK,CACxC,CAAC,EAAa,GAAkB,EAAA,QAAM,SAAS,GAAG,CAClD,CAAC,EAAe,GACpB,EAAA,QAAM,SAA2B,MAAM,CAGnC,EAAa,EAAA,iBADD,EAAA,eAAe,GAAU,gBAAgB,WACvB,CAAU,CACxC,EAAiB,EAAA,yBAAyB,EAAA,QAAgB,CAM1D,EAA2B,EAAW,OAAQ,GAClD,EAAA,4BACE,EACA,EAAA,0BAA0B,EAAQ,EAAe,CACjD,EACD,CACF,CAEK,EAA4B,GAA4B,CAC5D,EAAgB,EAAM,EA6CxB,OAdI,GAAa,CAAC,GAEd,EAAA,EAAA,MAAC,MAAD,CACE,cAAY,WACZ,UAAU,iEAFZ,EAIE,EAAA,EAAA,KAAC,EAAA,qBAAD,EAAwB,CAAA,EACxB,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wEACb,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,sFAAwF,CAAA,CACnG,CAAA,CACF,IAKR,EAAA,EAAA,MAAC,MAAD,CACE,cAAY,WACZ,UAAU,iEAFZ,EAIE,EAAA,EAAA,KAAC,EAAA,qBAAD,EAAwB,CAAA,EACxB,EAAA,EAAA,MAAC,OAAD,CAAM,UAAW,EAAA,yCAAjB,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,oEAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,oBACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,kDAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,qBAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yDACX,EAAE,EAAA,QAAQ,mBAAmB,CAC3B,CAAA,EACL,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,iDACZ,EAAE,EAAA,QAAQ,qBAAqB,CAC5B,CAAA,CACF,IACN,EAAA,EAAA,KAAC,EAAA,YAAD,CACE,KAAK,SACL,QAAQ,YACR,OAAO,wBACP,UAAU,kCACV,YAAe,EAAiB,CAAE,GAAI,GAAI,KAAM,MAAO,CAAC,UAEvD,EAAE,EAAA,QAAQ,eAAe,CACd,CAAA,CACV,GACF,CAAA,EAEN,EAAA,EAAA,KAAC,EAAA,WAAD,CACE,OAAQ,EACR,eAAgB,EACD,gBACf,sBAAuB,EACvB,CAAA,CAED,IAAkB,UAaf,MAZF,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,+BAAnB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,mDACX,EAAE,EAAA,QAAQ,oBAAoB,CAC5B,CAAA,EACL,EAAA,EAAA,KAAC,EAAA,wBAAD,CACE,QAAS,EACT,gBAAiB,EAAW,OAAS,EACrC,MAAO,EACP,OAxFM,GAA4B,CAC9C,EAAiB,EAAO,EAwFZ,SArFa,GAAqB,CAC9C,IAAM,EAAS,EAAW,KAAM,GAAM,EAAE,KAAO,EAAS,CACpD,GAAQ,EAAkB,EAAO,EAoFzB,CAAA,CACM,GAGX,IAAkB,YAOf,MANF,EAAA,EAAA,KAAC,EAAA,mBAAD,CACe,cACb,SAAU,EACV,MAAO,EACP,MAAO,EACP,CAAA,CAEA,GAEL,IACC,EAAA,EAAA,KAAC,EAAA,mBAAD,CACE,MAAO,EACP,YAAe,EAAgB,KAAK,CACpC,CAAA,CAKH,IACC,EAAA,EAAA,KAAC,EAAA,mBAAD,CACE,OAAQ,EACR,gBAAiB,EACjB,YAAe,EAAiB,KAAK,CACrC,CAAA,CAGH,IACC,EAAA,EAAA,KAAC,EAAA,kBAAD,CACE,KAAM,EAAE,EAAA,QAAQ,4BAA4B,CAC5C,aAAgB,EAAkB,KAAK,CACvC,cApHwB,CAC3B,GAKL,EAAgB,EAAgB,CAC9B,cAAiB,CACf,EAAA,oBAAoB,EAAE,EAAA,QAAQ,mBAAmB,CAAC,CAClD,EAAkB,KAAK,EAEzB,QAAU,GAAQ,CAEhB,EAAA,kBADgB,EAAA,0BAA0B,EACxB,EAAW,EAAE,EAAA,QAAQ,cAAc,CAAC,CACtD,EAAkB,KAAK,EAE1B,CAAC,EAqGM,aAAc,EACd,CAAA,CAEC,GACH"}
@@ -11,125 +11,125 @@ import { ExtensionsNavigation as u } from "../components/features/skills/extensi
11
11
  import { ConfirmationModal as d } from "../components/shared/modals/confirmation-modal.js";
12
12
  import { useDeleteMcpServer as f } from "../hooks/mutation/use-delete-mcp-server.js";
13
13
  import "../utils/acp-route-guard.js";
14
- import { findCatalogEntryForServer as p, installedServerMatchesQuery as m } from "../utils/mcp-marketplace-utils.js";
15
- import h from "../node_modules/@openhands/extensions/integrations/index.js";
16
- import { flattenMcpConfig as g } from "../utils/mcp-installed-servers.js";
17
- import { InstalledServersSection as _ } from "../components/features/mcp-page/installed-servers-section.js";
18
- import { MarketplaceSection as v } from "../components/features/mcp-page/marketplace-section.js";
19
- import { InstallServerModal as y } from "../components/features/mcp-page/install-server-modal.js";
20
- import { CustomServerEditor as b } from "../components/features/mcp-page/custom-server-editor.js";
21
- import { McpToolbar as x } from "../components/features/mcp-page/mcp-toolbar.js";
14
+ import { findCatalogEntryForServer as p, getMcpMarketplaceCatalog as m, installedServerMatchesQuery as h } from "../utils/mcp-marketplace-utils.js";
15
+ import g from "../node_modules/@openhands/extensions/integrations/index.js";
16
+ import { flattenMcpConfig as _ } from "../utils/mcp-installed-servers.js";
17
+ import { InstalledServersSection as v } from "../components/features/mcp-page/installed-servers-section.js";
18
+ import { MarketplaceSection as y } from "../components/features/mcp-page/marketplace-section.js";
19
+ import { InstallServerModal as b } from "../components/features/mcp-page/install-server-modal.js";
20
+ import { CustomServerEditor as x } from "../components/features/mcp-page/custom-server-editor.js";
21
+ import { McpToolbar as S } from "../components/features/mcp-page/mcp-toolbar.js";
22
22
  import "../components/features/mcp-page/index.js";
23
- import S from "react";
24
- import { jsx as C, jsxs as w } from "react/jsx-runtime";
23
+ import C from "react";
24
+ import { jsx as w, jsxs as T } from "react/jsx-runtime";
25
25
  //#region src/routes/mcp.tsx
26
- function T() {
27
- let { t: T } = e("openhands"), { data: E, isLoading: D } = o(), { mutate: O, isPending: k } = f(), A = n().backend.kind, [j, M] = S.useState(null), [N, P] = S.useState(null), [F, I] = S.useState(null), [L, R] = S.useState(""), [z, B] = S.useState("all"), V = g(a(E?.agent_settings?.mcp_config)), H = V.filter((e) => m(e, p(e, h), L)), U = (e) => {
28
- M(e);
26
+ function E() {
27
+ let { t: E } = e("openhands"), { data: D, isLoading: O } = o(), { mutate: k, isPending: A } = f(), j = n().backend.kind, [M, N] = C.useState(null), [P, F] = C.useState(null), [I, L] = C.useState(null), [R, z] = C.useState(""), [B, V] = C.useState("all"), H = _(a(D?.agent_settings?.mcp_config)), U = m(g), W = H.filter((e) => h(e, p(e, U), R)), G = (e) => {
28
+ N(e);
29
29
  };
30
- return D || !E ? /* @__PURE__ */ w("div", {
30
+ return O || !D ? /* @__PURE__ */ T("div", {
31
31
  "data-testid": "mcp-page",
32
32
  className: "flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10",
33
- children: [/* @__PURE__ */ C(u, {}), /* @__PURE__ */ C("div", {
33
+ children: [/* @__PURE__ */ w(u, {}), /* @__PURE__ */ w("div", {
34
34
  className: "flex h-full flex-1 items-center justify-center px-4 md:px-0",
35
- children: /* @__PURE__ */ C("div", { className: "h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin" })
35
+ children: /* @__PURE__ */ w("div", { className: "h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin" })
36
36
  })]
37
- }) : /* @__PURE__ */ w("div", {
37
+ }) : /* @__PURE__ */ T("div", {
38
38
  "data-testid": "mcp-page",
39
39
  className: "flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10",
40
- children: [/* @__PURE__ */ C(u, {}), /* @__PURE__ */ w("main", {
40
+ children: [/* @__PURE__ */ w(u, {}), /* @__PURE__ */ T("main", {
41
41
  className: c,
42
42
  children: [
43
- /* @__PURE__ */ w("div", {
43
+ /* @__PURE__ */ T("div", {
44
44
  className: "mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6",
45
45
  children: [
46
- /* @__PURE__ */ C("div", {
46
+ /* @__PURE__ */ w("div", {
47
47
  className: "min-w-0",
48
- children: /* @__PURE__ */ w("div", {
48
+ children: /* @__PURE__ */ T("div", {
49
49
  className: "flex items-start justify-between gap-4",
50
- children: [/* @__PURE__ */ w("div", {
50
+ children: [/* @__PURE__ */ T("div", {
51
51
  className: "space-y-1",
52
- children: [/* @__PURE__ */ C("h2", {
52
+ children: [/* @__PURE__ */ w("h2", {
53
53
  className: "text-xl font-medium leading-6 text-foreground",
54
- children: T(t.SETTINGS$MCP_TITLE)
55
- }), /* @__PURE__ */ C("div", {
54
+ children: E(t.SETTINGS$MCP_TITLE)
55
+ }), /* @__PURE__ */ w("div", {
56
56
  className: "max-w-2xl text-sm text-tertiary-light",
57
- children: T(t.MCP$PAGE_DESCRIPTION)
57
+ children: E(t.MCP$PAGE_DESCRIPTION)
58
58
  })]
59
- }), /* @__PURE__ */ C(s, {
59
+ }), /* @__PURE__ */ w(s, {
60
60
  type: "button",
61
61
  variant: "secondary",
62
62
  testId: "mcp-add-custom-server",
63
63
  className: "flex-shrink-0 whitespace-nowrap",
64
- onClick: () => P({
64
+ onClick: () => F({
65
65
  id: "",
66
66
  type: "sse"
67
67
  }),
68
- children: T(t.MCP$ADD_CUSTOM)
68
+ children: E(t.MCP$ADD_CUSTOM)
69
69
  })]
70
70
  })
71
71
  }),
72
- /* @__PURE__ */ C(x, {
73
- search: L,
74
- onSearchChange: R,
75
- sectionFilter: z,
76
- onSectionFilterChange: B
72
+ /* @__PURE__ */ w(S, {
73
+ search: R,
74
+ onSearchChange: z,
75
+ sectionFilter: B,
76
+ onSectionFilterChange: V
77
77
  }),
78
- z === "library" ? null : /* @__PURE__ */ w("section", {
78
+ B === "library" ? null : /* @__PURE__ */ T("section", {
79
79
  className: "flex flex-col gap-3",
80
- children: [/* @__PURE__ */ C("h2", {
80
+ children: [/* @__PURE__ */ w("h2", {
81
81
  className: "text-base font-semibold text-foreground",
82
- children: T(t.MCP$INSTALLED_TITLE)
83
- }), /* @__PURE__ */ C(_, {
84
- servers: H,
85
- hasAnyInstalled: V.length > 0,
86
- query: L,
82
+ children: E(t.MCP$INSTALLED_TITLE)
83
+ }), /* @__PURE__ */ w(v, {
84
+ servers: W,
85
+ hasAnyInstalled: H.length > 0,
86
+ query: R,
87
87
  onEdit: (e) => {
88
- P(e);
88
+ F(e);
89
89
  },
90
90
  onDelete: (e) => {
91
- let t = V.find((t) => t.id === e);
92
- t && I(t);
91
+ let t = H.find((t) => t.id === e);
92
+ t && L(t);
93
93
  }
94
94
  })]
95
95
  }),
96
- z === "installed" ? null : /* @__PURE__ */ C(v, {
97
- backendKind: A,
98
- onSelect: U,
99
- onAdd: U,
100
- query: L
96
+ B === "installed" ? null : /* @__PURE__ */ w(y, {
97
+ backendKind: j,
98
+ onSelect: G,
99
+ onAdd: G,
100
+ query: R
101
101
  })
102
102
  ]
103
103
  }),
104
- j && /* @__PURE__ */ C(y, {
105
- entry: j,
106
- onClose: () => M(null)
104
+ M && /* @__PURE__ */ w(b, {
105
+ entry: M,
106
+ onClose: () => N(null)
107
107
  }),
108
- N && /* @__PURE__ */ C(b, {
109
- server: N,
110
- existingServers: V,
111
- onClose: () => P(null)
108
+ P && /* @__PURE__ */ w(x, {
109
+ server: P,
110
+ existingServers: H,
111
+ onClose: () => F(null)
112
112
  }),
113
- F && /* @__PURE__ */ C(d, {
114
- text: T(t.SETTINGS$MCP_CONFIRM_DELETE),
115
- onCancel: () => I(null),
113
+ I && /* @__PURE__ */ w(d, {
114
+ text: E(t.SETTINGS$MCP_CONFIRM_DELETE),
115
+ onCancel: () => L(null),
116
116
  onConfirm: () => {
117
- F && O(F, {
117
+ I && k(I, {
118
118
  onSuccess: () => {
119
- i(T(t.MCP$REMOVE_SUCCESS)), I(null);
119
+ i(E(t.MCP$REMOVE_SUCCESS)), L(null);
120
120
  },
121
121
  onError: (e) => {
122
- r(l(e) || T(t.ERROR$GENERIC)), I(null);
122
+ r(l(e) || E(t.ERROR$GENERIC)), L(null);
123
123
  }
124
124
  });
125
125
  },
126
- isConfirming: k
126
+ isConfirming: A
127
127
  })
128
128
  ]
129
129
  })]
130
130
  });
131
131
  }
132
132
  //#endregion
133
- export { T as default };
133
+ export { E as default };
134
134
 
135
135
  //# sourceMappingURL=mcp.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport { redirectIfAcpActive } from \"#/utils/acp-route-guard\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as INTEGRATION_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// ACP guard: the ACP sub-agent owns its own MCP server configuration —\n// the SDK explicitly rejects `mcp_config` on ACPAgent init, and\n// `agent-server-adapter` already strips it from start payloads. The\n// Settings → Agent page is where the user configures the ACP server, so\n// bouncing there is consistent with how `/settings` and\n// `/settings/condenser` already behave under ACP.\n//\n// Declared with no parameters (rather than typed as Route.ClientLoaderArgs)\n// so the lib build doesn't pull generated React Router types out of rootDir.\nexport const clientLoader = async () => redirectIfAcpActive();\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, INTEGRATION_MARKETPLACE),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp.js","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport { redirectIfAcpActive } from \"#/utils/acp-route-guard\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as MCP_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// ACP guard: the ACP sub-agent owns its own MCP server configuration —\n// the SDK explicitly rejects `mcp_config` on ACPAgent init, and\n// `agent-server-adapter` already strips it from start payloads. The\n// Settings → Agent page is where the user configures the ACP server, so\n// bouncing there is consistent with how `/settings` and\n// `/settings/condenser` already behave under ACP.\n//\n// Declared with no parameters (rather than typed as Route.ClientLoaderArgs)\n// so the lib build doesn't pull generated React Router types out of rootDir.\nexport const clientLoader = async () => redirectIfAcpActive();\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n const mcpMarketplace = getMcpMarketplaceCatalog(MCP_MARKETPLACE);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, mcpMarketplace),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../node_modules/zustand/esm/react.cjs`);var t={url:`https://github.com/OpenHands/OpenHands`,screenshotSrc:``},n=e.create(e=>({...t,setUrl:t=>e({url:t}),setScreenshotSrc:t=>e({screenshotSrc:t}),reset:()=>e(t)}));exports.useBrowserStore=n;
1
+ require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../node_modules/zustand/esm/react.cjs`);var t={url:``,screenshotSrc:``},n=e.create(e=>({...t,setUrl:t=>e({url:t}),setScreenshotSrc:t=>e({screenshotSrc:t}),reset:()=>e(t)}));exports.useBrowserStore=n;
2
2
  //# sourceMappingURL=browser-store.cjs.map