docs(dashboard): fix misplaced CR3D3NTIALS content, dedupe, trim history
This commit is contained in:
parent
66442d41ff
commit
785b59a4bb
1 changed files with 184 additions and 225 deletions
|
|
@ -212,8 +212,8 @@ Three sub-tabs: **R3BU1LD QU3U3** (default), **M3T4 1NPUTS**,
|
||||||
`/api/state` and subscribes to `/api/dashboard/stream` for
|
`/api/state` and subscribes to `/api/dashboard/stream` for
|
||||||
`rebuild_queue_changed`, `meta_inputs_changed`, `meta_update_running`.
|
`rebuild_queue_changed`, `meta_inputs_changed`, `meta_update_running`.
|
||||||
The SW4RM tab (`/dashboard.html`) does **not** read this endpoint at
|
The SW4RM tab (`/dashboard.html`) does **not** read this endpoint at
|
||||||
all — mara, on review: "swarm.js should not need to pull in the jobq
|
all, by design — the swarm view stays independent of job-queue
|
||||||
to do its job." Its per-agent pending badges are transient-only, and
|
internals. Its per-agent pending badges are transient-only, and
|
||||||
its queue-summary banner reads the much narrower `GET /api/jobq/rollup`
|
its queue-summary banner reads the much narrower `GET /api/jobq/rollup`
|
||||||
instead (see Container row, below) — a handful of pre-tallied counts,
|
instead (see Container row, below) — a handful of pre-tallied counts,
|
||||||
not the graph.
|
not the graph.
|
||||||
|
|
@ -239,23 +239,21 @@ array order, unchanged from the wire). A row shows a state glyph (`⏸`
|
||||||
pending / `▶` running / `◐` finishing — own work done, a sub-node
|
pending / `▶` running / `◐` finishing — own work done, a sub-node
|
||||||
still running / `✔` done / `✖` failed / `⊘` cancelled / `·` skipped)
|
still running / `✔` done / `✖` failed / `⊘` cancelled / `·` skipped)
|
||||||
and each step's own label/agent. A `Node`-kind dep on a sibling shows
|
and each step's own label/agent. A `Node`-kind dep on a sibling shows
|
||||||
as a plain "waits on: `<label>`" text line under the row — an earlier
|
as a plain "waits on: `<label>`" text line under the row rather than a
|
||||||
gutter-rail version was reverted (it broke visually whenever a nested
|
gutter rail — a rail breaks visually whenever a nested subtree sits
|
||||||
subtree sat between the two related rows; text has no such gap).
|
between the two related rows, since a text line needs no continuous
|
||||||
|
vertical space to draw.
|
||||||
`builds.js` mounts the element with `cancellable` set, which turns on
|
`builds.js` mounts the element with `cancellable` set, which turns on
|
||||||
a per-node cancel button (`✕`) on any non-terminal row — the button
|
a per-node cancel button (`✕`) on any non-terminal row — the button
|
||||||
dispatches `hive-jobq-graph-cancel`, and the page does the actual
|
dispatches `hive-jobq-graph-cancel`, and the page does the actual
|
||||||
`POST /api/rebuild-queue/{id}/cancel`, matching the wire event as its
|
`POST /api/rebuild-queue/{id}/cancel`, matching the wire event as its
|
||||||
own domain concept (the component knows nothing about that endpoint).
|
own domain concept (the component knows nothing about that endpoint).
|
||||||
**Still no source chip, kind label, timing, or build-log deep-link on
|
**Rows carry no source chip, kind label, timing, or build-log
|
||||||
rows** — no equivalent of the old `DagView`'s `source`/`reason`/
|
deep-link** — the generic graph wire doesn't carry those fields, and
|
||||||
`created_at`, which were `NodeKind::Dag`-specific fields the generic
|
rows are meant to present exactly what the endpoint provides rather
|
||||||
wire doesn't carry; per mara's original steer ("dont feel constrained
|
than reconstruct chrome the backend no longer sends. Settled entries
|
||||||
by what the ui does currently"), rows present what the endpoint
|
render their **full step tree**, not just a bare summary — the wire
|
||||||
actually gives rather than reconstructing the old per-row chrome.
|
does not filter `Done` nodes out.
|
||||||
Settled entries render their **full step tree**, not just a bare
|
|
||||||
summary — unlike the old `DagView` projection, this wire does not
|
|
||||||
filter `Done` nodes out.
|
|
||||||
|
|
||||||
**State filter (hyperhive#2606).** A row of per-state checkboxes above
|
**State filter (hyperhive#2606).** A row of per-state checkboxes above
|
||||||
the tree — one per lifecycle state, matching the row glyphs — lets the
|
the tree — one per lifecycle state, matching the row glyphs — lets the
|
||||||
|
|
@ -359,24 +357,6 @@ The status dot renders these states:
|
||||||
!live` "provisioned but offline" case.
|
!live` "provisioned but offline" case.
|
||||||
- **grey** — no token (not provisioned).
|
- **grey** — no token (not provisioned).
|
||||||
|
|
||||||
### GITHUB tab
|
|
||||||
|
|
||||||
Provision a single per-agent GitHub personal access token (see
|
|
||||||
[`docs/github.md`](../github.md) for the injection + `gh`/git-push
|
|
||||||
mechanics). No login flow — the operator pastes an existing PAT for a
|
|
||||||
dedicated bot account, with a security-warning banner (dedicated account +
|
|
||||||
minimally-scoped token) and a link to
|
|
||||||
[github.com/settings/tokens](https://github.com/settings/tokens).
|
|
||||||
|
|
||||||
Status reads `GET /api/github-account?agent=<name>` →
|
|
||||||
`{ present: bool }` — whether the agent's `github-token` file exists.
|
|
||||||
There's no live/heartbeat concept for a static PAT, so this is just a
|
|
||||||
"token stored ✓" / "not set" line, unlike MATRIX's status-dot taxonomy.
|
|
||||||
Provisioning posts `POST /api/github-account` (form-encoded `agent`,
|
|
||||||
`token`) → `200 { ok: true }` on success, or the same `error_response`
|
|
||||||
shape `/api/matrix-account-login` uses on failure. The token is never
|
|
||||||
echoed back in either direction.
|
|
||||||
|
|
||||||
The container-down cross-reference (`/api/state`) takes precedence over
|
The container-down cross-reference (`/api/state`) takes precedence over
|
||||||
the age check. `as_of_unix` is tooltipped ("live as of N ago") throughout
|
the age check. `as_of_unix` is tooltipped ("live as of N ago") throughout
|
||||||
so freshness is always legible. When `live` is absent (an older backend
|
so freshness is always legible. When `live` is absent (an older backend
|
||||||
|
|
@ -398,6 +378,24 @@ regardless of outcome. The account list reflects what is *provisioned*
|
||||||
(an account with a stored token), so a config-declared-but-unprovisioned
|
(an account with a stored token), so a config-declared-but-unprovisioned
|
||||||
account appears only once it has been provisioned through the form.
|
account appears only once it has been provisioned through the form.
|
||||||
|
|
||||||
|
### GITHUB tab
|
||||||
|
|
||||||
|
Provision a single per-agent GitHub personal access token (see
|
||||||
|
[`docs/github.md`](../github.md) for the injection + `gh`/git-push
|
||||||
|
mechanics). No login flow — the operator pastes an existing PAT for a
|
||||||
|
dedicated bot account, with a security-warning banner (dedicated account +
|
||||||
|
minimally-scoped token) and a link to
|
||||||
|
[github.com/settings/tokens](https://github.com/settings/tokens).
|
||||||
|
|
||||||
|
Status reads `GET /api/github-account?agent=<name>` →
|
||||||
|
`{ present: bool }` — whether the agent's `github-token` file exists.
|
||||||
|
There's no live/heartbeat concept for a static PAT, so this is just a
|
||||||
|
"token stored ✓" / "not set" line, unlike MATRIX's status-dot taxonomy.
|
||||||
|
Provisioning posts `POST /api/github-account` (form-encoded `agent`,
|
||||||
|
`token`) → `200 { ok: true }` on success, or the same `error_response`
|
||||||
|
shape `/api/matrix-account-login` uses on failure. The token is never
|
||||||
|
echoed back in either direction.
|
||||||
|
|
||||||
### FORGES tab
|
### FORGES tab
|
||||||
|
|
||||||
Store a **label + base URL + access token** for an external Forgejo/Gitea/
|
Store a **label + base URL + access token** for an external Forgejo/Gitea/
|
||||||
|
|
@ -467,10 +465,8 @@ The current capabilities are:
|
||||||
Each row is one agent. Columns are the capability names returned by
|
Each row is one agent. Columns are the capability names returned by
|
||||||
`GET /api/capabilities` as `caps: Vec<String>`. Checking or unchecking
|
`GET /api/capabilities` as `caps: Vec<String>`. Checking or unchecking
|
||||||
boxes only stages the change in-browser; nothing is written until the
|
boxes only stages the change in-browser; nothing is written until the
|
||||||
page-level **save all** button (described below) is clicked. The
|
page-level **save all** button (described below) is clicked. Row
|
||||||
checkboxes reflect the *effective* set (explicit grant or role default),
|
values follow the `effective`/`assignments` rule described above.
|
||||||
so a default-perms agent shows its real grants rather than blank; absent
|
|
||||||
agents in the assignment map have no extra capabilities.
|
|
||||||
|
|
||||||
**T00L GR0UPS** — per-agent tool-group permissions. Tool groups are
|
**T00L GR0UPS** — per-agent tool-group permissions. Tool groups are
|
||||||
named buckets of MCP tools; each agent starts with a role default
|
named buckets of MCP tools; each agent starts with a role default
|
||||||
|
|
@ -752,9 +748,8 @@ isn't currently listed.
|
||||||
|
|
||||||
The row is a `flex-wrap: wrap` container holding ts / arrow / from / sep
|
The row is a `flex-wrap: wrap` container holding ts / arrow / from / sep
|
||||||
/ to chips inline; the **body wraps to its own full-width line below** the
|
/ to chips inline; the **body wraps to its own full-width line below** the
|
||||||
chips (`flex: 1 1 100%`) so the body always gets the full row width down to
|
chips (`flex: 1 1 100%`) so long timestamps and agent names never push the
|
||||||
the content edge — long timestamps + agent names used to push the body ~30ch
|
body into a narrow trailing column. `min-width: 0` keeps
|
||||||
in and force awkward narrow-column wraps. `min-width: 0` keeps
|
|
||||||
`word-break: break-word` effective so the body doesn't force the row wider
|
`word-break: break-word` effective so the body doesn't force the row wider
|
||||||
than its container. Sticky-bottom auto-scroll + "↓ N new" pill. Below the
|
than its container. Sticky-bottom auto-scroll + "↓ N new" pill. Below the
|
||||||
stream sits a terminal-style compose box: `@name` picks the recipient
|
stream sits a terminal-style compose box: `@name` picks the recipient
|
||||||
|
|
@ -783,9 +778,8 @@ latter — never guessed from the operator's browser hostname + a container
|
||||||
port, which is only right by accident off plain localhost. Operators without
|
port, which is only right by accident off plain localhost. Operators without
|
||||||
matrix or forge enabled — or with forge on but no public URL configured —
|
matrix or forge enabled — or with forge on but no public URL configured —
|
||||||
never see a dead or wrong link. `home.js` also fills the swarm/hive identity
|
never see a dead or wrong link. `home.js` also fills the swarm/hive identity
|
||||||
line at the top. Dashboard is now served at `/dashboard.html` (route swap
|
line at the top. All dashboard sub-pages include a `← Home` back-link for
|
||||||
completed in #1464 step 2); the home page at `/` replaces the old dashboard
|
navigation.
|
||||||
root. All dashboard sub-pages include a `← Home` back-link for navigation.
|
|
||||||
|
|
||||||
## L0GS page (`/logs.html`)
|
## L0GS page (`/logs.html`)
|
||||||
|
|
||||||
|
|
@ -862,122 +856,127 @@ is known stopped up front (`ContainerView.running = false`) the
|
||||||
fallback fires immediately, skipping the doomed `<url>/icon`
|
fallback fires immediately, skipping the doomed `<url>/icon`
|
||||||
fetch entirely.
|
fetch entirely.
|
||||||
|
|
||||||
- Line 1: agent name (link → new tab), m1nd/ag3nt chip, an
|
**Line 1** — agent name (link → new tab), m1nd/ag3nt chip, an
|
||||||
**icon-only nav strip** plus live agent-owned state, all populated
|
**icon-only nav strip** plus live agent-owned state, all populated
|
||||||
async from a single `GET /api/dashboard-state` call to the
|
async from a single `GET /api/dashboard-state` call to the agent's
|
||||||
agent's own backend. The response (`DashboardState`) carries:
|
own backend. The response (`DashboardState`) carries: `links` (nav
|
||||||
`links` (nav strip entries — `📊 stats`, `🖥 screen` when GUI is
|
strip entries — `📊 stats`, `🖥 screen` when GUI is enabled, `⬡ forge
|
||||||
enabled, `⬡ forge profile`, `↳ agent-configs mirror`, plus any
|
profile`, `↳ agent-configs mirror`, plus any agent-declared
|
||||||
agent-declared `dashboardLinks` extras), `status_text` /
|
`dashboardLinks` extras), `status_text` / `status_set_at` (agent
|
||||||
`status_set_at` (agent self-reported status — the `(set N ago)`
|
self-reported status — the `(set N ago)` chip is stamped `data-set-at`
|
||||||
chip is stamped `data-set-at` and ticks every 30s to stay fresh
|
and ticks every 30s to stay fresh across the long-lived keyed row
|
||||||
across the long-lived keyed row cache), `rate_limited`,
|
cache), `rate_limited`, `ctx_tokens` / `context_window_tokens`
|
||||||
`ctx_tokens` / `context_window_tokens` (context-window badge
|
(context-window badge data). The agent backend is the single source
|
||||||
data). The agent backend is the single source of truth for all
|
of truth for all of these. The dashboard resolves each `AgentLink.kind`
|
||||||
of these. The dashboard resolves each `AgentLink.kind` against a
|
against a per-agent base URL depending on whether hive-gateway is in
|
||||||
per-agent base URL depending on whether hive-gateway is in front
|
front (`StateSnapshot.gateway_enabled`, sourced from the
|
||||||
(`StateSnapshot.gateway_enabled`, sourced from the
|
`HIVE_GATEWAY_ENABLED` env the c0re NixOS module sets when
|
||||||
`HIVE_GATEWAY_ENABLED` env the c0re NixOS module sets when
|
`services.hyperhive.gateway.enable = true`). Gateway-on (default):
|
||||||
`services.hyperhive.gateway.enable = true`). Gateway-on (default):
|
base URL is `/agent/<name>` (same origin, gateway proxies to the
|
||||||
base URL is `/agent/<name>` (same origin, gateway proxies to the
|
per-agent harness — TCP or unix-domain depending on the agent's
|
||||||
per-agent harness — TCP or unix-domain depending on the agent's
|
`HIVE_WEB_SOCKET` opt-in, see
|
||||||
`HIVE_WEB_SOCKET` opt-in, see
|
`docs/gateway.md::Per-agent unix-socket upstream`).
|
||||||
`docs/gateway.md::Per-agent unix-socket upstream`).
|
Gateway-off (legacy / local dev): base URL is
|
||||||
Gateway-off (legacy / local dev): base URL is
|
`http://<host>:<container.port>` (direct TCP fallback). Forge
|
||||||
`http://<host>:<container.port>` (direct TCP fallback). Forge
|
links resolve against `state.forge_public_url` (sourced from
|
||||||
links resolve against `state.forge_public_url` (sourced from
|
`services.hyperhive.forge.publicUrl`) and are omitted entirely when
|
||||||
`services.hyperhive.forge.publicUrl`) and are omitted entirely when
|
that's unset — never guessed from `<host>:3000`. External links are
|
||||||
that's unset — never guessed from `<host>:3000`. External links are
|
already absolute. The same base URL drives the primary agent-name
|
||||||
already absolute. The same base URL drives the primary agent-name
|
link + favicon fetch, so the whole row routes through the gateway
|
||||||
link + favicon fetch, so the whole row routes through the gateway
|
as a unit.
|
||||||
as a unit.
|
|
||||||
**When the container is stopped** (`ContainerView.running = false`),
|
|
||||||
the async `dashboard-state` fetch is skipped entirely (the agent
|
|
||||||
web server is down), so the badge chain is replaced by a single
|
|
||||||
badge, the nav strip is empty, and status text / rate-limited / ctx
|
|
||||||
badges are suppressed. The agent icon goes straight to the dimmed
|
|
||||||
`/favicon.svg` fallback instead of attempting a doomed load from the
|
|
||||||
container's URL. Static fields — `needs_update`, `deployed_sha`,
|
|
||||||
`pending_reminders`, `parent`, `config` link — remain visible
|
|
||||||
regardless of run state.
|
|
||||||
**Which single badge (hyperhive#3139):** `ContainerView.failed`
|
|
||||||
(systemd `ActiveState=failed` — the unit exhausted its bounded
|
|
||||||
restarts and gave up on its own) draws a red `✖ gave up` badge;
|
|
||||||
otherwise a plain muted `■ not running` — a container an operator
|
|
||||||
stopped deliberately. Both states read `running: false`; `failed` is
|
|
||||||
the orthogonal fact (a fifth one alongside `paused`/`needs_update`/
|
|
||||||
`needs_login`, same "independent flags, no state machine" shape —
|
|
||||||
see `ContainerView`'s own doc comment) that tells them apart. An
|
|
||||||
older backend without the field serves `failed: undefined`, which
|
|
||||||
reads falsy — degrades cleanly to the single `not running` badge.
|
|
||||||
When the container is running, status badges follow — `⊘ rate
|
|
||||||
limited` (red, while the harness is parked after a 429), `needs
|
|
||||||
login`, `needs update` — plus **one `◐ pending-state…` pill per
|
|
||||||
active transient** (replaces buttons during operator-initiated
|
|
||||||
start / stop / restart / rebuild / destroy). An agent can carry
|
|
||||||
**several transients at once** (mara: "show all running nodes that
|
|
||||||
name the agent") — e.g. a lease-exempt `prebuild` running alongside
|
|
||||||
a `stop_for_update` on the same agent — and each renders as its own
|
|
||||||
independent badge rather than being collapsed into one label,
|
|
||||||
matching the existing multi-badge convention this line already uses
|
|
||||||
for `paused`/`needs_update`/model/ctx.
|
|
||||||
Any pending badge means the row is actually **running** something
|
|
||||||
right now — there is no separate queued-but-not-started row state
|
|
||||||
to visually distinguish it from (see **Pending-badge derivation**
|
|
||||||
below), so every row carrying ≥1 badge keeps the amber row tint AND
|
|
||||||
draws a **rotating amber ring** around the agent icon.
|
|
||||||
|
|
||||||
**Pending-badge derivation:** transients only (`transientsState`,
|
**When the container is stopped** (`ContainerView.running = false`),
|
||||||
keyed `agent -> Map<kind, since_unix>`) — a transient is **derived
|
the async `dashboard-state` fetch is skipped entirely (the agent
|
||||||
from a job-queue node currently `Running`** against that agent, not
|
web server is down), so the badge chain is replaced by a single
|
||||||
declared per request, so its label follows the operation as it
|
badge, the nav strip is empty, and status text / rate-limited / ctx
|
||||||
progresses (a rebuild reads `stop_for_update`, then `swap`, then
|
badges are suppressed. The agent icon goes straight to the dimmed
|
||||||
`reconcile` rather than one constant `rebuilding` for its whole
|
`/favicon.svg` fallback instead of attempting a doomed load from the
|
||||||
life). Two consequences for anything rendering it:
|
container's URL. Static fields — `needs_update`, `deployed_sha`,
|
||||||
|
`pending_reminders`, `parent`, `config` link — remain visible
|
||||||
|
regardless of run state.
|
||||||
|
|
||||||
- The label vocabulary is **open** — it is the node's own wire tag
|
**Line 2** — status badges only (no per-card action buttons — actions
|
||||||
(`NodeKind::as_str`, the same strings the graph wire's node
|
moved to the **selection bar** or the **per-agent `⋮` menu**, see
|
||||||
labels carry),
|
below).
|
||||||
not a fixed set. Treat it as an opaque display string; do not
|
|
||||||
switch on specific values. `restarting` in particular no longer
|
|
||||||
exists, because no node kind is unique to a restart.
|
|
||||||
- It is **not** exclusively operator-initiated, and **not** limited
|
|
||||||
to rebuild-shaped work — `running_transients()` on the backend is
|
|
||||||
a status-only test (any `Running` node whose payload names a
|
|
||||||
non-empty agent lights a pill), so work the operator never
|
|
||||||
clicked (a meta-update cascade, a crash-recover rebuild, a
|
|
||||||
lease-exempt `prebuild`) lights the same mechanism.
|
|
||||||
|
|
||||||
Ops with no queue node behind them (destroy, migration) supply
|
### Status badges
|
||||||
their own label directly via `TransientSet`/`TransientCleared`
|
|
||||||
events carrying no backing node at all.
|
|
||||||
|
|
||||||
**Queued (not-yet-started) work shows nothing on the card.** An
|
**Which single badge (hyperhive#3139):** `ContainerView.failed`
|
||||||
earlier version of this page had a job-queue-backed fallback badge
|
(systemd `ActiveState=failed` — the unit exhausted its bounded
|
||||||
for the `Pending` case (`queuedOpsByAgent()`, reading a `GET
|
restarts and gave up on its own) draws a red `✖ gave up` badge;
|
||||||
/api/jobq/graph` fetch); removed per mara, on review of
|
otherwise a plain muted `■ not running` — a container an operator
|
||||||
hyperhive#3028's PR: *"swarm.js should not need to pull in the jobq
|
stopped deliberately. Both states read `running: false`; `failed` is
|
||||||
to do its job,"* followed by *"remove the per agent pending stuff -
|
the orthogonal fact (a fifth one alongside `paused`/`needs_update`/
|
||||||
only show what is running."* Per-agent badges never came back — only
|
`needs_login`, same "independent flags, no state machine" shape —
|
||||||
the queue-summary banner below did, once a narrow enough endpoint
|
see `ContainerView`'s own doc comment) that tells them apart. An
|
||||||
existed for it to read instead of the full graph.
|
older backend without the field serves `failed: undefined`, which
|
||||||
An **active model badge** (`model · <name>`, blue) appears when the
|
reads falsy — degrades cleanly to the single `not running` badge.
|
||||||
container is running and the harness has persisted a model name
|
|
||||||
(`harness/hyperhive-model`). Read by hive-c0re's `ContainerView`
|
When the container is running, status badges follow — `⊘ rate
|
||||||
(`read_active_model`); absent until the agent has completed at least
|
limited` (red, while the harness is parked after a 429), `needs
|
||||||
one turn and stale values are suppressed for stopped containers.
|
login`, `needs update` — plus **one `◐ pending-state…` pill per
|
||||||
A `ctx · Nk` chip showing the agent's last-turn context size,
|
active transient** (replaces buttons during operator-initiated
|
||||||
populated from `DashboardState.ctx_tokens` (absent until the
|
start / stop / restart / rebuild / destroy). An agent can carry
|
||||||
agent has completed at least one turn). The chip colour (green /
|
**several transients at once** — e.g. a lease-exempt `prebuild`
|
||||||
yellow / red) is keyed off `DashboardState.context_window_tokens`
|
running alongside a `stop_for_update` on the same agent — and each
|
||||||
(the real context window for the model the agent last ran on,
|
renders as its own independent badge rather than being collapsed
|
||||||
authoritative from the agent side); the badge goes yellow ≥ 50%
|
into one label, matching the existing multi-badge convention this
|
||||||
and red ≥ 75% of that window, matching the harness compaction
|
line already uses for `paused`/`needs_update`/model/ctx.
|
||||||
watermarks. When the window value is absent the badge falls back
|
|
||||||
to fixed 100k / 150k thresholds.
|
Any pending badge means the row is actually **running** something
|
||||||
- Line 2: status badges only (no per-card action buttons — actions
|
right now — there is no separate queued-but-not-started row state
|
||||||
moved to the **selection bar** or the **per-agent `⋮` menu**, see
|
to visually distinguish it from (see **Pending-badge derivation**
|
||||||
below).
|
below), so every row carrying ≥1 badge keeps the amber row tint AND
|
||||||
|
draws a **rotating amber ring** around the agent icon.
|
||||||
|
|
||||||
|
**Pending-badge derivation:** transients only (`transientsState`,
|
||||||
|
keyed `agent -> Map<kind, since_unix>`) — a transient is **derived
|
||||||
|
from a job-queue node currently `Running`** against that agent, not
|
||||||
|
declared per request, so its label follows the operation as it
|
||||||
|
progresses (a rebuild reads `stop_for_update`, then `swap`, then
|
||||||
|
`reconcile` rather than one constant `rebuilding` for its whole
|
||||||
|
life). Two consequences for anything rendering it:
|
||||||
|
|
||||||
|
- The label vocabulary is **open** — it is the node's own wire tag
|
||||||
|
(`NodeKind::as_str`, the same strings the graph wire's node
|
||||||
|
labels carry), not a fixed set. Treat it as an opaque display
|
||||||
|
string; do not switch on specific values. `restarting` in
|
||||||
|
particular no longer exists, because no node kind is unique to a
|
||||||
|
restart.
|
||||||
|
- It is **not** exclusively operator-initiated, and **not** limited
|
||||||
|
to rebuild-shaped work — `running_transients()` on the backend is
|
||||||
|
a status-only test (any `Running` node whose payload names a
|
||||||
|
non-empty agent lights a pill), so work the operator never
|
||||||
|
clicked (a meta-update cascade, a crash-recover rebuild, a
|
||||||
|
lease-exempt `prebuild`) lights the same mechanism.
|
||||||
|
|
||||||
|
Ops with no queue node behind them (destroy, migration) supply
|
||||||
|
their own label directly via `TransientSet`/`TransientCleared`
|
||||||
|
events carrying no backing node at all.
|
||||||
|
|
||||||
|
**Queued (not-yet-started) work shows nothing on the card.** Only
|
||||||
|
running work gets a per-agent pending badge — by design, there is no
|
||||||
|
fallback badge for work that's merely `Pending` in the queue, since
|
||||||
|
the swarm view stays independent of job-queue internals. The queue-
|
||||||
|
summary banner below is the only queued-work indicator on this tab,
|
||||||
|
and it reads the narrow `/api/jobq/rollup` endpoint rather than the
|
||||||
|
full graph.
|
||||||
|
|
||||||
|
**Active model badge** (`model · <name>`, blue) appears when the
|
||||||
|
container is running and the harness has persisted a model name
|
||||||
|
(`harness/hyperhive-model`). Read by hive-c0re's `ContainerView`
|
||||||
|
(`read_active_model`); absent until the agent has completed at least
|
||||||
|
one turn and stale values are suppressed for stopped containers.
|
||||||
|
|
||||||
|
**`ctx · Nk` chip** shows the agent's last-turn context size,
|
||||||
|
populated from `DashboardState.ctx_tokens` (absent until the
|
||||||
|
agent has completed at least one turn). The chip colour (green /
|
||||||
|
yellow / red) is keyed off `DashboardState.context_window_tokens`
|
||||||
|
(the real context window for the model the agent last ran on,
|
||||||
|
authoritative from the agent side); the badge goes yellow ≥ 50%
|
||||||
|
and red ≥ 75% of that window, matching the harness compaction
|
||||||
|
watermarks. When the window value is absent the badge falls back
|
||||||
|
to fixed 100k / 150k thresholds.
|
||||||
|
|
||||||
**Per-agent `⋮` overflow menu** — a `⋮` button appears on the right
|
**Per-agent `⋮` overflow menu** — a `⋮` button appears on the right
|
||||||
edge of each container row. Clicking it opens a small dropdown with
|
edge of each container row. Clicking it opens a small dropdown with
|
||||||
|
|
@ -1011,19 +1010,11 @@ fixed order, zero counts included — rather than the full
|
||||||
`/api/jobq/graph` tree: `running` sums the `Running` and `Finishing`
|
`/api/jobq/graph` tree: `running` sums the `Running` and `Finishing`
|
||||||
entries' `roots` (`Finishing` = own work done, subtree still going,
|
entries' `roots` (`Finishing` = own work done, subtree still going,
|
||||||
still in flight), `queued` reads the `Pending` entry's `roots`.
|
still in flight), `queued` reads the `Pending` entry's `roots`.
|
||||||
`roots` specifically, not `nodes` — the banner has always meant *N
|
`roots` specifically, not `nodes` — the banner means *N whole
|
||||||
whole operations*, not raw steps (one rebuild is ~7 nodes but 1
|
operations*, not raw steps (one rebuild is ~7 nodes but 1 root);
|
||||||
root); `nodes` exists on the same endpoint for a consumer that wants
|
`nodes` exists on the same endpoint for a consumer that wants
|
||||||
step-level counts instead, unused here.
|
step-level counts instead, unused here.
|
||||||
|
|
||||||
This banner went through two prior shapes before landing here, both
|
|
||||||
per mara review comments on hyperhive#3028's PR: a client-side
|
|
||||||
derivation over the full graph (*"swarm.js should not need to pull in
|
|
||||||
the jobq to do its job"*), then removed entirely rather than keep
|
|
||||||
that interim fetch (*"dont replace one legacy thing with another"*).
|
|
||||||
Restored once the dedicated rollup endpoint (hyperhive#3033) existed
|
|
||||||
for it to read directly instead.
|
|
||||||
|
|
||||||
### Themed dialogs
|
### Themed dialogs
|
||||||
|
|
||||||
All confirmations, prompts, and transient error notices use an
|
All confirmations, prompts, and transient error notices use an
|
||||||
|
|
@ -1065,67 +1056,35 @@ the dashboard and CLI paths behave identically.)
|
||||||
|
|
||||||
### Topology tree
|
### Topology tree
|
||||||
|
|
||||||
Container rows render as a forest, not a flat list — each agent
|
See **SW4RM tab** above for the parent/child derivation, sibling
|
||||||
sits indented under its declared parent. `swarm.js::buildAgentTree`
|
sort order, and cycle-safety rules (`swarm.js::buildAgentTree` walks
|
||||||
walks `ContainerView.parent` for every container in the snapshot
|
`ContainerView.parent`) — this section covers only how the tree is
|
||||||
and produces a render order with per-row depth + sibling-position
|
*drawn*.
|
||||||
info:
|
|
||||||
|
|
||||||
- Top-level rows are agents with `parent = null` OR a parent that
|
|
||||||
doesn't appear in the container map (orphans get hoisted to root
|
|
||||||
so they're still visible).
|
|
||||||
- Within each level children sort alphabetically by name; roots
|
|
||||||
likewise.
|
|
||||||
- Cycle safety: any container not reached during the root-walk is
|
|
||||||
appended at the end as a root, so no agent ever silently
|
|
||||||
disappears from the list when the topology JSON is malformed.
|
|
||||||
- The pre-topology rendering shape (every container at depth 0,
|
|
||||||
flat list) collapses to the same visual today when no parent
|
|
||||||
field is set — bit-identical fallback path.
|
|
||||||
|
|
||||||
The per-row prefix column (`.tree-prefix`) is **DOM-painted, not
|
The per-row prefix column (`.tree-prefix`) is **DOM-painted, not
|
||||||
text-glyph-painted**. Each indent lane is its own positioned
|
text-glyph-painted**: each indent lane is its own positioned `<span>`
|
||||||
`<span>` so CSS can draw full-height vertical bars that bridge the
|
so CSS can draw full-height vertical bars that bridge the gap between
|
||||||
gap between sibling rows; using text box-drawing characters
|
sibling rows. Plain text box-drawing characters (`├─`, `└─`, `│ `)
|
||||||
(`├─`, `└─`, `│ `) only paints one text-line tall and leaves
|
would only paint one text-line tall and leave visible breaks between
|
||||||
visible breaks between the taller-than-one-line container cards.
|
the taller-than-one-line container cards, so the bars are drawn as
|
||||||
The bars come in two flavours: continuation (the ancestor's
|
CSS borders instead: a continuation bar runs the full height of an
|
||||||
subtree extends below this row → vertical line top→bottom) or
|
ancestor's still-open subtree, and the joint at a row's own depth is
|
||||||
blank (ancestor was the last sibling at its level → no line
|
`├` (more siblings below) or `└` (last sibling — the line stops at
|
||||||
needed). The joint at the row's own depth column is `├` (more
|
the row's icon midline). Exact lane widths and positioning live in
|
||||||
siblings below) or `└` (last sibling at this depth — vertical
|
`swarm.js`'s tree-prefix rendering and its paired CSS rules — not
|
||||||
stops at the row's icon midline).
|
reproduced here since they're tuned in pixel units and will drift.
|
||||||
|
When every container is at depth 0 (no `parent` set) these rules are
|
||||||
**Indent + lane geometry.** Each depth level shifts the row right
|
all no-ops and the layout reads like a plain flat list.
|
||||||
by `1.8em` (the lane width). The per-depth ladders are hardcoded
|
|
||||||
for six levels — enough for any plausible hive topology, and the
|
|
||||||
typed `attr()` function from CSS Values 5 that would collapse
|
|
||||||
this to one rule is still partial-support (Chromium-only as of
|
|
||||||
2026). The `.tree-prefix` span sits absolutely positioned with
|
|
||||||
`left: -<depth>*1.8em` so its right edge meets the row content
|
|
||||||
(the icon) and its leftmost lane lines up with top-level rows'
|
|
||||||
icons at `x = 0`. Each `.tree-lane` is `flex: 0 0 1.8em` so all
|
|
||||||
lanes have equal width. Continuation bars are drawn at lane
|
|
||||||
center (`left: 0.6em`, `border-left: 1px solid currentColor`,
|
|
||||||
`top: 0; bottom: 0`) and extend through `.containers { gap: 0.4em }`
|
|
||||||
into the next sibling's prefix (`bottom: -0.4em` on the prefix
|
|
||||||
span itself) so adjacent ancestor lines visually merge into one
|
|
||||||
unbroken vertical line. The horizontal stub at a row's own joint
|
|
||||||
lands at the icon midline so the L/T meets the icon edge cleanly.
|
|
||||||
When every container has `parent = null` (pre-topology state) the
|
|
||||||
`[data-depth]` attribute is absent on every row and these rules
|
|
||||||
are no-ops — the layout reads exactly like the legacy flat list.
|
|
||||||
|
|
||||||
## Selection bar
|
## Selection bar
|
||||||
|
|
||||||
Per-card action buttons (`R3ST4RT` / `ST0P` / `ST4RT` / `R3BU1LD` /
|
Bulk actions (`R3ST4RT` / `ST0P` / `ST4RT` / `R3BU1LD` / `DESTR0Y` /
|
||||||
`DESTR0Y` / `PURG3`) used to live on each container row; the
|
`PURG3`) live here rather than as per-card buttons — see **Container
|
||||||
operator picked the bulk-bar model instead. Clicking an agent's
|
row** above. Clicking an agent's icon toggles its selection (an
|
||||||
icon toggles its selection (an in-memory `Set<name>`); `Esc` or
|
in-memory `Set<name>`); `Esc` or the bar's `✕ clear` button drops
|
||||||
the bar's `✕ clear` button drops everything. The selection
|
everything. The selection persists across tab switches in-memory —
|
||||||
persists across tab switches in-memory — the bar just hides on
|
the bar just hides on non-SW4RM tabs since other tabs don't show the
|
||||||
non-SW4RM tabs since other tabs don't show the agent cards needed
|
agent cards needed to cross-reference.
|
||||||
to cross-reference.
|
|
||||||
|
|
||||||
When one or more agents are selected (via icon click), a sticky
|
When one or more agents are selected (via icon click), a sticky
|
||||||
frosted-mauve bar slides up from the bottom of the viewport
|
frosted-mauve bar slides up from the bottom of the viewport
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue