@opengeni/react 6.8.0 → 6.8.1-canary.41842879332001

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 (685) hide show
  1. package/dist/app/app-state.js +8 -8
  2. package/dist/app/components/Composer.js +18 -18
  3. package/dist/app/components/agent/agent-capability-picker.js +6 -6
  4. package/dist/app/components/artifacts/artifact-library.js +6 -6
  5. package/dist/app/components/artifacts/artifact-viewer.js +18 -18
  6. package/dist/app/components/artifacts/chat-interactive-block.js +11 -11
  7. package/dist/app/components/artifacts/file-reach-dialog.js +6 -6
  8. package/dist/app/components/artifacts/inline-chat-image.js +19 -19
  9. package/dist/app/components/artifacts/retained-file-preview.js +20 -20
  10. package/dist/app/components/artifacts/retained-text-preview.js +3 -3
  11. package/dist/app/components/artifacts/site-audience.js +3 -3
  12. package/dist/app/components/artifacts/site-conversations.js +9 -9
  13. package/dist/app/components/artifacts/site-data.js +10 -10
  14. package/dist/app/components/artifacts/site-publishing-page.js +25 -25
  15. package/dist/app/components/artifacts/site-publishing.js +22 -22
  16. package/dist/app/components/artifacts/site-settings.js +24 -24
  17. package/dist/app/components/artifacts/site-version-menu.js +3 -3
  18. package/dist/app/components/billing-class-mark.js +3 -3
  19. package/dist/app/components/bots/bot-launch-strip.js +20 -20
  20. package/dist/app/components/bots/bot-template-dialog.js +26 -26
  21. package/dist/app/components/bots/bot-template-shortcuts.js +20 -20
  22. package/dist/app/components/bots/bot-templates-page.js +30 -30
  23. package/dist/app/components/capabilities/capability-detail-sheet.js +6 -6
  24. package/dist/app/components/capabilities/capability-logo-source.js +13 -13
  25. package/dist/app/components/capabilities/connector-tool-permissions.js +4 -4
  26. package/dist/app/components/capabilities/native-connect-setup.js +13 -13
  27. package/dist/app/components/capabilities/own-logins-shared-heads-up.js +3 -3
  28. package/dist/app/components/capabilities/prepared-mcp-setup-card.js +15 -15
  29. package/dist/app/components/capabilities/session-capability-card.js +47 -47
  30. package/dist/app/components/capabilities/session-chrome-card.js +20 -20
  31. package/dist/app/components/capabilities/session-custom-mcp-card.js +16 -16
  32. package/dist/app/components/capabilities/session-github-card.js +16 -16
  33. package/dist/app/components/capabilities/session-machine-card.js +19 -19
  34. package/dist/app/components/capabilities/session-personal-github-card.js +14 -14
  35. package/dist/app/components/capabilities/session-plugin-card.js +8 -8
  36. package/dist/app/components/command-menu/chat-status.js +15 -15
  37. package/dist/app/components/command-menu/chat-switcher.js +32 -32
  38. package/dist/app/components/command-menu/command-menu.js +36 -36
  39. package/dist/app/components/command-menu/shortcut-sheet.js +8 -8
  40. package/dist/app/components/composer-capabilities-menu-body.js +4 -4
  41. package/dist/app/components/composer-mobile-plus-panel.js +8 -8
  42. package/dist/app/components/composer-mobile-plus.js +1 -1
  43. package/dist/app/components/credit-required-gate.js +1 -1
  44. package/dist/app/components/credit-required-prompt.js +3 -3
  45. package/dist/app/components/desktop/app-shots.js +6 -6
  46. package/dist/app/components/desktop/computer-use.js +2 -2
  47. package/dist/app/components/desktop/this-computer.js +5 -5
  48. package/dist/app/components/feedback.js +3 -3
  49. package/dist/app/components/github-app-connect-launcher.js +1 -1
  50. package/dist/app/components/machines/connect-machine-dialog.js +11 -11
  51. package/dist/app/components/markdown.js +6 -6
  52. package/dist/app/components/models/models-ui.js +5 -5
  53. package/dist/app/components/my-things.js +4 -4
  54. package/dist/app/components/own-where-it-works.js +3 -3
  55. package/dist/app/components/personal-resource-attachment-surface.js +4 -4
  56. package/dist/app/components/pickers.js +5 -5
  57. package/dist/app/components/rail/channel-create-dialog.js +3 -3
  58. package/dist/app/components/rail/project-glyph.js +20 -20
  59. package/dist/app/components/rail/project-profile.js +27 -27
  60. package/dist/app/components/rail/rail-context.js +1 -1
  61. package/dist/app/components/rail/rail-sections.js +55 -55
  62. package/dist/app/components/rail/session-header.js +47 -47
  63. package/dist/app/components/rail/session-list.js +53 -53
  64. package/dist/app/components/rail/session-row-content.js +4 -4
  65. package/dist/app/components/rail/session-row-hover-details.js +14 -14
  66. package/dist/app/components/rail/session-shell.js +73 -73
  67. package/dist/app/components/rail/site-session-group-heading.js +8 -8
  68. package/dist/app/components/session/agent-configuration-panel.js +12 -12
  69. package/dist/app/components/session/banners.js +8 -8
  70. package/dist/app/components/session/console-new-conversation.js +39 -39
  71. package/dist/app/components/session/descendant-requests.js +36 -36
  72. package/dist/app/components/session/editable-artifacts-workspace.js +16 -16
  73. package/dist/app/components/session/failed-session-banner.js +6 -6
  74. package/dist/app/components/session/failure-recovery-boundary.js +3 -3
  75. package/dist/app/components/session/human-input-delegation-record.js +2 -2
  76. package/dist/app/components/session/human-input.js +33 -33
  77. package/dist/app/components/session/inspector.js +43 -43
  78. package/dist/app/components/session/message-actions.js +3 -3
  79. package/dist/app/components/session/message-resource-attachments.js +10 -10
  80. package/dist/app/components/session/model-recovery-notice.js +3 -3
  81. package/dist/app/components/session/new-session-settings-menu.js +6 -6
  82. package/dist/app/components/session/new-session-setup-strip.js +21 -21
  83. package/dist/app/components/session/sandbox-recovery-actions.js +3 -3
  84. package/dist/app/components/session/sandbox-switcher.js +7 -7
  85. package/dist/app/components/session/sandbox-workspace.js +48 -48
  86. package/dist/app/components/session/search-markdown-highlight.js +7 -7
  87. package/dist/app/components/session/search-results-view.js +8 -8
  88. package/dist/app/components/session/session-admin-access.js +4 -4
  89. package/dist/app/components/session/session-admission-notice.js +4 -4
  90. package/dist/app/components/session/session-avatar-picker.js +21 -21
  91. package/dist/app/components/session/session-avatar.js +19 -19
  92. package/dist/app/components/session/session-machine-access-notice.js +4 -4
  93. package/dist/app/components/session/session-profile-dialog.js +25 -25
  94. package/dist/app/components/session/session-profile-editor.js +26 -26
  95. package/dist/app/components/session/session-retention.js +3 -3
  96. package/dist/app/components/session/session-search-dialog.js +8 -8
  97. package/dist/app/components/session/session-tenancy-control.js +2 -2
  98. package/dist/app/components/session/session-usage-limit-section.js +4 -4
  99. package/dist/app/components/session/share-chat-dialog.js +5 -5
  100. package/dist/app/components/session/subagents.js +8 -8
  101. package/dist/app/components/session/subscription-account-indicator.js +6 -6
  102. package/dist/app/components/settings/row-select.js +4 -4
  103. package/dist/app/components/transcription-settings.js +6 -6
  104. package/dist/app/components/ui/destructive-confirm.js +5 -5
  105. package/dist/app/components/usage/usage-entry.js +3 -3
  106. package/dist/app/components/window-bar.js +9 -9
  107. package/dist/app/components/workspace-composer-plus.js +16 -16
  108. package/dist/app/components/workspace-reach.js +4 -4
  109. package/dist/app/embed/session-app.js +156 -156
  110. package/dist/app/lib/actions/actions-provider.js +8 -8
  111. package/dist/app/lib/agent-capabilities.js +3 -3
  112. package/dist/app/lib/codex-usage-query.js +2 -2
  113. package/dist/app/lib/composer-connectors.js +14 -14
  114. package/dist/app/lib/console-site.js +2 -2
  115. package/dist/app/lib/console-text.js +2 -2
  116. package/dist/app/lib/events.js +12 -12
  117. package/dist/app/lib/failed-session-copy.js +3 -3
  118. package/dist/app/lib/model-access-onboarding.js +3 -3
  119. package/dist/app/lib/move-chat-to-machine.js +3 -3
  120. package/dist/app/lib/session-branch-cache.js +8 -8
  121. package/dist/app/lib/session-create.js +4 -4
  122. package/dist/app/lib/session-group-pagination.js +8 -8
  123. package/dist/app/lib/session-hover-facts.js +13 -13
  124. package/dist/app/lib/session-model.js +2 -2
  125. package/dist/app/lib/session-pins.js +1 -1
  126. package/dist/app/lib/session-rail.js +5 -5
  127. package/dist/app/lib/session-rename.js +3 -3
  128. package/dist/app/lib/sessions-group.d.ts +5 -3
  129. package/dist/app/lib/sessions-group.js +7 -7
  130. package/dist/app/lib/site-tool-consent-dialog.js +7 -7
  131. package/dist/app/lib/site-tool-consent.js +1 -1
  132. package/dist/app/lib/turn-failure-analytics.js +4 -4
  133. package/dist/app/lib/use-follow-up-repositories.js +3 -3
  134. package/dist/app/lib/use-workspace-machines.js +4 -4
  135. package/dist/app/lib/use-workspace-model-catalog.js +3 -3
  136. package/dist/app/lib/use-workspace-rigs.js +2 -2
  137. package/dist/app/lib/workspace-navigation-preference.js +4 -4
  138. package/dist/app/lib/workspace-scope-context.js +3 -3
  139. package/dist/app/routes/artifacts.js +48 -48
  140. package/dist/app/routes/retained-artifact.js +32 -32
  141. package/dist/app/routes/session.js +94 -94
  142. package/dist/app/routes/sessions-index-hydration.js +5 -5
  143. package/dist/app/routes/sessions-index.js +76 -76
  144. package/dist/app/routes/site-view.js +55 -55
  145. package/dist/artifacts-document.js +4 -4
  146. package/dist/artifacts-presentation.js +4 -4
  147. package/dist/artifacts-spreadsheet.js +4 -4
  148. package/dist/artifacts.js +10 -10
  149. package/dist/automations.js +10 -10
  150. package/dist/{browser-viewer-ZHQDVHZ2.js → browser-viewer-H7PKY67P.js} +4 -4
  151. package/dist/{chat-interactive-block-VSDD6X3M.js → chat-interactive-block-47TCT4DN.js} +5 -5
  152. package/dist/{chunk-7Z76QP64.js → chunk-2QH3Q6Z2.js} +35 -5
  153. package/dist/chunk-2QH3Q6Z2.js.map +1 -0
  154. package/dist/{chunk-5MHMCE2G.js → chunk-2X2B6D5G.js} +3 -3
  155. package/dist/{chunk-OCXEY7HE.js → chunk-3BUI5DT7.js} +2 -2
  156. package/dist/{chunk-OSJ366KR.js → chunk-3FWP3TD3.js} +29 -29
  157. package/dist/{chunk-PWUSSSSL.js → chunk-3G5IA36N.js} +2 -2
  158. package/dist/{chunk-RGR57NYY.js → chunk-3NK4JAHL.js} +2 -2
  159. package/dist/{chunk-XUOYNJPB.js → chunk-3O7UZRWM.js} +24 -24
  160. package/dist/{chunk-JV3UI7BH.js → chunk-3OR6HMA4.js} +3 -3
  161. package/dist/{chunk-MV2CLIO6.js → chunk-3PC45I5N.js} +6 -6
  162. package/dist/{chunk-SJYTQLN3.js → chunk-3PI2BYK5.js} +3 -3
  163. package/dist/{chunk-DCEQCGVN.js → chunk-3PNA2P2Z.js} +2 -2
  164. package/dist/{chunk-ESXAECZ3.js → chunk-3XBZKF3K.js} +2 -2
  165. package/dist/{chunk-SBXSKRFA.js → chunk-45OGYO3S.js} +3 -3
  166. package/dist/{chunk-M3FDGRB4.js → chunk-4A7TKVNX.js} +3 -3
  167. package/dist/{chunk-RHXYO4H2.js → chunk-4BXRGXTD.js} +2 -2
  168. package/dist/{chunk-CV4VVLPZ.js → chunk-4HQAJA3T.js} +2 -2
  169. package/dist/{chunk-VCJQQYRE.js → chunk-4X2A3KPB.js} +4 -4
  170. package/dist/{chunk-OCXTTKVA.js → chunk-555K37A7.js} +2 -2
  171. package/dist/{chunk-EBIVTDEG.js → chunk-57L5ZXDS.js} +2 -2
  172. package/dist/{chunk-3L465FBR.js → chunk-5IADORIV.js} +6 -6
  173. package/dist/{chunk-SK5S2PCK.js → chunk-5IZQT4TE.js} +14 -14
  174. package/dist/chunk-5IZQT4TE.js.map +1 -0
  175. package/dist/{chunk-ZW5YTIH3.js → chunk-5PB46DAA.js} +1 -1
  176. package/dist/{chunk-ZW5YTIH3.js.map → chunk-5PB46DAA.js.map} +1 -1
  177. package/dist/{chunk-PVB4YVDP.js → chunk-5Y2O2432.js} +2 -2
  178. package/dist/{chunk-OOOSGPJL.js → chunk-6572EFE4.js} +1 -1
  179. package/dist/{chunk-YMI27QPF.js → chunk-6BG5HCUP.js} +2 -2
  180. package/dist/{chunk-QRECBCJM.js → chunk-6EXFJWII.js} +2 -2
  181. package/dist/{chunk-74CBR5YE.js → chunk-6PNRUGOK.js} +2 -2
  182. package/dist/{chunk-PUUEI4W3.js → chunk-6RJEY6TC.js} +5 -5
  183. package/dist/{chunk-DLVIRJGK.js → chunk-727GL2YY.js} +2 -2
  184. package/dist/{chunk-J2BTILRR.js → chunk-7FGYLFW6.js} +2 -2
  185. package/dist/{chunk-MKDFYE2E.js → chunk-7IMWTFEG.js} +2 -2
  186. package/dist/{chunk-FER6EVIY.js → chunk-7POKH54R.js} +2 -2
  187. package/dist/{chunk-H6BX6WOW.js → chunk-7T26IH6W.js} +3 -3
  188. package/dist/{chunk-R33SBMB7.js → chunk-7XQRVZZQ.js} +3 -3
  189. package/dist/{chunk-NFCS5WYC.js → chunk-A3SPPXMC.js} +3 -3
  190. package/dist/{chunk-DQPIEQGP.js → chunk-A7CWPDEH.js} +2 -2
  191. package/dist/{chunk-3PM3M2Q6.js → chunk-AGOYVKTI.js} +2 -2
  192. package/dist/{chunk-OBGOLHCP.js → chunk-AIQKZUPB.js} +3 -3
  193. package/dist/{chunk-GSCGKJNK.js → chunk-AMYDHG3S.js} +2 -2
  194. package/dist/{chunk-U4LTPFD2.js → chunk-APJPB6TX.js} +2 -2
  195. package/dist/{chunk-SP44O3OU.js → chunk-APLGT5EI.js} +2 -2
  196. package/dist/{chunk-M3HGBO2Y.js → chunk-ATNKMGLO.js} +1 -1
  197. package/dist/{chunk-4O2XWOLZ.js → chunk-AVX4CZQ3.js} +3 -3
  198. package/dist/{chunk-CXAN2FHF.js → chunk-B46MK44K.js} +6 -6
  199. package/dist/{chunk-RMCLFSMX.js → chunk-BBKUPEGG.js} +2 -2
  200. package/dist/{chunk-J2WY42FA.js → chunk-BES6OQE3.js} +2 -2
  201. package/dist/{chunk-GU7T2S5N.js → chunk-BM2N26SH.js} +2 -2
  202. package/dist/{chunk-HEGV4QMS.js → chunk-C3NS74PZ.js} +2 -2
  203. package/dist/{chunk-752WXSDN.js → chunk-C56ABB5V.js} +2 -2
  204. package/dist/{chunk-77SYIH6O.js → chunk-C6MATJQ5.js} +2 -2
  205. package/dist/{chunk-KUE5BOQE.js → chunk-CRX47CO6.js} +4 -4
  206. package/dist/{chunk-QPQ7R77C.js → chunk-CUIV2XPO.js} +3 -1
  207. package/dist/chunk-CUIV2XPO.js.map +1 -0
  208. package/dist/{chunk-GTHCHCWW.js → chunk-D33KWZQJ.js} +3 -3
  209. package/dist/{chunk-AH3DGOTK.js → chunk-D7E3BSCX.js} +2 -2
  210. package/dist/{chunk-OJWDNNW3.js → chunk-DFR3TMTZ.js} +5 -5
  211. package/dist/{chunk-WYGTAQMX.js → chunk-DICC75CU.js} +2 -2
  212. package/dist/{chunk-736RUNIA.js → chunk-DJ2LMKKX.js} +4 -4
  213. package/dist/{chunk-4F3AEJI6.js → chunk-DJI4D7PM.js} +4 -4
  214. package/dist/{chunk-LVELUUK6.js → chunk-DSZUQL4W.js} +2 -2
  215. package/dist/{chunk-MT2R57SF.js → chunk-DVF246BE.js} +2 -2
  216. package/dist/{chunk-OI6VI6SU.js → chunk-DVOWBHWN.js} +8 -8
  217. package/dist/{chunk-PZKHST7A.js → chunk-E2KPRSA4.js} +2 -2
  218. package/dist/{chunk-EKJHOWTZ.js → chunk-E3LMLWEB.js} +4 -4
  219. package/dist/{chunk-QURYQFDN.js → chunk-EDC7X7PW.js} +2 -2
  220. package/dist/{chunk-HYEIA25Y.js → chunk-EDSMULHU.js} +2 -2
  221. package/dist/{chunk-U6552Q3T.js → chunk-EQQOZ6DD.js} +2 -2
  222. package/dist/{chunk-IFSXVU2S.js → chunk-ERBDQ2GY.js} +2 -2
  223. package/dist/{chunk-IZXYFWA4.js → chunk-EWI73URG.js} +13 -13
  224. package/dist/{chunk-N3FM4BNA.js → chunk-EZ6LFN33.js} +2 -2
  225. package/dist/{chunk-4K64EKM7.js → chunk-F7YL6DPR.js} +4 -4
  226. package/dist/{chunk-ICAMYP5M.js → chunk-FIGFXMUP.js} +2 -2
  227. package/dist/{chunk-54U6ZBEX.js → chunk-FJRJK67G.js} +3 -3
  228. package/dist/{chunk-E5KOWRDU.js → chunk-FLHB2NZT.js} +2 -2
  229. package/dist/{chunk-OWET7EY2.js → chunk-FRSZSL2S.js} +19 -13
  230. package/dist/{chunk-OWET7EY2.js.map → chunk-FRSZSL2S.js.map} +1 -1
  231. package/dist/{chunk-D3PTVN2I.js → chunk-FUGGM76A.js} +2 -2
  232. package/dist/{chunk-QQIZMVAJ.js → chunk-FWLLGNGP.js} +51 -49
  233. package/dist/chunk-FWLLGNGP.js.map +1 -0
  234. package/dist/{chunk-TDTD66BK.js → chunk-FXPZAZYT.js} +2 -2
  235. package/dist/{chunk-KO3OHHY2.js → chunk-GAGAM4MT.js} +2 -2
  236. package/dist/{chunk-TK5FWVZR.js → chunk-GESGH3HY.js} +3 -3
  237. package/dist/{chunk-2VJOSU4H.js → chunk-GI4PWKXI.js} +2 -2
  238. package/dist/{chunk-KFNZZ2N6.js → chunk-GJTEBAZ7.js} +2 -2
  239. package/dist/{chunk-LTJFV2JI.js → chunk-GNCGEW7F.js} +2 -2
  240. package/dist/{chunk-34NV52R3.js → chunk-GOMUNPB6.js} +4 -4
  241. package/dist/{chunk-7YTR3UFO.js → chunk-GPWE5UD7.js} +8 -5
  242. package/dist/chunk-GPWE5UD7.js.map +1 -0
  243. package/dist/{chunk-LIJNVIT3.js → chunk-GUMUILEI.js} +3 -3
  244. package/dist/{chunk-7NLF35YL.js → chunk-GVGNHBFT.js} +4 -4
  245. package/dist/{chunk-K3D7IQQP.js → chunk-GW4YI3FB.js} +6 -6
  246. package/dist/{chunk-D5TIVCXG.js → chunk-GXKCV7X7.js} +2 -2
  247. package/dist/{chunk-2J77TWGH.js → chunk-H467EQA6.js} +3 -3
  248. package/dist/{chunk-3OK7Y6ES.js → chunk-HE77VDDR.js} +2 -2
  249. package/dist/{chunk-UO35OEOX.js → chunk-HT65RGCX.js} +3 -3
  250. package/dist/{chunk-G6ICCGJ3.js → chunk-HVQSFTE7.js} +2 -2
  251. package/dist/{chunk-G5UQBTXY.js → chunk-HXJPDC76.js} +2 -2
  252. package/dist/{chunk-GIWFLWXG.js → chunk-I6LQW24C.js} +4 -4
  253. package/dist/{chunk-467WDSOK.js → chunk-I7A6S5YL.js} +2 -2
  254. package/dist/{chunk-AAS7OWV6.js → chunk-IADS4ZYD.js} +3 -3
  255. package/dist/{chunk-Y3XZEKDQ.js → chunk-IJWMWCGR.js} +2 -2
  256. package/dist/{chunk-SGH7I7OY.js → chunk-IWFO6KOU.js} +2 -2
  257. package/dist/{chunk-GMHIOYB7.js → chunk-IYC6QGV2.js} +4 -4
  258. package/dist/{chunk-2OXSB2OL.js → chunk-J2TZIFRC.js} +3 -2
  259. package/dist/chunk-J2TZIFRC.js.map +1 -0
  260. package/dist/{chunk-3NNAC43A.js → chunk-J5AODKJO.js} +2 -2
  261. package/dist/{chunk-DIP7YALH.js → chunk-JKI3LMLH.js} +2 -2
  262. package/dist/{chunk-IJR6VOLU.js → chunk-JSYRWOCE.js} +2 -2
  263. package/dist/{chunk-CEMSIU4Z.js → chunk-JTQTWO4D.js} +5 -5
  264. package/dist/{chunk-JHZRAYI4.js → chunk-JWSRFXRN.js} +2 -2
  265. package/dist/chunk-JWSRFXRN.js.map +1 -0
  266. package/dist/{chunk-BASI553K.js → chunk-KBTKAAHM.js} +4 -4
  267. package/dist/{chunk-OYOFPNLC.js → chunk-KD7VEMWY.js} +4 -4
  268. package/dist/{chunk-3DRLCX5V.js → chunk-KPGFGRSA.js} +2 -2
  269. package/dist/{chunk-PLYVGZIN.js → chunk-KWFDEJFI.js} +1 -1
  270. package/dist/{chunk-FNXCFIPW.js → chunk-KYLEH4OF.js} +2 -2
  271. package/dist/{chunk-WXF2RTS4.js → chunk-L7FJTFJN.js} +2 -2
  272. package/dist/{chunk-KI46GKMD.js → chunk-L7VVQOSY.js} +7 -7
  273. package/dist/{chunk-M5IQVMLR.js → chunk-LAZ2QZTJ.js} +11 -4
  274. package/dist/chunk-LAZ2QZTJ.js.map +1 -0
  275. package/dist/chunk-LKLQVANM.js +2 -0
  276. package/dist/{chunk-YNTLWCF4.js → chunk-LLYEAZ4E.js} +3 -3
  277. package/dist/{chunk-4Z5X7PLC.js → chunk-LWM7JUW6.js} +3 -3
  278. package/dist/{chunk-CHU3RDV4.js → chunk-LXKV4ND3.js} +3 -3
  279. package/dist/{chunk-AB5IW227.js → chunk-LYLICEQO.js} +3 -3
  280. package/dist/{chunk-PSM3CU7N.js → chunk-M3OZOCIK.js} +46 -39
  281. package/dist/chunk-M3OZOCIK.js.map +1 -0
  282. package/dist/{chunk-OTW25A6I.js → chunk-M5GRI5K4.js} +3 -3
  283. package/dist/{chunk-X2QJXDE4.js → chunk-MF65PKKF.js} +8 -8
  284. package/dist/{chunk-EDDKPIIV.js → chunk-MJ4XIOPM.js} +2 -2
  285. package/dist/{chunk-FLWQJDJ5.js → chunk-MMPJJQG3.js} +6 -6
  286. package/dist/{chunk-T67LTMSW.js → chunk-MOU54FGD.js} +10 -10
  287. package/dist/{chunk-LQKVNREV.js → chunk-NAWHQ4IL.js} +3 -3
  288. package/dist/{chunk-ZBHGNE2J.js → chunk-NBHBB2VV.js} +3 -3
  289. package/dist/{chunk-PF2WU2IL.js → chunk-ND4IQJUM.js} +120 -17
  290. package/dist/chunk-ND4IQJUM.js.map +1 -0
  291. package/dist/{chunk-U5UGM5XD.js → chunk-NMOZDAEZ.js} +5 -5
  292. package/dist/{chunk-D74Z2N4K.js → chunk-NZA4R3BE.js} +2 -2
  293. package/dist/{chunk-WRMUXZ7C.js → chunk-OB2CX7PJ.js} +3 -3
  294. package/dist/{chunk-YJSCLGAW.js → chunk-OB4I4OIT.js} +3 -3
  295. package/dist/{chunk-DWJ6J3YW.js → chunk-OKQW2FPL.js} +4 -4
  296. package/dist/{chunk-2GCHGWNE.js → chunk-ORLX6A3C.js} +3 -3
  297. package/dist/{chunk-EBTUPRRQ.js → chunk-P5N4EYFW.js} +4 -4
  298. package/dist/{chunk-JKL5S7UQ.js → chunk-PL4JE3NI.js} +6 -6
  299. package/dist/{chunk-OP2GD6QW.js → chunk-PNUHKDY2.js} +2 -2
  300. package/dist/{chunk-MZY3VKKM.js → chunk-PWJE7D6V.js} +2 -2
  301. package/dist/{chunk-RISUROBM.js → chunk-PYE27I6J.js} +4 -4
  302. package/dist/{chunk-SPD4ULVB.js → chunk-PYMROAWS.js} +2 -1
  303. package/dist/chunk-PYMROAWS.js.map +1 -0
  304. package/dist/{chunk-Q5K2J5GG.js → chunk-Q74FQK3A.js} +13 -3
  305. package/dist/chunk-Q74FQK3A.js.map +1 -0
  306. package/dist/{chunk-R5QAL43H.js → chunk-QIJHK6P4.js} +2 -2
  307. package/dist/{chunk-AJBDAVX3.js → chunk-QK3A23NP.js} +7 -7
  308. package/dist/{chunk-CYDXCILL.js → chunk-QLWDNAOV.js} +7 -7
  309. package/dist/{chunk-BQYRZIZ7.js → chunk-QS6DQBVJ.js} +2 -2
  310. package/dist/{chunk-3PZ3LRPV.js → chunk-QSUVFPG3.js} +3 -3
  311. package/dist/{chunk-PYB4BFEC.js → chunk-QUC5MLTN.js} +3 -3
  312. package/dist/{chunk-WDASYY4S.js → chunk-QVT5AWPI.js} +6 -6
  313. package/dist/{chunk-K4DQS2ML.js → chunk-QZC6WCBR.js} +4 -4
  314. package/dist/{chunk-HWVPLFIW.js → chunk-RAHNICPP.js} +2 -2
  315. package/dist/{chunk-H6MJFMHZ.js → chunk-RME6RGIW.js} +3 -3
  316. package/dist/{chunk-XMBOLFFS.js → chunk-RQIB2F53.js} +2 -2
  317. package/dist/{chunk-OXQ2SXVC.js → chunk-RUA72NQY.js} +2 -2
  318. package/dist/{chunk-UMX6DZME.js → chunk-SCJHWN4X.js} +2 -2
  319. package/dist/{chunk-HTMQGS63.js → chunk-SIXBDT5F.js} +8 -8
  320. package/dist/{chunk-ZAX4XQLN.js → chunk-SPK3T4JK.js} +2 -2
  321. package/dist/{chunk-WTSQUCHB.js → chunk-SSN2YSST.js} +3 -3
  322. package/dist/{chunk-5MIBQ4P5.js → chunk-SYJCDX5V.js} +2 -2
  323. package/dist/{chunk-NQ2CPQJF.js → chunk-SYL7LCRA.js} +26 -3
  324. package/dist/chunk-SYL7LCRA.js.map +1 -0
  325. package/dist/{chunk-ZR5EKJT6.js → chunk-T6276OXI.js} +2 -2
  326. package/dist/{chunk-DEHLWZSI.js → chunk-T7OARG4N.js} +4 -4
  327. package/dist/{chunk-77BHKC43.js → chunk-TF5L3BEV.js} +1 -1
  328. package/dist/{chunk-GOCODNQS.js → chunk-TF6Z7BOP.js} +2 -2
  329. package/dist/{chunk-WIFDNUKD.js → chunk-TJDXWZMO.js} +3 -3
  330. package/dist/{chunk-SFIXTOOJ.js → chunk-TL5ATBHZ.js} +3 -3
  331. package/dist/{chunk-XZCCEKPW.js → chunk-TMOHIOMT.js} +6 -6
  332. package/dist/{chunk-AVXDIRRW.js → chunk-UI5X63YC.js} +2 -2
  333. package/dist/{chunk-6QK65ZWM.js → chunk-UIY7BDZC.js} +3 -3
  334. package/dist/{chunk-VATYK3JQ.js → chunk-UMBFMEO7.js} +3 -3
  335. package/dist/{chunk-UU5FBVRX.js → chunk-UU5G7OA4.js} +2 -2
  336. package/dist/{chunk-EGKARC53.js → chunk-UZUCYCF4.js} +2 -2
  337. package/dist/{chunk-LPKJ77EK.js → chunk-V2A7G7S7.js} +2 -2
  338. package/dist/{chunk-CH4UQ4NO.js → chunk-V5G4TKRC.js} +5 -5
  339. package/dist/{chunk-UBRQ3PQD.js → chunk-VKAVW34W.js} +2 -2
  340. package/dist/{chunk-JV5ULONH.js → chunk-VVLEVNTQ.js} +36 -36
  341. package/dist/{chunk-44JWVYJB.js → chunk-VW7X7TWZ.js} +2 -2
  342. package/dist/{chunk-3CDJSKDW.js → chunk-VWA2CHSL.js} +3 -3
  343. package/dist/{chunk-IN3VQFKS.js → chunk-W43HZPM7.js} +2 -2
  344. package/dist/{chunk-SXGJL7UT.js → chunk-WHGD7Q2L.js} +14 -14
  345. package/dist/{chunk-XOIDUM2H.js → chunk-WNXKYEVN.js} +1 -1
  346. package/dist/{chunk-TKQL7EDB.js → chunk-WSA7UBX4.js} +2 -2
  347. package/dist/{chunk-AJDGP2N4.js → chunk-WZ5TQJ3T.js} +19 -19
  348. package/dist/{chunk-FBA2NXYH.js → chunk-X3TGNSOG.js} +3 -3
  349. package/dist/{chunk-R4JA5JFI.js → chunk-X4WXYI3N.js} +3 -3
  350. package/dist/{chunk-Q5EZNBPI.js → chunk-XIQ3AIAJ.js} +3 -3
  351. package/dist/{chunk-S27VZ5DO.js → chunk-XWYT4LEL.js} +6 -6
  352. package/dist/{chunk-477DTTMH.js → chunk-Y3PU75OC.js} +3 -3
  353. package/dist/{chunk-4JXPLTWV.js → chunk-Y5ZWX5YS.js} +2 -2
  354. package/dist/{chunk-4BWMAGJJ.js → chunk-YA5PABND.js} +3 -3
  355. package/dist/{chunk-VXORMNU4.js → chunk-YBHAAULA.js} +67 -2
  356. package/dist/chunk-YBHAAULA.js.map +1 -0
  357. package/dist/{chunk-OGU73VUN.js → chunk-YBPRR2QS.js} +2 -2
  358. package/dist/{chunk-TNSJFZ6Q.js → chunk-YDYR7XQE.js} +4 -4
  359. package/dist/{chunk-GTRAH4FG.js → chunk-YG6V2LQH.js} +2 -2
  360. package/dist/{chunk-XVLEBB4Y.js → chunk-YUXA7ALE.js} +2 -2
  361. package/dist/{chunk-SN2WENRP.js → chunk-YWHQDXPB.js} +3 -3
  362. package/dist/{chunk-BFFNINCC.js → chunk-YWRR5R7B.js} +3 -3
  363. package/dist/{chunk-FSDQQQIA.js → chunk-YYRK7A4N.js} +3 -3
  364. package/dist/{chunk-MRECRNVU.js → chunk-Z26CDLUV.js} +5 -5
  365. package/dist/{chunk-OYCK4JRS.js → chunk-Z27EXLMQ.js} +2 -2
  366. package/dist/{chunk-UTRNLNCW.js → chunk-Z7GDH7W2.js} +3 -3
  367. package/dist/{chunk-PRT4J2DL.js → chunk-ZGVLSAWL.js} +2 -2
  368. package/dist/{chunk-OK7BQMCI.js → chunk-ZM6Q5NQN.js} +9 -9
  369. package/dist/components/message-timeline.d.ts +10 -2
  370. package/dist/composer.js +8 -8
  371. package/dist/{computer-viewer-5LKRCEVQ.js → computer-viewer-SROXREYD.js} +5 -5
  372. package/dist/connect.js +12 -12
  373. package/dist/desktop-dictation.js +8 -8
  374. package/dist/desktop.js +2 -2
  375. package/dist/editor.js +2 -2
  376. package/dist/{embedded-new-voice-GHJRY3YL.js → embedded-new-voice-EIQY2VBF.js} +5 -5
  377. package/dist/{embedded-voice-ASQXBSTX.js → embedded-voice-LMWNH7F7.js} +5 -5
  378. package/dist/{fleet-decision-row-U7LDVBEM.js → fleet-decision-row-X2G56ZRA.js} +2 -2
  379. package/dist/hooks/use-recordings.d.ts +4 -2
  380. package/dist/in-chat-connect-model.js +5 -5
  381. package/dist/index.d.ts +2 -2
  382. package/dist/index.js +66 -60
  383. package/dist/interaction.js +5 -5
  384. package/dist/{latest-question-RNVF262Q.js → latest-question-KA7AQYVI.js} +2 -2
  385. package/dist/machines.js +3 -3
  386. package/dist/meetings/recorder-context.d.ts +6 -1
  387. package/dist/meetings/recorder-panel.d.ts +2 -5
  388. package/dist/meetings-recorder.js +1 -1
  389. package/dist/meetings.js +22 -21
  390. package/dist/meetings.js.map +1 -1
  391. package/dist/messages/en.d.ts +2 -0
  392. package/dist/messages.js +1 -1
  393. package/dist/{model-policy-picker-menu-E6XKMFTA.js → model-policy-picker-menu-SHWPT5VA.js} +4 -4
  394. package/dist/{payment-page-card-DJDKV2LW.js → payment-page-card-NNVUISN4.js} +4 -4
  395. package/dist/{platform-activity-row-MSDCSMET.js → platform-activity-row-7UDWSAHK.js} +2 -2
  396. package/dist/{queue-surface-implementation-GUAIG6TK.js → queue-surface-implementation-BUXSO24N.js} +5 -5
  397. package/dist/realtime.js +4 -4
  398. package/dist/{recorder-host-2MYDJPQW.js → recorder-host-POX54CFT.js} +5 -5
  399. package/dist/recordings.js +4 -4
  400. package/dist/{sandbox-files-W5W2LW4K.js → sandbox-files-33QD7DW2.js} +6 -6
  401. package/dist/session-app.js +156 -156
  402. package/dist/{session-connect-cards-HPH7JOZP.js → session-connect-cards-CXGNVA2A.js} +9 -9
  403. package/dist/session-list-model.js +2 -2
  404. package/dist/{session-realtime-SDTKFFIR.js → session-realtime-CVDSEULB.js} +3 -3
  405. package/dist/session-realtime.js +2 -2
  406. package/dist/session-ui.js +33 -33
  407. package/dist/session.d.ts +3 -2
  408. package/dist/session.js +16 -10
  409. package/dist/sites.js +2 -2
  410. package/dist/terminal.js +2 -2
  411. package/dist/this-computer.js +3 -3
  412. package/dist/timeline/index.d.ts +3 -2
  413. package/dist/timeline/projection.d.ts +52 -0
  414. package/dist/timeline/turn-summary-model.d.ts +4 -3
  415. package/dist/timeline/types.d.ts +8 -2
  416. package/dist/timeline/use-timeline-pauses.d.ts +12 -0
  417. package/dist/timeline/work-presentation.d.ts +4 -3
  418. package/dist/{timeline-annotation-markers-FNILLWNU.js → timeline-annotation-markers-5J5TM5IP.js} +2 -2
  419. package/dist/{timeline-annotation-selection-MBCIDO2Q.js → timeline-annotation-selection-WLY7FB7F.js} +2 -2
  420. package/dist/{timeline-annotations-dialog-JPNKLOTE.js → timeline-annotations-dialog-67VRFKJU.js} +3 -3
  421. package/dist/timeline-model.js +2 -2
  422. package/dist/ui/access-list.js +5 -5
  423. package/dist/ui/cadence-picker.js +4 -4
  424. package/dist/ui/choice-cards.js +3 -3
  425. package/dist/ui/confirm-dialog.js +2 -2
  426. package/dist/ui/copy-field.js +3 -3
  427. package/dist/ui/detail-page.js +2 -2
  428. package/dist/ui/detail-sheet.js +2 -2
  429. package/dist/ui/disclosure.js +3 -3
  430. package/dist/ui/email-chips-input.js +3 -3
  431. package/dist/ui/field.js +2 -2
  432. package/dist/ui/flush-form-page.js +3 -3
  433. package/dist/ui/form-dialog.js +2 -2
  434. package/dist/ui/list-row.js +3 -3
  435. package/dist/ui/relative-time.js +2 -2
  436. package/dist/ui/revision-history.js +4 -4
  437. package/dist/ui/role-select.js +5 -5
  438. package/dist/ui/select-menu.js +3 -3
  439. package/dist/ui/usage-meter.js +3 -3
  440. package/dist/usage.js +2 -2
  441. package/dist/workbench.js +4 -4
  442. package/package.json +6 -5
  443. package/src/app/components/rail/session-row-content.tsx +27 -0
  444. package/src/app/lib/session-branch-cache.tsx +1 -0
  445. package/src/app/lib/session-pins.tsx +1 -0
  446. package/src/app/lib/session-row-paused.test.tsx +183 -0
  447. package/src/app/lib/sessions-group-channels.test.ts +4 -4
  448. package/src/app/lib/sessions-group.tsx +62 -4
  449. package/src/app/routes/session.tsx +2 -0
  450. package/src/components/message-timeline.tsx +14 -2
  451. package/src/components/session-conversation.tsx +2 -1
  452. package/src/components/timeline-annotations.tsx +4 -1
  453. package/src/components/timeline-settlement.ts +1 -1
  454. package/src/hooks/use-recordings.ts +5 -0
  455. package/src/index.ts +5 -0
  456. package/src/meetings/recorder-context.tsx +28 -5
  457. package/src/meetings/recorder-panel.tsx +13 -5
  458. package/src/meetings/recorder-workspace.test.tsx +57 -8
  459. package/src/messages/en.ts +2 -0
  460. package/src/session.ts +8 -1
  461. package/src/timeline/index.ts +4 -1
  462. package/src/timeline/projection.ts +228 -16
  463. package/src/timeline/turn-summary-model.ts +4 -3
  464. package/src/timeline/turn-summary.tsx +15 -2
  465. package/src/timeline/types.ts +8 -2
  466. package/src/timeline/use-timeline-pauses.ts +105 -0
  467. package/src/timeline/work-presentation.ts +13 -4
  468. package/dist/chunk-2OXSB2OL.js.map +0 -1
  469. package/dist/chunk-7YTR3UFO.js.map +0 -1
  470. package/dist/chunk-7Z76QP64.js.map +0 -1
  471. package/dist/chunk-JHZRAYI4.js.map +0 -1
  472. package/dist/chunk-M5IQVMLR.js.map +0 -1
  473. package/dist/chunk-NQ2CPQJF.js.map +0 -1
  474. package/dist/chunk-O2UPPN5M.js +0 -2
  475. package/dist/chunk-PF2WU2IL.js.map +0 -1
  476. package/dist/chunk-PSM3CU7N.js.map +0 -1
  477. package/dist/chunk-Q5K2J5GG.js.map +0 -1
  478. package/dist/chunk-QPQ7R77C.js.map +0 -1
  479. package/dist/chunk-QQIZMVAJ.js.map +0 -1
  480. package/dist/chunk-SK5S2PCK.js.map +0 -1
  481. package/dist/chunk-SPD4ULVB.js.map +0 -1
  482. package/dist/chunk-VXORMNU4.js.map +0 -1
  483. /package/dist/{browser-viewer-ZHQDVHZ2.js.map → browser-viewer-H7PKY67P.js.map} +0 -0
  484. /package/dist/{chat-interactive-block-VSDD6X3M.js.map → chat-interactive-block-47TCT4DN.js.map} +0 -0
  485. /package/dist/{chunk-5MHMCE2G.js.map → chunk-2X2B6D5G.js.map} +0 -0
  486. /package/dist/{chunk-OCXEY7HE.js.map → chunk-3BUI5DT7.js.map} +0 -0
  487. /package/dist/{chunk-OSJ366KR.js.map → chunk-3FWP3TD3.js.map} +0 -0
  488. /package/dist/{chunk-PWUSSSSL.js.map → chunk-3G5IA36N.js.map} +0 -0
  489. /package/dist/{chunk-RGR57NYY.js.map → chunk-3NK4JAHL.js.map} +0 -0
  490. /package/dist/{chunk-XUOYNJPB.js.map → chunk-3O7UZRWM.js.map} +0 -0
  491. /package/dist/{chunk-JV3UI7BH.js.map → chunk-3OR6HMA4.js.map} +0 -0
  492. /package/dist/{chunk-MV2CLIO6.js.map → chunk-3PC45I5N.js.map} +0 -0
  493. /package/dist/{chunk-SJYTQLN3.js.map → chunk-3PI2BYK5.js.map} +0 -0
  494. /package/dist/{chunk-DCEQCGVN.js.map → chunk-3PNA2P2Z.js.map} +0 -0
  495. /package/dist/{chunk-ESXAECZ3.js.map → chunk-3XBZKF3K.js.map} +0 -0
  496. /package/dist/{chunk-SBXSKRFA.js.map → chunk-45OGYO3S.js.map} +0 -0
  497. /package/dist/{chunk-M3FDGRB4.js.map → chunk-4A7TKVNX.js.map} +0 -0
  498. /package/dist/{chunk-RHXYO4H2.js.map → chunk-4BXRGXTD.js.map} +0 -0
  499. /package/dist/{chunk-CV4VVLPZ.js.map → chunk-4HQAJA3T.js.map} +0 -0
  500. /package/dist/{chunk-VCJQQYRE.js.map → chunk-4X2A3KPB.js.map} +0 -0
  501. /package/dist/{chunk-OCXTTKVA.js.map → chunk-555K37A7.js.map} +0 -0
  502. /package/dist/{chunk-EBIVTDEG.js.map → chunk-57L5ZXDS.js.map} +0 -0
  503. /package/dist/{chunk-3L465FBR.js.map → chunk-5IADORIV.js.map} +0 -0
  504. /package/dist/{chunk-PVB4YVDP.js.map → chunk-5Y2O2432.js.map} +0 -0
  505. /package/dist/{chunk-OOOSGPJL.js.map → chunk-6572EFE4.js.map} +0 -0
  506. /package/dist/{chunk-YMI27QPF.js.map → chunk-6BG5HCUP.js.map} +0 -0
  507. /package/dist/{chunk-QRECBCJM.js.map → chunk-6EXFJWII.js.map} +0 -0
  508. /package/dist/{chunk-74CBR5YE.js.map → chunk-6PNRUGOK.js.map} +0 -0
  509. /package/dist/{chunk-PUUEI4W3.js.map → chunk-6RJEY6TC.js.map} +0 -0
  510. /package/dist/{chunk-DLVIRJGK.js.map → chunk-727GL2YY.js.map} +0 -0
  511. /package/dist/{chunk-J2BTILRR.js.map → chunk-7FGYLFW6.js.map} +0 -0
  512. /package/dist/{chunk-MKDFYE2E.js.map → chunk-7IMWTFEG.js.map} +0 -0
  513. /package/dist/{chunk-FER6EVIY.js.map → chunk-7POKH54R.js.map} +0 -0
  514. /package/dist/{chunk-H6BX6WOW.js.map → chunk-7T26IH6W.js.map} +0 -0
  515. /package/dist/{chunk-R33SBMB7.js.map → chunk-7XQRVZZQ.js.map} +0 -0
  516. /package/dist/{chunk-NFCS5WYC.js.map → chunk-A3SPPXMC.js.map} +0 -0
  517. /package/dist/{chunk-DQPIEQGP.js.map → chunk-A7CWPDEH.js.map} +0 -0
  518. /package/dist/{chunk-3PM3M2Q6.js.map → chunk-AGOYVKTI.js.map} +0 -0
  519. /package/dist/{chunk-OBGOLHCP.js.map → chunk-AIQKZUPB.js.map} +0 -0
  520. /package/dist/{chunk-GSCGKJNK.js.map → chunk-AMYDHG3S.js.map} +0 -0
  521. /package/dist/{chunk-U4LTPFD2.js.map → chunk-APJPB6TX.js.map} +0 -0
  522. /package/dist/{chunk-SP44O3OU.js.map → chunk-APLGT5EI.js.map} +0 -0
  523. /package/dist/{chunk-M3HGBO2Y.js.map → chunk-ATNKMGLO.js.map} +0 -0
  524. /package/dist/{chunk-4O2XWOLZ.js.map → chunk-AVX4CZQ3.js.map} +0 -0
  525. /package/dist/{chunk-CXAN2FHF.js.map → chunk-B46MK44K.js.map} +0 -0
  526. /package/dist/{chunk-RMCLFSMX.js.map → chunk-BBKUPEGG.js.map} +0 -0
  527. /package/dist/{chunk-J2WY42FA.js.map → chunk-BES6OQE3.js.map} +0 -0
  528. /package/dist/{chunk-GU7T2S5N.js.map → chunk-BM2N26SH.js.map} +0 -0
  529. /package/dist/{chunk-HEGV4QMS.js.map → chunk-C3NS74PZ.js.map} +0 -0
  530. /package/dist/{chunk-752WXSDN.js.map → chunk-C56ABB5V.js.map} +0 -0
  531. /package/dist/{chunk-77SYIH6O.js.map → chunk-C6MATJQ5.js.map} +0 -0
  532. /package/dist/{chunk-KUE5BOQE.js.map → chunk-CRX47CO6.js.map} +0 -0
  533. /package/dist/{chunk-GTHCHCWW.js.map → chunk-D33KWZQJ.js.map} +0 -0
  534. /package/dist/{chunk-AH3DGOTK.js.map → chunk-D7E3BSCX.js.map} +0 -0
  535. /package/dist/{chunk-OJWDNNW3.js.map → chunk-DFR3TMTZ.js.map} +0 -0
  536. /package/dist/{chunk-WYGTAQMX.js.map → chunk-DICC75CU.js.map} +0 -0
  537. /package/dist/{chunk-736RUNIA.js.map → chunk-DJ2LMKKX.js.map} +0 -0
  538. /package/dist/{chunk-4F3AEJI6.js.map → chunk-DJI4D7PM.js.map} +0 -0
  539. /package/dist/{chunk-LVELUUK6.js.map → chunk-DSZUQL4W.js.map} +0 -0
  540. /package/dist/{chunk-MT2R57SF.js.map → chunk-DVF246BE.js.map} +0 -0
  541. /package/dist/{chunk-OI6VI6SU.js.map → chunk-DVOWBHWN.js.map} +0 -0
  542. /package/dist/{chunk-PZKHST7A.js.map → chunk-E2KPRSA4.js.map} +0 -0
  543. /package/dist/{chunk-EKJHOWTZ.js.map → chunk-E3LMLWEB.js.map} +0 -0
  544. /package/dist/{chunk-QURYQFDN.js.map → chunk-EDC7X7PW.js.map} +0 -0
  545. /package/dist/{chunk-HYEIA25Y.js.map → chunk-EDSMULHU.js.map} +0 -0
  546. /package/dist/{chunk-U6552Q3T.js.map → chunk-EQQOZ6DD.js.map} +0 -0
  547. /package/dist/{chunk-IFSXVU2S.js.map → chunk-ERBDQ2GY.js.map} +0 -0
  548. /package/dist/{chunk-IZXYFWA4.js.map → chunk-EWI73URG.js.map} +0 -0
  549. /package/dist/{chunk-N3FM4BNA.js.map → chunk-EZ6LFN33.js.map} +0 -0
  550. /package/dist/{chunk-4K64EKM7.js.map → chunk-F7YL6DPR.js.map} +0 -0
  551. /package/dist/{chunk-ICAMYP5M.js.map → chunk-FIGFXMUP.js.map} +0 -0
  552. /package/dist/{chunk-54U6ZBEX.js.map → chunk-FJRJK67G.js.map} +0 -0
  553. /package/dist/{chunk-E5KOWRDU.js.map → chunk-FLHB2NZT.js.map} +0 -0
  554. /package/dist/{chunk-D3PTVN2I.js.map → chunk-FUGGM76A.js.map} +0 -0
  555. /package/dist/{chunk-TDTD66BK.js.map → chunk-FXPZAZYT.js.map} +0 -0
  556. /package/dist/{chunk-KO3OHHY2.js.map → chunk-GAGAM4MT.js.map} +0 -0
  557. /package/dist/{chunk-TK5FWVZR.js.map → chunk-GESGH3HY.js.map} +0 -0
  558. /package/dist/{chunk-2VJOSU4H.js.map → chunk-GI4PWKXI.js.map} +0 -0
  559. /package/dist/{chunk-KFNZZ2N6.js.map → chunk-GJTEBAZ7.js.map} +0 -0
  560. /package/dist/{chunk-LTJFV2JI.js.map → chunk-GNCGEW7F.js.map} +0 -0
  561. /package/dist/{chunk-34NV52R3.js.map → chunk-GOMUNPB6.js.map} +0 -0
  562. /package/dist/{chunk-LIJNVIT3.js.map → chunk-GUMUILEI.js.map} +0 -0
  563. /package/dist/{chunk-7NLF35YL.js.map → chunk-GVGNHBFT.js.map} +0 -0
  564. /package/dist/{chunk-K3D7IQQP.js.map → chunk-GW4YI3FB.js.map} +0 -0
  565. /package/dist/{chunk-D5TIVCXG.js.map → chunk-GXKCV7X7.js.map} +0 -0
  566. /package/dist/{chunk-2J77TWGH.js.map → chunk-H467EQA6.js.map} +0 -0
  567. /package/dist/{chunk-3OK7Y6ES.js.map → chunk-HE77VDDR.js.map} +0 -0
  568. /package/dist/{chunk-UO35OEOX.js.map → chunk-HT65RGCX.js.map} +0 -0
  569. /package/dist/{chunk-G6ICCGJ3.js.map → chunk-HVQSFTE7.js.map} +0 -0
  570. /package/dist/{chunk-G5UQBTXY.js.map → chunk-HXJPDC76.js.map} +0 -0
  571. /package/dist/{chunk-GIWFLWXG.js.map → chunk-I6LQW24C.js.map} +0 -0
  572. /package/dist/{chunk-467WDSOK.js.map → chunk-I7A6S5YL.js.map} +0 -0
  573. /package/dist/{chunk-AAS7OWV6.js.map → chunk-IADS4ZYD.js.map} +0 -0
  574. /package/dist/{chunk-Y3XZEKDQ.js.map → chunk-IJWMWCGR.js.map} +0 -0
  575. /package/dist/{chunk-SGH7I7OY.js.map → chunk-IWFO6KOU.js.map} +0 -0
  576. /package/dist/{chunk-GMHIOYB7.js.map → chunk-IYC6QGV2.js.map} +0 -0
  577. /package/dist/{chunk-3NNAC43A.js.map → chunk-J5AODKJO.js.map} +0 -0
  578. /package/dist/{chunk-DIP7YALH.js.map → chunk-JKI3LMLH.js.map} +0 -0
  579. /package/dist/{chunk-IJR6VOLU.js.map → chunk-JSYRWOCE.js.map} +0 -0
  580. /package/dist/{chunk-CEMSIU4Z.js.map → chunk-JTQTWO4D.js.map} +0 -0
  581. /package/dist/{chunk-BASI553K.js.map → chunk-KBTKAAHM.js.map} +0 -0
  582. /package/dist/{chunk-OYOFPNLC.js.map → chunk-KD7VEMWY.js.map} +0 -0
  583. /package/dist/{chunk-3DRLCX5V.js.map → chunk-KPGFGRSA.js.map} +0 -0
  584. /package/dist/{chunk-PLYVGZIN.js.map → chunk-KWFDEJFI.js.map} +0 -0
  585. /package/dist/{chunk-FNXCFIPW.js.map → chunk-KYLEH4OF.js.map} +0 -0
  586. /package/dist/{chunk-WXF2RTS4.js.map → chunk-L7FJTFJN.js.map} +0 -0
  587. /package/dist/{chunk-KI46GKMD.js.map → chunk-L7VVQOSY.js.map} +0 -0
  588. /package/dist/{chunk-O2UPPN5M.js.map → chunk-LKLQVANM.js.map} +0 -0
  589. /package/dist/{chunk-YNTLWCF4.js.map → chunk-LLYEAZ4E.js.map} +0 -0
  590. /package/dist/{chunk-4Z5X7PLC.js.map → chunk-LWM7JUW6.js.map} +0 -0
  591. /package/dist/{chunk-CHU3RDV4.js.map → chunk-LXKV4ND3.js.map} +0 -0
  592. /package/dist/{chunk-AB5IW227.js.map → chunk-LYLICEQO.js.map} +0 -0
  593. /package/dist/{chunk-OTW25A6I.js.map → chunk-M5GRI5K4.js.map} +0 -0
  594. /package/dist/{chunk-X2QJXDE4.js.map → chunk-MF65PKKF.js.map} +0 -0
  595. /package/dist/{chunk-EDDKPIIV.js.map → chunk-MJ4XIOPM.js.map} +0 -0
  596. /package/dist/{chunk-FLWQJDJ5.js.map → chunk-MMPJJQG3.js.map} +0 -0
  597. /package/dist/{chunk-T67LTMSW.js.map → chunk-MOU54FGD.js.map} +0 -0
  598. /package/dist/{chunk-LQKVNREV.js.map → chunk-NAWHQ4IL.js.map} +0 -0
  599. /package/dist/{chunk-ZBHGNE2J.js.map → chunk-NBHBB2VV.js.map} +0 -0
  600. /package/dist/{chunk-U5UGM5XD.js.map → chunk-NMOZDAEZ.js.map} +0 -0
  601. /package/dist/{chunk-D74Z2N4K.js.map → chunk-NZA4R3BE.js.map} +0 -0
  602. /package/dist/{chunk-WRMUXZ7C.js.map → chunk-OB2CX7PJ.js.map} +0 -0
  603. /package/dist/{chunk-YJSCLGAW.js.map → chunk-OB4I4OIT.js.map} +0 -0
  604. /package/dist/{chunk-DWJ6J3YW.js.map → chunk-OKQW2FPL.js.map} +0 -0
  605. /package/dist/{chunk-2GCHGWNE.js.map → chunk-ORLX6A3C.js.map} +0 -0
  606. /package/dist/{chunk-EBTUPRRQ.js.map → chunk-P5N4EYFW.js.map} +0 -0
  607. /package/dist/{chunk-JKL5S7UQ.js.map → chunk-PL4JE3NI.js.map} +0 -0
  608. /package/dist/{chunk-OP2GD6QW.js.map → chunk-PNUHKDY2.js.map} +0 -0
  609. /package/dist/{chunk-MZY3VKKM.js.map → chunk-PWJE7D6V.js.map} +0 -0
  610. /package/dist/{chunk-RISUROBM.js.map → chunk-PYE27I6J.js.map} +0 -0
  611. /package/dist/{chunk-R5QAL43H.js.map → chunk-QIJHK6P4.js.map} +0 -0
  612. /package/dist/{chunk-AJBDAVX3.js.map → chunk-QK3A23NP.js.map} +0 -0
  613. /package/dist/{chunk-CYDXCILL.js.map → chunk-QLWDNAOV.js.map} +0 -0
  614. /package/dist/{chunk-BQYRZIZ7.js.map → chunk-QS6DQBVJ.js.map} +0 -0
  615. /package/dist/{chunk-3PZ3LRPV.js.map → chunk-QSUVFPG3.js.map} +0 -0
  616. /package/dist/{chunk-PYB4BFEC.js.map → chunk-QUC5MLTN.js.map} +0 -0
  617. /package/dist/{chunk-WDASYY4S.js.map → chunk-QVT5AWPI.js.map} +0 -0
  618. /package/dist/{chunk-K4DQS2ML.js.map → chunk-QZC6WCBR.js.map} +0 -0
  619. /package/dist/{chunk-HWVPLFIW.js.map → chunk-RAHNICPP.js.map} +0 -0
  620. /package/dist/{chunk-H6MJFMHZ.js.map → chunk-RME6RGIW.js.map} +0 -0
  621. /package/dist/{chunk-XMBOLFFS.js.map → chunk-RQIB2F53.js.map} +0 -0
  622. /package/dist/{chunk-OXQ2SXVC.js.map → chunk-RUA72NQY.js.map} +0 -0
  623. /package/dist/{chunk-UMX6DZME.js.map → chunk-SCJHWN4X.js.map} +0 -0
  624. /package/dist/{chunk-HTMQGS63.js.map → chunk-SIXBDT5F.js.map} +0 -0
  625. /package/dist/{chunk-ZAX4XQLN.js.map → chunk-SPK3T4JK.js.map} +0 -0
  626. /package/dist/{chunk-WTSQUCHB.js.map → chunk-SSN2YSST.js.map} +0 -0
  627. /package/dist/{chunk-5MIBQ4P5.js.map → chunk-SYJCDX5V.js.map} +0 -0
  628. /package/dist/{chunk-ZR5EKJT6.js.map → chunk-T6276OXI.js.map} +0 -0
  629. /package/dist/{chunk-DEHLWZSI.js.map → chunk-T7OARG4N.js.map} +0 -0
  630. /package/dist/{chunk-77BHKC43.js.map → chunk-TF5L3BEV.js.map} +0 -0
  631. /package/dist/{chunk-GOCODNQS.js.map → chunk-TF6Z7BOP.js.map} +0 -0
  632. /package/dist/{chunk-WIFDNUKD.js.map → chunk-TJDXWZMO.js.map} +0 -0
  633. /package/dist/{chunk-SFIXTOOJ.js.map → chunk-TL5ATBHZ.js.map} +0 -0
  634. /package/dist/{chunk-XZCCEKPW.js.map → chunk-TMOHIOMT.js.map} +0 -0
  635. /package/dist/{chunk-AVXDIRRW.js.map → chunk-UI5X63YC.js.map} +0 -0
  636. /package/dist/{chunk-6QK65ZWM.js.map → chunk-UIY7BDZC.js.map} +0 -0
  637. /package/dist/{chunk-VATYK3JQ.js.map → chunk-UMBFMEO7.js.map} +0 -0
  638. /package/dist/{chunk-UU5FBVRX.js.map → chunk-UU5G7OA4.js.map} +0 -0
  639. /package/dist/{chunk-EGKARC53.js.map → chunk-UZUCYCF4.js.map} +0 -0
  640. /package/dist/{chunk-LPKJ77EK.js.map → chunk-V2A7G7S7.js.map} +0 -0
  641. /package/dist/{chunk-CH4UQ4NO.js.map → chunk-V5G4TKRC.js.map} +0 -0
  642. /package/dist/{chunk-UBRQ3PQD.js.map → chunk-VKAVW34W.js.map} +0 -0
  643. /package/dist/{chunk-JV5ULONH.js.map → chunk-VVLEVNTQ.js.map} +0 -0
  644. /package/dist/{chunk-44JWVYJB.js.map → chunk-VW7X7TWZ.js.map} +0 -0
  645. /package/dist/{chunk-3CDJSKDW.js.map → chunk-VWA2CHSL.js.map} +0 -0
  646. /package/dist/{chunk-IN3VQFKS.js.map → chunk-W43HZPM7.js.map} +0 -0
  647. /package/dist/{chunk-SXGJL7UT.js.map → chunk-WHGD7Q2L.js.map} +0 -0
  648. /package/dist/{chunk-XOIDUM2H.js.map → chunk-WNXKYEVN.js.map} +0 -0
  649. /package/dist/{chunk-TKQL7EDB.js.map → chunk-WSA7UBX4.js.map} +0 -0
  650. /package/dist/{chunk-AJDGP2N4.js.map → chunk-WZ5TQJ3T.js.map} +0 -0
  651. /package/dist/{chunk-FBA2NXYH.js.map → chunk-X3TGNSOG.js.map} +0 -0
  652. /package/dist/{chunk-R4JA5JFI.js.map → chunk-X4WXYI3N.js.map} +0 -0
  653. /package/dist/{chunk-Q5EZNBPI.js.map → chunk-XIQ3AIAJ.js.map} +0 -0
  654. /package/dist/{chunk-S27VZ5DO.js.map → chunk-XWYT4LEL.js.map} +0 -0
  655. /package/dist/{chunk-477DTTMH.js.map → chunk-Y3PU75OC.js.map} +0 -0
  656. /package/dist/{chunk-4JXPLTWV.js.map → chunk-Y5ZWX5YS.js.map} +0 -0
  657. /package/dist/{chunk-4BWMAGJJ.js.map → chunk-YA5PABND.js.map} +0 -0
  658. /package/dist/{chunk-OGU73VUN.js.map → chunk-YBPRR2QS.js.map} +0 -0
  659. /package/dist/{chunk-TNSJFZ6Q.js.map → chunk-YDYR7XQE.js.map} +0 -0
  660. /package/dist/{chunk-GTRAH4FG.js.map → chunk-YG6V2LQH.js.map} +0 -0
  661. /package/dist/{chunk-XVLEBB4Y.js.map → chunk-YUXA7ALE.js.map} +0 -0
  662. /package/dist/{chunk-SN2WENRP.js.map → chunk-YWHQDXPB.js.map} +0 -0
  663. /package/dist/{chunk-BFFNINCC.js.map → chunk-YWRR5R7B.js.map} +0 -0
  664. /package/dist/{chunk-FSDQQQIA.js.map → chunk-YYRK7A4N.js.map} +0 -0
  665. /package/dist/{chunk-MRECRNVU.js.map → chunk-Z26CDLUV.js.map} +0 -0
  666. /package/dist/{chunk-OYCK4JRS.js.map → chunk-Z27EXLMQ.js.map} +0 -0
  667. /package/dist/{chunk-UTRNLNCW.js.map → chunk-Z7GDH7W2.js.map} +0 -0
  668. /package/dist/{chunk-PRT4J2DL.js.map → chunk-ZGVLSAWL.js.map} +0 -0
  669. /package/dist/{chunk-OK7BQMCI.js.map → chunk-ZM6Q5NQN.js.map} +0 -0
  670. /package/dist/{computer-viewer-5LKRCEVQ.js.map → computer-viewer-SROXREYD.js.map} +0 -0
  671. /package/dist/{embedded-new-voice-GHJRY3YL.js.map → embedded-new-voice-EIQY2VBF.js.map} +0 -0
  672. /package/dist/{embedded-voice-ASQXBSTX.js.map → embedded-voice-LMWNH7F7.js.map} +0 -0
  673. /package/dist/{fleet-decision-row-U7LDVBEM.js.map → fleet-decision-row-X2G56ZRA.js.map} +0 -0
  674. /package/dist/{latest-question-RNVF262Q.js.map → latest-question-KA7AQYVI.js.map} +0 -0
  675. /package/dist/{model-policy-picker-menu-E6XKMFTA.js.map → model-policy-picker-menu-SHWPT5VA.js.map} +0 -0
  676. /package/dist/{payment-page-card-DJDKV2LW.js.map → payment-page-card-NNVUISN4.js.map} +0 -0
  677. /package/dist/{platform-activity-row-MSDCSMET.js.map → platform-activity-row-7UDWSAHK.js.map} +0 -0
  678. /package/dist/{queue-surface-implementation-GUAIG6TK.js.map → queue-surface-implementation-BUXSO24N.js.map} +0 -0
  679. /package/dist/{recorder-host-2MYDJPQW.js.map → recorder-host-POX54CFT.js.map} +0 -0
  680. /package/dist/{sandbox-files-W5W2LW4K.js.map → sandbox-files-33QD7DW2.js.map} +0 -0
  681. /package/dist/{session-connect-cards-HPH7JOZP.js.map → session-connect-cards-CXGNVA2A.js.map} +0 -0
  682. /package/dist/{session-realtime-SDTKFFIR.js.map → session-realtime-CVDSEULB.js.map} +0 -0
  683. /package/dist/{timeline-annotation-markers-FNILLWNU.js.map → timeline-annotation-markers-5J5TM5IP.js.map} +0 -0
  684. /package/dist/{timeline-annotation-selection-MBCIDO2Q.js.map → timeline-annotation-selection-WLY7FB7F.js.map} +0 -0
  685. /package/dist/{timeline-annotations-dialog-JPNKLOTE.js.map → timeline-annotations-dialog-67VRFKJU.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/app/lib/sessions-group.tsx"],"sourcesContent":["// Pure helpers behind the rail's session list: relative-time labels, recency\n// bucketing (Today / Yesterday / Previous 7 days / Older), and the ordering\n// rule — RUNNING sessions pinned to the very top, then most-recent activity\n// first within each recency group.\nimport { t } from \"./console-text\";\nimport { formatWaitingSince } from \"./format\";\nimport { awaitsPerson } from \"./needs-you\";\nimport { sessionInputWait } from \"./session-rail\";\nimport { sessionSiteOrigin, type SessionSiteOrigin } from \"./session-site-origin\";\nimport type { SessionListTotals, SiteConversationGroup } from \"@opengeni/sdk\";\nimport type { RailSession as Session } from \"./session-list-entry\";\n\n// The flat list rules are shared with native renderers through the pure\n// session-list model; the rail-only forest, project and browse logic stays here.\nimport {\n compareSessionActivity,\n compareSessionPins,\n hasActiveEffectiveControl,\n isEffectivelyRunning,\n partitionPinnedSessions,\n recencyGroupFor,\n SESSION_GROUP_LABELS,\n SESSION_GROUP_ORDER,\n sessionActivityTime,\n type SessionRecencyGroup,\n} from \"../../session-list-model\";\n\nexport {\n compareSessionActivity,\n compareSessionPins,\n groupSessionsForRail,\n isRunningStatus,\n partitionPinnedSessions,\n recencyGroupFor,\n relativeTimeLabel,\n SESSION_GROUP_LABELS,\n SESSION_GROUP_ORDER,\n sessionActivityTime,\n type GroupedSessions,\n type SessionRecencyBucket,\n type SessionRecencyGroup,\n} from \"../../session-list-model\";\n\n/* ----------------------------------------------------------------------------\n Lineage nesting for the rail\n\n The rail nests spawned worker sessions under the manager that spawned them\n (parentSessionId). A session is a ROOT in the rail when it has no parent OR\n its parent isn't in the loaded page (an orphan child renders at the root, as\n before). Roots are pinned/bucketed exactly like the flat list — but a root\n counts as \"running\" when it OR any descendant is active, so a manager whose\n only activity is a live child still floats to the top.\n -------------------------------------------------------------------------- */\n\nexport type SessionTreeNode = {\n /** Presentation-only group; never persisted or used for session actions. */\n siteGroup?: SessionSiteOrigin | undefined;\n /**\n * A Site row's complete server counts, independent of which conversations\n * are loaded. Absent when the row was built from loaded conversations only.\n */\n siteSummary?: SiteRowSummary | undefined;\n session: Session;\n children: SessionTreeNode[];\n /** A descendant (any depth, not the node itself) is running/queued/awaiting action. */\n hasActiveDescendant: boolean;\n};\n\nexport type RailAggregateStatusKind =\n | \"send_failed\"\n | \"needs_attention\"\n | \"failed\"\n | \"active\"\n | \"queued\"\n | \"waiting\"\n | \"unread\"\n | \"active_work\"\n | \"neutral\";\n\nexport type RailAggregateStatus = {\n kind: RailAggregateStatusKind;\n /** Number of sessions represented by the winning status. */\n count: number;\n /** Total sessions represented by the node or section. */\n total: number;\n label: string;\n /**\n * `needs_attention` only: when the longest-waiting represented session\n * entered `requires_action` (the earliest known `requiresActionSince` /\n * `treeStats.attentionSince`). Absent when no server reported it.\n */\n attentionSince?: string | undefined;\n};\n\nexport type RailStatusCounts = {\n total: number;\n sendFailed: number;\n attention: number;\n /** Earliest known requires_action entry across the counted `attention` sessions. */\n attentionSince: string | null;\n failed: number;\n active: number;\n queued: number;\n /** Idle sessions parked on their own wake-up (input or timer), not executing. */\n waiting: number;\n unread: number;\n activeWork: number;\n};\n\n/** Complete ordinary project counters; absent groups are authoritative zeroes. */\nexport function sessionProjectTotals(\n totals: SessionListTotals,\n channelIds: readonly string[],\n): Map<string | null, RailStatusCounts> {\n const known = new Set(channelIds);\n const zero = (): RailStatusCounts => ({\n total: 0,\n sendFailed: 0,\n attention: 0,\n attentionSince: null,\n failed: 0,\n active: 0,\n queued: 0,\n waiting: 0,\n unread: 0,\n activeWork: 0,\n });\n const result = new Map<string | null, RailStatusCounts>([\n ...channelIds.map((id) => [id, zero()] as const),\n [null, zero()],\n ]);\n for (const group of totals.groups) {\n const id = group.channelId && known.has(group.channelId) ? group.channelId : null;\n // Server `active` includes input waits for older clients; split them out.\n const waiting = Math.min(group.waiting ?? 0, group.active);\n addRailStatusCounts(result.get(id)!, {\n ...group,\n active: group.active - waiting,\n waiting,\n sendFailed: 0,\n });\n }\n return result;\n}\n\nfunction earliestIso(a: string | null | undefined, b: string | null | undefined): string | null {\n if (!a) return b ?? null;\n if (!b) return a;\n return Date.parse(b) < Date.parse(a) ? b : a;\n}\n\nfunction ownRailStatusCounts(\n session: Session,\n localDeliveryAttention: ReadonlyMap<string, number>,\n): RailStatusCounts {\n return {\n total: 1,\n sendFailed: localDeliveryAttention.get(session.id) ?? 0,\n attention: awaitsPerson(session) ? 1 : 0,\n attentionSince: awaitsPerson(session) ? (session.requiresActionSince ?? null) : null,\n // Failed is a review signal in the rail, not a permanent copy of the\n // lifecycle badge. Opening the session (or a parent agent consuming its\n // result) acknowledges the failure together with the unread frontier.\n failed: session.status === \"failed\" && session.unread ? 1 : 0,\n active:\n hasActiveEffectiveControl(session) &&\n (session.status === \"running\" || session.status === \"recovering\")\n ? 1\n : 0,\n queued:\n hasActiveEffectiveControl(session) &&\n (session.status === \"queued\" || session.status === \"waiting_capacity\")\n ? 1\n : 0,\n waiting: sessionInputWait(session) ? 1 : 0,\n unread: session.unread ? 1 : 0,\n activeWork: session.activelyWorking ? 1 : 0,\n };\n}\n\nfunction addRailStatusCounts(target: RailStatusCounts, source: RailStatusCounts): void {\n target.total += source.total;\n target.sendFailed += source.sendFailed;\n target.attention += source.attention;\n target.attentionSince = earliestIso(target.attentionSince, source.attentionSince);\n target.failed += source.failed;\n target.active += source.active;\n target.queued += source.queued;\n target.waiting += source.waiting;\n target.unread += source.unread;\n target.activeWork += source.activeWork;\n}\n\nfunction railStatusCounts(\n node: SessionTreeNode,\n localDeliveryAttention: ReadonlyMap<string, number>,\n): RailStatusCounts {\n if (node.siteGroup && node.siteSummary) {\n // Complete server counts; loaded rows add only browser-local send failures.\n const summary = node.siteSummary;\n const waiting = Math.min(summary.waiting, summary.active);\n return {\n total: summary.total,\n sendFailed: node.children.reduce(\n (total, child) => total + loadedLocalDeliveryFailureCount(child, localDeliveryAttention),\n 0,\n ),\n attention: summary.attention,\n attentionSince: summary.attentionSince,\n failed: summary.failed,\n active: summary.active - waiting,\n queued: summary.queued,\n waiting,\n unread: summary.unread,\n activeWork: summary.activeWork,\n };\n }\n if (node.siteGroup) {\n const counts = ownRailStatusCounts(node.session, localDeliveryAttention);\n for (const key of [\n \"total\",\n \"sendFailed\",\n \"attention\",\n \"failed\",\n \"active\",\n \"queued\",\n \"waiting\",\n \"unread\",\n \"activeWork\",\n ] as const)\n counts[key] = 0;\n counts.attentionSince = null;\n for (const child of node.children)\n addRailStatusCounts(counts, railStatusCounts(child, localDeliveryAttention));\n return counts;\n }\n const counts = ownRailStatusCounts(node.session, localDeliveryAttention);\n const stats = node.session.treeStats;\n if (stats) {\n counts.total += stats.totalDescendants;\n counts.attention += stats.attentionDescendants;\n counts.attentionSince = earliestIso(counts.attentionSince, stats.attentionSince);\n counts.failed += stats.unreadFailedDescendants ?? stats.failedDescendants;\n counts.active += stats.runningDescendants;\n counts.queued += stats.queuedDescendants;\n counts.waiting += stats.waitingDescendants ?? 0;\n counts.unread += stats.unreadDescendants ?? 0;\n counts.activeWork += stats.activelyWorkingDescendants ?? 0;\n\n // Scheduled-task grouping appends older root runs as synthetic children of\n // the newest run. They are not part of that run's server treeStats, unlike\n // ordinary spawned children, so include only those extra roots here.\n for (const child of node.children) {\n if (child.session.parentSessionId !== node.session.id) {\n addRailStatusCounts(counts, railStatusCounts(child, localDeliveryAttention));\n } else {\n counts.sendFailed += loadedLocalDeliveryFailureCount(child, localDeliveryAttention);\n }\n }\n } else {\n for (const child of node.children) {\n addRailStatusCounts(counts, railStatusCounts(child, localDeliveryAttention));\n }\n }\n return counts;\n}\n\n/**\n * Durable treeStats already account for ordinary descendants' lifecycle state,\n * but browser-local delivery failures have no server aggregate. Fold only that\n * local fact through the loaded child tree so collapsed parents stay truthful.\n */\nfunction loadedLocalDeliveryFailureCount(\n node: SessionTreeNode,\n localDeliveryAttention: ReadonlyMap<string, number>,\n): number {\n return (\n (localDeliveryAttention.get(node.session.id) ?? 0) +\n node.children.reduce(\n (total, child) => total + loadedLocalDeliveryFailureCount(child, localDeliveryAttention),\n 0,\n )\n );\n}\n\n/** One status for a collapsed parent or workstream, including all descendants. */\nexport function summarizeRailNodes(\n nodes: readonly SessionTreeNode[],\n localDeliveryAttention: ReadonlyMap<string, number> = new Map(),\n now: Date = new Date(),\n): RailAggregateStatus {\n const counts: RailStatusCounts = {\n total: 0,\n sendFailed: 0,\n attention: 0,\n attentionSince: null,\n failed: 0,\n active: 0,\n queued: 0,\n waiting: 0,\n unread: 0,\n activeWork: 0,\n };\n for (const node of nodes) {\n addRailStatusCounts(counts, railStatusCounts(node, localDeliveryAttention));\n }\n\n return summarizeRailStatusCounts(counts, now);\n}\n\n/**\n * The marker for one chat's row: the chat and everything it started.\n *\n * Like {@link summarizeRailNodes}, except that the chat's own unread reply\n * outranks its workers' progress. A manager that has answered you while its\n * workers still run (or while it waits on them) shows the unread dot, not a\n * spinner or hourglass that reads as \"nothing for you yet\". What the dot now\n * covers stays in its label (\"1 unread · 2 working\"), and an expanded row's\n * workers keep their own markers. The chat's own running or queued turn keeps\n * its spinner: progress it posts mid-turn can leave it unread, and the answer\n * arrives when that turn ends. Anything that needs you, a failure and an\n * unsent message still come first. Section headers and Site rows summarize\n * many chats and keep the plain order.\n */\nexport function summarizeRailRow(\n node: SessionTreeNode,\n localDeliveryAttention: ReadonlyMap<string, number> = new Map(),\n now: Date = new Date(),\n): RailAggregateStatus {\n const counts = railStatusCounts(node, localDeliveryAttention);\n const summary = summarizeRailStatusCounts(counts, now);\n if (node.siteGroup || !node.session.unread) return summary;\n if (summary.kind !== \"active\" && summary.kind !== \"queued\" && summary.kind !== \"waiting\")\n return summary;\n const own = ownRailStatusCounts(node.session, localDeliveryAttention);\n if (own.active > 0 || own.queued > 0) return summary;\n return {\n kind: \"unread\",\n count: counts.unread,\n total: counts.total,\n label: `${counts.unread} unread · ${summary.label}`,\n };\n}\n\n/** Shared presentation for complete server metadata and loaded node summaries. */\nexport function summarizeRailStatusCounts(\n counts: RailStatusCounts,\n now: Date = new Date(),\n): RailAggregateStatus {\n if (counts.sendFailed > 0) {\n return {\n kind: \"send_failed\",\n count: counts.sendFailed,\n total: counts.total,\n label: `${counts.sendFailed} message${counts.sendFailed === 1 ? \"\" : \"s\"} not sent`,\n };\n }\n\n if (counts.attention > 0) {\n // \"2 need you · 10h\": how long the longest-waiting one has been blocked on\n // a human, so a parked child is never silent in a collapsed parent row.\n const waiting = counts.attentionSince ? formatWaitingSince(counts.attentionSince, now) : \"\";\n return {\n kind: \"needs_attention\",\n count: counts.attention,\n total: counts.total,\n label: `${counts.attention} need${counts.attention === 1 ? \"s\" : \"\"} you${\n waiting ? ` · ${waiting}` : \"\"\n }`,\n ...(counts.attentionSince ? { attentionSince: counts.attentionSince } : {}),\n };\n }\n if (counts.failed > 0) {\n return {\n kind: \"failed\",\n count: counts.failed,\n total: counts.total,\n label: `${counts.failed} failed`,\n };\n }\n if (counts.active > 0) {\n return {\n kind: \"active\",\n count: counts.active,\n total: counts.total,\n label: `${counts.active} working`,\n };\n }\n if (counts.queued > 0) {\n return {\n kind: \"queued\",\n count: counts.queued,\n total: counts.total,\n label: `${counts.queued} waiting to run`,\n };\n }\n if (counts.waiting > 0) {\n return {\n kind: \"waiting\",\n count: counts.waiting,\n total: counts.total,\n label: `${counts.waiting} waiting to resume`,\n };\n }\n if (counts.unread > 0) {\n return {\n kind: \"unread\",\n count: counts.unread,\n total: counts.total,\n label: `${counts.unread} unread`,\n };\n }\n if (counts.activeWork > 0) {\n return {\n kind: \"active_work\",\n count: counts.activeWork,\n total: counts.total,\n label: `${counts.activeWork} actively working`,\n };\n }\n return {\n kind: \"neutral\",\n count: 0,\n total: counts.total,\n label: counts.total > 0 ? \"Read\" : \"Empty\",\n };\n}\n\n/**\n * Merge two projections of the same session for the rail. Detail/SSE data is\n * fresher for lifecycle fields, but detail reads intentionally omit treeStats.\n * An omitted list-only field must not make the selected row forget its loaded\n * hierarchy summary (and therefore lose its disclosure control).\n */\nexport function mergeSessionForRail<T extends Session>(current: Session, incoming: T): T {\n if (incoming.treeStats !== undefined || current.treeStats === undefined) {\n return incoming;\n }\n return { ...incoming, treeStats: current.treeStats };\n}\n\nexport type SessionForest = {\n running: SessionTreeNode[];\n grouped: {\n group: string;\n label: string;\n sessions: SessionTreeNode[];\n }[];\n};\n\nexport type SessionBrowseGroupBy = \"activity\" | \"project\" | \"none\" | \"created\" | \"creator\";\nexport type SessionBrowseSortBy = \"updatedAt\" | \"createdAt\" | \"name\";\n\nconst sessionNameEncoder = new TextEncoder();\nfunction sessionNameSortKey(title: string | null | undefined): Uint8Array {\n return sessionNameEncoder.encode(\n (title ?? \"\").replace(/^ +| +$/g, \"\").replace(/[A-Z]/g, (letter) => letter.toLowerCase()),\n );\n}\n\nfunction sessionSortMicroseconds(value: string): number {\n const fraction = value.match(/\\.(\\d+)(?:Z|[+-]\\d{2}:\\d{2})$/)?.[1] ?? \"\";\n return Number(fraction.padEnd(6, \"0\").slice(3, 6));\n}\n\n/** The same ordering as the server page, reapplied after live projection merges. */\nexport function compareSessionBrowse(\n left: Session,\n right: Session,\n sortBy: SessionBrowseSortBy,\n): number {\n if (sortBy === \"name\") {\n const a = sessionNameSortKey(left.title);\n const b = sessionNameSortKey(right.title);\n for (let index = 0; index < Math.min(a.length, b.length); index += 1) {\n if (a[index] !== b[index]) return a[index]! - b[index]!;\n }\n return a.length - b.length || left.id.localeCompare(right.id);\n }\n return (\n Date.parse(right[sortBy]) - Date.parse(left[sortBy]) ||\n sessionSortMicroseconds(right[sortBy]) - sessionSortMicroseconds(left[sortBy]) ||\n right.id.localeCompare(left.id)\n );\n}\n\nexport function sortSessionForest(\n forest: SessionForest,\n sortBy: SessionBrowseSortBy,\n): SessionForest {\n const sortNodes = (nodes: SessionTreeNode[]): SessionTreeNode[] =>\n nodes\n .map((node) => ({ ...node, children: sortNodes(node.children) }))\n .sort((a, b) => compareSessionBrowse(a.session, b.session, sortBy));\n return {\n running: sortNodes(forest.running),\n grouped: forest.grouped.map((bucket) => ({\n ...bucket,\n sessions: sortNodes(bucket.sessions),\n })),\n };\n}\nexport type SessionBrowseDateField = \"activity\" | \"created\";\nexport type SessionBrowseDateRange = \"any\" | \"today\" | \"week\" | \"month\";\n\nexport function sessionCreatorKey(session: Session): string {\n return `${session.createdBy.kind}:${session.createdBy.subjectId}`;\n}\n\nexport function sessionCreatorLabel(session: Session): string {\n const explicit = session.createdBy.label?.trim();\n if (explicit) return explicit;\n if (session.createdBy.subjectId === \"unattributed-legacy\") return \"Unattributed\";\n if (session.createdBy.kind === \"service\") {\n return `Service · ${session.createdBy.subjectId}`;\n }\n return session.createdBy.subjectId;\n}\n\nexport type SessionCreatorOption = {\n value: string;\n label: string;\n};\n\n/**\n * Loaded creator choices with identity-specific labels only when frozen display\n * labels collide. The subject ID remains opaque; it is displayed, not parsed.\n */\nexport function sessionCreatorLabelMap(sessions: Session[]): ReadonlyMap<string, string> {\n const byKey = new Map<\n string,\n { label: string; kind: Session[\"createdBy\"][\"kind\"]; subjectId: string }\n >();\n for (const session of sessions) {\n byKey.set(sessionCreatorKey(session), {\n label: sessionCreatorLabel(session),\n kind: session.createdBy.kind,\n subjectId: session.createdBy.subjectId,\n });\n }\n\n const labelCounts = new Map<string, number>();\n for (const creator of byKey.values()) {\n labelCounts.set(creator.label, (labelCounts.get(creator.label) ?? 0) + 1);\n }\n\n return new Map(\n [...byKey.entries()]\n .map(([value, creator]) => ({\n value,\n label:\n labelCounts.get(creator.label) === 1\n ? creator.label\n : `${creator.label} · ${creator.kind === \"service\" ? \"Service\" : \"Subject\"} · ${creator.subjectId}`,\n }))\n .sort(\n (left, right) =>\n left.label.localeCompare(right.label) || left.value.localeCompare(right.value),\n )\n .map((creator) => [creator.value, creator.label]),\n );\n}\n\nexport function sessionCreatorOptions(sessions: Session[]): SessionCreatorOption[] {\n return [...sessionCreatorLabelMap(sessions)].map(([value, label]) => ({ value, label }));\n}\n\n/** Drop a flat-search creator selection that is not valid for hierarchical browse roots. */\nexport function normalizeSessionBrowseCreator(\n creator: string | null,\n creatorLabels: ReadonlyMap<string, string>,\n hierarchical: boolean,\n): string | null {\n if (!hierarchical || !creator || creatorLabels.has(creator)) return creator;\n return null;\n}\n\n/** Count matching rows in flat search, or matching workstream roots in hierarchical browse. */\nexport function sessionBrowseResultCount(\n sessions: readonly Session[],\n hierarchical: boolean,\n): number {\n if (!hierarchical) return sessions.length;\n const loadedIds = new Set(sessions.map((session) => session.id));\n return sessions.filter(\n (session) => !session.parentSessionId || !loadedIds.has(session.parentSessionId),\n ).length;\n}\n\nfunction browseTimestamp(session: Session, field: SessionBrowseDateField): number {\n if (field === \"activity\") return sessionActivityTime(session);\n const created = Date.parse(session.createdAt);\n return Number.isNaN(created) ? 0 : created;\n}\n\nexport function filterSessionsForBrowse<T extends Session>(\n sessions: T[],\n options: {\n creator: string | null;\n dateField: SessionBrowseDateField;\n dateRange: SessionBrowseDateRange;\n /** Filter whole loaded workstreams by their root instead of orphaning descendants. */\n hierarchical?: boolean | undefined;\n now?: Date | undefined;\n },\n): T[] {\n const now = options.now ?? new Date();\n const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();\n const threshold =\n options.dateRange === \"today\"\n ? startOfToday\n : options.dateRange === \"week\"\n ? startOfToday - 6 * 24 * 60 * 60 * 1000\n : options.dateRange === \"month\"\n ? startOfToday - 29 * 24 * 60 * 60 * 1000\n : null;\n const matches = (session: T): boolean =>\n (!options.creator || sessionCreatorKey(session) === options.creator) &&\n (threshold === null || browseTimestamp(session, options.dateField) >= threshold);\n if (!options.hierarchical) return sessions.filter(matches);\n\n const byId = new Map(sessions.map((session) => [session.id, session]));\n const rootById = new Map<string, T>();\n const hierarchyRoot = (session: T): T => {\n const cached = rootById.get(session.id);\n if (cached) return cached;\n\n const path: T[] = [];\n const seen = new Set<string>();\n let current = session;\n while (current.parentSessionId) {\n if (seen.has(current.id)) {\n // A pathological cycle has no meaningful root. Fall back to direct\n // row filtering so every member stays independently reachable.\n return session;\n }\n seen.add(current.id);\n path.push(current);\n const parent = byId.get(current.parentSessionId);\n if (!parent) break;\n current = parent;\n }\n rootById.set(current.id, current);\n for (const member of path) rootById.set(member.id, current);\n return current;\n };\n\n return sessions.filter((session) => matches(hierarchyRoot(session)));\n}\n\n/** Regroup already-built workstream roots without flattening their descendants. */\nexport function groupSessionForestForBrowse(\n forest: SessionForest,\n groupBy: Exclude<SessionBrowseGroupBy, \"activity\">,\n options: {\n now?: Date | undefined;\n creatorLabels?: ReadonlyMap<string, string> | undefined;\n } = {},\n): SessionForest {\n const now = options.now ?? new Date();\n const roots = forestRoots(forest);\n if (groupBy === \"none\" || groupBy === \"project\") {\n return { running: [], grouped: [{ group: \"none\", label: \"Sessions\", sessions: roots }] };\n }\n const running = roots\n .filter(nodeIsActive)\n .sort((left, right) => compareSessionActivity(left.session, right.session));\n const rest = roots.filter((node) => !nodeIsActive(node));\n if (groupBy === \"created\") {\n const buckets = new Map<SessionRecencyGroup, SessionTreeNode[]>();\n for (const node of rest) {\n const group = recencyGroupFor(browseTimestamp(node.session, \"created\"), now);\n const list = buckets.get(group) ?? [];\n list.push(node);\n buckets.set(group, list);\n }\n return {\n running,\n grouped: SESSION_GROUP_ORDER.flatMap((group) => {\n const list = buckets.get(group);\n if (!list?.length) return [];\n const label =\n group === \"today\"\n ? \"Created today\"\n : group === \"yesterday\"\n ? \"Created yesterday\"\n : group === \"previous7\"\n ? \"Created in previous 7 days\"\n : \"Created earlier\";\n return [\n {\n group: `created:${group}`,\n label,\n sessions: list.sort(\n (left, right) =>\n browseTimestamp(right.session, \"created\") -\n browseTimestamp(left.session, \"created\") ||\n right.session.id.localeCompare(left.session.id),\n ),\n },\n ];\n }),\n };\n }\n\n const creatorLabels =\n options.creatorLabels ?? sessionCreatorLabelMap(roots.map((node) => node.session));\n const creators = new Map<string, { label: string; sessions: SessionTreeNode[] }>();\n for (const node of rest) {\n const key = sessionCreatorKey(node.session);\n const bucket = creators.get(key) ?? {\n label: creatorLabels.get(key) ?? sessionCreatorLabel(node.session),\n sessions: [],\n };\n bucket.sessions.push(node);\n creators.set(key, bucket);\n }\n return {\n running,\n grouped: [...creators.entries()]\n .sort(([, left], [, right]) => left.label.localeCompare(right.label))\n .map(([key, bucket]) => ({\n group: `creator:${key}`,\n label: bucket.label,\n sessions: bucket.sessions.sort((left, right) =>\n compareSessionActivity(left.session, right.session),\n ),\n })),\n };\n}\n\n/** Build and regroup a loaded session set while preserving its lineage tree. */\nexport function groupSessionsForBrowse(\n sessions: Session[],\n groupBy: Exclude<SessionBrowseGroupBy, \"activity\">,\n options: {\n now?: Date | undefined;\n creatorLabels?: ReadonlyMap<string, string> | undefined;\n } = {},\n): SessionForest {\n return groupSessionForestForBrowse(buildRailForest(sessions, options.now), groupBy, options);\n}\n\nexport type PinnedRailSections = {\n /** Complete loaded hierarchy, used for expansion and lineage lookups. */\n complete: SessionForest;\n /** Every explicit pin is an independently ordered shortcut root. */\n pinned: SessionTreeNode[];\n /** The ordinary hierarchy with every pin-owned subtree removed. */\n ordinary: SessionForest;\n};\n\n/** Whether the node's own status, or any descendant, is in a live state. */\nexport function nodeIsActive(node: SessionTreeNode): boolean {\n const stats = node.session.treeStats;\n const summarizedActive = Boolean(\n stats &&\n stats.runningDescendants +\n stats.queuedDescendants +\n (stats.waitingDescendants ?? 0) +\n stats.attentionDescendants >\n 0,\n );\n return isEffectivelyRunning(node.session) || node.hasActiveDescendant || summarizedActive;\n}\n\n/** Bucket already-built roots using the rail's activity and recency rules. */\n/**\n * The scheduled task a session was created for, or null. The worker stamps this\n * onto every session it generates for a run; it is deliberately read from\n * metadata rather than a column, because that is where the scheduler writes it.\n * A session a human started never carries the key, so it never groups.\n */\nexport function scheduledTaskIdOf(session: Session): string | null {\n if (\"scheduledTaskId\" in session) return session.scheduledTaskId;\n const value = (session.metadata as Record<string, unknown> | undefined)?.scheduledTaskId;\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\n/**\n * Collapse repeat runs of one scheduled task into a single rail entry.\n *\n * A schedule that fires hourly would otherwise push every other session out of\n * the rail, so runs of the same task fold together. This deliberately does NOT\n * introduce a scheduled-task row type: the newest run IS the entry, and the\n * older runs become its children, so the group renders and behaves exactly like\n * an ordinary session with spawned children. Clicking it opens the latest run,\n * expanding it reveals the rest, and each one stays individually openable.\n *\n * A task with a single run is left completely alone - one session is not a\n * flood, and wrapping it would only add a disclosure with nothing behind it.\n *\n * `roots` arrives running-first-then-recency, not purely newest-first, so the\n * members are re-sorted by activity here: the umbrella must be the latest run,\n * and the runs behind it must read newest to oldest. The group keeps the list\n * position of whichever member ranked highest in the incoming order, so folding\n * never pushes a live run down the rail.\n */\nexport function groupScheduledRuns(roots: SessionTreeNode[]): SessionTreeNode[] {\n const membersByTask = new Map<string, SessionTreeNode[]>();\n for (const node of roots) {\n const taskId = scheduledTaskIdOf(node.session);\n if (!taskId) continue;\n const members = membersByTask.get(taskId) ?? [];\n members.push(node);\n membersByTask.set(taskId, members);\n }\n for (const members of membersByTask.values()) {\n members.sort((left, right) => compareSessionActivity(left.session, right.session));\n }\n const grouped: SessionTreeNode[] = [];\n const emitted = new Set<string>();\n for (const node of roots) {\n const taskId = scheduledTaskIdOf(node.session);\n const members = taskId ? (membersByTask.get(taskId) ?? []) : [];\n if (members.length < 2) {\n grouped.push(node);\n continue;\n }\n if (emitted.has(taskId!)) continue;\n emitted.add(taskId!);\n const [latestRun, ...olderRuns] = members as [SessionTreeNode, ...SessionTreeNode[]];\n grouped.push({\n ...latestRun,\n // The latest run's own spawned children stay first; previous runs follow,\n // so a subagent of the latest run never sorts below an older run.\n children: [...latestRun.children, ...olderRuns],\n hasActiveDescendant:\n latestRun.hasActiveDescendant ||\n olderRuns.some((run) => nodeIsActive(run) || run.hasActiveDescendant),\n });\n }\n return grouped;\n}\n\nexport type SiteRowSummary = Omit<SiteConversationGroup, \"siteId\" | \"channelId\" | \"title\">;\n\n/**\n * A Site row's stable id. Rows are per project when the rail shows projects,\n * so a Site used from two projects appears in each; otherwise one per Site.\n */\nexport function siteRowKey(siteId: string, channelId?: string | null): string {\n return channelId === undefined ? `site:${siteId}` : `site:${siteId}:${channelId ?? \"default\"}`;\n}\n\n/** The Site and project a Site row stands for, or null for an ordinary id. */\nexport function parseSiteRowKey(\n key: string,\n): { siteId: string; channelId?: string | null | undefined } | null {\n const match = /^site:([0-9a-f-]{36})(?::(.+))?$/iu.exec(key);\n if (!match) return null;\n const channel = match[2];\n return channel === undefined\n ? { siteId: match[1]! }\n : { siteId: match[1]!, channelId: channel === \"default\" ? null : channel };\n}\n\nfunction laterIso(a: string, b: string | undefined): string {\n if (!b) return a;\n return Date.parse(b) > Date.parse(a) ? b : a;\n}\n\n/** Merge per-project server groups into one per Site for rails without projects. */\nfunction siteRowSummaries(\n groups: readonly SiteConversationGroup[],\n byProject: boolean,\n): Map<string, { origin: SessionSiteOrigin; channelId: string | null; summary: SiteRowSummary }> {\n const rows = new Map<\n string,\n { origin: SessionSiteOrigin; channelId: string | null; summary: SiteRowSummary }\n >();\n for (const group of groups) {\n const key = siteRowKey(group.siteId, byProject ? group.channelId : undefined);\n const { siteId, channelId, title, ...summary } = group;\n const current = rows.get(key);\n if (!current) {\n // A Site this viewer cannot read and that kept no label still needs a name.\n const origin = { siteId, title: title.trim() || \"Untitled Site\" };\n rows.set(key, { origin, channelId, summary: { ...summary } });\n continue;\n }\n const merged = current.summary;\n for (const field of [\n \"conversations\",\n \"total\",\n \"attention\",\n \"failed\",\n \"active\",\n \"queued\",\n \"waiting\",\n \"unread\",\n \"activeWork\",\n ] as const)\n merged[field] += summary[field];\n merged.attentionSince = earliestIso(merged.attentionSince, summary.attentionSince);\n // Every project's row of a readable Site has its newest publish; a Site\n // the viewer cannot read keeps its first conversation's start, so a new\n // conversation in another project never lifts it.\n merged.updatedAt = earliestIso(merged.updatedAt, summary.updatedAt) ?? merged.updatedAt;\n merged.createdAt = laterIso(merged.createdAt, summary.createdAt);\n }\n return rows;\n}\n\n/** The presentation-only row a Site's conversations nest under. */\nfunction siteRowSession(\n key: string,\n origin: SessionSiteOrigin,\n channelId: string | null,\n latest: Session | undefined,\n summary: SiteRowSummary | undefined,\n options: { workspaceId?: string | undefined; creator?: Session[\"createdBy\"] | undefined },\n): Session {\n // The server's row time is the Site's newest publish; a loaded conversation's\n // messages never move it. A row the server did not send (past its bound, or\n // an older chat that carries just a Site label) takes its conversation's\n // start, which messages do not change either.\n const updatedAt = summary ? summary.updatedAt : (latest?.createdAt ?? \"\");\n const createdAt = laterIso(summary?.createdAt ?? latest?.createdAt ?? \"\", latest?.createdAt);\n // Only the fields the rail reads for ordering, grouping and links. It is\n // never sent to the server or used for a session action.\n return {\n id: key,\n workspaceId: latest?.workspaceId ?? options.workspaceId ?? \"\",\n accountId: latest?.accountId ?? \"\",\n rootSessionId: key,\n parentSessionId: null,\n channelId,\n status: \"idle\",\n title: origin.title,\n displayTitle: origin.title,\n renameSeed: origin.title,\n titleSource: \"user\",\n createdBy: latest?.createdBy ?? options.creator ?? { kind: \"subject\", subjectId: \"\" },\n effectiveControl: { state: \"active\" },\n inputWait: null,\n // A pinned Site row carries this person's pin, like a pinned session.\n pinned: summary?.pinned === true,\n pinnedAt: summary?.pinned ? (summary.pinnedAt ?? null) : null,\n archived: false,\n archivedAt: null,\n unread: false,\n activelyWorking: false,\n lastSequence: 0,\n treeStats: undefined,\n scheduledTaskId: null,\n siteOrigin: origin,\n metadata: { _opengeniSiteOrigin: origin },\n createdAt,\n updatedAt,\n } as unknown as Session;\n}\n\n/**\n * Fold Site conversations into stable Site rows. `groups` are the complete\n * rows from the server; loaded conversations (an expanded Site, the open\n * session, a legacy labelled chat) join their row, so which session is\n * selected never decides whether a Site or its conversations are listed.\n * Pins have already been split out.\n */\nexport function attachSiteRows(\n roots: SessionTreeNode[],\n options: {\n groups?: readonly SiteConversationGroup[] | undefined;\n /** Rows per project when the rail shows projects. */\n byProject?: boolean | undefined;\n workspaceId?: string | undefined;\n creator?: Session[\"createdBy\"] | undefined;\n } = {},\n): SessionTreeNode[] {\n const byProject = options.byProject ?? false;\n const rows = new Map<\n string,\n {\n origin: SessionSiteOrigin;\n channelId: string | null;\n summary?: SiteRowSummary | undefined;\n members: SessionTreeNode[];\n }\n >();\n for (const [key, row] of siteRowSummaries(options.groups ?? [], byProject))\n rows.set(key, { ...row, members: [] });\n const rest: SessionTreeNode[] = [];\n for (const node of roots) {\n const origin = sessionSiteOrigin(node.session);\n if (!origin || node.session.parentSessionId) {\n rest.push(node);\n continue;\n }\n const channelId = node.session.channelId ?? null;\n const key = siteRowKey(origin.siteId, byProject ? channelId : undefined);\n const row = rows.get(key) ?? { origin, channelId, members: [] };\n row.members.push(node);\n rows.set(key, row);\n }\n const siteRows = [...rows].map(([key, row]): SessionTreeNode => {\n const members = row.members.sort((a, b) => compareSessionActivity(a.session, b.session));\n const summary = row.summary;\n return {\n siteGroup: row.origin,\n ...(summary ? { siteSummary: summary } : {}),\n session: siteRowSession(\n key,\n row.origin,\n row.channelId,\n members[0]?.session,\n summary,\n options,\n ),\n children: members,\n hasActiveDescendant:\n members.some(nodeIsActive) ||\n Boolean(summary && summary.active + summary.queued + summary.attention > 0),\n };\n });\n return [...rest, ...siteRows];\n}\n\n/**\n * How many conversations a Site row stands for, loaded or not. The server\n * counts Site conversations; an older chat that only carries a Site label\n * joins the row when loaded, so the count can grow by those on expansion.\n */\nexport function siteRowConversationCount(node: SessionTreeNode): number {\n return Math.max(node.siteSummary?.conversations ?? 0, node.children.length);\n}\n\nexport function categorizeRailRoots(\n rootNodes: SessionTreeNode[],\n now: Date = new Date(),\n): SessionForest {\n const running = rootNodes\n .filter((node) => nodeIsActive(node))\n .sort((a, b) => compareSessionActivity(a.session, b.session));\n const rest = rootNodes\n .filter((node) => !nodeIsActive(node))\n .sort((a, b) => compareSessionActivity(a.session, b.session));\n\n const buckets = new Map<SessionRecencyGroup, SessionTreeNode[]>();\n for (const node of rest) {\n const group = recencyGroupFor(sessionActivityTime(node.session), now);\n const list = buckets.get(group) ?? [];\n list.push(node);\n buckets.set(group, list);\n }\n const grouped: SessionForest[\"grouped\"] = [];\n for (const group of SESSION_GROUP_ORDER) {\n const list = buckets.get(group);\n if (list && list.length > 0) {\n grouped.push({\n group,\n label: SESSION_GROUP_LABELS(t)[group],\n sessions: list,\n });\n }\n }\n return { running, grouped };\n}\n\n/**\n * Build the rail forest: roots (parentSessionId null, or parent absent from the\n * page) at the top level, spawned children nested beneath their parent, each\n * subtree ordered most-recent-first. Running roots (self or via a live\n * descendant) are pinned above the recency buckets. A `seen` guard makes a\n * pathological parent cycle in the loaded page terminate rather than recurse\n * forever.\n */\nexport function buildRailForest(sessions: Session[], now: Date = new Date()): SessionForest {\n const byId = new Map(sessions.map((session) => [session.id, session]));\n const childrenOf = new Map<string, Session[]>();\n const roots: Session[] = [];\n for (const session of sessions) {\n const parentId = session.parentSessionId;\n if (parentId && parentId !== session.id && byId.has(parentId)) {\n const list = childrenOf.get(parentId) ?? [];\n list.push(session);\n childrenOf.set(parentId, list);\n } else {\n roots.push(session);\n }\n }\n\n const build = (session: Session, seen: Set<string>): SessionTreeNode => {\n const children = seen.has(session.id)\n ? []\n : (childrenOf.get(session.id) ?? [])\n .sort(compareSessionActivity)\n .map((child) => build(child, new Set(seen).add(session.id)));\n const hasActiveDescendant = children.some((child) => nodeIsActive(child));\n return { session, children, hasActiveDescendant };\n };\n\n const rootNodes = roots.map((session) => build(session, new Set()));\n const reachable = new Set<string>();\n const markReachable = (node: SessionTreeNode): void => {\n if (reachable.has(node.session.id)) {\n return;\n }\n reachable.add(node.session.id);\n for (const child of node.children) {\n markReachable(child);\n }\n };\n for (const node of rootNodes) {\n markReachable(node);\n }\n for (const session of sessions) {\n if (!reachable.has(session.id)) {\n rootNodes.push({ session, children: [], hasActiveDescendant: false });\n reachable.add(session.id);\n }\n }\n return categorizeRailRoots(rootNodes, now);\n}\n\ntype RemovedCounts = {\n total: number;\n running: number;\n queued: number;\n waiting: number;\n attention: number;\n paused: number;\n failed: number;\n unreadFailed: number;\n unread: number;\n activeWork: number;\n};\n\nfunction emptyRemovedCounts(): RemovedCounts {\n return {\n total: 0,\n running: 0,\n queued: 0,\n waiting: 0,\n attention: 0,\n paused: 0,\n failed: 0,\n unreadFailed: 0,\n unread: 0,\n activeWork: 0,\n };\n}\n\nfunction addRemovedCounts(target: RemovedCounts, source: RemovedCounts): void {\n target.total += source.total;\n target.running += source.running;\n target.queued += source.queued;\n target.waiting += source.waiting;\n target.attention += source.attention;\n target.paused += source.paused;\n target.failed += source.failed;\n target.unreadFailed += source.unreadFailed;\n target.unread += source.unread;\n target.activeWork += source.activeWork;\n}\n\nfunction subtreeCounts(node: SessionTreeNode): RemovedCounts {\n const status = node.session.status;\n const active = hasActiveEffectiveControl(node.session);\n const counts: RemovedCounts = {\n total: 1,\n running: active && (status === \"running\" || status === \"recovering\") ? 1 : 0,\n queued: active && (status === \"queued\" || status === \"waiting_capacity\") ? 1 : 0,\n waiting: sessionInputWait(node.session) ? 1 : 0,\n attention: awaitsPerson(node.session) ? 1 : 0,\n paused: node.session.effectiveControl?.state === \"paused\" ? 1 : 0,\n failed: status === \"failed\" ? 1 : 0,\n unreadFailed: status === \"failed\" && node.session.unread ? 1 : 0,\n unread: node.session.unread ? 1 : 0,\n activeWork: node.session.activelyWorking ? 1 : 0,\n };\n const stats = node.session.treeStats;\n if (stats) {\n counts.total += stats.totalDescendants;\n counts.running += stats.runningDescendants;\n counts.queued += stats.queuedDescendants;\n counts.waiting += stats.waitingDescendants ?? 0;\n counts.attention += stats.attentionDescendants;\n counts.paused += stats.pausedDescendants;\n counts.failed += stats.failedDescendants;\n counts.unreadFailed += stats.unreadFailedDescendants ?? stats.failedDescendants;\n counts.unread += stats.unreadDescendants ?? 0;\n counts.activeWork += stats.activelyWorkingDescendants ?? 0;\n } else {\n for (const child of node.children) addRemovedCounts(counts, subtreeCounts(child));\n }\n return counts;\n}\n\nfunction prunePinnedSubtreesWithCounts(\n node: SessionTreeNode,\n keepRoot: boolean,\n): { node: SessionTreeNode | null; removed: RemovedCounts } {\n if (node.session.pinned && !keepRoot) {\n return { node: null, removed: subtreeCounts(node) };\n }\n\n const removed = emptyRemovedCounts();\n let removedDirectChildren = 0;\n const children: SessionTreeNode[] = [];\n for (const child of node.children) {\n const result = prunePinnedSubtreesWithCounts(child, false);\n addRemovedCounts(removed, result.removed);\n if (result.node) children.push(result.node);\n else removedDirectChildren += 1;\n }\n\n const stats = node.session.treeStats;\n const session = stats\n ? {\n ...node.session,\n treeStats: {\n directChildren: Math.max(0, stats.directChildren - removedDirectChildren),\n totalDescendants: Math.max(0, stats.totalDescendants - removed.total),\n runningDescendants: Math.max(0, stats.runningDescendants - removed.running),\n queuedDescendants: Math.max(0, stats.queuedDescendants - removed.queued),\n ...(stats.waitingDescendants !== undefined\n ? { waitingDescendants: Math.max(0, stats.waitingDescendants - removed.waiting) }\n : {}),\n attentionDescendants: Math.max(0, stats.attentionDescendants - removed.attention),\n pausedDescendants: Math.max(0, stats.pausedDescendants - removed.paused),\n failedDescendants: Math.max(0, stats.failedDescendants - removed.failed),\n ...(stats.unreadFailedDescendants !== undefined\n ? {\n unreadFailedDescendants: Math.max(\n 0,\n stats.unreadFailedDescendants - removed.unreadFailed,\n ),\n }\n : {}),\n ...(stats.unreadDescendants !== undefined\n ? { unreadDescendants: Math.max(0, stats.unreadDescendants - removed.unread) }\n : {}),\n ...(stats.activelyWorkingDescendants !== undefined\n ? {\n activelyWorkingDescendants: Math.max(\n 0,\n stats.activelyWorkingDescendants - removed.activeWork,\n ),\n }\n : {}),\n // The pruned subtree may have held the oldest waiter; keep the server\n // timestamp only while some counted attention descendant remains.\n ...(stats.attentionSince !== undefined\n ? {\n attentionSince:\n stats.attentionDescendants - removed.attention > 0 ? stats.attentionSince : null,\n }\n : {}),\n truncated: stats.truncated,\n },\n }\n : node.session;\n return {\n node: {\n session,\n children,\n hasActiveDescendant: children.some((child) => nodeIsActive(child)),\n },\n removed,\n };\n}\n\n/**\n * Remove explicit pinned roots below `node`. `keepRoot` is used to build one\n * pin shortcut: that pin stays, but any nested explicit pin is promoted to its\n * own globally ordered shortcut instead of appearing twice.\n */\nexport function prunePinnedSubtrees(\n node: SessionTreeNode,\n keepRoot = false,\n): SessionTreeNode | null {\n return prunePinnedSubtreesWithCounts(node, keepRoot).node;\n}\n\nfunction forestRoots(forest: SessionForest): SessionTreeNode[] {\n return [...forest.running, ...forest.grouped.flatMap((bucket) => bucket.sessions)];\n}\n\n/**\n * Rows as the rail will actually render them.\n *\n * Hierarchy mode nests spawned sessions under their parent, so lineage stays.\n * Search results are deliberately flat because a partial match set is not a\n * tree, so every result there IS top-level and must say so. A row that renders\n * at the top level while still naming an absent parent is the bug this prevents.\n */\nexport function projectRailSessions<T extends Session>(sessions: T[], hierarchyMode: boolean): T[] {\n return hierarchyMode\n ? sessions\n : sessions.map((session) => ({ ...session, parentSessionId: null }));\n}\n\n/** Build the complete, explicit-pin, and ordinary rail projections together. */\nexport function buildPinnedRailSections(\n sessions: Session[],\n now: Date = new Date(),\n options: {\n groupSites?: boolean | undefined;\n /** Complete Site rows from a grouped root page. */\n siteGroups?: readonly SiteConversationGroup[] | undefined;\n /** Split Site rows by project (the rail's project view). */\n siteRowsByProject?: boolean | undefined;\n /** Sites this person just archived from the sidebar: their rows and conversations leave. */\n archivedSiteIds?: ReadonlySet<string> | undefined;\n workspaceId?: string | undefined;\n creator?: Session[\"createdBy\"] | undefined;\n } = {},\n): PinnedRailSections {\n const complete = buildRailForest(sessions, now);\n const roots = forestRoots(complete);\n const nodesById = new Map<string, SessionTreeNode>();\n const visit = (node: SessionTreeNode): void => {\n if (nodesById.has(node.session.id)) return;\n nodesById.set(node.session.id, node);\n for (const child of node.children) visit(child);\n };\n for (const root of roots) visit(root);\n\n const { pinned: pinnedSessions } = partitionPinnedSessions(sessions);\n const pinned = pinnedSessions.flatMap((session) => {\n const completeNode = nodesById.get(session.id) ?? {\n session,\n children: [],\n hasActiveDescendant: false,\n };\n const pruned = prunePinnedSubtrees(completeNode, true);\n return pruned ? [pruned] : [];\n });\n const groupSites = options.groupSites !== false;\n const archivedSiteIds = options.archivedSiteIds ?? new Set<string>();\n const siteGroups = (options.siteGroups ?? []).filter(\n (group) => !archivedSiteIds.has(group.siteId),\n );\n const pinnedSiteIds = new Set(\n siteGroups.filter((group) => group.pinned).map((group) => group.siteId),\n );\n // A Site conversation follows its Site row: into Pinned with a pinned Site,\n // and out of the rail with an archived one.\n const siteMember = (node: SessionTreeNode): string | null =>\n groupSites && !node.session.parentSessionId\n ? (sessionSiteOrigin(node.session)?.siteId ?? null)\n : null;\n const ordinaryRoots: SessionTreeNode[] = [];\n const pinnedSiteMembers: SessionTreeNode[] = [];\n // Archive hides a Site's conversations in every view, flat ones included.\n const archivedSiteMember = (node: SessionTreeNode): boolean => {\n const siteId = node.session.parentSessionId\n ? null\n : (sessionSiteOrigin(node.session)?.siteId ?? null);\n return siteId !== null && archivedSiteIds.has(siteId);\n };\n for (const root of roots) {\n const pruned = prunePinnedSubtrees(root);\n if (!pruned || archivedSiteMember(pruned)) continue;\n const siteId = siteMember(pruned);\n (siteId && pinnedSiteIds.has(siteId) ? pinnedSiteMembers : ordinaryRoots).push(pruned);\n }\n const siteRowOptions = {\n workspaceId: options.workspaceId,\n creator: options.creator,\n };\n // One pinned row per Site, whichever projects its conversations are in.\n const pinnedSites =\n pinnedSiteIds.size > 0\n ? attachSiteRows(pinnedSiteMembers, {\n ...siteRowOptions,\n groups: siteGroups.filter((group) => group.pinned),\n byProject: false,\n })\n : [];\n\n return {\n complete,\n pinned: [...pinnedSites, ...pinned.filter((node) => !archivedSiteMember(node))].sort(\n (left, right) => compareSessionPins(left.session, right.session),\n ),\n ordinary: categorizeRailRoots(\n !groupSites\n ? groupScheduledRuns(ordinaryRoots)\n : attachSiteRows(groupScheduledRuns(ordinaryRoots), {\n ...siteRowOptions,\n groups: siteGroups.filter((group) => !group.pinned),\n byProject: options.siteRowsByProject,\n }),\n now,\n ),\n };\n}\n\n/** The selected descendant under a collapsed node, projected one level deeper. */\nexport function selectedDescendantNode(\n node: SessionTreeNode,\n selectedSessionId: string | null,\n): SessionTreeNode | null {\n if (!selectedSessionId || node.session.id === selectedSessionId) return null;\n for (const child of node.children) {\n if (child.session.id === selectedSessionId) return child;\n const selected = selectedDescendantNode(child, selectedSessionId);\n if (selected) return selected;\n }\n return null;\n}\n\n/** Flatten the forest to the rows currently VISIBLE, given the expanded set —\n * a node, then its children only when the node is expanded (depth-first).\n * A collapsed branch keeps its selected descendant visible as one ordinary\n * child row, matching the rail projection. Keyboard navigation walks this. */\nexport function visibleTreeRows(\n roots: SessionTreeNode[],\n expanded: ReadonlySet<string>,\n selectedSessionId: string | null = null,\n): { node: SessionTreeNode; depth: number }[] {\n const rows: { node: SessionTreeNode; depth: number }[] = [];\n const walk = (node: SessionTreeNode, depth: number): void => {\n if (!node.siteGroup) rows.push({ node, depth });\n if (node.children.length > 0 && expanded.has(node.session.id)) {\n for (const child of node.children) {\n walk(child, depth + 1);\n }\n } else {\n const selected = selectedDescendantNode(node, selectedSessionId);\n if (selected) rows.push({ node: selected, depth: depth + 1 });\n }\n };\n for (const node of roots) walk(node, 0);\n return rows;\n}\n\nexport function visibleForestRows(\n forest: SessionForest,\n expanded: ReadonlySet<string>,\n selectedSessionId: string | null = null,\n): { node: SessionTreeNode; depth: number }[] {\n return visibleTreeRows(forestRoots(forest), expanded, selectedSessionId);\n}\n\n/* --------------------------------------------------------------------------\n Workstream sections. The hierarchy rail groups ordinary roots by their ROOT\n session's channel, with unfiled roots in Recents.\n -------------------------------------------------------------------------- */\n\nexport type ChannelRailSection = {\n /** Stable render key: the channel id, or \"recents\" for unfiled roots. */\n key: string;\n channelId: string | null;\n /** User-facing workstream name. */\n name: string;\n sessions: SessionTreeNode[];\n};\n\n/**\n * Group an ordinary rail forest's roots by channel. Channels render in the\n * given (server-defined) order — pinned projects first, then ordinary ones —\n * including empty ones, so a just-created project is immediately visible.\n * The catch-all \"Default\" section for unfiled roots follows them (only when\n * it has members). Within a section, active roots\n * keep floating above recency-ordered idle ones because the incoming forest\n * is flattened in that order. A root whose channel no longer exists folds\n * into Default rather than disappearing.\n */\nexport function channelRailSections(\n forest: SessionForest,\n channels: readonly { id: string; name: string }[],\n): ChannelRailSection[] {\n const roots = [...forest.running, ...forest.grouped.flatMap((bucket) => bucket.sessions)];\n const byChannel = new Map<string | null, SessionTreeNode[]>();\n for (const node of roots) {\n const channelId = node.session.channelId ?? null;\n const known = channelId !== null && channels.some((channel) => channel.id === channelId);\n const key = known ? channelId : null;\n const list = byChannel.get(key) ?? [];\n list.push(node);\n byChannel.set(key, list);\n }\n for (const list of byChannel.values()) {\n list.sort((left, right) => {\n const leftRank = nodeIsActive(left) ? 0 : left.session.activelyWorking ? 1 : 2;\n const rightRank = nodeIsActive(right) ? 0 : right.session.activelyWorking ? 1 : 2;\n return leftRank - rightRank || compareSessionActivity(left.session, right.session);\n });\n }\n const sections: ChannelRailSection[] = [];\n sections.push(\n ...channels.map((channel) => ({\n key: channel.id,\n channelId: channel.id,\n name: channel.name,\n sessions: byChannel.get(channel.id) ?? [],\n })),\n );\n const defaultSessions = byChannel.get(null) ?? [];\n if (defaultSessions.length > 0) {\n sections.push({ key: \"default\", channelId: null, name: \"Default\", sessions: defaultSessions });\n }\n return sections;\n}\n"],"mappings":"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","names":["counts"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/app/lib/session-pins.tsx"],"sourcesContent":["import type { Session as SessionDetails } from \"../types\";\n// Cross-tab invalidation for personal session pins. Postgres remains truth;\n// this message carries only workspace/session ids and tells sibling tabs to\n// re-read. Cross-device clients reconcile through the normal page refresh/poll.\n\nimport type { RailSession as Session } from \"./session-list-entry\";\n\nconst SESSION_PIN_CHANNEL_PREFIX = \"opengeni.session-pins\";\nconst SESSION_PIN_STORAGE_PREFIX = \"opengeni.session-pins.changed\";\nconst ACCEPTED_SESSION_CHANNEL_READ_SOFT_LIMIT = 512;\nconst outboundChannels = new Map<string, BroadcastChannel>();\n\ntype SessionTreeStats = NonNullable<Session[\"treeStats\"]>;\ntype SessionChannelProjection = Pick<Session, \"id\" | \"workspaceId\" | \"channelId\">;\ntype SessionChannelEvidence = [\n channelId: string | null,\n priority: number,\n readGeneration: number,\n retainsAcceptedRead?: boolean,\n];\ntype SessionChannelRead = [channelId: string | null, present: boolean, readGeneration: number];\ntype SessionChannelCommittedMove = [channelId: string | null, readGeneration: number];\ntype SessionChannelRetainedOwner = [\n channelId: string | null,\n readGeneration: number,\n blockingReads: Set<number>,\n];\ntype SessionChannelAcceptedRead = SessionChannelProjection & {\n readGeneration: number;\n};\nexport type SessionChannelMoveRequest = Readonly<{\n workspaceId: string;\n sessionId: string;\n operation: number;\n readGeneration: number;\n}>;\nexport type SessionChannelMoveResponseDisposition =\n | \"accepted\"\n | \"verification-required\"\n | \"rejected\";\n\nfunction sessionChannelProjectionKey(projection: Pick<Session, \"id\" | \"workspaceId\">): string {\n return `${projection.workspaceId}\\u0000${projection.id}`;\n}\n\n/**\n * Tracks list, exact-read, and settled-move ownership of channel projections\n * without putting browser-only provenance onto the public Session contract.\n */\nexport class SessionChannelProjectionAuthority {\n private readonly owners = new Map<object, Map<string, SessionChannelEvidence>>();\n private readonly reads = new Map<string, SessionChannelRead>();\n private readonly moves = new Map<string, SessionChannelCommittedMove>();\n private readonly retainedOwners = new Map<string, SessionChannelRetainedOwner>();\n private readonly detailReads = new Map<object, Map<number, string>>();\n private readonly listeners = new Set<(accepted?: SessionChannelAcceptedRead) => void>();\n private readonly requests = new Map<string, [owner: object, operation: number]>();\n private readClock = 0;\n private moveClock = 0;\n private revision = 0;\n\n readonly beginRead = (): number => ++this.readClock;\n\n /**\n * Register an exact/detail request whose delayed result can outlive a list\n * owner. One logical consumer keeps only its latest request generation; a\n * successor starts after the prior shared GET settled, so the older result\n * can no longer arrive and no longer blocks owner cleanup.\n */\n beginDetailRead(\n owner: object,\n projection: Pick<SessionChannelProjection, \"id\" | \"workspaceId\">,\n ): number {\n this.finishDetailReads(owner);\n const readGeneration = this.beginRead();\n this.detailReads.set(\n owner,\n new Map([[readGeneration, sessionChannelProjectionKey(projection)]]),\n );\n return readGeneration;\n }\n\n /** Retire every exact/detail request owned by one route or point probe. */\n finishDetailReads(owner: object): void {\n const reads = this.detailReads.get(owner);\n if (!reads) return;\n this.detailReads.delete(owner);\n const finished = new Set(reads.keys());\n for (const [key, retained] of this.retainedOwners) {\n for (const readGeneration of finished) retained[2].delete(readGeneration);\n if (retained[2].size === 0) this.retainedOwners.delete(key);\n }\n }\n\n /** React to persistent accepted server/write authority advancing. */\n readonly subscribe = (\n listener: (accepted?: SessionChannelAcceptedRead) => void,\n ): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n /** Reactive snapshot for consumers whose projected rows depend on persistent authority. */\n readonly getRevision = (): number => this.revision;\n\n /**\n * Persist one pending move across rail lifetimes. The same mounted owner\n * cannot duplicate its request; a new mount may supersede it with a new\n * explicit user intent, after which the older response loses authority.\n */\n beginMove(\n owner: object,\n projection: Pick<SessionChannelProjection, \"id\" | \"workspaceId\">,\n ): SessionChannelMoveRequest | null {\n const key = sessionChannelProjectionKey(projection);\n if (this.requests.get(key)?.[0] === owner) return null;\n const request = {\n workspaceId: projection.workspaceId,\n sessionId: projection.id,\n operation: ++this.moveClock,\n // A mutation response is evidence from the request start, not from the\n // later time at which its promise happens to settle.\n readGeneration: this.beginRead(),\n };\n this.requests.set(key, [owner, request.operation]);\n return request;\n }\n\n ownsMove(owner: object, request: SessionChannelMoveRequest): boolean {\n const current = this.requests.get(\n sessionChannelProjectionKey({ id: request.sessionId, workspaceId: request.workspaceId }),\n );\n return current?.[0] === owner && current[1] === request.operation;\n }\n\n recordMove(\n owner: object,\n request: SessionChannelMoveRequest,\n projection: SessionChannelProjection,\n ): SessionChannelMoveResponseDisposition {\n if (\n projection.id !== request.sessionId ||\n projection.workspaceId !== request.workspaceId ||\n !this.ownsMove(owner, request)\n ) {\n return \"rejected\";\n }\n const key = sessionChannelProjectionKey(projection);\n // Completed evidence newer than the mutation start may already be a\n // post-commit value, so only a fresh point read can choose between it and\n // this response. In either case retain exact B at a new settlement\n // generation: every overlapping read already has an older generation even\n // if it has not completed, and a rail unmount cannot discard this fence.\n const verificationRequired = this.highestGeneration(key) > request.readGeneration;\n const readGeneration = this.beginRead();\n this.moves.set(key, [projection.channelId ?? null, readGeneration]);\n this.publish({ ...projection, readGeneration });\n return verificationRequired ? \"verification-required\" : \"accepted\";\n }\n\n finishMove(owner: object, request: SessionChannelMoveRequest): void {\n if (!this.ownsMove(owner, request)) return;\n this.requests.delete(\n sessionChannelProjectionKey({ id: request.sessionId, workspaceId: request.workspaceId }),\n );\n }\n\n replace(\n owner: object,\n projections: readonly SessionChannelProjection[],\n priority = 0,\n readGeneration = 0,\n ): void {\n this.replaceOwner(\n owner,\n projections.map((projection) => [projection, readGeneration] as const),\n priority,\n );\n }\n\n replaceOwner(\n owner: object,\n evidence: readonly (readonly [projection: SessionChannelProjection, readGeneration: number])[],\n priority = 0,\n ): void {\n if (evidence.length === 0) {\n this.clear(owner);\n return;\n }\n const next = new Map<string, SessionChannelEvidence>();\n for (const [projection, readGeneration] of evidence) {\n const key = sessionChannelProjectionKey(projection);\n next.set(key, [projection.channelId ?? null, priority, readGeneration]);\n }\n const previous = this.owners.get(owner);\n if (previous) this.retainOwner(previous, next);\n this.owners.set(owner, next);\n if (priority === 0) {\n for (const [projection] of evidence) {\n const key = sessionChannelProjectionKey(projection);\n const candidate = next.get(key);\n const committedMove = this.moves.get(key);\n // Current server-owned page/lineage evidence is as authoritative as an\n // exact read for channel filing when its request actually started after\n // the successful move settled. Promote it persistently before retiring\n // B so owner cleanup/remount cannot revive either B or a pre-move A.\n if (candidate && committedMove && candidate[2] > committedMove[1]) {\n this.recordObservation(projection, candidate[2], true);\n }\n }\n }\n this.compact();\n }\n\n clear(owner: object): void {\n const previous = this.owners.get(owner);\n if (previous) this.retainOwner(previous);\n this.owners.delete(owner);\n }\n\n /** Drop browser-only evidence when its workspace principal/route fence is retired. */\n clearWorkspace(workspaceId: string): void {\n const prefix = `${workspaceId}\\u0000`;\n for (const key of this.reads.keys()) {\n if (!key.startsWith(prefix)) continue;\n this.reads.delete(key);\n }\n for (const [owner, projections] of this.owners) {\n for (const key of projections.keys()) {\n if (key.startsWith(prefix)) projections.delete(key);\n }\n if (projections.size === 0) this.owners.delete(owner);\n }\n for (const key of this.requests.keys()) {\n if (key.startsWith(prefix)) this.requests.delete(key);\n }\n for (const key of this.moves.keys()) {\n if (key.startsWith(prefix)) this.moves.delete(key);\n }\n for (const key of this.retainedOwners.keys()) {\n if (key.startsWith(prefix)) this.retainedOwners.delete(key);\n }\n for (const [owner, reads] of this.detailReads) {\n for (const [readGeneration, key] of reads) {\n if (key.startsWith(prefix)) reads.delete(readGeneration);\n }\n if (reads.size === 0) this.detailReads.delete(owner);\n }\n }\n\n /** Retain an accepted exact/detail read so older list requests cannot revive stale filing. */\n recordRead(projection: SessionChannelProjection, readGeneration: number): boolean {\n return this.recordObservation(projection, readGeneration, true);\n }\n\n /** Fence a not-found point read without treating absence as a channel projection. */\n recordMissing(\n projection: Pick<SessionChannelProjection, \"id\" | \"workspaceId\">,\n readGeneration: number,\n ): boolean {\n return this.recordObservation(projection, readGeneration, false);\n }\n\n private recordObservation(\n projection: Pick<SessionChannelProjection, \"id\" | \"workspaceId\"> &\n Partial<Pick<SessionChannelProjection, \"channelId\">>,\n readGeneration: number,\n present: boolean,\n ): boolean {\n if (readGeneration <= 0) return false;\n const key = sessionChannelProjectionKey(projection);\n if (this.highestGeneration(key) > readGeneration) return false;\n const retainedOwner = this.retainedOwners.get(key);\n if (retainedOwner && retainedOwner[1] <= readGeneration) {\n this.retainedOwners.delete(key);\n }\n const committedMove = this.moves.get(key);\n // Only accepted server evidence that started after settlement can choose\n // B, a genuinely newer C, or deletion and retire the persistent move\n // fence. Point/detail reads arrive here directly; current priority-0 list\n // owners are promoted by replaceOwner after the same causal check.\n if (committedMove && readGeneration > committedMove[1]) {\n this.moves.delete(key);\n }\n // Refresh iteration order when exact evidence for one session advances so\n // compaction considers genuinely older observations first.\n for (const projections of this.owners.values()) {\n const candidate = projections.get(key);\n if (candidate) candidate[3] = false;\n }\n this.reads.delete(key);\n this.reads.set(key, [projection.channelId ?? null, present, readGeneration]);\n this.compact();\n const accepted = present\n ? {\n id: projection.id,\n workspaceId: projection.workspaceId,\n channelId: projection.channelId ?? null,\n readGeneration,\n }\n : undefined;\n this.publish(accepted);\n return true;\n }\n\n private publish(accepted?: SessionChannelAcceptedRead): void {\n this.revision += 1;\n for (const listener of this.listeners) listener(accepted);\n }\n\n /**\n * Transfer a priority-0 owner's newest value before cleanup when compaction\n * already delegated an accepted fence or an older exact request for the same\n * session can still arrive. Request-causal transfers are released with their\n * blocker; optimistic priority owners are never promoted.\n */\n private retainOwner(\n previous: ReadonlyMap<string, SessionChannelEvidence>,\n replacement: ReadonlyMap<string, SessionChannelEvidence> = new Map(),\n ): void {\n for (const [key, candidate] of previous) {\n const retainsAcceptedRead = candidate[3] === true;\n candidate[3] = false;\n const next = replacement.get(key);\n if (retainsAcceptedRead && next && next[1] === 0 && next[2] >= candidate[2]) {\n next[3] = true;\n continue;\n }\n if (candidate[1] !== 0) continue;\n const newerOwner = this.highestOwnerEvidence(key, previous, replacement);\n if (newerOwner && newerOwner[2] >= candidate[2]) continue;\n if (this.highestPersistentGeneration(key) >= candidate[2]) continue;\n if (retainsAcceptedRead) {\n this.retainedOwners.delete(key);\n this.reads.set(key, [candidate[0], true, candidate[2]]);\n continue;\n }\n const blockingReads = this.blockingDetailReads(key, candidate[2]);\n if (blockingReads.size === 0) continue;\n this.retainedOwners.set(key, [candidate[0], candidate[2], blockingReads]);\n }\n }\n\n private highestOwnerEvidence(\n key: string,\n previous: ReadonlyMap<string, SessionChannelEvidence>,\n replacement: ReadonlyMap<string, SessionChannelEvidence>,\n ): SessionChannelEvidence | undefined {\n let highest = replacement.get(key);\n if (highest?.[1] !== 0) highest = undefined;\n for (const projections of this.owners.values()) {\n if (projections === previous) continue;\n const candidate = projections.get(key);\n if (candidate?.[1] !== 0) continue;\n if (!highest || candidate[2] > highest[2]) highest = candidate;\n }\n return highest;\n }\n\n private blockingDetailReads(key: string, readGeneration: number): Set<number> {\n const blocking = new Set<number>();\n for (const reads of this.detailReads.values()) {\n for (const [candidateGeneration, candidateKey] of reads) {\n if (candidateKey === key && candidateGeneration < readGeneration) {\n blocking.add(candidateGeneration);\n }\n }\n }\n return blocking;\n }\n\n private highestPersistentGeneration(key: string): number {\n return Math.max(\n this.reads.get(key)?.[2] ?? Number.NEGATIVE_INFINITY,\n this.moves.get(key)?.[1] ?? Number.NEGATIVE_INFINITY,\n this.retainedOwners.get(key)?.[1] ?? Number.NEGATIVE_INFINITY,\n );\n }\n\n /**\n * The limit is deliberately soft: an accepted read is the only fence that\n * can stop an older retained branch/page owner from reviving stale filing.\n * Compact only after every current owner for that session is at least as\n * new; otherwise retaining the winner is required for correctness. Workspace\n * transitions provide the hard lifecycle bound for unresolved evidence.\n */\n private compact(): void {\n if (this.reads.size <= ACCEPTED_SESSION_CHANNEL_READ_SOFT_LIMIT) return;\n for (const [key, accepted] of this.reads) {\n const ownerEvidence = [...this.owners.values()]\n .map((projections) => projections.get(key))\n .filter((candidate): candidate is SessionChannelEvidence => candidate?.[1] === 0);\n if (\n ownerEvidence.length === 0 ||\n ownerEvidence.some((candidate) => candidate[2] < accepted[2])\n ) {\n continue;\n }\n for (const candidate of ownerEvidence) candidate[3] = true;\n this.reads.delete(key);\n if (this.reads.size <= ACCEPTED_SESSION_CHANNEL_READ_SOFT_LIMIT) return;\n }\n }\n\n private highestGeneration(key: string): number {\n let generation = this.highestPersistentGeneration(key);\n for (const projections of this.owners.values()) {\n const candidate = projections.get(key);\n if (candidate) generation = Math.max(generation, candidate[2]);\n }\n return generation;\n }\n\n project<T extends SessionChannelProjection>(projection: T, readGeneration: number): T {\n const key = sessionChannelProjectionKey(projection);\n const committedMove = this.moves.get(key);\n if (committedMove && committedMove[0] !== (projection.channelId ?? null)) {\n return { ...projection, channelId: committedMove[0] };\n }\n const read = this.reads.get(key);\n const retainedOwner = this.retainedOwners.get(key);\n const accepted =\n retainedOwner && (!read || retainedOwner[1] > read[2])\n ? ([retainedOwner[0], true, retainedOwner[1]] as SessionChannelRead)\n : read;\n if (\n !accepted ||\n !accepted[1] ||\n accepted[2] <= readGeneration ||\n accepted[0] === (projection.channelId ?? null)\n ) {\n return projection;\n }\n return { ...projection, channelId: accepted[0] };\n }\n\n owns(projection: SessionChannelProjection | null): boolean {\n if (!projection) return false;\n const key = sessionChannelProjectionKey(projection);\n const channelId = projection.channelId ?? null;\n const committedMove = this.moves.get(key);\n if (committedMove) return committedMove[0] === channelId;\n const read = this.reads.get(key);\n const retainedOwner = this.retainedOwners.get(key);\n const accepted =\n retainedOwner && (!read || retainedOwner[1] > read[2])\n ? ([retainedOwner[0], true, retainedOwner[1]] as SessionChannelRead)\n : read;\n let highestPriority = accepted ? 0 : Number.NEGATIVE_INFINITY;\n let highestGeneration = accepted?.[2] ?? Number.NEGATIVE_INFINITY;\n let owned = accepted?.[1] === true && accepted[0] === channelId;\n for (const projections of this.owners.values()) {\n const candidate = projections.get(key);\n if (!candidate || candidate[1] < highestPriority) continue;\n if (candidate[1] > highestPriority || candidate[2] > highestGeneration) {\n highestPriority = candidate[1];\n highestGeneration = candidate[2];\n owned = candidate[0] === channelId;\n } else if (candidate[2] === highestGeneration && candidate[0] === channelId) {\n owned = true;\n }\n }\n return owned;\n }\n}\n\ntype SessionPinChangeMessage = {\n type: \"session-pin.changed\";\n sessionId: string;\n messageId: string;\n};\n\nfunction channelName(workspaceId: string): string {\n return `${SESSION_PIN_CHANNEL_PREFIX}:${workspaceId}`;\n}\n\nfunction storageKey(workspaceId: string): string {\n return `${SESSION_PIN_STORAGE_PREFIX}:${workspaceId}`;\n}\n\nfunction newMessageId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;\n}\n\nfunction sessionPinChangeMessage(value: unknown): SessionPinChangeMessage | null {\n const message = value as Partial<SessionPinChangeMessage> | null;\n return message?.type === \"session-pin.changed\" &&\n typeof message.sessionId === \"string\" &&\n message.sessionId.length > 0 &&\n typeof message.messageId === \"string\" &&\n message.messageId.length > 0\n ? (message as SessionPinChangeMessage)\n : null;\n}\n\nfunction sameTreeStats(a: SessionTreeStats | undefined, b: SessionTreeStats | undefined): boolean {\n if (a === b) {\n return true;\n }\n if (!a || !b) {\n return false;\n }\n return (\n a.directChildren === b.directChildren &&\n a.totalDescendants === b.totalDescendants &&\n a.runningDescendants === b.runningDescendants &&\n a.queuedDescendants === b.queuedDescendants &&\n a.attentionDescendants === b.attentionDescendants &&\n a.pausedDescendants === b.pausedDescendants &&\n a.failedDescendants === b.failedDescendants &&\n (a.unreadFailedDescendants ?? a.failedDescendants) ===\n (b.unreadFailedDescendants ?? b.failedDescendants) &&\n (a.unreadDescendants ?? 0) === (b.unreadDescendants ?? 0) &&\n (a.activelyWorkingDescendants ?? 0) === (b.activelyWorkingDescendants ?? 0) &&\n (a.attentionSince ?? null) === (b.attentionSince ?? null) &&\n a.truncated === b.truncated\n );\n}\n\n/**\n * Merge a fresh hierarchy summary without letting an older personal failure\n * projection resurrect attention the viewer already consumed locally.\n *\n * `failedDescendants` is durable lifecycle history, while\n * `unreadFailedDescendants` is viewer-specific. When the lifecycle count is\n * unchanged but an incoming page reports more unread failures, the excess may\n * be a list read that started before the local acknowledgement committed. Keep\n * the acknowledged failure count, and remove only that stale failure delta\n * from the broader unread count so genuinely new unrelated unread work still\n * surfaces.\n */\nfunction mergeTreeStats(\n current: SessionTreeStats | undefined,\n projected: SessionTreeStats | undefined,\n): SessionTreeStats | undefined {\n if (!projected || !current) return projected ?? current;\n\n const currentUnreadFailed = current.unreadFailedDescendants ?? current.failedDescendants;\n const projectedUnreadFailed = projected.unreadFailedDescendants ?? projected.failedDescendants;\n if (\n current.failedDescendants !== projected.failedDescendants ||\n currentUnreadFailed >= projectedUnreadFailed\n ) {\n return projected;\n }\n\n const staleFailureDelta = projectedUnreadFailed - currentUnreadFailed;\n return {\n ...projected,\n unreadFailedDescendants: currentUnreadFailed,\n unreadDescendants: Math.max(\n current.unreadDescendants ?? 0,\n (projected.unreadDescendants ?? 0) - staleFailureDelta,\n ),\n };\n}\n\n/**\n * Merge only personal pin fields from a list/page projection into the open\n * route projection. Lifecycle and event-driven session fields remain owned by\n * the route/SSE reducer and cannot be regressed by a slower list poll.\n */\nexport function applySessionPinProjection<T extends Session>(\n current: T | null,\n projected: Pick<Session, \"id\" | \"workspaceId\" | \"pinned\" | \"pinnedAt\" | \"pinVersion\">,\n): T | null {\n if (!current || current.id !== projected.id || current.workspaceId !== projected.workspaceId) {\n return current;\n }\n const pinned = Boolean(projected.pinned);\n const pinnedAt = projected.pinnedAt ?? null;\n const pinVersion = projected.pinVersion ?? 0;\n // A page poll, mutation response, or legacy-replica response can finish\n // after a newer optimistic/authoritative projection is already visible.\n // Pin revisions are monotonic, so never let that older response undo the\n // newer header/list state. Equal revisions remain authoritative: they let a\n // server response replace the local optimistic timestamp for that revision.\n if (pinVersion < (current.pinVersion ?? 0)) {\n return current;\n }\n if (\n Boolean(current.pinned) === pinned &&\n (current.pinnedAt ?? null) === pinnedAt &&\n (current.pinVersion ?? 0) === pinVersion\n ) {\n return current;\n }\n return { ...current, pinned, pinnedAt, pinVersion };\n}\n\n/** Merge the list-owned project filing without replacing route/SSE content. */\nexport function applySessionChannelProjection<T extends Session>(\n current: T | null,\n projected: Pick<Session, \"id\" | \"workspaceId\" | \"channelId\">,\n): T | null {\n if (!current || current.id !== projected.id || current.workspaceId !== projected.workspaceId) {\n return current;\n }\n const channelId = projected.channelId ?? null;\n return (current.channelId ?? null) === channelId ? current : { ...current, channelId };\n}\n\n/**\n * Merge a detail/SSE projection into the root context without allowing a\n * slower detail read to erase newer list-owned pin or project projections.\n * Detail remains authoritative for route-owned fields; the current context\n * contributes personal pin fields and the project filing.\n */\nexport function mergeSessionContextProjection(\n current: SessionDetails | null,\n projected: SessionDetails | null,\n channelAuthority: SessionChannelProjectionAuthority,\n source: \"detail\" | \"live\",\n): SessionDetails | null {\n if (!projected) {\n return null;\n }\n const pinned = applySessionPinProjection(projected, current ?? projected) ?? projected;\n return source === \"live\" || channelAuthority.owns(current)\n ? (applySessionChannelProjection(pinned, current ?? projected) ?? pinned)\n : pinned;\n}\n\n/**\n * Merge a completed detail request only through the channel evidence that won\n * its request generation. A rejected late detail may still contribute its\n * route-owned fields when persistent authority can project the newer channel;\n * without such a winner it cannot seed stale route context after the rail (and\n * its transient owner evidence) has unmounted.\n */\nexport function mergeSessionDetailReadProjection(\n current: SessionDetails | null,\n projected: SessionDetails,\n channelAuthority: SessionChannelProjectionAuthority,\n readGeneration: number,\n accepted: boolean,\n): SessionDetails | null {\n const authoritative = accepted ? projected : channelAuthority.project(projected, readGeneration);\n if (!accepted && authoritative === projected && !channelAuthority.owns(projected)) {\n return current;\n }\n return mergeSessionContextProjection(current, authoritative, channelAuthority, \"detail\");\n}\n\n/**\n * Merge list-owned personal pin and hierarchy fields into route-owned session\n * content. A route/SSE object must never overwrite a newer cross-device unpin,\n * while a list poll must never regress lifecycle state or message content.\n * Activity ordering belongs to the list too: borrowing the selected route's\n * timestamp would move that row on selection and move it back on deselection.\n * List refreshes advance recency consistently for selected and unselected rows.\n * Creation ordering also keeps the list's exact SQL timestamp; route/lineage\n * Date hydration can discard the microseconds that distinguish adjacent rows.\n * When both agree the session needs a person and the list row is at least as\n * fresh as the detail, the list's `requiresActionSince` fills in for a detail\n * read, which never carries it, so selecting a row does not erase how long it\n * has been waiting.\n */\nexport function applySessionRailProjection<T extends Session>(\n current: T,\n projected: Session,\n options: { channelOwned?: boolean | undefined } = {},\n): T {\n const timed =\n current.updatedAt === projected.updatedAt && current.createdAt === projected.createdAt\n ? current\n : { ...current, updatedAt: projected.updatedAt, createdAt: projected.createdAt };\n const activity =\n timed.requiresActionSince == null &&\n projected.requiresActionSince != null &&\n timed.status === \"requires_action\" &&\n projected.status === \"requires_action\" &&\n // A list row older than the detail may describe an earlier request.\n projected.lastSequence >= timed.lastSequence\n ? { ...timed, requiresActionSince: projected.requiresActionSince }\n : timed;\n const pinned = applySessionPinProjection(activity, projected) ?? activity;\n const merged =\n options.channelOwned === false\n ? pinned\n : (applySessionChannelProjection(pinned, projected) ?? pinned);\n if (sameTreeStats(merged.treeStats, projected.treeStats)) {\n return merged;\n }\n const treeStats = mergeTreeStats(merged.treeStats, projected.treeStats);\n return treeStats ? { ...merged, treeStats } : merged;\n}\n\n/**\n * Reconcile the point read performed after a failed pin request.\n *\n * An optimistic first pin projects version 1 before the server responds. If the\n * request fails before commit, the authoritative point read correctly returns\n * the absent relation at version 0. The normal monotonic merge must reject an\n * arbitrary lower revision, but doing so here would leave the exact optimistic\n * projection stuck forever. Allow the lower authoritative revision only while\n * the current state is still byte-for-byte the projection installed by this\n * operation. Any intervening poll, mutation, or device response wins instead.\n */\nexport function reconcileFailedSessionPin(\n current: SessionDetails | null,\n optimistic: Pick<Session, \"id\" | \"workspaceId\" | \"pinned\" | \"pinnedAt\" | \"pinVersion\"> | null,\n authoritative: Pick<Session, \"id\" | \"workspaceId\" | \"pinned\" | \"pinnedAt\" | \"pinVersion\">,\n): SessionDetails | null;\nexport function reconcileFailedSessionPin(\n current: Session | null,\n optimistic: Pick<Session, \"id\" | \"workspaceId\" | \"pinned\" | \"pinnedAt\" | \"pinVersion\"> | null,\n authoritative: Pick<Session, \"id\" | \"workspaceId\" | \"pinned\" | \"pinnedAt\" | \"pinVersion\">,\n): Session | null;\nexport function reconcileFailedSessionPin<T extends Session>(\n current: T | null,\n optimistic: Pick<Session, \"id\" | \"workspaceId\" | \"pinned\" | \"pinnedAt\" | \"pinVersion\"> | null,\n authoritative: Pick<Session, \"id\" | \"workspaceId\" | \"pinned\" | \"pinnedAt\" | \"pinVersion\">,\n): T | null {\n if (\n !current ||\n !optimistic ||\n current.id !== optimistic.id ||\n current.workspaceId !== optimistic.workspaceId ||\n authoritative.id !== optimistic.id ||\n authoritative.workspaceId !== optimistic.workspaceId\n ) {\n return applySessionPinProjection(current, authoritative);\n }\n const stillExactOptimistic =\n Boolean(current.pinned) === Boolean(optimistic.pinned) &&\n (current.pinnedAt ?? null) === (optimistic.pinnedAt ?? null) &&\n (current.pinVersion ?? 0) === (optimistic.pinVersion ?? 0);\n if (!stillExactOptimistic) {\n return applySessionPinProjection(current, authoritative);\n }\n const authoritativePinned = Boolean(authoritative.pinned);\n const authoritativePinnedAt = authoritative.pinnedAt ?? null;\n const authoritativeVersion = authoritative.pinVersion ?? 0;\n if (\n Boolean(current.pinned) === authoritativePinned &&\n (current.pinnedAt ?? null) === authoritativePinnedAt &&\n (current.pinVersion ?? 0) === authoritativeVersion\n ) {\n return current;\n }\n return {\n ...current,\n pinned: authoritativePinned,\n pinnedAt: authoritativePinnedAt,\n pinVersion: authoritativeVersion,\n };\n}\n\nexport function notifySessionPinChanged(workspaceId: string, sessionId: string): void {\n const message: SessionPinChangeMessage = {\n type: \"session-pin.changed\",\n sessionId,\n messageId: newMessageId(),\n };\n if (typeof BroadcastChannel !== \"undefined\") {\n const name = channelName(workspaceId);\n try {\n let channel = outboundChannels.get(name);\n if (!channel) {\n // Closing immediately after postMessage is observably lossy in real\n // browsers. Keep one document-scoped outbound channel alive instead.\n channel = new BroadcastChannel(name);\n outboundChannels.set(name, channel);\n }\n channel.postMessage(message);\n } catch {\n // localStorage below remains the cross-document fallback.\n }\n }\n\n if (typeof window === \"undefined\") return;\n const key = storageKey(workspaceId);\n const serialized = JSON.stringify(message);\n try {\n window.localStorage.setItem(key, serialized);\n // Removing synchronously can race delivery in sibling tabs. Leave the\n // unique payload long enough to emit a storage event, then remove only the\n // value written by this notification.\n window.setTimeout(() => {\n try {\n if (window.localStorage.getItem(key) === serialized) {\n window.localStorage.removeItem(key);\n }\n } catch {\n // Storage may become unavailable after the page was backgrounded.\n }\n }, 1_000);\n } catch {\n // Private browsing and embedded contexts may deny localStorage entirely.\n }\n}\n\nexport function subscribeToSessionPinChanges(\n workspaceId: string,\n onChange: (sessionId: string) => void,\n): () => void {\n // BroadcastChannel and storage events can arrive in either order, and two\n // rapid mutations can interleave those transports. Remember a small bounded\n // window rather than only the immediately previous id so A, B, A still\n // invalidates exactly once per mutation without growing for the tab's life.\n const seenMessageIds = new Set<string>();\n const receive = (value: unknown): void => {\n const message = sessionPinChangeMessage(value);\n if (!message || seenMessageIds.has(message.messageId)) return;\n seenMessageIds.add(message.messageId);\n if (seenMessageIds.size > 64) {\n const oldest = seenMessageIds.values().next().value;\n if (oldest !== undefined) seenMessageIds.delete(oldest);\n }\n onChange(message.sessionId);\n };\n\n let channel: BroadcastChannel | null = null;\n if (typeof BroadcastChannel !== \"undefined\") {\n try {\n channel = new BroadcastChannel(channelName(workspaceId));\n channel.addEventListener(\"message\", (event: MessageEvent<unknown>) => receive(event.data));\n } catch {\n channel = null;\n }\n }\n\n const key = storageKey(workspaceId);\n const onStorage = (event: StorageEvent): void => {\n if (event.key !== key || !event.newValue) return;\n try {\n receive(JSON.parse(event.newValue));\n } catch {\n // Ignore malformed or unrelated storage payloads.\n }\n };\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"storage\", onStorage);\n }\n\n return () => {\n channel?.close();\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"storage\", onStorage);\n }\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/timeline/question-nav-model.ts","../src/timeline/focus-sequence.ts","../src/timeline/work-presentation.ts","../src/timeline/notice-presentation.ts"],"sourcesContent":["/**\n * \"Back to your message\": which prompt the reader is reading the answer to, and\n * whether that prompt has scrolled out of view. Renderer-neutral geometry so\n * the web timeline (DOM rects) and native timelines (layout offsets) agree.\n */\n\n/** How far above the viewport a prompt must be before the pill appears. */\nexport const QUESTION_NAV_HIDDEN_PX = 24;\n/** Breathing room above the question when the reader jumps back to it. */\nexport const QUESTION_NAV_MARGIN_PX = 12;\n\nexport type QuestionNavPrompt = { key: string; top: number; bottom: number };\n\n/**\n * The last prompt before the reading position (the viewport's middle) owns the\n * response in view; it is a target only once it has scrolled fully above the\n * viewport. Prompts are in document order; coordinates share one axis.\n */\nexport function questionNavTarget(\n prompts: readonly QuestionNavPrompt[],\n view: { top: number; height: number },\n): string | null {\n const middle = view.top + view.height / 2;\n const prompt = [...prompts].reverse().find((candidate) => candidate.top <= middle);\n if (!prompt) return null;\n if (prompt.top >= view.top - QUESTION_NAV_HIDDEN_PX || prompt.bottom > view.top) return null;\n return prompt.key;\n}\n","import type { TimelineGroup, TimelineItem } from \"./types\";\n\n/*\n * Landing on a moment in a session: an inbox item or a phone notification\n * points at the durable event that raised it, and the timeline opens on the\n * row that holds that moment. Events that render no row of their own (an\n * agent's notification, a goal change) land on the nearest row before them.\n */\n\nfunction itemSequences(item: TimelineItem): number[] {\n const sources =\n item.sourceEvents ??\n (\"annotationSource\" in item && item.annotationSource ? [item.annotationSource] : []);\n return sources.map((source) => source.sequence);\n}\n\n/** Every durable event sequence a group renders, nested work included. */\nexport function timelineGroupSequences(group: TimelineGroup): number[] {\n if (group.kind === \"item\") return itemSequences(group.item);\n if (group.kind === \"turn\") return group.groups.flatMap(timelineGroupSequences);\n return [\n ...group.items.flatMap((item) => itemSequences(item)),\n ...(group.work?.details.flatMap(timelineGroupSequences) ?? []),\n ];\n}\n\n/**\n * The index of the group to land on for `sequence`: the group that holds it,\n * else the last group that starts before it. -1 when every loaded group is\n * later (the moment is in older history) or nothing is loaded.\n */\nexport function timelineGroupIndexAtSequence(\n groups: readonly TimelineGroup[],\n sequence: number,\n): number {\n let landing = -1;\n for (let index = 0; index < groups.length; index += 1) {\n const sequences = timelineGroupSequences(groups[index]!);\n if (sequences.length === 0) continue;\n if (sequences.includes(sequence)) return index;\n if (Math.min(...sequences) <= sequence) landing = index;\n }\n return landing;\n}\n","// Pure presentation decisions for a timeline turn's work, shared by the web and native\n// timelines. Every function here is extracted verbatim from the web MessageTimeline so both\n// renderers decide identically what a turn shows (preparing, working, waiting, worked).\nimport { timelineGroupContainsPresentedImage } from \"./presented-image\";\nimport type { TurnSummaryStatus } from \"./turn-summary-model\";\nimport type { ActivityItem, TimelineGroup, TimelineItem } from \"./types\";\nimport { type OpenGeniText } from \"../messages/runtime\";\n\nexport type ActivityGroup = Extract<TimelineGroup, { kind: \"activity\" }>;\nexport type TurnGroup = Extract<TimelineGroup, { kind: \"turn\" }>;\n\n/** Once useful output exists, startup decoration must not compete with it. */\nexport function timelineTurnsWithOutput(items: readonly TimelineItem[]): Set<string> {\n return new Set(\n items.flatMap((item) =>\n \"turnId\" in item &&\n item.turnId &&\n (item.kind === \"tool-call\" ||\n ((item.kind === \"agent-message\" || item.kind === \"reasoning\") && item.text.trim()))\n ? [item.turnId]\n : [],\n ),\n );\n}\n\nexport function durationBetween(startedAt: string, endedAt: string): number | undefined {\n const started = Date.parse(startedAt);\n const ended = Date.parse(endedAt);\n if (!Number.isFinite(started) || !Number.isFinite(ended) || ended < started) {\n return undefined;\n }\n return ended - started;\n}\n\n/**\n * Compaction landmarks among a fold's groups (secondary summary facet). The\n * one-time rebuild for a new model has its own note and is not counted.\n */\nexport function compactedLandmarkCount(groups: readonly TimelineGroup[]): number {\n return groups.filter(\n (group) =>\n group.kind === \"item\" &&\n group.item.kind === \"context-compaction\" &&\n group.item.phase === \"compacted\" &&\n group.item.implementation !== \"portable_model_switch\",\n ).length;\n}\n\nexport function clusterIsSettled(group: ActivityGroup): boolean {\n return group.items.every((item) => {\n if (item.kind === \"reasoning\" || item.kind === \"agent-message\") {\n return !item.streaming;\n }\n // Memory writes and fleet observations are discrete, already-settled events.\n if (item.kind === \"memory\" || item.kind === \"fleet-decision\") {\n return true;\n }\n return item.status !== \"running\";\n });\n}\n\nexport function flattenActivityItems(groups: readonly TimelineGroup[]): ActivityItem[] {\n const items: ActivityItem[] = [];\n for (const group of groups) {\n if (group.kind === \"activity\") {\n items.push(...flattenActivityItems(group.work?.details ?? []), ...group.items);\n } else if (group.kind === \"turn\") {\n items.push(...flattenActivityItems(group.groups));\n }\n }\n return items;\n}\n\nexport type ReadableWorkOptions = {\n /** Host shows startup phases as ordinary details (web: startup-details context). */\n startupDetails: boolean;\n /** Startup chrome was dismissed by the reader. */\n startupDismissed: boolean;\n};\n\n/**\n * A readable turn whose only work so far is environment preparation renders as one quiet\n * preparation surface instead of a \"Working\" fold.\n */\nexport function isPreparingWork(group: ActivityGroup, options: ReadableWorkOptions): boolean {\n if (!group.work) return false;\n // Steps not loaded yet are work the reader can open, not preparation.\n if (group.work.steps && group.work.steps.state !== \"complete\") return false;\n const phases = group.items.filter((item) => item.kind === \"startup-phase\");\n return (\n !options.startupDetails &&\n !options.startupDismissed &&\n !group.work.endedAt &&\n !group.work.waiting &&\n phases.length > 0 &&\n group.items.every(\n (item) => item.kind === \"startup-phase\" || (item.kind === \"reasoning\" && !item.text.trim()),\n ) &&\n !phases.some((item) => item.status === \"failed\" || item.status === \"cancelled\")\n );\n}\n\n/**\n * Whether a readable turn's work row has anything to reveal when expanded.\n * Unless the host shows startup phases as details, the work row's rail only\n * renders failed or cancelled preparation steps, so a detail made only of\n * completed or still-running steps (for example the queue phase before a turn\n * was parked on a usage limit) renders nothing and does not make the row\n * expandable.\n */\nexport function readableWorkHasDetails(\n group: ActivityGroup & { work: NonNullable<ActivityGroup[\"work\"]> },\n options: Pick<ReadableWorkOptions, \"startupDetails\">,\n): boolean {\n // Steps not loaded yet are revealed (and loaded) by opening the row.\n if (group.work.steps && group.work.steps.state !== \"complete\") return true;\n return group.work.details.some(\n (detail) =>\n options.startupDetails ||\n detail.kind !== \"activity\" ||\n Boolean(detail.work) ||\n !detail.items.every(\n (item) =>\n (item.kind === \"startup-phase\" &&\n item.status !== \"failed\" &&\n item.status !== \"cancelled\") ||\n (item.kind === \"reasoning\" && !item.text.trim()),\n ),\n );\n}\n\n/**\n * Status of a readable turn's work row, minus the host-rendered live preview.\n * Time spent waiting for model capacity, or between a failed attempt and its\n * Retry, is not work: the worked duration and the live working clock exclude\n * it, and a capacity wait itself shows no clock. A\n * wait's `detail` is its one quiet secondary line.\n */\nexport function readableWorkStatus(\n t: OpenGeniText,\n group: ActivityGroup & { work: NonNullable<ActivityGroup[\"work\"]> },\n): Omit<TurnSummaryStatus, \"preview\"> & { detail?: string | undefined } {\n const end = group.work.endedAt;\n const pausedMs = group.work.pausedMs ?? 0;\n if (end) {\n const durationMs = durationBetween(group.work.startedAt, end);\n const cycles = group.work.cycles;\n // Folded quiet cycles report their wall-clock span: waits are the point.\n if (cycles)\n return {\n kind: \"worked\",\n label: t(\"timeline.workPresentation.countUpdatesOver\", { count: cycles.count }),\n durationMs,\n };\n return {\n kind: \"worked\",\n durationMs: durationMs === undefined ? undefined : Math.max(0, durationMs - pausedMs),\n };\n }\n if (group.work.waiting) {\n const { untimed, since, ...waiting } = group.work.waiting;\n return { kind: \"waiting\", ...waiting, ...(untimed ? {} : { since }) };\n }\n const started = Date.parse(group.work.startedAt);\n return {\n kind: \"working\",\n since:\n pausedMs > 0 && Number.isFinite(started)\n ? new Date(started + pausedMs).toISOString()\n : group.work.startedAt,\n };\n}\n\n/** Whether a readable turn's work fold starts expanded. */\nexport function readableWorkDefaultOpen(group: ActivityGroup): true | undefined {\n return timelineGroupContainsPresentedImage(group) ||\n group.outcome === \"failed\" ||\n group.items.some(\n (item) =>\n item.kind === \"startup-phase\" &&\n (item.status === \"failed\" ||\n // A cancelled phase with a blocked reason is an expected wait (for\n // example compacting the conversation first), not an interruption.\n (item.status === \"cancelled\" && !item.blockedReason)),\n )\n ? true\n : undefined;\n}\n\n/** Whether the live preview should show (images stay primary output instead). */\nexport function readableWorkShowsPreview(group: ActivityGroup): boolean {\n return !timelineGroupContainsPresentedImage(group);\n}\n\n/**\n * The step a rolling preview shows: steps advance with event order (progress notes and\n * startup phases have their own surfaces). Mirrors the web RollingActivity selection.\n */\nexport function rollingActivityItem(\n items: readonly ActivityItem[],\n previousItem?: ActivityItem,\n mounted = true,\n): { item: ActivityItem; running: boolean; earlierCount: number } | null {\n const work = items.filter(\n (item) => item.kind !== \"startup-phase\" && item.kind !== \"agent-message\",\n );\n const active = work.filter((item) =>\n item.kind === \"reasoning\" ? item.streaming : \"status\" in item && item.status === \"running\",\n );\n const item =\n !mounted && previousItem && previousItem.kind !== \"agent-message\" ? previousItem : work.at(-1);\n if (!item) return null;\n return {\n item,\n running: active.some((entry) => entry.id === item.id),\n earlierCount: Math.max(\n 0,\n work.findIndex((entry) => entry.id === item.id),\n ),\n };\n}\n","import { formatClockTime } from \"../lib/format\";\nimport { formatElapsed } from \"./turn-summary-model\";\nimport type { NoticeItem } from \"./types\";\nimport { durationBetween } from \"./work-presentation\";\nimport { type OpenGeniText } from \"../messages/runtime\";\n\n/** An approval notice the person has since answered. */\nexport function noticeIsResolvedApproval(\n item: Pick<NoticeItem, \"approval\" | \"resolvedAt\">,\n): boolean {\n return Boolean(item.resolvedAt && item.approval);\n}\n\n/**\n * What an approval asked, as history: its question without the question mark\n * or anything after it (\"Remove the Gmail connection for anna@example.com?\n * …\" → \"Remove the Gmail connection for anna@example.com\"). A quoted name\n * (“…”) keeps its own punctuation.\n */\nexport function approvalHistoryTitle(title: string): string {\n // A question cut short lost its own \"?\": an earlier one is a name's.\n if (title.trimEnd().endsWith(\"…\")) return title.trim();\n let quoted = 0;\n let end = -1;\n for (let index = 0; index < title.length; index += 1) {\n const char = title[index];\n if (char === \"“\") quoted += 1;\n else if (char === \"”\") quoted = Math.max(0, quoted - 1);\n // The question ends at the last \"?\" that ends the title or starts\n // another sentence, so a \"?\" inside a name doesn't cut it short.\n else if (char === \"?\" && quoted === 0 && /^(\\s+\\p{Lu}|\\s*$)/u.test(title.slice(index + 1)))\n end = index;\n }\n return (end < 0 ? title : title.slice(0, end)).trim();\n}\n\ntype ApprovalAction = NonNullable<NoticeItem[\"approvalActions\"]>[number];\n\n/**\n * \"Added: 2 Oct 2026, 10:12 UTC\": the first of this action's facts whose\n * value differs from every other alike action's, or undefined when none do.\n */\nfunction tellingFact(action: ApprovalAction, alike: ApprovalAction[]): string | undefined {\n const valueOf = (other: ApprovalAction, label: string) =>\n other.facts?.find((fact) => fact.label === label)?.value;\n const fact = action.facts?.find((candidate) =>\n alike.every((other) => other === action || valueOf(other, candidate.label) !== candidate.value),\n );\n return fact ? `${fact.label}: ${fact.value}` : undefined;\n}\n\n/**\n * A resolved approval notice reads as history, saying what the person\n * decided for each action whose answer is known, one line each: \"You\n * approved “Remove the Gmail connection for anna@example.com”.\" Actions it\n * asked about but never got an answer for here (a later wait asked again)\n * are left out. Two that would read the same get the first fact that tells\n * them apart: \"(Added: 2 Oct 2026, 10:12 UTC)\".\n */\nexport function noticeDisplayText(\n t: OpenGeniText,\n item: Pick<NoticeItem, \"text\" | \"approval\" | \"resolvedAt\" | \"approvalActions\">,\n): string {\n if (!noticeIsResolvedApproval(item)) return item.text;\n const actions = item.approvalActions ?? [];\n const decided = actions.filter((action) => action.decision !== undefined);\n // Without any answer (an older replay), say only that it was answered.\n if (decided.length === 0) return t(\"timeline.noticePresentation.youRespondedToThisApproval\");\n // Each answered action, by what it asked.\n if (decided.every((action) => action.title)) {\n const titled = decided.map((action) => ({\n action,\n title: approvalHistoryTitle(action.title!),\n }));\n return titled\n .map(({ action, title }) => {\n const alike = titled.filter((other) => other.title === title).map((other) => other.action);\n const detail = alike.length > 1 ? tellingFact(action, alike) : undefined;\n if (detail)\n return action.decision === \"approve\"\n ? t(\"timeline.noticePresentation.youApprovedTitleWithDetail\", { title, detail })\n : action.decision === \"reject\"\n ? t(\"timeline.noticePresentation.youRejectedTitleWithDetail\", { title, detail })\n : t(\"timeline.noticePresentation.declinedAutomaticallyTitleWithDetail\", {\n title,\n detail,\n });\n return action.decision === \"approve\"\n ? t(\"timeline.noticePresentation.youApprovedTitle\", { title })\n : action.decision === \"reject\"\n ? t(\"timeline.noticePresentation.youRejectedTitle\", { title })\n : t(\"timeline.noticePresentation.declinedAutomaticallyTitle\", { title });\n })\n .join(\"\\n\");\n }\n // Declined by Opengeni rather than the person: never say \"You\".\n const automatic = decided.filter((action) => action.decision === \"automatic_reject\").length;\n if (automatic === decided.length) return t(\"timeline.noticePresentation.declinedAutomatically\");\n if (automatic > 0) return t(\"timeline.noticePresentation.youRespondedToThisApproval\");\n const approved = decided.filter((action) => action.decision === \"approve\").length;\n const rejected = decided.length - approved;\n if (decided.length === 1)\n return approved === 1\n ? t(\"timeline.noticePresentation.youApprovedThis\")\n : t(\"timeline.noticePresentation.youRejectedThis\");\n if (rejected === 0)\n return t(\"timeline.noticePresentation.youApprovedActions\", { count: approved });\n if (approved === 0)\n return t(\"timeline.noticePresentation.youRejectedActions\", { count: rejected });\n return t(\"timeline.noticePresentation.youApprovedAndRejected\", { approved, rejected });\n}\n\n/** Notice pill tone: failures stay red, an open wait keeps the waiting hue. */\nexport function noticeTone(\n item: Pick<NoticeItem, \"tone\" | \"resolvedAt\">,\n): \"failed\" | \"waiting\" | \"neutral\" {\n return item.tone === \"failed\"\n ? \"failed\"\n : item.tone === \"waiting\" && !item.resolvedAt\n ? \"waiting\"\n : \"neutral\";\n}\n\n/**\n * Plain-text summary of a recorded agent wait, as web's quiet disclosure reads\n * it: \"Waited for 2 agents · 3m 5s\" once later input ended the wait, otherwise\n * \"Waiting · since 10:32\" (with the date on a later day).\n */\nexport function recordedWaitSummaryText(\n t: OpenGeniText,\n item: Pick<NoticeItem, \"occurredAt\" | \"waitingAgents\" | \"waitEndedAt\">,\n now: Date = new Date(),\n): string {\n const agents = item.waitingAgents ?? 0;\n const waitedMs = item.waitEndedAt\n ? durationBetween(item.occurredAt, item.waitEndedAt)\n : undefined;\n if (waitedMs !== undefined) {\n const elapsed = formatElapsed(t, waitedMs);\n return agents > 0\n ? t(\"timeline.noticePresentation.waitedForAgentsElapsed\", { count: agents, elapsed })\n : t(\"timeline.noticePresentation.waitedElapsed\", { elapsed });\n }\n const started = new Date(item.occurredAt);\n const since =\n started.toDateString() === now.toDateString()\n ? formatClockTime(t, item.occurredAt)\n : started.toLocaleString(t.locale, { dateStyle: \"medium\", timeStyle: \"short\" });\n if (item.waitEndedAt)\n return agents > 0\n ? t(\"timeline.noticePresentation.waitedForAgentsSince\", { count: agents, since })\n : t(\"timeline.noticePresentation.waitedSince\", { since });\n return agents > 0\n ? t(\"timeline.noticePresentation.waitingForAgentsSince\", { count: agents, since })\n : t(\"timeline.noticePresentation.waitingSince\", { since });\n}\n"],"mappings":"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","names":["item","fact"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/app/components/rail/session-row-content.tsx"],"sourcesContent":["import {\n CalendarClockIcon,\n Clock3Icon,\n HourglassIcon,\n Loader2Icon,\n TriangleAlertIcon,\n ZapIcon,\n} from \"lucide-react\";\nimport { Children, isValidElement, useId, type ReactNode } from \"react\";\n\nimport { CreatorMonogram } from \"../creator-monogram\";\nimport { type CreatorRef, creatorAnnouncement, creatorInitials } from \"../../lib/creator-initials\";\nimport { formatWaitingSince } from \"../../lib/format\";\nimport { t } from \"../../lib/console-text\";\nimport { cn } from \"../../lib/utils\";\nimport type { RailAggregateStatus } from \"../../lib/sessions-group\";\nimport {\n sessionAutomationWaitLabel,\n type SessionAutomationWait,\n} from \"../../../session-list-model\";\n\nexport function ActiveWorkMark({ className }: { className?: string | undefined }) {\n const maskId = `active-work-${useId().replaceAll(\":\", \"\")}`;\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 108 108\"\n className={cn(\"size-2.5 shrink-0 text-session-update\", className)}\n >\n <defs>\n <mask id={maskId} maskUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\"108\" height=\"108\">\n <circle cx=\"54\" cy=\"54\" r=\"48\" fill=\"white\" />\n <g fill=\"none\" stroke=\"black\" strokeWidth=\"21\" strokeLinecap=\"round\">\n <path d=\"M-8 43 C35 40 71 29 116 16\" />\n <path d=\"M-8 86 C35 83 71 72 116 59\" />\n </g>\n </mask>\n </defs>\n <circle cx=\"54\" cy=\"54\" r=\"48\" fill=\"currentColor\" mask={`url(#${maskId})`} />\n <circle cx=\"54\" cy=\"54\" r=\"48\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" />\n </svg>\n );\n}\n\n/** The one descendant-aware status marker shared by rows and section headers. */\nfunction RailAggregateDot({ summary }: { summary: RailAggregateStatus }) {\n if (summary.kind === \"neutral\") return null;\n if (summary.kind === \"active\") {\n return (\n <Loader2Icon\n aria-hidden=\"true\"\n className=\"size-3 shrink-0 animate-spin text-fg-subtle motion-reduce:animate-none\"\n style={{ animationDuration: \"1.333333s\" }}\n />\n );\n }\n if (summary.kind === \"queued\") {\n return <Clock3Icon aria-hidden=\"true\" className=\"size-3 shrink-0 text-fg-subtle\" />;\n }\n if (summary.kind === \"waiting\") {\n // Parked until input or its wake-up time: nothing is executing, so no spinner.\n return <HourglassIcon aria-hidden=\"true\" className=\"size-3 shrink-0 text-fg-subtle\" />;\n }\n if (summary.kind === \"active_work\") {\n return <ActiveWorkMark />;\n }\n if (summary.kind === \"send_failed\") {\n return (\n <TriangleAlertIcon aria-hidden=\"true\" className=\"size-3.5 shrink-0 text-status-failed\" />\n );\n }\n const tone =\n summary.kind === \"needs_attention\"\n ? \"bg-status-waiting\"\n : summary.kind === \"failed\"\n ? \"bg-status-failed\"\n : \"bg-session-update\";\n return (\n <span\n aria-hidden=\"true\"\n className={cn(\"relative inline-flex size-2 shrink-0 rounded-full\", tone)}\n />\n );\n}\n\n/**\n * The row's announced name.\n *\n * `aria-label` replaces name-from-content, so this string is the whole of what\n * a screen reader hears for the row: the creator chip is `aria-hidden`, and\n * even the sr-only state line inside the link is inert for it. Every fact a\n * sighted user reads off the row belongs here, and in exactly one place.\n */\nexport function sessionRowAccessibleName({\n title,\n stateLabel,\n pinned,\n statusLabel,\n spawnedLabel,\n creator,\n}: {\n title: string;\n stateLabel: string;\n pinned: boolean;\n statusLabel: string;\n spawnedLabel?: string | null | undefined;\n creator?: CreatorRef | null | undefined;\n}): string {\n const spokenCreator = creatorAnnouncement(creator ?? null);\n return `Open ${title}. ${stateLabel}${pinned ? \". Pinned\" : \"\"}. ${statusLabel}${\n spawnedLabel ? `. ${spawnedLabel}` : \"\"\n }${spokenCreator ? `. Created by ${spokenCreator}` : \"\"}`;\n}\n\n/**\n * The quiet mark for a chat an automation will post into: a clock while it\n * waits for its schedule, a bolt while it waits for an event. `label` says\n * what exactly (\"Waiting for deploy.finished from Deploys\"); without it the\n * plain wait is named.\n */\nexport function AutomationWaitIcon({\n wait,\n label: detail,\n className,\n}: {\n wait: SessionAutomationWait;\n label?: string | undefined;\n className?: string | undefined;\n}) {\n const Icon = wait === \"event\" ? ZapIcon : CalendarClockIcon;\n const label = detail || sessionAutomationWaitLabel(t, wait);\n return (\n <span role=\"img\" aria-label={label} title={label} className=\"inline-flex shrink-0\">\n <Icon\n aria-hidden=\"true\"\n data-automation-wait={wait}\n className={cn(\"size-3.5 shrink-0 text-fg-subtle\", className)}\n />\n </span>\n );\n}\n\nexport function RailTrailingMetadata({\n summary,\n automationWait = null,\n automationWaitLabel,\n relativeTime,\n jumpKey,\n creator,\n quickActionSlots = 0,\n}: {\n summary: RailAggregateStatus;\n /** What an automation posting into this chat is waiting for; null for none. */\n automationWait?: SessionAutomationWait | null | undefined;\n /** That wait in words, for the mark's tooltip and accessible name. */\n automationWaitLabel?: string | undefined;\n relativeTime?: string | undefined;\n /** The key that opens this row (\"⌘3\"), shown in place of the time while ⌘ is held. */\n jumpKey?: string | undefined;\n /** Rightmost items replaced in place by the row's desktop quick actions. */\n quickActionSlots?: number | undefined;\n /**\n * Session creator for a top-level row, else null; callers decide which rows\n * are roots. A chip is its own reason to render this block: a mobile root row\n * can have no status marker and no time and still name who started it.\n */\n creator?: CreatorRef | null | undefined;\n}) {\n const hasStatusMarker = summary.kind !== \"neutral\";\n const hasRelativeTime = Boolean(relativeTime);\n const hasMonogram = creator ? creatorInitials(creator) !== null : false;\n // How long the longest-waiting session behind a \"needs you\" marker has been\n // blocked on a human. A collapsed parent with a child parked for ten hours\n // must say so, not hide it behind a dot.\n const waitingFor =\n summary.kind === \"needs_attention\" && summary.attentionSince\n ? formatWaitingSince(summary.attentionSince)\n : \"\";\n if (\n !automationWait &&\n !hasStatusMarker &&\n !hasRelativeTime &&\n !jumpKey &&\n !hasMonogram &&\n !quickActionSlots\n )\n return null;\n const items = Children.toArray([\n automationWait ? (\n <AutomationWaitIcon key=\"automation\" wait={automationWait} label={automationWaitLabel} />\n ) : null,\n hasMonogram && creator ? (\n <CreatorMonogram key=\"creator\" createdBy={creator} showTitle={false} />\n ) : null,\n waitingFor ? (\n <span\n key=\"waiting\"\n data-session-row-waiting\n title={summary.label}\n className=\"shrink-0 whitespace-nowrap text-2xs tabular-nums text-status-waiting\"\n >\n {waitingFor}\n </span>\n ) : null,\n hasStatusMarker ? (\n <span key=\"status\" className=\"flex size-3 items-center justify-center\" title={summary.label}>\n <RailAggregateDot summary={summary} />\n </span>\n ) : null,\n jumpKey ? (\n <kbd\n key=\"time\"\n data-session-row-jump-key\n className=\"inline-flex h-4.5 min-w-9 shrink-0 items-center justify-center rounded-[4px] border border-border bg-surface-2 px-1 font-sans text-2xs leading-none font-medium whitespace-nowrap text-fg-muted\"\n >\n {jumpKey}\n </kbd>\n ) : hasRelativeTime ? (\n <span\n key=\"time\"\n className=\"min-w-9 shrink-0 whitespace-nowrap text-right text-2xs tabular-nums text-fg\"\n >\n {relativeTime}\n </span>\n ) : null,\n ]).filter(isValidElement);\n if (!quickActionSlots) {\n return (\n <span\n data-session-row-metadata\n className=\"inline-flex shrink-0 items-center justify-end gap-1\"\n >\n {items}\n </span>\n );\n }\n // Empty rows still reserve their action footprint. Visibility (never display\n // or padding) swaps the last items, keeping every other box stationary.\n while (items.length < quickActionSlots) items.unshift(<span key={`empty-${items.length}`} />);\n return (\n <span data-session-row-metadata className=\"inline-flex shrink-0 items-center justify-end\">\n {items.map((item, index) => (\n <span\n key={item.key}\n data-session-row-slot\n className={cn(\n \"inline-flex min-w-6 shrink-0 items-center justify-center last:min-w-10\",\n index >= items.length - quickActionSlots &&\n \"pointer-fine:group-hover:invisible pointer-fine:group-focus-within:invisible\",\n )}\n >\n {item}\n </span>\n ))}\n </span>\n );\n}\n\nexport function SessionRowContent({\n title,\n stateLabel,\n depthLabel,\n descendantLabel,\n mobile,\n summary,\n automationWait = null,\n automationWaitLabel,\n relativeTime,\n jumpKey,\n creator,\n quickActionSlots = 0,\n leading,\n parentTitle,\n}: {\n /** Before the title: a bot's avatar. */\n leading?: ReactNode | undefined;\n title: string;\n /** For a pinned sub-agent chat, the chat it belongs to, said quietly after the title. */\n parentTitle?: string | null | undefined;\n stateLabel: string;\n depthLabel?: string | null | undefined;\n descendantLabel?: string | null | undefined;\n mobile: boolean;\n summary: RailAggregateStatus;\n /** What an automation posting into this chat is waiting for; null for none. */\n automationWait?: SessionAutomationWait | null | undefined;\n /** See RailTrailingMetadata. */\n automationWaitLabel?: string | undefined;\n relativeTime?: string | undefined;\n /** See RailTrailingMetadata. */\n jumpKey?: string | undefined;\n quickActionSlots?: number | undefined;\n /** Session creator for a top-level row, else null. See RailTrailingMetadata. */\n creator?: CreatorRef | null | undefined;\n}) {\n return (\n <>\n {/* Inert for the row's accessible name, which its `aria-label` owns -\n including the creator. Kept as-is so this change regresses nothing. */}\n <span className=\"sr-only\">{stateLabel}. </span>\n {leading}\n <span className=\"flex min-w-0 flex-1 flex-col leading-tight\">\n {parentTitle ? (\n // The title keeps its room; the parent's name gives way first. The\n // line as a whole fades at the column's edge, as a title does.\n <span\n data-session-row-title\n className=\"flex min-w-0 items-baseline gap-1.5 overflow-hidden whitespace-nowrap\"\n >\n <span className=\"min-w-0 truncate\">{title}</span>\n <span\n data-session-row-parent\n className=\"min-w-10 max-w-[55%] shrink-3 truncate text-2xs text-fg-muted\"\n >\n in {parentTitle}\n </span>\n </span>\n ) : (\n <span data-session-row-title className=\"block min-w-0 overflow-hidden whitespace-nowrap\">\n {title}\n </span>\n )}\n {mobile ? (\n <span\n data-session-row-state\n className=\"mt-0.5 truncate text-2xs font-normal text-fg-muted\"\n >\n {[stateLabel, depthLabel, descendantLabel, relativeTime].filter(Boolean).join(\" · \")}\n </span>\n ) : null}\n </span>\n <RailTrailingMetadata\n quickActionSlots={quickActionSlots}\n summary={summary}\n automationWait={automationWait}\n automationWaitLabel={automationWaitLabel}\n relativeTime={relativeTime}\n jumpKey={jumpKey}\n creator={creator}\n />\n </>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,2 +0,0 @@
1
- "use client";
2
- //# sourceMappingURL=chunk-O2UPPN5M.js.map