Follow-up to the route swap (#1501): now that every separate page is reachable from the H0M3 hub, the dashboard tab strip should hold only real in-page tabs, not the "→" links out to other pages (mara: "remove links to the pages from dashboard - only actual tabs stay here"). - dashboard.html: remove the `tab-matrix`, `tab-flow`, and `tab-logs` `.tab-link` entries (and the stale `tab-count-flow` pill slot — the operator inbox moved to Y3R C4LL). The dashboard strip is now SW4RM / Y3R C4LL / SYST3M / P3RM1SS10NS / SCH3DUL3S / P33RS / ST4TS / S3TT1NGS. - tabs.js: drop the now-dead `tab-matrix` matrix_gui_enabled gate (the H0M3 Matrix tile is gated by home.js instead) and the obsolete `#tab-count-flow` comment. Kept the contextual deep-links into the log viewer (an agent's logs, a build entry's log) — those are functional content links, not navigation chrome. - flow.css: remove the dead `.dashboard-chrome.flow-chrome` + `.tabbar .tab.active.tab-link` rules — the flow page uses a slim back-link header, not the dashboard tabbar, and `.tab-link` no longer exists anywhere. npm run build green (flow.css 1.8kb). No residual references.
365 lines
21 KiB
HTML
365 lines
21 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>hyperhive // h1ve-c0re</title>
|
||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||
<link rel="stylesheet" href="/static/theme.css">
|
||
<link rel="stylesheet" href="/static/common.css">
|
||
<link rel="stylesheet" href="/static/dashboard.css">
|
||
</head>
|
||
<body class="dashboard-shell">
|
||
|
||
<!-- Sticky chrome — just the tab strip. The "WE ARE THE WIRED"
|
||
slug lives at the page footer below `<main>`; chrome is
|
||
navigation only. Tabs route via the URL hash so F5 / back-
|
||
button / shared links keep you on the same view. JS owns
|
||
the show/hide. -->
|
||
<header class="dashboard-chrome">
|
||
<!-- Back to the H0M3 menu hub (served at /). Sub-pages and the
|
||
dashboard all link back to the landing page rather than to each
|
||
other — H0M3 is the single navigation hub. -->
|
||
<a class="dash-home-back" href="/" title="back to the H0M3 menu">← home</a>
|
||
<!-- Hive identity line: swarm/hive label. Hidden until JS populates
|
||
it from /api/state (hive_name + swarm_name). Falls back to
|
||
hostname when only the domain is configured. -->
|
||
<p class="banner-thin" id="hive-identity" hidden></p>
|
||
<nav class="tabbar" id="tabbar" role="tablist">
|
||
<a class="tab" id="tab-swarm" href="#swarm" role="tab"
|
||
aria-controls="tab-pane-swarm"
|
||
data-tab="swarm">
|
||
<span class="tab-label">◆ SW4RM ◆</span>
|
||
<span class="tab-count" id="tab-count-swarm" hidden></span>
|
||
</a>
|
||
<a class="tab" id="tab-call" href="#call" role="tab"
|
||
aria-controls="tab-pane-call"
|
||
data-tab="call">
|
||
<span class="tab-label">◆ Y3R C4LL ◆</span>
|
||
<span class="tab-count tab-count-attn" id="tab-count-call" hidden></span>
|
||
</a>
|
||
<a class="tab" id="tab-system" href="#system" role="tab"
|
||
aria-controls="tab-pane-system"
|
||
data-tab="system">
|
||
<span class="tab-label">◆ SYST3M ◆</span>
|
||
<span class="tab-count" id="tab-count-system" hidden></span>
|
||
</a>
|
||
<!-- P3RM1SS10NS: per-agent capability grants and tool-group
|
||
assignments. Both tables are fetched on tab activation. -->
|
||
<a class="tab" id="tab-permissions" href="#permissions" role="tab"
|
||
aria-controls="tab-pane-permissions"
|
||
data-tab="permissions">
|
||
<span class="tab-label">◆ P3RM1SS10NS ◆</span>
|
||
</a>
|
||
|
||
<!-- SCH3DUL3S: scheduled-prompts surface. List of queued
|
||
schedules + an operator-direct creation form. Count pill
|
||
mirrors the active (non-cancelled) schedule count; hidden
|
||
when zero. -->
|
||
<a class="tab" id="tab-schedules" href="#schedules" role="tab"
|
||
aria-controls="tab-pane-schedules"
|
||
data-tab="schedules">
|
||
<span class="tab-label">◆ SCH3DUL3S ◆</span>
|
||
<span class="tab-count" id="tab-count-schedules" hidden></span>
|
||
</a>
|
||
|
||
<!-- ST4TS: hive-wide turn-stats rollup (swarm totals, busiest
|
||
agents, model mix, est cost). Fetched on tab activation +
|
||
window change from GET /api/stats-hive. -->
|
||
<a class="tab" id="tab-stats" href="#stats" role="tab"
|
||
aria-controls="tab-pane-stats"
|
||
data-tab="stats">
|
||
<span class="tab-label">◆ ST4TS ◆</span>
|
||
</a>
|
||
|
||
<!-- P33RS: peer hive navigation links. Hidden until at least one
|
||
peer is configured in `services.hyperhive.peers`. -->
|
||
<a class="tab" id="tab-peers" href="#peers" role="tab"
|
||
aria-controls="tab-pane-peers"
|
||
data-tab="peers" hidden>
|
||
<span class="tab-label">◆ P33RS ◆</span>
|
||
<span class="tab-count" id="tab-count-peers" hidden></span>
|
||
</a>
|
||
|
||
<!-- FL0W, L0GS, and M4TR1X are separate pages reachable from the
|
||
H0M3 hub (served at /), not from the dashboard tab strip — the
|
||
strip holds only real in-page tabs now. Contextual deep-links
|
||
into the log viewer (an agent's logs, a build entry's log)
|
||
still live inside the relevant dashboard content. -->
|
||
|
||
<!-- S3TT1NGS: default-overflow — always lives in the ⋮ dropdown,
|
||
never in the main strip. `data-overflow="default"` marks it so
|
||
JS keeps it out of the bar regardless of available width. -->
|
||
<a class="tab" id="tab-settings" href="#settings" role="tab"
|
||
aria-controls="tab-pane-settings"
|
||
data-tab="settings"
|
||
data-overflow="default">
|
||
<span class="tab-label">◆ S3TT1NGS ◆</span>
|
||
</a>
|
||
|
||
<!-- Overflow ⋮ button + dropdown. JS populates the dropdown with
|
||
tab clones and keeps the button hidden when the dropdown would
|
||
be empty. Gets `.tabbar-overflow-active` when the active tab
|
||
is inside. -->
|
||
<div class="tabbar-overflow" id="tabbar-overflow">
|
||
<button type="button" class="tabbar-overflow-btn" id="tabbar-overflow-btn"
|
||
aria-haspopup="menu" aria-expanded="false"
|
||
title="more tabs" hidden>⋮</button>
|
||
<ul class="tabbar-overflow-dropdown" id="tabbar-overflow-dropdown"
|
||
role="menu" hidden></ul>
|
||
</div>
|
||
</nav>
|
||
</header>
|
||
|
||
<!-- Tab panes. Exactly one is `.tab-pane-active` at a time;
|
||
JS toggles based on the URL hash + `hashchange` events. -->
|
||
<main class="dashboard-main">
|
||
|
||
<!-- SW4RM: the swarm itself. Container cards (the central thing
|
||
the operator looks at) and rebuild queue / cascade visualisation
|
||
that drives them. No inline `C0NTAINERS` h2 heading + divider
|
||
— the tab label SW4RM already says it. -->
|
||
<section class="tab-pane" id="tab-pane-swarm"
|
||
role="tabpanel" aria-labelledby="tab-swarm">
|
||
<div id="containers-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Y3R C4LL: things blocked on operator decision. Approvals +
|
||
questions read as the same concept ("something is waiting on
|
||
you"); both surface their full bodies inline so the operator
|
||
can decide without leaving the pane. -->
|
||
<section class="tab-pane" id="tab-pane-call"
|
||
role="tabpanel" aria-labelledby="tab-call">
|
||
<!-- 1NB0X: unread agent→operator messages (#1469). Fetched on
|
||
tab activation + cold load, appended live from the broker
|
||
stream, cleared via "mark all read". Count folds into the
|
||
Y3R C4LL pill so messages aren't missed. -->
|
||
<h2>◆ 1NB0X ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<div id="operator-inbox-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
|
||
<h2>◆ P3NDING APPR0VALS ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<div id="approvals-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
|
||
<h2>◆ M1ND H4S QU3STI0NS ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<div id="questions-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- SYST3M: passive / rare-interaction state. Meta inputs (lock
|
||
bumps), rebuild queue (watch only), kept state from previous
|
||
tombstoned agents. Per-section content auto-compresses to a
|
||
one-line summary when empty (JS toggle). -->
|
||
<section class="tab-pane" id="tab-pane-system"
|
||
role="tabpanel" aria-labelledby="tab-system">
|
||
<h2>◆ M3T4 1NPUTS ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p class="meta">select inputs to <code>nix flake update</code> in <code>/meta/</code>. selected agents rebuild in sequence after the lock bump; manager learns each outcome via the usual <code>rebuilt</code> system event.</p>
|
||
<div id="meta-inputs-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
|
||
<h2>◆ R3BU1LD QU3U3 ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p class="meta">pending + running rebuilds, meta-updates, and first-spawns. one runs at a time; meta-update cascades nest under their parent. dedup: re-enqueueing a still-queued op collapses into the existing entry.</p>
|
||
<div id="rebuild-queue-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
|
||
<h2>◆ K3PT ST4T3 ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<div id="tombstones-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
|
||
<!-- C0NT41N3R L04D: live cpu + memory per agent container, read
|
||
from cgroup v2 on the host. Polled only while this tab is
|
||
active (cpu needs a short two-sample read each refresh). -->
|
||
<h2>◆ C0NT41N3R L04D ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p class="meta">live cpu + memory per agent container, from cgroup v2 on the host. cpu is % of total host capacity (all cores), sampled over ~200ms each refresh; polled every 5s while this tab is open. network is omitted on purpose — agents share the host netns, so there is no per-container counter (see <code>docs/network.md</code>).</p>
|
||
<div id="container-load-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
|
||
</section>
|
||
|
||
<!-- P3RM1SS10NS: per-agent capability grants + tool-group
|
||
assignments. Both tables are column-driven from the backend
|
||
(GET /api/capabilities, GET /api/tool-groups) so new entries
|
||
require no UI change. Saving POSTs to the respective
|
||
/{agent} endpoint and queues a rebuild. -->
|
||
<section class="tab-pane" id="tab-pane-permissions"
|
||
role="tabpanel" aria-labelledby="tab-permissions">
|
||
<h2>◆ C4P4B1L1T13S ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p class="meta">per-agent capability grants. capabilities unlock gated MCP tools and system access. saving queues a rebuild for the affected agent.</p>
|
||
<div id="capabilities-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
|
||
<!-- T00L GR0UPS: per-agent tool-group permission matrix. Rows = agents,
|
||
cols = tool groups fetched from GET /api/tool-groups.
|
||
Checking / unchecking and saving POSTs to
|
||
/api/tool-groups/{agent}; a rebuild is queued automatically.
|
||
Absent agents default to the role default (shown in parens). -->
|
||
<h2>◆ T00L GR0UPS ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p class="meta">per-agent tool-group permissions. columns are filled from the backend — adding a new group requires no UI change. agents without an explicit entry use the role default (agents: messaging, meta, inbox, execution; manager: all). saving queues a rebuild.</p>
|
||
<div id="tool-groups-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- P33RS: peer hive link cards. Rendered from state.peer_hives;
|
||
hidden when the list is empty. -->
|
||
<section class="tab-pane" id="tab-pane-peers"
|
||
role="tabpanel" aria-labelledby="tab-peers">
|
||
<h2>◆ P33R H1V3S ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p class="meta">peer hives in this swarm. click a card to open that hive's dashboard.</p>
|
||
<div id="peers-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- SCH3DUL3S: scheduled prompts. Creation + edit are folded
|
||
into the same table — empty bottom row is the create form
|
||
(fill cells, click +), inline-edit-row expands on the `✎`
|
||
toggle for existing schedules. Schedules list driven by
|
||
GET /api/schedules; POST /api/schedules to create, PATCH
|
||
/api/schedules/{id} to edit, POST /api/schedules/{id}/cancel
|
||
for per-target / whole-row cancel. Live updates via
|
||
`schedules_changed` SSE; tab activation re-fetches as a
|
||
safety net for disconnect windows.
|
||
See docs/web-ui.md::SCH3DUL3S tab. -->
|
||
<section class="tab-pane" id="tab-pane-schedules"
|
||
role="tabpanel" aria-labelledby="tab-schedules">
|
||
<h2>◆ SCH3DUL3S ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p class="meta">all schedules currently in the table. fill the bottom row to queue a new schedule (operator-direct, no approval gate; recurring when an interval is set). cancel a single target with the row button or the whole schedule with <code>✕ cancel all</code>.</p>
|
||
<div id="schedules-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
|
||
<!-- QU3U3D R3M1ND3RS: self-scheduled agent reminders. Lives
|
||
on this tab so the operator has one place for everything
|
||
that fires at a future time — operator-set schedules
|
||
above, agent-self reminders here. Backed by GET
|
||
/api/reminders; live updates via `reminders_changed` SSE;
|
||
refreshReminders() called from refreshState + tab
|
||
activation as safety net for disconnect windows. -->
|
||
<h2>◆ QU3U3D R3M1ND3RS ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p class="meta">reminders agents have queued for themselves but not yet delivered. cancel to drop a stuck or unwanted entry.</p>
|
||
<div id="reminders-section">
|
||
<p class="meta">loading…</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ST4TS: hive-wide turn-stats aggregate. Plain tables/bars (the
|
||
dashboard bundle has no chart lib); data from GET
|
||
/api/stats-hive?window=, fetched on tab activation + on
|
||
window change. Per-agent trend charts stay on each agent's
|
||
own /stats page. -->
|
||
<section class="tab-pane" id="tab-pane-stats"
|
||
role="tabpanel" aria-labelledby="tab-stats">
|
||
<h2>◆ ST4TS ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p class="meta">hive-wide turn statistics, aggregated across every agent over the selected window. <strong>cost is a rough estimate</strong> from approximate per-model list prices — it drifts and is a ballpark, not a bill.</p>
|
||
<div class="hive-stats-windows" id="hive-stats-windows">
|
||
<button type="button" class="btn" data-w="1h">1h</button>
|
||
<button type="button" class="btn" data-w="4h">4h</button>
|
||
<button type="button" class="btn active" data-w="24h">24h</button>
|
||
<button type="button" class="btn" data-w="3d">3d</button>
|
||
<button type="button" class="btn" data-w="7d">7d</button>
|
||
<button type="button" class="btn" data-w="30d">30d</button>
|
||
</div>
|
||
<div class="hive-stats-chips" id="hive-stats-summary"></div>
|
||
<h3>◇ busiest agents</h3>
|
||
<div id="hive-stats-agents"><p class="meta">loading…</p></div>
|
||
<h3>◇ model mix (turns across the swarm)</h3>
|
||
<div id="hive-stats-models"></div>
|
||
</section>
|
||
|
||
<!-- FL0W: lives on its own page now (`/flow.html`). The
|
||
message-flow + inbox + compose DOM only exists there — when
|
||
tabs.js boots on this page the corresponding renderers
|
||
no-op silently (each guard is `if (!el) return`). -->
|
||
|
||
<!-- S3TT1NGS: operator-local preferences. Today this is just the
|
||
browser-notification toggle (per-browser localStorage state).
|
||
The same IDs that used to live in the tab strip migrated
|
||
here unchanged so `NOTIF.bind()` in common.js wires them
|
||
without any JS change. -->
|
||
<section class="tab-pane" id="tab-pane-settings"
|
||
role="tabpanel" aria-labelledby="tab-settings">
|
||
<h2>◆ S3TT1NGS ◆</h2>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p class="meta">operator-local preferences. these live in the browser's localStorage — they do not sync between devices and do not survive a profile wipe.</p>
|
||
|
||
<h3>◇ browser notifications</h3>
|
||
<p class="meta">desktop notifications for new approvals, new operator questions, and broker messages addressed to you. requires a secure context (https or localhost). mute silences the notifications without revoking the OS-level permission.</p>
|
||
<div id="notif-row" class="notif-row">
|
||
<button type="button" id="notif-enable" class="btn btn-notif" hidden>🔔 enable notifications</button>
|
||
<button type="button" id="notif-mute" class="btn btn-notif" hidden>🔕 mute</button>
|
||
<button type="button" id="notif-unmute" class="btn btn-notif" hidden>🔔 unmute</button>
|
||
<span id="notif-status" class="meta" hidden></span>
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
|
||
<footer>
|
||
<pre class="banner banner-thin">░▒▓█▓▒░ HYPERHIVE / HIVE-C0RE / WE ARE THE WIRED ░▒▓█▓▒░</pre>
|
||
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
||
<p>▲△▲ <a href="https://forge.darkest.space/hyperhive/hyperhive">hyperhive</a> ▲△▲ hive-c0re on this host ▲△▲</p>
|
||
</footer>
|
||
|
||
<!-- Slide-in detail panel. Long content (clicked file previews,
|
||
approval diffs, journald logs, applied config) opens here
|
||
instead of expanding inline. Singleton — JS swaps the title +
|
||
body and toggles `.open`. Lives outside the tab panes so it
|
||
overlays any active tab. -->
|
||
<div id="side-panel" class="side-panel" aria-hidden="true">
|
||
<div class="side-panel-backdrop" id="side-panel-backdrop"></div>
|
||
<aside class="side-panel-drawer" role="dialog" aria-modal="true"
|
||
aria-labelledby="side-panel-title">
|
||
<header class="side-panel-head">
|
||
<span class="side-panel-title" id="side-panel-title"></span>
|
||
<button type="button" class="side-panel-close" id="side-panel-close"
|
||
title="close (esc)">✕</button>
|
||
</header>
|
||
<div class="side-panel-body" id="side-panel-body"></div>
|
||
</aside>
|
||
</div>
|
||
|
||
<!-- Selection action bar. Sticky-bottom strip that slides into
|
||
view when one or more agent cards is selected (click the icon
|
||
to toggle). See docs/web-ui.md::Selection bar for the bulk
|
||
action gating + clear semantics. -->
|
||
<div id="selection-bar" class="selection-bar" hidden role="toolbar"
|
||
aria-label="bulk agent actions">
|
||
<span class="selection-count" id="selection-count"></span>
|
||
<span class="selection-names" id="selection-names"></span>
|
||
<span class="selection-actions" id="selection-actions"></span>
|
||
<button type="button" class="btn selection-clear" id="selection-clear"
|
||
title="clear selection (esc)">✕ clear</button>
|
||
</div>
|
||
|
||
<!-- Single bundled entry — tabs.js is the dashboard tabs surface;
|
||
flow.html has its own flow.js bundle. esbuild folds
|
||
@hive/shared/terminal.js and the marked npm package into
|
||
tabs.js. -->
|
||
<script type="module" src="/static/tabs.js" defer></script>
|
||
</body>
|
||
</html>
|