fix(app): wire or remove dead menu items and drop the New Session ⇧⌘S (#57919)

This commit is contained in:
Kit Langton
2026-10-21 15:00:14 -07:00
committed by GitHub
Unverified
parent cf562213a3
commit 7eb29f822c
11 changed files with 67 additions and 40 deletions
@@ -319,7 +319,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
sessionCommand({
id: "session.new",
title: language.t("command.session.new"),
keybind: "mod+shift+s",
slash: "new",
onSelect: (source) => command.trigger("tab.new", source),
}),
+3 -2
View File
@@ -3,6 +3,8 @@ import { useLanguage } from "@/runtime/i18n/language"
import { useSettingsSurface } from "./surface"
import type { SettingsRootTab } from "./surface"
export const settingsOpenCommand = { id: "settings.open", keybind: "mod+comma" }
export function useSettingsDialog(defaultValue?: SettingsRootTab) {
const settings = useSettingsSurface()
@@ -16,10 +18,9 @@ export function useSettingsCommand() {
command.register("settings", () => [
{
id: "settings.open",
...settingsOpenCommand,
title: language.t("command.settings.open"),
category: language.t("command.category.settings"),
keybind: "mod+comma",
onSelect: show,
},
])
@@ -0,0 +1,29 @@
import { expect, test } from "bun:test"
import terminal, { terminalToggleCommand } from "@opencode/gui-extensions/terminal"
import { settingsOpenCommand } from "@/settings/command"
import { sidebarToggleCommand } from "@/shell/shell"
import { previousSessionCommand, nextSessionCommand } from "@/shell/titlebar/tab-strip"
import { goBackCommand, goForwardCommand, newTabCommand } from "@/shell/titlebar/titlebar"
import { exportLogsCommand } from "./desktop"
import { DESKTOP_MENU } from "./desktop-menu"
test("every desktop menu command is one its owner registers", () => {
const registered = new Set([
settingsOpenCommand.id,
exportLogsCommand.id,
newTabCommand.id,
sidebarToggleCommand.id,
goBackCommand.id,
goForwardCommand.id,
previousSessionCommand.id,
nextSessionCommand.id,
// The host publishes extension commands as `${extension}.${id}`.
`${terminal.id}.${terminalToggleCommand.id}`,
])
const commands = DESKTOP_MENU.flatMap((menu) => menu.items ?? []).flatMap((entry) =>
entry.type === "item" && entry.command ? [entry.command] : [],
)
expect(commands.filter((command) => !registered.has(command))).toEqual([])
})
@@ -97,14 +97,8 @@ export const DESKTOP_MENU: DesktopMenu[] = [
{
type: "item",
labelKey: "desktop.menu.newSession",
command: "session.new",
accelerator: { macos: "Shift+Cmd+S" },
},
{
type: "item",
labelKey: "desktop.menu.openProject",
command: "project.open",
accelerator: { macos: "Cmd+O" },
command: "tab.new",
accelerator: { macos: "Cmd+N" },
},
{
type: "item",
@@ -183,7 +177,12 @@ export const DESKTOP_MENU: DesktopMenu[] = [
id: "view",
labelKey: "desktop.menu.view",
items: [
{ type: "item", labelKey: "desktop.menu.toggleSidebar", command: "sidebar.toggle" },
{
type: "item",
labelKey: "desktop.menu.toggleSidebar",
command: "sidebar.toggle",
accelerator: { macos: "Shift+Cmd+B" },
},
{
type: "item",
labelKey: "desktop.menu.toggleTerminal",
@@ -248,19 +247,6 @@ export const DESKTOP_MENU: DesktopMenu[] = [
command: "session.next",
accelerator: { macos: "Option+Down" },
},
{ type: "separator" },
{
type: "item",
labelKey: "desktop.menu.previousProject",
command: "project.previous",
accelerator: { macos: "Cmd+Option+Up" },
},
{
type: "item",
labelKey: "desktop.menu.nextProject",
command: "project.next",
accelerator: { macos: "Cmd+Option+Down" },
},
],
},
{
+3 -1
View File
@@ -2,6 +2,8 @@ import { useLanguage } from "@/runtime/i18n/language"
import { usePlatform } from "@/runtime/platform/platform"
import { useCommand, type CommandOption } from "./command"
export const exportLogsCommand = { id: "logs.export" }
export function DesktopCommands() {
const command = useCommand()
const language = useLanguage()
@@ -12,7 +14,7 @@ export function DesktopCommands() {
if (platform.platform !== "desktop" || !platform.exportDebugLogs) return commands
commands.push({
id: "logs.export",
...exportLogsCommand,
title: language.t("command.logs.export"),
category: language.t("command.category.settings"),
onSelect: () => void platform.exportDebugLogs?.(),
+3 -2
View File
@@ -17,6 +17,8 @@ import { CollapsedSidebarToggle, measureSidebarToggles, paintCollapsedSlots } fr
import { createPanelMotion, guardClosingFocus, replayPanelToggle } from "@/shell/panel-motion"
import { windowDragEnabled } from "@/session/header/drag-area"
export const sidebarToggleCommand = { id: "sidebar.toggle", keybind: "mod+shift+b" }
export default function Layout(props: ParentProps) {
const platform = usePlatform()
const settings = useSettingsSurface()
@@ -70,10 +72,9 @@ export default function Layout(props: ParentProps) {
verticalTabs()
? [
{
id: "sidebar.toggle",
...sidebarToggleCommand,
title: language.t("command.sidebar.toggle"),
category: language.t("command.category.view"),
keybind: "mod+shift+b",
onSelect: toggleSidebar,
},
]
@@ -27,6 +27,10 @@ import { errorMessage } from "@/shell/layout/helpers"
import { notifySessionTabsRemoved } from "./session-events"
import type { SessionInfo } from "@opencode/client/promise"
export const previousSessionCommand = { id: "session.previous", keybind: "alt+arrowup" }
export const nextSessionCommand = { id: "session.next", keybind: "alt+arrowdown" }
function SessionTabSlot(props: {
tab: SessionTab
id: string
@@ -410,17 +414,15 @@ export function TitlebarTabStrip(props: {
onSelect: () => selectAdjacentTab(1),
},
{
id: "session.previous",
...previousSessionCommand,
category: language.t("command.category.session"),
title: language.t("command.session.previous"),
keybind: "alt+arrowup",
onSelect: () => selectAdjacentTab(-1),
},
{
id: "session.next",
...nextSessionCommand,
category: language.t("command.category.session"),
title: language.t("command.session.next"),
keybind: "alt+arrowdown",
onSelect: () => selectAdjacentTab(1),
},
{
+9 -6
View File
@@ -37,6 +37,12 @@ import { useSettingsDialog } from "@/settings/command"
import { rootSession } from "@/shell/routes/session"
import { TitlebarItems, useTitlebarItems } from "@/runtime/extension/titlebar-items"
export const newTabCommand = { id: "tab.new", keybind: "mod+t,mod+n" }
export const goBackCommand = { id: "common.goBack", keybind: "mod+[" }
export const goForwardCommand = { id: "common.goForward", keybind: "mod+]" }
const titlebarHeight = 36
const windowsTitlebarHeight = 44 // Includes the content inset; matches the native Windows overlay.
@@ -141,17 +147,15 @@ export function Titlebar(props: { verticalTabs?: { mount?: HTMLElement } }) {
command.register(() => [
{
id: "common.goBack",
...goBackCommand,
title: language.t("common.goBack"),
category: language.t("command.category.view"),
keybind: "mod+[",
onSelect: back,
},
{
id: "common.goForward",
...goForwardCommand,
title: language.t("common.goForward"),
category: language.t("command.category.view"),
keybind: "mod+]",
onSelect: forward,
},
])
@@ -531,10 +535,9 @@ export function Titlebar(props: { verticalTabs?: { mount?: HTMLElement } }) {
return [
{
id: "tab.new",
...newTabCommand,
category: "tab",
title: language.t("command.session.new"),
keybind: "mod+t,mod+n",
hidden: true,
onSelect: openNewTab,
},
+1
View File
@@ -11,6 +11,7 @@
"./sdk": "./src/sdk/index.ts",
"./sdk/main": "./src/sdk/main.ts",
"./sdk/bridge": "./src/sdk/bridge.ts",
"./terminal": "./src/terminal/index.ts",
"./updater": "./src/updater/contract.ts"
},
"scripts": {
@@ -1,6 +1,9 @@
import { Extension } from "../sdk"
import en from "./i18n/en"
/** Published as `terminal.toggle`; the desktop menu names it. */
export const terminalToggleCommand = { id: "toggle", bind: "ctrl+`" }
export default Extension.define({
id: "terminal",
i18n: {
@@ -1,6 +1,7 @@
import { createMemo, lazy, on, onCleanup, Suspense } from "solid-js"
import { Command, createKeyed, MenuItem, onIdle, Panel, type MountedSession, type PanelTab, type Setup } from "../sdk"
import type Terminal from "./index"
import { terminalToggleCommand } from "./index"
import { createTerminalModel, type TerminalWorkspace } from "./model"
import { terminalTab, type LocalPTY } from "./state"
import { terminalTabLabel } from "./title"
@@ -68,12 +69,11 @@ const setup: Setup<typeof Terminal> = (ctx) => {
ctx.add(
Command,
(): Command => ({
id: "toggle",
...terminalToggleCommand,
title: ctx.t("command.toggle"),
group: ctx.t("command.category.view"),
section: "terminal",
featured: true,
bind: "ctrl+`",
slash: { name: "terminal", after: "open" },
editable: true,
enabled: routed(),