Skip to content

feat: interactive cli client - #70

Merged
kacy merged 9 commits into
mainfrom
feat/cli-interactive-client
Feb 9, 2026
Merged

feat: interactive cli client#70
kacy merged 9 commits into
mainfrom
feat/cli-interactive-client

Conversation

@kacy

@kacy kacy commented Feb 9, 2026

Copy link
Copy Markdown
Owner

summary

implements the full interactive CLI client (phase 5, week 16). the cli is a thin client that tokenizes user input into RESP3 arrays and sends them to the server — no client-side command validation.

  • connection.rs: async tcp connection with buffered reads, RESP3 framing, and AUTH support
  • format.rs: colorized response formatting matching redis-cli conventions (green strings, red errors, numbered arrays, etc.)
  • commands.rs: static metadata table of ~70 commands across 10 groups for tab-completion and inline help
  • repl.rs: rustyline-based REPL with history (~/.emberkv_history), tab-completion, quoted string tokenizer, local commands (help, quit, clear), and automatic reconnection
  • main.rs: clap-based entry point dispatching between one-shot and interactive modes

what was tested

  • 32 unit tests covering the tokenizer (quoted strings, escapes, edge cases), response formatter (all frame types), and command metadata (lookup, grouping, sorting)
  • cargo clippy -p emberkv-cli -- -D warnings — clean
  • cargo test --workspace — no regressions
  • manual build verification with cargo build -p emberkv-cli

design considerations

  • thin client pattern: the server handles all command validation. the cli just tokenizes and forwards. this keeps the cli simple and means new server commands work automatically without cli changes.
  • rustyline on main thread: rustyline needs the main thread for terminal i/o, so we build a tokio runtime manually and use block_on for async calls rather than #[tokio::main].
  • tls deferred: the --tls flag is parsed but prints "not yet supported". keeps the PR focused on core functionality.

kacy added 9 commits February 8, 2026 19:42
adds the foundational modules for the interactive cli client:

- connection.rs: async tcp connection with RESP3 framing,
  send_command/authenticate methods, and buffered reads
- format.rs: pretty-print server responses with colors matching
  redis-cli conventions (colored strings, numbered arrays, etc.)
- Cargo.toml: add rustyline, colored, dirs, tokio, bytes,
  ember-protocol, thiserror dependencies
static table of ~70 commands across 10 groups (connection, string,
generic, list, hash, set, sorted_set, server, pubsub, cluster).

provides case-insensitive lookup and group-based iteration for
the help display and tab completion.
main.rs dispatches between one-shot (command-line args) and
interactive REPL mode. the REPL provides:

- rustyline integration with history (~/.emberkv_history)
- tab-completion of command names (first token)
- local commands: help, help <cmd>, quit, exit, clear
- automatic reconnection on server disconnect
- quoted string tokenizer with backslash escapes
replaces the stub notice with actual documentation covering
repl features, one-shot mode, local commands, and connection options.
audit findings addressed:

- remove all process::exit() calls — main returns ExitCode so
  destructors run and connections close cleanly
- remove all .expect() calls — runtime and editor creation errors
  are handled with eprintln + early return
- add Connection::shutdown() — sends QUIT to the server then does
  a TCP shutdown (FIN instead of RST)
- call shutdown on every exit path: repl quit/exit/ctrl-d, one-shot
  mode, and auth failures
- add connect timeout (5s) and read timeout (10s) to prevent
  hanging on unreachable or unresponsive servers
- cap read buffer at 64 KiB to prevent unbounded memory growth
  from malformed responses
- flush stdout after clear escape sequence
- extract reconnect helper to properly handle auth on reconnect
- fix -h to -H in cli readme (host flag changed to avoid
  conflict with --help)
- add options table and timeout info to cli readme
- replace redis-cli with ember-cli throughout root readme
  examples and quickstart
- add ember-cli to features list
- update project structure description
restructure the quickstart examples to make it clear that
redis-cli works as a drop-in replacement (same protocol, same port)
while ember-cli adds repl features like autocomplete and help.

command examples are shown tool-agnostic (bare commands) so
readers see they work with either client.
@kacy
kacy merged commit 76dd46f into main Feb 9, 2026
7 checks passed
@kacy
kacy deleted the feat/cli-interactive-client branch February 9, 2026 00:58
kacy added a commit that referenced this pull request Feb 11, 2026
* feat: add tcp connection and response formatting for cli

adds the foundational modules for the interactive cli client:

- connection.rs: async tcp connection with RESP3 framing,
  send_command/authenticate methods, and buffered reads
- format.rs: pretty-print server responses with colors matching
  redis-cli conventions (colored strings, numbered arrays, etc.)
- Cargo.toml: add rustyline, colored, dirs, tokio, bytes,
  ember-protocol, thiserror dependencies

* feat: add command metadata table for autocomplete and help

static table of ~70 commands across 10 groups (connection, string,
generic, list, hash, set, sorted_set, server, pubsub, cluster).

provides case-insensitive lookup and group-based iteration for
the help display and tab completion.

* feat: add interactive repl and one-shot mode

main.rs dispatches between one-shot (command-line args) and
interactive REPL mode. the REPL provides:

- rustyline integration with history (~/.emberkv_history)
- tab-completion of command names (first token)
- local commands: help, help <cmd>, quit, exit, clear
- automatic reconnection on server disconnect
- quoted string tokenizer with backslash escapes

* docs: update cli readme with usage and feature docs

replaces the stub notice with actual documentation covering
repl features, one-shot mode, local commands, and connection options.

* fix: use -H for host flag to avoid conflict with --help

* fix: handle errors and exits gracefully across the cli

audit findings addressed:

- remove all process::exit() calls — main returns ExitCode so
  destructors run and connections close cleanly
- remove all .expect() calls — runtime and editor creation errors
  are handled with eprintln + early return
- add Connection::shutdown() — sends QUIT to the server then does
  a TCP shutdown (FIN instead of RST)
- call shutdown on every exit path: repl quit/exit/ctrl-d, one-shot
  mode, and auth failures
- add connect timeout (5s) and read timeout (10s) to prevent
  hanging on unreachable or unresponsive servers
- cap read buffer at 64 KiB to prevent unbounded memory growth
  from malformed responses
- flush stdout after clear escape sequence
- extract reconnect helper to properly handle auth on reconnect

* chore: cargo fmt

* docs: update cli and root readmes for ember-cli

- fix -h to -H in cli readme (host flag changed to avoid
  conflict with --help)
- add options table and timeout info to cli readme
- replace redis-cli with ember-cli throughout root readme
  examples and quickstart
- add ember-cli to features list
- update project structure description

* docs: show redis-cli drop-in compatibility alongside ember-cli

restructure the quickstart examples to make it clear that
redis-cli works as a drop-in replacement (same protocol, same port)
while ember-cli adds repl features like autocomplete and help.

command examples are shown tool-agnostic (bare commands) so
readers see they work with either client.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant