hive-ag3nt + docs: extract web_ui prose (#716 batch 6)

docs/web-ui.md:
- New `### Listener bind` subsection — uncapped TCP retry rationale
  (replaces stale "12 tries" claim that contradicted the code) +
  pointer to gateway.md for unix-socket transition
- Expand `/api/logout` bullet with three-step teardown rationale
  (SIGINT race, selective cred-file wipe preserves --continue,
  wait_for_login resumption path)

hive-ag3nt/src/web_ui.rs:
- serve / bind_unix / bind_with_retry rustdocs trimmed to docs
  pointers (binding modes, .bound marker, retry budget all live in
  the prose now)
- AgentLink / StateSnapshot.links / agent_links rustdocs trimmed
  to single-line summaries
- post_logout / CRED_FILE_NAMES rustdocs reference docs/web-ui.md
- 13 → 0 cookies
This commit is contained in:
iris 2026-05-31 17:23:15 +02:00 committed by mara
commit 55716be8fc
2 changed files with 117 additions and 123 deletions

View file

@ -217,10 +217,30 @@ previews are type-aware:
real content-type (text files stay UTF-8-lossy `text/plain`).
- **Everything else** — raw text in a `<pre>`.
Both bind their listeners with `SO_REUSEADDR` via
`tokio::net::TcpSocket` plus a retry loop on `AddrInUse` (12 tries,
exponential backoff capped at 2s) so an nspawn restart that races
the previous process's socket release resolves itself.
### Listener bind
Both bind their TCP listener with `SO_REUSEADDR` via
`tokio::net::TcpSocket` plus a retry loop on `AddrInUse`
(exponential backoff capped at 2s, **no attempt cap**) so an nspawn
restart that races the previous process's socket release resolves
itself. The retry is uncapped on purpose: a capped budget once
left the harness silently UI-less for the rest of its lifetime
when a back-to-back restart held the port longer than the cap
allowed. Genuine port collisions are preflighted host-side
(`lifecycle::{spawn,rebuild}` refuses with a clear error,
surfaced on the dashboard as a banner), so at this layer a
persistent `AddrInUse` always reflects a recoverable stale
socket — retrying forever is the safe choice. The first 12
attempts log at WARN; after that the level drops to INFO so a
long-held stale socket doesn't flood the journal.
The per-agent UI optionally binds a `UnixListener` instead of
TCP when `HIVE_WEB_SOCKET` is set — the unix-socket transition
mechanics (per-agent `/run/hive-agent/<name>/` bind-mount,
`.bound` marker filtering, `agent-sockets.json` consumer on the
gateway side) live in [`docs/gateway.md::Per-agent unix-socket
upstream`](gateway.md). The env var is opt-in per agent so the
two modes coexist while sub-agents transition.
### Per-agent relative paths
@ -1162,12 +1182,33 @@ shaped).
future turns. `Bus::set_model` emits `ModelChanged`.
- `POST /api/new-session` — arm a one-shot for the next turn to
drop `--continue`. Emits a `LiveEvent::Note`.
- `POST /api/logout` — SIGINT any in-flight turn, wipe OAuth
credential files (`.credentials.json` + `mcp-needs-auth-cache.json`
under `~/.claude/`), flip `LoginState::NeedsLogin`. Session
history (`~/.claude/projects/`) is preserved. Returns 200 with a
plain-text wipe summary. Emits `needs_login_idle` status via
`wait_for_login` entry.
- `POST /api/logout` — three-step teardown that re-uses the
existing `wait_for_login` resumption path:
1. SIGINT any running claude (matches `/api/cancel`'s pattern —
idempotent no-op when nothing is running) so the credential
wipe doesn't race a mid-API-call turn.
2. Delete only the OAuth credential files
(`.credentials.json` + `mcp-needs-auth-cache.json` under
`~/.claude/`). **Preserves** session history files
(`projects/<hash>/*.jsonl`), sessions, shell-snapshots,
plans, settings, telemetry, and the dir itself, so
`claude --continue` keeps working after a fresh login.
Wholesale `remove_dir_all` of `~/.claude/` was the previous
shape and broke session continuity; the narrowed allow-list
is the fix.
3. Flip `LoginState::NeedsLogin` + emit a `LiveEvent::Note`
describing exactly what was wiped, then emit
`needs_login_idle`. The turn-loop's next iteration parks
into `wait_for_login`, which snapshots the credential dir
(now missing the wiped files) and resumes when a fresh
credentials file appears via the dashboard's `/login/code`
flow (the same mtime-resumption path manual re-login uses).
Always returns 200 with a body describing what happened —
per-file errors are folded into the response + the Note so the
operator sees them in the live panel rather than as an HTTP
error. Missing files (already logged out) are treated as
idempotent.
- `GET /events/history` — replay buffer for the terminal.
- `GET /screen` — VNC viewer page (minimal RFB-over-WebSocket
renderer — deliberately thin, just enough to display the