From 002f8174f69f05069a16da0fcb5bb94a90680d72 Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Fri, 21 Aug 2026 18:16:46 +0000 Subject: [PATCH] feat(web): add rightPanel.openTerminal keybinding command terminal.new only creates a right-panel terminal when focus is already there (ChatView's terminalFocusOwner check), so there was no way to open a terminal in the right panel from the keyboard. Add a bindable rightPanel.openTerminal command, defaulting to mod+alt+j to mirror mod+alt+b for rightPanel.toggle, wired to the existing addTerminalSurface path. Cmd+J behavior is unchanged. Closes #4790 --- apps/web/src/components/ChatView.tsx | 7 +++++++ docs/user/keybindings.md | 3 +++ packages/contracts/src/keybindings.ts | 1 + packages/shared/src/keybindings.test.ts | 24 ++++++++++++++++++++++++ packages/shared/src/keybindings.ts | 1 + 5 files changed, 36 insertions(+) create mode 100644 packages/shared/src/keybindings.test.ts diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 0a8a71e781fb..f8b1ea94c332 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -4860,6 +4860,13 @@ function ChatViewContent(props: ChatViewProps) { return; } + if (command === "rightPanel.openTerminal") { + event.preventDefault(); + event.stopPropagation(); + addTerminalSurface(); + return; + } + if (command === "terminal.split") { event.preventDefault(); event.stopPropagation(); diff --git a/docs/user/keybindings.md b/docs/user/keybindings.md index 8e56a79a287d..2bb2db02a43f 100644 --- a/docs/user/keybindings.md +++ b/docs/user/keybindings.md @@ -52,6 +52,9 @@ successful pick; its hover glow and badge preview the element and color family t `rightPanel.toggleMaximized` maximizes or restores the open right panel. It has no default shortcut, so add one in **Settings** → **Keybindings** if you want to use it. +`rightPanel.openTerminal` opens a terminal as a right-panel surface for the active thread, +independent of the bottom drawer, and defaults to `mod+alt+j`. + The command palette searches active thread titles, projects, branches, user messages, and final agent responses across connected environments. Message matches show one labeled excerpt while keeping the thread's project, branch, and machine context visible. Message search begins after two diff --git a/packages/contracts/src/keybindings.ts b/packages/contracts/src/keybindings.ts index 19276c41e7b6..372106a525d4 100644 --- a/packages/contracts/src/keybindings.ts +++ b/packages/contracts/src/keybindings.ts @@ -56,6 +56,7 @@ export const STATIC_KEYBINDING_COMMANDS = [ "terminal.close", "rightPanel.toggle", "rightPanel.toggleMaximized", + "rightPanel.openTerminal", "diff.toggle", "preview.toggle", "preview.refresh", diff --git a/packages/shared/src/keybindings.test.ts b/packages/shared/src/keybindings.test.ts new file mode 100644 index 000000000000..95ecc4931c3c --- /dev/null +++ b/packages/shared/src/keybindings.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from "vite-plus/test"; + +import { DEFAULT_KEYBINDINGS, DEFAULT_RESOLVED_KEYBINDINGS } from "./keybindings.ts"; + +describe("DEFAULT_KEYBINDINGS", () => { + it("binds mod+alt+j to rightPanel.openTerminal", () => { + const rules = DEFAULT_KEYBINDINGS.filter((rule) => rule.command === "rightPanel.openTerminal"); + expect(rules).toEqual([{ key: "mod+alt+j", command: "rightPanel.openTerminal" }]); + }); + + it("resolves the rightPanel.openTerminal default binding", () => { + const binding = DEFAULT_RESOLVED_KEYBINDINGS.find( + (rule) => rule.command === "rightPanel.openTerminal", + ); + expect(binding?.shortcut).toEqual({ + key: "j", + metaKey: false, + ctrlKey: false, + shiftKey: false, + altKey: true, + modKey: true, + }); + }); +}); diff --git a/packages/shared/src/keybindings.ts b/packages/shared/src/keybindings.ts index 158a9ffb1ac9..a8e8e6d3bd73 100644 --- a/packages/shared/src/keybindings.ts +++ b/packages/shared/src/keybindings.ts @@ -22,6 +22,7 @@ export const DEFAULT_KEYBINDINGS: ReadonlyArray = [ { key: "mod+b", command: "sidebar.toggle" }, { key: "mod+j", command: "terminal.toggle" }, { key: "mod+alt+b", command: "rightPanel.toggle" }, + { key: "mod+alt+j", command: "rightPanel.openTerminal" }, { key: "mod+d", command: "terminal.split", when: "terminalFocus" }, { key: "mod+shift+d", command: "terminal.splitVertical", when: "terminalFocus" }, { key: "mod+n", command: "terminal.new", when: "terminalFocus" },