Move dashboard settings into Y3R C4LL tab, drop standalone S3TT1NGS page

mara (issue #3817): remove the home link + page, put the setting toggle into the Y3R C4LL tab. Deleted settings.html/.js/.css; the browser-notification toggle (the only content there) now renders as a ◆ PR3F3R3NC3S ◆ section under Y3R C4LL's approvals/inbox, wired the same way (NOTIF.bind()/NOTIF.show() in common.js — no behavior change, just a new mount point). Updated build.mjs's entry lists and every doc/comment that pointed at the old page.
This commit is contained in:
iris 2026-08-31 10:42:01 +02:00
commit b33bb7a3d3
14 changed files with 106 additions and 175 deletions

View file

@ -26,11 +26,12 @@ of your time. It's a single page with exactly four tabs:
Everything else lives on its own page instead, all reachable from the Everything else lives on its own page instead, all reachable from the
H0M3 hub: **Flow** (`/flow.html`, the raw live message stream across H0M3 hub: **Flow** (`/flow.html`, the raw live message stream across
the whole swarm), **Logs** (`/logs.html`, per-agent and host the whole swarm), **Logs** (`/logs.html`, per-agent and host
journals), **Stats** (`/stats.html`, swarm-wide usage stats), **Settings** journals), **Stats** (`/stats.html`, swarm-wide usage stats),
(`/settings.html`, your local browser preferences), **Builds** (`/builds.html`, the rebuild **Builds** (`/builds.html`, the rebuild queue and build history),
queue and build history), **Core** (`/core.html`, tombstones and **Core** (`/core.html`, tombstones and container resource use), and
container resource use), and **Credentials** (`/credentials.html`, **Credentials** (`/credentials.html`, provisioning matrix/GitHub/forge
provisioning matrix/GitHub/forge accounts per agent). accounts per agent). Your local browser preferences (notifications)
live in the dashboard's Y3R C4LL tab now, not a separate page.
Each agent also has its own page — a full terminal view of that Each agent also has its own page — a full terminal view of that
agent's session, reachable by clicking its name anywhere in the agent's session, reachable by clicking its name anywhere in the

View file

@ -7,7 +7,7 @@
The dashboard is served at `/dashboard.html` (with the home page at `/`). The dashboard is served at `/dashboard.html` (with the home page at `/`).
It has a fixed chrome header at the top and a `<main>` that shows exactly It has a fixed chrome header at the top and a `<main>` that shows exactly
one tab pane at a time. The URL hash (`#swarm`, `#call`, `#system`, one tab pane at a time. The URL hash (`#swarm`, `#call`, `#system`,
`#permissions`, `#schedules`, `#settings`) drives which pane is `#permissions`, `#schedules`) drives which pane is
active; hash changes don't reload the page. FL0W, L0GS, and the optional active; hash changes don't reload the page. FL0W, L0GS, and the optional
M4TR1X client are separate pages reachable from the H0M3 hub at `/`, not M4TR1X client are separate pages reachable from the H0M3 hub at `/`, not
from the dashboard tab strip. from the dashboard tab strip.
@ -18,16 +18,15 @@ from the dashboard tab strip.
- **Tab strip**: `◆ SW4RM ◆`, `◆ Y3R C4LL ◆`, `◆ P3RM1SS10NS ◆`, - **Tab strip**: `◆ SW4RM ◆`, `◆ Y3R C4LL ◆`, `◆ P3RM1SS10NS ◆`,
`◆ SCH3DUL3S ◆`. In-page tabs only — the SYST3M panels moved to the `◆ SCH3DUL3S ◆`. In-page tabs only — the SYST3M panels moved to the
standalone **C0R3** page (`/core.html`), and FL0W / L0GS / ST4TS / standalone **C0R3** page (`/core.html`), and FL0W / L0GS / ST4TS /
S3TT1NGS / M4TR1X live on their own pages too, all reachable from the M4TR1X live on their own pages too, all reachable from the
H0M3 hub (not the tab strip). Count pills on SW4RM H0M3 hub (not the tab strip). Count pills on SW4RM
(container count), Y3R C4LL (pending approvals + unread (container count), Y3R C4LL (pending approvals + unread
operator messages), and SCH3DUL3S (active schedules); S3TT1NGS has no operator messages), and SCH3DUL3S (active schedules).
count.
- **Banner-thin** (`░▒▓█▓▒░ HYPERHIVE / HIVE-C0RE / WE ARE THE WIRED ░▒▓█▓▒░`) - **Banner-thin** (`░▒▓█▓▒░ HYPERHIVE / HIVE-C0RE / WE ARE THE WIRED ░▒▓█▓▒░`)
— sits below the tab strip. — sits below the tab strip.
- **Server-warnings banner** — a generic, sticky top-of-page strip shown - **Server-warnings banner** — a generic, sticky top-of-page strip shown
on **every** page (dashboard + every stand-alone page — FL0W, L0GS, on **every** page (dashboard + every stand-alone page — FL0W, L0GS,
H0M3, C0R3, BU1LDS, CR3D3NTIALS, ST4TS, S3TT1NGS), injected at the top H0M3, C0R3, BU1LDS, CR3D3NTIALS, ST4TS), injected at the top
of `<body>` by `renderServerWarnings` in `common.js`. Driven by of `<body>` by `renderServerWarnings` in `common.js`. Driven by
`state.server_warnings` — a list of `{ kind, level, message }` — and `state.server_warnings` — a list of `{ kind, level, message }` — and
coloured by `level` (`warn` amber / `crit` red). The backend owns the coloured by `level` (`warn` amber / `crit` red). The backend owns the
@ -100,6 +99,27 @@ messages are visible from any tab even while inactive. Backed by
`GET /api/operator-inbox``{ messages: [...] }` (id, from, body, at, `GET /api/operator-inbox``{ messages: [...] }` (id, from, body, at,
in_reply_to, file_refs). in_reply_to, file_refs).
**◆ PR3F3R3NC3S ◆** — operator-local preferences. State lives in the
browser's `localStorage` — preferences do NOT sync between devices and
do NOT survive a profile wipe. One section today (browser
notifications); future preferences land here as sibling `<h3>` blocks
in `dashboard.html`. Was its own S3TT1NGS page/tile (`/settings.html`)
until mara moved it in here — a standalone page for one toggle didn't
earn its own tile.
**◇ browser notifications** — `🔔 enable notifications` button when
permission ungranted; `🔕 mute / 🔔 unmute` toggle once granted
(mute silences the dispatch without revoking the OS-level
permission). On unsupported origins (non-secure context, or
browsers without the `Notification` API) the controls hide and a
single status line explains why. See `### Browser notifications`
below for the dispatch model + the three signals the dashboard
emits OS notifications on.
The "expand tool output panels" toggle lives on the per-agent page's
own settings popover (`SettingsMenu`, `@hive/shared/settings-menu.js`)
instead — it's agent-terminal-only, unrelated to this section.
## C0R3 page (`/core.html`) ## C0R3 page (`/core.html`)
Passive / rare-interaction state. No longer a dashboard tab — it's a Passive / rare-interaction state. No longer a dashboard tab — it's a
@ -595,32 +615,10 @@ the model id, longest match wins) mapping to
`{ input, output, cache_read, cache_write }` USD-per-million-token `{ input, output, cache_read, cache_write }` USD-per-million-token
prices. Models not covered fall back to hive-c0re's built-in estimate. prices. Models not covered fall back to hive-c0re's built-in estimate.
## S3TT1NGS tab The FL0W page does NOT host the PR3F3R3NC3S pane — it lives only on the
dashboard's Y3R C4LL tab (reach it via the FL0W page's `← home`
Operator-local preferences. State lives in the browser's
`localStorage` — preferences do NOT sync between devices and
do NOT survive a profile wipe. One section today (browser
notifications); future preferences land here as sibling `<h3>`
blocks in `settings.html`.
**◇ browser notifications** — `🔔 enable notifications` button when
permission ungranted; `🔕 mute / 🔔 unmute` toggle once granted
(mute silences the dispatch without revoking the OS-level
permission). On unsupported origins (non-secure context, or
browsers without the `Notification` API) the controls hide and a
single status line explains why. See `### Browser notifications`
below for the dispatch model + the three signals the dashboard
emits OS notifications on.
The "expand tool output panels" toggle used to live here too; it
moved into the per-agent page's own settings popover (`SettingsMenu`,
`@hive/shared/settings-menu.js`) since it's agent-terminal-only and
this tab is shared with swarm-ui — see that component's file comment.
The FL0W page does NOT host this pane — settings live only on the
dashboard's S3TT1NGS tab (reach it via the FL0W page's `← home`
back-link → Dashboard). Notifications still fire on the FL0W page when back-link → Dashboard). Notifications still fire on the FL0W page when
they're enabled here, because `NOTIF.show()` in they're enabled there, because `NOTIF.show()` in
`common.js` depends on `Notification.permission` + the `common.js` depends on `Notification.permission` + the
`hyperhive.notify.muted` localStorage key, not on the buttons `hyperhive.notify.muted` localStorage key, not on the buttons
existing in the page DOM. existing in the page DOM.
@ -1091,9 +1089,9 @@ Pure frontend (`Notification` API). Two signals trigger them:
- new pending approval (per id, delta on `/api/state`) - new pending approval (per id, delta on `/api/state`)
- new broker message sent `to: "operator"` (live via SSE) - new broker message sent `to: "operator"` (live via SSE)
The toggle controls live in the `S3TT1NGS` tab (`#settings`); see The toggle controls live in the Y3R C4LL tab's ◆ PR3F3R3NC3S ◆
that section above for the user-facing shape. Dispatch logic lives section; see that section above for the user-facing shape. Dispatch
in `common.js::NOTIF`. logic lives in `common.js::NOTIF`.
First `/api/state` after page load seeds "seen" sets without First `/api/state` after page load seeds "seen" sets without
firing — only items that arrive while the page is open count. firing — only items that arrive while the page is open count.

View file

@ -20,7 +20,7 @@
CSS bundle per page (`colors.css` + `theme.css` + `common.css`, CSS bundle per page (`colors.css` + `theme.css` + `common.css`,
loaded by every page, plus a page-specific bundle — loaded by every page, plus a page-specific bundle —
`dashboard.css` / `flow.css` / `logs.css` / `home.css` / `dashboard.css` / `flow.css` / `logs.css` / `home.css` /
`settings.css` / `stats.css` / `core.css` / `builds.css` / `stats.css` / `core.css` / `builds.css` /
`credentials.css`); `common.css` inlines `@hive/shared`'s `credentials.css`); `common.css` inlines `@hive/shared`'s
`base.css` + `terminal.css` + `tabs.css` + `chrome.css` + `base.css` + `terminal.css` + `tabs.css` + `chrome.css` +
`pill.css` via esbuild's `@import` resolution. `pill.css` via esbuild's `@import` resolution.

View file

@ -66,7 +66,7 @@ mkdirSync(staticDir(''), { recursive: true });
// follow-up once asset sizes warrant it). esbuild writes each entry // follow-up once asset sizes warrant it). esbuild writes each entry
// to `static/<name>.js` based on the entryPoint basename. // to `static/<name>.js` based on the entryPoint basename.
await build({ await build({
entryPoints: [src('tabs.js'), src('flow.js'), src('logs.js'), src('home.js'), src('settings.js'), src('stats.js'), src('core.js'), src('builds.js'), src('credentials.js')], entryPoints: [src('tabs.js'), src('flow.js'), src('logs.js'), src('home.js'), src('stats.js'), src('core.js'), src('builds.js'), src('credentials.js')],
outdir: staticDir(''), outdir: staticDir(''),
bundle: true, bundle: true,
format: 'esm', format: 'esm',
@ -122,7 +122,7 @@ await build({
// so a swap replaces only it) + theme.css (the semantic derivation // so a swap replaces only it) + theme.css (the semantic derivation
// layer) + common.css (shared typography, badges, buttons, inbox, side // layer) + common.css (shared typography, badges, buttons, inbox, side
// panel) plus its own page-specific bundle. // panel) plus its own page-specific bundle.
for (const entry of ['colors.css', 'theme.css', 'common.css', 'dashboard.css', 'flow.css', 'logs.css', 'home.css', 'settings.css', 'stats.css', 'core.css', 'builds.css', 'credentials.css']) { for (const entry of ['colors.css', 'theme.css', 'common.css', 'dashboard.css', 'flow.css', 'logs.css', 'home.css', 'stats.css', 'core.css', 'builds.css', 'credentials.css']) {
await build({ await build({
entryPoints: [src(entry)], entryPoints: [src(entry)],
outfile: staticDir(entry), outfile: staticDir(entry),
@ -132,7 +132,7 @@ for (const entry of ['colors.css', 'theme.css', 'common.css', 'dashboard.css', '
}); });
} }
for (const html of ['index.html', 'dashboard.html', 'flow.html', 'logs.html', 'settings.html', 'stats.html', 'core.html', 'builds.html', 'credentials.html']) { for (const html of ['index.html', 'dashboard.html', 'flow.html', 'logs.html', 'stats.html', 'core.html', 'builds.html', 'credentials.html']) {
copyFileSync(src(html), dist(html)); copyFileSync(src(html), dist(html));
} }

View file

@ -434,7 +434,7 @@ hive-side-panel .md td {
server-warnings banner, the footer) then spans edge-to-edge for free, server-warnings banner, the footer) then spans edge-to-edge for free,
with no negative-margin breakout hacks. Only matches on pages that opt with no negative-margin breakout hacks. Only matches on pages that opt
in by adding the wrapper (dashboard.html, index.html); FL0W / L0GS / in by adding the wrapper (dashboard.html, index.html); FL0W / L0GS /
ST4TS / S3TT1NGS are full-bleed with their own `.<page>-main` padding. */ ST4TS are full-bleed with their own `.<page>-main` padding. */
.page-content { padding: 0 1.5em; } .page-content { padding: 0 1.5em; }
/* sticky top region /* sticky top region

View file

@ -461,8 +461,32 @@ hive-agent-menu {
`JobqRollup` Preact component (`.jqr-*` classes, imported above) `JobqRollup` Preact component (`.jqr-*` classes, imported above)
mounted by swarm.js::initJobqRollup into #jobq-rollup-section. */ mounted by swarm.js::initJobqRollup into #jobq-rollup-section. */
/* .notif-row / .btn-notif moved to settings.css with the S3TT1NGS /* Browser-notification toggle row, now living in the Y3R C4LL tab's
page. */ PR3F3R3NC3S section (was its own S3TT1NGS page/tile; mara: a
standalone page for one toggle didn't earn its own tile). Buttons
wired by NOTIF.bind() in common.js. */
.notif-row {
display: flex;
gap: 0.5em;
align-items: center;
margin: 0.5em 0;
font-size: 0.85em;
}
.btn-notif {
font-family: inherit;
font-size: 0.85em;
background: transparent;
color: var(--cyan);
border: 1px solid var(--cyan);
padding: 0.2em 0.7em;
border-radius: 999px;
cursor: pointer;
text-shadow: 0 0 4px currentColor;
}
.btn-notif:hover {
background: color-mix(in srgb, var(--cyan) 10%, transparent);
box-shadow: 0 0 10px -2px currentColor;
}
.pending-state { .pending-state {
color: var(--amber); color: var(--amber);

View file

@ -72,9 +72,6 @@
into the log viewer (an agent's logs, a build entry's log) into the log viewer (an agent's logs, a build entry's log)
still live inside the relevant dashboard content. --> still live inside the relevant dashboard content. -->
<!-- S3TT1NGS lives on its own page now (`/settings.html`), reached
from the H0M3 hub — operator-local prefs don't need a slot in
the operational tab strip. -->
</nav> </nav>
</header> </header>
@ -129,6 +126,24 @@
<div id="approvals-section"> <div id="approvals-section">
<p class="meta">loading…</p> <p class="meta">loading…</p>
</div> </div>
<!-- Operator-local preferences (browser notifications). Was its own
S3TT1NGS page (`/settings.html`); mara moved it in here since a
standalone page for one toggle didn't earn its own tile. State
lives in the browser's localStorage — NOTIF.bind() (common.js)
wires the buttons, same dispatch NOTIF.show() already used for
approval/inbox notifications above. -->
<h2>◆ PR3F3R3NC3S ◆</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 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> </section>
<!-- SYST3M pane moved to /core.html (the standalone "C0R3" page): <!-- SYST3M pane moved to /core.html (the standalone "C0R3" page):
@ -210,12 +225,6 @@
tabs.js boots on this page the corresponding renderers tabs.js boots on this page the corresponding renderers
no-op silently (each guard is `if (!el) return`). --> no-op silently (each guard is `if (!el) return`). -->
<!-- S3TT1NGS: operator-local preferences (browser-notification
toggle) live on their own page now (`/settings.html`), reached
from the H0M3 hub. The notif buttons moved there verbatim;
`NOTIF.show()` on this page still fires (it reads the same
localStorage + browser permission the settings page sets). -->
</main> </main>
</div><!-- /.page-content --> </div><!-- /.page-content -->

View file

@ -76,14 +76,6 @@
<span class="home-tile-desc">hive-wide turn stats · cost · model mix</span> <span class="home-tile-desc">hive-wide turn stats · cost · model mix</span>
</a> </a>
<a class="home-tile" href="/settings.html">
<span class="home-tile-head">
<span class="home-tile-icon" aria-hidden="true"></span>
<span class="home-tile-label">Settings</span>
</span>
<span class="home-tile-desc">operator-local prefs · browser notifications</span>
</a>
<a class="home-tile" href="/core.html"> <a class="home-tile" href="/core.html">
<span class="home-tile-head"> <span class="home-tile-head">
<span class="home-tile-icon" aria-hidden="true"></span> <span class="home-tile-icon" aria-hidden="true"></span>

View file

@ -1,40 +0,0 @@
/* /settings.html operator-local preferences
Extracted from the dashboard S3TT1NGS tab. Same
minimal-chrome pattern as /flow.html and /logs.html: the back-link
header + title (.page-header / .page-back / .page-title) live in
@hive/shared/chrome.css; only the page body padding + the notif-toggle
row are page-specific and live here. */
body.settings-shell {
margin: 0;
padding: 0;
}
.settings-main {
padding: 1.2em 1.5em 2em;
}
/* Browser-notification toggle row (moved verbatim from dashboard.css
the buttons + status that NOTIF.bind() in common.js wires up). */
.notif-row {
display: flex;
gap: 0.5em;
align-items: center;
margin: 0.5em 0;
font-size: 0.85em;
}
.btn-notif {
font-family: inherit;
font-size: 0.85em;
background: transparent;
color: var(--cyan);
border: 1px solid var(--cyan);
padding: 0.2em 0.7em;
border-radius: 999px;
cursor: pointer;
text-shadow: 0 0 4px currentColor;
}
.btn-notif:hover {
background: color-mix(in srgb, var(--cyan) 10%, transparent);
box-shadow: 0 0 10px -2px currentColor;
}

View file

@ -1,39 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>hyperhive // S3TT1NGS</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="stylesheet" href="/static/colors.css">
<link rel="stylesheet" href="/static/theme.css">
<link rel="stylesheet" href="/static/common.css">
<link rel="stylesheet" href="/static/settings.css">
</head>
<body class="settings-shell">
<!-- Minimal chrome: back link + title. Same pattern as flow.html /
logs.html — no full dashboard tabbar. Back link points to the
H0M3 hub (served at /), not the dashboard. -->
<header class="page-header">
<a class="page-back" href="/">← home</a>
<span class="page-title">S3TT1NGS</span>
</header>
<main class="settings-main">
<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 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>
</main>
<script type="module" src="/static/settings.js" defer></script>
</body>
</html>

View file

@ -1,15 +0,0 @@
// /settings.html — operator-local preferences page.
//
// Extracted from the dashboard S3TT1NGS tab. The browser-notification
// toggle: NOTIF.bind() wires the enable / mute / unmute buttons and
// persists state to localStorage. The dashboard's NOTIF.show() calls
// (approvals) read that same localStorage state + the
// browser-level permission, so firing still works from the dashboard
// even though the toggle UI now lives on its own page.
//
// initServerWarnings() renders the shared top-of-page warnings banner,
// matching the other stand-alone pages (FL0W / L0GS / H0M3).
import { NOTIF, initServerWarnings } from './common.js';
initServerWarnings();
NOTIF.bind();

View file

@ -257,12 +257,14 @@ window.marked = marked;
// title reflect unread agent->operator messages immediately, before the // title reflect unread agent->operator messages immediately, before the
// operator opens the tab. Live updates arrive via the broker stream. // operator opens the tab. Live updates arrive via the broker stream.
refreshOperatorInbox(); refreshOperatorInbox();
// NOTIF.bind() (the enable/mute/unmute toggle UI) moved to /settings.html // NOTIF.bind() wires the enable/mute/unmute toggle buttons that now
// with the S3TT1NGS page. The dashboard keeps NOTIF.show() for approval // live in the Y3R C4LL tab's ◆ PR3F3R3NC3S ◆ section. NOTIF.show()
// notifications — it reads the browser permission + localStorage // (approval/inbox notifications) reads the same browser permission +
// mute flag the settings page sets, so no bind() is needed here. The // localStorage mute flag regardless of which page fires it — bind()
// side panel (<hive-side-panel>) wires its own internals in // only needs to run once, here, where the buttons live. The side
// connectedCallback — no bind() step needed either. // panel (<hive-side-panel>) wires its own internals in
// connectedCallback — no bind() step needed for it.
NOTIF.bind();
// ─── live updates: dashboard event stream ────────────────────────────── // ─── live updates: dashboard event stream ──────────────────────────────
// The dashboard subscribes to /dashboard/stream for live mutation // The dashboard subscribes to /dashboard/stream for live mutation
@ -349,9 +351,9 @@ window.marked = marked;
// ─── tab routing ─────────────────────────────────────────────────────── // ─── tab routing ───────────────────────────────────────────────────────
// Hash-based: `#swarm` / `#call` / `#system` / `#permissions` / // Hash-based: `#swarm` / `#call` / `#system` / `#permissions` /
// `#schedules` activate the matching pane on the dashboard. Empty // `#schedules` activate the matching pane on the dashboard. Empty
// hash defaults to SW4RM. FL0W, S3TT1NGS, and ST4TS are NOT tabs — // hash defaults to SW4RM. FL0W and ST4TS are NOT tabs —
// they're separate pages (`/flow.html`, `/settings.html`, // they're separate pages (`/flow.html`, `/stats.html`) reached from
// `/stats.html`) reached from the H0M3 hub. Tab routing only // the H0M3 hub. Tab routing only
// applies when the tab DOM is present (e.g. not on the flow page // applies when the tab DOM is present (e.g. not on the flow page
// itself, where these elements don't exist and the loop no-ops). // itself, where these elements don't exist and the loop no-ops).
// The shared hash-routed tab strip (@hive/shared/tabs.js) owns the // The shared hash-routed tab strip (@hive/shared/tabs.js) owns the

View file

@ -1,10 +1,9 @@
// Tiny browser-local (localStorage) preference helpers shared by the // Tiny browser-local (localStorage) preference helper, in `@hive/shared`
// dashboard's /settings.html and the per-agent page — both need the // so a future second consumer (e.g. swarm-ui's own terminal) gets the
// exact same key name to actually talk to each other via the browser's // exact same key name for free via the browser's shared per-origin
// shared per-origin storage (settings.html is where the operator sets // storage, rather than an independent copy that could drift.
// the preference; every per-agent page's terminal reads it), so the // `ExpandDetailsSetting` (the per-agent page's own settings popover) is
// get/set pair — and the key itself — live here once rather than as // the only writer today; `Row.tsx` is the only reader.
// independent copies in each package that could drift out of sync.
const EXPAND_DETAILS_KEY = 'hive-agent-expand-details'; const EXPAND_DETAILS_KEY = 'hive-agent-expand-details';

View file

@ -16,10 +16,10 @@
# $out/dashboard/ the hive-c0re dashboard assets (full layout in # $out/dashboard/ the hive-c0re dashboard assets (full layout in
# frontend/packages/dashboard/build.mjs): # frontend/packages/dashboard/build.mjs):
# index.html (H0M3 hub, served at /) dashboard.html (operator SPA, # index.html (H0M3 hub, served at /) dashboard.html (operator SPA,
# served at /dashboard.html) flow.html logs.html settings.html # served at /dashboard.html) flow.html logs.html
# stats.html favicon.svg # stats.html favicon.svg
# static/{home,tabs,flow,logs,settings,stats,stream-worker}.js{,.map} # static/{home,tabs,flow,logs,stats,stream-worker}.js{,.map}
# static/{colors,theme,common,home,dashboard,flow,logs,settings,stats}.css # static/{colors,theme,common,home,dashboard,flow,logs,stats}.css
# $out/agent/ the per-agent default UI (layered with # $out/agent/ the per-agent default UI (layered with
# hyperhive.frontend.extraFiles at activation time) # hyperhive.frontend.extraFiles at activation time)
# index.html stats.html screen.html # index.html stats.html screen.html