Commit graph

640 commits

Author SHA1 Message Date
iris
8bebd78895 frontend: add npm workspace scaffold under frontend/
Phase 1 of the backend/frontend code split (#273). Additive — no
existing code is touched; the legacy hive-c0re/assets, hive-ag3nt/
assets and hive-fr0nt/assets trees stay in place until the Rust
cutover later in this branch.

Layout:
  frontend/package.json                       npm workspaces root
  frontend/packages/shared/                   @hive/shared
    src/{base,terminal}.css + terminal.js     (ES module)
    src/index.js                              re-exports terminal.js
  frontend/packages/dashboard/                @hive/dashboard
    src/{index.html, app.js, dashboard.css}   ported from hive-c0re/assets
    build.mjs                                 esbuild config → dist/
  frontend/packages/agent/                    @hive/agent
    src/{index,stats,screen}.html + agent.css
        + {app,stats}.js                      ported from hive-ag3nt/assets
    build.mjs                                 esbuild config → dist/

Changes vs the existing assets:
- terminal.js is an ES module exporting { create, linkify } instead
  of assigning to window.HiveTerminal. The dashboard / agent app.js
  files re-expose them on window so the IIFE bodies keep working
  unchanged through Phase 1; the global aliases can be dropped in a
  follow-up once the IIFEs are unwrapped.
- marked is imported from the marked@4.3.0 npm package (replacing
  the vendored hive-fr0nt/assets/marked.umd.js bundle).
- chart.js is imported from chart.js@4.4.4 (replacing the jsDelivr
  CDN script tag on the per-agent stats page — page now works
  offline / on operator machines without internet egress).
- dashboard.css and agent.css both gain @import lines at the top
  that pull base.css + terminal.css from @hive/shared, replacing
  the runtime string concatenation in serve_css.
- index.html / stats.html collapse from three / two script tags to
  one type="module" tag pointing at the bundled output.

package-lock.json is intentionally omitted from this commit — npm
isn't available in the iris container yet (approval pending) and the
lockfile will land in the next commit on this branch once the
toolchain is in place. The PR will not be opened until it's there.

Phase 2 (nix derivations), Phase 3 (container plumbing + the
hyperhive.frontend.extraFiles option for per-agent layering), and
Phase 4 (Rust cutover to tower_http::ServeDir, delete hive-fr0nt
+ legacy assets dirs) land as follow-up commits on this same
branch.

Refs #273.
2026-05-23 14:51:01 +02:00
damocles
d81b430136 rebuild_queue: pre-enqueue meta-update cascade at submit time (closes #347) 2026-05-23 12:36:06 +02:00
lexis
4c425ede69 docs: document rebuild queue panel + module (follow-up to #340) 2026-05-23 12:27:03 +02:00
iris
a2ed35cd19 dashboard: pin agent icon at a fixed size
`.container-icon` had `align-self: stretch` + `aspect-ratio: 1`, so
the square's width tracked the body's height. As soon as state pills
(rate-limited / needs-login / needs-update / ctx) wrapped the head
row, the body grew taller and the icon grew with it — two cards
with different state ended up with visibly different-sized icons
(issue #344).

Pin the icon at 5em; height follows from aspect-ratio. Card-level
`align-items` drops to flex-start so a row taller than the icon
doesn't stretch the icon back out. The card body still flows
however many lines it needs.

Closes #344.
2026-05-23 12:12:49 +02:00
damocles
47d2f766c9 rebuild_queue: dashboard panel + snapshot field + SSE event wireup 2026-05-23 12:05:09 +02:00
damocles
11db5c2a8f rebuild_queue: switch dashboard / auto-update / manager call sites to enqueue 2026-05-23 12:05:09 +02:00
damocles
37f6bc4b6b rebuild_queue: wire worker into coordinator + dashboard event 2026-05-23 12:05:09 +02:00
damocles
5890e6796a rebuild_queue: add module with types + dedup + cancellation 2026-05-23 12:05:09 +02:00
damocles
73871f18c3 set_status: consolidate whoami into get_agent_meta with optional name 2026-05-23 11:32:33 +02:00
damocles
77fdaf0d1e set_status: add get_agent_meta tool for inter-agent status queries 2026-05-23 11:32:33 +02:00
damocles
8e8e8a771f set_status: add status_set_at timestamp (mtime of status file) 2026-05-23 11:32:33 +02:00
damocles
fe2933b213 feat: add set_status MCP tool and status field to whoami/dashboard (closes #325) 2026-05-23 11:32:33 +02:00
iris
6f3b56ad84 dashboard: tick question TTL chip every second
The ` MM:SS` chip on an asked-with-timeout question was rendered
once and then frozen — the operator saw stale info (e.g. 48s
sitting unchanged for the whole TTL window) (issue #335).

Stamp the deadline onto the chip as `data-deadline` and run a
single page-wide setInterval that refreshes every `.q-ttl[data-
deadline]`'s textContent each second. No re-render of the
questions section; no new state on the client. No-op when no
chips are on screen.

Also pulls the bucketed seconds-to-string logic into a
`formatTtl` helper so the renderer and the ticker share one
source of truth.

Closes #335.
2026-05-23 10:44:05 +02:00
iris
5887111327 dashboard: stop nav-link icons cramming against the head row's right edge
The per-container nav strip's <a> elements had class "meta nav-link".
`.container-row .head .meta { margin-left: auto }` then matched every
link, so as flex siblings the first one absorbed all the available
space and the rest packed against it on the right — the icons looked
like they overlapped (issue #333).

Drop `meta` from the link class. Add a `.nav-strip` rule that is
inline-flex with a 0.35em gap so the icons sit on a fixed cadence
regardless of how many backend-supplied links land. Give .nav-link a
real hit target (0.15em / 0.35em padding) + a subtle hover so the
icons read as interactive.
2026-05-23 02:43:12 +02:00
iris
2c087f53ed dashboard: same bind retry policy as the agent half
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.
2026-05-23 02:32:33 +02:00
iris
d73175a23e harness: keep retrying web-UI bind on AddrInUse
The retry was capped at 12 attempts (~20s of exponential backoff
capped at 2s). Two back-to-back nspawn restarts in #324 left the
previous socket holding the port longer than that budget; once the
cap fired, the web-UI task returned an error and silently died for
the rest of the process lifetime — the agent kept running fine
otherwise (MCP, turn loop), but the operator's dashboard click
hit nothing.

Genuine port collisions are preflighted host-side
(lifecycle::{spawn,rebuild}) and surfaced as a port-conflict banner,
so at this layer a persistent AddrInUse always reflects a
recoverable stale socket. Drop the cap, keep retrying forever with
the same 2s-capped backoff. WARN for the first dozen attempts so a
normal restart-race is visible; INFO after that to avoid spamming
the journal during a long stale-socket hold. Logs a one-line INFO
on success when we did have to retry, so post-mortems can find the
attempt count.

Closes #324.
2026-05-23 02:19:14 +02:00
iris
222a5b4dc6 dashboard+agent: agent backend owns its nav links; dashboard proxies
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.
2026-05-23 02:11:40 +02:00
damocles
e70ae7776c harness-base: add assertions for common agent config mistakes (closes #318) 2026-05-23 02:05:12 +02:00
iris
ce539559d5 forge: use base64 crate for avatar payload
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.
2026-05-23 01:15:16 +02:00
iris
dbb2ca4393 forge: upload hyperhive logo as the core user's avatar
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.
2026-05-23 01:05:58 +02:00
lexis
832c2f86c5 docs: clarify hyperthive.model priority in README
PR #321 changed the model priority to: HIVE_DEFAULT_MODEL (from nix config)
> persisted runtime choice > compiled-in DEFAULT_MODEL. The README now
clarifies that the nix config takes precedence and runtime overrides are
reset on rebuild.
2026-05-23 00:44:42 +02:00
damocles
77b249076f events: HIVE_DEFAULT_MODEL takes priority over persisted model (closes #319) 2026-05-23 00:38:17 +02:00
damocles
cd9831b39e forge-avatar-sync: fix data URI prefix and add jq to service path (closes #197) 2026-05-23 00:17:38 +02:00
damocles
edf7f1602d forge_notify: include reason field in all notification messages (closes #110) 2026-05-22 23:59:47 +02:00
iris
7f97acf19e dashboard: render META INPUTS as a full tree with bulk select
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.
2026-05-22 23:50:20 +02:00
damocles
dd3a820e57 hive-forge: reject empty/whitespace-only comment bodies (closes #297, closes #299) 2026-05-22 23:41:20 +02:00
lexis
631356f2f8 docs: update forge.rs entry for meta read access
added clarification that forge mirrors include meta read access for
agents as read-only collaborators on core/meta.
2026-05-22 23:05:09 +02:00
damocles
06cb87917d docs: add agent configuration section to README (supersedes #302) 2026-05-22 23:00:08 +02:00
damocles
2ac77a416b hive-forge pr-create: set allow_maintainer_edit=true by default (closes #308) 2026-05-22 22:52:36 +02:00
lexis
40589c8510 docs: update spawn flow docs for apply_commit handling first spawn (follow-up to 66f1568) 2026-05-22 22:34:42 +02:00
lexis
3abb00c327 docs: add request_update_meta_inputs to manager tools (follow-up to 3e098c5) 2026-05-22 22:34:42 +02:00
lexis
96f93f3b5e docs: add request_next_turn to turn-loop.md (follow-up to c99261b) 2026-05-22 22:34:42 +02:00
iris
4a27ef7304 dashboard: derive ctx badge thresholds from the model context window 2026-05-22 22:32:32 +02:00
damocles
cbd4b71322 fix #296: auto-generate GPG signing key for Forgejo on first boot 2026-05-22 22:29:57 +02:00
damocles
a94b504883 forge_notify: skip-reasons drop-list filter, configurable via agent.nix 2026-05-22 22:29:32 +02:00
damocles
b0f6bd8ece fix: self-calibrate context window from API result event
the stream-json result event carries modelUsage.<model>.contextWindow
which is the actual per-inference active window the model enforces.
for claude-sonnet-4-6 this is 200k even though the full prompt cache
can hold millions of tokens via accumulated cache reads.

with the nix-configured sonnet = 1000000 the proactive compact watermark
sat at 750k and was never reached. agents grew context until prompt_too_long
at ~170k — reactive compact, no checkpoint turn.

changes:
- bus gains api_context_window field seeded from modelUsage.*.contextWindow
  in each turn's result event. authoritative; falls back to env var, then 200k.
- new effective_context_window(bus) helper used by both watermark functions
- compact_watermark (75%) and auto_reset_watermark (50%) call effective_context_window
- context_tokens() docstring clarified: all three token fields (input +
  cache_read + cache_creation) count against the per-inference contextWindow
  limit. the large cache_read values seen in the result event are cumulative
  across all inferences in a turn, not per-inference.
- /api/state context_window_tokens now reflects the calibrated window

closes #129
2026-05-22 22:20:07 +02:00
damocles
3e94914569 fix #289: full forge sync on rebuild (extract sync_agent, use in rebuild_agent)
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.
2026-05-22 22:18:05 +02:00
damocles
7ad9809207 fix #289: re-seed forge token in rebuild_agent
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.
2026-05-22 22:18:05 +02:00
iris
2f1b846baf dashboard: show meta-update progress in the META INPUTS panel
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.
2026-05-22 21:54:28 +02:00
damocles
20d2b48fe5 hive-forge: fix comment --body flag swallowing, add comment-edit verb 2026-05-22 21:35:08 +02:00
damocles
3f08051bda lifecycle: seed applied repo at template commit, not main, for first-spawn diff 2026-05-22 21:29:52 +02:00
damocles
93bf91535f hive-forge: add --milestone to issue-edit 2026-05-22 20:31:13 +02:00
damocles
66ec8390e1 hive-forge: add comment-show <id> [--json] [repo] 2026-05-22 20:21:05 +02:00
iris
a9a10b631f dashboard: show when an approval was requested (closes #272) 2026-05-22 20:06:45 +02:00
damocles
908cadb151 docs: add missing #[must_use], # Errors, # Panics across public api 2026-05-22 19:41:27 +02:00
damocles
748536203b refactor: split long functions per review feedback; remove all #[allow] attributes 2026-05-22 19:24:44 +02:00
damocles
bbe2112dc9 fix: use try_from for i64/u64 casts; split format_notification into helpers 2026-05-22 19:14:22 +02:00
damocles
484cea62c7 fix #265: resolve all remaining clippy warnings (cast, too_many_lines, doc nits) 2026-05-22 19:11:40 +02:00
damocles
30d82148e0 clippy: apply auto-fixable warnings across workspace (closes #265 partial) 2026-05-22 18:55:57 +02:00
damocles
56d0b02c2f nix: drop unused weston-rdp.nix (closes #263) 2026-05-22 17:30:32 +02:00