Files
multica/server
YYClaw 7d04b1d9a3 fix(cli): fail fast with actionable daemon startup errors
* fix(cli): fail fast with login hint when starting daemon unauthenticated

'multica daemon start' (background mode) spawned the child first and
only then polled its health port. When the user never ran 'multica
login', the child died instantly on resolveAuth, but the parent kept
polling for the full 45s readiness window and ended with a vague
"check logs" warning and exit code 0 — looking like a silent hang.

Check the stored config token before spawning (mirroring
daemon.resolveAuth, which only accepts the config token) and exit
immediately with an actionable "run 'multica login'" hint.

'daemon restart' gets the same guard BEFORE its stop phase: it used
to stop the running daemon first and only then fail auth inside the
start phase, leaving the user with no daemon at all. The foreground
path already failed fast and is unchanged.

* fix(cli): report early daemon child exit with an actionable reason

Background 'daemon start' Release()d the child immediately and then
polled the health port blind. Any preflight failure — server
unreachable, stored token rejected with 401 — killed the child within
a second, but the parent still sat through the full 45s readiness
window and ended with a vague "check logs" warning and exit code 0.

Keep a Wait() goroutine on the child and select on it inside the
readiness poll. When the child dies before reporting ready, classify
what this startup attempt appended to the log and fail with exit
code 1 and a one-line reason plus next step:

  - token rejected / 401  -> run 'multica login' (profile-scoped)
  - connection refused / DNS / timeout -> server unreachable at <url>
  - anything else -> short log excerpt with DBG/INF noise dropped

* fix(cli): probe token validity and server reachability before restart stops the daemon

requireDaemonAuth only rejects an empty stored token, so a revoked or
expired token — or an unreachable server — passed the restart guard,
the running daemon was stopped, and the replacement child then died in
preflight, leaving no daemon at all (#5165).

daemon restart now runs a whoami round-trip (same /api/me call as
'multica auth status') against the server the daemon will talk to,
using the stored token, before entering the stop phase — and only when
a daemon is actually running, so plain 'daemon start' keeps its
zero-round-trip happy path. On 401 it reports the re-login hint; on a
transport error it reports the unreachable server; both state that the
running daemon was left untouched.

Regression tests cover a non-empty stored token against a fake 401
server and an unreachable server, asserting /shutdown is never
requested on the fake running daemon.
2026-07-17 13:27:06 +08:00
..