From b02e276d9c47011727f9b18c4308a13568d3b5d0 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Thu, 12 Feb 2026 21:13:14 -0500 Subject: [PATCH 1/9] fix(tui): move KV-persisted toggles from Session to System category Move four command palette items that persist via KV store from the session route to the app level so they are available at all times: - Show/Hide timestamps - Show/Hide thinking - Show/Hide tool details - Show/Hide header These toggles persist across sessions via kv.json, so they belong in the System category and should be accessible even before a session starts. Resolves #158 --- packages/opencode/src/cli/cmd/tui/app.tsx | 47 +++++++++++++++++++ .../src/cli/cmd/tui/routes/session/index.tsx | 46 ------------------ 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index dbad3f699fc6..cc621e4eab6b 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -620,6 +620,53 @@ function App() { dialog.clear() }, }, + { + title: kv.get("timestamps", "hide") === "show" ? "Hide timestamps" : "Show timestamps", + value: "app.toggle.timestamps", + category: "System", + slash: { + name: "timestamps", + aliases: ["toggle-timestamps"], + }, + onSelect: (dialog) => { + const current = kv.get("timestamps", "hide") + kv.set("timestamps", current === "show" ? "hide" : "show") + dialog.clear() + }, + }, + { + title: kv.get("thinking_visibility", true) ? "Hide thinking" : "Show thinking", + value: "app.toggle.thinking", + keybind: "display_thinking", + category: "System", + slash: { + name: "thinking", + aliases: ["toggle-thinking"], + }, + onSelect: (dialog) => { + kv.set("thinking_visibility", !kv.get("thinking_visibility", true)) + dialog.clear() + }, + }, + { + title: kv.get("tool_details_visibility", true) ? "Hide tool details" : "Show tool details", + value: "app.toggle.tooldetails", + keybind: "tool_details", + category: "System", + onSelect: (dialog) => { + kv.set("tool_details_visibility", !kv.get("tool_details_visibility", true)) + dialog.clear() + }, + }, + { + title: kv.get("header_visible", true) ? "Hide header" : "Show header", + value: "app.toggle.header", + category: "System", + onSelect: (dialog) => { + kv.set("header_visible", !kv.get("header_visible", true)) + dialog.clear() + }, + }, ]) createEffect(() => { diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index b843bda1c9db..0204795baa68 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -536,43 +536,6 @@ export function Session() { dialog.clear() }, }, - { - title: showTimestamps() ? "Hide timestamps" : "Show timestamps", - value: "session.toggle.timestamps", - category: "Session", - slash: { - name: "timestamps", - aliases: ["toggle-timestamps"], - }, - onSelect: (dialog) => { - setTimestamps((prev) => (prev === "show" ? "hide" : "show")) - dialog.clear() - }, - }, - { - title: showThinking() ? "Hide thinking" : "Show thinking", - value: "session.toggle.thinking", - keybind: "display_thinking", - category: "Session", - slash: { - name: "thinking", - aliases: ["toggle-thinking"], - }, - onSelect: (dialog) => { - setShowThinking((prev) => !prev) - dialog.clear() - }, - }, - { - title: showDetails() ? "Hide tool details" : "Show tool details", - value: "session.toggle.actions", - keybind: "tool_details", - category: "Session", - onSelect: (dialog) => { - setShowDetails((prev) => !prev) - dialog.clear() - }, - }, { title: "Toggle session scrollbar", value: "session.toggle.scrollbar", @@ -583,15 +546,6 @@ export function Session() { dialog.clear() }, }, - { - title: showHeader() ? "Hide header" : "Show header", - value: "session.toggle.header", - category: "Session", - onSelect: (dialog) => { - setShowHeader((prev) => !prev) - dialog.clear() - }, - }, { title: "Page up", value: "session.page.up", From d3c06767798a8440ae2b519444be44dddca063bb Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Mon, 2 Mar 2026 02:40:54 -0500 Subject: [PATCH 2/9] fix: move 'Show generic tool output' from Session to System category --- packages/opencode/src/cli/cmd/tui/routes/session/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 88be7e45fcab..4900f70fad45 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -571,7 +571,7 @@ export function Session() { { title: showGenericToolOutput() ? "Hide generic tool output" : "Show generic tool output", value: "session.toggle.generic_tool_output", - category: "Session", + category: "System", onSelect: (dialog) => { setShowGenericToolOutput((prev) => !prev) dialog.clear() From 31b6e1341a9a941b4c8c0d0acd61a5979bebb2e5 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Mon, 2 Mar 2026 21:40:00 -0500 Subject: [PATCH 3/9] feat: move session scrollbar toggle to System category with conditional title --- packages/opencode/src/cli/cmd/tui/routes/session/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 4900f70fad45..312a47c29db3 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -550,10 +550,10 @@ export function Session() { }, }, { - title: "Toggle session scrollbar", + title: showScrollbar() ? "Hide session scrollbar" : "Show session scrollbar", value: "session.toggle.scrollbar", keybind: "scrollbar_toggle", - category: "Session", + category: "System", onSelect: (dialog) => { setShowScrollbar((prev) => !prev) dialog.clear() From fe5490dc503f4db355003ac08847dff35d1ee0bb Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Fri, 6 Mar 2026 11:45:45 -0500 Subject: [PATCH 4/9] fix: Move sidebar and header toggles to System category (completes command-palette-consistecy intent) --- packages/opencode/src/cli/cmd/tui/routes/session/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 478e5c501bfe..728ccd9a51da 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -553,7 +553,7 @@ export function Session() { title: sidebarVisible() ? "Hide sidebar" : "Show sidebar", value: "session.sidebar.toggle", keybind: "sidebar_toggle", - category: "Session", + category: "System", onSelect: (dialog) => { batch(() => { const isVisible = sidebarVisible() @@ -586,7 +586,7 @@ export function Session() { { title: showHeader() ? "Hide header" : "Show header", value: "session.toggle.header", - category: "Session", + category: "System", onSelect: (dialog) => { setShowHeader((prev) => !prev) dialog.clear() From 30d19f493a0071f60045f8e8e6fa3e8ed435723e Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Fri, 6 Mar 2026 13:39:39 -0500 Subject: [PATCH 5/9] Complete command palette consistency: move scrollbar and generic_tool_output to app.tsx, remove duplicates from session/index.tsx --- packages/opencode/src/cli/cmd/tui/app.tsx | 19 +++++++++++++ .../src/cli/cmd/tui/routes/session/index.tsx | 28 ------------------- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 5cd79a0bd4d2..19058916aedf 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -704,6 +704,25 @@ function App() { dialog.clear() }, }, + { + title: kv.get("scrollbar_visible", true) ? "Hide session scrollbar" : "Show session scrollbar", + value: "app.toggle.scrollbar", + keybind: "scrollbar_toggle", + category: "System", + onSelect: (dialog) => { + kv.set("scrollbar_visible", !kv.get("scrollbar_visible", true)) + dialog.clear() + }, + }, + { + title: kv.get("generic_tool_output_visibility", false) ? "Hide generic tool output" : "Show generic tool output", + value: "app.toggle.generic_tool_output", + category: "System", + onSelect: (dialog) => { + kv.set("generic_tool_output_visibility", !kv.get("generic_tool_output_visibility", false)) + dialog.clear() + }, + }, ]) createEffect(() => { diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 728ccd9a51da..f56f50e35a70 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -573,34 +573,6 @@ export function Session() { dialog.clear() }, }, - { - title: showScrollbar() ? "Hide session scrollbar" : "Show session scrollbar", - value: "session.toggle.scrollbar", - keybind: "scrollbar_toggle", - category: "System", - onSelect: (dialog) => { - setShowScrollbar((prev) => !prev) - dialog.clear() - }, - }, - { - title: showHeader() ? "Hide header" : "Show header", - value: "session.toggle.header", - category: "System", - onSelect: (dialog) => { - setShowHeader((prev) => !prev) - dialog.clear() - }, - }, - { - title: showGenericToolOutput() ? "Hide generic tool output" : "Show generic tool output", - value: "session.toggle.generic_tool_output", - category: "System", - onSelect: (dialog) => { - setShowGenericToolOutput((prev) => !prev) - dialog.clear() - }, - }, { title: "Page up", value: "session.page.up", From 09cfecdeb9063863232737ff6556235b9eec6bfa Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Sun, 8 Mar 2026 11:48:25 -0400 Subject: [PATCH 6/9] fix: move sidebar_toggle command to app.tsx as System command Move the sidebar_toggle command from session/index.tsx to app.tsx to properly categorize it as a System command. The command now uses kv.get()/kv.set() to persist the sidebar visibility state across sessions, following the same pattern as other moved commands (timestamps, thinking, tool details, etc.). Changes: - Remove sidebar_toggle from session/index.tsx - Add sidebar_toggle to app.tsx with proper kv-based implementation - Update value from 'session.sidebar.toggle' to 'app.toggle.sidebar' --- packages/opencode/src/cli/cmd/tui/app.tsx | 11 +++++++++++ .../src/cli/cmd/tui/routes/session/index.tsx | 14 -------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 19058916aedf..5752e84ae280 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -723,6 +723,17 @@ function App() { dialog.clear() }, }, + { + title: kv.get("sidebar", "auto") === "auto" ? "Hide sidebar" : "Show sidebar", + value: "app.toggle.sidebar", + keybind: "sidebar_toggle", + category: "System", + onSelect: (dialog) => { + const current = kv.get("sidebar", "auto") + kv.set("sidebar", current === "auto" ? "hide" : "auto") + dialog.clear() + }, + }, ]) createEffect(() => { diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index f56f50e35a70..b569ffd14424 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -549,20 +549,6 @@ export function Session() { }) }, }, - { - title: sidebarVisible() ? "Hide sidebar" : "Show sidebar", - value: "session.sidebar.toggle", - keybind: "sidebar_toggle", - category: "System", - onSelect: (dialog) => { - batch(() => { - const isVisible = sidebarVisible() - setSidebar(() => (isVisible ? "hide" : "auto")) - setSidebarOpen(!isVisible) - }) - dialog.clear() - }, - }, { title: conceal() ? "Disable code concealment" : "Enable code concealment", value: "session.toggle.conceal", From 34b2345e05dcd16dc3c7c3aacb95479b874f6483 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Tue, 24 Mar 2026 22:19:28 -0400 Subject: [PATCH 7/9] test: add regression tests for command palette consistency Add tests to prevent duplicate command palette items from reappearing in the Session category after being moved to the System category. The tests verify: 1. session/index.tsx does not contain session.toggle.* values 2. app.tsx contains the corresponding app.toggle.* values This prevents the duplication issue that occurred when merging the command palette consistency changes. --- .../tui/command-palette-consistency.test.ts | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 packages/opencode/test/cli/cmd/tui/command-palette-consistency.test.ts diff --git a/packages/opencode/test/cli/cmd/tui/command-palette-consistency.test.ts b/packages/opencode/test/cli/cmd/tui/command-palette-consistency.test.ts new file mode 100644 index 000000000000..6f18f588d741 --- /dev/null +++ b/packages/opencode/test/cli/cmd/tui/command-palette-consistency.test.ts @@ -0,0 +1,53 @@ +import { describe, expect, test } from "bun:test" +import { readFileSync } from "fs" +import { join } from "path" + +describe("command palette consistency", () => { + const sessionPath = join( + __dirname, + "../../../../src/cli/cmd/tui/routes/session/index.tsx", + ) + const appPath = join( + __dirname, + "../../../../src/cli/cmd/tui/app.tsx", + ) + + test("session/index.tsx should not have session.toggle.* or session.sidebar.toggle commands", () => { + const content = readFileSync(sessionPath, "utf-8") + + // These patterns should NOT exist in session/index.tsx + // They should be in app.tsx as app.toggle.* + const forbiddenPatterns = [ + 'value: "session.toggle.timestamps"', + 'value: "session.toggle.thinking"', + 'value: "session.toggle.actions"', + 'value: "session.toggle.scrollbar"', + 'value: "session.toggle.header"', + 'value: "session.toggle.generic_tool_output"', + 'value: "session.sidebar.toggle"', + ] + + for (const pattern of forbiddenPatterns) { + expect(content).not.toContain(pattern) + } + }) + + test("app.tsx should have corresponding app.toggle.* commands", () => { + const content = readFileSync(appPath, "utf-8") + + // These patterns should exist in app.tsx + const expectedPatterns = [ + 'value: "app.toggle.timestamps"', + 'value: "app.toggle.thinking"', + 'value: "app.toggle.tooldetails"', + 'value: "app.toggle.scrollbar"', + 'value: "app.toggle.header"', + 'value: "app.toggle.generic_tool_output"', + 'value: "app.toggle.sidebar"', + ] + + for (const pattern of expectedPatterns) { + expect(content).toContain(pattern) + } + }) +}) From 78f7e826c8a4b2629927c8f05d3e17f355dfd692 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Mon, 6 Apr 2026 13:06:58 -0400 Subject: [PATCH 8/9] fix(tui): remove dead header toggle --- packages/opencode/src/cli/cmd/tui/app.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 5a0f2ae0a36b..8055933597ea 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -822,15 +822,6 @@ function App(props: { onSnapshot?: () => Promise }) { dialog.clear() }, }, - { - title: kv.get("header_visible", true) ? "Hide header" : "Show header", - value: "app.toggle.header", - category: "System", - onSelect: (dialog) => { - kv.set("header_visible", !kv.get("header_visible", true)) - dialog.clear() - }, - }, { title: kv.get("scrollbar_visible", true) ? "Hide session scrollbar" : "Show session scrollbar", value: "app.toggle.scrollbar", From a0165409e9b48020556653d3d135f9575a142523 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Mon, 6 Apr 2026 13:10:07 -0400 Subject: [PATCH 9/9] test(tui): drop stale header toggle assertions --- .../cli/cmd/tui/command-palette-consistency.test.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/opencode/test/cli/cmd/tui/command-palette-consistency.test.ts b/packages/opencode/test/cli/cmd/tui/command-palette-consistency.test.ts index 6f18f588d741..441e3583b711 100644 --- a/packages/opencode/test/cli/cmd/tui/command-palette-consistency.test.ts +++ b/packages/opencode/test/cli/cmd/tui/command-palette-consistency.test.ts @@ -14,7 +14,7 @@ describe("command palette consistency", () => { test("session/index.tsx should not have session.toggle.* or session.sidebar.toggle commands", () => { const content = readFileSync(sessionPath, "utf-8") - + // These patterns should NOT exist in session/index.tsx // They should be in app.tsx as app.toggle.* const forbiddenPatterns = [ @@ -22,11 +22,10 @@ describe("command palette consistency", () => { 'value: "session.toggle.thinking"', 'value: "session.toggle.actions"', 'value: "session.toggle.scrollbar"', - 'value: "session.toggle.header"', 'value: "session.toggle.generic_tool_output"', 'value: "session.sidebar.toggle"', ] - + for (const pattern of forbiddenPatterns) { expect(content).not.toContain(pattern) } @@ -34,18 +33,17 @@ describe("command palette consistency", () => { test("app.tsx should have corresponding app.toggle.* commands", () => { const content = readFileSync(appPath, "utf-8") - + // These patterns should exist in app.tsx const expectedPatterns = [ 'value: "app.toggle.timestamps"', 'value: "app.toggle.thinking"', 'value: "app.toggle.tooldetails"', 'value: "app.toggle.scrollbar"', - 'value: "app.toggle.header"', 'value: "app.toggle.generic_tool_output"', 'value: "app.toggle.sidebar"', ] - + for (const pattern of expectedPatterns) { expect(content).toContain(pattern) }