Adds a real MCP-side path for the workaround #2639 documented: dial the
in-container HIVE_AGENT_SOCKET directly from cancel_loose_end (kind:"todo")
instead of shelling out via a tracked bash task (nc -U ...), which is what
was spawning a fresh completion todo on every clear and cascading forever.
hive-agent-mcp/src/mcp/render.rs: renamed local_todos's socket-dial guts
into a shared dial_agent_socket(req) helper, added mark_local_todo_done(id)
on top of it (MarkTodoDone request already existed server-side, unused
until now). mod.rs wires kind:"todo" into cancel_loose_end ahead of the
question/reminder/approval parse. args.rs + render.rs + docs/tools/bash.md
text updated to point at the new path instead of the old raw nc invocation.
Replace the in-tree scheduler with the domain-agnostic hive-jobq crate
(merged in #2615): parent-axis grouping + borrow/subtree-reservation
resource model + roll-up completion (State::Finishing).
Host adaptation:
- NodeSpec gains an explicit `parent` axis; templates declare grouping +
sibling ordering directly (deps order execution, parent groups a subtree
whose resource the descendants borrow).
- Rebuild is a nested two-root subtree: Prebuild (root, owns the build slot
for the whole subtree, lease-exempt) -> StopForUpdate (child, owns the
agent lease) -> Swap/PostSwap (children, borrow both); Reconcile is a
separate top-level root (AfterAny Prebuild) so it survives the cancel-
cascade of any failed step (recovery-start invariant) and converges to
the persisted `wanted` on a fresh lease. This is the multi-root
correction to the single-root-chain sketch: node0=root broke lease-
exemption (hoisting the lease onto Prebuild) and recovery-reconcile
(root failure cancels all children).
- Spawn / perm-change / power-ops (stop/start/restart) group-rooted the
same way; per-agent power-op subgraphs stay independent roots so a
multi-agent DAG runs them concurrently, each on its own lease.
- insert_group honours the explicit parent axis (no lease hoisting); the
DAG terminal node deps AfterAny on every group root and runs once the
whole op rolls up. Drop the old Graph::add_dep terminal wiring.
36/36 job_queue tests, full hive-c0re suite green, clippy --all-targets.
Both old endpoints removed. refreshLooseEnds() call sites cleaned up;
lastLooseEnds stays as empty [] for reconcileAskBinds (no-op now that
the loose-ends source is gone).
Gate the unread sweep on sender: skip rooms where the latest unread message
was sent by the agent itself. This prevents self-authored messages from
triggering an unread notification and causing a self-wake loop.
Fixes: #2629
- mouse_click: error on unrecognised button name instead of silently
treating it as left click; "left" now explicit in match arm
- rfb_handshake: cap ServerInit name-length at 256 bytes to prevent
a multi-GB allocation from an aberrant server response
The display size is not always 1280x720 — it changes when the operator
clicks 'match size' in the web UI. Replace the fixed mention with a
recommendation to use screenshot first to check the current resolution.
Implements mouse input by speaking the RFB protocol directly to Weston's
neatvnc server (localhost:HIVE_GUI_VNC_PORT, default 5900) — the VNC
backend's native remote-input path. No /dev/uinput, no kernel bypass;
the compositor mediates all input just as it does for the browser VNC viewer.
Changes:
- rfb_handshake(): RFB 3.8 handshake with security type None (auth-method=none
in weston.ini); shared-session ClientInit keeps the browser viewer connected
- rfb_pointer_event(): encodes a 6-byte RFB PointerEvent (type=5, button-mask,
x/y big-endian)
- rfb_send_pointer_events(): connects, handshakes, sends an event slice,
flushes — all in one TCP connection
- mouse_move(x, y): sends a single PointerEvent(mask=0, x, y)
- mouse_click(x, y, button): sends move → button-down → button-up sequence
(left/middle/right via RFB button-mask bits 0/1/2)
- vnc_port(): reads HIVE_GUI_VNC_PORT from env, falls back to 5900
No new packages or nix options — HIVE_GUI_VNC_PORT is already set by the
harness when gui.enable = true; grim/wtype are the only runtime deps.
Closes#2618.
- run_cmd now returns Result<String, String> — callers pattern-match
instead of comparing against an "ok" sentinel string
- Add cmd_result() helper to format run_cmd results as tool strings
- mouse_click: collapse nested if-let into let-chain (clippy collapsible_if)
- nix fmt: reformat screen.nix package list
New crate hive-screen-mcp: a stdio MCP bridge activated automatically
when an agent has hyperhive.gui.enable = true. Provides five tools:
- screenshot — grim → saves PNG, returns path for Read tool
- type_text — wtype → Unicode text input (no daemon)
- key_press — ydotool key → combos like ctrl+c, super+l
- mouse_move — ydotool mousemove --absolute
- mouse_click — ydotool click, optionally with prior move
New nix/agent-modules/screen.nix: wires the MCP bridge into
extraMcpServers.screen; adds grim + wtype to systemPackages. Adds
hyperhive.gui.screenInput option (default false) which enables the
ydotoold daemon + ydotool for mouse/keyboard injection via /dev/uinput.
screenshot and type_text work without screenInput. key_press,
mouse_move, and mouse_click return a ydotool error until ydotoold is
running and /dev/uinput is accessible in the container.