mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-07 02:51:50 +00:00
fix(tui): honor client copy shortcut over ssh
- accept forwarded Cmd+C for selection copy in SSH sessions even when Hermes runs on Linux - keep local Linux Alt+C from acting as copy and update TUI hotkey hints for remote shells
This commit is contained in:
parent
283c8fd6e2
commit
bcc5362432
4 changed files with 48 additions and 10 deletions
|
|
@ -31,6 +31,28 @@ describe('platform action modifier', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('isCopyShortcut', () => {
|
||||
it('keeps Ctrl+C as the local non-macOS copy chord', async () => {
|
||||
const { isCopyShortcut } = await importPlatform('linux')
|
||||
|
||||
expect(isCopyShortcut({ ctrl: true, meta: false, super: false }, 'c', {})).toBe(true)
|
||||
})
|
||||
|
||||
it('accepts client Cmd+C over SSH even when running on Linux', async () => {
|
||||
const { isCopyShortcut } = await importPlatform('linux')
|
||||
const env = { SSH_CONNECTION: '1 2 3 4' } as NodeJS.ProcessEnv
|
||||
|
||||
expect(isCopyShortcut({ ctrl: false, meta: false, super: true }, 'c', env)).toBe(true)
|
||||
expect(isCopyShortcut({ ctrl: false, meta: true, super: false }, 'c', env)).toBe(true)
|
||||
})
|
||||
|
||||
it('does not treat local Linux Alt+C as copy', async () => {
|
||||
const { isCopyShortcut } = await importPlatform('linux')
|
||||
|
||||
expect(isCopyShortcut({ ctrl: false, meta: true, super: false }, 'c', {})).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isVoiceToggleKey', () => {
|
||||
it('matches raw Ctrl+B on macOS (doc-default across platforms)', async () => {
|
||||
const { isVoiceToggleKey } = await importPlatform('darwin')
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import type {
|
|||
SudoRespondResponse,
|
||||
VoiceRecordResponse
|
||||
} from '../gatewayTypes.js'
|
||||
import { isAction, isMac, isVoiceToggleKey } from '../lib/platform.js'
|
||||
import { isAction, isCopyShortcut, isMac, isVoiceToggleKey } from '../lib/platform.js'
|
||||
|
||||
import { getInputSelection } from './inputSelectionStore.js'
|
||||
import type { InputHandlerContext, InputHandlerResult } from './interfaces.js'
|
||||
|
|
@ -315,7 +315,7 @@ export function useInputHandlers(ctx: InputHandlerContext): InputHandlerResult {
|
|||
}
|
||||
}
|
||||
|
||||
if (isAction(key, ch, 'c')) {
|
||||
if (isCopyShortcut(key, ch)) {
|
||||
if (terminal.hasSelection) {
|
||||
return copySelection()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,21 @@
|
|||
import { isMac } from '../lib/platform.js'
|
||||
|
||||
const isRemoteShell = Boolean(process.env.SSH_CONNECTION || process.env.SSH_CLIENT || process.env.SSH_TTY)
|
||||
const action = isMac ? 'Cmd' : 'Ctrl'
|
||||
const paste = isMac ? 'Cmd' : 'Alt'
|
||||
|
||||
const copyHotkeys: [string, string][] = isMac
|
||||
? [
|
||||
['Cmd+C', 'copy selection'],
|
||||
['Ctrl+C', 'interrupt / clear draft / exit']
|
||||
]
|
||||
: [
|
||||
...(isRemoteShell ? ([['Cmd+C', 'copy selection when forwarded by the terminal']] as [string, string][]) : []),
|
||||
['Ctrl+C', 'copy selection / interrupt / clear draft / exit']
|
||||
]
|
||||
|
||||
export const HOTKEYS: [string, string][] = [
|
||||
...(isMac
|
||||
? ([
|
||||
['Cmd+C', 'copy selection'],
|
||||
['Ctrl+C', 'interrupt / clear draft / exit']
|
||||
] as [string, string][])
|
||||
: ([['Ctrl+C', 'copy selection / interrupt / clear draft / exit']] as [string, string][])),
|
||||
...copyHotkeys,
|
||||
[action + '+D', 'exit'],
|
||||
[action + '+G', 'open $EDITOR for prompt'],
|
||||
[action + '+L', 'new session (clear)'],
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
* as `key.meta`. Some macOS terminals also translate Cmd+Left/Right/Backspace
|
||||
* into readline-style Ctrl+A/Ctrl+E/Ctrl+U before the app sees them.
|
||||
* On other platforms the action modifier is Ctrl.
|
||||
* Ctrl+C is ALWAYS the interrupt key regardless of platform — it must never be
|
||||
* remapped to copy.
|
||||
* Ctrl+C stays the interrupt key on macOS. On non-mac terminals it can also
|
||||
* copy an active TUI selection, matching common terminal selection behavior.
|
||||
*/
|
||||
|
||||
export const isMac = process.platform === 'darwin'
|
||||
|
|
@ -34,6 +34,16 @@ export const isMacActionFallback = (
|
|||
export const isAction = (key: { ctrl: boolean; meta: boolean; super?: boolean }, ch: string, target: string): boolean =>
|
||||
isActionMod(key) && ch.toLowerCase() === target
|
||||
|
||||
const isRemoteShell = (env: NodeJS.ProcessEnv = process.env): boolean =>
|
||||
Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.SSH_TTY)
|
||||
|
||||
export const isCopyShortcut = (
|
||||
key: { ctrl: boolean; meta: boolean; super?: boolean },
|
||||
ch: string,
|
||||
env: NodeJS.ProcessEnv = process.env
|
||||
): boolean =>
|
||||
isAction(key, ch, 'c') || (isRemoteShell(env) && (key.meta || key.super === true) && ch.toLowerCase() === 'c')
|
||||
|
||||
/**
|
||||
* Voice recording toggle key (Ctrl+B).
|
||||
*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue