@opengeni/react 4.6.1 → 4.6.2-canary.39854174564001

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 (465) hide show
  1. package/dist/app/app-state.js +5 -5
  2. package/dist/app/components/Composer.js +14 -14
  3. package/dist/app/components/artifacts/artifact-library.js +2 -2
  4. package/dist/app/components/artifacts/chat-interactive-block.js +10 -10
  5. package/dist/app/components/artifacts/inline-chat-image.js +14 -14
  6. package/dist/app/components/artifacts/retained-file-preview.js +15 -15
  7. package/dist/app/components/artifacts/retained-text-preview.js +2 -2
  8. package/dist/app/components/artifacts/site-conversations.js +4 -3
  9. package/dist/app/components/artifacts/site-data.js +2 -2
  10. package/dist/app/components/artifacts/site-publishing.js +11 -11
  11. package/dist/app/components/artifacts/site-settings.js +12 -12
  12. package/dist/app/components/billing-class-mark.js +3 -3
  13. package/dist/app/components/capabilities/capability-detail-sheet.js +2 -2
  14. package/dist/app/components/capabilities/capability-logo-source.js +7 -7
  15. package/dist/app/components/capabilities/native-connect-readiness.js +1 -0
  16. package/dist/app/components/capabilities/native-connect-readiness.js.map +1 -1
  17. package/dist/app/components/capabilities/native-connect-setup.js +6 -6
  18. package/dist/app/components/capabilities/perform-capability-action.js +2 -1
  19. package/dist/app/components/capabilities/prepared-mcp-setup-card.js +8 -8
  20. package/dist/app/components/capabilities/session-capability-card.js +28 -27
  21. package/dist/app/components/capabilities/session-capability-card.js.map +1 -1
  22. package/dist/app/components/capabilities/session-chrome-card.js +14 -14
  23. package/dist/app/components/capabilities/session-custom-mcp-card.js +9 -9
  24. package/dist/app/components/capabilities/session-github-card.js +9 -9
  25. package/dist/app/components/capabilities/session-machine-card.js +13 -13
  26. package/dist/app/components/command-menu/chat-status.js +6 -5
  27. package/dist/app/components/command-menu/chat-switcher.d.ts +2 -0
  28. package/dist/app/components/command-menu/chat-switcher.js +26 -9
  29. package/dist/app/components/command-menu/chat-switcher.js.map +1 -1
  30. package/dist/app/components/command-menu/command-menu.js +9 -8
  31. package/dist/app/components/command-menu/command-menu.js.map +1 -1
  32. package/dist/app/components/command-menu/shortcut-sheet.js +4 -4
  33. package/dist/app/components/composer-mobile-plus-panel.js +5 -5
  34. package/dist/app/components/composer-mobile-plus.js +1 -1
  35. package/dist/app/components/credit-required-gate.js +1 -1
  36. package/dist/app/components/credit-required-prompt.js +3 -3
  37. package/dist/app/components/desktop/app-shots.js +5 -5
  38. package/dist/app/components/desktop/this-computer.js +4 -4
  39. package/dist/app/components/feedback.js +3 -3
  40. package/dist/app/components/github-app-connect-launcher.js +1 -1
  41. package/dist/app/components/machines/connect-machine-dialog.js +3 -3
  42. package/dist/app/components/markdown.js +4 -4
  43. package/dist/app/components/models/models-ui.js +2 -2
  44. package/dist/app/components/pickers.js +5 -5
  45. package/dist/app/components/rail/rail-context.js +1 -1
  46. package/dist/app/components/rail/rail-sections.js +15 -14
  47. package/dist/app/components/rail/session-header.d.ts +6 -5
  48. package/dist/app/components/rail/session-header.js +11 -10
  49. package/dist/app/components/rail/session-list.js +14 -13
  50. package/dist/app/components/rail/session-row-hover-details.js +7 -6
  51. package/dist/app/components/rail/session-shell.js +30 -32
  52. package/dist/app/components/rail/site-session-group-heading.js +2 -1
  53. package/dist/app/components/session/agent-configuration-panel.js +3 -3
  54. package/dist/app/components/session/banners.js +6 -6
  55. package/dist/app/components/session/editable-artifacts-workspace.js +12 -12
  56. package/dist/app/components/session/failed-session-banner.js +4 -4
  57. package/dist/app/components/session/human-input.js +24 -24
  58. package/dist/app/components/session/inspector.js +30 -30
  59. package/dist/app/components/session/message-actions.js +3 -3
  60. package/dist/app/components/session/message-resource-attachments.js +5 -5
  61. package/dist/app/components/session/model-recovery-notice.js +3 -3
  62. package/dist/app/components/session/new-session-settings-menu.js +4 -4
  63. package/dist/app/components/session/sandbox-switcher.js +7 -7
  64. package/dist/app/components/session/sandbox-workspace.js +33 -33
  65. package/dist/app/components/session/search-markdown-highlight.js +5 -5
  66. package/dist/app/components/session/search-results-view.js +6 -6
  67. package/dist/app/components/session/session-admission-notice.js +4 -4
  68. package/dist/app/components/session/session-machine-access-notice.js +4 -4
  69. package/dist/app/components/session/session-search-dialog.js +6 -6
  70. package/dist/app/components/session/session-usage-limit-section.js +3 -3
  71. package/dist/app/components/session/session-wait-status.js +2 -1
  72. package/dist/app/components/session/session-wait-status.js.map +1 -1
  73. package/dist/app/components/session/subagents.js +5 -4
  74. package/dist/app/components/session/subscription-account-indicator.d.ts +35 -0
  75. package/dist/app/components/session/{codex-account-indicator.js → subscription-account-indicator.js} +23 -10
  76. package/dist/app/components/session/subscription-account-menu.d.ts +11 -12
  77. package/dist/app/components/session/subscription-account-menu.js +1 -1
  78. package/dist/app/components/session/subscription-account.d.ts +105 -0
  79. package/dist/app/components/usage/usage-entry.js +3 -3
  80. package/dist/app/components/workspace-composer-plus.js +10 -10
  81. package/dist/app/embed/session-app.js +92 -94
  82. package/dist/app/lib/actions/actions-provider.js +4 -4
  83. package/dist/app/lib/actions/chat-switcher.d.ts +19 -7
  84. package/dist/app/lib/codex-usage-query.js +2 -2
  85. package/dist/app/lib/composer-connectors.js +8 -8
  86. package/dist/app/lib/console-text.js +2 -2
  87. package/dist/app/lib/drive-connect-return.d.ts +26 -0
  88. package/dist/app/lib/drive-connect-return.js +16 -0
  89. package/dist/app/lib/events.js +7 -7
  90. package/dist/app/lib/failed-session-copy.js +3 -3
  91. package/dist/app/lib/model-access-onboarding.js +3 -3
  92. package/dist/app/lib/move-chat-to-machine.js +3 -3
  93. package/dist/app/lib/session-branch-cache.js +6 -5
  94. package/dist/app/lib/session-group-pagination.js +6 -5
  95. package/dist/app/lib/session-hover-facts.js +6 -5
  96. package/dist/app/lib/session-rail.js +2 -1
  97. package/dist/app/lib/sessions-group.js +5 -4
  98. package/dist/app/lib/turn-failure-analytics.js +4 -4
  99. package/dist/app/lib/use-workspace-machines.js +4 -4
  100. package/dist/app/lib/use-workspace-model-catalog.js +3 -3
  101. package/dist/app/lib/use-workspace-rigs.js +2 -2
  102. package/dist/app/lib/workspace-navigation-preference.js +4 -4
  103. package/dist/app/lib/workspace-scope-context.js +3 -3
  104. package/dist/app/routes/artifacts.js +26 -25
  105. package/dist/app/routes/artifacts.js.map +1 -1
  106. package/dist/app/routes/retained-artifact.js +15 -15
  107. package/dist/app/routes/session.js +64 -63
  108. package/dist/app/routes/sessions-index.js +41 -41
  109. package/dist/app/routes/site-view.js +30 -29
  110. package/dist/app/routes/site-view.js.map +1 -1
  111. package/dist/artifacts-document.js +4 -4
  112. package/dist/artifacts-presentation.js +4 -4
  113. package/dist/artifacts-spreadsheet.js +4 -4
  114. package/dist/artifacts.js +10 -10
  115. package/dist/{browser-viewer-YQC6BFMS.js → browser-viewer-VKIAULG7.js} +4 -4
  116. package/dist/{chat-interactive-block-Z22YHDRU.js → chat-interactive-block-JGYSW4KB.js} +5 -5
  117. package/dist/{chunk-WN2MIB4Q.js → chunk-22V2QCEM.js} +2 -2
  118. package/dist/{chunk-SJPAKWWP.js → chunk-2BISI664.js} +2 -2
  119. package/dist/{chunk-O5UOCMH4.js → chunk-2LPJVEWY.js} +3 -3
  120. package/dist/{chunk-JI6WPLZB.js → chunk-2SBCOGQN.js} +4 -4
  121. package/dist/{chunk-6JF7C3U3.js → chunk-2WERWWSS.js} +2 -2
  122. package/dist/{chunk-4XKT4ENZ.js → chunk-2Y3QL3DA.js} +4 -4
  123. package/dist/{chunk-KVMFT6FN.js → chunk-3FL3F4WF.js} +2 -2
  124. package/dist/{chunk-4VJOZJDV.js → chunk-3JPQAIYJ.js} +2 -2
  125. package/dist/{chunk-27EORKJ4.js → chunk-3N4LNBJF.js} +2 -2
  126. package/dist/{chunk-7JZSFJHB.js → chunk-3OJU3RUR.js} +2 -2
  127. package/dist/{chunk-NV5OYV3G.js → chunk-3U6K36QA.js} +5 -5
  128. package/dist/{chunk-MDRLP5DO.js → chunk-3W7ROHN4.js} +3 -3
  129. package/dist/{chunk-3MQM4ZOC.js → chunk-3Y6ZR2VN.js} +3 -3
  130. package/dist/{chunk-HXZIX7MR.js → chunk-47AB65IO.js} +4 -4
  131. package/dist/{chunk-DNYD7AUG.js → chunk-4BOLIZ7Y.js} +3 -3
  132. package/dist/{chunk-4XO346BW.js → chunk-4FBJFQFU.js} +2 -2
  133. package/dist/{chunk-DAQG3C4W.js → chunk-4HM6YDBX.js} +3 -3
  134. package/dist/{chunk-BWKZEW6K.js → chunk-4T3E56NT.js} +3 -3
  135. package/dist/{chunk-4PC7LIQK.js → chunk-4ZMUWRFF.js} +3 -3
  136. package/dist/{chunk-O4AWXTZQ.js → chunk-52XIYULR.js} +3 -3
  137. package/dist/{chunk-GXK4CUAB.js → chunk-5WQKTT5Z.js} +2 -2
  138. package/dist/{chunk-MHIYYHCL.js → chunk-5ZAHAUWD.js} +10 -10
  139. package/dist/{chunk-6N7W3TOV.js → chunk-63BPMTBM.js} +2 -2
  140. package/dist/{chunk-R5YZ3ROM.js → chunk-63PQKTTT.js} +2 -2
  141. package/dist/{chunk-WLZVXCPZ.js → chunk-6GO6WN22.js} +3 -3
  142. package/dist/{chunk-6PQBKMUL.js → chunk-6IIA63VD.js} +11 -7
  143. package/dist/chunk-6IIA63VD.js.map +1 -0
  144. package/dist/{chunk-PQCFW2KT.js → chunk-6IRDW7K3.js} +18 -13
  145. package/dist/chunk-6IRDW7K3.js.map +1 -0
  146. package/dist/{chunk-XDCZBOEY.js → chunk-6LGBGPBU.js} +1 -1
  147. package/dist/{chunk-D4QOZXPM.js → chunk-7ITDATTP.js} +2 -2
  148. package/dist/{chunk-M5E3CKSE.js → chunk-7QWWE5XL.js} +2 -2
  149. package/dist/{chunk-RABKQFTA.js → chunk-A2HCAMRH.js} +2 -2
  150. package/dist/{chunk-6K3WNTRI.js → chunk-AODISQO6.js} +2 -2
  151. package/dist/{chunk-C6JL6PBL.js → chunk-AQDRH6VF.js} +3 -3
  152. package/dist/{chunk-72XEFLMD.js → chunk-ASWINLSW.js} +2 -2
  153. package/dist/{chunk-DNLXQUBX.js → chunk-B746OUJC.js} +24 -36
  154. package/dist/chunk-B746OUJC.js.map +1 -0
  155. package/dist/{chunk-FVCLVASD.js → chunk-B7ZKSROO.js} +24 -24
  156. package/dist/{chunk-EURDMOXZ.js → chunk-BYJZUCOQ.js} +2 -2
  157. package/dist/{chunk-ZWACUOU5.js → chunk-CDBGAAJY.js} +3 -3
  158. package/dist/chunk-CDBGAAJY.js.map +1 -0
  159. package/dist/{chunk-BPD4IJBG.js → chunk-CG6CJMIS.js} +2 -2
  160. package/dist/{chunk-B254JG72.js → chunk-CQX24PT7.js} +2 -2
  161. package/dist/{chunk-HJTTDLF6.js → chunk-CY3NO4JN.js} +4 -4
  162. package/dist/{chunk-OLUG4IFF.js → chunk-D2RLPRSG.js} +2 -2
  163. package/dist/{chunk-74NIHMAT.js → chunk-D653JH6D.js} +3 -3
  164. package/dist/{chunk-FMATVQFW.js → chunk-DA6EQDFR.js} +6 -6
  165. package/dist/{chunk-2LUO22FR.js → chunk-DAI5CTQF.js} +4 -4
  166. package/dist/{chunk-HTKVYEVB.js → chunk-DBM4ZXDN.js} +2 -2
  167. package/dist/{chunk-MB2DTUEG.js → chunk-DNYKLU3K.js} +4 -4
  168. package/dist/{chunk-NPDL4W4Y.js → chunk-DT53LBQN.js} +44 -45
  169. package/dist/chunk-DT53LBQN.js.map +1 -0
  170. package/dist/{chunk-26P7B46A.js → chunk-DXYARXK3.js} +3 -3
  171. package/dist/{chunk-JQKURO3S.js → chunk-E4MQRQ6Z.js} +2 -2
  172. package/dist/{chunk-KW53DBY7.js → chunk-EBW2E32G.js} +2 -2
  173. package/dist/{chunk-O73DRA77.js → chunk-ENKBO7FC.js} +4 -4
  174. package/dist/{chunk-32HA7DXJ.js → chunk-EQNGX77H.js} +11 -11
  175. package/dist/{chunk-CA64OZLZ.js → chunk-FAPYRTG6.js} +4 -4
  176. package/dist/{chunk-WWM7WVD2.js → chunk-GABFKHQE.js} +2 -2
  177. package/dist/chunk-GLCOKWLH.js +42 -0
  178. package/dist/chunk-GLCOKWLH.js.map +1 -0
  179. package/dist/{chunk-OHG2UQ2O.js → chunk-GNM3OY36.js} +51 -13
  180. package/dist/chunk-GNM3OY36.js.map +1 -0
  181. package/dist/{chunk-JJ7VMIEQ.js → chunk-H2GTWX4D.js} +14 -14
  182. package/dist/{chunk-LR7U3HCD.js → chunk-HPSATFLQ.js} +4 -4
  183. package/dist/{chunk-TM2ZLY3Q.js → chunk-I56TUH3Z.js} +13 -13
  184. package/dist/{chunk-ZZUKJ5HQ.js → chunk-IG2ERMSB.js} +2 -2
  185. package/dist/{chunk-2SZ3KC5S.js → chunk-IMKIIS4Y.js} +2 -2
  186. package/dist/{chunk-I57HZMMA.js → chunk-IXIE3H43.js} +2 -2
  187. package/dist/{chunk-OWJD3V4V.js → chunk-J3YQ3554.js} +2 -2
  188. package/dist/{chunk-BCFHMBMK.js → chunk-J5HZBHU4.js} +7 -7
  189. package/dist/{chunk-UHMMRQGU.js → chunk-KD7GNHOP.js} +3 -3
  190. package/dist/{chunk-RXMIXKB3.js → chunk-KIKAVZOW.js} +2 -2
  191. package/dist/{chunk-X7Z4B5GK.js → chunk-KPL7EXS6.js} +2 -2
  192. package/dist/{chunk-GTR2WUBA.js → chunk-KX6M5CJI.js} +1 -1
  193. package/dist/{chunk-CYO5HL4C.js → chunk-KYL2BPS2.js} +2 -2
  194. package/dist/{chunk-ZPZYYSHW.js → chunk-L7EAQGWN.js} +5 -5
  195. package/dist/{chunk-QLDMF7MH.js → chunk-LC5HE7PZ.js} +2 -2
  196. package/dist/{chunk-3SMJ2BIQ.js → chunk-LGD5RESZ.js} +7 -33
  197. package/dist/chunk-LGD5RESZ.js.map +1 -0
  198. package/dist/{chunk-4ICPJZAB.js → chunk-LMYSYG6U.js} +2 -2
  199. package/dist/{chunk-3ZZOE4SN.js → chunk-LOCDYMD6.js} +4 -4
  200. package/dist/{chunk-DNWBLT4U.js → chunk-MASBMJ2M.js} +2 -2
  201. package/dist/{chunk-6VITVQ23.js → chunk-MTYE2PPR.js} +1 -1
  202. package/dist/{chunk-NZMQDUOD.js → chunk-MU6HYDNF.js} +5 -5
  203. package/dist/{chunk-GMVKCEBG.js → chunk-MY6QEDZ2.js} +2 -2
  204. package/dist/{chunk-SK57RWSA.js → chunk-MZGKQ5WV.js} +2 -2
  205. package/dist/{chunk-HSQRYJ4P.js → chunk-N52SFH2K.js} +2 -2
  206. package/dist/{chunk-CEQUNJJY.js → chunk-NDCP5TVN.js} +2 -2
  207. package/dist/{chunk-MY6VZVCP.js → chunk-OAJX5CEL.js} +4 -4
  208. package/dist/{chunk-BQWUXC55.js → chunk-OBBLVC2W.js} +9 -9
  209. package/dist/{chunk-IWIMIRV3.js → chunk-OSJTLQXA.js} +9 -4
  210. package/dist/chunk-OSJTLQXA.js.map +1 -0
  211. package/dist/{chunk-FH75NNLB.js → chunk-OZ5NAXCP.js} +2 -2
  212. package/dist/{chunk-PEGNFZ3F.js → chunk-P5S777YI.js} +2 -2
  213. package/dist/{chunk-LY6727IF.js → chunk-PPSVFNEA.js} +1 -1
  214. package/dist/{chunk-K4FDZVMQ.js → chunk-PR42VIVY.js} +2 -2
  215. package/dist/{chunk-I74J2UZ2.js → chunk-PWMZCW4H.js} +8 -8
  216. package/dist/{chunk-6YDXUE5H.js → chunk-PYA2O3WS.js} +2 -2
  217. package/dist/{chunk-GUIZDI5T.js → chunk-Q2PA4KZS.js} +2 -2
  218. package/dist/{chunk-DZH2HTTB.js → chunk-R27GW5WV.js} +1 -1
  219. package/dist/chunk-R4U4EWZG.js +414 -0
  220. package/dist/chunk-R4U4EWZG.js.map +1 -0
  221. package/dist/{chunk-7OIBLMDP.js → chunk-RAQISW42.js} +2 -2
  222. package/dist/{chunk-CPKD2YGK.js → chunk-RNU5CUPI.js} +2 -2
  223. package/dist/{chunk-467VRP4E.js → chunk-RO5YZQHZ.js} +3 -3
  224. package/dist/{chunk-SSZROOOI.js → chunk-ROLXYGT5.js} +2 -2
  225. package/dist/{chunk-F4B2YYCN.js → chunk-TAWFXRXB.js} +3 -3
  226. package/dist/{chunk-G3FU2IF7.js → chunk-TB7UW5BB.js} +3 -3
  227. package/dist/{chunk-NF6Q4XTN.js → chunk-TQF2I5SY.js} +3 -3
  228. package/dist/{chunk-MM7OKOTE.js → chunk-UBXHP224.js} +43 -18
  229. package/dist/chunk-UBXHP224.js.map +1 -0
  230. package/dist/{chunk-M7A226EQ.js → chunk-UL44R3W2.js} +2 -2
  231. package/dist/{chunk-65K5LV4L.js → chunk-UQKBV22P.js} +21 -20
  232. package/dist/{chunk-65K5LV4L.js.map → chunk-UQKBV22P.js.map} +1 -1
  233. package/dist/{chunk-GTR5NLVP.js → chunk-VCRQPLKS.js} +2 -2
  234. package/dist/{chunk-NWSAF6P5.js → chunk-WJDH7CH5.js} +22 -1
  235. package/dist/chunk-WJDH7CH5.js.map +1 -0
  236. package/dist/{chunk-LG67ZNRU.js → chunk-WK2ZCTUF.js} +2 -2
  237. package/dist/{chunk-XGE75VPK.js → chunk-WNARM3LY.js} +3 -3
  238. package/dist/{chunk-RNBH5TSM.js → chunk-WQ2RTQYO.js} +2 -2
  239. package/dist/chunk-X5XEYQ4B.js +84 -0
  240. package/dist/chunk-X5XEYQ4B.js.map +1 -0
  241. package/dist/{chunk-W57QFLQD.js → chunk-X6JIGNLI.js} +4 -4
  242. package/dist/{chunk-CKA4SJRK.js → chunk-XIQDCQX7.js} +2 -2
  243. package/dist/{chunk-AJ7PY4FJ.js → chunk-Y3GCG6CA.js} +2 -2
  244. package/dist/{chunk-2K27S6LK.js → chunk-Y565N5ZJ.js} +24 -7
  245. package/dist/chunk-Y565N5ZJ.js.map +1 -0
  246. package/dist/{chunk-ZRB4M3GG.js → chunk-YC5KH7ZB.js} +3 -3
  247. package/dist/{chunk-4RY64KQY.js → chunk-YJUKLLNP.js} +2 -2
  248. package/dist/{chunk-24POWVUY.js → chunk-ZDJNRRVS.js} +4 -4
  249. package/dist/{chunk-S6WJ6TUT.js → chunk-ZEVJGMNB.js} +2 -2
  250. package/dist/chunk-ZEVJGMNB.js.map +1 -0
  251. package/dist/{chunk-M7YEZR6X.js → chunk-ZITMDA4C.js} +2 -2
  252. package/dist/components/model-policy-picker.d.ts +2 -0
  253. package/dist/composer.js +6 -6
  254. package/dist/{computer-viewer-BWVNDFTO.js → computer-viewer-6CRLWQHP.js} +5 -5
  255. package/dist/connect.js +6 -6
  256. package/dist/connection-service-presentation.d.ts +1 -4
  257. package/dist/desktop.js +2 -2
  258. package/dist/editor.js +2 -2
  259. package/dist/{embedded-new-voice-GBXSZ3TO.js → embedded-new-voice-KILV3RYM.js} +5 -5
  260. package/dist/{embedded-voice-MGI7EK7C.js → embedded-voice-GHDRLCFX.js} +5 -5
  261. package/dist/{fleet-decision-row-35S3GAUN.js → fleet-decision-row-DQXRRBT7.js} +2 -2
  262. package/dist/index.js +36 -36
  263. package/dist/interaction.js +5 -5
  264. package/dist/machines.js +3 -3
  265. package/dist/messages/en.d.ts +1 -1
  266. package/dist/messages.js +1 -1
  267. package/dist/{model-policy-picker-menu-KP53N6UJ.js → model-policy-picker-menu-5ALKUJMR.js} +4 -4
  268. package/dist/{platform-activity-row-ISMXR7NJ.js → platform-activity-row-227C764Z.js} +2 -2
  269. package/dist/{queue-surface-implementation-ULW7DDJA.js → queue-surface-implementation-H3NOBXU5.js} +5 -5
  270. package/dist/realtime.js +4 -4
  271. package/dist/{sandbox-files-QYSD4XCZ.js → sandbox-files-5FEOHUMD.js} +6 -6
  272. package/dist/session-app.js +92 -94
  273. package/dist/{session-realtime-JXRLPNUH.js → session-realtime-OHBMODNX.js} +3 -3
  274. package/dist/session-realtime.js +2 -2
  275. package/dist/session-ui.js +24 -24
  276. package/dist/session.js +5 -5
  277. package/dist/sites.js +2 -2
  278. package/dist/terminal.js +2 -2
  279. package/dist/this-computer.js +3 -3
  280. package/dist/timeline/connector-logo-index.d.ts +19 -0
  281. package/dist/{timeline-annotation-markers-OJYKHBEO.js → timeline-annotation-markers-NDHS7MCK.js} +2 -2
  282. package/dist/{timeline-annotation-selection-6OAZLXFU.js → timeline-annotation-selection-DRQSTJOV.js} +2 -2
  283. package/dist/{timeline-annotations-dialog-5M6DP5FX.js → timeline-annotations-dialog-G6J5ZJKN.js} +3 -3
  284. package/dist/timeline-model.d.ts +2 -0
  285. package/dist/timeline-model.js +9 -1
  286. package/dist/ui/list-row.js +1 -1
  287. package/dist/usage.js +2 -2
  288. package/dist/workbench.js +4 -4
  289. package/package.json +4 -4
  290. package/src/app/components/capabilities/native-connect-readiness.tsx +1 -0
  291. package/src/app/components/capabilities/perform-capability-action.test.ts +67 -0
  292. package/src/app/components/capabilities/perform-capability-action.tsx +28 -0
  293. package/src/app/components/command-menu/chat-switcher.tsx +25 -4
  294. package/src/app/components/rail/session-header.test.tsx +73 -2
  295. package/src/app/components/rail/session-header.tsx +20 -12
  296. package/src/app/components/rail/session-shell.tsx +10 -18
  297. package/src/app/components/session/subscription-account-indicator.test.ts +239 -0
  298. package/src/app/components/session/subscription-account-indicator.tsx +361 -0
  299. package/src/app/components/session/subscription-account-menu.tsx +21 -43
  300. package/src/app/components/session/subscription-account.test.ts +314 -0
  301. package/src/app/components/session/subscription-account.ts +354 -0
  302. package/src/app/lib/actions/actions-provider.tsx +11 -0
  303. package/src/app/lib/actions/actions.test.ts +59 -4
  304. package/src/app/lib/actions/chat-switcher.ts +73 -20
  305. package/src/app/lib/drive-connect-return.test.ts +183 -0
  306. package/src/app/lib/drive-connect-return.tsx +116 -0
  307. package/src/app/routes/session.tsx +12 -14
  308. package/src/app/routes/sessions-index.tsx +1 -0
  309. package/src/components/model-policy-picker-menu.tsx +25 -4
  310. package/src/components/model-policy-picker.tsx +2 -0
  311. package/src/components/session-mcp-capability-card.tsx +13 -4
  312. package/src/connection-service-presentation.ts +6 -1
  313. package/src/messages/en.ts +1 -1
  314. package/src/timeline/connector-logo-index.test.ts +46 -0
  315. package/src/timeline/connector-logo-index.ts +68 -0
  316. package/src/timeline-model.ts +6 -0
  317. package/src/ui/list-row.tsx +38 -10
  318. package/styles/compiled.css +13 -0
  319. package/dist/app/components/session/codex-account-indicator.d.ts +0 -9
  320. package/dist/app/components/session/model-account-indicator.d.ts +0 -10
  321. package/dist/app/components/session/model-account-indicator.js +0 -34
  322. package/dist/app/components/session/model-account-usage.d.ts +0 -8
  323. package/dist/app/components/session/model-account-usage.js +0 -8
  324. package/dist/chunk-2K27S6LK.js.map +0 -1
  325. package/dist/chunk-3SMJ2BIQ.js.map +0 -1
  326. package/dist/chunk-6PQBKMUL.js.map +0 -1
  327. package/dist/chunk-7H2D4VNU.js +0 -150
  328. package/dist/chunk-7H2D4VNU.js.map +0 -1
  329. package/dist/chunk-DNLXQUBX.js.map +0 -1
  330. package/dist/chunk-HCCSAECI.js +0 -132
  331. package/dist/chunk-HCCSAECI.js.map +0 -1
  332. package/dist/chunk-IWIMIRV3.js.map +0 -1
  333. package/dist/chunk-M77ZQE5T.js +0 -58
  334. package/dist/chunk-M77ZQE5T.js.map +0 -1
  335. package/dist/chunk-MM7OKOTE.js.map +0 -1
  336. package/dist/chunk-NPDL4W4Y.js.map +0 -1
  337. package/dist/chunk-NWSAF6P5.js.map +0 -1
  338. package/dist/chunk-OHG2UQ2O.js.map +0 -1
  339. package/dist/chunk-PQCFW2KT.js.map +0 -1
  340. package/dist/chunk-S6WJ6TUT.js.map +0 -1
  341. package/dist/chunk-ZWACUOU5.js.map +0 -1
  342. package/dist/session-realtime-JXRLPNUH.js.map +0 -1
  343. package/src/app/components/session/codex-account-indicator.tsx +0 -207
  344. package/src/app/components/session/model-account-indicator.tsx +0 -189
  345. package/src/app/components/session/model-account-usage.test.ts +0 -59
  346. package/src/app/components/session/model-account-usage.tsx +0 -89
  347. /package/dist/app/components/session/{codex-account-indicator.js.map → subscription-account-indicator.js.map} +0 -0
  348. /package/dist/app/{components/session/model-account-indicator.js.map → lib/drive-connect-return.js.map} +0 -0
  349. /package/dist/{app/components/session/model-account-usage.js.map → browser-viewer-VKIAULG7.js.map} +0 -0
  350. /package/dist/{browser-viewer-YQC6BFMS.js.map → chat-interactive-block-JGYSW4KB.js.map} +0 -0
  351. /package/dist/{chunk-WN2MIB4Q.js.map → chunk-22V2QCEM.js.map} +0 -0
  352. /package/dist/{chunk-SJPAKWWP.js.map → chunk-2BISI664.js.map} +0 -0
  353. /package/dist/{chunk-O5UOCMH4.js.map → chunk-2LPJVEWY.js.map} +0 -0
  354. /package/dist/{chunk-JI6WPLZB.js.map → chunk-2SBCOGQN.js.map} +0 -0
  355. /package/dist/{chunk-6JF7C3U3.js.map → chunk-2WERWWSS.js.map} +0 -0
  356. /package/dist/{chunk-4XKT4ENZ.js.map → chunk-2Y3QL3DA.js.map} +0 -0
  357. /package/dist/{chunk-KVMFT6FN.js.map → chunk-3FL3F4WF.js.map} +0 -0
  358. /package/dist/{chunk-4VJOZJDV.js.map → chunk-3JPQAIYJ.js.map} +0 -0
  359. /package/dist/{chunk-27EORKJ4.js.map → chunk-3N4LNBJF.js.map} +0 -0
  360. /package/dist/{chunk-7JZSFJHB.js.map → chunk-3OJU3RUR.js.map} +0 -0
  361. /package/dist/{chunk-NV5OYV3G.js.map → chunk-3U6K36QA.js.map} +0 -0
  362. /package/dist/{chunk-MDRLP5DO.js.map → chunk-3W7ROHN4.js.map} +0 -0
  363. /package/dist/{chunk-3MQM4ZOC.js.map → chunk-3Y6ZR2VN.js.map} +0 -0
  364. /package/dist/{chunk-HXZIX7MR.js.map → chunk-47AB65IO.js.map} +0 -0
  365. /package/dist/{chunk-DNYD7AUG.js.map → chunk-4BOLIZ7Y.js.map} +0 -0
  366. /package/dist/{chunk-4XO346BW.js.map → chunk-4FBJFQFU.js.map} +0 -0
  367. /package/dist/{chunk-DAQG3C4W.js.map → chunk-4HM6YDBX.js.map} +0 -0
  368. /package/dist/{chunk-BWKZEW6K.js.map → chunk-4T3E56NT.js.map} +0 -0
  369. /package/dist/{chunk-4PC7LIQK.js.map → chunk-4ZMUWRFF.js.map} +0 -0
  370. /package/dist/{chunk-O4AWXTZQ.js.map → chunk-52XIYULR.js.map} +0 -0
  371. /package/dist/{chunk-GXK4CUAB.js.map → chunk-5WQKTT5Z.js.map} +0 -0
  372. /package/dist/{chunk-MHIYYHCL.js.map → chunk-5ZAHAUWD.js.map} +0 -0
  373. /package/dist/{chunk-6N7W3TOV.js.map → chunk-63BPMTBM.js.map} +0 -0
  374. /package/dist/{chunk-R5YZ3ROM.js.map → chunk-63PQKTTT.js.map} +0 -0
  375. /package/dist/{chunk-WLZVXCPZ.js.map → chunk-6GO6WN22.js.map} +0 -0
  376. /package/dist/{chunk-XDCZBOEY.js.map → chunk-6LGBGPBU.js.map} +0 -0
  377. /package/dist/{chunk-D4QOZXPM.js.map → chunk-7ITDATTP.js.map} +0 -0
  378. /package/dist/{chunk-M5E3CKSE.js.map → chunk-7QWWE5XL.js.map} +0 -0
  379. /package/dist/{chunk-RABKQFTA.js.map → chunk-A2HCAMRH.js.map} +0 -0
  380. /package/dist/{chunk-6K3WNTRI.js.map → chunk-AODISQO6.js.map} +0 -0
  381. /package/dist/{chunk-C6JL6PBL.js.map → chunk-AQDRH6VF.js.map} +0 -0
  382. /package/dist/{chunk-72XEFLMD.js.map → chunk-ASWINLSW.js.map} +0 -0
  383. /package/dist/{chunk-FVCLVASD.js.map → chunk-B7ZKSROO.js.map} +0 -0
  384. /package/dist/{chunk-EURDMOXZ.js.map → chunk-BYJZUCOQ.js.map} +0 -0
  385. /package/dist/{chunk-BPD4IJBG.js.map → chunk-CG6CJMIS.js.map} +0 -0
  386. /package/dist/{chunk-B254JG72.js.map → chunk-CQX24PT7.js.map} +0 -0
  387. /package/dist/{chunk-HJTTDLF6.js.map → chunk-CY3NO4JN.js.map} +0 -0
  388. /package/dist/{chunk-OLUG4IFF.js.map → chunk-D2RLPRSG.js.map} +0 -0
  389. /package/dist/{chunk-74NIHMAT.js.map → chunk-D653JH6D.js.map} +0 -0
  390. /package/dist/{chunk-FMATVQFW.js.map → chunk-DA6EQDFR.js.map} +0 -0
  391. /package/dist/{chunk-2LUO22FR.js.map → chunk-DAI5CTQF.js.map} +0 -0
  392. /package/dist/{chunk-HTKVYEVB.js.map → chunk-DBM4ZXDN.js.map} +0 -0
  393. /package/dist/{chunk-MB2DTUEG.js.map → chunk-DNYKLU3K.js.map} +0 -0
  394. /package/dist/{chunk-26P7B46A.js.map → chunk-DXYARXK3.js.map} +0 -0
  395. /package/dist/{chunk-JQKURO3S.js.map → chunk-E4MQRQ6Z.js.map} +0 -0
  396. /package/dist/{chunk-KW53DBY7.js.map → chunk-EBW2E32G.js.map} +0 -0
  397. /package/dist/{chunk-O73DRA77.js.map → chunk-ENKBO7FC.js.map} +0 -0
  398. /package/dist/{chunk-32HA7DXJ.js.map → chunk-EQNGX77H.js.map} +0 -0
  399. /package/dist/{chunk-CA64OZLZ.js.map → chunk-FAPYRTG6.js.map} +0 -0
  400. /package/dist/{chunk-WWM7WVD2.js.map → chunk-GABFKHQE.js.map} +0 -0
  401. /package/dist/{chunk-JJ7VMIEQ.js.map → chunk-H2GTWX4D.js.map} +0 -0
  402. /package/dist/{chunk-LR7U3HCD.js.map → chunk-HPSATFLQ.js.map} +0 -0
  403. /package/dist/{chunk-TM2ZLY3Q.js.map → chunk-I56TUH3Z.js.map} +0 -0
  404. /package/dist/{chunk-ZZUKJ5HQ.js.map → chunk-IG2ERMSB.js.map} +0 -0
  405. /package/dist/{chunk-2SZ3KC5S.js.map → chunk-IMKIIS4Y.js.map} +0 -0
  406. /package/dist/{chunk-I57HZMMA.js.map → chunk-IXIE3H43.js.map} +0 -0
  407. /package/dist/{chunk-OWJD3V4V.js.map → chunk-J3YQ3554.js.map} +0 -0
  408. /package/dist/{chunk-BCFHMBMK.js.map → chunk-J5HZBHU4.js.map} +0 -0
  409. /package/dist/{chunk-UHMMRQGU.js.map → chunk-KD7GNHOP.js.map} +0 -0
  410. /package/dist/{chunk-RXMIXKB3.js.map → chunk-KIKAVZOW.js.map} +0 -0
  411. /package/dist/{chunk-X7Z4B5GK.js.map → chunk-KPL7EXS6.js.map} +0 -0
  412. /package/dist/{chunk-GTR2WUBA.js.map → chunk-KX6M5CJI.js.map} +0 -0
  413. /package/dist/{chunk-CYO5HL4C.js.map → chunk-KYL2BPS2.js.map} +0 -0
  414. /package/dist/{chunk-ZPZYYSHW.js.map → chunk-L7EAQGWN.js.map} +0 -0
  415. /package/dist/{chunk-QLDMF7MH.js.map → chunk-LC5HE7PZ.js.map} +0 -0
  416. /package/dist/{chunk-4ICPJZAB.js.map → chunk-LMYSYG6U.js.map} +0 -0
  417. /package/dist/{chunk-3ZZOE4SN.js.map → chunk-LOCDYMD6.js.map} +0 -0
  418. /package/dist/{chunk-DNWBLT4U.js.map → chunk-MASBMJ2M.js.map} +0 -0
  419. /package/dist/{chunk-6VITVQ23.js.map → chunk-MTYE2PPR.js.map} +0 -0
  420. /package/dist/{chunk-NZMQDUOD.js.map → chunk-MU6HYDNF.js.map} +0 -0
  421. /package/dist/{chunk-GMVKCEBG.js.map → chunk-MY6QEDZ2.js.map} +0 -0
  422. /package/dist/{chunk-SK57RWSA.js.map → chunk-MZGKQ5WV.js.map} +0 -0
  423. /package/dist/{chunk-HSQRYJ4P.js.map → chunk-N52SFH2K.js.map} +0 -0
  424. /package/dist/{chunk-CEQUNJJY.js.map → chunk-NDCP5TVN.js.map} +0 -0
  425. /package/dist/{chunk-MY6VZVCP.js.map → chunk-OAJX5CEL.js.map} +0 -0
  426. /package/dist/{chunk-BQWUXC55.js.map → chunk-OBBLVC2W.js.map} +0 -0
  427. /package/dist/{chunk-FH75NNLB.js.map → chunk-OZ5NAXCP.js.map} +0 -0
  428. /package/dist/{chunk-PEGNFZ3F.js.map → chunk-P5S777YI.js.map} +0 -0
  429. /package/dist/{chunk-LY6727IF.js.map → chunk-PPSVFNEA.js.map} +0 -0
  430. /package/dist/{chunk-K4FDZVMQ.js.map → chunk-PR42VIVY.js.map} +0 -0
  431. /package/dist/{chunk-I74J2UZ2.js.map → chunk-PWMZCW4H.js.map} +0 -0
  432. /package/dist/{chunk-6YDXUE5H.js.map → chunk-PYA2O3WS.js.map} +0 -0
  433. /package/dist/{chunk-GUIZDI5T.js.map → chunk-Q2PA4KZS.js.map} +0 -0
  434. /package/dist/{chunk-DZH2HTTB.js.map → chunk-R27GW5WV.js.map} +0 -0
  435. /package/dist/{chunk-7OIBLMDP.js.map → chunk-RAQISW42.js.map} +0 -0
  436. /package/dist/{chunk-CPKD2YGK.js.map → chunk-RNU5CUPI.js.map} +0 -0
  437. /package/dist/{chunk-467VRP4E.js.map → chunk-RO5YZQHZ.js.map} +0 -0
  438. /package/dist/{chunk-SSZROOOI.js.map → chunk-ROLXYGT5.js.map} +0 -0
  439. /package/dist/{chunk-F4B2YYCN.js.map → chunk-TAWFXRXB.js.map} +0 -0
  440. /package/dist/{chunk-G3FU2IF7.js.map → chunk-TB7UW5BB.js.map} +0 -0
  441. /package/dist/{chunk-NF6Q4XTN.js.map → chunk-TQF2I5SY.js.map} +0 -0
  442. /package/dist/{chunk-M7A226EQ.js.map → chunk-UL44R3W2.js.map} +0 -0
  443. /package/dist/{chunk-GTR5NLVP.js.map → chunk-VCRQPLKS.js.map} +0 -0
  444. /package/dist/{chunk-LG67ZNRU.js.map → chunk-WK2ZCTUF.js.map} +0 -0
  445. /package/dist/{chunk-XGE75VPK.js.map → chunk-WNARM3LY.js.map} +0 -0
  446. /package/dist/{chunk-RNBH5TSM.js.map → chunk-WQ2RTQYO.js.map} +0 -0
  447. /package/dist/{chunk-W57QFLQD.js.map → chunk-X6JIGNLI.js.map} +0 -0
  448. /package/dist/{chunk-CKA4SJRK.js.map → chunk-XIQDCQX7.js.map} +0 -0
  449. /package/dist/{chunk-AJ7PY4FJ.js.map → chunk-Y3GCG6CA.js.map} +0 -0
  450. /package/dist/{chunk-ZRB4M3GG.js.map → chunk-YC5KH7ZB.js.map} +0 -0
  451. /package/dist/{chunk-4RY64KQY.js.map → chunk-YJUKLLNP.js.map} +0 -0
  452. /package/dist/{chunk-24POWVUY.js.map → chunk-ZDJNRRVS.js.map} +0 -0
  453. /package/dist/{chunk-M7YEZR6X.js.map → chunk-ZITMDA4C.js.map} +0 -0
  454. /package/dist/{chat-interactive-block-Z22YHDRU.js.map → computer-viewer-6CRLWQHP.js.map} +0 -0
  455. /package/dist/{computer-viewer-BWVNDFTO.js.map → embedded-new-voice-KILV3RYM.js.map} +0 -0
  456. /package/dist/{embedded-new-voice-GBXSZ3TO.js.map → embedded-voice-GHDRLCFX.js.map} +0 -0
  457. /package/dist/{fleet-decision-row-35S3GAUN.js.map → fleet-decision-row-DQXRRBT7.js.map} +0 -0
  458. /package/dist/{embedded-voice-MGI7EK7C.js.map → model-policy-picker-menu-5ALKUJMR.js.map} +0 -0
  459. /package/dist/{platform-activity-row-ISMXR7NJ.js.map → platform-activity-row-227C764Z.js.map} +0 -0
  460. /package/dist/{queue-surface-implementation-ULW7DDJA.js.map → queue-surface-implementation-H3NOBXU5.js.map} +0 -0
  461. /package/dist/{model-policy-picker-menu-KP53N6UJ.js.map → sandbox-files-5FEOHUMD.js.map} +0 -0
  462. /package/dist/{sandbox-files-QYSD4XCZ.js.map → session-realtime-OHBMODNX.js.map} +0 -0
  463. /package/dist/{timeline-annotation-markers-OJYKHBEO.js.map → timeline-annotation-markers-NDHS7MCK.js.map} +0 -0
  464. /package/dist/{timeline-annotation-selection-6OAZLXFU.js.map → timeline-annotation-selection-DRQSTJOV.js.map} +0 -0
  465. /package/dist/{timeline-annotations-dialog-5M6DP5FX.js.map → timeline-annotations-dialog-G6J5ZJKN.js.map} +0 -0
@@ -0,0 +1,354 @@
1
+ // One provider-neutral shape for a chat's subscription account (Codex, Claude,
2
+ // SuperGrok) and its projection onto the account menu. Data sources normalize
3
+ // into `SubscriptionAccountState`; everything a person sees is decided here,
4
+ // so every provider shows the same structure and copy. Only names, marks and
5
+ // plan labels differ.
6
+ import type { ClientModel, ModelAccountChoiceRefusal } from "@opengeni/sdk";
7
+ import { isCodexProductModel } from "../../lib/session-model";
8
+ import type { BillingClass } from "../billing-class-mark";
9
+ import type {
10
+ SubscriptionAccountMenuRow,
11
+ SubscriptionAccountMenuUsage,
12
+ SubscriptionAccountUsageWindow,
13
+ } from "./subscription-account-menu";
14
+
15
+ export type SubscriptionAccountUsage = {
16
+ /** When the reading was taken; null when unknown. */
17
+ observedAt: string | null;
18
+ windows: Array<{
19
+ id: string;
20
+ /** Null means unknown; values over 100 can represent overage. */
21
+ usedPercent: number | null;
22
+ resetsAt: string | null;
23
+ status: "ok" | "warning" | "exhausted" | "unknown";
24
+ }>;
25
+ exhaustedUntil: string | null;
26
+ exhaustedKind: "quota" | "rate_limit" | null;
27
+ };
28
+
29
+ export type SubscriptionAccount = {
30
+ id: string;
31
+ label: string | null;
32
+ email: string | null;
33
+ plan: string | null;
34
+ /** Who the account belongs to; null when the source does not say. */
35
+ source: "personal" | "workspace" | "organization" | null;
36
+ /** The provider's account status (`active`, `needs_relogin`, …). */
37
+ status: string;
38
+ refusal: ModelAccountChoiceRefusal | null;
39
+ choosable: boolean;
40
+ /** Undefined: not reported. Null: no reading yet. */
41
+ usage: SubscriptionAccountUsage | null | undefined;
42
+ };
43
+
44
+ export type SubscriptionAccountState = {
45
+ /** `codex`, `claude`, `xai`, … */
46
+ provider: string;
47
+ /** True until the first read settles. */
48
+ loading: boolean;
49
+ /** The accounts could not be read. */
50
+ unavailable: boolean;
51
+ /** Accounts this person can pick for the next turn. */
52
+ accounts: SubscriptionAccount[];
53
+ /** The account the chat runs on (or will next), when this person can see it. */
54
+ current: SubscriptionAccount | null;
55
+ /** The chat runs on a chosen or serving account this person cannot see. */
56
+ currentHidden: boolean;
57
+ /** `current`/`currentHidden` is the account serving the chat's latest turn. */
58
+ serving: boolean;
59
+ /** Automatic selection, not a person's explicit choice. */
60
+ automatic: boolean;
61
+ /** The explicitly chosen account, when this person can see it. */
62
+ chosenId: string | null;
63
+ /** A turn waits for capacity on the current account. */
64
+ waiting: boolean;
65
+ /**
66
+ * A live usage check, for sources that offer one: `checking` until its
67
+ * first reading arrives, `failed` when it produced none for this account.
68
+ */
69
+ usageCheck: "idle" | "checking" | "failed";
70
+ choosing: boolean;
71
+ /** The in-flight target (`null` is automatic; `undefined` when idle). */
72
+ choosingTarget: string | null | undefined;
73
+ appliedTo: "waiting_turn" | "next_turn" | null;
74
+ mutationError: string | null;
75
+ };
76
+
77
+ const PROVIDER: Record<string, { name: string; billingClass: BillingClass }> = {
78
+ codex: { name: "Codex", billingClass: "codex_subscription" },
79
+ claude: { name: "Claude", billingClass: "claude_subscription" },
80
+ xai: { name: "SuperGrok", billingClass: "supergrok_subscription" },
81
+ };
82
+
83
+ export function subscriptionProviderPresentation(provider: string): {
84
+ name: string;
85
+ billingClass: BillingClass;
86
+ } {
87
+ return PROVIDER[provider] ?? { name: "Subscription", billingClass: "external" };
88
+ }
89
+
90
+ // Presentation labels only. Preserve every supplied window; never combine
91
+ // family-specific, overage or partial windows into an account capacity score.
92
+ const WINDOW_LABEL: Record<string, string> = {
93
+ // Neutral ids: they do not say how long the window is.
94
+ primary: "Primary",
95
+ secondary: "Secondary",
96
+ five_hour: "5h",
97
+ seven_day: "Week",
98
+ seven_day_opus: "Week · Opus",
99
+ seven_day_sonnet: "Week · Sonnet",
100
+ overage: "Overage",
101
+ billing: "Billing",
102
+ };
103
+
104
+ const REFUSAL_COPY: Record<ModelAccountChoiceRefusal, string> = {
105
+ inactive: "Unavailable",
106
+ personal_not_allowed: "Turned off here",
107
+ personal_not_owner_work: "Not available for this chat",
108
+ session_has_no_owner: "Needs an owner",
109
+ };
110
+
111
+ const STATUS_COPY: Record<string, string> = {
112
+ needs_relogin: "Needs reconnect",
113
+ error: "Error",
114
+ disabled: "Disabled",
115
+ revoked: "Revoked",
116
+ expired: "Expired",
117
+ suspended: "Suspended",
118
+ paused: "Paused",
119
+ inactive: "Inactive",
120
+ limit_reached: "Limit reached",
121
+ };
122
+
123
+ function time(value: string | null): string | null {
124
+ if (!value || !Number.isFinite(Date.parse(value))) return null;
125
+ return new Date(value).toLocaleString(undefined, {
126
+ month: "short",
127
+ day: "numeric",
128
+ hour: "numeric",
129
+ minute: "2-digit",
130
+ });
131
+ }
132
+
133
+ export function accountLabel(account: SubscriptionAccount): string {
134
+ return account.label ?? account.email ?? account.plan ?? "Account";
135
+ }
136
+
137
+ export function accountStatus(account: SubscriptionAccount): string | null {
138
+ // Inactive is a broad refusal; retain the actual status when it explains why.
139
+ if (account.refusal && account.refusal !== "inactive") return REFUSAL_COPY[account.refusal];
140
+ if (account.status !== "active") return STATUS_COPY[account.status] ?? account.status;
141
+ return account.refusal ? REFUSAL_COPY[account.refusal] : null;
142
+ }
143
+
144
+ function accountSource(account: SubscriptionAccount): string | null {
145
+ return account.source === "personal"
146
+ ? "Your account"
147
+ : account.source === "workspace"
148
+ ? "This workspace"
149
+ : account.source === "organization"
150
+ ? "Organization"
151
+ : null;
152
+ }
153
+
154
+ function windowLabel(id: string): string {
155
+ return WINDOW_LABEL[id] ?? id;
156
+ }
157
+
158
+ /** The reading as usage rows: percentage used, with when each window resets. */
159
+ export function subscriptionAccountUsage(
160
+ usage: SubscriptionAccountUsage | null | undefined,
161
+ now = Date.now(),
162
+ ): {
163
+ windows?: SubscriptionAccountUsageWindow[];
164
+ message?: string;
165
+ note?: string;
166
+ summary?: string;
167
+ } {
168
+ if (!usage) return { message: "No usage reading yet" };
169
+ const observed = time(usage.observedAt);
170
+ const windows = usage.windows.map((window) => {
171
+ const reset = time(window.resetsAt);
172
+ const past = reset !== null && Date.parse(window.resetsAt!) <= now;
173
+ return {
174
+ label: windowLabel(window.id),
175
+ usedPercent: window.usedPercent,
176
+ detail: [
177
+ window.status === "unknown"
178
+ ? "Status unknown"
179
+ : window.status === "warning"
180
+ ? "Near its limit"
181
+ : window.status === "exhausted"
182
+ ? "Limit reached"
183
+ : null,
184
+ past ? "Reset passed; usage may be outdated" : reset ? `Resets ${reset}` : null,
185
+ ]
186
+ .filter(Boolean)
187
+ .join(" · "),
188
+ };
189
+ });
190
+ const exhaustedTime = time(usage.exhaustedUntil);
191
+ // A limit whose end has passed no longer applies.
192
+ const exhausted =
193
+ usage.exhaustedKind !== null &&
194
+ !(usage.exhaustedUntil && Date.parse(usage.exhaustedUntil) <= now);
195
+ return {
196
+ windows,
197
+ ...(windows.length === 0
198
+ ? {
199
+ message: exhausted
200
+ ? `Limit reached${exhaustedTime ? ` until ${exhaustedTime}` : ""}`
201
+ : "No usage reading yet",
202
+ }
203
+ : {}),
204
+ ...(observed ? { note: `Updated ${observed}` } : {}),
205
+ ...(windows.length > 0
206
+ ? {
207
+ summary: `${windows
208
+ .map(
209
+ (window) =>
210
+ `${window.label} ${window.usedPercent === null ? "unknown" : `${Math.round(window.usedPercent)}%`}`,
211
+ )
212
+ .join(" · ")} used`,
213
+ }
214
+ : {}),
215
+ };
216
+ }
217
+
218
+ function nearLimit(usage: SubscriptionAccountUsage | null | undefined): boolean {
219
+ return (usage?.windows ?? []).some(
220
+ (window) =>
221
+ window.status === "warning" ||
222
+ window.status === "exhausted" ||
223
+ (window.usedPercent !== null && window.usedPercent >= 90),
224
+ );
225
+ }
226
+
227
+ /**
228
+ * Whether there is anything to show or choose. A chat whose provider offers
229
+ * no accounts to this person, with nothing chosen, serving or waiting, shows
230
+ * the provider's mark alone instead of an empty menu.
231
+ */
232
+ export function showsSubscriptionAccountMenu(state: SubscriptionAccountState): boolean {
233
+ return (
234
+ state.unavailable ||
235
+ state.accounts.length > 0 ||
236
+ state.current !== null ||
237
+ state.currentHidden ||
238
+ state.waiting ||
239
+ !state.automatic
240
+ );
241
+ }
242
+
243
+ /**
244
+ * The subscription whose accounts a chat's header offers, or null for a chat
245
+ * that does not run on a subscription. Codex product models are Codex
246
+ * subscriptions even before the catalog lists them.
247
+ */
248
+ export function subscriptionAccountProvider(
249
+ modelId: string,
250
+ credentialSource: ClientModel["credentialSource"],
251
+ ): string | null {
252
+ if (isCodexProductModel(modelId)) return "codex";
253
+ return credentialSource?.kind === "connected_subscription" ? credentialSource.provider : null;
254
+ }
255
+
256
+ /** Everything the account menu shows, from the neutral state. */
257
+ export function subscriptionAccountMenuContent(state: SubscriptionAccountState) {
258
+ const { name } = subscriptionProviderPresentation(state.provider);
259
+ const current = state.current;
260
+ // A failed read does not know the selection; never claim Automatic for it.
261
+ const unknown = state.unavailable && !current && !state.currentHidden;
262
+ const displayName = current
263
+ ? accountLabel(current)
264
+ : state.currentHidden
265
+ ? "Account unavailable"
266
+ : unknown
267
+ ? "Accounts unavailable"
268
+ : "Automatic";
269
+ const status = current ? accountStatus(current) : null;
270
+ const selectionLabel = state.waiting
271
+ ? "Limit reached"
272
+ : state.serving && (current || state.currentHidden)
273
+ ? "Current account"
274
+ : !state.automatic && !unknown && (!current || current.id === state.chosenId)
275
+ ? "Chosen account"
276
+ : current
277
+ ? "Current account"
278
+ : "Account selection";
279
+ const usageNearLimit = nearLimit(current?.usage);
280
+ const tone: "ok" | "warn" | "bad" =
281
+ current?.status === "needs_relogin" || current?.status === "error"
282
+ ? "bad"
283
+ : status || state.waiting || usageNearLimit
284
+ ? "warn"
285
+ : "ok";
286
+ const usage: SubscriptionAccountMenuUsage = !current
287
+ ? {
288
+ message: state.currentHidden
289
+ ? "Account usage hidden"
290
+ : unknown
291
+ ? "Usage unavailable"
292
+ : "Choose an account to see usage",
293
+ }
294
+ : state.usageCheck === "checking"
295
+ ? { checking: true }
296
+ : state.usageCheck === "failed"
297
+ ? { unavailable: true }
298
+ : subscriptionAccountUsage(current.usage);
299
+ const accounts: SubscriptionAccountMenuRow[] = state.accounts.map((account) => ({
300
+ id: account.id,
301
+ label: accountLabel(account),
302
+ plan: account.plan,
303
+ status: accountStatus(account),
304
+ detail: [
305
+ accountLabel(account),
306
+ account.email,
307
+ account.plan,
308
+ accountSource(account),
309
+ accountStatus(account),
310
+ ]
311
+ .filter(Boolean)
312
+ .join(" · "),
313
+ personal: account.source === "personal",
314
+ disabled: !account.choosable,
315
+ // The current account's usage is already shown above the list.
316
+ usageSummary:
317
+ account.id === current?.id || state.usageCheck === "checking"
318
+ ? undefined
319
+ : subscriptionAccountUsage(account.usage).summary,
320
+ }));
321
+ return {
322
+ ariaLabel: [
323
+ `${name} account`,
324
+ displayName,
325
+ state.waiting ? "Limit reached" : (status ?? (usageNearLimit ? "Near its limit" : null)),
326
+ ]
327
+ .filter(Boolean)
328
+ .join(" · "),
329
+ selectionLabel,
330
+ displayName,
331
+ identity: current?.email && current.email !== displayName ? current.email : null,
332
+ metadata: current
333
+ ? [current.plan, accountSource(current), status].filter(Boolean).join(" · ") ||
334
+ `${name} subscription`
335
+ : `${name} subscription`,
336
+ tone,
337
+ usage,
338
+ accounts,
339
+ selectedId: state.automatic || unknown ? null : state.chosenId,
340
+ automaticSelected: state.automatic && !unknown,
341
+ actionLabel: state.waiting ? "Retry with" : "Use for next turn",
342
+ automaticLabel: "Automatic",
343
+ emptyMessage: state.unavailable ? "Accounts unavailable." : "No accounts available.",
344
+ error: state.mutationError ? `Couldn't switch: ${state.mutationError}` : null,
345
+ note:
346
+ state.appliedTo === "waiting_turn"
347
+ ? "Selection saved. Capacity is being rechecked."
348
+ : state.appliedTo === "next_turn"
349
+ ? "Selection saved for the next turn."
350
+ : state.waiting
351
+ ? "Changing accounts retries the waiting turn."
352
+ : "Applies next turn. The current turn keeps its account.",
353
+ };
354
+ }
@@ -31,6 +31,7 @@ import { workspacesByOrganization } from "../org";
31
31
  import { hasWorkspacePermission } from "../permissions";
32
32
  import { readChatDirectory, recordChatVisit } from "./chat-directory";
33
33
  import {
34
+ extendChatSwitcher,
34
35
  isSwitcherKey,
35
36
  openChatSwitcher,
36
37
  stepChatSwitcher,
@@ -575,6 +576,16 @@ export function ActionsProvider(props: { children: ReactNode }) {
575
576
  const current = switcherRef.current;
576
577
  if (current) setSwitcher({ ...current, index });
577
578
  }}
579
+ onDirectoryChange={() => {
580
+ const current = switcherRef.current;
581
+ if (!current) return;
582
+ const next = extendChatSwitcher(
583
+ current,
584
+ readChatDirectory(subjectId, workspaceId),
585
+ reachableRef.current,
586
+ );
587
+ if (next !== current) setSwitcher(next);
588
+ }}
578
589
  onPick={pickSwitcherChat}
579
590
  onDismiss={() => setSwitcher(null)}
580
591
  />
@@ -9,7 +9,13 @@ import {
9
9
  type Chord,
10
10
  } from "./chords";
11
11
  import type { ChatRecord } from "./chat-directory";
12
- import { isSwitcherKey, openChatSwitcher, stepChatSwitcher, SWITCHER_LIMIT } from "./chat-switcher";
12
+ import {
13
+ extendChatSwitcher,
14
+ isSwitcherKey,
15
+ openChatSwitcher,
16
+ stepChatSwitcher,
17
+ SWITCHER_LIMIT,
18
+ } from "./chat-switcher";
13
19
  import { LOOSE_MATCH_BELOW, rankLabel, rankWithKeywords } from "./rank";
14
20
  import { appActions, stepWorkspace } from "./registry";
15
21
 
@@ -296,9 +302,58 @@ describe("chat switcher", () => {
296
302
  expect(state.ids[state.index]).toBe("b");
297
303
  });
298
304
 
299
- test("the list stops at ten chats", () => {
300
- const ids = Array.from({ length: 15 }, (_, index) => `c${index}`);
301
- expect(openChatSwitcher(directory(ids), "c0", false)!.ids).toHaveLength(SWITCHER_LIMIT);
305
+ test("past the opened chats it carries on through other chats by latest activity", () => {
306
+ const rows = [
307
+ record("a", { updatedAt: 1 }),
308
+ record("b", { updatedAt: 2 }),
309
+ record("older", { updatedAt: 5 }),
310
+ record("newer", { updatedAt: 9, workspaceId: "other" }),
311
+ record("gone", { updatedAt: 8, archived: true }),
312
+ record("child", { updatedAt: 7, row: { parentSessionId: "a" } as ChatRecord["row"] }),
313
+ ];
314
+ const state = openChatSwitcher(directory(["a", "b"], rows), "a", false)!;
315
+ expect(state.ids).toEqual(["a", "b", "newer", "older"]);
316
+ expect(state.viewed).toBe(2);
317
+ // Tab keeps going into the older chats before it wraps.
318
+ let stepped = stepChatSwitcher(state, 1);
319
+ stepped = stepChatSwitcher(stepped, 1);
320
+ expect(stepped.ids[stepped.index]).toBe("older");
321
+ });
322
+
323
+ test("with no opened chats yet, the most recently active chat is the target", () => {
324
+ const rows = [record("a", { updatedAt: 1 }), record("b", { updatedAt: 2 })];
325
+ const state = openChatSwitcher(directory([], rows), null, false)!;
326
+ expect(state.ids).toEqual(["b", "a"]);
327
+ expect(state.viewed).toBe(0);
328
+ expect(state.ids[state.index]).toBe("b");
329
+ });
330
+
331
+ test("chats that load while it is open join at the end, and nothing else moves", () => {
332
+ const start = directory(["a", "b"], [record("a"), record("b"), record("c", { updatedAt: 3 })]);
333
+ const state = stepChatSwitcher(openChatSwitcher(start, "a", false)!, 1);
334
+ expect(extendChatSwitcher(state, start)).toBe(state);
335
+ const later = directory(
336
+ ["a", "b"],
337
+ [record("a"), record("b"), record("c", { updatedAt: 3 }), record("d", { updatedAt: 9 })],
338
+ );
339
+ const grown = extendChatSwitcher(state, later);
340
+ expect(grown.ids).toEqual(["a", "b", "c", "d"]);
341
+ expect(grown.index).toBe(state.index);
342
+ expect(grown.viewed).toBe(2);
343
+ });
344
+
345
+ test("the list stops at its limit", () => {
346
+ const ids = Array.from({ length: SWITCHER_LIMIT + 20 }, (_, index) => `c${index}`);
347
+ const rows = Array.from({ length: 30 }, (_, index) =>
348
+ record(`x${index}`, { updatedAt: index }),
349
+ );
350
+ const state = openChatSwitcher(
351
+ directory(ids, [...ids.map((id) => record(id)), ...rows]),
352
+ "c0",
353
+ false,
354
+ )!;
355
+ expect(state.ids).toHaveLength(SWITCHER_LIMIT);
356
+ expect(extendChatSwitcher(state, directory(ids, rows))).toBe(state);
302
357
  });
303
358
 
304
359
  test("only Control+Tab opens it", () => {
@@ -5,50 +5,103 @@
5
5
  * chat (press again to return); holding Control shows the list, each Tab moves
6
6
  * down it (Shift+Tab up), and releasing Control opens the highlighted chat.
7
7
  *
8
- * The list is read once when the switcher opens, so it holds still while the
9
- * person cycles through it.
8
+ * Past the chats someone opened, the list carries on through the other chats
9
+ * the app knows, most recently active first, so holding Tab keeps going back
10
+ * in time. The list is read when the switcher opens and only ever grows at
11
+ * the end (as more chats load), so it holds still while the person cycles.
10
12
  */
11
- import type { ChatDirectorySnapshot } from "./chat-directory";
13
+ import type { ChatDirectorySnapshot, ChatRecord } from "./chat-directory";
12
14
 
13
15
  /** At most this many chats; older ones are a search away in ⌘K. */
14
- export const SWITCHER_LIMIT = 10;
16
+ export const SWITCHER_LIMIT = 100;
15
17
  /** A press shorter than this switches without ever drawing the list. */
16
18
  export const SWITCHER_SHOW_DELAY_MS = 140;
17
19
 
18
20
  export type ChatSwitcherState = Readonly<{
19
- /** Chats in the order shown, most recently viewed first. */
21
+ /** Chats in the order shown: recently viewed first, then recently active. */
20
22
  ids: readonly string[];
23
+ /** How many of `ids`, from the front, are chats the person opened recently. */
24
+ viewed: number;
21
25
  /** The highlighted chat. */
22
26
  index: number;
23
27
  /** Whether the list is drawn (after the delay, or once Tab is pressed again). */
24
28
  visible: boolean;
25
29
  }>;
26
30
 
31
+ type SwitcherDirectory = Pick<ChatDirectorySnapshot, "recent" | "rows">;
32
+
33
+ function switchable(
34
+ record: ChatRecord | undefined,
35
+ reachable: (workspaceId: string) => boolean,
36
+ ): boolean {
37
+ if (!record || record.archived || !reachable(record.workspaceId)) return false;
38
+ // Subagent chats live under their parent, as in the sidebar.
39
+ return !record.row || record.row.parentSessionId === null;
40
+ }
41
+
42
+ /** Known chats not in `taken`, most recently active first. */
43
+ function moreChats(
44
+ directory: SwitcherDirectory,
45
+ taken: ReadonlySet<string>,
46
+ reachable: (workspaceId: string) => boolean,
47
+ room: number,
48
+ ): string[] {
49
+ if (room <= 0) return [];
50
+ const more: ChatRecord[] = [];
51
+ for (const record of directory.rows.values()) {
52
+ if (!taken.has(record.id) && switchable(record, reachable)) more.push(record);
53
+ }
54
+ more.sort((a, b) => b.updatedAt - a.updatedAt || (a.id < b.id ? -1 : 1));
55
+ return more.slice(0, room).map((record) => record.id);
56
+ }
57
+
27
58
  /**
28
- * The chats to switch between, most recently viewed first, with the open chat
29
- * (when there is one) at the front. Null when there is nowhere to switch to.
59
+ * The chats to switch between: the open chat (when there is one), the other
60
+ * recently viewed chats, then the rest the app knows by latest activity.
61
+ * Null when there is nowhere to switch to.
30
62
  */
31
63
  export function openChatSwitcher(
32
- directory: Pick<ChatDirectorySnapshot, "recent" | "rows">,
64
+ directory: SwitcherDirectory,
33
65
  currentChatId: string | null,
34
66
  backwards: boolean,
35
67
  /** Whether a workspace is still open to the person; chats elsewhere are left out. */
36
68
  reachable: (workspaceId: string) => boolean = () => true,
37
69
  ): ChatSwitcherState | null {
38
- const switchable = directory.recent.filter((id) => {
39
- const record = directory.rows.get(id);
40
- if (!record || record.archived || !reachable(record.workspaceId)) return false;
41
- // Subagent chats live under their parent, as in the sidebar.
42
- return !record.row || record.row.parentSessionId === null;
43
- });
44
- const ids = currentChatId
45
- ? [currentChatId, ...switchable.filter((id) => id !== currentChatId)]
46
- : switchable;
47
- const limited = ids.slice(0, SWITCHER_LIMIT);
70
+ const recent = directory.recent.filter(
71
+ (id) => id !== currentChatId && switchable(directory.rows.get(id), reachable),
72
+ );
73
+ const viewed = (currentChatId ? [currentChatId, ...recent] : recent).slice(0, SWITCHER_LIMIT);
74
+ const ids = [
75
+ ...viewed,
76
+ ...moreChats(directory, new Set(viewed), reachable, SWITCHER_LIMIT - viewed.length),
77
+ ];
48
78
  // Away from a chat (the inbox, a new chat) the most recent chat is the target.
49
79
  const first = currentChatId ? 1 : 0;
50
- if (limited.length <= first) return null;
51
- return { ids: limited, index: backwards ? limited.length - 1 : first, visible: false };
80
+ if (ids.length <= first) return null;
81
+ return {
82
+ ids,
83
+ viewed: viewed.length,
84
+ index: backwards ? ids.length - 1 : first,
85
+ visible: false,
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Chats that loaded while the list is open join at its end, so nothing the
91
+ * person is looking at moves. The same state when there is nothing new.
92
+ */
93
+ export function extendChatSwitcher(
94
+ state: ChatSwitcherState,
95
+ directory: SwitcherDirectory,
96
+ reachable: (workspaceId: string) => boolean = () => true,
97
+ ): ChatSwitcherState {
98
+ const more = moreChats(
99
+ directory,
100
+ new Set(state.ids),
101
+ reachable,
102
+ SWITCHER_LIMIT - state.ids.length,
103
+ );
104
+ return more.length === 0 ? state : { ...state, ids: [...state.ids, ...more] };
52
105
  }
53
106
 
54
107
  /** Tab moves down the list and Shift+Tab up, wrapping at the ends. */