@openhands/agent-canvas 1.7.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/README.md +1 -1
  2. package/README.windows.md +2 -2
  3. package/build/assets/{Trans-DP5rcauH.js → Trans-B7lYw4uD.js} +1 -1
  4. package/build/assets/{acp-providers-BHKZvEm5.js → acp-providers-WUD4tfSq.js} +1 -1
  5. package/build/assets/active-backend-context-mY7Gff5c.js +2 -0
  6. package/build/assets/{agent-context-settings-BwAakl29.js → agent-context-settings-BTUmWEzL.js} +1 -1
  7. package/build/assets/{agent-profiles-settings-BYU6aWus.js → agent-profiles-settings-Ilqid_R5.js} +1 -1
  8. package/build/assets/agent-server-conversation-service.api-C_7YnjzP.js +41 -0
  9. package/build/assets/{agent-settings-DEPFl5hR.js → agent-settings-BGTyoT6X.js} +2 -2
  10. package/build/assets/agent-settings-CxfT4ksO.js +1 -0
  11. package/build/assets/{alert-banner-C1nzoXBC.js → alert-banner-eRyIwDyU.js} +1 -1
  12. package/build/assets/api-key-entry-screen-JOx3SH1-.js +1 -0
  13. package/build/assets/app-settings-D53QZy5p.js +1 -0
  14. package/build/assets/automation-detail-nEflClmc.js +2 -0
  15. package/build/assets/{automation-export-Ca2ehC-k.js → automation-export-BO_kfqC8.js} +1 -1
  16. package/build/assets/{automations-list-ZHQSW8qD.js → automations-list-BYncC7gv.js} +1 -1
  17. package/build/assets/{back-nav-button-Be_L157B.js → back-nav-button-C02hGa8t.js} +1 -1
  18. package/build/assets/backend-form-modal-CKrBF80P.js +1 -0
  19. package/build/assets/{backend-synced-settings-badge-DdUfuSN8.js → backend-synced-settings-badge-CQ9xtNWm.js} +1 -1
  20. package/build/assets/{badge-B6q3sVom.js → badge-CzXbf7tR.js} +1 -1
  21. package/build/assets/{base-modal-CSHhJTSr.js → base-modal-DkVyzFMt.js} +1 -1
  22. package/build/assets/{brand-button-CQO8oqVo.js → brand-button-BUlDL-mz.js} +1 -1
  23. package/build/assets/{browser-BUDJnBg4.js → browser-3QjrEr1D.js} +1 -1
  24. package/build/assets/{browser-tab-Cir7KbAL.js → browser-tab-BijpUbdt.js} +1 -1
  25. package/build/assets/{chat-send-button-D4614wUz.js → chat-send-button-BKsVjhtA.js} +1 -1
  26. package/build/assets/check-CrxQfJZ2.js +1 -0
  27. package/build/assets/chevron-down-D_LsyTA7.js +1 -0
  28. package/build/assets/circle-check-DZn9HkLE.js +1 -0
  29. package/build/assets/{circle-plus-check-toggle-E3Ecb_gg.js → circle-plus-check-toggle-DdjUiOo1.js} +1 -1
  30. package/build/assets/cloud-funnel-analytics-NlmDoeo2.js +1 -0
  31. package/build/assets/{combobox-caret-C8_eGdp2.js → combobox-caret-Dl9UtvD6.js} +1 -1
  32. package/build/assets/{command-menu-N_BriUy8.js → command-menu-CvLPs7dg.js} +1 -1
  33. package/build/assets/{condenser-settings-jNGOKFGz.js → condenser-settings-C4Y9CzQV.js} +1 -1
  34. package/build/assets/{confirmation-modal-gZtbojCm.js → confirmation-modal-CRBJSllP.js} +1 -1
  35. package/build/assets/{context-menu-list-item-BTHGFhIx.js → context-menu-list-item-FGaafXGh.js} +1 -1
  36. package/build/assets/conversation-D_ORtpKC.js +1 -0
  37. package/build/assets/conversation-Dpc5nmGi.js +90 -0
  38. package/build/assets/conversation-panel-D_ORtpKC.js +1 -0
  39. package/build/assets/conversation-state-store-CGRQemtx.js +1 -0
  40. package/build/assets/{conversation-tab-empty-state-BCMHkGQk.js → conversation-tab-empty-state-CDjvNgpG.js} +1 -1
  41. package/build/assets/{copy-B8Y5ufoR.js → copy-Drwu97Gx.js} +1 -1
  42. package/build/assets/{copy-to-clipboard-button-C4l3CMSd.js → copy-to-clipboard-button-NbN1clVr.js} +1 -1
  43. package/build/assets/{device-verify-C_M7Z8xs.js → device-verify-CDm_WrVu.js} +1 -1
  44. package/build/assets/{dropdown-classes-DQlj-MpS.js → dropdown-classes-CqA2BTCL.js} +1 -1
  45. package/build/assets/{entry.client-CCrlta8r.js → entry.client-BO2KQj0y.js} +2 -2
  46. package/build/assets/{enum-filter-dropdown-paB-lFSP.js → enum-filter-dropdown-DSqPZnsD.js} +1 -1
  47. package/build/assets/{environment-switch-overlay-D0FgCMqs.js → environment-switch-overlay-mGl2pqqx.js} +1 -1
  48. package/build/assets/extensions-hub-Br3Lgynp.js +1 -0
  49. package/build/assets/extensions-navigation-BQmstKDZ.js +1 -0
  50. package/build/assets/{external-link-Cnnd6ikC.js → external-link-D9B2QMPf.js} +1 -1
  51. package/build/assets/files-tab-4c9HFSLo.js +1 -0
  52. package/build/assets/{form-control-classes-CSPevi7c.js → form-control-classes-CtVAktAy.js} +1 -1
  53. package/build/assets/{format-time-delta-DuhE50B-.js → format-time-delta-DICE64sz.js} +1 -1
  54. package/build/assets/git-provider-icon-0PqmIS_S.js +1 -0
  55. package/build/assets/{highlighted-source-view-suUKd5if.js → highlighted-source-view-KMsA9c4a.js} +1 -1
  56. package/build/assets/home-D9JsyEmE.js +1 -0
  57. package/build/assets/{home-BZclW6kd.js → home-TFhnmZLx.js} +1 -1
  58. package/build/assets/index-home-D9JsyEmE.js +1 -0
  59. package/build/assets/install-server-modal-BgGRnqA0.js +1 -0
  60. package/build/assets/{launch-Bik37u9Y.js → launch-DjkKw55l.js} +1 -1
  61. package/build/assets/{list-todo-_BXQzOiB.js → list-todo-BpAf7aOT.js} +1 -1
  62. package/build/assets/{llm-not-configured-banner-znJFsW_O.js → llm-not-configured-banner-Y4W9-sar.js} +4 -4
  63. package/build/assets/llm-settings-D8zNkIlP.js +1 -0
  64. package/build/assets/llm-settings-nPwv7hKu.js +1 -0
  65. package/build/assets/{llm-subscription-service-_QUsVybQ.js → llm-subscription-service-COTgZc1C.js} +1 -1
  66. package/build/assets/loader-circle-CGD6-Vak.js +1 -0
  67. package/build/assets/{loading-spinner-CcpnCr_d.js → loading-spinner-DRFyh6Iy.js} +1 -1
  68. package/build/assets/manage-backends-modal-DiRWE3tJ.js +1 -0
  69. package/build/assets/manifest-1cf33a7b.js +1 -0
  70. package/build/assets/markdown-renderer-U40HF0Ak.js +8 -0
  71. package/build/assets/mcp-xDMaHzOw.js +9 -0
  72. package/build/assets/{messages-CYztjKLQ.js → messages-CdNfZPgd.js} +2 -2
  73. package/build/assets/{modal-body-DQhiw-AR.js → modal-body-C3bGicn4.js} +1 -1
  74. package/build/assets/{modal-classes-YaEEa5eZ.js → modal-classes-DFFO6BMU.js} +1 -1
  75. package/build/assets/{modal-close-button-turIYn0t.js → modal-close-button-vxkAIRyZ.js} +1 -1
  76. package/build/assets/{onboarding-9pEMFGtN.js → onboarding-DWuFieEA.js} +1 -1
  77. package/build/assets/onboarding-modal-C8m72Dpb.js +1 -0
  78. package/build/assets/organization-service.api-CQ73CB-S.js +1 -0
  79. package/build/assets/{pencil-8_lvWDoZ.js → pencil-DzW2GB2M.js} +1 -1
  80. package/build/assets/{planner-tab-Dr8B-ZBI.js → planner-tab-YG0bGxDY.js} +1 -1
  81. package/build/assets/plugins-management-service-ijhH8OSh.js +1 -0
  82. package/build/assets/plus-CTGLo3aa.js +1 -0
  83. package/build/assets/profiles-service.api-C32pPm70.js +1 -0
  84. package/build/assets/providers-DuSn9s2i.js +1 -0
  85. package/build/assets/proxy-BiyDhMBd.js +1 -0
  86. package/build/assets/{puzzle-DXWdfaa7.js → puzzle-DlqT0yvr.js} +1 -1
  87. package/build/assets/{recommended-automations-launcher-Dye8Li08.js → recommended-automations-launcher-Dru1yN46.js} +2 -2
  88. package/build/assets/{refresh-cw-D7CYLy-d.js → refresh-cw-Br5254f4.js} +1 -1
  89. package/build/assets/root-DOLLQteU.js +2 -0
  90. package/build/assets/root-layout-xmylWoew.js +3 -0
  91. package/build/assets/schema-field-htfNouTG.js +1 -0
  92. package/build/assets/{sdk-section-page-Di5mT86Y.js → sdk-section-page-D0K1dBQY.js} +1 -1
  93. package/build/assets/search-BrpWXWUi.js +1 -0
  94. package/build/assets/secrets-service-Dbv5Zb8G.js +1 -0
  95. package/build/assets/{secrets-settings-DPlA3moO.js → secrets-settings-Da4SSaX9.js} +1 -1
  96. package/build/assets/{segmented-toggle-DbbD3Tve.js → segmented-toggle-CZKOdIly.js} +1 -1
  97. package/build/assets/settings-F4a09IxY.js +1 -0
  98. package/build/assets/{settings-dropdown-input-Dx6vlkgf.js → settings-dropdown-input-jOiv5Yrk.js} +1 -1
  99. package/build/assets/{settings-index-D5dDKrDt.js → settings-index-CyJBf5NA.js} +1 -1
  100. package/build/assets/{settings-input-BjW_zyTN.js → settings-input-BEaTCem1.js} +1 -1
  101. package/build/assets/{settings-list-classes-gQdBahdt.js → settings-list-classes-VqMzkYYt.js} +1 -1
  102. package/build/assets/{settings-modal-DsJk2THd.js → settings-modal-C-S1NpbC.js} +1 -1
  103. package/build/assets/settings-service.api-CTJRrvMu.js +1 -0
  104. package/build/assets/{settings-switch-UNSf8K8I.js → settings-switch-B405oU_v.js} +1 -1
  105. package/build/assets/{shared-conversation-DU1kwDTF.js → shared-conversation-BvWtTwES.js} +1 -1
  106. package/build/assets/{sidebar-layout-DXHtbEj1.js → sidebar-layout-BGMuyC86.js} +1 -1
  107. package/build/assets/{sidebar-mobile-menu-toggle-BlmI8OrA.js → sidebar-mobile-menu-toggle-xiKoUfGa.js} +1 -1
  108. package/build/assets/{sidebar-nav-link-pvUivfK2.js → sidebar-nav-link-DA4_ct9G.js} +1 -1
  109. package/build/assets/{sidebar-store-DwrYKwYr.js → sidebar-store-FRJ3rADB.js} +1 -1
  110. package/build/assets/{skill-card-pill-row-D7XCz5uk.js → skill-card-pill-row-BMdhr_sd.js} +1 -1
  111. package/build/assets/{skill-icon-badge-HqBWZ2Eq.js → skill-icon-badge-CGUkgcVH.js} +1 -1
  112. package/build/assets/{skills-plugins-YJSV6A0M.js → skills-plugins-C5eJnyft.js} +1 -1
  113. package/build/assets/{skills-settings-BbREHv_-.js → skills-settings-pUxMr6WZ.js} +1 -1
  114. package/build/assets/{styled-tooltip-DsjDnR_W.js → styled-tooltip-B3kIdVyH.js} +1 -1
  115. package/build/assets/{task-list-tab-Dzim5ftn.js → task-list-tab-B3k4W1cK.js} +1 -1
  116. package/build/assets/{terminal-CYFAMiXx.js → terminal-CBI_41Zc.js} +1 -1
  117. package/build/assets/{toggle-switch-BptY3XRG.js → toggle-switch-DYRr9CAR.js} +1 -1
  118. package/build/assets/{trash-2-Bq4lHbTB.js → trash-2-gZPlx23R.js} +1 -1
  119. package/build/assets/{typography-C6fuRTTT.js → typography-B1UxuuEC.js} +1 -1
  120. package/build/assets/{use-acp-credential-form-CuBXKNvP.js → use-acp-credential-form-CjSvKWFH.js} +1 -1
  121. package/build/assets/use-activate-agent-profile-DCRf47e-.js +1 -0
  122. package/build/assets/use-agent-profiles-DmT9zxAN.js +1 -0
  123. package/build/assets/{use-can-manage-org-profiles-Uai-HHx2.js → use-can-manage-org-profiles-vBiP7rHF.js} +1 -1
  124. package/build/assets/use-cloud-current-user-id-BMq9gw93.js +1 -0
  125. package/build/assets/use-config-C959QcRC.js +1 -0
  126. package/build/assets/{use-create-conversation-DzcM79TE.js → use-create-conversation-CakhLF0X.js} +1 -1
  127. package/build/assets/{use-create-secret-2YLjoQw-.js → use-create-secret-RT4QtSS9.js} +1 -1
  128. package/build/assets/use-llm-profiles-CdaxVpyY.js +1 -0
  129. package/build/assets/use-onboarding-completion-CJU4MNAY.js +1 -0
  130. package/build/assets/use-plugins-marketplace-D-93nqtJ.js +1 -0
  131. package/build/assets/{use-save-agent-profile-Q2M72WgR.js → use-save-agent-profile-DGJ3-u0M.js} +1 -1
  132. package/build/assets/{use-save-settings-BZK7zVsK.js → use-save-settings--C6LZXfI.js} +1 -1
  133. package/build/assets/use-settings-DIAo5KFk.js +1 -0
  134. package/build/assets/use-settings-nav-items-DPK5sxvR.js +16 -0
  135. package/build/assets/use-skills-D_mLhYNa.js +1 -0
  136. package/build/assets/use-tracking-COqZLobY.js +1 -0
  137. package/build/assets/{use-user-conversation-43duhf7D.js → use-user-conversation-DhcAEyJX.js} +1 -1
  138. package/build/assets/{useMutation-DyQXZFEF.js → useMutation-DHLpZ6J0.js} +1 -1
  139. package/build/assets/utils-DsWhWn2F.js +1 -0
  140. package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~g4xrpilz-CJ7amdtQ.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~g4xrpilz-CYPMCkX1.js} +1 -1
  141. package/build/assets/{vendor~files-tab-vm3f67Pz.js → vendor~files-tab-atebg0iG.js} +1 -1
  142. package/build/assets/{vendor~index-home~home~conversation-panel~conversation-kX4LrGQC.js → vendor~index-home~home~conversation-panel~conversation-G9DMrR7m.js} +1 -1
  143. package/build/assets/{vendor~root-layout~conversation-panel~conversation-DpA6fir3.js → vendor~root-layout~conversation-panel~conversation-DEhW1h3I.js} +1 -1
  144. package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation-EShpjxey.js → vendor~root-layout~index-home~home~conversation-panel~conversation-Acmf1sKj.js} +1 -1
  145. package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation-DD_UNO02.js → vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation-CmzCY1BT.js} +1 -1
  146. package/build/assets/{vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-Be63Q2Ln.js → vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-C7Yh77RT.js} +1 -1
  147. package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~bi2r7bko-Bw4AuHN1.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~bi2r7bko-VFnwct3q.js} +1 -1
  148. package/build/assets/{verification-settings-B4DL3Tez.js → verification-settings-Vr5cN4md.js} +1 -1
  149. package/build/assets/x-Dx_JbpHA.js +1 -0
  150. package/build/favicon-16x16.png +0 -0
  151. package/build/favicon-32x32.png +0 -0
  152. package/build/favicon.ico +0 -0
  153. package/build/index.html +4 -4
  154. package/build/locales/ar/openhands.json +2 -0
  155. package/build/locales/ca/openhands.json +2 -0
  156. package/build/locales/de/openhands.json +2 -0
  157. package/build/locales/en/openhands.json +2 -0
  158. package/build/locales/es/openhands.json +2 -0
  159. package/build/locales/fr/openhands.json +2 -0
  160. package/build/locales/it/openhands.json +2 -0
  161. package/build/locales/ja/openhands.json +2 -0
  162. package/build/locales/ko-KR/openhands.json +2 -0
  163. package/build/locales/no/openhands.json +2 -0
  164. package/build/locales/pt/openhands.json +2 -0
  165. package/build/locales/tr/openhands.json +2 -0
  166. package/build/locales/uk/openhands.json +2 -0
  167. package/build/locales/zh-CN/openhands.json +2 -0
  168. package/build/locales/zh-TW/openhands.json +2 -0
  169. package/config/defaults.json +4 -4
  170. package/dist/api/agent-server-adapter.cjs +1 -1
  171. package/dist/api/agent-server-adapter.cjs.map +1 -1
  172. package/dist/api/agent-server-adapter.js +7 -7
  173. package/dist/api/agent-server-adapter.js.map +1 -1
  174. package/dist/api/automation-service/automation-service.api.cjs +1 -1
  175. package/dist/api/automation-service/automation-service.api.cjs.map +1 -1
  176. package/dist/api/automation-service/automation-service.api.js +95 -95
  177. package/dist/api/automation-service/automation-service.api.js.map +1 -1
  178. package/dist/api/backend-registry/storage.cjs +1 -1
  179. package/dist/api/backend-registry/storage.cjs.map +1 -1
  180. package/dist/api/backend-registry/storage.js +1 -1
  181. package/dist/api/backend-registry/storage.js.map +1 -1
  182. package/dist/api/backend-registry/types.d.ts +2 -0
  183. package/dist/api/cloud/conversation-service.api.cjs +1 -1
  184. package/dist/api/cloud/conversation-service.api.js +22 -22
  185. package/dist/api/mcp-service/mcp-service.api.cjs +1 -1
  186. package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -1
  187. package/dist/api/mcp-service/mcp-service.api.js +19 -19
  188. package/dist/api/mcp-service/mcp-service.api.js.map +1 -1
  189. package/dist/api/settings-service/settings-service.api.cjs +1 -1
  190. package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
  191. package/dist/api/settings-service/settings-service.api.js +26 -12
  192. package/dist/api/settings-service/settings-service.api.js.map +1 -1
  193. package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
  194. package/dist/components/features/mcp-page/custom-server-editor.js +16 -16
  195. package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
  196. package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
  197. package/dist/components/features/mcp-page/installed-server-card.d.ts +2 -2
  198. package/dist/components/features/mcp-page/installed-server-card.js +6 -7
  199. package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
  200. package/dist/components/features/mcp-page/installed-servers-section.cjs +1 -1
  201. package/dist/components/features/mcp-page/installed-servers-section.cjs.map +1 -1
  202. package/dist/components/features/mcp-page/installed-servers-section.d.ts +2 -2
  203. package/dist/components/features/mcp-page/installed-servers-section.js +2 -2
  204. package/dist/components/features/mcp-page/installed-servers-section.js.map +1 -1
  205. package/dist/components/features/mcp-page/mcp-server-health.cjs +1 -1
  206. package/dist/components/features/mcp-page/mcp-server-health.js +4 -4
  207. package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs +1 -1
  208. package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs.map +1 -1
  209. package/dist/components/features/settings/mcp-settings/mcp-server-form.js +2 -1
  210. package/dist/components/features/settings/mcp-settings/mcp-server-form.js.map +1 -1
  211. package/dist/config/defaults.cjs +1 -1
  212. package/dist/config/defaults.cjs.map +1 -1
  213. package/dist/config/defaults.js +3 -3
  214. package/dist/config/defaults.js.map +1 -1
  215. package/dist/contexts/active-backend-context.cjs +1 -1
  216. package/dist/contexts/active-backend-context.cjs.map +1 -1
  217. package/dist/contexts/active-backend-context.d.ts +3 -2
  218. package/dist/contexts/active-backend-context.js +55 -42
  219. package/dist/contexts/active-backend-context.js.map +1 -1
  220. package/dist/favicon-16x16.png +0 -0
  221. package/dist/favicon-32x32.png +0 -0
  222. package/dist/favicon.ico +0 -0
  223. package/dist/hooks/mutation/use-update-mcp-server.cjs +1 -1
  224. package/dist/hooks/mutation/use-update-mcp-server.js +5 -5
  225. package/dist/hooks/query/use-cloud-current-user-id.cjs +1 -1
  226. package/dist/hooks/query/use-cloud-current-user-id.cjs.map +1 -1
  227. package/dist/hooks/query/use-cloud-current-user-id.js +7 -5
  228. package/dist/hooks/query/use-cloud-current-user-id.js.map +1 -1
  229. package/dist/hooks/query/use-cloud-organizations.cjs +1 -1
  230. package/dist/hooks/query/use-cloud-organizations.cjs.map +1 -1
  231. package/dist/hooks/query/use-cloud-organizations.js +5 -1
  232. package/dist/hooks/query/use-cloud-organizations.js.map +1 -1
  233. package/dist/hooks/use-can-manage-org-profiles.cjs +1 -1
  234. package/dist/hooks/use-can-manage-org-profiles.cjs.map +1 -1
  235. package/dist/hooks/use-can-manage-org-profiles.js +2 -1
  236. package/dist/hooks/use-can-manage-org-profiles.js.map +1 -1
  237. package/dist/hooks/use-tracking.cjs +1 -1
  238. package/dist/hooks/use-tracking.js +9 -9
  239. package/dist/i18n/declaration.cjs +1 -1
  240. package/dist/i18n/declaration.cjs.map +1 -1
  241. package/dist/i18n/declaration.d.ts +2 -0
  242. package/dist/i18n/declaration.js +1 -1
  243. package/dist/i18n/declaration.js.map +1 -1
  244. package/dist/i18n/translation.cjs +1 -1
  245. package/dist/i18n/translation.cjs.map +1 -1
  246. package/dist/i18n/translation.js +34 -0
  247. package/dist/i18n/translation.js.map +1 -1
  248. package/dist/locales/ar/openhands.json +2 -0
  249. package/dist/locales/ca/openhands.json +2 -0
  250. package/dist/locales/de/openhands.json +2 -0
  251. package/dist/locales/en/openhands.json +2 -0
  252. package/dist/locales/es/openhands.json +2 -0
  253. package/dist/locales/fr/openhands.json +2 -0
  254. package/dist/locales/it/openhands.json +2 -0
  255. package/dist/locales/ja/openhands.json +2 -0
  256. package/dist/locales/ko-KR/openhands.json +2 -0
  257. package/dist/locales/no/openhands.json +2 -0
  258. package/dist/locales/pt/openhands.json +2 -0
  259. package/dist/locales/tr/openhands.json +2 -0
  260. package/dist/locales/uk/openhands.json +2 -0
  261. package/dist/locales/zh-CN/openhands.json +2 -0
  262. package/dist/locales/zh-TW/openhands.json +2 -0
  263. package/dist/node_modules/@openhands/typescript-client/dist/client/settings-client.cjs +1 -1
  264. package/dist/node_modules/@openhands/typescript-client/dist/client/settings-client.cjs.map +1 -1
  265. package/dist/node_modules/@openhands/typescript-client/dist/client/settings-client.js +9 -0
  266. package/dist/node_modules/@openhands/typescript-client/dist/client/settings-client.js.map +1 -1
  267. package/dist/package.cjs +1 -1
  268. package/dist/package.cjs.map +1 -1
  269. package/dist/package.js +7 -2
  270. package/dist/package.js.map +1 -1
  271. package/dist/routes/app-settings.cjs +1 -1
  272. package/dist/routes/app-settings.js +5 -5
  273. package/dist/routes/mcp.cjs +1 -1
  274. package/dist/routes/mcp.cjs.map +1 -1
  275. package/dist/routes/mcp.js +73 -82
  276. package/dist/routes/mcp.js.map +1 -1
  277. package/dist/services/telemetry.cjs +1 -1
  278. package/dist/services/telemetry.cjs.map +1 -1
  279. package/dist/services/telemetry.d.ts +8 -0
  280. package/dist/services/telemetry.js +163 -116
  281. package/dist/services/telemetry.js.map +1 -1
  282. package/dist/types/mcp-server.d.ts +5 -0
  283. package/dist/types/settings.d.ts +3 -0
  284. package/dist/utils/mcp-config.cjs +1 -1
  285. package/dist/utils/mcp-config.cjs.map +1 -1
  286. package/dist/utils/mcp-config.d.ts +8 -0
  287. package/dist/utils/mcp-config.js +25 -20
  288. package/dist/utils/mcp-config.js.map +1 -1
  289. package/dist/utils/mcp-installed-servers.cjs +1 -1
  290. package/dist/utils/mcp-installed-servers.cjs.map +1 -1
  291. package/dist/utils/mcp-installed-servers.js +6 -3
  292. package/dist/utils/mcp-installed-servers.js.map +1 -1
  293. package/package.json +7 -2
  294. package/scripts/check-sdk-version-sync.mjs +6 -6
  295. package/scripts/dev-safe.mjs +2 -2
  296. package/scripts/stryker-diff.mjs +137 -0
  297. package/build/assets/active-backend-context-B9942JGX.js +0 -1
  298. package/build/assets/agent-server-conversation-service.api-D7qh9amG.js +0 -41
  299. package/build/assets/agent-settings-BbNLRtoh.js +0 -1
  300. package/build/assets/api-key-entry-screen-B2kVLRDQ.js +0 -1
  301. package/build/assets/app-settings-B92bjTei.js +0 -1
  302. package/build/assets/automation-detail-DoVSHQLs.js +0 -2
  303. package/build/assets/backend-form-modal-C0CIsQvd.js +0 -1
  304. package/build/assets/check-BMOG005H.js +0 -1
  305. package/build/assets/chevron-down-CV1zZP_K.js +0 -1
  306. package/build/assets/circle-check-lvN_jFN5.js +0 -1
  307. package/build/assets/client-source-D8jWKBfE.js +0 -1
  308. package/build/assets/cloud-funnel-analytics-CnCkPgQa.js +0 -1
  309. package/build/assets/conversation-DceG4LFS.js +0 -90
  310. package/build/assets/conversation-Do2Vg7uo.js +0 -1
  311. package/build/assets/conversation-panel-Do2Vg7uo.js +0 -1
  312. package/build/assets/conversation-state-store-BORusMiV.js +0 -1
  313. package/build/assets/extensions-hub-B2WudOET.js +0 -1
  314. package/build/assets/extensions-navigation-CYjIM65d.js +0 -1
  315. package/build/assets/files-tab-LSBijbEi.js +0 -1
  316. package/build/assets/git-provider-icon-DeQUgZVE.js +0 -1
  317. package/build/assets/home-C_R5pEbs.js +0 -1
  318. package/build/assets/index-home-C_R5pEbs.js +0 -1
  319. package/build/assets/install-server-modal-xCf76eim.js +0 -1
  320. package/build/assets/llm-settings-BYo9SN0I.js +0 -1
  321. package/build/assets/llm-settings-BaM0zJg5.js +0 -1
  322. package/build/assets/loader-circle-6zlEYCJw.js +0 -1
  323. package/build/assets/manage-backends-modal-n6PtHOER.js +0 -1
  324. package/build/assets/manifest-e9bbad7b.js +0 -1
  325. package/build/assets/markdown-renderer-Dkmjmx_d.js +0 -8
  326. package/build/assets/mcp-BJUOnO6v.js +0 -9
  327. package/build/assets/onboarding-modal-dYsjXJwx.js +0 -1
  328. package/build/assets/organization-service.api-HsxJhNCf.js +0 -1
  329. package/build/assets/plugins-management-service-DEjBqDoT.js +0 -1
  330. package/build/assets/plus-vIbGD459.js +0 -1
  331. package/build/assets/profiles-service.api-BddMsEhq.js +0 -1
  332. package/build/assets/providers-BxJi3BMO.js +0 -1
  333. package/build/assets/proxy-CN3HaaOW.js +0 -1
  334. package/build/assets/root-D4hpCAq9.js +0 -2
  335. package/build/assets/root-layout-a4-4sfbh.js +0 -3
  336. package/build/assets/schema-field-CZSs0hQP.js +0 -1
  337. package/build/assets/search-sKuYKllf.js +0 -1
  338. package/build/assets/secrets-service-i4CCd-UN.js +0 -1
  339. package/build/assets/settings-SHSt9Rq2.js +0 -1
  340. package/build/assets/settings-service.api-i_HHIqJP.js +0 -1
  341. package/build/assets/telemetry-B-2fXtqV.js +0 -2
  342. package/build/assets/use-activate-agent-profile-CXDcjVt8.js +0 -1
  343. package/build/assets/use-agent-profiles-CliaHofi.js +0 -1
  344. package/build/assets/use-cloud-current-user-id-BzamKpu-.js +0 -1
  345. package/build/assets/use-config-DPEYpfIj.js +0 -1
  346. package/build/assets/use-llm-profiles-Ci3zAVzV.js +0 -1
  347. package/build/assets/use-onboarding-completion-STApsofr.js +0 -1
  348. package/build/assets/use-plugins-marketplace-CzzdrUSK.js +0 -1
  349. package/build/assets/use-settings-BKpkUS4y.js +0 -1
  350. package/build/assets/use-settings-nav-items-BlXge_bf.js +0 -16
  351. package/build/assets/use-skills-BltA9XrV.js +0 -1
  352. package/build/assets/use-tracking-De7qByD4.js +0 -1
  353. package/build/assets/utils-qjs_KuS4.js +0 -1
  354. package/build/assets/x-EjvKGawc.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"active-backend-context.cjs","names":[],"sources":["../../src/contexts/active-backend-context.tsx"],"sourcesContent":["import React from \"react\";\nimport { clearCachedAgentServerInfo } from \"#/api/agent-server-compatibility\";\nimport {\n getActiveSelection,\n getRegisteredBackends,\n getSnapshot,\n NO_BACKEND,\n setActiveSelection,\n setRegisteredBackends,\n subscribeActiveBackend,\n} from \"#/api/backend-registry/active-store\";\nimport { makeDefaultLocalBackend } from \"#/api/backend-registry/default-backend\";\nimport {\n dropBackendHealth,\n resetBackendHealth,\n} from \"#/api/backend-registry/health-store\";\nimport {\n type Backend,\n type BackendSelection,\n type ResolvedActiveBackend,\n} from \"#/api/backend-registry/types\";\nimport { QUERY_KEYS } from \"#/hooks/query/query-keys\";\nimport { queryClient } from \"#/query-client-config\";\n\ninterface ActiveBackendContextValue {\n backends: Backend[];\n active: ResolvedActiveBackend;\n setActive: (backendId: string, orgId?: string | null) => void;\n addBackend: (backend: Omit<Backend, \"id\">) => Backend;\n updateBackend: (id: string, patch: Partial<Omit<Backend, \"id\">>) => void;\n removeBackend: (id: string) => void;\n}\n\nconst ActiveBackendContext =\n React.createContext<ActiveBackendContextValue | null>(null);\n\nfunction generateId(): string {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return crypto.randomUUID();\n }\n return `backend-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport function ActiveBackendProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const snapshot = React.useSyncExternalStore(\n subscribeActiveBackend,\n getSnapshot,\n getSnapshot,\n );\n\n const retryBootstrapProbe = React.useCallback(() => {\n clearCachedAgentServerInfo();\n void queryClient.invalidateQueries({\n queryKey: QUERY_KEYS.WEB_CLIENT_CONFIG,\n });\n }, []);\n\n const setActive = React.useCallback(\n (backendId: string, orgId?: string | null) => {\n const prevBackendId = getActiveSelection()?.backendId ?? null;\n const prevOrgId = getActiveSelection()?.orgId ?? null;\n const nextOrgId = orgId ?? null;\n\n if (backendId === prevBackendId && nextOrgId === prevOrgId) return;\n\n const next: BackendSelection = { backendId, orgId: nextOrgId };\n setActiveSelection(next);\n retryBootstrapProbe();\n\n // No blanket `invalidateQueries()` here. Long-lived queries\n // (`useSettings`, `usePaginatedConversations`,\n // `useGitRepositories`, `useAppInstallations`,\n // `useCloudCurrentUserId`, `useGitUser`, …) include the active\n // backend's `id` and `orgId` in their query keys, so React Query\n // treats a backend/org switch as a brand-new query and fetches\n // automatically — once, with no duplicate waves.\n },\n [retryBootstrapProbe],\n );\n\n // @spec BM-001 — Auto-switch to newly connected backend\n const addBackend = React.useCallback(\n (backend: Omit<Backend, \"id\">): Backend => {\n const next: Backend = { ...backend, id: generateId() };\n const list = [...getRegisteredBackends(), next];\n setRegisteredBackends(list);\n setActiveSelection({ backendId: next.id });\n retryBootstrapProbe();\n return next;\n },\n [retryBootstrapProbe],\n );\n\n const updateBackend = React.useCallback(\n (id: string, patch: Partial<Omit<Backend, \"id\">>) => {\n const prev = getRegisteredBackends().find((b) => b.id === id);\n const activeBeforeUpdate = getActiveSelection()?.backendId ?? null;\n const list = getRegisteredBackends().map((b) =>\n b.id === id ? { ...b, ...patch } : b,\n );\n setRegisteredBackends(list);\n\n // Re-arm health polling when the user edits the fields that\n // actually drive the probe. Cosmetic edits (name) shouldn't\n // re-enable a backend that was disabled for being unreachable.\n const hostChanged =\n patch.host !== undefined &&\n prev !== undefined &&\n patch.host !== prev.host;\n const apiKeyChanged =\n patch.apiKey !== undefined &&\n prev !== undefined &&\n patch.apiKey !== prev.apiKey;\n if (hostChanged || apiKeyChanged) {\n resetBackendHealth(id);\n if (activeBeforeUpdate === id) {\n retryBootstrapProbe();\n }\n }\n },\n [retryBootstrapProbe],\n );\n\n const removeBackend = React.useCallback(\n (id: string) => {\n const list = getRegisteredBackends().filter((b) => b.id !== id);\n setRegisteredBackends(list);\n dropBackendHealth(id);\n retryBootstrapProbe();\n // If the active selection pointed at this backend, the active\n // store falls back to the first remaining local backend (or the\n // env-derived default if no locals exist); consumer hooks re-key\n // by the new active backend identity and refetch automatically.\n },\n [retryBootstrapProbe],\n );\n\n const value = React.useMemo<ActiveBackendContextValue>(\n () => ({\n backends: snapshot.backends,\n active: snapshot.active,\n setActive,\n addBackend,\n updateBackend,\n removeBackend,\n }),\n [snapshot, setActive, addBackend, updateBackend, removeBackend],\n );\n\n return (\n <ActiveBackendContext.Provider value={value}>\n {children}\n </ActiveBackendContext.Provider>\n );\n}\n\nexport function useActiveBackendContext(): ActiveBackendContextValue {\n const ctx = React.useContext(ActiveBackendContext);\n if (!ctx) {\n throw new Error(\n \"useActiveBackendContext must be used inside <ActiveBackendProvider>\",\n );\n }\n return ctx;\n}\n\n/**\n * Read the resolved active backend.\n *\n * Falls back to a synthesized env-derived local backend when called\n * outside an `<ActiveBackendProvider>` (e.g. from a unit test that\n * mounts a narrow component without the full provider stack). That\n * synthesized backend is identical to the seed used on first install.\n *\n * Components that need to mutate state (`setActive`, `addBackend`,\n * etc.) must use `useActiveBackendContext()` directly — that throws if\n * the provider is missing, since mutation requires the live store.\n */\nexport function useActiveBackend(): ResolvedActiveBackend {\n const ctx = React.useContext(ActiveBackendContext);\n if (ctx) return ctx.active;\n return { backend: makeDefaultLocalBackend() ?? NO_BACKEND, orgId: null };\n}\n"],"mappings":"2aAiCA,IAAM,EACJ,EAAA,QAAM,cAAgD,IAAI,EAE5D,SAAS,GAAqB,CAO5B,OALE,OAAO,OAAW,KAClB,OAAO,OAAO,YAAe,WAEtB,OAAO,WAAW,EAEpB,WAAW,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,EAAE,GACxE,CAEA,SAAgB,EAAsB,CACpC,YAGC,CACD,IAAM,EAAW,EAAA,QAAM,qBACrB,EAAA,uBACA,EAAA,YACA,EAAA,WACF,EAEM,EAAsB,EAAA,QAAM,gBAAkB,CAClD,EAAA,2BAA2B,EAC3B,EAAK,YAAY,kBAAkB,CACjC,SAAU,EAAA,WAAW,iBACvB,CAAC,CACH,EAAG,CAAC,CAAC,EAEC,EAAY,EAAA,QAAM,aACrB,EAAmB,IAA0B,CAC5C,IAAM,EAAgB,EAAA,mBAAmB,GAAG,WAAa,KACnD,EAAY,EAAA,mBAAmB,GAAG,OAAS,KAC3C,EAAY,GAAS,KAEvB,IAAc,GAAiB,IAAc,IAGjD,EAAA,mBAAmB,CADc,YAAW,MAAO,CAChC,CAAI,EACvB,EAAoB,EAStB,EACA,CAAC,CAAmB,CACtB,EAGM,EAAa,EAAA,QAAM,YACtB,GAA0C,CACzC,IAAM,EAAgB,CAAE,GAAG,EAAS,GAAI,EAAW,CAAE,EAKrD,OAHA,EAAA,sBAAsB,CADR,GAAG,EAAA,sBAAsB,EAAG,CACpB,CAAI,EAC1B,EAAA,mBAAmB,CAAE,UAAW,EAAK,EAAG,CAAC,EACzC,EAAoB,EACb,CACT,EACA,CAAC,CAAmB,CACtB,EAEM,EAAgB,EAAA,QAAM,aACzB,EAAY,IAAwC,CACnD,IAAM,EAAO,EAAA,sBAAsB,EAAE,KAAM,GAAM,EAAE,KAAO,CAAE,EACtD,EAAqB,EAAA,mBAAmB,GAAG,WAAa,KAI9D,EAAA,sBAHa,EAAA,sBAAsB,EAAE,IAAK,GACxC,EAAE,KAAO,EAAK,CAAE,GAAG,EAAG,GAAG,CAAM,EAAI,CAEf,CAAI,EAK1B,IAAM,EACJ,EAAM,OAAS,IAAA,IACf,IAAS,IAAA,IACT,EAAM,OAAS,EAAK,KAChB,EACJ,EAAM,SAAW,IAAA,IACjB,IAAS,IAAA,IACT,EAAM,SAAW,EAAK,QACpB,GAAe,KACjB,EAAA,mBAAmB,CAAE,EACjB,IAAuB,GACzB,EAAoB,EAG1B,EACA,CAAC,CAAmB,CACtB,EAEM,EAAgB,EAAA,QAAM,YACzB,GAAe,CAEd,EAAA,sBADa,EAAA,sBAAsB,EAAE,OAAQ,GAAM,EAAE,KAAO,CACtC,CAAI,EAC1B,EAAA,kBAAkB,CAAE,EACpB,EAAoB,CAKtB,EACA,CAAC,CAAmB,CACtB,EAEM,EAAQ,EAAA,QAAM,aACX,CACL,SAAU,EAAS,SACnB,OAAQ,EAAS,OACjB,YACA,aACA,gBACA,eACF,GACA,CAAC,EAAU,EAAW,EAAY,EAAe,CAAa,CAChE,EAEA,OACE,EAAA,EAAA,KAAC,EAAqB,SAAtB,CAAsC,QACnC,UAC4B,CAAA,CAEnC,CAEA,SAAgB,GAAqD,CACnE,IAAM,EAAM,EAAA,QAAM,WAAW,CAAoB,EACjD,GAAI,CAAC,EACH,MAAU,MACR,qEACF,EAEF,OAAO,CACT,CAcA,SAAgB,GAA0C,CACxD,IAAM,EAAM,EAAA,QAAM,WAAW,CAAoB,EAEjD,OADI,EAAY,EAAI,OACb,CAAE,QAAS,EAAA,wBAAwB,GAAK,EAAA,WAAY,MAAO,IAAK,CACzE"}
1
+ {"version":3,"file":"active-backend-context.cjs","names":[],"sources":["../../src/contexts/active-backend-context.tsx"],"sourcesContent":["import React from \"react\";\nimport { clearCachedAgentServerInfo } from \"#/api/agent-server-compatibility\";\nimport {\n getActiveSelection,\n getRegisteredBackends,\n getSnapshot,\n NO_BACKEND,\n setActiveSelection,\n setRegisteredBackends,\n subscribeActiveBackend,\n} from \"#/api/backend-registry/active-store\";\nimport { makeDefaultLocalBackend } from \"#/api/backend-registry/default-backend\";\nimport {\n dropBackendHealth,\n resetBackendHealth,\n} from \"#/api/backend-registry/health-store\";\nimport {\n type Backend,\n type BackendSelection,\n type ResolvedActiveBackend,\n} from \"#/api/backend-registry/types\";\nimport { QUERY_KEYS } from \"#/hooks/query/query-keys\";\nimport { queryClient } from \"#/query-client-config\";\nimport {\n setTelemetryCloudContext,\n setTelemetryIdentity,\n} from \"#/services/telemetry\";\n\ntype BackendInput = Omit<Backend, \"id\" | \"connectionRevision\">;\n\ninterface ActiveBackendContextValue {\n backends: Backend[];\n active: ResolvedActiveBackend;\n setActive: (backendId: string, orgId?: string | null) => void;\n addBackend: (backend: BackendInput) => Backend;\n updateBackend: (id: string, patch: Partial<BackendInput>) => void;\n removeBackend: (id: string) => void;\n}\n\nconst ActiveBackendContext =\n React.createContext<ActiveBackendContextValue | null>(null);\n\nfunction generateId(): string {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return crypto.randomUUID();\n }\n return `backend-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction applyTelemetrySelectionBoundary(\n previous: ResolvedActiveBackend,\n next: ResolvedActiveBackend,\n): void {\n const previousWasCloud = previous.backend.kind === \"cloud\";\n const nextIsCloud = next.backend.kind === \"cloud\";\n if (!previousWasCloud && !nextIsCloud) return;\n\n setTelemetryCloudContext(null);\n\n if (\n nextIsCloud &&\n (!previousWasCloud || previous.backend.id !== next.backend.id)\n ) {\n void setTelemetryIdentity(null);\n }\n}\n\nexport function ActiveBackendProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const snapshot = React.useSyncExternalStore(\n subscribeActiveBackend,\n getSnapshot,\n getSnapshot,\n );\n\n const retryBootstrapProbe = React.useCallback(() => {\n clearCachedAgentServerInfo();\n void queryClient.invalidateQueries({\n queryKey: QUERY_KEYS.WEB_CLIENT_CONFIG,\n });\n }, []);\n\n const setActive = React.useCallback(\n (backendId: string, orgId?: string | null) => {\n const currentSnapshot = getSnapshot();\n const prevBackendId = getActiveSelection()?.backendId ?? null;\n const prevOrgId = getActiveSelection()?.orgId ?? null;\n const nextOrgId = orgId ?? null;\n\n if (backendId === prevBackendId && nextOrgId === prevOrgId) return;\n\n const registeredBackends = getRegisteredBackends();\n const selectedBackend = registeredBackends.find(\n (b) => b.id === backendId,\n );\n const nextActive: ResolvedActiveBackend = {\n backend: selectedBackend ?? registeredBackends[0] ?? NO_BACKEND,\n orgId: selectedBackend ? nextOrgId : null,\n };\n applyTelemetrySelectionBoundary(currentSnapshot.active, nextActive);\n\n const next: BackendSelection = { backendId, orgId: nextOrgId };\n setActiveSelection(next);\n retryBootstrapProbe();\n\n // No blanket `invalidateQueries()` here. Long-lived queries\n // (`useSettings`, `usePaginatedConversations`,\n // `useGitRepositories`, `useAppInstallations`,\n // `useCloudCurrentUserId`, `useGitUser`, …) include the active\n // backend's `id` and `orgId` in their query keys, so React Query\n // treats a backend/org switch as a brand-new query and fetches\n // automatically — once, with no duplicate waves.\n },\n [retryBootstrapProbe],\n );\n\n // @spec BM-001 — Auto-switch to newly connected backend\n const addBackend = React.useCallback(\n (backend: BackendInput): Backend => {\n const previousActive = getSnapshot().active;\n const next: Backend = { ...backend, id: generateId() };\n const list = [...getRegisteredBackends(), next];\n applyTelemetrySelectionBoundary(previousActive, {\n backend: next,\n orgId: null,\n });\n setRegisteredBackends(list);\n setActiveSelection({ backendId: next.id });\n retryBootstrapProbe();\n return next;\n },\n [retryBootstrapProbe],\n );\n\n const updateBackend = React.useCallback(\n (id: string, patch: Partial<BackendInput>) => {\n const prev = getRegisteredBackends().find((b) => b.id === id);\n const activeBeforeUpdate = getSnapshot().active.backend.id;\n // Re-arm health polling when the user edits the fields that\n // actually drive the probe. Cosmetic edits (name) shouldn't\n // re-enable a backend that was disabled for being unreachable.\n const hostChanged =\n patch.host !== undefined &&\n prev !== undefined &&\n patch.host !== prev.host;\n const apiKeyChanged =\n patch.apiKey !== undefined &&\n prev !== undefined &&\n patch.apiKey !== prev.apiKey;\n const list = getRegisteredBackends().map((b) =>\n b.id === id\n ? {\n ...b,\n ...patch,\n connectionRevision:\n hostChanged || apiKeyChanged\n ? (b.connectionRevision ?? 0) + 1\n : b.connectionRevision,\n }\n : b,\n );\n setRegisteredBackends(list);\n\n if (hostChanged || apiKeyChanged) {\n resetBackendHealth(id);\n if (activeBeforeUpdate === id) {\n if (prev?.kind === \"cloud\") {\n setTelemetryCloudContext(null);\n void setTelemetryIdentity(null);\n }\n retryBootstrapProbe();\n }\n }\n },\n [retryBootstrapProbe],\n );\n\n const removeBackend = React.useCallback(\n (id: string) => {\n const removed = getRegisteredBackends().find((b) => b.id === id);\n const wasActiveCloud =\n removed?.kind === \"cloud\" &&\n getSnapshot().active.backend.id === removed.id;\n const list = getRegisteredBackends().filter((b) => b.id !== id);\n setRegisteredBackends(list);\n if (wasActiveCloud) {\n setTelemetryCloudContext(null);\n void setTelemetryIdentity(null);\n }\n dropBackendHealth(id);\n retryBootstrapProbe();\n // If the active selection pointed at this backend, the active\n // store falls back to the first remaining local backend (or the\n // env-derived default if no locals exist); consumer hooks re-key\n // by the new active backend identity and refetch automatically.\n },\n [retryBootstrapProbe],\n );\n\n const value = React.useMemo<ActiveBackendContextValue>(\n () => ({\n backends: snapshot.backends,\n active: snapshot.active,\n setActive,\n addBackend,\n updateBackend,\n removeBackend,\n }),\n [snapshot, setActive, addBackend, updateBackend, removeBackend],\n );\n\n return (\n <ActiveBackendContext.Provider value={value}>\n {children}\n </ActiveBackendContext.Provider>\n );\n}\n\nexport function useActiveBackendContext(): ActiveBackendContextValue {\n const ctx = React.useContext(ActiveBackendContext);\n if (!ctx) {\n throw new Error(\n \"useActiveBackendContext must be used inside <ActiveBackendProvider>\",\n );\n }\n return ctx;\n}\n\n/**\n * Read the resolved active backend.\n *\n * Falls back to a synthesized env-derived local backend when called\n * outside an `<ActiveBackendProvider>` (e.g. from a unit test that\n * mounts a narrow component without the full provider stack). That\n * synthesized backend is identical to the seed used on first install.\n *\n * Components that need to mutate state (`setActive`, `addBackend`,\n * etc.) must use `useActiveBackendContext()` directly — that throws if\n * the provider is missing, since mutation requires the live store.\n */\nexport function useActiveBackend(): ResolvedActiveBackend {\n const ctx = React.useContext(ActiveBackendContext);\n if (ctx) return ctx.active;\n return { backend: makeDefaultLocalBackend() ?? NO_BACKEND, orgId: null };\n}\n"],"mappings":"kdAuCA,IAAM,EACJ,EAAA,QAAM,cAAgD,IAAI,EAE5D,SAAS,GAAqB,CAO5B,OALE,OAAO,OAAW,KAClB,OAAO,OAAO,YAAe,WAEtB,OAAO,WAAW,EAEpB,WAAW,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,EAAE,GACxE,CAEA,SAAS,EACP,EACA,EACM,CACN,IAAM,EAAmB,EAAS,QAAQ,OAAS,QAC7C,EAAc,EAAK,QAAQ,OAAS,QACtC,CAAC,GAAoB,CAAC,IAE1B,EAAA,yBAAyB,IAAI,EAG3B,IACC,CAAC,GAAoB,EAAS,QAAQ,KAAO,EAAK,QAAQ,KAE3D,EAAK,qBAAqB,IAAI,EAElC,CAEA,SAAgB,EAAsB,CACpC,YAGC,CACD,IAAM,EAAW,EAAA,QAAM,qBACrB,EAAA,uBACA,EAAA,YACA,EAAA,WACF,EAEM,EAAsB,EAAA,QAAM,gBAAkB,CAClD,EAAA,2BAA2B,EAC3B,EAAK,YAAY,kBAAkB,CACjC,SAAU,EAAA,WAAW,iBACvB,CAAC,CACH,EAAG,CAAC,CAAC,EAEC,EAAY,EAAA,QAAM,aACrB,EAAmB,IAA0B,CAC5C,IAAM,EAAkB,EAAA,YAAY,EAC9B,EAAgB,EAAA,mBAAmB,GAAG,WAAa,KACnD,EAAY,EAAA,mBAAmB,GAAG,OAAS,KAC3C,EAAY,GAAS,KAE3B,GAAI,IAAc,GAAiB,IAAc,EAAW,OAE5D,IAAM,EAAqB,EAAA,sBAAsB,EAC3C,EAAkB,EAAmB,KACxC,GAAM,EAAE,KAAO,CAClB,EACM,EAAoC,CACxC,QAAS,GAAmB,EAAmB,IAAM,EAAA,WACrD,MAAO,EAAkB,EAAY,IACvC,EACA,EAAgC,EAAgB,OAAQ,CAAU,EAGlE,EAAA,mBAAmB,CADc,YAAW,MAAO,CAChC,CAAI,EACvB,EAAoB,CAStB,EACA,CAAC,CAAmB,CACtB,EAGM,EAAa,EAAA,QAAM,YACtB,GAAmC,CAClC,IAAM,EAAiB,EAAA,YAAY,EAAE,OAC/B,EAAgB,CAAE,GAAG,EAAS,GAAI,EAAW,CAAE,EAC/C,EAAO,CAAC,GAAG,EAAA,sBAAsB,EAAG,CAAI,EAQ9C,OAPA,EAAgC,EAAgB,CAC9C,QAAS,EACT,MAAO,IACT,CAAC,EACD,EAAA,sBAAsB,CAAI,EAC1B,EAAA,mBAAmB,CAAE,UAAW,EAAK,EAAG,CAAC,EACzC,EAAoB,EACb,CACT,EACA,CAAC,CAAmB,CACtB,EAEM,EAAgB,EAAA,QAAM,aACzB,EAAY,IAAiC,CAC5C,IAAM,EAAO,EAAA,sBAAsB,EAAE,KAAM,GAAM,EAAE,KAAO,CAAE,EACtD,EAAqB,EAAA,YAAY,EAAE,OAAO,QAAQ,GAIlD,EACJ,EAAM,OAAS,IAAA,IACf,IAAS,IAAA,IACT,EAAM,OAAS,EAAK,KAChB,EACJ,EAAM,SAAW,IAAA,IACjB,IAAS,IAAA,IACT,EAAM,SAAW,EAAK,OAaxB,EAAA,sBAZa,EAAA,sBAAsB,EAAE,IAAK,GACxC,EAAE,KAAO,EACL,CACE,GAAG,EACH,GAAG,EACH,mBACE,GAAe,GACV,EAAE,oBAAsB,GAAK,EAC9B,EAAE,kBACV,EACA,CAEgB,CAAI,GAEtB,GAAe,KACjB,EAAA,mBAAmB,CAAE,EACjB,IAAuB,IACrB,GAAM,OAAS,UACjB,EAAA,yBAAyB,IAAI,EAC7B,EAAK,qBAAqB,IAAI,GAEhC,EAAoB,GAG1B,EACA,CAAC,CAAmB,CACtB,EAEM,EAAgB,EAAA,QAAM,YACzB,GAAe,CACd,IAAM,EAAU,EAAA,sBAAsB,EAAE,KAAM,GAAM,EAAE,KAAO,CAAE,EACzD,EACJ,GAAS,OAAS,SAClB,EAAA,YAAY,EAAE,OAAO,QAAQ,KAAO,EAAQ,GAE9C,EAAA,sBADa,EAAA,sBAAsB,EAAE,OAAQ,GAAM,EAAE,KAAO,CACtC,CAAI,EACtB,IACF,EAAA,yBAAyB,IAAI,EAC7B,EAAK,qBAAqB,IAAI,GAEhC,EAAA,kBAAkB,CAAE,EACpB,EAAoB,CAKtB,EACA,CAAC,CAAmB,CACtB,EAEM,EAAQ,EAAA,QAAM,aACX,CACL,SAAU,EAAS,SACnB,OAAQ,EAAS,OACjB,YACA,aACA,gBACA,eACF,GACA,CAAC,EAAU,EAAW,EAAY,EAAe,CAAa,CAChE,EAEA,OACE,EAAA,EAAA,KAAC,EAAqB,SAAtB,CAAsC,QACnC,UAC4B,CAAA,CAEnC,CAEA,SAAgB,GAAqD,CACnE,IAAM,EAAM,EAAA,QAAM,WAAW,CAAoB,EACjD,GAAI,CAAC,EACH,MAAU,MACR,qEACF,EAEF,OAAO,CACT,CAcA,SAAgB,GAA0C,CACxD,IAAM,EAAM,EAAA,QAAM,WAAW,CAAoB,EAEjD,OADI,EAAY,EAAI,OACb,CAAE,QAAS,EAAA,wBAAwB,GAAK,EAAA,WAAY,MAAO,IAAK,CACzE"}
@@ -1,11 +1,12 @@
1
1
  import React from "react";
2
2
  import { type Backend, type ResolvedActiveBackend } from "#/api/backend-registry/types";
3
+ type BackendInput = Omit<Backend, "id" | "connectionRevision">;
3
4
  interface ActiveBackendContextValue {
4
5
  backends: Backend[];
5
6
  active: ResolvedActiveBackend;
6
7
  setActive: (backendId: string, orgId?: string | null) => void;
7
- addBackend: (backend: Omit<Backend, "id">) => Backend;
8
- updateBackend: (id: string, patch: Partial<Omit<Backend, "id">>) => void;
8
+ addBackend: (backend: BackendInput) => Backend;
9
+ updateBackend: (id: string, patch: Partial<BackendInput>) => void;
9
10
  removeBackend: (id: string) => void;
10
11
  }
11
12
  export declare function ActiveBackendProvider({ children, }: {
@@ -4,70 +4,83 @@ import { NO_BACKEND as r, getActiveSelection as i, getRegisteredBackends as a, g
4
4
  import { clearCachedAgentServerInfo as u } from "../api/agent-server-compatibility.js";
5
5
  import { QUERY_KEYS as d } from "../hooks/query/query-keys.js";
6
6
  import { queryClient as f } from "../query-client-config.js";
7
- import p from "react";
8
- import { jsx as m } from "react/jsx-runtime";
7
+ import { setTelemetryCloudContext as p, setTelemetryIdentity as m } from "../services/telemetry.js";
8
+ import h from "react";
9
+ import { jsx as g } from "react/jsx-runtime";
9
10
  //#region src/contexts/active-backend-context.tsx
10
- var h = p.createContext(null);
11
- function g() {
11
+ var _ = h.createContext(null);
12
+ function v() {
12
13
  return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `backend-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
13
14
  }
14
- function _({ children: n }) {
15
- let r = p.useSyncExternalStore(l, o, o), _ = p.useCallback(() => {
15
+ function y(e, t) {
16
+ let n = e.backend.kind === "cloud", r = t.backend.kind === "cloud";
17
+ !n && !r || (p(null), r && (!n || e.backend.id !== t.backend.id) && m(null));
18
+ }
19
+ function b({ children: n }) {
20
+ let b = h.useSyncExternalStore(l, o, o), x = h.useCallback(() => {
16
21
  u(), f.invalidateQueries({ queryKey: d.WEB_CLIENT_CONFIG });
17
- }, []), v = p.useCallback((e, t) => {
18
- let n = i()?.backendId ?? null, r = i()?.orgId ?? null, a = t ?? null;
19
- e === n && a === r || (s({
22
+ }, []), S = h.useCallback((e, t) => {
23
+ let n = o(), c = i()?.backendId ?? null, l = i()?.orgId ?? null, u = t ?? null;
24
+ if (e === c && u === l) return;
25
+ let d = a(), f = d.find((t) => t.id === e), p = {
26
+ backend: f ?? d[0] ?? r,
27
+ orgId: f ? u : null
28
+ };
29
+ y(n.active, p), s({
20
30
  backendId: e,
21
- orgId: a
22
- }), _());
23
- }, [_]), y = p.useCallback((e) => {
24
- let t = {
31
+ orgId: u
32
+ }), x();
33
+ }, [x]), C = h.useCallback((e) => {
34
+ let t = o().active, n = {
25
35
  ...e,
26
- id: g()
27
- };
28
- return c([...a(), t]), s({ backendId: t.id }), _(), t;
29
- }, [_]), b = p.useCallback((e, n) => {
30
- let r = a().find((t) => t.id === e), o = i()?.backendId ?? null;
36
+ id: v()
37
+ }, r = [...a(), n];
38
+ return y(t, {
39
+ backend: n,
40
+ orgId: null
41
+ }), c(r), s({ backendId: n.id }), x(), n;
42
+ }, [x]), w = h.useCallback((e, n) => {
43
+ let r = a().find((t) => t.id === e), i = o().active.backend.id, s = n.host !== void 0 && r !== void 0 && n.host !== r.host, l = n.apiKey !== void 0 && r !== void 0 && n.apiKey !== r.apiKey;
31
44
  c(a().map((t) => t.id === e ? {
32
45
  ...t,
33
- ...n
34
- } : t));
35
- let s = n.host !== void 0 && r !== void 0 && n.host !== r.host, l = n.apiKey !== void 0 && r !== void 0 && n.apiKey !== r.apiKey;
36
- (s || l) && (t(e), o === e && _());
37
- }, [_]), x = p.useCallback((t) => {
38
- c(a().filter((e) => e.id !== t)), e(t), _();
39
- }, [_]), S = p.useMemo(() => ({
40
- backends: r.backends,
41
- active: r.active,
42
- setActive: v,
43
- addBackend: y,
44
- updateBackend: b,
45
- removeBackend: x
46
+ ...n,
47
+ connectionRevision: s || l ? (t.connectionRevision ?? 0) + 1 : t.connectionRevision
48
+ } : t)), (s || l) && (t(e), i === e && (r?.kind === "cloud" && (p(null), m(null)), x()));
49
+ }, [x]), T = h.useCallback((t) => {
50
+ let n = a().find((e) => e.id === t), r = n?.kind === "cloud" && o().active.backend.id === n.id;
51
+ c(a().filter((e) => e.id !== t)), r && (p(null), m(null)), e(t), x();
52
+ }, [x]), E = h.useMemo(() => ({
53
+ backends: b.backends,
54
+ active: b.active,
55
+ setActive: S,
56
+ addBackend: C,
57
+ updateBackend: w,
58
+ removeBackend: T
46
59
  }), [
47
- r,
48
- v,
49
- y,
50
60
  b,
51
- x
61
+ S,
62
+ C,
63
+ w,
64
+ T
52
65
  ]);
53
- return /* @__PURE__ */ m(h.Provider, {
54
- value: S,
66
+ return /* @__PURE__ */ g(_.Provider, {
67
+ value: E,
55
68
  children: n
56
69
  });
57
70
  }
58
- function v() {
59
- let e = p.useContext(h);
71
+ function x() {
72
+ let e = h.useContext(_);
60
73
  if (!e) throw Error("useActiveBackendContext must be used inside <ActiveBackendProvider>");
61
74
  return e;
62
75
  }
63
- function y() {
64
- let e = p.useContext(h);
76
+ function S() {
77
+ let e = h.useContext(_);
65
78
  return e ? e.active : {
66
79
  backend: n() ?? r,
67
80
  orgId: null
68
81
  };
69
82
  }
70
83
  //#endregion
71
- export { _ as ActiveBackendProvider, y as useActiveBackend, v as useActiveBackendContext };
84
+ export { b as ActiveBackendProvider, S as useActiveBackend, x as useActiveBackendContext };
72
85
 
73
86
  //# sourceMappingURL=active-backend-context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"active-backend-context.js","names":[],"sources":["../../src/contexts/active-backend-context.tsx"],"sourcesContent":["import React from \"react\";\nimport { clearCachedAgentServerInfo } from \"#/api/agent-server-compatibility\";\nimport {\n getActiveSelection,\n getRegisteredBackends,\n getSnapshot,\n NO_BACKEND,\n setActiveSelection,\n setRegisteredBackends,\n subscribeActiveBackend,\n} from \"#/api/backend-registry/active-store\";\nimport { makeDefaultLocalBackend } from \"#/api/backend-registry/default-backend\";\nimport {\n dropBackendHealth,\n resetBackendHealth,\n} from \"#/api/backend-registry/health-store\";\nimport {\n type Backend,\n type BackendSelection,\n type ResolvedActiveBackend,\n} from \"#/api/backend-registry/types\";\nimport { QUERY_KEYS } from \"#/hooks/query/query-keys\";\nimport { queryClient } from \"#/query-client-config\";\n\ninterface ActiveBackendContextValue {\n backends: Backend[];\n active: ResolvedActiveBackend;\n setActive: (backendId: string, orgId?: string | null) => void;\n addBackend: (backend: Omit<Backend, \"id\">) => Backend;\n updateBackend: (id: string, patch: Partial<Omit<Backend, \"id\">>) => void;\n removeBackend: (id: string) => void;\n}\n\nconst ActiveBackendContext =\n React.createContext<ActiveBackendContextValue | null>(null);\n\nfunction generateId(): string {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return crypto.randomUUID();\n }\n return `backend-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport function ActiveBackendProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const snapshot = React.useSyncExternalStore(\n subscribeActiveBackend,\n getSnapshot,\n getSnapshot,\n );\n\n const retryBootstrapProbe = React.useCallback(() => {\n clearCachedAgentServerInfo();\n void queryClient.invalidateQueries({\n queryKey: QUERY_KEYS.WEB_CLIENT_CONFIG,\n });\n }, []);\n\n const setActive = React.useCallback(\n (backendId: string, orgId?: string | null) => {\n const prevBackendId = getActiveSelection()?.backendId ?? null;\n const prevOrgId = getActiveSelection()?.orgId ?? null;\n const nextOrgId = orgId ?? null;\n\n if (backendId === prevBackendId && nextOrgId === prevOrgId) return;\n\n const next: BackendSelection = { backendId, orgId: nextOrgId };\n setActiveSelection(next);\n retryBootstrapProbe();\n\n // No blanket `invalidateQueries()` here. Long-lived queries\n // (`useSettings`, `usePaginatedConversations`,\n // `useGitRepositories`, `useAppInstallations`,\n // `useCloudCurrentUserId`, `useGitUser`, …) include the active\n // backend's `id` and `orgId` in their query keys, so React Query\n // treats a backend/org switch as a brand-new query and fetches\n // automatically — once, with no duplicate waves.\n },\n [retryBootstrapProbe],\n );\n\n // @spec BM-001 — Auto-switch to newly connected backend\n const addBackend = React.useCallback(\n (backend: Omit<Backend, \"id\">): Backend => {\n const next: Backend = { ...backend, id: generateId() };\n const list = [...getRegisteredBackends(), next];\n setRegisteredBackends(list);\n setActiveSelection({ backendId: next.id });\n retryBootstrapProbe();\n return next;\n },\n [retryBootstrapProbe],\n );\n\n const updateBackend = React.useCallback(\n (id: string, patch: Partial<Omit<Backend, \"id\">>) => {\n const prev = getRegisteredBackends().find((b) => b.id === id);\n const activeBeforeUpdate = getActiveSelection()?.backendId ?? null;\n const list = getRegisteredBackends().map((b) =>\n b.id === id ? { ...b, ...patch } : b,\n );\n setRegisteredBackends(list);\n\n // Re-arm health polling when the user edits the fields that\n // actually drive the probe. Cosmetic edits (name) shouldn't\n // re-enable a backend that was disabled for being unreachable.\n const hostChanged =\n patch.host !== undefined &&\n prev !== undefined &&\n patch.host !== prev.host;\n const apiKeyChanged =\n patch.apiKey !== undefined &&\n prev !== undefined &&\n patch.apiKey !== prev.apiKey;\n if (hostChanged || apiKeyChanged) {\n resetBackendHealth(id);\n if (activeBeforeUpdate === id) {\n retryBootstrapProbe();\n }\n }\n },\n [retryBootstrapProbe],\n );\n\n const removeBackend = React.useCallback(\n (id: string) => {\n const list = getRegisteredBackends().filter((b) => b.id !== id);\n setRegisteredBackends(list);\n dropBackendHealth(id);\n retryBootstrapProbe();\n // If the active selection pointed at this backend, the active\n // store falls back to the first remaining local backend (or the\n // env-derived default if no locals exist); consumer hooks re-key\n // by the new active backend identity and refetch automatically.\n },\n [retryBootstrapProbe],\n );\n\n const value = React.useMemo<ActiveBackendContextValue>(\n () => ({\n backends: snapshot.backends,\n active: snapshot.active,\n setActive,\n addBackend,\n updateBackend,\n removeBackend,\n }),\n [snapshot, setActive, addBackend, updateBackend, removeBackend],\n );\n\n return (\n <ActiveBackendContext.Provider value={value}>\n {children}\n </ActiveBackendContext.Provider>\n );\n}\n\nexport function useActiveBackendContext(): ActiveBackendContextValue {\n const ctx = React.useContext(ActiveBackendContext);\n if (!ctx) {\n throw new Error(\n \"useActiveBackendContext must be used inside <ActiveBackendProvider>\",\n );\n }\n return ctx;\n}\n\n/**\n * Read the resolved active backend.\n *\n * Falls back to a synthesized env-derived local backend when called\n * outside an `<ActiveBackendProvider>` (e.g. from a unit test that\n * mounts a narrow component without the full provider stack). That\n * synthesized backend is identical to the seed used on first install.\n *\n * Components that need to mutate state (`setActive`, `addBackend`,\n * etc.) must use `useActiveBackendContext()` directly — that throws if\n * the provider is missing, since mutation requires the live store.\n */\nexport function useActiveBackend(): ResolvedActiveBackend {\n const ctx = React.useContext(ActiveBackendContext);\n if (ctx) return ctx.active;\n return { backend: makeDefaultLocalBackend() ?? NO_BACKEND, orgId: null };\n}\n"],"mappings":";;;;;;;;;AAiCA,IAAM,IACJ,EAAM,cAAgD,IAAI;AAE5D,SAAS,IAAqB;CAO5B,OALE,OAAO,SAAW,OAClB,OAAO,OAAO,cAAe,aAEtB,OAAO,WAAW,IAEpB,WAAW,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AACxE;AAEA,SAAgB,EAAsB,EACpC,eAGC;CACD,IAAM,IAAW,EAAM,qBACrB,GACA,GACA,CACF,GAEM,IAAsB,EAAM,kBAAkB;EAElD,AADA,EAA2B,GAC3B,EAAiB,kBAAkB,EACjC,UAAU,EAAW,kBACvB,CAAC;CACH,GAAG,CAAC,CAAC,GAEC,IAAY,EAAM,aACrB,GAAmB,MAA0B;EAC5C,IAAM,IAAgB,EAAmB,GAAG,aAAa,MACnD,IAAY,EAAmB,GAAG,SAAS,MAC3C,IAAY,KAAS;EAEvB,MAAc,KAAiB,MAAc,MAGjD,EAAmB;GADc;GAAW,OAAO;EAChC,CAAI,GACvB,EAAoB;CAStB,GACA,CAAC,CAAmB,CACtB,GAGM,IAAa,EAAM,aACtB,MAA0C;EACzC,IAAM,IAAgB;GAAE,GAAG;GAAS,IAAI,EAAW;EAAE;EAKrD,OAHA,EAAsB,CADR,GAAG,EAAsB,GAAG,CACpB,CAAI,GAC1B,EAAmB,EAAE,WAAW,EAAK,GAAG,CAAC,GACzC,EAAoB,GACb;CACT,GACA,CAAC,CAAmB,CACtB,GAEM,IAAgB,EAAM,aACzB,GAAY,MAAwC;EACnD,IAAM,IAAO,EAAsB,EAAE,MAAM,MAAM,EAAE,OAAO,CAAE,GACtD,IAAqB,EAAmB,GAAG,aAAa;EAI9D,EAHa,EAAsB,EAAE,KAAK,MACxC,EAAE,OAAO,IAAK;GAAE,GAAG;GAAG,GAAG;EAAM,IAAI,CAEf,CAAI;EAK1B,IAAM,IACJ,EAAM,SAAS,KAAA,KACf,MAAS,KAAA,KACT,EAAM,SAAS,EAAK,MAChB,IACJ,EAAM,WAAW,KAAA,KACjB,MAAS,KAAA,KACT,EAAM,WAAW,EAAK;EACxB,CAAI,KAAe,OACjB,EAAmB,CAAE,GACjB,MAAuB,KACzB,EAAoB;CAG1B,GACA,CAAC,CAAmB,CACtB,GAEM,IAAgB,EAAM,aACzB,MAAe;EAId,AAFA,EADa,EAAsB,EAAE,QAAQ,MAAM,EAAE,OAAO,CACtC,CAAI,GAC1B,EAAkB,CAAE,GACpB,EAAoB;CAKtB,GACA,CAAC,CAAmB,CACtB,GAEM,IAAQ,EAAM,eACX;EACL,UAAU,EAAS;EACnB,QAAQ,EAAS;EACjB;EACA;EACA;EACA;CACF,IACA;EAAC;EAAU;EAAW;EAAY;EAAe;CAAa,CAChE;CAEA,OACE,kBAAC,EAAqB,UAAtB;EAAsC;EACnC;CAC4B,CAAA;AAEnC;AAEA,SAAgB,IAAqD;CACnE,IAAM,IAAM,EAAM,WAAW,CAAoB;CACjD,IAAI,CAAC,GACH,MAAU,MACR,qEACF;CAEF,OAAO;AACT;AAcA,SAAgB,IAA0C;CACxD,IAAM,IAAM,EAAM,WAAW,CAAoB;CAEjD,OADI,IAAY,EAAI,SACb;EAAE,SAAS,EAAwB,KAAK;EAAY,OAAO;CAAK;AACzE"}
1
+ {"version":3,"file":"active-backend-context.js","names":[],"sources":["../../src/contexts/active-backend-context.tsx"],"sourcesContent":["import React from \"react\";\nimport { clearCachedAgentServerInfo } from \"#/api/agent-server-compatibility\";\nimport {\n getActiveSelection,\n getRegisteredBackends,\n getSnapshot,\n NO_BACKEND,\n setActiveSelection,\n setRegisteredBackends,\n subscribeActiveBackend,\n} from \"#/api/backend-registry/active-store\";\nimport { makeDefaultLocalBackend } from \"#/api/backend-registry/default-backend\";\nimport {\n dropBackendHealth,\n resetBackendHealth,\n} from \"#/api/backend-registry/health-store\";\nimport {\n type Backend,\n type BackendSelection,\n type ResolvedActiveBackend,\n} from \"#/api/backend-registry/types\";\nimport { QUERY_KEYS } from \"#/hooks/query/query-keys\";\nimport { queryClient } from \"#/query-client-config\";\nimport {\n setTelemetryCloudContext,\n setTelemetryIdentity,\n} from \"#/services/telemetry\";\n\ntype BackendInput = Omit<Backend, \"id\" | \"connectionRevision\">;\n\ninterface ActiveBackendContextValue {\n backends: Backend[];\n active: ResolvedActiveBackend;\n setActive: (backendId: string, orgId?: string | null) => void;\n addBackend: (backend: BackendInput) => Backend;\n updateBackend: (id: string, patch: Partial<BackendInput>) => void;\n removeBackend: (id: string) => void;\n}\n\nconst ActiveBackendContext =\n React.createContext<ActiveBackendContextValue | null>(null);\n\nfunction generateId(): string {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return crypto.randomUUID();\n }\n return `backend-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction applyTelemetrySelectionBoundary(\n previous: ResolvedActiveBackend,\n next: ResolvedActiveBackend,\n): void {\n const previousWasCloud = previous.backend.kind === \"cloud\";\n const nextIsCloud = next.backend.kind === \"cloud\";\n if (!previousWasCloud && !nextIsCloud) return;\n\n setTelemetryCloudContext(null);\n\n if (\n nextIsCloud &&\n (!previousWasCloud || previous.backend.id !== next.backend.id)\n ) {\n void setTelemetryIdentity(null);\n }\n}\n\nexport function ActiveBackendProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const snapshot = React.useSyncExternalStore(\n subscribeActiveBackend,\n getSnapshot,\n getSnapshot,\n );\n\n const retryBootstrapProbe = React.useCallback(() => {\n clearCachedAgentServerInfo();\n void queryClient.invalidateQueries({\n queryKey: QUERY_KEYS.WEB_CLIENT_CONFIG,\n });\n }, []);\n\n const setActive = React.useCallback(\n (backendId: string, orgId?: string | null) => {\n const currentSnapshot = getSnapshot();\n const prevBackendId = getActiveSelection()?.backendId ?? null;\n const prevOrgId = getActiveSelection()?.orgId ?? null;\n const nextOrgId = orgId ?? null;\n\n if (backendId === prevBackendId && nextOrgId === prevOrgId) return;\n\n const registeredBackends = getRegisteredBackends();\n const selectedBackend = registeredBackends.find(\n (b) => b.id === backendId,\n );\n const nextActive: ResolvedActiveBackend = {\n backend: selectedBackend ?? registeredBackends[0] ?? NO_BACKEND,\n orgId: selectedBackend ? nextOrgId : null,\n };\n applyTelemetrySelectionBoundary(currentSnapshot.active, nextActive);\n\n const next: BackendSelection = { backendId, orgId: nextOrgId };\n setActiveSelection(next);\n retryBootstrapProbe();\n\n // No blanket `invalidateQueries()` here. Long-lived queries\n // (`useSettings`, `usePaginatedConversations`,\n // `useGitRepositories`, `useAppInstallations`,\n // `useCloudCurrentUserId`, `useGitUser`, …) include the active\n // backend's `id` and `orgId` in their query keys, so React Query\n // treats a backend/org switch as a brand-new query and fetches\n // automatically — once, with no duplicate waves.\n },\n [retryBootstrapProbe],\n );\n\n // @spec BM-001 — Auto-switch to newly connected backend\n const addBackend = React.useCallback(\n (backend: BackendInput): Backend => {\n const previousActive = getSnapshot().active;\n const next: Backend = { ...backend, id: generateId() };\n const list = [...getRegisteredBackends(), next];\n applyTelemetrySelectionBoundary(previousActive, {\n backend: next,\n orgId: null,\n });\n setRegisteredBackends(list);\n setActiveSelection({ backendId: next.id });\n retryBootstrapProbe();\n return next;\n },\n [retryBootstrapProbe],\n );\n\n const updateBackend = React.useCallback(\n (id: string, patch: Partial<BackendInput>) => {\n const prev = getRegisteredBackends().find((b) => b.id === id);\n const activeBeforeUpdate = getSnapshot().active.backend.id;\n // Re-arm health polling when the user edits the fields that\n // actually drive the probe. Cosmetic edits (name) shouldn't\n // re-enable a backend that was disabled for being unreachable.\n const hostChanged =\n patch.host !== undefined &&\n prev !== undefined &&\n patch.host !== prev.host;\n const apiKeyChanged =\n patch.apiKey !== undefined &&\n prev !== undefined &&\n patch.apiKey !== prev.apiKey;\n const list = getRegisteredBackends().map((b) =>\n b.id === id\n ? {\n ...b,\n ...patch,\n connectionRevision:\n hostChanged || apiKeyChanged\n ? (b.connectionRevision ?? 0) + 1\n : b.connectionRevision,\n }\n : b,\n );\n setRegisteredBackends(list);\n\n if (hostChanged || apiKeyChanged) {\n resetBackendHealth(id);\n if (activeBeforeUpdate === id) {\n if (prev?.kind === \"cloud\") {\n setTelemetryCloudContext(null);\n void setTelemetryIdentity(null);\n }\n retryBootstrapProbe();\n }\n }\n },\n [retryBootstrapProbe],\n );\n\n const removeBackend = React.useCallback(\n (id: string) => {\n const removed = getRegisteredBackends().find((b) => b.id === id);\n const wasActiveCloud =\n removed?.kind === \"cloud\" &&\n getSnapshot().active.backend.id === removed.id;\n const list = getRegisteredBackends().filter((b) => b.id !== id);\n setRegisteredBackends(list);\n if (wasActiveCloud) {\n setTelemetryCloudContext(null);\n void setTelemetryIdentity(null);\n }\n dropBackendHealth(id);\n retryBootstrapProbe();\n // If the active selection pointed at this backend, the active\n // store falls back to the first remaining local backend (or the\n // env-derived default if no locals exist); consumer hooks re-key\n // by the new active backend identity and refetch automatically.\n },\n [retryBootstrapProbe],\n );\n\n const value = React.useMemo<ActiveBackendContextValue>(\n () => ({\n backends: snapshot.backends,\n active: snapshot.active,\n setActive,\n addBackend,\n updateBackend,\n removeBackend,\n }),\n [snapshot, setActive, addBackend, updateBackend, removeBackend],\n );\n\n return (\n <ActiveBackendContext.Provider value={value}>\n {children}\n </ActiveBackendContext.Provider>\n );\n}\n\nexport function useActiveBackendContext(): ActiveBackendContextValue {\n const ctx = React.useContext(ActiveBackendContext);\n if (!ctx) {\n throw new Error(\n \"useActiveBackendContext must be used inside <ActiveBackendProvider>\",\n );\n }\n return ctx;\n}\n\n/**\n * Read the resolved active backend.\n *\n * Falls back to a synthesized env-derived local backend when called\n * outside an `<ActiveBackendProvider>` (e.g. from a unit test that\n * mounts a narrow component without the full provider stack). That\n * synthesized backend is identical to the seed used on first install.\n *\n * Components that need to mutate state (`setActive`, `addBackend`,\n * etc.) must use `useActiveBackendContext()` directly — that throws if\n * the provider is missing, since mutation requires the live store.\n */\nexport function useActiveBackend(): ResolvedActiveBackend {\n const ctx = React.useContext(ActiveBackendContext);\n if (ctx) return ctx.active;\n return { backend: makeDefaultLocalBackend() ?? NO_BACKEND, orgId: null };\n}\n"],"mappings":";;;;;;;;;;AAuCA,IAAM,IACJ,EAAM,cAAgD,IAAI;AAE5D,SAAS,IAAqB;CAO5B,OALE,OAAO,SAAW,OAClB,OAAO,OAAO,cAAe,aAEtB,OAAO,WAAW,IAEpB,WAAW,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AACxE;AAEA,SAAS,EACP,GACA,GACM;CACN,IAAM,IAAmB,EAAS,QAAQ,SAAS,SAC7C,IAAc,EAAK,QAAQ,SAAS;CACtC,CAAC,KAAoB,CAAC,MAE1B,EAAyB,IAAI,GAG3B,MACC,CAAC,KAAoB,EAAS,QAAQ,OAAO,EAAK,QAAQ,OAE3D,EAA0B,IAAI;AAElC;AAEA,SAAgB,EAAsB,EACpC,eAGC;CACD,IAAM,IAAW,EAAM,qBACrB,GACA,GACA,CACF,GAEM,IAAsB,EAAM,kBAAkB;EAElD,AADA,EAA2B,GAC3B,EAAiB,kBAAkB,EACjC,UAAU,EAAW,kBACvB,CAAC;CACH,GAAG,CAAC,CAAC,GAEC,IAAY,EAAM,aACrB,GAAmB,MAA0B;EAC5C,IAAM,IAAkB,EAAY,GAC9B,IAAgB,EAAmB,GAAG,aAAa,MACnD,IAAY,EAAmB,GAAG,SAAS,MAC3C,IAAY,KAAS;EAE3B,IAAI,MAAc,KAAiB,MAAc,GAAW;EAE5D,IAAM,IAAqB,EAAsB,GAC3C,IAAkB,EAAmB,MACxC,MAAM,EAAE,OAAO,CAClB,GACM,IAAoC;GACxC,SAAS,KAAmB,EAAmB,MAAM;GACrD,OAAO,IAAkB,IAAY;EACvC;EAKA,AAJA,EAAgC,EAAgB,QAAQ,CAAU,GAGlE,EAAmB;GADc;GAAW,OAAO;EAChC,CAAI,GACvB,EAAoB;CAStB,GACA,CAAC,CAAmB,CACtB,GAGM,IAAa,EAAM,aACtB,MAAmC;EAClC,IAAM,IAAiB,EAAY,EAAE,QAC/B,IAAgB;GAAE,GAAG;GAAS,IAAI,EAAW;EAAE,GAC/C,IAAO,CAAC,GAAG,EAAsB,GAAG,CAAI;EAQ9C,OAPA,EAAgC,GAAgB;GAC9C,SAAS;GACT,OAAO;EACT,CAAC,GACD,EAAsB,CAAI,GAC1B,EAAmB,EAAE,WAAW,EAAK,GAAG,CAAC,GACzC,EAAoB,GACb;CACT,GACA,CAAC,CAAmB,CACtB,GAEM,IAAgB,EAAM,aACzB,GAAY,MAAiC;EAC5C,IAAM,IAAO,EAAsB,EAAE,MAAM,MAAM,EAAE,OAAO,CAAE,GACtD,IAAqB,EAAY,EAAE,OAAO,QAAQ,IAIlD,IACJ,EAAM,SAAS,KAAA,KACf,MAAS,KAAA,KACT,EAAM,SAAS,EAAK,MAChB,IACJ,EAAM,WAAW,KAAA,KACjB,MAAS,KAAA,KACT,EAAM,WAAW,EAAK;EAexB,AAFA,EAZa,EAAsB,EAAE,KAAK,MACxC,EAAE,OAAO,IACL;GACE,GAAG;GACH,GAAG;GACH,oBACE,KAAe,KACV,EAAE,sBAAsB,KAAK,IAC9B,EAAE;EACV,IACA,CAEgB,CAAI,IAEtB,KAAe,OACjB,EAAmB,CAAE,GACjB,MAAuB,MACrB,GAAM,SAAS,YACjB,EAAyB,IAAI,GAC7B,EAA0B,IAAI,IAEhC,EAAoB;CAG1B,GACA,CAAC,CAAmB,CACtB,GAEM,IAAgB,EAAM,aACzB,MAAe;EACd,IAAM,IAAU,EAAsB,EAAE,MAAM,MAAM,EAAE,OAAO,CAAE,GACzD,IACJ,GAAS,SAAS,WAClB,EAAY,EAAE,OAAO,QAAQ,OAAO,EAAQ;EAQ9C,AANA,EADa,EAAsB,EAAE,QAAQ,MAAM,EAAE,OAAO,CACtC,CAAI,GACtB,MACF,EAAyB,IAAI,GAC7B,EAA0B,IAAI,IAEhC,EAAkB,CAAE,GACpB,EAAoB;CAKtB,GACA,CAAC,CAAmB,CACtB,GAEM,IAAQ,EAAM,eACX;EACL,UAAU,EAAS;EACnB,QAAQ,EAAS;EACjB;EACA;EACA;EACA;CACF,IACA;EAAC;EAAU;EAAW;EAAY;EAAe;CAAa,CAChE;CAEA,OACE,kBAAC,EAAqB,UAAtB;EAAsC;EACnC;CAC4B,CAAA;AAEnC;AAEA,SAAgB,IAAqD;CACnE,IAAM,IAAM,EAAM,WAAW,CAAoB;CACjD,IAAI,CAAC,GACH,MAAU,MACR,qEACF;CAEF,OAAO;AACT;AAcA,SAAgB,IAA0C;CACxD,IAAM,IAAM,EAAM,WAAW,CAAoB;CAEjD,OADI,IAAY,EAAI,SACb;EAAE,SAAS,EAAwB,KAAK;EAAY,OAAO;CAAK;AACzE"}
Binary file
Binary file
package/dist/favicon.ico CHANGED
Binary file
@@ -1,2 +1,2 @@
1
- require("../../_virtual/_rolldown/runtime.cjs");const e=require("../query/query-keys.cjs"),t=require("../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.cjs"),n=require("../../node_modules/@tanstack/react-query/build/modern/useMutation.cjs"),r=require("../../utils/mcp-config.cjs"),i=require("../../api/settings-service/settings-service.api.cjs"),a=require("../query/use-settings.cjs"),o=require("../../api/mcp-health/mcp-health-store.cjs"),s=require("../../utils/mcp-server-health-key.cjs"),c=require("../../api/mcp-service/mcp-redacted-credentials.cjs");function l(){let l=t.useQueryClient(),{data:u}=a.useSettings();return n.useMutation({mutationFn:async({serverId:e,server:t})=>{let n=r.parseMcpConfig(u?.agent_settings?.mcp_config),a={sse_servers:[...n.sse_servers],stdio_servers:[...n.stdio_servers],shttp_servers:[...n.shttp_servers]},o=await c.substituteRedactedMcpCredentials(t),[s,l]=e.split(`-`),d=parseInt(l,10);s===`sse`?a.sse_servers[d]=r.toMcpSseServer(o):s===`stdio`?a.stdio_servers[d]=r.toMcpStdioServer(o):s===`shttp`&&(a.shttp_servers[d]=r.toMcpShttpServer(o)),await i.default.saveSettings({agent_settings_diff:{mcp_config:r.toSdkMcpConfig(a)}})},onSuccess:(t,n)=>{o.clearMcpServerHealth(s.getMcpServerHealthKey(n.server)),l.invalidateQueries({queryKey:e.SETTINGS_QUERY_KEYS.personal()})}})}exports.useUpdateMcpServer=l;
1
+ require("../../_virtual/_rolldown/runtime.cjs");const e=require("../query/query-keys.cjs"),t=require("../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.cjs"),n=require("../../node_modules/@tanstack/react-query/build/modern/useMutation.cjs"),r=require("../../utils/mcp-config.cjs"),i=require("../../api/settings-service/settings-service.api.cjs"),a=require("../query/use-settings.cjs"),o=require("../../api/mcp-health/mcp-health-store.cjs"),s=require("../../api/mcp-service/mcp-redacted-credentials.cjs"),c=require("../../utils/mcp-server-health-key.cjs");function l(){let l=t.useQueryClient(),{data:u}=a.useSettings();return n.useMutation({mutationFn:async({serverId:e,server:t})=>{let n=r.parseMcpConfig(u?.agent_settings?.mcp_config),a={sse_servers:[...n.sse_servers],stdio_servers:[...n.stdio_servers],shttp_servers:[...n.shttp_servers]},o=await s.substituteRedactedMcpCredentials(t),[c,l]=e.split(`-`),d=parseInt(l,10);c===`sse`?a.sse_servers[d]=r.toMcpSseServer(o):c===`stdio`?a.stdio_servers[d]=r.toMcpStdioServer(o):c===`shttp`&&(a.shttp_servers[d]=r.toMcpShttpServer(o)),await i.default.saveSettings({agent_settings_diff:{mcp_config:r.toSdkMcpConfig(a)}})},onSuccess:(t,n)=>{o.clearMcpServerHealth(c.getMcpServerHealthKey(n.server)),l.invalidateQueries({queryKey:e.SETTINGS_QUERY_KEYS.personal()})}})}exports.useUpdateMcpServer=l;
2
2
  //# sourceMappingURL=use-update-mcp-server.cjs.map
@@ -5,8 +5,8 @@ import { parseMcpConfig as r, toMcpShttpServer as i, toMcpSseServer as a, toMcpS
5
5
  import c from "../../api/settings-service/settings-service.api.js";
6
6
  import { useSettings as l } from "../query/use-settings.js";
7
7
  import { clearMcpServerHealth as u } from "../../api/mcp-health/mcp-health-store.js";
8
- import { getMcpServerHealthKey as d } from "../../utils/mcp-server-health-key.js";
9
- import { substituteRedactedMcpCredentials as f } from "../../api/mcp-service/mcp-redacted-credentials.js";
8
+ import { substituteRedactedMcpCredentials as d } from "../../api/mcp-service/mcp-redacted-credentials.js";
9
+ import { getMcpServerHealthKey as f } from "../../utils/mcp-server-health-key.js";
10
10
  //#region src/hooks/mutation/use-update-mcp-server.ts
11
11
  function p() {
12
12
  let p = t(), { data: m } = l();
@@ -16,11 +16,11 @@ function p() {
16
16
  sse_servers: [...n.sse_servers],
17
17
  stdio_servers: [...n.stdio_servers],
18
18
  shttp_servers: [...n.shttp_servers]
19
- }, u = await f(t), [d, p] = e.split("-"), h = parseInt(p, 10);
20
- d === "sse" ? l.sse_servers[h] = a(u) : d === "stdio" ? l.stdio_servers[h] = o(u) : d === "shttp" && (l.shttp_servers[h] = i(u)), await c.saveSettings({ agent_settings_diff: { mcp_config: s(l) } });
19
+ }, u = await d(t), [f, p] = e.split("-"), h = parseInt(p, 10);
20
+ f === "sse" ? l.sse_servers[h] = a(u) : f === "stdio" ? l.stdio_servers[h] = o(u) : f === "shttp" && (l.shttp_servers[h] = i(u)), await c.saveSettings({ agent_settings_diff: { mcp_config: s(l) } });
21
21
  },
22
22
  onSuccess: (t, n) => {
23
- u(d(n.server)), p.invalidateQueries({ queryKey: e.personal() });
23
+ u(f(n.server)), p.invalidateQueries({ queryKey: e.personal() });
24
24
  }
25
25
  });
26
26
  }
@@ -1,2 +1,2 @@
1
- require("../../_virtual/_rolldown/runtime.cjs");const e=require("../../node_modules/@tanstack/react-query/build/modern/useQueries.cjs"),t=require("../../contexts/active-backend-context.cjs"),n=require("../../api/cloud/organization-service.api.cjs"),r=require("./use-cloud-organizations.cjs");function i(){let{backends:i}=t.useActiveBackendContext(),a=t.useActiveBackend(),o=r.useAllCloudOrganizations(),s=[];for(let e of i)if(e.kind===`cloud`){let t=o[e.id],n=e.id===a.backend.id&&a.orgId?a.orgId:t?.orgs[0]?.id??null;n&&s.push({backendId:e.id,orgIdForMe:n})}let c=e.useQueries({queries:s.map(({backendId:e,orgIdForMe:t})=>{let r=i.find(t=>t.id===e);return{queryKey:[`cloud-current-user`,e,t],queryFn:async()=>r?n.getCloudOrganizationMe(t,r):{orgId:t,userId:``},enabled:!!r,staleTime:1e3*60*5,retry:!1,meta:{disableToast:!0}}})}),l={};return s.forEach((e,t)=>{let n=c[t];l[e.backendId]={isLoading:n.isLoading,userId:n.data?.userId??null}}),l}exports.useCloudCurrentUserId=i;
1
+ require("../../_virtual/_rolldown/runtime.cjs");const e=require("../../node_modules/@tanstack/react-query/build/modern/useQueries.cjs"),t=require("../../contexts/active-backend-context.cjs"),n=require("../../api/cloud/organization-service.api.cjs"),r=require("./use-cloud-organizations.cjs");function i(){let{backends:i}=t.useActiveBackendContext(),a=t.useActiveBackend(),o=r.useAllCloudOrganizations(),s=[];for(let e of i)if(e.kind===`cloud`){let t=o[e.id],n=e.id===a.backend.id&&a.orgId?a.orgId:t?.orgs[0]?.id??null;n&&s.push({backendId:e.id,connectionRevision:e.connectionRevision??0,orgIdForMe:n})}let c=e.useQueries({queries:s.map(({backendId:e,connectionRevision:t,orgIdForMe:r})=>{let a=i.find(t=>t.id===e);return{queryKey:[`cloud-current-user`,e,r,t],queryFn:async()=>a?n.getCloudOrganizationMe(r,a):{orgId:r,userId:``},enabled:!!a,staleTime:1e3*60*5,retry:!1,meta:{disableToast:!0}}})}),l={};return s.forEach((e,t)=>{let n=c[t];l[e.backendId]={isLoading:n.isLoading,userId:n.data?.userId??null}}),l}exports.useCloudCurrentUserId=i;
2
2
  //# sourceMappingURL=use-cloud-current-user-id.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-cloud-current-user-id.cjs","names":[],"sources":["../../../src/hooks/query/use-cloud-current-user-id.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { getCloudOrganizationMe } from \"#/api/cloud/organization-service.api\";\nimport {\n useActiveBackend,\n useActiveBackendContext,\n} from \"#/contexts/active-backend-context\";\nimport { useAllCloudOrganizations } from \"./use-cloud-organizations\";\n\n/**\n * Resolve the current user's `user_id` per cloud backend with one\n * `/api/organizations/{orgId}/me` call per backend (NOT one per org).\n *\n * The cloud contract: `/me` returns `{ org_id, user_id, … }`. `user_id`\n * is identical regardless of which org you ask, so we make a single\n * call per backend.\n *\n * Path-param rule: when `backend.id === active.backend.id` and\n * `active.orgId` is set, the call uses **that** orgId — i.e. `/me`\n * always tracks the currently selected environment for the active\n * backend. For inactive backends (or when no org is selected yet), the\n * first org is used as a sentinel just to obtain `user_id`. This\n * matches the requirement that `/me` reflect the selected org for the\n * active environment, while still supporting the personal-workspace\n * label across non-active backends in the dropdown.\n *\n * The query key includes `active.orgId`, so picking a different org\n * via `setActive` re-keys this query and refetches `/me` with the new\n * active orgId.\n */\nexport function useCloudCurrentUserId(): Record<\n string,\n { isLoading: boolean; userId: string | null }\n> {\n const { backends } = useActiveBackendContext();\n const active = useActiveBackend();\n const cloudOrgs = useAllCloudOrganizations();\n\n const targets: { backendId: string; orgIdForMe: string }[] = [];\n for (const backend of backends) {\n if (backend.kind === \"cloud\") {\n const entry = cloudOrgs[backend.id];\n // Prefer the active org when this backend IS the active one and\n // an org has been selected; otherwise fall back to the first org\n // we know about for that backend.\n const preferredOrgId =\n backend.id === active.backend.id && active.orgId\n ? active.orgId\n : (entry?.orgs[0]?.id ?? null);\n if (preferredOrgId) {\n targets.push({ backendId: backend.id, orgIdForMe: preferredOrgId });\n }\n }\n }\n\n const results = useQueries({\n queries: targets.map(({ backendId, orgIdForMe }) => {\n const backend = backends.find((b) => b.id === backendId);\n return {\n // `orgIdForMe` is included in the query key so re-resolving the\n // active org also re-keys this query → React Query refetches\n // automatically without relying on explicit invalidation.\n queryKey: [\"cloud-current-user\", backendId, orgIdForMe] as const,\n queryFn: async () => {\n if (!backend) return { orgId: orgIdForMe, userId: \"\" };\n return getCloudOrganizationMe(orgIdForMe, backend);\n },\n enabled: !!backend,\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n };\n }),\n });\n\n const out: Record<string, { isLoading: boolean; userId: string | null }> = {};\n targets.forEach((target, index) => {\n const q = results[index];\n out[target.backendId] = {\n isLoading: q.isLoading,\n userId: q.data?.userId ?? null,\n };\n });\n return out;\n}\n"],"mappings":"oSA6BA,SAAgB,GAGd,CACA,GAAM,CAAE,YAAa,EAAA,wBAAwB,EACvC,EAAS,EAAA,iBAAiB,EAC1B,EAAY,EAAA,yBAAyB,EAErC,EAAuD,CAAC,EAC9D,IAAK,IAAM,KAAW,EACpB,GAAI,EAAQ,OAAS,QAAS,CAC5B,IAAM,EAAQ,EAAU,EAAQ,IAI1B,EACJ,EAAQ,KAAO,EAAO,QAAQ,IAAM,EAAO,MACvC,EAAO,MACN,GAAO,KAAK,IAAI,IAAM,KACzB,GACF,EAAQ,KAAK,CAAE,UAAW,EAAQ,GAAI,WAAY,CAAe,CAAC,CAEtE,CAGF,IAAM,EAAU,EAAA,WAAW,CACzB,QAAS,EAAQ,KAAK,CAAE,YAAW,gBAAiB,CAClD,IAAM,EAAU,EAAS,KAAM,GAAM,EAAE,KAAO,CAAS,EACvD,MAAO,CAIL,SAAU,CAAC,qBAAsB,EAAW,CAAU,EACtD,QAAS,SACF,EACE,EAAA,uBAAuB,EAAY,CAAO,EAD5B,CAAE,MAAO,EAAY,OAAQ,EAAG,EAGvD,QAAS,CAAC,CAAC,EACX,UAAW,IAAO,GAAK,EACvB,MAAO,GACP,KAAM,CAAE,aAAc,EAAK,CAC7B,CACF,CAAC,CACH,CAAC,EAEK,EAAqE,CAAC,EAQ5E,OAPA,EAAQ,SAAS,EAAQ,IAAU,CACjC,IAAM,EAAI,EAAQ,GAClB,EAAI,EAAO,WAAa,CACtB,UAAW,EAAE,UACb,OAAQ,EAAE,MAAM,QAAU,IAC5B,CACF,CAAC,EACM,CACT"}
1
+ {"version":3,"file":"use-cloud-current-user-id.cjs","names":[],"sources":["../../../src/hooks/query/use-cloud-current-user-id.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { getCloudOrganizationMe } from \"#/api/cloud/organization-service.api\";\nimport {\n useActiveBackend,\n useActiveBackendContext,\n} from \"#/contexts/active-backend-context\";\nimport { useAllCloudOrganizations } from \"./use-cloud-organizations\";\n\n/**\n * Resolve the current user's `user_id` per cloud backend with one\n * `/api/organizations/{orgId}/me` call per backend (NOT one per org).\n *\n * The cloud contract: `/me` returns `{ org_id, user_id, … }`. `user_id`\n * is identical regardless of which org you ask, so we make a single\n * call per backend.\n *\n * Path-param rule: when `backend.id === active.backend.id` and\n * `active.orgId` is set, the call uses **that** orgId — i.e. `/me`\n * always tracks the currently selected environment for the active\n * backend. For inactive backends (or when no org is selected yet), the\n * first org is used as a sentinel just to obtain `user_id`. This\n * matches the requirement that `/me` reflect the selected org for the\n * active environment, while still supporting the personal-workspace\n * label across non-active backends in the dropdown.\n *\n * The query key includes `active.orgId`, so picking a different org\n * via `setActive` re-keys this query and refetches `/me` with the new\n * active orgId.\n */\nexport function useCloudCurrentUserId(): Record<\n string,\n { isLoading: boolean; userId: string | null }\n> {\n const { backends } = useActiveBackendContext();\n const active = useActiveBackend();\n const cloudOrgs = useAllCloudOrganizations();\n\n const targets: {\n backendId: string;\n connectionRevision: number;\n orgIdForMe: string;\n }[] = [];\n for (const backend of backends) {\n if (backend.kind === \"cloud\") {\n const entry = cloudOrgs[backend.id];\n // Prefer the active org when this backend IS the active one and\n // an org has been selected; otherwise fall back to the first org\n // we know about for that backend.\n const preferredOrgId =\n backend.id === active.backend.id && active.orgId\n ? active.orgId\n : (entry?.orgs[0]?.id ?? null);\n if (preferredOrgId) {\n targets.push({\n backendId: backend.id,\n connectionRevision: backend.connectionRevision ?? 0,\n orgIdForMe: preferredOrgId,\n });\n }\n }\n }\n\n const results = useQueries({\n queries: targets.map(({ backendId, connectionRevision, orgIdForMe }) => {\n const backend = backends.find((b) => b.id === backendId);\n return {\n // `orgIdForMe` is included in the query key so re-resolving the\n // active org also re-keys this query → React Query refetches\n // automatically without relying on explicit invalidation.\n queryKey: [\n \"cloud-current-user\",\n backendId,\n orgIdForMe,\n connectionRevision,\n ] as const,\n queryFn: async () => {\n if (!backend) return { orgId: orgIdForMe, userId: \"\" };\n return getCloudOrganizationMe(orgIdForMe, backend);\n },\n enabled: !!backend,\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n };\n }),\n });\n\n const out: Record<string, { isLoading: boolean; userId: string | null }> = {};\n targets.forEach((target, index) => {\n const q = results[index];\n out[target.backendId] = {\n isLoading: q.isLoading,\n userId: q.data?.userId ?? null,\n };\n });\n return out;\n}\n"],"mappings":"oSA6BA,SAAgB,GAGd,CACA,GAAM,CAAE,YAAa,EAAA,wBAAwB,EACvC,EAAS,EAAA,iBAAiB,EAC1B,EAAY,EAAA,yBAAyB,EAErC,EAIA,CAAC,EACP,IAAK,IAAM,KAAW,EACpB,GAAI,EAAQ,OAAS,QAAS,CAC5B,IAAM,EAAQ,EAAU,EAAQ,IAI1B,EACJ,EAAQ,KAAO,EAAO,QAAQ,IAAM,EAAO,MACvC,EAAO,MACN,GAAO,KAAK,IAAI,IAAM,KACzB,GACF,EAAQ,KAAK,CACX,UAAW,EAAQ,GACnB,mBAAoB,EAAQ,oBAAsB,EAClD,WAAY,CACd,CAAC,CAEL,CAGF,IAAM,EAAU,EAAA,WAAW,CACzB,QAAS,EAAQ,KAAK,CAAE,YAAW,qBAAoB,gBAAiB,CACtE,IAAM,EAAU,EAAS,KAAM,GAAM,EAAE,KAAO,CAAS,EACvD,MAAO,CAIL,SAAU,CACR,qBACA,EACA,EACA,CACF,EACA,QAAS,SACF,EACE,EAAA,uBAAuB,EAAY,CAAO,EAD5B,CAAE,MAAO,EAAY,OAAQ,EAAG,EAGvD,QAAS,CAAC,CAAC,EACX,UAAW,IAAO,GAAK,EACvB,MAAO,GACP,KAAM,CAAE,aAAc,EAAK,CAC7B,CACF,CAAC,CACH,CAAC,EAEK,EAAqE,CAAC,EAQ5E,OAPA,EAAQ,SAAS,EAAQ,IAAU,CACjC,IAAM,EAAI,EAAQ,GAClB,EAAI,EAAO,WAAa,CACtB,UAAW,EAAE,UACb,OAAQ,EAAE,MAAM,QAAU,IAC5B,CACF,CAAC,EACM,CACT"}
@@ -9,22 +9,24 @@ function a() {
9
9
  let t = s[e.id], n = e.id === o.backend.id && o.orgId ? o.orgId : t?.orgs[0]?.id ?? null;
10
10
  n && c.push({
11
11
  backendId: e.id,
12
+ connectionRevision: e.connectionRevision ?? 0,
12
13
  orgIdForMe: n
13
14
  });
14
15
  }
15
- let l = e({ queries: c.map(({ backendId: e, orgIdForMe: t }) => {
16
- let n = a.find((t) => t.id === e);
16
+ let l = e({ queries: c.map(({ backendId: e, connectionRevision: t, orgIdForMe: n }) => {
17
+ let i = a.find((t) => t.id === e);
17
18
  return {
18
19
  queryKey: [
19
20
  "cloud-current-user",
20
21
  e,
22
+ n,
21
23
  t
22
24
  ],
23
- queryFn: async () => n ? r(t, n) : {
24
- orgId: t,
25
+ queryFn: async () => i ? r(n, i) : {
26
+ orgId: n,
25
27
  userId: ""
26
28
  },
27
- enabled: !!n,
29
+ enabled: !!i,
28
30
  staleTime: 1e3 * 60 * 5,
29
31
  retry: !1,
30
32
  meta: { disableToast: !0 }
@@ -1 +1 @@
1
- {"version":3,"file":"use-cloud-current-user-id.js","names":[],"sources":["../../../src/hooks/query/use-cloud-current-user-id.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { getCloudOrganizationMe } from \"#/api/cloud/organization-service.api\";\nimport {\n useActiveBackend,\n useActiveBackendContext,\n} from \"#/contexts/active-backend-context\";\nimport { useAllCloudOrganizations } from \"./use-cloud-organizations\";\n\n/**\n * Resolve the current user's `user_id` per cloud backend with one\n * `/api/organizations/{orgId}/me` call per backend (NOT one per org).\n *\n * The cloud contract: `/me` returns `{ org_id, user_id, … }`. `user_id`\n * is identical regardless of which org you ask, so we make a single\n * call per backend.\n *\n * Path-param rule: when `backend.id === active.backend.id` and\n * `active.orgId` is set, the call uses **that** orgId — i.e. `/me`\n * always tracks the currently selected environment for the active\n * backend. For inactive backends (or when no org is selected yet), the\n * first org is used as a sentinel just to obtain `user_id`. This\n * matches the requirement that `/me` reflect the selected org for the\n * active environment, while still supporting the personal-workspace\n * label across non-active backends in the dropdown.\n *\n * The query key includes `active.orgId`, so picking a different org\n * via `setActive` re-keys this query and refetches `/me` with the new\n * active orgId.\n */\nexport function useCloudCurrentUserId(): Record<\n string,\n { isLoading: boolean; userId: string | null }\n> {\n const { backends } = useActiveBackendContext();\n const active = useActiveBackend();\n const cloudOrgs = useAllCloudOrganizations();\n\n const targets: { backendId: string; orgIdForMe: string }[] = [];\n for (const backend of backends) {\n if (backend.kind === \"cloud\") {\n const entry = cloudOrgs[backend.id];\n // Prefer the active org when this backend IS the active one and\n // an org has been selected; otherwise fall back to the first org\n // we know about for that backend.\n const preferredOrgId =\n backend.id === active.backend.id && active.orgId\n ? active.orgId\n : (entry?.orgs[0]?.id ?? null);\n if (preferredOrgId) {\n targets.push({ backendId: backend.id, orgIdForMe: preferredOrgId });\n }\n }\n }\n\n const results = useQueries({\n queries: targets.map(({ backendId, orgIdForMe }) => {\n const backend = backends.find((b) => b.id === backendId);\n return {\n // `orgIdForMe` is included in the query key so re-resolving the\n // active org also re-keys this query → React Query refetches\n // automatically without relying on explicit invalidation.\n queryKey: [\"cloud-current-user\", backendId, orgIdForMe] as const,\n queryFn: async () => {\n if (!backend) return { orgId: orgIdForMe, userId: \"\" };\n return getCloudOrganizationMe(orgIdForMe, backend);\n },\n enabled: !!backend,\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n };\n }),\n });\n\n const out: Record<string, { isLoading: boolean; userId: string | null }> = {};\n targets.forEach((target, index) => {\n const q = results[index];\n out[target.backendId] = {\n isLoading: q.isLoading,\n userId: q.data?.userId ?? null,\n };\n });\n return out;\n}\n"],"mappings":";;;;;AA6BA,SAAgB,IAGd;CACA,IAAM,EAAE,gBAAa,EAAwB,GACvC,IAAS,EAAiB,GAC1B,IAAY,EAAyB,GAErC,IAAuD,CAAC;CAC9D,KAAK,IAAM,KAAW,GACpB,IAAI,EAAQ,SAAS,SAAS;EAC5B,IAAM,IAAQ,EAAU,EAAQ,KAI1B,IACJ,EAAQ,OAAO,EAAO,QAAQ,MAAM,EAAO,QACvC,EAAO,QACN,GAAO,KAAK,IAAI,MAAM;EAC7B,AAAI,KACF,EAAQ,KAAK;GAAE,WAAW,EAAQ;GAAI,YAAY;EAAe,CAAC;CAEtE;CAGF,IAAM,IAAU,EAAW,EACzB,SAAS,EAAQ,KAAK,EAAE,cAAW,oBAAiB;EAClD,IAAM,IAAU,EAAS,MAAM,MAAM,EAAE,OAAO,CAAS;EACvD,OAAO;GAIL,UAAU;IAAC;IAAsB;IAAW;GAAU;GACtD,SAAS,YACF,IACE,EAAuB,GAAY,CAAO,IAD5B;IAAE,OAAO;IAAY,QAAQ;GAAG;GAGvD,SAAS,CAAC,CAAC;GACX,WAAW,MAAO,KAAK;GACvB,OAAO;GACP,MAAM,EAAE,cAAc,GAAK;EAC7B;CACF,CAAC,EACH,CAAC,GAEK,IAAqE,CAAC;CAQ5E,OAPA,EAAQ,SAAS,GAAQ,MAAU;EACjC,IAAM,IAAI,EAAQ;EAClB,EAAI,EAAO,aAAa;GACtB,WAAW,EAAE;GACb,QAAQ,EAAE,MAAM,UAAU;EAC5B;CACF,CAAC,GACM;AACT"}
1
+ {"version":3,"file":"use-cloud-current-user-id.js","names":[],"sources":["../../../src/hooks/query/use-cloud-current-user-id.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { getCloudOrganizationMe } from \"#/api/cloud/organization-service.api\";\nimport {\n useActiveBackend,\n useActiveBackendContext,\n} from \"#/contexts/active-backend-context\";\nimport { useAllCloudOrganizations } from \"./use-cloud-organizations\";\n\n/**\n * Resolve the current user's `user_id` per cloud backend with one\n * `/api/organizations/{orgId}/me` call per backend (NOT one per org).\n *\n * The cloud contract: `/me` returns `{ org_id, user_id, … }`. `user_id`\n * is identical regardless of which org you ask, so we make a single\n * call per backend.\n *\n * Path-param rule: when `backend.id === active.backend.id` and\n * `active.orgId` is set, the call uses **that** orgId — i.e. `/me`\n * always tracks the currently selected environment for the active\n * backend. For inactive backends (or when no org is selected yet), the\n * first org is used as a sentinel just to obtain `user_id`. This\n * matches the requirement that `/me` reflect the selected org for the\n * active environment, while still supporting the personal-workspace\n * label across non-active backends in the dropdown.\n *\n * The query key includes `active.orgId`, so picking a different org\n * via `setActive` re-keys this query and refetches `/me` with the new\n * active orgId.\n */\nexport function useCloudCurrentUserId(): Record<\n string,\n { isLoading: boolean; userId: string | null }\n> {\n const { backends } = useActiveBackendContext();\n const active = useActiveBackend();\n const cloudOrgs = useAllCloudOrganizations();\n\n const targets: {\n backendId: string;\n connectionRevision: number;\n orgIdForMe: string;\n }[] = [];\n for (const backend of backends) {\n if (backend.kind === \"cloud\") {\n const entry = cloudOrgs[backend.id];\n // Prefer the active org when this backend IS the active one and\n // an org has been selected; otherwise fall back to the first org\n // we know about for that backend.\n const preferredOrgId =\n backend.id === active.backend.id && active.orgId\n ? active.orgId\n : (entry?.orgs[0]?.id ?? null);\n if (preferredOrgId) {\n targets.push({\n backendId: backend.id,\n connectionRevision: backend.connectionRevision ?? 0,\n orgIdForMe: preferredOrgId,\n });\n }\n }\n }\n\n const results = useQueries({\n queries: targets.map(({ backendId, connectionRevision, orgIdForMe }) => {\n const backend = backends.find((b) => b.id === backendId);\n return {\n // `orgIdForMe` is included in the query key so re-resolving the\n // active org also re-keys this query → React Query refetches\n // automatically without relying on explicit invalidation.\n queryKey: [\n \"cloud-current-user\",\n backendId,\n orgIdForMe,\n connectionRevision,\n ] as const,\n queryFn: async () => {\n if (!backend) return { orgId: orgIdForMe, userId: \"\" };\n return getCloudOrganizationMe(orgIdForMe, backend);\n },\n enabled: !!backend,\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n };\n }),\n });\n\n const out: Record<string, { isLoading: boolean; userId: string | null }> = {};\n targets.forEach((target, index) => {\n const q = results[index];\n out[target.backendId] = {\n isLoading: q.isLoading,\n userId: q.data?.userId ?? null,\n };\n });\n return out;\n}\n"],"mappings":";;;;;AA6BA,SAAgB,IAGd;CACA,IAAM,EAAE,gBAAa,EAAwB,GACvC,IAAS,EAAiB,GAC1B,IAAY,EAAyB,GAErC,IAIA,CAAC;CACP,KAAK,IAAM,KAAW,GACpB,IAAI,EAAQ,SAAS,SAAS;EAC5B,IAAM,IAAQ,EAAU,EAAQ,KAI1B,IACJ,EAAQ,OAAO,EAAO,QAAQ,MAAM,EAAO,QACvC,EAAO,QACN,GAAO,KAAK,IAAI,MAAM;EAC7B,AAAI,KACF,EAAQ,KAAK;GACX,WAAW,EAAQ;GACnB,oBAAoB,EAAQ,sBAAsB;GAClD,YAAY;EACd,CAAC;CAEL;CAGF,IAAM,IAAU,EAAW,EACzB,SAAS,EAAQ,KAAK,EAAE,cAAW,uBAAoB,oBAAiB;EACtE,IAAM,IAAU,EAAS,MAAM,MAAM,EAAE,OAAO,CAAS;EACvD,OAAO;GAIL,UAAU;IACR;IACA;IACA;IACA;GACF;GACA,SAAS,YACF,IACE,EAAuB,GAAY,CAAO,IAD5B;IAAE,OAAO;IAAY,QAAQ;GAAG;GAGvD,SAAS,CAAC,CAAC;GACX,WAAW,MAAO,KAAK;GACvB,OAAO;GACP,MAAM,EAAE,cAAc,GAAK;EAC7B;CACF,CAAC,EACH,CAAC,GAEK,IAAqE,CAAC;CAQ5E,OAPA,EAAQ,SAAS,GAAQ,MAAU;EACjC,IAAM,IAAI,EAAQ;EAClB,EAAI,EAAO,aAAa;GACtB,WAAW,EAAE;GACb,QAAQ,EAAE,MAAM,UAAU;EAC5B;CACF,CAAC,GACM;AACT"}
@@ -1,2 +1,2 @@
1
- require("../../_virtual/_rolldown/runtime.cjs");const e=require("../../node_modules/@tanstack/react-query/build/modern/useQueries.cjs"),t=require("../../contexts/active-backend-context.cjs"),n=require("../../api/cloud/organization-service.api.cjs");function r(){let{backends:r}=t.useActiveBackendContext(),i=r.filter(e=>e.kind===`cloud`),a=e.useQueries({queries:i.map(e=>({queryKey:[`cloud-organizations`,e.id],queryFn:async()=>{let t=await n.getCloudOrganizations(e);if(e.authMode===`cookie`)return t;let r=await n.getCurrentCloudApiKey(e);return r.isLegacyKey||r.orgId===null?t:{...t,items:t.items.filter(e=>e.id===r.orgId)}},staleTime:1e3*60*5,retry:!1,meta:{disableToast:!0}}))}),o={};return i.forEach((e,t)=>{let n=a[t];o[e.id]={backend:e,isLoading:n.isLoading,orgs:n.data?.items??[],currentOrgId:n.data?.currentOrgId??null}}),o}exports.useAllCloudOrganizations=r;
1
+ require("../../_virtual/_rolldown/runtime.cjs");const e=require("../../node_modules/@tanstack/react-query/build/modern/useQueries.cjs"),t=require("../../contexts/active-backend-context.cjs"),n=require("../../api/cloud/organization-service.api.cjs");function r(){let{backends:r}=t.useActiveBackendContext(),i=r.filter(e=>e.kind===`cloud`),a=e.useQueries({queries:i.map(e=>({queryKey:[`cloud-organizations`,e.id,e.connectionRevision??0],queryFn:async()=>{let t=await n.getCloudOrganizations(e);if(e.authMode===`cookie`)return t;let r=await n.getCurrentCloudApiKey(e);return r.isLegacyKey||r.orgId===null?t:{...t,items:t.items.filter(e=>e.id===r.orgId)}},staleTime:1e3*60*5,retry:!1,meta:{disableToast:!0}}))}),o={};return i.forEach((e,t)=>{let n=a[t];o[e.id]={backend:e,isLoading:n.isLoading,orgs:n.data?.items??[],currentOrgId:n.data?.currentOrgId??null}}),o}exports.useAllCloudOrganizations=r;
2
2
  //# sourceMappingURL=use-cloud-organizations.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-cloud-organizations.cjs","names":[],"sources":["../../../src/hooks/query/use-cloud-organizations.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport {\n getCloudOrganizations,\n getCurrentCloudApiKey,\n} from \"#/api/cloud/organization-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\n\n/**\n * Fetch organizations for every registered cloud backend in parallel.\n *\n * Used by the BackendSelector to flatten each cloud backend into per-org\n * rows. Each query is keyed by the backend ID so React Query caches\n * responses independently and a switch (which clears the cache) refetches.\n */\nexport function useAllCloudOrganizations() {\n const { backends } = useActiveBackendContext();\n const cloudBackends = backends.filter((b) => b.kind === \"cloud\");\n\n const queries = useQueries({\n queries: cloudBackends.map((backend) => ({\n queryKey: [\"cloud-organizations\", backend.id],\n // Filter the user's full org membership down to the single org the\n // backend's API key is bound to. The cloud enforces one-key-one-org\n // server-side (HTTP 403 otherwise); without this filter the\n // selector would advertise orgs the key cannot use. Legacy keys\n // with no binding fall through unfiltered.\n queryFn: async () => {\n const orgs = await getCloudOrganizations(backend);\n if (backend.authMode === \"cookie\") return orgs;\n\n const key = await getCurrentCloudApiKey(backend);\n if (key.isLegacyKey || key.orgId === null) return orgs;\n return {\n ...orgs,\n items: orgs.items.filter((o) => o.id === key.orgId),\n };\n },\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n // Map backend id -> result to make consumers easy to read.\n const byBackendId: Record<\n string,\n {\n backend: Backend;\n isLoading: boolean;\n orgs: { id: string; name: string; is_personal?: boolean }[];\n currentOrgId: string | null;\n }\n > = {};\n cloudBackends.forEach((backend, index) => {\n const q = queries[index];\n byBackendId[backend.id] = {\n backend,\n isLoading: q.isLoading,\n orgs: q.data?.items ?? [],\n currentOrgId: q.data?.currentOrgId ?? null,\n };\n });\n\n return byBackendId;\n}\n"],"mappings":"yPAeA,SAAgB,GAA2B,CACzC,GAAM,CAAE,YAAa,EAAA,wBAAwB,EACvC,EAAgB,EAAS,OAAQ,GAAM,EAAE,OAAS,OAAO,EAEzD,EAAU,EAAA,WAAW,CACzB,QAAS,EAAc,IAAK,IAAa,CACvC,SAAU,CAAC,sBAAuB,EAAQ,EAAE,EAM5C,QAAS,SAAY,CACnB,IAAM,EAAO,MAAM,EAAA,sBAAsB,CAAO,EAChD,GAAI,EAAQ,WAAa,SAAU,OAAO,EAE1C,IAAM,EAAM,MAAM,EAAA,sBAAsB,CAAO,EAE/C,OADI,EAAI,aAAe,EAAI,QAAU,KAAa,EAC3C,CACL,GAAG,EACH,MAAO,EAAK,MAAM,OAAQ,GAAM,EAAE,KAAO,EAAI,KAAK,CACpD,CACF,EACA,UAAW,IAAO,GAAK,EACvB,MAAO,GACP,KAAM,CAAE,aAAc,EAAK,CAC7B,EAAE,CACJ,CAAC,EAGK,EAQF,CAAC,EAWL,OAVA,EAAc,SAAS,EAAS,IAAU,CACxC,IAAM,EAAI,EAAQ,GAClB,EAAY,EAAQ,IAAM,CACxB,UACA,UAAW,EAAE,UACb,KAAM,EAAE,MAAM,OAAS,CAAC,EACxB,aAAc,EAAE,MAAM,cAAgB,IACxC,CACF,CAAC,EAEM,CACT"}
1
+ {"version":3,"file":"use-cloud-organizations.cjs","names":[],"sources":["../../../src/hooks/query/use-cloud-organizations.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport {\n getCloudOrganizations,\n getCurrentCloudApiKey,\n} from \"#/api/cloud/organization-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\n\n/**\n * Fetch organizations for every registered cloud backend in parallel.\n *\n * Used by the BackendSelector to flatten each cloud backend into per-org\n * rows. Each query is keyed by the backend ID so React Query caches\n * responses independently and a switch (which clears the cache) refetches.\n */\nexport function useAllCloudOrganizations() {\n const { backends } = useActiveBackendContext();\n const cloudBackends = backends.filter((b) => b.kind === \"cloud\");\n\n const queries = useQueries({\n queries: cloudBackends.map((backend) => ({\n queryKey: [\n \"cloud-organizations\",\n backend.id,\n backend.connectionRevision ?? 0,\n ],\n // Filter the user's full org membership down to the single org the\n // backend's API key is bound to. The cloud enforces one-key-one-org\n // server-side (HTTP 403 otherwise); without this filter the\n // selector would advertise orgs the key cannot use. Legacy keys\n // with no binding fall through unfiltered.\n queryFn: async () => {\n const orgs = await getCloudOrganizations(backend);\n if (backend.authMode === \"cookie\") return orgs;\n\n const key = await getCurrentCloudApiKey(backend);\n if (key.isLegacyKey || key.orgId === null) return orgs;\n return {\n ...orgs,\n items: orgs.items.filter((o) => o.id === key.orgId),\n };\n },\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n // Map backend id -> result to make consumers easy to read.\n const byBackendId: Record<\n string,\n {\n backend: Backend;\n isLoading: boolean;\n orgs: { id: string; name: string; is_personal?: boolean }[];\n currentOrgId: string | null;\n }\n > = {};\n cloudBackends.forEach((backend, index) => {\n const q = queries[index];\n byBackendId[backend.id] = {\n backend,\n isLoading: q.isLoading,\n orgs: q.data?.items ?? [],\n currentOrgId: q.data?.currentOrgId ?? null,\n };\n });\n\n return byBackendId;\n}\n"],"mappings":"yPAeA,SAAgB,GAA2B,CACzC,GAAM,CAAE,YAAa,EAAA,wBAAwB,EACvC,EAAgB,EAAS,OAAQ,GAAM,EAAE,OAAS,OAAO,EAEzD,EAAU,EAAA,WAAW,CACzB,QAAS,EAAc,IAAK,IAAa,CACvC,SAAU,CACR,sBACA,EAAQ,GACR,EAAQ,oBAAsB,CAChC,EAMA,QAAS,SAAY,CACnB,IAAM,EAAO,MAAM,EAAA,sBAAsB,CAAO,EAChD,GAAI,EAAQ,WAAa,SAAU,OAAO,EAE1C,IAAM,EAAM,MAAM,EAAA,sBAAsB,CAAO,EAE/C,OADI,EAAI,aAAe,EAAI,QAAU,KAAa,EAC3C,CACL,GAAG,EACH,MAAO,EAAK,MAAM,OAAQ,GAAM,EAAE,KAAO,EAAI,KAAK,CACpD,CACF,EACA,UAAW,IAAO,GAAK,EACvB,MAAO,GACP,KAAM,CAAE,aAAc,EAAK,CAC7B,EAAE,CACJ,CAAC,EAGK,EAQF,CAAC,EAWL,OAVA,EAAc,SAAS,EAAS,IAAU,CACxC,IAAM,EAAI,EAAQ,GAClB,EAAY,EAAQ,IAAM,CACxB,UACA,UAAW,EAAE,UACb,KAAM,EAAE,MAAM,OAAS,CAAC,EACxB,aAAc,EAAE,MAAM,cAAgB,IACxC,CACF,CAAC,EAEM,CACT"}
@@ -4,7 +4,11 @@ import { getCloudOrganizations as n, getCurrentCloudApiKey as r } from "../../ap
4
4
  //#region src/hooks/query/use-cloud-organizations.ts
5
5
  function i() {
6
6
  let { backends: i } = t(), a = i.filter((e) => e.kind === "cloud"), o = e({ queries: a.map((e) => ({
7
- queryKey: ["cloud-organizations", e.id],
7
+ queryKey: [
8
+ "cloud-organizations",
9
+ e.id,
10
+ e.connectionRevision ?? 0
11
+ ],
8
12
  queryFn: async () => {
9
13
  let t = await n(e);
10
14
  if (e.authMode === "cookie") return t;
@@ -1 +1 @@
1
- {"version":3,"file":"use-cloud-organizations.js","names":[],"sources":["../../../src/hooks/query/use-cloud-organizations.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport {\n getCloudOrganizations,\n getCurrentCloudApiKey,\n} from \"#/api/cloud/organization-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\n\n/**\n * Fetch organizations for every registered cloud backend in parallel.\n *\n * Used by the BackendSelector to flatten each cloud backend into per-org\n * rows. Each query is keyed by the backend ID so React Query caches\n * responses independently and a switch (which clears the cache) refetches.\n */\nexport function useAllCloudOrganizations() {\n const { backends } = useActiveBackendContext();\n const cloudBackends = backends.filter((b) => b.kind === \"cloud\");\n\n const queries = useQueries({\n queries: cloudBackends.map((backend) => ({\n queryKey: [\"cloud-organizations\", backend.id],\n // Filter the user's full org membership down to the single org the\n // backend's API key is bound to. The cloud enforces one-key-one-org\n // server-side (HTTP 403 otherwise); without this filter the\n // selector would advertise orgs the key cannot use. Legacy keys\n // with no binding fall through unfiltered.\n queryFn: async () => {\n const orgs = await getCloudOrganizations(backend);\n if (backend.authMode === \"cookie\") return orgs;\n\n const key = await getCurrentCloudApiKey(backend);\n if (key.isLegacyKey || key.orgId === null) return orgs;\n return {\n ...orgs,\n items: orgs.items.filter((o) => o.id === key.orgId),\n };\n },\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n // Map backend id -> result to make consumers easy to read.\n const byBackendId: Record<\n string,\n {\n backend: Backend;\n isLoading: boolean;\n orgs: { id: string; name: string; is_personal?: boolean }[];\n currentOrgId: string | null;\n }\n > = {};\n cloudBackends.forEach((backend, index) => {\n const q = queries[index];\n byBackendId[backend.id] = {\n backend,\n isLoading: q.isLoading,\n orgs: q.data?.items ?? [],\n currentOrgId: q.data?.currentOrgId ?? null,\n };\n });\n\n return byBackendId;\n}\n"],"mappings":";;;;AAeA,SAAgB,IAA2B;CACzC,IAAM,EAAE,gBAAa,EAAwB,GACvC,IAAgB,EAAS,QAAQ,MAAM,EAAE,SAAS,OAAO,GAEzD,IAAU,EAAW,EACzB,SAAS,EAAc,KAAK,OAAa;EACvC,UAAU,CAAC,uBAAuB,EAAQ,EAAE;EAM5C,SAAS,YAAY;GACnB,IAAM,IAAO,MAAM,EAAsB,CAAO;GAChD,IAAI,EAAQ,aAAa,UAAU,OAAO;GAE1C,IAAM,IAAM,MAAM,EAAsB,CAAO;GAE/C,OADI,EAAI,eAAe,EAAI,UAAU,OAAa,IAC3C;IACL,GAAG;IACH,OAAO,EAAK,MAAM,QAAQ,MAAM,EAAE,OAAO,EAAI,KAAK;GACpD;EACF;EACA,WAAW,MAAO,KAAK;EACvB,OAAO;EACP,MAAM,EAAE,cAAc,GAAK;CAC7B,EAAE,EACJ,CAAC,GAGK,IAQF,CAAC;CAWL,OAVA,EAAc,SAAS,GAAS,MAAU;EACxC,IAAM,IAAI,EAAQ;EAClB,EAAY,EAAQ,MAAM;GACxB;GACA,WAAW,EAAE;GACb,MAAM,EAAE,MAAM,SAAS,CAAC;GACxB,cAAc,EAAE,MAAM,gBAAgB;EACxC;CACF,CAAC,GAEM;AACT"}
1
+ {"version":3,"file":"use-cloud-organizations.js","names":[],"sources":["../../../src/hooks/query/use-cloud-organizations.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport {\n getCloudOrganizations,\n getCurrentCloudApiKey,\n} from \"#/api/cloud/organization-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\n\n/**\n * Fetch organizations for every registered cloud backend in parallel.\n *\n * Used by the BackendSelector to flatten each cloud backend into per-org\n * rows. Each query is keyed by the backend ID so React Query caches\n * responses independently and a switch (which clears the cache) refetches.\n */\nexport function useAllCloudOrganizations() {\n const { backends } = useActiveBackendContext();\n const cloudBackends = backends.filter((b) => b.kind === \"cloud\");\n\n const queries = useQueries({\n queries: cloudBackends.map((backend) => ({\n queryKey: [\n \"cloud-organizations\",\n backend.id,\n backend.connectionRevision ?? 0,\n ],\n // Filter the user's full org membership down to the single org the\n // backend's API key is bound to. The cloud enforces one-key-one-org\n // server-side (HTTP 403 otherwise); without this filter the\n // selector would advertise orgs the key cannot use. Legacy keys\n // with no binding fall through unfiltered.\n queryFn: async () => {\n const orgs = await getCloudOrganizations(backend);\n if (backend.authMode === \"cookie\") return orgs;\n\n const key = await getCurrentCloudApiKey(backend);\n if (key.isLegacyKey || key.orgId === null) return orgs;\n return {\n ...orgs,\n items: orgs.items.filter((o) => o.id === key.orgId),\n };\n },\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n // Map backend id -> result to make consumers easy to read.\n const byBackendId: Record<\n string,\n {\n backend: Backend;\n isLoading: boolean;\n orgs: { id: string; name: string; is_personal?: boolean }[];\n currentOrgId: string | null;\n }\n > = {};\n cloudBackends.forEach((backend, index) => {\n const q = queries[index];\n byBackendId[backend.id] = {\n backend,\n isLoading: q.isLoading,\n orgs: q.data?.items ?? [],\n currentOrgId: q.data?.currentOrgId ?? null,\n };\n });\n\n return byBackendId;\n}\n"],"mappings":";;;;AAeA,SAAgB,IAA2B;CACzC,IAAM,EAAE,gBAAa,EAAwB,GACvC,IAAgB,EAAS,QAAQ,MAAM,EAAE,SAAS,OAAO,GAEzD,IAAU,EAAW,EACzB,SAAS,EAAc,KAAK,OAAa;EACvC,UAAU;GACR;GACA,EAAQ;GACR,EAAQ,sBAAsB;EAChC;EAMA,SAAS,YAAY;GACnB,IAAM,IAAO,MAAM,EAAsB,CAAO;GAChD,IAAI,EAAQ,aAAa,UAAU,OAAO;GAE1C,IAAM,IAAM,MAAM,EAAsB,CAAO;GAE/C,OADI,EAAI,eAAe,EAAI,UAAU,OAAa,IAC3C;IACL,GAAG;IACH,OAAO,EAAK,MAAM,QAAQ,MAAM,EAAE,OAAO,EAAI,KAAK;GACpD;EACF;EACA,WAAW,MAAO,KAAK;EACvB,OAAO;EACP,MAAM,EAAE,cAAc,GAAK;CAC7B,EAAE,EACJ,CAAC,GAGK,IAQF,CAAC;CAWL,OAVA,EAAc,SAAS,GAAS,MAAU;EACxC,IAAM,IAAI,EAAQ;EAClB,EAAY,EAAQ,MAAM;GACxB;GACA,WAAW,EAAE;GACb,MAAM,EAAE,MAAM,SAAS,CAAC;GACxB,cAAc,EAAE,MAAM,gBAAgB;EACxC;CACF,CAAC,GAEM;AACT"}
@@ -1,2 +1,2 @@
1
- require("../_virtual/_rolldown/runtime.cjs");const e=require("../node_modules/@tanstack/react-query/build/modern/useQuery.cjs"),t=require("../contexts/active-backend-context.cjs"),n=require("../api/cloud/organization-service.api.cjs");var r=`edit_org_settings`;function i(){let{backend:i,orgId:a}=t.useActiveBackend(),o=i.kind===`cloud`,{data:s}=e.useQuery({queryKey:[`cloud-current-user`,i.id,a],queryFn:()=>n.getCloudOrganizationMe(a,i),enabled:o&&!!a,staleTime:1e3*60*5,retry:!1,meta:{disableToast:!0}});return o?s?.permissions?s.permissions.includes(r):s?.role===`owner`||s?.role===`admin`:!0}exports.useCanManageOrgProfiles=i;
1
+ require("../_virtual/_rolldown/runtime.cjs");const e=require("../node_modules/@tanstack/react-query/build/modern/useQuery.cjs"),t=require("../contexts/active-backend-context.cjs"),n=require("../api/cloud/organization-service.api.cjs");var r=`edit_org_settings`;function i(){let{backend:i,orgId:a}=t.useActiveBackend(),o=i.kind===`cloud`,{data:s}=e.useQuery({queryKey:[`cloud-current-user`,i.id,a,i.connectionRevision??0],queryFn:()=>n.getCloudOrganizationMe(a,i),enabled:o&&!!a,staleTime:1e3*60*5,retry:!1,meta:{disableToast:!0}});return o?s?.permissions?s.permissions.includes(r):s?.role===`owner`||s?.role===`admin`:!0}exports.useCanManageOrgProfiles=i;
2
2
  //# sourceMappingURL=use-can-manage-org-profiles.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-can-manage-org-profiles.cjs","names":[],"sources":["../../src/hooks/use-can-manage-org-profiles.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport { getCloudOrganizationMe } from \"#/api/cloud/organization-service.api\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\n\n/**\n * Server-defined permission (mirrors the app-server's\n * `authorization.Permission.EDIT_ORG_SETTINGS`) that gates org-scoped profile\n * mutations (both LLM profiles and agent profiles).\n */\nconst EDIT_ORG_SETTINGS = \"edit_org_settings\";\n\n/**\n * Whether the current user may MUTATE org-scoped profiles — LLM profiles and\n * agent profiles alike — on the active backend: create, edit, rename, delete,\n * duplicate, or activate/switch.\n *\n * - Local agent-server (OSS): always `true`; the user owns their own profiles.\n * - Cloud: profiles are org-scoped. The app-server grants every mutating\n * profile action (save/delete/rename/activate) only to the `owner`/`admin`\n * roles via the `edit_org_settings` permission; a `member` is view-only. We\n * read the caller's server-defined permissions from\n * `GET /api/organizations/{orgId}/me` — the same call `useCloudCurrentUserId`\n * makes, reusing its query key so no extra request is issued — and fall back\n * to a role check when an older app-server doesn't return `permissions`.\n *\n * Returns `false` while the role/permissions are still loading or unknown on\n * cloud, so mutating controls never flash for a member before they resolve.\n */\nexport function useCanManageOrgProfiles(): boolean {\n const { backend, orgId } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // `backend` is identified by `backend.id`, which is already in the key; we\n // keep the key byte-identical to useCloudCurrentUserId so React Query shares\n // the cached /me result instead of firing a second request.\n // eslint-disable-next-line @tanstack/query/exhaustive-deps\n const { data } = useQuery({\n queryKey: [\"cloud-current-user\", backend.id, orgId],\n queryFn: () => getCloudOrganizationMe(orgId!, backend),\n enabled: isCloud && !!orgId,\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n });\n\n if (!isCloud) return true;\n // Prefer the server-defined permission set; fall back to a role check for\n // older app-servers whose /me doesn't return `permissions` yet, so this\n // keeps working against either backend version.\n if (data?.permissions) {\n return data.permissions.includes(EDIT_ORG_SETTINGS);\n }\n return data?.role === \"owner\" || data?.role === \"admin\";\n}\n"],"mappings":"2OASA,IAAM,EAAoB,oBAmB1B,SAAgB,GAAmC,CACjD,GAAM,CAAE,UAAS,SAAU,EAAA,iBAAiB,EACtC,EAAU,EAAQ,OAAS,QAM3B,CAAE,QAAS,EAAA,SAAS,CACxB,SAAU,CAAC,qBAAsB,EAAQ,GAAI,CAAK,EAClD,YAAe,EAAA,uBAAuB,EAAQ,CAAO,EACrD,QAAS,GAAW,CAAC,CAAC,EACtB,UAAW,IAAO,GAAK,EACvB,MAAO,GACP,KAAM,CAAE,aAAc,EAAK,CAC7B,CAAC,EASD,OAPK,EAID,GAAM,YACD,EAAK,YAAY,SAAS,CAAiB,EAE7C,GAAM,OAAS,SAAW,GAAM,OAAS,QAP3B,EAQvB"}
1
+ {"version":3,"file":"use-can-manage-org-profiles.cjs","names":[],"sources":["../../src/hooks/use-can-manage-org-profiles.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport { getCloudOrganizationMe } from \"#/api/cloud/organization-service.api\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\n\n/**\n * Server-defined permission (mirrors the app-server's\n * `authorization.Permission.EDIT_ORG_SETTINGS`) that gates org-scoped profile\n * mutations (both LLM profiles and agent profiles).\n */\nconst EDIT_ORG_SETTINGS = \"edit_org_settings\";\n\n/**\n * Whether the current user may MUTATE org-scoped profiles — LLM profiles and\n * agent profiles alike — on the active backend: create, edit, rename, delete,\n * duplicate, or activate/switch.\n *\n * - Local agent-server (OSS): always `true`; the user owns their own profiles.\n * - Cloud: profiles are org-scoped. The app-server grants every mutating\n * profile action (save/delete/rename/activate) only to the `owner`/`admin`\n * roles via the `edit_org_settings` permission; a `member` is view-only. We\n * read the caller's server-defined permissions from\n * `GET /api/organizations/{orgId}/me` — the same call `useCloudCurrentUserId`\n * makes, reusing its query key so no extra request is issued — and fall back\n * to a role check when an older app-server doesn't return `permissions`.\n *\n * Returns `false` while the role/permissions are still loading or unknown on\n * cloud, so mutating controls never flash for a member before they resolve.\n */\nexport function useCanManageOrgProfiles(): boolean {\n const { backend, orgId } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Keep the key byte-identical to useCloudCurrentUserId so React Query shares\n // the cached /me result, including its connection-credential revision.\n // eslint-disable-next-line @tanstack/query/exhaustive-deps\n const { data } = useQuery({\n queryKey: [\n \"cloud-current-user\",\n backend.id,\n orgId,\n backend.connectionRevision ?? 0,\n ],\n queryFn: () => getCloudOrganizationMe(orgId!, backend),\n enabled: isCloud && !!orgId,\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n });\n\n if (!isCloud) return true;\n // Prefer the server-defined permission set; fall back to a role check for\n // older app-servers whose /me doesn't return `permissions` yet, so this\n // keeps working against either backend version.\n if (data?.permissions) {\n return data.permissions.includes(EDIT_ORG_SETTINGS);\n }\n return data?.role === \"owner\" || data?.role === \"admin\";\n}\n"],"mappings":"2OASA,IAAM,EAAoB,oBAmB1B,SAAgB,GAAmC,CACjD,GAAM,CAAE,UAAS,SAAU,EAAA,iBAAiB,EACtC,EAAU,EAAQ,OAAS,QAK3B,CAAE,QAAS,EAAA,SAAS,CACxB,SAAU,CACR,qBACA,EAAQ,GACR,EACA,EAAQ,oBAAsB,CAChC,EACA,YAAe,EAAA,uBAAuB,EAAQ,CAAO,EACrD,QAAS,GAAW,CAAC,CAAC,EACtB,UAAW,IAAO,GAAK,EACvB,MAAO,GACP,KAAM,CAAE,aAAc,EAAK,CAC7B,CAAC,EASD,OAPK,EAID,GAAM,YACD,EAAK,YAAY,SAAS,CAAiB,EAE7C,GAAM,OAAS,SAAW,GAAM,OAAS,QAP3B,EAQvB"}
@@ -8,7 +8,8 @@ function i() {
8
8
  queryKey: [
9
9
  "cloud-current-user",
10
10
  i.id,
11
- a
11
+ a,
12
+ i.connectionRevision ?? 0
12
13
  ],
13
14
  queryFn: () => n(a, i),
14
15
  enabled: o && !!a,
@@ -1 +1 @@
1
- {"version":3,"file":"use-can-manage-org-profiles.js","names":[],"sources":["../../src/hooks/use-can-manage-org-profiles.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport { getCloudOrganizationMe } from \"#/api/cloud/organization-service.api\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\n\n/**\n * Server-defined permission (mirrors the app-server's\n * `authorization.Permission.EDIT_ORG_SETTINGS`) that gates org-scoped profile\n * mutations (both LLM profiles and agent profiles).\n */\nconst EDIT_ORG_SETTINGS = \"edit_org_settings\";\n\n/**\n * Whether the current user may MUTATE org-scoped profiles — LLM profiles and\n * agent profiles alike — on the active backend: create, edit, rename, delete,\n * duplicate, or activate/switch.\n *\n * - Local agent-server (OSS): always `true`; the user owns their own profiles.\n * - Cloud: profiles are org-scoped. The app-server grants every mutating\n * profile action (save/delete/rename/activate) only to the `owner`/`admin`\n * roles via the `edit_org_settings` permission; a `member` is view-only. We\n * read the caller's server-defined permissions from\n * `GET /api/organizations/{orgId}/me` — the same call `useCloudCurrentUserId`\n * makes, reusing its query key so no extra request is issued — and fall back\n * to a role check when an older app-server doesn't return `permissions`.\n *\n * Returns `false` while the role/permissions are still loading or unknown on\n * cloud, so mutating controls never flash for a member before they resolve.\n */\nexport function useCanManageOrgProfiles(): boolean {\n const { backend, orgId } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // `backend` is identified by `backend.id`, which is already in the key; we\n // keep the key byte-identical to useCloudCurrentUserId so React Query shares\n // the cached /me result instead of firing a second request.\n // eslint-disable-next-line @tanstack/query/exhaustive-deps\n const { data } = useQuery({\n queryKey: [\"cloud-current-user\", backend.id, orgId],\n queryFn: () => getCloudOrganizationMe(orgId!, backend),\n enabled: isCloud && !!orgId,\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n });\n\n if (!isCloud) return true;\n // Prefer the server-defined permission set; fall back to a role check for\n // older app-servers whose /me doesn't return `permissions` yet, so this\n // keeps working against either backend version.\n if (data?.permissions) {\n return data.permissions.includes(EDIT_ORG_SETTINGS);\n }\n return data?.role === \"owner\" || data?.role === \"admin\";\n}\n"],"mappings":";;;;AASA,IAAM,IAAoB;AAmB1B,SAAgB,IAAmC;CACjD,IAAM,EAAE,YAAS,aAAU,EAAiB,GACtC,IAAU,EAAQ,SAAS,SAM3B,EAAE,YAAS,EAAS;EACxB,UAAU;GAAC;GAAsB,EAAQ;GAAI;EAAK;EAClD,eAAe,EAAuB,GAAQ,CAAO;EACrD,SAAS,KAAW,CAAC,CAAC;EACtB,WAAW,MAAO,KAAK;EACvB,OAAO;EACP,MAAM,EAAE,cAAc,GAAK;CAC7B,CAAC;CASD,OAPK,IAID,GAAM,cACD,EAAK,YAAY,SAAS,CAAiB,IAE7C,GAAM,SAAS,WAAW,GAAM,SAAS,UAP3B;AAQvB"}
1
+ {"version":3,"file":"use-can-manage-org-profiles.js","names":[],"sources":["../../src/hooks/use-can-manage-org-profiles.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport { getCloudOrganizationMe } from \"#/api/cloud/organization-service.api\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\n\n/**\n * Server-defined permission (mirrors the app-server's\n * `authorization.Permission.EDIT_ORG_SETTINGS`) that gates org-scoped profile\n * mutations (both LLM profiles and agent profiles).\n */\nconst EDIT_ORG_SETTINGS = \"edit_org_settings\";\n\n/**\n * Whether the current user may MUTATE org-scoped profiles — LLM profiles and\n * agent profiles alike — on the active backend: create, edit, rename, delete,\n * duplicate, or activate/switch.\n *\n * - Local agent-server (OSS): always `true`; the user owns their own profiles.\n * - Cloud: profiles are org-scoped. The app-server grants every mutating\n * profile action (save/delete/rename/activate) only to the `owner`/`admin`\n * roles via the `edit_org_settings` permission; a `member` is view-only. We\n * read the caller's server-defined permissions from\n * `GET /api/organizations/{orgId}/me` — the same call `useCloudCurrentUserId`\n * makes, reusing its query key so no extra request is issued — and fall back\n * to a role check when an older app-server doesn't return `permissions`.\n *\n * Returns `false` while the role/permissions are still loading or unknown on\n * cloud, so mutating controls never flash for a member before they resolve.\n */\nexport function useCanManageOrgProfiles(): boolean {\n const { backend, orgId } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Keep the key byte-identical to useCloudCurrentUserId so React Query shares\n // the cached /me result, including its connection-credential revision.\n // eslint-disable-next-line @tanstack/query/exhaustive-deps\n const { data } = useQuery({\n queryKey: [\n \"cloud-current-user\",\n backend.id,\n orgId,\n backend.connectionRevision ?? 0,\n ],\n queryFn: () => getCloudOrganizationMe(orgId!, backend),\n enabled: isCloud && !!orgId,\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n });\n\n if (!isCloud) return true;\n // Prefer the server-defined permission set; fall back to a role check for\n // older app-servers whose /me doesn't return `permissions` yet, so this\n // keeps working against either backend version.\n if (data?.permissions) {\n return data.permissions.includes(EDIT_ORG_SETTINGS);\n }\n return data?.role === \"owner\" || data?.role === \"admin\";\n}\n"],"mappings":";;;;AASA,IAAM,IAAoB;AAmB1B,SAAgB,IAAmC;CACjD,IAAM,EAAE,YAAS,aAAU,EAAiB,GACtC,IAAU,EAAQ,SAAS,SAK3B,EAAE,YAAS,EAAS;EACxB,UAAU;GACR;GACA,EAAQ;GACR;GACA,EAAQ,sBAAsB;EAChC;EACA,eAAe,EAAuB,GAAQ,CAAO;EACrD,SAAS,KAAW,CAAC,CAAC;EACtB,WAAW,MAAO,KAAK;EACvB,OAAO;EACP,MAAM,EAAE,cAAc,GAAK;CAC7B,CAAC;CASD,OAPK,IAID,GAAM,cACD,EAAK,YAAY,SAAS,CAAiB,IAE7C,GAAM,SAAS,WAAW,GAAM,SAAS,UAP3B;AAQvB"}
@@ -1,2 +1,2 @@
1
- const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../api/agent-server-compatibility.cjs"),n=require("../contexts/active-backend-context.cjs"),r=require("../services/telemetry-context.cjs"),i=require("../services/telemetry.cjs"),a=require("./query/use-automation-sdk-version.cjs");let o=require("react");o=e.__toESM(o,1);var s=()=>{let{backend:e}=n.useActiveBackend(),s=a.useAutomationSdkVersion(),c=o.default.useCallback(()=>({backendKind:e.kind,agentServerVersion:e.kind===`local`?t.getCachedAgentServerVersion(e.host):null,automationSdkVersion:s??null}),[s,e.host,e.kind]);o.default.useEffect(()=>{i.setTelemetryBackendContext(c())},[c]);let l={current_url:window.location.href},u=(e,t={})=>{i.setTelemetryBackendContext(c()),i.trackEvent(e,{...l,...t})};return{trackLoginButtonClick:({provider:e})=>{u(`login_button_clicked`,{provider:e})},trackConversationCreated:({conversationId:e,taskId:t,hasRepository:n,gitProvider:r,hasWorkspace:i,workspaceMode:a,hasInitialQuery:o,agentType:s,hasParentConversation:c,entryPoint:l})=>{u(`conversation_created`,{conversation_id:e,task_id:t,is_start_task:e.startsWith(`task-`),has_repository:n,git_provider:r,has_workspace:i,workspace_mode:a,has_initial_query:o,agent_type:s,has_parent_conversation:c,entry_point:l})},trackPushButtonClick:()=>{u(`push_button_clicked`)},trackPullButtonClick:()=>{u(`pull_button_clicked`)},trackCreatePrButtonClick:()=>{u(`create_pr_button_clicked`)},trackUserSignupCompleted:()=>{u(`user_signup_completed`,{signup_timestamp:new Date().toISOString()})},trackPrebuiltAutomationEnabled:({automationId:e,automationName:t,automationCategory:n})=>{u(`prebuilt_automation_enabled`,{automation_id:e,automation_name:t,automation_category:n})},trackInitialQuerySubmitted:({entryPoint:e,queryCharacterLength:t,replayJsonSize:n})=>{u(`initial_query_submitted`,{entry_point:e,query_character_length:t,replay_json_size:n})},trackUserMessageSent:({sessionMessageCount:e,currentMessageLength:t})=>{u(`user_message_sent`,{session_message_count:e,current_message_length:t})},trackDownloadVsCodeButtonClicked:()=>{u(`download_via_vscode_button_clicked`)},trackSettingsSaved:({llmModel:e,llmApiKeySet:t,searchApiKeySet:n,remoteRuntimeResourceFactor:r})=>{u(`settings_saved`,{LLM_MODEL:e,LLM_API_KEY_SET:t,SEARCH_API_KEY_SET:n,REMOTE_RUNTIME_RESOURCE_FACTOR:r})},trackMcpConfigUpdated:({sseServersCount:e,stdioServersCount:t})=>{u(`mcp_config_updated`,{has_mcp_config:!0,sse_servers_count:e,stdio_servers_count:t})},trackDownloadTrajectoryButtonClicked:()=>{u(`download_trajectory_button_clicked`)},trackConversationExported:e=>{u(`conversation_exported`,{format:e})},trackAutomationCreatedButton:({backendKind:e})=>{u(`automation_created_button`,{backend_kind:e})},trackAutomationExecuted:({backendKind:e})=>{u(`automation_executed`,{backend_kind:e})},trackAutomationDeleted:({backendKind:e})=>{u(`automation_deleted`,{backend_kind:e})},trackAutomationDisableButton:({backendKind:e})=>{u(`automation_disable_button`,{backend_kind:e})},trackAutomationEdited:({backendKind:e})=>{u(`automation_edited`,{backend_kind:e})},trackAutomationExported:({backendKind:e})=>{u(`automation_exported`,{backend_kind:e})},trackAutomationImported:({backendKind:e})=>{u(`automation_imported`,{backend_kind:e})},trackBackendAdded:({backendKind:e,connectionMethod:t,hasApiKey:n,source:i,agentServerVersion:a,backendVersion:o})=>{u(`backend_added`,{...r.getBackendTelemetryProperties({backendKind:e,agentServerVersion:a,backendVersion:o,connectionMethod:t}),has_api_key:n,source:i})},trackOnboardingStarted:()=>{u(`onboarding_started`)},trackOnboardingStepViewed:({step:e,stepIndex:t,totalSteps:n,agent:r})=>{u(`onboarding_step_viewed`,{step:e,step_index:t,total_steps:n,agent:r})},trackOnboardingCompleted:({agent:e})=>{u(`onboarding_completed`,{agent:e})},trackOnboardingSkipped:({step:e,stepIndex:t,totalSteps:n,agent:r})=>{u(`onboarding_skipped`,{step:e,step_index:t,total_steps:n,agent:r})}}};exports.useTracking=s;
1
+ const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../api/agent-server-compatibility.cjs"),n=require("../services/telemetry-context.cjs"),r=require("../services/telemetry.cjs"),i=require("../contexts/active-backend-context.cjs"),a=require("./query/use-automation-sdk-version.cjs");let o=require("react");o=e.__toESM(o,1);var s=()=>{let{backend:e}=i.useActiveBackend(),s=a.useAutomationSdkVersion(),c=o.default.useCallback(()=>({backendKind:e.kind,agentServerVersion:e.kind===`local`?t.getCachedAgentServerVersion(e.host):null,automationSdkVersion:s??null}),[s,e.host,e.kind]);o.default.useEffect(()=>{r.setTelemetryBackendContext(c())},[c]);let l={current_url:window.location.href},u=(e,t={})=>{r.setTelemetryBackendContext(c()),r.trackEvent(e,{...l,...t})};return{trackLoginButtonClick:({provider:e})=>{u(`login_button_clicked`,{provider:e})},trackConversationCreated:({conversationId:e,taskId:t,hasRepository:n,gitProvider:r,hasWorkspace:i,workspaceMode:a,hasInitialQuery:o,agentType:s,hasParentConversation:c,entryPoint:l})=>{u(`conversation_created`,{conversation_id:e,task_id:t,is_start_task:e.startsWith(`task-`),has_repository:n,git_provider:r,has_workspace:i,workspace_mode:a,has_initial_query:o,agent_type:s,has_parent_conversation:c,entry_point:l})},trackPushButtonClick:()=>{u(`push_button_clicked`)},trackPullButtonClick:()=>{u(`pull_button_clicked`)},trackCreatePrButtonClick:()=>{u(`create_pr_button_clicked`)},trackUserSignupCompleted:()=>{u(`user_signup_completed`,{signup_timestamp:new Date().toISOString()})},trackPrebuiltAutomationEnabled:({automationId:e,automationName:t,automationCategory:n})=>{u(`prebuilt_automation_enabled`,{automation_id:e,automation_name:t,automation_category:n})},trackInitialQuerySubmitted:({entryPoint:e,queryCharacterLength:t,replayJsonSize:n})=>{u(`initial_query_submitted`,{entry_point:e,query_character_length:t,replay_json_size:n})},trackUserMessageSent:({sessionMessageCount:e,currentMessageLength:t})=>{u(`user_message_sent`,{session_message_count:e,current_message_length:t})},trackDownloadVsCodeButtonClicked:()=>{u(`download_via_vscode_button_clicked`)},trackSettingsSaved:({llmModel:e,llmApiKeySet:t,searchApiKeySet:n,remoteRuntimeResourceFactor:r})=>{u(`settings_saved`,{LLM_MODEL:e,LLM_API_KEY_SET:t,SEARCH_API_KEY_SET:n,REMOTE_RUNTIME_RESOURCE_FACTOR:r})},trackMcpConfigUpdated:({sseServersCount:e,stdioServersCount:t})=>{u(`mcp_config_updated`,{has_mcp_config:!0,sse_servers_count:e,stdio_servers_count:t})},trackDownloadTrajectoryButtonClicked:()=>{u(`download_trajectory_button_clicked`)},trackConversationExported:e=>{u(`conversation_exported`,{format:e})},trackAutomationCreatedButton:({backendKind:e})=>{u(`automation_created_button`,{backend_kind:e})},trackAutomationExecuted:({backendKind:e})=>{u(`automation_executed`,{backend_kind:e})},trackAutomationDeleted:({backendKind:e})=>{u(`automation_deleted`,{backend_kind:e})},trackAutomationDisableButton:({backendKind:e})=>{u(`automation_disable_button`,{backend_kind:e})},trackAutomationEdited:({backendKind:e})=>{u(`automation_edited`,{backend_kind:e})},trackAutomationExported:({backendKind:e})=>{u(`automation_exported`,{backend_kind:e})},trackAutomationImported:({backendKind:e})=>{u(`automation_imported`,{backend_kind:e})},trackBackendAdded:({backendKind:e,connectionMethod:t,hasApiKey:r,source:i,agentServerVersion:a,backendVersion:o})=>{u(`backend_added`,{...n.getBackendTelemetryProperties({backendKind:e,agentServerVersion:a,backendVersion:o,connectionMethod:t}),has_api_key:r,source:i})},trackOnboardingStarted:()=>{u(`onboarding_started`)},trackOnboardingStepViewed:({step:e,stepIndex:t,totalSteps:n,agent:r})=>{u(`onboarding_step_viewed`,{step:e,step_index:t,total_steps:n,agent:r})},trackOnboardingCompleted:({agent:e})=>{u(`onboarding_completed`,{agent:e})},trackOnboardingSkipped:({step:e,stepIndex:t,totalSteps:n,agent:r})=>{u(`onboarding_skipped`,{step:e,step_index:t,total_steps:n,agent:r})}}};exports.useTracking=s;
2
2
  //# sourceMappingURL=use-tracking.cjs.map
@@ -1,12 +1,12 @@
1
1
  import { getCachedAgentServerVersion as e } from "../api/agent-server-compatibility.js";
2
- import { useActiveBackend as t } from "../contexts/active-backend-context.js";
3
- import { getBackendTelemetryProperties as n } from "../services/telemetry-context.js";
4
- import { setTelemetryBackendContext as r, trackEvent as i } from "../services/telemetry.js";
2
+ import { getBackendTelemetryProperties as t } from "../services/telemetry-context.js";
3
+ import { setTelemetryBackendContext as n, trackEvent as r } from "../services/telemetry.js";
4
+ import { useActiveBackend as i } from "../contexts/active-backend-context.js";
5
5
  import { useAutomationSdkVersion as a } from "./query/use-automation-sdk-version.js";
6
6
  import o from "react";
7
7
  //#region src/hooks/use-tracking.ts
8
8
  var s = () => {
9
- let { backend: s } = t(), c = a(), l = o.useCallback(() => ({
9
+ let { backend: s } = i(), c = a(), l = o.useCallback(() => ({
10
10
  backendKind: s.kind,
11
11
  agentServerVersion: s.kind === "local" ? e(s.host) : null,
12
12
  automationSdkVersion: c ?? null
@@ -16,10 +16,10 @@ var s = () => {
16
16
  s.kind
17
17
  ]);
18
18
  o.useEffect(() => {
19
- r(l());
19
+ n(l());
20
20
  }, [l]);
21
21
  let u = { current_url: window.location.href }, d = (e, t = {}) => {
22
- r(l()), i(e, {
22
+ n(l()), r(e, {
23
23
  ...u,
24
24
  ...t
25
25
  });
@@ -120,13 +120,13 @@ var s = () => {
120
120
  trackAutomationImported: ({ backendKind: e }) => {
121
121
  d("automation_imported", { backend_kind: e });
122
122
  },
123
- trackBackendAdded: ({ backendKind: e, connectionMethod: t, hasApiKey: r, source: i, agentServerVersion: a, backendVersion: o }) => {
123
+ trackBackendAdded: ({ backendKind: e, connectionMethod: n, hasApiKey: r, source: i, agentServerVersion: a, backendVersion: o }) => {
124
124
  d("backend_added", {
125
- ...n({
125
+ ...t({
126
126
  backendKind: e,
127
127
  agentServerVersion: a,
128
128
  backendVersion: o,
129
- connectionMethod: t
129
+ connectionMethod: n
130
130
  }),
131
131
  has_api_key: r,
132
132
  source: i