@saadnvd1/agent-os 0.3.799 → 0.3.807

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 (101) hide show
  1. package/app/api/chat-views/[sessionId]/route.ts +19 -0
  2. package/app/api/chat-views/route.test.ts +79 -0
  3. package/app/api/chat-views/route.ts +8 -0
  4. package/app/page.tsx +17 -14
  5. package/components/Chat/ChatPanel.tsx +46 -59
  6. package/components/Chat/NewDivider.tsx +15 -0
  7. package/components/Chat/session-link.ts +7 -4
  8. package/components/Chat/useFind.ts +50 -1
  9. package/components/Chat/usePosition.ts +363 -0
  10. package/components/CodeSearchDialog.tsx +90 -0
  11. package/components/CommandPalette/CommandsBody.tsx +12 -4
  12. package/components/CommandPalette/useAppCommands.ts +29 -11
  13. package/components/DevServers/ServerLogsModal.tsx +24 -21
  14. package/components/Nav/HistoryButtons.tsx +128 -0
  15. package/components/Pane/MobileTabBar.tsx +3 -0
  16. package/components/Pane/index.tsx +2 -2
  17. package/components/SessionList/useSessionSwitching.ts +3 -2
  18. package/components/Shortcuts/PendingKeys.tsx +19 -0
  19. package/components/Shortcuts/ShortcutsButton.tsx +22 -0
  20. package/components/Shortcuts/ShortcutsDialog.tsx +122 -0
  21. package/components/SidebarFooter.tsx +2 -0
  22. package/components/Terminal/hooks/useTerminalConnection.ts +4 -3
  23. package/components/views/DesktopView.tsx +7 -9
  24. package/components/views/MobileView.tsx +2 -8
  25. package/components/views/lazy.ts +2 -2
  26. package/content/tips.json +146 -61
  27. package/content/whats-new.json +32 -0
  28. package/data/chat-views/index.ts +2 -0
  29. package/data/chat-views/keys.ts +3 -0
  30. package/data/chat-views/queries.ts +34 -0
  31. package/data/sessions/pin.ts +0 -1
  32. package/hooks/useChatViewsSync.ts +12 -0
  33. package/hooks/useNavActions.ts +104 -0
  34. package/hooks/useNavKeys.ts +105 -0
  35. package/hooks/useSessionUrl.ts +23 -5
  36. package/lib/bus/index.ts +4 -2
  37. package/lib/bus/role-alias.ts +4 -2
  38. package/lib/bus/targets.ts +2 -1
  39. package/lib/chat/escape.ts +8 -4
  40. package/lib/chat-views/body.ts +41 -0
  41. package/lib/chat-views/store.ts +67 -0
  42. package/lib/chat-views/types.ts +20 -0
  43. package/lib/db/migrations/20261031T1500_chat_views.ts +30 -0
  44. package/lib/keybindings/focus.ts +17 -0
  45. package/lib/keybindings/keymap.ts +120 -0
  46. package/lib/keybindings/sequence.ts +64 -0
  47. package/lib/live/service.ts +1 -1
  48. package/lib/nav/history-mirror.ts +59 -0
  49. package/lib/nav/history-writer.ts +109 -0
  50. package/lib/nav/position.ts +67 -0
  51. package/lib/nav/recent.ts +34 -0
  52. package/lib/orchestrator/armed.ts +5 -0
  53. package/lib/palette/sections.ts +12 -6
  54. package/lib/session-url.ts +11 -5
  55. package/package.json +1 -1
  56. package/public/tips/chat-access-picker-dark.webp +0 -0
  57. package/public/tips/chat-access-picker.webp +0 -0
  58. package/public/tips/chat-attach-files-poster.webp +0 -0
  59. package/public/tips/chat-attach-files.mp4 +0 -0
  60. package/public/tips/chat-bookmark-dark.webp +0 -0
  61. package/public/tips/chat-bookmark.webp +0 -0
  62. package/public/tips/chat-plan-mode-dark.webp +0 -0
  63. package/public/tips/chat-plan-mode.webp +0 -0
  64. package/public/tips/chat-search-poster.webp +0 -0
  65. package/public/tips/chat-search.mp4 +0 -0
  66. package/public/tips/chat-tab-suggestion-poster.webp +0 -0
  67. package/public/tips/chat-tab-suggestion.mp4 +0 -0
  68. package/public/tips/chat-terminal-handoff-poster.webp +0 -0
  69. package/public/tips/chat-terminal-handoff.mp4 +0 -0
  70. package/public/tips/chat-undo-dark.webp +0 -0
  71. package/public/tips/chat-undo.webp +0 -0
  72. package/public/tips/export-ai-dark.webp +0 -0
  73. package/public/tips/export-ai.webp +0 -0
  74. package/public/tips/net-messages-dark.webp +0 -0
  75. package/public/tips/net-messages.webp +0 -0
  76. package/public/tips/recipe-save-dark.webp +0 -0
  77. package/public/tips/recipe-save.webp +0 -0
  78. package/public/tips/schedule-first-dark.webp +0 -0
  79. package/public/tips/schedule-first.webp +0 -0
  80. package/public/tips/share-check-dark.webp +0 -0
  81. package/public/tips/share-check.webp +0 -0
  82. package/public/tips/sidebar-draft-poster.webp +0 -0
  83. package/public/tips/sidebar-draft.mp4 +0 -0
  84. package/public/tips/sidebar-groups-dark.webp +0 -0
  85. package/public/tips/sidebar-groups.webp +0 -0
  86. package/public/tips/sidebar-load-dark.webp +0 -0
  87. package/public/tips/sidebar-load.webp +0 -0
  88. package/public/tips/sidebar-snooze-dark.webp +0 -0
  89. package/public/tips/sidebar-snooze.webp +0 -0
  90. package/public/tips/tasks-plan-pieces-dark.webp +0 -0
  91. package/public/tips/tasks-plan-pieces.webp +0 -0
  92. package/public/tips/tasks-sign-off-dark.webp +0 -0
  93. package/public/tips/tasks-sign-off.webp +0 -0
  94. package/public/tips/tasks-stacks-dark.webp +0 -0
  95. package/public/tips/tasks-stacks.webp +0 -0
  96. package/scripts/check +2 -2
  97. package/stores/chatJump.ts +2 -6
  98. package/stores/chatPositions.ts +65 -0
  99. package/stores/navHistory.ts +98 -0
  100. package/stores/shortcutsUi.ts +20 -0
  101. package/components/QuickSwitcher.tsx +0 -286
@@ -0,0 +1,128 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { useSnapshot } from "valtio";
5
+ import { ArrowLeft, ArrowRight } from "lucide-react";
6
+ import { Button } from "@/components/ui/button";
7
+ import {
8
+ DropdownMenu,
9
+ DropdownMenuContent,
10
+ DropdownMenuItem,
11
+ DropdownMenuLabel,
12
+ DropdownMenuSeparator,
13
+ DropdownMenuTrigger,
14
+ } from "@/components/ui/dropdown-menu";
15
+ import {
16
+ Tooltip,
17
+ TooltipContent,
18
+ TooltipTrigger,
19
+ } from "@/components/ui/tooltip";
20
+ import { useLongPress } from "@/components/Chat/useLongPress";
21
+ import { earlier, later, type MirrorEntry } from "@/lib/nav/history-mirror";
22
+ import { isMac } from "@/lib/keybindings/chord";
23
+ import { navHistory, navHistoryActions } from "@/stores/navHistory";
24
+
25
+ const KEYS_BACK = () => (isMac() ? "⌘[" : "Alt+←");
26
+ const KEYS_FORWARD = () => (isMac() ? "⌘]" : "Alt+→");
27
+
28
+ function useReach() {
29
+ const snap = useSnapshot(navHistory);
30
+ const m = { entries: [...snap.entries], current: snap.current };
31
+ return { back: earlier(m), forward: later(m) };
32
+ }
33
+
34
+ function Entries({ entries }: { entries: MirrorEntry[] }) {
35
+ return entries.slice(0, 15).map((e) => (
36
+ <DropdownMenuItem
37
+ key={e.index}
38
+ className="min-h-11 md:min-h-0"
39
+ onSelect={() => navHistoryActions.goTo(e.index)}
40
+ >
41
+ <span className="truncate">{e.name || "Chat"}</span>
42
+ </DropdownMenuItem>
43
+ ));
44
+ }
45
+
46
+ /** One history button: tap goes a step; hold (touch) or right-click opens the list of chats it would pass. */
47
+ function HistoryButton({
48
+ dir,
49
+ entries,
50
+ className,
51
+ }: {
52
+ dir: "back" | "forward";
53
+ entries: MirrorEntry[];
54
+ className?: string;
55
+ }) {
56
+ const [open, setOpen] = useState(false);
57
+ const hold = useLongPress(entries.length > 0 ? () => setOpen(true) : null);
58
+ const Icon = dir === "back" ? ArrowLeft : ArrowRight;
59
+ const label = dir === "back" ? "Back" : "Forward";
60
+ const hint = dir === "back" ? KEYS_BACK() : KEYS_FORWARD();
61
+ const go = () =>
62
+ dir === "back" ? navHistoryActions.back() : navHistoryActions.forward();
63
+ const button = (
64
+ <Button
65
+ variant="ghost"
66
+ size="icon-sm"
67
+ aria-label={label}
68
+ disabled={entries.length === 0}
69
+ className={className}
70
+ onClick={(e) => {
71
+ e.stopPropagation();
72
+ go();
73
+ }}
74
+ onContextMenu={(e) => {
75
+ if (entries.length === 0) return;
76
+ e.preventDefault();
77
+ setOpen(true);
78
+ }}
79
+ {...hold}
80
+ >
81
+ <Icon className="h-4 w-4" />
82
+ </Button>
83
+ );
84
+ return (
85
+ <DropdownMenu open={open} onOpenChange={setOpen} modal={false}>
86
+ <Tooltip>
87
+ <TooltipTrigger asChild>
88
+ <DropdownMenuTrigger asChild>{button}</DropdownMenuTrigger>
89
+ </TooltipTrigger>
90
+ <TooltipContent>{`${label} (${hint})`}</TooltipContent>
91
+ </Tooltip>
92
+ <DropdownMenuContent align="start" className="max-w-72">
93
+ <DropdownMenuLabel>
94
+ {dir === "back" ? "Earlier" : "Later"}
95
+ </DropdownMenuLabel>
96
+ <DropdownMenuSeparator />
97
+ <Entries entries={entries} />
98
+ </DropdownMenuContent>
99
+ </DropdownMenu>
100
+ );
101
+ }
102
+
103
+ /** Desktop: back and forward through the chats and bookmarks visited. */
104
+ export function HistoryButtons() {
105
+ const { back, forward } = useReach();
106
+ return (
107
+ <>
108
+ <HistoryButton dir="back" entries={back} className="h-7 w-7 shrink-0" />
109
+ <HistoryButton
110
+ dir="forward"
111
+ entries={forward}
112
+ className="h-7 w-7 shrink-0"
113
+ />
114
+ </>
115
+ );
116
+ }
117
+
118
+ /** Phone: the back button beside the menu; hold it for the list. */
119
+ export function PhoneBackButton() {
120
+ const { back } = useReach();
121
+ return (
122
+ <HistoryButton
123
+ dir="back"
124
+ entries={back}
125
+ className="relative h-8 w-8 shrink-0 after:absolute after:-inset-1.5 after:content-['']"
126
+ />
127
+ );
128
+ }
@@ -44,6 +44,7 @@ import { useCanAddAnalyst } from "@/components/Analyst/pair";
44
44
  import { MoveMenuItems } from "@/components/Tasks/MoveMenuItems";
45
45
  import { ChatBookmarksButton } from "@/components/Bookmarks/ChatBookmarksButton";
46
46
  import type { ViewMode } from "@/contexts/PaneContext";
47
+ import { PhoneBackButton } from "@/components/Nav/HistoryButtons";
47
48
  import { MobileViewPicker } from "./MobileViewPicker";
48
49
 
49
50
  interface MobileTabBarProps {
@@ -169,6 +170,8 @@ export function MobileTabBar({
169
170
  </Button>
170
171
  )}
171
172
 
173
+ <PhoneBackButton />
174
+
172
175
  {/* Session/Tab navigation */}
173
176
  <div className="flex min-w-0 flex-1 items-center gap-1">
174
177
  <button
@@ -255,7 +255,7 @@ export const Pane = memo(function Pane({
255
255
  fileOpenActions.clearRequest();
256
256
  // TODO: Scroll to line (requires FileEditor enhancement)
257
257
  }
258
- }, [fileOpenRequest, isFocused, session, fileEditor]);
258
+ }, [fileOpenRequest, isFocused, session, fileEditor, setViewMode]);
259
259
 
260
260
  // An artifact's file, opened in the Files view.
261
261
  const openInFiles = useCallback(
@@ -291,7 +291,7 @@ export const Pane = memo(function Pane({
291
291
 
292
292
  // Create onConnected callback for a specific tab
293
293
  const getTerminalConnectedHandler = useCallback(
294
- (tab: (typeof paneData.tabs)[0]) => () => {
294
+ (tab: TabData) => () => {
295
295
  console.log(
296
296
  `[AgentOS] Terminal connected for pane: ${paneId}, tab: ${tab.id}`
297
297
  );
@@ -4,11 +4,12 @@ import { MessageSquare } from "lucide-react";
4
4
  import { useKeybindings } from "@/hooks/useKeybindings";
5
5
  import { usePaletteCommands } from "@/hooks/usePaletteCommands";
6
6
  import { chordHint } from "@/lib/keybindings/chord";
7
+ import { keysOf } from "@/lib/keybindings/keymap";
7
8
  import { fieldOwnsKey } from "@/lib/keybindings/focus";
8
9
  import { neighbourSession } from "@/lib/sidebar/visible-order";
9
10
 
10
- const PREVIOUS = "mod+up";
11
- const NEXT = "mod+down";
11
+ const PREVIOUS = keysOf("session.previous");
12
+ const NEXT = keysOf("session.next");
12
13
 
13
14
  // ⌘↑ / ⌘↓ (Ctrl off a Mac) select the row above or below the active one, as
14
15
  // a click would, in the order the sidebar shows. Nothing happens at either end.
@@ -0,0 +1,19 @@
1
+ "use client";
2
+
3
+ import { useSnapshot } from "valtio";
4
+ import { shortcutsUi } from "@/stores/shortcutsUi";
5
+
6
+ /** The first key of a sequence, shown until the second comes or time runs out. */
7
+ export function PendingKeys() {
8
+ const { pending } = useSnapshot(shortcutsUi);
9
+ if (!pending) return null;
10
+ return (
11
+ <div
12
+ role="status"
13
+ className="bg-popover text-popover-foreground border-foreground/10 pointer-events-none fixed bottom-4 left-1/2 z-50 -translate-x-1/2 rounded-md border px-3 py-1.5 text-sm shadow-md"
14
+ >
15
+ <kbd className="font-mono font-medium uppercase">{pending}</kbd>
16
+ <span className="text-muted-foreground ml-2">then…</span>
17
+ </div>
18
+ );
19
+ }
@@ -0,0 +1,22 @@
1
+ "use client";
2
+
3
+ import { Keyboard } from "lucide-react";
4
+ import { Button } from "@/components/ui/button";
5
+ import { shortcutsUiActions } from "@/stores/shortcutsUi";
6
+
7
+ /** A footer icon that opens the shortcuts panel; on a phone it is the only way in. */
8
+ export function ShortcutsButton() {
9
+ return (
10
+ <Button
11
+ type="button"
12
+ variant="ghost"
13
+ size="icon"
14
+ title="Keyboard shortcuts (?)"
15
+ aria-label="Keyboard shortcuts"
16
+ onClick={() => shortcutsUiActions.open()}
17
+ className="text-muted-foreground relative h-8 w-8 after:absolute after:-inset-1.5 after:content-[''] md:after:hidden [@media(hover:none)]:md:h-11 [@media(hover:none)]:md:w-11"
18
+ >
19
+ <Keyboard className="h-4 w-4" />
20
+ </Button>
21
+ );
22
+ }
@@ -0,0 +1,122 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { useSnapshot } from "valtio";
5
+ import { Search } from "lucide-react";
6
+ import {
7
+ Dialog,
8
+ DialogContent,
9
+ DialogDescription,
10
+ DialogTitle,
11
+ } from "@/components/ui/dialog";
12
+ import { Switch } from "@/components/ui/switch";
13
+ import { useSingleKeys } from "@/hooks/useNavKeys";
14
+ import { chordHint, isMac } from "@/lib/keybindings/chord";
15
+ import {
16
+ isSequence,
17
+ searchKeymap,
18
+ type KeyEntry,
19
+ type KeyGroup,
20
+ } from "@/lib/keybindings/keymap";
21
+ import { shortcutsUi, shortcutsUiActions } from "@/stores/shortcutsUi";
22
+
23
+ const GROUPS: KeyGroup[] = ["Go to", "Chats", "General", "Browser"];
24
+
25
+ // The browser's own keys for back and forward, per platform.
26
+ function hint(k: KeyEntry): string[] {
27
+ if (isSequence(k.keys)) return k.keys.split(" ").map((x) => x.toUpperCase());
28
+ if (k.browser) {
29
+ if (!isMac()) return [k.id === "history.back" ? "Alt+←" : "Alt+→"];
30
+ const arrow = k.keys.replace("[", "left").replace("]", "right");
31
+ return [chordHint(k.keys, true), chordHint(arrow, true)];
32
+ }
33
+ return [chordHint(k.keys)];
34
+ }
35
+
36
+ function Row({ k }: { k: KeyEntry }) {
37
+ const parts = hint(k);
38
+ return (
39
+ <li className="flex min-h-11 items-center justify-between gap-3 py-1 md:min-h-8">
40
+ <span className="min-w-0 text-sm">{k.label}</span>
41
+ <span className="flex shrink-0 items-center gap-1">
42
+ {isSequence(k.keys) ? (
43
+ parts.map((p, i) => <Kbd key={i}>{p}</Kbd>)
44
+ ) : (
45
+ <Kbd>{parts.join(" · ")}</Kbd>
46
+ )}
47
+ </span>
48
+ </li>
49
+ );
50
+ }
51
+
52
+ const Kbd = ({ children }: { children: React.ReactNode }) => (
53
+ <kbd className="bg-muted text-muted-foreground min-w-6 rounded border px-1.5 py-0.5 text-center font-mono text-xs">
54
+ {children}
55
+ </kbd>
56
+ );
57
+
58
+ /** Every shortcut, searchable, with the switch that turns the bare-key ones off. */
59
+ export function ShortcutsDialog() {
60
+ const { open } = useSnapshot(shortcutsUi);
61
+ const [query, setQuery] = useState("");
62
+ const [singles, setSingles] = useSingleKeys();
63
+ const found = searchKeymap(query);
64
+ return (
65
+ <Dialog
66
+ open={open}
67
+ onOpenChange={(o) => {
68
+ shortcutsUiActions.setOpen(o);
69
+ if (!o) setQuery("");
70
+ }}
71
+ >
72
+ <DialogContent className="flex max-h-[min(80dvh,640px)] flex-col gap-3 sm:max-w-lg">
73
+ <DialogTitle>Keyboard shortcuts</DialogTitle>
74
+ <DialogDescription className="sr-only">
75
+ Search the shortcuts and turn the single-key ones off
76
+ </DialogDescription>
77
+ <label className="border-foreground/10 flex items-center gap-2 rounded-md border px-3">
78
+ <Search className="text-muted-foreground h-4 w-4 shrink-0" />
79
+ <input
80
+ autoFocus
81
+ value={query}
82
+ onChange={(e) => setQuery(e.target.value)}
83
+ placeholder="Search shortcuts…"
84
+ aria-label="Search shortcuts"
85
+ className="placeholder:text-muted-foreground h-11 min-w-0 flex-1 bg-transparent text-base outline-none sm:text-sm"
86
+ />
87
+ </label>
88
+ <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain">
89
+ {found.length === 0 && (
90
+ <p className="text-muted-foreground py-6 text-center text-sm">
91
+ No shortcut matches.
92
+ </p>
93
+ )}
94
+ {GROUPS.map((g) => {
95
+ const rows = found.filter((k) => k.group === g);
96
+ if (!rows.length) return null;
97
+ return (
98
+ <section key={g} className="mb-3">
99
+ <h3 className="label-mono text-muted-foreground mb-1">{g}</h3>
100
+ <ul>
101
+ {rows.map((k) => (
102
+ <Row key={k.id} k={k} />
103
+ ))}
104
+ </ul>
105
+ </section>
106
+ );
107
+ })}
108
+ </div>
109
+ <label className="border-foreground/10 flex min-h-11 items-center justify-between gap-3 border-t pt-3 text-sm">
110
+ <span>
111
+ Single-key shortcuts
112
+ <span className="text-muted-foreground block text-xs">
113
+ Letters like C and G I, only when you are not typing. This browser
114
+ only.
115
+ </span>
116
+ </span>
117
+ <Switch checked={singles} onCheckedChange={setSingles} />
118
+ </label>
119
+ </DialogContent>
120
+ </Dialog>
121
+ );
122
+ }
@@ -1,6 +1,7 @@
1
1
  import { TipButton } from "@/components/Tips";
2
2
  import { WhatsNewButton } from "@/components/WhatsNew";
3
3
  import { ThemeToggle } from "@/components/ThemeToggle";
4
+ import { ShortcutsButton } from "@/components/Shortcuts/ShortcutsButton";
4
5
  import {
5
6
  Tooltip,
6
7
  TooltipContent,
@@ -13,6 +14,7 @@ export function SidebarFooter() {
13
14
  <div className="flex items-center justify-between">
14
15
  <span className="label-mono text-muted-foreground">Theme</span>
15
16
  <div className="flex items-center">
17
+ <ShortcutsButton />
16
18
  <TipButton />
17
19
  <WhatsNewButton />
18
20
  <ThemeToggle />
@@ -137,7 +137,8 @@ export function useTerminalConnection({
137
137
 
138
138
  // Main setup effect
139
139
  useEffect(() => {
140
- if (!terminalRef.current) return;
140
+ const container = terminalRef.current;
141
+ if (!container) return;
141
142
 
142
143
  let cancelled = false;
143
144
  // Reset intentional close flag (may be true from previous cleanup)
@@ -220,9 +221,9 @@ export function useTerminalConnection({
220
221
 
221
222
  // Save scroll state before unmount
222
223
  const term = xtermRef.current;
223
- if (term && callbacksRef.current.onBeforeUnmount && terminalRef.current) {
224
+ if (term && callbacksRef.current.onBeforeUnmount) {
224
225
  const buffer = term.buffer.active;
225
- const viewport = terminalRef.current.querySelector(
226
+ const viewport = container.querySelector(
226
227
  ".xterm-viewport"
227
228
  ) as HTMLElement;
228
229
  callbacksRef.current.onBeforeUnmount({
@@ -6,8 +6,9 @@ import { UpdateBanner } from "@/components/Updates";
6
6
  import { PaneLayout } from "@/components/PaneLayout";
7
7
  import { PaneBarSlotsProvider } from "@/components/Pane/PaneBarSlots";
8
8
  import type { ViewProps } from "./types";
9
- import { QuickSwitcher, StartServerDialog } from "./lazy";
9
+ import { CodeSearchDialog, StartServerDialog } from "./lazy";
10
10
  import { fileOpenActions } from "@/stores/fileOpen";
11
+ import { HistoryButtons } from "@/components/Nav/HistoryButtons";
11
12
  import { useSidebarPinned } from "@/hooks/useSidebarPinned";
12
13
 
13
14
  export function DesktopView({
@@ -57,7 +58,10 @@ export function DesktopView({
57
58
  <div className="min-h-0 flex-1">
58
59
  <PaneBarSlotsProvider
59
60
  leading={
60
- <SidebarToggle isPinned={isPinned} togglePin={togglePin} />
61
+ <>
62
+ <SidebarToggle isPinned={isPinned} togglePin={togglePin} />
63
+ <HistoryButtons />
64
+ </>
61
65
  }
62
66
  trailing={<DesktopAppActions showNew={!isPinned} />}
63
67
  >
@@ -67,16 +71,10 @@ export function DesktopView({
67
71
  </div>
68
72
 
69
73
  {/* Dialogs */}
70
- <QuickSwitcher
71
- sessions={sessions}
74
+ <CodeSearchDialog
72
75
  open={showQuickSwitcher}
73
76
  onOpenChange={setShowQuickSwitcher}
74
- currentSessionId={focusedActiveTab?.sessionId ?? undefined}
75
77
  activeSessionWorkingDir={activeSession?.working_directory ?? undefined}
76
- onSelectSession={(sessionId) => {
77
- const session = sessions.find((s) => s.id === sessionId);
78
- if (session) selectSession(session);
79
- }}
80
78
  onSelectFile={(file, line) => {
81
79
  // Convert relative path to absolute by prepending working directory
82
80
  const absolutePath = activeSession?.working_directory
@@ -6,7 +6,7 @@ import { PaneLayout } from "@/components/PaneLayout";
6
6
  import { SwipeSidebar } from "@/components/mobile/SwipeSidebar";
7
7
  import { UpdateBanner } from "@/components/Updates";
8
8
  import type { ViewProps } from "./types";
9
- import { QuickSwitcher, StartServerDialog } from "./lazy";
9
+ import { CodeSearchDialog, StartServerDialog } from "./lazy";
10
10
  import { fileOpenActions } from "@/stores/fileOpen";
11
11
 
12
12
  export function MobileView({
@@ -66,16 +66,10 @@ export function MobileView({
66
66
  </div>
67
67
 
68
68
  {/* Dialogs */}
69
- <QuickSwitcher
70
- sessions={sessions}
69
+ <CodeSearchDialog
71
70
  open={showQuickSwitcher}
72
71
  onOpenChange={setShowQuickSwitcher}
73
- currentSessionId={focusedActiveTab?.sessionId ?? undefined}
74
72
  activeSessionWorkingDir={activeSession?.working_directory ?? undefined}
75
- onSelectSession={(sessionId) => {
76
- const session = sessions.find((s) => s.id === sessionId);
77
- if (session) attachToSession(session);
78
- }}
79
73
  onSelectFile={(file, line) => {
80
74
  // Convert relative path to absolute by prepending working directory
81
75
  const absolutePath = activeSession?.working_directory
@@ -2,8 +2,8 @@ import dynamic from "next/dynamic";
2
2
 
3
3
  // Dialogs both views hold closed until asked for: their code loads after the
4
4
  // first paint rather than with it.
5
- export const QuickSwitcher = dynamic(
6
- () => import("@/components/QuickSwitcher").then((m) => m.QuickSwitcher),
5
+ export const CodeSearchDialog = dynamic(
6
+ () => import("@/components/CodeSearchDialog").then((m) => m.CodeSearchDialog),
7
7
  { ssr: false }
8
8
  );
9
9
  export const StartServerDialog = dynamic(