dashboard.rs had the same 12-attempt cap shape as the per-agent
bind_with_retry. Apply the same fix — retry forever with the 2s-capped
backoff, WARN early then INFO once we're clearly stuck on a stale
socket, INFO on success when we did have to retry. Mirrors the
agent change in this PR.
The previous take put a shared NavLink wire type in hive-sh4re and
duplicated the link-building logic across crates. Per @mara on #326:
that doesn't fit the eventual frontend/backend split goal (#273).
The agent backend is the natural source of truth for what links its
own page exposes; hive-c0re just passes the list through to the
dashboard.
* hive-ag3nt/src/web_ui.rs: agent_links now also serves the
config-repo link + reads agent-declared dashboardLinks extras
from {state_dir}/hyperhive-dashboard-links.json. AgentLink gains a
kind enum (Container | Forge | External) so the frontend can build
the right href no matter which surface is rendering. The host
header is no longer used — URLs are paths for Container/Forge,
absolute for External.
* hive-c0re/src/dashboard.rs: new GET /api/agent/{name}/links route,
a same-origin proxy that fetches the agent's /api/state and
forwards just the links field. No shared wire type — hive-c0re
treats the payload as opaque JSON (serde_json::Value). All failure
modes degrade to an empty list so the dashboard still renders.
* hive-c0re/assets/app.js: container card head row gets an async-
populated icon-only nav strip from the proxy. The hardcoded stats
link, the standalone config-repo trigger, and the extras block are
gone. The deployed:<sha> chip stays — the agent harness can't know
its own deployed sha, so this chip is how the operator sees what's
live alongside the agent's (root-only) config link.
* hive-ag3nt/assets/app.js: agent page meta-links rendered via
el() / textContent (DOM build) so agent-declared icon / label / url
strings never reach innerHTML. kind-based href resolution mirrors
the dashboard side.
* docs/web-ui.md: dashboard + per-agent sections updated for the new
architecture.
Closes#262.
Per @mara on #328: the hand-rolled encoder was over-cautious. Swap
for base64 = 0.22 from crates.io — a standard, widely-trusted dep,
no maintenance surface to carry. Drops the 15-line encoder and its
two RFC 4648 unit tests.
The 'core' Forgejo user (hive-c0re's identity for commits in
core/meta + agent-configs/*) was showing the default hash identicon.
Adds a one-shot ensure_core_avatar in the ensure_all bootstrap that
POSTs the branding PNG to the admin avatar API and writes a marker
file (CORE_AVATAR_MARKER) so subsequent startups skip the call
(delete the marker to re-upload). Best-effort: a non-2xx is logged
and swallowed, doesn't gate startup.
PNG bytes baked in via include_bytes! from branding/hyperhive.png.
Base64 is hand-rolled (one small image in one cold path, not worth
a new workspace dep) with RFC 4648 §10 test vectors.
Closes#320.
Remove the depth-2 cap in walk_meta_inputs so every fetched input
at every depth is surfaced, not just two levels (issue #275). The
uncapped walk needs a guard: a visited-node set makes it a spanning
tree — each fetched node walked once, at its shallowest path — so
shared subtrees don't re-walk and a cycle can't recurse forever.
A two-pass walk (claim a node's direct inputs before descending)
keeps shallow inputs at a shallow path.
Frontend: renderMetaInputs indents each row by its slash-path depth
and shows the leaf segment (full path on hover), plus a select-all /
select-none control so a long input list isn't ticked box by box.
extract per-agent forge logic from ensure_all() into sync_agent()
so both the startup sweep and rebuild_agent call identical code.
rebuild now runs: ensure_user_for + ensure_config_repo + push_config
+ meta_read_access + ensure_meta_remote — same as the boot sweep.
missing tokens and drift in any forge state are fixed by rebuild,
not just hive reboot.
if forge_after_first_spawn fails transiently on first spawn the
token is missing. rebuild_agent now calls ensure_user_for so
a manual rebuild (or the startup auto-update scan) recovers
the missing token — no full hive reboot needed.
post_meta_update returns 200 immediately and runs the nix flake
update + agent-rebuild ripple in a background task, so the META
INPUTS panel looked idle for the whole multi-minute window (#259).
Track in-flight runs with a Coordinator atomic counter, exposed via
an RAII MetaUpdateGuard held across run_meta_update. Surface it as
the meta_update_running snapshot field plus a MetaUpdateRunning SSE
event (flipped only when the count crosses 0, so concurrent runs
flip the flag once). The panel shows a pulsing in-progress banner
and disables the update button while a run is active.
Follow-up to #188. Two additions to the side-panel file preview:
- Markdown files get a rendered/plain tabbed view (was: always
rendered, no way to see source) — same tab pattern as SVG.
- Raster images (png/jpg/gif/webp/bmp/ico/avif) render as an
<img>. /api/state-file previously from_utf8_lossy-stringified
every file and served text/plain, which corrupts binary; it
now serves image files as raw bytes with their real
content-type (over-cap images are rejected, not truncated —
a clipped binary is corrupt).
buildSvgPanel generalised to buildTabbedPreview, shared by SVG +
markdown. .svg-host/.svg-render renamed .preview-host/.img-preview
since they now back images + md too.
closes#192
The main dashboard had no favicon — PR #145 added them to the
per-agent pages but missed hive-c0re's index. Serve branding/
hyperhive.svg at /favicon.svg and declare it in the index head.
The dashboard represents the whole hive, so it uses the project
mark (per-agent pages keep their own configurable /icon).
closes#173
row_to_approval matched only apply_commit + spawn, so any approvals
row with kind=init_config (added by 80dd5bb's two-step spawn) failed
to deserialize. pending() / recent_resolved() collect all-or-nothing
via collect::<Result<Vec>>(), so one bad row errored the whole query;
api_state's log_default then swallowed the error and returned an empty
list — every pending approval vanished from the dashboard (issue #160).
- add the missing init_config arm to row_to_approval
- collect_lenient(): skip + log unparseable rows so a single bad row
can never blank the whole approvals list again
- dashboard: label init_config approvals 'init' (was mislabeled
'spawn' by the apply-vs-other fallthrough)
closes#160
CountPendingReminders and ReminderRollup were hardcoded to
MANAGER_AGENT. Both now take agent: Option<String> — None keeps the
current behavior (manager's own), Some(name) returns that agent's
reminder stats. The broker functions already take an agent name, so
this is a thin wire-protocol change. Callers (web UI stats page,
post-turn counts) pass None.
Closes#122
GetLooseEnds now takes agent: Option<String>:
- None = manager's own loose ends (default; the bug fix)
- Some("*") = hive-wide view (every approval/question/reminder)
- Some("name") = that agent's loose ends
The get_loose_ends MCP tool exposes this as an optional agent arg, so
the manager can still scan the whole swarm on demand. The web UI and
post-turn counts pass None (manager's own).
hive_wide returns ALL agents' reminders and questions, causing other
agents' reminders (e.g. triage) to appear on the manager's web page
and in the get_loose_ends MCP tool. The MCP tool spec says it shows
your own pending items — switch to for_agent(MANAGER_AGENT) which
includes all approvals (manager is sole submitter), questions where
the manager is asker/target, and only the manager's own reminders.
Fixes#118
agent users were created with {name}@hive.local but git commits use
{name}@hyperhive (set by meta::render_flake). forgejo matches by email,
so no profile link appeared on any commit.
- extract agent_email() helper returning {name}@hyperhive
- use it in ensure_user_exists (new users)
- add ensure_user_email() that runs gitea admin user edit to patch
existing users; called from ensure_all on every startup sweep
Closes#64
- MessageEvent and DashboardEvent Sent/Delivered now carry id and in_reply_to
- broker.send() includes last_insert_rowid in the emitted event
- recent_all() and recv_batch() include id and in_reply_to from the DB
- deliver_reminders_batch() tracks per-row rowids within the transaction
- dashboard message flow: reply rows are indented with a border-left and a
clickable '↳ reply' tag that scroll-jumps + briefly highlights the parent
- per-agent inbox: reply messages get a '↳ reply ·' prefix and indent
Closes#26
- add rate_limited: Arc<AtomicBool> to Bus; set/cleared by emit_status
- write/remove sentinel file hyperhive-rate-limited in state dir so host-side
dashboard can detect it without a live socket call
- api_state returns status=rate_limited when flag is set (cold-load accurate)
- ALIVE_LABELS gains rate_limited entry (⊘ red chip) on per-agent page
- ContainerView gains rate_limited: bool read from sentinel file
- dashboard container row shows ⊘ rate limited badge (red) ahead of needs_login
Closes#24
Reads the most recent turn's context-window token count directly from
each agent's hyperhive-turn-stats.sqlite (same path the host-side
stats_vacuum uses). Adds ctx_tokens: Option<u64> to ContainerView;
populated in build_all via a single best-effort SQL query.
Dashboard app.js renders a 'ctx·Nk' badge colour-coded by harness
watermarks: green <100k (safe), yellow 100-150k (near auto-reset),
red ≥150k (compact territory). Badge only shown when ctx_tokens
is present (agent has run at least one turn).
Closes#17