@openhands/agent-canvas 1.0.0-rc.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (600) hide show
  1. package/README.md +46 -31
  2. package/README.windows.md +2 -2
  3. package/bin/agent-canvas.mjs +3 -1
  4. package/build/assets/Trans-CBypf0vt.js +1 -0
  5. package/build/assets/{acp-providers-BqUvf67Q.js → acp-providers-BMyF5WII.js} +1 -1
  6. package/build/assets/active-backend-context-Cy_Ui5d7.js +1 -0
  7. package/build/assets/add-backend-modal-CUw7x0zm.js +1 -0
  8. package/build/assets/agent-server-client-options-FoO1qgAQ.js +1 -0
  9. package/build/assets/agent-server-conversation-service.api-D6Cmbnhd.js +5 -0
  10. package/build/assets/{agent-settings-DoHXHcoA.js → agent-settings-DW4vwOaz.js} +2 -2
  11. package/build/assets/{alert-banner-Bsvys-hT.js → alert-banner-BHmoArV2.js} +1 -1
  12. package/build/assets/{analytics-consent-form-modal-CVhsAREx.js → analytics-consent-form-modal-BNK0yu4L.js} +1 -1
  13. package/build/assets/api-key-entry-screen-BjVajIjf.js +1 -0
  14. package/build/assets/app-settings-C-5X6RzZ.js +1 -0
  15. package/build/assets/automation-detail-uDMoYmAc.js +1 -0
  16. package/build/assets/automations-list-DBCKCbId.js +1 -0
  17. package/build/assets/{back-nav-button-D20Avel_.js → back-nav-button-Bckz5Wh6.js} +1 -1
  18. package/build/assets/backend-form-modal-D2-XqJA4.js +1 -0
  19. package/build/assets/{backend-synced-settings-badge-Dcd4712m.js → backend-synced-settings-badge-Dx16CR_k.js} +1 -1
  20. package/build/assets/{base-modal-DvuGYyu1.js → base-modal-7QRNzf6r.js} +1 -1
  21. package/build/assets/{brand-button-9SOzmqPP.js → brand-button-CKLvirxz.js} +1 -1
  22. package/build/assets/browser-D1ZybR7v.js +5 -0
  23. package/build/assets/browser-store-hzasvz9c.js +1 -0
  24. package/build/assets/{browser-tab-bveyJhG9.js → browser-tab-iOQjXzmI.js} +1 -1
  25. package/build/assets/chat-send-button-_Uc9iFpG.js +1 -0
  26. package/build/assets/check-DfvhVBub.js +1 -0
  27. package/build/assets/{checkmark--JWAesua.js → checkmark-BHPhb50L.js} +1 -1
  28. package/build/assets/{chevron-down-B9j6lcFg.js → chevron-down-CMkqyPEY.js} +1 -1
  29. package/build/assets/{circle-plus-check-toggle-AO9DWyDX.js → circle-plus-check-toggle-ChmnRlpR.js} +1 -1
  30. package/build/assets/{close--W-tHn1h.js → close-DBs90sI6.js} +1 -1
  31. package/build/assets/{code-tag-chmctf4w.js → code-tag-BtHOqHwB.js} +1 -1
  32. package/build/assets/{color-themes-0biOprdo.js → color-themes-CBikRn3w.js} +1 -1
  33. package/build/assets/{combobox-caret-C9BNHfSu.js → combobox-caret-evUAh6YW.js} +1 -1
  34. package/build/assets/{command-store-UzKGSUC2.js → command-store-DZfR8QtE.js} +1 -1
  35. package/build/assets/condenser-settings-0tw3yXX8.js +1 -0
  36. package/build/assets/{confirmation-modal-Cq3eqvqH.js → confirmation-modal-DWuxe1zG.js} +1 -1
  37. package/build/assets/{context-menu-list-item-BQU0jZPq.js → context-menu-list-item-BbHFxHaq.js} +1 -1
  38. package/build/assets/conversation-B1v96pQf.js +19 -0
  39. package/build/assets/conversation-DgfcjCPm.js +1 -0
  40. package/build/assets/{conversation-local-storage-an3MiIiJ.js → conversation-local-storage-Btum2xBJ.js} +1 -1
  41. package/build/assets/conversation-panel-TJ7swm6a.js +1 -0
  42. package/build/assets/conversation-service.api-DXawvmNN.js +1 -0
  43. package/build/assets/conversation-state-store-DmuPn875.js +1 -0
  44. package/build/assets/{conversation-store-FQmakEd-.js → conversation-store-Bu89Yxg1.js} +1 -1
  45. package/build/assets/{conversation-tab-empty-state-C8tztloo.js → conversation-tab-empty-state-7js7FjYM.js} +1 -1
  46. package/build/assets/{copy-CdKN5rtJ.js → copy-B0SkXenR.js} +1 -1
  47. package/build/assets/copy-to-clipboard-button-CfH2EQz9.js +1 -0
  48. package/build/assets/{createLucideIcon-CkGTf9Qj.js → createLucideIcon-Bazr-V-B.js} +1 -1
  49. package/build/assets/declaration-Cn-NXHEy.js +1 -0
  50. package/build/assets/{device-verify-YuGXnpRk.js → device-verify-CWKyQ680.js} +1 -1
  51. package/build/assets/{dist-5dObF4p4.js → dist-Cbu6eGx8.js} +1 -1
  52. package/build/assets/dist-Dg2JWLGc.js +1 -0
  53. package/build/assets/{dropdown-classes-CVp0kVdt.js → dropdown-classes-BI1bI1ho.js} +1 -1
  54. package/build/assets/edit-automation-modal-DdAG6kFZ.js +1 -0
  55. package/build/assets/{ellipsis-button-k7HLwYth.js → ellipsis-button-DdCsOBHV.js} +1 -1
  56. package/build/assets/entry.client-DXyvKj5G.js +2 -0
  57. package/build/assets/{enum-filter-dropdown-COqUq3mB.js → enum-filter-dropdown-WROAIeys.js} +1 -1
  58. package/build/assets/{environment-switch-overlay-wB5LxfYZ.js → environment-switch-overlay-Dv0imPE6.js} +1 -1
  59. package/build/assets/{extensions-hub-CoWO3SzQ.js → extensions-hub-CkyDPXvn.js} +1 -1
  60. package/build/assets/{extensions-navigation-D5w2sFQe.js → extensions-navigation-gMR-la1J.js} +1 -1
  61. package/build/assets/{external-link-BATfjnkz.js → external-link-FsutnU75.js} +1 -1
  62. package/build/assets/files-tab-DNUoveJZ.js +1 -0
  63. package/build/assets/files-tab-store-SyvkH3ic.js +1 -0
  64. package/build/assets/{folder-DPTBlxWb.js → folder-DusyBXDE.js} +1 -1
  65. package/build/assets/{globe-Dpgjreyy.js → globe-BUcin4kT.js} +1 -1
  66. package/build/assets/home-D809jWVS.js +1 -0
  67. package/build/assets/{iconBase-BVhFI-0E.js → iconBase-B6CXDDaE.js} +1 -1
  68. package/build/assets/index-redirect-nMYgOTBX.js +1 -0
  69. package/build/assets/install-server-modal-D92Qy57I.js +1 -0
  70. package/build/assets/{launch-fU77utLO.js → launch-BnCG2g2a.js} +1 -1
  71. package/build/assets/lesson-plan-j-ZaE8vK.js +3 -0
  72. package/build/assets/{lightbulb-S616sGEL.js → lightbulb-BJ5tWmAh.js} +1 -1
  73. package/build/assets/{link-external-ooNztGLp.js → link-external-DUtmHAHi.js} +1 -1
  74. package/build/assets/{list-todo-nCa9zxVE.js → list-todo-C-gekh-4.js} +1 -1
  75. package/build/assets/{llm-client-P9f2gKeW.js → llm-client-BZUkZYlc.js} +1 -1
  76. package/build/assets/llm-not-configured-banner-PlvJ99rE.js +27 -0
  77. package/build/assets/llm-settings-Dgk32xRW.js +1 -0
  78. package/build/assets/llm-settings-Dxo7owKm.js +1 -0
  79. package/build/assets/llm-subscription-Bvu8BLXc.js +1 -0
  80. package/build/assets/llm-subscription-service-Bq6z3Wkv.js +1 -0
  81. package/build/assets/loader-circle-Cw7_q9hg.js +1 -0
  82. package/build/assets/{loading-spinner-D7bOU6I7.js → loading-spinner-RF3IlMF5.js} +1 -1
  83. package/build/assets/manage-backends-modal-BT66a6e0.js +1 -0
  84. package/build/assets/manifest-b8402d59.js +1 -0
  85. package/build/assets/markdown-renderer-Tw6FR2ad.js +2 -0
  86. package/build/assets/mcp-B_pA7vZg.js +9 -0
  87. package/build/assets/mcp-client-ppbYplKX.js +1 -0
  88. package/build/assets/messages-Cg9aNVi6.js +41 -0
  89. package/build/assets/{modal-backdrop-_VbcKk5K.js → modal-backdrop-DRpBVVW5.js} +1 -1
  90. package/build/assets/{modal-body-Cd-PtMHr.js → modal-body-CEV2O67p.js} +1 -1
  91. package/build/assets/{modal-classes-CNm4ovfm.js → modal-classes-B2DuQ9qD.js} +1 -1
  92. package/build/assets/{modal-close-button-Dbo0NAMt.js → modal-close-button-gtb7RHFB.js} +1 -1
  93. package/build/assets/model-selector-CAv3RrJ3.js +1 -0
  94. package/build/assets/{mouse-pointer-click-D0QNGSIo.js → mouse-pointer-click-B3i6HcaF.js} +1 -1
  95. package/build/assets/{navigation-context-BpAOh_t5.js → navigation-context-CM9JmTvm.js} +1 -1
  96. package/build/assets/{navigation-link-Dci7Nuyf.js → navigation-link-FmXzqR1J.js} +1 -1
  97. package/build/assets/onboarding-Q9CzuVWy.js +1 -0
  98. package/build/assets/{openhands-logo-Dzm-d_V_.js → openhands-logo-B4aEO2sf.js} +1 -1
  99. package/build/assets/option-service.api-C-s2BYZp.js +1 -0
  100. package/build/assets/organization-service.api-CXTKpFnV.js +1 -0
  101. package/build/assets/{path-utils-YlkpoImJ.js → path-utils-CE98fIFP.js} +1 -1
  102. package/build/assets/{pencil-DPEtl5QD.js → pencil-bWrxRWlr.js} +1 -1
  103. package/build/assets/{plan-components-CutRBi0G.js → plan-components-BF-X7vnQ.js} +1 -1
  104. package/build/assets/{planner-tab-DjIFIQDk.js → planner-tab-jkyaGiRc.js} +1 -1
  105. package/build/assets/plus-BTCK8WtR.js +1 -0
  106. package/build/assets/{profiles-client-BNvHck-I.js → profiles-client-CQ9L1yHR.js} +1 -1
  107. package/build/assets/providers-B3hkV58J.js +1 -0
  108. package/build/assets/proxy-BOcEWkCD.js +1 -0
  109. package/build/assets/{react-dom-hVBnwgwZ.js → react-dom-BBXlXOZX.js} +1 -1
  110. package/build/assets/{react-CM_dJw1Z.js → react-uQK8du1l.js} +1 -1
  111. package/build/assets/{react-Dy05vyj5.js → react-x84lbX6s.js} +1 -1
  112. package/build/assets/{recommended-automations-launcher-DCi0RXIj.js → recommended-automations-launcher-DMk35aFI.js} +11 -11
  113. package/build/assets/root-CV0kyxfP.js +2 -0
  114. package/build/assets/root-PB2Jnj61.css +1 -0
  115. package/build/assets/root-layout-Bl4Qzg5J.js +2 -0
  116. package/build/assets/{runtime-waiting-state-8i0Z3A_i.js → runtime-waiting-state-C1hJpXxl.js} +1 -1
  117. package/build/assets/sdk-section-page-DHbC2_j3.js +1 -0
  118. package/build/assets/sdk-settings-schema-z51bBmMl.js +1 -0
  119. package/build/assets/{search-C_l_XW4e.js → search-Dxm1MUMi.js} +1 -1
  120. package/build/assets/{secrets-service-D6Gcymcs.js → secrets-service-DlScPUwy.js} +1 -1
  121. package/build/assets/secrets-settings-B97-JKBe.js +1 -0
  122. package/build/assets/settings-BpmooyBV.js +1 -0
  123. package/build/assets/{settings-dropdown-input-BP-arqjU.js → settings-dropdown-input-hIIAlmHb.js} +1 -1
  124. package/build/assets/{settings-gear-f-zWpxfI.js → settings-gear-DQLTCnFx.js} +1 -1
  125. package/build/assets/{settings-index-B035V2pu.js → settings-index-kKASonWk.js} +1 -1
  126. package/build/assets/{settings-input-BM8ANxDb.js → settings-input-BlOzCtP3.js} +1 -1
  127. package/build/assets/{settings-list-classes-B9uo5WES.js → settings-list-classes-BFRbCy4U.js} +1 -1
  128. package/build/assets/settings-modal-C4pZwj-l.js +1 -0
  129. package/build/assets/{settings-section-header-context-Cid25HM2.js → settings-section-header-context-iz4Go0dL.js} +1 -1
  130. package/build/assets/settings-service.api-DVLwi82B.js +1 -0
  131. package/build/assets/{settings-switch-xa6q4M6j.js → settings-switch-6cXIH-UE.js} +1 -1
  132. package/build/assets/{settings-utils--H_EvFjx.js → settings-utils-CfScEaPn.js} +1 -1
  133. package/build/assets/shared-conversation-CLkayApe.js +1 -0
  134. package/build/assets/sidebar-mobile-menu-toggle-C8uT4Mhd.js +1 -0
  135. package/build/assets/{sidebar-nav-link-CPWuQ_c6.js → sidebar-nav-link-BKZiAQxQ.js} +1 -1
  136. package/build/assets/{skill-card-pill-row-DeodrwPG.js → skill-card-pill-row-D13WRKIE.js} +1 -1
  137. package/build/assets/{skills-BE5HJuGM.js → skills-NpRk6v79.js} +1 -1
  138. package/build/assets/{skills-client-Ui_9FvXp.js → skills-client-DsqwQEwj.js} +1 -1
  139. package/build/assets/{skills-plugins-Dc4ec3CW.js → skills-plugins-bkwxItAw.js} +1 -1
  140. package/build/assets/{skills-settings-B6HwvA0S.js → skills-settings-DMbrlB2b.js} +2 -2
  141. package/build/assets/{square-chevron-right-BWAB7NPp.js → square-chevron-right-DxZKcVq4.js} +1 -1
  142. package/build/assets/{styled-tooltip-X61SEwqk.js → styled-tooltip-DG1ofAcS.js} +1 -1
  143. package/build/assets/suspense-sOGeme-f.js +1 -0
  144. package/build/assets/{switch-skeleton-BbIWemkK.js → switch-skeleton-CZ6XCVZk.js} +1 -1
  145. package/build/assets/{task-list-tab-BFnyHGsn.js → task-list-tab-CddMPNCD.js} +1 -1
  146. package/build/assets/telemetry-CX4mTZUw.js +2 -0
  147. package/build/assets/{terminal-CltMeLv4.js → terminal-BOAVxAej.js} +1 -1
  148. package/build/assets/{terminal-B92mACR5.js → terminal-DbtwHqt4.js} +1 -1
  149. package/build/assets/{toggle-switch-CL_wRiGs.js → toggle-switch-C0t6ge2m.js} +1 -1
  150. package/build/assets/{trash-2-C-RvV8WA.js → trash-2-Dmprz0A0.js} +1 -1
  151. package/build/assets/{typography-BLSEGjph.js → typography-CNHbO1eE.js} +1 -1
  152. package/build/assets/{u-check-circle-dG_VJqx5.js → u-check-circle-CX66WzfT.js} +1 -1
  153. package/build/assets/{u-check-circle-half-D-5ZPRnd.js → u-check-circle-half-Bj853Ub0.js} +1 -1
  154. package/build/assets/{u-circuit-BXoisXOA.js → u-circuit-B9bLCP7N.js} +1 -1
  155. package/build/assets/{u-edit-DIgADxLH.js → u-edit-D7JyvoWm.js} +1 -1
  156. package/build/assets/use-acp-credential-form-Cj_oUYd5.js +1 -0
  157. package/build/assets/{use-active-conversation-B0_rXnqa.js → use-active-conversation-B64-yy2X.js} +1 -1
  158. package/build/assets/use-agent-settings-schema-BzbQYEzb.js +1 -0
  159. package/build/assets/{use-agent-state-BuOzLeFN.js → use-agent-state-DxFk391r.js} +1 -1
  160. package/build/assets/{use-breakpoint-DpxHDmuH.js → use-breakpoint-Cent5lpI.js} +1 -1
  161. package/build/assets/{use-click-outside-element-DhxCUyWl.js → use-click-outside-element-DOYR26nw.js} +1 -1
  162. package/build/assets/{use-cloud-current-user-id-DVZXa_WH.js → use-cloud-current-user-id-BVf7pb8n.js} +1 -1
  163. package/build/assets/use-config-CvdJUq4E.js +1 -0
  164. package/build/assets/use-create-conversation-Cnouynop.js +1 -0
  165. package/build/assets/{use-create-secret-ClPpLBgD.js → use-create-secret-Cgu4uxyr.js} +1 -1
  166. package/build/assets/{use-event-store-DNSmyzUh.js → use-event-store-Nv92IYMU.js} +1 -1
  167. package/build/assets/use-handle-plan-click-C7824bbe.js +1 -0
  168. package/build/assets/use-is-authed-mnJtd2bw.js +1 -0
  169. package/build/assets/{use-launch-skill-in-chat-BTgXIu3N.js → use-launch-skill-in-chat-NDUo_UCA.js} +1 -1
  170. package/build/assets/use-llm-profiles-9eH3Y3Ef.js +1 -0
  171. package/build/assets/use-runtime-is-ready-DEnxJH7W.js +1 -0
  172. package/build/assets/use-save-settings-DrClHnX7.js +1 -0
  173. package/build/assets/use-settings-BNAoCX93.js +1 -0
  174. package/build/assets/{use-settings-nav-items-DVrMNk0I.js → use-settings-nav-items-CLIW2p2n.js} +2 -2
  175. package/build/assets/{use-skills-Bv8LXrys.js → use-skills-B9gOHrOj.js} +1 -1
  176. package/build/assets/{use-task-list-E5t-jtgs.js → use-task-list-DLKPnq3I.js} +1 -1
  177. package/build/assets/{use-tracking-BhyV5A9i.js → use-tracking-Dph_dRlL.js} +1 -1
  178. package/build/assets/{use-user-conversation-6yFVEXiG.js → use-user-conversation-leIsQH1B.js} +1 -1
  179. package/build/assets/useMutation-cXADjWAv.js +1 -0
  180. package/build/assets/useQuery-BQr6A6ry.js +1 -0
  181. package/build/assets/useTranslation-Bp1btAjp.js +1 -0
  182. package/build/assets/{utils-eXk6yerZ.js → utils-o-OXNtEy.js} +1 -1
  183. package/build/assets/v4-DOSjXdIn.js +1 -0
  184. package/build/assets/{vendor~browser-tab-BGJDGHyS.js → vendor~browser-tab-642bOcE1.js} +1 -1
  185. package/build/assets/{vendor~conversation-panel~conversation-D98u43rl.js → vendor~conversation-panel~conversation-DqmbnXRn.js} +1 -1
  186. package/build/assets/{vendor~conversation-panel~conversation~alert-banner-CtjHOMO_.js → vendor~conversation-panel~conversation~alert-banner-CSDVP1nw.js} +1 -1
  187. package/build/assets/{vendor~conversation-panel~conversation~index-BXt2-3Cc.js → vendor~conversation-panel~conversation~index-DITarr3F.js} +1 -1
  188. package/build/assets/{vendor~entry.client-DrAdOKqA.js → vendor~entry.client-CQ77DucR.js} +1 -1
  189. package/build/assets/{vendor~entry.client-EcEhmoJW.js → vendor~entry.client-ePAFmSwg.js} +1 -1
  190. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~f0pn7nss-DUk-MwlC.js +177 -0
  191. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~lb3qbbk3-BvmOva8I.js +1 -0
  192. package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-Cl4h-NSi.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-BkQQxq_q.js} +1 -1
  193. package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-BmOMM-6e.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-8xF3WeB9.js} +1 -1
  194. package/build/assets/{vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~cnj3raoq-BjMt2JeR.js → vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~nyk4vv4g-UzR6fe3Y.js} +1 -1
  195. package/build/assets/{vendor~files-tab--640YzQO.js → vendor~files-tab-Cko7Kr5k.js} +1 -1
  196. package/build/assets/{vendor~home~conversation-panel~conversation-dhKA2JVJ.js → vendor~home~conversation-panel~conversation-D3otw5Jn.js} +1 -1
  197. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DMOoHVBy.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CMdKUYP2.js} +1 -1
  198. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BoE6JRJj.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DSR6Mugx.js} +1 -1
  199. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dqpi2xyZ.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DdOzMvB1.js} +1 -1
  200. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DX2CmDJ0.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dj2eezvL.js} +1 -1
  201. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BNExlCqT.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DyN8jeZz.js} +1 -1
  202. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DCn1M97v.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-lpEWrbMA.js} +1 -1
  203. package/build/assets/{vendor~launch-C0VvUe2W.js → vendor~launch-DoYO54df.js} +1 -1
  204. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-COLUW-6M.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-BGwU2SbU.js} +1 -1
  205. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation-eG1kjEbj.js → vendor~root-layout~home~conversation-panel~conversation-Iqs0j4Wo.js} +1 -1
  206. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-7eqKdLSQ.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-BdS6bbw9.js} +1 -1
  207. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-BP3MGAAY.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-Fd3F3jth.js} +1 -1
  208. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ceijy54y-Dkd2wxJA.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ceijy54y-Cg0AqwMN.js} +2 -2
  209. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~bxn4ldi1-_LydBB1e.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~bxn4ldi1-BlsbqRyZ.js} +1 -1
  210. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~settings~settings-index~agen~ec6pk3ix-CBICqfKC.js +48 -0
  211. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~mcp~automati~dou5smdo-DavKsAvB.js → vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~automations-~nv6afr11-BYNoKMU0.js} +97 -69
  212. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-CsO1gYxF.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-BspUuSsP.js} +1 -1
  213. package/build/assets/{vendor~root-layout~home~mcp~automations-list-D40jgugf.js → vendor~root-layout~home~mcp~automations-list-C9U_eOqU.js} +1 -1
  214. package/build/assets/{vendor~root-layout~home~mcp~automations-list-cNHi83v_.js → vendor~root-layout~home~mcp~automations-list-DhQ3LPVw.js} +1 -1
  215. package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-xCM3k6Rd.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BEbhHQYg.js} +1 -1
  216. package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BIm99UaF.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-DdgDNzMc.js} +2 -2
  217. package/build/assets/{verification-settings-Be6NxjuT.js → verification-settings-D7R-Ne6L.js} +1 -1
  218. package/build/assets/x-DCZg87p7.js +1 -0
  219. package/build/assets/{x-mark-C42svtnu.js → x-mark-jrBTJbnP.js} +1 -1
  220. package/build/index.html +4 -4
  221. package/build/locales/ar/openhands.json +22 -0
  222. package/build/locales/ca/openhands.json +22 -0
  223. package/build/locales/de/openhands.json +22 -0
  224. package/build/locales/en/openhands.json +22 -0
  225. package/build/locales/es/openhands.json +22 -0
  226. package/build/locales/fr/openhands.json +22 -0
  227. package/build/locales/it/openhands.json +22 -0
  228. package/build/locales/ja/openhands.json +22 -0
  229. package/build/locales/ko-KR/openhands.json +22 -0
  230. package/build/locales/no/openhands.json +22 -0
  231. package/build/locales/pt/openhands.json +22 -0
  232. package/build/locales/tr/openhands.json +22 -0
  233. package/build/locales/uk/openhands.json +22 -0
  234. package/build/locales/zh-CN/openhands.json +22 -0
  235. package/build/locales/zh-TW/openhands.json +22 -0
  236. package/config/defaults.json +4 -7
  237. package/dist/api/agent-server-adapter.cjs +3 -3
  238. package/dist/api/agent-server-adapter.cjs.map +1 -1
  239. package/dist/api/agent-server-adapter.d.ts +8 -0
  240. package/dist/api/agent-server-adapter.js +82 -80
  241. package/dist/api/agent-server-adapter.js.map +1 -1
  242. package/dist/api/agent-server-compatibility.cjs +1 -1
  243. package/dist/api/agent-server-compatibility.cjs.map +1 -1
  244. package/dist/api/agent-server-compatibility.d.ts +10 -0
  245. package/dist/api/agent-server-compatibility.js +69 -25
  246. package/dist/api/agent-server-compatibility.js.map +1 -1
  247. package/dist/api/backend-registry/default-backend.cjs +1 -1
  248. package/dist/api/backend-registry/default-backend.cjs.map +1 -1
  249. package/dist/api/backend-registry/default-backend.d.ts +6 -5
  250. package/dist/api/backend-registry/default-backend.js +1 -1
  251. package/dist/api/backend-registry/default-backend.js.map +1 -1
  252. package/dist/api/backend-registry/storage.cjs +1 -1
  253. package/dist/api/backend-registry/storage.cjs.map +1 -1
  254. package/dist/api/backend-registry/storage.js +38 -68
  255. package/dist/api/backend-registry/storage.js.map +1 -1
  256. package/dist/api/cloud/proxy.cjs +1 -1
  257. package/dist/api/cloud/proxy.cjs.map +1 -1
  258. package/dist/api/cloud/proxy.d.ts +3 -16
  259. package/dist/api/cloud/proxy.js +1 -1
  260. package/dist/api/cloud/proxy.js.map +1 -1
  261. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  262. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  263. package/dist/api/conversation-service/agent-server-conversation-service.api.js +75 -75
  264. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  265. package/dist/api/llm-subscription-service.cjs +2 -0
  266. package/dist/api/llm-subscription-service.cjs.map +1 -0
  267. package/dist/api/llm-subscription-service.d.ts +23 -0
  268. package/dist/api/llm-subscription-service.js +109 -0
  269. package/dist/api/llm-subscription-service.js.map +1 -0
  270. package/dist/api/mcp-service/mcp-service.api.cjs +1 -1
  271. package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -1
  272. package/dist/api/mcp-service/mcp-service.api.d.ts +2 -3
  273. package/dist/api/mcp-service/mcp-service.api.js +38 -13
  274. package/dist/api/mcp-service/mcp-service.api.js.map +1 -1
  275. package/dist/api/settings-service/settings-service.api.cjs +1 -1
  276. package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
  277. package/dist/api/settings-service/settings-service.api.js +41 -42
  278. package/dist/api/settings-service/settings-service.api.js.map +1 -1
  279. package/dist/components/conversation-events/chat/messages.cjs +1 -1
  280. package/dist/components/conversation-events/chat/messages.cjs.map +1 -1
  281. package/dist/components/conversation-events/chat/messages.js +4 -4
  282. package/dist/components/conversation-events/chat/messages.js.map +1 -1
  283. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  284. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  285. package/dist/components/features/backends/backend-form-modal.js +136 -135
  286. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  287. package/dist/components/features/backends/backend-selector.cjs +1 -1
  288. package/dist/components/features/backends/backend-selector.cjs.map +1 -1
  289. package/dist/components/features/backends/backend-selector.js +103 -91
  290. package/dist/components/features/backends/backend-selector.js.map +1 -1
  291. package/dist/components/features/backends/manage-backends-modal.cjs +1 -1
  292. package/dist/components/features/backends/manage-backends-modal.cjs.map +1 -1
  293. package/dist/components/features/backends/manage-backends-modal.js +14 -8
  294. package/dist/components/features/backends/manage-backends-modal.js.map +1 -1
  295. package/dist/components/features/chat/path-component.cjs +1 -1
  296. package/dist/components/features/chat/path-component.cjs.map +1 -1
  297. package/dist/components/features/chat/path-component.js +1 -1
  298. package/dist/components/features/chat/path-component.js.map +1 -1
  299. package/dist/components/features/home/workspace-dropdown/folder-browser-modal.cjs +1 -1
  300. package/dist/components/features/home/workspace-dropdown/folder-browser-modal.cjs.map +1 -1
  301. package/dist/components/features/home/workspace-dropdown/folder-browser-modal.js +77 -66
  302. package/dist/components/features/home/workspace-dropdown/folder-browser-modal.js.map +1 -1
  303. package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
  304. package/dist/components/features/mcp-page/custom-server-editor.cjs.map +1 -1
  305. package/dist/components/features/mcp-page/custom-server-editor.js +1 -0
  306. package/dist/components/features/mcp-page/custom-server-editor.js.map +1 -1
  307. package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
  308. package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
  309. package/dist/components/features/mcp-page/install-server-modal.js +73 -46
  310. package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
  311. package/dist/components/features/mcp-page/marketplace-card.cjs +1 -1
  312. package/dist/components/features/mcp-page/marketplace-card.cjs.map +1 -1
  313. package/dist/components/features/mcp-page/marketplace-card.js +6 -2
  314. package/dist/components/features/mcp-page/marketplace-card.js.map +1 -1
  315. package/dist/components/features/settings/brand-button.cjs +1 -1
  316. package/dist/components/features/settings/brand-button.cjs.map +1 -1
  317. package/dist/components/features/settings/brand-button.js +1 -1
  318. package/dist/components/features/settings/brand-button.js.map +1 -1
  319. package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.cjs +2 -0
  320. package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.cjs.map +1 -0
  321. package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.d.ts +5 -0
  322. package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.js +167 -0
  323. package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.js.map +1 -0
  324. package/dist/components/shared/modals/settings/model-selector.cjs +1 -1
  325. package/dist/components/shared/modals/settings/model-selector.cjs.map +1 -1
  326. package/dist/components/shared/modals/settings/model-selector.d.ts +1 -2
  327. package/dist/components/shared/modals/settings/model-selector.js +59 -65
  328. package/dist/components/shared/modals/settings/model-selector.js.map +1 -1
  329. package/dist/components/shared/modals/settings/settings-form.cjs +1 -1
  330. package/dist/components/shared/modals/settings/settings-form.cjs.map +1 -1
  331. package/dist/components/shared/modals/settings/settings-form.js +1 -2
  332. package/dist/components/shared/modals/settings/settings-form.js.map +1 -1
  333. package/dist/config/defaults.cjs +2 -0
  334. package/dist/config/defaults.cjs.map +1 -0
  335. package/dist/config/defaults.js +35 -0
  336. package/dist/config/defaults.js.map +1 -0
  337. package/dist/constants/llm-subscription.cjs +2 -0
  338. package/dist/constants/llm-subscription.cjs.map +1 -0
  339. package/dist/constants/llm-subscription.d.ts +16 -0
  340. package/dist/constants/llm-subscription.js +47 -0
  341. package/dist/constants/llm-subscription.js.map +1 -0
  342. package/dist/contexts/conversation-websocket-context.cjs +1 -1
  343. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  344. package/dist/contexts/conversation-websocket-context.js +1 -1
  345. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  346. package/dist/hooks/mutation/use-llm-subscription-auth.cjs +2 -0
  347. package/dist/hooks/mutation/use-llm-subscription-auth.cjs.map +1 -0
  348. package/dist/hooks/mutation/use-llm-subscription-auth.d.ts +3 -0
  349. package/dist/hooks/mutation/use-llm-subscription-auth.js +30 -0
  350. package/dist/hooks/mutation/use-llm-subscription-auth.js.map +1 -0
  351. package/dist/hooks/mutation/use-save-fields-as-secrets.cjs +1 -1
  352. package/dist/hooks/mutation/use-save-fields-as-secrets.cjs.map +1 -1
  353. package/dist/hooks/mutation/use-save-fields-as-secrets.d.ts +8 -6
  354. package/dist/hooks/mutation/use-save-fields-as-secrets.js +1 -1
  355. package/dist/hooks/mutation/use-save-fields-as-secrets.js.map +1 -1
  356. package/dist/hooks/mutation/use-test-mcp-server.d.ts +1 -1
  357. package/dist/hooks/query/query-keys.cjs +1 -1
  358. package/dist/hooks/query/query-keys.cjs.map +1 -1
  359. package/dist/hooks/query/query-keys.d.ts +5 -0
  360. package/dist/hooks/query/query-keys.js +14 -2
  361. package/dist/hooks/query/query-keys.js.map +1 -1
  362. package/dist/hooks/query/use-agent-settings-schema.cjs +1 -1
  363. package/dist/hooks/query/use-agent-settings-schema.cjs.map +1 -1
  364. package/dist/hooks/query/use-agent-settings-schema.d.ts +2 -2
  365. package/dist/hooks/query/use-agent-settings-schema.js +21 -19
  366. package/dist/hooks/query/use-agent-settings-schema.js.map +1 -1
  367. package/dist/hooks/query/use-backends-health.cjs +1 -1
  368. package/dist/hooks/query/use-backends-health.cjs.map +1 -1
  369. package/dist/hooks/query/use-backends-health.js +38 -36
  370. package/dist/hooks/query/use-backends-health.js.map +1 -1
  371. package/dist/hooks/query/use-llm-subscription-models.cjs +2 -0
  372. package/dist/hooks/query/use-llm-subscription-models.cjs.map +1 -0
  373. package/dist/hooks/query/use-llm-subscription-models.d.ts +3 -0
  374. package/dist/hooks/query/use-llm-subscription-models.js +19 -0
  375. package/dist/hooks/query/use-llm-subscription-models.js.map +1 -0
  376. package/dist/hooks/query/use-llm-subscription-status.cjs +2 -0
  377. package/dist/hooks/query/use-llm-subscription-status.cjs.map +1 -0
  378. package/dist/hooks/query/use-llm-subscription-status.d.ts +3 -0
  379. package/dist/hooks/query/use-llm-subscription-status.js +19 -0
  380. package/dist/hooks/query/use-llm-subscription-status.js.map +1 -0
  381. package/dist/hooks/use-websocket.cjs +1 -1
  382. package/dist/hooks/use-websocket.cjs.map +1 -1
  383. package/dist/hooks/use-websocket.d.ts +0 -1
  384. package/dist/hooks/use-websocket.js +37 -38
  385. package/dist/hooks/use-websocket.js.map +1 -1
  386. package/dist/i18n/declaration.cjs +1 -1
  387. package/dist/i18n/declaration.cjs.map +1 -1
  388. package/dist/i18n/declaration.d.ts +22 -0
  389. package/dist/i18n/declaration.js +1 -1
  390. package/dist/i18n/declaration.js.map +1 -1
  391. package/dist/i18n/translation.cjs +2 -2
  392. package/dist/i18n/translation.cjs.map +1 -1
  393. package/dist/i18n/translation.js +374 -0
  394. package/dist/i18n/translation.js.map +1 -1
  395. package/dist/locales/ar/openhands.json +22 -0
  396. package/dist/locales/ca/openhands.json +22 -0
  397. package/dist/locales/de/openhands.json +22 -0
  398. package/dist/locales/en/openhands.json +22 -0
  399. package/dist/locales/es/openhands.json +22 -0
  400. package/dist/locales/fr/openhands.json +22 -0
  401. package/dist/locales/it/openhands.json +22 -0
  402. package/dist/locales/ja/openhands.json +22 -0
  403. package/dist/locales/ko-KR/openhands.json +22 -0
  404. package/dist/locales/no/openhands.json +22 -0
  405. package/dist/locales/pt/openhands.json +22 -0
  406. package/dist/locales/tr/openhands.json +22 -0
  407. package/dist/locales/uk/openhands.json +22 -0
  408. package/dist/locales/zh-CN/openhands.json +22 -0
  409. package/dist/locales/zh-TW/openhands.json +22 -0
  410. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs +1 -1
  411. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs.map +1 -1
  412. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js +10 -22
  413. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -1
  414. package/dist/node_modules/@openhands/extensions/skills/index.cjs +97 -69
  415. package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
  416. package/dist/node_modules/@openhands/extensions/skills/index.js +3 -3
  417. package/dist/node_modules/@openhands/extensions/skills/index.js.map +1 -1
  418. package/dist/package.cjs +1 -1
  419. package/dist/package.cjs.map +1 -1
  420. package/dist/package.js +3 -5
  421. package/dist/package.js.map +1 -1
  422. package/dist/routes/files-tab.cjs +1 -1
  423. package/dist/routes/files-tab.cjs.map +1 -1
  424. package/dist/routes/files-tab.js +28 -17
  425. package/dist/routes/files-tab.js.map +1 -1
  426. package/dist/routes/llm-settings.cjs +1 -1
  427. package/dist/routes/llm-settings.cjs.map +1 -1
  428. package/dist/routes/llm-settings.js +142 -85
  429. package/dist/routes/llm-settings.js.map +1 -1
  430. package/dist/services/canvas-ui.cjs +1 -1
  431. package/dist/services/canvas-ui.cjs.map +1 -1
  432. package/dist/services/canvas-ui.d.ts +1 -1
  433. package/dist/services/canvas-ui.js +2 -2
  434. package/dist/services/canvas-ui.js.map +1 -1
  435. package/dist/stores/files-tab-store.cjs +1 -1
  436. package/dist/stores/files-tab-store.cjs.map +1 -1
  437. package/dist/stores/files-tab-store.d.ts +2 -1
  438. package/dist/stores/files-tab-store.js +5 -1
  439. package/dist/stores/files-tab-store.js.map +1 -1
  440. package/dist/stores/use-event-store.cjs +1 -1
  441. package/dist/stores/use-event-store.cjs.map +1 -1
  442. package/dist/stores/use-event-store.js +39 -34
  443. package/dist/stores/use-event-store.js.map +1 -1
  444. package/dist/types/mcp-server.d.ts +21 -0
  445. package/dist/ui/dropdown/dropdown.cjs +1 -1
  446. package/dist/ui/dropdown/dropdown.cjs.map +1 -1
  447. package/dist/ui/dropdown/dropdown.js +6 -2
  448. package/dist/ui/dropdown/dropdown.js.map +1 -1
  449. package/dist/utils/handle-event-for-ui.cjs +1 -1
  450. package/dist/utils/handle-event-for-ui.cjs.map +1 -1
  451. package/dist/utils/handle-event-for-ui.d.ts +2 -0
  452. package/dist/utils/handle-event-for-ui.js +1 -1
  453. package/dist/utils/handle-event-for-ui.js.map +1 -1
  454. package/dist/utils/llm-subscription-schema.cjs +2 -0
  455. package/dist/utils/llm-subscription-schema.cjs.map +1 -0
  456. package/dist/utils/llm-subscription-schema.d.ts +2 -0
  457. package/dist/utils/llm-subscription-schema.js +22 -0
  458. package/dist/utils/llm-subscription-schema.js.map +1 -0
  459. package/dist/utils/mcp-config.cjs +1 -1
  460. package/dist/utils/mcp-config.cjs.map +1 -1
  461. package/dist/utils/mcp-config.js +32 -17
  462. package/dist/utils/mcp-config.js.map +1 -1
  463. package/dist/utils/mcp-credential-validation.cjs +2 -0
  464. package/dist/utils/mcp-credential-validation.cjs.map +1 -0
  465. package/dist/utils/mcp-credential-validation.d.ts +22 -0
  466. package/dist/utils/mcp-credential-validation.js +31 -0
  467. package/dist/utils/mcp-credential-validation.js.map +1 -0
  468. package/dist/utils/mcp-marketplace-utils.cjs +1 -1
  469. package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
  470. package/dist/utils/mcp-marketplace-utils.d.ts +7 -2
  471. package/dist/utils/mcp-marketplace-utils.js +33 -48
  472. package/dist/utils/mcp-marketplace-utils.js.map +1 -1
  473. package/dist/utils/sdk-settings-schema.cjs +1 -1
  474. package/dist/utils/sdk-settings-schema.cjs.map +1 -1
  475. package/dist/utils/sdk-settings-schema.js +64 -61
  476. package/dist/utils/sdk-settings-schema.js.map +1 -1
  477. package/dist/utils/websocket-url.cjs +1 -1
  478. package/dist/utils/websocket-url.cjs.map +1 -1
  479. package/dist/utils/websocket-url.js +2 -2
  480. package/dist/utils/websocket-url.js.map +1 -1
  481. package/package.json +3 -5
  482. package/scripts/check-sdk-version-sync.mjs +9 -27
  483. package/scripts/dev-with-automation.mjs +1 -3
  484. package/scripts/docker-build.mjs +0 -4
  485. package/scripts/run-staged-typecheck.mjs +44 -0
  486. package/build/assets/QueryClientProvider-XcSjsfpb.js +0 -1
  487. package/build/assets/Trans-sy4l4TyQ.js +0 -1
  488. package/build/assets/active-backend-context-CNF2lPkA.js +0 -1
  489. package/build/assets/add-backend-modal-BywVr6uq.js +0 -1
  490. package/build/assets/agent-server-adapter-k8veH-1O.js +0 -5
  491. package/build/assets/agent-server-client-options-B-C8JaTb.js +0 -1
  492. package/build/assets/agent-server-conversation-service.api-CGbkhsLj.js +0 -1
  493. package/build/assets/api-key-entry-screen-Dnr5TcV0.js +0 -1
  494. package/build/assets/app-settings-Bgm2-yOM.js +0 -1
  495. package/build/assets/automation-detail-86M_yMqz.js +0 -1
  496. package/build/assets/automations-list-BWUILrqY.js +0 -1
  497. package/build/assets/backend-form-modal-Dl29wkF5.js +0 -1
  498. package/build/assets/browser-store-JRrcGdlk.js +0 -1
  499. package/build/assets/browser-wz8UzRmF.js +0 -5
  500. package/build/assets/chat-send-button-BhoO7T0s.js +0 -1
  501. package/build/assets/check-BhnsMsWy.js +0 -1
  502. package/build/assets/condenser-settings-DgQ0rsAf.js +0 -1
  503. package/build/assets/context-CI9FqkUp.js +0 -1
  504. package/build/assets/conversation-CayU5Lrr.js +0 -19
  505. package/build/assets/conversation-erinyBqT.js +0 -1
  506. package/build/assets/conversation-panel-DiI4q-8-.js +0 -1
  507. package/build/assets/conversation-service.api-shHWtFwu.js +0 -1
  508. package/build/assets/conversation-state-store-NEktJKfL.js +0 -1
  509. package/build/assets/declaration-D9ucT0fq.js +0 -1
  510. package/build/assets/dist-BCpEDEJq.js +0 -1
  511. package/build/assets/edit-automation-modal-8y9Uctxo.js +0 -1
  512. package/build/assets/entry.client-D_wtryHT.js +0 -2
  513. package/build/assets/files-tab-CxdtgkIe.js +0 -1
  514. package/build/assets/files-tab-store-DSKUhziI.js +0 -1
  515. package/build/assets/home-3joHMYSR.js +0 -1
  516. package/build/assets/index-redirect-BQ_55qN6.js +0 -1
  517. package/build/assets/install-server-modal-_7l1gcjd.js +0 -1
  518. package/build/assets/lesson-plan-CHGc-B8Y.js +0 -3
  519. package/build/assets/llm-not-configured-banner-BMGzpBPV.js +0 -27
  520. package/build/assets/llm-settings-BRotm_g6.js +0 -1
  521. package/build/assets/llm-settings-yDgbXP6Q.js +0 -1
  522. package/build/assets/loader-circle-1XB9nbwF.js +0 -1
  523. package/build/assets/manage-backends-modal-tfdzTXWU.js +0 -1
  524. package/build/assets/manifest-bbc1374e.js +0 -1
  525. package/build/assets/markdown-renderer-z446oW0Z.js +0 -2
  526. package/build/assets/mcp-Dopstf0t.js +0 -9
  527. package/build/assets/mcp-settings-redirect-l3Zbmc0F.js +0 -1
  528. package/build/assets/messages-CsFUrAen.js +0 -41
  529. package/build/assets/model-selector-sioC8xP4.js +0 -1
  530. package/build/assets/onboarding-CQh50i2z.js +0 -1
  531. package/build/assets/option-service.api-DjPvPAtd.js +0 -1
  532. package/build/assets/organization-service.api-BNc9Kn6n.js +0 -1
  533. package/build/assets/plus-DKUID4kd.js +0 -1
  534. package/build/assets/providers-BiWSYwRT.js +0 -1
  535. package/build/assets/proxy--Uy1iGsW.js +0 -1
  536. package/build/assets/query-client-config-Ca3tW1AH.js +0 -1
  537. package/build/assets/root-CRkz_h2T.css +0 -1
  538. package/build/assets/root-DrHpnAqU.js +0 -2
  539. package/build/assets/root-layout-Cf7FC9DC.js +0 -2
  540. package/build/assets/sdk-section-page-COlGKv4E.js +0 -1
  541. package/build/assets/sdk-settings-schema-Big50zDH.js +0 -1
  542. package/build/assets/secrets-settings-DYfTc5c8.js +0 -1
  543. package/build/assets/settings-DRmVFdOc.js +0 -1
  544. package/build/assets/settings-modal-CeRvS5Bc.js +0 -1
  545. package/build/assets/settings-service.api-CFt5HmXD.js +0 -1
  546. package/build/assets/shared-conversation-CBbpyPaD.js +0 -1
  547. package/build/assets/sidebar-mobile-menu-toggle-SKcwsEtD.js +0 -1
  548. package/build/assets/suspense-Bqb0V0q1.js +0 -1
  549. package/build/assets/telemetry-DCFAqpIA.js +0 -2
  550. package/build/assets/use-acp-credential-form-LjCIhMSK.js +0 -1
  551. package/build/assets/use-agent-settings-schema-D8x5LJVS.js +0 -1
  552. package/build/assets/use-config-5zEjywCL.js +0 -1
  553. package/build/assets/use-create-conversation-pV2eA-e9.js +0 -1
  554. package/build/assets/use-handle-plan-click-CwN_nNib.js +0 -1
  555. package/build/assets/use-is-authed-B8eLO-Xq.js +0 -1
  556. package/build/assets/use-llm-profiles-CWLfWjav.js +0 -1
  557. package/build/assets/use-runtime-is-ready-Bbory9-s.js +0 -1
  558. package/build/assets/use-save-settings-Xp8DD-jf.js +0 -1
  559. package/build/assets/use-settings-0SeqaDeW.js +0 -1
  560. package/build/assets/useMutation-Dm84WAKR.js +0 -1
  561. package/build/assets/useQuery-DGRSm7IT.js +0 -1
  562. package/build/assets/useTranslation-CL6FTf1b.js +0 -1
  563. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~dqseey1n-D_BSEDk4.js +0 -1
  564. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~jfbjdnyv-C5ZIbuq8.js +0 -177
  565. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~mcp~settings~settings-index~~m3acswdn-CGm-Jxp5.js +0 -48
  566. package/build/assets/x-CCfDppg5.js +0 -1
  567. package/dist/api/settings-service/legacy-app-preferences-migration.cjs +0 -2
  568. package/dist/api/settings-service/legacy-app-preferences-migration.cjs.map +0 -1
  569. package/dist/api/settings-service/legacy-app-preferences-migration.d.ts +0 -34
  570. package/dist/api/settings-service/legacy-app-preferences-migration.js +0 -52
  571. package/dist/api/settings-service/legacy-app-preferences-migration.js.map +0 -1
  572. package/dist/hooks/query/use-openhands-verified-models.cjs +0 -2
  573. package/dist/hooks/query/use-openhands-verified-models.cjs.map +0 -1
  574. package/dist/hooks/query/use-openhands-verified-models.d.ts +0 -1
  575. package/dist/hooks/query/use-openhands-verified-models.js +0 -14
  576. package/dist/hooks/query/use-openhands-verified-models.js.map +0 -1
  577. package/dist/utils/normalize-display-model.cjs +0 -2
  578. package/dist/utils/normalize-display-model.cjs.map +0 -1
  579. package/dist/utils/normalize-display-model.d.ts +0 -9
  580. package/dist/utils/normalize-display-model.js +0 -13
  581. package/dist/utils/normalize-display-model.js.map +0 -1
  582. package/dist/utils/openhands-llm.cjs +0 -2
  583. package/dist/utils/openhands-llm.cjs.map +0 -1
  584. package/dist/utils/openhands-llm.d.ts +0 -15
  585. package/dist/utils/openhands-llm.js +0 -15
  586. package/dist/utils/openhands-llm.js.map +0 -1
  587. /package/build/assets/{agent-server-ui-style-scope-BwIZYdC1.js → agent-server-ui-style-scope-1MuaCC1k.js} +0 -0
  588. /package/build/assets/{common-Dh7OqABE.js → common-DqjLSBOt.js} +0 -0
  589. /package/build/assets/{environment-switch-store-CiurvTtK.js → environment-switch-store-CBXkf5bS.js} +0 -0
  590. /package/build/assets/{extension-module-card-classes-DP5J6ngE.js → extension-module-card-classes-CVGfXtoL.js} +0 -0
  591. /package/build/assets/{git-status-mapper-BI8FyUVp.js → git-status-mapper-DVFXF1_X.js} +0 -0
  592. /package/build/assets/{handle-capture-consent-CPMXU29K.js → handle-capture-consent-BTvatyfE.js} +0 -0
  593. /package/build/assets/{map-provider-BM2SJarp.js → map-provider-COgsZR9p.js} +0 -0
  594. /package/build/assets/{objectWithoutPropertiesLoose-DSQKyRhw.js → objectWithoutPropertiesLoose-B80nTzVc.js} +0 -0
  595. /package/build/assets/{preload-helper-CT1Z6Pdu.js → preload-helper-D_sPnjeL.js} +0 -0
  596. /package/build/assets/{rolldown-runtime-BFRubm34.js → rolldown-runtime-wFmyQBCi.js} +0 -0
  597. /package/build/assets/{sdk-settings-field-metadata-p2GVlft7.js → sdk-settings-field-metadata-Cc4D-ut7.js} +0 -0
  598. /package/build/assets/{settings-wh2sLLJM.js → settings-1287uR2J.js} +0 -0
  599. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~nh19ovoo-DJTFnsA1.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~cg1m3bv7-aUIHudsf.js} +0 -0
  600. /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ntycl9e1-BmZcy_kH.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ntycl9e1-DPPGSgT1.js} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-subscription-schema.js","names":[],"sources":["../../src/utils/llm-subscription-schema.ts"],"sourcesContent":["import type { SettingsSchema } from \"#/types/settings\";\nimport { LLM_SUBSCRIPTION_SCHEMA_FIELDS } from \"#/constants/llm-subscription\";\n\nconst LLM_SECTION_KEY = \"llm\";\n\nexport function withLlmSubscriptionSchemaFields(\n schema: SettingsSchema | null | undefined,\n): SettingsSchema | null | undefined {\n if (!schema?.sections) return schema;\n\n let changed = false;\n const sections = schema.sections.map((section) => {\n if (section.key !== LLM_SECTION_KEY) return section;\n\n const existingKeys = new Set(section.fields.map((field) => field.key));\n const missingFields = LLM_SUBSCRIPTION_SCHEMA_FIELDS.filter(\n (field) => !existingKeys.has(field.key),\n );\n\n if (missingFields.length === 0) return section;\n changed = true;\n return {\n ...section,\n fields: [...section.fields, ...missingFields],\n };\n });\n\n if (!changed) return schema;\n return { ...schema, sections };\n}\n"],"mappings":";;AAGA,IAAM,IAAkB;AAExB,SAAgB,EACd,GACmC;AACnC,KAAI,CAAC,GAAQ,SAAU,QAAO;CAE9B,IAAI,IAAU,IACR,IAAW,EAAO,SAAS,KAAK,MAAY;AAChD,MAAI,EAAQ,QAAQ,EAAiB,QAAO;EAE5C,IAAM,IAAe,IAAI,IAAI,EAAQ,OAAO,KAAK,MAAU,EAAM,IAAI,CAAC,EAChE,IAAgB,EAA+B,QAClD,MAAU,CAAC,EAAa,IAAI,EAAM,IAAI,CACxC;AAID,SAFI,EAAc,WAAW,IAAU,KACvC,IAAU,IACH;GACL,GAAG;GACH,QAAQ,CAAC,GAAG,EAAQ,QAAQ,GAAG,EAAc;GAC9C;GACD;AAGF,QADK,IACE;EAAE,GAAG;EAAQ;EAAU,GADT"}
@@ -1,2 +1,2 @@
1
- require(`../_virtual/_rolldown/runtime.cjs`);var e={sse_servers:[],stdio_servers:[],shttp_servers:[]},t=`https://mcp.linear.app/sse`,n=`https://mcp.linear.app/mcp`;function r(e,n){return n===`sse`?e.split(`?`)[0].replace(/\/+$/,``)===t:!1}function i(t){if(!t||typeof t!=`object`)return{...e};let i=t;if(!(`mcpServers`in i)||!i.mcpServers||typeof i.mcpServers!=`object`)return{...e};let a=[],o=[],s=[],c=[],l=i.mcpServers;for(let[e,t]of Object.entries(l)){if(!t||typeof t!=`object`)continue;let i=t.url;if(i){let e=t.transport,o=t.auth,l=typeof o==`string`&&o!==`oauth`?o:void 0;if(r(i,e)){let e={url:n};l&&(e.api_key=l),c.push(e)}else if(e===`sse`){let e={url:i};l&&(e.api_key=l),a.push(e)}else{let e={url:i};l&&(e.api_key=l),t.timeout!=null&&(e.timeout=t.timeout),s.push(e)}}else{let n={name:e,command:t.command};t.args&&(n.args=t.args),t.env&&(n.env=t.env),o.push(n)}}let u=e=>e.replace(/\/+$/,``);for(let e of c)s.some(t=>u(typeof t==`string`?t:t.url)===u(e.url))||s.push(e);return{sse_servers:a,stdio_servers:o,shttp_servers:s}}function a(e){let t={},n=e=>{if(!(e in t))return e;let n=1;for(;`${e}_${n}`in t;)n+=1;return`${e}_${n}`};for(let r of e.sse_servers){let e={};typeof r==`string`?e.url=r:(e.url=r.url,r.api_key&&(e.auth=r.api_key)),e.transport=`sse`,t[n(`sse`)]=e}for(let r of e.shttp_servers){let e={};typeof r==`string`?e.url=r:(e.url=r.url,r.api_key&&(e.auth=r.api_key),r.timeout!=null&&(e.timeout=r.timeout)),t[n(`shttp`)]=e}for(let r of e.stdio_servers){let e={command:r.command};r.args&&(e.args=r.args),r.env&&(e.env=r.env),t[n(r.name||`stdio`)]=e}return Object.keys(t).length>0?{mcpServers:t}:null}exports.parseMcpConfig=i,exports.toSdkMcpConfig=a;
1
+ require(`../_virtual/_rolldown/runtime.cjs`);var e={sse_servers:[],stdio_servers:[],shttp_servers:[]},t=`https://mcp.linear.app/sse`,n=`https://mcp.linear.app/mcp`;function r(e,n){return n===`sse`?e.split(`?`)[0].replace(/\/+$/,``)===t:!1}function i(e){if(Array.isArray(e))return e.map(i).find(e=>e!==void 0);if(typeof e!=`string`||e.length===0)return;let t=e.match(/^Bearer\s+(.+)$/i);return t?t[1]:e}function a(e){let t=e.headers,n=i(t&&typeof t==`object`?t.Authorization??t.authorization:void 0);if(n)return n;let r=e.auth;return typeof r==`string`&&r!==`oauth`?r:void 0}function o(e){return e?{headers:{Authorization:`Bearer ${e}`}}:{}}function s(t){if(!t||typeof t!=`object`)return{...e};let i=t;if(!(`mcpServers`in i)||!i.mcpServers||typeof i.mcpServers!=`object`)return{...e};let o=[],s=[],c=[],l=[],u=i.mcpServers;for(let[e,t]of Object.entries(u)){if(!t||typeof t!=`object`)continue;let i=t.url;if(i){let e=t.transport,s=a(t);if(r(i,e)){let e={url:n};s&&(e.api_key=s),l.push(e)}else if(e===`sse`){let e={url:i};s&&(e.api_key=s),o.push(e)}else{let e={url:i};s&&(e.api_key=s),t.timeout!=null&&(e.timeout=t.timeout),c.push(e)}}else{let n={name:e,command:t.command};t.args&&(n.args=t.args),t.env&&(n.env=t.env),s.push(n)}}let d=e=>e.replace(/\/+$/,``);for(let e of l)c.some(t=>d(typeof t==`string`?t:t.url)===d(e.url))||c.push(e);return{sse_servers:o,stdio_servers:s,shttp_servers:c}}function c(e){let t={},n=e=>{if(!(e in t))return e;let n=1;for(;`${e}_${n}`in t;)n+=1;return`${e}_${n}`};for(let r of e.sse_servers){let e={};typeof r==`string`?e.url=r:(e.url=r.url,Object.assign(e,o(r.api_key))),e.transport=`sse`,t[n(`sse`)]=e}for(let r of e.shttp_servers){let e={};typeof r==`string`?e.url=r:(e.url=r.url,Object.assign(e,o(r.api_key)),r.timeout!=null&&(e.timeout=r.timeout)),t[n(`shttp`)]=e}for(let r of e.stdio_servers){let e={command:r.command};r.args&&(e.args=r.args),r.env&&(e.env=r.env),t[n(r.name||`stdio`)]=e}return Object.keys(t).length>0?{mcpServers:t}:null}exports.parseMcpConfig=s,exports.toSdkMcpConfig=c;
2
2
  //# sourceMappingURL=mcp-config.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-config.cjs","names":[],"sources":["../../src/utils/mcp-config.ts"],"sourcesContent":["import {\n MCPConfig,\n MCPSSEServer,\n MCPSHTTPServer,\n MCPStdioServer,\n SettingsValue,\n} from \"#/types/settings\";\n\nconst EMPTY_MCP_CONFIG: MCPConfig = {\n sse_servers: [],\n stdio_servers: [],\n shttp_servers: [],\n};\n\nconst LINEAR_DEPRECATED_SSE_URL = \"https://mcp.linear.app/sse\";\nconst LINEAR_SHTTP_URL = \"https://mcp.linear.app/mcp\";\n\n/**\n * Linear removed its MCP SSE transport (the /sse endpoint rejects every\n * call since 2026-04-08). Detect persisted configs that still point at\n * the dead endpoint so they can be migrated to streamable HTTP at the\n * /mcp replacement. Matches only the exact deprecated URL (tolerating a\n * trailing slash or query string) — nothing else is rewritten.\n */\nfunction isDeprecatedLinearSse(\n url: string,\n transport: string | undefined,\n): boolean {\n if (transport !== \"sse\") return false;\n const normalized = url.split(\"?\")[0].replace(/\\/+$/, \"\");\n return normalized === LINEAR_DEPRECATED_SSE_URL;\n}\n\ntype SdkMcpServerConfig = Record<string, SettingsValue>;\ntype SdkMcpConfig = { mcpServers: Record<string, SdkMcpServerConfig> };\n\n/**\n * Parse an SDK mcp_config value ({ mcpServers: { ... } }) and convert it\n * to the frontend MCPConfig format used by UI components.\n */\nexport function parseMcpConfig(value: unknown): MCPConfig {\n if (!value || typeof value !== \"object\") {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const obj = value as Record<string, unknown>;\n\n if (\n !(\"mcpServers\" in obj) ||\n !obj.mcpServers ||\n typeof obj.mcpServers !== \"object\"\n ) {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const sseServers: (string | MCPSSEServer)[] = [];\n const stdioServers: MCPStdioServer[] = [];\n const shttpServers: (string | MCPSHTTPServer)[] = [];\n // Legacy Linear SSE entries rewritten to the /mcp endpoint. Collected\n // separately and merged after the loop so an existing hand-added /mcp\n // entry (with its own api_key/timeout) wins over the migrated one.\n const migratedShttpServers: MCPSHTTPServer[] = [];\n\n const mcpServers = obj.mcpServers as Record<string, Record<string, unknown>>;\n\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n if (!serverConfig || typeof serverConfig !== \"object\") continue;\n\n const url = serverConfig.url as string | undefined;\n\n if (url) {\n const transport = serverConfig.transport as string | undefined;\n const auth = serverConfig.auth as string | undefined;\n const apiKey =\n typeof auth === \"string\" && auth !== \"oauth\" ? auth : undefined;\n\n if (isDeprecatedLinearSse(url, transport)) {\n const server: MCPSHTTPServer = { url: LINEAR_SHTTP_URL };\n if (apiKey) server.api_key = apiKey;\n migratedShttpServers.push(server);\n } else if (transport === \"sse\") {\n const server: MCPSSEServer = { url };\n if (apiKey) server.api_key = apiKey;\n sseServers.push(server);\n } else {\n const server: MCPSHTTPServer = { url };\n if (apiKey) server.api_key = apiKey;\n if (serverConfig.timeout != null) {\n server.timeout = serverConfig.timeout as number;\n }\n shttpServers.push(server);\n }\n } else {\n const stdioServer: MCPStdioServer = {\n name: serverName,\n command: serverConfig.command as string,\n };\n if (serverConfig.args) {\n stdioServer.args = serverConfig.args as string[];\n }\n if (serverConfig.env) {\n stdioServer.env = serverConfig.env as Record<string, string>;\n }\n stdioServers.push(stdioServer);\n }\n }\n\n const normalizeUrl = (u: string) => u.replace(/\\/+$/, \"\");\n for (const migrated of migratedShttpServers) {\n const alreadyPresent = shttpServers.some((entry) => {\n const entryUrl = typeof entry === \"string\" ? entry : entry.url;\n return normalizeUrl(entryUrl) === normalizeUrl(migrated.url);\n });\n if (!alreadyPresent) shttpServers.push(migrated);\n }\n\n return {\n sse_servers: sseServers,\n stdio_servers: stdioServers,\n shttp_servers: shttpServers,\n };\n}\n\n/**\n * Convert the frontend MCPConfig format back to the SDK { mcpServers: { ... } }\n * shape expected by agent_settings.mcp_config on the backend.\n *\n * Names are only suffixed (``_1``, ``_2``, …) when an earlier entry has\n * already claimed the bare base name. We intentionally do NOT use a single\n * monotonic counter across server types: that would, for example, rename a\n * stdio server \"myname\" to \"myname_1\" the moment any sse/shttp entry is\n * persisted ahead of it, and shift the suffix on every save as the count\n * of other server types changes. With per-base collision suffixing,\n * unrelated entries keep their human-meaningful names stable across edits.\n */\nexport function toSdkMcpConfig(config: MCPConfig): SdkMcpConfig | null {\n const mcpServers: Record<string, SdkMcpServerConfig> = {};\n\n const reserve = (base: string): string => {\n if (!(base in mcpServers)) return base;\n let i = 1;\n while (`${base}_${i}` in mcpServers) i += 1;\n return `${base}_${i}`;\n };\n\n for (const entry of config.sse_servers) {\n const server: SdkMcpServerConfig = {};\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n server.url = entry.url;\n if (entry.api_key) server.auth = entry.api_key;\n }\n server.transport = \"sse\";\n mcpServers[reserve(\"sse\")] = server;\n }\n\n for (const entry of config.shttp_servers) {\n const server: SdkMcpServerConfig = {};\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n server.url = entry.url;\n if (entry.api_key) server.auth = entry.api_key;\n if (entry.timeout != null) server.timeout = entry.timeout;\n }\n mcpServers[reserve(\"shttp\")] = server;\n }\n\n for (const entry of config.stdio_servers) {\n const server: SdkMcpServerConfig = {\n command: entry.command,\n };\n if (entry.args) server.args = entry.args;\n if (entry.env) server.env = entry.env;\n mcpServers[reserve(entry.name || \"stdio\")] = server;\n }\n\n return Object.keys(mcpServers).length > 0 ? { mcpServers } : null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp-config.cjs","names":[],"sources":["../../src/utils/mcp-config.ts"],"sourcesContent":["import {\n MCPConfig,\n MCPSSEServer,\n MCPSHTTPServer,\n MCPStdioServer,\n SettingsValue,\n} from \"#/types/settings\";\n\nconst EMPTY_MCP_CONFIG: MCPConfig = {\n sse_servers: [],\n stdio_servers: [],\n shttp_servers: [],\n};\n\nconst LINEAR_DEPRECATED_SSE_URL = \"https://mcp.linear.app/sse\";\nconst LINEAR_SHTTP_URL = \"https://mcp.linear.app/mcp\";\n\n/**\n * Linear removed its MCP SSE transport (the /sse endpoint rejects every\n * call since 2026-04-08). Detect persisted configs that still point at\n * the dead endpoint so they can be migrated to streamable HTTP at the\n * /mcp replacement. Matches only the exact deprecated URL (tolerating a\n * trailing slash or query string) — nothing else is rewritten.\n */\nfunction isDeprecatedLinearSse(\n url: string,\n transport: string | undefined,\n): boolean {\n if (transport !== \"sse\") return false;\n const normalized = url.split(\"?\")[0].replace(/\\/+$/, \"\");\n return normalized === LINEAR_DEPRECATED_SSE_URL;\n}\n\ntype SdkMcpServerConfig = Record<string, SettingsValue>;\ntype SdkMcpConfig = { mcpServers: Record<string, SdkMcpServerConfig> };\n\nfunction apiKeyFromAuthorizationHeader(value: unknown): string | undefined {\n if (Array.isArray(value)) {\n return value\n .map(apiKeyFromAuthorizationHeader)\n .find((apiKey) => apiKey !== undefined);\n }\n\n if (typeof value !== \"string\" || value.length === 0) return undefined;\n const bearer = value.match(/^Bearer\\s+(.+)$/i);\n return bearer ? bearer[1] : value;\n}\n\nfunction apiKeyFromServerConfig(\n serverConfig: Record<string, unknown>,\n): string | undefined {\n const headers = serverConfig.headers;\n const authorization =\n headers && typeof headers === \"object\"\n ? ((headers as Record<string, unknown>).Authorization ??\n (headers as Record<string, unknown>).authorization)\n : undefined;\n const headerApiKey = apiKeyFromAuthorizationHeader(authorization);\n if (headerApiKey) return headerApiKey;\n\n const auth = serverConfig.auth;\n return typeof auth === \"string\" && auth !== \"oauth\" ? auth : undefined;\n}\n\nfunction getAuthorizationHeaders(apiKey: string | undefined) {\n if (!apiKey) return {};\n return {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n },\n };\n}\n\n/**\n * Parse an SDK mcp_config value ({ mcpServers: { ... } }) and convert it\n * to the frontend MCPConfig format used by UI components.\n */\nexport function parseMcpConfig(value: unknown): MCPConfig {\n if (!value || typeof value !== \"object\") {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const obj = value as Record<string, unknown>;\n\n if (\n !(\"mcpServers\" in obj) ||\n !obj.mcpServers ||\n typeof obj.mcpServers !== \"object\"\n ) {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const sseServers: (string | MCPSSEServer)[] = [];\n const stdioServers: MCPStdioServer[] = [];\n const shttpServers: (string | MCPSHTTPServer)[] = [];\n // Legacy Linear SSE entries rewritten to the /mcp endpoint. Collected\n // separately and merged after the loop so an existing hand-added /mcp\n // entry (with its own api_key/timeout) wins over the migrated one.\n const migratedShttpServers: MCPSHTTPServer[] = [];\n\n const mcpServers = obj.mcpServers as Record<string, Record<string, unknown>>;\n\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n if (!serverConfig || typeof serverConfig !== \"object\") continue;\n\n const url = serverConfig.url as string | undefined;\n\n if (url) {\n const transport = serverConfig.transport as string | undefined;\n const apiKey = apiKeyFromServerConfig(serverConfig);\n\n if (isDeprecatedLinearSse(url, transport)) {\n const server: MCPSHTTPServer = { url: LINEAR_SHTTP_URL };\n if (apiKey) server.api_key = apiKey;\n migratedShttpServers.push(server);\n } else if (transport === \"sse\") {\n const server: MCPSSEServer = { url };\n if (apiKey) server.api_key = apiKey;\n sseServers.push(server);\n } else {\n const server: MCPSHTTPServer = { url };\n if (apiKey) server.api_key = apiKey;\n if (serverConfig.timeout != null) {\n server.timeout = serverConfig.timeout as number;\n }\n shttpServers.push(server);\n }\n } else {\n const stdioServer: MCPStdioServer = {\n name: serverName,\n command: serverConfig.command as string,\n };\n if (serverConfig.args) {\n stdioServer.args = serverConfig.args as string[];\n }\n if (serverConfig.env) {\n stdioServer.env = serverConfig.env as Record<string, string>;\n }\n stdioServers.push(stdioServer);\n }\n }\n\n const normalizeUrl = (u: string) => u.replace(/\\/+$/, \"\");\n for (const migrated of migratedShttpServers) {\n const alreadyPresent = shttpServers.some((entry) => {\n const entryUrl = typeof entry === \"string\" ? entry : entry.url;\n return normalizeUrl(entryUrl) === normalizeUrl(migrated.url);\n });\n if (!alreadyPresent) shttpServers.push(migrated);\n }\n\n return {\n sse_servers: sseServers,\n stdio_servers: stdioServers,\n shttp_servers: shttpServers,\n };\n}\n\n/**\n * Convert the frontend MCPConfig format back to the SDK { mcpServers: { ... } }\n * shape expected by agent_settings.mcp_config on the backend.\n *\n * Names are only suffixed (``_1``, ``_2``, …) when an earlier entry has\n * already claimed the bare base name. We intentionally do NOT use a single\n * monotonic counter across server types: that would, for example, rename a\n * stdio server \"myname\" to \"myname_1\" the moment any sse/shttp entry is\n * persisted ahead of it, and shift the suffix on every save as the count\n * of other server types changes. With per-base collision suffixing,\n * unrelated entries keep their human-meaningful names stable across edits.\n */\nexport function toSdkMcpConfig(config: MCPConfig): SdkMcpConfig | null {\n const mcpServers: Record<string, SdkMcpServerConfig> = {};\n\n const reserve = (base: string): string => {\n if (!(base in mcpServers)) return base;\n let i = 1;\n while (`${base}_${i}` in mcpServers) i += 1;\n return `${base}_${i}`;\n };\n\n for (const entry of config.sse_servers) {\n const server: SdkMcpServerConfig = {};\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n server.url = entry.url;\n Object.assign(server, getAuthorizationHeaders(entry.api_key));\n }\n server.transport = \"sse\";\n mcpServers[reserve(\"sse\")] = server;\n }\n\n for (const entry of config.shttp_servers) {\n const server: SdkMcpServerConfig = {};\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n server.url = entry.url;\n Object.assign(server, getAuthorizationHeaders(entry.api_key));\n if (entry.timeout != null) server.timeout = entry.timeout;\n }\n mcpServers[reserve(\"shttp\")] = server;\n }\n\n for (const entry of config.stdio_servers) {\n const server: SdkMcpServerConfig = {\n command: entry.command,\n };\n if (entry.args) server.args = entry.args;\n if (entry.env) server.env = entry.env;\n mcpServers[reserve(entry.name || \"stdio\")] = server;\n }\n\n return Object.keys(mcpServers).length > 0 ? { mcpServers } : null;\n}\n"],"mappings":"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"}
@@ -7,43 +7,58 @@ var e = {
7
7
  function r(e, n) {
8
8
  return n === "sse" ? e.split("?")[0].replace(/\/+$/, "") === t : !1;
9
9
  }
10
- function i(t) {
10
+ function i(e) {
11
+ if (Array.isArray(e)) return e.map(i).find((e) => e !== void 0);
12
+ if (typeof e != "string" || e.length === 0) return;
13
+ let t = e.match(/^Bearer\s+(.+)$/i);
14
+ return t ? t[1] : e;
15
+ }
16
+ function a(e) {
17
+ let t = e.headers, n = i(t && typeof t == "object" ? t.Authorization ?? t.authorization : void 0);
18
+ if (n) return n;
19
+ let r = e.auth;
20
+ return typeof r == "string" && r !== "oauth" ? r : void 0;
21
+ }
22
+ function o(e) {
23
+ return e ? { headers: { Authorization: `Bearer ${e}` } } : {};
24
+ }
25
+ function s(t) {
11
26
  if (!t || typeof t != "object") return { ...e };
12
27
  let i = t;
13
28
  if (!("mcpServers" in i) || !i.mcpServers || typeof i.mcpServers != "object") return { ...e };
14
- let a = [], o = [], s = [], c = [], l = i.mcpServers;
15
- for (let [e, t] of Object.entries(l)) {
29
+ let o = [], s = [], c = [], l = [], u = i.mcpServers;
30
+ for (let [e, t] of Object.entries(u)) {
16
31
  if (!t || typeof t != "object") continue;
17
32
  let i = t.url;
18
33
  if (i) {
19
- let e = t.transport, o = t.auth, l = typeof o == "string" && o !== "oauth" ? o : void 0;
34
+ let e = t.transport, s = a(t);
20
35
  if (r(i, e)) {
21
36
  let e = { url: n };
22
- l && (e.api_key = l), c.push(e);
37
+ s && (e.api_key = s), l.push(e);
23
38
  } else if (e === "sse") {
24
39
  let e = { url: i };
25
- l && (e.api_key = l), a.push(e);
40
+ s && (e.api_key = s), o.push(e);
26
41
  } else {
27
42
  let e = { url: i };
28
- l && (e.api_key = l), t.timeout != null && (e.timeout = t.timeout), s.push(e);
43
+ s && (e.api_key = s), t.timeout != null && (e.timeout = t.timeout), c.push(e);
29
44
  }
30
45
  } else {
31
46
  let n = {
32
47
  name: e,
33
48
  command: t.command
34
49
  };
35
- t.args && (n.args = t.args), t.env && (n.env = t.env), o.push(n);
50
+ t.args && (n.args = t.args), t.env && (n.env = t.env), s.push(n);
36
51
  }
37
52
  }
38
- let u = (e) => e.replace(/\/+$/, "");
39
- for (let e of c) s.some((t) => u(typeof t == "string" ? t : t.url) === u(e.url)) || s.push(e);
53
+ let d = (e) => e.replace(/\/+$/, "");
54
+ for (let e of l) c.some((t) => d(typeof t == "string" ? t : t.url) === d(e.url)) || c.push(e);
40
55
  return {
41
- sse_servers: a,
42
- stdio_servers: o,
43
- shttp_servers: s
56
+ sse_servers: o,
57
+ stdio_servers: s,
58
+ shttp_servers: c
44
59
  };
45
60
  }
46
- function a(e) {
61
+ function c(e) {
47
62
  let t = {}, n = (e) => {
48
63
  if (!(e in t)) return e;
49
64
  let n = 1;
@@ -52,11 +67,11 @@ function a(e) {
52
67
  };
53
68
  for (let r of e.sse_servers) {
54
69
  let e = {};
55
- typeof r == "string" ? e.url = r : (e.url = r.url, r.api_key && (e.auth = r.api_key)), e.transport = "sse", t[n("sse")] = e;
70
+ typeof r == "string" ? e.url = r : (e.url = r.url, Object.assign(e, o(r.api_key))), e.transport = "sse", t[n("sse")] = e;
56
71
  }
57
72
  for (let r of e.shttp_servers) {
58
73
  let e = {};
59
- typeof r == "string" ? e.url = r : (e.url = r.url, r.api_key && (e.auth = r.api_key), r.timeout != null && (e.timeout = r.timeout)), t[n("shttp")] = e;
74
+ typeof r == "string" ? e.url = r : (e.url = r.url, Object.assign(e, o(r.api_key)), r.timeout != null && (e.timeout = r.timeout)), t[n("shttp")] = e;
60
75
  }
61
76
  for (let r of e.stdio_servers) {
62
77
  let e = { command: r.command };
@@ -65,6 +80,6 @@ function a(e) {
65
80
  return Object.keys(t).length > 0 ? { mcpServers: t } : null;
66
81
  }
67
82
  //#endregion
68
- export { i as parseMcpConfig, a as toSdkMcpConfig };
83
+ export { s as parseMcpConfig, c as toSdkMcpConfig };
69
84
 
70
85
  //# sourceMappingURL=mcp-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-config.js","names":[],"sources":["../../src/utils/mcp-config.ts"],"sourcesContent":["import {\n MCPConfig,\n MCPSSEServer,\n MCPSHTTPServer,\n MCPStdioServer,\n SettingsValue,\n} from \"#/types/settings\";\n\nconst EMPTY_MCP_CONFIG: MCPConfig = {\n sse_servers: [],\n stdio_servers: [],\n shttp_servers: [],\n};\n\nconst LINEAR_DEPRECATED_SSE_URL = \"https://mcp.linear.app/sse\";\nconst LINEAR_SHTTP_URL = \"https://mcp.linear.app/mcp\";\n\n/**\n * Linear removed its MCP SSE transport (the /sse endpoint rejects every\n * call since 2026-04-08). Detect persisted configs that still point at\n * the dead endpoint so they can be migrated to streamable HTTP at the\n * /mcp replacement. Matches only the exact deprecated URL (tolerating a\n * trailing slash or query string) — nothing else is rewritten.\n */\nfunction isDeprecatedLinearSse(\n url: string,\n transport: string | undefined,\n): boolean {\n if (transport !== \"sse\") return false;\n const normalized = url.split(\"?\")[0].replace(/\\/+$/, \"\");\n return normalized === LINEAR_DEPRECATED_SSE_URL;\n}\n\ntype SdkMcpServerConfig = Record<string, SettingsValue>;\ntype SdkMcpConfig = { mcpServers: Record<string, SdkMcpServerConfig> };\n\n/**\n * Parse an SDK mcp_config value ({ mcpServers: { ... } }) and convert it\n * to the frontend MCPConfig format used by UI components.\n */\nexport function parseMcpConfig(value: unknown): MCPConfig {\n if (!value || typeof value !== \"object\") {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const obj = value as Record<string, unknown>;\n\n if (\n !(\"mcpServers\" in obj) ||\n !obj.mcpServers ||\n typeof obj.mcpServers !== \"object\"\n ) {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const sseServers: (string | MCPSSEServer)[] = [];\n const stdioServers: MCPStdioServer[] = [];\n const shttpServers: (string | MCPSHTTPServer)[] = [];\n // Legacy Linear SSE entries rewritten to the /mcp endpoint. Collected\n // separately and merged after the loop so an existing hand-added /mcp\n // entry (with its own api_key/timeout) wins over the migrated one.\n const migratedShttpServers: MCPSHTTPServer[] = [];\n\n const mcpServers = obj.mcpServers as Record<string, Record<string, unknown>>;\n\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n if (!serverConfig || typeof serverConfig !== \"object\") continue;\n\n const url = serverConfig.url as string | undefined;\n\n if (url) {\n const transport = serverConfig.transport as string | undefined;\n const auth = serverConfig.auth as string | undefined;\n const apiKey =\n typeof auth === \"string\" && auth !== \"oauth\" ? auth : undefined;\n\n if (isDeprecatedLinearSse(url, transport)) {\n const server: MCPSHTTPServer = { url: LINEAR_SHTTP_URL };\n if (apiKey) server.api_key = apiKey;\n migratedShttpServers.push(server);\n } else if (transport === \"sse\") {\n const server: MCPSSEServer = { url };\n if (apiKey) server.api_key = apiKey;\n sseServers.push(server);\n } else {\n const server: MCPSHTTPServer = { url };\n if (apiKey) server.api_key = apiKey;\n if (serverConfig.timeout != null) {\n server.timeout = serverConfig.timeout as number;\n }\n shttpServers.push(server);\n }\n } else {\n const stdioServer: MCPStdioServer = {\n name: serverName,\n command: serverConfig.command as string,\n };\n if (serverConfig.args) {\n stdioServer.args = serverConfig.args as string[];\n }\n if (serverConfig.env) {\n stdioServer.env = serverConfig.env as Record<string, string>;\n }\n stdioServers.push(stdioServer);\n }\n }\n\n const normalizeUrl = (u: string) => u.replace(/\\/+$/, \"\");\n for (const migrated of migratedShttpServers) {\n const alreadyPresent = shttpServers.some((entry) => {\n const entryUrl = typeof entry === \"string\" ? entry : entry.url;\n return normalizeUrl(entryUrl) === normalizeUrl(migrated.url);\n });\n if (!alreadyPresent) shttpServers.push(migrated);\n }\n\n return {\n sse_servers: sseServers,\n stdio_servers: stdioServers,\n shttp_servers: shttpServers,\n };\n}\n\n/**\n * Convert the frontend MCPConfig format back to the SDK { mcpServers: { ... } }\n * shape expected by agent_settings.mcp_config on the backend.\n *\n * Names are only suffixed (``_1``, ``_2``, …) when an earlier entry has\n * already claimed the bare base name. We intentionally do NOT use a single\n * monotonic counter across server types: that would, for example, rename a\n * stdio server \"myname\" to \"myname_1\" the moment any sse/shttp entry is\n * persisted ahead of it, and shift the suffix on every save as the count\n * of other server types changes. With per-base collision suffixing,\n * unrelated entries keep their human-meaningful names stable across edits.\n */\nexport function toSdkMcpConfig(config: MCPConfig): SdkMcpConfig | null {\n const mcpServers: Record<string, SdkMcpServerConfig> = {};\n\n const reserve = (base: string): string => {\n if (!(base in mcpServers)) return base;\n let i = 1;\n while (`${base}_${i}` in mcpServers) i += 1;\n return `${base}_${i}`;\n };\n\n for (const entry of config.sse_servers) {\n const server: SdkMcpServerConfig = {};\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n server.url = entry.url;\n if (entry.api_key) server.auth = entry.api_key;\n }\n server.transport = \"sse\";\n mcpServers[reserve(\"sse\")] = server;\n }\n\n for (const entry of config.shttp_servers) {\n const server: SdkMcpServerConfig = {};\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n server.url = entry.url;\n if (entry.api_key) server.auth = entry.api_key;\n if (entry.timeout != null) server.timeout = entry.timeout;\n }\n mcpServers[reserve(\"shttp\")] = server;\n }\n\n for (const entry of config.stdio_servers) {\n const server: SdkMcpServerConfig = {\n command: entry.command,\n };\n if (entry.args) server.args = entry.args;\n if (entry.env) server.env = entry.env;\n mcpServers[reserve(entry.name || \"stdio\")] = server;\n }\n\n return Object.keys(mcpServers).length > 0 ? { mcpServers } : null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp-config.js","names":[],"sources":["../../src/utils/mcp-config.ts"],"sourcesContent":["import {\n MCPConfig,\n MCPSSEServer,\n MCPSHTTPServer,\n MCPStdioServer,\n SettingsValue,\n} from \"#/types/settings\";\n\nconst EMPTY_MCP_CONFIG: MCPConfig = {\n sse_servers: [],\n stdio_servers: [],\n shttp_servers: [],\n};\n\nconst LINEAR_DEPRECATED_SSE_URL = \"https://mcp.linear.app/sse\";\nconst LINEAR_SHTTP_URL = \"https://mcp.linear.app/mcp\";\n\n/**\n * Linear removed its MCP SSE transport (the /sse endpoint rejects every\n * call since 2026-04-08). Detect persisted configs that still point at\n * the dead endpoint so they can be migrated to streamable HTTP at the\n * /mcp replacement. Matches only the exact deprecated URL (tolerating a\n * trailing slash or query string) — nothing else is rewritten.\n */\nfunction isDeprecatedLinearSse(\n url: string,\n transport: string | undefined,\n): boolean {\n if (transport !== \"sse\") return false;\n const normalized = url.split(\"?\")[0].replace(/\\/+$/, \"\");\n return normalized === LINEAR_DEPRECATED_SSE_URL;\n}\n\ntype SdkMcpServerConfig = Record<string, SettingsValue>;\ntype SdkMcpConfig = { mcpServers: Record<string, SdkMcpServerConfig> };\n\nfunction apiKeyFromAuthorizationHeader(value: unknown): string | undefined {\n if (Array.isArray(value)) {\n return value\n .map(apiKeyFromAuthorizationHeader)\n .find((apiKey) => apiKey !== undefined);\n }\n\n if (typeof value !== \"string\" || value.length === 0) return undefined;\n const bearer = value.match(/^Bearer\\s+(.+)$/i);\n return bearer ? bearer[1] : value;\n}\n\nfunction apiKeyFromServerConfig(\n serverConfig: Record<string, unknown>,\n): string | undefined {\n const headers = serverConfig.headers;\n const authorization =\n headers && typeof headers === \"object\"\n ? ((headers as Record<string, unknown>).Authorization ??\n (headers as Record<string, unknown>).authorization)\n : undefined;\n const headerApiKey = apiKeyFromAuthorizationHeader(authorization);\n if (headerApiKey) return headerApiKey;\n\n const auth = serverConfig.auth;\n return typeof auth === \"string\" && auth !== \"oauth\" ? auth : undefined;\n}\n\nfunction getAuthorizationHeaders(apiKey: string | undefined) {\n if (!apiKey) return {};\n return {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n },\n };\n}\n\n/**\n * Parse an SDK mcp_config value ({ mcpServers: { ... } }) and convert it\n * to the frontend MCPConfig format used by UI components.\n */\nexport function parseMcpConfig(value: unknown): MCPConfig {\n if (!value || typeof value !== \"object\") {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const obj = value as Record<string, unknown>;\n\n if (\n !(\"mcpServers\" in obj) ||\n !obj.mcpServers ||\n typeof obj.mcpServers !== \"object\"\n ) {\n return { ...EMPTY_MCP_CONFIG };\n }\n\n const sseServers: (string | MCPSSEServer)[] = [];\n const stdioServers: MCPStdioServer[] = [];\n const shttpServers: (string | MCPSHTTPServer)[] = [];\n // Legacy Linear SSE entries rewritten to the /mcp endpoint. Collected\n // separately and merged after the loop so an existing hand-added /mcp\n // entry (with its own api_key/timeout) wins over the migrated one.\n const migratedShttpServers: MCPSHTTPServer[] = [];\n\n const mcpServers = obj.mcpServers as Record<string, Record<string, unknown>>;\n\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n if (!serverConfig || typeof serverConfig !== \"object\") continue;\n\n const url = serverConfig.url as string | undefined;\n\n if (url) {\n const transport = serverConfig.transport as string | undefined;\n const apiKey = apiKeyFromServerConfig(serverConfig);\n\n if (isDeprecatedLinearSse(url, transport)) {\n const server: MCPSHTTPServer = { url: LINEAR_SHTTP_URL };\n if (apiKey) server.api_key = apiKey;\n migratedShttpServers.push(server);\n } else if (transport === \"sse\") {\n const server: MCPSSEServer = { url };\n if (apiKey) server.api_key = apiKey;\n sseServers.push(server);\n } else {\n const server: MCPSHTTPServer = { url };\n if (apiKey) server.api_key = apiKey;\n if (serverConfig.timeout != null) {\n server.timeout = serverConfig.timeout as number;\n }\n shttpServers.push(server);\n }\n } else {\n const stdioServer: MCPStdioServer = {\n name: serverName,\n command: serverConfig.command as string,\n };\n if (serverConfig.args) {\n stdioServer.args = serverConfig.args as string[];\n }\n if (serverConfig.env) {\n stdioServer.env = serverConfig.env as Record<string, string>;\n }\n stdioServers.push(stdioServer);\n }\n }\n\n const normalizeUrl = (u: string) => u.replace(/\\/+$/, \"\");\n for (const migrated of migratedShttpServers) {\n const alreadyPresent = shttpServers.some((entry) => {\n const entryUrl = typeof entry === \"string\" ? entry : entry.url;\n return normalizeUrl(entryUrl) === normalizeUrl(migrated.url);\n });\n if (!alreadyPresent) shttpServers.push(migrated);\n }\n\n return {\n sse_servers: sseServers,\n stdio_servers: stdioServers,\n shttp_servers: shttpServers,\n };\n}\n\n/**\n * Convert the frontend MCPConfig format back to the SDK { mcpServers: { ... } }\n * shape expected by agent_settings.mcp_config on the backend.\n *\n * Names are only suffixed (``_1``, ``_2``, …) when an earlier entry has\n * already claimed the bare base name. We intentionally do NOT use a single\n * monotonic counter across server types: that would, for example, rename a\n * stdio server \"myname\" to \"myname_1\" the moment any sse/shttp entry is\n * persisted ahead of it, and shift the suffix on every save as the count\n * of other server types changes. With per-base collision suffixing,\n * unrelated entries keep their human-meaningful names stable across edits.\n */\nexport function toSdkMcpConfig(config: MCPConfig): SdkMcpConfig | null {\n const mcpServers: Record<string, SdkMcpServerConfig> = {};\n\n const reserve = (base: string): string => {\n if (!(base in mcpServers)) return base;\n let i = 1;\n while (`${base}_${i}` in mcpServers) i += 1;\n return `${base}_${i}`;\n };\n\n for (const entry of config.sse_servers) {\n const server: SdkMcpServerConfig = {};\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n server.url = entry.url;\n Object.assign(server, getAuthorizationHeaders(entry.api_key));\n }\n server.transport = \"sse\";\n mcpServers[reserve(\"sse\")] = server;\n }\n\n for (const entry of config.shttp_servers) {\n const server: SdkMcpServerConfig = {};\n if (typeof entry === \"string\") {\n server.url = entry;\n } else {\n server.url = entry.url;\n Object.assign(server, getAuthorizationHeaders(entry.api_key));\n if (entry.timeout != null) server.timeout = entry.timeout;\n }\n mcpServers[reserve(\"shttp\")] = server;\n }\n\n for (const entry of config.stdio_servers) {\n const server: SdkMcpServerConfig = {\n command: entry.command,\n };\n if (entry.args) server.args = entry.args;\n if (entry.env) server.env = entry.env;\n mcpServers[reserve(entry.name || \"stdio\")] = server;\n }\n\n return Object.keys(mcpServers).length > 0 ? { mcpServers } : null;\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`./mcp-marketplace-utils.cjs`),t=require(`../node_modules/@openhands/extensions/integrations/index.cjs`);var n=new Set([`invalid_auth`,`not_authed`,`account_inactive`,`token_revoked`,`token_expired`]),r={slack:{toolCall:{name:`slack_list_channels`,arguments:{limit:1}},interpret:e=>{if(e.is_error)return e.text||`tool call failed`;try{let t=JSON.parse(e.text);if(t?.ok===!1&&n.has(t.error))return String(t.error)}catch{}return null}}};function i(n){let i=e.findCatalogEntryForServer(n,e.getMcpMarketplaceCatalog(t.default));return i?r[i.id]:void 0}exports.getCredentialValidationForServer=i;
2
+ //# sourceMappingURL=mcp-credential-validation.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-credential-validation.cjs","names":[],"sources":["../../src/utils/mcp-credential-validation.ts"],"sourcesContent":["import { INTEGRATION_CATALOG as MCP_MARKETPLACE } from \"@openhands/extensions/integrations\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n} from \"#/utils/mcp-marketplace-utils\";\nimport type {\n MCPServerConfig,\n MCPTestToolCall,\n MCPTestToolResult,\n} from \"#/types/mcp-server\";\n\n/**\n * Credential validation specs for marketplace MCP servers whose credentials\n * are only exercised on tool invocation (listing tools succeeds with any\n * credentials). The test endpoint runs `toolCall` after listing and reports\n * the outcome verbatim; `interpret` decides whether that outcome proves the\n * credentials are invalid.\n *\n * `toolCall` MUST be read-only — it runs on every \"Test connection\" /\n * pre-save validation.\n */\nexport interface CredentialValidation {\n toolCall: MCPTestToolCall;\n /** Returns the provider's error code/message, or null when creds pass. */\n interpret: (toolResult: MCPTestToolResult) => string | null;\n}\n\n/**\n * Slack error codes that mean the credentials themselves are bad. Anything\n * else (e.g. `missing_scope`) proves the token *authenticated* — a valid\n * token lacking a scope must not be reported as invalid credentials.\n */\nconst SLACK_AUTH_FAILURES = new Set([\n \"invalid_auth\",\n \"not_authed\",\n \"account_inactive\",\n \"token_revoked\",\n \"token_expired\",\n]);\n\nconst VALIDATION_BY_ENTRY_ID: Record<string, CredentialValidation> = {\n slack: {\n // Read-only: lists at most one channel. The Slack MCP server returns\n // the raw Slack API JSON ({ok: boolean, error?: string}) as text.\n toolCall: { name: \"slack_list_channels\", arguments: { limit: 1 } },\n interpret: (toolResult) => {\n if (toolResult.is_error) {\n return toolResult.text || \"tool call failed\";\n }\n try {\n const parsed = JSON.parse(toolResult.text);\n if (parsed?.ok === false && SLACK_AUTH_FAILURES.has(parsed.error)) {\n return String(parsed.error);\n }\n } catch {\n // Non-JSON payload — make no claim about the credentials.\n }\n return null;\n },\n },\n};\n\n/**\n * Look up the credential validation for a server by matching it to its\n * marketplace catalog entry (same matching the MCP page uses for icons).\n * Returns undefined for custom servers — their test behaves as before.\n */\nexport function getCredentialValidationForServer(\n server: MCPServerConfig,\n): CredentialValidation | undefined {\n const entry = findCatalogEntryForServer(\n server,\n getMcpMarketplaceCatalog(MCP_MARKETPLACE),\n );\n return entry ? VALIDATION_BY_ENTRY_ID[entry.id] : undefined;\n}\n"],"mappings":"sKAgCA,IAAM,EAAsB,IAAI,IAAI,CAClC,eACA,aACA,mBACA,gBACA,gBACD,CAAC,CAEI,EAA+D,CACnE,MAAO,CAGL,SAAU,CAAE,KAAM,sBAAuB,UAAW,CAAE,MAAO,EAAG,CAAE,CAClE,UAAY,GAAe,CACzB,GAAI,EAAW,SACb,OAAO,EAAW,MAAQ,mBAE5B,GAAI,CACF,IAAM,EAAS,KAAK,MAAM,EAAW,KAAK,CAC1C,GAAI,GAAQ,KAAO,IAAS,EAAoB,IAAI,EAAO,MAAM,CAC/D,OAAO,OAAO,EAAO,MAAM,MAEvB,EAGR,OAAO,MAEV,CACF,CAOD,SAAgB,EACd,EACkC,CAClC,IAAM,EAAQ,EAAA,0BACZ,EACA,EAAA,yBAAyB,EAAA,QAAgB,CAC1C,CACD,OAAO,EAAQ,EAAuB,EAAM,IAAM,IAAA"}
@@ -0,0 +1,22 @@
1
+ import type { MCPServerConfig, MCPTestToolCall, MCPTestToolResult } from "#/types/mcp-server";
2
+ /**
3
+ * Credential validation specs for marketplace MCP servers whose credentials
4
+ * are only exercised on tool invocation (listing tools succeeds with any
5
+ * credentials). The test endpoint runs `toolCall` after listing and reports
6
+ * the outcome verbatim; `interpret` decides whether that outcome proves the
7
+ * credentials are invalid.
8
+ *
9
+ * `toolCall` MUST be read-only — it runs on every "Test connection" /
10
+ * pre-save validation.
11
+ */
12
+ export interface CredentialValidation {
13
+ toolCall: MCPTestToolCall;
14
+ /** Returns the provider's error code/message, or null when creds pass. */
15
+ interpret: (toolResult: MCPTestToolResult) => string | null;
16
+ }
17
+ /**
18
+ * Look up the credential validation for a server by matching it to its
19
+ * marketplace catalog entry (same matching the MCP page uses for icons).
20
+ * Returns undefined for custom servers — their test behaves as before.
21
+ */
22
+ export declare function getCredentialValidationForServer(server: MCPServerConfig): CredentialValidation | undefined;
@@ -0,0 +1,31 @@
1
+ import { findCatalogEntryForServer as e, getMcpMarketplaceCatalog as t } from "./mcp-marketplace-utils.js";
2
+ import n from "../node_modules/@openhands/extensions/integrations/index.js";
3
+ //#region src/utils/mcp-credential-validation.ts
4
+ var r = new Set([
5
+ "invalid_auth",
6
+ "not_authed",
7
+ "account_inactive",
8
+ "token_revoked",
9
+ "token_expired"
10
+ ]), i = { slack: {
11
+ toolCall: {
12
+ name: "slack_list_channels",
13
+ arguments: { limit: 1 }
14
+ },
15
+ interpret: (e) => {
16
+ if (e.is_error) return e.text || "tool call failed";
17
+ try {
18
+ let t = JSON.parse(e.text);
19
+ if (t?.ok === !1 && r.has(t.error)) return String(t.error);
20
+ } catch {}
21
+ return null;
22
+ }
23
+ } };
24
+ function a(r) {
25
+ let a = e(r, t(n));
26
+ return a ? i[a.id] : void 0;
27
+ }
28
+ //#endregion
29
+ export { a as getCredentialValidationForServer };
30
+
31
+ //# sourceMappingURL=mcp-credential-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-credential-validation.js","names":[],"sources":["../../src/utils/mcp-credential-validation.ts"],"sourcesContent":["import { INTEGRATION_CATALOG as MCP_MARKETPLACE } from \"@openhands/extensions/integrations\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n} from \"#/utils/mcp-marketplace-utils\";\nimport type {\n MCPServerConfig,\n MCPTestToolCall,\n MCPTestToolResult,\n} from \"#/types/mcp-server\";\n\n/**\n * Credential validation specs for marketplace MCP servers whose credentials\n * are only exercised on tool invocation (listing tools succeeds with any\n * credentials). The test endpoint runs `toolCall` after listing and reports\n * the outcome verbatim; `interpret` decides whether that outcome proves the\n * credentials are invalid.\n *\n * `toolCall` MUST be read-only — it runs on every \"Test connection\" /\n * pre-save validation.\n */\nexport interface CredentialValidation {\n toolCall: MCPTestToolCall;\n /** Returns the provider's error code/message, or null when creds pass. */\n interpret: (toolResult: MCPTestToolResult) => string | null;\n}\n\n/**\n * Slack error codes that mean the credentials themselves are bad. Anything\n * else (e.g. `missing_scope`) proves the token *authenticated* — a valid\n * token lacking a scope must not be reported as invalid credentials.\n */\nconst SLACK_AUTH_FAILURES = new Set([\n \"invalid_auth\",\n \"not_authed\",\n \"account_inactive\",\n \"token_revoked\",\n \"token_expired\",\n]);\n\nconst VALIDATION_BY_ENTRY_ID: Record<string, CredentialValidation> = {\n slack: {\n // Read-only: lists at most one channel. The Slack MCP server returns\n // the raw Slack API JSON ({ok: boolean, error?: string}) as text.\n toolCall: { name: \"slack_list_channels\", arguments: { limit: 1 } },\n interpret: (toolResult) => {\n if (toolResult.is_error) {\n return toolResult.text || \"tool call failed\";\n }\n try {\n const parsed = JSON.parse(toolResult.text);\n if (parsed?.ok === false && SLACK_AUTH_FAILURES.has(parsed.error)) {\n return String(parsed.error);\n }\n } catch {\n // Non-JSON payload — make no claim about the credentials.\n }\n return null;\n },\n },\n};\n\n/**\n * Look up the credential validation for a server by matching it to its\n * marketplace catalog entry (same matching the MCP page uses for icons).\n * Returns undefined for custom servers — their test behaves as before.\n */\nexport function getCredentialValidationForServer(\n server: MCPServerConfig,\n): CredentialValidation | undefined {\n const entry = findCatalogEntryForServer(\n server,\n getMcpMarketplaceCatalog(MCP_MARKETPLACE),\n );\n return entry ? VALIDATION_BY_ENTRY_ID[entry.id] : undefined;\n}\n"],"mappings":";;;AAgCA,IAAM,IAAsB,IAAI,IAAI;CAClC;CACA;CACA;CACA;CACA;CACD,CAAC,EAEI,IAA+D,EACnE,OAAO;CAGL,UAAU;EAAE,MAAM;EAAuB,WAAW,EAAE,OAAO,GAAG;EAAE;CAClE,YAAY,MAAe;AACzB,MAAI,EAAW,SACb,QAAO,EAAW,QAAQ;AAE5B,MAAI;GACF,IAAM,IAAS,KAAK,MAAM,EAAW,KAAK;AAC1C,OAAI,GAAQ,OAAO,MAAS,EAAoB,IAAI,EAAO,MAAM,CAC/D,QAAO,OAAO,EAAO,MAAM;UAEvB;AAGR,SAAO;;CAEV,EACF;AAOD,SAAgB,EACd,GACkC;CAClC,IAAM,IAAQ,EACZ,GACA,EAAyB,EAAgB,CAC1C;AACD,QAAO,IAAQ,EAAuB,EAAM,MAAM,KAAA"}
@@ -1,2 +1,2 @@
1
- require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../api/agent-server-adapter.cjs`);function t(e){return e.connectionOptions.filter(e=>e.provider===`mcp`&&!!e.transport)}function n(e){let n=t(e);return n.find(t=>t.id===e.defaultConnectionOptionId)??n[0]}function r(e){return e.auth.strategy!==`oauth2`}function i(e){let n=t(e),i=n.find(t=>t.id===e.defaultConnectionOptionId);return i&&r(i)?i:n.find(r)}function a(e){return n(e)?.transport}var o=`https://mcp.linear.app/sse`,s=`https://mcp.linear.app/mcp`,c=`https://linear.app/docs/mcp`;function l(e){return e.id===`linear`?{...e,docsUrl:c,installHint:`Authenticate with a Linear API key (Linear → Settings → Security & access) — sent as a Bearer token. Optional when the endpoint accepts your OAuth session.`,connectionOptions:e.connectionOptions.map(e=>e.transport?.kind===`sse`&&p(e.transport.url,o)?{...e,auth:{...e.auth,strategy:`bearer`},transport:{kind:`shttp`,url:s,apiKeyOptional:e.transport.apiKeyOptional}}:e)}:e}function u(t){return t.id!==`github`||e.getDeploymentMode()!==`docker`?t:{...t,installHint:`Requires a GitHub Personal Access Token (classic or fine-grained).`,connectionOptions:t.connectionOptions.map(e=>e.transport?.kind===`stdio`&&e.transport.command===`docker`?{...e,transport:{...e.transport,command:`github-mcp-server`,args:[`stdio`]}}:e)}}function d(e){return e.map(l).map(u).filter(e=>!!n(e))}var f=e=>{try{return new URL(e)}catch{return null}};function p(e,t){let n=typeof e==`string`?e:``,r=typeof t==`string`?t:``;if(!n||!r)return!1;let i=f(n),a=f(r);return!i||!a?n.replace(/\/+$/,``)===r.replace(/\/+$/,``):i.protocol===a.protocol&&i.host===a.host&&i.pathname.replace(/\/+$/,``)===a.pathname.replace(/\/+$/,``)}function m(e,t){if(e.kind===`shttp`){let n=e.url;return t.type===`shttp`&&!!t.url&&p(t.url,n)}if(e.kind===`sse`){let n=e.url;return t.type===`sse`&&!!t.url&&p(t.url,n)}return t.type===`stdio`&&t.name===e.serverName}function h(e,t){return!e.runtimeAvailability||e.runtimeAvailability===`all`?!0:e.runtimeAvailability===t}function g(e){return e.trim().toLowerCase()}function _(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 v(e,t){let n=g(t);return n?[e.name,e.description,e.id,...e.keywords??[]].join(` `).toLowerCase().includes(n):!0}function y(e,t,n){let r=g(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 b(e,n){return n.find(n=>t(n).some(t=>m(t.transport,e)))}exports.findCatalogEntryForServer=b,exports.getDefaultMcpTransport=a,exports.getInstallableMcpConnectionOption=i,exports.getMarketplaceEntriesByPopularity=_,exports.getMcpMarketplaceCatalog=d,exports.installedServerMatchesQuery=y,exports.isMarketplaceEntryAvailable=h,exports.marketplaceEntryMatchesQuery=v;
1
+ require(`../_virtual/_rolldown/runtime.cjs`);function e(e){return e.connectionOptions.filter(e=>e.provider===`mcp`&&!!e.transport)}function t(t){let n=e(t);return n.find(e=>e.id===t.defaultConnectionOptionId)??n[0]}function n(e){return e.auth.strategy!==`oauth2`}function r(t){let r=e(t),i=r.find(e=>e.id===t.defaultConnectionOptionId);return i&&n(i)?i:r.find(n)}function i(e){return t(e)?.transport}var a=`https://mcp.linear.app/sse`,o=`https://mcp.linear.app/mcp`,s=`https://linear.app/docs/mcp`;function c(e){return e.id===`linear`?{...e,docsUrl:s,installHint:`Authenticate with a Linear API key (Linear → Settings → Security & access) — sent as a Bearer token. Optional when the endpoint accepts your OAuth session.`,connectionOptions:e.connectionOptions.map(e=>e.transport?.kind===`sse`&&d(e.transport.url,a)?{...e,auth:{...e.auth,strategy:`bearer`},transport:{kind:`shttp`,url:o,apiKeyOptional:e.transport.apiKeyOptional}}:e)}:e}function l(e){return e.map(c).filter(e=>!!t(e))}var u=e=>{try{return new URL(e)}catch{return null}};function d(e,t){let n=typeof e==`string`?e:``,r=typeof t==`string`?t:``;if(!n||!r)return!1;let i=u(n),a=u(r);return!i||!a?n.replace(/\/+$/,``)===r.replace(/\/+$/,``):i.protocol===a.protocol&&i.host===a.host&&i.pathname.replace(/\/+$/,``)===a.pathname.replace(/\/+$/,``)}function f(e,t){if(e.kind===`shttp`){let n=e.url;return t.type===`shttp`&&!!t.url&&d(t.url,n)}if(e.kind===`sse`){let n=e.url;return t.type===`sse`&&!!t.url&&d(t.url,n)}return t.type===`stdio`&&t.name===e.serverName}function p(e,t){return!e.runtimeAvailability||e.runtimeAvailability===`all`?!0:e.runtimeAvailability===t}function m(e){return e.trim().toLowerCase()}function h(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 g(e,t){let n=m(t);return n?[e.name,e.description,e.id,...e.keywords??[]].join(` `).toLowerCase().includes(n):!0}function _(e,t,n){let r=m(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 v(t,n){return n.find(n=>e(n).some(e=>f(e.transport,t)))}exports.findCatalogEntryForServer=v,exports.getDefaultMcpTransport=i,exports.getInstallableMcpConnectionOption=r,exports.getMarketplaceEntriesByPopularity=h,exports.getMcpMarketplaceCatalog=l,exports.installedServerMatchesQuery=_,exports.isMarketplaceEntryAvailable=p,exports.marketplaceEntryMatchesQuery=g;
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 IntegrationCatalogEntry as MarketplaceEntry,\n IntegrationConnectionOption,\n IntegrationTransport,\n} from \"@openhands/extensions/integrations\";\nimport { getDeploymentMode } from \"#/api/agent-server-adapter\";\n\nexport type { MarketplaceEntry };\n\nexport type McpMarketplaceConnectionOption = IntegrationConnectionOption & {\n provider: \"mcp\";\n transport: IntegrationTransport;\n};\n\nexport function getMcpConnectionOptions(\n entry: MarketplaceEntry,\n): McpMarketplaceConnectionOption[] {\n return entry.connectionOptions.filter(\n (option): option is McpMarketplaceConnectionOption =>\n option.provider === \"mcp\" && !!option.transport,\n );\n}\n\nexport function getDefaultMcpConnectionOption(\n entry: MarketplaceEntry,\n): McpMarketplaceConnectionOption | undefined {\n const options = getMcpConnectionOptions(entry);\n return (\n options.find((option) => option.id === entry.defaultConnectionOptionId) ??\n options[0]\n );\n}\n\nfunction isLocallyInstallableMcpOption(\n option: McpMarketplaceConnectionOption,\n): boolean {\n // The local install modal writes static MCP server config. OAuth options\n // describe hosted redirect flows, so prefer an API/stdio fallback when one\n // exists and leave OAuth as the default connection for hosted integrations.\n return option.auth.strategy !== \"oauth2\";\n}\n\nexport function getInstallableMcpConnectionOption(\n entry: MarketplaceEntry,\n): McpMarketplaceConnectionOption | undefined {\n const options = getMcpConnectionOptions(entry);\n const defaultOption = options.find(\n (option) => option.id === entry.defaultConnectionOptionId,\n );\n if (defaultOption && isLocallyInstallableMcpOption(defaultOption)) {\n return defaultOption;\n }\n return options.find(isLocallyInstallableMcpOption);\n}\n\nexport function getDefaultMcpTransport(\n entry: MarketplaceEntry,\n): IntegrationTransport | undefined {\n return getDefaultMcpConnectionOption(entry)?.transport;\n}\n\nconst LINEAR_DEPRECATED_SSE_URL = \"https://mcp.linear.app/sse\";\nconst LINEAR_SHTTP_URL = \"https://mcp.linear.app/mcp\";\nconst LINEAR_DOCS_URL = \"https://linear.app/docs/mcp\";\n\n/**\n * Upstream @openhands/extensions still ships Linear's deprecated SSE\n * transport (removed upstream on 2026-04-08; the /sse endpoint now\n * rejects every call). Rewrite the entry to streamable HTTP at the\n * /mcp replacement endpoint until the pinned dependency catches up.\n *\n * The /mcp endpoint authenticates via OAuth 2.1 or a Linear API key\n * sent as \"Authorization: Bearer <token>\". This client has no\n * interactive OAuth flow for MCP installs, so switch the auth\n * strategy from \"none\" to \"bearer\" — the install modal then offers\n * an (optional) API key field and the agent server forwards it as a\n * Bearer header.\n *\n * Patches immutably — the imported catalog JSON is shared module\n * state and must not be mutated.\n */\nfunction patchLinearEntry(entry: MarketplaceEntry): MarketplaceEntry {\n if (entry.id !== \"linear\") return entry;\n return {\n ...entry,\n docsUrl: LINEAR_DOCS_URL,\n installHint:\n \"Authenticate with a Linear API key (Linear → Settings → Security & access) — sent as a Bearer token. Optional when the endpoint accepts your OAuth session.\",\n connectionOptions: entry.connectionOptions.map((option) =>\n option.transport?.kind === \"sse\" &&\n urlsMatch(option.transport.url, LINEAR_DEPRECATED_SSE_URL)\n ? {\n ...option,\n auth: { ...option.auth, strategy: \"bearer\" as const },\n transport: {\n kind: \"shttp\" as const,\n url: LINEAR_SHTTP_URL,\n apiKeyOptional: option.transport.apiKeyOptional,\n },\n }\n : option,\n ),\n };\n}\n\n/**\n * The upstream catalog ships the GitHub MCP server with `command: \"docker\"`\n * (`docker run … ghcr.io/github/github-mcp-server`). This requires Docker-\n * in-Docker when agent-canvas itself runs inside the Docker image, which\n * isn't available. The Docker image pre-installs the native Go binary at\n * `/usr/local/bin/github-mcp-server`, so we rewrite the transport to use\n * it directly.\n *\n * Only applied when `getDeploymentMode()` returns `\"docker\"`.\n */\nfunction patchGitHubEntry(entry: MarketplaceEntry): MarketplaceEntry {\n if (entry.id !== \"github\") return entry;\n if (getDeploymentMode() !== \"docker\") return entry;\n return {\n ...entry,\n installHint:\n \"Requires a GitHub Personal Access Token (classic or fine-grained).\",\n // The upstream @openhands/extensions catalog defines the GitHub entry\n // with `command: \"docker\"` (i.e. `docker run …`). We match on that\n // exact value to replace it with the pre-installed native binary.\n // If the upstream ever changes the command string, this patch becomes\n // a no-op and the original transport is preserved — the worst case is\n // the user falls back to the Docker-based transport (which still works\n // outside the Docker image).\n connectionOptions: entry.connectionOptions.map((option) =>\n option.transport?.kind === \"stdio\" &&\n option.transport.command === \"docker\"\n ? {\n ...option,\n transport: {\n ...option.transport,\n command: \"github-mcp-server\",\n args: [\"stdio\"],\n },\n }\n : option,\n ),\n };\n}\n\nexport function getMcpMarketplaceCatalog(\n catalog: MarketplaceEntry[],\n): MarketplaceEntry[] {\n return catalog\n .map(patchLinearEntry)\n .map(patchGitHubEntry)\n .filter((entry) => !!getDefaultMcpConnectionOption(entry));\n}\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 transport: IntegrationTransport,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n return (\n servers.find((server) => transportMatchesServer(transport, server)) ?? null\n );\n}\n\nexport function findInstalledEntryMatch(\n entry: MarketplaceEntry,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n for (const option of getMcpConnectionOptions(entry)) {\n const match = findInstalledMatch(option.transport, servers);\n if (match) return match;\n }\n return null;\n}\n\nfunction transportMatchesServer(\n transport: IntegrationTransport,\n server: MCPServerConfig,\n): boolean {\n if (transport.kind === \"shttp\") {\n const tplUrl = transport.url;\n return (\n server.type === \"shttp\" && !!server.url && urlsMatch(server.url, tplUrl)\n );\n }\n\n if (transport.kind === \"sse\") {\n const tplUrl = transport.url;\n return (\n server.type === \"sse\" && !!server.url && urlsMatch(server.url, tplUrl)\n );\n }\n\n // stdio: match on the registered server name.\n return server.type === \"stdio\" && server.name === transport.serverName;\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 */\nexport function findCatalogEntryForServer(\n server: MCPServerConfig,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => {\n // Check every MCP option rather than only the default. Some unified\n // integration entries default to OAuth-hosted MCP while still exposing\n // an API/stdio option; existing installed servers should match either.\n return getMcpConnectionOptions(entry).some((option) =>\n transportMatchesServer(option.transport, server),\n );\n });\n}\n"],"mappings":"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"}
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 IntegrationAuthConfig,\n IntegrationCatalogEntry as MarketplaceEntry,\n IntegrationConnectionOption,\n IntegrationTransport,\n} from \"@openhands/extensions/integrations\";\n\nexport type { MarketplaceEntry };\n\ntype McpIntegrationAuthConfig = IntegrationAuthConfig & {\n credentialSecretName?: string;\n saveCredentialAsSecretByDefault?: boolean;\n};\n\nexport type McpMarketplaceConnectionOption = Omit<\n IntegrationConnectionOption,\n \"auth\" | \"provider\" | \"transport\"\n> & {\n provider: \"mcp\";\n transport: IntegrationTransport;\n auth: McpIntegrationAuthConfig;\n};\n\nexport function getMcpConnectionOptions(\n entry: MarketplaceEntry,\n): McpMarketplaceConnectionOption[] {\n return entry.connectionOptions.filter(\n (option): option is McpMarketplaceConnectionOption =>\n option.provider === \"mcp\" && !!option.transport,\n );\n}\n\nexport function getDefaultMcpConnectionOption(\n entry: MarketplaceEntry,\n): McpMarketplaceConnectionOption | undefined {\n const options = getMcpConnectionOptions(entry);\n return (\n options.find((option) => option.id === entry.defaultConnectionOptionId) ??\n options[0]\n );\n}\n\nfunction isLocallyInstallableMcpOption(\n option: McpMarketplaceConnectionOption,\n): boolean {\n // The local install modal writes static MCP server config. OAuth options\n // describe hosted redirect flows, so prefer an API/stdio fallback when one\n // exists and leave OAuth as the default connection for hosted integrations.\n return option.auth.strategy !== \"oauth2\";\n}\n\nexport function getInstallableMcpConnectionOption(\n entry: MarketplaceEntry,\n): McpMarketplaceConnectionOption | undefined {\n const options = getMcpConnectionOptions(entry);\n const defaultOption = options.find(\n (option) => option.id === entry.defaultConnectionOptionId,\n );\n if (defaultOption && isLocallyInstallableMcpOption(defaultOption)) {\n return defaultOption;\n }\n return options.find(isLocallyInstallableMcpOption);\n}\n\nexport function getDefaultMcpTransport(\n entry: MarketplaceEntry,\n): IntegrationTransport | undefined {\n return getDefaultMcpConnectionOption(entry)?.transport;\n}\n\nconst LINEAR_DEPRECATED_SSE_URL = \"https://mcp.linear.app/sse\";\nconst LINEAR_SHTTP_URL = \"https://mcp.linear.app/mcp\";\nconst LINEAR_DOCS_URL = \"https://linear.app/docs/mcp\";\n\n/**\n * Upstream @openhands/extensions still ships Linear's deprecated SSE\n * transport (removed upstream on 2026-04-08; the /sse endpoint now\n * rejects every call). Rewrite the entry to streamable HTTP at the\n * /mcp replacement endpoint until the pinned dependency catches up.\n *\n * The /mcp endpoint authenticates via OAuth 2.1 or a Linear API key\n * sent as \"Authorization: Bearer <token>\". This client has no\n * interactive OAuth flow for MCP installs, so switch the auth\n * strategy from \"none\" to \"bearer\" — the install modal then offers\n * an (optional) API key field and the agent server forwards it as a\n * Bearer header.\n *\n * Patches immutably — the imported catalog JSON is shared module\n * state and must not be mutated.\n */\nfunction patchLinearEntry(entry: MarketplaceEntry): MarketplaceEntry {\n if (entry.id !== \"linear\") return entry;\n return {\n ...entry,\n docsUrl: LINEAR_DOCS_URL,\n installHint:\n \"Authenticate with a Linear API key (Linear → Settings → Security & access) — sent as a Bearer token. Optional when the endpoint accepts your OAuth session.\",\n connectionOptions: entry.connectionOptions.map((option) =>\n option.transport?.kind === \"sse\" &&\n urlsMatch(option.transport.url, LINEAR_DEPRECATED_SSE_URL)\n ? {\n ...option,\n auth: { ...option.auth, strategy: \"bearer\" as const },\n transport: {\n kind: \"shttp\" as const,\n url: LINEAR_SHTTP_URL,\n apiKeyOptional: option.transport.apiKeyOptional,\n },\n }\n : option,\n ),\n };\n}\n\nexport function getMcpMarketplaceCatalog(\n catalog: MarketplaceEntry[],\n): MarketplaceEntry[] {\n return catalog\n .map(patchLinearEntry)\n .filter((entry) => !!getDefaultMcpConnectionOption(entry));\n}\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 transport: IntegrationTransport,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n return (\n servers.find((server) => transportMatchesServer(transport, server)) ?? null\n );\n}\n\nexport function findInstalledEntryMatch(\n entry: MarketplaceEntry,\n servers: MCPServerConfig[],\n): MCPServerConfig | null {\n for (const option of getMcpConnectionOptions(entry)) {\n const match = findInstalledMatch(option.transport, servers);\n if (match) return match;\n }\n return null;\n}\n\nfunction transportMatchesServer(\n transport: IntegrationTransport,\n server: MCPServerConfig,\n): boolean {\n if (transport.kind === \"shttp\") {\n const tplUrl = transport.url;\n return (\n server.type === \"shttp\" && !!server.url && urlsMatch(server.url, tplUrl)\n );\n }\n\n if (transport.kind === \"sse\") {\n const tplUrl = transport.url;\n return (\n server.type === \"sse\" && !!server.url && urlsMatch(server.url, tplUrl)\n );\n }\n\n // stdio: match on the registered server name.\n return server.type === \"stdio\" && server.name === transport.serverName;\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 */\nexport function findCatalogEntryForServer(\n server: MCPServerConfig,\n catalog: MarketplaceEntry[],\n): MarketplaceEntry | undefined {\n return catalog.find((entry) => {\n // Check every MCP option rather than only the default. Some unified\n // integration entries default to OAuth-hosted MCP while still exposing\n // an API/stdio option; existing installed servers should match either.\n return getMcpConnectionOptions(entry).some((option) =>\n transportMatchesServer(option.transport, server),\n );\n });\n}\n"],"mappings":"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"}
@@ -1,9 +1,14 @@
1
1
  import { MCPServerConfig } from "#/types/mcp-server";
2
- import type { IntegrationCatalogEntry as MarketplaceEntry, IntegrationConnectionOption, IntegrationTransport } from "@openhands/extensions/integrations";
2
+ import type { IntegrationAuthConfig, IntegrationCatalogEntry as MarketplaceEntry, IntegrationConnectionOption, IntegrationTransport } from "@openhands/extensions/integrations";
3
3
  export type { MarketplaceEntry };
4
- export type McpMarketplaceConnectionOption = IntegrationConnectionOption & {
4
+ type McpIntegrationAuthConfig = IntegrationAuthConfig & {
5
+ credentialSecretName?: string;
6
+ saveCredentialAsSecretByDefault?: boolean;
7
+ };
8
+ export type McpMarketplaceConnectionOption = Omit<IntegrationConnectionOption, "auth" | "provider" | "transport"> & {
5
9
  provider: "mcp";
6
10
  transport: IntegrationTransport;
11
+ auth: McpIntegrationAuthConfig;
7
12
  };
8
13
  export declare function getMcpConnectionOptions(entry: MarketplaceEntry): McpMarketplaceConnectionOption[];
9
14
  export declare function getDefaultMcpConnectionOption(entry: MarketplaceEntry): McpMarketplaceConnectionOption | undefined;
@@ -1,29 +1,28 @@
1
- import { getDeploymentMode as e } from "../api/agent-server-adapter.js";
2
1
  //#region src/utils/mcp-marketplace-utils.ts
3
- function t(e) {
2
+ function e(e) {
4
3
  return e.connectionOptions.filter((e) => e.provider === "mcp" && !!e.transport);
5
4
  }
6
- function n(e) {
7
- let n = t(e);
8
- return n.find((t) => t.id === e.defaultConnectionOptionId) ?? n[0];
5
+ function t(t) {
6
+ let n = e(t);
7
+ return n.find((e) => e.id === t.defaultConnectionOptionId) ?? n[0];
9
8
  }
10
- function r(e) {
9
+ function n(e) {
11
10
  return e.auth.strategy !== "oauth2";
12
11
  }
13
- function i(e) {
14
- let n = t(e), i = n.find((t) => t.id === e.defaultConnectionOptionId);
15
- return i && r(i) ? i : n.find(r);
12
+ function r(t) {
13
+ let r = e(t), i = r.find((e) => e.id === t.defaultConnectionOptionId);
14
+ return i && n(i) ? i : r.find(n);
16
15
  }
17
- function a(e) {
18
- return n(e)?.transport;
16
+ function i(e) {
17
+ return t(e)?.transport;
19
18
  }
20
- var o = "https://mcp.linear.app/sse", s = "https://mcp.linear.app/mcp", c = "https://linear.app/docs/mcp";
21
- function l(e) {
19
+ var a = "https://mcp.linear.app/sse", o = "https://mcp.linear.app/mcp", s = "https://linear.app/docs/mcp";
20
+ function c(e) {
22
21
  return e.id === "linear" ? {
23
22
  ...e,
24
- docsUrl: c,
23
+ docsUrl: s,
25
24
  installHint: "Authenticate with a Linear API key (Linear → Settings → Security & access) — sent as a Bearer token. Optional when the endpoint accepts your OAuth session.",
26
- connectionOptions: e.connectionOptions.map((e) => e.transport?.kind === "sse" && p(e.transport.url, o) ? {
25
+ connectionOptions: e.connectionOptions.map((e) => e.transport?.kind === "sse" && d(e.transport.url, a) ? {
27
26
  ...e,
28
27
  auth: {
29
28
  ...e.auth,
@@ -31,67 +30,53 @@ function l(e) {
31
30
  },
32
31
  transport: {
33
32
  kind: "shttp",
34
- url: s,
33
+ url: o,
35
34
  apiKeyOptional: e.transport.apiKeyOptional
36
35
  }
37
36
  } : e)
38
37
  } : e;
39
38
  }
40
- function u(t) {
41
- return t.id !== "github" || e() !== "docker" ? t : {
42
- ...t,
43
- installHint: "Requires a GitHub Personal Access Token (classic or fine-grained).",
44
- connectionOptions: t.connectionOptions.map((e) => e.transport?.kind === "stdio" && e.transport.command === "docker" ? {
45
- ...e,
46
- transport: {
47
- ...e.transport,
48
- command: "github-mcp-server",
49
- args: ["stdio"]
50
- }
51
- } : e)
52
- };
53
- }
54
- function d(e) {
55
- return e.map(l).map(u).filter((e) => !!n(e));
39
+ function l(e) {
40
+ return e.map(c).filter((e) => !!t(e));
56
41
  }
57
- var f = (e) => {
42
+ var u = (e) => {
58
43
  try {
59
44
  return new URL(e);
60
45
  } catch {
61
46
  return null;
62
47
  }
63
48
  };
64
- function p(e, t) {
49
+ function d(e, t) {
65
50
  let n = typeof e == "string" ? e : "", r = typeof t == "string" ? t : "";
66
51
  if (!n || !r) return !1;
67
- let i = f(n), a = f(r);
52
+ let i = u(n), a = u(r);
68
53
  return !i || !a ? n.replace(/\/+$/, "") === r.replace(/\/+$/, "") : i.protocol === a.protocol && i.host === a.host && i.pathname.replace(/\/+$/, "") === a.pathname.replace(/\/+$/, "");
69
54
  }
70
- function m(e, t) {
55
+ function f(e, t) {
71
56
  if (e.kind === "shttp") {
72
57
  let n = e.url;
73
- return t.type === "shttp" && !!t.url && p(t.url, n);
58
+ return t.type === "shttp" && !!t.url && d(t.url, n);
74
59
  }
75
60
  if (e.kind === "sse") {
76
61
  let n = e.url;
77
- return t.type === "sse" && !!t.url && p(t.url, n);
62
+ return t.type === "sse" && !!t.url && d(t.url, n);
78
63
  }
79
64
  return t.type === "stdio" && t.name === e.serverName;
80
65
  }
81
- function h(e, t) {
66
+ function p(e, t) {
82
67
  return !e.runtimeAvailability || e.runtimeAvailability === "all" ? !0 : e.runtimeAvailability === t;
83
68
  }
84
- function g(e) {
69
+ function m(e) {
85
70
  return e.trim().toLowerCase();
86
71
  }
87
- function _(e) {
72
+ function h(e) {
88
73
  return e.map((e, t) => ({
89
74
  entry: e,
90
75
  index: t
91
76
  })).sort((e, t) => (t.entry.popularityRank ?? 0) - (e.entry.popularityRank ?? 0) || e.index - t.index).map(({ entry: e }) => e);
92
77
  }
93
- function v(e, t) {
94
- let n = g(t);
78
+ function g(e, t) {
79
+ let n = m(t);
95
80
  return n ? [
96
81
  e.name,
97
82
  e.description,
@@ -99,8 +84,8 @@ function v(e, t) {
99
84
  ...e.keywords ?? []
100
85
  ].join(" ").toLowerCase().includes(n) : !0;
101
86
  }
102
- function y(e, t, n) {
103
- let r = g(n);
87
+ function _(e, t, n) {
88
+ let r = m(n);
104
89
  return r ? [
105
90
  e.type,
106
91
  "name" in e ? e.name : void 0,
@@ -113,10 +98,10 @@ function y(e, t, n) {
113
98
  ...t?.keywords ?? []
114
99
  ].filter(Boolean).join(" ").toLowerCase().includes(r) : !0;
115
100
  }
116
- function b(e, n) {
117
- return n.find((n) => t(n).some((t) => m(t.transport, e)));
101
+ function v(t, n) {
102
+ return n.find((n) => e(n).some((e) => f(e.transport, t)));
118
103
  }
119
104
  //#endregion
120
- export { b as findCatalogEntryForServer, a as getDefaultMcpTransport, i as getInstallableMcpConnectionOption, _ as getMarketplaceEntriesByPopularity, d as getMcpMarketplaceCatalog, y as installedServerMatchesQuery, h as isMarketplaceEntryAvailable, v as marketplaceEntryMatchesQuery };
105
+ export { v as findCatalogEntryForServer, i as getDefaultMcpTransport, r as getInstallableMcpConnectionOption, h as getMarketplaceEntriesByPopularity, l as getMcpMarketplaceCatalog, _ as installedServerMatchesQuery, p as isMarketplaceEntryAvailable, g as marketplaceEntryMatchesQuery };
121
106
 
122
107
  //# sourceMappingURL=mcp-marketplace-utils.js.map