docs(web-ui): logout, mark-all-read, cancel-X queue, qualified_label (follow-up to #576 #559 #575 #595)

This commit is contained in:
lexis 2026-05-29 19:36:56 +02:00 committed by Mara
commit b6bff2556d

View file

@ -225,6 +225,12 @@ appears under the main row showing the in-flight step name
(e.g. `↳ meta prepare_deploy``↳ nixos-container update` (e.g. `↳ meta prepare_deploy``↳ nixos-container update`
`↳ finalize deploy`). Terminal transitions clear `step` on the `↳ finalize deploy`). Terminal transitions clear `step` on the
backend so Done / Failed rows don't render stale labels. backend so Done / Failed rows don't render stale labels.
Queued entries carry a `✕` cancel button on the right edge
(#575); running / done / failed / cancelled entries don't show
it — the backend refuses cancellation for non-`Queued` rows
anyway (`POST /api/rebuild-queue/{id}/cancel`). Successful
cancel flips the row to `⊘ cancelled` via the next
`rebuild_queue_changed` snapshot.
Cold-loaded from `/api/state.rebuild_queue`; live updates via Cold-loaded from `/api/state.rebuild_queue`; live updates via
`rebuild_queue_changed` snapshot event. `rebuild_queue_changed` snapshot event.
@ -493,6 +499,11 @@ not ours.
rebuilds can't be safely interrupted). Always 200; body is rebuilds can't be safely interrupted). Always 200; body is
`{"cancelled": true}` on a successful flip or `{"cancelled": true}` on a successful flip or
`{"cancelled": false}` when the entry was not in `Queued` state. `{"cancelled": false}` when the entry was not in `Queued` state.
- `POST /api/agent/{name}/mark-all-read` — ack all pending broker
messages for `{name}` (#559). Backfills `delivered_at` for rows
not yet delivered and sets `acked_at = now`. Returns
`{ "marked": N }`. Agent name validated against
`[a-z0-9_-]`, 1-63 chars; 400 on bad input.
- `POST /op-send` (`to=<name>`, `body=<text>`) — drop an - `POST /op-send` (`to=<name>`, `body=<text>`) — drop an
operator-authored message into `<name>`'s inbox. `to=*` fans operator-authored message into `<name>`'s inbox. `to=*` fans
out to every registered agent. Returns 200; the broker out to every registered agent. Returns 200; the broker
@ -681,21 +692,32 @@ through. Three flex columns (#394 redesign):
click opens the loose-ends flyout. click opens the loose-ends flyout.
- **Overflow button** (`⋯`): always visible. Opens a frosted popover - **Overflow button** (`⋯`): always visible. Opens a frosted popover
(`#overflow-menu`, positioned outside the header to escape any (`#overflow-menu`, positioned outside the header to escape any
stacking context) with three rows: `↑ dashboard` (link), `↻ rebuild stacking context) with four rows: `↑ dashboard` (link), `↻ rebuild
container` (POST confirm, same action as the dashboard R3BU1LD container` (POST confirm, same action as the dashboard R3BU1LD
button), `↻ new claude session` (POST confirm → `POST button), `↻ new claude session` (POST confirm → `POST
/api/new-session`; next turn drops `--continue`). Both destructive /api/new-session`; next turn drops `--continue`), `🔓 logout`
actions require one extra click to acknowledge (#394 — rare ops (POST confirm → `POST /api/logout`; SIGINTs any in-flight turn,
shouldn't live in the primary state strip). wipes OAuth credential files, flips the agent to `needs_login`
— session history preserved). All destructive actions require
one extra click to acknowledge (#394 — rare ops shouldn't live
in the primary state strip).
`/api/state` is fetched once on cold load (+ while `/api/state` is fetched once on cold load (+ while
`status === 'needs_login_in_progress'`); all other updates arrive via `status === 'needs_login_in_progress'`); all other updates arrive via
SSE. Snapshot includes `context_window_tokens` for the ctx badge tooltip. SSE. Snapshot includes `context_window_tokens` for the ctx badge
tooltip, and `qualified_label` — the hive-qualified agent name
(`name@domain` form when `HYPERHIVE_HIVE_DOMAIN` is set, otherwise
just `name`). The frontend uses `qualified_label` to set the browser
tab title so two tabs from different hives are distinguishable; the
header `<h2 id="title">` stays short (#589 phase A).
**Main content** (`<main class="agent-main">`): fills the viewport **Main content** (`<main class="agent-main">`): fills the viewport
and scrolls behind the fixed header + footer. and scrolls behind the fixed header + footer.
- `#status` overlay: empty when online; shows the login form / OAuth - `#status` overlay: empty when online; shows the login form / OAuth
URL when `status` is `needs_login_*`. URL when `status` is `needs_login_*`. The OAuth code input is
`type="password"` with a `👁 reveal` toggle (#568 — avoids
accidental on-screen token exposure; `autocomplete="one-time-code"`
for password-manager suppression).
- Terminal-wrap: live event tail (sticky-bottom auto-scroll + - Terminal-wrap: live event tail (sticky-bottom auto-scroll +
`↓ N new` pill when not at bottom). `↓ N new` pill when not at bottom).
@ -710,7 +732,15 @@ dashboard's side panel shape. Carries inbox and loose-ends flyouts
(opened via the header pills) as well as long content (file previews, (opened via the header pills) as well as long content (file previews,
diffs, journald logs). Inbox flyout: last 30 messages addressed to diffs, journald logs). Inbox flyout: last 30 messages addressed to
this agent (`AgentRequest::Recent { limit: 30 }`); reply messages this agent (`AgentRequest::Recent { limit: 30 }`); reply messages
indented with `↳ reply ·` in amber. Loose-ends flyout: questions, indented with `↳ reply ·` in amber. A `✓ mark all read` button
appears in the flyout header when the inbox is non-empty (#559);
clicking it confirms then POSTs cross-origin to the core
dashboard's `POST /api/agent/{name}/mark-all-read` — all pending
messages for this agent are acked, the harness won't receive
wake-prompts for them. A `{ marked: N }` pill surfaces the count.
The displayed message list stays put (it shows the most-recent N
regardless of ack state); the unread badge on the next turn-start
will reflect zero. Loose-ends flyout: questions,
approvals, and reminders pending against this agent (`GET /api/loose-ends`); approvals, and reminders pending against this agent (`GET /api/loose-ends`);
question rows carry an inline answer form that POSTs cross-origin to question rows carry an inline answer form that POSTs cross-origin to
the core dashboard's `/answer-question/{id}` so the operator answers the core dashboard's `/answer-question/{id}` so the operator answers
@ -778,6 +808,9 @@ Slash commands today:
- `/new-session``POST /api/new-session` (confirms first). - `/new-session``POST /api/new-session` (confirms first).
Arms a one-shot on the Bus; next turn runs without Arms a one-shot on the Bus; next turn runs without
`--continue`, dropping the resume session entirely. `--continue`, dropping the resume session entirely.
- `/logout``POST /api/logout` (confirms first). Wipes OAuth
credential files, parks the agent in `needs_login`. Session
history (`~/.claude/projects/`) is preserved.
Unknown `/foo` shows an error row instead of being silently sent. Unknown `/foo` shows an error row instead of being silently sent.
@ -805,6 +838,12 @@ shaped).
future turns. `Bus::set_model` emits `ModelChanged`. future turns. `Bus::set_model` emits `ModelChanged`.
- `POST /api/new-session` — arm a one-shot for the next turn to - `POST /api/new-session` — arm a one-shot for the next turn to
drop `--continue`. Emits a `LiveEvent::Note`. 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.
- `GET /events/history` — replay buffer for the terminal. - `GET /events/history` — replay buffer for the terminal.
- `GET /screen` — VNC viewer page (minimal RFB-over-WebSocket - `GET /screen` — VNC viewer page (minimal RFB-over-WebSocket
renderer). Only accessible when `hyperhive.gui.enable = true` renderer). Only accessible when `hyperhive.gui.enable = true`