@opengeni/react 6.8.0 → 6.9.1-canary.41937124785001
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.
- package/dist/app/app-state.js +8 -8
- package/dist/app/components/Composer.js +18 -18
- package/dist/app/components/agent/agent-capability-picker.js +6 -6
- package/dist/app/components/artifacts/artifact-library.js +6 -6
- package/dist/app/components/artifacts/artifact-viewer.js +18 -18
- package/dist/app/components/artifacts/chat-interactive-block.js +11 -11
- package/dist/app/components/artifacts/file-reach-dialog.js +6 -6
- package/dist/app/components/artifacts/inline-chat-image.js +19 -19
- package/dist/app/components/artifacts/retained-file-preview.js +20 -20
- package/dist/app/components/artifacts/retained-text-preview.js +3 -3
- package/dist/app/components/artifacts/site-audience.js +3 -3
- package/dist/app/components/artifacts/site-conversations.js +9 -9
- package/dist/app/components/artifacts/site-data.js +10 -10
- package/dist/app/components/artifacts/site-publishing-page.js +25 -25
- package/dist/app/components/artifacts/site-publishing.js +22 -22
- package/dist/app/components/artifacts/site-settings.js +24 -24
- package/dist/app/components/artifacts/site-version-menu.js +3 -3
- package/dist/app/components/billing-class-mark.js +3 -3
- package/dist/app/components/bots/bot-launch-strip.js +20 -20
- package/dist/app/components/bots/bot-template-dialog.js +26 -26
- package/dist/app/components/bots/bot-template-shortcuts.js +20 -20
- package/dist/app/components/bots/bot-templates-page.js +30 -30
- package/dist/app/components/capabilities/capability-detail-sheet.js +6 -6
- package/dist/app/components/capabilities/capability-logo-source.js +13 -13
- package/dist/app/components/capabilities/connector-tool-permissions.js +4 -4
- package/dist/app/components/capabilities/native-connect-setup.js +13 -13
- package/dist/app/components/capabilities/own-logins-shared-heads-up.js +3 -3
- package/dist/app/components/capabilities/prepared-mcp-setup-card.js +15 -15
- package/dist/app/components/capabilities/session-capability-card.js +52 -52
- package/dist/app/components/capabilities/session-chrome-card.js +20 -20
- package/dist/app/components/capabilities/session-custom-mcp-card.js +16 -16
- package/dist/app/components/capabilities/session-github-card.js +16 -16
- package/dist/app/components/capabilities/session-machine-card.js +19 -19
- package/dist/app/components/capabilities/session-personal-github-card.js +14 -14
- package/dist/app/components/capabilities/session-plugin-card.js +8 -8
- package/dist/app/components/command-menu/chat-status.js +15 -15
- package/dist/app/components/command-menu/chat-switcher.js +35 -35
- package/dist/app/components/command-menu/command-menu.js +39 -39
- package/dist/app/components/command-menu/shortcut-sheet.js +8 -8
- package/dist/app/components/composer-capabilities-menu-body.js +4 -4
- package/dist/app/components/composer-mobile-plus-panel.js +8 -8
- package/dist/app/components/composer-mobile-plus.js +1 -1
- package/dist/app/components/desktop/app-shots.js +6 -6
- package/dist/app/components/desktop/computer-use.js +2 -2
- package/dist/app/components/desktop/this-computer.js +5 -5
- package/dist/app/components/feedback.js +3 -3
- package/dist/app/components/github-app-connect-launcher.js +1 -1
- package/dist/app/components/machines/connect-machine-dialog.js +11 -11
- package/dist/app/components/markdown.js +6 -6
- package/dist/app/components/models/models-ui.js +5 -5
- package/dist/app/components/models/subscription-usage.d.ts +34 -0
- package/dist/app/components/models/subscription-usage.js +24 -0
- package/dist/app/components/my-things.js +4 -4
- package/dist/app/components/own-where-it-works.js +3 -3
- package/dist/app/components/personal-resource-attachment-surface.js +4 -4
- package/dist/app/components/pickers.js +5 -5
- package/dist/app/components/rail/channel-create-dialog.js +3 -3
- package/dist/app/components/rail/project-glyph.js +20 -20
- package/dist/app/components/rail/project-profile.js +27 -27
- package/dist/app/components/rail/rail-context.js +1 -1
- package/dist/app/components/rail/rail-sections.js +55 -55
- package/dist/app/components/rail/session-header.js +47 -47
- package/dist/app/components/rail/session-list.js +53 -53
- package/dist/app/components/rail/session-row-content.js +4 -4
- package/dist/app/components/rail/session-row-hover-details.js +14 -14
- package/dist/app/components/rail/session-shell.js +76 -73
- package/dist/app/components/rail/site-session-group-heading.js +8 -8
- package/dist/app/components/session/agent-configuration-panel.js +12 -12
- package/dist/app/components/session/banners.js +8 -8
- package/dist/app/components/session/console-new-conversation.js +39 -39
- package/dist/app/components/session/descendant-requests.js +36 -36
- package/dist/app/components/session/editable-artifacts-workspace.js +16 -16
- package/dist/app/components/session/failed-session-banner.js +6 -6
- package/dist/app/components/session/failure-recovery-boundary.js +3 -3
- package/dist/app/components/session/human-input-delegation-record.js +2 -2
- package/dist/app/components/session/human-input.js +33 -33
- package/dist/app/components/session/inspector.js +43 -43
- package/dist/app/components/session/message-actions.js +3 -3
- package/dist/app/components/session/message-resource-attachments.js +10 -10
- package/dist/app/components/session/model-recovery-notice.js +3 -3
- package/dist/app/components/session/new-session-settings-menu.js +6 -6
- package/dist/app/components/session/new-session-setup-strip.js +21 -21
- package/dist/app/components/session/sandbox-recovery-actions.js +3 -3
- package/dist/app/components/session/sandbox-switcher.js +7 -7
- package/dist/app/components/session/sandbox-workspace.js +48 -48
- package/dist/app/components/session/search-markdown-highlight.js +7 -7
- package/dist/app/components/session/search-results-view.js +8 -8
- package/dist/app/components/session/session-admin-access.js +4 -4
- package/dist/app/components/session/session-admission-notice.js +4 -4
- package/dist/app/components/session/session-avatar-picker.js +21 -21
- package/dist/app/components/session/session-avatar.js +19 -19
- package/dist/app/components/session/session-machine-access-notice.js +4 -4
- package/dist/app/components/session/session-profile-dialog.js +25 -25
- package/dist/app/components/session/session-profile-editor.js +26 -26
- package/dist/app/components/session/session-retention.js +3 -3
- package/dist/app/components/session/session-search-dialog.js +8 -8
- package/dist/app/components/session/session-tenancy-control.js +2 -2
- package/dist/app/components/session/session-usage-limit-section.js +4 -4
- package/dist/app/components/session/share-chat-dialog.js +5 -5
- package/dist/app/components/session/subagents.js +8 -8
- package/dist/app/components/session/subscription-account-indicator.js +12 -7
- package/dist/app/components/session/subscription-account-menu.d.ts +15 -15
- package/dist/app/components/session/subscription-account-menu.js +6 -1
- package/dist/app/components/session/subscription-account.d.ts +16 -9
- package/dist/app/components/settings/row-select.js +4 -4
- package/dist/app/components/transcription-settings.js +6 -6
- package/dist/app/components/ui/destructive-confirm.js +5 -5
- package/dist/app/components/usage/usage-entry.js +3 -3
- package/dist/app/components/window-bar.js +9 -9
- package/dist/app/components/workspace-composer-plus.js +16 -16
- package/dist/app/components/workspace-reach.js +4 -4
- package/dist/app/embed/session-app.js +160 -157
- package/dist/app/lib/actions/actions-provider.js +8 -8
- package/dist/app/lib/agent-capabilities.d.ts +12 -2
- package/dist/app/lib/agent-capabilities.js +3 -3
- package/dist/app/lib/codex-usage-query.js +2 -2
- package/dist/app/lib/composer-connectors.js +14 -14
- package/dist/app/lib/console-site.js +2 -2
- package/dist/app/lib/console-text.js +2 -2
- package/dist/app/lib/events.js +12 -12
- package/dist/app/lib/failed-session-copy.js +3 -3
- package/dist/app/lib/model-access-onboarding.js +3 -3
- package/dist/app/lib/move-chat-to-machine.js +3 -3
- package/dist/app/lib/session-branch-cache.js +8 -8
- package/dist/app/lib/session-create.js +4 -4
- package/dist/app/lib/session-group-pagination.js +8 -8
- package/dist/app/lib/session-hover-facts.js +13 -13
- package/dist/app/lib/session-model.js +2 -2
- package/dist/app/lib/session-pins.js +1 -1
- package/dist/app/lib/session-rail.js +5 -5
- package/dist/app/lib/session-rename.js +3 -3
- package/dist/app/lib/sessions-group.d.ts +5 -3
- package/dist/app/lib/sessions-group.js +7 -7
- package/dist/app/lib/site-tool-consent-dialog.js +7 -7
- package/dist/app/lib/site-tool-consent.js +1 -1
- package/dist/app/lib/subscription-accounts.d.ts +79 -0
- package/dist/app/lib/subscription-accounts.js +18 -0
- package/dist/app/lib/turn-failure-analytics.js +4 -4
- package/dist/app/lib/use-follow-up-repositories.js +3 -3
- package/dist/app/lib/use-workspace-machines.js +4 -4
- package/dist/app/lib/use-workspace-model-catalog.js +3 -3
- package/dist/app/lib/use-workspace-rigs.js +2 -2
- package/dist/app/lib/workspace-navigation-preference.js +4 -4
- package/dist/app/lib/workspace-scope-context.js +3 -3
- package/dist/app/routes/artifacts.js +48 -48
- package/dist/app/routes/retained-artifact.js +32 -32
- package/dist/app/routes/session.js +96 -96
- package/dist/app/routes/sessions-index-hydration.js +5 -5
- package/dist/app/routes/sessions-index.js +76 -76
- package/dist/app/routes/site-view.js +55 -55
- package/dist/artifacts-document.js +4 -4
- package/dist/artifacts-presentation.js +4 -4
- package/dist/artifacts-spreadsheet.js +4 -4
- package/dist/artifacts.js +10 -10
- package/dist/automations.js +10 -10
- package/dist/{browser-viewer-ZHQDVHZ2.js → browser-viewer-F4FL7JKB.js} +4 -4
- package/dist/{chat-interactive-block-VSDD6X3M.js → chat-interactive-block-4U5JWRSY.js} +5 -5
- package/dist/{chunk-4K64EKM7.js → chunk-22YIIM3X.js} +4 -4
- package/dist/{chunk-3NNAC43A.js → chunk-2N7ACQ7M.js} +2 -2
- package/dist/{chunk-7Z76QP64.js → chunk-2PY5XD3F.js} +35 -5
- package/dist/chunk-2PY5XD3F.js.map +1 -0
- package/dist/{chunk-WDASYY4S.js → chunk-2TEYUDJD.js} +8 -8
- package/dist/{chunk-OTW25A6I.js → chunk-37JJQNZB.js} +3 -3
- package/dist/{chunk-VCJQQYRE.js → chunk-3DWQPURZ.js} +4 -4
- package/dist/{chunk-GTRAH4FG.js → chunk-3GWC3FU3.js} +2 -2
- package/dist/{chunk-AB5IW227.js → chunk-3ICY6LP3.js} +3 -3
- package/dist/{chunk-WIFDNUKD.js → chunk-3OCU5RX5.js} +3 -3
- package/dist/{chunk-UBRQ3PQD.js → chunk-3SPDJLOR.js} +2 -2
- package/dist/{chunk-IZXYFWA4.js → chunk-3WVLR7UA.js} +12 -12
- package/dist/{chunk-DEHLWZSI.js → chunk-3XMB3L57.js} +4 -4
- package/dist/{chunk-AJBDAVX3.js → chunk-4IUOBO2H.js} +7 -7
- package/dist/{chunk-NFCS5WYC.js → chunk-4KQ3A3EO.js} +3 -3
- package/dist/{chunk-LIJNVIT3.js → chunk-4L5B5AZT.js} +3 -3
- package/dist/{chunk-EDDKPIIV.js → chunk-4NB3TPNE.js} +2 -2
- package/dist/{chunk-PSM3CU7N.js → chunk-4TDKXHCD.js} +46 -39
- package/dist/chunk-4TDKXHCD.js.map +1 -0
- package/dist/{chunk-OJWDNNW3.js → chunk-4TPTGBIO.js} +5 -5
- package/dist/{chunk-J2WY42FA.js → chunk-4UHGW6WF.js} +2 -2
- package/dist/{chunk-7NLF35YL.js → chunk-4YN2JLYK.js} +4 -4
- package/dist/{chunk-OOOSGPJL.js → chunk-53MYEEMA.js} +1 -1
- package/dist/{chunk-467WDSOK.js → chunk-5HYWXPMA.js} +2 -2
- package/dist/{chunk-XMBOLFFS.js → chunk-5IMNL6IV.js} +2 -2
- package/dist/{chunk-4Z5X7PLC.js → chunk-5MLM5T5C.js} +3 -3
- package/dist/{chunk-YMI27QPF.js → chunk-5NKQZVXP.js} +2 -2
- package/dist/{chunk-ZW5YTIH3.js → chunk-5PB46DAA.js} +1 -1
- package/dist/{chunk-ZW5YTIH3.js.map → chunk-5PB46DAA.js.map} +1 -1
- package/dist/{chunk-CYDXCILL.js → chunk-5SODSGW7.js} +7 -7
- package/dist/{chunk-Q5EZNBPI.js → chunk-5YAJASCO.js} +3 -3
- package/dist/{chunk-M3FDGRB4.js → chunk-62XAL5BA.js} +3 -3
- package/dist/{chunk-SGH7I7OY.js → chunk-67R6NAFI.js} +2 -2
- package/dist/{chunk-Q5K2J5GG.js → chunk-6BN3RU7T.js} +13 -3
- package/dist/chunk-6BN3RU7T.js.map +1 -0
- package/dist/{chunk-PYB4BFEC.js → chunk-6BQLDL6R.js} +3 -3
- package/dist/{chunk-YJSCLGAW.js → chunk-6EZYHJTL.js} +3 -3
- package/dist/{chunk-OWET7EY2.js → chunk-6GW7NJMK.js} +19 -13
- package/dist/{chunk-OWET7EY2.js.map → chunk-6GW7NJMK.js.map} +1 -1
- package/dist/{chunk-G5UQBTXY.js → chunk-6LXIL3Q3.js} +2 -2
- package/dist/{chunk-T67LTMSW.js → chunk-6LYVAJFZ.js} +10 -10
- package/dist/{chunk-3L465FBR.js → chunk-6WB5UXMZ.js} +6 -6
- package/dist/{chunk-EKJHOWTZ.js → chunk-74UGYVCA.js} +4 -4
- package/dist/{chunk-PWUSSSSL.js → chunk-7BTNYZC7.js} +2 -2
- package/dist/{chunk-NQ2CPQJF.js → chunk-7D3WIDKK.js} +26 -3
- package/dist/chunk-7D3WIDKK.js.map +1 -0
- package/dist/{chunk-ESXAECZ3.js → chunk-7KZFGA25.js} +2 -2
- package/dist/{chunk-EGKARC53.js → chunk-7MGDX2TD.js} +2 -2
- package/dist/{chunk-Y3XZEKDQ.js → chunk-7N3GFGB6.js} +2 -2
- package/dist/{chunk-AH3DGOTK.js → chunk-7SFSN6AX.js} +2 -2
- package/dist/{chunk-QPQ7R77C.js → chunk-7SU4YVZ5.js} +5 -1
- package/dist/chunk-7SU4YVZ5.js.map +1 -0
- package/dist/{chunk-6QK65ZWM.js → chunk-7TGUHFGO.js} +3 -3
- package/dist/{chunk-QURYQFDN.js → chunk-7ZIWO65F.js} +2 -2
- package/dist/{chunk-OYCK4JRS.js → chunk-AJHLEJTK.js} +2 -2
- package/dist/{chunk-3PZ3LRPV.js → chunk-AN4U7EPH.js} +3 -3
- package/dist/{chunk-77BHKC43.js → chunk-APG6CEG7.js} +1 -1
- package/dist/{chunk-FSDQQQIA.js → chunk-APHLXQNP.js} +3 -3
- package/dist/{chunk-SN2WENRP.js → chunk-AXHQ7QXV.js} +3 -3
- package/dist/{chunk-54U6ZBEX.js → chunk-AYTLSPF6.js} +3 -3
- package/dist/{chunk-WYGTAQMX.js → chunk-AZFVRPQM.js} +76 -22
- package/dist/chunk-AZFVRPQM.js.map +1 -0
- package/dist/{chunk-R33SBMB7.js → chunk-BBSKKBMV.js} +3 -3
- package/dist/{chunk-2GCHGWNE.js → chunk-BGH6TU2P.js} +3 -3
- package/dist/{chunk-D3PTVN2I.js → chunk-BGIYL26H.js} +2 -2
- package/dist/{chunk-BQYRZIZ7.js → chunk-BL7UQUC3.js} +2 -2
- package/dist/{chunk-EBTUPRRQ.js → chunk-BOUHCYL6.js} +4 -4
- package/dist/{chunk-MKDFYE2E.js → chunk-BVNGDFBC.js} +2 -2
- package/dist/{chunk-ICAMYP5M.js → chunk-BWJK64CP.js} +2 -2
- package/dist/{chunk-RHXYO4H2.js → chunk-BZ2GTCQV.js} +2 -2
- package/dist/{chunk-GIWFLWXG.js → chunk-C2KASMJK.js} +4 -4
- package/dist/{chunk-KO3OHHY2.js → chunk-CAZDRDQT.js} +2 -2
- package/dist/{chunk-OK7BQMCI.js → chunk-CBJRZKZB.js} +9 -9
- package/dist/{chunk-OYOFPNLC.js → chunk-CF6NYG7J.js} +4 -4
- package/dist/{chunk-MT2R57SF.js → chunk-COITN7WN.js} +2 -2
- package/dist/{chunk-OCXTTKVA.js → chunk-CPVOXM2Q.js} +2 -2
- package/dist/{chunk-HYEIA25Y.js → chunk-CTZRCBKH.js} +2 -2
- package/dist/{chunk-OCXEY7HE.js → chunk-CWL27YTB.js} +2 -2
- package/dist/{chunk-K4DQS2ML.js → chunk-D2I33V5P.js} +4 -4
- package/dist/{chunk-736RUNIA.js → chunk-DF7WI4JH.js} +4 -4
- package/dist/{chunk-KUE5BOQE.js → chunk-DKZYCJCO.js} +4 -4
- package/dist/{chunk-74CBR5YE.js → chunk-DQ32FKFQ.js} +2 -2
- package/dist/{chunk-4O2XWOLZ.js → chunk-DTKG2YUF.js} +3 -3
- package/dist/{chunk-GMHIOYB7.js → chunk-DUDA4V5R.js} +4 -4
- package/dist/{chunk-XUOYNJPB.js → chunk-ECROT4M5.js} +24 -24
- package/dist/{chunk-PVB4YVDP.js → chunk-EOXV5XGY.js} +2 -2
- package/dist/{chunk-U6552Q3T.js → chunk-EQQOZ6DD.js} +2 -2
- package/dist/{chunk-G6ICCGJ3.js → chunk-EY6W5H4B.js} +2 -2
- package/dist/{chunk-HWVPLFIW.js → chunk-EYRFEWXJ.js} +2 -2
- package/dist/{chunk-7YTR3UFO.js → chunk-FB4JWUVJ.js} +8 -5
- package/dist/chunk-FB4JWUVJ.js.map +1 -0
- package/dist/{chunk-U4LTPFD2.js → chunk-FKK2PD7K.js} +2 -2
- package/dist/{chunk-PUUEI4W3.js → chunk-FPHHIC5K.js} +5 -5
- package/dist/{chunk-SP44O3OU.js → chunk-FQM6L22H.js} +2 -2
- package/dist/{chunk-2J77TWGH.js → chunk-FW22IREV.js} +3 -3
- package/dist/{chunk-EBIVTDEG.js → chunk-G4M6AYDB.js} +2 -2
- package/dist/{chunk-O4JOE3R7.js → chunk-G55NAU5M.js} +60 -74
- package/dist/chunk-G55NAU5M.js.map +1 -0
- package/dist/{chunk-BASI553K.js → chunk-G6AZ2WIU.js} +4 -4
- package/dist/{chunk-SJYTQLN3.js → chunk-GJ5IDSAX.js} +3 -3
- package/dist/{chunk-TDTD66BK.js → chunk-GRDSEZWZ.js} +2 -2
- package/dist/{chunk-MV2CLIO6.js → chunk-HBVJIGY2.js} +6 -6
- package/dist/{chunk-R4JA5JFI.js → chunk-HCWQLIOE.js} +3 -3
- package/dist/{chunk-MZY3VKKM.js → chunk-HEVD4A5G.js} +2 -2
- package/dist/{chunk-DLVIRJGK.js → chunk-HNDHSEVJ.js} +2 -2
- package/dist/{chunk-LPKJ77EK.js → chunk-HNTZ7B7M.js} +2 -2
- package/dist/{chunk-QQIZMVAJ.js → chunk-HQ7GTMII.js} +59 -57
- package/dist/chunk-HQ7GTMII.js.map +1 -0
- package/dist/{chunk-IN3VQFKS.js → chunk-I2FC7CAI.js} +2 -2
- package/dist/{chunk-SK5S2PCK.js → chunk-I7BGHBOM.js} +14 -14
- package/dist/chunk-I7BGHBOM.js.map +1 -0
- package/dist/{chunk-ZBHGNE2J.js → chunk-IEHZFYMH.js} +3 -3
- package/dist/{chunk-DWJ6J3YW.js → chunk-IXISEVD7.js} +4 -4
- package/dist/{chunk-TK5FWVZR.js → chunk-IZEDVQUD.js} +3 -3
- package/dist/{chunk-HEGV4QMS.js → chunk-J42QE4VO.js} +2 -2
- package/dist/{chunk-PRT4J2DL.js → chunk-J555XSUM.js} +2 -2
- package/dist/{chunk-SBXSKRFA.js → chunk-JNMHFSDF.js} +3 -3
- package/dist/{chunk-KI46GKMD.js → chunk-JTBAOPYO.js} +7 -7
- package/dist/{chunk-JHZRAYI4.js → chunk-JWSRFXRN.js} +2 -2
- package/dist/chunk-JWSRFXRN.js.map +1 -0
- package/dist/{chunk-SXGJL7UT.js → chunk-K376MPJH.js} +14 -14
- package/dist/{chunk-OSJ366KR.js → chunk-KEBVT55V.js} +30 -30
- package/dist/{chunk-U5UGM5XD.js → chunk-KFIZAXHI.js} +5 -5
- package/dist/{chunk-KFNZZ2N6.js → chunk-KKGRDBMK.js} +2 -2
- package/dist/{chunk-PLYVGZIN.js → chunk-KKIG6DN5.js} +1 -1
- package/dist/{chunk-3OK7Y6ES.js → chunk-KKQO2GAA.js} +2 -2
- package/dist/{chunk-DQPIEQGP.js → chunk-KO753ZCZ.js} +2 -2
- package/dist/{chunk-YNTLWCF4.js → chunk-KYIRWU65.js} +3 -3
- package/dist/{chunk-JKL5S7UQ.js → chunk-L6V63DVI.js} +6 -6
- package/dist/{chunk-M5IQVMLR.js → chunk-LAZ2QZTJ.js} +11 -4
- package/dist/chunk-LAZ2QZTJ.js.map +1 -0
- package/dist/{chunk-CV4VVLPZ.js → chunk-LCNJ2KNS.js} +2 -2
- package/dist/{chunk-D74Z2N4K.js → chunk-LE7YKMTU.js} +2 -2
- package/dist/{chunk-D5TIVCXG.js → chunk-LEBEOMVT.js} +2 -2
- package/dist/chunk-LKLQVANM.js +2 -0
- package/dist/{chunk-2OXSB2OL.js → chunk-LKWVBUH6.js} +3 -2
- package/dist/chunk-LKWVBUH6.js.map +1 -0
- package/dist/{chunk-WXF2RTS4.js → chunk-M6URPYUB.js} +2 -2
- package/dist/{chunk-H6BX6WOW.js → chunk-MDHFMRBC.js} +3 -3
- package/dist/{chunk-3CDJSKDW.js → chunk-MGZO7CHI.js} +3 -3
- package/dist/{chunk-DCEQCGVN.js → chunk-MIWU52TW.js} +2 -2
- package/dist/{chunk-PF2WU2IL.js → chunk-ND4IQJUM.js} +120 -17
- package/dist/chunk-ND4IQJUM.js.map +1 -0
- package/dist/{chunk-3PM3M2Q6.js → chunk-NDXBF3RW.js} +27 -11
- package/dist/chunk-NDXBF3RW.js.map +1 -0
- package/dist/{chunk-LVELUUK6.js → chunk-NF6QVVMP.js} +2 -2
- package/dist/{chunk-UMX6DZME.js → chunk-NTZ5ZNVK.js} +2 -2
- package/dist/{chunk-FBA2NXYH.js → chunk-NWLRABUR.js} +3 -3
- package/dist/{chunk-TNSJFZ6Q.js → chunk-O2H2U7YS.js} +4 -4
- package/dist/{chunk-BFFNINCC.js → chunk-OAL2PPX4.js} +3 -3
- package/dist/{chunk-WTSQUCHB.js → chunk-OCYTHZ4A.js} +3 -3
- package/dist/{chunk-ZAX4XQLN.js → chunk-OEDTCIXF.js} +2 -2
- package/dist/{chunk-CHU3RDV4.js → chunk-OLVSYB3P.js} +3 -3
- package/dist/{chunk-PZKHST7A.js → chunk-OQ6QOPK6.js} +10 -3
- package/dist/chunk-OQ6QOPK6.js.map +1 -0
- package/dist/{chunk-IFSXVU2S.js → chunk-OQHTFOCA.js} +2 -2
- package/dist/{chunk-OXQ2SXVC.js → chunk-P56AVROH.js} +2 -2
- package/dist/{chunk-CXAN2FHF.js → chunk-PCEJHHGP.js} +6 -6
- package/dist/{chunk-5MIBQ4P5.js → chunk-PHGQGVVL.js} +2 -2
- package/dist/{chunk-FLWQJDJ5.js → chunk-PUZRHEQI.js} +6 -6
- package/dist/{chunk-OP2GD6QW.js → chunk-PV7U6OOJ.js} +2 -2
- package/dist/{chunk-SPD4ULVB.js → chunk-PYMROAWS.js} +2 -1
- package/dist/chunk-PYMROAWS.js.map +1 -0
- package/dist/{chunk-X2QJXDE4.js → chunk-PZQACDH5.js} +8 -8
- package/dist/{chunk-CH4UQ4NO.js → chunk-PZTS4O6E.js} +5 -5
- package/dist/{chunk-TKQL7EDB.js → chunk-Q42QHUAQ.js} +2 -2
- package/dist/{chunk-MRECRNVU.js → chunk-QCYGB6TZ.js} +5 -5
- package/dist/{chunk-GSCGKJNK.js → chunk-QECMETOF.js} +2 -2
- package/dist/{chunk-RMCLFSMX.js → chunk-QGX3LE6H.js} +2 -2
- package/dist/{chunk-HTMQGS63.js → chunk-QI3NDQFP.js} +8 -8
- package/dist/{chunk-UU5FBVRX.js → chunk-QZE4BTLA.js} +6 -5
- package/dist/chunk-QZE4BTLA.js.map +1 -0
- package/dist/{chunk-R5QAL43H.js → chunk-RA3Q52O2.js} +2 -2
- package/dist/chunk-RBOHWUSN.js +151 -0
- package/dist/chunk-RBOHWUSN.js.map +1 -0
- package/dist/{chunk-AJDGP2N4.js → chunk-RJNOQEJJ.js} +20 -20
- package/dist/{chunk-477DTTMH.js → chunk-RSFOFUR7.js} +3 -3
- package/dist/{chunk-JV5ULONH.js → chunk-RXR6PMSH.js} +39 -39
- package/dist/{chunk-J2BTILRR.js → chunk-SM7HFCGC.js} +2 -2
- package/dist/{chunk-UTRNLNCW.js → chunk-SN6ZWYOP.js} +69 -97
- package/dist/chunk-SN6ZWYOP.js.map +1 -0
- package/dist/{chunk-OBGOLHCP.js → chunk-T4HK4XCI.js} +3 -3
- package/dist/{chunk-XVLEBB4Y.js → chunk-TBWL6YWL.js} +2 -2
- package/dist/{chunk-AAS7OWV6.js → chunk-TIDXYWFX.js} +3 -3
- package/dist/{chunk-N3FM4BNA.js → chunk-TKHRGY2P.js} +2 -2
- package/dist/{chunk-GU7T2S5N.js → chunk-TU2GSZL7.js} +2 -2
- package/dist/{chunk-OI6VI6SU.js → chunk-U6HGJXXQ.js} +8 -8
- package/dist/{chunk-4BWMAGJJ.js → chunk-UGRW6RTR.js} +3 -3
- package/dist/{chunk-AVXDIRRW.js → chunk-UMRUDYUK.js} +2 -2
- package/dist/{chunk-FNXCFIPW.js → chunk-UOT2R5ZD.js} +2 -2
- package/dist/{chunk-DIP7YALH.js → chunk-USURKJVT.js} +2 -2
- package/dist/{chunk-S27VZ5DO.js → chunk-UU6Q67XM.js} +6 -6
- package/dist/{chunk-LTJFV2JI.js → chunk-UZ7NP5CW.js} +2 -2
- package/dist/{chunk-H6MJFMHZ.js → chunk-V4FO7UOE.js} +3 -3
- package/dist/{chunk-RGR57NYY.js → chunk-V4ZOZRCW.js} +2 -2
- package/dist/{chunk-LQKVNREV.js → chunk-V57YMKQZ.js} +3 -3
- package/dist/{chunk-XZCCEKPW.js → chunk-VOIWZBY6.js} +6 -6
- package/dist/{chunk-E5KOWRDU.js → chunk-VPHPLPDA.js} +2 -2
- package/dist/{chunk-OGU73VUN.js → chunk-VUL4KPUU.js} +2 -2
- package/dist/{chunk-SFIXTOOJ.js → chunk-VWF6ILAR.js} +3 -3
- package/dist/{chunk-FER6EVIY.js → chunk-W54BHJO7.js} +2 -2
- package/dist/{chunk-34NV52R3.js → chunk-WCYE4BLC.js} +4 -4
- package/dist/{chunk-RISUROBM.js → chunk-WTV25ELY.js} +4 -4
- package/dist/{chunk-UO35OEOX.js → chunk-WZYGH7CN.js} +3 -3
- package/dist/{chunk-CEMSIU4Z.js → chunk-XG2RWUF7.js} +5 -5
- package/dist/chunk-XK72HZ4C.js +147 -0
- package/dist/chunk-XK72HZ4C.js.map +1 -0
- package/dist/{chunk-K3D7IQQP.js → chunk-XV7QOT7W.js} +6 -6
- package/dist/{chunk-GOCODNQS.js → chunk-XWECT3GX.js} +2 -2
- package/dist/{chunk-5MHMCE2G.js → chunk-XZQK2ZLW.js} +3 -3
- package/dist/{chunk-JV3UI7BH.js → chunk-Y5BR66OH.js} +3 -3
- package/dist/{chunk-VXORMNU4.js → chunk-YBHAAULA.js} +67 -2
- package/dist/chunk-YBHAAULA.js.map +1 -0
- package/dist/{chunk-4F3AEJI6.js → chunk-YD6XU6FY.js} +4 -4
- package/dist/{chunk-VATYK3JQ.js → chunk-YFE47G3C.js} +3 -3
- package/dist/{chunk-ZR5EKJT6.js → chunk-YG6TWPP7.js} +2 -2
- package/dist/{chunk-44JWVYJB.js → chunk-YH3ARKBB.js} +2 -2
- package/dist/{chunk-752WXSDN.js → chunk-YI66STKJ.js} +2 -2
- package/dist/{chunk-QRECBCJM.js → chunk-YMVPYMKB.js} +2 -2
- package/dist/{chunk-77SYIH6O.js → chunk-YPIXBAF6.js} +2 -2
- package/dist/{chunk-WRMUXZ7C.js → chunk-YSWPNY6G.js} +3 -3
- package/dist/{chunk-GTHCHCWW.js → chunk-YWNNMBZG.js} +3 -3
- package/dist/{chunk-3DRLCX5V.js → chunk-Z3HYM2JT.js} +2 -2
- package/dist/{chunk-M3HGBO2Y.js → chunk-ZAC7YPRA.js} +1 -1
- package/dist/{chunk-2VJOSU4H.js → chunk-ZENESDAF.js} +2 -2
- package/dist/{chunk-4JXPLTWV.js → chunk-ZHAPMETO.js} +2 -2
- package/dist/{chunk-IJR6VOLU.js → chunk-ZVR6DUZH.js} +2 -2
- package/dist/components/message-timeline.d.ts +10 -2
- package/dist/composer.js +8 -8
- package/dist/{computer-viewer-5LKRCEVQ.js → computer-viewer-FOIOZUF5.js} +5 -5
- package/dist/connect.js +12 -12
- package/dist/desktop-dictation.js +8 -8
- package/dist/desktop.js +2 -2
- package/dist/editor.js +2 -2
- package/dist/{embedded-new-voice-GHJRY3YL.js → embedded-new-voice-WTXAJNGO.js} +5 -5
- package/dist/{embedded-voice-ASQXBSTX.js → embedded-voice-SIJOPN2G.js} +5 -5
- package/dist/{fleet-decision-row-U7LDVBEM.js → fleet-decision-row-XKQ3GMYT.js} +2 -2
- package/dist/hooks/use-recordings.d.ts +4 -2
- package/dist/in-chat-connect-model.js +5 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +66 -60
- package/dist/interaction.js +5 -5
- package/dist/{latest-question-RNVF262Q.js → latest-question-KA7AQYVI.js} +2 -2
- package/dist/machines.js +3 -3
- package/dist/meetings/recorder-context.d.ts +6 -1
- package/dist/meetings/recorder-panel.d.ts +2 -5
- package/dist/meetings-recorder.js +1 -1
- package/dist/meetings.js +25 -23
- package/dist/meetings.js.map +1 -1
- package/dist/messages/en.d.ts +4 -0
- package/dist/messages.js +1 -1
- package/dist/{model-policy-picker-menu-E6XKMFTA.js → model-policy-picker-menu-6N2G7VGX.js} +4 -4
- package/dist/{payment-page-card-DJDKV2LW.js → payment-page-card-IJFZHQ52.js} +4 -4
- package/dist/{platform-activity-row-MSDCSMET.js → platform-activity-row-MFCMGI43.js} +2 -2
- package/dist/{queue-surface-implementation-GUAIG6TK.js → queue-surface-implementation-BBCDWWOP.js} +5 -5
- package/dist/realtime.js +4 -4
- package/dist/{recorder-host-2MYDJPQW.js → recorder-host-LDYYOKG7.js} +5 -5
- package/dist/recordings.js +4 -4
- package/dist/{sandbox-files-W5W2LW4K.js → sandbox-files-VYRBIXJY.js} +6 -6
- package/dist/session-app.js +160 -157
- package/dist/{session-connect-cards-HPH7JOZP.js → session-connect-cards-GBPSL6OT.js} +9 -9
- package/dist/session-connect-cards-GBPSL6OT.js.map +1 -0
- package/dist/session-list-model.js +2 -2
- package/dist/{session-realtime-SDTKFFIR.js → session-realtime-QGU57TND.js} +3 -3
- package/dist/session-realtime-QGU57TND.js.map +1 -0
- package/dist/session-realtime.js +2 -2
- package/dist/session-ui.js +33 -33
- package/dist/session.d.ts +3 -2
- package/dist/session.js +16 -10
- package/dist/sites.js +2 -2
- package/dist/terminal.js +2 -2
- package/dist/this-computer.js +3 -3
- package/dist/timeline/index.d.ts +3 -2
- package/dist/timeline/projection.d.ts +52 -0
- package/dist/timeline/turn-summary-model.d.ts +4 -3
- package/dist/timeline/types.d.ts +8 -2
- package/dist/timeline/use-timeline-pauses.d.ts +12 -0
- package/dist/timeline/work-presentation.d.ts +4 -3
- package/dist/{timeline-annotation-markers-FNILLWNU.js → timeline-annotation-markers-LL6ZVBZH.js} +2 -2
- package/dist/{timeline-annotation-selection-MBCIDO2Q.js → timeline-annotation-selection-WQA76WYC.js} +2 -2
- package/dist/{timeline-annotations-dialog-JPNKLOTE.js → timeline-annotations-dialog-HHETAEZA.js} +3 -3
- package/dist/timeline-model.js +2 -2
- package/dist/ui/access-list.js +5 -5
- package/dist/ui/cadence-picker.js +4 -4
- package/dist/ui/choice-cards.js +3 -3
- package/dist/ui/confirm-dialog.js +2 -2
- package/dist/ui/copy-field.js +3 -3
- package/dist/ui/detail-page.js +2 -2
- package/dist/ui/detail-sheet.js +2 -2
- package/dist/ui/disclosure.js +3 -3
- package/dist/ui/email-chips-input.js +3 -3
- package/dist/ui/field.js +2 -2
- package/dist/ui/flush-form-page.js +3 -3
- package/dist/ui/form-dialog.js +2 -2
- package/dist/ui/list-row.js +3 -3
- package/dist/ui/relative-time.js +2 -2
- package/dist/ui/revision-history.js +4 -4
- package/dist/ui/role-select.js +5 -5
- package/dist/ui/select-menu.js +3 -3
- package/dist/ui/usage-meter.d.ts +8 -2
- package/dist/ui/usage-meter.js +5 -3
- package/dist/usage.js +2 -2
- package/dist/workbench.js +4 -4
- package/package.json +6 -5
- package/src/app/components/agent/agent-capability-picker.test.tsx +1 -1
- package/src/app/components/models/subscription-usage.tsx +178 -0
- package/src/app/components/rail/session-row-content.tsx +27 -0
- package/src/app/components/session/subscription-account-indicator.test.ts +78 -18
- package/src/app/components/session/subscription-account-indicator.tsx +16 -31
- package/src/app/components/session/subscription-account-menu.tsx +79 -101
- package/src/app/components/session/subscription-account.test.ts +161 -54
- package/src/app/components/session/subscription-account.ts +106 -117
- package/src/app/lib/agent-capabilities.tsx +34 -7
- package/src/app/lib/session-branch-cache.tsx +1 -0
- package/src/app/lib/session-pins.tsx +1 -0
- package/src/app/lib/session-row-paused.test.tsx +183 -0
- package/src/app/lib/sessions-group-channels.test.ts +4 -4
- package/src/app/lib/sessions-group.tsx +62 -4
- package/src/app/lib/subscription-accounts.tsx +283 -0
- package/src/app/routes/session.tsx +2 -0
- package/src/components/message-timeline.tsx +14 -2
- package/src/components/session-conversation.tsx +2 -1
- package/src/components/timeline-annotations.tsx +4 -1
- package/src/components/timeline-settlement.ts +1 -1
- package/src/hooks/use-composer.ts +104 -25
- package/src/hooks/use-recordings.ts +5 -0
- package/src/index.ts +5 -0
- package/src/meetings/meeting-detail-page.tsx +4 -2
- package/src/meetings/meetings-pages.test.tsx +38 -0
- package/src/meetings/recorder-context.tsx +28 -5
- package/src/meetings/recorder-panel.tsx +13 -5
- package/src/meetings/recorder-workspace.test.tsx +57 -8
- package/src/messages/en.ts +5 -0
- package/src/recordings-model.ts +7 -0
- package/src/session.ts +8 -1
- package/src/timeline/index.ts +4 -1
- package/src/timeline/projection.ts +228 -16
- package/src/timeline/turn-summary-model.ts +4 -3
- package/src/timeline/turn-summary.tsx +15 -2
- package/src/timeline/types.ts +8 -2
- package/src/timeline/use-timeline-pauses.ts +105 -0
- package/src/timeline/work-presentation.ts +13 -4
- package/src/ui/usage-meter.tsx +10 -7
- package/styles/compiled.css +3 -0
- package/dist/chunk-2OXSB2OL.js.map +0 -1
- package/dist/chunk-3PM3M2Q6.js.map +0 -1
- package/dist/chunk-7YTR3UFO.js.map +0 -1
- package/dist/chunk-7Z76QP64.js.map +0 -1
- package/dist/chunk-JHZRAYI4.js.map +0 -1
- package/dist/chunk-M5IQVMLR.js.map +0 -1
- package/dist/chunk-NQ2CPQJF.js.map +0 -1
- package/dist/chunk-O2UPPN5M.js +0 -2
- package/dist/chunk-O4JOE3R7.js.map +0 -1
- package/dist/chunk-PF2WU2IL.js.map +0 -1
- package/dist/chunk-PSM3CU7N.js.map +0 -1
- package/dist/chunk-PZKHST7A.js.map +0 -1
- package/dist/chunk-Q5K2J5GG.js.map +0 -1
- package/dist/chunk-QPQ7R77C.js.map +0 -1
- package/dist/chunk-QQIZMVAJ.js.map +0 -1
- package/dist/chunk-SK5S2PCK.js.map +0 -1
- package/dist/chunk-SPD4ULVB.js.map +0 -1
- package/dist/chunk-UTRNLNCW.js.map +0 -1
- package/dist/chunk-UU5FBVRX.js.map +0 -1
- package/dist/chunk-VXORMNU4.js.map +0 -1
- package/dist/chunk-WYGTAQMX.js.map +0 -1
- /package/dist/{browser-viewer-ZHQDVHZ2.js.map → app/components/models/subscription-usage.js.map} +0 -0
- /package/dist/{chat-interactive-block-VSDD6X3M.js.map → app/lib/subscription-accounts.js.map} +0 -0
- /package/dist/{chunk-O2UPPN5M.js.map → browser-viewer-F4FL7JKB.js.map} +0 -0
- /package/dist/{computer-viewer-5LKRCEVQ.js.map → chat-interactive-block-4U5JWRSY.js.map} +0 -0
- /package/dist/{chunk-4K64EKM7.js.map → chunk-22YIIM3X.js.map} +0 -0
- /package/dist/{chunk-3NNAC43A.js.map → chunk-2N7ACQ7M.js.map} +0 -0
- /package/dist/{chunk-WDASYY4S.js.map → chunk-2TEYUDJD.js.map} +0 -0
- /package/dist/{chunk-OTW25A6I.js.map → chunk-37JJQNZB.js.map} +0 -0
- /package/dist/{chunk-VCJQQYRE.js.map → chunk-3DWQPURZ.js.map} +0 -0
- /package/dist/{chunk-GTRAH4FG.js.map → chunk-3GWC3FU3.js.map} +0 -0
- /package/dist/{chunk-AB5IW227.js.map → chunk-3ICY6LP3.js.map} +0 -0
- /package/dist/{chunk-WIFDNUKD.js.map → chunk-3OCU5RX5.js.map} +0 -0
- /package/dist/{chunk-UBRQ3PQD.js.map → chunk-3SPDJLOR.js.map} +0 -0
- /package/dist/{chunk-IZXYFWA4.js.map → chunk-3WVLR7UA.js.map} +0 -0
- /package/dist/{chunk-DEHLWZSI.js.map → chunk-3XMB3L57.js.map} +0 -0
- /package/dist/{chunk-AJBDAVX3.js.map → chunk-4IUOBO2H.js.map} +0 -0
- /package/dist/{chunk-NFCS5WYC.js.map → chunk-4KQ3A3EO.js.map} +0 -0
- /package/dist/{chunk-LIJNVIT3.js.map → chunk-4L5B5AZT.js.map} +0 -0
- /package/dist/{chunk-EDDKPIIV.js.map → chunk-4NB3TPNE.js.map} +0 -0
- /package/dist/{chunk-OJWDNNW3.js.map → chunk-4TPTGBIO.js.map} +0 -0
- /package/dist/{chunk-J2WY42FA.js.map → chunk-4UHGW6WF.js.map} +0 -0
- /package/dist/{chunk-7NLF35YL.js.map → chunk-4YN2JLYK.js.map} +0 -0
- /package/dist/{chunk-OOOSGPJL.js.map → chunk-53MYEEMA.js.map} +0 -0
- /package/dist/{chunk-467WDSOK.js.map → chunk-5HYWXPMA.js.map} +0 -0
- /package/dist/{chunk-XMBOLFFS.js.map → chunk-5IMNL6IV.js.map} +0 -0
- /package/dist/{chunk-4Z5X7PLC.js.map → chunk-5MLM5T5C.js.map} +0 -0
- /package/dist/{chunk-YMI27QPF.js.map → chunk-5NKQZVXP.js.map} +0 -0
- /package/dist/{chunk-CYDXCILL.js.map → chunk-5SODSGW7.js.map} +0 -0
- /package/dist/{chunk-Q5EZNBPI.js.map → chunk-5YAJASCO.js.map} +0 -0
- /package/dist/{chunk-M3FDGRB4.js.map → chunk-62XAL5BA.js.map} +0 -0
- /package/dist/{chunk-SGH7I7OY.js.map → chunk-67R6NAFI.js.map} +0 -0
- /package/dist/{chunk-PYB4BFEC.js.map → chunk-6BQLDL6R.js.map} +0 -0
- /package/dist/{chunk-YJSCLGAW.js.map → chunk-6EZYHJTL.js.map} +0 -0
- /package/dist/{chunk-G5UQBTXY.js.map → chunk-6LXIL3Q3.js.map} +0 -0
- /package/dist/{chunk-T67LTMSW.js.map → chunk-6LYVAJFZ.js.map} +0 -0
- /package/dist/{chunk-3L465FBR.js.map → chunk-6WB5UXMZ.js.map} +0 -0
- /package/dist/{chunk-EKJHOWTZ.js.map → chunk-74UGYVCA.js.map} +0 -0
- /package/dist/{chunk-PWUSSSSL.js.map → chunk-7BTNYZC7.js.map} +0 -0
- /package/dist/{chunk-ESXAECZ3.js.map → chunk-7KZFGA25.js.map} +0 -0
- /package/dist/{chunk-EGKARC53.js.map → chunk-7MGDX2TD.js.map} +0 -0
- /package/dist/{chunk-Y3XZEKDQ.js.map → chunk-7N3GFGB6.js.map} +0 -0
- /package/dist/{chunk-AH3DGOTK.js.map → chunk-7SFSN6AX.js.map} +0 -0
- /package/dist/{chunk-6QK65ZWM.js.map → chunk-7TGUHFGO.js.map} +0 -0
- /package/dist/{chunk-QURYQFDN.js.map → chunk-7ZIWO65F.js.map} +0 -0
- /package/dist/{chunk-OYCK4JRS.js.map → chunk-AJHLEJTK.js.map} +0 -0
- /package/dist/{chunk-3PZ3LRPV.js.map → chunk-AN4U7EPH.js.map} +0 -0
- /package/dist/{chunk-77BHKC43.js.map → chunk-APG6CEG7.js.map} +0 -0
- /package/dist/{chunk-FSDQQQIA.js.map → chunk-APHLXQNP.js.map} +0 -0
- /package/dist/{chunk-SN2WENRP.js.map → chunk-AXHQ7QXV.js.map} +0 -0
- /package/dist/{chunk-54U6ZBEX.js.map → chunk-AYTLSPF6.js.map} +0 -0
- /package/dist/{chunk-R33SBMB7.js.map → chunk-BBSKKBMV.js.map} +0 -0
- /package/dist/{chunk-2GCHGWNE.js.map → chunk-BGH6TU2P.js.map} +0 -0
- /package/dist/{chunk-D3PTVN2I.js.map → chunk-BGIYL26H.js.map} +0 -0
- /package/dist/{chunk-BQYRZIZ7.js.map → chunk-BL7UQUC3.js.map} +0 -0
- /package/dist/{chunk-EBTUPRRQ.js.map → chunk-BOUHCYL6.js.map} +0 -0
- /package/dist/{chunk-MKDFYE2E.js.map → chunk-BVNGDFBC.js.map} +0 -0
- /package/dist/{chunk-ICAMYP5M.js.map → chunk-BWJK64CP.js.map} +0 -0
- /package/dist/{chunk-RHXYO4H2.js.map → chunk-BZ2GTCQV.js.map} +0 -0
- /package/dist/{chunk-GIWFLWXG.js.map → chunk-C2KASMJK.js.map} +0 -0
- /package/dist/{chunk-KO3OHHY2.js.map → chunk-CAZDRDQT.js.map} +0 -0
- /package/dist/{chunk-OK7BQMCI.js.map → chunk-CBJRZKZB.js.map} +0 -0
- /package/dist/{chunk-OYOFPNLC.js.map → chunk-CF6NYG7J.js.map} +0 -0
- /package/dist/{chunk-MT2R57SF.js.map → chunk-COITN7WN.js.map} +0 -0
- /package/dist/{chunk-OCXTTKVA.js.map → chunk-CPVOXM2Q.js.map} +0 -0
- /package/dist/{chunk-HYEIA25Y.js.map → chunk-CTZRCBKH.js.map} +0 -0
- /package/dist/{chunk-OCXEY7HE.js.map → chunk-CWL27YTB.js.map} +0 -0
- /package/dist/{chunk-K4DQS2ML.js.map → chunk-D2I33V5P.js.map} +0 -0
- /package/dist/{chunk-736RUNIA.js.map → chunk-DF7WI4JH.js.map} +0 -0
- /package/dist/{chunk-KUE5BOQE.js.map → chunk-DKZYCJCO.js.map} +0 -0
- /package/dist/{chunk-74CBR5YE.js.map → chunk-DQ32FKFQ.js.map} +0 -0
- /package/dist/{chunk-4O2XWOLZ.js.map → chunk-DTKG2YUF.js.map} +0 -0
- /package/dist/{chunk-GMHIOYB7.js.map → chunk-DUDA4V5R.js.map} +0 -0
- /package/dist/{chunk-XUOYNJPB.js.map → chunk-ECROT4M5.js.map} +0 -0
- /package/dist/{chunk-PVB4YVDP.js.map → chunk-EOXV5XGY.js.map} +0 -0
- /package/dist/{chunk-U6552Q3T.js.map → chunk-EQQOZ6DD.js.map} +0 -0
- /package/dist/{chunk-G6ICCGJ3.js.map → chunk-EY6W5H4B.js.map} +0 -0
- /package/dist/{chunk-HWVPLFIW.js.map → chunk-EYRFEWXJ.js.map} +0 -0
- /package/dist/{chunk-U4LTPFD2.js.map → chunk-FKK2PD7K.js.map} +0 -0
- /package/dist/{chunk-PUUEI4W3.js.map → chunk-FPHHIC5K.js.map} +0 -0
- /package/dist/{chunk-SP44O3OU.js.map → chunk-FQM6L22H.js.map} +0 -0
- /package/dist/{chunk-2J77TWGH.js.map → chunk-FW22IREV.js.map} +0 -0
- /package/dist/{chunk-EBIVTDEG.js.map → chunk-G4M6AYDB.js.map} +0 -0
- /package/dist/{chunk-BASI553K.js.map → chunk-G6AZ2WIU.js.map} +0 -0
- /package/dist/{chunk-SJYTQLN3.js.map → chunk-GJ5IDSAX.js.map} +0 -0
- /package/dist/{chunk-TDTD66BK.js.map → chunk-GRDSEZWZ.js.map} +0 -0
- /package/dist/{chunk-MV2CLIO6.js.map → chunk-HBVJIGY2.js.map} +0 -0
- /package/dist/{chunk-R4JA5JFI.js.map → chunk-HCWQLIOE.js.map} +0 -0
- /package/dist/{chunk-MZY3VKKM.js.map → chunk-HEVD4A5G.js.map} +0 -0
- /package/dist/{chunk-DLVIRJGK.js.map → chunk-HNDHSEVJ.js.map} +0 -0
- /package/dist/{chunk-LPKJ77EK.js.map → chunk-HNTZ7B7M.js.map} +0 -0
- /package/dist/{chunk-IN3VQFKS.js.map → chunk-I2FC7CAI.js.map} +0 -0
- /package/dist/{chunk-ZBHGNE2J.js.map → chunk-IEHZFYMH.js.map} +0 -0
- /package/dist/{chunk-DWJ6J3YW.js.map → chunk-IXISEVD7.js.map} +0 -0
- /package/dist/{chunk-TK5FWVZR.js.map → chunk-IZEDVQUD.js.map} +0 -0
- /package/dist/{chunk-HEGV4QMS.js.map → chunk-J42QE4VO.js.map} +0 -0
- /package/dist/{chunk-PRT4J2DL.js.map → chunk-J555XSUM.js.map} +0 -0
- /package/dist/{chunk-SBXSKRFA.js.map → chunk-JNMHFSDF.js.map} +0 -0
- /package/dist/{chunk-KI46GKMD.js.map → chunk-JTBAOPYO.js.map} +0 -0
- /package/dist/{chunk-SXGJL7UT.js.map → chunk-K376MPJH.js.map} +0 -0
- /package/dist/{chunk-OSJ366KR.js.map → chunk-KEBVT55V.js.map} +0 -0
- /package/dist/{chunk-U5UGM5XD.js.map → chunk-KFIZAXHI.js.map} +0 -0
- /package/dist/{chunk-KFNZZ2N6.js.map → chunk-KKGRDBMK.js.map} +0 -0
- /package/dist/{chunk-PLYVGZIN.js.map → chunk-KKIG6DN5.js.map} +0 -0
- /package/dist/{chunk-3OK7Y6ES.js.map → chunk-KKQO2GAA.js.map} +0 -0
- /package/dist/{chunk-DQPIEQGP.js.map → chunk-KO753ZCZ.js.map} +0 -0
- /package/dist/{chunk-YNTLWCF4.js.map → chunk-KYIRWU65.js.map} +0 -0
- /package/dist/{chunk-JKL5S7UQ.js.map → chunk-L6V63DVI.js.map} +0 -0
- /package/dist/{chunk-CV4VVLPZ.js.map → chunk-LCNJ2KNS.js.map} +0 -0
- /package/dist/{chunk-D74Z2N4K.js.map → chunk-LE7YKMTU.js.map} +0 -0
- /package/dist/{chunk-D5TIVCXG.js.map → chunk-LEBEOMVT.js.map} +0 -0
- /package/dist/{embedded-new-voice-GHJRY3YL.js.map → chunk-LKLQVANM.js.map} +0 -0
- /package/dist/{chunk-WXF2RTS4.js.map → chunk-M6URPYUB.js.map} +0 -0
- /package/dist/{chunk-H6BX6WOW.js.map → chunk-MDHFMRBC.js.map} +0 -0
- /package/dist/{chunk-3CDJSKDW.js.map → chunk-MGZO7CHI.js.map} +0 -0
- /package/dist/{chunk-DCEQCGVN.js.map → chunk-MIWU52TW.js.map} +0 -0
- /package/dist/{chunk-LVELUUK6.js.map → chunk-NF6QVVMP.js.map} +0 -0
- /package/dist/{chunk-UMX6DZME.js.map → chunk-NTZ5ZNVK.js.map} +0 -0
- /package/dist/{chunk-FBA2NXYH.js.map → chunk-NWLRABUR.js.map} +0 -0
- /package/dist/{chunk-TNSJFZ6Q.js.map → chunk-O2H2U7YS.js.map} +0 -0
- /package/dist/{chunk-BFFNINCC.js.map → chunk-OAL2PPX4.js.map} +0 -0
- /package/dist/{chunk-WTSQUCHB.js.map → chunk-OCYTHZ4A.js.map} +0 -0
- /package/dist/{chunk-ZAX4XQLN.js.map → chunk-OEDTCIXF.js.map} +0 -0
- /package/dist/{chunk-CHU3RDV4.js.map → chunk-OLVSYB3P.js.map} +0 -0
- /package/dist/{chunk-IFSXVU2S.js.map → chunk-OQHTFOCA.js.map} +0 -0
- /package/dist/{chunk-OXQ2SXVC.js.map → chunk-P56AVROH.js.map} +0 -0
- /package/dist/{chunk-CXAN2FHF.js.map → chunk-PCEJHHGP.js.map} +0 -0
- /package/dist/{chunk-5MIBQ4P5.js.map → chunk-PHGQGVVL.js.map} +0 -0
- /package/dist/{chunk-FLWQJDJ5.js.map → chunk-PUZRHEQI.js.map} +0 -0
- /package/dist/{chunk-OP2GD6QW.js.map → chunk-PV7U6OOJ.js.map} +0 -0
- /package/dist/{chunk-X2QJXDE4.js.map → chunk-PZQACDH5.js.map} +0 -0
- /package/dist/{chunk-CH4UQ4NO.js.map → chunk-PZTS4O6E.js.map} +0 -0
- /package/dist/{chunk-TKQL7EDB.js.map → chunk-Q42QHUAQ.js.map} +0 -0
- /package/dist/{chunk-MRECRNVU.js.map → chunk-QCYGB6TZ.js.map} +0 -0
- /package/dist/{chunk-GSCGKJNK.js.map → chunk-QECMETOF.js.map} +0 -0
- /package/dist/{chunk-RMCLFSMX.js.map → chunk-QGX3LE6H.js.map} +0 -0
- /package/dist/{chunk-HTMQGS63.js.map → chunk-QI3NDQFP.js.map} +0 -0
- /package/dist/{chunk-R5QAL43H.js.map → chunk-RA3Q52O2.js.map} +0 -0
- /package/dist/{chunk-AJDGP2N4.js.map → chunk-RJNOQEJJ.js.map} +0 -0
- /package/dist/{chunk-477DTTMH.js.map → chunk-RSFOFUR7.js.map} +0 -0
- /package/dist/{chunk-JV5ULONH.js.map → chunk-RXR6PMSH.js.map} +0 -0
- /package/dist/{chunk-J2BTILRR.js.map → chunk-SM7HFCGC.js.map} +0 -0
- /package/dist/{chunk-OBGOLHCP.js.map → chunk-T4HK4XCI.js.map} +0 -0
- /package/dist/{chunk-XVLEBB4Y.js.map → chunk-TBWL6YWL.js.map} +0 -0
- /package/dist/{chunk-AAS7OWV6.js.map → chunk-TIDXYWFX.js.map} +0 -0
- /package/dist/{chunk-N3FM4BNA.js.map → chunk-TKHRGY2P.js.map} +0 -0
- /package/dist/{chunk-GU7T2S5N.js.map → chunk-TU2GSZL7.js.map} +0 -0
- /package/dist/{chunk-OI6VI6SU.js.map → chunk-U6HGJXXQ.js.map} +0 -0
- /package/dist/{chunk-4BWMAGJJ.js.map → chunk-UGRW6RTR.js.map} +0 -0
- /package/dist/{chunk-AVXDIRRW.js.map → chunk-UMRUDYUK.js.map} +0 -0
- /package/dist/{chunk-FNXCFIPW.js.map → chunk-UOT2R5ZD.js.map} +0 -0
- /package/dist/{chunk-DIP7YALH.js.map → chunk-USURKJVT.js.map} +0 -0
- /package/dist/{chunk-S27VZ5DO.js.map → chunk-UU6Q67XM.js.map} +0 -0
- /package/dist/{chunk-LTJFV2JI.js.map → chunk-UZ7NP5CW.js.map} +0 -0
- /package/dist/{chunk-H6MJFMHZ.js.map → chunk-V4FO7UOE.js.map} +0 -0
- /package/dist/{chunk-RGR57NYY.js.map → chunk-V4ZOZRCW.js.map} +0 -0
- /package/dist/{chunk-LQKVNREV.js.map → chunk-V57YMKQZ.js.map} +0 -0
- /package/dist/{chunk-XZCCEKPW.js.map → chunk-VOIWZBY6.js.map} +0 -0
- /package/dist/{chunk-E5KOWRDU.js.map → chunk-VPHPLPDA.js.map} +0 -0
- /package/dist/{chunk-OGU73VUN.js.map → chunk-VUL4KPUU.js.map} +0 -0
- /package/dist/{chunk-SFIXTOOJ.js.map → chunk-VWF6ILAR.js.map} +0 -0
- /package/dist/{chunk-FER6EVIY.js.map → chunk-W54BHJO7.js.map} +0 -0
- /package/dist/{chunk-34NV52R3.js.map → chunk-WCYE4BLC.js.map} +0 -0
- /package/dist/{chunk-RISUROBM.js.map → chunk-WTV25ELY.js.map} +0 -0
- /package/dist/{chunk-UO35OEOX.js.map → chunk-WZYGH7CN.js.map} +0 -0
- /package/dist/{chunk-CEMSIU4Z.js.map → chunk-XG2RWUF7.js.map} +0 -0
- /package/dist/{chunk-K3D7IQQP.js.map → chunk-XV7QOT7W.js.map} +0 -0
- /package/dist/{chunk-GOCODNQS.js.map → chunk-XWECT3GX.js.map} +0 -0
- /package/dist/{chunk-5MHMCE2G.js.map → chunk-XZQK2ZLW.js.map} +0 -0
- /package/dist/{chunk-JV3UI7BH.js.map → chunk-Y5BR66OH.js.map} +0 -0
- /package/dist/{chunk-4F3AEJI6.js.map → chunk-YD6XU6FY.js.map} +0 -0
- /package/dist/{chunk-VATYK3JQ.js.map → chunk-YFE47G3C.js.map} +0 -0
- /package/dist/{chunk-ZR5EKJT6.js.map → chunk-YG6TWPP7.js.map} +0 -0
- /package/dist/{chunk-44JWVYJB.js.map → chunk-YH3ARKBB.js.map} +0 -0
- /package/dist/{chunk-752WXSDN.js.map → chunk-YI66STKJ.js.map} +0 -0
- /package/dist/{chunk-QRECBCJM.js.map → chunk-YMVPYMKB.js.map} +0 -0
- /package/dist/{chunk-77SYIH6O.js.map → chunk-YPIXBAF6.js.map} +0 -0
- /package/dist/{chunk-WRMUXZ7C.js.map → chunk-YSWPNY6G.js.map} +0 -0
- /package/dist/{chunk-GTHCHCWW.js.map → chunk-YWNNMBZG.js.map} +0 -0
- /package/dist/{chunk-3DRLCX5V.js.map → chunk-Z3HYM2JT.js.map} +0 -0
- /package/dist/{chunk-M3HGBO2Y.js.map → chunk-ZAC7YPRA.js.map} +0 -0
- /package/dist/{chunk-2VJOSU4H.js.map → chunk-ZENESDAF.js.map} +0 -0
- /package/dist/{chunk-4JXPLTWV.js.map → chunk-ZHAPMETO.js.map} +0 -0
- /package/dist/{chunk-IJR6VOLU.js.map → chunk-ZVR6DUZH.js.map} +0 -0
- /package/dist/{embedded-voice-ASQXBSTX.js.map → computer-viewer-FOIOZUF5.js.map} +0 -0
- /package/dist/{model-policy-picker-menu-E6XKMFTA.js.map → embedded-new-voice-WTXAJNGO.js.map} +0 -0
- /package/dist/{sandbox-files-W5W2LW4K.js.map → embedded-voice-SIJOPN2G.js.map} +0 -0
- /package/dist/{fleet-decision-row-U7LDVBEM.js.map → fleet-decision-row-XKQ3GMYT.js.map} +0 -0
- /package/dist/{latest-question-RNVF262Q.js.map → latest-question-KA7AQYVI.js.map} +0 -0
- /package/dist/{session-connect-cards-HPH7JOZP.js.map → model-policy-picker-menu-6N2G7VGX.js.map} +0 -0
- /package/dist/{payment-page-card-DJDKV2LW.js.map → payment-page-card-IJFZHQ52.js.map} +0 -0
- /package/dist/{platform-activity-row-MSDCSMET.js.map → platform-activity-row-MFCMGI43.js.map} +0 -0
- /package/dist/{queue-surface-implementation-GUAIG6TK.js.map → queue-surface-implementation-BBCDWWOP.js.map} +0 -0
- /package/dist/{recorder-host-2MYDJPQW.js.map → recorder-host-LDYYOKG7.js.map} +0 -0
- /package/dist/{session-realtime-SDTKFFIR.js.map → sandbox-files-VYRBIXJY.js.map} +0 -0
- /package/dist/{timeline-annotation-markers-FNILLWNU.js.map → timeline-annotation-markers-LL6ZVBZH.js.map} +0 -0
- /package/dist/{timeline-annotation-selection-MBCIDO2Q.js.map → timeline-annotation-selection-WQA76WYC.js.map} +0 -0
- /package/dist/{timeline-annotations-dialog-JPNKLOTE.js.map → timeline-annotations-dialog-HHETAEZA.js.map} +0 -0
|
@@ -81,10 +81,11 @@ export type TurnSummaryOptions = Readonly<{
|
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* Exchange status shown in place of the plain facet line. `working` and
|
|
84
|
-
* `waiting` run a live clock from `since`; `worked` shows the settled span
|
|
84
|
+
* `waiting` run a live clock from `since`; `worked` shows the settled span;
|
|
85
|
+
* `paused` shows the work done before the pause, with its clock stopped.
|
|
85
86
|
*/
|
|
86
87
|
export type TurnSummaryStatus = Readonly<{
|
|
87
|
-
kind: "working" | "waiting" | "worked";
|
|
88
|
+
kind: "working" | "waiting" | "worked" | "paused";
|
|
88
89
|
/** Replaces the default "Working" / "Waiting" wording. */
|
|
89
90
|
label?: string | undefined;
|
|
90
91
|
/** Who the wait is on: `you` when it needs the reader. */
|
|
@@ -93,7 +94,7 @@ export type TurnSummaryStatus = Readonly<{
|
|
|
93
94
|
updates?: number | undefined;
|
|
94
95
|
/** Live clock start for `working` and `waiting`. */
|
|
95
96
|
since?: string | undefined;
|
|
96
|
-
/** Settled span for `worked`. */
|
|
97
|
+
/** Settled span for `worked`; work done before the pause for `paused`. */
|
|
97
98
|
durationMs?: number | undefined;
|
|
98
99
|
/** Live step preview under the row while it is collapsed. */
|
|
99
100
|
preview?: ReactNode;
|
|
@@ -597,8 +597,9 @@ export function TurnSummary({
|
|
|
597
597
|
}
|
|
598
598
|
|
|
599
599
|
/**
|
|
600
|
-
* "Working · 2m 14s", "Waiting for 2 agents · 3m 5s",
|
|
601
|
-
* null when a settled span is too
|
|
600
|
+
* "Working · 2m 14s", "Waiting for 2 agents · 3m 5s", "Paused · 2m 14s" (its
|
|
601
|
+
* clock stopped), or "Worked for 4m 10s"; null when a settled span is too
|
|
602
|
+
* short to state.
|
|
602
603
|
*/
|
|
603
604
|
function turnSummaryStatusLine(t: OpenGeniText, status: TurnSummaryStatus): ReactNode {
|
|
604
605
|
if (status.kind === "worked") {
|
|
@@ -610,6 +611,18 @@ function turnSummaryStatusLine(t: OpenGeniText, status: TurnSummaryStatus): Reac
|
|
|
610
611
|
</span>
|
|
611
612
|
) : null;
|
|
612
613
|
}
|
|
614
|
+
if (status.kind === "paused") {
|
|
615
|
+
return (
|
|
616
|
+
<span data-og-exchange-status="paused">
|
|
617
|
+
{status.label ?? t("timeline.turnSummary.paused")}
|
|
618
|
+
{status.durationMs !== undefined &&
|
|
619
|
+
Number.isFinite(status.durationMs) &&
|
|
620
|
+
status.durationMs >= 1000 ? (
|
|
621
|
+
<span className="tabular-nums">{` · ${formatElapsed(t, status.durationMs)}`}</span>
|
|
622
|
+
) : null}
|
|
623
|
+
</span>
|
|
624
|
+
);
|
|
625
|
+
}
|
|
613
626
|
const label =
|
|
614
627
|
status.label ??
|
|
615
628
|
(status.kind === "working"
|
package/src/timeline/types.ts
CHANGED
|
@@ -782,10 +782,16 @@ export type TimelineGroup =
|
|
|
782
782
|
/**
|
|
783
783
|
* Settled time inside this work span in which the agent was not
|
|
784
784
|
* working: capacity waits, and the gap between a failed attempt and
|
|
785
|
-
* the Retry that reopened the turn. The worked
|
|
786
|
-
* working clock exclude it.
|
|
785
|
+
* the Retry that reopened the turn, and settled pauses. The worked
|
|
786
|
+
* duration and the live working clock exclude it.
|
|
787
787
|
*/
|
|
788
788
|
pausedMs?: number;
|
|
789
|
+
/**
|
|
790
|
+
* Set while a pause is in force over this still-open turn: when it
|
|
791
|
+
* began. Pause parks the turn for Resume, so it reads as paused with
|
|
792
|
+
* its clock stopped here, not as working.
|
|
793
|
+
*/
|
|
794
|
+
pausedAt?: string;
|
|
789
795
|
details: TimelineGroup[];
|
|
790
796
|
/**
|
|
791
797
|
* While the turn is live, its progress notes stay readable above the
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { SessionEvent } from "@opengeni/sdk";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { timelinePauseSpans, type TimelineLivePause, type TimelinePauseSpan } from "./projection";
|
|
4
|
+
|
|
5
|
+
/** At most this many pauses seen only through the live control are kept. */
|
|
6
|
+
const OBSERVED_PAUSE_LIMIT = 20;
|
|
7
|
+
|
|
8
|
+
type LivePauseHistory = {
|
|
9
|
+
sessionId: string | null;
|
|
10
|
+
/** The live pause as last rendered; undefined while it is unknown. */
|
|
11
|
+
live: boolean | undefined;
|
|
12
|
+
/** The last known pause state: a brief unknown does not forget a pause. */
|
|
13
|
+
paused: boolean | undefined;
|
|
14
|
+
/** When the pause in force began, as best known. */
|
|
15
|
+
since: string | null;
|
|
16
|
+
/** When this view saw the latest pause end. */
|
|
17
|
+
resumedAt: string | null;
|
|
18
|
+
/** Pauses this view saw begin and end. */
|
|
19
|
+
observed: TimelinePauseSpan[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function nextHistory(
|
|
23
|
+
previous: LivePauseHistory | null,
|
|
24
|
+
sessionId: string | null,
|
|
25
|
+
paused: boolean | undefined,
|
|
26
|
+
since: string | null,
|
|
27
|
+
now: string,
|
|
28
|
+
): LivePauseHistory {
|
|
29
|
+
if (!previous || previous.sessionId !== sessionId) {
|
|
30
|
+
return {
|
|
31
|
+
sessionId,
|
|
32
|
+
live: paused,
|
|
33
|
+
paused,
|
|
34
|
+
since: paused ? (since ?? now) : null,
|
|
35
|
+
resumedAt: null,
|
|
36
|
+
observed: [],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (paused === undefined) return { ...previous, live: paused };
|
|
40
|
+
if (previous.paused === true && paused === false) {
|
|
41
|
+
return {
|
|
42
|
+
...previous,
|
|
43
|
+
live: paused,
|
|
44
|
+
paused,
|
|
45
|
+
since: null,
|
|
46
|
+
resumedAt: now,
|
|
47
|
+
observed: [...previous.observed, { startedAt: previous.since ?? now, endedAt: now }].slice(
|
|
48
|
+
-OBSERVED_PAUSE_LIMIT,
|
|
49
|
+
),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (paused === true && previous.paused !== true) {
|
|
53
|
+
return { ...previous, live: paused, paused, since: since ?? now, resumedAt: null };
|
|
54
|
+
}
|
|
55
|
+
return { ...previous, live: paused, paused };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The session's pause spans for `groupTimeline`, from its events and its live
|
|
60
|
+
* pause (`timelineLivePause(session.effectiveControl)`).
|
|
61
|
+
*
|
|
62
|
+
* A pause that held a waiting turn, or an ancestor's pause of a turn it did
|
|
63
|
+
* not interrupt, leaves no events, so this view remembers the pauses it saw
|
|
64
|
+
* through the live control. It also notes the moment it saw a pause end, so
|
|
65
|
+
* the paused time never counts as work while the resume's events arrive.
|
|
66
|
+
*/
|
|
67
|
+
export function useTimelinePauses(
|
|
68
|
+
events: readonly SessionEvent[] | undefined,
|
|
69
|
+
pause: TimelineLivePause | null | undefined,
|
|
70
|
+
enabled = true,
|
|
71
|
+
): TimelinePauseSpan[] {
|
|
72
|
+
const paused = pause?.paused;
|
|
73
|
+
const since = pause?.since ?? null;
|
|
74
|
+
const sessionId = events?.[0]?.sessionId ?? null;
|
|
75
|
+
const [stored, setStored] = useState<LivePauseHistory | null>(null);
|
|
76
|
+
let history = stored;
|
|
77
|
+
if (!history || history.sessionId !== sessionId || history.live !== paused) {
|
|
78
|
+
// Derived during render so the first render after a flip is already right.
|
|
79
|
+
history = nextHistory(stored, sessionId, paused, since, new Date().toISOString());
|
|
80
|
+
setStored(history);
|
|
81
|
+
}
|
|
82
|
+
// While the control is briefly unknown, the last known pause stays in force.
|
|
83
|
+
const livePaused = paused ?? (history.paused === true ? true : undefined);
|
|
84
|
+
const historySince = history.since;
|
|
85
|
+
const historyResumedAt = history.resumedAt;
|
|
86
|
+
const observed = history.observed;
|
|
87
|
+
const resumedAt = pause?.resumedAt ?? null;
|
|
88
|
+
return useMemo(
|
|
89
|
+
() =>
|
|
90
|
+
enabled
|
|
91
|
+
? timelinePauseSpans(
|
|
92
|
+
events ?? [],
|
|
93
|
+
livePaused === undefined
|
|
94
|
+
? undefined
|
|
95
|
+
: {
|
|
96
|
+
paused: livePaused,
|
|
97
|
+
since: since ?? historySince,
|
|
98
|
+
resumedAt: resumedAt ?? historyResumedAt,
|
|
99
|
+
},
|
|
100
|
+
observed,
|
|
101
|
+
)
|
|
102
|
+
: [],
|
|
103
|
+
[enabled, events, livePaused, since, historySince, resumedAt, historyResumedAt, observed],
|
|
104
|
+
);
|
|
105
|
+
}
|
|
@@ -92,6 +92,7 @@ export function isPreparingWork(group: ActivityGroup, options: ReadableWorkOptio
|
|
|
92
92
|
!options.startupDismissed &&
|
|
93
93
|
!group.work.endedAt &&
|
|
94
94
|
!group.work.waiting &&
|
|
95
|
+
!group.work.pausedAt &&
|
|
95
96
|
phases.length > 0 &&
|
|
96
97
|
group.items.every(
|
|
97
98
|
(item) => item.kind === "startup-phase" || (item.kind === "reasoning" && !item.text.trim()),
|
|
@@ -132,9 +133,10 @@ export function readableWorkHasDetails(
|
|
|
132
133
|
/**
|
|
133
134
|
* Status of a readable turn's work row, minus the host-rendered live preview.
|
|
134
135
|
* Time spent waiting for model capacity, or between a failed attempt and its
|
|
135
|
-
* Retry, is not work: the worked duration and the live working
|
|
136
|
-
* it, and a capacity wait itself shows no clock. A
|
|
137
|
-
*
|
|
136
|
+
* Retry, or paused, is not work: the worked duration and the live working
|
|
137
|
+
* clock exclude it, and a capacity wait itself shows no clock. A turn parked
|
|
138
|
+
* by a pause still in force reads as paused, its clock stopped where the
|
|
139
|
+
* pause began. A wait's `detail` is its one quiet secondary line.
|
|
138
140
|
*/
|
|
139
141
|
export function readableWorkStatus(
|
|
140
142
|
t: OpenGeniText,
|
|
@@ -157,8 +159,15 @@ export function readableWorkStatus(
|
|
|
157
159
|
durationMs: durationMs === undefined ? undefined : Math.max(0, durationMs - pausedMs),
|
|
158
160
|
};
|
|
159
161
|
}
|
|
162
|
+
if (group.work.pausedAt) {
|
|
163
|
+
const durationMs = durationBetween(group.work.startedAt, group.work.pausedAt);
|
|
164
|
+
return {
|
|
165
|
+
kind: "paused",
|
|
166
|
+
durationMs: durationMs === undefined ? undefined : Math.max(0, durationMs - pausedMs),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
160
169
|
if (group.work.waiting) {
|
|
161
|
-
const { untimed, since, ...waiting } = group.work.waiting;
|
|
170
|
+
const { untimed, since, waitingOn: _waitingOn, ...waiting } = group.work.waiting;
|
|
162
171
|
return { kind: "waiting", ...waiting, ...(untimed ? {} : { since }) };
|
|
163
172
|
}
|
|
164
173
|
const started = Date.parse(group.work.startedAt);
|
package/src/ui/usage-meter.tsx
CHANGED
|
@@ -15,7 +15,9 @@ import { cn } from "../lib/cn";
|
|
|
15
15
|
/* ----------------------------------------------------------------------------
|
|
16
16
|
UsageMeter (design brief 7.20) - remaining quota at a glance and in detail.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Subscription windows use their short provider labels ("5h", "Week",
|
|
19
|
+
"Fable week"; lib/subscription-accounts); other meters say what they
|
|
20
|
+
measure ("Memory"). Never "Wk". Color is
|
|
19
21
|
quiet until it matters: a status tone only below 10% left. Reset times are
|
|
20
22
|
passed in already formatted ("Mon 28 Sep, 09:00"); the relative "Checked
|
|
21
23
|
just now" line comes from the shared RelativeTime helper.
|
|
@@ -23,7 +25,7 @@ import { cn } from "../lib/cn";
|
|
|
23
25
|
Three looks, same data:
|
|
24
26
|
- "bar" A. 4px bar, "22% left" and the reset time. In a row the bar
|
|
25
27
|
drops away and it reads as text: bar in the sheet, text in the row.
|
|
26
|
-
- "text" B. "
|
|
28
|
+
- "text" B. "Week 22% left", no bar. The quietest.
|
|
27
29
|
- "ring" C. A small ring per window. Compact, harder to compare.
|
|
28
30
|
Each has two densities: "full" (account sheet) and "compact" (a row).
|
|
29
31
|
-------------------------------------------------------------------------- */
|
|
@@ -122,7 +124,7 @@ const LEVEL_VALUE_TEXT: Record<UsageLevel, string> = {
|
|
|
122
124
|
};
|
|
123
125
|
|
|
124
126
|
export interface UsageMeterProps {
|
|
125
|
-
/** "
|
|
127
|
+
/** "5h", "Week", "Fable week", "Memory": the window's short label. */
|
|
126
128
|
label: string;
|
|
127
129
|
/** 0-100, or null when the provider hasn't reported a reading. */
|
|
128
130
|
percent: number | null;
|
|
@@ -219,7 +221,7 @@ export function UsageMeter({
|
|
|
219
221
|
/**
|
|
220
222
|
* The usage readout at the end of an account row: "78% left this week" and a
|
|
221
223
|
* 64px bar, right-aligned so it sits against the row's chevron, and under it
|
|
222
|
-
* when the limits reset: "Resets Thu 09:00 ·
|
|
224
|
+
* when the limits reset: "Resets Thu 09:00 · 5h 14:20". Without a reading
|
|
223
225
|
* it says why in words ("No usage yet"). Where the row folds its facts into
|
|
224
226
|
* the meta line (narrow lists), only the words stay.
|
|
225
227
|
*/
|
|
@@ -325,7 +327,7 @@ export function UsageReadout({
|
|
|
325
327
|
>
|
|
326
328
|
{text}
|
|
327
329
|
</span>
|
|
328
|
-
<
|
|
330
|
+
<UsageTrack
|
|
329
331
|
level={level}
|
|
330
332
|
fill={level === "exhausted" ? 0 : shown}
|
|
331
333
|
className="w-16 shrink-0 @max-[639px]/list:hidden"
|
|
@@ -409,7 +411,8 @@ function ResetLine({ level, resetsLabel }: { level: UsageLevel; resetsLabel?: st
|
|
|
409
411
|
);
|
|
410
412
|
}
|
|
411
413
|
|
|
412
|
-
|
|
414
|
+
/** The 4px bar every usage meter draws, filled to the share it shows. */
|
|
415
|
+
export function UsageTrack({
|
|
413
416
|
level,
|
|
414
417
|
fill,
|
|
415
418
|
className,
|
|
@@ -462,7 +465,7 @@ function BarFull({ label, value, level, fill, resetsLabel, loading }: Parts) {
|
|
|
462
465
|
className="block h-1 rounded-full bg-surface-3 motion-safe:animate-pulse"
|
|
463
466
|
/>
|
|
464
467
|
) : (
|
|
465
|
-
<
|
|
468
|
+
<UsageTrack level={level} fill={fill} />
|
|
466
469
|
)}
|
|
467
470
|
{loading ? (
|
|
468
471
|
<span
|
package/styles/compiled.css
CHANGED
|
@@ -1843,6 +1843,9 @@
|
|
|
1843
1843
|
:where(.og-root).max-h-\[min\(36rem\,55dvh\)\],:where(.og-root) .max-h-\[min\(36rem\,55dvh\)\] {
|
|
1844
1844
|
max-height: min(36rem, 55dvh);
|
|
1845
1845
|
}
|
|
1846
|
+
:where(.og-root).max-h-\[min\(40rem\,var\(--radix-dropdown-menu-content-available-height\)\)\],:where(.og-root) .max-h-\[min\(40rem\,var\(--radix-dropdown-menu-content-available-height\)\)\] {
|
|
1847
|
+
max-height: min(40rem, var(--radix-dropdown-menu-content-available-height));
|
|
1848
|
+
}
|
|
1846
1849
|
:where(.og-root).max-h-\[min\(480px\,70dvh\)\],:where(.og-root) .max-h-\[min\(480px\,70dvh\)\] {
|
|
1847
1850
|
max-height: min(480px, 70dvh);
|
|
1848
1851
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/app/lib/session-branch-cache.tsx"],"sourcesContent":["import type { Session as SessionDetails } from \"../types\";\nimport type { RailSession as Session } from \"./session-list-entry\";\n\nimport { mergeSessionForRail } from \"./sessions-group\";\n\nexport type SessionBranchPage<T extends Session = SessionDetails> = {\n sessions: T[];\n /** Per-row causal generations for rows returned by accepted branch reads. */\n channelGenerations: ReadonlyMap<string, number>;\n nextCursor: string | null;\n loading: boolean;\n /** Whether this load cycle may paint loading or retry feedback in the tree. */\n feedbackVisible: boolean;\n failed: boolean;\n stale: boolean;\n requestId: number | null;\n retryCursor: string | null;\n};\n\nexport type SessionBranchSummaryDecision = {\n acknowledge: boolean;\n refresh: boolean;\n markStale: boolean;\n};\n\n/**\n * Stable summary of the server-owned descendant facts that make an already\n * loaded branch stale. Child creation changes direct/total counts; lifecycle\n * changes advance the status aggregates. Title/content stays owned by the\n * child page or active route projection.\n */\nexport function sessionBranchSummaryKey(session: Session, readRevision = 0): string {\n const stats = session.treeStats;\n if (!stats) return `${session.id}:${session.updatedAt}:unknown:${readRevision}`;\n return [\n readRevision,\n session.id,\n session.updatedAt,\n stats.directChildren,\n stats.totalDescendants,\n stats.runningDescendants,\n stats.queuedDescendants,\n stats.attentionDescendants,\n stats.pausedDescendants,\n stats.failedDescendants,\n stats.unreadFailedDescendants ?? stats.failedDescendants,\n stats.unreadDescendants ?? 0,\n stats.activelyWorkingDescendants ?? 0,\n stats.attentionSince ?? \"\",\n stats.truncated ? 1 : 0,\n ].join(\":\");\n}\n\n/**\n * Persist a route/lineage child in its already-loaded parent branch. The route\n * owns current lifecycle/content while the cached row retains rail ordering\n * timestamps and may own treeStats.\n */\nexport function upsertSessionBranchChild(\n pages: ReadonlyMap<string, SessionBranchPage<SessionDetails>>,\n child: SessionDetails,\n): ReadonlyMap<string, SessionBranchPage<SessionDetails>>;\nexport function upsertSessionBranchChild<T extends Session = SessionDetails>(\n pages: ReadonlyMap<string, SessionBranchPage<T>>,\n child: T,\n): ReadonlyMap<string, SessionBranchPage<T>>;\nexport function upsertSessionBranchChild<T extends Session = SessionDetails>(\n pages: ReadonlyMap<string, SessionBranchPage<T>>,\n child: T,\n): ReadonlyMap<string, SessionBranchPage<T>> {\n const parentSessionId = child.parentSessionId;\n if (!parentSessionId) return pages;\n const page = pages.get(parentSessionId);\n const sessions = page?.sessions ?? [];\n const index = sessions.findIndex((session) => session.id === child.id);\n const nextSessions = [...sessions];\n if (index === -1) {\n nextSessions.push(child);\n } else {\n const cached = sessions[index]!;\n const merged = {\n ...mergeSessionForRail(cached, child),\n // Route/detail timestamps can be millisecond-truncated or ahead of the\n // list activity clock. Only a branch-page commit replaces rail ordering.\n createdAt: cached.createdAt,\n updatedAt: cached.updatedAt,\n };\n nextSessions[index] = page?.channelGenerations.has(child.id)\n ? { ...merged, channelId: cached.channelId ?? null }\n : merged;\n }\n return new Map(pages).set(parentSessionId, {\n sessions: nextSessions,\n channelGenerations: page?.channelGenerations ?? new Map(),\n nextCursor: page?.nextCursor ?? null,\n loading: page?.loading ?? false,\n feedbackVisible: page?.feedbackVisible ?? false,\n failed: page?.failed ?? false,\n stale: page?.stale ?? false,\n requestId: page?.requestId ?? null,\n retryCursor: page?.retryCursor ?? null,\n });\n}\n\n/** Mark one exact branch request active without discarding loaded children. */\nexport function beginSessionBranchRequest<T extends Session = SessionDetails>(\n pages: ReadonlyMap<string, SessionBranchPage<T>>,\n parentSessionId: string,\n requestId: number,\n cursor?: string,\n options: { feedbackVisible?: boolean | undefined } = {},\n): ReadonlyMap<string, SessionBranchPage<T>> {\n const previous = pages.get(parentSessionId);\n return new Map(pages).set(parentSessionId, {\n sessions: previous?.sessions ?? [],\n channelGenerations: previous?.channelGenerations ?? new Map(),\n nextCursor: previous?.nextCursor ?? null,\n loading: true,\n feedbackVisible: options.feedbackVisible ?? true,\n failed: false,\n stale: false,\n requestId,\n retryCursor: cursor ?? null,\n });\n}\n\n/** Refresh the already-loaded window with bounded, opaque-cursor reads. */\nexport async function readLoadedSessionBranchWindow<T extends Session = SessionDetails>(\n readPage: (cursor?: string) => Promise<{ sessions: T[]; pinned: T[]; nextCursor: string | null }>,\n minimumCount: number,\n initialCursor?: string,\n): Promise<{ sessions: T[]; nextCursor: string | null }> {\n const sessions = new Map<string, T>();\n const seen = new Set<string>();\n let cursor = initialCursor;\n for (let reads = 0; reads <= Math.max(1, minimumCount); reads += 1) {\n const page = await readPage(cursor);\n for (const session of [...page.sessions, ...page.pinned]) sessions.set(session.id, session);\n if (!page.nextCursor || sessions.size >= minimumCount) {\n return { sessions: [...sessions.values()], nextCursor: page.nextCursor };\n }\n if (seen.has(page.nextCursor)) throw new Error(\"Child pagination cursor repeated\");\n seen.add(page.nextCursor);\n cursor = page.nextCursor;\n }\n throw new Error(\"Child pagination made no progress\");\n}\n\n/** Commit one server child page or a fully refreshed loaded window. */\nexport function commitSessionBranchPage(\n pages: ReadonlyMap<string, SessionBranchPage<SessionDetails>>,\n parentSessionId: string,\n input: { sessions: readonly SessionDetails[]; nextCursor: string | null },\n options?: {\n append?: boolean | undefined;\n replaceWindow?: boolean | undefined;\n preserve?: readonly SessionDetails[] | undefined;\n requestId?: number | undefined;\n readGeneration?: number | undefined;\n },\n): ReadonlyMap<string, SessionBranchPage<SessionDetails>>;\nexport function commitSessionBranchPage<T extends Session = SessionDetails>(\n pages: ReadonlyMap<string, SessionBranchPage<T>>,\n parentSessionId: string,\n input: { sessions: readonly T[]; nextCursor: string | null },\n options?: {\n append?: boolean | undefined;\n replaceWindow?: boolean | undefined;\n preserve?: readonly T[] | undefined;\n requestId?: number | undefined;\n readGeneration?: number | undefined;\n },\n): ReadonlyMap<string, SessionBranchPage<T>>;\nexport function commitSessionBranchPage<T extends Session = SessionDetails>(\n pages: ReadonlyMap<string, SessionBranchPage<T>>,\n parentSessionId: string,\n input: { sessions: readonly T[]; nextCursor: string | null },\n options: {\n append?: boolean | undefined;\n replaceWindow?: boolean | undefined;\n preserve?: readonly T[] | undefined;\n requestId?: number | undefined;\n readGeneration?: number | undefined;\n } = {},\n): ReadonlyMap<string, SessionBranchPage<T>> {\n const previous = pages.get(parentSessionId);\n if (options.requestId !== undefined && previous?.requestId !== options.requestId) return pages;\n const merged = new Map<string, T>();\n const channelGenerations = options.append\n ? new Map(previous?.channelGenerations ?? [])\n : new Map<string, number>();\n if (options.append) {\n for (const session of [\n ...(previous?.sessions ?? []),\n ...(options.preserve ?? []),\n ...input.sessions,\n ]) {\n merged.set(session.id, session);\n }\n } else {\n // A refreshed first page owns the leading order. Retain already-loaded\n // tail entries (including an active child outside the first 50) behind it.\n for (const session of input.sessions) merged.set(session.id, session);\n for (const session of [\n ...(options.replaceWindow ? [] : (previous?.sessions ?? [])),\n ...(options.preserve ?? []),\n ]) {\n if (!merged.has(session.id)) merged.set(session.id, session);\n }\n }\n const readGeneration = options.readGeneration ?? 0;\n if (readGeneration > 0) {\n for (const session of input.sessions) {\n channelGenerations.set(session.id, readGeneration);\n }\n }\n return new Map(pages).set(parentSessionId, {\n sessions: [...merged.values()],\n channelGenerations,\n nextCursor: input.nextCursor,\n loading: false,\n feedbackVisible: false,\n failed: false,\n stale: false,\n requestId: null,\n retryCursor: null,\n });\n}\n\n/** Current branch rows that may own channel filing, with their actual read starts. */\nexport function authoritativeSessionBranchChannels<T extends Session = SessionDetails>(\n page: SessionBranchPage<T>,\n): Array<readonly [session: T, readGeneration: number]> {\n const byId = new Map(page.sessions.map((session) => [session.id, session]));\n const evidence: Array<readonly [session: T, readGeneration: number]> = [];\n for (const [sessionId, readGeneration] of page.channelGenerations) {\n const session = byId.get(sessionId);\n if (session && readGeneration > 0) evidence.push([session, readGeneration]);\n }\n return evidence;\n}\n\n/** Fail only the still-current request and expose its exact retry cursor. */\nexport function failSessionBranchRequest<T extends Session = SessionDetails>(\n pages: ReadonlyMap<string, SessionBranchPage<T>>,\n parentSessionId: string,\n requestId: number,\n): ReadonlyMap<string, SessionBranchPage<T>> {\n const previous = pages.get(parentSessionId);\n if (!previous || previous.requestId !== requestId) return pages;\n return new Map(pages).set(parentSessionId, {\n ...previous,\n loading: false,\n // Background hydration may suppress transient loading feedback, but a\n // failure must become actionable instead of leaving the branch silently\n // incomplete for the rest of the active route.\n feedbackVisible: true,\n failed: true,\n stale: false,\n requestId: null,\n });\n}\n\n/** A fresh cached page already owns the active child's parent branch. */\nexport function sessionBranchNeedsHydration<T extends Session = SessionDetails>(\n page: SessionBranchPage<T> | undefined,\n): boolean {\n return page === undefined || page.failed || page.stale;\n}\n\n/** Decide whether a changed parent summary can be acknowledged right now. */\nexport function sessionBranchSummaryDecision(input: {\n previousKey: string | undefined;\n nextKey: string;\n loading: boolean;\n expanded: boolean;\n stale: boolean;\n}): SessionBranchSummaryDecision {\n if (input.loading) {\n return {\n acknowledge: input.previousKey === input.nextKey,\n refresh: false,\n markStale: false,\n };\n }\n if (input.previousKey === undefined || input.previousKey === input.nextKey) {\n return { acknowledge: true, refresh: false, markStale: false };\n }\n return {\n acknowledge: true,\n refresh: input.expanded,\n markStale: !input.expanded && !input.stale,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/app/lib/agent-capabilities.tsx"],"sourcesContent":["/**\n * Web view of the agent capability registry (`@opengeni/contracts`\n * agent-config). Every screen that shows or edits what an agent can do (the\n * workspace defaults page, the composer's Capabilities panel, the session\n * Agent panel and the schedule form) reads its groups, labels and request\n * shapes from here, so they cannot drift from the server's meaning.\n *\n * A \"draft\" is what a picker edits: a starting point plus the full value of\n * every capability. `requestFromDraft` turns it back into the smallest\n * `AgentCapabilities` request (a starting point plus only the toggles that\n * differ from it), which is what the server stores and what people read in\n * the API.\n */\nimport {\n AGENT_CAPABILITY_DESCRIPTIONS,\n AGENT_CAPABILITY_IDS,\n allAgentCapabilities,\n noneAgentCapabilities,\n type AgentCapabilities,\n type AgentCapabilityId,\n type AgentCapabilityStartingPoint,\n type AgentCapabilityToggles,\n type AgentSkillsCapability,\n type ClientAgentConfig,\n type ResolvedAgentCapabilities,\n type ResolvedAgentConfig,\n} from \"@opengeni/contracts\";\nimport { regionRestrictedText } from \"../../inference-region\";\nimport { t } from \"./console-text\";\n\nexport type { AgentCapabilityId, ResolvedAgentCapabilities };\n\nexport type AgentCapabilityGroup = {\n id: \"conversation\" | \"work\" | \"workspace\";\n label: string;\n capabilities: readonly AgentCapabilityId[];\n};\n\n/** Three groups, in the order people scan them. Every capability appears once. */\nexport const AGENT_CAPABILITY_GROUPS: readonly AgentCapabilityGroup[] = [\n { id: \"conversation\", label: \"Conversation\", capabilities: [\"humanInput\", \"webSearch\", \"media\"] },\n {\n id: \"work\",\n label: \"Work\",\n capabilities: [\"goals\", \"subagents\", \"skills\", \"artifacts\", \"browser\", \"schedules\"],\n },\n {\n id: \"workspace\",\n label: \"Workspace\",\n capabilities: [\n \"knowledge\",\n \"secrets\",\n \"workspaceFiles\",\n \"workspaceConnectors\",\n \"workspaceAdmin\",\n ],\n },\n];\n\nexport function capabilityLabel(id: AgentCapabilityId): string {\n return AGENT_CAPABILITY_DESCRIPTIONS[id].label;\n}\n\nexport function capabilityDescription(id: AgentCapabilityId): string {\n return AGENT_CAPABILITY_DESCRIPTIONS[id].description;\n}\n\n/** The two starting points, in product words, each with its consequence. */\nexport const AGENT_STARTING_POINTS: readonly {\n value: AgentCapabilityStartingPoint;\n title: string;\n description: string;\n}[] = [\n {\n value: \"all\",\n title: \"Everything this workspace offers\",\n description: \"Every capability is on unless you turn it off.\",\n },\n {\n value: \"none\",\n title: \"Only what you choose\",\n description:\n \"Starts with its own tools, asking questions and reading Skills. Turn on the rest as needed.\",\n },\n];\n\nexport const SKILLS_OPTIONS: readonly { value: \"off\" | \"read\" | \"manage\"; label: string }[] = [\n { value: \"off\", label: \"Off\" },\n { value: \"read\", label: \"Read\" },\n { value: \"manage\", label: \"Read and write\" },\n];\n\nexport function skillsOptionValue(value: AgentSkillsCapability): \"off\" | \"read\" | \"manage\" {\n return value === false ? \"off\" : value;\n}\n\nexport function skillsFromOption(value: \"off\" | \"read\" | \"manage\"): AgentSkillsCapability {\n return value === \"off\" ? false : value;\n}\n\nexport const UNAVAILABLE_CAPABILITY_REASON = \"Not enabled on this server\";\n\n/** Capabilities this deployment offers. Unknown ids (an older server) count as available. */\nexport type CapabilityAvailability = {\n isAvailable: (id: AgentCapabilityId) => boolean;\n unavailable: ReadonlySet<AgentCapabilityId>;\n /**\n * Why a capability is unavailable: \"Not supported in EU\" when the server\n * switched it off for an EU-only workspace, otherwise \"Not enabled on this\n * server\".\n */\n unavailableReason: (id: AgentCapabilityId) => string;\n};\n\nexport function capabilityAvailability(\n config: Pick<ClientAgentConfig, \"capabilities\"> | null | undefined,\n alsoUnavailable: readonly AgentCapabilityId[] = [],\n): CapabilityAvailability {\n const unavailable = new Set<AgentCapabilityId>(alsoUnavailable);\n const reasons = new Map<AgentCapabilityId, string>();\n for (const entry of config?.capabilities ?? []) {\n if (entry.available) continue;\n unavailable.add(entry.id);\n const regionRestricted = regionRestrictedText(t, entry.code ?? entry.reason);\n if (regionRestricted) reasons.set(entry.id, regionRestricted);\n }\n return {\n unavailable,\n isAvailable: (id) => !unavailable.has(id),\n unavailableReason: (id) => reasons.get(id) ?? UNAVAILABLE_CAPABILITY_REASON,\n };\n}\n\nexport function baseCapabilities(from: AgentCapabilityStartingPoint): ResolvedAgentCapabilities {\n return from === \"all\" ? allAgentCapabilities() : noneAgentCapabilities();\n}\n\nexport type AgentCapabilityDraft = {\n from: AgentCapabilityStartingPoint;\n values: ResolvedAgentCapabilities;\n};\n\nfunction applyToggles(\n base: ResolvedAgentCapabilities,\n toggles: AgentCapabilityToggles,\n): ResolvedAgentCapabilities {\n const next = { ...base };\n for (const id of AGENT_CAPABILITY_IDS) {\n const value = toggles[id];\n if (value === undefined) continue;\n if (id === \"skills\") next.skills = value as AgentSkillsCapability;\n else next[id] = value as boolean;\n }\n return next;\n}\n\n/**\n * The editable form of a request. Omitted means \"everything\". A workspace's\n * older \"Ask questions\" setting (off) still turns the default off unless the\n * request says otherwise, matching the server's resolution.\n */\nexport function draftFromRequest(\n capabilities: AgentCapabilities | undefined,\n options: { legacyHumanInputOff?: boolean | undefined } = {},\n): AgentCapabilityDraft {\n const from: AgentCapabilityStartingPoint =\n capabilities === undefined\n ? \"all\"\n : typeof capabilities === \"string\"\n ? capabilities\n : capabilities.from;\n const toggles: AgentCapabilityToggles =\n capabilities === undefined || typeof capabilities === \"string\"\n ? {}\n : (({ from: _from, ...rest }) => rest)(capabilities);\n const values = applyToggles(baseCapabilities(from), toggles);\n if (options.legacyHumanInputOff && toggles.humanInput === undefined) values.humanInput = false;\n return { from, values };\n}\n\n/** A frozen session configuration as a draft (for editing a running session). */\nexport function draftFromResolved(config: ResolvedAgentConfig): AgentCapabilityDraft {\n return { from: config.from, values: { ...config.capabilities } };\n}\n\n/**\n * The smallest request for a draft: its starting point, plus only the\n * capabilities that differ from it. A capability this server does not offer\n * is never sent as on (the server would refuse it).\n */\nexport function requestFromDraft(\n draft: AgentCapabilityDraft,\n availability?: CapabilityAvailability,\n): AgentCapabilities {\n const base = baseCapabilities(draft.from);\n const toggles: AgentCapabilityToggles = {};\n for (const id of AGENT_CAPABILITY_IDS) {\n const value = draft.values[id];\n if (value === base[id]) continue;\n if (availability && !availability.isAvailable(id) && value !== false) continue;\n (toggles as Record<string, boolean | string>)[id] = value;\n }\n return Object.keys(toggles).length === 0 ? draft.from : { from: draft.from, ...toggles };\n}\n\n/** Switch the starting point: every capability takes that starting point's value. */\nexport function withStartingPoint(\n draft: AgentCapabilityDraft,\n from: AgentCapabilityStartingPoint,\n): AgentCapabilityDraft {\n return draft.from === from ? draft : { from, values: baseCapabilities(from) };\n}\n\nexport function withCapability(\n draft: AgentCapabilityDraft,\n id: AgentCapabilityId,\n value: boolean | AgentSkillsCapability,\n): AgentCapabilityDraft {\n return { ...draft, values: { ...draft.values, [id]: value } };\n}\n\nexport function capabilityOn(values: ResolvedAgentCapabilities, id: AgentCapabilityId): boolean {\n return id === \"skills\" ? values.skills !== false : values[id] === true;\n}\n\n/** What actually runs: a capability the server doesn't offer is off. */\nexport function effectiveCapabilityOn(\n values: ResolvedAgentCapabilities,\n id: AgentCapabilityId,\n availability: CapabilityAvailability,\n): boolean {\n return availability.isAvailable(id) && capabilityOn(values, id);\n}\n\nexport function draftsEqual(left: AgentCapabilityDraft, right: AgentCapabilityDraft): boolean {\n return (\n left.from === right.from &&\n AGENT_CAPABILITY_IDS.every((id) => left.values[id] === right.values[id])\n );\n}\n\n/**\n * One short line for a chip or a muted row value: \"All capabilities\",\n * \"9 of 13 capabilities\". Counts only what this server offers.\n */\nexport function capabilitySummary(\n values: ResolvedAgentCapabilities,\n availability: CapabilityAvailability,\n): string {\n const offered = AGENT_CAPABILITY_IDS.filter((id) => availability.isAvailable(id));\n const on = offered.filter((id) => capabilityOn(values, id)).length;\n if (on === offered.length) {\n // Say \"available\" when the server holds some back, so \"all\" stays true.\n return offered.length === AGENT_CAPABILITY_IDS.length\n ? \"All capabilities\"\n : `All ${offered.length} available capabilities`;\n }\n if (on === 0) return \"No capabilities\";\n return `${on} of ${offered.length} capabilities`;\n}\n\n/** The workspace's saved defaults, or null when it follows Opengeni's defaults. */\nexport function workspaceAgentDefaultsDraft(input: {\n capabilities: AgentCapabilities | undefined;\n legacyHumanInputOff: boolean;\n}): AgentCapabilityDraft {\n return draftFromRequest(input.capabilities, { legacyHumanInputOff: input.legacyHumanInputOff });\n}\n\n/** Tool owner in product words, for the Technical details list. */\nexport function toolOwnerLabel(owner: AgentCapabilityId | \"runtime\" | \"sandbox\" | \"product\") {\n switch (owner) {\n case \"runtime\":\n return \"Always available\";\n case \"sandbox\":\n return \"Sandbox\";\n case \"product\":\n return \"Added to this session\";\n default:\n return capabilityLabel(owner);\n }\n}\n\n/**\n * Agent-setting failures in product words: what happened and what to do.\n * The raw API text (with its reference) is only a last resort.\n */\nexport function agentConfigErrorText(error: unknown, fallback: string): string {\n const failure = error as {\n status?: unknown | undefined;\n code?: unknown | undefined;\n details?: Record<string, unknown> | undefined;\n message?: unknown | undefined;\n } | null;\n if (!failure || typeof failure !== \"object\") return fallback;\n if (failure.status === 409) {\n return \"Someone changed these settings while you were editing. Nothing was saved. Check the current settings and try again.\";\n }\n const details = failure.details ?? {};\n const code = String(details.code ?? failure.code ?? \"\");\n const capability =\n typeof details.capability === \"string\" &&\n (AGENT_CAPABILITY_IDS as readonly string[]).includes(details.capability)\n ? capabilityLabel(details.capability as AgentCapabilityId)\n : null;\n switch (code) {\n case \"agent_capability_unavailable\":\n return capability\n ? `${capability} isn't enabled on this server. Turn it off and save again.`\n : \"One of these capabilities isn't enabled on this server. Turn it off and save again.\";\n case \"agent_config_widening\":\n return capability\n ? `This session can't turn on ${capability}: the session that started it doesn't have it.`\n : \"This session can't have more than the session that started it.\";\n case \"agent_config_conflict\":\n return \"These settings conflict with the tools chosen for this session. Change one of them and save again.\";\n default:\n return failure.status === 403\n ? \"You don't have permission to change this. Ask a workspace admin.\"\n : fallback;\n }\n}\n"],"mappings":";;;;;;;;;AAaA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OASK;AAaA,IAAM,0BAA2D;AAAA,EACtE,EAAE,IAAI,gBAAgB,OAAO,gBAAgB,cAAc,CAAC,cAAc,aAAa,OAAO,EAAE;AAAA,EAChG;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,cAAc,CAAC,SAAS,aAAa,UAAU,aAAa,WAAW,WAAW;AAAA,EACpF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,gBAAgB,IAA+B;AAC7D,SAAO,8BAA8B,EAAE,EAAE;AAC3C;AAEO,SAAS,sBAAsB,IAA+B;AACnE,SAAO,8BAA8B,EAAE,EAAE;AAC3C;AAGO,IAAM,wBAIP;AAAA,EACJ;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aACE;AAAA,EACJ;AACF;AAEO,IAAM,iBAAiF;AAAA,EAC5F,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,EAC7B,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,EAC/B,EAAE,OAAO,UAAU,OAAO,iBAAiB;AAC7C;AAEO,SAAS,kBAAkB,OAAyD;AACzF,SAAO,UAAU,QAAQ,QAAQ;AACnC;AAEO,SAAS,iBAAiB,OAAyD;AACxF,SAAO,UAAU,QAAQ,QAAQ;AACnC;AAEO,IAAM,gCAAgC;AActC,SAAS,uBACd,QACA,kBAAgD,CAAC,GACzB;AACxB,QAAM,cAAc,IAAI,IAAuB,eAAe;AAC9D,QAAM,UAAU,oBAAI,IAA+B;AACnD,aAAW,SAAS,QAAQ,gBAAgB,CAAC,GAAG;AAC9C,QAAI,MAAM,UAAW;AACrB,gBAAY,IAAI,MAAM,EAAE;AACxB,UAAM,mBAAmB,qBAAqB,GAAG,MAAM,QAAQ,MAAM,MAAM;AAC3E,QAAI,iBAAkB,SAAQ,IAAI,MAAM,IAAI,gBAAgB;AAAA,EAC9D;AACA,SAAO;AAAA,IACL;AAAA,IACA,aAAa,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE;AAAA,IACxC,mBAAmB,CAAC,OAAO,QAAQ,IAAI,EAAE,KAAK;AAAA,EAChD;AACF;AAEO,SAAS,iBAAiB,MAA+D;AAC9F,SAAO,SAAS,QAAQ,qBAAqB,IAAI,sBAAsB;AACzE;AAOA,SAAS,aACP,MACA,SAC2B;AAC3B,QAAM,OAAO,EAAE,GAAG,KAAK;AACvB,aAAW,MAAM,sBAAsB;AACrC,UAAM,QAAQ,QAAQ,EAAE;AACxB,QAAI,UAAU,OAAW;AACzB,QAAI,OAAO,SAAU,MAAK,SAAS;AAAA,QAC9B,MAAK,EAAE,IAAI;AAAA,EAClB;AACA,SAAO;AACT;AAOO,SAAS,iBACd,cACA,UAAyD,CAAC,GACpC;AACtB,QAAM,OACJ,iBAAiB,SACb,QACA,OAAO,iBAAiB,WACtB,eACA,aAAa;AACrB,QAAM,UACJ,iBAAiB,UAAa,OAAO,iBAAiB,WAClD,CAAC,KACA,CAAC,EAAE,MAAM,OAAO,GAAG,KAAK,MAAM,MAAM,YAAY;AACvD,QAAM,SAAS,aAAa,iBAAiB,IAAI,GAAG,OAAO;AAC3D,MAAI,QAAQ,uBAAuB,QAAQ,eAAe,OAAW,QAAO,aAAa;AACzF,SAAO,EAAE,MAAM,OAAO;AACxB;AAGO,SAAS,kBAAkB,QAAmD;AACnF,SAAO,EAAE,MAAM,OAAO,MAAM,QAAQ,EAAE,GAAG,OAAO,aAAa,EAAE;AACjE;AAOO,SAAS,iBACd,OACA,cACmB;AACnB,QAAM,OAAO,iBAAiB,MAAM,IAAI;AACxC,QAAM,UAAkC,CAAC;AACzC,aAAW,MAAM,sBAAsB;AACrC,UAAM,QAAQ,MAAM,OAAO,EAAE;AAC7B,QAAI,UAAU,KAAK,EAAE,EAAG;AACxB,QAAI,gBAAgB,CAAC,aAAa,YAAY,EAAE,KAAK,UAAU,MAAO;AACtE,IAAC,QAA6C,EAAE,IAAI;AAAA,EACtD;AACA,SAAO,OAAO,KAAK,OAAO,EAAE,WAAW,IAAI,MAAM,OAAO,EAAE,MAAM,MAAM,MAAM,GAAG,QAAQ;AACzF;AAGO,SAAS,kBACd,OACA,MACsB;AACtB,SAAO,MAAM,SAAS,OAAO,QAAQ,EAAE,MAAM,QAAQ,iBAAiB,IAAI,EAAE;AAC9E;AAEO,SAAS,eACd,OACA,IACA,OACsB;AACtB,SAAO,EAAE,GAAG,OAAO,QAAQ,EAAE,GAAG,MAAM,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE;AAC9D;AAEO,SAAS,aAAa,QAAmC,IAAgC;AAC9F,SAAO,OAAO,WAAW,OAAO,WAAW,QAAQ,OAAO,EAAE,MAAM;AACpE;AAGO,SAAS,sBACd,QACA,IACA,cACS;AACT,SAAO,aAAa,YAAY,EAAE,KAAK,aAAa,QAAQ,EAAE;AAChE;AAEO,SAAS,YAAY,MAA4B,OAAsC;AAC5F,SACE,KAAK,SAAS,MAAM,QACpB,qBAAqB,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE,MAAM,MAAM,OAAO,EAAE,CAAC;AAE3E;AAMO,SAAS,kBACd,QACA,cACQ;AACR,QAAM,UAAU,qBAAqB,OAAO,CAAC,OAAO,aAAa,YAAY,EAAE,CAAC;AAChF,QAAM,KAAK,QAAQ,OAAO,CAAC,OAAO,aAAa,QAAQ,EAAE,CAAC,EAAE;AAC5D,MAAI,OAAO,QAAQ,QAAQ;AAEzB,WAAO,QAAQ,WAAW,qBAAqB,SAC3C,qBACA,OAAO,QAAQ,MAAM;AAAA,EAC3B;AACA,MAAI,OAAO,EAAG,QAAO;AACrB,SAAO,GAAG,EAAE,OAAO,QAAQ,MAAM;AACnC;AAGO,SAAS,4BAA4B,OAGnB;AACvB,SAAO,iBAAiB,MAAM,cAAc,EAAE,qBAAqB,MAAM,oBAAoB,CAAC;AAChG;AAGO,SAAS,eAAe,OAA8D;AAC3F,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO,gBAAgB,KAAK;AAAA,EAChC;AACF;AAMO,SAAS,qBAAqB,OAAgB,UAA0B;AAC7E,QAAM,UAAU;AAMhB,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,MAAI,QAAQ,WAAW,KAAK;AAC1B,WAAO;AAAA,EACT;AACA,QAAM,UAAU,QAAQ,WAAW,CAAC;AACpC,QAAM,OAAO,OAAO,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;AACtD,QAAM,aACJ,OAAO,QAAQ,eAAe,YAC7B,qBAA2C,SAAS,QAAQ,UAAU,IACnE,gBAAgB,QAAQ,UAA+B,IACvD;AACN,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,aACH,GAAG,UAAU,+DACb;AAAA,IACN,KAAK;AACH,aAAO,aACH,8BAA8B,UAAU,mDACxC;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO,QAAQ,WAAW,MACtB,qEACA;AAAA,EACR;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/timeline-annotations.tsx"],"sourcesContent":["import type { TimelineAnnotationSource } from \"@opengeni/sdk\";\nimport { QuoteIcon, XIcon } from \"lucide-react\";\nimport {\n Suspense,\n lazy,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n type RefObject,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\nimport {\n AnnotationAccentRow,\n AnnotationNotePreview,\n AnnotationQuoteSourceButton,\n type TimelineAnnotationLike,\n} from \"./timeline-annotation-chrome\";\nimport { ANNOTATION_CARD_STACK_SCROLL_AT } from \"./timeline-annotation-layout\";\nimport {\n TimelineAnnotationSourceRootContext,\n useTimelineAnnotationSourceRoot,\n} from \"./timeline-annotation-reveal-context\";\nimport {\n annotationDisplayOrdinal,\n annotationHasNote,\n resolveAnnotationRevealRoot,\n} from \"./timeline-annotation-shared\";\nimport { useOpenGeniText } from \"../messages/runtime\";\n\nexport type { TimelineAnnotationLike } from \"./timeline-annotation-chrome\";\n\nconst TimelineAnnotationsDialog = lazy(() => import(\"./timeline-annotations-dialog\"));\n\nfunction AnnotationSourceRootBridge({\n triggerRef,\n children,\n}: {\n triggerRef: RefObject<HTMLElement | null>;\n children: ReactNode;\n}) {\n const inheritedRoot = useTimelineAnnotationSourceRoot();\n const conversationRootRef = useRef<HTMLElement | null>(null);\n if (!inheritedRoot) {\n conversationRootRef.current = resolveAnnotationRevealRoot(triggerRef.current);\n }\n useLayoutEffect(() => {\n if (inheritedRoot) return;\n conversationRootRef.current = resolveAnnotationRevealRoot(triggerRef.current);\n });\n if (inheritedRoot) return children;\n return (\n <TimelineAnnotationSourceRootContext.Provider value={conversationRootRef}>\n {children}\n </TimelineAnnotationSourceRootContext.Provider>\n );\n}\n\nexport function TimelineAnnotationCards({\n annotations,\n onRevealSource,\n className,\n}: {\n annotations: readonly TimelineAnnotationLike[];\n onRevealSource?: ((source: TimelineAnnotationSource) => boolean) | undefined;\n className?: string | undefined;\n}) {\n const t = useOpenGeniText();\n const [unavailableId, setUnavailableId] = useState<string | null>(null);\n if (annotations.length === 0) return null;\n return (\n <div\n data-og-annotation-cards=\"\"\n className={cn(\n \"grid gap-2\",\n annotations.length >= ANNOTATION_CARD_STACK_SCROLL_AT &&\n \"max-h-[min(28rem,55vh)] overflow-x-hidden overflow-y-auto overscroll-contain pr-1\",\n className,\n )}\n >\n {annotations.map((annotation, index) => {\n const ordinal = annotationDisplayOrdinal(annotation, index);\n return (\n <section\n key={annotation.id}\n aria-label={t(\"timelineAnnotations.annotationOrdinal\", { ordinal })}\n >\n <AnnotationAccentRow>\n <p className=\"mb-0.5 text-og-xs font-medium tabular-nums text-og-fg-subtle\">\n {t(\"timelineAnnotations.annotationOrdinal\", { ordinal })}\n </p>\n <AnnotationQuoteSourceButton\n annotation={annotation}\n lines={2}\n onRevealSource={onRevealSource}\n onUnavailable={setUnavailableId}\n />\n {unavailableId === annotation.id ? (\n <p role=\"status\" className=\"text-og-xs text-og-status-waiting\">\n {t(\"timelineAnnotations.sourceIsOutsideTheLoaded\")}\n </p>\n ) : null}\n <AnnotationNotePreview\n note={annotation.note}\n annotationId={annotation.id}\n ordinal={ordinal}\n />\n </AnnotationAccentRow>\n </section>\n );\n })}\n </div>\n );\n}\n\nexport function TimelineAnnotationsChip({\n annotations,\n editable = false,\n focusAnnotationId,\n onFocusConsumed,\n onUpdate,\n onRemove,\n onRevealSource,\n className,\n compact = false,\n onCommit,\n}: {\n annotations: readonly TimelineAnnotationLike[];\n editable?: boolean | undefined;\n focusAnnotationId?: string | null | undefined;\n onFocusConsumed?: (() => void) | undefined;\n onUpdate?: ((id: string, note: string) => void) | undefined;\n onRemove?: ((id: string) => void) | undefined;\n /** Return focus to the owning input after all notes are completed with Enter. */\n onCommit?: (() => void) | undefined;\n onRevealSource?: ((source: TimelineAnnotationSource) => boolean) | undefined;\n className?: string | undefined;\n /** Dense trigger for single-line rows such as the compact queue dock. */\n compact?: boolean | undefined;\n}) {\n const t = useOpenGeniText();\n const focusRequested = Boolean(\n focusAnnotationId && annotations.some((item) => item.id === focusAnnotationId),\n );\n const [open, setOpen] = useState(focusRequested);\n const triggerRef = useRef<HTMLButtonElement | null>(null);\n const openedFocusId = useRef<string | null>(focusRequested ? (focusAnnotationId ?? null) : null);\n\n useEffect(() => {\n if (!focusRequested || !focusAnnotationId) {\n if (!focusRequested) openedFocusId.current = null;\n return;\n }\n if (openedFocusId.current === focusAnnotationId) return;\n openedFocusId.current = focusAnnotationId;\n setOpen(true);\n }, [focusAnnotationId, focusRequested]);\n\n if (annotations.length === 0) return null;\n const countLabel = t(\"counts.annotations\", { count: annotations.length });\n const incomplete = annotations.some((annotation) => !annotationHasNote(annotation.note));\n const canClear = Boolean(editable && onRemove);\n\n const dismiss = (restoreFocus: boolean) => {\n setOpen(false);\n onFocusConsumed?.();\n if (restoreFocus) triggerRef.current?.focus();\n };\n\n return (\n <span className={cn(\"inline-flex max-w-full items-center\", className)}>\n <span\n className={cn(\n \"inline-flex max-w-full items-center rounded-full border bg-og-surface-1 text-og-fg-muted\",\n incomplete ? \"border-og-accent/45 bg-og-accent-soft/50\" : \"border-og-border\",\n )}\n >\n <button\n ref={triggerRef}\n type=\"button\"\n className={cn(\n \"inline-flex min-w-0 max-w-full items-center gap-1.5 rounded-full border-0 bg-transparent font-medium outline-hidden transition hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-[44px]\",\n compact ? \"min-h-6 py-0.5 text-og-xs\" : \"min-h-8 py-1 text-og-sm\",\n canClear ? \"pr-1 pl-2.5\" : \"px-2.5\",\n )}\n aria-label={t(\"timelineAnnotations.reviewCountlabel\", { countLabel })}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n onClick={() => setOpen((current) => !current)}\n >\n <QuoteIcon className=\"size-3.5 shrink-0 text-og-accent\" aria-hidden=\"true\" />\n <span className=\"min-w-0 truncate\">{countLabel}</span>\n </button>\n {canClear ? (\n <button\n type=\"button\"\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-full border-0 bg-transparent text-og-fg-subtle outline-hidden hover:text-og-status-failed focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:size-11\"\n aria-label={t(\"timelineAnnotations.removeAllAnnotations\")}\n onClick={() => {\n for (const annotation of annotations) onRemove?.(annotation.id);\n }}\n >\n <XIcon className=\"size-3.5\" aria-hidden=\"true\" />\n </button>\n ) : null}\n </span>\n {open ? (\n <AnnotationSourceRootBridge triggerRef={triggerRef}>\n <Suspense fallback={null}>\n <TimelineAnnotationsDialog\n annotations={annotations}\n editable={editable}\n focusAnnotationId={focusAnnotationId}\n onFocusConsumed={onFocusConsumed}\n onUpdate={onUpdate}\n onRemove={onRemove}\n onRevealSource={onRevealSource}\n triggerRef={triggerRef}\n countLabel={countLabel}\n onDismiss={dismiss}\n onCommit={() => {\n dismiss(!onCommit);\n onCommit?.();\n }}\n />\n </Suspense>\n </AnnotationSourceRootBridge>\n ) : null}\n </span>\n );\n}\n\nexport default TimelineAnnotationsChip;\n"],"mappings":"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","names":[]}
|
|
@@ -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"]}
|