Skip to content

Commit a21d6ce

Browse files
authored
feature: sessions sidebar (#148)
* feat(tui): add vim NERDTree-style sessions sidebar Add a new sessions sidebar that can be toggled with ctrl+n from any screen. The sidebar displays sessions in a tree structure with vim-style navigation: - j/k, ↑/↓: Move cursor - Enter, o: Open session / Toggle expand - O: Expand all children - x: Collapse parent - X: Collapse all - p: Go to parent - g/G: Jump to top/bottom - n: New session - r: Rename session - d: Delete session - ?: Show help Features: - Tree structure showing parent/child session relationships - Context usage indicator with colored circles - Session status (busy/idle) indicator - Works globally from both home and session pages * fix: resolve typecheck errors in build.ts and mcp/index.ts * feat(sidebar): widen to 50 chars, add timestamp and message count * refactor(sidebar): remove message count, keep title/time/status/context * refactor(sidebar): reduce width to 35
1 parent 5537bc9 commit a21d6ce

9 files changed

Lines changed: 446 additions & 13 deletions

File tree

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,25 @@ This is used internally and can be invoked using `@general` in messages.
106106

107107
Learn more about [agents](https://opencode.ai/docs/agents).
108108

109+
### Sessions Sidebar
110+
111+
A NERDTree-style sidebar for managing sessions. Toggle with `ctrl+n`.
112+
113+
| Key | Action |
114+
| --- | --- |
115+
| `j/k` or `↑/↓` | Move cursor |
116+
| `Enter` or `o` | Open session / Toggle expand |
117+
| `O` | Expand all children |
118+
| `x` | Collapse parent |
119+
| `X` | Collapse all |
120+
| `p` | Go to parent |
121+
| `g/G` | Jump to top/bottom |
122+
| `n` | New session |
123+
| `r` | Rename session |
124+
| `d` | Delete session |
125+
| `?` | Show help |
126+
| `q` or `Esc` | Close sidebar |
127+
109128
### Documentation
110129

111130
For more info on how to configure OpenCode [**head over to our docs**](https://opencode.ai/docs).

packages/opencode/script/build.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env bun
22

3-
import solidPlugin from "../node_modules/@opentui/solid/scripts/solid-plugin"
3+
import solidPlugin from "@opentui/solid/bun-plugin"
44
import path from "path"
55
import fs from "fs"
66
import { $ } from "bun"

packages/opencode/src/cli/cmd/tui/app.tsx

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { KeybindProvider } from "@tui/context/keybind"
2222
import { ThemeProvider, useTheme } from "@tui/context/theme"
2323
import { Home } from "@tui/routes/home"
2424
import { Session } from "@tui/routes/session"
25+
import { SessionsSidebar } from "@tui/routes/session/sidebar-sessions"
2526
import { PromptHistoryProvider } from "./component/prompt/history"
2627
import { DialogAlert } from "./ui/dialog-alert"
2728
import { ToastProvider, useToast } from "./ui/toast"
@@ -178,6 +179,7 @@ function App() {
178179
const promptRef = usePromptRef()
179180

180181
const [terminalTitleEnabled, setTerminalTitleEnabled] = createSignal(kv.get("terminal_title_enabled", true))
182+
const [sessionsSidebarVisible, setSessionsSidebarVisible] = createSignal(false)
181183

182184
createEffect(() => {
183185
console.log(JSON.stringify(route.data))
@@ -280,6 +282,16 @@ function App() {
280282
dialog.clear()
281283
},
282284
},
285+
{
286+
title: sessionsSidebarVisible() ? "Hide sessions" : "Show sessions",
287+
value: "session.sessions_sidebar.toggle",
288+
keybind: "sessions_sidebar_toggle",
289+
category: "Session",
290+
onSelect: (dialog) => {
291+
setSessionsSidebarVisible((prev) => !prev)
292+
dialog.clear()
293+
},
294+
},
283295
{
284296
title: "Switch model",
285297
value: "model.list",
@@ -631,14 +643,21 @@ function App() {
631643
}
632644
}}
633645
>
634-
<Switch>
635-
<Match when={route.data.type === "home"}>
636-
<Home />
637-
</Match>
638-
<Match when={route.data.type === "session"}>
639-
<Session />
640-
</Match>
641-
</Switch>
646+
<box flexDirection="row" flexGrow={1}>
647+
<Show when={sessionsSidebarVisible()}>
648+
<SessionsSidebar onClose={() => setSessionsSidebarVisible(false)} />
649+
</Show>
650+
<box flexGrow={1}>
651+
<Switch>
652+
<Match when={route.data.type === "home"}>
653+
<Home />
654+
</Match>
655+
<Match when={route.data.type === "session"}>
656+
<Session />
657+
</Match>
658+
</Switch>
659+
</box>
660+
</box>
642661
</box>
643662
)
644663
}

packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,8 @@ export function Autocomplete(props: {
468468
onKeyDown(e: KeyEvent) {
469469
if (store.visible) {
470470
const name = e.name?.toLowerCase()
471-
const ctrlOnly = e.ctrl && !e.meta && !e.shift
472-
const isNavUp = name === "up" || (ctrlOnly && name === "p")
473-
const isNavDown = name === "down" || (ctrlOnly && name === "n")
471+
const isNavUp = name === "up"
472+
const isNavDown = name === "down"
474473

475474
if (isNavUp) {
476475
move(-1)

0 commit comments

Comments
 (0)