@openhands/agent-canvas 1.4.0 → 1.5.1

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 (710) hide show
  1. package/README.md +11 -12
  2. package/README.windows.md +4 -2
  3. package/build/assets/{Trans-Ch-OVWEA.js → Trans-DqF_OEZB.js} +1 -1
  4. package/build/assets/{acp-providers-Sy2LKyMa.js → acp-providers-DerAmTyY.js} +1 -1
  5. package/build/assets/active-backend-context-B8rMv0X9.js +1 -0
  6. package/build/assets/{add-backend-modal-Bgy8anoR.js → add-backend-modal-CxC7BNEc.js} +1 -1
  7. package/build/assets/{agent-profiles-settings-3mmXljZX.js → agent-profiles-settings-BJb8YXR1.js} +1 -1
  8. package/build/assets/agent-server-compatibility-BWN-EIQn.js +1 -0
  9. package/build/assets/agent-server-conversation-service.api-DSPIkMwJ.js +41 -0
  10. package/build/assets/{agent-settings-B-W10B4E.js → agent-settings-CgCnqaAA.js} +2 -2
  11. package/build/assets/agent-settings-DDkSavD7.js +1 -0
  12. package/build/assets/{alert-banner-Bpf2NQJq.js → alert-banner-Dh51WURQ.js} +1 -1
  13. package/build/assets/api-key-entry-screen-iZc7n8AI.js +1 -0
  14. package/build/assets/app-settings-B5zyipxJ.js +1 -0
  15. package/build/assets/automation-detail-CZsu2CoM.js +2 -0
  16. package/build/assets/automation-export-BwRX6H32.js +2 -0
  17. package/build/assets/automations-list-lHAVzMoA.js +1 -0
  18. package/build/assets/{back-nav-button-CUS2mi-U.js → back-nav-button-DVknCcSP.js} +1 -1
  19. package/build/assets/backend-form-modal-RGcu909r.js +1 -0
  20. package/build/assets/{backend-synced-settings-badge-D9hZx05w.js → backend-synced-settings-badge-BSfN0AZA.js} +1 -1
  21. package/build/assets/{base-modal-BuF2f0YL.js → base-modal-CIF_785P.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-B1izLAdR.js} +1 -1
  24. package/build/assets/{browser-BifzWIBd.js → browser-DKaeq_sT.js} +3 -3
  25. package/build/assets/{browser-tab-CkkqJnqw.js → browser-tab-qb_ftCxW.js} +1 -1
  26. package/build/assets/canvas-ui-COgjltGz.js +1 -0
  27. package/build/assets/{chat-send-button-B_jc5z5C.js → chat-send-button-BZHG2hAW.js} +1 -1
  28. package/build/assets/check-TbOEtHKj.js +1 -0
  29. package/build/assets/{chevron-down-CI8A6tet.js → chevron-down-D7IvFMBM.js} +1 -1
  30. package/build/assets/{circle-plus-check-toggle-C5YxjxvI.js → circle-plus-check-toggle-DoFIjVE0.js} +1 -1
  31. package/build/assets/client-source-BZK8vRs2.js +1 -0
  32. package/build/assets/cloud-funnel-analytics-Zcv57hfT.js +1 -0
  33. package/build/assets/{color-themes-DPBzNtVg.js → color-themes-CHizm1xF.js} +1 -1
  34. package/build/assets/{combobox-caret-DoObzqf4.js → combobox-caret-CxZpqoSR.js} +1 -1
  35. package/build/assets/{command-menu-D-JV3Wqm.js → command-menu-oTvKDU3Y.js} +1 -1
  36. package/build/assets/condenser-settings-BGlWn93P.js +1 -0
  37. package/build/assets/{confirmation-modal-BGLu6XJN.js → confirmation-modal-DGBWM2Ls.js} +1 -1
  38. package/build/assets/{context-menu-list-item-BD5_EaKN.js → context-menu-list-item-6psNyl7X.js} +1 -1
  39. package/build/assets/conversation-BoCYx8n2.js +89 -0
  40. package/build/assets/conversation-DgHqMjnY.js +1 -0
  41. package/build/assets/conversation-panel-78Rxh_-I.js +1 -0
  42. package/build/assets/conversation-service.api-_f9GlIEi.js +1 -0
  43. package/build/assets/{conversation-tab-empty-state-B2dDYEwf.js → conversation-tab-empty-state-CNUmIms2.js} +1 -1
  44. package/build/assets/{copy-3JCw_XFB.js → copy-D1YGjP-C.js} +1 -1
  45. package/build/assets/{copy-to-clipboard-button-CaR52OnA.js → copy-to-clipboard-button-CFzH_NOX.js} +1 -1
  46. package/build/assets/declaration-BGsHjPEW.js +1 -0
  47. package/build/assets/{device-verify-Dj6I4Iqe.js → device-verify-WBSjJBLH.js} +1 -1
  48. package/build/assets/{dropdown-classes-DJSXeLqc.js → dropdown-classes-D3wMJlXT.js} +1 -1
  49. package/build/assets/{ellipsis-button-C5Z-tPFp.js → ellipsis-button-CbNnHlIq.js} +1 -1
  50. package/build/assets/{entry.client-2_3ePAm0.js → entry.client-DNlPGxsu.js} +2 -2
  51. package/build/assets/{enum-filter-dropdown-DXbVwiNZ.js → enum-filter-dropdown-JLYv1t8L.js} +1 -1
  52. package/build/assets/{environment-switch-overlay-DZQfRGTx.js → environment-switch-overlay-B1PFO8P8.js} +1 -1
  53. package/build/assets/{extensions-hub-CLjmOGqS.js → extensions-hub-CCbLA7IM.js} +1 -1
  54. package/build/assets/{extensions-navigation-B5MeUiMq.js → extensions-navigation-CPNjMNvR.js} +1 -1
  55. package/build/assets/{external-link-D2zJjE9G.js → external-link-lhdITPqq.js} +1 -1
  56. package/build/assets/files-tab-y4K7EXBO.js +1 -0
  57. package/build/assets/{form-control-classes-ChpNBe9n.js → form-control-classes-CbdN5aO3.js} +1 -1
  58. package/build/assets/format-time-delta-DhDbkD7V.js +1 -0
  59. package/build/assets/git-provider-icon-ITvsH4Ko.js +1 -0
  60. package/build/assets/home-BwbeOWwU.js +1 -0
  61. package/build/assets/home-DKPGQ5P3.js +1 -0
  62. package/build/assets/index-home-Bko2Itv5.js +1 -0
  63. package/build/assets/install-server-modal-Qk1gwyI8.js +1 -0
  64. package/build/assets/{launch-V_3Rp7WS.js → launch-CAGavYl-.js} +1 -1
  65. package/build/assets/lesson-plan-DMCPdtrf.js +4 -0
  66. package/build/assets/{list-todo-BfH6yYUK.js → list-todo-CAtvkzcy.js} +1 -1
  67. package/build/assets/llm-not-configured-banner-C1ktyb3C.js +27 -0
  68. package/build/assets/llm-settings-BBsZFi9l.js +1 -0
  69. package/build/assets/llm-settings-DFkJQr_w.js +1 -0
  70. package/build/assets/llm-subscription-service-Casyzgn1.js +1 -0
  71. package/build/assets/loader-circle-CsAsfLIs.js +1 -0
  72. package/build/assets/{loading-spinner-BLdswi6q.js → loading-spinner-BcdnT0mN.js} +1 -1
  73. package/build/assets/manage-backends-modal-CKQ46rvw.js +1 -0
  74. package/build/assets/manifest-03478bbf.js +1 -0
  75. package/build/assets/{map-provider-BM2SJarp.js → map-provider-BbIb12oh.js} +1 -1
  76. package/build/assets/{markdown-renderer-DMT7Zkpd.js → markdown-renderer-B4V2OMFP.js} +1 -1
  77. package/build/assets/{mcp-BQufNPZ6.js → mcp-BapoJsDc.js} +2 -2
  78. package/build/assets/{messages-BnJCqnFf.js → messages-CUBFMY5o.js} +26 -26
  79. package/build/assets/{modal-body-DouOE5KH.js → modal-body-Cc2zp0xb.js} +1 -1
  80. package/build/assets/{modal-classes-Cf-4tbHz.js → modal-classes-3qT9Ap7Q.js} +1 -1
  81. package/build/assets/{modal-close-button-B6CfxxJj.js → modal-close-button-BcIBUdSq.js} +1 -1
  82. package/build/assets/model-selector-DJrMrFAr.js +1 -0
  83. package/build/assets/onboarding-6NMkdNxV.js +1 -0
  84. package/build/assets/onboarding-modal-Q4AnpIdg.js +1 -0
  85. package/build/assets/organization-service.api-vrRNwOma.js +1 -0
  86. package/build/assets/path-utils-PNfCKQDV.js +1 -0
  87. package/build/assets/{pencil-Dj2XjKmI.js → pencil-CWhApFIT.js} +1 -1
  88. package/build/assets/{plan-components-CcCBmCzW.js → plan-components-BdZXPyZU.js} +1 -1
  89. package/build/assets/{planner-tab-Dhyqcqmb.js → planner-tab-ByOw1he8.js} +1 -1
  90. package/build/assets/plugins-management-service-B75jyC56.js +1 -0
  91. package/build/assets/profiles-service.api-BQTklD5D.js +1 -0
  92. package/build/assets/providers-DfTB2gPd.js +1 -0
  93. package/build/assets/proxy-B3tCGf0X.js +1 -0
  94. package/build/assets/{recommended-automations-launcher-CTcGTl4d.js → recommended-automations-launcher-Bj7PuHY1.js} +1 -1
  95. package/build/assets/{refresh-cw-DM82EIyx.js → refresh-cw-B9B7-vsy.js} +1 -1
  96. package/build/assets/root-CDnuTToz.js +2 -0
  97. package/build/assets/root-CYWeTrWE.css +1 -0
  98. package/build/assets/root-layout-DfYVlcRG.js +2 -0
  99. package/build/assets/{runtime-waiting-state-BsXLElvN.js → runtime-waiting-state-CnyVhX4T.js} +1 -1
  100. package/build/assets/schema-field-CUwk4wrQ.js +1 -0
  101. package/build/assets/sdk-section-page-DLLNrYjI.js +1 -0
  102. package/build/assets/{sdk-settings-schema-Cv7M9eSe.js → sdk-settings-schema-CLR01YIK.js} +1 -1
  103. package/build/assets/search-dIQ09UY2.js +1 -0
  104. package/build/assets/secrets-service-CvyPWJhg.js +1 -0
  105. package/build/assets/{secrets-settings-Cx6yJlyb.js → secrets-settings-CHy72A5C.js} +1 -1
  106. package/build/assets/{segmented-toggle-DyQqPhoD.js → segmented-toggle-kzwZkLaj.js} +1 -1
  107. package/build/assets/settings-B9S8UVQr.js +1 -0
  108. package/build/assets/{settings-dropdown-input-BjunGXJb.js → settings-dropdown-input-Dhx9ErGd.js} +1 -1
  109. package/build/assets/{settings-index-D6sxWSRk.js → settings-index-BKDl2CQ-.js} +1 -1
  110. package/build/assets/{settings-input-bD6npsDm.js → settings-input-BsgQWS5R.js} +1 -1
  111. package/build/assets/{settings-list-classes-Dp_OgzN0.js → settings-list-classes-DSJJX99U.js} +1 -1
  112. package/build/assets/settings-modal-DeK11CyT.js +1 -0
  113. package/build/assets/settings-service.api-DXk5TdeJ.js +1 -0
  114. package/build/assets/{settings-switch-5cuxl8Dc.js → settings-switch-Bes8dIlV.js} +1 -1
  115. package/build/assets/{settings-utils-BMdG65By.js → settings-utils-DzCVfiR3.js} +1 -1
  116. package/build/assets/shared-conversation-9atDzTR4.js +1 -0
  117. package/build/assets/{sidebar-layout-DuzJMMw-.js → sidebar-layout-Bm7pa3Vk.js} +1 -1
  118. package/build/assets/{sidebar-mobile-menu-toggle-VvvX32iF.js → sidebar-mobile-menu-toggle-giMMZctn.js} +1 -1
  119. package/build/assets/{sidebar-nav-link-5AlTT5-j.js → sidebar-nav-link-CHqyFXwV.js} +1 -1
  120. package/build/assets/{sidebar-store-CZuE8AH5.js → sidebar-store-uiUXBU1N.js} +1 -1
  121. package/build/assets/{skill-card-pill-row-eTIkE4nz.js → skill-card-pill-row-BPYKQ3IN.js} +1 -1
  122. package/build/assets/skills-plugins-Tropusio.js +1 -0
  123. package/build/assets/{skills-settings-BUv04tSc.js → skills-settings-BvzBBCWk.js} +2 -2
  124. package/build/assets/{square-chevron-right-Czw3FFWc.js → square-chevron-right-DE-JN-2Z.js} +1 -1
  125. package/build/assets/{styled-tooltip-CgX2oRaK.js → styled-tooltip-B14i_Uac.js} +1 -1
  126. package/build/assets/{suspense-BO1Tl_Vf.js → suspense-DmZ3MSSh.js} +1 -1
  127. package/build/assets/{task-list-tab-0k9PhuqO.js → task-list-tab-DyfgG4MC.js} +1 -1
  128. package/build/assets/telemetry-C5JMEfqB.js +2 -0
  129. package/build/assets/{terminal-B61WrJdS.js → terminal-DRXt2Lr4.js} +1 -1
  130. package/build/assets/{toggle-switch-2j5wwR85.js → toggle-switch-DX_k418f.js} +1 -1
  131. package/build/assets/{trash-2-Be_7y3Mn.js → trash-2-BU6BlW4i.js} +1 -1
  132. package/build/assets/{typography-D8mHDeNG.js → typography-CzfoD9DY.js} +1 -1
  133. package/build/assets/use-acp-credential-form-Bm8qXdlc.js +1 -0
  134. package/build/assets/{use-activate-agent-profile-20v1xU0H.js → use-activate-agent-profile-DlykqEfN.js} +1 -1
  135. package/build/assets/{use-active-agent-profile-BkJN7Xsy.js → use-active-agent-profile-hI-x-UBa.js} +1 -1
  136. package/build/assets/{use-active-conversation-DOZVSVtU.js → use-active-conversation-2qeez40F.js} +1 -1
  137. package/build/assets/use-agent-profiles-0pr5bLS7.js +1 -0
  138. package/build/assets/{use-agent-state-DHZO1obC.js → use-agent-state-C6peDXUm.js} +1 -1
  139. package/build/assets/use-backends-health-CLHPitJM.js +1 -0
  140. package/build/assets/{use-can-manage-org-profiles-C-OhWVBS.js → use-can-manage-org-profiles-Ck_bsNbH.js} +1 -1
  141. package/build/assets/use-cloud-current-user-id-DUCSxNjY.js +1 -0
  142. package/build/assets/use-config-B5r8erYt.js +1 -0
  143. package/build/assets/use-create-conversation-r1JHfKO5.js +1 -0
  144. package/build/assets/{use-create-secret-D0HCOZFu.js → use-create-secret-Cf2N11d2.js} +1 -1
  145. package/build/assets/{use-event-store-DjgU4wfO.js → use-event-store-Bbaz51GR.js} +1 -1
  146. package/build/assets/{use-handle-plan-click-DyRASKMC.js → use-handle-plan-click-CsAW3FlH.js} +1 -1
  147. package/build/assets/use-is-authed-BezEyfeh.js +1 -0
  148. package/build/assets/use-llm-profiles-Dr5__SlZ.js +1 -0
  149. package/build/assets/use-plugins-marketplace-BplU65ae.js +1 -0
  150. package/build/assets/use-runtime-is-ready-vCFOcLFa.js +1 -0
  151. package/build/assets/use-save-agent-profile-RqUGqTv6.js +1 -0
  152. package/build/assets/use-save-settings-Chvzeu2s.js +1 -0
  153. package/build/assets/use-settings-CyxSlyTQ.js +1 -0
  154. package/build/assets/use-settings-nav-items-zEkSO_Bf.js +16 -0
  155. package/build/assets/use-skills-xrVoKYrF.js +1 -0
  156. package/build/assets/{use-task-list-AVBLbbcR.js → use-task-list-CfisapBW.js} +1 -1
  157. package/build/assets/use-tracking-D2Qg5Lpd.js +1 -0
  158. package/build/assets/{use-user-conversation-zpx7I18x.js → use-user-conversation-CnE4zhOA.js} +1 -1
  159. package/build/assets/{useMutation-DrCAVg5w.js → useMutation-u8UgRgDK.js} +1 -1
  160. package/build/assets/{useMutationState-D8QN0ZCy.js → useMutationState-OnAsCLA_.js} +1 -1
  161. package/build/assets/{useQueries-DClgUTc7.js → useQueries-BpIlT8Mt.js} +1 -1
  162. package/build/assets/{useQuery-CRBP8vIS.js → useQuery-D5pEZbY0.js} +1 -1
  163. package/build/assets/{useTranslation-CDRCKC9-.js → useTranslation-Cbf5AGg_.js} +1 -1
  164. package/build/assets/{utils-D3U3rlqr.js → utils-DB9LsAzA.js} +1 -1
  165. package/build/assets/{vendor~browser-tab-Di0kh5Zw.js → vendor~browser-tab-CsMb-pta.js} +1 -1
  166. package/build/assets/{vendor~browser-Cvg7jXCP.js → vendor~browser-wXQ-WZEC.js} +1 -1
  167. package/build/assets/{vendor~entry.client-9tWQ_Ugw.js → vendor~entry.client-DDuH4--y.js} +1 -1
  168. package/build/assets/{vendor~entry.client-D6BtSOtn.js → vendor~entry.client-DQGrNspu.js} +1 -1
  169. package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dhilvkxv-eGLBu60s.js +2 -0
  170. package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~iztiaf2o-rqo6vRFz.js +185 -0
  171. package/build/assets/{vendor~files-tab-B02k3xvx.js → vendor~files-tab-B-5fBohe.js} +1 -1
  172. package/build/assets/{vendor~home~conversation-panel~conversation-CYMF9JYB.js → vendor~index-home~home~conversation-panel~conversation-ChmYLVgz.js} +1 -1
  173. package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BD7v71DM.js +2 -0
  174. 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-BT05Osu4.js} +1 -1
  175. 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-DgzWSMRc.js} +1 -1
  176. 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-DqZatR3B.js} +1 -1
  177. package/build/assets/{vendor~launch-CHXA9cJu.js → vendor~launch-_Km3J77E.js} +1 -1
  178. package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~ivvrgjsa-BlIZPCXX.js → vendor~module-D5a_AClf.js} +1 -1
  179. package/build/assets/{vendor~root-layout~conversation-panel~conversation-CpiTHpHl.js → vendor~root-layout~conversation-panel~conversation-8tIsyrPj.js} +1 -1
  180. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-_TdZcNMD.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-BrguKXCn.js} +1 -1
  181. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation-Cn2jwSga.js → vendor~root-layout~index-home~home~conversation-panel~conversation-BTvhGHHG.js} +1 -1
  182. 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-BOKQkbc6.js} +1 -1
  183. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~settings~settings-index~agen~enjl5xdm-B0EIDu4M.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~ftka0fnu-cFNmfAE6.js} +2 -2
  184. package/build/assets/{verification-settings-D576N2xa.js → verification-settings-CfkrXoSa.js} +1 -1
  185. package/build/assets/x-ZE4iplpF.js +1 -0
  186. package/build/index.html +4 -4
  187. package/build/locales/ar/openhands.json +9 -0
  188. package/build/locales/ca/openhands.json +9 -0
  189. package/build/locales/de/openhands.json +9 -0
  190. package/build/locales/en/openhands.json +9 -0
  191. package/build/locales/es/openhands.json +9 -0
  192. package/build/locales/fr/openhands.json +9 -0
  193. package/build/locales/it/openhands.json +9 -0
  194. package/build/locales/ja/openhands.json +9 -0
  195. package/build/locales/ko-KR/openhands.json +9 -0
  196. package/build/locales/no/openhands.json +9 -0
  197. package/build/locales/pt/openhands.json +9 -0
  198. package/build/locales/tr/openhands.json +9 -0
  199. package/build/locales/uk/openhands.json +9 -0
  200. package/build/locales/zh-CN/openhands.json +9 -0
  201. package/build/locales/zh-TW/openhands.json +9 -0
  202. package/config/defaults.json +5 -4
  203. package/dist/api/agent-server-adapter.cjs +3 -3
  204. package/dist/api/agent-server-adapter.cjs.map +1 -1
  205. package/dist/api/agent-server-adapter.d.ts +9 -1
  206. package/dist/api/agent-server-adapter.js +105 -102
  207. package/dist/api/agent-server-adapter.js.map +1 -1
  208. package/dist/api/agent-server-config.cjs +1 -1
  209. package/dist/api/agent-server-config.cjs.map +1 -1
  210. package/dist/api/agent-server-config.d.ts +3 -0
  211. package/dist/api/agent-server-config.js +45 -23
  212. package/dist/api/agent-server-config.js.map +1 -1
  213. package/dist/api/backend-registry/auth.cjs +1 -1
  214. package/dist/api/backend-registry/auth.cjs.map +1 -1
  215. package/dist/api/backend-registry/auth.js +1 -1
  216. package/dist/api/backend-registry/auth.js.map +1 -1
  217. package/dist/api/backend-registry/default-backend.cjs +1 -1
  218. package/dist/api/backend-registry/default-backend.cjs.map +1 -1
  219. package/dist/api/backend-registry/default-backend.d.ts +3 -0
  220. package/dist/api/backend-registry/default-backend.js +22 -10
  221. package/dist/api/backend-registry/default-backend.js.map +1 -1
  222. package/dist/api/backend-registry/storage.cjs +1 -1
  223. package/dist/api/backend-registry/storage.cjs.map +1 -1
  224. package/dist/api/backend-registry/storage.js +38 -33
  225. package/dist/api/backend-registry/storage.js.map +1 -1
  226. package/dist/api/backend-registry/types.d.ts +2 -0
  227. package/dist/api/canvas-ui-client-tool.cjs +38 -0
  228. package/dist/api/canvas-ui-client-tool.cjs.map +1 -0
  229. package/dist/api/canvas-ui-client-tool.d.ts +14 -0
  230. package/dist/api/canvas-ui-client-tool.js +47 -0
  231. package/dist/api/canvas-ui-client-tool.js.map +1 -0
  232. package/dist/api/client-source.cjs +2 -0
  233. package/dist/api/client-source.cjs.map +1 -0
  234. package/dist/api/client-source.d.ts +9 -0
  235. package/dist/api/client-source.js +10 -0
  236. package/dist/api/client-source.js.map +1 -0
  237. package/dist/api/cloud/client.cjs +2 -0
  238. package/dist/api/cloud/client.cjs.map +1 -0
  239. package/dist/api/cloud/client.d.ts +4 -0
  240. package/dist/api/cloud/client.js +38 -0
  241. package/dist/api/cloud/client.js.map +1 -0
  242. package/dist/api/cloud/conversation-service.api.cjs +1 -1
  243. package/dist/api/cloud/conversation-service.api.cjs.map +1 -1
  244. package/dist/api/cloud/conversation-service.api.js +35 -33
  245. package/dist/api/cloud/conversation-service.api.js.map +1 -1
  246. package/dist/api/cloud/organization-service.api.cjs +1 -1
  247. package/dist/api/cloud/organization-service.api.cjs.map +1 -1
  248. package/dist/api/cloud/organization-service.api.js +11 -10
  249. package/dist/api/cloud/organization-service.api.js.map +1 -1
  250. package/dist/api/cloud/proxy.cjs +1 -1
  251. package/dist/api/cloud/proxy.cjs.map +1 -1
  252. package/dist/api/cloud/proxy.d.ts +2 -40
  253. package/dist/api/cloud/proxy.js +14 -39
  254. package/dist/api/cloud/proxy.js.map +1 -1
  255. package/dist/api/conversation-metadata-store.cjs +1 -1
  256. package/dist/api/conversation-metadata-store.cjs.map +1 -1
  257. package/dist/api/conversation-metadata-store.d.ts +2 -9
  258. package/dist/api/conversation-metadata-store.js +13 -9
  259. package/dist/api/conversation-metadata-store.js.map +1 -1
  260. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  261. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  262. package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +2 -1
  263. package/dist/api/conversation-service/agent-server-conversation-service.api.js +98 -88
  264. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  265. package/dist/api/conversation-service/agent-server-conversation-service.types.d.ts +5 -0
  266. package/dist/api/device-flow-client.cjs +1 -1
  267. package/dist/api/device-flow-client.cjs.map +1 -1
  268. package/dist/api/device-flow-client.d.ts +4 -58
  269. package/dist/api/device-flow-client.js +8 -98
  270. package/dist/api/device-flow-client.js.map +1 -1
  271. package/dist/api/git-service/agent-server-git-service.api.cjs +1 -1
  272. package/dist/api/git-service/agent-server-git-service.api.cjs.map +1 -1
  273. package/dist/api/git-service/agent-server-git-service.api.d.ts +10 -2
  274. package/dist/api/git-service/agent-server-git-service.api.js +107 -40
  275. package/dist/api/git-service/agent-server-git-service.api.js.map +1 -1
  276. package/dist/api/open-hands.types.d.ts +11 -0
  277. package/dist/api/option-service/option-service.api.cjs +1 -1
  278. package/dist/api/option-service/option-service.api.cjs.map +1 -1
  279. package/dist/api/option-service/option-service.api.js +0 -1
  280. package/dist/api/option-service/option-service.api.js.map +1 -1
  281. package/dist/api/option-service/option.types.d.ts +0 -1
  282. package/dist/api/secrets-service.cjs +1 -1
  283. package/dist/api/secrets-service.cjs.map +1 -1
  284. package/dist/api/secrets-service.js +15 -14
  285. package/dist/api/secrets-service.js.map +1 -1
  286. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs +1 -1
  287. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs.map +1 -1
  288. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js +73 -64
  289. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js.map +1 -1
  290. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.cjs +2 -2
  291. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.cjs.map +1 -1
  292. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.js +2 -0
  293. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.js.map +1 -1
  294. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  295. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  296. package/dist/components/features/backends/backend-form-modal.d.ts +4 -2
  297. package/dist/components/features/backends/backend-form-modal.js +108 -101
  298. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  299. package/dist/components/features/backends/backend-row.cjs +1 -1
  300. package/dist/components/features/backends/backend-row.cjs.map +1 -1
  301. package/dist/components/features/backends/backend-row.js +2 -1
  302. package/dist/components/features/backends/backend-row.js.map +1 -1
  303. package/dist/components/features/backends/backend-selector.cjs +1 -1
  304. package/dist/components/features/backends/backend-selector.cjs.map +1 -1
  305. package/dist/components/features/backends/backend-selector.js +51 -51
  306. package/dist/components/features/backends/backend-selector.js.map +1 -1
  307. package/dist/components/features/backends/device-flow-auth.cjs +1 -1
  308. package/dist/components/features/backends/device-flow-auth.cjs.map +1 -1
  309. package/dist/components/features/backends/device-flow-auth.d.ts +4 -1
  310. package/dist/components/features/backends/device-flow-auth.js +38 -38
  311. package/dist/components/features/backends/device-flow-auth.js.map +1 -1
  312. package/dist/components/features/chat/chat-interface.cjs +2 -2
  313. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  314. package/dist/components/features/chat/chat-interface.js +173 -165
  315. package/dist/components/features/chat/chat-interface.js.map +1 -1
  316. package/dist/components/features/chat/components/chat-input-actions.cjs +1 -1
  317. package/dist/components/features/chat/components/chat-input-actions.cjs.map +1 -1
  318. package/dist/components/features/chat/components/chat-input-actions.d.ts +2 -1
  319. package/dist/components/features/chat/components/chat-input-actions.js +44 -43
  320. package/dist/components/features/chat/components/chat-input-actions.js.map +1 -1
  321. package/dist/components/features/chat/components/chat-input-container.cjs +1 -1
  322. package/dist/components/features/chat/components/chat-input-container.cjs.map +1 -1
  323. package/dist/components/features/chat/components/chat-input-container.d.ts +2 -1
  324. package/dist/components/features/chat/components/chat-input-container.js +20 -19
  325. package/dist/components/features/chat/components/chat-input-container.js.map +1 -1
  326. package/dist/components/features/chat/components/chat-input-profile-picker.cjs +1 -1
  327. package/dist/components/features/chat/components/chat-input-profile-picker.cjs.map +1 -1
  328. package/dist/components/features/chat/components/chat-input-profile-picker.js +44 -32
  329. package/dist/components/features/chat/components/chat-input-profile-picker.js.map +1 -1
  330. package/dist/components/features/chat/components/resolve-picker-kind.cjs +1 -1
  331. package/dist/components/features/chat/components/resolve-picker-kind.cjs.map +1 -1
  332. package/dist/components/features/chat/components/resolve-picker-kind.d.ts +10 -22
  333. package/dist/components/features/chat/components/resolve-picker-kind.js +6 -3
  334. package/dist/components/features/chat/components/resolve-picker-kind.js.map +1 -1
  335. package/dist/components/features/chat/custom-chat-input.cjs +1 -1
  336. package/dist/components/features/chat/custom-chat-input.cjs.map +1 -1
  337. package/dist/components/features/chat/custom-chat-input.d.ts +2 -1
  338. package/dist/components/features/chat/custom-chat-input.js +52 -51
  339. package/dist/components/features/chat/custom-chat-input.js.map +1 -1
  340. package/dist/components/features/chat/interactive-chat-box.cjs +1 -1
  341. package/dist/components/features/chat/interactive-chat-box.cjs.map +1 -1
  342. package/dist/components/features/chat/interactive-chat-box.d.ts +2 -1
  343. package/dist/components/features/chat/interactive-chat-box.js +9 -8
  344. package/dist/components/features/chat/interactive-chat-box.js.map +1 -1
  345. package/dist/components/features/diff-viewer/commit-list.cjs +2 -0
  346. package/dist/components/features/diff-viewer/commit-list.cjs.map +1 -0
  347. package/dist/components/features/diff-viewer/commit-list.d.ts +13 -0
  348. package/dist/components/features/diff-viewer/commit-list.js +27 -0
  349. package/dist/components/features/diff-viewer/commit-list.js.map +1 -0
  350. package/dist/components/features/diff-viewer/commit-row.cjs +2 -0
  351. package/dist/components/features/diff-viewer/commit-row.cjs.map +1 -0
  352. package/dist/components/features/diff-viewer/commit-row.d.ts +14 -0
  353. package/dist/components/features/diff-viewer/commit-row.js +59 -0
  354. package/dist/components/features/diff-viewer/commit-row.js.map +1 -0
  355. package/dist/components/features/diff-viewer/file-diff-viewer.cjs +1 -1
  356. package/dist/components/features/diff-viewer/file-diff-viewer.cjs.map +1 -1
  357. package/dist/components/features/diff-viewer/file-diff-viewer.d.ts +7 -1
  358. package/dist/components/features/diff-viewer/file-diff-viewer.js +40 -39
  359. package/dist/components/features/diff-viewer/file-diff-viewer.js.map +1 -1
  360. package/dist/components/features/plugins/plugin-detail-modal.d.ts +2 -1
  361. package/dist/components/providers/agent-server-ui-providers.cjs +1 -1
  362. package/dist/components/providers/agent-server-ui-providers.cjs.map +1 -1
  363. package/dist/components/providers/agent-server-ui-providers.d.ts +4 -2
  364. package/dist/components/providers/agent-server-ui-providers.js +9 -2
  365. package/dist/components/providers/agent-server-ui-providers.js.map +1 -1
  366. package/dist/components/providers/index.cjs +1 -1
  367. package/dist/components/providers/index.d.ts +1 -2
  368. package/dist/components/providers/index.js +0 -1
  369. package/dist/components/providers/telemetry-provider.cjs +2 -0
  370. package/dist/components/providers/telemetry-provider.cjs.map +1 -0
  371. package/dist/components/providers/telemetry-provider.d.ts +6 -0
  372. package/dist/components/providers/telemetry-provider.js +64 -0
  373. package/dist/components/providers/telemetry-provider.js.map +1 -0
  374. package/dist/components/shared/modals/settings/settings-modal.cjs +1 -1
  375. package/dist/components/shared/modals/settings/settings-modal.cjs.map +1 -1
  376. package/dist/components/shared/modals/settings/settings-modal.js +23 -22
  377. package/dist/components/shared/modals/settings/settings-modal.js.map +1 -1
  378. package/dist/config/defaults.cjs +1 -1
  379. package/dist/config/defaults.cjs.map +1 -1
  380. package/dist/config/defaults.js +5 -4
  381. package/dist/config/defaults.js.map +1 -1
  382. package/dist/constants/acp-providers.cjs.map +1 -1
  383. package/dist/constants/acp-providers.d.ts +1 -1
  384. package/dist/constants/acp-providers.js.map +1 -1
  385. package/dist/constants/canvas-ui.cjs +2 -0
  386. package/dist/constants/canvas-ui.cjs.map +1 -0
  387. package/dist/constants/canvas-ui.d.ts +8 -0
  388. package/dist/constants/canvas-ui.js +6 -0
  389. package/dist/constants/canvas-ui.js.map +1 -0
  390. package/dist/contexts/conversation-websocket-context.cjs +3 -3
  391. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  392. package/dist/contexts/conversation-websocket-context.js +197 -204
  393. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  394. package/dist/hooks/mutation/use-create-conversation.cjs +1 -1
  395. package/dist/hooks/mutation/use-create-conversation.cjs.map +1 -1
  396. package/dist/hooks/mutation/use-create-conversation.d.ts +2 -1
  397. package/dist/hooks/mutation/use-create-conversation.js +52 -52
  398. package/dist/hooks/mutation/use-create-conversation.js.map +1 -1
  399. package/dist/hooks/mutation/use-save-settings.cjs +1 -1
  400. package/dist/hooks/mutation/use-save-settings.cjs.map +1 -1
  401. package/dist/hooks/mutation/use-save-settings.d.ts +3 -1
  402. package/dist/hooks/mutation/use-save-settings.js +6 -5
  403. package/dist/hooks/mutation/use-save-settings.js.map +1 -1
  404. package/dist/hooks/query/query-keys.cjs +1 -1
  405. package/dist/hooks/query/query-keys.cjs.map +1 -1
  406. package/dist/hooks/query/query-keys.d.ts +2 -0
  407. package/dist/hooks/query/query-keys.js +4 -1
  408. package/dist/hooks/query/query-keys.js.map +1 -1
  409. package/dist/hooks/query/use-backends-health.cjs +1 -1
  410. package/dist/hooks/query/use-backends-health.cjs.map +1 -1
  411. package/dist/hooks/query/use-backends-health.js +50 -48
  412. package/dist/hooks/query/use-backends-health.js.map +1 -1
  413. package/dist/hooks/query/use-cloud-organizations.cjs +1 -1
  414. package/dist/hooks/query/use-cloud-organizations.cjs.map +1 -1
  415. package/dist/hooks/query/use-cloud-organizations.d.ts +1 -0
  416. package/dist/hooks/query/use-cloud-organizations.js +5 -2
  417. package/dist/hooks/query/use-cloud-organizations.js.map +1 -1
  418. package/dist/hooks/query/use-commit-changes.cjs +2 -0
  419. package/dist/hooks/query/use-commit-changes.cjs.map +1 -0
  420. package/dist/hooks/query/use-commit-changes.d.ts +5 -0
  421. package/dist/hooks/query/use-commit-changes.js +34 -0
  422. package/dist/hooks/query/use-commit-changes.js.map +1 -0
  423. package/dist/hooks/query/use-task-polling.cjs +1 -1
  424. package/dist/hooks/query/use-task-polling.cjs.map +1 -1
  425. package/dist/hooks/query/use-task-polling.d.ts +3 -2
  426. package/dist/hooks/query/use-task-polling.js +53 -40
  427. package/dist/hooks/query/use-task-polling.js.map +1 -1
  428. package/dist/hooks/query/use-unified-git-commits.cjs +2 -0
  429. package/dist/hooks/query/use-unified-git-commits.cjs.map +1 -0
  430. package/dist/hooks/query/use-unified-git-commits.d.ts +10 -0
  431. package/dist/hooks/query/use-unified-git-commits.js +41 -0
  432. package/dist/hooks/query/use-unified-git-commits.js.map +1 -0
  433. package/dist/hooks/query/use-unified-git-diff.cjs +1 -1
  434. package/dist/hooks/query/use-unified-git-diff.cjs.map +1 -1
  435. package/dist/hooks/query/use-unified-git-diff.d.ts +5 -0
  436. package/dist/hooks/query/use-unified-git-diff.js +11 -4
  437. package/dist/hooks/query/use-unified-git-diff.js.map +1 -1
  438. package/dist/hooks/use-acp-model-context.cjs +1 -1
  439. package/dist/hooks/use-acp-model-context.cjs.map +1 -1
  440. package/dist/hooks/use-acp-model-context.d.ts +4 -1
  441. package/dist/hooks/use-acp-model-context.js +9 -8
  442. package/dist/hooks/use-acp-model-context.js.map +1 -1
  443. package/dist/hooks/use-auto-refresh-files-on-edit.cjs +1 -1
  444. package/dist/hooks/use-auto-refresh-files-on-edit.cjs.map +1 -1
  445. package/dist/hooks/use-auto-refresh-files-on-edit.js +1 -1
  446. package/dist/hooks/use-auto-refresh-files-on-edit.js.map +1 -1
  447. package/dist/hooks/use-chat-input-model-state.cjs.map +1 -1
  448. package/dist/hooks/use-chat-input-model-state.d.ts +2 -1
  449. package/dist/hooks/use-chat-input-model-state.js.map +1 -1
  450. package/dist/hooks/use-chat-input-profile-state.cjs +1 -1
  451. package/dist/hooks/use-chat-input-profile-state.cjs.map +1 -1
  452. package/dist/hooks/use-chat-input-profile-state.d.ts +1 -10
  453. package/dist/hooks/use-chat-input-profile-state.js +42 -15
  454. package/dist/hooks/use-chat-input-profile-state.js.map +1 -1
  455. package/dist/hooks/use-device-flow.cjs +1 -1
  456. package/dist/hooks/use-device-flow.cjs.map +1 -1
  457. package/dist/hooks/use-device-flow.d.ts +4 -1
  458. package/dist/hooks/use-device-flow.js +42 -40
  459. package/dist/hooks/use-device-flow.js.map +1 -1
  460. package/dist/hooks/use-telemetry.cjs +1 -1
  461. package/dist/hooks/use-telemetry.cjs.map +1 -1
  462. package/dist/hooks/use-telemetry.d.ts +3 -3
  463. package/dist/hooks/use-telemetry.js +16 -22
  464. package/dist/hooks/use-telemetry.js.map +1 -1
  465. package/dist/hooks/use-tracking.cjs +1 -1
  466. package/dist/hooks/use-tracking.cjs.map +1 -1
  467. package/dist/hooks/use-tracking.d.ts +5 -5
  468. package/dist/hooks/use-tracking.js +37 -37
  469. package/dist/hooks/use-tracking.js.map +1 -1
  470. package/dist/i18n/declaration.cjs +1 -1
  471. package/dist/i18n/declaration.cjs.map +1 -1
  472. package/dist/i18n/declaration.d.ts +9 -0
  473. package/dist/i18n/declaration.js +1 -1
  474. package/dist/i18n/declaration.js.map +1 -1
  475. package/dist/i18n/index.cjs +1 -1
  476. package/dist/i18n/index.cjs.map +1 -1
  477. package/dist/i18n/index.js +19 -18
  478. package/dist/i18n/index.js.map +1 -1
  479. package/dist/i18n/translation.cjs +2 -2
  480. package/dist/i18n/translation.cjs.map +1 -1
  481. package/dist/i18n/translation.js +153 -0
  482. package/dist/i18n/translation.js.map +1 -1
  483. package/dist/index.cjs +1 -1
  484. package/dist/index.js +32 -32
  485. package/dist/lib/index.cjs +1 -1
  486. package/dist/lib/index.d.ts +2 -2
  487. package/dist/lib/index.js +1 -1
  488. package/dist/locales/ar/openhands.json +9 -0
  489. package/dist/locales/ca/openhands.json +9 -0
  490. package/dist/locales/de/openhands.json +9 -0
  491. package/dist/locales/en/openhands.json +9 -0
  492. package/dist/locales/es/openhands.json +9 -0
  493. package/dist/locales/fr/openhands.json +9 -0
  494. package/dist/locales/it/openhands.json +9 -0
  495. package/dist/locales/ja/openhands.json +9 -0
  496. package/dist/locales/ko-KR/openhands.json +9 -0
  497. package/dist/locales/no/openhands.json +9 -0
  498. package/dist/locales/pt/openhands.json +9 -0
  499. package/dist/locales/tr/openhands.json +9 -0
  500. package/dist/locales/uk/openhands.json +9 -0
  501. package/dist/locales/zh-CN/openhands.json +9 -0
  502. package/dist/locales/zh-TW/openhands.json +9 -0
  503. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.cjs +2 -0
  504. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.cjs.map +1 -0
  505. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.js +351 -0
  506. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.js.map +1 -0
  507. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.cjs +2 -0
  508. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.cjs.map +1 -0
  509. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.js +106 -0
  510. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.js.map +1 -0
  511. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.cjs +2 -0
  512. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.cjs.map +1 -0
  513. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.js +69 -0
  514. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.js.map +1 -0
  515. package/dist/node_modules/@openhands/typescript-client/dist/clients.cjs +1 -1
  516. package/dist/node_modules/@openhands/typescript-client/dist/clients.js +3 -0
  517. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs +1 -1
  518. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs.map +1 -1
  519. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js +18 -2
  520. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js.map +1 -1
  521. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.cjs.map +1 -1
  522. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.js.map +1 -1
  523. package/dist/node_modules/axios/index.cjs +1 -1
  524. package/dist/node_modules/axios/index.js +1 -1
  525. package/dist/package.cjs +1 -1
  526. package/dist/package.cjs.map +1 -1
  527. package/dist/package.js +3 -3
  528. package/dist/package.js.map +1 -1
  529. package/dist/routes/app-settings.cjs +1 -1
  530. package/dist/routes/app-settings.cjs.map +1 -1
  531. package/dist/routes/app-settings.js +59 -60
  532. package/dist/routes/app-settings.js.map +1 -1
  533. package/dist/routes/commits-tab.cjs +2 -0
  534. package/dist/routes/commits-tab.cjs.map +1 -0
  535. package/dist/routes/commits-tab.d.ts +8 -0
  536. package/dist/routes/commits-tab.js +45 -0
  537. package/dist/routes/commits-tab.js.map +1 -0
  538. package/dist/routes/files-tab.cjs +1 -1
  539. package/dist/routes/files-tab.cjs.map +1 -1
  540. package/dist/routes/files-tab.js +148 -127
  541. package/dist/routes/files-tab.js.map +1 -1
  542. package/dist/routes/llm-settings.cjs +1 -1
  543. package/dist/routes/llm-settings.cjs.map +1 -1
  544. package/dist/routes/llm-settings.js +4 -1
  545. package/dist/routes/llm-settings.js.map +1 -1
  546. package/dist/services/cloud-funnel-analytics.cjs +2 -0
  547. package/dist/services/cloud-funnel-analytics.cjs.map +1 -0
  548. package/dist/services/cloud-funnel-analytics.d.ts +4 -0
  549. package/dist/services/cloud-funnel-analytics.js +39 -0
  550. package/dist/services/cloud-funnel-analytics.js.map +1 -0
  551. package/dist/services/telemetry.cjs +1 -1
  552. package/dist/services/telemetry.cjs.map +1 -1
  553. package/dist/services/telemetry.d.ts +46 -9
  554. package/dist/services/telemetry.js +182 -71
  555. package/dist/services/telemetry.js.map +1 -1
  556. package/dist/themes/color-themes.cjs.map +1 -1
  557. package/dist/themes/color-themes.d.ts +3 -6
  558. package/dist/themes/color-themes.js.map +1 -1
  559. package/dist/types/agent-server/core/base/action.d.ts +5 -4
  560. package/dist/types/agent-server/core/base/base.d.ts +3 -2
  561. package/dist/types/agent-server/core/base/observation.d.ts +1 -1
  562. package/dist/types/agent-server/type-guards.cjs +1 -1
  563. package/dist/types/agent-server/type-guards.cjs.map +1 -1
  564. package/dist/types/agent-server/type-guards.d.ts +3 -5
  565. package/dist/types/agent-server/type-guards.js +2 -1
  566. package/dist/types/agent-server/type-guards.js.map +1 -1
  567. package/dist/types/automation.d.ts +5 -0
  568. package/dist/utils/api-error-message.d.ts +11 -0
  569. package/dist/utils/automation-timeout.d.ts +19 -0
  570. package/dist/utils/base-path.cjs +2 -0
  571. package/dist/utils/base-path.cjs.map +1 -0
  572. package/dist/utils/base-path.d.ts +2 -0
  573. package/dist/utils/base-path.js +23 -0
  574. package/dist/utils/base-path.js.map +1 -0
  575. package/dist/utils/error-handler.cjs +1 -1
  576. package/dist/utils/error-handler.cjs.map +1 -1
  577. package/dist/utils/error-handler.d.ts +1 -4
  578. package/dist/utils/error-handler.js +6 -7
  579. package/dist/utils/error-handler.js.map +1 -1
  580. package/dist/utils/map-provider.cjs +1 -1
  581. package/dist/utils/map-provider.cjs.map +1 -1
  582. package/dist/utils/map-provider.d.ts +1 -0
  583. package/dist/utils/map-provider.js +2 -1
  584. package/dist/utils/map-provider.js.map +1 -1
  585. package/package.json +3 -3
  586. package/scripts/check-sdk-version-sync.mjs +6 -6
  587. package/scripts/dev-safe.mjs +7 -8
  588. package/scripts/dev-static.mjs +3 -0
  589. package/scripts/dev-with-automation.mjs +3 -0
  590. package/scripts/docker-build.mjs +4 -0
  591. package/scripts/static-server.mjs +93 -7
  592. package/tools/canvas_ui_tool.py +14 -8
  593. package/build/assets/active-backend-context-hxq31W25.js +0 -1
  594. package/build/assets/agent-server-client-options-DVLRd9sw.js +0 -1
  595. package/build/assets/agent-server-conversation-service.api-CuSdr4Qb.js +0 -5
  596. package/build/assets/agent-settings-D_yOy8XB.js +0 -1
  597. package/build/assets/api-key-entry-screen-Dl0qVYi4.js +0 -1
  598. package/build/assets/app-settings-yVizGXox.js +0 -1
  599. package/build/assets/automation-detail-dvJfLs5u.js +0 -2
  600. package/build/assets/automation-export-BPcgLqPD.js +0 -2
  601. package/build/assets/automations-list-CUXogTe0.js +0 -1
  602. package/build/assets/backend-form-modal-CQJGmItq.js +0 -1
  603. package/build/assets/check-Bvi71siz.js +0 -1
  604. package/build/assets/condenser-settings-Ca8fYZ_Z.js +0 -1
  605. package/build/assets/conversation-9NBSRoR9.js +0 -1
  606. package/build/assets/conversation-BXg6Oti2.js +0 -89
  607. package/build/assets/conversation-panel-CZri9Rup.js +0 -1
  608. package/build/assets/conversation-service.api-DPBQvTKD.js +0 -1
  609. package/build/assets/declaration-gq8V5eTU.js +0 -1
  610. package/build/assets/files-tab-UVoray88.js +0 -1
  611. package/build/assets/git-provider-icon-o6hdnJUB.js +0 -1
  612. package/build/assets/handle-capture-consent-CPMXU29K.js +0 -1
  613. package/build/assets/home-D1IHvGTN.js +0 -1
  614. package/build/assets/index-redirect-CUUJiNki.js +0 -1
  615. package/build/assets/install-server-modal-BbuQaA2w.js +0 -1
  616. package/build/assets/lesson-plan-jC0HBoe6.js +0 -4
  617. package/build/assets/llm-not-configured-banner-DoARbcdL.js +0 -27
  618. package/build/assets/llm-settings-4JMLV8mq.js +0 -1
  619. package/build/assets/llm-settings-D91gMw3U.js +0 -1
  620. package/build/assets/llm-subscription-service-CKyaV24y.js +0 -1
  621. package/build/assets/loader-circle-BEykUKYG.js +0 -1
  622. package/build/assets/manage-backends-modal-DkWAMSle.js +0 -1
  623. package/build/assets/manifest-aa5c29f6.js +0 -1
  624. package/build/assets/model-selector-BfqpMkSJ.js +0 -1
  625. package/build/assets/mouse-pointer-click-PdEQPL6v.js +0 -1
  626. package/build/assets/onboarding-Bu-HN1ze.js +0 -1
  627. package/build/assets/onboarding-modal-CZgjs5Bx.js +0 -1
  628. package/build/assets/option-service.api-BrZ5q87N.js +0 -1
  629. package/build/assets/organization-service.api-Bk4pCGU1.js +0 -1
  630. package/build/assets/path-utils-CSmuZoix.js +0 -1
  631. package/build/assets/plugins-management-service-BRBLxvUl.js +0 -1
  632. package/build/assets/profiles-service.api-BMXQ9pZC.js +0 -1
  633. package/build/assets/providers-BpO967xS.js +0 -1
  634. package/build/assets/proxy-BgJLtxu7.js +0 -1
  635. package/build/assets/root-BM5WgQ4_.js +0 -2
  636. package/build/assets/root-V8fkplMy.css +0 -1
  637. package/build/assets/root-layout-BdoyoobY.js +0 -2
  638. package/build/assets/schema-field-BSHrUMme.js +0 -1
  639. package/build/assets/sdk-section-page-t82gsOqa.js +0 -1
  640. package/build/assets/search-4DHskuhE.js +0 -1
  641. package/build/assets/secrets-service-B2GqPV0N.js +0 -1
  642. package/build/assets/settings-DmPLkgq0.js +0 -1
  643. package/build/assets/settings-modal-CwrZKrTq.js +0 -1
  644. package/build/assets/settings-service.api-Ce-ub11I.js +0 -1
  645. package/build/assets/shared-conversation-BDREQPnE.js +0 -1
  646. package/build/assets/skills-plugins-2Y44YHbO.js +0 -1
  647. package/build/assets/use-acp-credential-form-MzZM6D7D.js +0 -1
  648. package/build/assets/use-agent-profiles-DwZxnwO5.js +0 -1
  649. package/build/assets/use-backends-health-CRHzuvxO.js +0 -1
  650. package/build/assets/use-cloud-current-user-id-utFreJ0i.js +0 -1
  651. package/build/assets/use-config-mJrtZHP1.js +0 -1
  652. package/build/assets/use-create-conversation-DdqsP78F.js +0 -1
  653. package/build/assets/use-is-authed-B6M0mcGL.js +0 -1
  654. package/build/assets/use-llm-profiles-RC-PkpBl.js +0 -1
  655. package/build/assets/use-plugins-marketplace-FHlbeQ4c.js +0 -1
  656. package/build/assets/use-runtime-is-ready-RKj2WmEh.js +0 -1
  657. package/build/assets/use-save-agent-profile-tvDP15mh.js +0 -1
  658. package/build/assets/use-save-settings-BGlSfuYn.js +0 -1
  659. package/build/assets/use-settings-CH5LzXD8.js +0 -1
  660. package/build/assets/use-settings-nav-items-Dwktv8wo.js +0 -16
  661. package/build/assets/use-skills-CSzSL6HG.js +0 -1
  662. package/build/assets/use-tracking-BIXzagSI.js +0 -1
  663. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~lf310vj7-CSVPGId3.js +0 -10
  664. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~nfpll1wp-BCpa95De.js +0 -177
  665. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~jewnulst-C57fm7C-.js +0 -1
  666. package/build/assets/vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CqXiHwjU.js +0 -2
  667. package/build/assets/x-Cb0WAtak.js +0 -1
  668. package/dist/components/providers/posthog-wrapper.cjs +0 -2
  669. package/dist/components/providers/posthog-wrapper.cjs.map +0 -1
  670. package/dist/components/providers/posthog-wrapper.d.ts +0 -4
  671. package/dist/components/providers/posthog-wrapper.js +0 -49
  672. package/dist/components/providers/posthog-wrapper.js.map +0 -1
  673. package/dist/node_modules/posthog-js/react/dist/esm/index.cjs +0 -2
  674. package/dist/node_modules/posthog-js/react/dist/esm/index.cjs.map +0 -1
  675. package/dist/node_modules/posthog-js/react/dist/esm/index.js +0 -113
  676. package/dist/node_modules/posthog-js/react/dist/esm/index.js.map +0 -1
  677. package/dist/utils/handle-capture-consent.cjs +0 -2
  678. package/dist/utils/handle-capture-consent.cjs.map +0 -1
  679. package/dist/utils/handle-capture-consent.d.ts +0 -7
  680. package/dist/utils/handle-capture-consent.js +0 -8
  681. package/dist/utils/handle-capture-consent.js.map +0 -1
  682. /package/build/assets/{__vite-browser-external-4xJsU2-u.js → __vite-browser-external-BQUj0sYu.js} +0 -0
  683. /package/build/assets/{agent-server-ui-style-scope-COnDHTm5.js → agent-server-ui-style-scope-qhnhZHBV.js} +0 -0
  684. /package/build/assets/{automation-BU8zu-FP.js → automation-LZB0MjdV.js} +0 -0
  685. /package/build/assets/{close-p3Op5lxI.js → close-DLFb5kfv.js} +0 -0
  686. /package/build/assets/{common-Dh7OqABE.js → common-CxbUL3nR.js} +0 -0
  687. /package/build/assets/{createLucideIcon-CVAsW2Yo.js → createLucideIcon-D4Tak8A1.js} +0 -0
  688. /package/build/assets/{folder-mMWFvaw0.js → folder-Bk311brm.js} +0 -0
  689. /package/build/assets/{get-language-from-path-CPNnuVhI.js → get-language-from-path-DBqBsCWH.js} +0 -0
  690. /package/build/assets/{git-status-mapper-BI8FyUVp.js → git-status-mapper-DnL9OC8_.js} +0 -0
  691. /package/build/assets/{iconBase-DaTRRUjy.js → iconBase-Dz51Zn5x.js} +0 -0
  692. /package/build/assets/{link-external-DfKQroKX.js → link-external-CaBmUEs_.js} +0 -0
  693. /package/build/assets/{search-BsjCEFNf.js → search-BgOCR7_c.js} +0 -0
  694. /package/build/assets/{settings-like-page-layout-classes-DENKlZpD.js → settings-like-page-layout-classes-Cdl6jOe5.js} +0 -0
  695. /package/build/assets/{skills-9cDZONKh.js → skills-EqzxYBvT.js} +0 -0
  696. /package/build/assets/{terminal-BuLtIrb9.js → terminal-Cgf___rK.js} +0 -0
  697. /package/build/assets/{u-check-circle-half-LiwZkuFe.js → u-check-circle-half-MsShT8Ec.js} +0 -0
  698. /package/build/assets/{u-edit-DJ90xc8Z.js → u-edit-DL5LgKon.js} +0 -0
  699. /package/build/assets/{use-breakpoint-B-O0lQ84.js → use-breakpoint-BP3lqLMx.js} +0 -0
  700. /package/build/assets/{use-click-outside-element-Bf4Omzot.js → use-click-outside-element-D9BYdANT.js} +0 -0
  701. /package/build/assets/{use-launch-skill-in-chat-BnoDgvAy.js → use-launch-skill-in-chat-DJWEfVc5.js} +0 -0
  702. /package/build/assets/{vendor~browser-Dqd33JyP.js → vendor~browser-By2MVv_N.js} +0 -0
  703. /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-DHDkknt5.js → vendor~conversation-panel~conversation~alert-banner-CxfzCmkN.js} +0 -0
  704. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~epa72zsm-B4rXs7Zd.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~e0djk9ee-Cw6LUe8p.js} +0 -0
  705. /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
  706. /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-COhHANvV.js} +0 -0
  707. /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-FghQ3Z1a.js} +0 -0
  708. /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-mC0v44WR.js} +0 -0
  709. /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-C4-GDgiF.js} +0 -0
  710. /package/build/assets/{vendor~terminal-aeP3PnKf.js → vendor~terminal-CnKZILnC.js} +0 -0
@@ -1,117 +1,228 @@
1
1
  import e from "../package.js";
2
+ import { AGENT_CANVAS_CLIENT_SOURCE as t, AGENT_CANVAS_CLIENT_VERSION as n } from "../api/client-source.js";
2
3
  //#region src/services/telemetry.ts
3
- var t = "openhands-telemetry-consent", n = "openhands-telemetry-first-use", r = "openhands-telemetry-session", i = "phc_BgzfxKdgsYMLFTmJqt424ZoyVHvKFfrwttLimzdYTKFK", a = "https://z.openhands.dev", o = "https://us.posthog.com", s = !1, c = null;
4
- function l() {
4
+ var r = "openhands-telemetry-consent", i = "openhands-telemetry-consent-pending-cloud-sync", a = "openhands-telemetry-consent-change", o = "openhands-telemetry-first-use", s = "openhands-telemetry-session", c = "agent-canvas", l = "phc_BgzfxKdgsYMLFTmJqt424ZoyVHvKFfrwttLimzdYTKFK", u = "https://z.openhands.dev", d = "https://us.posthog.com", f = null, p = null, m, h = {}, g = !1, _, v = 0, y = -1, b = Object.freeze({
5
+ client_source: t,
6
+ client_version: n,
7
+ package_name: e.name,
8
+ package_version: e.version
9
+ });
10
+ function x(e) {
11
+ return e ? {
12
+ ...e,
13
+ properties: {
14
+ ...e.properties,
15
+ ...b
16
+ }
17
+ } : null;
18
+ }
19
+ function S(e) {
20
+ g || M() !== "granted" ? e.opt_out_capturing() : e.opt_in_capturing();
21
+ }
22
+ function C(e, t = !1) {
23
+ e.reset(t), y = -1, S(e);
24
+ }
25
+ function w(e) {
26
+ if (_ === void 0 || !R()) return;
27
+ let t = _?.distinctId, n = e.get_property("$user_id");
28
+ if (n != null && n !== t && C(e), _ === null) {
29
+ y = v;
30
+ return;
31
+ }
32
+ (e.get_property("$user_id") !== _.distinctId || y !== v) && (e.identify(_.distinctId, _.properties), y = v);
33
+ }
34
+ function T(e) {
35
+ if (e === !1) {
36
+ if (g) return;
37
+ g = !0, f?.opt_out_capturing(), P();
38
+ return;
39
+ }
40
+ let t = g;
41
+ if (g = !1, !f && !p) {
42
+ let t = Object.fromEntries(Object.entries(e).filter(([, e]) => e !== void 0));
43
+ h = {
44
+ ...h,
45
+ ...t
46
+ };
47
+ }
48
+ t && (f && (S(f), w(f)), P());
49
+ }
50
+ function E() {
51
+ return g ? null : {
52
+ apiKey: h.apiKey || l,
53
+ apiHost: h.apiHost || u,
54
+ uiHost: h.uiHost || d
55
+ };
56
+ }
57
+ function D() {
5
58
  return typeof window < "u" && typeof localStorage < "u";
6
59
  }
7
- async function u() {
8
- if (!l()) return null;
9
- if (c) return c;
60
+ async function O() {
61
+ if (!D()) return null;
62
+ if (f) return f;
10
63
  try {
11
64
  let { default: e } = await import("../node_modules/posthog-js/dist/module.js");
12
- return c = e, e;
65
+ return e;
13
66
  } catch {
14
67
  return null;
15
68
  }
16
69
  }
17
- function d() {
18
- return typeof process < "u" && process.env?.DO_NOT_TRACK === "1" || typeof navigator < "u" && (navigator.doNotTrack === "1" || typeof window < "u" && window.doNotTrack === "1");
19
- }
20
- async function f(t = !1) {
21
- if (s) return c;
22
- let n = await u();
23
- return n ? (n.init(i, {
24
- api_host: a,
25
- ui_host: o,
26
- opt_out_capturing_by_default: !t,
27
- capture_pageview: !1,
28
- autocapture: !1,
29
- persistence: "localStorage",
30
- disable_session_recording: !0,
31
- loaded: (t) => {
32
- t.register({
33
- package_name: e.name,
34
- package_version: e.version
35
- });
36
- }
37
- }), s = !0, n) : null;
70
+ function k() {
71
+ return !!(g || typeof process < "u" && process.env?.DO_NOT_TRACK === "1" || typeof navigator < "u" && (navigator.doNotTrack === "1" || typeof window < "u" && window.doNotTrack === "1"));
72
+ }
73
+ function A(e) {
74
+ f || (m = e);
75
+ }
76
+ async function j(e = !1) {
77
+ if (f) return f;
78
+ if (p) return p;
79
+ p = (async () => {
80
+ let t = E();
81
+ if (!t) return null;
82
+ let n = await O();
83
+ if (!n) return null;
84
+ let r = n.init(t.apiKey, {
85
+ api_host: t.apiHost,
86
+ ui_host: t.uiHost,
87
+ opt_out_capturing_by_default: !e,
88
+ capture_pageview: !1,
89
+ autocapture: !1,
90
+ persistence: "localStorage",
91
+ persistence_name: c,
92
+ consent_persistence_name: `${c}-consent`,
93
+ person_profiles: "identified_only",
94
+ disable_session_recording: !0,
95
+ bootstrap: m,
96
+ before_send: x
97
+ }, c);
98
+ return r ? (f = r, m = void 0, g ? f.opt_out_capturing() : M() === "granted" ? (f.opt_in_capturing(), w(f)) : e || f.opt_out_capturing(), f) : null;
99
+ })();
100
+ try {
101
+ return await p;
102
+ } finally {
103
+ f || (p = null);
104
+ }
38
105
  }
39
- function p() {
40
- if (!l()) return "pending";
41
- if (d()) return "denied";
106
+ function M() {
107
+ if (!D()) return "pending";
108
+ if (k()) return "denied";
42
109
  try {
43
- let e = localStorage.getItem(t);
110
+ let e = localStorage.getItem(r);
44
111
  if (e === "granted" || e === "denied") return e;
45
112
  } catch {}
46
113
  return "pending";
47
114
  }
48
- async function m(e) {
49
- if (l()) try {
50
- localStorage.setItem(t, e);
51
- let n = await f();
52
- if (!n) return;
53
- e === "granted" ? n.opt_in_capturing() : n.opt_out_capturing();
115
+ function N(e) {
116
+ if (!D()) return () => {};
117
+ let t = (t) => {
118
+ (t.key === r || t.key === i) && e();
119
+ };
120
+ return window.addEventListener(a, e), window.addEventListener("storage", t), () => {
121
+ window.removeEventListener(a, e), window.removeEventListener("storage", t);
122
+ };
123
+ }
124
+ function P() {
125
+ D() && window.dispatchEvent(new Event(a));
126
+ }
127
+ function F(e) {
128
+ if (D()) try {
129
+ localStorage.setItem(i, e);
130
+ } catch {}
131
+ }
132
+ function I(e) {
133
+ if (D()) try {
134
+ if (e !== void 0 && localStorage.getItem(i) !== e) return;
135
+ localStorage.removeItem(i), P();
54
136
  } catch {}
55
137
  }
56
- function h() {
57
- return p() === "granted";
138
+ async function L(e, { syncToCloud: t = !0 } = {}) {
139
+ if (D()) try {
140
+ if (localStorage.setItem(r, e), g) return;
141
+ let t = f ?? await j();
142
+ if (!t) return;
143
+ e === "granted" ? (t.opt_in_capturing(), w(t)) : t.get_property("$user_id") == null ? t.opt_out_capturing() : C(t);
144
+ } catch {} finally {
145
+ t && F(e), P();
146
+ }
147
+ }
148
+ function R() {
149
+ return M() === "granted";
58
150
  }
59
- function g() {
60
- if (!l()) return !1;
151
+ function z() {
152
+ if (!D()) return !1;
61
153
  try {
62
- return localStorage.getItem(n) === "true";
154
+ return localStorage.getItem(o) === "true";
63
155
  } catch {
64
156
  return !1;
65
157
  }
66
158
  }
67
- function _() {
68
- if (l()) try {
69
- localStorage.setItem(n, "true");
159
+ function B() {
160
+ if (D()) try {
161
+ localStorage.setItem(o, "true");
70
162
  } catch {}
71
163
  }
72
- async function v() {
73
- if (d() || g()) return;
74
- let e = await f(!0);
75
- e && ((e.has_opted_out_capturing?.() ?? !1) && e.opt_in_capturing(), e.capture("canvas_install", {
164
+ async function V() {
165
+ if (k() || z()) return;
166
+ let e = await j(!0);
167
+ !e || k() || ((e.has_opted_out_capturing?.() ?? !1) && e.opt_in_capturing(), e.capture("canvas_install", {
76
168
  platform: typeof navigator < "u" ? navigator.platform : "unknown",
77
169
  user_agent: typeof navigator < "u" ? navigator.userAgent : "unknown",
78
170
  referrer: typeof document < "u" ? document.referrer : "",
79
171
  url_origin: typeof window < "u" ? window.location.origin : "",
80
172
  embedded: typeof window < "u" && window.self !== window.top
81
- }), _(), p() !== "granted" && e.opt_out_capturing());
173
+ }), B(), M() !== "granted" && e.opt_out_capturing());
82
174
  }
83
- function y() {
84
- if (!l()) return !1;
175
+ function H() {
176
+ if (!D()) return !1;
85
177
  try {
86
- return sessionStorage.getItem(r) === "true";
178
+ return sessionStorage.getItem(s) === "true";
87
179
  } catch {
88
180
  return !1;
89
181
  }
90
182
  }
91
- function b() {
92
- if (l()) try {
93
- sessionStorage.setItem(r, "true");
183
+ function U() {
184
+ if (D()) try {
185
+ sessionStorage.setItem(s, "true");
94
186
  } catch {}
95
187
  }
96
- async function x() {
97
- if (!h() || y()) return;
98
- let e = await f();
99
- e && (e.capture("canvas_new_session", { is_first_use: !g() }), b());
188
+ async function W() {
189
+ if (!R()) return null;
190
+ let e = await j();
191
+ return !e || !R() ? null : (e.has_opted_out_capturing?.() && e.opt_in_capturing(), w(e), e);
100
192
  }
101
- async function S(e, t = {}) {
102
- if (!h()) return;
103
- let n = await f();
104
- n && n.capture(e, t);
193
+ async function G() {
194
+ if (H()) return;
195
+ let e = await W();
196
+ e && (e.capture("canvas_new_session", { is_first_use: !z() }), U());
105
197
  }
106
- async function C() {
107
- if (l()) try {
108
- localStorage.removeItem(t), localStorage.removeItem(n), sessionStorage.removeItem(r), s && c && c.reset();
109
- } catch {}
198
+ async function K(e, t = {}) {
199
+ let n = await W();
200
+ n && n.capture(e, t);
110
201
  }
111
- async function w() {
112
- return s ? c : null;
202
+ async function q(e, t = {}) {
203
+ let n = await W();
204
+ n && n.captureException(e, t);
205
+ }
206
+ async function J() {
207
+ if (D()) {
208
+ try {
209
+ localStorage.removeItem(r), localStorage.removeItem(o);
210
+ } catch {}
211
+ I();
212
+ try {
213
+ sessionStorage.removeItem(s);
214
+ } catch {}
215
+ _ = null, v += 1, y = -1;
216
+ try {
217
+ f && C(f, !0);
218
+ } catch {
219
+ try {
220
+ f?.opt_out_capturing();
221
+ } catch {}
222
+ }
223
+ }
113
224
  }
114
225
  //#endregion
115
- export { C as clearTelemetryData, w as getPostHogInstance, p as getTelemetryConsent, h as isTelemetryEnabled, m as setTelemetryConsent, S as trackEvent, v as trackInstall, x as trackSessionStart };
226
+ export { J as clearTelemetryData, A as configurePostHogBootstrap, T as configureTelemetry, M as getTelemetryConsent, j as initializePostHogClient, R as isTelemetryEnabled, L as setTelemetryConsent, N as subscribeTelemetryConsent, K as trackEvent, q as trackException, V as trackInstall, G as trackSessionStart };
116
227
 
117
228
  //# sourceMappingURL=telemetry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry.js","names":[],"sources":["../../src/services/telemetry.ts"],"sourcesContent":["/**\n * Telemetry service for tracking library usage.\n *\n * This module handles anonymous telemetry for the @openhands/agent-canvas package\n * using the PostHog SDK for reliable event delivery with batching, retry logic,\n * and offline support.\n *\n * TRACKING PHILOSOPHY:\n * - Install event (canvas_install): Sent immediately on first use, regardless of consent.\n * This is anonymous and contains no PII - just basic browser info and a random ID.\n * - Session/custom events: Only sent after user grants consent via the consent modal.\n * - Users can opt out of all future tracking by declining consent.\n *\n * AD BLOCKER BYPASS:\n * By default, telemetry is routed through OpenHands' reverse proxy (z.openhands.dev)\n * to avoid being blocked by ad blockers. Library consumers can override this with:\n * - VITE_POSTHOG_HOST: Custom proxy URL or direct PostHog URL\n * - VITE_POSTHOG_UI_HOST: PostHog UI host (defaults to https://us.posthog.com)\n *\n * IMPORTANT: By default, telemetry is sent to the OpenHands PostHog project.\n * Library consumers can override this by setting VITE_POSTHOG_API_KEY.\n *\n * Users can disable all telemetry (including install tracking) via:\n * - Setting VITE_DO_NOT_TRACK=1 environment variable\n * - Browser's Do Not Track setting\n */\n\nimport type { PostHog } from \"posthog-js\";\nimport packageJson from \"../../package.json\";\n\nconst TELEMETRY_CONSENT_KEY = \"openhands-telemetry-consent\";\nconst TELEMETRY_FIRST_USE_KEY = \"openhands-telemetry-first-use\";\nconst TELEMETRY_SESSION_KEY = \"openhands-telemetry-session\";\n\n// PostHog project keys — one per deployment environment, hardcoded so they\n// are baked into the static bundle at build time and cannot drift at runtime.\n// Replace POSTHOG_STAGING_KEY with a dedicated project key once provisioned.\nconst POSTHOG_PROD_KEY = \"phc_BgzfxKdgsYMLFTmJqt424ZoyVHvKFfrwttLimzdYTKFK\";\nconst POSTHOG_STAGING_KEY = \"phc_kBtz5nKmxVRRQ7HtPwr2QX9eMC5j65zE86QKocVNwb4U\";\n\n// Always use the staging key unless VITE_APP_ENV is explicitly set to\n// \"production\" at bundle time (hardcoded in build:lib and production CI).\n// Library consumers can always override with VITE_POSTHOG_API_KEY.\nconst POSTHOG_API_KEY: string =\n (import.meta.env.VITE_POSTHOG_API_KEY as string | undefined) ||\n (import.meta.env.VITE_APP_ENV === \"production\"\n ? POSTHOG_PROD_KEY\n : POSTHOG_STAGING_KEY);\n\n// Default to OpenHands' reverse proxy to bypass ad blockers.\n// The proxy at z.openhands.dev routes to PostHog's US region.\n// Library consumers can override this with their own proxy or direct PostHog URL.\nconst POSTHOG_HOST =\n import.meta.env.VITE_POSTHOG_HOST || \"https://z.openhands.dev\";\n\n// UI host is needed for PostHog features like toolbar to work correctly\n// when using a reverse proxy. Defaults to US region.\nconst POSTHOG_UI_HOST =\n import.meta.env.VITE_POSTHOG_UI_HOST || \"https://us.posthog.com\";\n\nexport type TelemetryConsent = \"granted\" | \"denied\" | \"pending\";\n\nlet isInitialized = false;\nlet posthogInstance: PostHog | null = null;\n\n/**\n * Check if we're in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof localStorage !== \"undefined\";\n}\n\n/**\n * Lazily load PostHog to avoid SSR/Node.js issues.\n * PostHog is a browser-only library, so we dynamically import it only when needed.\n */\nasync function getPostHog(): Promise<PostHog | null> {\n if (!isBrowser()) {\n return null;\n }\n\n if (posthogInstance) {\n return posthogInstance;\n }\n\n try {\n const { default: posthog } = await import(\"posthog-js\");\n posthogInstance = posthog;\n return posthog;\n } catch {\n // Failed to load PostHog - telemetry will be disabled\n return null;\n }\n}\n\n/**\n * Check if telemetry is disabled via environment variable or browser setting.\n * Works in both Node.js and browser (Vite) environments.\n */\nfunction isDoNotTrackEnabled(): boolean {\n // Check Vite environment variable (browser)\n if (\n typeof import.meta !== \"undefined\" &&\n import.meta.env?.VITE_DO_NOT_TRACK === \"1\"\n ) {\n return true;\n }\n\n // Check Node.js environment variable (SSR/testing)\n if (typeof process !== \"undefined\" && process.env?.DO_NOT_TRACK === \"1\") {\n return true;\n }\n\n // Check browser's navigator.doNotTrack standard\n if (\n typeof navigator !== \"undefined\" &&\n (navigator.doNotTrack === \"1\" ||\n // @ts-expect-error - Some browsers use window.doNotTrack\n (typeof window !== \"undefined\" && window.doNotTrack === \"1\"))\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Initialize PostHog SDK.\n *\n * @param enableCapturing - If true, enable capturing immediately (for install tracking).\n * If false, start with capturing disabled (for consent-gated tracking).\n */\nasync function initializePostHog(\n enableCapturing = false,\n): Promise<PostHog | null> {\n if (isInitialized) {\n return posthogInstance;\n }\n\n const posthog = await getPostHog();\n if (!posthog) {\n return null;\n }\n\n posthog.init(POSTHOG_API_KEY, {\n api_host: POSTHOG_HOST,\n // UI host is required when using a reverse proxy so PostHog features work correctly\n ui_host: POSTHOG_UI_HOST,\n // Start with capturing disabled by default - we enable it explicitly when needed\n opt_out_capturing_by_default: !enableCapturing,\n // Don't auto-capture page views - we control when to track\n capture_pageview: false,\n // Don't auto-capture clicks etc.\n autocapture: false,\n // Use localStorage for persistence\n persistence: \"localStorage\",\n // Disable session recording\n disable_session_recording: true,\n // Set default properties for all events\n loaded: (ph) => {\n ph.register({\n package_name: packageJson.name,\n package_version: packageJson.version,\n });\n },\n });\n\n isInitialized = true;\n return posthog;\n}\n\n/**\n * Get user's telemetry consent preference\n */\nexport function getTelemetryConsent(): TelemetryConsent {\n if (!isBrowser()) {\n return \"pending\";\n }\n\n // Check environment variable for opt-out\n if (isDoNotTrackEnabled()) {\n return \"denied\";\n }\n\n try {\n const consent = localStorage.getItem(TELEMETRY_CONSENT_KEY);\n if (consent === \"granted\" || consent === \"denied\") {\n return consent;\n }\n } catch {\n // Ignore storage errors\n }\n\n return \"pending\";\n}\n\n/**\n * Set user's telemetry consent preference\n */\nexport async function setTelemetryConsent(\n consent: \"granted\" | \"denied\",\n): Promise<void> {\n if (!isBrowser()) {\n return;\n }\n\n try {\n localStorage.setItem(TELEMETRY_CONSENT_KEY, consent);\n\n // Initialize PostHog if not already done\n const posthog = await initializePostHog();\n if (!posthog) {\n return;\n }\n\n if (consent === \"granted\") {\n // Enable capturing\n posthog.opt_in_capturing();\n } else {\n // Disable capturing and clear any queued events\n posthog.opt_out_capturing();\n }\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Check if telemetry is enabled (user has granted consent)\n */\nexport function isTelemetryEnabled(): boolean {\n return getTelemetryConsent() === \"granted\";\n}\n\n/**\n * Check if first use event has already been sent\n */\nfunction hasFirstUseSent(): boolean {\n if (!isBrowser()) {\n return false;\n }\n\n try {\n return localStorage.getItem(TELEMETRY_FIRST_USE_KEY) === \"true\";\n } catch {\n return false;\n }\n}\n\n/**\n * Mark first use event as sent\n */\nfunction markFirstUseSent(): void {\n if (!isBrowser()) {\n return;\n }\n\n try {\n localStorage.setItem(TELEMETRY_FIRST_USE_KEY, \"true\");\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Track the initial install of the library.\n *\n * IMPORTANT: This is sent immediately on first use, regardless of consent status.\n * This allows us to track library adoption even if users haven't made a consent choice yet.\n *\n * The event is:\n * - Completely anonymous (no PII, just a random PostHog distinct_id)\n * - Sent only once per installation (tracked via localStorage, persists across sessions)\n * - Still respects DO_NOT_TRACK environment variable and browser setting\n *\n * Users who want complete privacy can:\n * - Set VITE_DO_NOT_TRACK=1 or browser's Do Not Track\n * - Later deny consent to prevent all future tracking\n */\nexport async function trackInstall(): Promise<void> {\n // Respect hard opt-out via environment variable or browser setting\n if (isDoNotTrackEnabled()) {\n return;\n }\n\n // Already sent install event (persisted in localStorage - survives app relaunches)\n if (hasFirstUseSent()) {\n return;\n }\n\n // Initialize PostHog with capturing enabled (for this one event)\n const posthog = await initializePostHog(true);\n if (!posthog) {\n return;\n }\n\n // Temporarily enable capturing if it was disabled\n const wasOptedOut = posthog.has_opted_out_capturing?.() ?? false;\n if (wasOptedOut) {\n posthog.opt_in_capturing();\n }\n\n // Capture the install event\n posthog.capture(\"canvas_install\", {\n platform: typeof navigator !== \"undefined\" ? navigator.platform : \"unknown\",\n user_agent:\n typeof navigator !== \"undefined\" ? navigator.userAgent : \"unknown\",\n referrer: typeof document !== \"undefined\" ? document.referrer : \"\",\n url_origin: typeof window !== \"undefined\" ? window.location.origin : \"\",\n embedded: typeof window !== \"undefined\" && window.self !== window.top,\n });\n\n // Mark as sent (stored in localStorage - persists across browser sessions)\n markFirstUseSent();\n\n // Restore opt-out state if user hasn't granted consent yet\n // This ensures we only send the install event, not subsequent events\n const currentConsent = getTelemetryConsent();\n if (currentConsent !== \"granted\") {\n posthog.opt_out_capturing();\n }\n}\n\n/**\n * Check if session start event has already been sent (this browser session)\n */\nfunction hasSessionSent(): boolean {\n if (!isBrowser()) {\n return false;\n }\n\n try {\n return sessionStorage.getItem(TELEMETRY_SESSION_KEY) === \"true\";\n } catch {\n return false;\n }\n}\n\n/**\n * Mark session start event as sent (uses sessionStorage so it resets on new tabs/sessions)\n */\nfunction markSessionSent(): void {\n if (!isBrowser()) {\n return;\n }\n\n try {\n sessionStorage.setItem(TELEMETRY_SESSION_KEY, \"true\");\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Track a session start event.\n * Called each time a new browser session starts (respects consent).\n * Uses sessionStorage for deduplication - only sends once per browser session.\n */\nexport async function trackSessionStart(): Promise<void> {\n if (!isTelemetryEnabled()) {\n return;\n }\n\n // Already sent session event this browser session\n if (hasSessionSent()) {\n return;\n }\n\n // Initialize PostHog if needed\n const posthog = await initializePostHog();\n if (!posthog) {\n return;\n }\n\n posthog.capture(\"canvas_new_session\", {\n is_first_use: !hasFirstUseSent(),\n });\n\n // Mark as sent for this session\n markSessionSent();\n}\n\n/**\n * Track a custom event (respects consent).\n */\nexport async function trackEvent(\n eventName: string,\n properties: Record<string, unknown> = {},\n): Promise<void> {\n if (!isTelemetryEnabled()) {\n return;\n }\n\n // Initialize PostHog if needed\n const posthog = await initializePostHog();\n if (!posthog) {\n return;\n }\n\n posthog.capture(eventName, properties);\n}\n\n/**\n * Clear all telemetry data (for privacy/GDPR requests)\n */\nexport async function clearTelemetryData(): Promise<void> {\n if (!isBrowser()) {\n return;\n }\n\n try {\n localStorage.removeItem(TELEMETRY_CONSENT_KEY);\n localStorage.removeItem(TELEMETRY_FIRST_USE_KEY);\n sessionStorage.removeItem(TELEMETRY_SESSION_KEY);\n\n // Reset PostHog if initialized\n if (isInitialized && posthogInstance) {\n posthogInstance.reset();\n }\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Get the PostHog instance for advanced usage (if needed).\n * Returns the instance if initialized, otherwise null.\n * Note: This is async because PostHog is lazily loaded.\n */\nexport async function getPostHogInstance(): Promise<PostHog | null> {\n if (!isInitialized) {\n return null;\n }\n return posthogInstance;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"telemetry.js","names":[],"sources":["../../src/services/telemetry.ts"],"sourcesContent":["/**\n * Telemetry service for tracking library usage.\n *\n * This module handles anonymous telemetry for the @openhands/agent-canvas package\n * using the PostHog SDK for reliable event delivery with batching, retry logic,\n * and offline support.\n *\n * TRACKING PHILOSOPHY:\n * - Install event (canvas_install): Sent immediately on first use, regardless of consent.\n * This is anonymous and contains no PII - just basic browser info and a random ID.\n * - Session/custom events: Only sent after user grants consent via the consent modal.\n * - Users can opt out of all future tracking by declining consent.\n *\n * AD BLOCKER BYPASS:\n * By default, telemetry is routed through OpenHands' reverse proxy (z.openhands.dev)\n * to avoid being blocked by ad blockers. Library consumers can override this with:\n * - VITE_POSTHOG_HOST: Custom proxy URL or direct PostHog URL\n * - VITE_POSTHOG_UI_HOST: PostHog UI host (defaults to https://us.posthog.com)\n *\n * IMPORTANT: By default, telemetry is sent to the OpenHands PostHog project.\n * Source builds can override this with VITE_POSTHOG_API_KEY. Precompiled\n * library consumers can pass the same settings to configureTelemetry().\n *\n * Users can disable all telemetry (including install tracking) via:\n * - Setting VITE_DO_NOT_TRACK=1 environment variable\n * - Browser's Do Not Track setting\n */\n\nimport type { BootstrapConfig, CaptureResult, PostHog } from \"posthog-js\";\nimport packageJson from \"../../package.json\";\nimport {\n AGENT_CANVAS_CLIENT_SOURCE,\n AGENT_CANVAS_CLIENT_VERSION,\n} from \"#/api/client-source\";\n\nconst TELEMETRY_CONSENT_KEY = \"openhands-telemetry-consent\";\nconst TELEMETRY_CONSENT_PENDING_CLOUD_SYNC_KEY =\n \"openhands-telemetry-consent-pending-cloud-sync\";\nconst TELEMETRY_CONSENT_CHANGE_EVENT = \"openhands-telemetry-consent-change\";\nconst TELEMETRY_FIRST_USE_KEY = \"openhands-telemetry-first-use\";\nconst TELEMETRY_SESSION_KEY = \"openhands-telemetry-session\";\nconst POSTHOG_INSTANCE_NAME = \"agent-canvas\";\n\n// Unconfigured source builds use staging. Production release workflows pass\n// VITE_POSTHOG_API_KEY explicitly for both the app and library artifacts.\nconst POSTHOG_STAGING_KEY = \"phc_kBtz5nKmxVRRQ7HtPwr2QX9eMC5j65zE86QKocVNwb4U\";\nconst DEFAULT_POSTHOG_API_KEY: string =\n (import.meta.env.VITE_POSTHOG_API_KEY as string | undefined) ||\n POSTHOG_STAGING_KEY;\n\n// Default to OpenHands' reverse proxy to bypass ad blockers.\n// The proxy at z.openhands.dev routes to PostHog's US region.\n// Library consumers can override this with their own proxy or direct PostHog URL.\nconst DEFAULT_POSTHOG_HOST =\n import.meta.env.VITE_POSTHOG_HOST || \"https://z.openhands.dev\";\n\n// UI host is needed for PostHog features like toolbar to work correctly\n// when using a reverse proxy. Defaults to US region.\nconst DEFAULT_POSTHOG_UI_HOST =\n import.meta.env.VITE_POSTHOG_UI_HOST || \"https://us.posthog.com\";\n\nexport interface TelemetryConfig {\n /** PostHog project key. Useful for precompiled library consumers. */\n apiKey?: string;\n /** Event ingestion host or reverse proxy. */\n apiHost?: string;\n /** PostHog UI host used by toolbar links and other UI features. */\n uiHost?: string;\n}\n\nexport type TelemetryConfiguration = TelemetryConfig | false;\n\nexport type TelemetryConsent = \"granted\" | \"denied\" | \"pending\";\nexport type ResolvedTelemetryConsent = Exclude<TelemetryConsent, \"pending\">;\n\nexport interface SetTelemetryConsentOptions {\n /** Do not persist a value mirrored from backend settings back to Cloud. */\n syncToCloud?: boolean;\n}\n\nlet posthogInstance: PostHog | null = null;\nlet initializationPromise: Promise<PostHog | null> | null = null;\nlet pendingBootstrap: BootstrapConfig | undefined;\nlet telemetryConfig: TelemetryConfig = {};\nlet telemetryDisabled = false;\n\ninterface TelemetryIdentity {\n distinctId: string;\n properties: Record<string, unknown>;\n}\n\n// undefined means that Cloud identity has not resolved yet; null means that it\n// resolved without a user. This distinction prevents startup from resetting a\n// persisted identity while the current account is still loading.\nlet desiredTelemetryIdentity: TelemetryIdentity | null | undefined;\nlet desiredIdentityRevision = 0;\nlet appliedIdentityRevision = -1;\n\nconst CANVAS_EVENT_PROPERTIES = Object.freeze({\n client_source: AGENT_CANVAS_CLIENT_SOURCE,\n client_version: AGENT_CANVAS_CLIENT_VERSION,\n package_name: packageJson.name,\n package_version: packageJson.version,\n});\n\nfunction addCanvasEventProperties(\n event: CaptureResult | null,\n): CaptureResult | null {\n if (!event) return null;\n\n return {\n ...event,\n properties: {\n ...event.properties,\n ...CANVAS_EVENT_PROPERTIES,\n },\n };\n}\n\nfunction restorePostHogConsent(posthog: PostHog): void {\n if (telemetryDisabled || getTelemetryConsent() !== \"granted\") {\n posthog.opt_out_capturing();\n } else {\n posthog.opt_in_capturing();\n }\n}\n\nfunction resetPostHogIdentity(posthog: PostHog, resetDeviceId = false): void {\n posthog.reset(resetDeviceId);\n appliedIdentityRevision = -1;\n // PostHog reset clears its own consent persistence, so immediately restore\n // the canonical Canvas decision kept in localStorage.\n restorePostHogConsent(posthog);\n}\n\nfunction applyDesiredTelemetryIdentity(posthog: PostHog): void {\n if (desiredTelemetryIdentity === undefined || !isTelemetryEnabled()) return;\n\n const desiredId = desiredTelemetryIdentity?.distinctId;\n const currentId = posthog.get_property(\"$user_id\");\n if (currentId != null && currentId !== desiredId) {\n resetPostHogIdentity(posthog);\n }\n\n if (desiredTelemetryIdentity === null) {\n appliedIdentityRevision = desiredIdentityRevision;\n return;\n }\n\n if (\n posthog.get_property(\"$user_id\") !== desiredTelemetryIdentity.distinctId ||\n appliedIdentityRevision !== desiredIdentityRevision\n ) {\n posthog.identify(\n desiredTelemetryIdentity.distinctId,\n desiredTelemetryIdentity.properties,\n );\n appliedIdentityRevision = desiredIdentityRevision;\n }\n}\n\nfunction propertiesEqual(\n left: Record<string, unknown>,\n right: Record<string, unknown>,\n): boolean {\n const keys = Object.keys(left);\n return (\n keys.length === Object.keys(right).length &&\n keys.every((key) => left[key] === right[key])\n );\n}\n\n/**\n * Configure the single Canvas telemetry client before its first use.\n * Passing false disables telemetry and install tracking for embedded hosts.\n */\nexport function configureTelemetry(config: TelemetryConfiguration): void {\n if (config === false) {\n if (telemetryDisabled) return;\n telemetryDisabled = true;\n posthogInstance?.opt_out_capturing();\n notifyTelemetryConsentListeners();\n return;\n }\n\n const wasDisabled = telemetryDisabled;\n telemetryDisabled = false;\n\n if (!posthogInstance && !initializationPromise) {\n const definedConfig = Object.fromEntries(\n Object.entries(config).filter(([, value]) => value !== undefined),\n ) as TelemetryConfig;\n telemetryConfig = { ...telemetryConfig, ...definedConfig };\n }\n\n if (wasDisabled) {\n if (posthogInstance) {\n restorePostHogConsent(posthogInstance);\n applyDesiredTelemetryIdentity(posthogInstance);\n }\n notifyTelemetryConsentListeners();\n }\n}\n\nfunction getResolvedTelemetryConfig(): Required<TelemetryConfig> | null {\n if (telemetryDisabled) return null;\n\n return {\n apiKey: telemetryConfig.apiKey || DEFAULT_POSTHOG_API_KEY,\n apiHost: telemetryConfig.apiHost || DEFAULT_POSTHOG_HOST,\n uiHost: telemetryConfig.uiHost || DEFAULT_POSTHOG_UI_HOST,\n };\n}\n\n/**\n * Check if we're in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof localStorage !== \"undefined\";\n}\n\n/**\n * Lazily load PostHog to avoid SSR/Node.js issues.\n * PostHog is a browser-only library, so we dynamically import it only when needed.\n */\nasync function getPostHog(): Promise<PostHog | null> {\n if (!isBrowser()) {\n return null;\n }\n\n if (posthogInstance) {\n return posthogInstance;\n }\n\n try {\n const { default: posthog } = await import(\"posthog-js\");\n return posthog;\n } catch {\n // Failed to load PostHog - telemetry will be disabled\n return null;\n }\n}\n\n/**\n * Check if telemetry is disabled via environment variable or browser setting.\n * Works in both Node.js and browser (Vite) environments.\n */\nfunction isDoNotTrackEnabled(): boolean {\n if (telemetryDisabled) {\n return true;\n }\n\n // Check Vite environment variable (browser)\n if (\n typeof import.meta !== \"undefined\" &&\n import.meta.env?.VITE_DO_NOT_TRACK === \"1\"\n ) {\n return true;\n }\n\n // Check Node.js environment variable (SSR/testing)\n if (typeof process !== \"undefined\" && process.env?.DO_NOT_TRACK === \"1\") {\n return true;\n }\n\n // Check browser's navigator.doNotTrack standard\n if (\n typeof navigator !== \"undefined\" &&\n (navigator.doNotTrack === \"1\" ||\n // @ts-expect-error - Some browsers use window.doNotTrack\n (typeof window !== \"undefined\" && window.doNotTrack === \"1\"))\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Initialize PostHog SDK.\n *\n * @param enableCapturing - If true, enable capturing immediately (for install tracking).\n * If false, start with capturing disabled (for consent-gated tracking).\n */\nexport function configurePostHogBootstrap(\n bootstrap: BootstrapConfig | undefined,\n): void {\n if (!posthogInstance) {\n pendingBootstrap = bootstrap;\n }\n}\n\nexport async function initializePostHogClient(\n enableCapturing = false,\n): Promise<PostHog | null> {\n if (posthogInstance) {\n return posthogInstance;\n }\n\n if (initializationPromise) {\n return initializationPromise;\n }\n\n initializationPromise = (async () => {\n const config = getResolvedTelemetryConfig();\n if (!config) {\n return null;\n }\n\n const posthog = await getPostHog();\n if (!posthog) {\n return null;\n }\n\n // A named instance isolates Canvas configuration, consent, identity, and\n // persistence from a host application's default PostHog singleton.\n const initializedPostHog = posthog.init(\n config.apiKey,\n {\n api_host: config.apiHost,\n ui_host: config.uiHost,\n opt_out_capturing_by_default: !enableCapturing,\n capture_pageview: false,\n autocapture: false,\n persistence: \"localStorage\",\n persistence_name: POSTHOG_INSTANCE_NAME,\n consent_persistence_name: `${POSTHOG_INSTANCE_NAME}-consent`,\n person_profiles: \"identified_only\",\n disable_session_recording: true,\n bootstrap: pendingBootstrap,\n before_send: addCanvasEventProperties,\n },\n POSTHOG_INSTANCE_NAME,\n );\n if (!initializedPostHog) return null;\n\n posthogInstance = initializedPostHog;\n pendingBootstrap = undefined;\n\n if (telemetryDisabled) {\n posthogInstance.opt_out_capturing();\n } else if (getTelemetryConsent() === \"granted\") {\n posthogInstance.opt_in_capturing();\n applyDesiredTelemetryIdentity(posthogInstance);\n } else if (!enableCapturing) {\n posthogInstance.opt_out_capturing();\n }\n\n return posthogInstance;\n })();\n\n try {\n return await initializationPromise;\n } finally {\n if (!posthogInstance) {\n initializationPromise = null;\n }\n }\n}\n\n/**\n * Get user's telemetry consent preference\n */\nexport function getTelemetryConsent(): TelemetryConsent {\n if (!isBrowser()) {\n return \"pending\";\n }\n\n // Check environment variable for opt-out\n if (isDoNotTrackEnabled()) {\n return \"denied\";\n }\n\n try {\n const consent = localStorage.getItem(TELEMETRY_CONSENT_KEY);\n if (consent === \"granted\" || consent === \"denied\") {\n return consent;\n }\n } catch {\n // Ignore storage errors\n }\n\n return \"pending\";\n}\n\n/**\n * Return an explicit browser choice that still needs to survive a Cloud login.\n * It remains pending across local backends so their settings cannot consume a\n * decision that must still be applied after the user connects to Cloud.\n */\nexport function getPendingCloudTelemetryConsent(): ResolvedTelemetryConsent | null {\n if (!isBrowser()) return null;\n\n try {\n const consent = localStorage.getItem(\n TELEMETRY_CONSENT_PENDING_CLOUD_SYNC_KEY,\n );\n return consent === \"granted\" || consent === \"denied\" ? consent : null;\n } catch {\n return null;\n }\n}\n\nexport function subscribeTelemetryConsent(listener: () => void): () => void {\n if (!isBrowser()) return () => {};\n const handleStorage = (event: StorageEvent) => {\n if (\n event.key === TELEMETRY_CONSENT_KEY ||\n event.key === TELEMETRY_CONSENT_PENDING_CLOUD_SYNC_KEY\n ) {\n listener();\n }\n };\n window.addEventListener(TELEMETRY_CONSENT_CHANGE_EVENT, listener);\n window.addEventListener(\"storage\", handleStorage);\n\n return () => {\n window.removeEventListener(TELEMETRY_CONSENT_CHANGE_EVENT, listener);\n window.removeEventListener(\"storage\", handleStorage);\n };\n}\n\nfunction notifyTelemetryConsentListeners(): void {\n if (isBrowser())\n window.dispatchEvent(new Event(TELEMETRY_CONSENT_CHANGE_EVENT));\n}\n\nfunction markTelemetryConsentForCloudSync(\n consent: ResolvedTelemetryConsent,\n): void {\n if (!isBrowser()) return;\n\n try {\n localStorage.setItem(TELEMETRY_CONSENT_PENDING_CLOUD_SYNC_KEY, consent);\n } catch {\n // Ignore storage errors; the in-browser consent decision still applies.\n }\n}\n\nexport function clearPendingCloudTelemetryConsent(\n expected?: ResolvedTelemetryConsent,\n): void {\n if (!isBrowser()) return;\n\n try {\n if (\n expected !== undefined &&\n localStorage.getItem(TELEMETRY_CONSENT_PENDING_CLOUD_SYNC_KEY) !==\n expected\n ) {\n return;\n }\n localStorage.removeItem(TELEMETRY_CONSENT_PENDING_CLOUD_SYNC_KEY);\n notifyTelemetryConsentListeners();\n } catch {\n // Ignore storage errors.\n }\n}\n\n/**\n * Set user's telemetry consent preference\n */\nexport async function setTelemetryConsent(\n consent: ResolvedTelemetryConsent,\n { syncToCloud = true }: SetTelemetryConsentOptions = {},\n): Promise<void> {\n if (!isBrowser()) {\n return;\n }\n\n try {\n localStorage.setItem(TELEMETRY_CONSENT_KEY, consent);\n if (telemetryDisabled) return;\n\n // Reuse an initialized client synchronously so a same-flush identify()\n // cannot run before consent is applied. Only the cold path awaits import.\n const posthog = posthogInstance ?? (await initializePostHogClient());\n if (!posthog) {\n return;\n }\n\n if (consent === \"granted\") {\n posthog.opt_in_capturing();\n applyDesiredTelemetryIdentity(posthog);\n } else {\n if (posthog.get_property(\"$user_id\") != null) {\n resetPostHogIdentity(posthog);\n } else {\n posthog.opt_out_capturing();\n }\n }\n } catch {\n // Ignore storage errors\n } finally {\n // Notify UI/backend/identity reconcilers only after the browser capture state\n // reflects this decision. Otherwise a pre-login grant can trigger an\n // identify while PostHog is still opted out and lose funnel continuity.\n if (syncToCloud) {\n markTelemetryConsentForCloudSync(consent);\n }\n notifyTelemetryConsentListeners();\n }\n}\n\n/**\n * Declare the current Cloud identity. The telemetry service applies it only\n * after consent and owns all reset/account-switch semantics.\n */\nexport async function setTelemetryIdentity(\n distinctId: string | null,\n properties: Record<string, unknown> = {},\n): Promise<void> {\n const nextIdentity = distinctId === null ? null : { distinctId, properties };\n const unchanged =\n desiredTelemetryIdentity === nextIdentity ||\n (desiredTelemetryIdentity !== undefined &&\n desiredTelemetryIdentity !== null &&\n nextIdentity !== null &&\n desiredTelemetryIdentity.distinctId === nextIdentity.distinctId &&\n propertiesEqual(desiredTelemetryIdentity.properties, properties));\n if (unchanged) return;\n\n desiredTelemetryIdentity = nextIdentity;\n desiredIdentityRevision += 1;\n appliedIdentityRevision = -1;\n\n if (!isTelemetryEnabled()) return;\n const posthog = posthogInstance ?? (await initializePostHogClient());\n if (posthog && isTelemetryEnabled()) {\n // Read the desired identity after the await so a newer account always wins\n // if identity changes while the SDK is loading.\n applyDesiredTelemetryIdentity(posthog);\n }\n}\n\n/**\n * Check if telemetry is enabled (user has granted consent)\n */\nexport function isTelemetryEnabled(): boolean {\n return getTelemetryConsent() === \"granted\";\n}\n\n/**\n * Check if first use event has already been sent\n */\nfunction hasFirstUseSent(): boolean {\n if (!isBrowser()) {\n return false;\n }\n\n try {\n return localStorage.getItem(TELEMETRY_FIRST_USE_KEY) === \"true\";\n } catch {\n return false;\n }\n}\n\n/**\n * Mark first use event as sent\n */\nfunction markFirstUseSent(): void {\n if (!isBrowser()) {\n return;\n }\n\n try {\n localStorage.setItem(TELEMETRY_FIRST_USE_KEY, \"true\");\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Track the initial install of the library.\n *\n * IMPORTANT: This is sent immediately on first use, regardless of consent status.\n * This allows us to track library adoption even if users haven't made a consent choice yet.\n *\n * The event is:\n * - Completely anonymous (no PII, just a random PostHog distinct_id)\n * - Sent only once per installation (tracked via localStorage, persists across sessions)\n * - Still respects DO_NOT_TRACK environment variable and browser setting\n *\n * Users who want complete privacy can:\n * - Set VITE_DO_NOT_TRACK=1 or browser's Do Not Track\n * - Later deny consent to prevent all future tracking\n */\nexport async function trackInstall(): Promise<void> {\n // Respect hard opt-out via environment variable or browser setting\n if (isDoNotTrackEnabled()) {\n return;\n }\n\n // Already sent install event (persisted in localStorage - survives app relaunches)\n if (hasFirstUseSent()) {\n return;\n }\n\n // Initialize PostHog with capturing enabled (for this one event)\n const posthog = await initializePostHogClient(true);\n if (!posthog || isDoNotTrackEnabled()) {\n return;\n }\n\n // Temporarily enable capturing if it was disabled\n const wasOptedOut = posthog.has_opted_out_capturing?.() ?? false;\n if (wasOptedOut) {\n posthog.opt_in_capturing();\n }\n\n // Capture the install event\n posthog.capture(\"canvas_install\", {\n platform: typeof navigator !== \"undefined\" ? navigator.platform : \"unknown\",\n user_agent:\n typeof navigator !== \"undefined\" ? navigator.userAgent : \"unknown\",\n referrer: typeof document !== \"undefined\" ? document.referrer : \"\",\n url_origin: typeof window !== \"undefined\" ? window.location.origin : \"\",\n embedded: typeof window !== \"undefined\" && window.self !== window.top,\n });\n\n // Mark as sent (stored in localStorage - persists across browser sessions)\n markFirstUseSent();\n\n // Restore opt-out state if user hasn't granted consent yet\n // This ensures we only send the install event, not subsequent events\n const currentConsent = getTelemetryConsent();\n if (currentConsent !== \"granted\") {\n posthog.opt_out_capturing();\n }\n}\n\n/**\n * Check if session start event has already been sent (this browser session)\n */\nfunction hasSessionSent(): boolean {\n if (!isBrowser()) {\n return false;\n }\n\n try {\n return sessionStorage.getItem(TELEMETRY_SESSION_KEY) === \"true\";\n } catch {\n return false;\n }\n}\n\n/**\n * Mark session start event as sent (uses sessionStorage so it resets on new tabs/sessions)\n */\nfunction markSessionSent(): void {\n if (!isBrowser()) {\n return;\n }\n\n try {\n sessionStorage.setItem(TELEMETRY_SESSION_KEY, \"true\");\n } catch {\n // Ignore storage errors\n }\n}\n\n/** Return the shared client only when a consented capture is safe to emit. */\nasync function getPostHogForConsentedCapture(): Promise<PostHog | null> {\n if (!isTelemetryEnabled()) return null;\n\n const posthog = await initializePostHogClient();\n if (!posthog || !isTelemetryEnabled()) return null;\n\n // The browser preference is the canonical capture decision. PostHog may\n // still carry an older opt-out marker while backend consent is loading or\n // after a previous backend temporarily reported a stale value. Heal that\n // drift at the event boundary so capture() cannot silently discard an event\n // that the user has explicitly allowed.\n if (posthog.has_opted_out_capturing?.()) {\n posthog.opt_in_capturing();\n }\n\n applyDesiredTelemetryIdentity(posthog);\n\n return posthog;\n}\n\n/**\n * Track a session start event.\n * Called each time a new browser session starts (respects consent).\n * Uses sessionStorage for deduplication - only sends once per browser session.\n */\nexport async function trackSessionStart(): Promise<void> {\n // Already sent session event this browser session\n if (hasSessionSent()) {\n return;\n }\n\n const posthog = await getPostHogForConsentedCapture();\n if (!posthog) return;\n\n posthog.capture(\"canvas_new_session\", {\n is_first_use: !hasFirstUseSent(),\n });\n\n // Mark as sent for this session\n markSessionSent();\n}\n\n/**\n * Track a custom event (respects consent).\n */\nexport async function trackEvent(\n eventName: string,\n properties: Record<string, unknown> = {},\n): Promise<void> {\n const posthog = await getPostHogForConsentedCapture();\n if (!posthog) return;\n\n posthog.capture(eventName, properties);\n}\n\n/** Track an exception through the same consent-aware client as custom events. */\nexport async function trackException(\n error: unknown,\n properties: Record<string, unknown> = {},\n): Promise<void> {\n const posthog = await getPostHogForConsentedCapture();\n if (!posthog) return;\n\n posthog.captureException(error, properties);\n}\n\n/**\n * Clear all telemetry data (for privacy/GDPR requests)\n */\nexport async function clearTelemetryData(): Promise<void> {\n if (!isBrowser()) {\n return;\n }\n\n try {\n localStorage.removeItem(TELEMETRY_CONSENT_KEY);\n localStorage.removeItem(TELEMETRY_FIRST_USE_KEY);\n } catch {\n // Continue clearing the in-memory and SDK identity if storage is blocked.\n }\n clearPendingCloudTelemetryConsent();\n try {\n sessionStorage.removeItem(TELEMETRY_SESSION_KEY);\n } catch {\n // Continue clearing the in-memory and SDK identity if storage is blocked.\n }\n\n desiredTelemetryIdentity = null;\n desiredIdentityRevision += 1;\n appliedIdentityRevision = -1;\n\n try {\n if (posthogInstance) {\n resetPostHogIdentity(posthogInstance, true);\n }\n } catch {\n // A reset failure must not leave capture enabled after a privacy clear.\n try {\n posthogInstance?.opt_out_capturing();\n } catch {\n // Telemetry failures must not break the application.\n }\n }\n}\n"],"mappings":";;;AAmCA,IAAM,IAAwB,+BACxB,IACJ,kDACI,IAAiC,sCACjC,IAA0B,iCAC1B,IAAwB,+BACxB,IAAwB,gBAKxB,IAAA,oDAOA,IACiC,2BAIjC,IACoC,0BAqBtC,IAAkC,MAClC,IAAwD,MACxD,GACA,IAAmC,EAAE,EACrC,IAAoB,IAUpB,GACA,IAA0B,GAC1B,IAA0B,IAExB,IAA0B,OAAO,OAAO;CAC5C,eAAe;CACf,gBAAgB;CAChB,cAAc,EAAY;CAC1B,iBAAiB,EAAY;CAC9B,CAAC;AAEF,SAAS,EACP,GACsB;AAGtB,QAFK,IAEE;EACL,GAAG;EACH,YAAY;GACV,GAAG,EAAM;GACT,GAAG;GACJ;EACF,GARkB;;AAWrB,SAAS,EAAsB,GAAwB;AACrD,CAAI,KAAqB,GAAqB,KAAK,YACjD,EAAQ,mBAAmB,GAE3B,EAAQ,kBAAkB;;AAI9B,SAAS,EAAqB,GAAkB,IAAgB,IAAa;AAK3E,CAJA,EAAQ,MAAM,EAAc,EAC5B,IAA0B,IAG1B,EAAsB,EAAQ;;AAGhC,SAAS,EAA8B,GAAwB;AAC7D,KAAI,MAA6B,KAAA,KAAa,CAAC,GAAoB,CAAE;CAErE,IAAM,IAAY,GAA0B,YACtC,IAAY,EAAQ,aAAa,WAAW;AAKlD,KAJI,KAAa,QAAQ,MAAc,KACrC,EAAqB,EAAQ,EAG3B,MAA6B,MAAM;AACrC,MAA0B;AAC1B;;AAGF,EACE,EAAQ,aAAa,WAAW,KAAK,EAAyB,cAC9D,MAA4B,OAE5B,EAAQ,SACN,EAAyB,YACzB,EAAyB,WAC1B,EACD,IAA0B;;AAmB9B,SAAgB,EAAmB,GAAsC;AACvE,KAAI,MAAW,IAAO;AACpB,MAAI,EAAmB;AAGvB,EAFA,IAAoB,IACpB,GAAiB,mBAAmB,EACpC,GAAiC;AACjC;;CAGF,IAAM,IAAc;AAGpB,KAFA,IAAoB,IAEhB,CAAC,KAAmB,CAAC,GAAuB;EAC9C,IAAM,IAAgB,OAAO,YAC3B,OAAO,QAAQ,EAAO,CAAC,QAAQ,GAAG,OAAW,MAAU,KAAA,EAAU,CAClE;AACD,MAAkB;GAAE,GAAG;GAAiB,GAAG;GAAe;;AAG5D,CAAI,MACE,MACF,EAAsB,EAAgB,EACtC,EAA8B,EAAgB,GAEhD,GAAiC;;AAIrC,SAAS,IAA+D;AAGtE,QAFI,IAA0B,OAEvB;EACL,QAAQ,EAAgB,UAAU;EAClC,SAAS,EAAgB,WAAW;EACpC,QAAQ,EAAgB,UAAU;EACnC;;AAMH,SAAS,IAAqB;AAC5B,QAAO,OAAO,SAAW,OAAe,OAAO,eAAiB;;AAOlE,eAAe,IAAsC;AACnD,KAAI,CAAC,GAAW,CACd,QAAO;AAGT,KAAI,EACF,QAAO;AAGT,KAAI;EACF,IAAM,EAAE,SAAS,MAAY,MAAM,OAAO;AAC1C,SAAO;SACD;AAEN,SAAO;;;AAQX,SAAS,IAA+B;AA4BtC,QATA,GAlBI,KAaA,OAAO,UAAY,OAAe,QAAQ,KAAK,iBAAiB,OAMlE,OAAO,YAAc,QACpB,UAAU,eAAe,OAEvB,OAAO,SAAW,OAAe,OAAO,eAAe;;AAc9D,SAAgB,EACd,GACM;AACN,CAAK,MACH,IAAmB;;AAIvB,eAAsB,EACpB,IAAkB,IACO;AACzB,KAAI,EACF,QAAO;AAGT,KAAI,EACF,QAAO;AAGT,MAAyB,YAAY;EACnC,IAAM,IAAS,GAA4B;AAC3C,MAAI,CAAC,EACH,QAAO;EAGT,IAAM,IAAU,MAAM,GAAY;AAClC,MAAI,CAAC,EACH,QAAO;EAKT,IAAM,IAAqB,EAAQ,KACjC,EAAO,QACP;GACE,UAAU,EAAO;GACjB,SAAS,EAAO;GAChB,8BAA8B,CAAC;GAC/B,kBAAkB;GAClB,aAAa;GACb,aAAa;GACb,kBAAkB;GAClB,0BAA0B,GAAG,EAAsB;GACnD,iBAAiB;GACjB,2BAA2B;GAC3B,WAAW;GACX,aAAa;GACd,EACD,EACD;AAeD,SAdK,KAEL,IAAkB,GAClB,IAAmB,KAAA,GAEf,IACF,EAAgB,mBAAmB,GAC1B,GAAqB,KAAK,aACnC,EAAgB,kBAAkB,EAClC,EAA8B,EAAgB,IACpC,KACV,EAAgB,mBAAmB,EAG9B,KAdyB;KAe9B;AAEJ,KAAI;AACF,SAAO,MAAM;WACL;AACR,EAAK,MACH,IAAwB;;;AAQ9B,SAAgB,IAAwC;AACtD,KAAI,CAAC,GAAW,CACd,QAAO;AAIT,KAAI,GAAqB,CACvB,QAAO;AAGT,KAAI;EACF,IAAM,IAAU,aAAa,QAAQ,EAAsB;AAC3D,MAAI,MAAY,aAAa,MAAY,SACvC,QAAO;SAEH;AAIR,QAAO;;AAqBT,SAAgB,EAA0B,GAAkC;AAC1E,KAAI,CAAC,GAAW,CAAE,cAAa;CAC/B,IAAM,KAAiB,MAAwB;AAC7C,GACE,EAAM,QAAQ,KACd,EAAM,QAAQ,MAEd,GAAU;;AAMd,QAHA,OAAO,iBAAiB,GAAgC,EAAS,EACjE,OAAO,iBAAiB,WAAW,EAAc,QAEpC;AAEX,EADA,OAAO,oBAAoB,GAAgC,EAAS,EACpE,OAAO,oBAAoB,WAAW,EAAc;;;AAIxD,SAAS,IAAwC;AAC/C,CAAI,GAAW,IACb,OAAO,cAAc,IAAI,MAAM,EAA+B,CAAC;;AAGnE,SAAS,EACP,GACM;AACD,QAAW,CAEhB,KAAI;AACF,eAAa,QAAQ,GAA0C,EAAQ;SACjE;;AAKV,SAAgB,EACd,GACM;AACD,QAAW,CAEhB,KAAI;AACF,MACE,MAAa,KAAA,KACb,aAAa,QAAQ,EAAyC,KAC5D,EAEF;AAGF,EADA,aAAa,WAAW,EAAyC,EACjE,GAAiC;SAC3B;;AAQV,eAAsB,EACpB,GACA,EAAE,iBAAc,OAAqC,EAAE,EACxC;AACV,QAAW,CAIhB,KAAI;AAEF,MADA,aAAa,QAAQ,GAAuB,EAAQ,EAChD,EAAmB;EAIvB,IAAM,IAAU,KAAoB,MAAM,GAAyB;AACnE,MAAI,CAAC,EACH;AAGF,EAAI,MAAY,aACd,EAAQ,kBAAkB,EAC1B,EAA8B,EAAQ,IAElC,EAAQ,aAAa,WAAW,IAAI,OAGtC,EAAQ,mBAAmB,GAF3B,EAAqB,EAAQ;SAK3B,WAEE;AAOR,EAHI,KACF,EAAiC,EAAQ,EAE3C,GAAiC;;;AAsCrC,SAAgB,IAA8B;AAC5C,QAAO,GAAqB,KAAK;;AAMnC,SAAS,IAA2B;AAClC,KAAI,CAAC,GAAW,CACd,QAAO;AAGT,KAAI;AACF,SAAO,aAAa,QAAQ,EAAwB,KAAK;SACnD;AACN,SAAO;;;AAOX,SAAS,IAAyB;AAC3B,QAAW,CAIhB,KAAI;AACF,eAAa,QAAQ,GAAyB,OAAO;SAC/C;;AAoBV,eAAsB,IAA8B;AAOlD,KALI,GAAqB,IAKrB,GAAiB,CACnB;CAIF,IAAM,IAAU,MAAM,EAAwB,GAAK;AAC/C,EAAC,KAAW,GAAqB,MAKjB,EAAQ,2BAA2B,IAAI,OAEzD,EAAQ,kBAAkB,EAI5B,EAAQ,QAAQ,kBAAkB;EAChC,UAAU,OAAO,YAAc,MAAc,UAAU,WAAW;EAClE,YACE,OAAO,YAAc,MAAc,UAAU,YAAY;EAC3D,UAAU,OAAO,WAAa,MAAc,SAAS,WAAW;EAChE,YAAY,OAAO,SAAW,MAAc,OAAO,SAAS,SAAS;EACrE,UAAU,OAAO,SAAW,OAAe,OAAO,SAAS,OAAO;EACnE,CAAC,EAGF,GAAkB,EAIK,GACnB,KAAmB,aACrB,EAAQ,mBAAmB;;AAO/B,SAAS,IAA0B;AACjC,KAAI,CAAC,GAAW,CACd,QAAO;AAGT,KAAI;AACF,SAAO,eAAe,QAAQ,EAAsB,KAAK;SACnD;AACN,SAAO;;;AAOX,SAAS,IAAwB;AAC1B,QAAW,CAIhB,KAAI;AACF,iBAAe,QAAQ,GAAuB,OAAO;SAC/C;;AAMV,eAAe,IAAyD;AACtE,KAAI,CAAC,GAAoB,CAAE,QAAO;CAElC,IAAM,IAAU,MAAM,GAAyB;AAc/C,QAbI,CAAC,KAAW,CAAC,GAAoB,GAAS,QAO1C,EAAQ,2BAA2B,IACrC,EAAQ,kBAAkB,EAG5B,EAA8B,EAAQ,EAE/B;;AAQT,eAAsB,IAAmC;AAEvD,KAAI,GAAgB,CAClB;CAGF,IAAM,IAAU,MAAM,GAA+B;AAChD,OAEL,EAAQ,QAAQ,sBAAsB,EACpC,cAAc,CAAC,GAAiB,EACjC,CAAC,EAGF,GAAiB;;AAMnB,eAAsB,EACpB,GACA,IAAsC,EAAE,EACzB;CACf,IAAM,IAAU,MAAM,GAA+B;AAChD,MAEL,EAAQ,QAAQ,GAAW,EAAW;;AAIxC,eAAsB,EACpB,GACA,IAAsC,EAAE,EACzB;CACf,IAAM,IAAU,MAAM,GAA+B;AAChD,MAEL,EAAQ,iBAAiB,GAAO,EAAW;;AAM7C,eAAsB,IAAoC;AACnD,QAAW,EAIhB;MAAI;AAEF,GADA,aAAa,WAAW,EAAsB,EAC9C,aAAa,WAAW,EAAwB;UAC1C;AAGR,KAAmC;AACnC,MAAI;AACF,kBAAe,WAAW,EAAsB;UAC1C;AAMR,EAFA,IAA2B,MAC3B,KAA2B,GAC3B,IAA0B;AAE1B,MAAI;AACF,GAAI,KACF,EAAqB,GAAiB,GAAK;UAEvC;AAEN,OAAI;AACF,OAAiB,mBAAmB;WAC9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"color-themes.cjs","names":[],"sources":["../../src/themes/color-themes.ts"],"sourcesContent":["export type ColorThemeKey =\n | \"openhands-deepsea\"\n | \"openhands-neutral\"\n | \"openhands-neo\";\n\nexport interface ColorThemeDefinition {\n label: string;\n /** Overrides for --cool-grey-* CSS custom properties (our semantic scale) */\n scale: Record<string, string>;\n /**\n * Overrides for --heroui-* CSS custom properties.\n * HeroUI stores colors as space-separated HSL channels (\"H S% L%\") so Tailwind\n * utilities like bg-default-200 resolve to hsl(var(--heroui-default-200)).\n * These vars are set by the heroui() plugin on :root, [data-theme=dark] at\n * build time, so they must be overridden at the same or lower specificity\n * from a later stylesheet to pick up theme changes at runtime.\n */\n heroui: Record<string, string>;\n /** Overrides for --oh-* semantic tokens such as brand / button colors. */\n tokens?: Record<string, string>;\n}\n\n// HSL channel strings for the neutral grey palette (H=0, S=0%, L=hex/255*100)\n// prettier-ignore\nconst NEUTRAL_HSL = {\n 50: \"0 0% 96.86%\", // #F7F7F7\n 100: \"0 0% 92.55%\", // #ECECEC\n 200: \"0 0% 86.27%\", // #DCDCDC\n 300: \"0 0% 74.51%\", // #BEBEBE\n 400: \"0 0% 59.22%\", // #979797\n 500: \"0 0% 45.1%\", // #737373\n 600: \"0 0% 33.73%\", // #565656\n 700: \"0 0% 25.1%\", // #404040\n 800: \"0 0% 19.22%\", // #313131\n 850: \"0 0% 15.69%\", // #282828\n 900: \"0 0% 12.55%\", // #202020\n 950: \"0 0% 9.41%\", // #181818\n 975: \"0 0% 6.27%\", // #101010\n};\n\nconst NEUTRAL_SCALE = {\n \"--cool-grey-50\": \"#F7F7F7\",\n \"--cool-grey-100\": \"#ECECEC\",\n \"--cool-grey-200\": \"#DCDCDC\",\n \"--cool-grey-300\": \"#BEBEBE\",\n \"--cool-grey-400\": \"#979797\",\n \"--cool-grey-500\": \"#737373\",\n \"--cool-grey-600\": \"#565656\",\n \"--cool-grey-700\": \"#404040\",\n \"--cool-grey-800\": \"#313131\",\n \"--cool-grey-900\": \"#282828\",\n \"--cool-grey-925\": \"#202020\",\n \"--cool-grey-950\": \"#181818\",\n \"--cool-grey-975\": \"#101010\",\n};\n\nconst NEUTRAL_HEROUI = {\n \"--heroui-background\": NEUTRAL_HSL[950],\n \"--heroui-background-foreground\": NEUTRAL_HSL[50],\n \"--heroui-foreground-50\": NEUTRAL_HSL[975],\n \"--heroui-foreground-100\": NEUTRAL_HSL[950],\n \"--heroui-foreground-200\": NEUTRAL_HSL[900],\n \"--heroui-foreground-300\": NEUTRAL_HSL[850],\n \"--heroui-foreground-400\": NEUTRAL_HSL[800],\n \"--heroui-foreground-500\": NEUTRAL_HSL[700],\n \"--heroui-foreground-600\": NEUTRAL_HSL[600],\n \"--heroui-foreground-700\": NEUTRAL_HSL[500],\n \"--heroui-foreground-800\": NEUTRAL_HSL[400],\n \"--heroui-foreground-900\": NEUTRAL_HSL[300],\n \"--heroui-foreground\": NEUTRAL_HSL[300],\n \"--heroui-content1\": NEUTRAL_HSL[900],\n \"--heroui-content1-foreground\": NEUTRAL_HSL[100],\n \"--heroui-content2\": NEUTRAL_HSL[850],\n \"--heroui-content2-foreground\": NEUTRAL_HSL[200],\n \"--heroui-content3\": NEUTRAL_HSL[800],\n \"--heroui-content3-foreground\": NEUTRAL_HSL[300],\n \"--heroui-content4\": NEUTRAL_HSL[700],\n \"--heroui-content4-foreground\": NEUTRAL_HSL[400],\n \"--heroui-default-50\": NEUTRAL_HSL[975],\n \"--heroui-default-100\": NEUTRAL_HSL[950],\n \"--heroui-default-200\": NEUTRAL_HSL[900],\n \"--heroui-default-300\": NEUTRAL_HSL[850],\n \"--heroui-default-400\": NEUTRAL_HSL[800],\n \"--heroui-default-500\": NEUTRAL_HSL[700],\n \"--heroui-default-600\": NEUTRAL_HSL[600],\n \"--heroui-default-700\": NEUTRAL_HSL[500],\n \"--heroui-default-800\": NEUTRAL_HSL[400],\n \"--heroui-default-900\": NEUTRAL_HSL[300],\n \"--heroui-default-foreground\": NEUTRAL_HSL[50],\n \"--heroui-default\": NEUTRAL_HSL[800],\n};\n\nimport { AGENT_SERVER_UI_THEMEABLE_BRAND_VARIABLES } from \"#/styles/agent-server-ui-style-scope\";\n\n/** CSS custom properties overridden by color themes (see applyColorTheme). */\nexport const COLOR_THEME_TOKEN_KEYS = AGENT_SERVER_UI_THEMEABLE_BRAND_VARIABLES;\n\n/** White primary/accent tokens — used by OpenHands-Neo for button surfaces. */\nconst NEO_WHITE_BUTTON_TOKENS: Record<\n (typeof COLOR_THEME_TOKEN_KEYS)[number],\n string\n> = {\n \"--oh-color-primary\": \"#ffffff\",\n \"--oh-accent\": \"#ffffff\",\n \"--oh-warning\": \"#ffffff\",\n};\n\nexport const COLOR_THEMES: Record<ColorThemeKey, ColorThemeDefinition> = {\n \"openhands-deepsea\": {\n label: \"OpenHands-DeepSea\",\n // Matches the values already set by index.css; included so switching back\n // from another theme restores the original palette explicitly.\n scale: {\n \"--cool-grey-50\": \"#F7F9FC\",\n \"--cool-grey-100\": \"#EEF2F7\",\n \"--cool-grey-200\": \"#DCE3EE\",\n \"--cool-grey-300\": \"#C3CDDC\",\n \"--cool-grey-400\": \"#A3B0C4\",\n \"--cool-grey-500\": \"#7E8A9E\",\n \"--cool-grey-600\": \"#626D82\",\n \"--cool-grey-700\": \"#4B5468\",\n \"--cool-grey-800\": \"#383F50\",\n \"--cool-grey-900\": \"#2C313F\",\n \"--cool-grey-925\": \"#21252F\",\n \"--cool-grey-950\": \"#0B0E14\",\n \"--cool-grey-975\": \"#05070A\",\n },\n // Values generated by heroui() from hero.ts — restore them explicitly when\n // switching back from another theme.\n heroui: {\n \"--heroui-background\": \"220 29.03% 6.08%\",\n \"--heroui-background-foreground\": \"216 45.45% 97.84%\",\n \"--heroui-foreground-50\": \"216 33.33% 2.94%\",\n \"--heroui-foreground-100\": \"220 29.03% 6.08%\",\n \"--heroui-foreground-200\": \"222.86 17.5% 15.69%\",\n \"--heroui-foreground-300\": \"224.21 17.76% 20.98%\",\n \"--heroui-foreground-400\": \"222.5 17.65% 26.67%\",\n \"--heroui-foreground-500\": \"221.38 16.2% 35.1%\",\n \"--heroui-foreground-600\": \"219.38 14.04% 44.71%\",\n \"--heroui-foreground-700\": \"217.5 14.16% 55.69%\",\n \"--heroui-foreground-800\": \"216.36 21.85% 70.39%\",\n \"--heroui-foreground-900\": \"216 26.32% 81.37%\",\n \"--heroui-foreground\": \"216 26.32% 81.37%\",\n \"--heroui-content1\": \"222.86 17.5% 15.69%\",\n \"--heroui-content1-foreground\": \"213.33 36% 95.1%\",\n \"--heroui-content2\": \"224.21 17.76% 20.98%\",\n \"--heroui-content2-foreground\": \"216.67 34.62% 89.8%\",\n \"--heroui-content3\": \"222.5 17.65% 26.67%\",\n \"--heroui-content3-foreground\": \"216 26.32% 81.37%\",\n \"--heroui-content4\": \"221.38 16.2% 35.1%\",\n \"--heroui-content4-foreground\": \"216.36 21.85% 70.39%\",\n \"--heroui-default-50\": \"216 33.33% 2.94%\",\n \"--heroui-default-100\": \"220 29.03% 6.08%\",\n \"--heroui-default-200\": \"222.86 17.5% 15.69%\",\n \"--heroui-default-300\": \"224.21 17.76% 20.98%\",\n \"--heroui-default-400\": \"222.5 17.65% 26.67%\",\n \"--heroui-default-500\": \"221.38 16.2% 35.1%\",\n \"--heroui-default-600\": \"219.38 14.04% 44.71%\",\n \"--heroui-default-700\": \"217.5 14.16% 55.69%\",\n \"--heroui-default-800\": \"216.36 21.85% 70.39%\",\n \"--heroui-default-900\": \"216 26.32% 81.37%\",\n \"--heroui-default-foreground\": \"216 45.45% 97.84%\",\n \"--heroui-default\": \"222.5 17.65% 26.67%\",\n },\n },\n\n \"openhands-neutral\": {\n label: \"OpenHands-Neutral\",\n scale: NEUTRAL_SCALE,\n // Each stop follows the same positional mapping as hero.ts:\n // heroui-default-100 ← cool-grey-950 position ← neutral-950 (#181818)\n // heroui-default-200 ← cool-grey-925 position ← neutral-900 (#202020)\n // ...etc.\n heroui: NEUTRAL_HEROUI,\n },\n\n \"openhands-neo\": {\n label: \"OpenHands-Neo\",\n scale: NEUTRAL_SCALE,\n heroui: NEUTRAL_HEROUI,\n tokens: NEO_WHITE_BUTTON_TOKENS,\n },\n};\n\nexport const DEFAULT_COLOR_THEME: ColorThemeKey = \"openhands-neutral\";\n\nexport const AVAILABLE_COLOR_THEMES = Object.entries(COLOR_THEMES).map(\n ([key, def]) => ({ key: key as ColorThemeKey, label: def.label }),\n);\n\nconst STORAGE_KEY = \"openhands-color-theme\";\n\n/** Read the persisted theme key from localStorage, falling back to the default. */\nexport function readPersistedColorTheme(): ColorThemeKey {\n if (typeof window === \"undefined\") return DEFAULT_COLOR_THEME;\n try {\n const stored = window.localStorage.getItem(STORAGE_KEY);\n if (stored && stored in COLOR_THEMES) return stored as ColorThemeKey;\n } catch {\n // ignore quota / privacy-mode failures\n }\n return DEFAULT_COLOR_THEME;\n}\n\n/** Persist the theme key to localStorage. */\nexport function persistColorTheme(key: ColorThemeKey): void {\n try {\n window.localStorage.setItem(STORAGE_KEY, key);\n } catch {\n // ignore\n }\n}\n\nconst THEME_STYLE_TAG_ID = \"oh-color-theme-override\";\n\n/**\n * Apply a theme by injecting (or replacing) a <style> tag that overrides\n * both our custom --cool-grey-* primitives and HeroUI's --heroui-* tokens.\n *\n * Why a <style> tag:\n * PostCSS transforms :root / body to [data-agent-server-ui], so --cool-grey-*\n * is set on EVERY element carrying that attribute. A body inline-style only\n * overrides body itself — inner matching elements keep the stylesheet value.\n *\n * Why heroui variables:\n * HeroUI stores colors as HSL channels in --heroui-* vars on [data-theme=dark].\n * They reference their own token system and are unaffected by --cool-grey-*\n * changes, so we override them from the same injected sheet.\n *\n * Why doubled selectors + re-append on every call:\n * \"Later sheet wins the tie\" cannot be relied on: in the built SPA\n * (ssr:false, prerendered shell) React 19 re-creates the <head> elements it\n * manages (<Meta/>/<Links/>) whenever the tree above the router remounts —\n * e.g. PostHogWrapper swapping in <PostHogProvider> once the analytics key\n * resolves, which only happens in builds with VITE_POSTHOG_CLIENT_KEY baked\n * (the published npm package / tagged Docker images). That re-inserts the\n * base stylesheet <link> AFTER this tag, which would let the base sheet's\n * unlayered [data-agent-server-ui] variable rules (0,1,0) win every tie.\n * Doubling the attribute selectors ([x][x], 0,2,0) beats them from any\n * position in <head>; re-appending on each apply keeps document order\n * favorable as well.\n */\nexport function applyColorTheme(key: ColorThemeKey): void {\n if (typeof document === \"undefined\") return;\n const { scale, heroui, tokens = {} } = COLOR_THEMES[key];\n\n const scaleDecls = Object.entries(scale)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n const herouiDecls = Object.entries(heroui)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n const tokenDecls = Object.entries(tokens)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n // Target both selectors for heroui vars:\n // [data-agent-server-ui] — covers document.body (portal destination) so\n // portalled popover/listbox content inherits the overridden values.\n // [data-theme=dark] — covers the inner AgentServerUIRoot wrapper so\n // components scoped inside the dark theme wrapper also pick them up.\n // Both are doubled to out-specify the base sheet regardless of stylesheet\n // order (see the doc comment above).\n const css = [\n `[data-agent-server-ui][data-agent-server-ui] {\\n${scaleDecls}\\n${herouiDecls}\\n${tokenDecls}\\n}`,\n `[data-theme=dark][data-theme=dark] {\\n${herouiDecls}\\n}`,\n ].join(\"\\n\");\n\n let styleEl = document.getElementById(\n THEME_STYLE_TAG_ID,\n ) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = document.createElement(\"style\");\n styleEl.id = THEME_STYLE_TAG_ID;\n }\n styleEl.textContent = css;\n // Re-append even when the tag already exists (appendChild relocates a\n // connected node) so the override also stays after any re-inserted <link>.\n document.head.appendChild(styleEl);\n\n syncColorThemeTokensOnScopeRoots(tokens);\n}\n\nfunction syncColorThemeTokensOnScopeRoots(\n tokens: Record<string, string>,\n): void {\n const roots = document.querySelectorAll(\"[data-agent-server-ui]\");\n for (const root of roots) {\n if (!(root instanceof HTMLElement)) continue;\n\n for (const key of COLOR_THEME_TOKEN_KEYS) {\n const value = tokens[key];\n if (value) {\n root.style.setProperty(key, value);\n } else {\n root.style.removeProperty(key);\n }\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"color-themes.cjs","names":[],"sources":["../../src/themes/color-themes.ts"],"sourcesContent":["export type ColorThemeKey =\n | \"openhands-deepsea\"\n | \"openhands-neutral\"\n | \"openhands-neo\";\n\nexport interface ColorThemeDefinition {\n label: string;\n /** Overrides for --cool-grey-* CSS custom properties (our semantic scale) */\n scale: Record<string, string>;\n /**\n * Overrides for --heroui-* CSS custom properties.\n * HeroUI stores colors as space-separated HSL channels (\"H S% L%\") so Tailwind\n * utilities like bg-default-200 resolve to hsl(var(--heroui-default-200)).\n * These vars are set by the heroui() plugin on :root, [data-theme=dark] at\n * build time, so they must be overridden at the same or lower specificity\n * from a later stylesheet to pick up theme changes at runtime.\n */\n heroui: Record<string, string>;\n /** Overrides for --oh-* semantic tokens such as brand / button colors. */\n tokens?: Record<string, string>;\n}\n\n// HSL channel strings for the neutral grey palette (H=0, S=0%, L=hex/255*100)\n// prettier-ignore\nconst NEUTRAL_HSL = {\n 50: \"0 0% 96.86%\", // #F7F7F7\n 100: \"0 0% 92.55%\", // #ECECEC\n 200: \"0 0% 86.27%\", // #DCDCDC\n 300: \"0 0% 74.51%\", // #BEBEBE\n 400: \"0 0% 59.22%\", // #979797\n 500: \"0 0% 45.1%\", // #737373\n 600: \"0 0% 33.73%\", // #565656\n 700: \"0 0% 25.1%\", // #404040\n 800: \"0 0% 19.22%\", // #313131\n 850: \"0 0% 15.69%\", // #282828\n 900: \"0 0% 12.55%\", // #202020\n 950: \"0 0% 9.41%\", // #181818\n 975: \"0 0% 6.27%\", // #101010\n};\n\nconst NEUTRAL_SCALE = {\n \"--cool-grey-50\": \"#F7F7F7\",\n \"--cool-grey-100\": \"#ECECEC\",\n \"--cool-grey-200\": \"#DCDCDC\",\n \"--cool-grey-300\": \"#BEBEBE\",\n \"--cool-grey-400\": \"#979797\",\n \"--cool-grey-500\": \"#737373\",\n \"--cool-grey-600\": \"#565656\",\n \"--cool-grey-700\": \"#404040\",\n \"--cool-grey-800\": \"#313131\",\n \"--cool-grey-900\": \"#282828\",\n \"--cool-grey-925\": \"#202020\",\n \"--cool-grey-950\": \"#181818\",\n \"--cool-grey-975\": \"#101010\",\n};\n\nconst NEUTRAL_HEROUI = {\n \"--heroui-background\": NEUTRAL_HSL[950],\n \"--heroui-background-foreground\": NEUTRAL_HSL[50],\n \"--heroui-foreground-50\": NEUTRAL_HSL[975],\n \"--heroui-foreground-100\": NEUTRAL_HSL[950],\n \"--heroui-foreground-200\": NEUTRAL_HSL[900],\n \"--heroui-foreground-300\": NEUTRAL_HSL[850],\n \"--heroui-foreground-400\": NEUTRAL_HSL[800],\n \"--heroui-foreground-500\": NEUTRAL_HSL[700],\n \"--heroui-foreground-600\": NEUTRAL_HSL[600],\n \"--heroui-foreground-700\": NEUTRAL_HSL[500],\n \"--heroui-foreground-800\": NEUTRAL_HSL[400],\n \"--heroui-foreground-900\": NEUTRAL_HSL[300],\n \"--heroui-foreground\": NEUTRAL_HSL[300],\n \"--heroui-content1\": NEUTRAL_HSL[900],\n \"--heroui-content1-foreground\": NEUTRAL_HSL[100],\n \"--heroui-content2\": NEUTRAL_HSL[850],\n \"--heroui-content2-foreground\": NEUTRAL_HSL[200],\n \"--heroui-content3\": NEUTRAL_HSL[800],\n \"--heroui-content3-foreground\": NEUTRAL_HSL[300],\n \"--heroui-content4\": NEUTRAL_HSL[700],\n \"--heroui-content4-foreground\": NEUTRAL_HSL[400],\n \"--heroui-default-50\": NEUTRAL_HSL[975],\n \"--heroui-default-100\": NEUTRAL_HSL[950],\n \"--heroui-default-200\": NEUTRAL_HSL[900],\n \"--heroui-default-300\": NEUTRAL_HSL[850],\n \"--heroui-default-400\": NEUTRAL_HSL[800],\n \"--heroui-default-500\": NEUTRAL_HSL[700],\n \"--heroui-default-600\": NEUTRAL_HSL[600],\n \"--heroui-default-700\": NEUTRAL_HSL[500],\n \"--heroui-default-800\": NEUTRAL_HSL[400],\n \"--heroui-default-900\": NEUTRAL_HSL[300],\n \"--heroui-default-foreground\": NEUTRAL_HSL[50],\n \"--heroui-default\": NEUTRAL_HSL[800],\n};\n\nimport { AGENT_SERVER_UI_THEMEABLE_BRAND_VARIABLES } from \"#/styles/agent-server-ui-style-scope\";\n\n/** CSS custom properties overridden by color themes (see applyColorTheme). */\nexport const COLOR_THEME_TOKEN_KEYS = AGENT_SERVER_UI_THEMEABLE_BRAND_VARIABLES;\n\n/** White primary/accent tokens — used by OpenHands-Neo for button surfaces. */\nconst NEO_WHITE_BUTTON_TOKENS: Record<\n (typeof COLOR_THEME_TOKEN_KEYS)[number],\n string\n> = {\n \"--oh-color-primary\": \"#ffffff\",\n \"--oh-accent\": \"#ffffff\",\n \"--oh-warning\": \"#ffffff\",\n};\n\nexport const COLOR_THEMES: Record<ColorThemeKey, ColorThemeDefinition> = {\n \"openhands-deepsea\": {\n label: \"OpenHands-DeepSea\",\n // Matches the values already set by index.css; included so switching back\n // from another theme restores the original palette explicitly.\n scale: {\n \"--cool-grey-50\": \"#F7F9FC\",\n \"--cool-grey-100\": \"#EEF2F7\",\n \"--cool-grey-200\": \"#DCE3EE\",\n \"--cool-grey-300\": \"#C3CDDC\",\n \"--cool-grey-400\": \"#A3B0C4\",\n \"--cool-grey-500\": \"#7E8A9E\",\n \"--cool-grey-600\": \"#626D82\",\n \"--cool-grey-700\": \"#4B5468\",\n \"--cool-grey-800\": \"#383F50\",\n \"--cool-grey-900\": \"#2C313F\",\n \"--cool-grey-925\": \"#21252F\",\n \"--cool-grey-950\": \"#0B0E14\",\n \"--cool-grey-975\": \"#05070A\",\n },\n // Values generated by heroui() from hero.ts — restore them explicitly when\n // switching back from another theme.\n heroui: {\n \"--heroui-background\": \"220 29.03% 6.08%\",\n \"--heroui-background-foreground\": \"216 45.45% 97.84%\",\n \"--heroui-foreground-50\": \"216 33.33% 2.94%\",\n \"--heroui-foreground-100\": \"220 29.03% 6.08%\",\n \"--heroui-foreground-200\": \"222.86 17.5% 15.69%\",\n \"--heroui-foreground-300\": \"224.21 17.76% 20.98%\",\n \"--heroui-foreground-400\": \"222.5 17.65% 26.67%\",\n \"--heroui-foreground-500\": \"221.38 16.2% 35.1%\",\n \"--heroui-foreground-600\": \"219.38 14.04% 44.71%\",\n \"--heroui-foreground-700\": \"217.5 14.16% 55.69%\",\n \"--heroui-foreground-800\": \"216.36 21.85% 70.39%\",\n \"--heroui-foreground-900\": \"216 26.32% 81.37%\",\n \"--heroui-foreground\": \"216 26.32% 81.37%\",\n \"--heroui-content1\": \"222.86 17.5% 15.69%\",\n \"--heroui-content1-foreground\": \"213.33 36% 95.1%\",\n \"--heroui-content2\": \"224.21 17.76% 20.98%\",\n \"--heroui-content2-foreground\": \"216.67 34.62% 89.8%\",\n \"--heroui-content3\": \"222.5 17.65% 26.67%\",\n \"--heroui-content3-foreground\": \"216 26.32% 81.37%\",\n \"--heroui-content4\": \"221.38 16.2% 35.1%\",\n \"--heroui-content4-foreground\": \"216.36 21.85% 70.39%\",\n \"--heroui-default-50\": \"216 33.33% 2.94%\",\n \"--heroui-default-100\": \"220 29.03% 6.08%\",\n \"--heroui-default-200\": \"222.86 17.5% 15.69%\",\n \"--heroui-default-300\": \"224.21 17.76% 20.98%\",\n \"--heroui-default-400\": \"222.5 17.65% 26.67%\",\n \"--heroui-default-500\": \"221.38 16.2% 35.1%\",\n \"--heroui-default-600\": \"219.38 14.04% 44.71%\",\n \"--heroui-default-700\": \"217.5 14.16% 55.69%\",\n \"--heroui-default-800\": \"216.36 21.85% 70.39%\",\n \"--heroui-default-900\": \"216 26.32% 81.37%\",\n \"--heroui-default-foreground\": \"216 45.45% 97.84%\",\n \"--heroui-default\": \"222.5 17.65% 26.67%\",\n },\n },\n\n \"openhands-neutral\": {\n label: \"OpenHands-Neutral\",\n scale: NEUTRAL_SCALE,\n // Each stop follows the same positional mapping as hero.ts:\n // heroui-default-100 ← cool-grey-950 position ← neutral-950 (#181818)\n // heroui-default-200 ← cool-grey-925 position ← neutral-900 (#202020)\n // ...etc.\n heroui: NEUTRAL_HEROUI,\n },\n\n \"openhands-neo\": {\n label: \"OpenHands-Neo\",\n scale: NEUTRAL_SCALE,\n heroui: NEUTRAL_HEROUI,\n tokens: NEO_WHITE_BUTTON_TOKENS,\n },\n};\n\nexport const DEFAULT_COLOR_THEME: ColorThemeKey = \"openhands-neutral\";\n\nexport const AVAILABLE_COLOR_THEMES = Object.entries(COLOR_THEMES).map(\n ([key, def]) => ({ key: key as ColorThemeKey, label: def.label }),\n);\n\nconst STORAGE_KEY = \"openhands-color-theme\";\n\n/** Read the persisted theme key from localStorage, falling back to the default. */\nexport function readPersistedColorTheme(): ColorThemeKey {\n if (typeof window === \"undefined\") return DEFAULT_COLOR_THEME;\n try {\n const stored = window.localStorage.getItem(STORAGE_KEY);\n if (stored && stored in COLOR_THEMES) return stored as ColorThemeKey;\n } catch {\n // ignore quota / privacy-mode failures\n }\n return DEFAULT_COLOR_THEME;\n}\n\n/** Persist the theme key to localStorage. */\nexport function persistColorTheme(key: ColorThemeKey): void {\n try {\n window.localStorage.setItem(STORAGE_KEY, key);\n } catch {\n // ignore\n }\n}\n\nconst THEME_STYLE_TAG_ID = \"oh-color-theme-override\";\n\n/**\n * Apply a theme by injecting (or replacing) a <style> tag that overrides\n * both our custom --cool-grey-* primitives and HeroUI's --heroui-* tokens.\n *\n * Why a <style> tag:\n * PostCSS transforms :root / body to [data-agent-server-ui], so --cool-grey-*\n * is set on EVERY element carrying that attribute. A body inline-style only\n * overrides body itself — inner matching elements keep the stylesheet value.\n *\n * Why heroui variables:\n * HeroUI stores colors as HSL channels in --heroui-* vars on [data-theme=dark].\n * They reference their own token system and are unaffected by --cool-grey-*\n * changes, so we override them from the same injected sheet.\n *\n * Why doubled selectors + re-append on every call:\n * \"Later sheet wins the tie\" cannot be relied on: in the built SPA\n * (ssr:false, prerendered shell) React 19 re-creates the <head> elements it\n * manages (<Meta/>/<Links/>) whenever the tree above the router remounts.\n * That can re-insert the base stylesheet <link> AFTER this tag, allowing its\n * unlayered [data-agent-server-ui] variable rules (0,1,0) to win every tie.\n * Doubling the attribute selectors ([x][x], 0,2,0) beats them from any\n * position in <head>; re-appending on each apply keeps document order\n * favorable as well.\n */\nexport function applyColorTheme(key: ColorThemeKey): void {\n if (typeof document === \"undefined\") return;\n const { scale, heroui, tokens = {} } = COLOR_THEMES[key];\n\n const scaleDecls = Object.entries(scale)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n const herouiDecls = Object.entries(heroui)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n const tokenDecls = Object.entries(tokens)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n // Target both selectors for heroui vars:\n // [data-agent-server-ui] — covers document.body (portal destination) so\n // portalled popover/listbox content inherits the overridden values.\n // [data-theme=dark] — covers the inner AgentServerUIRoot wrapper so\n // components scoped inside the dark theme wrapper also pick them up.\n // Both are doubled to out-specify the base sheet regardless of stylesheet\n // order (see the doc comment above).\n const css = [\n `[data-agent-server-ui][data-agent-server-ui] {\\n${scaleDecls}\\n${herouiDecls}\\n${tokenDecls}\\n}`,\n `[data-theme=dark][data-theme=dark] {\\n${herouiDecls}\\n}`,\n ].join(\"\\n\");\n\n let styleEl = document.getElementById(\n THEME_STYLE_TAG_ID,\n ) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = document.createElement(\"style\");\n styleEl.id = THEME_STYLE_TAG_ID;\n }\n styleEl.textContent = css;\n // Re-append even when the tag already exists (appendChild relocates a\n // connected node) so the override also stays after any re-inserted <link>.\n document.head.appendChild(styleEl);\n\n syncColorThemeTokensOnScopeRoots(tokens);\n}\n\nfunction syncColorThemeTokensOnScopeRoots(\n tokens: Record<string, string>,\n): void {\n const roots = document.querySelectorAll(\"[data-agent-server-ui]\");\n for (const root of roots) {\n if (!(root instanceof HTMLElement)) continue;\n\n for (const key of COLOR_THEME_TOKEN_KEYS) {\n const value = tokens[key];\n if (value) {\n root.style.setProperty(key, value);\n } else {\n root.style.removeProperty(key);\n }\n }\n }\n}\n"],"mappings":"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"}
@@ -44,12 +44,9 @@ export declare function persistColorTheme(key: ColorThemeKey): void;
44
44
  * Why doubled selectors + re-append on every call:
45
45
  * "Later sheet wins the tie" cannot be relied on: in the built SPA
46
46
  * (ssr:false, prerendered shell) React 19 re-creates the <head> elements it
47
- * manages (<Meta/>/<Links/>) whenever the tree above the router remounts
48
- * e.g. PostHogWrapper swapping in <PostHogProvider> once the analytics key
49
- * resolves, which only happens in builds with VITE_POSTHOG_CLIENT_KEY baked
50
- * (the published npm package / tagged Docker images). That re-inserts the
51
- * base stylesheet <link> AFTER this tag, which would let the base sheet's
52
- * unlayered [data-agent-server-ui] variable rules (0,1,0) win every tie.
47
+ * manages (<Meta/>/<Links/>) whenever the tree above the router remounts.
48
+ * That can re-insert the base stylesheet <link> AFTER this tag, allowing its
49
+ * unlayered [data-agent-server-ui] variable rules (0,1,0) to win every tie.
53
50
  * Doubling the attribute selectors ([x][x], 0,2,0) beats them from any
54
51
  * position in <head>; re-appending on each apply keeps document order
55
52
  * favorable as well.
@@ -1 +1 @@
1
- {"version":3,"file":"color-themes.js","names":[],"sources":["../../src/themes/color-themes.ts"],"sourcesContent":["export type ColorThemeKey =\n | \"openhands-deepsea\"\n | \"openhands-neutral\"\n | \"openhands-neo\";\n\nexport interface ColorThemeDefinition {\n label: string;\n /** Overrides for --cool-grey-* CSS custom properties (our semantic scale) */\n scale: Record<string, string>;\n /**\n * Overrides for --heroui-* CSS custom properties.\n * HeroUI stores colors as space-separated HSL channels (\"H S% L%\") so Tailwind\n * utilities like bg-default-200 resolve to hsl(var(--heroui-default-200)).\n * These vars are set by the heroui() plugin on :root, [data-theme=dark] at\n * build time, so they must be overridden at the same or lower specificity\n * from a later stylesheet to pick up theme changes at runtime.\n */\n heroui: Record<string, string>;\n /** Overrides for --oh-* semantic tokens such as brand / button colors. */\n tokens?: Record<string, string>;\n}\n\n// HSL channel strings for the neutral grey palette (H=0, S=0%, L=hex/255*100)\n// prettier-ignore\nconst NEUTRAL_HSL = {\n 50: \"0 0% 96.86%\", // #F7F7F7\n 100: \"0 0% 92.55%\", // #ECECEC\n 200: \"0 0% 86.27%\", // #DCDCDC\n 300: \"0 0% 74.51%\", // #BEBEBE\n 400: \"0 0% 59.22%\", // #979797\n 500: \"0 0% 45.1%\", // #737373\n 600: \"0 0% 33.73%\", // #565656\n 700: \"0 0% 25.1%\", // #404040\n 800: \"0 0% 19.22%\", // #313131\n 850: \"0 0% 15.69%\", // #282828\n 900: \"0 0% 12.55%\", // #202020\n 950: \"0 0% 9.41%\", // #181818\n 975: \"0 0% 6.27%\", // #101010\n};\n\nconst NEUTRAL_SCALE = {\n \"--cool-grey-50\": \"#F7F7F7\",\n \"--cool-grey-100\": \"#ECECEC\",\n \"--cool-grey-200\": \"#DCDCDC\",\n \"--cool-grey-300\": \"#BEBEBE\",\n \"--cool-grey-400\": \"#979797\",\n \"--cool-grey-500\": \"#737373\",\n \"--cool-grey-600\": \"#565656\",\n \"--cool-grey-700\": \"#404040\",\n \"--cool-grey-800\": \"#313131\",\n \"--cool-grey-900\": \"#282828\",\n \"--cool-grey-925\": \"#202020\",\n \"--cool-grey-950\": \"#181818\",\n \"--cool-grey-975\": \"#101010\",\n};\n\nconst NEUTRAL_HEROUI = {\n \"--heroui-background\": NEUTRAL_HSL[950],\n \"--heroui-background-foreground\": NEUTRAL_HSL[50],\n \"--heroui-foreground-50\": NEUTRAL_HSL[975],\n \"--heroui-foreground-100\": NEUTRAL_HSL[950],\n \"--heroui-foreground-200\": NEUTRAL_HSL[900],\n \"--heroui-foreground-300\": NEUTRAL_HSL[850],\n \"--heroui-foreground-400\": NEUTRAL_HSL[800],\n \"--heroui-foreground-500\": NEUTRAL_HSL[700],\n \"--heroui-foreground-600\": NEUTRAL_HSL[600],\n \"--heroui-foreground-700\": NEUTRAL_HSL[500],\n \"--heroui-foreground-800\": NEUTRAL_HSL[400],\n \"--heroui-foreground-900\": NEUTRAL_HSL[300],\n \"--heroui-foreground\": NEUTRAL_HSL[300],\n \"--heroui-content1\": NEUTRAL_HSL[900],\n \"--heroui-content1-foreground\": NEUTRAL_HSL[100],\n \"--heroui-content2\": NEUTRAL_HSL[850],\n \"--heroui-content2-foreground\": NEUTRAL_HSL[200],\n \"--heroui-content3\": NEUTRAL_HSL[800],\n \"--heroui-content3-foreground\": NEUTRAL_HSL[300],\n \"--heroui-content4\": NEUTRAL_HSL[700],\n \"--heroui-content4-foreground\": NEUTRAL_HSL[400],\n \"--heroui-default-50\": NEUTRAL_HSL[975],\n \"--heroui-default-100\": NEUTRAL_HSL[950],\n \"--heroui-default-200\": NEUTRAL_HSL[900],\n \"--heroui-default-300\": NEUTRAL_HSL[850],\n \"--heroui-default-400\": NEUTRAL_HSL[800],\n \"--heroui-default-500\": NEUTRAL_HSL[700],\n \"--heroui-default-600\": NEUTRAL_HSL[600],\n \"--heroui-default-700\": NEUTRAL_HSL[500],\n \"--heroui-default-800\": NEUTRAL_HSL[400],\n \"--heroui-default-900\": NEUTRAL_HSL[300],\n \"--heroui-default-foreground\": NEUTRAL_HSL[50],\n \"--heroui-default\": NEUTRAL_HSL[800],\n};\n\nimport { AGENT_SERVER_UI_THEMEABLE_BRAND_VARIABLES } from \"#/styles/agent-server-ui-style-scope\";\n\n/** CSS custom properties overridden by color themes (see applyColorTheme). */\nexport const COLOR_THEME_TOKEN_KEYS = AGENT_SERVER_UI_THEMEABLE_BRAND_VARIABLES;\n\n/** White primary/accent tokens — used by OpenHands-Neo for button surfaces. */\nconst NEO_WHITE_BUTTON_TOKENS: Record<\n (typeof COLOR_THEME_TOKEN_KEYS)[number],\n string\n> = {\n \"--oh-color-primary\": \"#ffffff\",\n \"--oh-accent\": \"#ffffff\",\n \"--oh-warning\": \"#ffffff\",\n};\n\nexport const COLOR_THEMES: Record<ColorThemeKey, ColorThemeDefinition> = {\n \"openhands-deepsea\": {\n label: \"OpenHands-DeepSea\",\n // Matches the values already set by index.css; included so switching back\n // from another theme restores the original palette explicitly.\n scale: {\n \"--cool-grey-50\": \"#F7F9FC\",\n \"--cool-grey-100\": \"#EEF2F7\",\n \"--cool-grey-200\": \"#DCE3EE\",\n \"--cool-grey-300\": \"#C3CDDC\",\n \"--cool-grey-400\": \"#A3B0C4\",\n \"--cool-grey-500\": \"#7E8A9E\",\n \"--cool-grey-600\": \"#626D82\",\n \"--cool-grey-700\": \"#4B5468\",\n \"--cool-grey-800\": \"#383F50\",\n \"--cool-grey-900\": \"#2C313F\",\n \"--cool-grey-925\": \"#21252F\",\n \"--cool-grey-950\": \"#0B0E14\",\n \"--cool-grey-975\": \"#05070A\",\n },\n // Values generated by heroui() from hero.ts — restore them explicitly when\n // switching back from another theme.\n heroui: {\n \"--heroui-background\": \"220 29.03% 6.08%\",\n \"--heroui-background-foreground\": \"216 45.45% 97.84%\",\n \"--heroui-foreground-50\": \"216 33.33% 2.94%\",\n \"--heroui-foreground-100\": \"220 29.03% 6.08%\",\n \"--heroui-foreground-200\": \"222.86 17.5% 15.69%\",\n \"--heroui-foreground-300\": \"224.21 17.76% 20.98%\",\n \"--heroui-foreground-400\": \"222.5 17.65% 26.67%\",\n \"--heroui-foreground-500\": \"221.38 16.2% 35.1%\",\n \"--heroui-foreground-600\": \"219.38 14.04% 44.71%\",\n \"--heroui-foreground-700\": \"217.5 14.16% 55.69%\",\n \"--heroui-foreground-800\": \"216.36 21.85% 70.39%\",\n \"--heroui-foreground-900\": \"216 26.32% 81.37%\",\n \"--heroui-foreground\": \"216 26.32% 81.37%\",\n \"--heroui-content1\": \"222.86 17.5% 15.69%\",\n \"--heroui-content1-foreground\": \"213.33 36% 95.1%\",\n \"--heroui-content2\": \"224.21 17.76% 20.98%\",\n \"--heroui-content2-foreground\": \"216.67 34.62% 89.8%\",\n \"--heroui-content3\": \"222.5 17.65% 26.67%\",\n \"--heroui-content3-foreground\": \"216 26.32% 81.37%\",\n \"--heroui-content4\": \"221.38 16.2% 35.1%\",\n \"--heroui-content4-foreground\": \"216.36 21.85% 70.39%\",\n \"--heroui-default-50\": \"216 33.33% 2.94%\",\n \"--heroui-default-100\": \"220 29.03% 6.08%\",\n \"--heroui-default-200\": \"222.86 17.5% 15.69%\",\n \"--heroui-default-300\": \"224.21 17.76% 20.98%\",\n \"--heroui-default-400\": \"222.5 17.65% 26.67%\",\n \"--heroui-default-500\": \"221.38 16.2% 35.1%\",\n \"--heroui-default-600\": \"219.38 14.04% 44.71%\",\n \"--heroui-default-700\": \"217.5 14.16% 55.69%\",\n \"--heroui-default-800\": \"216.36 21.85% 70.39%\",\n \"--heroui-default-900\": \"216 26.32% 81.37%\",\n \"--heroui-default-foreground\": \"216 45.45% 97.84%\",\n \"--heroui-default\": \"222.5 17.65% 26.67%\",\n },\n },\n\n \"openhands-neutral\": {\n label: \"OpenHands-Neutral\",\n scale: NEUTRAL_SCALE,\n // Each stop follows the same positional mapping as hero.ts:\n // heroui-default-100 ← cool-grey-950 position ← neutral-950 (#181818)\n // heroui-default-200 ← cool-grey-925 position ← neutral-900 (#202020)\n // ...etc.\n heroui: NEUTRAL_HEROUI,\n },\n\n \"openhands-neo\": {\n label: \"OpenHands-Neo\",\n scale: NEUTRAL_SCALE,\n heroui: NEUTRAL_HEROUI,\n tokens: NEO_WHITE_BUTTON_TOKENS,\n },\n};\n\nexport const DEFAULT_COLOR_THEME: ColorThemeKey = \"openhands-neutral\";\n\nexport const AVAILABLE_COLOR_THEMES = Object.entries(COLOR_THEMES).map(\n ([key, def]) => ({ key: key as ColorThemeKey, label: def.label }),\n);\n\nconst STORAGE_KEY = \"openhands-color-theme\";\n\n/** Read the persisted theme key from localStorage, falling back to the default. */\nexport function readPersistedColorTheme(): ColorThemeKey {\n if (typeof window === \"undefined\") return DEFAULT_COLOR_THEME;\n try {\n const stored = window.localStorage.getItem(STORAGE_KEY);\n if (stored && stored in COLOR_THEMES) return stored as ColorThemeKey;\n } catch {\n // ignore quota / privacy-mode failures\n }\n return DEFAULT_COLOR_THEME;\n}\n\n/** Persist the theme key to localStorage. */\nexport function persistColorTheme(key: ColorThemeKey): void {\n try {\n window.localStorage.setItem(STORAGE_KEY, key);\n } catch {\n // ignore\n }\n}\n\nconst THEME_STYLE_TAG_ID = \"oh-color-theme-override\";\n\n/**\n * Apply a theme by injecting (or replacing) a <style> tag that overrides\n * both our custom --cool-grey-* primitives and HeroUI's --heroui-* tokens.\n *\n * Why a <style> tag:\n * PostCSS transforms :root / body to [data-agent-server-ui], so --cool-grey-*\n * is set on EVERY element carrying that attribute. A body inline-style only\n * overrides body itself — inner matching elements keep the stylesheet value.\n *\n * Why heroui variables:\n * HeroUI stores colors as HSL channels in --heroui-* vars on [data-theme=dark].\n * They reference their own token system and are unaffected by --cool-grey-*\n * changes, so we override them from the same injected sheet.\n *\n * Why doubled selectors + re-append on every call:\n * \"Later sheet wins the tie\" cannot be relied on: in the built SPA\n * (ssr:false, prerendered shell) React 19 re-creates the <head> elements it\n * manages (<Meta/>/<Links/>) whenever the tree above the router remounts —\n * e.g. PostHogWrapper swapping in <PostHogProvider> once the analytics key\n * resolves, which only happens in builds with VITE_POSTHOG_CLIENT_KEY baked\n * (the published npm package / tagged Docker images). That re-inserts the\n * base stylesheet <link> AFTER this tag, which would let the base sheet's\n * unlayered [data-agent-server-ui] variable rules (0,1,0) win every tie.\n * Doubling the attribute selectors ([x][x], 0,2,0) beats them from any\n * position in <head>; re-appending on each apply keeps document order\n * favorable as well.\n */\nexport function applyColorTheme(key: ColorThemeKey): void {\n if (typeof document === \"undefined\") return;\n const { scale, heroui, tokens = {} } = COLOR_THEMES[key];\n\n const scaleDecls = Object.entries(scale)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n const herouiDecls = Object.entries(heroui)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n const tokenDecls = Object.entries(tokens)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n // Target both selectors for heroui vars:\n // [data-agent-server-ui] — covers document.body (portal destination) so\n // portalled popover/listbox content inherits the overridden values.\n // [data-theme=dark] — covers the inner AgentServerUIRoot wrapper so\n // components scoped inside the dark theme wrapper also pick them up.\n // Both are doubled to out-specify the base sheet regardless of stylesheet\n // order (see the doc comment above).\n const css = [\n `[data-agent-server-ui][data-agent-server-ui] {\\n${scaleDecls}\\n${herouiDecls}\\n${tokenDecls}\\n}`,\n `[data-theme=dark][data-theme=dark] {\\n${herouiDecls}\\n}`,\n ].join(\"\\n\");\n\n let styleEl = document.getElementById(\n THEME_STYLE_TAG_ID,\n ) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = document.createElement(\"style\");\n styleEl.id = THEME_STYLE_TAG_ID;\n }\n styleEl.textContent = css;\n // Re-append even when the tag already exists (appendChild relocates a\n // connected node) so the override also stays after any re-inserted <link>.\n document.head.appendChild(styleEl);\n\n syncColorThemeTokensOnScopeRoots(tokens);\n}\n\nfunction syncColorThemeTokensOnScopeRoots(\n tokens: Record<string, string>,\n): void {\n const roots = document.querySelectorAll(\"[data-agent-server-ui]\");\n for (const root of roots) {\n if (!(root instanceof HTMLElement)) continue;\n\n for (const key of COLOR_THEME_TOKEN_KEYS) {\n const value = tokens[key];\n if (value) {\n root.style.setProperty(key, value);\n } else {\n root.style.removeProperty(key);\n }\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"color-themes.js","names":[],"sources":["../../src/themes/color-themes.ts"],"sourcesContent":["export type ColorThemeKey =\n | \"openhands-deepsea\"\n | \"openhands-neutral\"\n | \"openhands-neo\";\n\nexport interface ColorThemeDefinition {\n label: string;\n /** Overrides for --cool-grey-* CSS custom properties (our semantic scale) */\n scale: Record<string, string>;\n /**\n * Overrides for --heroui-* CSS custom properties.\n * HeroUI stores colors as space-separated HSL channels (\"H S% L%\") so Tailwind\n * utilities like bg-default-200 resolve to hsl(var(--heroui-default-200)).\n * These vars are set by the heroui() plugin on :root, [data-theme=dark] at\n * build time, so they must be overridden at the same or lower specificity\n * from a later stylesheet to pick up theme changes at runtime.\n */\n heroui: Record<string, string>;\n /** Overrides for --oh-* semantic tokens such as brand / button colors. */\n tokens?: Record<string, string>;\n}\n\n// HSL channel strings for the neutral grey palette (H=0, S=0%, L=hex/255*100)\n// prettier-ignore\nconst NEUTRAL_HSL = {\n 50: \"0 0% 96.86%\", // #F7F7F7\n 100: \"0 0% 92.55%\", // #ECECEC\n 200: \"0 0% 86.27%\", // #DCDCDC\n 300: \"0 0% 74.51%\", // #BEBEBE\n 400: \"0 0% 59.22%\", // #979797\n 500: \"0 0% 45.1%\", // #737373\n 600: \"0 0% 33.73%\", // #565656\n 700: \"0 0% 25.1%\", // #404040\n 800: \"0 0% 19.22%\", // #313131\n 850: \"0 0% 15.69%\", // #282828\n 900: \"0 0% 12.55%\", // #202020\n 950: \"0 0% 9.41%\", // #181818\n 975: \"0 0% 6.27%\", // #101010\n};\n\nconst NEUTRAL_SCALE = {\n \"--cool-grey-50\": \"#F7F7F7\",\n \"--cool-grey-100\": \"#ECECEC\",\n \"--cool-grey-200\": \"#DCDCDC\",\n \"--cool-grey-300\": \"#BEBEBE\",\n \"--cool-grey-400\": \"#979797\",\n \"--cool-grey-500\": \"#737373\",\n \"--cool-grey-600\": \"#565656\",\n \"--cool-grey-700\": \"#404040\",\n \"--cool-grey-800\": \"#313131\",\n \"--cool-grey-900\": \"#282828\",\n \"--cool-grey-925\": \"#202020\",\n \"--cool-grey-950\": \"#181818\",\n \"--cool-grey-975\": \"#101010\",\n};\n\nconst NEUTRAL_HEROUI = {\n \"--heroui-background\": NEUTRAL_HSL[950],\n \"--heroui-background-foreground\": NEUTRAL_HSL[50],\n \"--heroui-foreground-50\": NEUTRAL_HSL[975],\n \"--heroui-foreground-100\": NEUTRAL_HSL[950],\n \"--heroui-foreground-200\": NEUTRAL_HSL[900],\n \"--heroui-foreground-300\": NEUTRAL_HSL[850],\n \"--heroui-foreground-400\": NEUTRAL_HSL[800],\n \"--heroui-foreground-500\": NEUTRAL_HSL[700],\n \"--heroui-foreground-600\": NEUTRAL_HSL[600],\n \"--heroui-foreground-700\": NEUTRAL_HSL[500],\n \"--heroui-foreground-800\": NEUTRAL_HSL[400],\n \"--heroui-foreground-900\": NEUTRAL_HSL[300],\n \"--heroui-foreground\": NEUTRAL_HSL[300],\n \"--heroui-content1\": NEUTRAL_HSL[900],\n \"--heroui-content1-foreground\": NEUTRAL_HSL[100],\n \"--heroui-content2\": NEUTRAL_HSL[850],\n \"--heroui-content2-foreground\": NEUTRAL_HSL[200],\n \"--heroui-content3\": NEUTRAL_HSL[800],\n \"--heroui-content3-foreground\": NEUTRAL_HSL[300],\n \"--heroui-content4\": NEUTRAL_HSL[700],\n \"--heroui-content4-foreground\": NEUTRAL_HSL[400],\n \"--heroui-default-50\": NEUTRAL_HSL[975],\n \"--heroui-default-100\": NEUTRAL_HSL[950],\n \"--heroui-default-200\": NEUTRAL_HSL[900],\n \"--heroui-default-300\": NEUTRAL_HSL[850],\n \"--heroui-default-400\": NEUTRAL_HSL[800],\n \"--heroui-default-500\": NEUTRAL_HSL[700],\n \"--heroui-default-600\": NEUTRAL_HSL[600],\n \"--heroui-default-700\": NEUTRAL_HSL[500],\n \"--heroui-default-800\": NEUTRAL_HSL[400],\n \"--heroui-default-900\": NEUTRAL_HSL[300],\n \"--heroui-default-foreground\": NEUTRAL_HSL[50],\n \"--heroui-default\": NEUTRAL_HSL[800],\n};\n\nimport { AGENT_SERVER_UI_THEMEABLE_BRAND_VARIABLES } from \"#/styles/agent-server-ui-style-scope\";\n\n/** CSS custom properties overridden by color themes (see applyColorTheme). */\nexport const COLOR_THEME_TOKEN_KEYS = AGENT_SERVER_UI_THEMEABLE_BRAND_VARIABLES;\n\n/** White primary/accent tokens — used by OpenHands-Neo for button surfaces. */\nconst NEO_WHITE_BUTTON_TOKENS: Record<\n (typeof COLOR_THEME_TOKEN_KEYS)[number],\n string\n> = {\n \"--oh-color-primary\": \"#ffffff\",\n \"--oh-accent\": \"#ffffff\",\n \"--oh-warning\": \"#ffffff\",\n};\n\nexport const COLOR_THEMES: Record<ColorThemeKey, ColorThemeDefinition> = {\n \"openhands-deepsea\": {\n label: \"OpenHands-DeepSea\",\n // Matches the values already set by index.css; included so switching back\n // from another theme restores the original palette explicitly.\n scale: {\n \"--cool-grey-50\": \"#F7F9FC\",\n \"--cool-grey-100\": \"#EEF2F7\",\n \"--cool-grey-200\": \"#DCE3EE\",\n \"--cool-grey-300\": \"#C3CDDC\",\n \"--cool-grey-400\": \"#A3B0C4\",\n \"--cool-grey-500\": \"#7E8A9E\",\n \"--cool-grey-600\": \"#626D82\",\n \"--cool-grey-700\": \"#4B5468\",\n \"--cool-grey-800\": \"#383F50\",\n \"--cool-grey-900\": \"#2C313F\",\n \"--cool-grey-925\": \"#21252F\",\n \"--cool-grey-950\": \"#0B0E14\",\n \"--cool-grey-975\": \"#05070A\",\n },\n // Values generated by heroui() from hero.ts — restore them explicitly when\n // switching back from another theme.\n heroui: {\n \"--heroui-background\": \"220 29.03% 6.08%\",\n \"--heroui-background-foreground\": \"216 45.45% 97.84%\",\n \"--heroui-foreground-50\": \"216 33.33% 2.94%\",\n \"--heroui-foreground-100\": \"220 29.03% 6.08%\",\n \"--heroui-foreground-200\": \"222.86 17.5% 15.69%\",\n \"--heroui-foreground-300\": \"224.21 17.76% 20.98%\",\n \"--heroui-foreground-400\": \"222.5 17.65% 26.67%\",\n \"--heroui-foreground-500\": \"221.38 16.2% 35.1%\",\n \"--heroui-foreground-600\": \"219.38 14.04% 44.71%\",\n \"--heroui-foreground-700\": \"217.5 14.16% 55.69%\",\n \"--heroui-foreground-800\": \"216.36 21.85% 70.39%\",\n \"--heroui-foreground-900\": \"216 26.32% 81.37%\",\n \"--heroui-foreground\": \"216 26.32% 81.37%\",\n \"--heroui-content1\": \"222.86 17.5% 15.69%\",\n \"--heroui-content1-foreground\": \"213.33 36% 95.1%\",\n \"--heroui-content2\": \"224.21 17.76% 20.98%\",\n \"--heroui-content2-foreground\": \"216.67 34.62% 89.8%\",\n \"--heroui-content3\": \"222.5 17.65% 26.67%\",\n \"--heroui-content3-foreground\": \"216 26.32% 81.37%\",\n \"--heroui-content4\": \"221.38 16.2% 35.1%\",\n \"--heroui-content4-foreground\": \"216.36 21.85% 70.39%\",\n \"--heroui-default-50\": \"216 33.33% 2.94%\",\n \"--heroui-default-100\": \"220 29.03% 6.08%\",\n \"--heroui-default-200\": \"222.86 17.5% 15.69%\",\n \"--heroui-default-300\": \"224.21 17.76% 20.98%\",\n \"--heroui-default-400\": \"222.5 17.65% 26.67%\",\n \"--heroui-default-500\": \"221.38 16.2% 35.1%\",\n \"--heroui-default-600\": \"219.38 14.04% 44.71%\",\n \"--heroui-default-700\": \"217.5 14.16% 55.69%\",\n \"--heroui-default-800\": \"216.36 21.85% 70.39%\",\n \"--heroui-default-900\": \"216 26.32% 81.37%\",\n \"--heroui-default-foreground\": \"216 45.45% 97.84%\",\n \"--heroui-default\": \"222.5 17.65% 26.67%\",\n },\n },\n\n \"openhands-neutral\": {\n label: \"OpenHands-Neutral\",\n scale: NEUTRAL_SCALE,\n // Each stop follows the same positional mapping as hero.ts:\n // heroui-default-100 ← cool-grey-950 position ← neutral-950 (#181818)\n // heroui-default-200 ← cool-grey-925 position ← neutral-900 (#202020)\n // ...etc.\n heroui: NEUTRAL_HEROUI,\n },\n\n \"openhands-neo\": {\n label: \"OpenHands-Neo\",\n scale: NEUTRAL_SCALE,\n heroui: NEUTRAL_HEROUI,\n tokens: NEO_WHITE_BUTTON_TOKENS,\n },\n};\n\nexport const DEFAULT_COLOR_THEME: ColorThemeKey = \"openhands-neutral\";\n\nexport const AVAILABLE_COLOR_THEMES = Object.entries(COLOR_THEMES).map(\n ([key, def]) => ({ key: key as ColorThemeKey, label: def.label }),\n);\n\nconst STORAGE_KEY = \"openhands-color-theme\";\n\n/** Read the persisted theme key from localStorage, falling back to the default. */\nexport function readPersistedColorTheme(): ColorThemeKey {\n if (typeof window === \"undefined\") return DEFAULT_COLOR_THEME;\n try {\n const stored = window.localStorage.getItem(STORAGE_KEY);\n if (stored && stored in COLOR_THEMES) return stored as ColorThemeKey;\n } catch {\n // ignore quota / privacy-mode failures\n }\n return DEFAULT_COLOR_THEME;\n}\n\n/** Persist the theme key to localStorage. */\nexport function persistColorTheme(key: ColorThemeKey): void {\n try {\n window.localStorage.setItem(STORAGE_KEY, key);\n } catch {\n // ignore\n }\n}\n\nconst THEME_STYLE_TAG_ID = \"oh-color-theme-override\";\n\n/**\n * Apply a theme by injecting (or replacing) a <style> tag that overrides\n * both our custom --cool-grey-* primitives and HeroUI's --heroui-* tokens.\n *\n * Why a <style> tag:\n * PostCSS transforms :root / body to [data-agent-server-ui], so --cool-grey-*\n * is set on EVERY element carrying that attribute. A body inline-style only\n * overrides body itself — inner matching elements keep the stylesheet value.\n *\n * Why heroui variables:\n * HeroUI stores colors as HSL channels in --heroui-* vars on [data-theme=dark].\n * They reference their own token system and are unaffected by --cool-grey-*\n * changes, so we override them from the same injected sheet.\n *\n * Why doubled selectors + re-append on every call:\n * \"Later sheet wins the tie\" cannot be relied on: in the built SPA\n * (ssr:false, prerendered shell) React 19 re-creates the <head> elements it\n * manages (<Meta/>/<Links/>) whenever the tree above the router remounts.\n * That can re-insert the base stylesheet <link> AFTER this tag, allowing its\n * unlayered [data-agent-server-ui] variable rules (0,1,0) to win every tie.\n * Doubling the attribute selectors ([x][x], 0,2,0) beats them from any\n * position in <head>; re-appending on each apply keeps document order\n * favorable as well.\n */\nexport function applyColorTheme(key: ColorThemeKey): void {\n if (typeof document === \"undefined\") return;\n const { scale, heroui, tokens = {} } = COLOR_THEMES[key];\n\n const scaleDecls = Object.entries(scale)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n const herouiDecls = Object.entries(heroui)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n const tokenDecls = Object.entries(tokens)\n .map(([p, v]) => ` ${p}: ${v};`)\n .join(\"\\n\");\n\n // Target both selectors for heroui vars:\n // [data-agent-server-ui] — covers document.body (portal destination) so\n // portalled popover/listbox content inherits the overridden values.\n // [data-theme=dark] — covers the inner AgentServerUIRoot wrapper so\n // components scoped inside the dark theme wrapper also pick them up.\n // Both are doubled to out-specify the base sheet regardless of stylesheet\n // order (see the doc comment above).\n const css = [\n `[data-agent-server-ui][data-agent-server-ui] {\\n${scaleDecls}\\n${herouiDecls}\\n${tokenDecls}\\n}`,\n `[data-theme=dark][data-theme=dark] {\\n${herouiDecls}\\n}`,\n ].join(\"\\n\");\n\n let styleEl = document.getElementById(\n THEME_STYLE_TAG_ID,\n ) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = document.createElement(\"style\");\n styleEl.id = THEME_STYLE_TAG_ID;\n }\n styleEl.textContent = css;\n // Re-append even when the tag already exists (appendChild relocates a\n // connected node) so the override also stays after any re-inserted <link>.\n document.head.appendChild(styleEl);\n\n syncColorThemeTokensOnScopeRoots(tokens);\n}\n\nfunction syncColorThemeTokensOnScopeRoots(\n tokens: Record<string, string>,\n): void {\n const roots = document.querySelectorAll(\"[data-agent-server-ui]\");\n for (const root of roots) {\n if (!(root instanceof HTMLElement)) continue;\n\n for (const key of COLOR_THEME_TOKEN_KEYS) {\n const value = tokens[key];\n if (value) {\n root.style.setProperty(key, value);\n } else {\n root.style.removeProperty(key);\n }\n }\n }\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { CANVAS_UI_CLIENT_ACTION_KIND } from "#/constants/canvas-ui";
1
2
  import { ActionBase } from "./base";
2
3
  import { TaskItem } from "./common";
3
4
  export interface MCPToolAction extends ActionBase<"MCPToolAction"> {
@@ -281,11 +282,11 @@ export interface SwitchLLMAction extends ActionBase<"SwitchLLMAction"> {
281
282
  reason: string;
282
283
  }
283
284
  /**
284
- * Frontend-injected custom tool. Emitted over the existing WebSocket as a
285
- * regular ActionEvent; intercepted client-side by handleCanvasUIAction.
286
- * The Python definition lives in tools/canvas_ui_tool.py.
285
+ * Canvas UI action emitted over the existing WebSocket and intercepted by
286
+ * handleCanvasUIAction. Legacy conversations use CanvasUIAction; new
287
+ * conversations use the SDK-generated client action kind.
287
288
  */
288
- export interface CanvasUIAction extends ActionBase<"CanvasUIAction"> {
289
+ export interface CanvasUIAction extends ActionBase<"CanvasUIAction" | typeof CANVAS_UI_CLIENT_ACTION_KIND> {
289
290
  command: "navigate_to_file" | "open_tab" | "show_preview";
290
291
  path?: string | null;
291
292
  tab?: string | null;