Migrate readline from rustyline to reedline#30
Merged
Conversation
Adds a human-readable protocol name method to the Server trait, implemented as "QUIC" and "WebSocket" on the respective server types. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Default --version prints one line: "wallhack <version>". Full build metadata (time, git hash, features) is behind --verbose. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
format_level() now returns the plain level string (e.g. "[+]") when use_color is false, avoiding escape codes in piped or non-TTY output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…_name() Entry and relay now accept --name/-n (exit already had it). All three node types share a single generate_node_name() helper producing a random 8-char hex ID, replacing the inline logic that was duplicated in ExitCommand. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…our early - Remove redundant "Starting as <role> node" log lines (each run() now prints its own wallhack <version> <name> header) - --version now dispatches to print_version_short or print_version_verbose - Colour output is initialised at startup based on stderr IsTerminal - Add name: None to default EntryCommand struct literal Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…warn - Print wallhack <version> <name> header at startup (consistent with entry/exit) - Show "Connecting to <addr>..." before DNS resolve - Show "Resolved <host> as <ip>" only when DNS was actually performed - Demote retry log from info to warn - Remove redundant "Connected to upstream" messages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t_help() - PrintMsg enum (Text/Done) and DoneGuard RAII for readline output sync - uptime() replaces inline print_ping() which mixed version and uptime - print_version_info() prints version only (uptime moved to info command) - Unified print_help() replaces separate entry/exit help functions; command set and descriptions are now identical across all node types Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Print wallhack <version> <name> header at startup - Switch print channel to UnboundedSender<PrintMsg>; drain until Done before drawing next readline prompt - Add DoneGuard at REPL dispatch site to cover all exit paths - Replace print_entry_help with repl_common::print_help - Fix connect/listen help descriptions (were "Not available on entry nodes") Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sync - Print wallhack <version> <name> header at startup - Switch print channel to UnboundedSender<PrintMsg>; readline path waits for Done before drawing next prompt; non-readline path drains directly - Add DoneGuard at all REPL dispatch sites (7 call sites) - Drop state: field from info output; presence/absence of connect:/listen: lines conveys the same information without inventing a state abstraction - Replace print_exit_help with repl_common::print_help - Route commands available on all node types (consistent CLI) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The feature controls the interactive REPL (history, completion, prompt), not readline specifically. "repl" is more accurate and protocol-agnostic now that we are migrating from rustyline to reedline. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nces Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oilerplate - Replace rustyline dep with reedline 0.45 (external_printer feature) - Delete dead readline.rs; extract generic run_repl_input<T,F> to repl_common - entry.rs + exit.rs both use shared run_repl_input — no duplicate setup - Fix bench/bench.just musl build: add --no-default-features to prevent reedline/crossterm from compiling in the cross docker environment - Update bloat thresholds (+153 KB default, slim unchanged) - Purge all rustyline/readline terminology from comments Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entry node REPL was absent in connect mode (--connect flag). Restructure run_entry_connect to mirror exit.rs: REPL thread starts in run() before dispatch; run_entry_connect_quic/ws use tokio::select! so REPL commands (quit/info/stats/peers/help) work during connect + session. Peer name showing IP address in peers list: run_ws_relay_capability had name: None in its WsClient config — exit node never sent ExitNodeHello name. Fixed to name: Some(node_name.to_string()). Debug logs corrupting reedline display: subscriber.rs used eprintln! which bypasses ExternalPrinter and writes raw bytes to the TTY mid-prompt. Add LOG_SINK channel in repl_common; install_log_sink() wires it to the printer channel when stdin is interactive. emit_log() replaces eprintln! in subscriber. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Routes startup messages through Printer to fix raw-mode newline corruption
when reedline is active. Introduces EntryResources{metrics,peers,routes,sessions}
to reduce argument counts below clippy::too_many_arguments threshold.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- AGENTS.md: prohibit "reverse tunnel", "connect mode", "listen mode" — nodes have a transport direction (--connect / --listen), not a mode - Remove redundant inline comments from usage examples - Fix entry startup messages to use route_info!/route_warn! so they appear on stderr in headless (non-TTY) use, consistent with exit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 tasks
maxholman
added a commit
that referenced
this pull request
May 6, 2026
Sweep of website/ deps to latest within ranges, plus a vite downgrade from 8 -> 7 to match astro's transitive vite (7.3.2) and avoid a rolldown regression with @tailwindcss/vite 4.2.4. Closes alerts #28 #29 #30 #31 #33 #34 #35 #36 #37 #38 #39 #40 #44 #48 covering vite, picomatch, postcss, yaml, astro, smol-toml. - vite ^8.0.1 -> ^7.3.2 (drops the now-redundant vite 8 lineage; astro pulls 7.3.2 transitively, which is the patched version) - astro 6.0.6 -> 6.2.2 (#44) - @tailwindcss/vite 4.2.2 -> 4.2.4 - smol-toml: lockfile bump to 1.6.1 (#28) - postcss: lockfile bump to 8.5.14 (#48) - picomatch: lockfile bumps to 2.3.2 + 4.0.4 (#29 #30 #39 #40) - yaml is now omitted entirely (it was an optional vite peer) Verified: pnpm build succeeds; no @tailwindcss/vite peer-dep warnings.
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.
Migrate readline from rustyline to reedline
Branch
feat/reedline— based onfeat/version-and-startup-uxScope
crates/cli/—Cargo.toml,src/entry.rs,src/exit.rs,src/repl_common.rsThe
#[cfg(not(feature = "repl"))]non-REPL path must continue to work unchanged.The feature flag is named
repl(renamed fromreadlineas part of this branch).Out of scope
Core wallhack logic, transports, netstack, protobuf, website, bench.
Do not change command parsing, REPL command set, or output formatting.
Why
Problems with the current rustyline implementation
The current readline implementation is broken. No REPL commands produce visible output.
The root cause is architectural: rustyline's
ExternalPrinteronly works correctly whilerl.readline()is actively blocking for input. Command responses are generated afterreadline()returns (the command is sent to an async task, which processes it and sendsresponses back through the print channel). By that point,
readline()is no longer active,so
ExternalPrinterbuffers the responses and only flushes them whenreadline()is calledagain for the next prompt — after the prompt has already been drawn.
Concrete symptoms observed:
peers,info,statsproduce no visible output[+] Peer connected: ...) interleave with command responsesin unpredictable order
The workaround that was attempted and failed
A
Donesentinel (PrintMsg::Done) was introduced to signal command completion.The readline thread waits with
done_rx.recv_timeout(500ms)after sending a command,hoping all response messages are queued in
ExternalPrinterbefore the nextreadline()call draws the prompt. This does not fix the problem because:ExternalPrinterstill buffers whenreadline()is not active — messages arriveduring the 500ms window but are not printed until the next
readline()callDonebefore the user sees anythingagainst the command response window
DoneGuard/done_rxmachinery adds complexity and latency for zero benefitWhy reedline fixes this
reedline (the Nushell readline library) uses a fundamentally different model:
read_line()call, reedline flushes all pendingExternalPrintermessages before drawing the prompt. This means command responsessent to the printer after
read_line()returned will always appear correctly above thenext prompt, regardless of async timing.
ExternalPrinterchannel is decoupled from the event loop — messages sent at anytime are buffered and printed at the correct moment.
Ctrl-C,Ctrl-D) is first-class with a typedSignalreturn value.Goals
adding reedline vs rustyline. If the delta is unacceptable the migration may be
abandoned or a lighter alternative chosen. Do not proceed to goal 2 until this
is confirmed acceptable.
replfeature path.the prompt line.
#[cfg(not(feature = "repl"))]) path is unchanged.Binary size delta (measured 2026-02-23)
The increase comes from reedline's
external_printerfeature pulling in crossbeam channelprimitives.
default-features = falseis used; onlyexternal_printeris enabled.The slim build is unaffected (reedline is gated behind the
replfeature, excluded from slim).Known challenges
Binary size
reedline pulls in more dependencies than rustyline. The slim build (
--features slim,no readline) must be unaffected. The full build will grow; the question is how much.
cargo bloat --release --cratescan give per-crate size breakdown.PrintMsg / DoneGuard compatibility
The current
PrintMsg { Text(String), Done }enum andDoneGuardRAII were designedas a rustyline workaround. With reedline the
Donesentinel may become unnecessary forcommand responses. However, the non-readline path also uses
PrintMsgand must continueto work. Changing
PrintMsgaffects both paths.Printer channel type
Printerwrapsmpsc::UnboundedSender<PrintMsg>. reedline'sExternalPrinteracceptsStringnotPrintMsg. The channel andPrinterabstraction will need to bridge these.Single vs two printers
Currently one
Printeris used for both REPL command responses and background asyncevents. With reedline's model, it may be necessary or desirable to separate these two
concerns so each can be routed differently.
REPL feature gate
The
replfeature (renamed fromreadlinein this branch) is referenced inCargo.tomland guarded with
#[cfg(feature = "repl")]inentry.rsandexit.rs. reedline mustslot into the same feature gate.
Blocking thread model
The readline loop runs in a
spawn_blockingthread to avoid blocking the async runtime.reedline's
read_line()is synchronous, so this model is preserved. Verify thatreedline does not spawn its own tokio runtime or conflict with the existing one.
History, completions, hints
rustyline history (
add_history_entry) is used today. reedline has its own history API.Completions and hints are not implemented today — preserve the same capability gap; do
not add them as part of this migration.