diff --git a/frontend/packages/agent/src/agent.css b/frontend/packages/agent/src/agent.css index 5c31b21b..8353f45d 100644 --- a/frontend/packages/agent/src/agent.css +++ b/frontend/packages/agent/src/agent.css @@ -931,3 +931,19 @@ pre.diff { font-style: italic; padding: 1em 0; } + +/* Hive identity row — shows "swarm / hive" label beneath the title. + Hidden until JS populates from /api/state (hive_name + swarm_name). + Mirrors the `.banner-thin` style in dashboard.css but kept tight + (no letter-spacing, smaller text) so it reads as a sub-label. */ +.agent-hive-row { + /* Omit the default row gap when the row is hidden to avoid a + blank gap between the title row and the state row. */ + gap: 0; +} +.agent-hive-label { + font-size: 0.72em; + letter-spacing: 0.1em; + color: var(--purple-dim); + text-transform: uppercase; +} diff --git a/frontend/packages/agent/src/app.js b/frontend/packages/agent/src/app.js index 87b0b37c..0df8c3d6 100644 --- a/frontend/packages/agent/src/app.js +++ b/frontend/packages/agent/src/app.js @@ -138,7 +138,7 @@ window.marked = marked; })(); // ─── state rendering ──────────────────────────────────────────────────── - function setHeader(label, qualifiedLabel, dashboardPort) { + function setHeader(label, qualifiedLabel, dashboardPort, hiveName, swarmName) { const title = $('title'); // Title is just the glowing identity glyph — DASHB04RD, R3BU1LD, // NEW SESSION live in the overflow `⋯` menu. Glow + uppercase @@ -147,15 +147,26 @@ window.marked = marked; // the second row's `qualified` chip + the browser tab title so // the cinematic header reads cleanly at a glance. title.textContent = `◆ ${label} ◆`; - // Document title carries the qualified name so the browser's tab - // bar disambiguates between same-named agents on different hives - // in a federated swarm. Falls back to `${label} // hyperhive` when - // the qualified form is just the short label (single-hive deploys). + // Document title: prefer the human display names when available + // (e.g. "iris // pr1ma") so browser tabs read naturally. Fall back + // to the qualified domain label (e.g. "iris@pr1ma.darkest.space") + // for multi-hive disambiguation when display names are unset, then + // to plain label for single-hive deploys. + const hiveLabel = hiveName || null; const tab = qualifiedLabel && qualifiedLabel !== label ? qualifiedLabel : label; - document.title = `${tab} // hyperhive`; + document.title = hiveLabel ? `${label} // ${hiveLabel}` : `${tab} // hyperhive`; const dashUrl = `${location.protocol}//${location.hostname}:${dashboardPort}/`; dashboardBase = dashUrl; populateOverflowMenu(label, dashUrl); + // Swarm label in the chrome: show "swarm/hive" when both set, just + // "hive" when only hive is known. Targets the `.agent-hive-label` + // element in the header row if present. + const hiveEl = document.querySelector('.agent-hive-label'); + if (hiveEl && (hiveName || swarmName)) { + hiveEl.textContent = swarmName && hiveName + ? `${swarmName} / ${hiveName}` : (hiveName || swarmName); + hiveEl.hidden = false; + } } // Overflow popover: dashboard back-link + rebuild + new-session + @@ -1044,7 +1055,7 @@ window.marked = marked; const resp = await fetch('api/state'); if (!resp.ok) throw new Error('http ' + resp.status); const s = await resp.json(); - if (!headerSet) { setHeader(s.label, s.qualified_label, s.dashboard_port); headerSet = true; } + if (!headerSet) { setHeader(s.label, s.qualified_label, s.dashboard_port, s.hive_name, s.swarm_name); headerSet = true; } currentLabel = s.label; // Render server-supplied navigation links — see // docs/web-ui.md::Per-agent page (meta-nav) for the NavLink diff --git a/frontend/packages/agent/src/index.html b/frontend/packages/agent/src/index.html index d5a2a334..e0a79928 100644 --- a/frontend/packages/agent/src/index.html +++ b/frontend/packages/agent/src/index.html @@ -25,6 +25,12 @@ + +