feat(#1014): rename manager agent root→ruth across all crates + frontend

This commit is contained in:
damocles 2026-06-02 17:02:01 +02:00 committed by mara
commit 89665b94de
19 changed files with 71 additions and 166 deletions

View file

@ -12,7 +12,7 @@ use rusqlite::Connection;
use serde::{Deserialize, Serialize};
use crate::coordinator::Coordinator;
use crate::lifecycle::{self, AGENT_PREFIX, MANAGER_CONTAINER, MANAGER_NAME};
use crate::lifecycle::{self, AGENT_PREFIX, MANAGER_NAME};
/// An agent-declared extra navigation link surfaced on the dashboard card.
/// Written by the `hive-dashboard-links` NixOS oneshot into
@ -30,8 +30,11 @@ pub struct DashboardLink {
pub struct ContainerView {
/// Logical agent name (no `h-` prefix). Used in action URLs.
pub name: String,
/// Container name as nixos-container sees it (`h-foo`, `root`).
/// Container name as nixos-container sees it (`h-foo`).
pub container: String,
/// True when this is the manager agent. Informational — not used
/// to gate any server-side actions. Computed from `name ==
/// MANAGER_NAME` so it doesn't add new state.
pub is_manager: bool,
pub port: u16,
pub running: bool,
@ -108,11 +111,7 @@ pub async fn build_all(coord: &Coordinator) -> Vec<ContainerView> {
let topology = crate::topology::read();
let mut out = Vec::new();
for c in &raw {
let (logical, is_manager) = if c == MANAGER_CONTAINER {
(MANAGER_NAME.to_owned(), true)
} else if let Some(n) = c.strip_prefix(AGENT_PREFIX) {
(n.to_owned(), false)
} else {
let Some(logical) = c.strip_prefix(AGENT_PREFIX).map(str::to_owned) else {
continue;
};
let deployed_full = locked
@ -120,19 +119,9 @@ pub async fn build_all(coord: &Coordinator) -> Vec<ContainerView> {
.map(std::string::String::as_str);
let needs_update = crate::auto_update::agent_config_pending(&logical, deployed_full);
let deployed_sha = deployed_full.map(|s| s[..s.len().min(12)].to_owned());
// Recipient name the broker uses for this agent — sub-agents
// are addressed by logical name, the manager by the
// MANAGER_AGENT constant. Mirrors the rest of the broker
// surface so the count matches what `mcp__hyperhive__remind`
// queued.
let reminder_recipient = if is_manager {
hive_sh4re::MANAGER_AGENT
} else {
logical.as_str()
};
let pending_reminders = coord
.broker
.count_pending_reminders_for(reminder_recipient)
.count_pending_reminders_for(logical.as_str())
.unwrap_or(0);
let extra_links = read_dashboard_links(&logical);
let parent = topology.get(&logical).cloned().flatten();
@ -155,12 +144,9 @@ pub async fn build_all(coord: &Coordinator) -> Vec<ContainerView> {
) = if running {
// needs_login fires when EITHER the claude session dir is
// missing (boot-time / fresh container) OR the harness wrote
// the auth-failed sentinel because a turn hit 401. The
// manager has its own session lifecycle and never
// participates in needs_login.
let needs_login = !is_manager
&& (!claude_has_session(&Coordinator::agent_claude_dir(&logical))
|| auth_failed_sentinel(&logical));
// the auth-failed sentinel because a turn hit 401.
let needs_login = !claude_has_session(&Coordinator::agent_claude_dir(&logical))
|| auth_failed_sentinel(&logical);
let last_turn = read_last_turn(&logical);
let ctx_tokens = last_turn.as_ref().map(|(toks, _)| *toks);
let context_window_tokens = last_turn
@ -180,11 +166,11 @@ pub async fn build_all(coord: &Coordinator) -> Vec<ContainerView> {
(false, None, None, false, None, None)
};
out.push(ContainerView {
is_manager: logical == MANAGER_NAME,
port: lifecycle::agent_web_port(&logical),
running,
container: c.clone(),
name: logical,
is_manager,
needs_update,
needs_login,
deployed_sha,
@ -298,22 +284,10 @@ fn read_status(name: &str) -> (Option<String>, Option<i64>) {
/// when the container isn't running so callers don't have to know
/// about the sentinel rules — they just hand back what we give them.
///
/// Returned tuple is `(status_text, status_set_at, running)`. The
/// `name` argument is the broker-side recipient — `MANAGER_AGENT` for
/// the manager, the logical agent name otherwise — so callers can
/// reuse the same string they used to look the agent up.
/// Returned tuple is `(status_text, status_set_at, running)`.
/// `name` is the logical agent name (same as the broker recipient).
pub async fn read_agent_status_live(name: &str) -> (Option<String>, Option<i64>, bool) {
// The lifecycle helper wants the on-disk name (`root` for the
// manager, the bare logical name for sub-agents) and internally
// adds the `h-` prefix. Map the broker-side `MANAGER_AGENT`
// sentinel back to the lifecycle name here so callers don't have
// to bother.
let lifecycle_name = if name == hive_sh4re::MANAGER_AGENT {
lifecycle::MANAGER_NAME
} else {
name
};
if !lifecycle::is_running(lifecycle_name).await {
if !lifecycle::is_running(name).await {
return (None, None, false);
}
let (text, set_at) = read_agent_status(name);