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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (728) hide show
  1. package/README.md +32 -7
  2. package/bin/agent-canvas.mjs +35 -2
  3. package/build/assets/{QueryClientProvider-DITRCGAK.js → QueryClientProvider-B7kl84Kj.js} +1 -1
  4. package/build/assets/{Trans-D43bd3yR.js → Trans-1j65oy9O.js} +1 -1
  5. package/build/assets/{acp-providers-SCPK1BIU.js → acp-providers-DauuOsW9.js} +1 -1
  6. package/build/assets/{acp-route-guard-IWlFmS6x.js → acp-route-guard-CQTmeJwM.js} +1 -1
  7. package/build/assets/{active-backend-context-CkP3ZEJs.js → active-backend-context-TVbjnvmP.js} +1 -1
  8. package/build/assets/add-backend-modal-KMmPQNZU.js +1 -0
  9. package/build/assets/{agent-server-client-options-8OJSXbm8.js → agent-server-client-options-DT2GP6VJ.js} +1 -1
  10. package/build/assets/{agent-server-compatibility-DvKtnXHw.js → agent-server-compatibility-2aOx5iWd.js} +1 -1
  11. package/build/assets/{agent-server-conversation-service.api-BdEre_71.js → agent-server-conversation-service.api-DSl9G5UR.js} +3 -3
  12. package/build/assets/{agent-settings-DdisD2Xx.js → agent-settings-B247S9G3.js} +2 -2
  13. package/build/assets/{alert-banner-CvTYN73l.js → alert-banner-BWoqueRw.js} +1 -1
  14. package/build/assets/{analytics-consent-form-modal-BKgT9i2w.js → analytics-consent-form-modal-C7sXfxRh.js} +1 -1
  15. package/build/assets/{app-settings-DcYXtxGP.js → app-settings-BVeSaty9.js} +1 -1
  16. package/build/assets/automation-detail-g5-RZ0da.js +1 -0
  17. package/build/assets/automations-list-DHoq_0MM.js +1 -0
  18. package/build/assets/{backend-form-modal-KudhWUX8.js → backend-form-modal-K6IMCr3p.js} +1 -1
  19. package/build/assets/{backend-synced-settings-badge-BFy2HylT.js → backend-synced-settings-badge-nAfiUWvM.js} +1 -1
  20. package/build/assets/{base-modal-B4HvlFHE.js → base-modal-CQRvRHu1.js} +1 -1
  21. package/build/assets/{brand-button-8fVVei4i.js → brand-button-C2nEKopC.js} +1 -1
  22. package/build/assets/{browser-vYpdU3CR.js → browser-DKG63inJ.js} +1 -1
  23. package/build/assets/{browser-tab-DTM6RyoV.js → browser-tab-B_BuTvrO.js} +1 -1
  24. package/build/assets/{checkmark-BcvXE9bf.js → checkmark-BJJrZUF8.js} +1 -1
  25. package/build/assets/{chevron-left-small-BqSkXTeq.js → chevron-left-small-CSh-sE9L.js} +1 -1
  26. package/build/assets/{circle-plus-check-toggle-DRvuu-RD.js → circle-plus-check-toggle-qs8Va1cC.js} +1 -1
  27. package/build/assets/{clock-DfoVUZVq.js → clock-ZR4Kn-_Y.js} +1 -1
  28. package/build/assets/{close-SnIy2eLD.js → close-BdmyeRqS.js} +1 -1
  29. package/build/assets/{combobox-caret-BMsz5mQX.js → combobox-caret-B53O9Hsq.js} +1 -1
  30. package/build/assets/{condenser-settings-DduLQcpV.js → condenser-settings-A35V3yng.js} +1 -1
  31. package/build/assets/{confirmation-modal-B-DOYMUH.js → confirmation-modal-C9-La0h3.js} +1 -1
  32. package/build/assets/{context-menu-list-item-DzjPB8aC.js → context-menu-list-item-Buu9nc0q.js} +1 -1
  33. package/build/assets/conversation-BD5WemJI.js +19 -0
  34. package/build/assets/conversation-C47K62n8.js +1 -0
  35. package/build/assets/conversation-panel-Dn-S56Gk.js +1 -0
  36. package/build/assets/{conversation-service.api-YTGTw0pz.js → conversation-service.api-C8pYCyV6.js} +1 -1
  37. package/build/assets/{conversation-tab-empty-state-BtFDbyTe.js → conversation-tab-empty-state-D8dNvo-V.js} +1 -1
  38. package/build/assets/conversation-websocket-context-Ywrxd_9p.js +3 -0
  39. package/build/assets/{copy-BxgbrjDT.js → copy-C7Ti2d8C.js} +1 -1
  40. package/build/assets/{custom-toast-handlers-BYxhSr3t.js → custom-toast-handlers-BOc3qeQ7.js} +1 -1
  41. package/build/assets/declaration-D378OjpZ.js +1 -0
  42. package/build/assets/{device-verify-CTbXX9CQ.js → device-verify-CMusn8nX.js} +1 -1
  43. package/build/assets/edit-automation-modal-Dnjxbjn7.js +1 -0
  44. package/build/assets/{ellipsis-button-BoU2-xlG.js → ellipsis-button-ugUATsNo.js} +1 -1
  45. package/build/assets/{entry.client-DU7-q4ZU.js → entry.client-D9uR9Blz.js} +2 -2
  46. package/build/assets/{enum-filter-dropdown-BJt-NplD.js → enum-filter-dropdown-1vpOGySB.js} +1 -1
  47. package/build/assets/{environment-switch-overlay-DQ1n6Iu6.js → environment-switch-overlay-CTCTQikP.js} +1 -1
  48. package/build/assets/{extensions-hub-BW1FAKFJ.js → extensions-hub-BSUseHVF.js} +1 -1
  49. package/build/assets/{extensions-navigation-CbPMhSML.js → extensions-navigation-CT1kc1u_.js} +1 -1
  50. package/build/assets/{files-tab-CbJ4s7Ik.js → files-tab-B3A1NDlZ.js} +1 -1
  51. package/build/assets/{folder-CerIk8uG.js → folder-0WSMImNX.js} +1 -1
  52. package/build/assets/git-control-bar-branch-button-CcIpmyfM.js +27 -0
  53. package/build/assets/{git-provider-icon-D8RE4unY.js → git-provider-icon-DYE9n7fs.js} +1 -1
  54. package/build/assets/{home-D9fJfhQA.js → home-dIzxi5Dd.js} +1 -1
  55. package/build/assets/{i18n-DkYgs32x.js → i18n-DjAGhTis.js} +1 -1
  56. package/build/assets/install-server-modal-z5VaHeXd.js +1 -0
  57. package/build/assets/{launch-DKCU9uJH.js → launch-hZ0ifhcV.js} +1 -1
  58. package/build/assets/{lesson-plan-CmkRbe6Z.js → lesson-plan-DRYG5SLI.js} +1 -1
  59. package/build/assets/{link-external-CvxB0BmI.js → link-external-Df8J52xI.js} +1 -1
  60. package/build/assets/{llm-client-BpIfxETv.js → llm-client-ChQzg4wX.js} +1 -1
  61. package/build/assets/llm-settings-2036m7Wt.js +1 -0
  62. package/build/assets/{llm-settings-BOJC4vD-.js → llm-settings-CcHqGOYL.js} +1 -1
  63. package/build/assets/{loading-spinner-91b5FiMQ.js → loading-spinner-C04FGh14.js} +1 -1
  64. package/build/assets/{manage-backends-modal-DqpzcxdI.js → manage-backends-modal-rYeyGx7j.js} +1 -1
  65. package/build/assets/{manage-workspaces-modal-eG6XgAvw.js → manage-workspaces-modal-C5EuW8m1.js} +1 -1
  66. package/build/assets/manifest-97e839da.js +1 -0
  67. package/build/assets/{markdown-renderer-wZnLDbA1.js → markdown-renderer-CEX4Becj.js} +1 -1
  68. package/build/assets/mcp-C06YssEI.js +9 -0
  69. package/build/assets/messages-T2ewVkbp.js +36 -0
  70. package/build/assets/{modal-backdrop-B04pVYAD.js → modal-backdrop-DTYGVmOR.js} +1 -1
  71. package/build/assets/{modal-body-CgUoFQA1.js → modal-body-YElmM1dV.js} +1 -1
  72. package/build/assets/{modal-close-button-SM_WXzDY.js → modal-close-button-C_GpQt9F.js} +1 -1
  73. package/build/assets/{model-selector-7id-Uirf.js → model-selector-DeMmw-Xa.js} +1 -1
  74. package/build/assets/{navigation-context-BFjstyH6.js → navigation-context-DeIPtGPp.js} +1 -1
  75. package/build/assets/{navigation-link-DFQ7YcWq.js → navigation-link-C9JD4PYD.js} +1 -1
  76. package/build/assets/{openhands-logo-DkDp75rC.js → openhands-logo-CI5Fhn1W.js} +1 -1
  77. package/build/assets/{option-service.api-DN0ZcGjw.js → option-service.api-DsI1UW7N.js} +1 -1
  78. package/build/assets/{organization-service.api-Ct2dZF8M.js → organization-service.api-COwMPFg5.js} +1 -1
  79. package/build/assets/{path-utils-D1ZtqFC7.js → path-utils-CqJboYxo.js} +1 -1
  80. package/build/assets/{plan-components-gOm-daR3.js → plan-components-DEjMuDDG.js} +1 -1
  81. package/build/assets/{planner-tab-yubfN-6U.js → planner-tab-BrntFmb1.js} +1 -1
  82. package/build/assets/{profiles-client-D4twHRVf.js → profiles-client-BGkKEV9j.js} +1 -1
  83. package/build/assets/{providers-C2T07PM3.js → providers-DXvCAN_u.js} +1 -1
  84. package/build/assets/{proxy-BMZyC45G.js → proxy-CurRmrqf.js} +1 -1
  85. package/build/assets/{query-client-config-CiK0GJJO.js → query-client-config-Ba7qAAoO.js} +1 -1
  86. package/build/assets/recommended-automations-launcher-BI9NhG8Y.js +52 -0
  87. package/build/assets/root-BS1Td78t.js +2 -0
  88. package/build/assets/root-DHeCXo9N.css +1 -0
  89. package/build/assets/root-layout-BLjAEgle.js +2 -0
  90. package/build/assets/{sdk-section-page-03k88tIR.js → sdk-section-page-CJW0G04-.js} +1 -1
  91. package/build/assets/{sdk-settings-schema-BY8dOy3a.js → sdk-settings-schema-QBYH-ONX.js} +1 -1
  92. package/build/assets/{search-BCAF9EDS.js → search-Cq_cFrDt.js} +1 -1
  93. package/build/assets/{secrets-service-Z3qtRb_G.js → secrets-service-Bwd5DeUs.js} +1 -1
  94. package/build/assets/{secrets-settings-BnlByuMZ.js → secrets-settings-MLXqOtX2.js} +1 -1
  95. package/build/assets/{server-client-CG1zHqph.js → server-client-C3mC8Hl3.js} +1 -1
  96. package/build/assets/{settings-DyzGLF_d.js → settings-D7E2U5tK.js} +1 -1
  97. package/build/assets/{settings-client-CkXDJwIY.js → settings-client-CwjfwoiB.js} +1 -1
  98. package/build/assets/{settings-dropdown-input-CAQWQgx-.js → settings-dropdown-input-VwAXNrOb.js} +1 -1
  99. package/build/assets/{settings-gear-D4ZkEDGb.js → settings-gear-BJwWR1ej.js} +1 -1
  100. package/build/assets/{settings-index-KtTw49xL.js → settings-index-J-3BNR0W.js} +1 -1
  101. package/build/assets/{settings-input-BWCZt9g2.js → settings-input-DBywAnA7.js} +1 -1
  102. package/build/assets/{settings-list-classes-xMleGkTC.js → settings-list-classes-BOS092DR.js} +1 -1
  103. package/build/assets/{settings-modal-Cv2YWSUY.js → settings-modal-B8vgWDTe.js} +1 -1
  104. package/build/assets/{settings-section-header-context-1wfkgjZZ.js → settings-section-header-context-32x6WTyL.js} +1 -1
  105. package/build/assets/settings-service.api-FvJGK45W.js +1 -0
  106. package/build/assets/{settings-switch-CGap2LtG.js → settings-switch-DTKmHC8F.js} +1 -1
  107. package/build/assets/{settings-utils-BBozxqqi.js → settings-utils-BsvSU3OM.js} +1 -1
  108. package/build/assets/{shared-conversation-BfZNCsvo.js → shared-conversation-a0QV8o99.js} +1 -1
  109. package/build/assets/{sidebar-mobile-menu-toggle-DXplko7u.js → sidebar-mobile-menu-toggle-DTUNI1WQ.js} +1 -1
  110. package/build/assets/{sidebar-nav-link-B4h8naZ7.js → sidebar-nav-link-CnWoZcwc.js} +1 -1
  111. package/build/assets/{skill-card-pill-row-D0oTWx-a.js → skill-card-pill-row-tZ599jli.js} +1 -1
  112. package/build/assets/{skills-BN8atjgW.js → skills-ZyAO5dyK.js} +1 -1
  113. package/build/assets/{skills-plugins-BTnp7QcQ.js → skills-plugins-BSRz041I.js} +1 -1
  114. package/build/assets/{skills-settings-CbOQvzkR.js → skills-settings-DOnMn9q1.js} +2 -2
  115. package/build/assets/{status-DDL-ipIP.js → status-CsatcFbK.js} +1 -1
  116. package/build/assets/{styled-tooltip-Awq4HMw3.js → styled-tooltip-CS3mB_1X.js} +1 -1
  117. package/build/assets/{switch-skeleton-Bv21RGWd.js → switch-skeleton-C-CfhYYV.js} +1 -1
  118. package/build/assets/{task-list-tab-B45ktzHM.js → task-list-tab-Day9nhRT.js} +1 -1
  119. package/build/assets/{terminal-DGuR4559.js → terminal-LNa-iU5c.js} +1 -1
  120. package/build/assets/{terminal-D5pzR9Ru.js → terminal-ro4SNjUU.js} +1 -1
  121. package/build/assets/{toggle-switch-gj6T-wsU.js → toggle-switch-k-IZCDbt.js} +1 -1
  122. package/build/assets/{typography-BbaUAC4V.js → typography-vVUMoNUg.js} +1 -1
  123. package/build/assets/{u-check-circle-DHGiAi-w.js → u-check-circle-DplbarS5.js} +1 -1
  124. package/build/assets/{u-check-circle-half-BPcWtWwv.js → u-check-circle-half-yDuiSZHC.js} +1 -1
  125. package/build/assets/{u-circuit-B_nK9hOu.js → u-circuit-C9tYkpeK.js} +1 -1
  126. package/build/assets/{u-edit-BPFJBd34.js → u-edit-KAUlufD8.js} +1 -1
  127. package/build/assets/{use-active-conversation-Bu5J9iLy.js → use-active-conversation-D15D9GgR.js} +1 -1
  128. package/build/assets/{use-agent-settings-schema-BbtOsR7P.js → use-agent-settings-schema-Bvp5UzV8.js} +1 -1
  129. package/build/assets/{use-agent-state-DN9Nc5pP.js → use-agent-state-DE5dlEXJ.js} +1 -1
  130. package/build/assets/{use-cloud-current-user-id-B_rMUiu8.js → use-cloud-current-user-id-DWVar4st.js} +1 -1
  131. package/build/assets/{use-config-Bcz2JL2t.js → use-config-BSu_53GL.js} +1 -1
  132. package/build/assets/{use-conversation-id-BOaaZahn.js → use-conversation-id-DajhCn2A.js} +1 -1
  133. package/build/assets/{use-create-conversation-BWFA_FId.js → use-create-conversation-DW7AGgLA.js} +1 -1
  134. package/build/assets/{use-handle-plan-click-CgrCGmT1.js → use-handle-plan-click-DpgEQDAV.js} +1 -1
  135. package/build/assets/use-is-authed-hXC8vxgT.js +1 -0
  136. package/build/assets/{use-is-creating-conversation-DhoM7UAB.js → use-is-creating-conversation-DhDeeWfA.js} +1 -1
  137. package/build/assets/{use-launch-skill-in-chat-DOyQsXFO.js → use-launch-skill-in-chat-DVGPFrbI.js} +1 -1
  138. package/build/assets/{use-llm-profiles-CAIzHJDX.js → use-llm-profiles-D3-KXwQ0.js} +1 -1
  139. package/build/assets/use-runtime-is-ready-XFbT16BD.js +1 -0
  140. package/build/assets/{use-save-settings-5m3w89Ph.js → use-save-settings-CEEKSTWG.js} +1 -1
  141. package/build/assets/{use-settings-DzG0C3vO.js → use-settings-DQ7Oo1Hj.js} +1 -1
  142. package/build/assets/{use-settings-nav-items-BIsKeX52.js → use-settings-nav-items-YmrXrjn9.js} +2 -2
  143. package/build/assets/{use-skills-Cn-78xP1.js → use-skills-Xe0vjPMt.js} +1 -1
  144. package/build/assets/{use-unified-vscode-url-C5iI-Z5A.js → use-unified-vscode-url-BOsIOd-b.js} +1 -1
  145. package/build/assets/use-user-conversation-Mc0mQgkl.js +1 -0
  146. package/build/assets/{useMutation-CRJwk4cR.js → useMutation-B4OUESdw.js} +1 -1
  147. package/build/assets/{useTranslation-01pF7z10.js → useTranslation-CpIcQBq6.js} +1 -1
  148. package/build/assets/{utils-Czcl6buL.js → utils-D-HX7JCe.js} +1 -1
  149. package/build/assets/{vendor~conversation-panel~conversation-CbjvWBSu.js → vendor~conversation-panel~conversation-BlCIz9XQ.js} +1 -1
  150. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CofhIDpd.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Ds9quNZ9.js} +1 -1
  151. package/build/assets/vendor~home~mcp~automations-list-C5PoHCy6.js +1 -0
  152. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-BQPOygpY.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CGlZoBKa.js} +1 -1
  153. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CyYIBiBk.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-DE11mPxp.js} +1 -1
  154. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-CuGq_cxH.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-8b8V5bfO.js} +1 -1
  155. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-CFpDeb9o.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-Dy7L6fMG.js} +1 -1
  156. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-C1p8-pMr.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-D40EXhZx.js} +1 -1
  157. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-CHrEOFl6.js +48 -0
  158. package/build/assets/{vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-DlKA6SoO.js → vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-CyUbhpbm.js} +1 -1
  159. package/build/assets/{verification-settings-DbziMp4K.js → verification-settings-BtlTiHP8.js} +1 -1
  160. package/build/assets/{vscode-tab-BVhQR2rt.js → vscode-tab-C0ShhiSU.js} +1 -1
  161. package/build/assets/{waiting-for-runtime-message-JotSOBdC.js → waiting-for-runtime-message-DWPl_Yby.js} +1 -1
  162. package/build/assets/{x-mark-CZ57VvRX.js → x-mark-CWI0f9yI.js} +1 -1
  163. package/build/favicon.svg +1 -0
  164. package/build/index.html +4 -4
  165. package/build/locales/ar/openhands.json +8 -0
  166. package/build/locales/ca/openhands.json +8 -0
  167. package/build/locales/de/openhands.json +8 -0
  168. package/build/locales/en/openhands.json +8 -0
  169. package/build/locales/es/openhands.json +8 -0
  170. package/build/locales/fr/openhands.json +8 -0
  171. package/build/locales/it/openhands.json +8 -0
  172. package/build/locales/ja/openhands.json +8 -0
  173. package/build/locales/ko-KR/openhands.json +8 -0
  174. package/build/locales/no/openhands.json +8 -0
  175. package/build/locales/pt/openhands.json +8 -0
  176. package/build/locales/tr/openhands.json +8 -0
  177. package/build/locales/uk/openhands.json +8 -0
  178. package/build/locales/zh-CN/openhands.json +8 -0
  179. package/build/locales/zh-TW/openhands.json +8 -0
  180. package/config/defaults.json +1 -1
  181. package/dist/api/agent-server-config.cjs +1 -1
  182. package/dist/api/agent-server-config.cjs.map +1 -1
  183. package/dist/api/agent-server-config.d.ts +1 -1
  184. package/dist/api/agent-server-config.js +1 -1
  185. package/dist/api/agent-server-config.js.map +1 -1
  186. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  187. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  188. package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +12 -0
  189. package/dist/api/conversation-service/agent-server-conversation-service.api.js +4 -0
  190. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  191. package/dist/api/mcp-service/mcp-service.api.cjs +2 -0
  192. package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -0
  193. package/dist/api/mcp-service/mcp-service.api.d.ts +6 -0
  194. package/dist/api/mcp-service/mcp-service.api.js +36 -0
  195. package/dist/api/mcp-service/mcp-service.api.js.map +1 -0
  196. package/dist/api/settings-service/settings-service.api.cjs +1 -1
  197. package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
  198. package/dist/api/settings-service/settings-service.api.d.ts +1 -0
  199. package/dist/api/settings-service/settings-service.api.js +59 -41
  200. package/dist/api/settings-service/settings-service.api.js.map +1 -1
  201. package/dist/components/features/automations/detail/activity-log-item.d.ts +1 -1
  202. package/dist/components/features/automations/recommended-automations-launcher.d.ts +1 -1
  203. package/dist/components/features/backends/backend-selector.cjs +1 -1
  204. package/dist/components/features/backends/backend-selector.cjs.map +1 -1
  205. package/dist/components/features/backends/backend-selector.js +95 -95
  206. package/dist/components/features/backends/backend-selector.js.map +1 -1
  207. package/dist/components/features/chat/change-agent-button.cjs +1 -1
  208. package/dist/components/features/chat/change-agent-button.cjs.map +1 -1
  209. package/dist/components/features/chat/change-agent-button.js +65 -59
  210. package/dist/components/features/chat/change-agent-button.js.map +1 -1
  211. package/dist/components/features/chat/chat-interface.cjs +2 -2
  212. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  213. package/dist/components/features/chat/chat-interface.js +15 -14
  214. package/dist/components/features/chat/chat-interface.js.map +1 -1
  215. package/dist/components/features/chat/components/chat-input-actions.cjs +1 -1
  216. package/dist/components/features/chat/components/chat-input-actions.cjs.map +1 -1
  217. package/dist/components/features/chat/components/chat-input-actions.js +115 -137
  218. package/dist/components/features/chat/components/chat-input-actions.js.map +1 -1
  219. package/dist/components/features/chat/components/chat-input-model.cjs +1 -1
  220. package/dist/components/features/chat/components/chat-input-model.cjs.map +1 -1
  221. package/dist/components/features/chat/components/chat-input-model.d.ts +10 -0
  222. package/dist/components/features/chat/components/chat-input-model.js +95 -60
  223. package/dist/components/features/chat/components/chat-input-model.js.map +1 -1
  224. package/dist/components/features/chat/components/slash-command-menu.cjs +1 -1
  225. package/dist/components/features/chat/components/slash-command-menu.cjs.map +1 -1
  226. package/dist/components/features/chat/components/slash-command-menu.js +1 -1
  227. package/dist/components/features/chat/components/slash-command-menu.js.map +1 -1
  228. package/dist/components/features/chat/git-control-bar.cjs +1 -1
  229. package/dist/components/features/chat/git-control-bar.cjs.map +1 -1
  230. package/dist/components/features/chat/git-control-bar.js +60 -59
  231. package/dist/components/features/chat/git-control-bar.js.map +1 -1
  232. package/dist/components/features/conversation/conversation-name-with-status.cjs +1 -1
  233. package/dist/components/features/conversation/conversation-name-with-status.cjs.map +1 -1
  234. package/dist/components/features/conversation/conversation-name-with-status.js +2 -2
  235. package/dist/components/features/conversation/conversation-name-with-status.js.map +1 -1
  236. package/dist/components/features/conversation/conversation-name.cjs +1 -1
  237. package/dist/components/features/conversation/conversation-name.cjs.map +1 -1
  238. package/dist/components/features/conversation/conversation-name.js +3 -3
  239. package/dist/components/features/conversation/conversation-name.js.map +1 -1
  240. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs +1 -1
  241. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs.map +1 -1
  242. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js +1 -1
  243. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js.map +1 -1
  244. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs +1 -1
  245. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs.map +1 -1
  246. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js +16 -16
  247. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js.map +1 -1
  248. package/dist/components/features/mcp-logo-badge.cjs +1 -1
  249. package/dist/components/features/mcp-logo-badge.cjs.map +1 -1
  250. package/dist/components/features/mcp-logo-badge.d.ts +2 -2
  251. package/dist/components/features/mcp-logo-badge.js +1 -1
  252. package/dist/components/features/mcp-logo-badge.js.map +1 -1
  253. package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
  254. package/dist/components/features/mcp-page/custom-server-editor.cjs.map +1 -1
  255. package/dist/components/features/mcp-page/custom-server-editor.js +64 -41
  256. package/dist/components/features/mcp-page/custom-server-editor.js.map +1 -1
  257. package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
  258. package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
  259. package/dist/components/features/mcp-page/install-server-modal.d.ts +1 -1
  260. package/dist/components/features/mcp-page/install-server-modal.js +126 -102
  261. package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
  262. package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
  263. package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
  264. package/dist/components/features/mcp-page/installed-server-card.js +1 -1
  265. package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
  266. package/dist/components/features/mcp-page/marketplace-card.cjs +1 -1
  267. package/dist/components/features/mcp-page/marketplace-card.cjs.map +1 -1
  268. package/dist/components/features/mcp-page/marketplace-card.d.ts +1 -1
  269. package/dist/components/features/mcp-page/marketplace-card.js +27 -25
  270. package/dist/components/features/mcp-page/marketplace-card.js.map +1 -1
  271. package/dist/components/features/mcp-page/marketplace-section.cjs +1 -1
  272. package/dist/components/features/mcp-page/marketplace-section.cjs.map +1 -1
  273. package/dist/components/features/mcp-page/marketplace-section.d.ts +1 -1
  274. package/dist/components/features/mcp-page/marketplace-section.js +1 -1
  275. package/dist/components/features/mcp-page/marketplace-section.js.map +1 -1
  276. package/dist/components/features/mcp-page/mcp-logo-stack-badge.d.ts +2 -2
  277. package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs +7 -7
  278. package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs.map +1 -1
  279. package/dist/components/features/settings/mcp-settings/mcp-server-form.d.ts +8 -12
  280. package/dist/components/features/settings/mcp-settings/mcp-server-form.js +114 -87
  281. package/dist/components/features/settings/mcp-settings/mcp-server-form.js.map +1 -1
  282. package/dist/components/features/sidebar/sidebar-rail-body.cjs +1 -1
  283. package/dist/components/features/sidebar/sidebar-rail-body.cjs.map +1 -1
  284. package/dist/components/features/sidebar/sidebar-rail-body.d.ts +1 -2
  285. package/dist/components/features/sidebar/sidebar-rail-body.js +104 -104
  286. package/dist/components/features/sidebar/sidebar-rail-body.js.map +1 -1
  287. package/dist/components/features/sidebar/sidebar.cjs +1 -1
  288. package/dist/components/features/sidebar/sidebar.cjs.map +1 -1
  289. package/dist/components/features/sidebar/sidebar.js +82 -83
  290. package/dist/components/features/sidebar/sidebar.js.map +1 -1
  291. package/dist/context/scroll-context.cjs +1 -1
  292. package/dist/context/scroll-context.cjs.map +1 -1
  293. package/dist/context/scroll-context.d.ts +1 -0
  294. package/dist/context/scroll-context.js +4 -1
  295. package/dist/context/scroll-context.js.map +1 -1
  296. package/dist/contexts/conversation-websocket-context.cjs +3 -3
  297. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  298. package/dist/contexts/conversation-websocket-context.js +36 -36
  299. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  300. package/dist/favicon.svg +1 -0
  301. package/dist/hooks/mutation/use-switch-acp-model.cjs +2 -0
  302. package/dist/hooks/mutation/use-switch-acp-model.cjs.map +1 -0
  303. package/dist/hooks/mutation/use-switch-acp-model.d.ts +23 -0
  304. package/dist/hooks/mutation/use-switch-acp-model.js +26 -0
  305. package/dist/hooks/mutation/use-switch-acp-model.js.map +1 -0
  306. package/dist/hooks/mutation/use-test-mcp-server.cjs +2 -0
  307. package/dist/hooks/mutation/use-test-mcp-server.cjs.map +1 -0
  308. package/dist/hooks/mutation/use-test-mcp-server.d.ts +2 -0
  309. package/dist/hooks/mutation/use-test-mcp-server.js +10 -0
  310. package/dist/hooks/mutation/use-test-mcp-server.js.map +1 -0
  311. package/dist/hooks/query/use-automation-detail.d.ts +3 -2
  312. package/dist/hooks/query/use-local-git-info.cjs +3 -1
  313. package/dist/hooks/query/use-local-git-info.cjs.map +1 -1
  314. package/dist/hooks/query/use-local-git-info.d.ts +2 -2
  315. package/dist/hooks/query/use-local-git-info.js +27 -24
  316. package/dist/hooks/query/use-local-git-info.js.map +1 -1
  317. package/dist/hooks/use-acp-model-context.cjs.map +1 -1
  318. package/dist/hooks/use-acp-model-context.d.ts +3 -4
  319. package/dist/hooks/use-acp-model-context.js.map +1 -1
  320. package/dist/hooks/use-chat-input-model-state.cjs +2 -0
  321. package/dist/hooks/use-chat-input-model-state.cjs.map +1 -0
  322. package/dist/hooks/use-chat-input-model-state.d.ts +12 -0
  323. package/dist/hooks/use-chat-input-model-state.js +29 -0
  324. package/dist/hooks/use-chat-input-model-state.js.map +1 -0
  325. package/dist/i18n/declaration.cjs +1 -1
  326. package/dist/i18n/declaration.cjs.map +1 -1
  327. package/dist/i18n/declaration.d.ts +8 -0
  328. package/dist/i18n/declaration.js +1 -1
  329. package/dist/i18n/declaration.js.map +1 -1
  330. package/dist/i18n/translation.cjs +2 -2
  331. package/dist/i18n/translation.cjs.map +1 -1
  332. package/dist/i18n/translation.js +136 -0
  333. package/dist/i18n/translation.js.map +1 -1
  334. package/dist/locales/ar/openhands.json +8 -0
  335. package/dist/locales/ca/openhands.json +8 -0
  336. package/dist/locales/de/openhands.json +8 -0
  337. package/dist/locales/en/openhands.json +8 -0
  338. package/dist/locales/es/openhands.json +8 -0
  339. package/dist/locales/fr/openhands.json +8 -0
  340. package/dist/locales/it/openhands.json +8 -0
  341. package/dist/locales/ja/openhands.json +8 -0
  342. package/dist/locales/ko-KR/openhands.json +8 -0
  343. package/dist/locales/no/openhands.json +8 -0
  344. package/dist/locales/pt/openhands.json +8 -0
  345. package/dist/locales/tr/openhands.json +8 -0
  346. package/dist/locales/uk/openhands.json +8 -0
  347. package/dist/locales/zh-CN/openhands.json +8 -0
  348. package/dist/locales/zh-TW/openhands.json +8 -0
  349. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.cjs +2 -0
  350. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.cjs.map +1 -0
  351. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.js +37 -0
  352. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.js.map +1 -0
  353. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.cjs +2 -0
  354. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.cjs.map +1 -0
  355. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.js +36 -0
  356. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.js.map +1 -0
  357. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/atlassian.cjs +1 -1
  358. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs.map +1 -0
  359. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/atlassian.js +15 -5
  360. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js.map +1 -0
  361. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.cjs +2 -0
  362. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.cjs.map +1 -0
  363. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.js +36 -0
  364. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.js.map +1 -0
  365. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.cjs +2 -0
  366. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.cjs.map +1 -0
  367. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.js +31 -0
  368. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.js.map +1 -0
  369. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.cjs +2 -0
  370. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.cjs.map +1 -0
  371. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.js +52 -0
  372. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.js.map +1 -0
  373. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-bindings.cjs +1 -1
  374. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-bindings.cjs.map +1 -0
  375. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-bindings.js +15 -5
  376. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-bindings.js.map +1 -0
  377. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.cjs +2 -0
  378. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.cjs.map +1 -0
  379. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-browser-rendering.js +15 -5
  380. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.js.map +1 -0
  381. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-builds.cjs +1 -1
  382. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-builds.cjs.map +1 -0
  383. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-builds.js +15 -5
  384. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-builds.js.map +1 -0
  385. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-docs.cjs +1 -1
  386. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-docs.cjs.map +1 -0
  387. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-docs.js +15 -5
  388. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-docs.js.map +1 -0
  389. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.cjs +2 -0
  390. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.cjs.map +1 -0
  391. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-observability.js +15 -5
  392. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.js.map +1 -0
  393. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/deepwiki.cjs +1 -1
  394. package/dist/node_modules/@openhands/extensions/integrations/catalog/deepwiki.cjs.map +1 -0
  395. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/deepwiki.js +15 -5
  396. package/dist/node_modules/@openhands/extensions/integrations/catalog/deepwiki.js.map +1 -0
  397. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.cjs +2 -0
  398. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.cjs.map +1 -0
  399. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.js +36 -0
  400. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.js.map +1 -0
  401. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/everything.cjs +1 -1
  402. package/dist/node_modules/@openhands/extensions/integrations/catalog/everything.cjs.map +1 -0
  403. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/everything.js +13 -6
  404. package/dist/node_modules/@openhands/extensions/integrations/catalog/everything.js.map +1 -0
  405. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.cjs +2 -0
  406. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.cjs.map +1 -0
  407. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.js +36 -0
  408. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.js.map +1 -0
  409. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/fetch.cjs +1 -1
  410. package/dist/node_modules/@openhands/extensions/integrations/catalog/fetch.cjs.map +1 -0
  411. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/fetch.js +13 -6
  412. package/dist/node_modules/@openhands/extensions/integrations/catalog/fetch.js.map +1 -0
  413. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.cjs +2 -0
  414. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.cjs.map +1 -0
  415. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.js +40 -0
  416. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.js.map +1 -0
  417. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.cjs +2 -0
  418. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.cjs.map +1 -0
  419. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.js +39 -0
  420. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.js.map +1 -0
  421. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.cjs +2 -0
  422. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.cjs.map +1 -0
  423. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.js +36 -0
  424. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.js.map +1 -0
  425. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.cjs +2 -0
  426. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.cjs.map +1 -0
  427. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.js +40 -0
  428. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.js.map +1 -0
  429. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs +2 -0
  430. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs.map +1 -0
  431. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js +47 -0
  432. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -0
  433. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/huggingface.cjs +1 -1
  434. package/dist/node_modules/@openhands/extensions/integrations/catalog/huggingface.cjs.map +1 -0
  435. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/huggingface.js +15 -5
  436. package/dist/node_modules/@openhands/extensions/integrations/catalog/huggingface.js.map +1 -0
  437. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.cjs +2 -0
  438. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.cjs.map +1 -0
  439. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.js +36 -0
  440. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.js.map +1 -0
  441. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/linear.cjs +1 -1
  442. package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.cjs.map +1 -0
  443. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/linear.js +15 -5
  444. package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.js.map +1 -0
  445. package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.cjs +2 -0
  446. package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.cjs.map +1 -0
  447. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/memory.js +13 -6
  448. package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.js.map +1 -0
  449. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.cjs +2 -0
  450. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.cjs.map +1 -0
  451. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.js +36 -0
  452. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.js.map +1 -0
  453. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.cjs +2 -0
  454. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.cjs.map +1 -0
  455. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.js +40 -0
  456. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.js.map +1 -0
  457. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs +2 -0
  458. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs.map +1 -0
  459. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js +39 -0
  460. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js.map +1 -0
  461. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.cjs +2 -0
  462. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.cjs.map +1 -0
  463. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.js +38 -0
  464. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.js.map +1 -0
  465. package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.cjs +2 -0
  466. package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.cjs.map +1 -0
  467. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/paypal.js +15 -5
  468. package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.js.map +1 -0
  469. package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.cjs +2 -0
  470. package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.cjs.map +1 -0
  471. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/playwright.js +13 -6
  472. package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.js.map +1 -0
  473. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.cjs +2 -0
  474. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.cjs.map +1 -0
  475. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.js +43 -0
  476. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.js.map +1 -0
  477. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.cjs +2 -0
  478. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.cjs.map +1 -0
  479. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.js +41 -0
  480. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.js.map +1 -0
  481. package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.cjs +2 -0
  482. package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.cjs.map +1 -0
  483. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/sentry.js +15 -5
  484. package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.js.map +1 -0
  485. package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.cjs +2 -0
  486. package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.cjs.map +1 -0
  487. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/sequential-thinking.js +13 -6
  488. package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.js.map +1 -0
  489. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs +2 -0
  490. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs.map +1 -0
  491. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js +45 -0
  492. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js.map +1 -0
  493. package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.cjs +2 -0
  494. package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.cjs.map +1 -0
  495. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/stripe.js +15 -5
  496. package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.js.map +1 -0
  497. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.cjs +2 -0
  498. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.cjs.map +1 -0
  499. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.js +37 -0
  500. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.js.map +1 -0
  501. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/tavily.cjs +1 -1
  502. package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.cjs.map +1 -0
  503. package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.js +39 -0
  504. package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.js.map +1 -0
  505. package/dist/node_modules/@openhands/extensions/integrations/catalog/time.cjs +2 -0
  506. package/dist/node_modules/@openhands/extensions/integrations/catalog/time.cjs.map +1 -0
  507. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/time.js +13 -6
  508. package/dist/node_modules/@openhands/extensions/integrations/catalog/time.js.map +1 -0
  509. package/dist/node_modules/@openhands/extensions/integrations/index.cjs +2 -0
  510. package/dist/node_modules/@openhands/extensions/integrations/index.cjs.map +1 -0
  511. package/dist/node_modules/@openhands/extensions/integrations/index.js +175 -0
  512. package/dist/node_modules/@openhands/extensions/integrations/index.js.map +1 -0
  513. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/logos.cjs +1 -1
  514. package/dist/node_modules/@openhands/extensions/integrations/logos.cjs.map +1 -0
  515. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/logos.js +2 -2
  516. package/dist/node_modules/@openhands/extensions/integrations/logos.js.map +1 -0
  517. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.cjs +2 -0
  518. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.cjs.map +1 -0
  519. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.js +548 -0
  520. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.js.map +1 -0
  521. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.cjs +2 -0
  522. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.cjs.map +1 -0
  523. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.js +482 -0
  524. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.js.map +1 -0
  525. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.cjs +1 -1
  526. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.cjs.map +1 -1
  527. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.js +3 -0
  528. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.js.map +1 -1
  529. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.cjs +2 -0
  530. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.cjs.map +1 -0
  531. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.js +22 -0
  532. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.js.map +1 -0
  533. package/dist/node_modules/@openhands/typescript-client/dist/index.cjs +1 -1
  534. package/dist/node_modules/@openhands/typescript-client/dist/index.js +1 -0
  535. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs +1 -1
  536. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs.map +1 -1
  537. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js +3 -0
  538. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js.map +1 -1
  539. package/dist/package.cjs +1 -1
  540. package/dist/package.cjs.map +1 -1
  541. package/dist/package.js +6 -4
  542. package/dist/package.js.map +1 -1
  543. package/dist/routes/mcp.cjs +1 -1
  544. package/dist/routes/mcp.cjs.map +1 -1
  545. package/dist/routes/mcp.js +1 -1
  546. package/dist/routes/mcp.js.map +1 -1
  547. package/dist/stores/error-message-store.cjs +1 -1
  548. package/dist/stores/error-message-store.cjs.map +1 -1
  549. package/dist/stores/error-message-store.d.ts +10 -1
  550. package/dist/stores/error-message-store.js +16 -3
  551. package/dist/stores/error-message-store.js.map +1 -1
  552. package/dist/utils/mcp-marketplace-utils.cjs +1 -1
  553. package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
  554. package/dist/utils/mcp-marketplace-utils.d.ts +21 -1
  555. package/dist/utils/mcp-marketplace-utils.js +23 -13
  556. package/dist/utils/mcp-marketplace-utils.js.map +1 -1
  557. package/dist/utils/settings-utils.cjs.map +1 -1
  558. package/dist/utils/settings-utils.js.map +1 -1
  559. package/package.json +6 -4
  560. package/scripts/check-sdk-version-sync.mjs +6 -6
  561. package/scripts/dev-safe.mjs +25 -7
  562. package/scripts/dev-static.mjs +6 -0
  563. package/scripts/dev-with-automation.mjs +12 -1
  564. package/scripts/static-server.mjs +85 -4
  565. package/tools/canvas_ui_tool.py +129 -0
  566. package/build/assets/add-backend-modal-CqjNjGqY.js +0 -1
  567. package/build/assets/automation-detail-CQrtk33s.js +0 -1
  568. package/build/assets/automations-list-COmogz0S.js +0 -1
  569. package/build/assets/conversation-CeGMBOyB.js +0 -1
  570. package/build/assets/conversation-D8scXOe7.js +0 -17
  571. package/build/assets/conversation-panel-DMz46ji-.js +0 -1
  572. package/build/assets/conversation-websocket-context-B0Gd3yiT.js +0 -3
  573. package/build/assets/declaration-C9nuq2Dj.js +0 -1
  574. package/build/assets/edit-automation-modal-DnTHJrf1.js +0 -1
  575. package/build/assets/git-control-bar-branch-button-DhpPgadK.js +0 -27
  576. package/build/assets/install-server-modal-VB5hOBpW.js +0 -1
  577. package/build/assets/llm-settings-CIdxmimN.js +0 -1
  578. package/build/assets/manifest-6400820c.js +0 -1
  579. package/build/assets/mcp-BdfyCW1l.js +0 -9
  580. package/build/assets/messages-BfaEAG2q.js +0 -36
  581. package/build/assets/recommended-automations-launcher-Cx7svuGE.js +0 -52
  582. package/build/assets/root-6AdVEJBT.js +0 -2
  583. package/build/assets/root-DEotKI6b.css +0 -1
  584. package/build/assets/root-layout-DvYGxAnr.js +0 -2
  585. package/build/assets/settings-service.api-Z6x0l0GU.js +0 -1
  586. package/build/assets/use-is-authed-BFoh8Ogh.js +0 -1
  587. package/build/assets/use-runtime-is-ready-BQWLEyqa.js +0 -1
  588. package/build/assets/use-user-conversation-BCYpbPT1.js +0 -1
  589. package/build/assets/vendor~home~mcp~automations-list-DRfWZRnF.js +0 -1
  590. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-BJm2mGIp.js +0 -48
  591. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.cjs +0 -2
  592. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.cjs.map +0 -1
  593. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.js +0 -30
  594. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.js.map +0 -1
  595. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.cjs +0 -2
  596. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.cjs.map +0 -1
  597. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.js +0 -29
  598. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.js.map +0 -1
  599. package/dist/node_modules/@openhands/extensions/mcps/catalog/atlassian.cjs.map +0 -1
  600. package/dist/node_modules/@openhands/extensions/mcps/catalog/atlassian.js.map +0 -1
  601. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.cjs +0 -2
  602. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.cjs.map +0 -1
  603. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.js +0 -29
  604. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.js.map +0 -1
  605. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.cjs +0 -2
  606. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.cjs.map +0 -1
  607. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.js +0 -24
  608. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.js.map +0 -1
  609. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.cjs +0 -2
  610. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.cjs.map +0 -1
  611. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.js +0 -45
  612. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.js.map +0 -1
  613. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-bindings.cjs.map +0 -1
  614. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-bindings.js.map +0 -1
  615. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.cjs +0 -2
  616. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.cjs.map +0 -1
  617. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.js.map +0 -1
  618. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-builds.cjs.map +0 -1
  619. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-builds.js.map +0 -1
  620. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-docs.cjs.map +0 -1
  621. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-docs.js.map +0 -1
  622. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.cjs +0 -2
  623. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.cjs.map +0 -1
  624. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.js.map +0 -1
  625. package/dist/node_modules/@openhands/extensions/mcps/catalog/deepwiki.cjs.map +0 -1
  626. package/dist/node_modules/@openhands/extensions/mcps/catalog/deepwiki.js.map +0 -1
  627. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.cjs +0 -2
  628. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.cjs.map +0 -1
  629. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.js +0 -29
  630. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.js.map +0 -1
  631. package/dist/node_modules/@openhands/extensions/mcps/catalog/everything.cjs.map +0 -1
  632. package/dist/node_modules/@openhands/extensions/mcps/catalog/everything.js.map +0 -1
  633. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.cjs +0 -2
  634. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.cjs.map +0 -1
  635. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.js +0 -29
  636. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.js.map +0 -1
  637. package/dist/node_modules/@openhands/extensions/mcps/catalog/fetch.cjs.map +0 -1
  638. package/dist/node_modules/@openhands/extensions/mcps/catalog/fetch.js.map +0 -1
  639. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.cjs +0 -2
  640. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.cjs.map +0 -1
  641. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.js +0 -33
  642. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.js.map +0 -1
  643. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.cjs +0 -2
  644. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.cjs.map +0 -1
  645. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.js +0 -32
  646. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.js.map +0 -1
  647. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.cjs +0 -2
  648. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.cjs.map +0 -1
  649. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.js +0 -29
  650. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.js.map +0 -1
  651. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.cjs +0 -2
  652. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.cjs.map +0 -1
  653. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.js +0 -33
  654. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.js.map +0 -1
  655. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.cjs +0 -2
  656. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.cjs.map +0 -1
  657. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.js +0 -40
  658. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.js.map +0 -1
  659. package/dist/node_modules/@openhands/extensions/mcps/catalog/huggingface.cjs.map +0 -1
  660. package/dist/node_modules/@openhands/extensions/mcps/catalog/huggingface.js.map +0 -1
  661. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.cjs +0 -2
  662. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.cjs.map +0 -1
  663. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.js +0 -29
  664. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.js.map +0 -1
  665. package/dist/node_modules/@openhands/extensions/mcps/catalog/linear.cjs.map +0 -1
  666. package/dist/node_modules/@openhands/extensions/mcps/catalog/linear.js.map +0 -1
  667. package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.cjs +0 -2
  668. package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.cjs.map +0 -1
  669. package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.js.map +0 -1
  670. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.cjs +0 -2
  671. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.cjs.map +0 -1
  672. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.js +0 -29
  673. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.js.map +0 -1
  674. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.cjs +0 -2
  675. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.cjs.map +0 -1
  676. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.js +0 -33
  677. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.js.map +0 -1
  678. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.cjs +0 -2
  679. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.cjs.map +0 -1
  680. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.js +0 -32
  681. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.js.map +0 -1
  682. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.cjs +0 -2
  683. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.cjs.map +0 -1
  684. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.js +0 -31
  685. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.js.map +0 -1
  686. package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.cjs +0 -2
  687. package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.cjs.map +0 -1
  688. package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.js.map +0 -1
  689. package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.cjs +0 -2
  690. package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.cjs.map +0 -1
  691. package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.js.map +0 -1
  692. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.cjs +0 -2
  693. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.cjs.map +0 -1
  694. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.js +0 -36
  695. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.js.map +0 -1
  696. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.cjs +0 -2
  697. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.cjs.map +0 -1
  698. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.js +0 -34
  699. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.js.map +0 -1
  700. package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.cjs +0 -2
  701. package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.cjs.map +0 -1
  702. package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.js.map +0 -1
  703. package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.cjs +0 -2
  704. package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.cjs.map +0 -1
  705. package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.js.map +0 -1
  706. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.cjs +0 -2
  707. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.cjs.map +0 -1
  708. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.js +0 -38
  709. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.js.map +0 -1
  710. package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.cjs +0 -2
  711. package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.cjs.map +0 -1
  712. package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.js.map +0 -1
  713. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.cjs +0 -2
  714. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.cjs.map +0 -1
  715. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.js +0 -30
  716. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.js.map +0 -1
  717. package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.cjs.map +0 -1
  718. package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.js +0 -32
  719. package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.js.map +0 -1
  720. package/dist/node_modules/@openhands/extensions/mcps/catalog/time.cjs +0 -2
  721. package/dist/node_modules/@openhands/extensions/mcps/catalog/time.cjs.map +0 -1
  722. package/dist/node_modules/@openhands/extensions/mcps/catalog/time.js.map +0 -1
  723. package/dist/node_modules/@openhands/extensions/mcps/index.cjs +0 -2
  724. package/dist/node_modules/@openhands/extensions/mcps/index.cjs.map +0 -1
  725. package/dist/node_modules/@openhands/extensions/mcps/index.js +0 -87
  726. package/dist/node_modules/@openhands/extensions/mcps/index.js.map +0 -1
  727. package/dist/node_modules/@openhands/extensions/mcps/logos.cjs.map +0 -1
  728. package/dist/node_modules/@openhands/extensions/mcps/logos.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-tabs-context-menu.cjs","names":[],"sources":["../../../../../src/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ContextMenu } from \"#/ui/context-menu\";\nimport { useClickOutsideElement } from \"#/hooks/use-click-outside-element\";\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useConversationLocalStorageState } from \"#/utils/conversation-local-storage\";\nimport {\n useConversationStore,\n type ConversationTab,\n} from \"#/stores/conversation-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport TerminalIcon from \"#/icons/terminal.svg?react\";\nimport GlobeIcon from \"#/icons/globe.svg?react\";\nimport DocumentIcon from \"#/icons/document.svg?react\";\nimport VSCodeIcon from \"#/icons/vscode.svg?react\";\nimport PillIcon from \"#/icons/pill.svg?react\";\nimport PillFillIcon from \"#/icons/pill-fill.svg?react\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport DoubleCheckIcon from \"#/icons/double-check.svg?react\";\nimport { useTaskList } from \"#/hooks/use-task-list\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useSelectConversationTab } from \"#/hooks/use-select-conversation-tab\";\nimport { cn } from \"#/utils/utils\";\n\ninterface ConversationTabsContextMenuProps {\n isOpen: boolean;\n onClose: () => void;\n ignoreOutsideClickRef?: React.RefObject<HTMLElement | null>;\n}\n\nexport function ConversationTabsContextMenu({\n isOpen,\n onClose,\n ignoreOutsideClickRef,\n}: ConversationTabsContextMenuProps) {\n const ref = useClickOutsideElement<HTMLUListElement>(\n onClose,\n ignoreOutsideClickRef,\n );\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const {\n state,\n setUnpinnedTabs,\n setSelectedTab: setPersistedSelectedTab,\n } = useConversationLocalStorageState(conversationId);\n const { selectedTab, isRightPanelShown, setSelectedTab } =\n useConversationStore();\n\n const { navigateToTab } = useSelectConversationTab();\n\n const { hasTaskList } = useTaskList();\n const { backend } = useActiveBackend();\n\n const tabConfig = [\n {\n tab: \"planner\",\n icon: LessonPlanIcon,\n i18nKey: I18nKey.COMMON$PLANNER,\n },\n { tab: \"files\", icon: DocumentIcon, i18nKey: I18nKey.COMMON$FILES },\n { tab: \"vscode\", icon: VSCodeIcon, i18nKey: I18nKey.COMMON$CODE },\n { tab: \"terminal\", icon: TerminalIcon, i18nKey: I18nKey.COMMON$TERMINAL },\n { tab: \"browser\", icon: GlobeIcon, i18nKey: I18nKey.COMMON$BROWSER },\n ];\n\n if (hasTaskList) {\n tabConfig.unshift({\n tab: \"tasklist\",\n icon: DoubleCheckIcon,\n i18nKey: I18nKey.COMMON$TASK_LIST,\n });\n }\n\n const visibleTabConfig = tabConfig.filter(\n ({ tab }) => tab !== \"vscode\" || backend.kind === \"cloud\",\n );\n\n if (!isOpen) return null;\n\n const handleOpenTab = (tab: string) => {\n navigateToTab(tab as ConversationTab);\n onClose();\n };\n\n const handlePinToggle = (tab: string, e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (state.unpinnedTabs.includes(tab)) {\n setUnpinnedTabs(state.unpinnedTabs.filter((item) => item !== tab));\n } else {\n const newUnpinnedTabs = [...state.unpinnedTabs, tab];\n setUnpinnedTabs(newUnpinnedTabs);\n\n if (selectedTab === tab && isRightPanelShown) {\n const nextPinnedTab = visibleTabConfig.find(\n ({ tab: tabKey }) =>\n tabKey !== tab && !newUnpinnedTabs.includes(tabKey),\n );\n\n if (nextPinnedTab) {\n setSelectedTab(nextPinnedTab.tab as ConversationTab);\n setPersistedSelectedTab(nextPinnedTab.tab as ConversationTab);\n }\n }\n }\n };\n\n return (\n <ContextMenu\n ref={ref}\n alignment=\"right\"\n position=\"bottom\"\n className=\"z-[9999] mt-2 w-fit\"\n >\n {visibleTabConfig.map(({ tab, icon: Icon, i18nKey }) => {\n const pinned = !state.unpinnedTabs.includes(tab);\n return (\n <li key={tab} className=\"list-none\">\n <div\n className={cn(\n \"flex h-[30px] w-full min-w-0 items-stretch rounded\",\n \"hover:bg-[var(--oh-interactive-hover)]\",\n )}\n >\n <button\n type=\"button\"\n data-testid={`conversation-tabs-menu-open-${tab}`}\n className={cn(\n \"flex min-w-0 flex-1 cursor-pointer items-center gap-2 rounded-l p-2 text-start\",\n \"text-white transition-colors\",\n )}\n onClick={() => handleOpenTab(tab)}\n >\n <Icon className=\"h-4 w-4 shrink-0\" />\n <span className=\"text-sm\">{t(i18nKey)}</span>\n </button>\n <button\n type=\"button\"\n data-testid={`conversation-tabs-menu-pin-${tab}`}\n className={cn(\n \"flex shrink-0 cursor-pointer items-center justify-center rounded-r px-2\",\n \"text-white transition-colors hover:bg-white/10\",\n )}\n aria-pressed={pinned}\n aria-label={pinned ? \"Unpin tab from bar\" : \"Pin tab to bar\"}\n onClick={(e) => handlePinToggle(tab, e)}\n >\n {pinned ? (\n <PillFillIcon className=\"-mr-[5px] ml-auto h-7 w-7\" />\n ) : (\n <PillIcon className=\"ml-auto h-4.5 w-4.5\" />\n )}\n </button>\n </div>\n </li>\n );\n })}\n </ContextMenu>\n );\n}\n"],"mappings":"ilCA8BA,SAAgB,EAA4B,CAC1C,SACA,UACA,yBACmC,CACnC,IAAM,EAAM,EAAA,uBACV,EACA,EACD,CACK,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,CAAE,kBAAmB,EAAA,mBAAmB,CACxC,CACJ,QACA,kBACA,eAAgB,GACd,EAAA,iCAAiC,EAAe,CAC9C,CAAE,cAAa,oBAAmB,kBACtC,EAAA,sBAAsB,CAElB,CAAE,iBAAkB,EAAA,0BAA0B,CAE9C,CAAE,eAAgB,EAAA,aAAa,CAC/B,CAAE,WAAY,EAAA,kBAAkB,CAEhC,EAAY,CAChB,CACE,IAAK,UACL,KAAM,EAAA,QACN,QAAS,EAAA,QAAQ,eAClB,CACD,CAAE,IAAK,QAAS,KAAM,EAAA,QAAc,QAAS,EAAA,QAAQ,aAAc,CACnE,CAAE,IAAK,SAAU,KAAM,EAAA,QAAY,QAAS,EAAA,QAAQ,YAAa,CACjE,CAAE,IAAK,WAAY,KAAM,EAAA,QAAc,QAAS,EAAA,QAAQ,gBAAiB,CACzE,CAAE,IAAK,UAAW,KAAM,EAAA,QAAW,QAAS,EAAA,QAAQ,eAAgB,CACrE,CAEG,GACF,EAAU,QAAQ,CAChB,IAAK,WACL,KAAM,EAAA,QACN,QAAS,EAAA,QAAQ,iBAClB,CAAC,CAGJ,IAAM,EAAmB,EAAU,QAChC,CAAE,SAAU,IAAQ,UAAY,EAAQ,OAAS,QACnD,CAED,GAAI,CAAC,EAAQ,OAAO,KAEpB,IAAM,EAAiB,GAAgB,CACrC,EAAc,EAAuB,CACrC,GAAS,EAGL,GAAmB,EAAa,IAAwB,CAG5D,GAFA,EAAE,gBAAgB,CAClB,EAAE,iBAAiB,CACf,EAAM,aAAa,SAAS,EAAI,CAClC,EAAgB,EAAM,aAAa,OAAQ,GAAS,IAAS,EAAI,CAAC,KAC7D,CACL,IAAM,EAAkB,CAAC,GAAG,EAAM,aAAc,EAAI,CAGpD,GAFA,EAAgB,EAAgB,CAE5B,IAAgB,GAAO,EAAmB,CAC5C,IAAM,EAAgB,EAAiB,MACpC,CAAE,IAAK,KACN,IAAW,GAAO,CAAC,EAAgB,SAAS,EAAO,CACtD,CAEG,IACF,EAAe,EAAc,IAAuB,CACpD,EAAwB,EAAc,IAAuB,KAMrE,OACE,EAAA,EAAA,KAAC,EAAA,YAAD,CACO,MACL,UAAU,QACV,SAAS,SACT,UAAU,+BAET,EAAiB,KAAK,CAAE,MAAK,KAAM,EAAM,aAAc,CACtD,IAAM,EAAS,CAAC,EAAM,aAAa,SAAS,EAAI,CAChD,OACE,EAAA,EAAA,KAAC,KAAD,CAAc,UAAU,sBACtB,EAAA,EAAA,MAAC,MAAD,CACE,UAAW,EAAA,GACT,qDACA,yCACD,UAJH,EAME,EAAA,EAAA,MAAC,SAAD,CACE,KAAK,SACL,cAAa,+BAA+B,IAC5C,UAAW,EAAA,GACT,iFACA,+BACD,CACD,YAAe,EAAc,EAAI,UAPnC,EASE,EAAA,EAAA,KAAC,EAAD,CAAM,UAAU,mBAAqB,CAAA,EACrC,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,mBAAW,EAAE,EAAQ,CAAQ,CAAA,CACtC,IACT,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,cAAa,8BAA8B,IAC3C,UAAW,EAAA,GACT,0EACA,iDACD,CACD,eAAc,EACd,aAAY,EAAS,qBAAuB,iBAC5C,QAAU,GAAM,EAAgB,EAAK,EAAE,UAEtC,GACC,EAAA,EAAA,KAAC,EAAA,QAAD,CAAc,UAAU,4BAA8B,CAAA,EAEtD,EAAA,EAAA,KAAC,EAAA,QAAD,CAAU,UAAU,sBAAwB,CAAA,CAEvC,CAAA,CACL,GACH,CArCI,EAqCJ,EAEP,CACU,CAAA"}
1
+ {"version":3,"file":"conversation-tabs-context-menu.cjs","names":[],"sources":["../../../../../src/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ContextMenu } from \"#/ui/context-menu\";\nimport { useClickOutsideElement } from \"#/hooks/use-click-outside-element\";\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useConversationLocalStorageState } from \"#/utils/conversation-local-storage\";\nimport {\n useConversationStore,\n type ConversationTab,\n} from \"#/stores/conversation-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport TerminalIcon from \"#/icons/terminal.svg?react\";\nimport GlobeIcon from \"#/icons/globe.svg?react\";\nimport DocumentIcon from \"#/icons/document.svg?react\";\nimport VSCodeIcon from \"#/icons/vscode.svg?react\";\nimport PillIcon from \"#/icons/pill.svg?react\";\nimport PillFillIcon from \"#/icons/pill-fill.svg?react\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport DoubleCheckIcon from \"#/icons/double-check.svg?react\";\nimport { useTaskList } from \"#/hooks/use-task-list\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useSelectConversationTab } from \"#/hooks/use-select-conversation-tab\";\nimport { cn } from \"#/utils/utils\";\n\ninterface ConversationTabsContextMenuProps {\n isOpen: boolean;\n onClose: () => void;\n ignoreOutsideClickRef?: React.RefObject<HTMLElement | null>;\n}\n\nexport function ConversationTabsContextMenu({\n isOpen,\n onClose,\n ignoreOutsideClickRef,\n}: ConversationTabsContextMenuProps) {\n const ref = useClickOutsideElement<HTMLUListElement>(\n onClose,\n ignoreOutsideClickRef,\n );\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const {\n state,\n setUnpinnedTabs,\n setSelectedTab: setPersistedSelectedTab,\n } = useConversationLocalStorageState(conversationId);\n const { selectedTab, isRightPanelShown, setSelectedTab } =\n useConversationStore();\n\n const { navigateToTab } = useSelectConversationTab();\n\n const { hasTaskList } = useTaskList();\n const { backend } = useActiveBackend();\n\n const tabConfig = [\n {\n tab: \"planner\",\n icon: LessonPlanIcon,\n i18nKey: I18nKey.COMMON$PLANNER,\n },\n { tab: \"files\", icon: DocumentIcon, i18nKey: I18nKey.COMMON$FILES },\n { tab: \"vscode\", icon: VSCodeIcon, i18nKey: I18nKey.COMMON$CODE },\n { tab: \"terminal\", icon: TerminalIcon, i18nKey: I18nKey.COMMON$TERMINAL },\n { tab: \"browser\", icon: GlobeIcon, i18nKey: I18nKey.COMMON$BROWSER },\n ];\n\n if (hasTaskList) {\n tabConfig.unshift({\n tab: \"tasklist\",\n icon: DoubleCheckIcon,\n i18nKey: I18nKey.COMMON$TASK_LIST,\n });\n }\n\n const visibleTabConfig = tabConfig.filter(\n ({ tab }) =>\n (tab !== \"vscode\" && tab !== \"planner\") || backend.kind === \"cloud\",\n );\n\n if (!isOpen) return null;\n\n const handleOpenTab = (tab: string) => {\n navigateToTab(tab as ConversationTab);\n onClose();\n };\n\n const handlePinToggle = (tab: string, e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (state.unpinnedTabs.includes(tab)) {\n setUnpinnedTabs(state.unpinnedTabs.filter((item) => item !== tab));\n } else {\n const newUnpinnedTabs = [...state.unpinnedTabs, tab];\n setUnpinnedTabs(newUnpinnedTabs);\n\n if (selectedTab === tab && isRightPanelShown) {\n const nextPinnedTab = visibleTabConfig.find(\n ({ tab: tabKey }) =>\n tabKey !== tab && !newUnpinnedTabs.includes(tabKey),\n );\n\n if (nextPinnedTab) {\n setSelectedTab(nextPinnedTab.tab as ConversationTab);\n setPersistedSelectedTab(nextPinnedTab.tab as ConversationTab);\n }\n }\n }\n };\n\n return (\n <ContextMenu\n ref={ref}\n alignment=\"right\"\n position=\"bottom\"\n className=\"z-[9999] mt-2 w-fit\"\n >\n {visibleTabConfig.map(({ tab, icon: Icon, i18nKey }) => {\n const pinned = !state.unpinnedTabs.includes(tab);\n return (\n <li key={tab} className=\"list-none\">\n <div\n className={cn(\n \"flex h-[30px] w-full min-w-0 items-stretch rounded\",\n \"hover:bg-[var(--oh-interactive-hover)]\",\n )}\n >\n <button\n type=\"button\"\n data-testid={`conversation-tabs-menu-open-${tab}`}\n className={cn(\n \"flex min-w-0 flex-1 cursor-pointer items-center gap-2 rounded-l p-2 text-start\",\n \"text-white transition-colors\",\n )}\n onClick={() => handleOpenTab(tab)}\n >\n <Icon className=\"h-4 w-4 shrink-0\" />\n <span className=\"text-sm\">{t(i18nKey)}</span>\n </button>\n <button\n type=\"button\"\n data-testid={`conversation-tabs-menu-pin-${tab}`}\n className={cn(\n \"flex shrink-0 cursor-pointer items-center justify-center rounded-r px-2\",\n \"text-white transition-colors hover:bg-white/10\",\n )}\n aria-pressed={pinned}\n aria-label={pinned ? \"Unpin tab from bar\" : \"Pin tab to bar\"}\n onClick={(e) => handlePinToggle(tab, e)}\n >\n {pinned ? (\n <PillFillIcon className=\"-mr-[5px] ml-auto h-7 w-7\" />\n ) : (\n <PillIcon className=\"ml-auto h-4.5 w-4.5\" />\n )}\n </button>\n </div>\n </li>\n );\n })}\n </ContextMenu>\n );\n}\n"],"mappings":"ilCA8BA,SAAgB,EAA4B,CAC1C,SACA,UACA,yBACmC,CACnC,IAAM,EAAM,EAAA,uBACV,EACA,EACD,CACK,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,CAAE,kBAAmB,EAAA,mBAAmB,CACxC,CACJ,QACA,kBACA,eAAgB,GACd,EAAA,iCAAiC,EAAe,CAC9C,CAAE,cAAa,oBAAmB,kBACtC,EAAA,sBAAsB,CAElB,CAAE,iBAAkB,EAAA,0BAA0B,CAE9C,CAAE,eAAgB,EAAA,aAAa,CAC/B,CAAE,WAAY,EAAA,kBAAkB,CAEhC,EAAY,CAChB,CACE,IAAK,UACL,KAAM,EAAA,QACN,QAAS,EAAA,QAAQ,eAClB,CACD,CAAE,IAAK,QAAS,KAAM,EAAA,QAAc,QAAS,EAAA,QAAQ,aAAc,CACnE,CAAE,IAAK,SAAU,KAAM,EAAA,QAAY,QAAS,EAAA,QAAQ,YAAa,CACjE,CAAE,IAAK,WAAY,KAAM,EAAA,QAAc,QAAS,EAAA,QAAQ,gBAAiB,CACzE,CAAE,IAAK,UAAW,KAAM,EAAA,QAAW,QAAS,EAAA,QAAQ,eAAgB,CACrE,CAEG,GACF,EAAU,QAAQ,CAChB,IAAK,WACL,KAAM,EAAA,QACN,QAAS,EAAA,QAAQ,iBAClB,CAAC,CAGJ,IAAM,EAAmB,EAAU,QAChC,CAAE,SACA,IAAQ,UAAY,IAAQ,WAAc,EAAQ,OAAS,QAC/D,CAED,GAAI,CAAC,EAAQ,OAAO,KAEpB,IAAM,EAAiB,GAAgB,CACrC,EAAc,EAAuB,CACrC,GAAS,EAGL,GAAmB,EAAa,IAAwB,CAG5D,GAFA,EAAE,gBAAgB,CAClB,EAAE,iBAAiB,CACf,EAAM,aAAa,SAAS,EAAI,CAClC,EAAgB,EAAM,aAAa,OAAQ,GAAS,IAAS,EAAI,CAAC,KAC7D,CACL,IAAM,EAAkB,CAAC,GAAG,EAAM,aAAc,EAAI,CAGpD,GAFA,EAAgB,EAAgB,CAE5B,IAAgB,GAAO,EAAmB,CAC5C,IAAM,EAAgB,EAAiB,MACpC,CAAE,IAAK,KACN,IAAW,GAAO,CAAC,EAAgB,SAAS,EAAO,CACtD,CAEG,IACF,EAAe,EAAc,IAAuB,CACpD,EAAwB,EAAc,IAAuB,KAMrE,OACE,EAAA,EAAA,KAAC,EAAA,YAAD,CACO,MACL,UAAU,QACV,SAAS,SACT,UAAU,+BAET,EAAiB,KAAK,CAAE,MAAK,KAAM,EAAM,aAAc,CACtD,IAAM,EAAS,CAAC,EAAM,aAAa,SAAS,EAAI,CAChD,OACE,EAAA,EAAA,KAAC,KAAD,CAAc,UAAU,sBACtB,EAAA,EAAA,MAAC,MAAD,CACE,UAAW,EAAA,GACT,qDACA,yCACD,UAJH,EAME,EAAA,EAAA,MAAC,SAAD,CACE,KAAK,SACL,cAAa,+BAA+B,IAC5C,UAAW,EAAA,GACT,iFACA,+BACD,CACD,YAAe,EAAc,EAAI,UAPnC,EASE,EAAA,EAAA,KAAC,EAAD,CAAM,UAAU,mBAAqB,CAAA,EACrC,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,mBAAW,EAAE,EAAQ,CAAQ,CAAA,CACtC,IACT,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,cAAa,8BAA8B,IAC3C,UAAW,EAAA,GACT,0EACA,iDACD,CACD,eAAc,EACd,aAAY,EAAS,qBAAuB,iBAC5C,QAAU,GAAM,EAAgB,EAAK,EAAE,UAEtC,GACC,EAAA,EAAA,KAAC,EAAA,QAAD,CAAc,UAAU,4BAA8B,CAAA,EAEtD,EAAA,EAAA,KAAC,EAAA,QAAD,CAAU,UAAU,sBAAwB,CAAA,CAEvC,CAAA,CACL,GACH,CArCI,EAqCJ,EAEP,CACU,CAAA"}
@@ -53,7 +53,7 @@ function x({ isOpen: x, onClose: S, ignoreOutsideClickRef: C }) {
53
53
  icon: h,
54
54
  i18nKey: t.COMMON$TASK_LIST
55
55
  });
56
- let L = I.filter(({ tab: e }) => e !== "vscode" || F.kind === "cloud");
56
+ let L = I.filter(({ tab: e }) => e !== "vscode" && e !== "planner" || F.kind === "cloud");
57
57
  if (!x) return null;
58
58
  let R = (e) => {
59
59
  N(e), S();
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-tabs-context-menu.js","names":[],"sources":["../../../../../src/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ContextMenu } from \"#/ui/context-menu\";\nimport { useClickOutsideElement } from \"#/hooks/use-click-outside-element\";\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useConversationLocalStorageState } from \"#/utils/conversation-local-storage\";\nimport {\n useConversationStore,\n type ConversationTab,\n} from \"#/stores/conversation-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport TerminalIcon from \"#/icons/terminal.svg?react\";\nimport GlobeIcon from \"#/icons/globe.svg?react\";\nimport DocumentIcon from \"#/icons/document.svg?react\";\nimport VSCodeIcon from \"#/icons/vscode.svg?react\";\nimport PillIcon from \"#/icons/pill.svg?react\";\nimport PillFillIcon from \"#/icons/pill-fill.svg?react\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport DoubleCheckIcon from \"#/icons/double-check.svg?react\";\nimport { useTaskList } from \"#/hooks/use-task-list\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useSelectConversationTab } from \"#/hooks/use-select-conversation-tab\";\nimport { cn } from \"#/utils/utils\";\n\ninterface ConversationTabsContextMenuProps {\n isOpen: boolean;\n onClose: () => void;\n ignoreOutsideClickRef?: React.RefObject<HTMLElement | null>;\n}\n\nexport function ConversationTabsContextMenu({\n isOpen,\n onClose,\n ignoreOutsideClickRef,\n}: ConversationTabsContextMenuProps) {\n const ref = useClickOutsideElement<HTMLUListElement>(\n onClose,\n ignoreOutsideClickRef,\n );\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const {\n state,\n setUnpinnedTabs,\n setSelectedTab: setPersistedSelectedTab,\n } = useConversationLocalStorageState(conversationId);\n const { selectedTab, isRightPanelShown, setSelectedTab } =\n useConversationStore();\n\n const { navigateToTab } = useSelectConversationTab();\n\n const { hasTaskList } = useTaskList();\n const { backend } = useActiveBackend();\n\n const tabConfig = [\n {\n tab: \"planner\",\n icon: LessonPlanIcon,\n i18nKey: I18nKey.COMMON$PLANNER,\n },\n { tab: \"files\", icon: DocumentIcon, i18nKey: I18nKey.COMMON$FILES },\n { tab: \"vscode\", icon: VSCodeIcon, i18nKey: I18nKey.COMMON$CODE },\n { tab: \"terminal\", icon: TerminalIcon, i18nKey: I18nKey.COMMON$TERMINAL },\n { tab: \"browser\", icon: GlobeIcon, i18nKey: I18nKey.COMMON$BROWSER },\n ];\n\n if (hasTaskList) {\n tabConfig.unshift({\n tab: \"tasklist\",\n icon: DoubleCheckIcon,\n i18nKey: I18nKey.COMMON$TASK_LIST,\n });\n }\n\n const visibleTabConfig = tabConfig.filter(\n ({ tab }) => tab !== \"vscode\" || backend.kind === \"cloud\",\n );\n\n if (!isOpen) return null;\n\n const handleOpenTab = (tab: string) => {\n navigateToTab(tab as ConversationTab);\n onClose();\n };\n\n const handlePinToggle = (tab: string, e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (state.unpinnedTabs.includes(tab)) {\n setUnpinnedTabs(state.unpinnedTabs.filter((item) => item !== tab));\n } else {\n const newUnpinnedTabs = [...state.unpinnedTabs, tab];\n setUnpinnedTabs(newUnpinnedTabs);\n\n if (selectedTab === tab && isRightPanelShown) {\n const nextPinnedTab = visibleTabConfig.find(\n ({ tab: tabKey }) =>\n tabKey !== tab && !newUnpinnedTabs.includes(tabKey),\n );\n\n if (nextPinnedTab) {\n setSelectedTab(nextPinnedTab.tab as ConversationTab);\n setPersistedSelectedTab(nextPinnedTab.tab as ConversationTab);\n }\n }\n }\n };\n\n return (\n <ContextMenu\n ref={ref}\n alignment=\"right\"\n position=\"bottom\"\n className=\"z-[9999] mt-2 w-fit\"\n >\n {visibleTabConfig.map(({ tab, icon: Icon, i18nKey }) => {\n const pinned = !state.unpinnedTabs.includes(tab);\n return (\n <li key={tab} className=\"list-none\">\n <div\n className={cn(\n \"flex h-[30px] w-full min-w-0 items-stretch rounded\",\n \"hover:bg-[var(--oh-interactive-hover)]\",\n )}\n >\n <button\n type=\"button\"\n data-testid={`conversation-tabs-menu-open-${tab}`}\n className={cn(\n \"flex min-w-0 flex-1 cursor-pointer items-center gap-2 rounded-l p-2 text-start\",\n \"text-white transition-colors\",\n )}\n onClick={() => handleOpenTab(tab)}\n >\n <Icon className=\"h-4 w-4 shrink-0\" />\n <span className=\"text-sm\">{t(i18nKey)}</span>\n </button>\n <button\n type=\"button\"\n data-testid={`conversation-tabs-menu-pin-${tab}`}\n className={cn(\n \"flex shrink-0 cursor-pointer items-center justify-center rounded-r px-2\",\n \"text-white transition-colors hover:bg-white/10\",\n )}\n aria-pressed={pinned}\n aria-label={pinned ? \"Unpin tab from bar\" : \"Pin tab to bar\"}\n onClick={(e) => handlePinToggle(tab, e)}\n >\n {pinned ? (\n <PillFillIcon className=\"-mr-[5px] ml-auto h-7 w-7\" />\n ) : (\n <PillIcon className=\"ml-auto h-4.5 w-4.5\" />\n )}\n </button>\n </div>\n </li>\n );\n })}\n </ContextMenu>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,EAA4B,EAC1C,WACA,YACA,4BACmC;CACnC,IAAM,IAAM,EACV,GACA,EACD,EACK,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,sBAAmB,GAAmB,EACxC,EACJ,UACA,oBACA,gBAAgB,MACd,EAAiC,EAAe,EAC9C,EAAE,gBAAa,sBAAmB,sBACtC,GAAsB,EAElB,EAAE,qBAAkB,GAA0B,EAE9C,EAAE,mBAAgB,GAAa,EAC/B,EAAE,eAAY,GAAkB,EAEhC,IAAY;EAChB;GACE,KAAK;GACL,MAAM;GACN,SAAS,EAAQ;GAClB;EACD;GAAE,KAAK;GAAS,MAAM;GAAc,SAAS,EAAQ;GAAc;EACnE;GAAE,KAAK;GAAU,MAAM;GAAY,SAAS,EAAQ;GAAa;EACjE;GAAE,KAAK;GAAY,MAAM;GAAc,SAAS,EAAQ;GAAiB;EACzE;GAAE,KAAK;GAAW,MAAM;GAAW,SAAS,EAAQ;GAAgB;EACrE;AAED,CAAI,KACF,EAAU,QAAQ;EAChB,KAAK;EACL,MAAM;EACN,SAAS,EAAQ;EAClB,CAAC;CAGJ,IAAM,IAAmB,EAAU,QAChC,EAAE,aAAU,MAAQ,YAAY,EAAQ,SAAS,QACnD;AAED,KAAI,CAAC,EAAQ,QAAO;CAEpB,IAAM,KAAiB,MAAgB;AAErC,EADA,EAAc,EAAuB,EACrC,GAAS;IAGL,KAAmB,GAAa,MAAwB;AAG5D,MAFA,EAAE,gBAAgB,EAClB,EAAE,iBAAiB,EACf,EAAM,aAAa,SAAS,EAAI,CAClC,GAAgB,EAAM,aAAa,QAAQ,MAAS,MAAS,EAAI,CAAC;OAC7D;GACL,IAAM,IAAkB,CAAC,GAAG,EAAM,cAAc,EAAI;AAGpD,OAFA,EAAgB,EAAgB,EAE5B,MAAgB,KAAO,GAAmB;IAC5C,IAAM,IAAgB,EAAiB,MACpC,EAAE,KAAK,QACN,MAAW,KAAO,CAAC,EAAgB,SAAS,EAAO,CACtD;AAED,IAAI,MACF,EAAe,EAAc,IAAuB,EACpD,EAAwB,EAAc,IAAuB;;;;AAMrE,QACE,kBAAC,GAAD;EACO;EACL,WAAU;EACV,UAAS;EACT,WAAU;YAET,EAAiB,KAAK,EAAE,QAAK,MAAM,GAAM,iBAAc;GACtD,IAAM,IAAS,CAAC,EAAM,aAAa,SAAS,EAAI;AAChD,UACE,kBAAC,MAAD;IAAc,WAAU;cACtB,kBAAC,OAAD;KACE,WAAW,EACT,sDACA,yCACD;eAJH,CAME,kBAAC,UAAD;MACE,MAAK;MACL,eAAa,+BAA+B;MAC5C,WAAW,EACT,kFACA,+BACD;MACD,eAAe,EAAc,EAAI;gBAPnC,CASE,kBAAC,GAAD,EAAM,WAAU,oBAAqB,CAAA,EACrC,kBAAC,QAAD;OAAM,WAAU;iBAAW,EAAE,EAAQ;OAAQ,CAAA,CACtC;SACT,kBAAC,UAAD;MACE,MAAK;MACL,eAAa,8BAA8B;MAC3C,WAAW,EACT,2EACA,iDACD;MACD,gBAAc;MACd,cAAY,IAAS,uBAAuB;MAC5C,UAAU,MAAM,EAAgB,GAAK,EAAE;gBAEtC,IACC,kBAAC,GAAD,EAAc,WAAU,6BAA8B,CAAA,GAEtD,kBAAC,GAAD,EAAU,WAAU,uBAAwB,CAAA;MAEvC,CAAA,CACL;;IACH,EArCI,EAqCJ;IAEP;EACU,CAAA"}
1
+ {"version":3,"file":"conversation-tabs-context-menu.js","names":[],"sources":["../../../../../src/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ContextMenu } from \"#/ui/context-menu\";\nimport { useClickOutsideElement } from \"#/hooks/use-click-outside-element\";\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useConversationLocalStorageState } from \"#/utils/conversation-local-storage\";\nimport {\n useConversationStore,\n type ConversationTab,\n} from \"#/stores/conversation-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport TerminalIcon from \"#/icons/terminal.svg?react\";\nimport GlobeIcon from \"#/icons/globe.svg?react\";\nimport DocumentIcon from \"#/icons/document.svg?react\";\nimport VSCodeIcon from \"#/icons/vscode.svg?react\";\nimport PillIcon from \"#/icons/pill.svg?react\";\nimport PillFillIcon from \"#/icons/pill-fill.svg?react\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport DoubleCheckIcon from \"#/icons/double-check.svg?react\";\nimport { useTaskList } from \"#/hooks/use-task-list\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useSelectConversationTab } from \"#/hooks/use-select-conversation-tab\";\nimport { cn } from \"#/utils/utils\";\n\ninterface ConversationTabsContextMenuProps {\n isOpen: boolean;\n onClose: () => void;\n ignoreOutsideClickRef?: React.RefObject<HTMLElement | null>;\n}\n\nexport function ConversationTabsContextMenu({\n isOpen,\n onClose,\n ignoreOutsideClickRef,\n}: ConversationTabsContextMenuProps) {\n const ref = useClickOutsideElement<HTMLUListElement>(\n onClose,\n ignoreOutsideClickRef,\n );\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const {\n state,\n setUnpinnedTabs,\n setSelectedTab: setPersistedSelectedTab,\n } = useConversationLocalStorageState(conversationId);\n const { selectedTab, isRightPanelShown, setSelectedTab } =\n useConversationStore();\n\n const { navigateToTab } = useSelectConversationTab();\n\n const { hasTaskList } = useTaskList();\n const { backend } = useActiveBackend();\n\n const tabConfig = [\n {\n tab: \"planner\",\n icon: LessonPlanIcon,\n i18nKey: I18nKey.COMMON$PLANNER,\n },\n { tab: \"files\", icon: DocumentIcon, i18nKey: I18nKey.COMMON$FILES },\n { tab: \"vscode\", icon: VSCodeIcon, i18nKey: I18nKey.COMMON$CODE },\n { tab: \"terminal\", icon: TerminalIcon, i18nKey: I18nKey.COMMON$TERMINAL },\n { tab: \"browser\", icon: GlobeIcon, i18nKey: I18nKey.COMMON$BROWSER },\n ];\n\n if (hasTaskList) {\n tabConfig.unshift({\n tab: \"tasklist\",\n icon: DoubleCheckIcon,\n i18nKey: I18nKey.COMMON$TASK_LIST,\n });\n }\n\n const visibleTabConfig = tabConfig.filter(\n ({ tab }) =>\n (tab !== \"vscode\" && tab !== \"planner\") || backend.kind === \"cloud\",\n );\n\n if (!isOpen) return null;\n\n const handleOpenTab = (tab: string) => {\n navigateToTab(tab as ConversationTab);\n onClose();\n };\n\n const handlePinToggle = (tab: string, e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (state.unpinnedTabs.includes(tab)) {\n setUnpinnedTabs(state.unpinnedTabs.filter((item) => item !== tab));\n } else {\n const newUnpinnedTabs = [...state.unpinnedTabs, tab];\n setUnpinnedTabs(newUnpinnedTabs);\n\n if (selectedTab === tab && isRightPanelShown) {\n const nextPinnedTab = visibleTabConfig.find(\n ({ tab: tabKey }) =>\n tabKey !== tab && !newUnpinnedTabs.includes(tabKey),\n );\n\n if (nextPinnedTab) {\n setSelectedTab(nextPinnedTab.tab as ConversationTab);\n setPersistedSelectedTab(nextPinnedTab.tab as ConversationTab);\n }\n }\n }\n };\n\n return (\n <ContextMenu\n ref={ref}\n alignment=\"right\"\n position=\"bottom\"\n className=\"z-[9999] mt-2 w-fit\"\n >\n {visibleTabConfig.map(({ tab, icon: Icon, i18nKey }) => {\n const pinned = !state.unpinnedTabs.includes(tab);\n return (\n <li key={tab} className=\"list-none\">\n <div\n className={cn(\n \"flex h-[30px] w-full min-w-0 items-stretch rounded\",\n \"hover:bg-[var(--oh-interactive-hover)]\",\n )}\n >\n <button\n type=\"button\"\n data-testid={`conversation-tabs-menu-open-${tab}`}\n className={cn(\n \"flex min-w-0 flex-1 cursor-pointer items-center gap-2 rounded-l p-2 text-start\",\n \"text-white transition-colors\",\n )}\n onClick={() => handleOpenTab(tab)}\n >\n <Icon className=\"h-4 w-4 shrink-0\" />\n <span className=\"text-sm\">{t(i18nKey)}</span>\n </button>\n <button\n type=\"button\"\n data-testid={`conversation-tabs-menu-pin-${tab}`}\n className={cn(\n \"flex shrink-0 cursor-pointer items-center justify-center rounded-r px-2\",\n \"text-white transition-colors hover:bg-white/10\",\n )}\n aria-pressed={pinned}\n aria-label={pinned ? \"Unpin tab from bar\" : \"Pin tab to bar\"}\n onClick={(e) => handlePinToggle(tab, e)}\n >\n {pinned ? (\n <PillFillIcon className=\"-mr-[5px] ml-auto h-7 w-7\" />\n ) : (\n <PillIcon className=\"ml-auto h-4.5 w-4.5\" />\n )}\n </button>\n </div>\n </li>\n );\n })}\n </ContextMenu>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,EAA4B,EAC1C,WACA,YACA,4BACmC;CACnC,IAAM,IAAM,EACV,GACA,EACD,EACK,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,sBAAmB,GAAmB,EACxC,EACJ,UACA,oBACA,gBAAgB,MACd,EAAiC,EAAe,EAC9C,EAAE,gBAAa,sBAAmB,sBACtC,GAAsB,EAElB,EAAE,qBAAkB,GAA0B,EAE9C,EAAE,mBAAgB,GAAa,EAC/B,EAAE,eAAY,GAAkB,EAEhC,IAAY;EAChB;GACE,KAAK;GACL,MAAM;GACN,SAAS,EAAQ;GAClB;EACD;GAAE,KAAK;GAAS,MAAM;GAAc,SAAS,EAAQ;GAAc;EACnE;GAAE,KAAK;GAAU,MAAM;GAAY,SAAS,EAAQ;GAAa;EACjE;GAAE,KAAK;GAAY,MAAM;GAAc,SAAS,EAAQ;GAAiB;EACzE;GAAE,KAAK;GAAW,MAAM;GAAW,SAAS,EAAQ;GAAgB;EACrE;AAED,CAAI,KACF,EAAU,QAAQ;EAChB,KAAK;EACL,MAAM;EACN,SAAS,EAAQ;EAClB,CAAC;CAGJ,IAAM,IAAmB,EAAU,QAChC,EAAE,aACA,MAAQ,YAAY,MAAQ,aAAc,EAAQ,SAAS,QAC/D;AAED,KAAI,CAAC,EAAQ,QAAO;CAEpB,IAAM,KAAiB,MAAgB;AAErC,EADA,EAAc,EAAuB,EACrC,GAAS;IAGL,KAAmB,GAAa,MAAwB;AAG5D,MAFA,EAAE,gBAAgB,EAClB,EAAE,iBAAiB,EACf,EAAM,aAAa,SAAS,EAAI,CAClC,GAAgB,EAAM,aAAa,QAAQ,MAAS,MAAS,EAAI,CAAC;OAC7D;GACL,IAAM,IAAkB,CAAC,GAAG,EAAM,cAAc,EAAI;AAGpD,OAFA,EAAgB,EAAgB,EAE5B,MAAgB,KAAO,GAAmB;IAC5C,IAAM,IAAgB,EAAiB,MACpC,EAAE,KAAK,QACN,MAAW,KAAO,CAAC,EAAgB,SAAS,EAAO,CACtD;AAED,IAAI,MACF,EAAe,EAAc,IAAuB,EACpD,EAAwB,EAAc,IAAuB;;;;AAMrE,QACE,kBAAC,GAAD;EACO;EACL,WAAU;EACV,UAAS;EACT,WAAU;YAET,EAAiB,KAAK,EAAE,QAAK,MAAM,GAAM,iBAAc;GACtD,IAAM,IAAS,CAAC,EAAM,aAAa,SAAS,EAAI;AAChD,UACE,kBAAC,MAAD;IAAc,WAAU;cACtB,kBAAC,OAAD;KACE,WAAW,EACT,sDACA,yCACD;eAJH,CAME,kBAAC,UAAD;MACE,MAAK;MACL,eAAa,+BAA+B;MAC5C,WAAW,EACT,kFACA,+BACD;MACD,eAAe,EAAc,EAAI;gBAPnC,CASE,kBAAC,GAAD,EAAM,WAAU,oBAAqB,CAAA,EACrC,kBAAC,QAAD;OAAM,WAAU;iBAAW,EAAE,EAAQ;OAAQ,CAAA,CACtC;SACT,kBAAC,UAAD;MACE,MAAK;MACL,eAAa,8BAA8B;MAC3C,WAAW,EACT,2EACA,iDACD;MACD,gBAAc;MACd,cAAY,IAAS,uBAAuB;MAC5C,UAAU,MAAM,EAAgB,GAAK,EAAE;gBAEtC,IACC,kBAAC,GAAD,EAAc,WAAU,6BAA8B,CAAA,GAEtD,kBAAC,GAAD,EAAU,WAAU,uBAAwB,CAAA;MAEvC,CAAA,CACL;;IACH,EArCI,EAqCJ;IAEP;EACU,CAAA"}
@@ -1,2 +1,2 @@
1
- require(`../../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),t=require(`../../../../i18n/declaration.cjs`),n=require(`../../../../types/agent-state.cjs`),r=require(`../../../../utils/utils.cjs`),i=require(`../../../../hooks/use-conversation-id.cjs`),a=require(`../../../../utils/conversation-local-storage.cjs`),o=require(`../../../../stores/conversation-store.cjs`),s=require(`../../../../contexts/active-backend-context.cjs`),c=require(`../../../../hooks/use-agent-state.cjs`),l=require(`../../../../utils/mobile-top-bar-icon-button-classes.cjs`),u=require(`../../../../ui/typography.cjs`),d=require(`../../../../icons/lesson-plan.cjs`),f=require(`../../../../icons/document.cjs`),p=require(`../../../../hooks/use-handle-build-plan-click.cjs`),m=require(`../../../../hooks/use-select-conversation-tab.cjs`),h=require(`../../conversation-panel/ellipsis-button.cjs`),g=require(`../../chat/chat-action-tooltip.cjs`),_=require(`../../../../icons/terminal.cjs`),v=require(`../../../../icons/globe.cjs`),y=require(`../../../../icons/vscode.cjs`),b=require(`../../../../icons/double-check.cjs`),x=require(`./conversation-tab-nav.cjs`),ee=require(`./vscode-tooltip-content.cjs`),S=require(`../../../../hooks/use-task-list.cjs`),C=require(`./conversation-tabs-context-menu.cjs`);let w=require(`react`),T=require(`react/jsx-runtime`);function E({variant:E=`default`}){let{conversationId:D}=i.useConversationId(),{setSelectedTab:O,planContent:k}=o.useConversationStore(),[A,j]=(0,w.useState)(!1),{state:M}=a.useConversationLocalStorageState(D),{hasTaskList:N}=S.useTaskList(),{backend:P}=s.useActiveBackend(),{handleBuildPlanClick:F}=p.useHandleBuildPlanClick(),{curAgentState:I}=c.useAgentState(),{selectTab:L,isTabActive:R,onTabChange:z,selectedTab:B,isRightPanelShown:V}=m.useSelectConversationTab();(0,w.useEffect)(()=>{O(M.selectedTab)},[O,M.selectedTab]),(0,w.useEffect)(()=>{V&&(B||z(`files`))},[V,B,z]);let{t:H,i18n:U}=e.useTranslation(`openhands`),W=[{tabValue:`files`,isActive:R(`files`),icon:f.default,onClick:()=>L(`files`),tooltipContent:H(t.I18nKey.COMMON$FILES),tooltipAriaLabel:H(t.I18nKey.COMMON$FILES),label:H(t.I18nKey.COMMON$FILES)},{tabValue:`planner`,isActive:R(`planner`),icon:d.default,onClick:()=>L(`planner`),tooltipContent:H(t.I18nKey.COMMON$PLANNER),tooltipAriaLabel:H(t.I18nKey.COMMON$PLANNER),label:H(t.I18nKey.COMMON$PLANNER)},{tabValue:`vscode`,isActive:R(`vscode`),icon:y.default,onClick:()=>L(`vscode`),tooltipContent:(0,T.jsx)(ee.VSCodeTooltipContent,{}),tooltipAriaLabel:H(t.I18nKey.COMMON$CODE),label:H(t.I18nKey.COMMON$CODE)},{tabValue:`terminal`,isActive:R(`terminal`),icon:_.default,onClick:()=>L(`terminal`),tooltipContent:H(t.I18nKey.COMMON$TERMINAL),tooltipAriaLabel:H(t.I18nKey.COMMON$TERMINAL),label:H(t.I18nKey.COMMON$TERMINAL),className:`pl-2`},{tabValue:`browser`,isActive:R(`browser`),icon:v.default,onClick:()=>L(`browser`),tooltipContent:H(t.I18nKey.COMMON$BROWSER),tooltipAriaLabel:H(t.I18nKey.COMMON$BROWSER),label:H(t.I18nKey.COMMON$BROWSER)}];N&&W.splice(1,0,{tabValue:`tasklist`,isActive:R(`tasklist`),icon:b.default,onClick:()=>L(`tasklist`),tooltipContent:H(t.I18nKey.COMMON$TASK_LIST),tooltipAriaLabel:H(t.I18nKey.COMMON$TASK_LIST),label:H(t.I18nKey.COMMON$TASK_LIST)});let G=W.filter(e=>e.tabValue===`vscode`&&P.kind!==`cloud`?!1:M.unpinnedTabs.includes(e.tabValue)?B===e.tabValue:!0),K=M.unpinnedTabs.join(`,`),q=I===n.AgentState.RUNNING||I===n.AgentState.LOADING||!k,J=(0,w.useRef)(null),Y=(0,w.useRef)(null),X=(0,w.useRef)(null),Z=(0,w.useRef)(null),[Q,$]=(0,w.useState)(G.length);(0,w.useLayoutEffect)(()=>{let e=J.current,t=Y.current,n=X.current;if(!e||!t||!n)return;let r=()=>{let r=t.querySelectorAll(`[data-tab-measure="true"]`),i=r.length,a=e.getBoundingClientRect().width;if(a===0){$(i);return}let o=Array.from(r).map(e=>e.getBoundingClientRect().width);if(o.length!==i||i===0){$(Math.max(0,i));return}let s=n.getBoundingClientRect().width,c=getComputedStyle(e).columnGap||getComputedStyle(e).gap,l=parseFloat(c)||6,u=0;for(let e=i;e>=0;--e){let t=s;for(let n=0;n<e;n+=1)t+=o[n]??0;if(e>0&&(t+=e*l),t<=a+.5){u=e;break}}$(e=>e===u?e:u)};if(r(),typeof ResizeObserver>`u`)return;let i=new ResizeObserver(r);return i.observe(e),()=>i.disconnect()},[K,G.length,N,P.kind,B,V,U.language]);let te=Math.min(Q,G.length);return(0,T.jsxs)(T.Fragment,{children:[(0,T.jsxs)(`div`,{className:r.cn(`relative w-full min-w-0`,E===`compact`?`flex h-full min-h-0 items-center py-0 pl-0 pr-1`:`min-h-10 p-1`),children:[(0,T.jsx)(`div`,{ref:Y,"aria-hidden":!0,className:`pointer-events-none absolute top-0 left-[-10000px] flex flex-nowrap items-center gap-1.5`,children:G.map(({tabValue:e,icon:t,isActive:n,tooltipContent:i,tooltipAriaLabel:a,label:o,className:s},c)=>(0,T.jsx)(g.ChatActionTooltip,{tooltip:i,ariaLabel:a,children:(0,T.jsx)(x.ConversationTabNav,{tabValue:e,icon:t,onClick:()=>{},isActive:n,label:o,className:r.cn(s,`shrink-0`),measureOnly:!0})},`measure-${e}-${c}`))}),(0,T.jsx)(`div`,{ref:J,className:`flex w-full min-w-0 flex-nowrap items-center justify-start`,children:(0,T.jsxs)(`div`,{className:`flex w-fit max-w-full min-w-0 flex-nowrap items-center gap-1.5`,children:[(0,T.jsx)(`div`,{className:`flex min-w-0 flex-1 flex-nowrap items-center gap-1.5 overflow-x-hidden`,children:G.slice(0,te).map(({tabValue:e,icon:t,onClick:n,isActive:i,tooltipContent:a,tooltipAriaLabel:o,label:s,className:c},l)=>(0,T.jsx)(g.ChatActionTooltip,{tooltip:a,ariaLabel:o,children:(0,T.jsx)(x.ConversationTabNav,{tabValue:e,icon:t,onClick:n,isActive:i,label:s,className:r.cn(c,`shrink-0`)})},`${e}-${l}`))}),(0,T.jsxs)(`div`,{ref:X,className:`relative shrink-0`,children:[(0,T.jsx)(h.EllipsisButton,{ref:Z,onClick:()=>j(!A),ariaLabel:H(t.I18nKey.COMMON$MORE_OPTIONS),iconClassName:E===`compact`?l.mobileTopBarIconClassName:void 0}),(0,T.jsx)(C.ConversationTabsContextMenu,{isOpen:A,onClose:()=>j(!1),ignoreOutsideClickRef:Z})]})]})})]}),R(`planner`)&&(0,T.jsx)(`div`,{className:r.cn(`flex h-10 min-h-10 shrink-0 items-center border-t border-[var(--oh-border)] pl-[10px] pr-1`),children:(0,T.jsx)(`button`,{type:`button`,onClick:F,disabled:q,className:r.cn(`flex h-5 min-w-17 items-center justify-center rounded bg-white px-2 transition-opacity`,q?`cursor-not-allowed opacity-50`:`cursor-pointer hover:opacity-90`),"data-testid":`planner-tab-build-button`,children:(0,T.jsxs)(u.Typography.Text,{className:`text-[11px] font-normal leading-5 text-black`,children:[H(t.I18nKey.COMMON$BUILD),` ⌘↩`]})})})]})}exports.ConversationTabs=E;
1
+ require(`../../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),t=require(`../../../../i18n/declaration.cjs`),n=require(`../../../../types/agent-state.cjs`),r=require(`../../../../utils/utils.cjs`),i=require(`../../../../hooks/use-conversation-id.cjs`),a=require(`../../../../utils/conversation-local-storage.cjs`),o=require(`../../../../stores/conversation-store.cjs`),s=require(`../../../../contexts/active-backend-context.cjs`),c=require(`../../../../hooks/use-agent-state.cjs`),l=require(`../../../../utils/mobile-top-bar-icon-button-classes.cjs`),u=require(`../../../../ui/typography.cjs`),d=require(`../../../../icons/lesson-plan.cjs`),f=require(`../../../../icons/document.cjs`),p=require(`../../../../hooks/use-handle-build-plan-click.cjs`),m=require(`../../../../hooks/use-select-conversation-tab.cjs`),h=require(`../../conversation-panel/ellipsis-button.cjs`),g=require(`../../chat/chat-action-tooltip.cjs`),_=require(`../../../../icons/terminal.cjs`),v=require(`../../../../icons/globe.cjs`),y=require(`../../../../icons/vscode.cjs`),b=require(`../../../../icons/double-check.cjs`),x=require(`./conversation-tab-nav.cjs`),S=require(`./vscode-tooltip-content.cjs`),ee=require(`../../../../hooks/use-task-list.cjs`),C=require(`./conversation-tabs-context-menu.cjs`);let w=require(`react`),T=require(`react/jsx-runtime`);function E({variant:E=`default`}){let{conversationId:D}=i.useConversationId(),{setSelectedTab:O,planContent:k}=o.useConversationStore(),[A,j]=(0,w.useState)(!1),{state:M}=a.useConversationLocalStorageState(D),{hasTaskList:N}=ee.useTaskList(),{backend:P}=s.useActiveBackend(),{handleBuildPlanClick:F}=p.useHandleBuildPlanClick(),{curAgentState:I}=c.useAgentState(),{selectTab:L,isTabActive:R,onTabChange:z,selectedTab:B,isRightPanelShown:V}=m.useSelectConversationTab();(0,w.useEffect)(()=>{O(M.selectedTab)},[O,M.selectedTab]),(0,w.useEffect)(()=>{V&&(B||z(`files`))},[V,B,z]);let{t:H,i18n:U}=e.useTranslation(`openhands`),W=[{tabValue:`files`,isActive:R(`files`),icon:f.default,onClick:()=>L(`files`),tooltipContent:H(t.I18nKey.COMMON$FILES),tooltipAriaLabel:H(t.I18nKey.COMMON$FILES),label:H(t.I18nKey.COMMON$FILES)},{tabValue:`planner`,isActive:R(`planner`),icon:d.default,onClick:()=>L(`planner`),tooltipContent:H(t.I18nKey.COMMON$PLANNER),tooltipAriaLabel:H(t.I18nKey.COMMON$PLANNER),label:H(t.I18nKey.COMMON$PLANNER)},{tabValue:`vscode`,isActive:R(`vscode`),icon:y.default,onClick:()=>L(`vscode`),tooltipContent:(0,T.jsx)(S.VSCodeTooltipContent,{}),tooltipAriaLabel:H(t.I18nKey.COMMON$CODE),label:H(t.I18nKey.COMMON$CODE)},{tabValue:`terminal`,isActive:R(`terminal`),icon:_.default,onClick:()=>L(`terminal`),tooltipContent:H(t.I18nKey.COMMON$TERMINAL),tooltipAriaLabel:H(t.I18nKey.COMMON$TERMINAL),label:H(t.I18nKey.COMMON$TERMINAL),className:`pl-2`},{tabValue:`browser`,isActive:R(`browser`),icon:v.default,onClick:()=>L(`browser`),tooltipContent:H(t.I18nKey.COMMON$BROWSER),tooltipAriaLabel:H(t.I18nKey.COMMON$BROWSER),label:H(t.I18nKey.COMMON$BROWSER)}];N&&W.splice(1,0,{tabValue:`tasklist`,isActive:R(`tasklist`),icon:b.default,onClick:()=>L(`tasklist`),tooltipContent:H(t.I18nKey.COMMON$TASK_LIST),tooltipAriaLabel:H(t.I18nKey.COMMON$TASK_LIST),label:H(t.I18nKey.COMMON$TASK_LIST)});let G=W.filter(e=>e.tabValue===`vscode`&&P.kind!==`cloud`||e.tabValue===`planner`&&P.kind!==`cloud`?!1:M.unpinnedTabs.includes(e.tabValue)?B===e.tabValue:!0),K=M.unpinnedTabs.join(`,`),q=I===n.AgentState.RUNNING||I===n.AgentState.LOADING||!k,J=(0,w.useRef)(null),Y=(0,w.useRef)(null),X=(0,w.useRef)(null),Z=(0,w.useRef)(null),[Q,$]=(0,w.useState)(G.length);(0,w.useLayoutEffect)(()=>{let e=J.current,t=Y.current,n=X.current;if(!e||!t||!n)return;let r=()=>{let r=t.querySelectorAll(`[data-tab-measure="true"]`),i=r.length,a=e.getBoundingClientRect().width;if(a===0){$(i);return}let o=Array.from(r).map(e=>e.getBoundingClientRect().width);if(o.length!==i||i===0){$(Math.max(0,i));return}let s=n.getBoundingClientRect().width,c=getComputedStyle(e).columnGap||getComputedStyle(e).gap,l=parseFloat(c)||6,u=0;for(let e=i;e>=0;--e){let t=s;for(let n=0;n<e;n+=1)t+=o[n]??0;if(e>0&&(t+=e*l),t<=a+.5){u=e;break}}$(e=>e===u?e:u)};if(r(),typeof ResizeObserver>`u`)return;let i=new ResizeObserver(r);return i.observe(e),()=>i.disconnect()},[K,G.length,N,P.kind,B,V,U.language]);let te=Math.min(Q,G.length);return(0,T.jsxs)(T.Fragment,{children:[(0,T.jsxs)(`div`,{className:r.cn(`relative w-full min-w-0`,E===`compact`?`flex h-full min-h-0 items-center py-0 pl-0 pr-1`:`min-h-10 p-1`),children:[(0,T.jsx)(`div`,{ref:Y,"aria-hidden":!0,className:`pointer-events-none absolute top-0 left-[-10000px] flex flex-nowrap items-center gap-1.5`,children:G.map(({tabValue:e,icon:t,isActive:n,tooltipContent:i,tooltipAriaLabel:a,label:o,className:s},c)=>(0,T.jsx)(g.ChatActionTooltip,{tooltip:i,ariaLabel:a,children:(0,T.jsx)(x.ConversationTabNav,{tabValue:e,icon:t,onClick:()=>{},isActive:n,label:o,className:r.cn(s,`shrink-0`),measureOnly:!0})},`measure-${e}-${c}`))}),(0,T.jsx)(`div`,{ref:J,className:`flex w-full min-w-0 flex-nowrap items-center justify-start`,children:(0,T.jsxs)(`div`,{className:`flex w-fit max-w-full min-w-0 flex-nowrap items-center gap-1.5`,children:[(0,T.jsx)(`div`,{className:`flex min-w-0 flex-1 flex-nowrap items-center gap-1.5 overflow-x-hidden`,children:G.slice(0,te).map(({tabValue:e,icon:t,onClick:n,isActive:i,tooltipContent:a,tooltipAriaLabel:o,label:s,className:c},l)=>(0,T.jsx)(g.ChatActionTooltip,{tooltip:a,ariaLabel:o,children:(0,T.jsx)(x.ConversationTabNav,{tabValue:e,icon:t,onClick:n,isActive:i,label:s,className:r.cn(c,`shrink-0`)})},`${e}-${l}`))}),(0,T.jsxs)(`div`,{ref:X,className:`relative shrink-0`,children:[(0,T.jsx)(h.EllipsisButton,{ref:Z,onClick:()=>j(!A),ariaLabel:H(t.I18nKey.COMMON$MORE_OPTIONS),iconClassName:E===`compact`?l.mobileTopBarIconClassName:void 0}),(0,T.jsx)(C.ConversationTabsContextMenu,{isOpen:A,onClose:()=>j(!1),ignoreOutsideClickRef:Z})]})]})})]}),R(`planner`)&&(0,T.jsx)(`div`,{className:r.cn(`flex h-10 min-h-10 shrink-0 items-center border-t border-[var(--oh-border)] pl-[10px] pr-1`),children:(0,T.jsx)(`button`,{type:`button`,onClick:F,disabled:q,className:r.cn(`flex h-5 min-w-17 items-center justify-center rounded bg-white px-2 transition-opacity`,q?`cursor-not-allowed opacity-50`:`cursor-pointer hover:opacity-90`),"data-testid":`planner-tab-build-button`,children:(0,T.jsxs)(u.Typography.Text,{className:`text-[11px] font-normal leading-5 text-black`,children:[H(t.I18nKey.COMMON$BUILD),` ⌘↩`]})})})]})}exports.ConversationTabs=E;
2
2
  //# sourceMappingURL=conversation-tabs.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-tabs.cjs","names":[],"sources":["../../../../../src/components/features/conversation/conversation-tabs/conversation-tabs.tsx"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport TerminalIcon from \"#/icons/terminal.svg?react\";\nimport GlobeIcon from \"#/icons/globe.svg?react\";\nimport DocumentIcon from \"#/icons/document.svg?react\";\nimport VSCodeIcon from \"#/icons/vscode.svg?react\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport DoubleCheckIcon from \"#/icons/double-check.svg?react\";\nimport { EllipsisButton } from \"#/components/features/conversation-panel/ellipsis-button\";\nimport { cn } from \"#/utils/utils\";\nimport { useConversationLocalStorageState } from \"#/utils/conversation-local-storage\";\nimport { ConversationTabNav } from \"./conversation-tab-nav\";\nimport { ChatActionTooltip } from \"../../chat/chat-action-tooltip\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { VSCodeTooltipContent } from \"./vscode-tooltip-content\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { ConversationTabsContextMenu } from \"./conversation-tabs-context-menu\";\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useSelectConversationTab } from \"#/hooks/use-select-conversation-tab\";\nimport { useTaskList } from \"#/hooks/use-task-list\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useHandleBuildPlanClick } from \"#/hooks/use-handle-build-plan-click\";\nimport { useAgentState } from \"#/hooks/use-agent-state\";\nimport { AgentState } from \"#/types/agent-state\";\nimport { Typography } from \"#/ui/typography\";\nimport { mobileTopBarIconClassName } from \"#/utils/mobile-top-bar-icon-button-classes\";\n\nexport function ConversationTabs({\n variant = \"default\",\n}: {\n variant?: \"default\" | \"compact\";\n}) {\n const { conversationId } = useConversationId();\n const { setSelectedTab, planContent } = useConversationStore();\n\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n\n const { state: persistedState } =\n useConversationLocalStorageState(conversationId);\n\n const { hasTaskList } = useTaskList();\n const { backend } = useActiveBackend();\n\n const { handleBuildPlanClick } = useHandleBuildPlanClick();\n const { curAgentState } = useAgentState();\n\n const {\n selectTab,\n isTabActive,\n onTabChange,\n selectedTab,\n isRightPanelShown,\n } = useSelectConversationTab();\n\n // Restore the most-recently-used tab from localStorage so users don't\n // lose their tab selection across reloads.\n //\n // Note: we deliberately do NOT mirror `rightPanelShown` from\n // localStorage. The drawer's open/closed state is session-only — see\n // the comment in `useConversationStore` and the schema note in\n // `conversation-local-storage.ts` for the rationale.\n useEffect(() => {\n setSelectedTab(persistedState.selectedTab);\n }, [setSelectedTab, persistedState.selectedTab]);\n\n useEffect(() => {\n const handlePanelVisibilityChange = () => {\n if (isRightPanelShown) {\n // If no tab is selected, default to files tab\n if (!selectedTab) {\n onTabChange(\"files\");\n }\n }\n };\n\n handlePanelVisibilityChange();\n }, [isRightPanelShown, selectedTab, onTabChange]);\n\n const { t, i18n } = useTranslation(\"openhands\");\n\n // `files` is intentionally the leftmost tab — it's the primary entry\n // point for inspecting agent output (workspace files + git diff).\n const tabs = [\n {\n tabValue: \"files\",\n isActive: isTabActive(\"files\"),\n icon: DocumentIcon,\n onClick: () => selectTab(\"files\"),\n tooltipContent: t(I18nKey.COMMON$FILES),\n tooltipAriaLabel: t(I18nKey.COMMON$FILES),\n label: t(I18nKey.COMMON$FILES),\n },\n {\n tabValue: \"planner\",\n isActive: isTabActive(\"planner\"),\n icon: LessonPlanIcon,\n onClick: () => selectTab(\"planner\"),\n tooltipContent: t(I18nKey.COMMON$PLANNER),\n tooltipAriaLabel: t(I18nKey.COMMON$PLANNER),\n label: t(I18nKey.COMMON$PLANNER),\n },\n {\n tabValue: \"vscode\",\n isActive: isTabActive(\"vscode\"),\n icon: VSCodeIcon,\n onClick: () => selectTab(\"vscode\"),\n tooltipContent: <VSCodeTooltipContent />,\n tooltipAriaLabel: t(I18nKey.COMMON$CODE),\n label: t(I18nKey.COMMON$CODE),\n },\n {\n tabValue: \"terminal\",\n isActive: isTabActive(\"terminal\"),\n icon: TerminalIcon,\n onClick: () => selectTab(\"terminal\"),\n tooltipContent: t(I18nKey.COMMON$TERMINAL),\n tooltipAriaLabel: t(I18nKey.COMMON$TERMINAL),\n label: t(I18nKey.COMMON$TERMINAL),\n className: \"pl-2\",\n },\n {\n tabValue: \"browser\",\n isActive: isTabActive(\"browser\"),\n icon: GlobeIcon,\n onClick: () => selectTab(\"browser\"),\n tooltipContent: t(I18nKey.COMMON$BROWSER),\n tooltipAriaLabel: t(I18nKey.COMMON$BROWSER),\n label: t(I18nKey.COMMON$BROWSER),\n },\n ];\n\n if (hasTaskList) {\n // Insert after `files` so the leftmost slot stays Files.\n tabs.splice(1, 0, {\n tabValue: \"tasklist\",\n isActive: isTabActive(\"tasklist\"),\n icon: DoubleCheckIcon,\n onClick: () => selectTab(\"tasklist\"),\n tooltipContent: t(I18nKey.COMMON$TASK_LIST),\n tooltipAriaLabel: t(I18nKey.COMMON$TASK_LIST),\n label: t(I18nKey.COMMON$TASK_LIST),\n });\n }\n\n // Pinned tabs always show in the bar. Unpinned tabs stay hidden unless the\n // user has that tab selected — then it appears while active so the bar\n // matches the open panel. Hide VS Code on local backends (cloud-only URL).\n const visibleTabs = tabs.filter((tab) => {\n if (tab.tabValue === \"vscode\" && backend.kind !== \"cloud\") return false;\n if (!persistedState.unpinnedTabs.includes(tab.tabValue)) return true;\n return selectedTab === tab.tabValue;\n });\n\n const unpinnedSignature = persistedState.unpinnedTabs.join(\",\");\n\n const isAgentRunning =\n curAgentState === AgentState.RUNNING ||\n curAgentState === AgentState.LOADING;\n const isBuildDisabled = isAgentRunning || !planContent;\n\n const tabsRowInnerRef = useRef<HTMLDivElement>(null);\n const measureRowRef = useRef<HTMLDivElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLButtonElement>(null);\n const [inlineTabCount, setInlineTabCount] = useState(visibleTabs.length);\n\n useLayoutEffect(() => {\n const rowInner = tabsRowInnerRef.current;\n const measureRow = measureRowRef.current;\n const menuEl = menuRef.current;\n if (!rowInner || !measureRow || !menuEl) return undefined;\n\n const measure = () => {\n const measureButtons = measureRow.querySelectorAll<HTMLButtonElement>(\n '[data-tab-measure=\"true\"]',\n );\n const tabCount = measureButtons.length;\n\n const rowWidth = rowInner.getBoundingClientRect().width;\n if (rowWidth === 0) {\n setInlineTabCount(tabCount);\n return;\n }\n\n const widths = Array.from(measureButtons).map(\n (button) => button.getBoundingClientRect().width,\n );\n\n if (widths.length !== tabCount || tabCount === 0) {\n setInlineTabCount(Math.max(0, tabCount));\n return;\n }\n\n const menuWidth = menuEl.getBoundingClientRect().width;\n const gapCss =\n getComputedStyle(rowInner).columnGap || getComputedStyle(rowInner).gap;\n const gapPx = parseFloat(gapCss) || 6;\n\n let nextCount = 0;\n for (let k = tabCount; k >= 0; k -= 1) {\n let total = menuWidth;\n for (let i = 0; i < k; i += 1) {\n total += widths[i] ?? 0;\n }\n if (k > 0) {\n total += k * gapPx;\n }\n if (total <= rowWidth + 0.5) {\n nextCount = k;\n break;\n }\n }\n\n setInlineTabCount((prev) => (prev === nextCount ? prev : nextCount));\n };\n\n measure();\n if (typeof ResizeObserver === \"undefined\") return undefined;\n const ro = new ResizeObserver(measure);\n ro.observe(rowInner);\n return () => ro.disconnect();\n }, [\n unpinnedSignature,\n visibleTabs.length,\n hasTaskList,\n backend.kind,\n selectedTab,\n isRightPanelShown,\n i18n.language,\n ]);\n\n const safeInlineTabCount = Math.min(inlineTabCount, visibleTabs.length);\n\n return (\n <>\n <div\n className={cn(\n \"relative w-full min-w-0\",\n variant === \"compact\"\n ? \"flex h-full min-h-0 items-center py-0 pl-0 pr-1\"\n : \"min-h-10 p-1\",\n )}\n >\n <div\n ref={measureRowRef}\n aria-hidden\n className=\"pointer-events-none absolute top-0 left-[-10000px] flex flex-nowrap items-center gap-1.5\"\n >\n {visibleTabs.map(\n (\n {\n tabValue,\n icon,\n isActive,\n tooltipContent,\n tooltipAriaLabel,\n label,\n className: tabClassName,\n },\n index,\n ) => (\n <ChatActionTooltip\n key={`measure-${tabValue}-${index}`}\n tooltip={tooltipContent}\n ariaLabel={tooltipAriaLabel}\n >\n <ConversationTabNav\n tabValue={tabValue}\n icon={icon}\n onClick={() => {}}\n isActive={isActive}\n label={label}\n className={cn(tabClassName, \"shrink-0\")}\n measureOnly\n />\n </ChatActionTooltip>\n ),\n )}\n </div>\n <div\n ref={tabsRowInnerRef}\n className=\"flex w-full min-w-0 flex-nowrap items-center justify-start\"\n >\n <div className=\"flex w-fit max-w-full min-w-0 flex-nowrap items-center gap-1.5\">\n <div className=\"flex min-w-0 flex-1 flex-nowrap items-center gap-1.5 overflow-x-hidden\">\n {visibleTabs\n .slice(0, safeInlineTabCount)\n .map(\n (\n {\n tabValue,\n icon,\n onClick,\n isActive,\n tooltipContent,\n tooltipAriaLabel,\n label,\n className: tabClassName,\n },\n index,\n ) => (\n <ChatActionTooltip\n key={`${tabValue}-${index}`}\n tooltip={tooltipContent}\n ariaLabel={tooltipAriaLabel}\n >\n <ConversationTabNav\n tabValue={tabValue}\n icon={icon}\n onClick={onClick}\n isActive={isActive}\n label={label}\n className={cn(tabClassName, \"shrink-0\")}\n />\n </ChatActionTooltip>\n ),\n )}\n </div>\n <div ref={menuRef} className=\"relative shrink-0\">\n <EllipsisButton\n ref={anchorRef}\n onClick={() => setIsMenuOpen(!isMenuOpen)}\n ariaLabel={t(I18nKey.COMMON$MORE_OPTIONS)}\n iconClassName={\n variant === \"compact\" ? mobileTopBarIconClassName : undefined\n }\n />\n <ConversationTabsContextMenu\n isOpen={isMenuOpen}\n onClose={() => setIsMenuOpen(false)}\n ignoreOutsideClickRef={anchorRef}\n />\n </div>\n </div>\n </div>\n </div>\n {isTabActive(\"planner\") && (\n <div\n className={cn(\n \"flex h-10 min-h-10 shrink-0 items-center border-t border-[var(--oh-border)] pl-[10px] pr-1\",\n )}\n >\n <button\n type=\"button\"\n onClick={handleBuildPlanClick}\n disabled={isBuildDisabled}\n className={cn(\n \"flex h-5 min-w-17 items-center justify-center rounded bg-white px-2 transition-opacity\",\n isBuildDisabled\n ? \"cursor-not-allowed opacity-50\"\n : \"cursor-pointer hover:opacity-90\",\n )}\n data-testid=\"planner-tab-build-button\"\n >\n <Typography.Text className=\"text-[11px] font-normal leading-5 text-black\">\n {/* eslint-disable-next-line i18next/no-literal-string */}\n {t(I18nKey.COMMON$BUILD)} ⌘↩\n </Typography.Text>\n </button>\n </div>\n )}\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"conversation-tabs.cjs","names":[],"sources":["../../../../../src/components/features/conversation/conversation-tabs/conversation-tabs.tsx"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport TerminalIcon from \"#/icons/terminal.svg?react\";\nimport GlobeIcon from \"#/icons/globe.svg?react\";\nimport DocumentIcon from \"#/icons/document.svg?react\";\nimport VSCodeIcon from \"#/icons/vscode.svg?react\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport DoubleCheckIcon from \"#/icons/double-check.svg?react\";\nimport { EllipsisButton } from \"#/components/features/conversation-panel/ellipsis-button\";\nimport { cn } from \"#/utils/utils\";\nimport { useConversationLocalStorageState } from \"#/utils/conversation-local-storage\";\nimport { ConversationTabNav } from \"./conversation-tab-nav\";\nimport { ChatActionTooltip } from \"../../chat/chat-action-tooltip\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { VSCodeTooltipContent } from \"./vscode-tooltip-content\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { ConversationTabsContextMenu } from \"./conversation-tabs-context-menu\";\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useSelectConversationTab } from \"#/hooks/use-select-conversation-tab\";\nimport { useTaskList } from \"#/hooks/use-task-list\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useHandleBuildPlanClick } from \"#/hooks/use-handle-build-plan-click\";\nimport { useAgentState } from \"#/hooks/use-agent-state\";\nimport { AgentState } from \"#/types/agent-state\";\nimport { Typography } from \"#/ui/typography\";\nimport { mobileTopBarIconClassName } from \"#/utils/mobile-top-bar-icon-button-classes\";\n\nexport function ConversationTabs({\n variant = \"default\",\n}: {\n variant?: \"default\" | \"compact\";\n}) {\n const { conversationId } = useConversationId();\n const { setSelectedTab, planContent } = useConversationStore();\n\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n\n const { state: persistedState } =\n useConversationLocalStorageState(conversationId);\n\n const { hasTaskList } = useTaskList();\n const { backend } = useActiveBackend();\n\n const { handleBuildPlanClick } = useHandleBuildPlanClick();\n const { curAgentState } = useAgentState();\n\n const {\n selectTab,\n isTabActive,\n onTabChange,\n selectedTab,\n isRightPanelShown,\n } = useSelectConversationTab();\n\n // Restore the most-recently-used tab from localStorage so users don't\n // lose their tab selection across reloads.\n //\n // Note: we deliberately do NOT mirror `rightPanelShown` from\n // localStorage. The drawer's open/closed state is session-only — see\n // the comment in `useConversationStore` and the schema note in\n // `conversation-local-storage.ts` for the rationale.\n useEffect(() => {\n setSelectedTab(persistedState.selectedTab);\n }, [setSelectedTab, persistedState.selectedTab]);\n\n useEffect(() => {\n const handlePanelVisibilityChange = () => {\n if (isRightPanelShown) {\n // If no tab is selected, default to files tab\n if (!selectedTab) {\n onTabChange(\"files\");\n }\n }\n };\n\n handlePanelVisibilityChange();\n }, [isRightPanelShown, selectedTab, onTabChange]);\n\n const { t, i18n } = useTranslation(\"openhands\");\n\n // `files` is intentionally the leftmost tab — it's the primary entry\n // point for inspecting agent output (workspace files + git diff).\n const tabs = [\n {\n tabValue: \"files\",\n isActive: isTabActive(\"files\"),\n icon: DocumentIcon,\n onClick: () => selectTab(\"files\"),\n tooltipContent: t(I18nKey.COMMON$FILES),\n tooltipAriaLabel: t(I18nKey.COMMON$FILES),\n label: t(I18nKey.COMMON$FILES),\n },\n {\n tabValue: \"planner\",\n isActive: isTabActive(\"planner\"),\n icon: LessonPlanIcon,\n onClick: () => selectTab(\"planner\"),\n tooltipContent: t(I18nKey.COMMON$PLANNER),\n tooltipAriaLabel: t(I18nKey.COMMON$PLANNER),\n label: t(I18nKey.COMMON$PLANNER),\n },\n {\n tabValue: \"vscode\",\n isActive: isTabActive(\"vscode\"),\n icon: VSCodeIcon,\n onClick: () => selectTab(\"vscode\"),\n tooltipContent: <VSCodeTooltipContent />,\n tooltipAriaLabel: t(I18nKey.COMMON$CODE),\n label: t(I18nKey.COMMON$CODE),\n },\n {\n tabValue: \"terminal\",\n isActive: isTabActive(\"terminal\"),\n icon: TerminalIcon,\n onClick: () => selectTab(\"terminal\"),\n tooltipContent: t(I18nKey.COMMON$TERMINAL),\n tooltipAriaLabel: t(I18nKey.COMMON$TERMINAL),\n label: t(I18nKey.COMMON$TERMINAL),\n className: \"pl-2\",\n },\n {\n tabValue: \"browser\",\n isActive: isTabActive(\"browser\"),\n icon: GlobeIcon,\n onClick: () => selectTab(\"browser\"),\n tooltipContent: t(I18nKey.COMMON$BROWSER),\n tooltipAriaLabel: t(I18nKey.COMMON$BROWSER),\n label: t(I18nKey.COMMON$BROWSER),\n },\n ];\n\n if (hasTaskList) {\n // Insert after `files` so the leftmost slot stays Files.\n tabs.splice(1, 0, {\n tabValue: \"tasklist\",\n isActive: isTabActive(\"tasklist\"),\n icon: DoubleCheckIcon,\n onClick: () => selectTab(\"tasklist\"),\n tooltipContent: t(I18nKey.COMMON$TASK_LIST),\n tooltipAriaLabel: t(I18nKey.COMMON$TASK_LIST),\n label: t(I18nKey.COMMON$TASK_LIST),\n });\n }\n\n // Pinned tabs always show in the bar. Unpinned tabs stay hidden unless the\n // user has that tab selected — then it appears while active so the bar\n // matches the open panel. Hide VS Code and Planner on local backends —\n // both are cloud-only (the planning agent isn't supported locally).\n const visibleTabs = tabs.filter((tab) => {\n if (tab.tabValue === \"vscode\" && backend.kind !== \"cloud\") return false;\n if (tab.tabValue === \"planner\" && backend.kind !== \"cloud\") return false;\n if (!persistedState.unpinnedTabs.includes(tab.tabValue)) return true;\n return selectedTab === tab.tabValue;\n });\n\n const unpinnedSignature = persistedState.unpinnedTabs.join(\",\");\n\n const isAgentRunning =\n curAgentState === AgentState.RUNNING ||\n curAgentState === AgentState.LOADING;\n const isBuildDisabled = isAgentRunning || !planContent;\n\n const tabsRowInnerRef = useRef<HTMLDivElement>(null);\n const measureRowRef = useRef<HTMLDivElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLButtonElement>(null);\n const [inlineTabCount, setInlineTabCount] = useState(visibleTabs.length);\n\n useLayoutEffect(() => {\n const rowInner = tabsRowInnerRef.current;\n const measureRow = measureRowRef.current;\n const menuEl = menuRef.current;\n if (!rowInner || !measureRow || !menuEl) return undefined;\n\n const measure = () => {\n const measureButtons = measureRow.querySelectorAll<HTMLButtonElement>(\n '[data-tab-measure=\"true\"]',\n );\n const tabCount = measureButtons.length;\n\n const rowWidth = rowInner.getBoundingClientRect().width;\n if (rowWidth === 0) {\n setInlineTabCount(tabCount);\n return;\n }\n\n const widths = Array.from(measureButtons).map(\n (button) => button.getBoundingClientRect().width,\n );\n\n if (widths.length !== tabCount || tabCount === 0) {\n setInlineTabCount(Math.max(0, tabCount));\n return;\n }\n\n const menuWidth = menuEl.getBoundingClientRect().width;\n const gapCss =\n getComputedStyle(rowInner).columnGap || getComputedStyle(rowInner).gap;\n const gapPx = parseFloat(gapCss) || 6;\n\n let nextCount = 0;\n for (let k = tabCount; k >= 0; k -= 1) {\n let total = menuWidth;\n for (let i = 0; i < k; i += 1) {\n total += widths[i] ?? 0;\n }\n if (k > 0) {\n total += k * gapPx;\n }\n if (total <= rowWidth + 0.5) {\n nextCount = k;\n break;\n }\n }\n\n setInlineTabCount((prev) => (prev === nextCount ? prev : nextCount));\n };\n\n measure();\n if (typeof ResizeObserver === \"undefined\") return undefined;\n const ro = new ResizeObserver(measure);\n ro.observe(rowInner);\n return () => ro.disconnect();\n }, [\n unpinnedSignature,\n visibleTabs.length,\n hasTaskList,\n backend.kind,\n selectedTab,\n isRightPanelShown,\n i18n.language,\n ]);\n\n const safeInlineTabCount = Math.min(inlineTabCount, visibleTabs.length);\n\n return (\n <>\n <div\n className={cn(\n \"relative w-full min-w-0\",\n variant === \"compact\"\n ? \"flex h-full min-h-0 items-center py-0 pl-0 pr-1\"\n : \"min-h-10 p-1\",\n )}\n >\n <div\n ref={measureRowRef}\n aria-hidden\n className=\"pointer-events-none absolute top-0 left-[-10000px] flex flex-nowrap items-center gap-1.5\"\n >\n {visibleTabs.map(\n (\n {\n tabValue,\n icon,\n isActive,\n tooltipContent,\n tooltipAriaLabel,\n label,\n className: tabClassName,\n },\n index,\n ) => (\n <ChatActionTooltip\n key={`measure-${tabValue}-${index}`}\n tooltip={tooltipContent}\n ariaLabel={tooltipAriaLabel}\n >\n <ConversationTabNav\n tabValue={tabValue}\n icon={icon}\n onClick={() => {}}\n isActive={isActive}\n label={label}\n className={cn(tabClassName, \"shrink-0\")}\n measureOnly\n />\n </ChatActionTooltip>\n ),\n )}\n </div>\n <div\n ref={tabsRowInnerRef}\n className=\"flex w-full min-w-0 flex-nowrap items-center justify-start\"\n >\n <div className=\"flex w-fit max-w-full min-w-0 flex-nowrap items-center gap-1.5\">\n <div className=\"flex min-w-0 flex-1 flex-nowrap items-center gap-1.5 overflow-x-hidden\">\n {visibleTabs\n .slice(0, safeInlineTabCount)\n .map(\n (\n {\n tabValue,\n icon,\n onClick,\n isActive,\n tooltipContent,\n tooltipAriaLabel,\n label,\n className: tabClassName,\n },\n index,\n ) => (\n <ChatActionTooltip\n key={`${tabValue}-${index}`}\n tooltip={tooltipContent}\n ariaLabel={tooltipAriaLabel}\n >\n <ConversationTabNav\n tabValue={tabValue}\n icon={icon}\n onClick={onClick}\n isActive={isActive}\n label={label}\n className={cn(tabClassName, \"shrink-0\")}\n />\n </ChatActionTooltip>\n ),\n )}\n </div>\n <div ref={menuRef} className=\"relative shrink-0\">\n <EllipsisButton\n ref={anchorRef}\n onClick={() => setIsMenuOpen(!isMenuOpen)}\n ariaLabel={t(I18nKey.COMMON$MORE_OPTIONS)}\n iconClassName={\n variant === \"compact\" ? mobileTopBarIconClassName : undefined\n }\n />\n <ConversationTabsContextMenu\n isOpen={isMenuOpen}\n onClose={() => setIsMenuOpen(false)}\n ignoreOutsideClickRef={anchorRef}\n />\n </div>\n </div>\n </div>\n </div>\n {isTabActive(\"planner\") && (\n <div\n className={cn(\n \"flex h-10 min-h-10 shrink-0 items-center border-t border-[var(--oh-border)] pl-[10px] pr-1\",\n )}\n >\n <button\n type=\"button\"\n onClick={handleBuildPlanClick}\n disabled={isBuildDisabled}\n className={cn(\n \"flex h-5 min-w-17 items-center justify-center rounded bg-white px-2 transition-opacity\",\n isBuildDisabled\n ? \"cursor-not-allowed opacity-50\"\n : \"cursor-pointer hover:opacity-90\",\n )}\n data-testid=\"planner-tab-build-button\"\n >\n <Typography.Text className=\"text-[11px] font-normal leading-5 text-black\">\n {/* eslint-disable-next-line i18next/no-literal-string */}\n {t(I18nKey.COMMON$BUILD)} ⌘↩\n </Typography.Text>\n </button>\n </div>\n )}\n </>\n );\n}\n"],"mappings":"43CA2BA,SAAgB,EAAiB,CAC/B,UAAU,WAGT,CACD,GAAM,CAAE,kBAAmB,EAAA,mBAAmB,CACxC,CAAE,iBAAgB,eAAgB,EAAA,sBAAsB,CAExD,CAAC,EAAY,IAAA,EAAA,EAAA,UAA0B,GAAM,CAE7C,CAAE,MAAO,GACb,EAAA,iCAAiC,EAAe,CAE5C,CAAE,eAAgB,GAAA,aAAa,CAC/B,CAAE,WAAY,EAAA,kBAAkB,CAEhC,CAAE,wBAAyB,EAAA,yBAAyB,CACpD,CAAE,iBAAkB,EAAA,eAAe,CAEnC,CACJ,YACA,cACA,cACA,cACA,qBACE,EAAA,0BAA0B,EAS9B,EAAA,EAAA,eAAgB,CACd,EAAe,EAAe,YAAY,EACzC,CAAC,EAAgB,EAAe,YAAY,CAAC,EAEhD,EAAA,EAAA,eAAgB,CAER,IAEG,GACH,EAAY,QAAQ,GAMzB,CAAC,EAAmB,EAAa,EAAY,CAAC,CAEjD,GAAM,CAAE,IAAG,QAAS,EAAA,eAAe,YAAY,CAIzC,EAAO,CACX,CACE,SAAU,QACV,SAAU,EAAY,QAAQ,CAC9B,KAAM,EAAA,QACN,YAAe,EAAU,QAAQ,CACjC,eAAgB,EAAE,EAAA,QAAQ,aAAa,CACvC,iBAAkB,EAAE,EAAA,QAAQ,aAAa,CACzC,MAAO,EAAE,EAAA,QAAQ,aAAa,CAC/B,CACD,CACE,SAAU,UACV,SAAU,EAAY,UAAU,CAChC,KAAM,EAAA,QACN,YAAe,EAAU,UAAU,CACnC,eAAgB,EAAE,EAAA,QAAQ,eAAe,CACzC,iBAAkB,EAAE,EAAA,QAAQ,eAAe,CAC3C,MAAO,EAAE,EAAA,QAAQ,eAAe,CACjC,CACD,CACE,SAAU,SACV,SAAU,EAAY,SAAS,CAC/B,KAAM,EAAA,QACN,YAAe,EAAU,SAAS,CAClC,gBAAgB,EAAA,EAAA,KAAC,EAAA,qBAAD,EAAwB,CAAA,CACxC,iBAAkB,EAAE,EAAA,QAAQ,YAAY,CACxC,MAAO,EAAE,EAAA,QAAQ,YAAY,CAC9B,CACD,CACE,SAAU,WACV,SAAU,EAAY,WAAW,CACjC,KAAM,EAAA,QACN,YAAe,EAAU,WAAW,CACpC,eAAgB,EAAE,EAAA,QAAQ,gBAAgB,CAC1C,iBAAkB,EAAE,EAAA,QAAQ,gBAAgB,CAC5C,MAAO,EAAE,EAAA,QAAQ,gBAAgB,CACjC,UAAW,OACZ,CACD,CACE,SAAU,UACV,SAAU,EAAY,UAAU,CAChC,KAAM,EAAA,QACN,YAAe,EAAU,UAAU,CACnC,eAAgB,EAAE,EAAA,QAAQ,eAAe,CACzC,iBAAkB,EAAE,EAAA,QAAQ,eAAe,CAC3C,MAAO,EAAE,EAAA,QAAQ,eAAe,CACjC,CACF,CAEG,GAEF,EAAK,OAAO,EAAG,EAAG,CAChB,SAAU,WACV,SAAU,EAAY,WAAW,CACjC,KAAM,EAAA,QACN,YAAe,EAAU,WAAW,CACpC,eAAgB,EAAE,EAAA,QAAQ,iBAAiB,CAC3C,iBAAkB,EAAE,EAAA,QAAQ,iBAAiB,CAC7C,MAAO,EAAE,EAAA,QAAQ,iBAAiB,CACnC,CAAC,CAOJ,IAAM,EAAc,EAAK,OAAQ,GAC3B,EAAI,WAAa,UAAY,EAAQ,OAAS,SAC9C,EAAI,WAAa,WAAa,EAAQ,OAAS,QAAgB,GAC9D,EAAe,aAAa,SAAS,EAAI,SAAS,CAChD,IAAgB,EAAI,SADqC,GAEhE,CAEI,EAAoB,EAAe,aAAa,KAAK,IAAI,CAKzD,EAFJ,IAAkB,EAAA,WAAW,SAC7B,IAAkB,EAAA,WAAW,SACW,CAAC,EAErC,GAAA,EAAA,EAAA,QAAyC,KAAK,CAC9C,GAAA,EAAA,EAAA,QAAuC,KAAK,CAC5C,GAAA,EAAA,EAAA,QAAiC,KAAK,CACtC,GAAA,EAAA,EAAA,QAAsC,KAAK,CAC3C,CAAC,EAAgB,IAAA,EAAA,EAAA,UAA8B,EAAY,OAAO,EAExE,EAAA,EAAA,qBAAsB,CACpB,IAAM,EAAW,EAAgB,QAC3B,EAAa,EAAc,QAC3B,EAAS,EAAQ,QACvB,GAAI,CAAC,GAAY,CAAC,GAAc,CAAC,EAAQ,OAEzC,IAAM,MAAgB,CACpB,IAAM,EAAiB,EAAW,iBAChC,4BACD,CACK,EAAW,EAAe,OAE1B,EAAW,EAAS,uBAAuB,CAAC,MAClD,GAAI,IAAa,EAAG,CAClB,EAAkB,EAAS,CAC3B,OAGF,IAAM,EAAS,MAAM,KAAK,EAAe,CAAC,IACvC,GAAW,EAAO,uBAAuB,CAAC,MAC5C,CAED,GAAI,EAAO,SAAW,GAAY,IAAa,EAAG,CAChD,EAAkB,KAAK,IAAI,EAAG,EAAS,CAAC,CACxC,OAGF,IAAM,EAAY,EAAO,uBAAuB,CAAC,MAC3C,EACJ,iBAAiB,EAAS,CAAC,WAAa,iBAAiB,EAAS,CAAC,IAC/D,EAAQ,WAAW,EAAO,EAAI,EAEhC,EAAY,EAChB,IAAK,IAAI,EAAI,EAAU,GAAK,EAAG,IAAQ,CACrC,IAAI,EAAQ,EACZ,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,GAAK,EAC1B,GAAS,EAAO,IAAM,EAKxB,GAHI,EAAI,IACN,GAAS,EAAI,GAEX,GAAS,EAAW,GAAK,CAC3B,EAAY,EACZ,OAIJ,EAAmB,GAAU,IAAS,EAAY,EAAO,EAAW,EAItE,GADA,GAAS,CACL,OAAO,eAAmB,IAAa,OAC3C,IAAM,EAAK,IAAI,eAAe,EAAQ,CAEtC,OADA,EAAG,QAAQ,EAAS,KACP,EAAG,YAAY,EAC3B,CACD,EACA,EAAY,OACZ,EACA,EAAQ,KACR,EACA,EACA,EAAK,SACN,CAAC,CAEF,IAAM,GAAqB,KAAK,IAAI,EAAgB,EAAY,OAAO,CAEvE,OACE,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,MAAC,MAAD,CACE,UAAW,EAAA,GACT,0BACA,IAAY,UACR,kDACA,eACL,UANH,EAQE,EAAA,EAAA,KAAC,MAAD,CACE,IAAK,EACL,cAAA,GACA,UAAU,oGAET,EAAY,KAET,CACE,WACA,OACA,WACA,iBACA,mBACA,QACA,UAAW,GAEb,KAEA,EAAA,EAAA,KAAC,EAAA,kBAAD,CAEE,QAAS,EACT,UAAW,YAEX,EAAA,EAAA,KAAC,EAAA,mBAAD,CACY,WACJ,OACN,YAAe,GACL,WACH,QACP,UAAW,EAAA,GAAG,EAAc,WAAW,CACvC,YAAA,GACA,CAAA,CACgB,CAbb,WAAW,EAAS,GAAG,IAaV,CAEvB,CACG,CAAA,EACN,EAAA,EAAA,KAAC,MAAD,CACE,IAAK,EACL,UAAU,uEAEV,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0EAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,kFACZ,EACE,MAAM,EAAG,GAAmB,CAC5B,KAEG,CACE,WACA,OACA,UACA,WACA,iBACA,mBACA,QACA,UAAW,GAEb,KAEA,EAAA,EAAA,KAAC,EAAA,kBAAD,CAEE,QAAS,EACT,UAAW,YAEX,EAAA,EAAA,KAAC,EAAA,mBAAD,CACY,WACJ,OACG,UACC,WACH,QACP,UAAW,EAAA,GAAG,EAAc,WAAW,CACvC,CAAA,CACgB,CAZb,GAAG,EAAS,GAAG,IAYF,CAEvB,CACC,CAAA,EACN,EAAA,EAAA,MAAC,MAAD,CAAK,IAAK,EAAS,UAAU,6BAA7B,EACE,EAAA,EAAA,KAAC,EAAA,eAAD,CACE,IAAK,EACL,YAAe,EAAc,CAAC,EAAW,CACzC,UAAW,EAAE,EAAA,QAAQ,oBAAoB,CACzC,cACE,IAAY,UAAY,EAAA,0BAA4B,IAAA,GAEtD,CAAA,EACF,EAAA,EAAA,KAAC,EAAA,4BAAD,CACE,OAAQ,EACR,YAAe,EAAc,GAAM,CACnC,sBAAuB,EACvB,CAAA,CACE,GACF,GACF,CAAA,CACF,GACL,EAAY,UAAU,GACrB,EAAA,EAAA,KAAC,MAAD,CACE,UAAW,EAAA,GACT,6FACD,WAED,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,QAAS,EACT,SAAU,EACV,UAAW,EAAA,GACT,yFACA,EACI,gCACA,kCACL,CACD,cAAY,qCAEZ,EAAA,EAAA,MAAC,EAAA,WAAW,KAAZ,CAAiB,UAAU,wDAA3B,CAEG,EAAE,EAAA,QAAQ,aAAa,CAAC,MACT,GACX,CAAA,CACL,CAAA,CAEP,CAAA,CAAA"}
@@ -10,24 +10,24 @@ import { useAgentState as c } from "../../../../hooks/use-agent-state.js";
10
10
  import { mobileTopBarIconClassName as l } from "../../../../utils/mobile-top-bar-icon-button-classes.js";
11
11
  import { Typography as u } from "../../../../ui/typography.js";
12
12
  import d from "../../../../icons/lesson-plan.js";
13
- import ee from "../../../../icons/document.js";
14
- import { useHandleBuildPlanClick as te } from "../../../../hooks/use-handle-build-plan-click.js";
15
- import { useSelectConversationTab as ne } from "../../../../hooks/use-select-conversation-tab.js";
16
- import { EllipsisButton as f } from "../../conversation-panel/ellipsis-button.js";
17
- import { ChatActionTooltip as p } from "../../chat/chat-action-tooltip.js";
18
- import m from "../../../../icons/terminal.js";
13
+ import f from "../../../../icons/document.js";
14
+ import { useHandleBuildPlanClick as ee } from "../../../../hooks/use-handle-build-plan-click.js";
15
+ import { useSelectConversationTab as te } from "../../../../hooks/use-select-conversation-tab.js";
16
+ import { EllipsisButton as p } from "../../conversation-panel/ellipsis-button.js";
17
+ import { ChatActionTooltip as m } from "../../chat/chat-action-tooltip.js";
18
+ import ne from "../../../../icons/terminal.js";
19
19
  import h from "../../../../icons/globe.js";
20
20
  import g from "../../../../icons/vscode.js";
21
21
  import _ from "../../../../icons/double-check.js";
22
22
  import { ConversationTabNav as v } from "./conversation-tab-nav.js";
23
23
  import { VSCodeTooltipContent as y } from "./vscode-tooltip-content.js";
24
- import { useTaskList as re } from "../../../../hooks/use-task-list.js";
25
- import { ConversationTabsContextMenu as b } from "./conversation-tabs-context-menu.js";
24
+ import { useTaskList as b } from "../../../../hooks/use-task-list.js";
25
+ import { ConversationTabsContextMenu as re } from "./conversation-tabs-context-menu.js";
26
26
  import { useEffect as x, useLayoutEffect as S, useRef as C, useState as w } from "react";
27
27
  import { Fragment as ie, jsx as T, jsxs as E } from "react/jsx-runtime";
28
28
  //#region src/components/features/conversation/conversation-tabs/conversation-tabs.tsx
29
29
  function D({ variant: D = "default" }) {
30
- let { conversationId: O } = i(), { setSelectedTab: k, planContent: A } = o(), [j, M] = w(!1), { state: N } = a(O), { hasTaskList: P } = re(), { backend: F } = s(), { handleBuildPlanClick: I } = te(), { curAgentState: L } = c(), { selectTab: R, isTabActive: z, onTabChange: B, selectedTab: V, isRightPanelShown: H } = ne();
30
+ let { conversationId: O } = i(), { setSelectedTab: k, planContent: A } = o(), [j, M] = w(!1), { state: N } = a(O), { hasTaskList: P } = b(), { backend: F } = s(), { handleBuildPlanClick: I } = ee(), { curAgentState: L } = c(), { selectTab: R, isTabActive: z, onTabChange: B, selectedTab: V, isRightPanelShown: H } = te();
31
31
  x(() => {
32
32
  k(N.selectedTab);
33
33
  }, [k, N.selectedTab]), x(() => {
@@ -41,7 +41,7 @@ function D({ variant: D = "default" }) {
41
41
  {
42
42
  tabValue: "files",
43
43
  isActive: z("files"),
44
- icon: ee,
44
+ icon: f,
45
45
  onClick: () => R("files"),
46
46
  tooltipContent: U(t.COMMON$FILES),
47
47
  tooltipAriaLabel: U(t.COMMON$FILES),
@@ -68,7 +68,7 @@ function D({ variant: D = "default" }) {
68
68
  {
69
69
  tabValue: "terminal",
70
70
  isActive: z("terminal"),
71
- icon: m,
71
+ icon: ne,
72
72
  onClick: () => R("terminal"),
73
73
  tooltipContent: U(t.COMMON$TERMINAL),
74
74
  tooltipAriaLabel: U(t.COMMON$TERMINAL),
@@ -94,7 +94,7 @@ function D({ variant: D = "default" }) {
94
94
  tooltipAriaLabel: U(t.COMMON$TASK_LIST),
95
95
  label: U(t.COMMON$TASK_LIST)
96
96
  });
97
- let K = G.filter((e) => e.tabValue === "vscode" && F.kind !== "cloud" ? !1 : N.unpinnedTabs.includes(e.tabValue) ? V === e.tabValue : !0), q = N.unpinnedTabs.join(","), J = L === n.RUNNING || L === n.LOADING || !A, Y = C(null), X = C(null), Z = C(null), Q = C(null), [ae, $] = w(K.length);
97
+ let K = G.filter((e) => e.tabValue === "vscode" && F.kind !== "cloud" || e.tabValue === "planner" && F.kind !== "cloud" ? !1 : N.unpinnedTabs.includes(e.tabValue) ? V === e.tabValue : !0), q = N.unpinnedTabs.join(","), J = L === n.RUNNING || L === n.LOADING || !A, Y = C(null), X = C(null), Z = C(null), Q = C(null), [ae, $] = w(K.length);
98
98
  S(() => {
99
99
  let e = Y.current, t = X.current, n = Z.current;
100
100
  if (!e || !t || !n) return;
@@ -139,7 +139,7 @@ function D({ variant: D = "default" }) {
139
139
  ref: X,
140
140
  "aria-hidden": !0,
141
141
  className: "pointer-events-none absolute top-0 left-[-10000px] flex flex-nowrap items-center gap-1.5",
142
- children: K.map(({ tabValue: e, icon: t, isActive: n, tooltipContent: i, tooltipAriaLabel: a, label: o, className: s }, c) => /* @__PURE__ */ T(p, {
142
+ children: K.map(({ tabValue: e, icon: t, isActive: n, tooltipContent: i, tooltipAriaLabel: a, label: o, className: s }, c) => /* @__PURE__ */ T(m, {
143
143
  tooltip: i,
144
144
  ariaLabel: a,
145
145
  children: /* @__PURE__ */ T(v, {
@@ -159,7 +159,7 @@ function D({ variant: D = "default" }) {
159
159
  className: "flex w-fit max-w-full min-w-0 flex-nowrap items-center gap-1.5",
160
160
  children: [/* @__PURE__ */ T("div", {
161
161
  className: "flex min-w-0 flex-1 flex-nowrap items-center gap-1.5 overflow-x-hidden",
162
- children: K.slice(0, oe).map(({ tabValue: e, icon: t, onClick: n, isActive: i, tooltipContent: a, tooltipAriaLabel: o, label: s, className: c }, l) => /* @__PURE__ */ T(p, {
162
+ children: K.slice(0, oe).map(({ tabValue: e, icon: t, onClick: n, isActive: i, tooltipContent: a, tooltipAriaLabel: o, label: s, className: c }, l) => /* @__PURE__ */ T(m, {
163
163
  tooltip: a,
164
164
  ariaLabel: o,
165
165
  children: /* @__PURE__ */ T(v, {
@@ -174,12 +174,12 @@ function D({ variant: D = "default" }) {
174
174
  }), /* @__PURE__ */ E("div", {
175
175
  ref: Z,
176
176
  className: "relative shrink-0",
177
- children: [/* @__PURE__ */ T(f, {
177
+ children: [/* @__PURE__ */ T(p, {
178
178
  ref: Q,
179
179
  onClick: () => M(!j),
180
180
  ariaLabel: U(t.COMMON$MORE_OPTIONS),
181
181
  iconClassName: D === "compact" ? l : void 0
182
- }), /* @__PURE__ */ T(b, {
182
+ }), /* @__PURE__ */ T(re, {
183
183
  isOpen: j,
184
184
  onClose: () => M(!1),
185
185
  ignoreOutsideClickRef: Q
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-tabs.js","names":[],"sources":["../../../../../src/components/features/conversation/conversation-tabs/conversation-tabs.tsx"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport TerminalIcon from \"#/icons/terminal.svg?react\";\nimport GlobeIcon from \"#/icons/globe.svg?react\";\nimport DocumentIcon from \"#/icons/document.svg?react\";\nimport VSCodeIcon from \"#/icons/vscode.svg?react\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport DoubleCheckIcon from \"#/icons/double-check.svg?react\";\nimport { EllipsisButton } from \"#/components/features/conversation-panel/ellipsis-button\";\nimport { cn } from \"#/utils/utils\";\nimport { useConversationLocalStorageState } from \"#/utils/conversation-local-storage\";\nimport { ConversationTabNav } from \"./conversation-tab-nav\";\nimport { ChatActionTooltip } from \"../../chat/chat-action-tooltip\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { VSCodeTooltipContent } from \"./vscode-tooltip-content\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { ConversationTabsContextMenu } from \"./conversation-tabs-context-menu\";\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useSelectConversationTab } from \"#/hooks/use-select-conversation-tab\";\nimport { useTaskList } from \"#/hooks/use-task-list\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useHandleBuildPlanClick } from \"#/hooks/use-handle-build-plan-click\";\nimport { useAgentState } from \"#/hooks/use-agent-state\";\nimport { AgentState } from \"#/types/agent-state\";\nimport { Typography } from \"#/ui/typography\";\nimport { mobileTopBarIconClassName } from \"#/utils/mobile-top-bar-icon-button-classes\";\n\nexport function ConversationTabs({\n variant = \"default\",\n}: {\n variant?: \"default\" | \"compact\";\n}) {\n const { conversationId } = useConversationId();\n const { setSelectedTab, planContent } = useConversationStore();\n\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n\n const { state: persistedState } =\n useConversationLocalStorageState(conversationId);\n\n const { hasTaskList } = useTaskList();\n const { backend } = useActiveBackend();\n\n const { handleBuildPlanClick } = useHandleBuildPlanClick();\n const { curAgentState } = useAgentState();\n\n const {\n selectTab,\n isTabActive,\n onTabChange,\n selectedTab,\n isRightPanelShown,\n } = useSelectConversationTab();\n\n // Restore the most-recently-used tab from localStorage so users don't\n // lose their tab selection across reloads.\n //\n // Note: we deliberately do NOT mirror `rightPanelShown` from\n // localStorage. The drawer's open/closed state is session-only — see\n // the comment in `useConversationStore` and the schema note in\n // `conversation-local-storage.ts` for the rationale.\n useEffect(() => {\n setSelectedTab(persistedState.selectedTab);\n }, [setSelectedTab, persistedState.selectedTab]);\n\n useEffect(() => {\n const handlePanelVisibilityChange = () => {\n if (isRightPanelShown) {\n // If no tab is selected, default to files tab\n if (!selectedTab) {\n onTabChange(\"files\");\n }\n }\n };\n\n handlePanelVisibilityChange();\n }, [isRightPanelShown, selectedTab, onTabChange]);\n\n const { t, i18n } = useTranslation(\"openhands\");\n\n // `files` is intentionally the leftmost tab — it's the primary entry\n // point for inspecting agent output (workspace files + git diff).\n const tabs = [\n {\n tabValue: \"files\",\n isActive: isTabActive(\"files\"),\n icon: DocumentIcon,\n onClick: () => selectTab(\"files\"),\n tooltipContent: t(I18nKey.COMMON$FILES),\n tooltipAriaLabel: t(I18nKey.COMMON$FILES),\n label: t(I18nKey.COMMON$FILES),\n },\n {\n tabValue: \"planner\",\n isActive: isTabActive(\"planner\"),\n icon: LessonPlanIcon,\n onClick: () => selectTab(\"planner\"),\n tooltipContent: t(I18nKey.COMMON$PLANNER),\n tooltipAriaLabel: t(I18nKey.COMMON$PLANNER),\n label: t(I18nKey.COMMON$PLANNER),\n },\n {\n tabValue: \"vscode\",\n isActive: isTabActive(\"vscode\"),\n icon: VSCodeIcon,\n onClick: () => selectTab(\"vscode\"),\n tooltipContent: <VSCodeTooltipContent />,\n tooltipAriaLabel: t(I18nKey.COMMON$CODE),\n label: t(I18nKey.COMMON$CODE),\n },\n {\n tabValue: \"terminal\",\n isActive: isTabActive(\"terminal\"),\n icon: TerminalIcon,\n onClick: () => selectTab(\"terminal\"),\n tooltipContent: t(I18nKey.COMMON$TERMINAL),\n tooltipAriaLabel: t(I18nKey.COMMON$TERMINAL),\n label: t(I18nKey.COMMON$TERMINAL),\n className: \"pl-2\",\n },\n {\n tabValue: \"browser\",\n isActive: isTabActive(\"browser\"),\n icon: GlobeIcon,\n onClick: () => selectTab(\"browser\"),\n tooltipContent: t(I18nKey.COMMON$BROWSER),\n tooltipAriaLabel: t(I18nKey.COMMON$BROWSER),\n label: t(I18nKey.COMMON$BROWSER),\n },\n ];\n\n if (hasTaskList) {\n // Insert after `files` so the leftmost slot stays Files.\n tabs.splice(1, 0, {\n tabValue: \"tasklist\",\n isActive: isTabActive(\"tasklist\"),\n icon: DoubleCheckIcon,\n onClick: () => selectTab(\"tasklist\"),\n tooltipContent: t(I18nKey.COMMON$TASK_LIST),\n tooltipAriaLabel: t(I18nKey.COMMON$TASK_LIST),\n label: t(I18nKey.COMMON$TASK_LIST),\n });\n }\n\n // Pinned tabs always show in the bar. Unpinned tabs stay hidden unless the\n // user has that tab selected — then it appears while active so the bar\n // matches the open panel. Hide VS Code on local backends (cloud-only URL).\n const visibleTabs = tabs.filter((tab) => {\n if (tab.tabValue === \"vscode\" && backend.kind !== \"cloud\") return false;\n if (!persistedState.unpinnedTabs.includes(tab.tabValue)) return true;\n return selectedTab === tab.tabValue;\n });\n\n const unpinnedSignature = persistedState.unpinnedTabs.join(\",\");\n\n const isAgentRunning =\n curAgentState === AgentState.RUNNING ||\n curAgentState === AgentState.LOADING;\n const isBuildDisabled = isAgentRunning || !planContent;\n\n const tabsRowInnerRef = useRef<HTMLDivElement>(null);\n const measureRowRef = useRef<HTMLDivElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLButtonElement>(null);\n const [inlineTabCount, setInlineTabCount] = useState(visibleTabs.length);\n\n useLayoutEffect(() => {\n const rowInner = tabsRowInnerRef.current;\n const measureRow = measureRowRef.current;\n const menuEl = menuRef.current;\n if (!rowInner || !measureRow || !menuEl) return undefined;\n\n const measure = () => {\n const measureButtons = measureRow.querySelectorAll<HTMLButtonElement>(\n '[data-tab-measure=\"true\"]',\n );\n const tabCount = measureButtons.length;\n\n const rowWidth = rowInner.getBoundingClientRect().width;\n if (rowWidth === 0) {\n setInlineTabCount(tabCount);\n return;\n }\n\n const widths = Array.from(measureButtons).map(\n (button) => button.getBoundingClientRect().width,\n );\n\n if (widths.length !== tabCount || tabCount === 0) {\n setInlineTabCount(Math.max(0, tabCount));\n return;\n }\n\n const menuWidth = menuEl.getBoundingClientRect().width;\n const gapCss =\n getComputedStyle(rowInner).columnGap || getComputedStyle(rowInner).gap;\n const gapPx = parseFloat(gapCss) || 6;\n\n let nextCount = 0;\n for (let k = tabCount; k >= 0; k -= 1) {\n let total = menuWidth;\n for (let i = 0; i < k; i += 1) {\n total += widths[i] ?? 0;\n }\n if (k > 0) {\n total += k * gapPx;\n }\n if (total <= rowWidth + 0.5) {\n nextCount = k;\n break;\n }\n }\n\n setInlineTabCount((prev) => (prev === nextCount ? prev : nextCount));\n };\n\n measure();\n if (typeof ResizeObserver === \"undefined\") return undefined;\n const ro = new ResizeObserver(measure);\n ro.observe(rowInner);\n return () => ro.disconnect();\n }, [\n unpinnedSignature,\n visibleTabs.length,\n hasTaskList,\n backend.kind,\n selectedTab,\n isRightPanelShown,\n i18n.language,\n ]);\n\n const safeInlineTabCount = Math.min(inlineTabCount, visibleTabs.length);\n\n return (\n <>\n <div\n className={cn(\n \"relative w-full min-w-0\",\n variant === \"compact\"\n ? \"flex h-full min-h-0 items-center py-0 pl-0 pr-1\"\n : \"min-h-10 p-1\",\n )}\n >\n <div\n ref={measureRowRef}\n aria-hidden\n className=\"pointer-events-none absolute top-0 left-[-10000px] flex flex-nowrap items-center gap-1.5\"\n >\n {visibleTabs.map(\n (\n {\n tabValue,\n icon,\n isActive,\n tooltipContent,\n tooltipAriaLabel,\n label,\n className: tabClassName,\n },\n index,\n ) => (\n <ChatActionTooltip\n key={`measure-${tabValue}-${index}`}\n tooltip={tooltipContent}\n ariaLabel={tooltipAriaLabel}\n >\n <ConversationTabNav\n tabValue={tabValue}\n icon={icon}\n onClick={() => {}}\n isActive={isActive}\n label={label}\n className={cn(tabClassName, \"shrink-0\")}\n measureOnly\n />\n </ChatActionTooltip>\n ),\n )}\n </div>\n <div\n ref={tabsRowInnerRef}\n className=\"flex w-full min-w-0 flex-nowrap items-center justify-start\"\n >\n <div className=\"flex w-fit max-w-full min-w-0 flex-nowrap items-center gap-1.5\">\n <div className=\"flex min-w-0 flex-1 flex-nowrap items-center gap-1.5 overflow-x-hidden\">\n {visibleTabs\n .slice(0, safeInlineTabCount)\n .map(\n (\n {\n tabValue,\n icon,\n onClick,\n isActive,\n tooltipContent,\n tooltipAriaLabel,\n label,\n className: tabClassName,\n },\n index,\n ) => (\n <ChatActionTooltip\n key={`${tabValue}-${index}`}\n tooltip={tooltipContent}\n ariaLabel={tooltipAriaLabel}\n >\n <ConversationTabNav\n tabValue={tabValue}\n icon={icon}\n onClick={onClick}\n isActive={isActive}\n label={label}\n className={cn(tabClassName, \"shrink-0\")}\n />\n </ChatActionTooltip>\n ),\n )}\n </div>\n <div ref={menuRef} className=\"relative shrink-0\">\n <EllipsisButton\n ref={anchorRef}\n onClick={() => setIsMenuOpen(!isMenuOpen)}\n ariaLabel={t(I18nKey.COMMON$MORE_OPTIONS)}\n iconClassName={\n variant === \"compact\" ? mobileTopBarIconClassName : undefined\n }\n />\n <ConversationTabsContextMenu\n isOpen={isMenuOpen}\n onClose={() => setIsMenuOpen(false)}\n ignoreOutsideClickRef={anchorRef}\n />\n </div>\n </div>\n </div>\n </div>\n {isTabActive(\"planner\") && (\n <div\n className={cn(\n \"flex h-10 min-h-10 shrink-0 items-center border-t border-[var(--oh-border)] pl-[10px] pr-1\",\n )}\n >\n <button\n type=\"button\"\n onClick={handleBuildPlanClick}\n disabled={isBuildDisabled}\n className={cn(\n \"flex h-5 min-w-17 items-center justify-center rounded bg-white px-2 transition-opacity\",\n isBuildDisabled\n ? \"cursor-not-allowed opacity-50\"\n : \"cursor-pointer hover:opacity-90\",\n )}\n data-testid=\"planner-tab-build-button\"\n >\n <Typography.Text className=\"text-[11px] font-normal leading-5 text-black\">\n {/* eslint-disable-next-line i18next/no-literal-string */}\n {t(I18nKey.COMMON$BUILD)} ⌘↩\n </Typography.Text>\n </button>\n </div>\n )}\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"conversation-tabs.js","names":[],"sources":["../../../../../src/components/features/conversation/conversation-tabs/conversation-tabs.tsx"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport TerminalIcon from \"#/icons/terminal.svg?react\";\nimport GlobeIcon from \"#/icons/globe.svg?react\";\nimport DocumentIcon from \"#/icons/document.svg?react\";\nimport VSCodeIcon from \"#/icons/vscode.svg?react\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport DoubleCheckIcon from \"#/icons/double-check.svg?react\";\nimport { EllipsisButton } from \"#/components/features/conversation-panel/ellipsis-button\";\nimport { cn } from \"#/utils/utils\";\nimport { useConversationLocalStorageState } from \"#/utils/conversation-local-storage\";\nimport { ConversationTabNav } from \"./conversation-tab-nav\";\nimport { ChatActionTooltip } from \"../../chat/chat-action-tooltip\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { VSCodeTooltipContent } from \"./vscode-tooltip-content\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { ConversationTabsContextMenu } from \"./conversation-tabs-context-menu\";\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useSelectConversationTab } from \"#/hooks/use-select-conversation-tab\";\nimport { useTaskList } from \"#/hooks/use-task-list\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useHandleBuildPlanClick } from \"#/hooks/use-handle-build-plan-click\";\nimport { useAgentState } from \"#/hooks/use-agent-state\";\nimport { AgentState } from \"#/types/agent-state\";\nimport { Typography } from \"#/ui/typography\";\nimport { mobileTopBarIconClassName } from \"#/utils/mobile-top-bar-icon-button-classes\";\n\nexport function ConversationTabs({\n variant = \"default\",\n}: {\n variant?: \"default\" | \"compact\";\n}) {\n const { conversationId } = useConversationId();\n const { setSelectedTab, planContent } = useConversationStore();\n\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n\n const { state: persistedState } =\n useConversationLocalStorageState(conversationId);\n\n const { hasTaskList } = useTaskList();\n const { backend } = useActiveBackend();\n\n const { handleBuildPlanClick } = useHandleBuildPlanClick();\n const { curAgentState } = useAgentState();\n\n const {\n selectTab,\n isTabActive,\n onTabChange,\n selectedTab,\n isRightPanelShown,\n } = useSelectConversationTab();\n\n // Restore the most-recently-used tab from localStorage so users don't\n // lose their tab selection across reloads.\n //\n // Note: we deliberately do NOT mirror `rightPanelShown` from\n // localStorage. The drawer's open/closed state is session-only — see\n // the comment in `useConversationStore` and the schema note in\n // `conversation-local-storage.ts` for the rationale.\n useEffect(() => {\n setSelectedTab(persistedState.selectedTab);\n }, [setSelectedTab, persistedState.selectedTab]);\n\n useEffect(() => {\n const handlePanelVisibilityChange = () => {\n if (isRightPanelShown) {\n // If no tab is selected, default to files tab\n if (!selectedTab) {\n onTabChange(\"files\");\n }\n }\n };\n\n handlePanelVisibilityChange();\n }, [isRightPanelShown, selectedTab, onTabChange]);\n\n const { t, i18n } = useTranslation(\"openhands\");\n\n // `files` is intentionally the leftmost tab — it's the primary entry\n // point for inspecting agent output (workspace files + git diff).\n const tabs = [\n {\n tabValue: \"files\",\n isActive: isTabActive(\"files\"),\n icon: DocumentIcon,\n onClick: () => selectTab(\"files\"),\n tooltipContent: t(I18nKey.COMMON$FILES),\n tooltipAriaLabel: t(I18nKey.COMMON$FILES),\n label: t(I18nKey.COMMON$FILES),\n },\n {\n tabValue: \"planner\",\n isActive: isTabActive(\"planner\"),\n icon: LessonPlanIcon,\n onClick: () => selectTab(\"planner\"),\n tooltipContent: t(I18nKey.COMMON$PLANNER),\n tooltipAriaLabel: t(I18nKey.COMMON$PLANNER),\n label: t(I18nKey.COMMON$PLANNER),\n },\n {\n tabValue: \"vscode\",\n isActive: isTabActive(\"vscode\"),\n icon: VSCodeIcon,\n onClick: () => selectTab(\"vscode\"),\n tooltipContent: <VSCodeTooltipContent />,\n tooltipAriaLabel: t(I18nKey.COMMON$CODE),\n label: t(I18nKey.COMMON$CODE),\n },\n {\n tabValue: \"terminal\",\n isActive: isTabActive(\"terminal\"),\n icon: TerminalIcon,\n onClick: () => selectTab(\"terminal\"),\n tooltipContent: t(I18nKey.COMMON$TERMINAL),\n tooltipAriaLabel: t(I18nKey.COMMON$TERMINAL),\n label: t(I18nKey.COMMON$TERMINAL),\n className: \"pl-2\",\n },\n {\n tabValue: \"browser\",\n isActive: isTabActive(\"browser\"),\n icon: GlobeIcon,\n onClick: () => selectTab(\"browser\"),\n tooltipContent: t(I18nKey.COMMON$BROWSER),\n tooltipAriaLabel: t(I18nKey.COMMON$BROWSER),\n label: t(I18nKey.COMMON$BROWSER),\n },\n ];\n\n if (hasTaskList) {\n // Insert after `files` so the leftmost slot stays Files.\n tabs.splice(1, 0, {\n tabValue: \"tasklist\",\n isActive: isTabActive(\"tasklist\"),\n icon: DoubleCheckIcon,\n onClick: () => selectTab(\"tasklist\"),\n tooltipContent: t(I18nKey.COMMON$TASK_LIST),\n tooltipAriaLabel: t(I18nKey.COMMON$TASK_LIST),\n label: t(I18nKey.COMMON$TASK_LIST),\n });\n }\n\n // Pinned tabs always show in the bar. Unpinned tabs stay hidden unless the\n // user has that tab selected — then it appears while active so the bar\n // matches the open panel. Hide VS Code and Planner on local backends —\n // both are cloud-only (the planning agent isn't supported locally).\n const visibleTabs = tabs.filter((tab) => {\n if (tab.tabValue === \"vscode\" && backend.kind !== \"cloud\") return false;\n if (tab.tabValue === \"planner\" && backend.kind !== \"cloud\") return false;\n if (!persistedState.unpinnedTabs.includes(tab.tabValue)) return true;\n return selectedTab === tab.tabValue;\n });\n\n const unpinnedSignature = persistedState.unpinnedTabs.join(\",\");\n\n const isAgentRunning =\n curAgentState === AgentState.RUNNING ||\n curAgentState === AgentState.LOADING;\n const isBuildDisabled = isAgentRunning || !planContent;\n\n const tabsRowInnerRef = useRef<HTMLDivElement>(null);\n const measureRowRef = useRef<HTMLDivElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLButtonElement>(null);\n const [inlineTabCount, setInlineTabCount] = useState(visibleTabs.length);\n\n useLayoutEffect(() => {\n const rowInner = tabsRowInnerRef.current;\n const measureRow = measureRowRef.current;\n const menuEl = menuRef.current;\n if (!rowInner || !measureRow || !menuEl) return undefined;\n\n const measure = () => {\n const measureButtons = measureRow.querySelectorAll<HTMLButtonElement>(\n '[data-tab-measure=\"true\"]',\n );\n const tabCount = measureButtons.length;\n\n const rowWidth = rowInner.getBoundingClientRect().width;\n if (rowWidth === 0) {\n setInlineTabCount(tabCount);\n return;\n }\n\n const widths = Array.from(measureButtons).map(\n (button) => button.getBoundingClientRect().width,\n );\n\n if (widths.length !== tabCount || tabCount === 0) {\n setInlineTabCount(Math.max(0, tabCount));\n return;\n }\n\n const menuWidth = menuEl.getBoundingClientRect().width;\n const gapCss =\n getComputedStyle(rowInner).columnGap || getComputedStyle(rowInner).gap;\n const gapPx = parseFloat(gapCss) || 6;\n\n let nextCount = 0;\n for (let k = tabCount; k >= 0; k -= 1) {\n let total = menuWidth;\n for (let i = 0; i < k; i += 1) {\n total += widths[i] ?? 0;\n }\n if (k > 0) {\n total += k * gapPx;\n }\n if (total <= rowWidth + 0.5) {\n nextCount = k;\n break;\n }\n }\n\n setInlineTabCount((prev) => (prev === nextCount ? prev : nextCount));\n };\n\n measure();\n if (typeof ResizeObserver === \"undefined\") return undefined;\n const ro = new ResizeObserver(measure);\n ro.observe(rowInner);\n return () => ro.disconnect();\n }, [\n unpinnedSignature,\n visibleTabs.length,\n hasTaskList,\n backend.kind,\n selectedTab,\n isRightPanelShown,\n i18n.language,\n ]);\n\n const safeInlineTabCount = Math.min(inlineTabCount, visibleTabs.length);\n\n return (\n <>\n <div\n className={cn(\n \"relative w-full min-w-0\",\n variant === \"compact\"\n ? \"flex h-full min-h-0 items-center py-0 pl-0 pr-1\"\n : \"min-h-10 p-1\",\n )}\n >\n <div\n ref={measureRowRef}\n aria-hidden\n className=\"pointer-events-none absolute top-0 left-[-10000px] flex flex-nowrap items-center gap-1.5\"\n >\n {visibleTabs.map(\n (\n {\n tabValue,\n icon,\n isActive,\n tooltipContent,\n tooltipAriaLabel,\n label,\n className: tabClassName,\n },\n index,\n ) => (\n <ChatActionTooltip\n key={`measure-${tabValue}-${index}`}\n tooltip={tooltipContent}\n ariaLabel={tooltipAriaLabel}\n >\n <ConversationTabNav\n tabValue={tabValue}\n icon={icon}\n onClick={() => {}}\n isActive={isActive}\n label={label}\n className={cn(tabClassName, \"shrink-0\")}\n measureOnly\n />\n </ChatActionTooltip>\n ),\n )}\n </div>\n <div\n ref={tabsRowInnerRef}\n className=\"flex w-full min-w-0 flex-nowrap items-center justify-start\"\n >\n <div className=\"flex w-fit max-w-full min-w-0 flex-nowrap items-center gap-1.5\">\n <div className=\"flex min-w-0 flex-1 flex-nowrap items-center gap-1.5 overflow-x-hidden\">\n {visibleTabs\n .slice(0, safeInlineTabCount)\n .map(\n (\n {\n tabValue,\n icon,\n onClick,\n isActive,\n tooltipContent,\n tooltipAriaLabel,\n label,\n className: tabClassName,\n },\n index,\n ) => (\n <ChatActionTooltip\n key={`${tabValue}-${index}`}\n tooltip={tooltipContent}\n ariaLabel={tooltipAriaLabel}\n >\n <ConversationTabNav\n tabValue={tabValue}\n icon={icon}\n onClick={onClick}\n isActive={isActive}\n label={label}\n className={cn(tabClassName, \"shrink-0\")}\n />\n </ChatActionTooltip>\n ),\n )}\n </div>\n <div ref={menuRef} className=\"relative shrink-0\">\n <EllipsisButton\n ref={anchorRef}\n onClick={() => setIsMenuOpen(!isMenuOpen)}\n ariaLabel={t(I18nKey.COMMON$MORE_OPTIONS)}\n iconClassName={\n variant === \"compact\" ? mobileTopBarIconClassName : undefined\n }\n />\n <ConversationTabsContextMenu\n isOpen={isMenuOpen}\n onClose={() => setIsMenuOpen(false)}\n ignoreOutsideClickRef={anchorRef}\n />\n </div>\n </div>\n </div>\n </div>\n {isTabActive(\"planner\") && (\n <div\n className={cn(\n \"flex h-10 min-h-10 shrink-0 items-center border-t border-[var(--oh-border)] pl-[10px] pr-1\",\n )}\n >\n <button\n type=\"button\"\n onClick={handleBuildPlanClick}\n disabled={isBuildDisabled}\n className={cn(\n \"flex h-5 min-w-17 items-center justify-center rounded bg-white px-2 transition-opacity\",\n isBuildDisabled\n ? \"cursor-not-allowed opacity-50\"\n : \"cursor-pointer hover:opacity-90\",\n )}\n data-testid=\"planner-tab-build-button\"\n >\n <Typography.Text className=\"text-[11px] font-normal leading-5 text-black\">\n {/* eslint-disable-next-line i18next/no-literal-string */}\n {t(I18nKey.COMMON$BUILD)} ⌘↩\n </Typography.Text>\n </button>\n </div>\n )}\n </>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../utils/utils.cjs`),t=require(`../../node_modules/@openhands/extensions/mcps/logos.cjs`);let n=require(`react/jsx-runtime`);var r={xs:`h-4 w-4 rounded [&>svg]:h-2.5 [&>svg]:w-2.5`,sm:`h-5 w-5 rounded-md [&>svg]:h-3 [&>svg]:w-3`,md:`h-10 w-10 rounded-lg [&>svg]:h-5 [&>svg]:w-5`};function i({entry:i,size:a=`md`,className:o,fallback:s,testId:c}){return(0,n.jsx)(`span`,{"aria-hidden":`true`,title:i?.name,"data-testid":c,className:e.cn(`inline-flex shrink-0 items-center justify-center overflow-hidden`,`border border-white/10 shadow-[inset_0_1px_0_rgba(255,255,255,0.18)]`,r[a],o),style:{backgroundColor:i?.iconBg??`var(--oh-color-tertiary)`,color:i?.iconColor??`#FFFFFF`},children:i?t.MCP_LOGOS[i.id]??s??t.MCP_FALLBACK_LOGO:s??t.MCP_FALLBACK_LOGO})}exports.McpLogoBadge=i;
1
+ require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../utils/utils.cjs`),t=require(`../../node_modules/@openhands/extensions/integrations/logos.cjs`);let n=require(`react/jsx-runtime`);var r={xs:`h-4 w-4 rounded [&>svg]:h-2.5 [&>svg]:w-2.5`,sm:`h-5 w-5 rounded-md [&>svg]:h-3 [&>svg]:w-3`,md:`h-10 w-10 rounded-lg [&>svg]:h-5 [&>svg]:w-5`};function i({entry:i,size:a=`md`,className:o,fallback:s,testId:c}){return(0,n.jsx)(`span`,{"aria-hidden":`true`,title:i?.name,"data-testid":c,className:e.cn(`inline-flex shrink-0 items-center justify-center overflow-hidden`,`border border-white/10 shadow-[inset_0_1px_0_rgba(255,255,255,0.18)]`,r[a],o),style:{backgroundColor:i?.iconBg??`var(--oh-color-tertiary)`,color:i?.iconColor??`#FFFFFF`},children:i?t.INTEGRATION_LOGOS[i.id]??s??t.INTEGRATION_FALLBACK_LOGO:s??t.INTEGRATION_FALLBACK_LOGO})}exports.McpLogoBadge=i;
2
2
  //# sourceMappingURL=mcp-logo-badge.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-logo-badge.cjs","names":[],"sources":["../../../src/components/features/mcp-logo-badge.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { McpCatalogEntry } from \"@openhands/extensions/mcps\";\nimport { MCP_FALLBACK_LOGO, MCP_LOGOS } from \"@openhands/extensions/mcps/logos\";\nimport { cn } from \"#/utils/utils\";\n\ntype McpLogoEntry = Pick<\n McpCatalogEntry,\n \"id\" | \"name\" | \"iconBg\" | \"iconColor\"\n>;\n\nexport type { McpLogoEntry };\n\ninterface McpLogoBadgeProps {\n entry?: McpLogoEntry | null;\n size?: \"xs\" | \"sm\" | \"md\";\n className?: string;\n fallback?: ReactNode;\n testId?: string;\n}\n\nconst sizeClassNames = {\n xs: \"h-4 w-4 rounded [&>svg]:h-2.5 [&>svg]:w-2.5\",\n sm: \"h-5 w-5 rounded-md [&>svg]:h-3 [&>svg]:w-3\",\n md: \"h-10 w-10 rounded-lg [&>svg]:h-5 [&>svg]:w-5\",\n};\n\nexport function McpLogoBadge({\n entry,\n size = \"md\",\n className,\n fallback,\n testId,\n}: McpLogoBadgeProps) {\n return (\n <span\n aria-hidden=\"true\"\n title={entry?.name}\n data-testid={testId}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center overflow-hidden\",\n \"border border-white/10 shadow-[inset_0_1px_0_rgba(255,255,255,0.18)]\",\n sizeClassNames[size],\n className,\n )}\n style={{\n backgroundColor: entry?.iconBg ?? \"var(--oh-color-tertiary)\",\n color: entry?.iconColor ?? \"#FFFFFF\",\n }}\n >\n {entry\n ? (MCP_LOGOS[entry.id] ?? fallback ?? MCP_FALLBACK_LOGO)\n : (fallback ?? MCP_FALLBACK_LOGO)}\n </span>\n );\n}\n"],"mappings":"iMAoBA,IAAM,EAAiB,CACrB,GAAI,8CACJ,GAAI,6CACJ,GAAI,+CACL,CAED,SAAgB,EAAa,CAC3B,QACA,OAAO,KACP,YACA,WACA,UACoB,CACpB,OACE,EAAA,EAAA,KAAC,OAAD,CACE,cAAY,OACZ,MAAO,GAAO,KACd,cAAa,EACb,UAAW,EAAA,GACT,mEACA,uEACA,EAAe,GACf,EACD,CACD,MAAO,CACL,gBAAiB,GAAO,QAAU,2BAClC,MAAO,GAAO,WAAa,UAC5B,UAEA,EACI,EAAA,UAAU,EAAM,KAAO,GAAY,EAAA,kBACnC,GAAY,EAAA,kBACZ,CAAA"}
1
+ {"version":3,"file":"mcp-logo-badge.cjs","names":[],"sources":["../../../src/components/features/mcp-logo-badge.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { IntegrationCatalogEntry } from \"@openhands/extensions/integrations\";\nimport {\n INTEGRATION_FALLBACK_LOGO,\n INTEGRATION_LOGOS,\n} from \"@openhands/extensions/integrations/logos\";\nimport { cn } from \"#/utils/utils\";\n\ntype McpLogoEntry = Pick<\n IntegrationCatalogEntry,\n \"id\" | \"name\" | \"iconBg\" | \"iconColor\"\n>;\n\nexport type { McpLogoEntry };\n\ninterface McpLogoBadgeProps {\n entry?: McpLogoEntry | null;\n size?: \"xs\" | \"sm\" | \"md\";\n className?: string;\n fallback?: ReactNode;\n testId?: string;\n}\n\nconst sizeClassNames = {\n xs: \"h-4 w-4 rounded [&>svg]:h-2.5 [&>svg]:w-2.5\",\n sm: \"h-5 w-5 rounded-md [&>svg]:h-3 [&>svg]:w-3\",\n md: \"h-10 w-10 rounded-lg [&>svg]:h-5 [&>svg]:w-5\",\n};\n\nexport function McpLogoBadge({\n entry,\n size = \"md\",\n className,\n fallback,\n testId,\n}: McpLogoBadgeProps) {\n return (\n <span\n aria-hidden=\"true\"\n title={entry?.name}\n data-testid={testId}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center overflow-hidden\",\n \"border border-white/10 shadow-[inset_0_1px_0_rgba(255,255,255,0.18)]\",\n sizeClassNames[size],\n className,\n )}\n style={{\n backgroundColor: entry?.iconBg ?? \"var(--oh-color-tertiary)\",\n color: entry?.iconColor ?? \"#FFFFFF\",\n }}\n >\n {entry\n ? (INTEGRATION_LOGOS[entry.id] ?? fallback ?? INTEGRATION_FALLBACK_LOGO)\n : (fallback ?? INTEGRATION_FALLBACK_LOGO)}\n </span>\n );\n}\n"],"mappings":"yMAuBA,IAAM,EAAiB,CACrB,GAAI,8CACJ,GAAI,6CACJ,GAAI,+CACL,CAED,SAAgB,EAAa,CAC3B,QACA,OAAO,KACP,YACA,WACA,UACoB,CACpB,OACE,EAAA,EAAA,KAAC,OAAD,CACE,cAAY,OACZ,MAAO,GAAO,KACd,cAAa,EACb,UAAW,EAAA,GACT,mEACA,uEACA,EAAe,GACf,EACD,CACD,MAAO,CACL,gBAAiB,GAAO,QAAU,2BAClC,MAAO,GAAO,WAAa,UAC5B,UAEA,EACI,EAAA,kBAAkB,EAAM,KAAO,GAAY,EAAA,0BAC3C,GAAY,EAAA,0BACZ,CAAA"}
@@ -1,6 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
- import type { McpCatalogEntry } from "@openhands/extensions/mcps";
3
- type McpLogoEntry = Pick<McpCatalogEntry, "id" | "name" | "iconBg" | "iconColor">;
2
+ import type { IntegrationCatalogEntry } from "@openhands/extensions/integrations";
3
+ type McpLogoEntry = Pick<IntegrationCatalogEntry, "id" | "name" | "iconBg" | "iconColor">;
4
4
  export type { McpLogoEntry };
5
5
  interface McpLogoBadgeProps {
6
6
  entry?: McpLogoEntry | null;
@@ -1,5 +1,5 @@
1
1
  import { cn as e } from "../../utils/utils.js";
2
- import { MCP_FALLBACK_LOGO as t, MCP_LOGOS as n } from "../../node_modules/@openhands/extensions/mcps/logos.js";
2
+ import { INTEGRATION_FALLBACK_LOGO as t, INTEGRATION_LOGOS as n } from "../../node_modules/@openhands/extensions/integrations/logos.js";
3
3
  import { jsx as r } from "react/jsx-runtime";
4
4
  //#region src/components/features/mcp-logo-badge.tsx
5
5
  var i = {
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-logo-badge.js","names":[],"sources":["../../../src/components/features/mcp-logo-badge.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { McpCatalogEntry } from \"@openhands/extensions/mcps\";\nimport { MCP_FALLBACK_LOGO, MCP_LOGOS } from \"@openhands/extensions/mcps/logos\";\nimport { cn } from \"#/utils/utils\";\n\ntype McpLogoEntry = Pick<\n McpCatalogEntry,\n \"id\" | \"name\" | \"iconBg\" | \"iconColor\"\n>;\n\nexport type { McpLogoEntry };\n\ninterface McpLogoBadgeProps {\n entry?: McpLogoEntry | null;\n size?: \"xs\" | \"sm\" | \"md\";\n className?: string;\n fallback?: ReactNode;\n testId?: string;\n}\n\nconst sizeClassNames = {\n xs: \"h-4 w-4 rounded [&>svg]:h-2.5 [&>svg]:w-2.5\",\n sm: \"h-5 w-5 rounded-md [&>svg]:h-3 [&>svg]:w-3\",\n md: \"h-10 w-10 rounded-lg [&>svg]:h-5 [&>svg]:w-5\",\n};\n\nexport function McpLogoBadge({\n entry,\n size = \"md\",\n className,\n fallback,\n testId,\n}: McpLogoBadgeProps) {\n return (\n <span\n aria-hidden=\"true\"\n title={entry?.name}\n data-testid={testId}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center overflow-hidden\",\n \"border border-white/10 shadow-[inset_0_1px_0_rgba(255,255,255,0.18)]\",\n sizeClassNames[size],\n className,\n )}\n style={{\n backgroundColor: entry?.iconBg ?? \"var(--oh-color-tertiary)\",\n color: entry?.iconColor ?? \"#FFFFFF\",\n }}\n >\n {entry\n ? (MCP_LOGOS[entry.id] ?? fallback ?? MCP_FALLBACK_LOGO)\n : (fallback ?? MCP_FALLBACK_LOGO)}\n </span>\n );\n}\n"],"mappings":";;;;AAoBA,IAAM,IAAiB;CACrB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,SAAgB,EAAa,EAC3B,UACA,UAAO,MACP,cACA,aACA,aACoB;AACpB,QACE,kBAAC,QAAD;EACE,eAAY;EACZ,OAAO,GAAO;EACd,eAAa;EACb,WAAW,EACT,oEACA,wEACA,EAAe,IACf,EACD;EACD,OAAO;GACL,iBAAiB,GAAO,UAAU;GAClC,OAAO,GAAO,aAAa;GAC5B;YAEA,IACI,EAAU,EAAM,OAAO,KAAY,IACnC,KAAY;EACZ,CAAA"}
1
+ {"version":3,"file":"mcp-logo-badge.js","names":[],"sources":["../../../src/components/features/mcp-logo-badge.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { IntegrationCatalogEntry } from \"@openhands/extensions/integrations\";\nimport {\n INTEGRATION_FALLBACK_LOGO,\n INTEGRATION_LOGOS,\n} from \"@openhands/extensions/integrations/logos\";\nimport { cn } from \"#/utils/utils\";\n\ntype McpLogoEntry = Pick<\n IntegrationCatalogEntry,\n \"id\" | \"name\" | \"iconBg\" | \"iconColor\"\n>;\n\nexport type { McpLogoEntry };\n\ninterface McpLogoBadgeProps {\n entry?: McpLogoEntry | null;\n size?: \"xs\" | \"sm\" | \"md\";\n className?: string;\n fallback?: ReactNode;\n testId?: string;\n}\n\nconst sizeClassNames = {\n xs: \"h-4 w-4 rounded [&>svg]:h-2.5 [&>svg]:w-2.5\",\n sm: \"h-5 w-5 rounded-md [&>svg]:h-3 [&>svg]:w-3\",\n md: \"h-10 w-10 rounded-lg [&>svg]:h-5 [&>svg]:w-5\",\n};\n\nexport function McpLogoBadge({\n entry,\n size = \"md\",\n className,\n fallback,\n testId,\n}: McpLogoBadgeProps) {\n return (\n <span\n aria-hidden=\"true\"\n title={entry?.name}\n data-testid={testId}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center overflow-hidden\",\n \"border border-white/10 shadow-[inset_0_1px_0_rgba(255,255,255,0.18)]\",\n sizeClassNames[size],\n className,\n )}\n style={{\n backgroundColor: entry?.iconBg ?? \"var(--oh-color-tertiary)\",\n color: entry?.iconColor ?? \"#FFFFFF\",\n }}\n >\n {entry\n ? (INTEGRATION_LOGOS[entry.id] ?? fallback ?? INTEGRATION_FALLBACK_LOGO)\n : (fallback ?? INTEGRATION_FALLBACK_LOGO)}\n </span>\n );\n}\n"],"mappings":";;;;AAuBA,IAAM,IAAiB;CACrB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,SAAgB,EAAa,EAC3B,UACA,UAAO,MACP,cACA,aACA,aACoB;AACpB,QACE,kBAAC,QAAD;EACE,eAAY;EACZ,OAAO,GAAO;EACd,eAAa;EACb,WAAW,EACT,oEACA,wEACA,EAAe,IACf,EACD;EACD,OAAO;GACL,iBAAiB,GAAO,UAAU;GAClC,OAAO,GAAO,aAAa;GAC5B;YAEA,IACI,EAAkB,EAAM,OAAO,KAAY,IAC3C,KAAY;EACZ,CAAA"}
@@ -1,2 +1,2 @@
1
- const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../utils/custom-toast-handlers.cjs`),i=require(`../../shared/modals/modal-backdrop.cjs`),a=require(`../../shared/modals/modal-close-button.cjs`),o=require(`../../../utils/retrieve-axios-error-message.cjs`),s=require(`../../shared/modals/confirmation-modal.cjs`),c=require(`../../../hooks/mutation/use-delete-mcp-server.cjs`),l=require(`../../../hooks/mutation/use-add-mcp-server.cjs`),u=require(`../settings/mcp-settings/mcp-server-form.cjs`),d=require(`../../../hooks/mutation/use-update-mcp-server.cjs`);let f=require(`react`);f=e.__toESM(f,1);let p=require(`react/jsx-runtime`);function m({server:e,existingServers:m,onClose:h}){let{t:g}=t.useTranslation(`openhands`),{mutate:_,isPending:v}=l.useAddMcpServer(),{mutate:y,isPending:b}=d.useUpdateMcpServer(),{mutate:x,isPending:S}=c.useDeleteMcpServer(),[C,w]=f.default.useState(!1),T=!!e.id,E=v||b||S,D=E||C,O=e=>{r.displayErrorToast(o.retrieveAxiosErrorMessage(e)||g(n.I18nKey.ERROR$GENERIC))};return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(i.ModalBackdrop,{onClose:D?void 0:h,closeOnEscape:!D,"aria-label":g(T?n.I18nKey.MCP$EDIT_CUSTOM_TITLE:n.I18nKey.MCP$ADD_CUSTOM_TITLE),children:(0,p.jsxs)(`div`,{"data-testid":`mcp-custom-editor`,className:`relative bg-base-secondary p-6 rounded-xl border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[90vh] overflow-y-auto custom-scrollbar`,children:[(0,p.jsx)(a.ModalCloseButton,{onClose:h,testId:`mcp-custom-editor-close`,disabled:D}),(0,p.jsx)(`h2`,{className:`mb-4 pr-6 text-lg font-semibold`,children:g(T?n.I18nKey.MCP$EDIT_CUSTOM_TITLE:n.I18nKey.MCP$ADD_CUSTOM_TITLE)}),(0,p.jsx)(u.MCPServerForm,{mode:T?`edit`:`add`,server:T?e:void 0,existingServers:m,onSubmit:t=>{T?y({serverId:e.id,server:t},{onSuccess:h,onError:O}):_(t,{onSuccess:h,onError:O})},onCancel:h,onDelete:T?()=>w(!0):void 0,isActionDisabled:E})]})}),C?(0,p.jsx)(s.ConfirmationModal,{text:g(n.I18nKey.SETTINGS$MCP_CONFIRM_DELETE),onCancel:()=>w(!1),onConfirm:()=>{x(e,{onSuccess:()=>{r.displaySuccessToast(g(n.I18nKey.MCP$REMOVE_SUCCESS)),w(!1),h()},onError:e=>{O(e),w(!1)}})},isConfirming:S}):null]})}exports.CustomServerEditor=m;
1
+ const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../utils/custom-toast-handlers.cjs`),i=require(`../../shared/modals/modal-backdrop.cjs`),a=require(`../../shared/modals/modal-close-button.cjs`),o=require(`../../../utils/retrieve-axios-error-message.cjs`),s=require(`../../shared/modals/confirmation-modal.cjs`),c=require(`../../../hooks/mutation/use-delete-mcp-server.cjs`),l=require(`../../../hooks/mutation/use-add-mcp-server.cjs`),u=require(`../../../hooks/mutation/use-test-mcp-server.cjs`),d=require(`../settings/mcp-settings/mcp-server-form.cjs`),f=require(`../../../hooks/mutation/use-update-mcp-server.cjs`);let p=require(`react`);p=e.__toESM(p,1);let m=require(`react/jsx-runtime`);function h({server:e,existingServers:h,onClose:g}){let{t:_}=t.useTranslation(`openhands`),{mutate:v,isPending:y}=l.useAddMcpServer(),{mutate:b,isPending:x}=f.useUpdateMcpServer(),{mutate:S,isPending:C}=c.useDeleteMcpServer(),{mutate:w,isPending:T,data:E,reset:D}=u.useTestMcpServer(),[O,k]=p.default.useState(!1),A=!!e.id,j=y||x||C,M=j||T||O,N=e=>{switch(e.error_kind){case`timeout`:return _(n.I18nKey.MCP$TEST_ERROR_TIMEOUT);case`connection`:return _(n.I18nKey.MCP$TEST_ERROR_CONNECTION);default:return _(n.I18nKey.MCP$TEST_ERROR_UNKNOWN,{error:e.error})}},P=p.default.useMemo(()=>E?E.ok?{ok:!0,text:_(n.I18nKey.MCP$TEST_SUCCESS,{count:E.tools.length})}:{ok:!1,text:N(E)}:null,[E,_]),F=e=>{r.displayErrorToast(o.retrieveAxiosErrorMessage(e)||_(n.I18nKey.ERROR$GENERIC))};return(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(i.ModalBackdrop,{onClose:M?void 0:g,closeOnEscape:!M,"aria-label":_(A?n.I18nKey.MCP$EDIT_CUSTOM_TITLE:n.I18nKey.MCP$ADD_CUSTOM_TITLE),children:(0,m.jsxs)(`div`,{"data-testid":`mcp-custom-editor`,className:`relative bg-base-secondary p-6 rounded-xl border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[90vh] overflow-y-auto custom-scrollbar`,children:[(0,m.jsx)(a.ModalCloseButton,{onClose:g,testId:`mcp-custom-editor-close`,disabled:M}),(0,m.jsx)(`h2`,{className:`mb-4 pr-6 text-lg font-semibold`,children:_(A?n.I18nKey.MCP$EDIT_CUSTOM_TITLE:n.I18nKey.MCP$ADD_CUSTOM_TITLE)}),(0,m.jsx)(d.MCPServerForm,{mode:A?`edit`:`add`,server:A?e:void 0,existingServers:h,onSubmit:t=>{D(),w(t,{onSuccess:n=>{n.ok&&(A?b({serverId:e.id,server:t},{onSuccess:g,onError:F}):v(t,{onSuccess:g,onError:F}))},onError:F})},onCancel:g,onDelete:A?()=>k(!0):void 0,isActionDisabled:j,onTest:e=>{w(e)},isTestPending:T,testMessage:P})]})}),O?(0,m.jsx)(s.ConfirmationModal,{text:_(n.I18nKey.SETTINGS$MCP_CONFIRM_DELETE),onCancel:()=>k(!1),onConfirm:()=>{S(e,{onSuccess:()=>{r.displaySuccessToast(_(n.I18nKey.MCP$REMOVE_SUCCESS)),k(!1),g()},onError:e=>{F(e),k(!1)}})},isConfirming:C}):null]})}exports.CustomServerEditor=h;
2
2
  //# sourceMappingURL=custom-server-editor.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"custom-server-editor.cjs","names":[],"sources":["../../../../src/components/features/mcp-page/custom-server-editor.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { ModalBackdrop } from \"#/components/shared/modals/modal-backdrop\";\nimport { ModalCloseButton } from \"#/components/shared/modals/modal-close-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { MCPServerForm } from \"#/components/features/settings/mcp-settings/mcp-server-form\";\nimport { useAddMcpServer } from \"#/hooks/mutation/use-add-mcp-server\";\nimport { useUpdateMcpServer } from \"#/hooks/mutation/use-update-mcp-server\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\n\ninterface CustomServerEditorProps {\n server: MCPServerConfig;\n existingServers: MCPServerConfig[];\n onClose: () => void;\n}\n\n/**\n * Modal wrapper around `MCPServerForm` so users can hand-author\n * arbitrary stdio / SSE / SHTTP entries without reaching for raw JSON.\n * An empty `server.id` means \"Add new\".\n */\nexport function CustomServerEditor({\n server,\n existingServers,\n onClose,\n}: CustomServerEditorProps) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: addMcpServer, isPending: isAdding } = useAddMcpServer();\n const { mutate: updateMcpServer, isPending: isUpdating } =\n useUpdateMcpServer();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false);\n\n const isEditing = !!server.id;\n const isPending = isAdding || isUpdating || isDeleting;\n const isDismissBlocked = isPending || showDeleteConfirm;\n\n // Shared error handler so both add and update surface backend errors\n // as a toast instead of failing silently — previously these calls\n // had no `onError` and the modal closed even on a 4xx/5xx, leaving\n // the user to discover the failure on the next page load.\n const handleError = (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n };\n\n const handleSubmit = (payload: MCPServerConfig) => {\n if (isEditing) {\n updateMcpServer(\n { serverId: server.id, server: payload },\n { onSuccess: onClose, onError: handleError },\n );\n } else {\n addMcpServer(payload, { onSuccess: onClose, onError: handleError });\n }\n };\n\n const handleConfirmDelete = () => {\n deleteMcpServer(server, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setShowDeleteConfirm(false);\n onClose();\n },\n onError: (err) => {\n handleError(err);\n setShowDeleteConfirm(false);\n },\n });\n };\n\n return (\n <>\n <ModalBackdrop\n // Block backdrop-click / Escape from dismissing the modal while\n // a mutation is in flight — closing mid-request would orphan\n // the request and leave the user with no error feedback.\n onClose={isDismissBlocked ? undefined : onClose}\n closeOnEscape={!isDismissBlocked}\n aria-label={\n isEditing\n ? t(I18nKey.MCP$EDIT_CUSTOM_TITLE)\n : t(I18nKey.MCP$ADD_CUSTOM_TITLE)\n }\n >\n <div\n data-testid=\"mcp-custom-editor\"\n className=\"relative bg-base-secondary p-6 rounded-xl border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[90vh] overflow-y-auto custom-scrollbar\"\n >\n <ModalCloseButton\n onClose={onClose}\n testId=\"mcp-custom-editor-close\"\n disabled={isDismissBlocked}\n />\n <h2 className=\"mb-4 pr-6 text-lg font-semibold\">\n {isEditing\n ? t(I18nKey.MCP$EDIT_CUSTOM_TITLE)\n : t(I18nKey.MCP$ADD_CUSTOM_TITLE)}\n </h2>\n <MCPServerForm\n mode={isEditing ? \"edit\" : \"add\"}\n server={isEditing ? server : undefined}\n existingServers={existingServers}\n onSubmit={handleSubmit}\n onCancel={onClose}\n onDelete={isEditing ? () => setShowDeleteConfirm(true) : undefined}\n isActionDisabled={isPending}\n />\n </div>\n </ModalBackdrop>\n\n {showDeleteConfirm ? (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setShowDeleteConfirm(false)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"wwBA6BA,SAAgB,EAAmB,CACjC,SACA,kBACA,WAC0B,CAC1B,GAAM,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,CAAE,OAAQ,EAAc,UAAW,GAAa,EAAA,iBAAiB,CACjE,CAAE,OAAQ,EAAiB,UAAW,GAC1C,EAAA,oBAAoB,CAChB,CAAE,OAAQ,EAAiB,UAAW,GAC1C,EAAA,oBAAoB,CAChB,CAAC,EAAmB,GAAwB,EAAA,QAAM,SAAS,GAAM,CAEjE,EAAY,CAAC,CAAC,EAAO,GACrB,EAAY,GAAY,GAAc,EACtC,EAAmB,GAAa,EAMhC,EAAe,GAAiB,CAEpC,EAAA,kBADgB,EAAA,0BAA0B,EACxB,EAAW,EAAE,EAAA,QAAQ,cAAc,CAAC,EA4BxD,OACE,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,EAAA,cAAD,CAIE,QAAS,EAAmB,IAAA,GAAY,EACxC,cAAe,CAAC,EAChB,aAEM,EADJ,EACM,EAAA,QAAQ,sBACR,EAAA,QAAQ,qBAAqB,WAGrC,EAAA,EAAA,MAAC,MAAD,CACE,cAAY,oBACZ,UAAU,2JAFZ,EAIE,EAAA,EAAA,KAAC,EAAA,iBAAD,CACW,UACT,OAAO,0BACP,SAAU,EACV,CAAA,EACF,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,2CAER,EADH,EACK,EAAA,QAAQ,sBACR,EAAA,QAAQ,qBAAqB,CAChC,CAAA,EACL,EAAA,EAAA,KAAC,EAAA,cAAD,CACE,KAAM,EAAY,OAAS,MAC3B,OAAQ,EAAY,EAAS,IAAA,GACZ,kBACjB,SAzDY,GAA6B,CAC7C,EACF,EACE,CAAE,SAAU,EAAO,GAAI,OAAQ,EAAS,CACxC,CAAE,UAAW,EAAS,QAAS,EAAa,CAC7C,CAED,EAAa,EAAS,CAAE,UAAW,EAAS,QAAS,EAAa,CAAC,EAmD7D,SAAU,EACV,SAAU,MAAkB,EAAqB,GAAK,CAAG,IAAA,GACzD,iBAAkB,EAClB,CAAA,CACE,GACQ,CAAA,CAEf,GACC,EAAA,EAAA,KAAC,EAAA,kBAAD,CACE,KAAM,EAAE,EAAA,QAAQ,4BAA4B,CAC5C,aAAgB,EAAqB,GAAM,CAC3C,cA1D0B,CAChC,EAAgB,EAAQ,CACtB,cAAiB,CACf,EAAA,oBAAoB,EAAE,EAAA,QAAQ,mBAAmB,CAAC,CAClD,EAAqB,GAAM,CAC3B,GAAS,EAEX,QAAU,GAAQ,CAChB,EAAY,EAAI,CAChB,EAAqB,GAAM,EAE9B,CAAC,EAgDI,aAAc,EACd,CAAA,CACA,KACH,CAAA,CAAA"}
1
+ {"version":3,"file":"custom-server-editor.cjs","names":[],"sources":["../../../../src/components/features/mcp-page/custom-server-editor.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport type { MCPTestFailure } from \"@openhands/typescript-client\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { ModalBackdrop } from \"#/components/shared/modals/modal-backdrop\";\nimport { ModalCloseButton } from \"#/components/shared/modals/modal-close-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport {\n MCPServerForm,\n type TestMessage,\n} from \"#/components/features/settings/mcp-settings/mcp-server-form\";\nimport { useAddMcpServer } from \"#/hooks/mutation/use-add-mcp-server\";\nimport { useUpdateMcpServer } from \"#/hooks/mutation/use-update-mcp-server\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useTestMcpServer } from \"#/hooks/mutation/use-test-mcp-server\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\n\ninterface CustomServerEditorProps {\n server: MCPServerConfig;\n existingServers: MCPServerConfig[];\n onClose: () => void;\n}\n\n/**\n * Modal wrapper around `MCPServerForm` so users can hand-author\n * arbitrary stdio / SSE / SHTTP entries without reaching for raw JSON.\n * An empty `server.id` means \"Add new\".\n */\nexport function CustomServerEditor({\n server,\n existingServers,\n onClose,\n}: CustomServerEditorProps) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: addMcpServer, isPending: isAdding } = useAddMcpServer();\n const { mutate: updateMcpServer, isPending: isUpdating } =\n useUpdateMcpServer();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const {\n mutate: testServer,\n isPending: isTesting,\n data: testResult,\n reset: resetTest,\n } = useTestMcpServer();\n const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false);\n\n const isEditing = !!server.id;\n const isPending = isAdding || isUpdating || isDeleting;\n const isDismissBlocked = isPending || isTesting || showDeleteConfirm;\n\n const makeTestErrorMessage = (failure: MCPTestFailure): string => {\n switch (failure.error_kind) {\n case \"timeout\":\n return t(I18nKey.MCP$TEST_ERROR_TIMEOUT);\n case \"connection\":\n return t(I18nKey.MCP$TEST_ERROR_CONNECTION);\n default:\n return t(I18nKey.MCP$TEST_ERROR_UNKNOWN, { error: failure.error });\n }\n };\n\n const testMessage: TestMessage | null = React.useMemo(() => {\n if (!testResult) return null;\n if (testResult.ok) {\n return {\n ok: true,\n text: t(I18nKey.MCP$TEST_SUCCESS, { count: testResult.tools.length }),\n };\n }\n return { ok: false, text: makeTestErrorMessage(testResult) };\n }, [testResult, t]);\n\n // Shared error handler so both add and update surface backend errors\n // as a toast instead of failing silently — previously these calls\n // had no `onError` and the modal closed even on a 4xx/5xx, leaving\n // the user to discover the failure on the next page load.\n const handleError = (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n };\n\n const handleSubmit = (payload: MCPServerConfig) => {\n resetTest();\n testServer(payload, {\n onSuccess: (result) => {\n if (!result.ok) {\n // Test failed — modal stays open, error shown via testMessage.\n return;\n }\n if (isEditing) {\n updateMcpServer(\n { serverId: server.id, server: payload },\n { onSuccess: onClose, onError: handleError },\n );\n } else {\n addMcpServer(payload, { onSuccess: onClose, onError: handleError });\n }\n },\n onError: handleError,\n });\n };\n\n const handleTestClick = (payload: MCPServerConfig) => {\n testServer(payload);\n };\n\n const handleConfirmDelete = () => {\n deleteMcpServer(server, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setShowDeleteConfirm(false);\n onClose();\n },\n onError: (err) => {\n handleError(err);\n setShowDeleteConfirm(false);\n },\n });\n };\n\n return (\n <>\n <ModalBackdrop\n // Block backdrop-click / Escape from dismissing the modal while\n // a mutation is in flight — closing mid-request would orphan\n // the request and leave the user with no error feedback.\n onClose={isDismissBlocked ? undefined : onClose}\n closeOnEscape={!isDismissBlocked}\n aria-label={\n isEditing\n ? t(I18nKey.MCP$EDIT_CUSTOM_TITLE)\n : t(I18nKey.MCP$ADD_CUSTOM_TITLE)\n }\n >\n <div\n data-testid=\"mcp-custom-editor\"\n className=\"relative bg-base-secondary p-6 rounded-xl border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[90vh] overflow-y-auto custom-scrollbar\"\n >\n <ModalCloseButton\n onClose={onClose}\n testId=\"mcp-custom-editor-close\"\n disabled={isDismissBlocked}\n />\n <h2 className=\"mb-4 pr-6 text-lg font-semibold\">\n {isEditing\n ? t(I18nKey.MCP$EDIT_CUSTOM_TITLE)\n : t(I18nKey.MCP$ADD_CUSTOM_TITLE)}\n </h2>\n <MCPServerForm\n mode={isEditing ? \"edit\" : \"add\"}\n server={isEditing ? server : undefined}\n existingServers={existingServers}\n onSubmit={handleSubmit}\n onCancel={onClose}\n onDelete={isEditing ? () => setShowDeleteConfirm(true) : undefined}\n isActionDisabled={isPending}\n onTest={handleTestClick}\n isTestPending={isTesting}\n testMessage={testMessage}\n />\n </div>\n </ModalBackdrop>\n\n {showDeleteConfirm ? (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setShowDeleteConfirm(false)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"q0BAkCA,SAAgB,EAAmB,CACjC,SACA,kBACA,WAC0B,CAC1B,GAAM,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,CAAE,OAAQ,EAAc,UAAW,GAAa,EAAA,iBAAiB,CACjE,CAAE,OAAQ,EAAiB,UAAW,GAC1C,EAAA,oBAAoB,CAChB,CAAE,OAAQ,EAAiB,UAAW,GAC1C,EAAA,oBAAoB,CAChB,CACJ,OAAQ,EACR,UAAW,EACX,KAAM,EACN,MAAO,GACL,EAAA,kBAAkB,CAChB,CAAC,EAAmB,GAAwB,EAAA,QAAM,SAAS,GAAM,CAEjE,EAAY,CAAC,CAAC,EAAO,GACrB,EAAY,GAAY,GAAc,EACtC,EAAmB,GAAa,GAAa,EAE7C,EAAwB,GAAoC,CAChE,OAAQ,EAAQ,WAAhB,CACE,IAAK,UACH,OAAO,EAAE,EAAA,QAAQ,uBAAuB,CAC1C,IAAK,aACH,OAAO,EAAE,EAAA,QAAQ,0BAA0B,CAC7C,QACE,OAAO,EAAE,EAAA,QAAQ,uBAAwB,CAAE,MAAO,EAAQ,MAAO,CAAC,GAIlE,EAAkC,EAAA,QAAM,YACvC,EACD,EAAW,GACN,CACL,GAAI,GACJ,KAAM,EAAE,EAAA,QAAQ,iBAAkB,CAAE,MAAO,EAAW,MAAM,OAAQ,CAAC,CACtE,CAEI,CAAE,GAAI,GAAO,KAAM,EAAqB,EAAW,CAAE,CAPpC,KAQvB,CAAC,EAAY,EAAE,CAAC,CAMb,EAAe,GAAiB,CAEpC,EAAA,kBADgB,EAAA,0BAA0B,EACxB,EAAW,EAAE,EAAA,QAAQ,cAAc,CAAC,EA0CxD,OACE,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,EAAA,cAAD,CAIE,QAAS,EAAmB,IAAA,GAAY,EACxC,cAAe,CAAC,EAChB,aAEM,EADJ,EACM,EAAA,QAAQ,sBACR,EAAA,QAAQ,qBAAqB,WAGrC,EAAA,EAAA,MAAC,MAAD,CACE,cAAY,oBACZ,UAAU,2JAFZ,EAIE,EAAA,EAAA,KAAC,EAAA,iBAAD,CACW,UACT,OAAO,0BACP,SAAU,EACV,CAAA,EACF,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,2CAER,EADH,EACK,EAAA,QAAQ,sBACR,EAAA,QAAQ,qBAAqB,CAChC,CAAA,EACL,EAAA,EAAA,KAAC,EAAA,cAAD,CACE,KAAM,EAAY,OAAS,MAC3B,OAAQ,EAAY,EAAS,IAAA,GACZ,kBACjB,SAvEY,GAA6B,CACjD,GAAW,CACX,EAAW,EAAS,CAClB,UAAY,GAAW,CAChB,EAAO,KAIR,EACF,EACE,CAAE,SAAU,EAAO,GAAI,OAAQ,EAAS,CACxC,CAAE,UAAW,EAAS,QAAS,EAAa,CAC7C,CAED,EAAa,EAAS,CAAE,UAAW,EAAS,QAAS,EAAa,CAAC,GAGvE,QAAS,EACV,CAAC,EAsDM,SAAU,EACV,SAAU,MAAkB,EAAqB,GAAK,CAAG,IAAA,GACzD,iBAAkB,EAClB,OAtDe,GAA6B,CACpD,EAAW,EAAQ,EAsDX,cAAe,EACF,cACb,CAAA,CACE,GACQ,CAAA,CAEf,GACC,EAAA,EAAA,KAAC,EAAA,kBAAD,CACE,KAAM,EAAE,EAAA,QAAQ,4BAA4B,CAC5C,aAAgB,EAAqB,GAAM,CAC3C,cA7D0B,CAChC,EAAgB,EAAQ,CACtB,cAAiB,CACf,EAAA,oBAAoB,EAAE,EAAA,QAAQ,mBAAmB,CAAC,CAClD,EAAqB,GAAM,CAC3B,GAAS,EAEX,QAAU,GAAQ,CAChB,EAAY,EAAI,CAChB,EAAqB,GAAM,EAE9B,CAAC,EAmDI,aAAc,EACd,CAAA,CACA,KACH,CAAA,CAAA"}