@openhands/agent-canvas 1.3.0 → 1.5.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 (674) hide show
  1. package/README.md +11 -12
  2. package/README.windows.md +4 -2
  3. package/build/assets/{Trans-DY6toRDu.js → Trans-DqF_OEZB.js} +1 -1
  4. package/build/assets/{acp-providers-Djl6vNn-.js → acp-providers-BQwoUBpe.js} +1 -1
  5. package/build/assets/active-backend-context-BCXRv5pm.js +1 -0
  6. package/build/assets/{add-backend-modal-DljoP9lc.js → add-backend-modal-BKHzq5no.js} +1 -1
  7. package/build/assets/{agent-profiles-settings-BJMmTZgv.js → agent-profiles-settings-CEp5CIz8.js} +1 -1
  8. package/build/assets/agent-server-compatibility-D6DSanlx.js +1 -0
  9. package/build/assets/agent-server-conversation-service.api-cylugfDz.js +41 -0
  10. package/build/assets/{agent-settings-lUknCeaF.js → agent-settings-C-tann3x.js} +2 -2
  11. package/build/assets/agent-settings-DGUKNSnU.js +1 -0
  12. package/build/assets/{alert-banner-Bpf2NQJq.js → alert-banner-Dd4woGbm.js} +1 -1
  13. package/build/assets/api-key-entry-screen-Bll_CkuQ.js +1 -0
  14. package/build/assets/app-settings-BpViWwpC.js +1 -0
  15. package/build/assets/automation-detail-Z9dN2f5l.js +2 -0
  16. package/build/assets/automation-export-D5uL0Tf8.js +2 -0
  17. package/build/assets/automations-list-BMOWcqzZ.js +1 -0
  18. package/build/assets/{back-nav-button-CUS2mi-U.js → back-nav-button-ZUDTMOTB.js} +1 -1
  19. package/build/assets/backend-form-modal-DhBT8P4g.js +1 -0
  20. package/build/assets/{backend-synced-settings-badge-CanzmG12.js → backend-synced-settings-badge-Db_REKVw.js} +1 -1
  21. package/build/assets/{base-modal-BuF2f0YL.js → base-modal-Cb0C6m0Q.js} +1 -1
  22. package/build/assets/{bot-D7eUAuSB.js → bot-C-EA6685.js} +1 -1
  23. package/build/assets/{brand-button-vMVuyDXu.js → brand-button-2Tp3aXk1.js} +1 -1
  24. package/build/assets/{browser-BifzWIBd.js → browser-QYLVr1kS.js} +2 -2
  25. package/build/assets/browser-store-BGXOGo-R.js +1 -0
  26. package/build/assets/{browser-tab-CkkqJnqw.js → browser-tab-BTTP1OE2.js} +1 -1
  27. package/build/assets/canvas-ui-BhxjoA1f.js +1 -0
  28. package/build/assets/{chat-send-button-B_jc5z5C.js → chat-send-button-BZHG2hAW.js} +1 -1
  29. package/build/assets/check-TbOEtHKj.js +1 -0
  30. package/build/assets/{chevron-down-CI8A6tet.js → chevron-down-D7IvFMBM.js} +1 -1
  31. package/build/assets/{circle-plus-check-toggle-C5YxjxvI.js → circle-plus-check-toggle-QQJKUnF6.js} +1 -1
  32. package/build/assets/client-source-Biqarhgr.js +1 -0
  33. package/build/assets/cloud-funnel-analytics-D-27T5Ao.js +1 -0
  34. package/build/assets/{combobox-caret-DoObzqf4.js → combobox-caret-A5jMVHgE.js} +1 -1
  35. package/build/assets/{command-menu-D-JV3Wqm.js → command-menu-BMVEme4H.js} +1 -1
  36. package/build/assets/{command-store-D8J5LMW1.js → command-store-jrWX_CcW.js} +1 -1
  37. package/build/assets/condenser-settings-CIa6eyB4.js +1 -0
  38. package/build/assets/{confirmation-modal-BGLu6XJN.js → confirmation-modal-4n_944zq.js} +1 -1
  39. package/build/assets/{context-menu-list-item-BD5_EaKN.js → context-menu-list-item-DvfFic5I.js} +1 -1
  40. package/build/assets/conversation-CHnEXGRM.js +1 -0
  41. package/build/assets/conversation-D4o4dG2t.js +89 -0
  42. package/build/assets/conversation-panel-11FjLCId.js +1 -0
  43. package/build/assets/conversation-service.api-0JG_fF9d.js +1 -0
  44. package/build/assets/conversation-state-store-JiUQp02U.js +1 -0
  45. package/build/assets/{conversation-store-LptbOvKa.js → conversation-store-BCSpLuEf.js} +1 -1
  46. package/build/assets/{conversation-tab-empty-state-B2dDYEwf.js → conversation-tab-empty-state-BUhKVwoi.js} +1 -1
  47. package/build/assets/{copy-3JCw_XFB.js → copy-D1YGjP-C.js} +1 -1
  48. package/build/assets/{copy-to-clipboard-button-CaR52OnA.js → copy-to-clipboard-button-Dp4Q_hXi.js} +1 -1
  49. package/build/assets/declaration-BGsHjPEW.js +1 -0
  50. package/build/assets/{device-verify-BsznkV-a.js → device-verify-CM086oKs.js} +1 -1
  51. package/build/assets/{dropdown-classes-DJSXeLqc.js → dropdown-classes-DZq0BQjb.js} +1 -1
  52. package/build/assets/{ellipsis-button-C5Z-tPFp.js → ellipsis-button-TPJdyxnK.js} +1 -1
  53. package/build/assets/{entry.client-JixNvFrr.js → entry.client-DypYHsYm.js} +2 -2
  54. package/build/assets/{enum-filter-dropdown-DXbVwiNZ.js → enum-filter-dropdown-CW_mBg0e.js} +1 -1
  55. package/build/assets/{environment-switch-overlay-DZQfRGTx.js → environment-switch-overlay-6laJch-9.js} +1 -1
  56. package/build/assets/{extensions-hub-DfvgqzTc.js → extensions-hub-BJFbFfKS.js} +1 -1
  57. package/build/assets/{extensions-navigation-D9i0DL62.js → extensions-navigation-DqSl7CJw.js} +1 -1
  58. package/build/assets/{external-link-D2zJjE9G.js → external-link-lhdITPqq.js} +1 -1
  59. package/build/assets/files-tab-c316dKAq.js +1 -0
  60. package/build/assets/{files-tab-store-DJsPxYdg.js → files-tab-store-tfCav6bB.js} +1 -1
  61. package/build/assets/{form-control-classes-ChpNBe9n.js → form-control-classes-CvUaw8_L.js} +1 -1
  62. package/build/assets/format-time-delta-DhDbkD7V.js +1 -0
  63. package/build/assets/git-provider-icon-DUb2pEos.js +1 -0
  64. package/build/assets/home-BQ-DC06B.js +1 -0
  65. package/build/assets/home-D7ds4Jyw.js +1 -0
  66. package/build/assets/index-home-BRFDWs_4.js +1 -0
  67. package/build/assets/install-server-modal-CvHvzZj3.js +1 -0
  68. package/build/assets/{launch-BgIlZLSX.js → launch-A47TK2Me.js} +1 -1
  69. package/build/assets/lesson-plan-DSf95kQ2.js +4 -0
  70. package/build/assets/{list-todo-BfH6yYUK.js → list-todo-CAtvkzcy.js} +1 -1
  71. package/build/assets/llm-not-configured-banner-B7DR8SPs.js +27 -0
  72. package/build/assets/llm-settings-Ch4ZbW3c.js +1 -0
  73. package/build/assets/llm-settings-Cvi7q4ox.js +1 -0
  74. package/build/assets/llm-subscription-service-Cz1yBBvE.js +1 -0
  75. package/build/assets/loader-circle-CsAsfLIs.js +1 -0
  76. package/build/assets/{loading-spinner-BLdswi6q.js → loading-spinner-Txxx1I1p.js} +1 -1
  77. package/build/assets/manage-backends-modal-DAVhNUCe.js +1 -0
  78. package/build/assets/manifest-958c741a.js +1 -0
  79. package/build/assets/{markdown-renderer-DMT7Zkpd.js → markdown-renderer-B6cJJ_MN.js} +1 -1
  80. package/build/assets/{mcp-CHkklDMv.js → mcp-BwssgMpg.js} +2 -2
  81. package/build/assets/{messages-B3RugH7P.js → messages-D8MeG2ZQ.js} +26 -26
  82. package/build/assets/{modal-body-DouOE5KH.js → modal-body-CDZdZ-eT.js} +1 -1
  83. package/build/assets/{modal-classes-Cf-4tbHz.js → modal-classes-B4oit_4c.js} +1 -1
  84. package/build/assets/{modal-close-button-B6CfxxJj.js → modal-close-button-DQElFMPo.js} +1 -1
  85. package/build/assets/model-selector-BxTbbKub.js +1 -0
  86. package/build/assets/{navigation-link-D8hfwvxI.js → navigation-link-imH6S7h2.js} +1 -1
  87. package/build/assets/onboarding-CyicadGt.js +1 -0
  88. package/build/assets/onboarding-modal-DQwihcTz.js +1 -0
  89. package/build/assets/option-service.api-DAkg_F7p.js +1 -0
  90. package/build/assets/organization-service.api-QknzKDh3.js +1 -0
  91. package/build/assets/package-Dk_VtWJ4.js +1 -0
  92. package/build/assets/path-utils-BECGet7G.js +1 -0
  93. package/build/assets/{pencil-Dj2XjKmI.js → pencil-CWhApFIT.js} +1 -1
  94. package/build/assets/{plan-components-CcCBmCzW.js → plan-components-CgPHWz3E.js} +1 -1
  95. package/build/assets/{planner-tab-CCqdXxkL.js → planner-tab-DPKHmMAX.js} +1 -1
  96. package/build/assets/plugins-management-service-DuTTxquo.js +1 -0
  97. package/build/assets/profiles-service.api-D6jvZOWu.js +1 -0
  98. package/build/assets/providers-B8pxQK8x.js +1 -0
  99. package/build/assets/proxy-CuhhyjdX.js +1 -0
  100. package/build/assets/{recommended-automations-launcher-CVEF_1pc.js → recommended-automations-launcher-DA6DWS7V.js} +1 -1
  101. package/build/assets/{refresh-cw-DM82EIyx.js → refresh-cw-B9B7-vsy.js} +1 -1
  102. package/build/assets/root-BhP6bTBB.js +2 -0
  103. package/build/assets/root-CYWeTrWE.css +1 -0
  104. package/build/assets/root-layout-oBaHHW4s.js +2 -0
  105. package/build/assets/{runtime-waiting-state-BsXLElvN.js → runtime-waiting-state-DeD9G7yJ.js} +1 -1
  106. package/build/assets/schema-field-BOLdL_U7.js +1 -0
  107. package/build/assets/sdk-section-page-ZIltERxf.js +1 -0
  108. package/build/assets/{sdk-settings-schema-Cv7M9eSe.js → sdk-settings-schema-Ba_Pa9uf.js} +1 -1
  109. package/build/assets/search-dIQ09UY2.js +1 -0
  110. package/build/assets/secrets-service-50DElFny.js +1 -0
  111. package/build/assets/{secrets-settings-DxTx9HgU.js → secrets-settings-Digl7JLe.js} +1 -1
  112. package/build/assets/{segmented-toggle-DyQqPhoD.js → segmented-toggle-C1-ZVyr5.js} +1 -1
  113. package/build/assets/settings-BfgLHsgd.js +1 -0
  114. package/build/assets/{settings-dropdown-input-BjunGXJb.js → settings-dropdown-input-BD5C9fBn.js} +1 -1
  115. package/build/assets/{settings-index-BjeuYFFa.js → settings-index-CODBijya.js} +1 -1
  116. package/build/assets/{settings-input-bD6npsDm.js → settings-input-CzNOq-Pj.js} +1 -1
  117. package/build/assets/{settings-list-classes-Dp_OgzN0.js → settings-list-classes-CuxH9ZoR.js} +1 -1
  118. package/build/assets/settings-modal-BcSWpKI0.js +1 -0
  119. package/build/assets/settings-service.api-Bsu1PvYO.js +1 -0
  120. package/build/assets/{settings-switch-5cuxl8Dc.js → settings-switch-DqmHAfWJ.js} +1 -1
  121. package/build/assets/{settings-utils-BMdG65By.js → settings-utils-B1lBErvV.js} +1 -1
  122. package/build/assets/shared-conversation-CDskdmrb.js +1 -0
  123. package/build/assets/{sidebar-layout-DuzJMMw-.js → sidebar-layout-Cn6eQaEI.js} +1 -1
  124. package/build/assets/{sidebar-mobile-menu-toggle-CMmAYkh8.js → sidebar-mobile-menu-toggle-DmCmZgq1.js} +1 -1
  125. package/build/assets/{sidebar-nav-link-5AlTT5-j.js → sidebar-nav-link-DMc8AIe7.js} +1 -1
  126. package/build/assets/{sidebar-store-CZuE8AH5.js → sidebar-store-DXWSCFpa.js} +1 -1
  127. package/build/assets/{skill-card-pill-row-eTIkE4nz.js → skill-card-pill-row-DOIWjiMF.js} +1 -1
  128. package/build/assets/skills-plugins-DLgINYuY.js +1 -0
  129. package/build/assets/{skills-settings-BYn4-AQQ.js → skills-settings-DPiCWalR.js} +2 -2
  130. package/build/assets/{square-chevron-right-Czw3FFWc.js → square-chevron-right-DE-JN-2Z.js} +1 -1
  131. package/build/assets/{styled-tooltip-CgX2oRaK.js → styled-tooltip-CvsjHuIf.js} +1 -1
  132. package/build/assets/{suspense-X5dBsJzn.js → suspense-DmZ3MSSh.js} +1 -1
  133. package/build/assets/{task-list-tab-0k9PhuqO.js → task-list-tab-CuhcDycu.js} +1 -1
  134. package/build/assets/telemetry-DHiTRl5_.js +2 -0
  135. package/build/assets/{terminal-BsGcSpRS.js → terminal-CVqF-tCD.js} +1 -1
  136. package/build/assets/{toggle-switch-2j5wwR85.js → toggle-switch-CS0ClOy2.js} +1 -1
  137. package/build/assets/{trash-2-Be_7y3Mn.js → trash-2-BU6BlW4i.js} +1 -1
  138. package/build/assets/{typography-D8mHDeNG.js → typography-CQn9wyEX.js} +1 -1
  139. package/build/assets/use-acp-credential-form-LlfZO_DD.js +1 -0
  140. package/build/assets/{use-activate-agent-profile-WaAZYz4E.js → use-activate-agent-profile-DpQjsXM0.js} +1 -1
  141. package/build/assets/{use-active-agent-profile-CYY3vGar.js → use-active-agent-profile-Gw_uJujV.js} +1 -1
  142. package/build/assets/{use-active-conversation-D-r929nx.js → use-active-conversation-B0sttISF.js} +1 -1
  143. package/build/assets/use-agent-profiles-LHZEK0Gg.js +1 -0
  144. package/build/assets/{use-agent-state-DijdVAQ0.js → use-agent-state-C5uA0bRj.js} +1 -1
  145. package/build/assets/use-backends-health-DKt1SmiU.js +1 -0
  146. package/build/assets/{use-can-manage-org-profiles-BEo0peGn.js → use-can-manage-org-profiles-BAtqsbCi.js} +1 -1
  147. package/build/assets/use-cloud-current-user-id-C8m1oBy4.js +1 -0
  148. package/build/assets/use-config-CXy4vD0H.js +1 -0
  149. package/build/assets/use-create-conversation-CWQGNQ9J.js +1 -0
  150. package/build/assets/{use-create-secret-D5O5qdWC.js → use-create-secret-BIrsX3OB.js} +1 -1
  151. package/build/assets/{use-event-store-DjgU4wfO.js → use-event-store-CsD17BKu.js} +1 -1
  152. package/build/assets/{use-handle-plan-click-Mn_SNTCh.js → use-handle-plan-click-DEuO7Byo.js} +1 -1
  153. package/build/assets/use-is-authed-Dvbpiu3B.js +1 -0
  154. package/build/assets/{use-launch-skill-in-chat-BnoDgvAy.js → use-launch-skill-in-chat-CdHOoQGM.js} +1 -1
  155. package/build/assets/use-llm-profiles-DQpQxVOD.js +1 -0
  156. package/build/assets/use-plugins-marketplace-Bkk07W_M.js +1 -0
  157. package/build/assets/use-runtime-is-ready-D4pkGT6E.js +1 -0
  158. package/build/assets/use-save-agent-profile-BxEsjnW0.js +1 -0
  159. package/build/assets/{use-save-settings-D1HoCDbn.js → use-save-settings-ioSUMqbE.js} +1 -1
  160. package/build/assets/use-settings-DNJC4gqu.js +1 -0
  161. package/build/assets/use-settings-nav-items-BUsrDbVR.js +16 -0
  162. package/build/assets/use-skills-BsmKm23M.js +1 -0
  163. package/build/assets/{use-task-list-AVBLbbcR.js → use-task-list-rs7Xbzl8.js} +1 -1
  164. package/build/assets/{use-tracking-2ZwQwpg_.js → use-tracking-poxQHMwR.js} +1 -1
  165. package/build/assets/{use-user-conversation-OAfenBRG.js → use-user-conversation-B337kUKB.js} +1 -1
  166. package/build/assets/{useMutation-DCE9RcgK.js → useMutation-u8UgRgDK.js} +1 -1
  167. package/build/assets/{useMutationState-BUab8Kxr.js → useMutationState-OnAsCLA_.js} +1 -1
  168. package/build/assets/{useQueries-CRzaAqzH.js → useQueries-BpIlT8Mt.js} +1 -1
  169. package/build/assets/{useQuery-CpjHYtZc.js → useQuery-D5pEZbY0.js} +1 -1
  170. package/build/assets/{useTranslation-CDRCKC9-.js → useTranslation-Cbf5AGg_.js} +1 -1
  171. package/build/assets/{utils-D3U3rlqr.js → utils-DB9LsAzA.js} +1 -1
  172. package/build/assets/{vendor~browser-Cvg7jXCP.js → vendor~browser-5Njjw1Cl.js} +1 -1
  173. package/build/assets/{vendor~browser-tab-Di0kh5Zw.js → vendor~browser-tab-Xn94EtUo.js} +1 -1
  174. package/build/assets/{vendor~entry.client-9tWQ_Ugw.js → vendor~entry.client-DDuH4--y.js} +1 -1
  175. package/build/assets/{vendor~entry.client-D6BtSOtn.js → vendor~entry.client-DQGrNspu.js} +1 -1
  176. package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dhilvkxv-BIieS_OD.js +2 -0
  177. package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~iztiaf2o-rqo6vRFz.js +185 -0
  178. package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~nn5zty47-Zl0G1QCy.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~ljq5gbus-B2XD4bi2.js} +1 -1
  179. package/build/assets/{vendor~files-tab-B02k3xvx.js → vendor~files-tab-CiC3-lGh.js} +1 -1
  180. package/build/assets/{vendor~home~conversation-panel~conversation-CYMF9JYB.js → vendor~index-home~home~conversation-panel~conversation-ChmYLVgz.js} +1 -1
  181. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-9UMeuPV6.js → vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-B8XNNEQZ.js} +1 -1
  182. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-d8aETPbZ.js → vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CnJRLn5s.js} +1 -1
  183. package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DWteoTyr.js +2 -0
  184. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-D7EUmQ8Y.js → vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dc5nKwLO.js} +1 -1
  185. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BD0GaRGa.js → vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-tlf6AnDe.js} +1 -1
  186. package/build/assets/{vendor~launch-CHXA9cJu.js → vendor~launch-28DK5Rsl.js} +1 -1
  187. package/build/assets/{vendor~root-layout~conversation-panel~conversation-CpiTHpHl.js → vendor~root-layout~conversation-panel~conversation-8tIsyrPj.js} +1 -1
  188. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-_TdZcNMD.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-lYNG9C1U.js} +1 -1
  189. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation-Cn2jwSga.js → vendor~root-layout~index-home~home~conversation-panel~conversation-Zhq6xAxR.js} +1 -1
  190. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-CZM4hwUT.js → vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation~aler~gfu7qdtz-B81b08bw.js} +1 -1
  191. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~settings~settings-index~agen~enjl5xdm-mMKDm94D.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~ftka0fnu-jpyLM1Nn.js} +2 -2
  192. package/build/assets/{verification-settings-DnXS6VWv.js → verification-settings-HRgEM-_3.js} +1 -1
  193. package/build/assets/x-ZE4iplpF.js +1 -0
  194. package/build/index.html +4 -4
  195. package/build/locales/ar/openhands.json +9 -0
  196. package/build/locales/ca/openhands.json +9 -0
  197. package/build/locales/de/openhands.json +9 -0
  198. package/build/locales/en/openhands.json +10 -1
  199. package/build/locales/es/openhands.json +9 -0
  200. package/build/locales/fr/openhands.json +9 -0
  201. package/build/locales/it/openhands.json +9 -0
  202. package/build/locales/ja/openhands.json +9 -0
  203. package/build/locales/ko-KR/openhands.json +9 -0
  204. package/build/locales/no/openhands.json +9 -0
  205. package/build/locales/pt/openhands.json +9 -0
  206. package/build/locales/tr/openhands.json +9 -0
  207. package/build/locales/uk/openhands.json +9 -0
  208. package/build/locales/zh-CN/openhands.json +9 -0
  209. package/build/locales/zh-TW/openhands.json +9 -0
  210. package/config/defaults.json +5 -4
  211. package/dist/api/agent-server-adapter.cjs +3 -3
  212. package/dist/api/agent-server-adapter.cjs.map +1 -1
  213. package/dist/api/agent-server-adapter.d.ts +9 -1
  214. package/dist/api/agent-server-adapter.js +105 -102
  215. package/dist/api/agent-server-adapter.js.map +1 -1
  216. package/dist/api/agent-server-config.cjs +1 -1
  217. package/dist/api/agent-server-config.cjs.map +1 -1
  218. package/dist/api/agent-server-config.d.ts +3 -0
  219. package/dist/api/agent-server-config.js +45 -23
  220. package/dist/api/agent-server-config.js.map +1 -1
  221. package/dist/api/backend-registry/auth.cjs +1 -1
  222. package/dist/api/backend-registry/auth.cjs.map +1 -1
  223. package/dist/api/backend-registry/auth.js +1 -1
  224. package/dist/api/backend-registry/auth.js.map +1 -1
  225. package/dist/api/backend-registry/default-backend.cjs +1 -1
  226. package/dist/api/backend-registry/default-backend.cjs.map +1 -1
  227. package/dist/api/backend-registry/default-backend.d.ts +3 -0
  228. package/dist/api/backend-registry/default-backend.js +22 -10
  229. package/dist/api/backend-registry/default-backend.js.map +1 -1
  230. package/dist/api/backend-registry/storage.cjs +1 -1
  231. package/dist/api/backend-registry/storage.cjs.map +1 -1
  232. package/dist/api/backend-registry/storage.js +38 -33
  233. package/dist/api/backend-registry/storage.js.map +1 -1
  234. package/dist/api/backend-registry/types.d.ts +2 -0
  235. package/dist/api/canvas-ui-client-tool.cjs +38 -0
  236. package/dist/api/canvas-ui-client-tool.cjs.map +1 -0
  237. package/dist/api/canvas-ui-client-tool.d.ts +14 -0
  238. package/dist/api/canvas-ui-client-tool.js +47 -0
  239. package/dist/api/canvas-ui-client-tool.js.map +1 -0
  240. package/dist/api/client-source.cjs +2 -0
  241. package/dist/api/client-source.cjs.map +1 -0
  242. package/dist/api/client-source.d.ts +9 -0
  243. package/dist/api/client-source.js +10 -0
  244. package/dist/api/client-source.js.map +1 -0
  245. package/dist/api/cloud/client.cjs +2 -0
  246. package/dist/api/cloud/client.cjs.map +1 -0
  247. package/dist/api/cloud/client.d.ts +4 -0
  248. package/dist/api/cloud/client.js +38 -0
  249. package/dist/api/cloud/client.js.map +1 -0
  250. package/dist/api/cloud/conversation-service.api.cjs +1 -1
  251. package/dist/api/cloud/conversation-service.api.cjs.map +1 -1
  252. package/dist/api/cloud/conversation-service.api.js +33 -31
  253. package/dist/api/cloud/conversation-service.api.js.map +1 -1
  254. package/dist/api/cloud/organization-service.api.cjs +1 -1
  255. package/dist/api/cloud/organization-service.api.cjs.map +1 -1
  256. package/dist/api/cloud/organization-service.api.js +11 -10
  257. package/dist/api/cloud/organization-service.api.js.map +1 -1
  258. package/dist/api/cloud/proxy.cjs +1 -1
  259. package/dist/api/cloud/proxy.cjs.map +1 -1
  260. package/dist/api/cloud/proxy.d.ts +2 -40
  261. package/dist/api/cloud/proxy.js +14 -39
  262. package/dist/api/cloud/proxy.js.map +1 -1
  263. package/dist/api/conversation-metadata-store.cjs +1 -1
  264. package/dist/api/conversation-metadata-store.cjs.map +1 -1
  265. package/dist/api/conversation-metadata-store.d.ts +2 -9
  266. package/dist/api/conversation-metadata-store.js +13 -9
  267. package/dist/api/conversation-metadata-store.js.map +1 -1
  268. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  269. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  270. package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +2 -1
  271. package/dist/api/conversation-service/agent-server-conversation-service.api.js +98 -88
  272. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  273. package/dist/api/conversation-service/agent-server-conversation-service.types.d.ts +5 -0
  274. package/dist/api/device-flow-client.cjs +1 -1
  275. package/dist/api/device-flow-client.cjs.map +1 -1
  276. package/dist/api/device-flow-client.d.ts +4 -58
  277. package/dist/api/device-flow-client.js +8 -98
  278. package/dist/api/device-flow-client.js.map +1 -1
  279. package/dist/api/git-service/agent-server-git-service.api.cjs +1 -1
  280. package/dist/api/git-service/agent-server-git-service.api.cjs.map +1 -1
  281. package/dist/api/git-service/agent-server-git-service.api.d.ts +10 -2
  282. package/dist/api/git-service/agent-server-git-service.api.js +107 -40
  283. package/dist/api/git-service/agent-server-git-service.api.js.map +1 -1
  284. package/dist/api/open-hands.types.d.ts +11 -0
  285. package/dist/api/secrets-service.cjs +1 -1
  286. package/dist/api/secrets-service.cjs.map +1 -1
  287. package/dist/api/secrets-service.js +15 -14
  288. package/dist/api/secrets-service.js.map +1 -1
  289. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs +1 -1
  290. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs.map +1 -1
  291. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js +73 -64
  292. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js.map +1 -1
  293. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.cjs +2 -2
  294. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.cjs.map +1 -1
  295. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.js +2 -0
  296. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.js.map +1 -1
  297. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  298. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  299. package/dist/components/features/backends/backend-form-modal.d.ts +7 -3
  300. package/dist/components/features/backends/backend-form-modal.js +216 -201
  301. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  302. package/dist/components/features/backends/backend-row.cjs +1 -1
  303. package/dist/components/features/backends/backend-row.cjs.map +1 -1
  304. package/dist/components/features/backends/backend-row.js +2 -1
  305. package/dist/components/features/backends/backend-row.js.map +1 -1
  306. package/dist/components/features/backends/backend-selector.cjs +1 -1
  307. package/dist/components/features/backends/backend-selector.cjs.map +1 -1
  308. package/dist/components/features/backends/backend-selector.js +51 -51
  309. package/dist/components/features/backends/backend-selector.js.map +1 -1
  310. package/dist/components/features/backends/device-flow-auth.cjs +1 -1
  311. package/dist/components/features/backends/device-flow-auth.cjs.map +1 -1
  312. package/dist/components/features/backends/device-flow-auth.d.ts +4 -1
  313. package/dist/components/features/backends/device-flow-auth.js +38 -38
  314. package/dist/components/features/backends/device-flow-auth.js.map +1 -1
  315. package/dist/components/features/chat/chat-interface.cjs +2 -2
  316. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  317. package/dist/components/features/chat/chat-interface.js +173 -165
  318. package/dist/components/features/chat/chat-interface.js.map +1 -1
  319. package/dist/components/features/chat/components/chat-input-actions.cjs +1 -1
  320. package/dist/components/features/chat/components/chat-input-actions.cjs.map +1 -1
  321. package/dist/components/features/chat/components/chat-input-actions.d.ts +2 -1
  322. package/dist/components/features/chat/components/chat-input-actions.js +44 -43
  323. package/dist/components/features/chat/components/chat-input-actions.js.map +1 -1
  324. package/dist/components/features/chat/components/chat-input-container.cjs +1 -1
  325. package/dist/components/features/chat/components/chat-input-container.cjs.map +1 -1
  326. package/dist/components/features/chat/components/chat-input-container.d.ts +2 -1
  327. package/dist/components/features/chat/components/chat-input-container.js +20 -19
  328. package/dist/components/features/chat/components/chat-input-container.js.map +1 -1
  329. package/dist/components/features/chat/components/chat-input-profile-picker.cjs +1 -1
  330. package/dist/components/features/chat/components/chat-input-profile-picker.cjs.map +1 -1
  331. package/dist/components/features/chat/components/chat-input-profile-picker.js +44 -32
  332. package/dist/components/features/chat/components/chat-input-profile-picker.js.map +1 -1
  333. package/dist/components/features/chat/components/resolve-picker-kind.cjs +1 -1
  334. package/dist/components/features/chat/components/resolve-picker-kind.cjs.map +1 -1
  335. package/dist/components/features/chat/components/resolve-picker-kind.d.ts +10 -22
  336. package/dist/components/features/chat/components/resolve-picker-kind.js +6 -3
  337. package/dist/components/features/chat/components/resolve-picker-kind.js.map +1 -1
  338. package/dist/components/features/chat/custom-chat-input.cjs +1 -1
  339. package/dist/components/features/chat/custom-chat-input.cjs.map +1 -1
  340. package/dist/components/features/chat/custom-chat-input.d.ts +2 -1
  341. package/dist/components/features/chat/custom-chat-input.js +52 -51
  342. package/dist/components/features/chat/custom-chat-input.js.map +1 -1
  343. package/dist/components/features/chat/interactive-chat-box.cjs +1 -1
  344. package/dist/components/features/chat/interactive-chat-box.cjs.map +1 -1
  345. package/dist/components/features/chat/interactive-chat-box.d.ts +2 -1
  346. package/dist/components/features/chat/interactive-chat-box.js +9 -8
  347. package/dist/components/features/chat/interactive-chat-box.js.map +1 -1
  348. package/dist/components/features/diff-viewer/commit-list.cjs +2 -0
  349. package/dist/components/features/diff-viewer/commit-list.cjs.map +1 -0
  350. package/dist/components/features/diff-viewer/commit-list.d.ts +13 -0
  351. package/dist/components/features/diff-viewer/commit-list.js +27 -0
  352. package/dist/components/features/diff-viewer/commit-list.js.map +1 -0
  353. package/dist/components/features/diff-viewer/commit-row.cjs +2 -0
  354. package/dist/components/features/diff-viewer/commit-row.cjs.map +1 -0
  355. package/dist/components/features/diff-viewer/commit-row.d.ts +14 -0
  356. package/dist/components/features/diff-viewer/commit-row.js +59 -0
  357. package/dist/components/features/diff-viewer/commit-row.js.map +1 -0
  358. package/dist/components/features/diff-viewer/file-diff-viewer.cjs +1 -1
  359. package/dist/components/features/diff-viewer/file-diff-viewer.cjs.map +1 -1
  360. package/dist/components/features/diff-viewer/file-diff-viewer.d.ts +7 -1
  361. package/dist/components/features/diff-viewer/file-diff-viewer.js +40 -39
  362. package/dist/components/features/diff-viewer/file-diff-viewer.js.map +1 -1
  363. package/dist/components/features/plugins/plugin-detail-modal.d.ts +2 -1
  364. package/dist/components/shared/modals/settings/settings-modal.cjs +1 -1
  365. package/dist/components/shared/modals/settings/settings-modal.cjs.map +1 -1
  366. package/dist/components/shared/modals/settings/settings-modal.js +23 -22
  367. package/dist/components/shared/modals/settings/settings-modal.js.map +1 -1
  368. package/dist/config/defaults.cjs +1 -1
  369. package/dist/config/defaults.cjs.map +1 -1
  370. package/dist/config/defaults.js +5 -4
  371. package/dist/config/defaults.js.map +1 -1
  372. package/dist/constants/acp-providers.cjs.map +1 -1
  373. package/dist/constants/acp-providers.d.ts +1 -1
  374. package/dist/constants/acp-providers.js.map +1 -1
  375. package/dist/constants/canvas-ui.cjs +2 -0
  376. package/dist/constants/canvas-ui.cjs.map +1 -0
  377. package/dist/constants/canvas-ui.d.ts +8 -0
  378. package/dist/constants/canvas-ui.js +6 -0
  379. package/dist/constants/canvas-ui.js.map +1 -0
  380. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  381. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  382. package/dist/hooks/mutation/use-create-conversation.cjs +1 -1
  383. package/dist/hooks/mutation/use-create-conversation.cjs.map +1 -1
  384. package/dist/hooks/mutation/use-create-conversation.d.ts +2 -1
  385. package/dist/hooks/mutation/use-create-conversation.js +52 -52
  386. package/dist/hooks/mutation/use-create-conversation.js.map +1 -1
  387. package/dist/hooks/query/query-keys.cjs +1 -1
  388. package/dist/hooks/query/query-keys.cjs.map +1 -1
  389. package/dist/hooks/query/query-keys.d.ts +2 -0
  390. package/dist/hooks/query/query-keys.js +4 -1
  391. package/dist/hooks/query/query-keys.js.map +1 -1
  392. package/dist/hooks/query/use-backends-health.cjs +1 -1
  393. package/dist/hooks/query/use-backends-health.cjs.map +1 -1
  394. package/dist/hooks/query/use-backends-health.js +50 -48
  395. package/dist/hooks/query/use-backends-health.js.map +1 -1
  396. package/dist/hooks/query/use-cloud-organizations.cjs +1 -1
  397. package/dist/hooks/query/use-cloud-organizations.cjs.map +1 -1
  398. package/dist/hooks/query/use-cloud-organizations.d.ts +1 -0
  399. package/dist/hooks/query/use-cloud-organizations.js +5 -2
  400. package/dist/hooks/query/use-cloud-organizations.js.map +1 -1
  401. package/dist/hooks/query/use-commit-changes.cjs +2 -0
  402. package/dist/hooks/query/use-commit-changes.cjs.map +1 -0
  403. package/dist/hooks/query/use-commit-changes.d.ts +5 -0
  404. package/dist/hooks/query/use-commit-changes.js +34 -0
  405. package/dist/hooks/query/use-commit-changes.js.map +1 -0
  406. package/dist/hooks/query/use-task-polling.cjs +1 -1
  407. package/dist/hooks/query/use-task-polling.cjs.map +1 -1
  408. package/dist/hooks/query/use-task-polling.d.ts +3 -2
  409. package/dist/hooks/query/use-task-polling.js +53 -40
  410. package/dist/hooks/query/use-task-polling.js.map +1 -1
  411. package/dist/hooks/query/use-unified-git-commits.cjs +2 -0
  412. package/dist/hooks/query/use-unified-git-commits.cjs.map +1 -0
  413. package/dist/hooks/query/use-unified-git-commits.d.ts +10 -0
  414. package/dist/hooks/query/use-unified-git-commits.js +41 -0
  415. package/dist/hooks/query/use-unified-git-commits.js.map +1 -0
  416. package/dist/hooks/query/use-unified-git-diff.cjs +1 -1
  417. package/dist/hooks/query/use-unified-git-diff.cjs.map +1 -1
  418. package/dist/hooks/query/use-unified-git-diff.d.ts +5 -0
  419. package/dist/hooks/query/use-unified-git-diff.js +11 -4
  420. package/dist/hooks/query/use-unified-git-diff.js.map +1 -1
  421. package/dist/hooks/use-acp-model-context.cjs +1 -1
  422. package/dist/hooks/use-acp-model-context.cjs.map +1 -1
  423. package/dist/hooks/use-acp-model-context.d.ts +4 -1
  424. package/dist/hooks/use-acp-model-context.js +9 -8
  425. package/dist/hooks/use-acp-model-context.js.map +1 -1
  426. package/dist/hooks/use-auto-refresh-files-on-edit.cjs +1 -1
  427. package/dist/hooks/use-auto-refresh-files-on-edit.cjs.map +1 -1
  428. package/dist/hooks/use-auto-refresh-files-on-edit.js +1 -1
  429. package/dist/hooks/use-auto-refresh-files-on-edit.js.map +1 -1
  430. package/dist/hooks/use-chat-input-model-state.cjs.map +1 -1
  431. package/dist/hooks/use-chat-input-model-state.d.ts +2 -1
  432. package/dist/hooks/use-chat-input-model-state.js.map +1 -1
  433. package/dist/hooks/use-chat-input-profile-state.cjs +1 -1
  434. package/dist/hooks/use-chat-input-profile-state.cjs.map +1 -1
  435. package/dist/hooks/use-chat-input-profile-state.d.ts +1 -10
  436. package/dist/hooks/use-chat-input-profile-state.js +42 -15
  437. package/dist/hooks/use-chat-input-profile-state.js.map +1 -1
  438. package/dist/hooks/use-device-flow.cjs +1 -1
  439. package/dist/hooks/use-device-flow.cjs.map +1 -1
  440. package/dist/hooks/use-device-flow.d.ts +4 -1
  441. package/dist/hooks/use-device-flow.js +42 -40
  442. package/dist/hooks/use-device-flow.js.map +1 -1
  443. package/dist/hooks/use-tracking.cjs.map +1 -1
  444. package/dist/hooks/use-tracking.d.ts +2 -1
  445. package/dist/hooks/use-tracking.js.map +1 -1
  446. package/dist/i18n/declaration.cjs +1 -1
  447. package/dist/i18n/declaration.cjs.map +1 -1
  448. package/dist/i18n/declaration.d.ts +9 -0
  449. package/dist/i18n/declaration.js +1 -1
  450. package/dist/i18n/declaration.js.map +1 -1
  451. package/dist/i18n/index.cjs +1 -1
  452. package/dist/i18n/index.cjs.map +1 -1
  453. package/dist/i18n/index.js +19 -18
  454. package/dist/i18n/index.js.map +1 -1
  455. package/dist/i18n/translation.cjs +3 -3
  456. package/dist/i18n/translation.cjs.map +1 -1
  457. package/dist/i18n/translation.js +154 -1
  458. package/dist/i18n/translation.js.map +1 -1
  459. package/dist/index.cjs +1 -1
  460. package/dist/index.js +32 -32
  461. package/dist/lib/index.cjs +1 -1
  462. package/dist/lib/index.js +1 -1
  463. package/dist/locales/ar/openhands.json +9 -0
  464. package/dist/locales/ca/openhands.json +9 -0
  465. package/dist/locales/de/openhands.json +9 -0
  466. package/dist/locales/en/openhands.json +10 -1
  467. package/dist/locales/es/openhands.json +9 -0
  468. package/dist/locales/fr/openhands.json +9 -0
  469. package/dist/locales/it/openhands.json +9 -0
  470. package/dist/locales/ja/openhands.json +9 -0
  471. package/dist/locales/ko-KR/openhands.json +9 -0
  472. package/dist/locales/no/openhands.json +9 -0
  473. package/dist/locales/pt/openhands.json +9 -0
  474. package/dist/locales/tr/openhands.json +9 -0
  475. package/dist/locales/uk/openhands.json +9 -0
  476. package/dist/locales/zh-CN/openhands.json +9 -0
  477. package/dist/locales/zh-TW/openhands.json +9 -0
  478. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.cjs +2 -0
  479. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.cjs.map +1 -0
  480. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.js +351 -0
  481. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.js.map +1 -0
  482. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.cjs +2 -0
  483. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.cjs.map +1 -0
  484. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.js +106 -0
  485. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.js.map +1 -0
  486. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.cjs +2 -0
  487. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.cjs.map +1 -0
  488. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.js +69 -0
  489. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.js.map +1 -0
  490. package/dist/node_modules/@openhands/typescript-client/dist/clients.cjs +1 -1
  491. package/dist/node_modules/@openhands/typescript-client/dist/clients.js +3 -0
  492. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs +1 -1
  493. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs.map +1 -1
  494. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js +18 -2
  495. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js.map +1 -1
  496. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.cjs.map +1 -1
  497. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.js.map +1 -1
  498. package/dist/node_modules/axios/index.cjs +1 -1
  499. package/dist/node_modules/axios/index.js +1 -1
  500. package/dist/package.cjs +1 -1
  501. package/dist/package.cjs.map +1 -1
  502. package/dist/package.js +2 -2
  503. package/dist/package.js.map +1 -1
  504. package/dist/routes/app-settings.cjs +1 -1
  505. package/dist/routes/app-settings.cjs.map +1 -1
  506. package/dist/routes/app-settings.js +67 -66
  507. package/dist/routes/app-settings.js.map +1 -1
  508. package/dist/routes/commits-tab.cjs +2 -0
  509. package/dist/routes/commits-tab.cjs.map +1 -0
  510. package/dist/routes/commits-tab.d.ts +8 -0
  511. package/dist/routes/commits-tab.js +45 -0
  512. package/dist/routes/commits-tab.js.map +1 -0
  513. package/dist/routes/files-tab.cjs +1 -1
  514. package/dist/routes/files-tab.cjs.map +1 -1
  515. package/dist/routes/files-tab.js +148 -127
  516. package/dist/routes/files-tab.js.map +1 -1
  517. package/dist/services/cloud-funnel-analytics.cjs +2 -0
  518. package/dist/services/cloud-funnel-analytics.cjs.map +1 -0
  519. package/dist/services/cloud-funnel-analytics.d.ts +12 -0
  520. package/dist/services/cloud-funnel-analytics.js +53 -0
  521. package/dist/services/cloud-funnel-analytics.js.map +1 -0
  522. package/dist/services/telemetry.cjs +1 -1
  523. package/dist/services/telemetry.cjs.map +1 -1
  524. package/dist/services/telemetry.js +49 -47
  525. package/dist/services/telemetry.js.map +1 -1
  526. package/dist/types/agent-server/core/base/action.d.ts +5 -4
  527. package/dist/types/agent-server/core/base/base.d.ts +3 -2
  528. package/dist/types/agent-server/core/base/observation.d.ts +1 -1
  529. package/dist/types/agent-server/type-guards.cjs +1 -1
  530. package/dist/types/agent-server/type-guards.cjs.map +1 -1
  531. package/dist/types/agent-server/type-guards.d.ts +3 -5
  532. package/dist/types/agent-server/type-guards.js +2 -1
  533. package/dist/types/agent-server/type-guards.js.map +1 -1
  534. package/dist/types/automation.d.ts +5 -0
  535. package/dist/utils/api-error-message.d.ts +11 -0
  536. package/dist/utils/automation-timeout.d.ts +19 -0
  537. package/dist/utils/base-path.cjs +2 -0
  538. package/dist/utils/base-path.cjs.map +1 -0
  539. package/dist/utils/base-path.d.ts +2 -0
  540. package/dist/utils/base-path.js +23 -0
  541. package/dist/utils/base-path.js.map +1 -0
  542. package/package.json +2 -2
  543. package/scripts/check-sdk-version-sync.mjs +6 -6
  544. package/scripts/dev-safe.mjs +7 -8
  545. package/scripts/dev-static.mjs +3 -0
  546. package/scripts/dev-with-automation.mjs +3 -0
  547. package/scripts/docker-build.mjs +4 -0
  548. package/scripts/static-server.mjs +93 -7
  549. package/tools/canvas_ui_tool.py +14 -8
  550. package/build/assets/active-backend-context-B3umL5R-.js +0 -1
  551. package/build/assets/agent-server-client-options-DVLRd9sw.js +0 -1
  552. package/build/assets/agent-server-conversation-service.api-D_ZvtJjG.js +0 -5
  553. package/build/assets/agent-settings-BVVFzBWS.js +0 -1
  554. package/build/assets/api-key-entry-screen-CWEHcPJA.js +0 -1
  555. package/build/assets/app-settings-Dj90qosy.js +0 -1
  556. package/build/assets/automation-detail-CXJU0_gF.js +0 -2
  557. package/build/assets/automation-export-FWY9LPsG.js +0 -2
  558. package/build/assets/automations-list-DDGBkWLC.js +0 -1
  559. package/build/assets/backend-form-modal-DSbrafX2.js +0 -1
  560. package/build/assets/browser-store-BI6uklCG.js +0 -1
  561. package/build/assets/check-Bvi71siz.js +0 -1
  562. package/build/assets/condenser-settings-30cX9SK6.js +0 -1
  563. package/build/assets/conversation-BltULtFA.js +0 -89
  564. package/build/assets/conversation-e0a0_X4S.js +0 -1
  565. package/build/assets/conversation-panel-Cr9_ZGI-.js +0 -1
  566. package/build/assets/conversation-service.api-DQaKzIRj.js +0 -1
  567. package/build/assets/conversation-state-store-B2Bp32XI.js +0 -1
  568. package/build/assets/declaration-gq8V5eTU.js +0 -1
  569. package/build/assets/files-tab-DDtEJcGE.js +0 -1
  570. package/build/assets/git-provider-icon-BjkecAuV.js +0 -1
  571. package/build/assets/home-BCKWpKpf.js +0 -1
  572. package/build/assets/index-redirect-CUUJiNki.js +0 -1
  573. package/build/assets/install-server-modal-BIugLhVB.js +0 -1
  574. package/build/assets/lesson-plan-DgpP80mJ.js +0 -4
  575. package/build/assets/llm-not-configured-banner-BlX8NifC.js +0 -27
  576. package/build/assets/llm-settings-DJmbryaE.js +0 -1
  577. package/build/assets/llm-settings-kU5v0H1Z.js +0 -1
  578. package/build/assets/llm-subscription-service-CKyaV24y.js +0 -1
  579. package/build/assets/loader-circle-BEykUKYG.js +0 -1
  580. package/build/assets/manage-backends-modal-C8FJQIZR.js +0 -1
  581. package/build/assets/manifest-56d40d7c.js +0 -1
  582. package/build/assets/model-selector-BOj1wBlq.js +0 -1
  583. package/build/assets/mouse-pointer-click-PdEQPL6v.js +0 -1
  584. package/build/assets/onboarding-DYhDxmI9.js +0 -1
  585. package/build/assets/onboarding-modal-CP_WxDC9.js +0 -1
  586. package/build/assets/option-service.api-C0tYT4-r.js +0 -1
  587. package/build/assets/organization-service.api-CnynNoT-.js +0 -1
  588. package/build/assets/path-utils-DWcgCGen.js +0 -1
  589. package/build/assets/plugins-management-service-BAp70KN7.js +0 -1
  590. package/build/assets/profiles-service.api-CeYEmSM3.js +0 -1
  591. package/build/assets/providers-BxCuC9bZ.js +0 -1
  592. package/build/assets/proxy-CHmFkV16.js +0 -1
  593. package/build/assets/root-V8fkplMy.css +0 -1
  594. package/build/assets/root-layout-CttG_lQi.js +0 -2
  595. package/build/assets/root-uJ2t9rCQ.js +0 -2
  596. package/build/assets/schema-field-xUr6rDd6.js +0 -1
  597. package/build/assets/sdk-section-page-CbLrVUa3.js +0 -1
  598. package/build/assets/search-4DHskuhE.js +0 -1
  599. package/build/assets/secrets-service-CZYjNxFw.js +0 -1
  600. package/build/assets/settings-DnlfS09K.js +0 -1
  601. package/build/assets/settings-modal-DfTcL-mV.js +0 -1
  602. package/build/assets/settings-service.api-K4ncGlBv.js +0 -1
  603. package/build/assets/shared-conversation-DWtBkJv7.js +0 -1
  604. package/build/assets/skills-plugins-BJ040luO.js +0 -1
  605. package/build/assets/use-acp-credential-form-EtnbtYt0.js +0 -1
  606. package/build/assets/use-agent-profiles-DEAMFp-W.js +0 -1
  607. package/build/assets/use-backends-health-DkC7tKkC.js +0 -1
  608. package/build/assets/use-cloud-current-user-id-Dm99wXp2.js +0 -1
  609. package/build/assets/use-config-CHzNIHpv.js +0 -1
  610. package/build/assets/use-create-conversation-CTsvZ96U.js +0 -1
  611. package/build/assets/use-is-authed-_dhQ2Xuj.js +0 -1
  612. package/build/assets/use-llm-profiles-BMhPDlwQ.js +0 -1
  613. package/build/assets/use-plugins-marketplace-BGb-KgfD.js +0 -1
  614. package/build/assets/use-runtime-is-ready-CC-KrLKe.js +0 -1
  615. package/build/assets/use-save-agent-profile-CLMmbx_X.js +0 -1
  616. package/build/assets/use-settings-BReAMxCG.js +0 -1
  617. package/build/assets/use-settings-nav-items-xe1YgLnE.js +0 -16
  618. package/build/assets/use-skills-Dqo-pDDx.js +0 -1
  619. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~d1e18dtv-5Q6lQJdE.js +0 -177
  620. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~ncdxw0bh-ClHnt5lR.js +0 -10
  621. package/build/assets/vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CqXiHwjU.js +0 -2
  622. package/build/assets/x-Cb0WAtak.js +0 -1
  623. /package/build/assets/{__vite-browser-external-4xJsU2-u.js → __vite-browser-external-DU-Cb_sT.js} +0 -0
  624. /package/build/assets/{automation-BU8zu-FP.js → automation-BVEmGghX.js} +0 -0
  625. /package/build/assets/{checkmark-h7udgXMM.js → checkmark-DhcMGwtO.js} +0 -0
  626. /package/build/assets/{close-p3Op5lxI.js → close-DO5Rq_CS.js} +0 -0
  627. /package/build/assets/{code-tag-DYlAhEQY.js → code-tag-BvjtzUsr.js} +0 -0
  628. /package/build/assets/{color-themes-DPBzNtVg.js → color-themes-bVMmJJG6.js} +0 -0
  629. /package/build/assets/{common-Dh7OqABE.js → common-CxbUL3nR.js} +0 -0
  630. /package/build/assets/{conversation-local-storage-F6zVMM--.js → conversation-local-storage-B31voBg7.js} +0 -0
  631. /package/build/assets/{copy-BLmGeJcd.js → copy-DLUw2us-.js} +0 -0
  632. /package/build/assets/{createLucideIcon-CVAsW2Yo.js → createLucideIcon-D4Tak8A1.js} +0 -0
  633. /package/build/assets/{dist-CodhvuAP.js → dist-Dj01FXbZ.js} +0 -0
  634. /package/build/assets/{environment-switch-store-DkjlKWzN.js → environment-switch-store-D9hB9PvY.js} +0 -0
  635. /package/build/assets/{extension-module-card-classes-9V3J9J_b.js → extension-module-card-classes-BlO4w702.js} +0 -0
  636. /package/build/assets/{folder-mMWFvaw0.js → folder-ynxP2EIL.js} +0 -0
  637. /package/build/assets/{get-language-from-path-CPNnuVhI.js → get-language-from-path-rWEQrOGU.js} +0 -0
  638. /package/build/assets/{git-status-mapper-BI8FyUVp.js → git-status-mapper-C3rfzUex.js} +0 -0
  639. /package/build/assets/{handle-capture-consent-CPMXU29K.js → handle-capture-consent-DDnXMC9Y.js} +0 -0
  640. /package/build/assets/{iconBase-DaTRRUjy.js → iconBase-CuvxAQZ5.js} +0 -0
  641. /package/build/assets/{link-external-DfKQroKX.js → link-external-BVDiJfZt.js} +0 -0
  642. /package/build/assets/{llm-subscription-DtsX5Lhg.js → llm-subscription-BkdHwtQe.js} +0 -0
  643. /package/build/assets/{map-provider-BM2SJarp.js → map-provider-XSFHmdDs.js} +0 -0
  644. /package/build/assets/{middleware-DYHYNAnP.js → middleware-CWYDMVuG.js} +0 -0
  645. /package/build/assets/{modal-backdrop-zVwfOJZr.js → modal-backdrop-Dsmzgr5s.js} +0 -0
  646. /package/build/assets/{navigation-context-DPs2G0X8.js → navigation-context-SjzfpygH.js} +0 -0
  647. /package/build/assets/{objectWithoutPropertiesLoose-BgYIAs2y.js → objectWithoutPropertiesLoose-CQwg6tC0.js} +0 -0
  648. /package/build/assets/{openhands-logo-bcNw5bkY.js → openhands-logo-C-gDp1wr.js} +0 -0
  649. /package/build/assets/{react-DPDgL6du.js → react-ao3tWj6K.js} +0 -0
  650. /package/build/assets/{search-BsjCEFNf.js → search-pb4UKTfK.js} +0 -0
  651. /package/build/assets/{settings-mQUckT0g.js → settings-DksoDv5z.js} +0 -0
  652. /package/build/assets/{settings-gear-MXCyZW0x.js → settings-gear-D_HVvE5L.js} +0 -0
  653. /package/build/assets/{settings-like-page-layout-classes-DENKlZpD.js → settings-like-page-layout-classes-DLrsPCaI.js} +0 -0
  654. /package/build/assets/{settings-section-header-context-COMOIaxV.js → settings-section-header-context-C2MUIG88.js} +0 -0
  655. /package/build/assets/{skills-9cDZONKh.js → skills-CH4xgIh-.js} +0 -0
  656. /package/build/assets/{switch-skeleton-DqQwalyu.js → switch-skeleton-BpSOvZ-n.js} +0 -0
  657. /package/build/assets/{terminal-BuLtIrb9.js → terminal-Dokfkxn0.js} +0 -0
  658. /package/build/assets/{u-check-circle-BqoIxNz_.js → u-check-circle-DPWVO-9N.js} +0 -0
  659. /package/build/assets/{u-check-circle-half-LiwZkuFe.js → u-check-circle-half-BGNAAjOW.js} +0 -0
  660. /package/build/assets/{u-edit-DJ90xc8Z.js → u-edit-BIskOoEG.js} +0 -0
  661. /package/build/assets/{use-breakpoint-B-O0lQ84.js → use-breakpoint-OjLm94cF.js} +0 -0
  662. /package/build/assets/{use-click-outside-element-Bf4Omzot.js → use-click-outside-element-Jpt2WWd7.js} +0 -0
  663. /package/build/assets/{use-onboarding-completion-C_Swglzp.js → use-onboarding-completion-DkRpDTsD.js} +0 -0
  664. /package/build/assets/{v4-DbCkTSoU.js → v4-DPgam_jW.js} +0 -0
  665. /package/build/assets/{vendor~browser-Dqd33JyP.js → vendor~browser-BvEKaLBz.js} +0 -0
  666. /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-DHDkknt5.js → vendor~conversation-panel~conversation~alert-banner-CznX01nZ.js} +0 -0
  667. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~i3v2mlbw-BrJQ3XZH.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~e0djk9ee-Cw6LUe8p.js} +0 -0
  668. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~k6tszsdc-Bb-xMtbv.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~g9hift2g-DmmpG9SI.js} +0 -0
  669. /package/build/assets/{vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~byh8a1g4-XNPdpuO8.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~jkpzbynd-CkpBIhVe.js} +0 -0
  670. /package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DTzw2x50.js → vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BuL5kjfS.js} +0 -0
  671. /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~automations-~ki5qnp0d-rV6d1Iv_.js → vendor~root-layout~index-home~home~conversation-panel~conversation~launch~skills-settings~a~j2jlu22h-DUYl8gbZ.js} +0 -0
  672. /package/build/assets/{vendor~root-layout~home~mcp~automations-list~onboarding-modal-CXyYYvYh.js → vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-pIgQDxTc.js} +0 -0
  673. /package/build/assets/{vendor~terminal-aeP3PnKf.js → vendor~terminal-jAaNQWS9.js} +0 -0
  674. /package/build/assets/{x-mark-Batp6gXa.js → x-mark-C5przfXl.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"use-auto-refresh-files-on-edit.cjs","names":[],"sources":["../../src/hooks/use-auto-refresh-files-on-edit.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\n\nimport { useEventStore, type OHEvent } from \"#/stores/use-event-store\";\nimport { useWorkspaceMutationCounter } from \"#/stores/use-workspace-mutation-counter\";\n\n// `kind` values we treat as a file-mutation observation.\nconst FILE_EDIT_OBSERVATION_KINDS = new Set([\n \"FileEditorObservation\",\n \"StrReplaceEditorObservation\",\n \"PlanningFileEditorObservation\",\n]);\n\n// Commands on the str-replace-editor family that don't change anything on\n// disk. We don't want to invalidate caches for those.\nconst READ_ONLY_COMMANDS = new Set([\"view\"]);\n\n// Bash observations are how `git commit` / `git push` (and any file edit\n// done through the shell) arrive, so they must refresh the Diff view too.\n// Legacy agent-servers emit `ExecuteBashObservation`; the current SDK\n// emits `TerminalObservation`.\nconst BASH_OBSERVATION_KINDS = new Set([\n \"ExecuteBashObservation\",\n \"TerminalObservation\",\n]);\n\nfunction isFileMutationObservation(event: OHEvent): boolean {\n // ObservationEvents have `source: \"environment\"` and an `observation`\n // field — narrow to that shape without pulling in the whole event union.\n const obs = (event as { observation?: { kind?: string; command?: string } })\n .observation;\n if (!obs || typeof obs.kind !== \"string\") return false;\n if (!FILE_EDIT_OBSERVATION_KINDS.has(obs.kind)) return false;\n if (obs.command && READ_ONLY_COMMANDS.has(obs.command)) return false;\n return true;\n}\n\n// Note: `READ_ONLY_COMMANDS` intentionally doesn't apply here — for bash\n// observations `command` is the whole shell command line, not a\n// file-editor sub-command.\nfunction isBashObservation(event: OHEvent): boolean {\n const obs = (event as { observation?: { kind?: string } }).observation;\n return (\n !!obs &&\n typeof obs.kind === \"string\" &&\n BASH_OBSERVATION_KINDS.has(obs.kind)\n );\n}\n\n/**\n * Watches the conversation event stream and invalidates the workspace file\n * queries whenever the agent commits a file-editor mutation (create / edit /\n * insert / undo_edit). This keeps the Files tab's list, content view and\n * diff view in sync with what the agent has actually written to disk,\n * without requiring the user to click refresh manually.\n *\n * Bash observations also refresh the git-diff queries (`file_changes` /\n * `file_diff`) — a `git commit` or `git push` changes what the Diff view\n * should display, and shell commands can edit files too. They deliberately\n * do NOT touch the workspace file queries or the workspace mutation\n * counter: bumping the counter reloads canvas iframes, and doing that for\n * every shell command the agent runs would cause constant flicker.\n * Invalidation only refetches actively-mounted queries, so the cost is\n * limited to when the Files tab is open.\n *\n * Mount this hook inside any component that should drive auto-refresh —\n * the Files tab is the obvious caller. Multiple mounts are safe because\n * React Query coalesces overlapping invalidations.\n */\nexport function useAutoRefreshFilesOnEdit(): void {\n const queryClient = useQueryClient();\n const events = useEventStore((state) => state.events);\n const bumpWorkspaceMutationCounter = useWorkspaceMutationCounter(\n (state) => state.bump,\n );\n\n // Track which events we've already reacted to. Two parallel stores:\n //\n // 1. `processedIdsRef` — keys events that *have* an id. The event store\n // re-sorts on insert when out-of-order events arrive (an older event\n // can land *between* two newer ones already in the array), so we\n // cannot use a `slice(processedCount)` trick — it would miss a\n // late-arriving older event because the array length grew but the\n // tail we just diffed didn't contain it. Using a Set of ids is O(n)\n // per render in the worst case but small in practice and immune to\n // reordering. Type matches the event store's own dedup set\n // (`Set<string | number>` in `use-event-store.ts`) so a stray\n // numeric id (legacy server payload, hand-crafted test event, …)\n // can't sneak past.\n //\n // 2. `processedEventsRef` — keys events that have NO id. We cannot put\n // a literal `undefined` into the id Set: that would make the second,\n // third, … id-less arrival collide on the same `undefined` key and\n // silently skip them. We also cannot just skip dedup for id-less\n // events: the events array is rebuilt on every store mutation but\n // its element references are stable, so the same id-less event\n // appears in the array forever and would re-bump the workspace\n // mutation counter on every subsequent re-render. Keying by object\n // reference (via a WeakSet) gives us \"process each id-less event\n // exactly once\" — durable, free, no held-onto memory after the\n // store clears.\n const processedIdsRef = useRef<Set<string | number>>(new Set());\n const processedEventsRef = useRef<WeakSet<OHEvent>>(new WeakSet());\n\n useEffect(() => {\n let hasNewFileEdits = false;\n let hasNewBashCommands = false;\n for (const event of events) {\n const id: string | number | undefined =\n \"id\" in event ? event.id : undefined;\n const alreadyProcessed =\n id !== undefined\n ? processedIdsRef.current.has(id)\n : processedEventsRef.current.has(event);\n // Inverted predicate so we avoid `continue` (banned by repo lint).\n if (!alreadyProcessed) {\n if (id !== undefined) {\n processedIdsRef.current.add(id);\n } else {\n processedEventsRef.current.add(event);\n }\n if (isFileMutationObservation(event)) hasNewFileEdits = true;\n else if (isBashObservation(event)) hasNewBashCommands = true;\n }\n }\n\n if (!hasNewFileEdits && !hasNewBashCommands) return;\n\n // Editor and bash mutations both change what the git Diff view shows —\n // including the per-file diff content of an already-expanded file.\n queryClient.invalidateQueries({ queryKey: [\"file_changes\"] });\n queryClient.invalidateQueries({ queryKey: [\"file_diff\"] });\n\n if (hasNewFileEdits) {\n queryClient.invalidateQueries({ queryKey: [\"workspace-files\"] });\n queryClient.invalidateQueries({ queryKey: [\"workspace-file-content\"] });\n // Force iframes / <img> tags pointing at the static workspace\n // fileserver to re-fetch. Without this they happily keep showing the\n // stale (browser-cached) bytes even after the agent has rewritten the\n // file on disk — e.g. tweaking style.css would silently have no\n // visible effect on the rendered index.html until the user reloaded\n // the whole canvas.\n bumpWorkspaceMutationCounter();\n }\n }, [events, queryClient, bumpWorkspaceMutationCounter]);\n}\n"],"mappings":"uQAOA,IAAM,EAA8B,IAAI,IAAI,CAC1C,wBACA,8BACA,gCACD,CAAC,CAII,EAAqB,IAAI,IAAI,CAAC,OAAO,CAAC,CAMtC,EAAyB,IAAI,IAAI,CACrC,yBACA,sBACD,CAAC,CAEF,SAAS,EAA0B,EAAyB,CAG1D,IAAM,EAAO,EACV,YAIH,MADA,EAFI,CAAC,GAAO,OAAO,EAAI,MAAS,UAC5B,CAAC,EAA4B,IAAI,EAAI,KAAK,EAC1C,EAAI,SAAW,EAAmB,IAAI,EAAI,QAAQ,EAOxD,SAAS,EAAkB,EAAyB,CAClD,IAAM,EAAO,EAA8C,YAC3D,MACE,CAAC,CAAC,GACF,OAAO,EAAI,MAAS,UACpB,EAAuB,IAAI,EAAI,KAAK,CAwBxC,SAAgB,GAAkC,CAChD,IAAM,EAAc,EAAA,gBAAgB,CAC9B,EAAS,EAAA,cAAe,GAAU,EAAM,OAAO,CAC/C,EAA+B,EAAA,4BAClC,GAAU,EAAM,KAClB,CA2BK,GAAA,EAAA,EAAA,QAA+C,IAAI,IAAM,CACzD,GAAA,EAAA,EAAA,QAA8C,IAAI,QAAU,EAElE,EAAA,EAAA,eAAgB,CACd,IAAI,EAAkB,GAClB,EAAqB,GACzB,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EACJ,OAAQ,EAAQ,EAAM,GAAK,IAAA,IAE3B,IAAO,IAAA,GAEH,EAAmB,QAAQ,IAAI,EAAM,CADrC,EAAgB,QAAQ,IAAI,EAAG,IAI/B,IAAO,IAAA,GAGT,EAAmB,QAAQ,IAAI,EAAM,CAFrC,EAAgB,QAAQ,IAAI,EAAG,CAI7B,EAA0B,EAAM,CAAE,EAAkB,GAC/C,EAAkB,EAAM,GAAE,EAAqB,KAIxD,CAAC,GAAmB,CAAC,IAIzB,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,CAAE,CAAC,CAC7D,EAAY,kBAAkB,CAAE,SAAU,CAAC,YAAY,CAAE,CAAC,CAEtD,IACF,EAAY,kBAAkB,CAAE,SAAU,CAAC,kBAAkB,CAAE,CAAC,CAChE,EAAY,kBAAkB,CAAE,SAAU,CAAC,yBAAyB,CAAE,CAAC,CAOvE,GAA8B,IAE/B,CAAC,EAAQ,EAAa,EAA6B,CAAC"}
1
+ {"version":3,"file":"use-auto-refresh-files-on-edit.cjs","names":[],"sources":["../../src/hooks/use-auto-refresh-files-on-edit.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\n\nimport { useEventStore, type OHEvent } from \"#/stores/use-event-store\";\nimport { useWorkspaceMutationCounter } from \"#/stores/use-workspace-mutation-counter\";\n\n// `kind` values we treat as a file-mutation observation.\nconst FILE_EDIT_OBSERVATION_KINDS = new Set([\n \"FileEditorObservation\",\n \"StrReplaceEditorObservation\",\n \"PlanningFileEditorObservation\",\n]);\n\n// Commands on the str-replace-editor family that don't change anything on\n// disk. We don't want to invalidate caches for those.\nconst READ_ONLY_COMMANDS = new Set([\"view\"]);\n\n// Bash observations are how `git commit` / `git push` (and any file edit\n// done through the shell) arrive, so they must refresh the Diff view too.\n// Legacy agent-servers emit `ExecuteBashObservation`; the current SDK\n// emits `TerminalObservation`.\nconst BASH_OBSERVATION_KINDS = new Set([\n \"ExecuteBashObservation\",\n \"TerminalObservation\",\n]);\n\nfunction isFileMutationObservation(event: OHEvent): boolean {\n // ObservationEvents have `source: \"environment\"` and an `observation`\n // field — narrow to that shape without pulling in the whole event union.\n const obs = (event as { observation?: { kind?: string; command?: string } })\n .observation;\n if (!obs || typeof obs.kind !== \"string\") return false;\n if (!FILE_EDIT_OBSERVATION_KINDS.has(obs.kind)) return false;\n if (obs.command && READ_ONLY_COMMANDS.has(obs.command)) return false;\n return true;\n}\n\n// Note: `READ_ONLY_COMMANDS` intentionally doesn't apply here — for bash\n// observations `command` is the whole shell command line, not a\n// file-editor sub-command.\nfunction isBashObservation(event: OHEvent): boolean {\n const obs = (event as { observation?: { kind?: string } }).observation;\n return (\n !!obs &&\n typeof obs.kind === \"string\" &&\n BASH_OBSERVATION_KINDS.has(obs.kind)\n );\n}\n\n/**\n * Watches the conversation event stream and invalidates the workspace file\n * queries whenever the agent commits a file-editor mutation (create / edit /\n * insert / undo_edit). This keeps the Files tab's list, content view and\n * diff view in sync with what the agent has actually written to disk,\n * without requiring the user to click refresh manually.\n *\n * Bash observations also refresh the git-diff queries (`file_changes` /\n * `file_diff`) — a `git commit` or `git push` changes what the Diff view\n * should display, and shell commands can edit files too. They deliberately\n * do NOT touch the workspace file queries or the workspace mutation\n * counter: bumping the counter reloads canvas iframes, and doing that for\n * every shell command the agent runs would cause constant flicker.\n * Invalidation only refetches actively-mounted queries, so the cost is\n * limited to when the Files tab is open.\n *\n * Mount this hook inside any component that should drive auto-refresh —\n * the Files tab is the obvious caller. Multiple mounts are safe because\n * React Query coalesces overlapping invalidations.\n */\nexport function useAutoRefreshFilesOnEdit(): void {\n const queryClient = useQueryClient();\n const events = useEventStore((state) => state.events);\n const bumpWorkspaceMutationCounter = useWorkspaceMutationCounter(\n (state) => state.bump,\n );\n\n // Track which events we've already reacted to. Two parallel stores:\n //\n // 1. `processedIdsRef` — keys events that *have* an id. The event store\n // re-sorts on insert when out-of-order events arrive (an older event\n // can land *between* two newer ones already in the array), so we\n // cannot use a `slice(processedCount)` trick — it would miss a\n // late-arriving older event because the array length grew but the\n // tail we just diffed didn't contain it. Using a Set of ids is O(n)\n // per render in the worst case but small in practice and immune to\n // reordering. Type matches the event store's own dedup set\n // (`Set<string | number>` in `use-event-store.ts`) so a stray\n // numeric id (legacy server payload, hand-crafted test event, …)\n // can't sneak past.\n //\n // 2. `processedEventsRef` — keys events that have NO id. We cannot put\n // a literal `undefined` into the id Set: that would make the second,\n // third, … id-less arrival collide on the same `undefined` key and\n // silently skip them. We also cannot just skip dedup for id-less\n // events: the events array is rebuilt on every store mutation but\n // its element references are stable, so the same id-less event\n // appears in the array forever and would re-bump the workspace\n // mutation counter on every subsequent re-render. Keying by object\n // reference (via a WeakSet) gives us \"process each id-less event\n // exactly once\" — durable, free, no held-onto memory after the\n // store clears.\n const processedIdsRef = useRef<Set<string | number>>(new Set());\n const processedEventsRef = useRef<WeakSet<OHEvent>>(new WeakSet());\n\n useEffect(() => {\n let hasNewFileEdits = false;\n let hasNewBashCommands = false;\n for (const event of events) {\n const id: string | number | undefined =\n \"id\" in event ? event.id : undefined;\n const alreadyProcessed =\n id !== undefined\n ? processedIdsRef.current.has(id)\n : processedEventsRef.current.has(event);\n // Inverted predicate so we avoid `continue` (banned by repo lint).\n if (!alreadyProcessed) {\n if (id !== undefined) {\n processedIdsRef.current.add(id);\n } else {\n processedEventsRef.current.add(event);\n }\n if (isFileMutationObservation(event)) hasNewFileEdits = true;\n else if (isBashObservation(event)) hasNewBashCommands = true;\n }\n }\n\n if (!hasNewFileEdits && !hasNewBashCommands) return;\n\n // Editor and bash mutations both change what the git Diff view shows —\n // including the per-file diff content of an already-expanded file.\n // The commits list refreshes too (a `git commit` arrives as a bash\n // observation); per-commit queries (`commit_changes` /\n // `commit_file_diff`) are sha-addressed and immutable, so they are\n // deliberately NOT invalidated.\n queryClient.invalidateQueries({ queryKey: [\"file_changes\"] });\n queryClient.invalidateQueries({ queryKey: [\"file_diff\"] });\n queryClient.invalidateQueries({ queryKey: [\"git_commits\"] });\n\n if (hasNewFileEdits) {\n queryClient.invalidateQueries({ queryKey: [\"workspace-files\"] });\n queryClient.invalidateQueries({ queryKey: [\"workspace-file-content\"] });\n // Force iframes / <img> tags pointing at the static workspace\n // fileserver to re-fetch. Without this they happily keep showing the\n // stale (browser-cached) bytes even after the agent has rewritten the\n // file on disk — e.g. tweaking style.css would silently have no\n // visible effect on the rendered index.html until the user reloaded\n // the whole canvas.\n bumpWorkspaceMutationCounter();\n }\n }, [events, queryClient, bumpWorkspaceMutationCounter]);\n}\n"],"mappings":"uQAOA,IAAM,EAA8B,IAAI,IAAI,CAC1C,wBACA,8BACA,gCACD,CAAC,CAII,EAAqB,IAAI,IAAI,CAAC,OAAO,CAAC,CAMtC,EAAyB,IAAI,IAAI,CACrC,yBACA,sBACD,CAAC,CAEF,SAAS,EAA0B,EAAyB,CAG1D,IAAM,EAAO,EACV,YAIH,MADA,EAFI,CAAC,GAAO,OAAO,EAAI,MAAS,UAC5B,CAAC,EAA4B,IAAI,EAAI,KAAK,EAC1C,EAAI,SAAW,EAAmB,IAAI,EAAI,QAAQ,EAOxD,SAAS,EAAkB,EAAyB,CAClD,IAAM,EAAO,EAA8C,YAC3D,MACE,CAAC,CAAC,GACF,OAAO,EAAI,MAAS,UACpB,EAAuB,IAAI,EAAI,KAAK,CAwBxC,SAAgB,GAAkC,CAChD,IAAM,EAAc,EAAA,gBAAgB,CAC9B,EAAS,EAAA,cAAe,GAAU,EAAM,OAAO,CAC/C,EAA+B,EAAA,4BAClC,GAAU,EAAM,KAClB,CA2BK,GAAA,EAAA,EAAA,QAA+C,IAAI,IAAM,CACzD,GAAA,EAAA,EAAA,QAA8C,IAAI,QAAU,EAElE,EAAA,EAAA,eAAgB,CACd,IAAI,EAAkB,GAClB,EAAqB,GACzB,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EACJ,OAAQ,EAAQ,EAAM,GAAK,IAAA,IAE3B,IAAO,IAAA,GAEH,EAAmB,QAAQ,IAAI,EAAM,CADrC,EAAgB,QAAQ,IAAI,EAAG,IAI/B,IAAO,IAAA,GAGT,EAAmB,QAAQ,IAAI,EAAM,CAFrC,EAAgB,QAAQ,IAAI,EAAG,CAI7B,EAA0B,EAAM,CAAE,EAAkB,GAC/C,EAAkB,EAAM,GAAE,EAAqB,KAIxD,CAAC,GAAmB,CAAC,IAQzB,EAAY,kBAAkB,CAAE,SAAU,CAAC,eAAe,CAAE,CAAC,CAC7D,EAAY,kBAAkB,CAAE,SAAU,CAAC,YAAY,CAAE,CAAC,CAC1D,EAAY,kBAAkB,CAAE,SAAU,CAAC,cAAc,CAAE,CAAC,CAExD,IACF,EAAY,kBAAkB,CAAE,SAAU,CAAC,kBAAkB,CAAE,CAAC,CAChE,EAAY,kBAAkB,CAAE,SAAU,CAAC,yBAAyB,CAAE,CAAC,CAOvE,GAA8B,IAE/B,CAAC,EAAQ,EAAa,EAA6B,CAAC"}
@@ -24,7 +24,7 @@ function u() {
24
24
  let r = "id" in n ? n.id : void 0;
25
25
  (r === void 0 ? d.current.has(n) : u.current.has(r)) || (r === void 0 ? d.current.add(n) : u.current.add(r), c(n) ? e = !0 : l(n) && (t = !0));
26
26
  }
27
- !e && !t || (a.invalidateQueries({ queryKey: ["file_changes"] }), a.invalidateQueries({ queryKey: ["file_diff"] }), e && (a.invalidateQueries({ queryKey: ["workspace-files"] }), a.invalidateQueries({ queryKey: ["workspace-file-content"] }), s()));
27
+ !e && !t || (a.invalidateQueries({ queryKey: ["file_changes"] }), a.invalidateQueries({ queryKey: ["file_diff"] }), a.invalidateQueries({ queryKey: ["git_commits"] }), e && (a.invalidateQueries({ queryKey: ["workspace-files"] }), a.invalidateQueries({ queryKey: ["workspace-file-content"] }), s()));
28
28
  }, [
29
29
  o,
30
30
  a,
@@ -1 +1 @@
1
- {"version":3,"file":"use-auto-refresh-files-on-edit.js","names":[],"sources":["../../src/hooks/use-auto-refresh-files-on-edit.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\n\nimport { useEventStore, type OHEvent } from \"#/stores/use-event-store\";\nimport { useWorkspaceMutationCounter } from \"#/stores/use-workspace-mutation-counter\";\n\n// `kind` values we treat as a file-mutation observation.\nconst FILE_EDIT_OBSERVATION_KINDS = new Set([\n \"FileEditorObservation\",\n \"StrReplaceEditorObservation\",\n \"PlanningFileEditorObservation\",\n]);\n\n// Commands on the str-replace-editor family that don't change anything on\n// disk. We don't want to invalidate caches for those.\nconst READ_ONLY_COMMANDS = new Set([\"view\"]);\n\n// Bash observations are how `git commit` / `git push` (and any file edit\n// done through the shell) arrive, so they must refresh the Diff view too.\n// Legacy agent-servers emit `ExecuteBashObservation`; the current SDK\n// emits `TerminalObservation`.\nconst BASH_OBSERVATION_KINDS = new Set([\n \"ExecuteBashObservation\",\n \"TerminalObservation\",\n]);\n\nfunction isFileMutationObservation(event: OHEvent): boolean {\n // ObservationEvents have `source: \"environment\"` and an `observation`\n // field — narrow to that shape without pulling in the whole event union.\n const obs = (event as { observation?: { kind?: string; command?: string } })\n .observation;\n if (!obs || typeof obs.kind !== \"string\") return false;\n if (!FILE_EDIT_OBSERVATION_KINDS.has(obs.kind)) return false;\n if (obs.command && READ_ONLY_COMMANDS.has(obs.command)) return false;\n return true;\n}\n\n// Note: `READ_ONLY_COMMANDS` intentionally doesn't apply here — for bash\n// observations `command` is the whole shell command line, not a\n// file-editor sub-command.\nfunction isBashObservation(event: OHEvent): boolean {\n const obs = (event as { observation?: { kind?: string } }).observation;\n return (\n !!obs &&\n typeof obs.kind === \"string\" &&\n BASH_OBSERVATION_KINDS.has(obs.kind)\n );\n}\n\n/**\n * Watches the conversation event stream and invalidates the workspace file\n * queries whenever the agent commits a file-editor mutation (create / edit /\n * insert / undo_edit). This keeps the Files tab's list, content view and\n * diff view in sync with what the agent has actually written to disk,\n * without requiring the user to click refresh manually.\n *\n * Bash observations also refresh the git-diff queries (`file_changes` /\n * `file_diff`) — a `git commit` or `git push` changes what the Diff view\n * should display, and shell commands can edit files too. They deliberately\n * do NOT touch the workspace file queries or the workspace mutation\n * counter: bumping the counter reloads canvas iframes, and doing that for\n * every shell command the agent runs would cause constant flicker.\n * Invalidation only refetches actively-mounted queries, so the cost is\n * limited to when the Files tab is open.\n *\n * Mount this hook inside any component that should drive auto-refresh —\n * the Files tab is the obvious caller. Multiple mounts are safe because\n * React Query coalesces overlapping invalidations.\n */\nexport function useAutoRefreshFilesOnEdit(): void {\n const queryClient = useQueryClient();\n const events = useEventStore((state) => state.events);\n const bumpWorkspaceMutationCounter = useWorkspaceMutationCounter(\n (state) => state.bump,\n );\n\n // Track which events we've already reacted to. Two parallel stores:\n //\n // 1. `processedIdsRef` — keys events that *have* an id. The event store\n // re-sorts on insert when out-of-order events arrive (an older event\n // can land *between* two newer ones already in the array), so we\n // cannot use a `slice(processedCount)` trick — it would miss a\n // late-arriving older event because the array length grew but the\n // tail we just diffed didn't contain it. Using a Set of ids is O(n)\n // per render in the worst case but small in practice and immune to\n // reordering. Type matches the event store's own dedup set\n // (`Set<string | number>` in `use-event-store.ts`) so a stray\n // numeric id (legacy server payload, hand-crafted test event, …)\n // can't sneak past.\n //\n // 2. `processedEventsRef` — keys events that have NO id. We cannot put\n // a literal `undefined` into the id Set: that would make the second,\n // third, … id-less arrival collide on the same `undefined` key and\n // silently skip them. We also cannot just skip dedup for id-less\n // events: the events array is rebuilt on every store mutation but\n // its element references are stable, so the same id-less event\n // appears in the array forever and would re-bump the workspace\n // mutation counter on every subsequent re-render. Keying by object\n // reference (via a WeakSet) gives us \"process each id-less event\n // exactly once\" — durable, free, no held-onto memory after the\n // store clears.\n const processedIdsRef = useRef<Set<string | number>>(new Set());\n const processedEventsRef = useRef<WeakSet<OHEvent>>(new WeakSet());\n\n useEffect(() => {\n let hasNewFileEdits = false;\n let hasNewBashCommands = false;\n for (const event of events) {\n const id: string | number | undefined =\n \"id\" in event ? event.id : undefined;\n const alreadyProcessed =\n id !== undefined\n ? processedIdsRef.current.has(id)\n : processedEventsRef.current.has(event);\n // Inverted predicate so we avoid `continue` (banned by repo lint).\n if (!alreadyProcessed) {\n if (id !== undefined) {\n processedIdsRef.current.add(id);\n } else {\n processedEventsRef.current.add(event);\n }\n if (isFileMutationObservation(event)) hasNewFileEdits = true;\n else if (isBashObservation(event)) hasNewBashCommands = true;\n }\n }\n\n if (!hasNewFileEdits && !hasNewBashCommands) return;\n\n // Editor and bash mutations both change what the git Diff view shows —\n // including the per-file diff content of an already-expanded file.\n queryClient.invalidateQueries({ queryKey: [\"file_changes\"] });\n queryClient.invalidateQueries({ queryKey: [\"file_diff\"] });\n\n if (hasNewFileEdits) {\n queryClient.invalidateQueries({ queryKey: [\"workspace-files\"] });\n queryClient.invalidateQueries({ queryKey: [\"workspace-file-content\"] });\n // Force iframes / <img> tags pointing at the static workspace\n // fileserver to re-fetch. Without this they happily keep showing the\n // stale (browser-cached) bytes even after the agent has rewritten the\n // file on disk — e.g. tweaking style.css would silently have no\n // visible effect on the rendered index.html until the user reloaded\n // the whole canvas.\n bumpWorkspaceMutationCounter();\n }\n }, [events, queryClient, bumpWorkspaceMutationCounter]);\n}\n"],"mappings":";;;;;AAOA,IAAM,IAA8B,IAAI,IAAI;CAC1C;CACA;CACA;CACD,CAAC,EAII,IAAqB,IAAI,IAAI,CAAC,OAAO,CAAC,EAMtC,IAAyB,IAAI,IAAI,CACrC,0BACA,sBACD,CAAC;AAEF,SAAS,EAA0B,GAAyB;CAG1D,IAAM,IAAO,EACV;AAIH,QADA,EAFI,CAAC,KAAO,OAAO,EAAI,QAAS,YAC5B,CAAC,EAA4B,IAAI,EAAI,KAAK,IAC1C,EAAI,WAAW,EAAmB,IAAI,EAAI,QAAQ;;AAOxD,SAAS,EAAkB,GAAyB;CAClD,IAAM,IAAO,EAA8C;AAC3D,QACE,CAAC,CAAC,KACF,OAAO,EAAI,QAAS,YACpB,EAAuB,IAAI,EAAI,KAAK;;AAwBxC,SAAgB,IAAkC;CAChD,IAAM,IAAc,GAAgB,EAC9B,IAAS,GAAe,MAAU,EAAM,OAAO,EAC/C,IAA+B,GAClC,MAAU,EAAM,KAClB,EA2BK,IAAkB,kBAA6B,IAAI,KAAK,CAAC,EACzD,IAAqB,kBAAyB,IAAI,SAAS,CAAC;AAElE,SAAgB;EACd,IAAI,IAAkB,IAClB,IAAqB;AACzB,OAAK,IAAM,KAAS,GAAQ;GAC1B,IAAM,IACJ,QAAQ,IAAQ,EAAM,KAAK,KAAA;AAM7B,IAJE,MAAO,KAAA,IAEH,EAAmB,QAAQ,IAAI,EAAM,GADrC,EAAgB,QAAQ,IAAI,EAAG,MAI/B,MAAO,KAAA,IAGT,EAAmB,QAAQ,IAAI,EAAM,GAFrC,EAAgB,QAAQ,IAAI,EAAG,EAI7B,EAA0B,EAAM,GAAE,IAAkB,KAC/C,EAAkB,EAAM,KAAE,IAAqB;;AAIxD,GAAC,KAAmB,CAAC,MAIzB,EAAY,kBAAkB,EAAE,UAAU,CAAC,eAAe,EAAE,CAAC,EAC7D,EAAY,kBAAkB,EAAE,UAAU,CAAC,YAAY,EAAE,CAAC,EAEtD,MACF,EAAY,kBAAkB,EAAE,UAAU,CAAC,kBAAkB,EAAE,CAAC,EAChE,EAAY,kBAAkB,EAAE,UAAU,CAAC,yBAAyB,EAAE,CAAC,EAOvE,GAA8B;IAE/B;EAAC;EAAQ;EAAa;EAA6B,CAAC"}
1
+ {"version":3,"file":"use-auto-refresh-files-on-edit.js","names":[],"sources":["../../src/hooks/use-auto-refresh-files-on-edit.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\n\nimport { useEventStore, type OHEvent } from \"#/stores/use-event-store\";\nimport { useWorkspaceMutationCounter } from \"#/stores/use-workspace-mutation-counter\";\n\n// `kind` values we treat as a file-mutation observation.\nconst FILE_EDIT_OBSERVATION_KINDS = new Set([\n \"FileEditorObservation\",\n \"StrReplaceEditorObservation\",\n \"PlanningFileEditorObservation\",\n]);\n\n// Commands on the str-replace-editor family that don't change anything on\n// disk. We don't want to invalidate caches for those.\nconst READ_ONLY_COMMANDS = new Set([\"view\"]);\n\n// Bash observations are how `git commit` / `git push` (and any file edit\n// done through the shell) arrive, so they must refresh the Diff view too.\n// Legacy agent-servers emit `ExecuteBashObservation`; the current SDK\n// emits `TerminalObservation`.\nconst BASH_OBSERVATION_KINDS = new Set([\n \"ExecuteBashObservation\",\n \"TerminalObservation\",\n]);\n\nfunction isFileMutationObservation(event: OHEvent): boolean {\n // ObservationEvents have `source: \"environment\"` and an `observation`\n // field — narrow to that shape without pulling in the whole event union.\n const obs = (event as { observation?: { kind?: string; command?: string } })\n .observation;\n if (!obs || typeof obs.kind !== \"string\") return false;\n if (!FILE_EDIT_OBSERVATION_KINDS.has(obs.kind)) return false;\n if (obs.command && READ_ONLY_COMMANDS.has(obs.command)) return false;\n return true;\n}\n\n// Note: `READ_ONLY_COMMANDS` intentionally doesn't apply here — for bash\n// observations `command` is the whole shell command line, not a\n// file-editor sub-command.\nfunction isBashObservation(event: OHEvent): boolean {\n const obs = (event as { observation?: { kind?: string } }).observation;\n return (\n !!obs &&\n typeof obs.kind === \"string\" &&\n BASH_OBSERVATION_KINDS.has(obs.kind)\n );\n}\n\n/**\n * Watches the conversation event stream and invalidates the workspace file\n * queries whenever the agent commits a file-editor mutation (create / edit /\n * insert / undo_edit). This keeps the Files tab's list, content view and\n * diff view in sync with what the agent has actually written to disk,\n * without requiring the user to click refresh manually.\n *\n * Bash observations also refresh the git-diff queries (`file_changes` /\n * `file_diff`) — a `git commit` or `git push` changes what the Diff view\n * should display, and shell commands can edit files too. They deliberately\n * do NOT touch the workspace file queries or the workspace mutation\n * counter: bumping the counter reloads canvas iframes, and doing that for\n * every shell command the agent runs would cause constant flicker.\n * Invalidation only refetches actively-mounted queries, so the cost is\n * limited to when the Files tab is open.\n *\n * Mount this hook inside any component that should drive auto-refresh —\n * the Files tab is the obvious caller. Multiple mounts are safe because\n * React Query coalesces overlapping invalidations.\n */\nexport function useAutoRefreshFilesOnEdit(): void {\n const queryClient = useQueryClient();\n const events = useEventStore((state) => state.events);\n const bumpWorkspaceMutationCounter = useWorkspaceMutationCounter(\n (state) => state.bump,\n );\n\n // Track which events we've already reacted to. Two parallel stores:\n //\n // 1. `processedIdsRef` — keys events that *have* an id. The event store\n // re-sorts on insert when out-of-order events arrive (an older event\n // can land *between* two newer ones already in the array), so we\n // cannot use a `slice(processedCount)` trick — it would miss a\n // late-arriving older event because the array length grew but the\n // tail we just diffed didn't contain it. Using a Set of ids is O(n)\n // per render in the worst case but small in practice and immune to\n // reordering. Type matches the event store's own dedup set\n // (`Set<string | number>` in `use-event-store.ts`) so a stray\n // numeric id (legacy server payload, hand-crafted test event, …)\n // can't sneak past.\n //\n // 2. `processedEventsRef` — keys events that have NO id. We cannot put\n // a literal `undefined` into the id Set: that would make the second,\n // third, … id-less arrival collide on the same `undefined` key and\n // silently skip them. We also cannot just skip dedup for id-less\n // events: the events array is rebuilt on every store mutation but\n // its element references are stable, so the same id-less event\n // appears in the array forever and would re-bump the workspace\n // mutation counter on every subsequent re-render. Keying by object\n // reference (via a WeakSet) gives us \"process each id-less event\n // exactly once\" — durable, free, no held-onto memory after the\n // store clears.\n const processedIdsRef = useRef<Set<string | number>>(new Set());\n const processedEventsRef = useRef<WeakSet<OHEvent>>(new WeakSet());\n\n useEffect(() => {\n let hasNewFileEdits = false;\n let hasNewBashCommands = false;\n for (const event of events) {\n const id: string | number | undefined =\n \"id\" in event ? event.id : undefined;\n const alreadyProcessed =\n id !== undefined\n ? processedIdsRef.current.has(id)\n : processedEventsRef.current.has(event);\n // Inverted predicate so we avoid `continue` (banned by repo lint).\n if (!alreadyProcessed) {\n if (id !== undefined) {\n processedIdsRef.current.add(id);\n } else {\n processedEventsRef.current.add(event);\n }\n if (isFileMutationObservation(event)) hasNewFileEdits = true;\n else if (isBashObservation(event)) hasNewBashCommands = true;\n }\n }\n\n if (!hasNewFileEdits && !hasNewBashCommands) return;\n\n // Editor and bash mutations both change what the git Diff view shows —\n // including the per-file diff content of an already-expanded file.\n // The commits list refreshes too (a `git commit` arrives as a bash\n // observation); per-commit queries (`commit_changes` /\n // `commit_file_diff`) are sha-addressed and immutable, so they are\n // deliberately NOT invalidated.\n queryClient.invalidateQueries({ queryKey: [\"file_changes\"] });\n queryClient.invalidateQueries({ queryKey: [\"file_diff\"] });\n queryClient.invalidateQueries({ queryKey: [\"git_commits\"] });\n\n if (hasNewFileEdits) {\n queryClient.invalidateQueries({ queryKey: [\"workspace-files\"] });\n queryClient.invalidateQueries({ queryKey: [\"workspace-file-content\"] });\n // Force iframes / <img> tags pointing at the static workspace\n // fileserver to re-fetch. Without this they happily keep showing the\n // stale (browser-cached) bytes even after the agent has rewritten the\n // file on disk — e.g. tweaking style.css would silently have no\n // visible effect on the rendered index.html until the user reloaded\n // the whole canvas.\n bumpWorkspaceMutationCounter();\n }\n }, [events, queryClient, bumpWorkspaceMutationCounter]);\n}\n"],"mappings":";;;;;AAOA,IAAM,IAA8B,IAAI,IAAI;CAC1C;CACA;CACA;CACD,CAAC,EAII,IAAqB,IAAI,IAAI,CAAC,OAAO,CAAC,EAMtC,IAAyB,IAAI,IAAI,CACrC,0BACA,sBACD,CAAC;AAEF,SAAS,EAA0B,GAAyB;CAG1D,IAAM,IAAO,EACV;AAIH,QADA,EAFI,CAAC,KAAO,OAAO,EAAI,QAAS,YAC5B,CAAC,EAA4B,IAAI,EAAI,KAAK,IAC1C,EAAI,WAAW,EAAmB,IAAI,EAAI,QAAQ;;AAOxD,SAAS,EAAkB,GAAyB;CAClD,IAAM,IAAO,EAA8C;AAC3D,QACE,CAAC,CAAC,KACF,OAAO,EAAI,QAAS,YACpB,EAAuB,IAAI,EAAI,KAAK;;AAwBxC,SAAgB,IAAkC;CAChD,IAAM,IAAc,GAAgB,EAC9B,IAAS,GAAe,MAAU,EAAM,OAAO,EAC/C,IAA+B,GAClC,MAAU,EAAM,KAClB,EA2BK,IAAkB,kBAA6B,IAAI,KAAK,CAAC,EACzD,IAAqB,kBAAyB,IAAI,SAAS,CAAC;AAElE,SAAgB;EACd,IAAI,IAAkB,IAClB,IAAqB;AACzB,OAAK,IAAM,KAAS,GAAQ;GAC1B,IAAM,IACJ,QAAQ,IAAQ,EAAM,KAAK,KAAA;AAM7B,IAJE,MAAO,KAAA,IAEH,EAAmB,QAAQ,IAAI,EAAM,GADrC,EAAgB,QAAQ,IAAI,EAAG,MAI/B,MAAO,KAAA,IAGT,EAAmB,QAAQ,IAAI,EAAM,GAFrC,EAAgB,QAAQ,IAAI,EAAG,EAI7B,EAA0B,EAAM,GAAE,IAAkB,KAC/C,EAAkB,EAAM,KAAE,IAAqB;;AAIxD,GAAC,KAAmB,CAAC,MAQzB,EAAY,kBAAkB,EAAE,UAAU,CAAC,eAAe,EAAE,CAAC,EAC7D,EAAY,kBAAkB,EAAE,UAAU,CAAC,YAAY,EAAE,CAAC,EAC1D,EAAY,kBAAkB,EAAE,UAAU,CAAC,cAAc,EAAE,CAAC,EAExD,MACF,EAAY,kBAAkB,EAAE,UAAU,CAAC,kBAAkB,EAAE,CAAC,EAChE,EAAY,kBAAkB,EAAE,UAAU,CAAC,yBAAyB,EAAE,CAAC,EAOvE,GAA8B;IAE/B;EAAC;EAAQ;EAAa;EAA6B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-input-model-state.cjs","names":[],"sources":["../../src/hooks/use-chat-input-model-state.ts"],"sourcesContent":["import { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useAcpModelContext } from \"#/hooks/use-acp-model-context\";\nimport { useOptionalConversationId } from \"#/hooks/use-conversation-id\";\nimport {\n getAcpPreferredDefaultModel,\n getAcpProvider,\n labelForAcpModel,\n resolveEffectiveAcpModel,\n type ACPModelOption,\n} from \"#/constants/acp-providers\";\n\nexport interface ChatInputModelState {\n isAcpContext: boolean;\n displayModel: string | null;\n currentModelId: string | null;\n availableAcpModels: ACPModelOption[];\n showAcpPicker: boolean;\n switchConversationId: string | null;\n destinationPath: \"/settings/agents\" | \"/settings\";\n destinationLabel: string;\n}\n\nexport function useChatInputModelState(): ChatInputModelState {\n const { data: conversation } = useActiveConversation();\n const { data: settings } = useSettings();\n const { conversationId } = useOptionalConversationId();\n const {\n isActiveAcpConversation,\n isHomeAcp,\n isAcpContext,\n destinationPath,\n destinationLabel,\n } = useAcpModelContext();\n\n const acpServerKey = isActiveAcpConversation\n ? conversation?.acp_server\n : isHomeAcp\n ? typeof settings?.agent_settings?.acp_server === \"string\"\n ? settings.agent_settings.acp_server\n : null\n : null;\n const acpProvider = isAcpContext ? getAcpProvider(acpServerKey) : undefined;\n\n const acpConfiguredModel =\n typeof settings?.agent_settings?.acp_model === \"string\"\n ? settings.agent_settings.acp_model\n : null;\n\n let currentModelId: string | null = null;\n if (isActiveAcpConversation) {\n // ACP conversations store llm_model as the acp_model (persisted at\n // creation time). Use it directly if available; fall back to the\n // settings-configured model or provider default so the chip stays visible.\n currentModelId =\n conversation?.llm_model ??\n resolveEffectiveAcpModel({\n configured: acpConfiguredModel,\n providerDefault: getAcpPreferredDefaultModel(acpServerKey),\n });\n } else if (isHomeAcp) {\n currentModelId = resolveEffectiveAcpModel({\n configured: acpConfiguredModel,\n // Preferred default (Vertex-safe for Gemini) — must match what the\n // start request would substitute for an unconfigured model.\n providerDefault: getAcpPreferredDefaultModel(acpServerKey),\n });\n } else {\n currentModelId = conversation?.llm_model ?? settings?.llm_model ?? null;\n }\n\n const displayModel =\n currentModelId && isAcpContext\n ? (labelForAcpModel(acpServerKey, currentModelId) ?? currentModelId)\n : currentModelId;\n const availableAcpModels = acpProvider?.available_models ?? [];\n const showAcpPicker = isAcpContext && availableAcpModels.length > 0;\n const switchConversationId = isActiveAcpConversation\n ? (conversationId ?? null)\n : null;\n\n return {\n isAcpContext,\n displayModel,\n currentModelId,\n availableAcpModels,\n showAcpPicker,\n switchConversationId,\n destinationPath,\n destinationLabel,\n };\n}\n"],"mappings":"sQAuBA,SAAgB,GAA8C,CAC5D,GAAM,CAAE,KAAM,GAAiB,EAAA,uBAAuB,CAChD,CAAE,KAAM,GAAa,EAAA,aAAa,CAClC,CAAE,kBAAmB,EAAA,2BAA2B,CAChD,CACJ,0BACA,YACA,eACA,kBACA,oBACE,EAAA,oBAAoB,CAElB,EAAe,EACjB,GAAc,WACd,GACE,OAAO,GAAU,gBAAgB,YAAe,SAC9C,EAAS,eAAe,WACxB,KAEF,EAAc,EAAe,EAAA,eAAe,EAAa,CAAG,IAAA,GAE5D,EACJ,OAAO,GAAU,gBAAgB,WAAc,SAC3C,EAAS,eAAe,UACxB,KAEF,EAAgC,KACpC,AAkBE,EAlBE,EAKA,GAAc,WACd,EAAA,yBAAyB,CACvB,WAAY,EACZ,gBAAiB,EAAA,4BAA4B,EAAa,CAC3D,CAAC,CACK,EACQ,EAAA,yBAAyB,CACxC,WAAY,EAGZ,gBAAiB,EAAA,4BAA4B,EAAa,CAC3D,CAAC,CAEe,GAAc,WAAa,GAAU,WAAa,KAGrE,IAAM,EACJ,GAAkB,EACb,EAAA,iBAAiB,EAAc,EAAe,EAAI,EACnD,EACA,EAAqB,GAAa,kBAAoB,EAAE,CACxD,EAAgB,GAAgB,EAAmB,OAAS,EAKlE,MAAO,CACL,eACA,eACA,iBACA,qBACA,gBACA,qBAV2B,EACxB,GAAkB,KACnB,KASF,kBACA,mBACD"}
1
+ {"version":3,"file":"use-chat-input-model-state.cjs","names":[],"sources":["../../src/hooks/use-chat-input-model-state.ts"],"sourcesContent":["import { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport {\n type AcpModelContext,\n useAcpModelContext,\n} from \"#/hooks/use-acp-model-context\";\nimport { useOptionalConversationId } from \"#/hooks/use-conversation-id\";\nimport {\n getAcpPreferredDefaultModel,\n getAcpProvider,\n labelForAcpModel,\n resolveEffectiveAcpModel,\n type ACPModelOption,\n} from \"#/constants/acp-providers\";\n\nexport interface ChatInputModelState {\n isAcpContext: boolean;\n displayModel: string | null;\n currentModelId: string | null;\n availableAcpModels: ACPModelOption[];\n showAcpPicker: boolean;\n switchConversationId: string | null;\n destinationPath: AcpModelContext[\"destinationPath\"];\n destinationLabel: string;\n}\n\nexport function useChatInputModelState(): ChatInputModelState {\n const { data: conversation } = useActiveConversation();\n const { data: settings } = useSettings();\n const { conversationId } = useOptionalConversationId();\n const {\n isActiveAcpConversation,\n isHomeAcp,\n isAcpContext,\n destinationPath,\n destinationLabel,\n } = useAcpModelContext();\n\n const acpServerKey = isActiveAcpConversation\n ? conversation?.acp_server\n : isHomeAcp\n ? typeof settings?.agent_settings?.acp_server === \"string\"\n ? settings.agent_settings.acp_server\n : null\n : null;\n const acpProvider = isAcpContext ? getAcpProvider(acpServerKey) : undefined;\n\n const acpConfiguredModel =\n typeof settings?.agent_settings?.acp_model === \"string\"\n ? settings.agent_settings.acp_model\n : null;\n\n let currentModelId: string | null = null;\n if (isActiveAcpConversation) {\n // ACP conversations store llm_model as the acp_model (persisted at\n // creation time). Use it directly if available; fall back to the\n // settings-configured model or provider default so the chip stays visible.\n currentModelId =\n conversation?.llm_model ??\n resolveEffectiveAcpModel({\n configured: acpConfiguredModel,\n providerDefault: getAcpPreferredDefaultModel(acpServerKey),\n });\n } else if (isHomeAcp) {\n currentModelId = resolveEffectiveAcpModel({\n configured: acpConfiguredModel,\n // Preferred default (Vertex-safe for Gemini) — must match what the\n // start request would substitute for an unconfigured model.\n providerDefault: getAcpPreferredDefaultModel(acpServerKey),\n });\n } else {\n currentModelId = conversation?.llm_model ?? settings?.llm_model ?? null;\n }\n\n const displayModel =\n currentModelId && isAcpContext\n ? (labelForAcpModel(acpServerKey, currentModelId) ?? currentModelId)\n : currentModelId;\n const availableAcpModels = acpProvider?.available_models ?? [];\n const showAcpPicker = isAcpContext && availableAcpModels.length > 0;\n const switchConversationId = isActiveAcpConversation\n ? (conversationId ?? null)\n : null;\n\n return {\n isAcpContext,\n displayModel,\n currentModelId,\n availableAcpModels,\n showAcpPicker,\n switchConversationId,\n destinationPath,\n destinationLabel,\n };\n}\n"],"mappings":"sQA0BA,SAAgB,GAA8C,CAC5D,GAAM,CAAE,KAAM,GAAiB,EAAA,uBAAuB,CAChD,CAAE,KAAM,GAAa,EAAA,aAAa,CAClC,CAAE,kBAAmB,EAAA,2BAA2B,CAChD,CACJ,0BACA,YACA,eACA,kBACA,oBACE,EAAA,oBAAoB,CAElB,EAAe,EACjB,GAAc,WACd,GACE,OAAO,GAAU,gBAAgB,YAAe,SAC9C,EAAS,eAAe,WACxB,KAEF,EAAc,EAAe,EAAA,eAAe,EAAa,CAAG,IAAA,GAE5D,EACJ,OAAO,GAAU,gBAAgB,WAAc,SAC3C,EAAS,eAAe,UACxB,KAEF,EAAgC,KACpC,AAkBE,EAlBE,EAKA,GAAc,WACd,EAAA,yBAAyB,CACvB,WAAY,EACZ,gBAAiB,EAAA,4BAA4B,EAAa,CAC3D,CAAC,CACK,EACQ,EAAA,yBAAyB,CACxC,WAAY,EAGZ,gBAAiB,EAAA,4BAA4B,EAAa,CAC3D,CAAC,CAEe,GAAc,WAAa,GAAU,WAAa,KAGrE,IAAM,EACJ,GAAkB,EACb,EAAA,iBAAiB,EAAc,EAAe,EAAI,EACnD,EACA,EAAqB,GAAa,kBAAoB,EAAE,CACxD,EAAgB,GAAgB,EAAmB,OAAS,EAKlE,MAAO,CACL,eACA,eACA,iBACA,qBACA,gBACA,qBAV2B,EACxB,GAAkB,KACnB,KASF,kBACA,mBACD"}
@@ -1,3 +1,4 @@
1
+ import { type AcpModelContext } from "#/hooks/use-acp-model-context";
1
2
  import { type ACPModelOption } from "#/constants/acp-providers";
2
3
  export interface ChatInputModelState {
3
4
  isAcpContext: boolean;
@@ -6,7 +7,7 @@ export interface ChatInputModelState {
6
7
  availableAcpModels: ACPModelOption[];
7
8
  showAcpPicker: boolean;
8
9
  switchConversationId: string | null;
9
- destinationPath: "/settings/agents" | "/settings";
10
+ destinationPath: AcpModelContext["destinationPath"];
10
11
  destinationLabel: string;
11
12
  }
12
13
  export declare function useChatInputModelState(): ChatInputModelState;
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-input-model-state.js","names":[],"sources":["../../src/hooks/use-chat-input-model-state.ts"],"sourcesContent":["import { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useAcpModelContext } from \"#/hooks/use-acp-model-context\";\nimport { useOptionalConversationId } from \"#/hooks/use-conversation-id\";\nimport {\n getAcpPreferredDefaultModel,\n getAcpProvider,\n labelForAcpModel,\n resolveEffectiveAcpModel,\n type ACPModelOption,\n} from \"#/constants/acp-providers\";\n\nexport interface ChatInputModelState {\n isAcpContext: boolean;\n displayModel: string | null;\n currentModelId: string | null;\n availableAcpModels: ACPModelOption[];\n showAcpPicker: boolean;\n switchConversationId: string | null;\n destinationPath: \"/settings/agents\" | \"/settings\";\n destinationLabel: string;\n}\n\nexport function useChatInputModelState(): ChatInputModelState {\n const { data: conversation } = useActiveConversation();\n const { data: settings } = useSettings();\n const { conversationId } = useOptionalConversationId();\n const {\n isActiveAcpConversation,\n isHomeAcp,\n isAcpContext,\n destinationPath,\n destinationLabel,\n } = useAcpModelContext();\n\n const acpServerKey = isActiveAcpConversation\n ? conversation?.acp_server\n : isHomeAcp\n ? typeof settings?.agent_settings?.acp_server === \"string\"\n ? settings.agent_settings.acp_server\n : null\n : null;\n const acpProvider = isAcpContext ? getAcpProvider(acpServerKey) : undefined;\n\n const acpConfiguredModel =\n typeof settings?.agent_settings?.acp_model === \"string\"\n ? settings.agent_settings.acp_model\n : null;\n\n let currentModelId: string | null = null;\n if (isActiveAcpConversation) {\n // ACP conversations store llm_model as the acp_model (persisted at\n // creation time). Use it directly if available; fall back to the\n // settings-configured model or provider default so the chip stays visible.\n currentModelId =\n conversation?.llm_model ??\n resolveEffectiveAcpModel({\n configured: acpConfiguredModel,\n providerDefault: getAcpPreferredDefaultModel(acpServerKey),\n });\n } else if (isHomeAcp) {\n currentModelId = resolveEffectiveAcpModel({\n configured: acpConfiguredModel,\n // Preferred default (Vertex-safe for Gemini) — must match what the\n // start request would substitute for an unconfigured model.\n providerDefault: getAcpPreferredDefaultModel(acpServerKey),\n });\n } else {\n currentModelId = conversation?.llm_model ?? settings?.llm_model ?? null;\n }\n\n const displayModel =\n currentModelId && isAcpContext\n ? (labelForAcpModel(acpServerKey, currentModelId) ?? currentModelId)\n : currentModelId;\n const availableAcpModels = acpProvider?.available_models ?? [];\n const showAcpPicker = isAcpContext && availableAcpModels.length > 0;\n const switchConversationId = isActiveAcpConversation\n ? (conversationId ?? null)\n : null;\n\n return {\n isAcpContext,\n displayModel,\n currentModelId,\n availableAcpModels,\n showAcpPicker,\n switchConversationId,\n destinationPath,\n destinationLabel,\n };\n}\n"],"mappings":";;;;;;AAuBA,SAAgB,IAA8C;CAC5D,IAAM,EAAE,MAAM,MAAiB,GAAuB,EAChD,EAAE,MAAM,MAAa,GAAa,EAClC,EAAE,sBAAmB,GAA2B,EAChD,EACJ,4BACA,cACA,iBACA,oBACA,wBACE,GAAoB,EAElB,IAAe,IACjB,GAAc,aACd,KACE,OAAO,GAAU,gBAAgB,cAAe,WAC9C,EAAS,eAAe,aACxB,MAEF,IAAc,IAAe,EAAe,EAAa,GAAG,KAAA,GAE5D,IACJ,OAAO,GAAU,gBAAgB,aAAc,WAC3C,EAAS,eAAe,YACxB,MAEF,IAAgC;AACpC,CAkBE,IAlBE,IAKA,GAAc,aACd,EAAyB;EACvB,YAAY;EACZ,iBAAiB,EAA4B,EAAa;EAC3D,CAAC,GACK,IACQ,EAAyB;EACxC,YAAY;EAGZ,iBAAiB,EAA4B,EAAa;EAC3D,CAAC,GAEe,GAAc,aAAa,GAAU,aAAa;CAGrE,IAAM,IACJ,KAAkB,IACb,EAAiB,GAAc,EAAe,IAAI,IACnD,GACA,IAAqB,GAAa,oBAAoB,EAAE,EACxD,IAAgB,KAAgB,EAAmB,SAAS;AAKlE,QAAO;EACL;EACA;EACA;EACA;EACA;EACA,sBAV2B,IACxB,KAAkB,OACnB;EASF;EACA;EACD"}
1
+ {"version":3,"file":"use-chat-input-model-state.js","names":[],"sources":["../../src/hooks/use-chat-input-model-state.ts"],"sourcesContent":["import { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport {\n type AcpModelContext,\n useAcpModelContext,\n} from \"#/hooks/use-acp-model-context\";\nimport { useOptionalConversationId } from \"#/hooks/use-conversation-id\";\nimport {\n getAcpPreferredDefaultModel,\n getAcpProvider,\n labelForAcpModel,\n resolveEffectiveAcpModel,\n type ACPModelOption,\n} from \"#/constants/acp-providers\";\n\nexport interface ChatInputModelState {\n isAcpContext: boolean;\n displayModel: string | null;\n currentModelId: string | null;\n availableAcpModels: ACPModelOption[];\n showAcpPicker: boolean;\n switchConversationId: string | null;\n destinationPath: AcpModelContext[\"destinationPath\"];\n destinationLabel: string;\n}\n\nexport function useChatInputModelState(): ChatInputModelState {\n const { data: conversation } = useActiveConversation();\n const { data: settings } = useSettings();\n const { conversationId } = useOptionalConversationId();\n const {\n isActiveAcpConversation,\n isHomeAcp,\n isAcpContext,\n destinationPath,\n destinationLabel,\n } = useAcpModelContext();\n\n const acpServerKey = isActiveAcpConversation\n ? conversation?.acp_server\n : isHomeAcp\n ? typeof settings?.agent_settings?.acp_server === \"string\"\n ? settings.agent_settings.acp_server\n : null\n : null;\n const acpProvider = isAcpContext ? getAcpProvider(acpServerKey) : undefined;\n\n const acpConfiguredModel =\n typeof settings?.agent_settings?.acp_model === \"string\"\n ? settings.agent_settings.acp_model\n : null;\n\n let currentModelId: string | null = null;\n if (isActiveAcpConversation) {\n // ACP conversations store llm_model as the acp_model (persisted at\n // creation time). Use it directly if available; fall back to the\n // settings-configured model or provider default so the chip stays visible.\n currentModelId =\n conversation?.llm_model ??\n resolveEffectiveAcpModel({\n configured: acpConfiguredModel,\n providerDefault: getAcpPreferredDefaultModel(acpServerKey),\n });\n } else if (isHomeAcp) {\n currentModelId = resolveEffectiveAcpModel({\n configured: acpConfiguredModel,\n // Preferred default (Vertex-safe for Gemini) — must match what the\n // start request would substitute for an unconfigured model.\n providerDefault: getAcpPreferredDefaultModel(acpServerKey),\n });\n } else {\n currentModelId = conversation?.llm_model ?? settings?.llm_model ?? null;\n }\n\n const displayModel =\n currentModelId && isAcpContext\n ? (labelForAcpModel(acpServerKey, currentModelId) ?? currentModelId)\n : currentModelId;\n const availableAcpModels = acpProvider?.available_models ?? [];\n const showAcpPicker = isAcpContext && availableAcpModels.length > 0;\n const switchConversationId = isActiveAcpConversation\n ? (conversationId ?? null)\n : null;\n\n return {\n isAcpContext,\n displayModel,\n currentModelId,\n availableAcpModels,\n showAcpPicker,\n switchConversationId,\n destinationPath,\n destinationLabel,\n };\n}\n"],"mappings":";;;;;;AA0BA,SAAgB,IAA8C;CAC5D,IAAM,EAAE,MAAM,MAAiB,GAAuB,EAChD,EAAE,MAAM,MAAa,GAAa,EAClC,EAAE,sBAAmB,GAA2B,EAChD,EACJ,4BACA,cACA,iBACA,oBACA,wBACE,GAAoB,EAElB,IAAe,IACjB,GAAc,aACd,KACE,OAAO,GAAU,gBAAgB,cAAe,WAC9C,EAAS,eAAe,aACxB,MAEF,IAAc,IAAe,EAAe,EAAa,GAAG,KAAA,GAE5D,IACJ,OAAO,GAAU,gBAAgB,aAAc,WAC3C,EAAS,eAAe,YACxB,MAEF,IAAgC;AACpC,CAkBE,IAlBE,IAKA,GAAc,aACd,EAAyB;EACvB,YAAY;EACZ,iBAAiB,EAA4B,EAAa;EAC3D,CAAC,GACK,IACQ,EAAyB;EACxC,YAAY;EAGZ,iBAAiB,EAA4B,EAAa;EAC3D,CAAC,GAEe,GAAc,aAAa,GAAU,aAAa;CAGrE,IAAM,IACJ,KAAkB,IACb,EAAiB,GAAc,EAAe,IAAI,IACnD,GACA,IAAqB,GAAa,oBAAoB,EAAE,EACxD,IAAgB,KAAgB,EAAmB,SAAS;AAKlE,QAAO;EACL;EACA;EACA;EACA;EACA;EACA,sBAV2B,IACxB,KAAkB,OACnB;EASF;EACA;EACD"}
@@ -1,2 +1,2 @@
1
- require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../node_modules/@tanstack/react-query/build/modern/useMutationState.cjs`),t=require(`./query/use-agent-profiles.cjs`),n=require(`./mutation/use-activate-agent-profile.cjs`);let r=require(`react`);function i(){let{data:i,isLoading:a}=t.useAgentProfiles(),o=n.useActivateAgentProfile(),s=e.useIsMutating({mutationKey:n.ACTIVATE_AGENT_PROFILE_MUTATION_KEY})>0,c=i?.profiles??[],l=i?.active_agent_profile_id??null;return{profiles:c,currentProfileId:l,currentProfileName:c.find(e=>e.id!=null&&e.id===l)?.name??null,isLoading:a,isSwitching:s,selectProfile:(0,r.useCallback)(e=>{!e.id||e.id===l||o.mutate(e.id)},[l,o])}}exports.useChatInputProfileState=i;
1
+ require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../context/navigation-context.cjs`),t=require(`../node_modules/@tanstack/react-query/build/modern/useMutationState.cjs`),n=require(`../api/conversation-metadata-store.cjs`),r=require(`./query/use-active-conversation.cjs`),i=require(`./query/use-agent-profiles.cjs`),a=require(`./mutation/use-create-conversation.cjs`),o=require(`./mutation/use-activate-agent-profile.cjs`);let s=require(`react`);function c(){let{conversationId:c,navigate:l}=e.useNavigation(),{data:u,isLoading:d}=r.useActiveConversation(),{data:f,isLoading:p}=i.useAgentProfiles(),m=a.useCreateConversation(),h=o.useActivateAgentProfile(),g=t.useIsMutating({mutationKey:o.ACTIVATE_AGENT_PROFILE_MUTATION_KEY}),_=t.useIsMutating({mutationKey:a.CREATE_CONVERSATION_MUTATION_KEY}),v=c?.startsWith(`task-`)??!1,y=v||g>0||_>0,b=f?.profiles??[],x=!!c,S=x?u?.launched_agent_profile?.agent_profile_id??f?.active_agent_profile_id??null:f?.active_agent_profile_id??null,C=b.find(e=>e.id!=null&&e.id===S)?.name??null,w=(0,s.useCallback)(e=>{if(v||!e.id||e.id===S)return;if(!x){h.mutate(e.id);return}let t=c?n.getStoredConversationMetadata(c):null,r={agentProfileId:e.id,entryPoint:`blank_conversation_profile_picker`};u?.selected_repository&&(r.repository={name:u.selected_repository,gitProvider:u.git_provider??`github`,branch:u.selected_branch??void 0}),u?.selected_workspace&&(r.workingDir=u.selected_workspace,r.workspaceMode=t?.workspace_mode??`local_repo`),t?.plugins?.length&&(r.plugins=t.plugins),m.mutate(r,{onSuccess:e=>l(`/conversations/${e.conversation_id}`)})},[h,u,c,m,S,x,v,l]);return{profiles:b,currentProfileId:S,currentProfileName:C,isInConversation:x,isLoading:p||v||x&&d,isSwitching:y,selectProfile:w}}exports.useChatInputProfileState=c;
2
2
  //# sourceMappingURL=use-chat-input-profile-state.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-input-profile-state.cjs","names":[],"sources":["../../src/hooks/use-chat-input-profile-state.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { useIsMutating } from \"@tanstack/react-query\";\nimport type { AgentProfileSummary } from \"#/api/agent-profiles-service/agent-profiles-service.api\";\nimport { useAgentProfiles } from \"#/hooks/query/use-agent-profiles\";\nimport {\n useActivateAgentProfile,\n ACTIVATE_AGENT_PROFILE_MUTATION_KEY,\n} from \"#/hooks/mutation/use-activate-agent-profile\";\n\nexport interface ChatInputProfileState {\n profiles: AgentProfileSummary[];\n /** id of the active profile the next conversation will launch from. */\n currentProfileId: string | null;\n currentProfileName: string | null;\n isLoading: boolean;\n isSwitching: boolean;\n /** Activate a profile so the next conversation launches from it. */\n selectProfile: (profile: AgentProfileSummary) => void;\n}\n\n/**\n * Backs the home chat-input AgentProfile picker. This picker is only rendered\n * on the home screen — inside a conversation the chat input shows the\n * in-conversation LLM-profile picker (OpenHands) or model picker (ACP) instead\n * (see `chat-input-actions.tsx` `pickerKind`). So selecting a profile here\n * simply activates it as the launch default; `useCreateConversation` reads the\n * active profile when the next conversation starts.\n */\nexport function useChatInputProfileState(): ChatInputProfileState {\n const { data: agentProfiles, isLoading } = useAgentProfiles();\n const activateProfile = useActivateAgentProfile();\n // Observe the activation globally by mutation key so the picker button (a\n // separate hook instance from the menu that fires it) disables correctly\n // while a switch is in flight (#1571).\n const isSwitching =\n useIsMutating({ mutationKey: ACTIVATE_AGENT_PROFILE_MUTATION_KEY }) > 0;\n\n const profiles = agentProfiles?.profiles ?? [];\n const currentProfileId = agentProfiles?.active_agent_profile_id ?? null;\n const currentProfileName =\n profiles.find((p) => p.id != null && p.id === currentProfileId)?.name ??\n null;\n\n const selectProfile = useCallback(\n (profile: AgentProfileSummary) => {\n if (!profile.id || profile.id === currentProfileId) return;\n activateProfile.mutate(profile.id);\n },\n [currentProfileId, activateProfile],\n );\n\n return {\n profiles,\n currentProfileId,\n currentProfileName,\n isLoading,\n isSwitching,\n selectProfile,\n };\n}\n"],"mappings":"kQA4BA,SAAgB,GAAkD,CAChE,GAAM,CAAE,KAAM,EAAe,aAAc,EAAA,kBAAkB,CACvD,EAAkB,EAAA,yBAAyB,CAI3C,EACJ,EAAA,cAAc,CAAE,YAAa,EAAA,oCAAqC,CAAC,CAAG,EAElE,EAAW,GAAe,UAAY,EAAE,CACxC,EAAmB,GAAe,yBAA2B,KAanE,MAAO,CACL,WACA,mBACA,mBAdA,EAAS,KAAM,GAAM,EAAE,IAAM,MAAQ,EAAE,KAAO,EAAiB,EAAE,MACjE,KAcA,YACA,cACA,eAAA,EAAA,EAAA,aAbC,GAAiC,CAC5B,CAAC,EAAQ,IAAM,EAAQ,KAAO,GAClC,EAAgB,OAAO,EAAQ,GAAG,EAEpC,CAAC,EAAkB,EAAgB,CASnC,CACD"}
1
+ {"version":3,"file":"use-chat-input-profile-state.cjs","names":[],"sources":["../../src/hooks/use-chat-input-profile-state.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { useIsMutating } from \"@tanstack/react-query\";\nimport type { AgentProfileSummary } from \"#/api/agent-profiles-service/agent-profiles-service.api\";\nimport { getStoredConversationMetadata } from \"#/api/conversation-metadata-store\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { useAgentProfiles } from \"#/hooks/query/use-agent-profiles\";\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport {\n CREATE_CONVERSATION_MUTATION_KEY,\n useCreateConversation,\n type CreateConversationVariables,\n} from \"#/hooks/mutation/use-create-conversation\";\nimport {\n useActivateAgentProfile,\n ACTIVATE_AGENT_PROFILE_MUTATION_KEY,\n} from \"#/hooks/mutation/use-activate-agent-profile\";\n\nexport interface ChatInputProfileState {\n profiles: AgentProfileSummary[];\n currentProfileId: string | null;\n currentProfileName: string | null;\n isInConversation: boolean;\n isLoading: boolean;\n isSwitching: boolean;\n selectProfile: (profile: AgentProfileSummary) => void;\n}\n\nexport function useChatInputProfileState(): ChatInputProfileState {\n const { conversationId, navigate } = useNavigation();\n const { data: conversation, isLoading: isLoadingConversation } =\n useActiveConversation();\n const { data: agentProfiles, isLoading: isLoadingProfiles } =\n useAgentProfiles();\n const createConversation = useCreateConversation();\n const activateProfile = useActivateAgentProfile();\n const activatingProfiles = useIsMutating({\n mutationKey: ACTIVATE_AGENT_PROFILE_MUTATION_KEY,\n });\n const creatingConversations = useIsMutating({\n mutationKey: CREATE_CONVERSATION_MUTATION_KEY,\n });\n const isTaskRoute = conversationId?.startsWith(\"task-\") ?? false;\n const isSwitching =\n isTaskRoute || activatingProfiles > 0 || creatingConversations > 0;\n\n const profiles = agentProfiles?.profiles ?? [];\n const isInConversation = Boolean(conversationId);\n const currentProfileId = isInConversation\n ? (conversation?.launched_agent_profile?.agent_profile_id ??\n agentProfiles?.active_agent_profile_id ??\n null)\n : (agentProfiles?.active_agent_profile_id ?? null);\n const currentProfileName =\n profiles.find((p) => p.id != null && p.id === currentProfileId)?.name ??\n null;\n\n const selectProfile = useCallback(\n (profile: AgentProfileSummary) => {\n if (isTaskRoute || !profile.id || profile.id === currentProfileId) return;\n if (!isInConversation) {\n activateProfile.mutate(profile.id);\n return;\n }\n\n const metadata = conversationId\n ? getStoredConversationMetadata(conversationId)\n : null;\n const variables: CreateConversationVariables = {\n agentProfileId: profile.id,\n entryPoint: \"blank_conversation_profile_picker\",\n };\n if (conversation?.selected_repository) {\n variables.repository = {\n name: conversation.selected_repository,\n gitProvider: conversation.git_provider ?? \"github\",\n branch: conversation.selected_branch ?? undefined,\n };\n }\n if (conversation?.selected_workspace) {\n variables.workingDir = conversation.selected_workspace;\n variables.workspaceMode = metadata?.workspace_mode ?? \"local_repo\";\n }\n if (metadata?.plugins?.length) {\n variables.plugins = metadata.plugins;\n }\n\n createConversation.mutate(variables, {\n onSuccess: (data) => navigate(`/conversations/${data.conversation_id}`),\n });\n },\n [\n activateProfile,\n conversation,\n conversationId,\n createConversation,\n currentProfileId,\n isInConversation,\n isTaskRoute,\n navigate,\n ],\n );\n\n return {\n profiles,\n currentProfileId,\n currentProfileName,\n isInConversation,\n isLoading:\n isLoadingProfiles ||\n isTaskRoute ||\n (isInConversation && isLoadingConversation),\n isSwitching,\n selectProfile,\n };\n}\n"],"mappings":"0cA2BA,SAAgB,GAAkD,CAChE,GAAM,CAAE,iBAAgB,YAAa,EAAA,eAAe,CAC9C,CAAE,KAAM,EAAc,UAAW,GACrC,EAAA,uBAAuB,CACnB,CAAE,KAAM,EAAe,UAAW,GACtC,EAAA,kBAAkB,CACd,EAAqB,EAAA,uBAAuB,CAC5C,EAAkB,EAAA,yBAAyB,CAC3C,EAAqB,EAAA,cAAc,CACvC,YAAa,EAAA,oCACd,CAAC,CACI,EAAwB,EAAA,cAAc,CAC1C,YAAa,EAAA,iCACd,CAAC,CACI,EAAc,GAAgB,WAAW,QAAQ,EAAI,GACrD,EACJ,GAAe,EAAqB,GAAK,EAAwB,EAE7D,EAAW,GAAe,UAAY,EAAE,CACxC,EAAmB,EAAQ,EAC3B,EAAmB,EACpB,GAAc,wBAAwB,kBACvC,GAAe,yBACf,KACC,GAAe,yBAA2B,KACzC,EACJ,EAAS,KAAM,GAAM,EAAE,IAAM,MAAQ,EAAE,KAAO,EAAiB,EAAE,MACjE,KAEI,GAAA,EAAA,EAAA,aACH,GAAiC,CAChC,GAAI,GAAe,CAAC,EAAQ,IAAM,EAAQ,KAAO,EAAkB,OACnE,GAAI,CAAC,EAAkB,CACrB,EAAgB,OAAO,EAAQ,GAAG,CAClC,OAGF,IAAM,EAAW,EACb,EAAA,8BAA8B,EAAe,CAC7C,KACE,EAAyC,CAC7C,eAAgB,EAAQ,GACxB,WAAY,oCACb,CACG,GAAc,sBAChB,EAAU,WAAa,CACrB,KAAM,EAAa,oBACnB,YAAa,EAAa,cAAgB,SAC1C,OAAQ,EAAa,iBAAmB,IAAA,GACzC,EAEC,GAAc,qBAChB,EAAU,WAAa,EAAa,mBACpC,EAAU,cAAgB,GAAU,gBAAkB,cAEpD,GAAU,SAAS,SACrB,EAAU,QAAU,EAAS,SAG/B,EAAmB,OAAO,EAAW,CACnC,UAAY,GAAS,EAAS,kBAAkB,EAAK,kBAAkB,CACxE,CAAC,EAEJ,CACE,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACD,CACF,CAED,MAAO,CACL,WACA,mBACA,qBACA,mBACA,UACE,GACA,GACC,GAAoB,EACvB,cACA,gBACD"}
@@ -1,20 +1,11 @@
1
1
  import type { AgentProfileSummary } from "#/api/agent-profiles-service/agent-profiles-service.api";
2
2
  export interface ChatInputProfileState {
3
3
  profiles: AgentProfileSummary[];
4
- /** id of the active profile the next conversation will launch from. */
5
4
  currentProfileId: string | null;
6
5
  currentProfileName: string | null;
6
+ isInConversation: boolean;
7
7
  isLoading: boolean;
8
8
  isSwitching: boolean;
9
- /** Activate a profile so the next conversation launches from it. */
10
9
  selectProfile: (profile: AgentProfileSummary) => void;
11
10
  }
12
- /**
13
- * Backs the home chat-input AgentProfile picker. This picker is only rendered
14
- * on the home screen — inside a conversation the chat input shows the
15
- * in-conversation LLM-profile picker (OpenHands) or model picker (ACP) instead
16
- * (see `chat-input-actions.tsx` `pickerKind`). So selecting a profile here
17
- * simply activates it as the launch default; `useCreateConversation` reads the
18
- * active profile when the next conversation starts.
19
- */
20
11
  export declare function useChatInputProfileState(): ChatInputProfileState;
@@ -1,22 +1,49 @@
1
- import { useIsMutating as e } from "../node_modules/@tanstack/react-query/build/modern/useMutationState.js";
2
- import { useAgentProfiles as t } from "./query/use-agent-profiles.js";
3
- import { ACTIVATE_AGENT_PROFILE_MUTATION_KEY as n, useActivateAgentProfile as r } from "./mutation/use-activate-agent-profile.js";
4
- import { useCallback as i } from "react";
1
+ import { useNavigation as e } from "../context/navigation-context.js";
2
+ import { useIsMutating as t } from "../node_modules/@tanstack/react-query/build/modern/useMutationState.js";
3
+ import { getStoredConversationMetadata as n } from "../api/conversation-metadata-store.js";
4
+ import { useActiveConversation as r } from "./query/use-active-conversation.js";
5
+ import { useAgentProfiles as i } from "./query/use-agent-profiles.js";
6
+ import { CREATE_CONVERSATION_MUTATION_KEY as a, useCreateConversation as o } from "./mutation/use-create-conversation.js";
7
+ import { ACTIVATE_AGENT_PROFILE_MUTATION_KEY as s, useActivateAgentProfile as c } from "./mutation/use-activate-agent-profile.js";
8
+ import { useCallback as l } from "react";
5
9
  //#region src/hooks/use-chat-input-profile-state.ts
6
- function a() {
7
- let { data: a, isLoading: o } = t(), s = r(), c = e({ mutationKey: n }) > 0, l = a?.profiles ?? [], u = a?.active_agent_profile_id ?? null;
10
+ function u() {
11
+ let { conversationId: u, navigate: d } = e(), { data: f, isLoading: p } = r(), { data: m, isLoading: h } = i(), g = o(), _ = c(), v = t({ mutationKey: s }), y = t({ mutationKey: a }), b = u?.startsWith("task-") ?? !1, x = b || v > 0 || y > 0, S = m?.profiles ?? [], C = !!u, w = C ? f?.launched_agent_profile?.agent_profile_id ?? m?.active_agent_profile_id ?? null : m?.active_agent_profile_id ?? null, T = S.find((e) => e.id != null && e.id === w)?.name ?? null, E = l((e) => {
12
+ if (b || !e.id || e.id === w) return;
13
+ if (!C) {
14
+ _.mutate(e.id);
15
+ return;
16
+ }
17
+ let t = u ? n(u) : null, r = {
18
+ agentProfileId: e.id,
19
+ entryPoint: "blank_conversation_profile_picker"
20
+ };
21
+ f?.selected_repository && (r.repository = {
22
+ name: f.selected_repository,
23
+ gitProvider: f.git_provider ?? "github",
24
+ branch: f.selected_branch ?? void 0
25
+ }), f?.selected_workspace && (r.workingDir = f.selected_workspace, r.workspaceMode = t?.workspace_mode ?? "local_repo"), t?.plugins?.length && (r.plugins = t.plugins), g.mutate(r, { onSuccess: (e) => d(`/conversations/${e.conversation_id}`) });
26
+ }, [
27
+ _,
28
+ f,
29
+ u,
30
+ g,
31
+ w,
32
+ C,
33
+ b,
34
+ d
35
+ ]);
8
36
  return {
9
- profiles: l,
10
- currentProfileId: u,
11
- currentProfileName: l.find((e) => e.id != null && e.id === u)?.name ?? null,
12
- isLoading: o,
13
- isSwitching: c,
14
- selectProfile: i((e) => {
15
- !e.id || e.id === u || s.mutate(e.id);
16
- }, [u, s])
37
+ profiles: S,
38
+ currentProfileId: w,
39
+ currentProfileName: T,
40
+ isInConversation: C,
41
+ isLoading: h || b || C && p,
42
+ isSwitching: x,
43
+ selectProfile: E
17
44
  };
18
45
  }
19
46
  //#endregion
20
- export { a as useChatInputProfileState };
47
+ export { u as useChatInputProfileState };
21
48
 
22
49
  //# sourceMappingURL=use-chat-input-profile-state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-input-profile-state.js","names":[],"sources":["../../src/hooks/use-chat-input-profile-state.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { useIsMutating } from \"@tanstack/react-query\";\nimport type { AgentProfileSummary } from \"#/api/agent-profiles-service/agent-profiles-service.api\";\nimport { useAgentProfiles } from \"#/hooks/query/use-agent-profiles\";\nimport {\n useActivateAgentProfile,\n ACTIVATE_AGENT_PROFILE_MUTATION_KEY,\n} from \"#/hooks/mutation/use-activate-agent-profile\";\n\nexport interface ChatInputProfileState {\n profiles: AgentProfileSummary[];\n /** id of the active profile the next conversation will launch from. */\n currentProfileId: string | null;\n currentProfileName: string | null;\n isLoading: boolean;\n isSwitching: boolean;\n /** Activate a profile so the next conversation launches from it. */\n selectProfile: (profile: AgentProfileSummary) => void;\n}\n\n/**\n * Backs the home chat-input AgentProfile picker. This picker is only rendered\n * on the home screen — inside a conversation the chat input shows the\n * in-conversation LLM-profile picker (OpenHands) or model picker (ACP) instead\n * (see `chat-input-actions.tsx` `pickerKind`). So selecting a profile here\n * simply activates it as the launch default; `useCreateConversation` reads the\n * active profile when the next conversation starts.\n */\nexport function useChatInputProfileState(): ChatInputProfileState {\n const { data: agentProfiles, isLoading } = useAgentProfiles();\n const activateProfile = useActivateAgentProfile();\n // Observe the activation globally by mutation key so the picker button (a\n // separate hook instance from the menu that fires it) disables correctly\n // while a switch is in flight (#1571).\n const isSwitching =\n useIsMutating({ mutationKey: ACTIVATE_AGENT_PROFILE_MUTATION_KEY }) > 0;\n\n const profiles = agentProfiles?.profiles ?? [];\n const currentProfileId = agentProfiles?.active_agent_profile_id ?? null;\n const currentProfileName =\n profiles.find((p) => p.id != null && p.id === currentProfileId)?.name ??\n null;\n\n const selectProfile = useCallback(\n (profile: AgentProfileSummary) => {\n if (!profile.id || profile.id === currentProfileId) return;\n activateProfile.mutate(profile.id);\n },\n [currentProfileId, activateProfile],\n );\n\n return {\n profiles,\n currentProfileId,\n currentProfileName,\n isLoading,\n isSwitching,\n selectProfile,\n };\n}\n"],"mappings":";;;;;AA4BA,SAAgB,IAAkD;CAChE,IAAM,EAAE,MAAM,GAAe,iBAAc,GAAkB,EACvD,IAAkB,GAAyB,EAI3C,IACJ,EAAc,EAAE,aAAa,GAAqC,CAAC,GAAG,GAElE,IAAW,GAAe,YAAY,EAAE,EACxC,IAAmB,GAAe,2BAA2B;AAanE,QAAO;EACL;EACA;EACA,oBAdA,EAAS,MAAM,MAAM,EAAE,MAAM,QAAQ,EAAE,OAAO,EAAiB,EAAE,QACjE;EAcA;EACA;EACA,eAdoB,GACnB,MAAiC;AAC5B,IAAC,EAAQ,MAAM,EAAQ,OAAO,KAClC,EAAgB,OAAO,EAAQ,GAAG;KAEpC,CAAC,GAAkB,EAAgB,CASnC;EACD"}
1
+ {"version":3,"file":"use-chat-input-profile-state.js","names":[],"sources":["../../src/hooks/use-chat-input-profile-state.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { useIsMutating } from \"@tanstack/react-query\";\nimport type { AgentProfileSummary } from \"#/api/agent-profiles-service/agent-profiles-service.api\";\nimport { getStoredConversationMetadata } from \"#/api/conversation-metadata-store\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { useAgentProfiles } from \"#/hooks/query/use-agent-profiles\";\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport {\n CREATE_CONVERSATION_MUTATION_KEY,\n useCreateConversation,\n type CreateConversationVariables,\n} from \"#/hooks/mutation/use-create-conversation\";\nimport {\n useActivateAgentProfile,\n ACTIVATE_AGENT_PROFILE_MUTATION_KEY,\n} from \"#/hooks/mutation/use-activate-agent-profile\";\n\nexport interface ChatInputProfileState {\n profiles: AgentProfileSummary[];\n currentProfileId: string | null;\n currentProfileName: string | null;\n isInConversation: boolean;\n isLoading: boolean;\n isSwitching: boolean;\n selectProfile: (profile: AgentProfileSummary) => void;\n}\n\nexport function useChatInputProfileState(): ChatInputProfileState {\n const { conversationId, navigate } = useNavigation();\n const { data: conversation, isLoading: isLoadingConversation } =\n useActiveConversation();\n const { data: agentProfiles, isLoading: isLoadingProfiles } =\n useAgentProfiles();\n const createConversation = useCreateConversation();\n const activateProfile = useActivateAgentProfile();\n const activatingProfiles = useIsMutating({\n mutationKey: ACTIVATE_AGENT_PROFILE_MUTATION_KEY,\n });\n const creatingConversations = useIsMutating({\n mutationKey: CREATE_CONVERSATION_MUTATION_KEY,\n });\n const isTaskRoute = conversationId?.startsWith(\"task-\") ?? false;\n const isSwitching =\n isTaskRoute || activatingProfiles > 0 || creatingConversations > 0;\n\n const profiles = agentProfiles?.profiles ?? [];\n const isInConversation = Boolean(conversationId);\n const currentProfileId = isInConversation\n ? (conversation?.launched_agent_profile?.agent_profile_id ??\n agentProfiles?.active_agent_profile_id ??\n null)\n : (agentProfiles?.active_agent_profile_id ?? null);\n const currentProfileName =\n profiles.find((p) => p.id != null && p.id === currentProfileId)?.name ??\n null;\n\n const selectProfile = useCallback(\n (profile: AgentProfileSummary) => {\n if (isTaskRoute || !profile.id || profile.id === currentProfileId) return;\n if (!isInConversation) {\n activateProfile.mutate(profile.id);\n return;\n }\n\n const metadata = conversationId\n ? getStoredConversationMetadata(conversationId)\n : null;\n const variables: CreateConversationVariables = {\n agentProfileId: profile.id,\n entryPoint: \"blank_conversation_profile_picker\",\n };\n if (conversation?.selected_repository) {\n variables.repository = {\n name: conversation.selected_repository,\n gitProvider: conversation.git_provider ?? \"github\",\n branch: conversation.selected_branch ?? undefined,\n };\n }\n if (conversation?.selected_workspace) {\n variables.workingDir = conversation.selected_workspace;\n variables.workspaceMode = metadata?.workspace_mode ?? \"local_repo\";\n }\n if (metadata?.plugins?.length) {\n variables.plugins = metadata.plugins;\n }\n\n createConversation.mutate(variables, {\n onSuccess: (data) => navigate(`/conversations/${data.conversation_id}`),\n });\n },\n [\n activateProfile,\n conversation,\n conversationId,\n createConversation,\n currentProfileId,\n isInConversation,\n isTaskRoute,\n navigate,\n ],\n );\n\n return {\n profiles,\n currentProfileId,\n currentProfileName,\n isInConversation,\n isLoading:\n isLoadingProfiles ||\n isTaskRoute ||\n (isInConversation && isLoadingConversation),\n isSwitching,\n selectProfile,\n };\n}\n"],"mappings":";;;;;;;;;AA2BA,SAAgB,IAAkD;CAChE,IAAM,EAAE,mBAAgB,gBAAa,GAAe,EAC9C,EAAE,MAAM,GAAc,WAAW,MACrC,GAAuB,EACnB,EAAE,MAAM,GAAe,WAAW,MACtC,GAAkB,EACd,IAAqB,GAAuB,EAC5C,IAAkB,GAAyB,EAC3C,IAAqB,EAAc,EACvC,aAAa,GACd,CAAC,EACI,IAAwB,EAAc,EAC1C,aAAa,GACd,CAAC,EACI,IAAc,GAAgB,WAAW,QAAQ,IAAI,IACrD,IACJ,KAAe,IAAqB,KAAK,IAAwB,GAE7D,IAAW,GAAe,YAAY,EAAE,EACxC,IAAmB,EAAQ,GAC3B,IAAmB,IACpB,GAAc,wBAAwB,oBACvC,GAAe,2BACf,OACC,GAAe,2BAA2B,MACzC,IACJ,EAAS,MAAM,MAAM,EAAE,MAAM,QAAQ,EAAE,OAAO,EAAiB,EAAE,QACjE,MAEI,IAAgB,GACnB,MAAiC;AAChC,MAAI,KAAe,CAAC,EAAQ,MAAM,EAAQ,OAAO,EAAkB;AACnE,MAAI,CAAC,GAAkB;AACrB,KAAgB,OAAO,EAAQ,GAAG;AAClC;;EAGF,IAAM,IAAW,IACb,EAA8B,EAAe,GAC7C,MACE,IAAyC;GAC7C,gBAAgB,EAAQ;GACxB,YAAY;GACb;AAgBD,EAfI,GAAc,wBAChB,EAAU,aAAa;GACrB,MAAM,EAAa;GACnB,aAAa,EAAa,gBAAgB;GAC1C,QAAQ,EAAa,mBAAmB,KAAA;GACzC,GAEC,GAAc,uBAChB,EAAU,aAAa,EAAa,oBACpC,EAAU,gBAAgB,GAAU,kBAAkB,eAEpD,GAAU,SAAS,WACrB,EAAU,UAAU,EAAS,UAG/B,EAAmB,OAAO,GAAW,EACnC,YAAY,MAAS,EAAS,kBAAkB,EAAK,kBAAkB,EACxE,CAAC;IAEJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,QAAO;EACL;EACA;EACA;EACA;EACA,WACE,KACA,KACC,KAAoB;EACvB;EACA;EACD"}
@@ -1,2 +1,2 @@
1
- const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../api/device-flow-client.cjs`);let n=require(`react`);n=e.__toESM(n,1);var r={status:`idle`,verificationUrl:null,userCode:null,apiKey:null,error:null,errorCode:null};function i(){let[e,i]=n.default.useState(r),a=n.default.useRef(null),o=n.default.useCallback(e=>{a.current?.abort();let n=new AbortController;a.current=n,i({...r,status:`starting`}),(async()=>{let a;try{a=await t.startDeviceFlow(e)}catch(e){if(n.signal.aborted)return;let a=e instanceof Error?e.message:`Failed to start device flow`,o=e instanceof t.DeviceFlowError?e.code:void 0;i({...r,status:`error`,error:a,errorCode:o??null});return}if(!n.signal.aborted){i({...r,status:`awaiting_authorization`,verificationUrl:a.verification_uri_complete,userCode:a.user_code});try{let o=await t.pollForToken(e,a.device_code,{interval:a.interval,signal:n.signal});if(n.signal.aborted)return;i({...r,status:`success`,apiKey:o.access_token})}catch(e){if(n.signal.aborted)return;if(e instanceof t.DeviceFlowError&&e.code===`cancelled`){i(r);return}let a=e instanceof Error?e.message:`Authorization failed`,o=e instanceof t.DeviceFlowError?e.code:void 0;i({...r,status:`error`,error:a,errorCode:o??null})}}})()},[]),s=n.default.useCallback(()=>{a.current?.abort(),a.current=null,i(r)},[]),c=n.default.useCallback(()=>{a.current?.abort(),a.current=null,i(r)},[]);return n.default.useEffect(()=>()=>{a.current?.abort()},[]),{...e,start:o,cancel:s,reset:c}}exports.useDeviceFlow=i;
1
+ const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../node_modules/@openhands/typescript-client/dist/client/device-flow-client.cjs`),n=require(`../api/device-flow-client.cjs`),r=require(`../services/cloud-funnel-analytics.cjs`);let i=require(`react`);i=e.__toESM(i,1);var a={status:`idle`,verificationUrl:null,userCode:null,apiKey:null,error:null,errorCode:null};function o(){let[e,o]=i.default.useState(a),s=i.default.useRef(null),c=i.default.useCallback((e,i)=>{s.current?.abort();let c=new AbortController;s.current=c,o({...a,status:`starting`}),(async()=>{let s;try{s=await n.startDeviceFlow(e)}catch(e){if(c.signal.aborted)return;let n=e instanceof Error?e.message:`Failed to start device flow`,r=e instanceof t.DeviceFlowError?e.code:void 0;o({...a,status:`error`,error:n,errorCode:r??null});return}if(!c.signal.aborted){r.trackCloudDeviceAuthorizationStarted(e,i),o({...a,status:`awaiting_authorization`,verificationUrl:s.verification_uri_complete,userCode:s.user_code});try{let t=await n.pollForToken(e,s.device_code,{interval:s.interval,signal:c.signal});if(c.signal.aborted)return;r.trackCloudDeviceAuthorizationSucceeded(e,i),o({...a,status:`success`,apiKey:t.access_token})}catch(e){if(c.signal.aborted)return;if(e instanceof t.DeviceFlowError&&e.code===`cancelled`){o(a);return}let n=e instanceof Error?e.message:`Authorization failed`,r=e instanceof t.DeviceFlowError?e.code:void 0;o({...a,status:`error`,error:n,errorCode:r??null})}}})()},[]),l=i.default.useCallback(()=>{s.current?.abort(),s.current=null,o(a)},[]),u=i.default.useCallback(()=>{s.current?.abort(),s.current=null,o(a)},[]);return i.default.useEffect(()=>()=>{s.current?.abort()},[]),{...e,start:c,cancel:l,reset:u}}exports.useDeviceFlow=o;
2
2
  //# sourceMappingURL=use-device-flow.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-device-flow.cjs","names":[],"sources":["../../src/hooks/use-device-flow.ts"],"sourcesContent":["import React from \"react\";\nimport {\n startDeviceFlow,\n pollForToken,\n DeviceFlowError,\n type DeviceAuthorizationResponse,\n} from \"#/api/device-flow-client\";\n\nexport type DeviceFlowStatus =\n | \"idle\"\n | \"starting\"\n | \"awaiting_authorization\"\n | \"success\"\n | \"error\";\n\nexport interface DeviceFlowState {\n status: DeviceFlowStatus;\n /** The verification URL to show/open for the user */\n verificationUrl: string | null;\n /** User code to display as fallback */\n userCode: string | null;\n /** The resulting API key on success */\n apiKey: string | null;\n /** Error message if status is \"error\" */\n error: string | null;\n /** Error code for programmatic handling */\n errorCode: string | null;\n}\n\nexport interface UseDeviceFlowReturn extends DeviceFlowState {\n /** Start the device flow authentication */\n start: (host: string) => void;\n /** Cancel an in-progress flow */\n cancel: () => void;\n /** Reset state back to idle */\n reset: () => void;\n}\n\nconst initialState: DeviceFlowState = {\n status: \"idle\",\n verificationUrl: null,\n userCode: null,\n apiKey: null,\n error: null,\n errorCode: null,\n};\n\n/**\n * React hook for managing OAuth 2.0 Device Flow authentication.\n *\n * Usage:\n * ```tsx\n * const { status, verificationUrl, apiKey, error, start, cancel, reset } = useDeviceFlow();\n *\n * // Start auth\n * start(\"https://app.all-hands.dev\");\n *\n * // Open browser when awaiting\n * if (status === \"awaiting_authorization\" && verificationUrl) {\n * window.open(verificationUrl, \"_blank\");\n * }\n *\n * // Use API key on success\n * if (status === \"success\" && apiKey) {\n * setApiKeyField(apiKey);\n * }\n * ```\n */\nexport function useDeviceFlow(): UseDeviceFlowReturn {\n const [state, setState] = React.useState<DeviceFlowState>(initialState);\n const abortControllerRef = React.useRef<AbortController | null>(null);\n\n const start = React.useCallback((host: string) => {\n // Cancel any existing flow\n abortControllerRef.current?.abort();\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n setState({\n ...initialState,\n status: \"starting\",\n });\n\n (async () => {\n let authResponse: DeviceAuthorizationResponse;\n\n try {\n authResponse = await startDeviceFlow(host);\n } catch (error) {\n if (abortController.signal.aborted) return;\n\n const message =\n error instanceof Error\n ? error.message\n : \"Failed to start device flow\";\n const code = error instanceof DeviceFlowError ? error.code : undefined;\n\n setState({\n ...initialState,\n status: \"error\",\n error: message,\n errorCode: code ?? null,\n });\n return;\n }\n\n if (abortController.signal.aborted) return;\n\n setState({\n ...initialState,\n status: \"awaiting_authorization\",\n verificationUrl: authResponse.verification_uri_complete,\n userCode: authResponse.user_code,\n });\n\n try {\n const tokenResponse = await pollForToken(\n host,\n authResponse.device_code,\n {\n interval: authResponse.interval,\n signal: abortController.signal,\n },\n );\n\n if (abortController.signal.aborted) return;\n\n setState({\n ...initialState,\n status: \"success\",\n apiKey: tokenResponse.access_token,\n });\n } catch (error) {\n // Early return if component unmounted or user cancelled\n if (abortController.signal.aborted) return;\n\n // Defensive: handle cancellation errors that may slip through\n // (currently pollForToken only throws \"cancelled\" when signal.aborted,\n // which is caught above, but this guards against future changes)\n const isCancel =\n error instanceof DeviceFlowError && error.code === \"cancelled\";\n if (isCancel) {\n setState(initialState);\n return;\n }\n\n const message =\n error instanceof Error ? error.message : \"Authorization failed\";\n const code = error instanceof DeviceFlowError ? error.code : undefined;\n\n setState({\n ...initialState,\n status: \"error\",\n error: message,\n errorCode: code ?? null,\n });\n }\n })();\n }, []);\n\n const cancel = React.useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setState(initialState);\n }, []);\n\n const reset = React.useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setState(initialState);\n }, []);\n\n // Cleanup on unmount\n React.useEffect(() => {\n return () => {\n abortControllerRef.current?.abort();\n };\n }, []);\n\n return {\n ...state,\n start,\n cancel,\n reset,\n };\n}\n"],"mappings":"wIAsCA,IAAM,EAAgC,CACpC,OAAQ,OACR,gBAAiB,KACjB,SAAU,KACV,OAAQ,KACR,MAAO,KACP,UAAW,KACZ,CAuBD,SAAgB,GAAqC,CACnD,GAAM,CAAC,EAAO,GAAY,EAAA,QAAM,SAA0B,EAAa,CACjE,EAAqB,EAAA,QAAM,OAA+B,KAAK,CAE/D,EAAQ,EAAA,QAAM,YAAa,GAAiB,CAEhD,EAAmB,SAAS,OAAO,CACnC,IAAM,EAAkB,IAAI,gBAC5B,EAAmB,QAAU,EAE7B,EAAS,CACP,GAAG,EACH,OAAQ,WACT,CAAC,EAED,SAAY,CACX,IAAI,EAEJ,GAAI,CACF,EAAe,MAAM,EAAA,gBAAgB,EAAK,OACnC,EAAO,CACd,GAAI,EAAgB,OAAO,QAAS,OAEpC,IAAM,EACJ,aAAiB,MACb,EAAM,QACN,8BACA,EAAO,aAAiB,EAAA,gBAAkB,EAAM,KAAO,IAAA,GAE7D,EAAS,CACP,GAAG,EACH,OAAQ,QACR,MAAO,EACP,UAAW,GAAQ,KACpB,CAAC,CACF,OAGE,MAAgB,OAAO,QAE3B,GAAS,CACP,GAAG,EACH,OAAQ,yBACR,gBAAiB,EAAa,0BAC9B,SAAU,EAAa,UACxB,CAAC,CAEF,GAAI,CACF,IAAM,EAAgB,MAAM,EAAA,aAC1B,EACA,EAAa,YACb,CACE,SAAU,EAAa,SACvB,OAAQ,EAAgB,OACzB,CACF,CAED,GAAI,EAAgB,OAAO,QAAS,OAEpC,EAAS,CACP,GAAG,EACH,OAAQ,UACR,OAAQ,EAAc,aACvB,CAAC,OACK,EAAO,CAEd,GAAI,EAAgB,OAAO,QAAS,OAOpC,GADE,aAAiB,EAAA,iBAAmB,EAAM,OAAS,YACvC,CACZ,EAAS,EAAa,CACtB,OAGF,IAAM,EACJ,aAAiB,MAAQ,EAAM,QAAU,uBACrC,EAAO,aAAiB,EAAA,gBAAkB,EAAM,KAAO,IAAA,GAE7D,EAAS,CACP,GAAG,EACH,OAAQ,QACR,MAAO,EACP,UAAW,GAAQ,KACpB,CAAC,MAEF,EACH,EAAE,CAAC,CAEA,EAAS,EAAA,QAAM,gBAAkB,CACrC,EAAmB,SAAS,OAAO,CACnC,EAAmB,QAAU,KAC7B,EAAS,EAAa,EACrB,EAAE,CAAC,CAEA,EAAQ,EAAA,QAAM,gBAAkB,CACpC,EAAmB,SAAS,OAAO,CACnC,EAAmB,QAAU,KAC7B,EAAS,EAAa,EACrB,EAAE,CAAC,CASN,OANA,EAAA,QAAM,kBACS,CACX,EAAmB,SAAS,OAAO,EAEpC,EAAE,CAAC,CAEC,CACL,GAAG,EACH,QACA,SACA,QACD"}
1
+ {"version":3,"file":"use-device-flow.cjs","names":[],"sources":["../../src/hooks/use-device-flow.ts"],"sourcesContent":["import React from \"react\";\nimport {\n startDeviceFlow,\n pollForToken,\n DeviceFlowError,\n type DeviceAuthorizationResponse,\n} from \"#/api/device-flow-client\";\nimport {\n trackCloudDeviceAuthorizationStarted,\n trackCloudDeviceAuthorizationSucceeded,\n type CloudConnectionSource,\n} from \"#/services/cloud-funnel-analytics\";\n\nexport type DeviceFlowStatus =\n | \"idle\"\n | \"starting\"\n | \"awaiting_authorization\"\n | \"success\"\n | \"error\";\n\nexport interface DeviceFlowState {\n status: DeviceFlowStatus;\n /** The verification URL to show/open for the user */\n verificationUrl: string | null;\n /** User code to display as fallback */\n userCode: string | null;\n /** The resulting API key on success */\n apiKey: string | null;\n /** Error message if status is \"error\" */\n error: string | null;\n /** Error code for programmatic handling */\n errorCode: string | null;\n}\n\nexport interface UseDeviceFlowReturn extends DeviceFlowState {\n /** Start the device flow authentication */\n start: StartDeviceFlow;\n /** Cancel an in-progress flow */\n cancel: () => void;\n /** Reset state back to idle */\n reset: () => void;\n}\n\ntype StartDeviceFlow = (\n host: string,\n analyticsSource?: CloudConnectionSource,\n) => void;\n\nconst initialState: DeviceFlowState = {\n status: \"idle\",\n verificationUrl: null,\n userCode: null,\n apiKey: null,\n error: null,\n errorCode: null,\n};\n\n/**\n * React hook for managing OAuth 2.0 Device Flow authentication.\n *\n * Usage:\n * ```tsx\n * const { status, verificationUrl, apiKey, error, start, cancel, reset } = useDeviceFlow();\n *\n * // Start auth\n * start(\"https://app.all-hands.dev\");\n *\n * // Open browser when awaiting\n * if (status === \"awaiting_authorization\" && verificationUrl) {\n * window.open(verificationUrl, \"_blank\");\n * }\n *\n * // Use API key on success\n * if (status === \"success\" && apiKey) {\n * setApiKeyField(apiKey);\n * }\n * ```\n */\nexport function useDeviceFlow(): UseDeviceFlowReturn {\n const [state, setState] = React.useState<DeviceFlowState>(initialState);\n const abortControllerRef = React.useRef<AbortController | null>(null);\n\n const start: StartDeviceFlow = React.useCallback((host, analyticsSource) => {\n // Cancel any existing flow\n abortControllerRef.current?.abort();\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n setState({\n ...initialState,\n status: \"starting\",\n });\n\n (async () => {\n let authResponse: DeviceAuthorizationResponse;\n\n try {\n authResponse = await startDeviceFlow(host);\n } catch (error) {\n if (abortController.signal.aborted) return;\n\n const message =\n error instanceof Error\n ? error.message\n : \"Failed to start device flow\";\n const code = error instanceof DeviceFlowError ? error.code : undefined;\n\n setState({\n ...initialState,\n status: \"error\",\n error: message,\n errorCode: code ?? null,\n });\n return;\n }\n\n if (abortController.signal.aborted) return;\n\n trackCloudDeviceAuthorizationStarted(host, analyticsSource);\n\n setState({\n ...initialState,\n status: \"awaiting_authorization\",\n verificationUrl: authResponse.verification_uri_complete,\n userCode: authResponse.user_code,\n });\n\n try {\n const tokenResponse = await pollForToken(\n host,\n authResponse.device_code,\n {\n interval: authResponse.interval,\n signal: abortController.signal,\n },\n );\n\n if (abortController.signal.aborted) return;\n\n trackCloudDeviceAuthorizationSucceeded(host, analyticsSource);\n\n setState({\n ...initialState,\n status: \"success\",\n apiKey: tokenResponse.access_token,\n });\n } catch (error) {\n // Early return if component unmounted or user cancelled\n if (abortController.signal.aborted) return;\n\n // Defensive: handle cancellation errors that may slip through\n // (currently pollForToken only throws \"cancelled\" when signal.aborted,\n // which is caught above, but this guards against future changes)\n const isCancel =\n error instanceof DeviceFlowError && error.code === \"cancelled\";\n if (isCancel) {\n setState(initialState);\n return;\n }\n\n const message =\n error instanceof Error ? error.message : \"Authorization failed\";\n const code = error instanceof DeviceFlowError ? error.code : undefined;\n\n setState({\n ...initialState,\n status: \"error\",\n error: message,\n errorCode: code ?? null,\n });\n }\n })();\n }, []);\n\n const cancel = React.useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setState(initialState);\n }, []);\n\n const reset = React.useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setState(initialState);\n }, []);\n\n // Cleanup on unmount\n React.useEffect(() => {\n return () => {\n abortControllerRef.current?.abort();\n };\n }, []);\n\n return {\n ...state,\n start,\n cancel,\n reset,\n };\n}\n"],"mappings":"yRAgDA,IAAM,EAAgC,CACpC,OAAQ,OACR,gBAAiB,KACjB,SAAU,KACV,OAAQ,KACR,MAAO,KACP,UAAW,KACZ,CAuBD,SAAgB,GAAqC,CACnD,GAAM,CAAC,EAAO,GAAY,EAAA,QAAM,SAA0B,EAAa,CACjE,EAAqB,EAAA,QAAM,OAA+B,KAAK,CAE/D,EAAyB,EAAA,QAAM,aAAa,EAAM,IAAoB,CAE1E,EAAmB,SAAS,OAAO,CACnC,IAAM,EAAkB,IAAI,gBAC5B,EAAmB,QAAU,EAE7B,EAAS,CACP,GAAG,EACH,OAAQ,WACT,CAAC,EAED,SAAY,CACX,IAAI,EAEJ,GAAI,CACF,EAAe,MAAM,EAAA,gBAAgB,EAAK,OACnC,EAAO,CACd,GAAI,EAAgB,OAAO,QAAS,OAEpC,IAAM,EACJ,aAAiB,MACb,EAAM,QACN,8BACA,EAAO,aAAiB,EAAA,gBAAkB,EAAM,KAAO,IAAA,GAE7D,EAAS,CACP,GAAG,EACH,OAAQ,QACR,MAAO,EACP,UAAW,GAAQ,KACpB,CAAC,CACF,OAGE,MAAgB,OAAO,QAI3B,CAFA,EAAA,qCAAqC,EAAM,EAAgB,CAE3D,EAAS,CACP,GAAG,EACH,OAAQ,yBACR,gBAAiB,EAAa,0BAC9B,SAAU,EAAa,UACxB,CAAC,CAEF,GAAI,CACF,IAAM,EAAgB,MAAM,EAAA,aAC1B,EACA,EAAa,YACb,CACE,SAAU,EAAa,SACvB,OAAQ,EAAgB,OACzB,CACF,CAED,GAAI,EAAgB,OAAO,QAAS,OAEpC,EAAA,uCAAuC,EAAM,EAAgB,CAE7D,EAAS,CACP,GAAG,EACH,OAAQ,UACR,OAAQ,EAAc,aACvB,CAAC,OACK,EAAO,CAEd,GAAI,EAAgB,OAAO,QAAS,OAOpC,GADE,aAAiB,EAAA,iBAAmB,EAAM,OAAS,YACvC,CACZ,EAAS,EAAa,CACtB,OAGF,IAAM,EACJ,aAAiB,MAAQ,EAAM,QAAU,uBACrC,EAAO,aAAiB,EAAA,gBAAkB,EAAM,KAAO,IAAA,GAE7D,EAAS,CACP,GAAG,EACH,OAAQ,QACR,MAAO,EACP,UAAW,GAAQ,KACpB,CAAC,MAEF,EACH,EAAE,CAAC,CAEA,EAAS,EAAA,QAAM,gBAAkB,CACrC,EAAmB,SAAS,OAAO,CACnC,EAAmB,QAAU,KAC7B,EAAS,EAAa,EACrB,EAAE,CAAC,CAEA,EAAQ,EAAA,QAAM,gBAAkB,CACpC,EAAmB,SAAS,OAAO,CACnC,EAAmB,QAAU,KAC7B,EAAS,EAAa,EACrB,EAAE,CAAC,CASN,OANA,EAAA,QAAM,kBACS,CACX,EAAmB,SAAS,OAAO,EAEpC,EAAE,CAAC,CAEC,CACL,GAAG,EACH,QACA,SACA,QACD"}
@@ -1,3 +1,4 @@
1
+ import { type CloudConnectionSource } from "#/services/cloud-funnel-analytics";
1
2
  export type DeviceFlowStatus = "idle" | "starting" | "awaiting_authorization" | "success" | "error";
2
3
  export interface DeviceFlowState {
3
4
  status: DeviceFlowStatus;
@@ -14,12 +15,13 @@ export interface DeviceFlowState {
14
15
  }
15
16
  export interface UseDeviceFlowReturn extends DeviceFlowState {
16
17
  /** Start the device flow authentication */
17
- start: (host: string) => void;
18
+ start: StartDeviceFlow;
18
19
  /** Cancel an in-progress flow */
19
20
  cancel: () => void;
20
21
  /** Reset state back to idle */
21
22
  reset: () => void;
22
23
  }
24
+ type StartDeviceFlow = (host: string, analyticsSource?: CloudConnectionSource) => void;
23
25
  /**
24
26
  * React hook for managing OAuth 2.0 Device Flow authentication.
25
27
  *
@@ -42,3 +44,4 @@ export interface UseDeviceFlowReturn extends DeviceFlowState {
42
44
  * ```
43
45
  */
44
46
  export declare function useDeviceFlow(): UseDeviceFlowReturn;
47
+ export {};
@@ -1,7 +1,9 @@
1
- import { DeviceFlowError as e, pollForToken as t, startDeviceFlow as n } from "../api/device-flow-client.js";
2
- import r from "react";
1
+ import { DeviceFlowError as e } from "../node_modules/@openhands/typescript-client/dist/client/device-flow-client.js";
2
+ import { pollForToken as t, startDeviceFlow as n } from "../api/device-flow-client.js";
3
+ import { trackCloudDeviceAuthorizationStarted as r, trackCloudDeviceAuthorizationSucceeded as i } from "../services/cloud-funnel-analytics.js";
4
+ import a from "react";
3
5
  //#region src/hooks/use-device-flow.ts
4
- var i = {
6
+ var o = {
5
7
  status: "idle",
6
8
  verificationUrl: null,
7
9
  userCode: null,
@@ -9,55 +11,55 @@ var i = {
9
11
  error: null,
10
12
  errorCode: null
11
13
  };
12
- function a() {
13
- let [a, o] = r.useState(i), s = r.useRef(null), c = r.useCallback((r) => {
14
- s.current?.abort();
15
- let a = new AbortController();
16
- s.current = a, o({
17
- ...i,
14
+ function s() {
15
+ let [s, c] = a.useState(o), l = a.useRef(null), u = a.useCallback((a, s) => {
16
+ l.current?.abort();
17
+ let u = new AbortController();
18
+ l.current = u, c({
19
+ ...o,
18
20
  status: "starting"
19
21
  }), (async () => {
20
- let s;
22
+ let l;
21
23
  try {
22
- s = await n(r);
24
+ l = await n(a);
23
25
  } catch (t) {
24
- if (a.signal.aborted) return;
26
+ if (u.signal.aborted) return;
25
27
  let n = t instanceof Error ? t.message : "Failed to start device flow", r = t instanceof e ? t.code : void 0;
26
- o({
27
- ...i,
28
+ c({
29
+ ...o,
28
30
  status: "error",
29
31
  error: n,
30
32
  errorCode: r ?? null
31
33
  });
32
34
  return;
33
35
  }
34
- if (!a.signal.aborted) {
35
- o({
36
- ...i,
36
+ if (!u.signal.aborted) {
37
+ r(a, s), c({
38
+ ...o,
37
39
  status: "awaiting_authorization",
38
- verificationUrl: s.verification_uri_complete,
39
- userCode: s.user_code
40
+ verificationUrl: l.verification_uri_complete,
41
+ userCode: l.user_code
40
42
  });
41
43
  try {
42
- let e = await t(r, s.device_code, {
43
- interval: s.interval,
44
- signal: a.signal
44
+ let e = await t(a, l.device_code, {
45
+ interval: l.interval,
46
+ signal: u.signal
45
47
  });
46
- if (a.signal.aborted) return;
47
- o({
48
- ...i,
48
+ if (u.signal.aborted) return;
49
+ i(a, s), c({
50
+ ...o,
49
51
  status: "success",
50
52
  apiKey: e.access_token
51
53
  });
52
54
  } catch (t) {
53
- if (a.signal.aborted) return;
55
+ if (u.signal.aborted) return;
54
56
  if (t instanceof e && t.code === "cancelled") {
55
- o(i);
57
+ c(o);
56
58
  return;
57
59
  }
58
60
  let n = t instanceof Error ? t.message : "Authorization failed", r = t instanceof e ? t.code : void 0;
59
- o({
60
- ...i,
61
+ c({
62
+ ...o,
61
63
  status: "error",
62
64
  error: n,
63
65
  errorCode: r ?? null
@@ -65,21 +67,21 @@ function a() {
65
67
  }
66
68
  }
67
69
  })();
68
- }, []), l = r.useCallback(() => {
69
- s.current?.abort(), s.current = null, o(i);
70
- }, []), u = r.useCallback(() => {
71
- s.current?.abort(), s.current = null, o(i);
70
+ }, []), d = a.useCallback(() => {
71
+ l.current?.abort(), l.current = null, c(o);
72
+ }, []), f = a.useCallback(() => {
73
+ l.current?.abort(), l.current = null, c(o);
72
74
  }, []);
73
- return r.useEffect(() => () => {
74
- s.current?.abort();
75
+ return a.useEffect(() => () => {
76
+ l.current?.abort();
75
77
  }, []), {
76
- ...a,
77
- start: c,
78
- cancel: l,
79
- reset: u
78
+ ...s,
79
+ start: u,
80
+ cancel: d,
81
+ reset: f
80
82
  };
81
83
  }
82
84
  //#endregion
83
- export { a as useDeviceFlow };
85
+ export { s as useDeviceFlow };
84
86
 
85
87
  //# sourceMappingURL=use-device-flow.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-device-flow.js","names":[],"sources":["../../src/hooks/use-device-flow.ts"],"sourcesContent":["import React from \"react\";\nimport {\n startDeviceFlow,\n pollForToken,\n DeviceFlowError,\n type DeviceAuthorizationResponse,\n} from \"#/api/device-flow-client\";\n\nexport type DeviceFlowStatus =\n | \"idle\"\n | \"starting\"\n | \"awaiting_authorization\"\n | \"success\"\n | \"error\";\n\nexport interface DeviceFlowState {\n status: DeviceFlowStatus;\n /** The verification URL to show/open for the user */\n verificationUrl: string | null;\n /** User code to display as fallback */\n userCode: string | null;\n /** The resulting API key on success */\n apiKey: string | null;\n /** Error message if status is \"error\" */\n error: string | null;\n /** Error code for programmatic handling */\n errorCode: string | null;\n}\n\nexport interface UseDeviceFlowReturn extends DeviceFlowState {\n /** Start the device flow authentication */\n start: (host: string) => void;\n /** Cancel an in-progress flow */\n cancel: () => void;\n /** Reset state back to idle */\n reset: () => void;\n}\n\nconst initialState: DeviceFlowState = {\n status: \"idle\",\n verificationUrl: null,\n userCode: null,\n apiKey: null,\n error: null,\n errorCode: null,\n};\n\n/**\n * React hook for managing OAuth 2.0 Device Flow authentication.\n *\n * Usage:\n * ```tsx\n * const { status, verificationUrl, apiKey, error, start, cancel, reset } = useDeviceFlow();\n *\n * // Start auth\n * start(\"https://app.all-hands.dev\");\n *\n * // Open browser when awaiting\n * if (status === \"awaiting_authorization\" && verificationUrl) {\n * window.open(verificationUrl, \"_blank\");\n * }\n *\n * // Use API key on success\n * if (status === \"success\" && apiKey) {\n * setApiKeyField(apiKey);\n * }\n * ```\n */\nexport function useDeviceFlow(): UseDeviceFlowReturn {\n const [state, setState] = React.useState<DeviceFlowState>(initialState);\n const abortControllerRef = React.useRef<AbortController | null>(null);\n\n const start = React.useCallback((host: string) => {\n // Cancel any existing flow\n abortControllerRef.current?.abort();\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n setState({\n ...initialState,\n status: \"starting\",\n });\n\n (async () => {\n let authResponse: DeviceAuthorizationResponse;\n\n try {\n authResponse = await startDeviceFlow(host);\n } catch (error) {\n if (abortController.signal.aborted) return;\n\n const message =\n error instanceof Error\n ? error.message\n : \"Failed to start device flow\";\n const code = error instanceof DeviceFlowError ? error.code : undefined;\n\n setState({\n ...initialState,\n status: \"error\",\n error: message,\n errorCode: code ?? null,\n });\n return;\n }\n\n if (abortController.signal.aborted) return;\n\n setState({\n ...initialState,\n status: \"awaiting_authorization\",\n verificationUrl: authResponse.verification_uri_complete,\n userCode: authResponse.user_code,\n });\n\n try {\n const tokenResponse = await pollForToken(\n host,\n authResponse.device_code,\n {\n interval: authResponse.interval,\n signal: abortController.signal,\n },\n );\n\n if (abortController.signal.aborted) return;\n\n setState({\n ...initialState,\n status: \"success\",\n apiKey: tokenResponse.access_token,\n });\n } catch (error) {\n // Early return if component unmounted or user cancelled\n if (abortController.signal.aborted) return;\n\n // Defensive: handle cancellation errors that may slip through\n // (currently pollForToken only throws \"cancelled\" when signal.aborted,\n // which is caught above, but this guards against future changes)\n const isCancel =\n error instanceof DeviceFlowError && error.code === \"cancelled\";\n if (isCancel) {\n setState(initialState);\n return;\n }\n\n const message =\n error instanceof Error ? error.message : \"Authorization failed\";\n const code = error instanceof DeviceFlowError ? error.code : undefined;\n\n setState({\n ...initialState,\n status: \"error\",\n error: message,\n errorCode: code ?? null,\n });\n }\n })();\n }, []);\n\n const cancel = React.useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setState(initialState);\n }, []);\n\n const reset = React.useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setState(initialState);\n }, []);\n\n // Cleanup on unmount\n React.useEffect(() => {\n return () => {\n abortControllerRef.current?.abort();\n };\n }, []);\n\n return {\n ...state,\n start,\n cancel,\n reset,\n };\n}\n"],"mappings":";;;AAsCA,IAAM,IAAgC;CACpC,QAAQ;CACR,iBAAiB;CACjB,UAAU;CACV,QAAQ;CACR,OAAO;CACP,WAAW;CACZ;AAuBD,SAAgB,IAAqC;CACnD,IAAM,CAAC,GAAO,KAAY,EAAM,SAA0B,EAAa,EACjE,IAAqB,EAAM,OAA+B,KAAK,EAE/D,IAAQ,EAAM,aAAa,MAAiB;AAEhD,IAAmB,SAAS,OAAO;EACnC,IAAM,IAAkB,IAAI,iBAAiB;AAQ7C,EAPA,EAAmB,UAAU,GAE7B,EAAS;GACP,GAAG;GACH,QAAQ;GACT,CAAC,GAED,YAAY;GACX,IAAI;AAEJ,OAAI;AACF,QAAe,MAAM,EAAgB,EAAK;YACnC,GAAO;AACd,QAAI,EAAgB,OAAO,QAAS;IAEpC,IAAM,IACJ,aAAiB,QACb,EAAM,UACN,+BACA,IAAO,aAAiB,IAAkB,EAAM,OAAO,KAAA;AAE7D,MAAS;KACP,GAAG;KACH,QAAQ;KACR,OAAO;KACP,WAAW,KAAQ;KACpB,CAAC;AACF;;AAGE,UAAgB,OAAO,SAE3B;MAAS;KACP,GAAG;KACH,QAAQ;KACR,iBAAiB,EAAa;KAC9B,UAAU,EAAa;KACxB,CAAC;AAEF,QAAI;KACF,IAAM,IAAgB,MAAM,EAC1B,GACA,EAAa,aACb;MACE,UAAU,EAAa;MACvB,QAAQ,EAAgB;MACzB,CACF;AAED,SAAI,EAAgB,OAAO,QAAS;AAEpC,OAAS;MACP,GAAG;MACH,QAAQ;MACR,QAAQ,EAAc;MACvB,CAAC;aACK,GAAO;AAEd,SAAI,EAAgB,OAAO,QAAS;AAOpC,SADE,aAAiB,KAAmB,EAAM,SAAS,aACvC;AACZ,QAAS,EAAa;AACtB;;KAGF,IAAM,IACJ,aAAiB,QAAQ,EAAM,UAAU,wBACrC,IAAO,aAAiB,IAAkB,EAAM,OAAO,KAAA;AAE7D,OAAS;MACP,GAAG;MACH,QAAQ;MACR,OAAO;MACP,WAAW,KAAQ;MACpB,CAAC;;;MAEF;IACH,EAAE,CAAC,EAEA,IAAS,EAAM,kBAAkB;AAGrC,EAFA,EAAmB,SAAS,OAAO,EACnC,EAAmB,UAAU,MAC7B,EAAS,EAAa;IACrB,EAAE,CAAC,EAEA,IAAQ,EAAM,kBAAkB;AAGpC,EAFA,EAAmB,SAAS,OAAO,EACnC,EAAmB,UAAU,MAC7B,EAAS,EAAa;IACrB,EAAE,CAAC;AASN,QANA,EAAM,sBACS;AACX,IAAmB,SAAS,OAAO;IAEpC,EAAE,CAAC,EAEC;EACL,GAAG;EACH;EACA;EACA;EACD"}
1
+ {"version":3,"file":"use-device-flow.js","names":[],"sources":["../../src/hooks/use-device-flow.ts"],"sourcesContent":["import React from \"react\";\nimport {\n startDeviceFlow,\n pollForToken,\n DeviceFlowError,\n type DeviceAuthorizationResponse,\n} from \"#/api/device-flow-client\";\nimport {\n trackCloudDeviceAuthorizationStarted,\n trackCloudDeviceAuthorizationSucceeded,\n type CloudConnectionSource,\n} from \"#/services/cloud-funnel-analytics\";\n\nexport type DeviceFlowStatus =\n | \"idle\"\n | \"starting\"\n | \"awaiting_authorization\"\n | \"success\"\n | \"error\";\n\nexport interface DeviceFlowState {\n status: DeviceFlowStatus;\n /** The verification URL to show/open for the user */\n verificationUrl: string | null;\n /** User code to display as fallback */\n userCode: string | null;\n /** The resulting API key on success */\n apiKey: string | null;\n /** Error message if status is \"error\" */\n error: string | null;\n /** Error code for programmatic handling */\n errorCode: string | null;\n}\n\nexport interface UseDeviceFlowReturn extends DeviceFlowState {\n /** Start the device flow authentication */\n start: StartDeviceFlow;\n /** Cancel an in-progress flow */\n cancel: () => void;\n /** Reset state back to idle */\n reset: () => void;\n}\n\ntype StartDeviceFlow = (\n host: string,\n analyticsSource?: CloudConnectionSource,\n) => void;\n\nconst initialState: DeviceFlowState = {\n status: \"idle\",\n verificationUrl: null,\n userCode: null,\n apiKey: null,\n error: null,\n errorCode: null,\n};\n\n/**\n * React hook for managing OAuth 2.0 Device Flow authentication.\n *\n * Usage:\n * ```tsx\n * const { status, verificationUrl, apiKey, error, start, cancel, reset } = useDeviceFlow();\n *\n * // Start auth\n * start(\"https://app.all-hands.dev\");\n *\n * // Open browser when awaiting\n * if (status === \"awaiting_authorization\" && verificationUrl) {\n * window.open(verificationUrl, \"_blank\");\n * }\n *\n * // Use API key on success\n * if (status === \"success\" && apiKey) {\n * setApiKeyField(apiKey);\n * }\n * ```\n */\nexport function useDeviceFlow(): UseDeviceFlowReturn {\n const [state, setState] = React.useState<DeviceFlowState>(initialState);\n const abortControllerRef = React.useRef<AbortController | null>(null);\n\n const start: StartDeviceFlow = React.useCallback((host, analyticsSource) => {\n // Cancel any existing flow\n abortControllerRef.current?.abort();\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n setState({\n ...initialState,\n status: \"starting\",\n });\n\n (async () => {\n let authResponse: DeviceAuthorizationResponse;\n\n try {\n authResponse = await startDeviceFlow(host);\n } catch (error) {\n if (abortController.signal.aborted) return;\n\n const message =\n error instanceof Error\n ? error.message\n : \"Failed to start device flow\";\n const code = error instanceof DeviceFlowError ? error.code : undefined;\n\n setState({\n ...initialState,\n status: \"error\",\n error: message,\n errorCode: code ?? null,\n });\n return;\n }\n\n if (abortController.signal.aborted) return;\n\n trackCloudDeviceAuthorizationStarted(host, analyticsSource);\n\n setState({\n ...initialState,\n status: \"awaiting_authorization\",\n verificationUrl: authResponse.verification_uri_complete,\n userCode: authResponse.user_code,\n });\n\n try {\n const tokenResponse = await pollForToken(\n host,\n authResponse.device_code,\n {\n interval: authResponse.interval,\n signal: abortController.signal,\n },\n );\n\n if (abortController.signal.aborted) return;\n\n trackCloudDeviceAuthorizationSucceeded(host, analyticsSource);\n\n setState({\n ...initialState,\n status: \"success\",\n apiKey: tokenResponse.access_token,\n });\n } catch (error) {\n // Early return if component unmounted or user cancelled\n if (abortController.signal.aborted) return;\n\n // Defensive: handle cancellation errors that may slip through\n // (currently pollForToken only throws \"cancelled\" when signal.aborted,\n // which is caught above, but this guards against future changes)\n const isCancel =\n error instanceof DeviceFlowError && error.code === \"cancelled\";\n if (isCancel) {\n setState(initialState);\n return;\n }\n\n const message =\n error instanceof Error ? error.message : \"Authorization failed\";\n const code = error instanceof DeviceFlowError ? error.code : undefined;\n\n setState({\n ...initialState,\n status: \"error\",\n error: message,\n errorCode: code ?? null,\n });\n }\n })();\n }, []);\n\n const cancel = React.useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setState(initialState);\n }, []);\n\n const reset = React.useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setState(initialState);\n }, []);\n\n // Cleanup on unmount\n React.useEffect(() => {\n return () => {\n abortControllerRef.current?.abort();\n };\n }, []);\n\n return {\n ...state,\n start,\n cancel,\n reset,\n };\n}\n"],"mappings":";;;;;AAgDA,IAAM,IAAgC;CACpC,QAAQ;CACR,iBAAiB;CACjB,UAAU;CACV,QAAQ;CACR,OAAO;CACP,WAAW;CACZ;AAuBD,SAAgB,IAAqC;CACnD,IAAM,CAAC,GAAO,KAAY,EAAM,SAA0B,EAAa,EACjE,IAAqB,EAAM,OAA+B,KAAK,EAE/D,IAAyB,EAAM,aAAa,GAAM,MAAoB;AAE1E,IAAmB,SAAS,OAAO;EACnC,IAAM,IAAkB,IAAI,iBAAiB;AAQ7C,EAPA,EAAmB,UAAU,GAE7B,EAAS;GACP,GAAG;GACH,QAAQ;GACT,CAAC,GAED,YAAY;GACX,IAAI;AAEJ,OAAI;AACF,QAAe,MAAM,EAAgB,EAAK;YACnC,GAAO;AACd,QAAI,EAAgB,OAAO,QAAS;IAEpC,IAAM,IACJ,aAAiB,QACb,EAAM,UACN,+BACA,IAAO,aAAiB,IAAkB,EAAM,OAAO,KAAA;AAE7D,MAAS;KACP,GAAG;KACH,QAAQ;KACR,OAAO;KACP,WAAW,KAAQ;KACpB,CAAC;AACF;;AAGE,UAAgB,OAAO,SAI3B;IAFA,EAAqC,GAAM,EAAgB,EAE3D,EAAS;KACP,GAAG;KACH,QAAQ;KACR,iBAAiB,EAAa;KAC9B,UAAU,EAAa;KACxB,CAAC;AAEF,QAAI;KACF,IAAM,IAAgB,MAAM,EAC1B,GACA,EAAa,aACb;MACE,UAAU,EAAa;MACvB,QAAQ,EAAgB;MACzB,CACF;AAED,SAAI,EAAgB,OAAO,QAAS;AAIpC,KAFA,EAAuC,GAAM,EAAgB,EAE7D,EAAS;MACP,GAAG;MACH,QAAQ;MACR,QAAQ,EAAc;MACvB,CAAC;aACK,GAAO;AAEd,SAAI,EAAgB,OAAO,QAAS;AAOpC,SADE,aAAiB,KAAmB,EAAM,SAAS,aACvC;AACZ,QAAS,EAAa;AACtB;;KAGF,IAAM,IACJ,aAAiB,QAAQ,EAAM,UAAU,wBACrC,IAAO,aAAiB,IAAkB,EAAM,OAAO,KAAA;AAE7D,OAAS;MACP,GAAG;MACH,QAAQ;MACR,OAAO;MACP,WAAW,KAAQ;MACpB,CAAC;;;MAEF;IACH,EAAE,CAAC,EAEA,IAAS,EAAM,kBAAkB;AAGrC,EAFA,EAAmB,SAAS,OAAO,EACnC,EAAmB,UAAU,MAC7B,EAAS,EAAa;IACrB,EAAE,CAAC,EAEA,IAAQ,EAAM,kBAAkB;AAGpC,EAFA,EAAmB,SAAS,OAAO,EACnC,EAAmB,UAAU,MAC7B,EAAS,EAAa;IACrB,EAAE,CAAC;AASN,QANA,EAAM,sBACS;AACX,IAAmB,SAAS,OAAO;IAEpC,EAAE,CAAC,EAEC;EACL,GAAG;EACH;EACA;EACA;EACD"}