- Rust 1.70 or later (includes
cargo)
git clone https://github.com/RoundingWell/app-cli.git
cd app-cli
cargo build --releaseThe compiled binary is placed at target/release/rw.
cargo install --path .This places rw on your $PATH automatically (assuming ~/.cargo/bin is in your PATH).
Copy the binary to any directory on your $PATH:
# macOS / Linux
cp target/release/rw /usr/local/bin/rwVerify the installation:
rw --versionFormat code:
cargo fmtCheck for lint warnings (matches CI):
cargo clippy --all-targets --all-features -- -D warningsRun the test suite:
cargo testBuild a release binary (matches CI):
cargo build --releaserw is split into a library crate (src/lib.rs) holding all logic and a thin
binary (src/main.rs) that wires it up. This split lets integration tests
under tests/ exercise the binary without re-implementing the dispatch shell.
src/
├── lib.rs pub module declarations (the crate's public surface)
├── main.rs binary entry point — argument parse + dispatch
├── cli.rs clap argument structs + Stage + slug validation
├── config.rs Config / Profile / AppContext + on-disk persistence
├── api.rs stage → API URL resolution
├── auth_cache.rs AuthCache (Bearer | Basic) + 0600 on-disk store
├── http.rs ApiClient: auth-attached reqwest wrapper
├── jsonapi.rs generic Document / Resource / Single / List envelopes
├── prompt.rs interactive yes_no / text / stage / organization prompts
├── output.rs Output{json} + CommandOutput trait
├── migration.rs one-shot config migrations on startup
├── version_check.rs GitHub release check + self_update
└── commands/ one module per top-level subcommand
tests/
└── cli.rs end-to-end integration tests (assert_cmd + tempfile)
http.rs and jsonapi.rs are the canonical way to reach the API. New
commands should compose them rather than reaching for reqwest::Client
directly:
let api = ApiClient::new(ctx).await?;
let teams: List<TeamAttributes> = api.get("teams").await?;prompt::*_with variants take generic Read/Write and are used directly
in unit tests; the bare prompt::yes_no / prompt::text / etc. wrappers
default to stdin and stderr.