fix(dashboard): key the preview by the user's terminal shortcut policy

The preview passed 11 of the 12 inputs the pane's policy takes and let the
12th default to orca-first. Under terminal-first a remapped tab.close chord is
meant to yield to the shell — Ctrl+W is a word-kill there — but the preview
kept claiming it as a pane close and swallowed the bytes.
This commit is contained in:
Brennan Benson
2026-07-28 16:35:00 -07:00
parent 99214863b1
commit bb737b82e0
3 changed files with 42 additions and 3 deletions
@@ -227,7 +227,8 @@ export function AgentTerminalPreview({
macOptionAsAlt: macOptionAsAltRef.current,
keybindings: useAppStore.getState().keybindings,
terminalInput: terminalInputRef.current,
kittyKeyboardActive: () => kittyKeyboardModes.flags > 0
kittyKeyboardActive: () => kittyKeyboardModes.flags > 0,
terminalShortcutPolicy: settingsRef.current?.terminalShortcutPolicy
})
})
}
@@ -24,6 +24,7 @@ function contextFor(
keybindings: undefined,
terminalInput: LOCAL_MAC,
kittyKeyboardActive: () => overrides.kitty === true,
terminalShortcutPolicy: 'orca-first',
...overrides
}
}
@@ -110,6 +111,34 @@ describe('resolvePreviewShortcutAction', () => {
).toEqual({ type: 'splitActivePane', direction: 'vertical' })
})
// Why: a terminal-first user remapped terminal.closePane away, so only the
// tab.close alias still matches Ctrl+W — which the shell owns as a word-kill.
// The pane yields it; the preview must not swallow it.
it('follows the terminal shortcut policy for the tab.close pane-close alias', () => {
const keybindings = {
'terminal.closePane': ['Mod+Shift+W'],
'tab.close': ['Ctrl+W']
} as unknown as PreviewShortcutContext['keybindings']
const chord = (): KeyboardEvent => keydown({ key: 'w', code: 'KeyW', ctrlKey: true })
expect(
resolvePreviewShortcutAction(
chord(),
contextFor({ clientPlatform: 'linux', terminalInput: null, keybindings })
)
).toEqual({ type: 'closeActivePane' })
expect(
resolvePreviewShortcutAction(
chord(),
contextFor({
clientPlatform: 'linux',
terminalInput: null,
keybindings,
terminalShortcutPolicy: 'terminal-first'
})
)
).toBeNull()
})
it('leaves ordinary typing to xterm', () => {
expect(
resolvePreviewShortcutAction(keydown({ key: 'a', code: 'KeyA' }), contextFor())
@@ -5,7 +5,11 @@ import {
} from '@/components/terminal-pane/terminal-shortcut-policy'
import { getLayoutBaseCharacterForCode } from '@/lib/keyboard-layout/layout-base-character'
import type { DashboardCardTerminalInput } from '../../../../shared/dashboard-snapshot'
import type { KeybindingOverrides } from '../../../../shared/keybindings'
import {
normalizeTerminalShortcutPolicy,
type KeybindingOverrides,
type TerminalShortcutPolicy
} from '../../../../shared/keybindings'
export type PreviewShortcutContext = {
clientPlatform: NodeJS.Platform
@@ -17,6 +21,8 @@ export type PreviewShortcutContext = {
terminalInput: DashboardCardTerminalInput | null
/** Live kitty-protocol flags mirrored from this pty's output. */
kittyKeyboardActive: () => boolean
/** The user's setting; terminal-first yields the tab.close alias to the shell. */
terminalShortcutPolicy: TerminalShortcutPolicy | null | undefined
}
/**
@@ -44,6 +50,9 @@ export function resolvePreviewShortcutAction(
getLayoutBaseCharacterForCode,
() => context.terminalInput?.windowsShiftEnterEncoding ?? 'alt-enter',
// Why: byte protocols follow the pty's host, which differs from the client OS on remote runtimes.
() => hostPlatform === 'win32'
() => hostPlatform === 'win32',
// Why: without it a terminal-first user's remapped tab.close chord — Ctrl+W
// is a shell word-kill — reaches the shell in the pane but is swallowed here.
normalizeTerminalShortcutPolicy(context.terminalShortcutPolicy)
)
}