The browser reached the daemon through maestro-web, a second binary that
served the SPA and reverse-proxied /api/* — two TCP connections and a
WebSocket frame re-encode on every keystroke and every byte of PTY output.
On one machine that hop buys nothing.
The daemon now embeds the bundle and serves it off its own listener, behind
a default-on `web` feature. `--no-default-features` builds without pnpm or
node; MAESTRO_WEB_DIST still takes a prebuilt bundle.
The router's fallback answers an unmatched /api/* with 404 rather than the
SPA shell, so a client expecting JSON gets a status it can read instead of
HTML.
Removes maestro-web and the [web] config section. An existing [web] block
is ignored, not rejected. The installer deletes a leftover
maestro-web.service on upgrade.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The `flake` job was the pipeline's critical path at ~9 minutes, all of it
one cold `nix build`: with an empty /nix every run, it recompiled the whole
release closure under `lto = "thin"` + `codegen-units = 1`.
- Cache /nix across runs, keyed on the lockfiles the closure derives from,
so crane's deps-only derivation survives and only maestro's own crates
rebuild. Saved from pushes only, so a PR cannot write a partial store.
- Build only `.#webFrontend` on PRs — that is the step that guards
pnpmDeps.hash. The release binaries stay on main.
- Replace the hand-rolled `target/` cache with Swatinem/rust-cache, which
prunes to the current lockfile instead of accumulating stale artifacts
behind a prefix restore-key. ~60s per run went into moving that entry.
- Run tests under cargo-nextest, which parallelises across the 20
integration binaries. Capped at 4 threads in .config/nextest.toml: the
tmux-backed tests starve each other at the num-cpus default and trip
their 5s deadlines.
- actions/setup-node instead of a second apt-get pass via nodesource.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pushes queued a new run without stopping the old one. Group by ref and
cancel in-progress, except on main where runs finish.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The runner container is root with no `nixbld` group. The installer
writes `build-users-group = nixbld` regardless and then fails on it:
error: the group 'nixbld' specified in 'build-users-group' does not exist
Writing the config first (and again after, in case the installer
replaced it) clears that and enables flakes in the same place.
Refs #98
Two defects in the job as landed, both invisible locally:
- The multi-user installer needs systemd, which the act_runner container
does not have. Single-user install instead.
- The installer does not enable flakes, so `nix build .#…` fails on a
fresh install. A machine with them in nix.conf builds fine, which is
why this passed locally and failed in CI.
Refs #98
A web/pnpm-lock.yaml change invalidates the pinned pnpmDeps.hash in
flake.nix silently; nix build .#maestro-web then stays broken until
someone notices by hand (#98). Add a flake job that installs nix and
builds the packaged outputs on every CI run.
The umbrella `maestro` binary had zero coverage of its feature-gate
combinations (cli / daemon / registry / tui). Add:
- Unit tests in `main.rs` for `is_cli_subcommand` classification (CLI vs
server subcommands, plus the always-false non-`cli` stub) and the
`-v` verbosity -> tracing-directive mapping.
- A `verbosity_directive` helper, extracted from `cli_filter` purely to
make the verbosity mapping testable without touching the process-global
`RUST_LOG` (behavior unchanged).
- An integration test (`tests/cli.rs`) driving the real built binary via
`CARGO_BIN_EXE_maestro`, asserting the `--help`/`--version`/subcommand
dispatch surface. Per-subcommand checks are `#[cfg]`-gated so the suite
is meaningful under every feature subset.
- A CI feature-gate matrix step: build + test each of cli/daemon/registry/
tui in isolation, and assert the no-feature build is rejected.
All four subsets and the default build pass fmt, clippy, and tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The browser app had no tests and no way to run any: package.json shipped
dev/build/preview/typecheck, and CI installed Node and pnpm but never ran
anything with them. Its densest logic was module-private, so even with a
runner none of it was reachable.
Extracts four pure modules out of DOM-heavy ones — tree.ts (directory
grouping), keys.ts (terminal escape encoding), paths.ts (completion
arithmetic), html.ts (one escaper, replacing four copies). Extraction
rather than `export` because attach.ts imports xterm's CSS at module
level, which a node test cannot load.
CatalogStore takes an injectable socket factory, scheduler and refetch, so
the reducer and the backoff schedule run without a server. snapshot() now
returns a copy: it returned the live object while events mutated it in
place, so listeners could not diff and every event rebuilt the whole tree.
36 tests across 6 files, and a `web` CI job running typecheck, test and
build. vitest is pinned to 2.x — 4.x requires vite >= 6 and this is vite 5.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Compiling maestro-web now requires the frontend toolchain to build the
embedded SPA bundle.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`rust:1.83-bookworm` has no Node, which breaks `actions/checkout@v4`
(it's a JS action). The default gitea runner image has Node, so go back
to that and install rustup + tmux + git + build-essential ourselves.
CI has been red since NAP-211 because docker.gitea.com/runner-images:
ubuntu-latest has no `rustup`; the toolchain install step exits 127.
- Use `rust:1.83-bookworm` as the job container so rustup + cargo + a
stable toolchain are pre-installed
- Install `tmux` + `git` so the daemon integration tests can run
- Add `rustfmt` and `clippy` components
- Also trigger on pushes to `linear/**` so yolo branches see CI before
they're merged
Adds the empty Cargo workspace (resolver = 2, members = crates/*),
a stable rust-toolchain pin with rustfmt + clippy, and a Gitea
Actions pipeline that runs cargo fmt --check, clippy -D warnings,
and cargo test on every push/PR.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>