@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 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/dashboard/web/main.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,wGAAwG;AACxG,SAAS,KAAK;IACb,MAAM,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO;IAC1B,yFAAyF;IACzF,8FAA8F;IAC9F,+FAA+F;IAC/F,iGAAiG;IACjG,wFAAwF;IACxF,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,QAAQ,CAAC;IACtE,MAAM,SAAS,GAAG,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEpF,+FAA+F;IAC/F,4FAA4F;IAC5F,8FAA8F;IAC9F,gEAAgE;IAChE,MAAM,QAAQ,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAChF,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAE3C,MAAM,OAAO,GACZ,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CACtB,KAAC,aAAa,IAAC,SAAS,EAAE,SAAS,GAAI,CACvC,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CACxB,KAAC,WAAW,IAAC,SAAS,EAAE,SAAS,GAAI,CACrC,CAAC,CAAC,CAAC,CACH,KAAC,KAAK,IAAC,SAAS,EAAE,SAAS,GAAI,CAC/B,CAAC;IAEH,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAC,KAAK,CAAC,UAAU,cAAE,OAAO,GAAoB,CAAC,CAAC;AACzE,CAAC;AAED,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared "needs a project selection" EMPTY STATE — PRD-049e (49e-AC-5) — and the FIRST-RUN
|
|
3
|
+
* "pick a folder to start" CTA — PRD-059b (b-AC-1).
|
|
4
|
+
*
|
|
5
|
+
* When no project is selected in the scope switcher (or none is accessible), every project-specific
|
|
6
|
+
* page renders {@link NeedsProjectSelection} — the explicit empty/needs-selection state INSTEAD of any
|
|
7
|
+
* data, never another project's rows. It is one shared component (not duplicated per page) so the copy
|
|
8
|
+
* stays consistent and the jscpd gate is satisfied (a single definition, three call sites).
|
|
9
|
+
*
|
|
10
|
+
* When the workspace has ZERO bound projects, the dashboard's PRIMARY content is {@link FirstRunBindCTA}
|
|
11
|
+
* (b-AC-1): a purposeful "No active projects? Pick a folder to start" call-to-action with one line of
|
|
12
|
+
* plain instruction and the daemon-served {@link FolderPicker} behind it. On a successful bind it routes
|
|
13
|
+
* to the Projects page (b-AC-4). Both live here so the empty-state family stays one module. Every visual
|
|
14
|
+
* value is an existing DS token.
|
|
15
|
+
*/
|
|
16
|
+
import React from "react";
|
|
17
|
+
import type { WireClient } from "./wire.js";
|
|
18
|
+
/**
|
|
19
|
+
* The explicit needs-selection panel (49e-AC-5). Rendered by the graph / memories / sync pages when
|
|
20
|
+
* `useScope().scope.project` is undefined: an honest "pick a project to view its <surface>" message,
|
|
21
|
+
* NOT a faked/another-project's view. `surface` names the page's data ("codebase graph", "memories", …)
|
|
22
|
+
* so the copy reads naturally per page.
|
|
23
|
+
*/
|
|
24
|
+
export declare function NeedsProjectSelection({ surface }: {
|
|
25
|
+
surface: string;
|
|
26
|
+
}): React.JSX.Element;
|
|
27
|
+
/** Props for {@link FirstRunBindCTA}. */
|
|
28
|
+
export interface FirstRunBindCTAProps {
|
|
29
|
+
/** The shared wire client (the shell/page passes the SAME one — never `createWireClient`). */
|
|
30
|
+
readonly wire: WireClient;
|
|
31
|
+
/**
|
|
32
|
+
* Navigate the dashboard to a hash route. On a successful first bind the CTA routes to the Projects
|
|
33
|
+
* page (b-AC-4). The shell passes its 037b `navigate`; a test passes a spy.
|
|
34
|
+
*/
|
|
35
|
+
readonly navigate: (route: string) => void;
|
|
36
|
+
/**
|
|
37
|
+
* The host-stamped asset base (`data-asset-base`, `/dashboard` in production). The brand mark MUST
|
|
38
|
+
* be resolved against it — a hardcoded relative `assets/…` resolves to the unserved `/assets/…`
|
|
39
|
+
* (a 404), unlike the sidebar/setup-gate which already use `assetBase`. Threaded from `PageProps`.
|
|
40
|
+
*/
|
|
41
|
+
readonly assetBase: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The first-run "Pick a folder to start" CTA (PRD-059b b-AC-1). Rendered as the PRIMARY dashboard
|
|
45
|
+
* content when the workspace has ZERO bound projects — never an empty switcher or a blank page. It
|
|
46
|
+
* states the one action plainly ("point Honeycomb at the repo or folder you want it to remember"),
|
|
47
|
+
* then reveals the daemon-served {@link FolderPicker} so the user can browse, name, and bind a folder.
|
|
48
|
+
* On a successful bind it advances to the Projects page (b-AC-4); capture begins because the 059a gate
|
|
49
|
+
* opens the moment the binding is written (daemon-side).
|
|
50
|
+
*/
|
|
51
|
+
export declare function FirstRunBindCTA({ wire, navigate, assetBase }: FirstRunBindCTAProps): React.JSX.Element;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The shared "needs a project selection" EMPTY STATE — PRD-049e (49e-AC-5) — and the FIRST-RUN
|
|
4
|
+
* "pick a folder to start" CTA — PRD-059b (b-AC-1).
|
|
5
|
+
*
|
|
6
|
+
* When no project is selected in the scope switcher (or none is accessible), every project-specific
|
|
7
|
+
* page renders {@link NeedsProjectSelection} — the explicit empty/needs-selection state INSTEAD of any
|
|
8
|
+
* data, never another project's rows. It is one shared component (not duplicated per page) so the copy
|
|
9
|
+
* stays consistent and the jscpd gate is satisfied (a single definition, three call sites).
|
|
10
|
+
*
|
|
11
|
+
* When the workspace has ZERO bound projects, the dashboard's PRIMARY content is {@link FirstRunBindCTA}
|
|
12
|
+
* (b-AC-1): a purposeful "No active projects? Pick a folder to start" call-to-action with one line of
|
|
13
|
+
* plain instruction and the daemon-served {@link FolderPicker} behind it. On a successful bind it routes
|
|
14
|
+
* to the Projects page (b-AC-4). Both live here so the empty-state family stays one module. Every visual
|
|
15
|
+
* value is an existing DS token.
|
|
16
|
+
*/
|
|
17
|
+
import React from "react";
|
|
18
|
+
import { Button } from "./primitives.js";
|
|
19
|
+
import { FolderPicker } from "./folder-picker.js";
|
|
20
|
+
import { PROJECTS_ROUTE } from "./registry.js";
|
|
21
|
+
/**
|
|
22
|
+
* The explicit needs-selection panel (49e-AC-5). Rendered by the graph / memories / sync pages when
|
|
23
|
+
* `useScope().scope.project` is undefined: an honest "pick a project to view its <surface>" message,
|
|
24
|
+
* NOT a faked/another-project's view. `surface` names the page's data ("codebase graph", "memories", …)
|
|
25
|
+
* so the copy reads naturally per page.
|
|
26
|
+
*/
|
|
27
|
+
export function NeedsProjectSelection({ surface }) {
|
|
28
|
+
return (_jsxs("div", { "data-testid": "needs-project-selection", style: {
|
|
29
|
+
display: "flex",
|
|
30
|
+
flexDirection: "column",
|
|
31
|
+
alignItems: "center",
|
|
32
|
+
justifyContent: "center",
|
|
33
|
+
gap: 10,
|
|
34
|
+
minHeight: 320,
|
|
35
|
+
padding: "48px 16px",
|
|
36
|
+
background: "var(--bg-surface)",
|
|
37
|
+
border: "1px solid var(--border-default)",
|
|
38
|
+
borderRadius: "var(--radius-lg)",
|
|
39
|
+
textAlign: "center",
|
|
40
|
+
}, children: [_jsx("div", { style: { fontSize: 15, color: "var(--text-secondary)" }, children: "No project selected." }), _jsxs("span", { style: { fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--text-tertiary)", maxWidth: 460 }, children: ["Pick a project in the scope switcher (top of the sidebar) to view its ", surface, "."] })] }));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The first-run "Pick a folder to start" CTA (PRD-059b b-AC-1). Rendered as the PRIMARY dashboard
|
|
44
|
+
* content when the workspace has ZERO bound projects — never an empty switcher or a blank page. It
|
|
45
|
+
* states the one action plainly ("point Honeycomb at the repo or folder you want it to remember"),
|
|
46
|
+
* then reveals the daemon-served {@link FolderPicker} so the user can browse, name, and bind a folder.
|
|
47
|
+
* On a successful bind it advances to the Projects page (b-AC-4); capture begins because the 059a gate
|
|
48
|
+
* opens the moment the binding is written (daemon-side).
|
|
49
|
+
*/
|
|
50
|
+
export function FirstRunBindCTA({ wire, navigate, assetBase }) {
|
|
51
|
+
const [picking, setPicking] = React.useState(false);
|
|
52
|
+
const onBound = React.useCallback((_ack) => {
|
|
53
|
+
// b-AC-4: the bind is written + the 059a gate opened daemon-side; advance to the Projects page
|
|
54
|
+
// where the freshly-bound project now appears (the page hydrates from the synced registry).
|
|
55
|
+
navigate(PROJECTS_ROUTE);
|
|
56
|
+
}, [navigate]);
|
|
57
|
+
return (_jsxs("div", { "data-testid": "first-run-bind", style: {
|
|
58
|
+
display: "flex",
|
|
59
|
+
flexDirection: "column",
|
|
60
|
+
alignItems: "center",
|
|
61
|
+
gap: 16,
|
|
62
|
+
padding: "48px 16px",
|
|
63
|
+
background: "var(--bg-surface)",
|
|
64
|
+
border: "1px solid var(--border-default)",
|
|
65
|
+
borderRadius: "var(--radius-lg)",
|
|
66
|
+
textAlign: "center",
|
|
67
|
+
}, children: [_jsx("img", { src: `${assetBase}/honeycomb-memory-cluster.svg`, width: 48, height: 48, alt: "" }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8, maxWidth: 480 }, children: [_jsx("div", { style: { fontSize: 17, fontWeight: 700, color: "var(--text-primary)", letterSpacing: "-0.02em" }, children: "No active projects?" }), _jsx("div", { style: { fontSize: 14, color: "var(--text-secondary)", lineHeight: 1.5 }, children: "Pick a folder to start \u2014 point Honeycomb at the repo or folder you want it to remember, and it begins capturing there." })] }), picking ? (_jsx("div", { style: { width: "100%", maxWidth: 620, textAlign: "left" }, children: _jsx(FolderPicker, { wire: wire, onBound: onBound, onCancel: () => setPicking(false) }) })) : (_jsx(Button, { variant: "primary", size: "lg", onClick: () => setPicking(true), "data-testid": "first-run-pick", children: "Pick a folder to start" }))] }));
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=needs-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"needs-project.js","sourceRoot":"","sources":["../../../src/dashboard/web/needs-project.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared PAGE FRAME + the page contract — PRD-037c (the extensibility surface).
|
|
3
|
+
*
|
|
4
|
+
* Every routed page (the Dashboard lift-and-shift plus the six PRD-039..044 destinations) renders
|
|
5
|
+
* INSIDE `<PageFrame>`: an optional mono eyebrow, a title, and a content body capped at the
|
|
6
|
+
* preserved readable max-width (the old `.wrap` 1180px cap, D-8). The frame's background is
|
|
7
|
+
* transparent — the canvas `--bg-canvas` shows through and panels inside keep their own
|
|
8
|
+
* `--bg-surface` (mirrors the `Panel` header rhythm in `panels.tsx` but at PAGE scale). A page
|
|
9
|
+
* therefore carries NO chrome of its own (037c AC-1): the shell owns the sidebar/header, the page
|
|
10
|
+
* owns its content.
|
|
11
|
+
*
|
|
12
|
+
* `PageProps` is the single contract the router outlet passes EVERY page (037c): the shared `wire`
|
|
13
|
+
* client (so a page never re-creates one), the `daemonUp` flag (the shell owns the down state, so a
|
|
14
|
+
* page renders content assuming up — D-5), and the `assetBase`. `usePoll` is the documented
|
|
15
|
+
* hydration recipe — fetch-on-mount + interval + cleanup-on-unmount — replicating the old
|
|
16
|
+
* `app.tsx`'s log/health poll so a page (Logs, Memories, Graph…) hydrates the same way without
|
|
17
|
+
* re-deriving the lifecycle (037c AC-4).
|
|
18
|
+
*
|
|
19
|
+
* Every visual value here is an existing `var(--…)` design token — NO new token (D-3 / D-9).
|
|
20
|
+
*/
|
|
21
|
+
import React from "react";
|
|
22
|
+
import type { HealthReasonsWire, WireClient } from "./wire.js";
|
|
23
|
+
/**
|
|
24
|
+
* The props the router outlet passes every routed page (037c). A page reads the SHARED `wire`
|
|
25
|
+
* (never `createWireClient` itself), renders content for the up daemon (the shell swaps in the
|
|
26
|
+
* ConnectivityBanner when down — D-5, so `daemonUp` is informational for a page that wants to
|
|
27
|
+
* gate its own polling), and uses `assetBase` for any host-served asset (e.g. the mark).
|
|
28
|
+
*/
|
|
29
|
+
export interface PageProps {
|
|
30
|
+
/** The shared, already-constructed wire client (the shell builds ONE and passes it down). */
|
|
31
|
+
readonly wire: WireClient;
|
|
32
|
+
/** Daemon liveness — the shell owns the down view-swap; a page may use this to gate its polling. */
|
|
33
|
+
readonly daemonUp: boolean;
|
|
34
|
+
/** The base path the host serves assets (mark/logo) under (loopback, no secret — D-9). */
|
|
35
|
+
readonly assetBase: string;
|
|
36
|
+
/**
|
|
37
|
+
* Whether a Pollinate pass is currently active (D-5: the "Pollinate now" action lives in the SHELL chrome,
|
|
38
|
+
* so the pollinating flag is owned there and passed DOWN). Informational for most pages; the Dashboard
|
|
39
|
+
* page reads it to drive the graph/card pollinate pulse. Defaults `false` for a page that ignores it.
|
|
40
|
+
*/
|
|
41
|
+
readonly pollinating?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* The latest `/health` subsystem reasons, owned by the SHELL's single liveness poll and passed DOWN
|
|
44
|
+
* (so a page never polls `/health` a second time — the home's per-subsystem strip reads THIS). `null`
|
|
45
|
+
* before the first probe resolves or when the mode-gated public body omits reasons. Defaults `null`.
|
|
46
|
+
*/
|
|
47
|
+
readonly healthReasons?: HealthReasonsWire | null;
|
|
48
|
+
}
|
|
49
|
+
/** The maximum readable content width — preserves the old `.wrap` 1180px cap (D-8). */
|
|
50
|
+
export declare const PAGE_MAX_WIDTH: 1180;
|
|
51
|
+
/** Props for {@link PageFrame}. */
|
|
52
|
+
export interface PageFrameProps {
|
|
53
|
+
/** The page title (page-scale heading). */
|
|
54
|
+
readonly title: string;
|
|
55
|
+
/** An optional mono eyebrow above the title (e.g. a route tag or count). */
|
|
56
|
+
readonly eyebrow?: string;
|
|
57
|
+
/** An optional right-aligned slot on the title row (a page-level action/status). */
|
|
58
|
+
readonly right?: React.ReactNode;
|
|
59
|
+
/** The page content (panels, grids, etc.). */
|
|
60
|
+
readonly children?: React.ReactNode;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The shared page layout (037c AC-1). An optional mono eyebrow + a title row, then the content
|
|
64
|
+
* body capped at {@link PAGE_MAX_WIDTH}. Transparent background (the canvas shows through). Uses
|
|
65
|
+
* only existing DS tokens — the title treatment mirrors the `Panel` header (`--text-base`+,
|
|
66
|
+
* `--text-primary`, `letterSpacing: -0.01em`); the eyebrow mirrors the mono `--text-tertiary`
|
|
67
|
+
* uppercase eyebrow the KPI/health strip already speak.
|
|
68
|
+
*/
|
|
69
|
+
export declare function PageFrame({ title, eyebrow, right, children }: PageFrameProps): React.JSX.Element;
|
|
70
|
+
/**
|
|
71
|
+
* The documented hydration recipe (037c AC-4): fetch-on-mount + interval poll + cleanup-on-unmount,
|
|
72
|
+
* replicating the old `app.tsx`'s log/health poll lifecycle so a page polls a live endpoint the
|
|
73
|
+
* SAME way the dashboard does today. `fn` is invoked once immediately on mount, then every `ms`
|
|
74
|
+
* until the component unmounts; the `setInterval` is cleared and an `alive` flag prevents a
|
|
75
|
+
* late-resolving async `fn` from updating an unmounted tree. `fn` is held in a ref so a page can
|
|
76
|
+
* pass an inline closure without re-subscribing the interval every render (only `ms` re-arms it).
|
|
77
|
+
*
|
|
78
|
+
* ── Background pause (perf) ──────────────────────────────────────────────────
|
|
79
|
+
* A dashboard left open in a BACKGROUND tab must not keep hitting the daemon/DeepLake. So a tick
|
|
80
|
+
* NO-OPs while `document.visibilityState === "hidden"`; the interval keeps its cadence but does no
|
|
81
|
+
* work until the tab is foregrounded again. A `visibilitychange` → visible fires an IMMEDIATE tick
|
|
82
|
+
* so returning to the tab refreshes at once instead of waiting up to `ms`. This is the single seam
|
|
83
|
+
* every page's poll inherits the pause from.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* // A Logs page that polls /api/logs every 2.5s and stops on unmount:
|
|
87
|
+
* usePoll(async () => setLines(await wire.logs(8)), 2500);
|
|
88
|
+
*/
|
|
89
|
+
/**
|
|
90
|
+
* Whether the tab is currently backgrounded (the single visibility predicate). A backgrounded
|
|
91
|
+
* dashboard should not keep hitting the daemon/DeepLake, so {@link usePoll} and the pages' own raw
|
|
92
|
+
* poll loops skip their fetch while this is true. SSR/non-DOM safe (returns `false` with no `document`).
|
|
93
|
+
*/
|
|
94
|
+
export declare function isTabHidden(): boolean;
|
|
95
|
+
export declare function usePoll(fn: () => void | Promise<void>, ms: number): void;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The shared PAGE FRAME + the page contract — PRD-037c (the extensibility surface).
|
|
4
|
+
*
|
|
5
|
+
* Every routed page (the Dashboard lift-and-shift plus the six PRD-039..044 destinations) renders
|
|
6
|
+
* INSIDE `<PageFrame>`: an optional mono eyebrow, a title, and a content body capped at the
|
|
7
|
+
* preserved readable max-width (the old `.wrap` 1180px cap, D-8). The frame's background is
|
|
8
|
+
* transparent — the canvas `--bg-canvas` shows through and panels inside keep their own
|
|
9
|
+
* `--bg-surface` (mirrors the `Panel` header rhythm in `panels.tsx` but at PAGE scale). A page
|
|
10
|
+
* therefore carries NO chrome of its own (037c AC-1): the shell owns the sidebar/header, the page
|
|
11
|
+
* owns its content.
|
|
12
|
+
*
|
|
13
|
+
* `PageProps` is the single contract the router outlet passes EVERY page (037c): the shared `wire`
|
|
14
|
+
* client (so a page never re-creates one), the `daemonUp` flag (the shell owns the down state, so a
|
|
15
|
+
* page renders content assuming up — D-5), and the `assetBase`. `usePoll` is the documented
|
|
16
|
+
* hydration recipe — fetch-on-mount + interval + cleanup-on-unmount — replicating the old
|
|
17
|
+
* `app.tsx`'s log/health poll so a page (Logs, Memories, Graph…) hydrates the same way without
|
|
18
|
+
* re-deriving the lifecycle (037c AC-4).
|
|
19
|
+
*
|
|
20
|
+
* Every visual value here is an existing `var(--…)` design token — NO new token (D-3 / D-9).
|
|
21
|
+
*/
|
|
22
|
+
import React from "react";
|
|
23
|
+
/** The maximum readable content width — preserves the old `.wrap` 1180px cap (D-8). */
|
|
24
|
+
export const PAGE_MAX_WIDTH = 1180;
|
|
25
|
+
/**
|
|
26
|
+
* The shared page layout (037c AC-1). An optional mono eyebrow + a title row, then the content
|
|
27
|
+
* body capped at {@link PAGE_MAX_WIDTH}. Transparent background (the canvas shows through). Uses
|
|
28
|
+
* only existing DS tokens — the title treatment mirrors the `Panel` header (`--text-base`+,
|
|
29
|
+
* `--text-primary`, `letterSpacing: -0.01em`); the eyebrow mirrors the mono `--text-tertiary`
|
|
30
|
+
* uppercase eyebrow the KPI/health strip already speak.
|
|
31
|
+
*/
|
|
32
|
+
export function PageFrame({ title, eyebrow, right, children }) {
|
|
33
|
+
return (_jsxs("div", { style: { maxWidth: PAGE_MAX_WIDTH, margin: "0 auto", width: "100%" }, children: [_jsxs("header", { style: { display: "flex", alignItems: "center", gap: 12, marginBottom: 18 }, children: [_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 4, minWidth: 0 }, children: [eyebrow !== undefined && eyebrow !== "" && (_jsx("span", { style: {
|
|
34
|
+
fontFamily: "var(--font-mono)",
|
|
35
|
+
fontSize: 11,
|
|
36
|
+
color: "var(--text-tertiary)",
|
|
37
|
+
textTransform: "uppercase",
|
|
38
|
+
letterSpacing: "0.08em",
|
|
39
|
+
}, children: eyebrow })), _jsx("h1", { style: { fontSize: "var(--text-lg)", fontWeight: 700, color: "var(--text-primary)", margin: 0, letterSpacing: "-0.01em", lineHeight: 1.1 }, children: title })] }), _jsx("span", { style: { flex: 1 } }), right] }), _jsx("div", { children: children })] }));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The documented hydration recipe (037c AC-4): fetch-on-mount + interval poll + cleanup-on-unmount,
|
|
43
|
+
* replicating the old `app.tsx`'s log/health poll lifecycle so a page polls a live endpoint the
|
|
44
|
+
* SAME way the dashboard does today. `fn` is invoked once immediately on mount, then every `ms`
|
|
45
|
+
* until the component unmounts; the `setInterval` is cleared and an `alive` flag prevents a
|
|
46
|
+
* late-resolving async `fn` from updating an unmounted tree. `fn` is held in a ref so a page can
|
|
47
|
+
* pass an inline closure without re-subscribing the interval every render (only `ms` re-arms it).
|
|
48
|
+
*
|
|
49
|
+
* ── Background pause (perf) ──────────────────────────────────────────────────
|
|
50
|
+
* A dashboard left open in a BACKGROUND tab must not keep hitting the daemon/DeepLake. So a tick
|
|
51
|
+
* NO-OPs while `document.visibilityState === "hidden"`; the interval keeps its cadence but does no
|
|
52
|
+
* work until the tab is foregrounded again. A `visibilitychange` → visible fires an IMMEDIATE tick
|
|
53
|
+
* so returning to the tab refreshes at once instead of waiting up to `ms`. This is the single seam
|
|
54
|
+
* every page's poll inherits the pause from.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* // A Logs page that polls /api/logs every 2.5s and stops on unmount:
|
|
58
|
+
* usePoll(async () => setLines(await wire.logs(8)), 2500);
|
|
59
|
+
*/
|
|
60
|
+
/**
|
|
61
|
+
* Whether the tab is currently backgrounded (the single visibility predicate). A backgrounded
|
|
62
|
+
* dashboard should not keep hitting the daemon/DeepLake, so {@link usePoll} and the pages' own raw
|
|
63
|
+
* poll loops skip their fetch while this is true. SSR/non-DOM safe (returns `false` with no `document`).
|
|
64
|
+
*/
|
|
65
|
+
export function isTabHidden() {
|
|
66
|
+
return typeof document !== "undefined" && document.visibilityState === "hidden";
|
|
67
|
+
}
|
|
68
|
+
export function usePoll(fn, ms) {
|
|
69
|
+
const fnRef = React.useRef(fn);
|
|
70
|
+
// Keep the latest `fn` without re-arming the interval (only `ms` re-arms it).
|
|
71
|
+
React.useEffect(() => {
|
|
72
|
+
fnRef.current = fn;
|
|
73
|
+
}, [fn]);
|
|
74
|
+
React.useEffect(() => {
|
|
75
|
+
let alive = true;
|
|
76
|
+
const tick = async () => {
|
|
77
|
+
if (!alive || isTabHidden())
|
|
78
|
+
return;
|
|
79
|
+
await fnRef.current();
|
|
80
|
+
};
|
|
81
|
+
void tick();
|
|
82
|
+
const id = setInterval(() => void tick(), ms);
|
|
83
|
+
// Refresh immediately on re-foreground (the skipped ticks left the view as stale as `ms` ago).
|
|
84
|
+
const onVisible = () => {
|
|
85
|
+
if (!isTabHidden())
|
|
86
|
+
void tick();
|
|
87
|
+
};
|
|
88
|
+
if (typeof document !== "undefined")
|
|
89
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
90
|
+
return () => {
|
|
91
|
+
alive = false;
|
|
92
|
+
clearInterval(id);
|
|
93
|
+
if (typeof document !== "undefined")
|
|
94
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
95
|
+
};
|
|
96
|
+
}, [ms]);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=page-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-frame.js","sourceRoot":"","sources":["../../../src/dashboard/web/page-frame.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared "coming soon" placeholder — PRD-037b/037c (empty-frame the six non-Dashboard routes).
|
|
3
|
+
*
|
|
4
|
+
* 037 stands up LIVE, testable routes for Harnesses/Memories/Graph/Sync/Logs/Settings before PRDs
|
|
5
|
+
* 039-044 fill them. Each placeholder is a one-liner over this shared frame so the six pages do not
|
|
6
|
+
* duplicate the same markup (jscpd discipline — one helper, six thin call sites). It renders inside
|
|
7
|
+
* `<PageFrame>` (037c) with a mono "coming soon · owned by PRD-0XX" note, using only DS tokens. No
|
|
8
|
+
* data, no secret — the route is reachable and the seam is proven; the content arrives in its PRD.
|
|
9
|
+
*/
|
|
10
|
+
import React from "react";
|
|
11
|
+
/** Props for {@link ComingSoon}: the page title, its route tag, and the owning PRD id. */
|
|
12
|
+
export interface ComingSoonProps {
|
|
13
|
+
/** The page title (the nav label, e.g. `Harnesses`). */
|
|
14
|
+
readonly title: string;
|
|
15
|
+
/** The owning downstream PRD id, e.g. `PRD-039`, shown in the note so the seam is self-documenting. */
|
|
16
|
+
readonly ownerPrd: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A reachable, empty-framed route placeholder. The eyebrow carries a mono "coming soon" tag and the
|
|
20
|
+
* body a single line crediting the owning PRD, so a dogfooder navigating to the route sees an honest
|
|
21
|
+
* "owned by PRD-0XX" note rather than a blank screen, and a test can assert the route mounted.
|
|
22
|
+
*/
|
|
23
|
+
export declare function ComingSoon({ title, ownerPrd }: ComingSoonProps): React.JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { PageFrame } from "../page-frame.js";
|
|
3
|
+
/**
|
|
4
|
+
* A reachable, empty-framed route placeholder. The eyebrow carries a mono "coming soon" tag and the
|
|
5
|
+
* body a single line crediting the owning PRD, so a dogfooder navigating to the route sees an honest
|
|
6
|
+
* "owned by PRD-0XX" note rather than a blank screen, and a test can assert the route mounted.
|
|
7
|
+
*/
|
|
8
|
+
export function ComingSoon({ title, ownerPrd }) {
|
|
9
|
+
return (_jsx(PageFrame, { title: title, eyebrow: "coming soon", children: _jsxs("div", { style: {
|
|
10
|
+
padding: "28px 20px",
|
|
11
|
+
background: "var(--bg-surface)",
|
|
12
|
+
border: "1px solid var(--border-default)",
|
|
13
|
+
borderRadius: "var(--radius-lg)",
|
|
14
|
+
color: "var(--text-tertiary)",
|
|
15
|
+
fontFamily: "var(--font-mono)",
|
|
16
|
+
fontSize: 13,
|
|
17
|
+
}, children: ["coming soon \u00B7 owned by ", ownerPrd] }) }));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=coming-soon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coming-soon.js","sourceRoot":"","sources":["../../../../src/dashboard/web/pages/coming-soon.tsx"],"names":[],"mappings":";AAYA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAU7C;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAmB;IAC9D,OAAO,CACN,KAAC,SAAS,IAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAC,aAAa,YAC7C,eACC,KAAK,EAAE;gBACN,OAAO,EAAE,WAAW;gBACpB,UAAU,EAAE,mBAAmB;gBAC/B,MAAM,EAAE,iCAAiC;gBACzC,YAAY,EAAE,kBAAkB;gBAChC,KAAK,EAAE,sBAAsB;gBAC7B,UAAU,EAAE,kBAAkB;gBAC9B,QAAQ,EAAE,EAAE;aACZ,6CAEuB,QAAQ,IAC3B,GACK,CACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DASHBOARD page — the zoned home (PRD-038, re-laying the PRD-037b lift-and-shift).
|
|
3
|
+
*
|
|
4
|
+
* PRD-037 lifted the old `app.tsx` body onto this route VERBATIM. PRD-038 reorganizes that body into
|
|
5
|
+
* three named AREA landmarks so the home reads as zones, not one undifferentiated scroll (parent
|
|
6
|
+
* D-1 / AC-1):
|
|
7
|
+
* 1. `<section data-area="kpi-band">` — the per-subsystem health strip + the four headline KPIs
|
|
8
|
+
* (Memories, Turns, Est. savings, Team skills — 038a).
|
|
9
|
+
* 2. `<section data-area="recall-area">` — the recall bar + recalled-memory cards + the PRD-029
|
|
10
|
+
* lexical-fallback badge, the centerpiece (038b, moved
|
|
11
|
+
* VERBATIM — same `wire.recall` POST, same render).
|
|
12
|
+
* 3. `<section data-area="harness-area">` — the {@link HarnessStrip} (wired-in chips + per-harness
|
|
13
|
+
* KPI tiles + a short-tail `/api/logs` stream — 038c),
|
|
14
|
+
* then the existing 2-col grid + the full live log,
|
|
15
|
+
* reorganized into the zone (kept, not dropped).
|
|
16
|
+
*
|
|
17
|
+
* Behavior is UNCHANGED — recall, polling, and the KPI/grid panels are MOVED into the areas, not
|
|
18
|
+
* rebuilt (parent D-2/D-3/D-4). The page hydrates from the SHARED `wire` the shell passes via
|
|
19
|
+
* {@link PageProps} (it never calls `createWireClient` — the shell builds ONE) and reads the
|
|
20
|
+
* shell-owned `pollinating` flag (D-6: the "Pollinate now" action, the identity, the coarse daemon pill, and
|
|
21
|
+
* the daemon-down swap live in the shell, so this page renders NO header of its own). Every visual
|
|
22
|
+
* value is an existing `var(--…)` DS token; no new token, primitive, or daemon route (AC-7/AC-8).
|
|
23
|
+
*/
|
|
24
|
+
import React from "react";
|
|
25
|
+
import { type PageProps } from "../page-frame.js";
|
|
26
|
+
/**
|
|
27
|
+
* The Dashboard route content (the lift-and-shift, D-6). On mount it hydrates every view from the
|
|
28
|
+
* shared `wire` (AC-2), polls `/api/logs` (AC-4) and `/health` for the strip reasons (PRD-029), and
|
|
29
|
+
* runs recall (AC-3). The `pollinating` pulse is owned by the shell (D-5) and read from props. All
|
|
30
|
+
* polling clears on unmount. NO header — the shell owns the chrome (D-5).
|
|
31
|
+
*/
|
|
32
|
+
export declare function DashboardPage({ wire, pollinating, healthReasons }: PageProps): React.JSX.Element;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The DASHBOARD page — the zoned home (PRD-038, re-laying the PRD-037b lift-and-shift).
|
|
4
|
+
*
|
|
5
|
+
* PRD-037 lifted the old `app.tsx` body onto this route VERBATIM. PRD-038 reorganizes that body into
|
|
6
|
+
* three named AREA landmarks so the home reads as zones, not one undifferentiated scroll (parent
|
|
7
|
+
* D-1 / AC-1):
|
|
8
|
+
* 1. `<section data-area="kpi-band">` — the per-subsystem health strip + the four headline KPIs
|
|
9
|
+
* (Memories, Turns, Est. savings, Team skills — 038a).
|
|
10
|
+
* 2. `<section data-area="recall-area">` — the recall bar + recalled-memory cards + the PRD-029
|
|
11
|
+
* lexical-fallback badge, the centerpiece (038b, moved
|
|
12
|
+
* VERBATIM — same `wire.recall` POST, same render).
|
|
13
|
+
* 3. `<section data-area="harness-area">` — the {@link HarnessStrip} (wired-in chips + per-harness
|
|
14
|
+
* KPI tiles + a short-tail `/api/logs` stream — 038c),
|
|
15
|
+
* then the existing 2-col grid + the full live log,
|
|
16
|
+
* reorganized into the zone (kept, not dropped).
|
|
17
|
+
*
|
|
18
|
+
* Behavior is UNCHANGED — recall, polling, and the KPI/grid panels are MOVED into the areas, not
|
|
19
|
+
* rebuilt (parent D-2/D-3/D-4). The page hydrates from the SHARED `wire` the shell passes via
|
|
20
|
+
* {@link PageProps} (it never calls `createWireClient` — the shell builds ONE) and reads the
|
|
21
|
+
* shell-owned `pollinating` flag (D-6: the "Pollinate now" action, the identity, the coarse daemon pill, and
|
|
22
|
+
* the daemon-down swap live in the shell, so this page renders NO header of its own). Every visual
|
|
23
|
+
* value is an existing `var(--…)` DS token; no new token, primitive, or daemon route (AC-7/AC-8).
|
|
24
|
+
*/
|
|
25
|
+
import React from "react";
|
|
26
|
+
import { Badge, Button, Input, Kpi, MemoryCard } from "../primitives.js";
|
|
27
|
+
import { LiveLog, RulesPanel, SessionsPanel, SettingsPanel, SkillSyncPanel } from "../panels.js";
|
|
28
|
+
import { HarnessStrip } from "../harness-strip.js";
|
|
29
|
+
import { useScope } from "../scope-context.js";
|
|
30
|
+
import { usePoll } from "../page-frame.js";
|
|
31
|
+
import { EMPTY_KPIS, EMPTY_VAULT_SETTINGS, formatLogLine, } from "../wire.js";
|
|
32
|
+
/** How often the live-log poll re-reads `/api/logs` (ms). Reasonable cadence, stopped on unmount. */
|
|
33
|
+
const LOG_POLL_MS = 2500;
|
|
34
|
+
/** How often the harness-strip poll re-reads `/api/diagnostics/harnesses` for last-seen recency (ms). */
|
|
35
|
+
const HARNESS_POLL_MS = 5000;
|
|
36
|
+
/** How many recent log lines the panel keeps. */
|
|
37
|
+
const MAX_LOG_LINES = 8;
|
|
38
|
+
/** The short-tail cap for the harness-area live stream — tighter than the full log (038c-AC-2 / OQ-4). */
|
|
39
|
+
const MAX_STREAM_LINES = 5;
|
|
40
|
+
/** The local-clock prefix for a client-originated log line (recall notes). */
|
|
41
|
+
function clockPrefix() {
|
|
42
|
+
return new Date().toTimeString().slice(0, 8);
|
|
43
|
+
}
|
|
44
|
+
/** The recall bar: a mono lg Input + a primary Recall button. Enter and click both fire. */
|
|
45
|
+
function RecallBar({ query, setQuery, onRecall, busy, }) {
|
|
46
|
+
return (_jsxs("div", { style: { display: "flex", gap: 10, marginBottom: 18 }, children: [_jsx("div", { style: { flex: 1 }, children: _jsx(Input, { mono: true, size: "lg", value: query, placeholder: "recall\u2026 e.g. how do we deploy", onChange: (e) => setQuery(e.target.value), onKeyDown: (e) => {
|
|
47
|
+
if (e.key === "Enter")
|
|
48
|
+
onRecall();
|
|
49
|
+
} }) }), _jsx(Button, { variant: "primary", size: "lg", onClick: onRecall, disabled: busy, children: busy ? "…" : "Recall" })] }));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The PRD-029 "lexical fallback" badge (AC-1). Rendered ONLY when the recall response carried
|
|
53
|
+
* `degraded: true` (embeddings off/absent → lexical BM25/ILIKE). Renders subsystem STATE only — the
|
|
54
|
+
* single closed flag, NO token/org/header (AC-5) — using the kit's `Badge` in the `warning` tone.
|
|
55
|
+
*/
|
|
56
|
+
function LexicalFallbackBadge() {
|
|
57
|
+
return (_jsx("span", { title: "recall fell back to lexical (embeddings off) \u2014 semantic ranking unavailable", style: { display: "inline-flex" }, children: _jsx(Badge, { tone: "warning", mono: true, dot: true, children: "lexical fallback" }) }));
|
|
58
|
+
}
|
|
59
|
+
/** The display label + degraded predicate for one subsystem chip in {@link HealthStrip}. */
|
|
60
|
+
const SUBSYSTEMS = [
|
|
61
|
+
{ key: "storage", label: "storage", degraded: (r) => r.storage === "unreachable" },
|
|
62
|
+
{ key: "embeddings", label: "semantic", degraded: (r) => r.embeddings === "off" },
|
|
63
|
+
{ key: "schema", label: "schema", degraded: (r) => r.schema === "missing_table" },
|
|
64
|
+
// PRD-063b (b-AC-7): the Portkey gateway chip. `unconfigured` (on but no key) + `unreachable`
|
|
65
|
+
// (a real call failed) are the DOWN states → critical; `off` (not in force) + `ok` are healthy.
|
|
66
|
+
{ key: "portkey", label: "portkey", degraded: (r) => r.portkey === "unconfigured" || r.portkey === "unreachable" },
|
|
67
|
+
];
|
|
68
|
+
/**
|
|
69
|
+
* The PRD-029 per-subsystem health strip (D-2 render). Reads the `/health` `reasons` block and renders
|
|
70
|
+
* one small chip per subsystem — `storage`, `semantic` (embeddings), `schema` — tinting a degraded one
|
|
71
|
+
* `critical` and a healthy one `verified`. When `reasons` is `null` (the mode-gated public body, which
|
|
72
|
+
* the LOCAL dashboard never gets — defensive) the whole strip renders NOTHING.
|
|
73
|
+
*
|
|
74
|
+
* AC-5: every chip renders a subsystem NAME + a closed-enum STATE only — no token/org/endpoint/header.
|
|
75
|
+
*/
|
|
76
|
+
function HealthStrip({ reasons }) {
|
|
77
|
+
if (reasons === null)
|
|
78
|
+
return null;
|
|
79
|
+
return (_jsxs("div", { "data-testid": "health-strip", style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 18, flexWrap: "wrap" }, children: [_jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-tertiary)", textTransform: "uppercase", letterSpacing: "0.08em" }, children: "subsystems" }), SUBSYSTEMS.map((s) => {
|
|
80
|
+
const down = s.degraded(reasons);
|
|
81
|
+
const state = String(reasons[s.key]);
|
|
82
|
+
return (_jsxs(Badge, { tone: down ? "critical" : "verified", mono: true, dot: true, children: [s.label, ": ", state] }, s.key));
|
|
83
|
+
})] }));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The Dashboard route content (the lift-and-shift, D-6). On mount it hydrates every view from the
|
|
87
|
+
* shared `wire` (AC-2), polls `/api/logs` (AC-4) and `/health` for the strip reasons (PRD-029), and
|
|
88
|
+
* runs recall (AC-3). The `pollinating` pulse is owned by the shell (D-5) and read from props. All
|
|
89
|
+
* polling clears on unmount. NO header — the shell owns the chrome (D-5).
|
|
90
|
+
*/
|
|
91
|
+
export function DashboardPage({ wire, pollinating = false, healthReasons = null }) {
|
|
92
|
+
// PRD-049e: the active dashboard scope — the selected project re-scopes the KPI band's
|
|
93
|
+
// project-bearing counts (Memories / Turns / Est. savings). Absent → the workspace-wide view.
|
|
94
|
+
const { scope } = useScope();
|
|
95
|
+
// ── view state (hydrated from the shared wire) ──
|
|
96
|
+
// `healthReasons` is no longer polled here — the SHELL owns the single /health poll and passes the
|
|
97
|
+
// reasons down via PageProps (the former double-poll is gone). It still feeds the subsystem strip.
|
|
98
|
+
const [kpis, setKpis] = React.useState(EMPTY_KPIS);
|
|
99
|
+
const [sessions, setSessions] = React.useState([]);
|
|
100
|
+
const [rules, setRules] = React.useState([]);
|
|
101
|
+
const [skills, setSkills] = React.useState([]);
|
|
102
|
+
const [vaultSettings, setVaultSettings] = React.useState(EMPTY_VAULT_SETTINGS);
|
|
103
|
+
const [secretNames, setSecretNames] = React.useState([]);
|
|
104
|
+
// ── harness-area state (038c) — the PRD-039 registry/telemetry backbone (`wire.harnesses()`) ──
|
|
105
|
+
const [harnesses, setHarnesses] = React.useState([]);
|
|
106
|
+
// ── recall state (AC-3) ──
|
|
107
|
+
const [query, setQuery] = React.useState("how do we deploy");
|
|
108
|
+
const [results, setResults] = React.useState([]);
|
|
109
|
+
const [recallBusy, setRecallBusy] = React.useState(false);
|
|
110
|
+
const [recalled, setRecalled] = React.useState(false);
|
|
111
|
+
const [recallNonce, setRecallNonce] = React.useState(0);
|
|
112
|
+
const [recallDegraded, setRecallDegraded] = React.useState(false);
|
|
113
|
+
// ── log + recall-note state (AC-4) ──
|
|
114
|
+
const [logLines, setLogLines] = React.useState([]);
|
|
115
|
+
const [notes, setNotes] = React.useState([]);
|
|
116
|
+
/** Push a client-originated note (recall summary) onto the live-log feed. */
|
|
117
|
+
const pushNote = React.useCallback((text) => {
|
|
118
|
+
setNotes((prev) => [`${clockPrefix()} ${text}`, ...prev].slice(0, MAX_LOG_LINES));
|
|
119
|
+
}, []);
|
|
120
|
+
// PRD-049e: a monotonic request token guarding `hydrate` against a stale-overwrite race. Since the
|
|
121
|
+
// hydrate effect now re-runs on `scope.project` change, a SLOWER response for the PREVIOUS project can
|
|
122
|
+
// resolve AFTER the newer selection's and repaint the band with stale data. Each hydrate bumps this and
|
|
123
|
+
// captures its own token; only the LATEST run commits its state (older in-flight runs bail post-await).
|
|
124
|
+
const hydrateSeqRef = React.useRef(0);
|
|
125
|
+
/**
|
|
126
|
+
* Hydrate the diagnostics views + the vault settings from the live endpoints (AC-2), in ONE
|
|
127
|
+
* batched `Promise.all` round-trip (parity with the old app). The org/workspace `settings` view
|
|
128
|
+
* now renders in the SHELL header (D-5), so the page no longer keeps it — but the shell hydrates
|
|
129
|
+
* its own settings; this page hydrates only what its body renders.
|
|
130
|
+
*/
|
|
131
|
+
const hydrate = React.useCallback(async () => {
|
|
132
|
+
const seq = ++hydrateSeqRef.current;
|
|
133
|
+
const [k, sess, r, sk, vs, sn] = await Promise.all([
|
|
134
|
+
wire.kpis(scope.project),
|
|
135
|
+
wire.sessions(),
|
|
136
|
+
wire.rules(),
|
|
137
|
+
wire.skills(),
|
|
138
|
+
wire.vaultSettings(),
|
|
139
|
+
wire.secretNames(),
|
|
140
|
+
]);
|
|
141
|
+
// A newer hydrate (a faster project switch) superseded this one → drop this stale result wholesale
|
|
142
|
+
// so the band never flickers back to the previous project's numbers.
|
|
143
|
+
if (seq !== hydrateSeqRef.current)
|
|
144
|
+
return;
|
|
145
|
+
setKpis(k);
|
|
146
|
+
setSessions(sess);
|
|
147
|
+
setRules(r);
|
|
148
|
+
setSkills(sk);
|
|
149
|
+
setVaultSettings(vs);
|
|
150
|
+
setSecretNames(sn);
|
|
151
|
+
}, [wire, scope.project]);
|
|
152
|
+
/** PRD-032c (AC-5): persist one vault `setting` through the daemon, then RE-READ the persisted truth. */
|
|
153
|
+
const saveSetting = React.useCallback(async (key, value) => {
|
|
154
|
+
const ok = await wire.setSetting(key, value);
|
|
155
|
+
const [vs, sn] = await Promise.all([wire.vaultSettings(), wire.secretNames()]);
|
|
156
|
+
setVaultSettings(vs);
|
|
157
|
+
setSecretNames(sn);
|
|
158
|
+
return ok;
|
|
159
|
+
}, [wire]);
|
|
160
|
+
// AC-2: hydrate once on mount.
|
|
161
|
+
React.useEffect(() => {
|
|
162
|
+
void hydrate();
|
|
163
|
+
}, [hydrate]);
|
|
164
|
+
// Defer the below-the-fold harness area to a SECOND paint so the KPI band + recall (what the operator
|
|
165
|
+
// looks at) are interactive first. The flag flips in a passive effect (after the first commit paints),
|
|
166
|
+
// so the heavy strip/grid/log mount on the next render, not the first. The `harness-area` landmark
|
|
167
|
+
// itself always renders (stable layout); only its CONTENTS wait for this.
|
|
168
|
+
const [showSecondary, setShowSecondary] = React.useState(false);
|
|
169
|
+
React.useEffect(() => {
|
|
170
|
+
setShowSecondary(true);
|
|
171
|
+
}, []);
|
|
172
|
+
// AC-4: poll /api/logs and render real daemon log lines. Via `usePoll` → shared background-tab pause +
|
|
173
|
+
// stop-on-unmount (no hand-rolled interval/alive loop).
|
|
174
|
+
usePoll(async () => {
|
|
175
|
+
const records = await wire.logs(MAX_LOG_LINES);
|
|
176
|
+
setLogLines(records.slice(-MAX_LOG_LINES).reverse().map(formatLogLine));
|
|
177
|
+
}, LOG_POLL_MS);
|
|
178
|
+
// 038c: poll the PRD-039 harness registry/telemetry for the wired-in strip + per-harness tiles. A light
|
|
179
|
+
// poll keeps last-seen recency fresh; a failure degrades to [] (wire-safe). Via `usePoll` (gated + cleaned).
|
|
180
|
+
usePoll(async () => setHarnesses(await wire.harnesses()), HARNESS_POLL_MS);
|
|
181
|
+
// AC-3: recall → POST /api/memories/recall → render the hits as MemoryCards.
|
|
182
|
+
const recall = React.useCallback(async () => {
|
|
183
|
+
const q = query.trim();
|
|
184
|
+
if (q === "" || recallBusy)
|
|
185
|
+
return;
|
|
186
|
+
setRecallBusy(true);
|
|
187
|
+
const { memories, degraded } = await wire.recall(q);
|
|
188
|
+
setResults(memories);
|
|
189
|
+
setRecalled(true);
|
|
190
|
+
setRecallDegraded(degraded);
|
|
191
|
+
setRecallNonce((n) => n + 1);
|
|
192
|
+
const top = memories.length > 0 ? ` · ${memories[0]?.score.toFixed(2)} top` : "";
|
|
193
|
+
pushNote(`recall "${q}" → ${memories.length} hits${top}`);
|
|
194
|
+
setRecallBusy(false);
|
|
195
|
+
}, [query, recallBusy, wire, pushNote]);
|
|
196
|
+
// The live-log feed merges client notes (recall) ahead of the polled daemon lines.
|
|
197
|
+
const feed = React.useMemo(() => [...notes, ...logLines].slice(0, MAX_LOG_LINES), [notes, logLines]);
|
|
198
|
+
// 038c-AC-2: the harness-area short-tail stream — the SAME polled /api/logs lines, capped tighter
|
|
199
|
+
// than the full log. `/api/logs` carries no per-line harness field (c-OQ-3), so it is unlabeled.
|
|
200
|
+
const streamLines = React.useMemo(() => logLines.slice(0, MAX_STREAM_LINES), [logLines]);
|
|
201
|
+
return (_jsxs(_Fragment, { children: [_jsxs("section", { "data-area": "kpi-band", "aria-label": "Key metrics", style: { marginBottom: 22 }, children: [_jsx(HealthStrip, { reasons: healthReasons }), _jsxs("div", { className: "kpirow", children: [_jsx(Kpi, { label: "Memories", value: kpis.memoryCount.toLocaleString(), accent: "honey" }), _jsx(Kpi, { label: "Turns", value: kpis.turnCount || kpis.sessionCount, accent: "neutral" }), _jsx(Kpi, { label: "Est. savings", value: kpis.estimatedSavings.toLocaleString(), unit: "tok", accent: "verified" }), _jsx(Kpi, { label: "Team skills", value: kpis.teamSkillCount, accent: "pollinate" })] })] }), _jsxs("section", { "data-area": "recall-area", "aria-label": "Memory search", style: { marginBottom: 22 }, children: [_jsx(RecallBar, { query: query, setQuery: setQuery, onRecall: recall, busy: recallBusy }), recalled && recallDegraded && (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 12 }, children: [_jsx("span", { style: { fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-tertiary)", textTransform: "uppercase", letterSpacing: "0.08em" }, children: "recall" }), _jsx(LexicalFallbackBadge, {})] })), _jsx("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: results.length === 0
|
|
202
|
+
? recalled && (_jsx("div", { style: { padding: "10px 4px", fontSize: 13, color: "var(--text-tertiary)" }, children: "No memories matched that query." }))
|
|
203
|
+
: results.map((m, i) => (_jsx("div", { className: "mem-enter", style: { animationDelay: `${i * 55}ms` }, children: _jsx(MemoryCard, { ...m, pollinating: pollinating && i === 1 }) }, m.memoryKey))) }, recallNonce)] }), _jsx("section", { "data-area": "harness-area", "aria-label": "Harnesses and activity", children: showSecondary && (_jsxs(_Fragment, { children: [_jsx("div", { style: { marginBottom: 16 }, children: _jsx(HarnessStrip, { harnesses: harnesses, streamLines: streamLines }) }), _jsxs("div", { className: "grid2", style: { marginBottom: 16 }, children: [_jsxs("div", { className: "col", children: [_jsx(SessionsPanel, { sessions: sessions }), _jsx(RulesPanel, { rules: rules })] }), _jsxs("div", { className: "col", children: [_jsx(SettingsPanel, { catalog: vaultSettings.catalog, settings: vaultSettings.settings, secretNames: secretNames, onSave: saveSetting }), _jsx(SkillSyncPanel, { skills: skills })] })] }), _jsx(LiveLog, { lines: feed })] })) })] }));
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=dashboard.js.map
|