@openchambery/web 1.18.4-beta.14 → 1.18.4-beta.16
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/assets/{AgentAvatar-DAnelAnB.js → AgentAvatar-DDcjamcJ.js} +1 -1
- package/dist/assets/AssistantView-2oaKAdLl.js +1 -0
- package/dist/assets/{ChatContainer-C5G5Fr2b.js → ChatContainer-C3okCjTT.js} +40 -40
- package/dist/assets/{DiagramView-CzcoibbD.js → DiagramView-BdWjzN9Y.js} +1 -1
- package/dist/assets/{FadeInOnReveal-QxF1vuqX.js → FadeInOnReveal-By2F9vcI.js} +1 -1
- package/dist/assets/{Icon-D-X70irR.js → Icon-DpjYnXxn.js} +1 -1
- package/dist/assets/{MarkdownRendererImpl-D2QG5Cyz.js → MarkdownRendererImpl-DXzGhggv.js} +1 -1
- package/dist/assets/{MobileDetailNavigation-DsQJ4trf.js → MobileDetailNavigation-BxzzbVuo.js} +1 -1
- package/dist/assets/{MobileShareBridge-Bd1-7DML.js → MobileShareBridge-CO5oEylO.js} +3 -3
- package/dist/assets/MobileSurface-DS_tuMUX.js +2 -0
- package/dist/assets/{MultiRunWindow-BuyE-Pqt.js → MultiRunWindow-D_z9Yrj0.js} +1 -1
- package/dist/assets/{OnboardingScreen-Cx79VlTN.js → OnboardingScreen-BKmuT7AL.js} +1 -1
- package/dist/assets/{OverlayScrollbar-CHXk_jvF.js → OverlayScrollbar-Ch3J6ASR.js} +1 -1
- package/dist/assets/{SettingsView-CLHUtoGC.js → SettingsView-Dq4d1azT.js} +6 -6
- package/dist/assets/{SettingsWindow-jzHzqlrP.js → SettingsWindow-B-2mGlsr.js} +1 -1
- package/dist/assets/{TerminalView-Da9C2w1w.js → TerminalView-BGg8vpYk.js} +1 -1
- package/dist/assets/{ToolOutputDialog-CKHIer6h.js → ToolOutputDialog-TUgfUyPX.js} +1 -1
- package/dist/assets/{appThemeRegistry-C7KndtrT.js → appThemeRegistry-DYl9pc39.js} +2 -2
- package/dist/assets/{button-CwLFtUNT.js → button-C7OXr4ae.js} +1 -1
- package/dist/assets/{clipboard-BfgFef1i.js → clipboard-DWuULPzo.js} +1 -1
- package/dist/assets/{collapsible-CP1-_pY6.js → collapsible-DaEya6b6.js} +1 -1
- package/dist/assets/{context-menu-BNOtF78w.js → context-menu-CHKr-Ai0.js} +1 -1
- package/dist/assets/{desktopHosts-Cr3LE55y.js → desktopHosts-Txp4xOVQ.js} +1 -1
- package/dist/assets/desktopRelayRestore-C_FSEHKM.js +1 -0
- package/dist/assets/{diagram-rYL80jaS.js → diagram-CHfginjS.js} +1 -1
- package/dist/assets/{dialog-GR7KoP1o.js → dialog-DPS0W9eS.js} +1 -1
- package/dist/assets/{es-Bi4m8Mm6.js → es-BX0Vm3Ac.js} +1 -1
- package/dist/assets/fileQueries-BrUKKgPW.js +1 -0
- package/dist/assets/{fr-B5UdepyS.js → fr-CuPzXTYx.js} +1 -1
- package/dist/assets/{gitApi-BAEyohtw.js → gitApi-CBvO-0tn.js} +3 -3
- package/dist/assets/{input-D52Jicb1.js → input-BzYA603C.js} +1 -1
- package/dist/assets/insertionBoundaries-DOABfwfW.js +1 -0
- package/dist/assets/{ja-KtFuRjvm.js → ja-DGtzjrFO.js} +1 -1
- package/dist/assets/{ko-CWpFVSCH.js → ko-DZ9Di0je.js} +1 -1
- package/dist/assets/{main-Bk1Xkd1S.js → main-CfHT5-XW.js} +2 -2
- package/dist/assets/{main-BpPkJxmD.js → main-DmE2qI1o.js} +23 -23
- package/dist/assets/{markdown-worker-N9d_Z-7s.js → markdown-worker-W06-MhF5.js} +1 -1
- package/dist/assets/{markdownTheme-Bl0Sy0Lf.js → markdownTheme-B89dbj3N.js} +1 -1
- package/dist/assets/{miniChat-toYPrHwe.js → miniChat-2PBRWMPo.js} +2 -2
- package/dist/assets/mobile-BllXjQxK.js +2 -0
- package/dist/assets/{multirun-Yeg_Lc4g.js → multirun-CFX1tCht.js} +1 -1
- package/dist/assets/{persistence-vZ7H8WKh.js → persistence-6sclr7B6.js} +2 -2
- package/dist/assets/{pl-30X8TD5i.js → pl-BuCO3qb1.js} +1 -1
- package/dist/assets/{platform-CTaznShj.js → platform-CbeLpKPk.js} +1 -1
- package/dist/assets/projectMeta-BqjXxia6.js +3 -0
- package/dist/assets/{pt-BR-Cm-Klf0E.js → pt-BR-Brf4RMsw.js} +1 -1
- package/dist/assets/radio-DpGoPQGD.js +1 -0
- package/dist/assets/renderElectronMiniChatApp-DtSye_u8.js +2 -0
- package/dist/assets/renderMobileApp-BDpsb0XZ.js +23 -0
- package/dist/assets/{runtimeConfig-VyMtYAl_.js → runtimeConfig-qlXnVd3m.js} +1 -1
- package/dist/assets/runtimeEndpointReset-CBslSisj.js +147 -0
- package/dist/assets/{sortable-tabs-strip-BYmWSdS9.js → sortable-tabs-strip-nLsPC06f.js} +1 -1
- package/dist/assets/{src-Dbdlm5x1.css → src-06zk77Ia.css} +1 -1
- package/dist/assets/{store-Z1MxUaP4.js → store-DQY8Fkb0.js} +2 -2
- package/dist/assets/{terminalApi-KDUc5mh2.js → terminalApi-BpPeXWIu.js} +1 -1
- package/dist/assets/{tooltip-CaCe-GAm.js → tooltip-D_orJMYd.js} +1 -1
- package/dist/assets/{uk-Cgc5wXrs.js → uk-C-wmaPTi.js} +1 -1
- package/dist/assets/{url-B-FWrnxu.js → url-BsaBG5-1.js} +1 -1
- package/dist/assets/useAppFontEffects-D6a67KZ8.js +7 -0
- package/dist/assets/{useAssistantUIStore-ifqNyja4.js → useAssistantUIStore-BHsHXCKE.js} +1 -1
- package/dist/assets/{useDesktopWindowControlsLayout-CA8kRyzR.js → useDesktopWindowControlsLayout-B-P1qfXu.js} +1 -1
- package/dist/assets/{useEffectiveDirectory-Fl_r2Mvz.js → useEffectiveDirectory-DLsYww1j.js} +1 -1
- package/dist/assets/{useFontPreferences-D_LFFhFS.js → useFontPreferences-ckzpXQaJ.js} +1 -1
- package/dist/assets/useMobileNavigationStore-wm9JzfV_.js +475 -0
- package/dist/assets/useSessionAutoCleanup-IpHMdVbd.js +1 -0
- package/dist/assets/useUIStore-DzwCfRqr.js +1 -0
- package/dist/assets/{useWorkerHighlightedLines-C-c4vn3t.js → useWorkerHighlightedLines-B2PxEV54.js} +1 -1
- package/dist/assets/{utils-C2P0wcWO.js → utils-B1EK5zKa.js} +1 -1
- package/dist/assets/{zh-CN-BdRwDJuj.js → zh-CN-DueRrIql.js} +1 -1
- package/dist/assets/{zh-TW-C3LubKzZ.js → zh-TW-6875X80V.js} +1 -1
- package/dist/index.html +9 -9
- package/dist/mini-chat.html +9 -9
- package/dist/mobile.html +9 -9
- package/package.json +1 -1
- package/server/lib/notifications/DOCUMENTATION.md +2 -1
- package/server/lib/notifications/emitter-runtime.js +78 -1
- package/server/lib/notifications/emitter-runtime.test.js +94 -1
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +4 -1
- package/server/lib/scheduled-tasks/routes.js +51 -8
- package/server/lib/ui-auth/ui-auth.js +3 -1
- package/server/lib/ui-auth/ui-auth.test.js +25 -0
- package/server/sse-routes.test.js +64 -1
- package/dist/assets/AssistantView-CY4rsyXp.js +0 -1
- package/dist/assets/MobileSurface-CLyIIwQa.js +0 -2
- package/dist/assets/desktopRelayRestore-VfMK9fdk.js +0 -1
- package/dist/assets/fileQueries-CXaw4b1W.js +0 -1
- package/dist/assets/insertionBoundaries-DEVtR-jV.js +0 -1
- package/dist/assets/mobile-Cbb8zwcX.js +0 -2
- package/dist/assets/projectMeta-fvbfTReY.js +0 -3
- package/dist/assets/radio-CN_9l3le.js +0 -1
- package/dist/assets/renderElectronMiniChatApp-ETMoC_Rd.js +0 -2
- package/dist/assets/renderMobileApp-BSPouSPr.js +0 -23
- package/dist/assets/runtimeEndpointReset-DYSOSjpp.js +0 -147
- package/dist/assets/useAppFontEffects-DFXMOIvM.js +0 -7
- package/dist/assets/useMobileNavigationStore-DyfmQCpj.js +0 -476
- package/dist/assets/useSessionAutoCleanup-DyqGjW0i.js +0 -1
- package/dist/assets/useUIStore-NfqK-HA7.js +0 -1
package/dist/index.html
CHANGED
|
@@ -552,25 +552,25 @@
|
|
|
552
552
|
opacity: 0.72;
|
|
553
553
|
}
|
|
554
554
|
</style>
|
|
555
|
-
<script type="module" crossorigin src="/assets/main-
|
|
555
|
+
<script type="module" crossorigin src="/assets/main-CfHT5-XW.js"></script>
|
|
556
556
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
|
|
557
557
|
<link rel="modulepreload" crossorigin href="/assets/vendor-base-ui-CnHfUmDN.js">
|
|
558
558
|
<link rel="modulepreload" crossorigin href="/assets/vendor-zustand-B4dlGEM2.js">
|
|
559
|
-
<link rel="modulepreload" crossorigin href="/assets/useUIStore-
|
|
559
|
+
<link rel="modulepreload" crossorigin href="/assets/useUIStore-DzwCfRqr.js">
|
|
560
560
|
<link rel="modulepreload" crossorigin href="/assets/vendor-pathe-vBmvQE8f.js">
|
|
561
561
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-DLPElpoQ.js">
|
|
562
562
|
<link rel="modulepreload" crossorigin href="/assets/vendor-tanstack-query-core-BWz0ose6.js">
|
|
563
|
-
<link rel="modulepreload" crossorigin href="/assets/persistence-
|
|
564
|
-
<link rel="modulepreload" crossorigin href="/assets/desktopHosts-
|
|
565
|
-
<link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-
|
|
563
|
+
<link rel="modulepreload" crossorigin href="/assets/persistence-6sclr7B6.js">
|
|
564
|
+
<link rel="modulepreload" crossorigin href="/assets/desktopHosts-Txp4xOVQ.js">
|
|
565
|
+
<link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-C_FSEHKM.js">
|
|
566
566
|
<link rel="modulepreload" crossorigin href="/assets/vendor-opencode-sdk-C07HQypa.js">
|
|
567
567
|
<link rel="modulepreload" crossorigin href="/assets/vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js">
|
|
568
|
-
<link rel="modulepreload" crossorigin href="/assets/platform-
|
|
569
|
-
<link rel="modulepreload" crossorigin href="/assets/terminalApi-
|
|
568
|
+
<link rel="modulepreload" crossorigin href="/assets/platform-CbeLpKPk.js">
|
|
569
|
+
<link rel="modulepreload" crossorigin href="/assets/terminalApi-BpPeXWIu.js">
|
|
570
570
|
<link rel="modulepreload" crossorigin href="/assets/types-BuiqMmh_.js">
|
|
571
571
|
<link rel="modulepreload" crossorigin href="/assets/capgoAdapter-DCowZ2ab.js">
|
|
572
|
-
<link rel="modulepreload" crossorigin href="/assets/runtimeConfig-
|
|
573
|
-
<link rel="stylesheet" crossorigin href="/assets/src-
|
|
572
|
+
<link rel="modulepreload" crossorigin href="/assets/runtimeConfig-qlXnVd3m.js">
|
|
573
|
+
<link rel="stylesheet" crossorigin href="/assets/src-06zk77Ia.css">
|
|
574
574
|
</head>
|
|
575
575
|
<body class="h-full bg-background text-foreground">
|
|
576
576
|
<!-- Keep the startup layer outside #root. React replaces every child of
|
package/dist/mini-chat.html
CHANGED
|
@@ -74,25 +74,25 @@
|
|
|
74
74
|
}
|
|
75
75
|
</style>
|
|
76
76
|
|
|
77
|
-
<script type="module" crossorigin src="/assets/miniChat-
|
|
77
|
+
<script type="module" crossorigin src="/assets/miniChat-2PBRWMPo.js"></script>
|
|
78
78
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
|
|
79
79
|
<link rel="modulepreload" crossorigin href="/assets/vendor-base-ui-CnHfUmDN.js">
|
|
80
80
|
<link rel="modulepreload" crossorigin href="/assets/vendor-zustand-B4dlGEM2.js">
|
|
81
|
-
<link rel="modulepreload" crossorigin href="/assets/useUIStore-
|
|
81
|
+
<link rel="modulepreload" crossorigin href="/assets/useUIStore-DzwCfRqr.js">
|
|
82
82
|
<link rel="modulepreload" crossorigin href="/assets/vendor-pathe-vBmvQE8f.js">
|
|
83
83
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-DLPElpoQ.js">
|
|
84
84
|
<link rel="modulepreload" crossorigin href="/assets/vendor-tanstack-query-core-BWz0ose6.js">
|
|
85
|
-
<link rel="modulepreload" crossorigin href="/assets/persistence-
|
|
86
|
-
<link rel="modulepreload" crossorigin href="/assets/desktopHosts-
|
|
87
|
-
<link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-
|
|
85
|
+
<link rel="modulepreload" crossorigin href="/assets/persistence-6sclr7B6.js">
|
|
86
|
+
<link rel="modulepreload" crossorigin href="/assets/desktopHosts-Txp4xOVQ.js">
|
|
87
|
+
<link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-C_FSEHKM.js">
|
|
88
88
|
<link rel="modulepreload" crossorigin href="/assets/vendor-opencode-sdk-C07HQypa.js">
|
|
89
89
|
<link rel="modulepreload" crossorigin href="/assets/vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js">
|
|
90
|
-
<link rel="modulepreload" crossorigin href="/assets/platform-
|
|
91
|
-
<link rel="modulepreload" crossorigin href="/assets/terminalApi-
|
|
90
|
+
<link rel="modulepreload" crossorigin href="/assets/platform-CbeLpKPk.js">
|
|
91
|
+
<link rel="modulepreload" crossorigin href="/assets/terminalApi-BpPeXWIu.js">
|
|
92
92
|
<link rel="modulepreload" crossorigin href="/assets/types-BuiqMmh_.js">
|
|
93
93
|
<link rel="modulepreload" crossorigin href="/assets/capgoAdapter-DCowZ2ab.js">
|
|
94
|
-
<link rel="modulepreload" crossorigin href="/assets/runtimeConfig-
|
|
95
|
-
<link rel="stylesheet" crossorigin href="/assets/src-
|
|
94
|
+
<link rel="modulepreload" crossorigin href="/assets/runtimeConfig-qlXnVd3m.js">
|
|
95
|
+
<link rel="stylesheet" crossorigin href="/assets/src-06zk77Ia.css">
|
|
96
96
|
</head>
|
|
97
97
|
<body class="h-full bg-background text-foreground">
|
|
98
98
|
<div id="root" class="h-full">
|
package/dist/mobile.html
CHANGED
|
@@ -63,25 +63,25 @@
|
|
|
63
63
|
})();
|
|
64
64
|
</script>
|
|
65
65
|
|
|
66
|
-
<script type="module" crossorigin src="/assets/mobile-
|
|
66
|
+
<script type="module" crossorigin src="/assets/mobile-BllXjQxK.js"></script>
|
|
67
67
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
|
|
68
68
|
<link rel="modulepreload" crossorigin href="/assets/vendor-base-ui-CnHfUmDN.js">
|
|
69
69
|
<link rel="modulepreload" crossorigin href="/assets/vendor-zustand-B4dlGEM2.js">
|
|
70
|
-
<link rel="modulepreload" crossorigin href="/assets/useUIStore-
|
|
70
|
+
<link rel="modulepreload" crossorigin href="/assets/useUIStore-DzwCfRqr.js">
|
|
71
71
|
<link rel="modulepreload" crossorigin href="/assets/vendor-pathe-vBmvQE8f.js">
|
|
72
72
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-DLPElpoQ.js">
|
|
73
73
|
<link rel="modulepreload" crossorigin href="/assets/vendor-tanstack-query-core-BWz0ose6.js">
|
|
74
|
-
<link rel="modulepreload" crossorigin href="/assets/persistence-
|
|
75
|
-
<link rel="modulepreload" crossorigin href="/assets/desktopHosts-
|
|
76
|
-
<link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-
|
|
74
|
+
<link rel="modulepreload" crossorigin href="/assets/persistence-6sclr7B6.js">
|
|
75
|
+
<link rel="modulepreload" crossorigin href="/assets/desktopHosts-Txp4xOVQ.js">
|
|
76
|
+
<link rel="modulepreload" crossorigin href="/assets/desktopRelayRestore-C_FSEHKM.js">
|
|
77
77
|
<link rel="modulepreload" crossorigin href="/assets/vendor-opencode-sdk-C07HQypa.js">
|
|
78
78
|
<link rel="modulepreload" crossorigin href="/assets/vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js">
|
|
79
|
-
<link rel="modulepreload" crossorigin href="/assets/platform-
|
|
80
|
-
<link rel="modulepreload" crossorigin href="/assets/terminalApi-
|
|
79
|
+
<link rel="modulepreload" crossorigin href="/assets/platform-CbeLpKPk.js">
|
|
80
|
+
<link rel="modulepreload" crossorigin href="/assets/terminalApi-BpPeXWIu.js">
|
|
81
81
|
<link rel="modulepreload" crossorigin href="/assets/types-BuiqMmh_.js">
|
|
82
82
|
<link rel="modulepreload" crossorigin href="/assets/capgoAdapter-DCowZ2ab.js">
|
|
83
|
-
<link rel="modulepreload" crossorigin href="/assets/runtimeConfig-
|
|
84
|
-
<link rel="stylesheet" crossorigin href="/assets/src-
|
|
83
|
+
<link rel="modulepreload" crossorigin href="/assets/runtimeConfig-qlXnVd3m.js">
|
|
84
|
+
<link rel="stylesheet" crossorigin href="/assets/src-06zk77Ia.css">
|
|
85
85
|
</head>
|
|
86
86
|
<body class="h-full bg-background text-foreground">
|
|
87
87
|
<div id="root" class="h-full"></div>
|
package/package.json
CHANGED
|
@@ -77,9 +77,10 @@ This module provides notification message preparation utilities for the web serv
|
|
|
77
77
|
### Emitter runtime API (emitter-runtime.js)
|
|
78
78
|
- `createNotificationEmitterRuntime(dependencies)`: creates runtime for unified notification emission channels.
|
|
79
79
|
- Returned API:
|
|
80
|
-
- `writeSseEvent(res, payload)`
|
|
80
|
+
- `writeSseEvent(res, payload)` — best-effort SSE write with backpressure: when `res.write` returns `false`, the client is marked paused and further writes are skipped until `drain`; buffered bytes above `SSE_CLIENT_MAX_BUFFERED_BYTES` (2 MiB, aligned with relay-server) destroy the response. Authoritative data remains HTTP pull.
|
|
81
81
|
- `emitDesktopNotification(payload)`
|
|
82
82
|
- `broadcastUiNotification(payload)`
|
|
83
|
+
- Exported constant: `SSE_CLIENT_MAX_BUFFERED_BYTES`
|
|
83
84
|
|
|
84
85
|
### Template runtime API (template-runtime.js)
|
|
85
86
|
- `createNotificationTemplateRuntime(dependencies)`: creates shared notification/template runtime. Model-backed summarization was retired after the Zen provider became unavailable.
|
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
// Align with relay-server per-connection queue cap (2 MiB).
|
|
2
|
+
export const SSE_CLIENT_MAX_BUFFERED_BYTES = 2 * 1024 * 1024;
|
|
3
|
+
|
|
4
|
+
const isSseResponseClosed = (res) => Boolean(res?.writableEnded || res?.destroyed);
|
|
5
|
+
|
|
6
|
+
const getSseBufferedBytes = (res) => {
|
|
7
|
+
if (typeof res?.writableLength === 'number' && Number.isFinite(res.writableLength)) {
|
|
8
|
+
return res.writableLength;
|
|
9
|
+
}
|
|
10
|
+
const tracked = res?.__sseBufferedBytes;
|
|
11
|
+
return typeof tracked === 'number' && Number.isFinite(tracked) ? tracked : 0;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const attachSseDrainListener = (res) => {
|
|
15
|
+
if (res.__sseDrainAttached) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
res.__sseDrainAttached = true;
|
|
19
|
+
res.once('drain', () => {
|
|
20
|
+
res.__ssePaused = false;
|
|
21
|
+
res.__sseBufferedBytes = 0;
|
|
22
|
+
res.__sseDrainAttached = false;
|
|
23
|
+
res.__ssePausedHeartbeatCycles = 0;
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Intentional resource protection for slow/zombie SSE clients.
|
|
28
|
+
// SSE is best-effort; authoritative data is fetched over HTTP.
|
|
29
|
+
const destroySseClientForBackpressure = (res) => {
|
|
30
|
+
try {
|
|
31
|
+
if (!res.destroyed) {
|
|
32
|
+
res.destroy();
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
// ignore — cleanup must stay idempotent
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
1
39
|
export const createNotificationEmitterRuntime = (dependencies) => {
|
|
2
40
|
const {
|
|
3
41
|
process,
|
|
@@ -23,7 +61,46 @@ export const createNotificationEmitterRuntime = (dependencies) => {
|
|
|
23
61
|
};
|
|
24
62
|
|
|
25
63
|
const writeSseEvent = (res, payload) => {
|
|
26
|
-
res
|
|
64
|
+
if (!res || isSseResponseClosed(res)) {
|
|
65
|
+
throw new Error('SSE response closed');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Drop while backpressured — SSE is best-effort; authoritative data is HTTP pull.
|
|
69
|
+
if (res.__ssePaused) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const data = `data: ${JSON.stringify(payload)}\n\n`;
|
|
74
|
+
const byteLength = Buffer.byteLength(data);
|
|
75
|
+
|
|
76
|
+
let ok;
|
|
77
|
+
try {
|
|
78
|
+
ok = res.write(data);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
destroySseClientForBackpressure(res);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const bufferedBytes = ok === false
|
|
85
|
+
? Math.max(getSseBufferedBytes(res), (res.__sseBufferedBytes || 0) + byteLength)
|
|
86
|
+
: getSseBufferedBytes(res);
|
|
87
|
+
res.__sseBufferedBytes = bufferedBytes;
|
|
88
|
+
|
|
89
|
+
if (bufferedBytes > SSE_CLIENT_MAX_BUFFERED_BYTES) {
|
|
90
|
+
// Intentional resource protection: a slow client must not unbounded-buffer
|
|
91
|
+
// response body in host memory. SSE is best-effort; authoritative data is
|
|
92
|
+
// fetched over HTTP.
|
|
93
|
+
destroySseClientForBackpressure(res);
|
|
94
|
+
throw new Error('SSE client buffer exceeded');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (ok === false) {
|
|
98
|
+
res.__ssePaused = true;
|
|
99
|
+
attachSseDrainListener(res);
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return true;
|
|
27
104
|
};
|
|
28
105
|
|
|
29
106
|
const emitDesktopNotification = (payload) => {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createNotificationEmitterRuntime,
|
|
5
|
+
SSE_CLIENT_MAX_BUFFERED_BYTES,
|
|
6
|
+
} from './emitter-runtime.js';
|
|
4
7
|
|
|
5
8
|
const createRuntime = (overrides = {}) => createNotificationEmitterRuntime({
|
|
6
9
|
process: { stdout: { write: vi.fn() } },
|
|
@@ -11,6 +14,59 @@ const createRuntime = (overrides = {}) => createNotificationEmitterRuntime({
|
|
|
11
14
|
...overrides,
|
|
12
15
|
});
|
|
13
16
|
|
|
17
|
+
const createMockSseResponse = ({ writeImpl } = {}) => {
|
|
18
|
+
const listeners = new Map();
|
|
19
|
+
let destroyed = false;
|
|
20
|
+
let writableEnded = false;
|
|
21
|
+
let bufferedBytes = 0;
|
|
22
|
+
|
|
23
|
+
const res = {
|
|
24
|
+
get destroyed() {
|
|
25
|
+
return destroyed;
|
|
26
|
+
},
|
|
27
|
+
get writableEnded() {
|
|
28
|
+
return writableEnded;
|
|
29
|
+
},
|
|
30
|
+
get writableLength() {
|
|
31
|
+
return bufferedBytes;
|
|
32
|
+
},
|
|
33
|
+
on(event, handler) {
|
|
34
|
+
listeners.set(event, handler);
|
|
35
|
+
return this;
|
|
36
|
+
},
|
|
37
|
+
once(event, handler) {
|
|
38
|
+
listeners.set(event, handler);
|
|
39
|
+
return this;
|
|
40
|
+
},
|
|
41
|
+
emit(event) {
|
|
42
|
+
const handler = listeners.get(event);
|
|
43
|
+
listeners.delete(event);
|
|
44
|
+
if (typeof handler === 'function') {
|
|
45
|
+
handler();
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
write(chunk) {
|
|
49
|
+
if (typeof writeImpl === 'function') {
|
|
50
|
+
return writeImpl(chunk, {
|
|
51
|
+
addBuffered(bytes) {
|
|
52
|
+
bufferedBytes += bytes;
|
|
53
|
+
},
|
|
54
|
+
getBuffered() {
|
|
55
|
+
return bufferedBytes;
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
},
|
|
61
|
+
destroy() {
|
|
62
|
+
destroyed = true;
|
|
63
|
+
this.emit('error');
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return res;
|
|
68
|
+
};
|
|
69
|
+
|
|
14
70
|
describe('notification emitter runtime', () => {
|
|
15
71
|
it('reports desktop delivery through the injected native callback', () => {
|
|
16
72
|
const onDesktopNotification = vi.fn();
|
|
@@ -44,4 +100,41 @@ describe('notification emitter runtime', () => {
|
|
|
44
100
|
},
|
|
45
101
|
});
|
|
46
102
|
});
|
|
103
|
+
|
|
104
|
+
it('pauses slow SSE clients when write returns false and skips further buffering until drain', () => {
|
|
105
|
+
const runtime = createRuntime();
|
|
106
|
+
let writeCount = 0;
|
|
107
|
+
const res = createMockSseResponse({
|
|
108
|
+
writeImpl(chunk, { addBuffered }) {
|
|
109
|
+
writeCount += 1;
|
|
110
|
+
addBuffered(Buffer.byteLength(String(chunk)));
|
|
111
|
+
return false;
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(runtime.writeSseEvent(res, { type: 'a' })).toBe(false);
|
|
116
|
+
expect(res.__ssePaused).toBe(true);
|
|
117
|
+
expect(writeCount).toBe(1);
|
|
118
|
+
|
|
119
|
+
expect(runtime.writeSseEvent(res, { type: 'b' })).toBe(false);
|
|
120
|
+
expect(writeCount).toBe(1);
|
|
121
|
+
|
|
122
|
+
res.emit('drain');
|
|
123
|
+
expect(res.__ssePaused).toBe(false);
|
|
124
|
+
expect(runtime.writeSseEvent(res, { type: 'c' })).toBe(false);
|
|
125
|
+
expect(writeCount).toBe(2);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('destroys an SSE client whose buffered bytes exceed the per-client cap', () => {
|
|
129
|
+
const runtime = createRuntime();
|
|
130
|
+
const res = createMockSseResponse({
|
|
131
|
+
writeImpl(chunk, { addBuffered }) {
|
|
132
|
+
addBuffered(SSE_CLIENT_MAX_BUFFERED_BYTES + Buffer.byteLength(String(chunk)));
|
|
133
|
+
return false;
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(() => runtime.writeSseEvent(res, { type: 'overflow' })).toThrow(/buffer exceeded/);
|
|
138
|
+
expect(res.destroyed).toBe(true);
|
|
139
|
+
});
|
|
47
140
|
});
|
|
@@ -31,7 +31,10 @@ Server-owned scheduled task runtime and routes for OpenChamber-only automation.
|
|
|
31
31
|
- Global run history list endpoint
|
|
32
32
|
- Project scheduled task CRUD endpoints
|
|
33
33
|
- Manual run endpoint
|
|
34
|
-
- OpenChamber events SSE stream endpoint
|
|
34
|
+
- OpenChamber events SSE stream endpoint (`GET /api/openchamber/events`): 25s
|
|
35
|
+
heartbeat interval unchanged; half-open clients that stay paused across two
|
|
36
|
+
consecutive heartbeat cycles are destroyed and removed from the client set
|
|
37
|
+
(idempotent cleanup). SSE is best-effort; authoritative data is HTTP pull.
|
|
35
38
|
- Returns persisted mutation results with `schedulerSynced`; a failed scheduler
|
|
36
39
|
sync schedules one bounded retry while preserving the committed response
|
|
37
40
|
|
|
@@ -321,6 +321,33 @@ export const registerScheduledTaskRoutes = (app, dependencies) => {
|
|
|
321
321
|
const clients = getOpenChamberEventClients();
|
|
322
322
|
clients.add(res);
|
|
323
323
|
|
|
324
|
+
let closed = false;
|
|
325
|
+
let heartbeatTimer = null;
|
|
326
|
+
// Half-open / stalled-drain eviction: destroy after this many consecutive
|
|
327
|
+
// heartbeat cycles while the socket remains paused (no drain). Interval
|
|
328
|
+
// itself is unchanged — only failure cleanup was added.
|
|
329
|
+
// SSE is best-effort; authoritative data is fetched over HTTP.
|
|
330
|
+
const maxPausedHeartbeatCycles = 2;
|
|
331
|
+
|
|
332
|
+
const cleanup = () => {
|
|
333
|
+
if (closed) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
closed = true;
|
|
337
|
+
if (heartbeatTimer) {
|
|
338
|
+
clearInterval(heartbeatTimer);
|
|
339
|
+
heartbeatTimer = null;
|
|
340
|
+
}
|
|
341
|
+
clients.delete(res);
|
|
342
|
+
try {
|
|
343
|
+
if (!res.destroyed && !res.writableEnded) {
|
|
344
|
+
res.destroy();
|
|
345
|
+
}
|
|
346
|
+
} catch {
|
|
347
|
+
// ignore — destroy + delete must stay idempotent
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
324
351
|
try {
|
|
325
352
|
writeSseEvent(res, {
|
|
326
353
|
type: 'openchamber:event-stream-ready',
|
|
@@ -329,25 +356,41 @@ export const registerScheduledTaskRoutes = (app, dependencies) => {
|
|
|
329
356
|
},
|
|
330
357
|
});
|
|
331
358
|
} catch {
|
|
359
|
+
cleanup();
|
|
360
|
+
return;
|
|
332
361
|
}
|
|
333
362
|
|
|
334
|
-
|
|
363
|
+
heartbeatTimer = setInterval(() => {
|
|
364
|
+
if (closed || res.writableEnded || res.destroyed) {
|
|
365
|
+
cleanup();
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
335
369
|
try {
|
|
336
|
-
writeSseEvent(res, {
|
|
370
|
+
const ok = writeSseEvent(res, {
|
|
337
371
|
type: 'openchamber:heartbeat',
|
|
338
372
|
properties: {
|
|
339
373
|
timestamp: Date.now(),
|
|
340
374
|
},
|
|
341
375
|
});
|
|
376
|
+
if (ok === false || res.__ssePaused) {
|
|
377
|
+
const cycles = (res.__ssePausedHeartbeatCycles || 0) + 1;
|
|
378
|
+
res.__ssePausedHeartbeatCycles = cycles;
|
|
379
|
+
if (cycles >= maxPausedHeartbeatCycles) {
|
|
380
|
+
// Intentional half-open cleanup: TCP may still look open while the
|
|
381
|
+
// relay tunnel is dead and drain never fires. SSE is best-effort;
|
|
382
|
+
// authoritative data is fetched over HTTP.
|
|
383
|
+
cleanup();
|
|
384
|
+
}
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
res.__ssePausedHeartbeatCycles = 0;
|
|
342
388
|
} catch {
|
|
343
|
-
|
|
344
|
-
clients.delete(res);
|
|
389
|
+
cleanup();
|
|
345
390
|
}
|
|
346
391
|
}, 25_000);
|
|
347
392
|
|
|
348
|
-
req.on('close',
|
|
349
|
-
|
|
350
|
-
clients.delete(res);
|
|
351
|
-
});
|
|
393
|
+
req.on('close', cleanup);
|
|
394
|
+
res.on('error', cleanup);
|
|
352
395
|
});
|
|
353
396
|
};
|
|
@@ -714,7 +714,9 @@ export const createUiAuth = ({
|
|
|
714
714
|
const respondUnauthorized = (req, res) => {
|
|
715
715
|
res.status(401);
|
|
716
716
|
const acceptsJson = req.headers.accept?.includes('application/json');
|
|
717
|
-
|
|
717
|
+
// Express strips the mount prefix from req.path (e.g. app.use('/api') turns
|
|
718
|
+
// /api/mcp into /mcp), so resolve the original pathname instead.
|
|
719
|
+
if (acceptsJson || getRequestPathname(req).startsWith('/api')) {
|
|
718
720
|
res.json({ error: 'UI authentication required', locked: true });
|
|
719
721
|
} else {
|
|
720
722
|
res.type('text/plain').send('Authentication required');
|
|
@@ -259,6 +259,31 @@ describe('ui auth client credential seam', () => {
|
|
|
259
259
|
}
|
|
260
260
|
});
|
|
261
261
|
|
|
262
|
+
it('returns JSON 401 for unauthenticated API requests mounted under a sub-app', async () => {
|
|
263
|
+
const createUiAuth = await loadCreateUiAuth();
|
|
264
|
+
const auth = createUiAuth({ password: 'secret' });
|
|
265
|
+
|
|
266
|
+
// Express strips the mount prefix: app.use('/api') turns /api/mcp into
|
|
267
|
+
// req.path '/mcp'. The unauthorized response must still be identified as an
|
|
268
|
+
// API request (JSON + locked) so clients can react to the auth gate.
|
|
269
|
+
const req = {
|
|
270
|
+
method: 'GET',
|
|
271
|
+
baseUrl: '/api',
|
|
272
|
+
path: '/mcp',
|
|
273
|
+
originalUrl: '/api/mcp',
|
|
274
|
+
url: '/api/mcp',
|
|
275
|
+
headers: {},
|
|
276
|
+
};
|
|
277
|
+
const res = createResponse();
|
|
278
|
+
let called = false;
|
|
279
|
+
await auth.requireAuth(req, res, () => {
|
|
280
|
+
called = true;
|
|
281
|
+
});
|
|
282
|
+
expect(called).toBe(false);
|
|
283
|
+
expect(res.statusCode).toBe(401);
|
|
284
|
+
expect(res.body).toEqual({ error: 'UI authentication required', locked: true });
|
|
285
|
+
});
|
|
286
|
+
|
|
262
287
|
it('issues desktop client tokens with the UI session expiry', async () => {
|
|
263
288
|
const createUiAuth = await loadCreateUiAuth();
|
|
264
289
|
let createClientInput = null;
|
|
@@ -52,8 +52,10 @@ const createMockResponse = () => {
|
|
|
52
52
|
let body = '';
|
|
53
53
|
let flushed = false;
|
|
54
54
|
let bodyFlushCount = 0;
|
|
55
|
+
let destroyed = false;
|
|
56
|
+
let writableEnded = false;
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
const res = {
|
|
57
59
|
on(event, handler) {
|
|
58
60
|
listeners.set(event, handler);
|
|
59
61
|
return this;
|
|
@@ -80,6 +82,9 @@ const createMockResponse = () => {
|
|
|
80
82
|
body += String(chunk);
|
|
81
83
|
return true;
|
|
82
84
|
},
|
|
85
|
+
destroy() {
|
|
86
|
+
destroyed = true;
|
|
87
|
+
},
|
|
83
88
|
status(code) {
|
|
84
89
|
statusCode = code;
|
|
85
90
|
return this;
|
|
@@ -100,7 +105,21 @@ const createMockResponse = () => {
|
|
|
100
105
|
get bodyFlushCount() {
|
|
101
106
|
return bodyFlushCount;
|
|
102
107
|
},
|
|
108
|
+
get destroyed() {
|
|
109
|
+
return destroyed;
|
|
110
|
+
},
|
|
111
|
+
set destroyed(value) {
|
|
112
|
+
destroyed = Boolean(value);
|
|
113
|
+
},
|
|
114
|
+
get writableEnded() {
|
|
115
|
+
return writableEnded;
|
|
116
|
+
},
|
|
117
|
+
set writableEnded(value) {
|
|
118
|
+
writableEnded = Boolean(value);
|
|
119
|
+
},
|
|
103
120
|
};
|
|
121
|
+
|
|
122
|
+
return res;
|
|
104
123
|
};
|
|
105
124
|
|
|
106
125
|
describe('local SSE routes', () => {
|
|
@@ -162,6 +181,7 @@ describe('local SSE routes', () => {
|
|
|
162
181
|
getOpenChamberEventClients: () => clients,
|
|
163
182
|
writeSseEvent(res, payload) {
|
|
164
183
|
res.write(`data: ${JSON.stringify(payload)}\n\n`);
|
|
184
|
+
return true;
|
|
165
185
|
},
|
|
166
186
|
});
|
|
167
187
|
|
|
@@ -183,4 +203,47 @@ describe('local SSE routes', () => {
|
|
|
183
203
|
req.emit('close');
|
|
184
204
|
expect(clients.has(res)).toBe(false);
|
|
185
205
|
});
|
|
206
|
+
|
|
207
|
+
it('evicts half-open OpenChamber SSE clients after consecutive paused heartbeats', () => {
|
|
208
|
+
vi.useFakeTimers();
|
|
209
|
+
const { app, getRoute } = createRouteRegistry();
|
|
210
|
+
const clients = new Set();
|
|
211
|
+
let destroyCount = 0;
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
registerScheduledTaskRoutes(app, {
|
|
215
|
+
getOpenChamberEventClients: () => clients,
|
|
216
|
+
writeSseEvent(res) {
|
|
217
|
+
res.__ssePaused = true;
|
|
218
|
+
return false;
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const handler = getRoute('GET', '/api/openchamber/events');
|
|
223
|
+
const req = createMockRequest();
|
|
224
|
+
const res = createMockResponse();
|
|
225
|
+
res.destroy = () => {
|
|
226
|
+
destroyCount += 1;
|
|
227
|
+
res.destroyed = true;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
handler(req, res);
|
|
231
|
+
expect(clients.has(res)).toBe(true);
|
|
232
|
+
|
|
233
|
+
vi.advanceTimersByTime(25_000);
|
|
234
|
+
expect(clients.has(res)).toBe(true);
|
|
235
|
+
expect(destroyCount).toBe(0);
|
|
236
|
+
|
|
237
|
+
vi.advanceTimersByTime(25_000);
|
|
238
|
+
expect(clients.has(res)).toBe(false);
|
|
239
|
+
expect(destroyCount).toBe(1);
|
|
240
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
241
|
+
|
|
242
|
+
// Idempotent cleanup: a late close must not throw or re-destroy.
|
|
243
|
+
req.emit('close');
|
|
244
|
+
expect(destroyCount).toBe(1);
|
|
245
|
+
} finally {
|
|
246
|
+
vi.useRealTimers();
|
|
247
|
+
}
|
|
248
|
+
});
|
|
186
249
|
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o as e,r as t}from"./rolldown-runtime-C0FnF6B9.js";import{A as n,E as r,t as i,w as a}from"./useUIStore-NfqK-HA7.js";import{Ot as o,et as s,rt as c,yt as l}from"./persistence-vZ7H8WKh.js";import{nt as u,rt as d}from"./vendor-base-ui-CnHfUmDN.js";import{r as f}from"./platform-CTaznShj.js";import{n as p}from"./vendor-react-DLPElpoQ.js";import{r as m}from"./vendor-sonner-DVzioF3d.js";import{n as h}from"./vendor-reactuses-core-DDoDDyM9.js";import{n as g}from"./clipboard-BfgFef1i.js";import{a as _,n as v,s as y}from"./MobileShareBridge-Bd1-7DML.js";import{$a as b,Co as x,Lo as S,Qr as C,So as w,Ui as T,Xa as E,_n as D,fa as O,gn as k,in as A,ln as j,ni as M,o as N,vn as P,wi as F}from"./useMobileNavigationStore-DyfmQCpj.js";import{_ as I,a as L,c as R,d as ee,f as te,g as ne,l as re,n as ie,o as ae,p as oe,r as se,t as z,v as B,x as V,y as ce}from"./MobileDetailNavigation-DsQJ4trf.js";import{i as le,r as ue}from"./useAssistantUIStore-ifqNyja4.js";import{t as de}from"./AgentAvatar-DAnelAnB.js";import{t as fe}from"./utils-C2P0wcWO.js";import{n as pe}from"./Icon-D-X70irR.js";import{a as H,i as me,n as he,o as U,r as W,t as G}from"./dialog-GR7KoP1o.js";import{t as ge}from"./button-CwLFtUNT.js";import{i as _e}from"./OverlayScrollbar-CHXk_jvF.js";import{I as ve,L as ye,M as be,N as K,q as xe,t as q}from"./ChatContainer-C5G5Fr2b.js";import{a as Se,i as Ce,n as we,r as Te,t as Ee}from"./context-menu-BNOtF78w.js";var De=p(),J=e(d(),1),Y=u(),Oe=e=>{let t=(0,De.c)(46),{assistant:n,sessionID:r,warning:i,surface:a,onRevertMessage:o,onEditMessage:s,pendingUserMessages:c,onPendingUserMessagesMaterialized:l}=e,u=n.effectiveWorkspacePath,d;t[0]!==n.sessionGeneration||t[1]!==r?(d={sessionID:r,sessionGeneration:n.sessionGeneration},t[0]=n.sessionGeneration,t[1]=r,t[2]=d):d=t[2];let p=B(n.id,d,a.active);p.data?.pages;let m;t[3]===p.data?.pages?m=t[4]:(m=p.data?.pages??[],t[3]=p.data?.pages,t[4]=m);let g;t[5]===m?g=t[6]:(g=F(m),t[5]=m,t[6]=g);let _=g,v;if(t[7]!==_){v=new Map;for(let e of _){let t=v.get(e.sessionID);v.set(e.sessionID,t===void 0||t===e.directory?e.directory:null)}t[7]=_,t[8]=v}else v=t[8];let y=v,b;t[9]===p?b=t[10]:(b=async()=>{(p.hasNextPage||p.isFetchNextPageError)&&await p.fetchNextPage()},t[9]=p,t[10]=b);let x=h(b),S=n.mode===`continuous`,C=be(),w;t[11]!==u||t[12]!==y||t[13]!==C||t[14]!==r?(w=(e,t)=>{let n=e===r?u:y.get(e);if(!n||n!==t){D(e,`missing-directory`);return}P(e,t,{phoneShell:!!(C&&!f()),switchToChat:!0})},t[11]=u,t[12]=y,t[13]=C,t[14]=r,t[15]=w):w=t[15];let T=h(w),E;t[16]===S?E=t[17]:(E={...K,forkSession:!1,navigateNestedSession:!1,mutateSession:S},t[16]=S,t[17]=E);let O;t[18]===s?O=t[19]:(O=s?{onEditMessage:s}:{},t[18]=s,t[19]=O);let k;t[20]!==u||t[21]!==o||t[22]!==T||t[23]!==r||t[24]!==a.active||t[25]!==a.surfaceID||t[26]!==E||t[27]!==O?(k={kind:`embedded`,surfaceId:a.surfaceID,sessionId:r,directory:u,active:a.active,capabilities:E,onRevertMessage:o,...O,openSourceSession:T},t[20]=u,t[21]=o,t[22]=T,t[23]=r,t[24]=a.active,t[25]=a.surfaceID,t[26]=E,t[27]=O,t[28]=k):k=t[28];let A=k,j=p.isError||p.isSuccess&&!p.hasNextPage,M=p.isLoading||p.isFetchingNextPage,N;t[29]!==x||t[30]!==j||t[31]!==_||t[32]!==M?(N={entries:_,complete:j,loading:M,fetchPrevious:x},t[29]=x,t[30]=j,t[31]=_,t[32]=M,t[33]=N):N=t[33];let I;t[34]!==u||t[35]!==l||t[36]!==o||t[37]!==c||t[38]!==r||t[39]!==A||t[40]!==a||t[41]!==N||t[42]!==i?(I={sessionId:r,directory:u,composerSurface:a,sessionSurface:A,warning:i,pendingUserMessages:c,onPendingUserMessagesMaterialized:l,assistantHistory:N,onRevertMessage:o},t[34]=u,t[35]=l,t[36]=o,t[37]=c,t[38]=r,t[39]=A,t[40]=a,t[41]=N,t[42]=i,t[43]=I):I=t[43];let L=I,R;return t[44]===L?R=t[45]:(R=(0,Y.jsx)(q,{autoOpenDraft:!1,host:L}),t[44]=L,t[45]=R),R},ke=class extends Error{constructor(){super(`assistant_selection_stale`)}},Ae=(e,t)=>e.assistantID===t.assistantID&&e.transportIdentity===t.transportIdentity&&e.runtimeGeneration===t.runtimeGeneration,je=class{onBusyChange;onError;flight=null;authoritativeIdentity=null;constructor(e,t){this.onBusyChange=e,this.onError=t}activate(e){this.authoritativeIdentity&&!Ae(this.authoritativeIdentity,e)&&this.flight&&this.retire(this.flight),this.authoritativeIdentity=e}enqueue(e,t,n){if(!this.isAuthoritative(e))return Promise.reject(new ke);let r=this.flight;r||(r={identity:e,controller:new AbortController,running:!1,desired:null,waiters:[],activeWaiters:[],idleWaiters:[],retired:!1},this.flight=r),r.desired=t;let i=new Promise((e,t)=>{r.waiters.push({resolve:e,reject:t})});return r.running||(r.running=!0,this.onBusyChange(!0),this.run(r,n)),i}async flush(e){if(!this.isAuthoritative(e))throw new ke;let t=this.flight;t?.running&&await new Promise((e,n)=>t.idleWaiters.push({resolve:e,reject:n}))}assertAuthoritative(e){if(!this.isAuthoritative(e))throw new ke}dispose(){this.flight&&this.retire(this.flight),this.authoritativeIdentity=null}async run(e,t){for(;!e.retired&&e.desired;){let n=e.desired;e.desired=null;let r=e.waiters.splice(0);e.activeWaiters=r;try{if(await t({identity:e.identity,selection:n,signal:e.controller.signal}),!e.retired)for(let e of r)e.resolve()}catch(t){if(!e.retired){this.onError(t);for(let e of r)e.reject(t)}}e.activeWaiters=[]}e.running=!1;for(let t of e.idleWaiters.splice(0))t.resolve();this.flight===e&&this.onBusyChange(!1)}retire(e){e.retired=!0,e.controller.abort();let t=new ke;for(let n of e.activeWaiters.splice(0))n.reject(t);for(let n of e.waiters.splice(0))n.reject(t);for(let n of e.idleWaiters.splice(0))n.reject(t);this.flight===e&&(this.flight=null,this.onBusyChange(!1))}isAuthoritative(e){return this.authoritativeIdentity!==null&&Ae(this.authoritativeIdentity,e)}},X=(e,t)=>{let n=t.providerID??e.providerID,r=t.modelID??e.modelID,i=n!==e.providerID||r!==e.modelID;return{enabled:e.enabled,name:e.name,defaultPrompt:e.defaultPrompt,workspacePath:e.workspacePath,providerID:n,modelID:r,agent:t.agent??null,variant:i?null:t.variant??null,mode:e.mode}},Me=async(e,t,n)=>{n.assertAuthoritative();let r=n.readSnapshot()?.assistants.find(t=>t.id===e.assistantID);if(!r)throw Error(`assistant_unavailable`);try{n.assertAuthoritative(),await n.updateAssistant(r,X(r,t)),n.assertAuthoritative()}catch(i){if(n.assertAuthoritative(),n.signal.aborted)throw new ke;if(!(i instanceof V)||i.code!==`revision_conflict`)throw i;if(n.assertAuthoritative(),r=(await n.ensureSnapshot(n.signal)).assistants.find(t=>t.id===e.assistantID),n.assertAuthoritative(),!r)throw new V(`revision_conflict`,409);n.assertAuthoritative(),await n.updateAssistant(r,X(r,t)),n.assertAuthoritative()}};async function Z(e){await L(e);let t=le.getState().defaultShareAssistant;if(t?.assistantID!==e.id)return;let n=await R();n.serverInstanceID&&t.serverInstanceID===n.serverInstanceID&&le.getState().setDefaultShareAssistant(null)}function Ne({assistant:e,open:t,onOpenChange:n,onDeleted:r}){let{t:i}=g(),[a,o]=J.useState(!1),s=e?_(e.name).displayName||e.name:``,c=h(e=>{a&&!e||n(e)}),l=h(()=>{a||n(!1)}),u=h(async()=>{if(!(!e||a)){o(!0);try{await Z(e),r?.(e.id),n(!1),m.success(i(`assistants.settings.toast.deleted`))}catch{m.error(i(`assistants.settings.toast.deleteFailed`))}finally{o(!1)}}});return(0,Y.jsx)(G,{open:t&&e!==null,onOpenChange:c,children:(0,Y.jsxs)(he,{className:`max-w-md`,children:[(0,Y.jsxs)(H,{children:[(0,Y.jsx)(U,{children:i(`assistants.settings.delete`)}),(0,Y.jsx)(W,{children:i(`assistants.settings.deleteConfirm`,{name:s})})]}),(0,Y.jsxs)(me,{children:[(0,Y.jsx)(ge,{size:`sm`,variant:`ghost`,onClick:l,disabled:a,children:i(`settings.common.actions.cancel`)}),(0,Y.jsx)(ge,{size:`sm`,variant:`destructive`,onClick:u,disabled:a,children:i(`settings.common.actions.delete`)})]})]})})}var Pe=[0,500,1500,4e3],Fe=(e,t,n)=>{let r=!1,i=e.map(e=>e.info.id!==t||e.info.sessionID===n?e:(r=!0,{...e,info:{...e.info,sessionID:n}}));return r?i:e},Ie=e=>{let t=e.refreshDelaysMs??Pe,n=e.sleep??(e=>new Promise(t=>setTimeout(t,e)));(async()=>{for(let r of t){if(r>0&&await n(r),!e.isCurrent())return;try{await e.refresh(e.binding);break}catch{}}})()},Le=e=>`${e.transport}\u0000${e.assistantID}`,Re=e=>({transport:e.transport,assistantID:e.assistantID}),ze=(e,t)=>e.assistantID===t.assistantID&&e.sessionID===t.sessionID&&e.directory===t.directory&&e.sessionGeneration===t.sessionGeneration&&e.transport===t.transport&&e.runtimeGeneration===t.runtimeGeneration,Be=(e,t)=>e.assistantID===t.assistantID&&e.sessionID===t.sessionID&&e.directory===t.directory&&e.sessionGeneration===t.sessionGeneration&&e.messageID===t.messageID&&e.transport===t.transport&&e.runtimeGeneration===t.runtimeGeneration,Ve=()=>{let e=new Map,t=new Map,n=1,r=e=>Le(e),i=async(e,n)=>{let i=r(e),a=t.get(i)??Promise.resolve(),o,s=new Promise(e=>{o=e}),c=a.catch(()=>void 0).then(()=>s);t.set(i,c),await a.catch(()=>void 0);try{return await n()}finally{o(),t.get(i)===c&&t.delete(i)}},a=(t,i)=>{let a=r(Re(t)),o=n++;return e.set(a,{identity:t,rollback:i,token:o}),o},o=t=>e.get(r(t))?.identity,s=t=>e.delete(r(t)),c=async e=>i(e,()=>s(e)),l=async t=>{let n=r(t),i=e.get(n);if(!i)return{kind:`none`};let a=i.token,o=i.identity,s;try{s=await i.rollback()}catch{return{kind:`blocked`,status:`failed`}}let c=e.get(n);return!c||c.token!==a||!Be(c.identity,o)?{kind:`superseded`}:s.status===`rolled-back`||s.status===`conflict`?(e.delete(n),{kind:`cleared`,status:s.status}):{kind:`blocked`,status:s.status}},u=async(t,n)=>{let i=r(t),a=e.get(i);if(!a)return{kind:`none`};if(ze(a.identity,n))return{kind:`match`};let o=a.token,s=a.identity,c=await a.rollback(),l=e.get(i);return!l||l.token!==o||!Be(l.identity,s)?{kind:`superseded`}:c.status===`rolled-back`||c.status===`conflict`?(e.delete(i),{kind:`cleared`,status:c.status}):{kind:`rollback_failed`,retained:!0,status:c.status}};return{register:a,read:o,clear:s,clearExclusive:c,retireCurrent:l,rollbackAndClearIfBindingMismatch:async(e,t)=>i(e,()=>u(e,t)),rollbackAllBestEffort:async t=>{let n=[...e.entries()];await Promise.all(n.map(async([,n])=>{if(t?.excludeTransport!==void 0&&n.identity.transport===t.excludeTransport)return;let a=Re(n.identity);await i(a,async()=>{let t=r(a),i=e.get(t);if(!i||i.token!==n.token)return;let o=i.token,s=i.identity;try{let n=await i.rollback(),r=e.get(t);if(!r||r.token!==o||!Be(r.identity,s))return;(n.status===`rolled-back`||n.status===`conflict`)&&e.delete(t)}catch{}})}))},stageExclusive:async(e,t)=>i(e,async()=>{let n=await l(e);if(n.kind===`blocked`)return{kind:`blocked`,status:n.status};let r=await t();if(!r)return{kind:`skipped`};let i=a(r.identity,r.rollback);return r.protectOnStale?{kind:`stale_protected`,token:i,identity:r.identity}:{kind:`registered`,token:i,identity:r.identity}})}},He=(e,t)=>!e?.attachments?.length||!t?[]:e.attachments.flatMap(e=>{let n=t[e.attachmentRefID];return n?[n]:[]}),Ue=(e,t)=>{let n=t??{};return e.map(e=>({partID:e.partID,text:e.text,...e.synthetic===!0?{synthetic:!0}:{},attachments:e.attachments.flatMap(e=>n[e.attachmentRefID]?[n[e.attachmentRefID]]:[])}))},We=(e,t)=>{if(t.length===0)return[...e];let n=new Map;for(let t of e)n.set(t.partID,t);for(let e of t)n.set(e.partID,e);let r=new Set,i=[];for(let t of e){let e=n.get(t.partID);e&&(i.push(e),r.add(t.partID))}for(let e of t)r.has(e.partID)||(i.push(e),r.add(e.partID));return i},Ge=t({AssistantView:()=>Qe}),Ke={},qe=[],Je=[],Ye=(e,t,n)=>[...e===void 0?[]:[{type:`text`,text:e}],...(t??[]).flatMap(e=>[{type:`text`,text:e.text,...e.synthetic===!0?{synthetic:!0}:{}},...(e.attachments??[]).map(e=>({type:`file`,mime:e.mimeType,url:e.dataUrl}))]),...(n??[]).map(e=>({type:`file`,mime:e.mimeType,url:e.dataUrl}))],Xe=e=>{let t=(0,De.c)(11),{assistant:n,onBack:r}=e,{t:i}=g(),a;t[0]===n?a=t[1]:(a=n?_(n.name):null,t[0]=n,t[1]=a);let o=a,s=n&&o?o.displayName||n.name:``,c;t[2]!==s||t[3]!==i?(c=s||i(`assistants.title`),t[2]=s,t[3]=i,t[4]=c):c=t[4];let l;t[5]===i?l=t[6]:(l=i(`assistants.actions.backToChat`),t[5]=i,t[6]=l);let u;return t[7]!==r||t[8]!==c||t[9]!==l?(u=(0,Y.jsx)(z,{title:c,backAriaLabel:l,onBack:r}),t[7]=r,t[8]=c,t[9]=l,t[10]=u):u=t[10],u},Ze=e=>{let t=(0,De.c)(45),{assistantID:n,displayName:r,avatarEmoji:i,modeLabel:a,selected:o,enabled:s,editLabel:c,deleteLabel:l,onSelect:u,onEdit:d,onDelete:f}=e,[p,m]=J.useState(!1),g;t[0]===u?g=t[1]:(g=()=>u(),t[0]=u,t[1]=g);let _=h(g),v;t[2]===d?v=t[3]:(v=()=>{m(!1),d()},t[2]=d,t[3]=v);let y=h(v),b;t[4]===f?b=t[5]:(b=()=>{m(!1),f()},t[4]=f,t[5]=b);let x=h(b),S;t[6]===Symbol.for(`react.memo_cache_sentinel`)?(S=e=>{e.preventDefault(),m(!0)},t[6]=S):S=t[6];let C=o?`border-border/50 bg-[var(--surface-elevated)]`:`border-transparent hover:bg-interactive-hover`,w=!s&&`opacity-65`,T;t[7]!==C||t[8]!==w?(T=fe(`flex w-full min-h-11 items-center gap-3 rounded-xl border px-3 py-3 text-left outline-none transition-[background-color,border-color,transform,opacity] duration-150 ease-out active:scale-[0.995] focus-visible:ring-2 focus-visible:ring-[var(--interactive-focus-ring)] motion-reduce:transition-none`,C,w),t[7]=C,t[8]=w,t[9]=T):T=t[9];let E;t[10]!==_||t[11]!==o||t[12]!==T?(E=(0,Y.jsx)(`button`,{type:`button`,role:`option`,"aria-selected":o,onClick:_,onContextMenu:S,className:T}),t[10]=_,t[11]=o,t[12]=T,t[13]=E):E=t[13];let D;t[14]!==n||t[15]!==i||t[16]!==r?(D=(0,Y.jsx)(de,{name:n,emoji:i,size:24,label:r}),t[14]=n,t[15]=i,t[16]=r,t[17]=D):D=t[17];let O;t[18]===r?O=t[19]:(O=(0,Y.jsx)(`span`,{className:`block truncate typography-ui-label font-medium`,children:r}),t[18]=r,t[19]=O);let k;t[20]===a?k=t[21]:(k=(0,Y.jsx)(`span`,{className:`mt-0.5 block truncate typography-micro text-muted-foreground`,children:a}),t[20]=a,t[21]=k);let A;t[22]!==O||t[23]!==k?(A=(0,Y.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[O,k]}),t[22]=O,t[23]=k,t[24]=A):A=t[24];let j;t[25]!==A||t[26]!==E||t[27]!==D?(j=(0,Y.jsxs)(Se,{render:E,children:[D,A]}),t[25]=A,t[26]=E,t[27]=D,t[28]=j):j=t[28];let M;t[29]===Symbol.for(`react.memo_cache_sentinel`)?(M=(0,Y.jsx)(pe,{name:`edit`,className:`size-4`}),t[29]=M):M=t[29];let N;t[30]!==c||t[31]!==y?(N=(0,Y.jsxs)(Te,{onClick:y,children:[M,c]}),t[30]=c,t[31]=y,t[32]=N):N=t[32];let P;t[33]===Symbol.for(`react.memo_cache_sentinel`)?(P=(0,Y.jsx)(Ce,{}),t[33]=P):P=t[33];let F;t[34]===Symbol.for(`react.memo_cache_sentinel`)?(F=(0,Y.jsx)(pe,{name:`delete-bin`,className:`size-4`}),t[34]=F):F=t[34];let I;t[35]!==l||t[36]!==x?(I=(0,Y.jsxs)(Te,{onClick:x,className:`text-[var(--status-error)] focus:text-[var(--status-error)] data-[highlighted]:text-[var(--status-error)] [&_svg]:text-[var(--status-error)]`,children:[F,l]}),t[35]=l,t[36]=x,t[37]=I):I=t[37];let L;t[38]!==N||t[39]!==I?(L=(0,Y.jsxs)(we,{className:`min-w-[10rem]`,children:[N,P,I]}),t[38]=N,t[39]=I,t[40]=L):L=t[40];let R;return t[41]!==p||t[42]!==j||t[43]!==L?(R=(0,Y.jsxs)(Ee,{open:p,onOpenChange:m,children:[j,L]}),t[41]=p,t[42]=j,t[43]=L,t[44]=R):R=t[44],R},Qe=({activeOverride:e,onMobileBack:t})=>{let{t:u}=g(),{isMobile:d}=_e(),f=be(),p=J.useSyncExternalStore(n,r,r),D=a(),P=i(e=>e.activeMainTab===`assistant`),F=e??P,L=i(e=>e.isMobile),R=d||L,z=I(),B=ce(),V=B.data,H=le(e=>e.assistantByTransport[p]??null),me=le(e=>e.selectAssistant),he=le(e=>e.requestCreate),U=V?.assistants.find(e=>e.id===H)??null,W=U?.id??``,G=U?.sessionID??``,K=U?.effectiveWorkspacePath??``,q=J.useMemo(()=>o({transportIdentity:p},`assistant:${W}`),[W,p]),Se=l(q),Ce=S(e=>e.draftAttachmentViews[Se]??Ke),we=S(e=>e.drafts[Se]),Te=J.useMemo(()=>{let e=He(we,Ce);return e.length===0?qe:e},[Ce,we]),Ee=we?.attachments,De=we?.syntheticParts,Ae=J.useMemo(()=>!Ee||!De?``:`${Ee.map(e=>e.attachmentRefID).join(``)}\u0004${De.map(e=>`${e.partID}\u0002${e.attachments.map(e=>e.attachmentRefID).join(``)}`).join(``)}`,[Ee,De]);J.useEffect(()=>{W&&S.getState().hydrateDraftAttachments(q)},[W,q,Ae]);let X=x(K||null,{enabled:!!K&&F}),Z=w(K||null,{enabled:!!K&&F}),Pe=A(G,K||void 0),Le=j(G,K||void 0),ze=k(G),Be=xe(),[Ge,Qe]=J.useState(()=>new Map),$e=J.useRef(0),et=J.useRef(Ve()),tt=Ge.get(W)??Je,[,nt]=J.useState(!1),rt=J.useRef(()=>{});rt.current=()=>{m.error(u(`assistants.composer.selectionSaveFailed`))};let it=J.useRef(null);it.current||=new je(nt,e=>rt.current(e));let at=J.useMemo(()=>({assistantID:W,transportIdentity:p,runtimeGeneration:D}),[W,D,p]),Q=it.current,ot=J.useMemo(()=>({transport:p,assistantID:W}),[W,p]),st=h(async(e,t=p)=>{await et.current.clearExclusive({transport:t,assistantID:e})}),ct=h(e=>{et.current.rollbackAllBestEffort(e).catch(()=>void 0)});J.useEffect(()=>{!H&&V?.assistants[0]&&me(V.assistants[0].id)},[me,H,V?.assistants]),J.useEffect(()=>{B.isSuccess&&H&&!U&&me(V?.assistants[0]?.id??null)},[U,me,H,V?.assistants,B.isSuccess]),J.useEffect(()=>{F&&W&&!G&&ae(W)},[F,W,G]),J.useEffect(()=>{$e.current++,Qe(new Map),ct({excludeTransport:p})},[p,D,ct]),J.useEffect(()=>()=>{$e.current++,ct()},[ct]),J.useEffect(()=>{Q.activate(at)},[Q,at]),J.useEffect(()=>()=>{Q.dispose()},[Q]),J.useEffect(()=>{W&&et.current.rollbackAndClearIfBindingMismatch(ot,{assistantID:W,sessionID:G,directory:K,sessionGeneration:U?.sessionGeneration??-1,transport:p,runtimeGeneration:D}).catch(()=>void 0)},[U?.sessionGeneration,W,K,D,G,ot,p]);let lt=h(e=>at.assistantID?Q.enqueue(at,e,async({identity:e,selection:t,signal:n})=>{await Me(e,t,{readSnapshot:()=>te(void 0,e.transportIdentity),ensureSnapshot:e=>re(e),updateAssistant:ne,signal:n,assertAuthoritative:()=>{if(Q.assertAuthoritative(e),r()!==e.transportIdentity||a()!==e.runtimeGeneration)throw new ke}})}):Promise.reject(Error(`assistant_unavailable`))),ut=J.useMemo(()=>ye(Z.data),[Z.data]),dt=h(e=>{if(!U)return;let t=E(ut,U.agent??void 0,e);if(t){let e=b({providerID:U.providerID,modelID:U.modelID,agent:U.agent},t,ut,X.data??[]),n=e.providerID===U.providerID&&e.modelID===U.modelID;lt({...e,agent:e.agent??void 0,variant:n?U.variant??void 0:void 0})}}),$=h(async(e,t)=>{e.sessionID&&await Be.ensureSessionRenderable(e.sessionID,{directory:e.directory,...t?.force?{force:!0}:{}})}),ft=U?.sessionGeneration;J.useEffect(()=>{!F||!W||!G||!K||ft===void 0||$({sessionID:G,directory:K,sessionGeneration:ft},{force:!0})},[F,W,K,$,ft,G]);let pt=h((e,t)=>{if(t.length===0)return;let n=new Set(t);Qe(t=>{let r=t.get(e);if(!r?.some(e=>n.has(e.info.id)))return t;let i=new Map(t),a=r.filter(e=>!n.has(e.info.id));return a.length>0?i.set(e,a):i.delete(e),i})}),mt=h((e,t,n)=>{Qe(r=>{let i=r.get(e);if(!i)return r;let a=Fe(i,t,n);if(a===i)return r;let o=new Map(r);return o.set(e,a),o})}),ht=h(e=>{pt(W,e)}),gt=h(async e=>{if(!G||!K)throw Error(`assistant_unavailable`);O(G,K).some(t=>t?.id===e)&&(await C(G,e,{directory:K,draftKey:q,restorePrimaryInput:!1}),await st(W))}),_t=h(async(e,t)=>{if(!U||U.mode!==`continuous`)return;if(!G||!K)throw Error(`assistant_unavailable`);if(!O(G,K).some(t=>t?.id===e))return;if(t.info.id!==e||t.info.sessionID!==G||t.info.role!==`user`)throw Error(`The selected user message is unavailable`);let n={assistantID:U.id,sessionID:G,directory:K,sessionGeneration:U.sessionGeneration,messageID:e,transport:p,runtimeGeneration:D},i=Re(n),o=await et.current.stageExclusive(i,async()=>{let i=await M(G,e,t,{directory:K,draftKey:q}),o=r()===n.transport&&a()===n.runtimeGeneration,s=o?te(void 0,n.transport)?.assistants.find(e=>e.id===n.assistantID):void 0,c=!!(s&&s.mode===`continuous`&&s.sessionID===n.sessionID&&s.sessionGeneration===n.sessionGeneration&&(s.effectiveWorkspacePath??``)===n.directory);if(o&&c)return{identity:n,rollback:()=>i.rollback()};let l=await i.rollback();return l.status===`failed`||l.status===`skipped`?{identity:n,rollback:()=>i.rollback(),protectOnStale:!0}:null});if(o.kind===`blocked`)throw Error(`assistant_stage_message_edit_prior_blocked`);if(o.kind===`stale_protected`)throw Error(`assistant_stage_message_edit_rollback_failed`)}),vt=J.useMemo(()=>{let e=T(q,()=>S.getState());return{busy:!1,attachments:Te,addAttachment:t=>e.addLocal(t),removeAttachment:t=>e.removeByAttachmentID(t),clearAttachments:()=>e.clearRootAttachments(),restoreAttachments:t=>e.restoreRootAttachments(t),pendingInput:null,consumePendingInput:()=>null,pendingPreset:null,consumePendingPreset:()=>null,consumeSyntheticParts:()=>{let e=S.getState(),t=e.draftAttachmentViews[l(q)]??Ke,n=e.consumeDraftSyntheticParts(q,y);return n?Ue(n,t):null},restoreSyntheticParts:e=>{(async()=>{let t=S.getState(),n=e.map(e=>({partID:e.partID??s(),text:e.text,attachments:[],...e.synthetic===!0?{synthetic:!0}:{}})),r=We(t.getDraft(q)?.syntheticParts??[],n);t.setDraftSyntheticParts(q,r);for(let r=0;r<n.length;r++){let i=n[r].partID;for(let n of e[r]?.attachments??[])n.source===`server`&&n.dataUrl?t.addDraftDurableAttachment(q,{attachmentID:n.id,filename:n.filename,mimeType:n.mimeType,size:n.size,source:`server`,url:n.dataUrl,serverPath:n.serverPath,partID:i}):await t.addDraftLocalAttachment(q,n.file,{attachmentID:n.id,filename:n.filename,source:n.source===`vscode`?`vscode`:`local`,vscodePath:n.vscodePath,vscodeSource:n.vscodeSource===`selection`?`selection`:void 0,partID:i})}})()},inlineDrafts:[],removeInlineDraft:()=>{},restoreInlineDrafts:()=>{},history:ze,captureRuntime:()=>S.getState().captureDraftRuntime(),getDraft:e=>S.getState().getDraft(e),abortPrompt:{sessionID:null,clear:()=>{}}}},[Te,q,ze]),yt=J.useMemo(()=>{let e=(X.data??[]).find(e=>e.id===U?.providerID)?.models?.find(e=>e.id===U?.modelID);return ve(e)},[U?.modelID,U?.providerID,X.data]),bt=Pe.length>0,xt=J.useMemo(()=>{if(!U||!G||!K)return null;let e={sessionID:G,directory:K,sessionGeneration:U.sessionGeneration};return{kind:`secondary`,surfaceID:`assistant:${U.id}`,active:F,sessionID:G,directory:K,draftKey:q,transportIdentity:p,runtimeGeneration:D,deliveryTarget:{kind:`assistant`,assistantID:U.id},resources:vt,...U.mode===`stateless`?{queueSessionID:`assistant:${U.id}`}:{},selection:{value:{providerID:U.providerID,modelID:U.modelID,agent:U.agent??void 0,variant:U.variant??void 0},catalog:{providers:X.data??[],agents:ut,variants:yt,variantsReady:X.isSuccess,ready:X.isSuccess&&Z.isSuccess,loading:X.isPending||Z.isPending,error:X.isError||Z.isError},change:lt,flush:()=>Q.flush(at)},activity:{phase:Le?.type===`busy`?`busy`:Le?.type===`retry`?`retry`:`idle`,canAbort:Le?.type===`busy`||Le?.type===`retry`},commands:{sessionID:G,hasMessages:bt,hasNewDraft:!1},commandPolicy:e=>e.name!==`fork`&&e.name!==`thread`,backend:{send:async t=>{let n;for(let t of O(e.sessionID,e.directory)){let e=typeof t?.id==`string`?t.id:``;/^msg_[0-9a-f]{12}[0-9A-Za-z]{14}$/.test(e)&&(!n||e>n)&&(n=e)}let r=c(`msg`,n);t.options?.commitStagedMessageEdit&&et.current.clear({transport:p,assistantID:U.id});let i=N({messageID:r,sessionID:e.sessionID,providerID:t.providerID??U.providerID,modelID:t.modelID??U.modelID,agent:t.agent??U.agent??void 0,text:t.text,attachments:t.attachments,additionalParts:t.parts});Qe(e=>{let t=new Map(e);return t.set(U.id,[...e.get(U.id)??[],i]),t});let a;try{a=await oe(U.id,e,r,Ye(t.text,t.parts,t.attachments))}catch(e){throw pt(U.id,[r]),e}if(z.data?.serverInstanceID){let e=_(U.name);v({serverInstanceID:z.data.serverInstanceID,assistantID:U.id,name:e.displayName||U.name,avatarSeed:U.id,...e.avatarEmoji?{avatarEmoji:e.avatarEmoji}:{}}).catch(()=>void 0)}a.binding.sessionID&&mt(U.id,r,a.binding.sessionID);let o=$e.current;Ie({binding:a.binding,refresh:t=>$(t,{force:t.sessionID!==e.sessionID||t.sessionGeneration!==e.sessionGeneration}),isCurrent:()=>$e.current===o})},sendQueued:async()=>{throw Error(`assistant-server-queue-required`)},create:async()=>{let e=await ee(U.id);await st(U.id),await $(e,{force:!0})},compact:async()=>{let t=await se(U.id,e);await st(U.id),await $(t.binding,{force:!0})},abort:async()=>{await ie(U.id,e)}},shortcuts:{cycle:dt,new:async()=>{let e=await ee(U.id);await st(U.id),await $(e,{force:!0})},abort:async()=>{await ie(U.id,e)},submit:()=>{}}}},[F,U,z.data?.serverInstanceID,lt,st,dt,K,q,bt,X.data,X.isError,X.isPending,X.isSuccess,Z.isError,Z.isPending,Z.isSuccess,$,mt,pt,vt,D,Q,at,G,Le,p,yt,ut]),St=h(()=>{if(he(),f){f.openSettings();return}let e=i.getState();e.setSettingsPage(`assistants`),e.setSettingsDialogOpen(!0)}),Ct=h(e=>{ue(e,f?{openMobileSettings:f.openSettings}:void 0)}),[wt,Tt]=J.useState(null),Et=h(e=>{Tt(e)}),Dt=h(e=>{e||Tt(null)}),Ot=h(()=>{i.getState().setActiveMainTab(`chat`)}),kt=h(()=>{if(t){t();return}Ot()}),At=(e,t,n,r)=>(0,Y.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col`,children:[R?(0,Y.jsx)(Xe,{assistant:U,onBack:kt}):null,(0,Y.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col items-center justify-center px-6 text-center`,children:[(0,Y.jsx)(pe,{name:e,className:`size-6 text-muted-foreground`}),(0,Y.jsx)(`h1`,{className:`mt-4 typography-ui-header font-semibold`,children:t}),n?(0,Y.jsx)(`p`,{className:`mt-2 max-w-md typography-ui text-muted-foreground`,children:n}):null,r?(0,Y.jsx)(`div`,{className:`mt-5`,children:r}):null]})]});if(z.isPending||B.isPending)return At(`ai-agent`,u(`assistants.state.unavailable`));if(z.isError||!z.data?.supported||!z.data.enabled||!V?.enabled)return At(`cloud-off`,u(`assistants.state.unavailable`));if(!V.assistants.length)return At(`ai-agent`,u(`assistants.onboarding.title`),u(`assistants.onboarding.description`),(0,Y.jsx)(ge,{onClick:St,children:u(`assistants.onboarding.action`)}));if(!U)return At(`ai-agent`,u(`assistants.state.unavailable`));if(!xt)return(0,Y.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col bg-background`,children:[R?(0,Y.jsx)(Xe,{assistant:U,onBack:kt}):null,(0,Y.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col items-center justify-center gap-3 px-6`,"aria-busy":`true`,"aria-label":u(`assistants.state.unavailable`),children:[(0,Y.jsx)(`div`,{className:`size-10 animate-pulse rounded-xl bg-[var(--surface-muted)] motion-reduce:animate-none`}),(0,Y.jsx)(`div`,{className:`h-3.5 w-36 animate-pulse rounded-md bg-[var(--surface-muted)] motion-reduce:animate-none`})]})]});let jt=_(U.name),Mt=U.enabled?B.isError?u(`assistants.state.staleSnapshot`):null:u(`assistants.state.assistantDisabled`);return(0,Y.jsxs)(`div`,{className:`relative flex h-full min-h-0 overflow-hidden bg-background`,"data-presentation":`workspace`,children:[R?null:(0,Y.jsxs)(`section`,{className:`flex h-full min-h-0 w-[clamp(16rem,22vw,20rem)] shrink-0 flex-col overflow-hidden`,children:[(0,Y.jsx)(`header`,{className:`shrink-0 px-4 pb-3 pt-4 sm:px-5`,children:(0,Y.jsx)(`h1`,{className:`truncate typography-ui-label font-semibold text-foreground`,children:u(`assistants.title`)})}),(0,Y.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-3 pb-4 sm:px-4`,role:`listbox`,"aria-label":u(`assistants.listAria`),children:(0,Y.jsx)(`div`,{className:`flex flex-col gap-1 border-t border-border/40 pt-3`,children:V.assistants.map(e=>{let t=e.id===H,n=_(e.name);return(0,Y.jsx)(Ze,{assistantID:e.id,displayName:n.displayName,avatarEmoji:n.avatarEmoji??void 0,modeLabel:e.mode===`stateless`?u(`assistants.mode.stateless`):u(`assistants.mode.continuous`),selected:t,enabled:e.enabled,editLabel:u(`assistants.menu.edit`),deleteLabel:u(`assistants.settings.delete`),onSelect:()=>me(e.id),onEdit:()=>Ct(e.id),onDelete:()=>Et(e)},e.id)})})})]}),(0,Y.jsx)(Ne,{assistant:wt,open:wt!==null,onOpenChange:Dt}),(0,Y.jsxs)(`div`,{className:fe(`flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden bg-background`,!R&&`border-l border-border/60`),children:[R?(0,Y.jsx)(Xe,{assistant:U,onBack:kt}):(0,Y.jsxs)(`header`,{className:`flex h-14 shrink-0 items-center gap-3 border-b border-border/40 px-4 sm:px-5`,children:[(0,Y.jsx)(de,{name:U.id,emoji:jt.avatarEmoji,size:24,label:jt.displayName||U.name}),(0,Y.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,Y.jsx)(`div`,{className:`truncate typography-ui-label font-medium`,children:jt.displayName}),(0,Y.jsx)(`div`,{className:`mt-0.5 truncate typography-micro leading-none text-muted-foreground/70`,children:U.mode===`stateless`?u(`assistants.conversation.statelessHint`):u(`assistants.conversation.continuousHint`)})]})]}),(0,Y.jsx)(Oe,{onRevertMessage:gt,onEditMessage:U.mode===`continuous`?_t:void 0,assistant:U,sessionID:G,warning:Mt,surface:xt,pendingUserMessages:tt,onPendingUserMessagesMaterialized:ht})]})]})};export{Ge as n,Ne as r,Qe as t};
|