@opengeni/react 4.4.1 → 4.5.1-canary.39832248373001

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 (654) hide show
  1. package/dist/app/app-state.js +15 -15
  2. package/dist/app/components/Composer.js +19 -19
  3. package/dist/app/components/artifacts/artifact-browse-controls.js +3 -3
  4. package/dist/app/components/artifacts/artifact-library.js +9 -9
  5. package/dist/app/components/artifacts/artifact-page-chrome.js +2 -2
  6. package/dist/app/components/artifacts/chat-interactive-block.js +14 -14
  7. package/dist/app/components/artifacts/inline-chat-image.js +22 -21
  8. package/dist/app/components/artifacts/retained-file-preview.js +24 -23
  9. package/dist/app/components/artifacts/retained-text-preview.js +2 -2
  10. package/dist/app/components/artifacts/site-audience.js +2 -2
  11. package/dist/app/components/artifacts/site-conversations.js +14 -13
  12. package/dist/app/components/artifacts/site-data.js +4 -4
  13. package/dist/app/components/artifacts/site-publishing.js +20 -20
  14. package/dist/app/components/artifacts/site-settings.js +25 -25
  15. package/dist/app/components/billing-class-mark.js +3 -3
  16. package/dist/app/components/capabilities/capability-detail-sheet.js +6 -6
  17. package/dist/app/components/capabilities/capability-logo-source.js +8 -8
  18. package/dist/app/components/capabilities/connector-tool-permissions.js +3 -3
  19. package/dist/app/components/capabilities/native-connect-setup.js +8 -8
  20. package/dist/app/components/capabilities/prepared-mcp-setup-card.js +10 -10
  21. package/dist/app/components/capabilities/session-capability-card.js +43 -41
  22. package/dist/app/components/capabilities/session-capability-card.js.map +1 -1
  23. package/dist/app/components/capabilities/session-chrome-card.js +20 -18
  24. package/dist/app/components/capabilities/session-custom-mcp-card.js +11 -11
  25. package/dist/app/components/capabilities/session-github-card.js +13 -13
  26. package/dist/app/components/capabilities/session-machine-card.js +19 -17
  27. package/dist/app/components/command-menu/chat-status.js +16 -15
  28. package/dist/app/components/command-menu/chat-switcher.js +19 -18
  29. package/dist/app/components/command-menu/chat-switcher.js.map +1 -1
  30. package/dist/app/components/command-menu/command-menu.js +29 -107
  31. package/dist/app/components/command-menu/command-menu.js.map +1 -1
  32. package/dist/app/components/command-menu/shortcut-sheet.js +9 -9
  33. package/dist/app/components/composer-mobile-plus-panel.js +9 -9
  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 +5 -5
  37. package/dist/app/components/credits/coupon-redeem.js +2 -2
  38. package/dist/app/components/credits/credit-refusal-notice.js +2 -2
  39. package/dist/app/components/desktop/app-shots.js +7 -7
  40. package/dist/app/components/desktop/this-computer.js +4 -4
  41. package/dist/app/components/feedback.js +3 -3
  42. package/dist/app/components/follow-up-repository-menu-body.js +2 -2
  43. package/dist/app/components/follow-up-repository-picker.js +1 -1
  44. package/dist/app/components/github-app-connect-launcher.js +2 -2
  45. package/dist/app/components/in-app-help-link.js +2 -2
  46. package/dist/app/components/machines/connect-machine-dialog.js +3 -3
  47. package/dist/app/components/markdown.js +5 -5
  48. package/dist/app/components/models/models-ui.js +3 -3
  49. package/dist/app/components/new-session-starters.js +2 -2
  50. package/dist/app/components/pickers.js +6 -6
  51. package/dist/app/components/rail/rail-context.js +3 -3
  52. package/dist/app/components/rail/rail-sections.js +51 -48
  53. package/dist/app/components/rail/session-header.js +29 -28
  54. package/dist/app/components/rail/session-list.js +50 -47
  55. package/dist/app/components/rail/session-row-content.d.ts +6 -2
  56. package/dist/app/components/rail/session-row-content.js +1 -1
  57. package/dist/app/components/rail/session-row-hover-details.js +17 -16
  58. package/dist/app/components/rail/session-shell.js +78 -75
  59. package/dist/app/components/rail/site-session-group-heading.d.ts +7 -1
  60. package/dist/app/components/rail/site-session-group-heading.js +20 -3
  61. package/dist/app/components/repository-picker.js +2 -2
  62. package/dist/app/components/session/agent-configuration-panel.js +18 -18
  63. package/dist/app/components/session/artifact-link-boundary.js +2 -2
  64. package/dist/app/components/session/artifact-session-page.js +5 -5
  65. package/dist/app/components/session/banners.js +7 -7
  66. package/dist/app/components/session/codex-account-indicator.js +10 -10
  67. package/dist/app/components/session/editable-artifacts-workspace.js +24 -24
  68. package/dist/app/components/session/failed-session-banner.js +6 -6
  69. package/dist/app/components/session/human-input.js +41 -37
  70. package/dist/app/components/session/inspector.js +61 -57
  71. package/dist/app/components/session/inspector.js.map +1 -1
  72. package/dist/app/components/session/message-actions.js +3 -3
  73. package/dist/app/components/session/message-resource-attachments.js +12 -11
  74. package/dist/app/components/session/message-resource-attachments.js.map +1 -1
  75. package/dist/app/components/session/model-account-indicator.js +9 -9
  76. package/dist/app/components/session/model-recovery-notice.js +3 -3
  77. package/dist/app/components/session/new-session-settings-menu.js +8 -8
  78. package/dist/app/components/session/sandbox-switcher.js +12 -12
  79. package/dist/app/components/session/sandbox-workspace.js +58 -54
  80. package/dist/app/components/session/search-markdown-highlight.js +6 -6
  81. package/dist/app/components/session/search-results-view.js +7 -7
  82. package/dist/app/components/session/session-admin-access.js +3 -3
  83. package/dist/app/components/session/session-admission-notice.js +5 -5
  84. package/dist/app/components/session/session-machine-access-notice.js +5 -5
  85. package/dist/app/components/session/session-search-dialog.js +8 -8
  86. package/dist/app/components/session/session-tenancy-control.d.ts +2 -0
  87. package/dist/app/components/session/session-tenancy-control.js +26 -11
  88. package/dist/app/components/session/session-tenancy-control.js.map +1 -1
  89. package/dist/app/components/session/session-usage-limit-section.js +4 -4
  90. package/dist/app/components/session/session-wait-status.js +8 -7
  91. package/dist/app/components/session/session-wait-status.js.map +1 -1
  92. package/dist/app/components/session/site-origin-link.d.ts +1 -0
  93. package/dist/app/components/session/site-origin-link.js +2 -2
  94. package/dist/app/components/session/subagents.js +13 -12
  95. package/dist/app/components/settings/row-select.js +3 -3
  96. package/dist/app/components/transcription-settings.js +4 -4
  97. package/dist/app/components/usage/usage-entry.js +5 -5
  98. package/dist/app/components/workspace-composer-plus.js +12 -12
  99. package/dist/app/embed/memory-navigation.js +2 -2
  100. package/dist/app/embed/session-app.js +196 -190
  101. package/dist/app/lib/actions/actions-provider.js +9 -9
  102. package/dist/app/lib/actions/held-modifier.d.ts +11 -0
  103. package/dist/app/lib/app-surfaces.js +2 -2
  104. package/dist/app/lib/codex-usage-query.js +6 -6
  105. package/dist/app/lib/composer-connectors.js +9 -9
  106. package/dist/app/lib/console-site.d.ts +6 -0
  107. package/dist/app/lib/console-site.js +14 -0
  108. package/dist/app/lib/console-text.js +2 -2
  109. package/dist/app/lib/events.js +13 -12
  110. package/dist/app/lib/failed-session-copy.js +3 -3
  111. package/dist/app/lib/model-access-onboarding.js +3 -3
  112. package/dist/app/lib/move-chat-to-machine.js +3 -3
  113. package/dist/app/lib/navigation.d.ts +5 -0
  114. package/dist/app/lib/navigation.js +1 -1
  115. package/dist/app/lib/routes.d.ts +17 -0
  116. package/dist/app/lib/routes.js +9 -3
  117. package/dist/app/lib/session-branch-cache.js +12 -11
  118. package/dist/app/lib/session-create.js +2 -2
  119. package/dist/app/lib/session-deep-link.js +2 -2
  120. package/dist/app/lib/session-failure-toasts.d.ts +8 -0
  121. package/dist/app/lib/session-group-pagination.js +12 -11
  122. package/dist/app/lib/session-hover-facts.js +12 -11
  123. package/dist/app/lib/session-model.js +2 -2
  124. package/dist/app/lib/session-rail.js +8 -7
  125. package/dist/app/lib/session-rename.js +2 -2
  126. package/dist/app/lib/session-ui-features.d.ts +6 -1
  127. package/dist/app/lib/session-ui-features.js +1 -1
  128. package/dist/app/lib/sessions-group.d.ts +43 -3
  129. package/dist/app/lib/sessions-group.js +19 -12
  130. package/dist/app/lib/shared-query.js +3 -3
  131. package/dist/app/lib/site-opened.d.ts +6 -0
  132. package/dist/app/lib/site-opened.js +10 -0
  133. package/dist/app/lib/turn-failure-analytics.js +5 -5
  134. package/dist/app/lib/use-duplicate-site.js +2 -2
  135. package/dist/app/lib/use-follow-up-repositories.js +2 -2
  136. package/dist/app/lib/use-session-list-hint-refresh.d.ts +20 -2
  137. package/dist/app/lib/use-session-list-hint-refresh.js +5 -1
  138. package/dist/app/lib/use-workspace-machines.js +5 -5
  139. package/dist/app/lib/use-workspace-model-catalog.js +7 -7
  140. package/dist/app/lib/use-workspace-rigs.js +7 -7
  141. package/dist/app/lib/workspace-navigation-preference.js +4 -4
  142. package/dist/app/lib/workspace-scope-context.js +3 -3
  143. package/dist/app/routes/artifacts.js +70 -87
  144. package/dist/app/routes/artifacts.js.map +1 -1
  145. package/dist/app/routes/retained-artifact.js +36 -35
  146. package/dist/app/routes/retained-artifact.js.map +1 -1
  147. package/dist/app/routes/session-unavailable.js +6 -4
  148. package/dist/app/routes/session.js +127 -123
  149. package/dist/app/routes/sessions-index-hydration.js +3 -3
  150. package/dist/app/routes/sessions-index.js +96 -94
  151. package/dist/app/routes/site-view.d.ts +11 -0
  152. package/dist/app/routes/site-view.js +597 -0
  153. package/dist/app/routes/site-view.js.map +1 -0
  154. package/dist/artifacts-document.js +4 -4
  155. package/dist/artifacts-presentation.js +4 -4
  156. package/dist/artifacts-spreadsheet.js +4 -4
  157. package/dist/artifacts.js +13 -13
  158. package/dist/{browser-viewer-RYYQSRTC.js → browser-viewer-VPK3CV2H.js} +7 -5
  159. package/dist/{chat-interactive-block-ABCRKXJ4.js → chat-interactive-block-AMDSW656.js} +5 -5
  160. package/dist/chunk-22GTC4MZ.js +15 -0
  161. package/dist/chunk-22GTC4MZ.js.map +1 -0
  162. package/dist/{chunk-RQDFYQHA.js → chunk-25LWDG5D.js} +6 -6
  163. package/dist/{chunk-U3HSFCON.js → chunk-2CKVVAGP.js} +15 -15
  164. package/dist/{chunk-F6LBGYS6.js → chunk-2DL6NJP5.js} +15 -15
  165. package/dist/{chunk-UHFWF6ZU.js → chunk-2FPS5H2D.js} +2 -2
  166. package/dist/{chunk-NAWXARTY.js → chunk-2KO2G3RI.js} +72 -6
  167. package/dist/chunk-2KO2G3RI.js.map +1 -0
  168. package/dist/{chunk-TWXIFWBD.js → chunk-34EU25RL.js} +2 -2
  169. package/dist/{chunk-PTGRFAMH.js → chunk-3ABPIUCK.js} +2 -2
  170. package/dist/{chunk-722UO6YQ.js → chunk-3PEXVG4D.js} +2 -2
  171. package/dist/{chunk-N3ZP4IDU.js → chunk-45WYYFP6.js} +2 -2
  172. package/dist/{chunk-HOJGAJAB.js → chunk-4MQLGMV2.js} +5 -5
  173. package/dist/{chunk-L7YURQI2.js → chunk-4U4GXWXS.js} +3 -3
  174. package/dist/{chunk-63VGE4OH.js → chunk-5HIOVXOX.js} +3 -3
  175. package/dist/{chunk-GFUUFM2O.js → chunk-5M23GZA2.js} +3 -3
  176. package/dist/{chunk-PM3OSANE.js → chunk-5MJHH72T.js} +14 -3
  177. package/dist/chunk-5MJHH72T.js.map +1 -0
  178. package/dist/{chunk-RKB2Z457.js → chunk-5VGJXWQ2.js} +2 -2
  179. package/dist/{chunk-6W3LF3DB.js → chunk-5YFY4SFC.js} +2 -12
  180. package/dist/chunk-5YFY4SFC.js.map +1 -0
  181. package/dist/{chunk-I6VUUEXH.js → chunk-6AFSZKZA.js} +3 -3
  182. package/dist/{chunk-FBMU3VK5.js → chunk-6DCEDIF6.js} +2 -2
  183. package/dist/{chunk-5MZTJMZ3.js → chunk-6MRY2RUZ.js} +13 -7
  184. package/dist/chunk-6MRY2RUZ.js.map +1 -0
  185. package/dist/{chunk-4EONHNJU.js → chunk-6O4VWKSO.js} +2 -2
  186. package/dist/chunk-756MKA2J.js +45 -0
  187. package/dist/chunk-756MKA2J.js.map +1 -0
  188. package/dist/{chunk-BSX2R4CW.js → chunk-767WCGAX.js} +6 -6
  189. package/dist/{chunk-7KGKDWWR.js → chunk-7HFLYNWN.js} +2 -2
  190. package/dist/{chunk-OSVHU2WU.js → chunk-7IYAHFPE.js} +2 -2
  191. package/dist/{chunk-4EAF3HSD.js → chunk-7J7PZB4S.js} +2 -2
  192. package/dist/{chunk-ADJJQSYC.js → chunk-7PUFAH4I.js} +34 -32
  193. package/dist/chunk-7PUFAH4I.js.map +1 -0
  194. package/dist/{chunk-OR37STQZ.js → chunk-7R2JQHBX.js} +3 -3
  195. package/dist/{chunk-QM5H4FPT.js → chunk-7VN6VC3D.js} +3 -3
  196. package/dist/{chunk-HWDGJFM4.js → chunk-A2E3ZF6N.js} +4 -4
  197. package/dist/{chunk-RGW24ZZM.js → chunk-A6CK4ENG.js} +19 -17
  198. package/dist/chunk-A6CK4ENG.js.map +1 -0
  199. package/dist/{chunk-4432A3HQ.js → chunk-A6T4FGE7.js} +4 -4
  200. package/dist/{chunk-73SOCVLS.js → chunk-AIEXYO2X.js} +3 -3
  201. package/dist/{chunk-U7TC2XJQ.js → chunk-AJPW3SV4.js} +3 -3
  202. package/dist/{chunk-46VBQG2D.js → chunk-AOUCHCSB.js} +5 -5
  203. package/dist/{chunk-HDHK3SXK.js → chunk-AT4K4F6S.js} +2 -2
  204. package/dist/{chunk-TQGJN5UZ.js → chunk-AW3QEFOF.js} +140 -522
  205. package/dist/chunk-AW3QEFOF.js.map +1 -0
  206. package/dist/{chunk-HRJQAFKR.js → chunk-AX6YJA5U.js} +2 -2
  207. package/dist/{chunk-HO5Y2OOX.js → chunk-BLPXOHG6.js} +6 -6
  208. package/dist/{chunk-DT7BORXG.js → chunk-BMJTNPWK.js} +2 -2
  209. package/dist/{chunk-HIHO2QE7.js → chunk-BT2MVGHT.js} +2 -2
  210. package/dist/{chunk-AOLE4IRZ.js → chunk-C535KSTY.js} +2 -2
  211. package/dist/{chunk-IVOA3DXA.js → chunk-CB574ERL.js} +4 -4
  212. package/dist/{chunk-IBTXYLBW.js → chunk-CCFWY4GF.js} +2 -2
  213. package/dist/{chunk-ZOC3OP6F.js → chunk-CCR33J7L.js} +2 -2
  214. package/dist/{chunk-NYZQ7LO7.js → chunk-CDUDKETD.js} +2 -2
  215. package/dist/{chunk-JTN3T4QN.js → chunk-D3RK3NGM.js} +4 -4
  216. package/dist/{chunk-IOKSNX74.js → chunk-D5OWJZQR.js} +2 -2
  217. package/dist/{chunk-BJIZ7PL7.js → chunk-D64Z4V26.js} +145 -29
  218. package/dist/chunk-D64Z4V26.js.map +1 -0
  219. package/dist/{chunk-XWWXIZFP.js → chunk-DFXZYNTX.js} +7 -7
  220. package/dist/{chunk-SQGXMHJO.js → chunk-DGLRZMXL.js} +3 -3
  221. package/dist/{chunk-GNEHAPKV.js → chunk-DJFTH2DI.js} +3 -3
  222. package/dist/{chunk-KWKGBGAF.js → chunk-DKCX643S.js} +11 -11
  223. package/dist/{chunk-HQG4SLTE.js → chunk-DYJGYGPB.js} +2 -2
  224. package/dist/{chunk-GTQ3SNEI.js → chunk-E36IC3LU.js} +2 -2
  225. package/dist/{chunk-CVG4FILQ.js → chunk-ECHYJP63.js} +253 -1008
  226. package/dist/chunk-ECHYJP63.js.map +1 -0
  227. package/dist/{chunk-Q35DT6I6.js → chunk-EH7TTYE6.js} +179 -170
  228. package/dist/chunk-EH7TTYE6.js.map +1 -0
  229. package/dist/{chunk-72J6C2AJ.js → chunk-EMCB6XKU.js} +2 -2
  230. package/dist/{chunk-3AA6RNGE.js → chunk-ENS6E4RZ.js} +2 -2
  231. package/dist/{chunk-AG7VGUIW.js → chunk-ERG355NM.js} +3 -3
  232. package/dist/{chunk-TSBE4KOQ.js → chunk-EWL6NDOO.js} +3 -3
  233. package/dist/{chunk-Z5WMLJKI.js → chunk-F2RMKGDQ.js} +89 -1
  234. package/dist/chunk-F2RMKGDQ.js.map +1 -0
  235. package/dist/{chunk-X7L4H4VG.js → chunk-F33EDYS7.js} +524 -426
  236. package/dist/chunk-F33EDYS7.js.map +1 -0
  237. package/dist/{chunk-HTT3FB7T.js → chunk-F3FN6DO6.js} +2 -2
  238. package/dist/{chunk-ST22GONV.js → chunk-FB3B45FP.js} +11 -11
  239. package/dist/{chunk-P5T36BA3.js → chunk-FRP64DEK.js} +2 -2
  240. package/dist/{chunk-KBF3SE7G.js → chunk-FSP334UU.js} +2 -2
  241. package/dist/{chunk-4VKA5O7T.js → chunk-FVL4B552.js} +9 -9
  242. package/dist/{chunk-VP62LPLW.js → chunk-G2BX56CN.js} +5 -5
  243. package/dist/{chunk-CSHBR2IZ.js → chunk-GDLDBR6B.js} +2 -2
  244. package/dist/{chunk-PN66T6JA.js → chunk-GFSOXB2K.js} +2 -2
  245. package/dist/{chunk-S4EZ3JUB.js → chunk-GZGQHQI7.js} +29 -29
  246. package/dist/chunk-H4IE2PYF.js +792 -0
  247. package/dist/chunk-H4IE2PYF.js.map +1 -0
  248. package/dist/{chunk-XFNLU7EW.js → chunk-H5M33DAL.js} +15 -6
  249. package/dist/chunk-H5M33DAL.js.map +1 -0
  250. package/dist/{chunk-BXRIQZAH.js → chunk-HNNM2GDN.js} +3 -3
  251. package/dist/{chunk-EU6XSQFM.js → chunk-HPB4KSV3.js} +2 -2
  252. package/dist/{chunk-QCD5Y7K5.js → chunk-HSQRYJ4P.js} +5 -5
  253. package/dist/{chunk-YXOKAG66.js → chunk-HUXDGWAN.js} +2 -2
  254. package/dist/{chunk-VUHPA3XQ.js → chunk-I66ZB6KD.js} +3 -3
  255. package/dist/{chunk-7CZTKBTI.js → chunk-IC7KNOBB.js} +5 -5
  256. package/dist/{chunk-KF3MF6FP.js → chunk-IECRGM6K.js} +3 -2
  257. package/dist/chunk-IECRGM6K.js.map +1 -0
  258. package/dist/{chunk-HGMWMK5K.js → chunk-IIO2MR3B.js} +2 -2
  259. package/dist/chunk-IJYL5BZM.js +38 -0
  260. package/dist/chunk-IJYL5BZM.js.map +1 -0
  261. package/dist/{chunk-L6RXRRN3.js → chunk-ILDOW2IQ.js} +3 -3
  262. package/dist/{chunk-O756O2I7.js → chunk-IPPVX5GF.js} +1 -1
  263. package/dist/{chunk-X7ASQHR6.js → chunk-IUK5QGP5.js} +2 -2
  264. package/dist/{chunk-5JZYPZ72.js → chunk-JFK7NTEA.js} +4 -4
  265. package/dist/chunk-JFK7NTEA.js.map +1 -0
  266. package/dist/{chunk-PIVGX42P.js → chunk-JNY5MT3I.js} +2 -2
  267. package/dist/chunk-JRSNCSZN.js +37 -0
  268. package/dist/chunk-JRSNCSZN.js.map +1 -0
  269. package/dist/{chunk-DDK4WFJ3.js → chunk-JWN7SLTO.js} +9 -9
  270. package/dist/{chunk-Q35YZVDZ.js → chunk-KFWVBTUH.js} +3 -3
  271. package/dist/{chunk-JXT5QDJC.js → chunk-KNFDWNCH.js} +5 -5
  272. package/dist/{chunk-AZVANYMB.js → chunk-KUNFUSZ7.js} +2 -2
  273. package/dist/{chunk-DXZNDKQD.js → chunk-LEEJBZ5B.js} +2 -2
  274. package/dist/{chunk-STUCI6QA.js → chunk-LEKBNKLD.js} +1 -1
  275. package/dist/{chunk-STUCI6QA.js.map → chunk-LEKBNKLD.js.map} +1 -1
  276. package/dist/{chunk-RSNYGEVZ.js → chunk-LKJ2C7PH.js} +8 -8
  277. package/dist/{chunk-RIMKJBCD.js → chunk-LMPTC4CX.js} +2 -2
  278. package/dist/{chunk-3KVWXKD6.js → chunk-LQ47YL6E.js} +2 -2
  279. package/dist/{chunk-GAIM5RNE.js → chunk-MJQBC7C5.js} +3 -3
  280. package/dist/{chunk-NWZW2WHN.js → chunk-MM7OKOTE.js} +6 -6
  281. package/dist/{chunk-FM4OUCC2.js → chunk-MOKYT3X3.js} +3 -3
  282. package/dist/{chunk-GZ64CASI.js → chunk-MVZYNZXE.js} +5 -4
  283. package/dist/chunk-MVZYNZXE.js.map +1 -0
  284. package/dist/{chunk-XRRSFQEV.js → chunk-NAZZLAWX.js} +2 -2
  285. package/dist/{chunk-XOFUXMPP.js → chunk-ND2WCWXI.js} +4 -4
  286. package/dist/{chunk-6L7U46Y2.js → chunk-NKNVIO66.js} +2 -2
  287. package/dist/{chunk-JKUICTLM.js → chunk-NLAFNMPK.js} +2 -2
  288. package/dist/{chunk-OO2T63BY.js → chunk-NML44AW2.js} +2 -2
  289. package/dist/chunk-NQQKOJDI.js +89 -0
  290. package/dist/chunk-NQQKOJDI.js.map +1 -0
  291. package/dist/{chunk-4LKNIGHB.js → chunk-O2SBHS2N.js} +2 -2
  292. package/dist/{chunk-RA3FNMWF.js → chunk-O4DYOSOL.js} +5 -5
  293. package/dist/{chunk-ZKYYZH6L.js → chunk-OFB6TUDC.js} +4 -4
  294. package/dist/{chunk-DWPOQ3S5.js → chunk-OTMWHZBY.js} +2 -2
  295. package/dist/{chunk-VVCDB2T7.js → chunk-PCJLH45G.js} +3 -3
  296. package/dist/{chunk-WSMYOLHG.js → chunk-PEKPWK5M.js} +2 -2
  297. package/dist/{chunk-PZ24CYDO.js → chunk-PFAUGEV5.js} +2 -2
  298. package/dist/{chunk-KTRKZRID.js → chunk-PKEKZ2VA.js} +5 -5
  299. package/dist/{chunk-6JKZILLF.js → chunk-PMD7V4N7.js} +3 -3
  300. package/dist/{chunk-B74GSYR6.js → chunk-PUTS4DYW.js} +2 -2
  301. package/dist/{chunk-ZRJCGBVV.js → chunk-PVR5EELP.js} +2 -2
  302. package/dist/{chunk-JSIDLTTG.js → chunk-PZ2V2XIK.js} +2 -2
  303. package/dist/{chunk-TMEQPODK.js → chunk-PZ37VDB5.js} +2 -2
  304. package/dist/{chunk-FLGUVRR7.js → chunk-QBADR2FO.js} +6 -6
  305. package/dist/{chunk-TGVVEGZG.js → chunk-QLIDZGPV.js} +6 -6
  306. package/dist/{chunk-LVONK3YQ.js → chunk-QRKTESVE.js} +2 -2
  307. package/dist/{chunk-HT5WSUC7.js → chunk-QXEDIDBZ.js} +3 -3
  308. package/dist/{chunk-WURSS6MP.js → chunk-R66YMYJU.js} +2 -2
  309. package/dist/{chunk-6PQNLL4E.js → chunk-R7XCJWCD.js} +11 -11
  310. package/dist/{chunk-4R3JCVID.js → chunk-RAMZTZOB.js} +360 -103
  311. package/dist/chunk-RAMZTZOB.js.map +1 -0
  312. package/dist/{chunk-QRVNI5V6.js → chunk-SCNEQFIW.js} +3 -3
  313. package/dist/{chunk-BNUPYHHZ.js → chunk-SD4PPZFB.js} +4 -4
  314. package/dist/{chunk-ROQOVH4N.js → chunk-SFAU5R5S.js} +3 -3
  315. package/dist/{chunk-R63QEVPK.js → chunk-SJORXXLV.js} +6 -6
  316. package/dist/{chunk-FBE6AIIW.js → chunk-SOKNCW5U.js} +2 -2
  317. package/dist/{chunk-JRXHSVD5.js → chunk-SOXZ4LGS.js} +68 -11
  318. package/dist/chunk-SOXZ4LGS.js.map +1 -0
  319. package/dist/{chunk-EF5SYXAY.js → chunk-SQDPHCK2.js} +22 -14
  320. package/dist/chunk-SQDPHCK2.js.map +1 -0
  321. package/dist/{chunk-NDF3SH3X.js → chunk-TDIOBPLA.js} +5 -5
  322. package/dist/{chunk-EHCUFCXM.js → chunk-TEPPPAJI.js} +17 -7
  323. package/dist/chunk-TEPPPAJI.js.map +1 -0
  324. package/dist/{chunk-33TPANCR.js → chunk-TFK4KFKA.js} +4 -4
  325. package/dist/{chunk-6NIB2KGJ.js → chunk-THVIT3PW.js} +22 -22
  326. package/dist/{chunk-HPPKLBTJ.js → chunk-TJQDL3JH.js} +2 -2
  327. package/dist/{chunk-FD4Q5KFL.js → chunk-TLL22FFO.js} +2 -2
  328. package/dist/{chunk-7DU35P5J.js → chunk-TN5T5HRZ.js} +7 -7
  329. package/dist/{chunk-JK7C5A4I.js → chunk-TR4HIKJ2.js} +8 -8
  330. package/dist/{chunk-HNYJEAES.js → chunk-UGEWCWVV.js} +3 -3
  331. package/dist/chunk-ULYQEFNH.js +529 -0
  332. package/dist/chunk-ULYQEFNH.js.map +1 -0
  333. package/dist/{chunk-H5EVWF6L.js → chunk-UNNJUJVD.js} +2 -2
  334. package/dist/{chunk-AD22P5X3.js → chunk-UUSAOIJR.js} +3 -3
  335. package/dist/{chunk-Z6DKXQG7.js → chunk-UXXFMF4X.js} +2 -2
  336. package/dist/{chunk-RGPYMHKI.js → chunk-V3K4RQO7.js} +9 -3
  337. package/dist/chunk-V3K4RQO7.js.map +1 -0
  338. package/dist/{chunk-UP4BE32Y.js → chunk-VO6RVVP7.js} +5 -5
  339. package/dist/{chunk-S4SC5SSV.js → chunk-VPNXQUUS.js} +11 -11
  340. package/dist/{chunk-7BST7BA6.js → chunk-VW3BBTMA.js} +1 -1
  341. package/dist/{chunk-CBY5CXBD.js → chunk-VWSFA4LJ.js} +2 -2
  342. package/dist/{chunk-MYNUBDU7.js → chunk-VYKW6TB2.js} +1 -1
  343. package/dist/chunk-VYKW6TB2.js.map +1 -0
  344. package/dist/{chunk-QEJTQTF5.js → chunk-W6T5HR3Z.js} +3 -3
  345. package/dist/{chunk-5JEIDFPD.js → chunk-WBPQ7OPC.js} +1 -1
  346. package/dist/{chunk-GZLLDA6P.js → chunk-WEFN327U.js} +2 -2
  347. package/dist/{chunk-ANHUMDJX.js → chunk-WNDTLK44.js} +2 -2
  348. package/dist/{chunk-DLOYMWUQ.js → chunk-WSLPZ43N.js} +7 -7
  349. package/dist/{chunk-2DS4UOYQ.js → chunk-WSZQNTVN.js} +2 -2
  350. package/dist/{chunk-LE2EDBXU.js → chunk-WUHB422G.js} +5 -5
  351. package/dist/{chunk-BJW7G6EF.js → chunk-WVX5AQXS.js} +3 -3
  352. package/dist/{chunk-5POTDNQT.js → chunk-WWOHORRO.js} +3 -3
  353. package/dist/{chunk-4W7VISE7.js → chunk-WYDZP5F2.js} +93 -94
  354. package/dist/chunk-WYDZP5F2.js.map +1 -0
  355. package/dist/{chunk-KZHW27BV.js → chunk-WYEPUXGL.js} +2 -2
  356. package/dist/{chunk-GALB2G3W.js → chunk-X2AH4DRF.js} +2 -2
  357. package/dist/{chunk-NCX5SAQY.js → chunk-XN6CALYY.js} +9 -9
  358. package/dist/{chunk-SUVEDKE2.js → chunk-XNACICAB.js} +3 -3
  359. package/dist/{chunk-FDNJVZRE.js → chunk-XU4I47IP.js} +4 -4
  360. package/dist/chunk-XV6ZYRHK.js +59 -0
  361. package/dist/chunk-XV6ZYRHK.js.map +1 -0
  362. package/dist/{chunk-WRLWLGEF.js → chunk-Y5E3XQ2S.js} +25 -2
  363. package/dist/{chunk-WRLWLGEF.js.map → chunk-Y5E3XQ2S.js.map} +1 -1
  364. package/dist/{chunk-U36PO27Q.js → chunk-YG3IJCM2.js} +3 -3
  365. package/dist/{chunk-UWJ5P5CU.js → chunk-YGSJWWT3.js} +3 -3
  366. package/dist/{chunk-APU42QDI.js → chunk-YO64YVYL.js} +105 -101
  367. package/dist/chunk-YO64YVYL.js.map +1 -0
  368. package/dist/{chunk-P5WABK2H.js → chunk-Z4GJB24B.js} +2 -2
  369. package/dist/{chunk-NLMTNEWW.js → chunk-Z6E6TUAE.js} +2 -2
  370. package/dist/{chunk-OBQVTCTW.js → chunk-ZX5H7LWD.js} +2 -2
  371. package/dist/components/browser-viewer.d.ts +1 -1
  372. package/dist/composer.js +8 -8
  373. package/dist/{computer-viewer-KEDVLD42.js → computer-viewer-VA5JONUH.js} +6 -6
  374. package/dist/connect.js +7 -7
  375. package/dist/desktop.js +2 -2
  376. package/dist/editor.js +2 -2
  377. package/dist/{embedded-new-voice-LFHWWYD2.js → embedded-new-voice-6BILAOUG.js} +6 -6
  378. package/dist/{embedded-voice-6QS4ANNX.js → embedded-voice-UDE4JRKB.js} +6 -6
  379. package/dist/{fleet-decision-row-QNSTP3VX.js → fleet-decision-row-NN2HXDX3.js} +2 -2
  380. package/dist/hooks/internal.d.ts +38 -0
  381. package/dist/hooks/use-client-config-flags.d.ts +12 -0
  382. package/dist/hooks/use-workspace-sessions.d.ts +10 -1
  383. package/dist/index.js +86 -80
  384. package/dist/interaction.js +8 -6
  385. package/dist/interaction.js.map +1 -1
  386. package/dist/{latest-question-AW3PPDUM.js → latest-question-4WDBECXB.js} +4 -3
  387. package/dist/{latest-question-AW3PPDUM.js.map → latest-question-4WDBECXB.js.map} +1 -1
  388. package/dist/machines.js +4 -4
  389. package/dist/messages/en.d.ts +3 -3
  390. package/dist/messages.js +1 -1
  391. package/dist/{model-policy-picker-menu-CURJ247L.js → model-policy-picker-menu-NRTO6FRP.js} +4 -4
  392. package/dist/{platform-activity-row-BMXXNZKX.js → platform-activity-row-ENQVIFTL.js} +2 -2
  393. package/dist/{queue-surface-implementation-2X5AXB6I.js → queue-surface-implementation-H4XSNHZE.js} +8 -6
  394. package/dist/{queue-surface-implementation-2X5AXB6I.js.map → queue-surface-implementation-H4XSNHZE.js.map} +1 -1
  395. package/dist/realtime.js +5 -5
  396. package/dist/{sandbox-files-4FBG3GS2.js → sandbox-files-IEHODU35.js} +9 -9
  397. package/dist/sandbox-files-IEHODU35.js.map +1 -0
  398. package/dist/session-app.js +198 -192
  399. package/dist/session-list-model.d.ts +1 -0
  400. package/dist/session-list-model.js +7 -1
  401. package/dist/{session-realtime-2XIB254N.js → session-realtime-JNKDSGH7.js} +3 -3
  402. package/dist/session-realtime-JNKDSGH7.js.map +1 -0
  403. package/dist/session-realtime.js +2 -2
  404. package/dist/session-ui.js +48 -43
  405. package/dist/session.js +20 -18
  406. package/dist/sites.js +2 -2
  407. package/dist/terminal.js +2 -2
  408. package/dist/this-computer.js +3 -3
  409. package/dist/timeline/invoked-tool.d.ts +5 -0
  410. package/dist/timeline/tool-display-name.d.ts +2 -2
  411. package/dist/timeline/tool-icon.d.ts +14 -0
  412. package/dist/timeline/tool-presentation.d.ts +8 -3
  413. package/dist/{timeline-annotation-markers-X4K2IEOO.js → timeline-annotation-markers-ZSOFW7PG.js} +2 -2
  414. package/dist/{timeline-annotation-selection-MEHBW676.js → timeline-annotation-selection-YWV2UC34.js} +2 -2
  415. package/dist/{timeline-annotations-dialog-U2FPQ3UY.js → timeline-annotations-dialog-ZWQVX2HI.js} +3 -3
  416. package/dist/timeline-model.js +16 -14
  417. package/dist/ui/access-list.js +7 -7
  418. package/dist/ui/cadence-picker.js +2 -2
  419. package/dist/ui/list-row.js +3 -3
  420. package/dist/ui/revision-history.js +2 -2
  421. package/dist/ui/role-select.js +3 -3
  422. package/dist/ui/select-menu.js +2 -2
  423. package/dist/usage.js +3 -3
  424. package/dist/workbench.js +4 -4
  425. package/package.json +4 -4
  426. package/src/app/app-state.tsx +3 -1
  427. package/src/app/components/capabilities/session-machine-card.tsx +9 -2
  428. package/src/app/components/rail/session-list.tsx +254 -44
  429. package/src/app/components/rail/session-row-content.tsx +24 -2
  430. package/src/app/components/rail/session-shell.tsx +14 -9
  431. package/src/app/components/rail/site-session-group-heading.tsx +59 -20
  432. package/src/app/components/session/session-tenancy-control.tsx +18 -0
  433. package/src/app/components/session/site-origin-link.test.tsx +73 -0
  434. package/src/app/components/session/site-origin-link.tsx +4 -2
  435. package/src/app/embed/memory-navigation.tsx +1 -0
  436. package/src/app/lib/actions/held-modifier.test.ts +101 -0
  437. package/src/app/lib/actions/held-modifier.ts +108 -0
  438. package/src/app/lib/console-site.tsx +38 -0
  439. package/src/app/lib/navigation.tsx +4 -0
  440. package/src/app/lib/routes.tsx +42 -0
  441. package/src/app/lib/session-failure-toasts.ts +26 -0
  442. package/src/app/lib/session-ui-features.tsx +18 -4
  443. package/src/app/lib/sessions-group.tsx +219 -30
  444. package/src/app/lib/site-opened.tsx +48 -0
  445. package/src/app/lib/site-session-groups.test.ts +173 -6
  446. package/src/app/lib/site-view-routes.test.ts +55 -0
  447. package/src/app/lib/use-session-list-hint-refresh.tsx +44 -4
  448. package/src/app/routes/artifacts.tsx +2 -29
  449. package/src/app/routes/session-transient-failures.test.tsx +343 -0
  450. package/src/app/routes/session-unavailable.tsx +74 -3
  451. package/src/app/routes/session.tsx +4 -13
  452. package/src/app/routes/sessions-index.tsx +13 -9
  453. package/src/app/routes/site-view.test.tsx +476 -0
  454. package/src/app/routes/site-view.tsx +583 -0
  455. package/src/components/browser-viewer.tsx +16 -2
  456. package/src/hooks/internal.ts +129 -6
  457. package/src/hooks/use-client-config-flags.ts +8 -0
  458. package/src/hooks/use-session-events.ts +83 -9
  459. package/src/hooks/use-workspace-sessions.ts +21 -1
  460. package/src/messages/en.ts +3 -3
  461. package/src/session-list-model.ts +4 -0
  462. package/src/timeline/activity-rail.tsx +3 -2
  463. package/src/timeline/invoked-tool.ts +14 -4
  464. package/src/timeline/projection.ts +11 -6
  465. package/src/timeline/rolling-activity.tsx +6 -2
  466. package/src/timeline/tool-display-name.ts +2 -2
  467. package/src/timeline/tool-icon.tsx +165 -0
  468. package/src/timeline/tool-presentation.ts +207 -48
  469. package/src/timeline/tool-renderers.tsx +1 -70
  470. package/styles/compiled.css +38 -0
  471. package/dist/chunk-22ZBT6CN.js +0 -50
  472. package/dist/chunk-22ZBT6CN.js.map +0 -1
  473. package/dist/chunk-4R3JCVID.js.map +0 -1
  474. package/dist/chunk-4W7VISE7.js.map +0 -1
  475. package/dist/chunk-5JZYPZ72.js.map +0 -1
  476. package/dist/chunk-5MZTJMZ3.js.map +0 -1
  477. package/dist/chunk-6W3LF3DB.js.map +0 -1
  478. package/dist/chunk-ADJJQSYC.js.map +0 -1
  479. package/dist/chunk-APU42QDI.js.map +0 -1
  480. package/dist/chunk-BJIZ7PL7.js.map +0 -1
  481. package/dist/chunk-CVG4FILQ.js.map +0 -1
  482. package/dist/chunk-EF5SYXAY.js.map +0 -1
  483. package/dist/chunk-EHCUFCXM.js.map +0 -1
  484. package/dist/chunk-GZ64CASI.js.map +0 -1
  485. package/dist/chunk-JRXHSVD5.js.map +0 -1
  486. package/dist/chunk-KF3MF6FP.js.map +0 -1
  487. package/dist/chunk-MYNUBDU7.js.map +0 -1
  488. package/dist/chunk-NAWXARTY.js.map +0 -1
  489. package/dist/chunk-PM3OSANE.js.map +0 -1
  490. package/dist/chunk-Q35DT6I6.js.map +0 -1
  491. package/dist/chunk-R25ZKOZR.js +0 -24
  492. package/dist/chunk-R25ZKOZR.js.map +0 -1
  493. package/dist/chunk-RGPYMHKI.js.map +0 -1
  494. package/dist/chunk-RGW24ZZM.js.map +0 -1
  495. package/dist/chunk-TQGJN5UZ.js.map +0 -1
  496. package/dist/chunk-X7L4H4VG.js.map +0 -1
  497. package/dist/chunk-XFNLU7EW.js.map +0 -1
  498. package/dist/chunk-Z5WMLJKI.js.map +0 -1
  499. /package/dist/{browser-viewer-RYYQSRTC.js.map → app/lib/console-site.js.map} +0 -0
  500. /package/dist/{chat-interactive-block-ABCRKXJ4.js.map → app/lib/site-opened.js.map} +0 -0
  501. /package/dist/{computer-viewer-KEDVLD42.js.map → browser-viewer-VPK3CV2H.js.map} +0 -0
  502. /package/dist/{embedded-new-voice-LFHWWYD2.js.map → chat-interactive-block-AMDSW656.js.map} +0 -0
  503. /package/dist/{chunk-RQDFYQHA.js.map → chunk-25LWDG5D.js.map} +0 -0
  504. /package/dist/{chunk-U3HSFCON.js.map → chunk-2CKVVAGP.js.map} +0 -0
  505. /package/dist/{chunk-F6LBGYS6.js.map → chunk-2DL6NJP5.js.map} +0 -0
  506. /package/dist/{chunk-UHFWF6ZU.js.map → chunk-2FPS5H2D.js.map} +0 -0
  507. /package/dist/{chunk-TWXIFWBD.js.map → chunk-34EU25RL.js.map} +0 -0
  508. /package/dist/{chunk-PTGRFAMH.js.map → chunk-3ABPIUCK.js.map} +0 -0
  509. /package/dist/{chunk-722UO6YQ.js.map → chunk-3PEXVG4D.js.map} +0 -0
  510. /package/dist/{chunk-N3ZP4IDU.js.map → chunk-45WYYFP6.js.map} +0 -0
  511. /package/dist/{chunk-HOJGAJAB.js.map → chunk-4MQLGMV2.js.map} +0 -0
  512. /package/dist/{chunk-L7YURQI2.js.map → chunk-4U4GXWXS.js.map} +0 -0
  513. /package/dist/{chunk-63VGE4OH.js.map → chunk-5HIOVXOX.js.map} +0 -0
  514. /package/dist/{chunk-GFUUFM2O.js.map → chunk-5M23GZA2.js.map} +0 -0
  515. /package/dist/{chunk-RKB2Z457.js.map → chunk-5VGJXWQ2.js.map} +0 -0
  516. /package/dist/{chunk-I6VUUEXH.js.map → chunk-6AFSZKZA.js.map} +0 -0
  517. /package/dist/{chunk-FBMU3VK5.js.map → chunk-6DCEDIF6.js.map} +0 -0
  518. /package/dist/{chunk-4EONHNJU.js.map → chunk-6O4VWKSO.js.map} +0 -0
  519. /package/dist/{chunk-BSX2R4CW.js.map → chunk-767WCGAX.js.map} +0 -0
  520. /package/dist/{chunk-7KGKDWWR.js.map → chunk-7HFLYNWN.js.map} +0 -0
  521. /package/dist/{chunk-OSVHU2WU.js.map → chunk-7IYAHFPE.js.map} +0 -0
  522. /package/dist/{chunk-4EAF3HSD.js.map → chunk-7J7PZB4S.js.map} +0 -0
  523. /package/dist/{chunk-OR37STQZ.js.map → chunk-7R2JQHBX.js.map} +0 -0
  524. /package/dist/{chunk-QM5H4FPT.js.map → chunk-7VN6VC3D.js.map} +0 -0
  525. /package/dist/{chunk-HWDGJFM4.js.map → chunk-A2E3ZF6N.js.map} +0 -0
  526. /package/dist/{chunk-4432A3HQ.js.map → chunk-A6T4FGE7.js.map} +0 -0
  527. /package/dist/{chunk-73SOCVLS.js.map → chunk-AIEXYO2X.js.map} +0 -0
  528. /package/dist/{chunk-U7TC2XJQ.js.map → chunk-AJPW3SV4.js.map} +0 -0
  529. /package/dist/{chunk-46VBQG2D.js.map → chunk-AOUCHCSB.js.map} +0 -0
  530. /package/dist/{chunk-HDHK3SXK.js.map → chunk-AT4K4F6S.js.map} +0 -0
  531. /package/dist/{chunk-HRJQAFKR.js.map → chunk-AX6YJA5U.js.map} +0 -0
  532. /package/dist/{chunk-HO5Y2OOX.js.map → chunk-BLPXOHG6.js.map} +0 -0
  533. /package/dist/{chunk-DT7BORXG.js.map → chunk-BMJTNPWK.js.map} +0 -0
  534. /package/dist/{chunk-HIHO2QE7.js.map → chunk-BT2MVGHT.js.map} +0 -0
  535. /package/dist/{chunk-AOLE4IRZ.js.map → chunk-C535KSTY.js.map} +0 -0
  536. /package/dist/{chunk-IVOA3DXA.js.map → chunk-CB574ERL.js.map} +0 -0
  537. /package/dist/{chunk-IBTXYLBW.js.map → chunk-CCFWY4GF.js.map} +0 -0
  538. /package/dist/{chunk-ZOC3OP6F.js.map → chunk-CCR33J7L.js.map} +0 -0
  539. /package/dist/{chunk-NYZQ7LO7.js.map → chunk-CDUDKETD.js.map} +0 -0
  540. /package/dist/{chunk-JTN3T4QN.js.map → chunk-D3RK3NGM.js.map} +0 -0
  541. /package/dist/{chunk-IOKSNX74.js.map → chunk-D5OWJZQR.js.map} +0 -0
  542. /package/dist/{chunk-XWWXIZFP.js.map → chunk-DFXZYNTX.js.map} +0 -0
  543. /package/dist/{chunk-SQGXMHJO.js.map → chunk-DGLRZMXL.js.map} +0 -0
  544. /package/dist/{chunk-GNEHAPKV.js.map → chunk-DJFTH2DI.js.map} +0 -0
  545. /package/dist/{chunk-KWKGBGAF.js.map → chunk-DKCX643S.js.map} +0 -0
  546. /package/dist/{chunk-HQG4SLTE.js.map → chunk-DYJGYGPB.js.map} +0 -0
  547. /package/dist/{chunk-GTQ3SNEI.js.map → chunk-E36IC3LU.js.map} +0 -0
  548. /package/dist/{chunk-72J6C2AJ.js.map → chunk-EMCB6XKU.js.map} +0 -0
  549. /package/dist/{chunk-3AA6RNGE.js.map → chunk-ENS6E4RZ.js.map} +0 -0
  550. /package/dist/{chunk-AG7VGUIW.js.map → chunk-ERG355NM.js.map} +0 -0
  551. /package/dist/{chunk-TSBE4KOQ.js.map → chunk-EWL6NDOO.js.map} +0 -0
  552. /package/dist/{chunk-HTT3FB7T.js.map → chunk-F3FN6DO6.js.map} +0 -0
  553. /package/dist/{chunk-ST22GONV.js.map → chunk-FB3B45FP.js.map} +0 -0
  554. /package/dist/{chunk-P5T36BA3.js.map → chunk-FRP64DEK.js.map} +0 -0
  555. /package/dist/{chunk-KBF3SE7G.js.map → chunk-FSP334UU.js.map} +0 -0
  556. /package/dist/{chunk-4VKA5O7T.js.map → chunk-FVL4B552.js.map} +0 -0
  557. /package/dist/{chunk-VP62LPLW.js.map → chunk-G2BX56CN.js.map} +0 -0
  558. /package/dist/{chunk-CSHBR2IZ.js.map → chunk-GDLDBR6B.js.map} +0 -0
  559. /package/dist/{chunk-PN66T6JA.js.map → chunk-GFSOXB2K.js.map} +0 -0
  560. /package/dist/{chunk-S4EZ3JUB.js.map → chunk-GZGQHQI7.js.map} +0 -0
  561. /package/dist/{chunk-BXRIQZAH.js.map → chunk-HNNM2GDN.js.map} +0 -0
  562. /package/dist/{chunk-EU6XSQFM.js.map → chunk-HPB4KSV3.js.map} +0 -0
  563. /package/dist/{chunk-QCD5Y7K5.js.map → chunk-HSQRYJ4P.js.map} +0 -0
  564. /package/dist/{chunk-YXOKAG66.js.map → chunk-HUXDGWAN.js.map} +0 -0
  565. /package/dist/{chunk-VUHPA3XQ.js.map → chunk-I66ZB6KD.js.map} +0 -0
  566. /package/dist/{chunk-7CZTKBTI.js.map → chunk-IC7KNOBB.js.map} +0 -0
  567. /package/dist/{chunk-HGMWMK5K.js.map → chunk-IIO2MR3B.js.map} +0 -0
  568. /package/dist/{chunk-L6RXRRN3.js.map → chunk-ILDOW2IQ.js.map} +0 -0
  569. /package/dist/{chunk-O756O2I7.js.map → chunk-IPPVX5GF.js.map} +0 -0
  570. /package/dist/{chunk-X7ASQHR6.js.map → chunk-IUK5QGP5.js.map} +0 -0
  571. /package/dist/{chunk-PIVGX42P.js.map → chunk-JNY5MT3I.js.map} +0 -0
  572. /package/dist/{chunk-DDK4WFJ3.js.map → chunk-JWN7SLTO.js.map} +0 -0
  573. /package/dist/{chunk-Q35YZVDZ.js.map → chunk-KFWVBTUH.js.map} +0 -0
  574. /package/dist/{chunk-JXT5QDJC.js.map → chunk-KNFDWNCH.js.map} +0 -0
  575. /package/dist/{chunk-AZVANYMB.js.map → chunk-KUNFUSZ7.js.map} +0 -0
  576. /package/dist/{chunk-DXZNDKQD.js.map → chunk-LEEJBZ5B.js.map} +0 -0
  577. /package/dist/{chunk-RSNYGEVZ.js.map → chunk-LKJ2C7PH.js.map} +0 -0
  578. /package/dist/{chunk-RIMKJBCD.js.map → chunk-LMPTC4CX.js.map} +0 -0
  579. /package/dist/{chunk-3KVWXKD6.js.map → chunk-LQ47YL6E.js.map} +0 -0
  580. /package/dist/{chunk-GAIM5RNE.js.map → chunk-MJQBC7C5.js.map} +0 -0
  581. /package/dist/{chunk-NWZW2WHN.js.map → chunk-MM7OKOTE.js.map} +0 -0
  582. /package/dist/{chunk-FM4OUCC2.js.map → chunk-MOKYT3X3.js.map} +0 -0
  583. /package/dist/{chunk-XRRSFQEV.js.map → chunk-NAZZLAWX.js.map} +0 -0
  584. /package/dist/{chunk-XOFUXMPP.js.map → chunk-ND2WCWXI.js.map} +0 -0
  585. /package/dist/{chunk-6L7U46Y2.js.map → chunk-NKNVIO66.js.map} +0 -0
  586. /package/dist/{chunk-JKUICTLM.js.map → chunk-NLAFNMPK.js.map} +0 -0
  587. /package/dist/{chunk-OO2T63BY.js.map → chunk-NML44AW2.js.map} +0 -0
  588. /package/dist/{chunk-4LKNIGHB.js.map → chunk-O2SBHS2N.js.map} +0 -0
  589. /package/dist/{chunk-RA3FNMWF.js.map → chunk-O4DYOSOL.js.map} +0 -0
  590. /package/dist/{chunk-ZKYYZH6L.js.map → chunk-OFB6TUDC.js.map} +0 -0
  591. /package/dist/{chunk-DWPOQ3S5.js.map → chunk-OTMWHZBY.js.map} +0 -0
  592. /package/dist/{chunk-VVCDB2T7.js.map → chunk-PCJLH45G.js.map} +0 -0
  593. /package/dist/{chunk-WSMYOLHG.js.map → chunk-PEKPWK5M.js.map} +0 -0
  594. /package/dist/{chunk-PZ24CYDO.js.map → chunk-PFAUGEV5.js.map} +0 -0
  595. /package/dist/{chunk-KTRKZRID.js.map → chunk-PKEKZ2VA.js.map} +0 -0
  596. /package/dist/{chunk-6JKZILLF.js.map → chunk-PMD7V4N7.js.map} +0 -0
  597. /package/dist/{chunk-B74GSYR6.js.map → chunk-PUTS4DYW.js.map} +0 -0
  598. /package/dist/{chunk-ZRJCGBVV.js.map → chunk-PVR5EELP.js.map} +0 -0
  599. /package/dist/{chunk-JSIDLTTG.js.map → chunk-PZ2V2XIK.js.map} +0 -0
  600. /package/dist/{chunk-TMEQPODK.js.map → chunk-PZ37VDB5.js.map} +0 -0
  601. /package/dist/{chunk-FLGUVRR7.js.map → chunk-QBADR2FO.js.map} +0 -0
  602. /package/dist/{chunk-TGVVEGZG.js.map → chunk-QLIDZGPV.js.map} +0 -0
  603. /package/dist/{chunk-LVONK3YQ.js.map → chunk-QRKTESVE.js.map} +0 -0
  604. /package/dist/{chunk-HT5WSUC7.js.map → chunk-QXEDIDBZ.js.map} +0 -0
  605. /package/dist/{chunk-WURSS6MP.js.map → chunk-R66YMYJU.js.map} +0 -0
  606. /package/dist/{chunk-6PQNLL4E.js.map → chunk-R7XCJWCD.js.map} +0 -0
  607. /package/dist/{chunk-QRVNI5V6.js.map → chunk-SCNEQFIW.js.map} +0 -0
  608. /package/dist/{chunk-BNUPYHHZ.js.map → chunk-SD4PPZFB.js.map} +0 -0
  609. /package/dist/{chunk-ROQOVH4N.js.map → chunk-SFAU5R5S.js.map} +0 -0
  610. /package/dist/{chunk-R63QEVPK.js.map → chunk-SJORXXLV.js.map} +0 -0
  611. /package/dist/{chunk-FBE6AIIW.js.map → chunk-SOKNCW5U.js.map} +0 -0
  612. /package/dist/{chunk-NDF3SH3X.js.map → chunk-TDIOBPLA.js.map} +0 -0
  613. /package/dist/{chunk-33TPANCR.js.map → chunk-TFK4KFKA.js.map} +0 -0
  614. /package/dist/{chunk-6NIB2KGJ.js.map → chunk-THVIT3PW.js.map} +0 -0
  615. /package/dist/{chunk-HPPKLBTJ.js.map → chunk-TJQDL3JH.js.map} +0 -0
  616. /package/dist/{chunk-FD4Q5KFL.js.map → chunk-TLL22FFO.js.map} +0 -0
  617. /package/dist/{chunk-7DU35P5J.js.map → chunk-TN5T5HRZ.js.map} +0 -0
  618. /package/dist/{chunk-JK7C5A4I.js.map → chunk-TR4HIKJ2.js.map} +0 -0
  619. /package/dist/{chunk-HNYJEAES.js.map → chunk-UGEWCWVV.js.map} +0 -0
  620. /package/dist/{chunk-H5EVWF6L.js.map → chunk-UNNJUJVD.js.map} +0 -0
  621. /package/dist/{chunk-AD22P5X3.js.map → chunk-UUSAOIJR.js.map} +0 -0
  622. /package/dist/{chunk-Z6DKXQG7.js.map → chunk-UXXFMF4X.js.map} +0 -0
  623. /package/dist/{chunk-UP4BE32Y.js.map → chunk-VO6RVVP7.js.map} +0 -0
  624. /package/dist/{chunk-S4SC5SSV.js.map → chunk-VPNXQUUS.js.map} +0 -0
  625. /package/dist/{chunk-7BST7BA6.js.map → chunk-VW3BBTMA.js.map} +0 -0
  626. /package/dist/{chunk-CBY5CXBD.js.map → chunk-VWSFA4LJ.js.map} +0 -0
  627. /package/dist/{chunk-QEJTQTF5.js.map → chunk-W6T5HR3Z.js.map} +0 -0
  628. /package/dist/{chunk-5JEIDFPD.js.map → chunk-WBPQ7OPC.js.map} +0 -0
  629. /package/dist/{chunk-GZLLDA6P.js.map → chunk-WEFN327U.js.map} +0 -0
  630. /package/dist/{chunk-ANHUMDJX.js.map → chunk-WNDTLK44.js.map} +0 -0
  631. /package/dist/{chunk-DLOYMWUQ.js.map → chunk-WSLPZ43N.js.map} +0 -0
  632. /package/dist/{chunk-2DS4UOYQ.js.map → chunk-WSZQNTVN.js.map} +0 -0
  633. /package/dist/{chunk-LE2EDBXU.js.map → chunk-WUHB422G.js.map} +0 -0
  634. /package/dist/{chunk-BJW7G6EF.js.map → chunk-WVX5AQXS.js.map} +0 -0
  635. /package/dist/{chunk-5POTDNQT.js.map → chunk-WWOHORRO.js.map} +0 -0
  636. /package/dist/{chunk-KZHW27BV.js.map → chunk-WYEPUXGL.js.map} +0 -0
  637. /package/dist/{chunk-GALB2G3W.js.map → chunk-X2AH4DRF.js.map} +0 -0
  638. /package/dist/{chunk-NCX5SAQY.js.map → chunk-XN6CALYY.js.map} +0 -0
  639. /package/dist/{chunk-SUVEDKE2.js.map → chunk-XNACICAB.js.map} +0 -0
  640. /package/dist/{chunk-FDNJVZRE.js.map → chunk-XU4I47IP.js.map} +0 -0
  641. /package/dist/{chunk-U36PO27Q.js.map → chunk-YG3IJCM2.js.map} +0 -0
  642. /package/dist/{chunk-UWJ5P5CU.js.map → chunk-YGSJWWT3.js.map} +0 -0
  643. /package/dist/{chunk-P5WABK2H.js.map → chunk-Z4GJB24B.js.map} +0 -0
  644. /package/dist/{chunk-NLMTNEWW.js.map → chunk-Z6E6TUAE.js.map} +0 -0
  645. /package/dist/{chunk-OBQVTCTW.js.map → chunk-ZX5H7LWD.js.map} +0 -0
  646. /package/dist/{embedded-voice-6QS4ANNX.js.map → computer-viewer-VA5JONUH.js.map} +0 -0
  647. /package/dist/{model-policy-picker-menu-CURJ247L.js.map → embedded-new-voice-6BILAOUG.js.map} +0 -0
  648. /package/dist/{sandbox-files-4FBG3GS2.js.map → embedded-voice-UDE4JRKB.js.map} +0 -0
  649. /package/dist/{fleet-decision-row-QNSTP3VX.js.map → fleet-decision-row-NN2HXDX3.js.map} +0 -0
  650. /package/dist/{session-realtime-2XIB254N.js.map → model-policy-picker-menu-NRTO6FRP.js.map} +0 -0
  651. /package/dist/{platform-activity-row-BMXXNZKX.js.map → platform-activity-row-ENQVIFTL.js.map} +0 -0
  652. /package/dist/{timeline-annotation-markers-X4K2IEOO.js.map → timeline-annotation-markers-ZSOFW7PG.js.map} +0 -0
  653. /package/dist/{timeline-annotation-selection-MEHBW676.js.map → timeline-annotation-selection-YWV2UC34.js.map} +0 -0
  654. /package/dist/{timeline-annotations-dialog-U2FPQ3UY.js.map → timeline-annotations-dialog-ZWQVX2HI.js.map} +0 -0
@@ -0,0 +1,26 @@
1
+ import { useEffect } from "react";
2
+
3
+ import { isApiErrorStatus } from "./app-api";
4
+ import { toast } from "./toast";
5
+
6
+ /**
7
+ * Toast the session page's read failures, once per error. The read hooks keep
8
+ * transient failures (a rolling deploy, a network blip) quiet while they retry
9
+ * and keep one stable error per outage, so an error reaches here only when it
10
+ * is definitive or outlasted the quiet window. A 404 renders the unavailable
11
+ * route instead of a toast.
12
+ */
13
+ export function useSessionFailureToasts(loadError: Error | null, streamError: Error | null): void {
14
+ useEffect(() => {
15
+ if (streamError && !isApiErrorStatus(streamError, 404)) {
16
+ toast.error("Event stream disconnected", {
17
+ description: streamError.message,
18
+ });
19
+ }
20
+ }, [streamError]);
21
+ useEffect(() => {
22
+ if (loadError && !isApiErrorStatus(loadError, 404)) {
23
+ toast.error("Failed to load session", { description: String(loadError) });
24
+ }
25
+ }, [loadError]);
26
+ }
@@ -19,15 +19,27 @@ export type SessionUiFeatures = Readonly<{
19
19
  * chat, ⌘/Ctrl+K, next and previous chat, the shortcut sheet).
20
20
  */
21
21
  keyboardShortcuts: boolean;
22
- /** The Opengeni logo and wordmark at the top of the chat list. */
22
+ /** The Opengeni logo and wordmark at the top of the chat list and the mobile header. */
23
23
  brand: boolean;
24
+ /**
25
+ * Opengeni's suggested first tasks under the new-chat composer (connect
26
+ * Slack, GitHub or Linear, schedule a brief, and so on).
27
+ */
28
+ starters: boolean;
24
29
  }>;
25
30
 
26
31
  export type SessionUiPreset = "app" | "companion" | "embed";
27
32
 
28
33
  export const SESSION_UI_PRESETS: Readonly<Record<SessionUiPreset, SessionUiFeatures>> = {
29
34
  /** The web app and the desktop app. */
30
- app: { chatList: true, dock: true, adminAccess: true, keyboardShortcuts: true, brand: true },
35
+ app: {
36
+ chatList: true,
37
+ dock: true,
38
+ adminAccess: true,
39
+ keyboardShortcuts: true,
40
+ brand: true,
41
+ starters: true,
42
+ },
31
43
  /**
32
44
  * First-party side panes (the Excel add-in): everything but admin access and
33
45
  * page-wide keyboard shortcuts.
@@ -38,11 +50,12 @@ export const SESSION_UI_PRESETS: Readonly<Record<SessionUiPreset, SessionUiFeatu
38
50
  adminAccess: false,
39
51
  keyboardShortcuts: false,
40
52
  brand: true,
53
+ starters: true,
41
54
  },
42
55
  /**
43
56
  * A customer product page (the default): the chat list, chats and composer,
44
- * without Opengeni's brand, the session panel, admin access or page-wide
45
- * shortcuts until the host turns them on.
57
+ * without Opengeni's brand and suggested tasks, the session panel, admin
58
+ * access or page-wide shortcuts until the host turns them on.
46
59
  */
47
60
  embed: {
48
61
  chatList: true,
@@ -50,6 +63,7 @@ export const SESSION_UI_PRESETS: Readonly<Record<SessionUiPreset, SessionUiFeatu
50
63
  adminAccess: false,
51
64
  keyboardShortcuts: false,
52
65
  brand: false,
66
+ starters: false,
53
67
  },
54
68
  };
55
69
 
@@ -7,7 +7,7 @@ import { formatWaitingSince } from "./format";
7
7
  import { awaitsPerson } from "./needs-you";
8
8
  import { sessionInputWait } from "./session-rail";
9
9
  import { sessionSiteOrigin, type SessionSiteOrigin } from "./session-site-origin";
10
- import type { SessionListTotals } from "@opengeni/sdk";
10
+ import type { SessionListTotals, SiteConversationGroup } from "@opengeni/sdk";
11
11
  import type { RailSession as Session } from "./session-list-entry";
12
12
 
13
13
  // The flat list rules are shared with native renderers through the pure
@@ -54,6 +54,11 @@ export {
54
54
  export type SessionTreeNode = {
55
55
  /** Presentation-only group; never persisted or used for session actions. */
56
56
  siteGroup?: SessionSiteOrigin | undefined;
57
+ /**
58
+ * A Site row's complete server counts, independent of which conversations
59
+ * are loaded. Absent when the row was built from loaded conversations only.
60
+ */
61
+ siteSummary?: SiteRowSummary | undefined;
57
62
  session: Session;
58
63
  children: SessionTreeNode[];
59
64
  /** A descendant (any depth, not the node itself) is running/queued/awaiting action. */
@@ -189,6 +194,26 @@ function railStatusCounts(
189
194
  node: SessionTreeNode,
190
195
  localDeliveryAttention: ReadonlyMap<string, number>,
191
196
  ): RailStatusCounts {
197
+ if (node.siteGroup && node.siteSummary) {
198
+ // Complete server counts; loaded rows add only browser-local send failures.
199
+ const summary = node.siteSummary;
200
+ const waiting = Math.min(summary.waiting, summary.active);
201
+ return {
202
+ total: summary.total,
203
+ sendFailed: node.children.reduce(
204
+ (total, child) => total + loadedLocalDeliveryFailureCount(child, localDeliveryAttention),
205
+ 0,
206
+ ),
207
+ attention: summary.attention,
208
+ attentionSince: summary.attentionSince,
209
+ failed: summary.failed,
210
+ active: summary.active - waiting,
211
+ queued: summary.queued,
212
+ waiting,
213
+ unread: summary.unread,
214
+ activeWork: summary.activeWork,
215
+ };
216
+ }
192
217
  if (node.siteGroup) {
193
218
  const counts = ownRailStatusCounts(node.session, localDeliveryAttention);
194
219
  for (const key of [
@@ -773,37 +798,188 @@ export function groupScheduledRuns(roots: SessionTreeNode[]): SessionTreeNode[]
773
798
  return grouped;
774
799
  }
775
800
 
776
- /** Explicit project placement wins; pins have already been split out. */
777
- export function groupSiteConversations(roots: SessionTreeNode[]): SessionTreeNode[] {
778
- const groups = new Map<string, SessionTreeNode[]>();
801
+ export type SiteRowSummary = Omit<SiteConversationGroup, "siteId" | "channelId" | "title">;
802
+
803
+ /**
804
+ * A Site row's stable id. Rows are per project when the rail shows projects,
805
+ * so a Site used from two projects appears in each; otherwise one per Site.
806
+ */
807
+ export function siteRowKey(siteId: string, channelId?: string | null): string {
808
+ return channelId === undefined ? `site:${siteId}` : `site:${siteId}:${channelId ?? "default"}`;
809
+ }
810
+
811
+ /** The Site and project a Site row stands for, or null for an ordinary id. */
812
+ export function parseSiteRowKey(
813
+ key: string,
814
+ ): { siteId: string; channelId?: string | null | undefined } | null {
815
+ const match = /^site:([0-9a-f-]{36})(?::(.+))?$/iu.exec(key);
816
+ if (!match) return null;
817
+ const channel = match[2];
818
+ return channel === undefined
819
+ ? { siteId: match[1]! }
820
+ : { siteId: match[1]!, channelId: channel === "default" ? null : channel };
821
+ }
822
+
823
+ function laterIso(a: string, b: string | undefined): string {
824
+ if (!b) return a;
825
+ return Date.parse(b) > Date.parse(a) ? b : a;
826
+ }
827
+
828
+ /** Merge per-project server groups into one per Site for rails without projects. */
829
+ function siteRowSummaries(
830
+ groups: readonly SiteConversationGroup[],
831
+ byProject: boolean,
832
+ ): Map<string, { origin: SessionSiteOrigin; channelId: string | null; summary: SiteRowSummary }> {
833
+ const rows = new Map<
834
+ string,
835
+ { origin: SessionSiteOrigin; channelId: string | null; summary: SiteRowSummary }
836
+ >();
837
+ for (const group of groups) {
838
+ const key = siteRowKey(group.siteId, byProject ? group.channelId : undefined);
839
+ const { siteId, channelId, title, ...summary } = group;
840
+ const current = rows.get(key);
841
+ if (!current) {
842
+ // A Site this viewer cannot read and that kept no label still needs a name.
843
+ const origin = { siteId, title: title.trim() || "Untitled Site" };
844
+ rows.set(key, { origin, channelId, summary: { ...summary } });
845
+ continue;
846
+ }
847
+ const merged = current.summary;
848
+ for (const field of [
849
+ "conversations",
850
+ "total",
851
+ "attention",
852
+ "failed",
853
+ "active",
854
+ "queued",
855
+ "waiting",
856
+ "unread",
857
+ "activeWork",
858
+ ] as const)
859
+ merged[field] += summary[field];
860
+ merged.attentionSince = earliestIso(merged.attentionSince, summary.attentionSince);
861
+ merged.updatedAt = laterIso(merged.updatedAt, summary.updatedAt);
862
+ merged.createdAt = laterIso(merged.createdAt, summary.createdAt);
863
+ }
864
+ return rows;
865
+ }
866
+
867
+ /** The presentation-only row a Site's conversations nest under. */
868
+ function siteRowSession(
869
+ key: string,
870
+ origin: SessionSiteOrigin,
871
+ channelId: string | null,
872
+ latest: Session | undefined,
873
+ summary: SiteRowSummary | undefined,
874
+ options: { workspaceId?: string | undefined; creator?: Session["createdBy"] | undefined },
875
+ ): Session {
876
+ const updatedAt = laterIso(summary?.updatedAt ?? latest?.updatedAt ?? "", latest?.updatedAt);
877
+ const createdAt = laterIso(summary?.createdAt ?? latest?.createdAt ?? "", latest?.createdAt);
878
+ // Only the fields the rail reads for ordering, grouping and links. It is
879
+ // never sent to the server or used for a session action.
880
+ return {
881
+ id: key,
882
+ workspaceId: latest?.workspaceId ?? options.workspaceId ?? "",
883
+ accountId: latest?.accountId ?? "",
884
+ rootSessionId: key,
885
+ parentSessionId: null,
886
+ channelId,
887
+ status: "idle",
888
+ title: origin.title,
889
+ displayTitle: origin.title,
890
+ renameSeed: origin.title,
891
+ titleSource: "user",
892
+ createdBy: latest?.createdBy ?? options.creator ?? { kind: "subject", subjectId: "" },
893
+ effectiveControl: { state: "active" },
894
+ inputWait: null,
895
+ pinned: false,
896
+ pinnedAt: null,
897
+ archived: false,
898
+ archivedAt: null,
899
+ unread: false,
900
+ activelyWorking: false,
901
+ lastSequence: 0,
902
+ treeStats: undefined,
903
+ scheduledTaskId: null,
904
+ siteOrigin: origin,
905
+ metadata: { _opengeniSiteOrigin: origin },
906
+ createdAt,
907
+ updatedAt,
908
+ } as unknown as Session;
909
+ }
910
+
911
+ /**
912
+ * Fold Site conversations into stable Site rows. `groups` are the complete
913
+ * rows from the server; loaded conversations (an expanded Site, the open
914
+ * session, a legacy labelled chat) join their row, so which session is
915
+ * selected never decides whether a Site or its conversations are listed.
916
+ * Pins have already been split out.
917
+ */
918
+ export function attachSiteRows(
919
+ roots: SessionTreeNode[],
920
+ options: {
921
+ groups?: readonly SiteConversationGroup[] | undefined;
922
+ /** Rows per project when the rail shows projects. */
923
+ byProject?: boolean | undefined;
924
+ workspaceId?: string | undefined;
925
+ creator?: Session["createdBy"] | undefined;
926
+ } = {},
927
+ ): SessionTreeNode[] {
928
+ const byProject = options.byProject ?? false;
929
+ const rows = new Map<
930
+ string,
931
+ {
932
+ origin: SessionSiteOrigin;
933
+ channelId: string | null;
934
+ summary?: SiteRowSummary | undefined;
935
+ members: SessionTreeNode[];
936
+ }
937
+ >();
938
+ for (const [key, row] of siteRowSummaries(options.groups ?? [], byProject))
939
+ rows.set(key, { ...row, members: [] });
940
+ const rest: SessionTreeNode[] = [];
779
941
  for (const node of roots) {
780
942
  const origin = sessionSiteOrigin(node.session);
781
- if (!origin || node.session.channelId || node.session.parentSessionId) continue;
782
- const members = groups.get(origin.siteId) ?? [];
783
- members.push(node);
784
- groups.set(origin.siteId, members);
943
+ if (!origin || node.session.parentSessionId) {
944
+ rest.push(node);
945
+ continue;
946
+ }
947
+ const channelId = node.session.channelId ?? null;
948
+ const key = siteRowKey(origin.siteId, byProject ? channelId : undefined);
949
+ const row = rows.get(key) ?? { origin, channelId, members: [] };
950
+ row.members.push(node);
951
+ rows.set(key, row);
785
952
  }
786
- const emitted = new Set<string>();
787
- return roots.flatMap((node) => {
788
- const origin = sessionSiteOrigin(node.session);
789
- const members =
790
- origin && !node.session.channelId && !node.session.parentSessionId
791
- ? groups.get(origin.siteId)
792
- : undefined;
793
- if (!members || !origin) return [node];
794
- if (emitted.has(origin.siteId)) return [];
795
- emitted.add(origin.siteId);
796
- members.sort((a, b) => compareSessionActivity(a.session, b.session));
797
- const latest = members[0]!;
798
- return [
799
- {
800
- siteGroup: origin,
801
- session: { ...latest.session, id: `site:${origin.siteId}`, treeStats: undefined },
802
- children: members,
803
- hasActiveDescendant: members.some(nodeIsActive),
804
- },
805
- ];
953
+ const siteRows = [...rows].map(([key, row]): SessionTreeNode => {
954
+ const members = row.members.sort((a, b) => compareSessionActivity(a.session, b.session));
955
+ const summary = row.summary;
956
+ return {
957
+ siteGroup: row.origin,
958
+ ...(summary ? { siteSummary: summary } : {}),
959
+ session: siteRowSession(
960
+ key,
961
+ row.origin,
962
+ row.channelId,
963
+ members[0]?.session,
964
+ summary,
965
+ options,
966
+ ),
967
+ children: members,
968
+ hasActiveDescendant:
969
+ members.some(nodeIsActive) ||
970
+ Boolean(summary && summary.active + summary.queued + summary.attention > 0),
971
+ };
806
972
  });
973
+ return [...rest, ...siteRows];
974
+ }
975
+
976
+ /**
977
+ * How many conversations a Site row stands for, loaded or not. The server
978
+ * counts Site conversations; an older chat that only carries a Site label
979
+ * joins the row when loaded, so the count can grow by those on expansion.
980
+ */
981
+ export function siteRowConversationCount(node: SessionTreeNode): number {
982
+ return Math.max(node.siteSummary?.conversations ?? 0, node.children.length);
807
983
  }
808
984
 
809
985
  export function categorizeRailRoots(
@@ -1076,7 +1252,15 @@ export function projectRailSessions<T extends Session>(sessions: T[], hierarchyM
1076
1252
  export function buildPinnedRailSections(
1077
1253
  sessions: Session[],
1078
1254
  now: Date = new Date(),
1079
- options: { groupSites?: boolean | undefined } = {},
1255
+ options: {
1256
+ groupSites?: boolean | undefined;
1257
+ /** Complete Site rows from a grouped root page. */
1258
+ siteGroups?: readonly SiteConversationGroup[] | undefined;
1259
+ /** Split Site rows by project (the rail's project view). */
1260
+ siteRowsByProject?: boolean | undefined;
1261
+ workspaceId?: string | undefined;
1262
+ creator?: Session["createdBy"] | undefined;
1263
+ } = {},
1080
1264
  ): PinnedRailSections {
1081
1265
  const complete = buildRailForest(sessions, now);
1082
1266
  const roots = forestRoots(complete);
@@ -1109,7 +1293,12 @@ export function buildPinnedRailSections(
1109
1293
  ordinary: categorizeRailRoots(
1110
1294
  options.groupSites === false
1111
1295
  ? groupScheduledRuns(ordinaryRoots)
1112
- : groupSiteConversations(groupScheduledRuns(ordinaryRoots)),
1296
+ : attachSiteRows(groupScheduledRuns(ordinaryRoots), {
1297
+ groups: options.siteGroups,
1298
+ byProject: options.siteRowsByProject,
1299
+ workspaceId: options.workspaceId,
1300
+ creator: options.creator,
1301
+ }),
1113
1302
  now,
1114
1303
  ),
1115
1304
  };
@@ -0,0 +1,48 @@
1
+ import { useEffect } from "react";
2
+
3
+ const SITE_OPENED_EVENT = "opengeni:site-opened";
4
+
5
+ type SiteOpenedDetail = { workspaceId: string; siteId: string };
6
+
7
+ /** Opening a Site in the app counts as activity on its sidebar row. */
8
+ export function useRecordSiteOpened(
9
+ client: { recordSiteOpened?: (workspaceId: string, siteId: string) => Promise<unknown> },
10
+ workspaceId: string,
11
+ siteId: string,
12
+ ): void {
13
+ useEffect(() => {
14
+ if (typeof client.recordSiteOpened !== "function") return;
15
+ let current = true;
16
+ client
17
+ .recordSiteOpened(workspaceId, siteId)
18
+ .then(() => {
19
+ if (!current) return;
20
+ window.dispatchEvent(
21
+ new CustomEvent<SiteOpenedDetail>(SITE_OPENED_EVENT, { detail: { workspaceId, siteId } }),
22
+ );
23
+ })
24
+ // Ordering is a convenience: a server without it, or a failed write,
25
+ // leaves the Site and its row as they were.
26
+ .catch(() => undefined);
27
+ return () => {
28
+ current = false;
29
+ };
30
+ }, [client, workspaceId, siteId]);
31
+ }
32
+
33
+ /** Calls `onOpened` after this workspace records a Site open. */
34
+ export function useSiteOpenedListener(
35
+ workspaceId: string,
36
+ onOpened: () => void,
37
+ enabled = true,
38
+ ): void {
39
+ useEffect(() => {
40
+ if (!enabled) return;
41
+ const listener = (event: Event) => {
42
+ const detail = (event as CustomEvent<SiteOpenedDetail>).detail;
43
+ if (detail?.workspaceId === workspaceId) onOpened();
44
+ };
45
+ window.addEventListener(SITE_OPENED_EVENT, listener);
46
+ return () => window.removeEventListener(SITE_OPENED_EVENT, listener);
47
+ }, [workspaceId, onOpened, enabled]);
48
+ }
@@ -1,8 +1,19 @@
1
1
  import { expect, test } from "bun:test";
2
- import { buildPinnedRailSections, summarizeRailNodes, visibleTreeRows } from "./sessions-group";
2
+ import type { SiteConversationGroup } from "@opengeni/sdk";
3
+ import {
4
+ buildPinnedRailSections,
5
+ channelRailSections,
6
+ parseSiteRowKey,
7
+ siteRowConversationCount,
8
+ siteRowKey,
9
+ summarizeRailNodes,
10
+ visibleTreeRows,
11
+ type SessionTreeNode,
12
+ } from "./sessions-group";
3
13
  import type { Session } from "../types";
4
14
 
5
15
  const siteId = "11111111-1111-4111-8111-111111111111";
16
+ const otherSiteId = "22222222-2222-4222-8222-222222222222";
6
17
  function session(id: string, patch: Partial<Session> = {}): Session {
7
18
  return {
8
19
  id,
@@ -36,17 +47,173 @@ test("Site group has stable identity, real children, aggregate activity and no d
36
47
  ).toEqual(["newer", "older"]);
37
48
  expect(running.parentSessionId).toBeNull();
38
49
  });
39
- test("projects and pins win, while Site origin survives and a single unfiled chat still groups", () => {
50
+ function siteGroup(patch: Partial<SiteConversationGroup> = {}): SiteConversationGroup {
51
+ return {
52
+ siteId,
53
+ channelId: null,
54
+ title: "Analytics",
55
+ conversations: 3,
56
+ updatedAt: "2026-09-08T09:00:00.000Z",
57
+ createdAt: "2026-09-08T09:00:00.000Z",
58
+ total: 3,
59
+ attention: 0,
60
+ attentionSince: null,
61
+ failed: 0,
62
+ active: 0,
63
+ queued: 0,
64
+ waiting: 0,
65
+ unread: 0,
66
+ activeWork: 0,
67
+ ...patch,
68
+ };
69
+ }
70
+
71
+ function railRoots(result: ReturnType<typeof buildPinnedRailSections>): SessionTreeNode[] {
72
+ return [...result.ordinary.running, ...result.ordinary.grouped.flatMap((g) => g.sessions)];
73
+ }
74
+
75
+ test("pins win; projects split Site rows only when the rail shows projects", () => {
40
76
  const placed = session("project", { channelId: "project-id" });
41
77
  const pinned = session("pin", { pinned: true, pinnedAt: "2026-09-08T10:00:00Z" });
42
- const result = buildPinnedRailSections([placed, pinned, session("unfiled")]);
78
+ const sessions = [placed, pinned, session("unfiled")];
79
+ const result = buildPinnedRailSections(sessions);
43
80
  expect(result.pinned.map((n) => n.session.id)).toEqual(["pin"]);
44
- const roots = [...result.ordinary.running, ...result.ordinary.grouped.flatMap((g) => g.sessions)];
45
- expect(roots.find((n) => n.session.id === "project")?.siteGroup).toBeUndefined();
46
- expect(roots.find((n) => n.siteGroup)?.children.map((n) => n.session.id)).toEqual(["unfiled"]);
81
+ expect(
82
+ railRoots(result).map((n) => [n.session.id, n.children.map((c) => c.session.id).sort()]),
83
+ ).toEqual([[`site:${siteId}`, ["project", "unfiled"]]]);
84
+ const byProject = buildPinnedRailSections(sessions, new Date(), { siteRowsByProject: true });
85
+ const sections = channelRailSections(byProject.ordinary, [
86
+ { id: "project-id", name: "Project" } as never,
87
+ ]);
88
+ expect(
89
+ sections.map((section) => [
90
+ section.channelId,
91
+ section.sessions.map((n) => [n.session.id, n.children.map((c) => c.session.id)]),
92
+ ]),
93
+ ).toEqual(
94
+ expect.arrayContaining([
95
+ ["project-id", [[siteRowKey(siteId, "project-id"), ["project"]]]],
96
+ [null, [[siteRowKey(siteId, null), ["unfiled"]]]],
97
+ ]),
98
+ );
47
99
  expect(placed.metadata._opengeniSiteOrigin).toBeDefined();
48
100
  });
49
101
 
102
+ test("Site rows are complete from the server and never depend on the open session", () => {
103
+ const ordinary = session("ordinary", {
104
+ metadata: {},
105
+ updatedAt: "2026-09-08T08:00:00Z",
106
+ });
107
+ const nested = session("nested", { updatedAt: "2026-09-08T09:00:00Z" });
108
+ const groups = [
109
+ siteGroup(),
110
+ siteGroup({ siteId: otherSiteId, title: "Budget", conversations: 1 }),
111
+ ];
112
+ const build = (loaded: Session[]) =>
113
+ railRoots(buildPinnedRailSections(loaded, new Date(), { siteGroups: groups }));
114
+ // The nested conversation is open: the route injects it into the rail.
115
+ const whileOpen = build([ordinary, nested]);
116
+ const site = whileOpen.find((n) => n.session.id === `site:${siteId}`)!;
117
+ expect(site.children.map((n) => n.session.id)).toEqual(["nested"]);
118
+ expect(siteRowConversationCount(site)).toBe(3);
119
+ expect(visibleTreeRows(whileOpen, new Set(), "nested").map((r) => r.node.session.id)).toContain(
120
+ "nested",
121
+ );
122
+ // Another session is selected, so the conversation is no longer injected.
123
+ // Both Sites keep their rows and counts; nothing appears at the top level.
124
+ const afterSelectingAnother = build([ordinary]);
125
+ expect(afterSelectingAnother.map((n) => n.session.id).sort()).toEqual(
126
+ ["ordinary", `site:${otherSiteId}`, `site:${siteId}`].sort(),
127
+ );
128
+ const stable = afterSelectingAnother.find((n) => n.session.id === `site:${siteId}`)!;
129
+ expect(stable.siteGroup).toEqual({ siteId, title: "Analytics" });
130
+ expect(siteRowConversationCount(stable)).toBe(3);
131
+ expect(
132
+ visibleTreeRows(afterSelectingAnother, new Set(), "ordinary").map((r) => r.node.session.id),
133
+ ).toEqual(["ordinary"]);
134
+ // Expanding lists the Site's loaded conversations under the same row.
135
+ const expanded = build([
136
+ ordinary,
137
+ nested,
138
+ session("older", { updatedAt: "2026-09-08T07:00:00Z" }),
139
+ ]);
140
+ expect(
141
+ visibleTreeRows(expanded, new Set([`site:${siteId}`]), "ordinary")
142
+ .map((r) => r.node.session.id)
143
+ .filter((id) => id !== "ordinary"),
144
+ ).toEqual(["nested", "older"]);
145
+ });
146
+
147
+ test("Site rows sort by activity among ordinary rows and summarize complete counts", () => {
148
+ const recent = session("recent", { metadata: {}, updatedAt: "2026-09-08T12:00:00Z" });
149
+ const old = session("old", { metadata: {}, updatedAt: "2026-09-08T06:00:00Z" });
150
+ const result = buildPinnedRailSections([recent, old], new Date("2026-09-08T13:00:00Z"), {
151
+ siteGroups: [siteGroup({ total: 4, unread: 2 })],
152
+ });
153
+ expect(railRoots(result).map((n) => n.session.id)).toEqual(["recent", `site:${siteId}`, "old"]);
154
+ const site = railRoots(result)[1]!;
155
+ expect(summarizeRailNodes([site])).toMatchObject({ kind: "unread", count: 2, total: 4 });
156
+ // Live or waiting conversations float their Site row with the running rows.
157
+ for (const live of [{ active: 1 }, { attention: 1, attentionSince: "2026-09-08T08:30:00Z" }]) {
158
+ const running = buildPinnedRailSections([recent], new Date(), {
159
+ siteGroups: [siteGroup(live)],
160
+ });
161
+ expect(running.ordinary.running.map((n) => n.session.id)).toEqual([`site:${siteId}`]);
162
+ }
163
+ });
164
+
165
+ test("a Site without conversations is a plain row in its creating chat's project", () => {
166
+ const chat = session("chat", {
167
+ metadata: {},
168
+ channelId: "project-id",
169
+ updatedAt: "2026-09-08T11:00:00Z",
170
+ });
171
+ const older = session("older", { metadata: {}, updatedAt: "2026-09-08T06:00:00Z" });
172
+ const created = siteGroup({
173
+ channelId: "project-id",
174
+ conversations: 0,
175
+ total: 0,
176
+ updatedAt: "2026-09-08T10:00:00Z",
177
+ });
178
+ const result = buildPinnedRailSections([chat, older], new Date("2026-09-08T13:00:00Z"), {
179
+ siteGroups: [created],
180
+ siteRowsByProject: true,
181
+ });
182
+ const sections = channelRailSections(result.ordinary, [
183
+ { id: "project-id", name: "Project" } as never,
184
+ ]);
185
+ const project = sections.find((section) => section.channelId === "project-id")!;
186
+ // Top-level beside the chat that made it, ordered by its own activity.
187
+ expect(project.sessions.map((n) => n.session.id)).toEqual([
188
+ "chat",
189
+ siteRowKey(siteId, "project-id"),
190
+ ]);
191
+ const site = project.sessions[1]!;
192
+ expect(site.children).toEqual([]);
193
+ expect(siteRowConversationCount(site)).toBe(0);
194
+ expect(summarizeRailNodes([site])).toMatchObject({ total: 0 });
195
+ // Opening it later is newer activity, so it moves above the chat.
196
+ const opened = buildPinnedRailSections([chat, older], new Date("2026-09-08T13:00:00Z"), {
197
+ siteGroups: [{ ...created, updatedAt: "2026-09-08T12:30:00Z" }],
198
+ siteRowsByProject: true,
199
+ });
200
+ expect(
201
+ channelRailSections(opened.ordinary, [{ id: "project-id", name: "Project" } as never])
202
+ .find((section) => section.channelId === "project-id")!
203
+ .sessions.map((n) => n.session.id),
204
+ ).toEqual([siteRowKey(siteId, "project-id"), "chat"]);
205
+ });
206
+
207
+ test("Site row keys round-trip their Site and project", () => {
208
+ expect(parseSiteRowKey(siteRowKey(siteId))).toEqual({ siteId });
209
+ expect(parseSiteRowKey(siteRowKey(siteId, null))).toEqual({ siteId, channelId: null });
210
+ expect(parseSiteRowKey(siteRowKey(siteId, "project-id"))).toEqual({
211
+ siteId,
212
+ channelId: "project-id",
213
+ });
214
+ expect(parseSiteRowKey(siteId)).toBeNull();
215
+ });
216
+
50
217
  test("search and custom browse can keep matched conversations flat", () => {
51
218
  const result = buildPinnedRailSections([session("one"), session("two")], new Date(), {
52
219
  groupSites: false,
@@ -0,0 +1,55 @@
1
+ import { expect, test } from "bun:test";
2
+ import { railRouteSelection, siteViewSearch, workspaceSitePath } from "./routes";
3
+
4
+ const workspaceId = "11111111-1111-4111-8111-111111111111";
5
+ const siteId = "22222222-2222-4222-8222-222222222222";
6
+ const sessionId = "33333333-3333-4333-8333-333333333333";
7
+
8
+ test("the rail marks a session page's session", () => {
9
+ expect(
10
+ railRouteSelection({
11
+ pathname: `/workspaces/${workspaceId}/sessions/${sessionId}`,
12
+ search: {},
13
+ }),
14
+ ).toEqual({ sessionId, siteId: null });
15
+ });
16
+
17
+ test("the rail marks a Site view's Site, and its selected conversation", () => {
18
+ const pathname = `/workspaces/${workspaceId}/sites/${siteId}`;
19
+ expect(railRouteSelection({ pathname, search: {} })).toEqual({ sessionId: null, siteId });
20
+ expect(railRouteSelection({ pathname, search: { conversation: sessionId } })).toEqual({
21
+ sessionId,
22
+ siteId,
23
+ });
24
+ // A malformed conversation selects nothing rather than an arbitrary row.
25
+ expect(railRouteSelection({ pathname, search: { conversation: "../x" } })).toEqual({
26
+ sessionId: null,
27
+ siteId,
28
+ });
29
+ });
30
+
31
+ test("other pages mark nothing", () => {
32
+ for (const pathname of [
33
+ `/workspaces/${workspaceId}/artifacts/${siteId}`,
34
+ `/workspaces/${workspaceId}/sites`,
35
+ `/workspaces/${workspaceId}/sites/${siteId}/extra`,
36
+ // Not a Site id, including a malformed escape that can't be decoded.
37
+ `/workspaces/${workspaceId}/sites/%E0`,
38
+ `/workspaces/${workspaceId}/sites/not-a-site`,
39
+ ])
40
+ expect(railRouteSelection({ pathname, search: { conversation: sessionId } })).toEqual({
41
+ sessionId: null,
42
+ siteId: null,
43
+ });
44
+ });
45
+
46
+ test("Site view links and search", () => {
47
+ expect(workspaceSitePath(workspaceId, siteId)).toBe(`/workspaces/${workspaceId}/sites/${siteId}`);
48
+ expect(workspaceSitePath(workspaceId, siteId, sessionId)).toBe(
49
+ `/workspaces/${workspaceId}/sites/${siteId}?conversation=${sessionId}`,
50
+ );
51
+ expect(siteViewSearch({ conversation: sessionId, other: 1 })).toEqual({
52
+ conversation: sessionId,
53
+ });
54
+ expect(siteViewSearch({ conversation: 42 })).toEqual({ conversation: undefined });
55
+ });