feature: host-join mode, ngrok HTTPS tunnelling, and session UX improvements#3
Closed
marknimbuspay wants to merge 3 commits intodiorwave:mainfrom
Closed
feature: host-join mode, ngrok HTTPS tunnelling, and session UX improvements#3marknimbuspay wants to merge 3 commits intodiorwave:mainfrom
marknimbuspay wants to merge 3 commits intodiorwave:mainfrom
Conversation
…ixes Server: - New --join/-j flag on serve command starts the server and immediately joins as a chat participant in the same process (server runs as a daemon child process via multiprocessing to work around signal handler restrictions on non-main threads) - Host typing q broadcasts a farewell message to all connected clients before shutting the server down - Session store now cleaned up on WebSocket disconnect, allowing users to reconnect with the same username after leaving Client: - Async stdin reading via connect_read_pipe replaces run_in_executor, eliminating the hang on exit caused by asyncio waiting for the blocked input() thread - SOCKS proxy bypass (proxy=None) prevents websockets auto-detecting system proxy configuration for local connections - Chat display scales to terminal height with messages pinned to the bottom and input at the foot of the screen (minimum 15 message rows) - Separators fill terminal width dynamically - Server shutdown detected and reported; client exits cleanly without requiring user input - Screen cleared and session ended message shown on clean exit; error output preserved on connection or auth failure Launcher: - cmd_chat.py auto-selects venv interpreter via os.execv when not already running inside it (detected via sys.prefix comparison) - Server and client imports are lazy so connect command has no dependency on Sanic
Adds optional ngrok HTTPS tunnel to the serve command via --ngrok and --ngrok-token flags. On startup, opens an HTTP tunnel (TLS-terminated at grok). The host's chat UI shows the tunnel address in the Online header. Client auto-selects https:// and wss:// when connecting on port 443. Tunnel is torn down cleanly on server exit.
ngrok: - Show public access panel after Sanic "Worker ready" (not before startup noise) via after_server_start listener - With --join, hold at the panel until the first remote participant connects before launching the host's chat client - Redisplay ngrok panel inside the host's chat client (cleared on start) - Password omitted from connect command example — show <password> placeholder with a security warning to share it out-of-band Session exit: - Kill server process via on_disconnect callback the moment the host's websocket closes, so remote clients drop to "press any key" in sync - Await cancelled tasks after asyncio.wait so readline unblocks immediately when the server disconnects; no stale input prompt - Clear visible screen and scrollback (\033[H\033[2J\033[3J) written atomically to /dev/tty to avoid buffer-ordering issues with Rich - GRACEFUL_SHUTDOWN_TIMEOUT = 0 so Ctrl-C on serve exits immediately CLI: - username and password are now optional positionals on connect, and --password is optional on serve; missing values are prompted interactively (password via getpass, no echo) - --join now accepts an optional username; omitting it prompts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds several quality-of-life and security improvements to cmd-chat, centred around three themes: hosting UX, public access via ngrok, and clean
session lifecycle management.
Host-join mode (
--join)--join [USERNAME]flag onservelets the person starting the server participate in the chat from the same command, without opening a secondterminal
q, a farewell message is broadcast to all participants and the server shuts down immediately — remote clients are dropped toa clean exit prompt in sync
ngrok HTTPS tunnel (
--ngrok)--ngrokflag onserveopens a public HTTPS tunnel via pyngrok, allowing participants to connect fromanywhere without port forwarding
--ngrok-token TOKENto supply a free ngrok authtoken (removes session limits)wss://andhttps://<username>and<password>as placeholders — the password is intentionally omitted with a prominent securitywarning: it must be pre-shared out-of-band and never sent over the chat channel
--join, the host's screen holds at the public access panel until the first remote participant connects, giving time to share the addressSession lifecycle & terminal hygiene
via a single atomic write to
/dev/tty(\033[H\033[2J\033[3J)GRACEFUL_SHUTDOWN_TIMEOUT = 0so Ctrl-C onserveexits immediately rather than waiting up to 15 secondsos.execv; the terminal is restored cleanly on exitCLI improvements
usernameandpasswordonconnectare now optional positional arguments — if omitted, they are prompted interactively--passwordonserveis now optional — prompted if not supplied--joinaccepts an optional username; omitting it prompts interactivelygetpass(no terminal echo)Bug fixes
proxy=Nonepassed towebsockets.connectto suppress automatic system proxy detectionrun_in_executorstdin reading withasyncio.connect_read_pipe, eliminating the thread that blockedasyncio.run()from returningTest plan
servewithout flags starts cleanly; Ctrl-C exits immediatelyserve --joinprompts for username if omitted, connects host to chatserve --join alice --ngrokshows public access panel, waits for first participant, then opens chat with tunnel address in headerwss://(port 443)q— all clients drop to "press any key" simultaneouslyconnectwithout username/password prompts for both