@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,272 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The `/login` route's GUIDED-SETUP content — PRD-050b (b-AC-3 / b-AC-6) · PRD-003b (l-AC-1
|
|
4
|
+
* through l-AC-8, relocating this view from a pre-mount React gate to its own path).
|
|
5
|
+
*
|
|
6
|
+
* `/login` is served by hive's server ONLY when the portal gate (`gate.ts`, PRD-003a) has
|
|
7
|
+
* already determined the operator is NOT logged in (or the operator landed here directly — `/login`
|
|
8
|
+
* is gate-exempt, l-AC-3). So this module no longer decides "pre-auth vs authenticated" itself —
|
|
9
|
+
* that decision is the server's. {@link LoginScreen} renders ONE of:
|
|
10
|
+
*
|
|
11
|
+
* - the plain first-time {@link GuidedSetup} screen — a clear "let's connect your account" panel
|
|
12
|
+
* fronted by the **"First time setup"** button (b-AC-6). The button BEGINS the on-page device
|
|
13
|
+
* flow (`POST /setup/login`, proxied per l-AC-1/l-AC-2) and shows the returned `user_code` +
|
|
14
|
+
* the verification link; the daemon keeps polling → mint → persist in the background.
|
|
15
|
+
* - {@link MigrationInterrupted} / {@link CoexistenceWarning} when `/setup/state` reports one of
|
|
16
|
+
* those states (unchanged from the prior pre-auth gate; only the addressing moved).
|
|
17
|
+
*
|
|
18
|
+
* ── The live transition is a POLL, then a hard navigation (l-AC-7 / l-AC-8) ──
|
|
19
|
+
* While on `/login` this screen polls `setupState()` on an interval, exactly like the retired
|
|
20
|
+
* pre-mount gate did. The instant the login flow writes the shared credential, the next poll
|
|
21
|
+
* reports `authenticated: true`; instead of swapping to a client-rendered `<Shell>` (the old
|
|
22
|
+
* behavior), this screen does a HARD navigation (`window.location.assign("/")`) so hive's
|
|
23
|
+
* server gate re-validates health+auth and serves the authoritative next screen. This keeps the
|
|
24
|
+
* gate — not this component — as the single source of truth for "where does an authenticated
|
|
25
|
+
* operator land" (ADR-0004), and correctly falls back to `/buzzing` instead of the dashboard if
|
|
26
|
+
* the fleet happens to be unhealthy at that exact moment.
|
|
27
|
+
*
|
|
28
|
+
* ── b-AC-6: the button is PRESENT in fresh-install, ABSENT once linked ───────
|
|
29
|
+
* The "First time setup" button renders ONLY in the pre-auth branch. Once `authenticated` flips
|
|
30
|
+
* true the whole {@link GuidedSetup} subtree (button included) unmounts as this screen navigates
|
|
31
|
+
* away — so the button is structurally absent in the linked state, not merely hidden.
|
|
32
|
+
*
|
|
33
|
+
* ── No token, no secret, no portal session (l-AC-5) ──────────────────────────
|
|
34
|
+
* This screen reads only `/setup/state` (install metadata) and `/setup/login` (user_code + URIs).
|
|
35
|
+
* NO token crosses either wire (the schemas have no token field by construction), and it creates,
|
|
36
|
+
* stores, or reads no portal-specific cookie or session — credential presence via `/setup/state` is
|
|
37
|
+
* the sole source of truth (ADR-0004's rejection of a portal session).
|
|
38
|
+
*/
|
|
39
|
+
import React from "react";
|
|
40
|
+
import { Button } from "./primitives.js";
|
|
41
|
+
import { createWireClient, FRESH_SETUP_STATE, } from "./wire.js";
|
|
42
|
+
/** How often the pre-auth screen polls `/setup/state` for the live transition (ms). */
|
|
43
|
+
export const SETUP_POLL_MS = 2500;
|
|
44
|
+
/** The migration sub-phases that mean "interrupted, not terminal" (d-AC-7 resume/rollback trigger). */
|
|
45
|
+
const NON_TERMINAL_MIGRATION_PHASES = new Set(["backup", "uninstall", "link"]);
|
|
46
|
+
/**
|
|
47
|
+
* True when the setup state shows an INTERRUPTED migration (a non-terminal `migration.phase`) — the
|
|
48
|
+
* dashboard must then present the resume/rollback affordance, NEVER a clean state (d-AC-7).
|
|
49
|
+
*/
|
|
50
|
+
export function isMigrationInterrupted(state) {
|
|
51
|
+
return state.migration !== undefined && NON_TERMINAL_MIGRATION_PHASES.has(state.migration.phase);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* True when the setup state shows a PRIOR Hivemind install that has NOT yet been migrated (d-AC-1) — the
|
|
55
|
+
* dashboard renders the coexistence-warning wizard rather than the plain first-time state. Keys off the
|
|
56
|
+
* derived `priorTool.hivemind === "present"` (or the raw `~/.hivemind` dir presence), and is suppressed
|
|
57
|
+
* once `priorTool.hivemind === "migrated"`.
|
|
58
|
+
*/
|
|
59
|
+
export function hasUnmigratedPriorHivemind(state) {
|
|
60
|
+
if (state.priorTool.hivemind === "migrated")
|
|
61
|
+
return false;
|
|
62
|
+
return state.priorTool.hivemind === "present" || state.credentials.hivemind;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The guided-setup PRE-AUTH screen (b-AC-6). A single centered panel: the brand mark, a short
|
|
66
|
+
* "connect your account" line, and the "First time setup" button that begins the on-page login. Once
|
|
67
|
+
* the login grant arrives the panel shows the `user_code` + the verification link (the daemon polls →
|
|
68
|
+
* persists in the background; the parent {@link LoginScreen} polls `/setup/state` and hard-navigates
|
|
69
|
+
* to the dashboard when the credential lands). The migration variant (a detected prior Hivemind) is 050d.
|
|
70
|
+
*/
|
|
71
|
+
export function GuidedSetup({ wire, assetBase, state, }) {
|
|
72
|
+
const [grant, setGrant] = React.useState(null);
|
|
73
|
+
const [busy, setBusy] = React.useState(false);
|
|
74
|
+
const [error, setError] = React.useState(false);
|
|
75
|
+
// A synchronous in-flight guard so a rapid double-click never fires two device flows.
|
|
76
|
+
const inFlightRef = React.useRef(false);
|
|
77
|
+
const beginSetup = React.useCallback(async () => {
|
|
78
|
+
if (inFlightRef.current)
|
|
79
|
+
return;
|
|
80
|
+
inFlightRef.current = true;
|
|
81
|
+
setBusy(true);
|
|
82
|
+
setError(false);
|
|
83
|
+
const result = await wire.setupLogin();
|
|
84
|
+
if (result === null) {
|
|
85
|
+
// The device flow could not begin (502 / network). Show an honest error; the user can
|
|
86
|
+
// retry the button or fall back to the `honeycomb login` CLI.
|
|
87
|
+
setError(true);
|
|
88
|
+
setBusy(false);
|
|
89
|
+
inFlightRef.current = false;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
setGrant(result);
|
|
93
|
+
// Leave `busy` true: the page now waits for the background poll (in LoginScreen) to flip to the
|
|
94
|
+
// authenticated dashboard once the credential lands. The button stays disabled meanwhile.
|
|
95
|
+
}, [wire]);
|
|
96
|
+
// A prior Hivemind install is a HINT for the copy (050d owns the migration path); 050b only
|
|
97
|
+
// surfaces it as a sub-line so the fresh-install vs has-prior-tool states read differently.
|
|
98
|
+
const hasPriorHivemind = state.priorTool.hivemind === "present" || state.credentials.hivemind;
|
|
99
|
+
return (_jsxs("div", { "data-testid": "guided-setup", style: {
|
|
100
|
+
display: "flex",
|
|
101
|
+
flexDirection: "column",
|
|
102
|
+
alignItems: "center",
|
|
103
|
+
justifyContent: "center",
|
|
104
|
+
gap: 18,
|
|
105
|
+
minHeight: "100vh",
|
|
106
|
+
padding: "28px",
|
|
107
|
+
background: "var(--bg-canvas)",
|
|
108
|
+
textAlign: "center",
|
|
109
|
+
}, children: [_jsx("img", { src: `${assetBase}/honeycomb-memory-cluster.svg`, width: 56, height: 56, alt: "" }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8, maxWidth: 460 }, children: [_jsx("h1", { style: { fontSize: "var(--text-xl)", fontWeight: 700, color: "var(--text-primary)", margin: 0, letterSpacing: "-0.02em" }, children: "Let\u2019s connect your account" }), _jsx("p", { style: { fontSize: "var(--text-sm)", color: "var(--text-secondary)", margin: 0, lineHeight: 1.5 }, children: hasPriorHivemind
|
|
110
|
+
? "We found a previous Hivemind setup. Link your account to bring your memory online."
|
|
111
|
+
: "Honeycomb keeps one shared memory for all your coding agents. Link your account to get started." })] }), grant === null ? (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "primary", size: "lg", onClick: () => void beginSetup(), disabled: busy, children: busy ? "Starting setup…" : "First time setup" }), error && (_jsxs("p", { "data-testid": "setup-error", style: { fontSize: "var(--text-sm)", color: "var(--severity-critical)", margin: 0 }, children: ["Could not start setup. Retry, or run ", _jsx("code", { children: "honeycomb login" }), " in your terminal."] }))] })) : (_jsxs("div", { "data-testid": "setup-grant", style: { display: "flex", flexDirection: "column", gap: 10, alignItems: "center" }, children: [_jsx("p", { style: { fontSize: "var(--text-sm)", color: "var(--text-secondary)", margin: 0 }, children: "Enter this code to finish linking:" }), _jsx("code", { style: { fontFamily: "var(--font-mono)", fontSize: "var(--text-lg)", color: "var(--honey)", letterSpacing: "0.08em" }, children: grant.user_code }), _jsx("a", { href: grant.verification_uri_complete ?? grant.verification_uri, target: "_blank", rel: "noreferrer", style: { fontSize: "var(--text-sm)", color: "var(--text-secondary)" }, children: "Open the verification page" }), _jsx("span", { style: { fontSize: "var(--text-xs)", color: "var(--text-tertiary)" }, children: "Waiting for you to finish in the browser\u2026" })] }))] }));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The COEXISTENCE-WARNING wizard — PRD-050d (d-AC-1 / d-AC-2 / d-AC-3 / d-AC-4). Renders instead of the
|
|
115
|
+
* plain first-time {@link GuidedSetup} when a prior, un-migrated Hivemind install is detected. It states
|
|
116
|
+
* — BEFORE any destructive action — that running Hivemind and Honeycomb together is UNSUPPORTED and what
|
|
117
|
+
* "Proceed with Honeycomb" does (back up + uninstall Hivemind, then reuse the shared login), then gates
|
|
118
|
+
* the migrate call behind an explicit CONFIRM step (d-AC-2).
|
|
119
|
+
*
|
|
120
|
+
* On "Proceed" it POSTs `migrateFromHivemind`: a `migrated` result lets the parent's `/setup/state` poll
|
|
121
|
+
* flip to the dashboard (no re-auth — the shared credential was adopted, d-AC-4); a `needsLogin` result
|
|
122
|
+
* hands off to the on-page device flow ({@link GuidedSetup}'s login button, the 050c `--ref mario` flow);
|
|
123
|
+
* an `ok:false` partial failure shows the plain-language message + the backup path (d-AC-5), never a stack.
|
|
124
|
+
*/
|
|
125
|
+
export function CoexistenceWarning({ wire, assetBase, onNeedsLogin, }) {
|
|
126
|
+
const [confirming, setConfirming] = React.useState(false);
|
|
127
|
+
const [busy, setBusy] = React.useState(false);
|
|
128
|
+
const [result, setResult] = React.useState(null);
|
|
129
|
+
const inFlightRef = React.useRef(false);
|
|
130
|
+
const proceed = React.useCallback(async () => {
|
|
131
|
+
if (inFlightRef.current)
|
|
132
|
+
return;
|
|
133
|
+
inFlightRef.current = true;
|
|
134
|
+
setBusy(true);
|
|
135
|
+
const r = await wire.migrateFromHivemind();
|
|
136
|
+
setResult(r);
|
|
137
|
+
if (r.ok && r.needsLogin === true) {
|
|
138
|
+
// Uninstall done; the shared credential was not adoptable → run the 050c device flow.
|
|
139
|
+
onNeedsLogin();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// `migrated` success: leave `busy` true — the parent LoginScreen poll hard-navigates once
|
|
143
|
+
// `/setup/state.authenticated` lands. A partial failure (`ok:false`) re-enables retry below.
|
|
144
|
+
if (!r.ok) {
|
|
145
|
+
setBusy(false);
|
|
146
|
+
inFlightRef.current = false;
|
|
147
|
+
}
|
|
148
|
+
}, [wire, onNeedsLogin]);
|
|
149
|
+
return (_jsxs("div", { "data-testid": "coexistence-warning", style: {
|
|
150
|
+
display: "flex",
|
|
151
|
+
flexDirection: "column",
|
|
152
|
+
alignItems: "center",
|
|
153
|
+
justifyContent: "center",
|
|
154
|
+
gap: 18,
|
|
155
|
+
minHeight: "100vh",
|
|
156
|
+
padding: "28px",
|
|
157
|
+
background: "var(--bg-canvas)",
|
|
158
|
+
textAlign: "center",
|
|
159
|
+
}, children: [_jsx("img", { src: `${assetBase}/honeycomb-memory-cluster.svg`, width: 56, height: 56, alt: "" }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 10, maxWidth: 500 }, children: [_jsx("h1", { style: { fontSize: "var(--text-xl)", fontWeight: 700, color: "var(--text-primary)", margin: 0, letterSpacing: "-0.02em" }, children: "We found an existing Hivemind setup" }), _jsxs("p", { style: { fontSize: "var(--text-sm)", color: "var(--text-secondary)", margin: 0, lineHeight: 1.5 }, children: ["Running Hivemind and Honeycomb on the same machine isn\u2019t supported \u2014 they share one memory and would collide. ", _jsx("strong", { children: "Proceed with Honeycomb" }), " will back up your Hivemind config, uninstall Hivemind, and reuse your existing DeepLake login (so you likely won\u2019t even need to sign in again)."] })] }), result !== null && result.ok === false ? (_jsxs("div", { "data-testid": "migration-error", style: { display: "flex", flexDirection: "column", gap: 10, alignItems: "center", maxWidth: 500 }, children: [_jsx("p", { style: { fontSize: "var(--text-sm)", color: "var(--severity-critical)", margin: 0 }, children: result.message }), result.backupPath !== undefined && (_jsxs("p", { style: { fontSize: "var(--text-xs)", color: "var(--text-tertiary)", margin: 0 }, children: ["Backup saved at ", _jsx("code", { style: { fontFamily: "var(--font-mono)" }, children: result.backupPath })] })), _jsx(Button, { variant: "primary", size: "lg", onClick: () => void proceed(), disabled: busy, children: busy ? "Retrying…" : "Retry" })] })) : !confirming ? (_jsx(Button, { variant: "primary", size: "lg", onClick: () => setConfirming(true), "data-testid": "proceed-button", children: "Proceed with Honeycomb" })) : (_jsxs("div", { "data-testid": "migration-confirm", style: { display: "flex", flexDirection: "column", gap: 10, alignItems: "center" }, children: [_jsx("p", { style: { fontSize: "var(--text-sm)", color: "var(--text-secondary)", margin: 0 }, children: "This backs up and removes your Hivemind setup. Continue?" }), _jsxs("div", { style: { display: "flex", gap: 10 }, children: [_jsx(Button, { variant: "secondary", size: "md", onClick: () => setConfirming(false), disabled: busy, children: "Cancel" }), _jsx(Button, { variant: "danger", size: "md", onClick: () => void proceed(), disabled: busy, "data-testid": "confirm-migrate-button", children: busy ? "Migrating…" : "Yes, proceed" })] })] }))] }));
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* The INTERRUPTED-MIGRATION surface — PRD-050d (d-AC-7). Rendered when `/setup/state` reports a
|
|
163
|
+
* NON-TERMINAL `migration.phase` (a daemon crash mid-migration). It NEVER presents the machine as cleanly
|
|
164
|
+
* migrated or cleanly reverted: it states the migration was interrupted and offers RESUME (re-run the
|
|
165
|
+
* idempotent migration) or ROLL BACK (restore the Hivemind backup). The backup path is shown for trust.
|
|
166
|
+
*/
|
|
167
|
+
export function MigrationInterrupted({ wire, assetBase, state, onNeedsLogin, }) {
|
|
168
|
+
const [busy, setBusy] = React.useState("");
|
|
169
|
+
const [message, setMessage] = React.useState(null);
|
|
170
|
+
const phase = state.migration?.phase ?? "backup";
|
|
171
|
+
const backupPath = state.migration?.backupPath;
|
|
172
|
+
const resume = React.useCallback(async () => {
|
|
173
|
+
setBusy("resume");
|
|
174
|
+
const r = await wire.migrateFromHivemind();
|
|
175
|
+
setMessage(r.message);
|
|
176
|
+
if (r.ok && r.needsLogin === true) {
|
|
177
|
+
onNeedsLogin();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// On success the parent poll flips to the dashboard; on failure leave the message + re-enable.
|
|
181
|
+
if (!r.ok)
|
|
182
|
+
setBusy("");
|
|
183
|
+
}, [wire, onNeedsLogin]);
|
|
184
|
+
const rollback = React.useCallback(async () => {
|
|
185
|
+
setBusy("rollback");
|
|
186
|
+
const r = await wire.rollbackMigration();
|
|
187
|
+
setMessage(r.message);
|
|
188
|
+
// After a rollback the parent poll re-reads `/setup/state` (now `rolled_back`, terminal) and the
|
|
189
|
+
// coexistence-warning re-renders from a clean restored state; re-enable the buttons regardless.
|
|
190
|
+
setBusy("");
|
|
191
|
+
}, [wire]);
|
|
192
|
+
return (_jsxs("div", { "data-testid": "migration-interrupted", style: {
|
|
193
|
+
display: "flex",
|
|
194
|
+
flexDirection: "column",
|
|
195
|
+
alignItems: "center",
|
|
196
|
+
justifyContent: "center",
|
|
197
|
+
gap: 18,
|
|
198
|
+
minHeight: "100vh",
|
|
199
|
+
padding: "28px",
|
|
200
|
+
background: "var(--bg-canvas)",
|
|
201
|
+
textAlign: "center",
|
|
202
|
+
}, children: [_jsx("img", { src: `${assetBase}/honeycomb-memory-cluster.svg`, width: 56, height: 56, alt: "" }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 10, maxWidth: 500 }, children: [_jsx("h1", { style: { fontSize: "var(--text-xl)", fontWeight: 700, color: "var(--text-primary)", margin: 0, letterSpacing: "-0.02em" }, children: "Your migration was interrupted" }), _jsxs("p", { style: { fontSize: "var(--text-sm)", color: "var(--text-secondary)", margin: 0, lineHeight: 1.5 }, children: ["A previous switch to Honeycomb didn\u2019t finish (it stopped at the ", _jsx("code", { children: phase }), " step). You can resume it, or roll back to restore your previous Hivemind setup."] }), backupPath !== undefined && (_jsxs("p", { style: { fontSize: "var(--text-xs)", color: "var(--text-tertiary)", margin: 0 }, children: ["Backup at ", _jsx("code", { style: { fontFamily: "var(--font-mono)" }, children: backupPath })] }))] }), _jsxs("div", { style: { display: "flex", gap: 10 }, children: [_jsx(Button, { variant: "primary", size: "md", onClick: () => void resume(), disabled: busy !== "", "data-testid": "resume-button", children: busy === "resume" ? "Resuming…" : "Resume" }), _jsx(Button, { variant: "secondary", size: "md", onClick: () => void rollback(), disabled: busy !== "", "data-testid": "rollback-button", children: busy === "rollback" ? "Rolling back…" : "Roll back" })] }), message !== null && (_jsx("p", { "data-testid": "migration-interrupted-message", style: { fontSize: "var(--text-sm)", color: "var(--text-secondary)", margin: 0 }, children: message }))] }));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* The `/login` route's top-level content (b-AC-3 / b-AC-6 / d-AC-1 / d-AC-7 / l-AC-1 / l-AC-7 /
|
|
206
|
+
* l-AC-8). Polls `/setup/state` and renders ONE of:
|
|
207
|
+
* - the {@link MigrationInterrupted} resume/rollback surface when a migration is mid-flight (d-AC-7);
|
|
208
|
+
* - the {@link CoexistenceWarning} wizard when a prior un-migrated Hivemind is detected (d-AC-1);
|
|
209
|
+
* - the plain first-time {@link GuidedSetup} otherwise (l-AC-1).
|
|
210
|
+
* Once `/setup/state.authenticated` flips true, this screen does a HARD navigation to `/` instead
|
|
211
|
+
* of rendering the dashboard itself (l-AC-7 / l-AC-8) — see the module doc for why that stays the
|
|
212
|
+
* server gate's decision, not this component's.
|
|
213
|
+
*
|
|
214
|
+
* The FIRST render shows the guided-setup state (the fresh-install-safe default) until the first
|
|
215
|
+
* poll resolves, so a slow first read never flashes a stale state.
|
|
216
|
+
*/
|
|
217
|
+
export function LoginScreen({ client, assetBase = "assets" } = {}) {
|
|
218
|
+
const wire = React.useMemo(() => client ?? createWireClient(), [client]);
|
|
219
|
+
const [state, setState] = React.useState(FRESH_SETUP_STATE);
|
|
220
|
+
// Once the migration's uninstall completes but needs the device flow (d-AC-4), force the login UI
|
|
221
|
+
// (GuidedSetup) even though a prior-Hivemind dir may still be reported — the user must finish linking.
|
|
222
|
+
const [forceLogin, setForceLogin] = React.useState(false);
|
|
223
|
+
// A synchronous guard so the navigation below fires exactly once even if this effect re-runs
|
|
224
|
+
// (e.g. React 18 StrictMode's double-invoke in development) before the browser actually leaves.
|
|
225
|
+
const navigatedRef = React.useRef(false);
|
|
226
|
+
React.useEffect(() => {
|
|
227
|
+
if (state.authenticated) {
|
|
228
|
+
// l-AC-7 / l-AC-8: auth flipped true. A HARD navigation (not a client-side component swap)
|
|
229
|
+
// so hive's server gate (gate.ts) re-validates health+auth for the new request and serves
|
|
230
|
+
// the authoritative next screen — `/` (the dashboard) if the fleet is still healthy, or
|
|
231
|
+
// `/buzzing` in the (rare) case it degraded in the interim. This is deliberately NOT a
|
|
232
|
+
// `usePathRoute().navigate` client-side swap: there is no mounted Shell here to swap into,
|
|
233
|
+
// and re-deriving "go to the dashboard" here would duplicate the gate's own decision.
|
|
234
|
+
if (!navigatedRef.current && typeof window !== "undefined") {
|
|
235
|
+
navigatedRef.current = true;
|
|
236
|
+
window.location.assign("/");
|
|
237
|
+
}
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
let alive = true;
|
|
241
|
+
const tick = async () => {
|
|
242
|
+
const next = await wire.setupState();
|
|
243
|
+
if (alive)
|
|
244
|
+
setState(next);
|
|
245
|
+
};
|
|
246
|
+
void tick();
|
|
247
|
+
// Keep polling while pre-auth so the transition is live; cleared on unmount and on the
|
|
248
|
+
// authenticated flip (the effect re-runs and early-returns above).
|
|
249
|
+
const id = setInterval(() => void tick(), SETUP_POLL_MS);
|
|
250
|
+
return () => {
|
|
251
|
+
alive = false;
|
|
252
|
+
clearInterval(id);
|
|
253
|
+
};
|
|
254
|
+
}, [wire, state.authenticated]);
|
|
255
|
+
// AUTHENTICATED: the navigation above is in flight. Render nothing further — the browser is
|
|
256
|
+
// about to leave this screen for the real dashboard request.
|
|
257
|
+
if (state.authenticated) {
|
|
258
|
+
return _jsx(_Fragment, {});
|
|
259
|
+
}
|
|
260
|
+
// d-AC-7: an interrupted migration ALWAYS wins — a half-migrated machine is never presented as a
|
|
261
|
+
// clean first-time/coexistence state. Resume/rollback until the marker reaches a terminal phase.
|
|
262
|
+
if (isMigrationInterrupted(state) && !forceLogin) {
|
|
263
|
+
return _jsx(MigrationInterrupted, { wire: wire, assetBase: assetBase, state: state, onNeedsLogin: () => setForceLogin(true) });
|
|
264
|
+
}
|
|
265
|
+
// d-AC-1: a prior un-migrated Hivemind renders the coexistence-warning wizard (not the plain
|
|
266
|
+
// first-time state) — unless the migration already handed off to the login flow (`forceLogin`).
|
|
267
|
+
if (hasUnmigratedPriorHivemind(state) && !forceLogin) {
|
|
268
|
+
return _jsx(CoexistenceWarning, { wire: wire, assetBase: assetBase, onNeedsLogin: () => setForceLogin(true) });
|
|
269
|
+
}
|
|
270
|
+
return _jsx(GuidedSetup, { wire: wire, assetBase: assetBase, state: state });
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=setup-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-gate.js","sourceRoot":"","sources":["../../../src/dashboard/web/setup-gate.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The left-hand NAVIGATION sidebar — PRD-037a (the brand chrome + nav).
|
|
3
|
+
*
|
|
4
|
+
* A pure presentational + nav component: it READS the route registry (037c) for its items and the
|
|
5
|
+
* active route (037b) for its highlight, and EMITS navigation intent via `onNavigate(route)`. It
|
|
6
|
+
* does NOT mutate `location.pathname` itself — that is PRD-003c's `navigate` (037a AC-4 keeps the
|
|
7
|
+
* sidebar a thin, testable pass-through). It introduces NO new design system: every visual value is
|
|
8
|
+
* an existing `var(--…)` token already served in `/dashboard/styles.css` (037a AC-7, D-3).
|
|
9
|
+
*
|
|
10
|
+
* Layout (D-3 / D-4):
|
|
11
|
+
* - Top: the honeycomb mark + `honeycomb` wordmark + the org/workspace mono sub-line — the exact
|
|
12
|
+
* type treatment the old `Header` used (mark 34px; wordmark 700/19/-0.03em; sub-line mono/11).
|
|
13
|
+
* - Middle: the seven nav items from the registry, each icon + label, in registry order. The item
|
|
14
|
+
* matching `activeRoute` is highlighted with the honey accent (`--honey` / `--honey-subtle` /
|
|
15
|
+
* `--honey-border`) — the same language `Badge tone="honey"` / `Button variant="primary"` speak —
|
|
16
|
+
* and EXACTLY one item is active at a time.
|
|
17
|
+
* - Footer: the relocated daemon-health pill (green `--verified` dot up / `--severity-critical`
|
|
18
|
+
* offline, mono `daemon :3850` / `offline`) + the collapse toggle (a ghost `Button`). The pill is
|
|
19
|
+
* visible on every route (D-4), and in the collapsed rail it shows the dot only.
|
|
20
|
+
*
|
|
21
|
+
* Collapsed/responsive (037a AC-6): the `collapsed` flag (or a narrow viewport via the host's
|
|
22
|
+
* `@media (max-width:900px)` rule) renders an icon-only rail; the active highlight + the health dot
|
|
23
|
+
* survive it, and each item's label rides a `title` hover.
|
|
24
|
+
*/
|
|
25
|
+
import React from "react";
|
|
26
|
+
import type { RouteEntry } from "./registry.js";
|
|
27
|
+
/** The expanded sidebar gutter width (px). */
|
|
28
|
+
export declare const SIDEBAR_WIDTH: 220;
|
|
29
|
+
/** The collapsed icon-rail width (px). */
|
|
30
|
+
export declare const SIDEBAR_RAIL_WIDTH: 56;
|
|
31
|
+
/** Props for {@link Sidebar}. */
|
|
32
|
+
export interface SidebarProps {
|
|
33
|
+
/** The registry nav entries (037c) — rendered as nav items in order. */
|
|
34
|
+
readonly entries: readonly RouteEntry[];
|
|
35
|
+
/** The active route (PRD-003c's `usePathRoute().route`) — drives the single active highlight. */
|
|
36
|
+
readonly activeRoute: string;
|
|
37
|
+
/** Navigation intent — called with an item's `route`; the SHELL maps it to 037b's `navigate`. */
|
|
38
|
+
readonly onNavigate: (route: string) => void;
|
|
39
|
+
/** Daemon liveness — drives the footer health pill (green up / critical offline). */
|
|
40
|
+
readonly daemonUp: boolean;
|
|
41
|
+
/** The org/workspace sub-line under the wordmark (mono, tertiary). */
|
|
42
|
+
readonly identity: string;
|
|
43
|
+
/** The base path the host serves the mark under (loopback, no secret). */
|
|
44
|
+
readonly assetBase: string;
|
|
45
|
+
/** Collapsed (icon-rail) state — icon-only nav, dot-only pill. */
|
|
46
|
+
readonly collapsed: boolean;
|
|
47
|
+
/** Toggle the collapsed state (the shell owns the boolean; the sidebar calls this). */
|
|
48
|
+
readonly onToggleCollapsed: () => void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Decide which entry is active for the current route (037a AC-3 — EXACTLY one). An exact match wins;
|
|
52
|
+
* otherwise a deep sub-route highlights its top-level parent (e.g. `/harnesses/x` lights Harnesses);
|
|
53
|
+
* otherwise the Dashboard (`/`) entry is active (the unknown→Dashboard fallback, mirroring the
|
|
54
|
+
* registry's `matchRoute`). Returns the active entry's `route` so the renderer compares by value.
|
|
55
|
+
*/
|
|
56
|
+
export declare function activeEntryRoute(entries: readonly RouteEntry[], activeRoute: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* The navigation sidebar (037a). Renders the brand chrome, the seven registry nav items with the
|
|
59
|
+
* single honey active highlight, and the footer (health pill + collapse toggle). Pure presentation:
|
|
60
|
+
* all state (active route, daemon up, collapsed) is owned by the shell and passed in; every effect is
|
|
61
|
+
* an `onNavigate` / `onToggleCollapsed` callback out.
|
|
62
|
+
*/
|
|
63
|
+
export declare function Sidebar({ entries, activeRoute, onNavigate, daemonUp, identity, assetBase, collapsed, onToggleCollapsed, }: SidebarProps): React.JSX.Element;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from "./primitives.js";
|
|
3
|
+
import { ScopeSwitcherSlot } from "./scope-context.js";
|
|
4
|
+
/** The expanded sidebar gutter width (px). */
|
|
5
|
+
export const SIDEBAR_WIDTH = 220;
|
|
6
|
+
/** The collapsed icon-rail width (px). */
|
|
7
|
+
export const SIDEBAR_RAIL_WIDTH = 56;
|
|
8
|
+
/**
|
|
9
|
+
* Decide which entry is active for the current route (037a AC-3 — EXACTLY one). An exact match wins;
|
|
10
|
+
* otherwise a deep sub-route highlights its top-level parent (e.g. `/harnesses/x` lights Harnesses);
|
|
11
|
+
* otherwise the Dashboard (`/`) entry is active (the unknown→Dashboard fallback, mirroring the
|
|
12
|
+
* registry's `matchRoute`). Returns the active entry's `route` so the renderer compares by value.
|
|
13
|
+
*/
|
|
14
|
+
export function activeEntryRoute(entries, activeRoute) {
|
|
15
|
+
const exact = entries.find((e) => e.route === activeRoute);
|
|
16
|
+
if (exact !== undefined)
|
|
17
|
+
return exact.route;
|
|
18
|
+
const parent = entries.find((e) => e.route !== "/" && activeRoute.startsWith(`${e.route}/`));
|
|
19
|
+
if (parent !== undefined)
|
|
20
|
+
return parent.route;
|
|
21
|
+
const dashboard = entries.find((e) => e.route === "/");
|
|
22
|
+
return dashboard?.route ?? (entries[0]?.route ?? "/");
|
|
23
|
+
}
|
|
24
|
+
/** One nav item row. Honey-accented when active; resting `--text-secondary` otherwise. */
|
|
25
|
+
function NavItem({ entry, active, collapsed, onNavigate, }) {
|
|
26
|
+
return (_jsxs("button", { type: "button",
|
|
27
|
+
// AC-4: the click is the ONLY navigation effect — it calls onNavigate(route) and nothing
|
|
28
|
+
// else (the sidebar never touches location.hash; the shell wires this to 037b's navigate).
|
|
29
|
+
onClick: () => onNavigate(entry.route), "aria-current": active ? "page" : undefined, title: collapsed ? entry.label : undefined, "data-route": entry.route, "data-active": active ? "true" : "false", style: {
|
|
30
|
+
display: "flex",
|
|
31
|
+
alignItems: "center",
|
|
32
|
+
gap: 10,
|
|
33
|
+
width: "100%",
|
|
34
|
+
height: 38,
|
|
35
|
+
padding: collapsed ? "0" : "0 12px",
|
|
36
|
+
justifyContent: collapsed ? "center" : "flex-start",
|
|
37
|
+
// Honey active highlight (D-3) — exactly the `Badge tone="honey"` language.
|
|
38
|
+
background: active ? "var(--honey-subtle)" : "transparent",
|
|
39
|
+
color: active ? "var(--honey)" : "var(--text-secondary)",
|
|
40
|
+
border: `1px solid ${active ? "var(--honey-border)" : "transparent"}`,
|
|
41
|
+
borderRadius: "var(--radius-md)",
|
|
42
|
+
fontFamily: "var(--font-mono)",
|
|
43
|
+
fontSize: 13,
|
|
44
|
+
fontWeight: 600,
|
|
45
|
+
letterSpacing: "0.01em",
|
|
46
|
+
cursor: "pointer",
|
|
47
|
+
whiteSpace: "nowrap",
|
|
48
|
+
transition: "background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out)",
|
|
49
|
+
}, children: [_jsx("span", { style: { display: "inline-flex", flex: "none" }, children: entry.icon }), !collapsed && _jsx("span", { children: entry.label })] }));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The daemon-health pill, relocated into the sidebar footer (D-4). KEEPS the exact contract from the
|
|
53
|
+
* old `Header`: a green `--verified` dot when up, `--severity-critical` when offline, mono
|
|
54
|
+
* `daemon :3850` / `offline` label, on `--bg-elevated` with a `--border-default` border. Renders
|
|
55
|
+
* subsystem STATE only — NO token/secret (D-9). In the collapsed rail it shows the dot alone.
|
|
56
|
+
*/
|
|
57
|
+
function HealthPill({ daemonUp, collapsed }) {
|
|
58
|
+
return (_jsxs("div", { title: "daemon health", "data-testid": "daemon-health-pill", style: {
|
|
59
|
+
display: "flex",
|
|
60
|
+
alignItems: "center",
|
|
61
|
+
gap: 8,
|
|
62
|
+
height: 36,
|
|
63
|
+
padding: collapsed ? "0" : "0 12px",
|
|
64
|
+
justifyContent: collapsed ? "center" : "flex-start",
|
|
65
|
+
background: "var(--bg-elevated)",
|
|
66
|
+
border: "1px solid var(--border-default)",
|
|
67
|
+
borderRadius: "var(--radius-md)",
|
|
68
|
+
}, children: [_jsx("span", { style: { width: 8, height: 8, borderRadius: "50%", flex: "none", background: daemonUp ? "var(--verified)" : "var(--severity-critical)" } }), !collapsed && _jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--text-secondary)" }, children: daemonUp ? "daemon :3850" : "offline" })] }));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The navigation sidebar (037a). Renders the brand chrome, the seven registry nav items with the
|
|
72
|
+
* single honey active highlight, and the footer (health pill + collapse toggle). Pure presentation:
|
|
73
|
+
* all state (active route, daemon up, collapsed) is owned by the shell and passed in; every effect is
|
|
74
|
+
* an `onNavigate` / `onToggleCollapsed` callback out.
|
|
75
|
+
*/
|
|
76
|
+
export function Sidebar({ entries, activeRoute, onNavigate, daemonUp, identity, assetBase, collapsed, onToggleCollapsed, }) {
|
|
77
|
+
const activeRoot = activeEntryRoute(entries, activeRoute);
|
|
78
|
+
return (_jsxs("nav", { "aria-label": "Dashboard navigation", "data-collapsed": collapsed ? "true" : "false", style: {
|
|
79
|
+
display: "flex",
|
|
80
|
+
flexDirection: "column",
|
|
81
|
+
gap: 18,
|
|
82
|
+
width: collapsed ? SIDEBAR_RAIL_WIDTH : SIDEBAR_WIDTH,
|
|
83
|
+
flex: "none",
|
|
84
|
+
minHeight: "100vh",
|
|
85
|
+
boxSizing: "border-box",
|
|
86
|
+
padding: collapsed ? "20px 8px" : "22px 14px",
|
|
87
|
+
background: "var(--bg-surface)",
|
|
88
|
+
borderRight: "1px solid var(--border-default)",
|
|
89
|
+
}, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10, paddingLeft: collapsed ? 0 : 2, justifyContent: collapsed ? "center" : "flex-start" }, children: [_jsx("img", { src: `${assetBase}/honeycomb-memory-cluster.svg`, width: collapsed ? 28 : 34, height: collapsed ? 28 : 34, alt: "", style: { flex: "none" } }), !collapsed && (_jsxs("div", { style: { display: "flex", flexDirection: "column", minWidth: 0 }, children: [_jsx("span", { style: { fontWeight: 700, fontSize: 19, letterSpacing: "-0.03em", color: "var(--text-primary)", lineHeight: 1.1 }, children: "honeycomb" }), _jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-tertiary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: identity })] }))] }), _jsx(ScopeSwitcherSlot, { collapsed: collapsed }), _jsx("div", { style: { display: "flex", flexDirection: "column", gap: 4, flex: 1 }, children: entries.map((entry) => (_jsx(NavItem, { entry: entry, active: entry.route === activeRoot, collapsed: collapsed, onNavigate: onNavigate }, entry.route))) }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: [_jsx(HealthPill, { daemonUp: daemonUp, collapsed: collapsed }), _jsx(Button, { variant: "ghost", size: "sm", onClick: onToggleCollapsed, "aria-label": collapsed ? "expand sidebar" : "collapse sidebar", title: collapsed ? "expand" : "collapse", children: collapsed ? "»" : "« collapse" })] })] }));
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=sidebar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.js","sourceRoot":"","sources":["../../../src/dashboard/web/sidebar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SHARED fleet-telemetry view-model hook — hive PRD-004/PRD-005. One hook, consumed by
|
|
3
|
+
* `/buzzing` (PRD-004a), the health rail (PRD-005a), and the `/health` page (PRD-005b/PRD-005c),
|
|
4
|
+
* so the SSE-first/REST-fallback wiring, the registered-name enumeration, and the bounded log
|
|
5
|
+
* ring buffer are each written exactly once (per the implementation brief), not duplicated per
|
|
6
|
+
* consumer.
|
|
7
|
+
*
|
|
8
|
+
* Sourcing precedence (bz-AC-4/bz-AC-5/bz-AC-6, hr-AC-3/hr-AC-4/hr-AC-5):
|
|
9
|
+
* 1. `EventSource("/api/telemetry/stream")` — the same-origin relay of doctor's real SSE
|
|
10
|
+
* stream (`telemetry-proxy.ts`). Live, near-real-time. `EventSource` auto-reconnects on its
|
|
11
|
+
* own after a drop (the browser's built-in behavior), so "resumes without a manual refresh"
|
|
12
|
+
* falls out of the platform rather than hand-rolled reconnect logic.
|
|
13
|
+
* 2. `GET /api/fleet-status` (PRD-002a), polled — the fail-soft fallback the whole time SSE is
|
|
14
|
+
* unavailable/erroring. Coarser (no metrics/Deep Lake/lastSeen), but keeps every tile/pill
|
|
15
|
+
* rendering rather than blanking.
|
|
16
|
+
*
|
|
17
|
+
* Every state-mutating step below is a PURE, exported function (`applyRegisteredNames`,
|
|
18
|
+
* `applySseEvent`, `applyRestFallback`, `appendLogs`, `deriveServiceViews`) so the derivation and
|
|
19
|
+
* bookkeeping are unit-testable without a real `EventSource` (jsdom has none — the hook itself
|
|
20
|
+
* degrades to the REST path in that environment, exactly like `wire.ts`'s `logsStream`).
|
|
21
|
+
*
|
|
22
|
+
* Memory-bounded (parent index constraint, lg-AC-6): `logs` is a capped ring buffer
|
|
23
|
+
* ({@link LOG_RING_BUFFER_CAP}), oldest-dropped; `services` holds only CURRENT per-service state,
|
|
24
|
+
* never a history series (hr-AC-7).
|
|
25
|
+
*/
|
|
26
|
+
import { type FleetDeeplakeStats, type FleetLogEntry, type FleetTelemetryEvent, type ServiceMetrics, type TelemetryFaultReason } from "../../shared/fleet-telemetry.js";
|
|
27
|
+
import type { FleetHealth, FleetStatusResponse } from "../../shared/fleet-readiness.js";
|
|
28
|
+
import { type ServiceSignal, type ServiceState } from "../../shared/service-status.js";
|
|
29
|
+
/** The bounded log ring-buffer cap (lg-AC-6/lg-AC-8): older lines drop rather than accumulate. */
|
|
30
|
+
export declare const LOG_RING_BUFFER_CAP = 500;
|
|
31
|
+
/** One service's rendered view-model: its derived loader state plus whatever raw telemetry is known. */
|
|
32
|
+
export interface ServiceView {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly state: ServiceState;
|
|
35
|
+
/** The raw doctor health, or `null` before any signal has been observed for this service. */
|
|
36
|
+
readonly health: FleetHealth | null;
|
|
37
|
+
readonly lastSeen: string | null;
|
|
38
|
+
/** Schema-tolerant per-service counters (PRD-005b) — `{}` until telemetry reports any. */
|
|
39
|
+
readonly metrics: ServiceMetrics;
|
|
40
|
+
readonly deeplake: FleetDeeplakeStats | null;
|
|
41
|
+
readonly telemetryFault: TelemetryFaultReason | null;
|
|
42
|
+
}
|
|
43
|
+
export type TelemetrySource = "sse" | "rest" | "none";
|
|
44
|
+
/** The shared view-model {@link useFleetTelemetry} returns. */
|
|
45
|
+
export interface FleetTelemetryView {
|
|
46
|
+
readonly services: readonly ServiceView[];
|
|
47
|
+
/** A bounded, newest-appended log tail (PRD-005c) — never the full history. */
|
|
48
|
+
readonly logs: readonly FleetLogEntry[];
|
|
49
|
+
readonly source: TelemetrySource;
|
|
50
|
+
readonly asOf: string | null;
|
|
51
|
+
}
|
|
52
|
+
export declare const EMPTY_FLEET_TELEMETRY_VIEW: FleetTelemetryView;
|
|
53
|
+
interface ServiceRuntime {
|
|
54
|
+
readonly signal: ServiceSignal;
|
|
55
|
+
readonly metrics: ServiceMetrics;
|
|
56
|
+
readonly deeplake: FleetDeeplakeStats | null;
|
|
57
|
+
readonly firstActiveAt: number | null;
|
|
58
|
+
}
|
|
59
|
+
/** @internal exported only for tests. */
|
|
60
|
+
export interface TelemetryState {
|
|
61
|
+
readonly registeredNames: readonly string[];
|
|
62
|
+
readonly services: ReadonlyMap<string, ServiceRuntime>;
|
|
63
|
+
readonly logs: readonly FleetLogEntry[];
|
|
64
|
+
readonly source: TelemetrySource;
|
|
65
|
+
readonly asOf: string | null;
|
|
66
|
+
}
|
|
67
|
+
/** The initial, empty state before any registration/telemetry has arrived. */
|
|
68
|
+
export declare function createInitialTelemetryState(registeredNames?: readonly string[]): TelemetryState;
|
|
69
|
+
/**
|
|
70
|
+
* Merge the full registered-name enumeration (`GET /api/registered-services`) into state
|
|
71
|
+
* (bz-AC-1/bz-AC-2, hr-AC-1). Never drops a name already tracked from telemetry that this
|
|
72
|
+
* enumeration happens not to list (defense against a stale/partial registry read).
|
|
73
|
+
*/
|
|
74
|
+
export declare function applyRegisteredNames(state: TelemetryState, names: readonly string[]): TelemetryState;
|
|
75
|
+
/** Append new log lines, capped at {@link LOG_RING_BUFFER_CAP} with the OLDEST dropped first (lg-AC-6/lg-AC-8). */
|
|
76
|
+
export declare function appendLogs(existing: readonly FleetLogEntry[], incoming: readonly FleetLogEntry[]): readonly FleetLogEntry[];
|
|
77
|
+
/** Apply one live `fleet-telemetry` SSE event (bz-AC-4, hr-AC-3, sd-AC-8/sd-AC-9 per-service isolation). */
|
|
78
|
+
export declare function applySseEvent(state: TelemetryState, event: FleetTelemetryEvent, now: number): TelemetryState;
|
|
79
|
+
/**
|
|
80
|
+
* Apply one `GET /api/fleet-status` fail-soft projection (bz-AC-5, hr-AC-4). The coarse
|
|
81
|
+
* projection carries no metrics/Deep Lake/lastSeen, so existing per-service metrics/Deep Lake
|
|
82
|
+
* readings are RETAINED (hm-AC-10's "last known metrics") — only the derived health-driving
|
|
83
|
+
* signal is refreshed.
|
|
84
|
+
*
|
|
85
|
+
* The response is a SNAPSHOT, not a patch: `services` is rebuilt from `status.daemons` alone, so
|
|
86
|
+
* a daemon missing from a later response loses its stale `signal`/`firstActiveAt` and falls back
|
|
87
|
+
* to the registered-but-silent derivation (`starting`) instead of staying `active`/`degraded`
|
|
88
|
+
* forever. Its NAME is still retained via `registeredNames`, so the row never disappears.
|
|
89
|
+
*/
|
|
90
|
+
export declare function applyRestFallback(state: TelemetryState, status: FleetStatusResponse, now: number): TelemetryState;
|
|
91
|
+
/** Build the rendered per-service views for every KNOWN name, in first-seen order (never omitted, sd-AC-2/bz-AC-2). */
|
|
92
|
+
export declare function deriveServiceViews(state: TelemetryState, now: number): readonly ServiceView[];
|
|
93
|
+
/** Project internal {@link TelemetryState} into the public {@link FleetTelemetryView}. */
|
|
94
|
+
export declare function toFleetTelemetryView(state: TelemetryState, now: number): FleetTelemetryView;
|
|
95
|
+
/** Options for {@link useFleetTelemetry}. */
|
|
96
|
+
export interface UseFleetTelemetryOptions {
|
|
97
|
+
/** Override the REST-fallback poll interval (ms). Defaults to {@link DEFAULT_REST_POLL_MS}. */
|
|
98
|
+
readonly restPollMs?: number;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The shared fleet-telemetry hook (see module doc for the sourcing precedence). Every consumer
|
|
102
|
+
* mounts its own instance; the underlying SSE/REST wiring is identical code shared via this one
|
|
103
|
+
* function rather than re-implemented per screen.
|
|
104
|
+
*/
|
|
105
|
+
export declare function useFleetTelemetry(options?: UseFleetTelemetryOptions): FleetTelemetryView;
|
|
106
|
+
/** The four selectable verbosity levels (lg-AC-4), ordered least→most severe. */
|
|
107
|
+
export declare const LOG_LEVELS: readonly ["debug", "info", "warn", "error"];
|
|
108
|
+
export type LogLevel = (typeof LOG_LEVELS)[number];
|
|
109
|
+
/** Filter a log buffer to lines AT OR ABOVE `minLevel` (lg-AC-4/lg-AC-5) — a view filter, never a re-fetch. */
|
|
110
|
+
export declare function filterLogsByVerbosity(logs: readonly FleetLogEntry[], minLevel: LogLevel): readonly FleetLogEntry[];
|
|
111
|
+
export {};
|