@openhands/agent-canvas 1.15.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (739) hide show
  1. package/README.md +15 -1
  2. package/README.windows.md +2 -2
  3. package/build/assets/{acp-providers-BKvmTf82.js → acp-providers-CX3Lh9gj.js} +1 -1
  4. package/build/assets/active-backend-context-CrHTlgvN.js +2 -0
  5. package/build/assets/{agent-context-settings-D3PjSTU1.js → agent-context-settings-DSZlXrLj.js} +1 -1
  6. package/build/assets/{agent-profiles-settings-D4cY5U2T.js → agent-profiles-settings-Dzgb7G9z.js} +1 -1
  7. package/build/assets/agent-server-conversation-service.api-tnqNjbpE.js +86 -0
  8. package/build/assets/agent-settings-DLtsqaOs.js +2 -0
  9. package/build/assets/agent-settings-fFvR-XC2.js +1 -0
  10. package/build/assets/alert-banner-HP6mX-Vr.js +1 -0
  11. package/build/assets/{api-error-message-BJyfWp6p.js → api-error-message-B-XdSk3b.js} +1 -1
  12. package/build/assets/api-key-entry-screen-qTzrmJcr.js +1 -0
  13. package/build/assets/{app-settings-CbHqzQus.js → app-settings-dbnneVaV.js} +1 -1
  14. package/build/assets/automation-detail-BmwlCUAB.js +3 -0
  15. package/build/assets/{automation-export-BRopEHMu.js → automation-export-D3a3of4G.js} +1 -1
  16. package/build/assets/{automation-git-sync-CzyS4cn1.js → automation-git-sync-CprN5DcU.js} +1 -1
  17. package/build/assets/automation-setup-route-C40kXjMY.js +1 -0
  18. package/build/assets/{automation-templates-C_0FZgLG.js → automation-templates-BRppNh99.js} +1 -1
  19. package/build/assets/automations-list-DuNcRawl.js +1 -0
  20. package/build/assets/{back-nav-button-Dm9tIjVf.js → back-nav-button-Cjl_hoxq.js} +1 -1
  21. package/build/assets/backend-form-modal-lhGwzXFI.js +1 -0
  22. package/build/assets/{backend-synced-settings-badge-3fOwg6Bd.js → backend-synced-settings-badge-DPkz30BE.js} +1 -1
  23. package/build/assets/{badge-D4SqUCsR.js → badge-BU3S0VtE.js} +1 -1
  24. package/build/assets/{base-modal-C7_BDl_U.js → base-modal-D_L0oEbG.js} +1 -1
  25. package/build/assets/{bot-C-0Wu7vQ.js → bot-dMYHVfYM.js} +1 -1
  26. package/build/assets/{brand-button-Dxv6PDeN.js → brand-button-BAfk4wGP.js} +1 -1
  27. package/build/assets/browser-DSAo0tz1.js +46 -0
  28. package/build/assets/{browser-tab-BAl4ckJE.js → browser-tab-C9vy56R5.js} +1 -1
  29. package/build/assets/canvas-extension-page-dx1gFrfW.js +1 -0
  30. package/build/assets/canvas-extensions-8A-XhpgP.js +1 -0
  31. package/build/assets/canvas-extensions-runtime-2_x5Ezmi.js +1 -0
  32. package/build/assets/{chat-send-button-DWwR2cgI.js → chat-send-button-MUQqCZCS.js} +1 -1
  33. package/build/assets/check-CS0vmpQQ.js +1 -0
  34. package/build/assets/chevron-down-e1QBpjVy.js +1 -0
  35. package/build/assets/chevron-right-ZG4R5G4Q.js +1 -0
  36. package/build/assets/circle-check-DzWLNsbE.js +1 -0
  37. package/build/assets/{circle-plus-check-toggle-CBh_qomE.js → circle-plus-check-toggle-BO_kFZt3.js} +1 -1
  38. package/build/assets/{cloud-funnel-analytics-287iIERo.js → cloud-funnel-analytics-CztBCCPp.js} +1 -1
  39. package/build/assets/{cog-C4rrw-ZK.js → cog-D-MPQW6G.js} +1 -1
  40. package/build/assets/command-menu--UIlGL72.js +1 -0
  41. package/build/assets/{commits-tab-DZtJgaDM.js → commits-tab-AnZwLvh-.js} +1 -1
  42. package/build/assets/{condenser-settings-BcNmYR4s.js → condenser-settings-DmEOje-7.js} +1 -1
  43. package/build/assets/{confirmation-modal-Bk4JRcCM.js → confirmation-modal-Dv1ktp8K.js} +1 -1
  44. package/build/assets/{context-menu-list-item-lVYETtY5.js → context-menu-list-item-I86vKcmM.js} +1 -1
  45. package/build/assets/conversation-BbGrAO4Z.js +93 -0
  46. package/build/assets/conversation-mYT6NAoj.js +1 -0
  47. package/build/assets/conversation-panel-mYT6NAoj.js +1 -0
  48. package/build/assets/conversation-state-store-B0ImPLHO.js +1 -0
  49. package/build/assets/{conversation-tab-empty-state-HJtkmHZj.js → conversation-tab-empty-state-FIbh_lc8.js} +1 -1
  50. package/build/assets/{copy-to-clipboard-button-Cjkswvnj.js → copy-to-clipboard-button-Ca8iSkkA.js} +1 -1
  51. package/build/assets/{device-verify-EZhHhBT7.js → device-verify-Bhn2e_Ye.js} +1 -1
  52. package/build/assets/{dropdown-classes-DJe-E6MC.js → dropdown-classes-Bc1djN0-.js} +1 -1
  53. package/build/assets/{edit-automation-modal-D-urtv8n.js → edit-automation-modal-DadGbJ2u.js} +1 -1
  54. package/build/assets/empty-state-BoGVDecT.js +1 -0
  55. package/build/assets/{entry.client-C7Bi2tkU.js → entry.client-CqyPPjOq.js} +2 -2
  56. package/build/assets/{enum-filter-dropdown-DliX_Lo0.js → enum-filter-dropdown-Bgca129f.js} +1 -1
  57. package/build/assets/{environment-switch-overlay-CEKrFiMw.js → environment-switch-overlay-BmBRT7gv.js} +1 -1
  58. package/build/assets/{error-state-BALXiBNy.js → error-state-Body8Ngd.js} +1 -1
  59. package/build/assets/extensions-hub-CcDqq_vR.js +1 -0
  60. package/build/assets/extensions-navigation-Cr4yzYk4.js +1 -0
  61. package/build/assets/{external-link-DFpYunfj.js → external-link-DKUlnCQV.js} +1 -1
  62. package/build/assets/files-tab-D4o2VyE_.js +1 -0
  63. package/build/assets/{form-control-classes-CGw40z5h.js → form-control-classes-Bkh5FGrD.js} +1 -1
  64. package/build/assets/format-model-name-CasAP3nd.js +1 -0
  65. package/build/assets/get-git-path-ChKDVHZp.js +1 -0
  66. package/build/assets/{git-repo-dropdown-ai8qaNkD.js → git-repo-dropdown-4ROKl2cB.js} +1 -1
  67. package/build/assets/git-repo-dropdown-BkqzkMmM.js +1 -0
  68. package/build/assets/{highlighted-source-view-C3sxykQi.js → highlighted-source-view-BFRxGT_Q.js} +1 -1
  69. package/build/assets/home-ChpSuepX.js +1 -0
  70. package/build/assets/home-DIsB440S.js +1 -0
  71. package/build/assets/home-automation-run-tooltip-BVNDWjAH.js +1 -0
  72. package/build/assets/home-store-CY9Ej0ux.js +1 -0
  73. package/build/assets/index-home-BdlrFIif.js +1 -0
  74. package/build/assets/info-B6RQawoW.js +1 -0
  75. package/build/assets/install-server-modal-Dpy89p4g.js +1 -0
  76. package/build/assets/kebab-menu-item-content-D8hSNGmm.js +1 -0
  77. package/build/assets/{key-Cn5za3rg.js → key-BmVyxs-2.js} +1 -1
  78. package/build/assets/{launch-C1ieiOGe.js → launch-IrTDEFCs.js} +1 -1
  79. package/build/assets/list-filter-DsEK7NFC.js +1 -0
  80. package/build/assets/{list-todo-Cuu-STFc.js → list-todo-apgLVjMw.js} +1 -1
  81. package/build/assets/llm-not-configured-banner-CIFABh3K.js +27 -0
  82. package/build/assets/llm-settings-B9juXhIa.js +1 -0
  83. package/build/assets/llm-settings-De1d5dfr.js +1 -0
  84. package/build/assets/llm-subscription-service-BpJ0ouQo.js +1 -0
  85. package/build/assets/loader-circle-CC1au6hc.js +1 -0
  86. package/build/assets/{loading-spinner-0L3ZTToZ.js → loading-spinner-BY9N3pOe.js} +1 -1
  87. package/build/assets/manage-backends-modal-BrPV3oB-.js +1 -0
  88. package/build/assets/manifest-80fb1c29.js +1 -0
  89. package/build/assets/{manifest-subpage-layout-BGhiUQbA.js → manifest-subpage-layout-CAOYzrYp.js} +1 -1
  90. package/build/assets/{map-provider-B9LTm23I.js → map-provider-Cu3Zgumb.js} +1 -1
  91. package/build/assets/markdown-renderer-BzTlxI8x.js +8 -0
  92. package/build/assets/{mcp-CKbR4Vft.js → mcp-BTs_SXfZ.js} +1 -1
  93. package/build/assets/{mcp-marketplace-utils-C13fFccR.js → mcp-marketplace-utils-AIBzzHTO.js} +1 -1
  94. package/build/assets/{mcp-page-Bm4K2NQq.js → mcp-page-BEBYqH_K.js} +2 -2
  95. package/build/assets/messages-DKV9cRc2.js +41 -0
  96. package/build/assets/{modal-body-CMOc2tLl.js → modal-body-BxZjsju9.js} +1 -1
  97. package/build/assets/{modal-classes-BAb4Y_BG.js → modal-classes-C8eycCwG.js} +1 -1
  98. package/build/assets/{modal-close-button-CkJ0Ktjj.js → modal-close-button-DDzdRvCs.js} +1 -1
  99. package/build/assets/{mouse-pointer-click-CsgRs_-r.js → mouse-pointer-click-Co2uyaPA.js} +1 -1
  100. package/build/assets/onboarding-DV_OXoeP.js +1 -0
  101. package/build/assets/onboarding-modal-rkyBYkeQ.js +1 -0
  102. package/build/assets/{organization-service.api-C8XpQ0pM.js → organization-service.api-DrYNkEN_.js} +1 -1
  103. package/build/assets/{pencil-Clh1Wjvh.js → pencil-47jAZH_V.js} +1 -1
  104. package/build/assets/pin-By41Vl5J.js +1 -0
  105. package/build/assets/{planner-tab-DQvDU3ap.js → planner-tab-C9uZmhme.js} +1 -1
  106. package/build/assets/{plug-BuQhHSSG.js → plug-CG5HFcNG.js} +1 -1
  107. package/build/assets/plugins-management-service-BMJgC3Ga.js +1 -0
  108. package/build/assets/plus-C7Slq-0I.js +1 -0
  109. package/build/assets/profiles-service.api-ChoKrL0l.js +1 -0
  110. package/build/assets/providers-BhMcY5nv.js +1 -0
  111. package/build/assets/proxy-9Fe1v5na.js +1 -0
  112. package/build/assets/{puzzle-A9pGxxai.js → puzzle-JM_QaRm0.js} +1 -1
  113. package/build/assets/recommended-automations-launcher-6ABrI9Cy.js +1 -0
  114. package/build/assets/{refresh-cw-Bh69DyYO.js → refresh-cw-3q3Frrii.js} +1 -1
  115. package/build/assets/root-Dc8YmC9F.js +2 -0
  116. package/build/assets/root-VDaypvK4.css +1 -0
  117. package/build/assets/root-layout-CXkhSPYh.js +2 -0
  118. package/build/assets/schema-field-D-y9-LDb.js +1 -0
  119. package/build/assets/{sdk-section-page-HTffvm7Q.js → sdk-section-page-BlFiizlG.js} +1 -1
  120. package/build/assets/{secret-form-HTUbYw5o.js → secret-form-BB7the8W.js} +1 -1
  121. package/build/assets/secrets-service-ByZVENbp.js +1 -0
  122. package/build/assets/{secrets-settings-BizaTEr1.js → secrets-settings-B_GpxKW2.js} +1 -1
  123. package/build/assets/{settings-BlmrkwRi.js → settings-C0EWuBtA.js} +1 -1
  124. package/build/assets/settings-CKqk8ZnH.js +1 -0
  125. package/build/assets/{settings-dropdown-input-tM0A0ipy.js → settings-dropdown-input-BcwylHs2.js} +1 -1
  126. package/build/assets/{settings-index-CKq0b0Vg.js → settings-index-5w5UW2K3.js} +1 -1
  127. package/build/assets/{settings-input-C03KUoSC.js → settings-input-Db-1g8Ql.js} +1 -1
  128. package/build/assets/{settings-list-classes-BJ0g8rWj.js → settings-list-classes-BzeSZbF2.js} +1 -1
  129. package/build/assets/{settings-modal-AzEF1QPP.js → settings-modal-DfJ3tcJQ.js} +1 -1
  130. package/build/assets/settings-service.api-DJ1r62Zr.js +1 -0
  131. package/build/assets/{settings-switch-CQE0EGC-.js → settings-switch-CS-dJDmA.js} +1 -1
  132. package/build/assets/{settings-utils-ClYOkbbI.js → settings-utils-UYpEdPuD.js} +1 -1
  133. package/build/assets/shared-conversation-CA5ISEDy.js +1 -0
  134. package/build/assets/{shield-check-CFDViW82.js → shield-check-D2aCRd16.js} +1 -1
  135. package/build/assets/{sidebar-layout-D3hE08wK.js → sidebar-layout-D6fS8-Gl.js} +1 -1
  136. package/build/assets/{sidebar-mobile-menu-toggle-BOtyJHwE.js → sidebar-mobile-menu-toggle-C_fb0Jki.js} +1 -1
  137. package/build/assets/sidebar-nav-link-DQQcMf1A.js +1 -0
  138. package/build/assets/{sidebar-onboarding-checklist-storage-3qYflszY.js → sidebar-onboarding-checklist-storage-BBkeI6Bp.js} +1 -1
  139. package/build/assets/sidebar-store-DGqHkVLw.js +1 -0
  140. package/build/assets/{skill-card-pill-row-CFxjoqxn.js → skill-card-pill-row-B27-xyig.js} +1 -1
  141. package/build/assets/skill-enablement-DXeaImBz.js +1 -0
  142. package/build/assets/skill-filter-w__3UCEE.js +2 -0
  143. package/build/assets/{skill-icon-badge-CPQJ6A-I.js → skill-icon-badge-RQkq8wvl.js} +1 -1
  144. package/build/assets/skill-scope-B42H-XOc.js +1 -0
  145. package/build/assets/skills-plugins-tgF8EiXC.js +1 -0
  146. package/build/assets/skills-settings-BgJ9PaOe.js +1 -0
  147. package/build/assets/{styled-tooltip-Dl06rkpY.js → styled-tooltip-C4jf5Fv9.js} +1 -1
  148. package/build/assets/{task-list-tab-04GNQuii.js → task-list-tab-C5zcaktH.js} +1 -1
  149. package/build/assets/{terminal-Cj0iHIW7.js → terminal-CNElN42a.js} +2 -2
  150. package/build/assets/{toggle-switch-Fd_QGz0r.js → toggle-switch-ChOLXv2n.js} +1 -1
  151. package/build/assets/{trash-2-Dl8_RGz0.js → trash-2-D7K26eDO.js} +1 -1
  152. package/build/assets/{trash-_RMt7Ayc.js → trash-D-HYiVYM.js} +1 -1
  153. package/build/assets/{triangle-alert-SM-q4NU_.js → triangle-alert-CtdXWHUI.js} +1 -1
  154. package/build/assets/{typography-SgFy466J.js → typography-v1KN0tzi.js} +1 -1
  155. package/build/assets/usage-tab-CVDffLPt.js +1 -0
  156. package/build/assets/use-acp-credential-form-XIQmpX6M.js +1 -0
  157. package/build/assets/{use-activate-agent-profile-B2NS8nA5.js → use-activate-agent-profile-BLfmvDiG.js} +1 -1
  158. package/build/assets/use-agent-profiles-Bd9Bvvp1.js +1 -0
  159. package/build/assets/{use-automation-health-BxXdzZMP.js → use-automation-health-E6NZi9rb.js} +1 -1
  160. package/build/assets/{use-automations-zYb0dUny.js → use-automations-xijQKIl9.js} +1 -1
  161. package/build/assets/{use-can-manage-org-profiles-BWMahtUh.js → use-can-manage-org-profiles-CrJP5262.js} +1 -1
  162. package/build/assets/use-canvas-extensions-Bi693ujJ.js +1 -0
  163. package/build/assets/{use-cloud-current-user-id-CPHMDG-C.js → use-cloud-current-user-id-CDfAHpPX.js} +1 -1
  164. package/build/assets/use-config-A9QovgXO.js +1 -0
  165. package/build/assets/{use-create-conversation-DwN5vv2f.js → use-create-conversation-Dx3l7mFZ.js} +1 -1
  166. package/build/assets/use-create-secret-B9cUFWRG.js +1 -0
  167. package/build/assets/{use-get-secrets-BT4ihRwj.js → use-get-secrets-K3jmk-LH.js} +1 -1
  168. package/build/assets/use-is-authed-nTBcM7dE.js +1 -0
  169. package/build/assets/use-llm-configured-BV9nZ1_j.js +1 -0
  170. package/build/assets/use-llm-profiles-BO-P4Oyo.js +1 -0
  171. package/build/assets/use-manifest-capabilities-Cw_flwEz.js +1 -0
  172. package/build/assets/use-onboarding-completion-D8U7k4Qb.js +1 -0
  173. package/build/assets/use-pinned-home-route-CckOZrmb.js +1 -0
  174. package/build/assets/use-plugins-marketplace-7i94Zu3Z.js +1 -0
  175. package/build/assets/use-save-agent-profile-BUjSsDXK.js +1 -0
  176. package/build/assets/{use-save-settings-CUZW6yXP.js → use-save-settings-DYqkKv7T.js} +1 -1
  177. package/build/assets/{use-settings-C5VhGpqd.js → use-settings-DSXLbvBl.js} +1 -1
  178. package/build/assets/{use-settings-nav-items-DHaUu1Dg.js → use-settings-nav-items-CwRw-CmX.js} +1 -1
  179. package/build/assets/use-tracking-D53y3TH9.js +3 -0
  180. package/build/assets/{use-user-conversation-DT0_QCnL.js → use-user-conversation-B9Gebw_g.js} +1 -1
  181. package/build/assets/{useInfiniteQuery-CgeUQPfs.js → useInfiniteQuery-C926xzY4.js} +1 -1
  182. package/build/assets/{useMutation-DFnzkf6f.js → useMutation-B-qc391N.js} +1 -1
  183. package/build/assets/{useQueries-BhbrGEf1.js → useQueries-DlbhlH9I.js} +1 -1
  184. package/build/assets/{useQuery-BXWbZBZl.js → useQuery-BSTgq1rl.js} +1 -1
  185. package/build/assets/utils-CN5ZfZy1.js +1 -0
  186. package/build/assets/{vendor~conversation-panel~conversation-CTvDDiXg.js → vendor~conversation-panel~conversation-C8Fn4XOf.js} +1 -1
  187. package/build/assets/{vendor~entry.client-BFE7Llz9.js → vendor~entry.client-CoCfUXUF.js} +1 -1
  188. package/build/assets/{vendor~entry.client-BaKt_PIp.js → vendor~entry.client-DA2izTjq.js} +1 -1
  189. package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~kepq2zme-ZixYGy6E.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~czjee3a3-DqZDXfg2.js} +1 -1
  190. package/build/assets/{vendor~index-home~home~conversation-panel~conversation-BTyukeM-.js → vendor~index-home~home~conversation-panel~conversation-hWywRBaR.js} +1 -1
  191. package/build/assets/{vendor~root-layout-BlUaZ18v.js → vendor~root-layout-C9Ju9DQg.js} +1 -1
  192. package/build/assets/{vendor~root-layout~conversation-panel~conversation-BYAWJwQX.js → vendor~root-layout~conversation-panel~conversation-BMbMgaGu.js} +1 -1
  193. package/build/assets/{vendor~root-layout~conversation-panel~conversation~skills-settings~automations-list~shared-~bovqqk8e-CHaLEBVR.js → vendor~root-layout~conversation-panel~conversation~skills-settings~automations-list~shared-~bovqqk8e-BWir3rJs.js} +1 -1
  194. package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation-j5MFqfSy.js +1 -0
  195. package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation~mcp~automations-list~aut~ibfbmr9f-cDuKr-WD.js +1 -0
  196. package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~iw7io29p-Dz-MAyNb.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~iyia17eu-Chf7vmKB.js} +1 -1
  197. package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~hjcjabwg-Dtu7BpYk.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~nj1hli3r-DP9wmsjo.js} +2 -2
  198. package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~eo2nf80n-DonTKfQD.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~eo2nf80n-CUmIwQCN.js} +117 -13
  199. package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~jz4f6vo2-BgxDvUcf.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~jz4f6vo2-C7HiY4Ae.js} +42 -3
  200. package/build/assets/{verification-settings-Bj6bo097.js → verification-settings-gw_q6vkL.js} +1 -1
  201. package/build/assets/{wrench-hi7Q13dF.js → wrench-CUEI1krB.js} +1 -1
  202. package/build/assets/{x-DkgltWa0.js → x-DJdhbdmt.js} +1 -1
  203. package/build/index.html +4 -4
  204. package/build/locales/ar/openhands.json +32 -16
  205. package/build/locales/ca/openhands.json +32 -16
  206. package/build/locales/de/openhands.json +32 -16
  207. package/build/locales/en/openhands.json +32 -16
  208. package/build/locales/es/openhands.json +32 -16
  209. package/build/locales/fr/openhands.json +32 -16
  210. package/build/locales/it/openhands.json +32 -16
  211. package/build/locales/ja/openhands.json +32 -16
  212. package/build/locales/ko-KR/openhands.json +32 -16
  213. package/build/locales/no/openhands.json +32 -16
  214. package/build/locales/pt/openhands.json +32 -16
  215. package/build/locales/tr/openhands.json +32 -16
  216. package/build/locales/uk/openhands.json +32 -16
  217. package/build/locales/zh-CN/openhands.json +32 -16
  218. package/build/locales/zh-TW/openhands.json +32 -16
  219. package/config/defaults.json +9 -5
  220. package/dist/api/agent-profiles-service/profile-field-support.d.ts +26 -0
  221. package/dist/api/agent-server-adapter.cjs +3 -3
  222. package/dist/api/agent-server-adapter.cjs.map +1 -1
  223. package/dist/api/agent-server-adapter.js +118 -116
  224. package/dist/api/agent-server-adapter.js.map +1 -1
  225. package/dist/api/agent-server-compatibility.cjs +1 -1
  226. package/dist/api/agent-server-compatibility.cjs.map +1 -1
  227. package/dist/api/agent-server-compatibility.d.ts +21 -0
  228. package/dist/api/agent-server-compatibility.js +52 -38
  229. package/dist/api/agent-server-compatibility.js.map +1 -1
  230. package/dist/api/agent-server-config.cjs +1 -1
  231. package/dist/api/agent-server-config.cjs.map +1 -1
  232. package/dist/api/agent-server-config.d.ts +26 -0
  233. package/dist/api/agent-server-config.js +18 -5
  234. package/dist/api/agent-server-config.js.map +1 -1
  235. package/dist/api/canvas-extensions-service.cjs +1 -0
  236. package/dist/api/canvas-extensions-service.d.ts +22 -0
  237. package/dist/api/canvas-extensions-service.js +4 -0
  238. package/dist/api/cloud/conversation-service.api.cjs +1 -1
  239. package/dist/api/cloud/conversation-service.api.cjs.map +1 -1
  240. package/dist/api/cloud/conversation-service.api.d.ts +6 -0
  241. package/dist/api/cloud/conversation-service.api.js +14 -6
  242. package/dist/api/cloud/conversation-service.api.js.map +1 -1
  243. package/dist/api/conversation-file-upload.api.cjs +1 -1
  244. package/dist/api/conversation-file-upload.api.js +10 -10
  245. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  246. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  247. package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +11 -0
  248. package/dist/api/conversation-service/agent-server-conversation-service.api.js +129 -118
  249. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  250. package/dist/api/event-service/event-service.api.cjs +1 -1
  251. package/dist/api/event-service/event-service.api.js +12 -12
  252. package/dist/api/git-service/agent-server-git-service.api.cjs +1 -1
  253. package/dist/api/git-service/agent-server-git-service.api.js +8 -8
  254. package/dist/api/runtime-service/agent-server-runtime-service.cjs +1 -1
  255. package/dist/api/runtime-service/agent-server-runtime-service.js +8 -8
  256. package/dist/api/settings-service/settings-service.api.cjs +1 -1
  257. package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
  258. package/dist/api/settings-service/settings-service.api.d.ts +3 -2
  259. package/dist/api/settings-service/settings-service.api.js +2 -1
  260. package/dist/api/settings-service/settings-service.api.js.map +1 -1
  261. package/dist/components/conversation-events/chat/event-message-components/event-group.cjs +1 -1
  262. package/dist/components/conversation-events/chat/event-message-components/event-group.cjs.map +1 -1
  263. package/dist/components/conversation-events/chat/event-message-components/event-group.js +40 -36
  264. package/dist/components/conversation-events/chat/event-message-components/event-group.js.map +1 -1
  265. package/dist/components/features/automations/automation-card.cjs +1 -1
  266. package/dist/components/features/automations/automation-card.cjs.map +1 -1
  267. package/dist/components/features/automations/automation-card.js +114 -104
  268. package/dist/components/features/automations/automation-card.js.map +1 -1
  269. package/dist/components/features/automations/detail/run-phase.cjs +2 -0
  270. package/dist/components/features/automations/detail/run-phase.cjs.map +1 -0
  271. package/dist/components/features/automations/detail/run-phase.d.ts +89 -0
  272. package/dist/components/features/automations/detail/run-phase.js +72 -0
  273. package/dist/components/features/automations/detail/run-phase.js.map +1 -0
  274. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  275. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  276. package/dist/components/features/backends/backend-form-modal.js +5 -11
  277. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  278. package/dist/components/features/canvas-extensions/add-canvas-extension-modal.d.ts +6 -0
  279. package/dist/components/features/canvas-extensions/canvas-extension-card.d.ts +9 -0
  280. package/dist/components/features/canvas-extensions/canvas-extensions-runtime.cjs +2 -0
  281. package/dist/components/features/canvas-extensions/canvas-extensions-runtime.cjs.map +1 -0
  282. package/dist/components/features/canvas-extensions/canvas-extensions-runtime.d.ts +23 -0
  283. package/dist/components/features/canvas-extensions/canvas-extensions-runtime.js +19 -0
  284. package/dist/components/features/canvas-extensions/canvas-extensions-runtime.js.map +1 -0
  285. package/dist/components/features/chat/chat-interface.cjs +2 -2
  286. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  287. package/dist/components/features/chat/chat-interface.js +171 -168
  288. package/dist/components/features/chat/chat-interface.js.map +1 -1
  289. package/dist/components/features/chat/chat-markdown-path-code.cjs +3 -0
  290. package/dist/components/features/chat/chat-markdown-path-code.cjs.map +1 -0
  291. package/dist/components/features/chat/chat-markdown-path-code.d.ts +27 -0
  292. package/dist/components/features/chat/chat-markdown-path-code.js +72 -0
  293. package/dist/components/features/chat/chat-markdown-path-code.js.map +1 -0
  294. package/dist/components/features/chat/path-component.cjs +1 -1
  295. package/dist/components/features/chat/path-component.cjs.map +1 -1
  296. package/dist/components/features/chat/path-component.d.ts +8 -2
  297. package/dist/components/features/chat/path-component.js +33 -21
  298. package/dist/components/features/chat/path-component.js.map +1 -1
  299. package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.cjs +1 -1
  300. package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.cjs.map +1 -1
  301. package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.js +38 -43
  302. package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.js.map +1 -1
  303. package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.cjs +1 -1
  304. package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.cjs.map +1 -1
  305. package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.d.ts +8 -5
  306. package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.js +22 -16
  307. package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.js.map +1 -1
  308. package/dist/components/features/chat/user-message-body.cjs +1 -1
  309. package/dist/components/features/chat/user-message-body.cjs.map +1 -1
  310. package/dist/components/features/chat/user-message-body.d.ts +4 -0
  311. package/dist/components/features/chat/user-message-body.js +30 -24
  312. package/dist/components/features/chat/user-message-body.js.map +1 -1
  313. package/dist/components/features/conversation/conversation-overview-skills-panel.cjs +1 -1
  314. package/dist/components/features/conversation/conversation-overview-skills-panel.cjs.map +1 -1
  315. package/dist/components/features/conversation/conversation-overview-skills-panel.js +63 -81
  316. package/dist/components/features/conversation/conversation-overview-skills-panel.js.map +1 -1
  317. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs +1 -1
  318. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs.map +1 -1
  319. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js +50 -50
  320. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js.map +1 -1
  321. package/dist/components/features/conversation/conversation-tabs/drawer-vscode-link.cjs +1 -1
  322. package/dist/components/features/conversation/conversation-tabs/drawer-vscode-link.cjs.map +1 -1
  323. package/dist/components/features/conversation/conversation-tabs/drawer-vscode-link.d.ts +1 -1
  324. package/dist/components/features/conversation/conversation-tabs/drawer-vscode-link.js +3 -3
  325. package/dist/components/features/conversation/conversation-tabs/drawer-vscode-link.js.map +1 -1
  326. package/dist/components/features/conversation-panel/skills-modal.cjs +1 -1
  327. package/dist/components/features/conversation-panel/skills-modal.cjs.map +1 -1
  328. package/dist/components/features/conversation-panel/skills-modal.js +29 -28
  329. package/dist/components/features/conversation-panel/skills-modal.js.map +1 -1
  330. package/dist/components/features/files-tab/file-content-viewer.cjs +1 -1
  331. package/dist/components/features/files-tab/file-content-viewer.js +5 -5
  332. package/dist/components/features/home/featured-automations/home-automation-run-tooltip.cjs +1 -1
  333. package/dist/components/features/home/featured-automations/home-automation-run-tooltip.cjs.map +1 -1
  334. package/dist/components/features/home/featured-automations/home-automation-run-tooltip.js +51 -29
  335. package/dist/components/features/home/featured-automations/home-automation-run-tooltip.js.map +1 -1
  336. package/dist/components/features/onboarding/onboarding-host.d.ts +3 -4
  337. package/dist/components/features/onboarding/steps/setup-llm-step.d.ts +5 -9
  338. package/dist/components/features/settings/acp-auth-status-banner.d.ts +23 -6
  339. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.cjs +1 -1
  340. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.js +1 -0
  341. package/dist/components/features/settings/llm-profiles/provider-connection-modal.cjs +1 -1
  342. package/dist/components/features/settings/llm-profiles/provider-connection-modal.js +3 -0
  343. package/dist/components/features/settings/sdk-settings/field-help.cjs +1 -1
  344. package/dist/components/features/settings/sdk-settings/field-help.cjs.map +1 -1
  345. package/dist/components/features/settings/sdk-settings/field-help.d.ts +1 -1
  346. package/dist/components/features/settings/sdk-settings/field-help.js +1 -1
  347. package/dist/components/features/settings/sdk-settings/field-help.js.map +1 -1
  348. package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs +1 -1
  349. package/dist/components/features/settings/sdk-settings/sdk-section-page.js +6 -6
  350. package/dist/components/features/settings/sdk-settings/sdk-section-page.js.map +1 -1
  351. package/dist/components/features/sidebar/sidebar-nav-link.cjs +1 -1
  352. package/dist/components/features/sidebar/sidebar-nav-link.cjs.map +1 -1
  353. package/dist/components/features/sidebar/sidebar-nav-link.d.ts +10 -1
  354. package/dist/components/features/sidebar/sidebar-nav-link.js +54 -36
  355. package/dist/components/features/sidebar/sidebar-nav-link.js.map +1 -1
  356. package/dist/components/features/sidebar/sidebar-rail-body.cjs +1 -1
  357. package/dist/components/features/sidebar/sidebar-rail-body.cjs.map +1 -1
  358. package/dist/components/features/sidebar/sidebar-rail-body.js +143 -120
  359. package/dist/components/features/sidebar/sidebar-rail-body.js.map +1 -1
  360. package/dist/components/features/sidebar/sidebar.cjs +1 -1
  361. package/dist/components/features/sidebar/sidebar.cjs.map +1 -1
  362. package/dist/components/features/sidebar/sidebar.js +1 -1
  363. package/dist/components/features/sidebar/sidebar.js.map +1 -1
  364. package/dist/components/features/skills/build-skill-pills.cjs +1 -1
  365. package/dist/components/features/skills/build-skill-pills.cjs.map +1 -1
  366. package/dist/components/features/skills/build-skill-pills.js +60 -52
  367. package/dist/components/features/skills/build-skill-pills.js.map +1 -1
  368. package/dist/components/features/skills/extensions-navigation.cjs +1 -1
  369. package/dist/components/features/skills/extensions-navigation.cjs.map +1 -1
  370. package/dist/components/features/skills/extensions-navigation.js +54 -43
  371. package/dist/components/features/skills/extensions-navigation.js.map +1 -1
  372. package/dist/components/features/skills/skill-filter.cjs +1 -1
  373. package/dist/components/features/skills/skill-filter.cjs.map +1 -1
  374. package/dist/components/features/skills/skill-filter.d.ts +8 -3
  375. package/dist/components/features/skills/skill-filter.js +69 -52
  376. package/dist/components/features/skills/skill-filter.js.map +1 -1
  377. package/dist/components/shared/modals/settings/settings-form.cjs +1 -1
  378. package/dist/components/shared/modals/settings/settings-form.js +8 -8
  379. package/dist/config/defaults.cjs +1 -1
  380. package/dist/config/defaults.cjs.map +1 -1
  381. package/dist/config/defaults.js +9 -5
  382. package/dist/config/defaults.js.map +1 -1
  383. package/dist/contexts/conversation-websocket-context.cjs +3 -3
  384. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  385. package/dist/contexts/conversation-websocket-context.js +5 -5
  386. package/dist/extensions/canvas-extension-module-loader.d.ts +11 -0
  387. package/dist/hooks/mutation/use-manage-canvas-extensions.d.ts +12 -0
  388. package/dist/hooks/query/concurrency-limiter.cjs +2 -0
  389. package/dist/hooks/query/concurrency-limiter.cjs.map +1 -0
  390. package/dist/hooks/query/concurrency-limiter.d.ts +22 -0
  391. package/dist/hooks/query/concurrency-limiter.js +29 -0
  392. package/dist/hooks/query/concurrency-limiter.js.map +1 -0
  393. package/dist/hooks/query/query-keys.cjs.map +1 -1
  394. package/dist/hooks/query/query-keys.d.ts +4 -0
  395. package/dist/hooks/query/query-keys.js.map +1 -1
  396. package/dist/hooks/query/use-active-conversation.cjs +1 -1
  397. package/dist/hooks/query/use-active-conversation.js +4 -4
  398. package/dist/hooks/query/use-automations.cjs.map +1 -1
  399. package/dist/hooks/query/use-automations.js.map +1 -1
  400. package/dist/hooks/query/use-backends-health.cjs +1 -1
  401. package/dist/hooks/query/use-backends-health.cjs.map +1 -1
  402. package/dist/hooks/query/use-backends-health.d.ts +1 -1
  403. package/dist/hooks/query/use-backends-health.js +50 -64
  404. package/dist/hooks/query/use-backends-health.js.map +1 -1
  405. package/dist/hooks/query/use-canvas-extensions.cjs +1 -0
  406. package/dist/hooks/query/use-canvas-extensions.d.ts +5 -0
  407. package/dist/hooks/query/use-canvas-extensions.js +3 -0
  408. package/dist/hooks/query/use-commit-changes.cjs +1 -1
  409. package/dist/hooks/query/use-commit-changes.js +4 -4
  410. package/dist/hooks/query/use-latest-automation-runs.cjs +1 -1
  411. package/dist/hooks/query/use-latest-automation-runs.js +1 -0
  412. package/dist/hooks/query/use-paginated-conversations.cjs +1 -1
  413. package/dist/hooks/query/use-paginated-conversations.cjs.map +1 -1
  414. package/dist/hooks/query/use-paginated-conversations.js +19 -16
  415. package/dist/hooks/query/use-paginated-conversations.js.map +1 -1
  416. package/dist/hooks/query/use-search-providers.cjs +1 -1
  417. package/dist/hooks/query/use-search-providers.cjs.map +1 -1
  418. package/dist/hooks/query/use-search-providers.js +17 -10
  419. package/dist/hooks/query/use-search-providers.js.map +1 -1
  420. package/dist/hooks/query/use-unified-get-git-changes.cjs +1 -1
  421. package/dist/hooks/query/use-unified-get-git-changes.js +4 -4
  422. package/dist/hooks/query/use-unified-git-commits.cjs +1 -1
  423. package/dist/hooks/query/use-unified-git-commits.js +4 -4
  424. package/dist/hooks/query/use-unified-git-diff.cjs +1 -1
  425. package/dist/hooks/query/use-unified-git-diff.js +4 -4
  426. package/dist/hooks/query/use-unified-vscode-url.cjs +1 -1
  427. package/dist/hooks/query/use-unified-vscode-url.cjs.map +1 -1
  428. package/dist/hooks/query/use-unified-vscode-url.d.ts +1 -0
  429. package/dist/hooks/query/use-unified-vscode-url.js +40 -26
  430. package/dist/hooks/query/use-unified-vscode-url.js.map +1 -1
  431. package/dist/hooks/query/use-workspace-file-content.cjs +1 -1
  432. package/dist/hooks/query/use-workspace-file-content.js +5 -5
  433. package/dist/hooks/query/use-workspace-files.cjs +1 -1
  434. package/dist/hooks/query/use-workspace-files.js +6 -6
  435. package/dist/hooks/use-acp-credential-form.d.ts +6 -0
  436. package/dist/hooks/use-conversation-overview-git-diff-stats.cjs +1 -1
  437. package/dist/hooks/use-conversation-overview-git-diff-stats.js +4 -4
  438. package/dist/hooks/use-pinned-home-route.cjs +2 -0
  439. package/dist/hooks/use-pinned-home-route.cjs.map +1 -0
  440. package/dist/hooks/use-pinned-home-route.d.ts +33 -0
  441. package/dist/hooks/use-pinned-home-route.js +34 -0
  442. package/dist/hooks/use-pinned-home-route.js.map +1 -0
  443. package/dist/hooks/use-skill-enablement.cjs +2 -0
  444. package/dist/hooks/use-skill-enablement.cjs.map +1 -0
  445. package/dist/hooks/use-skill-enablement.d.ts +14 -0
  446. package/dist/hooks/use-skill-enablement.js +80 -0
  447. package/dist/hooks/use-skill-enablement.js.map +1 -0
  448. package/dist/i18n/declaration.cjs +1 -1
  449. package/dist/i18n/declaration.cjs.map +1 -1
  450. package/dist/i18n/declaration.d.ts +29 -13
  451. package/dist/i18n/declaration.js +1 -1
  452. package/dist/i18n/declaration.js.map +1 -1
  453. package/dist/i18n/translation.cjs +3 -3
  454. package/dist/i18n/translation.cjs.map +1 -1
  455. package/dist/i18n/translation.js +538 -266
  456. package/dist/i18n/translation.js.map +1 -1
  457. package/dist/index.cjs +1 -1
  458. package/dist/index.js +15 -14
  459. package/dist/lib/index.cjs +1 -1
  460. package/dist/lib/index.d.ts +1 -0
  461. package/dist/lib/index.js +1 -0
  462. package/dist/locales/ar/openhands.json +32 -16
  463. package/dist/locales/ca/openhands.json +32 -16
  464. package/dist/locales/de/openhands.json +32 -16
  465. package/dist/locales/en/openhands.json +32 -16
  466. package/dist/locales/es/openhands.json +32 -16
  467. package/dist/locales/fr/openhands.json +32 -16
  468. package/dist/locales/it/openhands.json +32 -16
  469. package/dist/locales/ja/openhands.json +32 -16
  470. package/dist/locales/ko-KR/openhands.json +32 -16
  471. package/dist/locales/no/openhands.json +32 -16
  472. package/dist/locales/pt/openhands.json +32 -16
  473. package/dist/locales/tr/openhands.json +32 -16
  474. package/dist/locales/uk/openhands.json +32 -16
  475. package/dist/locales/zh-CN/openhands.json +32 -16
  476. package/dist/locales/zh-TW/openhands.json +32 -16
  477. package/dist/manifests/automation-interface.cjs +1 -1
  478. package/dist/manifests/automation-interface.cjs.map +1 -1
  479. package/dist/manifests/automation-interface.d.ts +6 -0
  480. package/dist/manifests/automation-interface.js +11 -8
  481. package/dist/manifests/automation-interface.js.map +1 -1
  482. package/dist/node_modules/@openhands/extensions/automations/bundle-index.cjs +45 -4
  483. package/dist/node_modules/@openhands/extensions/automations/bundle-index.cjs.map +1 -1
  484. package/dist/node_modules/@openhands/extensions/automations/bundle-index.js +1 -1
  485. package/dist/node_modules/@openhands/extensions/automations/bundle-index.js.map +1 -1
  486. package/dist/node_modules/@openhands/extensions/automations/catalog/github-agents-md-maintainer/manifest.cjs +1 -1
  487. package/dist/node_modules/@openhands/extensions/automations/catalog/github-agents-md-maintainer/manifest.cjs.map +1 -1
  488. package/dist/node_modules/@openhands/extensions/automations/catalog/github-agents-md-maintainer/manifest.js +5 -0
  489. package/dist/node_modules/@openhands/extensions/automations/catalog/github-agents-md-maintainer/manifest.js.map +1 -1
  490. package/dist/node_modules/@openhands/extensions/automations/catalog/github-issue-to-pr/manifest.cjs +1 -1
  491. package/dist/node_modules/@openhands/extensions/automations/catalog/github-issue-to-pr/manifest.cjs.map +1 -1
  492. package/dist/node_modules/@openhands/extensions/automations/catalog/github-issue-to-pr/manifest.js +5 -0
  493. package/dist/node_modules/@openhands/extensions/automations/catalog/github-issue-to-pr/manifest.js.map +1 -1
  494. package/dist/node_modules/@openhands/extensions/automations/catalog/github-pr-reviewer/manifest.cjs +1 -1
  495. package/dist/node_modules/@openhands/extensions/automations/catalog/github-pr-reviewer/manifest.cjs.map +1 -1
  496. package/dist/node_modules/@openhands/extensions/automations/catalog/github-pr-reviewer/manifest.js +5 -0
  497. package/dist/node_modules/@openhands/extensions/automations/catalog/github-pr-reviewer/manifest.js.map +1 -1
  498. package/dist/node_modules/@openhands/extensions/automations/catalog/github-repo-monitor/manifest.cjs +1 -1
  499. package/dist/node_modules/@openhands/extensions/automations/catalog/github-repo-monitor/manifest.cjs.map +1 -1
  500. package/dist/node_modules/@openhands/extensions/automations/catalog/github-repo-monitor/manifest.js +5 -0
  501. package/dist/node_modules/@openhands/extensions/automations/catalog/github-repo-monitor/manifest.js.map +1 -1
  502. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-bitbucket-pr/manifest.cjs +9 -0
  503. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-bitbucket-pr/manifest.cjs.map +1 -0
  504. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-bitbucket-pr/manifest.js +21 -0
  505. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-bitbucket-pr/manifest.js.map +1 -0
  506. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-gitlab-mr/manifest.cjs +9 -0
  507. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-gitlab-mr/manifest.cjs.map +1 -0
  508. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-gitlab-mr/manifest.js +21 -0
  509. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-gitlab-mr/manifest.js.map +1 -0
  510. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-bitbucket-pr/manifest.cjs +9 -0
  511. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-bitbucket-pr/manifest.cjs.map +1 -0
  512. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-bitbucket-pr/manifest.js +21 -0
  513. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-bitbucket-pr/manifest.js.map +1 -0
  514. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-github-pr/manifest.cjs +9 -0
  515. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-github-pr/manifest.cjs.map +1 -0
  516. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-github-pr/manifest.js +21 -0
  517. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-github-pr/manifest.js.map +1 -0
  518. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-gitlab-mr/manifest.cjs +9 -0
  519. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-gitlab-mr/manifest.cjs.map +1 -0
  520. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-gitlab-mr/manifest.js +21 -0
  521. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-issue-to-gitlab-mr/manifest.js.map +1 -0
  522. package/dist/node_modules/@openhands/extensions/automations/catalog/news-digest/manifest.cjs +1 -1
  523. package/dist/node_modules/@openhands/extensions/automations/catalog/news-digest/manifest.cjs.map +1 -1
  524. package/dist/node_modules/@openhands/extensions/automations/catalog/news-digest/manifest.js +5 -0
  525. package/dist/node_modules/@openhands/extensions/automations/catalog/news-digest/manifest.js.map +1 -1
  526. package/dist/node_modules/@openhands/extensions/automations/catalog/qa-changes/manifest.cjs +30 -0
  527. package/dist/node_modules/@openhands/extensions/automations/catalog/qa-changes/manifest.cjs.map +1 -0
  528. package/dist/node_modules/@openhands/extensions/automations/catalog/qa-changes/manifest.js +65 -0
  529. package/dist/node_modules/@openhands/extensions/automations/catalog/qa-changes/manifest.js.map +1 -0
  530. package/dist/node_modules/@openhands/extensions/automations/catalog-index.cjs +1 -1
  531. package/dist/node_modules/@openhands/extensions/automations/catalog-index.cjs.map +1 -1
  532. package/dist/node_modules/@openhands/extensions/automations/catalog-index.js +21 -9
  533. package/dist/node_modules/@openhands/extensions/automations/catalog-index.js.map +1 -1
  534. package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.cjs +1 -1
  535. package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.cjs.map +1 -1
  536. package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.js +2 -2
  537. package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.js.map +1 -1
  538. package/dist/node_modules/@openhands/extensions/integrations/catalog/gitlab.cjs +2 -0
  539. package/dist/node_modules/@openhands/extensions/integrations/catalog/gitlab.cjs.map +1 -0
  540. package/dist/node_modules/@openhands/extensions/integrations/catalog/gitlab.js +40 -0
  541. package/dist/node_modules/@openhands/extensions/integrations/catalog/gitlab.js.map +1 -0
  542. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs +1 -1
  543. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs.map +1 -1
  544. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js +1 -1
  545. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js.map +1 -1
  546. package/dist/node_modules/@openhands/extensions/integrations/catalog-index.cjs +1 -1
  547. package/dist/node_modules/@openhands/extensions/integrations/catalog-index.cjs.map +1 -1
  548. package/dist/node_modules/@openhands/extensions/integrations/catalog-index.js +74 -72
  549. package/dist/node_modules/@openhands/extensions/integrations/catalog-index.js.map +1 -1
  550. package/dist/node_modules/@openhands/extensions/skills/index.cjs +42 -3
  551. package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
  552. package/dist/node_modules/@openhands/extensions/skills/index.js +22 -3
  553. package/dist/node_modules/@openhands/extensions/skills/index.js.map +1 -1
  554. package/dist/node_modules/@openhands/typescript-client/dist/conversation/remote-conversation.cjs +1 -1
  555. package/dist/node_modules/@openhands/typescript-client/dist/conversation/remote-conversation.js +1 -1
  556. package/dist/node_modules/@openhands/typescript-client/dist/conversation/remote-state.cjs +1 -1
  557. package/dist/node_modules/@openhands/typescript-client/dist/conversation/remote-state.cjs.map +1 -1
  558. package/dist/node_modules/@openhands/typescript-client/dist/conversation/remote-state.js +8 -7
  559. package/dist/node_modules/@openhands/typescript-client/dist/conversation/remote-state.js.map +1 -1
  560. package/dist/node_modules/@openhands/typescript-client/dist/index.cjs +1 -1
  561. package/dist/node_modules/@openhands/typescript-client/dist/index.js +2 -2
  562. package/dist/node_modules/lucide-react/dist/esm/icons/blocks.cjs +2 -0
  563. package/dist/node_modules/lucide-react/dist/esm/icons/blocks.cjs.map +1 -0
  564. package/dist/node_modules/lucide-react/dist/esm/icons/blocks.js +16 -0
  565. package/dist/node_modules/lucide-react/dist/esm/icons/blocks.js.map +1 -0
  566. package/dist/node_modules/lucide-react/dist/esm/icons/panels-top-left.cjs +2 -0
  567. package/dist/node_modules/lucide-react/dist/esm/icons/panels-top-left.cjs.map +1 -0
  568. package/dist/node_modules/lucide-react/dist/esm/icons/panels-top-left.js +23 -0
  569. package/dist/node_modules/lucide-react/dist/esm/icons/panels-top-left.js.map +1 -0
  570. package/dist/package.cjs +1 -1
  571. package/dist/package.cjs.map +1 -1
  572. package/dist/package.js +3 -3
  573. package/dist/package.js.map +1 -1
  574. package/dist/routes/agent-settings.d.ts +10 -0
  575. package/dist/routes/app-settings.cjs +1 -1
  576. package/dist/routes/app-settings.cjs.map +1 -1
  577. package/dist/routes/app-settings.js +7 -7
  578. package/dist/routes/files-tab.cjs +1 -1
  579. package/dist/routes/files-tab.cjs.map +1 -1
  580. package/dist/routes/files-tab.js +14 -14
  581. package/dist/routes/files-tab.js.map +1 -1
  582. package/dist/routes/llm-settings.cjs +1 -1
  583. package/dist/routes/llm-settings.cjs.map +1 -1
  584. package/dist/routes/llm-settings.js +122 -114
  585. package/dist/routes/llm-settings.js.map +1 -1
  586. package/dist/services/canvas-ui.cjs +1 -1
  587. package/dist/services/canvas-ui.cjs.map +1 -1
  588. package/dist/services/canvas-ui.d.ts +5 -0
  589. package/dist/services/canvas-ui.js +24 -10
  590. package/dist/services/canvas-ui.js.map +1 -1
  591. package/dist/services/settings.cjs +1 -1
  592. package/dist/services/settings.cjs.map +1 -1
  593. package/dist/services/settings.js +3 -2
  594. package/dist/services/settings.js.map +1 -1
  595. package/dist/types/automation.cjs.map +1 -1
  596. package/dist/types/automation.d.ts +20 -0
  597. package/dist/types/automation.js.map +1 -1
  598. package/dist/types/canvas-extension.cjs +2 -0
  599. package/dist/types/canvas-extension.cjs.map +1 -0
  600. package/dist/types/canvas-extension.d.ts +77 -0
  601. package/dist/types/canvas-extension.js +6 -0
  602. package/dist/types/canvas-extension.js.map +1 -0
  603. package/dist/types/settings.d.ts +7 -0
  604. package/dist/ui/help-link.cjs +1 -1
  605. package/dist/ui/help-link.cjs.map +1 -1
  606. package/dist/ui/help-link.d.ts +6 -1
  607. package/dist/ui/help-link.js +32 -18
  608. package/dist/ui/help-link.js.map +1 -1
  609. package/dist/utils/acp-auth-display.d.ts +35 -0
  610. package/dist/utils/cache-utils.cjs +1 -1
  611. package/dist/utils/cache-utils.js +5 -5
  612. package/dist/utils/format-model-name.cjs +1 -1
  613. package/dist/utils/format-model-name.cjs.map +1 -1
  614. package/dist/utils/format-model-name.d.ts +7 -3
  615. package/dist/utils/format-model-name.js +6 -11
  616. package/dist/utils/format-model-name.js.map +1 -1
  617. package/dist/utils/format-relative-time.cjs +1 -1
  618. package/dist/utils/format-relative-time.cjs.map +1 -1
  619. package/dist/utils/format-relative-time.d.ts +7 -0
  620. package/dist/utils/format-relative-time.js +7 -2
  621. package/dist/utils/format-relative-time.js.map +1 -1
  622. package/dist/utils/path-utils.cjs +1 -1
  623. package/dist/utils/path-utils.cjs.map +1 -1
  624. package/dist/utils/path-utils.d.ts +15 -3
  625. package/dist/utils/path-utils.js +29 -3
  626. package/dist/utils/path-utils.js.map +1 -1
  627. package/dist/utils/skill-enablement.cjs +2 -0
  628. package/dist/utils/skill-enablement.cjs.map +1 -0
  629. package/dist/utils/skill-enablement.d.ts +51 -0
  630. package/dist/utils/skill-enablement.js +31 -0
  631. package/dist/utils/skill-enablement.js.map +1 -0
  632. package/dist/utils/vscode-origin.cjs +2 -0
  633. package/dist/utils/vscode-origin.cjs.map +1 -0
  634. package/dist/utils/vscode-origin.d.ts +55 -0
  635. package/dist/utils/vscode-origin.js +27 -0
  636. package/dist/utils/vscode-origin.js.map +1 -0
  637. package/dist/utils/workspace-mode.d.ts +4 -0
  638. package/package.json +3 -3
  639. package/scripts/check-sdk-version-sync.mjs +6 -6
  640. package/scripts/check-translation-completeness.cjs +1 -0
  641. package/scripts/dev-extra-backend.mjs +28 -9
  642. package/scripts/dev-safe.mjs +81 -8
  643. package/scripts/dev-static.mjs +35 -37
  644. package/scripts/dev-with-automation.mjs +82 -1
  645. package/scripts/ingress.mjs +27 -1
  646. package/scripts/static-server.mjs +74 -1
  647. package/tools/canvas_ui_tool.py +19 -0
  648. package/build/assets/active-backend-context-DKFSMbn3.js +0 -2
  649. package/build/assets/agent-server-conversation-service.api-DozDKIW_.js +0 -86
  650. package/build/assets/agent-settings-351vXWc9.js +0 -2
  651. package/build/assets/agent-settings-Ce7BDZ6I.js +0 -1
  652. package/build/assets/alert-banner-Kyy1YWZU.js +0 -1
  653. package/build/assets/api-key-entry-screen-INIxqAMs.js +0 -1
  654. package/build/assets/automation-detail-DXDhUwPq.js +0 -3
  655. package/build/assets/automation-setup-route-FRr05f_g.js +0 -1
  656. package/build/assets/automations-list-CERuQWE6.js +0 -1
  657. package/build/assets/backend-form-modal-DK78-jn1.js +0 -1
  658. package/build/assets/browser-11etCQ04.js +0 -7
  659. package/build/assets/check-Cf2YoT90.js +0 -1
  660. package/build/assets/chevron-down-C3OQ-ehx.js +0 -1
  661. package/build/assets/chevron-right-CN1uUiJ1.js +0 -1
  662. package/build/assets/circle-check-g5yeGMd-.js +0 -1
  663. package/build/assets/command-menu-BZQ8S3Ke.js +0 -1
  664. package/build/assets/conversation-CchMzpGl.js +0 -1
  665. package/build/assets/conversation-Dpzftz57.js +0 -93
  666. package/build/assets/conversation-panel-CchMzpGl.js +0 -1
  667. package/build/assets/conversation-state-store-a9d2fxRc.js +0 -1
  668. package/build/assets/empty-state-CvaVahVr.js +0 -1
  669. package/build/assets/extensions-hub-CFduxBnk.js +0 -1
  670. package/build/assets/extensions-navigation-BeC224yX.js +0 -1
  671. package/build/assets/files-tab-CL3J9b3p.js +0 -1
  672. package/build/assets/format-model-name-BNPKVsIq.js +0 -1
  673. package/build/assets/get-git-path-DlAJa_i6.js +0 -1
  674. package/build/assets/git-repo-dropdown-DGMEhz7d.js +0 -1
  675. package/build/assets/home-BCGlNJCA.js +0 -1
  676. package/build/assets/home-DB1pRqTC.js +0 -1
  677. package/build/assets/home-automation-run-tooltip-CooFQRIG.js +0 -1
  678. package/build/assets/home-store-Dl1dPE58.js +0 -1
  679. package/build/assets/index-home-DB1pRqTC.js +0 -1
  680. package/build/assets/info-uYSVzX86.js +0 -1
  681. package/build/assets/install-server-modal-BbJdhzet.js +0 -1
  682. package/build/assets/kebab-menu-item-content-BYokkRHi.js +0 -1
  683. package/build/assets/list-filter-OFkpRrmi.js +0 -1
  684. package/build/assets/llm-not-configured-banner-BqqYnJ1t.js +0 -27
  685. package/build/assets/llm-settings-CnDbbmVW.js +0 -1
  686. package/build/assets/llm-settings-S8Yjg__1.js +0 -1
  687. package/build/assets/llm-subscription-service-BpPfzW4x.js +0 -1
  688. package/build/assets/loader-circle-nvrwthvj.js +0 -1
  689. package/build/assets/manage-backends-modal-BCUPswyl.js +0 -1
  690. package/build/assets/manifest-58597dde.js +0 -1
  691. package/build/assets/markdown-renderer-Cb2sBWtV.js +0 -8
  692. package/build/assets/messages-BTN5thLe.js +0 -40
  693. package/build/assets/onboarding-Cx_kaiD1.js +0 -1
  694. package/build/assets/onboarding-modal-vMwn7ihv.js +0 -1
  695. package/build/assets/plugins-management-service-BjYeF0b0.js +0 -1
  696. package/build/assets/plus-CEKne-Yp.js +0 -1
  697. package/build/assets/profiles-service.api-QB-T_u-g.js +0 -1
  698. package/build/assets/providers-FfSZ5TXP.js +0 -1
  699. package/build/assets/proxy-tcFL2yTQ.js +0 -1
  700. package/build/assets/recommended-automations-launcher-Bw8uC4V6.js +0 -1
  701. package/build/assets/root-BLeQfBEq.css +0 -1
  702. package/build/assets/root-ZKKYPR1Z.js +0 -2
  703. package/build/assets/root-layout-luJoE9IG.js +0 -2
  704. package/build/assets/schema-field-Csw5fhtN.js +0 -1
  705. package/build/assets/secrets-service-BTor9uAU.js +0 -1
  706. package/build/assets/settings-DcNPxz0v.js +0 -1
  707. package/build/assets/settings-service.api-B2agVfjL.js +0 -1
  708. package/build/assets/shared-conversation-B55pCyBG.js +0 -1
  709. package/build/assets/sidebar-nav-link-CPzhyHQg.js +0 -1
  710. package/build/assets/sidebar-store-DtpU7zaI.js +0 -1
  711. package/build/assets/skill-filter-CWZ5kjcg.js +0 -2
  712. package/build/assets/skill-scope-CV1dkAbW.js +0 -1
  713. package/build/assets/skills-plugins-DGHULTq6.js +0 -1
  714. package/build/assets/skills-settings-CM1lFv3e.js +0 -1
  715. package/build/assets/usage-tab-BcfWV6db.js +0 -1
  716. package/build/assets/use-acp-credential-form-BsSW5NHG.js +0 -1
  717. package/build/assets/use-agent-profiles-DWBPC0Si.js +0 -1
  718. package/build/assets/use-config-Bft35DOK.js +0 -1
  719. package/build/assets/use-create-secret-BSxJMxHp.js +0 -1
  720. package/build/assets/use-is-authed-CFGkY3-Z.js +0 -1
  721. package/build/assets/use-llm-configured-BI6obxsc.js +0 -1
  722. package/build/assets/use-llm-profiles-djGAhTWL.js +0 -1
  723. package/build/assets/use-manifest-capabilities-3z0-1G59.js +0 -1
  724. package/build/assets/use-onboarding-completion-BXpyUSsJ.js +0 -1
  725. package/build/assets/use-plugins-marketplace-DI4_pK56.js +0 -1
  726. package/build/assets/use-save-agent-profile-DdBSTdpN.js +0 -1
  727. package/build/assets/use-tracking-D5t9otIF.js +0 -3
  728. package/build/assets/utils-DaCIEEQP.js +0 -1
  729. package/build/assets/vendor~index-home~home~conversation-panel~conversation~alert-banner-B3qC_oj8.js +0 -1
  730. package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation~mcp~automations-list~aut~ibfbmr9f-B2OLKL7N.js +0 -1
  731. package/dist/components/features/tips/random-tip.d.ts +0 -2
  732. package/dist/utils/tips.d.ts +0 -7
  733. package/dist/utils/workspace-relative-path.cjs +0 -2
  734. package/dist/utils/workspace-relative-path.cjs.map +0 -1
  735. package/dist/utils/workspace-relative-path.d.ts +0 -10
  736. package/dist/utils/workspace-relative-path.js +0 -22
  737. package/dist/utils/workspace-relative-path.js.map +0 -1
  738. /package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~ew3u153i-rfV8mQ9m.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~ew9ih1s8-rfV8mQ9m.js} +0 -0
  739. /package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~ox0jfsa0-cHFhpUBq.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~i58xkef6-cHFhpUBq.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"home-automation-run-tooltip.js","names":[],"sources":["../../../../../src/components/features/home/featured-automations/home-automation-run-tooltip.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Zap } from \"lucide-react\";\nimport { useTranslation } from \"react-i18next\";\nimport type { LatestAutomationRunState } from \"#/hooks/query/use-latest-automation-runs\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport ClockIcon from \"#/icons/clock.svg?react\";\nimport { AutomationRunStatus, type Automation } from \"#/types/automation\";\nimport { formatRelativeTime } from \"#/utils/format-relative-time\";\nimport { AutomationHealthIndicator } from \"./automation-health-indicator\";\nimport {\n deriveRunHealth,\n getLastRunTimestamp,\n getRunHealthLabelKey,\n getTriggerSummary,\n} from \"./automation-run-health\";\n\nexport function getRunStatusLabelKey(\n runState: LatestAutomationRunState,\n): I18nKey {\n if (runState.isError) return I18nKey.FEATURED_AUTOMATIONS$STATUS_UNAVAILABLE;\n return getRunHealthLabelKey(deriveRunHealth(runState));\n}\n\nfunction PreviewRow({\n label,\n children,\n}: {\n label: string;\n children: ReactNode;\n}) {\n return (\n <div className=\"flex items-start gap-2 text-xs\">\n <span className=\"w-20 shrink-0 text-[var(--oh-muted)]\">{label}</span>\n <span className=\"min-w-0 flex-1 break-words text-[var(--oh-foreground)]\">\n {children}\n </span>\n </div>\n );\n}\n\n/**\n * Left-nav-style hovercard body for an automation's latest-run health.\n * Matches `ConversationCardPreview` layout: title + label/value rows.\n */\nexport function HomeAutomationRunTooltip({\n automation,\n runState,\n}: {\n automation: Automation;\n runState: LatestAutomationRunState;\n}) {\n const { t, i18n } = useTranslation(\"openhands\");\n const { latestRun } = runState;\n const timestamp = latestRun ? getLastRunTimestamp(latestRun) : null;\n const TriggerIcon = automation.trigger.type === \"event\" ? Zap : ClockIcon;\n const health = deriveRunHealth(runState);\n\n return (\n <div className=\"flex w-[280px] flex-col gap-3 p-3\">\n <span className=\"break-words text-sm font-medium text-white\">\n {automation.name}\n </span>\n\n <dl className=\"flex flex-col gap-1.5\">\n <PreviewRow label={t(I18nKey.AUTOMATIONS$DETAIL$TRIGGER)}>\n <span className=\"inline-flex min-w-0 items-start gap-1.5\">\n <TriggerIcon\n className=\"mt-0.5 size-3 shrink-0\"\n aria-hidden=\"true\"\n />\n <span className=\"break-all\">{getTriggerSummary(automation)}</span>\n </span>\n </PreviewRow>\n\n <PreviewRow label={t(I18nKey.COMMON$STATUS)}>\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n <AutomationHealthIndicator health={health} />\n <span>{t(getRunStatusLabelKey(runState))}</span>\n </span>\n </PreviewRow>\n\n {timestamp ? (\n <PreviewRow label={t(I18nKey.AUTOMATIONS$DETAIL$LAST_RUN)}>\n {formatRelativeTime(timestamp, i18n.language, t)}\n </PreviewRow>\n ) : null}\n\n {latestRun?.status === AutomationRunStatus.FAILED &&\n latestRun.error_detail ? (\n <PreviewRow label={t(I18nKey.STATUS$ERROR)}>\n <span className=\"line-clamp-3 text-[var(--oh-status-error)]\">\n {latestRun.error_detail}\n </span>\n </PreviewRow>\n ) : null}\n </dl>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAgBA,SAAgB,EACd,GACS;CAET,OADI,EAAS,UAAgB,EAAQ,0CAC9B,EAAqB,EAAgB,CAAQ,CAAC;AACvD;AAEA,SAAS,EAAW,EAClB,UACA,eAIC;CACD,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,QAAD;GAAM,WAAU;aAAwC;EAAY,CAAA,GACpE,kBAAC,QAAD;GAAM,WAAU;GACb;EACG,CAAA,CACH;;AAET;AAMA,SAAgB,EAAyB,EACvC,eACA,eAIC;CACD,IAAM,EAAE,MAAG,YAAS,EAAe,WAAW,GACxC,EAAE,iBAAc,GAChB,IAAY,IAAY,EAAoB,CAAS,IAAI,MACzD,IAAc,EAAW,QAAQ,SAAS,UAAU,IAAM,GAC1D,IAAS,EAAgB,CAAQ;CAEvC,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,QAAD;GAAM,WAAU;aACb,EAAW;EACR,CAAA,GAEN,kBAAC,MAAD;GAAI,WAAU;aAAd;IACE,kBAAC,GAAD;KAAY,OAAO,EAAE,EAAQ,0BAA0B;eACrD,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD;OACE,WAAU;OACV,eAAY;MACb,CAAA,GACD,kBAAC,QAAD;OAAM,WAAU;iBAAa,EAAkB,CAAU;MAAQ,CAAA,CAC7D;;IACI,CAAA;IAEZ,kBAAC,GAAD;KAAY,OAAO,EAAE,EAAQ,aAAa;eACxC,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAmC,UAAS,CAAA,GAC5C,kBAAC,QAAD,EAAA,UAAO,EAAE,EAAqB,CAAQ,CAAC,EAAQ,CAAA,CAC3C;;IACI,CAAA;IAEX,IACC,kBAAC,GAAD;KAAY,OAAO,EAAE,EAAQ,2BAA2B;eACrD,EAAmB,GAAW,EAAK,UAAU,CAAC;IACrC,CAAA,IACV;IAEH,GAAW,WAAW,EAAoB,UAC3C,EAAU,eACR,kBAAC,GAAD;KAAY,OAAO,EAAE,EAAQ,YAAY;eACvC,kBAAC,QAAD;MAAM,WAAU;gBACb,EAAU;KACP,CAAA;IACI,CAAA,IACV;GACF;IACD;;AAET"}
1
+ {"version":3,"file":"home-automation-run-tooltip.js","names":[],"sources":["../../../../../src/components/features/home/featured-automations/home-automation-run-tooltip.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Zap } from \"lucide-react\";\nimport { useTranslation } from \"react-i18next\";\nimport type { LatestAutomationRunState } from \"#/hooks/query/use-latest-automation-runs\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport ClockIcon from \"#/icons/clock.svg?react\";\nimport {\n shouldShowRunPhase,\n useRunPhase,\n} from \"#/components/features/automations/detail/run-phase\";\nimport {\n AutomationRunStatus,\n type Automation,\n type AutomationRun,\n} from \"#/types/automation\";\nimport { formatRelativeTime } from \"#/utils/format-relative-time\";\nimport { AutomationHealthIndicator } from \"./automation-health-indicator\";\nimport {\n deriveRunHealth,\n getLastRunTimestamp,\n getRunHealthLabelKey,\n getTriggerSummary,\n} from \"./automation-run-health\";\n\nexport function getRunStatusLabelKey(\n runState: LatestAutomationRunState,\n): I18nKey {\n if (runState.isError) return I18nKey.FEATURED_AUTOMATIONS$STATUS_UNAVAILABLE;\n return getRunHealthLabelKey(deriveRunHealth(runState));\n}\n\nfunction PreviewRow({\n label,\n children,\n}: {\n label: string;\n children: ReactNode;\n}) {\n return (\n <div className=\"flex items-start gap-2 text-xs\">\n <span className=\"w-20 shrink-0 text-[var(--oh-muted)]\">{label}</span>\n <span className=\"min-w-0 flex-1 break-words text-[var(--oh-foreground)]\">\n {children}\n </span>\n </div>\n );\n}\n\n/**\n * The run's phase and how long it has held it. The row that opens this\n * hovercard has to clip a long phase; here there is room to wrap, so this is\n * where the whole thing is readable — and the age is what says whether the\n * run is moving through phases or sitting in one. Only the layout differs\n * from the row's: what the phase says, and whether its age is meaningful,\n * comes from the same hook the row uses.\n */\nfunction PhaseRow({ run }: { run: AutomationRun | null }) {\n const { t } = useTranslation(\"openhands\");\n const phase = useRunPhase({\n status: run?.status,\n code: run?.phase_code,\n label: run?.phase_label,\n updatedAt: run?.phase_updated_at,\n });\n\n if (!run || !shouldShowRunPhase(run.status) || !phase) return null;\n\n const { text, age } = phase;\n\n return (\n <PreviewRow label={t(I18nKey.AUTOMATIONS$DETAIL$PHASE)}>\n <span data-testid=\"run-phase-row\">\n {text}\n {age ? <span className=\"text-muted\"> · {age}</span> : null}\n </span>\n </PreviewRow>\n );\n}\n\n/**\n * Left-nav-style hovercard body for an automation's latest-run health.\n * Matches `ConversationCardPreview` layout: title + label/value rows.\n */\nexport function HomeAutomationRunTooltip({\n automation,\n runState,\n}: {\n automation: Automation;\n runState: LatestAutomationRunState;\n}) {\n const { t, i18n } = useTranslation(\"openhands\");\n const { latestRun } = runState;\n const timestamp = latestRun ? getLastRunTimestamp(latestRun) : null;\n const TriggerIcon = automation.trigger.type === \"event\" ? Zap : ClockIcon;\n const health = deriveRunHealth(runState);\n\n return (\n <div className=\"flex w-[280px] flex-col gap-3 p-3\">\n <span className=\"break-words text-sm font-medium text-white\">\n {automation.name}\n </span>\n\n <dl className=\"flex flex-col gap-1.5\">\n <PreviewRow label={t(I18nKey.AUTOMATIONS$DETAIL$TRIGGER)}>\n <span className=\"inline-flex min-w-0 items-start gap-1.5\">\n <TriggerIcon\n className=\"mt-0.5 size-3 shrink-0\"\n aria-hidden=\"true\"\n />\n <span className=\"break-all\">{getTriggerSummary(automation)}</span>\n </span>\n </PreviewRow>\n\n <PreviewRow label={t(I18nKey.COMMON$STATUS)}>\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n <AutomationHealthIndicator health={health} />\n <span>{t(getRunStatusLabelKey(runState))}</span>\n </span>\n </PreviewRow>\n\n <PhaseRow run={latestRun} />\n\n {timestamp ? (\n <PreviewRow label={t(I18nKey.AUTOMATIONS$DETAIL$LAST_RUN)}>\n {formatRelativeTime(timestamp, i18n.language, t)}\n </PreviewRow>\n ) : null}\n\n {latestRun?.status === AutomationRunStatus.FAILED &&\n latestRun.error_detail ? (\n <PreviewRow label={t(I18nKey.STATUS$ERROR)}>\n <span className=\"line-clamp-3 text-[var(--oh-status-error)]\">\n {latestRun.error_detail}\n </span>\n </PreviewRow>\n ) : null}\n </dl>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AAwBA,SAAgB,EACd,GACS;CAET,OADI,EAAS,UAAgB,EAAQ,0CAC9B,EAAqB,EAAgB,CAAQ,CAAC;AACvD;AAEA,SAAS,EAAW,EAClB,UACA,eAIC;CACD,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,QAAD;GAAM,WAAU;aAAwC;EAAY,CAAA,GACpE,kBAAC,QAAD;GAAM,WAAU;GACb;EACG,CAAA,CACH;;AAET;AAUA,SAAS,EAAS,EAAE,UAAsC;CACxD,IAAM,EAAE,SAAM,EAAe,WAAW,GAClC,IAAQ,EAAY;EACxB,QAAQ,GAAK;EACb,MAAM,GAAK;EACX,OAAO,GAAK;EACZ,WAAW,GAAK;CAClB,CAAC;CAED,IAAI,CAAC,KAAO,CAAC,EAAmB,EAAI,MAAM,KAAK,CAAC,GAAO,OAAO;CAE9D,IAAM,EAAE,SAAM,WAAQ;CAEtB,OACE,kBAAC,GAAD;EAAY,OAAO,EAAE,EAAQ,wBAAwB;YACnD,kBAAC,QAAD;GAAM,eAAY;aAAlB,CACG,GACA,IAAM,kBAAC,QAAD;IAAM,WAAU;cAAhB,CAA6B,OAAI,CAAU;QAAI,IAClD;;CACI,CAAA;AAEhB;AAMA,SAAgB,EAAyB,EACvC,eACA,eAIC;CACD,IAAM,EAAE,MAAG,YAAS,EAAe,WAAW,GACxC,EAAE,iBAAc,GAChB,IAAY,IAAY,EAAoB,CAAS,IAAI,MACzD,IAAc,EAAW,QAAQ,SAAS,UAAU,IAAM,GAC1D,IAAS,EAAgB,CAAQ;CAEvC,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,QAAD;GAAM,WAAU;aACb,EAAW;EACR,CAAA,GAEN,kBAAC,MAAD;GAAI,WAAU;aAAd;IACE,kBAAC,GAAD;KAAY,OAAO,EAAE,EAAQ,0BAA0B;eACrD,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD;OACE,WAAU;OACV,eAAY;MACb,CAAA,GACD,kBAAC,QAAD;OAAM,WAAU;iBAAa,EAAkB,CAAU;MAAQ,CAAA,CAC7D;;IACI,CAAA;IAEZ,kBAAC,GAAD;KAAY,OAAO,EAAE,EAAQ,aAAa;eACxC,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAmC,UAAS,CAAA,GAC5C,kBAAC,QAAD,EAAA,UAAO,EAAE,EAAqB,CAAQ,CAAC,EAAQ,CAAA,CAC3C;;IACI,CAAA;IAEZ,kBAAC,GAAD,EAAU,KAAK,EAAY,CAAA;IAE1B,IACC,kBAAC,GAAD;KAAY,OAAO,EAAE,EAAQ,2BAA2B;eACrD,EAAmB,GAAW,EAAK,UAAU,CAAC;IACrC,CAAA,IACV;IAEH,GAAW,WAAW,EAAoB,UAC3C,EAAU,eACR,kBAAC,GAAD;KAAY,OAAO,EAAE,EAAQ,YAAY;eACvC,kBAAC,QAAD;MAAM,WAAU;gBACb,EAAU;KACP,CAAA;IACI,CAAA,IACV;GACF;IACD;;AAET"}
@@ -4,10 +4,9 @@
4
4
  * isn't set yet). Closing or completing the flow marks it done so the
5
5
  * modal won't re-appear on subsequent visits.
6
6
  *
7
- * An already-authenticated Cloud backend may provide everything onboarding
8
- * would collect. Once the active Cloud backend reports a usable LLM, suppress
9
- * the redundant modal without writing a fake completion marker. Local backends
10
- * remain browser-onboarding-driven.
7
+ * A backend already reporting a usable LLM makes the modal redundant, so it is
8
+ * skipped except the launcher-seeded default-local one, which may hold an
9
+ * LLM from an earlier user, leaving `openhands-onboarded` its first-run signal.
11
10
  *
12
11
  * With `?previewOnboardingStep=<0-3>` the modal opens on that slide for
13
12
  * design review without persisting completion (works on any route when
@@ -4,16 +4,12 @@ interface SetupLlmStepProps {
4
4
  onNext: () => void;
5
5
  }
6
6
  /**
7
- * Pre-fills the LLM form with the OpenHands provider's free default model
8
- * (`openhands/kimi-k3`), matching `DEFAULT_SETTINGS.llm_model`. The OpenHands
9
- * provider is the agent the user just selected, so the onboarding override
10
- * keeps the LLM provider aligned with that choice rather than silently
11
- * switching to OpenAI. Canvas stores provider-qualified LiteLLM model ids,
12
- * so the override uses this OpenHands-prefixed model id, and keeping it as an
13
- * explicit override marks the model dirty so the Next button persists the
14
- * suggested default immediately.
7
+ * Pre-fills the LLM form with the OpenAI GPT-5.6 Sol default
8
+ * (`openai/gpt-5.6-sol`), matching `DEFAULT_SETTINGS.llm_model`. The explicit
9
+ * override marks the model dirty so the Next button persists the suggested
10
+ * default immediately.
15
11
  */
16
- export declare const ONBOARDING_DEFAULT_LLM_MODEL = "openhands/kimi-k3";
12
+ export declare const ONBOARDING_DEFAULT_LLM_MODEL = "openai/gpt-5.6-sol";
17
13
  /**
18
14
  * Step 2: embed the LLM settings form. The screen runs in `embedded`
19
15
  * mode (so it doesn't render its own sticky Save bar) and with
@@ -3,18 +3,35 @@ interface AcpAuthStatusBannerProps {
3
3
  status: AcpAuthStatus;
4
4
  isChecking: boolean;
5
5
  providerName: string;
6
+ /**
7
+ * Whether a credential for the provider exists in the active backend's secret
8
+ * store. On Docker/cloud backends the host-login probe can't run (it shells
9
+ * the interactive CLI, which isn't installed there), so this is the only
10
+ * accurate "the agent will authenticate" signal. Optional; defaults to
11
+ * ``false`` so existing callers behave exactly as before.
12
+ */
13
+ credentialsConfigured?: boolean;
6
14
  /**
7
15
  * Prefix for the banner test ids, e.g. ``"onboarding-acp-auth"`` →
8
- * ``onboarding-acp-auth-detected`` / ``onboarding-acp-auth-checking``.
16
+ * ``onboarding-acp-auth-detected`` / ``onboarding-acp-auth-checking`` /
17
+ * ``onboarding-acp-auth-configured``.
9
18
  */
10
19
  testIdPrefix: string;
11
20
  }
12
21
  /**
13
22
  * Auth-status banner shared by the ACP credential forms (the onboarding step
14
- * and Settings → Agent): a green "already signed in" banner when the local
15
- * login probe detects a session, or a spinner while it's checking. Renders
16
- * nothing otherwise (unauthenticated / unknown / non-local backend), so the
17
- * caller falls back to the API-key fields.
23
+ * and Settings → Agent):
24
+ *
25
+ * - a green "already signed in" banner when the host-login probe detects a
26
+ * session (native backend),
27
+ * - a spinner while the probe is checking,
28
+ * - a neutral "credentials configured" banner when the probe can't confirm a
29
+ * login but a credential for the provider is stored — the accurate signal on
30
+ * Docker/cloud backends, where the probe goes silent,
31
+ * - nothing otherwise, so the caller falls back to the API-key fields.
32
+ *
33
+ * A stored credential never renders as "signed in": only the probe confirms an
34
+ * actual host login. See issue #1244.
18
35
  */
19
- export declare function AcpAuthStatusBanner({ status, isChecking, providerName, testIdPrefix, }: AcpAuthStatusBannerProps): import("react").JSX.Element | null;
36
+ export declare function AcpAuthStatusBanner({ status, isChecking, providerName, credentialsConfigured, testIdPrefix, }: AcpAuthStatusBannerProps): import("react").JSX.Element | null;
20
37
  export {};
@@ -1 +1 @@
1
- const e=require("../../../../_virtual/_rolldown/runtime.cjs");require("../../../../utils/custom-toast-handlers.cjs"),require("../../../../contexts/active-backend-context.cjs"),require("../../../../api/profiles-service/profiles-service.api.cjs"),require("../../../../hooks/query/use-llm-profiles.cjs"),require("../../../../hooks/query/use-settings.cjs"),require("../../../../ui/typography.cjs"),require("../brand-button.cjs"),require("../../../../hooks/query/use-agent-settings-schema.cjs"),require("./profile-name-input.cjs"),require("../../../../hooks/mutation/use-activate-llm-profile.cjs"),require("../../../../hooks/mutation/use-save-llm-profile.cjs"),require("./llm-profiles-manager.cjs"),require("../../../shared/buttons/back-nav-button.cjs"),require("../../../../contexts/settings-section-header-context.cjs"),require("../../../../routes/llm-settings.cjs");let t=require("react");t=e.__toESM(t,1),require("react/jsx-runtime");
1
+ const e=require("../../../../_virtual/_rolldown/runtime.cjs");require("../../../../utils/custom-toast-handlers.cjs"),require("../../../../contexts/active-backend-context.cjs"),require("../../../../api/profiles-service/profiles-service.api.cjs"),require("../../../../utils/format-model-name.cjs"),require("../../../../hooks/query/use-llm-profiles.cjs"),require("../../../../hooks/query/use-settings.cjs"),require("../../../../ui/typography.cjs"),require("../brand-button.cjs"),require("../../../../hooks/query/use-agent-settings-schema.cjs"),require("./profile-name-input.cjs"),require("../../../../hooks/mutation/use-activate-llm-profile.cjs"),require("../../../../hooks/mutation/use-save-llm-profile.cjs"),require("./llm-profiles-manager.cjs"),require("../../../shared/buttons/back-nav-button.cjs"),require("../../../../contexts/settings-section-header-context.cjs"),require("../../../../routes/llm-settings.cjs");let t=require("react");t=e.__toESM(t,1),require("react/jsx-runtime");
@@ -1,6 +1,7 @@
1
1
  import "../../../../utils/custom-toast-handlers.js";
2
2
  import "../../../../contexts/active-backend-context.js";
3
3
  import "../../../../api/profiles-service/profiles-service.api.js";
4
+ import "../../../../utils/format-model-name.js";
4
5
  import "../../../../hooks/query/use-llm-profiles.js";
5
6
  import "../../../../hooks/query/use-settings.js";
6
7
  import "../../../../ui/typography.js";
@@ -1 +1 @@
1
- require("../../../../_virtual/_rolldown/runtime.cjs"),require("../../../../utils/custom-toast-handlers.cjs"),require("../../../shared/loading-spinner.cjs"),require("../brand-button.cjs"),require("../settings-input.cjs"),require("../key-status-icon.cjs"),require("../api-key-modal-base.cjs"),require("../../../../hooks/mutation/use-create-provider-connection.cjs"),require("../../../../hooks/mutation/use-update-provider-connection.cjs"),require("react"),require("react/jsx-runtime");
1
+ require("../../../../_virtual/_rolldown/runtime.cjs"),require("../../../../utils/custom-toast-handlers.cjs"),require("../../../../utils/form-control-classes.cjs"),require("../../../../ui/combobox-caret.cjs"),require("../../../shared/loading-spinner.cjs"),require("../brand-button.cjs"),require("../settings-input.cjs"),require("../../../../hooks/query/use-search-providers.cjs"),require("../key-status-icon.cjs"),require("../api-key-modal-base.cjs"),require("../../../../hooks/mutation/use-create-provider-connection.cjs"),require("../../../../hooks/mutation/use-update-provider-connection.cjs"),require("react"),require("react/jsx-runtime");
@@ -1,7 +1,10 @@
1
1
  import "../../../../utils/custom-toast-handlers.js";
2
+ import "../../../../utils/form-control-classes.js";
3
+ import "../../../../ui/combobox-caret.js";
2
4
  import "../../../shared/loading-spinner.js";
3
5
  import "../brand-button.js";
4
6
  import "../settings-input.js";
7
+ import "../../../../hooks/query/use-search-providers.js";
5
8
  import "../key-status-icon.js";
6
9
  import "../api-key-modal-base.js";
7
10
  import "../../../../hooks/mutation/use-create-provider-connection.js";
@@ -1,2 +1,2 @@
1
- require("../../../../_virtual/_rolldown/runtime.cjs");const e=require("../../../../node_modules/react-i18next/dist/es/useTranslation.cjs"),t=require("../../../../ui/typography.cjs"),n=require("../../../../ui/help-link.cjs"),r=require("../../../../utils/sdk-settings-field-metadata.cjs");let i=require("react/jsx-runtime");var a={"llm.api_key":{textKey:`SCHEMA$LLM$API_KEY$HELP_TEXT`,linkTextKey:`SCHEMA$LLM$API_KEY$HELP_LINK_TEXT`,href:`https://docs.openhands.dev/usage/local-setup#getting-an-api-key`},"verification.critic_api_key":{textKey:`SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_TEXT`,linkTextKey:`SETTINGS$NAV_API_KEYS`,suffixKey:`SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_SUFFIX`,href:`https://app.all-hands.dev/settings/api-keys`,hideDescription:!0}};function o({field:o}){let{t:s}=e.useTranslation(`openhands`),c=a[o.key],l=r.resolveSchemaFieldDescription(s,o.key,o.description);return(0,i.jsxs)(i.Fragment,{children:[l&&!c?.hideDescription?(0,i.jsx)(t.Typography.Paragraph,{className:`text-tertiary-alt text-xs leading-5`,children:l}):null,c?(0,i.jsx)(n.HelpLink,{testId:`help-link-${o.key}`,text:s(c.textKey),linkText:s(c.linkTextKey),href:c.href,suffix:c.suffixKey?` ${s(c.suffixKey)}`:void 0,size:`settings`,linkColor:`white`}):null]})}exports.FieldHelp=o;
1
+ require("../../../../_virtual/_rolldown/runtime.cjs");const e=require("../../../../node_modules/react-i18next/dist/es/useTranslation.cjs"),t=require("../../../../ui/typography.cjs"),n=require("../../../../ui/help-link.cjs"),r=require("../../../../utils/sdk-settings-field-metadata.cjs");let i=require("react/jsx-runtime");var a={"llm.api_key":{textKey:`SCHEMA$LLM$API_KEY$HELP_TEXT`,linkTextKey:`SCHEMA$LLM$API_KEY$HELP_LINK_TEXT`,href:`https://docs.openhands.dev/usage/local-setup#getting-an-api-key`},"verification.critic_api_key":{textKey:`SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_TEXT`,linkTextKey:`SETTINGS$OPENHANDS_API_KEY_HELP_LINK`,suffixKey:`SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_SUFFIX`,href:`https://app.all-hands.dev/settings/api-keys`,hideDescription:!0}};function o({field:o}){let{t:s}=e.useTranslation(`openhands`),c=a[o.key],l=r.resolveSchemaFieldDescription(s,o.key,o.description);return(0,i.jsxs)(i.Fragment,{children:[l&&!c?.hideDescription?(0,i.jsx)(t.Typography.Paragraph,{className:`text-tertiary-alt text-xs leading-5`,children:l}):null,c?(0,i.jsx)(n.HelpLink,{testId:`help-link-${o.key}`,text:s(c.textKey),linkText:s(c.linkTextKey),href:c.href,suffix:c.suffixKey?` ${s(c.suffixKey)}`:void 0,size:`settings`,linkColor:`white`}):null]})}exports.FieldHelp=o;
2
2
  //# sourceMappingURL=field-help.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"field-help.cjs","names":[],"sources":["../../../../../src/components/features/settings/sdk-settings/field-help.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport { SettingsFieldSchema } from \"#/types/settings\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { Typography } from \"#/ui/typography\";\nimport { resolveSchemaFieldDescription } from \"#/utils/sdk-settings-field-metadata\";\n\n// ---------------------------------------------------------------------------\n// Help links – UI-only mapping from field keys to user-facing guidance.\n// Keys use conventional i18n pattern: SCHEMA$<PATH>$HELP_TEXT / HELP_LINK_TEXT\n// ---------------------------------------------------------------------------\nexport const FIELD_HELP_LINKS: Record<\n string,\n {\n textKey: string;\n linkTextKey: string;\n href: string;\n /** Skip rendering the schema description separately when the help text already includes it. */\n hideDescription?: boolean;\n /** Optional trailing copy rendered after the link (e.g. \" tab of OpenHands Cloud.\"). */\n suffixKey?: string;\n }\n> = {\n \"llm.api_key\": {\n textKey: \"SCHEMA$LLM$API_KEY$HELP_TEXT\",\n linkTextKey: \"SCHEMA$LLM$API_KEY$HELP_LINK_TEXT\",\n href: \"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\",\n },\n // Mirror the hint shown under the LLM provider's API key field when\n // OpenHands is selected as the active provider; the SDK reuses that active\n // LLM key when the critic key is empty.\n \"verification.critic_api_key\": {\n textKey: \"SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_TEXT\",\n linkTextKey: \"SETTINGS$NAV_API_KEYS\",\n suffixKey: \"SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_SUFFIX\",\n href: \"https://app.all-hands.dev/settings/api-keys\",\n hideDescription: true,\n },\n};\n\nexport function FieldHelp({ field }: { field: SettingsFieldSchema }) {\n const { t } = useTranslation(\"openhands\");\n const helpLink = FIELD_HELP_LINKS[field.key];\n const description = resolveSchemaFieldDescription(\n t,\n field.key,\n field.description,\n );\n\n return (\n <>\n {description && !helpLink?.hideDescription ? (\n <Typography.Paragraph className=\"text-tertiary-alt text-xs leading-5\">\n {description}\n </Typography.Paragraph>\n ) : null}\n {helpLink ? (\n <HelpLink\n testId={`help-link-${field.key}`}\n text={t(helpLink.textKey)}\n linkText={t(helpLink.linkTextKey)}\n href={helpLink.href}\n suffix={helpLink.suffixKey ? ` ${t(helpLink.suffixKey)}` : undefined}\n size=\"settings\"\n linkColor=\"white\"\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"kUAUA,IAAa,EAWT,CACF,cAAe,CACb,QAAS,+BACT,YAAa,oCACb,KAAM,iEACR,EAIA,8BAA+B,CAC7B,QAAS,+CACT,YAAa,wBACb,UAAW,iDACX,KAAM,8CACN,gBAAiB,EACnB,CACF,EAEA,SAAgB,EAAU,CAAE,SAAyC,CACnE,GAAM,CAAE,KAAM,EAAA,eAAe,WAAW,EAClC,EAAW,EAAiB,EAAM,KAClC,EAAc,EAAA,8BAClB,EACA,EAAM,IACN,EAAM,WACR,EAEA,OACE,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,CACG,GAAe,CAAC,GAAU,iBACzB,EAAA,EAAA,KAAC,EAAA,WAAW,UAAZ,CAAsB,UAAU,+CAC7B,CACmB,CAAA,EACpB,KACH,GACC,EAAA,EAAA,KAAC,EAAA,SAAD,CACE,OAAQ,aAAa,EAAM,MAC3B,KAAM,EAAE,EAAS,OAAO,EACxB,SAAU,EAAE,EAAS,WAAW,EAChC,KAAM,EAAS,KACf,OAAQ,EAAS,UAAY,IAAI,EAAE,EAAS,SAAS,IAAM,IAAA,GAC3D,KAAK,WACL,UAAU,OACX,CAAA,EACC,IACJ,CAAA,CAAA,CAEN"}
1
+ {"version":3,"file":"field-help.cjs","names":[],"sources":["../../../../../src/components/features/settings/sdk-settings/field-help.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport { SettingsFieldSchema } from \"#/types/settings\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { Typography } from \"#/ui/typography\";\nimport { resolveSchemaFieldDescription } from \"#/utils/sdk-settings-field-metadata\";\n\n// ---------------------------------------------------------------------------\n// Help links – UI-only mapping from field keys to user-facing guidance.\n// Keys use conventional i18n pattern: SCHEMA$<PATH>$HELP_TEXT / HELP_LINK_TEXT\n// ---------------------------------------------------------------------------\nexport const FIELD_HELP_LINKS: Record<\n string,\n {\n textKey: string;\n linkTextKey: string;\n href: string;\n /** Skip rendering the schema description separately when the help text already includes it. */\n hideDescription?: boolean;\n /** Optional trailing copy rendered after the link (e.g. \" section of OpenHands Cloud.\"). */\n suffixKey?: string;\n }\n> = {\n \"llm.api_key\": {\n textKey: \"SCHEMA$LLM$API_KEY$HELP_TEXT\",\n linkTextKey: \"SCHEMA$LLM$API_KEY$HELP_LINK_TEXT\",\n href: \"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\",\n },\n // Mirror the hint shown under the LLM provider's API key field when\n // OpenHands is selected as the active provider; the SDK reuses that active\n // LLM key when the critic key is empty.\n \"verification.critic_api_key\": {\n textKey: \"SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_TEXT\",\n linkTextKey: \"SETTINGS$OPENHANDS_API_KEY_HELP_LINK\",\n suffixKey: \"SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_SUFFIX\",\n href: \"https://app.all-hands.dev/settings/api-keys\",\n hideDescription: true,\n },\n};\n\nexport function FieldHelp({ field }: { field: SettingsFieldSchema }) {\n const { t } = useTranslation(\"openhands\");\n const helpLink = FIELD_HELP_LINKS[field.key];\n const description = resolveSchemaFieldDescription(\n t,\n field.key,\n field.description,\n );\n\n return (\n <>\n {description && !helpLink?.hideDescription ? (\n <Typography.Paragraph className=\"text-tertiary-alt text-xs leading-5\">\n {description}\n </Typography.Paragraph>\n ) : null}\n {helpLink ? (\n <HelpLink\n testId={`help-link-${field.key}`}\n text={t(helpLink.textKey)}\n linkText={t(helpLink.linkTextKey)}\n href={helpLink.href}\n suffix={helpLink.suffixKey ? ` ${t(helpLink.suffixKey)}` : undefined}\n size=\"settings\"\n linkColor=\"white\"\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"kUAUA,IAAa,EAWT,CACF,cAAe,CACb,QAAS,+BACT,YAAa,oCACb,KAAM,iEACR,EAIA,8BAA+B,CAC7B,QAAS,+CACT,YAAa,uCACb,UAAW,iDACX,KAAM,8CACN,gBAAiB,EACnB,CACF,EAEA,SAAgB,EAAU,CAAE,SAAyC,CACnE,GAAM,CAAE,KAAM,EAAA,eAAe,WAAW,EAClC,EAAW,EAAiB,EAAM,KAClC,EAAc,EAAA,8BAClB,EACA,EAAM,IACN,EAAM,WACR,EAEA,OACE,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,CACG,GAAe,CAAC,GAAU,iBACzB,EAAA,EAAA,KAAC,EAAA,WAAW,UAAZ,CAAsB,UAAU,+CAC7B,CACmB,CAAA,EACpB,KACH,GACC,EAAA,EAAA,KAAC,EAAA,SAAD,CACE,OAAQ,aAAa,EAAM,MAC3B,KAAM,EAAE,EAAS,OAAO,EACxB,SAAU,EAAE,EAAS,WAAW,EAChC,KAAM,EAAS,KACf,OAAQ,EAAS,UAAY,IAAI,EAAE,EAAS,SAAS,IAAM,IAAA,GAC3D,KAAK,WACL,UAAU,OACX,CAAA,EACC,IACJ,CAAA,CAAA,CAEN"}
@@ -5,7 +5,7 @@ export declare const FIELD_HELP_LINKS: Record<string, {
5
5
  href: string;
6
6
  /** Skip rendering the schema description separately when the help text already includes it. */
7
7
  hideDescription?: boolean;
8
- /** Optional trailing copy rendered after the link (e.g. " tab of OpenHands Cloud."). */
8
+ /** Optional trailing copy rendered after the link (e.g. " section of OpenHands Cloud."). */
9
9
  suffixKey?: string;
10
10
  }>;
11
11
  export declare function FieldHelp({ field }: {
@@ -12,7 +12,7 @@ var s = {
12
12
  },
13
13
  "verification.critic_api_key": {
14
14
  textKey: "SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_TEXT",
15
- linkTextKey: "SETTINGS$NAV_API_KEYS",
15
+ linkTextKey: "SETTINGS$OPENHANDS_API_KEY_HELP_LINK",
16
16
  suffixKey: "SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_SUFFIX",
17
17
  href: "https://app.all-hands.dev/settings/api-keys",
18
18
  hideDescription: !0
@@ -1 +1 @@
1
- {"version":3,"file":"field-help.js","names":[],"sources":["../../../../../src/components/features/settings/sdk-settings/field-help.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport { SettingsFieldSchema } from \"#/types/settings\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { Typography } from \"#/ui/typography\";\nimport { resolveSchemaFieldDescription } from \"#/utils/sdk-settings-field-metadata\";\n\n// ---------------------------------------------------------------------------\n// Help links – UI-only mapping from field keys to user-facing guidance.\n// Keys use conventional i18n pattern: SCHEMA$<PATH>$HELP_TEXT / HELP_LINK_TEXT\n// ---------------------------------------------------------------------------\nexport const FIELD_HELP_LINKS: Record<\n string,\n {\n textKey: string;\n linkTextKey: string;\n href: string;\n /** Skip rendering the schema description separately when the help text already includes it. */\n hideDescription?: boolean;\n /** Optional trailing copy rendered after the link (e.g. \" tab of OpenHands Cloud.\"). */\n suffixKey?: string;\n }\n> = {\n \"llm.api_key\": {\n textKey: \"SCHEMA$LLM$API_KEY$HELP_TEXT\",\n linkTextKey: \"SCHEMA$LLM$API_KEY$HELP_LINK_TEXT\",\n href: \"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\",\n },\n // Mirror the hint shown under the LLM provider's API key field when\n // OpenHands is selected as the active provider; the SDK reuses that active\n // LLM key when the critic key is empty.\n \"verification.critic_api_key\": {\n textKey: \"SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_TEXT\",\n linkTextKey: \"SETTINGS$NAV_API_KEYS\",\n suffixKey: \"SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_SUFFIX\",\n href: \"https://app.all-hands.dev/settings/api-keys\",\n hideDescription: true,\n },\n};\n\nexport function FieldHelp({ field }: { field: SettingsFieldSchema }) {\n const { t } = useTranslation(\"openhands\");\n const helpLink = FIELD_HELP_LINKS[field.key];\n const description = resolveSchemaFieldDescription(\n t,\n field.key,\n field.description,\n );\n\n return (\n <>\n {description && !helpLink?.hideDescription ? (\n <Typography.Paragraph className=\"text-tertiary-alt text-xs leading-5\">\n {description}\n </Typography.Paragraph>\n ) : null}\n {helpLink ? (\n <HelpLink\n testId={`help-link-${field.key}`}\n text={t(helpLink.textKey)}\n linkText={t(helpLink.linkTextKey)}\n href={helpLink.href}\n suffix={helpLink.suffixKey ? ` ${t(helpLink.suffixKey)}` : undefined}\n size=\"settings\"\n linkColor=\"white\"\n />\n ) : null}\n </>\n );\n}\n"],"mappings":";;;;;;AAUA,IAAa,IAWT;CACF,eAAe;EACb,SAAS;EACT,aAAa;EACb,MAAM;CACR;CAIA,+BAA+B;EAC7B,SAAS;EACT,aAAa;EACb,WAAW;EACX,MAAM;EACN,iBAAiB;CACnB;AACF;AAEA,SAAgB,EAAU,EAAE,YAAyC;CACnE,IAAM,EAAE,SAAM,EAAe,WAAW,GAClC,IAAW,EAAiB,EAAM,MAClC,IAAc,EAClB,GACA,EAAM,KACN,EAAM,WACR;CAEA,OACE,kBAAA,GAAA,EAAA,UAAA,CACG,KAAe,CAAC,GAAU,kBACzB,kBAAC,EAAW,WAAZ;EAAsB,WAAU;YAC7B;CACmB,CAAA,IACpB,MACH,IACC,kBAAC,GAAD;EACE,QAAQ,aAAa,EAAM;EAC3B,MAAM,EAAE,EAAS,OAAO;EACxB,UAAU,EAAE,EAAS,WAAW;EAChC,MAAM,EAAS;EACf,QAAQ,EAAS,YAAY,IAAI,EAAE,EAAS,SAAS,MAAM,KAAA;EAC3D,MAAK;EACL,WAAU;CACX,CAAA,IACC,IACJ,EAAA,CAAA;AAEN"}
1
+ {"version":3,"file":"field-help.js","names":[],"sources":["../../../../../src/components/features/settings/sdk-settings/field-help.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport { SettingsFieldSchema } from \"#/types/settings\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { Typography } from \"#/ui/typography\";\nimport { resolveSchemaFieldDescription } from \"#/utils/sdk-settings-field-metadata\";\n\n// ---------------------------------------------------------------------------\n// Help links – UI-only mapping from field keys to user-facing guidance.\n// Keys use conventional i18n pattern: SCHEMA$<PATH>$HELP_TEXT / HELP_LINK_TEXT\n// ---------------------------------------------------------------------------\nexport const FIELD_HELP_LINKS: Record<\n string,\n {\n textKey: string;\n linkTextKey: string;\n href: string;\n /** Skip rendering the schema description separately when the help text already includes it. */\n hideDescription?: boolean;\n /** Optional trailing copy rendered after the link (e.g. \" section of OpenHands Cloud.\"). */\n suffixKey?: string;\n }\n> = {\n \"llm.api_key\": {\n textKey: \"SCHEMA$LLM$API_KEY$HELP_TEXT\",\n linkTextKey: \"SCHEMA$LLM$API_KEY$HELP_LINK_TEXT\",\n href: \"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\",\n },\n // Mirror the hint shown under the LLM provider's API key field when\n // OpenHands is selected as the active provider; the SDK reuses that active\n // LLM key when the critic key is empty.\n \"verification.critic_api_key\": {\n textKey: \"SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_TEXT\",\n linkTextKey: \"SETTINGS$OPENHANDS_API_KEY_HELP_LINK\",\n suffixKey: \"SCHEMA$VERIFICATION$CRITIC_API_KEY$HELP_SUFFIX\",\n href: \"https://app.all-hands.dev/settings/api-keys\",\n hideDescription: true,\n },\n};\n\nexport function FieldHelp({ field }: { field: SettingsFieldSchema }) {\n const { t } = useTranslation(\"openhands\");\n const helpLink = FIELD_HELP_LINKS[field.key];\n const description = resolveSchemaFieldDescription(\n t,\n field.key,\n field.description,\n );\n\n return (\n <>\n {description && !helpLink?.hideDescription ? (\n <Typography.Paragraph className=\"text-tertiary-alt text-xs leading-5\">\n {description}\n </Typography.Paragraph>\n ) : null}\n {helpLink ? (\n <HelpLink\n testId={`help-link-${field.key}`}\n text={t(helpLink.textKey)}\n linkText={t(helpLink.linkTextKey)}\n href={helpLink.href}\n suffix={helpLink.suffixKey ? ` ${t(helpLink.suffixKey)}` : undefined}\n size=\"settings\"\n linkColor=\"white\"\n />\n ) : null}\n </>\n );\n}\n"],"mappings":";;;;;;AAUA,IAAa,IAWT;CACF,eAAe;EACb,SAAS;EACT,aAAa;EACb,MAAM;CACR;CAIA,+BAA+B;EAC7B,SAAS;EACT,aAAa;EACb,WAAW;EACX,MAAM;EACN,iBAAiB;CACnB;AACF;AAEA,SAAgB,EAAU,EAAE,YAAyC;CACnE,IAAM,EAAE,SAAM,EAAe,WAAW,GAClC,IAAW,EAAiB,EAAM,MAClC,IAAc,EAClB,GACA,EAAM,KACN,EAAM,WACR;CAEA,OACE,kBAAA,GAAA,EAAA,UAAA,CACG,KAAe,CAAC,GAAU,kBACzB,kBAAC,EAAW,WAAZ;EAAsB,WAAU;YAC7B;CACmB,CAAA,IACpB,MACH,IACC,kBAAC,GAAD;EACE,QAAQ,aAAa,EAAM;EAC3B,MAAM,EAAE,EAAS,OAAO;EACxB,UAAU,EAAE,EAAS,WAAW;EAChC,MAAM,EAAS;EACf,QAAQ,EAAS,YAAY,IAAI,EAAE,EAAS,SAAS,MAAM,KAAA;EAC3D,MAAK;EACL,WAAU;CACX,CAAA,IACC,IACJ,EAAA,CAAA;AAEN"}
@@ -1,2 +1,2 @@
1
- const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../../node_modules/react-i18next/dist/es/useTranslation.cjs"),n=require("../../../../i18n/declaration.cjs"),r=require("../../../../node_modules/axios/index.cjs"),i=require("../../../../utils/retrieve-axios-error-message.cjs"),a=require("../../../../utils/custom-toast-handlers.cjs"),ee=require("../../../../hooks/query/use-settings.cjs"),te=require("../brand-button.cjs"),ne=require("../../../../utils/extension-module-card-classes.cjs"),re=require("../../../../hooks/mutation/use-save-settings.cjs"),o=require("../../../../hooks/query/use-agent-settings-schema.cjs"),s=require("../llm-settings/llm-settings-inputs-skeleton.cjs"),c=require("../../../../utils/sdk-settings-schema.cjs"),l=require("./schema-field.cjs"),ie=require("./view-toggle.cjs");let u=require("react");u=e.__toESM(u,1);let d=require("react/jsx-runtime");var ae=new Set,f={basic:0,advanced:1,all:2},oe=(e,t)=>f[t]<f[e]?t:e,se=(e,t)=>f[t]>f[e]?t:e,p=(e,{showBasic:t,showAdvanced:n,showAll:r})=>{if(e===`all`)return r?`all`:n?`advanced`:`basic`;if(e===`advanced`)return n?`advanced`:r?`all`:`basic`;if(!t){if(n)return`advanced`;if(r)return`all`}return`basic`},m={agent_settings:`agent_settings_diff`,conversation_settings:`conversation_settings_diff`},ce=(e,t)=>e instanceof r.AxiosError?e.response?.status===401?`${t} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.`:e.response?.status===404?`${t} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`:t:t;function h({settingsSources:e,scope:r=`personal`,header:f,extraDirty:h=!1,buildPayload:g,onSaveSuccess:le,getInitialView:_,forceShowAdvancedView:ue=!1,allowAllView:de=!0,initialValueOverrides:v,embedded:fe=!1,hideSaveButton:pe=!1,suppressSuccessToast:me=!1,onSaveControlChange:y,testId:b=`sdk-section-settings-screen`}){let{t:x}=t.useTranslation(`openhands`),{mutate:he,isPending:S}=re.useSaveSettings(r),{data:C,isLoading:ge,isFetching:_e}=ee.useSettings(r),w=o.useAgentSettingsSchema(C?.agent_settings_schema),T=o.useConversationSettingsSchema(C?.conversation_settings_schema),E=u.default.useMemo(()=>JSON.stringify(e.map(e=>({source:e.settingsSource,sectionKeys:e.sectionKeys,excludeKeys:e.excludeKeys?Array.from(e.excludeKeys).sort():null}))),[e]),D=u.default.useMemo(()=>JSON.parse(E).map(e=>({settingsSource:e.source,sectionKeys:e.sectionKeys,excludeKeys:e.excludeKeys?new Set(e.excludeKeys):void 0})),[E]),O=u.default.useCallback(e=>e===`conversation_settings`?T.data:w.data,[w.data,T.data]),ve=D.some(e=>e.settingsSource===`conversation_settings`?T.isLoading:w.isLoading),k=u.default.useMemo(()=>D.map(e=>{let t=O(e.settingsSource);if(!c.isValidSettingsSchema(t))return{...e,filteredSchema:null};let n=new Set(e.sectionKeys),r=new Set,i={...t,sections:t.sections.filter(e=>!n.has(e.key)||r.has(e.key)?!1:(r.add(e.key),!0))};return{...e,filteredSchema:i}}),[D,O]),A=k.some(e=>c.hasCriticalSettings(e.filteredSchema)),j=ue||k.some(e=>c.hasAdvancedSettings(e.filteredSchema)),M=de&&k.some(e=>c.hasMinorSettings(e.filteredSchema)),N=u.default.useMemo(()=>ce(D.reduce((e,t)=>e??(t.settingsSource===`conversation_settings`?T.error:w.error),null),x(n.I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE)),[D,w.error,T.error,x]),P=u.default.useMemo(()=>v?JSON.stringify(v):``,[v]),[F,I]=u.default.useState(`basic`),[L,R]=u.default.useState({}),[z,B]=u.default.useState({}),V=u.default.useRef(!1),H=u.default.useMemo(()=>{if(!C)return null;let e={};for(let t of k){if(!t.filteredSchema)return null;e[t.settingsSource]={...e[t.settingsSource]??{},...c.buildInitialSettingsFormValues(C,t.filteredSchema,t.settingsSource)}}if(v){let t=k[0]?.settingsSource;t&&e[t]&&(e[t]={...e[t],...v})}return e},[C,k,P]),U=u.default.useMemo(()=>{if(!C)return null;let e=null;for(let t of k){if(!t.filteredSchema)return null;let n=_?_(C,t.filteredSchema):c.inferInitialView(C,t.filteredSchema,t.settingsSource);e=e?se(e,n):n}return e?p(e,{showBasic:A,showAdvanced:j,showAll:M}):null},[C,k,_,A,j,M]);u.default.useEffect(()=>{V.current=!1,I(`basic`),R({}),B({})},[r,E]),u.default.useEffect(()=>{if(!(!H||!U)){if(R(H),v){let e=k[0]?.settingsSource;if(e){let t=Object.fromEntries(Object.keys(v).map(e=>[e,!0]));B({[e]:t})}else B({})}else B({});V.current?I(e=>oe(e,U)):(V.current=!0,I(U))}},[H,U]);let W=u.default.useMemo(()=>{let e=new Map;for(let t of k)if(t.filteredSchema)for(let n of t.filteredSchema.sections)for(let r of n.fields)e.has(r.key)||e.set(r.key,t.settingsSource);return e},[k]),G=u.default.useMemo(()=>{let e={};for(let t of k)Object.assign(e,L[t.settingsSource]??{});return e},[k,L]),K=u.default.useMemo(()=>{let e={};for(let t of k)Object.assign(e,z[t.settingsSource]??{});return e},[k,z]),q=u.default.useCallback((e,t)=>{let n=W.get(e);n&&(R(r=>({...r,[n]:{...r[n]??{},[e]:t}})),B(t=>({...t,[n]:{...t[n]??{},[e]:!0}})))},[W]),ye=u.default.useCallback(e=>{a.displayErrorToast(i.retrieveAxiosErrorMessage(e)||x(n.I18nKey.ERROR$GENERIC))},[x]),J=u.default.useRef(()=>{}),Y=u.default.useCallback(()=>{J.current()},[]),X=u.default.useRef(()=>({})),be=u.default.useCallback(()=>X.current(),[]),Z=()=>{if(k.some(e=>!e.filteredSchema))return;let e;try{let t={};for(let e of k){let n=e.filteredSchema,r=c.buildSdkSettingsPayloadForView(n,L[e.settingsSource]??{},z[e.settingsSource]??{},F);if(Object.keys(r).length>0){let n=m[e.settingsSource];t[n]={...t[n]??{},...r}}}e=g?g(t,{values:G,dirty:K,view:F}):t}catch(e){a.displayErrorToast(e instanceof Error?e.message:x(n.I18nKey.ERROR$GENERIC));return}Object.keys(e).length!==0&&he(e,{onError:ye,onSuccess:()=>{me||a.displaySuccessToast(x(n.I18nKey.SETTINGS$SAVED_WARNING)),B({}),le?.()}})};J.current=Z,X.current=()=>{let e={};for(let t of k){if(!t.filteredSchema)continue;let n=L[t.settingsSource]??{},r=z[t.settingsSource]??{};Object.assign(e,c.buildSdkSettingsPayload(t.filteredSchema,n,r))}return e};let Q=Object.keys(K).length>0,$=Q||h;return u.default.useEffect(()=>{y&&y({save:Y,isSaving:S,isDirty:$,values:G,view:F,getDirtyPayload:be})},[S,$,G,F]),(ge||_e)&&!C||ve?(0,d.jsx)(s.LlmSettingsInputsSkeleton,{}):k.some(e=>e.filteredSchema&&e.filteredSchema.sections.length>0)?Object.keys(G).length===0?(0,d.jsx)(s.LlmSettingsInputsSkeleton,{}):(0,d.jsxs)(`div`,{"data-testid":b,className:fe?`relative flex min-h-0 w-full flex-1 flex-col`:`relative w-full min-h-0`,children:[(0,d.jsx)(ie.ViewToggle,{view:F,setView:I,showBasic:A,showAdvanced:j,showAll:M,isDisabled:!1}),(0,d.jsxs)(`div`,{className:`flex flex-col gap-8`,children:[f?.({values:G,isDisabled:!1,view:F,onChange:q}),k.map(e=>{if(!e.filteredSchema)return null;let t=L[e.settingsSource]??{};return c.getVisibleSettingsSections(e.filteredSchema,{...G,...t},F,e.excludeKeys??ae).map(n=>(0,d.jsx)(`section`,{className:`flex flex-col gap-4`,children:(0,d.jsx)(`div`,{className:`grid gap-4 xl:grid-cols-2`,children:n.fields.map(e=>(0,d.jsx)(`div`,{className:l.FIELD_FULL_WIDTH_KEYS.has(e.key)?`xl:col-span-2`:void 0,children:(0,d.jsx)(l.SchemaField,{field:e,value:t[e.key],isDisabled:!1,onChange:t=>q(e.key,t)})},e.key))})},`${e.settingsSource}:${n.key}`))}),pe?null:(0,d.jsx)(`div`,{className:`flex justify-start pt-2`,children:(0,d.jsx)(te.BrandButton,{testId:`save-button`,type:`button`,variant:`primary`,isDisabled:S||!Q&&!h,onClick:Z,children:x(S?n.I18nKey.SETTINGS$SAVING:n.I18nKey.SETTINGS$SAVE_CHANGES)})})]})]}):(0,d.jsx)(`div`,{"data-testid":`sdk-schema-unavailable`,className:ne.extensionModuleEmptyStateClassName,children:(0,d.jsx)(`p`,{className:`text-sm text-[var(--oh-muted)]`,children:N})})}exports.SdkSectionPage=h;
1
+ const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../../node_modules/react-i18next/dist/es/useTranslation.cjs"),n=require("../../../../i18n/declaration.cjs"),r=require("../../../../node_modules/axios/index.cjs"),i=require("../../../../utils/retrieve-axios-error-message.cjs"),a=require("../../../../utils/custom-toast-handlers.cjs"),ee=require("../../../../hooks/query/use-settings.cjs"),te=require("../../../../hooks/mutation/use-save-settings.cjs"),ne=require("../brand-button.cjs"),re=require("../../../../utils/extension-module-card-classes.cjs"),o=require("../../../../hooks/query/use-agent-settings-schema.cjs"),s=require("../llm-settings/llm-settings-inputs-skeleton.cjs"),c=require("../../../../utils/sdk-settings-schema.cjs"),l=require("./schema-field.cjs"),ie=require("./view-toggle.cjs");let u=require("react");u=e.__toESM(u,1);let d=require("react/jsx-runtime");var ae=new Set,f={basic:0,advanced:1,all:2},oe=(e,t)=>f[t]<f[e]?t:e,se=(e,t)=>f[t]>f[e]?t:e,p=(e,{showBasic:t,showAdvanced:n,showAll:r})=>{if(e===`all`)return r?`all`:n?`advanced`:`basic`;if(e===`advanced`)return n?`advanced`:r?`all`:`basic`;if(!t){if(n)return`advanced`;if(r)return`all`}return`basic`},m={agent_settings:`agent_settings_diff`,conversation_settings:`conversation_settings_diff`},ce=(e,t)=>e instanceof r.AxiosError?e.response?.status===401?`${t} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.`:e.response?.status===404?`${t} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`:t:t;function h({settingsSources:e,scope:r=`personal`,header:f,extraDirty:h=!1,buildPayload:g,onSaveSuccess:le,getInitialView:_,forceShowAdvancedView:ue=!1,allowAllView:de=!0,initialValueOverrides:v,embedded:fe=!1,hideSaveButton:pe=!1,suppressSuccessToast:me=!1,onSaveControlChange:y,testId:b=`sdk-section-settings-screen`}){let{t:x}=t.useTranslation(`openhands`),{mutate:he,isPending:S}=te.useSaveSettings(r),{data:C,isLoading:ge,isFetching:_e}=ee.useSettings(r),w=o.useAgentSettingsSchema(C?.agent_settings_schema),T=o.useConversationSettingsSchema(C?.conversation_settings_schema),E=u.default.useMemo(()=>JSON.stringify(e.map(e=>({source:e.settingsSource,sectionKeys:e.sectionKeys,excludeKeys:e.excludeKeys?Array.from(e.excludeKeys).sort():null}))),[e]),D=u.default.useMemo(()=>JSON.parse(E).map(e=>({settingsSource:e.source,sectionKeys:e.sectionKeys,excludeKeys:e.excludeKeys?new Set(e.excludeKeys):void 0})),[E]),O=u.default.useCallback(e=>e===`conversation_settings`?T.data:w.data,[w.data,T.data]),ve=D.some(e=>e.settingsSource===`conversation_settings`?T.isLoading:w.isLoading),k=u.default.useMemo(()=>D.map(e=>{let t=O(e.settingsSource);if(!c.isValidSettingsSchema(t))return{...e,filteredSchema:null};let n=new Set(e.sectionKeys),r=new Set,i={...t,sections:t.sections.filter(e=>!n.has(e.key)||r.has(e.key)?!1:(r.add(e.key),!0))};return{...e,filteredSchema:i}}),[D,O]),A=k.some(e=>c.hasCriticalSettings(e.filteredSchema)),j=ue||k.some(e=>c.hasAdvancedSettings(e.filteredSchema)),M=de&&k.some(e=>c.hasMinorSettings(e.filteredSchema)),N=u.default.useMemo(()=>ce(D.reduce((e,t)=>e??(t.settingsSource===`conversation_settings`?T.error:w.error),null),x(n.I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE)),[D,w.error,T.error,x]),P=u.default.useMemo(()=>v?JSON.stringify(v):``,[v]),[F,I]=u.default.useState(`basic`),[L,R]=u.default.useState({}),[z,B]=u.default.useState({}),V=u.default.useRef(!1),H=u.default.useMemo(()=>{if(!C)return null;let e={};for(let t of k){if(!t.filteredSchema)return null;e[t.settingsSource]={...e[t.settingsSource]??{},...c.buildInitialSettingsFormValues(C,t.filteredSchema,t.settingsSource)}}if(v){let t=k[0]?.settingsSource;t&&e[t]&&(e[t]={...e[t],...v})}return e},[C,k,P]),U=u.default.useMemo(()=>{if(!C)return null;let e=null;for(let t of k){if(!t.filteredSchema)return null;let n=_?_(C,t.filteredSchema):c.inferInitialView(C,t.filteredSchema,t.settingsSource);e=e?se(e,n):n}return e?p(e,{showBasic:A,showAdvanced:j,showAll:M}):null},[C,k,_,A,j,M]);u.default.useEffect(()=>{V.current=!1,I(`basic`),R({}),B({})},[r,E]),u.default.useEffect(()=>{if(!(!H||!U)){if(R(H),v){let e=k[0]?.settingsSource;if(e){let t=Object.fromEntries(Object.keys(v).map(e=>[e,!0]));B({[e]:t})}else B({})}else B({});V.current?I(e=>oe(e,U)):(V.current=!0,I(U))}},[H,U]);let W=u.default.useMemo(()=>{let e=new Map;for(let t of k)if(t.filteredSchema)for(let n of t.filteredSchema.sections)for(let r of n.fields)e.has(r.key)||e.set(r.key,t.settingsSource);return e},[k]),G=u.default.useMemo(()=>{let e={};for(let t of k)Object.assign(e,L[t.settingsSource]??{});return e},[k,L]),K=u.default.useMemo(()=>{let e={};for(let t of k)Object.assign(e,z[t.settingsSource]??{});return e},[k,z]),q=u.default.useCallback((e,t)=>{let n=W.get(e);n&&(R(r=>({...r,[n]:{...r[n]??{},[e]:t}})),B(t=>({...t,[n]:{...t[n]??{},[e]:!0}})))},[W]),ye=u.default.useCallback(e=>{a.displayErrorToast(i.retrieveAxiosErrorMessage(e)||x(n.I18nKey.ERROR$GENERIC))},[x]),J=u.default.useRef(()=>{}),Y=u.default.useCallback(()=>{J.current()},[]),X=u.default.useRef(()=>({})),be=u.default.useCallback(()=>X.current(),[]),Z=()=>{if(k.some(e=>!e.filteredSchema))return;let e;try{let t={};for(let e of k){let n=e.filteredSchema,r=c.buildSdkSettingsPayloadForView(n,L[e.settingsSource]??{},z[e.settingsSource]??{},F);if(Object.keys(r).length>0){let n=m[e.settingsSource];t[n]={...t[n]??{},...r}}}e=g?g(t,{values:G,dirty:K,view:F}):t}catch(e){a.displayErrorToast(e instanceof Error?e.message:x(n.I18nKey.ERROR$GENERIC));return}Object.keys(e).length!==0&&he(e,{onError:ye,onSuccess:()=>{me||a.displaySuccessToast(x(n.I18nKey.SETTINGS$SAVED_WARNING)),B({}),le?.()}})};J.current=Z,X.current=()=>{let e={};for(let t of k){if(!t.filteredSchema)continue;let n=L[t.settingsSource]??{},r=z[t.settingsSource]??{};Object.assign(e,c.buildSdkSettingsPayload(t.filteredSchema,n,r))}return e};let Q=Object.keys(K).length>0,$=Q||h;return u.default.useEffect(()=>{y&&y({save:Y,isSaving:S,isDirty:$,values:G,view:F,getDirtyPayload:be})},[S,$,G,F]),(ge||_e)&&!C||ve?(0,d.jsx)(s.LlmSettingsInputsSkeleton,{}):k.some(e=>e.filteredSchema&&e.filteredSchema.sections.length>0)?Object.keys(G).length===0?(0,d.jsx)(s.LlmSettingsInputsSkeleton,{}):(0,d.jsxs)(`div`,{"data-testid":b,className:fe?`relative flex min-h-0 w-full flex-1 flex-col`:`relative w-full min-h-0`,children:[(0,d.jsx)(ie.ViewToggle,{view:F,setView:I,showBasic:A,showAdvanced:j,showAll:M,isDisabled:!1}),(0,d.jsxs)(`div`,{className:`flex flex-col gap-8`,children:[f?.({values:G,isDisabled:!1,view:F,onChange:q}),k.map(e=>{if(!e.filteredSchema)return null;let t=L[e.settingsSource]??{};return c.getVisibleSettingsSections(e.filteredSchema,{...G,...t},F,e.excludeKeys??ae).map(n=>(0,d.jsx)(`section`,{className:`flex flex-col gap-4`,children:(0,d.jsx)(`div`,{className:`grid gap-4 xl:grid-cols-2`,children:n.fields.map(e=>(0,d.jsx)(`div`,{className:l.FIELD_FULL_WIDTH_KEYS.has(e.key)?`xl:col-span-2`:void 0,children:(0,d.jsx)(l.SchemaField,{field:e,value:t[e.key],isDisabled:!1,onChange:t=>q(e.key,t)})},e.key))})},`${e.settingsSource}:${n.key}`))}),pe?null:(0,d.jsx)(`div`,{className:`flex justify-start pt-2`,children:(0,d.jsx)(ne.BrandButton,{testId:`save-button`,type:`button`,variant:`primary`,isDisabled:S||!Q&&!h,onClick:Z,children:x(S?n.I18nKey.SETTINGS$SAVING:n.I18nKey.SETTINGS$SAVE_CHANGES)})})]})]}):(0,d.jsx)(`div`,{"data-testid":`sdk-schema-unavailable`,className:re.extensionModuleEmptyStateClassName,children:(0,d.jsx)(`p`,{className:`text-sm text-[var(--oh-muted)]`,children:N})})}exports.SdkSectionPage=h;
2
2
  //# sourceMappingURL=sdk-section-page.cjs.map
@@ -4,9 +4,9 @@ import { AxiosError as n } from "../../../../node_modules/axios/index.js";
4
4
  import { retrieveAxiosErrorMessage as r } from "../../../../utils/retrieve-axios-error-message.js";
5
5
  import { displayErrorToast as i, displaySuccessToast as ee } from "../../../../utils/custom-toast-handlers.js";
6
6
  import { useSettings as te } from "../../../../hooks/query/use-settings.js";
7
- import { BrandButton as ne } from "../brand-button.js";
8
- import { extensionModuleEmptyStateClassName as re } from "../../../../utils/extension-module-card-classes.js";
9
- import { useSaveSettings as a } from "../../../../hooks/mutation/use-save-settings.js";
7
+ import { useSaveSettings as ne } from "../../../../hooks/mutation/use-save-settings.js";
8
+ import { BrandButton as re } from "../brand-button.js";
9
+ import { extensionModuleEmptyStateClassName as a } from "../../../../utils/extension-module-card-classes.js";
10
10
  import { useAgentSettingsSchema as o, useConversationSettingsSchema as s } from "../../../../hooks/query/use-agent-settings-schema.js";
11
11
  import { LlmSettingsInputsSkeleton as c } from "../llm-settings/llm-settings-inputs-skeleton.js";
12
12
  import { buildInitialSettingsFormValues as ie, buildSdkSettingsPayload as ae, buildSdkSettingsPayloadForView as oe, getVisibleSettingsSections as se, hasAdvancedSettings as ce, hasCriticalSettings as le, hasMinorSettings as ue, inferInitialView as de, isValidSettingsSchema as fe } from "../../../../utils/sdk-settings-schema.js";
@@ -32,7 +32,7 @@ var ge = /* @__PURE__ */ new Set(), f = {
32
32
  conversation_settings: "conversation_settings_diff"
33
33
  }, be = (e, t) => e instanceof n ? e.response?.status === 401 ? `${t} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.` : e.response?.status === 404 ? `${t} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.` : t : t;
34
34
  function m({ settingsSources: n, scope: f = "personal", header: m, extraDirty: h = !1, buildPayload: g, onSaveSuccess: xe, getInitialView: _, forceShowAdvancedView: Se = !1, allowAllView: Ce = !0, initialValueOverrides: v, embedded: we = !1, hideSaveButton: Te = !1, suppressSuccessToast: Ee = !1, onSaveControlChange: y, testId: De = "sdk-section-settings-screen" }) {
35
- let { t: b } = e("openhands"), { mutate: x, isPending: S } = a(f), { data: C, isLoading: w, isFetching: T } = te(f), E = o(C?.agent_settings_schema), D = s(C?.conversation_settings_schema), O = l.useMemo(() => JSON.stringify(n.map((e) => ({
35
+ let { t: b } = e("openhands"), { mutate: x, isPending: S } = ne(f), { data: C, isLoading: w, isFetching: T } = te(f), E = o(C?.agent_settings_schema), D = s(C?.conversation_settings_schema), O = l.useMemo(() => JSON.stringify(n.map((e) => ({
36
36
  source: e.settingsSource,
37
37
  sectionKeys: e.sectionKeys,
38
38
  excludeKeys: e.excludeKeys ? Array.from(e.excludeKeys).sort() : null
@@ -245,7 +245,7 @@ function m({ settingsSources: n, scope: f = "personal", header: m, extraDirty: h
245
245
  }),
246
246
  Te ? null : /* @__PURE__ */ u("div", {
247
247
  className: "flex justify-start pt-2",
248
- children: /* @__PURE__ */ u(ne, {
248
+ children: /* @__PURE__ */ u(re, {
249
249
  testId: "save-button",
250
250
  type: "button",
251
251
  variant: "primary",
@@ -258,7 +258,7 @@ function m({ settingsSources: n, scope: f = "personal", header: m, extraDirty: h
258
258
  })]
259
259
  }) : /* @__PURE__ */ u("div", {
260
260
  "data-testid": "sdk-schema-unavailable",
261
- className: re,
261
+ className: a,
262
262
  children: /* @__PURE__ */ u("p", {
263
263
  className: "text-sm text-[var(--oh-muted)]",
264
264
  children: Oe
@@ -1 +1 @@
1
- {"version":3,"file":"sdk-section-page.js","names":[],"sources":["../../../../../src/components/features/settings/sdk-settings/sdk-section-page.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { LlmSettingsInputsSkeleton } from \"#/components/features/settings/llm-settings/llm-settings-inputs-skeleton\";\nimport { useSaveSettings } from \"#/hooks/mutation/use-save-settings\";\nimport {\n useAgentSettingsSchema,\n useConversationSettingsSchema,\n} from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extensionModuleEmptyStateClassName } from \"#/utils/extension-module-card-classes\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport {\n buildInitialSettingsFormValues,\n buildSdkSettingsPayload,\n buildSdkSettingsPayloadForView,\n getVisibleSettingsSections,\n hasAdvancedSettings,\n hasCriticalSettings,\n hasMinorSettings,\n inferInitialView,\n isValidSettingsSchema,\n SettingsDirtyState,\n SettingsFormValues,\n type SettingsValueSource,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { FIELD_FULL_WIDTH_KEYS, SchemaField } from \"./schema-field\";\nimport { ViewToggle } from \"./view-toggle\";\n\nconst EMPTY_EXCLUDE_KEYS = new Set<string>();\n\nconst VIEW_ORDER: Record<SettingsView, number> = {\n basic: 0,\n advanced: 1,\n all: 2,\n};\n\nconst getLessDetailedView = (\n currentView: SettingsView,\n nextView: SettingsView,\n): SettingsView =>\n VIEW_ORDER[nextView] < VIEW_ORDER[currentView] ? nextView : currentView;\n\nconst getMoreDetailedView = (\n currentView: SettingsView,\n nextView: SettingsView,\n): SettingsView =>\n VIEW_ORDER[nextView] > VIEW_ORDER[currentView] ? nextView : currentView;\n\nconst normalizeView = (\n view: SettingsView,\n {\n showBasic,\n showAdvanced,\n showAll,\n }: {\n showBasic: boolean;\n showAdvanced: boolean;\n showAll: boolean;\n },\n): SettingsView => {\n if (view === \"all\") {\n if (showAll) {\n return \"all\";\n }\n\n return showAdvanced ? \"advanced\" : \"basic\";\n }\n\n if (view === \"advanced\") {\n if (showAdvanced) {\n return \"advanced\";\n }\n\n return showAll ? \"all\" : \"basic\";\n }\n\n // A critical-less page has nothing to render in the basic tier; bump up.\n if (!showBasic) {\n if (showAdvanced) return \"advanced\";\n if (showAll) return \"all\";\n }\n return \"basic\";\n};\n\nconst PAYLOAD_DIFF_KEY: Record<SettingsValueSource, string> = {\n agent_settings: \"agent_settings_diff\",\n conversation_settings: \"conversation_settings_diff\",\n};\n\nconst getSchemaUnavailableMessage = (\n error: unknown,\n fallbackMessage: string,\n): string => {\n if (!(error instanceof AxiosError)) {\n return fallbackMessage;\n }\n\n if (error.response?.status === 401) {\n return `${fallbackMessage} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.`;\n }\n\n if (error.response?.status === 404) {\n return `${fallbackMessage} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`;\n }\n\n return fallbackMessage;\n};\n\nexport interface SettingsSourceConfig {\n /** Which schema/values bucket on `settings` this source pulls from. */\n settingsSource: SettingsValueSource;\n /** Section keys (e.g. [\"llm\"]) within that schema to render. */\n sectionKeys: string[];\n /** Field keys to skip (rendered elsewhere by the caller). */\n excludeKeys?: Set<string>;\n}\n\nexport interface SdkSectionHeaderProps {\n values: SettingsFormValues;\n isDisabled: boolean;\n view: SettingsView;\n onChange: (key: string, value: string | boolean) => void;\n}\n\ninterface ResolvedSource extends SettingsSourceConfig {\n filteredSchema: SettingsSchema | null;\n}\n\n/**\n * Snapshot of the page's save state, surfaced to the parent so it can\n * render its own Save/Next button (e.g. in onboarding) when\n * {@link SdkSectionPage}'s built-in button is hidden via\n * `hideSaveButton`.\n */\nexport interface SdkSectionSaveControl {\n /** Trigger a save of the currently-dirty fields. No-op while `isSaving` or `!isDirty`. */\n save: () => void;\n /** A save mutation is in flight. */\n isSaving: boolean;\n /** At least one field is dirty (or `extraDirty` was passed in). */\n isDirty: boolean;\n /** Current form values (for custom save flows). */\n values: SettingsFormValues;\n /** The active view tier (basic/advanced/all) the form is rendering. */\n view: SettingsView;\n /**\n * Returns the coerced, dirty-only payload as a nested object\n * (e.g. `{ llm: { temperature: 0.7 } }`). Lets a custom save flow persist\n * exactly the fields the user changed, with proper types, without\n * re-implementing schema-driven coercion. Throws if a field fails coercion.\n */\n getDirtyPayload: () => Record<string, unknown>;\n}\n\n/**\n * A generic SDK-schema-driven settings page that renders fields from one or\n * more schema sections.\n *\n * The `settingsSources` array specifies which schema(s)/section(s) the page\n * owns. The page tracks values/dirty state per source, renders sections from\n * each source in order (filtered by the schema's `prominence` field for the\n * selected view), and emits a combined save payload like\n * `{ conversation_settings_diff: {...}, agent_settings_diff: {...} }` ---\n * including only the keys for sources that actually have dirty changes.\n *\n * @param settingsSources one or more schemas to render fields from\n * @param header render prop above the fields (receives unified state)\n * @param buildPayload customize the save payload before submission\n * @param testId data-testid on the page wrapper\n */\nexport function SdkSectionPage({\n settingsSources,\n scope = \"personal\",\n header,\n extraDirty = false,\n buildPayload,\n onSaveSuccess,\n getInitialView,\n forceShowAdvancedView = false,\n allowAllView = true,\n initialValueOverrides,\n embedded = false,\n hideSaveButton = false,\n suppressSuccessToast = false,\n onSaveControlChange,\n testId = \"sdk-section-settings-screen\",\n}: {\n settingsSources: SettingsSourceConfig[];\n scope?: SettingsScope;\n\n header?: (props: SdkSectionHeaderProps) => React.ReactNode;\n extraDirty?: boolean;\n /**\n * Customize the save payload. Receives the wrapped default payload (e.g.\n * `{ agent_settings_diff: { llm: { model: \"gpt-4\" } } }`) plus the unified\n * form context. Return the payload to actually send.\n */\n buildPayload?: (\n defaultPayload: Record<string, unknown>,\n context: {\n values: SettingsFormValues;\n dirty: SettingsDirtyState;\n view: SettingsView;\n },\n ) => Record<string, unknown>;\n onSaveSuccess?: () => void;\n getInitialView?: (\n settings: Settings,\n filteredSchema: SettingsSchema,\n ) => SettingsView;\n forceShowAdvancedView?: boolean;\n allowAllView?: boolean;\n /**\n * Per-field initial value overrides that win over the values\n * derived from `useSettings`. The keys of each override are also\n * marked dirty on hydration so the user can save the form without\n * having to touch the prefilled fields. Useful when the page is\n * embedded in a flow that wants to nudge brand-new users toward a\n * particular default (e.g. onboarding pre-filling OpenHands/Opus).\n */\n initialValueOverrides?: SettingsFormValues;\n embedded?: boolean;\n hideSaveButton?: boolean;\n /** Suppress the default success toast after save completes. */\n suppressSuccessToast?: boolean;\n /**\n * Fires whenever the save state changes (a mutation starts/finishes,\n * dirty status flips). Provides a stable `save()` callback the\n * parent can wire to its own button. Useful when the form is\n * embedded in a custom flow and the built-in Save button is hidden.\n */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n testId?: string;\n}) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: saveSettings, isPending } = useSaveSettings(scope);\n const { data: settings, isLoading, isFetching } = useSettings(scope);\n const agentSchemaQuery = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n const conversationSchemaQuery = useConversationSettingsSchema(\n settings?.conversation_settings_schema,\n );\n const isReadOnly = false;\n\n const sourcesSignature = React.useMemo(\n () =>\n JSON.stringify(\n settingsSources.map((s) => ({\n source: s.settingsSource,\n sectionKeys: s.sectionKeys,\n excludeKeys: s.excludeKeys ? Array.from(s.excludeKeys).sort() : null,\n })),\n ),\n [settingsSources],\n );\n\n const resolvedSourceConfigs = React.useMemo<SettingsSourceConfig[]>(() => {\n const parsed = JSON.parse(sourcesSignature) as Array<{\n source: SettingsValueSource;\n sectionKeys: string[];\n excludeKeys: string[] | null;\n }>;\n return parsed.map((p) => ({\n settingsSource: p.source,\n sectionKeys: p.sectionKeys,\n excludeKeys: p.excludeKeys ? new Set(p.excludeKeys) : undefined,\n }));\n }, [sourcesSignature]);\n\n const getSchemaForSource = React.useCallback(\n (source: SettingsValueSource) =>\n source === \"conversation_settings\"\n ? conversationSchemaQuery.data\n : agentSchemaQuery.data,\n [agentSchemaQuery.data, conversationSchemaQuery.data],\n );\n\n const isSchemaLoading = resolvedSourceConfigs.some((src) =>\n src.settingsSource === \"conversation_settings\"\n ? conversationSchemaQuery.isLoading\n : agentSchemaQuery.isLoading,\n );\n\n const resolvedSources = React.useMemo<ResolvedSource[]>(\n () =>\n resolvedSourceConfigs.map((src) => {\n const schema = getSchemaForSource(src.settingsSource);\n if (!isValidSettingsSchema(schema)) {\n return { ...src, filteredSchema: null };\n }\n const sectionSet = new Set(src.sectionKeys);\n // The agent schema can carry more than one section per key — e.g. the\n // combined AgentSettings schema emits an \"llm\" section for both the\n // \"openhands\" and \"acp\" variants. Only the first (openhands) is used,\n // so keep the first section per key; otherwise every field renders\n // twice and React sees duplicate section keys.\n const seenKeys = new Set<string>();\n const filteredSchema: SettingsSchema = {\n ...schema,\n sections: schema.sections.filter((s) => {\n if (!sectionSet.has(s.key) || seenKeys.has(s.key)) return false;\n seenKeys.add(s.key);\n return true;\n }),\n };\n return { ...src, filteredSchema };\n }),\n [resolvedSourceConfigs, getSchemaForSource],\n );\n\n // The basic tier only exists when some field renders in it; a critical-less\n // page (e.g. Memory, whose only field is major) hides the Basic tab and\n // floors its view at \"advanced\".\n const showBasic = resolvedSources.some((src) =>\n hasCriticalSettings(src.filteredSchema),\n );\n const showAdvanced =\n forceShowAdvancedView ||\n resolvedSources.some((src) => hasAdvancedSettings(src.filteredSchema));\n const showAll =\n allowAllView &&\n resolvedSources.some((src) => hasMinorSettings(src.filteredSchema));\n\n const schemaUnavailableMessage = React.useMemo(() => {\n const firstError = resolvedSourceConfigs.reduce<unknown>(\n (err, src) =>\n err ??\n (src.settingsSource === \"conversation_settings\"\n ? conversationSchemaQuery.error\n : agentSchemaQuery.error),\n null,\n );\n return getSchemaUnavailableMessage(\n firstError,\n t(I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE),\n );\n }, [\n resolvedSourceConfigs,\n agentSchemaQuery.error,\n conversationSchemaQuery.error,\n t,\n ]);\n\n const overridesSignature = React.useMemo(\n () => (initialValueOverrides ? JSON.stringify(initialValueOverrides) : \"\"),\n [initialValueOverrides],\n );\n\n const [view, setView] = React.useState<SettingsView>(\"basic\");\n const [valuesBySource, setValuesBySource] = React.useState<\n Partial<Record<SettingsValueSource, SettingsFormValues>>\n >({});\n const [dirtyBySource, setDirtyBySource] = React.useState<\n Partial<Record<SettingsValueSource, SettingsDirtyState>>\n >({});\n const hasHydratedViewRef = React.useRef(false);\n\n const initialValuesBySource = React.useMemo<Partial<\n Record<SettingsValueSource, SettingsFormValues>\n > | null>(() => {\n if (!settings) return null;\n const result: Partial<Record<SettingsValueSource, SettingsFormValues>> = {};\n for (const src of resolvedSources) {\n if (!src.filteredSchema) return null;\n result[src.settingsSource] = {\n ...(result[src.settingsSource] ?? {}),\n ...buildInitialSettingsFormValues(\n settings,\n src.filteredSchema,\n src.settingsSource,\n ),\n };\n }\n if (initialValueOverrides) {\n const firstSource = resolvedSources[0]?.settingsSource;\n if (firstSource && result[firstSource]) {\n result[firstSource] = {\n ...result[firstSource],\n ...initialValueOverrides,\n };\n }\n }\n return result;\n }, [settings, resolvedSources, overridesSignature]);\n\n const initialView = React.useMemo(() => {\n if (!settings) return null;\n let result: SettingsView | null = null;\n for (const src of resolvedSources) {\n if (!src.filteredSchema) return null;\n const perSource = getInitialView\n ? getInitialView(settings, src.filteredSchema)\n : inferInitialView(settings, src.filteredSchema, src.settingsSource);\n result = result ? getMoreDetailedView(result, perSource) : perSource;\n }\n if (!result) return null;\n return normalizeView(result, { showBasic, showAdvanced, showAll });\n }, [\n settings,\n resolvedSources,\n getInitialView,\n showBasic,\n showAdvanced,\n showAll,\n ]);\n\n React.useEffect(() => {\n hasHydratedViewRef.current = false;\n setView(\"basic\");\n setValuesBySource({});\n setDirtyBySource({});\n }, [scope, sourcesSignature]);\n\n React.useEffect(() => {\n if (!initialValuesBySource || !initialView) return;\n\n setValuesBySource(initialValuesBySource);\n if (initialValueOverrides) {\n const firstSource = resolvedSources[0]?.settingsSource;\n if (firstSource) {\n const overrideDirty: SettingsDirtyState = Object.fromEntries(\n Object.keys(initialValueOverrides).map((key) => [key, true]),\n );\n setDirtyBySource({ [firstSource]: overrideDirty });\n } else {\n setDirtyBySource({});\n }\n } else {\n setDirtyBySource({});\n }\n // The ref flip stays outside the updater: React double-invokes state\n // updaters in StrictMode, so mutating it in there makes the second\n // (kept) call take the already-hydrated branch and pin the view.\n if (!hasHydratedViewRef.current) {\n hasHydratedViewRef.current = true;\n setView(initialView);\n } else {\n setView((currentView) => getLessDetailedView(currentView, initialView));\n }\n }, [initialValuesBySource, initialView]);\n\n const fieldKeyToSource = React.useMemo(() => {\n const map = new Map<string, SettingsValueSource>();\n for (const src of resolvedSources) {\n if (src.filteredSchema) {\n for (const section of src.filteredSchema.sections) {\n for (const field of section.fields) {\n if (!map.has(field.key)) {\n map.set(field.key, src.settingsSource);\n }\n }\n }\n }\n }\n return map;\n }, [resolvedSources]);\n\n const flatValues = React.useMemo<SettingsFormValues>(() => {\n const merged: SettingsFormValues = {};\n for (const src of resolvedSources) {\n Object.assign(merged, valuesBySource[src.settingsSource] ?? {});\n }\n return merged;\n }, [resolvedSources, valuesBySource]);\n\n const flatDirty = React.useMemo<SettingsDirtyState>(() => {\n const merged: SettingsDirtyState = {};\n for (const src of resolvedSources) {\n Object.assign(merged, dirtyBySource[src.settingsSource] ?? {});\n }\n return merged;\n }, [resolvedSources, dirtyBySource]);\n\n const handleFieldChange = React.useCallback(\n (fieldKey: string, nextValue: string | boolean) => {\n const sourceKey = fieldKeyToSource.get(fieldKey);\n if (!sourceKey) return;\n setValuesBySource((prev) => ({\n ...prev,\n [sourceKey]: {\n ...(prev[sourceKey] ?? {}),\n [fieldKey]: nextValue,\n },\n }));\n setDirtyBySource((prev) => ({\n ...prev,\n [sourceKey]: {\n ...(prev[sourceKey] ?? {}),\n [fieldKey]: true,\n },\n }));\n },\n [fieldKeyToSource],\n );\n\n const handleError = React.useCallback(\n (error: AxiosError) => {\n const msg = retrieveAxiosErrorMessage(error);\n displayErrorToast(msg || t(I18nKey.ERROR$GENERIC));\n },\n [t],\n );\n\n const handleSaveRef = React.useRef<() => void>(() => {});\n const stableSave = React.useCallback(() => {\n handleSaveRef.current();\n }, []);\n\n // Stable accessor for the coerced, dirty-only payload. Mirrors the\n // `handleSaveRef` pattern so the exposed function reference stays stable\n // across renders while always reading the latest closure at call time.\n const buildDirtyPayloadRef = React.useRef<() => Record<string, unknown>>(\n () => ({}),\n );\n const stableGetDirtyPayload = React.useCallback(\n () => buildDirtyPayloadRef.current(),\n [],\n );\n\n const handleSave = () => {\n if (isReadOnly) return;\n if (resolvedSources.some((src) => !src.filteredSchema)) return;\n\n let payload: Record<string, unknown>;\n try {\n const defaultPayload: Record<string, unknown> = {};\n for (const src of resolvedSources) {\n const schema = src.filteredSchema!;\n const sourceValues = valuesBySource[src.settingsSource] ?? {};\n const sourceDirty = dirtyBySource[src.settingsSource] ?? {};\n const diff = buildSdkSettingsPayloadForView(\n schema,\n sourceValues,\n sourceDirty,\n view,\n );\n if (Object.keys(diff).length > 0) {\n const diffKey = PAYLOAD_DIFF_KEY[src.settingsSource];\n defaultPayload[diffKey] = {\n ...((defaultPayload[diffKey] as\n | Record<string, unknown>\n | undefined) ?? {}),\n ...diff,\n };\n }\n }\n\n payload = buildPayload\n ? buildPayload(defaultPayload, {\n values: flatValues,\n dirty: flatDirty,\n view,\n })\n : defaultPayload;\n } catch (error) {\n displayErrorToast(\n error instanceof Error ? error.message : t(I18nKey.ERROR$GENERIC),\n );\n return;\n }\n\n if (Object.keys(payload).length === 0) return;\n\n saveSettings(payload, {\n onError: handleError,\n onSuccess: () => {\n if (!suppressSuccessToast) {\n displaySuccessToast(t(I18nKey.SETTINGS$SAVED_WARNING));\n }\n setDirtyBySource({});\n onSaveSuccess?.();\n },\n });\n };\n\n handleSaveRef.current = handleSave;\n // Dirty-only (NOT view-filtered): we must never inject defaults for\n // non-visible fields here, or a custom save flow would reset fields the\n // user never touched. `buildSdkSettingsPayloadForView` is reserved for the\n // built-in full-replace save above. With multiple sources, we merge each\n // source's nested payload at the top level so single-source consumers\n // (e.g. `LlmSettingsLocalView`) keep reading `.llm` etc. unchanged.\n buildDirtyPayloadRef.current = () => {\n const merged: Record<string, unknown> = {};\n for (const src of resolvedSources) {\n if (!src.filteredSchema) continue;\n const sourceValues = valuesBySource[src.settingsSource] ?? {};\n const sourceDirty = dirtyBySource[src.settingsSource] ?? {};\n Object.assign(\n merged,\n buildSdkSettingsPayload(src.filteredSchema, sourceValues, sourceDirty),\n );\n }\n return merged;\n };\n\n const isDirty = Object.keys(flatDirty).length > 0;\n const saveControlIsDirty = isDirty || extraDirty;\n React.useEffect(() => {\n if (!onSaveControlChange) return;\n onSaveControlChange({\n save: stableSave,\n isSaving: isPending,\n isDirty: saveControlIsDirty,\n values: flatValues,\n view,\n getDirtyPayload: stableGetDirtyPayload,\n });\n }, [isPending, saveControlIsDirty, flatValues, view]);\n\n // Keep existing form content visible during background refetches to avoid\n // flashing the full skeleton (notably during onboarding Next transitions).\n const isInitialSettingsLoad = (isLoading || isFetching) && !settings;\n if (isInitialSettingsLoad || isSchemaLoading) {\n return <LlmSettingsInputsSkeleton />;\n }\n\n const hasAnyVisibleSection = resolvedSources.some(\n (src) => src.filteredSchema && src.filteredSchema.sections.length > 0,\n );\n\n if (!hasAnyVisibleSection) {\n return (\n <div\n data-testid=\"sdk-schema-unavailable\"\n className={extensionModuleEmptyStateClassName}\n >\n <p className=\"text-sm text-[var(--oh-muted)]\">\n {schemaUnavailableMessage}\n </p>\n </div>\n );\n }\n\n if (Object.keys(flatValues).length === 0) {\n return <LlmSettingsInputsSkeleton />;\n }\n\n // Scrolling is owned by the settings shell (or onboarding wrapper), not a\n // nested scroll region. Save actions are inline after the last field.\n const bodyClassName = \"flex flex-col gap-8\";\n\n return (\n <div\n data-testid={testId}\n className={\n embedded\n ? \"relative flex min-h-0 w-full flex-1 flex-col\"\n : \"relative w-full min-h-0\"\n }\n >\n <ViewToggle\n view={view}\n setView={setView}\n showBasic={showBasic}\n showAdvanced={showAdvanced}\n showAll={showAll}\n isDisabled={isReadOnly}\n />\n\n <div className={bodyClassName}>\n {header?.({\n values: flatValues,\n isDisabled: isReadOnly,\n view,\n onChange: handleFieldChange,\n })}\n\n {resolvedSources.map((src) => {\n if (!src.filteredSchema) return null;\n const sourceValues = valuesBySource[src.settingsSource] ?? {};\n const visibleSections = getVisibleSettingsSections(\n src.filteredSchema,\n { ...flatValues, ...sourceValues },\n view,\n src.excludeKeys ?? EMPTY_EXCLUDE_KEYS,\n );\n return visibleSections.map((section) => (\n <section\n key={`${src.settingsSource}:${section.key}`}\n className=\"flex flex-col gap-4\"\n >\n <div className=\"grid gap-4 xl:grid-cols-2\">\n {section.fields.map((field) => (\n <div\n key={field.key}\n className={\n FIELD_FULL_WIDTH_KEYS.has(field.key)\n ? \"xl:col-span-2\"\n : undefined\n }\n >\n <SchemaField\n field={field}\n value={sourceValues[field.key]}\n isDisabled={isReadOnly}\n onChange={(nextValue) =>\n handleFieldChange(field.key, nextValue)\n }\n />\n </div>\n ))}\n </div>\n </section>\n ));\n })}\n\n {!isReadOnly && !hideSaveButton ? (\n <div className=\"flex justify-start pt-2\">\n <BrandButton\n testId=\"save-button\"\n type=\"button\"\n variant=\"primary\"\n isDisabled={isPending || (!isDirty && !extraDirty)}\n onClick={handleSave}\n >\n {isPending\n ? t(I18nKey.SETTINGS$SAVING)\n : t(I18nKey.SETTINGS$SAVE_CHANGES)}\n </BrandButton>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sdk-section-page.js","names":[],"sources":["../../../../../src/components/features/settings/sdk-settings/sdk-section-page.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { LlmSettingsInputsSkeleton } from \"#/components/features/settings/llm-settings/llm-settings-inputs-skeleton\";\nimport { useSaveSettings } from \"#/hooks/mutation/use-save-settings\";\nimport {\n useAgentSettingsSchema,\n useConversationSettingsSchema,\n} from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extensionModuleEmptyStateClassName } from \"#/utils/extension-module-card-classes\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport {\n buildInitialSettingsFormValues,\n buildSdkSettingsPayload,\n buildSdkSettingsPayloadForView,\n getVisibleSettingsSections,\n hasAdvancedSettings,\n hasCriticalSettings,\n hasMinorSettings,\n inferInitialView,\n isValidSettingsSchema,\n SettingsDirtyState,\n SettingsFormValues,\n type SettingsValueSource,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { FIELD_FULL_WIDTH_KEYS, SchemaField } from \"./schema-field\";\nimport { ViewToggle } from \"./view-toggle\";\n\nconst EMPTY_EXCLUDE_KEYS = new Set<string>();\n\nconst VIEW_ORDER: Record<SettingsView, number> = {\n basic: 0,\n advanced: 1,\n all: 2,\n};\n\nconst getLessDetailedView = (\n currentView: SettingsView,\n nextView: SettingsView,\n): SettingsView =>\n VIEW_ORDER[nextView] < VIEW_ORDER[currentView] ? nextView : currentView;\n\nconst getMoreDetailedView = (\n currentView: SettingsView,\n nextView: SettingsView,\n): SettingsView =>\n VIEW_ORDER[nextView] > VIEW_ORDER[currentView] ? nextView : currentView;\n\nconst normalizeView = (\n view: SettingsView,\n {\n showBasic,\n showAdvanced,\n showAll,\n }: {\n showBasic: boolean;\n showAdvanced: boolean;\n showAll: boolean;\n },\n): SettingsView => {\n if (view === \"all\") {\n if (showAll) {\n return \"all\";\n }\n\n return showAdvanced ? \"advanced\" : \"basic\";\n }\n\n if (view === \"advanced\") {\n if (showAdvanced) {\n return \"advanced\";\n }\n\n return showAll ? \"all\" : \"basic\";\n }\n\n // A critical-less page has nothing to render in the basic tier; bump up.\n if (!showBasic) {\n if (showAdvanced) return \"advanced\";\n if (showAll) return \"all\";\n }\n return \"basic\";\n};\n\nconst PAYLOAD_DIFF_KEY: Record<SettingsValueSource, string> = {\n agent_settings: \"agent_settings_diff\",\n conversation_settings: \"conversation_settings_diff\",\n};\n\nconst getSchemaUnavailableMessage = (\n error: unknown,\n fallbackMessage: string,\n): string => {\n if (!(error instanceof AxiosError)) {\n return fallbackMessage;\n }\n\n if (error.response?.status === 401) {\n return `${fallbackMessage} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.`;\n }\n\n if (error.response?.status === 404) {\n return `${fallbackMessage} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`;\n }\n\n return fallbackMessage;\n};\n\nexport interface SettingsSourceConfig {\n /** Which schema/values bucket on `settings` this source pulls from. */\n settingsSource: SettingsValueSource;\n /** Section keys (e.g. [\"llm\"]) within that schema to render. */\n sectionKeys: string[];\n /** Field keys to skip (rendered elsewhere by the caller). */\n excludeKeys?: Set<string>;\n}\n\nexport interface SdkSectionHeaderProps {\n values: SettingsFormValues;\n isDisabled: boolean;\n view: SettingsView;\n onChange: (key: string, value: string | boolean) => void;\n}\n\ninterface ResolvedSource extends SettingsSourceConfig {\n filteredSchema: SettingsSchema | null;\n}\n\n/**\n * Snapshot of the page's save state, surfaced to the parent so it can\n * render its own Save/Next button (e.g. in onboarding) when\n * {@link SdkSectionPage}'s built-in button is hidden via\n * `hideSaveButton`.\n */\nexport interface SdkSectionSaveControl {\n /** Trigger a save of the currently-dirty fields. No-op while `isSaving` or `!isDirty`. */\n save: () => void;\n /** A save mutation is in flight. */\n isSaving: boolean;\n /** At least one field is dirty (or `extraDirty` was passed in). */\n isDirty: boolean;\n /** Current form values (for custom save flows). */\n values: SettingsFormValues;\n /** The active view tier (basic/advanced/all) the form is rendering. */\n view: SettingsView;\n /**\n * Returns the coerced, dirty-only payload as a nested object\n * (e.g. `{ llm: { temperature: 0.7 } }`). Lets a custom save flow persist\n * exactly the fields the user changed, with proper types, without\n * re-implementing schema-driven coercion. Throws if a field fails coercion.\n */\n getDirtyPayload: () => Record<string, unknown>;\n}\n\n/**\n * A generic SDK-schema-driven settings page that renders fields from one or\n * more schema sections.\n *\n * The `settingsSources` array specifies which schema(s)/section(s) the page\n * owns. The page tracks values/dirty state per source, renders sections from\n * each source in order (filtered by the schema's `prominence` field for the\n * selected view), and emits a combined save payload like\n * `{ conversation_settings_diff: {...}, agent_settings_diff: {...} }` ---\n * including only the keys for sources that actually have dirty changes.\n *\n * @param settingsSources one or more schemas to render fields from\n * @param header render prop above the fields (receives unified state)\n * @param buildPayload customize the save payload before submission\n * @param testId data-testid on the page wrapper\n */\nexport function SdkSectionPage({\n settingsSources,\n scope = \"personal\",\n header,\n extraDirty = false,\n buildPayload,\n onSaveSuccess,\n getInitialView,\n forceShowAdvancedView = false,\n allowAllView = true,\n initialValueOverrides,\n embedded = false,\n hideSaveButton = false,\n suppressSuccessToast = false,\n onSaveControlChange,\n testId = \"sdk-section-settings-screen\",\n}: {\n settingsSources: SettingsSourceConfig[];\n scope?: SettingsScope;\n\n header?: (props: SdkSectionHeaderProps) => React.ReactNode;\n extraDirty?: boolean;\n /**\n * Customize the save payload. Receives the wrapped default payload (e.g.\n * `{ agent_settings_diff: { llm: { model: \"gpt-4\" } } }`) plus the unified\n * form context. Return the payload to actually send.\n */\n buildPayload?: (\n defaultPayload: Record<string, unknown>,\n context: {\n values: SettingsFormValues;\n dirty: SettingsDirtyState;\n view: SettingsView;\n },\n ) => Record<string, unknown>;\n onSaveSuccess?: () => void;\n getInitialView?: (\n settings: Settings,\n filteredSchema: SettingsSchema,\n ) => SettingsView;\n forceShowAdvancedView?: boolean;\n allowAllView?: boolean;\n /**\n * Per-field initial value overrides that win over the values\n * derived from `useSettings`. The keys of each override are also\n * marked dirty on hydration so the user can save the form without\n * having to touch the prefilled fields. Useful when the page is\n * embedded in a flow that wants to nudge brand-new users toward a\n * particular default (e.g. onboarding pre-filling OpenHands/Opus).\n */\n initialValueOverrides?: SettingsFormValues;\n embedded?: boolean;\n hideSaveButton?: boolean;\n /** Suppress the default success toast after save completes. */\n suppressSuccessToast?: boolean;\n /**\n * Fires whenever the save state changes (a mutation starts/finishes,\n * dirty status flips). Provides a stable `save()` callback the\n * parent can wire to its own button. Useful when the form is\n * embedded in a custom flow and the built-in Save button is hidden.\n */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n testId?: string;\n}) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: saveSettings, isPending } = useSaveSettings(scope);\n const { data: settings, isLoading, isFetching } = useSettings(scope);\n const agentSchemaQuery = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n const conversationSchemaQuery = useConversationSettingsSchema(\n settings?.conversation_settings_schema,\n );\n const isReadOnly = false;\n\n const sourcesSignature = React.useMemo(\n () =>\n JSON.stringify(\n settingsSources.map((s) => ({\n source: s.settingsSource,\n sectionKeys: s.sectionKeys,\n excludeKeys: s.excludeKeys ? Array.from(s.excludeKeys).sort() : null,\n })),\n ),\n [settingsSources],\n );\n\n const resolvedSourceConfigs = React.useMemo<SettingsSourceConfig[]>(() => {\n const parsed = JSON.parse(sourcesSignature) as Array<{\n source: SettingsValueSource;\n sectionKeys: string[];\n excludeKeys: string[] | null;\n }>;\n return parsed.map((p) => ({\n settingsSource: p.source,\n sectionKeys: p.sectionKeys,\n excludeKeys: p.excludeKeys ? new Set(p.excludeKeys) : undefined,\n }));\n }, [sourcesSignature]);\n\n const getSchemaForSource = React.useCallback(\n (source: SettingsValueSource) =>\n source === \"conversation_settings\"\n ? conversationSchemaQuery.data\n : agentSchemaQuery.data,\n [agentSchemaQuery.data, conversationSchemaQuery.data],\n );\n\n const isSchemaLoading = resolvedSourceConfigs.some((src) =>\n src.settingsSource === \"conversation_settings\"\n ? conversationSchemaQuery.isLoading\n : agentSchemaQuery.isLoading,\n );\n\n const resolvedSources = React.useMemo<ResolvedSource[]>(\n () =>\n resolvedSourceConfigs.map((src) => {\n const schema = getSchemaForSource(src.settingsSource);\n if (!isValidSettingsSchema(schema)) {\n return { ...src, filteredSchema: null };\n }\n const sectionSet = new Set(src.sectionKeys);\n // The agent schema can carry more than one section per key — e.g. the\n // combined AgentSettings schema emits an \"llm\" section for both the\n // \"openhands\" and \"acp\" variants. Only the first (openhands) is used,\n // so keep the first section per key; otherwise every field renders\n // twice and React sees duplicate section keys.\n const seenKeys = new Set<string>();\n const filteredSchema: SettingsSchema = {\n ...schema,\n sections: schema.sections.filter((s) => {\n if (!sectionSet.has(s.key) || seenKeys.has(s.key)) return false;\n seenKeys.add(s.key);\n return true;\n }),\n };\n return { ...src, filteredSchema };\n }),\n [resolvedSourceConfigs, getSchemaForSource],\n );\n\n // The basic tier only exists when some field renders in it; a critical-less\n // page (e.g. Memory, whose only field is major) hides the Basic tab and\n // floors its view at \"advanced\".\n const showBasic = resolvedSources.some((src) =>\n hasCriticalSettings(src.filteredSchema),\n );\n const showAdvanced =\n forceShowAdvancedView ||\n resolvedSources.some((src) => hasAdvancedSettings(src.filteredSchema));\n const showAll =\n allowAllView &&\n resolvedSources.some((src) => hasMinorSettings(src.filteredSchema));\n\n const schemaUnavailableMessage = React.useMemo(() => {\n const firstError = resolvedSourceConfigs.reduce<unknown>(\n (err, src) =>\n err ??\n (src.settingsSource === \"conversation_settings\"\n ? conversationSchemaQuery.error\n : agentSchemaQuery.error),\n null,\n );\n return getSchemaUnavailableMessage(\n firstError,\n t(I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE),\n );\n }, [\n resolvedSourceConfigs,\n agentSchemaQuery.error,\n conversationSchemaQuery.error,\n t,\n ]);\n\n const overridesSignature = React.useMemo(\n () => (initialValueOverrides ? JSON.stringify(initialValueOverrides) : \"\"),\n [initialValueOverrides],\n );\n\n const [view, setView] = React.useState<SettingsView>(\"basic\");\n const [valuesBySource, setValuesBySource] = React.useState<\n Partial<Record<SettingsValueSource, SettingsFormValues>>\n >({});\n const [dirtyBySource, setDirtyBySource] = React.useState<\n Partial<Record<SettingsValueSource, SettingsDirtyState>>\n >({});\n const hasHydratedViewRef = React.useRef(false);\n\n const initialValuesBySource = React.useMemo<Partial<\n Record<SettingsValueSource, SettingsFormValues>\n > | null>(() => {\n if (!settings) return null;\n const result: Partial<Record<SettingsValueSource, SettingsFormValues>> = {};\n for (const src of resolvedSources) {\n if (!src.filteredSchema) return null;\n result[src.settingsSource] = {\n ...(result[src.settingsSource] ?? {}),\n ...buildInitialSettingsFormValues(\n settings,\n src.filteredSchema,\n src.settingsSource,\n ),\n };\n }\n if (initialValueOverrides) {\n const firstSource = resolvedSources[0]?.settingsSource;\n if (firstSource && result[firstSource]) {\n result[firstSource] = {\n ...result[firstSource],\n ...initialValueOverrides,\n };\n }\n }\n return result;\n }, [settings, resolvedSources, overridesSignature]);\n\n const initialView = React.useMemo(() => {\n if (!settings) return null;\n let result: SettingsView | null = null;\n for (const src of resolvedSources) {\n if (!src.filteredSchema) return null;\n const perSource = getInitialView\n ? getInitialView(settings, src.filteredSchema)\n : inferInitialView(settings, src.filteredSchema, src.settingsSource);\n result = result ? getMoreDetailedView(result, perSource) : perSource;\n }\n if (!result) return null;\n return normalizeView(result, { showBasic, showAdvanced, showAll });\n }, [\n settings,\n resolvedSources,\n getInitialView,\n showBasic,\n showAdvanced,\n showAll,\n ]);\n\n React.useEffect(() => {\n hasHydratedViewRef.current = false;\n setView(\"basic\");\n setValuesBySource({});\n setDirtyBySource({});\n }, [scope, sourcesSignature]);\n\n React.useEffect(() => {\n if (!initialValuesBySource || !initialView) return;\n\n setValuesBySource(initialValuesBySource);\n if (initialValueOverrides) {\n const firstSource = resolvedSources[0]?.settingsSource;\n if (firstSource) {\n const overrideDirty: SettingsDirtyState = Object.fromEntries(\n Object.keys(initialValueOverrides).map((key) => [key, true]),\n );\n setDirtyBySource({ [firstSource]: overrideDirty });\n } else {\n setDirtyBySource({});\n }\n } else {\n setDirtyBySource({});\n }\n // The ref flip stays outside the updater: React double-invokes state\n // updaters in StrictMode, so mutating it in there makes the second\n // (kept) call take the already-hydrated branch and pin the view.\n if (!hasHydratedViewRef.current) {\n hasHydratedViewRef.current = true;\n setView(initialView);\n } else {\n setView((currentView) => getLessDetailedView(currentView, initialView));\n }\n }, [initialValuesBySource, initialView]);\n\n const fieldKeyToSource = React.useMemo(() => {\n const map = new Map<string, SettingsValueSource>();\n for (const src of resolvedSources) {\n if (src.filteredSchema) {\n for (const section of src.filteredSchema.sections) {\n for (const field of section.fields) {\n if (!map.has(field.key)) {\n map.set(field.key, src.settingsSource);\n }\n }\n }\n }\n }\n return map;\n }, [resolvedSources]);\n\n const flatValues = React.useMemo<SettingsFormValues>(() => {\n const merged: SettingsFormValues = {};\n for (const src of resolvedSources) {\n Object.assign(merged, valuesBySource[src.settingsSource] ?? {});\n }\n return merged;\n }, [resolvedSources, valuesBySource]);\n\n const flatDirty = React.useMemo<SettingsDirtyState>(() => {\n const merged: SettingsDirtyState = {};\n for (const src of resolvedSources) {\n Object.assign(merged, dirtyBySource[src.settingsSource] ?? {});\n }\n return merged;\n }, [resolvedSources, dirtyBySource]);\n\n const handleFieldChange = React.useCallback(\n (fieldKey: string, nextValue: string | boolean) => {\n const sourceKey = fieldKeyToSource.get(fieldKey);\n if (!sourceKey) return;\n setValuesBySource((prev) => ({\n ...prev,\n [sourceKey]: {\n ...(prev[sourceKey] ?? {}),\n [fieldKey]: nextValue,\n },\n }));\n setDirtyBySource((prev) => ({\n ...prev,\n [sourceKey]: {\n ...(prev[sourceKey] ?? {}),\n [fieldKey]: true,\n },\n }));\n },\n [fieldKeyToSource],\n );\n\n const handleError = React.useCallback(\n (error: AxiosError) => {\n const msg = retrieveAxiosErrorMessage(error);\n displayErrorToast(msg || t(I18nKey.ERROR$GENERIC));\n },\n [t],\n );\n\n const handleSaveRef = React.useRef<() => void>(() => {});\n const stableSave = React.useCallback(() => {\n handleSaveRef.current();\n }, []);\n\n // Stable accessor for the coerced, dirty-only payload. Mirrors the\n // `handleSaveRef` pattern so the exposed function reference stays stable\n // across renders while always reading the latest closure at call time.\n const buildDirtyPayloadRef = React.useRef<() => Record<string, unknown>>(\n () => ({}),\n );\n const stableGetDirtyPayload = React.useCallback(\n () => buildDirtyPayloadRef.current(),\n [],\n );\n\n const handleSave = () => {\n if (isReadOnly) return;\n if (resolvedSources.some((src) => !src.filteredSchema)) return;\n\n let payload: Record<string, unknown>;\n try {\n const defaultPayload: Record<string, unknown> = {};\n for (const src of resolvedSources) {\n const schema = src.filteredSchema!;\n const sourceValues = valuesBySource[src.settingsSource] ?? {};\n const sourceDirty = dirtyBySource[src.settingsSource] ?? {};\n const diff = buildSdkSettingsPayloadForView(\n schema,\n sourceValues,\n sourceDirty,\n view,\n );\n if (Object.keys(diff).length > 0) {\n const diffKey = PAYLOAD_DIFF_KEY[src.settingsSource];\n defaultPayload[diffKey] = {\n ...((defaultPayload[diffKey] as\n | Record<string, unknown>\n | undefined) ?? {}),\n ...diff,\n };\n }\n }\n\n payload = buildPayload\n ? buildPayload(defaultPayload, {\n values: flatValues,\n dirty: flatDirty,\n view,\n })\n : defaultPayload;\n } catch (error) {\n displayErrorToast(\n error instanceof Error ? error.message : t(I18nKey.ERROR$GENERIC),\n );\n return;\n }\n\n if (Object.keys(payload).length === 0) return;\n\n saveSettings(payload, {\n onError: handleError,\n onSuccess: () => {\n if (!suppressSuccessToast) {\n displaySuccessToast(t(I18nKey.SETTINGS$SAVED_WARNING));\n }\n setDirtyBySource({});\n onSaveSuccess?.();\n },\n });\n };\n\n handleSaveRef.current = handleSave;\n // Dirty-only (NOT view-filtered): we must never inject defaults for\n // non-visible fields here, or a custom save flow would reset fields the\n // user never touched. `buildSdkSettingsPayloadForView` is reserved for the\n // built-in full-replace save above. With multiple sources, we merge each\n // source's nested payload at the top level so single-source consumers\n // (e.g. `LlmSettingsLocalView`) keep reading `.llm` etc. unchanged.\n buildDirtyPayloadRef.current = () => {\n const merged: Record<string, unknown> = {};\n for (const src of resolvedSources) {\n if (!src.filteredSchema) continue;\n const sourceValues = valuesBySource[src.settingsSource] ?? {};\n const sourceDirty = dirtyBySource[src.settingsSource] ?? {};\n Object.assign(\n merged,\n buildSdkSettingsPayload(src.filteredSchema, sourceValues, sourceDirty),\n );\n }\n return merged;\n };\n\n const isDirty = Object.keys(flatDirty).length > 0;\n const saveControlIsDirty = isDirty || extraDirty;\n React.useEffect(() => {\n if (!onSaveControlChange) return;\n onSaveControlChange({\n save: stableSave,\n isSaving: isPending,\n isDirty: saveControlIsDirty,\n values: flatValues,\n view,\n getDirtyPayload: stableGetDirtyPayload,\n });\n }, [isPending, saveControlIsDirty, flatValues, view]);\n\n // Keep existing form content visible during background refetches to avoid\n // flashing the full skeleton (notably during onboarding Next transitions).\n const isInitialSettingsLoad = (isLoading || isFetching) && !settings;\n if (isInitialSettingsLoad || isSchemaLoading) {\n return <LlmSettingsInputsSkeleton />;\n }\n\n const hasAnyVisibleSection = resolvedSources.some(\n (src) => src.filteredSchema && src.filteredSchema.sections.length > 0,\n );\n\n if (!hasAnyVisibleSection) {\n return (\n <div\n data-testid=\"sdk-schema-unavailable\"\n className={extensionModuleEmptyStateClassName}\n >\n <p className=\"text-sm text-[var(--oh-muted)]\">\n {schemaUnavailableMessage}\n </p>\n </div>\n );\n }\n\n if (Object.keys(flatValues).length === 0) {\n return <LlmSettingsInputsSkeleton />;\n }\n\n // Scrolling is owned by the settings shell (or onboarding wrapper), not a\n // nested scroll region. Save actions are inline after the last field.\n const bodyClassName = \"flex flex-col gap-8\";\n\n return (\n <div\n data-testid={testId}\n className={\n embedded\n ? \"relative flex min-h-0 w-full flex-1 flex-col\"\n : \"relative w-full min-h-0\"\n }\n >\n <ViewToggle\n view={view}\n setView={setView}\n showBasic={showBasic}\n showAdvanced={showAdvanced}\n showAll={showAll}\n isDisabled={isReadOnly}\n />\n\n <div className={bodyClassName}>\n {header?.({\n values: flatValues,\n isDisabled: isReadOnly,\n view,\n onChange: handleFieldChange,\n })}\n\n {resolvedSources.map((src) => {\n if (!src.filteredSchema) return null;\n const sourceValues = valuesBySource[src.settingsSource] ?? {};\n const visibleSections = getVisibleSettingsSections(\n src.filteredSchema,\n { ...flatValues, ...sourceValues },\n view,\n src.excludeKeys ?? EMPTY_EXCLUDE_KEYS,\n );\n return visibleSections.map((section) => (\n <section\n key={`${src.settingsSource}:${section.key}`}\n className=\"flex flex-col gap-4\"\n >\n <div className=\"grid gap-4 xl:grid-cols-2\">\n {section.fields.map((field) => (\n <div\n key={field.key}\n className={\n FIELD_FULL_WIDTH_KEYS.has(field.key)\n ? \"xl:col-span-2\"\n : undefined\n }\n >\n <SchemaField\n field={field}\n value={sourceValues[field.key]}\n isDisabled={isReadOnly}\n onChange={(nextValue) =>\n handleFieldChange(field.key, nextValue)\n }\n />\n </div>\n ))}\n </div>\n </section>\n ));\n })}\n\n {!isReadOnly && !hideSaveButton ? (\n <div className=\"flex justify-start pt-2\">\n <BrandButton\n testId=\"save-button\"\n type=\"button\"\n variant=\"primary\"\n isDisabled={isPending || (!isDirty && !extraDirty)}\n onClick={handleSave}\n >\n {isPending\n ? t(I18nKey.SETTINGS$SAVING)\n : t(I18nKey.SETTINGS$SAVE_CHANGES)}\n </BrandButton>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../utils/utils.cjs"),n=require("../../../context/navigation-context.cjs"),r=require("../../shared/buttons/styled-tooltip.cjs"),i=require("../../shared/navigation-link.cjs"),a=require("./sidebar-layout.cjs"),o=require("./sidebar-collapsed-icon-slot.cjs");let s=require("react");s=e.__toESM(s,1);let c=require("react/jsx-runtime");function l(e,t,n){return t===`/`||n?e===t:e===t||e.startsWith(`${t}/`)}function u({to:e,label:s,end:u=!1,indent:d=!1,testId:f,disabled:p=!1,icon:m,collapsed:h=!1,hoverContent:g,forceActive:_=!1}){let{currentPath:v}=n.useNavigation(),y=_||l(v,e,u),b=(0,c.jsxs)(i.NavigationLink,{to:e,end:u,"data-testid":f,tabIndex:p?-1:0,"aria-label":h?s:void 0,"aria-disabled":p||void 0,onClick:e=>{p&&e.preventDefault()},className:t.cn(a.sidebarNavRowClassName({indent:d,collapsed:h}),!h&&(y?a.SIDEBAR_ROW_INTERACTIVE_CLASS.active:a.SIDEBAR_ROW_INTERACTIVE_CLASS.idle),p&&`opacity-50`,p&&`pointer-events-none`),children:[m?h?(0,c.jsx)(o.SidebarCollapsedIconSlot,{active:y,children:m}):(0,c.jsx)(`span`,{className:a.SIDEBAR_ICON_SLOT_CLASS,children:m}):null,(0,c.jsx)(`span`,{className:a.sidebarNavLabelClassName(h),children:s})]});return h?(0,c.jsx)(r.StyledTooltip,{content:g??s,placement:`right`,tooltipClassName:g?`p-0 bg-tertiary text-white`:void 0,children:b}):b}exports.SidebarNavLink=u;
1
+ const e=require("../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../node_modules/lucide-react/dist/esm/icons/pin.cjs"),n=require("../../../utils/utils.cjs"),r=require("../../../context/navigation-context.cjs"),i=require("../../shared/buttons/styled-tooltip.cjs"),a=require("../../shared/navigation-link.cjs"),o=require("../../../utils/hover-reveal-classes.cjs"),s=require("./sidebar-layout.cjs"),c=require("./sidebar-collapsed-icon-slot.cjs");let l=require("react");l=e.__toESM(l,1);let u=require("react/jsx-runtime");function d(e,t,n){return t===`/`||n?e===t:e===t||e.startsWith(`${t}/`)}function f({to:e,label:l,end:f=!1,indent:p=!1,testId:m,disabled:h=!1,icon:g,collapsed:_=!1,hoverContent:v,forceActive:y=!1,pinAction:b}){let{currentPath:x}=r.useNavigation(),S=y||d(x,e,f),C=!_&&b!=null,w=(0,u.jsxs)(a.NavigationLink,{to:e,end:f,"data-testid":m,tabIndex:h?-1:0,"aria-label":_?l:void 0,"aria-disabled":h||void 0,onClick:e=>{h&&e.preventDefault()},className:n.cn(s.sidebarNavRowClassName({indent:p,collapsed:_}),!_&&(S?s.SIDEBAR_ROW_INTERACTIVE_CLASS.active:s.SIDEBAR_ROW_INTERACTIVE_CLASS.idle),h&&`opacity-50`,h&&`pointer-events-none`,C&&`pr-9`),children:[g?_?(0,u.jsx)(c.SidebarCollapsedIconSlot,{active:S,children:g}):(0,u.jsx)(`span`,{className:s.SIDEBAR_ICON_SLOT_CLASS,children:g}):null,(0,u.jsx)(`span`,{className:s.sidebarNavLabelClassName(_),children:l})]});return _?(0,u.jsx)(i.StyledTooltip,{content:v??l,placement:`right`,tooltipClassName:v?`p-0 bg-tertiary text-white`:void 0,children:w}):b?(0,u.jsxs)(`div`,{className:`group relative`,children:[w,(0,u.jsx)(`button`,{type:`button`,"data-testid":b.testId,"aria-pressed":b.pinned,"aria-label":b.label,onClick:e=>{e.preventDefault(),e.stopPropagation(),b.onToggle()},className:n.cn(`absolute right-1.5 top-1/2 -translate-y-1/2`,`flex shrink-0 cursor-pointer items-center justify-center rounded-md p-1`,`text-[var(--oh-muted)] hover:bg-white/10 hover:text-white`,o.hoverRevealActionClassName(b.pinned)),children:(0,u.jsx)(t.Pin,{className:n.cn(`h-3.5 w-3.5`,b.pinned&&`fill-current`),"aria-hidden":!0})})]}):w}exports.SidebarNavLink=f;
2
2
  //# sourceMappingURL=sidebar-nav-link.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-nav-link.cjs","names":[],"sources":["../../../../src/components/features/sidebar/sidebar-nav-link.tsx"],"sourcesContent":["import React from \"react\";\nimport { NavigationLink } from \"#/components/shared/navigation-link\";\nimport { StyledTooltip } from \"#/components/shared/buttons/styled-tooltip\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { cn } from \"#/utils/utils\";\nimport { SidebarCollapsedIconSlot } from \"./sidebar-collapsed-icon-slot\";\nimport {\n SIDEBAR_ICON_SLOT_CLASS,\n SIDEBAR_ROW_INTERACTIVE_CLASS,\n sidebarNavLabelClassName,\n sidebarNavRowClassName,\n} from \"./sidebar-layout\";\n\nfunction isPathActive(currentPath: string, to: string, end: boolean) {\n if (to === \"/\") {\n return currentPath === to;\n }\n\n if (end) {\n return currentPath === to;\n }\n\n return currentPath === to || currentPath.startsWith(`${to}/`);\n}\n\ninterface SidebarNavLinkProps {\n to: string;\n label: string;\n end?: boolean;\n indent?: boolean;\n testId?: string;\n disabled?: boolean;\n icon?: React.ReactElement;\n collapsed?: boolean;\n hoverContent?: React.ReactNode;\n /**\n * When true, forces the active style regardless of the current path.\n * Useful for links that should appear active for multiple related routes\n * (e.g. the Extensions link being active on /mcp and /plugins too).\n */\n forceActive?: boolean;\n}\n\nexport function SidebarNavLink({\n to,\n label,\n end = false,\n indent = false,\n testId,\n disabled = false,\n icon,\n collapsed = false,\n hoverContent,\n forceActive = false,\n}: SidebarNavLinkProps) {\n const { currentPath } = useNavigation();\n const active = forceActive || isPathActive(currentPath, to, end);\n\n const link = (\n <NavigationLink\n to={to}\n end={end}\n data-testid={testId}\n tabIndex={disabled ? -1 : 0}\n aria-label={collapsed ? label : undefined}\n // Announce the disabled state to assistive tech. The visual disabled\n // styling plus tabIndex=-1 + preventDefault gives sighted/keyboard users\n // the right behaviour already; this closes the screen-reader gap so the\n // link doesn't sound \"actionable.\"\n aria-disabled={disabled || undefined}\n onClick={(e) => {\n if (disabled) {\n e.preventDefault();\n }\n }}\n className={cn(\n sidebarNavRowClassName({ indent, collapsed }),\n !collapsed &&\n (active\n ? SIDEBAR_ROW_INTERACTIVE_CLASS.active\n : SIDEBAR_ROW_INTERACTIVE_CLASS.idle),\n disabled && \"opacity-50\",\n disabled && \"pointer-events-none\",\n )}\n >\n {icon ? (\n collapsed ? (\n <SidebarCollapsedIconSlot active={active}>\n {icon}\n </SidebarCollapsedIconSlot>\n ) : (\n <span className={SIDEBAR_ICON_SLOT_CLASS}>{icon}</span>\n )\n ) : null}\n <span className={sidebarNavLabelClassName(collapsed)}>{label}</span>\n </NavigationLink>\n );\n\n if (!collapsed) return link;\n\n return (\n <StyledTooltip\n content={hoverContent ?? label}\n placement=\"right\"\n tooltipClassName={hoverContent ? \"p-0 bg-tertiary text-white\" : undefined}\n >\n {link}\n </StyledTooltip>\n );\n}\n"],"mappings":"qZAaA,SAAS,EAAa,EAAqB,EAAY,EAAc,CASnE,OARI,IAAO,KAIP,EACK,IAAgB,EAGlB,IAAgB,GAAM,EAAY,WAAW,GAAG,EAAG,EAAE,CAC9D,CAoBA,SAAgB,EAAe,CAC7B,KACA,QACA,MAAM,GACN,SAAS,GACT,SACA,WAAW,GACX,OACA,YAAY,GACZ,eACA,cAAc,IACQ,CACtB,GAAM,CAAE,eAAgB,EAAA,cAAc,EAChC,EAAS,GAAe,EAAa,EAAa,EAAI,CAAG,EAEzD,GACJ,EAAA,EAAA,MAAC,EAAA,eAAD,CACM,KACC,MACL,cAAa,EACb,SAAU,EAAW,GAAK,EAC1B,aAAY,EAAY,EAAQ,IAAA,GAKhC,gBAAe,GAAY,IAAA,GAC3B,QAAU,GAAM,CACV,GACF,EAAE,eAAe,CAErB,EACA,UAAW,EAAA,GACT,EAAA,uBAAuB,CAAE,SAAQ,WAAU,CAAC,EAC5C,CAAC,IACE,EACG,EAAA,8BAA8B,OAC9B,EAAA,8BAA8B,MACpC,GAAY,aACZ,GAAY,qBACd,WAxBF,CA0BG,EACC,GACE,EAAA,EAAA,KAAC,EAAA,yBAAD,CAAkC,kBAC/B,CACuB,CAAA,GAE1B,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAA,iCAA0B,CAAW,CAAA,EAEtD,MACJ,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAA,yBAAyB,CAAS,WAAI,CAAY,CAAA,CACrD,IAKlB,OAFK,GAGH,EAAA,EAAA,KAAC,EAAA,cAAD,CACE,QAAS,GAAgB,EACzB,UAAU,QACV,iBAAkB,EAAe,6BAA+B,IAAA,YAE/D,CACY,CAAA,EATM,CAWzB"}
1
+ {"version":3,"file":"sidebar-nav-link.cjs","names":[],"sources":["../../../../src/components/features/sidebar/sidebar-nav-link.tsx"],"sourcesContent":["import React from \"react\";\nimport { Pin } from \"lucide-react\";\nimport { NavigationLink } from \"#/components/shared/navigation-link\";\nimport { StyledTooltip } from \"#/components/shared/buttons/styled-tooltip\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { hoverRevealActionClassName } from \"#/utils/hover-reveal-classes\";\nimport { cn } from \"#/utils/utils\";\nimport { SidebarCollapsedIconSlot } from \"./sidebar-collapsed-icon-slot\";\nimport {\n SIDEBAR_ICON_SLOT_CLASS,\n SIDEBAR_ROW_INTERACTIVE_CLASS,\n sidebarNavLabelClassName,\n sidebarNavRowClassName,\n} from \"./sidebar-layout\";\n\nfunction isPathActive(currentPath: string, to: string, end: boolean) {\n if (to === \"/\") {\n return currentPath === to;\n }\n\n if (end) {\n return currentPath === to;\n }\n\n return currentPath === to || currentPath.startsWith(`${to}/`);\n}\n\nexport interface SidebarNavLinkPinAction {\n pinned: boolean;\n onToggle: () => void;\n /** Localized aria-label; pin vs unpin variants resolved by the caller. */\n label: string;\n testId: string;\n}\n\ninterface SidebarNavLinkProps {\n to: string;\n label: string;\n end?: boolean;\n indent?: boolean;\n testId?: string;\n disabled?: boolean;\n icon?: React.ReactElement;\n collapsed?: boolean;\n hoverContent?: React.ReactNode;\n /**\n * When true, forces the active style regardless of the current path.\n * Useful for links that should appear active for multiple related routes\n * (e.g. the Extensions link being active on /mcp and /plugins too).\n */\n forceActive?: boolean;\n /** Pin-as-home toggle; rendered only when the sidebar is expanded. */\n pinAction?: SidebarNavLinkPinAction;\n}\n\nexport function SidebarNavLink({\n to,\n label,\n end = false,\n indent = false,\n testId,\n disabled = false,\n icon,\n collapsed = false,\n hoverContent,\n forceActive = false,\n pinAction,\n}: SidebarNavLinkProps) {\n const { currentPath } = useNavigation();\n const active = forceActive || isPathActive(currentPath, to, end);\n const showPinAction = !collapsed && pinAction != null;\n\n const link = (\n <NavigationLink\n to={to}\n end={end}\n data-testid={testId}\n tabIndex={disabled ? -1 : 0}\n aria-label={collapsed ? label : undefined}\n // Announce the disabled state to assistive tech. The visual disabled\n // styling plus tabIndex=-1 + preventDefault gives sighted/keyboard users\n // the right behaviour already; this closes the screen-reader gap so the\n // link doesn't sound \"actionable.\"\n aria-disabled={disabled || undefined}\n onClick={(e) => {\n if (disabled) {\n e.preventDefault();\n }\n }}\n className={cn(\n sidebarNavRowClassName({ indent, collapsed }),\n !collapsed &&\n (active\n ? SIDEBAR_ROW_INTERACTIVE_CLASS.active\n : SIDEBAR_ROW_INTERACTIVE_CLASS.idle),\n disabled && \"opacity-50\",\n disabled && \"pointer-events-none\",\n // Constant right reserve so label truncation doesn't reflow on hover.\n showPinAction && \"pr-9\",\n )}\n >\n {icon ? (\n collapsed ? (\n <SidebarCollapsedIconSlot active={active}>\n {icon}\n </SidebarCollapsedIconSlot>\n ) : (\n <span className={SIDEBAR_ICON_SLOT_CLASS}>{icon}</span>\n )\n ) : null}\n <span className={sidebarNavLabelClassName(collapsed)}>{label}</span>\n </NavigationLink>\n );\n\n if (!collapsed) {\n if (!pinAction) return link;\n\n // NavigationLink renders an <a>, so the pin toggle is an absolutely\n // positioned sibling rather than a nested button. Bare `group` is safe\n // here: only collapsed rows use it, and this branch is expanded-only.\n return (\n <div className=\"group relative\">\n {link}\n <button\n type=\"button\"\n data-testid={pinAction.testId}\n aria-pressed={pinAction.pinned}\n aria-label={pinAction.label}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n pinAction.onToggle();\n }}\n className={cn(\n \"absolute right-1.5 top-1/2 -translate-y-1/2\",\n \"flex shrink-0 cursor-pointer items-center justify-center rounded-md p-1\",\n \"text-[var(--oh-muted)] hover:bg-white/10 hover:text-white\",\n hoverRevealActionClassName(pinAction.pinned),\n )}\n >\n <Pin\n className={cn(\"h-3.5 w-3.5\", pinAction.pinned && \"fill-current\")}\n aria-hidden\n />\n </button>\n </div>\n );\n }\n\n return (\n <StyledTooltip\n content={hoverContent ?? label}\n placement=\"right\"\n tooltipClassName={hoverContent ? \"p-0 bg-tertiary text-white\" : undefined}\n >\n {link}\n </StyledTooltip>\n );\n}\n"],"mappings":"ihBAeA,SAAS,EAAa,EAAqB,EAAY,EAAc,CASnE,OARI,IAAO,KAIP,EACK,IAAgB,EAGlB,IAAgB,GAAM,EAAY,WAAW,GAAG,EAAG,EAAE,CAC9D,CA8BA,SAAgB,EAAe,CAC7B,KACA,QACA,MAAM,GACN,SAAS,GACT,SACA,WAAW,GACX,OACA,YAAY,GACZ,eACA,cAAc,GACd,aACsB,CACtB,GAAM,CAAE,eAAgB,EAAA,cAAc,EAChC,EAAS,GAAe,EAAa,EAAa,EAAI,CAAG,EACzD,EAAgB,CAAC,GAAa,GAAa,KAE3C,GACJ,EAAA,EAAA,MAAC,EAAA,eAAD,CACM,KACC,MACL,cAAa,EACb,SAAU,EAAW,GAAK,EAC1B,aAAY,EAAY,EAAQ,IAAA,GAKhC,gBAAe,GAAY,IAAA,GAC3B,QAAU,GAAM,CACV,GACF,EAAE,eAAe,CAErB,EACA,UAAW,EAAA,GACT,EAAA,uBAAuB,CAAE,SAAQ,WAAU,CAAC,EAC5C,CAAC,IACE,EACG,EAAA,8BAA8B,OAC9B,EAAA,8BAA8B,MACpC,GAAY,aACZ,GAAY,sBAEZ,GAAiB,MACnB,WA1BF,CA4BG,EACC,GACE,EAAA,EAAA,KAAC,EAAA,yBAAD,CAAkC,kBAC/B,CACuB,CAAA,GAE1B,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAA,iCAA0B,CAAW,CAAA,EAEtD,MACJ,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAA,yBAAyB,CAAS,WAAI,CAAY,CAAA,CACrD,IAsClB,OAnCK,GAoCH,EAAA,EAAA,KAAC,EAAA,cAAD,CACE,QAAS,GAAgB,EACzB,UAAU,QACV,iBAAkB,EAAe,6BAA+B,IAAA,YAE/D,CACY,CAAA,EAzCV,GAMH,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,CACG,GACD,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,cAAa,EAAU,OACvB,eAAc,EAAU,OACxB,aAAY,EAAU,MACtB,QAAU,GAAU,CAClB,EAAM,eAAe,EACrB,EAAM,gBAAgB,EACtB,EAAU,SAAS,CACrB,EACA,UAAW,EAAA,GACT,8CACA,0EACA,4DACA,EAAA,2BAA2B,EAAU,MAAM,CAC7C,YAEA,EAAA,EAAA,KAAC,EAAA,IAAD,CACE,UAAW,EAAA,GAAG,cAAe,EAAU,QAAU,cAAc,EAC/D,cAAA,EACD,CAAA,CACK,CAAA,CACL,IA9BgB,CA2C3B"}
@@ -1,4 +1,11 @@
1
1
  import React from "react";
2
+ export interface SidebarNavLinkPinAction {
3
+ pinned: boolean;
4
+ onToggle: () => void;
5
+ /** Localized aria-label; pin vs unpin variants resolved by the caller. */
6
+ label: string;
7
+ testId: string;
8
+ }
2
9
  interface SidebarNavLinkProps {
3
10
  to: string;
4
11
  label: string;
@@ -15,6 +22,8 @@ interface SidebarNavLinkProps {
15
22
  * (e.g. the Extensions link being active on /mcp and /plugins too).
16
23
  */
17
24
  forceActive?: boolean;
25
+ /** Pin-as-home toggle; rendered only when the sidebar is expanded. */
26
+ pinAction?: SidebarNavLinkPinAction;
18
27
  }
19
- export declare function SidebarNavLink({ to, label, end, indent, testId, disabled, icon, collapsed, hoverContent, forceActive, }: SidebarNavLinkProps): React.JSX.Element;
28
+ export declare function SidebarNavLink({ to, label, end, indent, testId, disabled, icon, collapsed, hoverContent, forceActive, pinAction, }: SidebarNavLinkProps): React.JSX.Element;
20
29
  export {};