diff --git a/docs/trust-boundary/security.md b/docs/trust-boundary/security.md
index 14d1bfae..3181a3fe 100644
--- a/docs/trust-boundary/security.md
+++ b/docs/trust-boundary/security.md
@@ -247,7 +247,7 @@ bind-mount compatibility with user namespace UID mapping first.
`hive-c0re` runs as the unprivileged system user `hive-core`
(`/var/lib/hyperhive` owned by `hive-core:hive-core`). It can't
-directly invoke `nixos-container`, `journalctl -M`, or act on a system
+directly invoke `nixos-container` or act on a system
unit (`systemctl reload nginx`) — those require root. `hive-priv` fills
this gap.
@@ -275,7 +275,6 @@ known operations; there is no arbitrary command pass-through:
| `CreateContainer` / `UpdateContainer` | `nixos-container create/update --flake ` |
| `DestroyContainer` | `nixos-container destroy ` |
| `ListContainers` | `nixos-container list` |
-| `ReadContainerJournal` | `journalctl -M -n [filters...]` |
| `ReloadGatewayNginx` | `systemctl reload/start/reset-failed nginx` (host unit; the unit name is hard-coded, not a parameter) |
| `WriteNspawnFlags` | write `/etc/nixos-containers/.conf` (bind-mount list + network isolation vars) |
| `EnsureAgentSocketDir` | `mkdirat` `/run/hive-agent/` `0751 root:root` under an `O_NOFOLLOW` parent fd; leaves an existing directory alone, refuses anything else |
@@ -313,8 +312,8 @@ writes to only the paths `hive-priv` legitimately needs.
### Privilege boundary summary
-| Component | Runs as | Privilege needed for |
-| ---------------------------- | -------------- | ------------------------------------------------------------ |
-| `hive-c0re` | `hive-core` | broker, HTTP dashboard |
-| `hive-priv` | `root` | container lifecycle, journal reads, bind mounts, cred writes |
-| `hive-ag3nt` (per-container) | per-agent user | turn execution, MCP serving |
+| Component | Runs as | Privilege needed for |
+| ---------------------------- | -------------- | --------------------------------------------- |
+| `hive-c0re` | `hive-core` | broker, HTTP dashboard |
+| `hive-priv` | `root` | container lifecycle, bind mounts, cred writes |
+| `hive-ag3nt` (per-container) | per-agent user | turn execution, MCP serving |
diff --git a/docs/web-ui/README.md b/docs/web-ui/README.md
index 061308fa..a9ea42cd 100644
--- a/docs/web-ui/README.md
+++ b/docs/web-ui/README.md
@@ -28,8 +28,7 @@ of your time. It's a single page with exactly four tabs:
Everything else lives on its own page instead, all reachable from the
H0M3 hub: **Flow** (`/flow.html`, the raw live message stream across
-the whole swarm), **Logs** (`/logs.html`, per-agent and host
-journals), **Stats** (`/stats.html`, swarm-wide usage stats),
+the whole swarm), **Stats** (`/stats.html`, swarm-wide usage stats),
**Builds** (`/builds.html`, the rebuild queue and build history), and
**Core** (`/core.html`, tombstones and container resource use). Your local
browser preferences (notifications) live in the dashboard's Y3R C4LL
@@ -72,9 +71,10 @@ merging a config change or bumping a flake input.
takes effect until you hit **save all** at the bottom of the tab; a
save queues a rebuild for whichever agents actually changed.
-**Read an agent's logs.** The Logs page's AGENT tab pulls a live
-journald view for any agent + service; the per-agent `⋮` menu's
-**journal logs →** link jumps straight there, pre-filtered.
+**Read an agent's logs.** Logs aren't in the hive dashboard. Every
+hive ships its agents', daemons' and infra containers' journals to the
+swarm's VictoriaLogs; read them in Grafana's **Explore** — see
+[`swarm/services.md`](../swarm/services.md#logs-victorialogs).
**Set up a schedule.** Scheduled prompts are swarm-level: set them with
`swarmctl schedule` ([`swarm/schedules.md`](../swarm/schedules.md)).
diff --git a/docs/web-ui/css-vars.md b/docs/web-ui/css-vars.md
index 08c55847..4bd90e65 100644
--- a/docs/web-ui/css-vars.md
+++ b/docs/web-ui/css-vars.md
@@ -12,7 +12,7 @@ swap touches only the first:
what the app references and it **never changes on a swap**.
Both files live in `frontend/packages/shared/src/`. Per-page stylesheets
-(`common.css`, `dashboard.css`, `flow.css`, `logs.css`, `agent.css`)
+(`common.css`, `dashboard.css`, `flow.css`, `agent.css`)
reference the **semantic** names and must **not** redeclare them or reach
for the raw `--baseNN` slots directly. (`base.css` holds only the shared
`body` typography — it references the palette but no longer defines it.)
diff --git a/docs/web-ui/dashboard.md b/docs/web-ui/dashboard.md
index 32381ec4..07f2e4f9 100644
--- a/docs/web-ui/dashboard.md
+++ b/docs/web-ui/dashboard.md
@@ -12,7 +12,7 @@ hive-c0re serves the dashboard at `/dashboard.html` (with the home page at `/`).
It has a fixed chrome header at the top and a `` that shows exactly
one tab pane at a time. The URL hash (`#swarm`, `#call`,
`#permissions`, `#schedules`) drives which pane is
-active; hash changes don't reload the page. FL0W, L0GS, and the other
+active; hash changes don't reload the page. FL0W and the other
standalone pages are reachable from the H0M3 hub at `/`, not
from the dashboard tab strip.
@@ -21,7 +21,7 @@ from the dashboard tab strip.
at `/`. Every surface links back to the hub rather than to each other.
- **Tab strip**: `◆ SW4RM ◆`, `◆ Y3R C4LL ◆`, `◆ P3RM1SS10NS ◆`,
`◆ SCH3DUL3S ◆`. In-page tabs only — the SYST3M panels live on the
- standalone **C0R3** page (`/core.html`), and FL0W / L0GS / ST4TS
+ standalone **C0R3** page (`/core.html`), and FL0W / ST4TS
live on their own pages too, all reachable from the
H0M3 hub (not the tab strip). Count pills on SW4RM
(container count), Y3R C4LL (unread
@@ -29,7 +29,7 @@ from the dashboard tab strip.
- **Banner-thin** (`░▒▓█▓▒░ HYPERHIVE / HIVE-C0RE / WE ARE THE WIRED ░▒▓█▓▒░`)
— sits below the tab strip.
- **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,
H0M3, C0R3, BU1LDS, ST4TS), injected at the top
of `` by `renderServerWarnings` in `common.js`. Driven by
`state.server_warnings` — a list of `{ kind, level, message }` — and
@@ -53,9 +53,9 @@ from the dashboard tab strip.
cold-load and updates it live as broker `sent` events arrive; it's
preserved when `hive_name` / `swarm_name` later replace the raw title.
-The FL0W and L0GS pages use a slim header (a `← home` back-link + the
-page title) rather than the dashboard tab strip — they're standalone
-surfaces, not tab panes.
+The FL0W page uses a slim header (a `← home` back-link + the page
+title) rather than the dashboard tab strip — it's a standalone surface,
+not a tab pane.
## SW4RM tab
@@ -110,7 +110,7 @@ instead — it's agent-terminal-only, unrelated to this section.
Passive / rare-interaction state, reached from the **Core** tile on the
H0M3 hub (served at
-`/core.html`), with the same minimal chrome as `/logs.html`: a `← home`
+`/core.html`), with the same minimal chrome as `/builds.html`: a `← home`
back-link + a `createTabStrip` sub-tab nav (**K3PT ST4T3** default,
then **C0NT41N3R L04D**). The page is its own esbuild bundle (`core.js`)
that cold-loads `/api/state` and subscribes to `/api/dashboard/stream` for
@@ -400,7 +400,7 @@ tab activation and on each dashboard state load.
Hive-wide turn statistics, aggregated across every agent's
`hyperhive-turn-stats.sqlite` for the selected window. Not a dashboard
tab — a standalone page reached from the **Stats** tile on the H0M3
-hub, same minimal chrome as `/flow.html` / `/logs.html`. Distinct from
+hub, same minimal chrome as `/flow.html`. Distinct from
each agent's own `/stats` page (which carries the per-agent trend
charts): ST4TS is the swarm-level rollup.
@@ -488,7 +488,7 @@ re-renders the terminal row. The operator addresses the root agent as `@root`.
## H0M3 page (`/`)
The H0M3 hub is the primary landing page (served at `/` by default). A
-responsive grid of link tiles — Dashboard, Flow, Logs, Builds, Stats,
+responsive grid of link tiles — Dashboard, Flow, Builds, Stats,
Core, API — each pointing to their respective
surfaces, all unconditionally shown (no gating). The page is a pure
portal with no tab-bar or SSE subscriptions. Typography + colours inherit
@@ -496,45 +496,6 @@ from the shared theme (Catppuccin Mocha via `common.css` + `theme.css`).
`home.js` fills the swarm/hive identity line at the top. All dashboard
sub-pages include a `← Home` back-link for navigation.
-## L0GS page (`/logs.html`)
-
-A dedicated log-viewer page (not a tab pane — a separate HTML page),
-reachable from the Logs tile on the H0M3 hub. Minimal chrome:
-a `← home` back link and a three-item sub-tab strip. Tab
-routing is hash-based (`#agent`, `#infra`, `#system`); default is
-`#agent`. (Build log history lives on the BU1LDS page — see above.)
-
-**AGENT sub-tab** — per-container journald viewer. Two selects: agent
-name (populated from `GET /api/state`) and unit filter
-(`hive-agent.service` / `hive-mcp-http.service` /
-`hive-bash-daemon.service` / `hive-matrix-daemon.service` /
-`(full machine journal)`). Fetches
-`GET /api/journal/{name}?unit=&lines=500` on selection change
-or `↻ refresh`. Output rendered as a `
` block. A `?agent=`
-and/or `?unit=` URL param pre-selects the agent + unit on page
-load — the per-agent `⋮` menu's **journal logs →** entry uses this to
-deep-link directly to a specific agent's journal. A "fetched N ago"
-chip appears after the `↻ refresh` button following each successful
-fetch and ticks every 30 s.
-
-**INFRA sub-tab** — journald viewer for the three hive infrastructure
-containers (`hive-forge`, `hive-gateway`, `hive-matrix`), a
-fixed client-side list (`INFRA_NAMES` in `logs.js` — no dashboard API
-exposes just the name list). No unit filter (infra containers don't run
-the per-agent hive daemons) — always the full machine journal (or, for
-the gateway, the host journal filtered to its own unit). Fetches
-`GET /api/journal/{name}?lines=500`, same "fetched N ago" ticker as
-AGENT. A `?agent=` deep-link routes here instead of AGENT when
-the name is one of the three infra containers.
-
-**SYSTEM sub-tab** — host-side service logs. Unit selector
-(`hive-c0re.service` / `hive-priv.service`). Fetches
-`GET /api/journal-host?unit=&lines=500` on activation
-and on `↻ refresh`. Rendered as a `
` block. A "fetched N ago"
-chip ticks every 30 s. Available to the operator unconditionally (not
-capability-gated — the endpoint lives on the hive-c0re dashboard,
-behind the gateway).
-
## Container row
A full-height **square agent icon** (5em, capped) on the left. The
@@ -700,9 +661,6 @@ per-agent actions and navigation links. Contents:
Identical to the bulk actions on the selection bar but operate
on one agent without requiring a selection.
- `↻ R3BU1LD` — always available; queues a rebuild for this agent.
-- `journal logs →` — opens `/logs.html#agent?agent=` so the
- operator lands directly in the AGENT log tab pre-filtered to this
- container, without having to pick an agent from the dropdown.
- `DESTR0Y` / `PURG3` — destructive, each prompts for confirmation
via the themed dialog (see **Themed dialogs** below).
- `deployed: ↗` — present when the agent has a `deployed_sha`
@@ -884,8 +842,6 @@ below — some endpoints aren't in it yet.
stdout+stderr as `text/plain`. Used by the `↓ raw` / `↓ download
raw` links in BU1LDS. Works on both finished and in-progress
build logs.
-- `GET /api/journal/{name}?unit=&lines=` — journalctl viewer for
- a managed container; rendered in the side panel.
- `GET /static/marked.js` serves the vendored `marked` bundle used
for markdown previews.
- `GET /api/state-file?path=` — bounded
diff --git a/docs/web-ui/shape.md b/docs/web-ui/shape.md
index 42cd6499..91c60d6e 100644
--- a/docs/web-ui/shape.md
+++ b/docs/web-ui/shape.md
@@ -19,7 +19,7 @@
from `@hive/shared` (was `hive-fr0nt`); the dashboard ships one
CSS bundle per page (`colors.css` + `theme.css` + `common.css`,
loaded by every page, plus a page-specific bundle —
- `dashboard.css` / `flow.css` / `logs.css` / `home.css` /
+ `dashboard.css` / `flow.css` / `home.css` /
`stats.css` / `core.css` / `builds.css`);
`common.css` inlines `@hive/shared`'s
`base.css` + `terminal.css` + `tabs.css` + `chrome.css` +
@@ -247,7 +247,7 @@ values rather than per-row caches.
tagged with `data-restore-key=""` survives the
refresh. `snapshotOpenDetails()` walks managed sections before
render, `restoreOpenDetails()` re-applies after. Long-content
-drill-ins (file previews, diffs, journald logs) now open in the
+drill-ins (file previews, diffs) now open in the
**side panel** (see below) rather than expanding inline. The
dashboard's own answered-questions history list was the only
`` consumer and is gone
@@ -261,8 +261,8 @@ that needs it rather than ripped out along with their one caller.
swipes in from the right — a singleton `#side-panel` with a
titled header, a close button, and a scrollable body. Closes on
the button, selecting the backdrop, or `Escape`. `Panel.open(title,
-node)` swaps the body; the JS builders for file previews and
-journald logs all render into it. **The
+node)` swaps the body; the JS builder for file previews
+renders into it. **The
drawer width is drag-to-resize**: a thin 6px hit-strip on
the left edge captures pointer events, resizes the drawer in
real-time (pointer capture keeps dragging even if the cursor
diff --git a/frontend/packages/dashboard/build.mjs b/frontend/packages/dashboard/build.mjs
index eb71ce1f..44a84400 100644
--- a/frontend/packages/dashboard/build.mjs
+++ b/frontend/packages/dashboard/build.mjs
@@ -1,5 +1,5 @@
// esbuild build for @hive/dashboard: one JS+CSS bundle per page (H0M3 at
-// `/`, dashboard/flow/logs/core/builds at their own
+// `/`, dashboard/flow/core/builds at their own
// `.html`), each named after its own entry point below — see the
// `entryPoints`/`for` lists for the exact map, not repeated here to
// avoid this comment drifting out of sync with the real build steps.
@@ -35,7 +35,6 @@ await build({
entryPoints: [
src("tabs.js"),
src("flow.js"),
- src("logs.js"),
src("home.js"),
src("stats.js"),
src("core.js"),
@@ -101,7 +100,6 @@ for (const entry of [
"common.css",
"dashboard.css",
"flow.css",
- "logs.css",
"home.css",
"stats.css",
"core.css",
@@ -120,7 +118,6 @@ for (const html of [
"index.html",
"dashboard.html",
"flow.html",
- "logs.html",
"stats.html",
"core.html",
"builds.html",
diff --git a/frontend/packages/dashboard/src/agent-menu/hive-agent-menu.js b/frontend/packages/dashboard/src/agent-menu/hive-agent-menu.js
index 83991a73..afa4d261 100644
--- a/frontend/packages/dashboard/src/agent-menu/hive-agent-menu.js
+++ b/frontend/packages/dashboard/src/agent-menu/hive-agent-menu.js
@@ -140,24 +140,6 @@ class HiveAgentMenu extends HTMLElement {
const menuSep = () =>
el("li", { class: "agent-menu-sep", role: "separator" });
- // Navigation link item (opens in same tab by default).
- const menuLink = (label, href, title) => {
- const li = el("li", { role: "presentation" });
- const a = el(
- "a",
- {
- class: "agent-menu-item",
- href,
- role: "menuitem",
- title: title || "",
- },
- label,
- );
- a.addEventListener("click", close);
- li.append(a);
- return li;
- };
-
// Show only actions that are applicable in the current state.
if (c.running) {
dropdown.append(
@@ -209,15 +191,6 @@ class HiveAgentMenu extends HTMLElement {
action: "/api/rebuild/",
confirm: `rebuild ${c.name}? hot-reloads the container.`,
}),
- menuSep(),
- // Deep-link to the AGENT log tab pre-filtered to this container.
- // The ?agent= param is read by logs.js on load and pre-selects this
- // agent's journal without extra clicks.
- menuLink(
- "journal logs →",
- `/logs.html?agent=${encodeURIComponent(c.name)}#agent`,
- `view ${c.name} journal logs`,
- ),
);
dropdown.append(
diff --git a/frontend/packages/dashboard/src/builds.css b/frontend/packages/dashboard/src/builds.css
index c0fe2c09..a17106ae 100644
--- a/frontend/packages/dashboard/src/builds.css
+++ b/frontend/packages/dashboard/src/builds.css
@@ -1,14 +1,11 @@
/* ─── /builds.html — BU1LDS page ────────────────────────────────────
The build lifecycle hub: rebuild queue + live log, meta inputs, and
- build log history on one page. Carved out of /core.html (rebuild
- queue + meta inputs) and /logs.html (BUILD tab).
+ build log history on one page.
Imports system-sections.css for rebuild queue + meta inputs + live-log
- component styles, and logs.css for the build-logs-* component styles.
- Body-scoped `.logs-shell` rules in logs.css don't apply here
- (`.builds-shell` body); only the build-logs-* component rules are used. */
+ component styles; the build-logs-* rules for the BUILD L0GS list are
+ below. */
@import "./system-sections.css";
-@import "./logs.css";
@import "@hive/shared/jobq-graph.css";
body.builds-shell {
@@ -27,3 +24,116 @@ body.builds-shell {
.builds-pane[hidden] {
display: none;
}
+
+.logs-toolbar {
+ display: flex;
+ gap: 0.6em;
+ align-items: center;
+ margin-bottom: 0.9em;
+ flex-wrap: wrap;
+}
+
+/* ─── build-log list ──────────────────────────────────────────────
+ Scrollable list of log header rows; clicking a row expands full
+ stdout+stderr inline. */
+.build-logs-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ overflow-y: auto;
+ flex: 1 1 0;
+ min-height: 0;
+}
+.build-logs-item {
+ border-bottom: 1px solid var(--border);
+ padding: 0.15em 0;
+}
+.build-logs-row-btn {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.4em;
+ align-items: baseline;
+ width: 100%;
+ background: none;
+ border: none;
+ color: var(--fg);
+ font-family: inherit;
+ font-size: 0.85em;
+ text-align: left;
+ padding: 0.25em 0.4em;
+ cursor: pointer;
+ border-radius: 3px;
+}
+.build-logs-row-btn:hover {
+ background: var(--bg-elev);
+}
+.build-logs-kind {
+ font-weight: 600;
+}
+.build-logs-age {
+ font-size: 0.88em;
+}
+.build-logs-cmdline {
+ color: var(--muted);
+ font-size: 0.82em;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ max-width: 40em;
+}
+.build-logs-detail {
+ padding: 0 0.4em 0.4em;
+}
+.build-logs-output {
+ margin: 0.3em 0 0;
+ padding: 0.4em 0.6em;
+ background: var(--crust);
+ color: var(--fg);
+ border: 1px solid var(--purple-dim);
+ font-size: 0.82em;
+ line-height: 1.4;
+ white-space: pre-wrap;
+ word-break: break-word;
+ overflow-x: auto;
+ max-height: 30em;
+ overflow-y: auto;
+}
+.build-logs-dl {
+ color: var(--muted);
+ font-size: 0.8em;
+ text-decoration: none;
+ border: 1px solid var(--purple-dim);
+ padding: 0.1em 0.4em;
+ border-radius: 2px;
+ margin-top: 0.3em;
+ display: none;
+}
+.build-logs-dl:not([hidden]) {
+ display: inline-block;
+}
+.build-logs-dl:hover {
+ color: var(--fg);
+ border-color: var(--purple-dim);
+}
+
+.build-logs-live-badge {
+ margin-bottom: 0.4em;
+}
+
+@keyframes live-pulse {
+ 0%,
+ 100% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.45;
+ }
+}
+.build-logs-live-badge.badge-running {
+ animation: live-pulse 1.4s ease-in-out infinite;
+}
+
+.build-logs-runtime {
+ font-size: 0.85em;
+ color: var(--muted);
+}
diff --git a/frontend/packages/dashboard/src/builds.html b/frontend/packages/dashboard/src/builds.html
index 4fbf9281..90edfd96 100644
--- a/frontend/packages/dashboard/src/builds.html
+++ b/frontend/packages/dashboard/src/builds.html
@@ -12,9 +12,7 @@
@@ -74,7 +72,7 @@
-
diff --git a/frontend/packages/dashboard/src/builds.js b/frontend/packages/dashboard/src/builds.js
index 56cc5595..03e41e18 100644
--- a/frontend/packages/dashboard/src/builds.js
+++ b/frontend/packages/dashboard/src/builds.js
@@ -4,11 +4,6 @@
// - R3BU1LD QU3U3: pending + running rebuilds + live build log inline
// - M3T4 1NPUTS: nix flake input selector + meta-update trigger
// - BUILD L0GS: all-agents build log history (lazy-loaded on tab show)
-//
-// Carved out of /core.html (rebuild queue + meta inputs) and /logs.html
-// (BUILD tab) so the full build lifecycle is in one place. The section
-// renderers here are direct copies from core.js / logs.js with only the
-// deep-link URL and count-pill id adjusted.
import {
$,
diff --git a/frontend/packages/dashboard/src/common.css b/frontend/packages/dashboard/src/common.css
index 20840a9d..32699f14 100644
--- a/frontend/packages/dashboard/src/common.css
+++ b/frontend/packages/dashboard/src/common.css
@@ -10,8 +10,8 @@
@import "@hive/shared/pill.css";
/* ─── global typography ─────────────────────────────────────────────
- Element-level rules shared across all three pages (index, flow,
- logs). These must not reference page-specific chrome classes. */
+ Element-level rules shared across every page. These must not
+ reference page-specific chrome classes. */
h1,
h2 {
@@ -152,8 +152,7 @@ code {
}
/* ─── buttons ───────────────────────────────────────────────────────
- .btn base + semantic colour/size modifiers. Logs page uses
- .btn-restart for the ↻ refresh buttons; dashboard uses all variants. */
+ .btn base + semantic colour/size modifiers. */
.btn {
font-family: inherit;
font-weight: bold;
@@ -516,7 +515,7 @@ code {
}
/* ─── side panel ─────────────────────────────────────────────────
- Long content (file previews, diffs, journald, applied config) opens in
+ 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
@@ -605,8 +604,8 @@ hive-side-panel .md td {
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 / L0GS /
- ST4TS are full-bleed with their own `.-main` padding. */
+ in by adding the wrapper (dashboard.html, index.html); FL0W / ST4TS
+ are full-bleed with their own `.-main` padding. */
.page-content {
padding: 0 1.5em;
}
diff --git a/frontend/packages/dashboard/src/common.js b/frontend/packages/dashboard/src/common.js
index 5b592d91..d0b36673 100644
--- a/frontend/packages/dashboard/src/common.js
+++ b/frontend/packages/dashboard/src/common.js
@@ -292,12 +292,10 @@ export function openStream(url) {
return target;
}
-// Stream a build log into a
, returning the EventSource. Shared by the
-// L0GS page BUILD tab and the C0R3 rebuild-queue live-log panel so the
-// append / sticky-scroll / stderr-separator / reconnect-replay logic lives in
-// one place. Appends `stdout_append` then `stderr_append` (one `--- stderr ---`
-// separator) frames from `GET /api/build-logs/id/{id}/stream`; auto-scrolls to
-// the bottom unless the operator scrolled up; on the terminal `done` frame
+// Stream a build log into a
, returning the EventSource. Used by the
+// BU1LDS page's BUILD L0GS tab. Appends `stdout_append` then
+// `stderr_append` (one `--- stderr ---` separator) frames from
+// `GET /api/build-logs/id/{id}/stream`; auto-scrolls to the bottom unless the operator scrolled up; on the terminal `done` frame
// closes the stream and calls `onDone(status)`; on a non-transient error
// closes and calls `onError()`. The backend replays accumulated output on each
// (re)connect, so a CONNECTING reconnect resets the
to avoid doubling.
@@ -348,7 +346,7 @@ export function openBuildLogStream(id, pre, { onDone, onError } = {}) {
// ─── side panel ─────────────────────────────────────────────────────────
// Singleton drawer that swipes in from the right. Long content
-// (file previews, journald logs, applied config)
+// (file previews, applied config)
// opens here via `sidePanel.open(title, node)` instead of expanding
// inline. Body is swapped on each open; closing just slides out so
// the content stays visible through the transition.
@@ -654,7 +652,7 @@ export const NOTIF = (() => {
// ─── server warnings banner ──────────────────────────────────────────
// A generic top-of-page banner shown on every page (dashboard + the
-// stand-alone FL0W / L0GS / H0M3 pages). The backend decides what to
+// stand-alone FL0W / H0M3 pages). The backend decides what to
// warn about — `/api/state.server_warnings` is a list of
// `{ kind, level, message }` — and this just renders it, coloured by
// `level` (`warn` amber / `crit` red). Adding a new system warning is a
diff --git a/frontend/packages/dashboard/src/core.css b/frontend/packages/dashboard/src/core.css
index b08601e3..cb44415e 100644
--- a/frontend/packages/dashboard/src/core.css
+++ b/frontend/packages/dashboard/src/core.css
@@ -8,8 +8,8 @@ body.core-shell {
padding: 0;
}
-/* Fill the header row next to the ← home back-link, same as the logs
- sub-tab strip. */
+/* Fill the header row next to the ← home back-link, same as the
+ builds sub-tab strip. */
.core-tabbar {
flex: 1;
}
diff --git a/frontend/packages/dashboard/src/core.html b/frontend/packages/dashboard/src/core.html
index b74cc42c..37210ac8 100644
--- a/frontend/packages/dashboard/src/core.html
+++ b/frontend/packages/dashboard/src/core.html
@@ -14,7 +14,7 @@
-
+