feat(cli): seats, init, doc, browser install and stop

- `seats` reports every seat probed (Fable first, Haiku for a seat that
  needs it), the API seats beside the driver's ledger, the drivers on the
  board, or all of it as JSON. In the sandbox a last line names `stop`,
  since the pids above cannot be signalled from there.
- `init` sets a repository up: the config from the template, the artifact
  and worktree dirs ignored, the prepush skill with a marker that lets a
  later init refresh it. The old link into the review-gates submodule is
  replaced by a real directory, never written through. A foreign link, a
  subdirectory, the home directory and a dir outside git are refused before
  anything is written.
- `doc [--path] prepush|manifest|config` prints a shipped text, or where
  the host sees it (the deployment's `active` link in the Flatpak).
- `browser install` runs the installer of the Playwright the pinned MCP
  server depends on, and checks the Chromium revision landed.
- `stop <scratch>` and `stop --hash <hash8>` write the stop file a running
  driver checks every 2 s, for live drivers only; the board is read, never
  written.

The option parser takes positionals, in the usage line, the help and the
errors. The Commands test runs all of them through this binary, seats on a
claude stand-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jorijn van der Graaf 2026-10-31 15:45:36 +01:00
commit 2dd73b59bd
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
6 changed files with 751 additions and 9 deletions

View file

@ -820,6 +820,11 @@ namespace Crafter::Review::Seats {
}
}
std::string Clock(double epoch, const Zone& zone) {
const std::tm d = InZone(static_cast<std::time_t>(std::floor(epoch)), zone);
return std::format("{:02d}:{:02d}", d.tm_hour, d.tm_min);
}
std::string FormatWhen(double epoch, double now, const Zone& zone) {
const auto diffMin = static_cast<std::int64_t>(JsRound((epoch - now) / 60));
std::string relative;