@legioncodeinc/hive 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +262 -0
- package/dist/cli-commands.d.ts +41 -0
- package/dist/cli-commands.js +76 -0
- package/dist/cli-commands.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +46 -0
- package/dist/cli.js.map +1 -0
- package/dist/daemon/dashboard/app.js +118 -0
- package/dist/daemon/dashboard/host.d.ts +90 -0
- package/dist/daemon/dashboard/host.js +172 -0
- package/dist/daemon/dashboard/host.js.map +1 -0
- package/dist/daemon/dashboard/web-assets.d.ts +88 -0
- package/dist/daemon/dashboard/web-assets.js +195 -0
- package/dist/daemon/dashboard/web-assets.js.map +1 -0
- package/dist/daemon/fleet-status.d.ts +15 -0
- package/dist/daemon/fleet-status.js +56 -0
- package/dist/daemon/fleet-status.js.map +1 -0
- package/dist/daemon/gate.d.ts +55 -0
- package/dist/daemon/gate.js +128 -0
- package/dist/daemon/gate.js.map +1 -0
- package/dist/daemon/proxy.d.ts +38 -0
- package/dist/daemon/proxy.js +126 -0
- package/dist/daemon/proxy.js.map +1 -0
- package/dist/daemon/registry.d.ts +31 -0
- package/dist/daemon/registry.js +120 -0
- package/dist/daemon/registry.js.map +1 -0
- package/dist/daemon/server.d.ts +41 -0
- package/dist/daemon/server.js +126 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/setup-auth.d.ts +37 -0
- package/dist/daemon/setup-auth.js +51 -0
- package/dist/daemon/setup-auth.js.map +1 -0
- package/dist/daemon/telemetry-proxy.d.ts +47 -0
- package/dist/daemon/telemetry-proxy.js +63 -0
- package/dist/daemon/telemetry-proxy.js.map +1 -0
- package/dist/dashboard/contracts.d.ts +235 -0
- package/dist/dashboard/contracts.js +43 -0
- package/dist/dashboard/contracts.js.map +1 -0
- package/dist/dashboard/web/app.d.ts +44 -0
- package/dist/dashboard/web/app.js +179 -0
- package/dist/dashboard/web/app.js.map +1 -0
- package/dist/dashboard/web/boot-route.d.ts +23 -0
- package/dist/dashboard/web/boot-route.js +29 -0
- package/dist/dashboard/web/boot-route.js.map +1 -0
- package/dist/dashboard/web/build-graph-button.d.ts +46 -0
- package/dist/dashboard/web/build-graph-button.js +81 -0
- package/dist/dashboard/web/build-graph-button.js.map +1 -0
- package/dist/dashboard/web/buzzing-screen.d.ts +30 -0
- package/dist/dashboard/web/buzzing-screen.js +135 -0
- package/dist/dashboard/web/buzzing-screen.js.map +1 -0
- package/dist/dashboard/web/folder-picker.d.ts +54 -0
- package/dist/dashboard/web/folder-picker.js +125 -0
- package/dist/dashboard/web/folder-picker.js.map +1 -0
- package/dist/dashboard/web/graph-layout.d.ts +101 -0
- package/dist/dashboard/web/graph-layout.js +0 -0
- package/dist/dashboard/web/graph-layout.js.map +1 -0
- package/dist/dashboard/web/harness-strip.d.ts +38 -0
- package/dist/dashboard/web/harness-strip.js +65 -0
- package/dist/dashboard/web/harness-strip.js.map +1 -0
- package/dist/dashboard/web/health-rail.d.ts +26 -0
- package/dist/dashboard/web/health-rail.js +61 -0
- package/dist/dashboard/web/health-rail.js.map +1 -0
- package/dist/dashboard/web/main.d.ts +22 -0
- package/dist/dashboard/web/main.js +51 -0
- package/dist/dashboard/web/main.js.map +1 -0
- package/dist/dashboard/web/needs-project.d.ts +51 -0
- package/dist/dashboard/web/needs-project.js +69 -0
- package/dist/dashboard/web/needs-project.js.map +1 -0
- package/dist/dashboard/web/page-frame.d.ts +95 -0
- package/dist/dashboard/web/page-frame.js +98 -0
- package/dist/dashboard/web/page-frame.js.map +1 -0
- package/dist/dashboard/web/pages/coming-soon.d.ts +23 -0
- package/dist/dashboard/web/pages/coming-soon.js +19 -0
- package/dist/dashboard/web/pages/coming-soon.js.map +1 -0
- package/dist/dashboard/web/pages/dashboard.d.ts +32 -0
- package/dist/dashboard/web/pages/dashboard.js +205 -0
- package/dist/dashboard/web/pages/dashboard.js.map +1 -0
- package/dist/dashboard/web/pages/graph.d.ts +72 -0
- package/dist/dashboard/web/pages/graph.js +362 -0
- package/dist/dashboard/web/pages/graph.js.map +1 -0
- package/dist/dashboard/web/pages/harnesses.d.ts +65 -0
- package/dist/dashboard/web/pages/harnesses.js +210 -0
- package/dist/dashboard/web/pages/harnesses.js.map +1 -0
- package/dist/dashboard/web/pages/health.d.ts +22 -0
- package/dist/dashboard/web/pages/health.js +91 -0
- package/dist/dashboard/web/pages/health.js.map +1 -0
- package/dist/dashboard/web/pages/lifecycle-panel.d.ts +60 -0
- package/dist/dashboard/web/pages/lifecycle-panel.js +187 -0
- package/dist/dashboard/web/pages/lifecycle-panel.js.map +1 -0
- package/dist/dashboard/web/pages/logs.d.ts +55 -0
- package/dist/dashboard/web/pages/logs.js +311 -0
- package/dist/dashboard/web/pages/logs.js.map +1 -0
- package/dist/dashboard/web/pages/memories.d.ts +35 -0
- package/dist/dashboard/web/pages/memories.js +439 -0
- package/dist/dashboard/web/pages/memories.js.map +1 -0
- package/dist/dashboard/web/pages/projects.d.ts +38 -0
- package/dist/dashboard/web/pages/projects.js +325 -0
- package/dist/dashboard/web/pages/projects.js.map +1 -0
- package/dist/dashboard/web/pages/roi-chart.d.ts +52 -0
- package/dist/dashboard/web/pages/roi-chart.js +133 -0
- package/dist/dashboard/web/pages/roi-chart.js.map +1 -0
- package/dist/dashboard/web/pages/roi.d.ts +93 -0
- package/dist/dashboard/web/pages/roi.js +375 -0
- package/dist/dashboard/web/pages/roi.js.map +1 -0
- package/dist/dashboard/web/pages/settings.d.ts +103 -0
- package/dist/dashboard/web/pages/settings.js +420 -0
- package/dist/dashboard/web/pages/settings.js.map +1 -0
- package/dist/dashboard/web/pages/sync.d.ts +59 -0
- package/dist/dashboard/web/pages/sync.js +280 -0
- package/dist/dashboard/web/pages/sync.js.map +1 -0
- package/dist/dashboard/web/panels.d.ts +178 -0
- package/dist/dashboard/web/panels.js +471 -0
- package/dist/dashboard/web/panels.js.map +1 -0
- package/dist/dashboard/web/primitives.d.ts +80 -0
- package/dist/dashboard/web/primitives.js +208 -0
- package/dist/dashboard/web/primitives.js.map +1 -0
- package/dist/dashboard/web/readiness-splash.d.ts +39 -0
- package/dist/dashboard/web/readiness-splash.js +201 -0
- package/dist/dashboard/web/readiness-splash.js.map +1 -0
- package/dist/dashboard/web/registry.d.ts +96 -0
- package/dist/dashboard/web/registry.js +99 -0
- package/dist/dashboard/web/registry.js.map +1 -0
- package/dist/dashboard/web/router.d.ts +48 -0
- package/dist/dashboard/web/router.js +76 -0
- package/dist/dashboard/web/router.js.map +1 -0
- package/dist/dashboard/web/scope-context.d.ts +155 -0
- package/dist/dashboard/web/scope-context.js +266 -0
- package/dist/dashboard/web/scope-context.js.map +1 -0
- package/dist/dashboard/web/service-icons.d.ts +33 -0
- package/dist/dashboard/web/service-icons.js +80 -0
- package/dist/dashboard/web/service-icons.js.map +1 -0
- package/dist/dashboard/web/setup-gate.d.ts +116 -0
- package/dist/dashboard/web/setup-gate.js +272 -0
- package/dist/dashboard/web/setup-gate.js.map +1 -0
- package/dist/dashboard/web/sidebar.d.ts +63 -0
- package/dist/dashboard/web/sidebar.js +91 -0
- package/dist/dashboard/web/sidebar.js.map +1 -0
- package/dist/dashboard/web/use-fleet-telemetry.d.ts +111 -0
- package/dist/dashboard/web/use-fleet-telemetry.js +278 -0
- package/dist/dashboard/web/use-fleet-telemetry.js.map +1 -0
- package/dist/dashboard/web/wire.d.ts +1937 -0
- package/dist/dashboard/web/wire.js +1837 -0
- package/dist/dashboard/web/wire.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +11 -0
- package/dist/errors.js.map +1 -0
- package/dist/install/registry.d.ts +35 -0
- package/dist/install/registry.js +110 -0
- package/dist/install/registry.js.map +1 -0
- package/dist/lock.d.ts +10 -0
- package/dist/lock.js +87 -0
- package/dist/lock.js.map +1 -0
- package/dist/service/commands.d.ts +15 -0
- package/dist/service/commands.js +49 -0
- package/dist/service/commands.js.map +1 -0
- package/dist/service/index.d.ts +38 -0
- package/dist/service/index.js +174 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/platform.d.ts +37 -0
- package/dist/service/platform.js +67 -0
- package/dist/service/platform.js.map +1 -0
- package/dist/service/templates.d.ts +10 -0
- package/dist/service/templates.js +120 -0
- package/dist/service/templates.js.map +1 -0
- package/dist/shared/constants.d.ts +15 -0
- package/dist/shared/constants.js +19 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/daemon-routing.d.ts +11 -0
- package/dist/shared/daemon-routing.js +38 -0
- package/dist/shared/daemon-routing.js.map +1 -0
- package/dist/shared/fleet-readiness.d.ts +18 -0
- package/dist/shared/fleet-readiness.js +9 -0
- package/dist/shared/fleet-readiness.js.map +1 -0
- package/dist/shared/fleet-telemetry.d.ts +68 -0
- package/dist/shared/fleet-telemetry.js +61 -0
- package/dist/shared/fleet-telemetry.js.map +1 -0
- package/dist/shared/lifecycle-flags.d.ts +34 -0
- package/dist/shared/lifecycle-flags.js +39 -0
- package/dist/shared/lifecycle-flags.js.map +1 -0
- package/dist/shared/memory-types.d.ts +55 -0
- package/dist/shared/memory-types.js +75 -0
- package/dist/shared/memory-types.js.map +1 -0
- package/dist/shared/service-status.d.ts +82 -0
- package/dist/shared/service-status.js +97 -0
- package/dist/shared/service-status.js.map +1 -0
- package/dist/telemetry/emit.d.ts +197 -0
- package/dist/telemetry/emit.js +196 -0
- package/dist/telemetry/emit.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The HARNESSES page — PRD-039b (overview) + PRD-039c (per-harness detail).
|
|
4
|
+
*
|
|
5
|
+
* Mounted at the PRD-037 `#/harnesses` slot. The shell's `Outlet` resolves BOTH `#/harnesses` and a
|
|
6
|
+
* deep `#/harnesses/<name>` to THIS component (the registry prefix-match, 037c), so the page reads the
|
|
7
|
+
* active hash and renders:
|
|
8
|
+
* - `#/harnesses` → the OVERVIEW (039b): six per-harness KPI cards + an installed/active
|
|
9
|
+
* matrix, hydrated from `GET /api/diagnostics/harnesses` (039a) via the
|
|
10
|
+
* shared wire — no hardcoded list, uninstalled rendered honestly as greyed
|
|
11
|
+
* "not installed". Each card / matrix row drills into `#/harnesses/<name>`.
|
|
12
|
+
* - `#/harnesses/<name>` → the DETAIL (039c): the harness's summary header (from the SAME 039a
|
|
13
|
+
* status), its live activity filtered from the existing `/api/logs` stream
|
|
14
|
+
* (client-side per c-OQ-1 — no second log pipe), and capability panels
|
|
15
|
+
* DRIVEN BY the server-folded descriptor (c-OQ-2). A harness lacking a
|
|
16
|
+
* capability OMITS that panel (c-AC-3) — Cursor shows Agents, Claude Code
|
|
17
|
+
* does not.
|
|
18
|
+
*
|
|
19
|
+
* Every value is hydrated from the daemon's live endpoint through the shared wire (one source, D-3);
|
|
20
|
+
* every visual value is an existing `var(--…)` DS token + an existing primitive (`Kpi`/`Badge`/`Panel`).
|
|
21
|
+
* NO new dependency, NO CDN React, NO secret in the page/route/streamed lines (PRD-037 D-9 inherited).
|
|
22
|
+
*/
|
|
23
|
+
import React from "react";
|
|
24
|
+
import { Badge, Kpi } from "../primitives.js";
|
|
25
|
+
import { AGENT_DOT, AGENT_DOT_FALLBACK, LiveLog, Panel } from "../panels.js";
|
|
26
|
+
import { PageFrame, usePoll } from "../page-frame.js";
|
|
27
|
+
import { usePathRoute } from "../router.js";
|
|
28
|
+
import { formatLogLine } from "../wire.js";
|
|
29
|
+
/** How often the overview/detail re-hydrate the 039a status (ms) — light refresh, stopped on unmount. */
|
|
30
|
+
const STATUS_POLL_MS = 5000;
|
|
31
|
+
/** How often the detail page re-reads `/api/logs` for the filtered live stream (ms). */
|
|
32
|
+
const STREAM_POLL_MS = 2500;
|
|
33
|
+
/** How many recent log lines the detail live stream keeps. */
|
|
34
|
+
const MAX_STREAM_LINES = 12;
|
|
35
|
+
/** The harness-detail route prefix the page parses the `<name>` param out of. */
|
|
36
|
+
const DETAIL_PREFIX = "/harnesses/";
|
|
37
|
+
/** Parse the harness `<name>` from the active hash route, or `null` for the overview route. */
|
|
38
|
+
export function harnessNameFromRoute(route) {
|
|
39
|
+
if (!route.startsWith(DETAIL_PREFIX))
|
|
40
|
+
return null;
|
|
41
|
+
const name = route.slice(DETAIL_PREFIX.length).split("/")[0] ?? "";
|
|
42
|
+
return name === "" ? null : name;
|
|
43
|
+
}
|
|
44
|
+
/** The colour dot for a harness id (the shared `AGENT_DOT` language, extended to six — OQ-4). */
|
|
45
|
+
function HarnessDot({ name }) {
|
|
46
|
+
return _jsx("span", { style: { width: 9, height: 9, borderRadius: "50%", flex: "none", background: AGENT_DOT[name] ?? AGENT_DOT_FALLBACK } });
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Derive the at-a-glance status (b-AC-3): `not installed` when `!installed`; else `active` when the
|
|
50
|
+
* endpoint's `active` flag is set (mirrors 039a rather than re-deriving from the count, D-3); else
|
|
51
|
+
* `idle`. The endpoint already sets `active = turnsCaptured > 0`, so this stays consistent.
|
|
52
|
+
*/
|
|
53
|
+
export function uiStatus(h) {
|
|
54
|
+
if (!h.installed)
|
|
55
|
+
return "not installed";
|
|
56
|
+
return h.active ? "active" : "idle";
|
|
57
|
+
}
|
|
58
|
+
/** The Badge tone per UI status (honey/verified for active, neutral for idle, muted for uninstalled). */
|
|
59
|
+
const STATUS_TONE = {
|
|
60
|
+
active: "verified",
|
|
61
|
+
idle: "neutral",
|
|
62
|
+
"not installed": "neutral",
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Render a last-seen value as a relative "4m ago" string (b-AC-1), or "never" when null. `nowMs` is
|
|
66
|
+
* injectable so a test renders deterministically. Absolute time rides the title (hover) at the call site.
|
|
67
|
+
*/
|
|
68
|
+
export function relativeLastSeen(lastSeen, nowMs = Date.now()) {
|
|
69
|
+
if (lastSeen === null || lastSeen === "")
|
|
70
|
+
return "never";
|
|
71
|
+
const then = Date.parse(lastSeen);
|
|
72
|
+
if (!Number.isFinite(then))
|
|
73
|
+
return lastSeen; // un-parseable → show the raw value honestly
|
|
74
|
+
const deltaMs = Math.max(0, nowMs - then);
|
|
75
|
+
const sec = Math.floor(deltaMs / 1000);
|
|
76
|
+
if (sec < 60)
|
|
77
|
+
return `${sec}s ago`;
|
|
78
|
+
const min = Math.floor(sec / 60);
|
|
79
|
+
if (min < 60)
|
|
80
|
+
return `${min}m ago`;
|
|
81
|
+
const hr = Math.floor(min / 60);
|
|
82
|
+
if (hr < 24)
|
|
83
|
+
return `${hr}h ago`;
|
|
84
|
+
const day = Math.floor(hr / 24);
|
|
85
|
+
return `${day}d ago`;
|
|
86
|
+
}
|
|
87
|
+
/** A label for a UI status badge (the visible status text). */
|
|
88
|
+
const STATUS_LABEL = {
|
|
89
|
+
active: "active",
|
|
90
|
+
idle: "idle",
|
|
91
|
+
"not installed": "not installed",
|
|
92
|
+
};
|
|
93
|
+
// ── Overview (039b) ──────────────────────────────────────────────────────────
|
|
94
|
+
/** One per-harness KPI card (039b): name + dot, a turns Kpi, last-seen, a status badge. Click drills in. */
|
|
95
|
+
function HarnessCard({ h, onOpen }) {
|
|
96
|
+
const status = uiStatus(h);
|
|
97
|
+
const greyed = status === "not installed";
|
|
98
|
+
return (_jsxs("button", { type: "button", "data-testid": `harness-card-${h.name}`, "data-harness": h.name, onClick: () => onOpen(h.name), style: {
|
|
99
|
+
display: "flex",
|
|
100
|
+
flexDirection: "column",
|
|
101
|
+
gap: 12,
|
|
102
|
+
padding: 16,
|
|
103
|
+
textAlign: "left",
|
|
104
|
+
background: "var(--bg-surface)",
|
|
105
|
+
border: "1px solid var(--border-default)",
|
|
106
|
+
borderRadius: "var(--radius-lg)",
|
|
107
|
+
cursor: "pointer",
|
|
108
|
+
// Honest greying for an uninstalled harness (not omitted, not faked — b-AC-3).
|
|
109
|
+
opacity: greyed ? 0.6 : 1,
|
|
110
|
+
}, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 9 }, children: [_jsx(HarnessDot, { name: h.name }), _jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 14, fontWeight: 600, color: "var(--text-primary)" }, children: h.name }), _jsx("span", { style: { flex: 1 } }), _jsx(Badge, { tone: STATUS_TONE[status], mono: true, dot: true, children: STATUS_LABEL[status] })] }), _jsx(Kpi, { label: "turns captured", value: h.turnsCaptured.toLocaleString(), accent: h.active ? "verified" : "neutral", style: { padding: 0, background: "transparent", border: "none" } }), _jsxs("span", { title: h.lastSeen ?? "never", style: { fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--text-tertiary)" }, children: ["last seen ", relativeLastSeen(h.lastSeen)] })] }));
|
|
111
|
+
}
|
|
112
|
+
/** A ✓ / — cell for the installed/active matrix (b-AC-2). */
|
|
113
|
+
function Mark({ on }) {
|
|
114
|
+
return _jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 13, color: on ? "var(--verified)" : "var(--text-tertiary)" }, children: on ? "✓" : "—" });
|
|
115
|
+
}
|
|
116
|
+
/** The compact installed/active matrix (b-AC-2): one row per harness, click drills in. */
|
|
117
|
+
function HarnessMatrix({ harnesses, onOpen }) {
|
|
118
|
+
return (_jsx(Panel, { title: "Fleet", eyebrow: `${harnesses.length} harnesses`, children: _jsxs("div", { role: "table", "aria-label": "installed/active matrix", style: { display: "flex", flexDirection: "column" }, children: [_jsx("div", { role: "row", style: { display: "grid", gridTemplateColumns: "1.6fr 0.8fr 0.8fr 1.2fr 0.8fr", gap: 10, padding: "6px 6px", borderBottom: "1px solid var(--border-subtle)" }, children: ["harness", "installed", "active", "last seen", "turns"].map((c) => (_jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-tertiary)", textTransform: "uppercase", letterSpacing: "0.06em" }, children: c }, c))) }), harnesses.map((h) => (_jsxs("div", { role: "row", "data-testid": `harness-row-${h.name}`, "data-harness": h.name, onClick: () => onOpen(h.name), style: { display: "grid", gridTemplateColumns: "1.6fr 0.8fr 0.8fr 1.2fr 0.8fr", gap: 10, alignItems: "center", padding: "9px 6px", cursor: "pointer", borderTop: "1px solid var(--border-subtle)", opacity: h.installed ? 1 : 0.6 }, children: [_jsxs("span", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [_jsx(HarnessDot, { name: h.name }), _jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 13, color: "var(--text-primary)" }, children: h.name })] }), _jsx(Mark, { on: h.installed }), _jsx(Mark, { on: h.active }), _jsx("span", { title: h.lastSeen ?? "never", style: { fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--text-tertiary)" }, children: relativeLastSeen(h.lastSeen) }), _jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--text-secondary)" }, children: h.turnsCaptured.toLocaleString() })] }, h.name)))] }) }));
|
|
119
|
+
}
|
|
120
|
+
/** The overview body (039b): the KPI card grid + the matrix, hydrated from the live endpoint. */
|
|
121
|
+
function HarnessesOverview({ harnesses, onOpen }) {
|
|
122
|
+
return (_jsx(PageFrame, { title: "Harnesses", eyebrow: `${harnesses.length} · fleet`, children: harnesses.length === 0 ? (_jsx(Panel, { title: "Harnesses", children: _jsx("div", { style: { padding: "12px 4px", fontSize: 13, color: "var(--text-tertiary)" }, children: "No harness telemetry yet." }) })) : (_jsxs(_Fragment, { children: [_jsx("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(240px, 1fr))", gap: 12, marginBottom: 16 }, children: harnesses.map((h) => (_jsx(HarnessCard, { h: h, onOpen: onOpen }, h.name))) }), _jsx(HarnessMatrix, { harnesses: harnesses, onOpen: onOpen })] })) }));
|
|
123
|
+
}
|
|
124
|
+
// ── Detail (039c) ────────────────────────────────────────────────────────────
|
|
125
|
+
/** One labeled key/value row inside a capability panel. */
|
|
126
|
+
function CapRow({ label, children }) {
|
|
127
|
+
return (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12, padding: "8px 6px", borderTop: "1px solid var(--border-subtle)" }, children: [_jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--text-tertiary)", minWidth: 130 }, children: label }), _jsx("span", { style: { flex: 1 } }), _jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 13, color: "var(--text-primary)", textAlign: "right" }, children: children })] }));
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The capability panels for a harness (039c). The set is COMPUTED from the descriptor — a harness
|
|
131
|
+
* without a capability OMITS its panel (c-AC-3): Cursor renders the Agents panel, Claude Code does not.
|
|
132
|
+
* The Runtime panel is always present (every harness has a runtime path + host CLI + lifecycle events).
|
|
133
|
+
*/
|
|
134
|
+
function CapabilityPanels({ cap }) {
|
|
135
|
+
const hostCli = `${cap.hostCli.bin}${cap.hostCli.args.length > 0 ? " " + cap.hostCli.args.join(" ") : ""}`.trim();
|
|
136
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Panel, { title: "Runtime", eyebrow: cap.runtimePath || "—", style: { marginBottom: 16 }, children: [_jsx(CapRow, { label: "runtime path", children: cap.runtimePath || "—" }), _jsx(CapRow, { label: "context channel", children: cap.contextChannel || "—" }), _jsx(CapRow, { label: "host CLI", children: hostCli || "—" }), cap.hostCli.fallbackBin !== undefined && cap.hostCli.fallbackBin !== "" && (_jsx(CapRow, { label: "fallback CLI", children: cap.hostCli.fallbackBin })), _jsx(CapRow, { label: "lifecycle events", children: cap.lifecycleEvents.length > 0 ? cap.lifecycleEvents.join(", ") : "—" })] }), cap.agents !== undefined && (_jsx("div", { "data-testid": "cap-agents", style: { marginBottom: 16 }, children: _jsxs(Panel, { title: "Agents", eyebrow: "cursor-agent", children: [_jsx(CapRow, { label: "agent kind", children: cap.agents.kind }), _jsx(CapRow, { label: "binary", children: cap.agents.binary }), cap.agents.fallbackBin !== undefined && cap.agents.fallbackBin !== "" && (_jsx(CapRow, { label: "fallback", children: cap.agents.fallbackBin })), cap.workspaceRoots === true && _jsx(CapRow, { label: "workspace roots", children: "yes" })] }) })), cap.mcpRegistration === true && (_jsx("div", { "data-testid": "cap-mcp", style: { marginBottom: 16 }, children: _jsx(Panel, { title: "MCP", eyebrow: "registered", children: _jsx(CapRow, { label: "honeycomb tools", children: "honeycomb_search \u00B7 honeycomb_read \u00B7 honeycomb_index" }) }) })), cap.contractedTools === true && (_jsx("div", { "data-testid": "cap-contracted", style: { marginBottom: 16 }, children: _jsx(Panel, { title: "Contracted tools", eyebrow: "registered", children: _jsx(CapRow, { label: "tool registration", children: "contracted (no pre-tool hook)" }) }) })), cap.agentsMdContext === true && (_jsx("div", { "data-testid": "cap-agentsmd", style: { marginBottom: 16 }, children: _jsx(Panel, { title: "Context surface", eyebrow: "AGENTS.md", children: _jsx(CapRow, { label: "injection", children: "static AGENTS.md block" }) }) })), cap.userVisibleLogin === true && (_jsx("div", { "data-testid": "cap-login", style: { marginBottom: 16 }, children: _jsx(Panel, { title: "Context surface", eyebrow: "login line", children: _jsx(CapRow, { label: "injection", children: "user-visible login line" }) }) }))] }));
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Filter the `/api/logs` records to a harness's activity (c-OQ-1, client-side). The request-log
|
|
140
|
+
* record carries `method`/`path`/`status` (NO `agent` tag — logs/api.ts), so the only honest signal
|
|
141
|
+
* is the harness name appearing in the request PATH (e.g. a per-harness install/sync route). A record
|
|
142
|
+
* is kept iff its path mentions the harness; when none match, the live panel shows its waiting state —
|
|
143
|
+
* NEVER a fabricated line. The records carry no secret by construction, so the filtered lines inherit
|
|
144
|
+
* that guarantee (c-AC-2).
|
|
145
|
+
*/
|
|
146
|
+
export function filterRecordsForHarness(records, name) {
|
|
147
|
+
if (name === "")
|
|
148
|
+
return [];
|
|
149
|
+
const needle = name.toLowerCase();
|
|
150
|
+
return records.filter((r) => (r.path ?? "").toLowerCase().includes(needle));
|
|
151
|
+
}
|
|
152
|
+
/** The detail body (039c): the summary header, the capability panels, and the filtered live stream. */
|
|
153
|
+
function HarnessDetail({ name, status, lines, onBack, }) {
|
|
154
|
+
const back = (_jsx("button", { type: "button", onClick: onBack, style: { height: 28, padding: "0 12px", background: "transparent", border: "1px solid var(--border-default)", borderRadius: "var(--radius-md)", color: "var(--text-secondary)", fontFamily: "var(--font-mono)", fontSize: 12, cursor: "pointer" }, children: "\u2039 Harnesses" }));
|
|
155
|
+
// A harness id not in the live six (a stale/typo deep link) renders an honest "unknown" state
|
|
156
|
+
// rather than a blank — the registry resolves the route, but the data may not carry it.
|
|
157
|
+
if (status === null) {
|
|
158
|
+
return (_jsx(PageFrame, { title: name, eyebrow: "harness", right: back, children: _jsx(Panel, { title: "Unknown harness", children: _jsxs("div", { style: { padding: "12px 4px", fontSize: 13, color: "var(--text-tertiary)" }, children: ["No telemetry for ", _jsx("code", { style: { fontFamily: "var(--font-mono)", color: "var(--text-secondary)" }, children: name }), " \u2014 it is not one of the six canonical harnesses."] }) }) }));
|
|
159
|
+
}
|
|
160
|
+
const s = uiStatus(status);
|
|
161
|
+
return (_jsxs(PageFrame, { title: name, eyebrow: "harness", right: back, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10, marginBottom: 14 }, children: [_jsx(HarnessDot, { name: name }), _jsx(Badge, { tone: STATUS_TONE[s], mono: true, dot: true, children: STATUS_LABEL[s] }), _jsx("span", { style: { flex: 1 } }), _jsxs("span", { style: { fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--text-tertiary)" }, title: status.lastSeen ?? "never", children: ["last seen ", relativeLastSeen(status.lastSeen)] })] }), _jsxs("div", { className: "kpirow", style: { marginBottom: 18 }, children: [_jsx(Kpi, { label: "Turns", value: status.turnsCaptured.toLocaleString(), accent: status.active ? "verified" : "neutral" }), _jsx(Kpi, { label: "Installed", value: status.installed ? "yes" : "no", accent: status.installed ? "honey" : "neutral" }), _jsx(Kpi, { label: "Runtime", value: status.runtimePath || "—", accent: "pollinate" })] }), _jsx(CapabilityPanels, { cap: status.capabilities }), _jsx(LiveLog, { lines: lines })] }));
|
|
162
|
+
}
|
|
163
|
+
// ── The routed page (overview vs detail off the hash) ─────────────────────────
|
|
164
|
+
/**
|
|
165
|
+
* The Harnesses page (039b/039c). Hydrates the six `HarnessStatus`es from the shared wire (039a — the
|
|
166
|
+
* single backbone) and renders the OVERVIEW for `/harnesses` or the DETAIL for `/harnesses/<name>`,
|
|
167
|
+
* deciding off the active path route (PRD-003c). The detail page additionally polls the existing
|
|
168
|
+
* `/api/logs` records and filters them to the harness for its live stream (no second log pipe — D-4 / c-OQ-1).
|
|
169
|
+
*/
|
|
170
|
+
export function HarnessesPage({ wire }) {
|
|
171
|
+
const { route, navigate } = usePathRoute();
|
|
172
|
+
const detailName = harnessNameFromRoute(route);
|
|
173
|
+
const [harnesses, setHarnesses] = React.useState([]);
|
|
174
|
+
const [lines, setLines] = React.useState([]);
|
|
175
|
+
// Hydrate the six statuses (the backbone). A light poll keeps last-seen fresh; stops on unmount.
|
|
176
|
+
usePoll(async () => setHarnesses(await wire.harnesses()), STATUS_POLL_MS);
|
|
177
|
+
// On a detail route, poll /api/logs and filter the records to this harness (client-side — c-OQ-1).
|
|
178
|
+
// On the overview route `detailName` is null, so this poll is inert (it sets an empty feed).
|
|
179
|
+
usePoll(async () => {
|
|
180
|
+
if (detailName === null) {
|
|
181
|
+
setLines([]);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const records = await wire.logs(MAX_STREAM_LINES * 4);
|
|
185
|
+
const filtered = filterRecordsForHarness(records, detailName);
|
|
186
|
+
setLines(filtered.slice(-MAX_STREAM_LINES).reverse().map(formatLogLine));
|
|
187
|
+
}, STREAM_POLL_MS);
|
|
188
|
+
const onOpen = React.useCallback((name) => navigate(`/harnesses/${name}`), [navigate]);
|
|
189
|
+
const onBack = React.useCallback(() => navigate("/harnesses"), [navigate]);
|
|
190
|
+
if (detailName !== null) {
|
|
191
|
+
const status = harnesses.find((h) => h.name === detailName) ?? null;
|
|
192
|
+
return _jsx(HarnessDetail, { name: detailName, status: status, lines: lines, onBack: onBack });
|
|
193
|
+
}
|
|
194
|
+
return _jsx(HarnessesOverview, { harnesses: harnesses, onOpen: onOpen });
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* The 037c DYNAMIC registry resolver (parent D-6): given the live 039a harness list, compute the
|
|
198
|
+
* per-harness sub-items (`#/harnesses/<name>`) the dynamic group renders. Exported so the registry
|
|
199
|
+
* entry carries it; a narrow `unknown` → `HarnessStatusWire[]` narrowing keeps the registry the
|
|
200
|
+
* CONTRACT while THIS page owns the data shape (037c `DynamicGroup.resolve` is `(live: unknown)`).
|
|
201
|
+
*/
|
|
202
|
+
export function resolveHarnessSubItems(live) {
|
|
203
|
+
if (!Array.isArray(live))
|
|
204
|
+
return [];
|
|
205
|
+
return live
|
|
206
|
+
.map((h) => (h !== null && typeof h === "object" && "name" in h ? String(h.name) : ""))
|
|
207
|
+
.filter((name) => name !== "")
|
|
208
|
+
.map((name) => ({ route: `/harnesses/${name}`, label: name }));
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=harnesses.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harnesses.js","sourceRoot":"","sources":["../../../../src/dashboard/web/pages/harnesses.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `/health` PAGE — hive PRD-005b (per-service metrics + Deep Lake stats) and PRD-005c
|
|
3
|
+
* (live log tail with selectable verbosity). Registered at `/health` in `registry.tsx`; reachable
|
|
4
|
+
* via the health rail's "health details" link (PRD-005a) or direct navigation.
|
|
5
|
+
*
|
|
6
|
+
* `/health` shares the SAME literal path as hive's own machine-liveness probe (`GET /health`
|
|
7
|
+
* JSON, `server.ts`) — content negotiation on the SERVER (`accept: text/html` → this SPA page,
|
|
8
|
+
* anything else → the liveness JSON) keeps both working at the identical URL (see `gate.ts` /
|
|
9
|
+
* `server.ts` module docs). Client-side navigation (the sidebar link, `navigate()`) never touches
|
|
10
|
+
* the network at all, so this collision only ever matters for a full page load/refresh, which the
|
|
11
|
+
* server-side negotiation resolves.
|
|
12
|
+
*
|
|
13
|
+
* Fed entirely by the SHARED `useFleetTelemetry` hook (SSE-first, REST fail-soft) — no second
|
|
14
|
+
* fetch/poll loop is introduced here (hm-AC-8, lg-AC-1).
|
|
15
|
+
*/
|
|
16
|
+
import React from "react";
|
|
17
|
+
import type { PageProps } from "../page-frame.js";
|
|
18
|
+
/**
|
|
19
|
+
* The `/health` page (PRD-005b + PRD-005c). Renders per-service metrics + Deep Lake stats
|
|
20
|
+
* generically, plus a live, verbosity-filtered log tail — all from the ONE shared telemetry hook.
|
|
21
|
+
*/
|
|
22
|
+
export declare function HealthPage(_props: PageProps): React.JSX.Element;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The `/health` PAGE — hive PRD-005b (per-service metrics + Deep Lake stats) and PRD-005c
|
|
4
|
+
* (live log tail with selectable verbosity). Registered at `/health` in `registry.tsx`; reachable
|
|
5
|
+
* via the health rail's "health details" link (PRD-005a) or direct navigation.
|
|
6
|
+
*
|
|
7
|
+
* `/health` shares the SAME literal path as hive's own machine-liveness probe (`GET /health`
|
|
8
|
+
* JSON, `server.ts`) — content negotiation on the SERVER (`accept: text/html` → this SPA page,
|
|
9
|
+
* anything else → the liveness JSON) keeps both working at the identical URL (see `gate.ts` /
|
|
10
|
+
* `server.ts` module docs). Client-side navigation (the sidebar link, `navigate()`) never touches
|
|
11
|
+
* the network at all, so this collision only ever matters for a full page load/refresh, which the
|
|
12
|
+
* server-side negotiation resolves.
|
|
13
|
+
*
|
|
14
|
+
* Fed entirely by the SHARED `useFleetTelemetry` hook (SSE-first, REST fail-soft) — no second
|
|
15
|
+
* fetch/poll loop is introduced here (hm-AC-8, lg-AC-1).
|
|
16
|
+
*/
|
|
17
|
+
import React from "react";
|
|
18
|
+
import { Panel } from "../panels.js";
|
|
19
|
+
import { PageFrame } from "../page-frame.js";
|
|
20
|
+
import { SERVICE_STATE_COLOR, SERVICE_STATE_LABEL, ServiceStateIcon } from "../service-icons.js";
|
|
21
|
+
import { filterLogsByVerbosity, LOG_LEVELS, useFleetTelemetry, } from "../use-fleet-telemetry.js";
|
|
22
|
+
/** How many of the (already-bounded) filtered log lines the tail renders, newest first (a display cap, not a second buffer). */
|
|
23
|
+
const VISIBLE_LOG_LINES = 200;
|
|
24
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
25
|
+
// hm-AC-1..3: per-service metrics, rendered GENERICALLY (never one service's key names hardcoded).
|
|
26
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
27
|
+
/** Turn a camelCase metric key into a readable label (`filesProcessed` → `files processed`). */
|
|
28
|
+
function humanizeMetricKey(key) {
|
|
29
|
+
return key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase();
|
|
30
|
+
}
|
|
31
|
+
/** One service's metrics + Deep Lake block (hm-AC-1..3, hm-AC-5..7). Renders whatever keys are present. */
|
|
32
|
+
function ServiceHealthCard({ service }) {
|
|
33
|
+
const metricEntries = Object.entries(service.metrics);
|
|
34
|
+
return (_jsxs("div", { "data-testid": `health-service-${service.name}`, style: {
|
|
35
|
+
display: "flex",
|
|
36
|
+
flexDirection: "column",
|
|
37
|
+
gap: 10,
|
|
38
|
+
padding: "14px 16px",
|
|
39
|
+
borderRadius: "var(--radius-lg)",
|
|
40
|
+
border: "1px solid var(--border-default)",
|
|
41
|
+
background: "var(--bg-elevated)",
|
|
42
|
+
}, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [_jsx("span", { style: { color: SERVICE_STATE_COLOR[service.state], display: "inline-flex", flex: "none" }, children: _jsx(ServiceStateIcon, { state: service.state }) }), _jsx("span", { style: { fontWeight: 600, fontSize: "var(--text-base)", color: "var(--text-primary)" }, children: service.name }), _jsx("span", { "data-testid": `health-service-state-${service.name}`, style: { fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-tertiary)", textTransform: "lowercase" }, children: SERVICE_STATE_LABEL[service.state] })] }), metricEntries.length === 0 ? (_jsx("div", { "data-testid": `health-metrics-empty-${service.name}`, style: { fontSize: 12, color: "var(--text-tertiary)" }, children: "No metrics reported yet." })) : (_jsx("div", { "data-testid": `health-metrics-${service.name}`, style: { display: "grid", gridTemplateColumns: "1fr auto", rowGap: 4, columnGap: 12 }, children: metricEntries.map(([key, value]) => (_jsxs(React.Fragment, { children: [_jsx("span", { style: { fontSize: 12, color: "var(--text-secondary)", textTransform: "capitalize" }, children: humanizeMetricKey(key) }), _jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--text-primary)", textAlign: "right" }, children: value })] }, key))) })), _jsxs("div", { "data-testid": `health-deeplake-${service.name}`, style: { display: "flex", alignItems: "center", gap: 8, paddingTop: 8, borderTop: "1px solid var(--border-subtle)" }, children: [_jsx("span", { style: { fontSize: 12, color: "var(--text-secondary)" }, children: "Deep Lake" }), service.deeplake === null ? (_jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-tertiary)" }, children: "not reported" })) : (_jsxs(_Fragment, { children: [_jsx("span", { "data-testid": `health-deeplake-state-${service.name}`, style: {
|
|
43
|
+
fontFamily: "var(--font-mono)",
|
|
44
|
+
fontSize: 11,
|
|
45
|
+
color: service.deeplake.connected === true ? "var(--verified)" : "var(--severity-critical)",
|
|
46
|
+
}, children: service.deeplake.connected === true ? "connected" : service.deeplake.connected === false ? "unreachable" : "unknown" }), _jsx("span", { style: { flex: 1 } }), _jsxs("span", { style: { fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-tertiary)" }, children: ["last comm: ", service.deeplake.lastCommunicationAt ?? "never"] })] }))] })] }));
|
|
47
|
+
}
|
|
48
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
49
|
+
// PRD-005c: the live log tail + verbosity selector, over the SAME bounded buffer.
|
|
50
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
51
|
+
/** One rendered log line (newest first). */
|
|
52
|
+
function LogLine({ entry }) {
|
|
53
|
+
return (_jsxs("div", { style: { display: "grid", gridTemplateColumns: "auto auto 1fr", gap: 10, padding: "4px 0", fontFamily: "var(--font-mono)", fontSize: 12 }, children: [_jsx("span", { style: { color: "var(--text-tertiary)" }, children: (entry.ts || "").slice(11, 19) || entry.ts }), _jsx("span", { style: { color: "var(--text-secondary)", textTransform: "uppercase" }, children: entry.level }), _jsxs("span", { style: { color: "var(--text-primary)", whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: [_jsxs("span", { style: { color: "var(--text-tertiary)" }, children: ["[", entry.service, "]"] }), " ", entry.message] })] }));
|
|
54
|
+
}
|
|
55
|
+
/** The verbosity selector (lg-AC-4): a native `<select>` matching the DS token style. */
|
|
56
|
+
function VerbositySelect({ value, onChange }) {
|
|
57
|
+
return (_jsx("select", { "aria-label": "log verbosity", "data-testid": "log-verbosity-select", value: value, onChange: (e) => onChange(e.target.value), style: {
|
|
58
|
+
height: 30,
|
|
59
|
+
padding: "0 8px",
|
|
60
|
+
background: "var(--bg-surface)",
|
|
61
|
+
border: "1px solid var(--border-default)",
|
|
62
|
+
borderRadius: "var(--radius-md)",
|
|
63
|
+
color: "var(--text-primary)",
|
|
64
|
+
fontFamily: "var(--font-mono)",
|
|
65
|
+
fontSize: 12,
|
|
66
|
+
}, children: LOG_LEVELS.map((level) => (_jsxs("option", { value: level, children: [level, "+"] }, level))) }));
|
|
67
|
+
}
|
|
68
|
+
/** The live log tail panel (lg-AC-1..8): filtered by the selected verbosity, newest lines first, bounded display. */
|
|
69
|
+
function LiveLogTail({ logs }) {
|
|
70
|
+
const [level, setLevel] = React.useState("info");
|
|
71
|
+
const filtered = filterLogsByVerbosity(logs, level);
|
|
72
|
+
// Newest-first display over the already-bounded (ring-buffer) `logs` — never a second fetch.
|
|
73
|
+
const visible = filtered.slice(Math.max(0, filtered.length - VISIBLE_LOG_LINES)).reverse();
|
|
74
|
+
return (_jsx(Panel, { title: "Live logs", eyebrow: `${filtered.length} of ${logs.length} lines`, right: _jsx(VerbositySelect, { value: level, onChange: setLevel }), children: visible.length === 0 ? (_jsx("div", { "data-testid": "health-logs-empty", style: { padding: "12px 4px", fontSize: 13, color: "var(--text-tertiary)" }, children: "No log lines at this verbosity yet." })) : (_jsx("div", { "data-testid": "health-logs-list", style: { maxHeight: 360, overflowY: "auto" }, children: visible.map((entry, i) => (_jsx(LogLine, { entry: entry }, `${entry.ts}-${entry.service}-${i}`))) })) }));
|
|
75
|
+
}
|
|
76
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
77
|
+
// The routed page.
|
|
78
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
79
|
+
/** True when there is nothing at all to show (hm-AC-10): no service is known from any source yet. */
|
|
80
|
+
function isTelemetryUnavailable(view) {
|
|
81
|
+
return view.services.length === 0;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The `/health` page (PRD-005b + PRD-005c). Renders per-service metrics + Deep Lake stats
|
|
85
|
+
* generically, plus a live, verbosity-filtered log tail — all from the ONE shared telemetry hook.
|
|
86
|
+
*/
|
|
87
|
+
export function HealthPage(_props) {
|
|
88
|
+
const telemetry = useFleetTelemetry();
|
|
89
|
+
return (_jsx(PageFrame, { title: "Health", eyebrow: telemetry.source === "sse" ? "live" : telemetry.source === "rest" ? "fallback" : "unavailable", children: _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: [isTelemetryUnavailable(telemetry) ? (_jsx(Panel, { title: "Fleet metrics", children: _jsx("div", { "data-testid": "health-telemetry-unavailable", style: { padding: "12px 4px", fontSize: 13, color: "var(--text-tertiary)" }, children: "Telemetry unavailable. Waiting for doctor to report the fleet." }) })) : (_jsx("div", { "data-testid": "health-service-grid", style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(260px, 1fr))", gap: 12 }, children: telemetry.services.map((service) => (_jsx(ServiceHealthCard, { service: service }, service.name))) })), _jsx(LiveLogTail, { logs: telemetry.logs })] }) }));
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../../../src/dashboard/web/pages/health.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRD-058d — the LIFECYCLE HEALTH panel on the Memories page (the operator surface for the four
|
|
3
|
+
* lifecycle engines: recency/activation 058a, conflicts 058b, stale-references 058c, calibration 058e).
|
|
4
|
+
*
|
|
5
|
+
* Renders, off the SHARED `wire` (never `createWireClient`), inside the existing Memories page:
|
|
6
|
+
* - a store-level HEALTH summary: the aggregate health badge `H`, a freshness read, the open-conflict
|
|
7
|
+
* count, the stale-ref count, and the calibration ECE (US-55d.2.1);
|
|
8
|
+
* - the conflict QUEUE with a per-conflict RESOLVE action that calls the 058b
|
|
9
|
+
* `POST /api/memories/conflicts/:id/resolve` endpoint and POLLS to convergence (US-55d.2.2 —
|
|
10
|
+
* never a single immediate read-back, the DeepLake eventual-consistency rule);
|
|
11
|
+
* - the stale-reference list + count (US-55d.2.1);
|
|
12
|
+
* - the calibration view: the ECE/Brier + a reliability diagram from `GET /api/memories/calibration`
|
|
13
|
+
* (the 058e introspection payload, US-55d.2.4).
|
|
14
|
+
*
|
|
15
|
+
* It REUSES the PRD-040 memories-page data-fetching (the same `wire`) and the PRD-029 degradation
|
|
16
|
+
* states (loading / empty / degraded). A term whose producing engine is OFF renders as INERT (the
|
|
17
|
+
* honest empty state), NOT as an error — calibration dormant shows "calibration dormant", an empty
|
|
18
|
+
* conflict queue shows "no open conflicts", and the health scalar degrades to the live terms (an
|
|
19
|
+
* install with every engine off reads `H = 1`, not a phantom demotion).
|
|
20
|
+
*
|
|
21
|
+
* Security: every value renders as ESCAPED React text (never `dangerouslySetInnerHTML`); no
|
|
22
|
+
* token/secret rides any list/badge/diagram line (the wire shapes carry none by construction). Every
|
|
23
|
+
* visual value is an existing `var(--…)` DS token.
|
|
24
|
+
*/
|
|
25
|
+
import React from "react";
|
|
26
|
+
import type { WireClient } from "../wire.js";
|
|
27
|
+
/** The health badge tone by band: ≥0.66 verified, ≥0.33 honey, else warning. Pure. */
|
|
28
|
+
export declare function healthTone(h: number): "verified" | "honey" | "warning";
|
|
29
|
+
/**
|
|
30
|
+
* Assemble the store-level health scalar `H = A · C · (1 − σ) · κ` for the BADGE (058d read-side
|
|
31
|
+
* projection). Inputs come from the already-emitted aggregates: `freshness` (A), the calibration
|
|
32
|
+
* `1 − ece` proxy for trust (C — when calibration is dormant, identity 1), the stale-ref fraction
|
|
33
|
+
* (σ), and the open-conflict presence as a soft κ proxy. Each absent/dormant term is its IDENTITY,
|
|
34
|
+
* so the badge degrades to the live terms. Pure; bounded `[0,1]`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function assembleStoreHealth(inputs: {
|
|
37
|
+
freshness?: number;
|
|
38
|
+
calibrationConfidence?: number;
|
|
39
|
+
staleness?: number;
|
|
40
|
+
kappa?: number;
|
|
41
|
+
}): number;
|
|
42
|
+
/**
|
|
43
|
+
* Render the freshness (`A`) stat value: the bounded score when a read-side activation/freshness
|
|
44
|
+
* aggregate is available, else the inert dash (the wire carries no per-store `A` today, so freshness
|
|
45
|
+
* is dormant, NOT calibrated confidence mislabeled). Kept as a small pure helper so the freshness term
|
|
46
|
+
* threads cleanly the day the wire surfaces an `A` aggregate. Pure.
|
|
47
|
+
*/
|
|
48
|
+
export declare function freshnessLabel(freshness: number | undefined): string;
|
|
49
|
+
/** Props for {@link LifecycleHealthPanel}. */
|
|
50
|
+
export interface LifecycleHealthPanelProps {
|
|
51
|
+
/** The shared wire (the page passes its injected `wire`). */
|
|
52
|
+
readonly wire: WireClient;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The Lifecycle HEALTH panel (058d). Hydrates the conflict queue, the stale-ref list, and the
|
|
56
|
+
* calibration introspection on mount; resolves a conflict through the 058b endpoint and POLLS the
|
|
57
|
+
* queue to convergence (the resolved conflict drops out of the `open` list). Every read degrades to
|
|
58
|
+
* an honest empty/inert state on failure (PRD-029), never a throw.
|
|
59
|
+
*/
|
|
60
|
+
export declare function LifecycleHealthPanel({ wire }: LifecycleHealthPanelProps): React.JSX.Element;
|