Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/frontend/packages/dashboard/src/common.css
atlas 7e6a4c7727 agents: remove send(operator) and the operator inbox; alert on turn failures
Agents reach the operator over matrix now (#5115). A `send` to
`operator` is refused, by the broker and by the MCP allow-list check,
with an error that names the matrix MCP tools. The dashboard's Y3R C4LL
tab goes with it: the operator inbox, `GET /api/operator-inbox`,
`Broker::unread_for_recipient`, and the browser notifications that only
ever fired on operator-bound messages.

The harness no longer posts turn failures and plugin-install failures
to the operator inbox. Both are already logged at warn; a new Grafana
rule, `hh-agent-turn-failed`, fires per agent on the harness's
`turn failed` line.

Dashboard-to-agent messaging (op-send, the agent web UI's message box,
mark-all-read for agent inboxes) is unchanged.

Decisions per mara on #5115: q1 a, q2 a plus a grafana alert, q3 keep
dashboard-to-agent messaging and leave swarm-level code alone.
2026-10-12 08:50:06 +02:00

646 lines
18 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Shared Catppuccin palette + body typography + terminal pane styles.
Bundled in front of the page-specific rules via esbuild. */
@import "@hive/shared/base.css";
@import "@hive/shared/terminal.css";
@import "@hive/shared/tabs.css";
@import "@hive/shared/chrome.css";
/* Shared pill/chip/badge shape (the "extract pill component" issue,
resolved as shared CSS rather than a JS component) — see pill.css
itself for the classnames it covers. */
@import "@hive/shared/pill.css";
/* ─── global typography ─────────────────────────────────────────────
Element-level rules shared across every page. These must not
reference page-specific chrome classes. */
h1,
h2 {
color: var(--purple);
text-transform: uppercase;
letter-spacing: 0.15em;
margin-top: 2em;
text-shadow: 0 0 8px color-mix(in srgb, var(--purple) 40%, transparent);
}
.divider {
color: var(--purple-dim);
overflow: hidden;
white-space: nowrap;
margin-bottom: 0.5em;
}
ul {
list-style: none;
padding-left: 0;
}
li {
padding: 0.5em 0;
}
.glyph {
color: var(--purple);
margin-right: 0.5em;
}
a {
color: var(--cyan);
text-decoration: none;
font-weight: bold;
text-shadow: 0 0 4px color-mix(in srgb, var(--cyan) 50%, transparent);
}
a:hover {
color: var(--fg);
text-shadow: 0 0 12px color-mix(in srgb, var(--cyan) 90%, transparent);
}
code {
color: var(--amber);
background: var(--bg-elev);
padding: 0.1em 0.4em;
border: 1px solid var(--border);
border-radius: 2px;
font-size: 0.9em;
}
/* ─── shared inline labels ──────────────────────────────────────────
.meta / .id / .agent / .empty appear in message rows, build-log
toolbars, and side-panel content rendered by common.js. */
.meta {
color: var(--muted);
font-size: 0.85em;
margin-left: 0.4em;
}
.id {
color: var(--pink);
font-weight: bold;
margin-right: 0.4em;
}
.agent {
color: var(--amber);
font-weight: bold;
margin-right: 0.6em;
}
.empty {
color: var(--muted);
font-style: italic;
}
/* ─── status badges ─────────────────────────────────────────────────
Semantic colour variants only — shape comes from `hive-pill-sm`
(shared with the agent UI's pill/chip family, @hive/shared/pill.css),
carried directly in the markup alongside each of these classnames
(swarm.js/core.js/builds.js). Used on container rows and build-log
rows. */
.badge-warn {
color: var(--amber);
border-color: var(--amber);
text-shadow: 0 0 6px color-mix(in srgb, var(--amber) 50%, transparent);
}
.badge-rate-limited {
color: var(--red);
border-color: var(--red);
text-shadow: 0 0 6px color-mix(in srgb, var(--red) 50%, transparent);
}
.badge-muted {
color: var(--muted);
border-color: var(--purple-dim);
background: color-mix(in srgb, var(--muted) 8%, transparent);
}
.badge-loose-ends {
color: var(--purple);
border-color: var(--purple);
text-shadow: 0 0 6px color-mix(in srgb, var(--purple) 40%, transparent);
}
/* Paused agent: turn loop parked, container still up. Clickable (btn-inline):
clicking sends POST /api/resume/{name} so the badge doubles as a resume button. */
.badge-paused {
color: var(--yellow);
border-color: var(--yellow);
background: color-mix(in srgb, var(--yellow) 10%, transparent);
}
/* Active Claude model badge on dashboard container rows. */
.badge-model {
color: var(--blue);
border-color: var(--blue);
opacity: 0.8;
}
/* Context-window usage badges on dashboard container rows. */
.badge-ctx-ok {
color: var(--green);
border-color: var(--green);
opacity: 0.85;
}
.badge-ctx-caution {
color: var(--amber);
border-color: var(--amber);
text-shadow: 0 0 6px color-mix(in srgb, var(--amber) 50%, transparent);
}
.badge-ctx-warn {
color: var(--red);
border-color: var(--red);
text-shadow: 0 0 6px color-mix(in srgb, var(--red) 50%, transparent);
}
.badge-ok {
background: color-mix(in srgb, var(--green) 12%, transparent);
color: var(--green);
border-color: var(--green);
}
.badge-fail {
background: color-mix(in srgb, var(--red) 12%, transparent);
color: var(--red);
border-color: var(--red);
}
.badge-running {
background: color-mix(in srgb, var(--amber) 12%, transparent);
color: var(--amber);
border-color: var(--amber);
}
/* ─── buttons ───────────────────────────────────────────────────────
.btn base + semantic colour/size modifiers. */
.btn {
font-family: inherit;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.1em;
background: transparent;
/* Strip browser UA button chrome (solid fill, system text colour).
Without this, native <button> + <input type="submit"> elements
ignore our background:transparent and colour in some browsers. */
-webkit-appearance: none;
appearance: none;
border: 1px solid;
padding: 0.25em 0.8em;
cursor: pointer;
text-shadow: 0 0 4px currentColor;
box-shadow: 0 0 0 0 currentColor;
transition: box-shadow 0.15s ease;
}
.btn:hover {
background: color-mix(in srgb, var(--fg) 6%, transparent);
text-shadow: 0 0 10px currentColor;
box-shadow: 0 0 10px -2px currentColor;
}
.btn:disabled,
.btn[disabled] {
opacity: 0.32;
cursor: not-allowed;
text-shadow: none;
box-shadow: none;
}
.btn:disabled:hover,
.btn[disabled]:hover {
background: transparent;
text-shadow: none;
box-shadow: none;
}
.btn-approve {
color: var(--green);
border-color: var(--green);
}
.btn-destroy {
color: var(--red);
border-color: var(--red);
font-size: 0.75em;
padding: 0.15em 0.5em;
margin-left: 0.6em;
}
.btn-rebuild {
color: var(--amber);
border-color: var(--amber);
font-size: 0.75em;
padding: 0.15em 0.5em;
margin-left: 0.6em;
}
.btn-restart {
color: var(--cyan);
border-color: var(--cyan);
font-size: 0.75em;
padding: 0.15em 0.5em;
margin-left: 0.6em;
}
.btn-stop {
color: var(--pink);
border-color: var(--pink);
font-size: 0.75em;
padding: 0.15em 0.5em;
margin-left: 0.6em;
}
.btn-start {
color: var(--green);
border-color: var(--green);
font-size: 0.75em;
padding: 0.15em 0.5em;
margin-left: 0.6em;
}
/* Same yellow as .badge-paused (the paused-state pill) — pause enters
that state, so the trigger and the resulting badge read as one
colour, not two unrelated ones. Resume reads as green like
.btn-start: both are "go" actions, back to the turn loop running. */
.btn-pause {
color: var(--yellow);
border-color: var(--yellow);
font-size: 0.75em;
padding: 0.15em 0.5em;
margin-left: 0.6em;
}
.btn-resume {
color: var(--green);
border-color: var(--green);
font-size: 0.75em;
padding: 0.15em 0.5em;
margin-left: 0.6em;
}
/* M0V3 affordance (selection bar) — mauve reads as "structural
change" rather than the destructive red / amber chrome of
destroy / rebuild. See docs/web-ui/dashboard.md::Selection bar. */
.btn-move {
color: var(--purple);
border-color: var(--purple);
font-size: 0.75em;
padding: 0.15em 0.5em;
margin-left: 0.6em;
}
.btn-talk {
color: var(--cyan);
border-color: var(--cyan);
}
.btn-spawn {
color: var(--amber);
border-color: var(--amber);
}
/* ─── file-preview / diff panel (common.js Panel) ───────────────────
Side-panel content rendered by openFilePanel / buildTabbedPreview
in common.js; all three pages load the Panel singleton. */
.diff-panel {
display: flex;
flex-direction: column;
gap: 0.6em;
}
.diff-base-tabs {
display: flex;
flex-wrap: wrap;
gap: 0.4em;
}
.diff-base-tab {
background: transparent;
border: 1px solid var(--border);
color: var(--muted);
font: inherit;
font-size: 0.85em;
padding: 0.2em 0.7em;
cursor: pointer;
}
.diff-base-tab:hover {
color: var(--fg);
}
.diff-base-tab.active {
color: var(--purple);
border-color: var(--purple);
background: color-mix(in srgb, var(--purple) 8%, transparent);
}
/* Image / tabbed file preview */
.preview-host {
margin-top: 0.5em;
}
.img-preview {
display: block;
max-width: 100%;
height: auto;
margin: 0 auto;
border: 1px solid var(--border);
border-radius: 4px;
/* checkerboard so transparent regions of the image read clearly */
background: repeating-conic-gradient(var(--border) 0% 25%, var(--bg) 0% 50%)
50% / 18px 18px;
}
/* Path linkification — agents drop pointer strings into messages;
clicking the anchor opens the file in the side panel. */
.path-link {
color: var(--blue);
text-decoration: underline dotted;
cursor: pointer;
}
.path-link:hover {
color: var(--amber);
}
/* File-preview body — rendered inside the side panel. */
.path-preview-body {
background: var(--bg);
border: 1px solid var(--border);
padding: 0.5em 0.7em;
margin: 0;
white-space: pre-wrap;
word-break: break-word;
font-size: 0.85em;
color: var(--fg);
}
/* page chrome (.page-header / .page-back / .page-title — the standalone
pages' sticky back-link bar) moved to @hive/shared/chrome.css, imported
at the top of this file. */
/* `#msgflow` is a shared `.live` pane inside `.terminal-wrap`. The
msgrow / msg-* rules below power the /flow.html full-page terminal. */
.live .msgrow {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.5em;
padding: 0.1em 0;
text-indent: 0;
}
.live .msgrow .msg-body {
flex: 1 1 100%;
min-width: 0;
}
.live .msgrow.sent .msg-arrow {
color: var(--cyan);
}
.live .msgrow.delivered .msg-arrow {
color: var(--green);
}
/* Reply-thread rendering: indented border-left + muted reply tag. */
.live .msgrow.msg-reply {
padding-left: 1.2em;
border-left: 2px solid var(--border);
margin-left: 0.6em;
}
.msg-reply-tag {
color: var(--muted);
font-size: 0.8em;
white-space: nowrap;
order: -1;
}
.msg-reply-tag a {
color: var(--muted);
text-shadow: none;
font-weight: normal;
}
.msg-reply-tag a:hover {
color: var(--fg);
}
@keyframes msg-highlight-fade {
from {
background: color-mix(in srgb, var(--purple) 18%, transparent);
}
to {
background: transparent;
}
}
.msg-highlight {
animation: msg-highlight-fade 1.5s ease-out forwards;
}
.msg-ts {
color: var(--muted);
font-size: 0.85em;
}
.msg-arrow {
font-weight: bold;
}
.msg-from {
color: var(--amber);
}
.msg-sep {
color: var(--muted);
}
.msg-to {
color: var(--pink);
}
.msg-body {
color: var(--fg);
white-space: pre-wrap;
word-break: break-word;
}
/* ─── operator compose box ──────────────────────────────────────────
Sits inside `.terminal-wrap` on both /flow.html and the dashboard
CALL tab. Dashed top separator mirrors the agent terminal prompt. */
.op-compose {
position: relative;
display: flex;
align-items: flex-start;
gap: 0.6em;
padding: 0.55em 0.8em;
border-top: 1px dashed var(--purple-dim);
}
.op-compose-prompt {
color: var(--purple);
text-shadow: 0 0 4px currentColor;
font-weight: bold;
white-space: nowrap;
user-select: none;
padding-top: 0.15em;
}
.op-compose-input {
flex: 1;
background: transparent;
color: var(--fg);
border: none;
font-family: inherit;
font-size: 1em;
line-height: 1.4;
resize: none;
overflow: hidden;
max-height: 8em;
padding: 0;
}
.op-compose-input:focus {
outline: none;
}
.op-compose-input::placeholder {
color: var(--muted);
}
.op-compose-suggest {
position: absolute;
left: 3em;
bottom: 100%;
z-index: 50;
background: var(--bg-elev);
border: 1px solid var(--purple-dim);
border-radius: 4px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
list-style: none;
margin: 0;
padding: 0.3em 0;
min-width: 12em;
max-height: 14em;
overflow-y: auto;
}
.op-compose-suggest .item {
padding: 0.35em 0.9em;
cursor: pointer;
font-size: 0.9em;
color: var(--muted);
}
.op-compose-suggest .item.active,
.op-compose-suggest .item:hover {
background: var(--border);
color: var(--purple);
}
/* ─── side panel ─────────────────────────────────────────────────
Long content (file previews, diffs, applied config) opens in
a drawer that swipes in from the right — used by both /flow.html and
the dashboard. The drawer chrome itself (backdrop, drawer, resize
handle, header, title, close button) is now the shared
`<hive-side-panel>` element (@hive/shared/side-panel.js); what's left
here is the drag cursor-override escape hatch (has to be a global,
light-DOM rule — it reaches every element on the page during a drag,
not just the shared element's own shadow tree) and the styling for
the panel's own content types, which the shared element's shadow tree
can never reach (see @hive/shared/side-panel/hive-side-panel.css's
header comment). The `hive-side-panel .md …` rules below use the
element's own tag name as the selector root — no compatibility class
needed, the tag name already uniquely identifies the light-DOM
instance `common.js`'s `sidePanel` creates. */
body.side-panel-resizing {
user-select: none;
}
body.side-panel-resizing * {
cursor: ew-resize !important;
}
hive-side-panel .md {
color: var(--fg);
line-height: 1.5;
}
hive-side-panel .md > :first-child {
margin-top: 0;
}
hive-side-panel .md > :last-child {
margin-bottom: 0;
}
hive-side-panel .md p {
margin: 0.5em 0;
}
hive-side-panel .md h1,
hive-side-panel .md h2,
hive-side-panel .md h3,
hive-side-panel .md h4 {
color: var(--purple);
margin: 0.9em 0 0.4em;
}
hive-side-panel .md code {
background: var(--bg);
border: 1px solid var(--border);
border-radius: 2px;
padding: 0.1em 0.3em;
font-size: 0.9em;
}
hive-side-panel .md pre {
background: var(--crust);
border: 1px solid var(--border);
padding: 0.5em 0.7em;
overflow-x: auto;
margin: 0.5em 0;
}
hive-side-panel .md pre code {
background: none;
border: none;
padding: 0;
}
hive-side-panel .md a {
color: var(--cyan);
}
hive-side-panel .md ul,
hive-side-panel .md ol {
margin: 0.4em 0;
padding-left: 1.5em;
}
hive-side-panel .md blockquote {
border-left: 3px solid var(--purple-dim);
padding-left: 0.8em;
margin: 0.4em 0;
color: var(--muted);
}
hive-side-panel .md table {
border-collapse: collapse;
margin: 0.5em 0;
}
hive-side-panel .md th,
hive-side-panel .md td {
border: 1px solid var(--border);
padding: 0.2em 0.5em;
}
/* ─── page-content gutter ─────────────────────────────────────────────
Inverted-gutter layout: the dashboard + H0M3 keep `<body>` full-bleed
and wrap their padded content in a single `.page-content` div that
carries the horizontal gutter. Full-width chrome (the tab strip, the
server-warnings banner, the footer) then spans edge-to-edge for free,
with no negative-margin breakout hacks. Only matches on pages that opt
in by adding the wrapper (dashboard.html, index.html); FL0W / ST4TS
are full-bleed with their own `.<page>-main` padding. */
.page-content {
padding: 0 1.5em;
}
/* ─── sticky top region ───────────────────────────────────────────────
One sticky container per page holding the warning banner above the
page chrome (tab bar / page header). common.js (ensureStickyTop)
wraps the page's chrome in this on first render and injects the banner
as its first child, so the banner + chrome stack in a single sticky
context — pinned together — instead of two separate `top:0` stickies
colliding (the banner used to overlay the tab bar). */
.sticky-top {
position: sticky;
top: 0;
z-index: 50;
}
/* ─── server warnings banner ──────────────────────────────────────────
Generic top-of-page strip, injected as the first child of `.sticky-top`
by common.js (renderServerWarnings) on every page. One row per warning;
colour comes from the per-warning `level` (warn = amber, crit = red).
Stickiness lives on the `.sticky-top` wrapper, not here. The bar spans
the full width edge-to-edge; the dashboard + H0M3 are full-bleed at the
body level (their 1.5em gutter lives on an inner `.page-content`
wrapper), so the banner is full-width for free. */
.server-warnings[hidden] {
display: none;
}
.server-warn {
text-align: center;
padding: 0.4em 1em;
font-size: 0.85em;
font-weight: bold;
letter-spacing: 0.02em;
}
/* Tint composited over the opaque elevated-surface grey (not transparent):
the bar is `position: sticky`, so a see-through background would let
page content scroll through behind it. */
.server-warn-warn {
color: var(--amber);
background: color-mix(in srgb, var(--amber) 16%, var(--bg-elev));
border-bottom: 1px solid var(--amber);
}
.server-warn-crit {
color: var(--red);
background: color-mix(in srgb, var(--red) 18%, var(--bg-elev));
border-bottom: 1px solid var(--red);
}
/* ─── stats table ─────────────────────────────────────────────────
Shared right-aligned numeric table. Used by /stats.html (busiest
agents) and the dashboard SYST3M › C0NT41N3R L04D table — moved here
from dashboard.css when ST4TS became its own page. */
.hive-stats-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
margin-bottom: 8px;
}
.hive-stats-table th,
.hive-stats-table td {
border-bottom: 1px solid var(--border);
padding: 5px 8px;
text-align: right;
}
.hive-stats-table th:first-child,
.hive-stats-table td:first-child {
text-align: left;
}
.hive-stats-table th {
color: var(--muted);
font-weight: normal;
}
.hive-stats-table td.num {
font-variant-numeric: tabular-nums;
}