hyperhive/frontend
Repository files (latest commit first)
Filename Latest commit message Latest commit date
iris d1f82e725e frontend: swarm.js off rebuild-queue-derived in-flight status onto transients
Fixes #2822.

`swarm.js` had two independent per-agent "is this in flight" sources:
`transientsState` (operator/worker-initiated ops the backend chose to
flag) and `inFlightOpsByAgent()`, a separate derivation straight from
`rebuildQueueState` covering everything else. Since #3010/#3016,
`running_transients()` is a status-only test — any `Running` job-queue
node naming a non-empty agent lights a transient pill, not just a
curated subset — so the second source's Running-state handling is now
provably redundant: a Running node with an agent always already has a
transient by the time `queuedOpsByAgent()` (renamed from
`inFlightOpsByAgent`) would be consulted.

## What changed

- `transientsState`: `Map<name, {kind, since_unix}>` (one pill per
  agent) -> `Map<name, Map<kind, since_unix>>` (several pills per
  agent). `applyTransientSet`/`applyTransientCleared` now add/remove
  by `(name, kind)` rather than overwrite/delete by name alone, using
  `TransientCleared`'s `transient_kind` field (landed in #3016) to
  know which pill cleared. `syncTransientsFromSnapshot` groups the
  now-flat `TransientView` list by name instead of assuming one row
  per agent.
- `inFlightOpsByAgent()` -> `queuedOpsByAgent()`: trimmed to the
  `Pending` (queued, not yet started) case only. The `Running` branch
  and its "running beats queued" priority logic are gone entirely —
  dead weight now that transients cover every running case
  unconditionally.
- Render loop: an agent's transients win outright whenever any exist
  (rendered as **one badge per pill**, not collapsed into one label —
  mara: "show all running nodes that name the agent"); the queued
  fallback only applies when a agent has zero transients. `opRunning`
  simplifies to "does this agent have at least one transient".
- `docs/web-ui/dashboard.md`'s Container-row section rewritten to
  match — it described a "transient, then in-flight-queue, in
  priority order" model that's no longer accurate now that the second
  source only ever fires for the one case the first can't represent.

## Verification

`npm run build` clean for both packages (dashboard + agent). Standalone
re-derivation of the transient-map + queued-fallback logic
(`/tmp/verify-swarm-transients.mjs`, not part of this diff) run against
constructed event sequences: single-pill lifecycle, two simultaneous
pills on one agent with independent clear-by-kind, clearing an unknown
kind is a safe no-op, a flat snapshot with duplicate agent names groups
correctly, the queued fallback only fires when no transient exists and
steps aside the instant one arrives, and a Running-state rebuild-queue
entry produces no queued badge (confirming the Pending-only trim is
correct, not just assumed). All 17 checks passed.

Verified directly against the merged backend rather than trusting
summaries: `job_queue/mod.rs::running_transients()` filters
`State::Running` only (not Pending — an earlier note of mine claiming
otherwise was imprecise paraphrasing), and `NodeView.agent` /
`running_transients()`'s agent both resolve through the same
`payload.agent()`, so a Running node's presence in `rebuild_queue`
and its presence as a transient are guaranteed consistent, not just
usually so.

#2985 (DagView/NodeView deletion) unblocks once this merges — atlas is
waiting on a ping.
2026-08-03 18:47:51 +02:00
..
packages frontend: swarm.js off rebuild-queue-derived in-flight status onto transients 2026-08-03 18:47:51 +02:00
.gitignore frontend: add npm workspace scaffold under frontend/ 2026-05-23 14:51:01 +02:00
package-lock.json chore(frontend): update npm dependencies 2026-07-15 23:30:25 +02:00
package.json chore(frontend): update npm dependencies 2026-07-15 23:30:25 +02:00
README.md frontend: add npm workspace scaffold under frontend/ 2026-05-23 14:51:01 +02:00

hyperhive frontend

npm workspaces project for the hyperhive browser-facing assets:

  • packages/shared/ — shared modules used by both surfaces (terminal pane, Catppuccin palette + body typography).
  • packages/dashboard/ — the hive-c0re dashboard SPA.
  • packages/agent/ — the per-container web UI (default agent page, stats, screen).

Build

npm install            # one-off; uses the checked-in package-lock.json
npm run build          # builds every workspace into packages/*/dist/

The Rust binaries serve packages/dashboard/dist/ and packages/agent/dist/ via tower_http::ServeDir at runtime; the build derivation is wired up in nix/modules/frontend.nix. Per-agent additions are layered on top of the default agent dist via the hyperhive.frontend.extraFiles option in agent.nix.

Why npm + esbuild

  • Hermetic: dependencies vendored via the checked-in lockfile; buildNpmPackage in nix uses it as the source-of-truth so the output is reproducible without network access at build time.
  • esbuild: vanilla-JS bundler, no framework runtime overhead. Each workspace's build.mjs is ~30 lines.
  • Single-PR migration: see issue #273 for the design proposal and the four-commit shape (npm scaffold → nix derivations → container plumbing → Rust cutover).