Mutable handle the hook fills in on mount with a function that
politely tears down whatever OCapN session is currently live
(unsubscribe → leave → client.shutdown()). Both the in-app
Ctrl+C keystroke and the out-of-app signal handlers in the
entrypoint invoke it on the way out so we don't disappear from the
chatroom without saying goodbye, and so the websocket gets closed
cleanly instead of half-open.
Why not just use signals? While the TUI is running ink puts the TTY
into raw mode, which disables the kernel's ISIG translation — so a
literal ^C keystroke arrives as the byte 0x03 via useInput, NOT
as SIGINT. Conversely, SIGTERM/SIGHUP and kill -INT $pid never
touch useInput. Both code paths converge through this handle.
Mutable handle the hook fills in on mount with a function that politely tears down whatever OCapN session is currently live (
unsubscribe→leave→client.shutdown()). Both the in-app Ctrl+C keystroke and the out-of-app signal handlers in the entrypoint invoke it on the way out so we don't disappear from the chatroom without saying goodbye, and so the websocket gets closed cleanly instead of half-open.Why not just use signals? While the TUI is running ink puts the TTY into raw mode, which disables the kernel's ISIG translation — so a literal
^Ckeystroke arrives as the byte 0x03 viauseInput, NOT as SIGINT. Conversely, SIGTERM/SIGHUP andkill -INT $pidnever touchuseInput. Both code paths converge through this handle.