@burtson-labs/bandit-engine 2.1.7 → 2.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/AdvancedTab-D7SDAQEL.mjs +229 -0
  3. package/dist/AdvancedTab-D7SDAQEL.mjs.map +1 -0
  4. package/dist/CrewSection-N2J3TJGU.mjs +15 -0
  5. package/dist/InstructionsTab-MKOGBQ5L.mjs +195 -0
  6. package/dist/InstructionsTab-MKOGBQ5L.mjs.map +1 -0
  7. package/dist/PersonalizationTab-KPTVJKB3.mjs +179 -0
  8. package/dist/PersonalizationTab-KPTVJKB3.mjs.map +1 -0
  9. package/dist/{ProjectsPane-E5D72PUG.mjs → ProjectsPane-C63C6GW5.mjs} +17 -13
  10. package/dist/ProjectsPane-C63C6GW5.mjs.map +1 -0
  11. package/dist/{SchedulesTab-AKJ6WFZV.mjs → SchedulesTab-TEOM3NWQ.mjs} +13 -11
  12. package/dist/SchedulesTab-TEOM3NWQ.mjs.map +1 -0
  13. package/dist/{aiProviderStore-ANPQVHGD.mjs → aiProviderStore-GH4JZTMW.mjs} +3 -2
  14. package/dist/chat-QAEEYO73.mjs +29 -0
  15. package/dist/chunk-3CDCJJ4S.mjs +64 -0
  16. package/dist/chunk-3CDCJJ4S.mjs.map +1 -0
  17. package/dist/chunk-5JNKGMMN.mjs +5871 -0
  18. package/dist/chunk-5JNKGMMN.mjs.map +1 -0
  19. package/dist/{chunk-KWOUXBSF.mjs → chunk-5LXCZJLJ.mjs} +5 -213
  20. package/dist/chunk-5LXCZJLJ.mjs.map +1 -0
  21. package/dist/{chunk-GX4FVZNA.mjs → chunk-DHXSFFLX.mjs} +4 -26
  22. package/dist/chunk-DHXSFFLX.mjs.map +1 -0
  23. package/dist/chunk-F56OTXXR.mjs +17 -0
  24. package/dist/chunk-F56OTXXR.mjs.map +1 -0
  25. package/dist/{chunk-SQJ4OKWM.mjs → chunk-GN3X7IIZ.mjs} +18 -1734
  26. package/dist/chunk-GN3X7IIZ.mjs.map +1 -0
  27. package/dist/chunk-H2XUGGKV.mjs +168 -0
  28. package/dist/chunk-H2XUGGKV.mjs.map +1 -0
  29. package/dist/{chunk-4NUQYUZH.mjs → chunk-JGJRY4MR.mjs} +7 -569
  30. package/dist/chunk-JGJRY4MR.mjs.map +1 -0
  31. package/dist/chunk-KPT7NNNK.mjs +214 -0
  32. package/dist/chunk-KPT7NNNK.mjs.map +1 -0
  33. package/dist/chunk-LC64VSDS.mjs +541 -0
  34. package/dist/chunk-LC64VSDS.mjs.map +1 -0
  35. package/dist/{chunk-DH5A2HT2.mjs → chunk-LY3O7UWA.mjs} +45 -1
  36. package/dist/chunk-LY3O7UWA.mjs.map +1 -0
  37. package/dist/chunk-MR643IO6.mjs +294 -0
  38. package/dist/chunk-MR643IO6.mjs.map +1 -0
  39. package/dist/{chunk-4NHPLHXU.mjs → chunk-MX37LD3Z.mjs} +5469 -11527
  40. package/dist/chunk-MX37LD3Z.mjs.map +1 -0
  41. package/dist/chunk-MX7Z4RSP.mjs +1203 -0
  42. package/dist/chunk-MX7Z4RSP.mjs.map +1 -0
  43. package/dist/chunk-P42M52OW.mjs +1732 -0
  44. package/dist/chunk-P42M52OW.mjs.map +1 -0
  45. package/dist/{chunk-5URP2E5V.mjs → chunk-UT46TXNG.mjs} +42 -6
  46. package/dist/chunk-UT46TXNG.mjs.map +1 -0
  47. package/dist/{chunk-2HFSBPOE.mjs → chunk-WDFQG3RM.mjs} +21 -1
  48. package/dist/chunk-WDFQG3RM.mjs.map +1 -0
  49. package/dist/chunk-XWUHUDAV.mjs +814 -0
  50. package/dist/chunk-XWUHUDAV.mjs.map +1 -0
  51. package/dist/chunk-Y272M3D5.mjs +28 -0
  52. package/dist/chunk-Y272M3D5.mjs.map +1 -0
  53. package/dist/chunk-YY7BX2HM.mjs +566 -0
  54. package/dist/chunk-YY7BX2HM.mjs.map +1 -0
  55. package/dist/crew-delegate-card-I4SSZU5H.mjs +229 -0
  56. package/dist/crew-delegate-card-I4SSZU5H.mjs.map +1 -0
  57. package/dist/crew-mention-picker-OSJ2NHUB.mjs +118 -0
  58. package/dist/crew-mention-picker-OSJ2NHUB.mjs.map +1 -0
  59. package/dist/crew-task-card-ZCXFTR34.mjs +416 -0
  60. package/dist/crew-task-card-ZCXFTR34.mjs.map +1 -0
  61. package/dist/index.d.mts +121 -8
  62. package/dist/index.d.ts +121 -8
  63. package/dist/index.js +11313 -8127
  64. package/dist/index.js.map +1 -1
  65. package/dist/index.mjs +1222 -2217
  66. package/dist/index.mjs.map +1 -1
  67. package/dist/{modelStore-YNANSWCN.mjs → modelStore-KO45QAO2.mjs} +3 -2
  68. package/dist/modelStore-KO45QAO2.mjs.map +1 -0
  69. package/dist/{public-Tq2Pmw9m.d.mts → public-_W_Zew3C.d.mts} +14 -0
  70. package/dist/{public-Tq2Pmw9m.d.ts → public-_W_Zew3C.d.ts} +14 -0
  71. package/dist/public-types.d.mts +1 -1
  72. package/dist/public-types.d.ts +1 -1
  73. package/dist/{schedule-confirm-card-D4K76HEA.mjs → schedule-confirm-card-Y2JF2RBV.mjs} +5 -5
  74. package/package.json +1 -1
  75. package/dist/ProjectsPane-E5D72PUG.mjs.map +0 -1
  76. package/dist/SchedulesTab-AKJ6WFZV.mjs.map +0 -1
  77. package/dist/chat-MI4IL3WK.mjs +0 -19
  78. package/dist/chunk-2HFSBPOE.mjs.map +0 -1
  79. package/dist/chunk-4NHPLHXU.mjs.map +0 -1
  80. package/dist/chunk-4NUQYUZH.mjs.map +0 -1
  81. package/dist/chunk-5URP2E5V.mjs.map +0 -1
  82. package/dist/chunk-DH5A2HT2.mjs.map +0 -1
  83. package/dist/chunk-GX4FVZNA.mjs.map +0 -1
  84. package/dist/chunk-KWOUXBSF.mjs.map +0 -1
  85. package/dist/chunk-SQJ4OKWM.mjs.map +0 -1
  86. /package/dist/{aiProviderStore-ANPQVHGD.mjs.map → CrewSection-N2J3TJGU.mjs.map} +0 -0
  87. /package/dist/{chat-MI4IL3WK.mjs.map → aiProviderStore-GH4JZTMW.mjs.map} +0 -0
  88. /package/dist/{modelStore-YNANSWCN.mjs.map → chat-QAEEYO73.mjs.map} +0 -0
  89. /package/dist/{schedule-confirm-card-D4K76HEA.mjs.map → schedule-confirm-card-Y2JF2RBV.mjs.map} +0 -0
@@ -0,0 +1,1732 @@
1
+ import {
2
+ isNativeShell,
3
+ isStandalonePwa
4
+ } from "./chunk-F56OTXXR.mjs";
5
+ import {
6
+ PROJECT_COLORS,
7
+ useConversationStore,
8
+ useFeatureVisibility,
9
+ useProjectStore
10
+ } from "./chunk-GN3X7IIZ.mjs";
11
+ import {
12
+ usePreferencesStore
13
+ } from "./chunk-5LXCZJLJ.mjs";
14
+ import {
15
+ indexedDBService_default
16
+ } from "./chunk-KPT7NNNK.mjs";
17
+ import {
18
+ usePackageSettingsStore
19
+ } from "./chunk-K7SQWDNF.mjs";
20
+ import {
21
+ authenticationService,
22
+ readPersistedToken,
23
+ useAuthenticationStore
24
+ } from "./chunk-S3DWWUBD.mjs";
25
+ import {
26
+ debugLogger
27
+ } from "./chunk-NI7BKLC7.mjs";
28
+ import {
29
+ Check,
30
+ Edit,
31
+ Folder,
32
+ GripVertical,
33
+ Home,
34
+ Inbox,
35
+ LogOut,
36
+ MailOpen,
37
+ MessageSquarePlus,
38
+ MoreVertical,
39
+ Plus,
40
+ Search,
41
+ Settings,
42
+ Trash
43
+ } from "./chunk-UT46TXNG.mjs";
44
+
45
+ // src/chat/sidebar/sidebarState.ts
46
+ import { create } from "zustand";
47
+ var SIDEBAR_WIDTH = 300;
48
+ var SIDEBAR_COLLAPSED_KEY = "bandit.sidebar.collapsed";
49
+ var SIDEBAR_DEFAULT_OPEN_MIN_WIDTH = 1024;
50
+ var CHAT_VIEW = { kind: "chat" };
51
+ var readPersistedCollapsed = () => {
52
+ try {
53
+ const raw = localStorage.getItem(SIDEBAR_COLLAPSED_KEY);
54
+ return raw === null ? null : raw === "1";
55
+ } catch {
56
+ return null;
57
+ }
58
+ };
59
+ var writePersistedCollapsed = (collapsed) => {
60
+ try {
61
+ localStorage.setItem(SIDEBAR_COLLAPSED_KEY, collapsed ? "1" : "0");
62
+ } catch {
63
+ }
64
+ };
65
+ var initialSidebarOpen = (viewportWidth = typeof window === "undefined" ? 0 : window.innerWidth) => {
66
+ const persisted = readPersistedCollapsed();
67
+ if (persisted !== null) return !persisted;
68
+ return viewportWidth >= SIDEBAR_DEFAULT_OPEN_MIN_WIDTH;
69
+ };
70
+ function viewFromSearch(search) {
71
+ const params = new URLSearchParams(search);
72
+ const projectId = params.get("project");
73
+ if (projectId) return { kind: "project", projectId };
74
+ if (params.get("view") === "projects") return { kind: "projects" };
75
+ return CHAT_VIEW;
76
+ }
77
+ function searchWithView(search, view) {
78
+ const params = new URLSearchParams(search);
79
+ params.delete("view");
80
+ params.delete("project");
81
+ if (view.kind === "projects") params.set("view", "projects");
82
+ if (view.kind === "project") params.set("project", view.projectId);
83
+ const next = params.toString();
84
+ return next ? `?${next}` : "";
85
+ }
86
+ var sameView = (a, b) => a.kind === b.kind && (a.kind !== "project" || b.kind !== "project" || a.projectId === b.projectId);
87
+ var useSidebarStore = create((set) => ({
88
+ view: CHAT_VIEW,
89
+ searchFocusRequest: 0,
90
+ setView: (view) => set({ view }),
91
+ showChat: () => set({ view: CHAT_VIEW }),
92
+ showProjects: () => set({ view: { kind: "projects" } }),
93
+ openProject: (projectId) => set({ view: { kind: "project", projectId } }),
94
+ requestSearchFocus: () => set((state) => ({ searchFocusRequest: state.searchFocusRequest + 1 }))
95
+ }));
96
+ function syncViewWithUrl() {
97
+ if (typeof window === "undefined") return () => {
98
+ };
99
+ const store = useSidebarStore;
100
+ store.getState().setView(viewFromSearch(window.location.search));
101
+ const onPop = () => store.getState().setView(viewFromSearch(window.location.search));
102
+ window.addEventListener("popstate", onPop);
103
+ const unsubscribe = store.subscribe((state, previous) => {
104
+ if (sameView(state.view, previous.view)) return;
105
+ const current = viewFromSearch(window.location.search);
106
+ if (sameView(current, state.view)) return;
107
+ const search = searchWithView(window.location.search, state.view);
108
+ const url = `${window.location.pathname}${search}${window.location.hash}`;
109
+ window.history.pushState(window.history.state, "", url);
110
+ });
111
+ return () => {
112
+ window.removeEventListener("popstate", onPop);
113
+ unsubscribe();
114
+ };
115
+ }
116
+ var useSidebarLayout = () => usePackageSettingsStore((state) => state.settings?.navigation?.sidebar ?? "classic");
117
+ var useSectionsLayout = () => useSidebarLayout() === "sections";
118
+
119
+ // src/services/branding/brandingService.ts
120
+ var BrandingService = class {
121
+ DB_NAME = "banditConfig";
122
+ DB_VERSION = 1;
123
+ STORE_NAME = "config";
124
+ STORE_CONFIGS = [{ name: "config", keyPath: "id" }];
125
+ async getBranding() {
126
+ try {
127
+ const data = await indexedDBService_default.get(
128
+ this.DB_NAME,
129
+ this.DB_VERSION,
130
+ this.STORE_NAME,
131
+ "main",
132
+ this.STORE_CONFIGS
133
+ );
134
+ if (data?.branding && (data.branding.logoBase64 || data.branding.hasTransparentLogo !== void 0 || data.branding.brandingText)) {
135
+ return {
136
+ logoBase64: data.branding.logoBase64,
137
+ hasTransparentLogo: data.branding.hasTransparentLogo,
138
+ brandingText: data.branding.brandingText
139
+ };
140
+ }
141
+ return null;
142
+ } catch (error) {
143
+ throw error;
144
+ }
145
+ }
146
+ async setBrandingFromConfig(config) {
147
+ try {
148
+ const existing = await indexedDBService_default.get(
149
+ this.DB_NAME,
150
+ this.DB_VERSION,
151
+ this.STORE_NAME,
152
+ "main",
153
+ this.STORE_CONFIGS
154
+ ) || { id: "main" };
155
+ if (existing.branding?.userSaved) {
156
+ debugLogger.debug(
157
+ "\u{1F6E1}\uFE0F BrandingService: User branding detected, blocking CDN config override"
158
+ );
159
+ return;
160
+ }
161
+ const hasUserBranding = existing.branding && (existing.branding.logoBase64 || existing.branding.brandingText || existing.branding.theme || existing.branding.hasTransparentLogo !== void 0);
162
+ if (hasUserBranding) {
163
+ debugLogger.debug(
164
+ "\u{1F6E1}\uFE0F BrandingService: Detected user branding data, blocking CDN config override"
165
+ );
166
+ return;
167
+ }
168
+ debugLogger.debug(
169
+ "\u{1F527} BrandingService: No user branding detected, applying CDN config"
170
+ );
171
+ const branding = config.branding || {};
172
+ const updated = {
173
+ ...existing,
174
+ branding: {
175
+ ...existing.branding,
176
+ ...branding
177
+ }
178
+ };
179
+ await indexedDBService_default.put(
180
+ this.DB_NAME,
181
+ this.DB_VERSION,
182
+ this.STORE_NAME,
183
+ updated,
184
+ this.STORE_CONFIGS
185
+ );
186
+ } catch (error) {
187
+ throw error;
188
+ }
189
+ }
190
+ };
191
+ var brandingService = new BrandingService();
192
+ var brandingService_default = brandingService;
193
+
194
+ // src/hooks/useSafeNavigate.ts
195
+ import { useRef } from "react";
196
+ import { useNavigate } from "react-router-dom";
197
+ var useSafeNavigate = () => {
198
+ const warned = useRef(false);
199
+ let navigate = null;
200
+ try {
201
+ navigate = useNavigate();
202
+ } catch (error) {
203
+ if (!warned.current) {
204
+ debugLogger.warn("useSafeNavigate: no Router context; falling back to location", {
205
+ error
206
+ });
207
+ warned.current = true;
208
+ }
209
+ navigate = null;
210
+ }
211
+ return (to) => {
212
+ if (typeof window !== "undefined" && /^[a-z]+:\/\//i.test(to)) {
213
+ window.location.href = to;
214
+ return;
215
+ }
216
+ if (navigate) {
217
+ navigate(to);
218
+ return;
219
+ }
220
+ if (typeof window !== "undefined") {
221
+ window.location.href = to;
222
+ }
223
+ };
224
+ };
225
+
226
+ // src/chat/move-conversation-modal.tsx
227
+ import { useState, useEffect } from "react";
228
+ import {
229
+ Dialog,
230
+ DialogTitle,
231
+ DialogContent,
232
+ DialogActions,
233
+ Button,
234
+ List,
235
+ ListItem,
236
+ ListItemButton,
237
+ ListItemText,
238
+ ListItemIcon,
239
+ Typography,
240
+ Avatar,
241
+ Radio,
242
+ Box,
243
+ Divider
244
+ } from "@mui/material";
245
+ import { useTheme } from "@mui/material/styles";
246
+ import { jsx, jsxs } from "react/jsx-runtime";
247
+ var MoveConversationModal = ({
248
+ open,
249
+ onClose,
250
+ conversations,
251
+ currentProjectId = null
252
+ }) => {
253
+ const theme = useTheme();
254
+ const { projects, _hasHydrated, hydrate } = useProjectStore();
255
+ const { moveConversationToProject } = useConversationStore();
256
+ const [selectedProjectId, setSelectedProjectId] = useState(
257
+ currentProjectId
258
+ );
259
+ useEffect(() => {
260
+ if (open && !_hasHydrated) {
261
+ hydrate();
262
+ }
263
+ }, [open, _hasHydrated, hydrate]);
264
+ useEffect(() => {
265
+ setSelectedProjectId(currentProjectId);
266
+ }, [currentProjectId, open]);
267
+ const handleMove = async () => {
268
+ try {
269
+ await Promise.all(
270
+ conversations.map(
271
+ (conv) => moveConversationToProject(conv.id, selectedProjectId)
272
+ )
273
+ );
274
+ onClose();
275
+ } catch (error) {
276
+ debugLogger.error("Failed to move conversations", {
277
+ error: error instanceof Error ? error.message : String(error)
278
+ });
279
+ }
280
+ };
281
+ const conversationCount = conversations.length;
282
+ const isMultiple = conversationCount > 1;
283
+ return /* @__PURE__ */ jsxs(
284
+ Dialog,
285
+ {
286
+ open,
287
+ onClose,
288
+ maxWidth: "sm",
289
+ fullWidth: true,
290
+ PaperProps: {
291
+ sx: {
292
+ bgcolor: theme.palette.background.paper,
293
+ backgroundImage: "none"
294
+ }
295
+ },
296
+ children: [
297
+ /* @__PURE__ */ jsxs(DialogTitle, { children: [
298
+ "Move ",
299
+ isMultiple ? `${conversationCount} Conversations` : "Conversation"
300
+ ] }),
301
+ /* @__PURE__ */ jsxs(DialogContent, { sx: { px: 3 }, children: [
302
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: isMultiple ? `Select a project to move ${conversationCount} conversations to:` : `Select a project to move "${conversations[0]?.name}" to:` }),
303
+ /* @__PURE__ */ jsxs(List, { children: [
304
+ /* @__PURE__ */ jsx(ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxs(
305
+ ListItemButton,
306
+ {
307
+ onClick: () => setSelectedProjectId(null),
308
+ selected: selectedProjectId === null,
309
+ children: [
310
+ /* @__PURE__ */ jsx(ListItemIcon, { children: /* @__PURE__ */ jsx(
311
+ Radio,
312
+ {
313
+ checked: selectedProjectId === null,
314
+ onChange: () => setSelectedProjectId(null),
315
+ size: "small"
316
+ }
317
+ ) }),
318
+ /* @__PURE__ */ jsx(ListItemIcon, { children: /* @__PURE__ */ jsx(
319
+ Avatar,
320
+ {
321
+ sx: {
322
+ bgcolor: theme.palette.grey[400],
323
+ width: 32,
324
+ height: 32
325
+ },
326
+ children: /* @__PURE__ */ jsx(Inbox, {})
327
+ }
328
+ ) }),
329
+ /* @__PURE__ */ jsx(
330
+ ListItemText,
331
+ {
332
+ primary: "No Project",
333
+ secondary: "Keep conversations ungrouped"
334
+ }
335
+ )
336
+ ]
337
+ }
338
+ ) }),
339
+ /* @__PURE__ */ jsx(Divider, { sx: { my: 1 } }),
340
+ projects.map((project) => /* @__PURE__ */ jsx(ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxs(
341
+ ListItemButton,
342
+ {
343
+ onClick: () => setSelectedProjectId(project.id),
344
+ selected: selectedProjectId === project.id,
345
+ children: [
346
+ /* @__PURE__ */ jsx(ListItemIcon, { children: /* @__PURE__ */ jsx(
347
+ Radio,
348
+ {
349
+ checked: selectedProjectId === project.id,
350
+ onChange: () => setSelectedProjectId(project.id),
351
+ size: "small"
352
+ }
353
+ ) }),
354
+ /* @__PURE__ */ jsx(ListItemIcon, { children: /* @__PURE__ */ jsx(
355
+ Avatar,
356
+ {
357
+ sx: {
358
+ bgcolor: project.color,
359
+ width: 32,
360
+ height: 32
361
+ },
362
+ children: /* @__PURE__ */ jsx(Folder, {})
363
+ }
364
+ ) }),
365
+ /* @__PURE__ */ jsx(ListItemText, { primary: project.name, secondary: project.description })
366
+ ]
367
+ }
368
+ ) }, project.id)),
369
+ projects.length === 0 && /* @__PURE__ */ jsx(
370
+ Box,
371
+ {
372
+ sx: {
373
+ textAlign: "center",
374
+ py: 2,
375
+ color: theme.palette.text.secondary
376
+ },
377
+ children: /* @__PURE__ */ jsx(Typography, { variant: "body2", children: "No projects available. Create a project first to organize conversations." })
378
+ }
379
+ )
380
+ ] })
381
+ ] }),
382
+ /* @__PURE__ */ jsxs(DialogActions, { sx: { px: 3, pb: 2 }, children: [
383
+ /* @__PURE__ */ jsx(Button, { onClick: onClose, children: "Cancel" }),
384
+ /* @__PURE__ */ jsxs(
385
+ Button,
386
+ {
387
+ onClick: handleMove,
388
+ variant: "contained",
389
+ disabled: selectedProjectId === currentProjectId,
390
+ children: [
391
+ "Move ",
392
+ isMultiple ? "Conversations" : "Conversation"
393
+ ]
394
+ }
395
+ )
396
+ ] })
397
+ ]
398
+ }
399
+ );
400
+ };
401
+ var move_conversation_modal_default = MoveConversationModal;
402
+
403
+ // src/chat/simple-conversation-item.tsx
404
+ import { useState as useState2, useRef as useRef2, useEffect as useEffect2 } from "react";
405
+ import {
406
+ Box as Box2,
407
+ Typography as Typography2,
408
+ IconButton,
409
+ Menu,
410
+ MenuItem,
411
+ ListItemIcon as ListItemIcon2,
412
+ ListItemText as ListItemText2,
413
+ useMediaQuery,
414
+ TextField,
415
+ Dialog as Dialog2,
416
+ DialogTitle as DialogTitle2,
417
+ DialogContent as DialogContent2,
418
+ DialogActions as DialogActions2,
419
+ Button as Button2
420
+ } from "@mui/material";
421
+ import { useTheme as useTheme2, alpha } from "@mui/material/styles";
422
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
423
+ var SimpleConversationItem = ({
424
+ conversation,
425
+ isSelected,
426
+ onSelect,
427
+ onDelete,
428
+ onRename,
429
+ onMove,
430
+ projectColor,
431
+ snippet,
432
+ searchQuery,
433
+ onTouchDragStart,
434
+ onTouchDragMove,
435
+ onTouchDragEnd,
436
+ isTouchDragActive,
437
+ dense = false
438
+ }) => {
439
+ const theme = useTheme2();
440
+ const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
441
+ const [anchorEl, setAnchorEl] = useState2(null);
442
+ const [isEditing, setIsEditing] = useState2(false);
443
+ const [editName, setEditName] = useState2(conversation.name);
444
+ const [isDragging, setIsDragging] = useState2(false);
445
+ const [isTouchDragging, setIsTouchDragging] = useState2(false);
446
+ const [showRenameDialog, setShowRenameDialog] = useState2(false);
447
+ const longPressTimeoutRef = useRef2(null);
448
+ const touchStartPointRef = useRef2(null);
449
+ const activeTouchIdRef = useRef2(null);
450
+ const suppressClickRef = useRef2(false);
451
+ const highlightText = (text, query) => {
452
+ if (!query || !query.trim()) {
453
+ return text;
454
+ }
455
+ const regex = new RegExp(`(${query.trim()})`, "gi");
456
+ const parts = text.split(regex);
457
+ return parts.map(
458
+ (part, index) => regex.test(part) ? /* @__PURE__ */ jsx2(
459
+ Box2,
460
+ {
461
+ component: "span",
462
+ sx: {
463
+ bgcolor: alpha(theme.palette.warning.main, 0.3),
464
+ color: theme.palette.text.primary,
465
+ fontWeight: 600,
466
+ borderRadius: 0.5,
467
+ px: 0.25
468
+ },
469
+ children: part
470
+ },
471
+ index
472
+ ) : part
473
+ );
474
+ };
475
+ const handleMenuOpen = (event) => {
476
+ event.stopPropagation();
477
+ event.preventDefault();
478
+ setAnchorEl(event.currentTarget);
479
+ };
480
+ const handleMenuClose = () => {
481
+ setAnchorEl(null);
482
+ };
483
+ const handleEdit = () => {
484
+ setEditName(conversation.name);
485
+ if (isMobile) {
486
+ setShowRenameDialog(true);
487
+ } else {
488
+ setIsEditing(true);
489
+ }
490
+ handleMenuClose();
491
+ };
492
+ const handleMove = () => {
493
+ if (onMove) {
494
+ onMove();
495
+ }
496
+ handleMenuClose();
497
+ };
498
+ const handleDelete = () => {
499
+ onDelete();
500
+ handleMenuClose();
501
+ };
502
+ const commitRename = () => {
503
+ const trimmed = editName.trim();
504
+ if (!trimmed) {
505
+ return;
506
+ }
507
+ if (trimmed !== conversation.name) {
508
+ onRename?.(trimmed);
509
+ }
510
+ setEditName(trimmed);
511
+ };
512
+ const handleSaveEdit = () => {
513
+ commitRename();
514
+ setIsEditing(false);
515
+ };
516
+ const handleCancelEdit = () => {
517
+ setIsEditing(false);
518
+ setEditName(conversation.name);
519
+ };
520
+ const handleDragStart = (e) => {
521
+ setIsDragging(true);
522
+ e.dataTransfer.setData("text/plain", conversation.id);
523
+ e.dataTransfer.effectAllowed = "move";
524
+ };
525
+ const handleDragEnd = () => {
526
+ setIsDragging(false);
527
+ };
528
+ const cancelLongPress = () => {
529
+ if (longPressTimeoutRef.current !== null) {
530
+ window.clearTimeout(longPressTimeoutRef.current);
531
+ longPressTimeoutRef.current = null;
532
+ }
533
+ };
534
+ const handleTouchStart = (e) => {
535
+ if (!isMobile || isEditing) return;
536
+ if (e.touches.length === 0) return;
537
+ const touch = e.touches[0];
538
+ touchStartPointRef.current = { x: touch.clientX, y: touch.clientY };
539
+ activeTouchIdRef.current = touch.identifier;
540
+ suppressClickRef.current = false;
541
+ cancelLongPress();
542
+ const initialTouch = touch;
543
+ longPressTimeoutRef.current = window.setTimeout(() => {
544
+ if (activeTouchIdRef.current !== null) {
545
+ setIsTouchDragging(true);
546
+ onTouchDragStart?.(conversation, initialTouch);
547
+ }
548
+ }, 350);
549
+ };
550
+ const handleTouchMove = (e) => {
551
+ if (!isMobile) return;
552
+ const targetTouch = activeTouchIdRef.current !== null ? Array.from(e.touches).find((t) => t.identifier === activeTouchIdRef.current) : e.touches[0];
553
+ if (!targetTouch) return;
554
+ if (isTouchDragging) {
555
+ if (e.cancelable) {
556
+ e.preventDefault();
557
+ }
558
+ onTouchDragMove?.(targetTouch);
559
+ return;
560
+ }
561
+ const startPoint = touchStartPointRef.current;
562
+ if (startPoint) {
563
+ const deltaX = Math.abs(targetTouch.clientX - startPoint.x);
564
+ const deltaY = Math.abs(targetTouch.clientY - startPoint.y);
565
+ if (deltaX > 8 || deltaY > 8) {
566
+ cancelLongPress();
567
+ }
568
+ }
569
+ };
570
+ const finalizeTouchDrag = (touch) => {
571
+ if (isTouchDragging) {
572
+ onTouchDragEnd?.(touch);
573
+ suppressClickRef.current = true;
574
+ }
575
+ setIsTouchDragging(false);
576
+ activeTouchIdRef.current = null;
577
+ touchStartPointRef.current = null;
578
+ cancelLongPress();
579
+ };
580
+ const handleTouchEnd = (e) => {
581
+ if (!isMobile) return;
582
+ const touch = activeTouchIdRef.current !== null ? Array.from(e.changedTouches).find(
583
+ (t) => t.identifier === activeTouchIdRef.current
584
+ ) : e.changedTouches[0];
585
+ finalizeTouchDrag(touch);
586
+ };
587
+ const handleTouchCancel = () => {
588
+ if (!isMobile) return;
589
+ finalizeTouchDrag();
590
+ };
591
+ useEffect2(() => {
592
+ if (!isTouchDragActive && isTouchDragging) {
593
+ setIsTouchDragging(false);
594
+ }
595
+ }, [isTouchDragActive, isTouchDragging]);
596
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
597
+ /* @__PURE__ */ jsxs2(
598
+ Box2,
599
+ {
600
+ "data-project-id": conversation.projectId ?? "__ungrouped",
601
+ draggable: !isMobile && !isEditing,
602
+ onDragStart: handleDragStart,
603
+ onDragEnd: handleDragEnd,
604
+ onTouchStart: handleTouchStart,
605
+ onTouchMove: handleTouchMove,
606
+ onTouchEnd: handleTouchEnd,
607
+ onTouchCancel: handleTouchCancel,
608
+ onClick: isEditing || isTouchDragging ? void 0 : (event) => {
609
+ if (suppressClickRef.current) {
610
+ suppressClickRef.current = false;
611
+ event.preventDefault();
612
+ event.stopPropagation();
613
+ return;
614
+ }
615
+ onSelect();
616
+ },
617
+ sx: {
618
+ display: "flex",
619
+ alignItems: "center",
620
+ px: 2,
621
+ py: dense ? 0.5 : 1.5,
622
+ mx: 1,
623
+ borderRadius: 1,
624
+ cursor: isEditing || isTouchDragging ? "default" : "pointer",
625
+ bgcolor: isSelected ? alpha(projectColor || theme.palette.primary.main, 0.15) : "transparent",
626
+ border: isSelected ? `1px solid ${alpha(projectColor || theme.palette.primary.main, 0.3)}` : "1px solid transparent",
627
+ opacity: isDragging || isTouchDragActive ? 0.55 : 1,
628
+ transition: "all 0.2s ease",
629
+ transform: isTouchDragActive ? "scale(0.98)" : "none",
630
+ boxShadow: isTouchDragActive ? `0 12px 24px ${alpha(theme.palette.common.black, 0.25)}` : void 0,
631
+ touchAction: isTouchDragActive ? "none" : void 0,
632
+ userSelect: isTouchDragging || isTouchDragActive ? "none" : void 0,
633
+ WebkitUserSelect: isTouchDragging || isTouchDragActive ? "none" : void 0,
634
+ "&:hover": !isEditing && !isTouchDragging ? {
635
+ bgcolor: alpha(theme.palette.text.primary, 0.04)
636
+ } : {},
637
+ // Better touch handling on mobile
638
+ ...isMobile && {
639
+ minHeight: dense ? 44 : 48,
640
+ // Larger touch target
641
+ userSelect: "none",
642
+ WebkitUserSelect: "none",
643
+ WebkitTouchCallout: "none",
644
+ "&:active": {
645
+ bgcolor: alpha(theme.palette.text.primary, 0.08)
646
+ }
647
+ }
648
+ },
649
+ children: [
650
+ !isMobile && !isEditing && /* @__PURE__ */ jsx2(
651
+ GripVertical,
652
+ {
653
+ size: 16,
654
+ color: theme.palette.text.disabled,
655
+ style: { marginRight: 4, cursor: "grab" }
656
+ }
657
+ ),
658
+ /* @__PURE__ */ jsxs2(Box2, { sx: { flex: 1, minWidth: 0 }, children: [
659
+ isEditing ? /* @__PURE__ */ jsx2(
660
+ TextField,
661
+ {
662
+ value: editName,
663
+ onChange: (e) => setEditName(e.target.value),
664
+ onBlur: handleSaveEdit,
665
+ onKeyDown: (e) => {
666
+ if (e.key === "Enter") {
667
+ handleSaveEdit();
668
+ } else if (e.key === "Escape") {
669
+ handleCancelEdit();
670
+ }
671
+ },
672
+ size: "small",
673
+ variant: "standard",
674
+ autoFocus: true,
675
+ fullWidth: true,
676
+ sx: {
677
+ "& .MuiInput-root": {
678
+ fontSize: "0.875rem"
679
+ }
680
+ }
681
+ }
682
+ ) : /* @__PURE__ */ jsx2(
683
+ Typography2,
684
+ {
685
+ variant: "body2",
686
+ sx: {
687
+ fontWeight: isSelected ? 600 : 400,
688
+ color: isSelected ? projectColor || theme.palette.primary.main : theme.palette.text.primary,
689
+ overflow: "hidden",
690
+ textOverflow: "ellipsis",
691
+ whiteSpace: "nowrap",
692
+ fontSize: "0.875rem"
693
+ },
694
+ children: highlightText(conversation.name, searchQuery)
695
+ }
696
+ ),
697
+ !isEditing && snippet && /* @__PURE__ */ jsx2(
698
+ Typography2,
699
+ {
700
+ variant: "caption",
701
+ sx: {
702
+ display: "-webkit-box",
703
+ WebkitLineClamp: 2,
704
+ WebkitBoxOrient: "vertical",
705
+ overflow: "hidden",
706
+ color: alpha(theme.palette.text.secondary, 0.9),
707
+ mt: 0.25,
708
+ lineHeight: 1.3,
709
+ fontSize: "0.72rem"
710
+ },
711
+ title: snippet,
712
+ children: highlightText(snippet, searchQuery)
713
+ }
714
+ )
715
+ ] }),
716
+ !isEditing && /* @__PURE__ */ jsx2(
717
+ IconButton,
718
+ {
719
+ onClick: handleMenuOpen,
720
+ size: "small",
721
+ sx: {
722
+ opacity: isMobile ? 1 : isSelected ? 1 : 0,
723
+ // Always visible on mobile
724
+ color: theme.palette.text.secondary,
725
+ ml: 1,
726
+ minWidth: 32,
727
+ minHeight: 32,
728
+ transition: "opacity 0.2s ease",
729
+ ".MuiBox-root:hover &": {
730
+ opacity: 1
731
+ },
732
+ // Larger touch target on mobile
733
+ ...isMobile && {
734
+ padding: 1,
735
+ "&:before": {
736
+ content: '""',
737
+ position: "absolute",
738
+ top: -8,
739
+ left: -8,
740
+ right: -8,
741
+ bottom: -8
742
+ }
743
+ }
744
+ },
745
+ children: /* @__PURE__ */ jsx2(MoreVertical, { size: 16 })
746
+ }
747
+ ),
748
+ /* @__PURE__ */ jsxs2(
749
+ Menu,
750
+ {
751
+ anchorEl,
752
+ open: Boolean(anchorEl),
753
+ onClose: handleMenuClose,
754
+ onClick: (e) => e.stopPropagation(),
755
+ transformOrigin: {
756
+ vertical: "top",
757
+ horizontal: "right"
758
+ },
759
+ anchorOrigin: {
760
+ vertical: "top",
761
+ horizontal: "right"
762
+ },
763
+ PaperProps: {
764
+ sx: {
765
+ // Larger menu items on mobile for easier touch
766
+ ...isMobile && {
767
+ "& .MuiMenuItem-root": {
768
+ minHeight: 48,
769
+ fontSize: "1rem"
770
+ }
771
+ }
772
+ }
773
+ },
774
+ children: [
775
+ onRename && /* @__PURE__ */ jsxs2(MenuItem, { onClick: handleEdit, children: [
776
+ /* @__PURE__ */ jsx2(ListItemIcon2, { children: /* @__PURE__ */ jsx2(Edit, { size: 16 }) }),
777
+ /* @__PURE__ */ jsx2(ListItemText2, { children: "Rename" })
778
+ ] }),
779
+ onMove && /* @__PURE__ */ jsxs2(MenuItem, { onClick: handleMove, children: [
780
+ /* @__PURE__ */ jsx2(ListItemIcon2, { children: /* @__PURE__ */ jsx2(MailOpen, { size: 16 }) }),
781
+ /* @__PURE__ */ jsx2(ListItemText2, { children: "Move to Project" })
782
+ ] }),
783
+ /* @__PURE__ */ jsxs2(MenuItem, { onClick: handleDelete, children: [
784
+ /* @__PURE__ */ jsx2(ListItemIcon2, { children: /* @__PURE__ */ jsx2(Trash, { size: 16 }) }),
785
+ /* @__PURE__ */ jsx2(ListItemText2, { children: "Delete" })
786
+ ] })
787
+ ]
788
+ }
789
+ )
790
+ ]
791
+ }
792
+ ),
793
+ isMobile && /* @__PURE__ */ jsxs2(
794
+ Dialog2,
795
+ {
796
+ open: showRenameDialog,
797
+ onClose: () => {
798
+ setShowRenameDialog(false);
799
+ setEditName(conversation.name);
800
+ },
801
+ fullWidth: true,
802
+ PaperProps: {
803
+ sx: {
804
+ borderRadius: 3,
805
+ pb: 1
806
+ }
807
+ },
808
+ children: [
809
+ /* @__PURE__ */ jsx2(DialogTitle2, { sx: { pb: 1 }, children: "Rename Conversation" }),
810
+ /* @__PURE__ */ jsx2(DialogContent2, { children: /* @__PURE__ */ jsx2(
811
+ TextField,
812
+ {
813
+ value: editName,
814
+ onChange: (e) => setEditName(e.target.value),
815
+ autoFocus: true,
816
+ fullWidth: true,
817
+ placeholder: "Enter a new name",
818
+ InputProps: {
819
+ sx: { fontSize: "1rem" }
820
+ }
821
+ }
822
+ ) }),
823
+ /* @__PURE__ */ jsxs2(DialogActions2, { sx: { px: 3, pb: 2 }, children: [
824
+ /* @__PURE__ */ jsx2(
825
+ Button2,
826
+ {
827
+ onClick: () => {
828
+ setShowRenameDialog(false);
829
+ setEditName(conversation.name);
830
+ },
831
+ children: "Cancel"
832
+ }
833
+ ),
834
+ /* @__PURE__ */ jsx2(
835
+ Button2,
836
+ {
837
+ onClick: () => {
838
+ commitRename();
839
+ setShowRenameDialog(false);
840
+ },
841
+ variant: "contained",
842
+ disabled: !editName.trim() || editName.trim() === conversation.name,
843
+ children: "Save"
844
+ }
845
+ )
846
+ ] })
847
+ ]
848
+ }
849
+ )
850
+ ] });
851
+ };
852
+ var simple_conversation_item_default = SimpleConversationItem;
853
+
854
+ // src/chat/sidebar/SidebarUserCard.tsx
855
+ import { Avatar as Avatar2, Box as Box3, IconButton as IconButton2, Tooltip, Typography as Typography3, alpha as alpha2 } from "@mui/material";
856
+ import { useTheme as useTheme3 } from "@mui/material/styles";
857
+
858
+ // src/chat/sidebar/useSidebarUser.ts
859
+ import { useCallback, useEffect as useEffect3, useMemo, useState as useState3 } from "react";
860
+ var BANDIT_AVATAR = "https://cdn.burtson.ai/images/bandit-head.png";
861
+ var optionalString = (value) => {
862
+ if (typeof value !== "string") return void 0;
863
+ const trimmed = value.trim();
864
+ return trimmed.length > 0 ? trimmed : void 0;
865
+ };
866
+ var deriveInitials = (value) => {
867
+ const sanitized = (value || "").trim();
868
+ if (!sanitized) return "B";
869
+ const words = sanitized.split(/\s+/).filter(Boolean);
870
+ if (words.length >= 2) {
871
+ const initials = `${words[0]?.charAt(0) ?? ""}${words[words.length - 1]?.charAt(0) ?? ""}`;
872
+ return (initials.trim() || sanitized.slice(0, 2)).toUpperCase();
873
+ }
874
+ const alphanumeric = sanitized.replace(/[^A-Za-z0-9]/g, "");
875
+ if (alphanumeric.length >= 1) return alphanumeric.slice(0, 2).toUpperCase();
876
+ return sanitized.slice(0, 2).toUpperCase();
877
+ };
878
+ function useSidebarUser() {
879
+ const { user } = useAuthenticationStore();
880
+ const [avatarSrc, setAvatarSrc] = useState3(BANDIT_AVATAR);
881
+ const claim = useCallback(
882
+ (key) => user ? optionalString(user[key]) : void 0,
883
+ [user]
884
+ );
885
+ const displayName = useMemo(() => {
886
+ if (!user) return void 0;
887
+ const candidates = [
888
+ optionalString(user.name),
889
+ optionalString(user.preferred_username),
890
+ user.given_name && user.family_name ? optionalString(`${user.given_name} ${user.family_name}`) : void 0,
891
+ claim("full_name"),
892
+ claim("displayName")
893
+ ];
894
+ return candidates.find(Boolean) ?? optionalString(user.email) ?? user.sub;
895
+ }, [user, claim]);
896
+ const secondaryText = useMemo(() => {
897
+ if (!user) return void 0;
898
+ const email = optionalString(user.email);
899
+ if (email && email !== displayName) return email;
900
+ const sub = optionalString(user.sub);
901
+ return sub && sub !== displayName ? sub : void 0;
902
+ }, [user, displayName]);
903
+ useEffect3(() => {
904
+ const fresh = readPersistedToken();
905
+ const store = useAuthenticationStore.getState();
906
+ if (fresh && fresh !== store.token) store.setToken(fresh);
907
+ }, []);
908
+ useEffect3(() => {
909
+ let active = true;
910
+ let objectUrl = null;
911
+ const resolve = async () => {
912
+ try {
913
+ const avatarId = claim("avatarUrl");
914
+ const fileStorageApiUrl = usePackageSettingsStore.getState().settings?.fileStorageApiUrl;
915
+ const token = useAuthenticationStore.getState().token;
916
+ if (avatarId && fileStorageApiUrl && token) {
917
+ const base = fileStorageApiUrl.replace(/\/$/, "");
918
+ const response = await fetch(
919
+ `${base}/app-asset/download/${encodeURIComponent(avatarId)}`,
920
+ { headers: { Authorization: `Bearer ${token}` } }
921
+ );
922
+ if (response.ok) {
923
+ const blob = await response.blob();
924
+ if (active) {
925
+ objectUrl = URL.createObjectURL(blob);
926
+ setAvatarSrc(objectUrl);
927
+ }
928
+ return;
929
+ }
930
+ }
931
+ } catch {
932
+ }
933
+ try {
934
+ const branding = await brandingService_default.getBranding();
935
+ if (active) setAvatarSrc(branding?.logoBase64 || BANDIT_AVATAR);
936
+ } catch (error) {
937
+ debugLogger.error("Failed to load branding avatar", {
938
+ error: error instanceof Error ? error.message : String(error)
939
+ });
940
+ if (active) setAvatarSrc(BANDIT_AVATAR);
941
+ }
942
+ };
943
+ void resolve();
944
+ return () => {
945
+ active = false;
946
+ if (objectUrl) URL.revokeObjectURL(objectUrl);
947
+ };
948
+ }, [claim]);
949
+ const label = displayName || user?.email || "Bandit";
950
+ return {
951
+ signedIn: Boolean(user),
952
+ displayName,
953
+ secondaryText,
954
+ avatarSrc,
955
+ initials: deriveInitials(label)
956
+ };
957
+ }
958
+
959
+ // src/chat/sidebar/SidebarUserCard.tsx
960
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
961
+ function goHome(safeNavigate, preferencesHomeUrl) {
962
+ const homeUrl = preferencesHomeUrl?.trim() || usePackageSettingsStore.getState().settings?.homeUrl?.trim() || "";
963
+ if (homeUrl) {
964
+ window.location.href = homeUrl;
965
+ return;
966
+ }
967
+ if (isNativeShell()) {
968
+ safeNavigate("/chat");
969
+ return;
970
+ }
971
+ if (isStandalonePwa()) {
972
+ try {
973
+ sessionStorage.setItem("banditPwaStayOnHome", "true");
974
+ } catch {
975
+ }
976
+ window.location.href = "/?mode=home";
977
+ return;
978
+ }
979
+ window.location.href = "/";
980
+ }
981
+ var managementPathFor = (pathname) => pathname.startsWith("/playground") ? "/playground/management" : "/management";
982
+ var SidebarUserCard = ({ safeAreaBottom }) => {
983
+ const theme = useTheme3();
984
+ const user = useSidebarUser();
985
+ const safeNavigate = useSafeNavigate();
986
+ const { preferences } = usePreferencesStore();
987
+ const { showLimitedAdminPanel } = useFeatureVisibility();
988
+ const managementPath = managementPathFor(
989
+ typeof window === "undefined" ? "/" : window.location.pathname
990
+ );
991
+ const roundButton = {
992
+ flexShrink: 0,
993
+ width: 32,
994
+ height: 32,
995
+ border: `1px solid ${alpha2(theme.palette.divider, 0.8)}`,
996
+ color: theme.palette.text.secondary,
997
+ "&:hover": {
998
+ color: theme.palette.text.primary,
999
+ bgcolor: alpha2(theme.palette.text.primary, 0.06)
1000
+ },
1001
+ "&:focus-visible": {
1002
+ outline: `2px solid ${theme.palette.primary.main}`,
1003
+ outlineOffset: "2px"
1004
+ }
1005
+ };
1006
+ return /* @__PURE__ */ jsxs3(
1007
+ Box3,
1008
+ {
1009
+ sx: {
1010
+ mt: "auto",
1011
+ px: 1.5,
1012
+ py: 1.25,
1013
+ pb: safeAreaBottom ? `calc(${theme.spacing(1.25)} + env(safe-area-inset-bottom, 0px))` : 1.25,
1014
+ borderTop: `1px solid ${alpha2(theme.palette.divider, 0.6)}`,
1015
+ display: "flex",
1016
+ alignItems: "center",
1017
+ gap: 1
1018
+ },
1019
+ children: [
1020
+ /* @__PURE__ */ jsxs3(
1021
+ Box3,
1022
+ {
1023
+ component: user.signedIn ? "button" : "div",
1024
+ type: user.signedIn ? "button" : void 0,
1025
+ onClick: user.signedIn ? () => safeNavigate("/profile") : void 0,
1026
+ "aria-label": user.signedIn ? "Profile and account" : void 0,
1027
+ sx: {
1028
+ flex: 1,
1029
+ minWidth: 0,
1030
+ display: "flex",
1031
+ alignItems: "center",
1032
+ gap: 1.25,
1033
+ p: 0.5,
1034
+ m: -0.5,
1035
+ border: 0,
1036
+ borderRadius: 1,
1037
+ bgcolor: "transparent",
1038
+ color: "inherit",
1039
+ font: "inherit",
1040
+ textAlign: "left",
1041
+ cursor: user.signedIn ? "pointer" : "default",
1042
+ "&:hover": user.signedIn ? { bgcolor: alpha2(theme.palette.text.primary, 0.04) } : void 0,
1043
+ "&:focus-visible": {
1044
+ outline: `2px solid ${theme.palette.primary.main}`,
1045
+ outlineOffset: "-2px"
1046
+ }
1047
+ },
1048
+ children: [
1049
+ /* @__PURE__ */ jsx3(
1050
+ Avatar2,
1051
+ {
1052
+ src: user.avatarSrc,
1053
+ alt: "",
1054
+ sx: {
1055
+ width: 34,
1056
+ height: 34,
1057
+ fontSize: "0.9rem",
1058
+ bgcolor: alpha2(theme.palette.primary.main, 0.12),
1059
+ color: theme.palette.primary.main
1060
+ },
1061
+ children: user.initials
1062
+ }
1063
+ ),
1064
+ /* @__PURE__ */ jsxs3(Box3, { sx: { minWidth: 0, display: "flex", flexDirection: "column" }, children: [
1065
+ /* @__PURE__ */ jsx3(
1066
+ Typography3,
1067
+ {
1068
+ variant: "subtitle2",
1069
+ noWrap: true,
1070
+ sx: { fontWeight: 600, lineHeight: 1.3 },
1071
+ children: user.signedIn ? user.displayName : "Not signed in"
1072
+ }
1073
+ ),
1074
+ /* @__PURE__ */ jsx3(
1075
+ Typography3,
1076
+ {
1077
+ variant: "caption",
1078
+ noWrap: true,
1079
+ sx: { color: theme.palette.text.secondary, lineHeight: 1.3 },
1080
+ children: user.signedIn ? user.secondaryText || "Profile and account" : "Sign in to sync chats"
1081
+ }
1082
+ )
1083
+ ] })
1084
+ ]
1085
+ }
1086
+ ),
1087
+ /* @__PURE__ */ jsx3(Tooltip, { title: "Home", arrow: true, children: /* @__PURE__ */ jsx3(
1088
+ IconButton2,
1089
+ {
1090
+ "aria-label": "Home",
1091
+ onClick: () => goHome(safeNavigate, preferences.homeUrl),
1092
+ sx: roundButton,
1093
+ children: /* @__PURE__ */ jsx3(Home, { size: 16 })
1094
+ }
1095
+ ) }),
1096
+ user.signedIn && showLimitedAdminPanel() && /* @__PURE__ */ jsx3(Tooltip, { title: "Settings", arrow: true, children: /* @__PURE__ */ jsx3(
1097
+ IconButton2,
1098
+ {
1099
+ "aria-label": "Settings",
1100
+ onClick: () => safeNavigate(managementPath),
1101
+ sx: roundButton,
1102
+ children: /* @__PURE__ */ jsx3(Settings, { size: 16 })
1103
+ }
1104
+ ) }),
1105
+ user.signedIn && /* @__PURE__ */ jsx3(Tooltip, { title: "Sign out", arrow: true, children: /* @__PURE__ */ jsx3(
1106
+ IconButton2,
1107
+ {
1108
+ "aria-label": "Sign out",
1109
+ onClick: () => {
1110
+ authenticationService.clearToken();
1111
+ window.location.href = "/login";
1112
+ },
1113
+ sx: {
1114
+ ...roundButton,
1115
+ border: `1px solid ${alpha2(theme.palette.error.main, 0.4)}`,
1116
+ color: theme.palette.error.main,
1117
+ "&:hover": { bgcolor: alpha2(theme.palette.error.main, 0.1) }
1118
+ },
1119
+ children: /* @__PURE__ */ jsx3(LogOut, { size: 16 })
1120
+ }
1121
+ ) })
1122
+ ]
1123
+ }
1124
+ );
1125
+ };
1126
+
1127
+ // src/chat/sidebar/ProjectDialog.tsx
1128
+ import { useEffect as useEffect4, useState as useState4 } from "react";
1129
+ import {
1130
+ Box as Box4,
1131
+ Button as Button3,
1132
+ Dialog as Dialog3,
1133
+ DialogActions as DialogActions3,
1134
+ DialogContent as DialogContent3,
1135
+ DialogTitle as DialogTitle3,
1136
+ TextField as TextField2,
1137
+ alpha as alpha3
1138
+ } from "@mui/material";
1139
+ import { useTheme as useTheme4 } from "@mui/material/styles";
1140
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1141
+ var ProjectDialog = ({
1142
+ open,
1143
+ onClose,
1144
+ project,
1145
+ onCreated
1146
+ }) => {
1147
+ const theme = useTheme4();
1148
+ const { createProject, renameProject, updateProjectColor, projects } = useProjectStore();
1149
+ const [name, setName] = useState4("");
1150
+ const [color, setColor] = useState4(PROJECT_COLORS[0]);
1151
+ const [saving, setSaving] = useState4(false);
1152
+ const [error, setError] = useState4(null);
1153
+ useEffect4(() => {
1154
+ if (!open) return;
1155
+ setName(project?.name ?? "");
1156
+ setColor(project?.color ?? PROJECT_COLORS[projects.length % PROJECT_COLORS.length]);
1157
+ setError(null);
1158
+ }, [open, project, projects.length]);
1159
+ const trimmed = name.trim();
1160
+ const canSave = trimmed.length > 0 && !saving;
1161
+ const save = async () => {
1162
+ if (!canSave) return;
1163
+ setSaving(true);
1164
+ setError(null);
1165
+ try {
1166
+ if (project) {
1167
+ if (trimmed !== project.name)
1168
+ await renameProject(project.id, trimmed, project.description);
1169
+ if (color !== project.color) await updateProjectColor(project.id, color);
1170
+ } else {
1171
+ const created = await createProject(trimmed, void 0, color);
1172
+ onCreated?.(created);
1173
+ }
1174
+ onClose();
1175
+ } catch (cause) {
1176
+ debugLogger.error("Saving the project failed", {
1177
+ error: cause instanceof Error ? cause.message : String(cause)
1178
+ });
1179
+ setError("The project could not be saved. Try again.");
1180
+ } finally {
1181
+ setSaving(false);
1182
+ }
1183
+ };
1184
+ return /* @__PURE__ */ jsxs4(Dialog3, { open, onClose, maxWidth: "xs", fullWidth: true, children: [
1185
+ /* @__PURE__ */ jsx4(DialogTitle3, { children: project ? "Edit project" : "New project" }),
1186
+ /* @__PURE__ */ jsxs4(DialogContent3, { sx: { display: "flex", flexDirection: "column", gap: 2 }, children: [
1187
+ /* @__PURE__ */ jsx4(
1188
+ TextField2,
1189
+ {
1190
+ autoFocus: true,
1191
+ label: "Name",
1192
+ value: name,
1193
+ onChange: (event) => setName(event.target.value),
1194
+ onKeyDown: (event) => {
1195
+ if (event.key === "Enter") {
1196
+ event.preventDefault();
1197
+ void save();
1198
+ }
1199
+ },
1200
+ error: Boolean(error),
1201
+ helperText: error ?? " ",
1202
+ fullWidth: true,
1203
+ size: "small",
1204
+ inputProps: { maxLength: 80 }
1205
+ }
1206
+ ),
1207
+ /* @__PURE__ */ jsx4(
1208
+ Box4,
1209
+ {
1210
+ role: "radiogroup",
1211
+ "aria-label": "Colour",
1212
+ sx: { display: "flex", gap: 1, flexWrap: "wrap" },
1213
+ children: PROJECT_COLORS.map((swatch) => {
1214
+ const selected = swatch === color;
1215
+ return /* @__PURE__ */ jsx4(
1216
+ Box4,
1217
+ {
1218
+ component: "button",
1219
+ type: "button",
1220
+ role: "radio",
1221
+ "aria-checked": selected,
1222
+ "aria-label": `Colour ${swatch}`,
1223
+ onClick: () => setColor(swatch),
1224
+ sx: {
1225
+ width: 28,
1226
+ height: 28,
1227
+ p: 0,
1228
+ borderRadius: "50%",
1229
+ border: `2px solid ${selected ? theme.palette.text.primary : "transparent"}`,
1230
+ bgcolor: swatch,
1231
+ cursor: "pointer",
1232
+ display: "grid",
1233
+ placeItems: "center",
1234
+ color: theme.palette.getContrastText(swatch),
1235
+ "&:focus-visible": {
1236
+ outline: `2px solid ${theme.palette.primary.main}`,
1237
+ outlineOffset: "2px"
1238
+ },
1239
+ "&:hover": { boxShadow: `0 0 0 3px ${alpha3(swatch, 0.35)}` }
1240
+ },
1241
+ children: selected && /* @__PURE__ */ jsx4(Check, { size: 14, "aria-hidden": true })
1242
+ },
1243
+ swatch
1244
+ );
1245
+ })
1246
+ }
1247
+ )
1248
+ ] }),
1249
+ /* @__PURE__ */ jsxs4(DialogActions3, { children: [
1250
+ /* @__PURE__ */ jsx4(Button3, { onClick: onClose, children: "Cancel" }),
1251
+ /* @__PURE__ */ jsx4(Button3, { variant: "contained", onClick: () => void save(), disabled: !canSave, children: project ? "Save" : "Create" })
1252
+ ] })
1253
+ ] });
1254
+ };
1255
+
1256
+ // src/chat/sidebar/recents.ts
1257
+ var BUCKET_LABELS = {
1258
+ today: "Today",
1259
+ week: "Previous 7 days",
1260
+ older: "Older"
1261
+ };
1262
+ var DAY_MS = 24 * 60 * 60 * 1e3;
1263
+ var asTime = (value) => {
1264
+ if (!value) return 0;
1265
+ const time = value instanceof Date ? value.getTime() : new Date(value).getTime();
1266
+ return Number.isNaN(time) ? 0 : time;
1267
+ };
1268
+ var lastActivity = (conversation) => asTime(conversation.updatedAt) || asTime(conversation.createdAt);
1269
+ var startOfDay = (now) => {
1270
+ const date = new Date(now);
1271
+ date.setHours(0, 0, 0, 0);
1272
+ return date.getTime();
1273
+ };
1274
+ function groupByRecency(conversations, now = Date.now()) {
1275
+ const today = startOfDay(now);
1276
+ const weekAgo = today - 7 * DAY_MS;
1277
+ const sorted = [...conversations].sort((a, b) => lastActivity(b) - lastActivity(a));
1278
+ const buckets = { today: [], week: [], older: [] };
1279
+ for (const conversation of sorted) {
1280
+ const time = lastActivity(conversation);
1281
+ if (time >= today) buckets.today.push(conversation);
1282
+ else if (time >= weekAgo) buckets.week.push(conversation);
1283
+ else buckets.older.push(conversation);
1284
+ }
1285
+ return ["today", "week", "older"].filter((id) => buckets[id].length > 0).map((id) => ({ id, label: BUCKET_LABELS[id], items: buckets[id] }));
1286
+ }
1287
+ var buildSnippet = (text, query, index) => {
1288
+ const start = Math.max(0, index - 40);
1289
+ const end = Math.min(text.length, index + query.length + 60);
1290
+ return text.slice(start, end).replace(/\s+/g, " ").trim();
1291
+ };
1292
+ function searchConversations(conversations, query) {
1293
+ const needle = query.trim().toLowerCase();
1294
+ if (!needle) return [];
1295
+ const matches = [];
1296
+ for (const conversation of conversations) {
1297
+ if (conversation.name.toLowerCase().includes(needle)) {
1298
+ matches.push({ conversation });
1299
+ continue;
1300
+ }
1301
+ for (const entry of conversation.history) {
1302
+ const body = `${entry.question || ""} ${entry.answer || ""}`;
1303
+ const index = body.toLowerCase().indexOf(needle);
1304
+ if (index !== -1) {
1305
+ matches.push({ conversation, snippet: buildSnippet(body, needle, index) });
1306
+ break;
1307
+ }
1308
+ }
1309
+ }
1310
+ return matches;
1311
+ }
1312
+ var listable = (conversations) => conversations.filter((conversation) => !conversation.incognito);
1313
+ function formatRelative(time, now = Date.now()) {
1314
+ if (!time) return "";
1315
+ const diff = Math.max(0, now - time);
1316
+ const minute = 60 * 1e3;
1317
+ const hour = 60 * minute;
1318
+ if (diff < minute) return "just now";
1319
+ if (diff < hour) return `${Math.floor(diff / minute)} min ago`;
1320
+ if (diff < DAY_MS) return `${Math.floor(diff / hour)} h ago`;
1321
+ const days = Math.floor((startOfDay(now) - startOfDay(time)) / DAY_MS);
1322
+ if (days <= 1) return "yesterday";
1323
+ if (days < 7) return `${days} days ago`;
1324
+ const date = new Date(time);
1325
+ const sameYear = date.getFullYear() === new Date(now).getFullYear();
1326
+ return date.toLocaleDateString(void 0, {
1327
+ month: "short",
1328
+ day: "numeric",
1329
+ ...sameYear ? {} : { year: "numeric" }
1330
+ });
1331
+ }
1332
+
1333
+ // src/chat/sidebar/SidebarProjects.tsx
1334
+ import { useMemo as useMemo2 } from "react";
1335
+ import { Box as Box6, IconButton as IconButton3, Tooltip as Tooltip2, Typography as Typography5 } from "@mui/material";
1336
+ import { useTheme as useTheme6 } from "@mui/material/styles";
1337
+
1338
+ // src/chat/sidebar/SectionRow.tsx
1339
+ import { forwardRef } from "react";
1340
+ import { Box as Box5, ButtonBase, Typography as Typography4, alpha as alpha4 } from "@mui/material";
1341
+ import { useTheme as useTheme5 } from "@mui/material/styles";
1342
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1343
+ var IS_MAC = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "");
1344
+ var shortcutLabel = (combo) => {
1345
+ if (IS_MAC) {
1346
+ return combo.map((key) => key === "mod" ? "\u2318" : key === "shift" ? "\u21E7" : key).join("");
1347
+ }
1348
+ return combo.map((key) => key === "mod" ? "Ctrl" : key === "shift" ? "Shift" : key).join("+");
1349
+ };
1350
+ var SidebarKbd = ({ children }) => {
1351
+ const theme = useTheme5();
1352
+ return /* @__PURE__ */ jsx5(
1353
+ Box5,
1354
+ {
1355
+ component: "kbd",
1356
+ "aria-hidden": true,
1357
+ sx: {
1358
+ ml: "auto",
1359
+ px: 0.6,
1360
+ py: 0.1,
1361
+ borderRadius: 0.75,
1362
+ border: `1px solid ${alpha4(theme.palette.text.primary, 0.14)}`,
1363
+ color: theme.palette.text.secondary,
1364
+ fontFamily: "inherit",
1365
+ fontSize: "0.68rem",
1366
+ lineHeight: 1.4,
1367
+ whiteSpace: "nowrap",
1368
+ opacity: 0.9
1369
+ },
1370
+ children
1371
+ }
1372
+ );
1373
+ };
1374
+ var SidebarCaption = ({
1375
+ children,
1376
+ action,
1377
+ component = "h2"
1378
+ }) => {
1379
+ const theme = useTheme5();
1380
+ return /* @__PURE__ */ jsxs5(
1381
+ Box5,
1382
+ {
1383
+ sx: {
1384
+ display: "flex",
1385
+ alignItems: "center",
1386
+ gap: 1,
1387
+ px: 2,
1388
+ pt: 1.5,
1389
+ pb: 0.5,
1390
+ minHeight: 32
1391
+ },
1392
+ children: [
1393
+ /* @__PURE__ */ jsx5(
1394
+ Typography4,
1395
+ {
1396
+ component,
1397
+ sx: {
1398
+ m: 0,
1399
+ flex: 1,
1400
+ color: theme.palette.text.secondary,
1401
+ fontSize: "0.7rem",
1402
+ fontWeight: 600,
1403
+ letterSpacing: "0.5px",
1404
+ textTransform: "uppercase",
1405
+ lineHeight: 1.4
1406
+ },
1407
+ children
1408
+ }
1409
+ ),
1410
+ action
1411
+ ]
1412
+ }
1413
+ );
1414
+ };
1415
+ var SectionRow = forwardRef(function SectionRow2({
1416
+ icon,
1417
+ label,
1418
+ trailing,
1419
+ active = false,
1420
+ href,
1421
+ external,
1422
+ onClick,
1423
+ size = "regular",
1424
+ swatch,
1425
+ ...rest
1426
+ }, ref) {
1427
+ const theme = useTheme5();
1428
+ const anchorProps = href ? {
1429
+ component: "a",
1430
+ href,
1431
+ ...external ? { rel: "noopener" } : {}
1432
+ } : { component: "button", type: "button" };
1433
+ return /* @__PURE__ */ jsxs5(
1434
+ ButtonBase,
1435
+ {
1436
+ ref,
1437
+ ...anchorProps,
1438
+ onClick,
1439
+ "aria-current": active ? "page" : void 0,
1440
+ "aria-label": rest["aria-label"],
1441
+ "data-section": rest["data-section"],
1442
+ "data-external": external ? "" : void 0,
1443
+ sx: {
1444
+ width: "calc(100% - 16px)",
1445
+ mx: 1,
1446
+ minHeight: size === "touch" ? 44 : 36,
1447
+ px: 1.25,
1448
+ py: 0.5,
1449
+ display: "flex",
1450
+ alignItems: "center",
1451
+ justifyContent: "flex-start",
1452
+ gap: 1.25,
1453
+ borderRadius: 1,
1454
+ textAlign: "left",
1455
+ textDecoration: "none",
1456
+ font: "inherit",
1457
+ fontSize: "0.875rem",
1458
+ fontWeight: active ? 600 : 500,
1459
+ color: active ? theme.palette.text.primary : theme.palette.text.secondary,
1460
+ bgcolor: active ? alpha4(theme.palette.text.primary, 0.08) : "transparent",
1461
+ transition: theme.transitions.create(["background-color", "color"], {
1462
+ duration: theme.transitions.duration.shorter
1463
+ }),
1464
+ "@media (pointer: coarse)": { minHeight: 44 },
1465
+ "&:hover": {
1466
+ color: theme.palette.text.primary,
1467
+ bgcolor: alpha4(theme.palette.text.primary, active ? 0.1 : 0.04)
1468
+ },
1469
+ "&:focus-visible": {
1470
+ outline: `2px solid ${theme.palette.primary.main}`,
1471
+ outlineOffset: "-2px"
1472
+ },
1473
+ "& svg": { flexShrink: 0 }
1474
+ },
1475
+ children: [
1476
+ swatch ? /* @__PURE__ */ jsx5(
1477
+ Box5,
1478
+ {
1479
+ "aria-hidden": true,
1480
+ sx: {
1481
+ width: 10,
1482
+ height: 10,
1483
+ mx: "4px",
1484
+ borderRadius: "50%",
1485
+ bgcolor: swatch,
1486
+ flexShrink: 0
1487
+ }
1488
+ }
1489
+ ) : icon,
1490
+ /* @__PURE__ */ jsx5(
1491
+ Box5,
1492
+ {
1493
+ component: "span",
1494
+ sx: {
1495
+ flex: 1,
1496
+ minWidth: 0,
1497
+ overflow: "hidden",
1498
+ textOverflow: "ellipsis",
1499
+ whiteSpace: "nowrap"
1500
+ },
1501
+ children: label
1502
+ }
1503
+ ),
1504
+ trailing
1505
+ ]
1506
+ }
1507
+ );
1508
+ });
1509
+
1510
+ // src/chat/sidebar/SidebarProjects.tsx
1511
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1512
+ var SIDEBAR_PROJECT_LIMIT = 6;
1513
+ function summarizeProjects(projects, conversations) {
1514
+ return projects.map((project) => {
1515
+ const chats = conversations.filter((c) => c.projectId === project.id);
1516
+ const newest = chats.reduce((max, c) => Math.max(max, lastActivity(c)), 0);
1517
+ return {
1518
+ project,
1519
+ chatCount: chats.length,
1520
+ activeAt: newest || project.updatedAt.getTime()
1521
+ };
1522
+ }).sort((a, b) => b.activeAt - a.activeAt || a.project.order - b.project.order);
1523
+ }
1524
+ var SidebarProjects = ({
1525
+ activeProjectId,
1526
+ onOpenProject,
1527
+ onAllProjects,
1528
+ onNewProject,
1529
+ size
1530
+ }) => {
1531
+ const theme = useTheme6();
1532
+ const projects = useProjectStore((state) => state.projects);
1533
+ const conversations = useConversationStore((state) => state.conversations);
1534
+ const summaries = useMemo2(
1535
+ () => summarizeProjects(projects, listable(conversations)),
1536
+ [projects, conversations]
1537
+ );
1538
+ const shown = summaries.slice(0, SIDEBAR_PROJECT_LIMIT);
1539
+ return /* @__PURE__ */ jsxs6(Box6, { component: "section", "aria-labelledby": "bandit-sidebar-projects", children: [
1540
+ /* @__PURE__ */ jsx6(
1541
+ SidebarCaption,
1542
+ {
1543
+ action: /* @__PURE__ */ jsx6(Tooltip2, { title: "New project", arrow: true, children: /* @__PURE__ */ jsx6(
1544
+ IconButton3,
1545
+ {
1546
+ size: "small",
1547
+ "aria-label": "New project",
1548
+ onClick: onNewProject,
1549
+ sx: { color: theme.palette.text.secondary, width: 28, height: 28 },
1550
+ children: /* @__PURE__ */ jsx6(Plus, { size: 16 })
1551
+ }
1552
+ ) }),
1553
+ children: /* @__PURE__ */ jsx6("span", { id: "bandit-sidebar-projects", children: "Projects" })
1554
+ }
1555
+ ),
1556
+ shown.length === 0 && /* @__PURE__ */ jsx6(
1557
+ Typography5,
1558
+ {
1559
+ variant: "caption",
1560
+ sx: { display: "block", px: 2.25, pb: 1, color: theme.palette.text.secondary },
1561
+ children: "No projects yet."
1562
+ }
1563
+ ),
1564
+ shown.map(({ project, chatCount }) => /* @__PURE__ */ jsx6(
1565
+ SectionRow,
1566
+ {
1567
+ "data-section": `project:${project.id}`,
1568
+ swatch: project.color || theme.palette.text.disabled,
1569
+ label: project.name,
1570
+ size,
1571
+ active: activeProjectId === project.id,
1572
+ onClick: () => onOpenProject(project.id),
1573
+ trailing: chatCount > 0 ? /* @__PURE__ */ jsx6(
1574
+ Typography5,
1575
+ {
1576
+ component: "span",
1577
+ variant: "caption",
1578
+ "aria-label": `${chatCount} ${chatCount === 1 ? "chat" : "chats"}`,
1579
+ sx: {
1580
+ color: theme.palette.text.disabled,
1581
+ fontVariantNumeric: "tabular-nums"
1582
+ },
1583
+ children: chatCount
1584
+ }
1585
+ ) : null
1586
+ },
1587
+ project.id
1588
+ )),
1589
+ summaries.length > SIDEBAR_PROJECT_LIMIT && /* @__PURE__ */ jsx6(
1590
+ SectionRow,
1591
+ {
1592
+ "data-section": "all-projects",
1593
+ label: `All projects (${summaries.length})`,
1594
+ size,
1595
+ onClick: onAllProjects,
1596
+ icon: /* @__PURE__ */ jsx6(Box6, { "aria-hidden": true, sx: { width: 18 } })
1597
+ }
1598
+ )
1599
+ ] });
1600
+ };
1601
+
1602
+ // src/chat/sidebar/SidebarSections.tsx
1603
+ import { Box as Box7 } from "@mui/material";
1604
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1605
+ var NEW_CHAT_SHORTCUT = ["mod", "shift", "O"];
1606
+ var SEARCH_SHORTCUT = ["mod", "K"];
1607
+ var TOGGLE_SIDEBAR_SHORTCUT = ["mod", "shift", "S"];
1608
+ var useNoSections = () => [];
1609
+ function useHostSections() {
1610
+ const useSections = usePackageSettingsStore(
1611
+ (state) => state.settings?.navigation?.useSections
1612
+ );
1613
+ return (useSections ?? useNoSections)();
1614
+ }
1615
+ var isPlainLeftClick = (event) => event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;
1616
+ var SidebarSections = ({
1617
+ onNewChat,
1618
+ onSearch,
1619
+ searchOpen,
1620
+ onProjects,
1621
+ projectsActive,
1622
+ showHints = false,
1623
+ size = "regular",
1624
+ onAfterNavigate
1625
+ }) => {
1626
+ const hostSections = useHostSections();
1627
+ const safeNavigate = useSafeNavigate();
1628
+ const iconSize = 18;
1629
+ const follow = (section) => (event) => {
1630
+ if (!isPlainLeftClick(event)) return;
1631
+ section.onSelect?.(event);
1632
+ if (event.defaultPrevented) {
1633
+ onAfterNavigate?.();
1634
+ return;
1635
+ }
1636
+ if (section.external) {
1637
+ onAfterNavigate?.();
1638
+ return;
1639
+ }
1640
+ event.preventDefault();
1641
+ safeNavigate(section.href);
1642
+ onAfterNavigate?.();
1643
+ };
1644
+ return /* @__PURE__ */ jsxs7(
1645
+ Box7,
1646
+ {
1647
+ component: "nav",
1648
+ "aria-label": "Chat navigation",
1649
+ sx: { display: "flex", flexDirection: "column", gap: 0.25, pt: 0.5, pb: 1 },
1650
+ children: [
1651
+ /* @__PURE__ */ jsx7(
1652
+ SectionRow,
1653
+ {
1654
+ "data-section": "new-chat",
1655
+ icon: /* @__PURE__ */ jsx7(MessageSquarePlus, { size: iconSize }),
1656
+ label: "New chat",
1657
+ size,
1658
+ onClick: onNewChat,
1659
+ trailing: showHints ? /* @__PURE__ */ jsx7(SidebarKbd, { children: shortcutLabel(NEW_CHAT_SHORTCUT) }) : null
1660
+ }
1661
+ ),
1662
+ /* @__PURE__ */ jsx7(
1663
+ SectionRow,
1664
+ {
1665
+ "data-section": "search",
1666
+ icon: /* @__PURE__ */ jsx7(Search, { size: iconSize }),
1667
+ label: "Search chats",
1668
+ size,
1669
+ active: searchOpen,
1670
+ onClick: onSearch,
1671
+ "aria-label": searchOpen ? "Close search" : "Search chats",
1672
+ trailing: showHints ? /* @__PURE__ */ jsx7(SidebarKbd, { children: shortcutLabel(SEARCH_SHORTCUT) }) : null
1673
+ }
1674
+ ),
1675
+ /* @__PURE__ */ jsx7(
1676
+ SectionRow,
1677
+ {
1678
+ "data-section": "projects",
1679
+ icon: /* @__PURE__ */ jsx7(Folder, { size: iconSize }),
1680
+ label: "Projects",
1681
+ size,
1682
+ active: projectsActive,
1683
+ onClick: onProjects
1684
+ }
1685
+ ),
1686
+ hostSections.map((section) => /* @__PURE__ */ jsx7(
1687
+ SectionRow,
1688
+ {
1689
+ "data-section": section.id,
1690
+ icon: section.icon,
1691
+ label: section.label,
1692
+ size,
1693
+ href: section.href,
1694
+ external: section.external,
1695
+ active: section.active,
1696
+ onClick: follow(section)
1697
+ },
1698
+ section.id
1699
+ ))
1700
+ ]
1701
+ }
1702
+ );
1703
+ };
1704
+
1705
+ export {
1706
+ brandingService_default,
1707
+ useSafeNavigate,
1708
+ move_conversation_modal_default,
1709
+ simple_conversation_item_default,
1710
+ managementPathFor,
1711
+ SidebarUserCard,
1712
+ ProjectDialog,
1713
+ lastActivity,
1714
+ groupByRecency,
1715
+ searchConversations,
1716
+ listable,
1717
+ formatRelative,
1718
+ shortcutLabel,
1719
+ SidebarCaption,
1720
+ summarizeProjects,
1721
+ SidebarProjects,
1722
+ TOGGLE_SIDEBAR_SHORTCUT,
1723
+ useHostSections,
1724
+ SidebarSections,
1725
+ SIDEBAR_WIDTH,
1726
+ writePersistedCollapsed,
1727
+ initialSidebarOpen,
1728
+ useSidebarStore,
1729
+ syncViewWithUrl,
1730
+ useSectionsLayout
1731
+ };
1732
+ //# sourceMappingURL=chunk-P42M52OW.mjs.map