@opengeni/react 4.2.1-canary.39642758903001 → 4.3.1
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 +27 -27
- package/dist/app/components/Composer.js +27 -26
- package/dist/app/components/agent/agent-capability-picker.js +5 -5
- package/dist/app/components/artifacts/artifact-library.js +19 -19
- package/dist/app/components/artifacts/chat-interactive-block.js +16 -16
- package/dist/app/components/artifacts/inline-chat-image.js +31 -30
- package/dist/app/components/artifacts/retained-file-preview.js +35 -34
- package/dist/app/components/artifacts/retained-text-preview.js +5 -5
- package/dist/app/components/artifacts/site-audience.js +5 -5
- package/dist/app/components/artifacts/site-conversations.js +24 -22
- package/dist/app/components/artifacts/site-data.js +20 -20
- package/dist/app/components/artifacts/site-publishing.js +39 -39
- package/dist/app/components/artifacts/site-settings.js +48 -48
- package/dist/app/components/billing-class-mark.js +5 -5
- package/dist/app/components/capabilities/capability-detail-sheet.js +9 -9
- package/dist/app/components/capabilities/capability-logo-source.js +13 -12
- package/dist/app/components/capabilities/connection-account-picker.js +2 -2
- package/dist/app/components/capabilities/connector-tool-permissions.js +5 -5
- package/dist/app/components/capabilities/native-connect-setup.js +14 -13
- package/dist/app/components/capabilities/native-connect-setup.js.map +1 -1
- package/dist/app/components/capabilities/perform-capability-action.js +3 -3
- package/dist/app/components/capabilities/prepared-mcp-setup-card.js +15 -14
- package/dist/app/components/capabilities/session-capability-card.js +78 -77
- package/dist/app/components/capabilities/session-capability-card.js.map +1 -1
- package/dist/app/components/capabilities/session-custom-mcp-card.js +20 -19
- package/dist/app/components/capabilities/session-github-card.js +25 -24
- package/dist/app/components/capabilities/session-machine-card.js +38 -38
- package/dist/app/components/capabilities/use-capabilities-catalog.js +3 -3
- package/dist/app/components/capabilities/use-connection-accounts.js +1 -1
- package/dist/app/components/command-menu/chat-switcher.d.ts +12 -0
- package/dist/app/components/command-menu/chat-switcher.js +142 -0
- package/dist/app/components/command-menu/chat-switcher.js.map +1 -0
- package/dist/app/components/command-menu/command-menu.d.ts +15 -0
- package/dist/app/components/command-menu/command-menu.js +812 -0
- package/dist/app/components/command-menu/command-menu.js.map +1 -0
- package/dist/app/components/command-menu/keycaps.d.ts +21 -0
- package/dist/app/components/command-menu/keycaps.js +12 -0
- package/dist/app/components/command-menu/shortcut-sheet.d.ts +12 -0
- package/dist/app/components/command-menu/shortcut-sheet.js +150 -0
- package/dist/app/components/command-menu/shortcut-sheet.js.map +1 -0
- package/dist/app/components/composer-capabilities-menu-body.js +3 -3
- package/dist/app/components/composer-mobile-plus-panel.js +21 -21
- package/dist/app/components/composer-mobile-plus.js +3 -3
- package/dist/app/components/credit-required-gate.js +1 -1
- package/dist/app/components/credit-required-prompt.js +16 -16
- package/dist/app/components/credits/coupon-redeem.js +2 -2
- package/dist/app/components/credits/credit-refusal-notice.d.ts +18 -0
- package/dist/app/components/credits/credit-refusal-notice.js +17 -0
- package/dist/app/components/cross-slot-deep-link-recovery.js +1 -1
- package/dist/app/components/desktop/app-shots.js +6 -6
- package/dist/app/components/desktop/this-computer.js +4 -4
- package/dist/app/components/feedback.js +5 -5
- package/dist/app/components/follow-up-repository-menu-body.js +7 -7
- package/dist/app/components/follow-up-repository-picker.js +3 -3
- package/dist/app/components/github-app-connect-launcher.js +1 -1
- package/dist/app/components/knowledge/agent-learning-settings.js +6 -6
- package/dist/app/components/machines/connect-machine-dialog.js +18 -18
- package/dist/app/components/manual-repository-editor.js +2 -2
- package/dist/app/components/markdown.js +10 -9
- package/dist/app/components/message-context-pills.js +2 -2
- package/dist/app/components/models/models-ui.js +10 -10
- package/dist/app/components/pickers.js +10 -10
- package/dist/app/components/rail/rail-context.d.ts +6 -0
- package/dist/app/components/rail/rail-context.js +3 -3
- package/dist/app/components/rail/rail-sections.js +61 -55
- package/dist/app/components/rail/session-browse-order-controls.js +2 -2
- package/dist/app/components/rail/session-header.js +50 -36
- package/dist/app/components/rail/session-list.js +59 -52
- package/dist/app/components/rail/session-row-hover-details.js +25 -23
- package/dist/app/components/rail/session-shell.js +96 -91
- package/dist/app/components/repository-picker.js +7 -7
- package/dist/app/components/secrets/session-secrets-panel.js +4 -4
- package/dist/app/components/session/agent-configuration-panel.js +34 -34
- package/dist/app/components/session/banners.js +12 -11
- package/dist/app/components/session/codex-account-indicator.js +12 -12
- package/dist/app/components/session/composer-menu-radio.js +2 -2
- package/dist/app/components/session/conversation-find.js +1 -1
- package/dist/app/components/session/editable-artifacts-workspace.js +45 -45
- package/dist/app/components/session/failed-session-banner.js +12 -12
- package/dist/app/components/session/human-input.js +48 -47
- package/dist/app/components/session/inspector.js +80 -79
- package/dist/app/components/session/inspector.js.map +1 -1
- package/dist/app/components/session/message-actions.js +5 -5
- package/dist/app/components/session/message-resource-attachments.js +21 -20
- package/dist/app/components/session/message-resource-attachments.js.map +1 -1
- package/dist/app/components/session/model-account-indicator.js +11 -11
- package/dist/app/components/session/model-context-inspector.js +2 -2
- package/dist/app/components/session/model-recovery-notice.js +3 -3
- package/dist/app/components/session/new-session-settings-menu.js +13 -13
- package/dist/app/components/session/sandbox-switcher.js +16 -16
- package/dist/app/components/session/sandbox-workspace.js +68 -67
- package/dist/app/components/session/search-markdown-highlight.js +11 -10
- package/dist/app/components/session/search-results-view.js +12 -11
- package/dist/app/components/session/session-admin-access.js +11 -11
- package/dist/app/components/session/session-retention.js +4 -4
- package/dist/app/components/session/session-search-dialog.d.ts +5 -0
- package/dist/app/components/session/session-search-dialog.js +22 -12
- package/dist/app/components/session/session-search-dialog.js.map +1 -1
- package/dist/app/components/session/session-skill-reviews.js +3 -3
- package/dist/app/components/session/session-tenancy-control.js +25 -25
- package/dist/app/components/session/session-usage-limit-section.js +9 -9
- package/dist/app/components/session/session-wait-status.js +11 -9
- package/dist/app/components/session/session-wait-status.js.map +1 -1
- package/dist/app/components/session/subagents.js +17 -15
- package/dist/app/components/session/subscription-account-menu.js +2 -2
- package/dist/app/components/session-connectors-menu-body.js +6 -6
- package/dist/app/components/settings/row-select.js +1 -1
- package/dist/app/components/transcription-settings.js +2 -2
- package/dist/app/components/ui/destructive-confirm.js +8 -8
- package/dist/app/components/usage/usage-entry.js +6 -6
- package/dist/app/components/workspace-composer-plus.js +22 -21
- package/dist/app/embed/session-app.js +264 -258
- package/dist/app/lib/actions/actions-provider.d.ts +30 -0
- package/dist/app/lib/actions/actions-provider.js +32 -0
- package/dist/app/lib/actions/chat-directory.d.ts +30 -0
- package/dist/app/lib/actions/chat-operations.d.ts +11 -0
- package/dist/app/lib/actions/chat-switcher.d.ts +31 -0
- package/dist/app/lib/actions/chords.d.ts +40 -0
- package/dist/app/lib/actions/events.d.ts +6 -0
- package/dist/app/lib/actions/rank.d.ts +17 -0
- package/dist/app/lib/actions/registry.d.ts +71 -0
- package/dist/app/lib/codex-usage-query.js +3 -3
- package/dist/app/lib/composer-connectors.js +14 -13
- package/dist/app/lib/console-text.js +2 -2
- package/dist/app/lib/credit-coverage.d.ts +21 -0
- package/dist/app/lib/credit-coverage.js +15 -0
- package/dist/app/lib/deployment-free-model.js +2 -2
- package/dist/app/lib/events.js +19 -18
- package/dist/app/lib/failed-session-copy.js +5 -5
- package/dist/app/lib/free-credit-gap.d.ts +9 -0
- package/dist/app/lib/free-credit-gap.js +4 -2
- package/dist/app/lib/integration-connect-analytics.d.ts +1 -1
- package/dist/app/lib/integration-connect-analytics.js +1 -1
- package/dist/app/lib/integration-connect-redirect.js +1 -1
- package/dist/app/lib/model-access-onboarding.js +4 -4
- package/dist/app/lib/model-policy.js +1 -1
- package/dist/app/lib/models-route.d.ts +6 -2
- package/dist/app/lib/models-route.js +6 -3
- package/dist/app/lib/models-route.js.map +1 -1
- package/dist/app/lib/move-chat-to-machine.js +3 -3
- package/dist/app/lib/session-branch-cache.js +15 -13
- package/dist/app/lib/session-create.js +2 -2
- package/dist/app/lib/session-group-pagination.js +15 -13
- package/dist/app/lib/session-hover-facts.js +16 -14
- package/dist/app/lib/session-model.js +3 -3
- package/dist/app/lib/session-rail.js +11 -9
- package/dist/app/lib/session-rename.js +3 -3
- package/dist/app/lib/session-search-route.d.ts +1 -1
- package/dist/app/lib/session-search-route.js +1 -1
- package/dist/app/lib/session-ui-features.d.ts +11 -3
- package/dist/app/lib/session-ui-features.js +1 -1
- package/dist/app/lib/sessions-group.js +15 -13
- package/dist/app/lib/turn-failure-analytics.js +7 -7
- package/dist/app/lib/unavailable-session-model.js +2 -2
- package/dist/app/lib/use-duplicate-site.js +2 -2
- package/dist/app/lib/use-follow-up-repositories.js +3 -3
- package/dist/app/lib/use-workspace-machines.js +8 -8
- package/dist/app/lib/use-workspace-model-catalog.js +6 -6
- package/dist/app/lib/use-workspace-rigs.js +4 -4
- package/dist/app/lib/workspace-navigation-preference.js +5 -5
- package/dist/app/lib/workspace-scope-context.js +4 -4
- package/dist/app/routes/artifacts.js +124 -122
- package/dist/app/routes/artifacts.js.map +1 -1
- package/dist/app/routes/retained-artifact.js +69 -68
- package/dist/app/routes/retained-artifact.js.map +1 -1
- package/dist/app/routes/session-unavailable.js +3 -3
- package/dist/app/routes/session.js +168 -166
- package/dist/app/routes/sessions-index-hydration.js +3 -3
- package/dist/app/routes/sessions-index.js +122 -116
- 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 +39 -39
- package/dist/{browser-viewer-ZRFZX3VN.js → browser-viewer-HPUMK7UP.js} +7 -7
- package/dist/{chat-interactive-block-HUMYWVCK.js → chat-interactive-block-22PPECCT.js} +6 -6
- package/dist/{chunk-GVIQ7H62.js → chunk-2LUBBDZV.js} +5 -5
- package/dist/{chunk-SWWYYGQO.js → chunk-325C2TCI.js} +5 -2
- package/dist/chunk-325C2TCI.js.map +1 -0
- package/dist/{chunk-XMMVIY7B.js → chunk-3CCJWHQY.js} +2 -2
- package/dist/{chunk-XS2FZ6DX.js → chunk-3F5ZPIWI.js} +2 -2
- package/dist/{chunk-72US6QNB.js → chunk-3J2YZRY5.js} +2 -2
- package/dist/{chunk-D4YQF4E3.js → chunk-3SMJ2BIQ.js} +2 -2
- package/dist/{chunk-TBJINQXA.js → chunk-3WCYK36X.js} +17 -17
- package/dist/{chunk-WPCF34V6.js → chunk-3WG3CRL7.js} +14 -14
- package/dist/{chunk-JI5BYQKO.js → chunk-3X46PNBX.js} +14 -14
- package/dist/{chunk-UO36FC3S.js → chunk-46I7MMAL.js} +6 -2
- package/dist/chunk-46I7MMAL.js.map +1 -0
- package/dist/{chunk-PBK44WJC.js → chunk-4GJ37O6G.js} +2 -2
- package/dist/chunk-4IWBQUQU.js +152 -0
- package/dist/chunk-4IWBQUQU.js.map +1 -0
- package/dist/{chunk-LEXPBQ56.js → chunk-4SKJX3C4.js} +6 -6
- package/dist/{chunk-ZA6YD2LW.js → chunk-57SYK776.js} +2 -2
- package/dist/{chunk-22LBKJDE.js → chunk-5DIAN5GQ.js} +12 -12
- package/dist/{chunk-LJ3TDK2L.js → chunk-5FA455GR.js} +4 -4
- package/dist/{chunk-N2BEUKXT.js → chunk-5FBZDEHE.js} +228 -228
- package/dist/chunk-5FBZDEHE.js.map +1 -0
- package/dist/{chunk-YPR5INHV.js → chunk-5X3E2Z3D.js} +4 -4
- package/dist/{chunk-OXNWZTEU.js → chunk-5ZJCL6X4.js} +5 -5
- package/dist/{chunk-62OAZ4LO.js → chunk-6C5GQQMC.js} +12 -12
- package/dist/{chunk-VGITH57T.js → chunk-6ERTXDZM.js} +4 -4
- package/dist/{chunk-ZQ7XQZCF.js → chunk-6FX73Y4I.js} +8 -8
- package/dist/{chunk-QZO2KK2F.js → chunk-6P44NG6Y.js} +2 -2
- package/dist/{chunk-N2DDJLTM.js → chunk-6T7Y33JA.js} +3 -3
- package/dist/{chunk-RBAGC2MJ.js → chunk-75VE5QUS.js} +22 -22
- package/dist/{chunk-MRXOGI3O.js → chunk-77CUDSHG.js} +9 -9
- package/dist/{chunk-F2GXK2Z6.js → chunk-7G446JFO.js} +431 -348
- package/dist/chunk-7G446JFO.js.map +1 -0
- package/dist/{chunk-GZ65XQR5.js → chunk-7T7FHSGS.js} +3 -3
- package/dist/{chunk-YGAH34CD.js → chunk-A3S26JSP.js} +8 -8
- package/dist/{chunk-GYPAO6RS.js → chunk-A664GSDM.js} +8 -8
- package/dist/{chunk-JSZSNMDR.js → chunk-ASUYLXKO.js} +2 -2
- package/dist/{chunk-RTK7SUPL.js → chunk-AUUJLVA3.js} +7 -7
- package/dist/{chunk-OOTBYSCA.js → chunk-BBWKPNJB.js} +5 -5
- package/dist/{chunk-BGZIMIUU.js → chunk-BCUYWOQU.js} +2 -2
- package/dist/{chunk-EKN4N4LS.js → chunk-BDFMNJZJ.js} +2 -2
- package/dist/{chunk-YZKGOWCC.js → chunk-BIDXQAGO.js} +2 -2
- package/dist/{chunk-Q2UUANHF.js → chunk-BIKAJ4DY.js} +5 -5
- package/dist/{chunk-5IQBF2X3.js → chunk-BJPJ2OUX.js} +3 -3
- package/dist/{chunk-EY2EMHZW.js → chunk-BPM2OTYK.js} +8 -8
- package/dist/{chunk-MT4TBRQB.js → chunk-BSWS2RUZ.js} +2 -2
- package/dist/{chunk-T7YD3VGK.js → chunk-C52MNKXU.js} +12 -12
- package/dist/{chunk-THNW33K7.js → chunk-CEUDV4OA.js} +18 -18
- package/dist/{chunk-GRLPRM56.js → chunk-CFEFYPNR.js} +8 -2
- package/dist/chunk-CFEFYPNR.js.map +1 -0
- package/dist/{chunk-LHGIS6SZ.js → chunk-CVK74BH7.js} +2 -2
- package/dist/{chunk-DFO2UCYG.js → chunk-CW5I65ZX.js} +11 -11
- package/dist/chunk-DKNTQDVL.js +86 -0
- package/dist/chunk-DKNTQDVL.js.map +1 -0
- package/dist/{chunk-SKRLKQEG.js → chunk-DOSC2HRQ.js} +79 -79
- package/dist/{chunk-KVB6XDLP.js → chunk-DPJ2CWVN.js} +2 -2
- package/dist/{chunk-4J6V4DH7.js → chunk-DXMRO2MU.js} +3 -3
- package/dist/{chunk-42I4O4WQ.js → chunk-EE55IDDR.js} +26 -26
- package/dist/{chunk-2RA6XABP.js → chunk-EEERTLFF.js} +12 -12
- package/dist/{chunk-PTOTKUKO.js → chunk-EEO744XR.js} +8 -8
- package/dist/{chunk-LD3HVI2J.js → chunk-EMFGBAQL.js} +6 -6
- package/dist/{chunk-FQGUK4ST.js → chunk-ENPJKVMN.js} +38 -38
- package/dist/{chunk-HDHK3SXK.js → chunk-EU6RLHMP.js} +4 -4
- package/dist/{chunk-G7VLL3PG.js → chunk-F2YABPRJ.js} +13 -4
- package/dist/chunk-F2YABPRJ.js.map +1 -0
- package/dist/{chunk-MRUWRQBX.js → chunk-FET6XHGS.js} +2 -2
- package/dist/{chunk-M6KUY3YH.js → chunk-FIICQA55.js} +2 -2
- package/dist/{chunk-NLWLCYCT.js → chunk-FTZXCPE3.js} +19 -19
- package/dist/{chunk-FN2KA3MJ.js → chunk-FUS76DO4.js} +3 -3
- package/dist/{chunk-AM4IIPWI.js → chunk-G7N5NPRJ.js} +2 -2
- package/dist/{chunk-CCQ7YKOD.js → chunk-GBYZ6653.js} +2 -2
- package/dist/{chunk-SOOWLNC5.js → chunk-GJUPLSC5.js} +330 -109
- package/dist/chunk-GJUPLSC5.js.map +1 -0
- package/dist/{chunk-YKKVIJVX.js → chunk-GQDSC6QZ.js} +5 -5
- package/dist/chunk-GQGNRL2L.js +53 -0
- package/dist/chunk-GQGNRL2L.js.map +1 -0
- package/dist/{chunk-5X6JP75Q.js → chunk-GRSODLVO.js} +4 -4
- package/dist/{chunk-73YP3R5X.js → chunk-GSESCQFY.js} +4 -4
- package/dist/{chunk-KWB5U3ZT.js → chunk-GWRW4N3T.js} +199 -137
- package/dist/chunk-GWRW4N3T.js.map +1 -0
- package/dist/{chunk-RTR7RNG4.js → chunk-GYRU4PNM.js} +9 -7
- package/dist/{chunk-RTR7RNG4.js.map → chunk-GYRU4PNM.js.map} +1 -1
- package/dist/{chunk-MZLEBFUZ.js → chunk-GZD6VBIK.js} +3 -3
- package/dist/{chunk-IZR2QRFF.js → chunk-H3HH5AHS.js} +4 -4
- package/dist/{chunk-DN3TKURW.js → chunk-H3LIIAGE.js} +4 -54
- package/dist/chunk-H3LIIAGE.js.map +1 -0
- package/dist/{chunk-NPLEQMNM.js → chunk-H5GWAG4I.js} +7 -5
- package/dist/{chunk-NPLEQMNM.js.map → chunk-H5GWAG4I.js.map} +1 -1
- package/dist/{chunk-OJPUVUB6.js → chunk-HAOZCLLA.js} +3 -3
- package/dist/{chunk-ZBHDGAYL.js → chunk-HEFE4OZJ.js} +2 -2
- package/dist/{chunk-WTG34JVA.js → chunk-HI75UTI6.js} +2 -2
- package/dist/{chunk-OMBIG3NC.js → chunk-HM633ROV.js} +14 -14
- package/dist/{chunk-WDFZWSKD.js → chunk-HRIP4M6H.js} +3 -3
- package/dist/{chunk-A2BCW6CQ.js → chunk-HU2DRFFI.js} +3 -3
- package/dist/{chunk-PO35PBAB.js → chunk-HVH7FFJH.js} +2 -2
- package/dist/{chunk-EG7KNUF7.js → chunk-HYTXTKST.js} +18 -18
- package/dist/{chunk-TFHG75A4.js → chunk-I4XMDFUJ.js} +7 -7
- package/dist/{chunk-IZHVZZQA.js → chunk-ICAUYWSL.js} +9 -9
- package/dist/{chunk-ZSERYHHT.js → chunk-IDMXEPHL.js} +150 -150
- package/dist/chunk-IDMXEPHL.js.map +1 -0
- package/dist/{chunk-DCLPWYP3.js → chunk-IEVPJ3G6.js} +2 -2
- package/dist/{chunk-EVWZHDSF.js → chunk-IKH3VTA4.js} +2 -2
- package/dist/{chunk-L5UCO2UV.js → chunk-ILBSBZGC.js} +13 -4
- package/dist/chunk-ILBSBZGC.js.map +1 -0
- package/dist/{chunk-IO6K6UYJ.js → chunk-IQ64BNAG.js} +4 -2
- package/dist/chunk-IQ64BNAG.js.map +1 -0
- package/dist/{chunk-TYHLEFD2.js → chunk-IZJNMRIR.js} +9 -9
- package/dist/{chunk-D2SR3TEB.js → chunk-J243WGUA.js} +2 -2
- package/dist/{chunk-QGSGIYE3.js → chunk-J2C6LB6W.js} +4 -4
- package/dist/{chunk-MT6TRTXF.js → chunk-J5MEDX7C.js} +9 -9
- package/dist/{chunk-6QHUKBJP.js → chunk-J7SKOO44.js} +2 -2
- package/dist/{chunk-W2QK7PYS.js → chunk-JAAST75A.js} +11 -11
- package/dist/{chunk-NQCMS4AJ.js → chunk-JQCGPTZ6.js} +9 -9
- package/dist/chunk-JRJUSKDY.js +832 -0
- package/dist/chunk-JRJUSKDY.js.map +1 -0
- package/dist/{chunk-CMUXJHGH.js → chunk-JRSCWQMC.js} +9 -9
- package/dist/{chunk-Q4OHNGGB.js → chunk-JRXHSVD5.js} +4 -4
- package/dist/{chunk-SD2K5ZN5.js → chunk-JXYLDT6X.js} +4 -4
- package/dist/{chunk-S3M5WCZW.js → chunk-KA4LV7G6.js} +35 -50
- package/dist/chunk-KA4LV7G6.js.map +1 -0
- package/dist/{chunk-IXX6ZOL2.js → chunk-KGTMHEAP.js} +7 -7
- package/dist/{chunk-22OBGVEJ.js → chunk-KOXVGPW4.js} +3 -3
- package/dist/{chunk-NOZ5CGZE.js → chunk-L5GPPMUB.js} +2 -2
- package/dist/{chunk-KIHYJM5F.js → chunk-LXJT4WAW.js} +58 -58
- package/dist/{chunk-KIHYJM5F.js.map → chunk-LXJT4WAW.js.map} +1 -1
- package/dist/{chunk-4FOOHMTU.js → chunk-LY6727IF.js} +1 -1
- package/dist/{chunk-PT7MTXRE.js → chunk-MAOCN7J6.js} +2 -2
- package/dist/{chunk-4K2JSJNX.js → chunk-MB5LZVDO.js} +2 -2
- package/dist/chunk-MF464AKA.js +139 -0
- package/dist/chunk-MF464AKA.js.map +1 -0
- package/dist/{chunk-UYSZKDQY.js → chunk-MK54JLE4.js} +1 -1
- package/dist/chunk-MK54JLE4.js.map +1 -0
- package/dist/{chunk-5LES64PP.js → chunk-MKOQAVOE.js} +21 -21
- package/dist/{chunk-BMV2SNYX.js → chunk-MUPWNSEJ.js} +18 -18
- package/dist/{chunk-Y5TRG22C.js → chunk-NRXIECWC.js} +2 -2
- package/dist/{chunk-GOE7G5JX.js → chunk-NWSAF6P5.js} +2 -2
- package/dist/chunk-OB3YGXHQ.js +158 -0
- package/dist/chunk-OB3YGXHQ.js.map +1 -0
- package/dist/{chunk-DUM363VS.js → chunk-OFZQJNF6.js} +5 -5
- package/dist/{chunk-CKN5QPEL.js → chunk-OMF7POEY.js} +2 -2
- package/dist/{chunk-MVXKO2BD.js → chunk-OXD6ET34.js} +1 -1
- package/dist/{chunk-47JUEVME.js → chunk-PALX6HWV.js} +21 -21
- package/dist/{chunk-B6OGSG7I.js → chunk-PE3BLBDT.js} +3 -3
- package/dist/{chunk-RVISSNVE.js → chunk-PMZKJOG6.js} +15 -15
- package/dist/{chunk-CESAMXWX.js → chunk-PQUTMG3S.js} +2 -2
- package/dist/{chunk-7VFCOKPG.js → chunk-PWBGODZU.js} +3 -3
- package/dist/{chunk-MOPAXD2H.js → chunk-QCADUTYX.js} +2 -2
- package/dist/{chunk-CT5FBO7E.js → chunk-RPOUJI25.js} +1 -1
- package/dist/{chunk-VE3FKXJ7.js → chunk-RUSXEE7X.js} +35 -32
- package/dist/chunk-RUSXEE7X.js.map +1 -0
- package/dist/{chunk-WKHYOS72.js → chunk-RW4GFE56.js} +3 -3
- package/dist/{chunk-FH4GO7HO.js → chunk-RYLVVDR7.js} +1 -1
- package/dist/{chunk-QZRDCFHI.js → chunk-S66SBBFQ.js} +5 -5
- package/dist/{chunk-CQJFIPAH.js → chunk-S7TNV2I7.js} +14 -14
- package/dist/{chunk-ZBQSIGGR.js → chunk-SC773IMJ.js} +13 -13
- package/dist/{chunk-RZV7SXED.js → chunk-SF3M27AN.js} +37 -12
- package/dist/chunk-SF3M27AN.js.map +1 -0
- package/dist/{chunk-FBJ2HK7A.js → chunk-SGPJ3YS2.js} +20 -20
- package/dist/{chunk-A2EWJQXX.js → chunk-SM5QX6UK.js} +4 -4
- package/dist/chunk-SWCLN6JE.js +40 -0
- package/dist/chunk-SWCLN6JE.js.map +1 -0
- package/dist/{chunk-OS3EQOIS.js → chunk-T4F5TW2X.js} +29 -24
- package/dist/chunk-T4F5TW2X.js.map +1 -0
- package/dist/{chunk-RKZWCTXV.js → chunk-TAEKDMEF.js} +2 -2
- package/dist/{chunk-6AVCAUGL.js → chunk-TASEV25T.js} +3 -3
- package/dist/{chunk-3XOISKZC.js → chunk-TLGDPMUX.js} +6 -6
- package/dist/{chunk-MOF3XSUM.js → chunk-TREHTIBD.js} +3 -2
- package/dist/chunk-TREHTIBD.js.map +1 -0
- package/dist/{chunk-HUQHJSPV.js → chunk-TTPXGD5S.js} +68 -33
- package/dist/chunk-TTPXGD5S.js.map +1 -0
- package/dist/{chunk-NFCYIZHX.js → chunk-TXIIBNCA.js} +7 -3
- package/dist/{chunk-NFCYIZHX.js.map → chunk-TXIIBNCA.js.map} +1 -1
- package/dist/{chunk-5IUW34PG.js → chunk-TY3QYPJ6.js} +7 -7
- package/dist/{chunk-VQFR4EU4.js → chunk-U3JK5VJV.js} +2 -2
- package/dist/{chunk-2AWMJO54.js → chunk-U42P3RMZ.js} +5 -5
- package/dist/{chunk-2RIUMV7S.js → chunk-UBIJBLUK.js} +234 -234
- package/dist/chunk-UBIJBLUK.js.map +1 -0
- package/dist/{chunk-GUU75DES.js → chunk-UEJTOPLW.js} +8 -8
- package/dist/{chunk-QWCTYLMD.js → chunk-URDONAEJ.js} +240 -204
- package/dist/chunk-URDONAEJ.js.map +1 -0
- package/dist/{chunk-OZOEWLGR.js → chunk-UT6JAORE.js} +4 -4
- package/dist/{chunk-5TELOQA6.js → chunk-UTHPUINA.js} +3 -3
- package/dist/{chunk-SOV7DTTU.js → chunk-V6HZ2HJZ.js} +67 -67
- package/dist/{chunk-SOV7DTTU.js.map → chunk-V6HZ2HJZ.js.map} +1 -1
- package/dist/{chunk-26RQ6JBR.js → chunk-VBVCNH6D.js} +5 -5
- package/dist/{chunk-P646DND6.js → chunk-VCMQPCME.js} +2 -2
- package/dist/{chunk-LV7FMIMM.js → chunk-VGUHAHHV.js} +2 -2
- package/dist/{chunk-GYVXARCY.js → chunk-VIBPFVU4.js} +41 -41
- package/dist/{chunk-KHPOKZ6Z.js → chunk-VMAC66JX.js} +6 -6
- package/dist/{chunk-SHKRS6I5.js → chunk-VRPNETPK.js} +3 -3
- package/dist/{chunk-6U4J6RVS.js → chunk-WCHW4XN7.js} +14 -14
- package/dist/{chunk-CJH6QUQJ.js → chunk-WD3UXNJV.js} +3 -3
- package/dist/{chunk-H5EVWF6L.js → chunk-WR67FJMX.js} +4 -4
- package/dist/{chunk-XLIJ36RG.js → chunk-WRMQ7EX4.js} +5 -5
- package/dist/{chunk-VVFWOBAM.js → chunk-WTJUKYB2.js} +15 -16
- package/dist/chunk-WTJUKYB2.js.map +1 -0
- package/dist/{chunk-7KLCFJ5G.js → chunk-X4PPGXQG.js} +2 -2
- package/dist/{chunk-ZE2JTVCQ.js → chunk-X5BMQXFD.js} +11 -11
- package/dist/{chunk-OYJY4Y4A.js → chunk-XFNLU7EW.js} +14 -7
- package/dist/chunk-XFNLU7EW.js.map +1 -0
- package/dist/{chunk-UECU6LZI.js → chunk-XXRBOSWV.js} +3 -3
- package/dist/{chunk-SPKAIDWX.js → chunk-XZEFCPBL.js} +2 -2
- package/dist/{chunk-EZ5NYRHK.js → chunk-YL6N7QLA.js} +5 -5
- package/dist/{chunk-Q2ZJOECN.js → chunk-YMVTIV5L.js} +19 -19
- package/dist/chunk-YMVTIV5L.js.map +1 -0
- package/dist/{chunk-VAIESMPY.js → chunk-YVBHGMKC.js} +4 -4
- package/dist/{chunk-AR62NQXE.js → chunk-Z2S5VQG7.js} +2 -2
- package/dist/{chunk-2MXUB3ZO.js → chunk-Z5OGTWMZ.js} +15 -2
- package/dist/chunk-Z5OGTWMZ.js.map +1 -0
- package/dist/{chunk-7UQJEADK.js → chunk-ZL2O4BYP.js} +2 -2
- package/dist/{chunk-FOOITLHR.js → chunk-ZZHBT5WQ.js} +2 -2
- package/dist/{chunk-X6VJQJYY.js → chunk-ZZWHKC6A.js} +3 -3
- package/dist/components/timeline-annotation-shared.d.ts +1 -9
- package/dist/composer-messages.js +2 -2
- package/dist/composer.js +15 -15
- package/dist/{computer-viewer-D4NHQB5D.js → computer-viewer-S6TE6TN7.js} +8 -8
- package/dist/connect.js +12 -11
- package/dist/desktop.js +2 -2
- package/dist/editor.js +2 -2
- package/dist/{embedded-new-voice-X4ZW6SY4.js → embedded-new-voice-ZDZPGX25.js} +8 -8
- package/dist/{embedded-voice-4OD6Z3HU.js → embedded-voice-FKCUXSJO.js} +8 -8
- package/dist/{fleet-decision-row-5UCJXTDP.js → fleet-decision-row-VCGWYJAV.js} +2 -2
- package/dist/hooks/page-wake.d.ts +21 -0
- package/dist/hooks/use-session-events.d.ts +1 -0
- package/dist/index.js +206 -205
- package/dist/interaction.js +9 -9
- package/dist/{latest-question-VGVNUGAU.js → latest-question-SINEV4U6.js} +3 -3
- package/dist/lib/format.d.ts +3 -2
- package/dist/machines.js +6 -6
- package/dist/messages/en.d.ts +12 -3
- package/dist/messages.js +1 -1
- package/dist/model-picker-model.js +2 -2
- package/dist/{model-policy-picker-menu-XOPYY6YA.js → model-policy-picker-menu-66JPM3G5.js} +6 -6
- package/dist/model-policy-picker-menu-66JPM3G5.js.map +1 -0
- package/dist/model-policy.js +1 -1
- package/dist/native-previews.js +3 -3
- package/dist/{platform-activity-row-56XOVTRA.js → platform-activity-row-LU5WABI2.js} +2 -2
- package/dist/{queue-surface-implementation-OZDOBJ6W.js → queue-surface-implementation-Y4OUVS7N.js} +8 -7
- package/dist/{queue-surface-implementation-OZDOBJ6W.js.map → queue-surface-implementation-Y4OUVS7N.js.map} +1 -1
- package/dist/realtime.js +7 -7
- package/dist/{sandbox-files-LJCR437H.js → sandbox-files-NBIVKVCZ.js} +11 -11
- package/dist/sandbox-files-NBIVKVCZ.js.map +1 -0
- package/dist/session-app.js +266 -260
- package/dist/session-list-model.js +3 -3
- package/dist/{session-realtime-UISLBZ4A.js → session-realtime-3PALSNMJ.js} +3 -3
- package/dist/session-realtime-3PALSNMJ.js.map +1 -0
- package/dist/session-realtime.js +2 -2
- package/dist/session-ui.js +62 -61
- package/dist/session.d.ts +1 -1
- package/dist/session.js +17 -17
- package/dist/sites.js +2 -2
- package/dist/terminal.js +2 -2
- package/dist/this-computer.js +3 -3
- package/dist/timeline/annotation-model.d.ts +48 -0
- package/dist/{timeline-annotation-markers-ACT7XRMW.js → timeline-annotation-markers-6526H2NM.js} +11 -9
- package/dist/{timeline-annotation-markers-ACT7XRMW.js.map → timeline-annotation-markers-6526H2NM.js.map} +1 -1
- package/dist/{timeline-annotation-selection-2IA7T5VR.js → timeline-annotation-selection-KV5SM6TA.js} +16 -62
- package/dist/timeline-annotation-selection-KV5SM6TA.js.map +1 -0
- package/dist/{timeline-annotations-dialog-W5B2HMYY.js → timeline-annotations-dialog-7CDHWC7Y.js} +12 -10
- package/dist/{timeline-annotations-dialog-W5B2HMYY.js.map → timeline-annotations-dialog-7CDHWC7Y.js.map} +1 -1
- package/dist/timeline-model.d.ts +3 -0
- package/dist/timeline-model.js +40 -14
- package/dist/ui/access-list.js +24 -24
- package/dist/ui/choice-cards.js +2 -2
- package/dist/ui/composer-menu-action.js +2 -2
- package/dist/ui/context-menu.d.ts +3 -1
- package/dist/ui/context-menu.js +3 -1
- package/dist/ui/detail-page.js +3 -3
- package/dist/ui/detail-sheet.js +3 -3
- package/dist/ui/diff-view.js +3 -3
- package/dist/ui/disclosure.js +5 -5
- package/dist/ui/dropdown-menu.js +1 -1
- package/dist/ui/flush-form-page.js +5 -5
- package/dist/ui/form-dialog.js +4 -4
- package/dist/ui/list-row.js +5 -5
- package/dist/ui/load-failure.js +3 -3
- package/dist/ui/page-actions.js +3 -3
- package/dist/ui/revision-history.js +11 -11
- package/dist/ui/role-select.js +8 -8
- package/dist/ui/segmented-control.js +1 -1
- package/dist/ui/settings-nav.js +3 -3
- package/dist/ui/toolbar.js +3 -3
- package/dist/usage.js +2 -2
- package/dist/workbench.js +11 -11
- package/package.json +4 -4
- package/src/app/app-state.tsx +2 -1
- package/src/app/components/command-menu/chat-switcher.tsx +135 -0
- package/src/app/components/command-menu/command-menu.tsx +840 -0
- package/src/app/components/command-menu/keycaps.tsx +56 -0
- package/src/app/components/command-menu/shortcut-sheet.tsx +155 -0
- package/src/app/components/credits/credit-refusal-notice.test.tsx +132 -0
- package/src/app/components/credits/credit-refusal-notice.tsx +92 -0
- package/src/app/components/rail/rail-context.tsx +28 -5
- package/src/app/components/rail/rail-sections.tsx +3 -5
- package/src/app/components/rail/session-header-mute.test.tsx +23 -1
- package/src/app/components/rail/session-header.test.tsx +21 -2
- package/src/app/components/rail/session-header.tsx +31 -1
- package/src/app/components/rail/session-list.tsx +89 -16
- package/src/app/components/rail/session-shell.tsx +0 -14
- package/src/app/components/session/session-search-dialog.tsx +12 -1
- package/src/app/embed/session-app.tsx +6 -3
- package/src/app/lib/actions/actions-provider.tsx +486 -0
- package/src/app/lib/actions/actions.test.ts +249 -0
- package/src/app/lib/actions/chat-directory.ts +231 -0
- package/src/app/lib/actions/chat-operations.ts +145 -0
- package/src/app/lib/actions/chat-switcher.ts +62 -0
- package/src/app/lib/actions/chords.ts +185 -0
- package/src/app/lib/actions/events.ts +10 -0
- package/src/app/lib/actions/rank.ts +119 -0
- package/src/app/lib/actions/registry.ts +333 -0
- package/src/app/lib/credit-coverage.test.ts +83 -0
- package/src/app/lib/credit-coverage.tsx +48 -0
- package/src/app/lib/free-credit-gap.test.ts +32 -1
- package/src/app/lib/free-credit-gap.tsx +32 -2
- package/src/app/lib/integration-connect-analytics.test.ts +1 -0
- package/src/app/lib/integration-connect-analytics.tsx +4 -0
- package/src/app/lib/models-route.test.ts +18 -0
- package/src/app/lib/models-route.tsx +26 -4
- package/src/app/lib/session-search-route.tsx +6 -1
- package/src/app/lib/session-ui-features.tsx +28 -9
- package/src/app/routes/session.tsx +74 -16
- package/src/app/routes/sessions-index.tsx +83 -4
- package/src/components/timeline-annotation-selection.tsx +9 -64
- package/src/components/timeline-annotation-shared.ts +9 -57
- package/src/hooks/page-wake.ts +80 -0
- package/src/hooks/use-session-events.ts +309 -81
- package/src/lib/format.ts +3 -2
- package/src/messages/en.ts +13 -3
- package/src/model-picker-model.ts +3 -0
- package/src/model-policy.ts +9 -1
- package/src/session.ts +1 -0
- package/src/timeline/annotation-model.ts +217 -0
- package/src/timeline/projection.ts +27 -21
- package/src/timeline-model.ts +14 -0
- package/src/ui/context-menu.tsx +16 -0
- package/src/ui/dropdown-menu.tsx +4 -1
- package/src/ui/segmented-control.tsx +3 -0
- package/styles/compiled.css +92 -0
- package/dist/app/lib/keyboard-shortcuts.d.ts +0 -51
- package/dist/app/lib/keyboard-shortcuts.js +0 -16
- package/dist/chunk-2MXUB3ZO.js.map +0 -1
- package/dist/chunk-2RIUMV7S.js.map +0 -1
- package/dist/chunk-53IXIUYP.js +0 -39
- package/dist/chunk-53IXIUYP.js.map +0 -1
- package/dist/chunk-DN3TKURW.js.map +0 -1
- package/dist/chunk-F2GXK2Z6.js.map +0 -1
- package/dist/chunk-G7VLL3PG.js.map +0 -1
- package/dist/chunk-GRLPRM56.js.map +0 -1
- package/dist/chunk-HUQHJSPV.js.map +0 -1
- package/dist/chunk-IO6K6UYJ.js.map +0 -1
- package/dist/chunk-KWB5U3ZT.js.map +0 -1
- package/dist/chunk-L5UCO2UV.js.map +0 -1
- package/dist/chunk-MOF3XSUM.js.map +0 -1
- package/dist/chunk-N2BEUKXT.js.map +0 -1
- package/dist/chunk-OS3EQOIS.js.map +0 -1
- package/dist/chunk-OYJY4Y4A.js.map +0 -1
- package/dist/chunk-Q2ZJOECN.js.map +0 -1
- package/dist/chunk-QWCTYLMD.js.map +0 -1
- package/dist/chunk-RZV7SXED.js.map +0 -1
- package/dist/chunk-S3M5WCZW.js.map +0 -1
- package/dist/chunk-SOOWLNC5.js.map +0 -1
- package/dist/chunk-SWWYYGQO.js.map +0 -1
- package/dist/chunk-UO36FC3S.js.map +0 -1
- package/dist/chunk-UYSZKDQY.js.map +0 -1
- package/dist/chunk-VE3FKXJ7.js.map +0 -1
- package/dist/chunk-VVFWOBAM.js.map +0 -1
- package/dist/chunk-ZSERYHHT.js.map +0 -1
- package/dist/timeline-annotation-selection-2IA7T5VR.js.map +0 -1
- package/src/app/lib/keyboard-shortcuts.test.ts +0 -47
- package/src/app/lib/keyboard-shortcuts.tsx +0 -58
- /package/dist/app/{lib/keyboard-shortcuts.js.map → components/command-menu/keycaps.js.map} +0 -0
- /package/dist/{browser-viewer-ZRFZX3VN.js.map → app/components/credits/credit-refusal-notice.js.map} +0 -0
- /package/dist/{chat-interactive-block-HUMYWVCK.js.map → app/lib/actions/actions-provider.js.map} +0 -0
- /package/dist/{computer-viewer-D4NHQB5D.js.map → app/lib/credit-coverage.js.map} +0 -0
- /package/dist/{embedded-new-voice-X4ZW6SY4.js.map → browser-viewer-HPUMK7UP.js.map} +0 -0
- /package/dist/{embedded-voice-4OD6Z3HU.js.map → chat-interactive-block-22PPECCT.js.map} +0 -0
- /package/dist/{chunk-GVIQ7H62.js.map → chunk-2LUBBDZV.js.map} +0 -0
- /package/dist/{chunk-XMMVIY7B.js.map → chunk-3CCJWHQY.js.map} +0 -0
- /package/dist/{chunk-XS2FZ6DX.js.map → chunk-3F5ZPIWI.js.map} +0 -0
- /package/dist/{chunk-72US6QNB.js.map → chunk-3J2YZRY5.js.map} +0 -0
- /package/dist/{chunk-D4YQF4E3.js.map → chunk-3SMJ2BIQ.js.map} +0 -0
- /package/dist/{chunk-TBJINQXA.js.map → chunk-3WCYK36X.js.map} +0 -0
- /package/dist/{chunk-WPCF34V6.js.map → chunk-3WG3CRL7.js.map} +0 -0
- /package/dist/{chunk-JI5BYQKO.js.map → chunk-3X46PNBX.js.map} +0 -0
- /package/dist/{chunk-PBK44WJC.js.map → chunk-4GJ37O6G.js.map} +0 -0
- /package/dist/{chunk-LEXPBQ56.js.map → chunk-4SKJX3C4.js.map} +0 -0
- /package/dist/{chunk-ZA6YD2LW.js.map → chunk-57SYK776.js.map} +0 -0
- /package/dist/{chunk-22LBKJDE.js.map → chunk-5DIAN5GQ.js.map} +0 -0
- /package/dist/{chunk-LJ3TDK2L.js.map → chunk-5FA455GR.js.map} +0 -0
- /package/dist/{chunk-YPR5INHV.js.map → chunk-5X3E2Z3D.js.map} +0 -0
- /package/dist/{chunk-OXNWZTEU.js.map → chunk-5ZJCL6X4.js.map} +0 -0
- /package/dist/{chunk-62OAZ4LO.js.map → chunk-6C5GQQMC.js.map} +0 -0
- /package/dist/{chunk-VGITH57T.js.map → chunk-6ERTXDZM.js.map} +0 -0
- /package/dist/{chunk-ZQ7XQZCF.js.map → chunk-6FX73Y4I.js.map} +0 -0
- /package/dist/{chunk-QZO2KK2F.js.map → chunk-6P44NG6Y.js.map} +0 -0
- /package/dist/{chunk-N2DDJLTM.js.map → chunk-6T7Y33JA.js.map} +0 -0
- /package/dist/{chunk-RBAGC2MJ.js.map → chunk-75VE5QUS.js.map} +0 -0
- /package/dist/{chunk-MRXOGI3O.js.map → chunk-77CUDSHG.js.map} +0 -0
- /package/dist/{chunk-GZ65XQR5.js.map → chunk-7T7FHSGS.js.map} +0 -0
- /package/dist/{chunk-YGAH34CD.js.map → chunk-A3S26JSP.js.map} +0 -0
- /package/dist/{chunk-GYPAO6RS.js.map → chunk-A664GSDM.js.map} +0 -0
- /package/dist/{chunk-JSZSNMDR.js.map → chunk-ASUYLXKO.js.map} +0 -0
- /package/dist/{chunk-RTK7SUPL.js.map → chunk-AUUJLVA3.js.map} +0 -0
- /package/dist/{chunk-OOTBYSCA.js.map → chunk-BBWKPNJB.js.map} +0 -0
- /package/dist/{chunk-BGZIMIUU.js.map → chunk-BCUYWOQU.js.map} +0 -0
- /package/dist/{chunk-EKN4N4LS.js.map → chunk-BDFMNJZJ.js.map} +0 -0
- /package/dist/{chunk-YZKGOWCC.js.map → chunk-BIDXQAGO.js.map} +0 -0
- /package/dist/{chunk-Q2UUANHF.js.map → chunk-BIKAJ4DY.js.map} +0 -0
- /package/dist/{chunk-5IQBF2X3.js.map → chunk-BJPJ2OUX.js.map} +0 -0
- /package/dist/{chunk-EY2EMHZW.js.map → chunk-BPM2OTYK.js.map} +0 -0
- /package/dist/{chunk-MT4TBRQB.js.map → chunk-BSWS2RUZ.js.map} +0 -0
- /package/dist/{chunk-T7YD3VGK.js.map → chunk-C52MNKXU.js.map} +0 -0
- /package/dist/{chunk-THNW33K7.js.map → chunk-CEUDV4OA.js.map} +0 -0
- /package/dist/{chunk-LHGIS6SZ.js.map → chunk-CVK74BH7.js.map} +0 -0
- /package/dist/{chunk-DFO2UCYG.js.map → chunk-CW5I65ZX.js.map} +0 -0
- /package/dist/{chunk-SKRLKQEG.js.map → chunk-DOSC2HRQ.js.map} +0 -0
- /package/dist/{chunk-KVB6XDLP.js.map → chunk-DPJ2CWVN.js.map} +0 -0
- /package/dist/{chunk-4J6V4DH7.js.map → chunk-DXMRO2MU.js.map} +0 -0
- /package/dist/{chunk-42I4O4WQ.js.map → chunk-EE55IDDR.js.map} +0 -0
- /package/dist/{chunk-2RA6XABP.js.map → chunk-EEERTLFF.js.map} +0 -0
- /package/dist/{chunk-PTOTKUKO.js.map → chunk-EEO744XR.js.map} +0 -0
- /package/dist/{chunk-LD3HVI2J.js.map → chunk-EMFGBAQL.js.map} +0 -0
- /package/dist/{chunk-FQGUK4ST.js.map → chunk-ENPJKVMN.js.map} +0 -0
- /package/dist/{chunk-HDHK3SXK.js.map → chunk-EU6RLHMP.js.map} +0 -0
- /package/dist/{chunk-MRUWRQBX.js.map → chunk-FET6XHGS.js.map} +0 -0
- /package/dist/{chunk-M6KUY3YH.js.map → chunk-FIICQA55.js.map} +0 -0
- /package/dist/{chunk-NLWLCYCT.js.map → chunk-FTZXCPE3.js.map} +0 -0
- /package/dist/{chunk-FN2KA3MJ.js.map → chunk-FUS76DO4.js.map} +0 -0
- /package/dist/{chunk-AM4IIPWI.js.map → chunk-G7N5NPRJ.js.map} +0 -0
- /package/dist/{chunk-CCQ7YKOD.js.map → chunk-GBYZ6653.js.map} +0 -0
- /package/dist/{chunk-YKKVIJVX.js.map → chunk-GQDSC6QZ.js.map} +0 -0
- /package/dist/{chunk-5X6JP75Q.js.map → chunk-GRSODLVO.js.map} +0 -0
- /package/dist/{chunk-73YP3R5X.js.map → chunk-GSESCQFY.js.map} +0 -0
- /package/dist/{chunk-MZLEBFUZ.js.map → chunk-GZD6VBIK.js.map} +0 -0
- /package/dist/{chunk-IZR2QRFF.js.map → chunk-H3HH5AHS.js.map} +0 -0
- /package/dist/{chunk-OJPUVUB6.js.map → chunk-HAOZCLLA.js.map} +0 -0
- /package/dist/{chunk-ZBHDGAYL.js.map → chunk-HEFE4OZJ.js.map} +0 -0
- /package/dist/{chunk-WTG34JVA.js.map → chunk-HI75UTI6.js.map} +0 -0
- /package/dist/{chunk-OMBIG3NC.js.map → chunk-HM633ROV.js.map} +0 -0
- /package/dist/{chunk-WDFZWSKD.js.map → chunk-HRIP4M6H.js.map} +0 -0
- /package/dist/{chunk-A2BCW6CQ.js.map → chunk-HU2DRFFI.js.map} +0 -0
- /package/dist/{chunk-PO35PBAB.js.map → chunk-HVH7FFJH.js.map} +0 -0
- /package/dist/{chunk-EG7KNUF7.js.map → chunk-HYTXTKST.js.map} +0 -0
- /package/dist/{chunk-TFHG75A4.js.map → chunk-I4XMDFUJ.js.map} +0 -0
- /package/dist/{chunk-IZHVZZQA.js.map → chunk-ICAUYWSL.js.map} +0 -0
- /package/dist/{chunk-DCLPWYP3.js.map → chunk-IEVPJ3G6.js.map} +0 -0
- /package/dist/{chunk-EVWZHDSF.js.map → chunk-IKH3VTA4.js.map} +0 -0
- /package/dist/{chunk-TYHLEFD2.js.map → chunk-IZJNMRIR.js.map} +0 -0
- /package/dist/{chunk-D2SR3TEB.js.map → chunk-J243WGUA.js.map} +0 -0
- /package/dist/{chunk-QGSGIYE3.js.map → chunk-J2C6LB6W.js.map} +0 -0
- /package/dist/{chunk-MT6TRTXF.js.map → chunk-J5MEDX7C.js.map} +0 -0
- /package/dist/{chunk-6QHUKBJP.js.map → chunk-J7SKOO44.js.map} +0 -0
- /package/dist/{chunk-W2QK7PYS.js.map → chunk-JAAST75A.js.map} +0 -0
- /package/dist/{chunk-NQCMS4AJ.js.map → chunk-JQCGPTZ6.js.map} +0 -0
- /package/dist/{chunk-CMUXJHGH.js.map → chunk-JRSCWQMC.js.map} +0 -0
- /package/dist/{chunk-Q4OHNGGB.js.map → chunk-JRXHSVD5.js.map} +0 -0
- /package/dist/{chunk-SD2K5ZN5.js.map → chunk-JXYLDT6X.js.map} +0 -0
- /package/dist/{chunk-IXX6ZOL2.js.map → chunk-KGTMHEAP.js.map} +0 -0
- /package/dist/{chunk-22OBGVEJ.js.map → chunk-KOXVGPW4.js.map} +0 -0
- /package/dist/{chunk-NOZ5CGZE.js.map → chunk-L5GPPMUB.js.map} +0 -0
- /package/dist/{chunk-4FOOHMTU.js.map → chunk-LY6727IF.js.map} +0 -0
- /package/dist/{chunk-PT7MTXRE.js.map → chunk-MAOCN7J6.js.map} +0 -0
- /package/dist/{chunk-4K2JSJNX.js.map → chunk-MB5LZVDO.js.map} +0 -0
- /package/dist/{chunk-5LES64PP.js.map → chunk-MKOQAVOE.js.map} +0 -0
- /package/dist/{chunk-BMV2SNYX.js.map → chunk-MUPWNSEJ.js.map} +0 -0
- /package/dist/{chunk-Y5TRG22C.js.map → chunk-NRXIECWC.js.map} +0 -0
- /package/dist/{chunk-GOE7G5JX.js.map → chunk-NWSAF6P5.js.map} +0 -0
- /package/dist/{chunk-DUM363VS.js.map → chunk-OFZQJNF6.js.map} +0 -0
- /package/dist/{chunk-CKN5QPEL.js.map → chunk-OMF7POEY.js.map} +0 -0
- /package/dist/{chunk-MVXKO2BD.js.map → chunk-OXD6ET34.js.map} +0 -0
- /package/dist/{chunk-47JUEVME.js.map → chunk-PALX6HWV.js.map} +0 -0
- /package/dist/{chunk-B6OGSG7I.js.map → chunk-PE3BLBDT.js.map} +0 -0
- /package/dist/{chunk-RVISSNVE.js.map → chunk-PMZKJOG6.js.map} +0 -0
- /package/dist/{chunk-CESAMXWX.js.map → chunk-PQUTMG3S.js.map} +0 -0
- /package/dist/{chunk-7VFCOKPG.js.map → chunk-PWBGODZU.js.map} +0 -0
- /package/dist/{chunk-MOPAXD2H.js.map → chunk-QCADUTYX.js.map} +0 -0
- /package/dist/{chunk-CT5FBO7E.js.map → chunk-RPOUJI25.js.map} +0 -0
- /package/dist/{chunk-WKHYOS72.js.map → chunk-RW4GFE56.js.map} +0 -0
- /package/dist/{chunk-FH4GO7HO.js.map → chunk-RYLVVDR7.js.map} +0 -0
- /package/dist/{chunk-QZRDCFHI.js.map → chunk-S66SBBFQ.js.map} +0 -0
- /package/dist/{chunk-CQJFIPAH.js.map → chunk-S7TNV2I7.js.map} +0 -0
- /package/dist/{chunk-ZBQSIGGR.js.map → chunk-SC773IMJ.js.map} +0 -0
- /package/dist/{chunk-FBJ2HK7A.js.map → chunk-SGPJ3YS2.js.map} +0 -0
- /package/dist/{chunk-A2EWJQXX.js.map → chunk-SM5QX6UK.js.map} +0 -0
- /package/dist/{chunk-RKZWCTXV.js.map → chunk-TAEKDMEF.js.map} +0 -0
- /package/dist/{chunk-6AVCAUGL.js.map → chunk-TASEV25T.js.map} +0 -0
- /package/dist/{chunk-3XOISKZC.js.map → chunk-TLGDPMUX.js.map} +0 -0
- /package/dist/{chunk-5IUW34PG.js.map → chunk-TY3QYPJ6.js.map} +0 -0
- /package/dist/{chunk-VQFR4EU4.js.map → chunk-U3JK5VJV.js.map} +0 -0
- /package/dist/{chunk-2AWMJO54.js.map → chunk-U42P3RMZ.js.map} +0 -0
- /package/dist/{chunk-GUU75DES.js.map → chunk-UEJTOPLW.js.map} +0 -0
- /package/dist/{chunk-OZOEWLGR.js.map → chunk-UT6JAORE.js.map} +0 -0
- /package/dist/{chunk-5TELOQA6.js.map → chunk-UTHPUINA.js.map} +0 -0
- /package/dist/{chunk-26RQ6JBR.js.map → chunk-VBVCNH6D.js.map} +0 -0
- /package/dist/{chunk-P646DND6.js.map → chunk-VCMQPCME.js.map} +0 -0
- /package/dist/{chunk-LV7FMIMM.js.map → chunk-VGUHAHHV.js.map} +0 -0
- /package/dist/{chunk-GYVXARCY.js.map → chunk-VIBPFVU4.js.map} +0 -0
- /package/dist/{chunk-KHPOKZ6Z.js.map → chunk-VMAC66JX.js.map} +0 -0
- /package/dist/{chunk-SHKRS6I5.js.map → chunk-VRPNETPK.js.map} +0 -0
- /package/dist/{chunk-6U4J6RVS.js.map → chunk-WCHW4XN7.js.map} +0 -0
- /package/dist/{chunk-CJH6QUQJ.js.map → chunk-WD3UXNJV.js.map} +0 -0
- /package/dist/{chunk-H5EVWF6L.js.map → chunk-WR67FJMX.js.map} +0 -0
- /package/dist/{chunk-XLIJ36RG.js.map → chunk-WRMQ7EX4.js.map} +0 -0
- /package/dist/{chunk-7KLCFJ5G.js.map → chunk-X4PPGXQG.js.map} +0 -0
- /package/dist/{chunk-ZE2JTVCQ.js.map → chunk-X5BMQXFD.js.map} +0 -0
- /package/dist/{chunk-UECU6LZI.js.map → chunk-XXRBOSWV.js.map} +0 -0
- /package/dist/{chunk-SPKAIDWX.js.map → chunk-XZEFCPBL.js.map} +0 -0
- /package/dist/{chunk-EZ5NYRHK.js.map → chunk-YL6N7QLA.js.map} +0 -0
- /package/dist/{chunk-VAIESMPY.js.map → chunk-YVBHGMKC.js.map} +0 -0
- /package/dist/{chunk-AR62NQXE.js.map → chunk-Z2S5VQG7.js.map} +0 -0
- /package/dist/{chunk-7UQJEADK.js.map → chunk-ZL2O4BYP.js.map} +0 -0
- /package/dist/{chunk-FOOITLHR.js.map → chunk-ZZHBT5WQ.js.map} +0 -0
- /package/dist/{chunk-X6VJQJYY.js.map → chunk-ZZWHKC6A.js.map} +0 -0
- /package/dist/{model-policy-picker-menu-XOPYY6YA.js.map → computer-viewer-S6TE6TN7.js.map} +0 -0
- /package/dist/{sandbox-files-LJCR437H.js.map → embedded-new-voice-ZDZPGX25.js.map} +0 -0
- /package/dist/{session-realtime-UISLBZ4A.js.map → embedded-voice-FKCUXSJO.js.map} +0 -0
- /package/dist/{fleet-decision-row-5UCJXTDP.js.map → fleet-decision-row-VCGWYJAV.js.map} +0 -0
- /package/dist/{latest-question-VGVNUGAU.js.map → latest-question-SINEV4U6.js.map} +0 -0
- /package/dist/{platform-activity-row-56XOVTRA.js.map → platform-activity-row-LU5WABI2.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ui/segmented-control.tsx"],"sourcesContent":["import { useId, useState, type ComponentProps, type ReactNode } from \"react\";\nimport { Loader2Icon } from \"lucide-react\";\nimport { ToggleGroup as ToggleGroupPrimitive } from \"radix-ui\";\nimport { cn } from \"../lib/cn\";\nimport { DisabledReasonTooltip, joinIds, useSettingRowField } from \"./setting-row\";\n\n/**\n * - `filled` (default): a soft surface-2 track; the active option is raised on\n * the surface with a hairline and a small shadow. For settings and filters\n * alike.\n * - `outlined`: a bordered button group; the active option takes the brand\n * tint, like the app-wide selected highlight.\n * - `underline`: text options with a brand underline. Only for view filters.\n */\nexport type SegmentedControlVariant = \"filled\" | \"outlined\" | \"underline\";\n\n/**\n * `md` is 36px tall (forms, page toolbars); `sm` is 32px (setting rows, list\n * toolbars), the same height as a select in a row.\n */\nexport type SegmentedControlSize = \"md\" | \"sm\";\n\nexport interface SegmentedControlOption<Value extends string = string> {\n value: Value;\n /** Short: one or two words. */\n label: ReactNode;\n /** A trailing 11px count, for filters (\"Invited 2\"). */\n count?: number | string | undefined;\n /** Optional 14px leading icon. */\n icon?: ReactNode | undefined;\n /** Hides the label visually (icon-only option); it stays the accessible name. */\n iconOnly?: boolean | undefined;\n disabled?: boolean | undefined;\n /**\n * Why this option can't be picked and who can fix it. With `disabled`, the\n * option stays focusable and shows the reason on hover, focus and tap.\n */\n disabledReason?: ReactNode | undefined;\n}\n\nexport interface SegmentedControlProps<Value extends string = string> extends Omit<\n ComponentProps<\"div\">,\n \"defaultValue\" | \"onChange\" | \"dir\" | \"children\"\n> {\n /** 2 to 4 options. Use a select for more. */\n options: readonly SegmentedControlOption<Value>[];\n value?: Value | undefined;\n defaultValue?: Value | undefined;\n onValueChange?: ((value: Value) => void) | undefined;\n variant?: SegmentedControlVariant | undefined;\n size?: SegmentedControlSize | undefined;\n /** Disables every option. */\n disabled?: boolean | undefined;\n /** Saving the new value: a spinner replaces the active option's label, which keeps its width. */\n pending?: boolean | undefined;\n /** Stretch the options to fill the width (phones, sheets). */\n fullWidth?: boolean | undefined;\n}\n\nexport function SegmentedControl<Value extends string = string>({\n options,\n value: valueProp,\n defaultValue,\n onValueChange,\n variant = \"filled\",\n size = \"md\",\n disabled = false,\n pending = false,\n fullWidth = false,\n className,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledByProp,\n \"aria-describedby\": ariaDescribedByProp,\n ...props\n}: SegmentedControlProps<Value>) {\n const field = useSettingRowField();\n const reasonBaseId = useId();\n const [uncontrolled, setUncontrolled] = useState<Value | undefined>(\n defaultValue ?? options.find((option) => !option.disabled)?.value,\n );\n const value = valueProp ?? uncontrolled;\n\n const select = (next: string) => {\n // Radix sends \"\" when the active option is pressed again; one option always stays on.\n if (!next || next === value) return;\n const option = options.find((candidate) => candidate.value === next);\n if (!option || option.disabled) return;\n if (valueProp === undefined) setUncontrolled(option.value);\n onValueChange?.(option.value);\n };\n\n const reasons = options.flatMap((option, index) =>\n option.disabled && option.disabledReason\n ? [{ id: `${reasonBaseId}-${index}`, index, reason: option.disabledReason }]\n : [],\n );\n\n return (\n <>\n <ToggleGroupPrimitive.Root\n type=\"single\"\n data-slot=\"segmented-control\"\n data-variant={variant}\n data-size={size}\n value={value ?? \"\"}\n onValueChange={select}\n disabled={disabled}\n loop\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledByProp ?? (ariaLabel ? undefined : field?.labelId)}\n aria-describedby={joinIds(ariaDescribedByProp, field?.describedBy)}\n aria-busy={pending || undefined}\n className={cn(\n \"min-w-0 items-center\",\n fullWidth ? \"flex w-full\" : \"inline-flex max-w-full\",\n variant === \"filled\" && \"gap-0.5 rounded-[10px] bg-surface-2 p-0.75\",\n variant === \"outlined\" && \"isolate\",\n variant === \"underline\" && \"gap-4\",\n className,\n )}\n {...props}\n >\n {options.map((option, index) => {\n const active = option.value === value;\n const busy = pending && active;\n const reason = reasons.find((entry) => entry.index === index);\n const item = (\n <ToggleGroupPrimitive.Item\n key={option.value}\n value={option.value}\n data-slot=\"segmented-control-item\"\n disabled={option.disabled && !reason}\n aria-disabled={reason ? true : undefined}\n aria-describedby={reason?.id}\n aria-label={\n option.iconOnly && typeof option.label === \"string\" ? option.label : undefined\n }\n className={cn(\n itemClasses(variant, size),\n option.iconOnly && variant !== \"underline\" && \"px-2\",\n fullWidth && \"flex-1\",\n )}\n >\n {/* While saving, the content fades and a spinner takes its place, so\n nothing around the control moves. The label stays readable to\n assistive tech. */}\n <span\n className={cn(\n \"inline-flex min-w-0 items-center gap-1.5 transition-opacity duration-[120ms]\",\n busy && \"opacity-0\",\n )}\n >\n {option.icon ? (\n <span aria-hidden=\"true\" className=\"inline-flex shrink-0 [&_svg]:size-3.5\">\n {option.icon}\n </span>\n ) : null}\n {option.iconOnly ? (\n typeof option.label === \"string\" ? null : (\n <span className=\"sr-only\">{option.label}</span>\n )\n ) : (\n <span className=\"min-w-0 truncate\">{option.label}</span>\n )}\n {option.count !== undefined ? (\n <span\n className={cn(\n \"text-2xs font-medium tabular-nums\",\n active\n ? variant === \"outlined\"\n ? \"text-brand/80\"\n : \"text-fg-muted\"\n : \"text-fg-subtle\",\n )}\n >\n {option.count}\n </span>\n ) : null}\n </span>\n {busy ? (\n <Loader2Icon\n aria-hidden=\"true\"\n className=\"absolute inset-0 m-auto size-3.5 animate-spin\"\n />\n ) : null}\n </ToggleGroupPrimitive.Item>\n );\n return reason ? (\n <DisabledReasonTooltip key={option.value} reason={option.disabledReason}>\n {item}\n </DisabledReasonTooltip>\n ) : (\n item\n );\n })}\n </ToggleGroupPrimitive.Root>\n {reasons.map((entry) => (\n <span key={entry.id} id={entry.id} hidden>\n {entry.reason}\n </span>\n ))}\n </>\n );\n}\n\n// States key on aria-checked, not data-state: a disabled-reason tooltip trigger\n// replaces data-state on the items it wraps.\nfunction itemClasses(variant: SegmentedControlVariant, size: SegmentedControlSize): string {\n const base = cn(\n \"relative inline-flex min-w-0 shrink-0 items-center justify-center gap-1.5 font-medium whitespace-nowrap transition-colors duration-[120ms] ease-out select-none\",\n \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand/55 focus-visible:z-20\",\n \"disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50\",\n // Touch: 44px tall targets without changing the look.\n \"pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:top-1/2 pointer-coarse:after:h-11 pointer-coarse:after:-translate-y-1/2\",\n );\n if (variant === \"filled\") {\n return cn(\n base,\n \"rounded-sm px-3 text-xs text-fg-muted\",\n size === \"md\" ? \"h-7.5\" : \"h-6.5 px-2.5\",\n // Hover only brightens the text: a hover fill would outshine the active option in dark.\n \"enabled:hover:text-fg aria-disabled:hover:text-fg-muted\",\n \"aria-checked:bg-surface aria-checked:text-fg aria-checked:shadow-og-sm aria-checked:ring-1 aria-checked:ring-border\",\n // In dark, surface sits below surface-2; a faint light layer lifts the active\n // option above the track there, and disappears on white.\n \"aria-checked:bg-linear-to-b aria-checked:from-brand-fg/10 aria-checked:to-brand-fg/10\",\n );\n }\n if (variant === \"outlined\") {\n return cn(\n base,\n // `!` keeps the outer corners under the app-wide focus outline radius.\n \"-ml-px border border-border bg-surface px-3 text-xs text-fg-muted first:ml-0 first:rounded-l-[10px]! last:rounded-r-[10px]! not-first:not-last:rounded-none!\",\n size === \"md\" ? \"h-9\" : \"h-8 px-2.5\",\n \"enabled:hover:bg-surface-2 enabled:hover:text-fg aria-disabled:hover:bg-surface aria-disabled:hover:text-fg-muted\",\n \"aria-checked:z-10 aria-checked:border-brand/45 aria-checked:bg-brand/10 aria-checked:text-brand aria-checked:hover:bg-brand/10 aria-checked:hover:text-brand\",\n );\n }\n return cn(\n base,\n // Same 12px type as the other variants; the underline is the only treatment.\n \"rounded-sm px-0.5 text-xs text-fg-muted\",\n size === \"md\" ? \"h-9\" : \"h-8\",\n \"enabled:hover:text-fg aria-disabled:hover:text-fg-muted\",\n // The underline sits on the bottom edge, 2px, brand.\n \"before:absolute before:inset-x-0 before:bottom-0 before:h-0.5 before:rounded-full before:bg-transparent before:transition-colors before:duration-[120ms]\",\n \"aria-checked:text-fg aria-checked:before:bg-brand\",\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/app/lib/integration-connect-analytics.tsx"],"sourcesContent":["// Consent-gated integration connect journey (PostHog through\n// `captureAnalyticsEvent`). Every connect flow for an integration,\n// capability, or model provider reports\n//\n// integration_connect_started{integration_class, method}\n// integration_connect_finished{integration_class, method, outcome}\n//\n// `integration_class` reuses the closed provider classes of the server\n// lifecycle facts (`connection.created` and `model.connected` in\n// @opengeni/contracts product-lifecycle-facts), so browser funnels join the\n// server facts. Only closed values leave the browser: never a provider\n// domain, account, URL, error text, or identifier.\n//\n// Outcomes: `connected`, `denied` (the person or provider refused\n// authorization), `provider_error`, `cancelled` (the person cancelled or\n// closed the authorization window), `abandoned` (best effort: the setup\n// dialog was closed, the page was left, or the person came back from a\n// provider redirect without an outcome), and `outcome_unknown`.\nimport type { PRODUCT_LIFECYCLE_FACT_ATTRIBUTES } from \"@opengeni/contracts\";\nimport { useCallback, useEffect, useRef } from \"react\";\n\nimport { captureAnalyticsEvent } from \"./analytics-observer\";\nimport {\n takeIntegrationConnectReturn,\n type IntegrationConnectReturn,\n} from \"./integration-connect-return\";\n\ntype ConnectionClass = (typeof PRODUCT_LIFECYCLE_FACT_ATTRIBUTES)[\"connection.created\"][number];\ntype ModelClass = (typeof PRODUCT_LIFECYCLE_FACT_ATTRIBUTES)[\"model.connected\"][number];\n\n/** The `connection.created` provider classes (a test keeps them identical). */\nexport const INTEGRATION_CONNECTION_CLASSES = [\n \"slack\",\n \"github\",\n \"gitlab\",\n \"azure_devops\",\n \"bitbucket\",\n \"google\",\n \"microsoft\",\n \"linear\",\n \"atlassian\",\n \"notion\",\n \"supabase\",\n \"datadog\",\n \"posthog\",\n \"openai\",\n \"x\",\n \"other\",\n] as const satisfies readonly ConnectionClass[];\n\n/** The `model.connected` provider classes (a test keeps them identical). */\nexport const MODEL_CONNECTION_CLASSES = [\n \"codex\",\n \"supergrok\",\n \"vercel_gateway\",\n \"openrouter\",\n \"anthropic\",\n \"claude_subscription\",\n \"opper\",\n \"elevenlabs\",\n] as const satisfies readonly ModelClass[];\n\nexport type IntegrationClass = ConnectionClass | ModelClass;\n\nexport const INTEGRATION_CONNECT_METHODS = [\n \"oauth\",\n \"api_key\",\n \"device_code\",\n \"app_install\",\n \"custom\",\n] as const;\nexport type IntegrationConnectMethod = (typeof INTEGRATION_CONNECT_METHODS)[number];\n\nexport const INTEGRATION_CONNECT_OUTCOMES = [\n \"connected\",\n \"denied\",\n \"provider_error\",\n \"cancelled\",\n \"abandoned\",\n \"outcome_unknown\",\n] as const;\nexport type IntegrationConnectOutcome = (typeof INTEGRATION_CONNECT_OUTCOMES)[number];\n\nconst DOMAIN_CLASSES: ReadonlyArray<readonly [ConnectionClass, readonly string[]]> = [\n [\"slack\", [\"slack.com\"]],\n [\"github\", [\"github.com\"]],\n [\"gitlab\", [\"gitlab.com\"]],\n [\"azure_devops\", [\"dev.azure.com\", \"visualstudio.com\"]],\n [\"bitbucket\", [\"bitbucket.org\"]],\n [\"google\", [\"google.com\", \"googleapis.com\"]],\n [\"microsoft\", [\"microsoft.com\", \"office.com\", \"microsoftonline.com\"]],\n [\"linear\", [\"linear.app\"]],\n [\"atlassian\", [\"atlassian.com\", \"atlassian.net\"]],\n [\"notion\", [\"notion.so\", \"notion.com\"]],\n [\"supabase\", [\"supabase.com\", \"supabase.co\"]],\n [\"datadog\", [\"datadoghq.com\", \"datadog.com\", \"datadoghq.eu\"]],\n [\"posthog\", [\"posthog.com\"]],\n [\"openai\", [\"openai.com\", \"chatgpt.com\"]],\n [\"x\", [\"x.com\", \"twitter.com\"]],\n];\n\n/**\n * The provider class of a connection domain or MCP host, mirroring\n * `opengeni_private.product_lifecycle_connection_class` (migration 0532).\n */\nexport function integrationClassFromDomain(domain: string | null | undefined): ConnectionClass {\n let host = (domain ?? \"\").trim().toLowerCase();\n try {\n if (host.includes(\"/\")) host = new URL(host).hostname;\n } catch {\n return \"other\";\n }\n for (const [integrationClass, roots] of DOMAIN_CLASSES) {\n if (\n roots.some((root) =>\n integrationClass === \"azure_devops\" && root === \"dev.azure.com\"\n ? host === root\n : host === root || host.endsWith(`.${root}`),\n )\n ) {\n return integrationClass;\n }\n }\n return \"other\";\n}\n\nconst CONNECT_PROVIDER_CLASSES: ReadonlyArray<readonly [RegExp, ConnectionClass]> = [\n [/^slack(-|$)/, \"slack\"],\n [/^github(-|$)/, \"github\"],\n [/^(google-drive|gmail)(-|$)/, \"google\"],\n [/^(microsoft|outlook|onedrive)(-|$)/, \"microsoft\"],\n [/^atlassian(-|$)/, \"atlassian\"],\n [/^x$/, \"x\"],\n];\n\n/** The provider class of a Connect API `providerId` (for example `slack-bot`). */\nexport function integrationClassFromConnectProvider(providerId: string): ConnectionClass {\n return CONNECT_PROVIDER_CLASSES.find(([pattern]) => pattern.test(providerId))?.[1] ?? \"other\";\n}\n\n/** The `model.connected` class of a model provider name used in the console. */\nexport function modelConnectionClass(provider: string): ModelClass | null {\n switch (provider) {\n case \"codex\":\n case \"supergrok\":\n case \"openrouter\":\n case \"opper\":\n case \"anthropic\":\n case \"claude_subscription\":\n case \"elevenlabs\":\n return provider;\n case \"ai-gateway\":\n case \"vercel_gateway\":\n case \"vercel_ai_gateway\":\n case \"gateway\":\n return \"vercel_gateway\";\n default:\n return null;\n }\n}\n\n/** The outcome of a failed connect request or authorization. */\nexport function integrationConnectErrorOutcome(error: unknown): IntegrationConnectOutcome {\n const name =\n typeof error === \"object\" && error !== null ? (error as { name?: unknown }).name : undefined;\n if (name === \"AbortError\" || name === \"ConnectPopupClosedError\") return \"cancelled\";\n const status =\n typeof error === \"object\" && error !== null\n ? (error as { status?: unknown }).status\n : undefined;\n if (typeof status === \"number\" && status >= 400 && status < 600) return \"provider_error\";\n return \"outcome_unknown\";\n}\n\n/** The outcome of a settled Connect API attempt, or null while it is still in progress. */\nexport function connectAttemptOutcome(attempt: {\n state: string;\n error?: { code: string } | undefined;\n}): IntegrationConnectOutcome | null {\n switch (attempt.state) {\n case \"complete\":\n return \"connected\";\n case \"cancelled\":\n return \"cancelled\";\n case \"expired\":\n return \"abandoned\";\n case \"uncertain\":\n return \"outcome_unknown\";\n case \"failed\":\n return /denied/i.test(attempt.error?.code ?? \"\") ? \"denied\" : \"provider_error\";\n default:\n return null;\n }\n}\n\nexport type IntegrationConnectTracker = {\n /** Report the outcome. Only the first call reports. */\n finish(outcome: IntegrationConnectOutcome): void;\n /**\n * The page is about to leave for the provider. The journey finishes when\n * the browser returns (see `captureIntegrationConnectReturn`), so leaving\n * the page is not reported as `abandoned`.\n */\n redirecting(options?: { returnsWithOutcome?: boolean | undefined }): void;\n};\n\ntype Capture = (\n name: \"integration_connect_started\" | \"integration_connect_finished\",\n properties: Record<string, string>,\n) => boolean;\n\nconst REDIRECT_MARKER_KEY = \"opengeni.analytics.integrationConnect\";\nconst REDIRECT_MARKER_MAX_AGE_MS = 60 * 60_000;\ntype RedirectMarker = {\n integrationClass: IntegrationClass;\n method: IntegrationConnectMethod;\n returnsWithOutcome: boolean;\n startedAt: number;\n};\n\nconst pending = new Set<{ abandon(): void }>();\nlet pageHideInstalled = false;\n\nfunction installPageHide(): void {\n if (pageHideInstalled || typeof window === \"undefined\") return;\n pageHideInstalled = true;\n window.addEventListener(\"pagehide\", () => {\n for (const tracker of [...pending]) tracker.abandon();\n });\n}\n\nfunction sessionStore(): Storage | null {\n try {\n return typeof window === \"undefined\" ? null : window.sessionStorage;\n } catch {\n return null;\n }\n}\n\n/**\n * Start a connect journey. `capture` defaults to the consent-gated product\n * analytics; when collection is not allowed nothing is reported or stored.\n */\nexport function beginIntegrationConnect(\n integrationClass: IntegrationClass,\n method: IntegrationConnectMethod,\n options: {\n capture?: Capture | undefined;\n storage?: Storage | null | undefined;\n now?: (() => number) | undefined;\n } = {},\n): IntegrationConnectTracker {\n const capture: Capture = options.capture ?? captureAnalyticsEvent;\n const properties = { integration_class: integrationClass, method };\n let accepted = false;\n try {\n accepted = capture(\"integration_connect_started\", properties);\n } catch {\n accepted = false;\n }\n let settled = false;\n const entry = { abandon: () => finish(\"abandoned\") };\n function finish(outcome: IntegrationConnectOutcome) {\n if (settled) return;\n settled = true;\n pending.delete(entry);\n if (!accepted) return;\n try {\n capture(\"integration_connect_finished\", { ...properties, outcome });\n } catch {\n // Optional telemetry cannot fail product work.\n }\n }\n if (accepted) {\n pending.add(entry);\n installPageHide();\n }\n return {\n finish,\n redirecting({ returnsWithOutcome = true } = {}) {\n if (settled) return;\n settled = true;\n pending.delete(entry);\n if (!accepted) return;\n const marker: RedirectMarker = {\n integrationClass,\n method,\n returnsWithOutcome,\n startedAt: (options.now ?? Date.now)(),\n };\n try {\n (options.storage === undefined ? sessionStore() : options.storage)?.setItem(\n REDIRECT_MARKER_KEY,\n JSON.stringify(marker),\n );\n } catch {\n // Without the marker the return still reports its outcome as `other`.\n }\n },\n };\n}\n\nfunction readRedirectMarker(storage: Storage | null, now: number): RedirectMarker | null {\n if (!storage) return null;\n let raw: string | null = null;\n try {\n raw = storage.getItem(REDIRECT_MARKER_KEY);\n storage.removeItem(REDIRECT_MARKER_KEY);\n } catch {\n return null;\n }\n if (!raw) return null;\n try {\n const marker = JSON.parse(raw) as Partial<RedirectMarker>;\n const known: readonly string[] = [\n ...INTEGRATION_CONNECTION_CLASSES,\n ...MODEL_CONNECTION_CLASSES,\n ];\n if (\n typeof marker.integrationClass !== \"string\" ||\n !known.includes(marker.integrationClass) ||\n !INTEGRATION_CONNECT_METHODS.includes(marker.method as IntegrationConnectMethod) ||\n typeof marker.startedAt !== \"number\" ||\n now - marker.startedAt > REDIRECT_MARKER_MAX_AGE_MS\n ) {\n return null;\n }\n return marker as RedirectMarker;\n } catch {\n return null;\n }\n}\n\nconst RETURN_CLASSES: Partial<Record<IntegrationConnectReturn[\"parameter\"], ConnectionClass>> = {\n slack: \"slack\",\n google_drive: \"google\",\n atlassian: \"atlassian\",\n github_personal_oauth: \"github\",\n github: \"github\",\n};\n\n/** The closed outcome of a provider return parameter. */\nexport function integrationConnectReturnOutcome(\n value: IntegrationConnectReturn,\n): IntegrationConnectOutcome {\n if ([\"success\", \"connected\", \"complete\"].includes(value.status)) return \"connected\";\n // A GitHub install request waits on an organization owner; nothing failed yet.\n if (value.parameter === \"github\" && value.status === \"requested\") return \"outcome_unknown\";\n const reason = value.reason ?? \"\";\n if (/denied/i.test(reason)) return \"denied\";\n if (/cancel/i.test(reason)) return \"cancelled\";\n if (/^(state_expired|missing_code)$/.test(reason)) return \"abandoned\";\n if (/timeout/i.test(reason)) return \"outcome_unknown\";\n return \"provider_error\";\n}\n\n/**\n * Finish a redirect connect journey once analytics collection is active:\n * report the outcome of the provider return parameters this document loaded\n * with, or `abandoned` (`outcome_unknown` for flows whose return carries no\n * outcome) when a redirect started in this tab and the person came back\n * without one.\n */\nexport function captureIntegrationConnectReturn(\n options: {\n returned?: IntegrationConnectReturn | null | undefined;\n capture?: Capture | undefined;\n storage?: Storage | null | undefined;\n now?: (() => number) | undefined;\n } = {},\n): void {\n const returned =\n options.returned === undefined ? takeIntegrationConnectReturn() : options.returned;\n const marker = readRedirectMarker(\n options.storage === undefined ? sessionStore() : options.storage,\n (options.now ?? Date.now)(),\n );\n if (!returned && !marker) return;\n const capture: Capture = options.capture ?? captureAnalyticsEvent;\n const integrationClass: IntegrationClass =\n marker?.integrationClass ??\n (returned\n ? (RETURN_CLASSES[returned.parameter] ??\n (returned.providerDomain ? integrationClassFromDomain(returned.providerDomain) : \"other\"))\n : \"other\");\n const outcome: IntegrationConnectOutcome = returned\n ? integrationConnectReturnOutcome(returned)\n : marker?.returnsWithOutcome\n ? \"abandoned\"\n : \"outcome_unknown\";\n try {\n capture(\"integration_connect_finished\", {\n integration_class: integrationClass,\n method: marker?.method ?? (returned?.parameter === \"github\" ? \"app_install\" : \"oauth\"),\n outcome,\n });\n } catch {\n // Optional telemetry cannot fail product work.\n }\n}\n\n/**\n * A connect journey bound to a mounted setup surface: started on mount,\n * `abandoned` when it unmounts before `finish` was called.\n */\nexport function useIntegrationConnectJourney(\n integrationClass: IntegrationClass,\n method: IntegrationConnectMethod,\n): (outcome: IntegrationConnectOutcome) => void {\n const tracker = useRef<IntegrationConnectTracker | null>(null);\n useEffect(() => {\n const started = beginIntegrationConnect(integrationClass, method);\n tracker.current = started;\n return () => {\n started.finish(\"abandoned\");\n if (tracker.current === started) tracker.current = null;\n };\n }, [integrationClass, method]);\n return useCallback((outcome) => tracker.current?.finish(outcome), []);\n}\n\n/**\n * A model-provider connect journey with the outcome vocabulary of\n * `trackModelConnection`, for flows that have no workspace-scoped tracker\n * (organization connections, Claude). `expired` is reported as `abandoned`.\n */\nexport function beginModelConnectJourney(\n provider: string,\n method: IntegrationConnectMethod,\n): (outcome: \"connected\" | \"expired\" | \"denied\" | \"outcome_unknown\") => void {\n const tracker = beginIntegrationConnect(modelConnectionClass(provider) ?? \"other\", method);\n return (outcome) => tracker.finish(outcome === \"expired\" ? \"abandoned\" : outcome);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/format.ts"],"sourcesContent":["import { formatErrorMessage, OpenGeniApiError } from \"@opengeni/sdk\";\nimport { parseProviderRecovery, providerRecoveryExhaustedText } from \"./provider-recovery\";\nimport { type OpenGeniText } from \"../messages/runtime\";\n\nconst clockTimeFormatters = new Map<string, Intl.DateTimeFormat>();\nfunction clockTimeFormatter(locale: string | undefined): Intl.DateTimeFormat {\n const key = locale ?? \"\";\n let formatter = clockTimeFormatters.get(key);\n if (!formatter) {\n formatter = new Intl.DateTimeFormat(locale, {\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n clockTimeFormatters.set(key, formatter);\n }\n return formatter;\n}\n\n/** Local finished-at stamp for message footers: \"Aug 2, 3:42 PM\" / locale-equivalent. */\nexport function formatClockTime(t: OpenGeniText, iso: string): string {\n const then = new Date(iso);\n if (Number.isNaN(then.getTime())) {\n return \"\";\n }\n return clockTimeFormatter(t.locale).format(then);\n}\n\n/** Compact relative time: \"now\", \"42s\", \"7m\", \"3h\", \"2d\", then a date. */\nexport function formatRelativeTime(t: OpenGeniText, iso: string, now: Date = new Date()): string {\n const then = new Date(iso).getTime();\n if (Number.isNaN(then)) {\n return \"\";\n }\n const seconds = Math.max(0, Math.floor((now.getTime() - then) / 1000));\n if (seconds < 10) {\n return t(\"lib.format.now\");\n }\n if (seconds < 60) {\n return t(\"lib.format.seconds\", { count: seconds });\n }\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) {\n return t(\"lib.format.minutes\", { count: minutes });\n }\n const hours = Math.floor(minutes / 60);\n if (hours < 24) {\n return t(\"lib.format.hours\", { count: hours });\n }\n const days = Math.floor(hours / 24);\n if (days < 14) {\n return t(\"lib.format.days\", { count: days });\n }\n return new Date(iso).toLocaleDateString(t.locale);\n}\n\n/** Human-readable byte size: \"512 B\", \"8.0 KB\", \"1.4 MB\", \"3 GB\". */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n const units = [\"KB\", \"MB\", \"GB\"] as const;\n let value = bytes / 1024;\n for (const unit of units) {\n if (value < 1024 || unit === \"GB\") {\n return `${value.toFixed(value < 10 ? 1 : 0)} ${unit}`;\n }\n value /= 1024;\n }\n return `${bytes} B`;\n}\n\n/** Single-line preview of arbitrary text, for tiles and collapsed rows. */\nexport function truncate(text: string, maxLength: number): string {\n const collapsed = text.replace(/\\s+/g, \" \").trim();\n if (collapsed.length <= maxLength) {\n return collapsed;\n }\n return `${collapsed.slice(0, Math.max(0, maxLength - 1)).trimEnd()}…`;\n}\n\n/** Render an unknown payload as readable text (pretty JSON when possible). */\nexport function stringifyPayload(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n if (typeof value === \"string\") {\n const parsed = tryParseJson(value);\n if (parsed !== undefined && typeof parsed === \"object\") {\n return stringifyPayload(parsed);\n }\n return value;\n }\n try {\n return JSON.stringify(value, null, 2) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/** JSON.parse that returns `undefined` instead of throwing. */\nexport function tryParseJson(text: string): unknown {\n const trimmed = text.trim();\n if (!trimmed.startsWith(\"{\") && !trimmed.startsWith(\"[\") && !trimmed.startsWith('\"')) {\n return undefined;\n }\n try {\n return JSON.parse(trimmed) as unknown;\n } catch {\n return undefined;\n }\n}\n\n/**\n * The canonical credit-death sentence. Credit exhaustion is the one failure a\n * user can fix themselves — the copy must say what happened (no usable credit for this model),\n * what to do (add credits), and what is safe (nothing was lost). Crucially it\n * must NOT say \"send a message to revive\": a revive turn burns credits the\n * workspace no longer has.\n */\nexport const CREDIT_EXHAUSTION_MESSAGE = (t: OpenGeniText) =>\n t(\"lib.format.outOfCreditsThisWorkspace\");\n\n/** A usage ceiling refused the send; the default allowance wording, plus what is safe. */\nexport const COMPOSER_MEMBER_ALLOWANCE_MESSAGE = (t: OpenGeniText) =>\n t(\"lib.format.usageLimitReachedAWorkspace\");\nexport const COMPOSER_WORKSPACE_ALLOWANCE_MESSAGE = (t: OpenGeniText) =>\n t(\"lib.format.workspaceUsageLimitReachedAn\");\n\n/**\n * Actionable composer copy for an edge rejection before a turn is accepted.\n * Unlike an in-flight credit exhaustion, this path has not consumed the\n * actor-private draft or any finalized attachment.\n */\nexport const COMPOSER_PAYMENT_REQUIRED_MESSAGE = (t: OpenGeniText) =>\n t(\"lib.format.yourOrganizationDoesnTHave\");\n\n/** Trusted, composer-owned guidance; unlike remote diagnostic prose, this is UI copy. */\nexport class ComposerStateError extends Error {}\n\n/** A restored request has omitted credentials and must be reconciled, not replayed. */\nexport class ComposerReconciliationRequiredError extends ComposerStateError {\n constructor() {\n super(\n \"Opengeni cannot safely retry this uncertain request after remount; reconcile the session before sending again.\",\n );\n }\n}\n\nexport class ComposerWorkspaceControlUnavailableError extends Error {\n constructor() {\n super(\"@opengeni/react: workspace-scoped resume requires setWorkspaceInferenceState.\");\n }\n}\n\n/**\n * The send named a model that is no longer in the live catalog (retired or\n * removed). Retrying the same send cannot succeed; the person must choose\n * another model, and the typed message stays recoverable via Edit message.\n */\nexport const COMPOSER_MODEL_UNAVAILABLE_MESSAGE =\n \"This chat's model is no longer available. Choose another model to continue. Your message is saved.\";\n\n/** `details.code` the API sets on a 422 for a model missing from the live catalog. */\nexport const MODEL_UNAVAILABLE_DETAIL_CODE = \"model_unavailable\";\n\n/**\n * A fresh Send or Steer refused because the task's own usage limit is reached.\n * The draft is kept and an unchanged retry is never offered. The one current\n * recovery action (raise or remove the limit, resume a goal) belongs to the\n * composer's `SessionUsageLimitNotice`, so this line only says what happened.\n */\nexport const COMPOSER_SESSION_USAGE_LIMIT_MESSAGE =\n \"This task's usage limit is reached. Your message is saved.\";\n\n/** The earlier wording, still recognized in refusals restored from storage. */\nconst LEGACY_COMPOSER_SESSION_USAGE_LIMIT_MESSAGE =\n \"This task's usage limit is reached. Raise or remove the limit to continue. Your message is saved.\";\n\n/**\n * Is this send refusal the task's usage limit? Reads the typed SDK error code\n * (`OpenGeniSessionUsageLimitReachedError`), and also the composer's own\n * sentence so a refusal restored from storage after a reload is recognized.\n */\nexport function isSessionUsageLimitSubmissionError(error: Error): boolean {\n return (\n (error instanceof OpenGeniApiError && error.code === \"session_usage_limit_reached\") ||\n error.message === COMPOSER_SESSION_USAGE_LIMIT_MESSAGE ||\n error.message === LEGACY_COMPOSER_SESSION_USAGE_LIMIT_MESSAGE\n );\n}\n\n/**\n * Is this send refusal \"the model is no longer available\"? Reads the typed\n * `details.code`, and also the historical message so a refusal persisted\n * before a reload (only its text survives) or from an older API is recognized.\n */\nexport function isModelUnavailableSubmissionError(error: Error): boolean {\n if (error instanceof OpenGeniApiError && error.details?.code === MODEL_UNAVAILABLE_DETAIL_CODE) {\n return true;\n }\n return (\n error.message === COMPOSER_MODEL_UNAVAILABLE_MESSAGE ||\n /^(?:Opengeni|OpenGeni) API 422: model is not available: /.test(error.message)\n );\n}\n\n/**\n * What a published Site's assistant tells a viewer it refused, by the\n * refusal's `details.code`. The draft is kept in every case.\n */\nexport const COMPOSER_SITE_REFUSAL_MESSAGES = (t: OpenGeniText): Readonly<Record<string, string>> =>\n Object.freeze({\n not_available_for_viewer: t(\"lib.format.thisSiteSAssistantCan\"),\n site_budget_exhausted: t(\"lib.format.thisSiteSAssistantHas\"),\n site_budget_busy: t(\"lib.format.thisSiteSAssistantIs\"),\n site_platform_brake_engaged: t(\"lib.format.thisSiteSAssistantIs2\"),\n });\n\nconst SITE_REFUSAL_CODES: ReadonlySet<string> = new Set([\n \"not_available_for_viewer\",\n \"site_budget_exhausted\",\n \"site_budget_busy\",\n \"site_platform_brake_engaged\",\n]);\n\n/** The Site refusal code of a send refusal, if it is one. */\nexport function siteRefusalCode(error: Error): string | null {\n if (!(error instanceof OpenGeniApiError)) return null;\n const code = error.details?.code;\n return typeof code === \"string\" && SITE_REFUSAL_CODES.has(code) ? code : null;\n}\n\nexport function composerSubmissionErrorMessage(t: OpenGeniText, error: Error): string {\n if (error instanceof ComposerReconciliationRequiredError) {\n return t(\"lib.format.reconcileBeforeRetry\");\n }\n if (error instanceof ComposerWorkspaceControlUnavailableError) {\n return t(\"lib.format.thisClientCannotResumeThe\");\n }\n if (error instanceof ComposerStateError) return error.message;\n if (error instanceof OpenGeniApiError && error.outcomeUnknown) return formatErrorMessage(error);\n if (isModelUnavailableSubmissionError(error)) return t(\"lib.format.modelUnavailable\");\n if (isSessionUsageLimitSubmissionError(error)) return t(\"lib.format.sessionUsageLimitReached\");\n const siteRefusal = siteRefusalCode(error);\n if (siteRefusal) return COMPOSER_SITE_REFUSAL_MESSAGES(t)[siteRefusal]!;\n if (error instanceof OpenGeniApiError && error.code === \"allowance_exhausted\") {\n // OpenGeniAllowanceExhaustedError carries the scope; read it structurally\n // so this startup-path helper adds no SDK or wording imports.\n const message =\n (error as { scope?: unknown }).scope === \"workspace\"\n ? COMPOSER_WORKSPACE_ALLOWANCE_MESSAGE(t)\n : COMPOSER_MEMBER_ALLOWANCE_MESSAGE(t);\n return composerErrorReference(t, error, message);\n }\n return isComposerCreditRefusal(error)\n ? composerErrorReference(t, error, COMPOSER_PAYMENT_REQUIRED_MESSAGE(t))\n : formatErrorMessage(error);\n}\n\nfunction composerErrorReference(t: OpenGeniText, error: Error, message: string): string {\n return error instanceof OpenGeniApiError && error.correlationId\n ? t(\"lib.format.messageReferenceCorrelationid\", { message, correlationId: error.correlationId })\n : message;\n}\n\n/** These definitive refusals need a payment, allowance or model change, not an unchanged retry. */\nexport function composerSubmissionCanRetry(error: Error): boolean {\n return !(\n isComposerCreditRefusal(error) ||\n isModelUnavailableSubmissionError(error) ||\n isSessionUsageLimitSubmissionError(error) ||\n (error instanceof OpenGeniApiError && error.code === \"allowance_exhausted\") ||\n // Only a busy Site assistant is worth an unchanged retry.\n (siteRefusalCode(error) !== null && siteRefusalCode(error) !== \"site_budget_busy\")\n );\n}\n\nfunction isComposerCreditRefusal(error: Error): boolean {\n // A 402 for the task's own usage limit is not a credit or payment problem.\n if (isSessionUsageLimitSubmissionError(error)) return false;\n return (\n (error instanceof OpenGeniApiError &&\n error.status === 402 &&\n (error.code === \"payment_required\" || error.code === \"insufficient_credits\")) ||\n isCreditExhaustion(error.message)\n );\n}\n\n/**\n * Does this failure/completion payload (or raw error string) mean the\n * workspace ran out of credits? Matches the engine's \"insufficient workspace\n * credits\" text, and the older \"insufficient Opengeni credits\" wording in\n * existing history (case-insensitive, substring — it arrives both bare and\n * wrapped in \"Activity task failed: …\") and the\n * budget-exhausted segment limit the engine stamps on a turn it ended early.\n */\nconst CREDIT_EXHAUSTION_TEXT = /insufficient (?:workspace|opengeni) credits/i;\n\nexport function isCreditExhaustion(\n input: { error?: string | null; detail?: string | null; segmentLimit?: string | null } | string,\n): boolean {\n if (typeof input === \"string\") {\n return CREDIT_EXHAUSTION_TEXT.test(input);\n }\n if (input.segmentLimit === \"budget_exhausted\") {\n return true;\n }\n for (const text of [input.error, input.detail]) {\n if (typeof text === \"string\" && CREDIT_EXHAUSTION_TEXT.test(text)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Humanize engine/provider failure text before it reaches the timeline or a\n * failure banner. Raw provider errors leak the wrong audience's instructions —\n * \"Incorrect API key … find your API key at platform.openai.com\" tells a\n * managed-deployment USER to fix credentials only an OPERATOR controls (and is\n * flatly wrong for Azure or subscription-backed engines). Auth, quota, and\n * credit-exhaustion failures collapse to one neutral, honest sentence; every\n * other reason passes through untouched. Raw payloads stay available in the\n * debug surfaces.\n */\nexport function humanizeFailureReason(t: OpenGeniText, reason: string | null): string | null {\n if (!reason) {\n return reason;\n }\n if (isCreditExhaustion(reason)) {\n return CREDIT_EXHAUSTION_MESSAGE(t);\n }\n // A turn refused because the chat's model was retired or removed.\n if (\n /^Turn execution policy model is (?:retired from new selection|not present in the configured catalog|no longer configured)$/.test(\n reason.trim(),\n )\n ) {\n return t(\"lib.format.modelUnavailable\");\n }\n const normalized = reason.toLowerCase();\n const authFailure =\n normalized.includes(\"incorrect api key\") ||\n normalized.includes(\"invalid api key\") ||\n normalized.includes(\"invalid_api_key\") ||\n normalized.includes(\"platform.openai.com/account/api-keys\") ||\n (normalized.includes(\"401\") &&\n (normalized.includes(\"api key\") || normalized.includes(\"unauthorized\")));\n if (authFailure) {\n return t(\"lib.format.theModelProviderRejectedThis\");\n }\n const quotaFailure =\n normalized.includes(\"insufficient_quota\") || normalized.includes(\"exceeded your current quota\");\n if (quotaFailure) {\n return t(\"lib.format.theModelProviderRefusedThe\");\n }\n return reason;\n}\n\n/** Project failure diagnostics without changing the stored event, including legacy retry wrappers. */\nexport function presentFailure(\n t: OpenGeniText,\n payload: Record<string, unknown>,\n): {\n reason: string | null;\n safetyRefusal: boolean;\n} {\n const databaseFailure =\n payload.code === \"db_deadlock\" ||\n payload.code === \"db_serialization_failure\" ||\n payload.code === \"db_failure\" ||\n (typeof payload.sqlState === \"string\" &&\n /^[0-9A-Z]{5}$/.test(payload.sqlState) &&\n payload.database !== null &&\n typeof payload.database === \"object\" &&\n !Array.isArray(payload.database));\n if (databaseFailure) {\n return { reason: t(\"lib.format.theServiceEncounteredADatabase\"), safetyRefusal: false };\n }\n // Failures the server identifies by code read in the host's language; the\n // stored (and model-facing) English text stays on the event.\n const coded = typeof payload.code === \"string\" ? CODED_FAILURE_TEXT[payload.code] : undefined;\n if (coded) return { reason: coded(t), safetyRefusal: false };\n const text = (key: string): string | null => {\n const value = payload[key];\n return typeof value === \"string\" && value.trim() ? value : null;\n };\n const message = text(\"error\") ?? text(\"message\");\n const detail = text(\"lastRetryableError\") ?? text(\"detail\");\n const safetyRefusal =\n payload.code === \"provider_safety_refusal\" ||\n [message, detail].some(\n (value) =>\n value !== null && /\\bthis request was blocked by our safety systems\\b/i.test(value),\n );\n if (safetyRefusal) {\n return {\n reason:\n detail || message\n ? t(\"lib.format.providerBlockedRequestDetail\", { detail: detail ?? message })\n : t(\"lib.format.providerBlockedRequest\"),\n safetyRefusal: true,\n };\n }\n // Spent automatic retries: name the model and the remedy instead of the\n // recorded wrapper plus raw provider text (still in the stored event).\n const recovery = parseProviderRecovery(payload);\n if (recovery && payload.recoveryExhausted === true) {\n return { reason: providerRecoveryExhaustedText(t, recovery), safetyRefusal: false };\n }\n return {\n reason:\n detail && detail !== message\n ? [humanizeFailureReason(t, message), humanizeFailureReason(t, detail)]\n .filter(Boolean)\n .join(\" \")\n : humanizeFailureReason(t, message),\n safetyRefusal: false,\n };\n}\n\nconst capacityRecoveryExhausted = (t: OpenGeniText) => t(\"lib.format.capacityRecoveryExhausted\");\n\n/** Server failure codes whose recorded text is operator English, not end-user copy. */\nconst CODED_FAILURE_TEXT: Readonly<Record<string, ((t: OpenGeniText) => string) | undefined>> = {\n codex_capacity_recovery_exhausted: capacityRecoveryExhausted,\n xai_capacity_recovery_exhausted: capacityRecoveryExhausted,\n claude_capacity_recovery_exhausted: capacityRecoveryExhausted,\n};\n"],"mappings":";;;;;;;AAAA,SAAS,oBAAoB,wBAAwB;AAIrD,IAAM,sBAAsB,oBAAI,IAAiC;AACjE,SAAS,mBAAmB,QAAiD;AAC3E,QAAM,MAAM,UAAU;AACtB,MAAI,YAAY,oBAAoB,IAAI,GAAG;AAC3C,MAAI,CAAC,WAAW;AACd,gBAAY,IAAI,KAAK,eAAe,QAAQ;AAAA,MAC1C,OAAO;AAAA,MACP,KAAK;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,IACV,CAAC;AACD,wBAAoB,IAAI,KAAK,SAAS;AAAA,EACxC;AACA,SAAO;AACT;AAGO,SAAS,gBAAgB,GAAiB,KAAqB;AACpE,QAAM,OAAO,IAAI,KAAK,GAAG;AACzB,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAAG;AAChC,WAAO;AAAA,EACT;AACA,SAAO,mBAAmB,EAAE,MAAM,EAAE,OAAO,IAAI;AACjD;AAGO,SAAS,mBAAmB,GAAiB,KAAa,MAAY,oBAAI,KAAK,GAAW;AAC/F,QAAM,OAAO,IAAI,KAAK,GAAG,EAAE,QAAQ;AACnC,MAAI,OAAO,MAAM,IAAI,GAAG;AACtB,WAAO;AAAA,EACT;AACA,QAAM,UAAU,KAAK,IAAI,GAAG,KAAK,OAAO,IAAI,QAAQ,IAAI,QAAQ,GAAI,CAAC;AACrE,MAAI,UAAU,IAAI;AAChB,WAAO,EAAE,gBAAgB;AAAA,EAC3B;AACA,MAAI,UAAU,IAAI;AAChB,WAAO,EAAE,sBAAsB,EAAE,OAAO,QAAQ,CAAC;AAAA,EACnD;AACA,QAAM,UAAU,KAAK,MAAM,UAAU,EAAE;AACvC,MAAI,UAAU,IAAI;AAChB,WAAO,EAAE,sBAAsB,EAAE,OAAO,QAAQ,CAAC;AAAA,EACnD;AACA,QAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;AACrC,MAAI,QAAQ,IAAI;AACd,WAAO,EAAE,oBAAoB,EAAE,OAAO,MAAM,CAAC;AAAA,EAC/C;AACA,QAAM,OAAO,KAAK,MAAM,QAAQ,EAAE;AAClC,MAAI,OAAO,IAAI;AACb,WAAO,EAAE,mBAAmB,EAAE,OAAO,KAAK,CAAC;AAAA,EAC7C;AACA,SAAO,IAAI,KAAK,GAAG,EAAE,mBAAmB,EAAE,MAAM;AAClD;AAGO,SAAS,YAAY,OAAuB;AACjD,MAAI,QAAQ,MAAM;AAChB,WAAO,GAAG,KAAK;AAAA,EACjB;AACA,QAAM,QAAQ,CAAC,MAAM,MAAM,IAAI;AAC/B,MAAI,QAAQ,QAAQ;AACpB,aAAW,QAAQ,OAAO;AACxB,QAAI,QAAQ,QAAQ,SAAS,MAAM;AACjC,aAAO,GAAG,MAAM,QAAQ,QAAQ,KAAK,IAAI,CAAC,CAAC,IAAI,IAAI;AAAA,IACrD;AACA,aAAS;AAAA,EACX;AACA,SAAO,GAAG,KAAK;AACjB;AAGO,SAAS,SAAS,MAAc,WAA2B;AAChE,QAAM,YAAY,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAK;AACjD,MAAI,UAAU,UAAU,WAAW;AACjC,WAAO;AAAA,EACT;AACA,SAAO,GAAG,UAAU,MAAM,GAAG,KAAK,IAAI,GAAG,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC;AACpE;AAGO,SAAS,iBAAiB,OAAwB;AACvD,MAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,SAAS,aAAa,KAAK;AACjC,QAAI,WAAW,UAAa,OAAO,WAAW,UAAU;AACtD,aAAO,iBAAiB,MAAM;AAAA,IAChC;AACA,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,KAAK,UAAU,OAAO,MAAM,CAAC,KAAK,OAAO,KAAK;AAAA,EACvD,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAGO,SAAS,aAAa,MAAuB;AAClD,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,CAAC,QAAQ,WAAW,GAAG,KAAK,CAAC,QAAQ,WAAW,GAAG,KAAK,CAAC,QAAQ,WAAW,GAAG,GAAG;AACpF,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASO,IAAM,4BAA4B,CAAC,MACxC,EAAE,sCAAsC;AAGnC,IAAM,oCAAoC,CAAC,MAChD,EAAE,wCAAwC;AACrC,IAAM,uCAAuC,CAAC,MACnD,EAAE,yCAAyC;AAOtC,IAAM,oCAAoC,CAAC,MAChD,EAAE,uCAAuC;AAGpC,IAAM,qBAAN,cAAiC,MAAM;AAAC;AAGxC,IAAM,sCAAN,cAAkD,mBAAmB;AAAA,EAC1E,cAAc;AACZ;AAAA,MACE;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,2CAAN,cAAuD,MAAM;AAAA,EAClE,cAAc;AACZ,UAAM,+EAA+E;AAAA,EACvF;AACF;AAOO,IAAM,qCACX;AAGK,IAAM,gCAAgC;AAQtC,IAAM,uCACX;AAGF,IAAM,8CACJ;AAOK,SAAS,mCAAmC,OAAuB;AACxE,SACG,iBAAiB,oBAAoB,MAAM,SAAS,iCACrD,MAAM,YAAY,wCAClB,MAAM,YAAY;AAEtB;AAOO,SAAS,kCAAkC,OAAuB;AACvE,MAAI,iBAAiB,oBAAoB,MAAM,SAAS,SAAS,+BAA+B;AAC9F,WAAO;AAAA,EACT;AACA,SACE,MAAM,YAAY,sCAClB,2DAA2D,KAAK,MAAM,OAAO;AAEjF;AAMO,IAAM,iCAAiC,CAAC,MAC7C,OAAO,OAAO;AAAA,EACZ,0BAA0B,EAAE,kCAAkC;AAAA,EAC9D,uBAAuB,EAAE,kCAAkC;AAAA,EAC3D,kBAAkB,EAAE,iCAAiC;AAAA,EACrD,6BAA6B,EAAE,kCAAkC;AACnE,CAAC;AAEH,IAAM,qBAA0C,oBAAI,IAAI;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,SAAS,gBAAgB,OAA6B;AAC3D,MAAI,EAAE,iBAAiB,kBAAmB,QAAO;AACjD,QAAM,OAAO,MAAM,SAAS;AAC5B,SAAO,OAAO,SAAS,YAAY,mBAAmB,IAAI,IAAI,IAAI,OAAO;AAC3E;AAEO,SAAS,+BAA+B,GAAiB,OAAsB;AACpF,MAAI,iBAAiB,qCAAqC;AACxD,WAAO,EAAE,iCAAiC;AAAA,EAC5C;AACA,MAAI,iBAAiB,0CAA0C;AAC7D,WAAO,EAAE,sCAAsC;AAAA,EACjD;AACA,MAAI,iBAAiB,mBAAoB,QAAO,MAAM;AACtD,MAAI,iBAAiB,oBAAoB,MAAM,eAAgB,QAAO,mBAAmB,KAAK;AAC9F,MAAI,kCAAkC,KAAK,EAAG,QAAO,EAAE,6BAA6B;AACpF,MAAI,mCAAmC,KAAK,EAAG,QAAO,EAAE,qCAAqC;AAC7F,QAAM,cAAc,gBAAgB,KAAK;AACzC,MAAI,YAAa,QAAO,+BAA+B,CAAC,EAAE,WAAW;AACrE,MAAI,iBAAiB,oBAAoB,MAAM,SAAS,uBAAuB;AAG7E,UAAM,UACH,MAA8B,UAAU,cACrC,qCAAqC,CAAC,IACtC,kCAAkC,CAAC;AACzC,WAAO,uBAAuB,GAAG,OAAO,OAAO;AAAA,EACjD;AACA,SAAO,wBAAwB,KAAK,IAChC,uBAAuB,GAAG,OAAO,kCAAkC,CAAC,CAAC,IACrE,mBAAmB,KAAK;AAC9B;AAEA,SAAS,uBAAuB,GAAiB,OAAc,SAAyB;AACtF,SAAO,iBAAiB,oBAAoB,MAAM,gBAC9C,EAAE,4CAA4C,EAAE,SAAS,eAAe,MAAM,cAAc,CAAC,IAC7F;AACN;AAGO,SAAS,2BAA2B,OAAuB;AAChE,SAAO,EACL,wBAAwB,KAAK,KAC7B,kCAAkC,KAAK,KACvC,mCAAmC,KAAK,KACvC,iBAAiB,oBAAoB,MAAM,SAAS;AAAA,EAEpD,gBAAgB,KAAK,MAAM,QAAQ,gBAAgB,KAAK,MAAM;AAEnE;AAEA,SAAS,wBAAwB,OAAuB;AAEtD,MAAI,mCAAmC,KAAK,EAAG,QAAO;AACtD,SACG,iBAAiB,oBAChB,MAAM,WAAW,QAChB,MAAM,SAAS,sBAAsB,MAAM,SAAS,2BACvD,mBAAmB,MAAM,OAAO;AAEpC;AAUA,IAAM,yBAAyB;AAExB,SAAS,mBACd,OACS;AACT,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,uBAAuB,KAAK,KAAK;AAAA,EAC1C;AACA,MAAI,MAAM,iBAAiB,oBAAoB;AAC7C,WAAO;AAAA,EACT;AACA,aAAW,QAAQ,CAAC,MAAM,OAAO,MAAM,MAAM,GAAG;AAC9C,QAAI,OAAO,SAAS,YAAY,uBAAuB,KAAK,IAAI,GAAG;AACjE,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAYO,SAAS,sBAAsB,GAAiB,QAAsC;AAC3F,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,MAAI,mBAAmB,MAAM,GAAG;AAC9B,WAAO,0BAA0B,CAAC;AAAA,EACpC;AAEA,MACE,6HAA6H;AAAA,IAC3H,OAAO,KAAK;AAAA,EACd,GACA;AACA,WAAO,EAAE,6BAA6B;AAAA,EACxC;AACA,QAAM,aAAa,OAAO,YAAY;AACtC,QAAM,cACJ,WAAW,SAAS,mBAAmB,KACvC,WAAW,SAAS,iBAAiB,KACrC,WAAW,SAAS,iBAAiB,KACrC,WAAW,SAAS,sCAAsC,KACzD,WAAW,SAAS,KAAK,MACvB,WAAW,SAAS,SAAS,KAAK,WAAW,SAAS,cAAc;AACzE,MAAI,aAAa;AACf,WAAO,EAAE,yCAAyC;AAAA,EACpD;AACA,QAAM,eACJ,WAAW,SAAS,oBAAoB,KAAK,WAAW,SAAS,6BAA6B;AAChG,MAAI,cAAc;AAChB,WAAO,EAAE,uCAAuC;AAAA,EAClD;AACA,SAAO;AACT;AAGO,SAAS,eACd,GACA,SAIA;AACA,QAAM,kBACJ,QAAQ,SAAS,iBACjB,QAAQ,SAAS,8BACjB,QAAQ,SAAS,gBAChB,OAAO,QAAQ,aAAa,YAC3B,gBAAgB,KAAK,QAAQ,QAAQ,KACrC,QAAQ,aAAa,QACrB,OAAO,QAAQ,aAAa,YAC5B,CAAC,MAAM,QAAQ,QAAQ,QAAQ;AACnC,MAAI,iBAAiB;AACnB,WAAO,EAAE,QAAQ,EAAE,2CAA2C,GAAG,eAAe,MAAM;AAAA,EACxF;AAGA,QAAM,QAAQ,OAAO,QAAQ,SAAS,WAAW,mBAAmB,QAAQ,IAAI,IAAI;AACpF,MAAI,MAAO,QAAO,EAAE,QAAQ,MAAM,CAAC,GAAG,eAAe,MAAM;AAC3D,QAAM,OAAO,CAAC,QAA+B;AAC3C,UAAM,QAAQ,QAAQ,GAAG;AACzB,WAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,QAAQ;AAAA,EAC7D;AACA,QAAM,UAAU,KAAK,OAAO,KAAK,KAAK,SAAS;AAC/C,QAAM,SAAS,KAAK,oBAAoB,KAAK,KAAK,QAAQ;AAC1D,QAAM,gBACJ,QAAQ,SAAS,6BACjB,CAAC,SAAS,MAAM,EAAE;AAAA,IAChB,CAAC,UACC,UAAU,QAAQ,sDAAsD,KAAK,KAAK;AAAA,EACtF;AACF,MAAI,eAAe;AACjB,WAAO;AAAA,MACL,QACE,UAAU,UACN,EAAE,2CAA2C,EAAE,QAAQ,UAAU,QAAQ,CAAC,IAC1E,EAAE,mCAAmC;AAAA,MAC3C,eAAe;AAAA,IACjB;AAAA,EACF;AAGA,QAAM,WAAW,sBAAsB,OAAO;AAC9C,MAAI,YAAY,QAAQ,sBAAsB,MAAM;AAClD,WAAO,EAAE,QAAQ,8BAA8B,GAAG,QAAQ,GAAG,eAAe,MAAM;AAAA,EACpF;AACA,SAAO;AAAA,IACL,QACE,UAAU,WAAW,UACjB,CAAC,sBAAsB,GAAG,OAAO,GAAG,sBAAsB,GAAG,MAAM,CAAC,EACjE,OAAO,OAAO,EACd,KAAK,GAAG,IACX,sBAAsB,GAAG,OAAO;AAAA,IACtC,eAAe;AAAA,EACjB;AACF;AAEA,IAAM,4BAA4B,CAAC,MAAoB,EAAE,sCAAsC;AAG/F,IAAM,qBAA0F;AAAA,EAC9F,mCAAmC;AAAA,EACnC,iCAAiC;AAAA,EACjC,oCAAoC;AACtC;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/app/embed/session-app.tsx"],"sourcesContent":["// The Opengeni session app for an embedding page that already holds an\n// authenticated API client (a first-party side pane such as the Excel add-in,\n// the desktop app, a playground). It renders the web app's own session shell,\n// chat list, session page and new-chat page, backed by the same app state, with\n// in-memory navigation and the host's credentials. Pages that only the web app\n// has (settings, billing, schedules) open the web app beside the host page.\nimport {\n OPENGENI_API_CONTRACT_HEADER,\n OPENGENI_API_CONTRACT_REVISION,\n OpenGeniBrowserClient,\n type FetchLike,\n} from \"@opengeni/sdk/browser\";\nimport { useEffect, useMemo, useRef, useState, type ComponentType, type ReactNode } from \"react\";\n\nimport { OpenGeniProvider } from \"../../provider\";\nimport { SecretsUiProvider } from \"../../secrets-ui\";\nimport { Button } from \"../../ui/button\";\nimport { PortalContainerProvider } from \"../../ui/portal-container\";\nimport { AppContext, useAppContext } from \"../app-context\";\nimport { createSlackLinkPrepareController, useAppState, type AppStateHost } from \"../app-state\";\nimport { LoadingPanel, ProblemPanel } from \"../components/common\";\nimport { RailProvider } from \"../components/rail/rail-context\";\nimport { SessionShell, type SessionShellSlots } from \"../components/rail/session-shell\";\nimport { CreditRequiredGate } from \"../components/credit-required-gate\";\nimport { Toaster } from \"../components/toaster\";\nimport { WorkspaceTenantBoundary } from \"../components/workspace-tenant-boundary\";\nimport { apiErrorFromResponseBody, type AppApiHost } from \"../lib/app-api\";\nimport { AppHostProvider, type AppHost } from \"../lib/app-host\";\nimport type { EditableArtifactSurfaceProps, PdfPreviewProps } from \"../lib/app-surfaces\";\nimport { AppearanceProvider, useAppearance } from \"../lib/appearance\";\nimport { parseComposerLaunchSearch } from \"../lib/composer-launch\";\nimport { createMessageContextStore, type MessageContextInput } from \"../lib/message-context\";\nimport { openBlankTab, useLocation } from \"../lib/navigation\";\nimport { toast } from \"../lib/toast\";\nimport { UiEventTargetProvider } from \"../lib/ui-events\";\nimport { cn } from \"../lib/utils\";\nimport { webSecretsUi } from \"../lib/secrets-ui\";\nimport { parseSessionSearchRoute } from \"../lib/session-search-route\";\nimport { useWorkspaceIntegrations } from \"../lib/use-workspace-integrations\";\nimport { authorizedWorkspaceFromList } from \"../lib/workspace-scope-context\";\nimport { SessionRoute } from \"../routes/session\";\nimport { SessionsIndexRoute } from \"../routes/sessions-index\";\nimport type { ClientConfig } from \"../types\";\nimport {\n SessionUiFeaturesProvider,\n type SessionUiFeatures,\n type SessionUiPreset,\n} from \"../lib/session-ui-features\";\nimport { useMemoryNavigation } from \"./memory-navigation\";\n\n/**\n * Heavy viewers the host can supply (they need bundler-specific workers):\n * PDF pages, and the document, spreadsheet and presentation editor. Without\n * one, PDFs open as a link and editable artifacts open in the web app.\n */\nexport type SessionAppSurfaces = Readonly<{\n pdfPreview?: ComponentType<PdfPreviewProps> | undefined;\n editableArtifact?: ComponentType<EditableArtifactSurfaceProps> | undefined;\n}>;\n\nexport type { EditableArtifactSurfaceProps, PdfPreviewProps };\n\nexport type SessionAppProps = Readonly<{\n /** The Opengeni API origin, such as `https://api.example.com`. */\n apiBaseUrl: string;\n /** Headers that authenticate every API call, typically `Authorization: Bearer …`. */\n headers: () => Record<string, string>;\n /**\n * The Opengeni web app's origin, such as `https://app.example.com`, where\n * pages the embed doesn't show (settings, billing, schedules) open. App paths\n * resolve against the origin, so a path after it is ignored.\n */\n consoleUrl: string;\n workspaceId: string;\n /**\n * The open chat; null or absent for the new-chat page. Changing it opens\n * that chat. The person can open others inside the app: `onSessionChange`\n * reports each, so a host that stores this value stays in step.\n */\n sessionId?: string | null | undefined;\n /** Called when the person opens another chat (null: the new-chat page). */\n onSessionChange?: ((sessionId: string | null) => void) | undefined;\n /**\n * Which features show. `embed` (default) is the chat list, chats and\n * composer; `companion` (first-party side panes) adds the session panel and\n * Opengeni's brand; `app` is the web app. `features` switches single ones.\n */\n preset?: SessionUiPreset | undefined;\n features?: Partial<SessionUiFeatures> | undefined;\n /** Sections the host adds to the shell: a workspace picker, banners, a footer. */\n slots?: SessionShellSlots | undefined;\n /** Heavy viewers the host turns on. */\n surfaces?: SessionAppSurfaces | undefined;\n /** Light or dark from the host application; the person's own choice otherwise. */\n theme?: \"light\" | \"dark\" | undefined;\n /**\n * Opens a URL outside the embed: app-only pages, provider sign-in, checkout,\n * files and images opened in full. Defaults to a new tab, or a toast with an\n * Open button when the browser blocks it. When set, flows that would open a\n * tab in advance (checkout) wait for the URL and pass it here instead.\n */\n openUrl?: ((url: string) => void) | undefined;\n /** Classes for the app's root element (it fills its container by default). */\n className?: string | undefined;\n /** Called when the API rejects the credentials (any call answering 401). */\n onUnauthorized?: (() => void) | undefined;\n /**\n * Model context added to each new chat and message, such as where the person\n * is writing from and what they have selected. Items with a `label` show as\n * pills above the composer, and the person can leave one out; pass a new\n * value whenever it changes. A function is read when each message is sent\n * and shows nothing. Context for the model, never instructions.\n */\n messageContext?: MessageContextInput;\n}>;\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/u, \"\");\n}\n\nfunction sessionsPath(workspaceId: string, sessionId?: string | null): string {\n const base = `/workspaces/${encodeURIComponent(workspaceId)}/sessions`;\n return sessionId ? `${base}/${encodeURIComponent(sessionId)}` : base;\n}\n\n/** The open chat in an in-embed path, or null for the new-chat page. */\nfunction sessionIdIn(pathname: string): string | null {\n const match = /^\\/workspaces\\/[^/]+\\/sessions\\/([^/]+)/u.exec(pathname);\n return match ? decodeURIComponent(match[1]!) : null;\n}\n\n/** The embed renders its own workspace's chats; anything else opens the web app. */\nfunction handlesPath(workspaceId: string, pathname: string): boolean {\n const base = sessionsPath(workspaceId);\n if (pathname === base || pathname === `${base}/`) return true;\n return (\n pathname.startsWith(`${base}/`) &&\n !pathname\n .slice(base.length + 1)\n .replace(/\\/$/u, \"\")\n .includes(\"/\")\n );\n}\n\n/** A new tab; when the browser blocks it (after an await), a toast to open it by hand. */\nfunction openBeside(url: string): void {\n const opened = window.open(url, \"_blank\");\n if (opened) {\n opened.opener = null;\n return;\n }\n toast.info(\"Continue in a new tab\", {\n action: { label: \"Open\", onClick: () => void window.open(url, \"_blank\", \"noopener\") },\n });\n}\n\n/** Every API call, the SDK client's included, reports a 401 to the host. */\nfunction reportingFetch(onUnauthorized: () => void): FetchLike {\n return async (input, init) => {\n const response = await fetch(input, init);\n if (response.status === 401) onUnauthorized();\n return response;\n };\n}\n\nfunction createEmbedApiHost(\n apiBaseUrl: string,\n headers: () => Record<string, string>,\n fetchImpl: FetchLike,\n): AppApiHost {\n const requestResponse = async (path: string, init?: RequestInit) =>\n (await fetchImpl(`${apiBaseUrl}${path}`, {\n ...init,\n headers: {\n \"content-type\": \"application/json\",\n [OPENGENI_API_CONTRACT_HEADER]: OPENGENI_API_CONTRACT_REVISION,\n ...headers(),\n ...init?.headers,\n },\n })) as Response;\n return {\n apiBaseUrl,\n requestResponse,\n request: async <T,>(path: string, init?: RequestInit) => {\n const response = await requestResponse(path, init);\n if (!response.ok) throw apiErrorFromResponseBody(response.status, await response.text());\n return (await response.json()) as T;\n },\n voiceRealtimeClient: (client) => client,\n };\n}\n\nfunction signInUnavailable(): never {\n throw new Error(\"The embedding page signs this app in.\");\n}\n\nfunction createEmbedStateHost(\n apiBaseUrl: string,\n headers: () => Record<string, string>,\n api: AppApiHost,\n fetchImpl: FetchLike,\n): AppStateHost {\n return {\n authority: \"host\",\n createOpenGeniClient: (beginSharedRead) =>\n new OpenGeniBrowserClient({\n baseUrl: apiBaseUrl,\n headers,\n fetch: fetchImpl,\n beginSharedRead,\n onDeprecation: false,\n apiContract: \"compatible\",\n }),\n fetchClientConfig: (signal, workspaceId) =>\n api.request<ClientConfig>(\n workspaceId\n ? `/v1/config/client?workspaceId=${encodeURIComponent(workspaceId)}`\n : \"/v1/config/client\",\n { signal: signal ?? null },\n ),\n captureProductEvent: () => undefined,\n fetchAuthSession: async () => null,\n signInEmail: signInUnavailable,\n signUpEmail: signInUnavailable,\n signOutManaged: async () => undefined,\n startManagedSocialSignIn: signInUnavailable,\n configureManagedActorEpoch: () => undefined,\n getStoredAccessKey: () => null,\n setStoredAccessKey: () => undefined,\n clearStoredAccessKey: () => undefined,\n slackLink: createSlackLinkPrepareController(null),\n initialInvalidSlackLinkQueryWorkspaceId: null,\n };\n}\n\n/**\n * The embed's own root: the `og-root` the published stylesheet is scoped to,\n * carrying the theme so the host page's <html> is never touched.\n */\nfunction SessionAppRoot(props: { className?: string | undefined; children: ReactNode }) {\n const { resolvedTheme } = useAppearance();\n // Overlays (menus, dialogs, sheets, tooltips) portal into this root, inside\n // the scoped stylesheet and its theme.\n const [root, setRoot] = useState<HTMLDivElement | null>(null);\n // Requests between its parts (open find, chat search) stay inside this app.\n const [events] = useState(() => new EventTarget());\n return (\n <div\n ref={setRoot}\n className={cn(\n \"og-root og-session-app flex h-full min-h-0 w-full min-w-0 flex-1 flex-col overflow-hidden bg-bg font-sans text-fg\",\n resolvedTheme === \"dark\" && \"dark\",\n props.className,\n )}\n data-og-theme={resolvedTheme}\n >\n <PortalContainerProvider container={root}>\n <UiEventTargetProvider target={events}>{props.children}</UiEventTargetProvider>\n </PortalContainerProvider>\n </div>\n );\n}\n\n/** The session page or the new-chat page, from the in-memory location. */\nfunction SessionAppRoutes({ workspaceId }: { workspaceId: string }) {\n const location = useLocation();\n const sessionId = sessionIdIn(location.pathname);\n const launch = parseComposerLaunchSearch(location.search);\n if (sessionId) {\n return (\n <SessionRoute\n key={sessionId}\n workspaceId={workspaceId}\n sessionId={sessionId}\n launch={launch}\n realtimeAutostartModel={launch.realtime}\n searchTarget={parseSessionSearchRoute(location.search)}\n />\n );\n }\n return <SessionsIndexRoute workspaceId={workspaceId} launch={launch} />;\n}\n\n/**\n * The routed workspace, as the web app's workspace route prepares it: the app\n * state switches to this workspace before anything renders, then its\n * integrations (repositories, GitHub, the MCP catalog the composer waits on)\n * load.\n */\nfunction SessionAppWorkspace({\n workspaceId,\n slots,\n}: {\n workspaceId: string;\n slots: SessionShellSlots | undefined;\n}) {\n const context = useAppContext();\n const ready = context.workspaceStateOwnerId === workspaceId;\n const workspace = authorizedWorkspaceFromList({\n workspaceId,\n workspaces: context.workspaces,\n accessContext: context.accessContext,\n });\n useWorkspaceIntegrations(context, workspaceId, workspace !== null && ready);\n return (\n <WorkspaceTenantBoundary\n workspaceId={workspaceId}\n stateOwnerWorkspaceId={context.workspaceStateOwnerId}\n prepareTransition={context.prepareWorkspaceTransition}\n >\n {workspace ? (\n <OpenGeniProvider\n client={context.client}\n workspaceId={workspaceId}\n onWorkspaceControlEvent={(event) => {\n // Only workspace-wide controls change the workspace projection.\n if (event.scope === \"workspace\") void context.refreshWorkspace(workspaceId);\n }}\n >\n <SecretsUiProvider value={webSecretsUi}>\n <RailProvider workspaceId={workspaceId}>\n <SessionShell slots={slots}>\n <SessionAppRoutes workspaceId={workspaceId} />\n </SessionShell>\n </RailProvider>\n </SecretsUiProvider>\n </OpenGeniProvider>\n ) : (\n <ProblemPanel\n title=\"This workspace isn't available\"\n description=\"It doesn't exist, or this account can't open it.\"\n />\n )}\n </WorkspaceTenantBoundary>\n );\n}\n\nfunction SessionAppGates({\n stateHost,\n workspaceId,\n slots,\n}: {\n stateHost: AppStateHost;\n workspaceId: string;\n slots: SessionShellSlots | undefined;\n}) {\n const state = useAppState(stateHost, { bootstrapSuspended: false });\n let content: ReactNode;\n if (!state.clientConfig && !state.configError) content = <LoadingPanel />;\n else if (state.configError) {\n content = (\n <ProblemPanel\n title={state.configError.title}\n description={state.configError.description}\n action={\n <Button type=\"button\" variant=\"outline\" onClick={state.retryClientConfig}>\n Try again\n </Button>\n }\n />\n );\n } else if (state.accessError && !state.accessLoading) {\n content = (\n <ProblemPanel\n title={state.accessError.title}\n description={state.accessError.description}\n action={\n <Button type=\"button\" variant=\"outline\" onClick={state.retryAccess}>\n Retry\n </Button>\n }\n />\n );\n } else if (state.accessLoading || !state.appContext) content = <LoadingPanel />;\n else {\n const context = state.appContext;\n content = (\n <AppContext.Provider value={context}>\n <SessionAppWorkspace workspaceId={workspaceId} slots={slots} />\n <CreditRequiredGate\n creditRequired={state.creditRequired}\n setCreditRequired={state.setCreditRequired}\n accessContext={state.accessContext}\n />\n </AppContext.Provider>\n );\n }\n return (\n <>\n {content}\n <Toaster embedded />\n </>\n );\n}\n\n/**\n * The full Opengeni session app inside a host page: chat list, session page,\n * new-chat page and composer, exactly as the web app renders them.\n */\nexport function SessionApp(props: SessionAppProps) {\n // The workspace and API are the host's choice: another one starts a fresh app.\n return (\n <SessionAppForWorkspace\n key={`${props.workspaceId}\\u0000${props.apiBaseUrl}\\u0000${props.consoleUrl}`}\n {...props}\n />\n );\n}\n\nfunction SessionAppForWorkspace(props: SessionAppProps) {\n const apiBaseUrl = trimSlash(props.apiBaseUrl);\n const consoleUrl = trimSlash(props.consoleUrl);\n const latest = useRef(props);\n latest.current = props;\n const reportedSessionId = useRef<string | null>(props.sessionId ?? null);\n const navigation = useMemoryNavigation({\n initialPath: sessionsPath(props.workspaceId, props.sessionId),\n consoleOrigin: consoleUrl,\n handles: (pathname) => handlesPath(latest.current.workspaceId, pathname),\n openUrl: (url) => (latest.current.openUrl ?? openBeside)(url),\n // A host that shows URLs its own way (Excel opens them in the system\n // browser) cannot take a tab opened in advance.\n openTab: () => (latest.current.openUrl ? null : openBlankTab()),\n onLocationChange: (location) => {\n const sessionId = sessionIdIn(location.pathname);\n if (sessionId === reportedSessionId.current) return;\n reportedSessionId.current = sessionId;\n latest.current.onSessionChange?.(sessionId);\n },\n });\n // A new `sessionId` from the host opens that chat.\n const requestedSessionId = props.sessionId ?? null;\n useEffect(() => {\n const current = sessionIdIn(new URL(navigation.page.href()).pathname);\n if (requestedSessionId !== current) {\n navigation.page.assign(sessionsPath(props.workspaceId, requestedSessionId));\n }\n }, [navigation, props.workspaceId, requestedSessionId]);\n const { api, stateHost } = useMemo(() => {\n const headers = () => latest.current.headers();\n const fetchImpl = reportingFetch(() => latest.current.onUnauthorized?.());\n const apiHost = createEmbedApiHost(apiBaseUrl, headers, fetchImpl);\n return {\n api: apiHost,\n stateHost: createEmbedStateHost(apiBaseUrl, headers, apiHost, fetchImpl),\n };\n }, [apiBaseUrl]);\n const [messageContext] = useState(() => createMessageContextStore(props.messageContext));\n useEffect(() => messageContext.set(props.messageContext), [messageContext, props.messageContext]);\n const pdfPreview = props.surfaces?.pdfPreview;\n const editableArtifact = props.surfaces?.editableArtifact;\n const host = useMemo<AppHost>(\n () => ({\n navigation,\n api,\n surfaces: {\n ...(pdfPreview ? { pdfPreview } : {}),\n ...(editableArtifact ? { editableArtifact } : {}),\n },\n messageContext,\n }),\n [api, editableArtifact, messageContext, navigation, pdfPreview],\n );\n return (\n <AppearanceProvider hostTheme={props.theme} scope=\"local\">\n <AppHostProvider host={host}>\n <SessionUiFeaturesProvider preset={props.preset ?? \"embed\"} features={props.features}>\n <SessionAppRoot className={props.className}>\n <SessionAppGates\n stateHost={stateHost}\n workspaceId={props.workspaceId}\n slots={props.slots}\n />\n </SessionAppRoot>\n </SessionUiFeaturesProvider>\n </AppHostProvider>\n </AppearanceProvider>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/app/components/rail/rail-sections.tsx"],"sourcesContent":["// The rail's sections that surfaces fill in: the brand row with the workspace\n// switcher slot, and the primary navigation with \"New session\" plus the\n// surface's own entries. `SessionShell` composes them.\nimport { ChevronsLeftIcon, ChevronsRightIcon, SquarePenIcon, XIcon } from \"lucide-react\";\nimport { createContext, useContext, type ReactNode } from \"react\";\n\nimport { BrandMark, Wordmark } from \"../brand-mark\";\nimport { useRail } from \"./rail-context\";\nimport { NewSessionLink } from \"./session-list\";\nimport { Button } from \"../../../ui/button\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"../../../ui/tooltip\";\nimport { NEW_SESSION_SHORTCUT, shortcutLabel } from \"../../lib/keyboard-shortcuts\";\nimport { Link, useRouterState } from \"../../lib/navigation\";\nimport { cn } from \"../../lib/utils\";\nimport { windowControlsInPage } from \"../../lib/desktop\";\nimport { useSessionUiFeature } from \"../../lib/session-ui-features\";\n\n/**\n * The surface-owned sections of the session shell. Every slot is optional: a\n * surface without a workspace switcher, workspace navigation or footer simply\n * leaves them out and the shell keeps its layout.\n */\nexport type SessionShellSlots = Readonly<{\n /** The workspace switcher under the brand row (or under the window controls). */\n switcher?: ReactNode;\n /** Primary navigation after \"New session\" (inbox, workspace shortcuts). */\n primaryNav?: ReactNode;\n /**\n * The phone drawer's \"Workspace\" tab. Without it, phones show the sessions\n * list alone, with no tabs.\n */\n mobileWorkspacePanel?: ReactNode;\n /** Pinned under the rail's scroll viewport: account menu, offers. */\n railFooter?: ReactNode;\n /** Notices across the top of the canvas, under the top strip. */\n canvasBanners?: ReactNode;\n}>;\n\nexport const SessionShellSlotsContext = createContext<SessionShellSlots>({});\n\n/** Supplies the slots to a rail rendered outside `SessionShell` (previews, fixtures). */\nexport function SessionShellSlotsProvider({\n slots,\n children,\n}: {\n slots: SessionShellSlots;\n children: ReactNode;\n}) {\n return (\n <SessionShellSlotsContext.Provider value={slots}>{children}</SessionShellSlotsContext.Provider>\n );\n}\n\n/**\n * The top of the main rail: a brand row (the mark and the \"Opengeni\" wordmark)\n * and, under it, the workspace picker at full rail width. Its spacing matches\n * the settings rail's top (12px, 32px brand row, 12px gap) so switching\n * between the two rails doesn't jump. The collapse toggle sits at the right end\n * of the brand row; collapsed, only the mark stays, with the expand toggle\n * under it. In the macOS app the row holds just the toggle beside the window\n * controls.\n */\nexport function RailHeader({ showSwitcher = true }: { showSwitcher?: boolean }) {\n const rail = useRail();\n const { switcher } = useContext(SessionShellSlotsContext);\n // Without the brand (an embed, or the macOS app whose window controls sit\n // in the row), the row holds just the collapse toggle, at its end.\n const brand = useSessionUiFeature(\"brand\");\n const brandless = windowControlsInPage || !brand;\n const collapseToggle = !rail.isMobile ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={rail.collapsed ? \"Expand sidebar\" : \"Collapse sidebar\"}\n onClick={rail.toggleCollapsed}\n className=\"shrink-0 text-fg-label hover:text-fg pointer-coarse:size-10\"\n >\n {rail.collapsed ? (\n <ChevronsRightIcon className=\"size-4\" />\n ) : (\n <ChevronsLeftIcon className=\"size-4\" />\n )}\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">\n {rail.collapsed ? \"Expand sidebar\" : \"Collapse sidebar\"}\n </TooltipContent>\n </Tooltip>\n ) : null;\n return (\n <div data-rail-header className=\"flex shrink-0 flex-col gap-3 pt-3\">\n <div\n data-rail-brand\n data-window-drag\n className={cn(\n \"flex h-8 min-w-0 items-center gap-2 px-2\",\n rail.collapsed ? \"justify-center\" : brandless ? \"justify-end\" : \"justify-between\",\n )}\n >\n {brandless ? null : (\n <Link\n to=\"/workspaces/$workspaceId/sessions\"\n params={{ workspaceId: rail.workspaceId }}\n className=\"flex h-8 shrink-0 items-center gap-2 rounded-md px-1.5 text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\"\n aria-label=\"Opengeni home\"\n >\n <BrandMark className=\"w-5\" />\n {!rail.collapsed ? <Wordmark className=\"text-[18px]\" /> : null}\n </Link>\n )}\n {!rail.collapsed || brandless ? collapseToggle : null}\n {rail.isMobile ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label=\"Close navigation\"\n onClick={() => rail.setDrawerOpen(false)}\n className=\"pointer-coarse:size-11\"\n >\n <XIcon className=\"size-4\" />\n </Button>\n ) : null}\n </div>\n {rail.collapsed && collapseToggle && !brandless ? (\n <div className=\"-mt-1 grid justify-items-center\">{collapseToggle}</div>\n ) : null}\n {showSwitcher && !rail.collapsed ? switcher : null}\n </div>\n );\n}\n\n/** \"New session\" followed by the surface's own primary navigation. */\nexport function PrimaryNav() {\n const rail = useRail();\n const { primaryNav } = useContext(SessionShellSlotsContext);\n const pathname = useRouterState({ select: (state) => state.location.pathname });\n const newSessionActive = pathname === `/workspaces/${rail.workspaceId}/sessions`;\n const newChatShortcut = useSessionUiFeature(\"newChatShortcut\");\n return (\n <div className={cn(\"mt-2 grid gap-0.5 px-2\", rail.collapsed && \"justify-center\")}>\n <NewSessionLink\n aria-label={\n newChatShortcut ? `New session · ${shortcutLabel(NEW_SESSION_SHORTCUT)}` : \"New session\"\n }\n className={cn(\n \"group relative flex h-8 items-center rounded-md text-sm font-normal text-fg-label outline-hidden transition-colors pointer-coarse:h-10\",\n \"hover:bg-hover hover:text-fg focus-visible:ring-2 focus-visible:ring-ring/50\",\n newSessionActive && \"bg-selection text-fg hover:bg-selection\",\n rail.collapsed ? \"w-8 justify-center pointer-coarse:w-10\" : \"gap-2.5 px-2.5\",\n )}\n >\n <span\n aria-hidden=\"true\"\n className={cn(\n \"absolute left-0 top-1/2 h-4 w-0.5 -translate-y-1/2 rounded-full bg-brand transition-opacity\",\n newSessionActive ? \"opacity-100\" : \"opacity-0\",\n )}\n />\n <SquarePenIcon className=\"size-4 shrink-0\" />\n {rail.collapsed ? null : <span className=\"min-w-0 truncate\">New session</span>}\n </NewSessionLink>\n {primaryNav}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/timeline/work-presentation.ts","../src/human-input-model.ts","../src/timeline/notice-presentation.ts","../src/timeline/question-nav-model.ts","../src/timeline/focus-sequence.ts"],"sourcesContent":["// Pure presentation decisions for a timeline turn's work, shared by the web and native\n// timelines. Every function here is extracted verbatim from the web MessageTimeline so both\n// renderers decide identically what a turn shows (preparing, working, waiting, worked).\nimport { timelineGroupContainsPresentedImage } from \"./presented-image\";\nimport type { TurnSummaryStatus } from \"./turn-summary-model\";\nimport type { ActivityItem, TimelineGroup, ToolCallItem } from \"./types\";\nimport { type OpenGeniText } from \"../messages/runtime\";\n\nexport type ActivityGroup = Extract<TimelineGroup, { kind: \"activity\" }>;\nexport type TurnGroup = Extract<TimelineGroup, { kind: \"turn\" }>;\n\nexport function durationBetween(startedAt: string, endedAt: string): number | undefined {\n const started = Date.parse(startedAt);\n const ended = Date.parse(endedAt);\n if (!Number.isFinite(started) || !Number.isFinite(ended) || ended < started) {\n return undefined;\n }\n return ended - started;\n}\n\n/** Compaction landmarks among a fold's groups (secondary summary facet). */\nexport function compactedLandmarkCount(groups: readonly TimelineGroup[]): number {\n return groups.filter(\n (group) =>\n group.kind === \"item\" &&\n group.item.kind === \"context-compaction\" &&\n group.item.phase === \"compacted\",\n ).length;\n}\n\nexport function clusterIsSettled(group: ActivityGroup): boolean {\n return group.items.every((item) => {\n if (item.kind === \"reasoning\" || item.kind === \"agent-message\") {\n return !item.streaming;\n }\n // Memory writes and fleet observations are discrete, already-settled events.\n if (item.kind === \"memory\" || item.kind === \"fleet-decision\") {\n return true;\n }\n return item.status !== \"running\";\n });\n}\n\nexport function flattenActivityItems(groups: readonly TimelineGroup[]): ActivityItem[] {\n const items: ActivityItem[] = [];\n for (const group of groups) {\n if (group.kind === \"activity\") {\n items.push(...flattenActivityItems(group.work?.details ?? []), ...group.items);\n } else if (group.kind === \"turn\") {\n items.push(...flattenActivityItems(group.groups));\n }\n }\n return items;\n}\n\nexport type ReadableWorkOptions = {\n /** Host shows startup phases as ordinary details (web: startup-details context). */\n startupDetails: boolean;\n /** Startup chrome was dismissed by the reader. */\n startupDismissed: boolean;\n};\n\n/**\n * A readable turn whose only work so far is environment preparation renders as one quiet\n * preparation surface instead of a \"Working\" fold.\n */\nexport function isPreparingWork(group: ActivityGroup, options: ReadableWorkOptions): boolean {\n if (!group.work) return false;\n // Steps not loaded yet are work the reader can open, not preparation.\n if (group.work.steps && group.work.steps.state !== \"complete\") return false;\n const phases = group.items.filter((item) => item.kind === \"startup-phase\");\n return (\n !options.startupDetails &&\n !options.startupDismissed &&\n !group.work.endedAt &&\n !group.work.waiting &&\n phases.length > 0 &&\n group.items.every(\n (item) => item.kind === \"startup-phase\" || (item.kind === \"reasoning\" && !item.text.trim()),\n ) &&\n !phases.some((item) => item.status === \"failed\" || item.status === \"cancelled\")\n );\n}\n\n/**\n * Whether a readable turn's work row has anything to reveal when expanded.\n * Unless the host shows startup phases as details, the work row's rail only\n * renders failed or cancelled preparation steps, so a detail made only of\n * completed or still-running steps (for example the queue phase before a turn\n * was parked on a usage limit) renders nothing and does not make the row\n * expandable.\n */\nexport function readableWorkHasDetails(\n group: ActivityGroup & { work: NonNullable<ActivityGroup[\"work\"]> },\n options: Pick<ReadableWorkOptions, \"startupDetails\">,\n): boolean {\n // Steps not loaded yet are revealed (and loaded) by opening the row.\n if (group.work.steps && group.work.steps.state !== \"complete\") return true;\n return group.work.details.some(\n (detail) =>\n options.startupDetails ||\n detail.kind !== \"activity\" ||\n Boolean(detail.work) ||\n !detail.items.every(\n (item) =>\n (item.kind === \"startup-phase\" &&\n item.status !== \"failed\" &&\n item.status !== \"cancelled\") ||\n (item.kind === \"reasoning\" && !item.text.trim()),\n ),\n );\n}\n\n/**\n * Status of a readable turn's work row, minus the host-rendered live preview.\n * Time spent waiting for model capacity is not work: the worked duration and\n * the live working clock exclude it, and the wait itself shows no clock. A\n * wait's `detail` is its one quiet secondary line.\n */\nexport function readableWorkStatus(\n t: OpenGeniText,\n group: ActivityGroup & { work: NonNullable<ActivityGroup[\"work\"]> },\n): Omit<TurnSummaryStatus, \"preview\"> & { detail?: string | undefined } {\n const end = group.work.endedAt;\n const pausedMs = group.work.pausedMs ?? 0;\n if (end) {\n const durationMs = durationBetween(group.work.startedAt, end);\n const cycles = group.work.cycles;\n // Folded quiet cycles report their wall-clock span: waits are the point.\n if (cycles)\n return {\n kind: \"worked\",\n label: t(\"timeline.workPresentation.countUpdatesOver\", { count: cycles.count }),\n durationMs,\n };\n return {\n kind: \"worked\",\n durationMs: durationMs === undefined ? undefined : Math.max(0, durationMs - pausedMs),\n };\n }\n if (group.work.waiting) {\n const { untimed, since, ...waiting } = group.work.waiting;\n return { kind: \"waiting\", ...waiting, ...(untimed ? {} : { since }) };\n }\n const started = Date.parse(group.work.startedAt);\n return {\n kind: \"working\",\n since:\n pausedMs > 0 && Number.isFinite(started)\n ? new Date(started + pausedMs).toISOString()\n : group.work.startedAt,\n };\n}\n\n/** Whether a readable turn's work fold starts expanded. */\nexport function readableWorkDefaultOpen(group: ActivityGroup): true | undefined {\n return timelineGroupContainsPresentedImage(group) ||\n group.outcome === \"failed\" ||\n group.items.some(\n (item) =>\n item.kind === \"startup-phase\" &&\n (item.status === \"failed\" ||\n // A cancelled phase with a blocked reason is an expected wait (for\n // example compacting the conversation first), not an interruption.\n (item.status === \"cancelled\" && !item.blockedReason)),\n )\n ? true\n : undefined;\n}\n\n/** Whether the live preview should show (images stay primary output instead). */\nexport function readableWorkShowsPreview(group: ActivityGroup): boolean {\n return !timelineGroupContainsPresentedImage(group);\n}\n\n/**\n * The step a rolling preview shows: steps advance with event order (progress notes and\n * startup phases have their own surfaces). Mirrors the web RollingActivity selection.\n */\nexport function rollingActivityItem(\n items: readonly ActivityItem[],\n previousItem?: ActivityItem,\n mounted = true,\n): { item: ActivityItem; running: boolean; earlierCount: number } | null {\n const work = items.filter(\n (item) => item.kind !== \"startup-phase\" && item.kind !== \"agent-message\",\n );\n const active = work.filter((item) =>\n item.kind === \"reasoning\" ? item.streaming : \"status\" in item && item.status === \"running\",\n );\n const item =\n !mounted && previousItem && previousItem.kind !== \"agent-message\" ? previousItem : work.at(-1);\n if (!item) return null;\n return {\n item,\n running: active.some((entry) => entry.id === item.id),\n earlierCount: Math.max(\n 0,\n work.findIndex((entry) => entry.id === item.id),\n ),\n };\n}\n\nexport function isToolCall(item: ActivityItem): item is ToolCallItem {\n return item.kind === \"tool-call\";\n}\n","import type {\n GeneratePasswordSpec,\n HumanInputAnswer,\n HumanInputQuestion,\n HumanInputSecretAnswer,\n HumanInputSecretAnswerResult,\n HumanInputSecretSaveTo,\n HumanInputSecretSpec,\n} from \"@opengeni/sdk\";\nimport { type OpenGeniText } from \"./messages/runtime\";\n\n/* Pure drafting and validation rules for structured human-input requests,\n shared by the web HumanInputForm and non-DOM renderers. */\n\nexport type HumanInputAnswerDraft = {\n values: string[];\n other: string;\n otherSelected: boolean;\n};\n\nexport type HumanInputFormMessages = {\n title: string;\n description: string;\n submit: string;\n skip: string;\n submitting: string;\n other: string;\n deadlineLabel: string;\n formatDeadline: (value: string) => string;\n required: string;\n otherRequired: string;\n minSelections: (count: number) => string;\n maxSelections: (count: number) => string;\n optional: string;\n /** Shown when the question list overflows the card and more content is below. */\n moreBelow: string;\n questionCount: (count: number) => string;\n collapse: string;\n expand: string;\n selectionHint: (min: number | null | undefined, max: number | null | undefined) => string | null;\n /** Secret questions (`kind: \"secret\"`). */\n secretShow: string;\n secretHide: string;\n secretGenerate: string;\n /** Shown in place of the input when the server will generate the value. */\n secretWillGenerate: string;\n secretUndo: string;\n secretSaveTo: string;\n secretSaveToOptions: Record<HumanInputSecretSaveTo, string>;\n /** One line under Save to: where the value goes. `vault` is the agent's named vault, if any. */\n secretVaultHint: (saveTo: HumanInputSecretSaveTo, vault: string | null) => string;\n /** The requested Save to is not allowed for this person. */\n secretSaveToDowngraded: (\n requested: HumanInputSecretSaveTo,\n actual: HumanInputSecretSaveTo,\n ) => string;\n secretLooksLike: (example: string) => string;\n /** Soft warning only: the value does not match the agent's pattern. */\n secretPatternWarning: (looksLike: string | null) => string;\n /** The answered chip: \"Saved to Private › GitHub\". */\n secretSaved: (vaultName: string, itemName: string) => string;\n};\n\nconst SAVE_TO_IN_SENTENCE = (t: OpenGeniText): Record<HumanInputSecretSaveTo, string> => ({\n user: t(\"humanInputModel.onlyMe\"),\n task: t(\"humanInputModel.thisTask\"),\n workspace: t(\"humanInputModel.thisWorkspace\"),\n});\n\nexport const defaultHumanInputFormMessages = (t: OpenGeniText): HumanInputFormMessages => ({\n title: t(\"humanInputModel.inputRequired\"),\n /** Multi-question chrome has no default subtitle; hosts may still override. */\n description: \"\",\n submit: t(\"humanInputModel.sendAnswers\"),\n skip: t(\"humanInputModel.skip\"),\n submitting: t(\"humanInputModel.submitting\"),\n other: t(\"humanInputModel.other\"),\n deadlineLabel: t(\"humanInputModel.expires\"),\n formatDeadline: (value) => formatDeadline(t, value),\n required: t(\"humanInputModel.thisQuestionIsRequired\"),\n otherRequired: t(\"humanInputModel.enterAValueForOther\"),\n minSelections: (count) => t(\"humanInputModel.chooseAtLeastOptions\", { count }),\n maxSelections: (count) => t(\"humanInputModel.chooseNoMoreThanOptions\", { count }),\n optional: t(\"humanInputModel.optional\"),\n moreBelow: t(\"humanInputModel.moreBelow\"),\n questionCount: (count) => `${count} questions`,\n collapse: t(\"humanInputModel.collapse\"),\n expand: t(\"humanInputModel.expand\"),\n selectionHint: (min, max) => {\n if (min != null && max != null) return t(\"humanInputModel.chooseMinMax\", { min, max });\n if (min != null) return t(\"humanInputModel.chooseAtLeastMin\", { min });\n if (max != null) return t(\"humanInputModel.chooseUpToMax\", { max });\n return null;\n },\n secretShow: t(\"humanInputModel.show\"),\n secretHide: t(\"humanInputModel.hide\"),\n secretGenerate: t(\"humanInputModel.generate\"),\n secretWillGenerate: t(\"humanInputModel.aStrongPasswordWillBe\"),\n secretUndo: t(\"humanInputModel.undo\"),\n secretSaveTo: t(\"humanInputModel.saveTo\"),\n secretSaveToOptions: {\n user: t(\"humanInputModel.onlyMe\"),\n task: t(\"humanInputModel.thisTask2\"),\n workspace: t(\"humanInputModel.thisWorkspace2\"),\n },\n secretVaultHint: (saveTo, vault) =>\n vault\n ? t(\"humanInputModel.savesToTheVaultVault\", { vault })\n : saveTo === \"user\"\n ? t(\"humanInputModel.savesToYourPrivateVault\")\n : saveTo === \"task\"\n ? t(\"humanInputModel.savesToThisTask\")\n : t(\"humanInputModel.savesToTheWorkspaceVault\"),\n secretSaveToDowngraded: (requested, actual) =>\n t(\"humanInputModel.youCanTSaveTo\", {\n requested: SAVE_TO_IN_SENTENCE(t)[requested],\n actual: SAVE_TO_IN_SENTENCE(t)[actual],\n }),\n secretLooksLike: (example) => t(\"humanInputModel.looksLikeExample\", { example }),\n secretPatternWarning: (looksLike) =>\n looksLike\n ? t(\"humanInputModel.thisDoesnTLookLike\", { looksLike })\n : t(\"humanInputModel.thisDoesnTMatchThe\"),\n secretSaved: (vaultName, itemName) =>\n t(\"humanInputModel.savedToVaultnameItemname\", { vaultName, itemName }),\n});\n\n/**\n * Text, single- and multi-select drafts. Secret questions are not drafted:\n * their value lives only in an uncontrolled input and is collected with\n * {@link secretAnswerFromReading} at submit time.\n */\nexport function answersFromDrafts(\n t: OpenGeniText,\n questions: HumanInputQuestion[],\n drafts: Record<string, HumanInputAnswerDraft>,\n messageOverrides: Partial<HumanInputFormMessages> = {},\n): { answers: HumanInputAnswer[]; errors: Record<string, string> } {\n const messages = { ...defaultHumanInputFormMessages(t), ...messageOverrides };\n const answers: HumanInputAnswer[] = [];\n const errors: Record<string, string> = {};\n for (const question of questions) {\n if (question.kind === \"secret\") continue;\n const draft = drafts[question.id] ?? emptyDraft();\n const values = question.kind === \"text\" ? draft.values.filter(Boolean) : draft.values;\n const other = draft.otherSelected ? draft.other : \"\";\n const hasOther = Boolean(other.trim());\n const supplied = values.length + (hasOther ? 1 : 0);\n\n // Other-selected-but-empty must win over generic \"required\" — otherwise the\n // user sees the wrong diagnosis next to a clearly selected control.\n if (question.kind !== \"text\" && draft.otherSelected && !hasOther) {\n errors[question.id] = messages.otherRequired;\n continue;\n }\n\n if (question.required && supplied === 0) {\n errors[question.id] = messages.required;\n continue;\n }\n if (question.kind !== \"text\") {\n const min = question.validation?.minSelections;\n const max = question.kind === \"single_select\" ? 1 : question.validation?.maxSelections;\n if (min != null && supplied < min) {\n errors[question.id] = messages.minSelections(min);\n continue;\n }\n if (max != null && supplied > max) {\n errors[question.id] = messages.maxSelections(max);\n continue;\n }\n }\n if (supplied > 0) {\n answers.push({\n questionId: question.id,\n values,\n ...(hasOther ? { other } : {}),\n });\n }\n }\n return { answers, errors };\n}\n\nexport function initialDrafts(\n questions: HumanInputQuestion[],\n): Record<string, HumanInputAnswerDraft> {\n return Object.fromEntries(questions.map((question) => [question.id, emptyDraft()]));\n}\n\nexport function emptyDraft(): HumanInputAnswerDraft {\n return { values: [], other: \"\", otherSelected: false };\n}\n\nexport function formatDeadline(t: OpenGeniText, value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n const ms = date.getTime() - Date.now();\n if (ms <= 0) return t(\"humanInputModel.deadlinePassed\");\n const minutes = Math.round(ms / 60_000);\n if (minutes < 1) return t(\"humanInputModel.inUnderAMinute\");\n if (minutes < 60) return `in ${minutes}m`;\n const hours = Math.round(minutes / 60);\n if (hours < 48) return `in ${hours}h`;\n return date.toLocaleString(t.locale);\n}\n\n/** The form heading: a single question leads with its own label/prompt. */\nexport function humanInputHeading(\n questions: readonly HumanInputQuestion[],\n messages: Pick<HumanInputFormMessages, \"title\" | \"description\">,\n): { title: string; description: string | null } {\n const single = questions.length === 1 ? questions[0]! : null;\n return {\n title: single ? (single.label ?? single.prompt) : messages.title,\n description: single\n ? single.label\n ? single.prompt\n : (single.helpText ?? null)\n : messages.description || null,\n };\n}\n\n/* ---- secret questions ------------------------------------------------------ */\n\nexport const SECRET_SAVE_TO_ORDER: readonly HumanInputSecretSaveTo[] = [\n \"user\",\n \"task\",\n \"workspace\",\n];\n\nexport type SecretAutocomplete = \"current-password\" | \"new-password\" | \"one-time-code\" | \"off\";\n\n/**\n * The `autocomplete` token for the secret input. The contract defaults\n * `autocomplete` to \"current-password\", so that value is treated as \"not\n * chosen\": a TOTP field asks for a one-time code, and a field the person may\n * generate is a new password (password managers offer to create and save it).\n */\nexport function secretAutocomplete(spec: HumanInputSecretSpec): SecretAutocomplete {\n if (spec.autocomplete && spec.autocomplete !== \"current-password\") return spec.autocomplete;\n if (spec.fieldKind === \"totp\") return \"one-time-code\";\n if (spec.allowGenerate || spec.generate) return \"new-password\";\n return \"current-password\";\n}\n\n/** Digits keyboard on phones for one-time codes. */\nexport function secretInputMode(spec: HumanInputSecretSpec): \"numeric\" | undefined {\n return secretAutocomplete(spec) === \"one-time-code\" ? \"numeric\" : undefined;\n}\n\n/** A plain-text field kind is not concealed (no show/hide). */\nexport function secretConcealed(spec: HumanInputSecretSpec): boolean {\n return spec.fieldKind !== \"text\";\n}\n\n/** Generate is offered for concealed values the agent allows to be generated. */\nexport function secretCanGenerate(spec: HumanInputSecretSpec): boolean {\n return Boolean(spec.allowGenerate || spec.generate) && spec.fieldKind !== \"totp\";\n}\n\n/** The input's label: \"Password\", \"API key\", \"One-time code\", or the field name. */\nexport function secretFieldLabel(t: OpenGeniText, spec: HumanInputSecretSpec): string {\n const field = spec.field?.trim() || \"password\";\n if (spec.fieldKind === \"totp\" && field.toLowerCase() === \"password\")\n return t(\"humanInputModel.oneTimeCode\");\n if (spec.itemType === \"api_key\" && field.toLowerCase() === \"password\")\n return t(\"humanInputModel.apiKey\");\n if (spec.itemType === \"note\" && field.toLowerCase() === \"password\")\n return t(\"humanInputModel.note\");\n const words = field.replace(/[_-]+/g, \" \").replace(/\\s+/g, \" \").trim();\n return words.charAt(0).toUpperCase() + words.slice(1);\n}\n\nexport type SecretSaveToChoice = {\n /** What the agent asked for (contract default: \"user\"). */\n requested: HumanInputSecretSaveTo;\n /** The initial selection: the request, or the best allowed target. */\n initial: HumanInputSecretSaveTo;\n /** True when the request is not allowed and was replaced. */\n downgraded: boolean;\n /** Allowed choices in display order. */\n options: HumanInputSecretSaveTo[];\n};\n\n/**\n * Filter Save to by what this person may write. A request that is not allowed\n * falls back to the most private allowed target (Only me, then This task).\n */\nexport function resolveSecretSaveTo(\n spec: HumanInputSecretSpec,\n allowed: readonly HumanInputSecretSaveTo[] = SECRET_SAVE_TO_ORDER,\n): SecretSaveToChoice {\n const requested = spec.saveTo ?? \"user\";\n const options = SECRET_SAVE_TO_ORDER.filter((target) => allowed.includes(target));\n if (options.includes(requested)) {\n return { requested, initial: requested, downgraded: false, options };\n }\n // Nothing allowed is a host error; keep the request so the server decides.\n if (options.length === 0) {\n return { requested, initial: requested, downgraded: false, options: [requested] };\n }\n return { requested, initial: options[0]!, downgraded: true, options };\n}\n\n/** The vault the agent named applies only to the scope it asked for. */\nexport function secretVaultForTarget(\n spec: HumanInputSecretSpec,\n saveTo: HumanInputSecretSaveTo,\n): string | null {\n return spec.vault && saveTo === (spec.saveTo ?? \"user\") ? spec.vault : null;\n}\n\n/**\n * Soft check against the agent's `pattern` (a regular expression searched in\n * the value, not anchored). Never blocks submit; an invalid pattern is ignored.\n */\nexport function secretPatternMismatch(pattern: string | null | undefined, value: string): boolean {\n if (!pattern || !value) return false;\n let expression: RegExp;\n try {\n expression = new RegExp(pattern, \"u\");\n } catch {\n try {\n expression = new RegExp(pattern);\n } catch {\n return false;\n }\n }\n return !expression.test(value);\n}\n\n/** What a secret field holds at submit time. `value` exists only for this call. */\nexport type SecretFieldReading = {\n value: string | null;\n generate: GeneratePasswordSpec | null;\n username: string | null;\n saveTo: HumanInputSecretSaveTo;\n};\n\n/**\n * Build the write-only `secretAnswers` entry and the public answer for one\n * secret question. The public answer has no values: the server adds the\n * saved reference. Returns null for an unanswered optional question.\n */\nexport function secretAnswerFromReading(\n t: OpenGeniText,\n question: HumanInputQuestion,\n reading: SecretFieldReading,\n messageOverrides: Partial<HumanInputFormMessages> = {},\n): { answer: HumanInputAnswer; secretAnswer: HumanInputSecretAnswer } | { error: string } | null {\n const messages = { ...defaultHumanInputFormMessages(t), ...messageOverrides };\n const value = reading.generate ? null : reading.value || null;\n if (!reading.generate && value === null) {\n return question.required ? { error: messages.required } : null;\n }\n const username = reading.username?.trim() || null;\n const secretAnswer: HumanInputSecretAnswer = {\n questionId: question.id,\n ...(reading.generate ? { generate: reading.generate } : { value: value! }),\n ...(username ? { username } : {}),\n saveTo: reading.saveTo,\n };\n return { answer: { questionId: question.id, values: [] }, secretAnswer };\n}\n\n/** The answered chip label, never a value. */\nexport function secretAnswerLabel(\n t: OpenGeniText,\n result: HumanInputSecretAnswerResult,\n messageOverrides: Partial<HumanInputFormMessages> = {},\n): string {\n const messages = { ...defaultHumanInputFormMessages(t), ...messageOverrides };\n return messages.secretSaved(result.vaultName, result.itemName);\n}\n","import { formatClockTime } from \"../lib/format\";\nimport { formatElapsed } from \"./turn-summary-model\";\nimport type { NoticeItem } from \"./types\";\nimport { durationBetween } from \"./work-presentation\";\nimport { type OpenGeniText } from \"../messages/runtime\";\n\n/** An approval notice the person has since answered. */\nexport function noticeIsResolvedApproval(\n item: Pick<NoticeItem, \"approval\" | \"resolvedAt\">,\n): boolean {\n return Boolean(item.resolvedAt && item.approval);\n}\n\n/** A resolved approval notice reads as history. */\nexport function noticeDisplayText(\n t: OpenGeniText,\n item: Pick<NoticeItem, \"text\" | \"approval\" | \"resolvedAt\">,\n): string {\n return noticeIsResolvedApproval(item)\n ? t(\"timeline.noticePresentation.youRespondedToThisApproval\")\n : item.text;\n}\n\n/** Notice pill tone: failures stay red, an open wait keeps the waiting hue. */\nexport function noticeTone(\n item: Pick<NoticeItem, \"tone\" | \"resolvedAt\">,\n): \"failed\" | \"waiting\" | \"neutral\" {\n return item.tone === \"failed\"\n ? \"failed\"\n : item.tone === \"waiting\" && !item.resolvedAt\n ? \"waiting\"\n : \"neutral\";\n}\n\n/**\n * Plain-text summary of a recorded agent wait, as web's quiet disclosure reads\n * it: \"Waited for 2 agents · 3m 5s\" once later input ended the wait, otherwise\n * \"Waiting · since 10:32\" (with the date on a later day).\n */\nexport function recordedWaitSummaryText(\n t: OpenGeniText,\n item: Pick<NoticeItem, \"occurredAt\" | \"waitingAgents\" | \"waitEndedAt\">,\n now: Date = new Date(),\n): string {\n const agents = item.waitingAgents ?? 0;\n const waitedMs = item.waitEndedAt\n ? durationBetween(item.occurredAt, item.waitEndedAt)\n : undefined;\n if (waitedMs !== undefined) {\n const elapsed = formatElapsed(t, waitedMs);\n return agents > 0\n ? t(\"timeline.noticePresentation.waitedForAgentsElapsed\", { count: agents, elapsed })\n : t(\"timeline.noticePresentation.waitedElapsed\", { elapsed });\n }\n const started = new Date(item.occurredAt);\n const since =\n started.toDateString() === now.toDateString()\n ? formatClockTime(t, item.occurredAt)\n : started.toLocaleString(t.locale, { dateStyle: \"medium\", timeStyle: \"short\" });\n if (item.waitEndedAt)\n return agents > 0\n ? t(\"timeline.noticePresentation.waitedForAgentsSince\", { count: agents, since })\n : t(\"timeline.noticePresentation.waitedSince\", { since });\n return agents > 0\n ? t(\"timeline.noticePresentation.waitingForAgentsSince\", { count: agents, since })\n : t(\"timeline.noticePresentation.waitingSince\", { since });\n}\n","/**\n * \"Back to your message\": which prompt the reader is reading the answer to, and\n * whether that prompt has scrolled out of view. Renderer-neutral geometry so\n * the web timeline (DOM rects) and native timelines (layout offsets) agree.\n */\n\n/** How far above the viewport a prompt must be before the pill appears. */\nexport const QUESTION_NAV_HIDDEN_PX = 24;\n/** Breathing room above the question when the reader jumps back to it. */\nexport const QUESTION_NAV_MARGIN_PX = 12;\n\nexport type QuestionNavPrompt = { key: string; top: number; bottom: number };\n\n/**\n * The last prompt before the reading position (the viewport's middle) owns the\n * response in view; it is a target only once it has scrolled fully above the\n * viewport. Prompts are in document order; coordinates share one axis.\n */\nexport function questionNavTarget(\n prompts: readonly QuestionNavPrompt[],\n view: { top: number; height: number },\n): string | null {\n const middle = view.top + view.height / 2;\n const prompt = [...prompts].reverse().find((candidate) => candidate.top <= middle);\n if (!prompt) return null;\n if (prompt.top >= view.top - QUESTION_NAV_HIDDEN_PX || prompt.bottom > view.top) return null;\n return prompt.key;\n}\n","import type { TimelineGroup, TimelineItem } from \"./types\";\n\n/*\n * Landing on a moment in a session: an inbox item or a phone notification\n * points at the durable event that raised it, and the timeline opens on the\n * row that holds that moment. Events that render no row of their own (an\n * agent's notification, a goal change) land on the nearest row before them.\n */\n\nfunction itemSequences(item: TimelineItem): number[] {\n const sources =\n item.sourceEvents ??\n (\"annotationSource\" in item && item.annotationSource ? [item.annotationSource] : []);\n return sources.map((source) => source.sequence);\n}\n\n/** Every durable event sequence a group renders, nested work included. */\nexport function timelineGroupSequences(group: TimelineGroup): number[] {\n if (group.kind === \"item\") return itemSequences(group.item);\n if (group.kind === \"turn\") return group.groups.flatMap(timelineGroupSequences);\n return [\n ...group.items.flatMap((item) => itemSequences(item)),\n ...(group.work?.details.flatMap(timelineGroupSequences) ?? []),\n ];\n}\n\n/**\n * The index of the group to land on for `sequence`: the group that holds it,\n * else the last group that starts before it. -1 when every loaded group is\n * later (the moment is in older history) or nothing is loaded.\n */\nexport function timelineGroupIndexAtSequence(\n groups: readonly TimelineGroup[],\n sequence: number,\n): number {\n let landing = -1;\n for (let index = 0; index < groups.length; index += 1) {\n const sequences = timelineGroupSequences(groups[index]!);\n if (sequences.length === 0) continue;\n if (sequences.includes(sequence)) return index;\n if (Math.min(...sequences) <= sequence) landing = index;\n }\n return landing;\n}\n"],"mappings":"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","names":["item"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/timeline-annotation-selection.tsx"],"sourcesContent":["import type { DraftTimelineAnnotation } from \"@opengeni/sdk\";\nimport { QuoteIcon } from \"lucide-react\";\nimport { useEffect, useRef, useState, type RefObject } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { usePortalContainer } from \"../ui/portal-container\";\nimport { usePortalTokenStyle } from \"../lib/use-portal-token-style\";\nimport type { TimelineAnnotationSourceDescriptor } from \"../timeline\";\nimport {\n clipRangeToSource,\n matchingQuoteInSource,\n occurrenceOffsets,\n quoteOccurrenceIndex,\n truncateAnnotationQuote,\n visibleClientRect,\n} from \"./timeline-annotation-shared\";\nimport { useOpenGeniText } from \"../messages/runtime\";\n\ntype SelectionCandidate = {\n annotation: DraftTimelineAnnotation;\n left: number;\n top: number;\n keyboard: boolean;\n};\n\nconst CONTROL_SELECTOR = \"button,input,textarea,select,summary,[contenteditable='true']\";\nconst SOURCE_CONTEXT_BYTES = 160;\nconst MAX_QUOTE_BYTES = 16 * 1024;\nconst POPOVER_WIDTH = 280;\nconst POPOVER_HEIGHT = 64;\n\nfunction utf8Prefix(value: string, maxBytes: number): string {\n let output = \"\";\n let bytes = 0;\n for (const character of value) {\n const next = new TextEncoder().encode(character).byteLength;\n if (bytes + next > maxBytes) break;\n output += character;\n bytes += next;\n }\n return output;\n}\n\nfunction utf8Suffix(value: string, maxBytes: number): string {\n let output = \"\";\n let bytes = 0;\n for (const character of [...value].reverse()) {\n const next = new TextEncoder().encode(character).byteLength;\n if (bytes + next > maxBytes) break;\n output = character + output;\n bytes += next;\n }\n return output;\n}\n\nfunction selectionElement(node: Node | null): Element | null {\n return node instanceof Element ? node : (node?.parentElement ?? null);\n}\n\nfunction containingSource(node: Node | null): HTMLElement | null {\n const element = selectionElement(node);\n const source = element?.closest(\"[data-og-annotation-source-key]\");\n return source instanceof HTMLElement ? source : null;\n}\n\nfunction resolveSourceBoundary(range: Range, root: HTMLElement): HTMLElement | null {\n const start = containingSource(range.startContainer);\n const end = containingSource(range.endContainer);\n if (start && end && start !== end) return null;\n const boundary = start ?? end;\n if (!boundary || !root.contains(boundary)) return null;\n return boundary;\n}\n\nfunction isWhollyInsideControl(range: Range, boundary: HTMLElement): boolean {\n const start = selectionElement(range.startContainer)?.closest(CONTROL_SELECTOR);\n const end = selectionElement(range.endContainer)?.closest(CONTROL_SELECTOR);\n return (\n start instanceof Element && start === end && boundary.contains(start) && start !== boundary\n );\n}\n\nfunction annotationId(): string {\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n return `annotation-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction popoverPosition(rect: DOMRect): { left: number; top: number } {\n const half = POPOVER_WIDTH / 2;\n const left = clamp(rect.left + rect.width / 2, 12 + half, window.innerWidth - 12 - half);\n const preferBelow = rect.bottom + 8 + POPOVER_HEIGHT <= window.innerHeight - 12;\n const top = preferBelow ? rect.bottom + 8 : Math.max(12, rect.top - POPOVER_HEIGHT - 8);\n return { left, top };\n}\n\nfunction buildCandidate(\n root: HTMLElement,\n sources: ReadonlyMap<string, TimelineAnnotationSourceDescriptor>,\n keyboard: boolean,\n): SelectionCandidate | null {\n const selection = document.getSelection();\n if (!selection || selection.rangeCount !== 1 || selection.isCollapsed) return null;\n const range = selection.getRangeAt(0);\n const startBoundary = resolveSourceBoundary(range, root);\n if (!startBoundary) return null;\n if (isWhollyInsideControl(range, startBoundary)) return null;\n const clipped = clipRangeToSource(range, startBoundary);\n if (!clipped) return null;\n const sourceKey = startBoundary.dataset.ogAnnotationSourceKey;\n const source = sourceKey ? sources.get(sourceKey) : undefined;\n const rawQuote = clipped.toString();\n const quote = (source ? matchingQuoteInSource(source.text, rawQuote) : null) ?? rawQuote;\n if (\n !source ||\n quote.trim().length === 0 ||\n new TextEncoder().encode(quote).byteLength > MAX_QUOTE_BYTES\n ) {\n return null;\n }\n const sourceOffsets = occurrenceOffsets(source.text, quote);\n if (sourceOffsets.length === 0) return null;\n const occurrence = quoteOccurrenceIndex(startBoundary, clipped, quote);\n const startOffset = sourceOffsets[Math.min(occurrence, sourceOffsets.length - 1)]!;\n const endOffset = startOffset + quote.length;\n const rect = visibleClientRect(range) ?? visibleClientRect(clipped);\n if (!rect) return null;\n const position = popoverPosition(rect);\n return {\n annotation: {\n id: annotationId(),\n quote,\n note: \"\",\n source: {\n kind: source.kind,\n eventId: source.eventId,\n eventType: source.eventType,\n sequence: source.sequence,\n turnId: source.turnId,\n startOffset,\n endOffset,\n contextBefore: utf8Suffix(source.text.slice(0, startOffset), SOURCE_CONTEXT_BYTES),\n contextAfter: utf8Prefix(source.text.slice(endOffset), SOURCE_CONTEXT_BYTES),\n ...(source.label ? { label: source.label } : {}),\n },\n },\n left: position.left,\n top: position.top,\n keyboard,\n };\n}\n\nexport function TimelineAnnotationSelection({\n rootRef,\n sources,\n onAnnotate,\n}: {\n rootRef: RefObject<HTMLElement | null>;\n sources: ReadonlyMap<string, TimelineAnnotationSourceDescriptor>;\n onAnnotate?: ((annotation: DraftTimelineAnnotation) => void) | undefined;\n}) {\n const t = useOpenGeniText();\n const [candidate, setCandidate] = useState<SelectionCandidate | null>(null);\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n const initialSelectionObservedRef = useRef(false);\n const pointerOriginRef = useRef<\"unset\" | \"inside\" | \"outside\">(\"unset\");\n const portalContainer = usePortalContainer();\n const portalStyle = usePortalTokenStyle(rootRef.current);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root || !onAnnotate) {\n setCandidate(null);\n return;\n }\n const update = (keyboard: boolean) => {\n setCandidate(buildCandidate(root, sources, keyboard));\n };\n // A user may finish selecting text before this lazy component arrives.\n // Reconcile once; later prop changes must not revive dismissed selections.\n if (!initialSelectionObservedRef.current) {\n initialSelectionObservedRef.current = true;\n update(false);\n }\n const onRootPointerUp = (event: PointerEvent) => {\n if (event.target instanceof Node && buttonRef.current?.contains(event.target)) return;\n // Tests may fire only pointerup on the source. A real click that started\n // outside the timeline must not resurrect leftover selection.\n if (pointerOriginRef.current === \"outside\") return;\n window.setTimeout(() => update(false), 0);\n };\n const onDocumentPointerUp = (event: PointerEvent) => {\n if (event.target instanceof Node && buttonRef.current?.contains(event.target)) return;\n const startedInRoot = pointerOriginRef.current === \"inside\";\n pointerOriginRef.current = \"unset\";\n if (!startedInRoot) return;\n window.setTimeout(() => update(false), 0);\n };\n const onKeyUp = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setCandidate(null);\n return;\n }\n window.setTimeout(() => update(true), 0);\n };\n const onPointerDown = (event: PointerEvent) => {\n if (event.target instanceof Node && buttonRef.current?.contains(event.target)) {\n event.preventDefault();\n return;\n }\n pointerOriginRef.current =\n event.target instanceof Node && root.contains(event.target) ? \"inside\" : \"outside\";\n setCandidate(null);\n };\n const onDocumentKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setCandidate(null);\n };\n const onSelectionChange = () => {\n if (buttonRef.current && document.activeElement === buttonRef.current) return;\n const selection = document.getSelection();\n if (!selection || selection.isCollapsed) setCandidate(null);\n };\n root.addEventListener(\"pointerup\", onRootPointerUp);\n root.addEventListener(\"keyup\", onKeyUp);\n document.addEventListener(\"pointerup\", onDocumentPointerUp);\n document.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"keydown\", onDocumentKeyDown);\n document.addEventListener(\"selectionchange\", onSelectionChange);\n return () => {\n root.removeEventListener(\"pointerup\", onRootPointerUp);\n root.removeEventListener(\"keyup\", onKeyUp);\n document.removeEventListener(\"pointerup\", onDocumentPointerUp);\n document.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"keydown\", onDocumentKeyDown);\n document.removeEventListener(\"selectionchange\", onSelectionChange);\n };\n }, [onAnnotate, rootRef, sources]);\n\n useEffect(() => {\n if (candidate?.keyboard) buttonRef.current?.focus();\n }, [candidate]);\n\n if (!candidate || !onAnnotate || typeof document === \"undefined\") return null;\n const preview = truncateAnnotationQuote(candidate.annotation.quote, 72);\n return createPortal(\n <button\n ref={buttonRef}\n type=\"button\"\n data-og-annotation-popover=\"\"\n style={{ left: candidate.left, top: candidate.top, ...portalStyle }}\n className=\"og-root fixed z-[80] flex max-w-[min(18rem,calc(100vw-1.5rem))] -translate-x-1/2 items-start gap-2 rounded-2xl border border-og-border bg-og-surface-1 px-3 py-2 text-og-sm font-medium text-og-fg shadow-xl outline-hidden transition hover:border-og-accent/40 hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-[44px]\"\n aria-label={t(\"timelineAnnotationSelection.addANoteAboutPreview\", { preview })}\n title={candidate.annotation.quote}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => {\n onAnnotate(candidate.annotation);\n document.getSelection()?.removeAllRanges();\n setCandidate(null);\n }}\n >\n <QuoteIcon className=\"mt-0.5 size-3.5 shrink-0 text-og-accent\" aria-hidden=\"true\" />\n <span className=\"min-w-0 text-left\">\n <span className=\"block leading-5\">{t(\"timelineAnnotationSelection.addNote\")}</span>\n <span className=\"mt-0.5 block truncate text-og-xs font-normal text-og-fg-muted\">\n {preview}\n </span>\n </span>\n </button>,\n portalContainer ?? document.body,\n );\n}\n\nexport default TimelineAnnotationSelection;\n"],"mappings":"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","names":[]}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
|
|
3
|
-
import { matchesShortcut, NEW_SESSION_SHORTCUT, shortcutLabel } from "./keyboard-shortcuts";
|
|
4
|
-
|
|
5
|
-
function key(
|
|
6
|
-
overrides: Partial<{
|
|
7
|
-
code: string;
|
|
8
|
-
metaKey: boolean;
|
|
9
|
-
ctrlKey: boolean;
|
|
10
|
-
shiftKey: boolean;
|
|
11
|
-
altKey: boolean;
|
|
12
|
-
repeat: boolean;
|
|
13
|
-
}> = {},
|
|
14
|
-
) {
|
|
15
|
-
return {
|
|
16
|
-
code: "KeyO",
|
|
17
|
-
metaKey: false,
|
|
18
|
-
ctrlKey: false,
|
|
19
|
-
shiftKey: false,
|
|
20
|
-
altKey: false,
|
|
21
|
-
repeat: false,
|
|
22
|
-
...overrides,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
describe("keyboard shortcuts", () => {
|
|
27
|
-
test("matches Cmd/Ctrl+Shift+O for new session", () => {
|
|
28
|
-
const chord = NEW_SESSION_SHORTCUT.chord;
|
|
29
|
-
expect(matchesShortcut(key({ metaKey: true, shiftKey: true }), chord)).toBe(true);
|
|
30
|
-
expect(matchesShortcut(key({ ctrlKey: true, shiftKey: true }), chord)).toBe(true);
|
|
31
|
-
expect(matchesShortcut(key({ metaKey: true }), chord)).toBe(false);
|
|
32
|
-
expect(matchesShortcut(key({ shiftKey: true }), chord)).toBe(false);
|
|
33
|
-
expect(matchesShortcut(key({ metaKey: true, shiftKey: true, altKey: true }), chord)).toBe(
|
|
34
|
-
false,
|
|
35
|
-
);
|
|
36
|
-
expect(matchesShortcut(key({ metaKey: true, shiftKey: true, code: "KeyN" }), chord)).toBe(
|
|
37
|
-
false,
|
|
38
|
-
);
|
|
39
|
-
expect(matchesShortcut(key({ metaKey: true, shiftKey: true, repeat: true }), chord)).toBe(
|
|
40
|
-
false,
|
|
41
|
-
);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("labels prefer Apple glyphs when on Apple", () => {
|
|
45
|
-
expect(shortcutLabel(NEW_SESSION_SHORTCUT)).toMatch(/⌘⇧O|Ctrl\+Shift\+O/);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* App-global keyboard shortcuts.
|
|
3
|
-
*
|
|
4
|
-
* Chords use Cmd on Apple platforms and Ctrl elsewhere (`metaOrCtrl`). Keep this
|
|
5
|
-
* list small and conflict-aware — a Cmd-K command palette can surface these later.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export type ShortcutChord = {
|
|
9
|
-
/** `KeyboardEvent.code`, e.g. `"KeyO"`. Layout-stable vs `event.key`. */
|
|
10
|
-
code: string;
|
|
11
|
-
/** Require ⌘ (Mac) or Ctrl (Win/Linux). */
|
|
12
|
-
metaOrCtrl: boolean;
|
|
13
|
-
shift?: boolean;
|
|
14
|
-
alt?: boolean;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export type AppShortcut = {
|
|
18
|
-
id: string;
|
|
19
|
-
chord: ShortcutChord;
|
|
20
|
-
/** Tooltip / help labels. */
|
|
21
|
-
label: { mac: string; other: string };
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const NEW_SESSION_SHORTCUT = {
|
|
25
|
-
id: "new-session",
|
|
26
|
-
chord: { code: "KeyO", metaOrCtrl: true, shift: true },
|
|
27
|
-
label: { mac: "⌘⇧O", other: "Ctrl+Shift+O" },
|
|
28
|
-
} as const satisfies AppShortcut;
|
|
29
|
-
|
|
30
|
-
/** Every registered app shortcut — grow here; palette can read this later. */
|
|
31
|
-
export const APP_SHORTCUTS = [NEW_SESSION_SHORTCUT] as const;
|
|
32
|
-
|
|
33
|
-
export function isApplePlatform(): boolean {
|
|
34
|
-
if (typeof navigator === "undefined") return false;
|
|
35
|
-
const uaData = (navigator as Navigator & { userAgentData?: { platform?: string } }).userAgentData;
|
|
36
|
-
const platform = uaData?.platform ?? navigator.platform ?? "";
|
|
37
|
-
return /Mac|iPhone|iPad|iPod/i.test(platform);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function shortcutLabel(shortcut: Pick<AppShortcut, "label">): string {
|
|
41
|
-
return isApplePlatform() ? shortcut.label.mac : shortcut.label.other;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function matchesShortcut(
|
|
45
|
-
event: Pick<KeyboardEvent, "code" | "metaKey" | "ctrlKey" | "shiftKey" | "altKey" | "repeat">,
|
|
46
|
-
chord: ShortcutChord,
|
|
47
|
-
): boolean {
|
|
48
|
-
if (event.repeat) return false;
|
|
49
|
-
if (event.code !== chord.code) return false;
|
|
50
|
-
if (Boolean(chord.shift) !== event.shiftKey) return false;
|
|
51
|
-
if (Boolean(chord.alt) !== event.altKey) return false;
|
|
52
|
-
if (chord.metaOrCtrl) {
|
|
53
|
-
if (!(event.metaKey || event.ctrlKey)) return false;
|
|
54
|
-
} else if (event.metaKey || event.ctrlKey) {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
File without changes
|
/package/dist/{browser-viewer-ZRFZX3VN.js.map → app/components/credits/credit-refusal-notice.js.map}
RENAMED
|
File without changes
|
/package/dist/{chat-interactive-block-HUMYWVCK.js.map → app/lib/actions/actions-provider.js.map}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|