waterui-cli 0.1.0

A modern UI framework for Rust
Documentation
# waterui-cli

Cross-platform build orchestration and development tooling for WaterUI applications.

## Overview

`waterui-cli` is the command-line interface that powers the `water` binary, the primary tool for building, running, and managing WaterUI applications across iOS, macOS, and Android. It abstracts platform-specific build systems (Xcode for Apple, Gradle for Android) and provides a unified developer experience with hot reload, device management, and project scaffolding.

The crate is split into two components:
- **Library** (`src/lib.rs`): Core abstractions for platforms, devices, builds, and project management
- **Terminal** (`src/terminal/`): User-facing CLI with argument parsing and formatted output

This separation ensures all business logic lives in the library, while the terminal layer handles only user interaction.

## Installation

Install the CLI from source within the WaterUI workspace:

```bash
cargo install --path cli
```

Or build for development (not added to PATH):

```bash
cargo build -p waterui-cli
```

## Quick Start

Create a new WaterUI project and run it on iOS Simulator:

```bash
# Create a new project
water create my-app --platform ios,android

# Run on iOS Simulator with hot reload
cd my-app
water run --platform ios

# Run on Android
water run --platform android
```

Create a playground for quick experimentation (auto-managed backends):

```bash
water create --playground --name my-experiment
cd my-experiment
water run --platform ios
```

## Core Concepts

### Platform Abstraction

The `Platform` trait represents a build target (iOS, macOS, Android with different ABIs). Each platform implementation handles:

- **Device scanning**: Enumerate connected devices and emulators
- **Building**: Compile Rust library for the target triple
- **Packaging**: Generate platform-specific artifacts (`.app`, `.apk`)
- **Cleaning**: Remove build artifacts

Example from `src/platform.rs`:

```rust
pub trait Platform: Send {
    type Toolchain: Toolchain;
    type Device: Device;

    fn scan(&self) -> impl Future<Output = eyre::Result<Vec<Self::Device>>> + Send;
    fn build(&self, project: &Project, options: BuildOptions) -> impl Future<Output = eyre::Result<PathBuf>> + Send;
    fn package(&self, project: &Project, options: PackageOptions) -> impl Future<Output = eyre::Result<Artifact>> + Send;
    fn clean(&self, project: &Project) -> impl Future<Output = eyre::Result<()>> + Send;
    fn triple(&self) -> Triple;
    fn toolchain(&self) -> Self::Toolchain;
}
```

Implementations: `ApplePlatform` (iOS, macOS, simulators), `AndroidPlatform` (arm64-v8a, x86_64, etc.)

### Device Management

The `Device` trait represents something that can run an app (simulator, emulator, or physical device). Each device has a two-phase lifecycle:

1. **Launch**: Boot the emulator/simulator (no-op for physical devices)
2. **Run**: Install and execute the artifact, returning a `Running` stream

Example from `src/device.rs`:

```rust
pub trait Device: Send {
    type Platform: Platform;

    fn launch(&self) -> impl Future<Output = eyre::Result<()>> + Send;
    fn run(&self, artifact: Artifact, options: RunOptions) -> impl Future<Output = Result<Running, FailToRun>> + Send;
    fn platform(&self) -> Self::Platform;
}
```

Implementations: `AppleSimulator`, `MacOS`, `AndroidDevice`, `AndroidEmulator`

### Project Management

The `Project` type manages the `Water.toml` manifest and coordinates builds across platforms. Key methods:

- `Project::open()`: Open existing project
- `Project::create()`: Scaffold new project
- `Project::run()`: Build, package, and run on a device with optional hot reload

Example from `src/project.rs`:

```rust
pub async fn run(&self, device: impl Device, hot_reload: bool) -> Result<Running, FailToRun> {
    let platform = device.platform();

    // Build Rust library
    platform.build(self, BuildOptions::new(false, hot_reload)).await?;

    // Package for platform
    let artifact = platform.package(self, PackageOptions::new(false, true)).await?;

    // Start hot reload server if enabled
    let mut run_options = RunOptions::new();
    let server = if hot_reload {
        let server = HotReloadServer::launch(DEFAULT_PORT).await?;
        run_options.insert_env_var("WATERUI_HOT_RELOAD_HOST".to_string(), server.host());
        run_options.insert_env_var("WATERUI_HOT_RELOAD_PORT".to_string(), server.port().to_string());
        Some(server)
    } else { None };

    // Run on device
    let mut running = device.run(artifact, run_options).await?;
    if let Some(server) = server {
        running.retain(server); // Keep server alive
    }
    Ok(running)
}
```

### Hot Reload System

The hot reload system uses WebSocket to broadcast dylib updates to connected apps:

1. CLI launches `HotReloadServer` on `localhost:2006+`
2. Server monitors file changes with 250ms debouncing
3. On change, rebuild library and broadcast to all connected clients
4. Apps reload the updated library without restarting

Example from `src/debug/hot_reload.rs`:

```rust
pub async fn launch(starting_port: u16) -> Result<Self, FailToLaunch> {
    // Try ports 2006..2056
    for port in starting_port..(starting_port + PORT_RETRY_COUNT) {
        match Self::try_launch_on_port(port).await {
            Ok(server) => return Ok(server),
            Err(FailToLaunch::BindError(_, _)) => continue,
            Err(e) => return Err(e),
        }
    }
    Err(FailToLaunch::NoAvailablePort(starting_port, starting_port + PORT_RETRY_COUNT))
}

pub fn send_library(&self, data: Vec<u8>) {
    let _ = self.broadcast_tx.try_send(BroadcastMessage::Binary(data));
}
```

Environment variables `WATERUI_HOT_RELOAD_HOST` and `WATERUI_HOT_RELOAD_PORT` are passed to running apps.

### Rust Build

The `RustBuild` type wraps `cargo build` with platform-specific configuration:

- Target triple selection (e.g., `aarch64-apple-ios-sim`)
- Hot reload flag (`--cfg waterui_hot_reload_lib`)
- Simulator-specific clang args for bindgen

Example from `src/build.rs`:

```rust
let mut cmd = Command::new("cargo");
let mut cmd = command(&mut cmd)
    .arg("build")
    .arg("--lib")
    .args(["--target", self.triple.to_string().as_str()])
    .current_dir(&self.path);

if self.hot_reload {
    let mut rustflags = std::env::var("RUSTFLAGS").unwrap_or_default();
    if !rustflags.is_empty() { rustflags.push(' '); }
    rustflags.push_str("--cfg waterui_hot_reload_lib");
    cmd.env("RUSTFLAGS", rustflags);
}
```

### Toolchain Management

The `Toolchain` trait checks for required dependencies and provides installation plans:

```rust
pub trait Toolchain: Send + Sync {
    type Installation: Installation;
    fn check(&self) -> impl Future<Output = Result<(), ToolchainError<Self::Installation>>> + Send;
}

pub trait Installation: Send + Sync {
    type Error: Into<eyre::Report> + Send;
    fn install(&self) -> impl Future<Output = Result<(), Self::Error>> + Send;
}
```

Example: `AppleToolchain` checks for Xcode, simulators, and rust targets. `AndroidToolchain` checks for Android SDK, NDK, and JDK.

## Examples

### Run with Device Logs

```bash
water run --platform ios --logs debug
```

This streams device logs at debug level or above to the terminal.

### Run on Specific Device

```bash
# List available devices
water devices --platform ios

# Run on specific device by ID
water run --platform ios --device "iPhone 15 Pro"
```

### Create Project with Local WaterUI Development

```bash
water create my-app --dev --platform ios,android
```

This creates a project that uses the local WaterUI repository (useful for framework development).

### Build Without Running

```bash
water build --platform ios --release
```

### Clean Build Artifacts

```bash
water clean --platform ios
water clean --all  # Clean all platforms
```

### Check Development Environment

```bash
water doctor --platform ios
water doctor --platform android
```

This validates toolchain dependencies (Xcode, Android SDK, Rust targets).

## API Overview

### Library (`src/lib.rs`)

- **`platform`**: Platform trait and implementations (Apple, Android)
- **`device`**: Device trait, device types, run options, and events
- **`project`**: Project management, manifest parsing, create/open
- **`build`**: Rust build orchestration with cargo
- **`debug`**: Hot reload server, build manager, file watcher
- **`toolchain`**: Toolchain checking and installation
- **`backend`**: Backend configuration and scaffolding
- **`templates`**: Project scaffolding templates
- **`apple`**: Apple platform, devices, and backend
- **`android`**: Android platform, devices, and backend
- **`brew`**: Homebrew package management utilities
- **`water_dir`**: Global WaterUI directory management
- **`utils`**: Command execution helpers

### Terminal (`src/terminal/`)

- **`main.rs`**: CLI entry point, argument parsing
- **`shell.rs`**: Output formatting, spinners, colors
- **`commands/create.rs`**: Project scaffolding command
- **`commands/run.rs`**: Build and run command
- **`commands/build.rs`**: Build-only command
- **`commands/package.rs`**: Packaging command
- **`commands/clean.rs`**: Cleanup command
- **`commands/doctor.rs`**: Toolchain validation command
- **`commands/devices.rs`**: Device listing command

## Features

The CLI supports:

- **Hot reload**: WebSocket-based live code updates
- **Multi-platform**: iOS, macOS, Android with unified workflow
- **Device management**: Automatic device discovery and simulator launching
- **Interactive creation**: Guided project setup with prompts
- **Playground mode**: Auto-managed backends for quick prototyping
- **Parallel builds**: Device launch overlaps with compilation
- **Log streaming**: Real-time device logs with level filtering
- **JSON output**: Machine-readable output with `--json` flag
- **Graceful cancellation**: Ctrl+C cleanup without errors