@openhands/agent-canvas 1.0.0-alpha.7 → 1.0.0-alpha.8

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 (691) hide show
  1. package/README.md +9 -18
  2. package/bin/agent-canvas.mjs +27 -1
  3. package/build/assets/{QueryClientProvider-DITRCGAK.js → QueryClientProvider-B7kl84Kj.js} +1 -1
  4. package/build/assets/{Trans-D43bd3yR.js → Trans-1j65oy9O.js} +1 -1
  5. package/build/assets/{acp-providers-SCPK1BIU.js → acp-providers-DauuOsW9.js} +1 -1
  6. package/build/assets/{acp-route-guard-IWlFmS6x.js → acp-route-guard-CQTmeJwM.js} +1 -1
  7. package/build/assets/{active-backend-context-CkP3ZEJs.js → active-backend-context-TVbjnvmP.js} +1 -1
  8. package/build/assets/add-backend-modal-KMmPQNZU.js +1 -0
  9. package/build/assets/{agent-server-client-options-8OJSXbm8.js → agent-server-client-options-DT2GP6VJ.js} +1 -1
  10. package/build/assets/{agent-server-compatibility-DvKtnXHw.js → agent-server-compatibility-2aOx5iWd.js} +1 -1
  11. package/build/assets/{agent-server-conversation-service.api-BdEre_71.js → agent-server-conversation-service.api-DSl9G5UR.js} +3 -3
  12. package/build/assets/{agent-settings-DdisD2Xx.js → agent-settings-B247S9G3.js} +2 -2
  13. package/build/assets/{alert-banner-CvTYN73l.js → alert-banner-BWoqueRw.js} +1 -1
  14. package/build/assets/{analytics-consent-form-modal-BKgT9i2w.js → analytics-consent-form-modal-C7sXfxRh.js} +1 -1
  15. package/build/assets/{app-settings-DcYXtxGP.js → app-settings-BVeSaty9.js} +1 -1
  16. package/build/assets/{automation-detail-D7GEU0vR.js → automation-detail-g5-RZ0da.js} +1 -1
  17. package/build/assets/{automations-list-CkVNsgzm.js → automations-list-DHoq_0MM.js} +1 -1
  18. package/build/assets/{backend-form-modal-KudhWUX8.js → backend-form-modal-K6IMCr3p.js} +1 -1
  19. package/build/assets/{backend-synced-settings-badge-BFy2HylT.js → backend-synced-settings-badge-nAfiUWvM.js} +1 -1
  20. package/build/assets/{base-modal-B4HvlFHE.js → base-modal-CQRvRHu1.js} +1 -1
  21. package/build/assets/{brand-button-8fVVei4i.js → brand-button-C2nEKopC.js} +1 -1
  22. package/build/assets/{browser-vYpdU3CR.js → browser-DKG63inJ.js} +1 -1
  23. package/build/assets/{browser-tab-DTM6RyoV.js → browser-tab-B_BuTvrO.js} +1 -1
  24. package/build/assets/{checkmark-BcvXE9bf.js → checkmark-BJJrZUF8.js} +1 -1
  25. package/build/assets/{chevron-left-small-BqSkXTeq.js → chevron-left-small-CSh-sE9L.js} +1 -1
  26. package/build/assets/{circle-plus-check-toggle-DRvuu-RD.js → circle-plus-check-toggle-qs8Va1cC.js} +1 -1
  27. package/build/assets/{clock-DfoVUZVq.js → clock-ZR4Kn-_Y.js} +1 -1
  28. package/build/assets/{close-SnIy2eLD.js → close-BdmyeRqS.js} +1 -1
  29. package/build/assets/{combobox-caret-BMsz5mQX.js → combobox-caret-B53O9Hsq.js} +1 -1
  30. package/build/assets/{condenser-settings-DduLQcpV.js → condenser-settings-A35V3yng.js} +1 -1
  31. package/build/assets/{confirmation-modal-B-DOYMUH.js → confirmation-modal-C9-La0h3.js} +1 -1
  32. package/build/assets/{context-menu-list-item-DzjPB8aC.js → context-menu-list-item-Buu9nc0q.js} +1 -1
  33. package/build/assets/conversation-BD5WemJI.js +19 -0
  34. package/build/assets/conversation-C47K62n8.js +1 -0
  35. package/build/assets/conversation-panel-Dn-S56Gk.js +1 -0
  36. package/build/assets/{conversation-service.api-YTGTw0pz.js → conversation-service.api-C8pYCyV6.js} +1 -1
  37. package/build/assets/{conversation-tab-empty-state-BtFDbyTe.js → conversation-tab-empty-state-D8dNvo-V.js} +1 -1
  38. package/build/assets/{conversation-websocket-context-DulnrIHh.js → conversation-websocket-context-Ywrxd_9p.js} +1 -1
  39. package/build/assets/{copy-BxgbrjDT.js → copy-C7Ti2d8C.js} +1 -1
  40. package/build/assets/{custom-toast-handlers-BYxhSr3t.js → custom-toast-handlers-BOc3qeQ7.js} +1 -1
  41. package/build/assets/declaration-D378OjpZ.js +1 -0
  42. package/build/assets/{device-verify-CTbXX9CQ.js → device-verify-CMusn8nX.js} +1 -1
  43. package/build/assets/edit-automation-modal-Dnjxbjn7.js +1 -0
  44. package/build/assets/{ellipsis-button-BoU2-xlG.js → ellipsis-button-ugUATsNo.js} +1 -1
  45. package/build/assets/{entry.client-DU7-q4ZU.js → entry.client-D9uR9Blz.js} +2 -2
  46. package/build/assets/{enum-filter-dropdown-BJt-NplD.js → enum-filter-dropdown-1vpOGySB.js} +1 -1
  47. package/build/assets/{environment-switch-overlay-DQ1n6Iu6.js → environment-switch-overlay-CTCTQikP.js} +1 -1
  48. package/build/assets/{extensions-hub-BW1FAKFJ.js → extensions-hub-BSUseHVF.js} +1 -1
  49. package/build/assets/{extensions-navigation-CbPMhSML.js → extensions-navigation-CT1kc1u_.js} +1 -1
  50. package/build/assets/{files-tab-CbJ4s7Ik.js → files-tab-B3A1NDlZ.js} +1 -1
  51. package/build/assets/{folder-CerIk8uG.js → folder-0WSMImNX.js} +1 -1
  52. package/build/assets/git-control-bar-branch-button-CcIpmyfM.js +27 -0
  53. package/build/assets/{git-provider-icon-D8RE4unY.js → git-provider-icon-DYE9n7fs.js} +1 -1
  54. package/build/assets/{home-DR11ejqB.js → home-dIzxi5Dd.js} +1 -1
  55. package/build/assets/{i18n-DkYgs32x.js → i18n-DjAGhTis.js} +1 -1
  56. package/build/assets/install-server-modal-z5VaHeXd.js +1 -0
  57. package/build/assets/{launch-DKCU9uJH.js → launch-hZ0ifhcV.js} +1 -1
  58. package/build/assets/{lesson-plan-CmkRbe6Z.js → lesson-plan-DRYG5SLI.js} +1 -1
  59. package/build/assets/{link-external-CvxB0BmI.js → link-external-Df8J52xI.js} +1 -1
  60. package/build/assets/{llm-client-BpIfxETv.js → llm-client-ChQzg4wX.js} +1 -1
  61. package/build/assets/llm-settings-2036m7Wt.js +1 -0
  62. package/build/assets/{llm-settings-BOJC4vD-.js → llm-settings-CcHqGOYL.js} +1 -1
  63. package/build/assets/{loading-spinner-91b5FiMQ.js → loading-spinner-C04FGh14.js} +1 -1
  64. package/build/assets/{manage-backends-modal-DqpzcxdI.js → manage-backends-modal-rYeyGx7j.js} +1 -1
  65. package/build/assets/{manage-workspaces-modal-eG6XgAvw.js → manage-workspaces-modal-C5EuW8m1.js} +1 -1
  66. package/build/assets/manifest-97e839da.js +1 -0
  67. package/build/assets/{markdown-renderer-wZnLDbA1.js → markdown-renderer-CEX4Becj.js} +1 -1
  68. package/build/assets/mcp-C06YssEI.js +9 -0
  69. package/build/assets/messages-T2ewVkbp.js +36 -0
  70. package/build/assets/{modal-backdrop-B04pVYAD.js → modal-backdrop-DTYGVmOR.js} +1 -1
  71. package/build/assets/{modal-body-CgUoFQA1.js → modal-body-YElmM1dV.js} +1 -1
  72. package/build/assets/{modal-close-button-SM_WXzDY.js → modal-close-button-C_GpQt9F.js} +1 -1
  73. package/build/assets/{model-selector-7id-Uirf.js → model-selector-DeMmw-Xa.js} +1 -1
  74. package/build/assets/{navigation-context-BFjstyH6.js → navigation-context-DeIPtGPp.js} +1 -1
  75. package/build/assets/{navigation-link-DFQ7YcWq.js → navigation-link-C9JD4PYD.js} +1 -1
  76. package/build/assets/{openhands-logo-DkDp75rC.js → openhands-logo-CI5Fhn1W.js} +1 -1
  77. package/build/assets/{option-service.api-DN0ZcGjw.js → option-service.api-DsI1UW7N.js} +1 -1
  78. package/build/assets/{organization-service.api-Ct2dZF8M.js → organization-service.api-COwMPFg5.js} +1 -1
  79. package/build/assets/{path-utils-D1ZtqFC7.js → path-utils-CqJboYxo.js} +1 -1
  80. package/build/assets/{plan-components-gOm-daR3.js → plan-components-DEjMuDDG.js} +1 -1
  81. package/build/assets/{planner-tab-yubfN-6U.js → planner-tab-BrntFmb1.js} +1 -1
  82. package/build/assets/{profiles-client-D4twHRVf.js → profiles-client-BGkKEV9j.js} +1 -1
  83. package/build/assets/{providers-C2T07PM3.js → providers-DXvCAN_u.js} +1 -1
  84. package/build/assets/{proxy-BMZyC45G.js → proxy-CurRmrqf.js} +1 -1
  85. package/build/assets/{query-client-config-CiK0GJJO.js → query-client-config-Ba7qAAoO.js} +1 -1
  86. package/build/assets/recommended-automations-launcher-BI9NhG8Y.js +52 -0
  87. package/build/assets/root-BS1Td78t.js +2 -0
  88. package/build/assets/root-DHeCXo9N.css +1 -0
  89. package/build/assets/{root-layout-B4QioBS6.js → root-layout-BLjAEgle.js} +2 -2
  90. package/build/assets/{sdk-section-page-03k88tIR.js → sdk-section-page-CJW0G04-.js} +1 -1
  91. package/build/assets/{sdk-settings-schema-BY8dOy3a.js → sdk-settings-schema-QBYH-ONX.js} +1 -1
  92. package/build/assets/{search-BCAF9EDS.js → search-Cq_cFrDt.js} +1 -1
  93. package/build/assets/{secrets-service-Z3qtRb_G.js → secrets-service-Bwd5DeUs.js} +1 -1
  94. package/build/assets/{secrets-settings-BnlByuMZ.js → secrets-settings-MLXqOtX2.js} +1 -1
  95. package/build/assets/{server-client-CG1zHqph.js → server-client-C3mC8Hl3.js} +1 -1
  96. package/build/assets/{settings-DyzGLF_d.js → settings-D7E2U5tK.js} +1 -1
  97. package/build/assets/{settings-client-CkXDJwIY.js → settings-client-CwjfwoiB.js} +1 -1
  98. package/build/assets/{settings-dropdown-input-CAQWQgx-.js → settings-dropdown-input-VwAXNrOb.js} +1 -1
  99. package/build/assets/{settings-gear-D4ZkEDGb.js → settings-gear-BJwWR1ej.js} +1 -1
  100. package/build/assets/{settings-index-KtTw49xL.js → settings-index-J-3BNR0W.js} +1 -1
  101. package/build/assets/{settings-input-BWCZt9g2.js → settings-input-DBywAnA7.js} +1 -1
  102. package/build/assets/{settings-list-classes-xMleGkTC.js → settings-list-classes-BOS092DR.js} +1 -1
  103. package/build/assets/{settings-modal-Cv2YWSUY.js → settings-modal-B8vgWDTe.js} +1 -1
  104. package/build/assets/{settings-section-header-context-1wfkgjZZ.js → settings-section-header-context-32x6WTyL.js} +1 -1
  105. package/build/assets/settings-service.api-FvJGK45W.js +1 -0
  106. package/build/assets/{settings-switch-CGap2LtG.js → settings-switch-DTKmHC8F.js} +1 -1
  107. package/build/assets/{settings-utils-BBozxqqi.js → settings-utils-BsvSU3OM.js} +1 -1
  108. package/build/assets/{shared-conversation-DQlzwdpo.js → shared-conversation-a0QV8o99.js} +1 -1
  109. package/build/assets/{sidebar-mobile-menu-toggle-DXplko7u.js → sidebar-mobile-menu-toggle-DTUNI1WQ.js} +1 -1
  110. package/build/assets/{sidebar-nav-link-B4h8naZ7.js → sidebar-nav-link-CnWoZcwc.js} +1 -1
  111. package/build/assets/{skill-card-pill-row-D0oTWx-a.js → skill-card-pill-row-tZ599jli.js} +1 -1
  112. package/build/assets/{skills-BN8atjgW.js → skills-ZyAO5dyK.js} +1 -1
  113. package/build/assets/{skills-plugins-BTnp7QcQ.js → skills-plugins-BSRz041I.js} +1 -1
  114. package/build/assets/{skills-settings-CbOQvzkR.js → skills-settings-DOnMn9q1.js} +2 -2
  115. package/build/assets/{status-DDL-ipIP.js → status-CsatcFbK.js} +1 -1
  116. package/build/assets/{styled-tooltip-Awq4HMw3.js → styled-tooltip-CS3mB_1X.js} +1 -1
  117. package/build/assets/{switch-skeleton-Bv21RGWd.js → switch-skeleton-C-CfhYYV.js} +1 -1
  118. package/build/assets/{task-list-tab-B45ktzHM.js → task-list-tab-Day9nhRT.js} +1 -1
  119. package/build/assets/{terminal-DGuR4559.js → terminal-LNa-iU5c.js} +1 -1
  120. package/build/assets/{terminal-D5pzR9Ru.js → terminal-ro4SNjUU.js} +1 -1
  121. package/build/assets/{toggle-switch-gj6T-wsU.js → toggle-switch-k-IZCDbt.js} +1 -1
  122. package/build/assets/{typography-BbaUAC4V.js → typography-vVUMoNUg.js} +1 -1
  123. package/build/assets/{u-check-circle-DHGiAi-w.js → u-check-circle-DplbarS5.js} +1 -1
  124. package/build/assets/{u-check-circle-half-BPcWtWwv.js → u-check-circle-half-yDuiSZHC.js} +1 -1
  125. package/build/assets/{u-circuit-B_nK9hOu.js → u-circuit-C9tYkpeK.js} +1 -1
  126. package/build/assets/{u-edit-BPFJBd34.js → u-edit-KAUlufD8.js} +1 -1
  127. package/build/assets/{use-active-conversation-Bu5J9iLy.js → use-active-conversation-D15D9GgR.js} +1 -1
  128. package/build/assets/{use-agent-settings-schema-BbtOsR7P.js → use-agent-settings-schema-Bvp5UzV8.js} +1 -1
  129. package/build/assets/{use-agent-state-DN9Nc5pP.js → use-agent-state-DE5dlEXJ.js} +1 -1
  130. package/build/assets/{use-cloud-current-user-id-B_rMUiu8.js → use-cloud-current-user-id-DWVar4st.js} +1 -1
  131. package/build/assets/{use-config-Bcz2JL2t.js → use-config-BSu_53GL.js} +1 -1
  132. package/build/assets/{use-conversation-id-BOaaZahn.js → use-conversation-id-DajhCn2A.js} +1 -1
  133. package/build/assets/{use-create-conversation-BWFA_FId.js → use-create-conversation-DW7AGgLA.js} +1 -1
  134. package/build/assets/{use-handle-plan-click-CgrCGmT1.js → use-handle-plan-click-DpgEQDAV.js} +1 -1
  135. package/build/assets/use-is-authed-hXC8vxgT.js +1 -0
  136. package/build/assets/{use-is-creating-conversation-DhoM7UAB.js → use-is-creating-conversation-DhDeeWfA.js} +1 -1
  137. package/build/assets/{use-launch-skill-in-chat-DOyQsXFO.js → use-launch-skill-in-chat-DVGPFrbI.js} +1 -1
  138. package/build/assets/{use-llm-profiles-CAIzHJDX.js → use-llm-profiles-D3-KXwQ0.js} +1 -1
  139. package/build/assets/use-runtime-is-ready-XFbT16BD.js +1 -0
  140. package/build/assets/{use-save-settings-5m3w89Ph.js → use-save-settings-CEEKSTWG.js} +1 -1
  141. package/build/assets/{use-settings-DzG0C3vO.js → use-settings-DQ7Oo1Hj.js} +1 -1
  142. package/build/assets/{use-settings-nav-items-BIsKeX52.js → use-settings-nav-items-YmrXrjn9.js} +2 -2
  143. package/build/assets/{use-skills-Cn-78xP1.js → use-skills-Xe0vjPMt.js} +1 -1
  144. package/build/assets/{use-unified-vscode-url-C5iI-Z5A.js → use-unified-vscode-url-BOsIOd-b.js} +1 -1
  145. package/build/assets/use-user-conversation-Mc0mQgkl.js +1 -0
  146. package/build/assets/{useMutation-CRJwk4cR.js → useMutation-B4OUESdw.js} +1 -1
  147. package/build/assets/{useTranslation-01pF7z10.js → useTranslation-CpIcQBq6.js} +1 -1
  148. package/build/assets/{utils-Czcl6buL.js → utils-D-HX7JCe.js} +1 -1
  149. package/build/assets/{vendor~conversation-panel~conversation-CbjvWBSu.js → vendor~conversation-panel~conversation-BlCIz9XQ.js} +1 -1
  150. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CofhIDpd.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Ds9quNZ9.js} +1 -1
  151. package/build/assets/vendor~home~mcp~automations-list-C5PoHCy6.js +1 -0
  152. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-BQPOygpY.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CGlZoBKa.js} +1 -1
  153. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CyYIBiBk.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-DE11mPxp.js} +1 -1
  154. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-CuGq_cxH.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-8b8V5bfO.js} +1 -1
  155. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-CFpDeb9o.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-Dy7L6fMG.js} +1 -1
  156. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-C1p8-pMr.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-D40EXhZx.js} +1 -1
  157. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-CHrEOFl6.js +48 -0
  158. package/build/assets/{vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-DlKA6SoO.js → vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-CyUbhpbm.js} +1 -1
  159. package/build/assets/{verification-settings-DbziMp4K.js → verification-settings-BtlTiHP8.js} +1 -1
  160. package/build/assets/{vscode-tab-BVhQR2rt.js → vscode-tab-C0ShhiSU.js} +1 -1
  161. package/build/assets/{waiting-for-runtime-message-JotSOBdC.js → waiting-for-runtime-message-DWPl_Yby.js} +1 -1
  162. package/build/assets/{x-mark-CZ57VvRX.js → x-mark-CWI0f9yI.js} +1 -1
  163. package/build/favicon.svg +1 -0
  164. package/build/index.html +4 -4
  165. package/build/locales/ar/openhands.json +8 -0
  166. package/build/locales/ca/openhands.json +8 -0
  167. package/build/locales/de/openhands.json +8 -0
  168. package/build/locales/en/openhands.json +8 -0
  169. package/build/locales/es/openhands.json +8 -0
  170. package/build/locales/fr/openhands.json +8 -0
  171. package/build/locales/it/openhands.json +8 -0
  172. package/build/locales/ja/openhands.json +8 -0
  173. package/build/locales/ko-KR/openhands.json +8 -0
  174. package/build/locales/no/openhands.json +8 -0
  175. package/build/locales/pt/openhands.json +8 -0
  176. package/build/locales/tr/openhands.json +8 -0
  177. package/build/locales/uk/openhands.json +8 -0
  178. package/build/locales/zh-CN/openhands.json +8 -0
  179. package/build/locales/zh-TW/openhands.json +8 -0
  180. package/config/defaults.json +1 -1
  181. package/dist/api/agent-server-config.cjs +1 -1
  182. package/dist/api/agent-server-config.cjs.map +1 -1
  183. package/dist/api/agent-server-config.d.ts +1 -1
  184. package/dist/api/agent-server-config.js +1 -1
  185. package/dist/api/agent-server-config.js.map +1 -1
  186. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  187. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  188. package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +12 -0
  189. package/dist/api/conversation-service/agent-server-conversation-service.api.js +4 -0
  190. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  191. package/dist/api/mcp-service/mcp-service.api.cjs +2 -0
  192. package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -0
  193. package/dist/api/mcp-service/mcp-service.api.d.ts +6 -0
  194. package/dist/api/mcp-service/mcp-service.api.js +36 -0
  195. package/dist/api/mcp-service/mcp-service.api.js.map +1 -0
  196. package/dist/api/settings-service/settings-service.api.cjs +1 -1
  197. package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
  198. package/dist/api/settings-service/settings-service.api.d.ts +1 -0
  199. package/dist/api/settings-service/settings-service.api.js +59 -41
  200. package/dist/api/settings-service/settings-service.api.js.map +1 -1
  201. package/dist/components/features/automations/detail/activity-log-item.d.ts +1 -1
  202. package/dist/components/features/automations/recommended-automations-launcher.d.ts +1 -1
  203. package/dist/components/features/chat/change-agent-button.cjs +1 -1
  204. package/dist/components/features/chat/change-agent-button.cjs.map +1 -1
  205. package/dist/components/features/chat/change-agent-button.js +65 -59
  206. package/dist/components/features/chat/change-agent-button.js.map +1 -1
  207. package/dist/components/features/chat/chat-interface.cjs +2 -2
  208. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  209. package/dist/components/features/chat/chat-interface.js +15 -14
  210. package/dist/components/features/chat/chat-interface.js.map +1 -1
  211. package/dist/components/features/chat/components/chat-input-actions.cjs +1 -1
  212. package/dist/components/features/chat/components/chat-input-actions.cjs.map +1 -1
  213. package/dist/components/features/chat/components/chat-input-actions.js +127 -149
  214. package/dist/components/features/chat/components/chat-input-actions.js.map +1 -1
  215. package/dist/components/features/chat/components/chat-input-model.cjs +1 -1
  216. package/dist/components/features/chat/components/chat-input-model.cjs.map +1 -1
  217. package/dist/components/features/chat/components/chat-input-model.d.ts +10 -0
  218. package/dist/components/features/chat/components/chat-input-model.js +95 -60
  219. package/dist/components/features/chat/components/chat-input-model.js.map +1 -1
  220. package/dist/components/features/chat/git-control-bar.cjs +1 -1
  221. package/dist/components/features/chat/git-control-bar.cjs.map +1 -1
  222. package/dist/components/features/chat/git-control-bar.js +60 -59
  223. package/dist/components/features/chat/git-control-bar.js.map +1 -1
  224. package/dist/components/features/conversation/conversation-name-with-status.cjs +1 -1
  225. package/dist/components/features/conversation/conversation-name-with-status.cjs.map +1 -1
  226. package/dist/components/features/conversation/conversation-name-with-status.js +2 -2
  227. package/dist/components/features/conversation/conversation-name-with-status.js.map +1 -1
  228. package/dist/components/features/conversation/conversation-name.cjs +1 -1
  229. package/dist/components/features/conversation/conversation-name.cjs.map +1 -1
  230. package/dist/components/features/conversation/conversation-name.js +3 -3
  231. package/dist/components/features/conversation/conversation-name.js.map +1 -1
  232. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs +1 -1
  233. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs.map +1 -1
  234. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js +1 -1
  235. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js.map +1 -1
  236. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs +1 -1
  237. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs.map +1 -1
  238. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js +16 -16
  239. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js.map +1 -1
  240. package/dist/components/features/mcp-logo-badge.cjs +1 -1
  241. package/dist/components/features/mcp-logo-badge.cjs.map +1 -1
  242. package/dist/components/features/mcp-logo-badge.d.ts +2 -2
  243. package/dist/components/features/mcp-logo-badge.js +1 -1
  244. package/dist/components/features/mcp-logo-badge.js.map +1 -1
  245. package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
  246. package/dist/components/features/mcp-page/custom-server-editor.cjs.map +1 -1
  247. package/dist/components/features/mcp-page/custom-server-editor.js +64 -41
  248. package/dist/components/features/mcp-page/custom-server-editor.js.map +1 -1
  249. package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
  250. package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
  251. package/dist/components/features/mcp-page/install-server-modal.d.ts +1 -1
  252. package/dist/components/features/mcp-page/install-server-modal.js +126 -102
  253. package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
  254. package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
  255. package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
  256. package/dist/components/features/mcp-page/installed-server-card.js +1 -1
  257. package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
  258. package/dist/components/features/mcp-page/marketplace-card.cjs +1 -1
  259. package/dist/components/features/mcp-page/marketplace-card.cjs.map +1 -1
  260. package/dist/components/features/mcp-page/marketplace-card.d.ts +1 -1
  261. package/dist/components/features/mcp-page/marketplace-card.js +27 -25
  262. package/dist/components/features/mcp-page/marketplace-card.js.map +1 -1
  263. package/dist/components/features/mcp-page/marketplace-section.cjs +1 -1
  264. package/dist/components/features/mcp-page/marketplace-section.cjs.map +1 -1
  265. package/dist/components/features/mcp-page/marketplace-section.d.ts +1 -1
  266. package/dist/components/features/mcp-page/marketplace-section.js +1 -1
  267. package/dist/components/features/mcp-page/marketplace-section.js.map +1 -1
  268. package/dist/components/features/mcp-page/mcp-logo-stack-badge.d.ts +2 -2
  269. package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs +7 -7
  270. package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs.map +1 -1
  271. package/dist/components/features/settings/mcp-settings/mcp-server-form.d.ts +8 -12
  272. package/dist/components/features/settings/mcp-settings/mcp-server-form.js +114 -87
  273. package/dist/components/features/settings/mcp-settings/mcp-server-form.js.map +1 -1
  274. package/dist/context/scroll-context.cjs +1 -1
  275. package/dist/context/scroll-context.cjs.map +1 -1
  276. package/dist/context/scroll-context.d.ts +1 -0
  277. package/dist/context/scroll-context.js +4 -1
  278. package/dist/context/scroll-context.js.map +1 -1
  279. package/dist/favicon.svg +1 -0
  280. package/dist/hooks/mutation/use-switch-acp-model.cjs +2 -0
  281. package/dist/hooks/mutation/use-switch-acp-model.cjs.map +1 -0
  282. package/dist/hooks/mutation/use-switch-acp-model.d.ts +23 -0
  283. package/dist/hooks/mutation/use-switch-acp-model.js +26 -0
  284. package/dist/hooks/mutation/use-switch-acp-model.js.map +1 -0
  285. package/dist/hooks/mutation/use-test-mcp-server.cjs +2 -0
  286. package/dist/hooks/mutation/use-test-mcp-server.cjs.map +1 -0
  287. package/dist/hooks/mutation/use-test-mcp-server.d.ts +2 -0
  288. package/dist/hooks/mutation/use-test-mcp-server.js +10 -0
  289. package/dist/hooks/mutation/use-test-mcp-server.js.map +1 -0
  290. package/dist/hooks/query/use-automation-detail.d.ts +3 -2
  291. package/dist/hooks/use-acp-model-context.cjs.map +1 -1
  292. package/dist/hooks/use-acp-model-context.d.ts +3 -4
  293. package/dist/hooks/use-acp-model-context.js.map +1 -1
  294. package/dist/hooks/use-chat-input-model-state.cjs +2 -0
  295. package/dist/hooks/use-chat-input-model-state.cjs.map +1 -0
  296. package/dist/hooks/use-chat-input-model-state.d.ts +12 -0
  297. package/dist/hooks/use-chat-input-model-state.js +29 -0
  298. package/dist/hooks/use-chat-input-model-state.js.map +1 -0
  299. package/dist/i18n/declaration.cjs +1 -1
  300. package/dist/i18n/declaration.cjs.map +1 -1
  301. package/dist/i18n/declaration.d.ts +8 -0
  302. package/dist/i18n/declaration.js +1 -1
  303. package/dist/i18n/declaration.js.map +1 -1
  304. package/dist/i18n/translation.cjs +2 -2
  305. package/dist/i18n/translation.cjs.map +1 -1
  306. package/dist/i18n/translation.js +136 -0
  307. package/dist/i18n/translation.js.map +1 -1
  308. package/dist/locales/ar/openhands.json +8 -0
  309. package/dist/locales/ca/openhands.json +8 -0
  310. package/dist/locales/de/openhands.json +8 -0
  311. package/dist/locales/en/openhands.json +8 -0
  312. package/dist/locales/es/openhands.json +8 -0
  313. package/dist/locales/fr/openhands.json +8 -0
  314. package/dist/locales/it/openhands.json +8 -0
  315. package/dist/locales/ja/openhands.json +8 -0
  316. package/dist/locales/ko-KR/openhands.json +8 -0
  317. package/dist/locales/no/openhands.json +8 -0
  318. package/dist/locales/pt/openhands.json +8 -0
  319. package/dist/locales/tr/openhands.json +8 -0
  320. package/dist/locales/uk/openhands.json +8 -0
  321. package/dist/locales/zh-CN/openhands.json +8 -0
  322. package/dist/locales/zh-TW/openhands.json +8 -0
  323. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.cjs +2 -0
  324. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.cjs.map +1 -0
  325. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.js +37 -0
  326. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.js.map +1 -0
  327. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.cjs +2 -0
  328. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.cjs.map +1 -0
  329. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.js +36 -0
  330. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.js.map +1 -0
  331. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/atlassian.cjs +1 -1
  332. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs.map +1 -0
  333. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/atlassian.js +15 -5
  334. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js.map +1 -0
  335. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.cjs +2 -0
  336. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.cjs.map +1 -0
  337. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.js +36 -0
  338. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.js.map +1 -0
  339. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.cjs +2 -0
  340. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.cjs.map +1 -0
  341. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.js +31 -0
  342. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.js.map +1 -0
  343. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.cjs +2 -0
  344. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.cjs.map +1 -0
  345. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.js +52 -0
  346. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.js.map +1 -0
  347. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-bindings.cjs +1 -1
  348. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-bindings.cjs.map +1 -0
  349. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-bindings.js +15 -5
  350. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-bindings.js.map +1 -0
  351. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.cjs +2 -0
  352. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.cjs.map +1 -0
  353. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-browser-rendering.js +15 -5
  354. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.js.map +1 -0
  355. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-builds.cjs +1 -1
  356. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-builds.cjs.map +1 -0
  357. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-builds.js +15 -5
  358. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-builds.js.map +1 -0
  359. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-docs.cjs +1 -1
  360. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-docs.cjs.map +1 -0
  361. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-docs.js +15 -5
  362. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-docs.js.map +1 -0
  363. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.cjs +2 -0
  364. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.cjs.map +1 -0
  365. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-observability.js +15 -5
  366. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.js.map +1 -0
  367. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/deepwiki.cjs +1 -1
  368. package/dist/node_modules/@openhands/extensions/integrations/catalog/deepwiki.cjs.map +1 -0
  369. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/deepwiki.js +15 -5
  370. package/dist/node_modules/@openhands/extensions/integrations/catalog/deepwiki.js.map +1 -0
  371. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.cjs +2 -0
  372. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.cjs.map +1 -0
  373. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.js +36 -0
  374. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.js.map +1 -0
  375. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/everything.cjs +1 -1
  376. package/dist/node_modules/@openhands/extensions/integrations/catalog/everything.cjs.map +1 -0
  377. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/everything.js +13 -6
  378. package/dist/node_modules/@openhands/extensions/integrations/catalog/everything.js.map +1 -0
  379. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.cjs +2 -0
  380. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.cjs.map +1 -0
  381. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.js +36 -0
  382. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.js.map +1 -0
  383. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/fetch.cjs +1 -1
  384. package/dist/node_modules/@openhands/extensions/integrations/catalog/fetch.cjs.map +1 -0
  385. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/fetch.js +13 -6
  386. package/dist/node_modules/@openhands/extensions/integrations/catalog/fetch.js.map +1 -0
  387. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.cjs +2 -0
  388. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.cjs.map +1 -0
  389. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.js +40 -0
  390. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.js.map +1 -0
  391. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.cjs +2 -0
  392. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.cjs.map +1 -0
  393. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.js +39 -0
  394. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.js.map +1 -0
  395. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.cjs +2 -0
  396. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.cjs.map +1 -0
  397. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.js +36 -0
  398. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.js.map +1 -0
  399. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.cjs +2 -0
  400. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.cjs.map +1 -0
  401. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.js +40 -0
  402. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.js.map +1 -0
  403. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs +2 -0
  404. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs.map +1 -0
  405. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js +47 -0
  406. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -0
  407. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/huggingface.cjs +1 -1
  408. package/dist/node_modules/@openhands/extensions/integrations/catalog/huggingface.cjs.map +1 -0
  409. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/huggingface.js +15 -5
  410. package/dist/node_modules/@openhands/extensions/integrations/catalog/huggingface.js.map +1 -0
  411. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.cjs +2 -0
  412. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.cjs.map +1 -0
  413. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.js +36 -0
  414. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.js.map +1 -0
  415. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/linear.cjs +1 -1
  416. package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.cjs.map +1 -0
  417. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/linear.js +15 -5
  418. package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.js.map +1 -0
  419. package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.cjs +2 -0
  420. package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.cjs.map +1 -0
  421. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/memory.js +13 -6
  422. package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.js.map +1 -0
  423. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.cjs +2 -0
  424. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.cjs.map +1 -0
  425. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.js +36 -0
  426. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.js.map +1 -0
  427. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.cjs +2 -0
  428. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.cjs.map +1 -0
  429. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.js +40 -0
  430. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.js.map +1 -0
  431. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs +2 -0
  432. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs.map +1 -0
  433. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js +39 -0
  434. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js.map +1 -0
  435. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.cjs +2 -0
  436. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.cjs.map +1 -0
  437. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.js +38 -0
  438. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.js.map +1 -0
  439. package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.cjs +2 -0
  440. package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.cjs.map +1 -0
  441. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/paypal.js +15 -5
  442. package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.js.map +1 -0
  443. package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.cjs +2 -0
  444. package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.cjs.map +1 -0
  445. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/playwright.js +13 -6
  446. package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.js.map +1 -0
  447. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.cjs +2 -0
  448. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.cjs.map +1 -0
  449. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.js +43 -0
  450. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.js.map +1 -0
  451. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.cjs +2 -0
  452. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.cjs.map +1 -0
  453. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.js +41 -0
  454. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.js.map +1 -0
  455. package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.cjs +2 -0
  456. package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.cjs.map +1 -0
  457. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/sentry.js +15 -5
  458. package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.js.map +1 -0
  459. package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.cjs +2 -0
  460. package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.cjs.map +1 -0
  461. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/sequential-thinking.js +13 -6
  462. package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.js.map +1 -0
  463. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs +2 -0
  464. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs.map +1 -0
  465. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js +45 -0
  466. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js.map +1 -0
  467. package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.cjs +2 -0
  468. package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.cjs.map +1 -0
  469. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/stripe.js +15 -5
  470. package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.js.map +1 -0
  471. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.cjs +2 -0
  472. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.cjs.map +1 -0
  473. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.js +37 -0
  474. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.js.map +1 -0
  475. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/tavily.cjs +1 -1
  476. package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.cjs.map +1 -0
  477. package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.js +39 -0
  478. package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.js.map +1 -0
  479. package/dist/node_modules/@openhands/extensions/integrations/catalog/time.cjs +2 -0
  480. package/dist/node_modules/@openhands/extensions/integrations/catalog/time.cjs.map +1 -0
  481. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/time.js +13 -6
  482. package/dist/node_modules/@openhands/extensions/integrations/catalog/time.js.map +1 -0
  483. package/dist/node_modules/@openhands/extensions/integrations/index.cjs +2 -0
  484. package/dist/node_modules/@openhands/extensions/integrations/index.cjs.map +1 -0
  485. package/dist/node_modules/@openhands/extensions/integrations/index.js +175 -0
  486. package/dist/node_modules/@openhands/extensions/integrations/index.js.map +1 -0
  487. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/logos.cjs +1 -1
  488. package/dist/node_modules/@openhands/extensions/integrations/logos.cjs.map +1 -0
  489. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/logos.js +2 -2
  490. package/dist/node_modules/@openhands/extensions/integrations/logos.js.map +1 -0
  491. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.cjs +2 -0
  492. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.cjs.map +1 -0
  493. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.js +548 -0
  494. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.js.map +1 -0
  495. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.cjs +2 -0
  496. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.cjs.map +1 -0
  497. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.js +482 -0
  498. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.js.map +1 -0
  499. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.cjs +1 -1
  500. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.cjs.map +1 -1
  501. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.js +3 -0
  502. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.js.map +1 -1
  503. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.cjs +2 -0
  504. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.cjs.map +1 -0
  505. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.js +22 -0
  506. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.js.map +1 -0
  507. package/dist/node_modules/@openhands/typescript-client/dist/index.cjs +1 -1
  508. package/dist/node_modules/@openhands/typescript-client/dist/index.js +1 -0
  509. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs +1 -1
  510. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs.map +1 -1
  511. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js +3 -0
  512. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js.map +1 -1
  513. package/dist/package.cjs +1 -1
  514. package/dist/package.cjs.map +1 -1
  515. package/dist/package.js +6 -4
  516. package/dist/package.js.map +1 -1
  517. package/dist/routes/mcp.cjs +1 -1
  518. package/dist/routes/mcp.cjs.map +1 -1
  519. package/dist/routes/mcp.js +1 -1
  520. package/dist/routes/mcp.js.map +1 -1
  521. package/dist/utils/mcp-marketplace-utils.cjs +1 -1
  522. package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
  523. package/dist/utils/mcp-marketplace-utils.d.ts +21 -1
  524. package/dist/utils/mcp-marketplace-utils.js +23 -13
  525. package/dist/utils/mcp-marketplace-utils.js.map +1 -1
  526. package/dist/utils/settings-utils.cjs.map +1 -1
  527. package/dist/utils/settings-utils.js.map +1 -1
  528. package/package.json +6 -4
  529. package/scripts/check-sdk-version-sync.mjs +6 -6
  530. package/scripts/dev-safe.mjs +25 -7
  531. package/scripts/dev-with-automation.mjs +6 -1
  532. package/tools/canvas_ui_tool.py +129 -0
  533. package/build/assets/add-backend-modal-CqjNjGqY.js +0 -1
  534. package/build/assets/conversation-COZAKz_K.js +0 -1
  535. package/build/assets/conversation-DWcvnmds.js +0 -19
  536. package/build/assets/conversation-panel-CZDStT0b.js +0 -1
  537. package/build/assets/declaration-C9nuq2Dj.js +0 -1
  538. package/build/assets/edit-automation-modal-C3bFxS2f.js +0 -1
  539. package/build/assets/git-control-bar-branch-button-Bm6rzSpo.js +0 -27
  540. package/build/assets/install-server-modal-VB5hOBpW.js +0 -1
  541. package/build/assets/llm-settings-CIdxmimN.js +0 -1
  542. package/build/assets/manifest-f041e61a.js +0 -1
  543. package/build/assets/mcp-BdfyCW1l.js +0 -9
  544. package/build/assets/messages-v-q35ObG.js +0 -36
  545. package/build/assets/recommended-automations-launcher-Cx7svuGE.js +0 -52
  546. package/build/assets/root-D2PVd51i.js +0 -2
  547. package/build/assets/root-DEotKI6b.css +0 -1
  548. package/build/assets/settings-service.api-Z6x0l0GU.js +0 -1
  549. package/build/assets/use-is-authed-BFoh8Ogh.js +0 -1
  550. package/build/assets/use-runtime-is-ready-BQWLEyqa.js +0 -1
  551. package/build/assets/use-user-conversation-BCYpbPT1.js +0 -1
  552. package/build/assets/vendor~home~mcp~automations-list-DRfWZRnF.js +0 -1
  553. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-BJm2mGIp.js +0 -48
  554. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.cjs +0 -2
  555. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.cjs.map +0 -1
  556. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.js +0 -30
  557. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.js.map +0 -1
  558. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.cjs +0 -2
  559. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.cjs.map +0 -1
  560. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.js +0 -29
  561. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.js.map +0 -1
  562. package/dist/node_modules/@openhands/extensions/mcps/catalog/atlassian.cjs.map +0 -1
  563. package/dist/node_modules/@openhands/extensions/mcps/catalog/atlassian.js.map +0 -1
  564. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.cjs +0 -2
  565. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.cjs.map +0 -1
  566. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.js +0 -29
  567. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.js.map +0 -1
  568. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.cjs +0 -2
  569. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.cjs.map +0 -1
  570. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.js +0 -24
  571. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.js.map +0 -1
  572. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.cjs +0 -2
  573. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.cjs.map +0 -1
  574. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.js +0 -45
  575. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.js.map +0 -1
  576. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-bindings.cjs.map +0 -1
  577. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-bindings.js.map +0 -1
  578. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.cjs +0 -2
  579. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.cjs.map +0 -1
  580. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.js.map +0 -1
  581. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-builds.cjs.map +0 -1
  582. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-builds.js.map +0 -1
  583. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-docs.cjs.map +0 -1
  584. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-docs.js.map +0 -1
  585. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.cjs +0 -2
  586. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.cjs.map +0 -1
  587. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.js.map +0 -1
  588. package/dist/node_modules/@openhands/extensions/mcps/catalog/deepwiki.cjs.map +0 -1
  589. package/dist/node_modules/@openhands/extensions/mcps/catalog/deepwiki.js.map +0 -1
  590. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.cjs +0 -2
  591. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.cjs.map +0 -1
  592. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.js +0 -29
  593. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.js.map +0 -1
  594. package/dist/node_modules/@openhands/extensions/mcps/catalog/everything.cjs.map +0 -1
  595. package/dist/node_modules/@openhands/extensions/mcps/catalog/everything.js.map +0 -1
  596. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.cjs +0 -2
  597. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.cjs.map +0 -1
  598. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.js +0 -29
  599. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.js.map +0 -1
  600. package/dist/node_modules/@openhands/extensions/mcps/catalog/fetch.cjs.map +0 -1
  601. package/dist/node_modules/@openhands/extensions/mcps/catalog/fetch.js.map +0 -1
  602. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.cjs +0 -2
  603. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.cjs.map +0 -1
  604. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.js +0 -33
  605. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.js.map +0 -1
  606. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.cjs +0 -2
  607. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.cjs.map +0 -1
  608. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.js +0 -32
  609. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.js.map +0 -1
  610. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.cjs +0 -2
  611. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.cjs.map +0 -1
  612. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.js +0 -29
  613. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.js.map +0 -1
  614. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.cjs +0 -2
  615. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.cjs.map +0 -1
  616. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.js +0 -33
  617. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.js.map +0 -1
  618. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.cjs +0 -2
  619. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.cjs.map +0 -1
  620. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.js +0 -40
  621. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.js.map +0 -1
  622. package/dist/node_modules/@openhands/extensions/mcps/catalog/huggingface.cjs.map +0 -1
  623. package/dist/node_modules/@openhands/extensions/mcps/catalog/huggingface.js.map +0 -1
  624. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.cjs +0 -2
  625. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.cjs.map +0 -1
  626. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.js +0 -29
  627. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.js.map +0 -1
  628. package/dist/node_modules/@openhands/extensions/mcps/catalog/linear.cjs.map +0 -1
  629. package/dist/node_modules/@openhands/extensions/mcps/catalog/linear.js.map +0 -1
  630. package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.cjs +0 -2
  631. package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.cjs.map +0 -1
  632. package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.js.map +0 -1
  633. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.cjs +0 -2
  634. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.cjs.map +0 -1
  635. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.js +0 -29
  636. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.js.map +0 -1
  637. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.cjs +0 -2
  638. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.cjs.map +0 -1
  639. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.js +0 -33
  640. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.js.map +0 -1
  641. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.cjs +0 -2
  642. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.cjs.map +0 -1
  643. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.js +0 -32
  644. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.js.map +0 -1
  645. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.cjs +0 -2
  646. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.cjs.map +0 -1
  647. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.js +0 -31
  648. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.js.map +0 -1
  649. package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.cjs +0 -2
  650. package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.cjs.map +0 -1
  651. package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.js.map +0 -1
  652. package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.cjs +0 -2
  653. package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.cjs.map +0 -1
  654. package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.js.map +0 -1
  655. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.cjs +0 -2
  656. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.cjs.map +0 -1
  657. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.js +0 -36
  658. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.js.map +0 -1
  659. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.cjs +0 -2
  660. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.cjs.map +0 -1
  661. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.js +0 -34
  662. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.js.map +0 -1
  663. package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.cjs +0 -2
  664. package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.cjs.map +0 -1
  665. package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.js.map +0 -1
  666. package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.cjs +0 -2
  667. package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.cjs.map +0 -1
  668. package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.js.map +0 -1
  669. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.cjs +0 -2
  670. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.cjs.map +0 -1
  671. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.js +0 -38
  672. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.js.map +0 -1
  673. package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.cjs +0 -2
  674. package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.cjs.map +0 -1
  675. package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.js.map +0 -1
  676. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.cjs +0 -2
  677. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.cjs.map +0 -1
  678. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.js +0 -30
  679. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.js.map +0 -1
  680. package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.cjs.map +0 -1
  681. package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.js +0 -32
  682. package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.js.map +0 -1
  683. package/dist/node_modules/@openhands/extensions/mcps/catalog/time.cjs +0 -2
  684. package/dist/node_modules/@openhands/extensions/mcps/catalog/time.cjs.map +0 -1
  685. package/dist/node_modules/@openhands/extensions/mcps/catalog/time.js.map +0 -1
  686. package/dist/node_modules/@openhands/extensions/mcps/index.cjs +0 -2
  687. package/dist/node_modules/@openhands/extensions/mcps/index.cjs.map +0 -1
  688. package/dist/node_modules/@openhands/extensions/mcps/index.js +0 -87
  689. package/dist/node_modules/@openhands/extensions/mcps/index.js.map +0 -1
  690. package/dist/node_modules/@openhands/extensions/mcps/logos.cjs.map +0 -1
  691. package/dist/node_modules/@openhands/extensions/mcps/logos.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@openhands/agent-canvas\",\n \"version\": \"1.0.0-alpha.7\",\n \"description\": \"Agent Canvas UI for OpenHands - run AI coding agents with a visual interface\",\n \"license\": \"MIT\",\n \"private\": false,\n \"type\": \"module\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/OpenHands/agent-canvas\"\n },\n \"homepage\": \"https://github.com/OpenHands/agent-canvas#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/OpenHands/agent-canvas/issues\"\n },\n \"bin\": {\n \"agent-canvas\": \"bin/agent-canvas.mjs\"\n },\n \"engines\": {\n \"node\": \">=22.12.0\"\n },\n \"dependencies\": {\n \"@heroui/react\": \"2.8.10\",\n \"@microlink/react-json-view\": \"1.31.20\",\n \"@monaco-editor/react\": \"4.7.0\",\n \"@openhands/extensions\": \"git+https://github.com/OpenHands/extensions.git#b8c1869ec9dea4467bb27d5754dc695d14e27889\",\n \"@openhands/typescript-client\": \"1.23.3\",\n \"@react-router/node\": \"7.14.2\",\n \"@react-router/serve\": \"7.14.2\",\n \"@tailwindcss/vite\": \"4.2.4\",\n \"@tanstack/react-query\": \"5.100.9\",\n \"@types/shell-quote\": \"^1.7.5\",\n \"@uidotdev/usehooks\": \"2.4.1\",\n \"@xterm/addon-fit\": \"0.11.0\",\n \"@xterm/xterm\": \"6.0.0\",\n \"axios\": \"1.16.0\",\n \"class-variance-authority\": \"0.7.1\",\n \"clsx\": \"2.1.1\",\n \"downshift\": \"9.3.2\",\n \"framer-motion\": \"12.38.0\",\n \"i18next\": \"26.0.8\",\n \"i18next-browser-languagedetector\": \"8.2.1\",\n \"i18next-http-backend\": \"4.0.0\",\n \"isbot\": \"5.1.39\",\n \"lucide-react\": \"1.14.0\",\n \"monaco-editor\": \"0.55.1\",\n \"posthog-js\": \"1.372.6\",\n \"react\": \"19.2.5\",\n \"react-dom\": \"19.2.5\",\n \"react-hot-toast\": \"2.6.0\",\n \"react-i18next\": \"17.0.6\",\n \"react-icons\": \"5.6.0\",\n \"react-markdown\": \"10.1.0\",\n \"react-router\": \"7.14.2\",\n \"react-syntax-highlighter\": \"16.1.1\",\n \"rehype-raw\": \"7.0.0\",\n \"rehype-sanitize\": \"6.0.0\",\n \"remark-breaks\": \"4.0.0\",\n \"remark-gfm\": \"4.0.1\",\n \"shell-quote\": \"^1.8.3\",\n \"sirv-cli\": \"3.0.1\",\n \"socket.io-client\": \"4.8.3\",\n \"tailwind-merge\": \"3.5.0\",\n \"tailwind-scrollbar\": \"4.0.2\",\n \"unist-util-visit\": \"5.1.0\",\n \"uuid\": \"14.0.0\",\n \"vite\": \"8.0.10\",\n \"zustand\": \"5.0.12\"\n },\n \"scripts\": {\n \"dev\": \"node --env-file-if-exists=.env scripts/dev-with-automation.mjs\",\n \"dev:static\": \"node --env-file-if-exists=.env scripts/dev-static.mjs\",\n \"dev:extra-backend\": \"node --env-file-if-exists=.env scripts/dev-extra-backend.mjs\",\n \"dev:minimal\": \"node --env-file-if-exists=.env scripts/dev-safe.mjs\",\n \"dev:frontend\": \"npm run make-i18n && cross-env VITE_MOCK_API=false react-router dev\",\n \"dev:mock\": \"npm run make-i18n && cross-env VITE_MOCK_API=true react-router dev\",\n \"build\": \"npm run build:app\",\n \"build:mock\": \"npm run make-i18n && cross-env VITE_MOCK_API=true react-router build\",\n \"start\": \"npx sirv-cli build/ --single\",\n \"test\": \"npm run make-i18n && vitest run\",\n \"test:e2e\": \"playwright test --pass-with-no-tests\",\n \"test:e2e:live\": \"node --env-file-if-exists=.env tests/e2e/live/scripts/run-live-e2e.mjs\",\n \"test:e2e:snapshots\": \"playwright test tests/e2e/snapshots --project=chromium --retries=0\",\n \"test:e2e:snapshots:update\": \"playwright test tests/e2e/snapshots --project=chromium --update-snapshots\",\n \"test:coverage\": \"npm run make-i18n && vitest run --coverage\",\n \"dev_wsl\": \"VITE_WATCH_USE_POLLING=true vite\",\n \"preview\": \"vite preview\",\n \"make-i18n\": \"node scripts/make-i18n-translations.cjs\",\n \"prelint\": \"npm run make-i18n\",\n \"lint\": \"npm run typecheck && eslint src && prettier --check src/**/*.{ts,tsx}\",\n \"lint:fix\": \"eslint src --fix && prettier --write src/**/*.{ts,tsx}\",\n \"prepare\": \"husky\",\n \"typecheck\": \"react-router typegen && tsc\",\n \"typecheck:staged\": \"react-router typegen && npx tsc --noEmit --skipLibCheck\",\n \"check-translation-completeness\": \"node scripts/check-translation-completeness.cjs\",\n \"build:app\": \"npm run make-i18n && react-router build\",\n \"build:lib\": \"npm run make-i18n && react-router typegen && cross-env BUILD_LIB=true VITE_APP_ENV=production vite build && tsc -p tsconfig.lib.json\",\n \"build:docker\": \"node scripts/docker-build.mjs\"\n },\n \"lint-staged\": {\n \"src/**/*.{ts,tsx,js}\": [\n \"eslint --fix\",\n \"prettier --write\"\n ],\n \"src/**/*.{ts,tsx}\": [\n \"bash -c 'npm run typecheck:staged'\"\n ],\n \"src/**/*\": [\n \"npm run check-translation-completeness\"\n ]\n },\n \"devDependencies\": {\n \"@eslint/eslintrc\": \"3.3.1\",\n \"@eslint/js\": \"9.39.4\",\n \"@mswjs/socket.io-binding\": \"0.2.0\",\n \"@playwright/test\": \"1.59.1\",\n \"@react-router/dev\": \"7.14.2\",\n \"@tailwindcss/typography\": \"0.5.19\",\n \"@tanstack/eslint-plugin-query\": \"5.100.9\",\n \"@testing-library/dom\": \"10.4.1\",\n \"@testing-library/jest-dom\": \"6.9.1\",\n \"@testing-library/react\": \"16.3.2\",\n \"@testing-library/user-event\": \"14.6.1\",\n \"@types/mdast\": \"4.0.4\",\n \"@types/node\": \"25.6.0\",\n \"@types/react\": \"19.2.14\",\n \"@types/react-dom\": \"19.2.3\",\n \"@types/react-syntax-highlighter\": \"15.5.13\",\n \"@typescript-eslint/eslint-plugin\": \"8.59.2\",\n \"@typescript-eslint/parser\": \"8.59.2\",\n \"@vercel/react-router\": \"1.3.0\",\n \"@vitest/coverage-v8\": \"4.1.5\",\n \"cross-env\": \"10.1.0\",\n \"eslint\": \"9.39.4\",\n \"eslint-config-prettier\": \"10.1.8\",\n \"eslint-import-resolver-typescript\": \"4.4.4\",\n \"eslint-plugin-i18next\": \"6.1.4\",\n \"eslint-plugin-import-x\": \"4.16.2\",\n \"eslint-plugin-jsx-a11y\": \"6.10.2\",\n \"eslint-plugin-prettier\": \"5.5.5\",\n \"eslint-plugin-react\": \"7.37.5\",\n \"eslint-plugin-react-hooks\": \"7.1.1\",\n \"eslint-plugin-unused-imports\": \"4.4.1\",\n \"globals\": \"16.5.0\",\n \"husky\": \"9.1.7\",\n \"jsdom\": \"29.1.1\",\n \"lint-staged\": \"16.4.0\",\n \"msw\": \"2.14.2\",\n \"postcss-prefix-selector\": \"2.1.1\",\n \"prettier\": \"3.8.3\",\n \"tailwindcss\": \"4.2.4\",\n \"typescript\": \"6.0.3\",\n \"vite-plugin-svgr\": \"5.2.0\",\n \"vitest\": \"4.1.5\"\n },\n \"packageManager\": \"npm@10.5.0\",\n \"volta\": {\n \"node\": \"22.12.0\"\n },\n \"msw\": {\n \"workerDirectory\": [\n \"public\"\n ]\n },\n \"overrides\": {\n \"dompurify\": \"3.3.2\"\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"files\": [\n \"dist\",\n \"bin\",\n \"build\",\n \"config\",\n \"scripts\"\n ],\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./browser\": {\n \"types\": \"./dist/components/browser/index.d.ts\",\n \"import\": \"./dist/components/browser/index.js\",\n \"require\": \"./dist/components/browser/index.cjs\"\n },\n \"./conversation\": {\n \"types\": \"./dist/components/conversation/index.d.ts\",\n \"import\": \"./dist/components/conversation/index.js\",\n \"require\": \"./dist/components/conversation/index.cjs\"\n },\n \"./files\": {\n \"types\": \"./dist/components/files/index.d.ts\",\n \"import\": \"./dist/components/files/index.js\",\n \"require\": \"./dist/components/files/index.cjs\"\n },\n \"./settings\": {\n \"types\": \"./dist/components/settings/index.d.ts\",\n \"import\": \"./dist/components/settings/index.js\",\n \"require\": \"./dist/components/settings/index.cjs\"\n },\n \"./sidebar\": {\n \"types\": \"./dist/components/sidebar/index.d.ts\",\n \"import\": \"./dist/components/sidebar/index.js\",\n \"require\": \"./dist/components/sidebar/index.cjs\"\n },\n \"./terminal\": {\n \"types\": \"./dist/components/terminal/index.d.ts\",\n \"import\": \"./dist/components/terminal/index.js\",\n \"require\": \"./dist/components/terminal/index.cjs\"\n },\n \"./i18n\": {\n \"types\": \"./dist/i18n/index.d.ts\",\n \"import\": \"./dist/i18n/index.js\",\n \"require\": \"./dist/i18n/index.cjs\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"peerDependencies\": {\n \"react\": \"19.2.5\",\n \"react-dom\": \"19.2.5\",\n \"react-router\": \"7.14.2\"\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@openhands/agent-canvas\",\n \"version\": \"1.0.0-alpha.8\",\n \"description\": \"Agent Canvas UI for OpenHands - run AI coding agents with a visual interface\",\n \"license\": \"MIT\",\n \"private\": false,\n \"type\": \"module\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/OpenHands/agent-canvas\"\n },\n \"homepage\": \"https://github.com/OpenHands/agent-canvas#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/OpenHands/agent-canvas/issues\"\n },\n \"bin\": {\n \"agent-canvas\": \"bin/agent-canvas.mjs\"\n },\n \"engines\": {\n \"node\": \">=22.12.0\"\n },\n \"dependencies\": {\n \"@heroui/react\": \"2.8.10\",\n \"@microlink/react-json-view\": \"1.31.20\",\n \"@monaco-editor/react\": \"4.7.0\",\n \"@openhands/extensions\": \"git+https://github.com/OpenHands/extensions.git#39711065f53166c52608462f60a4c8507253ce56\",\n \"@openhands/typescript-client\": \"1.24.0\",\n \"@react-router/node\": \"7.14.2\",\n \"@react-router/serve\": \"7.14.2\",\n \"@tailwindcss/vite\": \"4.2.4\",\n \"@tanstack/react-query\": \"5.100.9\",\n \"@types/shell-quote\": \"^1.7.5\",\n \"@uidotdev/usehooks\": \"2.4.1\",\n \"@xterm/addon-fit\": \"0.11.0\",\n \"@xterm/xterm\": \"6.0.0\",\n \"axios\": \"1.16.0\",\n \"class-variance-authority\": \"0.7.1\",\n \"clsx\": \"2.1.1\",\n \"downshift\": \"9.3.2\",\n \"framer-motion\": \"12.38.0\",\n \"i18next\": \"26.0.8\",\n \"i18next-browser-languagedetector\": \"8.2.1\",\n \"i18next-http-backend\": \"4.0.0\",\n \"isbot\": \"5.1.39\",\n \"lucide-react\": \"1.14.0\",\n \"monaco-editor\": \"0.55.1\",\n \"posthog-js\": \"1.372.6\",\n \"react\": \"19.2.5\",\n \"react-dom\": \"19.2.5\",\n \"react-hot-toast\": \"2.6.0\",\n \"react-i18next\": \"17.0.6\",\n \"react-icons\": \"5.6.0\",\n \"react-markdown\": \"10.1.0\",\n \"react-router\": \"7.14.2\",\n \"react-syntax-highlighter\": \"16.1.1\",\n \"rehype-raw\": \"7.0.0\",\n \"rehype-sanitize\": \"6.0.0\",\n \"remark-breaks\": \"4.0.0\",\n \"remark-gfm\": \"4.0.1\",\n \"shell-quote\": \"^1.8.3\",\n \"sirv-cli\": \"3.0.1\",\n \"socket.io-client\": \"4.8.3\",\n \"tailwind-merge\": \"3.5.0\",\n \"tailwind-scrollbar\": \"4.0.2\",\n \"unist-util-visit\": \"5.1.0\",\n \"uuid\": \"14.0.0\",\n \"vite\": \"8.0.10\",\n \"zustand\": \"5.0.12\"\n },\n \"scripts\": {\n \"dev\": \"node --env-file-if-exists=.env scripts/dev-with-automation.mjs\",\n \"dev:static\": \"node --env-file-if-exists=.env scripts/dev-static.mjs\",\n \"dev:extra-backend\": \"node --env-file-if-exists=.env scripts/dev-extra-backend.mjs\",\n \"dev:minimal\": \"node --env-file-if-exists=.env scripts/dev-safe.mjs\",\n \"dev:frontend\": \"npm run make-i18n && cross-env VITE_MOCK_API=false react-router dev\",\n \"dev:mock\": \"npm run make-i18n && cross-env VITE_MOCK_API=true react-router dev\",\n \"build\": \"npm run build:app\",\n \"build:mock\": \"npm run make-i18n && cross-env VITE_MOCK_API=true react-router build\",\n \"start\": \"npx sirv-cli build/ --single\",\n \"test\": \"npm run make-i18n && vitest run\",\n \"test:e2e\": \"playwright test --pass-with-no-tests\",\n \"test:e2e:live\": \"node --env-file-if-exists=.env tests/e2e/live/scripts/run-live-e2e.mjs\",\n \"test:e2e:mock-llm\": \"playwright test --config=playwright.mock-llm.config.ts\",\n \"test:e2e:snapshots\": \"playwright test tests/e2e/snapshots --project=chromium --retries=0\",\n \"test:e2e:snapshots:update\": \"playwright test tests/e2e/snapshots --project=chromium --update-snapshots\",\n \"test:coverage\": \"npm run make-i18n && vitest run --coverage\",\n \"dev_wsl\": \"VITE_WATCH_USE_POLLING=true vite\",\n \"preview\": \"vite preview\",\n \"make-i18n\": \"node scripts/make-i18n-translations.cjs\",\n \"prelint\": \"npm run make-i18n\",\n \"lint\": \"npm run typecheck && eslint src && prettier --check src/**/*.{ts,tsx}\",\n \"lint:fix\": \"eslint src --fix && prettier --write src/**/*.{ts,tsx}\",\n \"prepare\": \"husky\",\n \"typecheck\": \"react-router typegen && tsc\",\n \"typecheck:staged\": \"react-router typegen && npx tsc --noEmit --skipLibCheck\",\n \"check-translation-completeness\": \"node scripts/check-translation-completeness.cjs\",\n \"build:app\": \"npm run make-i18n && react-router build\",\n \"build:lib\": \"npm run make-i18n && react-router typegen && cross-env BUILD_LIB=true VITE_APP_ENV=production vite build && tsc -p tsconfig.lib.json\",\n \"build:docker\": \"node scripts/docker-build.mjs\"\n },\n \"lint-staged\": {\n \"src/**/*.{ts,tsx,js}\": [\n \"eslint --fix\",\n \"prettier --write\"\n ],\n \"src/**/*.{ts,tsx}\": [\n \"bash -c 'npm run typecheck:staged'\"\n ],\n \"src/**/*\": [\n \"npm run check-translation-completeness\"\n ]\n },\n \"devDependencies\": {\n \"@eslint/eslintrc\": \"3.3.1\",\n \"@eslint/js\": \"9.39.4\",\n \"@mswjs/socket.io-binding\": \"0.2.0\",\n \"@playwright/test\": \"1.59.1\",\n \"@react-router/dev\": \"7.14.2\",\n \"@tailwindcss/typography\": \"0.5.19\",\n \"@tanstack/eslint-plugin-query\": \"5.100.9\",\n \"@testing-library/dom\": \"10.4.1\",\n \"@testing-library/jest-dom\": \"6.9.1\",\n \"@testing-library/react\": \"16.3.2\",\n \"@testing-library/user-event\": \"14.6.1\",\n \"@types/mdast\": \"4.0.4\",\n \"@types/node\": \"25.6.0\",\n \"@types/react\": \"19.2.14\",\n \"@types/react-dom\": \"19.2.3\",\n \"@types/react-syntax-highlighter\": \"15.5.13\",\n \"@typescript-eslint/eslint-plugin\": \"8.59.2\",\n \"@typescript-eslint/parser\": \"8.59.2\",\n \"@vercel/react-router\": \"1.3.0\",\n \"@vitest/coverage-v8\": \"4.1.5\",\n \"cross-env\": \"10.1.0\",\n \"eslint\": \"9.39.4\",\n \"eslint-config-prettier\": \"10.1.8\",\n \"eslint-import-resolver-typescript\": \"4.4.4\",\n \"eslint-plugin-i18next\": \"6.1.4\",\n \"eslint-plugin-import-x\": \"4.16.2\",\n \"eslint-plugin-jsx-a11y\": \"6.10.2\",\n \"eslint-plugin-prettier\": \"5.5.5\",\n \"eslint-plugin-react\": \"7.37.5\",\n \"eslint-plugin-react-hooks\": \"7.1.1\",\n \"eslint-plugin-unused-imports\": \"4.4.1\",\n \"globals\": \"16.5.0\",\n \"husky\": \"9.1.7\",\n \"jsdom\": \"29.1.1\",\n \"lint-staged\": \"16.4.0\",\n \"msw\": \"2.14.2\",\n \"postcss-prefix-selector\": \"2.1.1\",\n \"prettier\": \"3.8.3\",\n \"tailwindcss\": \"4.2.4\",\n \"typescript\": \"6.0.3\",\n \"vite-plugin-svgr\": \"5.2.0\",\n \"vitest\": \"4.1.5\"\n },\n \"packageManager\": \"npm@10.5.0\",\n \"volta\": {\n \"node\": \"22.12.0\"\n },\n \"msw\": {\n \"workerDirectory\": [\n \"public\"\n ]\n },\n \"overrides\": {\n \"dompurify\": \"3.3.2\"\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"files\": [\n \"dist\",\n \"bin\",\n \"build\",\n \"config\",\n \"scripts\",\n \"tools\"\n ],\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./browser\": {\n \"types\": \"./dist/components/browser/index.d.ts\",\n \"import\": \"./dist/components/browser/index.js\",\n \"require\": \"./dist/components/browser/index.cjs\"\n },\n \"./conversation\": {\n \"types\": \"./dist/components/conversation/index.d.ts\",\n \"import\": \"./dist/components/conversation/index.js\",\n \"require\": \"./dist/components/conversation/index.cjs\"\n },\n \"./files\": {\n \"types\": \"./dist/components/files/index.d.ts\",\n \"import\": \"./dist/components/files/index.js\",\n \"require\": \"./dist/components/files/index.cjs\"\n },\n \"./settings\": {\n \"types\": \"./dist/components/settings/index.d.ts\",\n \"import\": \"./dist/components/settings/index.js\",\n \"require\": \"./dist/components/settings/index.cjs\"\n },\n \"./sidebar\": {\n \"types\": \"./dist/components/sidebar/index.d.ts\",\n \"import\": \"./dist/components/sidebar/index.js\",\n \"require\": \"./dist/components/sidebar/index.cjs\"\n },\n \"./terminal\": {\n \"types\": \"./dist/components/terminal/index.d.ts\",\n \"import\": \"./dist/components/terminal/index.js\",\n \"require\": \"./dist/components/terminal/index.cjs\"\n },\n \"./i18n\": {\n \"types\": \"./dist/i18n/index.d.ts\",\n \"import\": \"./dist/i18n/index.js\",\n \"require\": \"./dist/i18n/index.cjs\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"peerDependencies\": {\n \"react\": \"19.2.5\",\n \"react-dom\": \"19.2.5\",\n \"react-router\": \"7.14.2\"\n }\n}\n"],"mappings":""}
@@ -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/mcps/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=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;
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 MCP_CATALOG as MCP_MARKETPLACE,\n type McpCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/mcps\";\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, MCP_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 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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"}
@@ -12,7 +12,7 @@ import { ConfirmationModal as d } from "../components/shared/modals/confirmation
12
12
  import { useDeleteMcpServer as f } from "../hooks/mutation/use-delete-mcp-server.js";
13
13
  import "../utils/acp-route-guard.js";
14
14
  import { findCatalogEntryForServer as p, installedServerMatchesQuery as m } from "../utils/mcp-marketplace-utils.js";
15
- import h from "../node_modules/@openhands/extensions/mcps/index.js";
15
+ import h from "../node_modules/@openhands/extensions/integrations/index.js";
16
16
  import { flattenMcpConfig as g } from "../utils/mcp-installed-servers.js";
17
17
  import { InstalledServersSection as _ } from "../components/features/mcp-page/installed-servers-section.js";
18
18
  import { MarketplaceSection as v } from "../components/features/mcp-page/marketplace-section.js";
@@ -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 MCP_CATALOG as MCP_MARKETPLACE,\n type McpCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/mcps\";\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, MCP_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":";;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAwB,IAAU;CAChC,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,MAAM,GAAU,iBAAc,GAAa,EAC7C,EAAE,QAAQ,GAAiB,WAAW,MAC1C,GAAoB,EAEhB,IADgB,GACF,CAAc,QAAQ,MAEpC,CAAC,GAAc,KACnB,EAAM,SAAkC,KAAK,EACzC,CAAC,GAAe,KACpB,EAAM,SAAiC,KAAK,EACxC,CAAC,GAAgB,KACrB,EAAM,SAAiC,KAAK,EACxC,CAAC,GAAa,KAAkB,EAAM,SAAS,GAAG,EAClD,CAAC,GAAe,KACpB,EAAM,SAA2B,MAAM,EAGnC,IAAa,EADD,EAAe,GAAU,gBAAgB,WACvB,CAAU,EAMxC,IAA2B,EAAW,QAAQ,MAClD,EACE,GACA,EAA0B,GAAQ,EAAgB,EAClD,EACD,CACF,EAEK,KAA4B,MAA4B;AAC5D,IAAgB,EAAM;;AA6CxB,QAdI,KAAa,CAAC,IAEd,kBAAC,OAAD;EACE,eAAY;EACZ,WAAU;YAFZ,CAIE,kBAAC,GAAD,EAAwB,CAAA,EACxB,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD,EAAK,WAAU,uFAAwF,CAAA;GACnG,CAAA,CACF;MAKR,kBAAC,OAAD;EACE,eAAY;EACZ,WAAU;YAFZ,CAIE,kBAAC,GAAD,EAAwB,CAAA,EACxB,kBAAC,QAAD;GAAM,WAAW;aAAjB;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAE,EAAQ,mBAAmB;UAC3B,CAAA,EACL,kBAAC,OAAD;UAAK,WAAU;oBACZ,EAAE,EAAQ,qBAAqB;UAC5B,CAAA,CACF;YACN,kBAAC,GAAD;SACE,MAAK;SACL,SAAQ;SACR,QAAO;SACP,WAAU;SACV,eAAe,EAAiB;UAAE,IAAI;UAAI,MAAM;UAAO,CAAC;mBAEvD,EAAE,EAAQ,eAAe;SACd,CAAA,CACV;;OACF,CAAA;MAEN,kBAAC,GAAD;OACE,QAAQ;OACR,gBAAgB;OACD;OACf,uBAAuB;OACvB,CAAA;MAED,MAAkB,YAaf,OAZF,kBAAC,WAAD;OAAS,WAAU;iBAAnB,CACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAE,EAAQ,oBAAoB;QAC5B,CAAA,EACL,kBAAC,GAAD;QACE,SAAS;QACT,iBAAiB,EAAW,SAAS;QACrC,OAAO;QACP,SAxFM,MAA4B;AAC9C,WAAiB,EAAO;;QAwFZ,WArFa,MAAqB;SAC9C,IAAM,IAAS,EAAW,MAAM,MAAM,EAAE,OAAO,EAAS;AACxD,SAAI,KAAQ,EAAkB,EAAO;;QAoFzB,CAAA,CACM;;MAGX,MAAkB,cAOf,OANF,kBAAC,GAAD;OACe;OACb,UAAU;OACV,OAAO;OACP,OAAO;OACP,CAAA;MAEA;;IAEL,KACC,kBAAC,GAAD;KACE,OAAO;KACP,eAAe,EAAgB,KAAK;KACpC,CAAA;IAKH,KACC,kBAAC,GAAD;KACE,QAAQ;KACR,iBAAiB;KACjB,eAAe,EAAiB,KAAK;KACrC,CAAA;IAGH,KACC,kBAAC,GAAD;KACE,MAAM,EAAE,EAAQ,4BAA4B;KAC5C,gBAAgB,EAAkB,KAAK;KACvC,iBApHwB;AAC3B,WAKL,EAAgB,GAAgB;OAC9B,iBAAiB;AAEf,QADA,EAAoB,EAAE,EAAQ,mBAAmB,CAAC,EAClD,EAAkB,KAAK;;OAEzB,UAAU,MAAQ;AAGhB,QADA,EADgB,EAA0B,EACxB,IAAW,EAAE,EAAQ,cAAc,CAAC,EACtD,EAAkB,KAAK;;OAE1B,CAAC;;KAqGM,cAAc;KACd,CAAA;IAEC;KACH"}
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,2 +1,2 @@
1
- require(`../_virtual/_rolldown/runtime.cjs`);var e=e=>{try{return new URL(e)}catch{return null}};function t(t,n){let r=typeof t==`string`?t:``,i=typeof n==`string`?n:``;if(!r||!i)return!1;let a=e(r),o=e(i);return!a||!o?r.replace(/\/+$/,``)===i.replace(/\/+$/,``):a.protocol===o.protocol&&a.host===o.host&&a.pathname.replace(/\/+$/,``)===o.pathname.replace(/\/+$/,``)}function n(e,t){return!e.availability||e.availability===`all`?!0:e.availability===t}function r(e){return e.trim().toLowerCase()}function i(e){return e.map((e,t)=>({entry:e,index:t})).sort((e,t)=>(t.entry.popularityRank??0)-(e.entry.popularityRank??0)||e.index-t.index).map(({entry:e})=>e)}function a(e,t){let n=r(t);return n?[e.name,e.description,e.id,...e.keywords??[]].join(` `).toLowerCase().includes(n):!0}function o(e,t,n){let i=r(n);return i?[e.type,`name`in e?e.name:void 0,`command`in e?e.command:void 0,`args`in e?e.args?.join(` `):void 0,`url`in e?e.url:void 0,t?.name,t?.description,t?.id,...t?.keywords??[]].filter(Boolean).join(` `).toLowerCase().includes(i):!0}function s(e,n){return n.find(n=>{let r=n.template;return r.kind===`stdio`?e.type===`stdio`&&e.name===r.serverName:r.kind===`shttp`?e.type===`shttp`&&t(e.url,r.url):r.kind===`sse`?e.type===`sse`&&t(e.url,r.url):!1})}exports.findCatalogEntryForServer=s,exports.getMarketplaceEntriesByPopularity=i,exports.installedServerMatchesQuery=o,exports.isMarketplaceEntryAvailable=n,exports.marketplaceEntryMatchesQuery=a;
1
+ require(`../_virtual/_rolldown/runtime.cjs`);var e=e=>{try{return new URL(e)}catch{return null}};function t(t,n){let r=typeof t==`string`?t:``,i=typeof n==`string`?n:``;if(!r||!i)return!1;let a=e(r),o=e(i);return!a||!o?r.replace(/\/+$/,``)===i.replace(/\/+$/,``):a.protocol===o.protocol&&a.host===o.host&&a.pathname.replace(/\/+$/,``)===o.pathname.replace(/\/+$/,``)}function n(e){return(e.connectionOptions.find(t=>t.id===e.defaultConnectionOptionId)??e.connectionOptions[0])?.transport}function r(e){let t=e.connectionOptions.find(e=>e.transport?.kind===`stdio`);return t?.transport?t.transport:n(e)}function i(e,t){return!e.runtimeAvailability||e.runtimeAvailability===`all`?!0:e.runtimeAvailability===t}function a(e){return e.trim().toLowerCase()}function o(e){return e.map((e,t)=>({entry:e,index:t})).sort((e,t)=>(t.entry.popularityRank??0)-(e.entry.popularityRank??0)||e.index-t.index).map(({entry:e})=>e)}function s(e,t){let n=a(t);return n?[e.name,e.description,e.id,...e.keywords??[]].join(` `).toLowerCase().includes(n):!0}function c(e,t,n){let r=a(n);return r?[e.type,`name`in e?e.name:void 0,`command`in e?e.command:void 0,`args`in e?e.args?.join(` `):void 0,`url`in e?e.url:void 0,t?.name,t?.description,t?.id,...t?.keywords??[]].filter(Boolean).join(` `).toLowerCase().includes(r):!0}function l(e,n){return n.find(n=>{for(let r of n.connectionOptions){let n=r.transport;if(n&&(n.kind===`stdio`&&e.type===`stdio`&&e.name===n.serverName||n.kind===`shttp`&&e.type===`shttp`&&t(e.url,n.url)||n.kind===`sse`&&e.type===`sse`&&t(e.url,n.url)))return!0}return!1})}exports.findCatalogEntryForServer=l,exports.getDefaultTemplate=n,exports.getInstallableTemplate=r,exports.getMarketplaceEntriesByPopularity=o,exports.installedServerMatchesQuery=c,exports.isMarketplaceEntryAvailable=i,exports.marketplaceEntryMatchesQuery=s;
2
2
  //# sourceMappingURL=mcp-marketplace-utils.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-marketplace-utils.cjs","names":[],"sources":["../../src/utils/mcp-marketplace-utils.ts"],"sourcesContent":["import { MCPServerConfig } from \"#/types/mcp-server\";\nimport type {\n McpCatalogEntry as MarketplaceEntry,\n MarketplaceTemplate,\n} from \"@openhands/extensions/mcps\";\n\nconst tryUrl = (raw: string): URL | null => {\n try {\n return new URL(raw);\n } catch {\n return null;\n }\n};\n\n/**\n * Loose URL match that ignores query strings, trailing slashes, and\n * default ports. We want clicking \"Linear\" to flag the entry as\n * installed even if the user pasted the URL with extra trailing slash\n * or a different port-equivalent variant.\n *\n * Defensive against runtime data that doesn't match the static type:\n * if either input is not a string (e.g. parsed from an older settings\n * blob), we fall through the URL parsing path and the safe trim\n * fallback below, never calling `.replace` on undefined.\n */\nexport function urlsMatch(a: unknown, b: unknown): boolean {\n const aStr = typeof a === \"string\" ? a : \"\";\n const bStr = typeof b === \"string\" ? b : \"\";\n if (!aStr || !bStr) return false;\n const left = tryUrl(aStr);\n const right = tryUrl(bStr);\n if (!left || !right) {\n return aStr.replace(/\\/+$/, \"\") === bStr.replace(/\\/+$/, \"\");\n }\n return (\n left.protocol === right.protocol &&\n left.host === right.host &&\n left.pathname.replace(/\\/+$/, \"\") === right.pathname.replace(/\\/+$/, \"\")\n );\n}\n\n/**\n * Decide whether a marketplace template is already represented by one\n * of the installed MCP servers. Used to render an \"Installed\" badge on\n * the marketplace tile. Returns the first matching server, or null.\n */\nexport function findInstalledMatch(\n template: MarketplaceTemplate,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n if (template.kind === \"shttp\") {\n const tplUrl = template.url;\n if (!tplUrl) return null;\n return (\n servers.find(\n (s) => s.type === \"shttp\" && !!s.url && urlsMatch(s.url, tplUrl),\n ) ?? null\n );\n }\n\n if (template.kind === \"sse\") {\n const tplUrl = template.url;\n if (!tplUrl) return null;\n return (\n servers.find(\n (s) => s.type === \"sse\" && !!s.url && urlsMatch(s.url, tplUrl),\n ) ?? null\n );\n }\n\n // stdio: match on the registered server name.\n return (\n servers.find((s) => s.type === \"stdio\" && s.name === template.serverName) ??\n null\n );\n}\n\nexport function isMarketplaceEntryAvailable(\n entry: MarketplaceEntry,\n backendKind: \"local\" | \"cloud\",\n): boolean {\n if (!entry.availability || entry.availability === \"all\") return true;\n return entry.availability === backendKind;\n}\n\nfunction normalize(query: string): string {\n return query.trim().toLowerCase();\n}\n\n/**\n * Case-insensitive substring match against the catalog entry's\n * user-visible identity (name, description, id, keywords). Empty\n * queries always match.\n */\nexport function getMarketplaceEntriesByPopularity(\n catalog: MarketplaceEntry[],\n): MarketplaceEntry[] {\n return catalog\n .map((entry, index) => ({ entry, index }))\n .sort((a, b) => {\n const byPopularity =\n (b.entry.popularityRank ?? 0) - (a.entry.popularityRank ?? 0);\n return byPopularity || a.index - b.index;\n })\n .map(({ entry }) => entry);\n}\n\nexport function getMarketplaceEntryById(\n id: string,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => entry.id === id);\n}\n\nexport function marketplaceEntryMatchesQuery(\n entry: MarketplaceEntry,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n entry.name,\n entry.description,\n entry.id,\n ...(entry.keywords ?? []),\n ]\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Search match for an installed (already-configured) server. We\n * search the server's own identifying fields and — if it's a catalog\n * entry — its catalog name/keywords too, so typing \"Slack\" matches\n * the installed Slack tile even though the persisted server is just\n * `{ type: \"stdio\", name: \"slack\", ... }`.\n */\nexport function installedServerMatchesQuery(\n server: MCPServerConfig,\n catalogEntry: MarketplaceEntry | undefined,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n server.type,\n \"name\" in server ? server.name : undefined,\n \"command\" in server ? server.command : undefined,\n \"args\" in server ? server.args?.join(\" \") : undefined,\n \"url\" in server ? server.url : undefined,\n catalogEntry?.name,\n catalogEntry?.description,\n catalogEntry?.id,\n ...(catalogEntry?.keywords ?? []),\n ]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Look up the catalog entry that best matches an installed server.\n * Mirrors the lookup used in `installed-server-card.tsx` for\n * rendering the friendly icon.\n */\nexport function findCatalogEntryForServer(\n server: MCPServerConfig,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => {\n const tpl = entry.template;\n if (tpl.kind === \"stdio\")\n return server.type === \"stdio\" && server.name === tpl.serverName;\n // Reuse the same loose URL match as `findInstalledMatch` so a\n // server whose URL was normalized by the backend (trailing slash\n // stripped, query string dropped, etc.) still gets paired with\n // its catalog tile — otherwise the installed-servers list would\n // render the generic icon while the marketplace shows the\n // entry as installed, which is confusing.\n if (tpl.kind === \"shttp\")\n return server.type === \"shttp\" && urlsMatch(server.url, tpl.url);\n if (tpl.kind === \"sse\")\n return server.type === \"sse\" && urlsMatch(server.url, tpl.url);\n return false;\n });\n}\n"],"mappings":"6CAMA,IAAM,EAAU,GAA4B,CAC1C,GAAI,CACF,OAAO,IAAI,IAAI,EAAI,MACb,CACN,OAAO,OAeX,SAAgB,EAAU,EAAY,EAAqB,CACzD,IAAM,EAAO,OAAO,GAAM,SAAW,EAAI,GACnC,EAAO,OAAO,GAAM,SAAW,EAAI,GACzC,GAAI,CAAC,GAAQ,CAAC,EAAM,MAAO,GAC3B,IAAM,EAAO,EAAO,EAAK,CACnB,EAAQ,EAAO,EAAK,CAI1B,MAHI,CAAC,GAAQ,CAAC,EACL,EAAK,QAAQ,OAAQ,GAAG,GAAK,EAAK,QAAQ,OAAQ,GAAG,CAG5D,EAAK,WAAa,EAAM,UACxB,EAAK,OAAS,EAAM,MACpB,EAAK,SAAS,QAAQ,OAAQ,GAAG,GAAK,EAAM,SAAS,QAAQ,OAAQ,GAAG,CAwC5E,SAAgB,EACd,EACA,EACS,CAET,MADI,CAAC,EAAM,cAAgB,EAAM,eAAiB,MAAc,GACzD,EAAM,eAAiB,EAGhC,SAAS,EAAU,EAAuB,CACxC,OAAO,EAAM,MAAM,CAAC,aAAa,CAQnC,SAAgB,EACd,EACoB,CACpB,OAAO,EACJ,KAAK,EAAO,KAAW,CAAE,QAAO,QAAO,EAAE,CACzC,MAAM,EAAG,KAEL,EAAE,MAAM,gBAAkB,IAAM,EAAE,MAAM,gBAAkB,IACtC,EAAE,MAAQ,EAAE,MACnC,CACD,KAAK,CAAE,WAAY,EAAM,CAU9B,SAAgB,EACd,EACA,EACS,CACT,IAAM,EAAI,EAAU,EAAS,CAU7B,OATK,EACY,CACf,EAAM,KACN,EAAM,YACN,EAAM,GACN,GAAI,EAAM,UAAY,EAAE,CACzB,CACE,KAAK,IAAI,CACT,aACI,CAAS,SAAS,EAAE,CATZ,GAmBjB,SAAgB,EACd,EACA,EACA,EACS,CACT,IAAM,EAAI,EAAU,EAAS,CAgB7B,OAfK,EACY,CACf,EAAO,KACP,SAAU,EAAS,EAAO,KAAO,IAAA,GACjC,YAAa,EAAS,EAAO,QAAU,IAAA,GACvC,SAAU,EAAS,EAAO,MAAM,KAAK,IAAI,CAAG,IAAA,GAC5C,QAAS,EAAS,EAAO,IAAM,IAAA,GAC/B,GAAc,KACd,GAAc,YACd,GAAc,GACd,GAAI,GAAc,UAAY,EAAE,CACjC,CACE,OAAO,QAAQ,CACf,KAAK,IAAI,CACT,aACI,CAAS,SAAS,EAAE,CAfZ,GAuBjB,SAAgB,EACd,EACA,EAC8B,CAC9B,OAAO,EAAQ,KAAM,GAAU,CAC7B,IAAM,EAAM,EAAM,SAalB,OAZI,EAAI,OAAS,QACR,EAAO,OAAS,SAAW,EAAO,OAAS,EAAI,WAOpD,EAAI,OAAS,QACR,EAAO,OAAS,SAAW,EAAU,EAAO,IAAK,EAAI,IAAI,CAC9D,EAAI,OAAS,MACR,EAAO,OAAS,OAAS,EAAU,EAAO,IAAK,EAAI,IAAI,CACzD,IACP"}
1
+ {"version":3,"file":"mcp-marketplace-utils.cjs","names":[],"sources":["../../src/utils/mcp-marketplace-utils.ts"],"sourcesContent":["import { MCPServerConfig } from \"#/types/mcp-server\";\nimport type {\n IntegrationCatalogEntry as MarketplaceEntry,\n IntegrationTransport as MarketplaceTemplate,\n} from \"@openhands/extensions/integrations\";\n\nconst tryUrl = (raw: string): URL | null => {\n try {\n return new URL(raw);\n } catch {\n return null;\n }\n};\n\n/**\n * Loose URL match that ignores query strings, trailing slashes, and\n * default ports. We want clicking \"Linear\" to flag the entry as\n * installed even if the user pasted the URL with extra trailing slash\n * or a different port-equivalent variant.\n *\n * Defensive against runtime data that doesn't match the static type:\n * if either input is not a string (e.g. parsed from an older settings\n * blob), we fall through the URL parsing path and the safe trim\n * fallback below, never calling `.replace` on undefined.\n */\nexport function urlsMatch(a: unknown, b: unknown): boolean {\n const aStr = typeof a === \"string\" ? a : \"\";\n const bStr = typeof b === \"string\" ? b : \"\";\n if (!aStr || !bStr) return false;\n const left = tryUrl(aStr);\n const right = tryUrl(bStr);\n if (!left || !right) {\n return aStr.replace(/\\/+$/, \"\") === bStr.replace(/\\/+$/, \"\");\n }\n return (\n left.protocol === right.protocol &&\n left.host === right.host &&\n left.pathname.replace(/\\/+$/, \"\") === right.pathname.replace(/\\/+$/, \"\")\n );\n}\n\n/**\n * Get the default transport template from an integration catalog entry.\n * Integrations may have multiple connection options; we use the default\n * one (or the first if no default is specified). Only MCP-backed options\n * have a `transport` field.\n */\nexport function getDefaultTemplate(\n entry: MarketplaceEntry,\n): MarketplaceTemplate | undefined {\n const option =\n entry.connectionOptions.find(\n (o) => o.id === entry.defaultConnectionOptionId,\n ) ?? entry.connectionOptions[0];\n return option?.transport;\n}\n\n/**\n * Get the stdio (API key-based) transport template from an integration entry.\n * Many integrations have multiple connection options (e.g., OAuth + stdio).\n * Since OAuth isn't implemented in the UI yet, the install modal should use\n * this function to get the stdio-based option that can be configured with\n * API keys/tokens.\n *\n * Falls back to getDefaultTemplate if no stdio option exists.\n */\nexport function getInstallableTemplate(\n entry: MarketplaceEntry,\n): MarketplaceTemplate | undefined {\n // First, try to find a stdio option (API key-based, what we can actually install)\n const stdioOption = entry.connectionOptions.find(\n (o) => o.transport?.kind === \"stdio\",\n );\n if (stdioOption?.transport) return stdioOption.transport;\n\n // Fall back to the default template (could be shttp/sse with api_key)\n return getDefaultTemplate(entry);\n}\n\n/**\n * Decide whether a marketplace template is already represented by one\n * of the installed MCP servers. Used to render an \"Installed\" badge on\n * the marketplace tile. Returns the first matching server, or null.\n */\nexport function findInstalledMatch(\n template: MarketplaceTemplate,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n if (template.kind === \"shttp\") {\n const tplUrl = template.url;\n if (!tplUrl) return null;\n return (\n servers.find(\n (s) => s.type === \"shttp\" && !!s.url && urlsMatch(s.url, tplUrl),\n ) ?? null\n );\n }\n\n if (template.kind === \"sse\") {\n const tplUrl = template.url;\n if (!tplUrl) return null;\n return (\n servers.find(\n (s) => s.type === \"sse\" && !!s.url && urlsMatch(s.url, tplUrl),\n ) ?? null\n );\n }\n\n // stdio: match on the registered server name.\n return (\n servers.find((s) => s.type === \"stdio\" && s.name === template.serverName) ??\n null\n );\n}\n\nexport function isMarketplaceEntryAvailable(\n entry: MarketplaceEntry,\n backendKind: \"local\" | \"cloud\",\n): boolean {\n if (!entry.runtimeAvailability || entry.runtimeAvailability === \"all\")\n return true;\n return entry.runtimeAvailability === backendKind;\n}\n\nfunction normalize(query: string): string {\n return query.trim().toLowerCase();\n}\n\n/**\n * Case-insensitive substring match against the catalog entry's\n * user-visible identity (name, description, id, keywords). Empty\n * queries always match.\n */\nexport function getMarketplaceEntriesByPopularity(\n catalog: MarketplaceEntry[],\n): MarketplaceEntry[] {\n return catalog\n .map((entry, index) => ({ entry, index }))\n .sort((a, b) => {\n const byPopularity =\n (b.entry.popularityRank ?? 0) - (a.entry.popularityRank ?? 0);\n return byPopularity || a.index - b.index;\n })\n .map(({ entry }) => entry);\n}\n\nexport function getMarketplaceEntryById(\n id: string,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => entry.id === id);\n}\n\nexport function marketplaceEntryMatchesQuery(\n entry: MarketplaceEntry,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n entry.name,\n entry.description,\n entry.id,\n ...(entry.keywords ?? []),\n ]\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Search match for an installed (already-configured) server. We\n * search the server's own identifying fields and — if it's a catalog\n * entry — its catalog name/keywords too, so typing \"Slack\" matches\n * the installed Slack tile even though the persisted server is just\n * `{ type: \"stdio\", name: \"slack\", ... }`.\n */\nexport function installedServerMatchesQuery(\n server: MCPServerConfig,\n catalogEntry: MarketplaceEntry | undefined,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n server.type,\n \"name\" in server ? server.name : undefined,\n \"command\" in server ? server.command : undefined,\n \"args\" in server ? server.args?.join(\" \") : undefined,\n \"url\" in server ? server.url : undefined,\n catalogEntry?.name,\n catalogEntry?.description,\n catalogEntry?.id,\n ...(catalogEntry?.keywords ?? []),\n ]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Look up the catalog entry that best matches an installed server.\n * Mirrors the lookup used in `installed-server-card.tsx` for\n * rendering the friendly icon.\n *\n * Since an entry may have multiple connection options (e.g., OAuth + stdio),\n * we check ALL templates in the entry's connectionOptions, not just the default.\n */\nexport function findCatalogEntryForServer(\n server: MCPServerConfig,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => {\n // Check all connection options, not just the default\n for (const option of entry.connectionOptions) {\n const tpl = option.transport;\n if (!tpl) continue;\n if (tpl.kind === \"stdio\") {\n if (server.type === \"stdio\" && server.name === tpl.serverName)\n return true;\n }\n // Reuse the same loose URL match as `findInstalledMatch` so a\n // server whose URL was normalized by the backend (trailing slash\n // stripped, query string dropped, etc.) still gets paired with\n // its catalog tile — otherwise the installed-servers list would\n // render the generic icon while the marketplace shows the\n // entry as installed, which is confusing.\n if (tpl.kind === \"shttp\") {\n if (server.type === \"shttp\" && urlsMatch(server.url, tpl.url))\n return true;\n }\n if (tpl.kind === \"sse\") {\n if (server.type === \"sse\" && urlsMatch(server.url, tpl.url))\n return true;\n }\n }\n return false;\n });\n}\n"],"mappings":"6CAMA,IAAM,EAAU,GAA4B,CAC1C,GAAI,CACF,OAAO,IAAI,IAAI,EAAI,MACb,CACN,OAAO,OAeX,SAAgB,EAAU,EAAY,EAAqB,CACzD,IAAM,EAAO,OAAO,GAAM,SAAW,EAAI,GACnC,EAAO,OAAO,GAAM,SAAW,EAAI,GACzC,GAAI,CAAC,GAAQ,CAAC,EAAM,MAAO,GAC3B,IAAM,EAAO,EAAO,EAAK,CACnB,EAAQ,EAAO,EAAK,CAI1B,MAHI,CAAC,GAAQ,CAAC,EACL,EAAK,QAAQ,OAAQ,GAAG,GAAK,EAAK,QAAQ,OAAQ,GAAG,CAG5D,EAAK,WAAa,EAAM,UACxB,EAAK,OAAS,EAAM,MACpB,EAAK,SAAS,QAAQ,OAAQ,GAAG,GAAK,EAAM,SAAS,QAAQ,OAAQ,GAAG,CAU5E,SAAgB,EACd,EACiC,CAKjC,OAHE,EAAM,kBAAkB,KACrB,GAAM,EAAE,KAAO,EAAM,0BACvB,EAAI,EAAM,kBAAkB,KAChB,UAYjB,SAAgB,EACd,EACiC,CAEjC,IAAM,EAAc,EAAM,kBAAkB,KACzC,GAAM,EAAE,WAAW,OAAS,QAC9B,CAID,OAHI,GAAa,UAAkB,EAAY,UAGxC,EAAmB,EAAM,CAuClC,SAAgB,EACd,EACA,EACS,CAGT,MAFI,CAAC,EAAM,qBAAuB,EAAM,sBAAwB,MACvD,GACF,EAAM,sBAAwB,EAGvC,SAAS,EAAU,EAAuB,CACxC,OAAO,EAAM,MAAM,CAAC,aAAa,CAQnC,SAAgB,EACd,EACoB,CACpB,OAAO,EACJ,KAAK,EAAO,KAAW,CAAE,QAAO,QAAO,EAAE,CACzC,MAAM,EAAG,KAEL,EAAE,MAAM,gBAAkB,IAAM,EAAE,MAAM,gBAAkB,IACtC,EAAE,MAAQ,EAAE,MACnC,CACD,KAAK,CAAE,WAAY,EAAM,CAU9B,SAAgB,EACd,EACA,EACS,CACT,IAAM,EAAI,EAAU,EAAS,CAU7B,OATK,EACY,CACf,EAAM,KACN,EAAM,YACN,EAAM,GACN,GAAI,EAAM,UAAY,EAAE,CACzB,CACE,KAAK,IAAI,CACT,aACI,CAAS,SAAS,EAAE,CATZ,GAmBjB,SAAgB,EACd,EACA,EACA,EACS,CACT,IAAM,EAAI,EAAU,EAAS,CAgB7B,OAfK,EACY,CACf,EAAO,KACP,SAAU,EAAS,EAAO,KAAO,IAAA,GACjC,YAAa,EAAS,EAAO,QAAU,IAAA,GACvC,SAAU,EAAS,EAAO,MAAM,KAAK,IAAI,CAAG,IAAA,GAC5C,QAAS,EAAS,EAAO,IAAM,IAAA,GAC/B,GAAc,KACd,GAAc,YACd,GAAc,GACd,GAAI,GAAc,UAAY,EAAE,CACjC,CACE,OAAO,QAAQ,CACf,KAAK,IAAI,CACT,aACI,CAAS,SAAS,EAAE,CAfZ,GA0BjB,SAAgB,EACd,EACA,EAC8B,CAC9B,OAAO,EAAQ,KAAM,GAAU,CAE7B,IAAK,IAAM,KAAU,EAAM,kBAAmB,CAC5C,IAAM,EAAM,EAAO,UACd,OACD,EAAI,OAAS,SACX,EAAO,OAAS,SAAW,EAAO,OAAS,EAAI,YASjD,EAAI,OAAS,SACX,EAAO,OAAS,SAAW,EAAU,EAAO,IAAK,EAAI,IAAI,EAG3D,EAAI,OAAS,OACX,EAAO,OAAS,OAAS,EAAU,EAAO,IAAK,EAAI,IAAI,EACzD,MAAO,GAGb,MAAO,IACP"}
@@ -1,5 +1,5 @@
1
1
  import { MCPServerConfig } from "#/types/mcp-server";
2
- import type { McpCatalogEntry as MarketplaceEntry, MarketplaceTemplate } from "@openhands/extensions/mcps";
2
+ import type { IntegrationCatalogEntry as MarketplaceEntry, IntegrationTransport as MarketplaceTemplate } from "@openhands/extensions/integrations";
3
3
  /**
4
4
  * Loose URL match that ignores query strings, trailing slashes, and
5
5
  * default ports. We want clicking "Linear" to flag the entry as
@@ -12,6 +12,23 @@ import type { McpCatalogEntry as MarketplaceEntry, MarketplaceTemplate } from "@
12
12
  * fallback below, never calling `.replace` on undefined.
13
13
  */
14
14
  export declare function urlsMatch(a: unknown, b: unknown): boolean;
15
+ /**
16
+ * Get the default transport template from an integration catalog entry.
17
+ * Integrations may have multiple connection options; we use the default
18
+ * one (or the first if no default is specified). Only MCP-backed options
19
+ * have a `transport` field.
20
+ */
21
+ export declare function getDefaultTemplate(entry: MarketplaceEntry): MarketplaceTemplate | undefined;
22
+ /**
23
+ * Get the stdio (API key-based) transport template from an integration entry.
24
+ * Many integrations have multiple connection options (e.g., OAuth + stdio).
25
+ * Since OAuth isn't implemented in the UI yet, the install modal should use
26
+ * this function to get the stdio-based option that can be configured with
27
+ * API keys/tokens.
28
+ *
29
+ * Falls back to getDefaultTemplate if no stdio option exists.
30
+ */
31
+ export declare function getInstallableTemplate(entry: MarketplaceEntry): MarketplaceTemplate | undefined;
15
32
  /**
16
33
  * Decide whether a marketplace template is already represented by one
17
34
  * of the installed MCP servers. Used to render an "Installed" badge on
@@ -39,5 +56,8 @@ export declare function installedServerMatchesQuery(server: MCPServerConfig, cat
39
56
  * Look up the catalog entry that best matches an installed server.
40
57
  * Mirrors the lookup used in `installed-server-card.tsx` for
41
58
  * rendering the friendly icon.
59
+ *
60
+ * Since an entry may have multiple connection options (e.g., OAuth + stdio),
61
+ * we check ALL templates in the entry's connectionOptions, not just the default.
42
62
  */
43
63
  export declare function findCatalogEntryForServer(server: MCPServerConfig, catalog: MarketplaceEntry[]): MarketplaceEntry | undefined;
@@ -12,20 +12,27 @@ function t(t, n) {
12
12
  let a = e(r), o = e(i);
13
13
  return !a || !o ? r.replace(/\/+$/, "") === i.replace(/\/+$/, "") : a.protocol === o.protocol && a.host === o.host && a.pathname.replace(/\/+$/, "") === o.pathname.replace(/\/+$/, "");
14
14
  }
15
- function n(e, t) {
16
- return !e.availability || e.availability === "all" ? !0 : e.availability === t;
15
+ function n(e) {
16
+ return (e.connectionOptions.find((t) => t.id === e.defaultConnectionOptionId) ?? e.connectionOptions[0])?.transport;
17
17
  }
18
18
  function r(e) {
19
+ let t = e.connectionOptions.find((e) => e.transport?.kind === "stdio");
20
+ return t?.transport ? t.transport : n(e);
21
+ }
22
+ function i(e, t) {
23
+ return !e.runtimeAvailability || e.runtimeAvailability === "all" ? !0 : e.runtimeAvailability === t;
24
+ }
25
+ function a(e) {
19
26
  return e.trim().toLowerCase();
20
27
  }
21
- function i(e) {
28
+ function o(e) {
22
29
  return e.map((e, t) => ({
23
30
  entry: e,
24
31
  index: t
25
32
  })).sort((e, t) => (t.entry.popularityRank ?? 0) - (e.entry.popularityRank ?? 0) || e.index - t.index).map(({ entry: e }) => e);
26
33
  }
27
- function a(e, t) {
28
- let n = r(t);
34
+ function s(e, t) {
35
+ let n = a(t);
29
36
  return n ? [
30
37
  e.name,
31
38
  e.description,
@@ -33,9 +40,9 @@ function a(e, t) {
33
40
  ...e.keywords ?? []
34
41
  ].join(" ").toLowerCase().includes(n) : !0;
35
42
  }
36
- function o(e, t, n) {
37
- let i = r(n);
38
- return i ? [
43
+ function c(e, t, n) {
44
+ let r = a(n);
45
+ return r ? [
39
46
  e.type,
40
47
  "name" in e ? e.name : void 0,
41
48
  "command" in e ? e.command : void 0,
@@ -45,15 +52,18 @@ function o(e, t, n) {
45
52
  t?.description,
46
53
  t?.id,
47
54
  ...t?.keywords ?? []
48
- ].filter(Boolean).join(" ").toLowerCase().includes(i) : !0;
55
+ ].filter(Boolean).join(" ").toLowerCase().includes(r) : !0;
49
56
  }
50
- function s(e, n) {
57
+ function l(e, n) {
51
58
  return n.find((n) => {
52
- let r = n.template;
53
- return r.kind === "stdio" ? e.type === "stdio" && e.name === r.serverName : r.kind === "shttp" ? e.type === "shttp" && t(e.url, r.url) : r.kind === "sse" ? e.type === "sse" && t(e.url, r.url) : !1;
59
+ for (let r of n.connectionOptions) {
60
+ let n = r.transport;
61
+ if (n && (n.kind === "stdio" && e.type === "stdio" && e.name === n.serverName || n.kind === "shttp" && e.type === "shttp" && t(e.url, n.url) || n.kind === "sse" && e.type === "sse" && t(e.url, n.url))) return !0;
62
+ }
63
+ return !1;
54
64
  });
55
65
  }
56
66
  //#endregion
57
- export { s as findCatalogEntryForServer, i as getMarketplaceEntriesByPopularity, o as installedServerMatchesQuery, n as isMarketplaceEntryAvailable, a as marketplaceEntryMatchesQuery };
67
+ export { l as findCatalogEntryForServer, n as getDefaultTemplate, r as getInstallableTemplate, o as getMarketplaceEntriesByPopularity, c as installedServerMatchesQuery, i as isMarketplaceEntryAvailable, s as marketplaceEntryMatchesQuery };
58
68
 
59
69
  //# sourceMappingURL=mcp-marketplace-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-marketplace-utils.js","names":[],"sources":["../../src/utils/mcp-marketplace-utils.ts"],"sourcesContent":["import { MCPServerConfig } from \"#/types/mcp-server\";\nimport type {\n McpCatalogEntry as MarketplaceEntry,\n MarketplaceTemplate,\n} from \"@openhands/extensions/mcps\";\n\nconst tryUrl = (raw: string): URL | null => {\n try {\n return new URL(raw);\n } catch {\n return null;\n }\n};\n\n/**\n * Loose URL match that ignores query strings, trailing slashes, and\n * default ports. We want clicking \"Linear\" to flag the entry as\n * installed even if the user pasted the URL with extra trailing slash\n * or a different port-equivalent variant.\n *\n * Defensive against runtime data that doesn't match the static type:\n * if either input is not a string (e.g. parsed from an older settings\n * blob), we fall through the URL parsing path and the safe trim\n * fallback below, never calling `.replace` on undefined.\n */\nexport function urlsMatch(a: unknown, b: unknown): boolean {\n const aStr = typeof a === \"string\" ? a : \"\";\n const bStr = typeof b === \"string\" ? b : \"\";\n if (!aStr || !bStr) return false;\n const left = tryUrl(aStr);\n const right = tryUrl(bStr);\n if (!left || !right) {\n return aStr.replace(/\\/+$/, \"\") === bStr.replace(/\\/+$/, \"\");\n }\n return (\n left.protocol === right.protocol &&\n left.host === right.host &&\n left.pathname.replace(/\\/+$/, \"\") === right.pathname.replace(/\\/+$/, \"\")\n );\n}\n\n/**\n * Decide whether a marketplace template is already represented by one\n * of the installed MCP servers. Used to render an \"Installed\" badge on\n * the marketplace tile. Returns the first matching server, or null.\n */\nexport function findInstalledMatch(\n template: MarketplaceTemplate,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n if (template.kind === \"shttp\") {\n const tplUrl = template.url;\n if (!tplUrl) return null;\n return (\n servers.find(\n (s) => s.type === \"shttp\" && !!s.url && urlsMatch(s.url, tplUrl),\n ) ?? null\n );\n }\n\n if (template.kind === \"sse\") {\n const tplUrl = template.url;\n if (!tplUrl) return null;\n return (\n servers.find(\n (s) => s.type === \"sse\" && !!s.url && urlsMatch(s.url, tplUrl),\n ) ?? null\n );\n }\n\n // stdio: match on the registered server name.\n return (\n servers.find((s) => s.type === \"stdio\" && s.name === template.serverName) ??\n null\n );\n}\n\nexport function isMarketplaceEntryAvailable(\n entry: MarketplaceEntry,\n backendKind: \"local\" | \"cloud\",\n): boolean {\n if (!entry.availability || entry.availability === \"all\") return true;\n return entry.availability === backendKind;\n}\n\nfunction normalize(query: string): string {\n return query.trim().toLowerCase();\n}\n\n/**\n * Case-insensitive substring match against the catalog entry's\n * user-visible identity (name, description, id, keywords). Empty\n * queries always match.\n */\nexport function getMarketplaceEntriesByPopularity(\n catalog: MarketplaceEntry[],\n): MarketplaceEntry[] {\n return catalog\n .map((entry, index) => ({ entry, index }))\n .sort((a, b) => {\n const byPopularity =\n (b.entry.popularityRank ?? 0) - (a.entry.popularityRank ?? 0);\n return byPopularity || a.index - b.index;\n })\n .map(({ entry }) => entry);\n}\n\nexport function getMarketplaceEntryById(\n id: string,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => entry.id === id);\n}\n\nexport function marketplaceEntryMatchesQuery(\n entry: MarketplaceEntry,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n entry.name,\n entry.description,\n entry.id,\n ...(entry.keywords ?? []),\n ]\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Search match for an installed (already-configured) server. We\n * search the server's own identifying fields and — if it's a catalog\n * entry — its catalog name/keywords too, so typing \"Slack\" matches\n * the installed Slack tile even though the persisted server is just\n * `{ type: \"stdio\", name: \"slack\", ... }`.\n */\nexport function installedServerMatchesQuery(\n server: MCPServerConfig,\n catalogEntry: MarketplaceEntry | undefined,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n server.type,\n \"name\" in server ? server.name : undefined,\n \"command\" in server ? server.command : undefined,\n \"args\" in server ? server.args?.join(\" \") : undefined,\n \"url\" in server ? server.url : undefined,\n catalogEntry?.name,\n catalogEntry?.description,\n catalogEntry?.id,\n ...(catalogEntry?.keywords ?? []),\n ]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Look up the catalog entry that best matches an installed server.\n * Mirrors the lookup used in `installed-server-card.tsx` for\n * rendering the friendly icon.\n */\nexport function findCatalogEntryForServer(\n server: MCPServerConfig,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => {\n const tpl = entry.template;\n if (tpl.kind === \"stdio\")\n return server.type === \"stdio\" && server.name === tpl.serverName;\n // Reuse the same loose URL match as `findInstalledMatch` so a\n // server whose URL was normalized by the backend (trailing slash\n // stripped, query string dropped, etc.) still gets paired with\n // its catalog tile — otherwise the installed-servers list would\n // render the generic icon while the marketplace shows the\n // entry as installed, which is confusing.\n if (tpl.kind === \"shttp\")\n return server.type === \"shttp\" && urlsMatch(server.url, tpl.url);\n if (tpl.kind === \"sse\")\n return server.type === \"sse\" && urlsMatch(server.url, tpl.url);\n return false;\n });\n}\n"],"mappings":";AAMA,IAAM,KAAU,MAA4B;AAC1C,KAAI;AACF,SAAO,IAAI,IAAI,EAAI;SACb;AACN,SAAO;;;AAeX,SAAgB,EAAU,GAAY,GAAqB;CACzD,IAAM,IAAO,OAAO,KAAM,WAAW,IAAI,IACnC,IAAO,OAAO,KAAM,WAAW,IAAI;AACzC,KAAI,CAAC,KAAQ,CAAC,EAAM,QAAO;CAC3B,IAAM,IAAO,EAAO,EAAK,EACnB,IAAQ,EAAO,EAAK;AAI1B,QAHI,CAAC,KAAQ,CAAC,IACL,EAAK,QAAQ,QAAQ,GAAG,KAAK,EAAK,QAAQ,QAAQ,GAAG,GAG5D,EAAK,aAAa,EAAM,YACxB,EAAK,SAAS,EAAM,QACpB,EAAK,SAAS,QAAQ,QAAQ,GAAG,KAAK,EAAM,SAAS,QAAQ,QAAQ,GAAG;;AAwC5E,SAAgB,EACd,GACA,GACS;AAET,QADI,CAAC,EAAM,gBAAgB,EAAM,iBAAiB,QAAc,KACzD,EAAM,iBAAiB;;AAGhC,SAAS,EAAU,GAAuB;AACxC,QAAO,EAAM,MAAM,CAAC,aAAa;;AAQnC,SAAgB,EACd,GACoB;AACpB,QAAO,EACJ,KAAK,GAAO,OAAW;EAAE;EAAO;EAAO,EAAE,CACzC,MAAM,GAAG,OAEL,EAAE,MAAM,kBAAkB,MAAM,EAAE,MAAM,kBAAkB,MACtC,EAAE,QAAQ,EAAE,MACnC,CACD,KAAK,EAAE,eAAY,EAAM;;AAU9B,SAAgB,EACd,GACA,GACS;CACT,IAAM,IAAI,EAAU,EAAS;AAU7B,QATK,IACY;EACf,EAAM;EACN,EAAM;EACN,EAAM;EACN,GAAI,EAAM,YAAY,EAAE;EACzB,CACE,KAAK,IAAI,CACT,aACI,CAAS,SAAS,EAAE,GATZ;;AAmBjB,SAAgB,EACd,GACA,GACA,GACS;CACT,IAAM,IAAI,EAAU,EAAS;AAgB7B,QAfK,IACY;EACf,EAAO;EACP,UAAU,IAAS,EAAO,OAAO,KAAA;EACjC,aAAa,IAAS,EAAO,UAAU,KAAA;EACvC,UAAU,IAAS,EAAO,MAAM,KAAK,IAAI,GAAG,KAAA;EAC5C,SAAS,IAAS,EAAO,MAAM,KAAA;EAC/B,GAAc;EACd,GAAc;EACd,GAAc;EACd,GAAI,GAAc,YAAY,EAAE;EACjC,CACE,OAAO,QAAQ,CACf,KAAK,IAAI,CACT,aACI,CAAS,SAAS,EAAE,GAfZ;;AAuBjB,SAAgB,EACd,GACA,GAC8B;AAC9B,QAAO,EAAQ,MAAM,MAAU;EAC7B,IAAM,IAAM,EAAM;AAalB,SAZI,EAAI,SAAS,UACR,EAAO,SAAS,WAAW,EAAO,SAAS,EAAI,aAOpD,EAAI,SAAS,UACR,EAAO,SAAS,WAAW,EAAU,EAAO,KAAK,EAAI,IAAI,GAC9D,EAAI,SAAS,QACR,EAAO,SAAS,SAAS,EAAU,EAAO,KAAK,EAAI,IAAI,GACzD;GACP"}
1
+ {"version":3,"file":"mcp-marketplace-utils.js","names":[],"sources":["../../src/utils/mcp-marketplace-utils.ts"],"sourcesContent":["import { MCPServerConfig } from \"#/types/mcp-server\";\nimport type {\n IntegrationCatalogEntry as MarketplaceEntry,\n IntegrationTransport as MarketplaceTemplate,\n} from \"@openhands/extensions/integrations\";\n\nconst tryUrl = (raw: string): URL | null => {\n try {\n return new URL(raw);\n } catch {\n return null;\n }\n};\n\n/**\n * Loose URL match that ignores query strings, trailing slashes, and\n * default ports. We want clicking \"Linear\" to flag the entry as\n * installed even if the user pasted the URL with extra trailing slash\n * or a different port-equivalent variant.\n *\n * Defensive against runtime data that doesn't match the static type:\n * if either input is not a string (e.g. parsed from an older settings\n * blob), we fall through the URL parsing path and the safe trim\n * fallback below, never calling `.replace` on undefined.\n */\nexport function urlsMatch(a: unknown, b: unknown): boolean {\n const aStr = typeof a === \"string\" ? a : \"\";\n const bStr = typeof b === \"string\" ? b : \"\";\n if (!aStr || !bStr) return false;\n const left = tryUrl(aStr);\n const right = tryUrl(bStr);\n if (!left || !right) {\n return aStr.replace(/\\/+$/, \"\") === bStr.replace(/\\/+$/, \"\");\n }\n return (\n left.protocol === right.protocol &&\n left.host === right.host &&\n left.pathname.replace(/\\/+$/, \"\") === right.pathname.replace(/\\/+$/, \"\")\n );\n}\n\n/**\n * Get the default transport template from an integration catalog entry.\n * Integrations may have multiple connection options; we use the default\n * one (or the first if no default is specified). Only MCP-backed options\n * have a `transport` field.\n */\nexport function getDefaultTemplate(\n entry: MarketplaceEntry,\n): MarketplaceTemplate | undefined {\n const option =\n entry.connectionOptions.find(\n (o) => o.id === entry.defaultConnectionOptionId,\n ) ?? entry.connectionOptions[0];\n return option?.transport;\n}\n\n/**\n * Get the stdio (API key-based) transport template from an integration entry.\n * Many integrations have multiple connection options (e.g., OAuth + stdio).\n * Since OAuth isn't implemented in the UI yet, the install modal should use\n * this function to get the stdio-based option that can be configured with\n * API keys/tokens.\n *\n * Falls back to getDefaultTemplate if no stdio option exists.\n */\nexport function getInstallableTemplate(\n entry: MarketplaceEntry,\n): MarketplaceTemplate | undefined {\n // First, try to find a stdio option (API key-based, what we can actually install)\n const stdioOption = entry.connectionOptions.find(\n (o) => o.transport?.kind === \"stdio\",\n );\n if (stdioOption?.transport) return stdioOption.transport;\n\n // Fall back to the default template (could be shttp/sse with api_key)\n return getDefaultTemplate(entry);\n}\n\n/**\n * Decide whether a marketplace template is already represented by one\n * of the installed MCP servers. Used to render an \"Installed\" badge on\n * the marketplace tile. Returns the first matching server, or null.\n */\nexport function findInstalledMatch(\n template: MarketplaceTemplate,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n if (template.kind === \"shttp\") {\n const tplUrl = template.url;\n if (!tplUrl) return null;\n return (\n servers.find(\n (s) => s.type === \"shttp\" && !!s.url && urlsMatch(s.url, tplUrl),\n ) ?? null\n );\n }\n\n if (template.kind === \"sse\") {\n const tplUrl = template.url;\n if (!tplUrl) return null;\n return (\n servers.find(\n (s) => s.type === \"sse\" && !!s.url && urlsMatch(s.url, tplUrl),\n ) ?? null\n );\n }\n\n // stdio: match on the registered server name.\n return (\n servers.find((s) => s.type === \"stdio\" && s.name === template.serverName) ??\n null\n );\n}\n\nexport function isMarketplaceEntryAvailable(\n entry: MarketplaceEntry,\n backendKind: \"local\" | \"cloud\",\n): boolean {\n if (!entry.runtimeAvailability || entry.runtimeAvailability === \"all\")\n return true;\n return entry.runtimeAvailability === backendKind;\n}\n\nfunction normalize(query: string): string {\n return query.trim().toLowerCase();\n}\n\n/**\n * Case-insensitive substring match against the catalog entry's\n * user-visible identity (name, description, id, keywords). Empty\n * queries always match.\n */\nexport function getMarketplaceEntriesByPopularity(\n catalog: MarketplaceEntry[],\n): MarketplaceEntry[] {\n return catalog\n .map((entry, index) => ({ entry, index }))\n .sort((a, b) => {\n const byPopularity =\n (b.entry.popularityRank ?? 0) - (a.entry.popularityRank ?? 0);\n return byPopularity || a.index - b.index;\n })\n .map(({ entry }) => entry);\n}\n\nexport function getMarketplaceEntryById(\n id: string,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => entry.id === id);\n}\n\nexport function marketplaceEntryMatchesQuery(\n entry: MarketplaceEntry,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n entry.name,\n entry.description,\n entry.id,\n ...(entry.keywords ?? []),\n ]\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Search match for an installed (already-configured) server. We\n * search the server's own identifying fields and — if it's a catalog\n * entry — its catalog name/keywords too, so typing \"Slack\" matches\n * the installed Slack tile even though the persisted server is just\n * `{ type: \"stdio\", name: \"slack\", ... }`.\n */\nexport function installedServerMatchesQuery(\n server: MCPServerConfig,\n catalogEntry: MarketplaceEntry | undefined,\n rawQuery: string,\n): boolean {\n const q = normalize(rawQuery);\n if (!q) return true;\n const haystack = [\n server.type,\n \"name\" in server ? server.name : undefined,\n \"command\" in server ? server.command : undefined,\n \"args\" in server ? server.args?.join(\" \") : undefined,\n \"url\" in server ? server.url : undefined,\n catalogEntry?.name,\n catalogEntry?.description,\n catalogEntry?.id,\n ...(catalogEntry?.keywords ?? []),\n ]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n return haystack.includes(q);\n}\n\n/**\n * Look up the catalog entry that best matches an installed server.\n * Mirrors the lookup used in `installed-server-card.tsx` for\n * rendering the friendly icon.\n *\n * Since an entry may have multiple connection options (e.g., OAuth + stdio),\n * we check ALL templates in the entry's connectionOptions, not just the default.\n */\nexport function findCatalogEntryForServer(\n server: MCPServerConfig,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => {\n // Check all connection options, not just the default\n for (const option of entry.connectionOptions) {\n const tpl = option.transport;\n if (!tpl) continue;\n if (tpl.kind === \"stdio\") {\n if (server.type === \"stdio\" && server.name === tpl.serverName)\n return true;\n }\n // Reuse the same loose URL match as `findInstalledMatch` so a\n // server whose URL was normalized by the backend (trailing slash\n // stripped, query string dropped, etc.) still gets paired with\n // its catalog tile — otherwise the installed-servers list would\n // render the generic icon while the marketplace shows the\n // entry as installed, which is confusing.\n if (tpl.kind === \"shttp\") {\n if (server.type === \"shttp\" && urlsMatch(server.url, tpl.url))\n return true;\n }\n if (tpl.kind === \"sse\") {\n if (server.type === \"sse\" && urlsMatch(server.url, tpl.url))\n return true;\n }\n }\n return false;\n });\n}\n"],"mappings":";AAMA,IAAM,KAAU,MAA4B;AAC1C,KAAI;AACF,SAAO,IAAI,IAAI,EAAI;SACb;AACN,SAAO;;;AAeX,SAAgB,EAAU,GAAY,GAAqB;CACzD,IAAM,IAAO,OAAO,KAAM,WAAW,IAAI,IACnC,IAAO,OAAO,KAAM,WAAW,IAAI;AACzC,KAAI,CAAC,KAAQ,CAAC,EAAM,QAAO;CAC3B,IAAM,IAAO,EAAO,EAAK,EACnB,IAAQ,EAAO,EAAK;AAI1B,QAHI,CAAC,KAAQ,CAAC,IACL,EAAK,QAAQ,QAAQ,GAAG,KAAK,EAAK,QAAQ,QAAQ,GAAG,GAG5D,EAAK,aAAa,EAAM,YACxB,EAAK,SAAS,EAAM,QACpB,EAAK,SAAS,QAAQ,QAAQ,GAAG,KAAK,EAAM,SAAS,QAAQ,QAAQ,GAAG;;AAU5E,SAAgB,EACd,GACiC;AAKjC,SAHE,EAAM,kBAAkB,MACrB,MAAM,EAAE,OAAO,EAAM,0BACvB,IAAI,EAAM,kBAAkB,KAChB;;AAYjB,SAAgB,EACd,GACiC;CAEjC,IAAM,IAAc,EAAM,kBAAkB,MACzC,MAAM,EAAE,WAAW,SAAS,QAC9B;AAID,QAHI,GAAa,YAAkB,EAAY,YAGxC,EAAmB,EAAM;;AAuClC,SAAgB,EACd,GACA,GACS;AAGT,QAFI,CAAC,EAAM,uBAAuB,EAAM,wBAAwB,QACvD,KACF,EAAM,wBAAwB;;AAGvC,SAAS,EAAU,GAAuB;AACxC,QAAO,EAAM,MAAM,CAAC,aAAa;;AAQnC,SAAgB,EACd,GACoB;AACpB,QAAO,EACJ,KAAK,GAAO,OAAW;EAAE;EAAO;EAAO,EAAE,CACzC,MAAM,GAAG,OAEL,EAAE,MAAM,kBAAkB,MAAM,EAAE,MAAM,kBAAkB,MACtC,EAAE,QAAQ,EAAE,MACnC,CACD,KAAK,EAAE,eAAY,EAAM;;AAU9B,SAAgB,EACd,GACA,GACS;CACT,IAAM,IAAI,EAAU,EAAS;AAU7B,QATK,IACY;EACf,EAAM;EACN,EAAM;EACN,EAAM;EACN,GAAI,EAAM,YAAY,EAAE;EACzB,CACE,KAAK,IAAI,CACT,aACI,CAAS,SAAS,EAAE,GATZ;;AAmBjB,SAAgB,EACd,GACA,GACA,GACS;CACT,IAAM,IAAI,EAAU,EAAS;AAgB7B,QAfK,IACY;EACf,EAAO;EACP,UAAU,IAAS,EAAO,OAAO,KAAA;EACjC,aAAa,IAAS,EAAO,UAAU,KAAA;EACvC,UAAU,IAAS,EAAO,MAAM,KAAK,IAAI,GAAG,KAAA;EAC5C,SAAS,IAAS,EAAO,MAAM,KAAA;EAC/B,GAAc;EACd,GAAc;EACd,GAAc;EACd,GAAI,GAAc,YAAY,EAAE;EACjC,CACE,OAAO,QAAQ,CACf,KAAK,IAAI,CACT,aACI,CAAS,SAAS,EAAE,GAfZ;;AA0BjB,SAAgB,EACd,GACA,GAC8B;AAC9B,QAAO,EAAQ,MAAM,MAAU;AAE7B,OAAK,IAAM,KAAU,EAAM,mBAAmB;GAC5C,IAAM,IAAM,EAAO;AACd,aACD,EAAI,SAAS,WACX,EAAO,SAAS,WAAW,EAAO,SAAS,EAAI,cASjD,EAAI,SAAS,WACX,EAAO,SAAS,WAAW,EAAU,EAAO,KAAK,EAAI,IAAI,IAG3D,EAAI,SAAS,SACX,EAAO,SAAS,SAAS,EAAU,EAAO,KAAK,EAAI,IAAI,EACzD,QAAO;;AAGb,SAAO;GACP"}
@@ -1 +1 @@
1
- {"version":3,"file":"settings-utils.cjs","names":[],"sources":["../../src/utils/settings-utils.ts"],"sourcesContent":["import { WebClientFeatureFlags } from \"#/api/option-service/option.types\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport { getProviderId } from \"#/utils/map-provider\";\n\nconst extractBasicFormData = (formData: FormData) => {\n const providerDisplay = formData.get(\"llm-provider-input\")?.toString();\n const provider = providerDisplay ? getProviderId(providerDisplay) : undefined;\n const model = formData.get(\"llm-model-input\")?.toString();\n\n return {\n llmModel: provider && model ? `${provider}/${model}` : undefined,\n llmApiKey: formData.get(\"llm-api-key-input\")?.toString(),\n agent: formData.get(\"agent\")?.toString(),\n language: formData.get(\"language\")?.toString(),\n };\n};\n\nexport const parseMaxBudgetPerTask = (value: string): number | null => {\n if (!value) {\n return null;\n }\n\n const parsedValue = parseFloat(value);\n return parsedValue && parsedValue >= 1 && Number.isFinite(parsedValue)\n ? parsedValue\n : null;\n};\n\nexport const extractSettings = (\n formData: FormData,\n): Partial<Settings> & Record<string, unknown> => {\n const { llmModel, llmApiKey, agent, language } =\n extractBasicFormData(formData);\n\n const llm: Record<string, unknown> = {};\n if (llmModel) llm.model = llmModel;\n if (llmApiKey !== undefined) llm.api_key = llmApiKey;\n\n const agentSettings: Record<string, SettingsValue> = {};\n if (Object.keys(llm).length > 0)\n agentSettings.llm = llm as Record<string, SettingsValue>;\n if (agent) agentSettings.agent = agent;\n\n return {\n ...(Object.keys(agentSettings).length > 0\n ? { agent_settings_diff: agentSettings }\n : {}),\n ...(language ? { language } : {}),\n };\n};\n\nexport function isSettingsPageHidden(\n path: string,\n featureFlags: WebClientFeatureFlags | undefined,\n): boolean {\n if (featureFlags?.hide_llm_settings && path === \"/settings/llm\") return true;\n return false;\n}\n\nexport function getFirstAvailablePath(\n featureFlags: WebClientFeatureFlags | undefined,\n): string | null {\n // ``/settings/agent`` precedes ``/settings`` because it is the ACP\n // landing page and is always available (no feature flag hides it).\n // When ``hide_llm_settings`` is on, the user is steered there rather\n // than to ``/settings/app`` (an unrelated section that used to win the\n // fallback). For OpenHands-agent users this is also a sensible landing\n // the Agent page is the single place to switch kinds.\n const fallbackOrder = [\n { path: \"/settings/llm\", hidden: !!featureFlags?.hide_llm_settings },\n { path: \"/settings/agent\", hidden: false },\n { path: \"/settings\", hidden: !!featureFlags?.hide_llm_settings },\n { path: \"/settings/app\", hidden: false },\n { path: \"/settings/secrets\", hidden: false },\n ];\n\n const firstAvailable = fallbackOrder.find((item) => !item.hidden);\n return firstAvailable?.path ?? null;\n}\n"],"mappings":"mFAIA,IAAM,EAAwB,GAAuB,CACnD,IAAM,EAAkB,EAAS,IAAI,qBAAqB,EAAE,UAAU,CAChE,EAAW,EAAkB,EAAA,cAAc,EAAgB,CAAG,IAAA,GAC9D,EAAQ,EAAS,IAAI,kBAAkB,EAAE,UAAU,CAEzD,MAAO,CACL,SAAU,GAAY,EAAQ,GAAG,EAAS,GAAG,IAAU,IAAA,GACvD,UAAW,EAAS,IAAI,oBAAoB,EAAE,UAAU,CACxD,MAAO,EAAS,IAAI,QAAQ,EAAE,UAAU,CACxC,SAAU,EAAS,IAAI,WAAW,EAAE,UAAU,CAC/C,EAcU,EACX,GACgD,CAChD,GAAM,CAAE,WAAU,YAAW,QAAO,YAClC,EAAqB,EAAS,CAE1B,EAA+B,EAAE,CACnC,IAAU,EAAI,MAAQ,GACtB,IAAc,IAAA,KAAW,EAAI,QAAU,GAE3C,IAAM,EAA+C,EAAE,CAKvD,OAJI,OAAO,KAAK,EAAI,CAAC,OAAS,IAC5B,EAAc,IAAM,GAClB,IAAO,EAAc,MAAQ,GAE1B,CACL,GAAI,OAAO,KAAK,EAAc,CAAC,OAAS,EACpC,CAAE,oBAAqB,EAAe,CACtC,EAAE,CACN,GAAI,EAAW,CAAE,WAAU,CAAG,EAAE,CACjC"}
1
+ {"version":3,"file":"settings-utils.cjs","names":[],"sources":["../../src/utils/settings-utils.ts"],"sourcesContent":["import { WebClientFeatureFlags } from \"#/api/option-service/option.types\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport { getProviderId } from \"#/utils/map-provider\";\n\nconst extractBasicFormData = (formData: FormData) => {\n const providerDisplay = formData.get(\"llm-provider-input\")?.toString();\n const provider = providerDisplay ? getProviderId(providerDisplay) : undefined;\n const model = formData.get(\"llm-model-input\")?.toString();\n\n return {\n llmModel: provider && model ? `${provider}/${model}` : undefined,\n llmApiKey: formData.get(\"llm-api-key-input\")?.toString(),\n agent: formData.get(\"agent\")?.toString(),\n language: formData.get(\"language\")?.toString(),\n };\n};\n\nexport const parseMaxBudgetPerTask = (value: string): number | null => {\n if (!value) {\n return null;\n }\n\n const parsedValue = parseFloat(value);\n return parsedValue && parsedValue >= 1 && Number.isFinite(parsedValue)\n ? parsedValue\n : null;\n};\n\nexport const extractSettings = (\n formData: FormData,\n): Partial<Settings> & Record<string, unknown> => {\n const { llmModel, llmApiKey, agent, language } =\n extractBasicFormData(formData);\n\n const llm: Record<string, unknown> = {};\n if (llmModel) llm.model = llmModel;\n if (llmApiKey !== undefined) llm.api_key = llmApiKey;\n\n const agentSettings: Record<string, SettingsValue> = {};\n if (Object.keys(llm).length > 0)\n agentSettings.llm = llm as Record<string, SettingsValue>;\n if (agent) agentSettings.agent = agent;\n\n return {\n ...(Object.keys(agentSettings).length > 0\n ? { agent_settings_diff: agentSettings }\n : {}),\n ...(language ? { language } : {}),\n };\n};\n\nexport function isSettingsPageHidden(\n path: string,\n featureFlags: WebClientFeatureFlags | undefined,\n): boolean {\n if (featureFlags?.hide_llm_settings && path === \"/settings/llm\") return true;\n return false;\n}\n\nexport function getFirstAvailablePath(\n featureFlags: WebClientFeatureFlags | undefined,\n): string | null {\n // ``/settings/agent`` always wins: it is the single place to switch\n // agent kinds (OpenHands / ACP) and the only sub-page that is always\n // available regardless of feature flags. Landing here keeps the\n // routing simple ACP users no longer have to bounce through\n // ``/settings/llm`` (which is disabled for them), and OpenHands users\n // are one nav-click away from the LLM page.\n const fallbackOrder = [\n { path: \"/settings/agent\", hidden: false },\n { path: \"/settings/llm\", hidden: !!featureFlags?.hide_llm_settings },\n { path: \"/settings\", hidden: !!featureFlags?.hide_llm_settings },\n { path: \"/settings/app\", hidden: false },\n { path: \"/settings/secrets\", hidden: false },\n ];\n\n const firstAvailable = fallbackOrder.find((item) => !item.hidden);\n return firstAvailable?.path ?? null;\n}\n"],"mappings":"mFAIA,IAAM,EAAwB,GAAuB,CACnD,IAAM,EAAkB,EAAS,IAAI,qBAAqB,EAAE,UAAU,CAChE,EAAW,EAAkB,EAAA,cAAc,EAAgB,CAAG,IAAA,GAC9D,EAAQ,EAAS,IAAI,kBAAkB,EAAE,UAAU,CAEzD,MAAO,CACL,SAAU,GAAY,EAAQ,GAAG,EAAS,GAAG,IAAU,IAAA,GACvD,UAAW,EAAS,IAAI,oBAAoB,EAAE,UAAU,CACxD,MAAO,EAAS,IAAI,QAAQ,EAAE,UAAU,CACxC,SAAU,EAAS,IAAI,WAAW,EAAE,UAAU,CAC/C,EAcU,EACX,GACgD,CAChD,GAAM,CAAE,WAAU,YAAW,QAAO,YAClC,EAAqB,EAAS,CAE1B,EAA+B,EAAE,CACnC,IAAU,EAAI,MAAQ,GACtB,IAAc,IAAA,KAAW,EAAI,QAAU,GAE3C,IAAM,EAA+C,EAAE,CAKvD,OAJI,OAAO,KAAK,EAAI,CAAC,OAAS,IAC5B,EAAc,IAAM,GAClB,IAAO,EAAc,MAAQ,GAE1B,CACL,GAAI,OAAO,KAAK,EAAc,CAAC,OAAS,EACpC,CAAE,oBAAqB,EAAe,CACtC,EAAE,CACN,GAAI,EAAW,CAAE,WAAU,CAAG,EAAE,CACjC"}
@@ -1 +1 @@
1
- {"version":3,"file":"settings-utils.js","names":[],"sources":["../../src/utils/settings-utils.ts"],"sourcesContent":["import { WebClientFeatureFlags } from \"#/api/option-service/option.types\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport { getProviderId } from \"#/utils/map-provider\";\n\nconst extractBasicFormData = (formData: FormData) => {\n const providerDisplay = formData.get(\"llm-provider-input\")?.toString();\n const provider = providerDisplay ? getProviderId(providerDisplay) : undefined;\n const model = formData.get(\"llm-model-input\")?.toString();\n\n return {\n llmModel: provider && model ? `${provider}/${model}` : undefined,\n llmApiKey: formData.get(\"llm-api-key-input\")?.toString(),\n agent: formData.get(\"agent\")?.toString(),\n language: formData.get(\"language\")?.toString(),\n };\n};\n\nexport const parseMaxBudgetPerTask = (value: string): number | null => {\n if (!value) {\n return null;\n }\n\n const parsedValue = parseFloat(value);\n return parsedValue && parsedValue >= 1 && Number.isFinite(parsedValue)\n ? parsedValue\n : null;\n};\n\nexport const extractSettings = (\n formData: FormData,\n): Partial<Settings> & Record<string, unknown> => {\n const { llmModel, llmApiKey, agent, language } =\n extractBasicFormData(formData);\n\n const llm: Record<string, unknown> = {};\n if (llmModel) llm.model = llmModel;\n if (llmApiKey !== undefined) llm.api_key = llmApiKey;\n\n const agentSettings: Record<string, SettingsValue> = {};\n if (Object.keys(llm).length > 0)\n agentSettings.llm = llm as Record<string, SettingsValue>;\n if (agent) agentSettings.agent = agent;\n\n return {\n ...(Object.keys(agentSettings).length > 0\n ? { agent_settings_diff: agentSettings }\n : {}),\n ...(language ? { language } : {}),\n };\n};\n\nexport function isSettingsPageHidden(\n path: string,\n featureFlags: WebClientFeatureFlags | undefined,\n): boolean {\n if (featureFlags?.hide_llm_settings && path === \"/settings/llm\") return true;\n return false;\n}\n\nexport function getFirstAvailablePath(\n featureFlags: WebClientFeatureFlags | undefined,\n): string | null {\n // ``/settings/agent`` precedes ``/settings`` because it is the ACP\n // landing page and is always available (no feature flag hides it).\n // When ``hide_llm_settings`` is on, the user is steered there rather\n // than to ``/settings/app`` (an unrelated section that used to win the\n // fallback). For OpenHands-agent users this is also a sensible landing\n // the Agent page is the single place to switch kinds.\n const fallbackOrder = [\n { path: \"/settings/llm\", hidden: !!featureFlags?.hide_llm_settings },\n { path: \"/settings/agent\", hidden: false },\n { path: \"/settings\", hidden: !!featureFlags?.hide_llm_settings },\n { path: \"/settings/app\", hidden: false },\n { path: \"/settings/secrets\", hidden: false },\n ];\n\n const firstAvailable = fallbackOrder.find((item) => !item.hidden);\n return firstAvailable?.path ?? null;\n}\n"],"mappings":";;AAIA,IAAM,KAAwB,MAAuB;CACnD,IAAM,IAAkB,EAAS,IAAI,qBAAqB,EAAE,UAAU,EAChE,IAAW,IAAkB,EAAc,EAAgB,GAAG,KAAA,GAC9D,IAAQ,EAAS,IAAI,kBAAkB,EAAE,UAAU;AAEzD,QAAO;EACL,UAAU,KAAY,IAAQ,GAAG,EAAS,GAAG,MAAU,KAAA;EACvD,WAAW,EAAS,IAAI,oBAAoB,EAAE,UAAU;EACxD,OAAO,EAAS,IAAI,QAAQ,EAAE,UAAU;EACxC,UAAU,EAAS,IAAI,WAAW,EAAE,UAAU;EAC/C;GAcU,KACX,MACgD;CAChD,IAAM,EAAE,aAAU,cAAW,UAAO,gBAClC,EAAqB,EAAS,EAE1B,IAA+B,EAAE;AAEvC,CADI,MAAU,EAAI,QAAQ,IACtB,MAAc,KAAA,MAAW,EAAI,UAAU;CAE3C,IAAM,IAA+C,EAAE;AAKvD,QAJI,OAAO,KAAK,EAAI,CAAC,SAAS,MAC5B,EAAc,MAAM,IAClB,MAAO,EAAc,QAAQ,IAE1B;EACL,GAAI,OAAO,KAAK,EAAc,CAAC,SAAS,IACpC,EAAE,qBAAqB,GAAe,GACtC,EAAE;EACN,GAAI,IAAW,EAAE,aAAU,GAAG,EAAE;EACjC"}
1
+ {"version":3,"file":"settings-utils.js","names":[],"sources":["../../src/utils/settings-utils.ts"],"sourcesContent":["import { WebClientFeatureFlags } from \"#/api/option-service/option.types\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport { getProviderId } from \"#/utils/map-provider\";\n\nconst extractBasicFormData = (formData: FormData) => {\n const providerDisplay = formData.get(\"llm-provider-input\")?.toString();\n const provider = providerDisplay ? getProviderId(providerDisplay) : undefined;\n const model = formData.get(\"llm-model-input\")?.toString();\n\n return {\n llmModel: provider && model ? `${provider}/${model}` : undefined,\n llmApiKey: formData.get(\"llm-api-key-input\")?.toString(),\n agent: formData.get(\"agent\")?.toString(),\n language: formData.get(\"language\")?.toString(),\n };\n};\n\nexport const parseMaxBudgetPerTask = (value: string): number | null => {\n if (!value) {\n return null;\n }\n\n const parsedValue = parseFloat(value);\n return parsedValue && parsedValue >= 1 && Number.isFinite(parsedValue)\n ? parsedValue\n : null;\n};\n\nexport const extractSettings = (\n formData: FormData,\n): Partial<Settings> & Record<string, unknown> => {\n const { llmModel, llmApiKey, agent, language } =\n extractBasicFormData(formData);\n\n const llm: Record<string, unknown> = {};\n if (llmModel) llm.model = llmModel;\n if (llmApiKey !== undefined) llm.api_key = llmApiKey;\n\n const agentSettings: Record<string, SettingsValue> = {};\n if (Object.keys(llm).length > 0)\n agentSettings.llm = llm as Record<string, SettingsValue>;\n if (agent) agentSettings.agent = agent;\n\n return {\n ...(Object.keys(agentSettings).length > 0\n ? { agent_settings_diff: agentSettings }\n : {}),\n ...(language ? { language } : {}),\n };\n};\n\nexport function isSettingsPageHidden(\n path: string,\n featureFlags: WebClientFeatureFlags | undefined,\n): boolean {\n if (featureFlags?.hide_llm_settings && path === \"/settings/llm\") return true;\n return false;\n}\n\nexport function getFirstAvailablePath(\n featureFlags: WebClientFeatureFlags | undefined,\n): string | null {\n // ``/settings/agent`` always wins: it is the single place to switch\n // agent kinds (OpenHands / ACP) and the only sub-page that is always\n // available regardless of feature flags. Landing here keeps the\n // routing simple ACP users no longer have to bounce through\n // ``/settings/llm`` (which is disabled for them), and OpenHands users\n // are one nav-click away from the LLM page.\n const fallbackOrder = [\n { path: \"/settings/agent\", hidden: false },\n { path: \"/settings/llm\", hidden: !!featureFlags?.hide_llm_settings },\n { path: \"/settings\", hidden: !!featureFlags?.hide_llm_settings },\n { path: \"/settings/app\", hidden: false },\n { path: \"/settings/secrets\", hidden: false },\n ];\n\n const firstAvailable = fallbackOrder.find((item) => !item.hidden);\n return firstAvailable?.path ?? null;\n}\n"],"mappings":";;AAIA,IAAM,KAAwB,MAAuB;CACnD,IAAM,IAAkB,EAAS,IAAI,qBAAqB,EAAE,UAAU,EAChE,IAAW,IAAkB,EAAc,EAAgB,GAAG,KAAA,GAC9D,IAAQ,EAAS,IAAI,kBAAkB,EAAE,UAAU;AAEzD,QAAO;EACL,UAAU,KAAY,IAAQ,GAAG,EAAS,GAAG,MAAU,KAAA;EACvD,WAAW,EAAS,IAAI,oBAAoB,EAAE,UAAU;EACxD,OAAO,EAAS,IAAI,QAAQ,EAAE,UAAU;EACxC,UAAU,EAAS,IAAI,WAAW,EAAE,UAAU;EAC/C;GAcU,KACX,MACgD;CAChD,IAAM,EAAE,aAAU,cAAW,UAAO,gBAClC,EAAqB,EAAS,EAE1B,IAA+B,EAAE;AAEvC,CADI,MAAU,EAAI,QAAQ,IACtB,MAAc,KAAA,MAAW,EAAI,UAAU;CAE3C,IAAM,IAA+C,EAAE;AAKvD,QAJI,OAAO,KAAK,EAAI,CAAC,SAAS,MAC5B,EAAc,MAAM,IAClB,MAAO,EAAc,QAAQ,IAE1B;EACL,GAAI,OAAO,KAAK,EAAc,CAAC,SAAS,IACpC,EAAE,qBAAqB,GAAe,GACtC,EAAE;EACN,GAAI,IAAW,EAAE,aAAU,GAAG,EAAE;EACjC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openhands/agent-canvas",
3
- "version": "1.0.0-alpha.7",
3
+ "version": "1.0.0-alpha.8",
4
4
  "description": "Agent Canvas UI for OpenHands - run AI coding agents with a visual interface",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -23,8 +23,8 @@
23
23
  "@heroui/react": "2.8.10",
24
24
  "@microlink/react-json-view": "1.31.20",
25
25
  "@monaco-editor/react": "4.7.0",
26
- "@openhands/extensions": "git+https://github.com/OpenHands/extensions.git#b8c1869ec9dea4467bb27d5754dc695d14e27889",
27
- "@openhands/typescript-client": "1.23.3",
26
+ "@openhands/extensions": "git+https://github.com/OpenHands/extensions.git#39711065f53166c52608462f60a4c8507253ce56",
27
+ "@openhands/typescript-client": "1.24.0",
28
28
  "@react-router/node": "7.14.2",
29
29
  "@react-router/serve": "7.14.2",
30
30
  "@tailwindcss/vite": "4.2.4",
@@ -80,6 +80,7 @@
80
80
  "test": "npm run make-i18n && vitest run",
81
81
  "test:e2e": "playwright test --pass-with-no-tests",
82
82
  "test:e2e:live": "node --env-file-if-exists=.env tests/e2e/live/scripts/run-live-e2e.mjs",
83
+ "test:e2e:mock-llm": "playwright test --config=playwright.mock-llm.config.ts",
83
84
  "test:e2e:snapshots": "playwright test tests/e2e/snapshots --project=chromium --retries=0",
84
85
  "test:e2e:snapshots:update": "playwright test tests/e2e/snapshots --project=chromium --update-snapshots",
85
86
  "test:coverage": "npm run make-i18n && vitest run --coverage",
@@ -173,7 +174,8 @@
173
174
  "bin",
174
175
  "build",
175
176
  "config",
176
- "scripts"
177
+ "scripts",
178
+ "tools"
177
179
  ],
178
180
  "exports": {
179
181
  ".": {
@@ -19,7 +19,7 @@
19
19
  *
20
20
  * Usage:
21
21
  * node scripts/check-sdk-version-sync.mjs
22
- * EXPECTED_SDK_VERSION=1.23.1 node scripts/check-sdk-version-sync.mjs
22
+ * EXPECTED_SDK_VERSION=1.24.0 node scripts/check-sdk-version-sync.mjs
23
23
  * node scripts/check-sdk-version-sync.mjs --check-pypi
24
24
  *
25
25
  * Environment variables:
@@ -79,7 +79,7 @@ Triggering from other repos:
79
79
  -H "Authorization: token \$GITHUB_TOKEN" \\
80
80
  -H "Accept: application/vnd.github.v3+json" \\
81
81
  https://api.github.com/repos/OpenHands/agent-canvas/dispatches \\
82
- -d '{"event_type": "sdk-version-check", "client_payload": {"version": "1.23.1"}}'
82
+ -d '{"event_type": "sdk-version-check", "client_payload": {"version": "1.24.0"}}'
83
83
  `);
84
84
  process.exit(0);
85
85
  }
@@ -268,9 +268,9 @@ async function fetchPyPIDependencies(packageName, version) {
268
268
  * Parse PyPI requires_dist array and extract SDK package versions
269
269
  *
270
270
  * PyPI returns dependencies in PEP 508 format like:
271
- * "openhands-sdk>=1.23.1,<2.0.0"
272
- * "openhands-tools==1.23.1"
273
- * "openhands-workspace (>=1.23.1)"
271
+ * "openhands-sdk>=1.24.0,<2.0.0"
272
+ * "openhands-tools==1.24.0"
273
+ * "openhands-workspace (>=1.24.0)"
274
274
  */
275
275
  function parseSdkVersionsFromRequiresDist(requiresDist) {
276
276
  const versions = {};
@@ -284,7 +284,7 @@ function parseSdkVersionsFromRequiresDist(requiresDist) {
284
284
  }
285
285
 
286
286
  // Extract the version number - look for patterns like:
287
- // ">=1.23.1", "==1.23.1", "(>=1.23.1)", "~=1.23.1"
287
+ // ">=1.24.0", "==1.24.0", "(>=1.24.0)", "~=1.24.0"
288
288
  // After the package name and before any comma or closing paren
289
289
  const versionPattern = /[><=~!]+\s*([0-9]+(?:\.[0-9]+)*)/;
290
290
  const match = dep.match(versionPattern);