Commit Graph
6 Commits
Author SHA1 Message Date
naps62-yolo 35482118b1 feat(maestro): unify maestro/maestrod/maestro-registry into single binary (NAP-245)
New `crates/maestro/` umbrella binary hosts the CLI, daemon, and registry
behind Cargo features `cli`, `daemon`, `registry` (default = all three).
Library crates keep their structure; per-binary `main.rs` files are removed
and their dispatch logic is exposed as public functions:

- `maestro_cli::dispatch(command, config, registry_url)`
- `maestro_daemon::cli::dispatch(config, cmd)` (with public `DaemonCmd`/`ConfigureArgs`)
- `maestro_registry::run()`

Subcommand surface:

- `maestro list / spawn / attach / kill / set-registry / policy` (unchanged)
- `maestro daemon [run|configure]` (was `maestrod`)
- `maestro registry` (was `maestro-registry`)

Hard cutover — old binary names are not preserved.

Verified: default-feature build, plus `--no-default-features --features {cli|daemon|registry}`
each build clean with `-D warnings`.
2026-05-27 10:35:41 +00:00
naps62-yoloandClaude Opus 4.7 f69c7a9eee feat(maestro): hot-reload [daemon.policy] via SIGHUP + maestro policy CLI (NAP-237)
ci / rust (push) Failing after 2m51s
`PairAttachVerifier` now stores `allow_inbound` behind `Arc<RwLock<_>>` so
clones share the same set. Two triggers re-read the unified config file
and swap it atomically:

- SIGHUP — `systemctl --user reload maestrod`, or any `kill -HUP`. The
  installer's user unit now sets `ExecReload=/bin/kill -HUP $MAINPID`.
- `POST /api/policy/reload` — used by `maestro policy reload`. The CLI
  reads `[daemon].bind_addr` from the unified config (default 7070) and
  POSTs to `http://127.0.0.1:<port>`. No PID lookup required.

Also adds `maestro policy show [--json]` and `GET /api/policy` for
"did my edit get picked up?" debugging. A broken mid-edit config logs
an error and leaves the previously-effective list in place rather than
locking everyone out.

In-flight attaches keep their existing connection — revocation requires
killing the session, as spec'd.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 09:53:19 +00:00
naps62-yolo 094cd1ffce fix(maestro): drop SHARED_ prefix from [shared] env vars
ci / rust (pull_request) Successful in 4m13s
The shared section is the implicit global scope, so its fields use
the bare `MAESTRO_<FIELD>` env-var spelling. Only `[daemon]` and
`[registry]` sections get section-prefixed env vars.

Renames:
- MAESTRO_SHARED_TOKEN        → MAESTRO_TOKEN
- MAESTRO_SHARED_REGISTRY_URL → MAESTRO_REGISTRY_URL

`MAESTRO_DAEMON_*` and `MAESTRO_REGISTRY_BIND_ADDR` are unchanged.

This restores the canonical spec name (`MAESTRO_TOKEN`) that operators
already use in their deployment scripts — NAP-233 had renamed it to
`MAESTRO_SHARED_TOKEN`, which silently broke daemon auth against
existing registry deployments still setting `MAESTRO_TOKEN` in env.

Constants renamed alongside: `ENV_SHARED_TOKEN` → `ENV_TOKEN`,
`ENV_SHARED_REGISTRY_URL` → `ENV_REGISTRY_URL`. `EnvOverrides` fields
shed their `shared_` prefix to match.

Touches: daemon/cli/registry crates, e2e harness, design spec.
2026-05-26 13:24:29 +00:00
naps62-yolo efaa8bfe13 feat(maestro): wire maestro-cli to unified config (NAP-233)
CLI now reads `[shared].registry_url` and `[cli].cookie` from the unified
file via maestro-config instead of `~/.config/maestro/cli.toml`. The
two persistence paths are now distinct:

- `maestro set-registry <url>` → writes `[shared].registry_url`
- captured Set-Cookie on first contact → writes `[cli].cookie`

Both go through read-modify-write so they preserve any `[daemon]` /
`[registry]` content already in the file.

Env-var renames on the CLI flag layer:
- `--registry-url` reads `MAESTRO_SHARED_REGISTRY_URL` (was `MAESTRO_REGISTRY_URL`)
- `--config`       reads `MAESTRO_CONFIG`               (was `MAESTRO_CLI_CONFIG`)

Default config path is now `~/.config/maestro/config.toml`.
2026-05-26 09:24:51 +00:00
naps62-yoloandClaude Opus 4.7 c1b4fe0bb6 fix(maestro): make attach exit cleanly when session ends (NAP-226)
ci / rust (push) Successful in 2m15s
When a session terminates (the user runs `exit`, tmux is killed, or
`maestro kill` is called) the daemon's per-session broadcast channel
closes and `serve_attach` breaks out of its loop. The socket was then
dropped without a Close frame, so the client's `stream.next()` would
hang and the terminal stayed stuck in raw mode.

- daemon: send `Message::Close(None)` before returning from
  `serve_attach` whenever the session itself ended (broadcast closed,
  or session was killed between auth and subscribe).
- client: track remote-close, restore the TTY first, then print
  `[maestro] session ended` so the message lands in cooked mode.
- tests: cover the kill path and the liveness-watcher reap path on the
  daemon side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 08:49:00 +00:00
naps62-yoloandClaude Opus 4.7 b68e39a9e5 feat(maestro): maestro-cli — list/spawn/attach/kill
ci / rust (push) Successful in 1m7s
Closes NAP-216. Thin client for the registry HTTP API + per-session
daemon WebSocket. Becomes the headless test harness for NAP-217 and
unblocks the demo-by-script path before the web client lands (NAP-218).

Crate layout (`crates/maestro-cli/`):

- `cli.rs` — clap-derive parser. Commands: `list`, `spawn`, `attach`,
  `kill`, `set-registry`. Global `--registry-url` (env
  `MAESTRO_REGISTRY_URL`), `--config`, repeatable `-v`.
- `config.rs` — `CliConfig` persisted at `~/.config/maestro/cli.toml`,
  storing the default registry URL + the session cookie issued by the
  registry's cookie middleware.
- `http.rs` — `RegistryClient` wrapping `reqwest`. Attaches the
  persisted cookie, captures `Set-Cookie` responses (first-contact
  bootstrap and rotation), atomically writes the new value back to
  the config file.
- `sessions.rs` — `list/spawn/kill` + connect-info fetch. `list` prints
  a per-daemon grouped table; `--json` for scripting.
- `attach.rs` — raw-TTY WS proxy. Termios cfmakeraw with an RAII guard
  for restore-on-drop, SIGWINCH → `ClientControl::Resize` text frame,
  configurable detach key (default Ctrl-q; accepts `^X` form), echoes
  `Ping`/`Pong` for keepalive symmetry with the daemon side.

Workspace deps added: clap (derive+env), reqwest (rustls+cookies),
nix (term+signal).

Smoke-tested against the live registry at maestro-registry.n62.casa:
`maestro list` issued + persisted the cookie and printed the empty
catalog cleanly. 19 new unit tests (parser, config round-trip,
table-printing, cookie extraction, attach URL/detach-key parsing).
Full workspace `cargo test`: 97 passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 09:49:46 +00:00