From fa62417328950f8d7300274f4c085751ad906693 Mon Sep 17 00:00:00 2001 From: iris Date: Fri, 5 Jun 2026 11:30:59 +0200 Subject: [PATCH 1/3] feat(dashboard): prefix browser tab title with pending call count When approvals or questions are waiting, document.title is prefixed with (N) so the operator can see activity in a background browser tab without switching windows. Clears to the base title when zero. Implemented in refreshTabCounts (1s tick): strips any existing prefix before re-applying so the hive-identity title update (once on state load) composes cleanly. --- frontend/packages/dashboard/src/tabs.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/packages/dashboard/src/tabs.js b/frontend/packages/dashboard/src/tabs.js index 5ef70fc0..2441836c 100644 --- a/frontend/packages/dashboard/src/tabs.js +++ b/frontend/packages/dashboard/src/tabs.js @@ -4036,6 +4036,12 @@ window.marked = marked; (approvalsState?.pending?.length ?? 0) + (questionsState?.pending?.length ?? 0); setTabCount('call', callCount); + // Browser tab title prefix — lets the operator see the pending + // call count without switching to the window. Strips any existing + // `(N) ` prefix before re-applying so identity-title updates + // (which run once on state load, not every tick) compose cleanly. + const rawTitle = document.title.replace(/^\(\d+\) /, ''); + document.title = callCount > 0 ? `(${callCount}) ${rawTitle}` : rawTitle; // SYST3M — queued + running rebuild_queue entries (terminal // entries are kept for history but aren't 'attention'). let sysCount = 0; From e24cfba124c91da0425a9ea15254b0fa67f62332 Mon Sep 17 00:00:00 2001 From: iris Date: Fri, 5 Jun 2026 11:32:25 +0200 Subject: [PATCH 2/3] feat(dashboard): preserve call-count prefix on hive-identity title update On refreshState, the hive-identity title update (fired once when hive_name/swarm_name are configured) now reads any existing (N) prefix and preserves it, so the title doesn't briefly drop back to the bare identity string before refreshTabCounts re-applies the prefix. --- frontend/packages/dashboard/src/tabs.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/packages/dashboard/src/tabs.js b/frontend/packages/dashboard/src/tabs.js index 2441836c..22ab322b 100644 --- a/frontend/packages/dashboard/src/tabs.js +++ b/frontend/packages/dashboard/src/tabs.js @@ -3684,7 +3684,10 @@ window.marked = marked; : hive || swarm; hiveId.textContent = label; hiveId.hidden = false; - document.title = label + ' // h1ve-c0re'; + // Preserve any (N) call-count prefix already applied by + // refreshTabCounts so the title doesn't flicker on reload. + const existingPrefix = document.title.match(/^(\(\d+\) )/)?.[1] || ''; + document.title = existingPrefix + label + ' // h1ve-c0re'; } } const openDetails = snapshotOpenDetails(); From 1c4619015dd8865d0f3d127cb85d2ecdee14433e Mon Sep 17 00:00:00 2001 From: iris Date: Fri, 5 Jun 2026 12:56:15 +0200 Subject: [PATCH 3/3] docs(web-ui): document browser tab title call-count prefix --- docs/web-ui/dashboard.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/web-ui/dashboard.md b/docs/web-ui/dashboard.md index 9691bf49..b87a4c08 100644 --- a/docs/web-ui/dashboard.md +++ b/docs/web-ui/dashboard.md @@ -26,6 +26,16 @@ swap. `state.matrix_gui_enabled` from `/api/state`. - **Banner-thin** (`░▒▓█▓▒░ HYPERHIVE / HIVE-C0RE / WE ARE THE WIRED ░▒▓█▓▒░`) — sits below the tab strip. +- **Browser tab title** — `hive / c0re` by default; updated to + ` / ` once `hive_name` / `swarm_name` arrive in the + state snapshot. When there are pending approvals or unanswered + questions, a `(N)` prefix is prepended — `(3) pr1ma / hive-c0re` + — so the operator can see the call count in an unfocused browser + tab without opening the dashboard. The prefix is set on the + initial `/api/state` cold-load and updated live by + `approval_added` / `approval_resolved` / `question_added` / + `question_resolved` SSE events; it's preserved when + `hive_name` / `swarm_name` later replace the raw title. The FL0W page reuses the same chrome strip but its `◆ S3TT1NGS ◆ →` entry is a cross-page link back to the dashboard