Commit graph

210 commits

Author SHA1 Message Date
iris
4539091f3c terminal: show recv wait/max params + bash [bg] flag
recv tool-use rows rendered as a bare recv() regardless of args,
hiding whether a turn is parked on a long-poll (wait_seconds) or
draining a burst (max). fmtToolUse now surfaces both. Bash rows
gain a [bg] flag when run_in_background is set.

closes #158
2026-05-21 17:57:24 +02:00
iris
62aa3bb3ec agent icon: render on dashboard + per-agent web UI
Consumes the GET /icon endpoint from #139:

- Dashboard: each container card shows the agent's icon next to its
  name (26px). Loaded from <agent-url>/icon; onerror hides it for a
  stopped container whose web server isn't answering.
- Per-agent web UI: the agent's icon next to the page title (40px),
  and /icon as the favicon on the index, stats, and screen pages.

/icon always returns an image (configured SVG or the default
hyperhive logo), so no presence check is needed.

Closes #140
2026-05-21 15:36:58 +02:00
iris
39bd46b244 agent icon: add hyperhive.icon option + GET /icon endpoint
Foundation for the per-agent icon feature (#137).

- harness-base.nix: new hyperhive.icon option (nullable path to an
  SVG). An agent commits an SVG into its config repo and references
  it as ./icon.svg; when set it lands at /etc/hyperhive/icon.svg.
- web_ui.rs: GET /icon serves the configured SVG, falling back to the
  bundled hyperhive logo when none is set — so it always returns an
  image and consumers can hit it unconditionally.

Closes #139
2026-05-21 01:06:34 +02:00
iris
305a32220b screen: add fit-to-window toggle
Adds a 'fit' toolbar toggle on the /screen VNC viewer. When on (the
default), the canvas is CSS-scaled down to fit the browser viewport
preserving aspect ratio — no more scrolling a desktop larger than the
window. When off, the canvas renders at native resolution with scroll.
The choice persists in localStorage.

The canvas's intrinsic resolution is never touched — only its display
size. sendPointer now rescales client coordinates by the canvas
display-vs-intrinsic ratio so clicks stay accurate in fit mode (this
also fixes a latent off-by-scale bug). Toolbar buttons share a .tbtn
class for consistent styling.

Issue #133 (fit toggle now; dynamic desktop resize tracked separately).
2026-05-20 22:56:19 +02:00
iris
1f52746bd9 manager: add optional agent param to reminder RPCs
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
2026-05-20 22:14:09 +02:00
iris
01cbd5e7cc manager prompt: update get_loose_ends docs for agent param
PR #119 changed get_loose_ends to default to the manager's own items
and accept an optional agent arg ("*" = hive-wide, "<name>" = one
agent), but the manager system prompt still described it as
"hive-wide ... no args". docs/turn-loop.md was already updated;
only manager.md was missed.
2026-05-20 22:13:25 +02:00
iris
a5ef10c10c screen: fix framebuffer height parse and stray byte consume
Two RFB protocol bugs in the /screen client:

1. ServerInit parsed framebuffer-height from byte offset 1 instead of
   2. RFB 3.8 ServerInit is width@0-1, height@2-3; u16be(b,1) mixes
   the low byte of width with the high byte of height. The wrong
   height went into the initial non-incremental FramebufferUpdate-
   Request; neatvnc feeds the client's width/height straight into
   pixman_region_union_rect un-clipped (src/server.c), so an
   out-of-range height corrupts the server damage region and pixman
   reports 'Invalid rectangle passed'.

2. FramebufferUpdate handler had a stray drainTo(1) after the 3-byte
   padding+nRects header, consuming the first byte of the first
   rectangle and desyncing every update.

Closes #128
2026-05-20 22:11:28 +02:00
iris
c10b4e26ef screen: fix MD5 rotation schedule and send root username
Two bugs found via the weston journal (issue #92):

1. MD5 rotation index used (j>>2 & 3) for the round number, which
   cycles every 4 steps instead of every 16. Verified against RFC 1321
   test vectors: md5("") was 7a1dce5b... instead of d41d8cd9... — the
   derived AES key was wrong, so the server decrypted the credentials
   to garbage. Fixed to j>>4.

2. weston's vnc_handle_auth calls getpwnam(username) and requires
   pw_uid == weston's own uid before PAM is consulted. We sent an empty
   username, which fails outright ("VNC: wrong user"). weston runs as
   root, so send username "root"; the empty password still passes via
   pam_permit.so on the weston-remote-access service.

Fixes #92
2026-05-20 21:47:27 +02:00
iris
d348ce885f manager: add optional agent param to GetLooseEnds
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).
2026-05-20 21:44:17 +02:00
damocles
a13f63f30c forge_notify: check mark-read HTTP status, warn on non-2xx 2026-05-20 21:22:53 +02:00
iris
e7d7aef1aa screen: fix Apple-DH response byte order
rfb_apple_dh_client_msg has encrypted_credentials at offset 0 and
public_key as a flexible array at offset 128. We were sending them
in the wrong order (pub_key first), so neatvnc decrypted the wrong
bytes as credentials and sent the wrong bytes as the DH public key,
causing a mismatched shared secret and SecurityResult=1.

Fixes #92
2026-05-20 20:53:30 +02:00
iris
f9d1e69a50 stats: add 1h, 4h, 3d time range windows
Adds Hour (5-min buckets), FourHour (15-min buckets), and ThreeDay
(hourly buckets) to the Window enum, plus the matching tab buttons
in stats.html. Simplifies web_ui.rs to use Window::span_secs()
instead of a duplicate match.

Closes #25
2026-05-20 20:23:09 +02:00
damocles
5951758b35 track compacted turns separately in stats 2026-05-20 19:59:59 +02:00
damocles
de2179540a fix: enrich forge notifications with subject body and comment content 2026-05-20 19:30:28 +02:00
iris
3224178d2d screen: implement Apple-DH (type 30) auth for neatvnc 0.9 compatibility 2026-05-20 19:12:40 +02:00
damocles
cddaacd12f feat: poll forge notifications in agent harness
Closes #27
2026-05-20 17:59:56 +02:00
iris
76061eb3ae screen: reject unsupported security types with clear error instead of mishandling 2026-05-20 17:49:26 +02:00
iris
86e4f41203 screen: add RFB debug log panel for handshake diagnosis 2026-05-20 17:13:35 +02:00
iris
bac7dd6cde docs: update prompts for two-step spawn + in_reply_to; trim CLAUDE.md to pointer index 2026-05-20 16:52:18 +02:00
damocles
5c27ab9d13 fix: scope rate-limit detection on stdout to JSON error events only
raw line.contains() on stdout false-positives when the agent's own
text mentions rate_limit_error or similar strings. stderr keeps the
raw match (it is always claude CLI output, not conversation content);
stdout now only fires on parsed {"type":"error"} events.

Closes #69
2026-05-20 16:22:57 +02:00
damocles
7e2f13cad8 model/context: defaults in nix module, no heuristic in rust 2026-05-20 15:49:03 +02:00
damocles
770cbaccf9 model/context: per-model ctx window overrides + expose window size in /api/state 2026-05-20 15:49:03 +02:00
damocles
9064cd3c57 model/context: configurable default model + model-derived context window 2026-05-20 15:49:03 +02:00
iris
b1f10b1d1b render message reply threads in dashboard and per-agent inbox
- 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
2026-05-20 15:29:47 +02:00
iris
804875d670 surface rate_limited status as red badge on per-agent page and dashboard
- 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
2026-05-20 15:16:00 +02:00
iris
de13e80082 screen: fix VeNCrypt security negotiation for weston VNC backend
weston's VNC backend (neatvnc) uses VeNCrypt (security type 19) as
the outer type even with --disable-transport-layer-security, offering
sub-type 1 (None, no TLS, no password) within it.

The old screen.html only handled type 1 (plain None) and type 2 (VNC
auth), causing 'auth failed' against weston.

Add VeNCrypt states to the RFB state machine:
- vencrypt-version: echo back server's major.minor
- vencrypt-subtypes: pick sub-type 1 (None) if available
- vencrypt-accept: check server's acceptance byte
Then falls through to the normal security-result / server-init path.
2026-05-20 15:01:35 +02:00
damocles
25659ee9f3 auto session-reset: drop checkpoint turn, reset cold without warming cache 2026-05-20 14:49:26 +02:00
damocles
fb951c1004 auto session-reset: fix default cache TTL to 1h, clarify state-preservation purpose 2026-05-20 14:49:26 +02:00
damocles
44c903f265 auto session-reset when context large and cache is cold 2026-05-20 14:49:26 +02:00
damocles
80dd5bb69e two-step agent spawn: request_init_config + request_spawn 2026-05-20 14:40:15 +02:00
iris
42437f9c6a agent UI: show 🖥 screen link when gui_enabled
index.html: add hidden #screen-link anchor (/screen, new tab).
app.js: reveal it in refreshState() when api/state returns gui_enabled=true.

gui_enabled is set by the harness when /etc/hyperhive/gui.json exists
(written by the weston VNC service from issue #50). The link opens the
RFB viewer from issue #51 in a new tab.

Closes #52
2026-05-20 14:39:11 +02:00
iris
2027e94432 harness: add /screen page and /screen/ws WebSocket VNC relay
Reads /etc/hyperhive/gui.json at startup to get the VNC port written
by the weston-vnc ExecStart script (issue #50). Adds:
- gui_vnc_port: Option<u16> on AppState
- gui_enabled: bool on StateSnapshot (for issue #52 screen link)
- GET /screen: serves a minimal RFB-over-WebSocket viewer (screen.html)
- GET /screen/ws: upgrades to WebSocket and byte-pumps to 127.0.0.1:<vnc_port>

The relay is a pure two-task byte pump (WS→TCP and TCP→WS), transparent
to any RFB variant including VeNCrypt. Returns 404 when gui is not
enabled.

screen.html is a self-contained RFB client: handshake, FramebufferUpdate
(Raw encoding), pointer and keyboard forwarding — enough to display the
desktop and interact with it. noVNC assets (issue #52) replace this.

Closes #51
2026-05-20 14:38:42 +02:00
iris
bded8d789f integrate reminder stats into stats page via socket RPC
Add fetch_reminder_stats() helper to query ReminderRollup from broker,
and update api_stats endpoint to include reminder stats in snapshot.
Reminder activity metrics (scheduled, delivered, pending) are now
available to the stats page UI for display.
2026-05-20 13:41:55 +02:00
damocles
3c672ed6b2 add allowedBashPatterns NixOS option for finer-grained Bash tool approval 2026-05-20 13:35:28 +02:00
damocles
67b47872e0 add optional in_reply_to field on send for conversation threading 2026-05-20 13:35:27 +02:00
damocles
03db764101 detect rate-limit errors; park serve loop instead of crashing 2026-05-20 13:35:27 +02:00
damocles
d0b65b1f47 fix: manager uses /agents/hm1nd/state, not /state, for HYPERHIVE_STATE_DIR 2026-05-20 13:35:12 +02:00
damocles
f21ae1ff98 inject HYPERHIVE_STATE_DIR into container env + extra MCP server envs 2026-05-20 13:35:12 +02:00
damocles
9cbb05bb86 add proactive context-size compaction with a notes-checkpoint turn 2026-05-20 13:27:57 +02:00
iris
f2015954d9 add reminder_stats field to stats Snapshot
Add Optional<ReminderStats> field to the per-agent stats page response,
placeholder for future ReminderRollup RPC integration to fetch reminder
activity metrics from the broker.
2026-05-20 13:24:17 +02:00
iris
8fe0725e1d fix: handle ReminderRollup in agent/manager response patterns
Add the ReminderRollup variant to exhaustive pattern matches
in both hive-ag3nt and hive-m1nd binaries.
2026-05-20 13:24:17 +02:00
iris
91bfa269fd add reminder rollup RPC and broker query
Surface reminder activity statistics (scheduled, delivered, pending counts)
for each agent over configurable time windows. Needed by the per-agent
stats page to display reminder metrics.

Adds:
- ReminderStats struct and ReminderRollup request/response variants
- Broker::reminder_rollup_for(agent, since_secs) method
- Agent and manager socket handlers for the new RPC
- SocketReply mapping for response conversion
2026-05-20 13:24:17 +02:00
damocles
4715e88fff docs: move backlog to forge issue tracker, extract boundary doc 2026-05-20 12:19:16 +02:00
müde
6ab3810e18 docs: refresh for the dashboard rework + recent harness commits
- web-ui.md: side panel, approval card + 3-way diff base, stats
  page, forge config links, removed agent.nix viewer, per-agent
  loose-ends inline answer.
- approvals.md: forge mirror section + diff base toggle.
- turn-loop.md: recv(max), get_logs, remind, loose-ends, whoami.
- agent.md / manager.md prompts: recv(max), remind, get_logs.
- CLAUDE.md: forge.rs / stats.rs / hive-forge.nix in the file
  map, scratchpad refresh.

also: forgejo migrations.ALLOW_LOCALNETWORKS = true so an in-hive
mirror of the hyperhive repo can import from a localhost source.
2026-05-20 11:34:43 +02:00
müde
f13c3dff8f stats: per-bucket turns-by-model chart
each turn_stats row already records the model; roll it up per bucket
so the /stats page can show which model ran when. model choice
greatly affects token cost, so the new stacked-bar chart sits right
under the cost chart for eyeball correlation across the window.

Snapshot gains a sorted `models` series list; each Bucket carries a
`model_counts` map.
2026-05-20 10:58:14 +02:00
damocles
0a79912b67 get_logs: resolve machine name via container_name like every other verb 2026-05-20 10:48:24 +02:00
damocles
1529c2d777 lifecycle: bind each sub-agent's config repo read-only at /agents/<name>/config 2026-05-20 10:05:02 +02:00
müde
56e7eb6e73 agent ui: answer questions inline from the per-agent page
loose-ends question rows get a textarea + send button; the operator
answers as operator by POSTing to the core dashboard's
/answer-question route, not the per-agent socket — keeps the
operator-authority path off the agent's own socket. cross-origin POST
needs a CORS shim on that route for now; drops out once the gateway
makes the page same-origin.

also splits deployment/ops/boundaries/gateway work into TODO-ops.md.
2026-05-20 10:01:12 +02:00
damocles
f8795dc029 fix: request_apply_commit resolves sha locally + rejects non-sha refs 2026-05-20 09:48:05 +02:00
damocles
5d27ae3048 recv: fold batch drain into recv(max) — one tool, uniform list response 2026-05-19 01:07:30 +02:00