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
|
||||
`rebuild_queue_changed`, `meta_inputs_changed`, `meta_update_running`.
|
||||
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
|
||||
to do its job." Its per-agent pending badges are transient-only, and
|
||||
all, by design — the swarm view stays independent of job-queue
|
||||
internals. Its per-agent pending badges are transient-only, and
|
||||
its queue-summary banner reads the much narrower `GET /api/jobq/rollup`
|
||||
instead (see Container row, below) — a handful of pre-tallied counts,
|
||||
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
|
||||
still running / `✔` done / `✖` failed / `⊘` cancelled / `·` skipped)
|
||||
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
|
||||
gutter-rail version was reverted (it broke visually whenever a nested
|
||||
subtree sat between the two related rows; text has no such gap).
|
||||
as a plain "waits on: `<label>`" text line under the row rather than a
|
||||
gutter rail — a rail breaks visually whenever a nested subtree sits
|
||||
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
|
||||
a per-node cancel button (`✕`) on any non-terminal row — the button
|
||||
dispatches `hive-jobq-graph-cancel`, and the page does the actual
|
||||
`POST /api/rebuild-queue/{id}/cancel`, matching the wire event as its
|
||||
own domain concept (the component knows nothing about that endpoint).
|
||||
**Still no source chip, kind label, timing, or build-log deep-link on
|
||||
rows** — no equivalent of the old `DagView`'s `source`/`reason`/
|
||||
`created_at`, which were `NodeKind::Dag`-specific fields the generic
|
||||
wire doesn't carry; per mara's original steer ("dont feel constrained
|
||||
by what the ui does currently"), rows present what the endpoint
|
||||
actually gives rather than reconstructing the old per-row chrome.
|
||||
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.
|
||||
**Rows carry no source chip, kind label, timing, or build-log
|
||||
deep-link** — the generic graph wire doesn't carry those fields, and
|
||||
rows are meant to present exactly what the endpoint provides rather
|
||||
than reconstruct chrome the backend no longer sends. Settled entries
|
||||
render their **full step tree**, not just a bare summary — the wire
|
||||
does not filter `Done` nodes out.
|
||||
|
||||
**State filter (hyperhive#2606).** A row of per-state checkboxes above
|
||||
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.
|
||||
- **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 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
|
||||
|
|
@ -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
|
||||
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
|
||||
|
||||
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
|
||||
`GET /api/capabilities` as `caps: Vec<String>`. Checking or unchecking
|
||||
boxes only stages the change in-browser; nothing is written until the
|
||||
page-level **save all** button (described below) is clicked. The
|
||||
checkboxes reflect the *effective* set (explicit grant or role default),
|
||||
so a default-perms agent shows its real grants rather than blank; absent
|
||||
agents in the assignment map have no extra capabilities.
|
||||
page-level **save all** button (described below) is clicked. Row
|
||||
values follow the `effective`/`assignments` rule described above.
|
||||
|
||||
**T00L GR0UPS** — per-agent tool-group permissions. Tool groups are
|
||||
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
|
||||
/ 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
|
||||
the content edge — long timestamps + agent names used to push the body ~30ch
|
||||
in and force awkward narrow-column wraps. `min-width: 0` keeps
|
||||
chips (`flex: 1 1 100%`) so long timestamps and agent names never push the
|
||||
body into a narrow trailing column. `min-width: 0` keeps
|
||||
`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
|
||||
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
|
||||
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
|
||||
line at the top. Dashboard is now served at `/dashboard.html` (route swap
|
||||
completed in #1464 step 2); the home page at `/` replaces the old dashboard
|
||||
root. All dashboard sub-pages include a `← Home` back-link for navigation.
|
||||
line at the top. All dashboard sub-pages include a `← Home` back-link for
|
||||
navigation.
|
||||
|
||||
## 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`
|
||||
fetch entirely.
|
||||
|
||||
- Line 1: agent name (link → new tab), m1nd/ag3nt chip, an
|
||||
**icon-only nav strip** plus live agent-owned state, all populated
|
||||
async from a single `GET /api/dashboard-state` call to the
|
||||
agent's own backend. The response (`DashboardState`) carries:
|
||||
`links` (nav strip entries — `📊 stats`, `🖥 screen` when GUI is
|
||||
enabled, `⬡ forge profile`, `↳ agent-configs mirror`, plus any
|
||||
agent-declared `dashboardLinks` extras), `status_text` /
|
||||
`status_set_at` (agent self-reported status — the `(set N ago)`
|
||||
chip is stamped `data-set-at` and ticks every 30s to stay fresh
|
||||
across the long-lived keyed row cache), `rate_limited`,
|
||||
`ctx_tokens` / `context_window_tokens` (context-window badge
|
||||
data). The agent backend is the single source of truth for all
|
||||
of these. The dashboard resolves each `AgentLink.kind` against a
|
||||
per-agent base URL depending on whether hive-gateway is in front
|
||||
(`StateSnapshot.gateway_enabled`, sourced from the
|
||||
`HIVE_GATEWAY_ENABLED` env the c0re NixOS module sets when
|
||||
`services.hyperhive.gateway.enable = true`). Gateway-on (default):
|
||||
base URL is `/agent/<name>` (same origin, gateway proxies to the
|
||||
per-agent harness — TCP or unix-domain depending on the agent's
|
||||
`HIVE_WEB_SOCKET` opt-in, see
|
||||
`docs/gateway.md::Per-agent unix-socket upstream`).
|
||||
Gateway-off (legacy / local dev): base URL is
|
||||
`http://<host>:<container.port>` (direct TCP fallback). Forge
|
||||
links resolve against `state.forge_public_url` (sourced from
|
||||
`services.hyperhive.forge.publicUrl`) and are omitted entirely when
|
||||
that's unset — never guessed from `<host>:3000`. External links are
|
||||
already absolute. The same base URL drives the primary agent-name
|
||||
link + favicon fetch, so the whole row routes through the gateway
|
||||
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.
|
||||
**Line 1** — agent name (link → new tab), m1nd/ag3nt chip, an
|
||||
**icon-only nav strip** plus live agent-owned state, all populated
|
||||
async from a single `GET /api/dashboard-state` call to the agent's
|
||||
own backend. The response (`DashboardState`) carries: `links` (nav
|
||||
strip entries — `📊 stats`, `🖥 screen` when GUI is enabled, `⬡ forge
|
||||
profile`, `↳ agent-configs mirror`, plus any agent-declared
|
||||
`dashboardLinks` extras), `status_text` / `status_set_at` (agent
|
||||
self-reported status — the `(set N ago)` chip is stamped `data-set-at`
|
||||
and ticks every 30s to stay fresh across the long-lived keyed row
|
||||
cache), `rate_limited`, `ctx_tokens` / `context_window_tokens`
|
||||
(context-window badge data). The agent backend is the single source
|
||||
of truth for all of these. The dashboard resolves each `AgentLink.kind`
|
||||
against a per-agent base URL depending on whether hive-gateway is in
|
||||
front (`StateSnapshot.gateway_enabled`, sourced from the
|
||||
`HIVE_GATEWAY_ENABLED` env the c0re NixOS module sets when
|
||||
`services.hyperhive.gateway.enable = true`). Gateway-on (default):
|
||||
base URL is `/agent/<name>` (same origin, gateway proxies to the
|
||||
per-agent harness — TCP or unix-domain depending on the agent's
|
||||
`HIVE_WEB_SOCKET` opt-in, see
|
||||
`docs/gateway.md::Per-agent unix-socket upstream`).
|
||||
Gateway-off (legacy / local dev): base URL is
|
||||
`http://<host>:<container.port>` (direct TCP fallback). Forge
|
||||
links resolve against `state.forge_public_url` (sourced from
|
||||
`services.hyperhive.forge.publicUrl`) and are omitted entirely when
|
||||
that's unset — never guessed from `<host>:3000`. External links are
|
||||
already absolute. The same base URL drives the primary agent-name
|
||||
link + favicon fetch, so the whole row routes through the gateway
|
||||
as a unit.
|
||||
|
||||
**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:
|
||||
**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.
|
||||
|
||||
- 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.
|
||||
**Line 2** — status badges only (no per-card action buttons — actions
|
||||
moved to the **selection bar** or the **per-agent `⋮` menu**, see
|
||||
below).
|
||||
|
||||
Ops with no queue node behind them (destroy, migration) supply
|
||||
their own label directly via `TransientSet`/`TransientCleared`
|
||||
events carrying no backing node at all.
|
||||
### Status badges
|
||||
|
||||
**Queued (not-yet-started) work shows nothing on the card.** An
|
||||
earlier version of this page had a job-queue-backed fallback badge
|
||||
for the `Pending` case (`queuedOpsByAgent()`, reading a `GET
|
||||
/api/jobq/graph` fetch); removed per mara, on review of
|
||||
hyperhive#3028's PR: *"swarm.js should not need to pull in the jobq
|
||||
to do its job,"* followed by *"remove the per agent pending stuff -
|
||||
only show what is running."* Per-agent badges never came back — only
|
||||
the queue-summary banner below did, once a narrow enough endpoint
|
||||
existed for it to read instead of the full graph.
|
||||
An **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.
|
||||
A `ctx · Nk` chip showing 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.
|
||||
- Line 2: status badges only (no per-card action buttons — actions
|
||||
moved to the **selection bar** or the **per-agent `⋮` menu**, see
|
||||
below).
|
||||
**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** — 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`,
|
||||
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
|
||||
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`
|
||||
entries' `roots` (`Finishing` = own work done, subtree still going,
|
||||
still in flight), `queued` reads the `Pending` entry's `roots`.
|
||||
`roots` specifically, not `nodes` — the banner has always meant *N
|
||||
whole operations*, not raw steps (one rebuild is ~7 nodes but 1
|
||||
root); `nodes` exists on the same endpoint for a consumer that wants
|
||||
`roots` specifically, not `nodes` — the banner means *N whole
|
||||
operations*, not raw steps (one rebuild is ~7 nodes but 1 root);
|
||||
`nodes` exists on the same endpoint for a consumer that wants
|
||||
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
|
||||
|
||||
All confirmations, prompts, and transient error notices use an
|
||||
|
|
@ -1065,67 +1056,35 @@ the dashboard and CLI paths behave identically.)
|
|||
|
||||
### Topology tree
|
||||
|
||||
Container rows render as a forest, not a flat list — each agent
|
||||
sits indented under its declared parent. `swarm.js::buildAgentTree`
|
||||
walks `ContainerView.parent` for every container in the snapshot
|
||||
and produces a render order with per-row depth + sibling-position
|
||||
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.
|
||||
See **SW4RM tab** above for the parent/child derivation, sibling
|
||||
sort order, and cycle-safety rules (`swarm.js::buildAgentTree` walks
|
||||
`ContainerView.parent`) — this section covers only how the tree is
|
||||
*drawn*.
|
||||
|
||||
The per-row prefix column (`.tree-prefix`) is **DOM-painted, not
|
||||
text-glyph-painted**. Each indent lane is its own positioned
|
||||
`<span>` so CSS can draw full-height vertical bars that bridge the
|
||||
gap between sibling rows; using text box-drawing characters
|
||||
(`├─`, `└─`, `│ `) only paints one text-line tall and leaves
|
||||
visible breaks between the taller-than-one-line container cards.
|
||||
The bars come in two flavours: continuation (the ancestor's
|
||||
subtree extends below this row → vertical line top→bottom) or
|
||||
blank (ancestor was the last sibling at its level → no line
|
||||
needed). The joint at the row's own depth column is `├` (more
|
||||
siblings below) or `└` (last sibling at this depth — vertical
|
||||
stops at the row's icon midline).
|
||||
|
||||
**Indent + lane geometry.** Each depth level shifts the row right
|
||||
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.
|
||||
text-glyph-painted**: each indent lane is its own positioned `<span>`
|
||||
so CSS can draw full-height vertical bars that bridge the gap between
|
||||
sibling rows. Plain text box-drawing characters (`├─`, `└─`, `│ `)
|
||||
would only paint one text-line tall and leave visible breaks between
|
||||
the taller-than-one-line container cards, so the bars are drawn as
|
||||
CSS borders instead: a continuation bar runs the full height of an
|
||||
ancestor's still-open subtree, and the joint at a row's own depth is
|
||||
`├` (more siblings below) or `└` (last sibling — the line stops at
|
||||
the row's icon midline). Exact lane widths and positioning live in
|
||||
`swarm.js`'s tree-prefix rendering and its paired CSS rules — not
|
||||
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
|
||||
all no-ops and the layout reads like a plain flat list.
|
||||
|
||||
## Selection bar
|
||||
|
||||
Per-card action buttons (`R3ST4RT` / `ST0P` / `ST4RT` / `R3BU1LD` /
|
||||
`DESTR0Y` / `PURG3`) used to live on each container row; the
|
||||
operator picked the bulk-bar model instead. Clicking an agent's
|
||||
icon toggles its selection (an in-memory `Set<name>`); `Esc` or
|
||||
the bar's `✕ clear` button drops everything. The selection
|
||||
persists across tab switches in-memory — the bar just hides on
|
||||
non-SW4RM tabs since other tabs don't show the agent cards needed
|
||||
to cross-reference.
|
||||
Bulk actions (`R3ST4RT` / `ST0P` / `ST4RT` / `R3BU1LD` / `DESTR0Y` /
|
||||
`PURG3`) live here rather than as per-card buttons — see **Container
|
||||
row** above. Clicking an agent's icon toggles its selection (an
|
||||
in-memory `Set<name>`); `Esc` or the bar's `✕ clear` button drops
|
||||
everything. The selection persists across tab switches in-memory —
|
||||
the bar just hides on non-SW4RM tabs since other tabs don't show the
|
||||
agent cards needed to cross-reference.
|
||||
|
||||
When one or more agents are selected (via icon click), a sticky
|
||||
frosted-mauve bar slides up from the bottom of the viewport
|
||||
|
|
|
|||
Loading…
Reference in a new issue