feat(cli): add /update slash command to CLI and TUI (#23854)
* feat: add /update slash command to CLI and TUI * test(cli): add Python tests for /update slash command Co-authored-by: Cursor <cursoragent@cursor.com> * fix(cli): address Copilot review for /update slash command Route classic CLI /update through prompt_toolkit modal confirmation and defer relaunch to the main-thread cleanup path after app.exit(). Tighten Y/n semantics, add Python wrapper and catalog coverage tests, and assert /update stays visible in the TUI command catalog. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(cli): address review feedback on /update command - Replace raw input() with _prompt_text_input_modal in _handle_update_command to avoid EOF/hang/keystroke-leak races with prompt_toolkit's stdin ownership - Fix confirmation logic: only proceed on recognized affirmative aliases (y/yes/1/ok); cancel on everything else including empty string, typos, and unrecognized input — matches all other [Y/n] prompts in the codebase - Route relaunch through main-thread shutdown path: set _pending_relaunch and return False from process_command so process_loop triggers app.exit(); run() then calls relaunch() after prompt_toolkit has restored terminal modes and after cleanup — safe on both POSIX (execvp) and Windows (subprocess+exit) - Fix misleading docstring in test_update_command.py: the Vitest only covers the TypeScript slash handler that emits code 42, not the Python wrapper branch that acts on it - Rewrite tests to use SimpleNamespace pattern (like test_destructive_slash_confirm) so _prompt_text_input_modal can be stubbed directly - Add Python test for _launch_tui exit-code-42 → relaunch branch in main.py Agent-Logs-Url: https://github.com/NousResearch/hermes-agent/sessions/f6da68cf-e7b1-4b7a-aed6-3d4b0f523bdb Co-authored-by: austinpickett <260188+austinpickett@users.noreply.github.com> * fix(cli): polish test fixtures for /update command - Remove unused _prompt_text_input from SimpleNamespace stub - Use pytest.fail sentinel in managed-install guard test to catch unexpected modal invocations Agent-Logs-Url: https://github.com/NousResearch/hermes-agent/sessions/f6da68cf-e7b1-4b7a-aed6-3d4b0f523bdb Co-authored-by: austinpickett <260188+austinpickett@users.noreply.github.com> * chore: re-trigger CI after Copilot review fixes Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: austinpickett <260188+austinpickett@users.noreply.github.com>
This commit is contained in:
@@ -277,6 +277,7 @@ export interface SlashHandlerContext {
|
||||
session: {
|
||||
closeSession: (targetSid?: null | string) => Promise<unknown>
|
||||
die: () => void
|
||||
dieWithCode: (code: number) => void
|
||||
guardBusySessionSwitch: (what?: string) => boolean
|
||||
newSession: (msg?: string, title?: string) => void
|
||||
resetVisibleHistory: (info?: null | SessionInfo) => void
|
||||
|
||||
@@ -92,6 +92,17 @@ export const coreCommands: SlashCommand[] = [
|
||||
run: (_arg, ctx) => ctx.session.die()
|
||||
},
|
||||
|
||||
{
|
||||
help: 'update Hermes Agent to the latest version (exits TUI)',
|
||||
name: 'update',
|
||||
run: (_arg, ctx) => {
|
||||
ctx.transcript.sys('exiting TUI to run update...')
|
||||
// Exit code 42 signals the Python wrapper to exec `hermes update`.
|
||||
// Use dieWithCode for proper cleanup (gateway kill + Ink unmount).
|
||||
setTimeout(() => ctx.session.dieWithCode(42), 100)
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
aliases: ['scroll'],
|
||||
help: 'toggle mouse/wheel tracking [on|off|toggle]',
|
||||
|
||||
@@ -377,6 +377,12 @@ export function useMainApp(gw: GatewayClient) {
|
||||
process.exit(0)
|
||||
}, [exit, gw])
|
||||
|
||||
const dieWithCode = useCallback((code: number) => {
|
||||
gw.kill()
|
||||
exit()
|
||||
process.exit(code)
|
||||
}, [exit, gw])
|
||||
|
||||
const session = useSessionLifecycle({
|
||||
colsRef,
|
||||
composerActions,
|
||||
@@ -643,6 +649,7 @@ export function useMainApp(gw: GatewayClient) {
|
||||
session: {
|
||||
closeSession: session.closeSession,
|
||||
die,
|
||||
dieWithCode,
|
||||
guardBusySessionSwitch: session.guardBusySessionSwitch,
|
||||
newSession: session.newSession,
|
||||
resetVisibleHistory: session.resetVisibleHistory,
|
||||
|
||||
Reference in New Issue
Block a user