maestro-cli/src/config.rs was two pass-throughs, a newtype error, a two-field projection of MaestroConfigFile, and one four-line or_else with a single caller. `resolve_daemon_url` moves onto MaestroConfigFile, next to the schema it reads, and the module goes; its tests move with it. `[web].dev_proxy_target` is deleted end to end — schema, env var, normalisation, three tests, README line, and the startup warning that admitted the server ignores it. MaestroConfigFile::save had no callers outside its own tests. Deleting it also removes every skip_serializing_if, the five is_empty impls, and the Serialize derives that existed only to make its output tidy. BroadcastTuning was a struct that was never instantiated: all three uses were `::DEFAULT.field` in const position and there is no [broadcast] section. Now two plain consts. $MAESTRO_CONFIG was honoured twice, by resolve_config_path and by clap's `env =`. Every binary already gets it through clap, so resolve_config_path and CONFIG_PATH_ENV go and the TUI falls back to default_config_path like everything else. Also collapses three layers of 1:1 forwarding: the umbrella's cli_dispatch shim, and four near-identical 8-line functions in cli/dispatch.rs that differed only in which run_* they called. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
83 lines
2.3 KiB
Markdown
83 lines
2.3 KiB
Markdown
# maestro-web
|
|
|
|
Standalone HTTP server that hosts the Maestro browser UI and reverse-proxies
|
|
to a co-located `maestrod`.
|
|
|
|
```
|
|
browser ──HTTP──▶ maestro-web (:8080) ──HTTP/WS──▶ maestrod (:7070)
|
|
│
|
|
└── / serves the embedded SPA (web/dist)
|
|
/api/... proxied unmodified
|
|
/api/attach/:id, /api/events proxied as WebSocket
|
|
```
|
|
|
|
## Trust model
|
|
|
|
`maestro-web` does not authenticate anyone. Whoever can reach the bind address
|
|
can use it. Pick the bind accordingly:
|
|
|
|
| Bind | Reach | Use when |
|
|
| --------------------- | ---------------------------------- | --------------------------- |
|
|
| `127.0.0.1:8080` | Local users on this host | Default. Same as tmux. |
|
|
| `<wg-ip>:8080` | Devices on your WireGuard mesh | Phone/tablet over VPN. |
|
|
| `<lan-ip>:8080` | Devices on your trusted LAN | Home / lab networks. |
|
|
| Public IP | Don't | — add real auth first. |
|
|
|
|
## Config
|
|
|
|
The binary reads `~/.config/maestro/config.toml`. The `[web]` section:
|
|
|
|
```toml
|
|
[web]
|
|
bind_addr = "127.0.0.1:8080" # default
|
|
daemon_url = "http://127.0.0.1:7070" # default
|
|
```
|
|
|
|
Env-var overrides (all optional):
|
|
|
|
- `MAESTRO_WEB_BIND_ADDR`
|
|
- `MAESTRO_WEB_DAEMON_URL`
|
|
- `MAESTRO_WEB_DEV_PROXY_TARGET`
|
|
- `MAESTRO_CONFIG` — override the unified config-file path.
|
|
|
|
## Build
|
|
|
|
The SPA bundle lives in `../../web` and is embedded into the binary at compile
|
|
time via `include_dir!`. Build the frontend first:
|
|
|
|
```sh
|
|
pnpm -C web install
|
|
pnpm -C web build
|
|
cargo build -p maestro-web --release
|
|
```
|
|
|
|
Or, from the repo root:
|
|
|
|
```sh
|
|
just web
|
|
```
|
|
|
|
A fresh checkout compiles even without `pnpm build` (an empty `web/dist`
|
|
exists in-tree); the binary just serves a placeholder until the bundle is
|
|
built.
|
|
|
|
## Run
|
|
|
|
```sh
|
|
target/release/maestro-web
|
|
```
|
|
|
|
Then point a browser at `http://127.0.0.1:8080/`.
|
|
|
|
## Development workflow for the frontend
|
|
|
|
Use Vite directly so you get HMR. From `web/`:
|
|
|
|
```sh
|
|
pnpm dev
|
|
```
|
|
|
|
Vite serves on `:5173` and proxies `/api/*` straight to `maestrod` at
|
|
`127.0.0.1:7070` (override with `MAESTRO_DAEMON_URL=...`). You don't need to
|
|
rebuild the Rust binary while iterating on the frontend.
|