@burtson-labs/bandit-engine 2.0.152 → 2.0.153

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 (47) hide show
  1. package/dist/chat-4UZ5QT7B.mjs +16 -0
  2. package/dist/chat-provider.js +6 -30
  3. package/dist/chat-provider.js.map +1 -1
  4. package/dist/chat-provider.mjs +5 -5
  5. package/dist/{chunk-6STVJJSG.mjs → chunk-2HGBMNX4.mjs} +17 -3
  6. package/dist/chunk-2HGBMNX4.mjs.map +1 -0
  7. package/dist/{chunk-CVFFNX7H.mjs → chunk-6KOEXQJN.mjs} +8 -32
  8. package/dist/chunk-6KOEXQJN.mjs.map +1 -0
  9. package/dist/{chunk-7ESJJN6D.mjs → chunk-6NYYYKYZ.mjs} +262 -75
  10. package/dist/chunk-6NYYYKYZ.mjs.map +1 -0
  11. package/dist/{chunk-QLATFSSO.mjs → chunk-AJL3JOD6.mjs} +5 -5
  12. package/dist/{chunk-RRCCSN3N.mjs → chunk-B2TJZM4Z.mjs} +2 -2
  13. package/dist/{chunk-LPSM62OE.mjs → chunk-DADHPWB7.mjs} +19 -14
  14. package/dist/chunk-DADHPWB7.mjs.map +1 -0
  15. package/dist/{chunk-U33KBX3Y.mjs → chunk-GQ3X6VPR.mjs} +4 -4
  16. package/dist/{chunk-TYRYAAP2.mjs → chunk-RN7FRSMX.mjs} +3 -3
  17. package/dist/{chunk-EORIRPPX.mjs → chunk-ZOCXFQID.mjs} +2 -2
  18. package/dist/{chunk-EORIRPPX.mjs.map → chunk-ZOCXFQID.mjs.map} +1 -1
  19. package/dist/{chunk-VLUXQE24.mjs → chunk-ZW3YNAD7.mjs} +2 -2
  20. package/dist/index.d.mts +2 -2
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.js +788 -591
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.mjs +10 -10
  25. package/dist/management/management.js +487 -290
  26. package/dist/management/management.js.map +1 -1
  27. package/dist/management/management.mjs +8 -8
  28. package/dist/modals/chat-modal/chat-modal.js.map +1 -1
  29. package/dist/modals/chat-modal/chat-modal.mjs +4 -4
  30. package/dist/{modelStore-U57LUIIB.mjs → modelStore-KBUW3XAV.mjs} +2 -2
  31. package/dist/{public-20My32EB.d.mts → public-0EYmtpGD.d.mts} +8 -0
  32. package/dist/{public-20My32EB.d.ts → public-0EYmtpGD.d.ts} +8 -0
  33. package/dist/public-types.d.mts +1 -1
  34. package/dist/public-types.d.ts +1 -1
  35. package/package.json +1 -1
  36. package/dist/chat-Y3WOTIKI.mjs +0 -16
  37. package/dist/chunk-6STVJJSG.mjs.map +0 -1
  38. package/dist/chunk-7ESJJN6D.mjs.map +0 -1
  39. package/dist/chunk-CVFFNX7H.mjs.map +0 -1
  40. package/dist/chunk-LPSM62OE.mjs.map +0 -1
  41. /package/dist/{chat-Y3WOTIKI.mjs.map → chat-4UZ5QT7B.mjs.map} +0 -0
  42. /package/dist/{chunk-QLATFSSO.mjs.map → chunk-AJL3JOD6.mjs.map} +0 -0
  43. /package/dist/{chunk-RRCCSN3N.mjs.map → chunk-B2TJZM4Z.mjs.map} +0 -0
  44. /package/dist/{chunk-U33KBX3Y.mjs.map → chunk-GQ3X6VPR.mjs.map} +0 -0
  45. /package/dist/{chunk-TYRYAAP2.mjs.map → chunk-RN7FRSMX.mjs.map} +0 -0
  46. /package/dist/{chunk-VLUXQE24.mjs.map → chunk-ZW3YNAD7.mjs.map} +0 -0
  47. /package/dist/{modelStore-U57LUIIB.mjs.map → modelStore-KBUW3XAV.mjs.map} +0 -0
@@ -2,11 +2,13 @@ import {
2
2
  styleInject
3
3
  } from "./chunk-ONQMRE2G.mjs";
4
4
  import {
5
- StreamingMarkdown_default
6
- } from "./chunk-6STVJJSG.mjs";
5
+ StreamingMarkdown_default,
6
+ isNativeShell,
7
+ isStandalonePwa
8
+ } from "./chunk-2HGBMNX4.mjs";
7
9
  import {
8
10
  useMCPToolsStore
9
- } from "./chunk-CVFFNX7H.mjs";
11
+ } from "./chunk-6KOEXQJN.mjs";
10
12
  import {
11
13
  AddIcon,
12
14
  ArrowDownwardIcon,
@@ -36,7 +38,7 @@ import {
36
38
  useNotificationService,
37
39
  useTTS,
38
40
  useVoiceStore
39
- } from "./chunk-TYRYAAP2.mjs";
41
+ } from "./chunk-RN7FRSMX.mjs";
40
42
  import {
41
43
  brandingService_default,
42
44
  detectMessageMood,
@@ -59,13 +61,13 @@ import {
59
61
  useMemoryStore,
60
62
  useProjectStore,
61
63
  useVectorStore
62
- } from "./chunk-VLUXQE24.mjs";
64
+ } from "./chunk-ZW3YNAD7.mjs";
63
65
  import {
64
66
  indexedDBService_default,
65
67
  useModelStore,
66
68
  usePackageSettingsStore,
67
69
  usePreferencesStore
68
- } from "./chunk-EORIRPPX.mjs";
70
+ } from "./chunk-ZOCXFQID.mjs";
69
71
  import {
70
72
  authenticationService as authenticationService2,
71
73
  readPersistedToken,
@@ -77,7 +79,7 @@ import {
77
79
  } from "./chunk-KCI46M23.mjs";
78
80
 
79
81
  // src/chat/chat.tsx
80
- import { useCallback as useCallback6, useEffect as useEffect17, useLayoutEffect, useMemo as useMemo4, useRef as useRef15, useState as useState19 } from "react";
82
+ import { useCallback as useCallback6, useEffect as useEffect17, useLayoutEffect, useMemo as useMemo4, useRef as useRef16, useState as useState19 } from "react";
81
83
 
82
84
  // src/chat/custom-logo.tsx
83
85
  import React, { useEffect } from "react";
@@ -164,7 +166,7 @@ var Logo = ({ visible, atTop = false }) => {
164
166
  var custom_logo_default = Logo;
165
167
 
166
168
  // src/chat/chat.tsx
167
- import { Box as Box20, ThemeProvider, CssBaseline, CircularProgress as CircularProgress4, Typography as Typography15 } from "@mui/material";
169
+ import { Box as Box20, ThemeProvider, CssBaseline, CircularProgress as CircularProgress4, Typography as Typography15, Button as Button10, IconButton as IconButton14 } from "@mui/material";
168
170
  import { createTheme } from "@mui/material/styles";
169
171
 
170
172
  // src/chat/canvas-panel.tsx
@@ -978,6 +980,7 @@ var EnginePickerPill = () => {
978
980
  const tier = String(getCurrentTier());
979
981
  return tier !== "trial" && tier !== "expired" && tier !== "free" && tier !== "basic";
980
982
  })();
983
+ const hideUpgradePrompts = usePackageSettingsStore((s) => s.settings?.hideUpgradePrompts === true);
981
984
  const plansPath = typeof window !== "undefined" && !(window.location.hostname === "banditailabs.com" || window.location.hostname.endsWith(".banditailabs.com") || window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1") ? "https://banditailabs.com/plans" : "/plans";
982
985
  if (engines.length === 0) return null;
983
986
  return /* @__PURE__ */ jsxs4(Fragment3, { children: [
@@ -1056,8 +1059,8 @@ var EnginePickerPill = () => {
1056
1059
  ),
1057
1060
  engine.id === resolvedEngineId && !isGated && /* @__PURE__ */ jsx7(Box5, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: theme.palette.primary.main } })
1058
1061
  ] }),
1059
- /* @__PURE__ */ jsx7(Typography2, { variant: "caption", sx: { color: theme.palette.text.secondary }, children: isGated ? "Premium engine \u2014 available on a paid plan." : engine.available ? engine.description : engine.unavailableReason || "Unavailable" }),
1060
- isGated && /* @__PURE__ */ jsx7(
1062
+ /* @__PURE__ */ jsx7(Typography2, { variant: "caption", sx: { color: theme.palette.text.secondary }, children: isGated ? hideUpgradePrompts ? "Not available on your current plan." : "Premium engine \u2014 available on a paid plan." : engine.available ? engine.description : engine.unavailableReason || "Unavailable" }),
1063
+ isGated && !hideUpgradePrompts && /* @__PURE__ */ jsx7(
1061
1064
  Button,
1062
1065
  {
1063
1066
  size: "small",
@@ -2349,6 +2352,7 @@ var RateLimitPrompt = () => {
2349
2352
  const theme = useTheme8();
2350
2353
  const prompt = useRateLimitStore((s) => s.prompt);
2351
2354
  const dismiss = useRateLimitStore((s) => s.dismiss);
2355
+ const hideUpgradePrompts = usePackageSettingsStore((s) => s.settings?.hideUpgradePrompts === true);
2352
2356
  const hasLoggedRouterWarningRef = useRef3(false);
2353
2357
  let navigate = null;
2354
2358
  try {
@@ -2378,6 +2382,12 @@ var RateLimitPrompt = () => {
2378
2382
  const { scope, frontier } = prompt;
2379
2383
  const title = scope === "weekly" ? "You've reached your weekly limit" : "You've hit your session limit";
2380
2384
  const body = (() => {
2385
+ if (hideUpgradePrompts) {
2386
+ if (frontier) {
2387
+ return scope === "weekly" ? "You've used your weekly allowance on premium engines. It resets with your weekly cycle." : "You've hit your session limit on premium engines. It resets soon.";
2388
+ }
2389
+ return scope === "weekly" ? "Your weekly chat allowance is used up. It resets with your weekly cycle." : "It resets shortly \u2014 check back in a bit.";
2390
+ }
2381
2391
  if (frontier) {
2382
2392
  return scope === "weekly" ? "You've used your weekly allowance on premium engines. Upgrade to keep chatting on the most capable models." : "You've hit your session limit on premium engines. It resets soon \u2014 or upgrade for higher limits and uninterrupted access.";
2383
2393
  }
@@ -2422,7 +2432,7 @@ var RateLimitPrompt = () => {
2422
2432
  /* @__PURE__ */ jsx11(Typography5, { variant: "subtitle2", sx: { fontWeight: 600, color: theme.palette.text.primary }, children: title }),
2423
2433
  /* @__PURE__ */ jsx11(Typography5, { variant: "body2", sx: { color: theme.palette.text.secondary, mt: 0.25 }, children: body }),
2424
2434
  /* @__PURE__ */ jsxs8(Box8, { sx: { display: "flex", gap: 1, mt: 1, flexWrap: "wrap" }, children: [
2425
- /* @__PURE__ */ jsx11(
2435
+ !hideUpgradePrompts && /* @__PURE__ */ jsx11(
2426
2436
  Button3,
2427
2437
  {
2428
2438
  size: "small",
@@ -4215,7 +4225,6 @@ TOOL USAGE PROTOCOL (conservative approach)
4215
4225
  - Only call tools for SPECIFIC, CURRENT information that requires real-time data or a source you don't already have:
4216
4226
  * web_search() - when asked about recent/current events, breaking news, live information (weather, prices, sports scores), or when you need to look up documentation, libraries, APIs, error messages, or verify a specific fact
4217
4227
  * web_fetch() - to read the FULL contents of a specific URL you already have. Reach for this when the user wants to "tell me more", "go deeper", "read/open that article", or asks for details about a specific source, link, or article from an EARLIER answer: take that item's URL from the previous Sources list in this conversation and fetch it, then answer from the page's actual content (not just the prior summary)
4218
- * image_generation() - ONLY when explicitly asked to create or generate an image
4219
4228
  * create_file({"content": "...", "filename": "report.docx", "format": "docx"}) - when the user asks for a downloadable FILE (a document, spreadsheet, slides, markdown, code, etc.) or to "export"/"download"/"save" something. Formats: md, txt, csv, json, html, xml, yaml, docx, pptx. PDF is NOT a supported format \u2014 if the user asks for a PDF, create a docx instead. For docx/pptx write well-structured Markdown (use "## " headings to start each slide for pptx). It returns a temporary download link \u2014 ALWAYS tell the user the file expires (~1 hour). If it is unclear whether they want it shown inline vs. as a downloadable file, use ask_user first.
4220
4229
  * ask_user({"questions": [{"question": "...", "header": "Format", "options": [{"label": "Inline (Recommended)"}, {"label": "Download a file"}]}]}) - when the request is AMBIGUOUS or missing a detail you need to do a good job (unclear scope, audience, format, tone, which of several interpretations they meant), or you are blocked on a decision that is the user's to make and cannot resolve from the request, context, or sensible defaults. Renders clickable options the user answers in one step \u2014 ALWAYS prefer this over asking a clarifying question in prose and ending your turn. Give 1-4 questions, each with 2-4 short options; if one is clearly best, list it first and append " (Recommended)". The user may also type their own answer; act on it directly. Don't overuse it \u2014 when a sensible default exists, take it and note the assumption instead.
4221
4230
  - For general questions about concepts, definitions, explanations, or how-to topics, use your built-in knowledge WITHOUT calling tools.
@@ -5296,7 +5305,7 @@ var useNetworkStatus = () => {
5296
5305
 
5297
5306
  // src/chat/chat-app-bar.tsx
5298
5307
  import { Avatar as Avatar8 } from "@mui/material";
5299
- import { useEffect as useEffect13, useRef as useRef11, useState as useState16 } from "react";
5308
+ import { useEffect as useEffect13, useRef as useRef12, useState as useState16 } from "react";
5300
5309
  import {
5301
5310
  Box as Box15,
5302
5311
  IconButton as IconButton12,
@@ -5310,10 +5319,10 @@ import {
5310
5319
  Typography as Typography12,
5311
5320
  Button as Button9
5312
5321
  } from "@mui/material";
5313
- import { useNavigate as useNavigate2 } from "react-router-dom";
5322
+ import { useNavigate as useNavigate3 } from "react-router-dom";
5314
5323
 
5315
5324
  // src/chat/conversation-drawer.tsx
5316
- import { useState as useState14, useMemo as useMemo2, useEffect as useEffect11, useRef as useRef9, useCallback as useCallback4 } from "react";
5325
+ import { useState as useState14, useMemo as useMemo2, useEffect as useEffect11, useRef as useRef10, useCallback as useCallback4 } from "react";
5317
5326
  import {
5318
5327
  Drawer,
5319
5328
  Box as Box13,
@@ -5340,8 +5349,38 @@ import {
5340
5349
  import { X as CloseIcon6, X as ClearIcon, Search as SearchIcon, Folder as FolderIcon4, MoreVertical as MoreVertIcon3, Trash2 as DeleteSweepIcon, Inbox as InboxIcon3, Plus as AddIcon4, Settings as SettingsIcon, Brain as MemoryIcon, LogOut as LogOutIcon, House as HomeLucideIcon, RefreshCw as SyncLucideIcon, CircleAlert as SyncErrorIcon, SlidersHorizontal as ManagementIcon, MessageSquare as FeedbackMenuIcon } from "lucide-react";
5341
5350
  import { useTheme as useTheme13 } from "@mui/material/styles";
5342
5351
 
5352
+ // src/hooks/useSafeNavigate.ts
5353
+ import { useRef as useRef6 } from "react";
5354
+ import { useNavigate as useNavigate2 } from "react-router-dom";
5355
+ var useSafeNavigate = () => {
5356
+ const warned = useRef6(false);
5357
+ let navigate = null;
5358
+ try {
5359
+ navigate = useNavigate2();
5360
+ } catch (error) {
5361
+ if (!warned.current) {
5362
+ debugLogger.warn("useSafeNavigate: no Router context; falling back to location", { error });
5363
+ warned.current = true;
5364
+ }
5365
+ navigate = null;
5366
+ }
5367
+ return (to) => {
5368
+ if (typeof window !== "undefined" && /^[a-z]+:\/\//i.test(to)) {
5369
+ window.location.href = to;
5370
+ return;
5371
+ }
5372
+ if (navigate) {
5373
+ navigate(to);
5374
+ return;
5375
+ }
5376
+ if (typeof window !== "undefined") {
5377
+ window.location.href = to;
5378
+ }
5379
+ };
5380
+ };
5381
+
5343
5382
  // src/chat/project-management-modal.tsx
5344
- import { useState as useState10, useEffect as useEffect8, useRef as useRef6 } from "react";
5383
+ import { useState as useState10, useEffect as useEffect8, useRef as useRef7 } from "react";
5345
5384
  import {
5346
5385
  Modal,
5347
5386
  Button as Button4,
@@ -5404,7 +5443,7 @@ var ProjectManagementModal = ({
5404
5443
  const [selectedProject, setSelectedProject] = useState10(null);
5405
5444
  const [loading, setLoading] = useState10(false);
5406
5445
  const [error, setError] = useState10(null);
5407
- const modalContainerRef = useRef6(null);
5446
+ const modalContainerRef = useRef7(null);
5408
5447
  useEffect8(() => {
5409
5448
  if (open && !_hasHydrated) {
5410
5449
  hydrate();
@@ -6121,7 +6160,7 @@ var MoveConversationModal = ({
6121
6160
  var move_conversation_modal_default = MoveConversationModal;
6122
6161
 
6123
6162
  // src/chat/simple-conversation-item.tsx
6124
- import { useState as useState12, useRef as useRef7, useEffect as useEffect10 } from "react";
6163
+ import { useState as useState12, useRef as useRef8, useEffect as useEffect10 } from "react";
6125
6164
  import {
6126
6165
  Box as Box11,
6127
6166
  Typography as Typography8,
@@ -6164,10 +6203,10 @@ var SimpleConversationItem = ({
6164
6203
  const [isDragging, setIsDragging] = useState12(false);
6165
6204
  const [isTouchDragging, setIsTouchDragging] = useState12(false);
6166
6205
  const [showRenameDialog, setShowRenameDialog] = useState12(false);
6167
- const longPressTimeoutRef = useRef7(null);
6168
- const touchStartPointRef = useRef7(null);
6169
- const activeTouchIdRef = useRef7(null);
6170
- const suppressClickRef = useRef7(false);
6206
+ const longPressTimeoutRef = useRef8(null);
6207
+ const touchStartPointRef = useRef8(null);
6208
+ const activeTouchIdRef = useRef8(null);
6209
+ const suppressClickRef = useRef8(false);
6171
6210
  const highlightText = (text, query) => {
6172
6211
  if (!query || !query.trim()) {
6173
6212
  return text;
@@ -6570,7 +6609,7 @@ var SimpleConversationItem = ({
6570
6609
  var simple_conversation_item_default = SimpleConversationItem;
6571
6610
 
6572
6611
  // src/chat/project-header.tsx
6573
- import { useRef as useRef8, useState as useState13 } from "react";
6612
+ import { useRef as useRef9, useState as useState13 } from "react";
6574
6613
  import {
6575
6614
  Box as Box12,
6576
6615
  Typography as Typography9,
@@ -6603,7 +6642,7 @@ var ProjectHeader = ({
6603
6642
  const [isHovered, setIsHovered] = useState13(false);
6604
6643
  const [isDragOver, setIsDragOver] = useState13(false);
6605
6644
  const [renameDraft, setRenameDraft] = useState13(projectName);
6606
- const renameActionRef = useRef8("none");
6645
+ const renameActionRef = useRef9("none");
6607
6646
  const isUngrouped = projectId === null;
6608
6647
  const Icon = isCollapsed ? FolderIcon3 : FolderOpenIcon;
6609
6648
  const handleAddConversation = (e) => {
@@ -6923,7 +6962,7 @@ var ConversationDrawer = ({ open, onClose }) => {
6923
6962
  const [projectManagementOpen, setProjectManagementOpen] = useState14(false);
6924
6963
  const [memoryModalOpen, setMemoryModalOpen] = useState14(false);
6925
6964
  const [collapsedProjects, setCollapsedProjects] = useState14(/* @__PURE__ */ new Set());
6926
- const didInitCollapseRef = useRef9(false);
6965
+ const didInitCollapseRef = useRef10(false);
6927
6966
  const [searchQuery, setSearchQuery] = useState14("");
6928
6967
  const [menuAnchorEl, setMenuAnchorEl] = useState14(null);
6929
6968
  const [clearConfirmOpen, setClearConfirmOpen] = useState14(false);
@@ -7101,15 +7140,18 @@ var ConversationDrawer = ({ open, onClose }) => {
7101
7140
  const syncEnabled = useConversationSyncStore((s) => s.syncEnabled);
7102
7141
  const syncStatus = useConversationSyncStore((s) => s.status);
7103
7142
  const runSync = useConversationSyncStore((s) => s.runSync);
7143
+ const safeNavigate = useSafeNavigate();
7104
7144
  const goToHome = () => {
7105
7145
  const resolvedHomeUrl = preferences.homeUrl?.trim() || usePackageSettingsStore.getState().settings?.homeUrl?.trim() || "";
7106
7146
  if (resolvedHomeUrl) {
7107
7147
  window.location.href = resolvedHomeUrl;
7108
7148
  return;
7109
7149
  }
7110
- const navigatorWithStandalone = window.navigator;
7111
- const isStandalone = window.matchMedia?.("(display-mode: standalone)").matches || navigatorWithStandalone.standalone === true;
7112
- if (isStandalone) {
7150
+ if (isNativeShell()) {
7151
+ safeNavigate("/chat");
7152
+ return;
7153
+ }
7154
+ if (isStandalonePwa()) {
7113
7155
  try {
7114
7156
  sessionStorage.setItem("banditPwaStayOnHome", "true");
7115
7157
  } catch {
@@ -7580,7 +7622,7 @@ var ConversationDrawer = ({ open, onClose }) => {
7580
7622
  Box13,
7581
7623
  {
7582
7624
  onClick: user ? () => {
7583
- window.location.href = "/profile";
7625
+ safeNavigate("/profile");
7584
7626
  } : void 0,
7585
7627
  title: user ? "Profile & settings" : void 0,
7586
7628
  sx: {
@@ -7673,7 +7715,7 @@ var ConversationDrawer = ({ open, onClose }) => {
7673
7715
  title: "Management & settings",
7674
7716
  onClick: (event) => {
7675
7717
  event.stopPropagation();
7676
- window.location.href = managementPath;
7718
+ safeNavigate(managementPath);
7677
7719
  },
7678
7720
  sx: {
7679
7721
  flexShrink: 0,
@@ -7831,7 +7873,7 @@ var ConversationDrawer = ({ open, onClose }) => {
7831
7873
  var conversation_drawer_default = ConversationDrawer;
7832
7874
 
7833
7875
  // src/chat/enhanced-mobile-conversations-modal.tsx
7834
- import { useState as useState15, useMemo as useMemo3, useEffect as useEffect12, useRef as useRef10, useCallback as useCallback5 } from "react";
7876
+ import { useState as useState15, useMemo as useMemo3, useEffect as useEffect12, useRef as useRef11, useCallback as useCallback5 } from "react";
7835
7877
  import {
7836
7878
  Box as Box14,
7837
7879
  IconButton as IconButton11,
@@ -7887,7 +7929,8 @@ var deriveInitials2 = (value) => {
7887
7929
  };
7888
7930
  var EnhancedMobileConversationsModal = ({
7889
7931
  open,
7890
- onClose
7932
+ onClose,
7933
+ drag
7891
7934
  }) => {
7892
7935
  const theme = useTheme14();
7893
7936
  const { user } = useAuthenticationStore();
@@ -7914,15 +7957,18 @@ var EnhancedMobileConversationsModal = ({
7914
7957
  const syncEnabled = useConversationSyncStore((s) => s.syncEnabled);
7915
7958
  const syncStatus = useConversationSyncStore((s) => s.status);
7916
7959
  const runSync = useConversationSyncStore((s) => s.runSync);
7960
+ const safeNavigate = useSafeNavigate();
7917
7961
  const goToHome = () => {
7918
7962
  const resolvedHomeUrl = preferences.homeUrl?.trim() || usePackageSettingsStore.getState().settings?.homeUrl?.trim() || "";
7919
7963
  if (resolvedHomeUrl) {
7920
7964
  window.location.href = resolvedHomeUrl;
7921
7965
  return;
7922
7966
  }
7923
- const navigatorWithStandalone = window.navigator;
7924
- const isStandalone = window.matchMedia?.("(display-mode: standalone)").matches || navigatorWithStandalone.standalone === true;
7925
- if (isStandalone) {
7967
+ if (isNativeShell()) {
7968
+ safeNavigate("/chat");
7969
+ return;
7970
+ }
7971
+ if (isStandalonePwa()) {
7926
7972
  try {
7927
7973
  sessionStorage.setItem("banditPwaStayOnHome", "true");
7928
7974
  } catch {
@@ -7936,7 +7982,7 @@ var EnhancedMobileConversationsModal = ({
7936
7982
  const [projectManagementOpen, setProjectManagementOpen] = useState15(false);
7937
7983
  const [memoryModalOpen, setMemoryModalOpen] = useState15(false);
7938
7984
  const [collapsedProjects, setCollapsedProjects] = useState15(/* @__PURE__ */ new Set());
7939
- const didInitCollapseRef = useRef10(false);
7985
+ const didInitCollapseRef = useRef11(false);
7940
7986
  const [searchQuery, setSearchQuery] = useState15("");
7941
7987
  const [menuAnchorEl, setMenuAnchorEl] = useState15(null);
7942
7988
  const [clearConfirmOpen, setClearConfirmOpen] = useState15(false);
@@ -8226,6 +8272,11 @@ var EnhancedMobileConversationsModal = ({
8226
8272
  children: /* @__PURE__ */ jsx17(Slide, { direction: "right", in: open, children: /* @__PURE__ */ jsxs14(
8227
8273
  Box14,
8228
8274
  {
8275
+ style: drag?.style,
8276
+ onTouchStart: drag?.onTouchStart,
8277
+ onTouchMove: drag?.onTouchMove,
8278
+ onTouchEnd: drag?.onTouchEnd,
8279
+ onTouchCancel: drag?.onTouchEnd,
8229
8280
  sx: {
8230
8281
  position: "fixed",
8231
8282
  top: 0,
@@ -8733,7 +8784,7 @@ var EnhancedMobileConversationsModal = ({
8733
8784
  Box14,
8734
8785
  {
8735
8786
  onClick: user ? () => {
8736
- window.location.href = "/profile";
8787
+ safeNavigate("/profile");
8737
8788
  } : void 0,
8738
8789
  sx: {
8739
8790
  mt: "auto",
@@ -8809,7 +8860,7 @@ var EnhancedMobileConversationsModal = ({
8809
8860
  title: "Management & settings",
8810
8861
  onClick: (event) => {
8811
8862
  event.stopPropagation();
8812
- window.location.href = managementPath;
8863
+ safeNavigate(managementPath);
8813
8864
  },
8814
8865
  sx: {
8815
8866
  flexShrink: 0,
@@ -8989,14 +9040,15 @@ var ChatAppBar = ({
8989
9040
  drawerOpen,
8990
9041
  setDrawerOpen,
8991
9042
  mobileConversationsOpen,
8992
- onMobileConversationsOpenChange
9043
+ onMobileConversationsOpenChange,
9044
+ mobileConversationsDrag
8993
9045
  }) => {
8994
9046
  const theme = useTheme15();
8995
9047
  const isMobile = useMediaQuery6(theme.breakpoints.down("sm"));
8996
- const hasLoggedRouterWarningRef = useRef11(false);
9048
+ const hasLoggedRouterWarningRef = useRef12(false);
8997
9049
  let navigate = null;
8998
9050
  try {
8999
- navigate = useNavigate2();
9051
+ navigate = useNavigate3();
9000
9052
  } catch (error) {
9001
9053
  if (!hasLoggedRouterWarningRef.current) {
9002
9054
  debugLogger.warn("ChatAppBar: Navigation not available (missing Router context)", { error });
@@ -9341,7 +9393,7 @@ var ChatAppBar = ({
9341
9393
  }
9342
9394
  ),
9343
9395
  /* @__PURE__ */ jsx18(conversation_drawer_default, { open: drawerOpen, onClose: () => setDrawerOpen(false) }),
9344
- /* @__PURE__ */ jsx18(enhanced_mobile_conversations_modal_default, { open: modalOpen, onClose: () => setModalOpen(false) }),
9396
+ /* @__PURE__ */ jsx18(enhanced_mobile_conversations_modal_default, { open: modalOpen, onClose: () => setModalOpen(false), drag: mobileConversationsDrag }),
9345
9397
  /* @__PURE__ */ jsxs15(
9346
9398
  Dialog7,
9347
9399
  {
@@ -9469,7 +9521,7 @@ Respond with just the title and nothing else.
9469
9521
  };
9470
9522
 
9471
9523
  // src/chat/query-suggestion-picker.tsx
9472
- import { useEffect as useEffect14, useRef as useRef12, useState as useState17 } from "react";
9524
+ import { useEffect as useEffect14, useRef as useRef13, useState as useState17 } from "react";
9473
9525
  import { Box as Box16, useMediaQuery as useMediaQuery7 } from "@mui/material";
9474
9526
  import { useTheme as useTheme16, alpha as alpha10 } from "@mui/material/styles";
9475
9527
  import ReactMarkdown from "react-markdown";
@@ -9488,11 +9540,11 @@ var QuerySuggestionPicker = ({
9488
9540
  onSend,
9489
9541
  inputHeight
9490
9542
  }) => {
9491
- const hasGenerated = useRef12(false);
9543
+ const hasGenerated = useRef13(false);
9492
9544
  const [hasSentPrompt, setHasSentPrompt] = useState17(false);
9493
9545
  const [examplePrompts, setExamplePrompts] = useState17([]);
9494
9546
  const [visiblePrompts, setVisiblePrompts] = useState17([]);
9495
- const scrollRef = useRef12(null);
9547
+ const scrollRef = useRef13(null);
9496
9548
  const theme = useTheme16();
9497
9549
  const isMobile = useMediaQuery7((theme2) => theme2.breakpoints.down("sm"));
9498
9550
  const { background, text, border, hoverBackground, hoverBorder } = theme.palette.chat.suggestion;
@@ -9651,11 +9703,11 @@ var QuerySuggestionPicker = ({
9651
9703
 
9652
9704
  // src/components/UnderReview.tsx
9653
9705
  import { Box as Box17, Typography as Typography13, useTheme as useTheme17 } from "@mui/material";
9654
- import { useNavigate as useNavigate3 } from "react-router-dom";
9706
+ import { useNavigate as useNavigate4 } from "react-router-dom";
9655
9707
  import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
9656
9708
  var UnderReview = () => {
9657
9709
  const theme = useTheme17();
9658
- const navigate = useNavigate3();
9710
+ const navigate = useNavigate4();
9659
9711
  const handleResetSession = () => {
9660
9712
  authenticationService2.clearToken();
9661
9713
  navigate("/login");
@@ -9717,7 +9769,7 @@ var UnderReview = () => {
9717
9769
  var UnderReview_default = UnderReview;
9718
9770
 
9719
9771
  // src/components/feedback/FeedbackPulse.tsx
9720
- import { useEffect as useEffect15, useRef as useRef13, useState as useState18 } from "react";
9772
+ import { useEffect as useEffect15, useRef as useRef14, useState as useState18 } from "react";
9721
9773
  import { Box as Box18, IconButton as IconButton13, Paper as Paper2, Slide as Slide2, Typography as Typography14 } from "@mui/material";
9722
9774
  import { useTheme as useTheme18, alpha as alpha11 } from "@mui/material/styles";
9723
9775
  import { X as CloseIcon8, Smile as SmileIcon, Meh as MehIcon, Frown as FrownIcon } from "lucide-react";
@@ -9746,8 +9798,8 @@ var FeedbackPulse = ({ isMobile, feedbackEmail }) => {
9746
9798
  const [visible, setVisible] = useState18(false);
9747
9799
  const [thanked, setThanked] = useState18(false);
9748
9800
  const [modalOpen, setModalOpen] = useState18(false);
9749
- const mountedAtRef = useRef13(Date.now());
9750
- const baselineMessagesRef = useRef13(null);
9801
+ const mountedAtRef = useRef14(Date.now());
9802
+ const baselineMessagesRef = useRef14(null);
9751
9803
  const totalMessages = useConversationStore(
9752
9804
  (s) => s.conversations.reduce((n, c) => n + c.history.length, 0)
9753
9805
  );
@@ -9957,7 +10009,7 @@ var ConnectionStatus = ({
9957
10009
  };
9958
10010
 
9959
10011
  // src/hooks/useVoiceMode.ts
9960
- import { useEffect as useEffect16, useRef as useRef14 } from "react";
10012
+ import { useEffect as useEffect16, useRef as useRef15 } from "react";
9961
10013
  var RMS_BASELINE = 128;
9962
10014
  var RMS_NORMALIZER = 128;
9963
10015
  var computeRms = (data) => {
@@ -9987,7 +10039,7 @@ var useVoiceMode = (config) => {
9987
10039
  const setError = useVoiceModeStore((state) => state.setError);
9988
10040
  const resetTransientState = useVoiceModeStore((state) => state.resetTransientState);
9989
10041
  const setLastTranscript = useVoiceModeStore((state) => state.setLastTranscript);
9990
- const configRef = useRef14(config);
10042
+ const configRef = useRef15(config);
9991
10043
  useEffect16(() => {
9992
10044
  configRef.current = config;
9993
10045
  }, [config]);
@@ -10309,8 +10361,8 @@ var ChatContent = () => {
10309
10361
  } = useVoiceStore();
10310
10362
  const isVoiceModeEnabled = useVoiceModeStore((state) => state.enabled);
10311
10363
  const canvasOpen = useCanvasStore((state) => state.open);
10312
- const previousVoiceModeEnabledRef = useRef15(isVoiceModeEnabled);
10313
- const historyRef = useRef15(history);
10364
+ const previousVoiceModeEnabledRef = useRef16(isVoiceModeEnabled);
10365
+ const historyRef = useRef16(history);
10314
10366
  useEffect17(() => {
10315
10367
  historyRef.current = history;
10316
10368
  }, [history]);
@@ -10356,9 +10408,9 @@ var ChatContent = () => {
10356
10408
  }
10357
10409
  }, [packageSettings?.gatewayApiUrl, availableVoices.length, initialized, loadVoicesFromAPI, token]);
10358
10410
  const provider = useAIProviderStore((state) => state.provider);
10359
- const inputRef = useRef15(null);
10411
+ const inputRef = useRef16(null);
10360
10412
  const [pastedImages, setPastedImages] = useState19([]);
10361
- const inputContainerRef = useRef15(null);
10413
+ const inputContainerRef = useRef16(null);
10362
10414
  const [inputHeight, setInputHeight] = useState19(80);
10363
10415
  const [isSubmitting, setIsSubmitting] = useState19(false);
10364
10416
  const [pendingMessage, setPendingMessage] = useState19(null);
@@ -10367,7 +10419,70 @@ var ChatContent = () => {
10367
10419
  const [isMobile, setIsMobile] = useState19(false);
10368
10420
  const [drawerOpen, setDrawerOpen] = useState19(false);
10369
10421
  const [mobileConversationsOpen, setMobileConversationsOpen] = useState19(false);
10370
- const cardSwipeStartXRef = useRef15(null);
10422
+ const cardSwipeStartXRef = useRef16(null);
10423
+ const dragStartRef = useRef16(null);
10424
+ const [drawerDragX, setDrawerDragX] = useState19(null);
10425
+ const [drawerSettling, setDrawerSettling] = useState19(false);
10426
+ const [drawerSwap, setDrawerSwap] = useState19(false);
10427
+ const drawerOpenOffset = () => (typeof window === "undefined" ? 360 : Math.min(window.innerWidth - 56, 360)) - 12;
10428
+ const drawerDragStart = (e) => {
10429
+ const t = e.touches[0];
10430
+ if (!t) return;
10431
+ dragStartRef.current = { x: t.clientX, y: t.clientY, t: performance.now(), axis: null };
10432
+ };
10433
+ const drawerDragMove = (e) => {
10434
+ const s = dragStartRef.current;
10435
+ const t = e.touches[0];
10436
+ if (!s || !t) return;
10437
+ const dx = t.clientX - s.x;
10438
+ const dy = t.clientY - s.y;
10439
+ if (s.axis === null) {
10440
+ if (Math.abs(dx) < 8 && Math.abs(dy) < 8) return;
10441
+ s.axis = Math.abs(dx) > Math.abs(dy) ? "x" : "y";
10442
+ }
10443
+ if (s.axis !== "x") return;
10444
+ setDrawerDragX(dx < 0 ? Math.max(dx, -drawerOpenOffset()) : dx * 0.15);
10445
+ };
10446
+ const drawerDragEnd = () => {
10447
+ const s = dragStartRef.current;
10448
+ dragStartRef.current = null;
10449
+ if (!s || s.axis !== "x" || drawerDragX === null) {
10450
+ setDrawerDragX(null);
10451
+ return;
10452
+ }
10453
+ const dt = Math.max(1, performance.now() - s.t);
10454
+ const velocity = drawerDragX / dt;
10455
+ const offset = drawerOpenOffset();
10456
+ const shouldClose = drawerDragX < -offset * 0.35 || velocity < -0.45;
10457
+ if (shouldClose) {
10458
+ setDrawerSettling(true);
10459
+ setDrawerDragX(-offset);
10460
+ window.setTimeout(() => {
10461
+ setDrawerSwap(true);
10462
+ setMobileConversationsOpen(false);
10463
+ requestAnimationFrame(() => requestAnimationFrame(() => setDrawerSwap(false)));
10464
+ window.setTimeout(() => {
10465
+ setDrawerDragX(null);
10466
+ setDrawerSettling(false);
10467
+ }, 320);
10468
+ }, 220);
10469
+ } else {
10470
+ setDrawerSettling(true);
10471
+ setDrawerDragX(0);
10472
+ window.setTimeout(() => {
10473
+ setDrawerDragX(null);
10474
+ setDrawerSettling(false);
10475
+ }, 220);
10476
+ }
10477
+ };
10478
+ const drawerDragStyle = drawerSwap ? { translate: "0px 0", transition: "none" } : isMobile && mobileConversationsOpen && drawerDragX !== null ? {
10479
+ translate: `${drawerDragX}px 0`,
10480
+ transition: drawerSettling ? "translate 0.22s cubic-bezier(0.2, 0.8, 0.2, 1)" : "none"
10481
+ } : void 0;
10482
+ const drawerPanelDragStyle = isMobile && drawerDragX !== null ? {
10483
+ translate: `${drawerDragX}px 0`,
10484
+ transition: drawerSettling ? "translate 0.22s cubic-bezier(0.2, 0.8, 0.2, 1)" : "none"
10485
+ } : void 0;
10371
10486
  useEffect17(() => {
10372
10487
  if (typeof document === "undefined") return;
10373
10488
  const meta = document.querySelector('meta[name="theme-color"]');
@@ -10394,18 +10509,41 @@ var ChatContent = () => {
10394
10509
  const initialLogoState = history.length === 0;
10395
10510
  const [logoVisible, setLogoVisible] = useState19(initialLogoState);
10396
10511
  const [logoShouldRender, setLogoShouldRender] = useState19(initialLogoState);
10397
- const streamingGraceUntilRef = useRef15(0);
10512
+ const streamingGraceUntilRef = useRef16(0);
10398
10513
  const GRACE_MS = 450;
10399
10514
  const GRACE_OFFSET_DESKTOP = 28;
10400
10515
  const GRACE_OFFSET_MOBILE = 20;
10401
- const followStreamRef = useRef15(true);
10402
- const lastSpokenResponseRef = useRef15(null);
10403
- const previousConversationIdRef = useRef15(null);
10404
- const logoFadeTimeoutRef = useRef15(null);
10516
+ const followStreamRef = useRef16(true);
10517
+ const lastSpokenResponseRef = useRef16(null);
10518
+ const previousConversationIdRef = useRef16(null);
10519
+ const logoFadeTimeoutRef = useRef16(null);
10405
10520
  const [branding, setBranding] = useState19(null);
10406
10521
  const [brandingLoading, setBrandingLoading] = useState19(true);
10407
- const isBrandingLoadInProgressRef = useRef15(false);
10522
+ const isBrandingLoadInProgressRef = useRef16(false);
10408
10523
  const logoOnly = history.length === 0 && !brandingLoading;
10524
+ const knowledgeDocs = useKnowledgeStore((s) => s.docs);
10525
+ const knowledgeLoaded = useKnowledgeStore((s) => s.isLoaded);
10526
+ const [knowledgeNudgeDismissed, setKnowledgeNudgeDismissed] = useState19(() => {
10527
+ try {
10528
+ return localStorage.getItem("bandit.knowledgeNudge.dismissed") === "true";
10529
+ } catch {
10530
+ return false;
10531
+ }
10532
+ });
10533
+ const dismissKnowledgeNudge = useCallback6(() => {
10534
+ setKnowledgeNudgeDismissed(true);
10535
+ try {
10536
+ localStorage.setItem("bandit.knowledgeNudge.dismissed", "true");
10537
+ } catch {
10538
+ }
10539
+ }, []);
10540
+ const showKnowledgeNudge = logoOnly && !knowledgeNudgeDismissed && knowledgeLoaded && knowledgeDocs.length === 0 && featureFlag.hasFeature("documentKnowledge");
10541
+ const knowledgePath = typeof window !== "undefined" && window.location.pathname.startsWith("/playground") ? "/playground/management" : "/management";
10542
+ const safeNavigateTo = (to) => {
10543
+ if (typeof window !== "undefined") {
10544
+ window.location.assign(to);
10545
+ }
10546
+ };
10409
10547
  useEffect17(() => {
10410
10548
  const isEmptyConversation = (history?.length ?? 0) === 0;
10411
10549
  const isSending = Boolean(pendingMessage);
@@ -11252,27 +11390,23 @@ var ChatContent = () => {
11252
11390
  // is the same near-black as the shell.
11253
11391
  border: isMobile && mobileConversationsOpen ? `1px solid ${theme.palette.mode === "dark" ? "rgba(255,255,255,0.14)" : "rgba(0,0,0,0.12)"}` : "none",
11254
11392
  boxShadow: isMobile && mobileConversationsOpen ? `0 12px 40px ${theme.palette.mode === "dark" ? "rgba(0,0,0,0.55)" : "rgba(0,0,0,0.25)"}` : "none",
11255
- transition: "left 0.3s ease-in-out, width 0.3s ease-in-out, transform 0.3s ease-in-out, border-radius 0.3s ease-in-out"
11393
+ transition: drawerSwap ? "none" : "left 0.3s ease-in-out, width 0.3s ease-in-out, transform 0.3s ease-in-out, border-radius 0.3s ease-in-out"
11256
11394
  }),
11257
11395
  onClick: isMobile && mobileConversationsOpen ? (e) => {
11258
11396
  if (e.currentTarget.contains(e.target)) {
11259
11397
  setMobileConversationsOpen(false);
11260
11398
  }
11261
11399
  } : void 0,
11400
+ style: drawerDragStyle,
11262
11401
  onTouchStart: isMobile && mobileConversationsOpen ? (e) => {
11263
11402
  if (e.currentTarget.contains(e.target)) {
11264
11403
  cardSwipeStartXRef.current = e.touches[0]?.clientX ?? null;
11404
+ drawerDragStart(e);
11265
11405
  }
11266
11406
  } : void 0,
11267
- onTouchMove: isMobile && mobileConversationsOpen ? (e) => {
11268
- const start = cardSwipeStartXRef.current;
11269
- if (start === null) return;
11270
- const dx = (e.touches[0]?.clientX ?? start) - start;
11271
- if (Math.abs(dx) > 40) {
11272
- cardSwipeStartXRef.current = null;
11273
- setMobileConversationsOpen(false);
11274
- }
11275
- } : void 0,
11407
+ onTouchMove: isMobile && mobileConversationsOpen ? drawerDragMove : void 0,
11408
+ onTouchEnd: isMobile && mobileConversationsOpen ? drawerDragEnd : void 0,
11409
+ onTouchCancel: isMobile && mobileConversationsOpen ? drawerDragEnd : void 0,
11276
11410
  children: [
11277
11411
  /* @__PURE__ */ jsx23(
11278
11412
  chat_app_bar_default,
@@ -11285,7 +11419,13 @@ var ChatContent = () => {
11285
11419
  drawerOpen,
11286
11420
  setDrawerOpen,
11287
11421
  mobileConversationsOpen,
11288
- onMobileConversationsOpenChange: setMobileConversationsOpen
11422
+ onMobileConversationsOpenChange: setMobileConversationsOpen,
11423
+ mobileConversationsDrag: isMobile ? {
11424
+ style: drawerPanelDragStyle,
11425
+ onTouchStart: drawerDragStart,
11426
+ onTouchMove: drawerDragMove,
11427
+ onTouchEnd: drawerDragEnd
11428
+ } : void 0
11289
11429
  }
11290
11430
  ),
11291
11431
  isTemporaryChat && /* @__PURE__ */ jsxs18(Fragment13, { children: [
@@ -11441,6 +11581,53 @@ var ChatContent = () => {
11441
11581
  }
11442
11582
  return branding?.logoBase64 ? /* @__PURE__ */ jsx23(custom_logo_default, { visible: logoVisible, atTop: true }) : /* @__PURE__ */ jsx23(bandit_chat_logo_default, { visible: logoVisible, atTop: true });
11443
11583
  })(),
11584
+ showKnowledgeNudge && /* @__PURE__ */ jsxs18(
11585
+ Box20,
11586
+ {
11587
+ sx: (theme) => ({
11588
+ mx: "auto",
11589
+ mt: 2,
11590
+ mb: 1,
11591
+ px: 2,
11592
+ py: 1.25,
11593
+ maxWidth: 420,
11594
+ display: "flex",
11595
+ alignItems: "center",
11596
+ gap: 1.25,
11597
+ borderRadius: 2.5,
11598
+ border: `1px solid ${theme.palette.divider}`,
11599
+ bgcolor: theme.palette.action.hover,
11600
+ opacity: logoVisible ? 1 : 0,
11601
+ transition: "opacity 0.5s ease"
11602
+ }),
11603
+ children: [
11604
+ /* @__PURE__ */ jsxs18(Box20, { sx: { flex: 1, minWidth: 0 }, children: [
11605
+ /* @__PURE__ */ jsx23(Typography15, { variant: "body2", sx: { fontWeight: 600 }, children: "Add your documents" }),
11606
+ /* @__PURE__ */ jsx23(Typography15, { variant: "caption", color: "text.secondary", children: "Upload your policies, handbooks or notes and Bandit answers from them, with sources." })
11607
+ ] }),
11608
+ /* @__PURE__ */ jsx23(
11609
+ Button10,
11610
+ {
11611
+ size: "small",
11612
+ variant: "outlined",
11613
+ onClick: () => safeNavigateTo(knowledgePath),
11614
+ sx: { textTransform: "none", fontWeight: 600, flexShrink: 0 },
11615
+ children: "Upload"
11616
+ }
11617
+ ),
11618
+ /* @__PURE__ */ jsx23(
11619
+ IconButton14,
11620
+ {
11621
+ size: "small",
11622
+ "aria-label": "Dismiss",
11623
+ onClick: dismissKnowledgeNudge,
11624
+ sx: { flexShrink: 0 },
11625
+ children: /* @__PURE__ */ jsx23(CloseIcon, { fontSize: "small" })
11626
+ }
11627
+ )
11628
+ ]
11629
+ }
11630
+ ),
11444
11631
  /* @__PURE__ */ jsx23(
11445
11632
  Box20,
11446
11633
  {
@@ -11586,4 +11773,4 @@ var chat_default = Chat;
11586
11773
  export {
11587
11774
  chat_default
11588
11775
  };
11589
- //# sourceMappingURL=chunk-7ESJJN6D.mjs.map
11776
+ //# sourceMappingURL=chunk-6NYYYKYZ.mjs.map