diff --git a/README.md b/README.md index 2f7b856..f7a1fb0 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Command-line tools and libraries for interacting with comma devices and the comm - `comma-connect-api`: Async Rust client for `https://api.commadotai.com` - `comma-cli`: CLI application that demonstrates configuration handling and basic API calls +- `comma-tui`: Lightweight terminal user interface (binary name: `comma`). Early design phase; see `crates/comma-tui/docs/`. - `comma-test-utils`: Shared helpers for cucumber/BDD tests (not published) ## Quick start diff --git a/crates/comma-tui/Cargo.toml b/crates/comma-tui/Cargo.toml new file mode 100644 index 0000000..1d626e0 --- /dev/null +++ b/crates/comma-tui/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "comma-tui" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +description = "Terminal user interface for comma devices" +repository.workspace = true +homepage.workspace = true +documentation.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[[bin]] +name = "comma" +path = "src/main.rs" + +[dependencies] +comma-connect-api.workspace = true +anyhow.workspace = true +clap.workspace = true +serde.workspace = true +serde_json.workspace = true +tokio.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true + +# TUI (to be added when implementation starts) +# ratatui = "0.29" +# crossterm = "0.28" + +[dev-dependencies] diff --git a/crates/comma-tui/README.md b/crates/comma-tui/README.md new file mode 100644 index 0000000..e2ad7f2 --- /dev/null +++ b/crates/comma-tui/README.md @@ -0,0 +1,24 @@ +# comma-tui + +Lightweight terminal user interface for interacting with comma devices and the comma connect API. + +The binary is named `comma` for convenience. + +## Status + +Early design phase. No real UI yet. See `docs/` for TUI design notes and decisions. + +## Design goals + +- Text-only early versions (no video, no thumbnails, no graphics protocols). +- Tabbed main screen inspired by rustnet. +- Fully configurable keybindings (Vim-like defaults). +- Separate config from `comma-cli`, but respects the same environment variables. +- Dongle switcher + routes + upload queue as the first useful views. + +## Building + +```bash +cargo build -p comma-tui +./target/debug/comma +``` diff --git a/crates/comma-tui/docs/DESIGN.md b/crates/comma-tui/docs/DESIGN.md new file mode 100644 index 0000000..805e44e --- /dev/null +++ b/crates/comma-tui/docs/DESIGN.md @@ -0,0 +1,124 @@ +# TUI Design Notes + +These are working notes on the intended look, feel, and behaviour of the `comma` TUI. +They are not formal architecture decision records (ADRs); they capture use-case and +interaction design thinking so we can implement deliberately. + +Related: see the individual notes in this directory. + +## Core principles + +- **Lightweight first.** Early versions are pure text. No video playback, no + thumbnails, no half-block rendering, no graphics protocols. +- **Useful before pretty.** Prioritise routes list, upload queue, device overview, + and dongle switching. Visual flourishes (coloured route markers, etc.) come later. +- **Fixed, source-defined keybindings.** Keybindings are not user-configurable. + They live in one place in the source code (with associated display strings). + Defaults are Vim-like, with support for modifiers and multiple keys per action. +- **Separate but compatible config.** The TUI has its own config file (TOML via + confy, same strategy as `comma-cli`). Dongle ID and token can live there, but + environment variables (`COMMA_TOKEN`, `COMMA_DONGLE`) are preferred and shared + with `comma-cli`. CLI flags override both. + +## Main screen layout (inspired by rustnet) + +``` +┌───────────────────────────────────────────────────────┐ +│ Routes Queue Device Devices Help │ ← tab bar +├───────────────────────────────────────────────────────┤ +│ │ +│ (active tab content) │ +│ │ +│ │ +├───────────────────────────────────────────────────────┤ +│ j/k: move space: select q: quit ? : help │ ← status / key hints +└───────────────────────────────────────────────────────┘ +``` + +- Top line: list of tabs, active tab highlighted. +- Bottom line: context-sensitive keyboard shortcuts currently available + (subset of bindings, ranked by importance, limited by terminal width). +- Rightmost tab is always **Help**, which lists all keybindings (including + alternatives and modifiers) generated from the source-defined binding table. + +## Tabs (initial set) + +1. **Routes** — list of routes for the active dongle (metadata only). +2. **Queue** — upload queue for the active dongle. +3. **Device** — overview of the active dongle. +4. **Devices** — switch the active dongle. Lists all devices the user can access + (owned + shared). Only one is active at a time; other tabs show data for it. +5. **Help** — full keybinding and command overview (generated from source). + +## Dongle selection + +- On startup, select the dongle from (in order): `--dongle` / `-d` CLI flag, + `COMMA_DONGLE` environment variable, last-selected dongle stored in the TUI + config, or prompt / first available. +- The Devices tab lets the user change the active dongle at runtime. + The choice is persisted to the TUI config. +- All other data tabs operate on the currently selected dongle. +- Users who want to ignore a persisted or environment dongle temporarily can + use `env -u COMMA_DONGLE comma` (or pass `--dongle`). + +## Configuration + +Own config file managed by `confy` (TOML, platform-standard location, same +strategy as `comma-cli`; typically `~/.config/comma-tui/config.toml` on Linux). + +Example sketch: + +```toml +default_dongle = "0123456789abcdef" +# token = "..." # prefer env var +last_dongle = "0123456789abcdef" # written by the TUI on dongle switch +``` + +Keybindings are **not** in the config; they are defined in source code. + +## Keybindings + +- Defined in a single place in the source code. +- Each binding has an associated display string (e.g. `space`, `enter`, + `ctrl-f`) used by the bottom bar and Help tab. Changing a binding or its + display string requires no other edits. +- Support for modifier keys (e.g. `Ctrl-F` / `Ctrl-B` for page up/down). +- Multiple keys may be bound to the same action (e.g. both `j`/`k` and arrow + keys for movement). +- Help tab lists all bindings for each action. +- Bottom bar shows a ranked subset (by importance), truncated as needed for + terminal width. The set of hints is context-sensitive per tab (Routes has + upload actions, Queue has cancel, Device has alias editing, etc.). + +## Feature parity with the CLI + +The TUI should offer roughly the same interactive capabilities as the CLI +(routes listing, upload queue management, requesting uploads of cameras/logs/ +routes/recent-routes, device alias changes, etc.). + +- CLI remains the right tool for scripting, one-off commands, and raw JSON + output. +- TUI translates API responses into human-friendly interactive views. +- Reusable helper logic currently living in `comma-cli/src/main.rs` (the + various `cmd_*` functions) should be extracted into a shared module that + both the CLI and TUI can use. + +## Non-goals for early versions + +- Rendering any frames from route video footage. +- Thumbnails or coloured route icons (possible later, e.g. time-of-day colour). +- Graphics protocol support (Kitty, Sixel, iTerm2) or half-block video. +- Replacing the web UI’s media viewing experience. +- User-configurable keybindings. + +## Resolved questions + +- **Config format and location:** TOML via `confy`, same strategy as + `comma-cli`. +- **Bottom bar:** Fully dynamic and context-sensitive. Number of shown hints + depends on terminal width and an importance ranking of the bindings. +- **Upload-request workflow:** Offer more or less the same features in CLI + and TUI. Extract shared helpers from the CLI. +- **Persistence of last-selected dongle:** Written to the TUI config. + Overridden by environment variable or CLI flag. Temporary override via + `env -u COMMA_DONGLE comma`. diff --git a/crates/comma-tui/docs/TDR-001-lightweight-text-only.md b/crates/comma-tui/docs/TDR-001-lightweight-text-only.md new file mode 100644 index 0000000..34cc9fa --- /dev/null +++ b/crates/comma-tui/docs/TDR-001-lightweight-text-only.md @@ -0,0 +1,30 @@ +# TDR-001: Lightweight text-only early versions + +## Context + +The comma web UI shows route video. Terminal video playback is possible via +graphics protocols (Kitty, iTerm2, Sixel) or unicode half-blocks, but: + +- Stock Alacritty supports none of the graphics protocols. +- Half-block video is blocky and bandwidth-heavy. +- The primary value of a TUI for many users is metadata, queue management, + and quick navigation, not media playback. + +## Decision + +Early versions of `comma` (the TUI) will contain **no** rendering of video +footage, not even still thumbnails or coloured route markers. + +Routes are listed as plain text lines derived from metadata. + +## Consequences + +- Faster to implement and ship useful functionality. +- Works identically in Alacritty, over SSH, and in any truecolor terminal. +- Leaves the door open for optional visual enhancements later (time-of-day + colour blocks, half-blocks, or protocol-based images) without blocking + the core experience. + +## Status + +Accepted (2026-10-18) diff --git a/crates/comma-tui/docs/TDR-002-tabbed-layout.md b/crates/comma-tui/docs/TDR-002-tabbed-layout.md new file mode 100644 index 0000000..7a6f948 --- /dev/null +++ b/crates/comma-tui/docs/TDR-002-tabbed-layout.md @@ -0,0 +1,31 @@ +# TDR-002: Tabbed layout inspired by rustnet + +## Context + +We want a clear, keyboard-driven main screen. Two reference TUIs are rustnet +(ratatui, tabbed) and btop (more dashboard-like). The preference is closer to +rustnet. + +## Decision + +The main screen is tabbed: + +- Top bar lists tabs and highlights the active one. +- Bottom bar shows currently relevant keybindings (ranked subset, limited by + terminal width; generated from the source-defined binding table). +- Rightmost tab is always Help and lists all bindings (including alternatives + and modifiers) generated from the same source table. + +Initial tabs: Routes, Queue, Device, Devices, Help. + +## Consequences + +- Familiar mental model for users of rustnet-style tools. +- Help and bottom bar stay automatically consistent with the code-defined + bindings. +- Easy to add further tabs later without redesigning the shell. +- Bottom bar can be context-sensitive per tab without extra configuration. + +## Status + +Accepted (2026-10-19) diff --git a/crates/comma-tui/docs/TDR-003-config-and-env.md b/crates/comma-tui/docs/TDR-003-config-and-env.md new file mode 100644 index 0000000..9ba03cd --- /dev/null +++ b/crates/comma-tui/docs/TDR-003-config-and-env.md @@ -0,0 +1,38 @@ +# TDR-003: Separate config with shared environment variables + +## Context + +`comma-cli` already stores a default dongle ID and token via confy +(`~/.config/comma-cli/config.toml`) and prefers `COMMA_TOKEN` / +`COMMA_DONGLE` environment variables. + +The TUI has different needs (persistence of last-selected dongle, possibly +other UI state) and different usage patterns. Keybindings are deliberately +not part of the config. + +## Decision + +- The TUI has its **own** config file, managed by `confy` (TOML, same + strategy and platform-standard locations as `comma-cli`). +- It may store a default dongle ID, token, and the last-selected dongle. +- It **must** honour the same environment variables (`COMMA_TOKEN`, + `COMMA_DONGLE`) that the CLI uses. +- CLI flags (`--dongle`, `--token`) override both config and environment. +- Keybindings are **not** stored in the config; they are defined in source + code (see TDR-004). + +Duplication of dongle/token is acceptable; environment variables remain the +preferred shared mechanism. + +## Consequences + +- Users can keep secrets out of config files via environment variables. +- TUI-specific state (last dongle) does not pollute the CLI config. +- Startup selection order is well-defined: CLI flag > env > config (including + last-selected) > fallback. +- Temporary override of a persisted or environment dongle is possible with + `env -u COMMA_DONGLE comma` or an explicit `--dongle` flag. + +## Status + +Accepted (2026-10-19) diff --git a/crates/comma-tui/docs/TDR-004-keybindings.md b/crates/comma-tui/docs/TDR-004-keybindings.md new file mode 100644 index 0000000..38e99bc --- /dev/null +++ b/crates/comma-tui/docs/TDR-004-keybindings.md @@ -0,0 +1,40 @@ +# TDR-004: Fixed source-defined keybindings (not user-configurable) + +## Context + +Earlier design considered fully user-configurable keybindings (to accommodate +layouts such as Colemak-DH). After further thought, the complexity of a +configurable binding system (config parsing, validation, dynamic Help and +status-bar generation from user input, conflict handling) is not worth the +benefit for a focused TUI. A single source-of-truth in code is simpler, +easier to test, and still allows the display strings to stay in sync with +the actual keys. + +## Decision + +- Keybindings are **not** user-configurable. +- All bindings live in one place in the source code. +- Each binding carries its own display string (e.g. `space`, `enter`, + `ctrl-f`, `up`). The bottom bar and Help tab are generated from this table, + so changing a key or its label requires no other edits. +- Modifier keys are supported (examples: `Ctrl-F` / `Ctrl-B` for page + up/down). +- Multiple keys may be bound to the same action (e.g. both `j`/`k` and the + arrow keys for vertical movement). +- The Help tab lists every binding for each action. +- The bottom bar shows a ranked subset of the currently relevant bindings + (importance rank + available terminal width). The set of hints is + context-sensitive per tab. + +## Consequences + +- Much less implementation and testing complexity. +- Help and status bar stay automatically consistent with the code. +- Users who strongly prefer a different layout must either live with the + defaults or fork/patch the binding table (acceptable trade-off). +- Easy to add alternative keys (arrows, etc.) without user configuration. + +## Status + +Accepted (2026-10-19) — supersedes the previous “fully configurable” +decision. diff --git a/crates/comma-tui/docs/TDR-005-dongle-switcher.md b/crates/comma-tui/docs/TDR-005-dongle-switcher.md new file mode 100644 index 0000000..23be58e --- /dev/null +++ b/crates/comma-tui/docs/TDR-005-dongle-switcher.md @@ -0,0 +1,32 @@ +# TDR-005: Dongle switcher tab (Devices) + +## Context + +A user may own multiple devices or have been granted read access to devices +owned by others (via useradmin.comma.ai). The TUI needs a clear way to choose +which dongle’s data is shown in the other tabs. + +## Decision + +- There is a dedicated **Devices** tab that lists all accessible devices. +- Exactly one dongle is active at a time. +- Other tabs (Routes, Queue, Device, …) always operate on the active dongle. +- On startup the active dongle is chosen by: CLI `--dongle`/`-d` > + `COMMA_DONGLE` env > last-selected dongle stored in the TUI config > + first available (or prompt). +- Changing the selection in the Devices tab updates the active dongle for the + rest of the session **and** persists the choice to the TUI config. +- Users can temporarily ignore the persisted or environment value with + `env -u COMMA_DONGLE comma` or by passing `--dongle`. + +## Consequences + +- Clear model for multi-device users. +- CLI and environment overrides are honoured, matching `comma-cli` behaviour. +- Avoids the need to restart the TUI when switching devices. +- Last-selected dongle survives across runs without requiring the user to + edit the config by hand. + +## Status + +Accepted (2026-10-19) diff --git a/crates/comma-tui/docs/TDR-006-feature-parity.md b/crates/comma-tui/docs/TDR-006-feature-parity.md new file mode 100644 index 0000000..1f1d915 --- /dev/null +++ b/crates/comma-tui/docs/TDR-006-feature-parity.md @@ -0,0 +1,35 @@ +# TDR-006: Feature parity with CLI and shared helpers + +## Context + +The CLI already implements a useful set of operations (route listing, upload +queue inspection and cancellation, requesting uploads of individual file +kinds, whole routes, and recent routes, device information, etc.). The TUI +should not reinvent these; it should expose roughly the same capabilities in +an interactive form. + +## Decision + +- The TUI will offer more or less the same interactive features as the CLI. +- The CLI remains the appropriate tool for scripting, one-off commands, and + obtaining raw JSON API responses. +- The TUI translates those responses into human-friendly interactive views. +- Reusable logic currently living in `comma-cli/src/main.rs` (the various + `cmd_*` helper functions) should be extracted into a shared module that + both the CLI and the TUI can depend on. +- As features are added, add any necessary new helpers in the shared module + so that CLI would be able to readily use them and thus speed-up the + reimplementation of a TUI feature or vice versa (reimplementation of a new + CLI feature in the TUI). + +## Consequences + +- Avoids divergent behaviour between CLI and TUI. +- Keeps the TUI focused on presentation and interaction while reusing + proven request/response handling. +- Slightly more up-front refactoring of the CLI, but pays off as both the + CLI and TUI grows. + +## Status + +Accepted (2026-10-19) diff --git a/crates/comma-tui/src/main.rs b/crates/comma-tui/src/main.rs new file mode 100644 index 0000000..01e5ed7 --- /dev/null +++ b/crates/comma-tui/src/main.rs @@ -0,0 +1,9 @@ +//! Placeholder entry point for the `comma` TUI. +//! +//! This binary will grow into a lightweight terminal UI for comma devices, +//! focusing first on text-based metadata views (routes, upload queue, devices). + +fn main() { + println!("comma TUI — coming soon"); + println!("See crates/comma-tui/docs/ for design notes."); +}