fix(tui): address Copilot round-5 review on #19835
Three follow-ups on the voice matcher's modifier + shift discipline:
* **``super`` branch falsely fired on Alt+<key> / bare Esc on macOS.**
``isVoiceToggleKey`` accepted ``isMac && key.meta`` as a Cmd
fallback for the ``super`` modifier — but hermes-ink sets
``key.meta`` for plain Alt/Option AND for bare Escape on some
macOS terminals. A ``cmd+b`` config silently fired on Alt+B;
``cmd+space`` on Alt+Space; ``cmd+escape`` on bare Esc. Drop the
fallback and require the literal ``key.super`` bit. Legacy-
terminal users who need Cmd should upgrade to a kitty-protocol
terminal or bind ``alt+X`` explicitly.
* **Shift bit was never checked.** The parser rejects multi-
modifier configs like ``ctrl+shift+tab``, but the runtime
matcher didn't check ``key.shift`` — so ``ctrl+tab`` also fired
on Ctrl+Shift+Tab and ``alt+enter`` on Alt+Shift+Enter.
Early-return on ``key.shift === true`` so the runtime only fires
the exact chord the user configured.
* **Test leaked ``HERMES_VOICE=1`` into later tests.**
``voice.toggle`` action=on writes to ``os.environ`` directly
(CLI parity, runtime-only flag); ``test_voice_toggle_returns_
configured_record_key`` dispatched action=on without letting
monkeypatch take ownership of the var first. Any later test
that read voice mode in the same Python process could inherit a
stale enabled state. Added ``monkeypatch.setenv("HERMES_VOICE",
"0")`` up front so monkeypatch restores the original value at
teardown.
Coverage added:
* ``cmd+b`` / ``cmd+space`` / ``cmd+escape`` do NOT fire on
``key.meta``-only events on darwin.
* ``ctrl+tab`` / ``alt+enter`` / ``ctrl+o`` reject matches when
``key.shift`` is held; sanity cases without Shift still fire.
Suite: 585/585 TUI vitest green, 3/3 backend voice tests green,
tsc --noEmit clean.
This commit is contained in:
@@ -207,6 +207,42 @@ describe('parseVoiceRecordKey (#18994)', () => {
|
||||
expect(parseVoiceRecordKey('alt+c').mod).toBe('alt')
|
||||
expect(parseVoiceRecordKey('cmd+l').mod).toBe('super')
|
||||
})
|
||||
|
||||
// Round-5 Copilot review regressions on #19835.
|
||||
it('cmd+<key> does NOT fire on key.meta-only events (Alt+X false-fire guard)', async () => {
|
||||
const { isVoiceToggleKey, parseVoiceRecordKey } = await importPlatform('darwin')
|
||||
|
||||
// hermes-ink sets ``key.meta`` for Alt/Option AND for bare Esc on
|
||||
// some macOS terminals. The super branch used to accept
|
||||
// ``isMac && key.meta`` as a Cmd fallback, which made cmd+<key>
|
||||
// bindings silently fire on Alt+<key> / bare Esc.
|
||||
const cmdB = parseVoiceRecordKey('cmd+b')
|
||||
const cmdSpace = parseVoiceRecordKey('cmd+space')
|
||||
const cmdEscape = parseVoiceRecordKey('cmd+escape')
|
||||
|
||||
expect(isVoiceToggleKey({ ctrl: false, meta: true, super: false }, 'b', cmdB)).toBe(false)
|
||||
expect(isVoiceToggleKey({ ctrl: false, meta: true, super: false }, ' ', cmdSpace)).toBe(false)
|
||||
expect(isVoiceToggleKey({ ctrl: false, escape: true, meta: true, super: false }, '', cmdEscape)).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects matches when Shift is held (different chord than configured)', async () => {
|
||||
const { isVoiceToggleKey, parseVoiceRecordKey } = await importPlatform('linux')
|
||||
|
||||
// Parser rejects multi-modifier configs like ``ctrl+shift+tab``,
|
||||
// so the runtime matcher must also reject Shift-held events —
|
||||
// otherwise ``ctrl+tab`` would fire on Ctrl+Shift+Tab.
|
||||
const ctrlTab = parseVoiceRecordKey('ctrl+tab')
|
||||
const altEnter = parseVoiceRecordKey('alt+enter')
|
||||
const ctrlO = parseVoiceRecordKey('ctrl+o')
|
||||
|
||||
expect(isVoiceToggleKey({ ctrl: true, meta: false, shift: true, super: false, tab: true }, '', ctrlTab)).toBe(false)
|
||||
expect(isVoiceToggleKey({ alt: true, ctrl: false, meta: false, return: true, shift: true, super: false }, '', altEnter)).toBe(false)
|
||||
expect(isVoiceToggleKey({ ctrl: true, meta: false, shift: true, super: false }, 'o', ctrlO)).toBe(false)
|
||||
|
||||
// Sanity: same events without Shift still fire.
|
||||
expect(isVoiceToggleKey({ ctrl: true, meta: false, shift: false, super: false, tab: true }, '', ctrlTab)).toBe(true)
|
||||
expect(isVoiceToggleKey({ ctrl: true, meta: false, shift: false, super: false }, 'o', ctrlO)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('formatVoiceRecordKey (#18994)', () => {
|
||||
@@ -332,15 +368,17 @@ describe('isVoiceToggleKey honours configured record key (#18994)', () => {
|
||||
expect(isVoiceToggleKey({ ctrl: true, meta: false, super: false }, 'o', ctrlO)).toBe(true)
|
||||
})
|
||||
|
||||
it('cmd+b renders "Cmd+B" and matches key.super OR (macOS) key.meta', async () => {
|
||||
it('cmd+b renders "Cmd+B" and requires the literal key.super bit', async () => {
|
||||
const { formatVoiceRecordKey, isVoiceToggleKey, parseVoiceRecordKey } = await importPlatform('darwin')
|
||||
const cmdB = parseVoiceRecordKey('cmd+b')
|
||||
|
||||
expect(formatVoiceRecordKey(cmdB)).toBe('Cmd+B')
|
||||
// Kitty-style: key.super
|
||||
// Kitty-style: key.super fires the binding.
|
||||
expect(isVoiceToggleKey({ ctrl: false, meta: false, super: true }, 'b', cmdB)).toBe(true)
|
||||
// Legacy macOS terminal: key.meta
|
||||
expect(isVoiceToggleKey({ ctrl: false, meta: true, super: false }, 'b', cmdB)).toBe(true)
|
||||
// ``key.meta`` is NOT accepted — hermes-ink uses meta for Alt too,
|
||||
// so accepting it here would make cmd+b silently fire on Alt+B
|
||||
// (Copilot round-5 review on #19835).
|
||||
expect(isVoiceToggleKey({ ctrl: false, meta: true, super: false }, 'b', cmdB)).toBe(false)
|
||||
// Ctrl held at the same time → reject (different chord).
|
||||
expect(isVoiceToggleKey({ ctrl: true, meta: false, super: true }, 'b', cmdB)).toBe(false)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user