fix(tui): address Copilot review on editor handoff

- resolveEditor() now returns argv (string[]) so EDITOR='code --wait'
  and VISUAL='emacsclient -t' tokenize correctly into spawnSync's
  separate command + args. Previously the whole string was passed as
  argv[0] and would ENOENT.
- Skip the POSIX X_OK PATH walk on Windows; return ['notepad.exe']
  there since fs.constants.X_OK is not meaningful and PATHEXT-based
  resolution would need its own implementation.
- Surface openEditor() rejections via actions.sys instead of letting
  them become unhandled promise rejections in the useInput callback.
- Hotkey docs/comment now say Cmd/Ctrl+G to match isAction()'s
  platform-action-modifier behavior (Cmd on macOS, Ctrl elsewhere).
This commit is contained in:
Brooklyn Nicholson 2026-04-25 20:34:24 -05:00
parent 83129e72de
commit 14dd8e9a72
6 changed files with 50 additions and 24 deletions

View file

@ -257,13 +257,14 @@ export function useComposerState({
const openEditor = useCallback(async () => {
const dir = mkdtempSync(join(tmpdir(), 'hermes-'))
const file = join(dir, 'prompt.md')
const [cmd, ...args] = resolveEditor()
writeFileSync(file, [...inputBuf, input].join('\n'))
let exitCode: null | number = null
await withInkSuspended(async () => {
exitCode = spawnSync(resolveEditor(), [file], { stdio: 'inherit' }).status
exitCode = spawnSync(cmd!, [...args, file], { stdio: 'inherit' }).status
})
try {

View file

@ -366,10 +366,13 @@ export function useInputHandlers(ctx: InputHandlerContext): InputHandlerResult {
return voiceRecordToggle()
}
// Ctrl+G, plus Alt+G fallback for VSCode/Cursor (they bind Ctrl+G to
// "Find Next" before the TUI sees it; Alt+G arrives as meta+g).
// Cmd/Ctrl+G, plus Alt+G fallback for VSCode/Cursor (they bind the
// primary keystroke to "Find Next" before the TUI sees it; Alt+G
// arrives as meta+g across platforms).
if (ch.toLowerCase() === 'g' && (isAction(key, ch, 'g') || key.meta)) {
return cActions.openEditor()
return void cActions.openEditor().catch((err: unknown) => {
actions.sys(err instanceof Error ? `failed to open editor: ${err.message}` : 'failed to open editor')
})
}
// shift-tab flips yolo without spending a turn (claude-code parity)