feat(cli): honest first run — wait for the backend, diagnose Docker failures, show image progress - #98
Merged
Conversation
Derssa
approved these changes
Sep 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary of Changes
torollo startused to be blind on a first run: it only checkeddocker info's exit code, spawned the backend with its output discarded, printed "ready" immediately and opened the browser 1.2 s later — before the backend listened, and while the backend was pulling five images (minutes) with no signal. Three real failures were misreported: Docker Desktop on macOS (thedockerCLI follows contexts, the backend's dockerode does not, sodocker infopassed while the backend hitsocket_not_found), a user outside thedockergroup (reduced to "not installed"), and rootless Docker (host forwarding rules failed silently, breaking subnets/NAT/security groups without a word).This PR makes the first run honest:
startupStaterecords what the startup routine is doing (network, host forwarding, image by image with pull/build action).GET /healthnow exposes it asstartup, pluschecks.docker.rootlessandchecks.network(ok/unsupported(rootless) /failed). The daemon ping is bounded (10 s →timeoutreason).ensureHostForwardingnow waits for the privileged container's exit code instead of logging "applied successfully" unconditionally, and skips it on rootless daemons. The three duplicated local-build blocks (Mongo/Redis/RabbitMQ) collapse into one table-driven helper that also checks theapk/aptexit code. Existing response fields are unchanged, so the frontend probe and telemetry are untouched.bin/cli.jsis split into small testable modules underbin/lib/.startnow: resolves the Docker endpoint the way the backend will (DOCKER_HOST, else the activedocker context, handed down asDOCKER_HOSTso both sides target the same daemon); starts the backend with its output in~/.torollo/logs/backend.log; waits for/health(30 s timeout); gives a starting daemon a 20 s grace; on failure prints one diagnosis perreasonwith the fix command for the OS (socket_not_found,permission_denied,connection_refused,timeout, unknown); follows the image preloading with one line per image ("Downloading the Redis image (4/5)...", "Building the RabbitMQ image locally (5/5)...") and a heartbeat every 30 s; warns clearly on rootless Docker; prints "ready" and opens the browser only once both the backend and the frontend answer. A crashed backend after startup is reported with the log path instead of leaving a dead URL. New flag:--no-open.npm test(Node's built-in test runner, no new dependency) with acli-testCI job; test files excluded from the npm package;engines.node >= 18; README gets a short "Iftorollo startstops with an error" table.Adjacent findings, not addressed here:
derssa/backend-lab-rabbitmq:v1is not on Docker Hub, so every first run rebuilds it locally (publishing it would shorten the first run); the publishedderssa/*images are amd64-only.Types of Changes
Verification & Testing
Automated Checks
npm run lintsuccessfully with no errors (backend clean; frontend: 5 pre-existing warnings in untouched files)npm run buildsuccessfully with no compilation errors (backend + frontend)npm testsuccessfully (all tests pass) — root 32 (new), backend 509, frontend 367Manual Verification
Played
node bin/cli.js start --no-openagainst real Docker states on Linux (Fedora, rootless daemon + a root-owned/var/run/docker.sockthe user cannot open), each with a scratchHOME:Docker is running (rootless).→ rootless network warning → ready banner in ~2 sDOCKER_HOSTunset, active context =rootlessfrom docker context, backend reaches the same daemon (before:docker infopassed, backend got EACCES on/var/run/docker.sock)DOCKER_HOST=unix:///tmp/nope.sockDocker's socket was not found (…)+ "DOCKER_HOST points at a socket that does not exist"DOCKER_HOSTunset, no context,/var/run/docker.sockroot:dockerYour user is not allowed to open Docker's socket+sudo usermod -aG docker $USER+ relogin, no grace waitDocker is not running.+sudo systemctl start dockerDOCKER_HOST=tcp://10.255.255.1:2375(blackhole)timeoutafter 10 s, CLI:Docker is not answering.TOROLLO_HOSTinvalid)The Torollo backend did not start.+ log path, within 1.5 sderssa/backend-lab-redis:v1and…-rabbitmq:v1removedFirst run: downloading…→Downloading the Redis image (4/5)...(Hub) →Downloading the RabbitMQ image (5/5)...→Building the RabbitMQ image locally (5/5)…(no Hub tag) →Node images are ready.→ banner; both tags back, no leftover build containerThe Torollo backend stopped unexpectedly (SIGKILL).+ log pathAlso confirmed on this host that the privileged host-forwarding container fails under rootless Docker (
iptables: Permission denied (you must be root)) — which the old code logged as a success.Checklist