Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
b94a3cf
Persist sidebar section expansion states
ariane-emory Dec 18, 2025
4fa52a6
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 18, 2025
aad1b9c
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 19, 2025
de9ca7c
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 19, 2025
8f188c6
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 20, 2025
1a1c89a
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 20, 2025
0f2e631
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 21, 2025
8c864f6
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 24, 2025
81eceaf
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 24, 2025
4e7468b
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 25, 2025
9f4578f
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 25, 2025
7980530
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 25, 2025
375d567
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 26, 2025
4cdb6f0
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 27, 2025
b82debc
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 27, 2025
4c9f4f0
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 27, 2025
1e28f63
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 28, 2025
5b8e20b
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 28, 2025
f490e08
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 28, 2025
ab87128
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 29, 2025
57c3f79
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 29, 2025
c77546c
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 29, 2025
0c79c38
Merge branch 'feat/persist-sidebar-group-folding-states' of github.co…
ariane-emory Dec 29, 2025
8481999
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 29, 2025
3d4d474
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 29, 2025
c8ba7bb
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 30, 2025
44ccf5f
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 30, 2025
f5e676a
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 30, 2025
2b06c0b
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 30, 2025
37d6ff1
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 30, 2025
c74d6e4
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Dec 31, 2025
9800155
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 1, 2026
e895ab2
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 1, 2026
4538971
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 1, 2026
6e3a4ce
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 2, 2026
8a47141
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 3, 2026
9439754
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 3, 2026
2e93a73
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 4, 2026
815e29d
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 4, 2026
d0a53b9
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 4, 2026
8c51a0c
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 5, 2026
36a18e0
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 5, 2026
ed61e9d
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 5, 2026
45bc26f
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 5, 2026
04c8a85
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 6, 2026
acdba0f
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 6, 2026
d0ab369
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 6, 2026
a73220d
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 6, 2026
3f9e282
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 6, 2026
c72c8af
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 7, 2026
9724021
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 7, 2026
ea4a2f2
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 7, 2026
6b03e9d
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 8, 2026
60f1047
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 11, 2026
735707f
Merge latest dev changes into feat/persist-sidebar-group-folding-states
ariane-emory Jan 13, 2026
21b43d6
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 13, 2026
9e3cdb4
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 13, 2026
9df6a67
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 15, 2026
1cb1e04
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 16, 2026
f67bff0
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 17, 2026
4dbae2b
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 17, 2026
7985b26
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 19, 2026
5d5b5dd
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 19, 2026
851be80
Merge branch 'dev' into feat/persist-sidebar-group-folding-states
ariane-emory Jan 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/opencode/src/cli/cmd/tui/context/kv.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ export const { use: useKV, provider: KVProvider } = createSimpleContext({
const [ready, setReady] = createSignal(false)
const [store, setStore] = createStore<Record<string, any>>()
const file = Bun.file(path.join(Global.Path.state, "kv.json"))
let rawData: Record<string, any> = {}

file
.json()
.then((x) => {
rawData = x
setStore(x)
})
.catch(() => {})
Expand Down Expand Up @@ -44,7 +46,8 @@ export const { use: useKV, provider: KVProvider } = createSimpleContext({
},
set(key: string, value: any) {
setStore(key, value)
Bun.write(file, JSON.stringify(store, null, 2))
rawData[key] = value
Bun.write(file, JSON.stringify(rawData, null, 2))
},
}
return result
Expand Down
35 changes: 25 additions & 10 deletions packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { useSync } from "@tui/context/sync"
import { createMemo, For, Show, Switch, Match } from "solid-js"
import { createEffect, createMemo, For, Show, Switch, Match } from "solid-js"
import { createStore } from "solid-js/store"
import { useTheme } from "../../context/theme"
import { Locale } from "@/util/locale"
import path from "path"
import type { AssistantMessage } from "@opencode-ai/sdk/v2"
import { Global } from "@/global"
import { Installation } from "@/installation"
import { useKeybind } from "../../context/keybind"
import { useDirectory } from "../../context/directory"
import { useKV } from "../../context/kv"
import { TodoItem } from "../../component/todo-item"

export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
const sync = useSync()
const { theme } = useTheme()
const directory = useDirectory()
const kv = useKV()
const session = createMemo(() => sync.session.get(props.sessionID)!)
const diff = createMemo(() => sync.data.session_diff[props.sessionID] ?? [])
const todo = createMemo(() => sync.data.todo[props.sessionID] ?? [])
Expand All @@ -27,6 +27,24 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
lsp: true,
})

// Load saved sidebar expansion states from KV store when ready
createEffect(() => {
if (kv.ready) {
setExpanded({
mcp: kv.get("sidebar_expanded_mcp", true),
diff: kv.get("sidebar_expanded_diff", true),
todo: kv.get("sidebar_expanded_todo", true),
lsp: kv.get("sidebar_expanded_lsp", true),
})
}
})

// Wrapper that persists expansion state to KV store
const setExpandedWithPersist = (key: "mcp" | "diff" | "todo" | "lsp", value: boolean) => {
setExpanded(key, value)
kv.set(`sidebar_expanded_${key}`, value)
}

// Sort MCP servers alphabetically for consistent display order
const mcpEntries = createMemo(() => Object.entries(sync.data.mcp).sort(([a], [b]) => a.localeCompare(b)))

Expand Down Expand Up @@ -60,9 +78,6 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
}
})

const directory = useDirectory()
const kv = useKV()

const hasProviders = createMemo(() =>
sync.data.provider.some((x) => x.id !== "opencode" || Object.values(x.models).some((y) => y.cost?.input !== 0)),
)
Expand Down Expand Up @@ -103,7 +118,7 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
<box
flexDirection="row"
gap={1}
onMouseDown={() => mcpEntries().length > 2 && setExpanded("mcp", !expanded.mcp)}
onMouseDown={() => mcpEntries().length > 2 && setExpandedWithPersist("mcp", !expanded.mcp)}
>
<Show when={mcpEntries().length > 2}>
<text fg={theme.text}>{expanded.mcp ? "▼" : "▶"}</text>
Expand Down Expand Up @@ -163,7 +178,7 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
<box
flexDirection="row"
gap={1}
onMouseDown={() => sync.data.lsp.length > 2 && setExpanded("lsp", !expanded.lsp)}
onMouseDown={() => sync.data.lsp.length > 2 && setExpandedWithPersist("lsp", !expanded.lsp)}
>
<Show when={sync.data.lsp.length > 2}>
<text fg={theme.text}>{expanded.lsp ? "▼" : "▶"}</text>
Expand Down Expand Up @@ -207,7 +222,7 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
<box
flexDirection="row"
gap={1}
onMouseDown={() => todo().length > 2 && setExpanded("todo", !expanded.todo)}
onMouseDown={() => todo().length > 2 && setExpandedWithPersist("todo", !expanded.todo)}
>
<Show when={todo().length > 2}>
<text fg={theme.text}>{expanded.todo ? "▼" : "▶"}</text>
Expand All @@ -226,7 +241,7 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
<box
flexDirection="row"
gap={1}
onMouseDown={() => diff().length > 2 && setExpanded("diff", !expanded.diff)}
onMouseDown={() => diff().length > 2 && setExpandedWithPersist("diff", !expanded.diff)}
>
<Show when={diff().length > 2}>
<text fg={theme.text}>{expanded.diff ? "▼" : "▶"}</text>
Expand Down