@burtson-labs/bandit-engine 2.1.3 → 2.1.5

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 (49) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/ProjectsPane-BSVOVNK7.mjs +866 -0
  3. package/dist/ProjectsPane-BSVOVNK7.mjs.map +1 -0
  4. package/dist/{SchedulesTab-YZG3P2GW.mjs → SchedulesTab-TCUOAKLH.mjs} +5 -4
  5. package/dist/SchedulesTab-TCUOAKLH.mjs.map +1 -0
  6. package/dist/chat-Y7KPN54G.mjs +18 -0
  7. package/dist/chunk-4257FVLK.mjs +158 -0
  8. package/dist/chunk-4257FVLK.mjs.map +1 -0
  9. package/dist/chunk-HS62C62A.mjs +22 -0
  10. package/dist/chunk-HS62C62A.mjs.map +1 -0
  11. package/dist/chunk-IXD2TDA5.mjs +3567 -0
  12. package/dist/chunk-IXD2TDA5.mjs.map +1 -0
  13. package/dist/{chunk-4LLCLYLH.mjs → chunk-K7SQWDNF.mjs} +1 -1
  14. package/dist/{chunk-4LLCLYLH.mjs.map → chunk-K7SQWDNF.mjs.map} +1 -1
  15. package/dist/{chunk-6CSFKF34.mjs → chunk-KWOUXBSF.mjs} +3 -3
  16. package/dist/chunk-MAKXJD7A.mjs +233 -0
  17. package/dist/chunk-MAKXJD7A.mjs.map +1 -0
  18. package/dist/{chunk-PSI7RQ54.mjs → chunk-SK7FSLCY.mjs} +2 -2
  19. package/dist/{chunk-W2D454CZ.mjs → chunk-XGIQNHUO.mjs} +3087 -4831
  20. package/dist/chunk-XGIQNHUO.mjs.map +1 -0
  21. package/dist/{chunk-62H3OLTV.mjs → chunk-ZG66NJC3.mjs} +19 -22
  22. package/dist/chunk-ZG66NJC3.mjs.map +1 -0
  23. package/dist/index.d.mts +2 -2
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.js +6000 -3087
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +501 -276
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/modelStore-YNANSWCN.mjs +9 -0
  30. package/dist/{public-ByjnoHLe.d.mts → public-Tq2Pmw9m.d.mts} +44 -2
  31. package/dist/{public-ByjnoHLe.d.ts → public-Tq2Pmw9m.d.ts} +44 -2
  32. package/dist/public-types.d.mts +1 -1
  33. package/dist/public-types.d.ts +1 -1
  34. package/dist/{schedule-confirm-card-N4TKLEHL.mjs → schedule-confirm-card-7CMATYSP.mjs} +8 -5
  35. package/dist/schedule-confirm-card-7CMATYSP.mjs.map +1 -0
  36. package/docs/package-settings.md +25 -0
  37. package/package.json +1 -1
  38. package/dist/SchedulesTab-YZG3P2GW.mjs.map +0 -1
  39. package/dist/chat-W7MDFESE.mjs +0 -15
  40. package/dist/chunk-62H3OLTV.mjs.map +0 -1
  41. package/dist/chunk-LMAQWR7Z.mjs +0 -388
  42. package/dist/chunk-LMAQWR7Z.mjs.map +0 -1
  43. package/dist/chunk-W2D454CZ.mjs.map +0 -1
  44. package/dist/modelStore-FIVOSLFY.mjs +0 -9
  45. package/dist/schedule-confirm-card-N4TKLEHL.mjs.map +0 -1
  46. /package/dist/{chat-W7MDFESE.mjs.map → chat-Y7KPN54G.mjs.map} +0 -0
  47. /package/dist/{chunk-6CSFKF34.mjs.map → chunk-KWOUXBSF.mjs.map} +0 -0
  48. /package/dist/{chunk-PSI7RQ54.mjs.map → chunk-SK7FSLCY.mjs.map} +0 -0
  49. /package/dist/{modelStore-FIVOSLFY.mjs.map → modelStore-YNANSWCN.mjs.map} +0 -0
@@ -0,0 +1,866 @@
1
+ import {
2
+ ProjectDialog,
3
+ chatTokens,
4
+ formatRelative,
5
+ lastActivity,
6
+ listable,
7
+ managementPathFor,
8
+ move_conversation_modal_default,
9
+ simple_conversation_item_default,
10
+ summarizeProjects,
11
+ useConversationStore,
12
+ useHostSections,
13
+ useProjectStore,
14
+ useSafeNavigate,
15
+ useSidebarStore
16
+ } from "./chunk-IXD2TDA5.mjs";
17
+ import "./chunk-KWOUXBSF.mjs";
18
+ import {
19
+ ArrowLeft,
20
+ Edit,
21
+ ExternalLink,
22
+ MessageSquarePlus,
23
+ MoreVertical,
24
+ Plus,
25
+ Trash
26
+ } from "./chunk-ZG66NJC3.mjs";
27
+ import "./chunk-4257FVLK.mjs";
28
+ import "./chunk-K7SQWDNF.mjs";
29
+ import "./chunk-S3DWWUBD.mjs";
30
+ import {
31
+ debugLogger
32
+ } from "./chunk-NI7BKLC7.mjs";
33
+
34
+ // src/chat/sidebar/ProjectsPane.tsx
35
+ import { useEffect as useEffect3 } from "react";
36
+ import { Box as Box3 } from "@mui/material";
37
+ import { useTheme as useTheme3 } from "@mui/material/styles";
38
+
39
+ // src/chat/sidebar/ProjectsIndexView.tsx
40
+ import { useMemo, useState } from "react";
41
+ import {
42
+ Box,
43
+ Button,
44
+ ButtonBase,
45
+ Dialog,
46
+ DialogActions,
47
+ DialogContent,
48
+ DialogTitle,
49
+ IconButton,
50
+ ListItemIcon,
51
+ ListItemText,
52
+ Menu,
53
+ MenuItem,
54
+ Typography,
55
+ alpha
56
+ } from "@mui/material";
57
+ import { useTheme } from "@mui/material/styles";
58
+ import { jsx, jsxs } from "react/jsx-runtime";
59
+ async function deleteProjectKeepingChats(projectId) {
60
+ const { conversations, moveConversationToProject } = useConversationStore.getState();
61
+ conversations.filter((c) => c.projectId === projectId).forEach((c) => moveConversationToProject(c.id, null));
62
+ await useProjectStore.getState().deleteProject(projectId);
63
+ }
64
+ var ProjectsIndexView = () => {
65
+ const theme = useTheme();
66
+ const projects = useProjectStore((state) => state.projects);
67
+ const hydrated = useProjectStore((state) => state._hasHydrated);
68
+ const conversations = useConversationStore((state) => state.conversations);
69
+ const openProject = useSidebarStore((state) => state.openProject);
70
+ const showChat = useSidebarStore((state) => state.showChat);
71
+ const [dialog, setDialog] = useState({
72
+ open: false,
73
+ project: null
74
+ });
75
+ const [menu, setMenu] = useState(
76
+ null
77
+ );
78
+ const [deleting, setDeleting] = useState(null);
79
+ const summaries = useMemo(
80
+ () => summarizeProjects(projects, listable(conversations)),
81
+ [projects, conversations]
82
+ );
83
+ const confirmDelete = async () => {
84
+ if (!deleting) return;
85
+ try {
86
+ await deleteProjectKeepingChats(deleting.id);
87
+ } catch (error) {
88
+ debugLogger.error("Failed to delete project", {
89
+ error: error instanceof Error ? error.message : String(error)
90
+ });
91
+ } finally {
92
+ setDeleting(null);
93
+ }
94
+ };
95
+ return /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", flexDirection: "column", gap: 2 }, children: [
96
+ /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
97
+ /* @__PURE__ */ jsx(IconButton, { "aria-label": "Back to chat", onClick: showChat, size: "small", children: /* @__PURE__ */ jsx(ArrowLeft, { size: 20 }) }),
98
+ /* @__PURE__ */ jsx(Typography, { component: "h1", variant: "h5", sx: { flex: 1, fontWeight: 600 }, children: "Projects" }),
99
+ /* @__PURE__ */ jsx(
100
+ Button,
101
+ {
102
+ variant: "contained",
103
+ size: "small",
104
+ startIcon: /* @__PURE__ */ jsx(Plus, { size: 16 }),
105
+ onClick: () => setDialog({ open: true, project: null }),
106
+ sx: { textTransform: "none", fontWeight: 600 },
107
+ children: "New project"
108
+ }
109
+ )
110
+ ] }),
111
+ hydrated && summaries.length === 0 && /* @__PURE__ */ jsx(
112
+ Box,
113
+ {
114
+ sx: {
115
+ p: 3,
116
+ border: `1px dashed ${theme.palette.divider}`,
117
+ borderRadius: 2,
118
+ color: theme.palette.text.secondary
119
+ },
120
+ children: /* @__PURE__ */ jsx(Typography, { variant: "body2", children: "No projects yet. A project keeps related chats together and gives every one of them the same standing instructions." })
121
+ }
122
+ ),
123
+ /* @__PURE__ */ jsx(
124
+ Box,
125
+ {
126
+ component: "ul",
127
+ "aria-label": "Projects",
128
+ sx: {
129
+ listStyle: "none",
130
+ m: 0,
131
+ p: 0,
132
+ display: "grid",
133
+ gap: 1.5,
134
+ gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))"
135
+ },
136
+ children: summaries.map(({ project, chatCount, activeAt }) => /* @__PURE__ */ jsxs(
137
+ Box,
138
+ {
139
+ component: "li",
140
+ sx: {
141
+ position: "relative",
142
+ border: `1px solid ${theme.palette.divider}`,
143
+ borderRadius: 2,
144
+ bgcolor: theme.palette.background.paper,
145
+ "&:hover": { borderColor: alpha(theme.palette.text.primary, 0.25) }
146
+ },
147
+ children: [
148
+ /* @__PURE__ */ jsxs(
149
+ ButtonBase,
150
+ {
151
+ onClick: () => openProject(project.id),
152
+ sx: {
153
+ width: "100%",
154
+ p: 2,
155
+ pr: 6,
156
+ display: "flex",
157
+ flexDirection: "column",
158
+ alignItems: "flex-start",
159
+ gap: 0.75,
160
+ textAlign: "left",
161
+ borderRadius: 2,
162
+ font: "inherit",
163
+ "&:focus-visible": {
164
+ outline: `2px solid ${theme.palette.primary.main}`,
165
+ outlineOffset: "2px"
166
+ }
167
+ },
168
+ children: [
169
+ /* @__PURE__ */ jsxs(
170
+ Box,
171
+ {
172
+ sx: {
173
+ display: "flex",
174
+ alignItems: "center",
175
+ gap: 1,
176
+ minWidth: 0,
177
+ width: "100%"
178
+ },
179
+ children: [
180
+ /* @__PURE__ */ jsx(
181
+ Box,
182
+ {
183
+ "aria-hidden": true,
184
+ sx: {
185
+ width: 10,
186
+ height: 10,
187
+ borderRadius: "50%",
188
+ bgcolor: project.color || theme.palette.text.disabled,
189
+ flexShrink: 0
190
+ }
191
+ }
192
+ ),
193
+ /* @__PURE__ */ jsx(Typography, { sx: { fontWeight: 600 }, noWrap: true, children: project.name })
194
+ ]
195
+ }
196
+ ),
197
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", sx: { color: theme.palette.text.secondary }, children: [
198
+ chatCount === 0 ? "No chats" : `${chatCount} ${chatCount === 1 ? "chat" : "chats"}`,
199
+ activeAt ? ` \xB7 ${formatRelative(activeAt)}` : ""
200
+ ] })
201
+ ]
202
+ }
203
+ ),
204
+ /* @__PURE__ */ jsx(
205
+ IconButton,
206
+ {
207
+ "aria-label": `Options for ${project.name}`,
208
+ "aria-haspopup": "menu",
209
+ size: "small",
210
+ onClick: (event) => setMenu({ anchor: event.currentTarget, project }),
211
+ sx: {
212
+ position: "absolute",
213
+ top: 10,
214
+ right: 10,
215
+ color: theme.palette.text.secondary
216
+ },
217
+ children: /* @__PURE__ */ jsx(MoreVertical, { size: 16 })
218
+ }
219
+ )
220
+ ]
221
+ },
222
+ project.id
223
+ ))
224
+ }
225
+ ),
226
+ /* @__PURE__ */ jsxs(
227
+ Menu,
228
+ {
229
+ anchorEl: menu?.anchor ?? null,
230
+ open: Boolean(menu),
231
+ onClose: () => setMenu(null),
232
+ anchorOrigin: { vertical: "bottom", horizontal: "right" },
233
+ transformOrigin: { vertical: "top", horizontal: "right" },
234
+ children: [
235
+ /* @__PURE__ */ jsxs(
236
+ MenuItem,
237
+ {
238
+ onClick: () => {
239
+ if (menu) setDialog({ open: true, project: menu.project });
240
+ setMenu(null);
241
+ },
242
+ children: [
243
+ /* @__PURE__ */ jsx(ListItemIcon, { children: /* @__PURE__ */ jsx(Edit, { size: 16 }) }),
244
+ /* @__PURE__ */ jsx(ListItemText, { children: "Edit name and colour" })
245
+ ]
246
+ }
247
+ ),
248
+ /* @__PURE__ */ jsxs(
249
+ MenuItem,
250
+ {
251
+ onClick: () => {
252
+ if (menu) setDeleting(menu.project);
253
+ setMenu(null);
254
+ },
255
+ sx: { color: theme.palette.error.main },
256
+ children: [
257
+ /* @__PURE__ */ jsx(ListItemIcon, { children: /* @__PURE__ */ jsx(Trash, { size: 16, color: theme.palette.error.main }) }),
258
+ /* @__PURE__ */ jsx(ListItemText, { children: "Delete project" })
259
+ ]
260
+ }
261
+ )
262
+ ]
263
+ }
264
+ ),
265
+ /* @__PURE__ */ jsx(
266
+ ProjectDialog,
267
+ {
268
+ open: dialog.open,
269
+ project: dialog.project,
270
+ onClose: () => setDialog({ open: false, project: null }),
271
+ onCreated: (project) => openProject(project.id)
272
+ }
273
+ ),
274
+ /* @__PURE__ */ jsxs(
275
+ Dialog,
276
+ {
277
+ open: Boolean(deleting),
278
+ onClose: () => setDeleting(null),
279
+ maxWidth: "xs",
280
+ fullWidth: true,
281
+ children: [
282
+ /* @__PURE__ */ jsxs(DialogTitle, { children: [
283
+ "Delete ",
284
+ deleting?.name,
285
+ "?"
286
+ ] }),
287
+ /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx(Typography, { children: "The project and its instructions are removed. Its chats are kept and move back to Recents." }) }),
288
+ /* @__PURE__ */ jsxs(DialogActions, { children: [
289
+ /* @__PURE__ */ jsx(Button, { onClick: () => setDeleting(null), children: "Cancel" }),
290
+ /* @__PURE__ */ jsx(Button, { onClick: () => void confirmDelete(), color: "error", variant: "contained", children: "Delete" })
291
+ ] })
292
+ ]
293
+ }
294
+ )
295
+ ] });
296
+ };
297
+
298
+ // src/chat/sidebar/ProjectView.tsx
299
+ import { useEffect as useEffect2, useMemo as useMemo3, useState as useState3 } from "react";
300
+ import {
301
+ Box as Box2,
302
+ Button as Button3,
303
+ Dialog as Dialog3,
304
+ DialogActions as DialogActions3,
305
+ DialogContent as DialogContent3,
306
+ DialogTitle as DialogTitle3,
307
+ IconButton as IconButton2,
308
+ ListItemIcon as ListItemIcon3,
309
+ ListItemText as ListItemText3,
310
+ Menu as Menu2,
311
+ MenuItem as MenuItem2,
312
+ Tab,
313
+ Tabs,
314
+ TextField,
315
+ Typography as Typography3
316
+ } from "@mui/material";
317
+ import { useTheme as useTheme2 } from "@mui/material/styles";
318
+
319
+ // src/chat/sidebar/AddChatsDialog.tsx
320
+ import { useEffect, useMemo as useMemo2, useState as useState2 } from "react";
321
+ import {
322
+ Button as Button2,
323
+ Checkbox,
324
+ Dialog as Dialog2,
325
+ DialogActions as DialogActions2,
326
+ DialogContent as DialogContent2,
327
+ DialogTitle as DialogTitle2,
328
+ List,
329
+ ListItem,
330
+ ListItemButton,
331
+ ListItemIcon as ListItemIcon2,
332
+ ListItemText as ListItemText2,
333
+ Typography as Typography2
334
+ } from "@mui/material";
335
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
336
+ var AddChatsDialog = ({
337
+ open,
338
+ onClose,
339
+ projectId,
340
+ projectName
341
+ }) => {
342
+ const { conversations, moveConversationToProject } = useConversationStore();
343
+ const [selected, setSelected] = useState2(/* @__PURE__ */ new Set());
344
+ const candidates = useMemo2(
345
+ () => listable(conversations).filter((c) => c.projectId !== projectId).sort((a, b) => lastActivity(b) - lastActivity(a)),
346
+ [conversations, projectId]
347
+ );
348
+ useEffect(() => {
349
+ if (open) setSelected(/* @__PURE__ */ new Set());
350
+ }, [open]);
351
+ const toggle = (id) => setSelected((previous) => {
352
+ const next = new Set(previous);
353
+ if (next.has(id)) next.delete(id);
354
+ else next.add(id);
355
+ return next;
356
+ });
357
+ const add = () => {
358
+ selected.forEach((id) => moveConversationToProject(id, projectId));
359
+ onClose();
360
+ };
361
+ return /* @__PURE__ */ jsxs2(Dialog2, { open, onClose, maxWidth: "xs", fullWidth: true, children: [
362
+ /* @__PURE__ */ jsxs2(DialogTitle2, { children: [
363
+ "Add chats to ",
364
+ projectName
365
+ ] }),
366
+ /* @__PURE__ */ jsx2(DialogContent2, { sx: { px: 1 }, children: candidates.length === 0 ? /* @__PURE__ */ jsx2(Typography2, { variant: "body2", color: "text.secondary", sx: { px: 2, py: 1 }, children: "Every chat is already in this project." }) : /* @__PURE__ */ jsx2(List, { dense: true, disablePadding: true, "aria-label": "Chats to add", children: candidates.map((conversation) => {
367
+ const checked = selected.has(conversation.id);
368
+ return /* @__PURE__ */ jsx2(ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxs2(
369
+ ListItemButton,
370
+ {
371
+ role: "checkbox",
372
+ "aria-checked": checked,
373
+ onClick: () => toggle(conversation.id),
374
+ dense: true,
375
+ children: [
376
+ /* @__PURE__ */ jsx2(ListItemIcon2, { sx: { minWidth: 36 }, children: /* @__PURE__ */ jsx2(
377
+ Checkbox,
378
+ {
379
+ edge: "start",
380
+ checked,
381
+ tabIndex: -1,
382
+ disableRipple: true
383
+ }
384
+ ) }),
385
+ /* @__PURE__ */ jsx2(
386
+ ListItemText2,
387
+ {
388
+ primary: conversation.name,
389
+ primaryTypographyProps: { noWrap: true }
390
+ }
391
+ )
392
+ ]
393
+ }
394
+ ) }, conversation.id);
395
+ }) }) }),
396
+ /* @__PURE__ */ jsxs2(DialogActions2, { children: [
397
+ /* @__PURE__ */ jsx2(Button2, { onClick: onClose, children: "Cancel" }),
398
+ /* @__PURE__ */ jsxs2(Button2, { variant: "contained", onClick: add, disabled: selected.size === 0, children: [
399
+ "Add ",
400
+ selected.size > 0 ? selected.size : ""
401
+ ] })
402
+ ] })
403
+ ] });
404
+ };
405
+
406
+ // src/chat/sidebar/ProjectView.tsx
407
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
408
+ var ProjectView = ({ projectId }) => {
409
+ const theme = useTheme2();
410
+ const safeNavigate = useSafeNavigate();
411
+ const project = useProjectStore(
412
+ (state) => state.projects.find((p) => p.id === projectId)
413
+ );
414
+ const hydrated = useProjectStore((state) => state._hasHydrated);
415
+ const updateProjectInstructions = useProjectStore(
416
+ (state) => state.updateProjectInstructions
417
+ );
418
+ const {
419
+ conversations,
420
+ currentId,
421
+ createNewConversation,
422
+ switchConversation,
423
+ deleteConversation,
424
+ renameConversation
425
+ } = useConversationStore();
426
+ const showChat = useSidebarStore((state) => state.showChat);
427
+ const showProjects = useSidebarStore((state) => state.showProjects);
428
+ const hostSections = useHostSections();
429
+ const stashSection = hostSections.find((section) => section.id === "stash");
430
+ const [tab, setTab] = useState3("chats");
431
+ const [menuAnchor, setMenuAnchor] = useState3(null);
432
+ const [editOpen, setEditOpen] = useState3(false);
433
+ const [addOpen, setAddOpen] = useState3(false);
434
+ const [deleteOpen, setDeleteOpen] = useState3(false);
435
+ const [moveTarget, setMoveTarget] = useState3(null);
436
+ const [draft, setDraft] = useState3("");
437
+ const [saved, setSaved] = useState3(false);
438
+ useEffect2(() => {
439
+ setDraft(project?.instructions ?? "");
440
+ setSaved(false);
441
+ }, [project?.id, project?.instructions]);
442
+ const chats = useMemo3(
443
+ () => listable(conversations).filter((c) => c.projectId === projectId).sort((a, b) => lastActivity(b) - lastActivity(a)),
444
+ [conversations, projectId]
445
+ );
446
+ if (!project) {
447
+ return /* @__PURE__ */ jsxs3(Box2, { sx: { display: "flex", flexDirection: "column", gap: 2 }, children: [
448
+ /* @__PURE__ */ jsxs3(Box2, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
449
+ /* @__PURE__ */ jsx3(IconButton2, { "aria-label": "Back to chat", onClick: showChat, size: "small", children: /* @__PURE__ */ jsx3(ArrowLeft, { size: 20 }) }),
450
+ /* @__PURE__ */ jsx3(Typography3, { component: "h1", variant: "h5", sx: { fontWeight: 600 }, children: "Project" })
451
+ ] }),
452
+ /* @__PURE__ */ jsx3(Typography3, { color: "text.secondary", children: hydrated ? "This project no longer exists." : "Loading\u2026" }),
453
+ hydrated && /* @__PURE__ */ jsx3(
454
+ Button3,
455
+ {
456
+ onClick: showProjects,
457
+ sx: { alignSelf: "flex-start", textTransform: "none" },
458
+ children: "All projects"
459
+ }
460
+ )
461
+ ] });
462
+ }
463
+ const instructionsChanged = draft.trim() !== (project.instructions ?? "").trim();
464
+ const saveInstructions = async () => {
465
+ try {
466
+ await updateProjectInstructions(project.id, draft);
467
+ setSaved(true);
468
+ } catch (error) {
469
+ debugLogger.error("Failed to save project instructions", {
470
+ error: error instanceof Error ? error.message : String(error)
471
+ });
472
+ }
473
+ };
474
+ const newChatHere = () => {
475
+ createNewConversation(project.id);
476
+ showChat();
477
+ };
478
+ const confirmDelete = async () => {
479
+ try {
480
+ await deleteProjectKeepingChats(project.id);
481
+ showProjects();
482
+ } catch (error) {
483
+ debugLogger.error("Failed to delete project", {
484
+ error: error instanceof Error ? error.message : String(error)
485
+ });
486
+ } finally {
487
+ setDeleteOpen(false);
488
+ }
489
+ };
490
+ const panelId = (name) => `bandit-project-panel-${name}`;
491
+ const tabId = (name) => `bandit-project-tab-${name}`;
492
+ return /* @__PURE__ */ jsxs3(Box2, { sx: { display: "flex", flexDirection: "column", gap: 2 }, children: [
493
+ /* @__PURE__ */ jsxs3(Box2, { sx: { display: "flex", alignItems: "center", gap: 1, minWidth: 0 }, children: [
494
+ /* @__PURE__ */ jsx3(IconButton2, { "aria-label": "Back to chat", onClick: showChat, size: "small", children: /* @__PURE__ */ jsx3(ArrowLeft, { size: 20 }) }),
495
+ /* @__PURE__ */ jsx3(
496
+ Box2,
497
+ {
498
+ "aria-hidden": true,
499
+ sx: {
500
+ width: 12,
501
+ height: 12,
502
+ borderRadius: "50%",
503
+ bgcolor: project.color || theme.palette.text.disabled,
504
+ flexShrink: 0
505
+ }
506
+ }
507
+ ),
508
+ /* @__PURE__ */ jsx3(
509
+ Typography3,
510
+ {
511
+ component: "h1",
512
+ variant: "h5",
513
+ sx: { flex: 1, minWidth: 0, fontWeight: 600 },
514
+ noWrap: true,
515
+ children: project.name
516
+ }
517
+ ),
518
+ /* @__PURE__ */ jsx3(
519
+ IconButton2,
520
+ {
521
+ "aria-label": "Project options",
522
+ "aria-haspopup": "menu",
523
+ "aria-expanded": Boolean(menuAnchor),
524
+ onClick: (event) => setMenuAnchor(event.currentTarget),
525
+ size: "small",
526
+ children: /* @__PURE__ */ jsx3(MoreVertical, { size: 18 })
527
+ }
528
+ )
529
+ ] }),
530
+ /* @__PURE__ */ jsxs3(
531
+ Tabs,
532
+ {
533
+ value: tab,
534
+ onChange: (_, value) => setTab(value),
535
+ variant: "scrollable",
536
+ allowScrollButtonsMobile: true,
537
+ "aria-label": "Project sections",
538
+ sx: { minHeight: 40, "& .MuiTab-root": { minHeight: 40, textTransform: "none" } },
539
+ children: [
540
+ /* @__PURE__ */ jsx3(
541
+ Tab,
542
+ {
543
+ value: "chats",
544
+ label: "Chats",
545
+ id: tabId("chats"),
546
+ "aria-controls": panelId("chats")
547
+ }
548
+ ),
549
+ /* @__PURE__ */ jsx3(
550
+ Tab,
551
+ {
552
+ value: "instructions",
553
+ label: "Instructions",
554
+ id: tabId("instructions"),
555
+ "aria-controls": panelId("instructions")
556
+ }
557
+ ),
558
+ /* @__PURE__ */ jsx3(
559
+ Tab,
560
+ {
561
+ value: "files",
562
+ label: "Files",
563
+ id: tabId("files"),
564
+ "aria-controls": panelId("files")
565
+ }
566
+ ),
567
+ stashSection && /* @__PURE__ */ jsx3(
568
+ Tab,
569
+ {
570
+ value: "stash",
571
+ label: "Stash",
572
+ id: tabId("stash"),
573
+ "aria-controls": panelId("stash")
574
+ }
575
+ )
576
+ ]
577
+ }
578
+ ),
579
+ tab === "chats" && /* @__PURE__ */ jsxs3(
580
+ Box2,
581
+ {
582
+ role: "tabpanel",
583
+ id: panelId("chats"),
584
+ "aria-labelledby": tabId("chats"),
585
+ sx: { display: "flex", flexDirection: "column", gap: 1.5 },
586
+ children: [
587
+ /* @__PURE__ */ jsxs3(Box2, { sx: { display: "flex", gap: 1, flexWrap: "wrap" }, children: [
588
+ /* @__PURE__ */ jsxs3(
589
+ Button3,
590
+ {
591
+ variant: "contained",
592
+ size: "small",
593
+ startIcon: /* @__PURE__ */ jsx3(MessageSquarePlus, { size: 16 }),
594
+ onClick: newChatHere,
595
+ sx: { textTransform: "none", fontWeight: 600 },
596
+ children: [
597
+ "New chat in ",
598
+ project.name
599
+ ]
600
+ }
601
+ ),
602
+ /* @__PURE__ */ jsx3(
603
+ Button3,
604
+ {
605
+ variant: "outlined",
606
+ size: "small",
607
+ startIcon: /* @__PURE__ */ jsx3(Plus, { size: 16 }),
608
+ onClick: () => setAddOpen(true),
609
+ sx: { textTransform: "none", fontWeight: 600 },
610
+ children: "Add existing chats"
611
+ }
612
+ )
613
+ ] }),
614
+ chats.length === 0 ? /* @__PURE__ */ jsx3(Typography3, { variant: "body2", color: "text.secondary", children: "No chats in this project yet." }) : /* @__PURE__ */ jsx3(Box2, { sx: { mx: -1 }, children: chats.map((conversation) => /* @__PURE__ */ jsx3(
615
+ simple_conversation_item_default,
616
+ {
617
+ conversation,
618
+ isSelected: conversation.id === currentId,
619
+ onSelect: () => {
620
+ switchConversation(conversation.id);
621
+ showChat();
622
+ },
623
+ onDelete: () => deleteConversation(conversation.id),
624
+ onRename: (name) => renameConversation(conversation.id, name),
625
+ onMove: () => setMoveTarget(conversation),
626
+ projectColor: project.color,
627
+ dense: true
628
+ },
629
+ conversation.id
630
+ )) })
631
+ ]
632
+ }
633
+ ),
634
+ tab === "instructions" && /* @__PURE__ */ jsxs3(
635
+ Box2,
636
+ {
637
+ role: "tabpanel",
638
+ id: panelId("instructions"),
639
+ "aria-labelledby": tabId("instructions"),
640
+ sx: { display: "flex", flexDirection: "column", gap: 1.5 },
641
+ children: [
642
+ /* @__PURE__ */ jsx3(
643
+ TextField,
644
+ {
645
+ multiline: true,
646
+ minRows: 8,
647
+ fullWidth: true,
648
+ label: "Instructions",
649
+ value: draft,
650
+ onChange: (event) => {
651
+ setDraft(event.target.value);
652
+ setSaved(false);
653
+ },
654
+ helperText: "Added to every chat in this project, ahead of the persona."
655
+ }
656
+ ),
657
+ /* @__PURE__ */ jsxs3(Box2, { sx: { display: "flex", alignItems: "center", gap: 1.5 }, children: [
658
+ /* @__PURE__ */ jsx3(
659
+ Button3,
660
+ {
661
+ variant: "contained",
662
+ size: "small",
663
+ disabled: !instructionsChanged,
664
+ onClick: () => void saveInstructions(),
665
+ sx: { textTransform: "none", fontWeight: 600 },
666
+ children: "Save"
667
+ }
668
+ ),
669
+ saved && !instructionsChanged && /* @__PURE__ */ jsx3(Typography3, { variant: "caption", color: "text.secondary", role: "status", children: "Saved" })
670
+ ] })
671
+ ]
672
+ }
673
+ ),
674
+ tab === "files" && /* @__PURE__ */ jsxs3(
675
+ Box2,
676
+ {
677
+ role: "tabpanel",
678
+ id: panelId("files"),
679
+ "aria-labelledby": tabId("files"),
680
+ sx: { display: "flex", flexDirection: "column", gap: 1.5 },
681
+ children: [
682
+ /* @__PURE__ */ jsx3(Typography3, { variant: "body2", color: "text.secondary", children: "Files are not kept per project yet. Documents added under Knowledge in Settings are available in every chat, including the chats in this project." }),
683
+ /* @__PURE__ */ jsx3(
684
+ Button3,
685
+ {
686
+ variant: "outlined",
687
+ size: "small",
688
+ onClick: () => safeNavigate(managementPathFor(window.location.pathname)),
689
+ sx: { alignSelf: "flex-start", textTransform: "none", fontWeight: 600 },
690
+ children: "Open Knowledge"
691
+ }
692
+ )
693
+ ]
694
+ }
695
+ ),
696
+ tab === "stash" && stashSection && /* @__PURE__ */ jsxs3(
697
+ Box2,
698
+ {
699
+ role: "tabpanel",
700
+ id: panelId("stash"),
701
+ "aria-labelledby": tabId("stash"),
702
+ sx: { display: "flex", flexDirection: "column", gap: 1.5 },
703
+ children: [
704
+ /* @__PURE__ */ jsx3(Typography3, { variant: "body2", color: "text.secondary", children: "Stash items are not grouped by project yet. Your Stash holds everything you have saved across Bandit." }),
705
+ /* @__PURE__ */ jsx3(
706
+ Button3,
707
+ {
708
+ component: "a",
709
+ href: stashSection.href,
710
+ variant: "outlined",
711
+ size: "small",
712
+ endIcon: stashSection.external ? /* @__PURE__ */ jsx3(ExternalLink, { size: 14 }) : void 0,
713
+ onClick: stashSection.onSelect,
714
+ sx: { alignSelf: "flex-start", textTransform: "none", fontWeight: 600 },
715
+ children: "Open Stash"
716
+ }
717
+ )
718
+ ]
719
+ }
720
+ ),
721
+ /* @__PURE__ */ jsxs3(
722
+ Menu2,
723
+ {
724
+ anchorEl: menuAnchor,
725
+ open: Boolean(menuAnchor),
726
+ onClose: () => setMenuAnchor(null),
727
+ anchorOrigin: { vertical: "bottom", horizontal: "right" },
728
+ transformOrigin: { vertical: "top", horizontal: "right" },
729
+ children: [
730
+ /* @__PURE__ */ jsxs3(
731
+ MenuItem2,
732
+ {
733
+ onClick: () => {
734
+ setMenuAnchor(null);
735
+ setEditOpen(true);
736
+ },
737
+ children: [
738
+ /* @__PURE__ */ jsx3(ListItemIcon3, { children: /* @__PURE__ */ jsx3(Edit, { size: 16 }) }),
739
+ /* @__PURE__ */ jsx3(ListItemText3, { children: "Edit name and colour" })
740
+ ]
741
+ }
742
+ ),
743
+ /* @__PURE__ */ jsxs3(
744
+ MenuItem2,
745
+ {
746
+ onClick: () => {
747
+ setMenuAnchor(null);
748
+ setDeleteOpen(true);
749
+ },
750
+ sx: { color: theme.palette.error.main },
751
+ children: [
752
+ /* @__PURE__ */ jsx3(ListItemIcon3, { children: /* @__PURE__ */ jsx3(Trash, { size: 16, color: theme.palette.error.main }) }),
753
+ /* @__PURE__ */ jsx3(ListItemText3, { children: "Delete project" })
754
+ ]
755
+ }
756
+ )
757
+ ]
758
+ }
759
+ ),
760
+ /* @__PURE__ */ jsx3(
761
+ ProjectDialog,
762
+ {
763
+ open: editOpen,
764
+ project,
765
+ onClose: () => setEditOpen(false)
766
+ }
767
+ ),
768
+ /* @__PURE__ */ jsx3(
769
+ AddChatsDialog,
770
+ {
771
+ open: addOpen,
772
+ onClose: () => setAddOpen(false),
773
+ projectId: project.id,
774
+ projectName: project.name
775
+ }
776
+ ),
777
+ moveTarget && /* @__PURE__ */ jsx3(
778
+ move_conversation_modal_default,
779
+ {
780
+ open: true,
781
+ onClose: () => setMoveTarget(null),
782
+ conversations: [moveTarget],
783
+ currentProjectId: moveTarget.projectId
784
+ }
785
+ ),
786
+ /* @__PURE__ */ jsxs3(
787
+ Dialog3,
788
+ {
789
+ open: deleteOpen,
790
+ onClose: () => setDeleteOpen(false),
791
+ maxWidth: "xs",
792
+ fullWidth: true,
793
+ children: [
794
+ /* @__PURE__ */ jsxs3(DialogTitle3, { children: [
795
+ "Delete ",
796
+ project.name,
797
+ "?"
798
+ ] }),
799
+ /* @__PURE__ */ jsx3(DialogContent3, { children: /* @__PURE__ */ jsxs3(Typography3, { children: [
800
+ "The project and its instructions are removed. Its ",
801
+ chats.length,
802
+ " ",
803
+ chats.length === 1 ? "chat is" : "chats are",
804
+ " kept and move back to Recents."
805
+ ] }) }),
806
+ /* @__PURE__ */ jsxs3(DialogActions3, { children: [
807
+ /* @__PURE__ */ jsx3(Button3, { onClick: () => setDeleteOpen(false), children: "Cancel" }),
808
+ /* @__PURE__ */ jsx3(Button3, { onClick: () => void confirmDelete(), color: "error", variant: "contained", children: "Delete" })
809
+ ] })
810
+ ]
811
+ }
812
+ )
813
+ ] });
814
+ };
815
+
816
+ // src/chat/sidebar/ProjectsPane.tsx
817
+ import { jsx as jsx4 } from "react/jsx-runtime";
818
+ var CHAT_APP_BAR_HEIGHT = 64;
819
+ var ProjectsPane = ({ isMobile }) => {
820
+ const theme = useTheme3();
821
+ const view = useSidebarStore((state) => state.view);
822
+ const hydrated = useProjectStore((state) => state._hasHydrated);
823
+ const hydrate = useProjectStore((state) => state.hydrate);
824
+ useEffect3(() => {
825
+ if (view.kind !== "chat" && !hydrated) void hydrate();
826
+ }, [view.kind, hydrated, hydrate]);
827
+ if (view.kind === "chat") return null;
828
+ return /* @__PURE__ */ jsx4(
829
+ Box3,
830
+ {
831
+ role: "region",
832
+ "aria-label": view.kind === "projects" ? "Projects" : "Project",
833
+ "data-bandit-projects-pane": view.kind,
834
+ sx: {
835
+ position: "absolute",
836
+ inset: 0,
837
+ zIndex: 1250,
838
+ display: "flex",
839
+ flexDirection: "column",
840
+ bgcolor: chatTokens(theme).surface.base,
841
+ color: theme.palette.text.primary,
842
+ pt: `calc(${CHAT_APP_BAR_HEIGHT}px + env(safe-area-inset-top, 0px))`,
843
+ overflow: "hidden"
844
+ },
845
+ children: /* @__PURE__ */ jsx4(
846
+ Box3,
847
+ {
848
+ sx: {
849
+ flex: 1,
850
+ minHeight: 0,
851
+ overflowY: "auto",
852
+ overscrollBehavior: "contain",
853
+ px: isMobile ? 2 : 4,
854
+ pb: `calc(${theme.spacing(4)} + env(safe-area-inset-bottom, 0px))`
855
+ },
856
+ children: /* @__PURE__ */ jsx4(Box3, { sx: { maxWidth: 768, mx: "auto" }, children: view.kind === "projects" ? /* @__PURE__ */ jsx4(ProjectsIndexView, {}) : /* @__PURE__ */ jsx4(ProjectView, { projectId: view.projectId }, view.projectId) })
857
+ }
858
+ )
859
+ }
860
+ );
861
+ };
862
+ export {
863
+ CHAT_APP_BAR_HEIGHT,
864
+ ProjectsPane
865
+ };
866
+ //# sourceMappingURL=ProjectsPane-BSVOVNK7.mjs.map