Commit graph hyperhive/hive-c0re/src/dashboard.rs
Author SHA1 Message Date
damocles
7ec0a36d7a fix(#1218): bulk topology move uses one git commit via new set-parent-bulk endpoint 2026-06-03 23:24:55 +02:00
damocles
fcd170e8b8 fix: rename hive-knowledge → knowledge in dashboard.rs doc comment 2026-06-03 20:56:17 +02:00
damocles
41befe3839 feat(#1167): hive-wide knowledge repo — forge, local clone, bind-mount, webhook 2026-06-03 20:56:17 +02:00
damocles
79265e04f8 cleanup(#1014): remove manager pinning from frontend — no special treatment for ruth 2026-06-03 16:44:29 +02:00
damocles
6feab54882 cleanup(#1014): remove is_manager from ContainerView, add manager_name to StateSnapshot 2026-06-03 16:44:29 +02:00
atlas
68e30b857c feat(#1137): rich unread summary in loose ends and wake signal
- hive-sh4re: UnreadMatrix gains summary: String field (per-room breakdown)
- hive-matrix-mcp/protocol: add RoomUnread struct + UnreadSummary request
- hive-matrix-mcp/handlers: collect_unread() fetches per-room data;
  single-unread rooms include truncated last-message body + sender;
  multi-unread rooms carry count only
- hive-matrix-mcp/wake: format_unread_summary() builds wake body from
  RoomUnread slice; terse one-liner for single-room/single-message,
  bulleted list for multi-room; always appends read-hint
- hive-matrix-mcp/timeline: wake body now covers all rooms with unread
  at fire time, not just the triggering event; falls back to per-event
  teaser if notification counts haven't updated yet
- hive-ag3nt/mcp: matrix_unread_summary() replaces matrix_unread_rooms();
  UnreadMatrix loose end carries per-room summary lines; render shows
  room breakdown with sender: body for single-unread rooms
2026-06-03 13:56:00 +02:00
iris
cd3ba24c3d fix(#1112): build agent nav-links from disk; drop broken TCP proxy
get_agent_links was proxying to http://127.0.0.1:{port}/api/state.
Since all agents now bind exclusively to a unix socket (HIVE_WEB_SOCKET
set unconditionally in harness-base.nix), the TCP fetch always fails
silently, returning [] — so the nav-strip icons on every card disappear.

Replace with container_view::build_nav_links(), which reconstructs the
same link list from disk:
  - stats.html always (container kind)
  - /{name} and /agent-configs/{name} when forge-token is present (forge kind)
  - extras from hyperhive-dashboard-links.json (external kind)

The GUI screen link is intentionally omitted — /etc/hyperhive/gui.json
lives inside the agent container and is not host-visible. GUI agents
are rare; the omission is acceptable until a host-visible marker lands.

No new dependencies. reqwest is no longer used in dashboard.rs for
this handler (still used by forge.rs and hivectl.rs).
2026-06-03 12:32:09 +02:00
damocles
a1c6736ba5 feat(#1106): transient wake for bash tasks — bypass broker sqlite 2026-06-03 12:30:30 +02:00
müde
9e12012a95 fix(#702): route container journal reads through hive-priv
The privsep drop to the hive-core user left four journalctl -M <container>
call sites shelling out directly. -M enters the container namespace via the
machine bus, which needs root, so all container-journal reads failed with
Permission denied. Add a ReadContainerJournal verb to hive-priv and route
dashboard get_journal, manager get_logs, the rebuild-failure journal tail,
and the agent host-journal -M path through it. Host-journal reads (no -M)
stay direct via systemd-journal group membership.
2026-06-02 23:43:02 +02:00
damocles
89665b94de feat(#1014): rename manager agent root→ruth across all crates + frontend 2026-06-02 18:18:06 +02:00
damocles
eae0e875cf feat(#1086): serialize perm changes through rebuild queue
add QueueKind::PermChange — dashboard tool-group and capability
handlers no longer write the shared JSON files inline. instead they
enqueue a PermChange entry; the FIFO worker applies the file write
then calls rebuild_agent so the updated env var takes effect.

concurrent batch-apply actions for different agents previously raced
on tool-groups.json / capabilities.json (last write wins, earlier
change silently dropped). serialising through the queue prevents this.

dedup check extended with perm-type discriminant so tool-groups and
capabilities changes for the same agent are kept as distinct entries
and never collapse into one slot.
2026-06-02 16:42:22 +02:00
damocles
dce2bd0686 feat(#343): route container restart through rebuild queue 2026-06-02 13:34:24 +02:00
iris
2368bec634 feat(#1082): add description() to ToolGroup + Capability; expose in API + UI tooltips
- hive-sh4re: ToolGroup::description() and Capability::description() return
  short human-readable strings for each variant
- hive-c0re: ToolGroupsSnapshot and CapabilitiesSnapshot now include a
  `descriptions` map (name → description); get_capabilities now iterates
  Capability::ALL instead of hardcoding the list
- tabs.js: renderToolGroups + renderCapabilities use descriptions[name] as
  the column header title attribute (native browser tooltip on hover)
2026-06-02 12:53:50 +02:00
iris
50f14f28ff fix(dashboard): have get_capabilities iterate Capability::ALL
The hardcoded vec was a maintenance hazard — any new capability added
to Capability::ALL would silently be omitted from the permissions UI
column list until get_capabilities was manually updated.

Now both the GET and POST handlers derive their known-capability lists
from the same Capability::ALL source of truth.
2026-06-02 12:46:12 +02:00
iris
c7f02993d0 chore(#1055): address argus review nits
- rename cap-cap-col → cap-col; add CSS rules for .cap-col and .cap-save-col
- drop zero-width-space replace in capability header cells (nowrap makes it a no-op)
- add Capability::ALL to hive-sh4re; validate incoming cap strings in post_capabilities
2026-06-02 11:15:33 +02:00
iris
013e8740bd feat(#1053): permissions tab — capabilities UI + move tool-groups
Add a new P3RM1SS10NS tab to the dashboard that consolidates all
per-agent permission configuration:

Backend:
- GET /api/capabilities returns { caps: [...], assignments: {...} }
  driven by Capability::ALL variants (manage_root_agent,
  read_host_journal, query_agent_state)
- POST /api/capabilities/{agent} writes capabilities.json and queues
  a rebuild so HIVE_CAPABILITIES takes effect

Frontend:
- New 'permissions' entry in TABS, placed after 'system'
- P3RM1SS10NS tab pane with two sections:
  C4P4B1L1T13S — agents × capabilities checkbox matrix (.cap-*)
  T00L GR0UPS — agents × tool-groups checkbox matrix (.tg-*) moved
    from SYST3M tab
- activateTab('permissions') fetches both tables; neither has an SSE
  channel so they re-fetch on each activation to stay fresh
- CSS for .cap-* mirrors the .tg-* layout (scrollable, Catppuccin)
2026-06-02 01:11:07 +02:00
atlas
4bff450343 feat(gateway): hivectl gateway user management + fix htpasswdFile assertion
Add `hivectl gateway {create-user,delete-user,list-users}` subcommands for
managing htpasswd files used by gateway Basic auth. Pure Rust bcrypt
(cost 12, $2y$ prefix nginx accepts). No external htpasswd binary required.

Also fix the NixOS module assertion: `cfg.auth ? htpasswdFile` is always
true in the module system (declared options always exist as keys); switch
to `nullOr path; default = null` + `!= null` check so the assertion
actually fires with a useful error when enable=true but no file is set.
Guard bind-mount and nginx config against null to prevent eval errors.

Update docs/gateway.md to show hivectl commands instead of raw htpasswd.
2026-06-01 23:25:28 +02:00
atlas
5c5ca38fe8 fix(#999): resolve all clippy warnings across the workspace
All crates now pass `cargo clippy --workspace -- -D warnings` cleanly.

Fixes span six crates (hive-sh4re, hive-ag3nt, hive-c0re, hive-forge,
hive-priv, hive-matrix-mcp was already clean):

- doc_markdown: wrap snake_case, type names, constants in backticks
- collapsible_if / collapsible_match: fold nested ifs into let-chains
- duration_suboptimal_units: Duration::from_secs(N) → from_mins/from_hours
- implicit_hasher: allow on HashMap-param fns where generalization is risky
- items_after_statements: hoist use to function tops
- map(f).unwrap_or(x) → map_or(x, f); map(f).unwrap_or_else(g) → map_or_else
- is_ok_and / is_none_or in place of map().unwrap_or(bool)
- needless_continue: {} instead of continue in loop match arms
- match_same_arms: Ok(None) | Err(_) merged
- format_push_str: write!() instead of push_str(&format!())
- while let replaces loop { let Some(..) = x else { break } }
- struct_excessive_bools / dead_code: allow on purpose-built structs
- too_many_lines / too_many_arguments: allow where refactor not worth it
- unused_async: remove async from poll_once in bash_runner
- needless_borrow: fix &repo deref in hive-forge comments verb
- cast_possible_truncation: allow u64→usize in fetch_tail

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 22:31:06 +02:00
damocles
e3f1544f5b fix: rename Raw::_cert_fingerprint back after rebase on #1025 2026-06-01 22:30:35 +02:00
damocles
9e2d6aa343 feat(#1026): validate and forward cert_fingerprint in parse_peer_hives 2026-06-01 22:30:35 +02:00
damocles
8dc89f53d0 fix(#999): remove lint warnings (unused mut, unread field) 2026-06-01 21:45:23 +02:00
iris
86a1591cfc feat(#1005): capabilities UI — per-agent tool-group table in SYST3M tab
Backend (hive-c0re/src/dashboard.rs):
  GET /api/tool-groups  — returns { groups: [...], assignments: {...} };
    groups list comes from ToolGroup::ALL so the UI needs no change when
    a new group is added (satisfies the 'no extend ui' requirement)
  POST /api/tool-groups/{agent} — accepts { groups: [...] }, calls
    set_groups() then enqueues a rebuild so the new HIVE_TOOL_GROUPS
    env var takes effect immediately

hive-sh4re/src/lib.rs:
  Added ToolGroup::ALL const (ordered slice of every group)
  Added ToolGroup::as_str() — snake_case wire name, matches serde

Frontend:
  SYST3M tab: new C4P4B1L1T13S section above K3PT ST4T3 with
    #capabilities-section placeholder
  tabs.js: fetchAndRenderCapabilities() + renderCapabilities() —
    columns are built from the groups array returned by the API;
    each row has one checkbox per group and a save button that POSTs
    and re-fetches after 800ms; agents without explicit assignments
    show a (default) label; triggered on each SYST3M tab activation
  dashboard.css: .cap-table-wrap/.cap-table/.cap-row/.cap-agent-*
    styles for the scrollable matrix table
2026-06-01 20:19:11 +02:00
iris
0b15cad93f feat(#986): dedicated logs page with build/agent/system sub-tabs
Add /logs.html as a standalone page (same back-link pattern as flow.html):
- BUILD tab: all-agents build log history via new GET /api/build-logs endpoint
- AGENT tab: per-container journald viewer with agent selector + unit filter
- SYSTEM tab: host-side hive-c0re.service logs via new GET /api/journal-host endpoint

Remove inline log drill-ins from SW4RM container rows (buildJournalTrigger
and buildBuildLogsTrigger) — log viewing now lives on the dedicated page.

flow.html: strip the full dashboard tabbar, replace with a simple back link
matching the new logs page chrome.

index.html: add L0GS tab link to /logs.html in the tab strip.

Backend additions:
- build_logs::list_recent_all — cross-agent query (newest first, cap 100)
- GET /api/build-logs — all-agents variant backed by list_recent_all
- GET /api/journal-host — host journald (no -M container flag), restricted
  to allow-listed units (hive-c0re.service)
2026-06-01 19:20:54 +02:00
iris
ab278affc7 rename(#162): scrub remaining hm1nd references from comments and MCP instructions
All functional renames (MANAGER_NAME, MANAGER_AGENT → "root") were done in
earlier commits. This cleans up the stale `hm1nd` strings that remained in
doc comments, test fixture labels, and the manager MCP server instructions
(which told the manager its config lived at /agents/hm1nd/config/agent.nix).
2026-06-01 19:18:02 +02:00
damocles
e7e0675d22 rename: role badge stays 'manager'; unify harness unit name to hive-ag3nt 2026-06-01 17:33:09 +02:00
damocles
42fe3965de docs: move dashboard.rs security + bind rationale to docs (#715) 2026-06-01 11:38:42 +02:00
damocles
52cfc3ea1c reshape swarm peers: domain-as-key, certFingerprint field 2026-05-31 23:55:34 +02:00
damocles
4093f4fdb4 fixup: remove issue tags from code, use plain prose 2026-05-31 23:06:38 +02:00
damocles
348fb3792a feat(#589): swarm peers option + HYPERHIVE_PEERS env wire v0
nix: services.hyperhive.peers attrset-of-submodules option; serialises
to HYPERHIVE_PEERS JSON ([{label,domain}]); forwarded to containers via
FORWARDED_VARS. dashboard.rs: peer_hives: Vec<PeerHiveView> in
StateSnapshot, derived as {name:label, url:"http://domain/"}.
identity.rs: PeerHive struct + peers() accessor for agent-side use.
2026-05-31 23:06:38 +02:00
iris
30328a5184 fix(#888): http→https in forge_public_url doc comment example 2026-05-31 22:08:59 +02:00
iris
d3ca857659 fix(#888): use gateway forge URL in dashboard links
Dashboard links to the forge were hardcoded as http://<hostname>:3000,
which breaks when the operator accesses the dashboard through
hive-gateway (forge is served at forge.<domain> with no port).

- nix/modules/hive-c0re.nix: inject HIVE_FORGE_PUBLIC_URL when
  forge.behindGateway = true (e.g. http://forge.pr1ma.darkest.space)
- hive-c0re/src/dashboard.rs: expose forge_url: Option<String> in
  StateSnapshot, reading from HIVE_FORGE_PUBLIC_URL
- frontend/packages/dashboard/src/tabs.js: use state.forge_url when
  present; fall back to http://<hostname>:3000 for gateway-off /
  local-dev deploys
2026-05-31 22:04:52 +02:00
iris
12985ade6d fix(#726): handle broadcast Lagged + clear on SSE reconnect
Distinguish RecvError::Lagged from Closed in the build-log stream
loop: Lagged continues (next recv delivers the full accumulated delta
via saved cursors), Closed returns (shutdown path).

Clear pre.textContent and reset cursor lengths in es.onerror when
readyState is CONNECTING so auto-reconnect doesn't double-append the
replay from cursor=0.
2026-05-31 21:48:31 +02:00
iris
050e130eba build-logs: SSE live streaming + raw download (#726 phase 4)
Backend (hive-c0re):
- build_logs.rs: add tokio::sync::broadcast::Sender<i64> to BuildLogs;
  append() and finish() notify subscribers after each sqlite write.
  Add BuildLogProgress struct and get_progress(id, stdout_cursor,
  stderr_cursor) for incremental delta reads.
- dashboard.rs: two new endpoints —
    GET /api/build-logs/id/{id}/stream  SSE; streams BuildLogFrame
      {stdout_append, stderr_append, status?, done} deltas until the
      build finishes or the browser disconnects. Backed by an mpsc
      channel task that watches the per-build broadcast notifications.
    GET /api/build-logs/id/{id}/raw    text/plain download with
      Content-Disposition: attachment; filename build-log-{agent}-{id}.txt

Frontend (dashboard):
- tabs.js: running builds (status === null) connect an EventSource to
  /stream and append lines live; "live" badge pulses amber while active,
  flips to ok/fail on done. Finished builds still use the JSON fetch path.
  Collapsing a running panel closes the EventSource; re-expanding
  reconnects. Adds a "⬇ raw" download link to every expanded row.
- dashboard.css: .build-logs-dl inline download link; .build-logs-live
  live pulse @keyframes animation.

Docs: web-ui.md updated for all three new endpoints + behaviour.
2026-05-31 21:48:31 +02:00
iris
e1e5195081 dashboard + agent UI: surface hive_name + swarm_name in chrome (#701)
Damocles's backend (c41bf1b) landed HYPERHIVE_HIVE_NAME / _SWARM_NAME
env vars and identity.rs accessors. This commit wires them into the two
web surfaces:

hive-c0re/dashboard.rs:
  StateSnapshot gains `hive_name` + `swarm_name` (Option<String>),
  populated from the env vars the c0re NixOS module injects.

hive-ag3nt/web_ui.rs:
  Per-agent StateSnapshot gains the same two fields, populated from
  crate::identity::hive_name() / swarm_name().

Dashboard frontend (index.html + tabs.js):
  A `<p class="banner-thin" id="hive-identity">` sits above the tab
  strip in the chrome. refreshState() populates it with "swarm / hive"
  (or just "hive") when the fields are non-null, and updates
  document.title to "<swarm>/<hive> // h1ve-c0re". No change to
  chrome when both fields are null (backward compat).

Per-agent frontend (index.html + app.js + agent.css):
  A hidden `.agent-hive-label` span under the title row shows the
  swarm/hive label once setHeader() receives non-null names.
  document.title is updated to "<label> // <hive_name>" when hive_name
  is set, enabling browser-tab disambiguation when multiple hives are
  open in parallel. Styled as a small uppercase purple-dim sub-label.
2026-05-31 21:09:08 +02:00
iris
f6b3145349 dashboard: add GET /api/build-logs/{agent} + /id/{id} endpoints (#726 phase 2)
Wires the Phase 1 sqlite store into the dashboard HTTP layer so the
frontend can surface full build logs without hitting journald.

Two new read endpoints:
- GET /api/build-logs/{agent}?limit=N  — Vec<BuildLogHeader> JSON,
  newest first, default limit 10, server-side cap at 50.
- GET /api/build-logs/id/{id}          — BuildLogFull JSON (header +
  stdout + stderr), HTTP 404 on vacuum-reaped / unknown ids.

Agent-name validated ([a-z0-9_-], 1-63 chars) before the sqlite call.
Both handlers reach coord.build_logs (Arc<BuildLogs>) introduced in
the Phase 1 commit. Docs updated in docs/web-ui.md.
2026-05-31 20:31:07 +02:00
atlas
cbe8d25e25 dashboard.rs: update gateway routing comment to reflect agents.conf (#872) 2026-05-31 20:29:56 +02:00
damocles
61aed469c9 fix post_set_parent doc: manager is reparentable 2026-05-31 20:05:01 +02:00
damocles
3fcacfbe6f docs(715): scrub 30 issue cookies from dashboard.rs 2026-05-31 20:04:35 +02:00
iris
fbc41d42a6 dashboard: build same-origin /agent/<name>/ links when gateway is up (closes #842)
When `services.hyperhive.gateway.enable` is on (default), the c0re
NixOS module now sets `HIVE_GATEWAY_ENABLED=1` on the service env.
`/api/state` exposes the flag as `gateway_enabled`; the SW4RM tab's
container-row renderer flips three link sites (primary agent-name
link, favicon fetch, `container`-kind nav-strip links) from the
legacy `http://<host>:<port>/` direct TCP shape to same-origin
`/agent/<name>/` URLs — the gateway proxies them to the per-agent
harness via `agent-ports.json` or `agent-sockets.json` (#784 / #815).
Gateway-off deploys keep the direct TCP fallback so local-dev /
operator opt-out keeps working.

`forge`-kind nav-strip links still resolve against `:3000` (separate
sub-domain transition, tracked by `forge.behindGateway`);
`external`-kind links are already absolute.

Mirrors the `HIVE_MATRIX_GUI_ENABLED` env→snapshot-flag pattern.
Docs updated: `docs/web-ui.md::Container row` + new
`docs/gateway.md::Dashboard link shape` section.
2026-05-31 17:16:53 +02:00
damocles
2c3b62be55 topology: drop manager-root special case + notify three agents on reparent (#743) 2026-05-31 13:27:30 +02:00
damocles
4526e40a49 lifecycle: drop manager port special case (#753) — manager hashes into 8100..8999 like every other agent 2026-05-31 13:25:13 +02:00
damocles
53447842bc hivectl: add operator-facing host CLI with forge + matrix create-user verbs (#655) 2026-05-30 20:34:59 +02:00
damocles
c5d466c5c5 c0re: bind dashboard to 127.0.0.1 only (#652) 2026-05-30 19:37:16 +02:00
atlas
e0070417fb nix/dashboard: walk hyperhive subtree before agents in meta inputs panel (#638)
mara on #638: in the dashboard's inputs section, `nixpkgs` appeared
under an `agent-*` path instead of `hyperhive/nixpkgs` where the
operator expects it.

Root cause (post-#632 follows refactor):
- meta's top-level `nixpkgs.follows = "hyperhive/nixpkgs"` is a
  `follows` chain, rendered in `flake.lock` as an array — the
  `String` extractor in `walk_meta_inputs` correctly skips it (can't
  `nix flake update` a follows alias).
- That left the root-level recursion to find `nixpkgs` only through
  some other input's subtree.
- Recursion order was the BTreeMap's alphabetical key order, so
  `agent-z` (or any agent starting with a letter before `h`) got
  walked first and claimed `nixpkgs` at `agent-z/nixpkgs`. Hyperhive's
  subsequent walk skipped `nixpkgs` (already visited).

Fix: sort `to_recurse` so hyperhive's subtree is descended first,
matching the same "hyperhive first, then alpha" priority
`read_meta_inputs` already uses for the final output ordering. Now
`nixpkgs` is claimed under `hyperhive/nixpkgs` regardless of which
agents the operator has spawned.

Added regression test covering the exact post-#632 lock shape
(`["hyperhive", "nixpkgs"]` follows array at root, agent-z
alphabetically before hyperhive). Asserts the emitted path is
`hyperhive/nixpkgs` and that `agent-z/nixpkgs` is NOT emitted (the
spanning-tree visited set guarantees one claim per node).

Closes #638.
2026-05-30 18:01:01 +02:00
damocles
effe00889f matrix: drop c0re /matrix mount, use targetFlags --base-href, surface availability via env (mara on #634) 2026-05-30 14:56:52 +02:00
damocles
360f2af15f dashboard: optional matrix GUI static mount at /matrix (#607 v0) 2026-05-29 21:40:05 +02:00
damocles
977bb16678 dashboard: format guard on post_purge_tombstone (path traversal hole — argus 🔴 on #593) 2026-05-29 18:54:22 +02:00
damocles
0006c0635e dashboard: validate agent-name on every write route (closes #572) 2026-05-29 18:54:22 +02:00
damocles
bf735357b2 dashboard: redo validate_agent_name for mark-all-read (orphaned at #566 merge, mara nag) 2026-05-29 16:48:37 +02:00
damocles
666c32ae65 broker: add mark_all_read + POST /api/agent/{name}/mark-all-read (#559 backend half) 2026-05-29 13:14:31 +02:00