mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-04 02:21:47 +00:00
This PR groups the TUI fixes that restore macOS Terminal usability and clean up the theme/composer regressions: - copy transcript selections on macOS drag-release so Terminal.app users can copy while mouse tracking is enabled - copy composer selections on macOS drag-release; composer selection is internal to TextInput and does not use the global Ink selection bus - keep IDE Cmd+C forwarding setup macOS-only, and make keybinding conflict checks respect simple when-clause overlap/negation - force truecolor before chalk initializes (unless NO_COLOR / FORCE_COLOR / HERMES_TUI_TRUECOLOR opt-outs apply) so the default banner keeps its gold/amber/bronze gradient in Terminal.app - move TUI surfaces onto semantic theme tokens and preserve skin prompt symbols as bare tokens with renderer-owned spacing - render focused placeholders as dim hint text in TTY mode instead of inverse/selected-looking synthetic cursor text
109 lines
4.5 KiB
TypeScript
109 lines
4.5 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const originalPlatform = process.platform
|
|
|
|
async function importPlatform(platform: NodeJS.Platform) {
|
|
vi.resetModules()
|
|
Object.defineProperty(process, 'platform', { value: platform })
|
|
|
|
return import('../lib/platform.js')
|
|
}
|
|
|
|
afterEach(() => {
|
|
Object.defineProperty(process, 'platform', { value: originalPlatform })
|
|
vi.resetModules()
|
|
})
|
|
|
|
describe('platform action modifier', () => {
|
|
it('treats kitty Cmd sequences as the macOS action modifier', async () => {
|
|
const { isActionMod } = await importPlatform('darwin')
|
|
|
|
expect(isActionMod({ ctrl: false, meta: false, super: true })).toBe(true)
|
|
expect(isActionMod({ ctrl: false, meta: true, super: false })).toBe(true)
|
|
expect(isActionMod({ ctrl: true, meta: false, super: false })).toBe(false)
|
|
})
|
|
|
|
it('still uses Ctrl as the action modifier on non-macOS', async () => {
|
|
const { isActionMod } = await importPlatform('linux')
|
|
|
|
expect(isActionMod({ ctrl: true, meta: false, super: false })).toBe(true)
|
|
expect(isActionMod({ ctrl: false, meta: false, super: true })).toBe(false)
|
|
})
|
|
})
|
|
|
|
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)
|
|
})
|
|
|
|
it('accepts the VS Code/Cursor forwarded Cmd+C copy sequence on macOS', async () => {
|
|
const { isCopyShortcut } = await importPlatform('darwin')
|
|
|
|
expect(isCopyShortcut({ ctrl: true, meta: false, super: true }, 'c', {})).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('isVoiceToggleKey', () => {
|
|
it('matches raw Ctrl+B on macOS (doc-default across platforms)', async () => {
|
|
const { isVoiceToggleKey } = await importPlatform('darwin')
|
|
|
|
expect(isVoiceToggleKey({ ctrl: true, meta: false, super: false }, 'b')).toBe(true)
|
|
expect(isVoiceToggleKey({ ctrl: true, meta: false, super: false }, 'B')).toBe(true)
|
|
})
|
|
|
|
it('matches Cmd+B on macOS (preserve platform muscle memory)', async () => {
|
|
const { isVoiceToggleKey } = await importPlatform('darwin')
|
|
|
|
expect(isVoiceToggleKey({ ctrl: false, meta: true, super: false }, 'b')).toBe(true)
|
|
expect(isVoiceToggleKey({ ctrl: false, meta: false, super: true }, 'b')).toBe(true)
|
|
})
|
|
|
|
it('matches Ctrl+B on non-macOS platforms', async () => {
|
|
const { isVoiceToggleKey } = await importPlatform('linux')
|
|
|
|
expect(isVoiceToggleKey({ ctrl: true, meta: false, super: false }, 'b')).toBe(true)
|
|
})
|
|
|
|
it('does not match unmodified b or other Ctrl combos', async () => {
|
|
const { isVoiceToggleKey } = await importPlatform('darwin')
|
|
|
|
expect(isVoiceToggleKey({ ctrl: false, meta: false, super: false }, 'b')).toBe(false)
|
|
expect(isVoiceToggleKey({ ctrl: true, meta: false, super: false }, 'a')).toBe(false)
|
|
expect(isVoiceToggleKey({ ctrl: true, meta: false, super: false }, 'c')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('isMacActionFallback', () => {
|
|
it('routes raw Ctrl+K and Ctrl+W to readline kill-to-end / delete-word on macOS', async () => {
|
|
const { isMacActionFallback } = await importPlatform('darwin')
|
|
|
|
expect(isMacActionFallback({ ctrl: true, meta: false, super: false }, 'k', 'k')).toBe(true)
|
|
expect(isMacActionFallback({ ctrl: true, meta: false, super: false }, 'w', 'w')).toBe(true)
|
|
// Must not fire when Cmd (meta/super) is held — those are distinct chords.
|
|
expect(isMacActionFallback({ ctrl: true, meta: true, super: false }, 'k', 'k')).toBe(false)
|
|
expect(isMacActionFallback({ ctrl: true, meta: false, super: true }, 'w', 'w')).toBe(false)
|
|
})
|
|
|
|
it('is a no-op on non-macOS (Linux routes Ctrl+K/W through isActionMod directly)', async () => {
|
|
const { isMacActionFallback } = await importPlatform('linux')
|
|
|
|
expect(isMacActionFallback({ ctrl: true, meta: false, super: false }, 'k', 'k')).toBe(false)
|
|
expect(isMacActionFallback({ ctrl: true, meta: false, super: false }, 'w', 'w')).toBe(false)
|
|
})
|
|
})
|