Dashboard frontend modernization: Rspack build, real Tailwind v4, LCM TSX#50
Dashboard frontend modernization: Rspack build, real Tailwind v4, LCM TSX#50ScriptedAlchemy wants to merge 30 commits into
Conversation
Replace the esbuild + hand-rolled-utility dashboard build with the Rspack engine (the one Rsbuild wraps) and real Tailwind v4, while preserving the prod-embed contract exactly: dist files are still embedded at compile time by src/dashboard/assets.rs and served with no Node/Rspack dependency at launch. Rspack runs only at build time. Build (dashboard/build.mjs, replaces esbuild): - shell + holographic/graph/savings plugins built with @rspack/core; React externalized onto the host SDK via resolve.alias to the in-tree shims, so every plugin still shares the host's single React instance and runs unmodified in both the standalone shell and Hermes. - single-file IIFE per plugin at the exact dist paths assets.rs expects. - hermes-wrapper concatenation + lcm copy preserved. - esbuild builder kept as build-esbuild.mjs (`npm run build:esbuild`) fallback. - holographic CSS compiled with real Tailwind v4 (@tailwindcss/node + @tailwindcss/oxide); @layer theme/base stripped so the plugin never clobbers host :root vars, wrapped in @layer hermes-plugin. Holographic styles (dashboard/holographic/src/styles.css): - @import "tailwindcss" + @theme color tokens replace the ~390-line hand-rolled utility subset (the fragile [class*="xl:grid-cols-[..."] attribute selectors). Arbitrary values now resolve natively. - surviving :root provides only the tokens the host doesn't (text-primary/secondary/tertiary, midground, shadow-*); hv-*/ts-card component polish kept verbatim. cn (dashboard/lib/cn.ts): one canonical class-name joiner (flatten nested arrays, keep non-empty strings) consumed by the shell SDK, lib/sdk.ts, and holographic's self-contained in-tree copy. Pinned by test/shashell-sdk.test.mjs. Verified: 100/100 node + 12/12 vitest; jsdom smokes (shell renders + exposes SDK; all 3 plugins register); cargo embed + dashboard serve (all routes 200, byte sizes match); real-browser Playwright smoke (desktop + narrow) exercises Holographic/Similarity/Curation/Code Graph/LCM.
…uild dev server LCM plugin — port the 2020-line hand-written vanilla IIFE (lcm/src/index.js, React.createElement via h()) to modern TSX built as a standard plugin bundle, mirroring graph/savings. Split into navigable modules: entry.tsx (registers "hermes-lcm"), App.tsx, components.tsx, markdown.tsx, helpers.ts. All behavior + hermes-lcm-* class names preserved (style.css unchanged, renamed to styles.css for build uniformity). Built as a TSX plugin (React externalized via lib/ shims) instead of copied verbatim; bundle shrinks 86 KB → 48 KB. Build pipeline — esbuild is gone from the build. build.mjs: - LCM now built with buildPlugin (was copyLcm). - Tailwind CSS minify switched from esbuild.transform to a small CSS compactor (preserves @supports color-mix blocks lightningcss would strip). - esbuild fallback builder (build-esbuild.mjs) and the build:esbuild script removed. esbuild remains a devDependency ONLY for the unit-test bundler helper (test/helpers/module-loader.mjs); not in the shipped build path. Dev server — new dashboard/dev/ Rsbuild dev server (`npm run dev`) with HMR, proxying /api/* to a running `tracedecay dashboard` (TRACEDECAY_DEV_API, default 127.0.0.1:7341; port TRACEDECAY_DEV_PORT, default 7342). The dev entry builds the SDK on window before importing plugin entries, so SDK consumers behave like prod. @rsbuild/plugin-tailwindcss compiles holographic's Tailwind v4 in dev (closes the prior dev/prod styling divergence). Verified: 100/100 node + 12/12 vitest; build emits all 14 artifacts; cargo embed + dashboard serve (all routes 200); real-browser Playwright smoke (desktop) exercises Holographic/Similarity/Curation/Code Graph/LCM incl. the new TSX LCM bundle.
- HolographicMemoryPage: CoverageGauge now exposes role="img" + an
aria-label ("N% HRR coverage, <status>") so the gauge is announced to
assistive tech instead of being sight-only. VIEW_TABS hoisted to module
scope (it was rebuilt on every render; it references only module-scope
icons).
- SavingsExplorer: the Savings/Sessions/Models view switch is now a proper
tablist (role="tablist" + role="tab" + aria-selected), matching the shell's
tablist pattern for screen-reader parity.
dev server (dashboard/dev/run.mjs): both Rsbuild Tailwind-v4 integrations (@rsbuild/plugin-tailwindcss and @tailwindcss/postcss via tools.postcss) segfault natively in this execution environment (createRsbuild core dump; @rspack/core itself is fine, so the Tailwind native path is the trigger). Ship the dev server as pluginReact()-only so `npm run dev` actually works — HMR + every non-holographic plugin styled. Holographic renders unstyled in dev (documented divergence); the prod build remains the source of truth for its Tailwind v4 styles. Verified: dev server starts (no segfault), serves HTTP 200, /api proxy wired. docs/dashboard.md: updated the build/frontend/dev sections to the new reality — Rspack build (@rspack/core, per-plugin IIFE, React externalized via shims), real Tailwind v4 for holographic, LCM as a TSX bundle, the `npm run dev` Rsbuild HMR server (env vars TRACEDECAY_DEV_API / TRACEDECAY_DEV_PORT, /api proxy), and the unchanged prod include_bytes! embed contract.
Add lib/primitives.tsx (+ lib/primitives.css) with shared EmptyState, ErrorPanel, SkeletonLines, Stat, BarList — the small UI patterns every plugin hand-rolled under a different class namespace. Components build on the SDK primitives + a tdp-* namespace whose colors resolve through host --color-* vars, so they theme correctly in both the standalone shell and Hermes. CSS is delivered by build.mjs: a new buildPlugin `primitives` option prepends lib/primitives.css to the consuming plugin's dist stylesheet (rides into standalone serve + the Hermes-wrapper concat). Adopted in graph (CodeGraphExplorer) — inline tsg-empty / tsg-error replaced with EmptyState / ErrorPanel (visible text + behavior preserved; graph's other tsg-* styling untouched) — as the reference pattern. Holographic stays self-contained; savings/lcm adoption is follow-up. Verified: 100/100 node + 12/12 vitest; build emits all artifacts; real- browser Playwright smoke (desktop+narrow) passes with the primitives prepended into graph's served CSS.
…ic tokens Replace the ~120-line block of 20 per-component [data-theme="light"] overrides with 32 semantic tokens (--ts-button-bg-2, --ts-card-bg, --ts-input-bg, --ts-tab-active-bg, ...) defined once in :root (dark) and flipped in :root[data-theme="light"]. Component rules now reference the tokens and theme automatically, so new components no longer need a matching manual light override. Dark and light computed values are byte-identical to before (every token's dark value = the old dark rule value; every light value = the old override value). Three rules with no original light override were intentionally left hardcoded (tokenizing them would have changed light-theme output). Residual per-component [data-theme="light"] selectors: 0. Verified: real-browser Playwright smoke (desktop+narrow) passes.
|
Route tracedecay info/todos reads and symbol-edit writes through ProjectPath resolution so out-of-root paths are rejected while valid files still populate touched context. Also update dashboard asset wording to describe UTF-8 JavaScript output independent of bundler.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 64a0025aa5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Rsbuild is now the single build tool. build.mjs is a thin orchestrator over build.shared.mjs, which builds the shell + every plugin via createRsbuild (@rsbuild/core + pluginReact), emitting the same single-file IIFE per plugin at the exact dist/ paths (splitChunks/runtimeChunk off, BannerPlugin, React externalized via the in-tree shims). The dev server config is shared there too (createDashboardDevConfig). Holographic Tailwind v4 still compiles via the programmatic @tailwindcss/node + oxide path (strip @layer theme/base, wrap @layer hermes-plugin), not the segfault-prone Rsbuild tailwind plugins. esbuild is fully removed: the unit-test bundler (test/helpers/module-loader.mjs) now bundles with @rspack/core to an ESM temp module (100/100 node tests still pass, ~unchanged runtime), and esbuild is dropped from devDependencies (no longer in node_modules at all). Redundant build-rsbuild.mjs/rsbuild.config.ts alternatives removed. Added dashboard/tsconfig.json + `npm run typecheck` (tsc --noEmit) with typescript as a devDep. The typecheck is intentionally lenient (strict:false) to surface real bugs over intentional host-SDK `any` noise — it already caught two real undefined-ref crashes (fixed in the follow-up commit). Verified: Rsbuild build emits all 14 artifacts; 100/100 node + 12/12 vitest; real-browser Playwright smoke passes against the cargo-embedded Rsbuild binary.
Real bugs surfaced by `npm run typecheck` (undefined at runtime): - lcm/src/components.tsx used ratioStr (compression ratio) without importing it — crash when the compression view rendered. Now imported from ./helpers. - holographic/src/CurationPanel.tsx referenced loadStatus (Status-tab refresh) without destructuring it from useCurationData — dead refresh button. Now destructured. Shared-primitives adoption (lib/primitives): savings (ErrorPanel, Stat) and lcm (EmptyState, ErrorPanel) adopt the shared components; graph's OverviewPanel adopts BarList/EmptyState (dropping its hand-rolled HBarChart). Holographic stays self-contained. (graph/savings/lcm build with primitives:true so lib/primitives.css is prepended to their dist stylesheet.) a11y: holographic Stat now exposes its hint via aria-describedby + a visually-hidden description element (native title kept for sighted users). docs/dashboard.md: documents the shared primitives + buildPlugin primitives opt-in, the canonical lib/cn.ts, and the dev-server Rsbuild-Tailwind segfault limitation (dev is pluginReact()-only; prod is the source of truth for holographic Tailwind styles). Verified: 100/100 node + 12/12 vitest; Rsbuild build clean; real-browser Playwright smoke passes.
Drop holographic jsx/react shims so Rsbuild typecheck covers all panels; rebuild embedded dist when dashboard sources drift and fix LCM fetchSession typing.
Type-checking is now integrated into the Rsbuild build/dev via @rsbuild/plugin-type-check (ts-checker-rspack-plugin), so the separate 'tsc --noEmit' npm script is redundant. The build is the source of truth for type errors.
b6ce776 to
5138ec8
Compare
5138ec8 to
99cea7f
Compare
99cea7f to
152012e
Compare
Modernizes the dashboard frontend build and UI onto a single Rust-based toolchain (Rspack/Rsbuild) and cleans up the inconsistencies called out in a frontend review. Prod-embed contract is unchanged: `src/dashboard/assets.rs` still `include_bytes!`/`include_str!` the `dist/` files at compile time, so the shipped binary serves the UI with no Node/Rspack dependency at launch — Rspack runs only at build time.
Build (Rspack, no esbuild in the pipeline)
Plugins
Shell / a11y
Dev server
Verification
Not in scope (follow-ups)
Branch based on `profile-storage` so the diff is UI-only. Retarget to `master` if you prefer.